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*69963Seric static char sccsid[] = "@(#)readcf.c 8.109 (Berkeley) 06/21/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 } 47269956Seric for (p = &bp[1]; *p != '\0' && *p != '='; 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; 68669935Seric # if 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 */ 86969858Seric /* extract MTA name type; default to "dns" */ 87068481Seric m->m_mtatype = newstr(p); 87168481Seric p = strchr(m->m_mtatype, '/'); 87268481Seric if (p != NULL) 87368481Seric { 87468481Seric *p++ = '\0'; 87568481Seric if (*p == '\0') 87668481Seric p = NULL; 87768481Seric } 87869858Seric if (*m->m_mtatype == '\0') 87969858Seric m->m_mtatype = "dns"; 88069858Seric 88169858Seric /* extract address type; default to "rfc822" */ 88269858Seric m->m_addrtype = p; 88369858Seric if (p != NULL) 88468481Seric p = strchr(p, '/'); 88568481Seric if (p != NULL) 88668481Seric { 88768481Seric *p++ = '\0'; 88868481Seric if (*p == '\0') 88968481Seric p = NULL; 89068481Seric } 89169858Seric if (m->m_addrtype == NULL || *m->m_addrtype == '\0') 89269858Seric m->m_addrtype = "rfc822"; 89369858Seric 89469858Seric /* extract diagnostic type; default to "smtp" */ 89569858Seric m->m_diagtype = p; 89669858Seric if (m->m_diagtype == NULL || *m->m_diagtype == '\0') 89769858Seric m->m_diagtype = "smtp"; 89868481Seric break; 89968481Seric 90068481Seric case 'U': /* user id */ 90168481Seric if (isascii(*p) && !isdigit(*p)) 90268481Seric { 90368481Seric char *q = p; 90468481Seric struct passwd *pw; 90568481Seric 90668481Seric while (isascii(*p) && isalnum(*p)) 90768481Seric p++; 90868481Seric while (isascii(*p) && isspace(*p)) 90968481Seric *p++ = '\0'; 91068481Seric if (*p != '\0') 91168481Seric *p++ = '\0'; 91268693Seric pw = sm_getpwnam(q); 91368481Seric if (pw == NULL) 91468481Seric syserr("readcf: mailer U= flag: unknown user %s", q); 91568481Seric else 91668481Seric { 91768481Seric m->m_uid = pw->pw_uid; 91868481Seric m->m_gid = pw->pw_gid; 91968481Seric } 92068481Seric } 92168481Seric else 92268481Seric { 92368481Seric auto char *q; 92468481Seric 92568481Seric m->m_uid = strtol(p, &q, 0); 92668481Seric p = q; 92768481Seric } 92868481Seric while (isascii(*p) && isspace(*p)) 92968481Seric p++; 93068481Seric if (*p == '\0') 93168481Seric break; 93268481Seric if (isascii(*p) && !isdigit(*p)) 93368481Seric { 93468481Seric char *q = p; 93568481Seric struct group *gr; 93668481Seric 93768481Seric while (isascii(*p) && isalnum(*p)) 93868481Seric p++; 93968481Seric *p++ = '\0'; 94068481Seric gr = getgrnam(q); 94168481Seric if (gr == NULL) 94268481Seric syserr("readcf: mailer U= flag: unknown group %s", q); 94368481Seric else 94468481Seric m->m_gid = gr->gr_gid; 94568481Seric } 94668481Seric else 94768481Seric { 94868481Seric m->m_gid = strtol(p, NULL, 0); 94968481Seric } 95068481Seric break; 95110327Seric } 95210327Seric 95358333Seric p = delimptr; 95410327Seric } 95510327Seric 95658321Seric /* do some rationality checking */ 95758321Seric if (m->m_argv == NULL) 95858321Seric { 95958321Seric syserr("M%s: A= argument required", m->m_name); 96058321Seric return; 96158321Seric } 96258321Seric if (m->m_mailer == NULL) 96358321Seric { 96458321Seric syserr("M%s: P= argument required", m->m_name); 96558321Seric return; 96658321Seric } 96758321Seric 9684096Seric if (NextMailer >= MAXMAILERS) 9694096Seric { 9709381Seric syserr("too many mailers defined (%d max)", MAXMAILERS); 9714096Seric return; 9724096Seric } 97357402Seric 97468481Seric /* do some heuristic cleanup for back compatibility */ 97568481Seric if (bitnset(M_LIMITS, m->m_flags)) 97668481Seric { 97768481Seric if (m->m_linelimit == 0) 97868481Seric m->m_linelimit = SMTPLINELIM; 97968481Seric if (ConfigLevel < 2) 98068481Seric setbitn(M_7BITS, m->m_flags); 98168481Seric } 98268481Seric 98368481Seric if (ConfigLevel < 6 && 98468481Seric (strcmp(m->m_mailer, "[IPC]") == 0 || 98568481Seric strcmp(m->m_mailer, "[TCP]") == 0)) 98668481Seric { 98768481Seric if (m->m_mtatype == NULL) 98868481Seric m->m_mtatype = "dns"; 98968481Seric if (m->m_addrtype == NULL) 99068481Seric m->m_addrtype = "rfc822"; 99168481Seric if (m->m_diagtype == NULL) 99268481Seric m->m_diagtype = "smtp"; 99368481Seric } 99468481Seric 99568481Seric /* enter the mailer into the symbol table */ 99610327Seric s = stab(m->m_name, ST_MAILER, ST_ENTER); 99757402Seric if (s->s_mailer != NULL) 99857402Seric { 99957402Seric i = s->s_mailer->m_mno; 100057402Seric free(s->s_mailer); 100157402Seric } 100257402Seric else 100357402Seric { 100457402Seric i = NextMailer++; 100557402Seric } 100657402Seric Mailer[i] = s->s_mailer = m; 100757454Seric m->m_mno = i; 100810327Seric } 100910327Seric /* 101010327Seric ** MUNCHSTRING -- translate a string into internal form. 101110327Seric ** 101210327Seric ** Parameters: 101310327Seric ** p -- the string to munch. 101458333Seric ** delimptr -- if non-NULL, set to the pointer of the 101558333Seric ** field delimiter character. 101610327Seric ** 101710327Seric ** Returns: 101810327Seric ** the munched string. 101910327Seric */ 10204096Seric 102110327Seric char * 102258333Seric munchstring(p, delimptr) 102310327Seric register char *p; 102458333Seric char **delimptr; 102510327Seric { 102610327Seric register char *q; 102710327Seric bool backslash = FALSE; 102810327Seric bool quotemode = FALSE; 102910327Seric static char buf[MAXLINE]; 10304096Seric 103110327Seric for (q = buf; *p != '\0'; p++) 10324096Seric { 103310327Seric if (backslash) 103410327Seric { 103510327Seric /* everything is roughly literal */ 103610357Seric backslash = FALSE; 103710327Seric switch (*p) 103810327Seric { 103910327Seric case 'r': /* carriage return */ 104010327Seric *q++ = '\r'; 104110327Seric continue; 104210327Seric 104310327Seric case 'n': /* newline */ 104410327Seric *q++ = '\n'; 104510327Seric continue; 104610327Seric 104710327Seric case 'f': /* form feed */ 104810327Seric *q++ = '\f'; 104910327Seric continue; 105010327Seric 105110327Seric case 'b': /* backspace */ 105210327Seric *q++ = '\b'; 105310327Seric continue; 105410327Seric } 105510327Seric *q++ = *p; 105610327Seric } 105710327Seric else 105810327Seric { 105910327Seric if (*p == '\\') 106010327Seric backslash = TRUE; 106110327Seric else if (*p == '"') 106210327Seric quotemode = !quotemode; 106310327Seric else if (quotemode || *p != ',') 106410327Seric *q++ = *p; 106510327Seric else 106610327Seric break; 106710327Seric } 10684096Seric } 10694096Seric 107058333Seric if (delimptr != NULL) 107158333Seric *delimptr = p; 107210327Seric *q++ = '\0'; 107310327Seric return (buf); 107410327Seric } 107510327Seric /* 107610327Seric ** MAKEARGV -- break up a string into words 107710327Seric ** 107810327Seric ** Parameters: 107910327Seric ** p -- the string to break up. 108010327Seric ** 108110327Seric ** Returns: 108210327Seric ** a char **argv (dynamically allocated) 108310327Seric ** 108410327Seric ** Side Effects: 108510327Seric ** munges p. 108610327Seric */ 10874096Seric 108810327Seric char ** 108910327Seric makeargv(p) 109010327Seric register char *p; 109110327Seric { 109210327Seric char *q; 109310327Seric int i; 109410327Seric char **avp; 109510327Seric char *argv[MAXPV + 1]; 109610327Seric 109710327Seric /* take apart the words */ 109810327Seric i = 0; 109910327Seric while (*p != '\0' && i < MAXPV) 11004096Seric { 110110327Seric q = p; 110258050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 110310327Seric p++; 110458050Seric while (isascii(*p) && isspace(*p)) 110510327Seric *p++ = '\0'; 110610327Seric argv[i++] = newstr(q); 11074096Seric } 110810327Seric argv[i++] = NULL; 11094096Seric 111010327Seric /* now make a copy of the argv */ 111110327Seric avp = (char **) xalloc(sizeof *avp * i); 111216893Seric bcopy((char *) argv, (char *) avp, sizeof *avp * i); 111310327Seric 111410327Seric return (avp); 11153308Seric } 11163308Seric /* 11173308Seric ** PRINTRULES -- print rewrite rules (for debugging) 11183308Seric ** 11193308Seric ** Parameters: 11203308Seric ** none. 11213308Seric ** 11223308Seric ** Returns: 11233308Seric ** none. 11243308Seric ** 11253308Seric ** Side Effects: 11263308Seric ** prints rewrite rules. 11273308Seric */ 11283308Seric 112969748Seric void 11303308Seric printrules() 11313308Seric { 11323308Seric register struct rewrite *rwp; 11334072Seric register int ruleset; 11343308Seric 11354072Seric for (ruleset = 0; ruleset < 10; ruleset++) 11363308Seric { 11374072Seric if (RewriteRules[ruleset] == NULL) 11384072Seric continue; 11398067Seric printf("\n----Rule Set %d:", ruleset); 11403308Seric 11414072Seric for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 11423308Seric { 11438067Seric printf("\nLHS:"); 11448067Seric printav(rwp->r_lhs); 11458067Seric printf("RHS:"); 11468067Seric printav(rwp->r_rhs); 11473308Seric } 11483308Seric } 11493308Seric } 115068481Seric /* 115168481Seric ** PRINTMAILER -- print mailer structure (for debugging) 115268481Seric ** 115368481Seric ** Parameters: 115468481Seric ** m -- the mailer to print 115568481Seric ** 115668481Seric ** Returns: 115768481Seric ** none. 115868481Seric */ 11594319Seric 116069748Seric void 116168481Seric printmailer(m) 116268481Seric register MAILER *m; 116368481Seric { 116468481Seric int j; 116568481Seric 116668481Seric printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld U=%d:%d F=", 116768481Seric m->m_mno, m->m_name, 116868481Seric m->m_mailer, m->m_se_rwset, m->m_sh_rwset, 116968481Seric m->m_re_rwset, m->m_rh_rwset, m->m_maxsize, 117068481Seric m->m_uid, m->m_gid); 117168481Seric for (j = '\0'; j <= '\177'; j++) 117268481Seric if (bitnset(j, m->m_flags)) 117368481Seric (void) putchar(j); 117468481Seric printf(" L=%d E=", m->m_linelimit); 117568481Seric xputs(m->m_eol); 117668481Seric if (m->m_defcharset != NULL) 117768481Seric printf(" C=%s", m->m_defcharset); 117868481Seric printf(" T=%s/%s/%s", 117968481Seric m->m_mtatype == NULL ? "<undefined>" : m->m_mtatype, 118068481Seric m->m_addrtype == NULL ? "<undefined>" : m->m_addrtype, 118168481Seric m->m_diagtype == NULL ? "<undefined>" : m->m_diagtype); 118268481Seric if (m->m_argv != NULL) 118368481Seric { 118468481Seric char **a = m->m_argv; 118568481Seric 118668481Seric printf(" A="); 118768481Seric while (*a != NULL) 118868481Seric { 118968481Seric if (a != m->m_argv) 119068481Seric printf(" "); 119168481Seric xputs(*a++); 119268481Seric } 119368481Seric } 119468481Seric printf("\n"); 119568481Seric } 11964096Seric /* 11978256Seric ** SETOPTION -- set global processing option 11988256Seric ** 11998256Seric ** Parameters: 12008256Seric ** opt -- option name. 12018256Seric ** val -- option value (as a text string). 120221755Seric ** safe -- set if this came from a configuration file. 120321755Seric ** Some options (if set from the command line) will 120421755Seric ** reset the user id to avoid security problems. 12058269Seric ** sticky -- if set, don't let other setoptions override 12068269Seric ** this value. 120758734Seric ** e -- the main envelope. 12088256Seric ** 12098256Seric ** Returns: 12108256Seric ** none. 12118256Seric ** 12128256Seric ** Side Effects: 12138256Seric ** Sets options as implied by the arguments. 12148256Seric */ 12158256Seric 121610687Seric static BITMAP StickyOpt; /* set if option is stuck */ 121769748Seric extern void settimeout __P((char *, char *)); 12188269Seric 121957207Seric 122066334Seric #if NAMED_BIND 122157207Seric 122257207Seric struct resolverflags 122357207Seric { 122457207Seric char *rf_name; /* name of the flag */ 122557207Seric long rf_bits; /* bits to set/clear */ 122657207Seric } ResolverFlags[] = 122757207Seric { 122857207Seric "debug", RES_DEBUG, 122957207Seric "aaonly", RES_AAONLY, 123057207Seric "usevc", RES_USEVC, 123157207Seric "primary", RES_PRIMARY, 123257207Seric "igntc", RES_IGNTC, 123357207Seric "recurse", RES_RECURSE, 123457207Seric "defnames", RES_DEFNAMES, 123557207Seric "stayopen", RES_STAYOPEN, 123657207Seric "dnsrch", RES_DNSRCH, 123765583Seric "true", 0, /* to avoid error on old syntax */ 123857207Seric NULL, 0 123957207Seric }; 124057207Seric 124157207Seric #endif 124257207Seric 124368481Seric struct optioninfo 124468481Seric { 124568481Seric char *o_name; /* long name of option */ 124668481Seric u_char o_code; /* short name of option */ 124768481Seric bool o_safe; /* safe for random people to use */ 124868481Seric } OptionTab[] = 124968481Seric { 125068481Seric "SevenBitInput", '7', TRUE, 125169480Seric #if MIME8TO7 125268481Seric "EightBitMode", '8', TRUE, 125369480Seric #endif 125468481Seric "AliasFile", 'A', FALSE, 125568481Seric "AliasWait", 'a', FALSE, 125668481Seric "BlankSub", 'B', FALSE, 125768481Seric "MinFreeBlocks", 'b', TRUE, 125868481Seric "CheckpointInterval", 'C', TRUE, 125968481Seric "HoldExpensive", 'c', FALSE, 126068481Seric "AutoRebuildAliases", 'D', FALSE, 126168481Seric "DeliveryMode", 'd', TRUE, 126268481Seric "ErrorHeader", 'E', FALSE, 126368481Seric "ErrorMode", 'e', TRUE, 126468481Seric "TempFileMode", 'F', FALSE, 126568481Seric "SaveFromLine", 'f', FALSE, 126668481Seric "MatchGECOS", 'G', FALSE, 126768481Seric "HelpFile", 'H', FALSE, 126868481Seric "MaxHopCount", 'h', FALSE, 126968569Seric "ResolverOptions", 'I', FALSE, 127068481Seric "IgnoreDots", 'i', TRUE, 127168481Seric "ForwardPath", 'J', FALSE, 127268481Seric "SendMimeErrors", 'j', TRUE, 127368481Seric "ConnectionCacheSize", 'k', FALSE, 127468481Seric "ConnectionCacheTimeout", 'K', FALSE, 127568481Seric "UseErrorsTo", 'l', FALSE, 127668481Seric "LogLevel", 'L', FALSE, 127768481Seric "MeToo", 'm', TRUE, 127868481Seric "CheckAliases", 'n', FALSE, 127968481Seric "OldStyleHeaders", 'o', TRUE, 128068481Seric "DaemonPortOptions", 'O', FALSE, 128168481Seric "PrivacyOptions", 'p', TRUE, 128268481Seric "PostmasterCopy", 'P', FALSE, 128368481Seric "QueueFactor", 'q', FALSE, 128468481Seric "QueueDirectory", 'Q', FALSE, 128568481Seric "DontPruneRoutes", 'R', FALSE, 128668481Seric "Timeout", 'r', TRUE, 128768481Seric "StatusFile", 'S', FALSE, 128868481Seric "SuperSafe", 's', TRUE, 128968481Seric "QueueTimeout", 'T', FALSE, 129068481Seric "TimeZoneSpec", 't', FALSE, 129168481Seric "UserDatabaseSpec", 'U', FALSE, 129268481Seric "DefaultUser", 'u', FALSE, 129368481Seric "FallbackMXhost", 'V', FALSE, 129468481Seric "Verbose", 'v', TRUE, 129568481Seric "TryNullMXList", 'w', TRUE, 129668481Seric "QueueLA", 'x', FALSE, 129768481Seric "RefuseLA", 'X', FALSE, 129868481Seric "RecipientFactor", 'y', FALSE, 129968569Seric "ForkEachJob", 'Y', FALSE, 130068481Seric "ClassFactor", 'z', FALSE, 130168569Seric "RetryFactor", 'Z', FALSE, 130268481Seric #define O_QUEUESORTORD 0x81 130368481Seric "QueueSortOrder", O_QUEUESORTORD, TRUE, 130469401Seric #define O_HOSTSFILE 0x82 130569401Seric "HostsFile", O_HOSTSFILE, FALSE, 130668481Seric #define O_MQA 0x83 130768481Seric "MinQueueAge", O_MQA, TRUE, 130868481Seric #define O_MHSA 0x84 130968481Seric /* 131068481Seric "MaxHostStatAge", O_MHSA, TRUE, 131168481Seric */ 131268481Seric #define O_DEFCHARSET 0x85 131368481Seric "DefaultCharSet", O_DEFCHARSET, TRUE, 131468481Seric #define O_SSFILE 0x86 131568481Seric "ServiceSwitchFile", O_SSFILE, FALSE, 131668481Seric #define O_DIALDELAY 0x87 131768481Seric "DialDelay", O_DIALDELAY, TRUE, 131868481Seric #define O_NORCPTACTION 0x88 131968481Seric "NoRecipientAction", O_NORCPTACTION, TRUE, 132068490Seric #define O_SAFEFILEENV 0x89 132168490Seric "SafeFileEnvironment", O_SAFEFILEENV, FALSE, 132268569Seric #define O_MAXMSGSIZE 0x8a 132368569Seric "MaxMessageSize", O_MAXMSGSIZE, FALSE, 132468756Seric #define O_COLONOKINADDR 0x8b 132568756Seric "ColonOkInAddr", O_COLONOKINADDR, TRUE, 132669724Seric #define O_MAXQUEUERUN 0x8c 132769724Seric "MaxQueueRunSize", O_MAXQUEUERUN, TRUE, 132869838Seric #define O_MAXCHILDREN 0x8d 132969838Seric /* 133069838Seric "MaxDaemonChildren", O_MAXCHILDREN, FALSE, 133169838Seric */ 133269852Seric #define O_KEEPCNAMES 0x8e 133369852Seric "DontExpandCnames", O_KEEPCNAMES, FALSE, 133468481Seric 133568481Seric NULL, '\0', FALSE, 133668481Seric }; 133768481Seric 133868481Seric 133968481Seric 134069748Seric void 134158734Seric setoption(opt, val, safe, sticky, e) 134269748Seric int opt; 13438256Seric char *val; 134421755Seric bool safe; 13458269Seric bool sticky; 134658734Seric register ENVELOPE *e; 13478256Seric { 134857207Seric register char *p; 134968481Seric register struct optioninfo *o; 135068481Seric char *subopt; 13518265Seric extern bool atobool(); 135212633Seric extern time_t convtime(); 135314879Seric extern int QueueLA; 135414879Seric extern int RefuseLA; 135564718Seric extern bool Warn_Q_option; 13568256Seric 135768481Seric errno = 0; 135868481Seric if (opt == ' ') 135968481Seric { 136068481Seric /* full word options */ 136168481Seric struct optioninfo *sel; 136268481Seric 136368481Seric p = strchr(val, '='); 136468481Seric if (p == NULL) 136568481Seric p = &val[strlen(val)]; 136668481Seric while (*--p == ' ') 136768481Seric continue; 136868481Seric while (*++p == ' ') 136968481Seric *p = '\0'; 137068481Seric if (p == val) 137168481Seric { 137268481Seric syserr("readcf: null option name"); 137368481Seric return; 137468481Seric } 137568481Seric if (*p == '=') 137668481Seric *p++ = '\0'; 137768481Seric while (*p == ' ') 137868481Seric p++; 137968481Seric subopt = strchr(val, '.'); 138068481Seric if (subopt != NULL) 138168481Seric *subopt++ = '\0'; 138268481Seric sel = NULL; 138368481Seric for (o = OptionTab; o->o_name != NULL; o++) 138468481Seric { 138568481Seric if (strncasecmp(o->o_name, val, strlen(val)) != 0) 138668481Seric continue; 138768481Seric if (strlen(o->o_name) == strlen(val)) 138868481Seric { 138968481Seric /* completely specified -- this must be it */ 139068481Seric sel = NULL; 139168481Seric break; 139268481Seric } 139368481Seric if (sel != NULL) 139468481Seric break; 139568481Seric sel = o; 139668481Seric } 139768481Seric if (sel != NULL && o->o_name == NULL) 139868481Seric o = sel; 139968481Seric else if (o->o_name == NULL) 140068481Seric { 140168481Seric syserr("readcf: unknown option name %s", val); 140268481Seric return; 140368481Seric } 140468481Seric else if (sel != NULL) 140568481Seric { 140668481Seric syserr("readcf: ambiguous option name %s (matches %s and %s)", 140768481Seric val, sel->o_name, o->o_name); 140868481Seric return; 140968481Seric } 141068481Seric if (strlen(val) != strlen(o->o_name)) 141168481Seric { 141268481Seric bool oldVerbose = Verbose; 141368481Seric 141468481Seric Verbose = TRUE; 141568481Seric message("Option %s used as abbreviation for %s", 141668481Seric val, o->o_name); 141768481Seric Verbose = oldVerbose; 141868481Seric } 141968481Seric opt = o->o_code; 142068481Seric val = p; 142168481Seric } 142268481Seric else 142368481Seric { 142468481Seric for (o = OptionTab; o->o_name != NULL; o++) 142568481Seric { 142668481Seric if (o->o_code == opt) 142768481Seric break; 142868481Seric } 142968481Seric subopt = NULL; 143068481Seric } 143168481Seric 14328256Seric if (tTd(37, 1)) 143368481Seric { 143468481Seric printf(isascii(opt) && isprint(opt) ? 143569917Seric "setoption %s (%c).%s=" : 143669917Seric "setoption %s (0x%x).%s=", 143768481Seric o->o_name == NULL ? "<unknown>" : o->o_name, 143868481Seric opt, 143969917Seric subopt == NULL ? "" : subopt); 144069917Seric xputs(val); 144168481Seric } 14428256Seric 14438256Seric /* 14448269Seric ** See if this option is preset for us. 14458256Seric */ 14468256Seric 144759731Seric if (!sticky && bitnset(opt, StickyOpt)) 14488269Seric { 14499341Seric if (tTd(37, 1)) 14509341Seric printf(" (ignored)\n"); 14518269Seric return; 14528269Seric } 14538269Seric 145421755Seric /* 145521755Seric ** Check to see if this option can be specified by this user. 145621755Seric */ 145721755Seric 145863787Seric if (!safe && RealUid == 0) 145921755Seric safe = TRUE; 146068481Seric if (!safe && !o->o_safe) 146121755Seric { 146239111Srick if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 146321755Seric { 146436582Sbostic if (tTd(37, 1)) 146536582Sbostic printf(" (unsafe)"); 146663787Seric if (RealUid != geteuid()) 146736582Sbostic { 146851210Seric if (tTd(37, 1)) 146951210Seric printf("(Resetting uid)"); 1470*69963Seric endpwent(); 147163787Seric (void) setgid(RealGid); 147263787Seric (void) setuid(RealUid); 147336582Sbostic } 147421755Seric } 147521755Seric } 147651210Seric if (tTd(37, 1)) 147717985Seric printf("\n"); 14788269Seric 147968481Seric switch (opt & 0xff) 14808256Seric { 148159709Seric case '7': /* force seven-bit input */ 148268481Seric SevenBitInput = atobool(val); 148352106Seric break; 148452106Seric 148569480Seric #if MIME8TO7 148668481Seric case '8': /* handling of 8-bit input */ 148768481Seric switch (*val) 148868481Seric { 148968481Seric case 'm': /* convert 8-bit, convert MIME */ 149068481Seric MimeMode = MM_CVTMIME|MM_MIME8BIT; 149168481Seric break; 149268481Seric 149368481Seric case 'p': /* pass 8 bit, convert MIME */ 149468856Seric MimeMode = MM_CVTMIME|MM_PASS8BIT; 149568481Seric break; 149668481Seric 149768481Seric case 's': /* strict adherence */ 149868481Seric MimeMode = MM_CVTMIME; 149968481Seric break; 150068481Seric 150168856Seric #if 0 150268856Seric case 'r': /* reject 8-bit, don't convert MIME */ 150368856Seric MimeMode = 0; 150468856Seric break; 150568856Seric 150668856Seric case 'j': /* "just send 8" */ 150768856Seric MimeMode = MM_PASS8BIT; 150868856Seric break; 150968856Seric 151068481Seric case 'a': /* encode 8 bit if available */ 151168481Seric MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 151268481Seric break; 151368481Seric 151468481Seric case 'c': /* convert 8 bit to MIME, never 7 bit */ 151568481Seric MimeMode = MM_MIME8BIT; 151668481Seric break; 151768856Seric #endif 151868481Seric 151968481Seric default: 152068481Seric syserr("Unknown 8-bit mode %c", *val); 152168481Seric exit(EX_USAGE); 152268481Seric } 152368481Seric break; 152469480Seric #endif 152568481Seric 15268256Seric case 'A': /* set default alias file */ 15279381Seric if (val[0] == '\0') 152859672Seric setalias("aliases"); 15299381Seric else 153059672Seric setalias(val); 15318256Seric break; 15328256Seric 153317474Seric case 'a': /* look N minutes for "@:@" in alias file */ 153417474Seric if (val[0] == '\0') 153564796Seric SafeAlias = 5 * 60; /* five minutes */ 153617474Seric else 153764796Seric SafeAlias = convtime(val, 'm'); 153817474Seric break; 153917474Seric 154016843Seric case 'B': /* substitution for blank character */ 154116843Seric SpaceSub = val[0]; 154216843Seric if (SpaceSub == '\0') 154316843Seric SpaceSub = ' '; 154416843Seric break; 154516843Seric 154659283Seric case 'b': /* min blocks free on queue fs/max msg size */ 154759283Seric p = strchr(val, '/'); 154859283Seric if (p != NULL) 154959283Seric { 155059283Seric *p++ = '\0'; 155159283Seric MaxMessageSize = atol(p); 155259283Seric } 155358082Seric MinBlocksFree = atol(val); 155458082Seric break; 155558082Seric 15569284Seric case 'c': /* don't connect to "expensive" mailers */ 15579381Seric NoConnect = atobool(val); 15589284Seric break; 15599284Seric 156051305Seric case 'C': /* checkpoint every N addresses */ 156151305Seric CheckpointInterval = atoi(val); 156224944Seric break; 156324944Seric 15649284Seric case 'd': /* delivery mode */ 15659284Seric switch (*val) 15668269Seric { 15679284Seric case '\0': 156858734Seric e->e_sendmode = SM_DELIVER; 15698269Seric break; 15708269Seric 157110755Seric case SM_QUEUE: /* queue only */ 157210755Seric #ifndef QUEUE 157310755Seric syserr("need QUEUE to set -odqueue"); 157456795Seric #endif /* QUEUE */ 157510755Seric /* fall through..... */ 157610755Seric 15779284Seric case SM_DELIVER: /* do everything */ 15789284Seric case SM_FORK: /* fork after verification */ 157958734Seric e->e_sendmode = *val; 15808269Seric break; 15818269Seric 15828269Seric default: 15839284Seric syserr("Unknown delivery mode %c", *val); 15848269Seric exit(EX_USAGE); 15858269Seric } 15868269Seric break; 15878269Seric 15889146Seric case 'D': /* rebuild alias database as needed */ 15899381Seric AutoRebuild = atobool(val); 15909146Seric break; 15919146Seric 159255372Seric case 'E': /* error message header/header file */ 159355379Seric if (*val != '\0') 159455379Seric ErrMsgFile = newstr(val); 159555372Seric break; 159655372Seric 15978269Seric case 'e': /* set error processing mode */ 15988269Seric switch (*val) 15998269Seric { 16009381Seric case EM_QUIET: /* be silent about it */ 16019381Seric case EM_MAIL: /* mail back */ 16029381Seric case EM_BERKNET: /* do berknet error processing */ 16039381Seric case EM_WRITE: /* write back (or mail) */ 16049381Seric case EM_PRINT: /* print errors normally (default) */ 160558734Seric e->e_errormode = *val; 16068269Seric break; 16078269Seric } 16088269Seric break; 16098269Seric 16109049Seric case 'F': /* file mode */ 161117975Seric FileMode = atooct(val) & 0777; 16129049Seric break; 16139049Seric 16148269Seric case 'f': /* save Unix-style From lines on front */ 16159381Seric SaveFrom = atobool(val); 16168269Seric break; 16178269Seric 161853735Seric case 'G': /* match recipients against GECOS field */ 161953735Seric MatchGecos = atobool(val); 162053735Seric break; 162153735Seric 16228256Seric case 'g': /* default gid */ 162368481Seric g_opt: 162464133Seric if (isascii(*val) && isdigit(*val)) 162564133Seric DefGid = atoi(val); 162664133Seric else 162764133Seric { 162864133Seric register struct group *gr; 162964133Seric 163064133Seric DefGid = -1; 163164133Seric gr = getgrnam(val); 163264133Seric if (gr == NULL) 163368481Seric syserr("readcf: option %c: unknown group %s", 163468481Seric opt, val); 163564133Seric else 163664133Seric DefGid = gr->gr_gid; 163764133Seric } 16388256Seric break; 16398256Seric 16408256Seric case 'H': /* help file */ 16419381Seric if (val[0] == '\0') 16428269Seric HelpFile = "sendmail.hf"; 16439381Seric else 16449381Seric HelpFile = newstr(val); 16458256Seric break; 16468256Seric 164751305Seric case 'h': /* maximum hop count */ 164851305Seric MaxHopCount = atoi(val); 164951305Seric break; 165051305Seric 165135651Seric case 'I': /* use internet domain name server */ 165266334Seric #if NAMED_BIND 165357207Seric for (p = val; *p != 0; ) 165457207Seric { 165557207Seric bool clearmode; 165657207Seric char *q; 165757207Seric struct resolverflags *rfp; 165857207Seric 165957207Seric while (*p == ' ') 166057207Seric p++; 166157207Seric if (*p == '\0') 166257207Seric break; 166357207Seric clearmode = FALSE; 166457207Seric if (*p == '-') 166557207Seric clearmode = TRUE; 166657207Seric else if (*p != '+') 166757207Seric p--; 166857207Seric p++; 166957207Seric q = p; 167058050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 167157207Seric p++; 167257207Seric if (*p != '\0') 167357207Seric *p++ = '\0'; 167468759Seric if (strcasecmp(q, "HasWildcardMX") == 0) 167568759Seric { 167669896Seric HasWildcardMX = !clearmode; 167768759Seric continue; 167868759Seric } 167957207Seric for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 168057207Seric { 168157207Seric if (strcasecmp(q, rfp->rf_name) == 0) 168257207Seric break; 168357207Seric } 168464923Seric if (rfp->rf_name == NULL) 168564923Seric syserr("readcf: I option value %s unrecognized", q); 168664923Seric else if (clearmode) 168757207Seric _res.options &= ~rfp->rf_bits; 168857207Seric else 168957207Seric _res.options |= rfp->rf_bits; 169057207Seric } 169157207Seric if (tTd(8, 2)) 169268759Seric printf("_res.options = %x, HasWildcardMX = %d\n", 169369896Seric _res.options, HasWildcardMX); 169457207Seric #else 169557207Seric usrerr("name server (I option) specified but BIND not compiled in"); 169657207Seric #endif 169735651Seric break; 169835651Seric 16998269Seric case 'i': /* ignore dot lines in message */ 17009381Seric IgnrDot = atobool(val); 17018269Seric break; 17028269Seric 170359730Seric case 'j': /* send errors in MIME (RFC 1341) format */ 170459730Seric SendMIMEErrors = atobool(val); 170559730Seric break; 170659730Seric 170757136Seric case 'J': /* .forward search path */ 170857136Seric ForwardPath = newstr(val); 170957136Seric break; 171057136Seric 171154967Seric case 'k': /* connection cache size */ 171254967Seric MaxMciCache = atoi(val); 171356215Seric if (MaxMciCache < 0) 171456215Seric MaxMciCache = 0; 171554967Seric break; 171654967Seric 171754967Seric case 'K': /* connection cache timeout */ 171858796Seric MciCacheTimeout = convtime(val, 'm'); 171954967Seric break; 172054967Seric 172161104Seric case 'l': /* use Errors-To: header */ 172261104Seric UseErrorsTo = atobool(val); 172361104Seric break; 172461104Seric 17258256Seric case 'L': /* log level */ 172664140Seric if (safe || LogLevel < atoi(val)) 172764140Seric LogLevel = atoi(val); 17288256Seric break; 17298256Seric 17308269Seric case 'M': /* define macro */ 173168267Seric p = newstr(&val[1]); 173268267Seric if (!safe) 173368267Seric cleanstrcpy(p, p, MAXNAME); 173468267Seric define(val[0], p, CurEnv); 173516878Seric sticky = FALSE; 17368269Seric break; 17378269Seric 17388269Seric case 'm': /* send to me too */ 17399381Seric MeToo = atobool(val); 17408269Seric break; 17418269Seric 174225820Seric case 'n': /* validate RHS in newaliases */ 174325820Seric CheckAliases = atobool(val); 174425820Seric break; 174525820Seric 174661104Seric /* 'N' available -- was "net name" */ 174761104Seric 174858851Seric case 'O': /* daemon options */ 174958851Seric setdaemonoptions(val); 175058851Seric break; 175158851Seric 17528269Seric case 'o': /* assume old style headers */ 17539381Seric if (atobool(val)) 17549341Seric CurEnv->e_flags |= EF_OLDSTYLE; 17559341Seric else 17569341Seric CurEnv->e_flags &= ~EF_OLDSTYLE; 17578269Seric break; 17588269Seric 175958082Seric case 'p': /* select privacy level */ 176058082Seric p = val; 176158082Seric for (;;) 176258082Seric { 176358082Seric register struct prival *pv; 176458082Seric extern struct prival PrivacyValues[]; 176558082Seric 176658082Seric while (isascii(*p) && (isspace(*p) || ispunct(*p))) 176758082Seric p++; 176858082Seric if (*p == '\0') 176958082Seric break; 177058082Seric val = p; 177158082Seric while (isascii(*p) && isalnum(*p)) 177258082Seric p++; 177358082Seric if (*p != '\0') 177458082Seric *p++ = '\0'; 177558082Seric 177658082Seric for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 177758082Seric { 177858082Seric if (strcasecmp(val, pv->pv_name) == 0) 177958082Seric break; 178058082Seric } 178158886Seric if (pv->pv_name == NULL) 178258886Seric syserr("readcf: Op line: %s unrecognized", val); 178358082Seric PrivacyFlags |= pv->pv_flag; 178458082Seric } 178568479Seric sticky = FALSE; 178658082Seric break; 178758082Seric 178824944Seric case 'P': /* postmaster copy address for returned mail */ 178924944Seric PostMasterCopy = newstr(val); 179024944Seric break; 179124944Seric 179224944Seric case 'q': /* slope of queue only function */ 179324944Seric QueueFactor = atoi(val); 179424944Seric break; 179524944Seric 17968256Seric case 'Q': /* queue directory */ 17979381Seric if (val[0] == '\0') 17988269Seric QueueDir = "mqueue"; 17999381Seric else 18009381Seric QueueDir = newstr(val); 180158789Seric if (RealUid != 0 && !safe) 180264718Seric Warn_Q_option = TRUE; 18038256Seric break; 18048256Seric 180558148Seric case 'R': /* don't prune routes */ 180658148Seric DontPruneRoutes = atobool(val); 180758148Seric break; 180858148Seric 18098256Seric case 'r': /* read timeout */ 181068481Seric if (subopt == NULL) 181168481Seric inittimeouts(val); 181268481Seric else 181368481Seric settimeout(subopt, val); 18148256Seric break; 18158256Seric 18168256Seric case 'S': /* status file */ 18179381Seric if (val[0] == '\0') 18188269Seric StatFile = "sendmail.st"; 18199381Seric else 18209381Seric StatFile = newstr(val); 18218256Seric break; 18228256Seric 18238265Seric case 's': /* be super safe, even if expensive */ 18249381Seric SuperSafe = atobool(val); 18258256Seric break; 18268256Seric 18278256Seric case 'T': /* queue timeout */ 182858737Seric p = strchr(val, '/'); 182958737Seric if (p != NULL) 183058737Seric { 183158737Seric *p++ = '\0'; 183268481Seric settimeout("queuewarn", p); 183358737Seric } 183468481Seric settimeout("queuereturn", val); 183554967Seric break; 18368256Seric 18378265Seric case 't': /* time zone name */ 183852106Seric TimeZoneSpec = newstr(val); 18398265Seric break; 18408265Seric 184150556Seric case 'U': /* location of user database */ 184251360Seric UdbSpec = newstr(val); 184350556Seric break; 184450556Seric 18458256Seric case 'u': /* set default uid */ 184668481Seric for (p = val; *p != '\0'; p++) 184768481Seric { 184868481Seric if (*p == '.' || *p == '/' || *p == ':') 184968481Seric { 185068481Seric *p++ = '\0'; 185168481Seric break; 185268481Seric } 185368481Seric } 185464133Seric if (isascii(*val) && isdigit(*val)) 185564133Seric DefUid = atoi(val); 185664133Seric else 185764133Seric { 185864133Seric register struct passwd *pw; 185964133Seric 186064133Seric DefUid = -1; 186168693Seric pw = sm_getpwnam(val); 186264133Seric if (pw == NULL) 186364133Seric syserr("readcf: option u: unknown user %s", val); 186464133Seric else 186568481Seric { 186664133Seric DefUid = pw->pw_uid; 186768481Seric DefGid = pw->pw_gid; 186868481Seric } 186964133Seric } 187040973Sbostic setdefuser(); 18718256Seric 187268481Seric /* handle the group if it is there */ 187368481Seric if (*p == '\0') 187468481Seric break; 187568481Seric val = p; 187668481Seric goto g_opt; 187768481Seric 187858851Seric case 'V': /* fallback MX host */ 187958851Seric FallBackMX = newstr(val); 188058851Seric break; 188158851Seric 18828269Seric case 'v': /* run in verbose mode */ 18839381Seric Verbose = atobool(val); 18848256Seric break; 18858256Seric 188663837Seric case 'w': /* if we are best MX, try host directly */ 188763837Seric TryNullMXList = atobool(val); 188863837Seric break; 188961104Seric 189061104Seric /* 'W' available -- was wizard password */ 189161104Seric 189214879Seric case 'x': /* load avg at which to auto-queue msgs */ 189314879Seric QueueLA = atoi(val); 189414879Seric break; 189514879Seric 189614879Seric case 'X': /* load avg at which to auto-reject connections */ 189714879Seric RefuseLA = atoi(val); 189814879Seric break; 189914879Seric 190024981Seric case 'y': /* work recipient factor */ 190124981Seric WkRecipFact = atoi(val); 190224981Seric break; 190324981Seric 190424981Seric case 'Y': /* fork jobs during queue runs */ 190524952Seric ForkQueueRuns = atobool(val); 190624952Seric break; 190724952Seric 190824981Seric case 'z': /* work message class factor */ 190924981Seric WkClassFact = atoi(val); 191024981Seric break; 191124981Seric 191224981Seric case 'Z': /* work time factor */ 191324981Seric WkTimeFact = atoi(val); 191424981Seric break; 191524981Seric 191668481Seric case O_QUEUESORTORD: /* queue sorting order */ 191768481Seric switch (*val) 191868481Seric { 191968481Seric case 'h': /* Host first */ 192068481Seric case 'H': 192168481Seric QueueSortOrder = QS_BYHOST; 192268481Seric break; 192368481Seric 192468481Seric case 'p': /* Priority order */ 192568481Seric case 'P': 192668481Seric QueueSortOrder = QS_BYPRIORITY; 192768481Seric break; 192868481Seric 192968481Seric default: 193068481Seric syserr("Invalid queue sort order \"%s\"", val); 193168481Seric } 193268481Seric break; 193368481Seric 193469401Seric case O_HOSTSFILE: /* pathname of /etc/hosts file */ 193569401Seric HostsFile = newstr(val); 193669401Seric break; 193769401Seric 193868481Seric case O_MQA: /* minimum queue age between deliveries */ 193968481Seric MinQueueAge = convtime(val, 'm'); 194068481Seric break; 194168481Seric 194268481Seric case O_MHSA: /* maximum age of cached host status */ 194368481Seric MaxHostStatAge = convtime(val, 'm'); 194468481Seric break; 194568481Seric 194668481Seric case O_DEFCHARSET: /* default character set for mimefying */ 194768481Seric DefaultCharSet = newstr(denlstring(val, TRUE, TRUE)); 194868481Seric break; 194968481Seric 195068481Seric case O_SSFILE: /* service switch file */ 195168481Seric ServiceSwitchFile = newstr(val); 195268481Seric break; 195368481Seric 195468481Seric case O_DIALDELAY: /* delay for dial-on-demand operation */ 195568481Seric DialDelay = convtime(val, 's'); 195668481Seric break; 195768481Seric 195868481Seric case O_NORCPTACTION: /* what to do if no recipient */ 195968481Seric if (strcasecmp(val, "none") == 0) 196068481Seric NoRecipientAction = NRA_NO_ACTION; 196168481Seric else if (strcasecmp(val, "add-to") == 0) 196268481Seric NoRecipientAction = NRA_ADD_TO; 196368481Seric else if (strcasecmp(val, "add-apparently-to") == 0) 196468481Seric NoRecipientAction = NRA_ADD_APPARENTLY_TO; 196568481Seric else if (strcasecmp(val, "add-bcc") == 0) 196668481Seric NoRecipientAction = NRA_ADD_BCC; 196768481Seric else if (strcasecmp(val, "add-to-undisclosed") == 0) 196868481Seric NoRecipientAction = NRA_ADD_TO_UNDISCLOSED; 196968481Seric else 197068481Seric syserr("Invalid NoRecipientAction: %s", val); 197168481Seric 197268490Seric case O_SAFEFILEENV: /* chroot() environ for writing to files */ 197368490Seric SafeFileEnv = newstr(val); 197468490Seric break; 197568490Seric 197668569Seric case O_MAXMSGSIZE: /* maximum message size */ 197769748Seric MaxMessageSize = atol(val); 197868569Seric break; 197968569Seric 198068756Seric case O_COLONOKINADDR: /* old style handling of colon addresses */ 198169748Seric ColonOkInAddr = atobool(val); 198268756Seric break; 198368756Seric 198469724Seric case O_MAXQUEUERUN: /* max # of jobs in a single queue run */ 198569748Seric MaxQueueRun = atol(val); 198669724Seric break; 198769724Seric 198869838Seric case O_MAXCHILDREN: /* max # of children of daemon */ 198969838Seric MaxChildren = atoi(val); 199069852Seric break; 199169838Seric 199269852Seric case O_KEEPCNAMES: /* don't expand CNAME records */ 199369852Seric DontExpandCnames = atobool(val); 199469852Seric break; 199569852Seric 19968256Seric default: 199768481Seric if (tTd(37, 1)) 199868481Seric { 199968481Seric if (isascii(opt) && isprint(opt)) 200068481Seric printf("Warning: option %c unknown\n", opt); 200168481Seric else 200268481Seric printf("Warning: option 0x%x unknown\n", opt); 200368481Seric } 20048256Seric break; 20058256Seric } 200616878Seric if (sticky) 200716878Seric setbitn(opt, StickyOpt); 20088256Seric } 200910687Seric /* 201068481Seric ** SETCLASS -- set a string into a class 201110687Seric ** 201210687Seric ** Parameters: 201368481Seric ** class -- the class to put the string in. 201468481Seric ** str -- the string to enter 201510687Seric ** 201610687Seric ** Returns: 201710687Seric ** none. 201810687Seric ** 201910687Seric ** Side Effects: 202010687Seric ** puts the word into the symbol table. 202110687Seric */ 202210687Seric 202369748Seric void 202468481Seric setclass(class, str) 202510687Seric int class; 202668481Seric char *str; 202710687Seric { 202810687Seric register STAB *s; 202910687Seric 203057943Seric if (tTd(37, 8)) 203168481Seric printf("setclass(%c, %s)\n", class, str); 203268481Seric s = stab(str, ST_CLASS, ST_ENTER); 203310687Seric setbitn(class, s->s_class); 203410687Seric } 203553654Seric /* 203653654Seric ** MAKEMAPENTRY -- create a map entry 203753654Seric ** 203853654Seric ** Parameters: 203953654Seric ** line -- the config file line 204053654Seric ** 204153654Seric ** Returns: 204269774Seric ** A pointer to the map that has been created. 204369774Seric ** NULL if there was a syntax error. 204453654Seric ** 204553654Seric ** Side Effects: 204653654Seric ** Enters the map into the dictionary. 204753654Seric */ 204853654Seric 204969774Seric MAP * 205053654Seric makemapentry(line) 205153654Seric char *line; 205253654Seric { 205353654Seric register char *p; 205453654Seric char *mapname; 205553654Seric char *classname; 205664078Seric register STAB *s; 205753654Seric STAB *class; 205853654Seric 205958050Seric for (p = line; isascii(*p) && isspace(*p); p++) 206053654Seric continue; 206158050Seric if (!(isascii(*p) && isalnum(*p))) 206253654Seric { 206353654Seric syserr("readcf: config K line: no map name"); 206469774Seric return NULL; 206553654Seric } 206653654Seric 206753654Seric mapname = p; 206868481Seric while ((isascii(*++p) && isalnum(*p)) || *p == '.') 206953654Seric continue; 207053654Seric if (*p != '\0') 207153654Seric *p++ = '\0'; 207258050Seric while (isascii(*p) && isspace(*p)) 207353654Seric p++; 207458050Seric if (!(isascii(*p) && isalnum(*p))) 207553654Seric { 207653654Seric syserr("readcf: config K line, map %s: no map class", mapname); 207769774Seric return NULL; 207853654Seric } 207953654Seric classname = p; 208058050Seric while (isascii(*++p) && isalnum(*p)) 208153654Seric continue; 208253654Seric if (*p != '\0') 208353654Seric *p++ = '\0'; 208458050Seric while (isascii(*p) && isspace(*p)) 208553654Seric p++; 208653654Seric 208753654Seric /* look up the class */ 208853654Seric class = stab(classname, ST_MAPCLASS, ST_FIND); 208953654Seric if (class == NULL) 209053654Seric { 209153654Seric syserr("readcf: map %s: class %s not available", mapname, classname); 209269774Seric return NULL; 209353654Seric } 209453654Seric 209553654Seric /* enter the map */ 209664078Seric s = stab(mapname, ST_MAP, ST_ENTER); 209764078Seric s->s_map.map_class = &class->s_mapclass; 209864078Seric s->s_map.map_mname = newstr(mapname); 209953654Seric 210064078Seric if (class->s_mapclass.map_parse(&s->s_map, p)) 210164078Seric s->s_map.map_mflags |= MF_VALID; 210264078Seric 210364078Seric if (tTd(37, 5)) 210464078Seric { 210564078Seric printf("map %s, class %s, flags %x, file %s,\n", 210664078Seric s->s_map.map_mname, s->s_map.map_class->map_cname, 210764078Seric s->s_map.map_mflags, 210864078Seric s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 210964078Seric printf("\tapp %s, domain %s, rebuild %s\n", 211064078Seric s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 211164078Seric s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 211264078Seric s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 211364078Seric } 211469774Seric 211569774Seric return &s->s_map; 211653654Seric } 211758112Seric /* 211869783Seric ** STRTORWSET -- convert string to rewriting set number 211969783Seric ** 212069783Seric ** Parameters: 212169783Seric ** p -- the pointer to the string to decode. 212269783Seric ** endp -- if set, store the trailing delimiter here. 212369783Seric ** stabmode -- ST_ENTER to create this entry, ST_FIND if 212469783Seric ** it must already exist. 212569783Seric ** 212669783Seric ** Returns: 212769783Seric ** The appropriate ruleset number. 212869783Seric ** -1 if it is not valid (error already printed) 212969783Seric */ 213069783Seric 213169783Seric int 213269783Seric strtorwset(p, endp, stabmode) 213369783Seric char *p; 213469783Seric char **endp; 213569783Seric int stabmode; 213669783Seric { 213769783Seric int ruleset; 213869783Seric static int nextruleset = MAXRWSETS; 213969783Seric 214069783Seric while (isascii(*p) && isspace(*p)) 214169783Seric p++; 214269783Seric if (!isascii(*p)) 214369783Seric { 214469783Seric syserr("invalid ruleset name: \"%.20s\"", p); 214569783Seric return -1; 214669783Seric } 214769783Seric if (isdigit(*p)) 214869783Seric { 214969783Seric ruleset = strtol(p, endp, 10); 215069783Seric if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 215169783Seric { 215269783Seric syserr("bad ruleset %d (%d max)", 215369783Seric ruleset, MAXRWSETS / 2); 215469783Seric ruleset = -1; 215569783Seric } 215669783Seric } 215769783Seric else 215869783Seric { 215969783Seric STAB *s; 216069783Seric char delim; 216169783Seric char *q; 216269783Seric 216369783Seric q = p; 216469783Seric while (*p != '\0' && isascii(*p) && 216569783Seric (isalnum(*p) || strchr("-_$", *p) != NULL)) 216669783Seric p++; 216769783Seric while (isascii(*p) && isspace(*p)) 216869783Seric *p++ = '\0'; 216969783Seric delim = *p; 217069783Seric if (delim != '\0') 217169783Seric *p = '\0'; 217269783Seric s = stab(q, ST_RULESET, stabmode); 217369783Seric if (delim != '\0') 217469783Seric *p = delim; 217569783Seric 217669783Seric if (s == NULL) 217769783Seric { 217869783Seric syserr("unknown ruleset %s", q); 217969783Seric return -1; 218069783Seric } 218169783Seric 218269783Seric if (stabmode == ST_ENTER && delim == '=') 218369783Seric { 218469962Seric ruleset = strtol(++p, endp, 10); 218569783Seric if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 218669783Seric { 218769783Seric syserr("bad ruleset %s = %d (%d max)", 218869783Seric q, ruleset, MAXRWSETS / 2); 218969783Seric ruleset = -1; 219069783Seric } 219169783Seric } 219269783Seric else 219369783Seric { 219469783Seric if (endp != NULL) 219569783Seric *endp = p; 219669783Seric if (s->s_ruleset > 0) 219769783Seric ruleset = s->s_ruleset; 219869783Seric else if ((ruleset = --nextruleset) < MAXRWSETS / 2) 219969783Seric { 220069783Seric syserr("%s: too many named rulesets (%d max)", 220169783Seric q, MAXRWSETS / 2); 220269783Seric ruleset = -1; 220369783Seric } 220469783Seric } 220569783Seric if (s->s_ruleset > 0 && ruleset >= 0 && ruleset != s->s_ruleset) 220669783Seric { 220769783Seric syserr("%s: ruleset changed value (old %d, new %d)", 220869783Seric q, ruleset, s->s_ruleset); 220969783Seric ruleset = s->s_ruleset; 221069783Seric } 221169783Seric else if (ruleset > 0) 221269783Seric { 221369783Seric s->s_ruleset = ruleset; 221469783Seric } 221569783Seric } 221669783Seric return ruleset; 221769783Seric } 221869783Seric /* 221968481Seric ** INITTIMEOUTS -- parse and set timeout values 222058112Seric ** 222158112Seric ** Parameters: 222258112Seric ** val -- a pointer to the values. If NULL, do initial 222358112Seric ** settings. 222458112Seric ** 222558112Seric ** Returns: 222658112Seric ** none. 222758112Seric ** 222858112Seric ** Side Effects: 222958112Seric ** Initializes the TimeOuts structure 223058112Seric */ 223158112Seric 223264255Seric #define SECONDS 223358112Seric #define MINUTES * 60 223458112Seric #define HOUR * 3600 223558112Seric 223669748Seric void 223768481Seric inittimeouts(val) 223858112Seric register char *val; 223958112Seric { 224058112Seric register char *p; 224158671Seric extern time_t convtime(); 224258112Seric 224358112Seric if (val == NULL) 224458112Seric { 224558112Seric TimeOuts.to_initial = (time_t) 5 MINUTES; 224658112Seric TimeOuts.to_helo = (time_t) 5 MINUTES; 224758112Seric TimeOuts.to_mail = (time_t) 10 MINUTES; 224858112Seric TimeOuts.to_rcpt = (time_t) 1 HOUR; 224958112Seric TimeOuts.to_datainit = (time_t) 5 MINUTES; 225058112Seric TimeOuts.to_datablock = (time_t) 1 HOUR; 225158112Seric TimeOuts.to_datafinal = (time_t) 1 HOUR; 225258112Seric TimeOuts.to_rset = (time_t) 5 MINUTES; 225358112Seric TimeOuts.to_quit = (time_t) 2 MINUTES; 225458112Seric TimeOuts.to_nextcommand = (time_t) 1 HOUR; 225558112Seric TimeOuts.to_miscshort = (time_t) 2 MINUTES; 225668481Seric #if IDENTPROTO 225764255Seric TimeOuts.to_ident = (time_t) 30 SECONDS; 225868481Seric #else 225968481Seric TimeOuts.to_ident = (time_t) 0 SECONDS; 226068481Seric #endif 226168481Seric TimeOuts.to_fileopen = (time_t) 60 SECONDS; 226258112Seric return; 226358112Seric } 226458112Seric 226558112Seric for (;; val = p) 226658112Seric { 226758112Seric while (isascii(*val) && isspace(*val)) 226858112Seric val++; 226958112Seric if (*val == '\0') 227058112Seric break; 227158112Seric for (p = val; *p != '\0' && *p != ','; p++) 227258112Seric continue; 227358112Seric if (*p != '\0') 227458112Seric *p++ = '\0'; 227558112Seric 227658112Seric if (isascii(*val) && isdigit(*val)) 227758112Seric { 227858112Seric /* old syntax -- set everything */ 227958796Seric TimeOuts.to_mail = convtime(val, 'm'); 228058112Seric TimeOuts.to_rcpt = TimeOuts.to_mail; 228158112Seric TimeOuts.to_datainit = TimeOuts.to_mail; 228258112Seric TimeOuts.to_datablock = TimeOuts.to_mail; 228358112Seric TimeOuts.to_datafinal = TimeOuts.to_mail; 228458112Seric TimeOuts.to_nextcommand = TimeOuts.to_mail; 228558112Seric continue; 228658112Seric } 228758112Seric else 228858112Seric { 228968481Seric register char *q = strchr(val, ':'); 229058112Seric 229168481Seric if (q == NULL && (q = strchr(val, '=')) == NULL) 229258112Seric { 229358112Seric /* syntax error */ 229458112Seric continue; 229558112Seric } 229658112Seric *q++ = '\0'; 229768481Seric settimeout(val, q); 229868481Seric } 229968481Seric } 230068481Seric } 230168481Seric /* 230268481Seric ** SETTIMEOUT -- set an individual timeout 230368481Seric ** 230468481Seric ** Parameters: 230568481Seric ** name -- the name of the timeout. 230668481Seric ** val -- the value of the timeout. 230768481Seric ** 230868481Seric ** Returns: 230968481Seric ** none. 231068481Seric */ 231158112Seric 231269748Seric void 231368481Seric settimeout(name, val) 231468481Seric char *name; 231568481Seric char *val; 231668481Seric { 231768481Seric register char *p; 231868481Seric time_t to; 231968481Seric extern time_t convtime(); 232068481Seric 232168481Seric to = convtime(val, 'm'); 232268481Seric p = strchr(name, '.'); 232368481Seric if (p != NULL) 232468481Seric *p++ = '\0'; 232568481Seric 232668481Seric if (strcasecmp(name, "initial") == 0) 232768481Seric TimeOuts.to_initial = to; 232868481Seric else if (strcasecmp(name, "mail") == 0) 232968481Seric TimeOuts.to_mail = to; 233068481Seric else if (strcasecmp(name, "rcpt") == 0) 233168481Seric TimeOuts.to_rcpt = to; 233268481Seric else if (strcasecmp(name, "datainit") == 0) 233368481Seric TimeOuts.to_datainit = to; 233468481Seric else if (strcasecmp(name, "datablock") == 0) 233568481Seric TimeOuts.to_datablock = to; 233668481Seric else if (strcasecmp(name, "datafinal") == 0) 233768481Seric TimeOuts.to_datafinal = to; 233868481Seric else if (strcasecmp(name, "command") == 0) 233968481Seric TimeOuts.to_nextcommand = to; 234068481Seric else if (strcasecmp(name, "rset") == 0) 234168481Seric TimeOuts.to_rset = to; 234268481Seric else if (strcasecmp(name, "helo") == 0) 234368481Seric TimeOuts.to_helo = to; 234468481Seric else if (strcasecmp(name, "quit") == 0) 234568481Seric TimeOuts.to_quit = to; 234668481Seric else if (strcasecmp(name, "misc") == 0) 234768481Seric TimeOuts.to_miscshort = to; 234868481Seric else if (strcasecmp(name, "ident") == 0) 234968481Seric TimeOuts.to_ident = to; 235068481Seric else if (strcasecmp(name, "fileopen") == 0) 235168481Seric TimeOuts.to_fileopen = to; 235268481Seric else if (strcasecmp(name, "queuewarn") == 0) 235368481Seric { 235468481Seric to = convtime(val, 'h'); 235568481Seric if (p == NULL || strcmp(p, "*") == 0) 235668481Seric { 235768481Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 235868481Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 235968481Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 236058112Seric } 236168481Seric else if (strcasecmp(p, "normal") == 0) 236268481Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 236368481Seric else if (strcasecmp(p, "urgent") == 0) 236468481Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 236568481Seric else if (strcasecmp(p, "non-urgent") == 0) 236668481Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 236768481Seric else 236868481Seric syserr("settimeout: invalid queuewarn subtimeout %s", p); 236958112Seric } 237068481Seric else if (strcasecmp(name, "queuereturn") == 0) 237168481Seric { 237268481Seric to = convtime(val, 'd'); 237368481Seric if (p == NULL || strcmp(p, "*") == 0) 237468481Seric { 237568481Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 237668481Seric TimeOuts.to_q_return[TOC_URGENT] = to; 237768481Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 237868481Seric } 237968481Seric else if (strcasecmp(p, "normal") == 0) 238068481Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 238168481Seric else if (strcasecmp(p, "urgent") == 0) 238268481Seric TimeOuts.to_q_return[TOC_URGENT] = to; 238368481Seric else if (strcasecmp(p, "non-urgent") == 0) 238468481Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 238568481Seric else 238668481Seric syserr("settimeout: invalid queuereturn subtimeout %s", p); 238768481Seric } 238868481Seric else 238968481Seric syserr("settimeout: invalid timeout %s", name); 239058112Seric } 2391