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*69838Seric static char sccsid[] = "@(#)readcf.c 8.100 (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, 1324*69838Seric #define O_MAXCHILDREN 0x8d 1325*69838Seric /* 1326*69838Seric "MaxDaemonChildren", O_MAXCHILDREN, FALSE, 1327*69838Seric */ 132868481Seric 132968481Seric NULL, '\0', FALSE, 133068481Seric }; 133168481Seric 133268481Seric 133368481Seric 133469748Seric void 133558734Seric setoption(opt, val, safe, sticky, e) 133669748Seric int opt; 13378256Seric char *val; 133821755Seric bool safe; 13398269Seric bool sticky; 134058734Seric register ENVELOPE *e; 13418256Seric { 134257207Seric register char *p; 134368481Seric register struct optioninfo *o; 134468481Seric char *subopt; 13458265Seric extern bool atobool(); 134612633Seric extern time_t convtime(); 134714879Seric extern int QueueLA; 134814879Seric extern int RefuseLA; 134964718Seric extern bool Warn_Q_option; 13508256Seric 135168481Seric errno = 0; 135268481Seric if (opt == ' ') 135368481Seric { 135468481Seric /* full word options */ 135568481Seric struct optioninfo *sel; 135668481Seric 135768481Seric p = strchr(val, '='); 135868481Seric if (p == NULL) 135968481Seric p = &val[strlen(val)]; 136068481Seric while (*--p == ' ') 136168481Seric continue; 136268481Seric while (*++p == ' ') 136368481Seric *p = '\0'; 136468481Seric if (p == val) 136568481Seric { 136668481Seric syserr("readcf: null option name"); 136768481Seric return; 136868481Seric } 136968481Seric if (*p == '=') 137068481Seric *p++ = '\0'; 137168481Seric while (*p == ' ') 137268481Seric p++; 137368481Seric subopt = strchr(val, '.'); 137468481Seric if (subopt != NULL) 137568481Seric *subopt++ = '\0'; 137668481Seric sel = NULL; 137768481Seric for (o = OptionTab; o->o_name != NULL; o++) 137868481Seric { 137968481Seric if (strncasecmp(o->o_name, val, strlen(val)) != 0) 138068481Seric continue; 138168481Seric if (strlen(o->o_name) == strlen(val)) 138268481Seric { 138368481Seric /* completely specified -- this must be it */ 138468481Seric sel = NULL; 138568481Seric break; 138668481Seric } 138768481Seric if (sel != NULL) 138868481Seric break; 138968481Seric sel = o; 139068481Seric } 139168481Seric if (sel != NULL && o->o_name == NULL) 139268481Seric o = sel; 139368481Seric else if (o->o_name == NULL) 139468481Seric { 139568481Seric syserr("readcf: unknown option name %s", val); 139668481Seric return; 139768481Seric } 139868481Seric else if (sel != NULL) 139968481Seric { 140068481Seric syserr("readcf: ambiguous option name %s (matches %s and %s)", 140168481Seric val, sel->o_name, o->o_name); 140268481Seric return; 140368481Seric } 140468481Seric if (strlen(val) != strlen(o->o_name)) 140568481Seric { 140668481Seric bool oldVerbose = Verbose; 140768481Seric 140868481Seric Verbose = TRUE; 140968481Seric message("Option %s used as abbreviation for %s", 141068481Seric val, o->o_name); 141168481Seric Verbose = oldVerbose; 141268481Seric } 141368481Seric opt = o->o_code; 141468481Seric val = p; 141568481Seric } 141668481Seric else 141768481Seric { 141868481Seric for (o = OptionTab; o->o_name != NULL; o++) 141968481Seric { 142068481Seric if (o->o_code == opt) 142168481Seric break; 142268481Seric } 142368481Seric subopt = NULL; 142468481Seric } 142568481Seric 14268256Seric if (tTd(37, 1)) 142768481Seric { 142868481Seric printf(isascii(opt) && isprint(opt) ? 142968481Seric "setoption %s (%c).%s=%s" : 143068481Seric "setoption %s (0x%x).%s=%s", 143168481Seric o->o_name == NULL ? "<unknown>" : o->o_name, 143268481Seric opt, 143368481Seric subopt == NULL ? "" : subopt, 143468481Seric val); 143568481Seric } 14368256Seric 14378256Seric /* 14388269Seric ** See if this option is preset for us. 14398256Seric */ 14408256Seric 144159731Seric if (!sticky && bitnset(opt, StickyOpt)) 14428269Seric { 14439341Seric if (tTd(37, 1)) 14449341Seric printf(" (ignored)\n"); 14458269Seric return; 14468269Seric } 14478269Seric 144821755Seric /* 144921755Seric ** Check to see if this option can be specified by this user. 145021755Seric */ 145121755Seric 145263787Seric if (!safe && RealUid == 0) 145321755Seric safe = TRUE; 145468481Seric if (!safe && !o->o_safe) 145521755Seric { 145639111Srick if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 145721755Seric { 145836582Sbostic if (tTd(37, 1)) 145936582Sbostic printf(" (unsafe)"); 146063787Seric if (RealUid != geteuid()) 146136582Sbostic { 146251210Seric if (tTd(37, 1)) 146351210Seric printf("(Resetting uid)"); 146463787Seric (void) setgid(RealGid); 146563787Seric (void) setuid(RealUid); 146636582Sbostic } 146721755Seric } 146821755Seric } 146951210Seric if (tTd(37, 1)) 147017985Seric printf("\n"); 14718269Seric 147268481Seric switch (opt & 0xff) 14738256Seric { 147459709Seric case '7': /* force seven-bit input */ 147568481Seric SevenBitInput = atobool(val); 147652106Seric break; 147752106Seric 147869480Seric #if MIME8TO7 147968481Seric case '8': /* handling of 8-bit input */ 148068481Seric switch (*val) 148168481Seric { 148268481Seric case 'm': /* convert 8-bit, convert MIME */ 148368481Seric MimeMode = MM_CVTMIME|MM_MIME8BIT; 148468481Seric break; 148568481Seric 148668481Seric case 'p': /* pass 8 bit, convert MIME */ 148768856Seric MimeMode = MM_CVTMIME|MM_PASS8BIT; 148868481Seric break; 148968481Seric 149068481Seric case 's': /* strict adherence */ 149168481Seric MimeMode = MM_CVTMIME; 149268481Seric break; 149368481Seric 149468856Seric #if 0 149568856Seric case 'r': /* reject 8-bit, don't convert MIME */ 149668856Seric MimeMode = 0; 149768856Seric break; 149868856Seric 149968856Seric case 'j': /* "just send 8" */ 150068856Seric MimeMode = MM_PASS8BIT; 150168856Seric break; 150268856Seric 150368481Seric case 'a': /* encode 8 bit if available */ 150468481Seric MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 150568481Seric break; 150668481Seric 150768481Seric case 'c': /* convert 8 bit to MIME, never 7 bit */ 150868481Seric MimeMode = MM_MIME8BIT; 150968481Seric break; 151068856Seric #endif 151168481Seric 151268481Seric default: 151368481Seric syserr("Unknown 8-bit mode %c", *val); 151468481Seric exit(EX_USAGE); 151568481Seric } 151668481Seric break; 151769480Seric #endif 151868481Seric 15198256Seric case 'A': /* set default alias file */ 15209381Seric if (val[0] == '\0') 152159672Seric setalias("aliases"); 15229381Seric else 152359672Seric setalias(val); 15248256Seric break; 15258256Seric 152617474Seric case 'a': /* look N minutes for "@:@" in alias file */ 152717474Seric if (val[0] == '\0') 152864796Seric SafeAlias = 5 * 60; /* five minutes */ 152917474Seric else 153064796Seric SafeAlias = convtime(val, 'm'); 153117474Seric break; 153217474Seric 153316843Seric case 'B': /* substitution for blank character */ 153416843Seric SpaceSub = val[0]; 153516843Seric if (SpaceSub == '\0') 153616843Seric SpaceSub = ' '; 153716843Seric break; 153816843Seric 153959283Seric case 'b': /* min blocks free on queue fs/max msg size */ 154059283Seric p = strchr(val, '/'); 154159283Seric if (p != NULL) 154259283Seric { 154359283Seric *p++ = '\0'; 154459283Seric MaxMessageSize = atol(p); 154559283Seric } 154658082Seric MinBlocksFree = atol(val); 154758082Seric break; 154858082Seric 15499284Seric case 'c': /* don't connect to "expensive" mailers */ 15509381Seric NoConnect = atobool(val); 15519284Seric break; 15529284Seric 155351305Seric case 'C': /* checkpoint every N addresses */ 155451305Seric CheckpointInterval = atoi(val); 155524944Seric break; 155624944Seric 15579284Seric case 'd': /* delivery mode */ 15589284Seric switch (*val) 15598269Seric { 15609284Seric case '\0': 156158734Seric e->e_sendmode = SM_DELIVER; 15628269Seric break; 15638269Seric 156410755Seric case SM_QUEUE: /* queue only */ 156510755Seric #ifndef QUEUE 156610755Seric syserr("need QUEUE to set -odqueue"); 156756795Seric #endif /* QUEUE */ 156810755Seric /* fall through..... */ 156910755Seric 15709284Seric case SM_DELIVER: /* do everything */ 15719284Seric case SM_FORK: /* fork after verification */ 157258734Seric e->e_sendmode = *val; 15738269Seric break; 15748269Seric 15758269Seric default: 15769284Seric syserr("Unknown delivery mode %c", *val); 15778269Seric exit(EX_USAGE); 15788269Seric } 15798269Seric break; 15808269Seric 15819146Seric case 'D': /* rebuild alias database as needed */ 15829381Seric AutoRebuild = atobool(val); 15839146Seric break; 15849146Seric 158555372Seric case 'E': /* error message header/header file */ 158655379Seric if (*val != '\0') 158755379Seric ErrMsgFile = newstr(val); 158855372Seric break; 158955372Seric 15908269Seric case 'e': /* set error processing mode */ 15918269Seric switch (*val) 15928269Seric { 15939381Seric case EM_QUIET: /* be silent about it */ 15949381Seric case EM_MAIL: /* mail back */ 15959381Seric case EM_BERKNET: /* do berknet error processing */ 15969381Seric case EM_WRITE: /* write back (or mail) */ 15979381Seric case EM_PRINT: /* print errors normally (default) */ 159858734Seric e->e_errormode = *val; 15998269Seric break; 16008269Seric } 16018269Seric break; 16028269Seric 16039049Seric case 'F': /* file mode */ 160417975Seric FileMode = atooct(val) & 0777; 16059049Seric break; 16069049Seric 16078269Seric case 'f': /* save Unix-style From lines on front */ 16089381Seric SaveFrom = atobool(val); 16098269Seric break; 16108269Seric 161153735Seric case 'G': /* match recipients against GECOS field */ 161253735Seric MatchGecos = atobool(val); 161353735Seric break; 161453735Seric 16158256Seric case 'g': /* default gid */ 161668481Seric g_opt: 161764133Seric if (isascii(*val) && isdigit(*val)) 161864133Seric DefGid = atoi(val); 161964133Seric else 162064133Seric { 162164133Seric register struct group *gr; 162264133Seric 162364133Seric DefGid = -1; 162464133Seric gr = getgrnam(val); 162564133Seric if (gr == NULL) 162668481Seric syserr("readcf: option %c: unknown group %s", 162768481Seric opt, val); 162864133Seric else 162964133Seric DefGid = gr->gr_gid; 163064133Seric } 16318256Seric break; 16328256Seric 16338256Seric case 'H': /* help file */ 16349381Seric if (val[0] == '\0') 16358269Seric HelpFile = "sendmail.hf"; 16369381Seric else 16379381Seric HelpFile = newstr(val); 16388256Seric break; 16398256Seric 164051305Seric case 'h': /* maximum hop count */ 164151305Seric MaxHopCount = atoi(val); 164251305Seric break; 164351305Seric 164435651Seric case 'I': /* use internet domain name server */ 164566334Seric #if NAMED_BIND 164657207Seric for (p = val; *p != 0; ) 164757207Seric { 164857207Seric bool clearmode; 164957207Seric char *q; 165057207Seric struct resolverflags *rfp; 165157207Seric 165257207Seric while (*p == ' ') 165357207Seric p++; 165457207Seric if (*p == '\0') 165557207Seric break; 165657207Seric clearmode = FALSE; 165757207Seric if (*p == '-') 165857207Seric clearmode = TRUE; 165957207Seric else if (*p != '+') 166057207Seric p--; 166157207Seric p++; 166257207Seric q = p; 166358050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 166457207Seric p++; 166557207Seric if (*p != '\0') 166657207Seric *p++ = '\0'; 166768759Seric if (strcasecmp(q, "HasWildcardMX") == 0) 166868759Seric { 166968759Seric NoMXforCanon = !clearmode; 167068759Seric continue; 167168759Seric } 167257207Seric for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 167357207Seric { 167457207Seric if (strcasecmp(q, rfp->rf_name) == 0) 167557207Seric break; 167657207Seric } 167764923Seric if (rfp->rf_name == NULL) 167864923Seric syserr("readcf: I option value %s unrecognized", q); 167964923Seric else if (clearmode) 168057207Seric _res.options &= ~rfp->rf_bits; 168157207Seric else 168257207Seric _res.options |= rfp->rf_bits; 168357207Seric } 168457207Seric if (tTd(8, 2)) 168568759Seric printf("_res.options = %x, HasWildcardMX = %d\n", 168668759Seric _res.options, !NoMXforCanon); 168757207Seric #else 168857207Seric usrerr("name server (I option) specified but BIND not compiled in"); 168957207Seric #endif 169035651Seric break; 169135651Seric 16928269Seric case 'i': /* ignore dot lines in message */ 16939381Seric IgnrDot = atobool(val); 16948269Seric break; 16958269Seric 169659730Seric case 'j': /* send errors in MIME (RFC 1341) format */ 169759730Seric SendMIMEErrors = atobool(val); 169859730Seric break; 169959730Seric 170057136Seric case 'J': /* .forward search path */ 170157136Seric ForwardPath = newstr(val); 170257136Seric break; 170357136Seric 170454967Seric case 'k': /* connection cache size */ 170554967Seric MaxMciCache = atoi(val); 170656215Seric if (MaxMciCache < 0) 170756215Seric MaxMciCache = 0; 170854967Seric break; 170954967Seric 171054967Seric case 'K': /* connection cache timeout */ 171158796Seric MciCacheTimeout = convtime(val, 'm'); 171254967Seric break; 171354967Seric 171461104Seric case 'l': /* use Errors-To: header */ 171561104Seric UseErrorsTo = atobool(val); 171661104Seric break; 171761104Seric 17188256Seric case 'L': /* log level */ 171964140Seric if (safe || LogLevel < atoi(val)) 172064140Seric LogLevel = atoi(val); 17218256Seric break; 17228256Seric 17238269Seric case 'M': /* define macro */ 172468267Seric p = newstr(&val[1]); 172568267Seric if (!safe) 172668267Seric cleanstrcpy(p, p, MAXNAME); 172768267Seric define(val[0], p, CurEnv); 172816878Seric sticky = FALSE; 17298269Seric break; 17308269Seric 17318269Seric case 'm': /* send to me too */ 17329381Seric MeToo = atobool(val); 17338269Seric break; 17348269Seric 173525820Seric case 'n': /* validate RHS in newaliases */ 173625820Seric CheckAliases = atobool(val); 173725820Seric break; 173825820Seric 173961104Seric /* 'N' available -- was "net name" */ 174061104Seric 174158851Seric case 'O': /* daemon options */ 174258851Seric setdaemonoptions(val); 174358851Seric break; 174458851Seric 17458269Seric case 'o': /* assume old style headers */ 17469381Seric if (atobool(val)) 17479341Seric CurEnv->e_flags |= EF_OLDSTYLE; 17489341Seric else 17499341Seric CurEnv->e_flags &= ~EF_OLDSTYLE; 17508269Seric break; 17518269Seric 175258082Seric case 'p': /* select privacy level */ 175358082Seric p = val; 175458082Seric for (;;) 175558082Seric { 175658082Seric register struct prival *pv; 175758082Seric extern struct prival PrivacyValues[]; 175858082Seric 175958082Seric while (isascii(*p) && (isspace(*p) || ispunct(*p))) 176058082Seric p++; 176158082Seric if (*p == '\0') 176258082Seric break; 176358082Seric val = p; 176458082Seric while (isascii(*p) && isalnum(*p)) 176558082Seric p++; 176658082Seric if (*p != '\0') 176758082Seric *p++ = '\0'; 176858082Seric 176958082Seric for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 177058082Seric { 177158082Seric if (strcasecmp(val, pv->pv_name) == 0) 177258082Seric break; 177358082Seric } 177458886Seric if (pv->pv_name == NULL) 177558886Seric syserr("readcf: Op line: %s unrecognized", val); 177658082Seric PrivacyFlags |= pv->pv_flag; 177758082Seric } 177868479Seric sticky = FALSE; 177958082Seric break; 178058082Seric 178124944Seric case 'P': /* postmaster copy address for returned mail */ 178224944Seric PostMasterCopy = newstr(val); 178324944Seric break; 178424944Seric 178524944Seric case 'q': /* slope of queue only function */ 178624944Seric QueueFactor = atoi(val); 178724944Seric break; 178824944Seric 17898256Seric case 'Q': /* queue directory */ 17909381Seric if (val[0] == '\0') 17918269Seric QueueDir = "mqueue"; 17929381Seric else 17939381Seric QueueDir = newstr(val); 179458789Seric if (RealUid != 0 && !safe) 179564718Seric Warn_Q_option = TRUE; 17968256Seric break; 17978256Seric 179858148Seric case 'R': /* don't prune routes */ 179958148Seric DontPruneRoutes = atobool(val); 180058148Seric break; 180158148Seric 18028256Seric case 'r': /* read timeout */ 180368481Seric if (subopt == NULL) 180468481Seric inittimeouts(val); 180568481Seric else 180668481Seric settimeout(subopt, val); 18078256Seric break; 18088256Seric 18098256Seric case 'S': /* status file */ 18109381Seric if (val[0] == '\0') 18118269Seric StatFile = "sendmail.st"; 18129381Seric else 18139381Seric StatFile = newstr(val); 18148256Seric break; 18158256Seric 18168265Seric case 's': /* be super safe, even if expensive */ 18179381Seric SuperSafe = atobool(val); 18188256Seric break; 18198256Seric 18208256Seric case 'T': /* queue timeout */ 182158737Seric p = strchr(val, '/'); 182258737Seric if (p != NULL) 182358737Seric { 182458737Seric *p++ = '\0'; 182568481Seric settimeout("queuewarn", p); 182658737Seric } 182768481Seric settimeout("queuereturn", val); 182854967Seric break; 18298256Seric 18308265Seric case 't': /* time zone name */ 183152106Seric TimeZoneSpec = newstr(val); 18328265Seric break; 18338265Seric 183450556Seric case 'U': /* location of user database */ 183551360Seric UdbSpec = newstr(val); 183650556Seric break; 183750556Seric 18388256Seric case 'u': /* set default uid */ 183968481Seric for (p = val; *p != '\0'; p++) 184068481Seric { 184168481Seric if (*p == '.' || *p == '/' || *p == ':') 184268481Seric { 184368481Seric *p++ = '\0'; 184468481Seric break; 184568481Seric } 184668481Seric } 184764133Seric if (isascii(*val) && isdigit(*val)) 184864133Seric DefUid = atoi(val); 184964133Seric else 185064133Seric { 185164133Seric register struct passwd *pw; 185264133Seric 185364133Seric DefUid = -1; 185468693Seric pw = sm_getpwnam(val); 185564133Seric if (pw == NULL) 185664133Seric syserr("readcf: option u: unknown user %s", val); 185764133Seric else 185868481Seric { 185964133Seric DefUid = pw->pw_uid; 186068481Seric DefGid = pw->pw_gid; 186168481Seric } 186264133Seric } 186340973Sbostic setdefuser(); 18648256Seric 186568481Seric /* handle the group if it is there */ 186668481Seric if (*p == '\0') 186768481Seric break; 186868481Seric val = p; 186968481Seric goto g_opt; 187068481Seric 187158851Seric case 'V': /* fallback MX host */ 187258851Seric FallBackMX = newstr(val); 187358851Seric break; 187458851Seric 18758269Seric case 'v': /* run in verbose mode */ 18769381Seric Verbose = atobool(val); 18778256Seric break; 18788256Seric 187963837Seric case 'w': /* if we are best MX, try host directly */ 188063837Seric TryNullMXList = atobool(val); 188163837Seric break; 188261104Seric 188361104Seric /* 'W' available -- was wizard password */ 188461104Seric 188514879Seric case 'x': /* load avg at which to auto-queue msgs */ 188614879Seric QueueLA = atoi(val); 188714879Seric break; 188814879Seric 188914879Seric case 'X': /* load avg at which to auto-reject connections */ 189014879Seric RefuseLA = atoi(val); 189114879Seric break; 189214879Seric 189324981Seric case 'y': /* work recipient factor */ 189424981Seric WkRecipFact = atoi(val); 189524981Seric break; 189624981Seric 189724981Seric case 'Y': /* fork jobs during queue runs */ 189824952Seric ForkQueueRuns = atobool(val); 189924952Seric break; 190024952Seric 190124981Seric case 'z': /* work message class factor */ 190224981Seric WkClassFact = atoi(val); 190324981Seric break; 190424981Seric 190524981Seric case 'Z': /* work time factor */ 190624981Seric WkTimeFact = atoi(val); 190724981Seric break; 190824981Seric 190968481Seric case O_QUEUESORTORD: /* queue sorting order */ 191068481Seric switch (*val) 191168481Seric { 191268481Seric case 'h': /* Host first */ 191368481Seric case 'H': 191468481Seric QueueSortOrder = QS_BYHOST; 191568481Seric break; 191668481Seric 191768481Seric case 'p': /* Priority order */ 191868481Seric case 'P': 191968481Seric QueueSortOrder = QS_BYPRIORITY; 192068481Seric break; 192168481Seric 192268481Seric default: 192368481Seric syserr("Invalid queue sort order \"%s\"", val); 192468481Seric } 192568481Seric break; 192668481Seric 192769401Seric case O_HOSTSFILE: /* pathname of /etc/hosts file */ 192869401Seric HostsFile = newstr(val); 192969401Seric break; 193069401Seric 193168481Seric case O_MQA: /* minimum queue age between deliveries */ 193268481Seric MinQueueAge = convtime(val, 'm'); 193368481Seric break; 193468481Seric 193568481Seric case O_MHSA: /* maximum age of cached host status */ 193668481Seric MaxHostStatAge = convtime(val, 'm'); 193768481Seric break; 193868481Seric 193968481Seric case O_DEFCHARSET: /* default character set for mimefying */ 194068481Seric DefaultCharSet = newstr(denlstring(val, TRUE, TRUE)); 194168481Seric break; 194268481Seric 194368481Seric case O_SSFILE: /* service switch file */ 194468481Seric ServiceSwitchFile = newstr(val); 194568481Seric break; 194668481Seric 194768481Seric case O_DIALDELAY: /* delay for dial-on-demand operation */ 194868481Seric DialDelay = convtime(val, 's'); 194968481Seric break; 195068481Seric 195168481Seric case O_NORCPTACTION: /* what to do if no recipient */ 195268481Seric if (strcasecmp(val, "none") == 0) 195368481Seric NoRecipientAction = NRA_NO_ACTION; 195468481Seric else if (strcasecmp(val, "add-to") == 0) 195568481Seric NoRecipientAction = NRA_ADD_TO; 195668481Seric else if (strcasecmp(val, "add-apparently-to") == 0) 195768481Seric NoRecipientAction = NRA_ADD_APPARENTLY_TO; 195868481Seric else if (strcasecmp(val, "add-bcc") == 0) 195968481Seric NoRecipientAction = NRA_ADD_BCC; 196068481Seric else if (strcasecmp(val, "add-to-undisclosed") == 0) 196168481Seric NoRecipientAction = NRA_ADD_TO_UNDISCLOSED; 196268481Seric else 196368481Seric syserr("Invalid NoRecipientAction: %s", val); 196468481Seric 196568490Seric case O_SAFEFILEENV: /* chroot() environ for writing to files */ 196668490Seric SafeFileEnv = newstr(val); 196768490Seric break; 196868490Seric 196968569Seric case O_MAXMSGSIZE: /* maximum message size */ 197069748Seric MaxMessageSize = atol(val); 197168569Seric break; 197268569Seric 197368756Seric case O_COLONOKINADDR: /* old style handling of colon addresses */ 197469748Seric ColonOkInAddr = atobool(val); 197568756Seric break; 197668756Seric 197769724Seric case O_MAXQUEUERUN: /* max # of jobs in a single queue run */ 197869748Seric MaxQueueRun = atol(val); 197969724Seric break; 198069724Seric 1981*69838Seric case O_MAXCHILDREN: /* max # of children of daemon */ 1982*69838Seric MaxChildren = atoi(val); 1983*69838Seric 19848256Seric default: 198568481Seric if (tTd(37, 1)) 198668481Seric { 198768481Seric if (isascii(opt) && isprint(opt)) 198868481Seric printf("Warning: option %c unknown\n", opt); 198968481Seric else 199068481Seric printf("Warning: option 0x%x unknown\n", opt); 199168481Seric } 19928256Seric break; 19938256Seric } 199416878Seric if (sticky) 199516878Seric setbitn(opt, StickyOpt); 19968256Seric } 199710687Seric /* 199868481Seric ** SETCLASS -- set a string into a class 199910687Seric ** 200010687Seric ** Parameters: 200168481Seric ** class -- the class to put the string in. 200268481Seric ** str -- the string to enter 200310687Seric ** 200410687Seric ** Returns: 200510687Seric ** none. 200610687Seric ** 200710687Seric ** Side Effects: 200810687Seric ** puts the word into the symbol table. 200910687Seric */ 201010687Seric 201169748Seric void 201268481Seric setclass(class, str) 201310687Seric int class; 201468481Seric char *str; 201510687Seric { 201610687Seric register STAB *s; 201710687Seric 201857943Seric if (tTd(37, 8)) 201968481Seric printf("setclass(%c, %s)\n", class, str); 202068481Seric s = stab(str, ST_CLASS, ST_ENTER); 202110687Seric setbitn(class, s->s_class); 202210687Seric } 202353654Seric /* 202453654Seric ** MAKEMAPENTRY -- create a map entry 202553654Seric ** 202653654Seric ** Parameters: 202753654Seric ** line -- the config file line 202853654Seric ** 202953654Seric ** Returns: 203069774Seric ** A pointer to the map that has been created. 203169774Seric ** NULL if there was a syntax error. 203253654Seric ** 203353654Seric ** Side Effects: 203453654Seric ** Enters the map into the dictionary. 203553654Seric */ 203653654Seric 203769774Seric MAP * 203853654Seric makemapentry(line) 203953654Seric char *line; 204053654Seric { 204153654Seric register char *p; 204253654Seric char *mapname; 204353654Seric char *classname; 204464078Seric register STAB *s; 204553654Seric STAB *class; 204653654Seric 204758050Seric for (p = line; isascii(*p) && isspace(*p); p++) 204853654Seric continue; 204958050Seric if (!(isascii(*p) && isalnum(*p))) 205053654Seric { 205153654Seric syserr("readcf: config K line: no map name"); 205269774Seric return NULL; 205353654Seric } 205453654Seric 205553654Seric mapname = p; 205668481Seric while ((isascii(*++p) && isalnum(*p)) || *p == '.') 205753654Seric continue; 205853654Seric if (*p != '\0') 205953654Seric *p++ = '\0'; 206058050Seric while (isascii(*p) && isspace(*p)) 206153654Seric p++; 206258050Seric if (!(isascii(*p) && isalnum(*p))) 206353654Seric { 206453654Seric syserr("readcf: config K line, map %s: no map class", mapname); 206569774Seric return NULL; 206653654Seric } 206753654Seric classname = p; 206858050Seric while (isascii(*++p) && isalnum(*p)) 206953654Seric continue; 207053654Seric if (*p != '\0') 207153654Seric *p++ = '\0'; 207258050Seric while (isascii(*p) && isspace(*p)) 207353654Seric p++; 207453654Seric 207553654Seric /* look up the class */ 207653654Seric class = stab(classname, ST_MAPCLASS, ST_FIND); 207753654Seric if (class == NULL) 207853654Seric { 207953654Seric syserr("readcf: map %s: class %s not available", mapname, classname); 208069774Seric return NULL; 208153654Seric } 208253654Seric 208353654Seric /* enter the map */ 208464078Seric s = stab(mapname, ST_MAP, ST_ENTER); 208564078Seric s->s_map.map_class = &class->s_mapclass; 208664078Seric s->s_map.map_mname = newstr(mapname); 208753654Seric 208864078Seric if (class->s_mapclass.map_parse(&s->s_map, p)) 208964078Seric s->s_map.map_mflags |= MF_VALID; 209064078Seric 209164078Seric if (tTd(37, 5)) 209264078Seric { 209364078Seric printf("map %s, class %s, flags %x, file %s,\n", 209464078Seric s->s_map.map_mname, s->s_map.map_class->map_cname, 209564078Seric s->s_map.map_mflags, 209664078Seric s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 209764078Seric printf("\tapp %s, domain %s, rebuild %s\n", 209864078Seric s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 209964078Seric s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 210064078Seric s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 210164078Seric } 210269774Seric 210369774Seric return &s->s_map; 210453654Seric } 210558112Seric /* 210669783Seric ** STRTORWSET -- convert string to rewriting set number 210769783Seric ** 210869783Seric ** Parameters: 210969783Seric ** p -- the pointer to the string to decode. 211069783Seric ** endp -- if set, store the trailing delimiter here. 211169783Seric ** stabmode -- ST_ENTER to create this entry, ST_FIND if 211269783Seric ** it must already exist. 211369783Seric ** 211469783Seric ** Returns: 211569783Seric ** The appropriate ruleset number. 211669783Seric ** -1 if it is not valid (error already printed) 211769783Seric */ 211869783Seric 211969783Seric int 212069783Seric strtorwset(p, endp, stabmode) 212169783Seric char *p; 212269783Seric char **endp; 212369783Seric int stabmode; 212469783Seric { 212569783Seric int ruleset; 212669783Seric static int nextruleset = MAXRWSETS; 212769783Seric 212869783Seric while (isascii(*p) && isspace(*p)) 212969783Seric p++; 213069783Seric if (!isascii(*p)) 213169783Seric { 213269783Seric syserr("invalid ruleset name: \"%.20s\"", p); 213369783Seric return -1; 213469783Seric } 213569783Seric if (isdigit(*p)) 213669783Seric { 213769783Seric ruleset = strtol(p, endp, 10); 213869783Seric if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 213969783Seric { 214069783Seric syserr("bad ruleset %d (%d max)", 214169783Seric ruleset, MAXRWSETS / 2); 214269783Seric ruleset = -1; 214369783Seric } 214469783Seric } 214569783Seric else 214669783Seric { 214769783Seric STAB *s; 214869783Seric char delim; 214969783Seric char *q; 215069783Seric 215169783Seric q = p; 215269783Seric while (*p != '\0' && isascii(*p) && 215369783Seric (isalnum(*p) || strchr("-_$", *p) != NULL)) 215469783Seric p++; 215569783Seric while (isascii(*p) && isspace(*p)) 215669783Seric *p++ = '\0'; 215769783Seric delim = *p; 215869783Seric if (delim != '\0') 215969783Seric *p = '\0'; 216069783Seric s = stab(q, ST_RULESET, stabmode); 216169783Seric if (delim != '\0') 216269783Seric *p = delim; 216369783Seric 216469783Seric if (s == NULL) 216569783Seric { 216669783Seric syserr("unknown ruleset %s", q); 216769783Seric return -1; 216869783Seric } 216969783Seric 217069783Seric if (stabmode == ST_ENTER && delim == '=') 217169783Seric { 217269783Seric ruleset = strtol(p, endp, 10); 217369783Seric if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 217469783Seric { 217569783Seric syserr("bad ruleset %s = %d (%d max)", 217669783Seric q, ruleset, MAXRWSETS / 2); 217769783Seric ruleset = -1; 217869783Seric } 217969783Seric } 218069783Seric else 218169783Seric { 218269783Seric if (endp != NULL) 218369783Seric *endp = p; 218469783Seric if (s->s_ruleset > 0) 218569783Seric ruleset = s->s_ruleset; 218669783Seric else if ((ruleset = --nextruleset) < MAXRWSETS / 2) 218769783Seric { 218869783Seric syserr("%s: too many named rulesets (%d max)", 218969783Seric q, MAXRWSETS / 2); 219069783Seric ruleset = -1; 219169783Seric } 219269783Seric } 219369783Seric if (s->s_ruleset > 0 && ruleset >= 0 && ruleset != s->s_ruleset) 219469783Seric { 219569783Seric syserr("%s: ruleset changed value (old %d, new %d)", 219669783Seric q, ruleset, s->s_ruleset); 219769783Seric ruleset = s->s_ruleset; 219869783Seric } 219969783Seric else if (ruleset > 0) 220069783Seric { 220169783Seric s->s_ruleset = ruleset; 220269783Seric } 220369783Seric } 220469783Seric return ruleset; 220569783Seric } 220669783Seric /* 220768481Seric ** INITTIMEOUTS -- parse and set timeout values 220858112Seric ** 220958112Seric ** Parameters: 221058112Seric ** val -- a pointer to the values. If NULL, do initial 221158112Seric ** settings. 221258112Seric ** 221358112Seric ** Returns: 221458112Seric ** none. 221558112Seric ** 221658112Seric ** Side Effects: 221758112Seric ** Initializes the TimeOuts structure 221858112Seric */ 221958112Seric 222064255Seric #define SECONDS 222158112Seric #define MINUTES * 60 222258112Seric #define HOUR * 3600 222358112Seric 222469748Seric void 222568481Seric inittimeouts(val) 222658112Seric register char *val; 222758112Seric { 222858112Seric register char *p; 222958671Seric extern time_t convtime(); 223058112Seric 223158112Seric if (val == NULL) 223258112Seric { 223358112Seric TimeOuts.to_initial = (time_t) 5 MINUTES; 223458112Seric TimeOuts.to_helo = (time_t) 5 MINUTES; 223558112Seric TimeOuts.to_mail = (time_t) 10 MINUTES; 223658112Seric TimeOuts.to_rcpt = (time_t) 1 HOUR; 223758112Seric TimeOuts.to_datainit = (time_t) 5 MINUTES; 223858112Seric TimeOuts.to_datablock = (time_t) 1 HOUR; 223958112Seric TimeOuts.to_datafinal = (time_t) 1 HOUR; 224058112Seric TimeOuts.to_rset = (time_t) 5 MINUTES; 224158112Seric TimeOuts.to_quit = (time_t) 2 MINUTES; 224258112Seric TimeOuts.to_nextcommand = (time_t) 1 HOUR; 224358112Seric TimeOuts.to_miscshort = (time_t) 2 MINUTES; 224468481Seric #if IDENTPROTO 224564255Seric TimeOuts.to_ident = (time_t) 30 SECONDS; 224668481Seric #else 224768481Seric TimeOuts.to_ident = (time_t) 0 SECONDS; 224868481Seric #endif 224968481Seric TimeOuts.to_fileopen = (time_t) 60 SECONDS; 225058112Seric return; 225158112Seric } 225258112Seric 225358112Seric for (;; val = p) 225458112Seric { 225558112Seric while (isascii(*val) && isspace(*val)) 225658112Seric val++; 225758112Seric if (*val == '\0') 225858112Seric break; 225958112Seric for (p = val; *p != '\0' && *p != ','; p++) 226058112Seric continue; 226158112Seric if (*p != '\0') 226258112Seric *p++ = '\0'; 226358112Seric 226458112Seric if (isascii(*val) && isdigit(*val)) 226558112Seric { 226658112Seric /* old syntax -- set everything */ 226758796Seric TimeOuts.to_mail = convtime(val, 'm'); 226858112Seric TimeOuts.to_rcpt = TimeOuts.to_mail; 226958112Seric TimeOuts.to_datainit = TimeOuts.to_mail; 227058112Seric TimeOuts.to_datablock = TimeOuts.to_mail; 227158112Seric TimeOuts.to_datafinal = TimeOuts.to_mail; 227258112Seric TimeOuts.to_nextcommand = TimeOuts.to_mail; 227358112Seric continue; 227458112Seric } 227558112Seric else 227658112Seric { 227768481Seric register char *q = strchr(val, ':'); 227858112Seric 227968481Seric if (q == NULL && (q = strchr(val, '=')) == NULL) 228058112Seric { 228158112Seric /* syntax error */ 228258112Seric continue; 228358112Seric } 228458112Seric *q++ = '\0'; 228568481Seric settimeout(val, q); 228668481Seric } 228768481Seric } 228868481Seric } 228968481Seric /* 229068481Seric ** SETTIMEOUT -- set an individual timeout 229168481Seric ** 229268481Seric ** Parameters: 229368481Seric ** name -- the name of the timeout. 229468481Seric ** val -- the value of the timeout. 229568481Seric ** 229668481Seric ** Returns: 229768481Seric ** none. 229868481Seric */ 229958112Seric 230069748Seric void 230168481Seric settimeout(name, val) 230268481Seric char *name; 230368481Seric char *val; 230468481Seric { 230568481Seric register char *p; 230668481Seric time_t to; 230768481Seric extern time_t convtime(); 230868481Seric 230968481Seric to = convtime(val, 'm'); 231068481Seric p = strchr(name, '.'); 231168481Seric if (p != NULL) 231268481Seric *p++ = '\0'; 231368481Seric 231468481Seric if (strcasecmp(name, "initial") == 0) 231568481Seric TimeOuts.to_initial = to; 231668481Seric else if (strcasecmp(name, "mail") == 0) 231768481Seric TimeOuts.to_mail = to; 231868481Seric else if (strcasecmp(name, "rcpt") == 0) 231968481Seric TimeOuts.to_rcpt = to; 232068481Seric else if (strcasecmp(name, "datainit") == 0) 232168481Seric TimeOuts.to_datainit = to; 232268481Seric else if (strcasecmp(name, "datablock") == 0) 232368481Seric TimeOuts.to_datablock = to; 232468481Seric else if (strcasecmp(name, "datafinal") == 0) 232568481Seric TimeOuts.to_datafinal = to; 232668481Seric else if (strcasecmp(name, "command") == 0) 232768481Seric TimeOuts.to_nextcommand = to; 232868481Seric else if (strcasecmp(name, "rset") == 0) 232968481Seric TimeOuts.to_rset = to; 233068481Seric else if (strcasecmp(name, "helo") == 0) 233168481Seric TimeOuts.to_helo = to; 233268481Seric else if (strcasecmp(name, "quit") == 0) 233368481Seric TimeOuts.to_quit = to; 233468481Seric else if (strcasecmp(name, "misc") == 0) 233568481Seric TimeOuts.to_miscshort = to; 233668481Seric else if (strcasecmp(name, "ident") == 0) 233768481Seric TimeOuts.to_ident = to; 233868481Seric else if (strcasecmp(name, "fileopen") == 0) 233968481Seric TimeOuts.to_fileopen = to; 234068481Seric else if (strcasecmp(name, "queuewarn") == 0) 234168481Seric { 234268481Seric to = convtime(val, 'h'); 234368481Seric if (p == NULL || strcmp(p, "*") == 0) 234468481Seric { 234568481Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 234668481Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 234768481Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 234858112Seric } 234968481Seric else if (strcasecmp(p, "normal") == 0) 235068481Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 235168481Seric else if (strcasecmp(p, "urgent") == 0) 235268481Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 235368481Seric else if (strcasecmp(p, "non-urgent") == 0) 235468481Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 235568481Seric else 235668481Seric syserr("settimeout: invalid queuewarn subtimeout %s", p); 235758112Seric } 235868481Seric else if (strcasecmp(name, "queuereturn") == 0) 235968481Seric { 236068481Seric to = convtime(val, 'd'); 236168481Seric if (p == NULL || strcmp(p, "*") == 0) 236268481Seric { 236368481Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 236468481Seric TimeOuts.to_q_return[TOC_URGENT] = to; 236568481Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 236668481Seric } 236768481Seric else if (strcasecmp(p, "normal") == 0) 236868481Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 236968481Seric else if (strcasecmp(p, "urgent") == 0) 237068481Seric TimeOuts.to_q_return[TOC_URGENT] = to; 237168481Seric else if (strcasecmp(p, "non-urgent") == 0) 237268481Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 237368481Seric else 237468481Seric syserr("settimeout: invalid queuereturn subtimeout %s", p); 237568481Seric } 237668481Seric else 237768481Seric syserr("settimeout: invalid timeout %s", name); 237858112Seric } 2379