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*69783Seric static char sccsid[] = "@(#)readcf.c 8.98 (Berkeley) 05/30/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 */ 372*69783Seric ruleset = strtorwset(&bp[1], NULL, ST_ENTER); 3734072Seric rwp = NULL; 3744072Seric break; 3754072Seric 3763308Seric case 'D': /* macro definition */ 37768481Seric mid = macid(&bp[1], &ep); 37868481Seric p = munchstring(ep, NULL); 37968481Seric define(mid, newstr(p), e); 3803308Seric break; 3813308Seric 3823387Seric case 'H': /* required header line */ 38368717Seric (void) chompheader(&bp[1], TRUE, NULL, e); 3843387Seric break; 3853387Seric 3864061Seric case 'C': /* word class */ 38768481Seric case 'T': /* trusted user (set class `t') */ 38868481Seric if (bp[0] == 'C') 3894061Seric { 39068481Seric mid = macid(&bp[1], &ep); 39168529Seric expand(ep, exbuf, sizeof exbuf, e); 39268481Seric p = exbuf; 39368481Seric } 39468481Seric else 39568481Seric { 39668481Seric mid = 't'; 39768481Seric p = &bp[1]; 39868481Seric } 39968481Seric while (*p != '\0') 40068481Seric { 4014061Seric register char *wd; 4024061Seric char delim; 4034061Seric 40458050Seric while (*p != '\0' && isascii(*p) && isspace(*p)) 4054061Seric p++; 4064061Seric wd = p; 40758050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 4084061Seric p++; 4094061Seric delim = *p; 4104061Seric *p = '\0'; 4114061Seric if (wd[0] != '\0') 41268481Seric setclass(mid, wd); 4134061Seric *p = delim; 4144061Seric } 4154061Seric break; 4164061Seric 41759272Seric case 'F': /* word class from file */ 41868481Seric mid = macid(&bp[1], &ep); 41968481Seric for (p = ep; isascii(*p) && isspace(*p); ) 42064133Seric p++; 42164133Seric if (p[0] == '-' && p[1] == 'o') 42264133Seric { 42364133Seric optional = TRUE; 42464133Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 42564133Seric p++; 42664133Seric while (isascii(*p) && isspace(*p)) 42768481Seric p++; 42864133Seric } 42964133Seric else 43064133Seric optional = FALSE; 43164133Seric file = p; 43264133Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 43364133Seric p++; 43459272Seric if (*p == '\0') 43559272Seric p = "%s"; 43659272Seric else 43759272Seric { 43859272Seric *p = '\0'; 43959272Seric while (isascii(*++p) && isspace(*p)) 44059272Seric continue; 44159272Seric } 44264133Seric fileclass(bp[1], file, p, safe, optional); 44359272Seric break; 44459272Seric 44559156Seric #ifdef XLA 44659156Seric case 'L': /* extended load average description */ 44759156Seric xla_init(&bp[1]); 44859156Seric break; 44959156Seric #endif 45059156Seric 4514096Seric case 'M': /* define mailer */ 45257135Seric makemailer(&bp[1]); 4534096Seric break; 4544096Seric 4558252Seric case 'O': /* set option */ 45658734Seric setoption(bp[1], &bp[2], safe, FALSE, e); 4578252Seric break; 4588252Seric 4598252Seric case 'P': /* set precedence */ 4608252Seric if (NumPriorities >= MAXPRIORITIES) 4618252Seric { 4628547Seric toomany('P', MAXPRIORITIES); 4638252Seric break; 4648252Seric } 46557135Seric for (p = &bp[1]; *p != '\0' && *p != '=' && *p != '\t'; p++) 4668252Seric continue; 4678252Seric if (*p == '\0') 4688252Seric goto badline; 4698252Seric *p = '\0'; 47057135Seric Priorities[NumPriorities].pri_name = newstr(&bp[1]); 4718252Seric Priorities[NumPriorities].pri_val = atoi(++p); 4728252Seric NumPriorities++; 4738252Seric break; 4748252Seric 47552645Seric case 'V': /* configuration syntax version */ 47664440Seric for (p = &bp[1]; isascii(*p) && isspace(*p); p++) 47764440Seric continue; 47864440Seric if (!isascii(*p) || !isdigit(*p)) 47964440Seric { 48064440Seric syserr("invalid argument to V line: \"%.20s\"", 48164440Seric &bp[1]); 48264440Seric break; 48364440Seric } 48464718Seric ConfigLevel = strtol(p, &ep, 10); 48568805Seric 48668805Seric /* 48768805Seric ** Do heuristic tweaking for back compatibility. 48868805Seric */ 48968805Seric 49064279Seric if (ConfigLevel >= 5) 49164279Seric { 49264279Seric /* level 5 configs have short name in $w */ 49364279Seric p = macvalue('w', e); 49464279Seric if (p != NULL && (p = strchr(p, '.')) != NULL) 49564279Seric *p = '\0'; 49664279Seric } 49768805Seric if (ConfigLevel >= 6) 49868805Seric { 49968805Seric ColonOkInAddr = FALSE; 50068805Seric } 50168805Seric 50268805Seric /* 50368805Seric ** Look for vendor code. 50468805Seric */ 50568805Seric 50664718Seric if (*ep++ == '/') 50764718Seric { 50864718Seric /* extract vendor code */ 50964718Seric for (p = ep; isascii(*p) && isalpha(*p); ) 51064718Seric p++; 51164718Seric *p = '\0'; 51264718Seric 51364718Seric if (!setvendor(ep)) 51464718Seric syserr("invalid V line vendor code: \"%s\"", 51564718Seric ep); 51664718Seric } 51752645Seric break; 51852645Seric 51953654Seric case 'K': 52069774Seric (void) makemapentry(&bp[1]); 52153654Seric break; 52253654Seric 52369476Seric case 'E': 52469476Seric p = strchr(bp, '='); 52569476Seric if (p != NULL) 52669476Seric *p++ = '\0'; 52769476Seric setuserenv(&bp[1], p); 52869476Seric break; 52969476Seric 5303308Seric default: 5314061Seric badline: 53257135Seric syserr("unknown control line \"%s\"", bp); 5333308Seric } 53457135Seric if (bp != buf) 53557135Seric free(bp); 5363308Seric } 53752637Seric if (ferror(cf)) 53852637Seric { 53952647Seric syserr("I/O read error", cfname); 54052637Seric exit(EX_OSFILE); 54152637Seric } 54252637Seric fclose(cf); 5439381Seric FileName = NULL; 54456836Seric 54568481Seric /* initialize host maps from local service tables */ 54668481Seric inithostmaps(); 54768481Seric 54868481Seric /* determine if we need to do special name-server frotz */ 54967905Seric { 55068481Seric int nmaps; 55168481Seric char *maptype[MAXMAPSTACK]; 55268481Seric short mapreturn[MAXMAPACTIONS]; 55368481Seric 55468481Seric nmaps = switch_map_find("hosts", maptype, mapreturn); 55568481Seric UseNameServer = FALSE; 55668481Seric if (nmaps > 0 && nmaps <= MAXMAPSTACK) 55768481Seric { 55868481Seric register int mapno; 55968481Seric 56068481Seric for (mapno = 0; mapno < nmaps && !UseNameServer; mapno++) 56168481Seric { 56268481Seric if (strcmp(maptype[mapno], "dns") == 0) 56368481Seric UseNameServer = TRUE; 56468481Seric } 56568481Seric } 56668481Seric 56768481Seric #ifdef HESIOD 56868481Seric nmaps = switch_map_find("passwd", maptype, mapreturn); 56968481Seric UseHesiod = FALSE; 57068481Seric if (nmaps > 0 && nmaps <= MAXMAPSTACK) 57168481Seric { 57268481Seric register int mapno; 57368481Seric 57468481Seric for (mapno = 0; mapno < nmaps && !UseHesiod; mapno++) 57568481Seric { 57668481Seric if (strcmp(maptype[mapno], "hesiod") == 0) 57768481Seric UseHesiod = TRUE; 57868481Seric } 57968481Seric } 58068204Seric #endif 58167905Seric } 5824096Seric } 5834096Seric /* 5848547Seric ** TOOMANY -- signal too many of some option 5858547Seric ** 5868547Seric ** Parameters: 5878547Seric ** id -- the id of the error line 5888547Seric ** maxcnt -- the maximum possible values 5898547Seric ** 5908547Seric ** Returns: 5918547Seric ** none. 5928547Seric ** 5938547Seric ** Side Effects: 5948547Seric ** gives a syserr. 5958547Seric */ 5968547Seric 59769748Seric void 5988547Seric toomany(id, maxcnt) 59969748Seric int id; 6008547Seric int maxcnt; 6018547Seric { 6029381Seric syserr("too many %c lines, %d max", id, maxcnt); 6038547Seric } 6048547Seric /* 6054432Seric ** FILECLASS -- read members of a class from a file 6064432Seric ** 6074432Seric ** Parameters: 6084432Seric ** class -- class to define. 6094432Seric ** filename -- name of file to read. 6104432Seric ** fmt -- scanf string to use for match. 61164133Seric ** safe -- if set, this is a safe read. 61264133Seric ** optional -- if set, it is not an error for the file to 61364133Seric ** not exist. 6144432Seric ** 6154432Seric ** Returns: 6164432Seric ** none 6174432Seric ** 6184432Seric ** Side Effects: 6194432Seric ** 6204432Seric ** puts all lines in filename that match a scanf into 6214432Seric ** the named class. 6224432Seric */ 6234432Seric 62469748Seric void 62564133Seric fileclass(class, filename, fmt, safe, optional) 6264432Seric int class; 6274432Seric char *filename; 6284432Seric char *fmt; 62954973Seric bool safe; 63064133Seric bool optional; 6314432Seric { 63225808Seric FILE *f; 63368513Seric int sff; 63469453Seric int pid; 63569453Seric register char *p; 6364432Seric char buf[MAXLINE]; 6374432Seric 63866101Seric if (tTd(37, 2)) 63966101Seric printf("fileclass(%s, fmt=%s)\n", filename, fmt); 64066101Seric 64166031Seric if (filename[0] == '|') 64266031Seric { 64369453Seric auto int fd; 64469453Seric int i; 64569453Seric char *argv[MAXPV + 1]; 64669453Seric 64769453Seric i = 0; 64869453Seric for (p = strtok(&filename[1], " \t"); p != NULL; p = strtok(NULL, " \t")) 64969453Seric { 65069453Seric if (i >= MAXPV) 65169453Seric break; 65269453Seric argv[i++] = p; 65369453Seric } 65469453Seric argv[i] = NULL; 65569453Seric pid = prog_open(argv, &fd, CurEnv); 65669453Seric if (pid < 0) 65769453Seric f = NULL; 65869453Seric else 65969453Seric f = fdopen(fd, "r"); 66066031Seric } 66169453Seric else 66269453Seric { 66369453Seric pid = -1; 66469453Seric sff = SFF_REGONLY; 66569453Seric if (safe) 66669453Seric sff |= SFF_OPENASROOT; 66769453Seric f = safefopen(filename, O_RDONLY, 0, sff); 66869453Seric } 66968602Seric if (f == NULL) 67054973Seric { 67168602Seric if (!optional) 67268602Seric syserr("fileclass: cannot open %s", filename); 6734432Seric return; 6744432Seric } 6754432Seric 6764432Seric while (fgets(buf, sizeof buf, f) != NULL) 6774432Seric { 67825808Seric register char *p; 67925808Seric # ifdef SCANF 6804432Seric char wordbuf[MAXNAME+1]; 6814432Seric 6824432Seric if (sscanf(buf, fmt, wordbuf) != 1) 6834432Seric continue; 68425808Seric p = wordbuf; 68556795Seric # else /* SCANF */ 68625808Seric p = buf; 68756795Seric # endif /* SCANF */ 68825808Seric 68925808Seric /* 69025808Seric ** Break up the match into words. 69125808Seric */ 69225808Seric 69325808Seric while (*p != '\0') 69425808Seric { 69525808Seric register char *q; 69625808Seric 69725808Seric /* strip leading spaces */ 69858050Seric while (isascii(*p) && isspace(*p)) 69925808Seric p++; 70025808Seric if (*p == '\0') 70125808Seric break; 70225808Seric 70325808Seric /* find the end of the word */ 70425808Seric q = p; 70558050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 70625808Seric p++; 70725808Seric if (*p != '\0') 70825808Seric *p++ = '\0'; 70925808Seric 71025808Seric /* enter the word in the symbol table */ 71166101Seric setclass(class, q); 71225808Seric } 7134432Seric } 7144432Seric 71554973Seric (void) fclose(f); 71669453Seric if (pid > 0) 71769453Seric (void) waitfor(pid); 7184432Seric } 7194432Seric /* 7204096Seric ** MAKEMAILER -- define a new mailer. 7214096Seric ** 7224096Seric ** Parameters: 72310327Seric ** line -- description of mailer. This is in labeled 72410327Seric ** fields. The fields are: 72568481Seric ** A -- the argv for this mailer 72668481Seric ** C -- the character set for MIME conversions 72768481Seric ** D -- the directory to run in 72868481Seric ** E -- the eol string 72968481Seric ** F -- the flags associated with the mailer 73068481Seric ** L -- the maximum line length 73168481Seric ** M -- the maximum message size 73268816Seric ** N -- the niceness at which to run 73368479Seric ** P -- the path to the mailer 73468481Seric ** R -- the recipient rewriting set 73568479Seric ** S -- the sender rewriting set 73668481Seric ** T -- the mailer type (for DSNs) 73768481Seric ** U -- the uid to run as 73810327Seric ** The first word is the canonical name of the mailer. 7394096Seric ** 7404096Seric ** Returns: 7414096Seric ** none. 7424096Seric ** 7434096Seric ** Side Effects: 7444096Seric ** enters the mailer into the mailer table. 7454096Seric */ 7463308Seric 74769748Seric void 74821066Seric makemailer(line) 7494096Seric char *line; 7504096Seric { 7514096Seric register char *p; 7528067Seric register struct mailer *m; 7538067Seric register STAB *s; 7548067Seric int i; 75510327Seric char fcode; 75658020Seric auto char *endp; 7574096Seric extern int NextMailer; 75810327Seric extern char **makeargv(); 75910327Seric extern char *munchstring(); 7604096Seric 76110327Seric /* allocate a mailer and set up defaults */ 76210327Seric m = (struct mailer *) xalloc(sizeof *m); 76310327Seric bzero((char *) m, sizeof *m); 76410327Seric m->m_eol = "\n"; 76568481Seric m->m_uid = m->m_gid = 0; 76610327Seric 76710327Seric /* collect the mailer name */ 76858050Seric for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++) 76910327Seric continue; 77010327Seric if (*p != '\0') 77110327Seric *p++ = '\0'; 77210327Seric m->m_name = newstr(line); 77310327Seric 77410327Seric /* now scan through and assign info from the fields */ 77510327Seric while (*p != '\0') 77610327Seric { 77758333Seric auto char *delimptr; 77858333Seric 77958050Seric while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p)))) 78010327Seric p++; 78110327Seric 78210327Seric /* p now points to field code */ 78310327Seric fcode = *p; 78410327Seric while (*p != '\0' && *p != '=' && *p != ',') 78510327Seric p++; 78610327Seric if (*p++ != '=') 78710327Seric { 78852637Seric syserr("mailer %s: `=' expected", m->m_name); 78910327Seric return; 79010327Seric } 79158050Seric while (isascii(*p) && isspace(*p)) 79210327Seric p++; 79310327Seric 79410327Seric /* p now points to the field body */ 79558333Seric p = munchstring(p, &delimptr); 79610327Seric 79710327Seric /* install the field into the mailer struct */ 79810327Seric switch (fcode) 79910327Seric { 80010327Seric case 'P': /* pathname */ 80110327Seric m->m_mailer = newstr(p); 80210327Seric break; 80310327Seric 80410327Seric case 'F': /* flags */ 80510687Seric for (; *p != '\0'; p++) 80658050Seric if (!(isascii(*p) && isspace(*p))) 80752637Seric setbitn(*p, m->m_flags); 80810327Seric break; 80910327Seric 81010327Seric case 'S': /* sender rewriting ruleset */ 81110327Seric case 'R': /* recipient rewriting ruleset */ 812*69783Seric i = strtorwset(p, &endp, ST_ENTER); 813*69783Seric if (i < 0) 81410327Seric return; 81510327Seric if (fcode == 'S') 81658020Seric m->m_sh_rwset = m->m_se_rwset = i; 81710327Seric else 81858020Seric m->m_rh_rwset = m->m_re_rwset = i; 81958020Seric 82058020Seric p = endp; 82159985Seric if (*p++ == '/') 82258020Seric { 823*69783Seric i = strtorwset(p, NULL); 824*69783Seric if (i < 0) 82558020Seric return; 82658020Seric if (fcode == 'S') 82758020Seric m->m_sh_rwset = i; 82858020Seric else 82958020Seric m->m_rh_rwset = i; 83058020Seric } 83110327Seric break; 83210327Seric 83310327Seric case 'E': /* end of line string */ 83410327Seric m->m_eol = newstr(p); 83510327Seric break; 83610327Seric 83710327Seric case 'A': /* argument vector */ 83810327Seric m->m_argv = makeargv(p); 83910327Seric break; 84010701Seric 84110701Seric case 'M': /* maximum message size */ 84210701Seric m->m_maxsize = atol(p); 84310701Seric break; 84452106Seric 84552106Seric case 'L': /* maximum line length */ 84652106Seric m->m_linelimit = atoi(p); 84752106Seric break; 84858935Seric 84968816Seric case 'N': /* run niceness */ 85068816Seric m->m_nice = atoi(p); 85168816Seric break; 85268816Seric 85358935Seric case 'D': /* working directory */ 85458935Seric m->m_execdir = newstr(p); 85558935Seric break; 85668481Seric 85768481Seric case 'C': /* default charset */ 85868481Seric m->m_defcharset = newstr(p); 85968481Seric break; 86068481Seric 86169720Seric case 'T': /* MTA-Name/Address/Diagnostic types */ 86268481Seric m->m_mtatype = newstr(p); 86368481Seric p = strchr(m->m_mtatype, '/'); 86468481Seric if (p != NULL) 86568481Seric { 86668481Seric *p++ = '\0'; 86768481Seric if (*p == '\0') 86868481Seric p = NULL; 86968481Seric } 87068481Seric if (p == NULL) 87168481Seric m->m_addrtype = m->m_mtatype; 87268481Seric else 87368481Seric { 87468481Seric m->m_addrtype = p; 87568481Seric p = strchr(p, '/'); 87668481Seric } 87768481Seric if (p != NULL) 87868481Seric { 87968481Seric *p++ = '\0'; 88068481Seric if (*p == '\0') 88168481Seric p = NULL; 88268481Seric } 88368481Seric if (p == NULL) 88468481Seric m->m_diagtype = m->m_mtatype; 88568481Seric else 88668481Seric m->m_diagtype = p; 88768481Seric break; 88868481Seric 88968481Seric case 'U': /* user id */ 89068481Seric if (isascii(*p) && !isdigit(*p)) 89168481Seric { 89268481Seric char *q = p; 89368481Seric struct passwd *pw; 89468481Seric 89568481Seric while (isascii(*p) && isalnum(*p)) 89668481Seric p++; 89768481Seric while (isascii(*p) && isspace(*p)) 89868481Seric *p++ = '\0'; 89968481Seric if (*p != '\0') 90068481Seric *p++ = '\0'; 90168693Seric pw = sm_getpwnam(q); 90268481Seric if (pw == NULL) 90368481Seric syserr("readcf: mailer U= flag: unknown user %s", q); 90468481Seric else 90568481Seric { 90668481Seric m->m_uid = pw->pw_uid; 90768481Seric m->m_gid = pw->pw_gid; 90868481Seric } 90968481Seric } 91068481Seric else 91168481Seric { 91268481Seric auto char *q; 91368481Seric 91468481Seric m->m_uid = strtol(p, &q, 0); 91568481Seric p = q; 91668481Seric } 91768481Seric while (isascii(*p) && isspace(*p)) 91868481Seric p++; 91968481Seric if (*p == '\0') 92068481Seric break; 92168481Seric if (isascii(*p) && !isdigit(*p)) 92268481Seric { 92368481Seric char *q = p; 92468481Seric struct group *gr; 92568481Seric 92668481Seric while (isascii(*p) && isalnum(*p)) 92768481Seric p++; 92868481Seric *p++ = '\0'; 92968481Seric gr = getgrnam(q); 93068481Seric if (gr == NULL) 93168481Seric syserr("readcf: mailer U= flag: unknown group %s", q); 93268481Seric else 93368481Seric m->m_gid = gr->gr_gid; 93468481Seric } 93568481Seric else 93668481Seric { 93768481Seric m->m_gid = strtol(p, NULL, 0); 93868481Seric } 93968481Seric break; 94010327Seric } 94110327Seric 94258333Seric p = delimptr; 94310327Seric } 94410327Seric 94558321Seric /* do some rationality checking */ 94658321Seric if (m->m_argv == NULL) 94758321Seric { 94858321Seric syserr("M%s: A= argument required", m->m_name); 94958321Seric return; 95058321Seric } 95158321Seric if (m->m_mailer == NULL) 95258321Seric { 95358321Seric syserr("M%s: P= argument required", m->m_name); 95458321Seric return; 95558321Seric } 95658321Seric 9574096Seric if (NextMailer >= MAXMAILERS) 9584096Seric { 9599381Seric syserr("too many mailers defined (%d max)", MAXMAILERS); 9604096Seric return; 9614096Seric } 96257402Seric 96368481Seric /* do some heuristic cleanup for back compatibility */ 96468481Seric if (bitnset(M_LIMITS, m->m_flags)) 96568481Seric { 96668481Seric if (m->m_linelimit == 0) 96768481Seric m->m_linelimit = SMTPLINELIM; 96868481Seric if (ConfigLevel < 2) 96968481Seric setbitn(M_7BITS, m->m_flags); 97068481Seric } 97168481Seric 97268481Seric if (ConfigLevel < 6 && 97368481Seric (strcmp(m->m_mailer, "[IPC]") == 0 || 97468481Seric strcmp(m->m_mailer, "[TCP]") == 0)) 97568481Seric { 97668481Seric if (m->m_mtatype == NULL) 97768481Seric m->m_mtatype = "dns"; 97868481Seric if (m->m_addrtype == NULL) 97968481Seric m->m_addrtype = "rfc822"; 98068481Seric if (m->m_diagtype == NULL) 98168481Seric m->m_diagtype = "smtp"; 98268481Seric } 98368481Seric 98468481Seric /* enter the mailer into the symbol table */ 98510327Seric s = stab(m->m_name, ST_MAILER, ST_ENTER); 98657402Seric if (s->s_mailer != NULL) 98757402Seric { 98857402Seric i = s->s_mailer->m_mno; 98957402Seric free(s->s_mailer); 99057402Seric } 99157402Seric else 99257402Seric { 99357402Seric i = NextMailer++; 99457402Seric } 99557402Seric Mailer[i] = s->s_mailer = m; 99657454Seric m->m_mno = i; 99710327Seric } 99810327Seric /* 99910327Seric ** MUNCHSTRING -- translate a string into internal form. 100010327Seric ** 100110327Seric ** Parameters: 100210327Seric ** p -- the string to munch. 100358333Seric ** delimptr -- if non-NULL, set to the pointer of the 100458333Seric ** field delimiter character. 100510327Seric ** 100610327Seric ** Returns: 100710327Seric ** the munched string. 100810327Seric */ 10094096Seric 101010327Seric char * 101158333Seric munchstring(p, delimptr) 101210327Seric register char *p; 101358333Seric char **delimptr; 101410327Seric { 101510327Seric register char *q; 101610327Seric bool backslash = FALSE; 101710327Seric bool quotemode = FALSE; 101810327Seric static char buf[MAXLINE]; 10194096Seric 102010327Seric for (q = buf; *p != '\0'; p++) 10214096Seric { 102210327Seric if (backslash) 102310327Seric { 102410327Seric /* everything is roughly literal */ 102510357Seric backslash = FALSE; 102610327Seric switch (*p) 102710327Seric { 102810327Seric case 'r': /* carriage return */ 102910327Seric *q++ = '\r'; 103010327Seric continue; 103110327Seric 103210327Seric case 'n': /* newline */ 103310327Seric *q++ = '\n'; 103410327Seric continue; 103510327Seric 103610327Seric case 'f': /* form feed */ 103710327Seric *q++ = '\f'; 103810327Seric continue; 103910327Seric 104010327Seric case 'b': /* backspace */ 104110327Seric *q++ = '\b'; 104210327Seric continue; 104310327Seric } 104410327Seric *q++ = *p; 104510327Seric } 104610327Seric else 104710327Seric { 104810327Seric if (*p == '\\') 104910327Seric backslash = TRUE; 105010327Seric else if (*p == '"') 105110327Seric quotemode = !quotemode; 105210327Seric else if (quotemode || *p != ',') 105310327Seric *q++ = *p; 105410327Seric else 105510327Seric break; 105610327Seric } 10574096Seric } 10584096Seric 105958333Seric if (delimptr != NULL) 106058333Seric *delimptr = p; 106110327Seric *q++ = '\0'; 106210327Seric return (buf); 106310327Seric } 106410327Seric /* 106510327Seric ** MAKEARGV -- break up a string into words 106610327Seric ** 106710327Seric ** Parameters: 106810327Seric ** p -- the string to break up. 106910327Seric ** 107010327Seric ** Returns: 107110327Seric ** a char **argv (dynamically allocated) 107210327Seric ** 107310327Seric ** Side Effects: 107410327Seric ** munges p. 107510327Seric */ 10764096Seric 107710327Seric char ** 107810327Seric makeargv(p) 107910327Seric register char *p; 108010327Seric { 108110327Seric char *q; 108210327Seric int i; 108310327Seric char **avp; 108410327Seric char *argv[MAXPV + 1]; 108510327Seric 108610327Seric /* take apart the words */ 108710327Seric i = 0; 108810327Seric while (*p != '\0' && i < MAXPV) 10894096Seric { 109010327Seric q = p; 109158050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 109210327Seric p++; 109358050Seric while (isascii(*p) && isspace(*p)) 109410327Seric *p++ = '\0'; 109510327Seric argv[i++] = newstr(q); 10964096Seric } 109710327Seric argv[i++] = NULL; 10984096Seric 109910327Seric /* now make a copy of the argv */ 110010327Seric avp = (char **) xalloc(sizeof *avp * i); 110116893Seric bcopy((char *) argv, (char *) avp, sizeof *avp * i); 110210327Seric 110310327Seric return (avp); 11043308Seric } 11053308Seric /* 11063308Seric ** PRINTRULES -- print rewrite rules (for debugging) 11073308Seric ** 11083308Seric ** Parameters: 11093308Seric ** none. 11103308Seric ** 11113308Seric ** Returns: 11123308Seric ** none. 11133308Seric ** 11143308Seric ** Side Effects: 11153308Seric ** prints rewrite rules. 11163308Seric */ 11173308Seric 111869748Seric void 11193308Seric printrules() 11203308Seric { 11213308Seric register struct rewrite *rwp; 11224072Seric register int ruleset; 11233308Seric 11244072Seric for (ruleset = 0; ruleset < 10; ruleset++) 11253308Seric { 11264072Seric if (RewriteRules[ruleset] == NULL) 11274072Seric continue; 11288067Seric printf("\n----Rule Set %d:", ruleset); 11293308Seric 11304072Seric for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 11313308Seric { 11328067Seric printf("\nLHS:"); 11338067Seric printav(rwp->r_lhs); 11348067Seric printf("RHS:"); 11358067Seric printav(rwp->r_rhs); 11363308Seric } 11373308Seric } 11383308Seric } 113968481Seric /* 114068481Seric ** PRINTMAILER -- print mailer structure (for debugging) 114168481Seric ** 114268481Seric ** Parameters: 114368481Seric ** m -- the mailer to print 114468481Seric ** 114568481Seric ** Returns: 114668481Seric ** none. 114768481Seric */ 11484319Seric 114969748Seric void 115068481Seric printmailer(m) 115168481Seric register MAILER *m; 115268481Seric { 115368481Seric int j; 115468481Seric 115568481Seric printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld U=%d:%d F=", 115668481Seric m->m_mno, m->m_name, 115768481Seric m->m_mailer, m->m_se_rwset, m->m_sh_rwset, 115868481Seric m->m_re_rwset, m->m_rh_rwset, m->m_maxsize, 115968481Seric m->m_uid, m->m_gid); 116068481Seric for (j = '\0'; j <= '\177'; j++) 116168481Seric if (bitnset(j, m->m_flags)) 116268481Seric (void) putchar(j); 116368481Seric printf(" L=%d E=", m->m_linelimit); 116468481Seric xputs(m->m_eol); 116568481Seric if (m->m_defcharset != NULL) 116668481Seric printf(" C=%s", m->m_defcharset); 116768481Seric printf(" T=%s/%s/%s", 116868481Seric m->m_mtatype == NULL ? "<undefined>" : m->m_mtatype, 116968481Seric m->m_addrtype == NULL ? "<undefined>" : m->m_addrtype, 117068481Seric m->m_diagtype == NULL ? "<undefined>" : m->m_diagtype); 117168481Seric if (m->m_argv != NULL) 117268481Seric { 117368481Seric char **a = m->m_argv; 117468481Seric 117568481Seric printf(" A="); 117668481Seric while (*a != NULL) 117768481Seric { 117868481Seric if (a != m->m_argv) 117968481Seric printf(" "); 118068481Seric xputs(*a++); 118168481Seric } 118268481Seric } 118368481Seric printf("\n"); 118468481Seric } 11854096Seric /* 11868256Seric ** SETOPTION -- set global processing option 11878256Seric ** 11888256Seric ** Parameters: 11898256Seric ** opt -- option name. 11908256Seric ** val -- option value (as a text string). 119121755Seric ** safe -- set if this came from a configuration file. 119221755Seric ** Some options (if set from the command line) will 119321755Seric ** reset the user id to avoid security problems. 11948269Seric ** sticky -- if set, don't let other setoptions override 11958269Seric ** this value. 119658734Seric ** e -- the main envelope. 11978256Seric ** 11988256Seric ** Returns: 11998256Seric ** none. 12008256Seric ** 12018256Seric ** Side Effects: 12028256Seric ** Sets options as implied by the arguments. 12038256Seric */ 12048256Seric 120510687Seric static BITMAP StickyOpt; /* set if option is stuck */ 120669748Seric extern void settimeout __P((char *, char *)); 12078269Seric 120857207Seric 120966334Seric #if NAMED_BIND 121057207Seric 121157207Seric struct resolverflags 121257207Seric { 121357207Seric char *rf_name; /* name of the flag */ 121457207Seric long rf_bits; /* bits to set/clear */ 121557207Seric } ResolverFlags[] = 121657207Seric { 121757207Seric "debug", RES_DEBUG, 121857207Seric "aaonly", RES_AAONLY, 121957207Seric "usevc", RES_USEVC, 122057207Seric "primary", RES_PRIMARY, 122157207Seric "igntc", RES_IGNTC, 122257207Seric "recurse", RES_RECURSE, 122357207Seric "defnames", RES_DEFNAMES, 122457207Seric "stayopen", RES_STAYOPEN, 122557207Seric "dnsrch", RES_DNSRCH, 122665583Seric "true", 0, /* to avoid error on old syntax */ 122757207Seric NULL, 0 122857207Seric }; 122957207Seric 123057207Seric #endif 123157207Seric 123268481Seric struct optioninfo 123368481Seric { 123468481Seric char *o_name; /* long name of option */ 123568481Seric u_char o_code; /* short name of option */ 123668481Seric bool o_safe; /* safe for random people to use */ 123768481Seric } OptionTab[] = 123868481Seric { 123968481Seric "SevenBitInput", '7', TRUE, 124069480Seric #if MIME8TO7 124168481Seric "EightBitMode", '8', TRUE, 124269480Seric #endif 124368481Seric "AliasFile", 'A', FALSE, 124468481Seric "AliasWait", 'a', FALSE, 124568481Seric "BlankSub", 'B', FALSE, 124668481Seric "MinFreeBlocks", 'b', TRUE, 124768481Seric "CheckpointInterval", 'C', TRUE, 124868481Seric "HoldExpensive", 'c', FALSE, 124968481Seric "AutoRebuildAliases", 'D', FALSE, 125068481Seric "DeliveryMode", 'd', TRUE, 125168481Seric "ErrorHeader", 'E', FALSE, 125268481Seric "ErrorMode", 'e', TRUE, 125368481Seric "TempFileMode", 'F', FALSE, 125468481Seric "SaveFromLine", 'f', FALSE, 125568481Seric "MatchGECOS", 'G', FALSE, 125668481Seric "HelpFile", 'H', FALSE, 125768481Seric "MaxHopCount", 'h', FALSE, 125868569Seric "ResolverOptions", 'I', FALSE, 125968481Seric "IgnoreDots", 'i', TRUE, 126068481Seric "ForwardPath", 'J', FALSE, 126168481Seric "SendMimeErrors", 'j', TRUE, 126268481Seric "ConnectionCacheSize", 'k', FALSE, 126368481Seric "ConnectionCacheTimeout", 'K', FALSE, 126468481Seric "UseErrorsTo", 'l', FALSE, 126568481Seric "LogLevel", 'L', FALSE, 126668481Seric "MeToo", 'm', TRUE, 126768481Seric "CheckAliases", 'n', FALSE, 126868481Seric "OldStyleHeaders", 'o', TRUE, 126968481Seric "DaemonPortOptions", 'O', FALSE, 127068481Seric "PrivacyOptions", 'p', TRUE, 127168481Seric "PostmasterCopy", 'P', FALSE, 127268481Seric "QueueFactor", 'q', FALSE, 127368481Seric "QueueDirectory", 'Q', FALSE, 127468481Seric "DontPruneRoutes", 'R', FALSE, 127568481Seric "Timeout", 'r', TRUE, 127668481Seric "StatusFile", 'S', FALSE, 127768481Seric "SuperSafe", 's', TRUE, 127868481Seric "QueueTimeout", 'T', FALSE, 127968481Seric "TimeZoneSpec", 't', FALSE, 128068481Seric "UserDatabaseSpec", 'U', FALSE, 128168481Seric "DefaultUser", 'u', FALSE, 128268481Seric "FallbackMXhost", 'V', FALSE, 128368481Seric "Verbose", 'v', TRUE, 128468481Seric "TryNullMXList", 'w', TRUE, 128568481Seric "QueueLA", 'x', FALSE, 128668481Seric "RefuseLA", 'X', FALSE, 128768481Seric "RecipientFactor", 'y', FALSE, 128868569Seric "ForkEachJob", 'Y', FALSE, 128968481Seric "ClassFactor", 'z', FALSE, 129068569Seric "RetryFactor", 'Z', FALSE, 129168481Seric #define O_QUEUESORTORD 0x81 129268481Seric "QueueSortOrder", O_QUEUESORTORD, TRUE, 129369401Seric #define O_HOSTSFILE 0x82 129469401Seric "HostsFile", O_HOSTSFILE, FALSE, 129568481Seric #define O_MQA 0x83 129668481Seric "MinQueueAge", O_MQA, TRUE, 129768481Seric #define O_MHSA 0x84 129868481Seric /* 129968481Seric "MaxHostStatAge", O_MHSA, TRUE, 130068481Seric */ 130168481Seric #define O_DEFCHARSET 0x85 130268481Seric "DefaultCharSet", O_DEFCHARSET, TRUE, 130368481Seric #define O_SSFILE 0x86 130468481Seric "ServiceSwitchFile", O_SSFILE, FALSE, 130568481Seric #define O_DIALDELAY 0x87 130668481Seric "DialDelay", O_DIALDELAY, TRUE, 130768481Seric #define O_NORCPTACTION 0x88 130868481Seric "NoRecipientAction", O_NORCPTACTION, TRUE, 130968490Seric #define O_SAFEFILEENV 0x89 131068490Seric "SafeFileEnvironment", O_SAFEFILEENV, FALSE, 131168569Seric #define O_MAXMSGSIZE 0x8a 131268569Seric "MaxMessageSize", O_MAXMSGSIZE, FALSE, 131368756Seric #define O_COLONOKINADDR 0x8b 131468756Seric "ColonOkInAddr", O_COLONOKINADDR, TRUE, 131569724Seric #define O_MAXQUEUERUN 0x8c 131669724Seric "MaxQueueRunSize", O_MAXQUEUERUN, TRUE, 131768481Seric 131868481Seric NULL, '\0', FALSE, 131968481Seric }; 132068481Seric 132168481Seric 132268481Seric 132369748Seric void 132458734Seric setoption(opt, val, safe, sticky, e) 132569748Seric int opt; 13268256Seric char *val; 132721755Seric bool safe; 13288269Seric bool sticky; 132958734Seric register ENVELOPE *e; 13308256Seric { 133157207Seric register char *p; 133268481Seric register struct optioninfo *o; 133368481Seric char *subopt; 13348265Seric extern bool atobool(); 133512633Seric extern time_t convtime(); 133614879Seric extern int QueueLA; 133714879Seric extern int RefuseLA; 133864718Seric extern bool Warn_Q_option; 13398256Seric 134068481Seric errno = 0; 134168481Seric if (opt == ' ') 134268481Seric { 134368481Seric /* full word options */ 134468481Seric struct optioninfo *sel; 134568481Seric 134668481Seric p = strchr(val, '='); 134768481Seric if (p == NULL) 134868481Seric p = &val[strlen(val)]; 134968481Seric while (*--p == ' ') 135068481Seric continue; 135168481Seric while (*++p == ' ') 135268481Seric *p = '\0'; 135368481Seric if (p == val) 135468481Seric { 135568481Seric syserr("readcf: null option name"); 135668481Seric return; 135768481Seric } 135868481Seric if (*p == '=') 135968481Seric *p++ = '\0'; 136068481Seric while (*p == ' ') 136168481Seric p++; 136268481Seric subopt = strchr(val, '.'); 136368481Seric if (subopt != NULL) 136468481Seric *subopt++ = '\0'; 136568481Seric sel = NULL; 136668481Seric for (o = OptionTab; o->o_name != NULL; o++) 136768481Seric { 136868481Seric if (strncasecmp(o->o_name, val, strlen(val)) != 0) 136968481Seric continue; 137068481Seric if (strlen(o->o_name) == strlen(val)) 137168481Seric { 137268481Seric /* completely specified -- this must be it */ 137368481Seric sel = NULL; 137468481Seric break; 137568481Seric } 137668481Seric if (sel != NULL) 137768481Seric break; 137868481Seric sel = o; 137968481Seric } 138068481Seric if (sel != NULL && o->o_name == NULL) 138168481Seric o = sel; 138268481Seric else if (o->o_name == NULL) 138368481Seric { 138468481Seric syserr("readcf: unknown option name %s", val); 138568481Seric return; 138668481Seric } 138768481Seric else if (sel != NULL) 138868481Seric { 138968481Seric syserr("readcf: ambiguous option name %s (matches %s and %s)", 139068481Seric val, sel->o_name, o->o_name); 139168481Seric return; 139268481Seric } 139368481Seric if (strlen(val) != strlen(o->o_name)) 139468481Seric { 139568481Seric bool oldVerbose = Verbose; 139668481Seric 139768481Seric Verbose = TRUE; 139868481Seric message("Option %s used as abbreviation for %s", 139968481Seric val, o->o_name); 140068481Seric Verbose = oldVerbose; 140168481Seric } 140268481Seric opt = o->o_code; 140368481Seric val = p; 140468481Seric } 140568481Seric else 140668481Seric { 140768481Seric for (o = OptionTab; o->o_name != NULL; o++) 140868481Seric { 140968481Seric if (o->o_code == opt) 141068481Seric break; 141168481Seric } 141268481Seric subopt = NULL; 141368481Seric } 141468481Seric 14158256Seric if (tTd(37, 1)) 141668481Seric { 141768481Seric printf(isascii(opt) && isprint(opt) ? 141868481Seric "setoption %s (%c).%s=%s" : 141968481Seric "setoption %s (0x%x).%s=%s", 142068481Seric o->o_name == NULL ? "<unknown>" : o->o_name, 142168481Seric opt, 142268481Seric subopt == NULL ? "" : subopt, 142368481Seric val); 142468481Seric } 14258256Seric 14268256Seric /* 14278269Seric ** See if this option is preset for us. 14288256Seric */ 14298256Seric 143059731Seric if (!sticky && bitnset(opt, StickyOpt)) 14318269Seric { 14329341Seric if (tTd(37, 1)) 14339341Seric printf(" (ignored)\n"); 14348269Seric return; 14358269Seric } 14368269Seric 143721755Seric /* 143821755Seric ** Check to see if this option can be specified by this user. 143921755Seric */ 144021755Seric 144163787Seric if (!safe && RealUid == 0) 144221755Seric safe = TRUE; 144368481Seric if (!safe && !o->o_safe) 144421755Seric { 144539111Srick if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 144621755Seric { 144736582Sbostic if (tTd(37, 1)) 144836582Sbostic printf(" (unsafe)"); 144963787Seric if (RealUid != geteuid()) 145036582Sbostic { 145151210Seric if (tTd(37, 1)) 145251210Seric printf("(Resetting uid)"); 145363787Seric (void) setgid(RealGid); 145463787Seric (void) setuid(RealUid); 145536582Sbostic } 145621755Seric } 145721755Seric } 145851210Seric if (tTd(37, 1)) 145917985Seric printf("\n"); 14608269Seric 146168481Seric switch (opt & 0xff) 14628256Seric { 146359709Seric case '7': /* force seven-bit input */ 146468481Seric SevenBitInput = atobool(val); 146552106Seric break; 146652106Seric 146769480Seric #if MIME8TO7 146868481Seric case '8': /* handling of 8-bit input */ 146968481Seric switch (*val) 147068481Seric { 147168481Seric case 'm': /* convert 8-bit, convert MIME */ 147268481Seric MimeMode = MM_CVTMIME|MM_MIME8BIT; 147368481Seric break; 147468481Seric 147568481Seric case 'p': /* pass 8 bit, convert MIME */ 147668856Seric MimeMode = MM_CVTMIME|MM_PASS8BIT; 147768481Seric break; 147868481Seric 147968481Seric case 's': /* strict adherence */ 148068481Seric MimeMode = MM_CVTMIME; 148168481Seric break; 148268481Seric 148368856Seric #if 0 148468856Seric case 'r': /* reject 8-bit, don't convert MIME */ 148568856Seric MimeMode = 0; 148668856Seric break; 148768856Seric 148868856Seric case 'j': /* "just send 8" */ 148968856Seric MimeMode = MM_PASS8BIT; 149068856Seric break; 149168856Seric 149268481Seric case 'a': /* encode 8 bit if available */ 149368481Seric MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 149468481Seric break; 149568481Seric 149668481Seric case 'c': /* convert 8 bit to MIME, never 7 bit */ 149768481Seric MimeMode = MM_MIME8BIT; 149868481Seric break; 149968856Seric #endif 150068481Seric 150168481Seric default: 150268481Seric syserr("Unknown 8-bit mode %c", *val); 150368481Seric exit(EX_USAGE); 150468481Seric } 150568481Seric break; 150669480Seric #endif 150768481Seric 15088256Seric case 'A': /* set default alias file */ 15099381Seric if (val[0] == '\0') 151059672Seric setalias("aliases"); 15119381Seric else 151259672Seric setalias(val); 15138256Seric break; 15148256Seric 151517474Seric case 'a': /* look N minutes for "@:@" in alias file */ 151617474Seric if (val[0] == '\0') 151764796Seric SafeAlias = 5 * 60; /* five minutes */ 151817474Seric else 151964796Seric SafeAlias = convtime(val, 'm'); 152017474Seric break; 152117474Seric 152216843Seric case 'B': /* substitution for blank character */ 152316843Seric SpaceSub = val[0]; 152416843Seric if (SpaceSub == '\0') 152516843Seric SpaceSub = ' '; 152616843Seric break; 152716843Seric 152859283Seric case 'b': /* min blocks free on queue fs/max msg size */ 152959283Seric p = strchr(val, '/'); 153059283Seric if (p != NULL) 153159283Seric { 153259283Seric *p++ = '\0'; 153359283Seric MaxMessageSize = atol(p); 153459283Seric } 153558082Seric MinBlocksFree = atol(val); 153658082Seric break; 153758082Seric 15389284Seric case 'c': /* don't connect to "expensive" mailers */ 15399381Seric NoConnect = atobool(val); 15409284Seric break; 15419284Seric 154251305Seric case 'C': /* checkpoint every N addresses */ 154351305Seric CheckpointInterval = atoi(val); 154424944Seric break; 154524944Seric 15469284Seric case 'd': /* delivery mode */ 15479284Seric switch (*val) 15488269Seric { 15499284Seric case '\0': 155058734Seric e->e_sendmode = SM_DELIVER; 15518269Seric break; 15528269Seric 155310755Seric case SM_QUEUE: /* queue only */ 155410755Seric #ifndef QUEUE 155510755Seric syserr("need QUEUE to set -odqueue"); 155656795Seric #endif /* QUEUE */ 155710755Seric /* fall through..... */ 155810755Seric 15599284Seric case SM_DELIVER: /* do everything */ 15609284Seric case SM_FORK: /* fork after verification */ 156158734Seric e->e_sendmode = *val; 15628269Seric break; 15638269Seric 15648269Seric default: 15659284Seric syserr("Unknown delivery mode %c", *val); 15668269Seric exit(EX_USAGE); 15678269Seric } 15688269Seric break; 15698269Seric 15709146Seric case 'D': /* rebuild alias database as needed */ 15719381Seric AutoRebuild = atobool(val); 15729146Seric break; 15739146Seric 157455372Seric case 'E': /* error message header/header file */ 157555379Seric if (*val != '\0') 157655379Seric ErrMsgFile = newstr(val); 157755372Seric break; 157855372Seric 15798269Seric case 'e': /* set error processing mode */ 15808269Seric switch (*val) 15818269Seric { 15829381Seric case EM_QUIET: /* be silent about it */ 15839381Seric case EM_MAIL: /* mail back */ 15849381Seric case EM_BERKNET: /* do berknet error processing */ 15859381Seric case EM_WRITE: /* write back (or mail) */ 15869381Seric case EM_PRINT: /* print errors normally (default) */ 158758734Seric e->e_errormode = *val; 15888269Seric break; 15898269Seric } 15908269Seric break; 15918269Seric 15929049Seric case 'F': /* file mode */ 159317975Seric FileMode = atooct(val) & 0777; 15949049Seric break; 15959049Seric 15968269Seric case 'f': /* save Unix-style From lines on front */ 15979381Seric SaveFrom = atobool(val); 15988269Seric break; 15998269Seric 160053735Seric case 'G': /* match recipients against GECOS field */ 160153735Seric MatchGecos = atobool(val); 160253735Seric break; 160353735Seric 16048256Seric case 'g': /* default gid */ 160568481Seric g_opt: 160664133Seric if (isascii(*val) && isdigit(*val)) 160764133Seric DefGid = atoi(val); 160864133Seric else 160964133Seric { 161064133Seric register struct group *gr; 161164133Seric 161264133Seric DefGid = -1; 161364133Seric gr = getgrnam(val); 161464133Seric if (gr == NULL) 161568481Seric syserr("readcf: option %c: unknown group %s", 161668481Seric opt, val); 161764133Seric else 161864133Seric DefGid = gr->gr_gid; 161964133Seric } 16208256Seric break; 16218256Seric 16228256Seric case 'H': /* help file */ 16239381Seric if (val[0] == '\0') 16248269Seric HelpFile = "sendmail.hf"; 16259381Seric else 16269381Seric HelpFile = newstr(val); 16278256Seric break; 16288256Seric 162951305Seric case 'h': /* maximum hop count */ 163051305Seric MaxHopCount = atoi(val); 163151305Seric break; 163251305Seric 163335651Seric case 'I': /* use internet domain name server */ 163466334Seric #if NAMED_BIND 163557207Seric for (p = val; *p != 0; ) 163657207Seric { 163757207Seric bool clearmode; 163857207Seric char *q; 163957207Seric struct resolverflags *rfp; 164057207Seric 164157207Seric while (*p == ' ') 164257207Seric p++; 164357207Seric if (*p == '\0') 164457207Seric break; 164557207Seric clearmode = FALSE; 164657207Seric if (*p == '-') 164757207Seric clearmode = TRUE; 164857207Seric else if (*p != '+') 164957207Seric p--; 165057207Seric p++; 165157207Seric q = p; 165258050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 165357207Seric p++; 165457207Seric if (*p != '\0') 165557207Seric *p++ = '\0'; 165668759Seric if (strcasecmp(q, "HasWildcardMX") == 0) 165768759Seric { 165868759Seric NoMXforCanon = !clearmode; 165968759Seric continue; 166068759Seric } 166157207Seric for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 166257207Seric { 166357207Seric if (strcasecmp(q, rfp->rf_name) == 0) 166457207Seric break; 166557207Seric } 166664923Seric if (rfp->rf_name == NULL) 166764923Seric syserr("readcf: I option value %s unrecognized", q); 166864923Seric else if (clearmode) 166957207Seric _res.options &= ~rfp->rf_bits; 167057207Seric else 167157207Seric _res.options |= rfp->rf_bits; 167257207Seric } 167357207Seric if (tTd(8, 2)) 167468759Seric printf("_res.options = %x, HasWildcardMX = %d\n", 167568759Seric _res.options, !NoMXforCanon); 167657207Seric #else 167757207Seric usrerr("name server (I option) specified but BIND not compiled in"); 167857207Seric #endif 167935651Seric break; 168035651Seric 16818269Seric case 'i': /* ignore dot lines in message */ 16829381Seric IgnrDot = atobool(val); 16838269Seric break; 16848269Seric 168559730Seric case 'j': /* send errors in MIME (RFC 1341) format */ 168659730Seric SendMIMEErrors = atobool(val); 168759730Seric break; 168859730Seric 168957136Seric case 'J': /* .forward search path */ 169057136Seric ForwardPath = newstr(val); 169157136Seric break; 169257136Seric 169354967Seric case 'k': /* connection cache size */ 169454967Seric MaxMciCache = atoi(val); 169556215Seric if (MaxMciCache < 0) 169656215Seric MaxMciCache = 0; 169754967Seric break; 169854967Seric 169954967Seric case 'K': /* connection cache timeout */ 170058796Seric MciCacheTimeout = convtime(val, 'm'); 170154967Seric break; 170254967Seric 170361104Seric case 'l': /* use Errors-To: header */ 170461104Seric UseErrorsTo = atobool(val); 170561104Seric break; 170661104Seric 17078256Seric case 'L': /* log level */ 170864140Seric if (safe || LogLevel < atoi(val)) 170964140Seric LogLevel = atoi(val); 17108256Seric break; 17118256Seric 17128269Seric case 'M': /* define macro */ 171368267Seric p = newstr(&val[1]); 171468267Seric if (!safe) 171568267Seric cleanstrcpy(p, p, MAXNAME); 171668267Seric define(val[0], p, CurEnv); 171716878Seric sticky = FALSE; 17188269Seric break; 17198269Seric 17208269Seric case 'm': /* send to me too */ 17219381Seric MeToo = atobool(val); 17228269Seric break; 17238269Seric 172425820Seric case 'n': /* validate RHS in newaliases */ 172525820Seric CheckAliases = atobool(val); 172625820Seric break; 172725820Seric 172861104Seric /* 'N' available -- was "net name" */ 172961104Seric 173058851Seric case 'O': /* daemon options */ 173158851Seric setdaemonoptions(val); 173258851Seric break; 173358851Seric 17348269Seric case 'o': /* assume old style headers */ 17359381Seric if (atobool(val)) 17369341Seric CurEnv->e_flags |= EF_OLDSTYLE; 17379341Seric else 17389341Seric CurEnv->e_flags &= ~EF_OLDSTYLE; 17398269Seric break; 17408269Seric 174158082Seric case 'p': /* select privacy level */ 174258082Seric p = val; 174358082Seric for (;;) 174458082Seric { 174558082Seric register struct prival *pv; 174658082Seric extern struct prival PrivacyValues[]; 174758082Seric 174858082Seric while (isascii(*p) && (isspace(*p) || ispunct(*p))) 174958082Seric p++; 175058082Seric if (*p == '\0') 175158082Seric break; 175258082Seric val = p; 175358082Seric while (isascii(*p) && isalnum(*p)) 175458082Seric p++; 175558082Seric if (*p != '\0') 175658082Seric *p++ = '\0'; 175758082Seric 175858082Seric for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 175958082Seric { 176058082Seric if (strcasecmp(val, pv->pv_name) == 0) 176158082Seric break; 176258082Seric } 176358886Seric if (pv->pv_name == NULL) 176458886Seric syserr("readcf: Op line: %s unrecognized", val); 176558082Seric PrivacyFlags |= pv->pv_flag; 176658082Seric } 176768479Seric sticky = FALSE; 176858082Seric break; 176958082Seric 177024944Seric case 'P': /* postmaster copy address for returned mail */ 177124944Seric PostMasterCopy = newstr(val); 177224944Seric break; 177324944Seric 177424944Seric case 'q': /* slope of queue only function */ 177524944Seric QueueFactor = atoi(val); 177624944Seric break; 177724944Seric 17788256Seric case 'Q': /* queue directory */ 17799381Seric if (val[0] == '\0') 17808269Seric QueueDir = "mqueue"; 17819381Seric else 17829381Seric QueueDir = newstr(val); 178358789Seric if (RealUid != 0 && !safe) 178464718Seric Warn_Q_option = TRUE; 17858256Seric break; 17868256Seric 178758148Seric case 'R': /* don't prune routes */ 178858148Seric DontPruneRoutes = atobool(val); 178958148Seric break; 179058148Seric 17918256Seric case 'r': /* read timeout */ 179268481Seric if (subopt == NULL) 179368481Seric inittimeouts(val); 179468481Seric else 179568481Seric settimeout(subopt, val); 17968256Seric break; 17978256Seric 17988256Seric case 'S': /* status file */ 17999381Seric if (val[0] == '\0') 18008269Seric StatFile = "sendmail.st"; 18019381Seric else 18029381Seric StatFile = newstr(val); 18038256Seric break; 18048256Seric 18058265Seric case 's': /* be super safe, even if expensive */ 18069381Seric SuperSafe = atobool(val); 18078256Seric break; 18088256Seric 18098256Seric case 'T': /* queue timeout */ 181058737Seric p = strchr(val, '/'); 181158737Seric if (p != NULL) 181258737Seric { 181358737Seric *p++ = '\0'; 181468481Seric settimeout("queuewarn", p); 181558737Seric } 181668481Seric settimeout("queuereturn", val); 181754967Seric break; 18188256Seric 18198265Seric case 't': /* time zone name */ 182052106Seric TimeZoneSpec = newstr(val); 18218265Seric break; 18228265Seric 182350556Seric case 'U': /* location of user database */ 182451360Seric UdbSpec = newstr(val); 182550556Seric break; 182650556Seric 18278256Seric case 'u': /* set default uid */ 182868481Seric for (p = val; *p != '\0'; p++) 182968481Seric { 183068481Seric if (*p == '.' || *p == '/' || *p == ':') 183168481Seric { 183268481Seric *p++ = '\0'; 183368481Seric break; 183468481Seric } 183568481Seric } 183664133Seric if (isascii(*val) && isdigit(*val)) 183764133Seric DefUid = atoi(val); 183864133Seric else 183964133Seric { 184064133Seric register struct passwd *pw; 184164133Seric 184264133Seric DefUid = -1; 184368693Seric pw = sm_getpwnam(val); 184464133Seric if (pw == NULL) 184564133Seric syserr("readcf: option u: unknown user %s", val); 184664133Seric else 184768481Seric { 184864133Seric DefUid = pw->pw_uid; 184968481Seric DefGid = pw->pw_gid; 185068481Seric } 185164133Seric } 185240973Sbostic setdefuser(); 18538256Seric 185468481Seric /* handle the group if it is there */ 185568481Seric if (*p == '\0') 185668481Seric break; 185768481Seric val = p; 185868481Seric goto g_opt; 185968481Seric 186058851Seric case 'V': /* fallback MX host */ 186158851Seric FallBackMX = newstr(val); 186258851Seric break; 186358851Seric 18648269Seric case 'v': /* run in verbose mode */ 18659381Seric Verbose = atobool(val); 18668256Seric break; 18678256Seric 186863837Seric case 'w': /* if we are best MX, try host directly */ 186963837Seric TryNullMXList = atobool(val); 187063837Seric break; 187161104Seric 187261104Seric /* 'W' available -- was wizard password */ 187361104Seric 187414879Seric case 'x': /* load avg at which to auto-queue msgs */ 187514879Seric QueueLA = atoi(val); 187614879Seric break; 187714879Seric 187814879Seric case 'X': /* load avg at which to auto-reject connections */ 187914879Seric RefuseLA = atoi(val); 188014879Seric break; 188114879Seric 188224981Seric case 'y': /* work recipient factor */ 188324981Seric WkRecipFact = atoi(val); 188424981Seric break; 188524981Seric 188624981Seric case 'Y': /* fork jobs during queue runs */ 188724952Seric ForkQueueRuns = atobool(val); 188824952Seric break; 188924952Seric 189024981Seric case 'z': /* work message class factor */ 189124981Seric WkClassFact = atoi(val); 189224981Seric break; 189324981Seric 189424981Seric case 'Z': /* work time factor */ 189524981Seric WkTimeFact = atoi(val); 189624981Seric break; 189724981Seric 189868481Seric case O_QUEUESORTORD: /* queue sorting order */ 189968481Seric switch (*val) 190068481Seric { 190168481Seric case 'h': /* Host first */ 190268481Seric case 'H': 190368481Seric QueueSortOrder = QS_BYHOST; 190468481Seric break; 190568481Seric 190668481Seric case 'p': /* Priority order */ 190768481Seric case 'P': 190868481Seric QueueSortOrder = QS_BYPRIORITY; 190968481Seric break; 191068481Seric 191168481Seric default: 191268481Seric syserr("Invalid queue sort order \"%s\"", val); 191368481Seric } 191468481Seric break; 191568481Seric 191669401Seric case O_HOSTSFILE: /* pathname of /etc/hosts file */ 191769401Seric HostsFile = newstr(val); 191869401Seric break; 191969401Seric 192068481Seric case O_MQA: /* minimum queue age between deliveries */ 192168481Seric MinQueueAge = convtime(val, 'm'); 192268481Seric break; 192368481Seric 192468481Seric case O_MHSA: /* maximum age of cached host status */ 192568481Seric MaxHostStatAge = convtime(val, 'm'); 192668481Seric break; 192768481Seric 192868481Seric case O_DEFCHARSET: /* default character set for mimefying */ 192968481Seric DefaultCharSet = newstr(denlstring(val, TRUE, TRUE)); 193068481Seric break; 193168481Seric 193268481Seric case O_SSFILE: /* service switch file */ 193368481Seric ServiceSwitchFile = newstr(val); 193468481Seric break; 193568481Seric 193668481Seric case O_DIALDELAY: /* delay for dial-on-demand operation */ 193768481Seric DialDelay = convtime(val, 's'); 193868481Seric break; 193968481Seric 194068481Seric case O_NORCPTACTION: /* what to do if no recipient */ 194168481Seric if (strcasecmp(val, "none") == 0) 194268481Seric NoRecipientAction = NRA_NO_ACTION; 194368481Seric else if (strcasecmp(val, "add-to") == 0) 194468481Seric NoRecipientAction = NRA_ADD_TO; 194568481Seric else if (strcasecmp(val, "add-apparently-to") == 0) 194668481Seric NoRecipientAction = NRA_ADD_APPARENTLY_TO; 194768481Seric else if (strcasecmp(val, "add-bcc") == 0) 194868481Seric NoRecipientAction = NRA_ADD_BCC; 194968481Seric else if (strcasecmp(val, "add-to-undisclosed") == 0) 195068481Seric NoRecipientAction = NRA_ADD_TO_UNDISCLOSED; 195168481Seric else 195268481Seric syserr("Invalid NoRecipientAction: %s", val); 195368481Seric 195468490Seric case O_SAFEFILEENV: /* chroot() environ for writing to files */ 195568490Seric SafeFileEnv = newstr(val); 195668490Seric break; 195768490Seric 195868569Seric case O_MAXMSGSIZE: /* maximum message size */ 195969748Seric MaxMessageSize = atol(val); 196068569Seric break; 196168569Seric 196268756Seric case O_COLONOKINADDR: /* old style handling of colon addresses */ 196369748Seric ColonOkInAddr = atobool(val); 196468756Seric break; 196568756Seric 196669724Seric case O_MAXQUEUERUN: /* max # of jobs in a single queue run */ 196769748Seric MaxQueueRun = atol(val); 196869724Seric break; 196969724Seric 19708256Seric default: 197168481Seric if (tTd(37, 1)) 197268481Seric { 197368481Seric if (isascii(opt) && isprint(opt)) 197468481Seric printf("Warning: option %c unknown\n", opt); 197568481Seric else 197668481Seric printf("Warning: option 0x%x unknown\n", opt); 197768481Seric } 19788256Seric break; 19798256Seric } 198016878Seric if (sticky) 198116878Seric setbitn(opt, StickyOpt); 19828256Seric } 198310687Seric /* 198468481Seric ** SETCLASS -- set a string into a class 198510687Seric ** 198610687Seric ** Parameters: 198768481Seric ** class -- the class to put the string in. 198868481Seric ** str -- the string to enter 198910687Seric ** 199010687Seric ** Returns: 199110687Seric ** none. 199210687Seric ** 199310687Seric ** Side Effects: 199410687Seric ** puts the word into the symbol table. 199510687Seric */ 199610687Seric 199769748Seric void 199868481Seric setclass(class, str) 199910687Seric int class; 200068481Seric char *str; 200110687Seric { 200210687Seric register STAB *s; 200310687Seric 200457943Seric if (tTd(37, 8)) 200568481Seric printf("setclass(%c, %s)\n", class, str); 200668481Seric s = stab(str, ST_CLASS, ST_ENTER); 200710687Seric setbitn(class, s->s_class); 200810687Seric } 200953654Seric /* 201053654Seric ** MAKEMAPENTRY -- create a map entry 201153654Seric ** 201253654Seric ** Parameters: 201353654Seric ** line -- the config file line 201453654Seric ** 201553654Seric ** Returns: 201669774Seric ** A pointer to the map that has been created. 201769774Seric ** NULL if there was a syntax error. 201853654Seric ** 201953654Seric ** Side Effects: 202053654Seric ** Enters the map into the dictionary. 202153654Seric */ 202253654Seric 202369774Seric MAP * 202453654Seric makemapentry(line) 202553654Seric char *line; 202653654Seric { 202753654Seric register char *p; 202853654Seric char *mapname; 202953654Seric char *classname; 203064078Seric register STAB *s; 203153654Seric STAB *class; 203253654Seric 203358050Seric for (p = line; isascii(*p) && isspace(*p); p++) 203453654Seric continue; 203558050Seric if (!(isascii(*p) && isalnum(*p))) 203653654Seric { 203753654Seric syserr("readcf: config K line: no map name"); 203869774Seric return NULL; 203953654Seric } 204053654Seric 204153654Seric mapname = p; 204268481Seric while ((isascii(*++p) && isalnum(*p)) || *p == '.') 204353654Seric continue; 204453654Seric if (*p != '\0') 204553654Seric *p++ = '\0'; 204658050Seric while (isascii(*p) && isspace(*p)) 204753654Seric p++; 204858050Seric if (!(isascii(*p) && isalnum(*p))) 204953654Seric { 205053654Seric syserr("readcf: config K line, map %s: no map class", mapname); 205169774Seric return NULL; 205253654Seric } 205353654Seric classname = p; 205458050Seric while (isascii(*++p) && isalnum(*p)) 205553654Seric continue; 205653654Seric if (*p != '\0') 205753654Seric *p++ = '\0'; 205858050Seric while (isascii(*p) && isspace(*p)) 205953654Seric p++; 206053654Seric 206153654Seric /* look up the class */ 206253654Seric class = stab(classname, ST_MAPCLASS, ST_FIND); 206353654Seric if (class == NULL) 206453654Seric { 206553654Seric syserr("readcf: map %s: class %s not available", mapname, classname); 206669774Seric return NULL; 206753654Seric } 206853654Seric 206953654Seric /* enter the map */ 207064078Seric s = stab(mapname, ST_MAP, ST_ENTER); 207164078Seric s->s_map.map_class = &class->s_mapclass; 207264078Seric s->s_map.map_mname = newstr(mapname); 207353654Seric 207464078Seric if (class->s_mapclass.map_parse(&s->s_map, p)) 207564078Seric s->s_map.map_mflags |= MF_VALID; 207664078Seric 207764078Seric if (tTd(37, 5)) 207864078Seric { 207964078Seric printf("map %s, class %s, flags %x, file %s,\n", 208064078Seric s->s_map.map_mname, s->s_map.map_class->map_cname, 208164078Seric s->s_map.map_mflags, 208264078Seric s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 208364078Seric printf("\tapp %s, domain %s, rebuild %s\n", 208464078Seric s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 208564078Seric s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 208664078Seric s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 208764078Seric } 208869774Seric 208969774Seric return &s->s_map; 209053654Seric } 209158112Seric /* 2092*69783Seric ** STRTORWSET -- convert string to rewriting set number 2093*69783Seric ** 2094*69783Seric ** Parameters: 2095*69783Seric ** p -- the pointer to the string to decode. 2096*69783Seric ** endp -- if set, store the trailing delimiter here. 2097*69783Seric ** stabmode -- ST_ENTER to create this entry, ST_FIND if 2098*69783Seric ** it must already exist. 2099*69783Seric ** 2100*69783Seric ** Returns: 2101*69783Seric ** The appropriate ruleset number. 2102*69783Seric ** -1 if it is not valid (error already printed) 2103*69783Seric */ 2104*69783Seric 2105*69783Seric int 2106*69783Seric strtorwset(p, endp, stabmode) 2107*69783Seric char *p; 2108*69783Seric char **endp; 2109*69783Seric int stabmode; 2110*69783Seric { 2111*69783Seric int ruleset; 2112*69783Seric static int nextruleset = MAXRWSETS; 2113*69783Seric 2114*69783Seric while (isascii(*p) && isspace(*p)) 2115*69783Seric p++; 2116*69783Seric if (!isascii(*p)) 2117*69783Seric { 2118*69783Seric syserr("invalid ruleset name: \"%.20s\"", p); 2119*69783Seric return -1; 2120*69783Seric } 2121*69783Seric if (isdigit(*p)) 2122*69783Seric { 2123*69783Seric ruleset = strtol(p, endp, 10); 2124*69783Seric if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 2125*69783Seric { 2126*69783Seric syserr("bad ruleset %d (%d max)", 2127*69783Seric ruleset, MAXRWSETS / 2); 2128*69783Seric ruleset = -1; 2129*69783Seric } 2130*69783Seric } 2131*69783Seric else 2132*69783Seric { 2133*69783Seric STAB *s; 2134*69783Seric char delim; 2135*69783Seric char *q; 2136*69783Seric 2137*69783Seric q = p; 2138*69783Seric while (*p != '\0' && isascii(*p) && 2139*69783Seric (isalnum(*p) || strchr("-_$", *p) != NULL)) 2140*69783Seric p++; 2141*69783Seric while (isascii(*p) && isspace(*p)) 2142*69783Seric *p++ = '\0'; 2143*69783Seric delim = *p; 2144*69783Seric if (delim != '\0') 2145*69783Seric *p = '\0'; 2146*69783Seric s = stab(q, ST_RULESET, stabmode); 2147*69783Seric if (delim != '\0') 2148*69783Seric *p = delim; 2149*69783Seric 2150*69783Seric if (s == NULL) 2151*69783Seric { 2152*69783Seric syserr("unknown ruleset %s", q); 2153*69783Seric return -1; 2154*69783Seric } 2155*69783Seric 2156*69783Seric if (stabmode == ST_ENTER && delim == '=') 2157*69783Seric { 2158*69783Seric ruleset = strtol(p, endp, 10); 2159*69783Seric if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 2160*69783Seric { 2161*69783Seric syserr("bad ruleset %s = %d (%d max)", 2162*69783Seric q, ruleset, MAXRWSETS / 2); 2163*69783Seric ruleset = -1; 2164*69783Seric } 2165*69783Seric } 2166*69783Seric else 2167*69783Seric { 2168*69783Seric if (endp != NULL) 2169*69783Seric *endp = p; 2170*69783Seric if (s->s_ruleset > 0) 2171*69783Seric ruleset = s->s_ruleset; 2172*69783Seric else if ((ruleset = --nextruleset) < MAXRWSETS / 2) 2173*69783Seric { 2174*69783Seric syserr("%s: too many named rulesets (%d max)", 2175*69783Seric q, MAXRWSETS / 2); 2176*69783Seric ruleset = -1; 2177*69783Seric } 2178*69783Seric } 2179*69783Seric if (s->s_ruleset > 0 && ruleset >= 0 && ruleset != s->s_ruleset) 2180*69783Seric { 2181*69783Seric syserr("%s: ruleset changed value (old %d, new %d)", 2182*69783Seric q, ruleset, s->s_ruleset); 2183*69783Seric ruleset = s->s_ruleset; 2184*69783Seric } 2185*69783Seric else if (ruleset > 0) 2186*69783Seric { 2187*69783Seric s->s_ruleset = ruleset; 2188*69783Seric } 2189*69783Seric } 2190*69783Seric return ruleset; 2191*69783Seric } 2192*69783Seric /* 219368481Seric ** INITTIMEOUTS -- parse and set timeout values 219458112Seric ** 219558112Seric ** Parameters: 219658112Seric ** val -- a pointer to the values. If NULL, do initial 219758112Seric ** settings. 219858112Seric ** 219958112Seric ** Returns: 220058112Seric ** none. 220158112Seric ** 220258112Seric ** Side Effects: 220358112Seric ** Initializes the TimeOuts structure 220458112Seric */ 220558112Seric 220664255Seric #define SECONDS 220758112Seric #define MINUTES * 60 220858112Seric #define HOUR * 3600 220958112Seric 221069748Seric void 221168481Seric inittimeouts(val) 221258112Seric register char *val; 221358112Seric { 221458112Seric register char *p; 221558671Seric extern time_t convtime(); 221658112Seric 221758112Seric if (val == NULL) 221858112Seric { 221958112Seric TimeOuts.to_initial = (time_t) 5 MINUTES; 222058112Seric TimeOuts.to_helo = (time_t) 5 MINUTES; 222158112Seric TimeOuts.to_mail = (time_t) 10 MINUTES; 222258112Seric TimeOuts.to_rcpt = (time_t) 1 HOUR; 222358112Seric TimeOuts.to_datainit = (time_t) 5 MINUTES; 222458112Seric TimeOuts.to_datablock = (time_t) 1 HOUR; 222558112Seric TimeOuts.to_datafinal = (time_t) 1 HOUR; 222658112Seric TimeOuts.to_rset = (time_t) 5 MINUTES; 222758112Seric TimeOuts.to_quit = (time_t) 2 MINUTES; 222858112Seric TimeOuts.to_nextcommand = (time_t) 1 HOUR; 222958112Seric TimeOuts.to_miscshort = (time_t) 2 MINUTES; 223068481Seric #if IDENTPROTO 223164255Seric TimeOuts.to_ident = (time_t) 30 SECONDS; 223268481Seric #else 223368481Seric TimeOuts.to_ident = (time_t) 0 SECONDS; 223468481Seric #endif 223568481Seric TimeOuts.to_fileopen = (time_t) 60 SECONDS; 223658112Seric return; 223758112Seric } 223858112Seric 223958112Seric for (;; val = p) 224058112Seric { 224158112Seric while (isascii(*val) && isspace(*val)) 224258112Seric val++; 224358112Seric if (*val == '\0') 224458112Seric break; 224558112Seric for (p = val; *p != '\0' && *p != ','; p++) 224658112Seric continue; 224758112Seric if (*p != '\0') 224858112Seric *p++ = '\0'; 224958112Seric 225058112Seric if (isascii(*val) && isdigit(*val)) 225158112Seric { 225258112Seric /* old syntax -- set everything */ 225358796Seric TimeOuts.to_mail = convtime(val, 'm'); 225458112Seric TimeOuts.to_rcpt = TimeOuts.to_mail; 225558112Seric TimeOuts.to_datainit = TimeOuts.to_mail; 225658112Seric TimeOuts.to_datablock = TimeOuts.to_mail; 225758112Seric TimeOuts.to_datafinal = TimeOuts.to_mail; 225858112Seric TimeOuts.to_nextcommand = TimeOuts.to_mail; 225958112Seric continue; 226058112Seric } 226158112Seric else 226258112Seric { 226368481Seric register char *q = strchr(val, ':'); 226458112Seric 226568481Seric if (q == NULL && (q = strchr(val, '=')) == NULL) 226658112Seric { 226758112Seric /* syntax error */ 226858112Seric continue; 226958112Seric } 227058112Seric *q++ = '\0'; 227168481Seric settimeout(val, q); 227268481Seric } 227368481Seric } 227468481Seric } 227568481Seric /* 227668481Seric ** SETTIMEOUT -- set an individual timeout 227768481Seric ** 227868481Seric ** Parameters: 227968481Seric ** name -- the name of the timeout. 228068481Seric ** val -- the value of the timeout. 228168481Seric ** 228268481Seric ** Returns: 228368481Seric ** none. 228468481Seric */ 228558112Seric 228669748Seric void 228768481Seric settimeout(name, val) 228868481Seric char *name; 228968481Seric char *val; 229068481Seric { 229168481Seric register char *p; 229268481Seric time_t to; 229368481Seric extern time_t convtime(); 229468481Seric 229568481Seric to = convtime(val, 'm'); 229668481Seric p = strchr(name, '.'); 229768481Seric if (p != NULL) 229868481Seric *p++ = '\0'; 229968481Seric 230068481Seric if (strcasecmp(name, "initial") == 0) 230168481Seric TimeOuts.to_initial = to; 230268481Seric else if (strcasecmp(name, "mail") == 0) 230368481Seric TimeOuts.to_mail = to; 230468481Seric else if (strcasecmp(name, "rcpt") == 0) 230568481Seric TimeOuts.to_rcpt = to; 230668481Seric else if (strcasecmp(name, "datainit") == 0) 230768481Seric TimeOuts.to_datainit = to; 230868481Seric else if (strcasecmp(name, "datablock") == 0) 230968481Seric TimeOuts.to_datablock = to; 231068481Seric else if (strcasecmp(name, "datafinal") == 0) 231168481Seric TimeOuts.to_datafinal = to; 231268481Seric else if (strcasecmp(name, "command") == 0) 231368481Seric TimeOuts.to_nextcommand = to; 231468481Seric else if (strcasecmp(name, "rset") == 0) 231568481Seric TimeOuts.to_rset = to; 231668481Seric else if (strcasecmp(name, "helo") == 0) 231768481Seric TimeOuts.to_helo = to; 231868481Seric else if (strcasecmp(name, "quit") == 0) 231968481Seric TimeOuts.to_quit = to; 232068481Seric else if (strcasecmp(name, "misc") == 0) 232168481Seric TimeOuts.to_miscshort = to; 232268481Seric else if (strcasecmp(name, "ident") == 0) 232368481Seric TimeOuts.to_ident = to; 232468481Seric else if (strcasecmp(name, "fileopen") == 0) 232568481Seric TimeOuts.to_fileopen = to; 232668481Seric else if (strcasecmp(name, "queuewarn") == 0) 232768481Seric { 232868481Seric to = convtime(val, 'h'); 232968481Seric if (p == NULL || strcmp(p, "*") == 0) 233068481Seric { 233168481Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 233268481Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 233368481Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 233458112Seric } 233568481Seric else if (strcasecmp(p, "normal") == 0) 233668481Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 233768481Seric else if (strcasecmp(p, "urgent") == 0) 233868481Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 233968481Seric else if (strcasecmp(p, "non-urgent") == 0) 234068481Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 234168481Seric else 234268481Seric syserr("settimeout: invalid queuewarn subtimeout %s", p); 234358112Seric } 234468481Seric else if (strcasecmp(name, "queuereturn") == 0) 234568481Seric { 234668481Seric to = convtime(val, 'd'); 234768481Seric if (p == NULL || strcmp(p, "*") == 0) 234868481Seric { 234968481Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 235068481Seric TimeOuts.to_q_return[TOC_URGENT] = to; 235168481Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 235268481Seric } 235368481Seric else if (strcasecmp(p, "normal") == 0) 235468481Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 235568481Seric else if (strcasecmp(p, "urgent") == 0) 235668481Seric TimeOuts.to_q_return[TOC_URGENT] = to; 235768481Seric else if (strcasecmp(p, "non-urgent") == 0) 235868481Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 235968481Seric else 236068481Seric syserr("settimeout: invalid queuereturn subtimeout %s", p); 236168481Seric } 236268481Seric else 236368481Seric syserr("settimeout: invalid timeout %s", name); 236458112Seric } 2365