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*69956Seric static char sccsid[] = "@(#)readcf.c 8.107 (Berkeley) 06/20/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 } 472*69956Seric 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)"); 147063787Seric (void) setgid(RealGid); 147163787Seric (void) setuid(RealUid); 147236582Sbostic } 147321755Seric } 147421755Seric } 147551210Seric if (tTd(37, 1)) 147617985Seric printf("\n"); 14778269Seric 147868481Seric switch (opt & 0xff) 14798256Seric { 148059709Seric case '7': /* force seven-bit input */ 148168481Seric SevenBitInput = atobool(val); 148252106Seric break; 148352106Seric 148469480Seric #if MIME8TO7 148568481Seric case '8': /* handling of 8-bit input */ 148668481Seric switch (*val) 148768481Seric { 148868481Seric case 'm': /* convert 8-bit, convert MIME */ 148968481Seric MimeMode = MM_CVTMIME|MM_MIME8BIT; 149068481Seric break; 149168481Seric 149268481Seric case 'p': /* pass 8 bit, convert MIME */ 149368856Seric MimeMode = MM_CVTMIME|MM_PASS8BIT; 149468481Seric break; 149568481Seric 149668481Seric case 's': /* strict adherence */ 149768481Seric MimeMode = MM_CVTMIME; 149868481Seric break; 149968481Seric 150068856Seric #if 0 150168856Seric case 'r': /* reject 8-bit, don't convert MIME */ 150268856Seric MimeMode = 0; 150368856Seric break; 150468856Seric 150568856Seric case 'j': /* "just send 8" */ 150668856Seric MimeMode = MM_PASS8BIT; 150768856Seric break; 150868856Seric 150968481Seric case 'a': /* encode 8 bit if available */ 151068481Seric MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 151168481Seric break; 151268481Seric 151368481Seric case 'c': /* convert 8 bit to MIME, never 7 bit */ 151468481Seric MimeMode = MM_MIME8BIT; 151568481Seric break; 151668856Seric #endif 151768481Seric 151868481Seric default: 151968481Seric syserr("Unknown 8-bit mode %c", *val); 152068481Seric exit(EX_USAGE); 152168481Seric } 152268481Seric break; 152369480Seric #endif 152468481Seric 15258256Seric case 'A': /* set default alias file */ 15269381Seric if (val[0] == '\0') 152759672Seric setalias("aliases"); 15289381Seric else 152959672Seric setalias(val); 15308256Seric break; 15318256Seric 153217474Seric case 'a': /* look N minutes for "@:@" in alias file */ 153317474Seric if (val[0] == '\0') 153464796Seric SafeAlias = 5 * 60; /* five minutes */ 153517474Seric else 153664796Seric SafeAlias = convtime(val, 'm'); 153717474Seric break; 153817474Seric 153916843Seric case 'B': /* substitution for blank character */ 154016843Seric SpaceSub = val[0]; 154116843Seric if (SpaceSub == '\0') 154216843Seric SpaceSub = ' '; 154316843Seric break; 154416843Seric 154559283Seric case 'b': /* min blocks free on queue fs/max msg size */ 154659283Seric p = strchr(val, '/'); 154759283Seric if (p != NULL) 154859283Seric { 154959283Seric *p++ = '\0'; 155059283Seric MaxMessageSize = atol(p); 155159283Seric } 155258082Seric MinBlocksFree = atol(val); 155358082Seric break; 155458082Seric 15559284Seric case 'c': /* don't connect to "expensive" mailers */ 15569381Seric NoConnect = atobool(val); 15579284Seric break; 15589284Seric 155951305Seric case 'C': /* checkpoint every N addresses */ 156051305Seric CheckpointInterval = atoi(val); 156124944Seric break; 156224944Seric 15639284Seric case 'd': /* delivery mode */ 15649284Seric switch (*val) 15658269Seric { 15669284Seric case '\0': 156758734Seric e->e_sendmode = SM_DELIVER; 15688269Seric break; 15698269Seric 157010755Seric case SM_QUEUE: /* queue only */ 157110755Seric #ifndef QUEUE 157210755Seric syserr("need QUEUE to set -odqueue"); 157356795Seric #endif /* QUEUE */ 157410755Seric /* fall through..... */ 157510755Seric 15769284Seric case SM_DELIVER: /* do everything */ 15779284Seric case SM_FORK: /* fork after verification */ 157858734Seric e->e_sendmode = *val; 15798269Seric break; 15808269Seric 15818269Seric default: 15829284Seric syserr("Unknown delivery mode %c", *val); 15838269Seric exit(EX_USAGE); 15848269Seric } 15858269Seric break; 15868269Seric 15879146Seric case 'D': /* rebuild alias database as needed */ 15889381Seric AutoRebuild = atobool(val); 15899146Seric break; 15909146Seric 159155372Seric case 'E': /* error message header/header file */ 159255379Seric if (*val != '\0') 159355379Seric ErrMsgFile = newstr(val); 159455372Seric break; 159555372Seric 15968269Seric case 'e': /* set error processing mode */ 15978269Seric switch (*val) 15988269Seric { 15999381Seric case EM_QUIET: /* be silent about it */ 16009381Seric case EM_MAIL: /* mail back */ 16019381Seric case EM_BERKNET: /* do berknet error processing */ 16029381Seric case EM_WRITE: /* write back (or mail) */ 16039381Seric case EM_PRINT: /* print errors normally (default) */ 160458734Seric e->e_errormode = *val; 16058269Seric break; 16068269Seric } 16078269Seric break; 16088269Seric 16099049Seric case 'F': /* file mode */ 161017975Seric FileMode = atooct(val) & 0777; 16119049Seric break; 16129049Seric 16138269Seric case 'f': /* save Unix-style From lines on front */ 16149381Seric SaveFrom = atobool(val); 16158269Seric break; 16168269Seric 161753735Seric case 'G': /* match recipients against GECOS field */ 161853735Seric MatchGecos = atobool(val); 161953735Seric break; 162053735Seric 16218256Seric case 'g': /* default gid */ 162268481Seric g_opt: 162364133Seric if (isascii(*val) && isdigit(*val)) 162464133Seric DefGid = atoi(val); 162564133Seric else 162664133Seric { 162764133Seric register struct group *gr; 162864133Seric 162964133Seric DefGid = -1; 163064133Seric gr = getgrnam(val); 163164133Seric if (gr == NULL) 163268481Seric syserr("readcf: option %c: unknown group %s", 163368481Seric opt, val); 163464133Seric else 163564133Seric DefGid = gr->gr_gid; 163664133Seric } 16378256Seric break; 16388256Seric 16398256Seric case 'H': /* help file */ 16409381Seric if (val[0] == '\0') 16418269Seric HelpFile = "sendmail.hf"; 16429381Seric else 16439381Seric HelpFile = newstr(val); 16448256Seric break; 16458256Seric 164651305Seric case 'h': /* maximum hop count */ 164751305Seric MaxHopCount = atoi(val); 164851305Seric break; 164951305Seric 165035651Seric case 'I': /* use internet domain name server */ 165166334Seric #if NAMED_BIND 165257207Seric for (p = val; *p != 0; ) 165357207Seric { 165457207Seric bool clearmode; 165557207Seric char *q; 165657207Seric struct resolverflags *rfp; 165757207Seric 165857207Seric while (*p == ' ') 165957207Seric p++; 166057207Seric if (*p == '\0') 166157207Seric break; 166257207Seric clearmode = FALSE; 166357207Seric if (*p == '-') 166457207Seric clearmode = TRUE; 166557207Seric else if (*p != '+') 166657207Seric p--; 166757207Seric p++; 166857207Seric q = p; 166958050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 167057207Seric p++; 167157207Seric if (*p != '\0') 167257207Seric *p++ = '\0'; 167368759Seric if (strcasecmp(q, "HasWildcardMX") == 0) 167468759Seric { 167569896Seric HasWildcardMX = !clearmode; 167668759Seric continue; 167768759Seric } 167857207Seric for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 167957207Seric { 168057207Seric if (strcasecmp(q, rfp->rf_name) == 0) 168157207Seric break; 168257207Seric } 168364923Seric if (rfp->rf_name == NULL) 168464923Seric syserr("readcf: I option value %s unrecognized", q); 168564923Seric else if (clearmode) 168657207Seric _res.options &= ~rfp->rf_bits; 168757207Seric else 168857207Seric _res.options |= rfp->rf_bits; 168957207Seric } 169057207Seric if (tTd(8, 2)) 169168759Seric printf("_res.options = %x, HasWildcardMX = %d\n", 169269896Seric _res.options, HasWildcardMX); 169357207Seric #else 169457207Seric usrerr("name server (I option) specified but BIND not compiled in"); 169557207Seric #endif 169635651Seric break; 169735651Seric 16988269Seric case 'i': /* ignore dot lines in message */ 16999381Seric IgnrDot = atobool(val); 17008269Seric break; 17018269Seric 170259730Seric case 'j': /* send errors in MIME (RFC 1341) format */ 170359730Seric SendMIMEErrors = atobool(val); 170459730Seric break; 170559730Seric 170657136Seric case 'J': /* .forward search path */ 170757136Seric ForwardPath = newstr(val); 170857136Seric break; 170957136Seric 171054967Seric case 'k': /* connection cache size */ 171154967Seric MaxMciCache = atoi(val); 171256215Seric if (MaxMciCache < 0) 171356215Seric MaxMciCache = 0; 171454967Seric break; 171554967Seric 171654967Seric case 'K': /* connection cache timeout */ 171758796Seric MciCacheTimeout = convtime(val, 'm'); 171854967Seric break; 171954967Seric 172061104Seric case 'l': /* use Errors-To: header */ 172161104Seric UseErrorsTo = atobool(val); 172261104Seric break; 172361104Seric 17248256Seric case 'L': /* log level */ 172564140Seric if (safe || LogLevel < atoi(val)) 172664140Seric LogLevel = atoi(val); 17278256Seric break; 17288256Seric 17298269Seric case 'M': /* define macro */ 173068267Seric p = newstr(&val[1]); 173168267Seric if (!safe) 173268267Seric cleanstrcpy(p, p, MAXNAME); 173368267Seric define(val[0], p, CurEnv); 173416878Seric sticky = FALSE; 17358269Seric break; 17368269Seric 17378269Seric case 'm': /* send to me too */ 17389381Seric MeToo = atobool(val); 17398269Seric break; 17408269Seric 174125820Seric case 'n': /* validate RHS in newaliases */ 174225820Seric CheckAliases = atobool(val); 174325820Seric break; 174425820Seric 174561104Seric /* 'N' available -- was "net name" */ 174661104Seric 174758851Seric case 'O': /* daemon options */ 174858851Seric setdaemonoptions(val); 174958851Seric break; 175058851Seric 17518269Seric case 'o': /* assume old style headers */ 17529381Seric if (atobool(val)) 17539341Seric CurEnv->e_flags |= EF_OLDSTYLE; 17549341Seric else 17559341Seric CurEnv->e_flags &= ~EF_OLDSTYLE; 17568269Seric break; 17578269Seric 175858082Seric case 'p': /* select privacy level */ 175958082Seric p = val; 176058082Seric for (;;) 176158082Seric { 176258082Seric register struct prival *pv; 176358082Seric extern struct prival PrivacyValues[]; 176458082Seric 176558082Seric while (isascii(*p) && (isspace(*p) || ispunct(*p))) 176658082Seric p++; 176758082Seric if (*p == '\0') 176858082Seric break; 176958082Seric val = p; 177058082Seric while (isascii(*p) && isalnum(*p)) 177158082Seric p++; 177258082Seric if (*p != '\0') 177358082Seric *p++ = '\0'; 177458082Seric 177558082Seric for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 177658082Seric { 177758082Seric if (strcasecmp(val, pv->pv_name) == 0) 177858082Seric break; 177958082Seric } 178058886Seric if (pv->pv_name == NULL) 178158886Seric syserr("readcf: Op line: %s unrecognized", val); 178258082Seric PrivacyFlags |= pv->pv_flag; 178358082Seric } 178468479Seric sticky = FALSE; 178558082Seric break; 178658082Seric 178724944Seric case 'P': /* postmaster copy address for returned mail */ 178824944Seric PostMasterCopy = newstr(val); 178924944Seric break; 179024944Seric 179124944Seric case 'q': /* slope of queue only function */ 179224944Seric QueueFactor = atoi(val); 179324944Seric break; 179424944Seric 17958256Seric case 'Q': /* queue directory */ 17969381Seric if (val[0] == '\0') 17978269Seric QueueDir = "mqueue"; 17989381Seric else 17999381Seric QueueDir = newstr(val); 180058789Seric if (RealUid != 0 && !safe) 180164718Seric Warn_Q_option = TRUE; 18028256Seric break; 18038256Seric 180458148Seric case 'R': /* don't prune routes */ 180558148Seric DontPruneRoutes = atobool(val); 180658148Seric break; 180758148Seric 18088256Seric case 'r': /* read timeout */ 180968481Seric if (subopt == NULL) 181068481Seric inittimeouts(val); 181168481Seric else 181268481Seric settimeout(subopt, val); 18138256Seric break; 18148256Seric 18158256Seric case 'S': /* status file */ 18169381Seric if (val[0] == '\0') 18178269Seric StatFile = "sendmail.st"; 18189381Seric else 18199381Seric StatFile = newstr(val); 18208256Seric break; 18218256Seric 18228265Seric case 's': /* be super safe, even if expensive */ 18239381Seric SuperSafe = atobool(val); 18248256Seric break; 18258256Seric 18268256Seric case 'T': /* queue timeout */ 182758737Seric p = strchr(val, '/'); 182858737Seric if (p != NULL) 182958737Seric { 183058737Seric *p++ = '\0'; 183168481Seric settimeout("queuewarn", p); 183258737Seric } 183368481Seric settimeout("queuereturn", val); 183454967Seric break; 18358256Seric 18368265Seric case 't': /* time zone name */ 183752106Seric TimeZoneSpec = newstr(val); 18388265Seric break; 18398265Seric 184050556Seric case 'U': /* location of user database */ 184151360Seric UdbSpec = newstr(val); 184250556Seric break; 184350556Seric 18448256Seric case 'u': /* set default uid */ 184568481Seric for (p = val; *p != '\0'; p++) 184668481Seric { 184768481Seric if (*p == '.' || *p == '/' || *p == ':') 184868481Seric { 184968481Seric *p++ = '\0'; 185068481Seric break; 185168481Seric } 185268481Seric } 185364133Seric if (isascii(*val) && isdigit(*val)) 185464133Seric DefUid = atoi(val); 185564133Seric else 185664133Seric { 185764133Seric register struct passwd *pw; 185864133Seric 185964133Seric DefUid = -1; 186068693Seric pw = sm_getpwnam(val); 186164133Seric if (pw == NULL) 186264133Seric syserr("readcf: option u: unknown user %s", val); 186364133Seric else 186468481Seric { 186564133Seric DefUid = pw->pw_uid; 186668481Seric DefGid = pw->pw_gid; 186768481Seric } 186864133Seric } 186940973Sbostic setdefuser(); 18708256Seric 187168481Seric /* handle the group if it is there */ 187268481Seric if (*p == '\0') 187368481Seric break; 187468481Seric val = p; 187568481Seric goto g_opt; 187668481Seric 187758851Seric case 'V': /* fallback MX host */ 187858851Seric FallBackMX = newstr(val); 187958851Seric break; 188058851Seric 18818269Seric case 'v': /* run in verbose mode */ 18829381Seric Verbose = atobool(val); 18838256Seric break; 18848256Seric 188563837Seric case 'w': /* if we are best MX, try host directly */ 188663837Seric TryNullMXList = atobool(val); 188763837Seric break; 188861104Seric 188961104Seric /* 'W' available -- was wizard password */ 189061104Seric 189114879Seric case 'x': /* load avg at which to auto-queue msgs */ 189214879Seric QueueLA = atoi(val); 189314879Seric break; 189414879Seric 189514879Seric case 'X': /* load avg at which to auto-reject connections */ 189614879Seric RefuseLA = atoi(val); 189714879Seric break; 189814879Seric 189924981Seric case 'y': /* work recipient factor */ 190024981Seric WkRecipFact = atoi(val); 190124981Seric break; 190224981Seric 190324981Seric case 'Y': /* fork jobs during queue runs */ 190424952Seric ForkQueueRuns = atobool(val); 190524952Seric break; 190624952Seric 190724981Seric case 'z': /* work message class factor */ 190824981Seric WkClassFact = atoi(val); 190924981Seric break; 191024981Seric 191124981Seric case 'Z': /* work time factor */ 191224981Seric WkTimeFact = atoi(val); 191324981Seric break; 191424981Seric 191568481Seric case O_QUEUESORTORD: /* queue sorting order */ 191668481Seric switch (*val) 191768481Seric { 191868481Seric case 'h': /* Host first */ 191968481Seric case 'H': 192068481Seric QueueSortOrder = QS_BYHOST; 192168481Seric break; 192268481Seric 192368481Seric case 'p': /* Priority order */ 192468481Seric case 'P': 192568481Seric QueueSortOrder = QS_BYPRIORITY; 192668481Seric break; 192768481Seric 192868481Seric default: 192968481Seric syserr("Invalid queue sort order \"%s\"", val); 193068481Seric } 193168481Seric break; 193268481Seric 193369401Seric case O_HOSTSFILE: /* pathname of /etc/hosts file */ 193469401Seric HostsFile = newstr(val); 193569401Seric break; 193669401Seric 193768481Seric case O_MQA: /* minimum queue age between deliveries */ 193868481Seric MinQueueAge = convtime(val, 'm'); 193968481Seric break; 194068481Seric 194168481Seric case O_MHSA: /* maximum age of cached host status */ 194268481Seric MaxHostStatAge = convtime(val, 'm'); 194368481Seric break; 194468481Seric 194568481Seric case O_DEFCHARSET: /* default character set for mimefying */ 194668481Seric DefaultCharSet = newstr(denlstring(val, TRUE, TRUE)); 194768481Seric break; 194868481Seric 194968481Seric case O_SSFILE: /* service switch file */ 195068481Seric ServiceSwitchFile = newstr(val); 195168481Seric break; 195268481Seric 195368481Seric case O_DIALDELAY: /* delay for dial-on-demand operation */ 195468481Seric DialDelay = convtime(val, 's'); 195568481Seric break; 195668481Seric 195768481Seric case O_NORCPTACTION: /* what to do if no recipient */ 195868481Seric if (strcasecmp(val, "none") == 0) 195968481Seric NoRecipientAction = NRA_NO_ACTION; 196068481Seric else if (strcasecmp(val, "add-to") == 0) 196168481Seric NoRecipientAction = NRA_ADD_TO; 196268481Seric else if (strcasecmp(val, "add-apparently-to") == 0) 196368481Seric NoRecipientAction = NRA_ADD_APPARENTLY_TO; 196468481Seric else if (strcasecmp(val, "add-bcc") == 0) 196568481Seric NoRecipientAction = NRA_ADD_BCC; 196668481Seric else if (strcasecmp(val, "add-to-undisclosed") == 0) 196768481Seric NoRecipientAction = NRA_ADD_TO_UNDISCLOSED; 196868481Seric else 196968481Seric syserr("Invalid NoRecipientAction: %s", val); 197068481Seric 197168490Seric case O_SAFEFILEENV: /* chroot() environ for writing to files */ 197268490Seric SafeFileEnv = newstr(val); 197368490Seric break; 197468490Seric 197568569Seric case O_MAXMSGSIZE: /* maximum message size */ 197669748Seric MaxMessageSize = atol(val); 197768569Seric break; 197868569Seric 197968756Seric case O_COLONOKINADDR: /* old style handling of colon addresses */ 198069748Seric ColonOkInAddr = atobool(val); 198168756Seric break; 198268756Seric 198369724Seric case O_MAXQUEUERUN: /* max # of jobs in a single queue run */ 198469748Seric MaxQueueRun = atol(val); 198569724Seric break; 198669724Seric 198769838Seric case O_MAXCHILDREN: /* max # of children of daemon */ 198869838Seric MaxChildren = atoi(val); 198969852Seric break; 199069838Seric 199169852Seric case O_KEEPCNAMES: /* don't expand CNAME records */ 199269852Seric DontExpandCnames = atobool(val); 199369852Seric break; 199469852Seric 19958256Seric default: 199668481Seric if (tTd(37, 1)) 199768481Seric { 199868481Seric if (isascii(opt) && isprint(opt)) 199968481Seric printf("Warning: option %c unknown\n", opt); 200068481Seric else 200168481Seric printf("Warning: option 0x%x unknown\n", opt); 200268481Seric } 20038256Seric break; 20048256Seric } 200516878Seric if (sticky) 200616878Seric setbitn(opt, StickyOpt); 20078256Seric } 200810687Seric /* 200968481Seric ** SETCLASS -- set a string into a class 201010687Seric ** 201110687Seric ** Parameters: 201268481Seric ** class -- the class to put the string in. 201368481Seric ** str -- the string to enter 201410687Seric ** 201510687Seric ** Returns: 201610687Seric ** none. 201710687Seric ** 201810687Seric ** Side Effects: 201910687Seric ** puts the word into the symbol table. 202010687Seric */ 202110687Seric 202269748Seric void 202368481Seric setclass(class, str) 202410687Seric int class; 202568481Seric char *str; 202610687Seric { 202710687Seric register STAB *s; 202810687Seric 202957943Seric if (tTd(37, 8)) 203068481Seric printf("setclass(%c, %s)\n", class, str); 203168481Seric s = stab(str, ST_CLASS, ST_ENTER); 203210687Seric setbitn(class, s->s_class); 203310687Seric } 203453654Seric /* 203553654Seric ** MAKEMAPENTRY -- create a map entry 203653654Seric ** 203753654Seric ** Parameters: 203853654Seric ** line -- the config file line 203953654Seric ** 204053654Seric ** Returns: 204169774Seric ** A pointer to the map that has been created. 204269774Seric ** NULL if there was a syntax error. 204353654Seric ** 204453654Seric ** Side Effects: 204553654Seric ** Enters the map into the dictionary. 204653654Seric */ 204753654Seric 204869774Seric MAP * 204953654Seric makemapentry(line) 205053654Seric char *line; 205153654Seric { 205253654Seric register char *p; 205353654Seric char *mapname; 205453654Seric char *classname; 205564078Seric register STAB *s; 205653654Seric STAB *class; 205753654Seric 205858050Seric for (p = line; isascii(*p) && isspace(*p); p++) 205953654Seric continue; 206058050Seric if (!(isascii(*p) && isalnum(*p))) 206153654Seric { 206253654Seric syserr("readcf: config K line: no map name"); 206369774Seric return NULL; 206453654Seric } 206553654Seric 206653654Seric mapname = p; 206768481Seric while ((isascii(*++p) && isalnum(*p)) || *p == '.') 206853654Seric continue; 206953654Seric if (*p != '\0') 207053654Seric *p++ = '\0'; 207158050Seric while (isascii(*p) && isspace(*p)) 207253654Seric p++; 207358050Seric if (!(isascii(*p) && isalnum(*p))) 207453654Seric { 207553654Seric syserr("readcf: config K line, map %s: no map class", mapname); 207669774Seric return NULL; 207753654Seric } 207853654Seric classname = p; 207958050Seric while (isascii(*++p) && isalnum(*p)) 208053654Seric continue; 208153654Seric if (*p != '\0') 208253654Seric *p++ = '\0'; 208358050Seric while (isascii(*p) && isspace(*p)) 208453654Seric p++; 208553654Seric 208653654Seric /* look up the class */ 208753654Seric class = stab(classname, ST_MAPCLASS, ST_FIND); 208853654Seric if (class == NULL) 208953654Seric { 209053654Seric syserr("readcf: map %s: class %s not available", mapname, classname); 209169774Seric return NULL; 209253654Seric } 209353654Seric 209453654Seric /* enter the map */ 209564078Seric s = stab(mapname, ST_MAP, ST_ENTER); 209664078Seric s->s_map.map_class = &class->s_mapclass; 209764078Seric s->s_map.map_mname = newstr(mapname); 209853654Seric 209964078Seric if (class->s_mapclass.map_parse(&s->s_map, p)) 210064078Seric s->s_map.map_mflags |= MF_VALID; 210164078Seric 210264078Seric if (tTd(37, 5)) 210364078Seric { 210464078Seric printf("map %s, class %s, flags %x, file %s,\n", 210564078Seric s->s_map.map_mname, s->s_map.map_class->map_cname, 210664078Seric s->s_map.map_mflags, 210764078Seric s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 210864078Seric printf("\tapp %s, domain %s, rebuild %s\n", 210964078Seric s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 211064078Seric s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 211164078Seric s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 211264078Seric } 211369774Seric 211469774Seric return &s->s_map; 211553654Seric } 211658112Seric /* 211769783Seric ** STRTORWSET -- convert string to rewriting set number 211869783Seric ** 211969783Seric ** Parameters: 212069783Seric ** p -- the pointer to the string to decode. 212169783Seric ** endp -- if set, store the trailing delimiter here. 212269783Seric ** stabmode -- ST_ENTER to create this entry, ST_FIND if 212369783Seric ** it must already exist. 212469783Seric ** 212569783Seric ** Returns: 212669783Seric ** The appropriate ruleset number. 212769783Seric ** -1 if it is not valid (error already printed) 212869783Seric */ 212969783Seric 213069783Seric int 213169783Seric strtorwset(p, endp, stabmode) 213269783Seric char *p; 213369783Seric char **endp; 213469783Seric int stabmode; 213569783Seric { 213669783Seric int ruleset; 213769783Seric static int nextruleset = MAXRWSETS; 213869783Seric 213969783Seric while (isascii(*p) && isspace(*p)) 214069783Seric p++; 214169783Seric if (!isascii(*p)) 214269783Seric { 214369783Seric syserr("invalid ruleset name: \"%.20s\"", p); 214469783Seric return -1; 214569783Seric } 214669783Seric if (isdigit(*p)) 214769783Seric { 214869783Seric ruleset = strtol(p, endp, 10); 214969783Seric if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 215069783Seric { 215169783Seric syserr("bad ruleset %d (%d max)", 215269783Seric ruleset, MAXRWSETS / 2); 215369783Seric ruleset = -1; 215469783Seric } 215569783Seric } 215669783Seric else 215769783Seric { 215869783Seric STAB *s; 215969783Seric char delim; 216069783Seric char *q; 216169783Seric 216269783Seric q = p; 216369783Seric while (*p != '\0' && isascii(*p) && 216469783Seric (isalnum(*p) || strchr("-_$", *p) != NULL)) 216569783Seric p++; 216669783Seric while (isascii(*p) && isspace(*p)) 216769783Seric *p++ = '\0'; 216869783Seric delim = *p; 216969783Seric if (delim != '\0') 217069783Seric *p = '\0'; 217169783Seric s = stab(q, ST_RULESET, stabmode); 217269783Seric if (delim != '\0') 217369783Seric *p = delim; 217469783Seric 217569783Seric if (s == NULL) 217669783Seric { 217769783Seric syserr("unknown ruleset %s", q); 217869783Seric return -1; 217969783Seric } 218069783Seric 218169783Seric if (stabmode == ST_ENTER && delim == '=') 218269783Seric { 218369783Seric ruleset = strtol(p, endp, 10); 218469783Seric if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 218569783Seric { 218669783Seric syserr("bad ruleset %s = %d (%d max)", 218769783Seric q, ruleset, MAXRWSETS / 2); 218869783Seric ruleset = -1; 218969783Seric } 219069783Seric } 219169783Seric else 219269783Seric { 219369783Seric if (endp != NULL) 219469783Seric *endp = p; 219569783Seric if (s->s_ruleset > 0) 219669783Seric ruleset = s->s_ruleset; 219769783Seric else if ((ruleset = --nextruleset) < MAXRWSETS / 2) 219869783Seric { 219969783Seric syserr("%s: too many named rulesets (%d max)", 220069783Seric q, MAXRWSETS / 2); 220169783Seric ruleset = -1; 220269783Seric } 220369783Seric } 220469783Seric if (s->s_ruleset > 0 && ruleset >= 0 && ruleset != s->s_ruleset) 220569783Seric { 220669783Seric syserr("%s: ruleset changed value (old %d, new %d)", 220769783Seric q, ruleset, s->s_ruleset); 220869783Seric ruleset = s->s_ruleset; 220969783Seric } 221069783Seric else if (ruleset > 0) 221169783Seric { 221269783Seric s->s_ruleset = ruleset; 221369783Seric } 221469783Seric } 221569783Seric return ruleset; 221669783Seric } 221769783Seric /* 221868481Seric ** INITTIMEOUTS -- parse and set timeout values 221958112Seric ** 222058112Seric ** Parameters: 222158112Seric ** val -- a pointer to the values. If NULL, do initial 222258112Seric ** settings. 222358112Seric ** 222458112Seric ** Returns: 222558112Seric ** none. 222658112Seric ** 222758112Seric ** Side Effects: 222858112Seric ** Initializes the TimeOuts structure 222958112Seric */ 223058112Seric 223164255Seric #define SECONDS 223258112Seric #define MINUTES * 60 223358112Seric #define HOUR * 3600 223458112Seric 223569748Seric void 223668481Seric inittimeouts(val) 223758112Seric register char *val; 223858112Seric { 223958112Seric register char *p; 224058671Seric extern time_t convtime(); 224158112Seric 224258112Seric if (val == NULL) 224358112Seric { 224458112Seric TimeOuts.to_initial = (time_t) 5 MINUTES; 224558112Seric TimeOuts.to_helo = (time_t) 5 MINUTES; 224658112Seric TimeOuts.to_mail = (time_t) 10 MINUTES; 224758112Seric TimeOuts.to_rcpt = (time_t) 1 HOUR; 224858112Seric TimeOuts.to_datainit = (time_t) 5 MINUTES; 224958112Seric TimeOuts.to_datablock = (time_t) 1 HOUR; 225058112Seric TimeOuts.to_datafinal = (time_t) 1 HOUR; 225158112Seric TimeOuts.to_rset = (time_t) 5 MINUTES; 225258112Seric TimeOuts.to_quit = (time_t) 2 MINUTES; 225358112Seric TimeOuts.to_nextcommand = (time_t) 1 HOUR; 225458112Seric TimeOuts.to_miscshort = (time_t) 2 MINUTES; 225568481Seric #if IDENTPROTO 225664255Seric TimeOuts.to_ident = (time_t) 30 SECONDS; 225768481Seric #else 225868481Seric TimeOuts.to_ident = (time_t) 0 SECONDS; 225968481Seric #endif 226068481Seric TimeOuts.to_fileopen = (time_t) 60 SECONDS; 226158112Seric return; 226258112Seric } 226358112Seric 226458112Seric for (;; val = p) 226558112Seric { 226658112Seric while (isascii(*val) && isspace(*val)) 226758112Seric val++; 226858112Seric if (*val == '\0') 226958112Seric break; 227058112Seric for (p = val; *p != '\0' && *p != ','; p++) 227158112Seric continue; 227258112Seric if (*p != '\0') 227358112Seric *p++ = '\0'; 227458112Seric 227558112Seric if (isascii(*val) && isdigit(*val)) 227658112Seric { 227758112Seric /* old syntax -- set everything */ 227858796Seric TimeOuts.to_mail = convtime(val, 'm'); 227958112Seric TimeOuts.to_rcpt = TimeOuts.to_mail; 228058112Seric TimeOuts.to_datainit = TimeOuts.to_mail; 228158112Seric TimeOuts.to_datablock = TimeOuts.to_mail; 228258112Seric TimeOuts.to_datafinal = TimeOuts.to_mail; 228358112Seric TimeOuts.to_nextcommand = TimeOuts.to_mail; 228458112Seric continue; 228558112Seric } 228658112Seric else 228758112Seric { 228868481Seric register char *q = strchr(val, ':'); 228958112Seric 229068481Seric if (q == NULL && (q = strchr(val, '=')) == NULL) 229158112Seric { 229258112Seric /* syntax error */ 229358112Seric continue; 229458112Seric } 229558112Seric *q++ = '\0'; 229668481Seric settimeout(val, q); 229768481Seric } 229868481Seric } 229968481Seric } 230068481Seric /* 230168481Seric ** SETTIMEOUT -- set an individual timeout 230268481Seric ** 230368481Seric ** Parameters: 230468481Seric ** name -- the name of the timeout. 230568481Seric ** val -- the value of the timeout. 230668481Seric ** 230768481Seric ** Returns: 230868481Seric ** none. 230968481Seric */ 231058112Seric 231169748Seric void 231268481Seric settimeout(name, val) 231368481Seric char *name; 231468481Seric char *val; 231568481Seric { 231668481Seric register char *p; 231768481Seric time_t to; 231868481Seric extern time_t convtime(); 231968481Seric 232068481Seric to = convtime(val, 'm'); 232168481Seric p = strchr(name, '.'); 232268481Seric if (p != NULL) 232368481Seric *p++ = '\0'; 232468481Seric 232568481Seric if (strcasecmp(name, "initial") == 0) 232668481Seric TimeOuts.to_initial = to; 232768481Seric else if (strcasecmp(name, "mail") == 0) 232868481Seric TimeOuts.to_mail = to; 232968481Seric else if (strcasecmp(name, "rcpt") == 0) 233068481Seric TimeOuts.to_rcpt = to; 233168481Seric else if (strcasecmp(name, "datainit") == 0) 233268481Seric TimeOuts.to_datainit = to; 233368481Seric else if (strcasecmp(name, "datablock") == 0) 233468481Seric TimeOuts.to_datablock = to; 233568481Seric else if (strcasecmp(name, "datafinal") == 0) 233668481Seric TimeOuts.to_datafinal = to; 233768481Seric else if (strcasecmp(name, "command") == 0) 233868481Seric TimeOuts.to_nextcommand = to; 233968481Seric else if (strcasecmp(name, "rset") == 0) 234068481Seric TimeOuts.to_rset = to; 234168481Seric else if (strcasecmp(name, "helo") == 0) 234268481Seric TimeOuts.to_helo = to; 234368481Seric else if (strcasecmp(name, "quit") == 0) 234468481Seric TimeOuts.to_quit = to; 234568481Seric else if (strcasecmp(name, "misc") == 0) 234668481Seric TimeOuts.to_miscshort = to; 234768481Seric else if (strcasecmp(name, "ident") == 0) 234868481Seric TimeOuts.to_ident = to; 234968481Seric else if (strcasecmp(name, "fileopen") == 0) 235068481Seric TimeOuts.to_fileopen = to; 235168481Seric else if (strcasecmp(name, "queuewarn") == 0) 235268481Seric { 235368481Seric to = convtime(val, 'h'); 235468481Seric if (p == NULL || strcmp(p, "*") == 0) 235568481Seric { 235668481Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 235768481Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 235868481Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 235958112Seric } 236068481Seric else if (strcasecmp(p, "normal") == 0) 236168481Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 236268481Seric else if (strcasecmp(p, "urgent") == 0) 236368481Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 236468481Seric else if (strcasecmp(p, "non-urgent") == 0) 236568481Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 236668481Seric else 236768481Seric syserr("settimeout: invalid queuewarn subtimeout %s", p); 236858112Seric } 236968481Seric else if (strcasecmp(name, "queuereturn") == 0) 237068481Seric { 237168481Seric to = convtime(val, 'd'); 237268481Seric if (p == NULL || strcmp(p, "*") == 0) 237368481Seric { 237468481Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 237568481Seric TimeOuts.to_q_return[TOC_URGENT] = to; 237668481Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 237768481Seric } 237868481Seric else if (strcasecmp(p, "normal") == 0) 237968481Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 238068481Seric else if (strcasecmp(p, "urgent") == 0) 238168481Seric TimeOuts.to_q_return[TOC_URGENT] = to; 238268481Seric else if (strcasecmp(p, "non-urgent") == 0) 238368481Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 238468481Seric else 238568481Seric syserr("settimeout: invalid queuereturn subtimeout %s", p); 238668481Seric } 238768481Seric else 238868481Seric syserr("settimeout: invalid timeout %s", name); 238958112Seric } 2390