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*69724Seric static char sccsid[] = "@(#)readcf.c 8.94 (Berkeley) 05/27/95"; 1133731Sbostic #endif /* not lint */ 1222709Sdist 133313Seric # include "sendmail.h" 1464133Seric # include <grp.h> 1566334Seric #if NAMED_BIND 1657207Seric # include <resolv.h> 1757207Seric #endif 183308Seric 193308Seric /* 203308Seric ** READCF -- read control file. 213308Seric ** 223308Seric ** This routine reads the control file and builds the internal 233308Seric ** form. 243308Seric ** 254432Seric ** The file is formatted as a sequence of lines, each taken 264432Seric ** atomically. The first character of each line describes how 274432Seric ** the line is to be interpreted. The lines are: 284432Seric ** Dxval Define macro x to have value val. 294432Seric ** Cxword Put word into class x. 304432Seric ** Fxfile [fmt] Read file for lines to put into 314432Seric ** class x. Use scanf string 'fmt' 324432Seric ** or "%s" if not present. Fmt should 334432Seric ** only produce one string-valued result. 344432Seric ** Hname: value Define header with field-name 'name' 354432Seric ** and value as specified; this will be 364432Seric ** macro expanded immediately before 374432Seric ** use. 384432Seric ** Sn Use rewriting set n. 394432Seric ** Rlhs rhs Rewrite addresses that match lhs to 404432Seric ** be rhs. 4124944Seric ** Mn arg=val... Define mailer. n is the internal name. 4224944Seric ** Args specify mailer parameters. 438252Seric ** Oxvalue Set option x to value. 448252Seric ** Pname=value Set precedence name to value. 4564718Seric ** Vversioncode[/vendorcode] 4664718Seric ** Version level/vendor name of 4764718Seric ** configuration syntax. 4853654Seric ** Kmapname mapclass arguments.... 4953654Seric ** Define keyed lookup of a given class. 5053654Seric ** Arguments are class dependent. 5169476Seric ** Eenvar=value Set the environment value to the given value. 524432Seric ** 533308Seric ** Parameters: 543308Seric ** cfname -- control file name. 5554973Seric ** safe -- TRUE if this is the system config file; 5654973Seric ** FALSE otherwise. 5755012Seric ** e -- the main envelope. 583308Seric ** 593308Seric ** Returns: 603308Seric ** none. 613308Seric ** 623308Seric ** Side Effects: 633308Seric ** Builds several internal tables. 643308Seric */ 653308Seric 6655012Seric readcf(cfname, safe, e) 673308Seric char *cfname; 6854973Seric bool safe; 6955012Seric register ENVELOPE *e; 703308Seric { 713308Seric FILE *cf; 728547Seric int ruleset = 0; 7368481Seric int nextruleset = MAXRWSETS; 748547Seric char *q; 759350Seric struct rewrite *rwp = NULL; 7657135Seric char *bp; 7764718Seric auto char *ep; 7857589Seric int nfuzzy; 7964133Seric char *file; 8064133Seric bool optional; 8168481Seric int mid; 823308Seric char buf[MAXLINE]; 833308Seric register char *p; 843308Seric extern char **copyplist(); 8552647Seric struct stat statb; 865909Seric char exbuf[MAXLINE]; 8765066Seric char pvpbuf[MAXLINE + MAXATOM]; 8868481Seric static char *null_list[1] = { NULL }; 8910709Seric extern char *munchstring(); 9053654Seric extern void makemapentry(); 913308Seric 9252647Seric FileName = cfname; 9352647Seric LineNumber = 0; 9452647Seric 953308Seric cf = fopen(cfname, "r"); 963308Seric if (cf == NULL) 973308Seric { 9852647Seric syserr("cannot open"); 993308Seric exit(EX_OSFILE); 1003308Seric } 1013308Seric 10252647Seric if (fstat(fileno(cf), &statb) < 0) 10352647Seric { 10452647Seric syserr("cannot fstat"); 10552647Seric exit(EX_OSFILE); 10652647Seric } 10752647Seric 10852647Seric if (!S_ISREG(statb.st_mode)) 10952647Seric { 11052647Seric syserr("not a plain file"); 11152647Seric exit(EX_OSFILE); 11252647Seric } 11352647Seric 11452647Seric if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode)) 11552647Seric { 11669686Seric if (OpMode == MD_DAEMON || OpMode == MD_INITALIAS) 11753037Seric fprintf(stderr, "%s: WARNING: dangerous write permissions\n", 11853037Seric FileName); 11953037Seric #ifdef LOG 12053037Seric if (LogLevel > 0) 12153037Seric syslog(LOG_CRIT, "%s: WARNING: dangerous write permissions", 12253037Seric FileName); 12353037Seric #endif 12452647Seric } 12552647Seric 12659254Seric #ifdef XLA 12759254Seric xla_zero(); 12859254Seric #endif 12959254Seric 13057135Seric while ((bp = fgetfolded(buf, sizeof buf, cf)) != NULL) 1313308Seric { 13257135Seric if (bp[0] == '#') 13357135Seric { 13457135Seric if (bp != buf) 13557135Seric free(bp); 13652637Seric continue; 13757135Seric } 13852637Seric 13968481Seric /* do macro expansion mappings */ 14057135Seric for (p = bp; *p != '\0'; p++) 14116157Seric { 14257135Seric if (*p == '#' && p > bp && ConfigLevel >= 3) 14352647Seric { 14452647Seric /* this is an on-line comment */ 14552647Seric register char *e; 14652647Seric 14758050Seric switch (*--p & 0377) 14852647Seric { 14958050Seric case MACROEXPAND: 15052647Seric /* it's from $# -- let it go through */ 15152647Seric p++; 15252647Seric break; 15352647Seric 15452647Seric case '\\': 15552647Seric /* it's backslash escaped */ 15652647Seric (void) strcpy(p, p + 1); 15752647Seric break; 15852647Seric 15952647Seric default: 16052647Seric /* delete preceeding white space */ 16158050Seric while (isascii(*p) && isspace(*p) && p > bp) 16252647Seric p--; 16356795Seric if ((e = strchr(++p, '\n')) != NULL) 16452647Seric (void) strcpy(p, e); 16552647Seric else 16652647Seric p[0] = p[1] = '\0'; 16752647Seric break; 16852647Seric } 16952647Seric continue; 17052647Seric } 17152647Seric 17268481Seric if (*p != '$' || p[1] == '\0') 17316157Seric continue; 17416157Seric 17516157Seric if (p[1] == '$') 17616157Seric { 17716157Seric /* actual dollar sign.... */ 17823111Seric (void) strcpy(p, p + 1); 17916157Seric continue; 18016157Seric } 18116157Seric 18216157Seric /* convert to macro expansion character */ 18368481Seric *p++ = MACROEXPAND; 18468481Seric 18568481Seric /* convert macro name to code */ 18668481Seric *p = macid(p, &ep); 18768481Seric if (ep != p) 18868481Seric strcpy(p + 1, ep); 18916157Seric } 19016157Seric 19116157Seric /* interpret this line */ 19264718Seric errno = 0; 19357135Seric switch (bp[0]) 1943308Seric { 1953308Seric case '\0': 1963308Seric case '#': /* comment */ 1973308Seric break; 1983308Seric 1993308Seric case 'R': /* rewriting rule */ 20057135Seric for (p = &bp[1]; *p != '\0' && *p != '\t'; p++) 2013308Seric continue; 2023308Seric 2033308Seric if (*p == '\0') 2045909Seric { 20565821Seric syserr("invalid rewrite line \"%s\" (tab expected)", bp); 2065909Seric break; 2075909Seric } 2085909Seric 2095909Seric /* allocate space for the rule header */ 2105909Seric if (rwp == NULL) 2115909Seric { 2125909Seric RewriteRules[ruleset] = rwp = 2135909Seric (struct rewrite *) xalloc(sizeof *rwp); 2145909Seric } 2153308Seric else 2163308Seric { 2175909Seric rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp); 2185909Seric rwp = rwp->r_next; 2195909Seric } 2205909Seric rwp->r_next = NULL; 2213308Seric 2225909Seric /* expand and save the LHS */ 2235909Seric *p = '\0'; 22468529Seric expand(&bp[1], exbuf, sizeof exbuf, e); 22565066Seric rwp->r_lhs = prescan(exbuf, '\t', pvpbuf, 22668711Seric sizeof pvpbuf, NULL, NULL); 22757589Seric nfuzzy = 0; 2285909Seric if (rwp->r_lhs != NULL) 22957589Seric { 23057589Seric register char **ap; 23157589Seric 2325909Seric rwp->r_lhs = copyplist(rwp->r_lhs, TRUE); 23357589Seric 23457589Seric /* count the number of fuzzy matches in LHS */ 23557589Seric for (ap = rwp->r_lhs; *ap != NULL; ap++) 23657589Seric { 23758148Seric char *botch; 23858148Seric 23958148Seric botch = NULL; 24058050Seric switch (**ap & 0377) 24157589Seric { 24257589Seric case MATCHZANY: 24357589Seric case MATCHANY: 24457589Seric case MATCHONE: 24557589Seric case MATCHCLASS: 24657589Seric case MATCHNCLASS: 24757589Seric nfuzzy++; 24858148Seric break; 24958148Seric 25058148Seric case MATCHREPL: 25158148Seric botch = "$0-$9"; 25258148Seric break; 25358148Seric 25458148Seric case CANONNET: 25558148Seric botch = "$#"; 25658148Seric break; 25758148Seric 25858148Seric case CANONUSER: 25958148Seric botch = "$:"; 26058148Seric break; 26158148Seric 26258148Seric case CALLSUBR: 26358148Seric botch = "$>"; 26458148Seric break; 26558148Seric 26658148Seric case CONDIF: 26758148Seric botch = "$?"; 26858148Seric break; 26958148Seric 27058148Seric case CONDELSE: 27158148Seric botch = "$|"; 27258148Seric break; 27358148Seric 27458148Seric case CONDFI: 27558148Seric botch = "$."; 27658148Seric break; 27758148Seric 27858148Seric case HOSTBEGIN: 27958148Seric botch = "$["; 28058148Seric break; 28158148Seric 28258148Seric case HOSTEND: 28358148Seric botch = "$]"; 28458148Seric break; 28558148Seric 28658148Seric case LOOKUPBEGIN: 28758148Seric botch = "$("; 28858148Seric break; 28958148Seric 29058148Seric case LOOKUPEND: 29158148Seric botch = "$)"; 29258148Seric break; 29357589Seric } 29458148Seric if (botch != NULL) 29558148Seric syserr("Inappropriate use of %s on LHS", 29658148Seric botch); 29757589Seric } 29857589Seric } 29956678Seric else 30068481Seric { 30156678Seric syserr("R line: null LHS"); 30268481Seric rwp->r_lhs = null_list; 30368481Seric } 3045909Seric 3055909Seric /* expand and save the RHS */ 3065909Seric while (*++p == '\t') 3075909Seric continue; 3087231Seric q = p; 3097231Seric while (*p != '\0' && *p != '\t') 3107231Seric p++; 3117231Seric *p = '\0'; 31268529Seric expand(q, exbuf, sizeof exbuf, e); 31365066Seric rwp->r_rhs = prescan(exbuf, '\t', pvpbuf, 31468711Seric sizeof pvpbuf, NULL, NULL); 3155909Seric if (rwp->r_rhs != NULL) 31657589Seric { 31757589Seric register char **ap; 31857589Seric 3195909Seric rwp->r_rhs = copyplist(rwp->r_rhs, TRUE); 32057589Seric 32157589Seric /* check no out-of-bounds replacements */ 32257589Seric nfuzzy += '0'; 32357589Seric for (ap = rwp->r_rhs; *ap != NULL; ap++) 32457589Seric { 32558148Seric char *botch; 32658148Seric 32758148Seric botch = NULL; 32858148Seric switch (**ap & 0377) 32957589Seric { 33058148Seric case MATCHREPL: 33158148Seric if ((*ap)[1] <= '0' || (*ap)[1] > nfuzzy) 33258148Seric { 33358148Seric syserr("replacement $%c out of bounds", 33458148Seric (*ap)[1]); 33558148Seric } 33658148Seric break; 33758148Seric 33858148Seric case MATCHZANY: 33958148Seric botch = "$*"; 34058148Seric break; 34158148Seric 34258148Seric case MATCHANY: 34358148Seric botch = "$+"; 34458148Seric break; 34558148Seric 34658148Seric case MATCHONE: 34758148Seric botch = "$-"; 34858148Seric break; 34958148Seric 35058148Seric case MATCHCLASS: 35158148Seric botch = "$="; 35258148Seric break; 35358148Seric 35458148Seric case MATCHNCLASS: 35558148Seric botch = "$~"; 35658148Seric break; 35757589Seric } 35858148Seric if (botch != NULL) 35958148Seric syserr("Inappropriate use of %s on RHS", 36058148Seric botch); 36157589Seric } 36257589Seric } 36356678Seric else 36468481Seric { 36556678Seric syserr("R line: null RHS"); 36668481Seric rwp->r_rhs = null_list; 36768481Seric } 3683308Seric break; 3693308Seric 3704072Seric case 'S': /* select rewriting set */ 37164440Seric for (p = &bp[1]; isascii(*p) && isspace(*p); p++) 37264440Seric continue; 37368481Seric if (!isascii(*p)) 37464440Seric { 37564440Seric syserr("invalid argument to S line: \"%.20s\"", 37664440Seric &bp[1]); 37764440Seric break; 37864440Seric } 37968481Seric if (isdigit(*p)) 3808056Seric { 38168481Seric ruleset = atoi(p); 38268481Seric if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 38368481Seric { 38468481Seric syserr("bad ruleset %d (%d max)", 38568481Seric ruleset, MAXRWSETS / 2); 38668481Seric ruleset = 0; 38768481Seric } 3888056Seric } 38968481Seric else 39068481Seric { 39168481Seric STAB *s; 39268481Seric char delim; 39368481Seric 39468481Seric q = p; 39568481Seric while (*p != '\0' && isascii(*p) && 39668481Seric (isalnum(*p) || strchr("-_$", *p) != NULL)) 39768481Seric p++; 39868481Seric while (isascii(*p) && isspace(*p)) 39968481Seric *p++ = '\0'; 40068481Seric delim = *p; 40168481Seric if (delim != '\0') 40268481Seric *p++ = '\0'; 40368481Seric s = stab(q, ST_RULESET, ST_ENTER); 40468481Seric if (s->s_ruleset != 0) 40568481Seric ruleset = s->s_ruleset; 40668481Seric else if (delim == '=') 40768481Seric { 40868481Seric ruleset = atoi(p); 40968481Seric if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 41068481Seric { 41168481Seric syserr("bad ruleset %s = %d (%d max)", 41268481Seric q, ruleset, MAXRWSETS / 2); 41368481Seric ruleset = 0; 41468481Seric } 41568481Seric } 41668481Seric else if ((ruleset = --nextruleset) < MAXRWSETS / 2) 41768481Seric { 41868481Seric syserr("%s: too many named rulesets (%d max)", 41968481Seric q, MAXRWSETS / 2); 42068481Seric ruleset = 0; 42168481Seric } 42268481Seric s->s_ruleset = ruleset; 42368481Seric } 4244072Seric rwp = NULL; 4254072Seric break; 4264072Seric 4273308Seric case 'D': /* macro definition */ 42868481Seric mid = macid(&bp[1], &ep); 42968481Seric p = munchstring(ep, NULL); 43068481Seric define(mid, newstr(p), e); 4313308Seric break; 4323308Seric 4333387Seric case 'H': /* required header line */ 43468717Seric (void) chompheader(&bp[1], TRUE, NULL, e); 4353387Seric break; 4363387Seric 4374061Seric case 'C': /* word class */ 43868481Seric case 'T': /* trusted user (set class `t') */ 43968481Seric if (bp[0] == 'C') 4404061Seric { 44168481Seric mid = macid(&bp[1], &ep); 44268529Seric expand(ep, exbuf, sizeof exbuf, e); 44368481Seric p = exbuf; 44468481Seric } 44568481Seric else 44668481Seric { 44768481Seric mid = 't'; 44868481Seric p = &bp[1]; 44968481Seric } 45068481Seric while (*p != '\0') 45168481Seric { 4524061Seric register char *wd; 4534061Seric char delim; 4544061Seric 45558050Seric while (*p != '\0' && isascii(*p) && isspace(*p)) 4564061Seric p++; 4574061Seric wd = p; 45858050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 4594061Seric p++; 4604061Seric delim = *p; 4614061Seric *p = '\0'; 4624061Seric if (wd[0] != '\0') 46368481Seric setclass(mid, wd); 4644061Seric *p = delim; 4654061Seric } 4664061Seric break; 4674061Seric 46859272Seric case 'F': /* word class from file */ 46968481Seric mid = macid(&bp[1], &ep); 47068481Seric for (p = ep; isascii(*p) && isspace(*p); ) 47164133Seric p++; 47264133Seric if (p[0] == '-' && p[1] == 'o') 47364133Seric { 47464133Seric optional = TRUE; 47564133Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 47664133Seric p++; 47764133Seric while (isascii(*p) && isspace(*p)) 47868481Seric p++; 47964133Seric } 48064133Seric else 48164133Seric optional = FALSE; 48264133Seric file = p; 48364133Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 48464133Seric p++; 48559272Seric if (*p == '\0') 48659272Seric p = "%s"; 48759272Seric else 48859272Seric { 48959272Seric *p = '\0'; 49059272Seric while (isascii(*++p) && isspace(*p)) 49159272Seric continue; 49259272Seric } 49364133Seric fileclass(bp[1], file, p, safe, optional); 49459272Seric break; 49559272Seric 49659156Seric #ifdef XLA 49759156Seric case 'L': /* extended load average description */ 49859156Seric xla_init(&bp[1]); 49959156Seric break; 50059156Seric #endif 50159156Seric 5024096Seric case 'M': /* define mailer */ 50357135Seric makemailer(&bp[1]); 5044096Seric break; 5054096Seric 5068252Seric case 'O': /* set option */ 50758734Seric setoption(bp[1], &bp[2], safe, FALSE, e); 5088252Seric break; 5098252Seric 5108252Seric case 'P': /* set precedence */ 5118252Seric if (NumPriorities >= MAXPRIORITIES) 5128252Seric { 5138547Seric toomany('P', MAXPRIORITIES); 5148252Seric break; 5158252Seric } 51657135Seric for (p = &bp[1]; *p != '\0' && *p != '=' && *p != '\t'; p++) 5178252Seric continue; 5188252Seric if (*p == '\0') 5198252Seric goto badline; 5208252Seric *p = '\0'; 52157135Seric Priorities[NumPriorities].pri_name = newstr(&bp[1]); 5228252Seric Priorities[NumPriorities].pri_val = atoi(++p); 5238252Seric NumPriorities++; 5248252Seric break; 5258252Seric 52652645Seric case 'V': /* configuration syntax version */ 52764440Seric for (p = &bp[1]; isascii(*p) && isspace(*p); p++) 52864440Seric continue; 52964440Seric if (!isascii(*p) || !isdigit(*p)) 53064440Seric { 53164440Seric syserr("invalid argument to V line: \"%.20s\"", 53264440Seric &bp[1]); 53364440Seric break; 53464440Seric } 53564718Seric ConfigLevel = strtol(p, &ep, 10); 53668805Seric 53768805Seric /* 53868805Seric ** Do heuristic tweaking for back compatibility. 53968805Seric */ 54068805Seric 54164279Seric if (ConfigLevel >= 5) 54264279Seric { 54364279Seric /* level 5 configs have short name in $w */ 54464279Seric p = macvalue('w', e); 54564279Seric if (p != NULL && (p = strchr(p, '.')) != NULL) 54664279Seric *p = '\0'; 54764279Seric } 54868805Seric if (ConfigLevel >= 6) 54968805Seric { 55068805Seric ColonOkInAddr = FALSE; 55168805Seric } 55268805Seric 55368805Seric /* 55468805Seric ** Look for vendor code. 55568805Seric */ 55668805Seric 55764718Seric if (*ep++ == '/') 55864718Seric { 55964718Seric /* extract vendor code */ 56064718Seric for (p = ep; isascii(*p) && isalpha(*p); ) 56164718Seric p++; 56264718Seric *p = '\0'; 56364718Seric 56464718Seric if (!setvendor(ep)) 56564718Seric syserr("invalid V line vendor code: \"%s\"", 56664718Seric ep); 56764718Seric } 56852645Seric break; 56952645Seric 57053654Seric case 'K': 57157135Seric makemapentry(&bp[1]); 57253654Seric break; 57353654Seric 57469476Seric case 'E': 57569476Seric p = strchr(bp, '='); 57669476Seric if (p != NULL) 57769476Seric *p++ = '\0'; 57869476Seric setuserenv(&bp[1], p); 57969476Seric break; 58069476Seric 5813308Seric default: 5824061Seric badline: 58357135Seric syserr("unknown control line \"%s\"", bp); 5843308Seric } 58557135Seric if (bp != buf) 58657135Seric free(bp); 5873308Seric } 58852637Seric if (ferror(cf)) 58952637Seric { 59052647Seric syserr("I/O read error", cfname); 59152637Seric exit(EX_OSFILE); 59252637Seric } 59352637Seric fclose(cf); 5949381Seric FileName = NULL; 59556836Seric 59668481Seric /* initialize host maps from local service tables */ 59768481Seric inithostmaps(); 59868481Seric 59968481Seric /* determine if we need to do special name-server frotz */ 60067905Seric { 60168481Seric int nmaps; 60268481Seric char *maptype[MAXMAPSTACK]; 60368481Seric short mapreturn[MAXMAPACTIONS]; 60468481Seric 60568481Seric nmaps = switch_map_find("hosts", maptype, mapreturn); 60668481Seric UseNameServer = FALSE; 60768481Seric if (nmaps > 0 && nmaps <= MAXMAPSTACK) 60868481Seric { 60968481Seric register int mapno; 61068481Seric 61168481Seric for (mapno = 0; mapno < nmaps && !UseNameServer; mapno++) 61268481Seric { 61368481Seric if (strcmp(maptype[mapno], "dns") == 0) 61468481Seric UseNameServer = TRUE; 61568481Seric } 61668481Seric } 61768481Seric 61868481Seric #ifdef HESIOD 61968481Seric nmaps = switch_map_find("passwd", maptype, mapreturn); 62068481Seric UseHesiod = FALSE; 62168481Seric if (nmaps > 0 && nmaps <= MAXMAPSTACK) 62268481Seric { 62368481Seric register int mapno; 62468481Seric 62568481Seric for (mapno = 0; mapno < nmaps && !UseHesiod; mapno++) 62668481Seric { 62768481Seric if (strcmp(maptype[mapno], "hesiod") == 0) 62868481Seric UseHesiod = TRUE; 62968481Seric } 63068481Seric } 63168204Seric #endif 63267905Seric } 6334096Seric } 6344096Seric /* 6358547Seric ** TOOMANY -- signal too many of some option 6368547Seric ** 6378547Seric ** Parameters: 6388547Seric ** id -- the id of the error line 6398547Seric ** maxcnt -- the maximum possible values 6408547Seric ** 6418547Seric ** Returns: 6428547Seric ** none. 6438547Seric ** 6448547Seric ** Side Effects: 6458547Seric ** gives a syserr. 6468547Seric */ 6478547Seric 6488547Seric toomany(id, maxcnt) 6498547Seric char id; 6508547Seric int maxcnt; 6518547Seric { 6529381Seric syserr("too many %c lines, %d max", id, maxcnt); 6538547Seric } 6548547Seric /* 6554432Seric ** FILECLASS -- read members of a class from a file 6564432Seric ** 6574432Seric ** Parameters: 6584432Seric ** class -- class to define. 6594432Seric ** filename -- name of file to read. 6604432Seric ** fmt -- scanf string to use for match. 66164133Seric ** safe -- if set, this is a safe read. 66264133Seric ** optional -- if set, it is not an error for the file to 66364133Seric ** not exist. 6644432Seric ** 6654432Seric ** Returns: 6664432Seric ** none 6674432Seric ** 6684432Seric ** Side Effects: 6694432Seric ** 6704432Seric ** puts all lines in filename that match a scanf into 6714432Seric ** the named class. 6724432Seric */ 6734432Seric 67464133Seric fileclass(class, filename, fmt, safe, optional) 6754432Seric int class; 6764432Seric char *filename; 6774432Seric char *fmt; 67854973Seric bool safe; 67964133Seric bool optional; 6804432Seric { 68125808Seric FILE *f; 68268513Seric int sff; 68369453Seric int pid; 68469453Seric register char *p; 6854432Seric char buf[MAXLINE]; 6864432Seric 68766101Seric if (tTd(37, 2)) 68866101Seric printf("fileclass(%s, fmt=%s)\n", filename, fmt); 68966101Seric 69066031Seric if (filename[0] == '|') 69166031Seric { 69269453Seric auto int fd; 69369453Seric int i; 69469453Seric char *argv[MAXPV + 1]; 69569453Seric 69669453Seric i = 0; 69769453Seric for (p = strtok(&filename[1], " \t"); p != NULL; p = strtok(NULL, " \t")) 69869453Seric { 69969453Seric if (i >= MAXPV) 70069453Seric break; 70169453Seric argv[i++] = p; 70269453Seric } 70369453Seric argv[i] = NULL; 70469453Seric pid = prog_open(argv, &fd, CurEnv); 70569453Seric if (pid < 0) 70669453Seric f = NULL; 70769453Seric else 70869453Seric f = fdopen(fd, "r"); 70966031Seric } 71069453Seric else 71169453Seric { 71269453Seric pid = -1; 71369453Seric sff = SFF_REGONLY; 71469453Seric if (safe) 71569453Seric sff |= SFF_OPENASROOT; 71669453Seric f = safefopen(filename, O_RDONLY, 0, sff); 71769453Seric } 71868602Seric if (f == NULL) 71954973Seric { 72068602Seric if (!optional) 72168602Seric syserr("fileclass: cannot open %s", filename); 7224432Seric return; 7234432Seric } 7244432Seric 7254432Seric while (fgets(buf, sizeof buf, f) != NULL) 7264432Seric { 7274432Seric register STAB *s; 72825808Seric register char *p; 72925808Seric # ifdef SCANF 7304432Seric char wordbuf[MAXNAME+1]; 7314432Seric 7324432Seric if (sscanf(buf, fmt, wordbuf) != 1) 7334432Seric continue; 73425808Seric p = wordbuf; 73556795Seric # else /* SCANF */ 73625808Seric p = buf; 73756795Seric # endif /* SCANF */ 73825808Seric 73925808Seric /* 74025808Seric ** Break up the match into words. 74125808Seric */ 74225808Seric 74325808Seric while (*p != '\0') 74425808Seric { 74525808Seric register char *q; 74625808Seric 74725808Seric /* strip leading spaces */ 74858050Seric while (isascii(*p) && isspace(*p)) 74925808Seric p++; 75025808Seric if (*p == '\0') 75125808Seric break; 75225808Seric 75325808Seric /* find the end of the word */ 75425808Seric q = p; 75558050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 75625808Seric p++; 75725808Seric if (*p != '\0') 75825808Seric *p++ = '\0'; 75925808Seric 76025808Seric /* enter the word in the symbol table */ 76166101Seric setclass(class, q); 76225808Seric } 7634432Seric } 7644432Seric 76554973Seric (void) fclose(f); 76669453Seric if (pid > 0) 76769453Seric (void) waitfor(pid); 7684432Seric } 7694432Seric /* 7704096Seric ** MAKEMAILER -- define a new mailer. 7714096Seric ** 7724096Seric ** Parameters: 77310327Seric ** line -- description of mailer. This is in labeled 77410327Seric ** fields. The fields are: 77568481Seric ** A -- the argv for this mailer 77668481Seric ** C -- the character set for MIME conversions 77768481Seric ** D -- the directory to run in 77868481Seric ** E -- the eol string 77968481Seric ** F -- the flags associated with the mailer 78068481Seric ** L -- the maximum line length 78168481Seric ** M -- the maximum message size 78268816Seric ** N -- the niceness at which to run 78368479Seric ** P -- the path to the mailer 78468481Seric ** R -- the recipient rewriting set 78568479Seric ** S -- the sender rewriting set 78668481Seric ** T -- the mailer type (for DSNs) 78768481Seric ** U -- the uid to run as 78810327Seric ** The first word is the canonical name of the mailer. 7894096Seric ** 7904096Seric ** Returns: 7914096Seric ** none. 7924096Seric ** 7934096Seric ** Side Effects: 7944096Seric ** enters the mailer into the mailer table. 7954096Seric */ 7963308Seric 79721066Seric makemailer(line) 7984096Seric char *line; 7994096Seric { 8004096Seric register char *p; 8018067Seric register struct mailer *m; 8028067Seric register STAB *s; 8038067Seric int i; 80410327Seric char fcode; 80558020Seric auto char *endp; 8064096Seric extern int NextMailer; 80710327Seric extern char **makeargv(); 80810327Seric extern char *munchstring(); 8094096Seric 81010327Seric /* allocate a mailer and set up defaults */ 81110327Seric m = (struct mailer *) xalloc(sizeof *m); 81210327Seric bzero((char *) m, sizeof *m); 81310327Seric m->m_eol = "\n"; 81468481Seric m->m_uid = m->m_gid = 0; 81510327Seric 81610327Seric /* collect the mailer name */ 81758050Seric for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++) 81810327Seric continue; 81910327Seric if (*p != '\0') 82010327Seric *p++ = '\0'; 82110327Seric m->m_name = newstr(line); 82210327Seric 82310327Seric /* now scan through and assign info from the fields */ 82410327Seric while (*p != '\0') 82510327Seric { 82658333Seric auto char *delimptr; 82758333Seric 82858050Seric while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p)))) 82910327Seric p++; 83010327Seric 83110327Seric /* p now points to field code */ 83210327Seric fcode = *p; 83310327Seric while (*p != '\0' && *p != '=' && *p != ',') 83410327Seric p++; 83510327Seric if (*p++ != '=') 83610327Seric { 83752637Seric syserr("mailer %s: `=' expected", m->m_name); 83810327Seric return; 83910327Seric } 84058050Seric while (isascii(*p) && isspace(*p)) 84110327Seric p++; 84210327Seric 84310327Seric /* p now points to the field body */ 84458333Seric p = munchstring(p, &delimptr); 84510327Seric 84610327Seric /* install the field into the mailer struct */ 84710327Seric switch (fcode) 84810327Seric { 84910327Seric case 'P': /* pathname */ 85010327Seric m->m_mailer = newstr(p); 85110327Seric break; 85210327Seric 85310327Seric case 'F': /* flags */ 85410687Seric for (; *p != '\0'; p++) 85558050Seric if (!(isascii(*p) && isspace(*p))) 85652637Seric setbitn(*p, m->m_flags); 85710327Seric break; 85810327Seric 85910327Seric case 'S': /* sender rewriting ruleset */ 86010327Seric case 'R': /* recipient rewriting ruleset */ 86158020Seric i = strtol(p, &endp, 10); 86210327Seric if (i < 0 || i >= MAXRWSETS) 86310327Seric { 86410327Seric syserr("invalid rewrite set, %d max", MAXRWSETS); 86510327Seric return; 86610327Seric } 86710327Seric if (fcode == 'S') 86858020Seric m->m_sh_rwset = m->m_se_rwset = i; 86910327Seric else 87058020Seric m->m_rh_rwset = m->m_re_rwset = i; 87158020Seric 87258020Seric p = endp; 87359985Seric if (*p++ == '/') 87458020Seric { 87558020Seric i = strtol(p, NULL, 10); 87658020Seric if (i < 0 || i >= MAXRWSETS) 87758020Seric { 87858020Seric syserr("invalid rewrite set, %d max", 87958020Seric MAXRWSETS); 88058020Seric return; 88158020Seric } 88258020Seric if (fcode == 'S') 88358020Seric m->m_sh_rwset = i; 88458020Seric else 88558020Seric m->m_rh_rwset = i; 88658020Seric } 88710327Seric break; 88810327Seric 88910327Seric case 'E': /* end of line string */ 89010327Seric m->m_eol = newstr(p); 89110327Seric break; 89210327Seric 89310327Seric case 'A': /* argument vector */ 89410327Seric m->m_argv = makeargv(p); 89510327Seric break; 89610701Seric 89710701Seric case 'M': /* maximum message size */ 89810701Seric m->m_maxsize = atol(p); 89910701Seric break; 90052106Seric 90152106Seric case 'L': /* maximum line length */ 90252106Seric m->m_linelimit = atoi(p); 90352106Seric break; 90458935Seric 90568816Seric case 'N': /* run niceness */ 90668816Seric m->m_nice = atoi(p); 90768816Seric break; 90868816Seric 90958935Seric case 'D': /* working directory */ 91058935Seric m->m_execdir = newstr(p); 91158935Seric break; 91268481Seric 91368481Seric case 'C': /* default charset */ 91468481Seric m->m_defcharset = newstr(p); 91568481Seric break; 91668481Seric 91769720Seric case 'T': /* MTA-Name/Address/Diagnostic types */ 91868481Seric m->m_mtatype = newstr(p); 91968481Seric p = strchr(m->m_mtatype, '/'); 92068481Seric if (p != NULL) 92168481Seric { 92268481Seric *p++ = '\0'; 92368481Seric if (*p == '\0') 92468481Seric p = NULL; 92568481Seric } 92668481Seric if (p == NULL) 92768481Seric m->m_addrtype = m->m_mtatype; 92868481Seric else 92968481Seric { 93068481Seric m->m_addrtype = p; 93168481Seric p = strchr(p, '/'); 93268481Seric } 93368481Seric if (p != NULL) 93468481Seric { 93568481Seric *p++ = '\0'; 93668481Seric if (*p == '\0') 93768481Seric p = NULL; 93868481Seric } 93968481Seric if (p == NULL) 94068481Seric m->m_diagtype = m->m_mtatype; 94168481Seric else 94268481Seric m->m_diagtype = p; 94368481Seric break; 94468481Seric 94568481Seric case 'U': /* user id */ 94668481Seric if (isascii(*p) && !isdigit(*p)) 94768481Seric { 94868481Seric char *q = p; 94968481Seric struct passwd *pw; 95068481Seric 95168481Seric while (isascii(*p) && isalnum(*p)) 95268481Seric p++; 95368481Seric while (isascii(*p) && isspace(*p)) 95468481Seric *p++ = '\0'; 95568481Seric if (*p != '\0') 95668481Seric *p++ = '\0'; 95768693Seric pw = sm_getpwnam(q); 95868481Seric if (pw == NULL) 95968481Seric syserr("readcf: mailer U= flag: unknown user %s", q); 96068481Seric else 96168481Seric { 96268481Seric m->m_uid = pw->pw_uid; 96368481Seric m->m_gid = pw->pw_gid; 96468481Seric } 96568481Seric } 96668481Seric else 96768481Seric { 96868481Seric auto char *q; 96968481Seric 97068481Seric m->m_uid = strtol(p, &q, 0); 97168481Seric p = q; 97268481Seric } 97368481Seric while (isascii(*p) && isspace(*p)) 97468481Seric p++; 97568481Seric if (*p == '\0') 97668481Seric break; 97768481Seric if (isascii(*p) && !isdigit(*p)) 97868481Seric { 97968481Seric char *q = p; 98068481Seric struct group *gr; 98168481Seric 98268481Seric while (isascii(*p) && isalnum(*p)) 98368481Seric p++; 98468481Seric *p++ = '\0'; 98568481Seric gr = getgrnam(q); 98668481Seric if (gr == NULL) 98768481Seric syserr("readcf: mailer U= flag: unknown group %s", q); 98868481Seric else 98968481Seric m->m_gid = gr->gr_gid; 99068481Seric } 99168481Seric else 99268481Seric { 99368481Seric m->m_gid = strtol(p, NULL, 0); 99468481Seric } 99568481Seric break; 99610327Seric } 99710327Seric 99858333Seric p = delimptr; 99910327Seric } 100010327Seric 100158321Seric /* do some rationality checking */ 100258321Seric if (m->m_argv == NULL) 100358321Seric { 100458321Seric syserr("M%s: A= argument required", m->m_name); 100558321Seric return; 100658321Seric } 100758321Seric if (m->m_mailer == NULL) 100858321Seric { 100958321Seric syserr("M%s: P= argument required", m->m_name); 101058321Seric return; 101158321Seric } 101258321Seric 10134096Seric if (NextMailer >= MAXMAILERS) 10144096Seric { 10159381Seric syserr("too many mailers defined (%d max)", MAXMAILERS); 10164096Seric return; 10174096Seric } 101857402Seric 101968481Seric /* do some heuristic cleanup for back compatibility */ 102068481Seric if (bitnset(M_LIMITS, m->m_flags)) 102168481Seric { 102268481Seric if (m->m_linelimit == 0) 102368481Seric m->m_linelimit = SMTPLINELIM; 102468481Seric if (ConfigLevel < 2) 102568481Seric setbitn(M_7BITS, m->m_flags); 102668481Seric } 102768481Seric 102868481Seric if (ConfigLevel < 6 && 102968481Seric (strcmp(m->m_mailer, "[IPC]") == 0 || 103068481Seric strcmp(m->m_mailer, "[TCP]") == 0)) 103168481Seric { 103268481Seric if (m->m_mtatype == NULL) 103368481Seric m->m_mtatype = "dns"; 103468481Seric if (m->m_addrtype == NULL) 103568481Seric m->m_addrtype = "rfc822"; 103668481Seric if (m->m_diagtype == NULL) 103768481Seric m->m_diagtype = "smtp"; 103868481Seric } 103968481Seric 104068481Seric /* enter the mailer into the symbol table */ 104110327Seric s = stab(m->m_name, ST_MAILER, ST_ENTER); 104257402Seric if (s->s_mailer != NULL) 104357402Seric { 104457402Seric i = s->s_mailer->m_mno; 104557402Seric free(s->s_mailer); 104657402Seric } 104757402Seric else 104857402Seric { 104957402Seric i = NextMailer++; 105057402Seric } 105157402Seric Mailer[i] = s->s_mailer = m; 105257454Seric m->m_mno = i; 105310327Seric } 105410327Seric /* 105510327Seric ** MUNCHSTRING -- translate a string into internal form. 105610327Seric ** 105710327Seric ** Parameters: 105810327Seric ** p -- the string to munch. 105958333Seric ** delimptr -- if non-NULL, set to the pointer of the 106058333Seric ** field delimiter character. 106110327Seric ** 106210327Seric ** Returns: 106310327Seric ** the munched string. 106410327Seric */ 10654096Seric 106610327Seric char * 106758333Seric munchstring(p, delimptr) 106810327Seric register char *p; 106958333Seric char **delimptr; 107010327Seric { 107110327Seric register char *q; 107210327Seric bool backslash = FALSE; 107310327Seric bool quotemode = FALSE; 107410327Seric static char buf[MAXLINE]; 10754096Seric 107610327Seric for (q = buf; *p != '\0'; p++) 10774096Seric { 107810327Seric if (backslash) 107910327Seric { 108010327Seric /* everything is roughly literal */ 108110357Seric backslash = FALSE; 108210327Seric switch (*p) 108310327Seric { 108410327Seric case 'r': /* carriage return */ 108510327Seric *q++ = '\r'; 108610327Seric continue; 108710327Seric 108810327Seric case 'n': /* newline */ 108910327Seric *q++ = '\n'; 109010327Seric continue; 109110327Seric 109210327Seric case 'f': /* form feed */ 109310327Seric *q++ = '\f'; 109410327Seric continue; 109510327Seric 109610327Seric case 'b': /* backspace */ 109710327Seric *q++ = '\b'; 109810327Seric continue; 109910327Seric } 110010327Seric *q++ = *p; 110110327Seric } 110210327Seric else 110310327Seric { 110410327Seric if (*p == '\\') 110510327Seric backslash = TRUE; 110610327Seric else if (*p == '"') 110710327Seric quotemode = !quotemode; 110810327Seric else if (quotemode || *p != ',') 110910327Seric *q++ = *p; 111010327Seric else 111110327Seric break; 111210327Seric } 11134096Seric } 11144096Seric 111558333Seric if (delimptr != NULL) 111658333Seric *delimptr = p; 111710327Seric *q++ = '\0'; 111810327Seric return (buf); 111910327Seric } 112010327Seric /* 112110327Seric ** MAKEARGV -- break up a string into words 112210327Seric ** 112310327Seric ** Parameters: 112410327Seric ** p -- the string to break up. 112510327Seric ** 112610327Seric ** Returns: 112710327Seric ** a char **argv (dynamically allocated) 112810327Seric ** 112910327Seric ** Side Effects: 113010327Seric ** munges p. 113110327Seric */ 11324096Seric 113310327Seric char ** 113410327Seric makeargv(p) 113510327Seric register char *p; 113610327Seric { 113710327Seric char *q; 113810327Seric int i; 113910327Seric char **avp; 114010327Seric char *argv[MAXPV + 1]; 114110327Seric 114210327Seric /* take apart the words */ 114310327Seric i = 0; 114410327Seric while (*p != '\0' && i < MAXPV) 11454096Seric { 114610327Seric q = p; 114758050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 114810327Seric p++; 114958050Seric while (isascii(*p) && isspace(*p)) 115010327Seric *p++ = '\0'; 115110327Seric argv[i++] = newstr(q); 11524096Seric } 115310327Seric argv[i++] = NULL; 11544096Seric 115510327Seric /* now make a copy of the argv */ 115610327Seric avp = (char **) xalloc(sizeof *avp * i); 115716893Seric bcopy((char *) argv, (char *) avp, sizeof *avp * i); 115810327Seric 115910327Seric return (avp); 11603308Seric } 11613308Seric /* 11623308Seric ** PRINTRULES -- print rewrite rules (for debugging) 11633308Seric ** 11643308Seric ** Parameters: 11653308Seric ** none. 11663308Seric ** 11673308Seric ** Returns: 11683308Seric ** none. 11693308Seric ** 11703308Seric ** Side Effects: 11713308Seric ** prints rewrite rules. 11723308Seric */ 11733308Seric 11743308Seric printrules() 11753308Seric { 11763308Seric register struct rewrite *rwp; 11774072Seric register int ruleset; 11783308Seric 11794072Seric for (ruleset = 0; ruleset < 10; ruleset++) 11803308Seric { 11814072Seric if (RewriteRules[ruleset] == NULL) 11824072Seric continue; 11838067Seric printf("\n----Rule Set %d:", ruleset); 11843308Seric 11854072Seric for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 11863308Seric { 11878067Seric printf("\nLHS:"); 11888067Seric printav(rwp->r_lhs); 11898067Seric printf("RHS:"); 11908067Seric printav(rwp->r_rhs); 11913308Seric } 11923308Seric } 11933308Seric } 119468481Seric /* 119568481Seric ** PRINTMAILER -- print mailer structure (for debugging) 119668481Seric ** 119768481Seric ** Parameters: 119868481Seric ** m -- the mailer to print 119968481Seric ** 120068481Seric ** Returns: 120168481Seric ** none. 120268481Seric */ 12034319Seric 120468481Seric printmailer(m) 120568481Seric register MAILER *m; 120668481Seric { 120768481Seric int j; 120868481Seric 120968481Seric printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld U=%d:%d F=", 121068481Seric m->m_mno, m->m_name, 121168481Seric m->m_mailer, m->m_se_rwset, m->m_sh_rwset, 121268481Seric m->m_re_rwset, m->m_rh_rwset, m->m_maxsize, 121368481Seric m->m_uid, m->m_gid); 121468481Seric for (j = '\0'; j <= '\177'; j++) 121568481Seric if (bitnset(j, m->m_flags)) 121668481Seric (void) putchar(j); 121768481Seric printf(" L=%d E=", m->m_linelimit); 121868481Seric xputs(m->m_eol); 121968481Seric if (m->m_defcharset != NULL) 122068481Seric printf(" C=%s", m->m_defcharset); 122168481Seric printf(" T=%s/%s/%s", 122268481Seric m->m_mtatype == NULL ? "<undefined>" : m->m_mtatype, 122368481Seric m->m_addrtype == NULL ? "<undefined>" : m->m_addrtype, 122468481Seric m->m_diagtype == NULL ? "<undefined>" : m->m_diagtype); 122568481Seric if (m->m_argv != NULL) 122668481Seric { 122768481Seric char **a = m->m_argv; 122868481Seric 122968481Seric printf(" A="); 123068481Seric while (*a != NULL) 123168481Seric { 123268481Seric if (a != m->m_argv) 123368481Seric printf(" "); 123468481Seric xputs(*a++); 123568481Seric } 123668481Seric } 123768481Seric printf("\n"); 123868481Seric } 12394096Seric /* 12408256Seric ** SETOPTION -- set global processing option 12418256Seric ** 12428256Seric ** Parameters: 12438256Seric ** opt -- option name. 12448256Seric ** val -- option value (as a text string). 124521755Seric ** safe -- set if this came from a configuration file. 124621755Seric ** Some options (if set from the command line) will 124721755Seric ** reset the user id to avoid security problems. 12488269Seric ** sticky -- if set, don't let other setoptions override 12498269Seric ** this value. 125058734Seric ** e -- the main envelope. 12518256Seric ** 12528256Seric ** Returns: 12538256Seric ** none. 12548256Seric ** 12558256Seric ** Side Effects: 12568256Seric ** Sets options as implied by the arguments. 12578256Seric */ 12588256Seric 125910687Seric static BITMAP StickyOpt; /* set if option is stuck */ 12608269Seric 126157207Seric 126266334Seric #if NAMED_BIND 126357207Seric 126457207Seric struct resolverflags 126557207Seric { 126657207Seric char *rf_name; /* name of the flag */ 126757207Seric long rf_bits; /* bits to set/clear */ 126857207Seric } ResolverFlags[] = 126957207Seric { 127057207Seric "debug", RES_DEBUG, 127157207Seric "aaonly", RES_AAONLY, 127257207Seric "usevc", RES_USEVC, 127357207Seric "primary", RES_PRIMARY, 127457207Seric "igntc", RES_IGNTC, 127557207Seric "recurse", RES_RECURSE, 127657207Seric "defnames", RES_DEFNAMES, 127757207Seric "stayopen", RES_STAYOPEN, 127857207Seric "dnsrch", RES_DNSRCH, 127965583Seric "true", 0, /* to avoid error on old syntax */ 128057207Seric NULL, 0 128157207Seric }; 128257207Seric 128357207Seric #endif 128457207Seric 128568481Seric struct optioninfo 128668481Seric { 128768481Seric char *o_name; /* long name of option */ 128868481Seric u_char o_code; /* short name of option */ 128968481Seric bool o_safe; /* safe for random people to use */ 129068481Seric } OptionTab[] = 129168481Seric { 129268481Seric "SevenBitInput", '7', TRUE, 129369480Seric #if MIME8TO7 129468481Seric "EightBitMode", '8', TRUE, 129569480Seric #endif 129668481Seric "AliasFile", 'A', FALSE, 129768481Seric "AliasWait", 'a', FALSE, 129868481Seric "BlankSub", 'B', FALSE, 129968481Seric "MinFreeBlocks", 'b', TRUE, 130068481Seric "CheckpointInterval", 'C', TRUE, 130168481Seric "HoldExpensive", 'c', FALSE, 130268481Seric "AutoRebuildAliases", 'D', FALSE, 130368481Seric "DeliveryMode", 'd', TRUE, 130468481Seric "ErrorHeader", 'E', FALSE, 130568481Seric "ErrorMode", 'e', TRUE, 130668481Seric "TempFileMode", 'F', FALSE, 130768481Seric "SaveFromLine", 'f', FALSE, 130868481Seric "MatchGECOS", 'G', FALSE, 130968481Seric "HelpFile", 'H', FALSE, 131068481Seric "MaxHopCount", 'h', FALSE, 131168569Seric "ResolverOptions", 'I', FALSE, 131268481Seric "IgnoreDots", 'i', TRUE, 131368481Seric "ForwardPath", 'J', FALSE, 131468481Seric "SendMimeErrors", 'j', TRUE, 131568481Seric "ConnectionCacheSize", 'k', FALSE, 131668481Seric "ConnectionCacheTimeout", 'K', FALSE, 131768481Seric "UseErrorsTo", 'l', FALSE, 131868481Seric "LogLevel", 'L', FALSE, 131968481Seric "MeToo", 'm', TRUE, 132068481Seric "CheckAliases", 'n', FALSE, 132168481Seric "OldStyleHeaders", 'o', TRUE, 132268481Seric "DaemonPortOptions", 'O', FALSE, 132368481Seric "PrivacyOptions", 'p', TRUE, 132468481Seric "PostmasterCopy", 'P', FALSE, 132568481Seric "QueueFactor", 'q', FALSE, 132668481Seric "QueueDirectory", 'Q', FALSE, 132768481Seric "DontPruneRoutes", 'R', FALSE, 132868481Seric "Timeout", 'r', TRUE, 132968481Seric "StatusFile", 'S', FALSE, 133068481Seric "SuperSafe", 's', TRUE, 133168481Seric "QueueTimeout", 'T', FALSE, 133268481Seric "TimeZoneSpec", 't', FALSE, 133368481Seric "UserDatabaseSpec", 'U', FALSE, 133468481Seric "DefaultUser", 'u', FALSE, 133568481Seric "FallbackMXhost", 'V', FALSE, 133668481Seric "Verbose", 'v', TRUE, 133768481Seric "TryNullMXList", 'w', TRUE, 133868481Seric "QueueLA", 'x', FALSE, 133968481Seric "RefuseLA", 'X', FALSE, 134068481Seric "RecipientFactor", 'y', FALSE, 134168569Seric "ForkEachJob", 'Y', FALSE, 134268481Seric "ClassFactor", 'z', FALSE, 134368569Seric "RetryFactor", 'Z', FALSE, 134468481Seric #define O_QUEUESORTORD 0x81 134568481Seric "QueueSortOrder", O_QUEUESORTORD, TRUE, 134669401Seric #define O_HOSTSFILE 0x82 134769401Seric "HostsFile", O_HOSTSFILE, FALSE, 134868481Seric #define O_MQA 0x83 134968481Seric "MinQueueAge", O_MQA, TRUE, 135068481Seric #define O_MHSA 0x84 135168481Seric /* 135268481Seric "MaxHostStatAge", O_MHSA, TRUE, 135368481Seric */ 135468481Seric #define O_DEFCHARSET 0x85 135568481Seric "DefaultCharSet", O_DEFCHARSET, TRUE, 135668481Seric #define O_SSFILE 0x86 135768481Seric "ServiceSwitchFile", O_SSFILE, FALSE, 135868481Seric #define O_DIALDELAY 0x87 135968481Seric "DialDelay", O_DIALDELAY, TRUE, 136068481Seric #define O_NORCPTACTION 0x88 136168481Seric "NoRecipientAction", O_NORCPTACTION, TRUE, 136268490Seric #define O_SAFEFILEENV 0x89 136368490Seric "SafeFileEnvironment", O_SAFEFILEENV, FALSE, 136468569Seric #define O_MAXMSGSIZE 0x8a 136568569Seric "MaxMessageSize", O_MAXMSGSIZE, FALSE, 136668756Seric #define O_COLONOKINADDR 0x8b 136768756Seric "ColonOkInAddr", O_COLONOKINADDR, TRUE, 1368*69724Seric #define O_MAXQUEUERUN 0x8c 1369*69724Seric "MaxQueueRunSize", O_MAXQUEUERUN, TRUE, 137068481Seric 137168481Seric NULL, '\0', FALSE, 137268481Seric }; 137368481Seric 137468481Seric 137568481Seric 137658734Seric setoption(opt, val, safe, sticky, e) 137768481Seric u_char opt; 13788256Seric char *val; 137921755Seric bool safe; 13808269Seric bool sticky; 138158734Seric register ENVELOPE *e; 13828256Seric { 138357207Seric register char *p; 138468481Seric register struct optioninfo *o; 138568481Seric char *subopt; 13868265Seric extern bool atobool(); 138712633Seric extern time_t convtime(); 138814879Seric extern int QueueLA; 138914879Seric extern int RefuseLA; 139064718Seric extern bool Warn_Q_option; 13918256Seric 139268481Seric errno = 0; 139368481Seric if (opt == ' ') 139468481Seric { 139568481Seric /* full word options */ 139668481Seric struct optioninfo *sel; 139768481Seric 139868481Seric p = strchr(val, '='); 139968481Seric if (p == NULL) 140068481Seric p = &val[strlen(val)]; 140168481Seric while (*--p == ' ') 140268481Seric continue; 140368481Seric while (*++p == ' ') 140468481Seric *p = '\0'; 140568481Seric if (p == val) 140668481Seric { 140768481Seric syserr("readcf: null option name"); 140868481Seric return; 140968481Seric } 141068481Seric if (*p == '=') 141168481Seric *p++ = '\0'; 141268481Seric while (*p == ' ') 141368481Seric p++; 141468481Seric subopt = strchr(val, '.'); 141568481Seric if (subopt != NULL) 141668481Seric *subopt++ = '\0'; 141768481Seric sel = NULL; 141868481Seric for (o = OptionTab; o->o_name != NULL; o++) 141968481Seric { 142068481Seric if (strncasecmp(o->o_name, val, strlen(val)) != 0) 142168481Seric continue; 142268481Seric if (strlen(o->o_name) == strlen(val)) 142368481Seric { 142468481Seric /* completely specified -- this must be it */ 142568481Seric sel = NULL; 142668481Seric break; 142768481Seric } 142868481Seric if (sel != NULL) 142968481Seric break; 143068481Seric sel = o; 143168481Seric } 143268481Seric if (sel != NULL && o->o_name == NULL) 143368481Seric o = sel; 143468481Seric else if (o->o_name == NULL) 143568481Seric { 143668481Seric syserr("readcf: unknown option name %s", val); 143768481Seric return; 143868481Seric } 143968481Seric else if (sel != NULL) 144068481Seric { 144168481Seric syserr("readcf: ambiguous option name %s (matches %s and %s)", 144268481Seric val, sel->o_name, o->o_name); 144368481Seric return; 144468481Seric } 144568481Seric if (strlen(val) != strlen(o->o_name)) 144668481Seric { 144768481Seric bool oldVerbose = Verbose; 144868481Seric 144968481Seric Verbose = TRUE; 145068481Seric message("Option %s used as abbreviation for %s", 145168481Seric val, o->o_name); 145268481Seric Verbose = oldVerbose; 145368481Seric } 145468481Seric opt = o->o_code; 145568481Seric val = p; 145668481Seric } 145768481Seric else 145868481Seric { 145968481Seric for (o = OptionTab; o->o_name != NULL; o++) 146068481Seric { 146168481Seric if (o->o_code == opt) 146268481Seric break; 146368481Seric } 146468481Seric subopt = NULL; 146568481Seric } 146668481Seric 14678256Seric if (tTd(37, 1)) 146868481Seric { 146968481Seric printf(isascii(opt) && isprint(opt) ? 147068481Seric "setoption %s (%c).%s=%s" : 147168481Seric "setoption %s (0x%x).%s=%s", 147268481Seric o->o_name == NULL ? "<unknown>" : o->o_name, 147368481Seric opt, 147468481Seric subopt == NULL ? "" : subopt, 147568481Seric val); 147668481Seric } 14778256Seric 14788256Seric /* 14798269Seric ** See if this option is preset for us. 14808256Seric */ 14818256Seric 148259731Seric if (!sticky && bitnset(opt, StickyOpt)) 14838269Seric { 14849341Seric if (tTd(37, 1)) 14859341Seric printf(" (ignored)\n"); 14868269Seric return; 14878269Seric } 14888269Seric 148921755Seric /* 149021755Seric ** Check to see if this option can be specified by this user. 149121755Seric */ 149221755Seric 149363787Seric if (!safe && RealUid == 0) 149421755Seric safe = TRUE; 149568481Seric if (!safe && !o->o_safe) 149621755Seric { 149739111Srick if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 149821755Seric { 149936582Sbostic if (tTd(37, 1)) 150036582Sbostic printf(" (unsafe)"); 150163787Seric if (RealUid != geteuid()) 150236582Sbostic { 150351210Seric if (tTd(37, 1)) 150451210Seric printf("(Resetting uid)"); 150563787Seric (void) setgid(RealGid); 150663787Seric (void) setuid(RealUid); 150736582Sbostic } 150821755Seric } 150921755Seric } 151051210Seric if (tTd(37, 1)) 151117985Seric printf("\n"); 15128269Seric 151368481Seric switch (opt & 0xff) 15148256Seric { 151559709Seric case '7': /* force seven-bit input */ 151668481Seric SevenBitInput = atobool(val); 151752106Seric break; 151852106Seric 151969480Seric #if MIME8TO7 152068481Seric case '8': /* handling of 8-bit input */ 152168481Seric switch (*val) 152268481Seric { 152368481Seric case 'm': /* convert 8-bit, convert MIME */ 152468481Seric MimeMode = MM_CVTMIME|MM_MIME8BIT; 152568481Seric break; 152668481Seric 152768481Seric case 'p': /* pass 8 bit, convert MIME */ 152868856Seric MimeMode = MM_CVTMIME|MM_PASS8BIT; 152968481Seric break; 153068481Seric 153168481Seric case 's': /* strict adherence */ 153268481Seric MimeMode = MM_CVTMIME; 153368481Seric break; 153468481Seric 153568856Seric #if 0 153668856Seric case 'r': /* reject 8-bit, don't convert MIME */ 153768856Seric MimeMode = 0; 153868856Seric break; 153968856Seric 154068856Seric case 'j': /* "just send 8" */ 154168856Seric MimeMode = MM_PASS8BIT; 154268856Seric break; 154368856Seric 154468481Seric case 'a': /* encode 8 bit if available */ 154568481Seric MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 154668481Seric break; 154768481Seric 154868481Seric case 'c': /* convert 8 bit to MIME, never 7 bit */ 154968481Seric MimeMode = MM_MIME8BIT; 155068481Seric break; 155168856Seric #endif 155268481Seric 155368481Seric default: 155468481Seric syserr("Unknown 8-bit mode %c", *val); 155568481Seric exit(EX_USAGE); 155668481Seric } 155768481Seric break; 155869480Seric #endif 155968481Seric 15608256Seric case 'A': /* set default alias file */ 15619381Seric if (val[0] == '\0') 156259672Seric setalias("aliases"); 15639381Seric else 156459672Seric setalias(val); 15658256Seric break; 15668256Seric 156717474Seric case 'a': /* look N minutes for "@:@" in alias file */ 156817474Seric if (val[0] == '\0') 156964796Seric SafeAlias = 5 * 60; /* five minutes */ 157017474Seric else 157164796Seric SafeAlias = convtime(val, 'm'); 157217474Seric break; 157317474Seric 157416843Seric case 'B': /* substitution for blank character */ 157516843Seric SpaceSub = val[0]; 157616843Seric if (SpaceSub == '\0') 157716843Seric SpaceSub = ' '; 157816843Seric break; 157916843Seric 158059283Seric case 'b': /* min blocks free on queue fs/max msg size */ 158159283Seric p = strchr(val, '/'); 158259283Seric if (p != NULL) 158359283Seric { 158459283Seric *p++ = '\0'; 158559283Seric MaxMessageSize = atol(p); 158659283Seric } 158758082Seric MinBlocksFree = atol(val); 158858082Seric break; 158958082Seric 15909284Seric case 'c': /* don't connect to "expensive" mailers */ 15919381Seric NoConnect = atobool(val); 15929284Seric break; 15939284Seric 159451305Seric case 'C': /* checkpoint every N addresses */ 159551305Seric CheckpointInterval = atoi(val); 159624944Seric break; 159724944Seric 15989284Seric case 'd': /* delivery mode */ 15999284Seric switch (*val) 16008269Seric { 16019284Seric case '\0': 160258734Seric e->e_sendmode = SM_DELIVER; 16038269Seric break; 16048269Seric 160510755Seric case SM_QUEUE: /* queue only */ 160610755Seric #ifndef QUEUE 160710755Seric syserr("need QUEUE to set -odqueue"); 160856795Seric #endif /* QUEUE */ 160910755Seric /* fall through..... */ 161010755Seric 16119284Seric case SM_DELIVER: /* do everything */ 16129284Seric case SM_FORK: /* fork after verification */ 161358734Seric e->e_sendmode = *val; 16148269Seric break; 16158269Seric 16168269Seric default: 16179284Seric syserr("Unknown delivery mode %c", *val); 16188269Seric exit(EX_USAGE); 16198269Seric } 16208269Seric break; 16218269Seric 16229146Seric case 'D': /* rebuild alias database as needed */ 16239381Seric AutoRebuild = atobool(val); 16249146Seric break; 16259146Seric 162655372Seric case 'E': /* error message header/header file */ 162755379Seric if (*val != '\0') 162855379Seric ErrMsgFile = newstr(val); 162955372Seric break; 163055372Seric 16318269Seric case 'e': /* set error processing mode */ 16328269Seric switch (*val) 16338269Seric { 16349381Seric case EM_QUIET: /* be silent about it */ 16359381Seric case EM_MAIL: /* mail back */ 16369381Seric case EM_BERKNET: /* do berknet error processing */ 16379381Seric case EM_WRITE: /* write back (or mail) */ 16389381Seric case EM_PRINT: /* print errors normally (default) */ 163958734Seric e->e_errormode = *val; 16408269Seric break; 16418269Seric } 16428269Seric break; 16438269Seric 16449049Seric case 'F': /* file mode */ 164517975Seric FileMode = atooct(val) & 0777; 16469049Seric break; 16479049Seric 16488269Seric case 'f': /* save Unix-style From lines on front */ 16499381Seric SaveFrom = atobool(val); 16508269Seric break; 16518269Seric 165253735Seric case 'G': /* match recipients against GECOS field */ 165353735Seric MatchGecos = atobool(val); 165453735Seric break; 165553735Seric 16568256Seric case 'g': /* default gid */ 165768481Seric g_opt: 165864133Seric if (isascii(*val) && isdigit(*val)) 165964133Seric DefGid = atoi(val); 166064133Seric else 166164133Seric { 166264133Seric register struct group *gr; 166364133Seric 166464133Seric DefGid = -1; 166564133Seric gr = getgrnam(val); 166664133Seric if (gr == NULL) 166768481Seric syserr("readcf: option %c: unknown group %s", 166868481Seric opt, val); 166964133Seric else 167064133Seric DefGid = gr->gr_gid; 167164133Seric } 16728256Seric break; 16738256Seric 16748256Seric case 'H': /* help file */ 16759381Seric if (val[0] == '\0') 16768269Seric HelpFile = "sendmail.hf"; 16779381Seric else 16789381Seric HelpFile = newstr(val); 16798256Seric break; 16808256Seric 168151305Seric case 'h': /* maximum hop count */ 168251305Seric MaxHopCount = atoi(val); 168351305Seric break; 168451305Seric 168535651Seric case 'I': /* use internet domain name server */ 168666334Seric #if NAMED_BIND 168757207Seric for (p = val; *p != 0; ) 168857207Seric { 168957207Seric bool clearmode; 169057207Seric char *q; 169157207Seric struct resolverflags *rfp; 169257207Seric 169357207Seric while (*p == ' ') 169457207Seric p++; 169557207Seric if (*p == '\0') 169657207Seric break; 169757207Seric clearmode = FALSE; 169857207Seric if (*p == '-') 169957207Seric clearmode = TRUE; 170057207Seric else if (*p != '+') 170157207Seric p--; 170257207Seric p++; 170357207Seric q = p; 170458050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 170557207Seric p++; 170657207Seric if (*p != '\0') 170757207Seric *p++ = '\0'; 170868759Seric if (strcasecmp(q, "HasWildcardMX") == 0) 170968759Seric { 171068759Seric NoMXforCanon = !clearmode; 171168759Seric continue; 171268759Seric } 171357207Seric for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 171457207Seric { 171557207Seric if (strcasecmp(q, rfp->rf_name) == 0) 171657207Seric break; 171757207Seric } 171864923Seric if (rfp->rf_name == NULL) 171964923Seric syserr("readcf: I option value %s unrecognized", q); 172064923Seric else if (clearmode) 172157207Seric _res.options &= ~rfp->rf_bits; 172257207Seric else 172357207Seric _res.options |= rfp->rf_bits; 172457207Seric } 172557207Seric if (tTd(8, 2)) 172668759Seric printf("_res.options = %x, HasWildcardMX = %d\n", 172768759Seric _res.options, !NoMXforCanon); 172857207Seric #else 172957207Seric usrerr("name server (I option) specified but BIND not compiled in"); 173057207Seric #endif 173135651Seric break; 173235651Seric 17338269Seric case 'i': /* ignore dot lines in message */ 17349381Seric IgnrDot = atobool(val); 17358269Seric break; 17368269Seric 173759730Seric case 'j': /* send errors in MIME (RFC 1341) format */ 173859730Seric SendMIMEErrors = atobool(val); 173959730Seric break; 174059730Seric 174157136Seric case 'J': /* .forward search path */ 174257136Seric ForwardPath = newstr(val); 174357136Seric break; 174457136Seric 174554967Seric case 'k': /* connection cache size */ 174654967Seric MaxMciCache = atoi(val); 174756215Seric if (MaxMciCache < 0) 174856215Seric MaxMciCache = 0; 174954967Seric break; 175054967Seric 175154967Seric case 'K': /* connection cache timeout */ 175258796Seric MciCacheTimeout = convtime(val, 'm'); 175354967Seric break; 175454967Seric 175561104Seric case 'l': /* use Errors-To: header */ 175661104Seric UseErrorsTo = atobool(val); 175761104Seric break; 175861104Seric 17598256Seric case 'L': /* log level */ 176064140Seric if (safe || LogLevel < atoi(val)) 176164140Seric LogLevel = atoi(val); 17628256Seric break; 17638256Seric 17648269Seric case 'M': /* define macro */ 176568267Seric p = newstr(&val[1]); 176668267Seric if (!safe) 176768267Seric cleanstrcpy(p, p, MAXNAME); 176868267Seric define(val[0], p, CurEnv); 176916878Seric sticky = FALSE; 17708269Seric break; 17718269Seric 17728269Seric case 'm': /* send to me too */ 17739381Seric MeToo = atobool(val); 17748269Seric break; 17758269Seric 177625820Seric case 'n': /* validate RHS in newaliases */ 177725820Seric CheckAliases = atobool(val); 177825820Seric break; 177925820Seric 178061104Seric /* 'N' available -- was "net name" */ 178161104Seric 178258851Seric case 'O': /* daemon options */ 178358851Seric setdaemonoptions(val); 178458851Seric break; 178558851Seric 17868269Seric case 'o': /* assume old style headers */ 17879381Seric if (atobool(val)) 17889341Seric CurEnv->e_flags |= EF_OLDSTYLE; 17899341Seric else 17909341Seric CurEnv->e_flags &= ~EF_OLDSTYLE; 17918269Seric break; 17928269Seric 179358082Seric case 'p': /* select privacy level */ 179458082Seric p = val; 179558082Seric for (;;) 179658082Seric { 179758082Seric register struct prival *pv; 179858082Seric extern struct prival PrivacyValues[]; 179958082Seric 180058082Seric while (isascii(*p) && (isspace(*p) || ispunct(*p))) 180158082Seric p++; 180258082Seric if (*p == '\0') 180358082Seric break; 180458082Seric val = p; 180558082Seric while (isascii(*p) && isalnum(*p)) 180658082Seric p++; 180758082Seric if (*p != '\0') 180858082Seric *p++ = '\0'; 180958082Seric 181058082Seric for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 181158082Seric { 181258082Seric if (strcasecmp(val, pv->pv_name) == 0) 181358082Seric break; 181458082Seric } 181558886Seric if (pv->pv_name == NULL) 181658886Seric syserr("readcf: Op line: %s unrecognized", val); 181758082Seric PrivacyFlags |= pv->pv_flag; 181858082Seric } 181968479Seric sticky = FALSE; 182058082Seric break; 182158082Seric 182224944Seric case 'P': /* postmaster copy address for returned mail */ 182324944Seric PostMasterCopy = newstr(val); 182424944Seric break; 182524944Seric 182624944Seric case 'q': /* slope of queue only function */ 182724944Seric QueueFactor = atoi(val); 182824944Seric break; 182924944Seric 18308256Seric case 'Q': /* queue directory */ 18319381Seric if (val[0] == '\0') 18328269Seric QueueDir = "mqueue"; 18339381Seric else 18349381Seric QueueDir = newstr(val); 183558789Seric if (RealUid != 0 && !safe) 183664718Seric Warn_Q_option = TRUE; 18378256Seric break; 18388256Seric 183958148Seric case 'R': /* don't prune routes */ 184058148Seric DontPruneRoutes = atobool(val); 184158148Seric break; 184258148Seric 18438256Seric case 'r': /* read timeout */ 184468481Seric if (subopt == NULL) 184568481Seric inittimeouts(val); 184668481Seric else 184768481Seric settimeout(subopt, val); 18488256Seric break; 18498256Seric 18508256Seric case 'S': /* status file */ 18519381Seric if (val[0] == '\0') 18528269Seric StatFile = "sendmail.st"; 18539381Seric else 18549381Seric StatFile = newstr(val); 18558256Seric break; 18568256Seric 18578265Seric case 's': /* be super safe, even if expensive */ 18589381Seric SuperSafe = atobool(val); 18598256Seric break; 18608256Seric 18618256Seric case 'T': /* queue timeout */ 186258737Seric p = strchr(val, '/'); 186358737Seric if (p != NULL) 186458737Seric { 186558737Seric *p++ = '\0'; 186668481Seric settimeout("queuewarn", p); 186758737Seric } 186868481Seric settimeout("queuereturn", val); 186954967Seric break; 18708256Seric 18718265Seric case 't': /* time zone name */ 187252106Seric TimeZoneSpec = newstr(val); 18738265Seric break; 18748265Seric 187550556Seric case 'U': /* location of user database */ 187651360Seric UdbSpec = newstr(val); 187750556Seric break; 187850556Seric 18798256Seric case 'u': /* set default uid */ 188068481Seric for (p = val; *p != '\0'; p++) 188168481Seric { 188268481Seric if (*p == '.' || *p == '/' || *p == ':') 188368481Seric { 188468481Seric *p++ = '\0'; 188568481Seric break; 188668481Seric } 188768481Seric } 188864133Seric if (isascii(*val) && isdigit(*val)) 188964133Seric DefUid = atoi(val); 189064133Seric else 189164133Seric { 189264133Seric register struct passwd *pw; 189364133Seric 189464133Seric DefUid = -1; 189568693Seric pw = sm_getpwnam(val); 189664133Seric if (pw == NULL) 189764133Seric syserr("readcf: option u: unknown user %s", val); 189864133Seric else 189968481Seric { 190064133Seric DefUid = pw->pw_uid; 190168481Seric DefGid = pw->pw_gid; 190268481Seric } 190364133Seric } 190440973Sbostic setdefuser(); 19058256Seric 190668481Seric /* handle the group if it is there */ 190768481Seric if (*p == '\0') 190868481Seric break; 190968481Seric val = p; 191068481Seric goto g_opt; 191168481Seric 191258851Seric case 'V': /* fallback MX host */ 191358851Seric FallBackMX = newstr(val); 191458851Seric break; 191558851Seric 19168269Seric case 'v': /* run in verbose mode */ 19179381Seric Verbose = atobool(val); 19188256Seric break; 19198256Seric 192063837Seric case 'w': /* if we are best MX, try host directly */ 192163837Seric TryNullMXList = atobool(val); 192263837Seric break; 192361104Seric 192461104Seric /* 'W' available -- was wizard password */ 192561104Seric 192614879Seric case 'x': /* load avg at which to auto-queue msgs */ 192714879Seric QueueLA = atoi(val); 192814879Seric break; 192914879Seric 193014879Seric case 'X': /* load avg at which to auto-reject connections */ 193114879Seric RefuseLA = atoi(val); 193214879Seric break; 193314879Seric 193424981Seric case 'y': /* work recipient factor */ 193524981Seric WkRecipFact = atoi(val); 193624981Seric break; 193724981Seric 193824981Seric case 'Y': /* fork jobs during queue runs */ 193924952Seric ForkQueueRuns = atobool(val); 194024952Seric break; 194124952Seric 194224981Seric case 'z': /* work message class factor */ 194324981Seric WkClassFact = atoi(val); 194424981Seric break; 194524981Seric 194624981Seric case 'Z': /* work time factor */ 194724981Seric WkTimeFact = atoi(val); 194824981Seric break; 194924981Seric 195068481Seric case O_QUEUESORTORD: /* queue sorting order */ 195168481Seric switch (*val) 195268481Seric { 195368481Seric case 'h': /* Host first */ 195468481Seric case 'H': 195568481Seric QueueSortOrder = QS_BYHOST; 195668481Seric break; 195768481Seric 195868481Seric case 'p': /* Priority order */ 195968481Seric case 'P': 196068481Seric QueueSortOrder = QS_BYPRIORITY; 196168481Seric break; 196268481Seric 196368481Seric default: 196468481Seric syserr("Invalid queue sort order \"%s\"", val); 196568481Seric } 196668481Seric break; 196768481Seric 196869401Seric case O_HOSTSFILE: /* pathname of /etc/hosts file */ 196969401Seric HostsFile = newstr(val); 197069401Seric break; 197169401Seric 197268481Seric case O_MQA: /* minimum queue age between deliveries */ 197368481Seric MinQueueAge = convtime(val, 'm'); 197468481Seric break; 197568481Seric 197668481Seric case O_MHSA: /* maximum age of cached host status */ 197768481Seric MaxHostStatAge = convtime(val, 'm'); 197868481Seric break; 197968481Seric 198068481Seric case O_DEFCHARSET: /* default character set for mimefying */ 198168481Seric DefaultCharSet = newstr(denlstring(val, TRUE, TRUE)); 198268481Seric break; 198368481Seric 198468481Seric case O_SSFILE: /* service switch file */ 198568481Seric ServiceSwitchFile = newstr(val); 198668481Seric break; 198768481Seric 198868481Seric case O_DIALDELAY: /* delay for dial-on-demand operation */ 198968481Seric DialDelay = convtime(val, 's'); 199068481Seric break; 199168481Seric 199268481Seric case O_NORCPTACTION: /* what to do if no recipient */ 199368481Seric if (strcasecmp(val, "none") == 0) 199468481Seric NoRecipientAction = NRA_NO_ACTION; 199568481Seric else if (strcasecmp(val, "add-to") == 0) 199668481Seric NoRecipientAction = NRA_ADD_TO; 199768481Seric else if (strcasecmp(val, "add-apparently-to") == 0) 199868481Seric NoRecipientAction = NRA_ADD_APPARENTLY_TO; 199968481Seric else if (strcasecmp(val, "add-bcc") == 0) 200068481Seric NoRecipientAction = NRA_ADD_BCC; 200168481Seric else if (strcasecmp(val, "add-to-undisclosed") == 0) 200268481Seric NoRecipientAction = NRA_ADD_TO_UNDISCLOSED; 200368481Seric else 200468481Seric syserr("Invalid NoRecipientAction: %s", val); 200568481Seric 200668490Seric case O_SAFEFILEENV: /* chroot() environ for writing to files */ 200768490Seric SafeFileEnv = newstr(val); 200868490Seric break; 200968490Seric 201068569Seric case O_MAXMSGSIZE: /* maximum message size */ 201168569Seric MaxMessageSize = atol(p); 201268569Seric break; 201368569Seric 201468756Seric case O_COLONOKINADDR: /* old style handling of colon addresses */ 201568756Seric ColonOkInAddr = atobool(p); 201668756Seric break; 201768756Seric 2018*69724Seric case O_MAXQUEUERUN: /* max # of jobs in a single queue run */ 2019*69724Seric MaxQueueRun = atol(p); 2020*69724Seric break; 2021*69724Seric 20228256Seric default: 202368481Seric if (tTd(37, 1)) 202468481Seric { 202568481Seric if (isascii(opt) && isprint(opt)) 202668481Seric printf("Warning: option %c unknown\n", opt); 202768481Seric else 202868481Seric printf("Warning: option 0x%x unknown\n", opt); 202968481Seric } 20308256Seric break; 20318256Seric } 203216878Seric if (sticky) 203316878Seric setbitn(opt, StickyOpt); 20349188Seric return; 20358256Seric } 203610687Seric /* 203768481Seric ** SETCLASS -- set a string into a class 203810687Seric ** 203910687Seric ** Parameters: 204068481Seric ** class -- the class to put the string in. 204168481Seric ** str -- the string to enter 204210687Seric ** 204310687Seric ** Returns: 204410687Seric ** none. 204510687Seric ** 204610687Seric ** Side Effects: 204710687Seric ** puts the word into the symbol table. 204810687Seric */ 204910687Seric 205068481Seric setclass(class, str) 205110687Seric int class; 205268481Seric char *str; 205310687Seric { 205410687Seric register STAB *s; 205510687Seric 205657943Seric if (tTd(37, 8)) 205768481Seric printf("setclass(%c, %s)\n", class, str); 205868481Seric s = stab(str, ST_CLASS, ST_ENTER); 205910687Seric setbitn(class, s->s_class); 206010687Seric } 206153654Seric /* 206253654Seric ** MAKEMAPENTRY -- create a map entry 206353654Seric ** 206453654Seric ** Parameters: 206553654Seric ** line -- the config file line 206653654Seric ** 206753654Seric ** Returns: 206853654Seric ** TRUE if it successfully entered the map entry. 206953654Seric ** FALSE otherwise (usually syntax error). 207053654Seric ** 207153654Seric ** Side Effects: 207253654Seric ** Enters the map into the dictionary. 207353654Seric */ 207453654Seric 207553654Seric void 207653654Seric makemapentry(line) 207753654Seric char *line; 207853654Seric { 207953654Seric register char *p; 208053654Seric char *mapname; 208153654Seric char *classname; 208264078Seric register STAB *s; 208353654Seric STAB *class; 208453654Seric 208558050Seric for (p = line; isascii(*p) && isspace(*p); p++) 208653654Seric continue; 208758050Seric if (!(isascii(*p) && isalnum(*p))) 208853654Seric { 208953654Seric syserr("readcf: config K line: no map name"); 209053654Seric return; 209153654Seric } 209253654Seric 209353654Seric mapname = p; 209468481Seric while ((isascii(*++p) && isalnum(*p)) || *p == '.') 209553654Seric continue; 209653654Seric if (*p != '\0') 209753654Seric *p++ = '\0'; 209858050Seric while (isascii(*p) && isspace(*p)) 209953654Seric p++; 210058050Seric if (!(isascii(*p) && isalnum(*p))) 210153654Seric { 210253654Seric syserr("readcf: config K line, map %s: no map class", mapname); 210353654Seric return; 210453654Seric } 210553654Seric classname = p; 210658050Seric while (isascii(*++p) && isalnum(*p)) 210753654Seric continue; 210853654Seric if (*p != '\0') 210953654Seric *p++ = '\0'; 211058050Seric while (isascii(*p) && isspace(*p)) 211153654Seric p++; 211253654Seric 211353654Seric /* look up the class */ 211453654Seric class = stab(classname, ST_MAPCLASS, ST_FIND); 211553654Seric if (class == NULL) 211653654Seric { 211753654Seric syserr("readcf: map %s: class %s not available", mapname, classname); 211853654Seric return; 211953654Seric } 212053654Seric 212153654Seric /* enter the map */ 212264078Seric s = stab(mapname, ST_MAP, ST_ENTER); 212364078Seric s->s_map.map_class = &class->s_mapclass; 212464078Seric s->s_map.map_mname = newstr(mapname); 212553654Seric 212664078Seric if (class->s_mapclass.map_parse(&s->s_map, p)) 212764078Seric s->s_map.map_mflags |= MF_VALID; 212864078Seric 212964078Seric if (tTd(37, 5)) 213064078Seric { 213164078Seric printf("map %s, class %s, flags %x, file %s,\n", 213264078Seric s->s_map.map_mname, s->s_map.map_class->map_cname, 213364078Seric s->s_map.map_mflags, 213464078Seric s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 213564078Seric printf("\tapp %s, domain %s, rebuild %s\n", 213664078Seric s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 213764078Seric s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 213864078Seric s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 213964078Seric } 214053654Seric } 214158112Seric /* 214268481Seric ** INITTIMEOUTS -- parse and set timeout values 214358112Seric ** 214458112Seric ** Parameters: 214558112Seric ** val -- a pointer to the values. If NULL, do initial 214658112Seric ** settings. 214758112Seric ** 214858112Seric ** Returns: 214958112Seric ** none. 215058112Seric ** 215158112Seric ** Side Effects: 215258112Seric ** Initializes the TimeOuts structure 215358112Seric */ 215458112Seric 215564255Seric #define SECONDS 215658112Seric #define MINUTES * 60 215758112Seric #define HOUR * 3600 215858112Seric 215968481Seric inittimeouts(val) 216058112Seric register char *val; 216158112Seric { 216258112Seric register char *p; 216358671Seric extern time_t convtime(); 216458112Seric 216558112Seric if (val == NULL) 216658112Seric { 216758112Seric TimeOuts.to_initial = (time_t) 5 MINUTES; 216858112Seric TimeOuts.to_helo = (time_t) 5 MINUTES; 216958112Seric TimeOuts.to_mail = (time_t) 10 MINUTES; 217058112Seric TimeOuts.to_rcpt = (time_t) 1 HOUR; 217158112Seric TimeOuts.to_datainit = (time_t) 5 MINUTES; 217258112Seric TimeOuts.to_datablock = (time_t) 1 HOUR; 217358112Seric TimeOuts.to_datafinal = (time_t) 1 HOUR; 217458112Seric TimeOuts.to_rset = (time_t) 5 MINUTES; 217558112Seric TimeOuts.to_quit = (time_t) 2 MINUTES; 217658112Seric TimeOuts.to_nextcommand = (time_t) 1 HOUR; 217758112Seric TimeOuts.to_miscshort = (time_t) 2 MINUTES; 217868481Seric #if IDENTPROTO 217964255Seric TimeOuts.to_ident = (time_t) 30 SECONDS; 218068481Seric #else 218168481Seric TimeOuts.to_ident = (time_t) 0 SECONDS; 218268481Seric #endif 218368481Seric TimeOuts.to_fileopen = (time_t) 60 SECONDS; 218458112Seric return; 218558112Seric } 218658112Seric 218758112Seric for (;; val = p) 218858112Seric { 218958112Seric while (isascii(*val) && isspace(*val)) 219058112Seric val++; 219158112Seric if (*val == '\0') 219258112Seric break; 219358112Seric for (p = val; *p != '\0' && *p != ','; p++) 219458112Seric continue; 219558112Seric if (*p != '\0') 219658112Seric *p++ = '\0'; 219758112Seric 219858112Seric if (isascii(*val) && isdigit(*val)) 219958112Seric { 220058112Seric /* old syntax -- set everything */ 220158796Seric TimeOuts.to_mail = convtime(val, 'm'); 220258112Seric TimeOuts.to_rcpt = TimeOuts.to_mail; 220358112Seric TimeOuts.to_datainit = TimeOuts.to_mail; 220458112Seric TimeOuts.to_datablock = TimeOuts.to_mail; 220558112Seric TimeOuts.to_datafinal = TimeOuts.to_mail; 220658112Seric TimeOuts.to_nextcommand = TimeOuts.to_mail; 220758112Seric continue; 220858112Seric } 220958112Seric else 221058112Seric { 221168481Seric register char *q = strchr(val, ':'); 221258112Seric 221368481Seric if (q == NULL && (q = strchr(val, '=')) == NULL) 221458112Seric { 221558112Seric /* syntax error */ 221658112Seric continue; 221758112Seric } 221858112Seric *q++ = '\0'; 221968481Seric settimeout(val, q); 222068481Seric } 222168481Seric } 222268481Seric } 222368481Seric /* 222468481Seric ** SETTIMEOUT -- set an individual timeout 222568481Seric ** 222668481Seric ** Parameters: 222768481Seric ** name -- the name of the timeout. 222868481Seric ** val -- the value of the timeout. 222968481Seric ** 223068481Seric ** Returns: 223168481Seric ** none. 223268481Seric */ 223358112Seric 223468481Seric settimeout(name, val) 223568481Seric char *name; 223668481Seric char *val; 223768481Seric { 223868481Seric register char *p; 223968481Seric time_t to; 224068481Seric extern time_t convtime(); 224168481Seric 224268481Seric to = convtime(val, 'm'); 224368481Seric p = strchr(name, '.'); 224468481Seric if (p != NULL) 224568481Seric *p++ = '\0'; 224668481Seric 224768481Seric if (strcasecmp(name, "initial") == 0) 224868481Seric TimeOuts.to_initial = to; 224968481Seric else if (strcasecmp(name, "mail") == 0) 225068481Seric TimeOuts.to_mail = to; 225168481Seric else if (strcasecmp(name, "rcpt") == 0) 225268481Seric TimeOuts.to_rcpt = to; 225368481Seric else if (strcasecmp(name, "datainit") == 0) 225468481Seric TimeOuts.to_datainit = to; 225568481Seric else if (strcasecmp(name, "datablock") == 0) 225668481Seric TimeOuts.to_datablock = to; 225768481Seric else if (strcasecmp(name, "datafinal") == 0) 225868481Seric TimeOuts.to_datafinal = to; 225968481Seric else if (strcasecmp(name, "command") == 0) 226068481Seric TimeOuts.to_nextcommand = to; 226168481Seric else if (strcasecmp(name, "rset") == 0) 226268481Seric TimeOuts.to_rset = to; 226368481Seric else if (strcasecmp(name, "helo") == 0) 226468481Seric TimeOuts.to_helo = to; 226568481Seric else if (strcasecmp(name, "quit") == 0) 226668481Seric TimeOuts.to_quit = to; 226768481Seric else if (strcasecmp(name, "misc") == 0) 226868481Seric TimeOuts.to_miscshort = to; 226968481Seric else if (strcasecmp(name, "ident") == 0) 227068481Seric TimeOuts.to_ident = to; 227168481Seric else if (strcasecmp(name, "fileopen") == 0) 227268481Seric TimeOuts.to_fileopen = to; 227368481Seric else if (strcasecmp(name, "queuewarn") == 0) 227468481Seric { 227568481Seric to = convtime(val, 'h'); 227668481Seric if (p == NULL || strcmp(p, "*") == 0) 227768481Seric { 227868481Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 227968481Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 228068481Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 228158112Seric } 228268481Seric else if (strcasecmp(p, "normal") == 0) 228368481Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 228468481Seric else if (strcasecmp(p, "urgent") == 0) 228568481Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 228668481Seric else if (strcasecmp(p, "non-urgent") == 0) 228768481Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 228868481Seric else 228968481Seric syserr("settimeout: invalid queuewarn subtimeout %s", p); 229058112Seric } 229168481Seric else if (strcasecmp(name, "queuereturn") == 0) 229268481Seric { 229368481Seric to = convtime(val, 'd'); 229468481Seric if (p == NULL || strcmp(p, "*") == 0) 229568481Seric { 229668481Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 229768481Seric TimeOuts.to_q_return[TOC_URGENT] = to; 229868481Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 229968481Seric } 230068481Seric else if (strcasecmp(p, "normal") == 0) 230168481Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 230268481Seric else if (strcasecmp(p, "urgent") == 0) 230368481Seric TimeOuts.to_q_return[TOC_URGENT] = to; 230468481Seric else if (strcasecmp(p, "non-urgent") == 0) 230568481Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 230668481Seric else 230768481Seric syserr("settimeout: invalid queuereturn subtimeout %s", p); 230868481Seric } 230968481Seric else 231068481Seric syserr("settimeout: invalid timeout %s", name); 231158112Seric } 2312