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*68481Seric static char sccsid[] = "@(#)readcf.c 8.71 (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; 73*68481Seric 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; 81*68481Seric 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]; 88*68481Seric 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 139*68481Seric /* 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 172*68481Seric 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 */ 183*68481Seric *p++ = MACROEXPAND; 184*68481Seric 185*68481Seric /* convert macro name to code */ 186*68481Seric *p = macid(p, &ep); 187*68481Seric if (ep != p) 188*68481Seric 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 300*68481Seric { 30156678Seric syserr("R line: null LHS"); 302*68481Seric rwp->r_lhs = null_list; 303*68481Seric } 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 364*68481Seric { 36556678Seric syserr("R line: null RHS"); 366*68481Seric rwp->r_rhs = null_list; 367*68481Seric } 3683308Seric break; 3693308Seric 3704072Seric case 'S': /* select rewriting set */ 37164440Seric for (p = &bp[1]; isascii(*p) && isspace(*p); p++) 37264440Seric continue; 373*68481Seric if (!isascii(*p)) 37464440Seric { 37564440Seric syserr("invalid argument to S line: \"%.20s\"", 37664440Seric &bp[1]); 37764440Seric break; 37864440Seric } 379*68481Seric if (isdigit(*p)) 3808056Seric { 381*68481Seric ruleset = atoi(p); 382*68481Seric if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 383*68481Seric { 384*68481Seric syserr("bad ruleset %d (%d max)", 385*68481Seric ruleset, MAXRWSETS / 2); 386*68481Seric ruleset = 0; 387*68481Seric } 3888056Seric } 389*68481Seric else 390*68481Seric { 391*68481Seric STAB *s; 392*68481Seric char delim; 393*68481Seric 394*68481Seric q = p; 395*68481Seric while (*p != '\0' && isascii(*p) && 396*68481Seric (isalnum(*p) || strchr("-_$", *p) != NULL)) 397*68481Seric p++; 398*68481Seric while (isascii(*p) && isspace(*p)) 399*68481Seric *p++ = '\0'; 400*68481Seric delim = *p; 401*68481Seric if (delim != '\0') 402*68481Seric *p++ = '\0'; 403*68481Seric s = stab(q, ST_RULESET, ST_ENTER); 404*68481Seric if (s->s_ruleset != 0) 405*68481Seric ruleset = s->s_ruleset; 406*68481Seric else if (delim == '=') 407*68481Seric { 408*68481Seric ruleset = atoi(p); 409*68481Seric if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 410*68481Seric { 411*68481Seric syserr("bad ruleset %s = %d (%d max)", 412*68481Seric q, ruleset, MAXRWSETS / 2); 413*68481Seric ruleset = 0; 414*68481Seric } 415*68481Seric } 416*68481Seric else if ((ruleset = --nextruleset) < MAXRWSETS / 2) 417*68481Seric { 418*68481Seric syserr("%s: too many named rulesets (%d max)", 419*68481Seric q, MAXRWSETS / 2); 420*68481Seric ruleset = 0; 421*68481Seric } 422*68481Seric s->s_ruleset = ruleset; 423*68481Seric } 4244072Seric rwp = NULL; 4254072Seric break; 4264072Seric 4273308Seric case 'D': /* macro definition */ 428*68481Seric mid = macid(&bp[1], &ep); 429*68481Seric p = munchstring(ep, NULL); 430*68481Seric 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 */ 438*68481Seric case 'T': /* trusted user (set class `t') */ 439*68481Seric if (bp[0] == 'C') 4404061Seric { 441*68481Seric mid = macid(&bp[1], &ep); 442*68481Seric expand(ep, exbuf, &exbuf[sizeof exbuf], e); 443*68481Seric p = exbuf; 444*68481Seric } 445*68481Seric else 446*68481Seric { 447*68481Seric mid = 't'; 448*68481Seric p = &bp[1]; 449*68481Seric } 450*68481Seric while (*p != '\0') 451*68481Seric { 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') 463*68481Seric setclass(mid, wd); 4644061Seric *p = delim; 4654061Seric } 4664061Seric break; 4674061Seric 46859272Seric case 'F': /* word class from file */ 469*68481Seric mid = macid(&bp[1], &ep); 470*68481Seric 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)) 478*68481Seric 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 575*68481Seric /* initialize host maps from local service tables */ 576*68481Seric inithostmaps(); 577*68481Seric 578*68481Seric /* determine if we need to do special name-server frotz */ 57967905Seric { 580*68481Seric int nmaps; 581*68481Seric char *maptype[MAXMAPSTACK]; 582*68481Seric short mapreturn[MAXMAPACTIONS]; 583*68481Seric 584*68481Seric nmaps = switch_map_find("hosts", maptype, mapreturn); 585*68481Seric UseNameServer = FALSE; 586*68481Seric if (nmaps > 0 && nmaps <= MAXMAPSTACK) 587*68481Seric { 588*68481Seric register int mapno; 589*68481Seric 590*68481Seric for (mapno = 0; mapno < nmaps && !UseNameServer; mapno++) 591*68481Seric { 592*68481Seric if (strcmp(maptype[mapno], "dns") == 0) 593*68481Seric UseNameServer = TRUE; 594*68481Seric } 595*68481Seric } 596*68481Seric 597*68481Seric #ifdef HESIOD 598*68481Seric nmaps = switch_map_find("passwd", maptype, mapreturn); 599*68481Seric UseHesiod = FALSE; 600*68481Seric if (nmaps > 0 && nmaps <= MAXMAPSTACK) 601*68481Seric { 602*68481Seric register int mapno; 603*68481Seric 604*68481Seric for (mapno = 0; mapno < nmaps && !UseHesiod; mapno++) 605*68481Seric { 606*68481Seric if (strcmp(maptype[mapno], "hesiod") == 0) 607*68481Seric UseHesiod = TRUE; 608*68481Seric } 609*68481Seric } 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: 746*68481Seric ** A -- the argv for this mailer 747*68481Seric ** C -- the character set for MIME conversions 748*68481Seric ** D -- the directory to run in 749*68481Seric ** E -- the eol string 750*68481Seric ** F -- the flags associated with the mailer 751*68481Seric ** L -- the maximum line length 752*68481Seric ** M -- the maximum message size 75368479Seric ** P -- the path to the mailer 754*68481Seric ** R -- the recipient rewriting set 75568479Seric ** S -- the sender rewriting set 756*68481Seric ** T -- the mailer type (for DSNs) 757*68481Seric ** 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"; 785*68481Seric 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; 879*68481Seric 880*68481Seric case 'C': /* default charset */ 881*68481Seric m->m_defcharset = newstr(p); 882*68481Seric break; 883*68481Seric 884*68481Seric case 'T': /* MTA Type */ 885*68481Seric m->m_mtatype = newstr(p); 886*68481Seric p = strchr(m->m_mtatype, '/'); 887*68481Seric if (p != NULL) 888*68481Seric { 889*68481Seric *p++ = '\0'; 890*68481Seric if (*p == '\0') 891*68481Seric p = NULL; 892*68481Seric } 893*68481Seric if (p == NULL) 894*68481Seric m->m_addrtype = m->m_mtatype; 895*68481Seric else 896*68481Seric { 897*68481Seric m->m_addrtype = p; 898*68481Seric p = strchr(p, '/'); 899*68481Seric } 900*68481Seric if (p != NULL) 901*68481Seric { 902*68481Seric *p++ = '\0'; 903*68481Seric if (*p == '\0') 904*68481Seric p = NULL; 905*68481Seric } 906*68481Seric if (p == NULL) 907*68481Seric m->m_diagtype = m->m_mtatype; 908*68481Seric else 909*68481Seric m->m_diagtype = p; 910*68481Seric break; 911*68481Seric 912*68481Seric case 'U': /* user id */ 913*68481Seric if (isascii(*p) && !isdigit(*p)) 914*68481Seric { 915*68481Seric char *q = p; 916*68481Seric struct passwd *pw; 917*68481Seric 918*68481Seric while (isascii(*p) && isalnum(*p)) 919*68481Seric p++; 920*68481Seric while (isascii(*p) && isspace(*p)) 921*68481Seric *p++ = '\0'; 922*68481Seric if (*p != '\0') 923*68481Seric *p++ = '\0'; 924*68481Seric pw = getpwnam(q); 925*68481Seric if (pw == NULL) 926*68481Seric syserr("readcf: mailer U= flag: unknown user %s", q); 927*68481Seric else 928*68481Seric { 929*68481Seric m->m_uid = pw->pw_uid; 930*68481Seric m->m_gid = pw->pw_gid; 931*68481Seric } 932*68481Seric } 933*68481Seric else 934*68481Seric { 935*68481Seric auto char *q; 936*68481Seric 937*68481Seric m->m_uid = strtol(p, &q, 0); 938*68481Seric p = q; 939*68481Seric } 940*68481Seric while (isascii(*p) && isspace(*p)) 941*68481Seric p++; 942*68481Seric if (*p == '\0') 943*68481Seric break; 944*68481Seric if (isascii(*p) && !isdigit(*p)) 945*68481Seric { 946*68481Seric char *q = p; 947*68481Seric struct group *gr; 948*68481Seric 949*68481Seric while (isascii(*p) && isalnum(*p)) 950*68481Seric p++; 951*68481Seric *p++ = '\0'; 952*68481Seric gr = getgrnam(q); 953*68481Seric if (gr == NULL) 954*68481Seric syserr("readcf: mailer U= flag: unknown group %s", q); 955*68481Seric else 956*68481Seric m->m_gid = gr->gr_gid; 957*68481Seric } 958*68481Seric else 959*68481Seric { 960*68481Seric m->m_gid = strtol(p, NULL, 0); 961*68481Seric } 962*68481Seric 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 986*68481Seric /* do some heuristic cleanup for back compatibility */ 987*68481Seric if (bitnset(M_LIMITS, m->m_flags)) 988*68481Seric { 989*68481Seric if (m->m_linelimit == 0) 990*68481Seric m->m_linelimit = SMTPLINELIM; 991*68481Seric if (ConfigLevel < 2) 992*68481Seric setbitn(M_7BITS, m->m_flags); 993*68481Seric } 994*68481Seric 995*68481Seric if (ConfigLevel < 6 && 996*68481Seric (strcmp(m->m_mailer, "[IPC]") == 0 || 997*68481Seric strcmp(m->m_mailer, "[TCP]") == 0)) 998*68481Seric { 999*68481Seric if (m->m_mtatype == NULL) 1000*68481Seric m->m_mtatype = "dns"; 1001*68481Seric if (m->m_addrtype == NULL) 1002*68481Seric m->m_addrtype = "rfc822"; 1003*68481Seric if (m->m_diagtype == NULL) 1004*68481Seric m->m_diagtype = "smtp"; 1005*68481Seric } 1006*68481Seric 1007*68481Seric /* 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 } 1161*68481Seric /* 1162*68481Seric ** PRINTMAILER -- print mailer structure (for debugging) 1163*68481Seric ** 1164*68481Seric ** Parameters: 1165*68481Seric ** m -- the mailer to print 1166*68481Seric ** 1167*68481Seric ** Returns: 1168*68481Seric ** none. 1169*68481Seric */ 11704319Seric 1171*68481Seric printmailer(m) 1172*68481Seric register MAILER *m; 1173*68481Seric { 1174*68481Seric int j; 1175*68481Seric 1176*68481Seric printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld U=%d:%d F=", 1177*68481Seric m->m_mno, m->m_name, 1178*68481Seric m->m_mailer, m->m_se_rwset, m->m_sh_rwset, 1179*68481Seric m->m_re_rwset, m->m_rh_rwset, m->m_maxsize, 1180*68481Seric m->m_uid, m->m_gid); 1181*68481Seric for (j = '\0'; j <= '\177'; j++) 1182*68481Seric if (bitnset(j, m->m_flags)) 1183*68481Seric (void) putchar(j); 1184*68481Seric printf(" L=%d E=", m->m_linelimit); 1185*68481Seric xputs(m->m_eol); 1186*68481Seric if (m->m_defcharset != NULL) 1187*68481Seric printf(" C=%s", m->m_defcharset); 1188*68481Seric printf(" T=%s/%s/%s", 1189*68481Seric m->m_mtatype == NULL ? "<undefined>" : m->m_mtatype, 1190*68481Seric m->m_addrtype == NULL ? "<undefined>" : m->m_addrtype, 1191*68481Seric m->m_diagtype == NULL ? "<undefined>" : m->m_diagtype); 1192*68481Seric if (m->m_argv != NULL) 1193*68481Seric { 1194*68481Seric char **a = m->m_argv; 1195*68481Seric 1196*68481Seric printf(" A="); 1197*68481Seric while (*a != NULL) 1198*68481Seric { 1199*68481Seric if (a != m->m_argv) 1200*68481Seric printf(" "); 1201*68481Seric xputs(*a++); 1202*68481Seric } 1203*68481Seric } 1204*68481Seric printf("\n"); 1205*68481Seric } 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 1252*68481Seric struct optioninfo 1253*68481Seric { 1254*68481Seric char *o_name; /* long name of option */ 1255*68481Seric u_char o_code; /* short name of option */ 1256*68481Seric bool o_safe; /* safe for random people to use */ 1257*68481Seric } OptionTab[] = 1258*68481Seric { 1259*68481Seric "SevenBitInput", '7', TRUE, 1260*68481Seric "EightBitMode", '8', TRUE, 1261*68481Seric "AliasFile", 'A', FALSE, 1262*68481Seric "AliasWait", 'a', FALSE, 1263*68481Seric "BlankSub", 'B', FALSE, 1264*68481Seric "MinFreeBlocks", 'b', TRUE, 1265*68481Seric "CheckpointInterval", 'C', TRUE, 1266*68481Seric "HoldExpensive", 'c', FALSE, 1267*68481Seric "AutoRebuildAliases", 'D', FALSE, 1268*68481Seric "DeliveryMode", 'd', TRUE, 1269*68481Seric "ErrorHeader", 'E', FALSE, 1270*68481Seric "ErrorMode", 'e', TRUE, 1271*68481Seric "TempFileMode", 'F', FALSE, 1272*68481Seric "SaveFromLine", 'f', FALSE, 1273*68481Seric "MatchGECOS", 'G', FALSE, 1274*68481Seric "HelpFile", 'H', FALSE, 1275*68481Seric "MaxHopCount", 'h', FALSE, 1276*68481Seric "NameServerOptions", 'I', FALSE, 1277*68481Seric "IgnoreDots", 'i', TRUE, 1278*68481Seric "ForwardPath", 'J', FALSE, 1279*68481Seric "SendMimeErrors", 'j', TRUE, 1280*68481Seric "ConnectionCacheSize", 'k', FALSE, 1281*68481Seric "ConnectionCacheTimeout", 'K', FALSE, 1282*68481Seric "UseErrorsTo", 'l', FALSE, 1283*68481Seric "LogLevel", 'L', FALSE, 1284*68481Seric "MeToo", 'm', TRUE, 1285*68481Seric "CheckAliases", 'n', FALSE, 1286*68481Seric "OldStyleHeaders", 'o', TRUE, 1287*68481Seric "DaemonPortOptions", 'O', FALSE, 1288*68481Seric "PrivacyOptions", 'p', TRUE, 1289*68481Seric "PostmasterCopy", 'P', FALSE, 1290*68481Seric "QueueFactor", 'q', FALSE, 1291*68481Seric "QueueDirectory", 'Q', FALSE, 1292*68481Seric "DontPruneRoutes", 'R', FALSE, 1293*68481Seric "Timeout", 'r', TRUE, 1294*68481Seric "StatusFile", 'S', FALSE, 1295*68481Seric "SuperSafe", 's', TRUE, 1296*68481Seric "QueueTimeout", 'T', FALSE, 1297*68481Seric "TimeZoneSpec", 't', FALSE, 1298*68481Seric "UserDatabaseSpec", 'U', FALSE, 1299*68481Seric "DefaultUser", 'u', FALSE, 1300*68481Seric "FallbackMXhost", 'V', FALSE, 1301*68481Seric "Verbose", 'v', TRUE, 1302*68481Seric "TryNullMXList", 'w', TRUE, 1303*68481Seric "QueueLA", 'x', FALSE, 1304*68481Seric "RefuseLA", 'X', FALSE, 1305*68481Seric "RecipientFactor", 'y', FALSE, 1306*68481Seric "ForkQueueRuns", 'Y', FALSE, 1307*68481Seric "ClassFactor", 'z', FALSE, 1308*68481Seric "TimeFactor", 'Z', FALSE, 1309*68481Seric #define O_BSP 0x80 1310*68481Seric "BrokenSmtpPeers", O_BSP, TRUE, 1311*68481Seric #define O_QUEUESORTORD 0x81 1312*68481Seric "QueueSortOrder", O_QUEUESORTORD, TRUE, 1313*68481Seric #define O_MQA 0x83 1314*68481Seric "MinQueueAge", O_MQA, TRUE, 1315*68481Seric #define O_MHSA 0x84 1316*68481Seric /* 1317*68481Seric "MaxHostStatAge", O_MHSA, TRUE, 1318*68481Seric */ 1319*68481Seric #define O_DEFCHARSET 0x85 1320*68481Seric "DefaultCharSet", O_DEFCHARSET, TRUE, 1321*68481Seric #define O_SSFILE 0x86 1322*68481Seric "ServiceSwitchFile", O_SSFILE, FALSE, 1323*68481Seric #define O_DIALDELAY 0x87 1324*68481Seric "DialDelay", O_DIALDELAY, TRUE, 1325*68481Seric #define O_NORCPTACTION 0x88 1326*68481Seric "NoRecipientAction", O_NORCPTACTION, TRUE, 1327*68481Seric 1328*68481Seric NULL, '\0', FALSE, 1329*68481Seric }; 1330*68481Seric 1331*68481Seric 1332*68481Seric 133358734Seric setoption(opt, val, safe, sticky, e) 1334*68481Seric u_char opt; 13358256Seric char *val; 133621755Seric bool safe; 13378269Seric bool sticky; 133858734Seric register ENVELOPE *e; 13398256Seric { 134057207Seric register char *p; 1341*68481Seric register struct optioninfo *o; 1342*68481Seric char *subopt; 13438265Seric extern bool atobool(); 134412633Seric extern time_t convtime(); 134514879Seric extern int QueueLA; 134614879Seric extern int RefuseLA; 134764718Seric extern bool Warn_Q_option; 13488256Seric 1349*68481Seric errno = 0; 1350*68481Seric if (opt == ' ') 1351*68481Seric { 1352*68481Seric /* full word options */ 1353*68481Seric struct optioninfo *sel; 1354*68481Seric 1355*68481Seric p = strchr(val, '='); 1356*68481Seric if (p == NULL) 1357*68481Seric p = &val[strlen(val)]; 1358*68481Seric while (*--p == ' ') 1359*68481Seric continue; 1360*68481Seric while (*++p == ' ') 1361*68481Seric *p = '\0'; 1362*68481Seric if (p == val) 1363*68481Seric { 1364*68481Seric syserr("readcf: null option name"); 1365*68481Seric return; 1366*68481Seric } 1367*68481Seric if (*p == '=') 1368*68481Seric *p++ = '\0'; 1369*68481Seric while (*p == ' ') 1370*68481Seric p++; 1371*68481Seric subopt = strchr(val, '.'); 1372*68481Seric if (subopt != NULL) 1373*68481Seric *subopt++ = '\0'; 1374*68481Seric sel = NULL; 1375*68481Seric for (o = OptionTab; o->o_name != NULL; o++) 1376*68481Seric { 1377*68481Seric if (strncasecmp(o->o_name, val, strlen(val)) != 0) 1378*68481Seric continue; 1379*68481Seric if (strlen(o->o_name) == strlen(val)) 1380*68481Seric { 1381*68481Seric /* completely specified -- this must be it */ 1382*68481Seric sel = NULL; 1383*68481Seric break; 1384*68481Seric } 1385*68481Seric if (sel != NULL) 1386*68481Seric break; 1387*68481Seric sel = o; 1388*68481Seric } 1389*68481Seric if (sel != NULL && o->o_name == NULL) 1390*68481Seric o = sel; 1391*68481Seric else if (o->o_name == NULL) 1392*68481Seric { 1393*68481Seric syserr("readcf: unknown option name %s", val); 1394*68481Seric return; 1395*68481Seric } 1396*68481Seric else if (sel != NULL) 1397*68481Seric { 1398*68481Seric syserr("readcf: ambiguous option name %s (matches %s and %s)", 1399*68481Seric val, sel->o_name, o->o_name); 1400*68481Seric return; 1401*68481Seric } 1402*68481Seric if (strlen(val) != strlen(o->o_name)) 1403*68481Seric { 1404*68481Seric bool oldVerbose = Verbose; 1405*68481Seric 1406*68481Seric Verbose = TRUE; 1407*68481Seric message("Option %s used as abbreviation for %s", 1408*68481Seric val, o->o_name); 1409*68481Seric Verbose = oldVerbose; 1410*68481Seric } 1411*68481Seric opt = o->o_code; 1412*68481Seric val = p; 1413*68481Seric } 1414*68481Seric else 1415*68481Seric { 1416*68481Seric for (o = OptionTab; o->o_name != NULL; o++) 1417*68481Seric { 1418*68481Seric if (o->o_code == opt) 1419*68481Seric break; 1420*68481Seric } 1421*68481Seric subopt = NULL; 1422*68481Seric } 1423*68481Seric 14248256Seric if (tTd(37, 1)) 1425*68481Seric { 1426*68481Seric printf(isascii(opt) && isprint(opt) ? 1427*68481Seric "setoption %s (%c).%s=%s" : 1428*68481Seric "setoption %s (0x%x).%s=%s", 1429*68481Seric o->o_name == NULL ? "<unknown>" : o->o_name, 1430*68481Seric opt, 1431*68481Seric subopt == NULL ? "" : subopt, 1432*68481Seric val); 1433*68481Seric } 14348256Seric 14358256Seric /* 14368269Seric ** See if this option is preset for us. 14378256Seric */ 14388256Seric 143959731Seric if (!sticky && bitnset(opt, StickyOpt)) 14408269Seric { 14419341Seric if (tTd(37, 1)) 14429341Seric printf(" (ignored)\n"); 14438269Seric return; 14448269Seric } 14458269Seric 144621755Seric /* 144721755Seric ** Check to see if this option can be specified by this user. 144821755Seric */ 144921755Seric 145063787Seric if (!safe && RealUid == 0) 145121755Seric safe = TRUE; 1452*68481Seric if (!safe && !o->o_safe) 145321755Seric { 145439111Srick if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 145521755Seric { 145636582Sbostic if (tTd(37, 1)) 145736582Sbostic printf(" (unsafe)"); 145863787Seric if (RealUid != geteuid()) 145936582Sbostic { 146051210Seric if (tTd(37, 1)) 146151210Seric printf("(Resetting uid)"); 146263787Seric (void) setgid(RealGid); 146363787Seric (void) setuid(RealUid); 146436582Sbostic } 146521755Seric } 146621755Seric } 146751210Seric if (tTd(37, 1)) 146817985Seric printf("\n"); 14698269Seric 1470*68481Seric switch (opt & 0xff) 14718256Seric { 147259709Seric case '7': /* force seven-bit input */ 1473*68481Seric SevenBitInput = atobool(val); 147452106Seric break; 147552106Seric 1476*68481Seric case '8': /* handling of 8-bit input */ 1477*68481Seric switch (*val) 1478*68481Seric { 1479*68481Seric case 'r': /* reject 8-bit, don't convert MIME */ 1480*68481Seric MimeMode = 0; 1481*68481Seric break; 1482*68481Seric 1483*68481Seric case 'm': /* convert 8-bit, convert MIME */ 1484*68481Seric MimeMode = MM_CVTMIME|MM_MIME8BIT; 1485*68481Seric break; 1486*68481Seric 1487*68481Seric case 'j': /* "just send 8" */ 1488*68481Seric MimeMode = MM_PASS8BIT; 1489*68481Seric break; 1490*68481Seric 1491*68481Seric case 'p': /* pass 8 bit, convert MIME */ 1492*68481Seric MimeMode = MM_PASS8BIT|MM_CVTMIME; 1493*68481Seric break; 1494*68481Seric 1495*68481Seric case 's': /* strict adherence */ 1496*68481Seric MimeMode = MM_CVTMIME; 1497*68481Seric break; 1498*68481Seric 1499*68481Seric case 'a': /* encode 8 bit if available */ 1500*68481Seric MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 1501*68481Seric break; 1502*68481Seric 1503*68481Seric case 'c': /* convert 8 bit to MIME, never 7 bit */ 1504*68481Seric MimeMode = MM_MIME8BIT; 1505*68481Seric break; 1506*68481Seric 1507*68481Seric default: 1508*68481Seric syserr("Unknown 8-bit mode %c", *val); 1509*68481Seric exit(EX_USAGE); 1510*68481Seric } 1511*68481Seric break; 1512*68481Seric 15138256Seric case 'A': /* set default alias file */ 15149381Seric if (val[0] == '\0') 151559672Seric setalias("aliases"); 15169381Seric else 151759672Seric setalias(val); 15188256Seric break; 15198256Seric 152017474Seric case 'a': /* look N minutes for "@:@" in alias file */ 152117474Seric if (val[0] == '\0') 152264796Seric SafeAlias = 5 * 60; /* five minutes */ 152317474Seric else 152464796Seric SafeAlias = convtime(val, 'm'); 152517474Seric break; 152617474Seric 152716843Seric case 'B': /* substitution for blank character */ 152816843Seric SpaceSub = val[0]; 152916843Seric if (SpaceSub == '\0') 153016843Seric SpaceSub = ' '; 153116843Seric break; 153216843Seric 153359283Seric case 'b': /* min blocks free on queue fs/max msg size */ 153459283Seric p = strchr(val, '/'); 153559283Seric if (p != NULL) 153659283Seric { 153759283Seric *p++ = '\0'; 153859283Seric MaxMessageSize = atol(p); 153959283Seric } 154058082Seric MinBlocksFree = atol(val); 154158082Seric break; 154258082Seric 15439284Seric case 'c': /* don't connect to "expensive" mailers */ 15449381Seric NoConnect = atobool(val); 15459284Seric break; 15469284Seric 154751305Seric case 'C': /* checkpoint every N addresses */ 154851305Seric CheckpointInterval = atoi(val); 154924944Seric break; 155024944Seric 15519284Seric case 'd': /* delivery mode */ 15529284Seric switch (*val) 15538269Seric { 15549284Seric case '\0': 155558734Seric e->e_sendmode = SM_DELIVER; 15568269Seric break; 15578269Seric 155810755Seric case SM_QUEUE: /* queue only */ 155910755Seric #ifndef QUEUE 156010755Seric syserr("need QUEUE to set -odqueue"); 156156795Seric #endif /* QUEUE */ 156210755Seric /* fall through..... */ 156310755Seric 15649284Seric case SM_DELIVER: /* do everything */ 15659284Seric case SM_FORK: /* fork after verification */ 156658734Seric e->e_sendmode = *val; 15678269Seric break; 15688269Seric 15698269Seric default: 15709284Seric syserr("Unknown delivery mode %c", *val); 15718269Seric exit(EX_USAGE); 15728269Seric } 15738269Seric break; 15748269Seric 15759146Seric case 'D': /* rebuild alias database as needed */ 15769381Seric AutoRebuild = atobool(val); 15779146Seric break; 15789146Seric 157955372Seric case 'E': /* error message header/header file */ 158055379Seric if (*val != '\0') 158155379Seric ErrMsgFile = newstr(val); 158255372Seric break; 158355372Seric 15848269Seric case 'e': /* set error processing mode */ 15858269Seric switch (*val) 15868269Seric { 15879381Seric case EM_QUIET: /* be silent about it */ 15889381Seric case EM_MAIL: /* mail back */ 15899381Seric case EM_BERKNET: /* do berknet error processing */ 15909381Seric case EM_WRITE: /* write back (or mail) */ 15919381Seric case EM_PRINT: /* print errors normally (default) */ 159258734Seric e->e_errormode = *val; 15938269Seric break; 15948269Seric } 15958269Seric break; 15968269Seric 15979049Seric case 'F': /* file mode */ 159817975Seric FileMode = atooct(val) & 0777; 15999049Seric break; 16009049Seric 16018269Seric case 'f': /* save Unix-style From lines on front */ 16029381Seric SaveFrom = atobool(val); 16038269Seric break; 16048269Seric 160553735Seric case 'G': /* match recipients against GECOS field */ 160653735Seric MatchGecos = atobool(val); 160753735Seric break; 160853735Seric 16098256Seric case 'g': /* default gid */ 1610*68481Seric g_opt: 161164133Seric if (isascii(*val) && isdigit(*val)) 161264133Seric DefGid = atoi(val); 161364133Seric else 161464133Seric { 161564133Seric register struct group *gr; 161664133Seric 161764133Seric DefGid = -1; 161864133Seric gr = getgrnam(val); 161964133Seric if (gr == NULL) 1620*68481Seric syserr("readcf: option %c: unknown group %s", 1621*68481Seric opt, val); 162264133Seric else 162364133Seric DefGid = gr->gr_gid; 162464133Seric } 16258256Seric break; 16268256Seric 16278256Seric case 'H': /* help file */ 16289381Seric if (val[0] == '\0') 16298269Seric HelpFile = "sendmail.hf"; 16309381Seric else 16319381Seric HelpFile = newstr(val); 16328256Seric break; 16338256Seric 163451305Seric case 'h': /* maximum hop count */ 163551305Seric MaxHopCount = atoi(val); 163651305Seric break; 163751305Seric 163835651Seric case 'I': /* use internet domain name server */ 163966334Seric #if NAMED_BIND 164057207Seric for (p = val; *p != 0; ) 164157207Seric { 164257207Seric bool clearmode; 164357207Seric char *q; 164457207Seric struct resolverflags *rfp; 164557207Seric 164657207Seric while (*p == ' ') 164757207Seric p++; 164857207Seric if (*p == '\0') 164957207Seric break; 165057207Seric clearmode = FALSE; 165157207Seric if (*p == '-') 165257207Seric clearmode = TRUE; 165357207Seric else if (*p != '+') 165457207Seric p--; 165557207Seric p++; 165657207Seric q = p; 165758050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 165857207Seric p++; 165957207Seric if (*p != '\0') 166057207Seric *p++ = '\0'; 166157207Seric for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 166257207Seric { 166357207Seric if (strcasecmp(q, rfp->rf_name) == 0) 166457207Seric break; 166557207Seric } 166664923Seric if (rfp->rf_name == NULL) 166764923Seric syserr("readcf: I option value %s unrecognized", q); 166864923Seric else if (clearmode) 166957207Seric _res.options &= ~rfp->rf_bits; 167057207Seric else 167157207Seric _res.options |= rfp->rf_bits; 167257207Seric } 167357207Seric if (tTd(8, 2)) 167457207Seric printf("_res.options = %x\n", _res.options); 167557207Seric #else 167657207Seric usrerr("name server (I option) specified but BIND not compiled in"); 167757207Seric #endif 167835651Seric break; 167935651Seric 16808269Seric case 'i': /* ignore dot lines in message */ 16819381Seric IgnrDot = atobool(val); 16828269Seric break; 16838269Seric 168459730Seric case 'j': /* send errors in MIME (RFC 1341) format */ 168559730Seric SendMIMEErrors = atobool(val); 168659730Seric break; 168759730Seric 168857136Seric case 'J': /* .forward search path */ 168957136Seric ForwardPath = newstr(val); 169057136Seric break; 169157136Seric 169254967Seric case 'k': /* connection cache size */ 169354967Seric MaxMciCache = atoi(val); 169456215Seric if (MaxMciCache < 0) 169556215Seric MaxMciCache = 0; 169654967Seric break; 169754967Seric 169854967Seric case 'K': /* connection cache timeout */ 169958796Seric MciCacheTimeout = convtime(val, 'm'); 170054967Seric break; 170154967Seric 170261104Seric case 'l': /* use Errors-To: header */ 170361104Seric UseErrorsTo = atobool(val); 170461104Seric break; 170561104Seric 17068256Seric case 'L': /* log level */ 170764140Seric if (safe || LogLevel < atoi(val)) 170864140Seric LogLevel = atoi(val); 17098256Seric break; 17108256Seric 17118269Seric case 'M': /* define macro */ 171268267Seric p = newstr(&val[1]); 171368267Seric if (!safe) 171468267Seric cleanstrcpy(p, p, MAXNAME); 171568267Seric define(val[0], p, CurEnv); 171616878Seric sticky = FALSE; 17178269Seric break; 17188269Seric 17198269Seric case 'm': /* send to me too */ 17209381Seric MeToo = atobool(val); 17218269Seric break; 17228269Seric 172325820Seric case 'n': /* validate RHS in newaliases */ 172425820Seric CheckAliases = atobool(val); 172525820Seric break; 172625820Seric 172761104Seric /* 'N' available -- was "net name" */ 172861104Seric 172958851Seric case 'O': /* daemon options */ 173058851Seric setdaemonoptions(val); 173158851Seric break; 173258851Seric 17338269Seric case 'o': /* assume old style headers */ 17349381Seric if (atobool(val)) 17359341Seric CurEnv->e_flags |= EF_OLDSTYLE; 17369341Seric else 17379341Seric CurEnv->e_flags &= ~EF_OLDSTYLE; 17388269Seric break; 17398269Seric 174058082Seric case 'p': /* select privacy level */ 174158082Seric p = val; 174258082Seric for (;;) 174358082Seric { 174458082Seric register struct prival *pv; 174558082Seric extern struct prival PrivacyValues[]; 174658082Seric 174758082Seric while (isascii(*p) && (isspace(*p) || ispunct(*p))) 174858082Seric p++; 174958082Seric if (*p == '\0') 175058082Seric break; 175158082Seric val = p; 175258082Seric while (isascii(*p) && isalnum(*p)) 175358082Seric p++; 175458082Seric if (*p != '\0') 175558082Seric *p++ = '\0'; 175658082Seric 175758082Seric for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 175858082Seric { 175958082Seric if (strcasecmp(val, pv->pv_name) == 0) 176058082Seric break; 176158082Seric } 176258886Seric if (pv->pv_name == NULL) 176358886Seric syserr("readcf: Op line: %s unrecognized", val); 176458082Seric PrivacyFlags |= pv->pv_flag; 176558082Seric } 176668479Seric sticky = FALSE; 176758082Seric break; 176858082Seric 176924944Seric case 'P': /* postmaster copy address for returned mail */ 177024944Seric PostMasterCopy = newstr(val); 177124944Seric break; 177224944Seric 177324944Seric case 'q': /* slope of queue only function */ 177424944Seric QueueFactor = atoi(val); 177524944Seric break; 177624944Seric 17778256Seric case 'Q': /* queue directory */ 17789381Seric if (val[0] == '\0') 17798269Seric QueueDir = "mqueue"; 17809381Seric else 17819381Seric QueueDir = newstr(val); 178258789Seric if (RealUid != 0 && !safe) 178364718Seric Warn_Q_option = TRUE; 17848256Seric break; 17858256Seric 178658148Seric case 'R': /* don't prune routes */ 178758148Seric DontPruneRoutes = atobool(val); 178858148Seric break; 178958148Seric 17908256Seric case 'r': /* read timeout */ 1791*68481Seric if (subopt == NULL) 1792*68481Seric inittimeouts(val); 1793*68481Seric else 1794*68481Seric settimeout(subopt, val); 17958256Seric break; 17968256Seric 17978256Seric case 'S': /* status file */ 17989381Seric if (val[0] == '\0') 17998269Seric StatFile = "sendmail.st"; 18009381Seric else 18019381Seric StatFile = newstr(val); 18028256Seric break; 18038256Seric 18048265Seric case 's': /* be super safe, even if expensive */ 18059381Seric SuperSafe = atobool(val); 18068256Seric break; 18078256Seric 18088256Seric case 'T': /* queue timeout */ 180958737Seric p = strchr(val, '/'); 181058737Seric if (p != NULL) 181158737Seric { 181258737Seric *p++ = '\0'; 1813*68481Seric settimeout("queuewarn", p); 181458737Seric } 1815*68481Seric settimeout("queuereturn", val); 181654967Seric break; 18178256Seric 18188265Seric case 't': /* time zone name */ 181952106Seric TimeZoneSpec = newstr(val); 18208265Seric break; 18218265Seric 182250556Seric case 'U': /* location of user database */ 182351360Seric UdbSpec = newstr(val); 182450556Seric break; 182550556Seric 18268256Seric case 'u': /* set default uid */ 1827*68481Seric for (p = val; *p != '\0'; p++) 1828*68481Seric { 1829*68481Seric if (*p == '.' || *p == '/' || *p == ':') 1830*68481Seric { 1831*68481Seric *p++ = '\0'; 1832*68481Seric break; 1833*68481Seric } 1834*68481Seric } 183564133Seric if (isascii(*val) && isdigit(*val)) 183664133Seric DefUid = atoi(val); 183764133Seric else 183864133Seric { 183964133Seric register struct passwd *pw; 184064133Seric 184164133Seric DefUid = -1; 184264133Seric pw = getpwnam(val); 184364133Seric if (pw == NULL) 184464133Seric syserr("readcf: option u: unknown user %s", val); 184564133Seric else 1846*68481Seric { 184764133Seric DefUid = pw->pw_uid; 1848*68481Seric DefGid = pw->pw_gid; 1849*68481Seric } 185064133Seric } 185140973Sbostic setdefuser(); 18528256Seric 1853*68481Seric /* handle the group if it is there */ 1854*68481Seric if (*p == '\0') 1855*68481Seric break; 1856*68481Seric val = p; 1857*68481Seric goto g_opt; 1858*68481Seric 185958851Seric case 'V': /* fallback MX host */ 186058851Seric FallBackMX = newstr(val); 186158851Seric break; 186258851Seric 18638269Seric case 'v': /* run in verbose mode */ 18649381Seric Verbose = atobool(val); 18658256Seric break; 18668256Seric 186763837Seric case 'w': /* if we are best MX, try host directly */ 186863837Seric TryNullMXList = atobool(val); 186963837Seric break; 187061104Seric 187161104Seric /* 'W' available -- was wizard password */ 187261104Seric 187314879Seric case 'x': /* load avg at which to auto-queue msgs */ 187414879Seric QueueLA = atoi(val); 187514879Seric break; 187614879Seric 187714879Seric case 'X': /* load avg at which to auto-reject connections */ 187814879Seric RefuseLA = atoi(val); 187914879Seric break; 188014879Seric 188124981Seric case 'y': /* work recipient factor */ 188224981Seric WkRecipFact = atoi(val); 188324981Seric break; 188424981Seric 188524981Seric case 'Y': /* fork jobs during queue runs */ 188624952Seric ForkQueueRuns = atobool(val); 188724952Seric break; 188824952Seric 188924981Seric case 'z': /* work message class factor */ 189024981Seric WkClassFact = atoi(val); 189124981Seric break; 189224981Seric 189324981Seric case 'Z': /* work time factor */ 189424981Seric WkTimeFact = atoi(val); 189524981Seric break; 189624981Seric 1897*68481Seric case O_BSP: /* SMTP Peers can't handle 2-line greeting */ 1898*68481Seric BrokenSmtpPeers = atobool(val); 1899*68481Seric break; 1900*68481Seric 1901*68481Seric case O_QUEUESORTORD: /* queue sorting order */ 1902*68481Seric switch (*val) 1903*68481Seric { 1904*68481Seric case 'h': /* Host first */ 1905*68481Seric case 'H': 1906*68481Seric QueueSortOrder = QS_BYHOST; 1907*68481Seric break; 1908*68481Seric 1909*68481Seric case 'p': /* Priority order */ 1910*68481Seric case 'P': 1911*68481Seric QueueSortOrder = QS_BYPRIORITY; 1912*68481Seric break; 1913*68481Seric 1914*68481Seric default: 1915*68481Seric syserr("Invalid queue sort order \"%s\"", val); 1916*68481Seric } 1917*68481Seric break; 1918*68481Seric 1919*68481Seric case O_MQA: /* minimum queue age between deliveries */ 1920*68481Seric MinQueueAge = convtime(val, 'm'); 1921*68481Seric break; 1922*68481Seric 1923*68481Seric case O_MHSA: /* maximum age of cached host status */ 1924*68481Seric MaxHostStatAge = convtime(val, 'm'); 1925*68481Seric break; 1926*68481Seric 1927*68481Seric case O_DEFCHARSET: /* default character set for mimefying */ 1928*68481Seric DefaultCharSet = newstr(denlstring(val, TRUE, TRUE)); 1929*68481Seric break; 1930*68481Seric 1931*68481Seric case O_SSFILE: /* service switch file */ 1932*68481Seric ServiceSwitchFile = newstr(val); 1933*68481Seric break; 1934*68481Seric 1935*68481Seric case O_DIALDELAY: /* delay for dial-on-demand operation */ 1936*68481Seric DialDelay = convtime(val, 's'); 1937*68481Seric break; 1938*68481Seric 1939*68481Seric case O_NORCPTACTION: /* what to do if no recipient */ 1940*68481Seric if (strcasecmp(val, "none") == 0) 1941*68481Seric NoRecipientAction = NRA_NO_ACTION; 1942*68481Seric else if (strcasecmp(val, "add-to") == 0) 1943*68481Seric NoRecipientAction = NRA_ADD_TO; 1944*68481Seric else if (strcasecmp(val, "add-apparently-to") == 0) 1945*68481Seric NoRecipientAction = NRA_ADD_APPARENTLY_TO; 1946*68481Seric else if (strcasecmp(val, "add-bcc") == 0) 1947*68481Seric NoRecipientAction = NRA_ADD_BCC; 1948*68481Seric else if (strcasecmp(val, "add-to-undisclosed") == 0) 1949*68481Seric NoRecipientAction = NRA_ADD_TO_UNDISCLOSED; 1950*68481Seric else 1951*68481Seric syserr("Invalid NoRecipientAction: %s", val); 1952*68481Seric 19538256Seric default: 1954*68481Seric if (tTd(37, 1)) 1955*68481Seric { 1956*68481Seric if (isascii(opt) && isprint(opt)) 1957*68481Seric printf("Warning: option %c unknown\n", opt); 1958*68481Seric else 1959*68481Seric printf("Warning: option 0x%x unknown\n", opt); 1960*68481Seric } 19618256Seric break; 19628256Seric } 196316878Seric if (sticky) 196416878Seric setbitn(opt, StickyOpt); 19659188Seric return; 19668256Seric } 196710687Seric /* 1968*68481Seric ** SETCLASS -- set a string into a class 196910687Seric ** 197010687Seric ** Parameters: 1971*68481Seric ** class -- the class to put the string in. 1972*68481Seric ** str -- the string to enter 197310687Seric ** 197410687Seric ** Returns: 197510687Seric ** none. 197610687Seric ** 197710687Seric ** Side Effects: 197810687Seric ** puts the word into the symbol table. 197910687Seric */ 198010687Seric 1981*68481Seric setclass(class, str) 198210687Seric int class; 1983*68481Seric char *str; 198410687Seric { 198510687Seric register STAB *s; 198610687Seric 198757943Seric if (tTd(37, 8)) 1988*68481Seric printf("setclass(%c, %s)\n", class, str); 1989*68481Seric s = stab(str, ST_CLASS, ST_ENTER); 199010687Seric setbitn(class, s->s_class); 199110687Seric } 199253654Seric /* 199353654Seric ** MAKEMAPENTRY -- create a map entry 199453654Seric ** 199553654Seric ** Parameters: 199653654Seric ** line -- the config file line 199753654Seric ** 199853654Seric ** Returns: 199953654Seric ** TRUE if it successfully entered the map entry. 200053654Seric ** FALSE otherwise (usually syntax error). 200153654Seric ** 200253654Seric ** Side Effects: 200353654Seric ** Enters the map into the dictionary. 200453654Seric */ 200553654Seric 200653654Seric void 200753654Seric makemapentry(line) 200853654Seric char *line; 200953654Seric { 201053654Seric register char *p; 201153654Seric char *mapname; 201253654Seric char *classname; 201364078Seric register STAB *s; 201453654Seric STAB *class; 201553654Seric 201658050Seric for (p = line; isascii(*p) && isspace(*p); p++) 201753654Seric continue; 201858050Seric if (!(isascii(*p) && isalnum(*p))) 201953654Seric { 202053654Seric syserr("readcf: config K line: no map name"); 202153654Seric return; 202253654Seric } 202353654Seric 202453654Seric mapname = p; 2025*68481Seric while ((isascii(*++p) && isalnum(*p)) || *p == '.') 202653654Seric continue; 202753654Seric if (*p != '\0') 202853654Seric *p++ = '\0'; 202958050Seric while (isascii(*p) && isspace(*p)) 203053654Seric p++; 203158050Seric if (!(isascii(*p) && isalnum(*p))) 203253654Seric { 203353654Seric syserr("readcf: config K line, map %s: no map class", mapname); 203453654Seric return; 203553654Seric } 203653654Seric classname = p; 203758050Seric while (isascii(*++p) && isalnum(*p)) 203853654Seric continue; 203953654Seric if (*p != '\0') 204053654Seric *p++ = '\0'; 204158050Seric while (isascii(*p) && isspace(*p)) 204253654Seric p++; 204353654Seric 204453654Seric /* look up the class */ 204553654Seric class = stab(classname, ST_MAPCLASS, ST_FIND); 204653654Seric if (class == NULL) 204753654Seric { 204853654Seric syserr("readcf: map %s: class %s not available", mapname, classname); 204953654Seric return; 205053654Seric } 205153654Seric 205253654Seric /* enter the map */ 205364078Seric s = stab(mapname, ST_MAP, ST_ENTER); 205464078Seric s->s_map.map_class = &class->s_mapclass; 205564078Seric s->s_map.map_mname = newstr(mapname); 205653654Seric 205764078Seric if (class->s_mapclass.map_parse(&s->s_map, p)) 205864078Seric s->s_map.map_mflags |= MF_VALID; 205964078Seric 206064078Seric if (tTd(37, 5)) 206164078Seric { 206264078Seric printf("map %s, class %s, flags %x, file %s,\n", 206364078Seric s->s_map.map_mname, s->s_map.map_class->map_cname, 206464078Seric s->s_map.map_mflags, 206564078Seric s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 206664078Seric printf("\tapp %s, domain %s, rebuild %s\n", 206764078Seric s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 206864078Seric s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 206964078Seric s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 207064078Seric } 207153654Seric } 207258112Seric /* 2073*68481Seric ** INITTIMEOUTS -- parse and set timeout values 207458112Seric ** 207558112Seric ** Parameters: 207658112Seric ** val -- a pointer to the values. If NULL, do initial 207758112Seric ** settings. 207858112Seric ** 207958112Seric ** Returns: 208058112Seric ** none. 208158112Seric ** 208258112Seric ** Side Effects: 208358112Seric ** Initializes the TimeOuts structure 208458112Seric */ 208558112Seric 208664255Seric #define SECONDS 208758112Seric #define MINUTES * 60 208858112Seric #define HOUR * 3600 208958112Seric 2090*68481Seric inittimeouts(val) 209158112Seric register char *val; 209258112Seric { 209358112Seric register char *p; 209458671Seric extern time_t convtime(); 209558112Seric 209658112Seric if (val == NULL) 209758112Seric { 209858112Seric TimeOuts.to_initial = (time_t) 5 MINUTES; 209958112Seric TimeOuts.to_helo = (time_t) 5 MINUTES; 210058112Seric TimeOuts.to_mail = (time_t) 10 MINUTES; 210158112Seric TimeOuts.to_rcpt = (time_t) 1 HOUR; 210258112Seric TimeOuts.to_datainit = (time_t) 5 MINUTES; 210358112Seric TimeOuts.to_datablock = (time_t) 1 HOUR; 210458112Seric TimeOuts.to_datafinal = (time_t) 1 HOUR; 210558112Seric TimeOuts.to_rset = (time_t) 5 MINUTES; 210658112Seric TimeOuts.to_quit = (time_t) 2 MINUTES; 210758112Seric TimeOuts.to_nextcommand = (time_t) 1 HOUR; 210858112Seric TimeOuts.to_miscshort = (time_t) 2 MINUTES; 2109*68481Seric #if IDENTPROTO 211064255Seric TimeOuts.to_ident = (time_t) 30 SECONDS; 2111*68481Seric #else 2112*68481Seric TimeOuts.to_ident = (time_t) 0 SECONDS; 2113*68481Seric #endif 2114*68481Seric TimeOuts.to_fileopen = (time_t) 60 SECONDS; 211558112Seric return; 211658112Seric } 211758112Seric 211858112Seric for (;; val = p) 211958112Seric { 212058112Seric while (isascii(*val) && isspace(*val)) 212158112Seric val++; 212258112Seric if (*val == '\0') 212358112Seric break; 212458112Seric for (p = val; *p != '\0' && *p != ','; p++) 212558112Seric continue; 212658112Seric if (*p != '\0') 212758112Seric *p++ = '\0'; 212858112Seric 212958112Seric if (isascii(*val) && isdigit(*val)) 213058112Seric { 213158112Seric /* old syntax -- set everything */ 213258796Seric TimeOuts.to_mail = convtime(val, 'm'); 213358112Seric TimeOuts.to_rcpt = TimeOuts.to_mail; 213458112Seric TimeOuts.to_datainit = TimeOuts.to_mail; 213558112Seric TimeOuts.to_datablock = TimeOuts.to_mail; 213658112Seric TimeOuts.to_datafinal = TimeOuts.to_mail; 213758112Seric TimeOuts.to_nextcommand = TimeOuts.to_mail; 213858112Seric continue; 213958112Seric } 214058112Seric else 214158112Seric { 2142*68481Seric register char *q = strchr(val, ':'); 214358112Seric 2144*68481Seric if (q == NULL && (q = strchr(val, '=')) == NULL) 214558112Seric { 214658112Seric /* syntax error */ 214758112Seric continue; 214858112Seric } 214958112Seric *q++ = '\0'; 2150*68481Seric settimeout(val, q); 2151*68481Seric } 2152*68481Seric } 2153*68481Seric } 2154*68481Seric /* 2155*68481Seric ** SETTIMEOUT -- set an individual timeout 2156*68481Seric ** 2157*68481Seric ** Parameters: 2158*68481Seric ** name -- the name of the timeout. 2159*68481Seric ** val -- the value of the timeout. 2160*68481Seric ** 2161*68481Seric ** Returns: 2162*68481Seric ** none. 2163*68481Seric */ 216458112Seric 2165*68481Seric settimeout(name, val) 2166*68481Seric char *name; 2167*68481Seric char *val; 2168*68481Seric { 2169*68481Seric register char *p; 2170*68481Seric time_t to; 2171*68481Seric extern time_t convtime(); 2172*68481Seric 2173*68481Seric to = convtime(val, 'm'); 2174*68481Seric p = strchr(name, '.'); 2175*68481Seric if (p != NULL) 2176*68481Seric *p++ = '\0'; 2177*68481Seric 2178*68481Seric if (strcasecmp(name, "initial") == 0) 2179*68481Seric TimeOuts.to_initial = to; 2180*68481Seric else if (strcasecmp(name, "mail") == 0) 2181*68481Seric TimeOuts.to_mail = to; 2182*68481Seric else if (strcasecmp(name, "rcpt") == 0) 2183*68481Seric TimeOuts.to_rcpt = to; 2184*68481Seric else if (strcasecmp(name, "datainit") == 0) 2185*68481Seric TimeOuts.to_datainit = to; 2186*68481Seric else if (strcasecmp(name, "datablock") == 0) 2187*68481Seric TimeOuts.to_datablock = to; 2188*68481Seric else if (strcasecmp(name, "datafinal") == 0) 2189*68481Seric TimeOuts.to_datafinal = to; 2190*68481Seric else if (strcasecmp(name, "command") == 0) 2191*68481Seric TimeOuts.to_nextcommand = to; 2192*68481Seric else if (strcasecmp(name, "rset") == 0) 2193*68481Seric TimeOuts.to_rset = to; 2194*68481Seric else if (strcasecmp(name, "helo") == 0) 2195*68481Seric TimeOuts.to_helo = to; 2196*68481Seric else if (strcasecmp(name, "quit") == 0) 2197*68481Seric TimeOuts.to_quit = to; 2198*68481Seric else if (strcasecmp(name, "misc") == 0) 2199*68481Seric TimeOuts.to_miscshort = to; 2200*68481Seric else if (strcasecmp(name, "ident") == 0) 2201*68481Seric TimeOuts.to_ident = to; 2202*68481Seric else if (strcasecmp(name, "fileopen") == 0) 2203*68481Seric TimeOuts.to_fileopen = to; 2204*68481Seric else if (strcasecmp(name, "queuewarn") == 0) 2205*68481Seric { 2206*68481Seric to = convtime(val, 'h'); 2207*68481Seric if (p == NULL || strcmp(p, "*") == 0) 2208*68481Seric { 2209*68481Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 2210*68481Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 2211*68481Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 221258112Seric } 2213*68481Seric else if (strcasecmp(p, "normal") == 0) 2214*68481Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 2215*68481Seric else if (strcasecmp(p, "urgent") == 0) 2216*68481Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 2217*68481Seric else if (strcasecmp(p, "non-urgent") == 0) 2218*68481Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 2219*68481Seric else 2220*68481Seric syserr("settimeout: invalid queuewarn subtimeout %s", p); 222158112Seric } 2222*68481Seric else if (strcasecmp(name, "queuereturn") == 0) 2223*68481Seric { 2224*68481Seric to = convtime(val, 'd'); 2225*68481Seric if (p == NULL || strcmp(p, "*") == 0) 2226*68481Seric { 2227*68481Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 2228*68481Seric TimeOuts.to_q_return[TOC_URGENT] = to; 2229*68481Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 2230*68481Seric } 2231*68481Seric else if (strcasecmp(p, "normal") == 0) 2232*68481Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 2233*68481Seric else if (strcasecmp(p, "urgent") == 0) 2234*68481Seric TimeOuts.to_q_return[TOC_URGENT] = to; 2235*68481Seric else if (strcasecmp(p, "non-urgent") == 0) 2236*68481Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 2237*68481Seric else 2238*68481Seric syserr("settimeout: invalid queuereturn subtimeout %s", p); 2239*68481Seric } 2240*68481Seric else 2241*68481Seric syserr("settimeout: invalid timeout %s", name); 224258112Seric } 2243