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*69453Seric static char sccsid[] = "@(#)readcf.c 8.89 (Berkeley) 05/14/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. 514432Seric ** 523308Seric ** Parameters: 533308Seric ** cfname -- control file name. 5454973Seric ** safe -- TRUE if this is the system config file; 5554973Seric ** FALSE otherwise. 5655012Seric ** e -- the main envelope. 573308Seric ** 583308Seric ** Returns: 593308Seric ** none. 603308Seric ** 613308Seric ** Side Effects: 623308Seric ** Builds several internal tables. 633308Seric */ 643308Seric 6555012Seric readcf(cfname, safe, e) 663308Seric char *cfname; 6754973Seric bool safe; 6855012Seric register ENVELOPE *e; 693308Seric { 703308Seric FILE *cf; 718547Seric int ruleset = 0; 7268481Seric int nextruleset = MAXRWSETS; 738547Seric char *q; 749350Seric struct rewrite *rwp = NULL; 7557135Seric char *bp; 7664718Seric auto char *ep; 7757589Seric int nfuzzy; 7864133Seric char *file; 7964133Seric bool optional; 8068481Seric int mid; 813308Seric char buf[MAXLINE]; 823308Seric register char *p; 833308Seric extern char **copyplist(); 8452647Seric struct stat statb; 855909Seric char exbuf[MAXLINE]; 8665066Seric char pvpbuf[MAXLINE + MAXATOM]; 8768481Seric static char *null_list[1] = { NULL }; 8810709Seric extern char *munchstring(); 8953654Seric extern void makemapentry(); 903308Seric 9152647Seric FileName = cfname; 9252647Seric LineNumber = 0; 9352647Seric 943308Seric cf = fopen(cfname, "r"); 953308Seric if (cf == NULL) 963308Seric { 9752647Seric syserr("cannot open"); 983308Seric exit(EX_OSFILE); 993308Seric } 1003308Seric 10152647Seric if (fstat(fileno(cf), &statb) < 0) 10252647Seric { 10352647Seric syserr("cannot fstat"); 10452647Seric exit(EX_OSFILE); 10552647Seric } 10652647Seric 10752647Seric if (!S_ISREG(statb.st_mode)) 10852647Seric { 10952647Seric syserr("not a plain file"); 11052647Seric exit(EX_OSFILE); 11152647Seric } 11252647Seric 11352647Seric if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode)) 11452647Seric { 11553037Seric if (OpMode == MD_DAEMON || OpMode == MD_FREEZE) 11653037Seric fprintf(stderr, "%s: WARNING: dangerous write permissions\n", 11753037Seric FileName); 11853037Seric #ifdef LOG 11953037Seric if (LogLevel > 0) 12053037Seric syslog(LOG_CRIT, "%s: WARNING: dangerous write permissions", 12153037Seric FileName); 12253037Seric #endif 12352647Seric } 12452647Seric 12559254Seric #ifdef XLA 12659254Seric xla_zero(); 12759254Seric #endif 12859254Seric 12957135Seric while ((bp = fgetfolded(buf, sizeof buf, cf)) != NULL) 1303308Seric { 13157135Seric if (bp[0] == '#') 13257135Seric { 13357135Seric if (bp != buf) 13457135Seric free(bp); 13552637Seric continue; 13657135Seric } 13752637Seric 13868481Seric /* do macro expansion mappings */ 13957135Seric for (p = bp; *p != '\0'; p++) 14016157Seric { 14157135Seric if (*p == '#' && p > bp && ConfigLevel >= 3) 14252647Seric { 14352647Seric /* this is an on-line comment */ 14452647Seric register char *e; 14552647Seric 14658050Seric switch (*--p & 0377) 14752647Seric { 14858050Seric case MACROEXPAND: 14952647Seric /* it's from $# -- let it go through */ 15052647Seric p++; 15152647Seric break; 15252647Seric 15352647Seric case '\\': 15452647Seric /* it's backslash escaped */ 15552647Seric (void) strcpy(p, p + 1); 15652647Seric break; 15752647Seric 15852647Seric default: 15952647Seric /* delete preceeding white space */ 16058050Seric while (isascii(*p) && isspace(*p) && p > bp) 16152647Seric p--; 16256795Seric if ((e = strchr(++p, '\n')) != NULL) 16352647Seric (void) strcpy(p, e); 16452647Seric else 16552647Seric p[0] = p[1] = '\0'; 16652647Seric break; 16752647Seric } 16852647Seric continue; 16952647Seric } 17052647Seric 17168481Seric if (*p != '$' || p[1] == '\0') 17216157Seric continue; 17316157Seric 17416157Seric if (p[1] == '$') 17516157Seric { 17616157Seric /* actual dollar sign.... */ 17723111Seric (void) strcpy(p, p + 1); 17816157Seric continue; 17916157Seric } 18016157Seric 18116157Seric /* convert to macro expansion character */ 18268481Seric *p++ = MACROEXPAND; 18368481Seric 18468481Seric /* convert macro name to code */ 18568481Seric *p = macid(p, &ep); 18668481Seric if (ep != p) 18768481Seric strcpy(p + 1, ep); 18816157Seric } 18916157Seric 19016157Seric /* interpret this line */ 19164718Seric errno = 0; 19257135Seric switch (bp[0]) 1933308Seric { 1943308Seric case '\0': 1953308Seric case '#': /* comment */ 1963308Seric break; 1973308Seric 1983308Seric case 'R': /* rewriting rule */ 19957135Seric for (p = &bp[1]; *p != '\0' && *p != '\t'; p++) 2003308Seric continue; 2013308Seric 2023308Seric if (*p == '\0') 2035909Seric { 20465821Seric syserr("invalid rewrite line \"%s\" (tab expected)", bp); 2055909Seric break; 2065909Seric } 2075909Seric 2085909Seric /* allocate space for the rule header */ 2095909Seric if (rwp == NULL) 2105909Seric { 2115909Seric RewriteRules[ruleset] = rwp = 2125909Seric (struct rewrite *) xalloc(sizeof *rwp); 2135909Seric } 2143308Seric else 2153308Seric { 2165909Seric rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp); 2175909Seric rwp = rwp->r_next; 2185909Seric } 2195909Seric rwp->r_next = NULL; 2203308Seric 2215909Seric /* expand and save the LHS */ 2225909Seric *p = '\0'; 22368529Seric expand(&bp[1], exbuf, sizeof exbuf, e); 22465066Seric rwp->r_lhs = prescan(exbuf, '\t', pvpbuf, 22568711Seric sizeof pvpbuf, NULL, NULL); 22657589Seric nfuzzy = 0; 2275909Seric if (rwp->r_lhs != NULL) 22857589Seric { 22957589Seric register char **ap; 23057589Seric 2315909Seric rwp->r_lhs = copyplist(rwp->r_lhs, TRUE); 23257589Seric 23357589Seric /* count the number of fuzzy matches in LHS */ 23457589Seric for (ap = rwp->r_lhs; *ap != NULL; ap++) 23557589Seric { 23658148Seric char *botch; 23758148Seric 23858148Seric botch = NULL; 23958050Seric switch (**ap & 0377) 24057589Seric { 24157589Seric case MATCHZANY: 24257589Seric case MATCHANY: 24357589Seric case MATCHONE: 24457589Seric case MATCHCLASS: 24557589Seric case MATCHNCLASS: 24657589Seric nfuzzy++; 24758148Seric break; 24858148Seric 24958148Seric case MATCHREPL: 25058148Seric botch = "$0-$9"; 25158148Seric break; 25258148Seric 25358148Seric case CANONNET: 25458148Seric botch = "$#"; 25558148Seric break; 25658148Seric 25758148Seric case CANONUSER: 25858148Seric botch = "$:"; 25958148Seric break; 26058148Seric 26158148Seric case CALLSUBR: 26258148Seric botch = "$>"; 26358148Seric break; 26458148Seric 26558148Seric case CONDIF: 26658148Seric botch = "$?"; 26758148Seric break; 26858148Seric 26958148Seric case CONDELSE: 27058148Seric botch = "$|"; 27158148Seric break; 27258148Seric 27358148Seric case CONDFI: 27458148Seric botch = "$."; 27558148Seric break; 27658148Seric 27758148Seric case HOSTBEGIN: 27858148Seric botch = "$["; 27958148Seric break; 28058148Seric 28158148Seric case HOSTEND: 28258148Seric botch = "$]"; 28358148Seric break; 28458148Seric 28558148Seric case LOOKUPBEGIN: 28658148Seric botch = "$("; 28758148Seric break; 28858148Seric 28958148Seric case LOOKUPEND: 29058148Seric botch = "$)"; 29158148Seric break; 29257589Seric } 29358148Seric if (botch != NULL) 29458148Seric syserr("Inappropriate use of %s on LHS", 29558148Seric botch); 29657589Seric } 29757589Seric } 29856678Seric else 29968481Seric { 30056678Seric syserr("R line: null LHS"); 30168481Seric rwp->r_lhs = null_list; 30268481Seric } 3035909Seric 3045909Seric /* expand and save the RHS */ 3055909Seric while (*++p == '\t') 3065909Seric continue; 3077231Seric q = p; 3087231Seric while (*p != '\0' && *p != '\t') 3097231Seric p++; 3107231Seric *p = '\0'; 31168529Seric expand(q, exbuf, sizeof exbuf, e); 31265066Seric rwp->r_rhs = prescan(exbuf, '\t', pvpbuf, 31368711Seric sizeof pvpbuf, NULL, NULL); 3145909Seric if (rwp->r_rhs != NULL) 31557589Seric { 31657589Seric register char **ap; 31757589Seric 3185909Seric rwp->r_rhs = copyplist(rwp->r_rhs, TRUE); 31957589Seric 32057589Seric /* check no out-of-bounds replacements */ 32157589Seric nfuzzy += '0'; 32257589Seric for (ap = rwp->r_rhs; *ap != NULL; ap++) 32357589Seric { 32458148Seric char *botch; 32558148Seric 32658148Seric botch = NULL; 32758148Seric switch (**ap & 0377) 32857589Seric { 32958148Seric case MATCHREPL: 33058148Seric if ((*ap)[1] <= '0' || (*ap)[1] > nfuzzy) 33158148Seric { 33258148Seric syserr("replacement $%c out of bounds", 33358148Seric (*ap)[1]); 33458148Seric } 33558148Seric break; 33658148Seric 33758148Seric case MATCHZANY: 33858148Seric botch = "$*"; 33958148Seric break; 34058148Seric 34158148Seric case MATCHANY: 34258148Seric botch = "$+"; 34358148Seric break; 34458148Seric 34558148Seric case MATCHONE: 34658148Seric botch = "$-"; 34758148Seric break; 34858148Seric 34958148Seric case MATCHCLASS: 35058148Seric botch = "$="; 35158148Seric break; 35258148Seric 35358148Seric case MATCHNCLASS: 35458148Seric botch = "$~"; 35558148Seric break; 35657589Seric } 35758148Seric if (botch != NULL) 35858148Seric syserr("Inappropriate use of %s on RHS", 35958148Seric botch); 36057589Seric } 36157589Seric } 36256678Seric else 36368481Seric { 36456678Seric syserr("R line: null RHS"); 36568481Seric rwp->r_rhs = null_list; 36668481Seric } 3673308Seric break; 3683308Seric 3694072Seric case 'S': /* select rewriting set */ 37064440Seric for (p = &bp[1]; isascii(*p) && isspace(*p); p++) 37164440Seric continue; 37268481Seric if (!isascii(*p)) 37364440Seric { 37464440Seric syserr("invalid argument to S line: \"%.20s\"", 37564440Seric &bp[1]); 37664440Seric break; 37764440Seric } 37868481Seric if (isdigit(*p)) 3798056Seric { 38068481Seric ruleset = atoi(p); 38168481Seric if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 38268481Seric { 38368481Seric syserr("bad ruleset %d (%d max)", 38468481Seric ruleset, MAXRWSETS / 2); 38568481Seric ruleset = 0; 38668481Seric } 3878056Seric } 38868481Seric else 38968481Seric { 39068481Seric STAB *s; 39168481Seric char delim; 39268481Seric 39368481Seric q = p; 39468481Seric while (*p != '\0' && isascii(*p) && 39568481Seric (isalnum(*p) || strchr("-_$", *p) != NULL)) 39668481Seric p++; 39768481Seric while (isascii(*p) && isspace(*p)) 39868481Seric *p++ = '\0'; 39968481Seric delim = *p; 40068481Seric if (delim != '\0') 40168481Seric *p++ = '\0'; 40268481Seric s = stab(q, ST_RULESET, ST_ENTER); 40368481Seric if (s->s_ruleset != 0) 40468481Seric ruleset = s->s_ruleset; 40568481Seric else if (delim == '=') 40668481Seric { 40768481Seric ruleset = atoi(p); 40868481Seric if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 40968481Seric { 41068481Seric syserr("bad ruleset %s = %d (%d max)", 41168481Seric q, ruleset, MAXRWSETS / 2); 41268481Seric ruleset = 0; 41368481Seric } 41468481Seric } 41568481Seric else if ((ruleset = --nextruleset) < MAXRWSETS / 2) 41668481Seric { 41768481Seric syserr("%s: too many named rulesets (%d max)", 41868481Seric q, MAXRWSETS / 2); 41968481Seric ruleset = 0; 42068481Seric } 42168481Seric s->s_ruleset = ruleset; 42268481Seric } 4234072Seric rwp = NULL; 4244072Seric break; 4254072Seric 4263308Seric case 'D': /* macro definition */ 42768481Seric mid = macid(&bp[1], &ep); 42868481Seric p = munchstring(ep, NULL); 42968481Seric define(mid, newstr(p), e); 4303308Seric break; 4313308Seric 4323387Seric case 'H': /* required header line */ 43368717Seric (void) chompheader(&bp[1], TRUE, NULL, e); 4343387Seric break; 4353387Seric 4364061Seric case 'C': /* word class */ 43768481Seric case 'T': /* trusted user (set class `t') */ 43868481Seric if (bp[0] == 'C') 4394061Seric { 44068481Seric mid = macid(&bp[1], &ep); 44168529Seric expand(ep, exbuf, sizeof exbuf, e); 44268481Seric p = exbuf; 44368481Seric } 44468481Seric else 44568481Seric { 44668481Seric mid = 't'; 44768481Seric p = &bp[1]; 44868481Seric } 44968481Seric while (*p != '\0') 45068481Seric { 4514061Seric register char *wd; 4524061Seric char delim; 4534061Seric 45458050Seric while (*p != '\0' && isascii(*p) && isspace(*p)) 4554061Seric p++; 4564061Seric wd = p; 45758050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 4584061Seric p++; 4594061Seric delim = *p; 4604061Seric *p = '\0'; 4614061Seric if (wd[0] != '\0') 46268481Seric setclass(mid, wd); 4634061Seric *p = delim; 4644061Seric } 4654061Seric break; 4664061Seric 46759272Seric case 'F': /* word class from file */ 46868481Seric mid = macid(&bp[1], &ep); 46968481Seric for (p = ep; isascii(*p) && isspace(*p); ) 47064133Seric p++; 47164133Seric if (p[0] == '-' && p[1] == 'o') 47264133Seric { 47364133Seric optional = TRUE; 47464133Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 47564133Seric p++; 47664133Seric while (isascii(*p) && isspace(*p)) 47768481Seric p++; 47864133Seric } 47964133Seric else 48064133Seric optional = FALSE; 48164133Seric file = p; 48264133Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 48364133Seric p++; 48459272Seric if (*p == '\0') 48559272Seric p = "%s"; 48659272Seric else 48759272Seric { 48859272Seric *p = '\0'; 48959272Seric while (isascii(*++p) && isspace(*p)) 49059272Seric continue; 49159272Seric } 49264133Seric fileclass(bp[1], file, p, safe, optional); 49359272Seric break; 49459272Seric 49559156Seric #ifdef XLA 49659156Seric case 'L': /* extended load average description */ 49759156Seric xla_init(&bp[1]); 49859156Seric break; 49959156Seric #endif 50059156Seric 5014096Seric case 'M': /* define mailer */ 50257135Seric makemailer(&bp[1]); 5034096Seric break; 5044096Seric 5058252Seric case 'O': /* set option */ 50658734Seric setoption(bp[1], &bp[2], safe, FALSE, e); 5078252Seric break; 5088252Seric 5098252Seric case 'P': /* set precedence */ 5108252Seric if (NumPriorities >= MAXPRIORITIES) 5118252Seric { 5128547Seric toomany('P', MAXPRIORITIES); 5138252Seric break; 5148252Seric } 51557135Seric for (p = &bp[1]; *p != '\0' && *p != '=' && *p != '\t'; p++) 5168252Seric continue; 5178252Seric if (*p == '\0') 5188252Seric goto badline; 5198252Seric *p = '\0'; 52057135Seric Priorities[NumPriorities].pri_name = newstr(&bp[1]); 5218252Seric Priorities[NumPriorities].pri_val = atoi(++p); 5228252Seric NumPriorities++; 5238252Seric break; 5248252Seric 52552645Seric case 'V': /* configuration syntax version */ 52664440Seric for (p = &bp[1]; isascii(*p) && isspace(*p); p++) 52764440Seric continue; 52864440Seric if (!isascii(*p) || !isdigit(*p)) 52964440Seric { 53064440Seric syserr("invalid argument to V line: \"%.20s\"", 53164440Seric &bp[1]); 53264440Seric break; 53364440Seric } 53464718Seric ConfigLevel = strtol(p, &ep, 10); 53568805Seric 53668805Seric /* 53768805Seric ** Do heuristic tweaking for back compatibility. 53868805Seric */ 53968805Seric 54064279Seric if (ConfigLevel >= 5) 54164279Seric { 54264279Seric /* level 5 configs have short name in $w */ 54364279Seric p = macvalue('w', e); 54464279Seric if (p != NULL && (p = strchr(p, '.')) != NULL) 54564279Seric *p = '\0'; 54664279Seric } 54768805Seric if (ConfigLevel >= 6) 54868805Seric { 54968805Seric ColonOkInAddr = FALSE; 55068805Seric } 55168805Seric 55268805Seric /* 55368805Seric ** Look for vendor code. 55468805Seric */ 55568805Seric 55664718Seric if (*ep++ == '/') 55764718Seric { 55864718Seric /* extract vendor code */ 55964718Seric for (p = ep; isascii(*p) && isalpha(*p); ) 56064718Seric p++; 56164718Seric *p = '\0'; 56264718Seric 56364718Seric if (!setvendor(ep)) 56464718Seric syserr("invalid V line vendor code: \"%s\"", 56564718Seric ep); 56664718Seric } 56752645Seric break; 56852645Seric 56953654Seric case 'K': 57057135Seric makemapentry(&bp[1]); 57153654Seric break; 57253654Seric 5733308Seric default: 5744061Seric badline: 57557135Seric syserr("unknown control line \"%s\"", bp); 5763308Seric } 57757135Seric if (bp != buf) 57857135Seric free(bp); 5793308Seric } 58052637Seric if (ferror(cf)) 58152637Seric { 58252647Seric syserr("I/O read error", cfname); 58352637Seric exit(EX_OSFILE); 58452637Seric } 58552637Seric fclose(cf); 5869381Seric FileName = NULL; 58756836Seric 58868481Seric /* initialize host maps from local service tables */ 58968481Seric inithostmaps(); 59068481Seric 59168481Seric /* determine if we need to do special name-server frotz */ 59267905Seric { 59368481Seric int nmaps; 59468481Seric char *maptype[MAXMAPSTACK]; 59568481Seric short mapreturn[MAXMAPACTIONS]; 59668481Seric 59768481Seric nmaps = switch_map_find("hosts", maptype, mapreturn); 59868481Seric UseNameServer = FALSE; 59968481Seric if (nmaps > 0 && nmaps <= MAXMAPSTACK) 60068481Seric { 60168481Seric register int mapno; 60268481Seric 60368481Seric for (mapno = 0; mapno < nmaps && !UseNameServer; mapno++) 60468481Seric { 60568481Seric if (strcmp(maptype[mapno], "dns") == 0) 60668481Seric UseNameServer = TRUE; 60768481Seric } 60868481Seric } 60968481Seric 61068481Seric #ifdef HESIOD 61168481Seric nmaps = switch_map_find("passwd", maptype, mapreturn); 61268481Seric UseHesiod = FALSE; 61368481Seric if (nmaps > 0 && nmaps <= MAXMAPSTACK) 61468481Seric { 61568481Seric register int mapno; 61668481Seric 61768481Seric for (mapno = 0; mapno < nmaps && !UseHesiod; mapno++) 61868481Seric { 61968481Seric if (strcmp(maptype[mapno], "hesiod") == 0) 62068481Seric UseHesiod = TRUE; 62168481Seric } 62268481Seric } 62368204Seric #endif 62467905Seric } 6254096Seric } 6264096Seric /* 6278547Seric ** TOOMANY -- signal too many of some option 6288547Seric ** 6298547Seric ** Parameters: 6308547Seric ** id -- the id of the error line 6318547Seric ** maxcnt -- the maximum possible values 6328547Seric ** 6338547Seric ** Returns: 6348547Seric ** none. 6358547Seric ** 6368547Seric ** Side Effects: 6378547Seric ** gives a syserr. 6388547Seric */ 6398547Seric 6408547Seric toomany(id, maxcnt) 6418547Seric char id; 6428547Seric int maxcnt; 6438547Seric { 6449381Seric syserr("too many %c lines, %d max", id, maxcnt); 6458547Seric } 6468547Seric /* 6474432Seric ** FILECLASS -- read members of a class from a file 6484432Seric ** 6494432Seric ** Parameters: 6504432Seric ** class -- class to define. 6514432Seric ** filename -- name of file to read. 6524432Seric ** fmt -- scanf string to use for match. 65364133Seric ** safe -- if set, this is a safe read. 65464133Seric ** optional -- if set, it is not an error for the file to 65564133Seric ** not exist. 6564432Seric ** 6574432Seric ** Returns: 6584432Seric ** none 6594432Seric ** 6604432Seric ** Side Effects: 6614432Seric ** 6624432Seric ** puts all lines in filename that match a scanf into 6634432Seric ** the named class. 6644432Seric */ 6654432Seric 66664133Seric fileclass(class, filename, fmt, safe, optional) 6674432Seric int class; 6684432Seric char *filename; 6694432Seric char *fmt; 67054973Seric bool safe; 67164133Seric bool optional; 6724432Seric { 67325808Seric FILE *f; 67468513Seric int sff; 675*69453Seric int pid; 676*69453Seric register char *p; 6774432Seric char buf[MAXLINE]; 6784432Seric 67966101Seric if (tTd(37, 2)) 68066101Seric printf("fileclass(%s, fmt=%s)\n", filename, fmt); 68166101Seric 68266031Seric if (filename[0] == '|') 68366031Seric { 684*69453Seric auto int fd; 685*69453Seric int i; 686*69453Seric char *argv[MAXPV + 1]; 687*69453Seric 688*69453Seric i = 0; 689*69453Seric for (p = strtok(&filename[1], " \t"); p != NULL; p = strtok(NULL, " \t")) 690*69453Seric { 691*69453Seric if (i >= MAXPV) 692*69453Seric break; 693*69453Seric argv[i++] = p; 694*69453Seric } 695*69453Seric argv[i] = NULL; 696*69453Seric pid = prog_open(argv, &fd, CurEnv); 697*69453Seric if (pid < 0) 698*69453Seric f = NULL; 699*69453Seric else 700*69453Seric f = fdopen(fd, "r"); 70166031Seric } 702*69453Seric else 703*69453Seric { 704*69453Seric pid = -1; 705*69453Seric sff = SFF_REGONLY; 706*69453Seric if (safe) 707*69453Seric sff |= SFF_OPENASROOT; 708*69453Seric f = safefopen(filename, O_RDONLY, 0, sff); 709*69453Seric } 71068602Seric if (f == NULL) 71154973Seric { 71268602Seric if (!optional) 71368602Seric syserr("fileclass: cannot open %s", filename); 7144432Seric return; 7154432Seric } 7164432Seric 7174432Seric while (fgets(buf, sizeof buf, f) != NULL) 7184432Seric { 7194432Seric register STAB *s; 72025808Seric register char *p; 72125808Seric # ifdef SCANF 7224432Seric char wordbuf[MAXNAME+1]; 7234432Seric 7244432Seric if (sscanf(buf, fmt, wordbuf) != 1) 7254432Seric continue; 72625808Seric p = wordbuf; 72756795Seric # else /* SCANF */ 72825808Seric p = buf; 72956795Seric # endif /* SCANF */ 73025808Seric 73125808Seric /* 73225808Seric ** Break up the match into words. 73325808Seric */ 73425808Seric 73525808Seric while (*p != '\0') 73625808Seric { 73725808Seric register char *q; 73825808Seric 73925808Seric /* strip leading spaces */ 74058050Seric while (isascii(*p) && isspace(*p)) 74125808Seric p++; 74225808Seric if (*p == '\0') 74325808Seric break; 74425808Seric 74525808Seric /* find the end of the word */ 74625808Seric q = p; 74758050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 74825808Seric p++; 74925808Seric if (*p != '\0') 75025808Seric *p++ = '\0'; 75125808Seric 75225808Seric /* enter the word in the symbol table */ 75366101Seric setclass(class, q); 75425808Seric } 7554432Seric } 7564432Seric 75754973Seric (void) fclose(f); 758*69453Seric if (pid > 0) 759*69453Seric (void) waitfor(pid); 7604432Seric } 7614432Seric /* 7624096Seric ** MAKEMAILER -- define a new mailer. 7634096Seric ** 7644096Seric ** Parameters: 76510327Seric ** line -- description of mailer. This is in labeled 76610327Seric ** fields. The fields are: 76768481Seric ** A -- the argv for this mailer 76868481Seric ** C -- the character set for MIME conversions 76968481Seric ** D -- the directory to run in 77068481Seric ** E -- the eol string 77168481Seric ** F -- the flags associated with the mailer 77268481Seric ** L -- the maximum line length 77368481Seric ** M -- the maximum message size 77468816Seric ** N -- the niceness at which to run 77568479Seric ** P -- the path to the mailer 77668481Seric ** R -- the recipient rewriting set 77768479Seric ** S -- the sender rewriting set 77868481Seric ** T -- the mailer type (for DSNs) 77968481Seric ** U -- the uid to run as 78010327Seric ** The first word is the canonical name of the mailer. 7814096Seric ** 7824096Seric ** Returns: 7834096Seric ** none. 7844096Seric ** 7854096Seric ** Side Effects: 7864096Seric ** enters the mailer into the mailer table. 7874096Seric */ 7883308Seric 78921066Seric makemailer(line) 7904096Seric char *line; 7914096Seric { 7924096Seric register char *p; 7938067Seric register struct mailer *m; 7948067Seric register STAB *s; 7958067Seric int i; 79610327Seric char fcode; 79758020Seric auto char *endp; 7984096Seric extern int NextMailer; 79910327Seric extern char **makeargv(); 80010327Seric extern char *munchstring(); 8014096Seric 80210327Seric /* allocate a mailer and set up defaults */ 80310327Seric m = (struct mailer *) xalloc(sizeof *m); 80410327Seric bzero((char *) m, sizeof *m); 80510327Seric m->m_eol = "\n"; 80668481Seric m->m_uid = m->m_gid = 0; 80710327Seric 80810327Seric /* collect the mailer name */ 80958050Seric for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++) 81010327Seric continue; 81110327Seric if (*p != '\0') 81210327Seric *p++ = '\0'; 81310327Seric m->m_name = newstr(line); 81410327Seric 81510327Seric /* now scan through and assign info from the fields */ 81610327Seric while (*p != '\0') 81710327Seric { 81858333Seric auto char *delimptr; 81958333Seric 82058050Seric while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p)))) 82110327Seric p++; 82210327Seric 82310327Seric /* p now points to field code */ 82410327Seric fcode = *p; 82510327Seric while (*p != '\0' && *p != '=' && *p != ',') 82610327Seric p++; 82710327Seric if (*p++ != '=') 82810327Seric { 82952637Seric syserr("mailer %s: `=' expected", m->m_name); 83010327Seric return; 83110327Seric } 83258050Seric while (isascii(*p) && isspace(*p)) 83310327Seric p++; 83410327Seric 83510327Seric /* p now points to the field body */ 83658333Seric p = munchstring(p, &delimptr); 83710327Seric 83810327Seric /* install the field into the mailer struct */ 83910327Seric switch (fcode) 84010327Seric { 84110327Seric case 'P': /* pathname */ 84210327Seric m->m_mailer = newstr(p); 84310327Seric break; 84410327Seric 84510327Seric case 'F': /* flags */ 84610687Seric for (; *p != '\0'; p++) 84758050Seric if (!(isascii(*p) && isspace(*p))) 84852637Seric setbitn(*p, m->m_flags); 84910327Seric break; 85010327Seric 85110327Seric case 'S': /* sender rewriting ruleset */ 85210327Seric case 'R': /* recipient rewriting ruleset */ 85358020Seric i = strtol(p, &endp, 10); 85410327Seric if (i < 0 || i >= MAXRWSETS) 85510327Seric { 85610327Seric syserr("invalid rewrite set, %d max", MAXRWSETS); 85710327Seric return; 85810327Seric } 85910327Seric if (fcode == 'S') 86058020Seric m->m_sh_rwset = m->m_se_rwset = i; 86110327Seric else 86258020Seric m->m_rh_rwset = m->m_re_rwset = i; 86358020Seric 86458020Seric p = endp; 86559985Seric if (*p++ == '/') 86658020Seric { 86758020Seric i = strtol(p, NULL, 10); 86858020Seric if (i < 0 || i >= MAXRWSETS) 86958020Seric { 87058020Seric syserr("invalid rewrite set, %d max", 87158020Seric MAXRWSETS); 87258020Seric return; 87358020Seric } 87458020Seric if (fcode == 'S') 87558020Seric m->m_sh_rwset = i; 87658020Seric else 87758020Seric m->m_rh_rwset = i; 87858020Seric } 87910327Seric break; 88010327Seric 88110327Seric case 'E': /* end of line string */ 88210327Seric m->m_eol = newstr(p); 88310327Seric break; 88410327Seric 88510327Seric case 'A': /* argument vector */ 88610327Seric m->m_argv = makeargv(p); 88710327Seric break; 88810701Seric 88910701Seric case 'M': /* maximum message size */ 89010701Seric m->m_maxsize = atol(p); 89110701Seric break; 89252106Seric 89352106Seric case 'L': /* maximum line length */ 89452106Seric m->m_linelimit = atoi(p); 89552106Seric break; 89658935Seric 89768816Seric case 'N': /* run niceness */ 89868816Seric m->m_nice = atoi(p); 89968816Seric break; 90068816Seric 90158935Seric case 'D': /* working directory */ 90258935Seric m->m_execdir = newstr(p); 90358935Seric break; 90468481Seric 90568481Seric case 'C': /* default charset */ 90668481Seric m->m_defcharset = newstr(p); 90768481Seric break; 90868481Seric 90968481Seric case 'T': /* MTA Type */ 91068481Seric m->m_mtatype = newstr(p); 91168481Seric p = strchr(m->m_mtatype, '/'); 91268481Seric if (p != NULL) 91368481Seric { 91468481Seric *p++ = '\0'; 91568481Seric if (*p == '\0') 91668481Seric p = NULL; 91768481Seric } 91868481Seric if (p == NULL) 91968481Seric m->m_addrtype = m->m_mtatype; 92068481Seric else 92168481Seric { 92268481Seric m->m_addrtype = p; 92368481Seric p = strchr(p, '/'); 92468481Seric } 92568481Seric if (p != NULL) 92668481Seric { 92768481Seric *p++ = '\0'; 92868481Seric if (*p == '\0') 92968481Seric p = NULL; 93068481Seric } 93168481Seric if (p == NULL) 93268481Seric m->m_diagtype = m->m_mtatype; 93368481Seric else 93468481Seric m->m_diagtype = p; 93568481Seric break; 93668481Seric 93768481Seric case 'U': /* user id */ 93868481Seric if (isascii(*p) && !isdigit(*p)) 93968481Seric { 94068481Seric char *q = p; 94168481Seric struct passwd *pw; 94268481Seric 94368481Seric while (isascii(*p) && isalnum(*p)) 94468481Seric p++; 94568481Seric while (isascii(*p) && isspace(*p)) 94668481Seric *p++ = '\0'; 94768481Seric if (*p != '\0') 94868481Seric *p++ = '\0'; 94968693Seric pw = sm_getpwnam(q); 95068481Seric if (pw == NULL) 95168481Seric syserr("readcf: mailer U= flag: unknown user %s", q); 95268481Seric else 95368481Seric { 95468481Seric m->m_uid = pw->pw_uid; 95568481Seric m->m_gid = pw->pw_gid; 95668481Seric } 95768481Seric } 95868481Seric else 95968481Seric { 96068481Seric auto char *q; 96168481Seric 96268481Seric m->m_uid = strtol(p, &q, 0); 96368481Seric p = q; 96468481Seric } 96568481Seric while (isascii(*p) && isspace(*p)) 96668481Seric p++; 96768481Seric if (*p == '\0') 96868481Seric break; 96968481Seric if (isascii(*p) && !isdigit(*p)) 97068481Seric { 97168481Seric char *q = p; 97268481Seric struct group *gr; 97368481Seric 97468481Seric while (isascii(*p) && isalnum(*p)) 97568481Seric p++; 97668481Seric *p++ = '\0'; 97768481Seric gr = getgrnam(q); 97868481Seric if (gr == NULL) 97968481Seric syserr("readcf: mailer U= flag: unknown group %s", q); 98068481Seric else 98168481Seric m->m_gid = gr->gr_gid; 98268481Seric } 98368481Seric else 98468481Seric { 98568481Seric m->m_gid = strtol(p, NULL, 0); 98668481Seric } 98768481Seric break; 98810327Seric } 98910327Seric 99058333Seric p = delimptr; 99110327Seric } 99210327Seric 99358321Seric /* do some rationality checking */ 99458321Seric if (m->m_argv == NULL) 99558321Seric { 99658321Seric syserr("M%s: A= argument required", m->m_name); 99758321Seric return; 99858321Seric } 99958321Seric if (m->m_mailer == NULL) 100058321Seric { 100158321Seric syserr("M%s: P= argument required", m->m_name); 100258321Seric return; 100358321Seric } 100458321Seric 10054096Seric if (NextMailer >= MAXMAILERS) 10064096Seric { 10079381Seric syserr("too many mailers defined (%d max)", MAXMAILERS); 10084096Seric return; 10094096Seric } 101057402Seric 101168481Seric /* do some heuristic cleanup for back compatibility */ 101268481Seric if (bitnset(M_LIMITS, m->m_flags)) 101368481Seric { 101468481Seric if (m->m_linelimit == 0) 101568481Seric m->m_linelimit = SMTPLINELIM; 101668481Seric if (ConfigLevel < 2) 101768481Seric setbitn(M_7BITS, m->m_flags); 101868481Seric } 101968481Seric 102068481Seric if (ConfigLevel < 6 && 102168481Seric (strcmp(m->m_mailer, "[IPC]") == 0 || 102268481Seric strcmp(m->m_mailer, "[TCP]") == 0)) 102368481Seric { 102468481Seric if (m->m_mtatype == NULL) 102568481Seric m->m_mtatype = "dns"; 102668481Seric if (m->m_addrtype == NULL) 102768481Seric m->m_addrtype = "rfc822"; 102868481Seric if (m->m_diagtype == NULL) 102968481Seric m->m_diagtype = "smtp"; 103068481Seric } 103168481Seric 103268481Seric /* enter the mailer into the symbol table */ 103310327Seric s = stab(m->m_name, ST_MAILER, ST_ENTER); 103457402Seric if (s->s_mailer != NULL) 103557402Seric { 103657402Seric i = s->s_mailer->m_mno; 103757402Seric free(s->s_mailer); 103857402Seric } 103957402Seric else 104057402Seric { 104157402Seric i = NextMailer++; 104257402Seric } 104357402Seric Mailer[i] = s->s_mailer = m; 104457454Seric m->m_mno = i; 104510327Seric } 104610327Seric /* 104710327Seric ** MUNCHSTRING -- translate a string into internal form. 104810327Seric ** 104910327Seric ** Parameters: 105010327Seric ** p -- the string to munch. 105158333Seric ** delimptr -- if non-NULL, set to the pointer of the 105258333Seric ** field delimiter character. 105310327Seric ** 105410327Seric ** Returns: 105510327Seric ** the munched string. 105610327Seric */ 10574096Seric 105810327Seric char * 105958333Seric munchstring(p, delimptr) 106010327Seric register char *p; 106158333Seric char **delimptr; 106210327Seric { 106310327Seric register char *q; 106410327Seric bool backslash = FALSE; 106510327Seric bool quotemode = FALSE; 106610327Seric static char buf[MAXLINE]; 10674096Seric 106810327Seric for (q = buf; *p != '\0'; p++) 10694096Seric { 107010327Seric if (backslash) 107110327Seric { 107210327Seric /* everything is roughly literal */ 107310357Seric backslash = FALSE; 107410327Seric switch (*p) 107510327Seric { 107610327Seric case 'r': /* carriage return */ 107710327Seric *q++ = '\r'; 107810327Seric continue; 107910327Seric 108010327Seric case 'n': /* newline */ 108110327Seric *q++ = '\n'; 108210327Seric continue; 108310327Seric 108410327Seric case 'f': /* form feed */ 108510327Seric *q++ = '\f'; 108610327Seric continue; 108710327Seric 108810327Seric case 'b': /* backspace */ 108910327Seric *q++ = '\b'; 109010327Seric continue; 109110327Seric } 109210327Seric *q++ = *p; 109310327Seric } 109410327Seric else 109510327Seric { 109610327Seric if (*p == '\\') 109710327Seric backslash = TRUE; 109810327Seric else if (*p == '"') 109910327Seric quotemode = !quotemode; 110010327Seric else if (quotemode || *p != ',') 110110327Seric *q++ = *p; 110210327Seric else 110310327Seric break; 110410327Seric } 11054096Seric } 11064096Seric 110758333Seric if (delimptr != NULL) 110858333Seric *delimptr = p; 110910327Seric *q++ = '\0'; 111010327Seric return (buf); 111110327Seric } 111210327Seric /* 111310327Seric ** MAKEARGV -- break up a string into words 111410327Seric ** 111510327Seric ** Parameters: 111610327Seric ** p -- the string to break up. 111710327Seric ** 111810327Seric ** Returns: 111910327Seric ** a char **argv (dynamically allocated) 112010327Seric ** 112110327Seric ** Side Effects: 112210327Seric ** munges p. 112310327Seric */ 11244096Seric 112510327Seric char ** 112610327Seric makeargv(p) 112710327Seric register char *p; 112810327Seric { 112910327Seric char *q; 113010327Seric int i; 113110327Seric char **avp; 113210327Seric char *argv[MAXPV + 1]; 113310327Seric 113410327Seric /* take apart the words */ 113510327Seric i = 0; 113610327Seric while (*p != '\0' && i < MAXPV) 11374096Seric { 113810327Seric q = p; 113958050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 114010327Seric p++; 114158050Seric while (isascii(*p) && isspace(*p)) 114210327Seric *p++ = '\0'; 114310327Seric argv[i++] = newstr(q); 11444096Seric } 114510327Seric argv[i++] = NULL; 11464096Seric 114710327Seric /* now make a copy of the argv */ 114810327Seric avp = (char **) xalloc(sizeof *avp * i); 114916893Seric bcopy((char *) argv, (char *) avp, sizeof *avp * i); 115010327Seric 115110327Seric return (avp); 11523308Seric } 11533308Seric /* 11543308Seric ** PRINTRULES -- print rewrite rules (for debugging) 11553308Seric ** 11563308Seric ** Parameters: 11573308Seric ** none. 11583308Seric ** 11593308Seric ** Returns: 11603308Seric ** none. 11613308Seric ** 11623308Seric ** Side Effects: 11633308Seric ** prints rewrite rules. 11643308Seric */ 11653308Seric 11663308Seric printrules() 11673308Seric { 11683308Seric register struct rewrite *rwp; 11694072Seric register int ruleset; 11703308Seric 11714072Seric for (ruleset = 0; ruleset < 10; ruleset++) 11723308Seric { 11734072Seric if (RewriteRules[ruleset] == NULL) 11744072Seric continue; 11758067Seric printf("\n----Rule Set %d:", ruleset); 11763308Seric 11774072Seric for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 11783308Seric { 11798067Seric printf("\nLHS:"); 11808067Seric printav(rwp->r_lhs); 11818067Seric printf("RHS:"); 11828067Seric printav(rwp->r_rhs); 11833308Seric } 11843308Seric } 11853308Seric } 118668481Seric /* 118768481Seric ** PRINTMAILER -- print mailer structure (for debugging) 118868481Seric ** 118968481Seric ** Parameters: 119068481Seric ** m -- the mailer to print 119168481Seric ** 119268481Seric ** Returns: 119368481Seric ** none. 119468481Seric */ 11954319Seric 119668481Seric printmailer(m) 119768481Seric register MAILER *m; 119868481Seric { 119968481Seric int j; 120068481Seric 120168481Seric printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld U=%d:%d F=", 120268481Seric m->m_mno, m->m_name, 120368481Seric m->m_mailer, m->m_se_rwset, m->m_sh_rwset, 120468481Seric m->m_re_rwset, m->m_rh_rwset, m->m_maxsize, 120568481Seric m->m_uid, m->m_gid); 120668481Seric for (j = '\0'; j <= '\177'; j++) 120768481Seric if (bitnset(j, m->m_flags)) 120868481Seric (void) putchar(j); 120968481Seric printf(" L=%d E=", m->m_linelimit); 121068481Seric xputs(m->m_eol); 121168481Seric if (m->m_defcharset != NULL) 121268481Seric printf(" C=%s", m->m_defcharset); 121368481Seric printf(" T=%s/%s/%s", 121468481Seric m->m_mtatype == NULL ? "<undefined>" : m->m_mtatype, 121568481Seric m->m_addrtype == NULL ? "<undefined>" : m->m_addrtype, 121668481Seric m->m_diagtype == NULL ? "<undefined>" : m->m_diagtype); 121768481Seric if (m->m_argv != NULL) 121868481Seric { 121968481Seric char **a = m->m_argv; 122068481Seric 122168481Seric printf(" A="); 122268481Seric while (*a != NULL) 122368481Seric { 122468481Seric if (a != m->m_argv) 122568481Seric printf(" "); 122668481Seric xputs(*a++); 122768481Seric } 122868481Seric } 122968481Seric printf("\n"); 123068481Seric } 12314096Seric /* 12328256Seric ** SETOPTION -- set global processing option 12338256Seric ** 12348256Seric ** Parameters: 12358256Seric ** opt -- option name. 12368256Seric ** val -- option value (as a text string). 123721755Seric ** safe -- set if this came from a configuration file. 123821755Seric ** Some options (if set from the command line) will 123921755Seric ** reset the user id to avoid security problems. 12408269Seric ** sticky -- if set, don't let other setoptions override 12418269Seric ** this value. 124258734Seric ** e -- the main envelope. 12438256Seric ** 12448256Seric ** Returns: 12458256Seric ** none. 12468256Seric ** 12478256Seric ** Side Effects: 12488256Seric ** Sets options as implied by the arguments. 12498256Seric */ 12508256Seric 125110687Seric static BITMAP StickyOpt; /* set if option is stuck */ 12528269Seric 125357207Seric 125466334Seric #if NAMED_BIND 125557207Seric 125657207Seric struct resolverflags 125757207Seric { 125857207Seric char *rf_name; /* name of the flag */ 125957207Seric long rf_bits; /* bits to set/clear */ 126057207Seric } ResolverFlags[] = 126157207Seric { 126257207Seric "debug", RES_DEBUG, 126357207Seric "aaonly", RES_AAONLY, 126457207Seric "usevc", RES_USEVC, 126557207Seric "primary", RES_PRIMARY, 126657207Seric "igntc", RES_IGNTC, 126757207Seric "recurse", RES_RECURSE, 126857207Seric "defnames", RES_DEFNAMES, 126957207Seric "stayopen", RES_STAYOPEN, 127057207Seric "dnsrch", RES_DNSRCH, 127165583Seric "true", 0, /* to avoid error on old syntax */ 127257207Seric NULL, 0 127357207Seric }; 127457207Seric 127557207Seric #endif 127657207Seric 127768481Seric struct optioninfo 127868481Seric { 127968481Seric char *o_name; /* long name of option */ 128068481Seric u_char o_code; /* short name of option */ 128168481Seric bool o_safe; /* safe for random people to use */ 128268481Seric } OptionTab[] = 128368481Seric { 128468481Seric "SevenBitInput", '7', TRUE, 128568481Seric "EightBitMode", '8', TRUE, 128668481Seric "AliasFile", 'A', FALSE, 128768481Seric "AliasWait", 'a', FALSE, 128868481Seric "BlankSub", 'B', FALSE, 128968481Seric "MinFreeBlocks", 'b', TRUE, 129068481Seric "CheckpointInterval", 'C', TRUE, 129168481Seric "HoldExpensive", 'c', FALSE, 129268481Seric "AutoRebuildAliases", 'D', FALSE, 129368481Seric "DeliveryMode", 'd', TRUE, 129468481Seric "ErrorHeader", 'E', FALSE, 129568481Seric "ErrorMode", 'e', TRUE, 129668481Seric "TempFileMode", 'F', FALSE, 129768481Seric "SaveFromLine", 'f', FALSE, 129868481Seric "MatchGECOS", 'G', FALSE, 129968481Seric "HelpFile", 'H', FALSE, 130068481Seric "MaxHopCount", 'h', FALSE, 130168569Seric "ResolverOptions", 'I', FALSE, 130268481Seric "IgnoreDots", 'i', TRUE, 130368481Seric "ForwardPath", 'J', FALSE, 130468481Seric "SendMimeErrors", 'j', TRUE, 130568481Seric "ConnectionCacheSize", 'k', FALSE, 130668481Seric "ConnectionCacheTimeout", 'K', FALSE, 130768481Seric "UseErrorsTo", 'l', FALSE, 130868481Seric "LogLevel", 'L', FALSE, 130968481Seric "MeToo", 'm', TRUE, 131068481Seric "CheckAliases", 'n', FALSE, 131168481Seric "OldStyleHeaders", 'o', TRUE, 131268481Seric "DaemonPortOptions", 'O', FALSE, 131368481Seric "PrivacyOptions", 'p', TRUE, 131468481Seric "PostmasterCopy", 'P', FALSE, 131568481Seric "QueueFactor", 'q', FALSE, 131668481Seric "QueueDirectory", 'Q', FALSE, 131768481Seric "DontPruneRoutes", 'R', FALSE, 131868481Seric "Timeout", 'r', TRUE, 131968481Seric "StatusFile", 'S', FALSE, 132068481Seric "SuperSafe", 's', TRUE, 132168481Seric "QueueTimeout", 'T', FALSE, 132268481Seric "TimeZoneSpec", 't', FALSE, 132368481Seric "UserDatabaseSpec", 'U', FALSE, 132468481Seric "DefaultUser", 'u', FALSE, 132568481Seric "FallbackMXhost", 'V', FALSE, 132668481Seric "Verbose", 'v', TRUE, 132768481Seric "TryNullMXList", 'w', TRUE, 132868481Seric "QueueLA", 'x', FALSE, 132968481Seric "RefuseLA", 'X', FALSE, 133068481Seric "RecipientFactor", 'y', FALSE, 133168569Seric "ForkEachJob", 'Y', FALSE, 133268481Seric "ClassFactor", 'z', FALSE, 133368569Seric "RetryFactor", 'Z', FALSE, 133468481Seric #define O_QUEUESORTORD 0x81 133568481Seric "QueueSortOrder", O_QUEUESORTORD, TRUE, 133669401Seric #define O_HOSTSFILE 0x82 133769401Seric "HostsFile", O_HOSTSFILE, FALSE, 133868481Seric #define O_MQA 0x83 133968481Seric "MinQueueAge", O_MQA, TRUE, 134068481Seric #define O_MHSA 0x84 134168481Seric /* 134268481Seric "MaxHostStatAge", O_MHSA, TRUE, 134368481Seric */ 134468481Seric #define O_DEFCHARSET 0x85 134568481Seric "DefaultCharSet", O_DEFCHARSET, TRUE, 134668481Seric #define O_SSFILE 0x86 134768481Seric "ServiceSwitchFile", O_SSFILE, FALSE, 134868481Seric #define O_DIALDELAY 0x87 134968481Seric "DialDelay", O_DIALDELAY, TRUE, 135068481Seric #define O_NORCPTACTION 0x88 135168481Seric "NoRecipientAction", O_NORCPTACTION, TRUE, 135268490Seric #define O_SAFEFILEENV 0x89 135368490Seric "SafeFileEnvironment", O_SAFEFILEENV, FALSE, 135468569Seric #define O_MAXMSGSIZE 0x8a 135568569Seric "MaxMessageSize", O_MAXMSGSIZE, FALSE, 135668756Seric #define O_COLONOKINADDR 0x8b 135768756Seric "ColonOkInAddr", O_COLONOKINADDR, TRUE, 135868481Seric 135968481Seric NULL, '\0', FALSE, 136068481Seric }; 136168481Seric 136268481Seric 136368481Seric 136458734Seric setoption(opt, val, safe, sticky, e) 136568481Seric u_char opt; 13668256Seric char *val; 136721755Seric bool safe; 13688269Seric bool sticky; 136958734Seric register ENVELOPE *e; 13708256Seric { 137157207Seric register char *p; 137268481Seric register struct optioninfo *o; 137368481Seric char *subopt; 13748265Seric extern bool atobool(); 137512633Seric extern time_t convtime(); 137614879Seric extern int QueueLA; 137714879Seric extern int RefuseLA; 137864718Seric extern bool Warn_Q_option; 13798256Seric 138068481Seric errno = 0; 138168481Seric if (opt == ' ') 138268481Seric { 138368481Seric /* full word options */ 138468481Seric struct optioninfo *sel; 138568481Seric 138668481Seric p = strchr(val, '='); 138768481Seric if (p == NULL) 138868481Seric p = &val[strlen(val)]; 138968481Seric while (*--p == ' ') 139068481Seric continue; 139168481Seric while (*++p == ' ') 139268481Seric *p = '\0'; 139368481Seric if (p == val) 139468481Seric { 139568481Seric syserr("readcf: null option name"); 139668481Seric return; 139768481Seric } 139868481Seric if (*p == '=') 139968481Seric *p++ = '\0'; 140068481Seric while (*p == ' ') 140168481Seric p++; 140268481Seric subopt = strchr(val, '.'); 140368481Seric if (subopt != NULL) 140468481Seric *subopt++ = '\0'; 140568481Seric sel = NULL; 140668481Seric for (o = OptionTab; o->o_name != NULL; o++) 140768481Seric { 140868481Seric if (strncasecmp(o->o_name, val, strlen(val)) != 0) 140968481Seric continue; 141068481Seric if (strlen(o->o_name) == strlen(val)) 141168481Seric { 141268481Seric /* completely specified -- this must be it */ 141368481Seric sel = NULL; 141468481Seric break; 141568481Seric } 141668481Seric if (sel != NULL) 141768481Seric break; 141868481Seric sel = o; 141968481Seric } 142068481Seric if (sel != NULL && o->o_name == NULL) 142168481Seric o = sel; 142268481Seric else if (o->o_name == NULL) 142368481Seric { 142468481Seric syserr("readcf: unknown option name %s", val); 142568481Seric return; 142668481Seric } 142768481Seric else if (sel != NULL) 142868481Seric { 142968481Seric syserr("readcf: ambiguous option name %s (matches %s and %s)", 143068481Seric val, sel->o_name, o->o_name); 143168481Seric return; 143268481Seric } 143368481Seric if (strlen(val) != strlen(o->o_name)) 143468481Seric { 143568481Seric bool oldVerbose = Verbose; 143668481Seric 143768481Seric Verbose = TRUE; 143868481Seric message("Option %s used as abbreviation for %s", 143968481Seric val, o->o_name); 144068481Seric Verbose = oldVerbose; 144168481Seric } 144268481Seric opt = o->o_code; 144368481Seric val = p; 144468481Seric } 144568481Seric else 144668481Seric { 144768481Seric for (o = OptionTab; o->o_name != NULL; o++) 144868481Seric { 144968481Seric if (o->o_code == opt) 145068481Seric break; 145168481Seric } 145268481Seric subopt = NULL; 145368481Seric } 145468481Seric 14558256Seric if (tTd(37, 1)) 145668481Seric { 145768481Seric printf(isascii(opt) && isprint(opt) ? 145868481Seric "setoption %s (%c).%s=%s" : 145968481Seric "setoption %s (0x%x).%s=%s", 146068481Seric o->o_name == NULL ? "<unknown>" : o->o_name, 146168481Seric opt, 146268481Seric subopt == NULL ? "" : subopt, 146368481Seric val); 146468481Seric } 14658256Seric 14668256Seric /* 14678269Seric ** See if this option is preset for us. 14688256Seric */ 14698256Seric 147059731Seric if (!sticky && bitnset(opt, StickyOpt)) 14718269Seric { 14729341Seric if (tTd(37, 1)) 14739341Seric printf(" (ignored)\n"); 14748269Seric return; 14758269Seric } 14768269Seric 147721755Seric /* 147821755Seric ** Check to see if this option can be specified by this user. 147921755Seric */ 148021755Seric 148163787Seric if (!safe && RealUid == 0) 148221755Seric safe = TRUE; 148368481Seric if (!safe && !o->o_safe) 148421755Seric { 148539111Srick if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 148621755Seric { 148736582Sbostic if (tTd(37, 1)) 148836582Sbostic printf(" (unsafe)"); 148963787Seric if (RealUid != geteuid()) 149036582Sbostic { 149151210Seric if (tTd(37, 1)) 149251210Seric printf("(Resetting uid)"); 149363787Seric (void) setgid(RealGid); 149463787Seric (void) setuid(RealUid); 149536582Sbostic } 149621755Seric } 149721755Seric } 149851210Seric if (tTd(37, 1)) 149917985Seric printf("\n"); 15008269Seric 150168481Seric switch (opt & 0xff) 15028256Seric { 150359709Seric case '7': /* force seven-bit input */ 150468481Seric SevenBitInput = atobool(val); 150552106Seric break; 150652106Seric 150768481Seric case '8': /* handling of 8-bit input */ 150868481Seric switch (*val) 150968481Seric { 151068481Seric case 'm': /* convert 8-bit, convert MIME */ 151168481Seric MimeMode = MM_CVTMIME|MM_MIME8BIT; 151268481Seric break; 151368481Seric 151468481Seric case 'p': /* pass 8 bit, convert MIME */ 151568856Seric MimeMode = MM_CVTMIME|MM_PASS8BIT; 151668481Seric break; 151768481Seric 151868481Seric case 's': /* strict adherence */ 151968481Seric MimeMode = MM_CVTMIME; 152068481Seric break; 152168481Seric 152268856Seric #if 0 152368856Seric case 'r': /* reject 8-bit, don't convert MIME */ 152468856Seric MimeMode = 0; 152568856Seric break; 152668856Seric 152768856Seric case 'j': /* "just send 8" */ 152868856Seric MimeMode = MM_PASS8BIT; 152968856Seric break; 153068856Seric 153168481Seric case 'a': /* encode 8 bit if available */ 153268481Seric MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 153368481Seric break; 153468481Seric 153568481Seric case 'c': /* convert 8 bit to MIME, never 7 bit */ 153668481Seric MimeMode = MM_MIME8BIT; 153768481Seric break; 153868856Seric #endif 153968481Seric 154068481Seric default: 154168481Seric syserr("Unknown 8-bit mode %c", *val); 154268481Seric exit(EX_USAGE); 154368481Seric } 154468481Seric break; 154568481Seric 15468256Seric case 'A': /* set default alias file */ 15479381Seric if (val[0] == '\0') 154859672Seric setalias("aliases"); 15499381Seric else 155059672Seric setalias(val); 15518256Seric break; 15528256Seric 155317474Seric case 'a': /* look N minutes for "@:@" in alias file */ 155417474Seric if (val[0] == '\0') 155564796Seric SafeAlias = 5 * 60; /* five minutes */ 155617474Seric else 155764796Seric SafeAlias = convtime(val, 'm'); 155817474Seric break; 155917474Seric 156016843Seric case 'B': /* substitution for blank character */ 156116843Seric SpaceSub = val[0]; 156216843Seric if (SpaceSub == '\0') 156316843Seric SpaceSub = ' '; 156416843Seric break; 156516843Seric 156659283Seric case 'b': /* min blocks free on queue fs/max msg size */ 156759283Seric p = strchr(val, '/'); 156859283Seric if (p != NULL) 156959283Seric { 157059283Seric *p++ = '\0'; 157159283Seric MaxMessageSize = atol(p); 157259283Seric } 157358082Seric MinBlocksFree = atol(val); 157458082Seric break; 157558082Seric 15769284Seric case 'c': /* don't connect to "expensive" mailers */ 15779381Seric NoConnect = atobool(val); 15789284Seric break; 15799284Seric 158051305Seric case 'C': /* checkpoint every N addresses */ 158151305Seric CheckpointInterval = atoi(val); 158224944Seric break; 158324944Seric 15849284Seric case 'd': /* delivery mode */ 15859284Seric switch (*val) 15868269Seric { 15879284Seric case '\0': 158858734Seric e->e_sendmode = SM_DELIVER; 15898269Seric break; 15908269Seric 159110755Seric case SM_QUEUE: /* queue only */ 159210755Seric #ifndef QUEUE 159310755Seric syserr("need QUEUE to set -odqueue"); 159456795Seric #endif /* QUEUE */ 159510755Seric /* fall through..... */ 159610755Seric 15979284Seric case SM_DELIVER: /* do everything */ 15989284Seric case SM_FORK: /* fork after verification */ 159958734Seric e->e_sendmode = *val; 16008269Seric break; 16018269Seric 16028269Seric default: 16039284Seric syserr("Unknown delivery mode %c", *val); 16048269Seric exit(EX_USAGE); 16058269Seric } 16068269Seric break; 16078269Seric 16089146Seric case 'D': /* rebuild alias database as needed */ 16099381Seric AutoRebuild = atobool(val); 16109146Seric break; 16119146Seric 161255372Seric case 'E': /* error message header/header file */ 161355379Seric if (*val != '\0') 161455379Seric ErrMsgFile = newstr(val); 161555372Seric break; 161655372Seric 16178269Seric case 'e': /* set error processing mode */ 16188269Seric switch (*val) 16198269Seric { 16209381Seric case EM_QUIET: /* be silent about it */ 16219381Seric case EM_MAIL: /* mail back */ 16229381Seric case EM_BERKNET: /* do berknet error processing */ 16239381Seric case EM_WRITE: /* write back (or mail) */ 16249381Seric case EM_PRINT: /* print errors normally (default) */ 162558734Seric e->e_errormode = *val; 16268269Seric break; 16278269Seric } 16288269Seric break; 16298269Seric 16309049Seric case 'F': /* file mode */ 163117975Seric FileMode = atooct(val) & 0777; 16329049Seric break; 16339049Seric 16348269Seric case 'f': /* save Unix-style From lines on front */ 16359381Seric SaveFrom = atobool(val); 16368269Seric break; 16378269Seric 163853735Seric case 'G': /* match recipients against GECOS field */ 163953735Seric MatchGecos = atobool(val); 164053735Seric break; 164153735Seric 16428256Seric case 'g': /* default gid */ 164368481Seric g_opt: 164464133Seric if (isascii(*val) && isdigit(*val)) 164564133Seric DefGid = atoi(val); 164664133Seric else 164764133Seric { 164864133Seric register struct group *gr; 164964133Seric 165064133Seric DefGid = -1; 165164133Seric gr = getgrnam(val); 165264133Seric if (gr == NULL) 165368481Seric syserr("readcf: option %c: unknown group %s", 165468481Seric opt, val); 165564133Seric else 165664133Seric DefGid = gr->gr_gid; 165764133Seric } 16588256Seric break; 16598256Seric 16608256Seric case 'H': /* help file */ 16619381Seric if (val[0] == '\0') 16628269Seric HelpFile = "sendmail.hf"; 16639381Seric else 16649381Seric HelpFile = newstr(val); 16658256Seric break; 16668256Seric 166751305Seric case 'h': /* maximum hop count */ 166851305Seric MaxHopCount = atoi(val); 166951305Seric break; 167051305Seric 167135651Seric case 'I': /* use internet domain name server */ 167266334Seric #if NAMED_BIND 167357207Seric for (p = val; *p != 0; ) 167457207Seric { 167557207Seric bool clearmode; 167657207Seric char *q; 167757207Seric struct resolverflags *rfp; 167857207Seric 167957207Seric while (*p == ' ') 168057207Seric p++; 168157207Seric if (*p == '\0') 168257207Seric break; 168357207Seric clearmode = FALSE; 168457207Seric if (*p == '-') 168557207Seric clearmode = TRUE; 168657207Seric else if (*p != '+') 168757207Seric p--; 168857207Seric p++; 168957207Seric q = p; 169058050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 169157207Seric p++; 169257207Seric if (*p != '\0') 169357207Seric *p++ = '\0'; 169468759Seric if (strcasecmp(q, "HasWildcardMX") == 0) 169568759Seric { 169668759Seric NoMXforCanon = !clearmode; 169768759Seric continue; 169868759Seric } 169957207Seric for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 170057207Seric { 170157207Seric if (strcasecmp(q, rfp->rf_name) == 0) 170257207Seric break; 170357207Seric } 170464923Seric if (rfp->rf_name == NULL) 170564923Seric syserr("readcf: I option value %s unrecognized", q); 170664923Seric else if (clearmode) 170757207Seric _res.options &= ~rfp->rf_bits; 170857207Seric else 170957207Seric _res.options |= rfp->rf_bits; 171057207Seric } 171157207Seric if (tTd(8, 2)) 171268759Seric printf("_res.options = %x, HasWildcardMX = %d\n", 171368759Seric _res.options, !NoMXforCanon); 171457207Seric #else 171557207Seric usrerr("name server (I option) specified but BIND not compiled in"); 171657207Seric #endif 171735651Seric break; 171835651Seric 17198269Seric case 'i': /* ignore dot lines in message */ 17209381Seric IgnrDot = atobool(val); 17218269Seric break; 17228269Seric 172359730Seric case 'j': /* send errors in MIME (RFC 1341) format */ 172459730Seric SendMIMEErrors = atobool(val); 172559730Seric break; 172659730Seric 172757136Seric case 'J': /* .forward search path */ 172857136Seric ForwardPath = newstr(val); 172957136Seric break; 173057136Seric 173154967Seric case 'k': /* connection cache size */ 173254967Seric MaxMciCache = atoi(val); 173356215Seric if (MaxMciCache < 0) 173456215Seric MaxMciCache = 0; 173554967Seric break; 173654967Seric 173754967Seric case 'K': /* connection cache timeout */ 173858796Seric MciCacheTimeout = convtime(val, 'm'); 173954967Seric break; 174054967Seric 174161104Seric case 'l': /* use Errors-To: header */ 174261104Seric UseErrorsTo = atobool(val); 174361104Seric break; 174461104Seric 17458256Seric case 'L': /* log level */ 174664140Seric if (safe || LogLevel < atoi(val)) 174764140Seric LogLevel = atoi(val); 17488256Seric break; 17498256Seric 17508269Seric case 'M': /* define macro */ 175168267Seric p = newstr(&val[1]); 175268267Seric if (!safe) 175368267Seric cleanstrcpy(p, p, MAXNAME); 175468267Seric define(val[0], p, CurEnv); 175516878Seric sticky = FALSE; 17568269Seric break; 17578269Seric 17588269Seric case 'm': /* send to me too */ 17599381Seric MeToo = atobool(val); 17608269Seric break; 17618269Seric 176225820Seric case 'n': /* validate RHS in newaliases */ 176325820Seric CheckAliases = atobool(val); 176425820Seric break; 176525820Seric 176661104Seric /* 'N' available -- was "net name" */ 176761104Seric 176858851Seric case 'O': /* daemon options */ 176958851Seric setdaemonoptions(val); 177058851Seric break; 177158851Seric 17728269Seric case 'o': /* assume old style headers */ 17739381Seric if (atobool(val)) 17749341Seric CurEnv->e_flags |= EF_OLDSTYLE; 17759341Seric else 17769341Seric CurEnv->e_flags &= ~EF_OLDSTYLE; 17778269Seric break; 17788269Seric 177958082Seric case 'p': /* select privacy level */ 178058082Seric p = val; 178158082Seric for (;;) 178258082Seric { 178358082Seric register struct prival *pv; 178458082Seric extern struct prival PrivacyValues[]; 178558082Seric 178658082Seric while (isascii(*p) && (isspace(*p) || ispunct(*p))) 178758082Seric p++; 178858082Seric if (*p == '\0') 178958082Seric break; 179058082Seric val = p; 179158082Seric while (isascii(*p) && isalnum(*p)) 179258082Seric p++; 179358082Seric if (*p != '\0') 179458082Seric *p++ = '\0'; 179558082Seric 179658082Seric for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 179758082Seric { 179858082Seric if (strcasecmp(val, pv->pv_name) == 0) 179958082Seric break; 180058082Seric } 180158886Seric if (pv->pv_name == NULL) 180258886Seric syserr("readcf: Op line: %s unrecognized", val); 180358082Seric PrivacyFlags |= pv->pv_flag; 180458082Seric } 180568479Seric sticky = FALSE; 180658082Seric break; 180758082Seric 180824944Seric case 'P': /* postmaster copy address for returned mail */ 180924944Seric PostMasterCopy = newstr(val); 181024944Seric break; 181124944Seric 181224944Seric case 'q': /* slope of queue only function */ 181324944Seric QueueFactor = atoi(val); 181424944Seric break; 181524944Seric 18168256Seric case 'Q': /* queue directory */ 18179381Seric if (val[0] == '\0') 18188269Seric QueueDir = "mqueue"; 18199381Seric else 18209381Seric QueueDir = newstr(val); 182158789Seric if (RealUid != 0 && !safe) 182264718Seric Warn_Q_option = TRUE; 18238256Seric break; 18248256Seric 182558148Seric case 'R': /* don't prune routes */ 182658148Seric DontPruneRoutes = atobool(val); 182758148Seric break; 182858148Seric 18298256Seric case 'r': /* read timeout */ 183068481Seric if (subopt == NULL) 183168481Seric inittimeouts(val); 183268481Seric else 183368481Seric settimeout(subopt, val); 18348256Seric break; 18358256Seric 18368256Seric case 'S': /* status file */ 18379381Seric if (val[0] == '\0') 18388269Seric StatFile = "sendmail.st"; 18399381Seric else 18409381Seric StatFile = newstr(val); 18418256Seric break; 18428256Seric 18438265Seric case 's': /* be super safe, even if expensive */ 18449381Seric SuperSafe = atobool(val); 18458256Seric break; 18468256Seric 18478256Seric case 'T': /* queue timeout */ 184858737Seric p = strchr(val, '/'); 184958737Seric if (p != NULL) 185058737Seric { 185158737Seric *p++ = '\0'; 185268481Seric settimeout("queuewarn", p); 185358737Seric } 185468481Seric settimeout("queuereturn", val); 185554967Seric break; 18568256Seric 18578265Seric case 't': /* time zone name */ 185852106Seric TimeZoneSpec = newstr(val); 18598265Seric break; 18608265Seric 186150556Seric case 'U': /* location of user database */ 186251360Seric UdbSpec = newstr(val); 186350556Seric break; 186450556Seric 18658256Seric case 'u': /* set default uid */ 186668481Seric for (p = val; *p != '\0'; p++) 186768481Seric { 186868481Seric if (*p == '.' || *p == '/' || *p == ':') 186968481Seric { 187068481Seric *p++ = '\0'; 187168481Seric break; 187268481Seric } 187368481Seric } 187464133Seric if (isascii(*val) && isdigit(*val)) 187564133Seric DefUid = atoi(val); 187664133Seric else 187764133Seric { 187864133Seric register struct passwd *pw; 187964133Seric 188064133Seric DefUid = -1; 188168693Seric pw = sm_getpwnam(val); 188264133Seric if (pw == NULL) 188364133Seric syserr("readcf: option u: unknown user %s", val); 188464133Seric else 188568481Seric { 188664133Seric DefUid = pw->pw_uid; 188768481Seric DefGid = pw->pw_gid; 188868481Seric } 188964133Seric } 189040973Sbostic setdefuser(); 18918256Seric 189268481Seric /* handle the group if it is there */ 189368481Seric if (*p == '\0') 189468481Seric break; 189568481Seric val = p; 189668481Seric goto g_opt; 189768481Seric 189858851Seric case 'V': /* fallback MX host */ 189958851Seric FallBackMX = newstr(val); 190058851Seric break; 190158851Seric 19028269Seric case 'v': /* run in verbose mode */ 19039381Seric Verbose = atobool(val); 19048256Seric break; 19058256Seric 190663837Seric case 'w': /* if we are best MX, try host directly */ 190763837Seric TryNullMXList = atobool(val); 190863837Seric break; 190961104Seric 191061104Seric /* 'W' available -- was wizard password */ 191161104Seric 191214879Seric case 'x': /* load avg at which to auto-queue msgs */ 191314879Seric QueueLA = atoi(val); 191414879Seric break; 191514879Seric 191614879Seric case 'X': /* load avg at which to auto-reject connections */ 191714879Seric RefuseLA = atoi(val); 191814879Seric break; 191914879Seric 192024981Seric case 'y': /* work recipient factor */ 192124981Seric WkRecipFact = atoi(val); 192224981Seric break; 192324981Seric 192424981Seric case 'Y': /* fork jobs during queue runs */ 192524952Seric ForkQueueRuns = atobool(val); 192624952Seric break; 192724952Seric 192824981Seric case 'z': /* work message class factor */ 192924981Seric WkClassFact = atoi(val); 193024981Seric break; 193124981Seric 193224981Seric case 'Z': /* work time factor */ 193324981Seric WkTimeFact = atoi(val); 193424981Seric break; 193524981Seric 193668481Seric case O_QUEUESORTORD: /* queue sorting order */ 193768481Seric switch (*val) 193868481Seric { 193968481Seric case 'h': /* Host first */ 194068481Seric case 'H': 194168481Seric QueueSortOrder = QS_BYHOST; 194268481Seric break; 194368481Seric 194468481Seric case 'p': /* Priority order */ 194568481Seric case 'P': 194668481Seric QueueSortOrder = QS_BYPRIORITY; 194768481Seric break; 194868481Seric 194968481Seric default: 195068481Seric syserr("Invalid queue sort order \"%s\"", val); 195168481Seric } 195268481Seric break; 195368481Seric 195469401Seric case O_HOSTSFILE: /* pathname of /etc/hosts file */ 195569401Seric HostsFile = newstr(val); 195669401Seric break; 195769401Seric 195868481Seric case O_MQA: /* minimum queue age between deliveries */ 195968481Seric MinQueueAge = convtime(val, 'm'); 196068481Seric break; 196168481Seric 196268481Seric case O_MHSA: /* maximum age of cached host status */ 196368481Seric MaxHostStatAge = convtime(val, 'm'); 196468481Seric break; 196568481Seric 196668481Seric case O_DEFCHARSET: /* default character set for mimefying */ 196768481Seric DefaultCharSet = newstr(denlstring(val, TRUE, TRUE)); 196868481Seric break; 196968481Seric 197068481Seric case O_SSFILE: /* service switch file */ 197168481Seric ServiceSwitchFile = newstr(val); 197268481Seric break; 197368481Seric 197468481Seric case O_DIALDELAY: /* delay for dial-on-demand operation */ 197568481Seric DialDelay = convtime(val, 's'); 197668481Seric break; 197768481Seric 197868481Seric case O_NORCPTACTION: /* what to do if no recipient */ 197968481Seric if (strcasecmp(val, "none") == 0) 198068481Seric NoRecipientAction = NRA_NO_ACTION; 198168481Seric else if (strcasecmp(val, "add-to") == 0) 198268481Seric NoRecipientAction = NRA_ADD_TO; 198368481Seric else if (strcasecmp(val, "add-apparently-to") == 0) 198468481Seric NoRecipientAction = NRA_ADD_APPARENTLY_TO; 198568481Seric else if (strcasecmp(val, "add-bcc") == 0) 198668481Seric NoRecipientAction = NRA_ADD_BCC; 198768481Seric else if (strcasecmp(val, "add-to-undisclosed") == 0) 198868481Seric NoRecipientAction = NRA_ADD_TO_UNDISCLOSED; 198968481Seric else 199068481Seric syserr("Invalid NoRecipientAction: %s", val); 199168481Seric 199268490Seric case O_SAFEFILEENV: /* chroot() environ for writing to files */ 199368490Seric SafeFileEnv = newstr(val); 199468490Seric break; 199568490Seric 199668569Seric case O_MAXMSGSIZE: /* maximum message size */ 199768569Seric MaxMessageSize = atol(p); 199868569Seric break; 199968569Seric 200068756Seric case O_COLONOKINADDR: /* old style handling of colon addresses */ 200168756Seric ColonOkInAddr = atobool(p); 200268756Seric break; 200368756Seric 20048256Seric default: 200568481Seric if (tTd(37, 1)) 200668481Seric { 200768481Seric if (isascii(opt) && isprint(opt)) 200868481Seric printf("Warning: option %c unknown\n", opt); 200968481Seric else 201068481Seric printf("Warning: option 0x%x unknown\n", opt); 201168481Seric } 20128256Seric break; 20138256Seric } 201416878Seric if (sticky) 201516878Seric setbitn(opt, StickyOpt); 20169188Seric return; 20178256Seric } 201810687Seric /* 201968481Seric ** SETCLASS -- set a string into a class 202010687Seric ** 202110687Seric ** Parameters: 202268481Seric ** class -- the class to put the string in. 202368481Seric ** str -- the string to enter 202410687Seric ** 202510687Seric ** Returns: 202610687Seric ** none. 202710687Seric ** 202810687Seric ** Side Effects: 202910687Seric ** puts the word into the symbol table. 203010687Seric */ 203110687Seric 203268481Seric setclass(class, str) 203310687Seric int class; 203468481Seric char *str; 203510687Seric { 203610687Seric register STAB *s; 203710687Seric 203857943Seric if (tTd(37, 8)) 203968481Seric printf("setclass(%c, %s)\n", class, str); 204068481Seric s = stab(str, ST_CLASS, ST_ENTER); 204110687Seric setbitn(class, s->s_class); 204210687Seric } 204353654Seric /* 204453654Seric ** MAKEMAPENTRY -- create a map entry 204553654Seric ** 204653654Seric ** Parameters: 204753654Seric ** line -- the config file line 204853654Seric ** 204953654Seric ** Returns: 205053654Seric ** TRUE if it successfully entered the map entry. 205153654Seric ** FALSE otherwise (usually syntax error). 205253654Seric ** 205353654Seric ** Side Effects: 205453654Seric ** Enters the map into the dictionary. 205553654Seric */ 205653654Seric 205753654Seric void 205853654Seric makemapentry(line) 205953654Seric char *line; 206053654Seric { 206153654Seric register char *p; 206253654Seric char *mapname; 206353654Seric char *classname; 206464078Seric register STAB *s; 206553654Seric STAB *class; 206653654Seric 206758050Seric for (p = line; isascii(*p) && isspace(*p); p++) 206853654Seric continue; 206958050Seric if (!(isascii(*p) && isalnum(*p))) 207053654Seric { 207153654Seric syserr("readcf: config K line: no map name"); 207253654Seric return; 207353654Seric } 207453654Seric 207553654Seric mapname = p; 207668481Seric while ((isascii(*++p) && isalnum(*p)) || *p == '.') 207753654Seric continue; 207853654Seric if (*p != '\0') 207953654Seric *p++ = '\0'; 208058050Seric while (isascii(*p) && isspace(*p)) 208153654Seric p++; 208258050Seric if (!(isascii(*p) && isalnum(*p))) 208353654Seric { 208453654Seric syserr("readcf: config K line, map %s: no map class", mapname); 208553654Seric return; 208653654Seric } 208753654Seric classname = p; 208858050Seric while (isascii(*++p) && isalnum(*p)) 208953654Seric continue; 209053654Seric if (*p != '\0') 209153654Seric *p++ = '\0'; 209258050Seric while (isascii(*p) && isspace(*p)) 209353654Seric p++; 209453654Seric 209553654Seric /* look up the class */ 209653654Seric class = stab(classname, ST_MAPCLASS, ST_FIND); 209753654Seric if (class == NULL) 209853654Seric { 209953654Seric syserr("readcf: map %s: class %s not available", mapname, classname); 210053654Seric return; 210153654Seric } 210253654Seric 210353654Seric /* enter the map */ 210464078Seric s = stab(mapname, ST_MAP, ST_ENTER); 210564078Seric s->s_map.map_class = &class->s_mapclass; 210664078Seric s->s_map.map_mname = newstr(mapname); 210753654Seric 210864078Seric if (class->s_mapclass.map_parse(&s->s_map, p)) 210964078Seric s->s_map.map_mflags |= MF_VALID; 211064078Seric 211164078Seric if (tTd(37, 5)) 211264078Seric { 211364078Seric printf("map %s, class %s, flags %x, file %s,\n", 211464078Seric s->s_map.map_mname, s->s_map.map_class->map_cname, 211564078Seric s->s_map.map_mflags, 211664078Seric s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 211764078Seric printf("\tapp %s, domain %s, rebuild %s\n", 211864078Seric s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 211964078Seric s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 212064078Seric s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 212164078Seric } 212253654Seric } 212358112Seric /* 212468481Seric ** INITTIMEOUTS -- parse and set timeout values 212558112Seric ** 212658112Seric ** Parameters: 212758112Seric ** val -- a pointer to the values. If NULL, do initial 212858112Seric ** settings. 212958112Seric ** 213058112Seric ** Returns: 213158112Seric ** none. 213258112Seric ** 213358112Seric ** Side Effects: 213458112Seric ** Initializes the TimeOuts structure 213558112Seric */ 213658112Seric 213764255Seric #define SECONDS 213858112Seric #define MINUTES * 60 213958112Seric #define HOUR * 3600 214058112Seric 214168481Seric inittimeouts(val) 214258112Seric register char *val; 214358112Seric { 214458112Seric register char *p; 214558671Seric extern time_t convtime(); 214658112Seric 214758112Seric if (val == NULL) 214858112Seric { 214958112Seric TimeOuts.to_initial = (time_t) 5 MINUTES; 215058112Seric TimeOuts.to_helo = (time_t) 5 MINUTES; 215158112Seric TimeOuts.to_mail = (time_t) 10 MINUTES; 215258112Seric TimeOuts.to_rcpt = (time_t) 1 HOUR; 215358112Seric TimeOuts.to_datainit = (time_t) 5 MINUTES; 215458112Seric TimeOuts.to_datablock = (time_t) 1 HOUR; 215558112Seric TimeOuts.to_datafinal = (time_t) 1 HOUR; 215658112Seric TimeOuts.to_rset = (time_t) 5 MINUTES; 215758112Seric TimeOuts.to_quit = (time_t) 2 MINUTES; 215858112Seric TimeOuts.to_nextcommand = (time_t) 1 HOUR; 215958112Seric TimeOuts.to_miscshort = (time_t) 2 MINUTES; 216068481Seric #if IDENTPROTO 216164255Seric TimeOuts.to_ident = (time_t) 30 SECONDS; 216268481Seric #else 216368481Seric TimeOuts.to_ident = (time_t) 0 SECONDS; 216468481Seric #endif 216568481Seric TimeOuts.to_fileopen = (time_t) 60 SECONDS; 216658112Seric return; 216758112Seric } 216858112Seric 216958112Seric for (;; val = p) 217058112Seric { 217158112Seric while (isascii(*val) && isspace(*val)) 217258112Seric val++; 217358112Seric if (*val == '\0') 217458112Seric break; 217558112Seric for (p = val; *p != '\0' && *p != ','; p++) 217658112Seric continue; 217758112Seric if (*p != '\0') 217858112Seric *p++ = '\0'; 217958112Seric 218058112Seric if (isascii(*val) && isdigit(*val)) 218158112Seric { 218258112Seric /* old syntax -- set everything */ 218358796Seric TimeOuts.to_mail = convtime(val, 'm'); 218458112Seric TimeOuts.to_rcpt = TimeOuts.to_mail; 218558112Seric TimeOuts.to_datainit = TimeOuts.to_mail; 218658112Seric TimeOuts.to_datablock = TimeOuts.to_mail; 218758112Seric TimeOuts.to_datafinal = TimeOuts.to_mail; 218858112Seric TimeOuts.to_nextcommand = TimeOuts.to_mail; 218958112Seric continue; 219058112Seric } 219158112Seric else 219258112Seric { 219368481Seric register char *q = strchr(val, ':'); 219458112Seric 219568481Seric if (q == NULL && (q = strchr(val, '=')) == NULL) 219658112Seric { 219758112Seric /* syntax error */ 219858112Seric continue; 219958112Seric } 220058112Seric *q++ = '\0'; 220168481Seric settimeout(val, q); 220268481Seric } 220368481Seric } 220468481Seric } 220568481Seric /* 220668481Seric ** SETTIMEOUT -- set an individual timeout 220768481Seric ** 220868481Seric ** Parameters: 220968481Seric ** name -- the name of the timeout. 221068481Seric ** val -- the value of the timeout. 221168481Seric ** 221268481Seric ** Returns: 221368481Seric ** none. 221468481Seric */ 221558112Seric 221668481Seric settimeout(name, val) 221768481Seric char *name; 221868481Seric char *val; 221968481Seric { 222068481Seric register char *p; 222168481Seric time_t to; 222268481Seric extern time_t convtime(); 222368481Seric 222468481Seric to = convtime(val, 'm'); 222568481Seric p = strchr(name, '.'); 222668481Seric if (p != NULL) 222768481Seric *p++ = '\0'; 222868481Seric 222968481Seric if (strcasecmp(name, "initial") == 0) 223068481Seric TimeOuts.to_initial = to; 223168481Seric else if (strcasecmp(name, "mail") == 0) 223268481Seric TimeOuts.to_mail = to; 223368481Seric else if (strcasecmp(name, "rcpt") == 0) 223468481Seric TimeOuts.to_rcpt = to; 223568481Seric else if (strcasecmp(name, "datainit") == 0) 223668481Seric TimeOuts.to_datainit = to; 223768481Seric else if (strcasecmp(name, "datablock") == 0) 223868481Seric TimeOuts.to_datablock = to; 223968481Seric else if (strcasecmp(name, "datafinal") == 0) 224068481Seric TimeOuts.to_datafinal = to; 224168481Seric else if (strcasecmp(name, "command") == 0) 224268481Seric TimeOuts.to_nextcommand = to; 224368481Seric else if (strcasecmp(name, "rset") == 0) 224468481Seric TimeOuts.to_rset = to; 224568481Seric else if (strcasecmp(name, "helo") == 0) 224668481Seric TimeOuts.to_helo = to; 224768481Seric else if (strcasecmp(name, "quit") == 0) 224868481Seric TimeOuts.to_quit = to; 224968481Seric else if (strcasecmp(name, "misc") == 0) 225068481Seric TimeOuts.to_miscshort = to; 225168481Seric else if (strcasecmp(name, "ident") == 0) 225268481Seric TimeOuts.to_ident = to; 225368481Seric else if (strcasecmp(name, "fileopen") == 0) 225468481Seric TimeOuts.to_fileopen = to; 225568481Seric else if (strcasecmp(name, "queuewarn") == 0) 225668481Seric { 225768481Seric to = convtime(val, 'h'); 225868481Seric if (p == NULL || strcmp(p, "*") == 0) 225968481Seric { 226068481Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 226168481Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 226268481Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 226358112Seric } 226468481Seric else if (strcasecmp(p, "normal") == 0) 226568481Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 226668481Seric else if (strcasecmp(p, "urgent") == 0) 226768481Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 226868481Seric else if (strcasecmp(p, "non-urgent") == 0) 226968481Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 227068481Seric else 227168481Seric syserr("settimeout: invalid queuewarn subtimeout %s", p); 227258112Seric } 227368481Seric else if (strcasecmp(name, "queuereturn") == 0) 227468481Seric { 227568481Seric to = convtime(val, 'd'); 227668481Seric if (p == NULL || strcmp(p, "*") == 0) 227768481Seric { 227868481Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 227968481Seric TimeOuts.to_q_return[TOC_URGENT] = to; 228068481Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 228168481Seric } 228268481Seric else if (strcasecmp(p, "normal") == 0) 228368481Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 228468481Seric else if (strcasecmp(p, "urgent") == 0) 228568481Seric TimeOuts.to_q_return[TOC_URGENT] = to; 228668481Seric else if (strcasecmp(p, "non-urgent") == 0) 228768481Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 228868481Seric else 228968481Seric syserr("settimeout: invalid queuereturn subtimeout %s", p); 229068481Seric } 229168481Seric else 229268481Seric syserr("settimeout: invalid timeout %s", name); 229358112Seric } 2294