122709Sdist /* 268839Seric * Copyright (c) 1983, 1995 Eric P. Allman 362530Sbostic * Copyright (c) 1988, 1993 462530Sbostic * The Regents of the University of California. All rights reserved. 533731Sbostic * 642829Sbostic * %sccs.include.redist.c% 733731Sbostic */ 822709Sdist 922709Sdist #ifndef lint 10*69852Seric static char sccsid[] = "@(#)readcf.c 8.101 (Berkeley) 06/10/95"; 1133731Sbostic #endif /* not lint */ 1222709Sdist 133313Seric # include "sendmail.h" 1464133Seric # include <grp.h> 1566334Seric #if NAMED_BIND 1657207Seric # include <resolv.h> 1757207Seric #endif 183308Seric 193308Seric /* 203308Seric ** READCF -- read control file. 213308Seric ** 223308Seric ** This routine reads the control file and builds the internal 233308Seric ** form. 243308Seric ** 254432Seric ** The file is formatted as a sequence of lines, each taken 264432Seric ** atomically. The first character of each line describes how 274432Seric ** the line is to be interpreted. The lines are: 284432Seric ** Dxval Define macro x to have value val. 294432Seric ** Cxword Put word into class x. 304432Seric ** Fxfile [fmt] Read file for lines to put into 314432Seric ** class x. Use scanf string 'fmt' 324432Seric ** or "%s" if not present. Fmt should 334432Seric ** only produce one string-valued result. 344432Seric ** Hname: value Define header with field-name 'name' 354432Seric ** and value as specified; this will be 364432Seric ** macro expanded immediately before 374432Seric ** use. 384432Seric ** Sn Use rewriting set n. 394432Seric ** Rlhs rhs Rewrite addresses that match lhs to 404432Seric ** be rhs. 4124944Seric ** Mn arg=val... Define mailer. n is the internal name. 4224944Seric ** Args specify mailer parameters. 438252Seric ** Oxvalue Set option x to value. 448252Seric ** Pname=value Set precedence name to value. 4564718Seric ** Vversioncode[/vendorcode] 4664718Seric ** Version level/vendor name of 4764718Seric ** configuration syntax. 4853654Seric ** Kmapname mapclass arguments.... 4953654Seric ** Define keyed lookup of a given class. 5053654Seric ** Arguments are class dependent. 5169476Seric ** Eenvar=value Set the environment value to the given value. 524432Seric ** 533308Seric ** Parameters: 543308Seric ** cfname -- control file name. 5554973Seric ** safe -- TRUE if this is the system config file; 5654973Seric ** FALSE otherwise. 5755012Seric ** e -- the main envelope. 583308Seric ** 593308Seric ** Returns: 603308Seric ** none. 613308Seric ** 623308Seric ** Side Effects: 633308Seric ** Builds several internal tables. 643308Seric */ 653308Seric 6669748Seric void 6755012Seric readcf(cfname, safe, e) 683308Seric char *cfname; 6954973Seric bool safe; 7055012Seric register ENVELOPE *e; 713308Seric { 723308Seric FILE *cf; 738547Seric int ruleset = 0; 748547Seric char *q; 759350Seric struct rewrite *rwp = NULL; 7657135Seric char *bp; 7764718Seric auto char *ep; 7857589Seric int nfuzzy; 7964133Seric char *file; 8064133Seric bool optional; 8168481Seric int mid; 823308Seric char buf[MAXLINE]; 833308Seric register char *p; 843308Seric extern char **copyplist(); 8552647Seric struct stat statb; 865909Seric char exbuf[MAXLINE]; 8765066Seric char pvpbuf[MAXLINE + MAXATOM]; 8868481Seric static char *null_list[1] = { NULL }; 8969748Seric extern char *munchstring __P((char *, char **)); 9069748Seric extern void fileclass __P((int, char *, char *, bool, bool)); 9169748Seric extern void toomany __P((int, int)); 923308Seric 9352647Seric FileName = cfname; 9452647Seric LineNumber = 0; 9552647Seric 963308Seric cf = fopen(cfname, "r"); 973308Seric if (cf == NULL) 983308Seric { 9952647Seric syserr("cannot open"); 1003308Seric exit(EX_OSFILE); 1013308Seric } 1023308Seric 10352647Seric if (fstat(fileno(cf), &statb) < 0) 10452647Seric { 10552647Seric syserr("cannot fstat"); 10652647Seric exit(EX_OSFILE); 10752647Seric } 10852647Seric 10952647Seric if (!S_ISREG(statb.st_mode)) 11052647Seric { 11152647Seric syserr("not a plain file"); 11252647Seric exit(EX_OSFILE); 11352647Seric } 11452647Seric 11552647Seric if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode)) 11652647Seric { 11769686Seric if (OpMode == MD_DAEMON || OpMode == MD_INITALIAS) 11853037Seric fprintf(stderr, "%s: WARNING: dangerous write permissions\n", 11953037Seric FileName); 12053037Seric #ifdef LOG 12153037Seric if (LogLevel > 0) 12253037Seric syslog(LOG_CRIT, "%s: WARNING: dangerous write permissions", 12353037Seric FileName); 12453037Seric #endif 12552647Seric } 12652647Seric 12759254Seric #ifdef XLA 12859254Seric xla_zero(); 12959254Seric #endif 13059254Seric 13157135Seric while ((bp = fgetfolded(buf, sizeof buf, cf)) != NULL) 1323308Seric { 13357135Seric if (bp[0] == '#') 13457135Seric { 13557135Seric if (bp != buf) 13657135Seric free(bp); 13752637Seric continue; 13857135Seric } 13952637Seric 14068481Seric /* do macro expansion mappings */ 14157135Seric for (p = bp; *p != '\0'; p++) 14216157Seric { 14357135Seric if (*p == '#' && p > bp && ConfigLevel >= 3) 14452647Seric { 14552647Seric /* this is an on-line comment */ 14652647Seric register char *e; 14752647Seric 14858050Seric switch (*--p & 0377) 14952647Seric { 15058050Seric case MACROEXPAND: 15152647Seric /* it's from $# -- let it go through */ 15252647Seric p++; 15352647Seric break; 15452647Seric 15552647Seric case '\\': 15652647Seric /* it's backslash escaped */ 15752647Seric (void) strcpy(p, p + 1); 15852647Seric break; 15952647Seric 16052647Seric default: 16152647Seric /* delete preceeding white space */ 16258050Seric while (isascii(*p) && isspace(*p) && p > bp) 16352647Seric p--; 16456795Seric if ((e = strchr(++p, '\n')) != NULL) 16552647Seric (void) strcpy(p, e); 16652647Seric else 16752647Seric p[0] = p[1] = '\0'; 16852647Seric break; 16952647Seric } 17052647Seric continue; 17152647Seric } 17252647Seric 17368481Seric if (*p != '$' || p[1] == '\0') 17416157Seric continue; 17516157Seric 17616157Seric if (p[1] == '$') 17716157Seric { 17816157Seric /* actual dollar sign.... */ 17923111Seric (void) strcpy(p, p + 1); 18016157Seric continue; 18116157Seric } 18216157Seric 18316157Seric /* convert to macro expansion character */ 18468481Seric *p++ = MACROEXPAND; 18568481Seric 18668481Seric /* convert macro name to code */ 18768481Seric *p = macid(p, &ep); 18868481Seric if (ep != p) 18968481Seric strcpy(p + 1, ep); 19016157Seric } 19116157Seric 19216157Seric /* interpret this line */ 19364718Seric errno = 0; 19457135Seric switch (bp[0]) 1953308Seric { 1963308Seric case '\0': 1973308Seric case '#': /* comment */ 1983308Seric break; 1993308Seric 2003308Seric case 'R': /* rewriting rule */ 20157135Seric for (p = &bp[1]; *p != '\0' && *p != '\t'; p++) 2023308Seric continue; 2033308Seric 2043308Seric if (*p == '\0') 2055909Seric { 20665821Seric syserr("invalid rewrite line \"%s\" (tab expected)", bp); 2075909Seric break; 2085909Seric } 2095909Seric 2105909Seric /* allocate space for the rule header */ 2115909Seric if (rwp == NULL) 2125909Seric { 2135909Seric RewriteRules[ruleset] = rwp = 2145909Seric (struct rewrite *) xalloc(sizeof *rwp); 2155909Seric } 2163308Seric else 2173308Seric { 2185909Seric rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp); 2195909Seric rwp = rwp->r_next; 2205909Seric } 2215909Seric rwp->r_next = NULL; 2223308Seric 2235909Seric /* expand and save the LHS */ 2245909Seric *p = '\0'; 22568529Seric expand(&bp[1], exbuf, sizeof exbuf, e); 22665066Seric rwp->r_lhs = prescan(exbuf, '\t', pvpbuf, 22768711Seric sizeof pvpbuf, NULL, NULL); 22857589Seric nfuzzy = 0; 2295909Seric if (rwp->r_lhs != NULL) 23057589Seric { 23157589Seric register char **ap; 23257589Seric 2335909Seric rwp->r_lhs = copyplist(rwp->r_lhs, TRUE); 23457589Seric 23557589Seric /* count the number of fuzzy matches in LHS */ 23657589Seric for (ap = rwp->r_lhs; *ap != NULL; ap++) 23757589Seric { 23858148Seric char *botch; 23958148Seric 24058148Seric botch = NULL; 24158050Seric switch (**ap & 0377) 24257589Seric { 24357589Seric case MATCHZANY: 24457589Seric case MATCHANY: 24557589Seric case MATCHONE: 24657589Seric case MATCHCLASS: 24757589Seric case MATCHNCLASS: 24857589Seric nfuzzy++; 24958148Seric break; 25058148Seric 25158148Seric case MATCHREPL: 25258148Seric botch = "$0-$9"; 25358148Seric break; 25458148Seric 25558148Seric case CANONNET: 25658148Seric botch = "$#"; 25758148Seric break; 25858148Seric 25958148Seric case CANONUSER: 26058148Seric botch = "$:"; 26158148Seric break; 26258148Seric 26358148Seric case CALLSUBR: 26458148Seric botch = "$>"; 26558148Seric break; 26658148Seric 26758148Seric case CONDIF: 26858148Seric botch = "$?"; 26958148Seric break; 27058148Seric 27158148Seric case CONDELSE: 27258148Seric botch = "$|"; 27358148Seric break; 27458148Seric 27558148Seric case CONDFI: 27658148Seric botch = "$."; 27758148Seric break; 27858148Seric 27958148Seric case HOSTBEGIN: 28058148Seric botch = "$["; 28158148Seric break; 28258148Seric 28358148Seric case HOSTEND: 28458148Seric botch = "$]"; 28558148Seric break; 28658148Seric 28758148Seric case LOOKUPBEGIN: 28858148Seric botch = "$("; 28958148Seric break; 29058148Seric 29158148Seric case LOOKUPEND: 29258148Seric botch = "$)"; 29358148Seric break; 29457589Seric } 29558148Seric if (botch != NULL) 29658148Seric syserr("Inappropriate use of %s on LHS", 29758148Seric botch); 29857589Seric } 29957589Seric } 30056678Seric else 30168481Seric { 30256678Seric syserr("R line: null LHS"); 30368481Seric rwp->r_lhs = null_list; 30468481Seric } 3055909Seric 3065909Seric /* expand and save the RHS */ 3075909Seric while (*++p == '\t') 3085909Seric continue; 3097231Seric q = p; 3107231Seric while (*p != '\0' && *p != '\t') 3117231Seric p++; 3127231Seric *p = '\0'; 31368529Seric expand(q, exbuf, sizeof exbuf, e); 31465066Seric rwp->r_rhs = prescan(exbuf, '\t', pvpbuf, 31568711Seric sizeof pvpbuf, NULL, NULL); 3165909Seric if (rwp->r_rhs != NULL) 31757589Seric { 31857589Seric register char **ap; 31957589Seric 3205909Seric rwp->r_rhs = copyplist(rwp->r_rhs, TRUE); 32157589Seric 32257589Seric /* check no out-of-bounds replacements */ 32357589Seric nfuzzy += '0'; 32457589Seric for (ap = rwp->r_rhs; *ap != NULL; ap++) 32557589Seric { 32658148Seric char *botch; 32758148Seric 32858148Seric botch = NULL; 32958148Seric switch (**ap & 0377) 33057589Seric { 33158148Seric case MATCHREPL: 33258148Seric if ((*ap)[1] <= '0' || (*ap)[1] > nfuzzy) 33358148Seric { 33458148Seric syserr("replacement $%c out of bounds", 33558148Seric (*ap)[1]); 33658148Seric } 33758148Seric break; 33858148Seric 33958148Seric case MATCHZANY: 34058148Seric botch = "$*"; 34158148Seric break; 34258148Seric 34358148Seric case MATCHANY: 34458148Seric botch = "$+"; 34558148Seric break; 34658148Seric 34758148Seric case MATCHONE: 34858148Seric botch = "$-"; 34958148Seric break; 35058148Seric 35158148Seric case MATCHCLASS: 35258148Seric botch = "$="; 35358148Seric break; 35458148Seric 35558148Seric case MATCHNCLASS: 35658148Seric botch = "$~"; 35758148Seric break; 35857589Seric } 35958148Seric if (botch != NULL) 36058148Seric syserr("Inappropriate use of %s on RHS", 36158148Seric botch); 36257589Seric } 36357589Seric } 36456678Seric else 36568481Seric { 36656678Seric syserr("R line: null RHS"); 36768481Seric rwp->r_rhs = null_list; 36868481Seric } 3693308Seric break; 3703308Seric 3714072Seric case 'S': /* select rewriting set */ 37269783Seric ruleset = strtorwset(&bp[1], NULL, ST_ENTER); 37369789Seric rwp = RewriteRules[ruleset]; 37469789Seric if (rwp != NULL) 37569789Seric { 37669789Seric while (rwp->r_next != NULL) 37769789Seric rwp = rwp->r_next; 37869789Seric fprintf(stderr, "WARNING: Ruleset %s redefined\n", 37969789Seric &bp[1]); 38069789Seric } 3814072Seric break; 3824072Seric 3833308Seric case 'D': /* macro definition */ 38468481Seric mid = macid(&bp[1], &ep); 38568481Seric p = munchstring(ep, NULL); 38668481Seric define(mid, newstr(p), e); 3873308Seric break; 3883308Seric 3893387Seric case 'H': /* required header line */ 39068717Seric (void) chompheader(&bp[1], TRUE, NULL, e); 3913387Seric break; 3923387Seric 3934061Seric case 'C': /* word class */ 39468481Seric case 'T': /* trusted user (set class `t') */ 39568481Seric if (bp[0] == 'C') 3964061Seric { 39768481Seric mid = macid(&bp[1], &ep); 39868529Seric expand(ep, exbuf, sizeof exbuf, e); 39968481Seric p = exbuf; 40068481Seric } 40168481Seric else 40268481Seric { 40368481Seric mid = 't'; 40468481Seric p = &bp[1]; 40568481Seric } 40668481Seric while (*p != '\0') 40768481Seric { 4084061Seric register char *wd; 4094061Seric char delim; 4104061Seric 41158050Seric while (*p != '\0' && isascii(*p) && isspace(*p)) 4124061Seric p++; 4134061Seric wd = p; 41458050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 4154061Seric p++; 4164061Seric delim = *p; 4174061Seric *p = '\0'; 4184061Seric if (wd[0] != '\0') 41968481Seric setclass(mid, wd); 4204061Seric *p = delim; 4214061Seric } 4224061Seric break; 4234061Seric 42459272Seric case 'F': /* word class from file */ 42568481Seric mid = macid(&bp[1], &ep); 42668481Seric for (p = ep; isascii(*p) && isspace(*p); ) 42764133Seric p++; 42864133Seric if (p[0] == '-' && p[1] == 'o') 42964133Seric { 43064133Seric optional = TRUE; 43164133Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 43264133Seric p++; 43364133Seric while (isascii(*p) && isspace(*p)) 43468481Seric p++; 43564133Seric } 43664133Seric else 43764133Seric optional = FALSE; 43864133Seric file = p; 43964133Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 44064133Seric p++; 44159272Seric if (*p == '\0') 44259272Seric p = "%s"; 44359272Seric else 44459272Seric { 44559272Seric *p = '\0'; 44659272Seric while (isascii(*++p) && isspace(*p)) 44759272Seric continue; 44859272Seric } 44964133Seric fileclass(bp[1], file, p, safe, optional); 45059272Seric break; 45159272Seric 45259156Seric #ifdef XLA 45359156Seric case 'L': /* extended load average description */ 45459156Seric xla_init(&bp[1]); 45559156Seric break; 45659156Seric #endif 45759156Seric 4584096Seric case 'M': /* define mailer */ 45957135Seric makemailer(&bp[1]); 4604096Seric break; 4614096Seric 4628252Seric case 'O': /* set option */ 46358734Seric setoption(bp[1], &bp[2], safe, FALSE, e); 4648252Seric break; 4658252Seric 4668252Seric case 'P': /* set precedence */ 4678252Seric if (NumPriorities >= MAXPRIORITIES) 4688252Seric { 4698547Seric toomany('P', MAXPRIORITIES); 4708252Seric break; 4718252Seric } 47257135Seric for (p = &bp[1]; *p != '\0' && *p != '=' && *p != '\t'; p++) 4738252Seric continue; 4748252Seric if (*p == '\0') 4758252Seric goto badline; 4768252Seric *p = '\0'; 47757135Seric Priorities[NumPriorities].pri_name = newstr(&bp[1]); 4788252Seric Priorities[NumPriorities].pri_val = atoi(++p); 4798252Seric NumPriorities++; 4808252Seric break; 4818252Seric 48252645Seric case 'V': /* configuration syntax version */ 48364440Seric for (p = &bp[1]; isascii(*p) && isspace(*p); p++) 48464440Seric continue; 48564440Seric if (!isascii(*p) || !isdigit(*p)) 48664440Seric { 48764440Seric syserr("invalid argument to V line: \"%.20s\"", 48864440Seric &bp[1]); 48964440Seric break; 49064440Seric } 49164718Seric ConfigLevel = strtol(p, &ep, 10); 49268805Seric 49368805Seric /* 49468805Seric ** Do heuristic tweaking for back compatibility. 49568805Seric */ 49668805Seric 49764279Seric if (ConfigLevel >= 5) 49864279Seric { 49964279Seric /* level 5 configs have short name in $w */ 50064279Seric p = macvalue('w', e); 50164279Seric if (p != NULL && (p = strchr(p, '.')) != NULL) 50264279Seric *p = '\0'; 50364279Seric } 50468805Seric if (ConfigLevel >= 6) 50568805Seric { 50668805Seric ColonOkInAddr = FALSE; 50768805Seric } 50868805Seric 50968805Seric /* 51068805Seric ** Look for vendor code. 51168805Seric */ 51268805Seric 51364718Seric if (*ep++ == '/') 51464718Seric { 51564718Seric /* extract vendor code */ 51664718Seric for (p = ep; isascii(*p) && isalpha(*p); ) 51764718Seric p++; 51864718Seric *p = '\0'; 51964718Seric 52064718Seric if (!setvendor(ep)) 52164718Seric syserr("invalid V line vendor code: \"%s\"", 52264718Seric ep); 52364718Seric } 52452645Seric break; 52552645Seric 52653654Seric case 'K': 52769774Seric (void) makemapentry(&bp[1]); 52853654Seric break; 52953654Seric 53069476Seric case 'E': 53169476Seric p = strchr(bp, '='); 53269476Seric if (p != NULL) 53369476Seric *p++ = '\0'; 53469476Seric setuserenv(&bp[1], p); 53569476Seric break; 53669476Seric 5373308Seric default: 5384061Seric badline: 53957135Seric syserr("unknown control line \"%s\"", bp); 5403308Seric } 54157135Seric if (bp != buf) 54257135Seric free(bp); 5433308Seric } 54452637Seric if (ferror(cf)) 54552637Seric { 54652647Seric syserr("I/O read error", cfname); 54752637Seric exit(EX_OSFILE); 54852637Seric } 54952637Seric fclose(cf); 5509381Seric FileName = NULL; 55156836Seric 55268481Seric /* initialize host maps from local service tables */ 55368481Seric inithostmaps(); 55468481Seric 55568481Seric /* determine if we need to do special name-server frotz */ 55667905Seric { 55768481Seric int nmaps; 55868481Seric char *maptype[MAXMAPSTACK]; 55968481Seric short mapreturn[MAXMAPACTIONS]; 56068481Seric 56168481Seric nmaps = switch_map_find("hosts", maptype, mapreturn); 56268481Seric UseNameServer = FALSE; 56368481Seric if (nmaps > 0 && nmaps <= MAXMAPSTACK) 56468481Seric { 56568481Seric register int mapno; 56668481Seric 56768481Seric for (mapno = 0; mapno < nmaps && !UseNameServer; mapno++) 56868481Seric { 56968481Seric if (strcmp(maptype[mapno], "dns") == 0) 57068481Seric UseNameServer = TRUE; 57168481Seric } 57268481Seric } 57368481Seric 57468481Seric #ifdef HESIOD 57568481Seric nmaps = switch_map_find("passwd", maptype, mapreturn); 57668481Seric UseHesiod = FALSE; 57768481Seric if (nmaps > 0 && nmaps <= MAXMAPSTACK) 57868481Seric { 57968481Seric register int mapno; 58068481Seric 58168481Seric for (mapno = 0; mapno < nmaps && !UseHesiod; mapno++) 58268481Seric { 58368481Seric if (strcmp(maptype[mapno], "hesiod") == 0) 58468481Seric UseHesiod = TRUE; 58568481Seric } 58668481Seric } 58768204Seric #endif 58867905Seric } 5894096Seric } 5904096Seric /* 5918547Seric ** TOOMANY -- signal too many of some option 5928547Seric ** 5938547Seric ** Parameters: 5948547Seric ** id -- the id of the error line 5958547Seric ** maxcnt -- the maximum possible values 5968547Seric ** 5978547Seric ** Returns: 5988547Seric ** none. 5998547Seric ** 6008547Seric ** Side Effects: 6018547Seric ** gives a syserr. 6028547Seric */ 6038547Seric 60469748Seric void 6058547Seric toomany(id, maxcnt) 60669748Seric int id; 6078547Seric int maxcnt; 6088547Seric { 6099381Seric syserr("too many %c lines, %d max", id, maxcnt); 6108547Seric } 6118547Seric /* 6124432Seric ** FILECLASS -- read members of a class from a file 6134432Seric ** 6144432Seric ** Parameters: 6154432Seric ** class -- class to define. 6164432Seric ** filename -- name of file to read. 6174432Seric ** fmt -- scanf string to use for match. 61864133Seric ** safe -- if set, this is a safe read. 61964133Seric ** optional -- if set, it is not an error for the file to 62064133Seric ** not exist. 6214432Seric ** 6224432Seric ** Returns: 6234432Seric ** none 6244432Seric ** 6254432Seric ** Side Effects: 6264432Seric ** 6274432Seric ** puts all lines in filename that match a scanf into 6284432Seric ** the named class. 6294432Seric */ 6304432Seric 63169748Seric void 63264133Seric fileclass(class, filename, fmt, safe, optional) 6334432Seric int class; 6344432Seric char *filename; 6354432Seric char *fmt; 63654973Seric bool safe; 63764133Seric bool optional; 6384432Seric { 63925808Seric FILE *f; 64068513Seric int sff; 64169453Seric int pid; 64269453Seric register char *p; 6434432Seric char buf[MAXLINE]; 6444432Seric 64566101Seric if (tTd(37, 2)) 64666101Seric printf("fileclass(%s, fmt=%s)\n", filename, fmt); 64766101Seric 64866031Seric if (filename[0] == '|') 64966031Seric { 65069453Seric auto int fd; 65169453Seric int i; 65269453Seric char *argv[MAXPV + 1]; 65369453Seric 65469453Seric i = 0; 65569453Seric for (p = strtok(&filename[1], " \t"); p != NULL; p = strtok(NULL, " \t")) 65669453Seric { 65769453Seric if (i >= MAXPV) 65869453Seric break; 65969453Seric argv[i++] = p; 66069453Seric } 66169453Seric argv[i] = NULL; 66269453Seric pid = prog_open(argv, &fd, CurEnv); 66369453Seric if (pid < 0) 66469453Seric f = NULL; 66569453Seric else 66669453Seric f = fdopen(fd, "r"); 66766031Seric } 66869453Seric else 66969453Seric { 67069453Seric pid = -1; 67169453Seric sff = SFF_REGONLY; 67269453Seric if (safe) 67369453Seric sff |= SFF_OPENASROOT; 67469453Seric f = safefopen(filename, O_RDONLY, 0, sff); 67569453Seric } 67668602Seric if (f == NULL) 67754973Seric { 67868602Seric if (!optional) 67968602Seric syserr("fileclass: cannot open %s", filename); 6804432Seric return; 6814432Seric } 6824432Seric 6834432Seric while (fgets(buf, sizeof buf, f) != NULL) 6844432Seric { 68525808Seric register char *p; 68625808Seric # ifdef SCANF 6874432Seric char wordbuf[MAXNAME+1]; 6884432Seric 6894432Seric if (sscanf(buf, fmt, wordbuf) != 1) 6904432Seric continue; 69125808Seric p = wordbuf; 69256795Seric # else /* SCANF */ 69325808Seric p = buf; 69456795Seric # endif /* SCANF */ 69525808Seric 69625808Seric /* 69725808Seric ** Break up the match into words. 69825808Seric */ 69925808Seric 70025808Seric while (*p != '\0') 70125808Seric { 70225808Seric register char *q; 70325808Seric 70425808Seric /* strip leading spaces */ 70558050Seric while (isascii(*p) && isspace(*p)) 70625808Seric p++; 70725808Seric if (*p == '\0') 70825808Seric break; 70925808Seric 71025808Seric /* find the end of the word */ 71125808Seric q = p; 71258050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 71325808Seric p++; 71425808Seric if (*p != '\0') 71525808Seric *p++ = '\0'; 71625808Seric 71725808Seric /* enter the word in the symbol table */ 71866101Seric setclass(class, q); 71925808Seric } 7204432Seric } 7214432Seric 72254973Seric (void) fclose(f); 72369453Seric if (pid > 0) 72469453Seric (void) waitfor(pid); 7254432Seric } 7264432Seric /* 7274096Seric ** MAKEMAILER -- define a new mailer. 7284096Seric ** 7294096Seric ** Parameters: 73010327Seric ** line -- description of mailer. This is in labeled 73110327Seric ** fields. The fields are: 73268481Seric ** A -- the argv for this mailer 73368481Seric ** C -- the character set for MIME conversions 73468481Seric ** D -- the directory to run in 73568481Seric ** E -- the eol string 73668481Seric ** F -- the flags associated with the mailer 73768481Seric ** L -- the maximum line length 73868481Seric ** M -- the maximum message size 73968816Seric ** N -- the niceness at which to run 74068479Seric ** P -- the path to the mailer 74168481Seric ** R -- the recipient rewriting set 74268479Seric ** S -- the sender rewriting set 74368481Seric ** T -- the mailer type (for DSNs) 74468481Seric ** U -- the uid to run as 74510327Seric ** The first word is the canonical name of the mailer. 7464096Seric ** 7474096Seric ** Returns: 7484096Seric ** none. 7494096Seric ** 7504096Seric ** Side Effects: 7514096Seric ** enters the mailer into the mailer table. 7524096Seric */ 7533308Seric 75469748Seric void 75521066Seric makemailer(line) 7564096Seric char *line; 7574096Seric { 7584096Seric register char *p; 7598067Seric register struct mailer *m; 7608067Seric register STAB *s; 7618067Seric int i; 76210327Seric char fcode; 76358020Seric auto char *endp; 7644096Seric extern int NextMailer; 76510327Seric extern char **makeargv(); 76610327Seric extern char *munchstring(); 7674096Seric 76810327Seric /* allocate a mailer and set up defaults */ 76910327Seric m = (struct mailer *) xalloc(sizeof *m); 77010327Seric bzero((char *) m, sizeof *m); 77110327Seric m->m_eol = "\n"; 77268481Seric m->m_uid = m->m_gid = 0; 77310327Seric 77410327Seric /* collect the mailer name */ 77558050Seric for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++) 77610327Seric continue; 77710327Seric if (*p != '\0') 77810327Seric *p++ = '\0'; 77910327Seric m->m_name = newstr(line); 78010327Seric 78110327Seric /* now scan through and assign info from the fields */ 78210327Seric while (*p != '\0') 78310327Seric { 78458333Seric auto char *delimptr; 78558333Seric 78658050Seric while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p)))) 78710327Seric p++; 78810327Seric 78910327Seric /* p now points to field code */ 79010327Seric fcode = *p; 79110327Seric while (*p != '\0' && *p != '=' && *p != ',') 79210327Seric p++; 79310327Seric if (*p++ != '=') 79410327Seric { 79552637Seric syserr("mailer %s: `=' expected", m->m_name); 79610327Seric return; 79710327Seric } 79858050Seric while (isascii(*p) && isspace(*p)) 79910327Seric p++; 80010327Seric 80110327Seric /* p now points to the field body */ 80258333Seric p = munchstring(p, &delimptr); 80310327Seric 80410327Seric /* install the field into the mailer struct */ 80510327Seric switch (fcode) 80610327Seric { 80710327Seric case 'P': /* pathname */ 80810327Seric m->m_mailer = newstr(p); 80910327Seric break; 81010327Seric 81110327Seric case 'F': /* flags */ 81210687Seric for (; *p != '\0'; p++) 81358050Seric if (!(isascii(*p) && isspace(*p))) 81452637Seric setbitn(*p, m->m_flags); 81510327Seric break; 81610327Seric 81710327Seric case 'S': /* sender rewriting ruleset */ 81810327Seric case 'R': /* recipient rewriting ruleset */ 81969783Seric i = strtorwset(p, &endp, ST_ENTER); 82069783Seric if (i < 0) 82110327Seric return; 82210327Seric if (fcode == 'S') 82358020Seric m->m_sh_rwset = m->m_se_rwset = i; 82410327Seric else 82558020Seric m->m_rh_rwset = m->m_re_rwset = i; 82658020Seric 82758020Seric p = endp; 82859985Seric if (*p++ == '/') 82958020Seric { 83069783Seric i = strtorwset(p, NULL); 83169783Seric if (i < 0) 83258020Seric return; 83358020Seric if (fcode == 'S') 83458020Seric m->m_sh_rwset = i; 83558020Seric else 83658020Seric m->m_rh_rwset = i; 83758020Seric } 83810327Seric break; 83910327Seric 84010327Seric case 'E': /* end of line string */ 84110327Seric m->m_eol = newstr(p); 84210327Seric break; 84310327Seric 84410327Seric case 'A': /* argument vector */ 84510327Seric m->m_argv = makeargv(p); 84610327Seric break; 84710701Seric 84810701Seric case 'M': /* maximum message size */ 84910701Seric m->m_maxsize = atol(p); 85010701Seric break; 85152106Seric 85252106Seric case 'L': /* maximum line length */ 85352106Seric m->m_linelimit = atoi(p); 85452106Seric break; 85558935Seric 85668816Seric case 'N': /* run niceness */ 85768816Seric m->m_nice = atoi(p); 85868816Seric break; 85968816Seric 86058935Seric case 'D': /* working directory */ 86158935Seric m->m_execdir = newstr(p); 86258935Seric break; 86368481Seric 86468481Seric case 'C': /* default charset */ 86568481Seric m->m_defcharset = newstr(p); 86668481Seric break; 86768481Seric 86869720Seric case 'T': /* MTA-Name/Address/Diagnostic types */ 86968481Seric m->m_mtatype = newstr(p); 87068481Seric p = strchr(m->m_mtatype, '/'); 87168481Seric if (p != NULL) 87268481Seric { 87368481Seric *p++ = '\0'; 87468481Seric if (*p == '\0') 87568481Seric p = NULL; 87668481Seric } 87768481Seric if (p == NULL) 87868481Seric m->m_addrtype = m->m_mtatype; 87968481Seric else 88068481Seric { 88168481Seric m->m_addrtype = p; 88268481Seric p = strchr(p, '/'); 88368481Seric } 88468481Seric if (p != NULL) 88568481Seric { 88668481Seric *p++ = '\0'; 88768481Seric if (*p == '\0') 88868481Seric p = NULL; 88968481Seric } 89068481Seric if (p == NULL) 89168481Seric m->m_diagtype = m->m_mtatype; 89268481Seric else 89368481Seric m->m_diagtype = p; 89468481Seric break; 89568481Seric 89668481Seric case 'U': /* user id */ 89768481Seric if (isascii(*p) && !isdigit(*p)) 89868481Seric { 89968481Seric char *q = p; 90068481Seric struct passwd *pw; 90168481Seric 90268481Seric while (isascii(*p) && isalnum(*p)) 90368481Seric p++; 90468481Seric while (isascii(*p) && isspace(*p)) 90568481Seric *p++ = '\0'; 90668481Seric if (*p != '\0') 90768481Seric *p++ = '\0'; 90868693Seric pw = sm_getpwnam(q); 90968481Seric if (pw == NULL) 91068481Seric syserr("readcf: mailer U= flag: unknown user %s", q); 91168481Seric else 91268481Seric { 91368481Seric m->m_uid = pw->pw_uid; 91468481Seric m->m_gid = pw->pw_gid; 91568481Seric } 91668481Seric } 91768481Seric else 91868481Seric { 91968481Seric auto char *q; 92068481Seric 92168481Seric m->m_uid = strtol(p, &q, 0); 92268481Seric p = q; 92368481Seric } 92468481Seric while (isascii(*p) && isspace(*p)) 92568481Seric p++; 92668481Seric if (*p == '\0') 92768481Seric break; 92868481Seric if (isascii(*p) && !isdigit(*p)) 92968481Seric { 93068481Seric char *q = p; 93168481Seric struct group *gr; 93268481Seric 93368481Seric while (isascii(*p) && isalnum(*p)) 93468481Seric p++; 93568481Seric *p++ = '\0'; 93668481Seric gr = getgrnam(q); 93768481Seric if (gr == NULL) 93868481Seric syserr("readcf: mailer U= flag: unknown group %s", q); 93968481Seric else 94068481Seric m->m_gid = gr->gr_gid; 94168481Seric } 94268481Seric else 94368481Seric { 94468481Seric m->m_gid = strtol(p, NULL, 0); 94568481Seric } 94668481Seric break; 94710327Seric } 94810327Seric 94958333Seric p = delimptr; 95010327Seric } 95110327Seric 95258321Seric /* do some rationality checking */ 95358321Seric if (m->m_argv == NULL) 95458321Seric { 95558321Seric syserr("M%s: A= argument required", m->m_name); 95658321Seric return; 95758321Seric } 95858321Seric if (m->m_mailer == NULL) 95958321Seric { 96058321Seric syserr("M%s: P= argument required", m->m_name); 96158321Seric return; 96258321Seric } 96358321Seric 9644096Seric if (NextMailer >= MAXMAILERS) 9654096Seric { 9669381Seric syserr("too many mailers defined (%d max)", MAXMAILERS); 9674096Seric return; 9684096Seric } 96957402Seric 97068481Seric /* do some heuristic cleanup for back compatibility */ 97168481Seric if (bitnset(M_LIMITS, m->m_flags)) 97268481Seric { 97368481Seric if (m->m_linelimit == 0) 97468481Seric m->m_linelimit = SMTPLINELIM; 97568481Seric if (ConfigLevel < 2) 97668481Seric setbitn(M_7BITS, m->m_flags); 97768481Seric } 97868481Seric 97968481Seric if (ConfigLevel < 6 && 98068481Seric (strcmp(m->m_mailer, "[IPC]") == 0 || 98168481Seric strcmp(m->m_mailer, "[TCP]") == 0)) 98268481Seric { 98368481Seric if (m->m_mtatype == NULL) 98468481Seric m->m_mtatype = "dns"; 98568481Seric if (m->m_addrtype == NULL) 98668481Seric m->m_addrtype = "rfc822"; 98768481Seric if (m->m_diagtype == NULL) 98868481Seric m->m_diagtype = "smtp"; 98968481Seric } 99068481Seric 99168481Seric /* enter the mailer into the symbol table */ 99210327Seric s = stab(m->m_name, ST_MAILER, ST_ENTER); 99357402Seric if (s->s_mailer != NULL) 99457402Seric { 99557402Seric i = s->s_mailer->m_mno; 99657402Seric free(s->s_mailer); 99757402Seric } 99857402Seric else 99957402Seric { 100057402Seric i = NextMailer++; 100157402Seric } 100257402Seric Mailer[i] = s->s_mailer = m; 100357454Seric m->m_mno = i; 100410327Seric } 100510327Seric /* 100610327Seric ** MUNCHSTRING -- translate a string into internal form. 100710327Seric ** 100810327Seric ** Parameters: 100910327Seric ** p -- the string to munch. 101058333Seric ** delimptr -- if non-NULL, set to the pointer of the 101158333Seric ** field delimiter character. 101210327Seric ** 101310327Seric ** Returns: 101410327Seric ** the munched string. 101510327Seric */ 10164096Seric 101710327Seric char * 101858333Seric munchstring(p, delimptr) 101910327Seric register char *p; 102058333Seric char **delimptr; 102110327Seric { 102210327Seric register char *q; 102310327Seric bool backslash = FALSE; 102410327Seric bool quotemode = FALSE; 102510327Seric static char buf[MAXLINE]; 10264096Seric 102710327Seric for (q = buf; *p != '\0'; p++) 10284096Seric { 102910327Seric if (backslash) 103010327Seric { 103110327Seric /* everything is roughly literal */ 103210357Seric backslash = FALSE; 103310327Seric switch (*p) 103410327Seric { 103510327Seric case 'r': /* carriage return */ 103610327Seric *q++ = '\r'; 103710327Seric continue; 103810327Seric 103910327Seric case 'n': /* newline */ 104010327Seric *q++ = '\n'; 104110327Seric continue; 104210327Seric 104310327Seric case 'f': /* form feed */ 104410327Seric *q++ = '\f'; 104510327Seric continue; 104610327Seric 104710327Seric case 'b': /* backspace */ 104810327Seric *q++ = '\b'; 104910327Seric continue; 105010327Seric } 105110327Seric *q++ = *p; 105210327Seric } 105310327Seric else 105410327Seric { 105510327Seric if (*p == '\\') 105610327Seric backslash = TRUE; 105710327Seric else if (*p == '"') 105810327Seric quotemode = !quotemode; 105910327Seric else if (quotemode || *p != ',') 106010327Seric *q++ = *p; 106110327Seric else 106210327Seric break; 106310327Seric } 10644096Seric } 10654096Seric 106658333Seric if (delimptr != NULL) 106758333Seric *delimptr = p; 106810327Seric *q++ = '\0'; 106910327Seric return (buf); 107010327Seric } 107110327Seric /* 107210327Seric ** MAKEARGV -- break up a string into words 107310327Seric ** 107410327Seric ** Parameters: 107510327Seric ** p -- the string to break up. 107610327Seric ** 107710327Seric ** Returns: 107810327Seric ** a char **argv (dynamically allocated) 107910327Seric ** 108010327Seric ** Side Effects: 108110327Seric ** munges p. 108210327Seric */ 10834096Seric 108410327Seric char ** 108510327Seric makeargv(p) 108610327Seric register char *p; 108710327Seric { 108810327Seric char *q; 108910327Seric int i; 109010327Seric char **avp; 109110327Seric char *argv[MAXPV + 1]; 109210327Seric 109310327Seric /* take apart the words */ 109410327Seric i = 0; 109510327Seric while (*p != '\0' && i < MAXPV) 10964096Seric { 109710327Seric q = p; 109858050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 109910327Seric p++; 110058050Seric while (isascii(*p) && isspace(*p)) 110110327Seric *p++ = '\0'; 110210327Seric argv[i++] = newstr(q); 11034096Seric } 110410327Seric argv[i++] = NULL; 11054096Seric 110610327Seric /* now make a copy of the argv */ 110710327Seric avp = (char **) xalloc(sizeof *avp * i); 110816893Seric bcopy((char *) argv, (char *) avp, sizeof *avp * i); 110910327Seric 111010327Seric return (avp); 11113308Seric } 11123308Seric /* 11133308Seric ** PRINTRULES -- print rewrite rules (for debugging) 11143308Seric ** 11153308Seric ** Parameters: 11163308Seric ** none. 11173308Seric ** 11183308Seric ** Returns: 11193308Seric ** none. 11203308Seric ** 11213308Seric ** Side Effects: 11223308Seric ** prints rewrite rules. 11233308Seric */ 11243308Seric 112569748Seric void 11263308Seric printrules() 11273308Seric { 11283308Seric register struct rewrite *rwp; 11294072Seric register int ruleset; 11303308Seric 11314072Seric for (ruleset = 0; ruleset < 10; ruleset++) 11323308Seric { 11334072Seric if (RewriteRules[ruleset] == NULL) 11344072Seric continue; 11358067Seric printf("\n----Rule Set %d:", ruleset); 11363308Seric 11374072Seric for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 11383308Seric { 11398067Seric printf("\nLHS:"); 11408067Seric printav(rwp->r_lhs); 11418067Seric printf("RHS:"); 11428067Seric printav(rwp->r_rhs); 11433308Seric } 11443308Seric } 11453308Seric } 114668481Seric /* 114768481Seric ** PRINTMAILER -- print mailer structure (for debugging) 114868481Seric ** 114968481Seric ** Parameters: 115068481Seric ** m -- the mailer to print 115168481Seric ** 115268481Seric ** Returns: 115368481Seric ** none. 115468481Seric */ 11554319Seric 115669748Seric void 115768481Seric printmailer(m) 115868481Seric register MAILER *m; 115968481Seric { 116068481Seric int j; 116168481Seric 116268481Seric printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld U=%d:%d F=", 116368481Seric m->m_mno, m->m_name, 116468481Seric m->m_mailer, m->m_se_rwset, m->m_sh_rwset, 116568481Seric m->m_re_rwset, m->m_rh_rwset, m->m_maxsize, 116668481Seric m->m_uid, m->m_gid); 116768481Seric for (j = '\0'; j <= '\177'; j++) 116868481Seric if (bitnset(j, m->m_flags)) 116968481Seric (void) putchar(j); 117068481Seric printf(" L=%d E=", m->m_linelimit); 117168481Seric xputs(m->m_eol); 117268481Seric if (m->m_defcharset != NULL) 117368481Seric printf(" C=%s", m->m_defcharset); 117468481Seric printf(" T=%s/%s/%s", 117568481Seric m->m_mtatype == NULL ? "<undefined>" : m->m_mtatype, 117668481Seric m->m_addrtype == NULL ? "<undefined>" : m->m_addrtype, 117768481Seric m->m_diagtype == NULL ? "<undefined>" : m->m_diagtype); 117868481Seric if (m->m_argv != NULL) 117968481Seric { 118068481Seric char **a = m->m_argv; 118168481Seric 118268481Seric printf(" A="); 118368481Seric while (*a != NULL) 118468481Seric { 118568481Seric if (a != m->m_argv) 118668481Seric printf(" "); 118768481Seric xputs(*a++); 118868481Seric } 118968481Seric } 119068481Seric printf("\n"); 119168481Seric } 11924096Seric /* 11938256Seric ** SETOPTION -- set global processing option 11948256Seric ** 11958256Seric ** Parameters: 11968256Seric ** opt -- option name. 11978256Seric ** val -- option value (as a text string). 119821755Seric ** safe -- set if this came from a configuration file. 119921755Seric ** Some options (if set from the command line) will 120021755Seric ** reset the user id to avoid security problems. 12018269Seric ** sticky -- if set, don't let other setoptions override 12028269Seric ** this value. 120358734Seric ** e -- the main envelope. 12048256Seric ** 12058256Seric ** Returns: 12068256Seric ** none. 12078256Seric ** 12088256Seric ** Side Effects: 12098256Seric ** Sets options as implied by the arguments. 12108256Seric */ 12118256Seric 121210687Seric static BITMAP StickyOpt; /* set if option is stuck */ 121369748Seric extern void settimeout __P((char *, char *)); 12148269Seric 121557207Seric 121666334Seric #if NAMED_BIND 121757207Seric 121857207Seric struct resolverflags 121957207Seric { 122057207Seric char *rf_name; /* name of the flag */ 122157207Seric long rf_bits; /* bits to set/clear */ 122257207Seric } ResolverFlags[] = 122357207Seric { 122457207Seric "debug", RES_DEBUG, 122557207Seric "aaonly", RES_AAONLY, 122657207Seric "usevc", RES_USEVC, 122757207Seric "primary", RES_PRIMARY, 122857207Seric "igntc", RES_IGNTC, 122957207Seric "recurse", RES_RECURSE, 123057207Seric "defnames", RES_DEFNAMES, 123157207Seric "stayopen", RES_STAYOPEN, 123257207Seric "dnsrch", RES_DNSRCH, 123365583Seric "true", 0, /* to avoid error on old syntax */ 123457207Seric NULL, 0 123557207Seric }; 123657207Seric 123757207Seric #endif 123857207Seric 123968481Seric struct optioninfo 124068481Seric { 124168481Seric char *o_name; /* long name of option */ 124268481Seric u_char o_code; /* short name of option */ 124368481Seric bool o_safe; /* safe for random people to use */ 124468481Seric } OptionTab[] = 124568481Seric { 124668481Seric "SevenBitInput", '7', TRUE, 124769480Seric #if MIME8TO7 124868481Seric "EightBitMode", '8', TRUE, 124969480Seric #endif 125068481Seric "AliasFile", 'A', FALSE, 125168481Seric "AliasWait", 'a', FALSE, 125268481Seric "BlankSub", 'B', FALSE, 125368481Seric "MinFreeBlocks", 'b', TRUE, 125468481Seric "CheckpointInterval", 'C', TRUE, 125568481Seric "HoldExpensive", 'c', FALSE, 125668481Seric "AutoRebuildAliases", 'D', FALSE, 125768481Seric "DeliveryMode", 'd', TRUE, 125868481Seric "ErrorHeader", 'E', FALSE, 125968481Seric "ErrorMode", 'e', TRUE, 126068481Seric "TempFileMode", 'F', FALSE, 126168481Seric "SaveFromLine", 'f', FALSE, 126268481Seric "MatchGECOS", 'G', FALSE, 126368481Seric "HelpFile", 'H', FALSE, 126468481Seric "MaxHopCount", 'h', FALSE, 126568569Seric "ResolverOptions", 'I', FALSE, 126668481Seric "IgnoreDots", 'i', TRUE, 126768481Seric "ForwardPath", 'J', FALSE, 126868481Seric "SendMimeErrors", 'j', TRUE, 126968481Seric "ConnectionCacheSize", 'k', FALSE, 127068481Seric "ConnectionCacheTimeout", 'K', FALSE, 127168481Seric "UseErrorsTo", 'l', FALSE, 127268481Seric "LogLevel", 'L', FALSE, 127368481Seric "MeToo", 'm', TRUE, 127468481Seric "CheckAliases", 'n', FALSE, 127568481Seric "OldStyleHeaders", 'o', TRUE, 127668481Seric "DaemonPortOptions", 'O', FALSE, 127768481Seric "PrivacyOptions", 'p', TRUE, 127868481Seric "PostmasterCopy", 'P', FALSE, 127968481Seric "QueueFactor", 'q', FALSE, 128068481Seric "QueueDirectory", 'Q', FALSE, 128168481Seric "DontPruneRoutes", 'R', FALSE, 128268481Seric "Timeout", 'r', TRUE, 128368481Seric "StatusFile", 'S', FALSE, 128468481Seric "SuperSafe", 's', TRUE, 128568481Seric "QueueTimeout", 'T', FALSE, 128668481Seric "TimeZoneSpec", 't', FALSE, 128768481Seric "UserDatabaseSpec", 'U', FALSE, 128868481Seric "DefaultUser", 'u', FALSE, 128968481Seric "FallbackMXhost", 'V', FALSE, 129068481Seric "Verbose", 'v', TRUE, 129168481Seric "TryNullMXList", 'w', TRUE, 129268481Seric "QueueLA", 'x', FALSE, 129368481Seric "RefuseLA", 'X', FALSE, 129468481Seric "RecipientFactor", 'y', FALSE, 129568569Seric "ForkEachJob", 'Y', FALSE, 129668481Seric "ClassFactor", 'z', FALSE, 129768569Seric "RetryFactor", 'Z', FALSE, 129868481Seric #define O_QUEUESORTORD 0x81 129968481Seric "QueueSortOrder", O_QUEUESORTORD, TRUE, 130069401Seric #define O_HOSTSFILE 0x82 130169401Seric "HostsFile", O_HOSTSFILE, FALSE, 130268481Seric #define O_MQA 0x83 130368481Seric "MinQueueAge", O_MQA, TRUE, 130468481Seric #define O_MHSA 0x84 130568481Seric /* 130668481Seric "MaxHostStatAge", O_MHSA, TRUE, 130768481Seric */ 130868481Seric #define O_DEFCHARSET 0x85 130968481Seric "DefaultCharSet", O_DEFCHARSET, TRUE, 131068481Seric #define O_SSFILE 0x86 131168481Seric "ServiceSwitchFile", O_SSFILE, FALSE, 131268481Seric #define O_DIALDELAY 0x87 131368481Seric "DialDelay", O_DIALDELAY, TRUE, 131468481Seric #define O_NORCPTACTION 0x88 131568481Seric "NoRecipientAction", O_NORCPTACTION, TRUE, 131668490Seric #define O_SAFEFILEENV 0x89 131768490Seric "SafeFileEnvironment", O_SAFEFILEENV, FALSE, 131868569Seric #define O_MAXMSGSIZE 0x8a 131968569Seric "MaxMessageSize", O_MAXMSGSIZE, FALSE, 132068756Seric #define O_COLONOKINADDR 0x8b 132168756Seric "ColonOkInAddr", O_COLONOKINADDR, TRUE, 132269724Seric #define O_MAXQUEUERUN 0x8c 132369724Seric "MaxQueueRunSize", O_MAXQUEUERUN, TRUE, 132469838Seric #define O_MAXCHILDREN 0x8d 132569838Seric /* 132669838Seric "MaxDaemonChildren", O_MAXCHILDREN, FALSE, 132769838Seric */ 1328*69852Seric #define O_KEEPCNAMES 0x8e 1329*69852Seric "DontExpandCnames", O_KEEPCNAMES, FALSE, 133068481Seric 133168481Seric NULL, '\0', FALSE, 133268481Seric }; 133368481Seric 133468481Seric 133568481Seric 133669748Seric void 133758734Seric setoption(opt, val, safe, sticky, e) 133869748Seric int opt; 13398256Seric char *val; 134021755Seric bool safe; 13418269Seric bool sticky; 134258734Seric register ENVELOPE *e; 13438256Seric { 134457207Seric register char *p; 134568481Seric register struct optioninfo *o; 134668481Seric char *subopt; 13478265Seric extern bool atobool(); 134812633Seric extern time_t convtime(); 134914879Seric extern int QueueLA; 135014879Seric extern int RefuseLA; 135164718Seric extern bool Warn_Q_option; 13528256Seric 135368481Seric errno = 0; 135468481Seric if (opt == ' ') 135568481Seric { 135668481Seric /* full word options */ 135768481Seric struct optioninfo *sel; 135868481Seric 135968481Seric p = strchr(val, '='); 136068481Seric if (p == NULL) 136168481Seric p = &val[strlen(val)]; 136268481Seric while (*--p == ' ') 136368481Seric continue; 136468481Seric while (*++p == ' ') 136568481Seric *p = '\0'; 136668481Seric if (p == val) 136768481Seric { 136868481Seric syserr("readcf: null option name"); 136968481Seric return; 137068481Seric } 137168481Seric if (*p == '=') 137268481Seric *p++ = '\0'; 137368481Seric while (*p == ' ') 137468481Seric p++; 137568481Seric subopt = strchr(val, '.'); 137668481Seric if (subopt != NULL) 137768481Seric *subopt++ = '\0'; 137868481Seric sel = NULL; 137968481Seric for (o = OptionTab; o->o_name != NULL; o++) 138068481Seric { 138168481Seric if (strncasecmp(o->o_name, val, strlen(val)) != 0) 138268481Seric continue; 138368481Seric if (strlen(o->o_name) == strlen(val)) 138468481Seric { 138568481Seric /* completely specified -- this must be it */ 138668481Seric sel = NULL; 138768481Seric break; 138868481Seric } 138968481Seric if (sel != NULL) 139068481Seric break; 139168481Seric sel = o; 139268481Seric } 139368481Seric if (sel != NULL && o->o_name == NULL) 139468481Seric o = sel; 139568481Seric else if (o->o_name == NULL) 139668481Seric { 139768481Seric syserr("readcf: unknown option name %s", val); 139868481Seric return; 139968481Seric } 140068481Seric else if (sel != NULL) 140168481Seric { 140268481Seric syserr("readcf: ambiguous option name %s (matches %s and %s)", 140368481Seric val, sel->o_name, o->o_name); 140468481Seric return; 140568481Seric } 140668481Seric if (strlen(val) != strlen(o->o_name)) 140768481Seric { 140868481Seric bool oldVerbose = Verbose; 140968481Seric 141068481Seric Verbose = TRUE; 141168481Seric message("Option %s used as abbreviation for %s", 141268481Seric val, o->o_name); 141368481Seric Verbose = oldVerbose; 141468481Seric } 141568481Seric opt = o->o_code; 141668481Seric val = p; 141768481Seric } 141868481Seric else 141968481Seric { 142068481Seric for (o = OptionTab; o->o_name != NULL; o++) 142168481Seric { 142268481Seric if (o->o_code == opt) 142368481Seric break; 142468481Seric } 142568481Seric subopt = NULL; 142668481Seric } 142768481Seric 14288256Seric if (tTd(37, 1)) 142968481Seric { 143068481Seric printf(isascii(opt) && isprint(opt) ? 143168481Seric "setoption %s (%c).%s=%s" : 143268481Seric "setoption %s (0x%x).%s=%s", 143368481Seric o->o_name == NULL ? "<unknown>" : o->o_name, 143468481Seric opt, 143568481Seric subopt == NULL ? "" : subopt, 143668481Seric val); 143768481Seric } 14388256Seric 14398256Seric /* 14408269Seric ** See if this option is preset for us. 14418256Seric */ 14428256Seric 144359731Seric if (!sticky && bitnset(opt, StickyOpt)) 14448269Seric { 14459341Seric if (tTd(37, 1)) 14469341Seric printf(" (ignored)\n"); 14478269Seric return; 14488269Seric } 14498269Seric 145021755Seric /* 145121755Seric ** Check to see if this option can be specified by this user. 145221755Seric */ 145321755Seric 145463787Seric if (!safe && RealUid == 0) 145521755Seric safe = TRUE; 145668481Seric if (!safe && !o->o_safe) 145721755Seric { 145839111Srick if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 145921755Seric { 146036582Sbostic if (tTd(37, 1)) 146136582Sbostic printf(" (unsafe)"); 146263787Seric if (RealUid != geteuid()) 146336582Sbostic { 146451210Seric if (tTd(37, 1)) 146551210Seric printf("(Resetting uid)"); 146663787Seric (void) setgid(RealGid); 146763787Seric (void) setuid(RealUid); 146836582Sbostic } 146921755Seric } 147021755Seric } 147151210Seric if (tTd(37, 1)) 147217985Seric printf("\n"); 14738269Seric 147468481Seric switch (opt & 0xff) 14758256Seric { 147659709Seric case '7': /* force seven-bit input */ 147768481Seric SevenBitInput = atobool(val); 147852106Seric break; 147952106Seric 148069480Seric #if MIME8TO7 148168481Seric case '8': /* handling of 8-bit input */ 148268481Seric switch (*val) 148368481Seric { 148468481Seric case 'm': /* convert 8-bit, convert MIME */ 148568481Seric MimeMode = MM_CVTMIME|MM_MIME8BIT; 148668481Seric break; 148768481Seric 148868481Seric case 'p': /* pass 8 bit, convert MIME */ 148968856Seric MimeMode = MM_CVTMIME|MM_PASS8BIT; 149068481Seric break; 149168481Seric 149268481Seric case 's': /* strict adherence */ 149368481Seric MimeMode = MM_CVTMIME; 149468481Seric break; 149568481Seric 149668856Seric #if 0 149768856Seric case 'r': /* reject 8-bit, don't convert MIME */ 149868856Seric MimeMode = 0; 149968856Seric break; 150068856Seric 150168856Seric case 'j': /* "just send 8" */ 150268856Seric MimeMode = MM_PASS8BIT; 150368856Seric break; 150468856Seric 150568481Seric case 'a': /* encode 8 bit if available */ 150668481Seric MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 150768481Seric break; 150868481Seric 150968481Seric case 'c': /* convert 8 bit to MIME, never 7 bit */ 151068481Seric MimeMode = MM_MIME8BIT; 151168481Seric break; 151268856Seric #endif 151368481Seric 151468481Seric default: 151568481Seric syserr("Unknown 8-bit mode %c", *val); 151668481Seric exit(EX_USAGE); 151768481Seric } 151868481Seric break; 151969480Seric #endif 152068481Seric 15218256Seric case 'A': /* set default alias file */ 15229381Seric if (val[0] == '\0') 152359672Seric setalias("aliases"); 15249381Seric else 152559672Seric setalias(val); 15268256Seric break; 15278256Seric 152817474Seric case 'a': /* look N minutes for "@:@" in alias file */ 152917474Seric if (val[0] == '\0') 153064796Seric SafeAlias = 5 * 60; /* five minutes */ 153117474Seric else 153264796Seric SafeAlias = convtime(val, 'm'); 153317474Seric break; 153417474Seric 153516843Seric case 'B': /* substitution for blank character */ 153616843Seric SpaceSub = val[0]; 153716843Seric if (SpaceSub == '\0') 153816843Seric SpaceSub = ' '; 153916843Seric break; 154016843Seric 154159283Seric case 'b': /* min blocks free on queue fs/max msg size */ 154259283Seric p = strchr(val, '/'); 154359283Seric if (p != NULL) 154459283Seric { 154559283Seric *p++ = '\0'; 154659283Seric MaxMessageSize = atol(p); 154759283Seric } 154858082Seric MinBlocksFree = atol(val); 154958082Seric break; 155058082Seric 15519284Seric case 'c': /* don't connect to "expensive" mailers */ 15529381Seric NoConnect = atobool(val); 15539284Seric break; 15549284Seric 155551305Seric case 'C': /* checkpoint every N addresses */ 155651305Seric CheckpointInterval = atoi(val); 155724944Seric break; 155824944Seric 15599284Seric case 'd': /* delivery mode */ 15609284Seric switch (*val) 15618269Seric { 15629284Seric case '\0': 156358734Seric e->e_sendmode = SM_DELIVER; 15648269Seric break; 15658269Seric 156610755Seric case SM_QUEUE: /* queue only */ 156710755Seric #ifndef QUEUE 156810755Seric syserr("need QUEUE to set -odqueue"); 156956795Seric #endif /* QUEUE */ 157010755Seric /* fall through..... */ 157110755Seric 15729284Seric case SM_DELIVER: /* do everything */ 15739284Seric case SM_FORK: /* fork after verification */ 157458734Seric e->e_sendmode = *val; 15758269Seric break; 15768269Seric 15778269Seric default: 15789284Seric syserr("Unknown delivery mode %c", *val); 15798269Seric exit(EX_USAGE); 15808269Seric } 15818269Seric break; 15828269Seric 15839146Seric case 'D': /* rebuild alias database as needed */ 15849381Seric AutoRebuild = atobool(val); 15859146Seric break; 15869146Seric 158755372Seric case 'E': /* error message header/header file */ 158855379Seric if (*val != '\0') 158955379Seric ErrMsgFile = newstr(val); 159055372Seric break; 159155372Seric 15928269Seric case 'e': /* set error processing mode */ 15938269Seric switch (*val) 15948269Seric { 15959381Seric case EM_QUIET: /* be silent about it */ 15969381Seric case EM_MAIL: /* mail back */ 15979381Seric case EM_BERKNET: /* do berknet error processing */ 15989381Seric case EM_WRITE: /* write back (or mail) */ 15999381Seric case EM_PRINT: /* print errors normally (default) */ 160058734Seric e->e_errormode = *val; 16018269Seric break; 16028269Seric } 16038269Seric break; 16048269Seric 16059049Seric case 'F': /* file mode */ 160617975Seric FileMode = atooct(val) & 0777; 16079049Seric break; 16089049Seric 16098269Seric case 'f': /* save Unix-style From lines on front */ 16109381Seric SaveFrom = atobool(val); 16118269Seric break; 16128269Seric 161353735Seric case 'G': /* match recipients against GECOS field */ 161453735Seric MatchGecos = atobool(val); 161553735Seric break; 161653735Seric 16178256Seric case 'g': /* default gid */ 161868481Seric g_opt: 161964133Seric if (isascii(*val) && isdigit(*val)) 162064133Seric DefGid = atoi(val); 162164133Seric else 162264133Seric { 162364133Seric register struct group *gr; 162464133Seric 162564133Seric DefGid = -1; 162664133Seric gr = getgrnam(val); 162764133Seric if (gr == NULL) 162868481Seric syserr("readcf: option %c: unknown group %s", 162968481Seric opt, val); 163064133Seric else 163164133Seric DefGid = gr->gr_gid; 163264133Seric } 16338256Seric break; 16348256Seric 16358256Seric case 'H': /* help file */ 16369381Seric if (val[0] == '\0') 16378269Seric HelpFile = "sendmail.hf"; 16389381Seric else 16399381Seric HelpFile = newstr(val); 16408256Seric break; 16418256Seric 164251305Seric case 'h': /* maximum hop count */ 164351305Seric MaxHopCount = atoi(val); 164451305Seric break; 164551305Seric 164635651Seric case 'I': /* use internet domain name server */ 164766334Seric #if NAMED_BIND 164857207Seric for (p = val; *p != 0; ) 164957207Seric { 165057207Seric bool clearmode; 165157207Seric char *q; 165257207Seric struct resolverflags *rfp; 165357207Seric 165457207Seric while (*p == ' ') 165557207Seric p++; 165657207Seric if (*p == '\0') 165757207Seric break; 165857207Seric clearmode = FALSE; 165957207Seric if (*p == '-') 166057207Seric clearmode = TRUE; 166157207Seric else if (*p != '+') 166257207Seric p--; 166357207Seric p++; 166457207Seric q = p; 166558050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 166657207Seric p++; 166757207Seric if (*p != '\0') 166857207Seric *p++ = '\0'; 166968759Seric if (strcasecmp(q, "HasWildcardMX") == 0) 167068759Seric { 167168759Seric NoMXforCanon = !clearmode; 167268759Seric continue; 167368759Seric } 167457207Seric for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 167557207Seric { 167657207Seric if (strcasecmp(q, rfp->rf_name) == 0) 167757207Seric break; 167857207Seric } 167964923Seric if (rfp->rf_name == NULL) 168064923Seric syserr("readcf: I option value %s unrecognized", q); 168164923Seric else if (clearmode) 168257207Seric _res.options &= ~rfp->rf_bits; 168357207Seric else 168457207Seric _res.options |= rfp->rf_bits; 168557207Seric } 168657207Seric if (tTd(8, 2)) 168768759Seric printf("_res.options = %x, HasWildcardMX = %d\n", 168868759Seric _res.options, !NoMXforCanon); 168957207Seric #else 169057207Seric usrerr("name server (I option) specified but BIND not compiled in"); 169157207Seric #endif 169235651Seric break; 169335651Seric 16948269Seric case 'i': /* ignore dot lines in message */ 16959381Seric IgnrDot = atobool(val); 16968269Seric break; 16978269Seric 169859730Seric case 'j': /* send errors in MIME (RFC 1341) format */ 169959730Seric SendMIMEErrors = atobool(val); 170059730Seric break; 170159730Seric 170257136Seric case 'J': /* .forward search path */ 170357136Seric ForwardPath = newstr(val); 170457136Seric break; 170557136Seric 170654967Seric case 'k': /* connection cache size */ 170754967Seric MaxMciCache = atoi(val); 170856215Seric if (MaxMciCache < 0) 170956215Seric MaxMciCache = 0; 171054967Seric break; 171154967Seric 171254967Seric case 'K': /* connection cache timeout */ 171358796Seric MciCacheTimeout = convtime(val, 'm'); 171454967Seric break; 171554967Seric 171661104Seric case 'l': /* use Errors-To: header */ 171761104Seric UseErrorsTo = atobool(val); 171861104Seric break; 171961104Seric 17208256Seric case 'L': /* log level */ 172164140Seric if (safe || LogLevel < atoi(val)) 172264140Seric LogLevel = atoi(val); 17238256Seric break; 17248256Seric 17258269Seric case 'M': /* define macro */ 172668267Seric p = newstr(&val[1]); 172768267Seric if (!safe) 172868267Seric cleanstrcpy(p, p, MAXNAME); 172968267Seric define(val[0], p, CurEnv); 173016878Seric sticky = FALSE; 17318269Seric break; 17328269Seric 17338269Seric case 'm': /* send to me too */ 17349381Seric MeToo = atobool(val); 17358269Seric break; 17368269Seric 173725820Seric case 'n': /* validate RHS in newaliases */ 173825820Seric CheckAliases = atobool(val); 173925820Seric break; 174025820Seric 174161104Seric /* 'N' available -- was "net name" */ 174261104Seric 174358851Seric case 'O': /* daemon options */ 174458851Seric setdaemonoptions(val); 174558851Seric break; 174658851Seric 17478269Seric case 'o': /* assume old style headers */ 17489381Seric if (atobool(val)) 17499341Seric CurEnv->e_flags |= EF_OLDSTYLE; 17509341Seric else 17519341Seric CurEnv->e_flags &= ~EF_OLDSTYLE; 17528269Seric break; 17538269Seric 175458082Seric case 'p': /* select privacy level */ 175558082Seric p = val; 175658082Seric for (;;) 175758082Seric { 175858082Seric register struct prival *pv; 175958082Seric extern struct prival PrivacyValues[]; 176058082Seric 176158082Seric while (isascii(*p) && (isspace(*p) || ispunct(*p))) 176258082Seric p++; 176358082Seric if (*p == '\0') 176458082Seric break; 176558082Seric val = p; 176658082Seric while (isascii(*p) && isalnum(*p)) 176758082Seric p++; 176858082Seric if (*p != '\0') 176958082Seric *p++ = '\0'; 177058082Seric 177158082Seric for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 177258082Seric { 177358082Seric if (strcasecmp(val, pv->pv_name) == 0) 177458082Seric break; 177558082Seric } 177658886Seric if (pv->pv_name == NULL) 177758886Seric syserr("readcf: Op line: %s unrecognized", val); 177858082Seric PrivacyFlags |= pv->pv_flag; 177958082Seric } 178068479Seric sticky = FALSE; 178158082Seric break; 178258082Seric 178324944Seric case 'P': /* postmaster copy address for returned mail */ 178424944Seric PostMasterCopy = newstr(val); 178524944Seric break; 178624944Seric 178724944Seric case 'q': /* slope of queue only function */ 178824944Seric QueueFactor = atoi(val); 178924944Seric break; 179024944Seric 17918256Seric case 'Q': /* queue directory */ 17929381Seric if (val[0] == '\0') 17938269Seric QueueDir = "mqueue"; 17949381Seric else 17959381Seric QueueDir = newstr(val); 179658789Seric if (RealUid != 0 && !safe) 179764718Seric Warn_Q_option = TRUE; 17988256Seric break; 17998256Seric 180058148Seric case 'R': /* don't prune routes */ 180158148Seric DontPruneRoutes = atobool(val); 180258148Seric break; 180358148Seric 18048256Seric case 'r': /* read timeout */ 180568481Seric if (subopt == NULL) 180668481Seric inittimeouts(val); 180768481Seric else 180868481Seric settimeout(subopt, val); 18098256Seric break; 18108256Seric 18118256Seric case 'S': /* status file */ 18129381Seric if (val[0] == '\0') 18138269Seric StatFile = "sendmail.st"; 18149381Seric else 18159381Seric StatFile = newstr(val); 18168256Seric break; 18178256Seric 18188265Seric case 's': /* be super safe, even if expensive */ 18199381Seric SuperSafe = atobool(val); 18208256Seric break; 18218256Seric 18228256Seric case 'T': /* queue timeout */ 182358737Seric p = strchr(val, '/'); 182458737Seric if (p != NULL) 182558737Seric { 182658737Seric *p++ = '\0'; 182768481Seric settimeout("queuewarn", p); 182858737Seric } 182968481Seric settimeout("queuereturn", val); 183054967Seric break; 18318256Seric 18328265Seric case 't': /* time zone name */ 183352106Seric TimeZoneSpec = newstr(val); 18348265Seric break; 18358265Seric 183650556Seric case 'U': /* location of user database */ 183751360Seric UdbSpec = newstr(val); 183850556Seric break; 183950556Seric 18408256Seric case 'u': /* set default uid */ 184168481Seric for (p = val; *p != '\0'; p++) 184268481Seric { 184368481Seric if (*p == '.' || *p == '/' || *p == ':') 184468481Seric { 184568481Seric *p++ = '\0'; 184668481Seric break; 184768481Seric } 184868481Seric } 184964133Seric if (isascii(*val) && isdigit(*val)) 185064133Seric DefUid = atoi(val); 185164133Seric else 185264133Seric { 185364133Seric register struct passwd *pw; 185464133Seric 185564133Seric DefUid = -1; 185668693Seric pw = sm_getpwnam(val); 185764133Seric if (pw == NULL) 185864133Seric syserr("readcf: option u: unknown user %s", val); 185964133Seric else 186068481Seric { 186164133Seric DefUid = pw->pw_uid; 186268481Seric DefGid = pw->pw_gid; 186368481Seric } 186464133Seric } 186540973Sbostic setdefuser(); 18668256Seric 186768481Seric /* handle the group if it is there */ 186868481Seric if (*p == '\0') 186968481Seric break; 187068481Seric val = p; 187168481Seric goto g_opt; 187268481Seric 187358851Seric case 'V': /* fallback MX host */ 187458851Seric FallBackMX = newstr(val); 187558851Seric break; 187658851Seric 18778269Seric case 'v': /* run in verbose mode */ 18789381Seric Verbose = atobool(val); 18798256Seric break; 18808256Seric 188163837Seric case 'w': /* if we are best MX, try host directly */ 188263837Seric TryNullMXList = atobool(val); 188363837Seric break; 188461104Seric 188561104Seric /* 'W' available -- was wizard password */ 188661104Seric 188714879Seric case 'x': /* load avg at which to auto-queue msgs */ 188814879Seric QueueLA = atoi(val); 188914879Seric break; 189014879Seric 189114879Seric case 'X': /* load avg at which to auto-reject connections */ 189214879Seric RefuseLA = atoi(val); 189314879Seric break; 189414879Seric 189524981Seric case 'y': /* work recipient factor */ 189624981Seric WkRecipFact = atoi(val); 189724981Seric break; 189824981Seric 189924981Seric case 'Y': /* fork jobs during queue runs */ 190024952Seric ForkQueueRuns = atobool(val); 190124952Seric break; 190224952Seric 190324981Seric case 'z': /* work message class factor */ 190424981Seric WkClassFact = atoi(val); 190524981Seric break; 190624981Seric 190724981Seric case 'Z': /* work time factor */ 190824981Seric WkTimeFact = atoi(val); 190924981Seric break; 191024981Seric 191168481Seric case O_QUEUESORTORD: /* queue sorting order */ 191268481Seric switch (*val) 191368481Seric { 191468481Seric case 'h': /* Host first */ 191568481Seric case 'H': 191668481Seric QueueSortOrder = QS_BYHOST; 191768481Seric break; 191868481Seric 191968481Seric case 'p': /* Priority order */ 192068481Seric case 'P': 192168481Seric QueueSortOrder = QS_BYPRIORITY; 192268481Seric break; 192368481Seric 192468481Seric default: 192568481Seric syserr("Invalid queue sort order \"%s\"", val); 192668481Seric } 192768481Seric break; 192868481Seric 192969401Seric case O_HOSTSFILE: /* pathname of /etc/hosts file */ 193069401Seric HostsFile = newstr(val); 193169401Seric break; 193269401Seric 193368481Seric case O_MQA: /* minimum queue age between deliveries */ 193468481Seric MinQueueAge = convtime(val, 'm'); 193568481Seric break; 193668481Seric 193768481Seric case O_MHSA: /* maximum age of cached host status */ 193868481Seric MaxHostStatAge = convtime(val, 'm'); 193968481Seric break; 194068481Seric 194168481Seric case O_DEFCHARSET: /* default character set for mimefying */ 194268481Seric DefaultCharSet = newstr(denlstring(val, TRUE, TRUE)); 194368481Seric break; 194468481Seric 194568481Seric case O_SSFILE: /* service switch file */ 194668481Seric ServiceSwitchFile = newstr(val); 194768481Seric break; 194868481Seric 194968481Seric case O_DIALDELAY: /* delay for dial-on-demand operation */ 195068481Seric DialDelay = convtime(val, 's'); 195168481Seric break; 195268481Seric 195368481Seric case O_NORCPTACTION: /* what to do if no recipient */ 195468481Seric if (strcasecmp(val, "none") == 0) 195568481Seric NoRecipientAction = NRA_NO_ACTION; 195668481Seric else if (strcasecmp(val, "add-to") == 0) 195768481Seric NoRecipientAction = NRA_ADD_TO; 195868481Seric else if (strcasecmp(val, "add-apparently-to") == 0) 195968481Seric NoRecipientAction = NRA_ADD_APPARENTLY_TO; 196068481Seric else if (strcasecmp(val, "add-bcc") == 0) 196168481Seric NoRecipientAction = NRA_ADD_BCC; 196268481Seric else if (strcasecmp(val, "add-to-undisclosed") == 0) 196368481Seric NoRecipientAction = NRA_ADD_TO_UNDISCLOSED; 196468481Seric else 196568481Seric syserr("Invalid NoRecipientAction: %s", val); 196668481Seric 196768490Seric case O_SAFEFILEENV: /* chroot() environ for writing to files */ 196868490Seric SafeFileEnv = newstr(val); 196968490Seric break; 197068490Seric 197168569Seric case O_MAXMSGSIZE: /* maximum message size */ 197269748Seric MaxMessageSize = atol(val); 197368569Seric break; 197468569Seric 197568756Seric case O_COLONOKINADDR: /* old style handling of colon addresses */ 197669748Seric ColonOkInAddr = atobool(val); 197768756Seric break; 197868756Seric 197969724Seric case O_MAXQUEUERUN: /* max # of jobs in a single queue run */ 198069748Seric MaxQueueRun = atol(val); 198169724Seric break; 198269724Seric 198369838Seric case O_MAXCHILDREN: /* max # of children of daemon */ 198469838Seric MaxChildren = atoi(val); 1985*69852Seric break; 198669838Seric 1987*69852Seric case O_KEEPCNAMES: /* don't expand CNAME records */ 1988*69852Seric DontExpandCnames = atobool(val); 1989*69852Seric break; 1990*69852Seric 19918256Seric default: 199268481Seric if (tTd(37, 1)) 199368481Seric { 199468481Seric if (isascii(opt) && isprint(opt)) 199568481Seric printf("Warning: option %c unknown\n", opt); 199668481Seric else 199768481Seric printf("Warning: option 0x%x unknown\n", opt); 199868481Seric } 19998256Seric break; 20008256Seric } 200116878Seric if (sticky) 200216878Seric setbitn(opt, StickyOpt); 20038256Seric } 200410687Seric /* 200568481Seric ** SETCLASS -- set a string into a class 200610687Seric ** 200710687Seric ** Parameters: 200868481Seric ** class -- the class to put the string in. 200968481Seric ** str -- the string to enter 201010687Seric ** 201110687Seric ** Returns: 201210687Seric ** none. 201310687Seric ** 201410687Seric ** Side Effects: 201510687Seric ** puts the word into the symbol table. 201610687Seric */ 201710687Seric 201869748Seric void 201968481Seric setclass(class, str) 202010687Seric int class; 202168481Seric char *str; 202210687Seric { 202310687Seric register STAB *s; 202410687Seric 202557943Seric if (tTd(37, 8)) 202668481Seric printf("setclass(%c, %s)\n", class, str); 202768481Seric s = stab(str, ST_CLASS, ST_ENTER); 202810687Seric setbitn(class, s->s_class); 202910687Seric } 203053654Seric /* 203153654Seric ** MAKEMAPENTRY -- create a map entry 203253654Seric ** 203353654Seric ** Parameters: 203453654Seric ** line -- the config file line 203553654Seric ** 203653654Seric ** Returns: 203769774Seric ** A pointer to the map that has been created. 203869774Seric ** NULL if there was a syntax error. 203953654Seric ** 204053654Seric ** Side Effects: 204153654Seric ** Enters the map into the dictionary. 204253654Seric */ 204353654Seric 204469774Seric MAP * 204553654Seric makemapentry(line) 204653654Seric char *line; 204753654Seric { 204853654Seric register char *p; 204953654Seric char *mapname; 205053654Seric char *classname; 205164078Seric register STAB *s; 205253654Seric STAB *class; 205353654Seric 205458050Seric for (p = line; isascii(*p) && isspace(*p); p++) 205553654Seric continue; 205658050Seric if (!(isascii(*p) && isalnum(*p))) 205753654Seric { 205853654Seric syserr("readcf: config K line: no map name"); 205969774Seric return NULL; 206053654Seric } 206153654Seric 206253654Seric mapname = p; 206368481Seric while ((isascii(*++p) && isalnum(*p)) || *p == '.') 206453654Seric continue; 206553654Seric if (*p != '\0') 206653654Seric *p++ = '\0'; 206758050Seric while (isascii(*p) && isspace(*p)) 206853654Seric p++; 206958050Seric if (!(isascii(*p) && isalnum(*p))) 207053654Seric { 207153654Seric syserr("readcf: config K line, map %s: no map class", mapname); 207269774Seric return NULL; 207353654Seric } 207453654Seric classname = p; 207558050Seric while (isascii(*++p) && isalnum(*p)) 207653654Seric continue; 207753654Seric if (*p != '\0') 207853654Seric *p++ = '\0'; 207958050Seric while (isascii(*p) && isspace(*p)) 208053654Seric p++; 208153654Seric 208253654Seric /* look up the class */ 208353654Seric class = stab(classname, ST_MAPCLASS, ST_FIND); 208453654Seric if (class == NULL) 208553654Seric { 208653654Seric syserr("readcf: map %s: class %s not available", mapname, classname); 208769774Seric return NULL; 208853654Seric } 208953654Seric 209053654Seric /* enter the map */ 209164078Seric s = stab(mapname, ST_MAP, ST_ENTER); 209264078Seric s->s_map.map_class = &class->s_mapclass; 209364078Seric s->s_map.map_mname = newstr(mapname); 209453654Seric 209564078Seric if (class->s_mapclass.map_parse(&s->s_map, p)) 209664078Seric s->s_map.map_mflags |= MF_VALID; 209764078Seric 209864078Seric if (tTd(37, 5)) 209964078Seric { 210064078Seric printf("map %s, class %s, flags %x, file %s,\n", 210164078Seric s->s_map.map_mname, s->s_map.map_class->map_cname, 210264078Seric s->s_map.map_mflags, 210364078Seric s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 210464078Seric printf("\tapp %s, domain %s, rebuild %s\n", 210564078Seric s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 210664078Seric s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 210764078Seric s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 210864078Seric } 210969774Seric 211069774Seric return &s->s_map; 211153654Seric } 211258112Seric /* 211369783Seric ** STRTORWSET -- convert string to rewriting set number 211469783Seric ** 211569783Seric ** Parameters: 211669783Seric ** p -- the pointer to the string to decode. 211769783Seric ** endp -- if set, store the trailing delimiter here. 211869783Seric ** stabmode -- ST_ENTER to create this entry, ST_FIND if 211969783Seric ** it must already exist. 212069783Seric ** 212169783Seric ** Returns: 212269783Seric ** The appropriate ruleset number. 212369783Seric ** -1 if it is not valid (error already printed) 212469783Seric */ 212569783Seric 212669783Seric int 212769783Seric strtorwset(p, endp, stabmode) 212869783Seric char *p; 212969783Seric char **endp; 213069783Seric int stabmode; 213169783Seric { 213269783Seric int ruleset; 213369783Seric static int nextruleset = MAXRWSETS; 213469783Seric 213569783Seric while (isascii(*p) && isspace(*p)) 213669783Seric p++; 213769783Seric if (!isascii(*p)) 213869783Seric { 213969783Seric syserr("invalid ruleset name: \"%.20s\"", p); 214069783Seric return -1; 214169783Seric } 214269783Seric if (isdigit(*p)) 214369783Seric { 214469783Seric ruleset = strtol(p, endp, 10); 214569783Seric if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 214669783Seric { 214769783Seric syserr("bad ruleset %d (%d max)", 214869783Seric ruleset, MAXRWSETS / 2); 214969783Seric ruleset = -1; 215069783Seric } 215169783Seric } 215269783Seric else 215369783Seric { 215469783Seric STAB *s; 215569783Seric char delim; 215669783Seric char *q; 215769783Seric 215869783Seric q = p; 215969783Seric while (*p != '\0' && isascii(*p) && 216069783Seric (isalnum(*p) || strchr("-_$", *p) != NULL)) 216169783Seric p++; 216269783Seric while (isascii(*p) && isspace(*p)) 216369783Seric *p++ = '\0'; 216469783Seric delim = *p; 216569783Seric if (delim != '\0') 216669783Seric *p = '\0'; 216769783Seric s = stab(q, ST_RULESET, stabmode); 216869783Seric if (delim != '\0') 216969783Seric *p = delim; 217069783Seric 217169783Seric if (s == NULL) 217269783Seric { 217369783Seric syserr("unknown ruleset %s", q); 217469783Seric return -1; 217569783Seric } 217669783Seric 217769783Seric if (stabmode == ST_ENTER && delim == '=') 217869783Seric { 217969783Seric ruleset = strtol(p, endp, 10); 218069783Seric if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 218169783Seric { 218269783Seric syserr("bad ruleset %s = %d (%d max)", 218369783Seric q, ruleset, MAXRWSETS / 2); 218469783Seric ruleset = -1; 218569783Seric } 218669783Seric } 218769783Seric else 218869783Seric { 218969783Seric if (endp != NULL) 219069783Seric *endp = p; 219169783Seric if (s->s_ruleset > 0) 219269783Seric ruleset = s->s_ruleset; 219369783Seric else if ((ruleset = --nextruleset) < MAXRWSETS / 2) 219469783Seric { 219569783Seric syserr("%s: too many named rulesets (%d max)", 219669783Seric q, MAXRWSETS / 2); 219769783Seric ruleset = -1; 219869783Seric } 219969783Seric } 220069783Seric if (s->s_ruleset > 0 && ruleset >= 0 && ruleset != s->s_ruleset) 220169783Seric { 220269783Seric syserr("%s: ruleset changed value (old %d, new %d)", 220369783Seric q, ruleset, s->s_ruleset); 220469783Seric ruleset = s->s_ruleset; 220569783Seric } 220669783Seric else if (ruleset > 0) 220769783Seric { 220869783Seric s->s_ruleset = ruleset; 220969783Seric } 221069783Seric } 221169783Seric return ruleset; 221269783Seric } 221369783Seric /* 221468481Seric ** INITTIMEOUTS -- parse and set timeout values 221558112Seric ** 221658112Seric ** Parameters: 221758112Seric ** val -- a pointer to the values. If NULL, do initial 221858112Seric ** settings. 221958112Seric ** 222058112Seric ** Returns: 222158112Seric ** none. 222258112Seric ** 222358112Seric ** Side Effects: 222458112Seric ** Initializes the TimeOuts structure 222558112Seric */ 222658112Seric 222764255Seric #define SECONDS 222858112Seric #define MINUTES * 60 222958112Seric #define HOUR * 3600 223058112Seric 223169748Seric void 223268481Seric inittimeouts(val) 223358112Seric register char *val; 223458112Seric { 223558112Seric register char *p; 223658671Seric extern time_t convtime(); 223758112Seric 223858112Seric if (val == NULL) 223958112Seric { 224058112Seric TimeOuts.to_initial = (time_t) 5 MINUTES; 224158112Seric TimeOuts.to_helo = (time_t) 5 MINUTES; 224258112Seric TimeOuts.to_mail = (time_t) 10 MINUTES; 224358112Seric TimeOuts.to_rcpt = (time_t) 1 HOUR; 224458112Seric TimeOuts.to_datainit = (time_t) 5 MINUTES; 224558112Seric TimeOuts.to_datablock = (time_t) 1 HOUR; 224658112Seric TimeOuts.to_datafinal = (time_t) 1 HOUR; 224758112Seric TimeOuts.to_rset = (time_t) 5 MINUTES; 224858112Seric TimeOuts.to_quit = (time_t) 2 MINUTES; 224958112Seric TimeOuts.to_nextcommand = (time_t) 1 HOUR; 225058112Seric TimeOuts.to_miscshort = (time_t) 2 MINUTES; 225168481Seric #if IDENTPROTO 225264255Seric TimeOuts.to_ident = (time_t) 30 SECONDS; 225368481Seric #else 225468481Seric TimeOuts.to_ident = (time_t) 0 SECONDS; 225568481Seric #endif 225668481Seric TimeOuts.to_fileopen = (time_t) 60 SECONDS; 225758112Seric return; 225858112Seric } 225958112Seric 226058112Seric for (;; val = p) 226158112Seric { 226258112Seric while (isascii(*val) && isspace(*val)) 226358112Seric val++; 226458112Seric if (*val == '\0') 226558112Seric break; 226658112Seric for (p = val; *p != '\0' && *p != ','; p++) 226758112Seric continue; 226858112Seric if (*p != '\0') 226958112Seric *p++ = '\0'; 227058112Seric 227158112Seric if (isascii(*val) && isdigit(*val)) 227258112Seric { 227358112Seric /* old syntax -- set everything */ 227458796Seric TimeOuts.to_mail = convtime(val, 'm'); 227558112Seric TimeOuts.to_rcpt = TimeOuts.to_mail; 227658112Seric TimeOuts.to_datainit = TimeOuts.to_mail; 227758112Seric TimeOuts.to_datablock = TimeOuts.to_mail; 227858112Seric TimeOuts.to_datafinal = TimeOuts.to_mail; 227958112Seric TimeOuts.to_nextcommand = TimeOuts.to_mail; 228058112Seric continue; 228158112Seric } 228258112Seric else 228358112Seric { 228468481Seric register char *q = strchr(val, ':'); 228558112Seric 228668481Seric if (q == NULL && (q = strchr(val, '=')) == NULL) 228758112Seric { 228858112Seric /* syntax error */ 228958112Seric continue; 229058112Seric } 229158112Seric *q++ = '\0'; 229268481Seric settimeout(val, q); 229368481Seric } 229468481Seric } 229568481Seric } 229668481Seric /* 229768481Seric ** SETTIMEOUT -- set an individual timeout 229868481Seric ** 229968481Seric ** Parameters: 230068481Seric ** name -- the name of the timeout. 230168481Seric ** val -- the value of the timeout. 230268481Seric ** 230368481Seric ** Returns: 230468481Seric ** none. 230568481Seric */ 230658112Seric 230769748Seric void 230868481Seric settimeout(name, val) 230968481Seric char *name; 231068481Seric char *val; 231168481Seric { 231268481Seric register char *p; 231368481Seric time_t to; 231468481Seric extern time_t convtime(); 231568481Seric 231668481Seric to = convtime(val, 'm'); 231768481Seric p = strchr(name, '.'); 231868481Seric if (p != NULL) 231968481Seric *p++ = '\0'; 232068481Seric 232168481Seric if (strcasecmp(name, "initial") == 0) 232268481Seric TimeOuts.to_initial = to; 232368481Seric else if (strcasecmp(name, "mail") == 0) 232468481Seric TimeOuts.to_mail = to; 232568481Seric else if (strcasecmp(name, "rcpt") == 0) 232668481Seric TimeOuts.to_rcpt = to; 232768481Seric else if (strcasecmp(name, "datainit") == 0) 232868481Seric TimeOuts.to_datainit = to; 232968481Seric else if (strcasecmp(name, "datablock") == 0) 233068481Seric TimeOuts.to_datablock = to; 233168481Seric else if (strcasecmp(name, "datafinal") == 0) 233268481Seric TimeOuts.to_datafinal = to; 233368481Seric else if (strcasecmp(name, "command") == 0) 233468481Seric TimeOuts.to_nextcommand = to; 233568481Seric else if (strcasecmp(name, "rset") == 0) 233668481Seric TimeOuts.to_rset = to; 233768481Seric else if (strcasecmp(name, "helo") == 0) 233868481Seric TimeOuts.to_helo = to; 233968481Seric else if (strcasecmp(name, "quit") == 0) 234068481Seric TimeOuts.to_quit = to; 234168481Seric else if (strcasecmp(name, "misc") == 0) 234268481Seric TimeOuts.to_miscshort = to; 234368481Seric else if (strcasecmp(name, "ident") == 0) 234468481Seric TimeOuts.to_ident = to; 234568481Seric else if (strcasecmp(name, "fileopen") == 0) 234668481Seric TimeOuts.to_fileopen = to; 234768481Seric else if (strcasecmp(name, "queuewarn") == 0) 234868481Seric { 234968481Seric to = convtime(val, 'h'); 235068481Seric if (p == NULL || strcmp(p, "*") == 0) 235168481Seric { 235268481Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 235368481Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 235468481Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 235558112Seric } 235668481Seric else if (strcasecmp(p, "normal") == 0) 235768481Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 235868481Seric else if (strcasecmp(p, "urgent") == 0) 235968481Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 236068481Seric else if (strcasecmp(p, "non-urgent") == 0) 236168481Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 236268481Seric else 236368481Seric syserr("settimeout: invalid queuewarn subtimeout %s", p); 236458112Seric } 236568481Seric else if (strcasecmp(name, "queuereturn") == 0) 236668481Seric { 236768481Seric to = convtime(val, 'd'); 236868481Seric if (p == NULL || strcmp(p, "*") == 0) 236968481Seric { 237068481Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 237168481Seric TimeOuts.to_q_return[TOC_URGENT] = to; 237268481Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 237368481Seric } 237468481Seric else if (strcasecmp(p, "normal") == 0) 237568481Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 237668481Seric else if (strcasecmp(p, "urgent") == 0) 237768481Seric TimeOuts.to_q_return[TOC_URGENT] = to; 237868481Seric else if (strcasecmp(p, "non-urgent") == 0) 237968481Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 238068481Seric else 238168481Seric syserr("settimeout: invalid queuereturn subtimeout %s", p); 238268481Seric } 238368481Seric else 238468481Seric syserr("settimeout: invalid timeout %s", name); 238558112Seric } 2386