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*68759Seric static char sccsid[] = "@(#)readcf.c 8.81 (Berkeley) 04/09/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); 53564279Seric if (ConfigLevel >= 5) 53664279Seric { 53764279Seric /* level 5 configs have short name in $w */ 53864279Seric p = macvalue('w', e); 53964279Seric if (p != NULL && (p = strchr(p, '.')) != NULL) 54064279Seric *p = '\0'; 54164279Seric } 54264718Seric if (*ep++ == '/') 54364718Seric { 54464718Seric /* extract vendor code */ 54564718Seric for (p = ep; isascii(*p) && isalpha(*p); ) 54664718Seric p++; 54764718Seric *p = '\0'; 54864718Seric 54964718Seric if (!setvendor(ep)) 55064718Seric syserr("invalid V line vendor code: \"%s\"", 55164718Seric ep); 55264718Seric } 55352645Seric break; 55452645Seric 55553654Seric case 'K': 55657135Seric makemapentry(&bp[1]); 55753654Seric break; 55853654Seric 5593308Seric default: 5604061Seric badline: 56157135Seric syserr("unknown control line \"%s\"", bp); 5623308Seric } 56357135Seric if (bp != buf) 56457135Seric free(bp); 5653308Seric } 56652637Seric if (ferror(cf)) 56752637Seric { 56852647Seric syserr("I/O read error", cfname); 56952637Seric exit(EX_OSFILE); 57052637Seric } 57152637Seric fclose(cf); 5729381Seric FileName = NULL; 57356836Seric 57468481Seric /* initialize host maps from local service tables */ 57568481Seric inithostmaps(); 57668481Seric 57768481Seric /* determine if we need to do special name-server frotz */ 57867905Seric { 57968481Seric int nmaps; 58068481Seric char *maptype[MAXMAPSTACK]; 58168481Seric short mapreturn[MAXMAPACTIONS]; 58268481Seric 58368481Seric nmaps = switch_map_find("hosts", maptype, mapreturn); 58468481Seric UseNameServer = FALSE; 58568481Seric if (nmaps > 0 && nmaps <= MAXMAPSTACK) 58668481Seric { 58768481Seric register int mapno; 58868481Seric 58968481Seric for (mapno = 0; mapno < nmaps && !UseNameServer; mapno++) 59068481Seric { 59168481Seric if (strcmp(maptype[mapno], "dns") == 0) 59268481Seric UseNameServer = TRUE; 59368481Seric } 59468481Seric } 59568481Seric 59668481Seric #ifdef HESIOD 59768481Seric nmaps = switch_map_find("passwd", maptype, mapreturn); 59868481Seric UseHesiod = FALSE; 59968481Seric if (nmaps > 0 && nmaps <= MAXMAPSTACK) 60068481Seric { 60168481Seric register int mapno; 60268481Seric 60368481Seric for (mapno = 0; mapno < nmaps && !UseHesiod; mapno++) 60468481Seric { 60568481Seric if (strcmp(maptype[mapno], "hesiod") == 0) 60668481Seric UseHesiod = TRUE; 60768481Seric } 60868481Seric } 60968204Seric #endif 61067905Seric } 6114096Seric } 6124096Seric /* 6138547Seric ** TOOMANY -- signal too many of some option 6148547Seric ** 6158547Seric ** Parameters: 6168547Seric ** id -- the id of the error line 6178547Seric ** maxcnt -- the maximum possible values 6188547Seric ** 6198547Seric ** Returns: 6208547Seric ** none. 6218547Seric ** 6228547Seric ** Side Effects: 6238547Seric ** gives a syserr. 6248547Seric */ 6258547Seric 6268547Seric toomany(id, maxcnt) 6278547Seric char id; 6288547Seric int maxcnt; 6298547Seric { 6309381Seric syserr("too many %c lines, %d max", id, maxcnt); 6318547Seric } 6328547Seric /* 6334432Seric ** FILECLASS -- read members of a class from a file 6344432Seric ** 6354432Seric ** Parameters: 6364432Seric ** class -- class to define. 6374432Seric ** filename -- name of file to read. 6384432Seric ** fmt -- scanf string to use for match. 63964133Seric ** safe -- if set, this is a safe read. 64064133Seric ** optional -- if set, it is not an error for the file to 64164133Seric ** not exist. 6424432Seric ** 6434432Seric ** Returns: 6444432Seric ** none 6454432Seric ** 6464432Seric ** Side Effects: 6474432Seric ** 6484432Seric ** puts all lines in filename that match a scanf into 6494432Seric ** the named class. 6504432Seric */ 6514432Seric 65264133Seric fileclass(class, filename, fmt, safe, optional) 6534432Seric int class; 6544432Seric char *filename; 6554432Seric char *fmt; 65654973Seric bool safe; 65764133Seric bool optional; 6584432Seric { 65925808Seric FILE *f; 66068513Seric int sff; 6614432Seric char buf[MAXLINE]; 6624432Seric 66366101Seric if (tTd(37, 2)) 66466101Seric printf("fileclass(%s, fmt=%s)\n", filename, fmt); 66566101Seric 66666031Seric if (filename[0] == '|') 66766031Seric { 66866031Seric syserr("fileclass: pipes (F%c%s) not supported due to security problems", 66966031Seric class, filename); 67066031Seric return; 67166031Seric } 67268513Seric sff = SFF_REGONLY; 67368513Seric if (safe) 67468513Seric sff |= SFF_OPENASROOT; 67568513Seric f = safefopen(filename, O_RDONLY, 0, sff); 67668602Seric if (f == NULL) 67754973Seric { 67868602Seric if (!optional) 67968602Seric syserr("fileclass: cannot open %s", filename); 6804432Seric return; 6814432Seric } 6824432Seric 6834432Seric while (fgets(buf, sizeof buf, f) != NULL) 6844432Seric { 6854432Seric register STAB *s; 68625808Seric register char *p; 68725808Seric # ifdef SCANF 6884432Seric char wordbuf[MAXNAME+1]; 6894432Seric 6904432Seric if (sscanf(buf, fmt, wordbuf) != 1) 6914432Seric continue; 69225808Seric p = wordbuf; 69356795Seric # else /* SCANF */ 69425808Seric p = buf; 69556795Seric # endif /* SCANF */ 69625808Seric 69725808Seric /* 69825808Seric ** Break up the match into words. 69925808Seric */ 70025808Seric 70125808Seric while (*p != '\0') 70225808Seric { 70325808Seric register char *q; 70425808Seric 70525808Seric /* strip leading spaces */ 70658050Seric while (isascii(*p) && isspace(*p)) 70725808Seric p++; 70825808Seric if (*p == '\0') 70925808Seric break; 71025808Seric 71125808Seric /* find the end of the word */ 71225808Seric q = p; 71358050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 71425808Seric p++; 71525808Seric if (*p != '\0') 71625808Seric *p++ = '\0'; 71725808Seric 71825808Seric /* enter the word in the symbol table */ 71966101Seric setclass(class, q); 72025808Seric } 7214432Seric } 7224432Seric 72354973Seric (void) fclose(f); 7244432Seric } 7254432Seric /* 7264096Seric ** MAKEMAILER -- define a new mailer. 7274096Seric ** 7284096Seric ** Parameters: 72910327Seric ** line -- description of mailer. This is in labeled 73010327Seric ** fields. The fields are: 73168481Seric ** A -- the argv for this mailer 73268481Seric ** C -- the character set for MIME conversions 73368481Seric ** D -- the directory to run in 73468481Seric ** E -- the eol string 73568481Seric ** F -- the flags associated with the mailer 73668481Seric ** L -- the maximum line length 73768481Seric ** M -- the maximum message size 73868479Seric ** P -- the path to the mailer 73968481Seric ** R -- the recipient rewriting set 74068479Seric ** S -- the sender rewriting set 74168481Seric ** T -- the mailer type (for DSNs) 74268481Seric ** U -- the uid to run as 74310327Seric ** The first word is the canonical name of the mailer. 7444096Seric ** 7454096Seric ** Returns: 7464096Seric ** none. 7474096Seric ** 7484096Seric ** Side Effects: 7494096Seric ** enters the mailer into the mailer table. 7504096Seric */ 7513308Seric 75221066Seric makemailer(line) 7534096Seric char *line; 7544096Seric { 7554096Seric register char *p; 7568067Seric register struct mailer *m; 7578067Seric register STAB *s; 7588067Seric int i; 75910327Seric char fcode; 76058020Seric auto char *endp; 7614096Seric extern int NextMailer; 76210327Seric extern char **makeargv(); 76310327Seric extern char *munchstring(); 76410701Seric extern long atol(); 7654096Seric 76610327Seric /* allocate a mailer and set up defaults */ 76710327Seric m = (struct mailer *) xalloc(sizeof *m); 76810327Seric bzero((char *) m, sizeof *m); 76910327Seric m->m_eol = "\n"; 77068481Seric m->m_uid = m->m_gid = 0; 77110327Seric 77210327Seric /* collect the mailer name */ 77358050Seric for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++) 77410327Seric continue; 77510327Seric if (*p != '\0') 77610327Seric *p++ = '\0'; 77710327Seric m->m_name = newstr(line); 77810327Seric 77910327Seric /* now scan through and assign info from the fields */ 78010327Seric while (*p != '\0') 78110327Seric { 78258333Seric auto char *delimptr; 78358333Seric 78458050Seric while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p)))) 78510327Seric p++; 78610327Seric 78710327Seric /* p now points to field code */ 78810327Seric fcode = *p; 78910327Seric while (*p != '\0' && *p != '=' && *p != ',') 79010327Seric p++; 79110327Seric if (*p++ != '=') 79210327Seric { 79352637Seric syserr("mailer %s: `=' expected", m->m_name); 79410327Seric return; 79510327Seric } 79658050Seric while (isascii(*p) && isspace(*p)) 79710327Seric p++; 79810327Seric 79910327Seric /* p now points to the field body */ 80058333Seric p = munchstring(p, &delimptr); 80110327Seric 80210327Seric /* install the field into the mailer struct */ 80310327Seric switch (fcode) 80410327Seric { 80510327Seric case 'P': /* pathname */ 80610327Seric m->m_mailer = newstr(p); 80710327Seric break; 80810327Seric 80910327Seric case 'F': /* flags */ 81010687Seric for (; *p != '\0'; p++) 81158050Seric if (!(isascii(*p) && isspace(*p))) 81252637Seric setbitn(*p, m->m_flags); 81310327Seric break; 81410327Seric 81510327Seric case 'S': /* sender rewriting ruleset */ 81610327Seric case 'R': /* recipient rewriting ruleset */ 81758020Seric i = strtol(p, &endp, 10); 81810327Seric if (i < 0 || i >= MAXRWSETS) 81910327Seric { 82010327Seric syserr("invalid rewrite set, %d max", MAXRWSETS); 82110327Seric return; 82210327Seric } 82310327Seric if (fcode == 'S') 82458020Seric m->m_sh_rwset = m->m_se_rwset = i; 82510327Seric else 82658020Seric m->m_rh_rwset = m->m_re_rwset = i; 82758020Seric 82858020Seric p = endp; 82959985Seric if (*p++ == '/') 83058020Seric { 83158020Seric i = strtol(p, NULL, 10); 83258020Seric if (i < 0 || i >= MAXRWSETS) 83358020Seric { 83458020Seric syserr("invalid rewrite set, %d max", 83558020Seric MAXRWSETS); 83658020Seric return; 83758020Seric } 83858020Seric if (fcode == 'S') 83958020Seric m->m_sh_rwset = i; 84058020Seric else 84158020Seric m->m_rh_rwset = i; 84258020Seric } 84310327Seric break; 84410327Seric 84510327Seric case 'E': /* end of line string */ 84610327Seric m->m_eol = newstr(p); 84710327Seric break; 84810327Seric 84910327Seric case 'A': /* argument vector */ 85010327Seric m->m_argv = makeargv(p); 85110327Seric break; 85210701Seric 85310701Seric case 'M': /* maximum message size */ 85410701Seric m->m_maxsize = atol(p); 85510701Seric break; 85652106Seric 85752106Seric case 'L': /* maximum line length */ 85852106Seric m->m_linelimit = atoi(p); 85952106Seric break; 86058935Seric 86158935Seric case 'D': /* working directory */ 86258935Seric m->m_execdir = newstr(p); 86358935Seric break; 86468481Seric 86568481Seric case 'C': /* default charset */ 86668481Seric m->m_defcharset = newstr(p); 86768481Seric break; 86868481Seric 86968481Seric case 'T': /* MTA Type */ 87068481Seric m->m_mtatype = newstr(p); 87168481Seric p = strchr(m->m_mtatype, '/'); 87268481Seric if (p != NULL) 87368481Seric { 87468481Seric *p++ = '\0'; 87568481Seric if (*p == '\0') 87668481Seric p = NULL; 87768481Seric } 87868481Seric if (p == NULL) 87968481Seric m->m_addrtype = m->m_mtatype; 88068481Seric else 88168481Seric { 88268481Seric m->m_addrtype = p; 88368481Seric p = strchr(p, '/'); 88468481Seric } 88568481Seric if (p != NULL) 88668481Seric { 88768481Seric *p++ = '\0'; 88868481Seric if (*p == '\0') 88968481Seric p = NULL; 89068481Seric } 89168481Seric if (p == NULL) 89268481Seric m->m_diagtype = m->m_mtatype; 89368481Seric else 89468481Seric m->m_diagtype = p; 89568481Seric break; 89668481Seric 89768481Seric case 'U': /* user id */ 89868481Seric if (isascii(*p) && !isdigit(*p)) 89968481Seric { 90068481Seric char *q = p; 90168481Seric struct passwd *pw; 90268481Seric 90368481Seric while (isascii(*p) && isalnum(*p)) 90468481Seric p++; 90568481Seric while (isascii(*p) && isspace(*p)) 90668481Seric *p++ = '\0'; 90768481Seric if (*p != '\0') 90868481Seric *p++ = '\0'; 90968693Seric pw = sm_getpwnam(q); 91068481Seric if (pw == NULL) 91168481Seric syserr("readcf: mailer U= flag: unknown user %s", q); 91268481Seric else 91368481Seric { 91468481Seric m->m_uid = pw->pw_uid; 91568481Seric m->m_gid = pw->pw_gid; 91668481Seric } 91768481Seric } 91868481Seric else 91968481Seric { 92068481Seric auto char *q; 92168481Seric 92268481Seric m->m_uid = strtol(p, &q, 0); 92368481Seric p = q; 92468481Seric } 92568481Seric while (isascii(*p) && isspace(*p)) 92668481Seric p++; 92768481Seric if (*p == '\0') 92868481Seric break; 92968481Seric if (isascii(*p) && !isdigit(*p)) 93068481Seric { 93168481Seric char *q = p; 93268481Seric struct group *gr; 93368481Seric 93468481Seric while (isascii(*p) && isalnum(*p)) 93568481Seric p++; 93668481Seric *p++ = '\0'; 93768481Seric gr = getgrnam(q); 93868481Seric if (gr == NULL) 93968481Seric syserr("readcf: mailer U= flag: unknown group %s", q); 94068481Seric else 94168481Seric m->m_gid = gr->gr_gid; 94268481Seric } 94368481Seric else 94468481Seric { 94568481Seric m->m_gid = strtol(p, NULL, 0); 94668481Seric } 94768481Seric break; 94810327Seric } 94910327Seric 95058333Seric p = delimptr; 95110327Seric } 95210327Seric 95358321Seric /* do some rationality checking */ 95458321Seric if (m->m_argv == NULL) 95558321Seric { 95658321Seric syserr("M%s: A= argument required", m->m_name); 95758321Seric return; 95858321Seric } 95958321Seric if (m->m_mailer == NULL) 96058321Seric { 96158321Seric syserr("M%s: P= argument required", m->m_name); 96258321Seric return; 96358321Seric } 96458321Seric 9654096Seric if (NextMailer >= MAXMAILERS) 9664096Seric { 9679381Seric syserr("too many mailers defined (%d max)", MAXMAILERS); 9684096Seric return; 9694096Seric } 97057402Seric 97168481Seric /* do some heuristic cleanup for back compatibility */ 97268481Seric if (bitnset(M_LIMITS, m->m_flags)) 97368481Seric { 97468481Seric if (m->m_linelimit == 0) 97568481Seric m->m_linelimit = SMTPLINELIM; 97668481Seric if (ConfigLevel < 2) 97768481Seric setbitn(M_7BITS, m->m_flags); 97868481Seric } 97968481Seric 98068481Seric if (ConfigLevel < 6 && 98168481Seric (strcmp(m->m_mailer, "[IPC]") == 0 || 98268481Seric strcmp(m->m_mailer, "[TCP]") == 0)) 98368481Seric { 98468481Seric if (m->m_mtatype == NULL) 98568481Seric m->m_mtatype = "dns"; 98668481Seric if (m->m_addrtype == NULL) 98768481Seric m->m_addrtype = "rfc822"; 98868481Seric if (m->m_diagtype == NULL) 98968481Seric m->m_diagtype = "smtp"; 99068481Seric } 99168481Seric 99268481Seric /* enter the mailer into the symbol table */ 99310327Seric s = stab(m->m_name, ST_MAILER, ST_ENTER); 99457402Seric if (s->s_mailer != NULL) 99557402Seric { 99657402Seric i = s->s_mailer->m_mno; 99757402Seric free(s->s_mailer); 99857402Seric } 99957402Seric else 100057402Seric { 100157402Seric i = NextMailer++; 100257402Seric } 100357402Seric Mailer[i] = s->s_mailer = m; 100457454Seric m->m_mno = i; 100510327Seric } 100610327Seric /* 100710327Seric ** MUNCHSTRING -- translate a string into internal form. 100810327Seric ** 100910327Seric ** Parameters: 101010327Seric ** p -- the string to munch. 101158333Seric ** delimptr -- if non-NULL, set to the pointer of the 101258333Seric ** field delimiter character. 101310327Seric ** 101410327Seric ** Returns: 101510327Seric ** the munched string. 101610327Seric */ 10174096Seric 101810327Seric char * 101958333Seric munchstring(p, delimptr) 102010327Seric register char *p; 102158333Seric char **delimptr; 102210327Seric { 102310327Seric register char *q; 102410327Seric bool backslash = FALSE; 102510327Seric bool quotemode = FALSE; 102610327Seric static char buf[MAXLINE]; 10274096Seric 102810327Seric for (q = buf; *p != '\0'; p++) 10294096Seric { 103010327Seric if (backslash) 103110327Seric { 103210327Seric /* everything is roughly literal */ 103310357Seric backslash = FALSE; 103410327Seric switch (*p) 103510327Seric { 103610327Seric case 'r': /* carriage return */ 103710327Seric *q++ = '\r'; 103810327Seric continue; 103910327Seric 104010327Seric case 'n': /* newline */ 104110327Seric *q++ = '\n'; 104210327Seric continue; 104310327Seric 104410327Seric case 'f': /* form feed */ 104510327Seric *q++ = '\f'; 104610327Seric continue; 104710327Seric 104810327Seric case 'b': /* backspace */ 104910327Seric *q++ = '\b'; 105010327Seric continue; 105110327Seric } 105210327Seric *q++ = *p; 105310327Seric } 105410327Seric else 105510327Seric { 105610327Seric if (*p == '\\') 105710327Seric backslash = TRUE; 105810327Seric else if (*p == '"') 105910327Seric quotemode = !quotemode; 106010327Seric else if (quotemode || *p != ',') 106110327Seric *q++ = *p; 106210327Seric else 106310327Seric break; 106410327Seric } 10654096Seric } 10664096Seric 106758333Seric if (delimptr != NULL) 106858333Seric *delimptr = p; 106910327Seric *q++ = '\0'; 107010327Seric return (buf); 107110327Seric } 107210327Seric /* 107310327Seric ** MAKEARGV -- break up a string into words 107410327Seric ** 107510327Seric ** Parameters: 107610327Seric ** p -- the string to break up. 107710327Seric ** 107810327Seric ** Returns: 107910327Seric ** a char **argv (dynamically allocated) 108010327Seric ** 108110327Seric ** Side Effects: 108210327Seric ** munges p. 108310327Seric */ 10844096Seric 108510327Seric char ** 108610327Seric makeargv(p) 108710327Seric register char *p; 108810327Seric { 108910327Seric char *q; 109010327Seric int i; 109110327Seric char **avp; 109210327Seric char *argv[MAXPV + 1]; 109310327Seric 109410327Seric /* take apart the words */ 109510327Seric i = 0; 109610327Seric while (*p != '\0' && i < MAXPV) 10974096Seric { 109810327Seric q = p; 109958050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 110010327Seric p++; 110158050Seric while (isascii(*p) && isspace(*p)) 110210327Seric *p++ = '\0'; 110310327Seric argv[i++] = newstr(q); 11044096Seric } 110510327Seric argv[i++] = NULL; 11064096Seric 110710327Seric /* now make a copy of the argv */ 110810327Seric avp = (char **) xalloc(sizeof *avp * i); 110916893Seric bcopy((char *) argv, (char *) avp, sizeof *avp * i); 111010327Seric 111110327Seric return (avp); 11123308Seric } 11133308Seric /* 11143308Seric ** PRINTRULES -- print rewrite rules (for debugging) 11153308Seric ** 11163308Seric ** Parameters: 11173308Seric ** none. 11183308Seric ** 11193308Seric ** Returns: 11203308Seric ** none. 11213308Seric ** 11223308Seric ** Side Effects: 11233308Seric ** prints rewrite rules. 11243308Seric */ 11253308Seric 11263308Seric printrules() 11273308Seric { 11283308Seric register struct rewrite *rwp; 11294072Seric register int ruleset; 11303308Seric 11314072Seric for (ruleset = 0; ruleset < 10; ruleset++) 11323308Seric { 11334072Seric if (RewriteRules[ruleset] == NULL) 11344072Seric continue; 11358067Seric printf("\n----Rule Set %d:", ruleset); 11363308Seric 11374072Seric for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 11383308Seric { 11398067Seric printf("\nLHS:"); 11408067Seric printav(rwp->r_lhs); 11418067Seric printf("RHS:"); 11428067Seric printav(rwp->r_rhs); 11433308Seric } 11443308Seric } 11453308Seric } 114668481Seric /* 114768481Seric ** PRINTMAILER -- print mailer structure (for debugging) 114868481Seric ** 114968481Seric ** Parameters: 115068481Seric ** m -- the mailer to print 115168481Seric ** 115268481Seric ** Returns: 115368481Seric ** none. 115468481Seric */ 11554319Seric 115668481Seric printmailer(m) 115768481Seric register MAILER *m; 115868481Seric { 115968481Seric int j; 116068481Seric 116168481Seric printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld U=%d:%d F=", 116268481Seric m->m_mno, m->m_name, 116368481Seric m->m_mailer, m->m_se_rwset, m->m_sh_rwset, 116468481Seric m->m_re_rwset, m->m_rh_rwset, m->m_maxsize, 116568481Seric m->m_uid, m->m_gid); 116668481Seric for (j = '\0'; j <= '\177'; j++) 116768481Seric if (bitnset(j, m->m_flags)) 116868481Seric (void) putchar(j); 116968481Seric printf(" L=%d E=", m->m_linelimit); 117068481Seric xputs(m->m_eol); 117168481Seric if (m->m_defcharset != NULL) 117268481Seric printf(" C=%s", m->m_defcharset); 117368481Seric printf(" T=%s/%s/%s", 117468481Seric m->m_mtatype == NULL ? "<undefined>" : m->m_mtatype, 117568481Seric m->m_addrtype == NULL ? "<undefined>" : m->m_addrtype, 117668481Seric m->m_diagtype == NULL ? "<undefined>" : m->m_diagtype); 117768481Seric if (m->m_argv != NULL) 117868481Seric { 117968481Seric char **a = m->m_argv; 118068481Seric 118168481Seric printf(" A="); 118268481Seric while (*a != NULL) 118368481Seric { 118468481Seric if (a != m->m_argv) 118568481Seric printf(" "); 118668481Seric xputs(*a++); 118768481Seric } 118868481Seric } 118968481Seric printf("\n"); 119068481Seric } 11914096Seric /* 11928256Seric ** SETOPTION -- set global processing option 11938256Seric ** 11948256Seric ** Parameters: 11958256Seric ** opt -- option name. 11968256Seric ** val -- option value (as a text string). 119721755Seric ** safe -- set if this came from a configuration file. 119821755Seric ** Some options (if set from the command line) will 119921755Seric ** reset the user id to avoid security problems. 12008269Seric ** sticky -- if set, don't let other setoptions override 12018269Seric ** this value. 120258734Seric ** e -- the main envelope. 12038256Seric ** 12048256Seric ** Returns: 12058256Seric ** none. 12068256Seric ** 12078256Seric ** Side Effects: 12088256Seric ** Sets options as implied by the arguments. 12098256Seric */ 12108256Seric 121110687Seric static BITMAP StickyOpt; /* set if option is stuck */ 12128269Seric 121357207Seric 121466334Seric #if NAMED_BIND 121557207Seric 121657207Seric struct resolverflags 121757207Seric { 121857207Seric char *rf_name; /* name of the flag */ 121957207Seric long rf_bits; /* bits to set/clear */ 122057207Seric } ResolverFlags[] = 122157207Seric { 122257207Seric "debug", RES_DEBUG, 122357207Seric "aaonly", RES_AAONLY, 122457207Seric "usevc", RES_USEVC, 122557207Seric "primary", RES_PRIMARY, 122657207Seric "igntc", RES_IGNTC, 122757207Seric "recurse", RES_RECURSE, 122857207Seric "defnames", RES_DEFNAMES, 122957207Seric "stayopen", RES_STAYOPEN, 123057207Seric "dnsrch", RES_DNSRCH, 123165583Seric "true", 0, /* to avoid error on old syntax */ 123257207Seric NULL, 0 123357207Seric }; 123457207Seric 123557207Seric #endif 123657207Seric 123768481Seric struct optioninfo 123868481Seric { 123968481Seric char *o_name; /* long name of option */ 124068481Seric u_char o_code; /* short name of option */ 124168481Seric bool o_safe; /* safe for random people to use */ 124268481Seric } OptionTab[] = 124368481Seric { 124468481Seric "SevenBitInput", '7', TRUE, 124568481Seric "EightBitMode", '8', TRUE, 124668481Seric "AliasFile", 'A', FALSE, 124768481Seric "AliasWait", 'a', FALSE, 124868481Seric "BlankSub", 'B', FALSE, 124968481Seric "MinFreeBlocks", 'b', TRUE, 125068481Seric "CheckpointInterval", 'C', TRUE, 125168481Seric "HoldExpensive", 'c', FALSE, 125268481Seric "AutoRebuildAliases", 'D', FALSE, 125368481Seric "DeliveryMode", 'd', TRUE, 125468481Seric "ErrorHeader", 'E', FALSE, 125568481Seric "ErrorMode", 'e', TRUE, 125668481Seric "TempFileMode", 'F', FALSE, 125768481Seric "SaveFromLine", 'f', FALSE, 125868481Seric "MatchGECOS", 'G', FALSE, 125968481Seric "HelpFile", 'H', FALSE, 126068481Seric "MaxHopCount", 'h', FALSE, 126168569Seric "ResolverOptions", 'I', FALSE, 126268481Seric "IgnoreDots", 'i', TRUE, 126368481Seric "ForwardPath", 'J', FALSE, 126468481Seric "SendMimeErrors", 'j', TRUE, 126568481Seric "ConnectionCacheSize", 'k', FALSE, 126668481Seric "ConnectionCacheTimeout", 'K', FALSE, 126768481Seric "UseErrorsTo", 'l', FALSE, 126868481Seric "LogLevel", 'L', FALSE, 126968481Seric "MeToo", 'm', TRUE, 127068481Seric "CheckAliases", 'n', FALSE, 127168481Seric "OldStyleHeaders", 'o', TRUE, 127268481Seric "DaemonPortOptions", 'O', FALSE, 127368481Seric "PrivacyOptions", 'p', TRUE, 127468481Seric "PostmasterCopy", 'P', FALSE, 127568481Seric "QueueFactor", 'q', FALSE, 127668481Seric "QueueDirectory", 'Q', FALSE, 127768481Seric "DontPruneRoutes", 'R', FALSE, 127868481Seric "Timeout", 'r', TRUE, 127968481Seric "StatusFile", 'S', FALSE, 128068481Seric "SuperSafe", 's', TRUE, 128168481Seric "QueueTimeout", 'T', FALSE, 128268481Seric "TimeZoneSpec", 't', FALSE, 128368481Seric "UserDatabaseSpec", 'U', FALSE, 128468481Seric "DefaultUser", 'u', FALSE, 128568481Seric "FallbackMXhost", 'V', FALSE, 128668481Seric "Verbose", 'v', TRUE, 128768481Seric "TryNullMXList", 'w', TRUE, 128868481Seric "QueueLA", 'x', FALSE, 128968481Seric "RefuseLA", 'X', FALSE, 129068481Seric "RecipientFactor", 'y', FALSE, 129168569Seric "ForkEachJob", 'Y', FALSE, 129268481Seric "ClassFactor", 'z', FALSE, 129368569Seric "RetryFactor", 'Z', FALSE, 129468481Seric #define O_BSP 0x80 129568481Seric "BrokenSmtpPeers", O_BSP, TRUE, 129668481Seric #define O_QUEUESORTORD 0x81 129768481Seric "QueueSortOrder", O_QUEUESORTORD, TRUE, 129868481Seric #define O_MQA 0x83 129968481Seric "MinQueueAge", O_MQA, TRUE, 130068481Seric #define O_MHSA 0x84 130168481Seric /* 130268481Seric "MaxHostStatAge", O_MHSA, TRUE, 130368481Seric */ 130468481Seric #define O_DEFCHARSET 0x85 130568481Seric "DefaultCharSet", O_DEFCHARSET, TRUE, 130668481Seric #define O_SSFILE 0x86 130768481Seric "ServiceSwitchFile", O_SSFILE, FALSE, 130868481Seric #define O_DIALDELAY 0x87 130968481Seric "DialDelay", O_DIALDELAY, TRUE, 131068481Seric #define O_NORCPTACTION 0x88 131168481Seric "NoRecipientAction", O_NORCPTACTION, TRUE, 131268490Seric #define O_SAFEFILEENV 0x89 131368490Seric "SafeFileEnvironment", O_SAFEFILEENV, FALSE, 131468569Seric #define O_MAXMSGSIZE 0x8a 131568569Seric "MaxMessageSize", O_MAXMSGSIZE, FALSE, 131668756Seric #define O_COLONOKINADDR 0x8b 131768756Seric "ColonOkInAddr", O_COLONOKINADDR, TRUE, 131868481Seric 131968481Seric NULL, '\0', FALSE, 132068481Seric }; 132168481Seric 132268481Seric 132368481Seric 132458734Seric setoption(opt, val, safe, sticky, e) 132568481Seric u_char opt; 13268256Seric char *val; 132721755Seric bool safe; 13288269Seric bool sticky; 132958734Seric register ENVELOPE *e; 13308256Seric { 133157207Seric register char *p; 133268481Seric register struct optioninfo *o; 133368481Seric char *subopt; 13348265Seric extern bool atobool(); 133512633Seric extern time_t convtime(); 133614879Seric extern int QueueLA; 133714879Seric extern int RefuseLA; 133864718Seric extern bool Warn_Q_option; 13398256Seric 134068481Seric errno = 0; 134168481Seric if (opt == ' ') 134268481Seric { 134368481Seric /* full word options */ 134468481Seric struct optioninfo *sel; 134568481Seric 134668481Seric p = strchr(val, '='); 134768481Seric if (p == NULL) 134868481Seric p = &val[strlen(val)]; 134968481Seric while (*--p == ' ') 135068481Seric continue; 135168481Seric while (*++p == ' ') 135268481Seric *p = '\0'; 135368481Seric if (p == val) 135468481Seric { 135568481Seric syserr("readcf: null option name"); 135668481Seric return; 135768481Seric } 135868481Seric if (*p == '=') 135968481Seric *p++ = '\0'; 136068481Seric while (*p == ' ') 136168481Seric p++; 136268481Seric subopt = strchr(val, '.'); 136368481Seric if (subopt != NULL) 136468481Seric *subopt++ = '\0'; 136568481Seric sel = NULL; 136668481Seric for (o = OptionTab; o->o_name != NULL; o++) 136768481Seric { 136868481Seric if (strncasecmp(o->o_name, val, strlen(val)) != 0) 136968481Seric continue; 137068481Seric if (strlen(o->o_name) == strlen(val)) 137168481Seric { 137268481Seric /* completely specified -- this must be it */ 137368481Seric sel = NULL; 137468481Seric break; 137568481Seric } 137668481Seric if (sel != NULL) 137768481Seric break; 137868481Seric sel = o; 137968481Seric } 138068481Seric if (sel != NULL && o->o_name == NULL) 138168481Seric o = sel; 138268481Seric else if (o->o_name == NULL) 138368481Seric { 138468481Seric syserr("readcf: unknown option name %s", val); 138568481Seric return; 138668481Seric } 138768481Seric else if (sel != NULL) 138868481Seric { 138968481Seric syserr("readcf: ambiguous option name %s (matches %s and %s)", 139068481Seric val, sel->o_name, o->o_name); 139168481Seric return; 139268481Seric } 139368481Seric if (strlen(val) != strlen(o->o_name)) 139468481Seric { 139568481Seric bool oldVerbose = Verbose; 139668481Seric 139768481Seric Verbose = TRUE; 139868481Seric message("Option %s used as abbreviation for %s", 139968481Seric val, o->o_name); 140068481Seric Verbose = oldVerbose; 140168481Seric } 140268481Seric opt = o->o_code; 140368481Seric val = p; 140468481Seric } 140568481Seric else 140668481Seric { 140768481Seric for (o = OptionTab; o->o_name != NULL; o++) 140868481Seric { 140968481Seric if (o->o_code == opt) 141068481Seric break; 141168481Seric } 141268481Seric subopt = NULL; 141368481Seric } 141468481Seric 14158256Seric if (tTd(37, 1)) 141668481Seric { 141768481Seric printf(isascii(opt) && isprint(opt) ? 141868481Seric "setoption %s (%c).%s=%s" : 141968481Seric "setoption %s (0x%x).%s=%s", 142068481Seric o->o_name == NULL ? "<unknown>" : o->o_name, 142168481Seric opt, 142268481Seric subopt == NULL ? "" : subopt, 142368481Seric val); 142468481Seric } 14258256Seric 14268256Seric /* 14278269Seric ** See if this option is preset for us. 14288256Seric */ 14298256Seric 143059731Seric if (!sticky && bitnset(opt, StickyOpt)) 14318269Seric { 14329341Seric if (tTd(37, 1)) 14339341Seric printf(" (ignored)\n"); 14348269Seric return; 14358269Seric } 14368269Seric 143721755Seric /* 143821755Seric ** Check to see if this option can be specified by this user. 143921755Seric */ 144021755Seric 144163787Seric if (!safe && RealUid == 0) 144221755Seric safe = TRUE; 144368481Seric if (!safe && !o->o_safe) 144421755Seric { 144539111Srick if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 144621755Seric { 144736582Sbostic if (tTd(37, 1)) 144836582Sbostic printf(" (unsafe)"); 144963787Seric if (RealUid != geteuid()) 145036582Sbostic { 145151210Seric if (tTd(37, 1)) 145251210Seric printf("(Resetting uid)"); 145363787Seric (void) setgid(RealGid); 145463787Seric (void) setuid(RealUid); 145536582Sbostic } 145621755Seric } 145721755Seric } 145851210Seric if (tTd(37, 1)) 145917985Seric printf("\n"); 14608269Seric 146168481Seric switch (opt & 0xff) 14628256Seric { 146359709Seric case '7': /* force seven-bit input */ 146468481Seric SevenBitInput = atobool(val); 146552106Seric break; 146652106Seric 146768481Seric case '8': /* handling of 8-bit input */ 146868481Seric switch (*val) 146968481Seric { 147068481Seric case 'r': /* reject 8-bit, don't convert MIME */ 147168481Seric MimeMode = 0; 147268481Seric break; 147368481Seric 147468481Seric case 'm': /* convert 8-bit, convert MIME */ 147568481Seric MimeMode = MM_CVTMIME|MM_MIME8BIT; 147668481Seric break; 147768481Seric 147868481Seric case 'j': /* "just send 8" */ 147968481Seric MimeMode = MM_PASS8BIT; 148068481Seric break; 148168481Seric 148268481Seric case 'p': /* pass 8 bit, convert MIME */ 148368481Seric MimeMode = MM_PASS8BIT|MM_CVTMIME; 148468481Seric break; 148568481Seric 148668481Seric case 's': /* strict adherence */ 148768481Seric MimeMode = MM_CVTMIME; 148868481Seric break; 148968481Seric 149068481Seric case 'a': /* encode 8 bit if available */ 149168481Seric MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 149268481Seric break; 149368481Seric 149468481Seric case 'c': /* convert 8 bit to MIME, never 7 bit */ 149568481Seric MimeMode = MM_MIME8BIT; 149668481Seric break; 149768481Seric 149868481Seric default: 149968481Seric syserr("Unknown 8-bit mode %c", *val); 150068481Seric exit(EX_USAGE); 150168481Seric } 150268481Seric break; 150368481Seric 15048256Seric case 'A': /* set default alias file */ 15059381Seric if (val[0] == '\0') 150659672Seric setalias("aliases"); 15079381Seric else 150859672Seric setalias(val); 15098256Seric break; 15108256Seric 151117474Seric case 'a': /* look N minutes for "@:@" in alias file */ 151217474Seric if (val[0] == '\0') 151364796Seric SafeAlias = 5 * 60; /* five minutes */ 151417474Seric else 151564796Seric SafeAlias = convtime(val, 'm'); 151617474Seric break; 151717474Seric 151816843Seric case 'B': /* substitution for blank character */ 151916843Seric SpaceSub = val[0]; 152016843Seric if (SpaceSub == '\0') 152116843Seric SpaceSub = ' '; 152216843Seric break; 152316843Seric 152459283Seric case 'b': /* min blocks free on queue fs/max msg size */ 152559283Seric p = strchr(val, '/'); 152659283Seric if (p != NULL) 152759283Seric { 152859283Seric *p++ = '\0'; 152959283Seric MaxMessageSize = atol(p); 153059283Seric } 153158082Seric MinBlocksFree = atol(val); 153258082Seric break; 153358082Seric 15349284Seric case 'c': /* don't connect to "expensive" mailers */ 15359381Seric NoConnect = atobool(val); 15369284Seric break; 15379284Seric 153851305Seric case 'C': /* checkpoint every N addresses */ 153951305Seric CheckpointInterval = atoi(val); 154024944Seric break; 154124944Seric 15429284Seric case 'd': /* delivery mode */ 15439284Seric switch (*val) 15448269Seric { 15459284Seric case '\0': 154658734Seric e->e_sendmode = SM_DELIVER; 15478269Seric break; 15488269Seric 154910755Seric case SM_QUEUE: /* queue only */ 155010755Seric #ifndef QUEUE 155110755Seric syserr("need QUEUE to set -odqueue"); 155256795Seric #endif /* QUEUE */ 155310755Seric /* fall through..... */ 155410755Seric 15559284Seric case SM_DELIVER: /* do everything */ 15569284Seric case SM_FORK: /* fork after verification */ 155758734Seric e->e_sendmode = *val; 15588269Seric break; 15598269Seric 15608269Seric default: 15619284Seric syserr("Unknown delivery mode %c", *val); 15628269Seric exit(EX_USAGE); 15638269Seric } 15648269Seric break; 15658269Seric 15669146Seric case 'D': /* rebuild alias database as needed */ 15679381Seric AutoRebuild = atobool(val); 15689146Seric break; 15699146Seric 157055372Seric case 'E': /* error message header/header file */ 157155379Seric if (*val != '\0') 157255379Seric ErrMsgFile = newstr(val); 157355372Seric break; 157455372Seric 15758269Seric case 'e': /* set error processing mode */ 15768269Seric switch (*val) 15778269Seric { 15789381Seric case EM_QUIET: /* be silent about it */ 15799381Seric case EM_MAIL: /* mail back */ 15809381Seric case EM_BERKNET: /* do berknet error processing */ 15819381Seric case EM_WRITE: /* write back (or mail) */ 15829381Seric case EM_PRINT: /* print errors normally (default) */ 158358734Seric e->e_errormode = *val; 15848269Seric break; 15858269Seric } 15868269Seric break; 15878269Seric 15889049Seric case 'F': /* file mode */ 158917975Seric FileMode = atooct(val) & 0777; 15909049Seric break; 15919049Seric 15928269Seric case 'f': /* save Unix-style From lines on front */ 15939381Seric SaveFrom = atobool(val); 15948269Seric break; 15958269Seric 159653735Seric case 'G': /* match recipients against GECOS field */ 159753735Seric MatchGecos = atobool(val); 159853735Seric break; 159953735Seric 16008256Seric case 'g': /* default gid */ 160168481Seric g_opt: 160264133Seric if (isascii(*val) && isdigit(*val)) 160364133Seric DefGid = atoi(val); 160464133Seric else 160564133Seric { 160664133Seric register struct group *gr; 160764133Seric 160864133Seric DefGid = -1; 160964133Seric gr = getgrnam(val); 161064133Seric if (gr == NULL) 161168481Seric syserr("readcf: option %c: unknown group %s", 161268481Seric opt, val); 161364133Seric else 161464133Seric DefGid = gr->gr_gid; 161564133Seric } 16168256Seric break; 16178256Seric 16188256Seric case 'H': /* help file */ 16199381Seric if (val[0] == '\0') 16208269Seric HelpFile = "sendmail.hf"; 16219381Seric else 16229381Seric HelpFile = newstr(val); 16238256Seric break; 16248256Seric 162551305Seric case 'h': /* maximum hop count */ 162651305Seric MaxHopCount = atoi(val); 162751305Seric break; 162851305Seric 162935651Seric case 'I': /* use internet domain name server */ 163066334Seric #if NAMED_BIND 163157207Seric for (p = val; *p != 0; ) 163257207Seric { 163357207Seric bool clearmode; 163457207Seric char *q; 163557207Seric struct resolverflags *rfp; 163657207Seric 163757207Seric while (*p == ' ') 163857207Seric p++; 163957207Seric if (*p == '\0') 164057207Seric break; 164157207Seric clearmode = FALSE; 164257207Seric if (*p == '-') 164357207Seric clearmode = TRUE; 164457207Seric else if (*p != '+') 164557207Seric p--; 164657207Seric p++; 164757207Seric q = p; 164858050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 164957207Seric p++; 165057207Seric if (*p != '\0') 165157207Seric *p++ = '\0'; 1652*68759Seric if (strcasecmp(q, "HasWildcardMX") == 0) 1653*68759Seric { 1654*68759Seric NoMXforCanon = !clearmode; 1655*68759Seric continue; 1656*68759Seric } 165757207Seric for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 165857207Seric { 165957207Seric if (strcasecmp(q, rfp->rf_name) == 0) 166057207Seric break; 166157207Seric } 166264923Seric if (rfp->rf_name == NULL) 166364923Seric syserr("readcf: I option value %s unrecognized", q); 166464923Seric else if (clearmode) 166557207Seric _res.options &= ~rfp->rf_bits; 166657207Seric else 166757207Seric _res.options |= rfp->rf_bits; 166857207Seric } 166957207Seric if (tTd(8, 2)) 1670*68759Seric printf("_res.options = %x, HasWildcardMX = %d\n", 1671*68759Seric _res.options, !NoMXforCanon); 167257207Seric #else 167357207Seric usrerr("name server (I option) specified but BIND not compiled in"); 167457207Seric #endif 167535651Seric break; 167635651Seric 16778269Seric case 'i': /* ignore dot lines in message */ 16789381Seric IgnrDot = atobool(val); 16798269Seric break; 16808269Seric 168159730Seric case 'j': /* send errors in MIME (RFC 1341) format */ 168259730Seric SendMIMEErrors = atobool(val); 168359730Seric break; 168459730Seric 168557136Seric case 'J': /* .forward search path */ 168657136Seric ForwardPath = newstr(val); 168757136Seric break; 168857136Seric 168954967Seric case 'k': /* connection cache size */ 169054967Seric MaxMciCache = atoi(val); 169156215Seric if (MaxMciCache < 0) 169256215Seric MaxMciCache = 0; 169354967Seric break; 169454967Seric 169554967Seric case 'K': /* connection cache timeout */ 169658796Seric MciCacheTimeout = convtime(val, 'm'); 169754967Seric break; 169854967Seric 169961104Seric case 'l': /* use Errors-To: header */ 170061104Seric UseErrorsTo = atobool(val); 170161104Seric break; 170261104Seric 17038256Seric case 'L': /* log level */ 170464140Seric if (safe || LogLevel < atoi(val)) 170564140Seric LogLevel = atoi(val); 17068256Seric break; 17078256Seric 17088269Seric case 'M': /* define macro */ 170968267Seric p = newstr(&val[1]); 171068267Seric if (!safe) 171168267Seric cleanstrcpy(p, p, MAXNAME); 171268267Seric define(val[0], p, CurEnv); 171316878Seric sticky = FALSE; 17148269Seric break; 17158269Seric 17168269Seric case 'm': /* send to me too */ 17179381Seric MeToo = atobool(val); 17188269Seric break; 17198269Seric 172025820Seric case 'n': /* validate RHS in newaliases */ 172125820Seric CheckAliases = atobool(val); 172225820Seric break; 172325820Seric 172461104Seric /* 'N' available -- was "net name" */ 172561104Seric 172658851Seric case 'O': /* daemon options */ 172758851Seric setdaemonoptions(val); 172858851Seric break; 172958851Seric 17308269Seric case 'o': /* assume old style headers */ 17319381Seric if (atobool(val)) 17329341Seric CurEnv->e_flags |= EF_OLDSTYLE; 17339341Seric else 17349341Seric CurEnv->e_flags &= ~EF_OLDSTYLE; 17358269Seric break; 17368269Seric 173758082Seric case 'p': /* select privacy level */ 173858082Seric p = val; 173958082Seric for (;;) 174058082Seric { 174158082Seric register struct prival *pv; 174258082Seric extern struct prival PrivacyValues[]; 174358082Seric 174458082Seric while (isascii(*p) && (isspace(*p) || ispunct(*p))) 174558082Seric p++; 174658082Seric if (*p == '\0') 174758082Seric break; 174858082Seric val = p; 174958082Seric while (isascii(*p) && isalnum(*p)) 175058082Seric p++; 175158082Seric if (*p != '\0') 175258082Seric *p++ = '\0'; 175358082Seric 175458082Seric for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 175558082Seric { 175658082Seric if (strcasecmp(val, pv->pv_name) == 0) 175758082Seric break; 175858082Seric } 175958886Seric if (pv->pv_name == NULL) 176058886Seric syserr("readcf: Op line: %s unrecognized", val); 176158082Seric PrivacyFlags |= pv->pv_flag; 176258082Seric } 176368479Seric sticky = FALSE; 176458082Seric break; 176558082Seric 176624944Seric case 'P': /* postmaster copy address for returned mail */ 176724944Seric PostMasterCopy = newstr(val); 176824944Seric break; 176924944Seric 177024944Seric case 'q': /* slope of queue only function */ 177124944Seric QueueFactor = atoi(val); 177224944Seric break; 177324944Seric 17748256Seric case 'Q': /* queue directory */ 17759381Seric if (val[0] == '\0') 17768269Seric QueueDir = "mqueue"; 17779381Seric else 17789381Seric QueueDir = newstr(val); 177958789Seric if (RealUid != 0 && !safe) 178064718Seric Warn_Q_option = TRUE; 17818256Seric break; 17828256Seric 178358148Seric case 'R': /* don't prune routes */ 178458148Seric DontPruneRoutes = atobool(val); 178558148Seric break; 178658148Seric 17878256Seric case 'r': /* read timeout */ 178868481Seric if (subopt == NULL) 178968481Seric inittimeouts(val); 179068481Seric else 179168481Seric settimeout(subopt, val); 17928256Seric break; 17938256Seric 17948256Seric case 'S': /* status file */ 17959381Seric if (val[0] == '\0') 17968269Seric StatFile = "sendmail.st"; 17979381Seric else 17989381Seric StatFile = newstr(val); 17998256Seric break; 18008256Seric 18018265Seric case 's': /* be super safe, even if expensive */ 18029381Seric SuperSafe = atobool(val); 18038256Seric break; 18048256Seric 18058256Seric case 'T': /* queue timeout */ 180658737Seric p = strchr(val, '/'); 180758737Seric if (p != NULL) 180858737Seric { 180958737Seric *p++ = '\0'; 181068481Seric settimeout("queuewarn", p); 181158737Seric } 181268481Seric settimeout("queuereturn", val); 181354967Seric break; 18148256Seric 18158265Seric case 't': /* time zone name */ 181652106Seric TimeZoneSpec = newstr(val); 18178265Seric break; 18188265Seric 181950556Seric case 'U': /* location of user database */ 182051360Seric UdbSpec = newstr(val); 182150556Seric break; 182250556Seric 18238256Seric case 'u': /* set default uid */ 182468481Seric for (p = val; *p != '\0'; p++) 182568481Seric { 182668481Seric if (*p == '.' || *p == '/' || *p == ':') 182768481Seric { 182868481Seric *p++ = '\0'; 182968481Seric break; 183068481Seric } 183168481Seric } 183264133Seric if (isascii(*val) && isdigit(*val)) 183364133Seric DefUid = atoi(val); 183464133Seric else 183564133Seric { 183664133Seric register struct passwd *pw; 183764133Seric 183864133Seric DefUid = -1; 183968693Seric pw = sm_getpwnam(val); 184064133Seric if (pw == NULL) 184164133Seric syserr("readcf: option u: unknown user %s", val); 184264133Seric else 184368481Seric { 184464133Seric DefUid = pw->pw_uid; 184568481Seric DefGid = pw->pw_gid; 184668481Seric } 184764133Seric } 184840973Sbostic setdefuser(); 18498256Seric 185068481Seric /* handle the group if it is there */ 185168481Seric if (*p == '\0') 185268481Seric break; 185368481Seric val = p; 185468481Seric goto g_opt; 185568481Seric 185658851Seric case 'V': /* fallback MX host */ 185758851Seric FallBackMX = newstr(val); 185858851Seric break; 185958851Seric 18608269Seric case 'v': /* run in verbose mode */ 18619381Seric Verbose = atobool(val); 18628256Seric break; 18638256Seric 186463837Seric case 'w': /* if we are best MX, try host directly */ 186563837Seric TryNullMXList = atobool(val); 186663837Seric break; 186761104Seric 186861104Seric /* 'W' available -- was wizard password */ 186961104Seric 187014879Seric case 'x': /* load avg at which to auto-queue msgs */ 187114879Seric QueueLA = atoi(val); 187214879Seric break; 187314879Seric 187414879Seric case 'X': /* load avg at which to auto-reject connections */ 187514879Seric RefuseLA = atoi(val); 187614879Seric break; 187714879Seric 187824981Seric case 'y': /* work recipient factor */ 187924981Seric WkRecipFact = atoi(val); 188024981Seric break; 188124981Seric 188224981Seric case 'Y': /* fork jobs during queue runs */ 188324952Seric ForkQueueRuns = atobool(val); 188424952Seric break; 188524952Seric 188624981Seric case 'z': /* work message class factor */ 188724981Seric WkClassFact = atoi(val); 188824981Seric break; 188924981Seric 189024981Seric case 'Z': /* work time factor */ 189124981Seric WkTimeFact = atoi(val); 189224981Seric break; 189324981Seric 189468481Seric case O_BSP: /* SMTP Peers can't handle 2-line greeting */ 189568481Seric BrokenSmtpPeers = atobool(val); 189668481Seric break; 189768481Seric 189868481Seric case O_QUEUESORTORD: /* queue sorting order */ 189968481Seric switch (*val) 190068481Seric { 190168481Seric case 'h': /* Host first */ 190268481Seric case 'H': 190368481Seric QueueSortOrder = QS_BYHOST; 190468481Seric break; 190568481Seric 190668481Seric case 'p': /* Priority order */ 190768481Seric case 'P': 190868481Seric QueueSortOrder = QS_BYPRIORITY; 190968481Seric break; 191068481Seric 191168481Seric default: 191268481Seric syserr("Invalid queue sort order \"%s\"", val); 191368481Seric } 191468481Seric break; 191568481Seric 191668481Seric case O_MQA: /* minimum queue age between deliveries */ 191768481Seric MinQueueAge = convtime(val, 'm'); 191868481Seric break; 191968481Seric 192068481Seric case O_MHSA: /* maximum age of cached host status */ 192168481Seric MaxHostStatAge = convtime(val, 'm'); 192268481Seric break; 192368481Seric 192468481Seric case O_DEFCHARSET: /* default character set for mimefying */ 192568481Seric DefaultCharSet = newstr(denlstring(val, TRUE, TRUE)); 192668481Seric break; 192768481Seric 192868481Seric case O_SSFILE: /* service switch file */ 192968481Seric ServiceSwitchFile = newstr(val); 193068481Seric break; 193168481Seric 193268481Seric case O_DIALDELAY: /* delay for dial-on-demand operation */ 193368481Seric DialDelay = convtime(val, 's'); 193468481Seric break; 193568481Seric 193668481Seric case O_NORCPTACTION: /* what to do if no recipient */ 193768481Seric if (strcasecmp(val, "none") == 0) 193868481Seric NoRecipientAction = NRA_NO_ACTION; 193968481Seric else if (strcasecmp(val, "add-to") == 0) 194068481Seric NoRecipientAction = NRA_ADD_TO; 194168481Seric else if (strcasecmp(val, "add-apparently-to") == 0) 194268481Seric NoRecipientAction = NRA_ADD_APPARENTLY_TO; 194368481Seric else if (strcasecmp(val, "add-bcc") == 0) 194468481Seric NoRecipientAction = NRA_ADD_BCC; 194568481Seric else if (strcasecmp(val, "add-to-undisclosed") == 0) 194668481Seric NoRecipientAction = NRA_ADD_TO_UNDISCLOSED; 194768481Seric else 194868481Seric syserr("Invalid NoRecipientAction: %s", val); 194968481Seric 195068490Seric case O_SAFEFILEENV: /* chroot() environ for writing to files */ 195168490Seric SafeFileEnv = newstr(val); 195268490Seric break; 195368490Seric 195468569Seric case O_MAXMSGSIZE: /* maximum message size */ 195568569Seric MaxMessageSize = atol(p); 195668569Seric break; 195768569Seric 195868756Seric case O_COLONOKINADDR: /* old style handling of colon addresses */ 195968756Seric ColonOkInAddr = atobool(p); 196068756Seric break; 196168756Seric 19628256Seric default: 196368481Seric if (tTd(37, 1)) 196468481Seric { 196568481Seric if (isascii(opt) && isprint(opt)) 196668481Seric printf("Warning: option %c unknown\n", opt); 196768481Seric else 196868481Seric printf("Warning: option 0x%x unknown\n", opt); 196968481Seric } 19708256Seric break; 19718256Seric } 197216878Seric if (sticky) 197316878Seric setbitn(opt, StickyOpt); 19749188Seric return; 19758256Seric } 197610687Seric /* 197768481Seric ** SETCLASS -- set a string into a class 197810687Seric ** 197910687Seric ** Parameters: 198068481Seric ** class -- the class to put the string in. 198168481Seric ** str -- the string to enter 198210687Seric ** 198310687Seric ** Returns: 198410687Seric ** none. 198510687Seric ** 198610687Seric ** Side Effects: 198710687Seric ** puts the word into the symbol table. 198810687Seric */ 198910687Seric 199068481Seric setclass(class, str) 199110687Seric int class; 199268481Seric char *str; 199310687Seric { 199410687Seric register STAB *s; 199510687Seric 199657943Seric if (tTd(37, 8)) 199768481Seric printf("setclass(%c, %s)\n", class, str); 199868481Seric s = stab(str, ST_CLASS, ST_ENTER); 199910687Seric setbitn(class, s->s_class); 200010687Seric } 200153654Seric /* 200253654Seric ** MAKEMAPENTRY -- create a map entry 200353654Seric ** 200453654Seric ** Parameters: 200553654Seric ** line -- the config file line 200653654Seric ** 200753654Seric ** Returns: 200853654Seric ** TRUE if it successfully entered the map entry. 200953654Seric ** FALSE otherwise (usually syntax error). 201053654Seric ** 201153654Seric ** Side Effects: 201253654Seric ** Enters the map into the dictionary. 201353654Seric */ 201453654Seric 201553654Seric void 201653654Seric makemapentry(line) 201753654Seric char *line; 201853654Seric { 201953654Seric register char *p; 202053654Seric char *mapname; 202153654Seric char *classname; 202264078Seric register STAB *s; 202353654Seric STAB *class; 202453654Seric 202558050Seric for (p = line; isascii(*p) && isspace(*p); p++) 202653654Seric continue; 202758050Seric if (!(isascii(*p) && isalnum(*p))) 202853654Seric { 202953654Seric syserr("readcf: config K line: no map name"); 203053654Seric return; 203153654Seric } 203253654Seric 203353654Seric mapname = p; 203468481Seric while ((isascii(*++p) && isalnum(*p)) || *p == '.') 203553654Seric continue; 203653654Seric if (*p != '\0') 203753654Seric *p++ = '\0'; 203858050Seric while (isascii(*p) && isspace(*p)) 203953654Seric p++; 204058050Seric if (!(isascii(*p) && isalnum(*p))) 204153654Seric { 204253654Seric syserr("readcf: config K line, map %s: no map class", mapname); 204353654Seric return; 204453654Seric } 204553654Seric classname = p; 204658050Seric while (isascii(*++p) && isalnum(*p)) 204753654Seric continue; 204853654Seric if (*p != '\0') 204953654Seric *p++ = '\0'; 205058050Seric while (isascii(*p) && isspace(*p)) 205153654Seric p++; 205253654Seric 205353654Seric /* look up the class */ 205453654Seric class = stab(classname, ST_MAPCLASS, ST_FIND); 205553654Seric if (class == NULL) 205653654Seric { 205753654Seric syserr("readcf: map %s: class %s not available", mapname, classname); 205853654Seric return; 205953654Seric } 206053654Seric 206153654Seric /* enter the map */ 206264078Seric s = stab(mapname, ST_MAP, ST_ENTER); 206364078Seric s->s_map.map_class = &class->s_mapclass; 206464078Seric s->s_map.map_mname = newstr(mapname); 206553654Seric 206664078Seric if (class->s_mapclass.map_parse(&s->s_map, p)) 206764078Seric s->s_map.map_mflags |= MF_VALID; 206864078Seric 206964078Seric if (tTd(37, 5)) 207064078Seric { 207164078Seric printf("map %s, class %s, flags %x, file %s,\n", 207264078Seric s->s_map.map_mname, s->s_map.map_class->map_cname, 207364078Seric s->s_map.map_mflags, 207464078Seric s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 207564078Seric printf("\tapp %s, domain %s, rebuild %s\n", 207664078Seric s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 207764078Seric s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 207864078Seric s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 207964078Seric } 208053654Seric } 208158112Seric /* 208268481Seric ** INITTIMEOUTS -- parse and set timeout values 208358112Seric ** 208458112Seric ** Parameters: 208558112Seric ** val -- a pointer to the values. If NULL, do initial 208658112Seric ** settings. 208758112Seric ** 208858112Seric ** Returns: 208958112Seric ** none. 209058112Seric ** 209158112Seric ** Side Effects: 209258112Seric ** Initializes the TimeOuts structure 209358112Seric */ 209458112Seric 209564255Seric #define SECONDS 209658112Seric #define MINUTES * 60 209758112Seric #define HOUR * 3600 209858112Seric 209968481Seric inittimeouts(val) 210058112Seric register char *val; 210158112Seric { 210258112Seric register char *p; 210358671Seric extern time_t convtime(); 210458112Seric 210558112Seric if (val == NULL) 210658112Seric { 210758112Seric TimeOuts.to_initial = (time_t) 5 MINUTES; 210858112Seric TimeOuts.to_helo = (time_t) 5 MINUTES; 210958112Seric TimeOuts.to_mail = (time_t) 10 MINUTES; 211058112Seric TimeOuts.to_rcpt = (time_t) 1 HOUR; 211158112Seric TimeOuts.to_datainit = (time_t) 5 MINUTES; 211258112Seric TimeOuts.to_datablock = (time_t) 1 HOUR; 211358112Seric TimeOuts.to_datafinal = (time_t) 1 HOUR; 211458112Seric TimeOuts.to_rset = (time_t) 5 MINUTES; 211558112Seric TimeOuts.to_quit = (time_t) 2 MINUTES; 211658112Seric TimeOuts.to_nextcommand = (time_t) 1 HOUR; 211758112Seric TimeOuts.to_miscshort = (time_t) 2 MINUTES; 211868481Seric #if IDENTPROTO 211964255Seric TimeOuts.to_ident = (time_t) 30 SECONDS; 212068481Seric #else 212168481Seric TimeOuts.to_ident = (time_t) 0 SECONDS; 212268481Seric #endif 212368481Seric TimeOuts.to_fileopen = (time_t) 60 SECONDS; 212458112Seric return; 212558112Seric } 212658112Seric 212758112Seric for (;; val = p) 212858112Seric { 212958112Seric while (isascii(*val) && isspace(*val)) 213058112Seric val++; 213158112Seric if (*val == '\0') 213258112Seric break; 213358112Seric for (p = val; *p != '\0' && *p != ','; p++) 213458112Seric continue; 213558112Seric if (*p != '\0') 213658112Seric *p++ = '\0'; 213758112Seric 213858112Seric if (isascii(*val) && isdigit(*val)) 213958112Seric { 214058112Seric /* old syntax -- set everything */ 214158796Seric TimeOuts.to_mail = convtime(val, 'm'); 214258112Seric TimeOuts.to_rcpt = TimeOuts.to_mail; 214358112Seric TimeOuts.to_datainit = TimeOuts.to_mail; 214458112Seric TimeOuts.to_datablock = TimeOuts.to_mail; 214558112Seric TimeOuts.to_datafinal = TimeOuts.to_mail; 214658112Seric TimeOuts.to_nextcommand = TimeOuts.to_mail; 214758112Seric continue; 214858112Seric } 214958112Seric else 215058112Seric { 215168481Seric register char *q = strchr(val, ':'); 215258112Seric 215368481Seric if (q == NULL && (q = strchr(val, '=')) == NULL) 215458112Seric { 215558112Seric /* syntax error */ 215658112Seric continue; 215758112Seric } 215858112Seric *q++ = '\0'; 215968481Seric settimeout(val, q); 216068481Seric } 216168481Seric } 216268481Seric } 216368481Seric /* 216468481Seric ** SETTIMEOUT -- set an individual timeout 216568481Seric ** 216668481Seric ** Parameters: 216768481Seric ** name -- the name of the timeout. 216868481Seric ** val -- the value of the timeout. 216968481Seric ** 217068481Seric ** Returns: 217168481Seric ** none. 217268481Seric */ 217358112Seric 217468481Seric settimeout(name, val) 217568481Seric char *name; 217668481Seric char *val; 217768481Seric { 217868481Seric register char *p; 217968481Seric time_t to; 218068481Seric extern time_t convtime(); 218168481Seric 218268481Seric to = convtime(val, 'm'); 218368481Seric p = strchr(name, '.'); 218468481Seric if (p != NULL) 218568481Seric *p++ = '\0'; 218668481Seric 218768481Seric if (strcasecmp(name, "initial") == 0) 218868481Seric TimeOuts.to_initial = to; 218968481Seric else if (strcasecmp(name, "mail") == 0) 219068481Seric TimeOuts.to_mail = to; 219168481Seric else if (strcasecmp(name, "rcpt") == 0) 219268481Seric TimeOuts.to_rcpt = to; 219368481Seric else if (strcasecmp(name, "datainit") == 0) 219468481Seric TimeOuts.to_datainit = to; 219568481Seric else if (strcasecmp(name, "datablock") == 0) 219668481Seric TimeOuts.to_datablock = to; 219768481Seric else if (strcasecmp(name, "datafinal") == 0) 219868481Seric TimeOuts.to_datafinal = to; 219968481Seric else if (strcasecmp(name, "command") == 0) 220068481Seric TimeOuts.to_nextcommand = to; 220168481Seric else if (strcasecmp(name, "rset") == 0) 220268481Seric TimeOuts.to_rset = to; 220368481Seric else if (strcasecmp(name, "helo") == 0) 220468481Seric TimeOuts.to_helo = to; 220568481Seric else if (strcasecmp(name, "quit") == 0) 220668481Seric TimeOuts.to_quit = to; 220768481Seric else if (strcasecmp(name, "misc") == 0) 220868481Seric TimeOuts.to_miscshort = to; 220968481Seric else if (strcasecmp(name, "ident") == 0) 221068481Seric TimeOuts.to_ident = to; 221168481Seric else if (strcasecmp(name, "fileopen") == 0) 221268481Seric TimeOuts.to_fileopen = to; 221368481Seric else if (strcasecmp(name, "queuewarn") == 0) 221468481Seric { 221568481Seric to = convtime(val, 'h'); 221668481Seric if (p == NULL || strcmp(p, "*") == 0) 221768481Seric { 221868481Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 221968481Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 222068481Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 222158112Seric } 222268481Seric else if (strcasecmp(p, "normal") == 0) 222368481Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 222468481Seric else if (strcasecmp(p, "urgent") == 0) 222568481Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 222668481Seric else if (strcasecmp(p, "non-urgent") == 0) 222768481Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 222868481Seric else 222968481Seric syserr("settimeout: invalid queuewarn subtimeout %s", p); 223058112Seric } 223168481Seric else if (strcasecmp(name, "queuereturn") == 0) 223268481Seric { 223368481Seric to = convtime(val, 'd'); 223468481Seric if (p == NULL || strcmp(p, "*") == 0) 223568481Seric { 223668481Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 223768481Seric TimeOuts.to_q_return[TOC_URGENT] = to; 223868481Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 223968481Seric } 224068481Seric else if (strcasecmp(p, "normal") == 0) 224168481Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 224268481Seric else if (strcasecmp(p, "urgent") == 0) 224368481Seric TimeOuts.to_q_return[TOC_URGENT] = to; 224468481Seric else if (strcasecmp(p, "non-urgent") == 0) 224568481Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 224668481Seric else 224768481Seric syserr("settimeout: invalid queuereturn subtimeout %s", p); 224868481Seric } 224968481Seric else 225068481Seric syserr("settimeout: invalid timeout %s", name); 225158112Seric } 2252