122709Sdist /* 234921Sbostic * Copyright (c) 1983 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*67826Seric static char sccsid[] = "@(#)readcf.c 8.43 (Berkeley) 10/17/94"; 1133731Sbostic #endif /* not lint */ 1222709Sdist 133313Seric # include "sendmail.h" 1464133Seric # include <pwd.h> 1564133Seric # include <grp.h> 1666334Seric #if NAMED_BIND 1757207Seric # include <resolv.h> 1857207Seric #endif 193308Seric 203308Seric /* 213308Seric ** READCF -- read control file. 223308Seric ** 233308Seric ** This routine reads the control file and builds the internal 243308Seric ** form. 253308Seric ** 264432Seric ** The file is formatted as a sequence of lines, each taken 274432Seric ** atomically. The first character of each line describes how 284432Seric ** the line is to be interpreted. The lines are: 294432Seric ** Dxval Define macro x to have value val. 304432Seric ** Cxword Put word into class x. 314432Seric ** Fxfile [fmt] Read file for lines to put into 324432Seric ** class x. Use scanf string 'fmt' 334432Seric ** or "%s" if not present. Fmt should 344432Seric ** only produce one string-valued result. 354432Seric ** Hname: value Define header with field-name 'name' 364432Seric ** and value as specified; this will be 374432Seric ** macro expanded immediately before 384432Seric ** use. 394432Seric ** Sn Use rewriting set n. 404432Seric ** Rlhs rhs Rewrite addresses that match lhs to 414432Seric ** be rhs. 4224944Seric ** Mn arg=val... Define mailer. n is the internal name. 4324944Seric ** Args specify mailer parameters. 448252Seric ** Oxvalue Set option x to value. 458252Seric ** Pname=value Set precedence name to value. 4664718Seric ** Vversioncode[/vendorcode] 4764718Seric ** Version level/vendor name of 4864718Seric ** configuration syntax. 4953654Seric ** Kmapname mapclass arguments.... 5053654Seric ** Define keyed lookup of a given class. 5153654Seric ** Arguments are class dependent. 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 6655012Seric readcf(cfname, safe, e) 673308Seric char *cfname; 6854973Seric bool safe; 6955012Seric register ENVELOPE *e; 703308Seric { 713308Seric FILE *cf; 728547Seric int ruleset = 0; 738547Seric char *q; 749350Seric struct rewrite *rwp = NULL; 7557135Seric char *bp; 7664718Seric auto char *ep; 7757589Seric int nfuzzy; 7864133Seric char *file; 7964133Seric bool optional; 8067769Seric int mid; 813308Seric char buf[MAXLINE]; 823308Seric register char *p; 833308Seric extern char **copyplist(); 8452647Seric struct stat statb; 855909Seric char exbuf[MAXLINE]; 8665066Seric char pvpbuf[MAXLINE + MAXATOM]; 87*67826Seric static char *null_list[1] = { NULL }; 8810709Seric extern char *munchstring(); 8953654Seric extern void makemapentry(); 903308Seric 9152647Seric FileName = cfname; 9252647Seric LineNumber = 0; 9352647Seric 943308Seric cf = fopen(cfname, "r"); 953308Seric if (cf == NULL) 963308Seric { 9752647Seric syserr("cannot open"); 983308Seric exit(EX_OSFILE); 993308Seric } 1003308Seric 10152647Seric if (fstat(fileno(cf), &statb) < 0) 10252647Seric { 10352647Seric syserr("cannot fstat"); 10452647Seric exit(EX_OSFILE); 10552647Seric } 10652647Seric 10752647Seric if (!S_ISREG(statb.st_mode)) 10852647Seric { 10952647Seric syserr("not a plain file"); 11052647Seric exit(EX_OSFILE); 11152647Seric } 11252647Seric 11352647Seric if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode)) 11452647Seric { 11553037Seric if (OpMode == MD_DAEMON || OpMode == MD_FREEZE) 11653037Seric fprintf(stderr, "%s: WARNING: dangerous write permissions\n", 11753037Seric FileName); 11853037Seric #ifdef LOG 11953037Seric if (LogLevel > 0) 12053037Seric syslog(LOG_CRIT, "%s: WARNING: dangerous write permissions", 12153037Seric FileName); 12253037Seric #endif 12352647Seric } 12452647Seric 12559254Seric #ifdef XLA 12659254Seric xla_zero(); 12759254Seric #endif 12859254Seric 12957135Seric while ((bp = fgetfolded(buf, sizeof buf, cf)) != NULL) 1303308Seric { 13157135Seric if (bp[0] == '#') 13257135Seric { 13357135Seric if (bp != buf) 13457135Seric free(bp); 13552637Seric continue; 13657135Seric } 13752637Seric 13867769Seric /* do macro expansion mappings */ 13957135Seric for (p = bp; *p != '\0'; p++) 14016157Seric { 14157135Seric if (*p == '#' && p > bp && ConfigLevel >= 3) 14252647Seric { 14352647Seric /* this is an on-line comment */ 14452647Seric register char *e; 14552647Seric 14658050Seric switch (*--p & 0377) 14752647Seric { 14858050Seric case MACROEXPAND: 14952647Seric /* it's from $# -- let it go through */ 15052647Seric p++; 15152647Seric break; 15252647Seric 15352647Seric case '\\': 15452647Seric /* it's backslash escaped */ 15552647Seric (void) strcpy(p, p + 1); 15652647Seric break; 15752647Seric 15852647Seric default: 15952647Seric /* delete preceeding white space */ 16058050Seric while (isascii(*p) && isspace(*p) && p > bp) 16152647Seric p--; 16256795Seric if ((e = strchr(++p, '\n')) != NULL) 16352647Seric (void) strcpy(p, e); 16452647Seric else 16552647Seric p[0] = p[1] = '\0'; 16652647Seric break; 16752647Seric } 16852647Seric continue; 16952647Seric } 17052647Seric 17167769Seric if (*p != '$' || p[1] == '\0') 17216157Seric continue; 17316157Seric 17416157Seric if (p[1] == '$') 17516157Seric { 17616157Seric /* actual dollar sign.... */ 17723111Seric (void) strcpy(p, p + 1); 17816157Seric continue; 17916157Seric } 18016157Seric 18116157Seric /* convert to macro expansion character */ 18267769Seric *p++ = MACROEXPAND; 18367769Seric 18467769Seric /* convert macro name to code */ 18567769Seric *p = macid(p, &ep); 18667769Seric if (ep != p) 18767769Seric strcpy(p + 1, ep); 18816157Seric } 18916157Seric 19016157Seric /* interpret this line */ 19164718Seric errno = 0; 19257135Seric switch (bp[0]) 1933308Seric { 1943308Seric case '\0': 1953308Seric case '#': /* comment */ 1963308Seric break; 1973308Seric 1983308Seric case 'R': /* rewriting rule */ 19957135Seric for (p = &bp[1]; *p != '\0' && *p != '\t'; p++) 2003308Seric continue; 2013308Seric 2023308Seric if (*p == '\0') 2035909Seric { 20465821Seric syserr("invalid rewrite line \"%s\" (tab expected)", bp); 2055909Seric break; 2065909Seric } 2075909Seric 2085909Seric /* allocate space for the rule header */ 2095909Seric if (rwp == NULL) 2105909Seric { 2115909Seric RewriteRules[ruleset] = rwp = 2125909Seric (struct rewrite *) xalloc(sizeof *rwp); 2135909Seric } 2143308Seric else 2153308Seric { 2165909Seric rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp); 2175909Seric rwp = rwp->r_next; 2185909Seric } 2195909Seric rwp->r_next = NULL; 2203308Seric 2215909Seric /* expand and save the LHS */ 2225909Seric *p = '\0'; 22357135Seric expand(&bp[1], exbuf, &exbuf[sizeof exbuf], e); 22465066Seric rwp->r_lhs = prescan(exbuf, '\t', pvpbuf, 22565066Seric sizeof pvpbuf, NULL); 22657589Seric nfuzzy = 0; 2275909Seric if (rwp->r_lhs != NULL) 22857589Seric { 22957589Seric register char **ap; 23057589Seric 2315909Seric rwp->r_lhs = copyplist(rwp->r_lhs, TRUE); 23257589Seric 23357589Seric /* count the number of fuzzy matches in LHS */ 23457589Seric for (ap = rwp->r_lhs; *ap != NULL; ap++) 23557589Seric { 23658148Seric char *botch; 23758148Seric 23858148Seric botch = NULL; 23958050Seric switch (**ap & 0377) 24057589Seric { 24157589Seric case MATCHZANY: 24257589Seric case MATCHANY: 24357589Seric case MATCHONE: 24457589Seric case MATCHCLASS: 24557589Seric case MATCHNCLASS: 24657589Seric nfuzzy++; 24758148Seric break; 24858148Seric 24958148Seric case MATCHREPL: 25058148Seric botch = "$0-$9"; 25158148Seric break; 25258148Seric 25358148Seric case CANONNET: 25458148Seric botch = "$#"; 25558148Seric break; 25658148Seric 25758148Seric case CANONUSER: 25858148Seric botch = "$:"; 25958148Seric break; 26058148Seric 26158148Seric case CALLSUBR: 26258148Seric botch = "$>"; 26358148Seric break; 26458148Seric 26558148Seric case CONDIF: 26658148Seric botch = "$?"; 26758148Seric break; 26858148Seric 26958148Seric case CONDELSE: 27058148Seric botch = "$|"; 27158148Seric break; 27258148Seric 27358148Seric case CONDFI: 27458148Seric botch = "$."; 27558148Seric break; 27658148Seric 27758148Seric case HOSTBEGIN: 27858148Seric botch = "$["; 27958148Seric break; 28058148Seric 28158148Seric case HOSTEND: 28258148Seric botch = "$]"; 28358148Seric break; 28458148Seric 28558148Seric case LOOKUPBEGIN: 28658148Seric botch = "$("; 28758148Seric break; 28858148Seric 28958148Seric case LOOKUPEND: 29058148Seric botch = "$)"; 29158148Seric break; 29257589Seric } 29358148Seric if (botch != NULL) 29458148Seric syserr("Inappropriate use of %s on LHS", 29558148Seric botch); 29657589Seric } 29757589Seric } 29856678Seric else 299*67826Seric { 30056678Seric syserr("R line: null LHS"); 301*67826Seric rwp->r_lhs = null_list; 302*67826Seric } 3035909Seric 3045909Seric /* expand and save the RHS */ 3055909Seric while (*++p == '\t') 3065909Seric continue; 3077231Seric q = p; 3087231Seric while (*p != '\0' && *p != '\t') 3097231Seric p++; 3107231Seric *p = '\0'; 31155012Seric expand(q, exbuf, &exbuf[sizeof exbuf], e); 31265066Seric rwp->r_rhs = prescan(exbuf, '\t', pvpbuf, 31365066Seric sizeof pvpbuf, NULL); 3145909Seric if (rwp->r_rhs != NULL) 31557589Seric { 31657589Seric register char **ap; 31757589Seric 3185909Seric rwp->r_rhs = copyplist(rwp->r_rhs, TRUE); 31957589Seric 32057589Seric /* check no out-of-bounds replacements */ 32157589Seric nfuzzy += '0'; 32257589Seric for (ap = rwp->r_rhs; *ap != NULL; ap++) 32357589Seric { 32458148Seric char *botch; 32558148Seric 32658148Seric botch = NULL; 32758148Seric switch (**ap & 0377) 32857589Seric { 32958148Seric case MATCHREPL: 33058148Seric if ((*ap)[1] <= '0' || (*ap)[1] > nfuzzy) 33158148Seric { 33258148Seric syserr("replacement $%c out of bounds", 33358148Seric (*ap)[1]); 33458148Seric } 33558148Seric break; 33658148Seric 33758148Seric case MATCHZANY: 33858148Seric botch = "$*"; 33958148Seric break; 34058148Seric 34158148Seric case MATCHANY: 34258148Seric botch = "$+"; 34358148Seric break; 34458148Seric 34558148Seric case MATCHONE: 34658148Seric botch = "$-"; 34758148Seric break; 34858148Seric 34958148Seric case MATCHCLASS: 35058148Seric botch = "$="; 35158148Seric break; 35258148Seric 35358148Seric case MATCHNCLASS: 35458148Seric botch = "$~"; 35558148Seric break; 35657589Seric } 35758148Seric if (botch != NULL) 35858148Seric syserr("Inappropriate use of %s on RHS", 35958148Seric botch); 36057589Seric } 36157589Seric } 36256678Seric else 363*67826Seric { 36456678Seric syserr("R line: null RHS"); 365*67826Seric rwp->r_rhs = null_list; 366*67826Seric } 3673308Seric break; 3683308Seric 3694072Seric case 'S': /* select rewriting set */ 37064440Seric for (p = &bp[1]; isascii(*p) && isspace(*p); p++) 37164440Seric continue; 37264440Seric if (!isascii(*p) || !isdigit(*p)) 37364440Seric { 37464440Seric syserr("invalid argument to S line: \"%.20s\"", 37564440Seric &bp[1]); 37664440Seric break; 37764440Seric } 37864440Seric ruleset = atoi(p); 3798056Seric if (ruleset >= MAXRWSETS || ruleset < 0) 3808056Seric { 3819381Seric syserr("bad ruleset %d (%d max)", ruleset, MAXRWSETS); 3828056Seric ruleset = 0; 3838056Seric } 3844072Seric rwp = NULL; 3854072Seric break; 3864072Seric 3873308Seric case 'D': /* macro definition */ 38867769Seric mid = macid(&bp[1], &ep); 38967769Seric p = munchstring(ep, NULL); 39067769Seric define(mid, newstr(p), e); 3913308Seric break; 3923308Seric 3933387Seric case 'H': /* required header line */ 39457135Seric (void) chompheader(&bp[1], TRUE, e); 3953387Seric break; 3963387Seric 3974061Seric case 'C': /* word class */ 3984432Seric /* scan the list of words and set class for all */ 39967769Seric mid = macid(&bp[1], &ep); 40067769Seric expand(ep, exbuf, &exbuf[sizeof exbuf], e); 40164121Seric for (p = exbuf; *p != '\0'; ) 4024061Seric { 4034061Seric register char *wd; 4044061Seric char delim; 4054061Seric 40658050Seric while (*p != '\0' && isascii(*p) && isspace(*p)) 4074061Seric p++; 4084061Seric wd = p; 40958050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 4104061Seric p++; 4114061Seric delim = *p; 4124061Seric *p = '\0'; 4134061Seric if (wd[0] != '\0') 41467769Seric setclass(mid, wd); 4154061Seric *p = delim; 4164061Seric } 4174061Seric break; 4184061Seric 41959272Seric case 'F': /* word class from file */ 42067769Seric mid = macid(&bp[1], &ep); 42167769Seric for (p = ep; isascii(*p) && isspace(*p); ) 42264133Seric p++; 42364133Seric if (p[0] == '-' && p[1] == 'o') 42464133Seric { 42564133Seric optional = TRUE; 42664133Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 42764133Seric p++; 42864133Seric while (isascii(*p) && isspace(*p)) 42967615Seric p++; 43064133Seric } 43164133Seric else 43264133Seric optional = FALSE; 43364133Seric file = p; 43464133Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 43564133Seric p++; 43659272Seric if (*p == '\0') 43759272Seric p = "%s"; 43859272Seric else 43959272Seric { 44059272Seric *p = '\0'; 44159272Seric while (isascii(*++p) && isspace(*p)) 44259272Seric continue; 44359272Seric } 44464133Seric fileclass(bp[1], file, p, safe, optional); 44559272Seric break; 44659272Seric 44759156Seric #ifdef XLA 44859156Seric case 'L': /* extended load average description */ 44959156Seric xla_init(&bp[1]); 45059156Seric break; 45159156Seric #endif 45259156Seric 4534096Seric case 'M': /* define mailer */ 45457135Seric makemailer(&bp[1]); 4554096Seric break; 4564096Seric 4578252Seric case 'O': /* set option */ 45858734Seric setoption(bp[1], &bp[2], safe, FALSE, e); 4598252Seric break; 4608252Seric 4618252Seric case 'P': /* set precedence */ 4628252Seric if (NumPriorities >= MAXPRIORITIES) 4638252Seric { 4648547Seric toomany('P', MAXPRIORITIES); 4658252Seric break; 4668252Seric } 46757135Seric for (p = &bp[1]; *p != '\0' && *p != '=' && *p != '\t'; p++) 4688252Seric continue; 4698252Seric if (*p == '\0') 4708252Seric goto badline; 4718252Seric *p = '\0'; 47257135Seric Priorities[NumPriorities].pri_name = newstr(&bp[1]); 4738252Seric Priorities[NumPriorities].pri_val = atoi(++p); 4748252Seric NumPriorities++; 4758252Seric break; 4768252Seric 4778547Seric case 'T': /* trusted user(s) */ 47858161Seric /* this option is obsolete, but will be ignored */ 4798547Seric break; 4808547Seric 48152645Seric case 'V': /* configuration syntax version */ 48264440Seric for (p = &bp[1]; isascii(*p) && isspace(*p); p++) 48364440Seric continue; 48464440Seric if (!isascii(*p) || !isdigit(*p)) 48564440Seric { 48664440Seric syserr("invalid argument to V line: \"%.20s\"", 48764440Seric &bp[1]); 48864440Seric break; 48964440Seric } 49064718Seric ConfigLevel = strtol(p, &ep, 10); 49164279Seric if (ConfigLevel >= 5) 49264279Seric { 49364279Seric /* level 5 configs have short name in $w */ 49464279Seric p = macvalue('w', e); 49564279Seric if (p != NULL && (p = strchr(p, '.')) != NULL) 49664279Seric *p = '\0'; 49764279Seric } 49864718Seric if (*ep++ == '/') 49964718Seric { 50064718Seric /* extract vendor code */ 50164718Seric for (p = ep; isascii(*p) && isalpha(*p); ) 50264718Seric p++; 50364718Seric *p = '\0'; 50464718Seric 50564718Seric if (!setvendor(ep)) 50664718Seric syserr("invalid V line vendor code: \"%s\"", 50764718Seric ep); 50864718Seric } 50952645Seric break; 51052645Seric 51153654Seric case 'K': 51257135Seric makemapentry(&bp[1]); 51353654Seric break; 51453654Seric 5153308Seric default: 5164061Seric badline: 51757135Seric syserr("unknown control line \"%s\"", bp); 5183308Seric } 51957135Seric if (bp != buf) 52057135Seric free(bp); 5213308Seric } 52252637Seric if (ferror(cf)) 52352637Seric { 52452647Seric syserr("I/O read error", cfname); 52552637Seric exit(EX_OSFILE); 52652637Seric } 52752637Seric fclose(cf); 5289381Seric FileName = NULL; 52956836Seric 53067730Seric /* initialize host maps from local service tables */ 53167730Seric inithostmaps(); 53267730Seric 53357076Seric if (stab("host", ST_MAP, ST_FIND) == NULL) 53457076Seric { 53557076Seric /* user didn't initialize: set up host map */ 53657076Seric strcpy(buf, "host host"); 53766334Seric #if NAMED_BIND 53857076Seric if (ConfigLevel >= 2) 53957076Seric strcat(buf, " -a."); 54064947Seric #endif 54157076Seric makemapentry(buf); 54257076Seric } 5434096Seric } 5444096Seric /* 5458547Seric ** TOOMANY -- signal too many of some option 5468547Seric ** 5478547Seric ** Parameters: 5488547Seric ** id -- the id of the error line 5498547Seric ** maxcnt -- the maximum possible values 5508547Seric ** 5518547Seric ** Returns: 5528547Seric ** none. 5538547Seric ** 5548547Seric ** Side Effects: 5558547Seric ** gives a syserr. 5568547Seric */ 5578547Seric 5588547Seric toomany(id, maxcnt) 5598547Seric char id; 5608547Seric int maxcnt; 5618547Seric { 5629381Seric syserr("too many %c lines, %d max", id, maxcnt); 5638547Seric } 5648547Seric /* 5654432Seric ** FILECLASS -- read members of a class from a file 5664432Seric ** 5674432Seric ** Parameters: 5684432Seric ** class -- class to define. 5694432Seric ** filename -- name of file to read. 5704432Seric ** fmt -- scanf string to use for match. 57164133Seric ** safe -- if set, this is a safe read. 57264133Seric ** optional -- if set, it is not an error for the file to 57364133Seric ** not exist. 5744432Seric ** 5754432Seric ** Returns: 5764432Seric ** none 5774432Seric ** 5784432Seric ** Side Effects: 5794432Seric ** 5804432Seric ** puts all lines in filename that match a scanf into 5814432Seric ** the named class. 5824432Seric */ 5834432Seric 58464133Seric fileclass(class, filename, fmt, safe, optional) 5854432Seric int class; 5864432Seric char *filename; 5874432Seric char *fmt; 58854973Seric bool safe; 58964133Seric bool optional; 5904432Seric { 59125808Seric FILE *f; 59254973Seric struct stat stbuf; 5934432Seric char buf[MAXLINE]; 5944432Seric 59566101Seric if (tTd(37, 2)) 59666101Seric printf("fileclass(%s, fmt=%s)\n", filename, fmt); 59766101Seric 59866031Seric if (filename[0] == '|') 59966031Seric { 60066031Seric syserr("fileclass: pipes (F%c%s) not supported due to security problems", 60166031Seric class, filename); 60266031Seric return; 60366031Seric } 60454973Seric if (stat(filename, &stbuf) < 0) 60554973Seric { 60666101Seric if (tTd(37, 2)) 60766101Seric printf(" cannot stat (%s)\n", errstring(errno)); 60864133Seric if (!optional) 60964133Seric syserr("fileclass: cannot stat %s", filename); 61054973Seric return; 61154973Seric } 61254973Seric if (!S_ISREG(stbuf.st_mode)) 61354973Seric { 61454973Seric syserr("fileclass: %s not a regular file", filename); 61554973Seric return; 61654973Seric } 61754973Seric if (!safe && access(filename, R_OK) < 0) 61854973Seric { 61954973Seric syserr("fileclass: access denied on %s", filename); 62054973Seric return; 62154973Seric } 62254973Seric f = fopen(filename, "r"); 6234432Seric if (f == NULL) 6244432Seric { 62554973Seric syserr("fileclass: cannot open %s", filename); 6264432Seric return; 6274432Seric } 6284432Seric 6294432Seric while (fgets(buf, sizeof buf, f) != NULL) 6304432Seric { 6314432Seric register STAB *s; 63225808Seric register char *p; 63325808Seric # ifdef SCANF 6344432Seric char wordbuf[MAXNAME+1]; 6354432Seric 6364432Seric if (sscanf(buf, fmt, wordbuf) != 1) 6374432Seric continue; 63825808Seric p = wordbuf; 63956795Seric # else /* SCANF */ 64025808Seric p = buf; 64156795Seric # endif /* SCANF */ 64225808Seric 64325808Seric /* 64425808Seric ** Break up the match into words. 64525808Seric */ 64625808Seric 64725808Seric while (*p != '\0') 64825808Seric { 64925808Seric register char *q; 65025808Seric 65125808Seric /* strip leading spaces */ 65258050Seric while (isascii(*p) && isspace(*p)) 65325808Seric p++; 65425808Seric if (*p == '\0') 65525808Seric break; 65625808Seric 65725808Seric /* find the end of the word */ 65825808Seric q = p; 65958050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 66025808Seric p++; 66125808Seric if (*p != '\0') 66225808Seric *p++ = '\0'; 66325808Seric 66425808Seric /* enter the word in the symbol table */ 66566101Seric setclass(class, q); 66625808Seric } 6674432Seric } 6684432Seric 66954973Seric (void) fclose(f); 6704432Seric } 6714432Seric /* 6724096Seric ** MAKEMAILER -- define a new mailer. 6734096Seric ** 6744096Seric ** Parameters: 67510327Seric ** line -- description of mailer. This is in labeled 67610327Seric ** fields. The fields are: 67710327Seric ** P -- the path to the mailer 67810327Seric ** F -- the flags associated with the mailer 67910327Seric ** A -- the argv for this mailer 68010327Seric ** S -- the sender rewriting set 68110327Seric ** R -- the recipient rewriting set 68210327Seric ** E -- the eol string 68310327Seric ** The first word is the canonical name of the mailer. 6844096Seric ** 6854096Seric ** Returns: 6864096Seric ** none. 6874096Seric ** 6884096Seric ** Side Effects: 6894096Seric ** enters the mailer into the mailer table. 6904096Seric */ 6913308Seric 69221066Seric makemailer(line) 6934096Seric char *line; 6944096Seric { 6954096Seric register char *p; 6968067Seric register struct mailer *m; 6978067Seric register STAB *s; 6988067Seric int i; 69910327Seric char fcode; 70058020Seric auto char *endp; 7014096Seric extern int NextMailer; 70210327Seric extern char **makeargv(); 70310327Seric extern char *munchstring(); 70410701Seric extern long atol(); 7054096Seric 70610327Seric /* allocate a mailer and set up defaults */ 70710327Seric m = (struct mailer *) xalloc(sizeof *m); 70810327Seric bzero((char *) m, sizeof *m); 70910327Seric m->m_eol = "\n"; 71067604Seric m->m_uid = m->m_gid = 0; 71110327Seric 71210327Seric /* collect the mailer name */ 71358050Seric for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++) 71410327Seric continue; 71510327Seric if (*p != '\0') 71610327Seric *p++ = '\0'; 71710327Seric m->m_name = newstr(line); 71810327Seric 71910327Seric /* now scan through and assign info from the fields */ 72010327Seric while (*p != '\0') 72110327Seric { 72258333Seric auto char *delimptr; 72358333Seric 72458050Seric while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p)))) 72510327Seric p++; 72610327Seric 72710327Seric /* p now points to field code */ 72810327Seric fcode = *p; 72910327Seric while (*p != '\0' && *p != '=' && *p != ',') 73010327Seric p++; 73110327Seric if (*p++ != '=') 73210327Seric { 73352637Seric syserr("mailer %s: `=' expected", m->m_name); 73410327Seric return; 73510327Seric } 73658050Seric while (isascii(*p) && isspace(*p)) 73710327Seric p++; 73810327Seric 73910327Seric /* p now points to the field body */ 74058333Seric p = munchstring(p, &delimptr); 74110327Seric 74210327Seric /* install the field into the mailer struct */ 74310327Seric switch (fcode) 74410327Seric { 74510327Seric case 'P': /* pathname */ 74610327Seric m->m_mailer = newstr(p); 74710327Seric break; 74810327Seric 74910327Seric case 'F': /* flags */ 75010687Seric for (; *p != '\0'; p++) 75158050Seric if (!(isascii(*p) && isspace(*p))) 75252637Seric setbitn(*p, m->m_flags); 75310327Seric break; 75410327Seric 75510327Seric case 'S': /* sender rewriting ruleset */ 75610327Seric case 'R': /* recipient rewriting ruleset */ 75758020Seric i = strtol(p, &endp, 10); 75810327Seric if (i < 0 || i >= MAXRWSETS) 75910327Seric { 76010327Seric syserr("invalid rewrite set, %d max", MAXRWSETS); 76110327Seric return; 76210327Seric } 76310327Seric if (fcode == 'S') 76458020Seric m->m_sh_rwset = m->m_se_rwset = i; 76510327Seric else 76658020Seric m->m_rh_rwset = m->m_re_rwset = i; 76758020Seric 76858020Seric p = endp; 76959985Seric if (*p++ == '/') 77058020Seric { 77158020Seric i = strtol(p, NULL, 10); 77258020Seric if (i < 0 || i >= MAXRWSETS) 77358020Seric { 77458020Seric syserr("invalid rewrite set, %d max", 77558020Seric MAXRWSETS); 77658020Seric return; 77758020Seric } 77858020Seric if (fcode == 'S') 77958020Seric m->m_sh_rwset = i; 78058020Seric else 78158020Seric m->m_rh_rwset = i; 78258020Seric } 78310327Seric break; 78410327Seric 78510327Seric case 'E': /* end of line string */ 78610327Seric m->m_eol = newstr(p); 78710327Seric break; 78810327Seric 78910327Seric case 'A': /* argument vector */ 79010327Seric m->m_argv = makeargv(p); 79110327Seric break; 79210701Seric 79310701Seric case 'M': /* maximum message size */ 79410701Seric m->m_maxsize = atol(p); 79510701Seric break; 79652106Seric 79752106Seric case 'L': /* maximum line length */ 79852106Seric m->m_linelimit = atoi(p); 79952106Seric break; 80058935Seric 80158935Seric case 'D': /* working directory */ 80258935Seric m->m_execdir = newstr(p); 80358935Seric break; 80467604Seric 80567604Seric case 'U': /* user id */ 80667604Seric if (isascii(*p) && !isdigit(*p)) 80767604Seric { 80867604Seric char *q = p; 80967604Seric struct passwd *pw; 81067604Seric 81167604Seric while (isascii(*p) && isalnum(*p)) 81267604Seric p++; 81367604Seric while (isascii(*p) && isspace(*p)) 81467604Seric *p++ = '\0'; 81567604Seric if (*p != '\0') 81667604Seric *p++ = '\0'; 81767604Seric pw = getpwnam(q); 81867604Seric if (pw == NULL) 81967604Seric syserr("readcf: mailer U= flag: unknown user %s", q); 82067604Seric else 82167604Seric { 82267604Seric m->m_uid = pw->pw_uid; 82367604Seric m->m_gid = pw->pw_gid; 82467604Seric } 82567604Seric } 82667604Seric else 82767604Seric { 82867604Seric auto char *q; 82967604Seric 83067604Seric m->m_uid = strtol(p, &q, 0); 83167604Seric p = q; 83267604Seric } 83367604Seric while (isascii(*p) && isspace(*p)) 83467604Seric p++; 83567604Seric if (*p == '\0') 83667604Seric break; 83767604Seric if (isascii(*p) && !isdigit(*p)) 83867604Seric { 83967604Seric char *q = p; 84067604Seric struct group *gr; 84167604Seric 84267604Seric while (isascii(*p) && isalnum(*p)) 84367604Seric p++; 84467604Seric *p++ = '\0'; 84567604Seric gr = getgrnam(q); 84667604Seric if (gr == NULL) 84767604Seric syserr("readcf: mailer U= flag: unknown group %s", q); 84867604Seric else 84967604Seric m->m_gid = gr->gr_gid; 85067604Seric } 85167604Seric else 85267604Seric { 85367604Seric m->m_gid = strtol(p, NULL, 0); 85467604Seric } 85567604Seric break; 85610327Seric } 85710327Seric 85858333Seric p = delimptr; 85910327Seric } 86010327Seric 86152106Seric /* do some heuristic cleanup for back compatibility */ 86252106Seric if (bitnset(M_LIMITS, m->m_flags)) 86352106Seric { 86452106Seric if (m->m_linelimit == 0) 86552106Seric m->m_linelimit = SMTPLINELIM; 86655418Seric if (ConfigLevel < 2) 86752106Seric setbitn(M_7BITS, m->m_flags); 86852106Seric } 86952106Seric 87058321Seric /* do some rationality checking */ 87158321Seric if (m->m_argv == NULL) 87258321Seric { 87358321Seric syserr("M%s: A= argument required", m->m_name); 87458321Seric return; 87558321Seric } 87658321Seric if (m->m_mailer == NULL) 87758321Seric { 87858321Seric syserr("M%s: P= argument required", m->m_name); 87958321Seric return; 88058321Seric } 88158321Seric 8824096Seric if (NextMailer >= MAXMAILERS) 8834096Seric { 8849381Seric syserr("too many mailers defined (%d max)", MAXMAILERS); 8854096Seric return; 8864096Seric } 88757402Seric 88810327Seric s = stab(m->m_name, ST_MAILER, ST_ENTER); 88957402Seric if (s->s_mailer != NULL) 89057402Seric { 89157402Seric i = s->s_mailer->m_mno; 89257402Seric free(s->s_mailer); 89357402Seric } 89457402Seric else 89557402Seric { 89657402Seric i = NextMailer++; 89757402Seric } 89857402Seric Mailer[i] = s->s_mailer = m; 89957454Seric m->m_mno = i; 90010327Seric } 90110327Seric /* 90210327Seric ** MUNCHSTRING -- translate a string into internal form. 90310327Seric ** 90410327Seric ** Parameters: 90510327Seric ** p -- the string to munch. 90658333Seric ** delimptr -- if non-NULL, set to the pointer of the 90758333Seric ** field delimiter character. 90810327Seric ** 90910327Seric ** Returns: 91010327Seric ** the munched string. 91110327Seric */ 9124096Seric 91310327Seric char * 91458333Seric munchstring(p, delimptr) 91510327Seric register char *p; 91658333Seric char **delimptr; 91710327Seric { 91810327Seric register char *q; 91910327Seric bool backslash = FALSE; 92010327Seric bool quotemode = FALSE; 92110327Seric static char buf[MAXLINE]; 9224096Seric 92310327Seric for (q = buf; *p != '\0'; p++) 9244096Seric { 92510327Seric if (backslash) 92610327Seric { 92710327Seric /* everything is roughly literal */ 92810357Seric backslash = FALSE; 92910327Seric switch (*p) 93010327Seric { 93110327Seric case 'r': /* carriage return */ 93210327Seric *q++ = '\r'; 93310327Seric continue; 93410327Seric 93510327Seric case 'n': /* newline */ 93610327Seric *q++ = '\n'; 93710327Seric continue; 93810327Seric 93910327Seric case 'f': /* form feed */ 94010327Seric *q++ = '\f'; 94110327Seric continue; 94210327Seric 94310327Seric case 'b': /* backspace */ 94410327Seric *q++ = '\b'; 94510327Seric continue; 94610327Seric } 94710327Seric *q++ = *p; 94810327Seric } 94910327Seric else 95010327Seric { 95110327Seric if (*p == '\\') 95210327Seric backslash = TRUE; 95310327Seric else if (*p == '"') 95410327Seric quotemode = !quotemode; 95510327Seric else if (quotemode || *p != ',') 95610327Seric *q++ = *p; 95710327Seric else 95810327Seric break; 95910327Seric } 9604096Seric } 9614096Seric 96258333Seric if (delimptr != NULL) 96358333Seric *delimptr = p; 96410327Seric *q++ = '\0'; 96510327Seric return (buf); 96610327Seric } 96710327Seric /* 96810327Seric ** MAKEARGV -- break up a string into words 96910327Seric ** 97010327Seric ** Parameters: 97110327Seric ** p -- the string to break up. 97210327Seric ** 97310327Seric ** Returns: 97410327Seric ** a char **argv (dynamically allocated) 97510327Seric ** 97610327Seric ** Side Effects: 97710327Seric ** munges p. 97810327Seric */ 9794096Seric 98010327Seric char ** 98110327Seric makeargv(p) 98210327Seric register char *p; 98310327Seric { 98410327Seric char *q; 98510327Seric int i; 98610327Seric char **avp; 98710327Seric char *argv[MAXPV + 1]; 98810327Seric 98910327Seric /* take apart the words */ 99010327Seric i = 0; 99110327Seric while (*p != '\0' && i < MAXPV) 9924096Seric { 99310327Seric q = p; 99458050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 99510327Seric p++; 99658050Seric while (isascii(*p) && isspace(*p)) 99710327Seric *p++ = '\0'; 99810327Seric argv[i++] = newstr(q); 9994096Seric } 100010327Seric argv[i++] = NULL; 10014096Seric 100210327Seric /* now make a copy of the argv */ 100310327Seric avp = (char **) xalloc(sizeof *avp * i); 100416893Seric bcopy((char *) argv, (char *) avp, sizeof *avp * i); 100510327Seric 100610327Seric return (avp); 10073308Seric } 10083308Seric /* 10093308Seric ** PRINTRULES -- print rewrite rules (for debugging) 10103308Seric ** 10113308Seric ** Parameters: 10123308Seric ** none. 10133308Seric ** 10143308Seric ** Returns: 10153308Seric ** none. 10163308Seric ** 10173308Seric ** Side Effects: 10183308Seric ** prints rewrite rules. 10193308Seric */ 10203308Seric 10213308Seric printrules() 10223308Seric { 10233308Seric register struct rewrite *rwp; 10244072Seric register int ruleset; 10253308Seric 10264072Seric for (ruleset = 0; ruleset < 10; ruleset++) 10273308Seric { 10284072Seric if (RewriteRules[ruleset] == NULL) 10294072Seric continue; 10308067Seric printf("\n----Rule Set %d:", ruleset); 10313308Seric 10324072Seric for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 10333308Seric { 10348067Seric printf("\nLHS:"); 10358067Seric printav(rwp->r_lhs); 10368067Seric printf("RHS:"); 10378067Seric printav(rwp->r_rhs); 10383308Seric } 10393308Seric } 10403308Seric } 10414319Seric 10424096Seric /* 10438256Seric ** SETOPTION -- set global processing option 10448256Seric ** 10458256Seric ** Parameters: 10468256Seric ** opt -- option name. 10478256Seric ** val -- option value (as a text string). 104821755Seric ** safe -- set if this came from a configuration file. 104921755Seric ** Some options (if set from the command line) will 105021755Seric ** reset the user id to avoid security problems. 10518269Seric ** sticky -- if set, don't let other setoptions override 10528269Seric ** this value. 105358734Seric ** e -- the main envelope. 10548256Seric ** 10558256Seric ** Returns: 10568256Seric ** none. 10578256Seric ** 10588256Seric ** Side Effects: 10598256Seric ** Sets options as implied by the arguments. 10608256Seric */ 10618256Seric 106210687Seric static BITMAP StickyOpt; /* set if option is stuck */ 10638269Seric 106457207Seric 106566334Seric #if NAMED_BIND 106657207Seric 106757207Seric struct resolverflags 106857207Seric { 106957207Seric char *rf_name; /* name of the flag */ 107057207Seric long rf_bits; /* bits to set/clear */ 107157207Seric } ResolverFlags[] = 107257207Seric { 107357207Seric "debug", RES_DEBUG, 107457207Seric "aaonly", RES_AAONLY, 107557207Seric "usevc", RES_USEVC, 107657207Seric "primary", RES_PRIMARY, 107757207Seric "igntc", RES_IGNTC, 107857207Seric "recurse", RES_RECURSE, 107957207Seric "defnames", RES_DEFNAMES, 108057207Seric "stayopen", RES_STAYOPEN, 108157207Seric "dnsrch", RES_DNSRCH, 108265583Seric "true", 0, /* to avoid error on old syntax */ 108357207Seric NULL, 0 108457207Seric }; 108557207Seric 108657207Seric #endif 108757207Seric 108867614Seric struct optioninfo 108967614Seric { 109067614Seric char *o_name; /* long name of option */ 109167787Seric u_char o_code; /* short name of option */ 109267614Seric bool o_safe; /* safe for random people to use */ 109367614Seric } OptionTab[] = 109467614Seric { 109567707Seric "SevenBitInput", '7', TRUE, 109667707Seric "EightBitMode", '8', TRUE, 109767707Seric "AliasFile", 'A', FALSE, 109867707Seric "AliasWait", 'a', FALSE, 109967707Seric "BlankSub", 'B', FALSE, 110067707Seric "MinFreeBlocks", 'b', TRUE, 110167707Seric "CheckpointInterval", 'C', TRUE, 110267707Seric "HoldExpensive", 'c', FALSE, 110367707Seric "AutoRebuildAliases", 'D', FALSE, 110467707Seric "DeliveryMode", 'd', TRUE, 110567707Seric "ErrorHeader", 'E', FALSE, 110667707Seric "ErrorMode", 'e', TRUE, 110767707Seric "TempFileMode", 'F', FALSE, 110867707Seric "SaveFromLine", 'f', FALSE, 110967707Seric "MatchGECOS", 'G', FALSE, 111067707Seric "HelpFile", 'H', FALSE, 111167707Seric "MaxHopCount", 'h', FALSE, 111267707Seric "NameServerOptions", 'I', FALSE, 111367707Seric "IgnoreDots", 'i', TRUE, 111467707Seric "ForwardPath", 'J', FALSE, 111567707Seric "SendMimeErrors", 'j', TRUE, 111667707Seric "ConnectionCacheSize", 'k', FALSE, 111767707Seric "ConnectionCacheTimeout", 'K', FALSE, 111867707Seric "UseErrorsTo", 'l', FALSE, 111967707Seric "LogLevel", 'L', FALSE, 112067707Seric "MeToo", 'm', TRUE, 112167707Seric "CheckAliases", 'n', FALSE, 112267707Seric "OldStyleHeaders", 'o', TRUE, 112367707Seric "DaemonPortOptions", 'O', FALSE, 112467707Seric "PrivacyOptions", 'p', TRUE, 112567707Seric "PostmasterCopy", 'P', FALSE, 112667707Seric "QueueFactor", 'q', FALSE, 112767707Seric "QueueDirectory", 'Q', FALSE, 112867707Seric "DontPruneRoutes", 'R', FALSE, 112967711Seric "Timeouts", 'r', TRUE, 113067707Seric "StatusFile", 'S', FALSE, 113167707Seric "SuperSafe", 's', TRUE, 113267707Seric "QueueTimeout", 'T', FALSE, 113367707Seric "TimeZoneSpec", 't', FALSE, 113467707Seric "UserDatabaseSpec", 'U', FALSE, 113567707Seric "DefaultUser", 'u', FALSE, 113667707Seric "FallbackMXhost", 'V', FALSE, 113767707Seric "Verbose", 'v', TRUE, 113867707Seric "TryNullMXList", 'w', TRUE, 113967707Seric "QueueLA", 'x', FALSE, 114067707Seric "RefuseLA", 'X', FALSE, 114167707Seric "RecipientFactor", 'y', FALSE, 114267707Seric "ForkQueueRuns", 'Y', FALSE, 114367707Seric "ClassFactor", 'z', FALSE, 114467707Seric "TimeFactor", 'Z', FALSE, 114567707Seric #define O_BSP 0x80 114667707Seric "BrokenSmtpPeers", O_BSP, TRUE, 114767707Seric #define O_SQBH 0x81 114867707Seric "SortQueueByHost", O_SQBH, TRUE, 114967707Seric #define O_DNICE 0x82 115067707Seric "DeliveryNiceness", O_DNICE, TRUE, 115167707Seric #define O_MQA 0x83 115267707Seric "MinQueueAge", O_MQA, TRUE, 115367707Seric #define O_MHSA 0x84 115467707Seric "MaxHostStatAge", O_MHSA, TRUE, 115567813Seric #define O_DEFCHARSET 0x85 115667813Seric "DefaultCharSet", O_DEFCHARSET, TRUE, 115767707Seric 115867707Seric NULL, '\0', FALSE, 115967614Seric }; 116067614Seric 116167614Seric 116267614Seric 116358734Seric setoption(opt, val, safe, sticky, e) 116467614Seric u_char opt; 11658256Seric char *val; 116621755Seric bool safe; 11678269Seric bool sticky; 116858734Seric register ENVELOPE *e; 11698256Seric { 117057207Seric register char *p; 117167614Seric register struct optioninfo *o; 11728265Seric extern bool atobool(); 117312633Seric extern time_t convtime(); 117414879Seric extern int QueueLA; 117514879Seric extern int RefuseLA; 117664718Seric extern bool Warn_Q_option; 11778256Seric 117867736Seric errno = 0; 117967614Seric if (opt == ' ') 118067614Seric { 118167614Seric /* full word options */ 118267736Seric struct optioninfo *sel; 118367614Seric 118467614Seric p = strchr(val, '='); 118567614Seric if (p == NULL) 118667614Seric p = &val[strlen(val)]; 118767614Seric while (*--p == ' ') 118867614Seric continue; 118967614Seric while (*++p == ' ') 119067614Seric *p = '\0'; 119167731Seric if (p == val) 119267731Seric { 119367731Seric syserr("readcf: null option name"); 119467731Seric return; 119567731Seric } 119667614Seric if (*p == '=') 119767614Seric *p++ = '\0'; 119867614Seric while (*p == ' ') 119967614Seric p++; 120067736Seric sel = NULL; 120167614Seric for (o = OptionTab; o->o_name != NULL; o++) 120267614Seric { 120367736Seric if (strncasecmp(o->o_name, val, strlen(val)) != 0) 120467736Seric continue; 120567736Seric if (strlen(o->o_name) == strlen(val)) 120667736Seric { 120767736Seric /* completely specified -- this must be it */ 120867736Seric sel = NULL; 120967614Seric break; 121067736Seric } 121167736Seric if (sel != NULL) 121267736Seric break; 121367736Seric sel = o; 121467614Seric } 121567736Seric if (sel != NULL && o->o_name == NULL) 121667736Seric o = sel; 121767736Seric else if (o->o_name == NULL) 121867787Seric { 121967614Seric syserr("readcf: unknown option name %s", val); 122067787Seric return; 122167787Seric } 122267736Seric else if (sel != NULL) 122367736Seric { 122467736Seric syserr("readcf: ambiguous option name %s (matches %s and %s)", 122567736Seric val, sel->o_name, o->o_name); 122667736Seric return; 122767736Seric } 122867736Seric if (strlen(val) != strlen(o->o_name)) 122967736Seric { 123067736Seric bool oldVerbose = Verbose; 123167736Seric 123267736Seric Verbose = TRUE; 123367736Seric message("Option %s used as abbreviation for %s", 123467736Seric val, o->o_name); 123567736Seric Verbose = oldVerbose; 123667736Seric } 123767614Seric opt = o->o_code; 123867614Seric val = p; 123967614Seric } 124067614Seric else 124167614Seric { 124267614Seric for (o = OptionTab; o->o_name != NULL; o++) 124367614Seric { 124467614Seric if (o->o_code == opt) 124567614Seric break; 124667614Seric } 124767614Seric } 124867614Seric 12498256Seric if (tTd(37, 1)) 125067731Seric { 125167731Seric printf(isascii(opt) && isprint(opt) ? 125267731Seric "setoption %s (%c)=%s" : "setoption %s (0x%x)=%s", 125367614Seric o->o_name == NULL ? "<unknown>" : o->o_name, 125467614Seric opt, val); 125567731Seric } 12568256Seric 12578256Seric /* 12588269Seric ** See if this option is preset for us. 12598256Seric */ 12608256Seric 126159731Seric if (!sticky && bitnset(opt, StickyOpt)) 12628269Seric { 12639341Seric if (tTd(37, 1)) 12649341Seric printf(" (ignored)\n"); 12658269Seric return; 12668269Seric } 12678269Seric 126821755Seric /* 126921755Seric ** Check to see if this option can be specified by this user. 127021755Seric */ 127121755Seric 127263787Seric if (!safe && RealUid == 0) 127321755Seric safe = TRUE; 127467614Seric if (!safe && !o->o_safe) 127521755Seric { 127639111Srick if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 127721755Seric { 127836582Sbostic if (tTd(37, 1)) 127936582Sbostic printf(" (unsafe)"); 128063787Seric if (RealUid != geteuid()) 128136582Sbostic { 128251210Seric if (tTd(37, 1)) 128351210Seric printf("(Resetting uid)"); 128463787Seric (void) setgid(RealGid); 128563787Seric (void) setuid(RealUid); 128636582Sbostic } 128721755Seric } 128821755Seric } 128951210Seric if (tTd(37, 1)) 129017985Seric printf("\n"); 12918269Seric 129267614Seric switch (opt & 0xff) 12938256Seric { 129459709Seric case '7': /* force seven-bit input */ 129567546Seric SevenBitInput = atobool(val); 129652106Seric break; 129752106Seric 129867546Seric case '8': /* handling of 8-bit input */ 129967546Seric switch (*val) 130067546Seric { 130167547Seric case 'r': /* reject 8-bit, don't convert MIME */ 130267546Seric MimeMode = 0; 130367546Seric break; 130467546Seric 130567547Seric case 'm': /* convert 8-bit, convert MIME */ 130667546Seric MimeMode = MM_CVTMIME|MM_MIME8BIT; 130767546Seric break; 130867546Seric 130967547Seric case 'j': /* "just send 8" */ 131067546Seric MimeMode = MM_PASS8BIT; 131167546Seric break; 131267546Seric 131367546Seric case 'p': /* pass 8 bit, convert MIME */ 131467546Seric MimeMode = MM_PASS8BIT|MM_CVTMIME; 131567546Seric break; 131667546Seric 131767546Seric case 's': /* strict adherence */ 131867546Seric MimeMode = MM_CVTMIME; 131967546Seric break; 132067546Seric 132167547Seric case 'a': /* encode 8 bit if available */ 132267546Seric MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 132367546Seric break; 132467546Seric 132567547Seric case 'c': /* convert 8 bit to MIME, never 7 bit */ 132667547Seric MimeMode = MM_MIME8BIT; 132767547Seric break; 132867547Seric 132967546Seric default: 133067546Seric syserr("Unknown 8-bit mode %c", *val); 133167546Seric exit(EX_USAGE); 133267546Seric } 133367546Seric break; 133467546Seric 13358256Seric case 'A': /* set default alias file */ 13369381Seric if (val[0] == '\0') 133759672Seric setalias("aliases"); 13389381Seric else 133959672Seric setalias(val); 13408256Seric break; 13418256Seric 134217474Seric case 'a': /* look N minutes for "@:@" in alias file */ 134317474Seric if (val[0] == '\0') 134464796Seric SafeAlias = 5 * 60; /* five minutes */ 134517474Seric else 134664796Seric SafeAlias = convtime(val, 'm'); 134717474Seric break; 134817474Seric 134916843Seric case 'B': /* substitution for blank character */ 135016843Seric SpaceSub = val[0]; 135116843Seric if (SpaceSub == '\0') 135216843Seric SpaceSub = ' '; 135316843Seric break; 135416843Seric 135559283Seric case 'b': /* min blocks free on queue fs/max msg size */ 135659283Seric p = strchr(val, '/'); 135759283Seric if (p != NULL) 135859283Seric { 135959283Seric *p++ = '\0'; 136059283Seric MaxMessageSize = atol(p); 136159283Seric } 136258082Seric MinBlocksFree = atol(val); 136358082Seric break; 136458082Seric 13659284Seric case 'c': /* don't connect to "expensive" mailers */ 13669381Seric NoConnect = atobool(val); 13679284Seric break; 13689284Seric 136951305Seric case 'C': /* checkpoint every N addresses */ 137051305Seric CheckpointInterval = atoi(val); 137124944Seric break; 137224944Seric 13739284Seric case 'd': /* delivery mode */ 13749284Seric switch (*val) 13758269Seric { 13769284Seric case '\0': 137758734Seric e->e_sendmode = SM_DELIVER; 13788269Seric break; 13798269Seric 138010755Seric case SM_QUEUE: /* queue only */ 138110755Seric #ifndef QUEUE 138210755Seric syserr("need QUEUE to set -odqueue"); 138356795Seric #endif /* QUEUE */ 138410755Seric /* fall through..... */ 138510755Seric 13869284Seric case SM_DELIVER: /* do everything */ 13879284Seric case SM_FORK: /* fork after verification */ 138858734Seric e->e_sendmode = *val; 13898269Seric break; 13908269Seric 13918269Seric default: 13929284Seric syserr("Unknown delivery mode %c", *val); 13938269Seric exit(EX_USAGE); 13948269Seric } 13958269Seric break; 13968269Seric 13979146Seric case 'D': /* rebuild alias database as needed */ 13989381Seric AutoRebuild = atobool(val); 13999146Seric break; 14009146Seric 140155372Seric case 'E': /* error message header/header file */ 140255379Seric if (*val != '\0') 140355379Seric ErrMsgFile = newstr(val); 140455372Seric break; 140555372Seric 14068269Seric case 'e': /* set error processing mode */ 14078269Seric switch (*val) 14088269Seric { 14099381Seric case EM_QUIET: /* be silent about it */ 14109381Seric case EM_MAIL: /* mail back */ 14119381Seric case EM_BERKNET: /* do berknet error processing */ 14129381Seric case EM_WRITE: /* write back (or mail) */ 14139381Seric case EM_PRINT: /* print errors normally (default) */ 141458734Seric e->e_errormode = *val; 14158269Seric break; 14168269Seric } 14178269Seric break; 14188269Seric 14199049Seric case 'F': /* file mode */ 142017975Seric FileMode = atooct(val) & 0777; 14219049Seric break; 14229049Seric 14238269Seric case 'f': /* save Unix-style From lines on front */ 14249381Seric SaveFrom = atobool(val); 14258269Seric break; 14268269Seric 142753735Seric case 'G': /* match recipients against GECOS field */ 142853735Seric MatchGecos = atobool(val); 142953735Seric break; 143053735Seric 14318256Seric case 'g': /* default gid */ 143267823Seric g_opt: 143364133Seric if (isascii(*val) && isdigit(*val)) 143464133Seric DefGid = atoi(val); 143564133Seric else 143664133Seric { 143764133Seric register struct group *gr; 143864133Seric 143964133Seric DefGid = -1; 144064133Seric gr = getgrnam(val); 144164133Seric if (gr == NULL) 144267823Seric syserr("readcf: option %c: unknown group %s", 144367823Seric opt, val); 144464133Seric else 144564133Seric DefGid = gr->gr_gid; 144664133Seric } 14478256Seric break; 14488256Seric 14498256Seric case 'H': /* help file */ 14509381Seric if (val[0] == '\0') 14518269Seric HelpFile = "sendmail.hf"; 14529381Seric else 14539381Seric HelpFile = newstr(val); 14548256Seric break; 14558256Seric 145651305Seric case 'h': /* maximum hop count */ 145751305Seric MaxHopCount = atoi(val); 145851305Seric break; 145951305Seric 146035651Seric case 'I': /* use internet domain name server */ 146166334Seric #if NAMED_BIND 146257207Seric UseNameServer = TRUE; 146357207Seric for (p = val; *p != 0; ) 146457207Seric { 146557207Seric bool clearmode; 146657207Seric char *q; 146757207Seric struct resolverflags *rfp; 146857207Seric 146957207Seric while (*p == ' ') 147057207Seric p++; 147157207Seric if (*p == '\0') 147257207Seric break; 147357207Seric clearmode = FALSE; 147457207Seric if (*p == '-') 147557207Seric clearmode = TRUE; 147657207Seric else if (*p != '+') 147757207Seric p--; 147857207Seric p++; 147957207Seric q = p; 148058050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 148157207Seric p++; 148257207Seric if (*p != '\0') 148357207Seric *p++ = '\0'; 148457207Seric for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 148557207Seric { 148657207Seric if (strcasecmp(q, rfp->rf_name) == 0) 148757207Seric break; 148857207Seric } 148964923Seric if (rfp->rf_name == NULL) 149064923Seric syserr("readcf: I option value %s unrecognized", q); 149164923Seric else if (clearmode) 149257207Seric _res.options &= ~rfp->rf_bits; 149357207Seric else 149457207Seric _res.options |= rfp->rf_bits; 149557207Seric } 149657207Seric if (tTd(8, 2)) 149757207Seric printf("_res.options = %x\n", _res.options); 149857207Seric #else 149957207Seric usrerr("name server (I option) specified but BIND not compiled in"); 150057207Seric #endif 150135651Seric break; 150235651Seric 15038269Seric case 'i': /* ignore dot lines in message */ 15049381Seric IgnrDot = atobool(val); 15058269Seric break; 15068269Seric 150759730Seric case 'j': /* send errors in MIME (RFC 1341) format */ 150859730Seric SendMIMEErrors = atobool(val); 150959730Seric break; 151059730Seric 151157136Seric case 'J': /* .forward search path */ 151257136Seric ForwardPath = newstr(val); 151357136Seric break; 151457136Seric 151554967Seric case 'k': /* connection cache size */ 151654967Seric MaxMciCache = atoi(val); 151756215Seric if (MaxMciCache < 0) 151856215Seric MaxMciCache = 0; 151954967Seric break; 152054967Seric 152154967Seric case 'K': /* connection cache timeout */ 152258796Seric MciCacheTimeout = convtime(val, 'm'); 152354967Seric break; 152454967Seric 152561104Seric case 'l': /* use Errors-To: header */ 152661104Seric UseErrorsTo = atobool(val); 152761104Seric break; 152861104Seric 15298256Seric case 'L': /* log level */ 153064140Seric if (safe || LogLevel < atoi(val)) 153164140Seric LogLevel = atoi(val); 15328256Seric break; 15338256Seric 15348269Seric case 'M': /* define macro */ 15359381Seric define(val[0], newstr(&val[1]), CurEnv); 153616878Seric sticky = FALSE; 15378269Seric break; 15388269Seric 15398269Seric case 'm': /* send to me too */ 15409381Seric MeToo = atobool(val); 15418269Seric break; 15428269Seric 154325820Seric case 'n': /* validate RHS in newaliases */ 154425820Seric CheckAliases = atobool(val); 154525820Seric break; 154625820Seric 154761104Seric /* 'N' available -- was "net name" */ 154861104Seric 154958851Seric case 'O': /* daemon options */ 155058851Seric setdaemonoptions(val); 155158851Seric break; 155258851Seric 15538269Seric case 'o': /* assume old style headers */ 15549381Seric if (atobool(val)) 15559341Seric CurEnv->e_flags |= EF_OLDSTYLE; 15569341Seric else 15579341Seric CurEnv->e_flags &= ~EF_OLDSTYLE; 15588269Seric break; 15598269Seric 156058082Seric case 'p': /* select privacy level */ 156158082Seric p = val; 156258082Seric for (;;) 156358082Seric { 156458082Seric register struct prival *pv; 156558082Seric extern struct prival PrivacyValues[]; 156658082Seric 156758082Seric while (isascii(*p) && (isspace(*p) || ispunct(*p))) 156858082Seric p++; 156958082Seric if (*p == '\0') 157058082Seric break; 157158082Seric val = p; 157258082Seric while (isascii(*p) && isalnum(*p)) 157358082Seric p++; 157458082Seric if (*p != '\0') 157558082Seric *p++ = '\0'; 157658082Seric 157758082Seric for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 157858082Seric { 157958082Seric if (strcasecmp(val, pv->pv_name) == 0) 158058082Seric break; 158158082Seric } 158258886Seric if (pv->pv_name == NULL) 158358886Seric syserr("readcf: Op line: %s unrecognized", val); 158458082Seric PrivacyFlags |= pv->pv_flag; 158558082Seric } 158658082Seric break; 158758082Seric 158824944Seric case 'P': /* postmaster copy address for returned mail */ 158924944Seric PostMasterCopy = newstr(val); 159024944Seric break; 159124944Seric 159224944Seric case 'q': /* slope of queue only function */ 159324944Seric QueueFactor = atoi(val); 159424944Seric break; 159524944Seric 15968256Seric case 'Q': /* queue directory */ 15979381Seric if (val[0] == '\0') 15988269Seric QueueDir = "mqueue"; 15999381Seric else 16009381Seric QueueDir = newstr(val); 160158789Seric if (RealUid != 0 && !safe) 160264718Seric Warn_Q_option = TRUE; 16038256Seric break; 16048256Seric 160558148Seric case 'R': /* don't prune routes */ 160658148Seric DontPruneRoutes = atobool(val); 160758148Seric break; 160858148Seric 16098256Seric case 'r': /* read timeout */ 161058112Seric settimeouts(val); 16118256Seric break; 16128256Seric 16138256Seric case 'S': /* status file */ 16149381Seric if (val[0] == '\0') 16158269Seric StatFile = "sendmail.st"; 16169381Seric else 16179381Seric StatFile = newstr(val); 16188256Seric break; 16198256Seric 16208265Seric case 's': /* be super safe, even if expensive */ 16219381Seric SuperSafe = atobool(val); 16228256Seric break; 16238256Seric 16248256Seric case 'T': /* queue timeout */ 162558737Seric p = strchr(val, '/'); 162658737Seric if (p != NULL) 162758737Seric { 162858737Seric *p++ = '\0'; 162967730Seric TimeOuts.to_q_warning[TOC_NORMAL] = convtime(p, 'd'); 163058737Seric } 163167730Seric TimeOuts.to_q_return[TOC_NORMAL] = convtime(val, 'h'); 163254967Seric break; 16338256Seric 16348265Seric case 't': /* time zone name */ 163552106Seric TimeZoneSpec = newstr(val); 16368265Seric break; 16378265Seric 163850556Seric case 'U': /* location of user database */ 163951360Seric UdbSpec = newstr(val); 164050556Seric break; 164150556Seric 16428256Seric case 'u': /* set default uid */ 164367823Seric for (p = val; *p != '\0'; p++) 164467823Seric { 164567823Seric if (*p == '.' || *p == '/' || *p == ':') 164667823Seric { 164767823Seric *p++ = '\0'; 164867823Seric break; 164967823Seric } 165067823Seric } 165164133Seric if (isascii(*val) && isdigit(*val)) 165264133Seric DefUid = atoi(val); 165364133Seric else 165464133Seric { 165564133Seric register struct passwd *pw; 165664133Seric 165764133Seric DefUid = -1; 165864133Seric pw = getpwnam(val); 165964133Seric if (pw == NULL) 166064133Seric syserr("readcf: option u: unknown user %s", val); 166164133Seric else 166267823Seric { 166364133Seric DefUid = pw->pw_uid; 166467823Seric DefGid = pw->pw_gid; 166567823Seric } 166664133Seric } 166740973Sbostic setdefuser(); 16688256Seric 166967823Seric /* handle the group if it is there */ 167067823Seric if (*p == '\0') 167167823Seric break; 167267823Seric val = p; 167367823Seric goto g_opt; 167467823Seric 167558851Seric case 'V': /* fallback MX host */ 167658851Seric FallBackMX = newstr(val); 167758851Seric break; 167858851Seric 16798269Seric case 'v': /* run in verbose mode */ 16809381Seric Verbose = atobool(val); 16818256Seric break; 16828256Seric 168363837Seric case 'w': /* if we are best MX, try host directly */ 168463837Seric TryNullMXList = atobool(val); 168563837Seric break; 168661104Seric 168761104Seric /* 'W' available -- was wizard password */ 168861104Seric 168914879Seric case 'x': /* load avg at which to auto-queue msgs */ 169014879Seric QueueLA = atoi(val); 169114879Seric break; 169214879Seric 169314879Seric case 'X': /* load avg at which to auto-reject connections */ 169414879Seric RefuseLA = atoi(val); 169514879Seric break; 169614879Seric 169724981Seric case 'y': /* work recipient factor */ 169824981Seric WkRecipFact = atoi(val); 169924981Seric break; 170024981Seric 170124981Seric case 'Y': /* fork jobs during queue runs */ 170224952Seric ForkQueueRuns = atobool(val); 170324952Seric break; 170424952Seric 170524981Seric case 'z': /* work message class factor */ 170624981Seric WkClassFact = atoi(val); 170724981Seric break; 170824981Seric 170924981Seric case 'Z': /* work time factor */ 171024981Seric WkTimeFact = atoi(val); 171124981Seric break; 171224981Seric 171367614Seric case O_BSP: /* SMTP Peers can't handle 2-line greeting */ 171467614Seric BrokenSmtpPeers = atobool(val); 171567614Seric break; 171667614Seric 171767614Seric case O_SQBH: /* sort work queue by host first */ 171867614Seric SortQueueByHost = atobool(val); 171967614Seric break; 172067614Seric 172167707Seric case O_DNICE: /* delivery nice value */ 172267707Seric DeliveryNiceness = atoi(val); 172367707Seric break; 172467707Seric 172567707Seric case O_MQA: /* minimum queue age between deliveries */ 172667707Seric MinQueueAge = convtime(val, 'm'); 172767707Seric break; 172867707Seric 172967707Seric case O_MHSA: /* maximum age of cached host status */ 173067707Seric MaxHostStatAge = convtime(val, 'm'); 173167707Seric break; 173267707Seric 173367813Seric case O_DEFCHARSET: /* default character set for mimefying */ 173467814Seric DefaultCharSet = newstr(val); 173567813Seric break; 173667813Seric 17378256Seric default: 17388256Seric break; 17398256Seric } 174016878Seric if (sticky) 174116878Seric setbitn(opt, StickyOpt); 17429188Seric return; 17438256Seric } 174410687Seric /* 174510687Seric ** SETCLASS -- set a word into a class 174610687Seric ** 174710687Seric ** Parameters: 174810687Seric ** class -- the class to put the word in. 174910687Seric ** word -- the word to enter 175010687Seric ** 175110687Seric ** Returns: 175210687Seric ** none. 175310687Seric ** 175410687Seric ** Side Effects: 175510687Seric ** puts the word into the symbol table. 175610687Seric */ 175710687Seric 175810687Seric setclass(class, word) 175910687Seric int class; 176010687Seric char *word; 176110687Seric { 176210687Seric register STAB *s; 176310687Seric 176457943Seric if (tTd(37, 8)) 176564326Seric printf("setclass(%c, %s)\n", class, word); 176610687Seric s = stab(word, ST_CLASS, ST_ENTER); 176710687Seric setbitn(class, s->s_class); 176810687Seric } 176953654Seric /* 177053654Seric ** MAKEMAPENTRY -- create a map entry 177153654Seric ** 177253654Seric ** Parameters: 177353654Seric ** line -- the config file line 177453654Seric ** 177553654Seric ** Returns: 177653654Seric ** TRUE if it successfully entered the map entry. 177753654Seric ** FALSE otherwise (usually syntax error). 177853654Seric ** 177953654Seric ** Side Effects: 178053654Seric ** Enters the map into the dictionary. 178153654Seric */ 178253654Seric 178353654Seric void 178453654Seric makemapentry(line) 178553654Seric char *line; 178653654Seric { 178753654Seric register char *p; 178853654Seric char *mapname; 178953654Seric char *classname; 179064078Seric register STAB *s; 179153654Seric STAB *class; 179253654Seric 179358050Seric for (p = line; isascii(*p) && isspace(*p); p++) 179453654Seric continue; 179558050Seric if (!(isascii(*p) && isalnum(*p))) 179653654Seric { 179753654Seric syserr("readcf: config K line: no map name"); 179853654Seric return; 179953654Seric } 180053654Seric 180153654Seric mapname = p; 180258050Seric while (isascii(*++p) && isalnum(*p)) 180353654Seric continue; 180453654Seric if (*p != '\0') 180553654Seric *p++ = '\0'; 180658050Seric while (isascii(*p) && isspace(*p)) 180753654Seric p++; 180858050Seric if (!(isascii(*p) && isalnum(*p))) 180953654Seric { 181053654Seric syserr("readcf: config K line, map %s: no map class", mapname); 181153654Seric return; 181253654Seric } 181353654Seric classname = p; 181458050Seric while (isascii(*++p) && isalnum(*p)) 181553654Seric continue; 181653654Seric if (*p != '\0') 181753654Seric *p++ = '\0'; 181858050Seric while (isascii(*p) && isspace(*p)) 181953654Seric p++; 182053654Seric 182153654Seric /* look up the class */ 182253654Seric class = stab(classname, ST_MAPCLASS, ST_FIND); 182353654Seric if (class == NULL) 182453654Seric { 182553654Seric syserr("readcf: map %s: class %s not available", mapname, classname); 182653654Seric return; 182753654Seric } 182853654Seric 182953654Seric /* enter the map */ 183064078Seric s = stab(mapname, ST_MAP, ST_ENTER); 183164078Seric s->s_map.map_class = &class->s_mapclass; 183264078Seric s->s_map.map_mname = newstr(mapname); 183353654Seric 183464078Seric if (class->s_mapclass.map_parse(&s->s_map, p)) 183564078Seric s->s_map.map_mflags |= MF_VALID; 183664078Seric 183764078Seric if (tTd(37, 5)) 183864078Seric { 183964078Seric printf("map %s, class %s, flags %x, file %s,\n", 184064078Seric s->s_map.map_mname, s->s_map.map_class->map_cname, 184164078Seric s->s_map.map_mflags, 184264078Seric s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 184364078Seric printf("\tapp %s, domain %s, rebuild %s\n", 184464078Seric s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 184564078Seric s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 184664078Seric s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 184764078Seric } 184853654Seric } 184958112Seric /* 185058112Seric ** SETTIMEOUTS -- parse and set timeout values 185158112Seric ** 185258112Seric ** Parameters: 185358112Seric ** val -- a pointer to the values. If NULL, do initial 185458112Seric ** settings. 185558112Seric ** 185658112Seric ** Returns: 185758112Seric ** none. 185858112Seric ** 185958112Seric ** Side Effects: 186058112Seric ** Initializes the TimeOuts structure 186158112Seric */ 186258112Seric 186364255Seric #define SECONDS 186458112Seric #define MINUTES * 60 186558112Seric #define HOUR * 3600 186658112Seric 186758112Seric settimeouts(val) 186858112Seric register char *val; 186958112Seric { 187058112Seric register char *p; 187158671Seric extern time_t convtime(); 187258112Seric 187358112Seric if (val == NULL) 187458112Seric { 187558112Seric TimeOuts.to_initial = (time_t) 5 MINUTES; 187658112Seric TimeOuts.to_helo = (time_t) 5 MINUTES; 187758112Seric TimeOuts.to_mail = (time_t) 10 MINUTES; 187858112Seric TimeOuts.to_rcpt = (time_t) 1 HOUR; 187958112Seric TimeOuts.to_datainit = (time_t) 5 MINUTES; 188058112Seric TimeOuts.to_datablock = (time_t) 1 HOUR; 188158112Seric TimeOuts.to_datafinal = (time_t) 1 HOUR; 188258112Seric TimeOuts.to_rset = (time_t) 5 MINUTES; 188358112Seric TimeOuts.to_quit = (time_t) 2 MINUTES; 188458112Seric TimeOuts.to_nextcommand = (time_t) 1 HOUR; 188558112Seric TimeOuts.to_miscshort = (time_t) 2 MINUTES; 188664255Seric TimeOuts.to_ident = (time_t) 30 SECONDS; 188767711Seric TimeOuts.to_fileopen = (time_t) 60 SECONDS; 188858112Seric return; 188958112Seric } 189058112Seric 189158112Seric for (;; val = p) 189258112Seric { 189358112Seric while (isascii(*val) && isspace(*val)) 189458112Seric val++; 189558112Seric if (*val == '\0') 189658112Seric break; 189758112Seric for (p = val; *p != '\0' && *p != ','; p++) 189858112Seric continue; 189958112Seric if (*p != '\0') 190058112Seric *p++ = '\0'; 190158112Seric 190258112Seric if (isascii(*val) && isdigit(*val)) 190358112Seric { 190458112Seric /* old syntax -- set everything */ 190558796Seric TimeOuts.to_mail = convtime(val, 'm'); 190658112Seric TimeOuts.to_rcpt = TimeOuts.to_mail; 190758112Seric TimeOuts.to_datainit = TimeOuts.to_mail; 190858112Seric TimeOuts.to_datablock = TimeOuts.to_mail; 190958112Seric TimeOuts.to_datafinal = TimeOuts.to_mail; 191058112Seric TimeOuts.to_nextcommand = TimeOuts.to_mail; 191158112Seric continue; 191258112Seric } 191358112Seric else 191458112Seric { 191567711Seric register char *q = strchr(val, ':'); 191658112Seric time_t to; 191758112Seric 191867711Seric if (q == NULL && (q = strchr(val, '=')) == NULL) 191958112Seric { 192058112Seric /* syntax error */ 192158112Seric continue; 192258112Seric } 192358112Seric *q++ = '\0'; 192458796Seric to = convtime(q, 'm'); 192558112Seric 192658112Seric if (strcasecmp(val, "initial") == 0) 192758112Seric TimeOuts.to_initial = to; 192858112Seric else if (strcasecmp(val, "mail") == 0) 192958112Seric TimeOuts.to_mail = to; 193058112Seric else if (strcasecmp(val, "rcpt") == 0) 193158112Seric TimeOuts.to_rcpt = to; 193258112Seric else if (strcasecmp(val, "datainit") == 0) 193358112Seric TimeOuts.to_datainit = to; 193458112Seric else if (strcasecmp(val, "datablock") == 0) 193558112Seric TimeOuts.to_datablock = to; 193658112Seric else if (strcasecmp(val, "datafinal") == 0) 193758112Seric TimeOuts.to_datafinal = to; 193858112Seric else if (strcasecmp(val, "command") == 0) 193958112Seric TimeOuts.to_nextcommand = to; 194058112Seric else if (strcasecmp(val, "rset") == 0) 194158112Seric TimeOuts.to_rset = to; 194258112Seric else if (strcasecmp(val, "helo") == 0) 194358112Seric TimeOuts.to_helo = to; 194458112Seric else if (strcasecmp(val, "quit") == 0) 194558112Seric TimeOuts.to_quit = to; 194658112Seric else if (strcasecmp(val, "misc") == 0) 194758112Seric TimeOuts.to_miscshort = to; 194864255Seric else if (strcasecmp(val, "ident") == 0) 194964255Seric TimeOuts.to_ident = to; 195067711Seric else if (strcasecmp(val, "fileopen") == 0) 195167711Seric TimeOuts.to_fileopen = to; 195267711Seric else if (strcasecmp(val, "queuewarn") == 0) 195367730Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 195467711Seric else if (strcasecmp(val, "queuereturn") == 0) 195567730Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 195667730Seric else if (strcasecmp(val, "queuewarn.normal") == 0) 195767730Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 195867730Seric else if (strcasecmp(val, "queuereturn.normal") == 0) 195967730Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 196067730Seric else if (strcasecmp(val, "queuewarn.urgent") == 0) 196167730Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 196267730Seric else if (strcasecmp(val, "queuereturn.urgent") == 0) 196367730Seric TimeOuts.to_q_return[TOC_URGENT] = to; 196467730Seric else if (strcasecmp(val, "queuewarn.non-urgent") == 0) 196567730Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 196667730Seric else if (strcasecmp(val, "queuereturn.non-urgent") == 0) 196767730Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 196858112Seric else 196958112Seric syserr("settimeouts: invalid timeout %s", val); 197058112Seric } 197158112Seric } 197258112Seric } 1973