122709Sdist /* 234921Sbostic * Copyright (c) 1983 Eric P. Allman 362530Sbostic * Copyright (c) 1988, 1993 462530Sbostic * The Regents of the University of California. All rights reserved. 533731Sbostic * 642829Sbostic * %sccs.include.redist.c% 733731Sbostic */ 822709Sdist 922709Sdist #ifndef lint 10*68490Seric static char sccsid[] = "@(#)readcf.c 8.72 (Berkeley) 03/05/95"; 1133731Sbostic #endif /* not lint */ 1222709Sdist 133313Seric # include "sendmail.h" 1464133Seric # include <pwd.h> 1564133Seric # include <grp.h> 1666334Seric #if NAMED_BIND 1757207Seric # include <resolv.h> 1857207Seric #endif 193308Seric 203308Seric /* 213308Seric ** READCF -- read control file. 223308Seric ** 233308Seric ** This routine reads the control file and builds the internal 243308Seric ** form. 253308Seric ** 264432Seric ** The file is formatted as a sequence of lines, each taken 274432Seric ** atomically. The first character of each line describes how 284432Seric ** the line is to be interpreted. The lines are: 294432Seric ** Dxval Define macro x to have value val. 304432Seric ** Cxword Put word into class x. 314432Seric ** Fxfile [fmt] Read file for lines to put into 324432Seric ** class x. Use scanf string 'fmt' 334432Seric ** or "%s" if not present. Fmt should 344432Seric ** only produce one string-valued result. 354432Seric ** Hname: value Define header with field-name 'name' 364432Seric ** and value as specified; this will be 374432Seric ** macro expanded immediately before 384432Seric ** use. 394432Seric ** Sn Use rewriting set n. 404432Seric ** Rlhs rhs Rewrite addresses that match lhs to 414432Seric ** be rhs. 4224944Seric ** Mn arg=val... Define mailer. n is the internal name. 4324944Seric ** Args specify mailer parameters. 448252Seric ** Oxvalue Set option x to value. 458252Seric ** Pname=value Set precedence name to value. 4664718Seric ** Vversioncode[/vendorcode] 4764718Seric ** Version level/vendor name of 4864718Seric ** configuration syntax. 4953654Seric ** Kmapname mapclass arguments.... 5053654Seric ** Define keyed lookup of a given class. 5153654Seric ** Arguments are class dependent. 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 { 11653037Seric if (OpMode == MD_DAEMON || OpMode == MD_FREEZE) 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'; 22457135Seric expand(&bp[1], exbuf, &exbuf[sizeof exbuf], e); 22565066Seric rwp->r_lhs = prescan(exbuf, '\t', pvpbuf, 22665066Seric sizeof pvpbuf, 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'; 31255012Seric expand(q, exbuf, &exbuf[sizeof exbuf], e); 31365066Seric rwp->r_rhs = prescan(exbuf, '\t', pvpbuf, 31465066Seric sizeof pvpbuf, 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 */ 43457135Seric (void) chompheader(&bp[1], TRUE, 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); 44268481Seric expand(ep, exbuf, &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); 53664279Seric if (ConfigLevel >= 5) 53764279Seric { 53864279Seric /* level 5 configs have short name in $w */ 53964279Seric p = macvalue('w', e); 54064279Seric if (p != NULL && (p = strchr(p, '.')) != NULL) 54164279Seric *p = '\0'; 54264279Seric } 54364718Seric if (*ep++ == '/') 54464718Seric { 54564718Seric /* extract vendor code */ 54664718Seric for (p = ep; isascii(*p) && isalpha(*p); ) 54764718Seric p++; 54864718Seric *p = '\0'; 54964718Seric 55064718Seric if (!setvendor(ep)) 55164718Seric syserr("invalid V line vendor code: \"%s\"", 55264718Seric ep); 55364718Seric } 55452645Seric break; 55552645Seric 55653654Seric case 'K': 55757135Seric makemapentry(&bp[1]); 55853654Seric break; 55953654Seric 5603308Seric default: 5614061Seric badline: 56257135Seric syserr("unknown control line \"%s\"", bp); 5633308Seric } 56457135Seric if (bp != buf) 56557135Seric free(bp); 5663308Seric } 56752637Seric if (ferror(cf)) 56852637Seric { 56952647Seric syserr("I/O read error", cfname); 57052637Seric exit(EX_OSFILE); 57152637Seric } 57252637Seric fclose(cf); 5739381Seric FileName = NULL; 57456836Seric 57568481Seric /* initialize host maps from local service tables */ 57668481Seric inithostmaps(); 57768481Seric 57868481Seric /* determine if we need to do special name-server frotz */ 57967905Seric { 58068481Seric int nmaps; 58168481Seric char *maptype[MAXMAPSTACK]; 58268481Seric short mapreturn[MAXMAPACTIONS]; 58368481Seric 58468481Seric nmaps = switch_map_find("hosts", maptype, mapreturn); 58568481Seric UseNameServer = FALSE; 58668481Seric if (nmaps > 0 && nmaps <= MAXMAPSTACK) 58768481Seric { 58868481Seric register int mapno; 58968481Seric 59068481Seric for (mapno = 0; mapno < nmaps && !UseNameServer; mapno++) 59168481Seric { 59268481Seric if (strcmp(maptype[mapno], "dns") == 0) 59368481Seric UseNameServer = TRUE; 59468481Seric } 59568481Seric } 59668481Seric 59768481Seric #ifdef HESIOD 59868481Seric nmaps = switch_map_find("passwd", maptype, mapreturn); 59968481Seric UseHesiod = FALSE; 60068481Seric if (nmaps > 0 && nmaps <= MAXMAPSTACK) 60168481Seric { 60268481Seric register int mapno; 60368481Seric 60468481Seric for (mapno = 0; mapno < nmaps && !UseHesiod; mapno++) 60568481Seric { 60668481Seric if (strcmp(maptype[mapno], "hesiod") == 0) 60768481Seric UseHesiod = TRUE; 60868481Seric } 60968481Seric } 61068204Seric #endif 61167905Seric } 6124096Seric } 6134096Seric /* 6148547Seric ** TOOMANY -- signal too many of some option 6158547Seric ** 6168547Seric ** Parameters: 6178547Seric ** id -- the id of the error line 6188547Seric ** maxcnt -- the maximum possible values 6198547Seric ** 6208547Seric ** Returns: 6218547Seric ** none. 6228547Seric ** 6238547Seric ** Side Effects: 6248547Seric ** gives a syserr. 6258547Seric */ 6268547Seric 6278547Seric toomany(id, maxcnt) 6288547Seric char id; 6298547Seric int maxcnt; 6308547Seric { 6319381Seric syserr("too many %c lines, %d max", id, maxcnt); 6328547Seric } 6338547Seric /* 6344432Seric ** FILECLASS -- read members of a class from a file 6354432Seric ** 6364432Seric ** Parameters: 6374432Seric ** class -- class to define. 6384432Seric ** filename -- name of file to read. 6394432Seric ** fmt -- scanf string to use for match. 64064133Seric ** safe -- if set, this is a safe read. 64164133Seric ** optional -- if set, it is not an error for the file to 64264133Seric ** not exist. 6434432Seric ** 6444432Seric ** Returns: 6454432Seric ** none 6464432Seric ** 6474432Seric ** Side Effects: 6484432Seric ** 6494432Seric ** puts all lines in filename that match a scanf into 6504432Seric ** the named class. 6514432Seric */ 6524432Seric 65364133Seric fileclass(class, filename, fmt, safe, optional) 6544432Seric int class; 6554432Seric char *filename; 6564432Seric char *fmt; 65754973Seric bool safe; 65864133Seric bool optional; 6594432Seric { 66025808Seric FILE *f; 66154973Seric struct stat stbuf; 6624432Seric char buf[MAXLINE]; 6634432Seric 66466101Seric if (tTd(37, 2)) 66566101Seric printf("fileclass(%s, fmt=%s)\n", filename, fmt); 66666101Seric 66766031Seric if (filename[0] == '|') 66866031Seric { 66966031Seric syserr("fileclass: pipes (F%c%s) not supported due to security problems", 67066031Seric class, filename); 67166031Seric return; 67266031Seric } 67354973Seric if (stat(filename, &stbuf) < 0) 67454973Seric { 67566101Seric if (tTd(37, 2)) 67666101Seric printf(" cannot stat (%s)\n", errstring(errno)); 67764133Seric if (!optional) 67864133Seric syserr("fileclass: cannot stat %s", filename); 67954973Seric return; 68054973Seric } 68154973Seric if (!S_ISREG(stbuf.st_mode)) 68254973Seric { 68354973Seric syserr("fileclass: %s not a regular file", filename); 68454973Seric return; 68554973Seric } 68654973Seric if (!safe && access(filename, R_OK) < 0) 68754973Seric { 68854973Seric syserr("fileclass: access denied on %s", filename); 68954973Seric return; 69054973Seric } 69154973Seric f = fopen(filename, "r"); 6924432Seric if (f == NULL) 6934432Seric { 69454973Seric syserr("fileclass: cannot open %s", filename); 6954432Seric return; 6964432Seric } 6974432Seric 6984432Seric while (fgets(buf, sizeof buf, f) != NULL) 6994432Seric { 7004432Seric register STAB *s; 70125808Seric register char *p; 70225808Seric # ifdef SCANF 7034432Seric char wordbuf[MAXNAME+1]; 7044432Seric 7054432Seric if (sscanf(buf, fmt, wordbuf) != 1) 7064432Seric continue; 70725808Seric p = wordbuf; 70856795Seric # else /* SCANF */ 70925808Seric p = buf; 71056795Seric # endif /* SCANF */ 71125808Seric 71225808Seric /* 71325808Seric ** Break up the match into words. 71425808Seric */ 71525808Seric 71625808Seric while (*p != '\0') 71725808Seric { 71825808Seric register char *q; 71925808Seric 72025808Seric /* strip leading spaces */ 72158050Seric while (isascii(*p) && isspace(*p)) 72225808Seric p++; 72325808Seric if (*p == '\0') 72425808Seric break; 72525808Seric 72625808Seric /* find the end of the word */ 72725808Seric q = p; 72858050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 72925808Seric p++; 73025808Seric if (*p != '\0') 73125808Seric *p++ = '\0'; 73225808Seric 73325808Seric /* enter the word in the symbol table */ 73466101Seric setclass(class, q); 73525808Seric } 7364432Seric } 7374432Seric 73854973Seric (void) fclose(f); 7394432Seric } 7404432Seric /* 7414096Seric ** MAKEMAILER -- define a new mailer. 7424096Seric ** 7434096Seric ** Parameters: 74410327Seric ** line -- description of mailer. This is in labeled 74510327Seric ** fields. The fields are: 74668481Seric ** A -- the argv for this mailer 74768481Seric ** C -- the character set for MIME conversions 74868481Seric ** D -- the directory to run in 74968481Seric ** E -- the eol string 75068481Seric ** F -- the flags associated with the mailer 75168481Seric ** L -- the maximum line length 75268481Seric ** M -- the maximum message size 75368479Seric ** P -- the path to the mailer 75468481Seric ** R -- the recipient rewriting set 75568479Seric ** S -- the sender rewriting set 75668481Seric ** T -- the mailer type (for DSNs) 75768481Seric ** U -- the uid to run as 75810327Seric ** The first word is the canonical name of the mailer. 7594096Seric ** 7604096Seric ** Returns: 7614096Seric ** none. 7624096Seric ** 7634096Seric ** Side Effects: 7644096Seric ** enters the mailer into the mailer table. 7654096Seric */ 7663308Seric 76721066Seric makemailer(line) 7684096Seric char *line; 7694096Seric { 7704096Seric register char *p; 7718067Seric register struct mailer *m; 7728067Seric register STAB *s; 7738067Seric int i; 77410327Seric char fcode; 77558020Seric auto char *endp; 7764096Seric extern int NextMailer; 77710327Seric extern char **makeargv(); 77810327Seric extern char *munchstring(); 77910701Seric extern long atol(); 7804096Seric 78110327Seric /* allocate a mailer and set up defaults */ 78210327Seric m = (struct mailer *) xalloc(sizeof *m); 78310327Seric bzero((char *) m, sizeof *m); 78410327Seric m->m_eol = "\n"; 78568481Seric m->m_uid = m->m_gid = 0; 78610327Seric 78710327Seric /* collect the mailer name */ 78858050Seric for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++) 78910327Seric continue; 79010327Seric if (*p != '\0') 79110327Seric *p++ = '\0'; 79210327Seric m->m_name = newstr(line); 79310327Seric 79410327Seric /* now scan through and assign info from the fields */ 79510327Seric while (*p != '\0') 79610327Seric { 79758333Seric auto char *delimptr; 79858333Seric 79958050Seric while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p)))) 80010327Seric p++; 80110327Seric 80210327Seric /* p now points to field code */ 80310327Seric fcode = *p; 80410327Seric while (*p != '\0' && *p != '=' && *p != ',') 80510327Seric p++; 80610327Seric if (*p++ != '=') 80710327Seric { 80852637Seric syserr("mailer %s: `=' expected", m->m_name); 80910327Seric return; 81010327Seric } 81158050Seric while (isascii(*p) && isspace(*p)) 81210327Seric p++; 81310327Seric 81410327Seric /* p now points to the field body */ 81558333Seric p = munchstring(p, &delimptr); 81610327Seric 81710327Seric /* install the field into the mailer struct */ 81810327Seric switch (fcode) 81910327Seric { 82010327Seric case 'P': /* pathname */ 82110327Seric m->m_mailer = newstr(p); 82210327Seric break; 82310327Seric 82410327Seric case 'F': /* flags */ 82510687Seric for (; *p != '\0'; p++) 82658050Seric if (!(isascii(*p) && isspace(*p))) 82752637Seric setbitn(*p, m->m_flags); 82810327Seric break; 82910327Seric 83010327Seric case 'S': /* sender rewriting ruleset */ 83110327Seric case 'R': /* recipient rewriting ruleset */ 83258020Seric i = strtol(p, &endp, 10); 83310327Seric if (i < 0 || i >= MAXRWSETS) 83410327Seric { 83510327Seric syserr("invalid rewrite set, %d max", MAXRWSETS); 83610327Seric return; 83710327Seric } 83810327Seric if (fcode == 'S') 83958020Seric m->m_sh_rwset = m->m_se_rwset = i; 84010327Seric else 84158020Seric m->m_rh_rwset = m->m_re_rwset = i; 84258020Seric 84358020Seric p = endp; 84459985Seric if (*p++ == '/') 84558020Seric { 84658020Seric i = strtol(p, NULL, 10); 84758020Seric if (i < 0 || i >= MAXRWSETS) 84858020Seric { 84958020Seric syserr("invalid rewrite set, %d max", 85058020Seric MAXRWSETS); 85158020Seric return; 85258020Seric } 85358020Seric if (fcode == 'S') 85458020Seric m->m_sh_rwset = i; 85558020Seric else 85658020Seric m->m_rh_rwset = i; 85758020Seric } 85810327Seric break; 85910327Seric 86010327Seric case 'E': /* end of line string */ 86110327Seric m->m_eol = newstr(p); 86210327Seric break; 86310327Seric 86410327Seric case 'A': /* argument vector */ 86510327Seric m->m_argv = makeargv(p); 86610327Seric break; 86710701Seric 86810701Seric case 'M': /* maximum message size */ 86910701Seric m->m_maxsize = atol(p); 87010701Seric break; 87152106Seric 87252106Seric case 'L': /* maximum line length */ 87352106Seric m->m_linelimit = atoi(p); 87452106Seric break; 87558935Seric 87658935Seric case 'D': /* working directory */ 87758935Seric m->m_execdir = newstr(p); 87858935Seric break; 87968481Seric 88068481Seric case 'C': /* default charset */ 88168481Seric m->m_defcharset = newstr(p); 88268481Seric break; 88368481Seric 88468481Seric case 'T': /* MTA Type */ 88568481Seric m->m_mtatype = newstr(p); 88668481Seric p = strchr(m->m_mtatype, '/'); 88768481Seric if (p != NULL) 88868481Seric { 88968481Seric *p++ = '\0'; 89068481Seric if (*p == '\0') 89168481Seric p = NULL; 89268481Seric } 89368481Seric if (p == NULL) 89468481Seric m->m_addrtype = m->m_mtatype; 89568481Seric else 89668481Seric { 89768481Seric m->m_addrtype = p; 89868481Seric p = strchr(p, '/'); 89968481Seric } 90068481Seric if (p != NULL) 90168481Seric { 90268481Seric *p++ = '\0'; 90368481Seric if (*p == '\0') 90468481Seric p = NULL; 90568481Seric } 90668481Seric if (p == NULL) 90768481Seric m->m_diagtype = m->m_mtatype; 90868481Seric else 90968481Seric m->m_diagtype = p; 91068481Seric break; 91168481Seric 91268481Seric case 'U': /* user id */ 91368481Seric if (isascii(*p) && !isdigit(*p)) 91468481Seric { 91568481Seric char *q = p; 91668481Seric struct passwd *pw; 91768481Seric 91868481Seric while (isascii(*p) && isalnum(*p)) 91968481Seric p++; 92068481Seric while (isascii(*p) && isspace(*p)) 92168481Seric *p++ = '\0'; 92268481Seric if (*p != '\0') 92368481Seric *p++ = '\0'; 92468481Seric pw = getpwnam(q); 92568481Seric if (pw == NULL) 92668481Seric syserr("readcf: mailer U= flag: unknown user %s", q); 92768481Seric else 92868481Seric { 92968481Seric m->m_uid = pw->pw_uid; 93068481Seric m->m_gid = pw->pw_gid; 93168481Seric } 93268481Seric } 93368481Seric else 93468481Seric { 93568481Seric auto char *q; 93668481Seric 93768481Seric m->m_uid = strtol(p, &q, 0); 93868481Seric p = q; 93968481Seric } 94068481Seric while (isascii(*p) && isspace(*p)) 94168481Seric p++; 94268481Seric if (*p == '\0') 94368481Seric break; 94468481Seric if (isascii(*p) && !isdigit(*p)) 94568481Seric { 94668481Seric char *q = p; 94768481Seric struct group *gr; 94868481Seric 94968481Seric while (isascii(*p) && isalnum(*p)) 95068481Seric p++; 95168481Seric *p++ = '\0'; 95268481Seric gr = getgrnam(q); 95368481Seric if (gr == NULL) 95468481Seric syserr("readcf: mailer U= flag: unknown group %s", q); 95568481Seric else 95668481Seric m->m_gid = gr->gr_gid; 95768481Seric } 95868481Seric else 95968481Seric { 96068481Seric m->m_gid = strtol(p, NULL, 0); 96168481Seric } 96268481Seric break; 96310327Seric } 96410327Seric 96558333Seric p = delimptr; 96610327Seric } 96710327Seric 96858321Seric /* do some rationality checking */ 96958321Seric if (m->m_argv == NULL) 97058321Seric { 97158321Seric syserr("M%s: A= argument required", m->m_name); 97258321Seric return; 97358321Seric } 97458321Seric if (m->m_mailer == NULL) 97558321Seric { 97658321Seric syserr("M%s: P= argument required", m->m_name); 97758321Seric return; 97858321Seric } 97958321Seric 9804096Seric if (NextMailer >= MAXMAILERS) 9814096Seric { 9829381Seric syserr("too many mailers defined (%d max)", MAXMAILERS); 9834096Seric return; 9844096Seric } 98557402Seric 98668481Seric /* do some heuristic cleanup for back compatibility */ 98768481Seric if (bitnset(M_LIMITS, m->m_flags)) 98868481Seric { 98968481Seric if (m->m_linelimit == 0) 99068481Seric m->m_linelimit = SMTPLINELIM; 99168481Seric if (ConfigLevel < 2) 99268481Seric setbitn(M_7BITS, m->m_flags); 99368481Seric } 99468481Seric 99568481Seric if (ConfigLevel < 6 && 99668481Seric (strcmp(m->m_mailer, "[IPC]") == 0 || 99768481Seric strcmp(m->m_mailer, "[TCP]") == 0)) 99868481Seric { 99968481Seric if (m->m_mtatype == NULL) 100068481Seric m->m_mtatype = "dns"; 100168481Seric if (m->m_addrtype == NULL) 100268481Seric m->m_addrtype = "rfc822"; 100368481Seric if (m->m_diagtype == NULL) 100468481Seric m->m_diagtype = "smtp"; 100568481Seric } 100668481Seric 100768481Seric /* enter the mailer into the symbol table */ 100810327Seric s = stab(m->m_name, ST_MAILER, ST_ENTER); 100957402Seric if (s->s_mailer != NULL) 101057402Seric { 101157402Seric i = s->s_mailer->m_mno; 101257402Seric free(s->s_mailer); 101357402Seric } 101457402Seric else 101557402Seric { 101657402Seric i = NextMailer++; 101757402Seric } 101857402Seric Mailer[i] = s->s_mailer = m; 101957454Seric m->m_mno = i; 102010327Seric } 102110327Seric /* 102210327Seric ** MUNCHSTRING -- translate a string into internal form. 102310327Seric ** 102410327Seric ** Parameters: 102510327Seric ** p -- the string to munch. 102658333Seric ** delimptr -- if non-NULL, set to the pointer of the 102758333Seric ** field delimiter character. 102810327Seric ** 102910327Seric ** Returns: 103010327Seric ** the munched string. 103110327Seric */ 10324096Seric 103310327Seric char * 103458333Seric munchstring(p, delimptr) 103510327Seric register char *p; 103658333Seric char **delimptr; 103710327Seric { 103810327Seric register char *q; 103910327Seric bool backslash = FALSE; 104010327Seric bool quotemode = FALSE; 104110327Seric static char buf[MAXLINE]; 10424096Seric 104310327Seric for (q = buf; *p != '\0'; p++) 10444096Seric { 104510327Seric if (backslash) 104610327Seric { 104710327Seric /* everything is roughly literal */ 104810357Seric backslash = FALSE; 104910327Seric switch (*p) 105010327Seric { 105110327Seric case 'r': /* carriage return */ 105210327Seric *q++ = '\r'; 105310327Seric continue; 105410327Seric 105510327Seric case 'n': /* newline */ 105610327Seric *q++ = '\n'; 105710327Seric continue; 105810327Seric 105910327Seric case 'f': /* form feed */ 106010327Seric *q++ = '\f'; 106110327Seric continue; 106210327Seric 106310327Seric case 'b': /* backspace */ 106410327Seric *q++ = '\b'; 106510327Seric continue; 106610327Seric } 106710327Seric *q++ = *p; 106810327Seric } 106910327Seric else 107010327Seric { 107110327Seric if (*p == '\\') 107210327Seric backslash = TRUE; 107310327Seric else if (*p == '"') 107410327Seric quotemode = !quotemode; 107510327Seric else if (quotemode || *p != ',') 107610327Seric *q++ = *p; 107710327Seric else 107810327Seric break; 107910327Seric } 10804096Seric } 10814096Seric 108258333Seric if (delimptr != NULL) 108358333Seric *delimptr = p; 108410327Seric *q++ = '\0'; 108510327Seric return (buf); 108610327Seric } 108710327Seric /* 108810327Seric ** MAKEARGV -- break up a string into words 108910327Seric ** 109010327Seric ** Parameters: 109110327Seric ** p -- the string to break up. 109210327Seric ** 109310327Seric ** Returns: 109410327Seric ** a char **argv (dynamically allocated) 109510327Seric ** 109610327Seric ** Side Effects: 109710327Seric ** munges p. 109810327Seric */ 10994096Seric 110010327Seric char ** 110110327Seric makeargv(p) 110210327Seric register char *p; 110310327Seric { 110410327Seric char *q; 110510327Seric int i; 110610327Seric char **avp; 110710327Seric char *argv[MAXPV + 1]; 110810327Seric 110910327Seric /* take apart the words */ 111010327Seric i = 0; 111110327Seric while (*p != '\0' && i < MAXPV) 11124096Seric { 111310327Seric q = p; 111458050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 111510327Seric p++; 111658050Seric while (isascii(*p) && isspace(*p)) 111710327Seric *p++ = '\0'; 111810327Seric argv[i++] = newstr(q); 11194096Seric } 112010327Seric argv[i++] = NULL; 11214096Seric 112210327Seric /* now make a copy of the argv */ 112310327Seric avp = (char **) xalloc(sizeof *avp * i); 112416893Seric bcopy((char *) argv, (char *) avp, sizeof *avp * i); 112510327Seric 112610327Seric return (avp); 11273308Seric } 11283308Seric /* 11293308Seric ** PRINTRULES -- print rewrite rules (for debugging) 11303308Seric ** 11313308Seric ** Parameters: 11323308Seric ** none. 11333308Seric ** 11343308Seric ** Returns: 11353308Seric ** none. 11363308Seric ** 11373308Seric ** Side Effects: 11383308Seric ** prints rewrite rules. 11393308Seric */ 11403308Seric 11413308Seric printrules() 11423308Seric { 11433308Seric register struct rewrite *rwp; 11444072Seric register int ruleset; 11453308Seric 11464072Seric for (ruleset = 0; ruleset < 10; ruleset++) 11473308Seric { 11484072Seric if (RewriteRules[ruleset] == NULL) 11494072Seric continue; 11508067Seric printf("\n----Rule Set %d:", ruleset); 11513308Seric 11524072Seric for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 11533308Seric { 11548067Seric printf("\nLHS:"); 11558067Seric printav(rwp->r_lhs); 11568067Seric printf("RHS:"); 11578067Seric printav(rwp->r_rhs); 11583308Seric } 11593308Seric } 11603308Seric } 116168481Seric /* 116268481Seric ** PRINTMAILER -- print mailer structure (for debugging) 116368481Seric ** 116468481Seric ** Parameters: 116568481Seric ** m -- the mailer to print 116668481Seric ** 116768481Seric ** Returns: 116868481Seric ** none. 116968481Seric */ 11704319Seric 117168481Seric printmailer(m) 117268481Seric register MAILER *m; 117368481Seric { 117468481Seric int j; 117568481Seric 117668481Seric printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld U=%d:%d F=", 117768481Seric m->m_mno, m->m_name, 117868481Seric m->m_mailer, m->m_se_rwset, m->m_sh_rwset, 117968481Seric m->m_re_rwset, m->m_rh_rwset, m->m_maxsize, 118068481Seric m->m_uid, m->m_gid); 118168481Seric for (j = '\0'; j <= '\177'; j++) 118268481Seric if (bitnset(j, m->m_flags)) 118368481Seric (void) putchar(j); 118468481Seric printf(" L=%d E=", m->m_linelimit); 118568481Seric xputs(m->m_eol); 118668481Seric if (m->m_defcharset != NULL) 118768481Seric printf(" C=%s", m->m_defcharset); 118868481Seric printf(" T=%s/%s/%s", 118968481Seric m->m_mtatype == NULL ? "<undefined>" : m->m_mtatype, 119068481Seric m->m_addrtype == NULL ? "<undefined>" : m->m_addrtype, 119168481Seric m->m_diagtype == NULL ? "<undefined>" : m->m_diagtype); 119268481Seric if (m->m_argv != NULL) 119368481Seric { 119468481Seric char **a = m->m_argv; 119568481Seric 119668481Seric printf(" A="); 119768481Seric while (*a != NULL) 119868481Seric { 119968481Seric if (a != m->m_argv) 120068481Seric printf(" "); 120168481Seric xputs(*a++); 120268481Seric } 120368481Seric } 120468481Seric printf("\n"); 120568481Seric } 12064096Seric /* 12078256Seric ** SETOPTION -- set global processing option 12088256Seric ** 12098256Seric ** Parameters: 12108256Seric ** opt -- option name. 12118256Seric ** val -- option value (as a text string). 121221755Seric ** safe -- set if this came from a configuration file. 121321755Seric ** Some options (if set from the command line) will 121421755Seric ** reset the user id to avoid security problems. 12158269Seric ** sticky -- if set, don't let other setoptions override 12168269Seric ** this value. 121758734Seric ** e -- the main envelope. 12188256Seric ** 12198256Seric ** Returns: 12208256Seric ** none. 12218256Seric ** 12228256Seric ** Side Effects: 12238256Seric ** Sets options as implied by the arguments. 12248256Seric */ 12258256Seric 122610687Seric static BITMAP StickyOpt; /* set if option is stuck */ 12278269Seric 122857207Seric 122966334Seric #if NAMED_BIND 123057207Seric 123157207Seric struct resolverflags 123257207Seric { 123357207Seric char *rf_name; /* name of the flag */ 123457207Seric long rf_bits; /* bits to set/clear */ 123557207Seric } ResolverFlags[] = 123657207Seric { 123757207Seric "debug", RES_DEBUG, 123857207Seric "aaonly", RES_AAONLY, 123957207Seric "usevc", RES_USEVC, 124057207Seric "primary", RES_PRIMARY, 124157207Seric "igntc", RES_IGNTC, 124257207Seric "recurse", RES_RECURSE, 124357207Seric "defnames", RES_DEFNAMES, 124457207Seric "stayopen", RES_STAYOPEN, 124557207Seric "dnsrch", RES_DNSRCH, 124665583Seric "true", 0, /* to avoid error on old syntax */ 124757207Seric NULL, 0 124857207Seric }; 124957207Seric 125057207Seric #endif 125157207Seric 125268481Seric struct optioninfo 125368481Seric { 125468481Seric char *o_name; /* long name of option */ 125568481Seric u_char o_code; /* short name of option */ 125668481Seric bool o_safe; /* safe for random people to use */ 125768481Seric } OptionTab[] = 125868481Seric { 125968481Seric "SevenBitInput", '7', TRUE, 126068481Seric "EightBitMode", '8', TRUE, 126168481Seric "AliasFile", 'A', FALSE, 126268481Seric "AliasWait", 'a', FALSE, 126368481Seric "BlankSub", 'B', FALSE, 126468481Seric "MinFreeBlocks", 'b', TRUE, 126568481Seric "CheckpointInterval", 'C', TRUE, 126668481Seric "HoldExpensive", 'c', FALSE, 126768481Seric "AutoRebuildAliases", 'D', FALSE, 126868481Seric "DeliveryMode", 'd', TRUE, 126968481Seric "ErrorHeader", 'E', FALSE, 127068481Seric "ErrorMode", 'e', TRUE, 127168481Seric "TempFileMode", 'F', FALSE, 127268481Seric "SaveFromLine", 'f', FALSE, 127368481Seric "MatchGECOS", 'G', FALSE, 127468481Seric "HelpFile", 'H', FALSE, 127568481Seric "MaxHopCount", 'h', FALSE, 127668481Seric "NameServerOptions", 'I', FALSE, 127768481Seric "IgnoreDots", 'i', TRUE, 127868481Seric "ForwardPath", 'J', FALSE, 127968481Seric "SendMimeErrors", 'j', TRUE, 128068481Seric "ConnectionCacheSize", 'k', FALSE, 128168481Seric "ConnectionCacheTimeout", 'K', FALSE, 128268481Seric "UseErrorsTo", 'l', FALSE, 128368481Seric "LogLevel", 'L', FALSE, 128468481Seric "MeToo", 'm', TRUE, 128568481Seric "CheckAliases", 'n', FALSE, 128668481Seric "OldStyleHeaders", 'o', TRUE, 128768481Seric "DaemonPortOptions", 'O', FALSE, 128868481Seric "PrivacyOptions", 'p', TRUE, 128968481Seric "PostmasterCopy", 'P', FALSE, 129068481Seric "QueueFactor", 'q', FALSE, 129168481Seric "QueueDirectory", 'Q', FALSE, 129268481Seric "DontPruneRoutes", 'R', FALSE, 129368481Seric "Timeout", 'r', TRUE, 129468481Seric "StatusFile", 'S', FALSE, 129568481Seric "SuperSafe", 's', TRUE, 129668481Seric "QueueTimeout", 'T', FALSE, 129768481Seric "TimeZoneSpec", 't', FALSE, 129868481Seric "UserDatabaseSpec", 'U', FALSE, 129968481Seric "DefaultUser", 'u', FALSE, 130068481Seric "FallbackMXhost", 'V', FALSE, 130168481Seric "Verbose", 'v', TRUE, 130268481Seric "TryNullMXList", 'w', TRUE, 130368481Seric "QueueLA", 'x', FALSE, 130468481Seric "RefuseLA", 'X', FALSE, 130568481Seric "RecipientFactor", 'y', FALSE, 130668481Seric "ForkQueueRuns", 'Y', FALSE, 130768481Seric "ClassFactor", 'z', FALSE, 130868481Seric "TimeFactor", 'Z', FALSE, 130968481Seric #define O_BSP 0x80 131068481Seric "BrokenSmtpPeers", O_BSP, TRUE, 131168481Seric #define O_QUEUESORTORD 0x81 131268481Seric "QueueSortOrder", O_QUEUESORTORD, TRUE, 131368481Seric #define O_MQA 0x83 131468481Seric "MinQueueAge", O_MQA, TRUE, 131568481Seric #define O_MHSA 0x84 131668481Seric /* 131768481Seric "MaxHostStatAge", O_MHSA, TRUE, 131868481Seric */ 131968481Seric #define O_DEFCHARSET 0x85 132068481Seric "DefaultCharSet", O_DEFCHARSET, TRUE, 132168481Seric #define O_SSFILE 0x86 132268481Seric "ServiceSwitchFile", O_SSFILE, FALSE, 132368481Seric #define O_DIALDELAY 0x87 132468481Seric "DialDelay", O_DIALDELAY, TRUE, 132568481Seric #define O_NORCPTACTION 0x88 132668481Seric "NoRecipientAction", O_NORCPTACTION, TRUE, 1327*68490Seric #define O_SAFEFILEENV 0x89 1328*68490Seric "SafeFileEnvironment", O_SAFEFILEENV, FALSE, 132968481Seric 133068481Seric NULL, '\0', FALSE, 133168481Seric }; 133268481Seric 133368481Seric 133468481Seric 133558734Seric setoption(opt, val, safe, sticky, e) 133668481Seric u_char opt; 13378256Seric char *val; 133821755Seric bool safe; 13398269Seric bool sticky; 134058734Seric register ENVELOPE *e; 13418256Seric { 134257207Seric register char *p; 134368481Seric register struct optioninfo *o; 134468481Seric char *subopt; 13458265Seric extern bool atobool(); 134612633Seric extern time_t convtime(); 134714879Seric extern int QueueLA; 134814879Seric extern int RefuseLA; 134964718Seric extern bool Warn_Q_option; 13508256Seric 135168481Seric errno = 0; 135268481Seric if (opt == ' ') 135368481Seric { 135468481Seric /* full word options */ 135568481Seric struct optioninfo *sel; 135668481Seric 135768481Seric p = strchr(val, '='); 135868481Seric if (p == NULL) 135968481Seric p = &val[strlen(val)]; 136068481Seric while (*--p == ' ') 136168481Seric continue; 136268481Seric while (*++p == ' ') 136368481Seric *p = '\0'; 136468481Seric if (p == val) 136568481Seric { 136668481Seric syserr("readcf: null option name"); 136768481Seric return; 136868481Seric } 136968481Seric if (*p == '=') 137068481Seric *p++ = '\0'; 137168481Seric while (*p == ' ') 137268481Seric p++; 137368481Seric subopt = strchr(val, '.'); 137468481Seric if (subopt != NULL) 137568481Seric *subopt++ = '\0'; 137668481Seric sel = NULL; 137768481Seric for (o = OptionTab; o->o_name != NULL; o++) 137868481Seric { 137968481Seric if (strncasecmp(o->o_name, val, strlen(val)) != 0) 138068481Seric continue; 138168481Seric if (strlen(o->o_name) == strlen(val)) 138268481Seric { 138368481Seric /* completely specified -- this must be it */ 138468481Seric sel = NULL; 138568481Seric break; 138668481Seric } 138768481Seric if (sel != NULL) 138868481Seric break; 138968481Seric sel = o; 139068481Seric } 139168481Seric if (sel != NULL && o->o_name == NULL) 139268481Seric o = sel; 139368481Seric else if (o->o_name == NULL) 139468481Seric { 139568481Seric syserr("readcf: unknown option name %s", val); 139668481Seric return; 139768481Seric } 139868481Seric else if (sel != NULL) 139968481Seric { 140068481Seric syserr("readcf: ambiguous option name %s (matches %s and %s)", 140168481Seric val, sel->o_name, o->o_name); 140268481Seric return; 140368481Seric } 140468481Seric if (strlen(val) != strlen(o->o_name)) 140568481Seric { 140668481Seric bool oldVerbose = Verbose; 140768481Seric 140868481Seric Verbose = TRUE; 140968481Seric message("Option %s used as abbreviation for %s", 141068481Seric val, o->o_name); 141168481Seric Verbose = oldVerbose; 141268481Seric } 141368481Seric opt = o->o_code; 141468481Seric val = p; 141568481Seric } 141668481Seric else 141768481Seric { 141868481Seric for (o = OptionTab; o->o_name != NULL; o++) 141968481Seric { 142068481Seric if (o->o_code == opt) 142168481Seric break; 142268481Seric } 142368481Seric subopt = NULL; 142468481Seric } 142568481Seric 14268256Seric if (tTd(37, 1)) 142768481Seric { 142868481Seric printf(isascii(opt) && isprint(opt) ? 142968481Seric "setoption %s (%c).%s=%s" : 143068481Seric "setoption %s (0x%x).%s=%s", 143168481Seric o->o_name == NULL ? "<unknown>" : o->o_name, 143268481Seric opt, 143368481Seric subopt == NULL ? "" : subopt, 143468481Seric val); 143568481Seric } 14368256Seric 14378256Seric /* 14388269Seric ** See if this option is preset for us. 14398256Seric */ 14408256Seric 144159731Seric if (!sticky && bitnset(opt, StickyOpt)) 14428269Seric { 14439341Seric if (tTd(37, 1)) 14449341Seric printf(" (ignored)\n"); 14458269Seric return; 14468269Seric } 14478269Seric 144821755Seric /* 144921755Seric ** Check to see if this option can be specified by this user. 145021755Seric */ 145121755Seric 145263787Seric if (!safe && RealUid == 0) 145321755Seric safe = TRUE; 145468481Seric if (!safe && !o->o_safe) 145521755Seric { 145639111Srick if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 145721755Seric { 145836582Sbostic if (tTd(37, 1)) 145936582Sbostic printf(" (unsafe)"); 146063787Seric if (RealUid != geteuid()) 146136582Sbostic { 146251210Seric if (tTd(37, 1)) 146351210Seric printf("(Resetting uid)"); 146463787Seric (void) setgid(RealGid); 146563787Seric (void) setuid(RealUid); 146636582Sbostic } 146721755Seric } 146821755Seric } 146951210Seric if (tTd(37, 1)) 147017985Seric printf("\n"); 14718269Seric 147268481Seric switch (opt & 0xff) 14738256Seric { 147459709Seric case '7': /* force seven-bit input */ 147568481Seric SevenBitInput = atobool(val); 147652106Seric break; 147752106Seric 147868481Seric case '8': /* handling of 8-bit input */ 147968481Seric switch (*val) 148068481Seric { 148168481Seric case 'r': /* reject 8-bit, don't convert MIME */ 148268481Seric MimeMode = 0; 148368481Seric break; 148468481Seric 148568481Seric case 'm': /* convert 8-bit, convert MIME */ 148668481Seric MimeMode = MM_CVTMIME|MM_MIME8BIT; 148768481Seric break; 148868481Seric 148968481Seric case 'j': /* "just send 8" */ 149068481Seric MimeMode = MM_PASS8BIT; 149168481Seric break; 149268481Seric 149368481Seric case 'p': /* pass 8 bit, convert MIME */ 149468481Seric MimeMode = MM_PASS8BIT|MM_CVTMIME; 149568481Seric break; 149668481Seric 149768481Seric case 's': /* strict adherence */ 149868481Seric MimeMode = MM_CVTMIME; 149968481Seric break; 150068481Seric 150168481Seric case 'a': /* encode 8 bit if available */ 150268481Seric MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 150368481Seric break; 150468481Seric 150568481Seric case 'c': /* convert 8 bit to MIME, never 7 bit */ 150668481Seric MimeMode = MM_MIME8BIT; 150768481Seric break; 150868481Seric 150968481Seric default: 151068481Seric syserr("Unknown 8-bit mode %c", *val); 151168481Seric exit(EX_USAGE); 151268481Seric } 151368481Seric break; 151468481Seric 15158256Seric case 'A': /* set default alias file */ 15169381Seric if (val[0] == '\0') 151759672Seric setalias("aliases"); 15189381Seric else 151959672Seric setalias(val); 15208256Seric break; 15218256Seric 152217474Seric case 'a': /* look N minutes for "@:@" in alias file */ 152317474Seric if (val[0] == '\0') 152464796Seric SafeAlias = 5 * 60; /* five minutes */ 152517474Seric else 152664796Seric SafeAlias = convtime(val, 'm'); 152717474Seric break; 152817474Seric 152916843Seric case 'B': /* substitution for blank character */ 153016843Seric SpaceSub = val[0]; 153116843Seric if (SpaceSub == '\0') 153216843Seric SpaceSub = ' '; 153316843Seric break; 153416843Seric 153559283Seric case 'b': /* min blocks free on queue fs/max msg size */ 153659283Seric p = strchr(val, '/'); 153759283Seric if (p != NULL) 153859283Seric { 153959283Seric *p++ = '\0'; 154059283Seric MaxMessageSize = atol(p); 154159283Seric } 154258082Seric MinBlocksFree = atol(val); 154358082Seric break; 154458082Seric 15459284Seric case 'c': /* don't connect to "expensive" mailers */ 15469381Seric NoConnect = atobool(val); 15479284Seric break; 15489284Seric 154951305Seric case 'C': /* checkpoint every N addresses */ 155051305Seric CheckpointInterval = atoi(val); 155124944Seric break; 155224944Seric 15539284Seric case 'd': /* delivery mode */ 15549284Seric switch (*val) 15558269Seric { 15569284Seric case '\0': 155758734Seric e->e_sendmode = SM_DELIVER; 15588269Seric break; 15598269Seric 156010755Seric case SM_QUEUE: /* queue only */ 156110755Seric #ifndef QUEUE 156210755Seric syserr("need QUEUE to set -odqueue"); 156356795Seric #endif /* QUEUE */ 156410755Seric /* fall through..... */ 156510755Seric 15669284Seric case SM_DELIVER: /* do everything */ 15679284Seric case SM_FORK: /* fork after verification */ 156858734Seric e->e_sendmode = *val; 15698269Seric break; 15708269Seric 15718269Seric default: 15729284Seric syserr("Unknown delivery mode %c", *val); 15738269Seric exit(EX_USAGE); 15748269Seric } 15758269Seric break; 15768269Seric 15779146Seric case 'D': /* rebuild alias database as needed */ 15789381Seric AutoRebuild = atobool(val); 15799146Seric break; 15809146Seric 158155372Seric case 'E': /* error message header/header file */ 158255379Seric if (*val != '\0') 158355379Seric ErrMsgFile = newstr(val); 158455372Seric break; 158555372Seric 15868269Seric case 'e': /* set error processing mode */ 15878269Seric switch (*val) 15888269Seric { 15899381Seric case EM_QUIET: /* be silent about it */ 15909381Seric case EM_MAIL: /* mail back */ 15919381Seric case EM_BERKNET: /* do berknet error processing */ 15929381Seric case EM_WRITE: /* write back (or mail) */ 15939381Seric case EM_PRINT: /* print errors normally (default) */ 159458734Seric e->e_errormode = *val; 15958269Seric break; 15968269Seric } 15978269Seric break; 15988269Seric 15999049Seric case 'F': /* file mode */ 160017975Seric FileMode = atooct(val) & 0777; 16019049Seric break; 16029049Seric 16038269Seric case 'f': /* save Unix-style From lines on front */ 16049381Seric SaveFrom = atobool(val); 16058269Seric break; 16068269Seric 160753735Seric case 'G': /* match recipients against GECOS field */ 160853735Seric MatchGecos = atobool(val); 160953735Seric break; 161053735Seric 16118256Seric case 'g': /* default gid */ 161268481Seric g_opt: 161364133Seric if (isascii(*val) && isdigit(*val)) 161464133Seric DefGid = atoi(val); 161564133Seric else 161664133Seric { 161764133Seric register struct group *gr; 161864133Seric 161964133Seric DefGid = -1; 162064133Seric gr = getgrnam(val); 162164133Seric if (gr == NULL) 162268481Seric syserr("readcf: option %c: unknown group %s", 162368481Seric opt, val); 162464133Seric else 162564133Seric DefGid = gr->gr_gid; 162664133Seric } 16278256Seric break; 16288256Seric 16298256Seric case 'H': /* help file */ 16309381Seric if (val[0] == '\0') 16318269Seric HelpFile = "sendmail.hf"; 16329381Seric else 16339381Seric HelpFile = newstr(val); 16348256Seric break; 16358256Seric 163651305Seric case 'h': /* maximum hop count */ 163751305Seric MaxHopCount = atoi(val); 163851305Seric break; 163951305Seric 164035651Seric case 'I': /* use internet domain name server */ 164166334Seric #if NAMED_BIND 164257207Seric for (p = val; *p != 0; ) 164357207Seric { 164457207Seric bool clearmode; 164557207Seric char *q; 164657207Seric struct resolverflags *rfp; 164757207Seric 164857207Seric while (*p == ' ') 164957207Seric p++; 165057207Seric if (*p == '\0') 165157207Seric break; 165257207Seric clearmode = FALSE; 165357207Seric if (*p == '-') 165457207Seric clearmode = TRUE; 165557207Seric else if (*p != '+') 165657207Seric p--; 165757207Seric p++; 165857207Seric q = p; 165958050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 166057207Seric p++; 166157207Seric if (*p != '\0') 166257207Seric *p++ = '\0'; 166357207Seric for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 166457207Seric { 166557207Seric if (strcasecmp(q, rfp->rf_name) == 0) 166657207Seric break; 166757207Seric } 166864923Seric if (rfp->rf_name == NULL) 166964923Seric syserr("readcf: I option value %s unrecognized", q); 167064923Seric else if (clearmode) 167157207Seric _res.options &= ~rfp->rf_bits; 167257207Seric else 167357207Seric _res.options |= rfp->rf_bits; 167457207Seric } 167557207Seric if (tTd(8, 2)) 167657207Seric printf("_res.options = %x\n", _res.options); 167757207Seric #else 167857207Seric usrerr("name server (I option) specified but BIND not compiled in"); 167957207Seric #endif 168035651Seric break; 168135651Seric 16828269Seric case 'i': /* ignore dot lines in message */ 16839381Seric IgnrDot = atobool(val); 16848269Seric break; 16858269Seric 168659730Seric case 'j': /* send errors in MIME (RFC 1341) format */ 168759730Seric SendMIMEErrors = atobool(val); 168859730Seric break; 168959730Seric 169057136Seric case 'J': /* .forward search path */ 169157136Seric ForwardPath = newstr(val); 169257136Seric break; 169357136Seric 169454967Seric case 'k': /* connection cache size */ 169554967Seric MaxMciCache = atoi(val); 169656215Seric if (MaxMciCache < 0) 169756215Seric MaxMciCache = 0; 169854967Seric break; 169954967Seric 170054967Seric case 'K': /* connection cache timeout */ 170158796Seric MciCacheTimeout = convtime(val, 'm'); 170254967Seric break; 170354967Seric 170461104Seric case 'l': /* use Errors-To: header */ 170561104Seric UseErrorsTo = atobool(val); 170661104Seric break; 170761104Seric 17088256Seric case 'L': /* log level */ 170964140Seric if (safe || LogLevel < atoi(val)) 171064140Seric LogLevel = atoi(val); 17118256Seric break; 17128256Seric 17138269Seric case 'M': /* define macro */ 171468267Seric p = newstr(&val[1]); 171568267Seric if (!safe) 171668267Seric cleanstrcpy(p, p, MAXNAME); 171768267Seric define(val[0], p, CurEnv); 171816878Seric sticky = FALSE; 17198269Seric break; 17208269Seric 17218269Seric case 'm': /* send to me too */ 17229381Seric MeToo = atobool(val); 17238269Seric break; 17248269Seric 172525820Seric case 'n': /* validate RHS in newaliases */ 172625820Seric CheckAliases = atobool(val); 172725820Seric break; 172825820Seric 172961104Seric /* 'N' available -- was "net name" */ 173061104Seric 173158851Seric case 'O': /* daemon options */ 173258851Seric setdaemonoptions(val); 173358851Seric break; 173458851Seric 17358269Seric case 'o': /* assume old style headers */ 17369381Seric if (atobool(val)) 17379341Seric CurEnv->e_flags |= EF_OLDSTYLE; 17389341Seric else 17399341Seric CurEnv->e_flags &= ~EF_OLDSTYLE; 17408269Seric break; 17418269Seric 174258082Seric case 'p': /* select privacy level */ 174358082Seric p = val; 174458082Seric for (;;) 174558082Seric { 174658082Seric register struct prival *pv; 174758082Seric extern struct prival PrivacyValues[]; 174858082Seric 174958082Seric while (isascii(*p) && (isspace(*p) || ispunct(*p))) 175058082Seric p++; 175158082Seric if (*p == '\0') 175258082Seric break; 175358082Seric val = p; 175458082Seric while (isascii(*p) && isalnum(*p)) 175558082Seric p++; 175658082Seric if (*p != '\0') 175758082Seric *p++ = '\0'; 175858082Seric 175958082Seric for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 176058082Seric { 176158082Seric if (strcasecmp(val, pv->pv_name) == 0) 176258082Seric break; 176358082Seric } 176458886Seric if (pv->pv_name == NULL) 176558886Seric syserr("readcf: Op line: %s unrecognized", val); 176658082Seric PrivacyFlags |= pv->pv_flag; 176758082Seric } 176868479Seric sticky = FALSE; 176958082Seric break; 177058082Seric 177124944Seric case 'P': /* postmaster copy address for returned mail */ 177224944Seric PostMasterCopy = newstr(val); 177324944Seric break; 177424944Seric 177524944Seric case 'q': /* slope of queue only function */ 177624944Seric QueueFactor = atoi(val); 177724944Seric break; 177824944Seric 17798256Seric case 'Q': /* queue directory */ 17809381Seric if (val[0] == '\0') 17818269Seric QueueDir = "mqueue"; 17829381Seric else 17839381Seric QueueDir = newstr(val); 178458789Seric if (RealUid != 0 && !safe) 178564718Seric Warn_Q_option = TRUE; 17868256Seric break; 17878256Seric 178858148Seric case 'R': /* don't prune routes */ 178958148Seric DontPruneRoutes = atobool(val); 179058148Seric break; 179158148Seric 17928256Seric case 'r': /* read timeout */ 179368481Seric if (subopt == NULL) 179468481Seric inittimeouts(val); 179568481Seric else 179668481Seric settimeout(subopt, val); 17978256Seric break; 17988256Seric 17998256Seric case 'S': /* status file */ 18009381Seric if (val[0] == '\0') 18018269Seric StatFile = "sendmail.st"; 18029381Seric else 18039381Seric StatFile = newstr(val); 18048256Seric break; 18058256Seric 18068265Seric case 's': /* be super safe, even if expensive */ 18079381Seric SuperSafe = atobool(val); 18088256Seric break; 18098256Seric 18108256Seric case 'T': /* queue timeout */ 181158737Seric p = strchr(val, '/'); 181258737Seric if (p != NULL) 181358737Seric { 181458737Seric *p++ = '\0'; 181568481Seric settimeout("queuewarn", p); 181658737Seric } 181768481Seric settimeout("queuereturn", val); 181854967Seric break; 18198256Seric 18208265Seric case 't': /* time zone name */ 182152106Seric TimeZoneSpec = newstr(val); 18228265Seric break; 18238265Seric 182450556Seric case 'U': /* location of user database */ 182551360Seric UdbSpec = newstr(val); 182650556Seric break; 182750556Seric 18288256Seric case 'u': /* set default uid */ 182968481Seric for (p = val; *p != '\0'; p++) 183068481Seric { 183168481Seric if (*p == '.' || *p == '/' || *p == ':') 183268481Seric { 183368481Seric *p++ = '\0'; 183468481Seric break; 183568481Seric } 183668481Seric } 183764133Seric if (isascii(*val) && isdigit(*val)) 183864133Seric DefUid = atoi(val); 183964133Seric else 184064133Seric { 184164133Seric register struct passwd *pw; 184264133Seric 184364133Seric DefUid = -1; 184464133Seric pw = getpwnam(val); 184564133Seric if (pw == NULL) 184664133Seric syserr("readcf: option u: unknown user %s", val); 184764133Seric else 184868481Seric { 184964133Seric DefUid = pw->pw_uid; 185068481Seric DefGid = pw->pw_gid; 185168481Seric } 185264133Seric } 185340973Sbostic setdefuser(); 18548256Seric 185568481Seric /* handle the group if it is there */ 185668481Seric if (*p == '\0') 185768481Seric break; 185868481Seric val = p; 185968481Seric goto g_opt; 186068481Seric 186158851Seric case 'V': /* fallback MX host */ 186258851Seric FallBackMX = newstr(val); 186358851Seric break; 186458851Seric 18658269Seric case 'v': /* run in verbose mode */ 18669381Seric Verbose = atobool(val); 18678256Seric break; 18688256Seric 186963837Seric case 'w': /* if we are best MX, try host directly */ 187063837Seric TryNullMXList = atobool(val); 187163837Seric break; 187261104Seric 187361104Seric /* 'W' available -- was wizard password */ 187461104Seric 187514879Seric case 'x': /* load avg at which to auto-queue msgs */ 187614879Seric QueueLA = atoi(val); 187714879Seric break; 187814879Seric 187914879Seric case 'X': /* load avg at which to auto-reject connections */ 188014879Seric RefuseLA = atoi(val); 188114879Seric break; 188214879Seric 188324981Seric case 'y': /* work recipient factor */ 188424981Seric WkRecipFact = atoi(val); 188524981Seric break; 188624981Seric 188724981Seric case 'Y': /* fork jobs during queue runs */ 188824952Seric ForkQueueRuns = atobool(val); 188924952Seric break; 189024952Seric 189124981Seric case 'z': /* work message class factor */ 189224981Seric WkClassFact = atoi(val); 189324981Seric break; 189424981Seric 189524981Seric case 'Z': /* work time factor */ 189624981Seric WkTimeFact = atoi(val); 189724981Seric break; 189824981Seric 189968481Seric case O_BSP: /* SMTP Peers can't handle 2-line greeting */ 190068481Seric BrokenSmtpPeers = atobool(val); 190168481Seric break; 190268481Seric 190368481Seric case O_QUEUESORTORD: /* queue sorting order */ 190468481Seric switch (*val) 190568481Seric { 190668481Seric case 'h': /* Host first */ 190768481Seric case 'H': 190868481Seric QueueSortOrder = QS_BYHOST; 190968481Seric break; 191068481Seric 191168481Seric case 'p': /* Priority order */ 191268481Seric case 'P': 191368481Seric QueueSortOrder = QS_BYPRIORITY; 191468481Seric break; 191568481Seric 191668481Seric default: 191768481Seric syserr("Invalid queue sort order \"%s\"", val); 191868481Seric } 191968481Seric break; 192068481Seric 192168481Seric case O_MQA: /* minimum queue age between deliveries */ 192268481Seric MinQueueAge = convtime(val, 'm'); 192368481Seric break; 192468481Seric 192568481Seric case O_MHSA: /* maximum age of cached host status */ 192668481Seric MaxHostStatAge = convtime(val, 'm'); 192768481Seric break; 192868481Seric 192968481Seric case O_DEFCHARSET: /* default character set for mimefying */ 193068481Seric DefaultCharSet = newstr(denlstring(val, TRUE, TRUE)); 193168481Seric break; 193268481Seric 193368481Seric case O_SSFILE: /* service switch file */ 193468481Seric ServiceSwitchFile = newstr(val); 193568481Seric break; 193668481Seric 193768481Seric case O_DIALDELAY: /* delay for dial-on-demand operation */ 193868481Seric DialDelay = convtime(val, 's'); 193968481Seric break; 194068481Seric 194168481Seric case O_NORCPTACTION: /* what to do if no recipient */ 194268481Seric if (strcasecmp(val, "none") == 0) 194368481Seric NoRecipientAction = NRA_NO_ACTION; 194468481Seric else if (strcasecmp(val, "add-to") == 0) 194568481Seric NoRecipientAction = NRA_ADD_TO; 194668481Seric else if (strcasecmp(val, "add-apparently-to") == 0) 194768481Seric NoRecipientAction = NRA_ADD_APPARENTLY_TO; 194868481Seric else if (strcasecmp(val, "add-bcc") == 0) 194968481Seric NoRecipientAction = NRA_ADD_BCC; 195068481Seric else if (strcasecmp(val, "add-to-undisclosed") == 0) 195168481Seric NoRecipientAction = NRA_ADD_TO_UNDISCLOSED; 195268481Seric else 195368481Seric syserr("Invalid NoRecipientAction: %s", val); 195468481Seric 1955*68490Seric case O_SAFEFILEENV: /* chroot() environ for writing to files */ 1956*68490Seric SafeFileEnv = newstr(val); 1957*68490Seric break; 1958*68490Seric 19598256Seric default: 196068481Seric if (tTd(37, 1)) 196168481Seric { 196268481Seric if (isascii(opt) && isprint(opt)) 196368481Seric printf("Warning: option %c unknown\n", opt); 196468481Seric else 196568481Seric printf("Warning: option 0x%x unknown\n", opt); 196668481Seric } 19678256Seric break; 19688256Seric } 196916878Seric if (sticky) 197016878Seric setbitn(opt, StickyOpt); 19719188Seric return; 19728256Seric } 197310687Seric /* 197468481Seric ** SETCLASS -- set a string into a class 197510687Seric ** 197610687Seric ** Parameters: 197768481Seric ** class -- the class to put the string in. 197868481Seric ** str -- the string to enter 197910687Seric ** 198010687Seric ** Returns: 198110687Seric ** none. 198210687Seric ** 198310687Seric ** Side Effects: 198410687Seric ** puts the word into the symbol table. 198510687Seric */ 198610687Seric 198768481Seric setclass(class, str) 198810687Seric int class; 198968481Seric char *str; 199010687Seric { 199110687Seric register STAB *s; 199210687Seric 199357943Seric if (tTd(37, 8)) 199468481Seric printf("setclass(%c, %s)\n", class, str); 199568481Seric s = stab(str, ST_CLASS, ST_ENTER); 199610687Seric setbitn(class, s->s_class); 199710687Seric } 199853654Seric /* 199953654Seric ** MAKEMAPENTRY -- create a map entry 200053654Seric ** 200153654Seric ** Parameters: 200253654Seric ** line -- the config file line 200353654Seric ** 200453654Seric ** Returns: 200553654Seric ** TRUE if it successfully entered the map entry. 200653654Seric ** FALSE otherwise (usually syntax error). 200753654Seric ** 200853654Seric ** Side Effects: 200953654Seric ** Enters the map into the dictionary. 201053654Seric */ 201153654Seric 201253654Seric void 201353654Seric makemapentry(line) 201453654Seric char *line; 201553654Seric { 201653654Seric register char *p; 201753654Seric char *mapname; 201853654Seric char *classname; 201964078Seric register STAB *s; 202053654Seric STAB *class; 202153654Seric 202258050Seric for (p = line; isascii(*p) && isspace(*p); p++) 202353654Seric continue; 202458050Seric if (!(isascii(*p) && isalnum(*p))) 202553654Seric { 202653654Seric syserr("readcf: config K line: no map name"); 202753654Seric return; 202853654Seric } 202953654Seric 203053654Seric mapname = p; 203168481Seric while ((isascii(*++p) && isalnum(*p)) || *p == '.') 203253654Seric continue; 203353654Seric if (*p != '\0') 203453654Seric *p++ = '\0'; 203558050Seric while (isascii(*p) && isspace(*p)) 203653654Seric p++; 203758050Seric if (!(isascii(*p) && isalnum(*p))) 203853654Seric { 203953654Seric syserr("readcf: config K line, map %s: no map class", mapname); 204053654Seric return; 204153654Seric } 204253654Seric classname = p; 204358050Seric while (isascii(*++p) && isalnum(*p)) 204453654Seric continue; 204553654Seric if (*p != '\0') 204653654Seric *p++ = '\0'; 204758050Seric while (isascii(*p) && isspace(*p)) 204853654Seric p++; 204953654Seric 205053654Seric /* look up the class */ 205153654Seric class = stab(classname, ST_MAPCLASS, ST_FIND); 205253654Seric if (class == NULL) 205353654Seric { 205453654Seric syserr("readcf: map %s: class %s not available", mapname, classname); 205553654Seric return; 205653654Seric } 205753654Seric 205853654Seric /* enter the map */ 205964078Seric s = stab(mapname, ST_MAP, ST_ENTER); 206064078Seric s->s_map.map_class = &class->s_mapclass; 206164078Seric s->s_map.map_mname = newstr(mapname); 206253654Seric 206364078Seric if (class->s_mapclass.map_parse(&s->s_map, p)) 206464078Seric s->s_map.map_mflags |= MF_VALID; 206564078Seric 206664078Seric if (tTd(37, 5)) 206764078Seric { 206864078Seric printf("map %s, class %s, flags %x, file %s,\n", 206964078Seric s->s_map.map_mname, s->s_map.map_class->map_cname, 207064078Seric s->s_map.map_mflags, 207164078Seric s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 207264078Seric printf("\tapp %s, domain %s, rebuild %s\n", 207364078Seric s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 207464078Seric s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 207564078Seric s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 207664078Seric } 207753654Seric } 207858112Seric /* 207968481Seric ** INITTIMEOUTS -- parse and set timeout values 208058112Seric ** 208158112Seric ** Parameters: 208258112Seric ** val -- a pointer to the values. If NULL, do initial 208358112Seric ** settings. 208458112Seric ** 208558112Seric ** Returns: 208658112Seric ** none. 208758112Seric ** 208858112Seric ** Side Effects: 208958112Seric ** Initializes the TimeOuts structure 209058112Seric */ 209158112Seric 209264255Seric #define SECONDS 209358112Seric #define MINUTES * 60 209458112Seric #define HOUR * 3600 209558112Seric 209668481Seric inittimeouts(val) 209758112Seric register char *val; 209858112Seric { 209958112Seric register char *p; 210058671Seric extern time_t convtime(); 210158112Seric 210258112Seric if (val == NULL) 210358112Seric { 210458112Seric TimeOuts.to_initial = (time_t) 5 MINUTES; 210558112Seric TimeOuts.to_helo = (time_t) 5 MINUTES; 210658112Seric TimeOuts.to_mail = (time_t) 10 MINUTES; 210758112Seric TimeOuts.to_rcpt = (time_t) 1 HOUR; 210858112Seric TimeOuts.to_datainit = (time_t) 5 MINUTES; 210958112Seric TimeOuts.to_datablock = (time_t) 1 HOUR; 211058112Seric TimeOuts.to_datafinal = (time_t) 1 HOUR; 211158112Seric TimeOuts.to_rset = (time_t) 5 MINUTES; 211258112Seric TimeOuts.to_quit = (time_t) 2 MINUTES; 211358112Seric TimeOuts.to_nextcommand = (time_t) 1 HOUR; 211458112Seric TimeOuts.to_miscshort = (time_t) 2 MINUTES; 211568481Seric #if IDENTPROTO 211664255Seric TimeOuts.to_ident = (time_t) 30 SECONDS; 211768481Seric #else 211868481Seric TimeOuts.to_ident = (time_t) 0 SECONDS; 211968481Seric #endif 212068481Seric TimeOuts.to_fileopen = (time_t) 60 SECONDS; 212158112Seric return; 212258112Seric } 212358112Seric 212458112Seric for (;; val = p) 212558112Seric { 212658112Seric while (isascii(*val) && isspace(*val)) 212758112Seric val++; 212858112Seric if (*val == '\0') 212958112Seric break; 213058112Seric for (p = val; *p != '\0' && *p != ','; p++) 213158112Seric continue; 213258112Seric if (*p != '\0') 213358112Seric *p++ = '\0'; 213458112Seric 213558112Seric if (isascii(*val) && isdigit(*val)) 213658112Seric { 213758112Seric /* old syntax -- set everything */ 213858796Seric TimeOuts.to_mail = convtime(val, 'm'); 213958112Seric TimeOuts.to_rcpt = TimeOuts.to_mail; 214058112Seric TimeOuts.to_datainit = TimeOuts.to_mail; 214158112Seric TimeOuts.to_datablock = TimeOuts.to_mail; 214258112Seric TimeOuts.to_datafinal = TimeOuts.to_mail; 214358112Seric TimeOuts.to_nextcommand = TimeOuts.to_mail; 214458112Seric continue; 214558112Seric } 214658112Seric else 214758112Seric { 214868481Seric register char *q = strchr(val, ':'); 214958112Seric 215068481Seric if (q == NULL && (q = strchr(val, '=')) == NULL) 215158112Seric { 215258112Seric /* syntax error */ 215358112Seric continue; 215458112Seric } 215558112Seric *q++ = '\0'; 215668481Seric settimeout(val, q); 215768481Seric } 215868481Seric } 215968481Seric } 216068481Seric /* 216168481Seric ** SETTIMEOUT -- set an individual timeout 216268481Seric ** 216368481Seric ** Parameters: 216468481Seric ** name -- the name of the timeout. 216568481Seric ** val -- the value of the timeout. 216668481Seric ** 216768481Seric ** Returns: 216868481Seric ** none. 216968481Seric */ 217058112Seric 217168481Seric settimeout(name, val) 217268481Seric char *name; 217368481Seric char *val; 217468481Seric { 217568481Seric register char *p; 217668481Seric time_t to; 217768481Seric extern time_t convtime(); 217868481Seric 217968481Seric to = convtime(val, 'm'); 218068481Seric p = strchr(name, '.'); 218168481Seric if (p != NULL) 218268481Seric *p++ = '\0'; 218368481Seric 218468481Seric if (strcasecmp(name, "initial") == 0) 218568481Seric TimeOuts.to_initial = to; 218668481Seric else if (strcasecmp(name, "mail") == 0) 218768481Seric TimeOuts.to_mail = to; 218868481Seric else if (strcasecmp(name, "rcpt") == 0) 218968481Seric TimeOuts.to_rcpt = to; 219068481Seric else if (strcasecmp(name, "datainit") == 0) 219168481Seric TimeOuts.to_datainit = to; 219268481Seric else if (strcasecmp(name, "datablock") == 0) 219368481Seric TimeOuts.to_datablock = to; 219468481Seric else if (strcasecmp(name, "datafinal") == 0) 219568481Seric TimeOuts.to_datafinal = to; 219668481Seric else if (strcasecmp(name, "command") == 0) 219768481Seric TimeOuts.to_nextcommand = to; 219868481Seric else if (strcasecmp(name, "rset") == 0) 219968481Seric TimeOuts.to_rset = to; 220068481Seric else if (strcasecmp(name, "helo") == 0) 220168481Seric TimeOuts.to_helo = to; 220268481Seric else if (strcasecmp(name, "quit") == 0) 220368481Seric TimeOuts.to_quit = to; 220468481Seric else if (strcasecmp(name, "misc") == 0) 220568481Seric TimeOuts.to_miscshort = to; 220668481Seric else if (strcasecmp(name, "ident") == 0) 220768481Seric TimeOuts.to_ident = to; 220868481Seric else if (strcasecmp(name, "fileopen") == 0) 220968481Seric TimeOuts.to_fileopen = to; 221068481Seric else if (strcasecmp(name, "queuewarn") == 0) 221168481Seric { 221268481Seric to = convtime(val, 'h'); 221368481Seric if (p == NULL || strcmp(p, "*") == 0) 221468481Seric { 221568481Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 221668481Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 221768481Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 221858112Seric } 221968481Seric else if (strcasecmp(p, "normal") == 0) 222068481Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 222168481Seric else if (strcasecmp(p, "urgent") == 0) 222268481Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 222368481Seric else if (strcasecmp(p, "non-urgent") == 0) 222468481Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 222568481Seric else 222668481Seric syserr("settimeout: invalid queuewarn subtimeout %s", p); 222758112Seric } 222868481Seric else if (strcasecmp(name, "queuereturn") == 0) 222968481Seric { 223068481Seric to = convtime(val, 'd'); 223168481Seric if (p == NULL || strcmp(p, "*") == 0) 223268481Seric { 223368481Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 223468481Seric TimeOuts.to_q_return[TOC_URGENT] = to; 223568481Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 223668481Seric } 223768481Seric else if (strcasecmp(p, "normal") == 0) 223868481Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 223968481Seric else if (strcasecmp(p, "urgent") == 0) 224068481Seric TimeOuts.to_q_return[TOC_URGENT] = to; 224168481Seric else if (strcasecmp(p, "non-urgent") == 0) 224268481Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 224368481Seric else 224468481Seric syserr("settimeout: invalid queuereturn subtimeout %s", p); 224568481Seric } 224668481Seric else 224768481Seric syserr("settimeout: invalid timeout %s", name); 224858112Seric } 2249