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*68856Seric static char sccsid[] = "@(#)readcf.c 8.87 (Berkeley) 04/22/95"; 1133731Sbostic #endif /* not lint */ 1222709Sdist 133313Seric # include "sendmail.h" 1464133Seric # include <grp.h> 1566334Seric #if NAMED_BIND 1657207Seric # include <resolv.h> 1757207Seric #endif 183308Seric 193308Seric /* 203308Seric ** READCF -- read control file. 213308Seric ** 223308Seric ** This routine reads the control file and builds the internal 233308Seric ** form. 243308Seric ** 254432Seric ** The file is formatted as a sequence of lines, each taken 264432Seric ** atomically. The first character of each line describes how 274432Seric ** the line is to be interpreted. The lines are: 284432Seric ** Dxval Define macro x to have value val. 294432Seric ** Cxword Put word into class x. 304432Seric ** Fxfile [fmt] Read file for lines to put into 314432Seric ** class x. Use scanf string 'fmt' 324432Seric ** or "%s" if not present. Fmt should 334432Seric ** only produce one string-valued result. 344432Seric ** Hname: value Define header with field-name 'name' 354432Seric ** and value as specified; this will be 364432Seric ** macro expanded immediately before 374432Seric ** use. 384432Seric ** Sn Use rewriting set n. 394432Seric ** Rlhs rhs Rewrite addresses that match lhs to 404432Seric ** be rhs. 4124944Seric ** Mn arg=val... Define mailer. n is the internal name. 4224944Seric ** Args specify mailer parameters. 438252Seric ** Oxvalue Set option x to value. 448252Seric ** Pname=value Set precedence name to value. 4564718Seric ** Vversioncode[/vendorcode] 4664718Seric ** Version level/vendor name of 4764718Seric ** configuration syntax. 4853654Seric ** Kmapname mapclass arguments.... 4953654Seric ** Define keyed lookup of a given class. 5053654Seric ** Arguments are class dependent. 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; 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 75268816Seric ** N -- the niceness at which to run 75368479Seric ** P -- the path to the mailer 75468481Seric ** R -- the recipient rewriting set 75568479Seric ** S -- the sender rewriting set 75668481Seric ** T -- the mailer type (for DSNs) 75768481Seric ** U -- the uid to run as 75810327Seric ** The first word is the canonical name of the mailer. 7594096Seric ** 7604096Seric ** Returns: 7614096Seric ** none. 7624096Seric ** 7634096Seric ** Side Effects: 7644096Seric ** enters the mailer into the mailer table. 7654096Seric */ 7663308Seric 76721066Seric makemailer(line) 7684096Seric char *line; 7694096Seric { 7704096Seric register char *p; 7718067Seric register struct mailer *m; 7728067Seric register STAB *s; 7738067Seric int i; 77410327Seric char fcode; 77558020Seric auto char *endp; 7764096Seric extern int NextMailer; 77710327Seric extern char **makeargv(); 77810327Seric extern char *munchstring(); 7794096Seric 78010327Seric /* allocate a mailer and set up defaults */ 78110327Seric m = (struct mailer *) xalloc(sizeof *m); 78210327Seric bzero((char *) m, sizeof *m); 78310327Seric m->m_eol = "\n"; 78468481Seric m->m_uid = m->m_gid = 0; 78510327Seric 78610327Seric /* collect the mailer name */ 78758050Seric for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++) 78810327Seric continue; 78910327Seric if (*p != '\0') 79010327Seric *p++ = '\0'; 79110327Seric m->m_name = newstr(line); 79210327Seric 79310327Seric /* now scan through and assign info from the fields */ 79410327Seric while (*p != '\0') 79510327Seric { 79658333Seric auto char *delimptr; 79758333Seric 79858050Seric while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p)))) 79910327Seric p++; 80010327Seric 80110327Seric /* p now points to field code */ 80210327Seric fcode = *p; 80310327Seric while (*p != '\0' && *p != '=' && *p != ',') 80410327Seric p++; 80510327Seric if (*p++ != '=') 80610327Seric { 80752637Seric syserr("mailer %s: `=' expected", m->m_name); 80810327Seric return; 80910327Seric } 81058050Seric while (isascii(*p) && isspace(*p)) 81110327Seric p++; 81210327Seric 81310327Seric /* p now points to the field body */ 81458333Seric p = munchstring(p, &delimptr); 81510327Seric 81610327Seric /* install the field into the mailer struct */ 81710327Seric switch (fcode) 81810327Seric { 81910327Seric case 'P': /* pathname */ 82010327Seric m->m_mailer = newstr(p); 82110327Seric break; 82210327Seric 82310327Seric case 'F': /* flags */ 82410687Seric for (; *p != '\0'; p++) 82558050Seric if (!(isascii(*p) && isspace(*p))) 82652637Seric setbitn(*p, m->m_flags); 82710327Seric break; 82810327Seric 82910327Seric case 'S': /* sender rewriting ruleset */ 83010327Seric case 'R': /* recipient rewriting ruleset */ 83158020Seric i = strtol(p, &endp, 10); 83210327Seric if (i < 0 || i >= MAXRWSETS) 83310327Seric { 83410327Seric syserr("invalid rewrite set, %d max", MAXRWSETS); 83510327Seric return; 83610327Seric } 83710327Seric if (fcode == 'S') 83858020Seric m->m_sh_rwset = m->m_se_rwset = i; 83910327Seric else 84058020Seric m->m_rh_rwset = m->m_re_rwset = i; 84158020Seric 84258020Seric p = endp; 84359985Seric if (*p++ == '/') 84458020Seric { 84558020Seric i = strtol(p, NULL, 10); 84658020Seric if (i < 0 || i >= MAXRWSETS) 84758020Seric { 84858020Seric syserr("invalid rewrite set, %d max", 84958020Seric MAXRWSETS); 85058020Seric return; 85158020Seric } 85258020Seric if (fcode == 'S') 85358020Seric m->m_sh_rwset = i; 85458020Seric else 85558020Seric m->m_rh_rwset = i; 85658020Seric } 85710327Seric break; 85810327Seric 85910327Seric case 'E': /* end of line string */ 86010327Seric m->m_eol = newstr(p); 86110327Seric break; 86210327Seric 86310327Seric case 'A': /* argument vector */ 86410327Seric m->m_argv = makeargv(p); 86510327Seric break; 86610701Seric 86710701Seric case 'M': /* maximum message size */ 86810701Seric m->m_maxsize = atol(p); 86910701Seric break; 87052106Seric 87152106Seric case 'L': /* maximum line length */ 87252106Seric m->m_linelimit = atoi(p); 87352106Seric break; 87458935Seric 87568816Seric case 'N': /* run niceness */ 87668816Seric m->m_nice = atoi(p); 87768816Seric break; 87868816Seric 87958935Seric case 'D': /* working directory */ 88058935Seric m->m_execdir = newstr(p); 88158935Seric break; 88268481Seric 88368481Seric case 'C': /* default charset */ 88468481Seric m->m_defcharset = newstr(p); 88568481Seric break; 88668481Seric 88768481Seric case 'T': /* MTA Type */ 88868481Seric m->m_mtatype = newstr(p); 88968481Seric p = strchr(m->m_mtatype, '/'); 89068481Seric if (p != NULL) 89168481Seric { 89268481Seric *p++ = '\0'; 89368481Seric if (*p == '\0') 89468481Seric p = NULL; 89568481Seric } 89668481Seric if (p == NULL) 89768481Seric m->m_addrtype = m->m_mtatype; 89868481Seric else 89968481Seric { 90068481Seric m->m_addrtype = p; 90168481Seric p = strchr(p, '/'); 90268481Seric } 90368481Seric if (p != NULL) 90468481Seric { 90568481Seric *p++ = '\0'; 90668481Seric if (*p == '\0') 90768481Seric p = NULL; 90868481Seric } 90968481Seric if (p == NULL) 91068481Seric m->m_diagtype = m->m_mtatype; 91168481Seric else 91268481Seric m->m_diagtype = p; 91368481Seric break; 91468481Seric 91568481Seric case 'U': /* user id */ 91668481Seric if (isascii(*p) && !isdigit(*p)) 91768481Seric { 91868481Seric char *q = p; 91968481Seric struct passwd *pw; 92068481Seric 92168481Seric while (isascii(*p) && isalnum(*p)) 92268481Seric p++; 92368481Seric while (isascii(*p) && isspace(*p)) 92468481Seric *p++ = '\0'; 92568481Seric if (*p != '\0') 92668481Seric *p++ = '\0'; 92768693Seric pw = sm_getpwnam(q); 92868481Seric if (pw == NULL) 92968481Seric syserr("readcf: mailer U= flag: unknown user %s", q); 93068481Seric else 93168481Seric { 93268481Seric m->m_uid = pw->pw_uid; 93368481Seric m->m_gid = pw->pw_gid; 93468481Seric } 93568481Seric } 93668481Seric else 93768481Seric { 93868481Seric auto char *q; 93968481Seric 94068481Seric m->m_uid = strtol(p, &q, 0); 94168481Seric p = q; 94268481Seric } 94368481Seric while (isascii(*p) && isspace(*p)) 94468481Seric p++; 94568481Seric if (*p == '\0') 94668481Seric break; 94768481Seric if (isascii(*p) && !isdigit(*p)) 94868481Seric { 94968481Seric char *q = p; 95068481Seric struct group *gr; 95168481Seric 95268481Seric while (isascii(*p) && isalnum(*p)) 95368481Seric p++; 95468481Seric *p++ = '\0'; 95568481Seric gr = getgrnam(q); 95668481Seric if (gr == NULL) 95768481Seric syserr("readcf: mailer U= flag: unknown group %s", q); 95868481Seric else 95968481Seric m->m_gid = gr->gr_gid; 96068481Seric } 96168481Seric else 96268481Seric { 96368481Seric m->m_gid = strtol(p, NULL, 0); 96468481Seric } 96568481Seric break; 96610327Seric } 96710327Seric 96858333Seric p = delimptr; 96910327Seric } 97010327Seric 97158321Seric /* do some rationality checking */ 97258321Seric if (m->m_argv == NULL) 97358321Seric { 97458321Seric syserr("M%s: A= argument required", m->m_name); 97558321Seric return; 97658321Seric } 97758321Seric if (m->m_mailer == NULL) 97858321Seric { 97958321Seric syserr("M%s: P= argument required", m->m_name); 98058321Seric return; 98158321Seric } 98258321Seric 9834096Seric if (NextMailer >= MAXMAILERS) 9844096Seric { 9859381Seric syserr("too many mailers defined (%d max)", MAXMAILERS); 9864096Seric return; 9874096Seric } 98857402Seric 98968481Seric /* do some heuristic cleanup for back compatibility */ 99068481Seric if (bitnset(M_LIMITS, m->m_flags)) 99168481Seric { 99268481Seric if (m->m_linelimit == 0) 99368481Seric m->m_linelimit = SMTPLINELIM; 99468481Seric if (ConfigLevel < 2) 99568481Seric setbitn(M_7BITS, m->m_flags); 99668481Seric } 99768481Seric 99868481Seric if (ConfigLevel < 6 && 99968481Seric (strcmp(m->m_mailer, "[IPC]") == 0 || 100068481Seric strcmp(m->m_mailer, "[TCP]") == 0)) 100168481Seric { 100268481Seric if (m->m_mtatype == NULL) 100368481Seric m->m_mtatype = "dns"; 100468481Seric if (m->m_addrtype == NULL) 100568481Seric m->m_addrtype = "rfc822"; 100668481Seric if (m->m_diagtype == NULL) 100768481Seric m->m_diagtype = "smtp"; 100868481Seric } 100968481Seric 101068481Seric /* enter the mailer into the symbol table */ 101110327Seric s = stab(m->m_name, ST_MAILER, ST_ENTER); 101257402Seric if (s->s_mailer != NULL) 101357402Seric { 101457402Seric i = s->s_mailer->m_mno; 101557402Seric free(s->s_mailer); 101657402Seric } 101757402Seric else 101857402Seric { 101957402Seric i = NextMailer++; 102057402Seric } 102157402Seric Mailer[i] = s->s_mailer = m; 102257454Seric m->m_mno = i; 102310327Seric } 102410327Seric /* 102510327Seric ** MUNCHSTRING -- translate a string into internal form. 102610327Seric ** 102710327Seric ** Parameters: 102810327Seric ** p -- the string to munch. 102958333Seric ** delimptr -- if non-NULL, set to the pointer of the 103058333Seric ** field delimiter character. 103110327Seric ** 103210327Seric ** Returns: 103310327Seric ** the munched string. 103410327Seric */ 10354096Seric 103610327Seric char * 103758333Seric munchstring(p, delimptr) 103810327Seric register char *p; 103958333Seric char **delimptr; 104010327Seric { 104110327Seric register char *q; 104210327Seric bool backslash = FALSE; 104310327Seric bool quotemode = FALSE; 104410327Seric static char buf[MAXLINE]; 10454096Seric 104610327Seric for (q = buf; *p != '\0'; p++) 10474096Seric { 104810327Seric if (backslash) 104910327Seric { 105010327Seric /* everything is roughly literal */ 105110357Seric backslash = FALSE; 105210327Seric switch (*p) 105310327Seric { 105410327Seric case 'r': /* carriage return */ 105510327Seric *q++ = '\r'; 105610327Seric continue; 105710327Seric 105810327Seric case 'n': /* newline */ 105910327Seric *q++ = '\n'; 106010327Seric continue; 106110327Seric 106210327Seric case 'f': /* form feed */ 106310327Seric *q++ = '\f'; 106410327Seric continue; 106510327Seric 106610327Seric case 'b': /* backspace */ 106710327Seric *q++ = '\b'; 106810327Seric continue; 106910327Seric } 107010327Seric *q++ = *p; 107110327Seric } 107210327Seric else 107310327Seric { 107410327Seric if (*p == '\\') 107510327Seric backslash = TRUE; 107610327Seric else if (*p == '"') 107710327Seric quotemode = !quotemode; 107810327Seric else if (quotemode || *p != ',') 107910327Seric *q++ = *p; 108010327Seric else 108110327Seric break; 108210327Seric } 10834096Seric } 10844096Seric 108558333Seric if (delimptr != NULL) 108658333Seric *delimptr = p; 108710327Seric *q++ = '\0'; 108810327Seric return (buf); 108910327Seric } 109010327Seric /* 109110327Seric ** MAKEARGV -- break up a string into words 109210327Seric ** 109310327Seric ** Parameters: 109410327Seric ** p -- the string to break up. 109510327Seric ** 109610327Seric ** Returns: 109710327Seric ** a char **argv (dynamically allocated) 109810327Seric ** 109910327Seric ** Side Effects: 110010327Seric ** munges p. 110110327Seric */ 11024096Seric 110310327Seric char ** 110410327Seric makeargv(p) 110510327Seric register char *p; 110610327Seric { 110710327Seric char *q; 110810327Seric int i; 110910327Seric char **avp; 111010327Seric char *argv[MAXPV + 1]; 111110327Seric 111210327Seric /* take apart the words */ 111310327Seric i = 0; 111410327Seric while (*p != '\0' && i < MAXPV) 11154096Seric { 111610327Seric q = p; 111758050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 111810327Seric p++; 111958050Seric while (isascii(*p) && isspace(*p)) 112010327Seric *p++ = '\0'; 112110327Seric argv[i++] = newstr(q); 11224096Seric } 112310327Seric argv[i++] = NULL; 11244096Seric 112510327Seric /* now make a copy of the argv */ 112610327Seric avp = (char **) xalloc(sizeof *avp * i); 112716893Seric bcopy((char *) argv, (char *) avp, sizeof *avp * i); 112810327Seric 112910327Seric return (avp); 11303308Seric } 11313308Seric /* 11323308Seric ** PRINTRULES -- print rewrite rules (for debugging) 11333308Seric ** 11343308Seric ** Parameters: 11353308Seric ** none. 11363308Seric ** 11373308Seric ** Returns: 11383308Seric ** none. 11393308Seric ** 11403308Seric ** Side Effects: 11413308Seric ** prints rewrite rules. 11423308Seric */ 11433308Seric 11443308Seric printrules() 11453308Seric { 11463308Seric register struct rewrite *rwp; 11474072Seric register int ruleset; 11483308Seric 11494072Seric for (ruleset = 0; ruleset < 10; ruleset++) 11503308Seric { 11514072Seric if (RewriteRules[ruleset] == NULL) 11524072Seric continue; 11538067Seric printf("\n----Rule Set %d:", ruleset); 11543308Seric 11554072Seric for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 11563308Seric { 11578067Seric printf("\nLHS:"); 11588067Seric printav(rwp->r_lhs); 11598067Seric printf("RHS:"); 11608067Seric printav(rwp->r_rhs); 11613308Seric } 11623308Seric } 11633308Seric } 116468481Seric /* 116568481Seric ** PRINTMAILER -- print mailer structure (for debugging) 116668481Seric ** 116768481Seric ** Parameters: 116868481Seric ** m -- the mailer to print 116968481Seric ** 117068481Seric ** Returns: 117168481Seric ** none. 117268481Seric */ 11734319Seric 117468481Seric printmailer(m) 117568481Seric register MAILER *m; 117668481Seric { 117768481Seric int j; 117868481Seric 117968481Seric printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld U=%d:%d F=", 118068481Seric m->m_mno, m->m_name, 118168481Seric m->m_mailer, m->m_se_rwset, m->m_sh_rwset, 118268481Seric m->m_re_rwset, m->m_rh_rwset, m->m_maxsize, 118368481Seric m->m_uid, m->m_gid); 118468481Seric for (j = '\0'; j <= '\177'; j++) 118568481Seric if (bitnset(j, m->m_flags)) 118668481Seric (void) putchar(j); 118768481Seric printf(" L=%d E=", m->m_linelimit); 118868481Seric xputs(m->m_eol); 118968481Seric if (m->m_defcharset != NULL) 119068481Seric printf(" C=%s", m->m_defcharset); 119168481Seric printf(" T=%s/%s/%s", 119268481Seric m->m_mtatype == NULL ? "<undefined>" : m->m_mtatype, 119368481Seric m->m_addrtype == NULL ? "<undefined>" : m->m_addrtype, 119468481Seric m->m_diagtype == NULL ? "<undefined>" : m->m_diagtype); 119568481Seric if (m->m_argv != NULL) 119668481Seric { 119768481Seric char **a = m->m_argv; 119868481Seric 119968481Seric printf(" A="); 120068481Seric while (*a != NULL) 120168481Seric { 120268481Seric if (a != m->m_argv) 120368481Seric printf(" "); 120468481Seric xputs(*a++); 120568481Seric } 120668481Seric } 120768481Seric printf("\n"); 120868481Seric } 12094096Seric /* 12108256Seric ** SETOPTION -- set global processing option 12118256Seric ** 12128256Seric ** Parameters: 12138256Seric ** opt -- option name. 12148256Seric ** val -- option value (as a text string). 121521755Seric ** safe -- set if this came from a configuration file. 121621755Seric ** Some options (if set from the command line) will 121721755Seric ** reset the user id to avoid security problems. 12188269Seric ** sticky -- if set, don't let other setoptions override 12198269Seric ** this value. 122058734Seric ** e -- the main envelope. 12218256Seric ** 12228256Seric ** Returns: 12238256Seric ** none. 12248256Seric ** 12258256Seric ** Side Effects: 12268256Seric ** Sets options as implied by the arguments. 12278256Seric */ 12288256Seric 122910687Seric static BITMAP StickyOpt; /* set if option is stuck */ 12308269Seric 123157207Seric 123266334Seric #if NAMED_BIND 123357207Seric 123457207Seric struct resolverflags 123557207Seric { 123657207Seric char *rf_name; /* name of the flag */ 123757207Seric long rf_bits; /* bits to set/clear */ 123857207Seric } ResolverFlags[] = 123957207Seric { 124057207Seric "debug", RES_DEBUG, 124157207Seric "aaonly", RES_AAONLY, 124257207Seric "usevc", RES_USEVC, 124357207Seric "primary", RES_PRIMARY, 124457207Seric "igntc", RES_IGNTC, 124557207Seric "recurse", RES_RECURSE, 124657207Seric "defnames", RES_DEFNAMES, 124757207Seric "stayopen", RES_STAYOPEN, 124857207Seric "dnsrch", RES_DNSRCH, 124965583Seric "true", 0, /* to avoid error on old syntax */ 125057207Seric NULL, 0 125157207Seric }; 125257207Seric 125357207Seric #endif 125457207Seric 125568481Seric struct optioninfo 125668481Seric { 125768481Seric char *o_name; /* long name of option */ 125868481Seric u_char o_code; /* short name of option */ 125968481Seric bool o_safe; /* safe for random people to use */ 126068481Seric } OptionTab[] = 126168481Seric { 126268481Seric "SevenBitInput", '7', TRUE, 126368481Seric "EightBitMode", '8', TRUE, 126468481Seric "AliasFile", 'A', FALSE, 126568481Seric "AliasWait", 'a', FALSE, 126668481Seric "BlankSub", 'B', FALSE, 126768481Seric "MinFreeBlocks", 'b', TRUE, 126868481Seric "CheckpointInterval", 'C', TRUE, 126968481Seric "HoldExpensive", 'c', FALSE, 127068481Seric "AutoRebuildAliases", 'D', FALSE, 127168481Seric "DeliveryMode", 'd', TRUE, 127268481Seric "ErrorHeader", 'E', FALSE, 127368481Seric "ErrorMode", 'e', TRUE, 127468481Seric "TempFileMode", 'F', FALSE, 127568481Seric "SaveFromLine", 'f', FALSE, 127668481Seric "MatchGECOS", 'G', FALSE, 127768481Seric "HelpFile", 'H', FALSE, 127868481Seric "MaxHopCount", 'h', FALSE, 127968569Seric "ResolverOptions", 'I', FALSE, 128068481Seric "IgnoreDots", 'i', TRUE, 128168481Seric "ForwardPath", 'J', FALSE, 128268481Seric "SendMimeErrors", 'j', TRUE, 128368481Seric "ConnectionCacheSize", 'k', FALSE, 128468481Seric "ConnectionCacheTimeout", 'K', FALSE, 128568481Seric "UseErrorsTo", 'l', FALSE, 128668481Seric "LogLevel", 'L', FALSE, 128768481Seric "MeToo", 'm', TRUE, 128868481Seric "CheckAliases", 'n', FALSE, 128968481Seric "OldStyleHeaders", 'o', TRUE, 129068481Seric "DaemonPortOptions", 'O', FALSE, 129168481Seric "PrivacyOptions", 'p', TRUE, 129268481Seric "PostmasterCopy", 'P', FALSE, 129368481Seric "QueueFactor", 'q', FALSE, 129468481Seric "QueueDirectory", 'Q', FALSE, 129568481Seric "DontPruneRoutes", 'R', FALSE, 129668481Seric "Timeout", 'r', TRUE, 129768481Seric "StatusFile", 'S', FALSE, 129868481Seric "SuperSafe", 's', TRUE, 129968481Seric "QueueTimeout", 'T', FALSE, 130068481Seric "TimeZoneSpec", 't', FALSE, 130168481Seric "UserDatabaseSpec", 'U', FALSE, 130268481Seric "DefaultUser", 'u', FALSE, 130368481Seric "FallbackMXhost", 'V', FALSE, 130468481Seric "Verbose", 'v', TRUE, 130568481Seric "TryNullMXList", 'w', TRUE, 130668481Seric "QueueLA", 'x', FALSE, 130768481Seric "RefuseLA", 'X', FALSE, 130868481Seric "RecipientFactor", 'y', FALSE, 130968569Seric "ForkEachJob", 'Y', FALSE, 131068481Seric "ClassFactor", 'z', FALSE, 131168569Seric "RetryFactor", 'Z', FALSE, 131268481Seric #define O_QUEUESORTORD 0x81 131368481Seric "QueueSortOrder", O_QUEUESORTORD, TRUE, 131468481Seric #define O_MQA 0x83 131568481Seric "MinQueueAge", O_MQA, TRUE, 131668481Seric #define O_MHSA 0x84 131768481Seric /* 131868481Seric "MaxHostStatAge", O_MHSA, TRUE, 131968481Seric */ 132068481Seric #define O_DEFCHARSET 0x85 132168481Seric "DefaultCharSet", O_DEFCHARSET, TRUE, 132268481Seric #define O_SSFILE 0x86 132368481Seric "ServiceSwitchFile", O_SSFILE, FALSE, 132468481Seric #define O_DIALDELAY 0x87 132568481Seric "DialDelay", O_DIALDELAY, TRUE, 132668481Seric #define O_NORCPTACTION 0x88 132768481Seric "NoRecipientAction", O_NORCPTACTION, TRUE, 132868490Seric #define O_SAFEFILEENV 0x89 132968490Seric "SafeFileEnvironment", O_SAFEFILEENV, FALSE, 133068569Seric #define O_MAXMSGSIZE 0x8a 133168569Seric "MaxMessageSize", O_MAXMSGSIZE, FALSE, 133268756Seric #define O_COLONOKINADDR 0x8b 133368756Seric "ColonOkInAddr", O_COLONOKINADDR, TRUE, 133468481Seric 133568481Seric NULL, '\0', FALSE, 133668481Seric }; 133768481Seric 133868481Seric 133968481Seric 134058734Seric setoption(opt, val, safe, sticky, e) 134168481Seric u_char opt; 13428256Seric char *val; 134321755Seric bool safe; 13448269Seric bool sticky; 134558734Seric register ENVELOPE *e; 13468256Seric { 134757207Seric register char *p; 134868481Seric register struct optioninfo *o; 134968481Seric char *subopt; 13508265Seric extern bool atobool(); 135112633Seric extern time_t convtime(); 135214879Seric extern int QueueLA; 135314879Seric extern int RefuseLA; 135464718Seric extern bool Warn_Q_option; 13558256Seric 135668481Seric errno = 0; 135768481Seric if (opt == ' ') 135868481Seric { 135968481Seric /* full word options */ 136068481Seric struct optioninfo *sel; 136168481Seric 136268481Seric p = strchr(val, '='); 136368481Seric if (p == NULL) 136468481Seric p = &val[strlen(val)]; 136568481Seric while (*--p == ' ') 136668481Seric continue; 136768481Seric while (*++p == ' ') 136868481Seric *p = '\0'; 136968481Seric if (p == val) 137068481Seric { 137168481Seric syserr("readcf: null option name"); 137268481Seric return; 137368481Seric } 137468481Seric if (*p == '=') 137568481Seric *p++ = '\0'; 137668481Seric while (*p == ' ') 137768481Seric p++; 137868481Seric subopt = strchr(val, '.'); 137968481Seric if (subopt != NULL) 138068481Seric *subopt++ = '\0'; 138168481Seric sel = NULL; 138268481Seric for (o = OptionTab; o->o_name != NULL; o++) 138368481Seric { 138468481Seric if (strncasecmp(o->o_name, val, strlen(val)) != 0) 138568481Seric continue; 138668481Seric if (strlen(o->o_name) == strlen(val)) 138768481Seric { 138868481Seric /* completely specified -- this must be it */ 138968481Seric sel = NULL; 139068481Seric break; 139168481Seric } 139268481Seric if (sel != NULL) 139368481Seric break; 139468481Seric sel = o; 139568481Seric } 139668481Seric if (sel != NULL && o->o_name == NULL) 139768481Seric o = sel; 139868481Seric else if (o->o_name == NULL) 139968481Seric { 140068481Seric syserr("readcf: unknown option name %s", val); 140168481Seric return; 140268481Seric } 140368481Seric else if (sel != NULL) 140468481Seric { 140568481Seric syserr("readcf: ambiguous option name %s (matches %s and %s)", 140668481Seric val, sel->o_name, o->o_name); 140768481Seric return; 140868481Seric } 140968481Seric if (strlen(val) != strlen(o->o_name)) 141068481Seric { 141168481Seric bool oldVerbose = Verbose; 141268481Seric 141368481Seric Verbose = TRUE; 141468481Seric message("Option %s used as abbreviation for %s", 141568481Seric val, o->o_name); 141668481Seric Verbose = oldVerbose; 141768481Seric } 141868481Seric opt = o->o_code; 141968481Seric val = p; 142068481Seric } 142168481Seric else 142268481Seric { 142368481Seric for (o = OptionTab; o->o_name != NULL; o++) 142468481Seric { 142568481Seric if (o->o_code == opt) 142668481Seric break; 142768481Seric } 142868481Seric subopt = NULL; 142968481Seric } 143068481Seric 14318256Seric if (tTd(37, 1)) 143268481Seric { 143368481Seric printf(isascii(opt) && isprint(opt) ? 143468481Seric "setoption %s (%c).%s=%s" : 143568481Seric "setoption %s (0x%x).%s=%s", 143668481Seric o->o_name == NULL ? "<unknown>" : o->o_name, 143768481Seric opt, 143868481Seric subopt == NULL ? "" : subopt, 143968481Seric val); 144068481Seric } 14418256Seric 14428256Seric /* 14438269Seric ** See if this option is preset for us. 14448256Seric */ 14458256Seric 144659731Seric if (!sticky && bitnset(opt, StickyOpt)) 14478269Seric { 14489341Seric if (tTd(37, 1)) 14499341Seric printf(" (ignored)\n"); 14508269Seric return; 14518269Seric } 14528269Seric 145321755Seric /* 145421755Seric ** Check to see if this option can be specified by this user. 145521755Seric */ 145621755Seric 145763787Seric if (!safe && RealUid == 0) 145821755Seric safe = TRUE; 145968481Seric if (!safe && !o->o_safe) 146021755Seric { 146139111Srick if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 146221755Seric { 146336582Sbostic if (tTd(37, 1)) 146436582Sbostic printf(" (unsafe)"); 146563787Seric if (RealUid != geteuid()) 146636582Sbostic { 146751210Seric if (tTd(37, 1)) 146851210Seric printf("(Resetting uid)"); 146963787Seric (void) setgid(RealGid); 147063787Seric (void) setuid(RealUid); 147136582Sbostic } 147221755Seric } 147321755Seric } 147451210Seric if (tTd(37, 1)) 147517985Seric printf("\n"); 14768269Seric 147768481Seric switch (opt & 0xff) 14788256Seric { 147959709Seric case '7': /* force seven-bit input */ 148068481Seric SevenBitInput = atobool(val); 148152106Seric break; 148252106Seric 148368481Seric case '8': /* handling of 8-bit input */ 148468481Seric switch (*val) 148568481Seric { 148668481Seric case 'm': /* convert 8-bit, convert MIME */ 148768481Seric MimeMode = MM_CVTMIME|MM_MIME8BIT; 148868481Seric break; 148968481Seric 149068481Seric case 'p': /* pass 8 bit, convert MIME */ 1491*68856Seric MimeMode = MM_CVTMIME|MM_PASS8BIT; 149268481Seric break; 149368481Seric 149468481Seric case 's': /* strict adherence */ 149568481Seric MimeMode = MM_CVTMIME; 149668481Seric break; 149768481Seric 1498*68856Seric #if 0 1499*68856Seric case 'r': /* reject 8-bit, don't convert MIME */ 1500*68856Seric MimeMode = 0; 1501*68856Seric break; 1502*68856Seric 1503*68856Seric case 'j': /* "just send 8" */ 1504*68856Seric MimeMode = MM_PASS8BIT; 1505*68856Seric break; 1506*68856Seric 150768481Seric case 'a': /* encode 8 bit if available */ 150868481Seric MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 150968481Seric break; 151068481Seric 151168481Seric case 'c': /* convert 8 bit to MIME, never 7 bit */ 151268481Seric MimeMode = MM_MIME8BIT; 151368481Seric break; 1514*68856Seric #endif 151568481Seric 151668481Seric default: 151768481Seric syserr("Unknown 8-bit mode %c", *val); 151868481Seric exit(EX_USAGE); 151968481Seric } 152068481Seric break; 152168481Seric 15228256Seric case 'A': /* set default alias file */ 15239381Seric if (val[0] == '\0') 152459672Seric setalias("aliases"); 15259381Seric else 152659672Seric setalias(val); 15278256Seric break; 15288256Seric 152917474Seric case 'a': /* look N minutes for "@:@" in alias file */ 153017474Seric if (val[0] == '\0') 153164796Seric SafeAlias = 5 * 60; /* five minutes */ 153217474Seric else 153364796Seric SafeAlias = convtime(val, 'm'); 153417474Seric break; 153517474Seric 153616843Seric case 'B': /* substitution for blank character */ 153716843Seric SpaceSub = val[0]; 153816843Seric if (SpaceSub == '\0') 153916843Seric SpaceSub = ' '; 154016843Seric break; 154116843Seric 154259283Seric case 'b': /* min blocks free on queue fs/max msg size */ 154359283Seric p = strchr(val, '/'); 154459283Seric if (p != NULL) 154559283Seric { 154659283Seric *p++ = '\0'; 154759283Seric MaxMessageSize = atol(p); 154859283Seric } 154958082Seric MinBlocksFree = atol(val); 155058082Seric break; 155158082Seric 15529284Seric case 'c': /* don't connect to "expensive" mailers */ 15539381Seric NoConnect = atobool(val); 15549284Seric break; 15559284Seric 155651305Seric case 'C': /* checkpoint every N addresses */ 155751305Seric CheckpointInterval = atoi(val); 155824944Seric break; 155924944Seric 15609284Seric case 'd': /* delivery mode */ 15619284Seric switch (*val) 15628269Seric { 15639284Seric case '\0': 156458734Seric e->e_sendmode = SM_DELIVER; 15658269Seric break; 15668269Seric 156710755Seric case SM_QUEUE: /* queue only */ 156810755Seric #ifndef QUEUE 156910755Seric syserr("need QUEUE to set -odqueue"); 157056795Seric #endif /* QUEUE */ 157110755Seric /* fall through..... */ 157210755Seric 15739284Seric case SM_DELIVER: /* do everything */ 15749284Seric case SM_FORK: /* fork after verification */ 157558734Seric e->e_sendmode = *val; 15768269Seric break; 15778269Seric 15788269Seric default: 15799284Seric syserr("Unknown delivery mode %c", *val); 15808269Seric exit(EX_USAGE); 15818269Seric } 15828269Seric break; 15838269Seric 15849146Seric case 'D': /* rebuild alias database as needed */ 15859381Seric AutoRebuild = atobool(val); 15869146Seric break; 15879146Seric 158855372Seric case 'E': /* error message header/header file */ 158955379Seric if (*val != '\0') 159055379Seric ErrMsgFile = newstr(val); 159155372Seric break; 159255372Seric 15938269Seric case 'e': /* set error processing mode */ 15948269Seric switch (*val) 15958269Seric { 15969381Seric case EM_QUIET: /* be silent about it */ 15979381Seric case EM_MAIL: /* mail back */ 15989381Seric case EM_BERKNET: /* do berknet error processing */ 15999381Seric case EM_WRITE: /* write back (or mail) */ 16009381Seric case EM_PRINT: /* print errors normally (default) */ 160158734Seric e->e_errormode = *val; 16028269Seric break; 16038269Seric } 16048269Seric break; 16058269Seric 16069049Seric case 'F': /* file mode */ 160717975Seric FileMode = atooct(val) & 0777; 16089049Seric break; 16099049Seric 16108269Seric case 'f': /* save Unix-style From lines on front */ 16119381Seric SaveFrom = atobool(val); 16128269Seric break; 16138269Seric 161453735Seric case 'G': /* match recipients against GECOS field */ 161553735Seric MatchGecos = atobool(val); 161653735Seric break; 161753735Seric 16188256Seric case 'g': /* default gid */ 161968481Seric g_opt: 162064133Seric if (isascii(*val) && isdigit(*val)) 162164133Seric DefGid = atoi(val); 162264133Seric else 162364133Seric { 162464133Seric register struct group *gr; 162564133Seric 162664133Seric DefGid = -1; 162764133Seric gr = getgrnam(val); 162864133Seric if (gr == NULL) 162968481Seric syserr("readcf: option %c: unknown group %s", 163068481Seric opt, val); 163164133Seric else 163264133Seric DefGid = gr->gr_gid; 163364133Seric } 16348256Seric break; 16358256Seric 16368256Seric case 'H': /* help file */ 16379381Seric if (val[0] == '\0') 16388269Seric HelpFile = "sendmail.hf"; 16399381Seric else 16409381Seric HelpFile = newstr(val); 16418256Seric break; 16428256Seric 164351305Seric case 'h': /* maximum hop count */ 164451305Seric MaxHopCount = atoi(val); 164551305Seric break; 164651305Seric 164735651Seric case 'I': /* use internet domain name server */ 164866334Seric #if NAMED_BIND 164957207Seric for (p = val; *p != 0; ) 165057207Seric { 165157207Seric bool clearmode; 165257207Seric char *q; 165357207Seric struct resolverflags *rfp; 165457207Seric 165557207Seric while (*p == ' ') 165657207Seric p++; 165757207Seric if (*p == '\0') 165857207Seric break; 165957207Seric clearmode = FALSE; 166057207Seric if (*p == '-') 166157207Seric clearmode = TRUE; 166257207Seric else if (*p != '+') 166357207Seric p--; 166457207Seric p++; 166557207Seric q = p; 166658050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 166757207Seric p++; 166857207Seric if (*p != '\0') 166957207Seric *p++ = '\0'; 167068759Seric if (strcasecmp(q, "HasWildcardMX") == 0) 167168759Seric { 167268759Seric NoMXforCanon = !clearmode; 167368759Seric continue; 167468759Seric } 167557207Seric for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 167657207Seric { 167757207Seric if (strcasecmp(q, rfp->rf_name) == 0) 167857207Seric break; 167957207Seric } 168064923Seric if (rfp->rf_name == NULL) 168164923Seric syserr("readcf: I option value %s unrecognized", q); 168264923Seric else if (clearmode) 168357207Seric _res.options &= ~rfp->rf_bits; 168457207Seric else 168557207Seric _res.options |= rfp->rf_bits; 168657207Seric } 168757207Seric if (tTd(8, 2)) 168868759Seric printf("_res.options = %x, HasWildcardMX = %d\n", 168968759Seric _res.options, !NoMXforCanon); 169057207Seric #else 169157207Seric usrerr("name server (I option) specified but BIND not compiled in"); 169257207Seric #endif 169335651Seric break; 169435651Seric 16958269Seric case 'i': /* ignore dot lines in message */ 16969381Seric IgnrDot = atobool(val); 16978269Seric break; 16988269Seric 169959730Seric case 'j': /* send errors in MIME (RFC 1341) format */ 170059730Seric SendMIMEErrors = atobool(val); 170159730Seric break; 170259730Seric 170357136Seric case 'J': /* .forward search path */ 170457136Seric ForwardPath = newstr(val); 170557136Seric break; 170657136Seric 170754967Seric case 'k': /* connection cache size */ 170854967Seric MaxMciCache = atoi(val); 170956215Seric if (MaxMciCache < 0) 171056215Seric MaxMciCache = 0; 171154967Seric break; 171254967Seric 171354967Seric case 'K': /* connection cache timeout */ 171458796Seric MciCacheTimeout = convtime(val, 'm'); 171554967Seric break; 171654967Seric 171761104Seric case 'l': /* use Errors-To: header */ 171861104Seric UseErrorsTo = atobool(val); 171961104Seric break; 172061104Seric 17218256Seric case 'L': /* log level */ 172264140Seric if (safe || LogLevel < atoi(val)) 172364140Seric LogLevel = atoi(val); 17248256Seric break; 17258256Seric 17268269Seric case 'M': /* define macro */ 172768267Seric p = newstr(&val[1]); 172868267Seric if (!safe) 172968267Seric cleanstrcpy(p, p, MAXNAME); 173068267Seric define(val[0], p, CurEnv); 173116878Seric sticky = FALSE; 17328269Seric break; 17338269Seric 17348269Seric case 'm': /* send to me too */ 17359381Seric MeToo = atobool(val); 17368269Seric break; 17378269Seric 173825820Seric case 'n': /* validate RHS in newaliases */ 173925820Seric CheckAliases = atobool(val); 174025820Seric break; 174125820Seric 174261104Seric /* 'N' available -- was "net name" */ 174361104Seric 174458851Seric case 'O': /* daemon options */ 174558851Seric setdaemonoptions(val); 174658851Seric break; 174758851Seric 17488269Seric case 'o': /* assume old style headers */ 17499381Seric if (atobool(val)) 17509341Seric CurEnv->e_flags |= EF_OLDSTYLE; 17519341Seric else 17529341Seric CurEnv->e_flags &= ~EF_OLDSTYLE; 17538269Seric break; 17548269Seric 175558082Seric case 'p': /* select privacy level */ 175658082Seric p = val; 175758082Seric for (;;) 175858082Seric { 175958082Seric register struct prival *pv; 176058082Seric extern struct prival PrivacyValues[]; 176158082Seric 176258082Seric while (isascii(*p) && (isspace(*p) || ispunct(*p))) 176358082Seric p++; 176458082Seric if (*p == '\0') 176558082Seric break; 176658082Seric val = p; 176758082Seric while (isascii(*p) && isalnum(*p)) 176858082Seric p++; 176958082Seric if (*p != '\0') 177058082Seric *p++ = '\0'; 177158082Seric 177258082Seric for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 177358082Seric { 177458082Seric if (strcasecmp(val, pv->pv_name) == 0) 177558082Seric break; 177658082Seric } 177758886Seric if (pv->pv_name == NULL) 177858886Seric syserr("readcf: Op line: %s unrecognized", val); 177958082Seric PrivacyFlags |= pv->pv_flag; 178058082Seric } 178168479Seric sticky = FALSE; 178258082Seric break; 178358082Seric 178424944Seric case 'P': /* postmaster copy address for returned mail */ 178524944Seric PostMasterCopy = newstr(val); 178624944Seric break; 178724944Seric 178824944Seric case 'q': /* slope of queue only function */ 178924944Seric QueueFactor = atoi(val); 179024944Seric break; 179124944Seric 17928256Seric case 'Q': /* queue directory */ 17939381Seric if (val[0] == '\0') 17948269Seric QueueDir = "mqueue"; 17959381Seric else 17969381Seric QueueDir = newstr(val); 179758789Seric if (RealUid != 0 && !safe) 179864718Seric Warn_Q_option = TRUE; 17998256Seric break; 18008256Seric 180158148Seric case 'R': /* don't prune routes */ 180258148Seric DontPruneRoutes = atobool(val); 180358148Seric break; 180458148Seric 18058256Seric case 'r': /* read timeout */ 180668481Seric if (subopt == NULL) 180768481Seric inittimeouts(val); 180868481Seric else 180968481Seric settimeout(subopt, val); 18108256Seric break; 18118256Seric 18128256Seric case 'S': /* status file */ 18139381Seric if (val[0] == '\0') 18148269Seric StatFile = "sendmail.st"; 18159381Seric else 18169381Seric StatFile = newstr(val); 18178256Seric break; 18188256Seric 18198265Seric case 's': /* be super safe, even if expensive */ 18209381Seric SuperSafe = atobool(val); 18218256Seric break; 18228256Seric 18238256Seric case 'T': /* queue timeout */ 182458737Seric p = strchr(val, '/'); 182558737Seric if (p != NULL) 182658737Seric { 182758737Seric *p++ = '\0'; 182868481Seric settimeout("queuewarn", p); 182958737Seric } 183068481Seric settimeout("queuereturn", val); 183154967Seric break; 18328256Seric 18338265Seric case 't': /* time zone name */ 183452106Seric TimeZoneSpec = newstr(val); 18358265Seric break; 18368265Seric 183750556Seric case 'U': /* location of user database */ 183851360Seric UdbSpec = newstr(val); 183950556Seric break; 184050556Seric 18418256Seric case 'u': /* set default uid */ 184268481Seric for (p = val; *p != '\0'; p++) 184368481Seric { 184468481Seric if (*p == '.' || *p == '/' || *p == ':') 184568481Seric { 184668481Seric *p++ = '\0'; 184768481Seric break; 184868481Seric } 184968481Seric } 185064133Seric if (isascii(*val) && isdigit(*val)) 185164133Seric DefUid = atoi(val); 185264133Seric else 185364133Seric { 185464133Seric register struct passwd *pw; 185564133Seric 185664133Seric DefUid = -1; 185768693Seric pw = sm_getpwnam(val); 185864133Seric if (pw == NULL) 185964133Seric syserr("readcf: option u: unknown user %s", val); 186064133Seric else 186168481Seric { 186264133Seric DefUid = pw->pw_uid; 186368481Seric DefGid = pw->pw_gid; 186468481Seric } 186564133Seric } 186640973Sbostic setdefuser(); 18678256Seric 186868481Seric /* handle the group if it is there */ 186968481Seric if (*p == '\0') 187068481Seric break; 187168481Seric val = p; 187268481Seric goto g_opt; 187368481Seric 187458851Seric case 'V': /* fallback MX host */ 187558851Seric FallBackMX = newstr(val); 187658851Seric break; 187758851Seric 18788269Seric case 'v': /* run in verbose mode */ 18799381Seric Verbose = atobool(val); 18808256Seric break; 18818256Seric 188263837Seric case 'w': /* if we are best MX, try host directly */ 188363837Seric TryNullMXList = atobool(val); 188463837Seric break; 188561104Seric 188661104Seric /* 'W' available -- was wizard password */ 188761104Seric 188814879Seric case 'x': /* load avg at which to auto-queue msgs */ 188914879Seric QueueLA = atoi(val); 189014879Seric break; 189114879Seric 189214879Seric case 'X': /* load avg at which to auto-reject connections */ 189314879Seric RefuseLA = atoi(val); 189414879Seric break; 189514879Seric 189624981Seric case 'y': /* work recipient factor */ 189724981Seric WkRecipFact = atoi(val); 189824981Seric break; 189924981Seric 190024981Seric case 'Y': /* fork jobs during queue runs */ 190124952Seric ForkQueueRuns = atobool(val); 190224952Seric break; 190324952Seric 190424981Seric case 'z': /* work message class factor */ 190524981Seric WkClassFact = atoi(val); 190624981Seric break; 190724981Seric 190824981Seric case 'Z': /* work time factor */ 190924981Seric WkTimeFact = atoi(val); 191024981Seric break; 191124981Seric 191268481Seric case O_QUEUESORTORD: /* queue sorting order */ 191368481Seric switch (*val) 191468481Seric { 191568481Seric case 'h': /* Host first */ 191668481Seric case 'H': 191768481Seric QueueSortOrder = QS_BYHOST; 191868481Seric break; 191968481Seric 192068481Seric case 'p': /* Priority order */ 192168481Seric case 'P': 192268481Seric QueueSortOrder = QS_BYPRIORITY; 192368481Seric break; 192468481Seric 192568481Seric default: 192668481Seric syserr("Invalid queue sort order \"%s\"", val); 192768481Seric } 192868481Seric break; 192968481Seric 193068481Seric case O_MQA: /* minimum queue age between deliveries */ 193168481Seric MinQueueAge = convtime(val, 'm'); 193268481Seric break; 193368481Seric 193468481Seric case O_MHSA: /* maximum age of cached host status */ 193568481Seric MaxHostStatAge = convtime(val, 'm'); 193668481Seric break; 193768481Seric 193868481Seric case O_DEFCHARSET: /* default character set for mimefying */ 193968481Seric DefaultCharSet = newstr(denlstring(val, TRUE, TRUE)); 194068481Seric break; 194168481Seric 194268481Seric case O_SSFILE: /* service switch file */ 194368481Seric ServiceSwitchFile = newstr(val); 194468481Seric break; 194568481Seric 194668481Seric case O_DIALDELAY: /* delay for dial-on-demand operation */ 194768481Seric DialDelay = convtime(val, 's'); 194868481Seric break; 194968481Seric 195068481Seric case O_NORCPTACTION: /* what to do if no recipient */ 195168481Seric if (strcasecmp(val, "none") == 0) 195268481Seric NoRecipientAction = NRA_NO_ACTION; 195368481Seric else if (strcasecmp(val, "add-to") == 0) 195468481Seric NoRecipientAction = NRA_ADD_TO; 195568481Seric else if (strcasecmp(val, "add-apparently-to") == 0) 195668481Seric NoRecipientAction = NRA_ADD_APPARENTLY_TO; 195768481Seric else if (strcasecmp(val, "add-bcc") == 0) 195868481Seric NoRecipientAction = NRA_ADD_BCC; 195968481Seric else if (strcasecmp(val, "add-to-undisclosed") == 0) 196068481Seric NoRecipientAction = NRA_ADD_TO_UNDISCLOSED; 196168481Seric else 196268481Seric syserr("Invalid NoRecipientAction: %s", val); 196368481Seric 196468490Seric case O_SAFEFILEENV: /* chroot() environ for writing to files */ 196568490Seric SafeFileEnv = newstr(val); 196668490Seric break; 196768490Seric 196868569Seric case O_MAXMSGSIZE: /* maximum message size */ 196968569Seric MaxMessageSize = atol(p); 197068569Seric break; 197168569Seric 197268756Seric case O_COLONOKINADDR: /* old style handling of colon addresses */ 197368756Seric ColonOkInAddr = atobool(p); 197468756Seric break; 197568756Seric 19768256Seric default: 197768481Seric if (tTd(37, 1)) 197868481Seric { 197968481Seric if (isascii(opt) && isprint(opt)) 198068481Seric printf("Warning: option %c unknown\n", opt); 198168481Seric else 198268481Seric printf("Warning: option 0x%x unknown\n", opt); 198368481Seric } 19848256Seric break; 19858256Seric } 198616878Seric if (sticky) 198716878Seric setbitn(opt, StickyOpt); 19889188Seric return; 19898256Seric } 199010687Seric /* 199168481Seric ** SETCLASS -- set a string into a class 199210687Seric ** 199310687Seric ** Parameters: 199468481Seric ** class -- the class to put the string in. 199568481Seric ** str -- the string to enter 199610687Seric ** 199710687Seric ** Returns: 199810687Seric ** none. 199910687Seric ** 200010687Seric ** Side Effects: 200110687Seric ** puts the word into the symbol table. 200210687Seric */ 200310687Seric 200468481Seric setclass(class, str) 200510687Seric int class; 200668481Seric char *str; 200710687Seric { 200810687Seric register STAB *s; 200910687Seric 201057943Seric if (tTd(37, 8)) 201168481Seric printf("setclass(%c, %s)\n", class, str); 201268481Seric s = stab(str, ST_CLASS, ST_ENTER); 201310687Seric setbitn(class, s->s_class); 201410687Seric } 201553654Seric /* 201653654Seric ** MAKEMAPENTRY -- create a map entry 201753654Seric ** 201853654Seric ** Parameters: 201953654Seric ** line -- the config file line 202053654Seric ** 202153654Seric ** Returns: 202253654Seric ** TRUE if it successfully entered the map entry. 202353654Seric ** FALSE otherwise (usually syntax error). 202453654Seric ** 202553654Seric ** Side Effects: 202653654Seric ** Enters the map into the dictionary. 202753654Seric */ 202853654Seric 202953654Seric void 203053654Seric makemapentry(line) 203153654Seric char *line; 203253654Seric { 203353654Seric register char *p; 203453654Seric char *mapname; 203553654Seric char *classname; 203664078Seric register STAB *s; 203753654Seric STAB *class; 203853654Seric 203958050Seric for (p = line; isascii(*p) && isspace(*p); p++) 204053654Seric continue; 204158050Seric if (!(isascii(*p) && isalnum(*p))) 204253654Seric { 204353654Seric syserr("readcf: config K line: no map name"); 204453654Seric return; 204553654Seric } 204653654Seric 204753654Seric mapname = p; 204868481Seric while ((isascii(*++p) && isalnum(*p)) || *p == '.') 204953654Seric continue; 205053654Seric if (*p != '\0') 205153654Seric *p++ = '\0'; 205258050Seric while (isascii(*p) && isspace(*p)) 205353654Seric p++; 205458050Seric if (!(isascii(*p) && isalnum(*p))) 205553654Seric { 205653654Seric syserr("readcf: config K line, map %s: no map class", mapname); 205753654Seric return; 205853654Seric } 205953654Seric classname = p; 206058050Seric while (isascii(*++p) && isalnum(*p)) 206153654Seric continue; 206253654Seric if (*p != '\0') 206353654Seric *p++ = '\0'; 206458050Seric while (isascii(*p) && isspace(*p)) 206553654Seric p++; 206653654Seric 206753654Seric /* look up the class */ 206853654Seric class = stab(classname, ST_MAPCLASS, ST_FIND); 206953654Seric if (class == NULL) 207053654Seric { 207153654Seric syserr("readcf: map %s: class %s not available", mapname, classname); 207253654Seric return; 207353654Seric } 207453654Seric 207553654Seric /* enter the map */ 207664078Seric s = stab(mapname, ST_MAP, ST_ENTER); 207764078Seric s->s_map.map_class = &class->s_mapclass; 207864078Seric s->s_map.map_mname = newstr(mapname); 207953654Seric 208064078Seric if (class->s_mapclass.map_parse(&s->s_map, p)) 208164078Seric s->s_map.map_mflags |= MF_VALID; 208264078Seric 208364078Seric if (tTd(37, 5)) 208464078Seric { 208564078Seric printf("map %s, class %s, flags %x, file %s,\n", 208664078Seric s->s_map.map_mname, s->s_map.map_class->map_cname, 208764078Seric s->s_map.map_mflags, 208864078Seric s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 208964078Seric printf("\tapp %s, domain %s, rebuild %s\n", 209064078Seric s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 209164078Seric s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 209264078Seric s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 209364078Seric } 209453654Seric } 209558112Seric /* 209668481Seric ** INITTIMEOUTS -- parse and set timeout values 209758112Seric ** 209858112Seric ** Parameters: 209958112Seric ** val -- a pointer to the values. If NULL, do initial 210058112Seric ** settings. 210158112Seric ** 210258112Seric ** Returns: 210358112Seric ** none. 210458112Seric ** 210558112Seric ** Side Effects: 210658112Seric ** Initializes the TimeOuts structure 210758112Seric */ 210858112Seric 210964255Seric #define SECONDS 211058112Seric #define MINUTES * 60 211158112Seric #define HOUR * 3600 211258112Seric 211368481Seric inittimeouts(val) 211458112Seric register char *val; 211558112Seric { 211658112Seric register char *p; 211758671Seric extern time_t convtime(); 211858112Seric 211958112Seric if (val == NULL) 212058112Seric { 212158112Seric TimeOuts.to_initial = (time_t) 5 MINUTES; 212258112Seric TimeOuts.to_helo = (time_t) 5 MINUTES; 212358112Seric TimeOuts.to_mail = (time_t) 10 MINUTES; 212458112Seric TimeOuts.to_rcpt = (time_t) 1 HOUR; 212558112Seric TimeOuts.to_datainit = (time_t) 5 MINUTES; 212658112Seric TimeOuts.to_datablock = (time_t) 1 HOUR; 212758112Seric TimeOuts.to_datafinal = (time_t) 1 HOUR; 212858112Seric TimeOuts.to_rset = (time_t) 5 MINUTES; 212958112Seric TimeOuts.to_quit = (time_t) 2 MINUTES; 213058112Seric TimeOuts.to_nextcommand = (time_t) 1 HOUR; 213158112Seric TimeOuts.to_miscshort = (time_t) 2 MINUTES; 213268481Seric #if IDENTPROTO 213364255Seric TimeOuts.to_ident = (time_t) 30 SECONDS; 213468481Seric #else 213568481Seric TimeOuts.to_ident = (time_t) 0 SECONDS; 213668481Seric #endif 213768481Seric TimeOuts.to_fileopen = (time_t) 60 SECONDS; 213858112Seric return; 213958112Seric } 214058112Seric 214158112Seric for (;; val = p) 214258112Seric { 214358112Seric while (isascii(*val) && isspace(*val)) 214458112Seric val++; 214558112Seric if (*val == '\0') 214658112Seric break; 214758112Seric for (p = val; *p != '\0' && *p != ','; p++) 214858112Seric continue; 214958112Seric if (*p != '\0') 215058112Seric *p++ = '\0'; 215158112Seric 215258112Seric if (isascii(*val) && isdigit(*val)) 215358112Seric { 215458112Seric /* old syntax -- set everything */ 215558796Seric TimeOuts.to_mail = convtime(val, 'm'); 215658112Seric TimeOuts.to_rcpt = TimeOuts.to_mail; 215758112Seric TimeOuts.to_datainit = TimeOuts.to_mail; 215858112Seric TimeOuts.to_datablock = TimeOuts.to_mail; 215958112Seric TimeOuts.to_datafinal = TimeOuts.to_mail; 216058112Seric TimeOuts.to_nextcommand = TimeOuts.to_mail; 216158112Seric continue; 216258112Seric } 216358112Seric else 216458112Seric { 216568481Seric register char *q = strchr(val, ':'); 216658112Seric 216768481Seric if (q == NULL && (q = strchr(val, '=')) == NULL) 216858112Seric { 216958112Seric /* syntax error */ 217058112Seric continue; 217158112Seric } 217258112Seric *q++ = '\0'; 217368481Seric settimeout(val, q); 217468481Seric } 217568481Seric } 217668481Seric } 217768481Seric /* 217868481Seric ** SETTIMEOUT -- set an individual timeout 217968481Seric ** 218068481Seric ** Parameters: 218168481Seric ** name -- the name of the timeout. 218268481Seric ** val -- the value of the timeout. 218368481Seric ** 218468481Seric ** Returns: 218568481Seric ** none. 218668481Seric */ 218758112Seric 218868481Seric settimeout(name, val) 218968481Seric char *name; 219068481Seric char *val; 219168481Seric { 219268481Seric register char *p; 219368481Seric time_t to; 219468481Seric extern time_t convtime(); 219568481Seric 219668481Seric to = convtime(val, 'm'); 219768481Seric p = strchr(name, '.'); 219868481Seric if (p != NULL) 219968481Seric *p++ = '\0'; 220068481Seric 220168481Seric if (strcasecmp(name, "initial") == 0) 220268481Seric TimeOuts.to_initial = to; 220368481Seric else if (strcasecmp(name, "mail") == 0) 220468481Seric TimeOuts.to_mail = to; 220568481Seric else if (strcasecmp(name, "rcpt") == 0) 220668481Seric TimeOuts.to_rcpt = to; 220768481Seric else if (strcasecmp(name, "datainit") == 0) 220868481Seric TimeOuts.to_datainit = to; 220968481Seric else if (strcasecmp(name, "datablock") == 0) 221068481Seric TimeOuts.to_datablock = to; 221168481Seric else if (strcasecmp(name, "datafinal") == 0) 221268481Seric TimeOuts.to_datafinal = to; 221368481Seric else if (strcasecmp(name, "command") == 0) 221468481Seric TimeOuts.to_nextcommand = to; 221568481Seric else if (strcasecmp(name, "rset") == 0) 221668481Seric TimeOuts.to_rset = to; 221768481Seric else if (strcasecmp(name, "helo") == 0) 221868481Seric TimeOuts.to_helo = to; 221968481Seric else if (strcasecmp(name, "quit") == 0) 222068481Seric TimeOuts.to_quit = to; 222168481Seric else if (strcasecmp(name, "misc") == 0) 222268481Seric TimeOuts.to_miscshort = to; 222368481Seric else if (strcasecmp(name, "ident") == 0) 222468481Seric TimeOuts.to_ident = to; 222568481Seric else if (strcasecmp(name, "fileopen") == 0) 222668481Seric TimeOuts.to_fileopen = to; 222768481Seric else if (strcasecmp(name, "queuewarn") == 0) 222868481Seric { 222968481Seric to = convtime(val, 'h'); 223068481Seric if (p == NULL || strcmp(p, "*") == 0) 223168481Seric { 223268481Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 223368481Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 223468481Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 223558112Seric } 223668481Seric else if (strcasecmp(p, "normal") == 0) 223768481Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 223868481Seric else if (strcasecmp(p, "urgent") == 0) 223968481Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 224068481Seric else if (strcasecmp(p, "non-urgent") == 0) 224168481Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 224268481Seric else 224368481Seric syserr("settimeout: invalid queuewarn subtimeout %s", p); 224458112Seric } 224568481Seric else if (strcasecmp(name, "queuereturn") == 0) 224668481Seric { 224768481Seric to = convtime(val, 'd'); 224868481Seric if (p == NULL || strcmp(p, "*") == 0) 224968481Seric { 225068481Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 225168481Seric TimeOuts.to_q_return[TOC_URGENT] = to; 225268481Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 225368481Seric } 225468481Seric else if (strcasecmp(p, "normal") == 0) 225568481Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 225668481Seric else if (strcasecmp(p, "urgent") == 0) 225768481Seric TimeOuts.to_q_return[TOC_URGENT] = to; 225868481Seric else if (strcasecmp(p, "non-urgent") == 0) 225968481Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 226068481Seric else 226168481Seric syserr("settimeout: invalid queuereturn subtimeout %s", p); 226268481Seric } 226368481Seric else 226468481Seric syserr("settimeout: invalid timeout %s", name); 226558112Seric } 2266