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*69686Seric static char sccsid[] = "@(#)readcf.c 8.92 (Berkeley) 05/25/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 { 116*69686Seric 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 91768481Seric case 'T': /* MTA Type */ 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, 136868481Seric 136968481Seric NULL, '\0', FALSE, 137068481Seric }; 137168481Seric 137268481Seric 137368481Seric 137458734Seric setoption(opt, val, safe, sticky, e) 137568481Seric u_char opt; 13768256Seric char *val; 137721755Seric bool safe; 13788269Seric bool sticky; 137958734Seric register ENVELOPE *e; 13808256Seric { 138157207Seric register char *p; 138268481Seric register struct optioninfo *o; 138368481Seric char *subopt; 13848265Seric extern bool atobool(); 138512633Seric extern time_t convtime(); 138614879Seric extern int QueueLA; 138714879Seric extern int RefuseLA; 138864718Seric extern bool Warn_Q_option; 13898256Seric 139068481Seric errno = 0; 139168481Seric if (opt == ' ') 139268481Seric { 139368481Seric /* full word options */ 139468481Seric struct optioninfo *sel; 139568481Seric 139668481Seric p = strchr(val, '='); 139768481Seric if (p == NULL) 139868481Seric p = &val[strlen(val)]; 139968481Seric while (*--p == ' ') 140068481Seric continue; 140168481Seric while (*++p == ' ') 140268481Seric *p = '\0'; 140368481Seric if (p == val) 140468481Seric { 140568481Seric syserr("readcf: null option name"); 140668481Seric return; 140768481Seric } 140868481Seric if (*p == '=') 140968481Seric *p++ = '\0'; 141068481Seric while (*p == ' ') 141168481Seric p++; 141268481Seric subopt = strchr(val, '.'); 141368481Seric if (subopt != NULL) 141468481Seric *subopt++ = '\0'; 141568481Seric sel = NULL; 141668481Seric for (o = OptionTab; o->o_name != NULL; o++) 141768481Seric { 141868481Seric if (strncasecmp(o->o_name, val, strlen(val)) != 0) 141968481Seric continue; 142068481Seric if (strlen(o->o_name) == strlen(val)) 142168481Seric { 142268481Seric /* completely specified -- this must be it */ 142368481Seric sel = NULL; 142468481Seric break; 142568481Seric } 142668481Seric if (sel != NULL) 142768481Seric break; 142868481Seric sel = o; 142968481Seric } 143068481Seric if (sel != NULL && o->o_name == NULL) 143168481Seric o = sel; 143268481Seric else if (o->o_name == NULL) 143368481Seric { 143468481Seric syserr("readcf: unknown option name %s", val); 143568481Seric return; 143668481Seric } 143768481Seric else if (sel != NULL) 143868481Seric { 143968481Seric syserr("readcf: ambiguous option name %s (matches %s and %s)", 144068481Seric val, sel->o_name, o->o_name); 144168481Seric return; 144268481Seric } 144368481Seric if (strlen(val) != strlen(o->o_name)) 144468481Seric { 144568481Seric bool oldVerbose = Verbose; 144668481Seric 144768481Seric Verbose = TRUE; 144868481Seric message("Option %s used as abbreviation for %s", 144968481Seric val, o->o_name); 145068481Seric Verbose = oldVerbose; 145168481Seric } 145268481Seric opt = o->o_code; 145368481Seric val = p; 145468481Seric } 145568481Seric else 145668481Seric { 145768481Seric for (o = OptionTab; o->o_name != NULL; o++) 145868481Seric { 145968481Seric if (o->o_code == opt) 146068481Seric break; 146168481Seric } 146268481Seric subopt = NULL; 146368481Seric } 146468481Seric 14658256Seric if (tTd(37, 1)) 146668481Seric { 146768481Seric printf(isascii(opt) && isprint(opt) ? 146868481Seric "setoption %s (%c).%s=%s" : 146968481Seric "setoption %s (0x%x).%s=%s", 147068481Seric o->o_name == NULL ? "<unknown>" : o->o_name, 147168481Seric opt, 147268481Seric subopt == NULL ? "" : subopt, 147368481Seric val); 147468481Seric } 14758256Seric 14768256Seric /* 14778269Seric ** See if this option is preset for us. 14788256Seric */ 14798256Seric 148059731Seric if (!sticky && bitnset(opt, StickyOpt)) 14818269Seric { 14829341Seric if (tTd(37, 1)) 14839341Seric printf(" (ignored)\n"); 14848269Seric return; 14858269Seric } 14868269Seric 148721755Seric /* 148821755Seric ** Check to see if this option can be specified by this user. 148921755Seric */ 149021755Seric 149163787Seric if (!safe && RealUid == 0) 149221755Seric safe = TRUE; 149368481Seric if (!safe && !o->o_safe) 149421755Seric { 149539111Srick if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 149621755Seric { 149736582Sbostic if (tTd(37, 1)) 149836582Sbostic printf(" (unsafe)"); 149963787Seric if (RealUid != geteuid()) 150036582Sbostic { 150151210Seric if (tTd(37, 1)) 150251210Seric printf("(Resetting uid)"); 150363787Seric (void) setgid(RealGid); 150463787Seric (void) setuid(RealUid); 150536582Sbostic } 150621755Seric } 150721755Seric } 150851210Seric if (tTd(37, 1)) 150917985Seric printf("\n"); 15108269Seric 151168481Seric switch (opt & 0xff) 15128256Seric { 151359709Seric case '7': /* force seven-bit input */ 151468481Seric SevenBitInput = atobool(val); 151552106Seric break; 151652106Seric 151769480Seric #if MIME8TO7 151868481Seric case '8': /* handling of 8-bit input */ 151968481Seric switch (*val) 152068481Seric { 152168481Seric case 'm': /* convert 8-bit, convert MIME */ 152268481Seric MimeMode = MM_CVTMIME|MM_MIME8BIT; 152368481Seric break; 152468481Seric 152568481Seric case 'p': /* pass 8 bit, convert MIME */ 152668856Seric MimeMode = MM_CVTMIME|MM_PASS8BIT; 152768481Seric break; 152868481Seric 152968481Seric case 's': /* strict adherence */ 153068481Seric MimeMode = MM_CVTMIME; 153168481Seric break; 153268481Seric 153368856Seric #if 0 153468856Seric case 'r': /* reject 8-bit, don't convert MIME */ 153568856Seric MimeMode = 0; 153668856Seric break; 153768856Seric 153868856Seric case 'j': /* "just send 8" */ 153968856Seric MimeMode = MM_PASS8BIT; 154068856Seric break; 154168856Seric 154268481Seric case 'a': /* encode 8 bit if available */ 154368481Seric MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 154468481Seric break; 154568481Seric 154668481Seric case 'c': /* convert 8 bit to MIME, never 7 bit */ 154768481Seric MimeMode = MM_MIME8BIT; 154868481Seric break; 154968856Seric #endif 155068481Seric 155168481Seric default: 155268481Seric syserr("Unknown 8-bit mode %c", *val); 155368481Seric exit(EX_USAGE); 155468481Seric } 155568481Seric break; 155669480Seric #endif 155768481Seric 15588256Seric case 'A': /* set default alias file */ 15599381Seric if (val[0] == '\0') 156059672Seric setalias("aliases"); 15619381Seric else 156259672Seric setalias(val); 15638256Seric break; 15648256Seric 156517474Seric case 'a': /* look N minutes for "@:@" in alias file */ 156617474Seric if (val[0] == '\0') 156764796Seric SafeAlias = 5 * 60; /* five minutes */ 156817474Seric else 156964796Seric SafeAlias = convtime(val, 'm'); 157017474Seric break; 157117474Seric 157216843Seric case 'B': /* substitution for blank character */ 157316843Seric SpaceSub = val[0]; 157416843Seric if (SpaceSub == '\0') 157516843Seric SpaceSub = ' '; 157616843Seric break; 157716843Seric 157859283Seric case 'b': /* min blocks free on queue fs/max msg size */ 157959283Seric p = strchr(val, '/'); 158059283Seric if (p != NULL) 158159283Seric { 158259283Seric *p++ = '\0'; 158359283Seric MaxMessageSize = atol(p); 158459283Seric } 158558082Seric MinBlocksFree = atol(val); 158658082Seric break; 158758082Seric 15889284Seric case 'c': /* don't connect to "expensive" mailers */ 15899381Seric NoConnect = atobool(val); 15909284Seric break; 15919284Seric 159251305Seric case 'C': /* checkpoint every N addresses */ 159351305Seric CheckpointInterval = atoi(val); 159424944Seric break; 159524944Seric 15969284Seric case 'd': /* delivery mode */ 15979284Seric switch (*val) 15988269Seric { 15999284Seric case '\0': 160058734Seric e->e_sendmode = SM_DELIVER; 16018269Seric break; 16028269Seric 160310755Seric case SM_QUEUE: /* queue only */ 160410755Seric #ifndef QUEUE 160510755Seric syserr("need QUEUE to set -odqueue"); 160656795Seric #endif /* QUEUE */ 160710755Seric /* fall through..... */ 160810755Seric 16099284Seric case SM_DELIVER: /* do everything */ 16109284Seric case SM_FORK: /* fork after verification */ 161158734Seric e->e_sendmode = *val; 16128269Seric break; 16138269Seric 16148269Seric default: 16159284Seric syserr("Unknown delivery mode %c", *val); 16168269Seric exit(EX_USAGE); 16178269Seric } 16188269Seric break; 16198269Seric 16209146Seric case 'D': /* rebuild alias database as needed */ 16219381Seric AutoRebuild = atobool(val); 16229146Seric break; 16239146Seric 162455372Seric case 'E': /* error message header/header file */ 162555379Seric if (*val != '\0') 162655379Seric ErrMsgFile = newstr(val); 162755372Seric break; 162855372Seric 16298269Seric case 'e': /* set error processing mode */ 16308269Seric switch (*val) 16318269Seric { 16329381Seric case EM_QUIET: /* be silent about it */ 16339381Seric case EM_MAIL: /* mail back */ 16349381Seric case EM_BERKNET: /* do berknet error processing */ 16359381Seric case EM_WRITE: /* write back (or mail) */ 16369381Seric case EM_PRINT: /* print errors normally (default) */ 163758734Seric e->e_errormode = *val; 16388269Seric break; 16398269Seric } 16408269Seric break; 16418269Seric 16429049Seric case 'F': /* file mode */ 164317975Seric FileMode = atooct(val) & 0777; 16449049Seric break; 16459049Seric 16468269Seric case 'f': /* save Unix-style From lines on front */ 16479381Seric SaveFrom = atobool(val); 16488269Seric break; 16498269Seric 165053735Seric case 'G': /* match recipients against GECOS field */ 165153735Seric MatchGecos = atobool(val); 165253735Seric break; 165353735Seric 16548256Seric case 'g': /* default gid */ 165568481Seric g_opt: 165664133Seric if (isascii(*val) && isdigit(*val)) 165764133Seric DefGid = atoi(val); 165864133Seric else 165964133Seric { 166064133Seric register struct group *gr; 166164133Seric 166264133Seric DefGid = -1; 166364133Seric gr = getgrnam(val); 166464133Seric if (gr == NULL) 166568481Seric syserr("readcf: option %c: unknown group %s", 166668481Seric opt, val); 166764133Seric else 166864133Seric DefGid = gr->gr_gid; 166964133Seric } 16708256Seric break; 16718256Seric 16728256Seric case 'H': /* help file */ 16739381Seric if (val[0] == '\0') 16748269Seric HelpFile = "sendmail.hf"; 16759381Seric else 16769381Seric HelpFile = newstr(val); 16778256Seric break; 16788256Seric 167951305Seric case 'h': /* maximum hop count */ 168051305Seric MaxHopCount = atoi(val); 168151305Seric break; 168251305Seric 168335651Seric case 'I': /* use internet domain name server */ 168466334Seric #if NAMED_BIND 168557207Seric for (p = val; *p != 0; ) 168657207Seric { 168757207Seric bool clearmode; 168857207Seric char *q; 168957207Seric struct resolverflags *rfp; 169057207Seric 169157207Seric while (*p == ' ') 169257207Seric p++; 169357207Seric if (*p == '\0') 169457207Seric break; 169557207Seric clearmode = FALSE; 169657207Seric if (*p == '-') 169757207Seric clearmode = TRUE; 169857207Seric else if (*p != '+') 169957207Seric p--; 170057207Seric p++; 170157207Seric q = p; 170258050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 170357207Seric p++; 170457207Seric if (*p != '\0') 170557207Seric *p++ = '\0'; 170668759Seric if (strcasecmp(q, "HasWildcardMX") == 0) 170768759Seric { 170868759Seric NoMXforCanon = !clearmode; 170968759Seric continue; 171068759Seric } 171157207Seric for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 171257207Seric { 171357207Seric if (strcasecmp(q, rfp->rf_name) == 0) 171457207Seric break; 171557207Seric } 171664923Seric if (rfp->rf_name == NULL) 171764923Seric syserr("readcf: I option value %s unrecognized", q); 171864923Seric else if (clearmode) 171957207Seric _res.options &= ~rfp->rf_bits; 172057207Seric else 172157207Seric _res.options |= rfp->rf_bits; 172257207Seric } 172357207Seric if (tTd(8, 2)) 172468759Seric printf("_res.options = %x, HasWildcardMX = %d\n", 172568759Seric _res.options, !NoMXforCanon); 172657207Seric #else 172757207Seric usrerr("name server (I option) specified but BIND not compiled in"); 172857207Seric #endif 172935651Seric break; 173035651Seric 17318269Seric case 'i': /* ignore dot lines in message */ 17329381Seric IgnrDot = atobool(val); 17338269Seric break; 17348269Seric 173559730Seric case 'j': /* send errors in MIME (RFC 1341) format */ 173659730Seric SendMIMEErrors = atobool(val); 173759730Seric break; 173859730Seric 173957136Seric case 'J': /* .forward search path */ 174057136Seric ForwardPath = newstr(val); 174157136Seric break; 174257136Seric 174354967Seric case 'k': /* connection cache size */ 174454967Seric MaxMciCache = atoi(val); 174556215Seric if (MaxMciCache < 0) 174656215Seric MaxMciCache = 0; 174754967Seric break; 174854967Seric 174954967Seric case 'K': /* connection cache timeout */ 175058796Seric MciCacheTimeout = convtime(val, 'm'); 175154967Seric break; 175254967Seric 175361104Seric case 'l': /* use Errors-To: header */ 175461104Seric UseErrorsTo = atobool(val); 175561104Seric break; 175661104Seric 17578256Seric case 'L': /* log level */ 175864140Seric if (safe || LogLevel < atoi(val)) 175964140Seric LogLevel = atoi(val); 17608256Seric break; 17618256Seric 17628269Seric case 'M': /* define macro */ 176368267Seric p = newstr(&val[1]); 176468267Seric if (!safe) 176568267Seric cleanstrcpy(p, p, MAXNAME); 176668267Seric define(val[0], p, CurEnv); 176716878Seric sticky = FALSE; 17688269Seric break; 17698269Seric 17708269Seric case 'm': /* send to me too */ 17719381Seric MeToo = atobool(val); 17728269Seric break; 17738269Seric 177425820Seric case 'n': /* validate RHS in newaliases */ 177525820Seric CheckAliases = atobool(val); 177625820Seric break; 177725820Seric 177861104Seric /* 'N' available -- was "net name" */ 177961104Seric 178058851Seric case 'O': /* daemon options */ 178158851Seric setdaemonoptions(val); 178258851Seric break; 178358851Seric 17848269Seric case 'o': /* assume old style headers */ 17859381Seric if (atobool(val)) 17869341Seric CurEnv->e_flags |= EF_OLDSTYLE; 17879341Seric else 17889341Seric CurEnv->e_flags &= ~EF_OLDSTYLE; 17898269Seric break; 17908269Seric 179158082Seric case 'p': /* select privacy level */ 179258082Seric p = val; 179358082Seric for (;;) 179458082Seric { 179558082Seric register struct prival *pv; 179658082Seric extern struct prival PrivacyValues[]; 179758082Seric 179858082Seric while (isascii(*p) && (isspace(*p) || ispunct(*p))) 179958082Seric p++; 180058082Seric if (*p == '\0') 180158082Seric break; 180258082Seric val = p; 180358082Seric while (isascii(*p) && isalnum(*p)) 180458082Seric p++; 180558082Seric if (*p != '\0') 180658082Seric *p++ = '\0'; 180758082Seric 180858082Seric for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 180958082Seric { 181058082Seric if (strcasecmp(val, pv->pv_name) == 0) 181158082Seric break; 181258082Seric } 181358886Seric if (pv->pv_name == NULL) 181458886Seric syserr("readcf: Op line: %s unrecognized", val); 181558082Seric PrivacyFlags |= pv->pv_flag; 181658082Seric } 181768479Seric sticky = FALSE; 181858082Seric break; 181958082Seric 182024944Seric case 'P': /* postmaster copy address for returned mail */ 182124944Seric PostMasterCopy = newstr(val); 182224944Seric break; 182324944Seric 182424944Seric case 'q': /* slope of queue only function */ 182524944Seric QueueFactor = atoi(val); 182624944Seric break; 182724944Seric 18288256Seric case 'Q': /* queue directory */ 18299381Seric if (val[0] == '\0') 18308269Seric QueueDir = "mqueue"; 18319381Seric else 18329381Seric QueueDir = newstr(val); 183358789Seric if (RealUid != 0 && !safe) 183464718Seric Warn_Q_option = TRUE; 18358256Seric break; 18368256Seric 183758148Seric case 'R': /* don't prune routes */ 183858148Seric DontPruneRoutes = atobool(val); 183958148Seric break; 184058148Seric 18418256Seric case 'r': /* read timeout */ 184268481Seric if (subopt == NULL) 184368481Seric inittimeouts(val); 184468481Seric else 184568481Seric settimeout(subopt, val); 18468256Seric break; 18478256Seric 18488256Seric case 'S': /* status file */ 18499381Seric if (val[0] == '\0') 18508269Seric StatFile = "sendmail.st"; 18519381Seric else 18529381Seric StatFile = newstr(val); 18538256Seric break; 18548256Seric 18558265Seric case 's': /* be super safe, even if expensive */ 18569381Seric SuperSafe = atobool(val); 18578256Seric break; 18588256Seric 18598256Seric case 'T': /* queue timeout */ 186058737Seric p = strchr(val, '/'); 186158737Seric if (p != NULL) 186258737Seric { 186358737Seric *p++ = '\0'; 186468481Seric settimeout("queuewarn", p); 186558737Seric } 186668481Seric settimeout("queuereturn", val); 186754967Seric break; 18688256Seric 18698265Seric case 't': /* time zone name */ 187052106Seric TimeZoneSpec = newstr(val); 18718265Seric break; 18728265Seric 187350556Seric case 'U': /* location of user database */ 187451360Seric UdbSpec = newstr(val); 187550556Seric break; 187650556Seric 18778256Seric case 'u': /* set default uid */ 187868481Seric for (p = val; *p != '\0'; p++) 187968481Seric { 188068481Seric if (*p == '.' || *p == '/' || *p == ':') 188168481Seric { 188268481Seric *p++ = '\0'; 188368481Seric break; 188468481Seric } 188568481Seric } 188664133Seric if (isascii(*val) && isdigit(*val)) 188764133Seric DefUid = atoi(val); 188864133Seric else 188964133Seric { 189064133Seric register struct passwd *pw; 189164133Seric 189264133Seric DefUid = -1; 189368693Seric pw = sm_getpwnam(val); 189464133Seric if (pw == NULL) 189564133Seric syserr("readcf: option u: unknown user %s", val); 189664133Seric else 189768481Seric { 189864133Seric DefUid = pw->pw_uid; 189968481Seric DefGid = pw->pw_gid; 190068481Seric } 190164133Seric } 190240973Sbostic setdefuser(); 19038256Seric 190468481Seric /* handle the group if it is there */ 190568481Seric if (*p == '\0') 190668481Seric break; 190768481Seric val = p; 190868481Seric goto g_opt; 190968481Seric 191058851Seric case 'V': /* fallback MX host */ 191158851Seric FallBackMX = newstr(val); 191258851Seric break; 191358851Seric 19148269Seric case 'v': /* run in verbose mode */ 19159381Seric Verbose = atobool(val); 19168256Seric break; 19178256Seric 191863837Seric case 'w': /* if we are best MX, try host directly */ 191963837Seric TryNullMXList = atobool(val); 192063837Seric break; 192161104Seric 192261104Seric /* 'W' available -- was wizard password */ 192361104Seric 192414879Seric case 'x': /* load avg at which to auto-queue msgs */ 192514879Seric QueueLA = atoi(val); 192614879Seric break; 192714879Seric 192814879Seric case 'X': /* load avg at which to auto-reject connections */ 192914879Seric RefuseLA = atoi(val); 193014879Seric break; 193114879Seric 193224981Seric case 'y': /* work recipient factor */ 193324981Seric WkRecipFact = atoi(val); 193424981Seric break; 193524981Seric 193624981Seric case 'Y': /* fork jobs during queue runs */ 193724952Seric ForkQueueRuns = atobool(val); 193824952Seric break; 193924952Seric 194024981Seric case 'z': /* work message class factor */ 194124981Seric WkClassFact = atoi(val); 194224981Seric break; 194324981Seric 194424981Seric case 'Z': /* work time factor */ 194524981Seric WkTimeFact = atoi(val); 194624981Seric break; 194724981Seric 194868481Seric case O_QUEUESORTORD: /* queue sorting order */ 194968481Seric switch (*val) 195068481Seric { 195168481Seric case 'h': /* Host first */ 195268481Seric case 'H': 195368481Seric QueueSortOrder = QS_BYHOST; 195468481Seric break; 195568481Seric 195668481Seric case 'p': /* Priority order */ 195768481Seric case 'P': 195868481Seric QueueSortOrder = QS_BYPRIORITY; 195968481Seric break; 196068481Seric 196168481Seric default: 196268481Seric syserr("Invalid queue sort order \"%s\"", val); 196368481Seric } 196468481Seric break; 196568481Seric 196669401Seric case O_HOSTSFILE: /* pathname of /etc/hosts file */ 196769401Seric HostsFile = newstr(val); 196869401Seric break; 196969401Seric 197068481Seric case O_MQA: /* minimum queue age between deliveries */ 197168481Seric MinQueueAge = convtime(val, 'm'); 197268481Seric break; 197368481Seric 197468481Seric case O_MHSA: /* maximum age of cached host status */ 197568481Seric MaxHostStatAge = convtime(val, 'm'); 197668481Seric break; 197768481Seric 197868481Seric case O_DEFCHARSET: /* default character set for mimefying */ 197968481Seric DefaultCharSet = newstr(denlstring(val, TRUE, TRUE)); 198068481Seric break; 198168481Seric 198268481Seric case O_SSFILE: /* service switch file */ 198368481Seric ServiceSwitchFile = newstr(val); 198468481Seric break; 198568481Seric 198668481Seric case O_DIALDELAY: /* delay for dial-on-demand operation */ 198768481Seric DialDelay = convtime(val, 's'); 198868481Seric break; 198968481Seric 199068481Seric case O_NORCPTACTION: /* what to do if no recipient */ 199168481Seric if (strcasecmp(val, "none") == 0) 199268481Seric NoRecipientAction = NRA_NO_ACTION; 199368481Seric else if (strcasecmp(val, "add-to") == 0) 199468481Seric NoRecipientAction = NRA_ADD_TO; 199568481Seric else if (strcasecmp(val, "add-apparently-to") == 0) 199668481Seric NoRecipientAction = NRA_ADD_APPARENTLY_TO; 199768481Seric else if (strcasecmp(val, "add-bcc") == 0) 199868481Seric NoRecipientAction = NRA_ADD_BCC; 199968481Seric else if (strcasecmp(val, "add-to-undisclosed") == 0) 200068481Seric NoRecipientAction = NRA_ADD_TO_UNDISCLOSED; 200168481Seric else 200268481Seric syserr("Invalid NoRecipientAction: %s", val); 200368481Seric 200468490Seric case O_SAFEFILEENV: /* chroot() environ for writing to files */ 200568490Seric SafeFileEnv = newstr(val); 200668490Seric break; 200768490Seric 200868569Seric case O_MAXMSGSIZE: /* maximum message size */ 200968569Seric MaxMessageSize = atol(p); 201068569Seric break; 201168569Seric 201268756Seric case O_COLONOKINADDR: /* old style handling of colon addresses */ 201368756Seric ColonOkInAddr = atobool(p); 201468756Seric break; 201568756Seric 20168256Seric default: 201768481Seric if (tTd(37, 1)) 201868481Seric { 201968481Seric if (isascii(opt) && isprint(opt)) 202068481Seric printf("Warning: option %c unknown\n", opt); 202168481Seric else 202268481Seric printf("Warning: option 0x%x unknown\n", opt); 202368481Seric } 20248256Seric break; 20258256Seric } 202616878Seric if (sticky) 202716878Seric setbitn(opt, StickyOpt); 20289188Seric return; 20298256Seric } 203010687Seric /* 203168481Seric ** SETCLASS -- set a string into a class 203210687Seric ** 203310687Seric ** Parameters: 203468481Seric ** class -- the class to put the string in. 203568481Seric ** str -- the string to enter 203610687Seric ** 203710687Seric ** Returns: 203810687Seric ** none. 203910687Seric ** 204010687Seric ** Side Effects: 204110687Seric ** puts the word into the symbol table. 204210687Seric */ 204310687Seric 204468481Seric setclass(class, str) 204510687Seric int class; 204668481Seric char *str; 204710687Seric { 204810687Seric register STAB *s; 204910687Seric 205057943Seric if (tTd(37, 8)) 205168481Seric printf("setclass(%c, %s)\n", class, str); 205268481Seric s = stab(str, ST_CLASS, ST_ENTER); 205310687Seric setbitn(class, s->s_class); 205410687Seric } 205553654Seric /* 205653654Seric ** MAKEMAPENTRY -- create a map entry 205753654Seric ** 205853654Seric ** Parameters: 205953654Seric ** line -- the config file line 206053654Seric ** 206153654Seric ** Returns: 206253654Seric ** TRUE if it successfully entered the map entry. 206353654Seric ** FALSE otherwise (usually syntax error). 206453654Seric ** 206553654Seric ** Side Effects: 206653654Seric ** Enters the map into the dictionary. 206753654Seric */ 206853654Seric 206953654Seric void 207053654Seric makemapentry(line) 207153654Seric char *line; 207253654Seric { 207353654Seric register char *p; 207453654Seric char *mapname; 207553654Seric char *classname; 207664078Seric register STAB *s; 207753654Seric STAB *class; 207853654Seric 207958050Seric for (p = line; isascii(*p) && isspace(*p); p++) 208053654Seric continue; 208158050Seric if (!(isascii(*p) && isalnum(*p))) 208253654Seric { 208353654Seric syserr("readcf: config K line: no map name"); 208453654Seric return; 208553654Seric } 208653654Seric 208753654Seric mapname = p; 208868481Seric while ((isascii(*++p) && isalnum(*p)) || *p == '.') 208953654Seric continue; 209053654Seric if (*p != '\0') 209153654Seric *p++ = '\0'; 209258050Seric while (isascii(*p) && isspace(*p)) 209353654Seric p++; 209458050Seric if (!(isascii(*p) && isalnum(*p))) 209553654Seric { 209653654Seric syserr("readcf: config K line, map %s: no map class", mapname); 209753654Seric return; 209853654Seric } 209953654Seric classname = p; 210058050Seric while (isascii(*++p) && isalnum(*p)) 210153654Seric continue; 210253654Seric if (*p != '\0') 210353654Seric *p++ = '\0'; 210458050Seric while (isascii(*p) && isspace(*p)) 210553654Seric p++; 210653654Seric 210753654Seric /* look up the class */ 210853654Seric class = stab(classname, ST_MAPCLASS, ST_FIND); 210953654Seric if (class == NULL) 211053654Seric { 211153654Seric syserr("readcf: map %s: class %s not available", mapname, classname); 211253654Seric return; 211353654Seric } 211453654Seric 211553654Seric /* enter the map */ 211664078Seric s = stab(mapname, ST_MAP, ST_ENTER); 211764078Seric s->s_map.map_class = &class->s_mapclass; 211864078Seric s->s_map.map_mname = newstr(mapname); 211953654Seric 212064078Seric if (class->s_mapclass.map_parse(&s->s_map, p)) 212164078Seric s->s_map.map_mflags |= MF_VALID; 212264078Seric 212364078Seric if (tTd(37, 5)) 212464078Seric { 212564078Seric printf("map %s, class %s, flags %x, file %s,\n", 212664078Seric s->s_map.map_mname, s->s_map.map_class->map_cname, 212764078Seric s->s_map.map_mflags, 212864078Seric s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 212964078Seric printf("\tapp %s, domain %s, rebuild %s\n", 213064078Seric s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 213164078Seric s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 213264078Seric s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 213364078Seric } 213453654Seric } 213558112Seric /* 213668481Seric ** INITTIMEOUTS -- parse and set timeout values 213758112Seric ** 213858112Seric ** Parameters: 213958112Seric ** val -- a pointer to the values. If NULL, do initial 214058112Seric ** settings. 214158112Seric ** 214258112Seric ** Returns: 214358112Seric ** none. 214458112Seric ** 214558112Seric ** Side Effects: 214658112Seric ** Initializes the TimeOuts structure 214758112Seric */ 214858112Seric 214964255Seric #define SECONDS 215058112Seric #define MINUTES * 60 215158112Seric #define HOUR * 3600 215258112Seric 215368481Seric inittimeouts(val) 215458112Seric register char *val; 215558112Seric { 215658112Seric register char *p; 215758671Seric extern time_t convtime(); 215858112Seric 215958112Seric if (val == NULL) 216058112Seric { 216158112Seric TimeOuts.to_initial = (time_t) 5 MINUTES; 216258112Seric TimeOuts.to_helo = (time_t) 5 MINUTES; 216358112Seric TimeOuts.to_mail = (time_t) 10 MINUTES; 216458112Seric TimeOuts.to_rcpt = (time_t) 1 HOUR; 216558112Seric TimeOuts.to_datainit = (time_t) 5 MINUTES; 216658112Seric TimeOuts.to_datablock = (time_t) 1 HOUR; 216758112Seric TimeOuts.to_datafinal = (time_t) 1 HOUR; 216858112Seric TimeOuts.to_rset = (time_t) 5 MINUTES; 216958112Seric TimeOuts.to_quit = (time_t) 2 MINUTES; 217058112Seric TimeOuts.to_nextcommand = (time_t) 1 HOUR; 217158112Seric TimeOuts.to_miscshort = (time_t) 2 MINUTES; 217268481Seric #if IDENTPROTO 217364255Seric TimeOuts.to_ident = (time_t) 30 SECONDS; 217468481Seric #else 217568481Seric TimeOuts.to_ident = (time_t) 0 SECONDS; 217668481Seric #endif 217768481Seric TimeOuts.to_fileopen = (time_t) 60 SECONDS; 217858112Seric return; 217958112Seric } 218058112Seric 218158112Seric for (;; val = p) 218258112Seric { 218358112Seric while (isascii(*val) && isspace(*val)) 218458112Seric val++; 218558112Seric if (*val == '\0') 218658112Seric break; 218758112Seric for (p = val; *p != '\0' && *p != ','; p++) 218858112Seric continue; 218958112Seric if (*p != '\0') 219058112Seric *p++ = '\0'; 219158112Seric 219258112Seric if (isascii(*val) && isdigit(*val)) 219358112Seric { 219458112Seric /* old syntax -- set everything */ 219558796Seric TimeOuts.to_mail = convtime(val, 'm'); 219658112Seric TimeOuts.to_rcpt = TimeOuts.to_mail; 219758112Seric TimeOuts.to_datainit = TimeOuts.to_mail; 219858112Seric TimeOuts.to_datablock = TimeOuts.to_mail; 219958112Seric TimeOuts.to_datafinal = TimeOuts.to_mail; 220058112Seric TimeOuts.to_nextcommand = TimeOuts.to_mail; 220158112Seric continue; 220258112Seric } 220358112Seric else 220458112Seric { 220568481Seric register char *q = strchr(val, ':'); 220658112Seric 220768481Seric if (q == NULL && (q = strchr(val, '=')) == NULL) 220858112Seric { 220958112Seric /* syntax error */ 221058112Seric continue; 221158112Seric } 221258112Seric *q++ = '\0'; 221368481Seric settimeout(val, q); 221468481Seric } 221568481Seric } 221668481Seric } 221768481Seric /* 221868481Seric ** SETTIMEOUT -- set an individual timeout 221968481Seric ** 222068481Seric ** Parameters: 222168481Seric ** name -- the name of the timeout. 222268481Seric ** val -- the value of the timeout. 222368481Seric ** 222468481Seric ** Returns: 222568481Seric ** none. 222668481Seric */ 222758112Seric 222868481Seric settimeout(name, val) 222968481Seric char *name; 223068481Seric char *val; 223168481Seric { 223268481Seric register char *p; 223368481Seric time_t to; 223468481Seric extern time_t convtime(); 223568481Seric 223668481Seric to = convtime(val, 'm'); 223768481Seric p = strchr(name, '.'); 223868481Seric if (p != NULL) 223968481Seric *p++ = '\0'; 224068481Seric 224168481Seric if (strcasecmp(name, "initial") == 0) 224268481Seric TimeOuts.to_initial = to; 224368481Seric else if (strcasecmp(name, "mail") == 0) 224468481Seric TimeOuts.to_mail = to; 224568481Seric else if (strcasecmp(name, "rcpt") == 0) 224668481Seric TimeOuts.to_rcpt = to; 224768481Seric else if (strcasecmp(name, "datainit") == 0) 224868481Seric TimeOuts.to_datainit = to; 224968481Seric else if (strcasecmp(name, "datablock") == 0) 225068481Seric TimeOuts.to_datablock = to; 225168481Seric else if (strcasecmp(name, "datafinal") == 0) 225268481Seric TimeOuts.to_datafinal = to; 225368481Seric else if (strcasecmp(name, "command") == 0) 225468481Seric TimeOuts.to_nextcommand = to; 225568481Seric else if (strcasecmp(name, "rset") == 0) 225668481Seric TimeOuts.to_rset = to; 225768481Seric else if (strcasecmp(name, "helo") == 0) 225868481Seric TimeOuts.to_helo = to; 225968481Seric else if (strcasecmp(name, "quit") == 0) 226068481Seric TimeOuts.to_quit = to; 226168481Seric else if (strcasecmp(name, "misc") == 0) 226268481Seric TimeOuts.to_miscshort = to; 226368481Seric else if (strcasecmp(name, "ident") == 0) 226468481Seric TimeOuts.to_ident = to; 226568481Seric else if (strcasecmp(name, "fileopen") == 0) 226668481Seric TimeOuts.to_fileopen = to; 226768481Seric else if (strcasecmp(name, "queuewarn") == 0) 226868481Seric { 226968481Seric to = convtime(val, 'h'); 227068481Seric if (p == NULL || strcmp(p, "*") == 0) 227168481Seric { 227268481Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 227368481Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 227468481Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 227558112Seric } 227668481Seric else if (strcasecmp(p, "normal") == 0) 227768481Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 227868481Seric else if (strcasecmp(p, "urgent") == 0) 227968481Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 228068481Seric else if (strcasecmp(p, "non-urgent") == 0) 228168481Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 228268481Seric else 228368481Seric syserr("settimeout: invalid queuewarn subtimeout %s", p); 228458112Seric } 228568481Seric else if (strcasecmp(name, "queuereturn") == 0) 228668481Seric { 228768481Seric to = convtime(val, 'd'); 228868481Seric if (p == NULL || strcmp(p, "*") == 0) 228968481Seric { 229068481Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 229168481Seric TimeOuts.to_q_return[TOC_URGENT] = to; 229268481Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 229368481Seric } 229468481Seric else if (strcasecmp(p, "normal") == 0) 229568481Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 229668481Seric else if (strcasecmp(p, "urgent") == 0) 229768481Seric TimeOuts.to_q_return[TOC_URGENT] = to; 229868481Seric else if (strcasecmp(p, "non-urgent") == 0) 229968481Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 230068481Seric else 230168481Seric syserr("settimeout: invalid queuereturn subtimeout %s", p); 230268481Seric } 230368481Seric else 230468481Seric syserr("settimeout: invalid timeout %s", name); 230558112Seric } 2306