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*68529Seric static char sccsid[] = "@(#)readcf.c 8.74 (Berkeley) 03/14/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'; 224*68529Seric expand(&bp[1], 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'; 312*68529Seric expand(q, 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); 442*68529Seric 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); 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; 66168513Seric int sff; 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 } 67368513Seric sff = SFF_REGONLY; 67468513Seric if (safe) 67568513Seric sff |= SFF_OPENASROOT; 67668513Seric f = safefopen(filename, O_RDONLY, 0, sff); 67768513Seric if (f == NULL && !optional) 67854973Seric { 67954973Seric syserr("fileclass: cannot open %s", filename); 6804432Seric return; 6814432Seric } 6824432Seric 6834432Seric while (fgets(buf, sizeof buf, f) != NULL) 6844432Seric { 6854432Seric register STAB *s; 68625808Seric register char *p; 68725808Seric # ifdef SCANF 6884432Seric char wordbuf[MAXNAME+1]; 6894432Seric 6904432Seric if (sscanf(buf, fmt, wordbuf) != 1) 6914432Seric continue; 69225808Seric p = wordbuf; 69356795Seric # else /* SCANF */ 69425808Seric p = buf; 69556795Seric # endif /* SCANF */ 69625808Seric 69725808Seric /* 69825808Seric ** Break up the match into words. 69925808Seric */ 70025808Seric 70125808Seric while (*p != '\0') 70225808Seric { 70325808Seric register char *q; 70425808Seric 70525808Seric /* strip leading spaces */ 70658050Seric while (isascii(*p) && isspace(*p)) 70725808Seric p++; 70825808Seric if (*p == '\0') 70925808Seric break; 71025808Seric 71125808Seric /* find the end of the word */ 71225808Seric q = p; 71358050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 71425808Seric p++; 71525808Seric if (*p != '\0') 71625808Seric *p++ = '\0'; 71725808Seric 71825808Seric /* enter the word in the symbol table */ 71966101Seric setclass(class, q); 72025808Seric } 7214432Seric } 7224432Seric 72354973Seric (void) fclose(f); 7244432Seric } 7254432Seric /* 7264096Seric ** MAKEMAILER -- define a new mailer. 7274096Seric ** 7284096Seric ** Parameters: 72910327Seric ** line -- description of mailer. This is in labeled 73010327Seric ** fields. The fields are: 73168481Seric ** A -- the argv for this mailer 73268481Seric ** C -- the character set for MIME conversions 73368481Seric ** D -- the directory to run in 73468481Seric ** E -- the eol string 73568481Seric ** F -- the flags associated with the mailer 73668481Seric ** L -- the maximum line length 73768481Seric ** M -- the maximum message size 73868479Seric ** P -- the path to the mailer 73968481Seric ** R -- the recipient rewriting set 74068479Seric ** S -- the sender rewriting set 74168481Seric ** T -- the mailer type (for DSNs) 74268481Seric ** U -- the uid to run as 74310327Seric ** The first word is the canonical name of the mailer. 7444096Seric ** 7454096Seric ** Returns: 7464096Seric ** none. 7474096Seric ** 7484096Seric ** Side Effects: 7494096Seric ** enters the mailer into the mailer table. 7504096Seric */ 7513308Seric 75221066Seric makemailer(line) 7534096Seric char *line; 7544096Seric { 7554096Seric register char *p; 7568067Seric register struct mailer *m; 7578067Seric register STAB *s; 7588067Seric int i; 75910327Seric char fcode; 76058020Seric auto char *endp; 7614096Seric extern int NextMailer; 76210327Seric extern char **makeargv(); 76310327Seric extern char *munchstring(); 76410701Seric extern long atol(); 7654096Seric 76610327Seric /* allocate a mailer and set up defaults */ 76710327Seric m = (struct mailer *) xalloc(sizeof *m); 76810327Seric bzero((char *) m, sizeof *m); 76910327Seric m->m_eol = "\n"; 77068481Seric m->m_uid = m->m_gid = 0; 77110327Seric 77210327Seric /* collect the mailer name */ 77358050Seric for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++) 77410327Seric continue; 77510327Seric if (*p != '\0') 77610327Seric *p++ = '\0'; 77710327Seric m->m_name = newstr(line); 77810327Seric 77910327Seric /* now scan through and assign info from the fields */ 78010327Seric while (*p != '\0') 78110327Seric { 78258333Seric auto char *delimptr; 78358333Seric 78458050Seric while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p)))) 78510327Seric p++; 78610327Seric 78710327Seric /* p now points to field code */ 78810327Seric fcode = *p; 78910327Seric while (*p != '\0' && *p != '=' && *p != ',') 79010327Seric p++; 79110327Seric if (*p++ != '=') 79210327Seric { 79352637Seric syserr("mailer %s: `=' expected", m->m_name); 79410327Seric return; 79510327Seric } 79658050Seric while (isascii(*p) && isspace(*p)) 79710327Seric p++; 79810327Seric 79910327Seric /* p now points to the field body */ 80058333Seric p = munchstring(p, &delimptr); 80110327Seric 80210327Seric /* install the field into the mailer struct */ 80310327Seric switch (fcode) 80410327Seric { 80510327Seric case 'P': /* pathname */ 80610327Seric m->m_mailer = newstr(p); 80710327Seric break; 80810327Seric 80910327Seric case 'F': /* flags */ 81010687Seric for (; *p != '\0'; p++) 81158050Seric if (!(isascii(*p) && isspace(*p))) 81252637Seric setbitn(*p, m->m_flags); 81310327Seric break; 81410327Seric 81510327Seric case 'S': /* sender rewriting ruleset */ 81610327Seric case 'R': /* recipient rewriting ruleset */ 81758020Seric i = strtol(p, &endp, 10); 81810327Seric if (i < 0 || i >= MAXRWSETS) 81910327Seric { 82010327Seric syserr("invalid rewrite set, %d max", MAXRWSETS); 82110327Seric return; 82210327Seric } 82310327Seric if (fcode == 'S') 82458020Seric m->m_sh_rwset = m->m_se_rwset = i; 82510327Seric else 82658020Seric m->m_rh_rwset = m->m_re_rwset = i; 82758020Seric 82858020Seric p = endp; 82959985Seric if (*p++ == '/') 83058020Seric { 83158020Seric i = strtol(p, NULL, 10); 83258020Seric if (i < 0 || i >= MAXRWSETS) 83358020Seric { 83458020Seric syserr("invalid rewrite set, %d max", 83558020Seric MAXRWSETS); 83658020Seric return; 83758020Seric } 83858020Seric if (fcode == 'S') 83958020Seric m->m_sh_rwset = i; 84058020Seric else 84158020Seric m->m_rh_rwset = i; 84258020Seric } 84310327Seric break; 84410327Seric 84510327Seric case 'E': /* end of line string */ 84610327Seric m->m_eol = newstr(p); 84710327Seric break; 84810327Seric 84910327Seric case 'A': /* argument vector */ 85010327Seric m->m_argv = makeargv(p); 85110327Seric break; 85210701Seric 85310701Seric case 'M': /* maximum message size */ 85410701Seric m->m_maxsize = atol(p); 85510701Seric break; 85652106Seric 85752106Seric case 'L': /* maximum line length */ 85852106Seric m->m_linelimit = atoi(p); 85952106Seric break; 86058935Seric 86158935Seric case 'D': /* working directory */ 86258935Seric m->m_execdir = newstr(p); 86358935Seric break; 86468481Seric 86568481Seric case 'C': /* default charset */ 86668481Seric m->m_defcharset = newstr(p); 86768481Seric break; 86868481Seric 86968481Seric case 'T': /* MTA Type */ 87068481Seric m->m_mtatype = newstr(p); 87168481Seric p = strchr(m->m_mtatype, '/'); 87268481Seric if (p != NULL) 87368481Seric { 87468481Seric *p++ = '\0'; 87568481Seric if (*p == '\0') 87668481Seric p = NULL; 87768481Seric } 87868481Seric if (p == NULL) 87968481Seric m->m_addrtype = m->m_mtatype; 88068481Seric else 88168481Seric { 88268481Seric m->m_addrtype = p; 88368481Seric p = strchr(p, '/'); 88468481Seric } 88568481Seric if (p != NULL) 88668481Seric { 88768481Seric *p++ = '\0'; 88868481Seric if (*p == '\0') 88968481Seric p = NULL; 89068481Seric } 89168481Seric if (p == NULL) 89268481Seric m->m_diagtype = m->m_mtatype; 89368481Seric else 89468481Seric m->m_diagtype = p; 89568481Seric break; 89668481Seric 89768481Seric case 'U': /* user id */ 89868481Seric if (isascii(*p) && !isdigit(*p)) 89968481Seric { 90068481Seric char *q = p; 90168481Seric struct passwd *pw; 90268481Seric 90368481Seric while (isascii(*p) && isalnum(*p)) 90468481Seric p++; 90568481Seric while (isascii(*p) && isspace(*p)) 90668481Seric *p++ = '\0'; 90768481Seric if (*p != '\0') 90868481Seric *p++ = '\0'; 90968481Seric pw = getpwnam(q); 91068481Seric if (pw == NULL) 91168481Seric syserr("readcf: mailer U= flag: unknown user %s", q); 91268481Seric else 91368481Seric { 91468481Seric m->m_uid = pw->pw_uid; 91568481Seric m->m_gid = pw->pw_gid; 91668481Seric } 91768481Seric } 91868481Seric else 91968481Seric { 92068481Seric auto char *q; 92168481Seric 92268481Seric m->m_uid = strtol(p, &q, 0); 92368481Seric p = q; 92468481Seric } 92568481Seric while (isascii(*p) && isspace(*p)) 92668481Seric p++; 92768481Seric if (*p == '\0') 92868481Seric break; 92968481Seric if (isascii(*p) && !isdigit(*p)) 93068481Seric { 93168481Seric char *q = p; 93268481Seric struct group *gr; 93368481Seric 93468481Seric while (isascii(*p) && isalnum(*p)) 93568481Seric p++; 93668481Seric *p++ = '\0'; 93768481Seric gr = getgrnam(q); 93868481Seric if (gr == NULL) 93968481Seric syserr("readcf: mailer U= flag: unknown group %s", q); 94068481Seric else 94168481Seric m->m_gid = gr->gr_gid; 94268481Seric } 94368481Seric else 94468481Seric { 94568481Seric m->m_gid = strtol(p, NULL, 0); 94668481Seric } 94768481Seric break; 94810327Seric } 94910327Seric 95058333Seric p = delimptr; 95110327Seric } 95210327Seric 95358321Seric /* do some rationality checking */ 95458321Seric if (m->m_argv == NULL) 95558321Seric { 95658321Seric syserr("M%s: A= argument required", m->m_name); 95758321Seric return; 95858321Seric } 95958321Seric if (m->m_mailer == NULL) 96058321Seric { 96158321Seric syserr("M%s: P= argument required", m->m_name); 96258321Seric return; 96358321Seric } 96458321Seric 9654096Seric if (NextMailer >= MAXMAILERS) 9664096Seric { 9679381Seric syserr("too many mailers defined (%d max)", MAXMAILERS); 9684096Seric return; 9694096Seric } 97057402Seric 97168481Seric /* do some heuristic cleanup for back compatibility */ 97268481Seric if (bitnset(M_LIMITS, m->m_flags)) 97368481Seric { 97468481Seric if (m->m_linelimit == 0) 97568481Seric m->m_linelimit = SMTPLINELIM; 97668481Seric if (ConfigLevel < 2) 97768481Seric setbitn(M_7BITS, m->m_flags); 97868481Seric } 97968481Seric 98068481Seric if (ConfigLevel < 6 && 98168481Seric (strcmp(m->m_mailer, "[IPC]") == 0 || 98268481Seric strcmp(m->m_mailer, "[TCP]") == 0)) 98368481Seric { 98468481Seric if (m->m_mtatype == NULL) 98568481Seric m->m_mtatype = "dns"; 98668481Seric if (m->m_addrtype == NULL) 98768481Seric m->m_addrtype = "rfc822"; 98868481Seric if (m->m_diagtype == NULL) 98968481Seric m->m_diagtype = "smtp"; 99068481Seric } 99168481Seric 99268481Seric /* enter the mailer into the symbol table */ 99310327Seric s = stab(m->m_name, ST_MAILER, ST_ENTER); 99457402Seric if (s->s_mailer != NULL) 99557402Seric { 99657402Seric i = s->s_mailer->m_mno; 99757402Seric free(s->s_mailer); 99857402Seric } 99957402Seric else 100057402Seric { 100157402Seric i = NextMailer++; 100257402Seric } 100357402Seric Mailer[i] = s->s_mailer = m; 100457454Seric m->m_mno = i; 100510327Seric } 100610327Seric /* 100710327Seric ** MUNCHSTRING -- translate a string into internal form. 100810327Seric ** 100910327Seric ** Parameters: 101010327Seric ** p -- the string to munch. 101158333Seric ** delimptr -- if non-NULL, set to the pointer of the 101258333Seric ** field delimiter character. 101310327Seric ** 101410327Seric ** Returns: 101510327Seric ** the munched string. 101610327Seric */ 10174096Seric 101810327Seric char * 101958333Seric munchstring(p, delimptr) 102010327Seric register char *p; 102158333Seric char **delimptr; 102210327Seric { 102310327Seric register char *q; 102410327Seric bool backslash = FALSE; 102510327Seric bool quotemode = FALSE; 102610327Seric static char buf[MAXLINE]; 10274096Seric 102810327Seric for (q = buf; *p != '\0'; p++) 10294096Seric { 103010327Seric if (backslash) 103110327Seric { 103210327Seric /* everything is roughly literal */ 103310357Seric backslash = FALSE; 103410327Seric switch (*p) 103510327Seric { 103610327Seric case 'r': /* carriage return */ 103710327Seric *q++ = '\r'; 103810327Seric continue; 103910327Seric 104010327Seric case 'n': /* newline */ 104110327Seric *q++ = '\n'; 104210327Seric continue; 104310327Seric 104410327Seric case 'f': /* form feed */ 104510327Seric *q++ = '\f'; 104610327Seric continue; 104710327Seric 104810327Seric case 'b': /* backspace */ 104910327Seric *q++ = '\b'; 105010327Seric continue; 105110327Seric } 105210327Seric *q++ = *p; 105310327Seric } 105410327Seric else 105510327Seric { 105610327Seric if (*p == '\\') 105710327Seric backslash = TRUE; 105810327Seric else if (*p == '"') 105910327Seric quotemode = !quotemode; 106010327Seric else if (quotemode || *p != ',') 106110327Seric *q++ = *p; 106210327Seric else 106310327Seric break; 106410327Seric } 10654096Seric } 10664096Seric 106758333Seric if (delimptr != NULL) 106858333Seric *delimptr = p; 106910327Seric *q++ = '\0'; 107010327Seric return (buf); 107110327Seric } 107210327Seric /* 107310327Seric ** MAKEARGV -- break up a string into words 107410327Seric ** 107510327Seric ** Parameters: 107610327Seric ** p -- the string to break up. 107710327Seric ** 107810327Seric ** Returns: 107910327Seric ** a char **argv (dynamically allocated) 108010327Seric ** 108110327Seric ** Side Effects: 108210327Seric ** munges p. 108310327Seric */ 10844096Seric 108510327Seric char ** 108610327Seric makeargv(p) 108710327Seric register char *p; 108810327Seric { 108910327Seric char *q; 109010327Seric int i; 109110327Seric char **avp; 109210327Seric char *argv[MAXPV + 1]; 109310327Seric 109410327Seric /* take apart the words */ 109510327Seric i = 0; 109610327Seric while (*p != '\0' && i < MAXPV) 10974096Seric { 109810327Seric q = p; 109958050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 110010327Seric p++; 110158050Seric while (isascii(*p) && isspace(*p)) 110210327Seric *p++ = '\0'; 110310327Seric argv[i++] = newstr(q); 11044096Seric } 110510327Seric argv[i++] = NULL; 11064096Seric 110710327Seric /* now make a copy of the argv */ 110810327Seric avp = (char **) xalloc(sizeof *avp * i); 110916893Seric bcopy((char *) argv, (char *) avp, sizeof *avp * i); 111010327Seric 111110327Seric return (avp); 11123308Seric } 11133308Seric /* 11143308Seric ** PRINTRULES -- print rewrite rules (for debugging) 11153308Seric ** 11163308Seric ** Parameters: 11173308Seric ** none. 11183308Seric ** 11193308Seric ** Returns: 11203308Seric ** none. 11213308Seric ** 11223308Seric ** Side Effects: 11233308Seric ** prints rewrite rules. 11243308Seric */ 11253308Seric 11263308Seric printrules() 11273308Seric { 11283308Seric register struct rewrite *rwp; 11294072Seric register int ruleset; 11303308Seric 11314072Seric for (ruleset = 0; ruleset < 10; ruleset++) 11323308Seric { 11334072Seric if (RewriteRules[ruleset] == NULL) 11344072Seric continue; 11358067Seric printf("\n----Rule Set %d:", ruleset); 11363308Seric 11374072Seric for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 11383308Seric { 11398067Seric printf("\nLHS:"); 11408067Seric printav(rwp->r_lhs); 11418067Seric printf("RHS:"); 11428067Seric printav(rwp->r_rhs); 11433308Seric } 11443308Seric } 11453308Seric } 114668481Seric /* 114768481Seric ** PRINTMAILER -- print mailer structure (for debugging) 114868481Seric ** 114968481Seric ** Parameters: 115068481Seric ** m -- the mailer to print 115168481Seric ** 115268481Seric ** Returns: 115368481Seric ** none. 115468481Seric */ 11554319Seric 115668481Seric printmailer(m) 115768481Seric register MAILER *m; 115868481Seric { 115968481Seric int j; 116068481Seric 116168481Seric printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld U=%d:%d F=", 116268481Seric m->m_mno, m->m_name, 116368481Seric m->m_mailer, m->m_se_rwset, m->m_sh_rwset, 116468481Seric m->m_re_rwset, m->m_rh_rwset, m->m_maxsize, 116568481Seric m->m_uid, m->m_gid); 116668481Seric for (j = '\0'; j <= '\177'; j++) 116768481Seric if (bitnset(j, m->m_flags)) 116868481Seric (void) putchar(j); 116968481Seric printf(" L=%d E=", m->m_linelimit); 117068481Seric xputs(m->m_eol); 117168481Seric if (m->m_defcharset != NULL) 117268481Seric printf(" C=%s", m->m_defcharset); 117368481Seric printf(" T=%s/%s/%s", 117468481Seric m->m_mtatype == NULL ? "<undefined>" : m->m_mtatype, 117568481Seric m->m_addrtype == NULL ? "<undefined>" : m->m_addrtype, 117668481Seric m->m_diagtype == NULL ? "<undefined>" : m->m_diagtype); 117768481Seric if (m->m_argv != NULL) 117868481Seric { 117968481Seric char **a = m->m_argv; 118068481Seric 118168481Seric printf(" A="); 118268481Seric while (*a != NULL) 118368481Seric { 118468481Seric if (a != m->m_argv) 118568481Seric printf(" "); 118668481Seric xputs(*a++); 118768481Seric } 118868481Seric } 118968481Seric printf("\n"); 119068481Seric } 11914096Seric /* 11928256Seric ** SETOPTION -- set global processing option 11938256Seric ** 11948256Seric ** Parameters: 11958256Seric ** opt -- option name. 11968256Seric ** val -- option value (as a text string). 119721755Seric ** safe -- set if this came from a configuration file. 119821755Seric ** Some options (if set from the command line) will 119921755Seric ** reset the user id to avoid security problems. 12008269Seric ** sticky -- if set, don't let other setoptions override 12018269Seric ** this value. 120258734Seric ** e -- the main envelope. 12038256Seric ** 12048256Seric ** Returns: 12058256Seric ** none. 12068256Seric ** 12078256Seric ** Side Effects: 12088256Seric ** Sets options as implied by the arguments. 12098256Seric */ 12108256Seric 121110687Seric static BITMAP StickyOpt; /* set if option is stuck */ 12128269Seric 121357207Seric 121466334Seric #if NAMED_BIND 121557207Seric 121657207Seric struct resolverflags 121757207Seric { 121857207Seric char *rf_name; /* name of the flag */ 121957207Seric long rf_bits; /* bits to set/clear */ 122057207Seric } ResolverFlags[] = 122157207Seric { 122257207Seric "debug", RES_DEBUG, 122357207Seric "aaonly", RES_AAONLY, 122457207Seric "usevc", RES_USEVC, 122557207Seric "primary", RES_PRIMARY, 122657207Seric "igntc", RES_IGNTC, 122757207Seric "recurse", RES_RECURSE, 122857207Seric "defnames", RES_DEFNAMES, 122957207Seric "stayopen", RES_STAYOPEN, 123057207Seric "dnsrch", RES_DNSRCH, 123165583Seric "true", 0, /* to avoid error on old syntax */ 123257207Seric NULL, 0 123357207Seric }; 123457207Seric 123557207Seric #endif 123657207Seric 123768481Seric struct optioninfo 123868481Seric { 123968481Seric char *o_name; /* long name of option */ 124068481Seric u_char o_code; /* short name of option */ 124168481Seric bool o_safe; /* safe for random people to use */ 124268481Seric } OptionTab[] = 124368481Seric { 124468481Seric "SevenBitInput", '7', TRUE, 124568481Seric "EightBitMode", '8', TRUE, 124668481Seric "AliasFile", 'A', FALSE, 124768481Seric "AliasWait", 'a', FALSE, 124868481Seric "BlankSub", 'B', FALSE, 124968481Seric "MinFreeBlocks", 'b', TRUE, 125068481Seric "CheckpointInterval", 'C', TRUE, 125168481Seric "HoldExpensive", 'c', FALSE, 125268481Seric "AutoRebuildAliases", 'D', FALSE, 125368481Seric "DeliveryMode", 'd', TRUE, 125468481Seric "ErrorHeader", 'E', FALSE, 125568481Seric "ErrorMode", 'e', TRUE, 125668481Seric "TempFileMode", 'F', FALSE, 125768481Seric "SaveFromLine", 'f', FALSE, 125868481Seric "MatchGECOS", 'G', FALSE, 125968481Seric "HelpFile", 'H', FALSE, 126068481Seric "MaxHopCount", 'h', FALSE, 126168481Seric "NameServerOptions", 'I', FALSE, 126268481Seric "IgnoreDots", 'i', TRUE, 126368481Seric "ForwardPath", 'J', FALSE, 126468481Seric "SendMimeErrors", 'j', TRUE, 126568481Seric "ConnectionCacheSize", 'k', FALSE, 126668481Seric "ConnectionCacheTimeout", 'K', FALSE, 126768481Seric "UseErrorsTo", 'l', FALSE, 126868481Seric "LogLevel", 'L', FALSE, 126968481Seric "MeToo", 'm', TRUE, 127068481Seric "CheckAliases", 'n', FALSE, 127168481Seric "OldStyleHeaders", 'o', TRUE, 127268481Seric "DaemonPortOptions", 'O', FALSE, 127368481Seric "PrivacyOptions", 'p', TRUE, 127468481Seric "PostmasterCopy", 'P', FALSE, 127568481Seric "QueueFactor", 'q', FALSE, 127668481Seric "QueueDirectory", 'Q', FALSE, 127768481Seric "DontPruneRoutes", 'R', FALSE, 127868481Seric "Timeout", 'r', TRUE, 127968481Seric "StatusFile", 'S', FALSE, 128068481Seric "SuperSafe", 's', TRUE, 128168481Seric "QueueTimeout", 'T', FALSE, 128268481Seric "TimeZoneSpec", 't', FALSE, 128368481Seric "UserDatabaseSpec", 'U', FALSE, 128468481Seric "DefaultUser", 'u', FALSE, 128568481Seric "FallbackMXhost", 'V', FALSE, 128668481Seric "Verbose", 'v', TRUE, 128768481Seric "TryNullMXList", 'w', TRUE, 128868481Seric "QueueLA", 'x', FALSE, 128968481Seric "RefuseLA", 'X', FALSE, 129068481Seric "RecipientFactor", 'y', FALSE, 129168481Seric "ForkQueueRuns", 'Y', FALSE, 129268481Seric "ClassFactor", 'z', FALSE, 129368481Seric "TimeFactor", 'Z', FALSE, 129468481Seric #define O_BSP 0x80 129568481Seric "BrokenSmtpPeers", O_BSP, TRUE, 129668481Seric #define O_QUEUESORTORD 0x81 129768481Seric "QueueSortOrder", O_QUEUESORTORD, TRUE, 129868481Seric #define O_MQA 0x83 129968481Seric "MinQueueAge", O_MQA, TRUE, 130068481Seric #define O_MHSA 0x84 130168481Seric /* 130268481Seric "MaxHostStatAge", O_MHSA, TRUE, 130368481Seric */ 130468481Seric #define O_DEFCHARSET 0x85 130568481Seric "DefaultCharSet", O_DEFCHARSET, TRUE, 130668481Seric #define O_SSFILE 0x86 130768481Seric "ServiceSwitchFile", O_SSFILE, FALSE, 130868481Seric #define O_DIALDELAY 0x87 130968481Seric "DialDelay", O_DIALDELAY, TRUE, 131068481Seric #define O_NORCPTACTION 0x88 131168481Seric "NoRecipientAction", O_NORCPTACTION, TRUE, 131268490Seric #define O_SAFEFILEENV 0x89 131368490Seric "SafeFileEnvironment", O_SAFEFILEENV, FALSE, 131468481Seric 131568481Seric NULL, '\0', FALSE, 131668481Seric }; 131768481Seric 131868481Seric 131968481Seric 132058734Seric setoption(opt, val, safe, sticky, e) 132168481Seric u_char opt; 13228256Seric char *val; 132321755Seric bool safe; 13248269Seric bool sticky; 132558734Seric register ENVELOPE *e; 13268256Seric { 132757207Seric register char *p; 132868481Seric register struct optioninfo *o; 132968481Seric char *subopt; 13308265Seric extern bool atobool(); 133112633Seric extern time_t convtime(); 133214879Seric extern int QueueLA; 133314879Seric extern int RefuseLA; 133464718Seric extern bool Warn_Q_option; 13358256Seric 133668481Seric errno = 0; 133768481Seric if (opt == ' ') 133868481Seric { 133968481Seric /* full word options */ 134068481Seric struct optioninfo *sel; 134168481Seric 134268481Seric p = strchr(val, '='); 134368481Seric if (p == NULL) 134468481Seric p = &val[strlen(val)]; 134568481Seric while (*--p == ' ') 134668481Seric continue; 134768481Seric while (*++p == ' ') 134868481Seric *p = '\0'; 134968481Seric if (p == val) 135068481Seric { 135168481Seric syserr("readcf: null option name"); 135268481Seric return; 135368481Seric } 135468481Seric if (*p == '=') 135568481Seric *p++ = '\0'; 135668481Seric while (*p == ' ') 135768481Seric p++; 135868481Seric subopt = strchr(val, '.'); 135968481Seric if (subopt != NULL) 136068481Seric *subopt++ = '\0'; 136168481Seric sel = NULL; 136268481Seric for (o = OptionTab; o->o_name != NULL; o++) 136368481Seric { 136468481Seric if (strncasecmp(o->o_name, val, strlen(val)) != 0) 136568481Seric continue; 136668481Seric if (strlen(o->o_name) == strlen(val)) 136768481Seric { 136868481Seric /* completely specified -- this must be it */ 136968481Seric sel = NULL; 137068481Seric break; 137168481Seric } 137268481Seric if (sel != NULL) 137368481Seric break; 137468481Seric sel = o; 137568481Seric } 137668481Seric if (sel != NULL && o->o_name == NULL) 137768481Seric o = sel; 137868481Seric else if (o->o_name == NULL) 137968481Seric { 138068481Seric syserr("readcf: unknown option name %s", val); 138168481Seric return; 138268481Seric } 138368481Seric else if (sel != NULL) 138468481Seric { 138568481Seric syserr("readcf: ambiguous option name %s (matches %s and %s)", 138668481Seric val, sel->o_name, o->o_name); 138768481Seric return; 138868481Seric } 138968481Seric if (strlen(val) != strlen(o->o_name)) 139068481Seric { 139168481Seric bool oldVerbose = Verbose; 139268481Seric 139368481Seric Verbose = TRUE; 139468481Seric message("Option %s used as abbreviation for %s", 139568481Seric val, o->o_name); 139668481Seric Verbose = oldVerbose; 139768481Seric } 139868481Seric opt = o->o_code; 139968481Seric val = p; 140068481Seric } 140168481Seric else 140268481Seric { 140368481Seric for (o = OptionTab; o->o_name != NULL; o++) 140468481Seric { 140568481Seric if (o->o_code == opt) 140668481Seric break; 140768481Seric } 140868481Seric subopt = NULL; 140968481Seric } 141068481Seric 14118256Seric if (tTd(37, 1)) 141268481Seric { 141368481Seric printf(isascii(opt) && isprint(opt) ? 141468481Seric "setoption %s (%c).%s=%s" : 141568481Seric "setoption %s (0x%x).%s=%s", 141668481Seric o->o_name == NULL ? "<unknown>" : o->o_name, 141768481Seric opt, 141868481Seric subopt == NULL ? "" : subopt, 141968481Seric val); 142068481Seric } 14218256Seric 14228256Seric /* 14238269Seric ** See if this option is preset for us. 14248256Seric */ 14258256Seric 142659731Seric if (!sticky && bitnset(opt, StickyOpt)) 14278269Seric { 14289341Seric if (tTd(37, 1)) 14299341Seric printf(" (ignored)\n"); 14308269Seric return; 14318269Seric } 14328269Seric 143321755Seric /* 143421755Seric ** Check to see if this option can be specified by this user. 143521755Seric */ 143621755Seric 143763787Seric if (!safe && RealUid == 0) 143821755Seric safe = TRUE; 143968481Seric if (!safe && !o->o_safe) 144021755Seric { 144139111Srick if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 144221755Seric { 144336582Sbostic if (tTd(37, 1)) 144436582Sbostic printf(" (unsafe)"); 144563787Seric if (RealUid != geteuid()) 144636582Sbostic { 144751210Seric if (tTd(37, 1)) 144851210Seric printf("(Resetting uid)"); 144963787Seric (void) setgid(RealGid); 145063787Seric (void) setuid(RealUid); 145136582Sbostic } 145221755Seric } 145321755Seric } 145451210Seric if (tTd(37, 1)) 145517985Seric printf("\n"); 14568269Seric 145768481Seric switch (opt & 0xff) 14588256Seric { 145959709Seric case '7': /* force seven-bit input */ 146068481Seric SevenBitInput = atobool(val); 146152106Seric break; 146252106Seric 146368481Seric case '8': /* handling of 8-bit input */ 146468481Seric switch (*val) 146568481Seric { 146668481Seric case 'r': /* reject 8-bit, don't convert MIME */ 146768481Seric MimeMode = 0; 146868481Seric break; 146968481Seric 147068481Seric case 'm': /* convert 8-bit, convert MIME */ 147168481Seric MimeMode = MM_CVTMIME|MM_MIME8BIT; 147268481Seric break; 147368481Seric 147468481Seric case 'j': /* "just send 8" */ 147568481Seric MimeMode = MM_PASS8BIT; 147668481Seric break; 147768481Seric 147868481Seric case 'p': /* pass 8 bit, convert MIME */ 147968481Seric MimeMode = MM_PASS8BIT|MM_CVTMIME; 148068481Seric break; 148168481Seric 148268481Seric case 's': /* strict adherence */ 148368481Seric MimeMode = MM_CVTMIME; 148468481Seric break; 148568481Seric 148668481Seric case 'a': /* encode 8 bit if available */ 148768481Seric MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 148868481Seric break; 148968481Seric 149068481Seric case 'c': /* convert 8 bit to MIME, never 7 bit */ 149168481Seric MimeMode = MM_MIME8BIT; 149268481Seric break; 149368481Seric 149468481Seric default: 149568481Seric syserr("Unknown 8-bit mode %c", *val); 149668481Seric exit(EX_USAGE); 149768481Seric } 149868481Seric break; 149968481Seric 15008256Seric case 'A': /* set default alias file */ 15019381Seric if (val[0] == '\0') 150259672Seric setalias("aliases"); 15039381Seric else 150459672Seric setalias(val); 15058256Seric break; 15068256Seric 150717474Seric case 'a': /* look N minutes for "@:@" in alias file */ 150817474Seric if (val[0] == '\0') 150964796Seric SafeAlias = 5 * 60; /* five minutes */ 151017474Seric else 151164796Seric SafeAlias = convtime(val, 'm'); 151217474Seric break; 151317474Seric 151416843Seric case 'B': /* substitution for blank character */ 151516843Seric SpaceSub = val[0]; 151616843Seric if (SpaceSub == '\0') 151716843Seric SpaceSub = ' '; 151816843Seric break; 151916843Seric 152059283Seric case 'b': /* min blocks free on queue fs/max msg size */ 152159283Seric p = strchr(val, '/'); 152259283Seric if (p != NULL) 152359283Seric { 152459283Seric *p++ = '\0'; 152559283Seric MaxMessageSize = atol(p); 152659283Seric } 152758082Seric MinBlocksFree = atol(val); 152858082Seric break; 152958082Seric 15309284Seric case 'c': /* don't connect to "expensive" mailers */ 15319381Seric NoConnect = atobool(val); 15329284Seric break; 15339284Seric 153451305Seric case 'C': /* checkpoint every N addresses */ 153551305Seric CheckpointInterval = atoi(val); 153624944Seric break; 153724944Seric 15389284Seric case 'd': /* delivery mode */ 15399284Seric switch (*val) 15408269Seric { 15419284Seric case '\0': 154258734Seric e->e_sendmode = SM_DELIVER; 15438269Seric break; 15448269Seric 154510755Seric case SM_QUEUE: /* queue only */ 154610755Seric #ifndef QUEUE 154710755Seric syserr("need QUEUE to set -odqueue"); 154856795Seric #endif /* QUEUE */ 154910755Seric /* fall through..... */ 155010755Seric 15519284Seric case SM_DELIVER: /* do everything */ 15529284Seric case SM_FORK: /* fork after verification */ 155358734Seric e->e_sendmode = *val; 15548269Seric break; 15558269Seric 15568269Seric default: 15579284Seric syserr("Unknown delivery mode %c", *val); 15588269Seric exit(EX_USAGE); 15598269Seric } 15608269Seric break; 15618269Seric 15629146Seric case 'D': /* rebuild alias database as needed */ 15639381Seric AutoRebuild = atobool(val); 15649146Seric break; 15659146Seric 156655372Seric case 'E': /* error message header/header file */ 156755379Seric if (*val != '\0') 156855379Seric ErrMsgFile = newstr(val); 156955372Seric break; 157055372Seric 15718269Seric case 'e': /* set error processing mode */ 15728269Seric switch (*val) 15738269Seric { 15749381Seric case EM_QUIET: /* be silent about it */ 15759381Seric case EM_MAIL: /* mail back */ 15769381Seric case EM_BERKNET: /* do berknet error processing */ 15779381Seric case EM_WRITE: /* write back (or mail) */ 15789381Seric case EM_PRINT: /* print errors normally (default) */ 157958734Seric e->e_errormode = *val; 15808269Seric break; 15818269Seric } 15828269Seric break; 15838269Seric 15849049Seric case 'F': /* file mode */ 158517975Seric FileMode = atooct(val) & 0777; 15869049Seric break; 15879049Seric 15888269Seric case 'f': /* save Unix-style From lines on front */ 15899381Seric SaveFrom = atobool(val); 15908269Seric break; 15918269Seric 159253735Seric case 'G': /* match recipients against GECOS field */ 159353735Seric MatchGecos = atobool(val); 159453735Seric break; 159553735Seric 15968256Seric case 'g': /* default gid */ 159768481Seric g_opt: 159864133Seric if (isascii(*val) && isdigit(*val)) 159964133Seric DefGid = atoi(val); 160064133Seric else 160164133Seric { 160264133Seric register struct group *gr; 160364133Seric 160464133Seric DefGid = -1; 160564133Seric gr = getgrnam(val); 160664133Seric if (gr == NULL) 160768481Seric syserr("readcf: option %c: unknown group %s", 160868481Seric opt, val); 160964133Seric else 161064133Seric DefGid = gr->gr_gid; 161164133Seric } 16128256Seric break; 16138256Seric 16148256Seric case 'H': /* help file */ 16159381Seric if (val[0] == '\0') 16168269Seric HelpFile = "sendmail.hf"; 16179381Seric else 16189381Seric HelpFile = newstr(val); 16198256Seric break; 16208256Seric 162151305Seric case 'h': /* maximum hop count */ 162251305Seric MaxHopCount = atoi(val); 162351305Seric break; 162451305Seric 162535651Seric case 'I': /* use internet domain name server */ 162666334Seric #if NAMED_BIND 162757207Seric for (p = val; *p != 0; ) 162857207Seric { 162957207Seric bool clearmode; 163057207Seric char *q; 163157207Seric struct resolverflags *rfp; 163257207Seric 163357207Seric while (*p == ' ') 163457207Seric p++; 163557207Seric if (*p == '\0') 163657207Seric break; 163757207Seric clearmode = FALSE; 163857207Seric if (*p == '-') 163957207Seric clearmode = TRUE; 164057207Seric else if (*p != '+') 164157207Seric p--; 164257207Seric p++; 164357207Seric q = p; 164458050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 164557207Seric p++; 164657207Seric if (*p != '\0') 164757207Seric *p++ = '\0'; 164857207Seric for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 164957207Seric { 165057207Seric if (strcasecmp(q, rfp->rf_name) == 0) 165157207Seric break; 165257207Seric } 165364923Seric if (rfp->rf_name == NULL) 165464923Seric syserr("readcf: I option value %s unrecognized", q); 165564923Seric else if (clearmode) 165657207Seric _res.options &= ~rfp->rf_bits; 165757207Seric else 165857207Seric _res.options |= rfp->rf_bits; 165957207Seric } 166057207Seric if (tTd(8, 2)) 166157207Seric printf("_res.options = %x\n", _res.options); 166257207Seric #else 166357207Seric usrerr("name server (I option) specified but BIND not compiled in"); 166457207Seric #endif 166535651Seric break; 166635651Seric 16678269Seric case 'i': /* ignore dot lines in message */ 16689381Seric IgnrDot = atobool(val); 16698269Seric break; 16708269Seric 167159730Seric case 'j': /* send errors in MIME (RFC 1341) format */ 167259730Seric SendMIMEErrors = atobool(val); 167359730Seric break; 167459730Seric 167557136Seric case 'J': /* .forward search path */ 167657136Seric ForwardPath = newstr(val); 167757136Seric break; 167857136Seric 167954967Seric case 'k': /* connection cache size */ 168054967Seric MaxMciCache = atoi(val); 168156215Seric if (MaxMciCache < 0) 168256215Seric MaxMciCache = 0; 168354967Seric break; 168454967Seric 168554967Seric case 'K': /* connection cache timeout */ 168658796Seric MciCacheTimeout = convtime(val, 'm'); 168754967Seric break; 168854967Seric 168961104Seric case 'l': /* use Errors-To: header */ 169061104Seric UseErrorsTo = atobool(val); 169161104Seric break; 169261104Seric 16938256Seric case 'L': /* log level */ 169464140Seric if (safe || LogLevel < atoi(val)) 169564140Seric LogLevel = atoi(val); 16968256Seric break; 16978256Seric 16988269Seric case 'M': /* define macro */ 169968267Seric p = newstr(&val[1]); 170068267Seric if (!safe) 170168267Seric cleanstrcpy(p, p, MAXNAME); 170268267Seric define(val[0], p, CurEnv); 170316878Seric sticky = FALSE; 17048269Seric break; 17058269Seric 17068269Seric case 'm': /* send to me too */ 17079381Seric MeToo = atobool(val); 17088269Seric break; 17098269Seric 171025820Seric case 'n': /* validate RHS in newaliases */ 171125820Seric CheckAliases = atobool(val); 171225820Seric break; 171325820Seric 171461104Seric /* 'N' available -- was "net name" */ 171561104Seric 171658851Seric case 'O': /* daemon options */ 171758851Seric setdaemonoptions(val); 171858851Seric break; 171958851Seric 17208269Seric case 'o': /* assume old style headers */ 17219381Seric if (atobool(val)) 17229341Seric CurEnv->e_flags |= EF_OLDSTYLE; 17239341Seric else 17249341Seric CurEnv->e_flags &= ~EF_OLDSTYLE; 17258269Seric break; 17268269Seric 172758082Seric case 'p': /* select privacy level */ 172858082Seric p = val; 172958082Seric for (;;) 173058082Seric { 173158082Seric register struct prival *pv; 173258082Seric extern struct prival PrivacyValues[]; 173358082Seric 173458082Seric while (isascii(*p) && (isspace(*p) || ispunct(*p))) 173558082Seric p++; 173658082Seric if (*p == '\0') 173758082Seric break; 173858082Seric val = p; 173958082Seric while (isascii(*p) && isalnum(*p)) 174058082Seric p++; 174158082Seric if (*p != '\0') 174258082Seric *p++ = '\0'; 174358082Seric 174458082Seric for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 174558082Seric { 174658082Seric if (strcasecmp(val, pv->pv_name) == 0) 174758082Seric break; 174858082Seric } 174958886Seric if (pv->pv_name == NULL) 175058886Seric syserr("readcf: Op line: %s unrecognized", val); 175158082Seric PrivacyFlags |= pv->pv_flag; 175258082Seric } 175368479Seric sticky = FALSE; 175458082Seric break; 175558082Seric 175624944Seric case 'P': /* postmaster copy address for returned mail */ 175724944Seric PostMasterCopy = newstr(val); 175824944Seric break; 175924944Seric 176024944Seric case 'q': /* slope of queue only function */ 176124944Seric QueueFactor = atoi(val); 176224944Seric break; 176324944Seric 17648256Seric case 'Q': /* queue directory */ 17659381Seric if (val[0] == '\0') 17668269Seric QueueDir = "mqueue"; 17679381Seric else 17689381Seric QueueDir = newstr(val); 176958789Seric if (RealUid != 0 && !safe) 177064718Seric Warn_Q_option = TRUE; 17718256Seric break; 17728256Seric 177358148Seric case 'R': /* don't prune routes */ 177458148Seric DontPruneRoutes = atobool(val); 177558148Seric break; 177658148Seric 17778256Seric case 'r': /* read timeout */ 177868481Seric if (subopt == NULL) 177968481Seric inittimeouts(val); 178068481Seric else 178168481Seric settimeout(subopt, val); 17828256Seric break; 17838256Seric 17848256Seric case 'S': /* status file */ 17859381Seric if (val[0] == '\0') 17868269Seric StatFile = "sendmail.st"; 17879381Seric else 17889381Seric StatFile = newstr(val); 17898256Seric break; 17908256Seric 17918265Seric case 's': /* be super safe, even if expensive */ 17929381Seric SuperSafe = atobool(val); 17938256Seric break; 17948256Seric 17958256Seric case 'T': /* queue timeout */ 179658737Seric p = strchr(val, '/'); 179758737Seric if (p != NULL) 179858737Seric { 179958737Seric *p++ = '\0'; 180068481Seric settimeout("queuewarn", p); 180158737Seric } 180268481Seric settimeout("queuereturn", val); 180354967Seric break; 18048256Seric 18058265Seric case 't': /* time zone name */ 180652106Seric TimeZoneSpec = newstr(val); 18078265Seric break; 18088265Seric 180950556Seric case 'U': /* location of user database */ 181051360Seric UdbSpec = newstr(val); 181150556Seric break; 181250556Seric 18138256Seric case 'u': /* set default uid */ 181468481Seric for (p = val; *p != '\0'; p++) 181568481Seric { 181668481Seric if (*p == '.' || *p == '/' || *p == ':') 181768481Seric { 181868481Seric *p++ = '\0'; 181968481Seric break; 182068481Seric } 182168481Seric } 182264133Seric if (isascii(*val) && isdigit(*val)) 182364133Seric DefUid = atoi(val); 182464133Seric else 182564133Seric { 182664133Seric register struct passwd *pw; 182764133Seric 182864133Seric DefUid = -1; 182964133Seric pw = getpwnam(val); 183064133Seric if (pw == NULL) 183164133Seric syserr("readcf: option u: unknown user %s", val); 183264133Seric else 183368481Seric { 183464133Seric DefUid = pw->pw_uid; 183568481Seric DefGid = pw->pw_gid; 183668481Seric } 183764133Seric } 183840973Sbostic setdefuser(); 18398256Seric 184068481Seric /* handle the group if it is there */ 184168481Seric if (*p == '\0') 184268481Seric break; 184368481Seric val = p; 184468481Seric goto g_opt; 184568481Seric 184658851Seric case 'V': /* fallback MX host */ 184758851Seric FallBackMX = newstr(val); 184858851Seric break; 184958851Seric 18508269Seric case 'v': /* run in verbose mode */ 18519381Seric Verbose = atobool(val); 18528256Seric break; 18538256Seric 185463837Seric case 'w': /* if we are best MX, try host directly */ 185563837Seric TryNullMXList = atobool(val); 185663837Seric break; 185761104Seric 185861104Seric /* 'W' available -- was wizard password */ 185961104Seric 186014879Seric case 'x': /* load avg at which to auto-queue msgs */ 186114879Seric QueueLA = atoi(val); 186214879Seric break; 186314879Seric 186414879Seric case 'X': /* load avg at which to auto-reject connections */ 186514879Seric RefuseLA = atoi(val); 186614879Seric break; 186714879Seric 186824981Seric case 'y': /* work recipient factor */ 186924981Seric WkRecipFact = atoi(val); 187024981Seric break; 187124981Seric 187224981Seric case 'Y': /* fork jobs during queue runs */ 187324952Seric ForkQueueRuns = atobool(val); 187424952Seric break; 187524952Seric 187624981Seric case 'z': /* work message class factor */ 187724981Seric WkClassFact = atoi(val); 187824981Seric break; 187924981Seric 188024981Seric case 'Z': /* work time factor */ 188124981Seric WkTimeFact = atoi(val); 188224981Seric break; 188324981Seric 188468481Seric case O_BSP: /* SMTP Peers can't handle 2-line greeting */ 188568481Seric BrokenSmtpPeers = atobool(val); 188668481Seric break; 188768481Seric 188868481Seric case O_QUEUESORTORD: /* queue sorting order */ 188968481Seric switch (*val) 189068481Seric { 189168481Seric case 'h': /* Host first */ 189268481Seric case 'H': 189368481Seric QueueSortOrder = QS_BYHOST; 189468481Seric break; 189568481Seric 189668481Seric case 'p': /* Priority order */ 189768481Seric case 'P': 189868481Seric QueueSortOrder = QS_BYPRIORITY; 189968481Seric break; 190068481Seric 190168481Seric default: 190268481Seric syserr("Invalid queue sort order \"%s\"", val); 190368481Seric } 190468481Seric break; 190568481Seric 190668481Seric case O_MQA: /* minimum queue age between deliveries */ 190768481Seric MinQueueAge = convtime(val, 'm'); 190868481Seric break; 190968481Seric 191068481Seric case O_MHSA: /* maximum age of cached host status */ 191168481Seric MaxHostStatAge = convtime(val, 'm'); 191268481Seric break; 191368481Seric 191468481Seric case O_DEFCHARSET: /* default character set for mimefying */ 191568481Seric DefaultCharSet = newstr(denlstring(val, TRUE, TRUE)); 191668481Seric break; 191768481Seric 191868481Seric case O_SSFILE: /* service switch file */ 191968481Seric ServiceSwitchFile = newstr(val); 192068481Seric break; 192168481Seric 192268481Seric case O_DIALDELAY: /* delay for dial-on-demand operation */ 192368481Seric DialDelay = convtime(val, 's'); 192468481Seric break; 192568481Seric 192668481Seric case O_NORCPTACTION: /* what to do if no recipient */ 192768481Seric if (strcasecmp(val, "none") == 0) 192868481Seric NoRecipientAction = NRA_NO_ACTION; 192968481Seric else if (strcasecmp(val, "add-to") == 0) 193068481Seric NoRecipientAction = NRA_ADD_TO; 193168481Seric else if (strcasecmp(val, "add-apparently-to") == 0) 193268481Seric NoRecipientAction = NRA_ADD_APPARENTLY_TO; 193368481Seric else if (strcasecmp(val, "add-bcc") == 0) 193468481Seric NoRecipientAction = NRA_ADD_BCC; 193568481Seric else if (strcasecmp(val, "add-to-undisclosed") == 0) 193668481Seric NoRecipientAction = NRA_ADD_TO_UNDISCLOSED; 193768481Seric else 193868481Seric syserr("Invalid NoRecipientAction: %s", val); 193968481Seric 194068490Seric case O_SAFEFILEENV: /* chroot() environ for writing to files */ 194168490Seric SafeFileEnv = newstr(val); 194268490Seric break; 194368490Seric 19448256Seric default: 194568481Seric if (tTd(37, 1)) 194668481Seric { 194768481Seric if (isascii(opt) && isprint(opt)) 194868481Seric printf("Warning: option %c unknown\n", opt); 194968481Seric else 195068481Seric printf("Warning: option 0x%x unknown\n", opt); 195168481Seric } 19528256Seric break; 19538256Seric } 195416878Seric if (sticky) 195516878Seric setbitn(opt, StickyOpt); 19569188Seric return; 19578256Seric } 195810687Seric /* 195968481Seric ** SETCLASS -- set a string into a class 196010687Seric ** 196110687Seric ** Parameters: 196268481Seric ** class -- the class to put the string in. 196368481Seric ** str -- the string to enter 196410687Seric ** 196510687Seric ** Returns: 196610687Seric ** none. 196710687Seric ** 196810687Seric ** Side Effects: 196910687Seric ** puts the word into the symbol table. 197010687Seric */ 197110687Seric 197268481Seric setclass(class, str) 197310687Seric int class; 197468481Seric char *str; 197510687Seric { 197610687Seric register STAB *s; 197710687Seric 197857943Seric if (tTd(37, 8)) 197968481Seric printf("setclass(%c, %s)\n", class, str); 198068481Seric s = stab(str, ST_CLASS, ST_ENTER); 198110687Seric setbitn(class, s->s_class); 198210687Seric } 198353654Seric /* 198453654Seric ** MAKEMAPENTRY -- create a map entry 198553654Seric ** 198653654Seric ** Parameters: 198753654Seric ** line -- the config file line 198853654Seric ** 198953654Seric ** Returns: 199053654Seric ** TRUE if it successfully entered the map entry. 199153654Seric ** FALSE otherwise (usually syntax error). 199253654Seric ** 199353654Seric ** Side Effects: 199453654Seric ** Enters the map into the dictionary. 199553654Seric */ 199653654Seric 199753654Seric void 199853654Seric makemapentry(line) 199953654Seric char *line; 200053654Seric { 200153654Seric register char *p; 200253654Seric char *mapname; 200353654Seric char *classname; 200464078Seric register STAB *s; 200553654Seric STAB *class; 200653654Seric 200758050Seric for (p = line; isascii(*p) && isspace(*p); p++) 200853654Seric continue; 200958050Seric if (!(isascii(*p) && isalnum(*p))) 201053654Seric { 201153654Seric syserr("readcf: config K line: no map name"); 201253654Seric return; 201353654Seric } 201453654Seric 201553654Seric mapname = p; 201668481Seric while ((isascii(*++p) && isalnum(*p)) || *p == '.') 201753654Seric continue; 201853654Seric if (*p != '\0') 201953654Seric *p++ = '\0'; 202058050Seric while (isascii(*p) && isspace(*p)) 202153654Seric p++; 202258050Seric if (!(isascii(*p) && isalnum(*p))) 202353654Seric { 202453654Seric syserr("readcf: config K line, map %s: no map class", mapname); 202553654Seric return; 202653654Seric } 202753654Seric classname = p; 202858050Seric while (isascii(*++p) && isalnum(*p)) 202953654Seric continue; 203053654Seric if (*p != '\0') 203153654Seric *p++ = '\0'; 203258050Seric while (isascii(*p) && isspace(*p)) 203353654Seric p++; 203453654Seric 203553654Seric /* look up the class */ 203653654Seric class = stab(classname, ST_MAPCLASS, ST_FIND); 203753654Seric if (class == NULL) 203853654Seric { 203953654Seric syserr("readcf: map %s: class %s not available", mapname, classname); 204053654Seric return; 204153654Seric } 204253654Seric 204353654Seric /* enter the map */ 204464078Seric s = stab(mapname, ST_MAP, ST_ENTER); 204564078Seric s->s_map.map_class = &class->s_mapclass; 204664078Seric s->s_map.map_mname = newstr(mapname); 204753654Seric 204864078Seric if (class->s_mapclass.map_parse(&s->s_map, p)) 204964078Seric s->s_map.map_mflags |= MF_VALID; 205064078Seric 205164078Seric if (tTd(37, 5)) 205264078Seric { 205364078Seric printf("map %s, class %s, flags %x, file %s,\n", 205464078Seric s->s_map.map_mname, s->s_map.map_class->map_cname, 205564078Seric s->s_map.map_mflags, 205664078Seric s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 205764078Seric printf("\tapp %s, domain %s, rebuild %s\n", 205864078Seric s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 205964078Seric s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 206064078Seric s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 206164078Seric } 206253654Seric } 206358112Seric /* 206468481Seric ** INITTIMEOUTS -- parse and set timeout values 206558112Seric ** 206658112Seric ** Parameters: 206758112Seric ** val -- a pointer to the values. If NULL, do initial 206858112Seric ** settings. 206958112Seric ** 207058112Seric ** Returns: 207158112Seric ** none. 207258112Seric ** 207358112Seric ** Side Effects: 207458112Seric ** Initializes the TimeOuts structure 207558112Seric */ 207658112Seric 207764255Seric #define SECONDS 207858112Seric #define MINUTES * 60 207958112Seric #define HOUR * 3600 208058112Seric 208168481Seric inittimeouts(val) 208258112Seric register char *val; 208358112Seric { 208458112Seric register char *p; 208558671Seric extern time_t convtime(); 208658112Seric 208758112Seric if (val == NULL) 208858112Seric { 208958112Seric TimeOuts.to_initial = (time_t) 5 MINUTES; 209058112Seric TimeOuts.to_helo = (time_t) 5 MINUTES; 209158112Seric TimeOuts.to_mail = (time_t) 10 MINUTES; 209258112Seric TimeOuts.to_rcpt = (time_t) 1 HOUR; 209358112Seric TimeOuts.to_datainit = (time_t) 5 MINUTES; 209458112Seric TimeOuts.to_datablock = (time_t) 1 HOUR; 209558112Seric TimeOuts.to_datafinal = (time_t) 1 HOUR; 209658112Seric TimeOuts.to_rset = (time_t) 5 MINUTES; 209758112Seric TimeOuts.to_quit = (time_t) 2 MINUTES; 209858112Seric TimeOuts.to_nextcommand = (time_t) 1 HOUR; 209958112Seric TimeOuts.to_miscshort = (time_t) 2 MINUTES; 210068481Seric #if IDENTPROTO 210164255Seric TimeOuts.to_ident = (time_t) 30 SECONDS; 210268481Seric #else 210368481Seric TimeOuts.to_ident = (time_t) 0 SECONDS; 210468481Seric #endif 210568481Seric TimeOuts.to_fileopen = (time_t) 60 SECONDS; 210658112Seric return; 210758112Seric } 210858112Seric 210958112Seric for (;; val = p) 211058112Seric { 211158112Seric while (isascii(*val) && isspace(*val)) 211258112Seric val++; 211358112Seric if (*val == '\0') 211458112Seric break; 211558112Seric for (p = val; *p != '\0' && *p != ','; p++) 211658112Seric continue; 211758112Seric if (*p != '\0') 211858112Seric *p++ = '\0'; 211958112Seric 212058112Seric if (isascii(*val) && isdigit(*val)) 212158112Seric { 212258112Seric /* old syntax -- set everything */ 212358796Seric TimeOuts.to_mail = convtime(val, 'm'); 212458112Seric TimeOuts.to_rcpt = TimeOuts.to_mail; 212558112Seric TimeOuts.to_datainit = TimeOuts.to_mail; 212658112Seric TimeOuts.to_datablock = TimeOuts.to_mail; 212758112Seric TimeOuts.to_datafinal = TimeOuts.to_mail; 212858112Seric TimeOuts.to_nextcommand = TimeOuts.to_mail; 212958112Seric continue; 213058112Seric } 213158112Seric else 213258112Seric { 213368481Seric register char *q = strchr(val, ':'); 213458112Seric 213568481Seric if (q == NULL && (q = strchr(val, '=')) == NULL) 213658112Seric { 213758112Seric /* syntax error */ 213858112Seric continue; 213958112Seric } 214058112Seric *q++ = '\0'; 214168481Seric settimeout(val, q); 214268481Seric } 214368481Seric } 214468481Seric } 214568481Seric /* 214668481Seric ** SETTIMEOUT -- set an individual timeout 214768481Seric ** 214868481Seric ** Parameters: 214968481Seric ** name -- the name of the timeout. 215068481Seric ** val -- the value of the timeout. 215168481Seric ** 215268481Seric ** Returns: 215368481Seric ** none. 215468481Seric */ 215558112Seric 215668481Seric settimeout(name, val) 215768481Seric char *name; 215868481Seric char *val; 215968481Seric { 216068481Seric register char *p; 216168481Seric time_t to; 216268481Seric extern time_t convtime(); 216368481Seric 216468481Seric to = convtime(val, 'm'); 216568481Seric p = strchr(name, '.'); 216668481Seric if (p != NULL) 216768481Seric *p++ = '\0'; 216868481Seric 216968481Seric if (strcasecmp(name, "initial") == 0) 217068481Seric TimeOuts.to_initial = to; 217168481Seric else if (strcasecmp(name, "mail") == 0) 217268481Seric TimeOuts.to_mail = to; 217368481Seric else if (strcasecmp(name, "rcpt") == 0) 217468481Seric TimeOuts.to_rcpt = to; 217568481Seric else if (strcasecmp(name, "datainit") == 0) 217668481Seric TimeOuts.to_datainit = to; 217768481Seric else if (strcasecmp(name, "datablock") == 0) 217868481Seric TimeOuts.to_datablock = to; 217968481Seric else if (strcasecmp(name, "datafinal") == 0) 218068481Seric TimeOuts.to_datafinal = to; 218168481Seric else if (strcasecmp(name, "command") == 0) 218268481Seric TimeOuts.to_nextcommand = to; 218368481Seric else if (strcasecmp(name, "rset") == 0) 218468481Seric TimeOuts.to_rset = to; 218568481Seric else if (strcasecmp(name, "helo") == 0) 218668481Seric TimeOuts.to_helo = to; 218768481Seric else if (strcasecmp(name, "quit") == 0) 218868481Seric TimeOuts.to_quit = to; 218968481Seric else if (strcasecmp(name, "misc") == 0) 219068481Seric TimeOuts.to_miscshort = to; 219168481Seric else if (strcasecmp(name, "ident") == 0) 219268481Seric TimeOuts.to_ident = to; 219368481Seric else if (strcasecmp(name, "fileopen") == 0) 219468481Seric TimeOuts.to_fileopen = to; 219568481Seric else if (strcasecmp(name, "queuewarn") == 0) 219668481Seric { 219768481Seric to = convtime(val, 'h'); 219868481Seric if (p == NULL || strcmp(p, "*") == 0) 219968481Seric { 220068481Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 220168481Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 220268481Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 220358112Seric } 220468481Seric else if (strcasecmp(p, "normal") == 0) 220568481Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 220668481Seric else if (strcasecmp(p, "urgent") == 0) 220768481Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 220868481Seric else if (strcasecmp(p, "non-urgent") == 0) 220968481Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 221068481Seric else 221168481Seric syserr("settimeout: invalid queuewarn subtimeout %s", p); 221258112Seric } 221368481Seric else if (strcasecmp(name, "queuereturn") == 0) 221468481Seric { 221568481Seric to = convtime(val, 'd'); 221668481Seric if (p == NULL || strcmp(p, "*") == 0) 221768481Seric { 221868481Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 221968481Seric TimeOuts.to_q_return[TOC_URGENT] = to; 222068481Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 222168481Seric } 222268481Seric else if (strcasecmp(p, "normal") == 0) 222368481Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 222468481Seric else if (strcasecmp(p, "urgent") == 0) 222568481Seric TimeOuts.to_q_return[TOC_URGENT] = to; 222668481Seric else if (strcasecmp(p, "non-urgent") == 0) 222768481Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 222868481Seric else 222968481Seric syserr("settimeout: invalid queuereturn subtimeout %s", p); 223068481Seric } 223168481Seric else 223268481Seric syserr("settimeout: invalid timeout %s", name); 223358112Seric } 2234