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*69748Seric static char sccsid[] = "@(#)readcf.c 8.95 (Berkeley) 05/28/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 66*69748Seric void 6755012Seric readcf(cfname, safe, e) 683308Seric char *cfname; 6954973Seric bool safe; 7055012Seric register ENVELOPE *e; 713308Seric { 723308Seric FILE *cf; 738547Seric int ruleset = 0; 7468481Seric int nextruleset = MAXRWSETS; 758547Seric char *q; 769350Seric struct rewrite *rwp = NULL; 7757135Seric char *bp; 7864718Seric auto char *ep; 7957589Seric int nfuzzy; 8064133Seric char *file; 8164133Seric bool optional; 8268481Seric int mid; 833308Seric char buf[MAXLINE]; 843308Seric register char *p; 853308Seric extern char **copyplist(); 8652647Seric struct stat statb; 875909Seric char exbuf[MAXLINE]; 8865066Seric char pvpbuf[MAXLINE + MAXATOM]; 8968481Seric static char *null_list[1] = { NULL }; 90*69748Seric extern char *munchstring __P((char *, char **)); 91*69748Seric extern void fileclass __P((int, char *, char *, bool, bool)); 92*69748Seric extern void toomany __P((int, int)); 933308Seric 9452647Seric FileName = cfname; 9552647Seric LineNumber = 0; 9652647Seric 973308Seric cf = fopen(cfname, "r"); 983308Seric if (cf == NULL) 993308Seric { 10052647Seric syserr("cannot open"); 1013308Seric exit(EX_OSFILE); 1023308Seric } 1033308Seric 10452647Seric if (fstat(fileno(cf), &statb) < 0) 10552647Seric { 10652647Seric syserr("cannot fstat"); 10752647Seric exit(EX_OSFILE); 10852647Seric } 10952647Seric 11052647Seric if (!S_ISREG(statb.st_mode)) 11152647Seric { 11252647Seric syserr("not a plain file"); 11352647Seric exit(EX_OSFILE); 11452647Seric } 11552647Seric 11652647Seric if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode)) 11752647Seric { 11869686Seric if (OpMode == MD_DAEMON || OpMode == MD_INITALIAS) 11953037Seric fprintf(stderr, "%s: WARNING: dangerous write permissions\n", 12053037Seric FileName); 12153037Seric #ifdef LOG 12253037Seric if (LogLevel > 0) 12353037Seric syslog(LOG_CRIT, "%s: WARNING: dangerous write permissions", 12453037Seric FileName); 12553037Seric #endif 12652647Seric } 12752647Seric 12859254Seric #ifdef XLA 12959254Seric xla_zero(); 13059254Seric #endif 13159254Seric 13257135Seric while ((bp = fgetfolded(buf, sizeof buf, cf)) != NULL) 1333308Seric { 13457135Seric if (bp[0] == '#') 13557135Seric { 13657135Seric if (bp != buf) 13757135Seric free(bp); 13852637Seric continue; 13957135Seric } 14052637Seric 14168481Seric /* do macro expansion mappings */ 14257135Seric for (p = bp; *p != '\0'; p++) 14316157Seric { 14457135Seric if (*p == '#' && p > bp && ConfigLevel >= 3) 14552647Seric { 14652647Seric /* this is an on-line comment */ 14752647Seric register char *e; 14852647Seric 14958050Seric switch (*--p & 0377) 15052647Seric { 15158050Seric case MACROEXPAND: 15252647Seric /* it's from $# -- let it go through */ 15352647Seric p++; 15452647Seric break; 15552647Seric 15652647Seric case '\\': 15752647Seric /* it's backslash escaped */ 15852647Seric (void) strcpy(p, p + 1); 15952647Seric break; 16052647Seric 16152647Seric default: 16252647Seric /* delete preceeding white space */ 16358050Seric while (isascii(*p) && isspace(*p) && p > bp) 16452647Seric p--; 16556795Seric if ((e = strchr(++p, '\n')) != NULL) 16652647Seric (void) strcpy(p, e); 16752647Seric else 16852647Seric p[0] = p[1] = '\0'; 16952647Seric break; 17052647Seric } 17152647Seric continue; 17252647Seric } 17352647Seric 17468481Seric if (*p != '$' || p[1] == '\0') 17516157Seric continue; 17616157Seric 17716157Seric if (p[1] == '$') 17816157Seric { 17916157Seric /* actual dollar sign.... */ 18023111Seric (void) strcpy(p, p + 1); 18116157Seric continue; 18216157Seric } 18316157Seric 18416157Seric /* convert to macro expansion character */ 18568481Seric *p++ = MACROEXPAND; 18668481Seric 18768481Seric /* convert macro name to code */ 18868481Seric *p = macid(p, &ep); 18968481Seric if (ep != p) 19068481Seric strcpy(p + 1, ep); 19116157Seric } 19216157Seric 19316157Seric /* interpret this line */ 19464718Seric errno = 0; 19557135Seric switch (bp[0]) 1963308Seric { 1973308Seric case '\0': 1983308Seric case '#': /* comment */ 1993308Seric break; 2003308Seric 2013308Seric case 'R': /* rewriting rule */ 20257135Seric for (p = &bp[1]; *p != '\0' && *p != '\t'; p++) 2033308Seric continue; 2043308Seric 2053308Seric if (*p == '\0') 2065909Seric { 20765821Seric syserr("invalid rewrite line \"%s\" (tab expected)", bp); 2085909Seric break; 2095909Seric } 2105909Seric 2115909Seric /* allocate space for the rule header */ 2125909Seric if (rwp == NULL) 2135909Seric { 2145909Seric RewriteRules[ruleset] = rwp = 2155909Seric (struct rewrite *) xalloc(sizeof *rwp); 2165909Seric } 2173308Seric else 2183308Seric { 2195909Seric rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp); 2205909Seric rwp = rwp->r_next; 2215909Seric } 2225909Seric rwp->r_next = NULL; 2233308Seric 2245909Seric /* expand and save the LHS */ 2255909Seric *p = '\0'; 22668529Seric expand(&bp[1], exbuf, sizeof exbuf, e); 22765066Seric rwp->r_lhs = prescan(exbuf, '\t', pvpbuf, 22868711Seric sizeof pvpbuf, NULL, NULL); 22957589Seric nfuzzy = 0; 2305909Seric if (rwp->r_lhs != NULL) 23157589Seric { 23257589Seric register char **ap; 23357589Seric 2345909Seric rwp->r_lhs = copyplist(rwp->r_lhs, TRUE); 23557589Seric 23657589Seric /* count the number of fuzzy matches in LHS */ 23757589Seric for (ap = rwp->r_lhs; *ap != NULL; ap++) 23857589Seric { 23958148Seric char *botch; 24058148Seric 24158148Seric botch = NULL; 24258050Seric switch (**ap & 0377) 24357589Seric { 24457589Seric case MATCHZANY: 24557589Seric case MATCHANY: 24657589Seric case MATCHONE: 24757589Seric case MATCHCLASS: 24857589Seric case MATCHNCLASS: 24957589Seric nfuzzy++; 25058148Seric break; 25158148Seric 25258148Seric case MATCHREPL: 25358148Seric botch = "$0-$9"; 25458148Seric break; 25558148Seric 25658148Seric case CANONNET: 25758148Seric botch = "$#"; 25858148Seric break; 25958148Seric 26058148Seric case CANONUSER: 26158148Seric botch = "$:"; 26258148Seric break; 26358148Seric 26458148Seric case CALLSUBR: 26558148Seric botch = "$>"; 26658148Seric break; 26758148Seric 26858148Seric case CONDIF: 26958148Seric botch = "$?"; 27058148Seric break; 27158148Seric 27258148Seric case CONDELSE: 27358148Seric botch = "$|"; 27458148Seric break; 27558148Seric 27658148Seric case CONDFI: 27758148Seric botch = "$."; 27858148Seric break; 27958148Seric 28058148Seric case HOSTBEGIN: 28158148Seric botch = "$["; 28258148Seric break; 28358148Seric 28458148Seric case HOSTEND: 28558148Seric botch = "$]"; 28658148Seric break; 28758148Seric 28858148Seric case LOOKUPBEGIN: 28958148Seric botch = "$("; 29058148Seric break; 29158148Seric 29258148Seric case LOOKUPEND: 29358148Seric botch = "$)"; 29458148Seric break; 29557589Seric } 29658148Seric if (botch != NULL) 29758148Seric syserr("Inappropriate use of %s on LHS", 29858148Seric botch); 29957589Seric } 30057589Seric } 30156678Seric else 30268481Seric { 30356678Seric syserr("R line: null LHS"); 30468481Seric rwp->r_lhs = null_list; 30568481Seric } 3065909Seric 3075909Seric /* expand and save the RHS */ 3085909Seric while (*++p == '\t') 3095909Seric continue; 3107231Seric q = p; 3117231Seric while (*p != '\0' && *p != '\t') 3127231Seric p++; 3137231Seric *p = '\0'; 31468529Seric expand(q, exbuf, sizeof exbuf, e); 31565066Seric rwp->r_rhs = prescan(exbuf, '\t', pvpbuf, 31668711Seric sizeof pvpbuf, NULL, NULL); 3175909Seric if (rwp->r_rhs != NULL) 31857589Seric { 31957589Seric register char **ap; 32057589Seric 3215909Seric rwp->r_rhs = copyplist(rwp->r_rhs, TRUE); 32257589Seric 32357589Seric /* check no out-of-bounds replacements */ 32457589Seric nfuzzy += '0'; 32557589Seric for (ap = rwp->r_rhs; *ap != NULL; ap++) 32657589Seric { 32758148Seric char *botch; 32858148Seric 32958148Seric botch = NULL; 33058148Seric switch (**ap & 0377) 33157589Seric { 33258148Seric case MATCHREPL: 33358148Seric if ((*ap)[1] <= '0' || (*ap)[1] > nfuzzy) 33458148Seric { 33558148Seric syserr("replacement $%c out of bounds", 33658148Seric (*ap)[1]); 33758148Seric } 33858148Seric break; 33958148Seric 34058148Seric case MATCHZANY: 34158148Seric botch = "$*"; 34258148Seric break; 34358148Seric 34458148Seric case MATCHANY: 34558148Seric botch = "$+"; 34658148Seric break; 34758148Seric 34858148Seric case MATCHONE: 34958148Seric botch = "$-"; 35058148Seric break; 35158148Seric 35258148Seric case MATCHCLASS: 35358148Seric botch = "$="; 35458148Seric break; 35558148Seric 35658148Seric case MATCHNCLASS: 35758148Seric botch = "$~"; 35858148Seric break; 35957589Seric } 36058148Seric if (botch != NULL) 36158148Seric syserr("Inappropriate use of %s on RHS", 36258148Seric botch); 36357589Seric } 36457589Seric } 36556678Seric else 36668481Seric { 36756678Seric syserr("R line: null RHS"); 36868481Seric rwp->r_rhs = null_list; 36968481Seric } 3703308Seric break; 3713308Seric 3724072Seric case 'S': /* select rewriting set */ 37364440Seric for (p = &bp[1]; isascii(*p) && isspace(*p); p++) 37464440Seric continue; 37568481Seric if (!isascii(*p)) 37664440Seric { 37764440Seric syserr("invalid argument to S line: \"%.20s\"", 37864440Seric &bp[1]); 37964440Seric break; 38064440Seric } 38168481Seric if (isdigit(*p)) 3828056Seric { 38368481Seric ruleset = atoi(p); 38468481Seric if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 38568481Seric { 38668481Seric syserr("bad ruleset %d (%d max)", 38768481Seric ruleset, MAXRWSETS / 2); 38868481Seric ruleset = 0; 38968481Seric } 3908056Seric } 39168481Seric else 39268481Seric { 39368481Seric STAB *s; 39468481Seric char delim; 39568481Seric 39668481Seric q = p; 39768481Seric while (*p != '\0' && isascii(*p) && 39868481Seric (isalnum(*p) || strchr("-_$", *p) != NULL)) 39968481Seric p++; 40068481Seric while (isascii(*p) && isspace(*p)) 40168481Seric *p++ = '\0'; 40268481Seric delim = *p; 40368481Seric if (delim != '\0') 40468481Seric *p++ = '\0'; 40568481Seric s = stab(q, ST_RULESET, ST_ENTER); 40668481Seric if (s->s_ruleset != 0) 40768481Seric ruleset = s->s_ruleset; 40868481Seric else if (delim == '=') 40968481Seric { 41068481Seric ruleset = atoi(p); 41168481Seric if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 41268481Seric { 41368481Seric syserr("bad ruleset %s = %d (%d max)", 41468481Seric q, ruleset, MAXRWSETS / 2); 41568481Seric ruleset = 0; 41668481Seric } 41768481Seric } 41868481Seric else if ((ruleset = --nextruleset) < MAXRWSETS / 2) 41968481Seric { 42068481Seric syserr("%s: too many named rulesets (%d max)", 42168481Seric q, MAXRWSETS / 2); 42268481Seric ruleset = 0; 42368481Seric } 42468481Seric s->s_ruleset = ruleset; 42568481Seric } 4264072Seric rwp = NULL; 4274072Seric break; 4284072Seric 4293308Seric case 'D': /* macro definition */ 43068481Seric mid = macid(&bp[1], &ep); 43168481Seric p = munchstring(ep, NULL); 43268481Seric define(mid, newstr(p), e); 4333308Seric break; 4343308Seric 4353387Seric case 'H': /* required header line */ 43668717Seric (void) chompheader(&bp[1], TRUE, NULL, e); 4373387Seric break; 4383387Seric 4394061Seric case 'C': /* word class */ 44068481Seric case 'T': /* trusted user (set class `t') */ 44168481Seric if (bp[0] == 'C') 4424061Seric { 44368481Seric mid = macid(&bp[1], &ep); 44468529Seric expand(ep, exbuf, sizeof exbuf, e); 44568481Seric p = exbuf; 44668481Seric } 44768481Seric else 44868481Seric { 44968481Seric mid = 't'; 45068481Seric p = &bp[1]; 45168481Seric } 45268481Seric while (*p != '\0') 45368481Seric { 4544061Seric register char *wd; 4554061Seric char delim; 4564061Seric 45758050Seric while (*p != '\0' && isascii(*p) && isspace(*p)) 4584061Seric p++; 4594061Seric wd = p; 46058050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 4614061Seric p++; 4624061Seric delim = *p; 4634061Seric *p = '\0'; 4644061Seric if (wd[0] != '\0') 46568481Seric setclass(mid, wd); 4664061Seric *p = delim; 4674061Seric } 4684061Seric break; 4694061Seric 47059272Seric case 'F': /* word class from file */ 47168481Seric mid = macid(&bp[1], &ep); 47268481Seric for (p = ep; isascii(*p) && isspace(*p); ) 47364133Seric p++; 47464133Seric if (p[0] == '-' && p[1] == 'o') 47564133Seric { 47664133Seric optional = TRUE; 47764133Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 47864133Seric p++; 47964133Seric while (isascii(*p) && isspace(*p)) 48068481Seric p++; 48164133Seric } 48264133Seric else 48364133Seric optional = FALSE; 48464133Seric file = p; 48564133Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 48664133Seric p++; 48759272Seric if (*p == '\0') 48859272Seric p = "%s"; 48959272Seric else 49059272Seric { 49159272Seric *p = '\0'; 49259272Seric while (isascii(*++p) && isspace(*p)) 49359272Seric continue; 49459272Seric } 49564133Seric fileclass(bp[1], file, p, safe, optional); 49659272Seric break; 49759272Seric 49859156Seric #ifdef XLA 49959156Seric case 'L': /* extended load average description */ 50059156Seric xla_init(&bp[1]); 50159156Seric break; 50259156Seric #endif 50359156Seric 5044096Seric case 'M': /* define mailer */ 50557135Seric makemailer(&bp[1]); 5064096Seric break; 5074096Seric 5088252Seric case 'O': /* set option */ 50958734Seric setoption(bp[1], &bp[2], safe, FALSE, e); 5108252Seric break; 5118252Seric 5128252Seric case 'P': /* set precedence */ 5138252Seric if (NumPriorities >= MAXPRIORITIES) 5148252Seric { 5158547Seric toomany('P', MAXPRIORITIES); 5168252Seric break; 5178252Seric } 51857135Seric for (p = &bp[1]; *p != '\0' && *p != '=' && *p != '\t'; p++) 5198252Seric continue; 5208252Seric if (*p == '\0') 5218252Seric goto badline; 5228252Seric *p = '\0'; 52357135Seric Priorities[NumPriorities].pri_name = newstr(&bp[1]); 5248252Seric Priorities[NumPriorities].pri_val = atoi(++p); 5258252Seric NumPriorities++; 5268252Seric break; 5278252Seric 52852645Seric case 'V': /* configuration syntax version */ 52964440Seric for (p = &bp[1]; isascii(*p) && isspace(*p); p++) 53064440Seric continue; 53164440Seric if (!isascii(*p) || !isdigit(*p)) 53264440Seric { 53364440Seric syserr("invalid argument to V line: \"%.20s\"", 53464440Seric &bp[1]); 53564440Seric break; 53664440Seric } 53764718Seric ConfigLevel = strtol(p, &ep, 10); 53868805Seric 53968805Seric /* 54068805Seric ** Do heuristic tweaking for back compatibility. 54168805Seric */ 54268805Seric 54364279Seric if (ConfigLevel >= 5) 54464279Seric { 54564279Seric /* level 5 configs have short name in $w */ 54664279Seric p = macvalue('w', e); 54764279Seric if (p != NULL && (p = strchr(p, '.')) != NULL) 54864279Seric *p = '\0'; 54964279Seric } 55068805Seric if (ConfigLevel >= 6) 55168805Seric { 55268805Seric ColonOkInAddr = FALSE; 55368805Seric } 55468805Seric 55568805Seric /* 55668805Seric ** Look for vendor code. 55768805Seric */ 55868805Seric 55964718Seric if (*ep++ == '/') 56064718Seric { 56164718Seric /* extract vendor code */ 56264718Seric for (p = ep; isascii(*p) && isalpha(*p); ) 56364718Seric p++; 56464718Seric *p = '\0'; 56564718Seric 56664718Seric if (!setvendor(ep)) 56764718Seric syserr("invalid V line vendor code: \"%s\"", 56864718Seric ep); 56964718Seric } 57052645Seric break; 57152645Seric 57253654Seric case 'K': 57357135Seric makemapentry(&bp[1]); 57453654Seric break; 57553654Seric 57669476Seric case 'E': 57769476Seric p = strchr(bp, '='); 57869476Seric if (p != NULL) 57969476Seric *p++ = '\0'; 58069476Seric setuserenv(&bp[1], p); 58169476Seric break; 58269476Seric 5833308Seric default: 5844061Seric badline: 58557135Seric syserr("unknown control line \"%s\"", bp); 5863308Seric } 58757135Seric if (bp != buf) 58857135Seric free(bp); 5893308Seric } 59052637Seric if (ferror(cf)) 59152637Seric { 59252647Seric syserr("I/O read error", cfname); 59352637Seric exit(EX_OSFILE); 59452637Seric } 59552637Seric fclose(cf); 5969381Seric FileName = NULL; 59756836Seric 59868481Seric /* initialize host maps from local service tables */ 59968481Seric inithostmaps(); 60068481Seric 60168481Seric /* determine if we need to do special name-server frotz */ 60267905Seric { 60368481Seric int nmaps; 60468481Seric char *maptype[MAXMAPSTACK]; 60568481Seric short mapreturn[MAXMAPACTIONS]; 60668481Seric 60768481Seric nmaps = switch_map_find("hosts", maptype, mapreturn); 60868481Seric UseNameServer = FALSE; 60968481Seric if (nmaps > 0 && nmaps <= MAXMAPSTACK) 61068481Seric { 61168481Seric register int mapno; 61268481Seric 61368481Seric for (mapno = 0; mapno < nmaps && !UseNameServer; mapno++) 61468481Seric { 61568481Seric if (strcmp(maptype[mapno], "dns") == 0) 61668481Seric UseNameServer = TRUE; 61768481Seric } 61868481Seric } 61968481Seric 62068481Seric #ifdef HESIOD 62168481Seric nmaps = switch_map_find("passwd", maptype, mapreturn); 62268481Seric UseHesiod = FALSE; 62368481Seric if (nmaps > 0 && nmaps <= MAXMAPSTACK) 62468481Seric { 62568481Seric register int mapno; 62668481Seric 62768481Seric for (mapno = 0; mapno < nmaps && !UseHesiod; mapno++) 62868481Seric { 62968481Seric if (strcmp(maptype[mapno], "hesiod") == 0) 63068481Seric UseHesiod = TRUE; 63168481Seric } 63268481Seric } 63368204Seric #endif 63467905Seric } 6354096Seric } 6364096Seric /* 6378547Seric ** TOOMANY -- signal too many of some option 6388547Seric ** 6398547Seric ** Parameters: 6408547Seric ** id -- the id of the error line 6418547Seric ** maxcnt -- the maximum possible values 6428547Seric ** 6438547Seric ** Returns: 6448547Seric ** none. 6458547Seric ** 6468547Seric ** Side Effects: 6478547Seric ** gives a syserr. 6488547Seric */ 6498547Seric 650*69748Seric void 6518547Seric toomany(id, maxcnt) 652*69748Seric int id; 6538547Seric int maxcnt; 6548547Seric { 6559381Seric syserr("too many %c lines, %d max", id, maxcnt); 6568547Seric } 6578547Seric /* 6584432Seric ** FILECLASS -- read members of a class from a file 6594432Seric ** 6604432Seric ** Parameters: 6614432Seric ** class -- class to define. 6624432Seric ** filename -- name of file to read. 6634432Seric ** fmt -- scanf string to use for match. 66464133Seric ** safe -- if set, this is a safe read. 66564133Seric ** optional -- if set, it is not an error for the file to 66664133Seric ** not exist. 6674432Seric ** 6684432Seric ** Returns: 6694432Seric ** none 6704432Seric ** 6714432Seric ** Side Effects: 6724432Seric ** 6734432Seric ** puts all lines in filename that match a scanf into 6744432Seric ** the named class. 6754432Seric */ 6764432Seric 677*69748Seric void 67864133Seric fileclass(class, filename, fmt, safe, optional) 6794432Seric int class; 6804432Seric char *filename; 6814432Seric char *fmt; 68254973Seric bool safe; 68364133Seric bool optional; 6844432Seric { 68525808Seric FILE *f; 68668513Seric int sff; 68769453Seric int pid; 68869453Seric register char *p; 6894432Seric char buf[MAXLINE]; 6904432Seric 69166101Seric if (tTd(37, 2)) 69266101Seric printf("fileclass(%s, fmt=%s)\n", filename, fmt); 69366101Seric 69466031Seric if (filename[0] == '|') 69566031Seric { 69669453Seric auto int fd; 69769453Seric int i; 69869453Seric char *argv[MAXPV + 1]; 69969453Seric 70069453Seric i = 0; 70169453Seric for (p = strtok(&filename[1], " \t"); p != NULL; p = strtok(NULL, " \t")) 70269453Seric { 70369453Seric if (i >= MAXPV) 70469453Seric break; 70569453Seric argv[i++] = p; 70669453Seric } 70769453Seric argv[i] = NULL; 70869453Seric pid = prog_open(argv, &fd, CurEnv); 70969453Seric if (pid < 0) 71069453Seric f = NULL; 71169453Seric else 71269453Seric f = fdopen(fd, "r"); 71366031Seric } 71469453Seric else 71569453Seric { 71669453Seric pid = -1; 71769453Seric sff = SFF_REGONLY; 71869453Seric if (safe) 71969453Seric sff |= SFF_OPENASROOT; 72069453Seric f = safefopen(filename, O_RDONLY, 0, sff); 72169453Seric } 72268602Seric if (f == NULL) 72354973Seric { 72468602Seric if (!optional) 72568602Seric syserr("fileclass: cannot open %s", filename); 7264432Seric return; 7274432Seric } 7284432Seric 7294432Seric while (fgets(buf, sizeof buf, f) != NULL) 7304432Seric { 73125808Seric register char *p; 73225808Seric # ifdef SCANF 7334432Seric char wordbuf[MAXNAME+1]; 7344432Seric 7354432Seric if (sscanf(buf, fmt, wordbuf) != 1) 7364432Seric continue; 73725808Seric p = wordbuf; 73856795Seric # else /* SCANF */ 73925808Seric p = buf; 74056795Seric # endif /* SCANF */ 74125808Seric 74225808Seric /* 74325808Seric ** Break up the match into words. 74425808Seric */ 74525808Seric 74625808Seric while (*p != '\0') 74725808Seric { 74825808Seric register char *q; 74925808Seric 75025808Seric /* strip leading spaces */ 75158050Seric while (isascii(*p) && isspace(*p)) 75225808Seric p++; 75325808Seric if (*p == '\0') 75425808Seric break; 75525808Seric 75625808Seric /* find the end of the word */ 75725808Seric q = p; 75858050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 75925808Seric p++; 76025808Seric if (*p != '\0') 76125808Seric *p++ = '\0'; 76225808Seric 76325808Seric /* enter the word in the symbol table */ 76466101Seric setclass(class, q); 76525808Seric } 7664432Seric } 7674432Seric 76854973Seric (void) fclose(f); 76969453Seric if (pid > 0) 77069453Seric (void) waitfor(pid); 7714432Seric } 7724432Seric /* 7734096Seric ** MAKEMAILER -- define a new mailer. 7744096Seric ** 7754096Seric ** Parameters: 77610327Seric ** line -- description of mailer. This is in labeled 77710327Seric ** fields. The fields are: 77868481Seric ** A -- the argv for this mailer 77968481Seric ** C -- the character set for MIME conversions 78068481Seric ** D -- the directory to run in 78168481Seric ** E -- the eol string 78268481Seric ** F -- the flags associated with the mailer 78368481Seric ** L -- the maximum line length 78468481Seric ** M -- the maximum message size 78568816Seric ** N -- the niceness at which to run 78668479Seric ** P -- the path to the mailer 78768481Seric ** R -- the recipient rewriting set 78868479Seric ** S -- the sender rewriting set 78968481Seric ** T -- the mailer type (for DSNs) 79068481Seric ** U -- the uid to run as 79110327Seric ** The first word is the canonical name of the mailer. 7924096Seric ** 7934096Seric ** Returns: 7944096Seric ** none. 7954096Seric ** 7964096Seric ** Side Effects: 7974096Seric ** enters the mailer into the mailer table. 7984096Seric */ 7993308Seric 800*69748Seric void 80121066Seric makemailer(line) 8024096Seric char *line; 8034096Seric { 8044096Seric register char *p; 8058067Seric register struct mailer *m; 8068067Seric register STAB *s; 8078067Seric int i; 80810327Seric char fcode; 80958020Seric auto char *endp; 8104096Seric extern int NextMailer; 81110327Seric extern char **makeargv(); 81210327Seric extern char *munchstring(); 8134096Seric 81410327Seric /* allocate a mailer and set up defaults */ 81510327Seric m = (struct mailer *) xalloc(sizeof *m); 81610327Seric bzero((char *) m, sizeof *m); 81710327Seric m->m_eol = "\n"; 81868481Seric m->m_uid = m->m_gid = 0; 81910327Seric 82010327Seric /* collect the mailer name */ 82158050Seric for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++) 82210327Seric continue; 82310327Seric if (*p != '\0') 82410327Seric *p++ = '\0'; 82510327Seric m->m_name = newstr(line); 82610327Seric 82710327Seric /* now scan through and assign info from the fields */ 82810327Seric while (*p != '\0') 82910327Seric { 83058333Seric auto char *delimptr; 83158333Seric 83258050Seric while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p)))) 83310327Seric p++; 83410327Seric 83510327Seric /* p now points to field code */ 83610327Seric fcode = *p; 83710327Seric while (*p != '\0' && *p != '=' && *p != ',') 83810327Seric p++; 83910327Seric if (*p++ != '=') 84010327Seric { 84152637Seric syserr("mailer %s: `=' expected", m->m_name); 84210327Seric return; 84310327Seric } 84458050Seric while (isascii(*p) && isspace(*p)) 84510327Seric p++; 84610327Seric 84710327Seric /* p now points to the field body */ 84858333Seric p = munchstring(p, &delimptr); 84910327Seric 85010327Seric /* install the field into the mailer struct */ 85110327Seric switch (fcode) 85210327Seric { 85310327Seric case 'P': /* pathname */ 85410327Seric m->m_mailer = newstr(p); 85510327Seric break; 85610327Seric 85710327Seric case 'F': /* flags */ 85810687Seric for (; *p != '\0'; p++) 85958050Seric if (!(isascii(*p) && isspace(*p))) 86052637Seric setbitn(*p, m->m_flags); 86110327Seric break; 86210327Seric 86310327Seric case 'S': /* sender rewriting ruleset */ 86410327Seric case 'R': /* recipient rewriting ruleset */ 86558020Seric i = strtol(p, &endp, 10); 86610327Seric if (i < 0 || i >= MAXRWSETS) 86710327Seric { 86810327Seric syserr("invalid rewrite set, %d max", MAXRWSETS); 86910327Seric return; 87010327Seric } 87110327Seric if (fcode == 'S') 87258020Seric m->m_sh_rwset = m->m_se_rwset = i; 87310327Seric else 87458020Seric m->m_rh_rwset = m->m_re_rwset = i; 87558020Seric 87658020Seric p = endp; 87759985Seric if (*p++ == '/') 87858020Seric { 87958020Seric i = strtol(p, NULL, 10); 88058020Seric if (i < 0 || i >= MAXRWSETS) 88158020Seric { 88258020Seric syserr("invalid rewrite set, %d max", 88358020Seric MAXRWSETS); 88458020Seric return; 88558020Seric } 88658020Seric if (fcode == 'S') 88758020Seric m->m_sh_rwset = i; 88858020Seric else 88958020Seric m->m_rh_rwset = i; 89058020Seric } 89110327Seric break; 89210327Seric 89310327Seric case 'E': /* end of line string */ 89410327Seric m->m_eol = newstr(p); 89510327Seric break; 89610327Seric 89710327Seric case 'A': /* argument vector */ 89810327Seric m->m_argv = makeargv(p); 89910327Seric break; 90010701Seric 90110701Seric case 'M': /* maximum message size */ 90210701Seric m->m_maxsize = atol(p); 90310701Seric break; 90452106Seric 90552106Seric case 'L': /* maximum line length */ 90652106Seric m->m_linelimit = atoi(p); 90752106Seric break; 90858935Seric 90968816Seric case 'N': /* run niceness */ 91068816Seric m->m_nice = atoi(p); 91168816Seric break; 91268816Seric 91358935Seric case 'D': /* working directory */ 91458935Seric m->m_execdir = newstr(p); 91558935Seric break; 91668481Seric 91768481Seric case 'C': /* default charset */ 91868481Seric m->m_defcharset = newstr(p); 91968481Seric break; 92068481Seric 92169720Seric case 'T': /* MTA-Name/Address/Diagnostic types */ 92268481Seric m->m_mtatype = newstr(p); 92368481Seric p = strchr(m->m_mtatype, '/'); 92468481Seric if (p != NULL) 92568481Seric { 92668481Seric *p++ = '\0'; 92768481Seric if (*p == '\0') 92868481Seric p = NULL; 92968481Seric } 93068481Seric if (p == NULL) 93168481Seric m->m_addrtype = m->m_mtatype; 93268481Seric else 93368481Seric { 93468481Seric m->m_addrtype = p; 93568481Seric p = strchr(p, '/'); 93668481Seric } 93768481Seric if (p != NULL) 93868481Seric { 93968481Seric *p++ = '\0'; 94068481Seric if (*p == '\0') 94168481Seric p = NULL; 94268481Seric } 94368481Seric if (p == NULL) 94468481Seric m->m_diagtype = m->m_mtatype; 94568481Seric else 94668481Seric m->m_diagtype = p; 94768481Seric break; 94868481Seric 94968481Seric case 'U': /* user id */ 95068481Seric if (isascii(*p) && !isdigit(*p)) 95168481Seric { 95268481Seric char *q = p; 95368481Seric struct passwd *pw; 95468481Seric 95568481Seric while (isascii(*p) && isalnum(*p)) 95668481Seric p++; 95768481Seric while (isascii(*p) && isspace(*p)) 95868481Seric *p++ = '\0'; 95968481Seric if (*p != '\0') 96068481Seric *p++ = '\0'; 96168693Seric pw = sm_getpwnam(q); 96268481Seric if (pw == NULL) 96368481Seric syserr("readcf: mailer U= flag: unknown user %s", q); 96468481Seric else 96568481Seric { 96668481Seric m->m_uid = pw->pw_uid; 96768481Seric m->m_gid = pw->pw_gid; 96868481Seric } 96968481Seric } 97068481Seric else 97168481Seric { 97268481Seric auto char *q; 97368481Seric 97468481Seric m->m_uid = strtol(p, &q, 0); 97568481Seric p = q; 97668481Seric } 97768481Seric while (isascii(*p) && isspace(*p)) 97868481Seric p++; 97968481Seric if (*p == '\0') 98068481Seric break; 98168481Seric if (isascii(*p) && !isdigit(*p)) 98268481Seric { 98368481Seric char *q = p; 98468481Seric struct group *gr; 98568481Seric 98668481Seric while (isascii(*p) && isalnum(*p)) 98768481Seric p++; 98868481Seric *p++ = '\0'; 98968481Seric gr = getgrnam(q); 99068481Seric if (gr == NULL) 99168481Seric syserr("readcf: mailer U= flag: unknown group %s", q); 99268481Seric else 99368481Seric m->m_gid = gr->gr_gid; 99468481Seric } 99568481Seric else 99668481Seric { 99768481Seric m->m_gid = strtol(p, NULL, 0); 99868481Seric } 99968481Seric break; 100010327Seric } 100110327Seric 100258333Seric p = delimptr; 100310327Seric } 100410327Seric 100558321Seric /* do some rationality checking */ 100658321Seric if (m->m_argv == NULL) 100758321Seric { 100858321Seric syserr("M%s: A= argument required", m->m_name); 100958321Seric return; 101058321Seric } 101158321Seric if (m->m_mailer == NULL) 101258321Seric { 101358321Seric syserr("M%s: P= argument required", m->m_name); 101458321Seric return; 101558321Seric } 101658321Seric 10174096Seric if (NextMailer >= MAXMAILERS) 10184096Seric { 10199381Seric syserr("too many mailers defined (%d max)", MAXMAILERS); 10204096Seric return; 10214096Seric } 102257402Seric 102368481Seric /* do some heuristic cleanup for back compatibility */ 102468481Seric if (bitnset(M_LIMITS, m->m_flags)) 102568481Seric { 102668481Seric if (m->m_linelimit == 0) 102768481Seric m->m_linelimit = SMTPLINELIM; 102868481Seric if (ConfigLevel < 2) 102968481Seric setbitn(M_7BITS, m->m_flags); 103068481Seric } 103168481Seric 103268481Seric if (ConfigLevel < 6 && 103368481Seric (strcmp(m->m_mailer, "[IPC]") == 0 || 103468481Seric strcmp(m->m_mailer, "[TCP]") == 0)) 103568481Seric { 103668481Seric if (m->m_mtatype == NULL) 103768481Seric m->m_mtatype = "dns"; 103868481Seric if (m->m_addrtype == NULL) 103968481Seric m->m_addrtype = "rfc822"; 104068481Seric if (m->m_diagtype == NULL) 104168481Seric m->m_diagtype = "smtp"; 104268481Seric } 104368481Seric 104468481Seric /* enter the mailer into the symbol table */ 104510327Seric s = stab(m->m_name, ST_MAILER, ST_ENTER); 104657402Seric if (s->s_mailer != NULL) 104757402Seric { 104857402Seric i = s->s_mailer->m_mno; 104957402Seric free(s->s_mailer); 105057402Seric } 105157402Seric else 105257402Seric { 105357402Seric i = NextMailer++; 105457402Seric } 105557402Seric Mailer[i] = s->s_mailer = m; 105657454Seric m->m_mno = i; 105710327Seric } 105810327Seric /* 105910327Seric ** MUNCHSTRING -- translate a string into internal form. 106010327Seric ** 106110327Seric ** Parameters: 106210327Seric ** p -- the string to munch. 106358333Seric ** delimptr -- if non-NULL, set to the pointer of the 106458333Seric ** field delimiter character. 106510327Seric ** 106610327Seric ** Returns: 106710327Seric ** the munched string. 106810327Seric */ 10694096Seric 107010327Seric char * 107158333Seric munchstring(p, delimptr) 107210327Seric register char *p; 107358333Seric char **delimptr; 107410327Seric { 107510327Seric register char *q; 107610327Seric bool backslash = FALSE; 107710327Seric bool quotemode = FALSE; 107810327Seric static char buf[MAXLINE]; 10794096Seric 108010327Seric for (q = buf; *p != '\0'; p++) 10814096Seric { 108210327Seric if (backslash) 108310327Seric { 108410327Seric /* everything is roughly literal */ 108510357Seric backslash = FALSE; 108610327Seric switch (*p) 108710327Seric { 108810327Seric case 'r': /* carriage return */ 108910327Seric *q++ = '\r'; 109010327Seric continue; 109110327Seric 109210327Seric case 'n': /* newline */ 109310327Seric *q++ = '\n'; 109410327Seric continue; 109510327Seric 109610327Seric case 'f': /* form feed */ 109710327Seric *q++ = '\f'; 109810327Seric continue; 109910327Seric 110010327Seric case 'b': /* backspace */ 110110327Seric *q++ = '\b'; 110210327Seric continue; 110310327Seric } 110410327Seric *q++ = *p; 110510327Seric } 110610327Seric else 110710327Seric { 110810327Seric if (*p == '\\') 110910327Seric backslash = TRUE; 111010327Seric else if (*p == '"') 111110327Seric quotemode = !quotemode; 111210327Seric else if (quotemode || *p != ',') 111310327Seric *q++ = *p; 111410327Seric else 111510327Seric break; 111610327Seric } 11174096Seric } 11184096Seric 111958333Seric if (delimptr != NULL) 112058333Seric *delimptr = p; 112110327Seric *q++ = '\0'; 112210327Seric return (buf); 112310327Seric } 112410327Seric /* 112510327Seric ** MAKEARGV -- break up a string into words 112610327Seric ** 112710327Seric ** Parameters: 112810327Seric ** p -- the string to break up. 112910327Seric ** 113010327Seric ** Returns: 113110327Seric ** a char **argv (dynamically allocated) 113210327Seric ** 113310327Seric ** Side Effects: 113410327Seric ** munges p. 113510327Seric */ 11364096Seric 113710327Seric char ** 113810327Seric makeargv(p) 113910327Seric register char *p; 114010327Seric { 114110327Seric char *q; 114210327Seric int i; 114310327Seric char **avp; 114410327Seric char *argv[MAXPV + 1]; 114510327Seric 114610327Seric /* take apart the words */ 114710327Seric i = 0; 114810327Seric while (*p != '\0' && i < MAXPV) 11494096Seric { 115010327Seric q = p; 115158050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 115210327Seric p++; 115358050Seric while (isascii(*p) && isspace(*p)) 115410327Seric *p++ = '\0'; 115510327Seric argv[i++] = newstr(q); 11564096Seric } 115710327Seric argv[i++] = NULL; 11584096Seric 115910327Seric /* now make a copy of the argv */ 116010327Seric avp = (char **) xalloc(sizeof *avp * i); 116116893Seric bcopy((char *) argv, (char *) avp, sizeof *avp * i); 116210327Seric 116310327Seric return (avp); 11643308Seric } 11653308Seric /* 11663308Seric ** PRINTRULES -- print rewrite rules (for debugging) 11673308Seric ** 11683308Seric ** Parameters: 11693308Seric ** none. 11703308Seric ** 11713308Seric ** Returns: 11723308Seric ** none. 11733308Seric ** 11743308Seric ** Side Effects: 11753308Seric ** prints rewrite rules. 11763308Seric */ 11773308Seric 1178*69748Seric void 11793308Seric printrules() 11803308Seric { 11813308Seric register struct rewrite *rwp; 11824072Seric register int ruleset; 11833308Seric 11844072Seric for (ruleset = 0; ruleset < 10; ruleset++) 11853308Seric { 11864072Seric if (RewriteRules[ruleset] == NULL) 11874072Seric continue; 11888067Seric printf("\n----Rule Set %d:", ruleset); 11893308Seric 11904072Seric for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 11913308Seric { 11928067Seric printf("\nLHS:"); 11938067Seric printav(rwp->r_lhs); 11948067Seric printf("RHS:"); 11958067Seric printav(rwp->r_rhs); 11963308Seric } 11973308Seric } 11983308Seric } 119968481Seric /* 120068481Seric ** PRINTMAILER -- print mailer structure (for debugging) 120168481Seric ** 120268481Seric ** Parameters: 120368481Seric ** m -- the mailer to print 120468481Seric ** 120568481Seric ** Returns: 120668481Seric ** none. 120768481Seric */ 12084319Seric 1209*69748Seric void 121068481Seric printmailer(m) 121168481Seric register MAILER *m; 121268481Seric { 121368481Seric int j; 121468481Seric 121568481Seric printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld U=%d:%d F=", 121668481Seric m->m_mno, m->m_name, 121768481Seric m->m_mailer, m->m_se_rwset, m->m_sh_rwset, 121868481Seric m->m_re_rwset, m->m_rh_rwset, m->m_maxsize, 121968481Seric m->m_uid, m->m_gid); 122068481Seric for (j = '\0'; j <= '\177'; j++) 122168481Seric if (bitnset(j, m->m_flags)) 122268481Seric (void) putchar(j); 122368481Seric printf(" L=%d E=", m->m_linelimit); 122468481Seric xputs(m->m_eol); 122568481Seric if (m->m_defcharset != NULL) 122668481Seric printf(" C=%s", m->m_defcharset); 122768481Seric printf(" T=%s/%s/%s", 122868481Seric m->m_mtatype == NULL ? "<undefined>" : m->m_mtatype, 122968481Seric m->m_addrtype == NULL ? "<undefined>" : m->m_addrtype, 123068481Seric m->m_diagtype == NULL ? "<undefined>" : m->m_diagtype); 123168481Seric if (m->m_argv != NULL) 123268481Seric { 123368481Seric char **a = m->m_argv; 123468481Seric 123568481Seric printf(" A="); 123668481Seric while (*a != NULL) 123768481Seric { 123868481Seric if (a != m->m_argv) 123968481Seric printf(" "); 124068481Seric xputs(*a++); 124168481Seric } 124268481Seric } 124368481Seric printf("\n"); 124468481Seric } 12454096Seric /* 12468256Seric ** SETOPTION -- set global processing option 12478256Seric ** 12488256Seric ** Parameters: 12498256Seric ** opt -- option name. 12508256Seric ** val -- option value (as a text string). 125121755Seric ** safe -- set if this came from a configuration file. 125221755Seric ** Some options (if set from the command line) will 125321755Seric ** reset the user id to avoid security problems. 12548269Seric ** sticky -- if set, don't let other setoptions override 12558269Seric ** this value. 125658734Seric ** e -- the main envelope. 12578256Seric ** 12588256Seric ** Returns: 12598256Seric ** none. 12608256Seric ** 12618256Seric ** Side Effects: 12628256Seric ** Sets options as implied by the arguments. 12638256Seric */ 12648256Seric 126510687Seric static BITMAP StickyOpt; /* set if option is stuck */ 1266*69748Seric extern void settimeout __P((char *, char *)); 12678269Seric 126857207Seric 126966334Seric #if NAMED_BIND 127057207Seric 127157207Seric struct resolverflags 127257207Seric { 127357207Seric char *rf_name; /* name of the flag */ 127457207Seric long rf_bits; /* bits to set/clear */ 127557207Seric } ResolverFlags[] = 127657207Seric { 127757207Seric "debug", RES_DEBUG, 127857207Seric "aaonly", RES_AAONLY, 127957207Seric "usevc", RES_USEVC, 128057207Seric "primary", RES_PRIMARY, 128157207Seric "igntc", RES_IGNTC, 128257207Seric "recurse", RES_RECURSE, 128357207Seric "defnames", RES_DEFNAMES, 128457207Seric "stayopen", RES_STAYOPEN, 128557207Seric "dnsrch", RES_DNSRCH, 128665583Seric "true", 0, /* to avoid error on old syntax */ 128757207Seric NULL, 0 128857207Seric }; 128957207Seric 129057207Seric #endif 129157207Seric 129268481Seric struct optioninfo 129368481Seric { 129468481Seric char *o_name; /* long name of option */ 129568481Seric u_char o_code; /* short name of option */ 129668481Seric bool o_safe; /* safe for random people to use */ 129768481Seric } OptionTab[] = 129868481Seric { 129968481Seric "SevenBitInput", '7', TRUE, 130069480Seric #if MIME8TO7 130168481Seric "EightBitMode", '8', TRUE, 130269480Seric #endif 130368481Seric "AliasFile", 'A', FALSE, 130468481Seric "AliasWait", 'a', FALSE, 130568481Seric "BlankSub", 'B', FALSE, 130668481Seric "MinFreeBlocks", 'b', TRUE, 130768481Seric "CheckpointInterval", 'C', TRUE, 130868481Seric "HoldExpensive", 'c', FALSE, 130968481Seric "AutoRebuildAliases", 'D', FALSE, 131068481Seric "DeliveryMode", 'd', TRUE, 131168481Seric "ErrorHeader", 'E', FALSE, 131268481Seric "ErrorMode", 'e', TRUE, 131368481Seric "TempFileMode", 'F', FALSE, 131468481Seric "SaveFromLine", 'f', FALSE, 131568481Seric "MatchGECOS", 'G', FALSE, 131668481Seric "HelpFile", 'H', FALSE, 131768481Seric "MaxHopCount", 'h', FALSE, 131868569Seric "ResolverOptions", 'I', FALSE, 131968481Seric "IgnoreDots", 'i', TRUE, 132068481Seric "ForwardPath", 'J', FALSE, 132168481Seric "SendMimeErrors", 'j', TRUE, 132268481Seric "ConnectionCacheSize", 'k', FALSE, 132368481Seric "ConnectionCacheTimeout", 'K', FALSE, 132468481Seric "UseErrorsTo", 'l', FALSE, 132568481Seric "LogLevel", 'L', FALSE, 132668481Seric "MeToo", 'm', TRUE, 132768481Seric "CheckAliases", 'n', FALSE, 132868481Seric "OldStyleHeaders", 'o', TRUE, 132968481Seric "DaemonPortOptions", 'O', FALSE, 133068481Seric "PrivacyOptions", 'p', TRUE, 133168481Seric "PostmasterCopy", 'P', FALSE, 133268481Seric "QueueFactor", 'q', FALSE, 133368481Seric "QueueDirectory", 'Q', FALSE, 133468481Seric "DontPruneRoutes", 'R', FALSE, 133568481Seric "Timeout", 'r', TRUE, 133668481Seric "StatusFile", 'S', FALSE, 133768481Seric "SuperSafe", 's', TRUE, 133868481Seric "QueueTimeout", 'T', FALSE, 133968481Seric "TimeZoneSpec", 't', FALSE, 134068481Seric "UserDatabaseSpec", 'U', FALSE, 134168481Seric "DefaultUser", 'u', FALSE, 134268481Seric "FallbackMXhost", 'V', FALSE, 134368481Seric "Verbose", 'v', TRUE, 134468481Seric "TryNullMXList", 'w', TRUE, 134568481Seric "QueueLA", 'x', FALSE, 134668481Seric "RefuseLA", 'X', FALSE, 134768481Seric "RecipientFactor", 'y', FALSE, 134868569Seric "ForkEachJob", 'Y', FALSE, 134968481Seric "ClassFactor", 'z', FALSE, 135068569Seric "RetryFactor", 'Z', FALSE, 135168481Seric #define O_QUEUESORTORD 0x81 135268481Seric "QueueSortOrder", O_QUEUESORTORD, TRUE, 135369401Seric #define O_HOSTSFILE 0x82 135469401Seric "HostsFile", O_HOSTSFILE, FALSE, 135568481Seric #define O_MQA 0x83 135668481Seric "MinQueueAge", O_MQA, TRUE, 135768481Seric #define O_MHSA 0x84 135868481Seric /* 135968481Seric "MaxHostStatAge", O_MHSA, TRUE, 136068481Seric */ 136168481Seric #define O_DEFCHARSET 0x85 136268481Seric "DefaultCharSet", O_DEFCHARSET, TRUE, 136368481Seric #define O_SSFILE 0x86 136468481Seric "ServiceSwitchFile", O_SSFILE, FALSE, 136568481Seric #define O_DIALDELAY 0x87 136668481Seric "DialDelay", O_DIALDELAY, TRUE, 136768481Seric #define O_NORCPTACTION 0x88 136868481Seric "NoRecipientAction", O_NORCPTACTION, TRUE, 136968490Seric #define O_SAFEFILEENV 0x89 137068490Seric "SafeFileEnvironment", O_SAFEFILEENV, FALSE, 137168569Seric #define O_MAXMSGSIZE 0x8a 137268569Seric "MaxMessageSize", O_MAXMSGSIZE, FALSE, 137368756Seric #define O_COLONOKINADDR 0x8b 137468756Seric "ColonOkInAddr", O_COLONOKINADDR, TRUE, 137569724Seric #define O_MAXQUEUERUN 0x8c 137669724Seric "MaxQueueRunSize", O_MAXQUEUERUN, TRUE, 137768481Seric 137868481Seric NULL, '\0', FALSE, 137968481Seric }; 138068481Seric 138168481Seric 138268481Seric 1383*69748Seric void 138458734Seric setoption(opt, val, safe, sticky, e) 1385*69748Seric int opt; 13868256Seric char *val; 138721755Seric bool safe; 13888269Seric bool sticky; 138958734Seric register ENVELOPE *e; 13908256Seric { 139157207Seric register char *p; 139268481Seric register struct optioninfo *o; 139368481Seric char *subopt; 13948265Seric extern bool atobool(); 139512633Seric extern time_t convtime(); 139614879Seric extern int QueueLA; 139714879Seric extern int RefuseLA; 139864718Seric extern bool Warn_Q_option; 13998256Seric 140068481Seric errno = 0; 140168481Seric if (opt == ' ') 140268481Seric { 140368481Seric /* full word options */ 140468481Seric struct optioninfo *sel; 140568481Seric 140668481Seric p = strchr(val, '='); 140768481Seric if (p == NULL) 140868481Seric p = &val[strlen(val)]; 140968481Seric while (*--p == ' ') 141068481Seric continue; 141168481Seric while (*++p == ' ') 141268481Seric *p = '\0'; 141368481Seric if (p == val) 141468481Seric { 141568481Seric syserr("readcf: null option name"); 141668481Seric return; 141768481Seric } 141868481Seric if (*p == '=') 141968481Seric *p++ = '\0'; 142068481Seric while (*p == ' ') 142168481Seric p++; 142268481Seric subopt = strchr(val, '.'); 142368481Seric if (subopt != NULL) 142468481Seric *subopt++ = '\0'; 142568481Seric sel = NULL; 142668481Seric for (o = OptionTab; o->o_name != NULL; o++) 142768481Seric { 142868481Seric if (strncasecmp(o->o_name, val, strlen(val)) != 0) 142968481Seric continue; 143068481Seric if (strlen(o->o_name) == strlen(val)) 143168481Seric { 143268481Seric /* completely specified -- this must be it */ 143368481Seric sel = NULL; 143468481Seric break; 143568481Seric } 143668481Seric if (sel != NULL) 143768481Seric break; 143868481Seric sel = o; 143968481Seric } 144068481Seric if (sel != NULL && o->o_name == NULL) 144168481Seric o = sel; 144268481Seric else if (o->o_name == NULL) 144368481Seric { 144468481Seric syserr("readcf: unknown option name %s", val); 144568481Seric return; 144668481Seric } 144768481Seric else if (sel != NULL) 144868481Seric { 144968481Seric syserr("readcf: ambiguous option name %s (matches %s and %s)", 145068481Seric val, sel->o_name, o->o_name); 145168481Seric return; 145268481Seric } 145368481Seric if (strlen(val) != strlen(o->o_name)) 145468481Seric { 145568481Seric bool oldVerbose = Verbose; 145668481Seric 145768481Seric Verbose = TRUE; 145868481Seric message("Option %s used as abbreviation for %s", 145968481Seric val, o->o_name); 146068481Seric Verbose = oldVerbose; 146168481Seric } 146268481Seric opt = o->o_code; 146368481Seric val = p; 146468481Seric } 146568481Seric else 146668481Seric { 146768481Seric for (o = OptionTab; o->o_name != NULL; o++) 146868481Seric { 146968481Seric if (o->o_code == opt) 147068481Seric break; 147168481Seric } 147268481Seric subopt = NULL; 147368481Seric } 147468481Seric 14758256Seric if (tTd(37, 1)) 147668481Seric { 147768481Seric printf(isascii(opt) && isprint(opt) ? 147868481Seric "setoption %s (%c).%s=%s" : 147968481Seric "setoption %s (0x%x).%s=%s", 148068481Seric o->o_name == NULL ? "<unknown>" : o->o_name, 148168481Seric opt, 148268481Seric subopt == NULL ? "" : subopt, 148368481Seric val); 148468481Seric } 14858256Seric 14868256Seric /* 14878269Seric ** See if this option is preset for us. 14888256Seric */ 14898256Seric 149059731Seric if (!sticky && bitnset(opt, StickyOpt)) 14918269Seric { 14929341Seric if (tTd(37, 1)) 14939341Seric printf(" (ignored)\n"); 14948269Seric return; 14958269Seric } 14968269Seric 149721755Seric /* 149821755Seric ** Check to see if this option can be specified by this user. 149921755Seric */ 150021755Seric 150163787Seric if (!safe && RealUid == 0) 150221755Seric safe = TRUE; 150368481Seric if (!safe && !o->o_safe) 150421755Seric { 150539111Srick if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 150621755Seric { 150736582Sbostic if (tTd(37, 1)) 150836582Sbostic printf(" (unsafe)"); 150963787Seric if (RealUid != geteuid()) 151036582Sbostic { 151151210Seric if (tTd(37, 1)) 151251210Seric printf("(Resetting uid)"); 151363787Seric (void) setgid(RealGid); 151463787Seric (void) setuid(RealUid); 151536582Sbostic } 151621755Seric } 151721755Seric } 151851210Seric if (tTd(37, 1)) 151917985Seric printf("\n"); 15208269Seric 152168481Seric switch (opt & 0xff) 15228256Seric { 152359709Seric case '7': /* force seven-bit input */ 152468481Seric SevenBitInput = atobool(val); 152552106Seric break; 152652106Seric 152769480Seric #if MIME8TO7 152868481Seric case '8': /* handling of 8-bit input */ 152968481Seric switch (*val) 153068481Seric { 153168481Seric case 'm': /* convert 8-bit, convert MIME */ 153268481Seric MimeMode = MM_CVTMIME|MM_MIME8BIT; 153368481Seric break; 153468481Seric 153568481Seric case 'p': /* pass 8 bit, convert MIME */ 153668856Seric MimeMode = MM_CVTMIME|MM_PASS8BIT; 153768481Seric break; 153868481Seric 153968481Seric case 's': /* strict adherence */ 154068481Seric MimeMode = MM_CVTMIME; 154168481Seric break; 154268481Seric 154368856Seric #if 0 154468856Seric case 'r': /* reject 8-bit, don't convert MIME */ 154568856Seric MimeMode = 0; 154668856Seric break; 154768856Seric 154868856Seric case 'j': /* "just send 8" */ 154968856Seric MimeMode = MM_PASS8BIT; 155068856Seric break; 155168856Seric 155268481Seric case 'a': /* encode 8 bit if available */ 155368481Seric MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 155468481Seric break; 155568481Seric 155668481Seric case 'c': /* convert 8 bit to MIME, never 7 bit */ 155768481Seric MimeMode = MM_MIME8BIT; 155868481Seric break; 155968856Seric #endif 156068481Seric 156168481Seric default: 156268481Seric syserr("Unknown 8-bit mode %c", *val); 156368481Seric exit(EX_USAGE); 156468481Seric } 156568481Seric break; 156669480Seric #endif 156768481Seric 15688256Seric case 'A': /* set default alias file */ 15699381Seric if (val[0] == '\0') 157059672Seric setalias("aliases"); 15719381Seric else 157259672Seric setalias(val); 15738256Seric break; 15748256Seric 157517474Seric case 'a': /* look N minutes for "@:@" in alias file */ 157617474Seric if (val[0] == '\0') 157764796Seric SafeAlias = 5 * 60; /* five minutes */ 157817474Seric else 157964796Seric SafeAlias = convtime(val, 'm'); 158017474Seric break; 158117474Seric 158216843Seric case 'B': /* substitution for blank character */ 158316843Seric SpaceSub = val[0]; 158416843Seric if (SpaceSub == '\0') 158516843Seric SpaceSub = ' '; 158616843Seric break; 158716843Seric 158859283Seric case 'b': /* min blocks free on queue fs/max msg size */ 158959283Seric p = strchr(val, '/'); 159059283Seric if (p != NULL) 159159283Seric { 159259283Seric *p++ = '\0'; 159359283Seric MaxMessageSize = atol(p); 159459283Seric } 159558082Seric MinBlocksFree = atol(val); 159658082Seric break; 159758082Seric 15989284Seric case 'c': /* don't connect to "expensive" mailers */ 15999381Seric NoConnect = atobool(val); 16009284Seric break; 16019284Seric 160251305Seric case 'C': /* checkpoint every N addresses */ 160351305Seric CheckpointInterval = atoi(val); 160424944Seric break; 160524944Seric 16069284Seric case 'd': /* delivery mode */ 16079284Seric switch (*val) 16088269Seric { 16099284Seric case '\0': 161058734Seric e->e_sendmode = SM_DELIVER; 16118269Seric break; 16128269Seric 161310755Seric case SM_QUEUE: /* queue only */ 161410755Seric #ifndef QUEUE 161510755Seric syserr("need QUEUE to set -odqueue"); 161656795Seric #endif /* QUEUE */ 161710755Seric /* fall through..... */ 161810755Seric 16199284Seric case SM_DELIVER: /* do everything */ 16209284Seric case SM_FORK: /* fork after verification */ 162158734Seric e->e_sendmode = *val; 16228269Seric break; 16238269Seric 16248269Seric default: 16259284Seric syserr("Unknown delivery mode %c", *val); 16268269Seric exit(EX_USAGE); 16278269Seric } 16288269Seric break; 16298269Seric 16309146Seric case 'D': /* rebuild alias database as needed */ 16319381Seric AutoRebuild = atobool(val); 16329146Seric break; 16339146Seric 163455372Seric case 'E': /* error message header/header file */ 163555379Seric if (*val != '\0') 163655379Seric ErrMsgFile = newstr(val); 163755372Seric break; 163855372Seric 16398269Seric case 'e': /* set error processing mode */ 16408269Seric switch (*val) 16418269Seric { 16429381Seric case EM_QUIET: /* be silent about it */ 16439381Seric case EM_MAIL: /* mail back */ 16449381Seric case EM_BERKNET: /* do berknet error processing */ 16459381Seric case EM_WRITE: /* write back (or mail) */ 16469381Seric case EM_PRINT: /* print errors normally (default) */ 164758734Seric e->e_errormode = *val; 16488269Seric break; 16498269Seric } 16508269Seric break; 16518269Seric 16529049Seric case 'F': /* file mode */ 165317975Seric FileMode = atooct(val) & 0777; 16549049Seric break; 16559049Seric 16568269Seric case 'f': /* save Unix-style From lines on front */ 16579381Seric SaveFrom = atobool(val); 16588269Seric break; 16598269Seric 166053735Seric case 'G': /* match recipients against GECOS field */ 166153735Seric MatchGecos = atobool(val); 166253735Seric break; 166353735Seric 16648256Seric case 'g': /* default gid */ 166568481Seric g_opt: 166664133Seric if (isascii(*val) && isdigit(*val)) 166764133Seric DefGid = atoi(val); 166864133Seric else 166964133Seric { 167064133Seric register struct group *gr; 167164133Seric 167264133Seric DefGid = -1; 167364133Seric gr = getgrnam(val); 167464133Seric if (gr == NULL) 167568481Seric syserr("readcf: option %c: unknown group %s", 167668481Seric opt, val); 167764133Seric else 167864133Seric DefGid = gr->gr_gid; 167964133Seric } 16808256Seric break; 16818256Seric 16828256Seric case 'H': /* help file */ 16839381Seric if (val[0] == '\0') 16848269Seric HelpFile = "sendmail.hf"; 16859381Seric else 16869381Seric HelpFile = newstr(val); 16878256Seric break; 16888256Seric 168951305Seric case 'h': /* maximum hop count */ 169051305Seric MaxHopCount = atoi(val); 169151305Seric break; 169251305Seric 169335651Seric case 'I': /* use internet domain name server */ 169466334Seric #if NAMED_BIND 169557207Seric for (p = val; *p != 0; ) 169657207Seric { 169757207Seric bool clearmode; 169857207Seric char *q; 169957207Seric struct resolverflags *rfp; 170057207Seric 170157207Seric while (*p == ' ') 170257207Seric p++; 170357207Seric if (*p == '\0') 170457207Seric break; 170557207Seric clearmode = FALSE; 170657207Seric if (*p == '-') 170757207Seric clearmode = TRUE; 170857207Seric else if (*p != '+') 170957207Seric p--; 171057207Seric p++; 171157207Seric q = p; 171258050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 171357207Seric p++; 171457207Seric if (*p != '\0') 171557207Seric *p++ = '\0'; 171668759Seric if (strcasecmp(q, "HasWildcardMX") == 0) 171768759Seric { 171868759Seric NoMXforCanon = !clearmode; 171968759Seric continue; 172068759Seric } 172157207Seric for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 172257207Seric { 172357207Seric if (strcasecmp(q, rfp->rf_name) == 0) 172457207Seric break; 172557207Seric } 172664923Seric if (rfp->rf_name == NULL) 172764923Seric syserr("readcf: I option value %s unrecognized", q); 172864923Seric else if (clearmode) 172957207Seric _res.options &= ~rfp->rf_bits; 173057207Seric else 173157207Seric _res.options |= rfp->rf_bits; 173257207Seric } 173357207Seric if (tTd(8, 2)) 173468759Seric printf("_res.options = %x, HasWildcardMX = %d\n", 173568759Seric _res.options, !NoMXforCanon); 173657207Seric #else 173757207Seric usrerr("name server (I option) specified but BIND not compiled in"); 173857207Seric #endif 173935651Seric break; 174035651Seric 17418269Seric case 'i': /* ignore dot lines in message */ 17429381Seric IgnrDot = atobool(val); 17438269Seric break; 17448269Seric 174559730Seric case 'j': /* send errors in MIME (RFC 1341) format */ 174659730Seric SendMIMEErrors = atobool(val); 174759730Seric break; 174859730Seric 174957136Seric case 'J': /* .forward search path */ 175057136Seric ForwardPath = newstr(val); 175157136Seric break; 175257136Seric 175354967Seric case 'k': /* connection cache size */ 175454967Seric MaxMciCache = atoi(val); 175556215Seric if (MaxMciCache < 0) 175656215Seric MaxMciCache = 0; 175754967Seric break; 175854967Seric 175954967Seric case 'K': /* connection cache timeout */ 176058796Seric MciCacheTimeout = convtime(val, 'm'); 176154967Seric break; 176254967Seric 176361104Seric case 'l': /* use Errors-To: header */ 176461104Seric UseErrorsTo = atobool(val); 176561104Seric break; 176661104Seric 17678256Seric case 'L': /* log level */ 176864140Seric if (safe || LogLevel < atoi(val)) 176964140Seric LogLevel = atoi(val); 17708256Seric break; 17718256Seric 17728269Seric case 'M': /* define macro */ 177368267Seric p = newstr(&val[1]); 177468267Seric if (!safe) 177568267Seric cleanstrcpy(p, p, MAXNAME); 177668267Seric define(val[0], p, CurEnv); 177716878Seric sticky = FALSE; 17788269Seric break; 17798269Seric 17808269Seric case 'm': /* send to me too */ 17819381Seric MeToo = atobool(val); 17828269Seric break; 17838269Seric 178425820Seric case 'n': /* validate RHS in newaliases */ 178525820Seric CheckAliases = atobool(val); 178625820Seric break; 178725820Seric 178861104Seric /* 'N' available -- was "net name" */ 178961104Seric 179058851Seric case 'O': /* daemon options */ 179158851Seric setdaemonoptions(val); 179258851Seric break; 179358851Seric 17948269Seric case 'o': /* assume old style headers */ 17959381Seric if (atobool(val)) 17969341Seric CurEnv->e_flags |= EF_OLDSTYLE; 17979341Seric else 17989341Seric CurEnv->e_flags &= ~EF_OLDSTYLE; 17998269Seric break; 18008269Seric 180158082Seric case 'p': /* select privacy level */ 180258082Seric p = val; 180358082Seric for (;;) 180458082Seric { 180558082Seric register struct prival *pv; 180658082Seric extern struct prival PrivacyValues[]; 180758082Seric 180858082Seric while (isascii(*p) && (isspace(*p) || ispunct(*p))) 180958082Seric p++; 181058082Seric if (*p == '\0') 181158082Seric break; 181258082Seric val = p; 181358082Seric while (isascii(*p) && isalnum(*p)) 181458082Seric p++; 181558082Seric if (*p != '\0') 181658082Seric *p++ = '\0'; 181758082Seric 181858082Seric for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 181958082Seric { 182058082Seric if (strcasecmp(val, pv->pv_name) == 0) 182158082Seric break; 182258082Seric } 182358886Seric if (pv->pv_name == NULL) 182458886Seric syserr("readcf: Op line: %s unrecognized", val); 182558082Seric PrivacyFlags |= pv->pv_flag; 182658082Seric } 182768479Seric sticky = FALSE; 182858082Seric break; 182958082Seric 183024944Seric case 'P': /* postmaster copy address for returned mail */ 183124944Seric PostMasterCopy = newstr(val); 183224944Seric break; 183324944Seric 183424944Seric case 'q': /* slope of queue only function */ 183524944Seric QueueFactor = atoi(val); 183624944Seric break; 183724944Seric 18388256Seric case 'Q': /* queue directory */ 18399381Seric if (val[0] == '\0') 18408269Seric QueueDir = "mqueue"; 18419381Seric else 18429381Seric QueueDir = newstr(val); 184358789Seric if (RealUid != 0 && !safe) 184464718Seric Warn_Q_option = TRUE; 18458256Seric break; 18468256Seric 184758148Seric case 'R': /* don't prune routes */ 184858148Seric DontPruneRoutes = atobool(val); 184958148Seric break; 185058148Seric 18518256Seric case 'r': /* read timeout */ 185268481Seric if (subopt == NULL) 185368481Seric inittimeouts(val); 185468481Seric else 185568481Seric settimeout(subopt, val); 18568256Seric break; 18578256Seric 18588256Seric case 'S': /* status file */ 18599381Seric if (val[0] == '\0') 18608269Seric StatFile = "sendmail.st"; 18619381Seric else 18629381Seric StatFile = newstr(val); 18638256Seric break; 18648256Seric 18658265Seric case 's': /* be super safe, even if expensive */ 18669381Seric SuperSafe = atobool(val); 18678256Seric break; 18688256Seric 18698256Seric case 'T': /* queue timeout */ 187058737Seric p = strchr(val, '/'); 187158737Seric if (p != NULL) 187258737Seric { 187358737Seric *p++ = '\0'; 187468481Seric settimeout("queuewarn", p); 187558737Seric } 187668481Seric settimeout("queuereturn", val); 187754967Seric break; 18788256Seric 18798265Seric case 't': /* time zone name */ 188052106Seric TimeZoneSpec = newstr(val); 18818265Seric break; 18828265Seric 188350556Seric case 'U': /* location of user database */ 188451360Seric UdbSpec = newstr(val); 188550556Seric break; 188650556Seric 18878256Seric case 'u': /* set default uid */ 188868481Seric for (p = val; *p != '\0'; p++) 188968481Seric { 189068481Seric if (*p == '.' || *p == '/' || *p == ':') 189168481Seric { 189268481Seric *p++ = '\0'; 189368481Seric break; 189468481Seric } 189568481Seric } 189664133Seric if (isascii(*val) && isdigit(*val)) 189764133Seric DefUid = atoi(val); 189864133Seric else 189964133Seric { 190064133Seric register struct passwd *pw; 190164133Seric 190264133Seric DefUid = -1; 190368693Seric pw = sm_getpwnam(val); 190464133Seric if (pw == NULL) 190564133Seric syserr("readcf: option u: unknown user %s", val); 190664133Seric else 190768481Seric { 190864133Seric DefUid = pw->pw_uid; 190968481Seric DefGid = pw->pw_gid; 191068481Seric } 191164133Seric } 191240973Sbostic setdefuser(); 19138256Seric 191468481Seric /* handle the group if it is there */ 191568481Seric if (*p == '\0') 191668481Seric break; 191768481Seric val = p; 191868481Seric goto g_opt; 191968481Seric 192058851Seric case 'V': /* fallback MX host */ 192158851Seric FallBackMX = newstr(val); 192258851Seric break; 192358851Seric 19248269Seric case 'v': /* run in verbose mode */ 19259381Seric Verbose = atobool(val); 19268256Seric break; 19278256Seric 192863837Seric case 'w': /* if we are best MX, try host directly */ 192963837Seric TryNullMXList = atobool(val); 193063837Seric break; 193161104Seric 193261104Seric /* 'W' available -- was wizard password */ 193361104Seric 193414879Seric case 'x': /* load avg at which to auto-queue msgs */ 193514879Seric QueueLA = atoi(val); 193614879Seric break; 193714879Seric 193814879Seric case 'X': /* load avg at which to auto-reject connections */ 193914879Seric RefuseLA = atoi(val); 194014879Seric break; 194114879Seric 194224981Seric case 'y': /* work recipient factor */ 194324981Seric WkRecipFact = atoi(val); 194424981Seric break; 194524981Seric 194624981Seric case 'Y': /* fork jobs during queue runs */ 194724952Seric ForkQueueRuns = atobool(val); 194824952Seric break; 194924952Seric 195024981Seric case 'z': /* work message class factor */ 195124981Seric WkClassFact = atoi(val); 195224981Seric break; 195324981Seric 195424981Seric case 'Z': /* work time factor */ 195524981Seric WkTimeFact = atoi(val); 195624981Seric break; 195724981Seric 195868481Seric case O_QUEUESORTORD: /* queue sorting order */ 195968481Seric switch (*val) 196068481Seric { 196168481Seric case 'h': /* Host first */ 196268481Seric case 'H': 196368481Seric QueueSortOrder = QS_BYHOST; 196468481Seric break; 196568481Seric 196668481Seric case 'p': /* Priority order */ 196768481Seric case 'P': 196868481Seric QueueSortOrder = QS_BYPRIORITY; 196968481Seric break; 197068481Seric 197168481Seric default: 197268481Seric syserr("Invalid queue sort order \"%s\"", val); 197368481Seric } 197468481Seric break; 197568481Seric 197669401Seric case O_HOSTSFILE: /* pathname of /etc/hosts file */ 197769401Seric HostsFile = newstr(val); 197869401Seric break; 197969401Seric 198068481Seric case O_MQA: /* minimum queue age between deliveries */ 198168481Seric MinQueueAge = convtime(val, 'm'); 198268481Seric break; 198368481Seric 198468481Seric case O_MHSA: /* maximum age of cached host status */ 198568481Seric MaxHostStatAge = convtime(val, 'm'); 198668481Seric break; 198768481Seric 198868481Seric case O_DEFCHARSET: /* default character set for mimefying */ 198968481Seric DefaultCharSet = newstr(denlstring(val, TRUE, TRUE)); 199068481Seric break; 199168481Seric 199268481Seric case O_SSFILE: /* service switch file */ 199368481Seric ServiceSwitchFile = newstr(val); 199468481Seric break; 199568481Seric 199668481Seric case O_DIALDELAY: /* delay for dial-on-demand operation */ 199768481Seric DialDelay = convtime(val, 's'); 199868481Seric break; 199968481Seric 200068481Seric case O_NORCPTACTION: /* what to do if no recipient */ 200168481Seric if (strcasecmp(val, "none") == 0) 200268481Seric NoRecipientAction = NRA_NO_ACTION; 200368481Seric else if (strcasecmp(val, "add-to") == 0) 200468481Seric NoRecipientAction = NRA_ADD_TO; 200568481Seric else if (strcasecmp(val, "add-apparently-to") == 0) 200668481Seric NoRecipientAction = NRA_ADD_APPARENTLY_TO; 200768481Seric else if (strcasecmp(val, "add-bcc") == 0) 200868481Seric NoRecipientAction = NRA_ADD_BCC; 200968481Seric else if (strcasecmp(val, "add-to-undisclosed") == 0) 201068481Seric NoRecipientAction = NRA_ADD_TO_UNDISCLOSED; 201168481Seric else 201268481Seric syserr("Invalid NoRecipientAction: %s", val); 201368481Seric 201468490Seric case O_SAFEFILEENV: /* chroot() environ for writing to files */ 201568490Seric SafeFileEnv = newstr(val); 201668490Seric break; 201768490Seric 201868569Seric case O_MAXMSGSIZE: /* maximum message size */ 2019*69748Seric MaxMessageSize = atol(val); 202068569Seric break; 202168569Seric 202268756Seric case O_COLONOKINADDR: /* old style handling of colon addresses */ 2023*69748Seric ColonOkInAddr = atobool(val); 202468756Seric break; 202568756Seric 202669724Seric case O_MAXQUEUERUN: /* max # of jobs in a single queue run */ 2027*69748Seric MaxQueueRun = atol(val); 202869724Seric break; 202969724Seric 20308256Seric default: 203168481Seric if (tTd(37, 1)) 203268481Seric { 203368481Seric if (isascii(opt) && isprint(opt)) 203468481Seric printf("Warning: option %c unknown\n", opt); 203568481Seric else 203668481Seric printf("Warning: option 0x%x unknown\n", opt); 203768481Seric } 20388256Seric break; 20398256Seric } 204016878Seric if (sticky) 204116878Seric setbitn(opt, StickyOpt); 20428256Seric } 204310687Seric /* 204468481Seric ** SETCLASS -- set a string into a class 204510687Seric ** 204610687Seric ** Parameters: 204768481Seric ** class -- the class to put the string in. 204868481Seric ** str -- the string to enter 204910687Seric ** 205010687Seric ** Returns: 205110687Seric ** none. 205210687Seric ** 205310687Seric ** Side Effects: 205410687Seric ** puts the word into the symbol table. 205510687Seric */ 205610687Seric 2057*69748Seric void 205868481Seric setclass(class, str) 205910687Seric int class; 206068481Seric char *str; 206110687Seric { 206210687Seric register STAB *s; 206310687Seric 206457943Seric if (tTd(37, 8)) 206568481Seric printf("setclass(%c, %s)\n", class, str); 206668481Seric s = stab(str, ST_CLASS, ST_ENTER); 206710687Seric setbitn(class, s->s_class); 206810687Seric } 206953654Seric /* 207053654Seric ** MAKEMAPENTRY -- create a map entry 207153654Seric ** 207253654Seric ** Parameters: 207353654Seric ** line -- the config file line 207453654Seric ** 207553654Seric ** Returns: 207653654Seric ** TRUE if it successfully entered the map entry. 207753654Seric ** FALSE otherwise (usually syntax error). 207853654Seric ** 207953654Seric ** Side Effects: 208053654Seric ** Enters the map into the dictionary. 208153654Seric */ 208253654Seric 208353654Seric void 208453654Seric makemapentry(line) 208553654Seric char *line; 208653654Seric { 208753654Seric register char *p; 208853654Seric char *mapname; 208953654Seric char *classname; 209064078Seric register STAB *s; 209153654Seric STAB *class; 209253654Seric 209358050Seric for (p = line; isascii(*p) && isspace(*p); p++) 209453654Seric continue; 209558050Seric if (!(isascii(*p) && isalnum(*p))) 209653654Seric { 209753654Seric syserr("readcf: config K line: no map name"); 209853654Seric return; 209953654Seric } 210053654Seric 210153654Seric mapname = p; 210268481Seric while ((isascii(*++p) && isalnum(*p)) || *p == '.') 210353654Seric continue; 210453654Seric if (*p != '\0') 210553654Seric *p++ = '\0'; 210658050Seric while (isascii(*p) && isspace(*p)) 210753654Seric p++; 210858050Seric if (!(isascii(*p) && isalnum(*p))) 210953654Seric { 211053654Seric syserr("readcf: config K line, map %s: no map class", mapname); 211153654Seric return; 211253654Seric } 211353654Seric classname = p; 211458050Seric while (isascii(*++p) && isalnum(*p)) 211553654Seric continue; 211653654Seric if (*p != '\0') 211753654Seric *p++ = '\0'; 211858050Seric while (isascii(*p) && isspace(*p)) 211953654Seric p++; 212053654Seric 212153654Seric /* look up the class */ 212253654Seric class = stab(classname, ST_MAPCLASS, ST_FIND); 212353654Seric if (class == NULL) 212453654Seric { 212553654Seric syserr("readcf: map %s: class %s not available", mapname, classname); 212653654Seric return; 212753654Seric } 212853654Seric 212953654Seric /* enter the map */ 213064078Seric s = stab(mapname, ST_MAP, ST_ENTER); 213164078Seric s->s_map.map_class = &class->s_mapclass; 213264078Seric s->s_map.map_mname = newstr(mapname); 213353654Seric 213464078Seric if (class->s_mapclass.map_parse(&s->s_map, p)) 213564078Seric s->s_map.map_mflags |= MF_VALID; 213664078Seric 213764078Seric if (tTd(37, 5)) 213864078Seric { 213964078Seric printf("map %s, class %s, flags %x, file %s,\n", 214064078Seric s->s_map.map_mname, s->s_map.map_class->map_cname, 214164078Seric s->s_map.map_mflags, 214264078Seric s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 214364078Seric printf("\tapp %s, domain %s, rebuild %s\n", 214464078Seric s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 214564078Seric s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 214664078Seric s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 214764078Seric } 214853654Seric } 214958112Seric /* 215068481Seric ** INITTIMEOUTS -- parse and set timeout values 215158112Seric ** 215258112Seric ** Parameters: 215358112Seric ** val -- a pointer to the values. If NULL, do initial 215458112Seric ** settings. 215558112Seric ** 215658112Seric ** Returns: 215758112Seric ** none. 215858112Seric ** 215958112Seric ** Side Effects: 216058112Seric ** Initializes the TimeOuts structure 216158112Seric */ 216258112Seric 216364255Seric #define SECONDS 216458112Seric #define MINUTES * 60 216558112Seric #define HOUR * 3600 216658112Seric 2167*69748Seric void 216868481Seric inittimeouts(val) 216958112Seric register char *val; 217058112Seric { 217158112Seric register char *p; 217258671Seric extern time_t convtime(); 217358112Seric 217458112Seric if (val == NULL) 217558112Seric { 217658112Seric TimeOuts.to_initial = (time_t) 5 MINUTES; 217758112Seric TimeOuts.to_helo = (time_t) 5 MINUTES; 217858112Seric TimeOuts.to_mail = (time_t) 10 MINUTES; 217958112Seric TimeOuts.to_rcpt = (time_t) 1 HOUR; 218058112Seric TimeOuts.to_datainit = (time_t) 5 MINUTES; 218158112Seric TimeOuts.to_datablock = (time_t) 1 HOUR; 218258112Seric TimeOuts.to_datafinal = (time_t) 1 HOUR; 218358112Seric TimeOuts.to_rset = (time_t) 5 MINUTES; 218458112Seric TimeOuts.to_quit = (time_t) 2 MINUTES; 218558112Seric TimeOuts.to_nextcommand = (time_t) 1 HOUR; 218658112Seric TimeOuts.to_miscshort = (time_t) 2 MINUTES; 218768481Seric #if IDENTPROTO 218864255Seric TimeOuts.to_ident = (time_t) 30 SECONDS; 218968481Seric #else 219068481Seric TimeOuts.to_ident = (time_t) 0 SECONDS; 219168481Seric #endif 219268481Seric TimeOuts.to_fileopen = (time_t) 60 SECONDS; 219358112Seric return; 219458112Seric } 219558112Seric 219658112Seric for (;; val = p) 219758112Seric { 219858112Seric while (isascii(*val) && isspace(*val)) 219958112Seric val++; 220058112Seric if (*val == '\0') 220158112Seric break; 220258112Seric for (p = val; *p != '\0' && *p != ','; p++) 220358112Seric continue; 220458112Seric if (*p != '\0') 220558112Seric *p++ = '\0'; 220658112Seric 220758112Seric if (isascii(*val) && isdigit(*val)) 220858112Seric { 220958112Seric /* old syntax -- set everything */ 221058796Seric TimeOuts.to_mail = convtime(val, 'm'); 221158112Seric TimeOuts.to_rcpt = TimeOuts.to_mail; 221258112Seric TimeOuts.to_datainit = TimeOuts.to_mail; 221358112Seric TimeOuts.to_datablock = TimeOuts.to_mail; 221458112Seric TimeOuts.to_datafinal = TimeOuts.to_mail; 221558112Seric TimeOuts.to_nextcommand = TimeOuts.to_mail; 221658112Seric continue; 221758112Seric } 221858112Seric else 221958112Seric { 222068481Seric register char *q = strchr(val, ':'); 222158112Seric 222268481Seric if (q == NULL && (q = strchr(val, '=')) == NULL) 222358112Seric { 222458112Seric /* syntax error */ 222558112Seric continue; 222658112Seric } 222758112Seric *q++ = '\0'; 222868481Seric settimeout(val, q); 222968481Seric } 223068481Seric } 223168481Seric } 223268481Seric /* 223368481Seric ** SETTIMEOUT -- set an individual timeout 223468481Seric ** 223568481Seric ** Parameters: 223668481Seric ** name -- the name of the timeout. 223768481Seric ** val -- the value of the timeout. 223868481Seric ** 223968481Seric ** Returns: 224068481Seric ** none. 224168481Seric */ 224258112Seric 2243*69748Seric void 224468481Seric settimeout(name, val) 224568481Seric char *name; 224668481Seric char *val; 224768481Seric { 224868481Seric register char *p; 224968481Seric time_t to; 225068481Seric extern time_t convtime(); 225168481Seric 225268481Seric to = convtime(val, 'm'); 225368481Seric p = strchr(name, '.'); 225468481Seric if (p != NULL) 225568481Seric *p++ = '\0'; 225668481Seric 225768481Seric if (strcasecmp(name, "initial") == 0) 225868481Seric TimeOuts.to_initial = to; 225968481Seric else if (strcasecmp(name, "mail") == 0) 226068481Seric TimeOuts.to_mail = to; 226168481Seric else if (strcasecmp(name, "rcpt") == 0) 226268481Seric TimeOuts.to_rcpt = to; 226368481Seric else if (strcasecmp(name, "datainit") == 0) 226468481Seric TimeOuts.to_datainit = to; 226568481Seric else if (strcasecmp(name, "datablock") == 0) 226668481Seric TimeOuts.to_datablock = to; 226768481Seric else if (strcasecmp(name, "datafinal") == 0) 226868481Seric TimeOuts.to_datafinal = to; 226968481Seric else if (strcasecmp(name, "command") == 0) 227068481Seric TimeOuts.to_nextcommand = to; 227168481Seric else if (strcasecmp(name, "rset") == 0) 227268481Seric TimeOuts.to_rset = to; 227368481Seric else if (strcasecmp(name, "helo") == 0) 227468481Seric TimeOuts.to_helo = to; 227568481Seric else if (strcasecmp(name, "quit") == 0) 227668481Seric TimeOuts.to_quit = to; 227768481Seric else if (strcasecmp(name, "misc") == 0) 227868481Seric TimeOuts.to_miscshort = to; 227968481Seric else if (strcasecmp(name, "ident") == 0) 228068481Seric TimeOuts.to_ident = to; 228168481Seric else if (strcasecmp(name, "fileopen") == 0) 228268481Seric TimeOuts.to_fileopen = to; 228368481Seric else if (strcasecmp(name, "queuewarn") == 0) 228468481Seric { 228568481Seric to = convtime(val, 'h'); 228668481Seric if (p == NULL || strcmp(p, "*") == 0) 228768481Seric { 228868481Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 228968481Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 229068481Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 229158112Seric } 229268481Seric else if (strcasecmp(p, "normal") == 0) 229368481Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 229468481Seric else if (strcasecmp(p, "urgent") == 0) 229568481Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 229668481Seric else if (strcasecmp(p, "non-urgent") == 0) 229768481Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 229868481Seric else 229968481Seric syserr("settimeout: invalid queuewarn subtimeout %s", p); 230058112Seric } 230168481Seric else if (strcasecmp(name, "queuereturn") == 0) 230268481Seric { 230368481Seric to = convtime(val, 'd'); 230468481Seric if (p == NULL || strcmp(p, "*") == 0) 230568481Seric { 230668481Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 230768481Seric TimeOuts.to_q_return[TOC_URGENT] = to; 230868481Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 230968481Seric } 231068481Seric else if (strcasecmp(p, "normal") == 0) 231168481Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 231268481Seric else if (strcasecmp(p, "urgent") == 0) 231368481Seric TimeOuts.to_q_return[TOC_URGENT] = to; 231468481Seric else if (strcasecmp(p, "non-urgent") == 0) 231568481Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 231668481Seric else 231768481Seric syserr("settimeout: invalid queuereturn subtimeout %s", p); 231868481Seric } 231968481Seric else 232068481Seric syserr("settimeout: invalid timeout %s", name); 232158112Seric } 2322