122709Sdist /* 234921Sbostic * Copyright (c) 1983 Eric P. Allman 362530Sbostic * Copyright (c) 1988, 1993 462530Sbostic * The Regents of the University of California. All rights reserved. 533731Sbostic * 642829Sbostic * %sccs.include.redist.c% 733731Sbostic */ 822709Sdist 922709Sdist #ifndef lint 10*68805Seric static char sccsid[] = "@(#)readcf.c 8.84 (Berkeley) 04/19/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); 535*68805Seric 536*68805Seric /* 537*68805Seric ** Do heuristic tweaking for back compatibility. 538*68805Seric */ 539*68805Seric 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 } 547*68805Seric if (ConfigLevel >= 6) 548*68805Seric { 549*68805Seric ColonOkInAddr = FALSE; 550*68805Seric } 551*68805Seric 552*68805Seric /* 553*68805Seric ** Look for vendor code. 554*68805Seric */ 555*68805Seric 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; 6754432Seric char buf[MAXLINE]; 6764432Seric 67766101Seric if (tTd(37, 2)) 67866101Seric printf("fileclass(%s, fmt=%s)\n", filename, fmt); 67966101Seric 68066031Seric if (filename[0] == '|') 68166031Seric { 68266031Seric syserr("fileclass: pipes (F%c%s) not supported due to security problems", 68366031Seric class, filename); 68466031Seric return; 68566031Seric } 68668513Seric sff = SFF_REGONLY; 68768513Seric if (safe) 68868513Seric sff |= SFF_OPENASROOT; 68968513Seric f = safefopen(filename, O_RDONLY, 0, sff); 69068602Seric if (f == NULL) 69154973Seric { 69268602Seric if (!optional) 69368602Seric syserr("fileclass: cannot open %s", filename); 6944432Seric return; 6954432Seric } 6964432Seric 6974432Seric while (fgets(buf, sizeof buf, f) != NULL) 6984432Seric { 6994432Seric register STAB *s; 70025808Seric register char *p; 70125808Seric # ifdef SCANF 7024432Seric char wordbuf[MAXNAME+1]; 7034432Seric 7044432Seric if (sscanf(buf, fmt, wordbuf) != 1) 7054432Seric continue; 70625808Seric p = wordbuf; 70756795Seric # else /* SCANF */ 70825808Seric p = buf; 70956795Seric # endif /* SCANF */ 71025808Seric 71125808Seric /* 71225808Seric ** Break up the match into words. 71325808Seric */ 71425808Seric 71525808Seric while (*p != '\0') 71625808Seric { 71725808Seric register char *q; 71825808Seric 71925808Seric /* strip leading spaces */ 72058050Seric while (isascii(*p) && isspace(*p)) 72125808Seric p++; 72225808Seric if (*p == '\0') 72325808Seric break; 72425808Seric 72525808Seric /* find the end of the word */ 72625808Seric q = p; 72758050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 72825808Seric p++; 72925808Seric if (*p != '\0') 73025808Seric *p++ = '\0'; 73125808Seric 73225808Seric /* enter the word in the symbol table */ 73366101Seric setclass(class, q); 73425808Seric } 7354432Seric } 7364432Seric 73754973Seric (void) fclose(f); 7384432Seric } 7394432Seric /* 7404096Seric ** MAKEMAILER -- define a new mailer. 7414096Seric ** 7424096Seric ** Parameters: 74310327Seric ** line -- description of mailer. This is in labeled 74410327Seric ** fields. The fields are: 74568481Seric ** A -- the argv for this mailer 74668481Seric ** C -- the character set for MIME conversions 74768481Seric ** D -- the directory to run in 74868481Seric ** E -- the eol string 74968481Seric ** F -- the flags associated with the mailer 75068481Seric ** L -- the maximum line length 75168481Seric ** M -- the maximum message size 75268479Seric ** P -- the path to the mailer 75368481Seric ** R -- the recipient rewriting set 75468479Seric ** S -- the sender rewriting set 75568481Seric ** T -- the mailer type (for DSNs) 75668481Seric ** U -- the uid to run as 75710327Seric ** The first word is the canonical name of the mailer. 7584096Seric ** 7594096Seric ** Returns: 7604096Seric ** none. 7614096Seric ** 7624096Seric ** Side Effects: 7634096Seric ** enters the mailer into the mailer table. 7644096Seric */ 7653308Seric 76621066Seric makemailer(line) 7674096Seric char *line; 7684096Seric { 7694096Seric register char *p; 7708067Seric register struct mailer *m; 7718067Seric register STAB *s; 7728067Seric int i; 77310327Seric char fcode; 77458020Seric auto char *endp; 7754096Seric extern int NextMailer; 77610327Seric extern char **makeargv(); 77710327Seric extern char *munchstring(); 7784096Seric 77910327Seric /* allocate a mailer and set up defaults */ 78010327Seric m = (struct mailer *) xalloc(sizeof *m); 78110327Seric bzero((char *) m, sizeof *m); 78210327Seric m->m_eol = "\n"; 78368481Seric m->m_uid = m->m_gid = 0; 78410327Seric 78510327Seric /* collect the mailer name */ 78658050Seric for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++) 78710327Seric continue; 78810327Seric if (*p != '\0') 78910327Seric *p++ = '\0'; 79010327Seric m->m_name = newstr(line); 79110327Seric 79210327Seric /* now scan through and assign info from the fields */ 79310327Seric while (*p != '\0') 79410327Seric { 79558333Seric auto char *delimptr; 79658333Seric 79758050Seric while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p)))) 79810327Seric p++; 79910327Seric 80010327Seric /* p now points to field code */ 80110327Seric fcode = *p; 80210327Seric while (*p != '\0' && *p != '=' && *p != ',') 80310327Seric p++; 80410327Seric if (*p++ != '=') 80510327Seric { 80652637Seric syserr("mailer %s: `=' expected", m->m_name); 80710327Seric return; 80810327Seric } 80958050Seric while (isascii(*p) && isspace(*p)) 81010327Seric p++; 81110327Seric 81210327Seric /* p now points to the field body */ 81358333Seric p = munchstring(p, &delimptr); 81410327Seric 81510327Seric /* install the field into the mailer struct */ 81610327Seric switch (fcode) 81710327Seric { 81810327Seric case 'P': /* pathname */ 81910327Seric m->m_mailer = newstr(p); 82010327Seric break; 82110327Seric 82210327Seric case 'F': /* flags */ 82310687Seric for (; *p != '\0'; p++) 82458050Seric if (!(isascii(*p) && isspace(*p))) 82552637Seric setbitn(*p, m->m_flags); 82610327Seric break; 82710327Seric 82810327Seric case 'S': /* sender rewriting ruleset */ 82910327Seric case 'R': /* recipient rewriting ruleset */ 83058020Seric i = strtol(p, &endp, 10); 83110327Seric if (i < 0 || i >= MAXRWSETS) 83210327Seric { 83310327Seric syserr("invalid rewrite set, %d max", MAXRWSETS); 83410327Seric return; 83510327Seric } 83610327Seric if (fcode == 'S') 83758020Seric m->m_sh_rwset = m->m_se_rwset = i; 83810327Seric else 83958020Seric m->m_rh_rwset = m->m_re_rwset = i; 84058020Seric 84158020Seric p = endp; 84259985Seric if (*p++ == '/') 84358020Seric { 84458020Seric i = strtol(p, NULL, 10); 84558020Seric if (i < 0 || i >= MAXRWSETS) 84658020Seric { 84758020Seric syserr("invalid rewrite set, %d max", 84858020Seric MAXRWSETS); 84958020Seric return; 85058020Seric } 85158020Seric if (fcode == 'S') 85258020Seric m->m_sh_rwset = i; 85358020Seric else 85458020Seric m->m_rh_rwset = i; 85558020Seric } 85610327Seric break; 85710327Seric 85810327Seric case 'E': /* end of line string */ 85910327Seric m->m_eol = newstr(p); 86010327Seric break; 86110327Seric 86210327Seric case 'A': /* argument vector */ 86310327Seric m->m_argv = makeargv(p); 86410327Seric break; 86510701Seric 86610701Seric case 'M': /* maximum message size */ 86710701Seric m->m_maxsize = atol(p); 86810701Seric break; 86952106Seric 87052106Seric case 'L': /* maximum line length */ 87152106Seric m->m_linelimit = atoi(p); 87252106Seric break; 87358935Seric 87458935Seric case 'D': /* working directory */ 87558935Seric m->m_execdir = newstr(p); 87658935Seric break; 87768481Seric 87868481Seric case 'C': /* default charset */ 87968481Seric m->m_defcharset = newstr(p); 88068481Seric break; 88168481Seric 88268481Seric case 'T': /* MTA Type */ 88368481Seric m->m_mtatype = newstr(p); 88468481Seric p = strchr(m->m_mtatype, '/'); 88568481Seric if (p != NULL) 88668481Seric { 88768481Seric *p++ = '\0'; 88868481Seric if (*p == '\0') 88968481Seric p = NULL; 89068481Seric } 89168481Seric if (p == NULL) 89268481Seric m->m_addrtype = m->m_mtatype; 89368481Seric else 89468481Seric { 89568481Seric m->m_addrtype = p; 89668481Seric p = strchr(p, '/'); 89768481Seric } 89868481Seric if (p != NULL) 89968481Seric { 90068481Seric *p++ = '\0'; 90168481Seric if (*p == '\0') 90268481Seric p = NULL; 90368481Seric } 90468481Seric if (p == NULL) 90568481Seric m->m_diagtype = m->m_mtatype; 90668481Seric else 90768481Seric m->m_diagtype = p; 90868481Seric break; 90968481Seric 91068481Seric case 'U': /* user id */ 91168481Seric if (isascii(*p) && !isdigit(*p)) 91268481Seric { 91368481Seric char *q = p; 91468481Seric struct passwd *pw; 91568481Seric 91668481Seric while (isascii(*p) && isalnum(*p)) 91768481Seric p++; 91868481Seric while (isascii(*p) && isspace(*p)) 91968481Seric *p++ = '\0'; 92068481Seric if (*p != '\0') 92168481Seric *p++ = '\0'; 92268693Seric pw = sm_getpwnam(q); 92368481Seric if (pw == NULL) 92468481Seric syserr("readcf: mailer U= flag: unknown user %s", q); 92568481Seric else 92668481Seric { 92768481Seric m->m_uid = pw->pw_uid; 92868481Seric m->m_gid = pw->pw_gid; 92968481Seric } 93068481Seric } 93168481Seric else 93268481Seric { 93368481Seric auto char *q; 93468481Seric 93568481Seric m->m_uid = strtol(p, &q, 0); 93668481Seric p = q; 93768481Seric } 93868481Seric while (isascii(*p) && isspace(*p)) 93968481Seric p++; 94068481Seric if (*p == '\0') 94168481Seric break; 94268481Seric if (isascii(*p) && !isdigit(*p)) 94368481Seric { 94468481Seric char *q = p; 94568481Seric struct group *gr; 94668481Seric 94768481Seric while (isascii(*p) && isalnum(*p)) 94868481Seric p++; 94968481Seric *p++ = '\0'; 95068481Seric gr = getgrnam(q); 95168481Seric if (gr == NULL) 95268481Seric syserr("readcf: mailer U= flag: unknown group %s", q); 95368481Seric else 95468481Seric m->m_gid = gr->gr_gid; 95568481Seric } 95668481Seric else 95768481Seric { 95868481Seric m->m_gid = strtol(p, NULL, 0); 95968481Seric } 96068481Seric break; 96110327Seric } 96210327Seric 96358333Seric p = delimptr; 96410327Seric } 96510327Seric 96658321Seric /* do some rationality checking */ 96758321Seric if (m->m_argv == NULL) 96858321Seric { 96958321Seric syserr("M%s: A= argument required", m->m_name); 97058321Seric return; 97158321Seric } 97258321Seric if (m->m_mailer == NULL) 97358321Seric { 97458321Seric syserr("M%s: P= argument required", m->m_name); 97558321Seric return; 97658321Seric } 97758321Seric 9784096Seric if (NextMailer >= MAXMAILERS) 9794096Seric { 9809381Seric syserr("too many mailers defined (%d max)", MAXMAILERS); 9814096Seric return; 9824096Seric } 98357402Seric 98468481Seric /* do some heuristic cleanup for back compatibility */ 98568481Seric if (bitnset(M_LIMITS, m->m_flags)) 98668481Seric { 98768481Seric if (m->m_linelimit == 0) 98868481Seric m->m_linelimit = SMTPLINELIM; 98968481Seric if (ConfigLevel < 2) 99068481Seric setbitn(M_7BITS, m->m_flags); 99168481Seric } 99268481Seric 99368481Seric if (ConfigLevel < 6 && 99468481Seric (strcmp(m->m_mailer, "[IPC]") == 0 || 99568481Seric strcmp(m->m_mailer, "[TCP]") == 0)) 99668481Seric { 99768481Seric if (m->m_mtatype == NULL) 99868481Seric m->m_mtatype = "dns"; 99968481Seric if (m->m_addrtype == NULL) 100068481Seric m->m_addrtype = "rfc822"; 100168481Seric if (m->m_diagtype == NULL) 100268481Seric m->m_diagtype = "smtp"; 100368481Seric } 100468481Seric 100568481Seric /* enter the mailer into the symbol table */ 100610327Seric s = stab(m->m_name, ST_MAILER, ST_ENTER); 100757402Seric if (s->s_mailer != NULL) 100857402Seric { 100957402Seric i = s->s_mailer->m_mno; 101057402Seric free(s->s_mailer); 101157402Seric } 101257402Seric else 101357402Seric { 101457402Seric i = NextMailer++; 101557402Seric } 101657402Seric Mailer[i] = s->s_mailer = m; 101757454Seric m->m_mno = i; 101810327Seric } 101910327Seric /* 102010327Seric ** MUNCHSTRING -- translate a string into internal form. 102110327Seric ** 102210327Seric ** Parameters: 102310327Seric ** p -- the string to munch. 102458333Seric ** delimptr -- if non-NULL, set to the pointer of the 102558333Seric ** field delimiter character. 102610327Seric ** 102710327Seric ** Returns: 102810327Seric ** the munched string. 102910327Seric */ 10304096Seric 103110327Seric char * 103258333Seric munchstring(p, delimptr) 103310327Seric register char *p; 103458333Seric char **delimptr; 103510327Seric { 103610327Seric register char *q; 103710327Seric bool backslash = FALSE; 103810327Seric bool quotemode = FALSE; 103910327Seric static char buf[MAXLINE]; 10404096Seric 104110327Seric for (q = buf; *p != '\0'; p++) 10424096Seric { 104310327Seric if (backslash) 104410327Seric { 104510327Seric /* everything is roughly literal */ 104610357Seric backslash = FALSE; 104710327Seric switch (*p) 104810327Seric { 104910327Seric case 'r': /* carriage return */ 105010327Seric *q++ = '\r'; 105110327Seric continue; 105210327Seric 105310327Seric case 'n': /* newline */ 105410327Seric *q++ = '\n'; 105510327Seric continue; 105610327Seric 105710327Seric case 'f': /* form feed */ 105810327Seric *q++ = '\f'; 105910327Seric continue; 106010327Seric 106110327Seric case 'b': /* backspace */ 106210327Seric *q++ = '\b'; 106310327Seric continue; 106410327Seric } 106510327Seric *q++ = *p; 106610327Seric } 106710327Seric else 106810327Seric { 106910327Seric if (*p == '\\') 107010327Seric backslash = TRUE; 107110327Seric else if (*p == '"') 107210327Seric quotemode = !quotemode; 107310327Seric else if (quotemode || *p != ',') 107410327Seric *q++ = *p; 107510327Seric else 107610327Seric break; 107710327Seric } 10784096Seric } 10794096Seric 108058333Seric if (delimptr != NULL) 108158333Seric *delimptr = p; 108210327Seric *q++ = '\0'; 108310327Seric return (buf); 108410327Seric } 108510327Seric /* 108610327Seric ** MAKEARGV -- break up a string into words 108710327Seric ** 108810327Seric ** Parameters: 108910327Seric ** p -- the string to break up. 109010327Seric ** 109110327Seric ** Returns: 109210327Seric ** a char **argv (dynamically allocated) 109310327Seric ** 109410327Seric ** Side Effects: 109510327Seric ** munges p. 109610327Seric */ 10974096Seric 109810327Seric char ** 109910327Seric makeargv(p) 110010327Seric register char *p; 110110327Seric { 110210327Seric char *q; 110310327Seric int i; 110410327Seric char **avp; 110510327Seric char *argv[MAXPV + 1]; 110610327Seric 110710327Seric /* take apart the words */ 110810327Seric i = 0; 110910327Seric while (*p != '\0' && i < MAXPV) 11104096Seric { 111110327Seric q = p; 111258050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 111310327Seric p++; 111458050Seric while (isascii(*p) && isspace(*p)) 111510327Seric *p++ = '\0'; 111610327Seric argv[i++] = newstr(q); 11174096Seric } 111810327Seric argv[i++] = NULL; 11194096Seric 112010327Seric /* now make a copy of the argv */ 112110327Seric avp = (char **) xalloc(sizeof *avp * i); 112216893Seric bcopy((char *) argv, (char *) avp, sizeof *avp * i); 112310327Seric 112410327Seric return (avp); 11253308Seric } 11263308Seric /* 11273308Seric ** PRINTRULES -- print rewrite rules (for debugging) 11283308Seric ** 11293308Seric ** Parameters: 11303308Seric ** none. 11313308Seric ** 11323308Seric ** Returns: 11333308Seric ** none. 11343308Seric ** 11353308Seric ** Side Effects: 11363308Seric ** prints rewrite rules. 11373308Seric */ 11383308Seric 11393308Seric printrules() 11403308Seric { 11413308Seric register struct rewrite *rwp; 11424072Seric register int ruleset; 11433308Seric 11444072Seric for (ruleset = 0; ruleset < 10; ruleset++) 11453308Seric { 11464072Seric if (RewriteRules[ruleset] == NULL) 11474072Seric continue; 11488067Seric printf("\n----Rule Set %d:", ruleset); 11493308Seric 11504072Seric for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 11513308Seric { 11528067Seric printf("\nLHS:"); 11538067Seric printav(rwp->r_lhs); 11548067Seric printf("RHS:"); 11558067Seric printav(rwp->r_rhs); 11563308Seric } 11573308Seric } 11583308Seric } 115968481Seric /* 116068481Seric ** PRINTMAILER -- print mailer structure (for debugging) 116168481Seric ** 116268481Seric ** Parameters: 116368481Seric ** m -- the mailer to print 116468481Seric ** 116568481Seric ** Returns: 116668481Seric ** none. 116768481Seric */ 11684319Seric 116968481Seric printmailer(m) 117068481Seric register MAILER *m; 117168481Seric { 117268481Seric int j; 117368481Seric 117468481Seric printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld U=%d:%d F=", 117568481Seric m->m_mno, m->m_name, 117668481Seric m->m_mailer, m->m_se_rwset, m->m_sh_rwset, 117768481Seric m->m_re_rwset, m->m_rh_rwset, m->m_maxsize, 117868481Seric m->m_uid, m->m_gid); 117968481Seric for (j = '\0'; j <= '\177'; j++) 118068481Seric if (bitnset(j, m->m_flags)) 118168481Seric (void) putchar(j); 118268481Seric printf(" L=%d E=", m->m_linelimit); 118368481Seric xputs(m->m_eol); 118468481Seric if (m->m_defcharset != NULL) 118568481Seric printf(" C=%s", m->m_defcharset); 118668481Seric printf(" T=%s/%s/%s", 118768481Seric m->m_mtatype == NULL ? "<undefined>" : m->m_mtatype, 118868481Seric m->m_addrtype == NULL ? "<undefined>" : m->m_addrtype, 118968481Seric m->m_diagtype == NULL ? "<undefined>" : m->m_diagtype); 119068481Seric if (m->m_argv != NULL) 119168481Seric { 119268481Seric char **a = m->m_argv; 119368481Seric 119468481Seric printf(" A="); 119568481Seric while (*a != NULL) 119668481Seric { 119768481Seric if (a != m->m_argv) 119868481Seric printf(" "); 119968481Seric xputs(*a++); 120068481Seric } 120168481Seric } 120268481Seric printf("\n"); 120368481Seric } 12044096Seric /* 12058256Seric ** SETOPTION -- set global processing option 12068256Seric ** 12078256Seric ** Parameters: 12088256Seric ** opt -- option name. 12098256Seric ** val -- option value (as a text string). 121021755Seric ** safe -- set if this came from a configuration file. 121121755Seric ** Some options (if set from the command line) will 121221755Seric ** reset the user id to avoid security problems. 12138269Seric ** sticky -- if set, don't let other setoptions override 12148269Seric ** this value. 121558734Seric ** e -- the main envelope. 12168256Seric ** 12178256Seric ** Returns: 12188256Seric ** none. 12198256Seric ** 12208256Seric ** Side Effects: 12218256Seric ** Sets options as implied by the arguments. 12228256Seric */ 12238256Seric 122410687Seric static BITMAP StickyOpt; /* set if option is stuck */ 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, 125868481Seric "EightBitMode", '8', TRUE, 125968481Seric "AliasFile", 'A', FALSE, 126068481Seric "AliasWait", 'a', FALSE, 126168481Seric "BlankSub", 'B', FALSE, 126268481Seric "MinFreeBlocks", 'b', TRUE, 126368481Seric "CheckpointInterval", 'C', TRUE, 126468481Seric "HoldExpensive", 'c', FALSE, 126568481Seric "AutoRebuildAliases", 'D', FALSE, 126668481Seric "DeliveryMode", 'd', TRUE, 126768481Seric "ErrorHeader", 'E', FALSE, 126868481Seric "ErrorMode", 'e', TRUE, 126968481Seric "TempFileMode", 'F', FALSE, 127068481Seric "SaveFromLine", 'f', FALSE, 127168481Seric "MatchGECOS", 'G', FALSE, 127268481Seric "HelpFile", 'H', FALSE, 127368481Seric "MaxHopCount", 'h', FALSE, 127468569Seric "ResolverOptions", 'I', FALSE, 127568481Seric "IgnoreDots", 'i', TRUE, 127668481Seric "ForwardPath", 'J', FALSE, 127768481Seric "SendMimeErrors", 'j', TRUE, 127868481Seric "ConnectionCacheSize", 'k', FALSE, 127968481Seric "ConnectionCacheTimeout", 'K', FALSE, 128068481Seric "UseErrorsTo", 'l', FALSE, 128168481Seric "LogLevel", 'L', FALSE, 128268481Seric "MeToo", 'm', TRUE, 128368481Seric "CheckAliases", 'n', FALSE, 128468481Seric "OldStyleHeaders", 'o', TRUE, 128568481Seric "DaemonPortOptions", 'O', FALSE, 128668481Seric "PrivacyOptions", 'p', TRUE, 128768481Seric "PostmasterCopy", 'P', FALSE, 128868481Seric "QueueFactor", 'q', FALSE, 128968481Seric "QueueDirectory", 'Q', FALSE, 129068481Seric "DontPruneRoutes", 'R', FALSE, 129168481Seric "Timeout", 'r', TRUE, 129268481Seric "StatusFile", 'S', FALSE, 129368481Seric "SuperSafe", 's', TRUE, 129468481Seric "QueueTimeout", 'T', FALSE, 129568481Seric "TimeZoneSpec", 't', FALSE, 129668481Seric "UserDatabaseSpec", 'U', FALSE, 129768481Seric "DefaultUser", 'u', FALSE, 129868481Seric "FallbackMXhost", 'V', FALSE, 129968481Seric "Verbose", 'v', TRUE, 130068481Seric "TryNullMXList", 'w', TRUE, 130168481Seric "QueueLA", 'x', FALSE, 130268481Seric "RefuseLA", 'X', FALSE, 130368481Seric "RecipientFactor", 'y', FALSE, 130468569Seric "ForkEachJob", 'Y', FALSE, 130568481Seric "ClassFactor", 'z', FALSE, 130668569Seric "RetryFactor", 'Z', FALSE, 130768481Seric #define O_QUEUESORTORD 0x81 130868481Seric "QueueSortOrder", O_QUEUESORTORD, TRUE, 130968481Seric #define O_MQA 0x83 131068481Seric "MinQueueAge", O_MQA, TRUE, 131168481Seric #define O_MHSA 0x84 131268481Seric /* 131368481Seric "MaxHostStatAge", O_MHSA, TRUE, 131468481Seric */ 131568481Seric #define O_DEFCHARSET 0x85 131668481Seric "DefaultCharSet", O_DEFCHARSET, TRUE, 131768481Seric #define O_SSFILE 0x86 131868481Seric "ServiceSwitchFile", O_SSFILE, FALSE, 131968481Seric #define O_DIALDELAY 0x87 132068481Seric "DialDelay", O_DIALDELAY, TRUE, 132168481Seric #define O_NORCPTACTION 0x88 132268481Seric "NoRecipientAction", O_NORCPTACTION, TRUE, 132368490Seric #define O_SAFEFILEENV 0x89 132468490Seric "SafeFileEnvironment", O_SAFEFILEENV, FALSE, 132568569Seric #define O_MAXMSGSIZE 0x8a 132668569Seric "MaxMessageSize", O_MAXMSGSIZE, FALSE, 132768756Seric #define O_COLONOKINADDR 0x8b 132868756Seric "ColonOkInAddr", O_COLONOKINADDR, TRUE, 132968481Seric 133068481Seric NULL, '\0', FALSE, 133168481Seric }; 133268481Seric 133368481Seric 133468481Seric 133558734Seric setoption(opt, val, safe, sticky, e) 133668481Seric u_char opt; 13378256Seric char *val; 133821755Seric bool safe; 13398269Seric bool sticky; 134058734Seric register ENVELOPE *e; 13418256Seric { 134257207Seric register char *p; 134368481Seric register struct optioninfo *o; 134468481Seric char *subopt; 13458265Seric extern bool atobool(); 134612633Seric extern time_t convtime(); 134714879Seric extern int QueueLA; 134814879Seric extern int RefuseLA; 134964718Seric extern bool Warn_Q_option; 13508256Seric 135168481Seric errno = 0; 135268481Seric if (opt == ' ') 135368481Seric { 135468481Seric /* full word options */ 135568481Seric struct optioninfo *sel; 135668481Seric 135768481Seric p = strchr(val, '='); 135868481Seric if (p == NULL) 135968481Seric p = &val[strlen(val)]; 136068481Seric while (*--p == ' ') 136168481Seric continue; 136268481Seric while (*++p == ' ') 136368481Seric *p = '\0'; 136468481Seric if (p == val) 136568481Seric { 136668481Seric syserr("readcf: null option name"); 136768481Seric return; 136868481Seric } 136968481Seric if (*p == '=') 137068481Seric *p++ = '\0'; 137168481Seric while (*p == ' ') 137268481Seric p++; 137368481Seric subopt = strchr(val, '.'); 137468481Seric if (subopt != NULL) 137568481Seric *subopt++ = '\0'; 137668481Seric sel = NULL; 137768481Seric for (o = OptionTab; o->o_name != NULL; o++) 137868481Seric { 137968481Seric if (strncasecmp(o->o_name, val, strlen(val)) != 0) 138068481Seric continue; 138168481Seric if (strlen(o->o_name) == strlen(val)) 138268481Seric { 138368481Seric /* completely specified -- this must be it */ 138468481Seric sel = NULL; 138568481Seric break; 138668481Seric } 138768481Seric if (sel != NULL) 138868481Seric break; 138968481Seric sel = o; 139068481Seric } 139168481Seric if (sel != NULL && o->o_name == NULL) 139268481Seric o = sel; 139368481Seric else if (o->o_name == NULL) 139468481Seric { 139568481Seric syserr("readcf: unknown option name %s", val); 139668481Seric return; 139768481Seric } 139868481Seric else if (sel != NULL) 139968481Seric { 140068481Seric syserr("readcf: ambiguous option name %s (matches %s and %s)", 140168481Seric val, sel->o_name, o->o_name); 140268481Seric return; 140368481Seric } 140468481Seric if (strlen(val) != strlen(o->o_name)) 140568481Seric { 140668481Seric bool oldVerbose = Verbose; 140768481Seric 140868481Seric Verbose = TRUE; 140968481Seric message("Option %s used as abbreviation for %s", 141068481Seric val, o->o_name); 141168481Seric Verbose = oldVerbose; 141268481Seric } 141368481Seric opt = o->o_code; 141468481Seric val = p; 141568481Seric } 141668481Seric else 141768481Seric { 141868481Seric for (o = OptionTab; o->o_name != NULL; o++) 141968481Seric { 142068481Seric if (o->o_code == opt) 142168481Seric break; 142268481Seric } 142368481Seric subopt = NULL; 142468481Seric } 142568481Seric 14268256Seric if (tTd(37, 1)) 142768481Seric { 142868481Seric printf(isascii(opt) && isprint(opt) ? 142968481Seric "setoption %s (%c).%s=%s" : 143068481Seric "setoption %s (0x%x).%s=%s", 143168481Seric o->o_name == NULL ? "<unknown>" : o->o_name, 143268481Seric opt, 143368481Seric subopt == NULL ? "" : subopt, 143468481Seric val); 143568481Seric } 14368256Seric 14378256Seric /* 14388269Seric ** See if this option is preset for us. 14398256Seric */ 14408256Seric 144159731Seric if (!sticky && bitnset(opt, StickyOpt)) 14428269Seric { 14439341Seric if (tTd(37, 1)) 14449341Seric printf(" (ignored)\n"); 14458269Seric return; 14468269Seric } 14478269Seric 144821755Seric /* 144921755Seric ** Check to see if this option can be specified by this user. 145021755Seric */ 145121755Seric 145263787Seric if (!safe && RealUid == 0) 145321755Seric safe = TRUE; 145468481Seric if (!safe && !o->o_safe) 145521755Seric { 145639111Srick if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 145721755Seric { 145836582Sbostic if (tTd(37, 1)) 145936582Sbostic printf(" (unsafe)"); 146063787Seric if (RealUid != geteuid()) 146136582Sbostic { 146251210Seric if (tTd(37, 1)) 146351210Seric printf("(Resetting uid)"); 146463787Seric (void) setgid(RealGid); 146563787Seric (void) setuid(RealUid); 146636582Sbostic } 146721755Seric } 146821755Seric } 146951210Seric if (tTd(37, 1)) 147017985Seric printf("\n"); 14718269Seric 147268481Seric switch (opt & 0xff) 14738256Seric { 147459709Seric case '7': /* force seven-bit input */ 147568481Seric SevenBitInput = atobool(val); 147652106Seric break; 147752106Seric 147868481Seric case '8': /* handling of 8-bit input */ 147968481Seric switch (*val) 148068481Seric { 148168481Seric case 'r': /* reject 8-bit, don't convert MIME */ 148268481Seric MimeMode = 0; 148368481Seric break; 148468481Seric 148568481Seric case 'm': /* convert 8-bit, convert MIME */ 148668481Seric MimeMode = MM_CVTMIME|MM_MIME8BIT; 148768481Seric break; 148868481Seric 148968481Seric case 'j': /* "just send 8" */ 149068481Seric MimeMode = MM_PASS8BIT; 149168481Seric break; 149268481Seric 149368481Seric case 'p': /* pass 8 bit, convert MIME */ 149468481Seric MimeMode = MM_PASS8BIT|MM_CVTMIME; 149568481Seric break; 149668481Seric 149768481Seric case 's': /* strict adherence */ 149868481Seric MimeMode = MM_CVTMIME; 149968481Seric break; 150068481Seric 150168481Seric case 'a': /* encode 8 bit if available */ 150268481Seric MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 150368481Seric break; 150468481Seric 150568481Seric case 'c': /* convert 8 bit to MIME, never 7 bit */ 150668481Seric MimeMode = MM_MIME8BIT; 150768481Seric break; 150868481Seric 150968481Seric default: 151068481Seric syserr("Unknown 8-bit mode %c", *val); 151168481Seric exit(EX_USAGE); 151268481Seric } 151368481Seric break; 151468481Seric 15158256Seric case 'A': /* set default alias file */ 15169381Seric if (val[0] == '\0') 151759672Seric setalias("aliases"); 15189381Seric else 151959672Seric setalias(val); 15208256Seric break; 15218256Seric 152217474Seric case 'a': /* look N minutes for "@:@" in alias file */ 152317474Seric if (val[0] == '\0') 152464796Seric SafeAlias = 5 * 60; /* five minutes */ 152517474Seric else 152664796Seric SafeAlias = convtime(val, 'm'); 152717474Seric break; 152817474Seric 152916843Seric case 'B': /* substitution for blank character */ 153016843Seric SpaceSub = val[0]; 153116843Seric if (SpaceSub == '\0') 153216843Seric SpaceSub = ' '; 153316843Seric break; 153416843Seric 153559283Seric case 'b': /* min blocks free on queue fs/max msg size */ 153659283Seric p = strchr(val, '/'); 153759283Seric if (p != NULL) 153859283Seric { 153959283Seric *p++ = '\0'; 154059283Seric MaxMessageSize = atol(p); 154159283Seric } 154258082Seric MinBlocksFree = atol(val); 154358082Seric break; 154458082Seric 15459284Seric case 'c': /* don't connect to "expensive" mailers */ 15469381Seric NoConnect = atobool(val); 15479284Seric break; 15489284Seric 154951305Seric case 'C': /* checkpoint every N addresses */ 155051305Seric CheckpointInterval = atoi(val); 155124944Seric break; 155224944Seric 15539284Seric case 'd': /* delivery mode */ 15549284Seric switch (*val) 15558269Seric { 15569284Seric case '\0': 155758734Seric e->e_sendmode = SM_DELIVER; 15588269Seric break; 15598269Seric 156010755Seric case SM_QUEUE: /* queue only */ 156110755Seric #ifndef QUEUE 156210755Seric syserr("need QUEUE to set -odqueue"); 156356795Seric #endif /* QUEUE */ 156410755Seric /* fall through..... */ 156510755Seric 15669284Seric case SM_DELIVER: /* do everything */ 15679284Seric case SM_FORK: /* fork after verification */ 156858734Seric e->e_sendmode = *val; 15698269Seric break; 15708269Seric 15718269Seric default: 15729284Seric syserr("Unknown delivery mode %c", *val); 15738269Seric exit(EX_USAGE); 15748269Seric } 15758269Seric break; 15768269Seric 15779146Seric case 'D': /* rebuild alias database as needed */ 15789381Seric AutoRebuild = atobool(val); 15799146Seric break; 15809146Seric 158155372Seric case 'E': /* error message header/header file */ 158255379Seric if (*val != '\0') 158355379Seric ErrMsgFile = newstr(val); 158455372Seric break; 158555372Seric 15868269Seric case 'e': /* set error processing mode */ 15878269Seric switch (*val) 15888269Seric { 15899381Seric case EM_QUIET: /* be silent about it */ 15909381Seric case EM_MAIL: /* mail back */ 15919381Seric case EM_BERKNET: /* do berknet error processing */ 15929381Seric case EM_WRITE: /* write back (or mail) */ 15939381Seric case EM_PRINT: /* print errors normally (default) */ 159458734Seric e->e_errormode = *val; 15958269Seric break; 15968269Seric } 15978269Seric break; 15988269Seric 15999049Seric case 'F': /* file mode */ 160017975Seric FileMode = atooct(val) & 0777; 16019049Seric break; 16029049Seric 16038269Seric case 'f': /* save Unix-style From lines on front */ 16049381Seric SaveFrom = atobool(val); 16058269Seric break; 16068269Seric 160753735Seric case 'G': /* match recipients against GECOS field */ 160853735Seric MatchGecos = atobool(val); 160953735Seric break; 161053735Seric 16118256Seric case 'g': /* default gid */ 161268481Seric g_opt: 161364133Seric if (isascii(*val) && isdigit(*val)) 161464133Seric DefGid = atoi(val); 161564133Seric else 161664133Seric { 161764133Seric register struct group *gr; 161864133Seric 161964133Seric DefGid = -1; 162064133Seric gr = getgrnam(val); 162164133Seric if (gr == NULL) 162268481Seric syserr("readcf: option %c: unknown group %s", 162368481Seric opt, val); 162464133Seric else 162564133Seric DefGid = gr->gr_gid; 162664133Seric } 16278256Seric break; 16288256Seric 16298256Seric case 'H': /* help file */ 16309381Seric if (val[0] == '\0') 16318269Seric HelpFile = "sendmail.hf"; 16329381Seric else 16339381Seric HelpFile = newstr(val); 16348256Seric break; 16358256Seric 163651305Seric case 'h': /* maximum hop count */ 163751305Seric MaxHopCount = atoi(val); 163851305Seric break; 163951305Seric 164035651Seric case 'I': /* use internet domain name server */ 164166334Seric #if NAMED_BIND 164257207Seric for (p = val; *p != 0; ) 164357207Seric { 164457207Seric bool clearmode; 164557207Seric char *q; 164657207Seric struct resolverflags *rfp; 164757207Seric 164857207Seric while (*p == ' ') 164957207Seric p++; 165057207Seric if (*p == '\0') 165157207Seric break; 165257207Seric clearmode = FALSE; 165357207Seric if (*p == '-') 165457207Seric clearmode = TRUE; 165557207Seric else if (*p != '+') 165657207Seric p--; 165757207Seric p++; 165857207Seric q = p; 165958050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 166057207Seric p++; 166157207Seric if (*p != '\0') 166257207Seric *p++ = '\0'; 166368759Seric if (strcasecmp(q, "HasWildcardMX") == 0) 166468759Seric { 166568759Seric NoMXforCanon = !clearmode; 166668759Seric continue; 166768759Seric } 166857207Seric for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 166957207Seric { 167057207Seric if (strcasecmp(q, rfp->rf_name) == 0) 167157207Seric break; 167257207Seric } 167364923Seric if (rfp->rf_name == NULL) 167464923Seric syserr("readcf: I option value %s unrecognized", q); 167564923Seric else if (clearmode) 167657207Seric _res.options &= ~rfp->rf_bits; 167757207Seric else 167857207Seric _res.options |= rfp->rf_bits; 167957207Seric } 168057207Seric if (tTd(8, 2)) 168168759Seric printf("_res.options = %x, HasWildcardMX = %d\n", 168268759Seric _res.options, !NoMXforCanon); 168357207Seric #else 168457207Seric usrerr("name server (I option) specified but BIND not compiled in"); 168557207Seric #endif 168635651Seric break; 168735651Seric 16888269Seric case 'i': /* ignore dot lines in message */ 16899381Seric IgnrDot = atobool(val); 16908269Seric break; 16918269Seric 169259730Seric case 'j': /* send errors in MIME (RFC 1341) format */ 169359730Seric SendMIMEErrors = atobool(val); 169459730Seric break; 169559730Seric 169657136Seric case 'J': /* .forward search path */ 169757136Seric ForwardPath = newstr(val); 169857136Seric break; 169957136Seric 170054967Seric case 'k': /* connection cache size */ 170154967Seric MaxMciCache = atoi(val); 170256215Seric if (MaxMciCache < 0) 170356215Seric MaxMciCache = 0; 170454967Seric break; 170554967Seric 170654967Seric case 'K': /* connection cache timeout */ 170758796Seric MciCacheTimeout = convtime(val, 'm'); 170854967Seric break; 170954967Seric 171061104Seric case 'l': /* use Errors-To: header */ 171161104Seric UseErrorsTo = atobool(val); 171261104Seric break; 171361104Seric 17148256Seric case 'L': /* log level */ 171564140Seric if (safe || LogLevel < atoi(val)) 171664140Seric LogLevel = atoi(val); 17178256Seric break; 17188256Seric 17198269Seric case 'M': /* define macro */ 172068267Seric p = newstr(&val[1]); 172168267Seric if (!safe) 172268267Seric cleanstrcpy(p, p, MAXNAME); 172368267Seric define(val[0], p, CurEnv); 172416878Seric sticky = FALSE; 17258269Seric break; 17268269Seric 17278269Seric case 'm': /* send to me too */ 17289381Seric MeToo = atobool(val); 17298269Seric break; 17308269Seric 173125820Seric case 'n': /* validate RHS in newaliases */ 173225820Seric CheckAliases = atobool(val); 173325820Seric break; 173425820Seric 173561104Seric /* 'N' available -- was "net name" */ 173661104Seric 173758851Seric case 'O': /* daemon options */ 173858851Seric setdaemonoptions(val); 173958851Seric break; 174058851Seric 17418269Seric case 'o': /* assume old style headers */ 17429381Seric if (atobool(val)) 17439341Seric CurEnv->e_flags |= EF_OLDSTYLE; 17449341Seric else 17459341Seric CurEnv->e_flags &= ~EF_OLDSTYLE; 17468269Seric break; 17478269Seric 174858082Seric case 'p': /* select privacy level */ 174958082Seric p = val; 175058082Seric for (;;) 175158082Seric { 175258082Seric register struct prival *pv; 175358082Seric extern struct prival PrivacyValues[]; 175458082Seric 175558082Seric while (isascii(*p) && (isspace(*p) || ispunct(*p))) 175658082Seric p++; 175758082Seric if (*p == '\0') 175858082Seric break; 175958082Seric val = p; 176058082Seric while (isascii(*p) && isalnum(*p)) 176158082Seric p++; 176258082Seric if (*p != '\0') 176358082Seric *p++ = '\0'; 176458082Seric 176558082Seric for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 176658082Seric { 176758082Seric if (strcasecmp(val, pv->pv_name) == 0) 176858082Seric break; 176958082Seric } 177058886Seric if (pv->pv_name == NULL) 177158886Seric syserr("readcf: Op line: %s unrecognized", val); 177258082Seric PrivacyFlags |= pv->pv_flag; 177358082Seric } 177468479Seric sticky = FALSE; 177558082Seric break; 177658082Seric 177724944Seric case 'P': /* postmaster copy address for returned mail */ 177824944Seric PostMasterCopy = newstr(val); 177924944Seric break; 178024944Seric 178124944Seric case 'q': /* slope of queue only function */ 178224944Seric QueueFactor = atoi(val); 178324944Seric break; 178424944Seric 17858256Seric case 'Q': /* queue directory */ 17869381Seric if (val[0] == '\0') 17878269Seric QueueDir = "mqueue"; 17889381Seric else 17899381Seric QueueDir = newstr(val); 179058789Seric if (RealUid != 0 && !safe) 179164718Seric Warn_Q_option = TRUE; 17928256Seric break; 17938256Seric 179458148Seric case 'R': /* don't prune routes */ 179558148Seric DontPruneRoutes = atobool(val); 179658148Seric break; 179758148Seric 17988256Seric case 'r': /* read timeout */ 179968481Seric if (subopt == NULL) 180068481Seric inittimeouts(val); 180168481Seric else 180268481Seric settimeout(subopt, val); 18038256Seric break; 18048256Seric 18058256Seric case 'S': /* status file */ 18069381Seric if (val[0] == '\0') 18078269Seric StatFile = "sendmail.st"; 18089381Seric else 18099381Seric StatFile = newstr(val); 18108256Seric break; 18118256Seric 18128265Seric case 's': /* be super safe, even if expensive */ 18139381Seric SuperSafe = atobool(val); 18148256Seric break; 18158256Seric 18168256Seric case 'T': /* queue timeout */ 181758737Seric p = strchr(val, '/'); 181858737Seric if (p != NULL) 181958737Seric { 182058737Seric *p++ = '\0'; 182168481Seric settimeout("queuewarn", p); 182258737Seric } 182368481Seric settimeout("queuereturn", val); 182454967Seric break; 18258256Seric 18268265Seric case 't': /* time zone name */ 182752106Seric TimeZoneSpec = newstr(val); 18288265Seric break; 18298265Seric 183050556Seric case 'U': /* location of user database */ 183151360Seric UdbSpec = newstr(val); 183250556Seric break; 183350556Seric 18348256Seric case 'u': /* set default uid */ 183568481Seric for (p = val; *p != '\0'; p++) 183668481Seric { 183768481Seric if (*p == '.' || *p == '/' || *p == ':') 183868481Seric { 183968481Seric *p++ = '\0'; 184068481Seric break; 184168481Seric } 184268481Seric } 184364133Seric if (isascii(*val) && isdigit(*val)) 184464133Seric DefUid = atoi(val); 184564133Seric else 184664133Seric { 184764133Seric register struct passwd *pw; 184864133Seric 184964133Seric DefUid = -1; 185068693Seric pw = sm_getpwnam(val); 185164133Seric if (pw == NULL) 185264133Seric syserr("readcf: option u: unknown user %s", val); 185364133Seric else 185468481Seric { 185564133Seric DefUid = pw->pw_uid; 185668481Seric DefGid = pw->pw_gid; 185768481Seric } 185864133Seric } 185940973Sbostic setdefuser(); 18608256Seric 186168481Seric /* handle the group if it is there */ 186268481Seric if (*p == '\0') 186368481Seric break; 186468481Seric val = p; 186568481Seric goto g_opt; 186668481Seric 186758851Seric case 'V': /* fallback MX host */ 186858851Seric FallBackMX = newstr(val); 186958851Seric break; 187058851Seric 18718269Seric case 'v': /* run in verbose mode */ 18729381Seric Verbose = atobool(val); 18738256Seric break; 18748256Seric 187563837Seric case 'w': /* if we are best MX, try host directly */ 187663837Seric TryNullMXList = atobool(val); 187763837Seric break; 187861104Seric 187961104Seric /* 'W' available -- was wizard password */ 188061104Seric 188114879Seric case 'x': /* load avg at which to auto-queue msgs */ 188214879Seric QueueLA = atoi(val); 188314879Seric break; 188414879Seric 188514879Seric case 'X': /* load avg at which to auto-reject connections */ 188614879Seric RefuseLA = atoi(val); 188714879Seric break; 188814879Seric 188924981Seric case 'y': /* work recipient factor */ 189024981Seric WkRecipFact = atoi(val); 189124981Seric break; 189224981Seric 189324981Seric case 'Y': /* fork jobs during queue runs */ 189424952Seric ForkQueueRuns = atobool(val); 189524952Seric break; 189624952Seric 189724981Seric case 'z': /* work message class factor */ 189824981Seric WkClassFact = atoi(val); 189924981Seric break; 190024981Seric 190124981Seric case 'Z': /* work time factor */ 190224981Seric WkTimeFact = atoi(val); 190324981Seric break; 190424981Seric 190568481Seric case O_QUEUESORTORD: /* queue sorting order */ 190668481Seric switch (*val) 190768481Seric { 190868481Seric case 'h': /* Host first */ 190968481Seric case 'H': 191068481Seric QueueSortOrder = QS_BYHOST; 191168481Seric break; 191268481Seric 191368481Seric case 'p': /* Priority order */ 191468481Seric case 'P': 191568481Seric QueueSortOrder = QS_BYPRIORITY; 191668481Seric break; 191768481Seric 191868481Seric default: 191968481Seric syserr("Invalid queue sort order \"%s\"", val); 192068481Seric } 192168481Seric break; 192268481Seric 192368481Seric case O_MQA: /* minimum queue age between deliveries */ 192468481Seric MinQueueAge = convtime(val, 'm'); 192568481Seric break; 192668481Seric 192768481Seric case O_MHSA: /* maximum age of cached host status */ 192868481Seric MaxHostStatAge = convtime(val, 'm'); 192968481Seric break; 193068481Seric 193168481Seric case O_DEFCHARSET: /* default character set for mimefying */ 193268481Seric DefaultCharSet = newstr(denlstring(val, TRUE, TRUE)); 193368481Seric break; 193468481Seric 193568481Seric case O_SSFILE: /* service switch file */ 193668481Seric ServiceSwitchFile = newstr(val); 193768481Seric break; 193868481Seric 193968481Seric case O_DIALDELAY: /* delay for dial-on-demand operation */ 194068481Seric DialDelay = convtime(val, 's'); 194168481Seric break; 194268481Seric 194368481Seric case O_NORCPTACTION: /* what to do if no recipient */ 194468481Seric if (strcasecmp(val, "none") == 0) 194568481Seric NoRecipientAction = NRA_NO_ACTION; 194668481Seric else if (strcasecmp(val, "add-to") == 0) 194768481Seric NoRecipientAction = NRA_ADD_TO; 194868481Seric else if (strcasecmp(val, "add-apparently-to") == 0) 194968481Seric NoRecipientAction = NRA_ADD_APPARENTLY_TO; 195068481Seric else if (strcasecmp(val, "add-bcc") == 0) 195168481Seric NoRecipientAction = NRA_ADD_BCC; 195268481Seric else if (strcasecmp(val, "add-to-undisclosed") == 0) 195368481Seric NoRecipientAction = NRA_ADD_TO_UNDISCLOSED; 195468481Seric else 195568481Seric syserr("Invalid NoRecipientAction: %s", val); 195668481Seric 195768490Seric case O_SAFEFILEENV: /* chroot() environ for writing to files */ 195868490Seric SafeFileEnv = newstr(val); 195968490Seric break; 196068490Seric 196168569Seric case O_MAXMSGSIZE: /* maximum message size */ 196268569Seric MaxMessageSize = atol(p); 196368569Seric break; 196468569Seric 196568756Seric case O_COLONOKINADDR: /* old style handling of colon addresses */ 196668756Seric ColonOkInAddr = atobool(p); 196768756Seric break; 196868756Seric 19698256Seric default: 197068481Seric if (tTd(37, 1)) 197168481Seric { 197268481Seric if (isascii(opt) && isprint(opt)) 197368481Seric printf("Warning: option %c unknown\n", opt); 197468481Seric else 197568481Seric printf("Warning: option 0x%x unknown\n", opt); 197668481Seric } 19778256Seric break; 19788256Seric } 197916878Seric if (sticky) 198016878Seric setbitn(opt, StickyOpt); 19819188Seric return; 19828256Seric } 198310687Seric /* 198468481Seric ** SETCLASS -- set a string into a class 198510687Seric ** 198610687Seric ** Parameters: 198768481Seric ** class -- the class to put the string in. 198868481Seric ** str -- the string to enter 198910687Seric ** 199010687Seric ** Returns: 199110687Seric ** none. 199210687Seric ** 199310687Seric ** Side Effects: 199410687Seric ** puts the word into the symbol table. 199510687Seric */ 199610687Seric 199768481Seric setclass(class, str) 199810687Seric int class; 199968481Seric char *str; 200010687Seric { 200110687Seric register STAB *s; 200210687Seric 200357943Seric if (tTd(37, 8)) 200468481Seric printf("setclass(%c, %s)\n", class, str); 200568481Seric s = stab(str, ST_CLASS, ST_ENTER); 200610687Seric setbitn(class, s->s_class); 200710687Seric } 200853654Seric /* 200953654Seric ** MAKEMAPENTRY -- create a map entry 201053654Seric ** 201153654Seric ** Parameters: 201253654Seric ** line -- the config file line 201353654Seric ** 201453654Seric ** Returns: 201553654Seric ** TRUE if it successfully entered the map entry. 201653654Seric ** FALSE otherwise (usually syntax error). 201753654Seric ** 201853654Seric ** Side Effects: 201953654Seric ** Enters the map into the dictionary. 202053654Seric */ 202153654Seric 202253654Seric void 202353654Seric makemapentry(line) 202453654Seric char *line; 202553654Seric { 202653654Seric register char *p; 202753654Seric char *mapname; 202853654Seric char *classname; 202964078Seric register STAB *s; 203053654Seric STAB *class; 203153654Seric 203258050Seric for (p = line; isascii(*p) && isspace(*p); p++) 203353654Seric continue; 203458050Seric if (!(isascii(*p) && isalnum(*p))) 203553654Seric { 203653654Seric syserr("readcf: config K line: no map name"); 203753654Seric return; 203853654Seric } 203953654Seric 204053654Seric mapname = p; 204168481Seric while ((isascii(*++p) && isalnum(*p)) || *p == '.') 204253654Seric continue; 204353654Seric if (*p != '\0') 204453654Seric *p++ = '\0'; 204558050Seric while (isascii(*p) && isspace(*p)) 204653654Seric p++; 204758050Seric if (!(isascii(*p) && isalnum(*p))) 204853654Seric { 204953654Seric syserr("readcf: config K line, map %s: no map class", mapname); 205053654Seric return; 205153654Seric } 205253654Seric classname = p; 205358050Seric while (isascii(*++p) && isalnum(*p)) 205453654Seric continue; 205553654Seric if (*p != '\0') 205653654Seric *p++ = '\0'; 205758050Seric while (isascii(*p) && isspace(*p)) 205853654Seric p++; 205953654Seric 206053654Seric /* look up the class */ 206153654Seric class = stab(classname, ST_MAPCLASS, ST_FIND); 206253654Seric if (class == NULL) 206353654Seric { 206453654Seric syserr("readcf: map %s: class %s not available", mapname, classname); 206553654Seric return; 206653654Seric } 206753654Seric 206853654Seric /* enter the map */ 206964078Seric s = stab(mapname, ST_MAP, ST_ENTER); 207064078Seric s->s_map.map_class = &class->s_mapclass; 207164078Seric s->s_map.map_mname = newstr(mapname); 207253654Seric 207364078Seric if (class->s_mapclass.map_parse(&s->s_map, p)) 207464078Seric s->s_map.map_mflags |= MF_VALID; 207564078Seric 207664078Seric if (tTd(37, 5)) 207764078Seric { 207864078Seric printf("map %s, class %s, flags %x, file %s,\n", 207964078Seric s->s_map.map_mname, s->s_map.map_class->map_cname, 208064078Seric s->s_map.map_mflags, 208164078Seric s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 208264078Seric printf("\tapp %s, domain %s, rebuild %s\n", 208364078Seric s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 208464078Seric s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 208564078Seric s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 208664078Seric } 208753654Seric } 208858112Seric /* 208968481Seric ** INITTIMEOUTS -- parse and set timeout values 209058112Seric ** 209158112Seric ** Parameters: 209258112Seric ** val -- a pointer to the values. If NULL, do initial 209358112Seric ** settings. 209458112Seric ** 209558112Seric ** Returns: 209658112Seric ** none. 209758112Seric ** 209858112Seric ** Side Effects: 209958112Seric ** Initializes the TimeOuts structure 210058112Seric */ 210158112Seric 210264255Seric #define SECONDS 210358112Seric #define MINUTES * 60 210458112Seric #define HOUR * 3600 210558112Seric 210668481Seric inittimeouts(val) 210758112Seric register char *val; 210858112Seric { 210958112Seric register char *p; 211058671Seric extern time_t convtime(); 211158112Seric 211258112Seric if (val == NULL) 211358112Seric { 211458112Seric TimeOuts.to_initial = (time_t) 5 MINUTES; 211558112Seric TimeOuts.to_helo = (time_t) 5 MINUTES; 211658112Seric TimeOuts.to_mail = (time_t) 10 MINUTES; 211758112Seric TimeOuts.to_rcpt = (time_t) 1 HOUR; 211858112Seric TimeOuts.to_datainit = (time_t) 5 MINUTES; 211958112Seric TimeOuts.to_datablock = (time_t) 1 HOUR; 212058112Seric TimeOuts.to_datafinal = (time_t) 1 HOUR; 212158112Seric TimeOuts.to_rset = (time_t) 5 MINUTES; 212258112Seric TimeOuts.to_quit = (time_t) 2 MINUTES; 212358112Seric TimeOuts.to_nextcommand = (time_t) 1 HOUR; 212458112Seric TimeOuts.to_miscshort = (time_t) 2 MINUTES; 212568481Seric #if IDENTPROTO 212664255Seric TimeOuts.to_ident = (time_t) 30 SECONDS; 212768481Seric #else 212868481Seric TimeOuts.to_ident = (time_t) 0 SECONDS; 212968481Seric #endif 213068481Seric TimeOuts.to_fileopen = (time_t) 60 SECONDS; 213158112Seric return; 213258112Seric } 213358112Seric 213458112Seric for (;; val = p) 213558112Seric { 213658112Seric while (isascii(*val) && isspace(*val)) 213758112Seric val++; 213858112Seric if (*val == '\0') 213958112Seric break; 214058112Seric for (p = val; *p != '\0' && *p != ','; p++) 214158112Seric continue; 214258112Seric if (*p != '\0') 214358112Seric *p++ = '\0'; 214458112Seric 214558112Seric if (isascii(*val) && isdigit(*val)) 214658112Seric { 214758112Seric /* old syntax -- set everything */ 214858796Seric TimeOuts.to_mail = convtime(val, 'm'); 214958112Seric TimeOuts.to_rcpt = TimeOuts.to_mail; 215058112Seric TimeOuts.to_datainit = TimeOuts.to_mail; 215158112Seric TimeOuts.to_datablock = TimeOuts.to_mail; 215258112Seric TimeOuts.to_datafinal = TimeOuts.to_mail; 215358112Seric TimeOuts.to_nextcommand = TimeOuts.to_mail; 215458112Seric continue; 215558112Seric } 215658112Seric else 215758112Seric { 215868481Seric register char *q = strchr(val, ':'); 215958112Seric 216068481Seric if (q == NULL && (q = strchr(val, '=')) == NULL) 216158112Seric { 216258112Seric /* syntax error */ 216358112Seric continue; 216458112Seric } 216558112Seric *q++ = '\0'; 216668481Seric settimeout(val, q); 216768481Seric } 216868481Seric } 216968481Seric } 217068481Seric /* 217168481Seric ** SETTIMEOUT -- set an individual timeout 217268481Seric ** 217368481Seric ** Parameters: 217468481Seric ** name -- the name of the timeout. 217568481Seric ** val -- the value of the timeout. 217668481Seric ** 217768481Seric ** Returns: 217868481Seric ** none. 217968481Seric */ 218058112Seric 218168481Seric settimeout(name, val) 218268481Seric char *name; 218368481Seric char *val; 218468481Seric { 218568481Seric register char *p; 218668481Seric time_t to; 218768481Seric extern time_t convtime(); 218868481Seric 218968481Seric to = convtime(val, 'm'); 219068481Seric p = strchr(name, '.'); 219168481Seric if (p != NULL) 219268481Seric *p++ = '\0'; 219368481Seric 219468481Seric if (strcasecmp(name, "initial") == 0) 219568481Seric TimeOuts.to_initial = to; 219668481Seric else if (strcasecmp(name, "mail") == 0) 219768481Seric TimeOuts.to_mail = to; 219868481Seric else if (strcasecmp(name, "rcpt") == 0) 219968481Seric TimeOuts.to_rcpt = to; 220068481Seric else if (strcasecmp(name, "datainit") == 0) 220168481Seric TimeOuts.to_datainit = to; 220268481Seric else if (strcasecmp(name, "datablock") == 0) 220368481Seric TimeOuts.to_datablock = to; 220468481Seric else if (strcasecmp(name, "datafinal") == 0) 220568481Seric TimeOuts.to_datafinal = to; 220668481Seric else if (strcasecmp(name, "command") == 0) 220768481Seric TimeOuts.to_nextcommand = to; 220868481Seric else if (strcasecmp(name, "rset") == 0) 220968481Seric TimeOuts.to_rset = to; 221068481Seric else if (strcasecmp(name, "helo") == 0) 221168481Seric TimeOuts.to_helo = to; 221268481Seric else if (strcasecmp(name, "quit") == 0) 221368481Seric TimeOuts.to_quit = to; 221468481Seric else if (strcasecmp(name, "misc") == 0) 221568481Seric TimeOuts.to_miscshort = to; 221668481Seric else if (strcasecmp(name, "ident") == 0) 221768481Seric TimeOuts.to_ident = to; 221868481Seric else if (strcasecmp(name, "fileopen") == 0) 221968481Seric TimeOuts.to_fileopen = to; 222068481Seric else if (strcasecmp(name, "queuewarn") == 0) 222168481Seric { 222268481Seric to = convtime(val, 'h'); 222368481Seric if (p == NULL || strcmp(p, "*") == 0) 222468481Seric { 222568481Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 222668481Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 222768481Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 222858112Seric } 222968481Seric else if (strcasecmp(p, "normal") == 0) 223068481Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 223168481Seric else if (strcasecmp(p, "urgent") == 0) 223268481Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 223368481Seric else if (strcasecmp(p, "non-urgent") == 0) 223468481Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 223568481Seric else 223668481Seric syserr("settimeout: invalid queuewarn subtimeout %s", p); 223758112Seric } 223868481Seric else if (strcasecmp(name, "queuereturn") == 0) 223968481Seric { 224068481Seric to = convtime(val, 'd'); 224168481Seric if (p == NULL || strcmp(p, "*") == 0) 224268481Seric { 224368481Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 224468481Seric TimeOuts.to_q_return[TOC_URGENT] = to; 224568481Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 224668481Seric } 224768481Seric else if (strcasecmp(p, "normal") == 0) 224868481Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 224968481Seric else if (strcasecmp(p, "urgent") == 0) 225068481Seric TimeOuts.to_q_return[TOC_URGENT] = to; 225168481Seric else if (strcasecmp(p, "non-urgent") == 0) 225268481Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 225368481Seric else 225468481Seric syserr("settimeout: invalid queuereturn subtimeout %s", p); 225568481Seric } 225668481Seric else 225768481Seric syserr("settimeout: invalid timeout %s", name); 225858112Seric } 2259