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*69975Seric static char sccsid[] = "@(#)readcf.c 8.112 (Berkeley) 06/21/95"; 1133731Sbostic #endif /* not lint */ 1222709Sdist 133313Seric # include "sendmail.h" 1464133Seric # include <grp.h> 1566334Seric #if NAMED_BIND 1657207Seric # include <resolv.h> 1757207Seric #endif 183308Seric 193308Seric /* 203308Seric ** READCF -- read control file. 213308Seric ** 223308Seric ** This routine reads the control file and builds the internal 233308Seric ** form. 243308Seric ** 254432Seric ** The file is formatted as a sequence of lines, each taken 264432Seric ** atomically. The first character of each line describes how 274432Seric ** the line is to be interpreted. The lines are: 284432Seric ** Dxval Define macro x to have value val. 294432Seric ** Cxword Put word into class x. 304432Seric ** Fxfile [fmt] Read file for lines to put into 314432Seric ** class x. Use scanf string 'fmt' 324432Seric ** or "%s" if not present. Fmt should 334432Seric ** only produce one string-valued result. 344432Seric ** Hname: value Define header with field-name 'name' 354432Seric ** and value as specified; this will be 364432Seric ** macro expanded immediately before 374432Seric ** use. 384432Seric ** Sn Use rewriting set n. 394432Seric ** Rlhs rhs Rewrite addresses that match lhs to 404432Seric ** be rhs. 4124944Seric ** Mn arg=val... Define mailer. n is the internal name. 4224944Seric ** Args specify mailer parameters. 438252Seric ** Oxvalue Set option x to value. 448252Seric ** Pname=value Set precedence name to value. 4564718Seric ** Vversioncode[/vendorcode] 4664718Seric ** Version level/vendor name of 4764718Seric ** configuration syntax. 4853654Seric ** Kmapname mapclass arguments.... 4953654Seric ** Define keyed lookup of a given class. 5053654Seric ** Arguments are class dependent. 5169476Seric ** Eenvar=value Set the environment value to the given value. 524432Seric ** 533308Seric ** Parameters: 543308Seric ** cfname -- control file name. 5554973Seric ** safe -- TRUE if this is the system config file; 5654973Seric ** FALSE otherwise. 5755012Seric ** e -- the main envelope. 583308Seric ** 593308Seric ** Returns: 603308Seric ** none. 613308Seric ** 623308Seric ** Side Effects: 633308Seric ** Builds several internal tables. 643308Seric */ 653308Seric 6669748Seric void 6755012Seric readcf(cfname, safe, e) 683308Seric char *cfname; 6954973Seric bool safe; 7055012Seric register ENVELOPE *e; 713308Seric { 723308Seric FILE *cf; 738547Seric int ruleset = 0; 748547Seric char *q; 759350Seric struct rewrite *rwp = NULL; 7657135Seric char *bp; 7764718Seric auto char *ep; 7857589Seric int nfuzzy; 7964133Seric char *file; 8064133Seric bool optional; 8168481Seric int mid; 823308Seric char buf[MAXLINE]; 833308Seric register char *p; 843308Seric extern char **copyplist(); 8552647Seric struct stat statb; 865909Seric char exbuf[MAXLINE]; 8765066Seric char pvpbuf[MAXLINE + MAXATOM]; 8868481Seric static char *null_list[1] = { NULL }; 8969748Seric extern char *munchstring __P((char *, char **)); 9069748Seric extern void fileclass __P((int, char *, char *, bool, bool)); 9169748Seric extern void toomany __P((int, int)); 923308Seric 9352647Seric FileName = cfname; 9452647Seric LineNumber = 0; 9552647Seric 963308Seric cf = fopen(cfname, "r"); 973308Seric if (cf == NULL) 983308Seric { 9952647Seric syserr("cannot open"); 1003308Seric exit(EX_OSFILE); 1013308Seric } 1023308Seric 10352647Seric if (fstat(fileno(cf), &statb) < 0) 10452647Seric { 10552647Seric syserr("cannot fstat"); 10652647Seric exit(EX_OSFILE); 10752647Seric } 10852647Seric 10952647Seric if (!S_ISREG(statb.st_mode)) 11052647Seric { 11152647Seric syserr("not a plain file"); 11252647Seric exit(EX_OSFILE); 11352647Seric } 11452647Seric 11552647Seric if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode)) 11652647Seric { 11769686Seric if (OpMode == MD_DAEMON || OpMode == MD_INITALIAS) 11853037Seric fprintf(stderr, "%s: WARNING: dangerous write permissions\n", 11953037Seric FileName); 12053037Seric #ifdef LOG 12153037Seric if (LogLevel > 0) 12253037Seric syslog(LOG_CRIT, "%s: WARNING: dangerous write permissions", 12353037Seric FileName); 12453037Seric #endif 12552647Seric } 12652647Seric 12759254Seric #ifdef XLA 12859254Seric xla_zero(); 12959254Seric #endif 13059254Seric 13157135Seric while ((bp = fgetfolded(buf, sizeof buf, cf)) != NULL) 1323308Seric { 13357135Seric if (bp[0] == '#') 13457135Seric { 13557135Seric if (bp != buf) 13657135Seric free(bp); 13752637Seric continue; 13857135Seric } 13952637Seric 14068481Seric /* do macro expansion mappings */ 14157135Seric for (p = bp; *p != '\0'; p++) 14216157Seric { 14357135Seric if (*p == '#' && p > bp && ConfigLevel >= 3) 14452647Seric { 14552647Seric /* this is an on-line comment */ 14652647Seric register char *e; 14752647Seric 14858050Seric switch (*--p & 0377) 14952647Seric { 15058050Seric case MACROEXPAND: 15152647Seric /* it's from $# -- let it go through */ 15252647Seric p++; 15352647Seric break; 15452647Seric 15552647Seric case '\\': 15652647Seric /* it's backslash escaped */ 15752647Seric (void) strcpy(p, p + 1); 15852647Seric break; 15952647Seric 16052647Seric default: 16152647Seric /* delete preceeding white space */ 16258050Seric while (isascii(*p) && isspace(*p) && p > bp) 16352647Seric p--; 16456795Seric if ((e = strchr(++p, '\n')) != NULL) 16552647Seric (void) strcpy(p, e); 16652647Seric else 16752647Seric p[0] = p[1] = '\0'; 16852647Seric break; 16952647Seric } 17052647Seric continue; 17152647Seric } 17252647Seric 17368481Seric if (*p != '$' || p[1] == '\0') 17416157Seric continue; 17516157Seric 17616157Seric if (p[1] == '$') 17716157Seric { 17816157Seric /* actual dollar sign.... */ 17923111Seric (void) strcpy(p, p + 1); 18016157Seric continue; 18116157Seric } 18216157Seric 18316157Seric /* convert to macro expansion character */ 18468481Seric *p++ = MACROEXPAND; 18568481Seric 186*69975Seric /* special handling for $=, $~, and $& */ 187*69975Seric if (*p == '=' || *p == '~' || *p == '&') 188*69975Seric p++; 189*69975Seric 19068481Seric /* convert macro name to code */ 19168481Seric *p = macid(p, &ep); 19268481Seric if (ep != p) 19368481Seric strcpy(p + 1, ep); 19416157Seric } 19516157Seric 19616157Seric /* interpret this line */ 19764718Seric errno = 0; 19857135Seric switch (bp[0]) 1993308Seric { 2003308Seric case '\0': 2013308Seric case '#': /* comment */ 2023308Seric break; 2033308Seric 2043308Seric case 'R': /* rewriting rule */ 20557135Seric for (p = &bp[1]; *p != '\0' && *p != '\t'; p++) 2063308Seric continue; 2073308Seric 2083308Seric if (*p == '\0') 2095909Seric { 21065821Seric syserr("invalid rewrite line \"%s\" (tab expected)", bp); 2115909Seric break; 2125909Seric } 2135909Seric 2145909Seric /* allocate space for the rule header */ 2155909Seric if (rwp == NULL) 2165909Seric { 2175909Seric RewriteRules[ruleset] = rwp = 2185909Seric (struct rewrite *) xalloc(sizeof *rwp); 2195909Seric } 2203308Seric else 2213308Seric { 2225909Seric rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp); 2235909Seric rwp = rwp->r_next; 2245909Seric } 2255909Seric rwp->r_next = NULL; 2263308Seric 2275909Seric /* expand and save the LHS */ 2285909Seric *p = '\0'; 22968529Seric expand(&bp[1], exbuf, sizeof exbuf, e); 23065066Seric rwp->r_lhs = prescan(exbuf, '\t', pvpbuf, 23168711Seric sizeof pvpbuf, NULL, NULL); 23257589Seric nfuzzy = 0; 2335909Seric if (rwp->r_lhs != NULL) 23457589Seric { 23557589Seric register char **ap; 23657589Seric 2375909Seric rwp->r_lhs = copyplist(rwp->r_lhs, TRUE); 23857589Seric 23957589Seric /* count the number of fuzzy matches in LHS */ 24057589Seric for (ap = rwp->r_lhs; *ap != NULL; ap++) 24157589Seric { 24258148Seric char *botch; 24358148Seric 24458148Seric botch = NULL; 24558050Seric switch (**ap & 0377) 24657589Seric { 24757589Seric case MATCHZANY: 24857589Seric case MATCHANY: 24957589Seric case MATCHONE: 25057589Seric case MATCHCLASS: 25157589Seric case MATCHNCLASS: 25257589Seric nfuzzy++; 25358148Seric break; 25458148Seric 25558148Seric case MATCHREPL: 25658148Seric botch = "$0-$9"; 25758148Seric break; 25858148Seric 25958148Seric case CANONNET: 26058148Seric botch = "$#"; 26158148Seric break; 26258148Seric 26358148Seric case CANONUSER: 26458148Seric botch = "$:"; 26558148Seric break; 26658148Seric 26758148Seric case CALLSUBR: 26858148Seric botch = "$>"; 26958148Seric break; 27058148Seric 27158148Seric case CONDIF: 27258148Seric botch = "$?"; 27358148Seric break; 27458148Seric 27558148Seric case CONDELSE: 27658148Seric botch = "$|"; 27758148Seric break; 27858148Seric 27958148Seric case CONDFI: 28058148Seric botch = "$."; 28158148Seric break; 28258148Seric 28358148Seric case HOSTBEGIN: 28458148Seric botch = "$["; 28558148Seric break; 28658148Seric 28758148Seric case HOSTEND: 28858148Seric botch = "$]"; 28958148Seric break; 29058148Seric 29158148Seric case LOOKUPBEGIN: 29258148Seric botch = "$("; 29358148Seric break; 29458148Seric 29558148Seric case LOOKUPEND: 29658148Seric botch = "$)"; 29758148Seric break; 29857589Seric } 29958148Seric if (botch != NULL) 30058148Seric syserr("Inappropriate use of %s on LHS", 30158148Seric botch); 30257589Seric } 30357589Seric } 30456678Seric else 30568481Seric { 30656678Seric syserr("R line: null LHS"); 30768481Seric rwp->r_lhs = null_list; 30868481Seric } 3095909Seric 3105909Seric /* expand and save the RHS */ 3115909Seric while (*++p == '\t') 3125909Seric continue; 3137231Seric q = p; 3147231Seric while (*p != '\0' && *p != '\t') 3157231Seric p++; 3167231Seric *p = '\0'; 31768529Seric expand(q, exbuf, sizeof exbuf, e); 31865066Seric rwp->r_rhs = prescan(exbuf, '\t', pvpbuf, 31968711Seric sizeof pvpbuf, NULL, NULL); 3205909Seric if (rwp->r_rhs != NULL) 32157589Seric { 32257589Seric register char **ap; 32357589Seric 3245909Seric rwp->r_rhs = copyplist(rwp->r_rhs, TRUE); 32557589Seric 32657589Seric /* check no out-of-bounds replacements */ 32757589Seric nfuzzy += '0'; 32857589Seric for (ap = rwp->r_rhs; *ap != NULL; ap++) 32957589Seric { 33058148Seric char *botch; 33158148Seric 33258148Seric botch = NULL; 33358148Seric switch (**ap & 0377) 33457589Seric { 33558148Seric case MATCHREPL: 33658148Seric if ((*ap)[1] <= '0' || (*ap)[1] > nfuzzy) 33758148Seric { 33858148Seric syserr("replacement $%c out of bounds", 33958148Seric (*ap)[1]); 34058148Seric } 34158148Seric break; 34258148Seric 34358148Seric case MATCHZANY: 34458148Seric botch = "$*"; 34558148Seric break; 34658148Seric 34758148Seric case MATCHANY: 34858148Seric botch = "$+"; 34958148Seric break; 35058148Seric 35158148Seric case MATCHONE: 35258148Seric botch = "$-"; 35358148Seric break; 35458148Seric 35558148Seric case MATCHCLASS: 35658148Seric botch = "$="; 35758148Seric break; 35858148Seric 35958148Seric case MATCHNCLASS: 36058148Seric botch = "$~"; 36158148Seric break; 36257589Seric } 36358148Seric if (botch != NULL) 36458148Seric syserr("Inappropriate use of %s on RHS", 36558148Seric botch); 36657589Seric } 36757589Seric } 36856678Seric else 36968481Seric { 37056678Seric syserr("R line: null RHS"); 37168481Seric rwp->r_rhs = null_list; 37268481Seric } 3733308Seric break; 3743308Seric 3754072Seric case 'S': /* select rewriting set */ 37669783Seric ruleset = strtorwset(&bp[1], NULL, ST_ENTER); 37769789Seric rwp = RewriteRules[ruleset]; 37869789Seric if (rwp != NULL) 37969789Seric { 38069789Seric while (rwp->r_next != NULL) 38169789Seric rwp = rwp->r_next; 38269789Seric fprintf(stderr, "WARNING: Ruleset %s redefined\n", 38369789Seric &bp[1]); 38469789Seric } 3854072Seric break; 3864072Seric 3873308Seric case 'D': /* macro definition */ 38868481Seric mid = macid(&bp[1], &ep); 38968481Seric p = munchstring(ep, NULL); 39068481Seric define(mid, newstr(p), e); 3913308Seric break; 3923308Seric 3933387Seric case 'H': /* required header line */ 39468717Seric (void) chompheader(&bp[1], TRUE, NULL, e); 3953387Seric break; 3963387Seric 3974061Seric case 'C': /* word class */ 39868481Seric case 'T': /* trusted user (set class `t') */ 39968481Seric if (bp[0] == 'C') 4004061Seric { 40168481Seric mid = macid(&bp[1], &ep); 40268529Seric expand(ep, exbuf, sizeof exbuf, e); 40368481Seric p = exbuf; 40468481Seric } 40568481Seric else 40668481Seric { 40768481Seric mid = 't'; 40868481Seric p = &bp[1]; 40968481Seric } 41068481Seric while (*p != '\0') 41168481Seric { 4124061Seric register char *wd; 4134061Seric char delim; 4144061Seric 41558050Seric while (*p != '\0' && isascii(*p) && isspace(*p)) 4164061Seric p++; 4174061Seric wd = p; 41858050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 4194061Seric p++; 4204061Seric delim = *p; 4214061Seric *p = '\0'; 4224061Seric if (wd[0] != '\0') 42368481Seric setclass(mid, wd); 4244061Seric *p = delim; 4254061Seric } 4264061Seric break; 4274061Seric 42859272Seric case 'F': /* word class from file */ 42968481Seric mid = macid(&bp[1], &ep); 43068481Seric for (p = ep; isascii(*p) && isspace(*p); ) 43164133Seric p++; 43264133Seric if (p[0] == '-' && p[1] == 'o') 43364133Seric { 43464133Seric optional = TRUE; 43564133Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 43664133Seric p++; 43764133Seric while (isascii(*p) && isspace(*p)) 43868481Seric p++; 43964133Seric } 44064133Seric else 44164133Seric optional = FALSE; 44264133Seric file = p; 44364133Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 44464133Seric p++; 44559272Seric if (*p == '\0') 44659272Seric p = "%s"; 44759272Seric else 44859272Seric { 44959272Seric *p = '\0'; 45059272Seric while (isascii(*++p) && isspace(*p)) 45159272Seric continue; 45259272Seric } 45364133Seric fileclass(bp[1], file, p, safe, optional); 45459272Seric break; 45559272Seric 45659156Seric #ifdef XLA 45759156Seric case 'L': /* extended load average description */ 45859156Seric xla_init(&bp[1]); 45959156Seric break; 46059156Seric #endif 46159156Seric 4624096Seric case 'M': /* define mailer */ 46357135Seric makemailer(&bp[1]); 4644096Seric break; 4654096Seric 4668252Seric case 'O': /* set option */ 46758734Seric setoption(bp[1], &bp[2], safe, FALSE, e); 4688252Seric break; 4698252Seric 4708252Seric case 'P': /* set precedence */ 4718252Seric if (NumPriorities >= MAXPRIORITIES) 4728252Seric { 4738547Seric toomany('P', MAXPRIORITIES); 4748252Seric break; 4758252Seric } 47669956Seric for (p = &bp[1]; *p != '\0' && *p != '='; p++) 4778252Seric continue; 4788252Seric if (*p == '\0') 4798252Seric goto badline; 4808252Seric *p = '\0'; 48157135Seric Priorities[NumPriorities].pri_name = newstr(&bp[1]); 4828252Seric Priorities[NumPriorities].pri_val = atoi(++p); 4838252Seric NumPriorities++; 4848252Seric break; 4858252Seric 48652645Seric case 'V': /* configuration syntax version */ 48764440Seric for (p = &bp[1]; isascii(*p) && isspace(*p); p++) 48864440Seric continue; 48964440Seric if (!isascii(*p) || !isdigit(*p)) 49064440Seric { 49164440Seric syserr("invalid argument to V line: \"%.20s\"", 49264440Seric &bp[1]); 49364440Seric break; 49464440Seric } 49564718Seric ConfigLevel = strtol(p, &ep, 10); 49668805Seric 49768805Seric /* 49868805Seric ** Do heuristic tweaking for back compatibility. 49968805Seric */ 50068805Seric 50164279Seric if (ConfigLevel >= 5) 50264279Seric { 50364279Seric /* level 5 configs have short name in $w */ 50464279Seric p = macvalue('w', e); 50564279Seric if (p != NULL && (p = strchr(p, '.')) != NULL) 50664279Seric *p = '\0'; 50764279Seric } 50868805Seric if (ConfigLevel >= 6) 50968805Seric { 51068805Seric ColonOkInAddr = FALSE; 51168805Seric } 51268805Seric 51368805Seric /* 51468805Seric ** Look for vendor code. 51568805Seric */ 51668805Seric 51764718Seric if (*ep++ == '/') 51864718Seric { 51964718Seric /* extract vendor code */ 52064718Seric for (p = ep; isascii(*p) && isalpha(*p); ) 52164718Seric p++; 52264718Seric *p = '\0'; 52364718Seric 52464718Seric if (!setvendor(ep)) 52564718Seric syserr("invalid V line vendor code: \"%s\"", 52664718Seric ep); 52764718Seric } 52852645Seric break; 52952645Seric 53053654Seric case 'K': 53169774Seric (void) makemapentry(&bp[1]); 53253654Seric break; 53353654Seric 53469476Seric case 'E': 53569476Seric p = strchr(bp, '='); 53669476Seric if (p != NULL) 53769476Seric *p++ = '\0'; 53869476Seric setuserenv(&bp[1], p); 53969476Seric break; 54069476Seric 5413308Seric default: 5424061Seric badline: 54357135Seric syserr("unknown control line \"%s\"", bp); 5443308Seric } 54557135Seric if (bp != buf) 54657135Seric free(bp); 5473308Seric } 54852637Seric if (ferror(cf)) 54952637Seric { 55052647Seric syserr("I/O read error", cfname); 55152637Seric exit(EX_OSFILE); 55252637Seric } 55352637Seric fclose(cf); 5549381Seric FileName = NULL; 55556836Seric 55668481Seric /* initialize host maps from local service tables */ 55768481Seric inithostmaps(); 55868481Seric 55968481Seric /* determine if we need to do special name-server frotz */ 56067905Seric { 56168481Seric int nmaps; 56268481Seric char *maptype[MAXMAPSTACK]; 56368481Seric short mapreturn[MAXMAPACTIONS]; 56468481Seric 56568481Seric nmaps = switch_map_find("hosts", maptype, mapreturn); 56668481Seric UseNameServer = FALSE; 56768481Seric if (nmaps > 0 && nmaps <= MAXMAPSTACK) 56868481Seric { 56968481Seric register int mapno; 57068481Seric 57168481Seric for (mapno = 0; mapno < nmaps && !UseNameServer; mapno++) 57268481Seric { 57368481Seric if (strcmp(maptype[mapno], "dns") == 0) 57468481Seric UseNameServer = TRUE; 57568481Seric } 57668481Seric } 57768481Seric 57868481Seric #ifdef HESIOD 57968481Seric nmaps = switch_map_find("passwd", maptype, mapreturn); 58068481Seric UseHesiod = FALSE; 58168481Seric if (nmaps > 0 && nmaps <= MAXMAPSTACK) 58268481Seric { 58368481Seric register int mapno; 58468481Seric 58568481Seric for (mapno = 0; mapno < nmaps && !UseHesiod; mapno++) 58668481Seric { 58768481Seric if (strcmp(maptype[mapno], "hesiod") == 0) 58868481Seric UseHesiod = TRUE; 58968481Seric } 59068481Seric } 59168204Seric #endif 59267905Seric } 5934096Seric } 5944096Seric /* 5958547Seric ** TOOMANY -- signal too many of some option 5968547Seric ** 5978547Seric ** Parameters: 5988547Seric ** id -- the id of the error line 5998547Seric ** maxcnt -- the maximum possible values 6008547Seric ** 6018547Seric ** Returns: 6028547Seric ** none. 6038547Seric ** 6048547Seric ** Side Effects: 6058547Seric ** gives a syserr. 6068547Seric */ 6078547Seric 60869748Seric void 6098547Seric toomany(id, maxcnt) 61069748Seric int id; 6118547Seric int maxcnt; 6128547Seric { 6139381Seric syserr("too many %c lines, %d max", id, maxcnt); 6148547Seric } 6158547Seric /* 6164432Seric ** FILECLASS -- read members of a class from a file 6174432Seric ** 6184432Seric ** Parameters: 6194432Seric ** class -- class to define. 6204432Seric ** filename -- name of file to read. 6214432Seric ** fmt -- scanf string to use for match. 62264133Seric ** safe -- if set, this is a safe read. 62364133Seric ** optional -- if set, it is not an error for the file to 62464133Seric ** not exist. 6254432Seric ** 6264432Seric ** Returns: 6274432Seric ** none 6284432Seric ** 6294432Seric ** Side Effects: 6304432Seric ** 6314432Seric ** puts all lines in filename that match a scanf into 6324432Seric ** the named class. 6334432Seric */ 6344432Seric 63569748Seric void 63664133Seric fileclass(class, filename, fmt, safe, optional) 6374432Seric int class; 6384432Seric char *filename; 6394432Seric char *fmt; 64054973Seric bool safe; 64164133Seric bool optional; 6424432Seric { 64325808Seric FILE *f; 64468513Seric int sff; 64569453Seric int pid; 64669453Seric register char *p; 6474432Seric char buf[MAXLINE]; 6484432Seric 64966101Seric if (tTd(37, 2)) 65066101Seric printf("fileclass(%s, fmt=%s)\n", filename, fmt); 65166101Seric 65266031Seric if (filename[0] == '|') 65366031Seric { 65469453Seric auto int fd; 65569453Seric int i; 65669453Seric char *argv[MAXPV + 1]; 65769453Seric 65869453Seric i = 0; 65969453Seric for (p = strtok(&filename[1], " \t"); p != NULL; p = strtok(NULL, " \t")) 66069453Seric { 66169453Seric if (i >= MAXPV) 66269453Seric break; 66369453Seric argv[i++] = p; 66469453Seric } 66569453Seric argv[i] = NULL; 66669453Seric pid = prog_open(argv, &fd, CurEnv); 66769453Seric if (pid < 0) 66869453Seric f = NULL; 66969453Seric else 67069453Seric f = fdopen(fd, "r"); 67166031Seric } 67269453Seric else 67369453Seric { 67469453Seric pid = -1; 67569453Seric sff = SFF_REGONLY; 67669453Seric if (safe) 67769453Seric sff |= SFF_OPENASROOT; 67869453Seric f = safefopen(filename, O_RDONLY, 0, sff); 67969453Seric } 68068602Seric if (f == NULL) 68154973Seric { 68268602Seric if (!optional) 68368602Seric syserr("fileclass: cannot open %s", filename); 6844432Seric return; 6854432Seric } 6864432Seric 6874432Seric while (fgets(buf, sizeof buf, f) != NULL) 6884432Seric { 68925808Seric register char *p; 69069935Seric # if SCANF 6914432Seric char wordbuf[MAXNAME+1]; 6924432Seric 6934432Seric if (sscanf(buf, fmt, wordbuf) != 1) 6944432Seric continue; 69525808Seric p = wordbuf; 69656795Seric # else /* SCANF */ 69725808Seric p = buf; 69856795Seric # endif /* SCANF */ 69925808Seric 70025808Seric /* 70125808Seric ** Break up the match into words. 70225808Seric */ 70325808Seric 70425808Seric while (*p != '\0') 70525808Seric { 70625808Seric register char *q; 70725808Seric 70825808Seric /* strip leading spaces */ 70958050Seric while (isascii(*p) && isspace(*p)) 71025808Seric p++; 71125808Seric if (*p == '\0') 71225808Seric break; 71325808Seric 71425808Seric /* find the end of the word */ 71525808Seric q = p; 71658050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 71725808Seric p++; 71825808Seric if (*p != '\0') 71925808Seric *p++ = '\0'; 72025808Seric 72125808Seric /* enter the word in the symbol table */ 72266101Seric setclass(class, q); 72325808Seric } 7244432Seric } 7254432Seric 72654973Seric (void) fclose(f); 72769453Seric if (pid > 0) 72869453Seric (void) waitfor(pid); 7294432Seric } 7304432Seric /* 7314096Seric ** MAKEMAILER -- define a new mailer. 7324096Seric ** 7334096Seric ** Parameters: 73410327Seric ** line -- description of mailer. This is in labeled 73510327Seric ** fields. The fields are: 73668481Seric ** A -- the argv for this mailer 73768481Seric ** C -- the character set for MIME conversions 73868481Seric ** D -- the directory to run in 73968481Seric ** E -- the eol string 74068481Seric ** F -- the flags associated with the mailer 74168481Seric ** L -- the maximum line length 74268481Seric ** M -- the maximum message size 74368816Seric ** N -- the niceness at which to run 74468479Seric ** P -- the path to the mailer 74568481Seric ** R -- the recipient rewriting set 74668479Seric ** S -- the sender rewriting set 74768481Seric ** T -- the mailer type (for DSNs) 74868481Seric ** U -- the uid to run as 74910327Seric ** The first word is the canonical name of the mailer. 7504096Seric ** 7514096Seric ** Returns: 7524096Seric ** none. 7534096Seric ** 7544096Seric ** Side Effects: 7554096Seric ** enters the mailer into the mailer table. 7564096Seric */ 7573308Seric 75869748Seric void 75921066Seric makemailer(line) 7604096Seric char *line; 7614096Seric { 7624096Seric register char *p; 7638067Seric register struct mailer *m; 7648067Seric register STAB *s; 7658067Seric int i; 76610327Seric char fcode; 76758020Seric auto char *endp; 7684096Seric extern int NextMailer; 76910327Seric extern char **makeargv(); 77010327Seric extern char *munchstring(); 7714096Seric 77210327Seric /* allocate a mailer and set up defaults */ 77310327Seric m = (struct mailer *) xalloc(sizeof *m); 77410327Seric bzero((char *) m, sizeof *m); 77510327Seric m->m_eol = "\n"; 77668481Seric m->m_uid = m->m_gid = 0; 77710327Seric 77810327Seric /* collect the mailer name */ 77958050Seric for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++) 78010327Seric continue; 78110327Seric if (*p != '\0') 78210327Seric *p++ = '\0'; 78310327Seric m->m_name = newstr(line); 78410327Seric 78510327Seric /* now scan through and assign info from the fields */ 78610327Seric while (*p != '\0') 78710327Seric { 78858333Seric auto char *delimptr; 78958333Seric 79058050Seric while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p)))) 79110327Seric p++; 79210327Seric 79310327Seric /* p now points to field code */ 79410327Seric fcode = *p; 79510327Seric while (*p != '\0' && *p != '=' && *p != ',') 79610327Seric p++; 79710327Seric if (*p++ != '=') 79810327Seric { 79952637Seric syserr("mailer %s: `=' expected", m->m_name); 80010327Seric return; 80110327Seric } 80258050Seric while (isascii(*p) && isspace(*p)) 80310327Seric p++; 80410327Seric 80510327Seric /* p now points to the field body */ 80658333Seric p = munchstring(p, &delimptr); 80710327Seric 80810327Seric /* install the field into the mailer struct */ 80910327Seric switch (fcode) 81010327Seric { 81110327Seric case 'P': /* pathname */ 81210327Seric m->m_mailer = newstr(p); 81310327Seric break; 81410327Seric 81510327Seric case 'F': /* flags */ 81610687Seric for (; *p != '\0'; p++) 81758050Seric if (!(isascii(*p) && isspace(*p))) 81852637Seric setbitn(*p, m->m_flags); 81910327Seric break; 82010327Seric 82110327Seric case 'S': /* sender rewriting ruleset */ 82210327Seric case 'R': /* recipient rewriting ruleset */ 82369783Seric i = strtorwset(p, &endp, ST_ENTER); 82469783Seric if (i < 0) 82510327Seric return; 82610327Seric if (fcode == 'S') 82758020Seric m->m_sh_rwset = m->m_se_rwset = i; 82810327Seric else 82958020Seric m->m_rh_rwset = m->m_re_rwset = i; 83058020Seric 83158020Seric p = endp; 83259985Seric if (*p++ == '/') 83358020Seric { 83469971Seric i = strtorwset(p, NULL, ST_ENTER); 83569783Seric if (i < 0) 83658020Seric return; 83758020Seric if (fcode == 'S') 83858020Seric m->m_sh_rwset = i; 83958020Seric else 84058020Seric m->m_rh_rwset = i; 84158020Seric } 84210327Seric break; 84310327Seric 84410327Seric case 'E': /* end of line string */ 84510327Seric m->m_eol = newstr(p); 84610327Seric break; 84710327Seric 84810327Seric case 'A': /* argument vector */ 84910327Seric m->m_argv = makeargv(p); 85010327Seric break; 85110701Seric 85210701Seric case 'M': /* maximum message size */ 85310701Seric m->m_maxsize = atol(p); 85410701Seric break; 85552106Seric 85652106Seric case 'L': /* maximum line length */ 85752106Seric m->m_linelimit = atoi(p); 85852106Seric break; 85958935Seric 86068816Seric case 'N': /* run niceness */ 86168816Seric m->m_nice = atoi(p); 86268816Seric break; 86368816Seric 86458935Seric case 'D': /* working directory */ 86558935Seric m->m_execdir = newstr(p); 86658935Seric break; 86768481Seric 86868481Seric case 'C': /* default charset */ 86968481Seric m->m_defcharset = newstr(p); 87068481Seric break; 87168481Seric 87269720Seric case 'T': /* MTA-Name/Address/Diagnostic types */ 87369858Seric /* extract MTA name type; default to "dns" */ 87468481Seric m->m_mtatype = newstr(p); 87568481Seric p = strchr(m->m_mtatype, '/'); 87668481Seric if (p != NULL) 87768481Seric { 87868481Seric *p++ = '\0'; 87968481Seric if (*p == '\0') 88068481Seric p = NULL; 88168481Seric } 88269858Seric if (*m->m_mtatype == '\0') 88369858Seric m->m_mtatype = "dns"; 88469858Seric 88569858Seric /* extract address type; default to "rfc822" */ 88669858Seric m->m_addrtype = p; 88769858Seric if (p != NULL) 88868481Seric p = strchr(p, '/'); 88968481Seric if (p != NULL) 89068481Seric { 89168481Seric *p++ = '\0'; 89268481Seric if (*p == '\0') 89368481Seric p = NULL; 89468481Seric } 89569858Seric if (m->m_addrtype == NULL || *m->m_addrtype == '\0') 89669858Seric m->m_addrtype = "rfc822"; 89769858Seric 89869858Seric /* extract diagnostic type; default to "smtp" */ 89969858Seric m->m_diagtype = p; 90069858Seric if (m->m_diagtype == NULL || *m->m_diagtype == '\0') 90169858Seric m->m_diagtype = "smtp"; 90268481Seric break; 90368481Seric 90468481Seric case 'U': /* user id */ 90568481Seric if (isascii(*p) && !isdigit(*p)) 90668481Seric { 90768481Seric char *q = p; 90868481Seric struct passwd *pw; 90968481Seric 91068481Seric while (isascii(*p) && isalnum(*p)) 91168481Seric p++; 91268481Seric while (isascii(*p) && isspace(*p)) 91368481Seric *p++ = '\0'; 91468481Seric if (*p != '\0') 91568481Seric *p++ = '\0'; 91668693Seric pw = sm_getpwnam(q); 91768481Seric if (pw == NULL) 91868481Seric syserr("readcf: mailer U= flag: unknown user %s", q); 91968481Seric else 92068481Seric { 92168481Seric m->m_uid = pw->pw_uid; 92268481Seric m->m_gid = pw->pw_gid; 92368481Seric } 92468481Seric } 92568481Seric else 92668481Seric { 92768481Seric auto char *q; 92868481Seric 92968481Seric m->m_uid = strtol(p, &q, 0); 93068481Seric p = q; 93168481Seric } 93268481Seric while (isascii(*p) && isspace(*p)) 93368481Seric p++; 93468481Seric if (*p == '\0') 93568481Seric break; 93668481Seric if (isascii(*p) && !isdigit(*p)) 93768481Seric { 93868481Seric char *q = p; 93968481Seric struct group *gr; 94068481Seric 94168481Seric while (isascii(*p) && isalnum(*p)) 94268481Seric p++; 94368481Seric *p++ = '\0'; 94468481Seric gr = getgrnam(q); 94568481Seric if (gr == NULL) 94668481Seric syserr("readcf: mailer U= flag: unknown group %s", q); 94768481Seric else 94868481Seric m->m_gid = gr->gr_gid; 94968481Seric } 95068481Seric else 95168481Seric { 95268481Seric m->m_gid = strtol(p, NULL, 0); 95368481Seric } 95468481Seric break; 95510327Seric } 95610327Seric 95758333Seric p = delimptr; 95810327Seric } 95910327Seric 96058321Seric /* do some rationality checking */ 96158321Seric if (m->m_argv == NULL) 96258321Seric { 96358321Seric syserr("M%s: A= argument required", m->m_name); 96458321Seric return; 96558321Seric } 96658321Seric if (m->m_mailer == NULL) 96758321Seric { 96858321Seric syserr("M%s: P= argument required", m->m_name); 96958321Seric return; 97058321Seric } 97158321Seric 9724096Seric if (NextMailer >= MAXMAILERS) 9734096Seric { 9749381Seric syserr("too many mailers defined (%d max)", MAXMAILERS); 9754096Seric return; 9764096Seric } 97757402Seric 97868481Seric /* do some heuristic cleanup for back compatibility */ 97968481Seric if (bitnset(M_LIMITS, m->m_flags)) 98068481Seric { 98168481Seric if (m->m_linelimit == 0) 98268481Seric m->m_linelimit = SMTPLINELIM; 98368481Seric if (ConfigLevel < 2) 98468481Seric setbitn(M_7BITS, m->m_flags); 98568481Seric } 98668481Seric 98768481Seric if (ConfigLevel < 6 && 98868481Seric (strcmp(m->m_mailer, "[IPC]") == 0 || 98968481Seric strcmp(m->m_mailer, "[TCP]") == 0)) 99068481Seric { 99168481Seric if (m->m_mtatype == NULL) 99268481Seric m->m_mtatype = "dns"; 99368481Seric if (m->m_addrtype == NULL) 99468481Seric m->m_addrtype = "rfc822"; 99568481Seric if (m->m_diagtype == NULL) 99668481Seric m->m_diagtype = "smtp"; 99768481Seric } 99868481Seric 99968481Seric /* enter the mailer into the symbol table */ 100010327Seric s = stab(m->m_name, ST_MAILER, ST_ENTER); 100157402Seric if (s->s_mailer != NULL) 100257402Seric { 100357402Seric i = s->s_mailer->m_mno; 100457402Seric free(s->s_mailer); 100557402Seric } 100657402Seric else 100757402Seric { 100857402Seric i = NextMailer++; 100957402Seric } 101057402Seric Mailer[i] = s->s_mailer = m; 101157454Seric m->m_mno = i; 101210327Seric } 101310327Seric /* 101410327Seric ** MUNCHSTRING -- translate a string into internal form. 101510327Seric ** 101610327Seric ** Parameters: 101710327Seric ** p -- the string to munch. 101858333Seric ** delimptr -- if non-NULL, set to the pointer of the 101958333Seric ** field delimiter character. 102010327Seric ** 102110327Seric ** Returns: 102210327Seric ** the munched string. 102310327Seric */ 10244096Seric 102510327Seric char * 102658333Seric munchstring(p, delimptr) 102710327Seric register char *p; 102858333Seric char **delimptr; 102910327Seric { 103010327Seric register char *q; 103110327Seric bool backslash = FALSE; 103210327Seric bool quotemode = FALSE; 103310327Seric static char buf[MAXLINE]; 10344096Seric 103510327Seric for (q = buf; *p != '\0'; p++) 10364096Seric { 103710327Seric if (backslash) 103810327Seric { 103910327Seric /* everything is roughly literal */ 104010357Seric backslash = FALSE; 104110327Seric switch (*p) 104210327Seric { 104310327Seric case 'r': /* carriage return */ 104410327Seric *q++ = '\r'; 104510327Seric continue; 104610327Seric 104710327Seric case 'n': /* newline */ 104810327Seric *q++ = '\n'; 104910327Seric continue; 105010327Seric 105110327Seric case 'f': /* form feed */ 105210327Seric *q++ = '\f'; 105310327Seric continue; 105410327Seric 105510327Seric case 'b': /* backspace */ 105610327Seric *q++ = '\b'; 105710327Seric continue; 105810327Seric } 105910327Seric *q++ = *p; 106010327Seric } 106110327Seric else 106210327Seric { 106310327Seric if (*p == '\\') 106410327Seric backslash = TRUE; 106510327Seric else if (*p == '"') 106610327Seric quotemode = !quotemode; 106710327Seric else if (quotemode || *p != ',') 106810327Seric *q++ = *p; 106910327Seric else 107010327Seric break; 107110327Seric } 10724096Seric } 10734096Seric 107458333Seric if (delimptr != NULL) 107558333Seric *delimptr = p; 107610327Seric *q++ = '\0'; 107710327Seric return (buf); 107810327Seric } 107910327Seric /* 108010327Seric ** MAKEARGV -- break up a string into words 108110327Seric ** 108210327Seric ** Parameters: 108310327Seric ** p -- the string to break up. 108410327Seric ** 108510327Seric ** Returns: 108610327Seric ** a char **argv (dynamically allocated) 108710327Seric ** 108810327Seric ** Side Effects: 108910327Seric ** munges p. 109010327Seric */ 10914096Seric 109210327Seric char ** 109310327Seric makeargv(p) 109410327Seric register char *p; 109510327Seric { 109610327Seric char *q; 109710327Seric int i; 109810327Seric char **avp; 109910327Seric char *argv[MAXPV + 1]; 110010327Seric 110110327Seric /* take apart the words */ 110210327Seric i = 0; 110310327Seric while (*p != '\0' && i < MAXPV) 11044096Seric { 110510327Seric q = p; 110658050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 110710327Seric p++; 110858050Seric while (isascii(*p) && isspace(*p)) 110910327Seric *p++ = '\0'; 111010327Seric argv[i++] = newstr(q); 11114096Seric } 111210327Seric argv[i++] = NULL; 11134096Seric 111410327Seric /* now make a copy of the argv */ 111510327Seric avp = (char **) xalloc(sizeof *avp * i); 111616893Seric bcopy((char *) argv, (char *) avp, sizeof *avp * i); 111710327Seric 111810327Seric return (avp); 11193308Seric } 11203308Seric /* 11213308Seric ** PRINTRULES -- print rewrite rules (for debugging) 11223308Seric ** 11233308Seric ** Parameters: 11243308Seric ** none. 11253308Seric ** 11263308Seric ** Returns: 11273308Seric ** none. 11283308Seric ** 11293308Seric ** Side Effects: 11303308Seric ** prints rewrite rules. 11313308Seric */ 11323308Seric 113369748Seric void 11343308Seric printrules() 11353308Seric { 11363308Seric register struct rewrite *rwp; 11374072Seric register int ruleset; 11383308Seric 11394072Seric for (ruleset = 0; ruleset < 10; ruleset++) 11403308Seric { 11414072Seric if (RewriteRules[ruleset] == NULL) 11424072Seric continue; 11438067Seric printf("\n----Rule Set %d:", ruleset); 11443308Seric 11454072Seric for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 11463308Seric { 11478067Seric printf("\nLHS:"); 11488067Seric printav(rwp->r_lhs); 11498067Seric printf("RHS:"); 11508067Seric printav(rwp->r_rhs); 11513308Seric } 11523308Seric } 11533308Seric } 115468481Seric /* 115568481Seric ** PRINTMAILER -- print mailer structure (for debugging) 115668481Seric ** 115768481Seric ** Parameters: 115868481Seric ** m -- the mailer to print 115968481Seric ** 116068481Seric ** Returns: 116168481Seric ** none. 116268481Seric */ 11634319Seric 116469748Seric void 116568481Seric printmailer(m) 116668481Seric register MAILER *m; 116768481Seric { 116868481Seric int j; 116968481Seric 117068481Seric printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld U=%d:%d F=", 117168481Seric m->m_mno, m->m_name, 117268481Seric m->m_mailer, m->m_se_rwset, m->m_sh_rwset, 117368481Seric m->m_re_rwset, m->m_rh_rwset, m->m_maxsize, 117468481Seric m->m_uid, m->m_gid); 117568481Seric for (j = '\0'; j <= '\177'; j++) 117668481Seric if (bitnset(j, m->m_flags)) 117768481Seric (void) putchar(j); 117868481Seric printf(" L=%d E=", m->m_linelimit); 117968481Seric xputs(m->m_eol); 118068481Seric if (m->m_defcharset != NULL) 118168481Seric printf(" C=%s", m->m_defcharset); 118268481Seric printf(" T=%s/%s/%s", 118368481Seric m->m_mtatype == NULL ? "<undefined>" : m->m_mtatype, 118468481Seric m->m_addrtype == NULL ? "<undefined>" : m->m_addrtype, 118568481Seric m->m_diagtype == NULL ? "<undefined>" : m->m_diagtype); 118668481Seric if (m->m_argv != NULL) 118768481Seric { 118868481Seric char **a = m->m_argv; 118968481Seric 119068481Seric printf(" A="); 119168481Seric while (*a != NULL) 119268481Seric { 119368481Seric if (a != m->m_argv) 119468481Seric printf(" "); 119568481Seric xputs(*a++); 119668481Seric } 119768481Seric } 119868481Seric printf("\n"); 119968481Seric } 12004096Seric /* 12018256Seric ** SETOPTION -- set global processing option 12028256Seric ** 12038256Seric ** Parameters: 12048256Seric ** opt -- option name. 12058256Seric ** val -- option value (as a text string). 120621755Seric ** safe -- set if this came from a configuration file. 120721755Seric ** Some options (if set from the command line) will 120821755Seric ** reset the user id to avoid security problems. 12098269Seric ** sticky -- if set, don't let other setoptions override 12108269Seric ** this value. 121158734Seric ** e -- the main envelope. 12128256Seric ** 12138256Seric ** Returns: 12148256Seric ** none. 12158256Seric ** 12168256Seric ** Side Effects: 12178256Seric ** Sets options as implied by the arguments. 12188256Seric */ 12198256Seric 122010687Seric static BITMAP StickyOpt; /* set if option is stuck */ 122169748Seric extern void settimeout __P((char *, char *)); 12228269Seric 122357207Seric 122466334Seric #if NAMED_BIND 122557207Seric 122657207Seric struct resolverflags 122757207Seric { 122857207Seric char *rf_name; /* name of the flag */ 122957207Seric long rf_bits; /* bits to set/clear */ 123057207Seric } ResolverFlags[] = 123157207Seric { 123257207Seric "debug", RES_DEBUG, 123357207Seric "aaonly", RES_AAONLY, 123457207Seric "usevc", RES_USEVC, 123557207Seric "primary", RES_PRIMARY, 123657207Seric "igntc", RES_IGNTC, 123757207Seric "recurse", RES_RECURSE, 123857207Seric "defnames", RES_DEFNAMES, 123957207Seric "stayopen", RES_STAYOPEN, 124057207Seric "dnsrch", RES_DNSRCH, 124165583Seric "true", 0, /* to avoid error on old syntax */ 124257207Seric NULL, 0 124357207Seric }; 124457207Seric 124557207Seric #endif 124657207Seric 124768481Seric struct optioninfo 124868481Seric { 124968481Seric char *o_name; /* long name of option */ 125068481Seric u_char o_code; /* short name of option */ 125168481Seric bool o_safe; /* safe for random people to use */ 125268481Seric } OptionTab[] = 125368481Seric { 125468481Seric "SevenBitInput", '7', TRUE, 125569480Seric #if MIME8TO7 125668481Seric "EightBitMode", '8', TRUE, 125769480Seric #endif 125868481Seric "AliasFile", 'A', FALSE, 125968481Seric "AliasWait", 'a', FALSE, 126068481Seric "BlankSub", 'B', FALSE, 126168481Seric "MinFreeBlocks", 'b', TRUE, 126268481Seric "CheckpointInterval", 'C', TRUE, 126368481Seric "HoldExpensive", 'c', FALSE, 126468481Seric "AutoRebuildAliases", 'D', FALSE, 126568481Seric "DeliveryMode", 'd', TRUE, 126668481Seric "ErrorHeader", 'E', FALSE, 126768481Seric "ErrorMode", 'e', TRUE, 126868481Seric "TempFileMode", 'F', FALSE, 126968481Seric "SaveFromLine", 'f', FALSE, 127068481Seric "MatchGECOS", 'G', FALSE, 127168481Seric "HelpFile", 'H', FALSE, 127268481Seric "MaxHopCount", 'h', FALSE, 127368569Seric "ResolverOptions", 'I', FALSE, 127468481Seric "IgnoreDots", 'i', TRUE, 127568481Seric "ForwardPath", 'J', FALSE, 127668481Seric "SendMimeErrors", 'j', TRUE, 127768481Seric "ConnectionCacheSize", 'k', FALSE, 127868481Seric "ConnectionCacheTimeout", 'K', FALSE, 127968481Seric "UseErrorsTo", 'l', FALSE, 128068481Seric "LogLevel", 'L', FALSE, 128168481Seric "MeToo", 'm', TRUE, 128268481Seric "CheckAliases", 'n', FALSE, 128368481Seric "OldStyleHeaders", 'o', TRUE, 128468481Seric "DaemonPortOptions", 'O', FALSE, 128568481Seric "PrivacyOptions", 'p', TRUE, 128668481Seric "PostmasterCopy", 'P', FALSE, 128768481Seric "QueueFactor", 'q', FALSE, 128868481Seric "QueueDirectory", 'Q', FALSE, 128968481Seric "DontPruneRoutes", 'R', FALSE, 129068481Seric "Timeout", 'r', TRUE, 129168481Seric "StatusFile", 'S', FALSE, 129268481Seric "SuperSafe", 's', TRUE, 129368481Seric "QueueTimeout", 'T', FALSE, 129468481Seric "TimeZoneSpec", 't', FALSE, 129568481Seric "UserDatabaseSpec", 'U', FALSE, 129668481Seric "DefaultUser", 'u', FALSE, 129768481Seric "FallbackMXhost", 'V', FALSE, 129868481Seric "Verbose", 'v', TRUE, 129968481Seric "TryNullMXList", 'w', TRUE, 130068481Seric "QueueLA", 'x', FALSE, 130168481Seric "RefuseLA", 'X', FALSE, 130268481Seric "RecipientFactor", 'y', FALSE, 130368569Seric "ForkEachJob", 'Y', FALSE, 130468481Seric "ClassFactor", 'z', FALSE, 130568569Seric "RetryFactor", 'Z', FALSE, 130668481Seric #define O_QUEUESORTORD 0x81 130768481Seric "QueueSortOrder", O_QUEUESORTORD, TRUE, 130869401Seric #define O_HOSTSFILE 0x82 130969401Seric "HostsFile", O_HOSTSFILE, FALSE, 131068481Seric #define O_MQA 0x83 131168481Seric "MinQueueAge", O_MQA, TRUE, 131268481Seric #define O_MHSA 0x84 131368481Seric /* 131468481Seric "MaxHostStatAge", O_MHSA, TRUE, 131568481Seric */ 131668481Seric #define O_DEFCHARSET 0x85 131768481Seric "DefaultCharSet", O_DEFCHARSET, TRUE, 131868481Seric #define O_SSFILE 0x86 131968481Seric "ServiceSwitchFile", O_SSFILE, FALSE, 132068481Seric #define O_DIALDELAY 0x87 132168481Seric "DialDelay", O_DIALDELAY, TRUE, 132268481Seric #define O_NORCPTACTION 0x88 132368481Seric "NoRecipientAction", O_NORCPTACTION, TRUE, 132468490Seric #define O_SAFEFILEENV 0x89 132568490Seric "SafeFileEnvironment", O_SAFEFILEENV, FALSE, 132668569Seric #define O_MAXMSGSIZE 0x8a 132768569Seric "MaxMessageSize", O_MAXMSGSIZE, FALSE, 132868756Seric #define O_COLONOKINADDR 0x8b 132968756Seric "ColonOkInAddr", O_COLONOKINADDR, TRUE, 133069724Seric #define O_MAXQUEUERUN 0x8c 133169724Seric "MaxQueueRunSize", O_MAXQUEUERUN, TRUE, 133269838Seric #define O_MAXCHILDREN 0x8d 133369838Seric /* 133469838Seric "MaxDaemonChildren", O_MAXCHILDREN, FALSE, 133569838Seric */ 133669852Seric #define O_KEEPCNAMES 0x8e 133769852Seric "DontExpandCnames", O_KEEPCNAMES, FALSE, 133868481Seric 133968481Seric NULL, '\0', FALSE, 134068481Seric }; 134168481Seric 134268481Seric 134368481Seric 134469748Seric void 134558734Seric setoption(opt, val, safe, sticky, e) 134669748Seric int opt; 13478256Seric char *val; 134821755Seric bool safe; 13498269Seric bool sticky; 135058734Seric register ENVELOPE *e; 13518256Seric { 135257207Seric register char *p; 135368481Seric register struct optioninfo *o; 135468481Seric char *subopt; 13558265Seric extern bool atobool(); 135612633Seric extern time_t convtime(); 135714879Seric extern int QueueLA; 135814879Seric extern int RefuseLA; 135964718Seric extern bool Warn_Q_option; 13608256Seric 136168481Seric errno = 0; 136268481Seric if (opt == ' ') 136368481Seric { 136468481Seric /* full word options */ 136568481Seric struct optioninfo *sel; 136668481Seric 136768481Seric p = strchr(val, '='); 136868481Seric if (p == NULL) 136968481Seric p = &val[strlen(val)]; 137068481Seric while (*--p == ' ') 137168481Seric continue; 137268481Seric while (*++p == ' ') 137368481Seric *p = '\0'; 137468481Seric if (p == val) 137568481Seric { 137668481Seric syserr("readcf: null option name"); 137768481Seric return; 137868481Seric } 137968481Seric if (*p == '=') 138068481Seric *p++ = '\0'; 138168481Seric while (*p == ' ') 138268481Seric p++; 138368481Seric subopt = strchr(val, '.'); 138468481Seric if (subopt != NULL) 138568481Seric *subopt++ = '\0'; 138668481Seric sel = NULL; 138768481Seric for (o = OptionTab; o->o_name != NULL; o++) 138868481Seric { 138968481Seric if (strncasecmp(o->o_name, val, strlen(val)) != 0) 139068481Seric continue; 139168481Seric if (strlen(o->o_name) == strlen(val)) 139268481Seric { 139368481Seric /* completely specified -- this must be it */ 139468481Seric sel = NULL; 139568481Seric break; 139668481Seric } 139768481Seric if (sel != NULL) 139868481Seric break; 139968481Seric sel = o; 140068481Seric } 140168481Seric if (sel != NULL && o->o_name == NULL) 140268481Seric o = sel; 140368481Seric else if (o->o_name == NULL) 140468481Seric { 140568481Seric syserr("readcf: unknown option name %s", val); 140668481Seric return; 140768481Seric } 140868481Seric else if (sel != NULL) 140968481Seric { 141068481Seric syserr("readcf: ambiguous option name %s (matches %s and %s)", 141168481Seric val, sel->o_name, o->o_name); 141268481Seric return; 141368481Seric } 141468481Seric if (strlen(val) != strlen(o->o_name)) 141568481Seric { 141668481Seric bool oldVerbose = Verbose; 141768481Seric 141868481Seric Verbose = TRUE; 141968481Seric message("Option %s used as abbreviation for %s", 142068481Seric val, o->o_name); 142168481Seric Verbose = oldVerbose; 142268481Seric } 142368481Seric opt = o->o_code; 142468481Seric val = p; 142568481Seric } 142668481Seric else 142768481Seric { 142868481Seric for (o = OptionTab; o->o_name != NULL; o++) 142968481Seric { 143068481Seric if (o->o_code == opt) 143168481Seric break; 143268481Seric } 143368481Seric subopt = NULL; 143468481Seric } 143568481Seric 14368256Seric if (tTd(37, 1)) 143768481Seric { 143868481Seric printf(isascii(opt) && isprint(opt) ? 143969917Seric "setoption %s (%c).%s=" : 144069917Seric "setoption %s (0x%x).%s=", 144168481Seric o->o_name == NULL ? "<unknown>" : o->o_name, 144268481Seric opt, 144369917Seric subopt == NULL ? "" : subopt); 144469917Seric xputs(val); 144568481Seric } 14468256Seric 14478256Seric /* 14488269Seric ** See if this option is preset for us. 14498256Seric */ 14508256Seric 145159731Seric if (!sticky && bitnset(opt, StickyOpt)) 14528269Seric { 14539341Seric if (tTd(37, 1)) 14549341Seric printf(" (ignored)\n"); 14558269Seric return; 14568269Seric } 14578269Seric 145821755Seric /* 145921755Seric ** Check to see if this option can be specified by this user. 146021755Seric */ 146121755Seric 146263787Seric if (!safe && RealUid == 0) 146321755Seric safe = TRUE; 146468481Seric if (!safe && !o->o_safe) 146521755Seric { 146639111Srick if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 146721755Seric { 146836582Sbostic if (tTd(37, 1)) 146936582Sbostic printf(" (unsafe)"); 147063787Seric if (RealUid != geteuid()) 147136582Sbostic { 147251210Seric if (tTd(37, 1)) 147351210Seric printf("(Resetting uid)"); 147469963Seric endpwent(); 147563787Seric (void) setgid(RealGid); 147663787Seric (void) setuid(RealUid); 147736582Sbostic } 147821755Seric } 147921755Seric } 148051210Seric if (tTd(37, 1)) 148117985Seric printf("\n"); 14828269Seric 148368481Seric switch (opt & 0xff) 14848256Seric { 148559709Seric case '7': /* force seven-bit input */ 148668481Seric SevenBitInput = atobool(val); 148752106Seric break; 148852106Seric 148969480Seric #if MIME8TO7 149068481Seric case '8': /* handling of 8-bit input */ 149168481Seric switch (*val) 149268481Seric { 149368481Seric case 'm': /* convert 8-bit, convert MIME */ 149468481Seric MimeMode = MM_CVTMIME|MM_MIME8BIT; 149568481Seric break; 149668481Seric 149768481Seric case 'p': /* pass 8 bit, convert MIME */ 149868856Seric MimeMode = MM_CVTMIME|MM_PASS8BIT; 149968481Seric break; 150068481Seric 150168481Seric case 's': /* strict adherence */ 150268481Seric MimeMode = MM_CVTMIME; 150368481Seric break; 150468481Seric 150568856Seric #if 0 150668856Seric case 'r': /* reject 8-bit, don't convert MIME */ 150768856Seric MimeMode = 0; 150868856Seric break; 150968856Seric 151068856Seric case 'j': /* "just send 8" */ 151168856Seric MimeMode = MM_PASS8BIT; 151268856Seric break; 151368856Seric 151468481Seric case 'a': /* encode 8 bit if available */ 151568481Seric MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 151668481Seric break; 151768481Seric 151868481Seric case 'c': /* convert 8 bit to MIME, never 7 bit */ 151968481Seric MimeMode = MM_MIME8BIT; 152068481Seric break; 152168856Seric #endif 152268481Seric 152368481Seric default: 152468481Seric syserr("Unknown 8-bit mode %c", *val); 152568481Seric exit(EX_USAGE); 152668481Seric } 152768481Seric break; 152869480Seric #endif 152968481Seric 15308256Seric case 'A': /* set default alias file */ 15319381Seric if (val[0] == '\0') 153259672Seric setalias("aliases"); 15339381Seric else 153459672Seric setalias(val); 15358256Seric break; 15368256Seric 153717474Seric case 'a': /* look N minutes for "@:@" in alias file */ 153817474Seric if (val[0] == '\0') 153964796Seric SafeAlias = 5 * 60; /* five minutes */ 154017474Seric else 154164796Seric SafeAlias = convtime(val, 'm'); 154217474Seric break; 154317474Seric 154416843Seric case 'B': /* substitution for blank character */ 154516843Seric SpaceSub = val[0]; 154616843Seric if (SpaceSub == '\0') 154716843Seric SpaceSub = ' '; 154816843Seric break; 154916843Seric 155059283Seric case 'b': /* min blocks free on queue fs/max msg size */ 155159283Seric p = strchr(val, '/'); 155259283Seric if (p != NULL) 155359283Seric { 155459283Seric *p++ = '\0'; 155559283Seric MaxMessageSize = atol(p); 155659283Seric } 155758082Seric MinBlocksFree = atol(val); 155858082Seric break; 155958082Seric 15609284Seric case 'c': /* don't connect to "expensive" mailers */ 15619381Seric NoConnect = atobool(val); 15629284Seric break; 15639284Seric 156451305Seric case 'C': /* checkpoint every N addresses */ 156551305Seric CheckpointInterval = atoi(val); 156624944Seric break; 156724944Seric 15689284Seric case 'd': /* delivery mode */ 15699284Seric switch (*val) 15708269Seric { 15719284Seric case '\0': 157258734Seric e->e_sendmode = SM_DELIVER; 15738269Seric break; 15748269Seric 157510755Seric case SM_QUEUE: /* queue only */ 157610755Seric #ifndef QUEUE 157710755Seric syserr("need QUEUE to set -odqueue"); 157856795Seric #endif /* QUEUE */ 157910755Seric /* fall through..... */ 158010755Seric 15819284Seric case SM_DELIVER: /* do everything */ 15829284Seric case SM_FORK: /* fork after verification */ 158358734Seric e->e_sendmode = *val; 15848269Seric break; 15858269Seric 15868269Seric default: 15879284Seric syserr("Unknown delivery mode %c", *val); 15888269Seric exit(EX_USAGE); 15898269Seric } 15908269Seric break; 15918269Seric 15929146Seric case 'D': /* rebuild alias database as needed */ 15939381Seric AutoRebuild = atobool(val); 15949146Seric break; 15959146Seric 159655372Seric case 'E': /* error message header/header file */ 159755379Seric if (*val != '\0') 159855379Seric ErrMsgFile = newstr(val); 159955372Seric break; 160055372Seric 16018269Seric case 'e': /* set error processing mode */ 16028269Seric switch (*val) 16038269Seric { 16049381Seric case EM_QUIET: /* be silent about it */ 16059381Seric case EM_MAIL: /* mail back */ 16069381Seric case EM_BERKNET: /* do berknet error processing */ 16079381Seric case EM_WRITE: /* write back (or mail) */ 16089381Seric case EM_PRINT: /* print errors normally (default) */ 160958734Seric e->e_errormode = *val; 16108269Seric break; 16118269Seric } 16128269Seric break; 16138269Seric 16149049Seric case 'F': /* file mode */ 161517975Seric FileMode = atooct(val) & 0777; 16169049Seric break; 16179049Seric 16188269Seric case 'f': /* save Unix-style From lines on front */ 16199381Seric SaveFrom = atobool(val); 16208269Seric break; 16218269Seric 162253735Seric case 'G': /* match recipients against GECOS field */ 162353735Seric MatchGecos = atobool(val); 162453735Seric break; 162553735Seric 16268256Seric case 'g': /* default gid */ 162768481Seric g_opt: 162864133Seric if (isascii(*val) && isdigit(*val)) 162964133Seric DefGid = atoi(val); 163064133Seric else 163164133Seric { 163264133Seric register struct group *gr; 163364133Seric 163464133Seric DefGid = -1; 163564133Seric gr = getgrnam(val); 163664133Seric if (gr == NULL) 163768481Seric syserr("readcf: option %c: unknown group %s", 163868481Seric opt, val); 163964133Seric else 164064133Seric DefGid = gr->gr_gid; 164164133Seric } 16428256Seric break; 16438256Seric 16448256Seric case 'H': /* help file */ 16459381Seric if (val[0] == '\0') 16468269Seric HelpFile = "sendmail.hf"; 16479381Seric else 16489381Seric HelpFile = newstr(val); 16498256Seric break; 16508256Seric 165151305Seric case 'h': /* maximum hop count */ 165251305Seric MaxHopCount = atoi(val); 165351305Seric break; 165451305Seric 165535651Seric case 'I': /* use internet domain name server */ 165666334Seric #if NAMED_BIND 165757207Seric for (p = val; *p != 0; ) 165857207Seric { 165957207Seric bool clearmode; 166057207Seric char *q; 166157207Seric struct resolverflags *rfp; 166257207Seric 166357207Seric while (*p == ' ') 166457207Seric p++; 166557207Seric if (*p == '\0') 166657207Seric break; 166757207Seric clearmode = FALSE; 166857207Seric if (*p == '-') 166957207Seric clearmode = TRUE; 167057207Seric else if (*p != '+') 167157207Seric p--; 167257207Seric p++; 167357207Seric q = p; 167458050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 167557207Seric p++; 167657207Seric if (*p != '\0') 167757207Seric *p++ = '\0'; 167868759Seric if (strcasecmp(q, "HasWildcardMX") == 0) 167968759Seric { 168069896Seric HasWildcardMX = !clearmode; 168168759Seric continue; 168268759Seric } 168357207Seric for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 168457207Seric { 168557207Seric if (strcasecmp(q, rfp->rf_name) == 0) 168657207Seric break; 168757207Seric } 168864923Seric if (rfp->rf_name == NULL) 168964923Seric syserr("readcf: I option value %s unrecognized", q); 169064923Seric else if (clearmode) 169157207Seric _res.options &= ~rfp->rf_bits; 169257207Seric else 169357207Seric _res.options |= rfp->rf_bits; 169457207Seric } 169557207Seric if (tTd(8, 2)) 169668759Seric printf("_res.options = %x, HasWildcardMX = %d\n", 169769896Seric _res.options, HasWildcardMX); 169857207Seric #else 169957207Seric usrerr("name server (I option) specified but BIND not compiled in"); 170057207Seric #endif 170135651Seric break; 170235651Seric 17038269Seric case 'i': /* ignore dot lines in message */ 17049381Seric IgnrDot = atobool(val); 17058269Seric break; 17068269Seric 170759730Seric case 'j': /* send errors in MIME (RFC 1341) format */ 170859730Seric SendMIMEErrors = atobool(val); 170959730Seric break; 171059730Seric 171157136Seric case 'J': /* .forward search path */ 171257136Seric ForwardPath = newstr(val); 171357136Seric break; 171457136Seric 171554967Seric case 'k': /* connection cache size */ 171654967Seric MaxMciCache = atoi(val); 171756215Seric if (MaxMciCache < 0) 171856215Seric MaxMciCache = 0; 171954967Seric break; 172054967Seric 172154967Seric case 'K': /* connection cache timeout */ 172258796Seric MciCacheTimeout = convtime(val, 'm'); 172354967Seric break; 172454967Seric 172561104Seric case 'l': /* use Errors-To: header */ 172661104Seric UseErrorsTo = atobool(val); 172761104Seric break; 172861104Seric 17298256Seric case 'L': /* log level */ 173064140Seric if (safe || LogLevel < atoi(val)) 173164140Seric LogLevel = atoi(val); 17328256Seric break; 17338256Seric 17348269Seric case 'M': /* define macro */ 173568267Seric p = newstr(&val[1]); 173668267Seric if (!safe) 173768267Seric cleanstrcpy(p, p, MAXNAME); 173868267Seric define(val[0], p, CurEnv); 173916878Seric sticky = FALSE; 17408269Seric break; 17418269Seric 17428269Seric case 'm': /* send to me too */ 17439381Seric MeToo = atobool(val); 17448269Seric break; 17458269Seric 174625820Seric case 'n': /* validate RHS in newaliases */ 174725820Seric CheckAliases = atobool(val); 174825820Seric break; 174925820Seric 175061104Seric /* 'N' available -- was "net name" */ 175161104Seric 175258851Seric case 'O': /* daemon options */ 175358851Seric setdaemonoptions(val); 175458851Seric break; 175558851Seric 17568269Seric case 'o': /* assume old style headers */ 17579381Seric if (atobool(val)) 17589341Seric CurEnv->e_flags |= EF_OLDSTYLE; 17599341Seric else 17609341Seric CurEnv->e_flags &= ~EF_OLDSTYLE; 17618269Seric break; 17628269Seric 176358082Seric case 'p': /* select privacy level */ 176458082Seric p = val; 176558082Seric for (;;) 176658082Seric { 176758082Seric register struct prival *pv; 176858082Seric extern struct prival PrivacyValues[]; 176958082Seric 177058082Seric while (isascii(*p) && (isspace(*p) || ispunct(*p))) 177158082Seric p++; 177258082Seric if (*p == '\0') 177358082Seric break; 177458082Seric val = p; 177558082Seric while (isascii(*p) && isalnum(*p)) 177658082Seric p++; 177758082Seric if (*p != '\0') 177858082Seric *p++ = '\0'; 177958082Seric 178058082Seric for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 178158082Seric { 178258082Seric if (strcasecmp(val, pv->pv_name) == 0) 178358082Seric break; 178458082Seric } 178558886Seric if (pv->pv_name == NULL) 178658886Seric syserr("readcf: Op line: %s unrecognized", val); 178758082Seric PrivacyFlags |= pv->pv_flag; 178858082Seric } 178968479Seric sticky = FALSE; 179058082Seric break; 179158082Seric 179224944Seric case 'P': /* postmaster copy address for returned mail */ 179324944Seric PostMasterCopy = newstr(val); 179424944Seric break; 179524944Seric 179624944Seric case 'q': /* slope of queue only function */ 179724944Seric QueueFactor = atoi(val); 179824944Seric break; 179924944Seric 18008256Seric case 'Q': /* queue directory */ 18019381Seric if (val[0] == '\0') 18028269Seric QueueDir = "mqueue"; 18039381Seric else 18049381Seric QueueDir = newstr(val); 180558789Seric if (RealUid != 0 && !safe) 180664718Seric Warn_Q_option = TRUE; 18078256Seric break; 18088256Seric 180958148Seric case 'R': /* don't prune routes */ 181058148Seric DontPruneRoutes = atobool(val); 181158148Seric break; 181258148Seric 18138256Seric case 'r': /* read timeout */ 181468481Seric if (subopt == NULL) 181568481Seric inittimeouts(val); 181668481Seric else 181768481Seric settimeout(subopt, val); 18188256Seric break; 18198256Seric 18208256Seric case 'S': /* status file */ 18219381Seric if (val[0] == '\0') 18228269Seric StatFile = "sendmail.st"; 18239381Seric else 18249381Seric StatFile = newstr(val); 18258256Seric break; 18268256Seric 18278265Seric case 's': /* be super safe, even if expensive */ 18289381Seric SuperSafe = atobool(val); 18298256Seric break; 18308256Seric 18318256Seric case 'T': /* queue timeout */ 183258737Seric p = strchr(val, '/'); 183358737Seric if (p != NULL) 183458737Seric { 183558737Seric *p++ = '\0'; 183668481Seric settimeout("queuewarn", p); 183758737Seric } 183868481Seric settimeout("queuereturn", val); 183954967Seric break; 18408256Seric 18418265Seric case 't': /* time zone name */ 184252106Seric TimeZoneSpec = newstr(val); 18438265Seric break; 18448265Seric 184550556Seric case 'U': /* location of user database */ 184651360Seric UdbSpec = newstr(val); 184750556Seric break; 184850556Seric 18498256Seric case 'u': /* set default uid */ 185068481Seric for (p = val; *p != '\0'; p++) 185168481Seric { 185268481Seric if (*p == '.' || *p == '/' || *p == ':') 185368481Seric { 185468481Seric *p++ = '\0'; 185568481Seric break; 185668481Seric } 185768481Seric } 185864133Seric if (isascii(*val) && isdigit(*val)) 185964133Seric DefUid = atoi(val); 186064133Seric else 186164133Seric { 186264133Seric register struct passwd *pw; 186364133Seric 186464133Seric DefUid = -1; 186568693Seric pw = sm_getpwnam(val); 186664133Seric if (pw == NULL) 186764133Seric syserr("readcf: option u: unknown user %s", val); 186864133Seric else 186968481Seric { 187064133Seric DefUid = pw->pw_uid; 187168481Seric DefGid = pw->pw_gid; 187268481Seric } 187364133Seric } 187440973Sbostic setdefuser(); 18758256Seric 187668481Seric /* handle the group if it is there */ 187768481Seric if (*p == '\0') 187868481Seric break; 187968481Seric val = p; 188068481Seric goto g_opt; 188168481Seric 188258851Seric case 'V': /* fallback MX host */ 188358851Seric FallBackMX = newstr(val); 188458851Seric break; 188558851Seric 18868269Seric case 'v': /* run in verbose mode */ 18879381Seric Verbose = atobool(val); 18888256Seric break; 18898256Seric 189063837Seric case 'w': /* if we are best MX, try host directly */ 189163837Seric TryNullMXList = atobool(val); 189263837Seric break; 189361104Seric 189461104Seric /* 'W' available -- was wizard password */ 189561104Seric 189614879Seric case 'x': /* load avg at which to auto-queue msgs */ 189714879Seric QueueLA = atoi(val); 189814879Seric break; 189914879Seric 190014879Seric case 'X': /* load avg at which to auto-reject connections */ 190114879Seric RefuseLA = atoi(val); 190214879Seric break; 190314879Seric 190424981Seric case 'y': /* work recipient factor */ 190524981Seric WkRecipFact = atoi(val); 190624981Seric break; 190724981Seric 190824981Seric case 'Y': /* fork jobs during queue runs */ 190924952Seric ForkQueueRuns = atobool(val); 191024952Seric break; 191124952Seric 191224981Seric case 'z': /* work message class factor */ 191324981Seric WkClassFact = atoi(val); 191424981Seric break; 191524981Seric 191624981Seric case 'Z': /* work time factor */ 191724981Seric WkTimeFact = atoi(val); 191824981Seric break; 191924981Seric 192068481Seric case O_QUEUESORTORD: /* queue sorting order */ 192168481Seric switch (*val) 192268481Seric { 192368481Seric case 'h': /* Host first */ 192468481Seric case 'H': 192568481Seric QueueSortOrder = QS_BYHOST; 192668481Seric break; 192768481Seric 192868481Seric case 'p': /* Priority order */ 192968481Seric case 'P': 193068481Seric QueueSortOrder = QS_BYPRIORITY; 193168481Seric break; 193268481Seric 193368481Seric default: 193468481Seric syserr("Invalid queue sort order \"%s\"", val); 193568481Seric } 193668481Seric break; 193768481Seric 193869401Seric case O_HOSTSFILE: /* pathname of /etc/hosts file */ 193969401Seric HostsFile = newstr(val); 194069401Seric break; 194169401Seric 194268481Seric case O_MQA: /* minimum queue age between deliveries */ 194368481Seric MinQueueAge = convtime(val, 'm'); 194468481Seric break; 194568481Seric 194668481Seric case O_MHSA: /* maximum age of cached host status */ 194768481Seric MaxHostStatAge = convtime(val, 'm'); 194868481Seric break; 194968481Seric 195068481Seric case O_DEFCHARSET: /* default character set for mimefying */ 195168481Seric DefaultCharSet = newstr(denlstring(val, TRUE, TRUE)); 195268481Seric break; 195368481Seric 195468481Seric case O_SSFILE: /* service switch file */ 195568481Seric ServiceSwitchFile = newstr(val); 195668481Seric break; 195768481Seric 195868481Seric case O_DIALDELAY: /* delay for dial-on-demand operation */ 195968481Seric DialDelay = convtime(val, 's'); 196068481Seric break; 196168481Seric 196268481Seric case O_NORCPTACTION: /* what to do if no recipient */ 196368481Seric if (strcasecmp(val, "none") == 0) 196468481Seric NoRecipientAction = NRA_NO_ACTION; 196568481Seric else if (strcasecmp(val, "add-to") == 0) 196668481Seric NoRecipientAction = NRA_ADD_TO; 196768481Seric else if (strcasecmp(val, "add-apparently-to") == 0) 196868481Seric NoRecipientAction = NRA_ADD_APPARENTLY_TO; 196968481Seric else if (strcasecmp(val, "add-bcc") == 0) 197068481Seric NoRecipientAction = NRA_ADD_BCC; 197168481Seric else if (strcasecmp(val, "add-to-undisclosed") == 0) 197268481Seric NoRecipientAction = NRA_ADD_TO_UNDISCLOSED; 197368481Seric else 197468481Seric syserr("Invalid NoRecipientAction: %s", val); 197568481Seric 197668490Seric case O_SAFEFILEENV: /* chroot() environ for writing to files */ 197768490Seric SafeFileEnv = newstr(val); 197868490Seric break; 197968490Seric 198068569Seric case O_MAXMSGSIZE: /* maximum message size */ 198169748Seric MaxMessageSize = atol(val); 198268569Seric break; 198368569Seric 198468756Seric case O_COLONOKINADDR: /* old style handling of colon addresses */ 198569748Seric ColonOkInAddr = atobool(val); 198668756Seric break; 198768756Seric 198869724Seric case O_MAXQUEUERUN: /* max # of jobs in a single queue run */ 198969748Seric MaxQueueRun = atol(val); 199069724Seric break; 199169724Seric 199269838Seric case O_MAXCHILDREN: /* max # of children of daemon */ 199369838Seric MaxChildren = atoi(val); 199469852Seric break; 199569838Seric 199669852Seric case O_KEEPCNAMES: /* don't expand CNAME records */ 199769852Seric DontExpandCnames = atobool(val); 199869852Seric break; 199969852Seric 20008256Seric default: 200168481Seric if (tTd(37, 1)) 200268481Seric { 200368481Seric if (isascii(opt) && isprint(opt)) 200468481Seric printf("Warning: option %c unknown\n", opt); 200568481Seric else 200668481Seric printf("Warning: option 0x%x unknown\n", opt); 200768481Seric } 20088256Seric break; 20098256Seric } 201016878Seric if (sticky) 201116878Seric setbitn(opt, StickyOpt); 20128256Seric } 201310687Seric /* 201468481Seric ** SETCLASS -- set a string into a class 201510687Seric ** 201610687Seric ** Parameters: 201768481Seric ** class -- the class to put the string in. 201868481Seric ** str -- the string to enter 201910687Seric ** 202010687Seric ** Returns: 202110687Seric ** none. 202210687Seric ** 202310687Seric ** Side Effects: 202410687Seric ** puts the word into the symbol table. 202510687Seric */ 202610687Seric 202769748Seric void 202868481Seric setclass(class, str) 202910687Seric int class; 203068481Seric char *str; 203110687Seric { 203210687Seric register STAB *s; 203310687Seric 203457943Seric if (tTd(37, 8)) 203568481Seric printf("setclass(%c, %s)\n", class, str); 203668481Seric s = stab(str, ST_CLASS, ST_ENTER); 203710687Seric setbitn(class, s->s_class); 203810687Seric } 203953654Seric /* 204053654Seric ** MAKEMAPENTRY -- create a map entry 204153654Seric ** 204253654Seric ** Parameters: 204353654Seric ** line -- the config file line 204453654Seric ** 204553654Seric ** Returns: 204669774Seric ** A pointer to the map that has been created. 204769774Seric ** NULL if there was a syntax error. 204853654Seric ** 204953654Seric ** Side Effects: 205053654Seric ** Enters the map into the dictionary. 205153654Seric */ 205253654Seric 205369774Seric MAP * 205453654Seric makemapentry(line) 205553654Seric char *line; 205653654Seric { 205753654Seric register char *p; 205853654Seric char *mapname; 205953654Seric char *classname; 206064078Seric register STAB *s; 206153654Seric STAB *class; 206253654Seric 206358050Seric for (p = line; isascii(*p) && isspace(*p); p++) 206453654Seric continue; 206558050Seric if (!(isascii(*p) && isalnum(*p))) 206653654Seric { 206753654Seric syserr("readcf: config K line: no map name"); 206869774Seric return NULL; 206953654Seric } 207053654Seric 207153654Seric mapname = p; 207268481Seric while ((isascii(*++p) && isalnum(*p)) || *p == '.') 207353654Seric continue; 207453654Seric if (*p != '\0') 207553654Seric *p++ = '\0'; 207658050Seric while (isascii(*p) && isspace(*p)) 207753654Seric p++; 207858050Seric if (!(isascii(*p) && isalnum(*p))) 207953654Seric { 208053654Seric syserr("readcf: config K line, map %s: no map class", mapname); 208169774Seric return NULL; 208253654Seric } 208353654Seric classname = p; 208458050Seric while (isascii(*++p) && isalnum(*p)) 208553654Seric continue; 208653654Seric if (*p != '\0') 208753654Seric *p++ = '\0'; 208858050Seric while (isascii(*p) && isspace(*p)) 208953654Seric p++; 209053654Seric 209153654Seric /* look up the class */ 209253654Seric class = stab(classname, ST_MAPCLASS, ST_FIND); 209353654Seric if (class == NULL) 209453654Seric { 209553654Seric syserr("readcf: map %s: class %s not available", mapname, classname); 209669774Seric return NULL; 209753654Seric } 209853654Seric 209953654Seric /* enter the map */ 210064078Seric s = stab(mapname, ST_MAP, ST_ENTER); 210164078Seric s->s_map.map_class = &class->s_mapclass; 210264078Seric s->s_map.map_mname = newstr(mapname); 210353654Seric 210464078Seric if (class->s_mapclass.map_parse(&s->s_map, p)) 210564078Seric s->s_map.map_mflags |= MF_VALID; 210664078Seric 210764078Seric if (tTd(37, 5)) 210864078Seric { 210964078Seric printf("map %s, class %s, flags %x, file %s,\n", 211064078Seric s->s_map.map_mname, s->s_map.map_class->map_cname, 211164078Seric s->s_map.map_mflags, 211264078Seric s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 211364078Seric printf("\tapp %s, domain %s, rebuild %s\n", 211464078Seric s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 211564078Seric s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 211664078Seric s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 211764078Seric } 211869774Seric 211969774Seric return &s->s_map; 212053654Seric } 212158112Seric /* 212269783Seric ** STRTORWSET -- convert string to rewriting set number 212369783Seric ** 212469783Seric ** Parameters: 212569783Seric ** p -- the pointer to the string to decode. 212669783Seric ** endp -- if set, store the trailing delimiter here. 212769783Seric ** stabmode -- ST_ENTER to create this entry, ST_FIND if 212869783Seric ** it must already exist. 212969783Seric ** 213069783Seric ** Returns: 213169783Seric ** The appropriate ruleset number. 213269783Seric ** -1 if it is not valid (error already printed) 213369783Seric */ 213469783Seric 213569783Seric int 213669783Seric strtorwset(p, endp, stabmode) 213769783Seric char *p; 213869783Seric char **endp; 213969783Seric int stabmode; 214069783Seric { 214169783Seric int ruleset; 214269783Seric static int nextruleset = MAXRWSETS; 214369783Seric 214469783Seric while (isascii(*p) && isspace(*p)) 214569783Seric p++; 214669783Seric if (!isascii(*p)) 214769783Seric { 214869783Seric syserr("invalid ruleset name: \"%.20s\"", p); 214969783Seric return -1; 215069783Seric } 215169783Seric if (isdigit(*p)) 215269783Seric { 215369783Seric ruleset = strtol(p, endp, 10); 215469783Seric if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 215569783Seric { 215669783Seric syserr("bad ruleset %d (%d max)", 215769783Seric ruleset, MAXRWSETS / 2); 215869783Seric ruleset = -1; 215969783Seric } 216069783Seric } 216169783Seric else 216269783Seric { 216369783Seric STAB *s; 216469783Seric char delim; 216569783Seric char *q; 216669783Seric 216769783Seric q = p; 216869783Seric while (*p != '\0' && isascii(*p) && 216969783Seric (isalnum(*p) || strchr("-_$", *p) != NULL)) 217069783Seric p++; 217169970Seric if (q == p || !isalpha(*q)) 217269970Seric { 217369970Seric /* no valid characters */ 217469970Seric syserr("invalid ruleset name: \"%.20s\"", q); 217569970Seric return -1; 217669970Seric } 217769783Seric while (isascii(*p) && isspace(*p)) 217869783Seric *p++ = '\0'; 217969783Seric delim = *p; 218069783Seric if (delim != '\0') 218169783Seric *p = '\0'; 218269783Seric s = stab(q, ST_RULESET, stabmode); 218369783Seric if (delim != '\0') 218469783Seric *p = delim; 218569783Seric 218669783Seric if (s == NULL) 218769783Seric { 218869783Seric syserr("unknown ruleset %s", q); 218969783Seric return -1; 219069783Seric } 219169783Seric 219269783Seric if (stabmode == ST_ENTER && delim == '=') 219369783Seric { 219469962Seric ruleset = strtol(++p, endp, 10); 219569783Seric if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 219669783Seric { 219769783Seric syserr("bad ruleset %s = %d (%d max)", 219869783Seric q, ruleset, MAXRWSETS / 2); 219969783Seric ruleset = -1; 220069783Seric } 220169783Seric } 220269783Seric else 220369783Seric { 220469783Seric if (endp != NULL) 220569783Seric *endp = p; 220669783Seric if (s->s_ruleset > 0) 220769783Seric ruleset = s->s_ruleset; 220869783Seric else if ((ruleset = --nextruleset) < MAXRWSETS / 2) 220969783Seric { 221069783Seric syserr("%s: too many named rulesets (%d max)", 221169783Seric q, MAXRWSETS / 2); 221269783Seric ruleset = -1; 221369783Seric } 221469783Seric } 221569783Seric if (s->s_ruleset > 0 && ruleset >= 0 && ruleset != s->s_ruleset) 221669783Seric { 221769783Seric syserr("%s: ruleset changed value (old %d, new %d)", 221869783Seric q, ruleset, s->s_ruleset); 221969783Seric ruleset = s->s_ruleset; 222069783Seric } 222169783Seric else if (ruleset > 0) 222269783Seric { 222369783Seric s->s_ruleset = ruleset; 222469783Seric } 222569783Seric } 222669783Seric return ruleset; 222769783Seric } 222869783Seric /* 222968481Seric ** INITTIMEOUTS -- parse and set timeout values 223058112Seric ** 223158112Seric ** Parameters: 223258112Seric ** val -- a pointer to the values. If NULL, do initial 223358112Seric ** settings. 223458112Seric ** 223558112Seric ** Returns: 223658112Seric ** none. 223758112Seric ** 223858112Seric ** Side Effects: 223958112Seric ** Initializes the TimeOuts structure 224058112Seric */ 224158112Seric 224264255Seric #define SECONDS 224358112Seric #define MINUTES * 60 224458112Seric #define HOUR * 3600 224558112Seric 224669748Seric void 224768481Seric inittimeouts(val) 224858112Seric register char *val; 224958112Seric { 225058112Seric register char *p; 225158671Seric extern time_t convtime(); 225258112Seric 225358112Seric if (val == NULL) 225458112Seric { 225558112Seric TimeOuts.to_initial = (time_t) 5 MINUTES; 225658112Seric TimeOuts.to_helo = (time_t) 5 MINUTES; 225758112Seric TimeOuts.to_mail = (time_t) 10 MINUTES; 225858112Seric TimeOuts.to_rcpt = (time_t) 1 HOUR; 225958112Seric TimeOuts.to_datainit = (time_t) 5 MINUTES; 226058112Seric TimeOuts.to_datablock = (time_t) 1 HOUR; 226158112Seric TimeOuts.to_datafinal = (time_t) 1 HOUR; 226258112Seric TimeOuts.to_rset = (time_t) 5 MINUTES; 226358112Seric TimeOuts.to_quit = (time_t) 2 MINUTES; 226458112Seric TimeOuts.to_nextcommand = (time_t) 1 HOUR; 226558112Seric TimeOuts.to_miscshort = (time_t) 2 MINUTES; 226668481Seric #if IDENTPROTO 226764255Seric TimeOuts.to_ident = (time_t) 30 SECONDS; 226868481Seric #else 226968481Seric TimeOuts.to_ident = (time_t) 0 SECONDS; 227068481Seric #endif 227168481Seric TimeOuts.to_fileopen = (time_t) 60 SECONDS; 227258112Seric return; 227358112Seric } 227458112Seric 227558112Seric for (;; val = p) 227658112Seric { 227758112Seric while (isascii(*val) && isspace(*val)) 227858112Seric val++; 227958112Seric if (*val == '\0') 228058112Seric break; 228158112Seric for (p = val; *p != '\0' && *p != ','; p++) 228258112Seric continue; 228358112Seric if (*p != '\0') 228458112Seric *p++ = '\0'; 228558112Seric 228658112Seric if (isascii(*val) && isdigit(*val)) 228758112Seric { 228858112Seric /* old syntax -- set everything */ 228958796Seric TimeOuts.to_mail = convtime(val, 'm'); 229058112Seric TimeOuts.to_rcpt = TimeOuts.to_mail; 229158112Seric TimeOuts.to_datainit = TimeOuts.to_mail; 229258112Seric TimeOuts.to_datablock = TimeOuts.to_mail; 229358112Seric TimeOuts.to_datafinal = TimeOuts.to_mail; 229458112Seric TimeOuts.to_nextcommand = TimeOuts.to_mail; 229558112Seric continue; 229658112Seric } 229758112Seric else 229858112Seric { 229968481Seric register char *q = strchr(val, ':'); 230058112Seric 230168481Seric if (q == NULL && (q = strchr(val, '=')) == NULL) 230258112Seric { 230358112Seric /* syntax error */ 230458112Seric continue; 230558112Seric } 230658112Seric *q++ = '\0'; 230768481Seric settimeout(val, q); 230868481Seric } 230968481Seric } 231068481Seric } 231168481Seric /* 231268481Seric ** SETTIMEOUT -- set an individual timeout 231368481Seric ** 231468481Seric ** Parameters: 231568481Seric ** name -- the name of the timeout. 231668481Seric ** val -- the value of the timeout. 231768481Seric ** 231868481Seric ** Returns: 231968481Seric ** none. 232068481Seric */ 232158112Seric 232269748Seric void 232368481Seric settimeout(name, val) 232468481Seric char *name; 232568481Seric char *val; 232668481Seric { 232768481Seric register char *p; 232868481Seric time_t to; 232968481Seric extern time_t convtime(); 233068481Seric 233168481Seric to = convtime(val, 'm'); 233268481Seric p = strchr(name, '.'); 233368481Seric if (p != NULL) 233468481Seric *p++ = '\0'; 233568481Seric 233668481Seric if (strcasecmp(name, "initial") == 0) 233768481Seric TimeOuts.to_initial = to; 233868481Seric else if (strcasecmp(name, "mail") == 0) 233968481Seric TimeOuts.to_mail = to; 234068481Seric else if (strcasecmp(name, "rcpt") == 0) 234168481Seric TimeOuts.to_rcpt = to; 234268481Seric else if (strcasecmp(name, "datainit") == 0) 234368481Seric TimeOuts.to_datainit = to; 234468481Seric else if (strcasecmp(name, "datablock") == 0) 234568481Seric TimeOuts.to_datablock = to; 234668481Seric else if (strcasecmp(name, "datafinal") == 0) 234768481Seric TimeOuts.to_datafinal = to; 234868481Seric else if (strcasecmp(name, "command") == 0) 234968481Seric TimeOuts.to_nextcommand = to; 235068481Seric else if (strcasecmp(name, "rset") == 0) 235168481Seric TimeOuts.to_rset = to; 235268481Seric else if (strcasecmp(name, "helo") == 0) 235368481Seric TimeOuts.to_helo = to; 235468481Seric else if (strcasecmp(name, "quit") == 0) 235568481Seric TimeOuts.to_quit = to; 235668481Seric else if (strcasecmp(name, "misc") == 0) 235768481Seric TimeOuts.to_miscshort = to; 235868481Seric else if (strcasecmp(name, "ident") == 0) 235968481Seric TimeOuts.to_ident = to; 236068481Seric else if (strcasecmp(name, "fileopen") == 0) 236168481Seric TimeOuts.to_fileopen = to; 236268481Seric else if (strcasecmp(name, "queuewarn") == 0) 236368481Seric { 236468481Seric to = convtime(val, 'h'); 236568481Seric if (p == NULL || strcmp(p, "*") == 0) 236668481Seric { 236768481Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 236868481Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 236968481Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 237058112Seric } 237168481Seric else if (strcasecmp(p, "normal") == 0) 237268481Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 237368481Seric else if (strcasecmp(p, "urgent") == 0) 237468481Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 237568481Seric else if (strcasecmp(p, "non-urgent") == 0) 237668481Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 237768481Seric else 237868481Seric syserr("settimeout: invalid queuewarn subtimeout %s", p); 237958112Seric } 238068481Seric else if (strcasecmp(name, "queuereturn") == 0) 238168481Seric { 238268481Seric to = convtime(val, 'd'); 238368481Seric if (p == NULL || strcmp(p, "*") == 0) 238468481Seric { 238568481Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 238668481Seric TimeOuts.to_q_return[TOC_URGENT] = to; 238768481Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 238868481Seric } 238968481Seric else if (strcasecmp(p, "normal") == 0) 239068481Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 239168481Seric else if (strcasecmp(p, "urgent") == 0) 239268481Seric TimeOuts.to_q_return[TOC_URGENT] = to; 239368481Seric else if (strcasecmp(p, "non-urgent") == 0) 239468481Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 239568481Seric else 239668481Seric syserr("settimeout: invalid queuereturn subtimeout %s", p); 239768481Seric } 239868481Seric else 239968481Seric syserr("settimeout: invalid timeout %s", name); 240058112Seric } 2401