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*68276Seric static char sccsid[] = "@(#)readcf.c 8.65 (Berkeley) 02/10/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; 738547Seric char *q; 749350Seric struct rewrite *rwp = NULL; 7557135Seric char *bp; 7664718Seric auto char *ep; 7757589Seric int nfuzzy; 7864133Seric char *file; 7964133Seric bool optional; 80*68276Seric int mid; 813308Seric char buf[MAXLINE]; 823308Seric register char *p; 833308Seric extern char **copyplist(); 8452647Seric struct stat statb; 855909Seric char exbuf[MAXLINE]; 8665066Seric char pvpbuf[MAXLINE + MAXATOM]; 87*68276Seric static char *null_list[1] = { NULL }; 8810709Seric extern char *munchstring(); 8953654Seric extern void makemapentry(); 903308Seric 9152647Seric FileName = cfname; 9252647Seric LineNumber = 0; 9352647Seric 943308Seric cf = fopen(cfname, "r"); 953308Seric if (cf == NULL) 963308Seric { 9752647Seric syserr("cannot open"); 983308Seric exit(EX_OSFILE); 993308Seric } 1003308Seric 10152647Seric if (fstat(fileno(cf), &statb) < 0) 10252647Seric { 10352647Seric syserr("cannot fstat"); 10452647Seric exit(EX_OSFILE); 10552647Seric } 10652647Seric 10752647Seric if (!S_ISREG(statb.st_mode)) 10852647Seric { 10952647Seric syserr("not a plain file"); 11052647Seric exit(EX_OSFILE); 11152647Seric } 11252647Seric 11352647Seric if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode)) 11452647Seric { 11553037Seric if (OpMode == MD_DAEMON || OpMode == MD_FREEZE) 11653037Seric fprintf(stderr, "%s: WARNING: dangerous write permissions\n", 11753037Seric FileName); 11853037Seric #ifdef LOG 11953037Seric if (LogLevel > 0) 12053037Seric syslog(LOG_CRIT, "%s: WARNING: dangerous write permissions", 12153037Seric FileName); 12253037Seric #endif 12352647Seric } 12452647Seric 12559254Seric #ifdef XLA 12659254Seric xla_zero(); 12759254Seric #endif 12859254Seric 12957135Seric while ((bp = fgetfolded(buf, sizeof buf, cf)) != NULL) 1303308Seric { 13157135Seric if (bp[0] == '#') 13257135Seric { 13357135Seric if (bp != buf) 13457135Seric free(bp); 13552637Seric continue; 13657135Seric } 13752637Seric 138*68276Seric /* do macro expansion mappings */ 13957135Seric for (p = bp; *p != '\0'; p++) 14016157Seric { 14157135Seric if (*p == '#' && p > bp && ConfigLevel >= 3) 14252647Seric { 14352647Seric /* this is an on-line comment */ 14452647Seric register char *e; 14552647Seric 14658050Seric switch (*--p & 0377) 14752647Seric { 14858050Seric case MACROEXPAND: 14952647Seric /* it's from $# -- let it go through */ 15052647Seric p++; 15152647Seric break; 15252647Seric 15352647Seric case '\\': 15452647Seric /* it's backslash escaped */ 15552647Seric (void) strcpy(p, p + 1); 15652647Seric break; 15752647Seric 15852647Seric default: 15952647Seric /* delete preceeding white space */ 16058050Seric while (isascii(*p) && isspace(*p) && p > bp) 16152647Seric p--; 16256795Seric if ((e = strchr(++p, '\n')) != NULL) 16352647Seric (void) strcpy(p, e); 16452647Seric else 16552647Seric p[0] = p[1] = '\0'; 16652647Seric break; 16752647Seric } 16852647Seric continue; 16952647Seric } 17052647Seric 171*68276Seric if (*p != '$' || p[1] == '\0') 17216157Seric continue; 17316157Seric 17416157Seric if (p[1] == '$') 17516157Seric { 17616157Seric /* actual dollar sign.... */ 17723111Seric (void) strcpy(p, p + 1); 17816157Seric continue; 17916157Seric } 18016157Seric 18116157Seric /* convert to macro expansion character */ 182*68276Seric *p++ = MACROEXPAND; 183*68276Seric 184*68276Seric /* convert macro name to code */ 185*68276Seric *p = macid(p, &ep); 186*68276Seric if (ep != p) 187*68276Seric strcpy(p + 1, ep); 18816157Seric } 18916157Seric 19016157Seric /* interpret this line */ 19164718Seric errno = 0; 19257135Seric switch (bp[0]) 1933308Seric { 1943308Seric case '\0': 1953308Seric case '#': /* comment */ 1963308Seric break; 1973308Seric 1983308Seric case 'R': /* rewriting rule */ 19957135Seric for (p = &bp[1]; *p != '\0' && *p != '\t'; p++) 2003308Seric continue; 2013308Seric 2023308Seric if (*p == '\0') 2035909Seric { 20465821Seric syserr("invalid rewrite line \"%s\" (tab expected)", bp); 2055909Seric break; 2065909Seric } 2075909Seric 2085909Seric /* allocate space for the rule header */ 2095909Seric if (rwp == NULL) 2105909Seric { 2115909Seric RewriteRules[ruleset] = rwp = 2125909Seric (struct rewrite *) xalloc(sizeof *rwp); 2135909Seric } 2143308Seric else 2153308Seric { 2165909Seric rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp); 2175909Seric rwp = rwp->r_next; 2185909Seric } 2195909Seric rwp->r_next = NULL; 2203308Seric 2215909Seric /* expand and save the LHS */ 2225909Seric *p = '\0'; 22357135Seric expand(&bp[1], exbuf, &exbuf[sizeof exbuf], e); 22465066Seric rwp->r_lhs = prescan(exbuf, '\t', pvpbuf, 22565066Seric sizeof pvpbuf, NULL); 22657589Seric nfuzzy = 0; 2275909Seric if (rwp->r_lhs != NULL) 22857589Seric { 22957589Seric register char **ap; 23057589Seric 2315909Seric rwp->r_lhs = copyplist(rwp->r_lhs, TRUE); 23257589Seric 23357589Seric /* count the number of fuzzy matches in LHS */ 23457589Seric for (ap = rwp->r_lhs; *ap != NULL; ap++) 23557589Seric { 23658148Seric char *botch; 23758148Seric 23858148Seric botch = NULL; 23958050Seric switch (**ap & 0377) 24057589Seric { 24157589Seric case MATCHZANY: 24257589Seric case MATCHANY: 24357589Seric case MATCHONE: 24457589Seric case MATCHCLASS: 24557589Seric case MATCHNCLASS: 24657589Seric nfuzzy++; 24758148Seric break; 24858148Seric 24958148Seric case MATCHREPL: 25058148Seric botch = "$0-$9"; 25158148Seric break; 25258148Seric 25358148Seric case CANONNET: 25458148Seric botch = "$#"; 25558148Seric break; 25658148Seric 25758148Seric case CANONUSER: 25858148Seric botch = "$:"; 25958148Seric break; 26058148Seric 26158148Seric case CALLSUBR: 26258148Seric botch = "$>"; 26358148Seric break; 26458148Seric 26558148Seric case CONDIF: 26658148Seric botch = "$?"; 26758148Seric break; 26858148Seric 26958148Seric case CONDELSE: 27058148Seric botch = "$|"; 27158148Seric break; 27258148Seric 27358148Seric case CONDFI: 27458148Seric botch = "$."; 27558148Seric break; 27658148Seric 27758148Seric case HOSTBEGIN: 27858148Seric botch = "$["; 27958148Seric break; 28058148Seric 28158148Seric case HOSTEND: 28258148Seric botch = "$]"; 28358148Seric break; 28458148Seric 28558148Seric case LOOKUPBEGIN: 28658148Seric botch = "$("; 28758148Seric break; 28858148Seric 28958148Seric case LOOKUPEND: 29058148Seric botch = "$)"; 29158148Seric break; 29257589Seric } 29358148Seric if (botch != NULL) 29458148Seric syserr("Inappropriate use of %s on LHS", 29558148Seric botch); 29657589Seric } 29757589Seric } 29856678Seric else 299*68276Seric { 30056678Seric syserr("R line: null LHS"); 301*68276Seric rwp->r_lhs = null_list; 302*68276Seric } 3035909Seric 3045909Seric /* expand and save the RHS */ 3055909Seric while (*++p == '\t') 3065909Seric continue; 3077231Seric q = p; 3087231Seric while (*p != '\0' && *p != '\t') 3097231Seric p++; 3107231Seric *p = '\0'; 31155012Seric expand(q, exbuf, &exbuf[sizeof exbuf], e); 31265066Seric rwp->r_rhs = prescan(exbuf, '\t', pvpbuf, 31365066Seric sizeof pvpbuf, NULL); 3145909Seric if (rwp->r_rhs != NULL) 31557589Seric { 31657589Seric register char **ap; 31757589Seric 3185909Seric rwp->r_rhs = copyplist(rwp->r_rhs, TRUE); 31957589Seric 32057589Seric /* check no out-of-bounds replacements */ 32157589Seric nfuzzy += '0'; 32257589Seric for (ap = rwp->r_rhs; *ap != NULL; ap++) 32357589Seric { 32458148Seric char *botch; 32558148Seric 32658148Seric botch = NULL; 32758148Seric switch (**ap & 0377) 32857589Seric { 32958148Seric case MATCHREPL: 33058148Seric if ((*ap)[1] <= '0' || (*ap)[1] > nfuzzy) 33158148Seric { 33258148Seric syserr("replacement $%c out of bounds", 33358148Seric (*ap)[1]); 33458148Seric } 33558148Seric break; 33658148Seric 33758148Seric case MATCHZANY: 33858148Seric botch = "$*"; 33958148Seric break; 34058148Seric 34158148Seric case MATCHANY: 34258148Seric botch = "$+"; 34358148Seric break; 34458148Seric 34558148Seric case MATCHONE: 34658148Seric botch = "$-"; 34758148Seric break; 34858148Seric 34958148Seric case MATCHCLASS: 35058148Seric botch = "$="; 35158148Seric break; 35258148Seric 35358148Seric case MATCHNCLASS: 35458148Seric botch = "$~"; 35558148Seric break; 35657589Seric } 35758148Seric if (botch != NULL) 35858148Seric syserr("Inappropriate use of %s on RHS", 35958148Seric botch); 36057589Seric } 36157589Seric } 36256678Seric else 363*68276Seric { 36456678Seric syserr("R line: null RHS"); 365*68276Seric rwp->r_rhs = null_list; 366*68276Seric } 3673308Seric break; 3683308Seric 3694072Seric case 'S': /* select rewriting set */ 37064440Seric for (p = &bp[1]; isascii(*p) && isspace(*p); p++) 37164440Seric continue; 37264440Seric if (!isascii(*p) || !isdigit(*p)) 37364440Seric { 37464440Seric syserr("invalid argument to S line: \"%.20s\"", 37564440Seric &bp[1]); 37664440Seric break; 37764440Seric } 37864440Seric ruleset = atoi(p); 3798056Seric if (ruleset >= MAXRWSETS || ruleset < 0) 3808056Seric { 3819381Seric syserr("bad ruleset %d (%d max)", ruleset, MAXRWSETS); 3828056Seric ruleset = 0; 3838056Seric } 3844072Seric rwp = NULL; 3854072Seric break; 3864072Seric 3873308Seric case 'D': /* macro definition */ 388*68276Seric mid = macid(&bp[1], &ep); 389*68276Seric p = munchstring(ep, NULL); 390*68276Seric define(mid, newstr(p), e); 3913308Seric break; 3923308Seric 3933387Seric case 'H': /* required header line */ 39457135Seric (void) chompheader(&bp[1], TRUE, e); 3953387Seric break; 3963387Seric 3974061Seric case 'C': /* word class */ 3984432Seric /* scan the list of words and set class for all */ 399*68276Seric mid = macid(&bp[1], &ep); 400*68276Seric expand(ep, exbuf, &exbuf[sizeof exbuf], e); 40164121Seric for (p = exbuf; *p != '\0'; ) 4024061Seric { 4034061Seric register char *wd; 4044061Seric char delim; 4054061Seric 40658050Seric while (*p != '\0' && isascii(*p) && isspace(*p)) 4074061Seric p++; 4084061Seric wd = p; 40958050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 4104061Seric p++; 4114061Seric delim = *p; 4124061Seric *p = '\0'; 4134061Seric if (wd[0] != '\0') 414*68276Seric setclass(mid, wd); 4154061Seric *p = delim; 4164061Seric } 4174061Seric break; 4184061Seric 41959272Seric case 'F': /* word class from file */ 420*68276Seric mid = macid(&bp[1], &ep); 421*68276Seric for (p = ep; isascii(*p) && isspace(*p); ) 42264133Seric p++; 42364133Seric if (p[0] == '-' && p[1] == 'o') 42464133Seric { 42564133Seric optional = TRUE; 42664133Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 42764133Seric p++; 42864133Seric while (isascii(*p) && isspace(*p)) 429*68276Seric p++; 43064133Seric } 43164133Seric else 43264133Seric optional = FALSE; 43364133Seric file = p; 43464133Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 43564133Seric p++; 43659272Seric if (*p == '\0') 43759272Seric p = "%s"; 43859272Seric else 43959272Seric { 44059272Seric *p = '\0'; 44159272Seric while (isascii(*++p) && isspace(*p)) 44259272Seric continue; 44359272Seric } 44464133Seric fileclass(bp[1], file, p, safe, optional); 44559272Seric break; 44659272Seric 44759156Seric #ifdef XLA 44859156Seric case 'L': /* extended load average description */ 44959156Seric xla_init(&bp[1]); 45059156Seric break; 45159156Seric #endif 45259156Seric 4534096Seric case 'M': /* define mailer */ 45457135Seric makemailer(&bp[1]); 4554096Seric break; 4564096Seric 4578252Seric case 'O': /* set option */ 45858734Seric setoption(bp[1], &bp[2], safe, FALSE, e); 4598252Seric break; 4608252Seric 4618252Seric case 'P': /* set precedence */ 4628252Seric if (NumPriorities >= MAXPRIORITIES) 4638252Seric { 4648547Seric toomany('P', MAXPRIORITIES); 4658252Seric break; 4668252Seric } 46757135Seric for (p = &bp[1]; *p != '\0' && *p != '=' && *p != '\t'; p++) 4688252Seric continue; 4698252Seric if (*p == '\0') 4708252Seric goto badline; 4718252Seric *p = '\0'; 47257135Seric Priorities[NumPriorities].pri_name = newstr(&bp[1]); 4738252Seric Priorities[NumPriorities].pri_val = atoi(++p); 4748252Seric NumPriorities++; 4758252Seric break; 4768252Seric 4778547Seric case 'T': /* trusted user(s) */ 478*68276Seric p = &buf[1]; 479*68276Seric while (*p != '\0') 480*68276Seric { 481*68276Seric while (isspace(*p)) 482*68276Seric p++; 483*68276Seric q = p; 484*68276Seric while (*p != '\0' && !isspace(*p)) 485*68276Seric p++; 486*68276Seric if (*p != '\0') 487*68276Seric *p++ = '\0'; 488*68276Seric if (*q == '\0') 489*68276Seric continue; 490*68276Seric (void) stab(q, ST_TRUSTED, ST_ENTER); 491*68276Seric } 4928547Seric break; 4938547Seric 49452645Seric case 'V': /* configuration syntax version */ 49564440Seric for (p = &bp[1]; isascii(*p) && isspace(*p); p++) 49664440Seric continue; 49764440Seric if (!isascii(*p) || !isdigit(*p)) 49864440Seric { 49964440Seric syserr("invalid argument to V line: \"%.20s\"", 50064440Seric &bp[1]); 50164440Seric break; 50264440Seric } 50364718Seric ConfigLevel = strtol(p, &ep, 10); 50464279Seric if (ConfigLevel >= 5) 50564279Seric { 50664279Seric /* level 5 configs have short name in $w */ 50764279Seric p = macvalue('w', e); 50864279Seric if (p != NULL && (p = strchr(p, '.')) != NULL) 50964279Seric *p = '\0'; 51064279Seric } 51164718Seric if (*ep++ == '/') 51264718Seric { 51364718Seric /* extract vendor code */ 51464718Seric for (p = ep; isascii(*p) && isalpha(*p); ) 51564718Seric p++; 51664718Seric *p = '\0'; 51764718Seric 51864718Seric if (!setvendor(ep)) 51964718Seric syserr("invalid V line vendor code: \"%s\"", 52064718Seric ep); 52164718Seric } 52252645Seric break; 52352645Seric 52453654Seric case 'K': 52557135Seric makemapentry(&bp[1]); 52653654Seric break; 52753654Seric 5283308Seric default: 5294061Seric badline: 53057135Seric syserr("unknown control line \"%s\"", bp); 5313308Seric } 53257135Seric if (bp != buf) 53357135Seric free(bp); 5343308Seric } 53552637Seric if (ferror(cf)) 53652637Seric { 53752647Seric syserr("I/O read error", cfname); 53852637Seric exit(EX_OSFILE); 53952637Seric } 54052637Seric fclose(cf); 5419381Seric FileName = NULL; 54256836Seric 543*68276Seric /* initialize host maps from local service tables */ 544*68276Seric inithostmaps(); 545*68276Seric 546*68276Seric /* determine if we need to do special name-server frotz */ 54767905Seric { 548*68276Seric int nmaps; 549*68276Seric char *maptype[MAXMAPSTACK]; 550*68276Seric short mapreturn[MAXMAPACTIONS]; 551*68276Seric 552*68276Seric nmaps = switch_map_find("hosts", maptype, mapreturn); 553*68276Seric UseNameServer = FALSE; 554*68276Seric if (nmaps > 0 && nmaps <= MAXMAPSTACK) 555*68276Seric { 556*68276Seric register int mapno; 557*68276Seric 558*68276Seric for (mapno = 0; mapno < nmaps && !UseNameServer; mapno++) 559*68276Seric { 560*68276Seric if (strcmp(maptype[mapno], "dns") == 0) 561*68276Seric UseNameServer = TRUE; 562*68276Seric } 563*68276Seric } 564*68276Seric 565*68276Seric #ifdef HESIOD 566*68276Seric nmaps = switch_map_find("passwd", maptype, mapreturn); 567*68276Seric UseHesiod = FALSE; 568*68276Seric if (nmaps > 0 && nmaps <= MAXMAPSTACK) 569*68276Seric { 570*68276Seric register int mapno; 571*68276Seric 572*68276Seric for (mapno = 0; mapno < nmaps && !UseHesiod; mapno++) 573*68276Seric { 574*68276Seric if (strcmp(maptype[mapno], "hesiod") == 0) 575*68276Seric UseHesiod = TRUE; 576*68276Seric } 577*68276Seric } 57868204Seric #endif 57967905Seric } 5804096Seric } 5814096Seric /* 5828547Seric ** TOOMANY -- signal too many of some option 5838547Seric ** 5848547Seric ** Parameters: 5858547Seric ** id -- the id of the error line 5868547Seric ** maxcnt -- the maximum possible values 5878547Seric ** 5888547Seric ** Returns: 5898547Seric ** none. 5908547Seric ** 5918547Seric ** Side Effects: 5928547Seric ** gives a syserr. 5938547Seric */ 5948547Seric 5958547Seric toomany(id, maxcnt) 5968547Seric char id; 5978547Seric int maxcnt; 5988547Seric { 5999381Seric syserr("too many %c lines, %d max", id, maxcnt); 6008547Seric } 6018547Seric /* 6024432Seric ** FILECLASS -- read members of a class from a file 6034432Seric ** 6044432Seric ** Parameters: 6054432Seric ** class -- class to define. 6064432Seric ** filename -- name of file to read. 6074432Seric ** fmt -- scanf string to use for match. 60864133Seric ** safe -- if set, this is a safe read. 60964133Seric ** optional -- if set, it is not an error for the file to 61064133Seric ** not exist. 6114432Seric ** 6124432Seric ** Returns: 6134432Seric ** none 6144432Seric ** 6154432Seric ** Side Effects: 6164432Seric ** 6174432Seric ** puts all lines in filename that match a scanf into 6184432Seric ** the named class. 6194432Seric */ 6204432Seric 62164133Seric fileclass(class, filename, fmt, safe, optional) 6224432Seric int class; 6234432Seric char *filename; 6244432Seric char *fmt; 62554973Seric bool safe; 62664133Seric bool optional; 6274432Seric { 62825808Seric FILE *f; 62954973Seric struct stat stbuf; 6304432Seric char buf[MAXLINE]; 6314432Seric 63266101Seric if (tTd(37, 2)) 63366101Seric printf("fileclass(%s, fmt=%s)\n", filename, fmt); 63466101Seric 63566031Seric if (filename[0] == '|') 63666031Seric { 63766031Seric syserr("fileclass: pipes (F%c%s) not supported due to security problems", 63866031Seric class, filename); 63966031Seric return; 64066031Seric } 64154973Seric if (stat(filename, &stbuf) < 0) 64254973Seric { 64366101Seric if (tTd(37, 2)) 64466101Seric printf(" cannot stat (%s)\n", errstring(errno)); 64564133Seric if (!optional) 64664133Seric syserr("fileclass: cannot stat %s", filename); 64754973Seric return; 64854973Seric } 64954973Seric if (!S_ISREG(stbuf.st_mode)) 65054973Seric { 65154973Seric syserr("fileclass: %s not a regular file", filename); 65254973Seric return; 65354973Seric } 65454973Seric if (!safe && access(filename, R_OK) < 0) 65554973Seric { 65654973Seric syserr("fileclass: access denied on %s", filename); 65754973Seric return; 65854973Seric } 65954973Seric f = fopen(filename, "r"); 6604432Seric if (f == NULL) 6614432Seric { 66254973Seric syserr("fileclass: cannot open %s", filename); 6634432Seric return; 6644432Seric } 6654432Seric 6664432Seric while (fgets(buf, sizeof buf, f) != NULL) 6674432Seric { 6684432Seric register STAB *s; 66925808Seric register char *p; 67025808Seric # ifdef SCANF 6714432Seric char wordbuf[MAXNAME+1]; 6724432Seric 6734432Seric if (sscanf(buf, fmt, wordbuf) != 1) 6744432Seric continue; 67525808Seric p = wordbuf; 67656795Seric # else /* SCANF */ 67725808Seric p = buf; 67856795Seric # endif /* SCANF */ 67925808Seric 68025808Seric /* 68125808Seric ** Break up the match into words. 68225808Seric */ 68325808Seric 68425808Seric while (*p != '\0') 68525808Seric { 68625808Seric register char *q; 68725808Seric 68825808Seric /* strip leading spaces */ 68958050Seric while (isascii(*p) && isspace(*p)) 69025808Seric p++; 69125808Seric if (*p == '\0') 69225808Seric break; 69325808Seric 69425808Seric /* find the end of the word */ 69525808Seric q = p; 69658050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 69725808Seric p++; 69825808Seric if (*p != '\0') 69925808Seric *p++ = '\0'; 70025808Seric 70125808Seric /* enter the word in the symbol table */ 70266101Seric setclass(class, q); 70325808Seric } 7044432Seric } 7054432Seric 70654973Seric (void) fclose(f); 7074432Seric } 7084432Seric /* 7094096Seric ** MAKEMAILER -- define a new mailer. 7104096Seric ** 7114096Seric ** Parameters: 71210327Seric ** line -- description of mailer. This is in labeled 71310327Seric ** fields. The fields are: 714*68276Seric ** A -- the argv for this mailer 715*68276Seric ** C -- the character set for MIME conversions 716*68276Seric ** D -- the directory to run in 717*68276Seric ** E -- the eol string 718*68276Seric ** F -- the flags associated with the mailer 719*68276Seric ** L -- the maximum line length 720*68276Seric ** M -- the maximum message size 72168270Seric ** P -- the path to the mailer 722*68276Seric ** R -- the recipient rewriting set 72368270Seric ** S -- the sender rewriting set 724*68276Seric ** T -- the mailer type (for DSNs) 725*68276Seric ** U -- the uid to run as 72610327Seric ** The first word is the canonical name of the mailer. 7274096Seric ** 7284096Seric ** Returns: 7294096Seric ** none. 7304096Seric ** 7314096Seric ** Side Effects: 7324096Seric ** enters the mailer into the mailer table. 7334096Seric */ 7343308Seric 73521066Seric makemailer(line) 7364096Seric char *line; 7374096Seric { 7384096Seric register char *p; 7398067Seric register struct mailer *m; 7408067Seric register STAB *s; 7418067Seric int i; 74210327Seric char fcode; 74358020Seric auto char *endp; 7444096Seric extern int NextMailer; 74510327Seric extern char **makeargv(); 74610327Seric extern char *munchstring(); 74710701Seric extern long atol(); 7484096Seric 74910327Seric /* allocate a mailer and set up defaults */ 75010327Seric m = (struct mailer *) xalloc(sizeof *m); 75110327Seric bzero((char *) m, sizeof *m); 75210327Seric m->m_eol = "\n"; 753*68276Seric m->m_uid = m->m_gid = 0; 75410327Seric 75510327Seric /* collect the mailer name */ 75658050Seric for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++) 75710327Seric continue; 75810327Seric if (*p != '\0') 75910327Seric *p++ = '\0'; 76010327Seric m->m_name = newstr(line); 76110327Seric 76210327Seric /* now scan through and assign info from the fields */ 76310327Seric while (*p != '\0') 76410327Seric { 76558333Seric auto char *delimptr; 76658333Seric 76758050Seric while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p)))) 76810327Seric p++; 76910327Seric 77010327Seric /* p now points to field code */ 77110327Seric fcode = *p; 77210327Seric while (*p != '\0' && *p != '=' && *p != ',') 77310327Seric p++; 77410327Seric if (*p++ != '=') 77510327Seric { 77652637Seric syserr("mailer %s: `=' expected", m->m_name); 77710327Seric return; 77810327Seric } 77958050Seric while (isascii(*p) && isspace(*p)) 78010327Seric p++; 78110327Seric 78210327Seric /* p now points to the field body */ 78358333Seric p = munchstring(p, &delimptr); 78410327Seric 78510327Seric /* install the field into the mailer struct */ 78610327Seric switch (fcode) 78710327Seric { 78810327Seric case 'P': /* pathname */ 78910327Seric m->m_mailer = newstr(p); 79010327Seric break; 79110327Seric 79210327Seric case 'F': /* flags */ 79310687Seric for (; *p != '\0'; p++) 79458050Seric if (!(isascii(*p) && isspace(*p))) 79552637Seric setbitn(*p, m->m_flags); 79610327Seric break; 79710327Seric 79810327Seric case 'S': /* sender rewriting ruleset */ 79910327Seric case 'R': /* recipient rewriting ruleset */ 80058020Seric i = strtol(p, &endp, 10); 80110327Seric if (i < 0 || i >= MAXRWSETS) 80210327Seric { 80310327Seric syserr("invalid rewrite set, %d max", MAXRWSETS); 80410327Seric return; 80510327Seric } 80610327Seric if (fcode == 'S') 80758020Seric m->m_sh_rwset = m->m_se_rwset = i; 80810327Seric else 80958020Seric m->m_rh_rwset = m->m_re_rwset = i; 81058020Seric 81158020Seric p = endp; 81259985Seric if (*p++ == '/') 81358020Seric { 81458020Seric i = strtol(p, NULL, 10); 81558020Seric if (i < 0 || i >= MAXRWSETS) 81658020Seric { 81758020Seric syserr("invalid rewrite set, %d max", 81858020Seric MAXRWSETS); 81958020Seric return; 82058020Seric } 82158020Seric if (fcode == 'S') 82258020Seric m->m_sh_rwset = i; 82358020Seric else 82458020Seric m->m_rh_rwset = i; 82558020Seric } 82610327Seric break; 82710327Seric 82810327Seric case 'E': /* end of line string */ 82910327Seric m->m_eol = newstr(p); 83010327Seric break; 83110327Seric 83210327Seric case 'A': /* argument vector */ 83310327Seric m->m_argv = makeargv(p); 83410327Seric break; 83510701Seric 83610701Seric case 'M': /* maximum message size */ 83710701Seric m->m_maxsize = atol(p); 83810701Seric break; 83952106Seric 84052106Seric case 'L': /* maximum line length */ 84152106Seric m->m_linelimit = atoi(p); 84252106Seric break; 84358935Seric 84458935Seric case 'D': /* working directory */ 84558935Seric m->m_execdir = newstr(p); 84658935Seric break; 847*68276Seric 848*68276Seric case 'C': /* default charset */ 849*68276Seric m->m_defcharset = newstr(p); 850*68276Seric break; 851*68276Seric 852*68276Seric case 'T': /* MTA Type */ 853*68276Seric m->m_mtatype = newstr(p); 854*68276Seric p = strchr(m->m_mtatype, '/'); 855*68276Seric if (p != NULL) 856*68276Seric { 857*68276Seric *p++ = '\0'; 858*68276Seric if (*p == '\0') 859*68276Seric p = NULL; 860*68276Seric } 861*68276Seric if (p == NULL) 862*68276Seric m->m_addrtype = m->m_mtatype; 863*68276Seric else 864*68276Seric { 865*68276Seric m->m_addrtype = p; 866*68276Seric p = strchr(p, '/'); 867*68276Seric } 868*68276Seric if (p != NULL) 869*68276Seric { 870*68276Seric *p++ = '\0'; 871*68276Seric if (*p == '\0') 872*68276Seric p = NULL; 873*68276Seric } 874*68276Seric if (p == NULL) 875*68276Seric m->m_diagtype = m->m_mtatype; 876*68276Seric else 877*68276Seric m->m_diagtype = p; 878*68276Seric break; 879*68276Seric 880*68276Seric case 'U': /* user id */ 881*68276Seric if (isascii(*p) && !isdigit(*p)) 882*68276Seric { 883*68276Seric char *q = p; 884*68276Seric struct passwd *pw; 885*68276Seric 886*68276Seric while (isascii(*p) && isalnum(*p)) 887*68276Seric p++; 888*68276Seric while (isascii(*p) && isspace(*p)) 889*68276Seric *p++ = '\0'; 890*68276Seric if (*p != '\0') 891*68276Seric *p++ = '\0'; 892*68276Seric pw = getpwnam(q); 893*68276Seric if (pw == NULL) 894*68276Seric syserr("readcf: mailer U= flag: unknown user %s", q); 895*68276Seric else 896*68276Seric { 897*68276Seric m->m_uid = pw->pw_uid; 898*68276Seric m->m_gid = pw->pw_gid; 899*68276Seric } 900*68276Seric } 901*68276Seric else 902*68276Seric { 903*68276Seric auto char *q; 904*68276Seric 905*68276Seric m->m_uid = strtol(p, &q, 0); 906*68276Seric p = q; 907*68276Seric } 908*68276Seric while (isascii(*p) && isspace(*p)) 909*68276Seric p++; 910*68276Seric if (*p == '\0') 911*68276Seric break; 912*68276Seric if (isascii(*p) && !isdigit(*p)) 913*68276Seric { 914*68276Seric char *q = p; 915*68276Seric struct group *gr; 916*68276Seric 917*68276Seric while (isascii(*p) && isalnum(*p)) 918*68276Seric p++; 919*68276Seric *p++ = '\0'; 920*68276Seric gr = getgrnam(q); 921*68276Seric if (gr == NULL) 922*68276Seric syserr("readcf: mailer U= flag: unknown group %s", q); 923*68276Seric else 924*68276Seric m->m_gid = gr->gr_gid; 925*68276Seric } 926*68276Seric else 927*68276Seric { 928*68276Seric m->m_gid = strtol(p, NULL, 0); 929*68276Seric } 930*68276Seric break; 93110327Seric } 93210327Seric 93358333Seric p = delimptr; 93410327Seric } 93510327Seric 93658321Seric /* do some rationality checking */ 93758321Seric if (m->m_argv == NULL) 93858321Seric { 93958321Seric syserr("M%s: A= argument required", m->m_name); 94058321Seric return; 94158321Seric } 94258321Seric if (m->m_mailer == NULL) 94358321Seric { 94458321Seric syserr("M%s: P= argument required", m->m_name); 94558321Seric return; 94658321Seric } 94758321Seric 9484096Seric if (NextMailer >= MAXMAILERS) 9494096Seric { 9509381Seric syserr("too many mailers defined (%d max)", MAXMAILERS); 9514096Seric return; 9524096Seric } 95357402Seric 954*68276Seric /* do some heuristic cleanup for back compatibility */ 955*68276Seric if (bitnset(M_LIMITS, m->m_flags)) 956*68276Seric { 957*68276Seric if (m->m_linelimit == 0) 958*68276Seric m->m_linelimit = SMTPLINELIM; 959*68276Seric if (ConfigLevel < 2) 960*68276Seric setbitn(M_7BITS, m->m_flags); 961*68276Seric } 962*68276Seric 963*68276Seric if (ConfigLevel < 6 && 964*68276Seric (strcmp(m->m_mailer, "[IPC]") == 0 || 965*68276Seric strcmp(m->m_mailer, "[TCP]") == 0)) 966*68276Seric { 967*68276Seric if (m->m_mtatype == NULL) 968*68276Seric m->m_mtatype = "dns"; 969*68276Seric if (m->m_addrtype == NULL) 970*68276Seric m->m_addrtype = "rfc822"; 971*68276Seric if (m->m_diagtype == NULL) 972*68276Seric m->m_diagtype = "smtp"; 973*68276Seric } 974*68276Seric 975*68276Seric /* enter the mailer into the symbol table */ 97610327Seric s = stab(m->m_name, ST_MAILER, ST_ENTER); 97757402Seric if (s->s_mailer != NULL) 97857402Seric { 97957402Seric i = s->s_mailer->m_mno; 98057402Seric free(s->s_mailer); 98157402Seric } 98257402Seric else 98357402Seric { 98457402Seric i = NextMailer++; 98557402Seric } 98657402Seric Mailer[i] = s->s_mailer = m; 98757454Seric m->m_mno = i; 98810327Seric } 98910327Seric /* 99010327Seric ** MUNCHSTRING -- translate a string into internal form. 99110327Seric ** 99210327Seric ** Parameters: 99310327Seric ** p -- the string to munch. 99458333Seric ** delimptr -- if non-NULL, set to the pointer of the 99558333Seric ** field delimiter character. 99610327Seric ** 99710327Seric ** Returns: 99810327Seric ** the munched string. 99910327Seric */ 10004096Seric 100110327Seric char * 100258333Seric munchstring(p, delimptr) 100310327Seric register char *p; 100458333Seric char **delimptr; 100510327Seric { 100610327Seric register char *q; 100710327Seric bool backslash = FALSE; 100810327Seric bool quotemode = FALSE; 100910327Seric static char buf[MAXLINE]; 10104096Seric 101110327Seric for (q = buf; *p != '\0'; p++) 10124096Seric { 101310327Seric if (backslash) 101410327Seric { 101510327Seric /* everything is roughly literal */ 101610357Seric backslash = FALSE; 101710327Seric switch (*p) 101810327Seric { 101910327Seric case 'r': /* carriage return */ 102010327Seric *q++ = '\r'; 102110327Seric continue; 102210327Seric 102310327Seric case 'n': /* newline */ 102410327Seric *q++ = '\n'; 102510327Seric continue; 102610327Seric 102710327Seric case 'f': /* form feed */ 102810327Seric *q++ = '\f'; 102910327Seric continue; 103010327Seric 103110327Seric case 'b': /* backspace */ 103210327Seric *q++ = '\b'; 103310327Seric continue; 103410327Seric } 103510327Seric *q++ = *p; 103610327Seric } 103710327Seric else 103810327Seric { 103910327Seric if (*p == '\\') 104010327Seric backslash = TRUE; 104110327Seric else if (*p == '"') 104210327Seric quotemode = !quotemode; 104310327Seric else if (quotemode || *p != ',') 104410327Seric *q++ = *p; 104510327Seric else 104610327Seric break; 104710327Seric } 10484096Seric } 10494096Seric 105058333Seric if (delimptr != NULL) 105158333Seric *delimptr = p; 105210327Seric *q++ = '\0'; 105310327Seric return (buf); 105410327Seric } 105510327Seric /* 105610327Seric ** MAKEARGV -- break up a string into words 105710327Seric ** 105810327Seric ** Parameters: 105910327Seric ** p -- the string to break up. 106010327Seric ** 106110327Seric ** Returns: 106210327Seric ** a char **argv (dynamically allocated) 106310327Seric ** 106410327Seric ** Side Effects: 106510327Seric ** munges p. 106610327Seric */ 10674096Seric 106810327Seric char ** 106910327Seric makeargv(p) 107010327Seric register char *p; 107110327Seric { 107210327Seric char *q; 107310327Seric int i; 107410327Seric char **avp; 107510327Seric char *argv[MAXPV + 1]; 107610327Seric 107710327Seric /* take apart the words */ 107810327Seric i = 0; 107910327Seric while (*p != '\0' && i < MAXPV) 10804096Seric { 108110327Seric q = p; 108258050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 108310327Seric p++; 108458050Seric while (isascii(*p) && isspace(*p)) 108510327Seric *p++ = '\0'; 108610327Seric argv[i++] = newstr(q); 10874096Seric } 108810327Seric argv[i++] = NULL; 10894096Seric 109010327Seric /* now make a copy of the argv */ 109110327Seric avp = (char **) xalloc(sizeof *avp * i); 109216893Seric bcopy((char *) argv, (char *) avp, sizeof *avp * i); 109310327Seric 109410327Seric return (avp); 10953308Seric } 10963308Seric /* 10973308Seric ** PRINTRULES -- print rewrite rules (for debugging) 10983308Seric ** 10993308Seric ** Parameters: 11003308Seric ** none. 11013308Seric ** 11023308Seric ** Returns: 11033308Seric ** none. 11043308Seric ** 11053308Seric ** Side Effects: 11063308Seric ** prints rewrite rules. 11073308Seric */ 11083308Seric 11093308Seric printrules() 11103308Seric { 11113308Seric register struct rewrite *rwp; 11124072Seric register int ruleset; 11133308Seric 11144072Seric for (ruleset = 0; ruleset < 10; ruleset++) 11153308Seric { 11164072Seric if (RewriteRules[ruleset] == NULL) 11174072Seric continue; 11188067Seric printf("\n----Rule Set %d:", ruleset); 11193308Seric 11204072Seric for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 11213308Seric { 11228067Seric printf("\nLHS:"); 11238067Seric printav(rwp->r_lhs); 11248067Seric printf("RHS:"); 11258067Seric printav(rwp->r_rhs); 11263308Seric } 11273308Seric } 11283308Seric } 1129*68276Seric /* 1130*68276Seric ** PRINTMAILER -- print mailer structure (for debugging) 1131*68276Seric ** 1132*68276Seric ** Parameters: 1133*68276Seric ** m -- the mailer to print 1134*68276Seric ** 1135*68276Seric ** Returns: 1136*68276Seric ** none. 1137*68276Seric */ 11384319Seric 1139*68276Seric printmailer(m) 1140*68276Seric register MAILER *m; 1141*68276Seric { 1142*68276Seric int j; 1143*68276Seric 1144*68276Seric printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld U=%d:%d F=", 1145*68276Seric m->m_mno, m->m_name, 1146*68276Seric m->m_mailer, m->m_se_rwset, m->m_sh_rwset, 1147*68276Seric m->m_re_rwset, m->m_rh_rwset, m->m_maxsize, 1148*68276Seric m->m_uid, m->m_gid); 1149*68276Seric for (j = '\0'; j <= '\177'; j++) 1150*68276Seric if (bitnset(j, m->m_flags)) 1151*68276Seric (void) putchar(j); 1152*68276Seric printf(" L=%d E=", m->m_linelimit); 1153*68276Seric xputs(m->m_eol); 1154*68276Seric if (m->m_defcharset != NULL) 1155*68276Seric printf(" C=%s", m->m_defcharset); 1156*68276Seric printf(" T=%s/%s/%s", 1157*68276Seric m->m_mtatype == NULL ? "<undefined>" : m->m_mtatype, 1158*68276Seric m->m_addrtype == NULL ? "<undefined>" : m->m_addrtype, 1159*68276Seric m->m_diagtype == NULL ? "<undefined>" : m->m_diagtype); 1160*68276Seric if (m->m_argv != NULL) 1161*68276Seric { 1162*68276Seric char **a = m->m_argv; 1163*68276Seric 1164*68276Seric printf(" A="); 1165*68276Seric while (*a != NULL) 1166*68276Seric { 1167*68276Seric if (a != m->m_argv) 1168*68276Seric printf(" "); 1169*68276Seric xputs(*a++); 1170*68276Seric } 1171*68276Seric } 1172*68276Seric printf("\n"); 1173*68276Seric } 11744096Seric /* 11758256Seric ** SETOPTION -- set global processing option 11768256Seric ** 11778256Seric ** Parameters: 11788256Seric ** opt -- option name. 11798256Seric ** val -- option value (as a text string). 118021755Seric ** safe -- set if this came from a configuration file. 118121755Seric ** Some options (if set from the command line) will 118221755Seric ** reset the user id to avoid security problems. 11838269Seric ** sticky -- if set, don't let other setoptions override 11848269Seric ** this value. 118558734Seric ** e -- the main envelope. 11868256Seric ** 11878256Seric ** Returns: 11888256Seric ** none. 11898256Seric ** 11908256Seric ** Side Effects: 11918256Seric ** Sets options as implied by the arguments. 11928256Seric */ 11938256Seric 119410687Seric static BITMAP StickyOpt; /* set if option is stuck */ 11958269Seric 119657207Seric 119766334Seric #if NAMED_BIND 119857207Seric 119957207Seric struct resolverflags 120057207Seric { 120157207Seric char *rf_name; /* name of the flag */ 120257207Seric long rf_bits; /* bits to set/clear */ 120357207Seric } ResolverFlags[] = 120457207Seric { 120557207Seric "debug", RES_DEBUG, 120657207Seric "aaonly", RES_AAONLY, 120757207Seric "usevc", RES_USEVC, 120857207Seric "primary", RES_PRIMARY, 120957207Seric "igntc", RES_IGNTC, 121057207Seric "recurse", RES_RECURSE, 121157207Seric "defnames", RES_DEFNAMES, 121257207Seric "stayopen", RES_STAYOPEN, 121357207Seric "dnsrch", RES_DNSRCH, 121465583Seric "true", 0, /* to avoid error on old syntax */ 121557207Seric NULL, 0 121657207Seric }; 121757207Seric 121857207Seric #endif 121957207Seric 1220*68276Seric struct optioninfo 1221*68276Seric { 1222*68276Seric char *o_name; /* long name of option */ 1223*68276Seric u_char o_code; /* short name of option */ 1224*68276Seric bool o_safe; /* safe for random people to use */ 1225*68276Seric } OptionTab[] = 1226*68276Seric { 1227*68276Seric "SevenBitInput", '7', TRUE, 1228*68276Seric "EightBitMode", '8', TRUE, 1229*68276Seric "AliasFile", 'A', FALSE, 1230*68276Seric "AliasWait", 'a', FALSE, 1231*68276Seric "BlankSub", 'B', FALSE, 1232*68276Seric "MinFreeBlocks", 'b', TRUE, 1233*68276Seric "CheckpointInterval", 'C', TRUE, 1234*68276Seric "HoldExpensive", 'c', FALSE, 1235*68276Seric "AutoRebuildAliases", 'D', FALSE, 1236*68276Seric "DeliveryMode", 'd', TRUE, 1237*68276Seric "ErrorHeader", 'E', FALSE, 1238*68276Seric "ErrorMode", 'e', TRUE, 1239*68276Seric "TempFileMode", 'F', FALSE, 1240*68276Seric "SaveFromLine", 'f', FALSE, 1241*68276Seric "MatchGECOS", 'G', FALSE, 1242*68276Seric "HelpFile", 'H', FALSE, 1243*68276Seric "MaxHopCount", 'h', FALSE, 1244*68276Seric "NameServerOptions", 'I', FALSE, 1245*68276Seric "IgnoreDots", 'i', TRUE, 1246*68276Seric "ForwardPath", 'J', FALSE, 1247*68276Seric "SendMimeErrors", 'j', TRUE, 1248*68276Seric "ConnectionCacheSize", 'k', FALSE, 1249*68276Seric "ConnectionCacheTimeout", 'K', FALSE, 1250*68276Seric "UseErrorsTo", 'l', FALSE, 1251*68276Seric "LogLevel", 'L', FALSE, 1252*68276Seric "MeToo", 'm', TRUE, 1253*68276Seric "CheckAliases", 'n', FALSE, 1254*68276Seric "OldStyleHeaders", 'o', TRUE, 1255*68276Seric "DaemonPortOptions", 'O', FALSE, 1256*68276Seric "PrivacyOptions", 'p', TRUE, 1257*68276Seric "PostmasterCopy", 'P', FALSE, 1258*68276Seric "QueueFactor", 'q', FALSE, 1259*68276Seric "QueueDirectory", 'Q', FALSE, 1260*68276Seric "DontPruneRoutes", 'R', FALSE, 1261*68276Seric "Timeout", 'r', TRUE, 1262*68276Seric "StatusFile", 'S', FALSE, 1263*68276Seric "SuperSafe", 's', TRUE, 1264*68276Seric "QueueTimeout", 'T', FALSE, 1265*68276Seric "TimeZoneSpec", 't', FALSE, 1266*68276Seric "UserDatabaseSpec", 'U', FALSE, 1267*68276Seric "DefaultUser", 'u', FALSE, 1268*68276Seric "FallbackMXhost", 'V', FALSE, 1269*68276Seric "Verbose", 'v', TRUE, 1270*68276Seric "TryNullMXList", 'w', TRUE, 1271*68276Seric "QueueLA", 'x', FALSE, 1272*68276Seric "RefuseLA", 'X', FALSE, 1273*68276Seric "RecipientFactor", 'y', FALSE, 1274*68276Seric "ForkQueueRuns", 'Y', FALSE, 1275*68276Seric "ClassFactor", 'z', FALSE, 1276*68276Seric "TimeFactor", 'Z', FALSE, 1277*68276Seric #define O_BSP 0x80 1278*68276Seric "BrokenSmtpPeers", O_BSP, TRUE, 1279*68276Seric #define O_QUEUESORTORD 0x81 1280*68276Seric "QueueSortOrder", O_QUEUESORTORD, TRUE, 1281*68276Seric #define O_MQA 0x83 1282*68276Seric "MinQueueAge", O_MQA, TRUE, 1283*68276Seric #define O_MHSA 0x84 1284*68276Seric /* 1285*68276Seric "MaxHostStatAge", O_MHSA, TRUE, 1286*68276Seric */ 1287*68276Seric #define O_DEFCHARSET 0x85 1288*68276Seric "DefaultCharSet", O_DEFCHARSET, TRUE, 1289*68276Seric #define O_SSFILE 0x86 1290*68276Seric "ServiceSwitchFile", O_SSFILE, FALSE, 1291*68276Seric #define O_DIALDELAY 0x87 1292*68276Seric "DialDelay", O_DIALDELAY, TRUE, 1293*68276Seric 1294*68276Seric NULL, '\0', FALSE, 1295*68276Seric }; 1296*68276Seric 1297*68276Seric 1298*68276Seric 129958734Seric setoption(opt, val, safe, sticky, e) 1300*68276Seric u_char opt; 13018256Seric char *val; 130221755Seric bool safe; 13038269Seric bool sticky; 130458734Seric register ENVELOPE *e; 13058256Seric { 130657207Seric register char *p; 1307*68276Seric register struct optioninfo *o; 1308*68276Seric char *subopt; 13098265Seric extern bool atobool(); 131012633Seric extern time_t convtime(); 131114879Seric extern int QueueLA; 131214879Seric extern int RefuseLA; 131364718Seric extern bool Warn_Q_option; 13148256Seric 1315*68276Seric errno = 0; 1316*68276Seric if (opt == ' ') 1317*68276Seric { 1318*68276Seric /* full word options */ 1319*68276Seric struct optioninfo *sel; 1320*68276Seric 1321*68276Seric p = strchr(val, '='); 1322*68276Seric if (p == NULL) 1323*68276Seric p = &val[strlen(val)]; 1324*68276Seric while (*--p == ' ') 1325*68276Seric continue; 1326*68276Seric while (*++p == ' ') 1327*68276Seric *p = '\0'; 1328*68276Seric if (p == val) 1329*68276Seric { 1330*68276Seric syserr("readcf: null option name"); 1331*68276Seric return; 1332*68276Seric } 1333*68276Seric if (*p == '=') 1334*68276Seric *p++ = '\0'; 1335*68276Seric while (*p == ' ') 1336*68276Seric p++; 1337*68276Seric subopt = strchr(val, '.'); 1338*68276Seric if (subopt != NULL) 1339*68276Seric *subopt++ = '\0'; 1340*68276Seric sel = NULL; 1341*68276Seric for (o = OptionTab; o->o_name != NULL; o++) 1342*68276Seric { 1343*68276Seric if (strncasecmp(o->o_name, val, strlen(val)) != 0) 1344*68276Seric continue; 1345*68276Seric if (strlen(o->o_name) == strlen(val)) 1346*68276Seric { 1347*68276Seric /* completely specified -- this must be it */ 1348*68276Seric sel = NULL; 1349*68276Seric break; 1350*68276Seric } 1351*68276Seric if (sel != NULL) 1352*68276Seric break; 1353*68276Seric sel = o; 1354*68276Seric } 1355*68276Seric if (sel != NULL && o->o_name == NULL) 1356*68276Seric o = sel; 1357*68276Seric else if (o->o_name == NULL) 1358*68276Seric { 1359*68276Seric syserr("readcf: unknown option name %s", val); 1360*68276Seric return; 1361*68276Seric } 1362*68276Seric else if (sel != NULL) 1363*68276Seric { 1364*68276Seric syserr("readcf: ambiguous option name %s (matches %s and %s)", 1365*68276Seric val, sel->o_name, o->o_name); 1366*68276Seric return; 1367*68276Seric } 1368*68276Seric if (strlen(val) != strlen(o->o_name)) 1369*68276Seric { 1370*68276Seric bool oldVerbose = Verbose; 1371*68276Seric 1372*68276Seric Verbose = TRUE; 1373*68276Seric message("Option %s used as abbreviation for %s", 1374*68276Seric val, o->o_name); 1375*68276Seric Verbose = oldVerbose; 1376*68276Seric } 1377*68276Seric opt = o->o_code; 1378*68276Seric val = p; 1379*68276Seric } 1380*68276Seric else 1381*68276Seric { 1382*68276Seric for (o = OptionTab; o->o_name != NULL; o++) 1383*68276Seric { 1384*68276Seric if (o->o_code == opt) 1385*68276Seric break; 1386*68276Seric } 1387*68276Seric subopt = NULL; 1388*68276Seric } 1389*68276Seric 13908256Seric if (tTd(37, 1)) 1391*68276Seric { 1392*68276Seric printf(isascii(opt) && isprint(opt) ? 1393*68276Seric "setoption %s (%c).%s=%s" : 1394*68276Seric "setoption %s (0x%x).%s=%s", 1395*68276Seric o->o_name == NULL ? "<unknown>" : o->o_name, 1396*68276Seric opt, 1397*68276Seric subopt == NULL ? "" : subopt, 1398*68276Seric val); 1399*68276Seric } 14008256Seric 14018256Seric /* 14028269Seric ** See if this option is preset for us. 14038256Seric */ 14048256Seric 140559731Seric if (!sticky && bitnset(opt, StickyOpt)) 14068269Seric { 14079341Seric if (tTd(37, 1)) 14089341Seric printf(" (ignored)\n"); 14098269Seric return; 14108269Seric } 14118269Seric 141221755Seric /* 141321755Seric ** Check to see if this option can be specified by this user. 141421755Seric */ 141521755Seric 141663787Seric if (!safe && RealUid == 0) 141721755Seric safe = TRUE; 1418*68276Seric if (!safe && !o->o_safe) 141921755Seric { 142039111Srick if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 142121755Seric { 142236582Sbostic if (tTd(37, 1)) 142336582Sbostic printf(" (unsafe)"); 142463787Seric if (RealUid != geteuid()) 142536582Sbostic { 142651210Seric if (tTd(37, 1)) 142751210Seric printf("(Resetting uid)"); 142863787Seric (void) setgid(RealGid); 142963787Seric (void) setuid(RealUid); 143036582Sbostic } 143121755Seric } 143221755Seric } 143351210Seric if (tTd(37, 1)) 143417985Seric printf("\n"); 14358269Seric 1436*68276Seric switch (opt & 0xff) 14378256Seric { 143859709Seric case '7': /* force seven-bit input */ 1439*68276Seric SevenBitInput = atobool(val); 144052106Seric break; 144152106Seric 1442*68276Seric case '8': /* handling of 8-bit input */ 1443*68276Seric switch (*val) 1444*68276Seric { 1445*68276Seric case 'r': /* reject 8-bit, don't convert MIME */ 1446*68276Seric MimeMode = 0; 1447*68276Seric break; 1448*68276Seric 1449*68276Seric case 'm': /* convert 8-bit, convert MIME */ 1450*68276Seric MimeMode = MM_CVTMIME|MM_MIME8BIT; 1451*68276Seric break; 1452*68276Seric 1453*68276Seric case 'j': /* "just send 8" */ 1454*68276Seric MimeMode = MM_PASS8BIT; 1455*68276Seric break; 1456*68276Seric 1457*68276Seric case 'p': /* pass 8 bit, convert MIME */ 1458*68276Seric MimeMode = MM_PASS8BIT|MM_CVTMIME; 1459*68276Seric break; 1460*68276Seric 1461*68276Seric case 's': /* strict adherence */ 1462*68276Seric MimeMode = MM_CVTMIME; 1463*68276Seric break; 1464*68276Seric 1465*68276Seric case 'a': /* encode 8 bit if available */ 1466*68276Seric MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 1467*68276Seric break; 1468*68276Seric 1469*68276Seric case 'c': /* convert 8 bit to MIME, never 7 bit */ 1470*68276Seric MimeMode = MM_MIME8BIT; 1471*68276Seric break; 1472*68276Seric 1473*68276Seric default: 1474*68276Seric syserr("Unknown 8-bit mode %c", *val); 1475*68276Seric exit(EX_USAGE); 1476*68276Seric } 1477*68276Seric break; 1478*68276Seric 14798256Seric case 'A': /* set default alias file */ 14809381Seric if (val[0] == '\0') 148159672Seric setalias("aliases"); 14829381Seric else 148359672Seric setalias(val); 14848256Seric break; 14858256Seric 148617474Seric case 'a': /* look N minutes for "@:@" in alias file */ 148717474Seric if (val[0] == '\0') 148864796Seric SafeAlias = 5 * 60; /* five minutes */ 148917474Seric else 149064796Seric SafeAlias = convtime(val, 'm'); 149117474Seric break; 149217474Seric 149316843Seric case 'B': /* substitution for blank character */ 149416843Seric SpaceSub = val[0]; 149516843Seric if (SpaceSub == '\0') 149616843Seric SpaceSub = ' '; 149716843Seric break; 149816843Seric 149959283Seric case 'b': /* min blocks free on queue fs/max msg size */ 150059283Seric p = strchr(val, '/'); 150159283Seric if (p != NULL) 150259283Seric { 150359283Seric *p++ = '\0'; 150459283Seric MaxMessageSize = atol(p); 150559283Seric } 150658082Seric MinBlocksFree = atol(val); 150758082Seric break; 150858082Seric 15099284Seric case 'c': /* don't connect to "expensive" mailers */ 15109381Seric NoConnect = atobool(val); 15119284Seric break; 15129284Seric 151351305Seric case 'C': /* checkpoint every N addresses */ 151451305Seric CheckpointInterval = atoi(val); 151524944Seric break; 151624944Seric 15179284Seric case 'd': /* delivery mode */ 15189284Seric switch (*val) 15198269Seric { 15209284Seric case '\0': 152158734Seric e->e_sendmode = SM_DELIVER; 15228269Seric break; 15238269Seric 152410755Seric case SM_QUEUE: /* queue only */ 152510755Seric #ifndef QUEUE 152610755Seric syserr("need QUEUE to set -odqueue"); 152756795Seric #endif /* QUEUE */ 152810755Seric /* fall through..... */ 152910755Seric 15309284Seric case SM_DELIVER: /* do everything */ 15319284Seric case SM_FORK: /* fork after verification */ 153258734Seric e->e_sendmode = *val; 15338269Seric break; 15348269Seric 15358269Seric default: 15369284Seric syserr("Unknown delivery mode %c", *val); 15378269Seric exit(EX_USAGE); 15388269Seric } 15398269Seric break; 15408269Seric 15419146Seric case 'D': /* rebuild alias database as needed */ 15429381Seric AutoRebuild = atobool(val); 15439146Seric break; 15449146Seric 154555372Seric case 'E': /* error message header/header file */ 154655379Seric if (*val != '\0') 154755379Seric ErrMsgFile = newstr(val); 154855372Seric break; 154955372Seric 15508269Seric case 'e': /* set error processing mode */ 15518269Seric switch (*val) 15528269Seric { 15539381Seric case EM_QUIET: /* be silent about it */ 15549381Seric case EM_MAIL: /* mail back */ 15559381Seric case EM_BERKNET: /* do berknet error processing */ 15569381Seric case EM_WRITE: /* write back (or mail) */ 15579381Seric case EM_PRINT: /* print errors normally (default) */ 155858734Seric e->e_errormode = *val; 15598269Seric break; 15608269Seric } 15618269Seric break; 15628269Seric 15639049Seric case 'F': /* file mode */ 156417975Seric FileMode = atooct(val) & 0777; 15659049Seric break; 15669049Seric 15678269Seric case 'f': /* save Unix-style From lines on front */ 15689381Seric SaveFrom = atobool(val); 15698269Seric break; 15708269Seric 157153735Seric case 'G': /* match recipients against GECOS field */ 157253735Seric MatchGecos = atobool(val); 157353735Seric break; 157453735Seric 15758256Seric case 'g': /* default gid */ 1576*68276Seric g_opt: 157764133Seric if (isascii(*val) && isdigit(*val)) 157864133Seric DefGid = atoi(val); 157964133Seric else 158064133Seric { 158164133Seric register struct group *gr; 158264133Seric 158364133Seric DefGid = -1; 158464133Seric gr = getgrnam(val); 158564133Seric if (gr == NULL) 1586*68276Seric syserr("readcf: option %c: unknown group %s", 1587*68276Seric opt, val); 158864133Seric else 158964133Seric DefGid = gr->gr_gid; 159064133Seric } 15918256Seric break; 15928256Seric 15938256Seric case 'H': /* help file */ 15949381Seric if (val[0] == '\0') 15958269Seric HelpFile = "sendmail.hf"; 15969381Seric else 15979381Seric HelpFile = newstr(val); 15988256Seric break; 15998256Seric 160051305Seric case 'h': /* maximum hop count */ 160151305Seric MaxHopCount = atoi(val); 160251305Seric break; 160351305Seric 160435651Seric case 'I': /* use internet domain name server */ 160566334Seric #if NAMED_BIND 160657207Seric for (p = val; *p != 0; ) 160757207Seric { 160857207Seric bool clearmode; 160957207Seric char *q; 161057207Seric struct resolverflags *rfp; 161157207Seric 161257207Seric while (*p == ' ') 161357207Seric p++; 161457207Seric if (*p == '\0') 161557207Seric break; 161657207Seric clearmode = FALSE; 161757207Seric if (*p == '-') 161857207Seric clearmode = TRUE; 161957207Seric else if (*p != '+') 162057207Seric p--; 162157207Seric p++; 162257207Seric q = p; 162358050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 162457207Seric p++; 162557207Seric if (*p != '\0') 162657207Seric *p++ = '\0'; 162757207Seric for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 162857207Seric { 162957207Seric if (strcasecmp(q, rfp->rf_name) == 0) 163057207Seric break; 163157207Seric } 163264923Seric if (rfp->rf_name == NULL) 163364923Seric syserr("readcf: I option value %s unrecognized", q); 163464923Seric else if (clearmode) 163557207Seric _res.options &= ~rfp->rf_bits; 163657207Seric else 163757207Seric _res.options |= rfp->rf_bits; 163857207Seric } 163957207Seric if (tTd(8, 2)) 164057207Seric printf("_res.options = %x\n", _res.options); 164157207Seric #else 164257207Seric usrerr("name server (I option) specified but BIND not compiled in"); 164357207Seric #endif 164435651Seric break; 164535651Seric 16468269Seric case 'i': /* ignore dot lines in message */ 16479381Seric IgnrDot = atobool(val); 16488269Seric break; 16498269Seric 165059730Seric case 'j': /* send errors in MIME (RFC 1341) format */ 165159730Seric SendMIMEErrors = atobool(val); 165259730Seric break; 165359730Seric 165457136Seric case 'J': /* .forward search path */ 165557136Seric ForwardPath = newstr(val); 165657136Seric break; 165757136Seric 165854967Seric case 'k': /* connection cache size */ 165954967Seric MaxMciCache = atoi(val); 166056215Seric if (MaxMciCache < 0) 166156215Seric MaxMciCache = 0; 166254967Seric break; 166354967Seric 166454967Seric case 'K': /* connection cache timeout */ 166558796Seric MciCacheTimeout = convtime(val, 'm'); 166654967Seric break; 166754967Seric 166861104Seric case 'l': /* use Errors-To: header */ 166961104Seric UseErrorsTo = atobool(val); 167061104Seric break; 167161104Seric 16728256Seric case 'L': /* log level */ 167364140Seric if (safe || LogLevel < atoi(val)) 167464140Seric LogLevel = atoi(val); 16758256Seric break; 16768256Seric 16778269Seric case 'M': /* define macro */ 167868267Seric p = newstr(&val[1]); 167968267Seric if (!safe) 168068267Seric cleanstrcpy(p, p, MAXNAME); 168168267Seric define(val[0], p, CurEnv); 168216878Seric sticky = FALSE; 16838269Seric break; 16848269Seric 16858269Seric case 'm': /* send to me too */ 16869381Seric MeToo = atobool(val); 16878269Seric break; 16888269Seric 168925820Seric case 'n': /* validate RHS in newaliases */ 169025820Seric CheckAliases = atobool(val); 169125820Seric break; 169225820Seric 169361104Seric /* 'N' available -- was "net name" */ 169461104Seric 169558851Seric case 'O': /* daemon options */ 169658851Seric setdaemonoptions(val); 169758851Seric break; 169858851Seric 16998269Seric case 'o': /* assume old style headers */ 17009381Seric if (atobool(val)) 17019341Seric CurEnv->e_flags |= EF_OLDSTYLE; 17029341Seric else 17039341Seric CurEnv->e_flags &= ~EF_OLDSTYLE; 17048269Seric break; 17058269Seric 170658082Seric case 'p': /* select privacy level */ 170758082Seric p = val; 170858082Seric for (;;) 170958082Seric { 171058082Seric register struct prival *pv; 171158082Seric extern struct prival PrivacyValues[]; 171258082Seric 171358082Seric while (isascii(*p) && (isspace(*p) || ispunct(*p))) 171458082Seric p++; 171558082Seric if (*p == '\0') 171658082Seric break; 171758082Seric val = p; 171858082Seric while (isascii(*p) && isalnum(*p)) 171958082Seric p++; 172058082Seric if (*p != '\0') 172158082Seric *p++ = '\0'; 172258082Seric 172358082Seric for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 172458082Seric { 172558082Seric if (strcasecmp(val, pv->pv_name) == 0) 172658082Seric break; 172758082Seric } 172858886Seric if (pv->pv_name == NULL) 172958886Seric syserr("readcf: Op line: %s unrecognized", val); 173058082Seric PrivacyFlags |= pv->pv_flag; 173158082Seric } 173258082Seric break; 173358082Seric 173424944Seric case 'P': /* postmaster copy address for returned mail */ 173524944Seric PostMasterCopy = newstr(val); 173624944Seric break; 173724944Seric 173824944Seric case 'q': /* slope of queue only function */ 173924944Seric QueueFactor = atoi(val); 174024944Seric break; 174124944Seric 17428256Seric case 'Q': /* queue directory */ 17439381Seric if (val[0] == '\0') 17448269Seric QueueDir = "mqueue"; 17459381Seric else 17469381Seric QueueDir = newstr(val); 174758789Seric if (RealUid != 0 && !safe) 174864718Seric Warn_Q_option = TRUE; 17498256Seric break; 17508256Seric 175158148Seric case 'R': /* don't prune routes */ 175258148Seric DontPruneRoutes = atobool(val); 175358148Seric break; 175458148Seric 17558256Seric case 'r': /* read timeout */ 1756*68276Seric if (subopt == NULL) 1757*68276Seric inittimeouts(val); 1758*68276Seric else 1759*68276Seric settimeout(subopt, val); 17608256Seric break; 17618256Seric 17628256Seric case 'S': /* status file */ 17639381Seric if (val[0] == '\0') 17648269Seric StatFile = "sendmail.st"; 17659381Seric else 17669381Seric StatFile = newstr(val); 17678256Seric break; 17688256Seric 17698265Seric case 's': /* be super safe, even if expensive */ 17709381Seric SuperSafe = atobool(val); 17718256Seric break; 17728256Seric 17738256Seric case 'T': /* queue timeout */ 177458737Seric p = strchr(val, '/'); 177558737Seric if (p != NULL) 177658737Seric { 177758737Seric *p++ = '\0'; 1778*68276Seric settimeout("queuewarn", p); 177958737Seric } 1780*68276Seric settimeout("queuereturn", val); 178154967Seric break; 17828256Seric 17838265Seric case 't': /* time zone name */ 178452106Seric TimeZoneSpec = newstr(val); 17858265Seric break; 17868265Seric 178750556Seric case 'U': /* location of user database */ 178851360Seric UdbSpec = newstr(val); 178950556Seric break; 179050556Seric 17918256Seric case 'u': /* set default uid */ 1792*68276Seric for (p = val; *p != '\0'; p++) 1793*68276Seric { 1794*68276Seric if (*p == '.' || *p == '/' || *p == ':') 1795*68276Seric { 1796*68276Seric *p++ = '\0'; 1797*68276Seric break; 1798*68276Seric } 1799*68276Seric } 180064133Seric if (isascii(*val) && isdigit(*val)) 180164133Seric DefUid = atoi(val); 180264133Seric else 180364133Seric { 180464133Seric register struct passwd *pw; 180564133Seric 180664133Seric DefUid = -1; 180764133Seric pw = getpwnam(val); 180864133Seric if (pw == NULL) 180964133Seric syserr("readcf: option u: unknown user %s", val); 181064133Seric else 1811*68276Seric { 181264133Seric DefUid = pw->pw_uid; 1813*68276Seric DefGid = pw->pw_gid; 1814*68276Seric } 181564133Seric } 181640973Sbostic setdefuser(); 18178256Seric 1818*68276Seric /* handle the group if it is there */ 1819*68276Seric if (*p == '\0') 1820*68276Seric break; 1821*68276Seric val = p; 1822*68276Seric goto g_opt; 1823*68276Seric 182458851Seric case 'V': /* fallback MX host */ 182558851Seric FallBackMX = newstr(val); 182658851Seric break; 182758851Seric 18288269Seric case 'v': /* run in verbose mode */ 18299381Seric Verbose = atobool(val); 18308256Seric break; 18318256Seric 183263837Seric case 'w': /* if we are best MX, try host directly */ 183363837Seric TryNullMXList = atobool(val); 183463837Seric break; 183561104Seric 183661104Seric /* 'W' available -- was wizard password */ 183761104Seric 183814879Seric case 'x': /* load avg at which to auto-queue msgs */ 183914879Seric QueueLA = atoi(val); 184014879Seric break; 184114879Seric 184214879Seric case 'X': /* load avg at which to auto-reject connections */ 184314879Seric RefuseLA = atoi(val); 184414879Seric break; 184514879Seric 184624981Seric case 'y': /* work recipient factor */ 184724981Seric WkRecipFact = atoi(val); 184824981Seric break; 184924981Seric 185024981Seric case 'Y': /* fork jobs during queue runs */ 185124952Seric ForkQueueRuns = atobool(val); 185224952Seric break; 185324952Seric 185424981Seric case 'z': /* work message class factor */ 185524981Seric WkClassFact = atoi(val); 185624981Seric break; 185724981Seric 185824981Seric case 'Z': /* work time factor */ 185924981Seric WkTimeFact = atoi(val); 186024981Seric break; 186124981Seric 1862*68276Seric case O_BSP: /* SMTP Peers can't handle 2-line greeting */ 1863*68276Seric BrokenSmtpPeers = atobool(val); 1864*68276Seric break; 1865*68276Seric 1866*68276Seric case O_QUEUESORTORD: /* queue sorting order */ 1867*68276Seric switch (*val) 1868*68276Seric { 1869*68276Seric case 'h': /* Host first */ 1870*68276Seric case 'H': 1871*68276Seric QueueSortOrder = QS_BYHOST; 1872*68276Seric break; 1873*68276Seric 1874*68276Seric case 'p': /* Priority order */ 1875*68276Seric case 'P': 1876*68276Seric QueueSortOrder = QS_BYPRIORITY; 1877*68276Seric break; 1878*68276Seric 1879*68276Seric default: 1880*68276Seric syserr("Invalid queue sort order \"%s\"", val); 1881*68276Seric } 1882*68276Seric break; 1883*68276Seric 1884*68276Seric case O_MQA: /* minimum queue age between deliveries */ 1885*68276Seric MinQueueAge = convtime(val, 'm'); 1886*68276Seric break; 1887*68276Seric 1888*68276Seric case O_MHSA: /* maximum age of cached host status */ 1889*68276Seric MaxHostStatAge = convtime(val, 'm'); 1890*68276Seric break; 1891*68276Seric 1892*68276Seric case O_DEFCHARSET: /* default character set for mimefying */ 1893*68276Seric DefaultCharSet = newstr(denlstring(val)); 1894*68276Seric break; 1895*68276Seric 1896*68276Seric case O_SSFILE: /* service switch file */ 1897*68276Seric ServiceSwitchFile = newstr(val); 1898*68276Seric break; 1899*68276Seric 1900*68276Seric case O_DIALDELAY: /* delay for dial-on-demand operation */ 1901*68276Seric DialDelay = convtime(val, 's'); 1902*68276Seric break; 1903*68276Seric 19048256Seric default: 1905*68276Seric if (tTd(37, 1)) 1906*68276Seric { 1907*68276Seric if (isascii(opt) && isprint(opt)) 1908*68276Seric printf("Warning: option %c unknown\n", opt); 1909*68276Seric else 1910*68276Seric printf("Warning: option 0x%x unknown\n", opt); 1911*68276Seric } 19128256Seric break; 19138256Seric } 191416878Seric if (sticky) 191516878Seric setbitn(opt, StickyOpt); 19169188Seric return; 19178256Seric } 191810687Seric /* 191910687Seric ** SETCLASS -- set a word into a class 192010687Seric ** 192110687Seric ** Parameters: 192210687Seric ** class -- the class to put the word in. 192310687Seric ** word -- the word to enter 192410687Seric ** 192510687Seric ** Returns: 192610687Seric ** none. 192710687Seric ** 192810687Seric ** Side Effects: 192910687Seric ** puts the word into the symbol table. 193010687Seric */ 193110687Seric 193210687Seric setclass(class, word) 193310687Seric int class; 193410687Seric char *word; 193510687Seric { 193610687Seric register STAB *s; 193710687Seric 193857943Seric if (tTd(37, 8)) 193964326Seric printf("setclass(%c, %s)\n", class, word); 194010687Seric s = stab(word, ST_CLASS, ST_ENTER); 194110687Seric setbitn(class, s->s_class); 194210687Seric } 194353654Seric /* 194453654Seric ** MAKEMAPENTRY -- create a map entry 194553654Seric ** 194653654Seric ** Parameters: 194753654Seric ** line -- the config file line 194853654Seric ** 194953654Seric ** Returns: 195053654Seric ** TRUE if it successfully entered the map entry. 195153654Seric ** FALSE otherwise (usually syntax error). 195253654Seric ** 195353654Seric ** Side Effects: 195453654Seric ** Enters the map into the dictionary. 195553654Seric */ 195653654Seric 195753654Seric void 195853654Seric makemapentry(line) 195953654Seric char *line; 196053654Seric { 196153654Seric register char *p; 196253654Seric char *mapname; 196353654Seric char *classname; 196464078Seric register STAB *s; 196553654Seric STAB *class; 196653654Seric 196758050Seric for (p = line; isascii(*p) && isspace(*p); p++) 196853654Seric continue; 196958050Seric if (!(isascii(*p) && isalnum(*p))) 197053654Seric { 197153654Seric syserr("readcf: config K line: no map name"); 197253654Seric return; 197353654Seric } 197453654Seric 197553654Seric mapname = p; 1976*68276Seric while ((isascii(*++p) && isalnum(*p)) || *p == '.') 197753654Seric continue; 197853654Seric if (*p != '\0') 197953654Seric *p++ = '\0'; 198058050Seric while (isascii(*p) && isspace(*p)) 198153654Seric p++; 198258050Seric if (!(isascii(*p) && isalnum(*p))) 198353654Seric { 198453654Seric syserr("readcf: config K line, map %s: no map class", mapname); 198553654Seric return; 198653654Seric } 198753654Seric classname = p; 198858050Seric while (isascii(*++p) && isalnum(*p)) 198953654Seric continue; 199053654Seric if (*p != '\0') 199153654Seric *p++ = '\0'; 199258050Seric while (isascii(*p) && isspace(*p)) 199353654Seric p++; 199453654Seric 199553654Seric /* look up the class */ 199653654Seric class = stab(classname, ST_MAPCLASS, ST_FIND); 199753654Seric if (class == NULL) 199853654Seric { 199953654Seric syserr("readcf: map %s: class %s not available", mapname, classname); 200053654Seric return; 200153654Seric } 200253654Seric 200353654Seric /* enter the map */ 200464078Seric s = stab(mapname, ST_MAP, ST_ENTER); 200564078Seric s->s_map.map_class = &class->s_mapclass; 200664078Seric s->s_map.map_mname = newstr(mapname); 200753654Seric 200864078Seric if (class->s_mapclass.map_parse(&s->s_map, p)) 200964078Seric s->s_map.map_mflags |= MF_VALID; 201064078Seric 201164078Seric if (tTd(37, 5)) 201264078Seric { 201364078Seric printf("map %s, class %s, flags %x, file %s,\n", 201464078Seric s->s_map.map_mname, s->s_map.map_class->map_cname, 201564078Seric s->s_map.map_mflags, 201664078Seric s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 201764078Seric printf("\tapp %s, domain %s, rebuild %s\n", 201864078Seric s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 201964078Seric s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 202064078Seric s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 202164078Seric } 202253654Seric } 202358112Seric /* 2024*68276Seric ** INITTIMEOUTS -- parse and set timeout values 202558112Seric ** 202658112Seric ** Parameters: 202758112Seric ** val -- a pointer to the values. If NULL, do initial 202858112Seric ** settings. 202958112Seric ** 203058112Seric ** Returns: 203158112Seric ** none. 203258112Seric ** 203358112Seric ** Side Effects: 203458112Seric ** Initializes the TimeOuts structure 203558112Seric */ 203658112Seric 203764255Seric #define SECONDS 203858112Seric #define MINUTES * 60 203958112Seric #define HOUR * 3600 204058112Seric 2041*68276Seric inittimeouts(val) 204258112Seric register char *val; 204358112Seric { 204458112Seric register char *p; 204558671Seric extern time_t convtime(); 204658112Seric 204758112Seric if (val == NULL) 204858112Seric { 204958112Seric TimeOuts.to_initial = (time_t) 5 MINUTES; 205058112Seric TimeOuts.to_helo = (time_t) 5 MINUTES; 205158112Seric TimeOuts.to_mail = (time_t) 10 MINUTES; 205258112Seric TimeOuts.to_rcpt = (time_t) 1 HOUR; 205358112Seric TimeOuts.to_datainit = (time_t) 5 MINUTES; 205458112Seric TimeOuts.to_datablock = (time_t) 1 HOUR; 205558112Seric TimeOuts.to_datafinal = (time_t) 1 HOUR; 205658112Seric TimeOuts.to_rset = (time_t) 5 MINUTES; 205758112Seric TimeOuts.to_quit = (time_t) 2 MINUTES; 205858112Seric TimeOuts.to_nextcommand = (time_t) 1 HOUR; 205958112Seric TimeOuts.to_miscshort = (time_t) 2 MINUTES; 2060*68276Seric #if IDENTPROTO 206164255Seric TimeOuts.to_ident = (time_t) 30 SECONDS; 2062*68276Seric #else 2063*68276Seric TimeOuts.to_ident = (time_t) 0 SECONDS; 2064*68276Seric #endif 2065*68276Seric TimeOuts.to_fileopen = (time_t) 60 SECONDS; 206658112Seric return; 206758112Seric } 206858112Seric 206958112Seric for (;; val = p) 207058112Seric { 207158112Seric while (isascii(*val) && isspace(*val)) 207258112Seric val++; 207358112Seric if (*val == '\0') 207458112Seric break; 207558112Seric for (p = val; *p != '\0' && *p != ','; p++) 207658112Seric continue; 207758112Seric if (*p != '\0') 207858112Seric *p++ = '\0'; 207958112Seric 208058112Seric if (isascii(*val) && isdigit(*val)) 208158112Seric { 208258112Seric /* old syntax -- set everything */ 208358796Seric TimeOuts.to_mail = convtime(val, 'm'); 208458112Seric TimeOuts.to_rcpt = TimeOuts.to_mail; 208558112Seric TimeOuts.to_datainit = TimeOuts.to_mail; 208658112Seric TimeOuts.to_datablock = TimeOuts.to_mail; 208758112Seric TimeOuts.to_datafinal = TimeOuts.to_mail; 208858112Seric TimeOuts.to_nextcommand = TimeOuts.to_mail; 208958112Seric continue; 209058112Seric } 209158112Seric else 209258112Seric { 2093*68276Seric register char *q = strchr(val, ':'); 209458112Seric 2095*68276Seric if (q == NULL && (q = strchr(val, '=')) == NULL) 209658112Seric { 209758112Seric /* syntax error */ 209858112Seric continue; 209958112Seric } 210058112Seric *q++ = '\0'; 2101*68276Seric settimeout(val, q); 2102*68276Seric } 2103*68276Seric } 2104*68276Seric } 2105*68276Seric /* 2106*68276Seric ** SETTIMEOUT -- set an individual timeout 2107*68276Seric ** 2108*68276Seric ** Parameters: 2109*68276Seric ** name -- the name of the timeout. 2110*68276Seric ** val -- the value of the timeout. 2111*68276Seric ** 2112*68276Seric ** Returns: 2113*68276Seric ** none. 2114*68276Seric */ 211558112Seric 2116*68276Seric settimeout(name, val) 2117*68276Seric char *name; 2118*68276Seric char *val; 2119*68276Seric { 2120*68276Seric register char *p; 2121*68276Seric time_t to; 2122*68276Seric extern time_t convtime(); 2123*68276Seric 2124*68276Seric to = convtime(val, 'm'); 2125*68276Seric p = strchr(name, '.'); 2126*68276Seric if (p != NULL) 2127*68276Seric *p++ = '\0'; 2128*68276Seric 2129*68276Seric if (strcasecmp(name, "initial") == 0) 2130*68276Seric TimeOuts.to_initial = to; 2131*68276Seric else if (strcasecmp(name, "mail") == 0) 2132*68276Seric TimeOuts.to_mail = to; 2133*68276Seric else if (strcasecmp(name, "rcpt") == 0) 2134*68276Seric TimeOuts.to_rcpt = to; 2135*68276Seric else if (strcasecmp(name, "datainit") == 0) 2136*68276Seric TimeOuts.to_datainit = to; 2137*68276Seric else if (strcasecmp(name, "datablock") == 0) 2138*68276Seric TimeOuts.to_datablock = to; 2139*68276Seric else if (strcasecmp(name, "datafinal") == 0) 2140*68276Seric TimeOuts.to_datafinal = to; 2141*68276Seric else if (strcasecmp(name, "command") == 0) 2142*68276Seric TimeOuts.to_nextcommand = to; 2143*68276Seric else if (strcasecmp(name, "rset") == 0) 2144*68276Seric TimeOuts.to_rset = to; 2145*68276Seric else if (strcasecmp(name, "helo") == 0) 2146*68276Seric TimeOuts.to_helo = to; 2147*68276Seric else if (strcasecmp(name, "quit") == 0) 2148*68276Seric TimeOuts.to_quit = to; 2149*68276Seric else if (strcasecmp(name, "misc") == 0) 2150*68276Seric TimeOuts.to_miscshort = to; 2151*68276Seric else if (strcasecmp(name, "ident") == 0) 2152*68276Seric TimeOuts.to_ident = to; 2153*68276Seric else if (strcasecmp(name, "fileopen") == 0) 2154*68276Seric TimeOuts.to_fileopen = to; 2155*68276Seric else if (strcasecmp(name, "queuewarn") == 0) 2156*68276Seric { 2157*68276Seric to = convtime(val, 'h'); 2158*68276Seric if (p == NULL || strcmp(p, "*") == 0) 2159*68276Seric { 2160*68276Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 2161*68276Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 2162*68276Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 216358112Seric } 2164*68276Seric else if (strcasecmp(p, "normal") == 0) 2165*68276Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 2166*68276Seric else if (strcasecmp(p, "urgent") == 0) 2167*68276Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 2168*68276Seric else if (strcasecmp(p, "non-urgent") == 0) 2169*68276Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 2170*68276Seric else 2171*68276Seric syserr("settimeout: invalid queuewarn subtimeout %s", p); 217258112Seric } 2173*68276Seric else if (strcasecmp(name, "queuereturn") == 0) 2174*68276Seric { 2175*68276Seric to = convtime(val, 'd'); 2176*68276Seric if (p == NULL || strcmp(p, "*") == 0) 2177*68276Seric { 2178*68276Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 2179*68276Seric TimeOuts.to_q_return[TOC_URGENT] = to; 2180*68276Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 2181*68276Seric } 2182*68276Seric else if (strcasecmp(p, "normal") == 0) 2183*68276Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 2184*68276Seric else if (strcasecmp(p, "urgent") == 0) 2185*68276Seric TimeOuts.to_q_return[TOC_URGENT] = to; 2186*68276Seric else if (strcasecmp(p, "non-urgent") == 0) 2187*68276Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 2188*68276Seric else 2189*68276Seric syserr("settimeout: invalid queuereturn subtimeout %s", p); 2190*68276Seric } 2191*68276Seric else 2192*68276Seric syserr("settimeout: invalid timeout %s", name); 219358112Seric } 2194