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*67848Seric static char sccsid[] = "@(#)readcf.c 8.44 (Berkeley) 10/24/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]; 8767826Seric 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 29967826Seric { 30056678Seric syserr("R line: null LHS"); 30167826Seric rwp->r_lhs = null_list; 30267826Seric } 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 36367826Seric { 36456678Seric syserr("R line: null RHS"); 36567826Seric rwp->r_rhs = null_list; 36667826Seric } 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(); 5324096Seric } 5334096Seric /* 5348547Seric ** TOOMANY -- signal too many of some option 5358547Seric ** 5368547Seric ** Parameters: 5378547Seric ** id -- the id of the error line 5388547Seric ** maxcnt -- the maximum possible values 5398547Seric ** 5408547Seric ** Returns: 5418547Seric ** none. 5428547Seric ** 5438547Seric ** Side Effects: 5448547Seric ** gives a syserr. 5458547Seric */ 5468547Seric 5478547Seric toomany(id, maxcnt) 5488547Seric char id; 5498547Seric int maxcnt; 5508547Seric { 5519381Seric syserr("too many %c lines, %d max", id, maxcnt); 5528547Seric } 5538547Seric /* 5544432Seric ** FILECLASS -- read members of a class from a file 5554432Seric ** 5564432Seric ** Parameters: 5574432Seric ** class -- class to define. 5584432Seric ** filename -- name of file to read. 5594432Seric ** fmt -- scanf string to use for match. 56064133Seric ** safe -- if set, this is a safe read. 56164133Seric ** optional -- if set, it is not an error for the file to 56264133Seric ** not exist. 5634432Seric ** 5644432Seric ** Returns: 5654432Seric ** none 5664432Seric ** 5674432Seric ** Side Effects: 5684432Seric ** 5694432Seric ** puts all lines in filename that match a scanf into 5704432Seric ** the named class. 5714432Seric */ 5724432Seric 57364133Seric fileclass(class, filename, fmt, safe, optional) 5744432Seric int class; 5754432Seric char *filename; 5764432Seric char *fmt; 57754973Seric bool safe; 57864133Seric bool optional; 5794432Seric { 58025808Seric FILE *f; 58154973Seric struct stat stbuf; 5824432Seric char buf[MAXLINE]; 5834432Seric 58466101Seric if (tTd(37, 2)) 58566101Seric printf("fileclass(%s, fmt=%s)\n", filename, fmt); 58666101Seric 58766031Seric if (filename[0] == '|') 58866031Seric { 58966031Seric syserr("fileclass: pipes (F%c%s) not supported due to security problems", 59066031Seric class, filename); 59166031Seric return; 59266031Seric } 59354973Seric if (stat(filename, &stbuf) < 0) 59454973Seric { 59566101Seric if (tTd(37, 2)) 59666101Seric printf(" cannot stat (%s)\n", errstring(errno)); 59764133Seric if (!optional) 59864133Seric syserr("fileclass: cannot stat %s", filename); 59954973Seric return; 60054973Seric } 60154973Seric if (!S_ISREG(stbuf.st_mode)) 60254973Seric { 60354973Seric syserr("fileclass: %s not a regular file", filename); 60454973Seric return; 60554973Seric } 60654973Seric if (!safe && access(filename, R_OK) < 0) 60754973Seric { 60854973Seric syserr("fileclass: access denied on %s", filename); 60954973Seric return; 61054973Seric } 61154973Seric f = fopen(filename, "r"); 6124432Seric if (f == NULL) 6134432Seric { 61454973Seric syserr("fileclass: cannot open %s", filename); 6154432Seric return; 6164432Seric } 6174432Seric 6184432Seric while (fgets(buf, sizeof buf, f) != NULL) 6194432Seric { 6204432Seric register STAB *s; 62125808Seric register char *p; 62225808Seric # ifdef SCANF 6234432Seric char wordbuf[MAXNAME+1]; 6244432Seric 6254432Seric if (sscanf(buf, fmt, wordbuf) != 1) 6264432Seric continue; 62725808Seric p = wordbuf; 62856795Seric # else /* SCANF */ 62925808Seric p = buf; 63056795Seric # endif /* SCANF */ 63125808Seric 63225808Seric /* 63325808Seric ** Break up the match into words. 63425808Seric */ 63525808Seric 63625808Seric while (*p != '\0') 63725808Seric { 63825808Seric register char *q; 63925808Seric 64025808Seric /* strip leading spaces */ 64158050Seric while (isascii(*p) && isspace(*p)) 64225808Seric p++; 64325808Seric if (*p == '\0') 64425808Seric break; 64525808Seric 64625808Seric /* find the end of the word */ 64725808Seric q = p; 64858050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 64925808Seric p++; 65025808Seric if (*p != '\0') 65125808Seric *p++ = '\0'; 65225808Seric 65325808Seric /* enter the word in the symbol table */ 65466101Seric setclass(class, q); 65525808Seric } 6564432Seric } 6574432Seric 65854973Seric (void) fclose(f); 6594432Seric } 6604432Seric /* 6614096Seric ** MAKEMAILER -- define a new mailer. 6624096Seric ** 6634096Seric ** Parameters: 66410327Seric ** line -- description of mailer. This is in labeled 66510327Seric ** fields. The fields are: 66610327Seric ** P -- the path to the mailer 66710327Seric ** F -- the flags associated with the mailer 66810327Seric ** A -- the argv for this mailer 66910327Seric ** S -- the sender rewriting set 67010327Seric ** R -- the recipient rewriting set 67110327Seric ** E -- the eol string 67210327Seric ** The first word is the canonical name of the mailer. 6734096Seric ** 6744096Seric ** Returns: 6754096Seric ** none. 6764096Seric ** 6774096Seric ** Side Effects: 6784096Seric ** enters the mailer into the mailer table. 6794096Seric */ 6803308Seric 68121066Seric makemailer(line) 6824096Seric char *line; 6834096Seric { 6844096Seric register char *p; 6858067Seric register struct mailer *m; 6868067Seric register STAB *s; 6878067Seric int i; 68810327Seric char fcode; 68958020Seric auto char *endp; 6904096Seric extern int NextMailer; 69110327Seric extern char **makeargv(); 69210327Seric extern char *munchstring(); 69310701Seric extern long atol(); 6944096Seric 69510327Seric /* allocate a mailer and set up defaults */ 69610327Seric m = (struct mailer *) xalloc(sizeof *m); 69710327Seric bzero((char *) m, sizeof *m); 69810327Seric m->m_eol = "\n"; 69967604Seric m->m_uid = m->m_gid = 0; 70010327Seric 70110327Seric /* collect the mailer name */ 70258050Seric for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++) 70310327Seric continue; 70410327Seric if (*p != '\0') 70510327Seric *p++ = '\0'; 70610327Seric m->m_name = newstr(line); 70710327Seric 70810327Seric /* now scan through and assign info from the fields */ 70910327Seric while (*p != '\0') 71010327Seric { 71158333Seric auto char *delimptr; 71258333Seric 71358050Seric while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p)))) 71410327Seric p++; 71510327Seric 71610327Seric /* p now points to field code */ 71710327Seric fcode = *p; 71810327Seric while (*p != '\0' && *p != '=' && *p != ',') 71910327Seric p++; 72010327Seric if (*p++ != '=') 72110327Seric { 72252637Seric syserr("mailer %s: `=' expected", m->m_name); 72310327Seric return; 72410327Seric } 72558050Seric while (isascii(*p) && isspace(*p)) 72610327Seric p++; 72710327Seric 72810327Seric /* p now points to the field body */ 72958333Seric p = munchstring(p, &delimptr); 73010327Seric 73110327Seric /* install the field into the mailer struct */ 73210327Seric switch (fcode) 73310327Seric { 73410327Seric case 'P': /* pathname */ 73510327Seric m->m_mailer = newstr(p); 73610327Seric break; 73710327Seric 73810327Seric case 'F': /* flags */ 73910687Seric for (; *p != '\0'; p++) 74058050Seric if (!(isascii(*p) && isspace(*p))) 74152637Seric setbitn(*p, m->m_flags); 74210327Seric break; 74310327Seric 74410327Seric case 'S': /* sender rewriting ruleset */ 74510327Seric case 'R': /* recipient rewriting ruleset */ 74658020Seric i = strtol(p, &endp, 10); 74710327Seric if (i < 0 || i >= MAXRWSETS) 74810327Seric { 74910327Seric syserr("invalid rewrite set, %d max", MAXRWSETS); 75010327Seric return; 75110327Seric } 75210327Seric if (fcode == 'S') 75358020Seric m->m_sh_rwset = m->m_se_rwset = i; 75410327Seric else 75558020Seric m->m_rh_rwset = m->m_re_rwset = i; 75658020Seric 75758020Seric p = endp; 75859985Seric if (*p++ == '/') 75958020Seric { 76058020Seric i = strtol(p, NULL, 10); 76158020Seric if (i < 0 || i >= MAXRWSETS) 76258020Seric { 76358020Seric syserr("invalid rewrite set, %d max", 76458020Seric MAXRWSETS); 76558020Seric return; 76658020Seric } 76758020Seric if (fcode == 'S') 76858020Seric m->m_sh_rwset = i; 76958020Seric else 77058020Seric m->m_rh_rwset = i; 77158020Seric } 77210327Seric break; 77310327Seric 77410327Seric case 'E': /* end of line string */ 77510327Seric m->m_eol = newstr(p); 77610327Seric break; 77710327Seric 77810327Seric case 'A': /* argument vector */ 77910327Seric m->m_argv = makeargv(p); 78010327Seric break; 78110701Seric 78210701Seric case 'M': /* maximum message size */ 78310701Seric m->m_maxsize = atol(p); 78410701Seric break; 78552106Seric 78652106Seric case 'L': /* maximum line length */ 78752106Seric m->m_linelimit = atoi(p); 78852106Seric break; 78958935Seric 79058935Seric case 'D': /* working directory */ 79158935Seric m->m_execdir = newstr(p); 79258935Seric break; 79367604Seric 79467604Seric case 'U': /* user id */ 79567604Seric if (isascii(*p) && !isdigit(*p)) 79667604Seric { 79767604Seric char *q = p; 79867604Seric struct passwd *pw; 79967604Seric 80067604Seric while (isascii(*p) && isalnum(*p)) 80167604Seric p++; 80267604Seric while (isascii(*p) && isspace(*p)) 80367604Seric *p++ = '\0'; 80467604Seric if (*p != '\0') 80567604Seric *p++ = '\0'; 80667604Seric pw = getpwnam(q); 80767604Seric if (pw == NULL) 80867604Seric syserr("readcf: mailer U= flag: unknown user %s", q); 80967604Seric else 81067604Seric { 81167604Seric m->m_uid = pw->pw_uid; 81267604Seric m->m_gid = pw->pw_gid; 81367604Seric } 81467604Seric } 81567604Seric else 81667604Seric { 81767604Seric auto char *q; 81867604Seric 81967604Seric m->m_uid = strtol(p, &q, 0); 82067604Seric p = q; 82167604Seric } 82267604Seric while (isascii(*p) && isspace(*p)) 82367604Seric p++; 82467604Seric if (*p == '\0') 82567604Seric break; 82667604Seric if (isascii(*p) && !isdigit(*p)) 82767604Seric { 82867604Seric char *q = p; 82967604Seric struct group *gr; 83067604Seric 83167604Seric while (isascii(*p) && isalnum(*p)) 83267604Seric p++; 83367604Seric *p++ = '\0'; 83467604Seric gr = getgrnam(q); 83567604Seric if (gr == NULL) 83667604Seric syserr("readcf: mailer U= flag: unknown group %s", q); 83767604Seric else 83867604Seric m->m_gid = gr->gr_gid; 83967604Seric } 84067604Seric else 84167604Seric { 84267604Seric m->m_gid = strtol(p, NULL, 0); 84367604Seric } 84467604Seric break; 84510327Seric } 84610327Seric 84758333Seric p = delimptr; 84810327Seric } 84910327Seric 85052106Seric /* do some heuristic cleanup for back compatibility */ 85152106Seric if (bitnset(M_LIMITS, m->m_flags)) 85252106Seric { 85352106Seric if (m->m_linelimit == 0) 85452106Seric m->m_linelimit = SMTPLINELIM; 85555418Seric if (ConfigLevel < 2) 85652106Seric setbitn(M_7BITS, m->m_flags); 85752106Seric } 85852106Seric 85958321Seric /* do some rationality checking */ 86058321Seric if (m->m_argv == NULL) 86158321Seric { 86258321Seric syserr("M%s: A= argument required", m->m_name); 86358321Seric return; 86458321Seric } 86558321Seric if (m->m_mailer == NULL) 86658321Seric { 86758321Seric syserr("M%s: P= argument required", m->m_name); 86858321Seric return; 86958321Seric } 87058321Seric 8714096Seric if (NextMailer >= MAXMAILERS) 8724096Seric { 8739381Seric syserr("too many mailers defined (%d max)", MAXMAILERS); 8744096Seric return; 8754096Seric } 87657402Seric 87710327Seric s = stab(m->m_name, ST_MAILER, ST_ENTER); 87857402Seric if (s->s_mailer != NULL) 87957402Seric { 88057402Seric i = s->s_mailer->m_mno; 88157402Seric free(s->s_mailer); 88257402Seric } 88357402Seric else 88457402Seric { 88557402Seric i = NextMailer++; 88657402Seric } 88757402Seric Mailer[i] = s->s_mailer = m; 88857454Seric m->m_mno = i; 88910327Seric } 89010327Seric /* 89110327Seric ** MUNCHSTRING -- translate a string into internal form. 89210327Seric ** 89310327Seric ** Parameters: 89410327Seric ** p -- the string to munch. 89558333Seric ** delimptr -- if non-NULL, set to the pointer of the 89658333Seric ** field delimiter character. 89710327Seric ** 89810327Seric ** Returns: 89910327Seric ** the munched string. 90010327Seric */ 9014096Seric 90210327Seric char * 90358333Seric munchstring(p, delimptr) 90410327Seric register char *p; 90558333Seric char **delimptr; 90610327Seric { 90710327Seric register char *q; 90810327Seric bool backslash = FALSE; 90910327Seric bool quotemode = FALSE; 91010327Seric static char buf[MAXLINE]; 9114096Seric 91210327Seric for (q = buf; *p != '\0'; p++) 9134096Seric { 91410327Seric if (backslash) 91510327Seric { 91610327Seric /* everything is roughly literal */ 91710357Seric backslash = FALSE; 91810327Seric switch (*p) 91910327Seric { 92010327Seric case 'r': /* carriage return */ 92110327Seric *q++ = '\r'; 92210327Seric continue; 92310327Seric 92410327Seric case 'n': /* newline */ 92510327Seric *q++ = '\n'; 92610327Seric continue; 92710327Seric 92810327Seric case 'f': /* form feed */ 92910327Seric *q++ = '\f'; 93010327Seric continue; 93110327Seric 93210327Seric case 'b': /* backspace */ 93310327Seric *q++ = '\b'; 93410327Seric continue; 93510327Seric } 93610327Seric *q++ = *p; 93710327Seric } 93810327Seric else 93910327Seric { 94010327Seric if (*p == '\\') 94110327Seric backslash = TRUE; 94210327Seric else if (*p == '"') 94310327Seric quotemode = !quotemode; 94410327Seric else if (quotemode || *p != ',') 94510327Seric *q++ = *p; 94610327Seric else 94710327Seric break; 94810327Seric } 9494096Seric } 9504096Seric 95158333Seric if (delimptr != NULL) 95258333Seric *delimptr = p; 95310327Seric *q++ = '\0'; 95410327Seric return (buf); 95510327Seric } 95610327Seric /* 95710327Seric ** MAKEARGV -- break up a string into words 95810327Seric ** 95910327Seric ** Parameters: 96010327Seric ** p -- the string to break up. 96110327Seric ** 96210327Seric ** Returns: 96310327Seric ** a char **argv (dynamically allocated) 96410327Seric ** 96510327Seric ** Side Effects: 96610327Seric ** munges p. 96710327Seric */ 9684096Seric 96910327Seric char ** 97010327Seric makeargv(p) 97110327Seric register char *p; 97210327Seric { 97310327Seric char *q; 97410327Seric int i; 97510327Seric char **avp; 97610327Seric char *argv[MAXPV + 1]; 97710327Seric 97810327Seric /* take apart the words */ 97910327Seric i = 0; 98010327Seric while (*p != '\0' && i < MAXPV) 9814096Seric { 98210327Seric q = p; 98358050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 98410327Seric p++; 98558050Seric while (isascii(*p) && isspace(*p)) 98610327Seric *p++ = '\0'; 98710327Seric argv[i++] = newstr(q); 9884096Seric } 98910327Seric argv[i++] = NULL; 9904096Seric 99110327Seric /* now make a copy of the argv */ 99210327Seric avp = (char **) xalloc(sizeof *avp * i); 99316893Seric bcopy((char *) argv, (char *) avp, sizeof *avp * i); 99410327Seric 99510327Seric return (avp); 9963308Seric } 9973308Seric /* 9983308Seric ** PRINTRULES -- print rewrite rules (for debugging) 9993308Seric ** 10003308Seric ** Parameters: 10013308Seric ** none. 10023308Seric ** 10033308Seric ** Returns: 10043308Seric ** none. 10053308Seric ** 10063308Seric ** Side Effects: 10073308Seric ** prints rewrite rules. 10083308Seric */ 10093308Seric 10103308Seric printrules() 10113308Seric { 10123308Seric register struct rewrite *rwp; 10134072Seric register int ruleset; 10143308Seric 10154072Seric for (ruleset = 0; ruleset < 10; ruleset++) 10163308Seric { 10174072Seric if (RewriteRules[ruleset] == NULL) 10184072Seric continue; 10198067Seric printf("\n----Rule Set %d:", ruleset); 10203308Seric 10214072Seric for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 10223308Seric { 10238067Seric printf("\nLHS:"); 10248067Seric printav(rwp->r_lhs); 10258067Seric printf("RHS:"); 10268067Seric printav(rwp->r_rhs); 10273308Seric } 10283308Seric } 10293308Seric } 10304319Seric 10314096Seric /* 10328256Seric ** SETOPTION -- set global processing option 10338256Seric ** 10348256Seric ** Parameters: 10358256Seric ** opt -- option name. 10368256Seric ** val -- option value (as a text string). 103721755Seric ** safe -- set if this came from a configuration file. 103821755Seric ** Some options (if set from the command line) will 103921755Seric ** reset the user id to avoid security problems. 10408269Seric ** sticky -- if set, don't let other setoptions override 10418269Seric ** this value. 104258734Seric ** e -- the main envelope. 10438256Seric ** 10448256Seric ** Returns: 10458256Seric ** none. 10468256Seric ** 10478256Seric ** Side Effects: 10488256Seric ** Sets options as implied by the arguments. 10498256Seric */ 10508256Seric 105110687Seric static BITMAP StickyOpt; /* set if option is stuck */ 10528269Seric 105357207Seric 105466334Seric #if NAMED_BIND 105557207Seric 105657207Seric struct resolverflags 105757207Seric { 105857207Seric char *rf_name; /* name of the flag */ 105957207Seric long rf_bits; /* bits to set/clear */ 106057207Seric } ResolverFlags[] = 106157207Seric { 106257207Seric "debug", RES_DEBUG, 106357207Seric "aaonly", RES_AAONLY, 106457207Seric "usevc", RES_USEVC, 106557207Seric "primary", RES_PRIMARY, 106657207Seric "igntc", RES_IGNTC, 106757207Seric "recurse", RES_RECURSE, 106857207Seric "defnames", RES_DEFNAMES, 106957207Seric "stayopen", RES_STAYOPEN, 107057207Seric "dnsrch", RES_DNSRCH, 107165583Seric "true", 0, /* to avoid error on old syntax */ 107257207Seric NULL, 0 107357207Seric }; 107457207Seric 107557207Seric #endif 107657207Seric 107767614Seric struct optioninfo 107867614Seric { 107967614Seric char *o_name; /* long name of option */ 108067787Seric u_char o_code; /* short name of option */ 108167614Seric bool o_safe; /* safe for random people to use */ 108267614Seric } OptionTab[] = 108367614Seric { 108467707Seric "SevenBitInput", '7', TRUE, 108567707Seric "EightBitMode", '8', TRUE, 108667707Seric "AliasFile", 'A', FALSE, 108767707Seric "AliasWait", 'a', FALSE, 108867707Seric "BlankSub", 'B', FALSE, 108967707Seric "MinFreeBlocks", 'b', TRUE, 109067707Seric "CheckpointInterval", 'C', TRUE, 109167707Seric "HoldExpensive", 'c', FALSE, 109267707Seric "AutoRebuildAliases", 'D', FALSE, 109367707Seric "DeliveryMode", 'd', TRUE, 109467707Seric "ErrorHeader", 'E', FALSE, 109567707Seric "ErrorMode", 'e', TRUE, 109667707Seric "TempFileMode", 'F', FALSE, 109767707Seric "SaveFromLine", 'f', FALSE, 109867707Seric "MatchGECOS", 'G', FALSE, 109967707Seric "HelpFile", 'H', FALSE, 110067707Seric "MaxHopCount", 'h', FALSE, 110167707Seric "NameServerOptions", 'I', FALSE, 110267707Seric "IgnoreDots", 'i', TRUE, 110367707Seric "ForwardPath", 'J', FALSE, 110467707Seric "SendMimeErrors", 'j', TRUE, 110567707Seric "ConnectionCacheSize", 'k', FALSE, 110667707Seric "ConnectionCacheTimeout", 'K', FALSE, 110767707Seric "UseErrorsTo", 'l', FALSE, 110867707Seric "LogLevel", 'L', FALSE, 110967707Seric "MeToo", 'm', TRUE, 111067707Seric "CheckAliases", 'n', FALSE, 111167707Seric "OldStyleHeaders", 'o', TRUE, 111267707Seric "DaemonPortOptions", 'O', FALSE, 111367707Seric "PrivacyOptions", 'p', TRUE, 111467707Seric "PostmasterCopy", 'P', FALSE, 111567707Seric "QueueFactor", 'q', FALSE, 111667707Seric "QueueDirectory", 'Q', FALSE, 111767707Seric "DontPruneRoutes", 'R', FALSE, 111867711Seric "Timeouts", 'r', TRUE, 111967707Seric "StatusFile", 'S', FALSE, 112067707Seric "SuperSafe", 's', TRUE, 112167707Seric "QueueTimeout", 'T', FALSE, 112267707Seric "TimeZoneSpec", 't', FALSE, 112367707Seric "UserDatabaseSpec", 'U', FALSE, 112467707Seric "DefaultUser", 'u', FALSE, 112567707Seric "FallbackMXhost", 'V', FALSE, 112667707Seric "Verbose", 'v', TRUE, 112767707Seric "TryNullMXList", 'w', TRUE, 112867707Seric "QueueLA", 'x', FALSE, 112967707Seric "RefuseLA", 'X', FALSE, 113067707Seric "RecipientFactor", 'y', FALSE, 113167707Seric "ForkQueueRuns", 'Y', FALSE, 113267707Seric "ClassFactor", 'z', FALSE, 113367707Seric "TimeFactor", 'Z', FALSE, 113467707Seric #define O_BSP 0x80 113567707Seric "BrokenSmtpPeers", O_BSP, TRUE, 113667707Seric #define O_SQBH 0x81 113767707Seric "SortQueueByHost", O_SQBH, TRUE, 113867707Seric #define O_DNICE 0x82 113967707Seric "DeliveryNiceness", O_DNICE, TRUE, 114067707Seric #define O_MQA 0x83 114167707Seric "MinQueueAge", O_MQA, TRUE, 114267707Seric #define O_MHSA 0x84 114367707Seric "MaxHostStatAge", O_MHSA, TRUE, 114467813Seric #define O_DEFCHARSET 0x85 114567813Seric "DefaultCharSet", O_DEFCHARSET, TRUE, 1146*67848Seric #define O_SSFILE 0x86 1147*67848Seric "ServiceSwitchFile", O_SSFILE, FALSE, 114867707Seric 114967707Seric NULL, '\0', FALSE, 115067614Seric }; 115167614Seric 115267614Seric 115367614Seric 115458734Seric setoption(opt, val, safe, sticky, e) 115567614Seric u_char opt; 11568256Seric char *val; 115721755Seric bool safe; 11588269Seric bool sticky; 115958734Seric register ENVELOPE *e; 11608256Seric { 116157207Seric register char *p; 116267614Seric register struct optioninfo *o; 11638265Seric extern bool atobool(); 116412633Seric extern time_t convtime(); 116514879Seric extern int QueueLA; 116614879Seric extern int RefuseLA; 116764718Seric extern bool Warn_Q_option; 11688256Seric 116967736Seric errno = 0; 117067614Seric if (opt == ' ') 117167614Seric { 117267614Seric /* full word options */ 117367736Seric struct optioninfo *sel; 117467614Seric 117567614Seric p = strchr(val, '='); 117667614Seric if (p == NULL) 117767614Seric p = &val[strlen(val)]; 117867614Seric while (*--p == ' ') 117967614Seric continue; 118067614Seric while (*++p == ' ') 118167614Seric *p = '\0'; 118267731Seric if (p == val) 118367731Seric { 118467731Seric syserr("readcf: null option name"); 118567731Seric return; 118667731Seric } 118767614Seric if (*p == '=') 118867614Seric *p++ = '\0'; 118967614Seric while (*p == ' ') 119067614Seric p++; 119167736Seric sel = NULL; 119267614Seric for (o = OptionTab; o->o_name != NULL; o++) 119367614Seric { 119467736Seric if (strncasecmp(o->o_name, val, strlen(val)) != 0) 119567736Seric continue; 119667736Seric if (strlen(o->o_name) == strlen(val)) 119767736Seric { 119867736Seric /* completely specified -- this must be it */ 119967736Seric sel = NULL; 120067614Seric break; 120167736Seric } 120267736Seric if (sel != NULL) 120367736Seric break; 120467736Seric sel = o; 120567614Seric } 120667736Seric if (sel != NULL && o->o_name == NULL) 120767736Seric o = sel; 120867736Seric else if (o->o_name == NULL) 120967787Seric { 121067614Seric syserr("readcf: unknown option name %s", val); 121167787Seric return; 121267787Seric } 121367736Seric else if (sel != NULL) 121467736Seric { 121567736Seric syserr("readcf: ambiguous option name %s (matches %s and %s)", 121667736Seric val, sel->o_name, o->o_name); 121767736Seric return; 121867736Seric } 121967736Seric if (strlen(val) != strlen(o->o_name)) 122067736Seric { 122167736Seric bool oldVerbose = Verbose; 122267736Seric 122367736Seric Verbose = TRUE; 122467736Seric message("Option %s used as abbreviation for %s", 122567736Seric val, o->o_name); 122667736Seric Verbose = oldVerbose; 122767736Seric } 122867614Seric opt = o->o_code; 122967614Seric val = p; 123067614Seric } 123167614Seric else 123267614Seric { 123367614Seric for (o = OptionTab; o->o_name != NULL; o++) 123467614Seric { 123567614Seric if (o->o_code == opt) 123667614Seric break; 123767614Seric } 123867614Seric } 123967614Seric 12408256Seric if (tTd(37, 1)) 124167731Seric { 124267731Seric printf(isascii(opt) && isprint(opt) ? 124367731Seric "setoption %s (%c)=%s" : "setoption %s (0x%x)=%s", 124467614Seric o->o_name == NULL ? "<unknown>" : o->o_name, 124567614Seric opt, val); 124667731Seric } 12478256Seric 12488256Seric /* 12498269Seric ** See if this option is preset for us. 12508256Seric */ 12518256Seric 125259731Seric if (!sticky && bitnset(opt, StickyOpt)) 12538269Seric { 12549341Seric if (tTd(37, 1)) 12559341Seric printf(" (ignored)\n"); 12568269Seric return; 12578269Seric } 12588269Seric 125921755Seric /* 126021755Seric ** Check to see if this option can be specified by this user. 126121755Seric */ 126221755Seric 126363787Seric if (!safe && RealUid == 0) 126421755Seric safe = TRUE; 126567614Seric if (!safe && !o->o_safe) 126621755Seric { 126739111Srick if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 126821755Seric { 126936582Sbostic if (tTd(37, 1)) 127036582Sbostic printf(" (unsafe)"); 127163787Seric if (RealUid != geteuid()) 127236582Sbostic { 127351210Seric if (tTd(37, 1)) 127451210Seric printf("(Resetting uid)"); 127563787Seric (void) setgid(RealGid); 127663787Seric (void) setuid(RealUid); 127736582Sbostic } 127821755Seric } 127921755Seric } 128051210Seric if (tTd(37, 1)) 128117985Seric printf("\n"); 12828269Seric 128367614Seric switch (opt & 0xff) 12848256Seric { 128559709Seric case '7': /* force seven-bit input */ 128667546Seric SevenBitInput = atobool(val); 128752106Seric break; 128852106Seric 128967546Seric case '8': /* handling of 8-bit input */ 129067546Seric switch (*val) 129167546Seric { 129267547Seric case 'r': /* reject 8-bit, don't convert MIME */ 129367546Seric MimeMode = 0; 129467546Seric break; 129567546Seric 129667547Seric case 'm': /* convert 8-bit, convert MIME */ 129767546Seric MimeMode = MM_CVTMIME|MM_MIME8BIT; 129867546Seric break; 129967546Seric 130067547Seric case 'j': /* "just send 8" */ 130167546Seric MimeMode = MM_PASS8BIT; 130267546Seric break; 130367546Seric 130467546Seric case 'p': /* pass 8 bit, convert MIME */ 130567546Seric MimeMode = MM_PASS8BIT|MM_CVTMIME; 130667546Seric break; 130767546Seric 130867546Seric case 's': /* strict adherence */ 130967546Seric MimeMode = MM_CVTMIME; 131067546Seric break; 131167546Seric 131267547Seric case 'a': /* encode 8 bit if available */ 131367546Seric MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 131467546Seric break; 131567546Seric 131667547Seric case 'c': /* convert 8 bit to MIME, never 7 bit */ 131767547Seric MimeMode = MM_MIME8BIT; 131867547Seric break; 131967547Seric 132067546Seric default: 132167546Seric syserr("Unknown 8-bit mode %c", *val); 132267546Seric exit(EX_USAGE); 132367546Seric } 132467546Seric break; 132567546Seric 13268256Seric case 'A': /* set default alias file */ 13279381Seric if (val[0] == '\0') 132859672Seric setalias("aliases"); 13299381Seric else 133059672Seric setalias(val); 13318256Seric break; 13328256Seric 133317474Seric case 'a': /* look N minutes for "@:@" in alias file */ 133417474Seric if (val[0] == '\0') 133564796Seric SafeAlias = 5 * 60; /* five minutes */ 133617474Seric else 133764796Seric SafeAlias = convtime(val, 'm'); 133817474Seric break; 133917474Seric 134016843Seric case 'B': /* substitution for blank character */ 134116843Seric SpaceSub = val[0]; 134216843Seric if (SpaceSub == '\0') 134316843Seric SpaceSub = ' '; 134416843Seric break; 134516843Seric 134659283Seric case 'b': /* min blocks free on queue fs/max msg size */ 134759283Seric p = strchr(val, '/'); 134859283Seric if (p != NULL) 134959283Seric { 135059283Seric *p++ = '\0'; 135159283Seric MaxMessageSize = atol(p); 135259283Seric } 135358082Seric MinBlocksFree = atol(val); 135458082Seric break; 135558082Seric 13569284Seric case 'c': /* don't connect to "expensive" mailers */ 13579381Seric NoConnect = atobool(val); 13589284Seric break; 13599284Seric 136051305Seric case 'C': /* checkpoint every N addresses */ 136151305Seric CheckpointInterval = atoi(val); 136224944Seric break; 136324944Seric 13649284Seric case 'd': /* delivery mode */ 13659284Seric switch (*val) 13668269Seric { 13679284Seric case '\0': 136858734Seric e->e_sendmode = SM_DELIVER; 13698269Seric break; 13708269Seric 137110755Seric case SM_QUEUE: /* queue only */ 137210755Seric #ifndef QUEUE 137310755Seric syserr("need QUEUE to set -odqueue"); 137456795Seric #endif /* QUEUE */ 137510755Seric /* fall through..... */ 137610755Seric 13779284Seric case SM_DELIVER: /* do everything */ 13789284Seric case SM_FORK: /* fork after verification */ 137958734Seric e->e_sendmode = *val; 13808269Seric break; 13818269Seric 13828269Seric default: 13839284Seric syserr("Unknown delivery mode %c", *val); 13848269Seric exit(EX_USAGE); 13858269Seric } 13868269Seric break; 13878269Seric 13889146Seric case 'D': /* rebuild alias database as needed */ 13899381Seric AutoRebuild = atobool(val); 13909146Seric break; 13919146Seric 139255372Seric case 'E': /* error message header/header file */ 139355379Seric if (*val != '\0') 139455379Seric ErrMsgFile = newstr(val); 139555372Seric break; 139655372Seric 13978269Seric case 'e': /* set error processing mode */ 13988269Seric switch (*val) 13998269Seric { 14009381Seric case EM_QUIET: /* be silent about it */ 14019381Seric case EM_MAIL: /* mail back */ 14029381Seric case EM_BERKNET: /* do berknet error processing */ 14039381Seric case EM_WRITE: /* write back (or mail) */ 14049381Seric case EM_PRINT: /* print errors normally (default) */ 140558734Seric e->e_errormode = *val; 14068269Seric break; 14078269Seric } 14088269Seric break; 14098269Seric 14109049Seric case 'F': /* file mode */ 141117975Seric FileMode = atooct(val) & 0777; 14129049Seric break; 14139049Seric 14148269Seric case 'f': /* save Unix-style From lines on front */ 14159381Seric SaveFrom = atobool(val); 14168269Seric break; 14178269Seric 141853735Seric case 'G': /* match recipients against GECOS field */ 141953735Seric MatchGecos = atobool(val); 142053735Seric break; 142153735Seric 14228256Seric case 'g': /* default gid */ 142367823Seric g_opt: 142464133Seric if (isascii(*val) && isdigit(*val)) 142564133Seric DefGid = atoi(val); 142664133Seric else 142764133Seric { 142864133Seric register struct group *gr; 142964133Seric 143064133Seric DefGid = -1; 143164133Seric gr = getgrnam(val); 143264133Seric if (gr == NULL) 143367823Seric syserr("readcf: option %c: unknown group %s", 143467823Seric opt, val); 143564133Seric else 143664133Seric DefGid = gr->gr_gid; 143764133Seric } 14388256Seric break; 14398256Seric 14408256Seric case 'H': /* help file */ 14419381Seric if (val[0] == '\0') 14428269Seric HelpFile = "sendmail.hf"; 14439381Seric else 14449381Seric HelpFile = newstr(val); 14458256Seric break; 14468256Seric 144751305Seric case 'h': /* maximum hop count */ 144851305Seric MaxHopCount = atoi(val); 144951305Seric break; 145051305Seric 145135651Seric case 'I': /* use internet domain name server */ 145266334Seric #if NAMED_BIND 145357207Seric UseNameServer = TRUE; 145457207Seric for (p = val; *p != 0; ) 145557207Seric { 145657207Seric bool clearmode; 145757207Seric char *q; 145857207Seric struct resolverflags *rfp; 145957207Seric 146057207Seric while (*p == ' ') 146157207Seric p++; 146257207Seric if (*p == '\0') 146357207Seric break; 146457207Seric clearmode = FALSE; 146557207Seric if (*p == '-') 146657207Seric clearmode = TRUE; 146757207Seric else if (*p != '+') 146857207Seric p--; 146957207Seric p++; 147057207Seric q = p; 147158050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 147257207Seric p++; 147357207Seric if (*p != '\0') 147457207Seric *p++ = '\0'; 147557207Seric for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 147657207Seric { 147757207Seric if (strcasecmp(q, rfp->rf_name) == 0) 147857207Seric break; 147957207Seric } 148064923Seric if (rfp->rf_name == NULL) 148164923Seric syserr("readcf: I option value %s unrecognized", q); 148264923Seric else if (clearmode) 148357207Seric _res.options &= ~rfp->rf_bits; 148457207Seric else 148557207Seric _res.options |= rfp->rf_bits; 148657207Seric } 148757207Seric if (tTd(8, 2)) 148857207Seric printf("_res.options = %x\n", _res.options); 148957207Seric #else 149057207Seric usrerr("name server (I option) specified but BIND not compiled in"); 149157207Seric #endif 149235651Seric break; 149335651Seric 14948269Seric case 'i': /* ignore dot lines in message */ 14959381Seric IgnrDot = atobool(val); 14968269Seric break; 14978269Seric 149859730Seric case 'j': /* send errors in MIME (RFC 1341) format */ 149959730Seric SendMIMEErrors = atobool(val); 150059730Seric break; 150159730Seric 150257136Seric case 'J': /* .forward search path */ 150357136Seric ForwardPath = newstr(val); 150457136Seric break; 150557136Seric 150654967Seric case 'k': /* connection cache size */ 150754967Seric MaxMciCache = atoi(val); 150856215Seric if (MaxMciCache < 0) 150956215Seric MaxMciCache = 0; 151054967Seric break; 151154967Seric 151254967Seric case 'K': /* connection cache timeout */ 151358796Seric MciCacheTimeout = convtime(val, 'm'); 151454967Seric break; 151554967Seric 151661104Seric case 'l': /* use Errors-To: header */ 151761104Seric UseErrorsTo = atobool(val); 151861104Seric break; 151961104Seric 15208256Seric case 'L': /* log level */ 152164140Seric if (safe || LogLevel < atoi(val)) 152264140Seric LogLevel = atoi(val); 15238256Seric break; 15248256Seric 15258269Seric case 'M': /* define macro */ 15269381Seric define(val[0], newstr(&val[1]), CurEnv); 152716878Seric sticky = FALSE; 15288269Seric break; 15298269Seric 15308269Seric case 'm': /* send to me too */ 15319381Seric MeToo = atobool(val); 15328269Seric break; 15338269Seric 153425820Seric case 'n': /* validate RHS in newaliases */ 153525820Seric CheckAliases = atobool(val); 153625820Seric break; 153725820Seric 153861104Seric /* 'N' available -- was "net name" */ 153961104Seric 154058851Seric case 'O': /* daemon options */ 154158851Seric setdaemonoptions(val); 154258851Seric break; 154358851Seric 15448269Seric case 'o': /* assume old style headers */ 15459381Seric if (atobool(val)) 15469341Seric CurEnv->e_flags |= EF_OLDSTYLE; 15479341Seric else 15489341Seric CurEnv->e_flags &= ~EF_OLDSTYLE; 15498269Seric break; 15508269Seric 155158082Seric case 'p': /* select privacy level */ 155258082Seric p = val; 155358082Seric for (;;) 155458082Seric { 155558082Seric register struct prival *pv; 155658082Seric extern struct prival PrivacyValues[]; 155758082Seric 155858082Seric while (isascii(*p) && (isspace(*p) || ispunct(*p))) 155958082Seric p++; 156058082Seric if (*p == '\0') 156158082Seric break; 156258082Seric val = p; 156358082Seric while (isascii(*p) && isalnum(*p)) 156458082Seric p++; 156558082Seric if (*p != '\0') 156658082Seric *p++ = '\0'; 156758082Seric 156858082Seric for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 156958082Seric { 157058082Seric if (strcasecmp(val, pv->pv_name) == 0) 157158082Seric break; 157258082Seric } 157358886Seric if (pv->pv_name == NULL) 157458886Seric syserr("readcf: Op line: %s unrecognized", val); 157558082Seric PrivacyFlags |= pv->pv_flag; 157658082Seric } 157758082Seric break; 157858082Seric 157924944Seric case 'P': /* postmaster copy address for returned mail */ 158024944Seric PostMasterCopy = newstr(val); 158124944Seric break; 158224944Seric 158324944Seric case 'q': /* slope of queue only function */ 158424944Seric QueueFactor = atoi(val); 158524944Seric break; 158624944Seric 15878256Seric case 'Q': /* queue directory */ 15889381Seric if (val[0] == '\0') 15898269Seric QueueDir = "mqueue"; 15909381Seric else 15919381Seric QueueDir = newstr(val); 159258789Seric if (RealUid != 0 && !safe) 159364718Seric Warn_Q_option = TRUE; 15948256Seric break; 15958256Seric 159658148Seric case 'R': /* don't prune routes */ 159758148Seric DontPruneRoutes = atobool(val); 159858148Seric break; 159958148Seric 16008256Seric case 'r': /* read timeout */ 160158112Seric settimeouts(val); 16028256Seric break; 16038256Seric 16048256Seric case 'S': /* status file */ 16059381Seric if (val[0] == '\0') 16068269Seric StatFile = "sendmail.st"; 16079381Seric else 16089381Seric StatFile = newstr(val); 16098256Seric break; 16108256Seric 16118265Seric case 's': /* be super safe, even if expensive */ 16129381Seric SuperSafe = atobool(val); 16138256Seric break; 16148256Seric 16158256Seric case 'T': /* queue timeout */ 161658737Seric p = strchr(val, '/'); 161758737Seric if (p != NULL) 161858737Seric { 161958737Seric *p++ = '\0'; 162067730Seric TimeOuts.to_q_warning[TOC_NORMAL] = convtime(p, 'd'); 162158737Seric } 162267730Seric TimeOuts.to_q_return[TOC_NORMAL] = convtime(val, 'h'); 162354967Seric break; 16248256Seric 16258265Seric case 't': /* time zone name */ 162652106Seric TimeZoneSpec = newstr(val); 16278265Seric break; 16288265Seric 162950556Seric case 'U': /* location of user database */ 163051360Seric UdbSpec = newstr(val); 163150556Seric break; 163250556Seric 16338256Seric case 'u': /* set default uid */ 163467823Seric for (p = val; *p != '\0'; p++) 163567823Seric { 163667823Seric if (*p == '.' || *p == '/' || *p == ':') 163767823Seric { 163867823Seric *p++ = '\0'; 163967823Seric break; 164067823Seric } 164167823Seric } 164264133Seric if (isascii(*val) && isdigit(*val)) 164364133Seric DefUid = atoi(val); 164464133Seric else 164564133Seric { 164664133Seric register struct passwd *pw; 164764133Seric 164864133Seric DefUid = -1; 164964133Seric pw = getpwnam(val); 165064133Seric if (pw == NULL) 165164133Seric syserr("readcf: option u: unknown user %s", val); 165264133Seric else 165367823Seric { 165464133Seric DefUid = pw->pw_uid; 165567823Seric DefGid = pw->pw_gid; 165667823Seric } 165764133Seric } 165840973Sbostic setdefuser(); 16598256Seric 166067823Seric /* handle the group if it is there */ 166167823Seric if (*p == '\0') 166267823Seric break; 166367823Seric val = p; 166467823Seric goto g_opt; 166567823Seric 166658851Seric case 'V': /* fallback MX host */ 166758851Seric FallBackMX = newstr(val); 166858851Seric break; 166958851Seric 16708269Seric case 'v': /* run in verbose mode */ 16719381Seric Verbose = atobool(val); 16728256Seric break; 16738256Seric 167463837Seric case 'w': /* if we are best MX, try host directly */ 167563837Seric TryNullMXList = atobool(val); 167663837Seric break; 167761104Seric 167861104Seric /* 'W' available -- was wizard password */ 167961104Seric 168014879Seric case 'x': /* load avg at which to auto-queue msgs */ 168114879Seric QueueLA = atoi(val); 168214879Seric break; 168314879Seric 168414879Seric case 'X': /* load avg at which to auto-reject connections */ 168514879Seric RefuseLA = atoi(val); 168614879Seric break; 168714879Seric 168824981Seric case 'y': /* work recipient factor */ 168924981Seric WkRecipFact = atoi(val); 169024981Seric break; 169124981Seric 169224981Seric case 'Y': /* fork jobs during queue runs */ 169324952Seric ForkQueueRuns = atobool(val); 169424952Seric break; 169524952Seric 169624981Seric case 'z': /* work message class factor */ 169724981Seric WkClassFact = atoi(val); 169824981Seric break; 169924981Seric 170024981Seric case 'Z': /* work time factor */ 170124981Seric WkTimeFact = atoi(val); 170224981Seric break; 170324981Seric 170467614Seric case O_BSP: /* SMTP Peers can't handle 2-line greeting */ 170567614Seric BrokenSmtpPeers = atobool(val); 170667614Seric break; 170767614Seric 170867614Seric case O_SQBH: /* sort work queue by host first */ 170967614Seric SortQueueByHost = atobool(val); 171067614Seric break; 171167614Seric 171267707Seric case O_DNICE: /* delivery nice value */ 171367707Seric DeliveryNiceness = atoi(val); 171467707Seric break; 171567707Seric 171667707Seric case O_MQA: /* minimum queue age between deliveries */ 171767707Seric MinQueueAge = convtime(val, 'm'); 171867707Seric break; 171967707Seric 172067707Seric case O_MHSA: /* maximum age of cached host status */ 172167707Seric MaxHostStatAge = convtime(val, 'm'); 172267707Seric break; 172367707Seric 172467813Seric case O_DEFCHARSET: /* default character set for mimefying */ 172567814Seric DefaultCharSet = newstr(val); 172667813Seric break; 172767813Seric 1728*67848Seric case O_SSFILE: /* service switch file */ 1729*67848Seric ServiceSwitchFile = newstr(val); 1730*67848Seric break; 1731*67848Seric 17328256Seric default: 17338256Seric break; 17348256Seric } 173516878Seric if (sticky) 173616878Seric setbitn(opt, StickyOpt); 17379188Seric return; 17388256Seric } 173910687Seric /* 174010687Seric ** SETCLASS -- set a word into a class 174110687Seric ** 174210687Seric ** Parameters: 174310687Seric ** class -- the class to put the word in. 174410687Seric ** word -- the word to enter 174510687Seric ** 174610687Seric ** Returns: 174710687Seric ** none. 174810687Seric ** 174910687Seric ** Side Effects: 175010687Seric ** puts the word into the symbol table. 175110687Seric */ 175210687Seric 175310687Seric setclass(class, word) 175410687Seric int class; 175510687Seric char *word; 175610687Seric { 175710687Seric register STAB *s; 175810687Seric 175957943Seric if (tTd(37, 8)) 176064326Seric printf("setclass(%c, %s)\n", class, word); 176110687Seric s = stab(word, ST_CLASS, ST_ENTER); 176210687Seric setbitn(class, s->s_class); 176310687Seric } 176453654Seric /* 176553654Seric ** MAKEMAPENTRY -- create a map entry 176653654Seric ** 176753654Seric ** Parameters: 176853654Seric ** line -- the config file line 176953654Seric ** 177053654Seric ** Returns: 177153654Seric ** TRUE if it successfully entered the map entry. 177253654Seric ** FALSE otherwise (usually syntax error). 177353654Seric ** 177453654Seric ** Side Effects: 177553654Seric ** Enters the map into the dictionary. 177653654Seric */ 177753654Seric 177853654Seric void 177953654Seric makemapentry(line) 178053654Seric char *line; 178153654Seric { 178253654Seric register char *p; 178353654Seric char *mapname; 178453654Seric char *classname; 178564078Seric register STAB *s; 178653654Seric STAB *class; 178753654Seric 178858050Seric for (p = line; isascii(*p) && isspace(*p); p++) 178953654Seric continue; 179058050Seric if (!(isascii(*p) && isalnum(*p))) 179153654Seric { 179253654Seric syserr("readcf: config K line: no map name"); 179353654Seric return; 179453654Seric } 179553654Seric 179653654Seric mapname = p; 1797*67848Seric while ((isascii(*++p) && isalnum(*p)) || *p == '.') 179853654Seric continue; 179953654Seric if (*p != '\0') 180053654Seric *p++ = '\0'; 180158050Seric while (isascii(*p) && isspace(*p)) 180253654Seric p++; 180358050Seric if (!(isascii(*p) && isalnum(*p))) 180453654Seric { 180553654Seric syserr("readcf: config K line, map %s: no map class", mapname); 180653654Seric return; 180753654Seric } 180853654Seric classname = p; 180958050Seric while (isascii(*++p) && isalnum(*p)) 181053654Seric continue; 181153654Seric if (*p != '\0') 181253654Seric *p++ = '\0'; 181358050Seric while (isascii(*p) && isspace(*p)) 181453654Seric p++; 181553654Seric 181653654Seric /* look up the class */ 181753654Seric class = stab(classname, ST_MAPCLASS, ST_FIND); 181853654Seric if (class == NULL) 181953654Seric { 182053654Seric syserr("readcf: map %s: class %s not available", mapname, classname); 182153654Seric return; 182253654Seric } 182353654Seric 182453654Seric /* enter the map */ 182564078Seric s = stab(mapname, ST_MAP, ST_ENTER); 182664078Seric s->s_map.map_class = &class->s_mapclass; 182764078Seric s->s_map.map_mname = newstr(mapname); 182853654Seric 182964078Seric if (class->s_mapclass.map_parse(&s->s_map, p)) 183064078Seric s->s_map.map_mflags |= MF_VALID; 183164078Seric 183264078Seric if (tTd(37, 5)) 183364078Seric { 183464078Seric printf("map %s, class %s, flags %x, file %s,\n", 183564078Seric s->s_map.map_mname, s->s_map.map_class->map_cname, 183664078Seric s->s_map.map_mflags, 183764078Seric s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 183864078Seric printf("\tapp %s, domain %s, rebuild %s\n", 183964078Seric s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 184064078Seric s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 184164078Seric s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 184264078Seric } 184353654Seric } 184458112Seric /* 184558112Seric ** SETTIMEOUTS -- parse and set timeout values 184658112Seric ** 184758112Seric ** Parameters: 184858112Seric ** val -- a pointer to the values. If NULL, do initial 184958112Seric ** settings. 185058112Seric ** 185158112Seric ** Returns: 185258112Seric ** none. 185358112Seric ** 185458112Seric ** Side Effects: 185558112Seric ** Initializes the TimeOuts structure 185658112Seric */ 185758112Seric 185864255Seric #define SECONDS 185958112Seric #define MINUTES * 60 186058112Seric #define HOUR * 3600 186158112Seric 186258112Seric settimeouts(val) 186358112Seric register char *val; 186458112Seric { 186558112Seric register char *p; 186658671Seric extern time_t convtime(); 186758112Seric 186858112Seric if (val == NULL) 186958112Seric { 187058112Seric TimeOuts.to_initial = (time_t) 5 MINUTES; 187158112Seric TimeOuts.to_helo = (time_t) 5 MINUTES; 187258112Seric TimeOuts.to_mail = (time_t) 10 MINUTES; 187358112Seric TimeOuts.to_rcpt = (time_t) 1 HOUR; 187458112Seric TimeOuts.to_datainit = (time_t) 5 MINUTES; 187558112Seric TimeOuts.to_datablock = (time_t) 1 HOUR; 187658112Seric TimeOuts.to_datafinal = (time_t) 1 HOUR; 187758112Seric TimeOuts.to_rset = (time_t) 5 MINUTES; 187858112Seric TimeOuts.to_quit = (time_t) 2 MINUTES; 187958112Seric TimeOuts.to_nextcommand = (time_t) 1 HOUR; 188058112Seric TimeOuts.to_miscshort = (time_t) 2 MINUTES; 188164255Seric TimeOuts.to_ident = (time_t) 30 SECONDS; 188267711Seric TimeOuts.to_fileopen = (time_t) 60 SECONDS; 188358112Seric return; 188458112Seric } 188558112Seric 188658112Seric for (;; val = p) 188758112Seric { 188858112Seric while (isascii(*val) && isspace(*val)) 188958112Seric val++; 189058112Seric if (*val == '\0') 189158112Seric break; 189258112Seric for (p = val; *p != '\0' && *p != ','; p++) 189358112Seric continue; 189458112Seric if (*p != '\0') 189558112Seric *p++ = '\0'; 189658112Seric 189758112Seric if (isascii(*val) && isdigit(*val)) 189858112Seric { 189958112Seric /* old syntax -- set everything */ 190058796Seric TimeOuts.to_mail = convtime(val, 'm'); 190158112Seric TimeOuts.to_rcpt = TimeOuts.to_mail; 190258112Seric TimeOuts.to_datainit = TimeOuts.to_mail; 190358112Seric TimeOuts.to_datablock = TimeOuts.to_mail; 190458112Seric TimeOuts.to_datafinal = TimeOuts.to_mail; 190558112Seric TimeOuts.to_nextcommand = TimeOuts.to_mail; 190658112Seric continue; 190758112Seric } 190858112Seric else 190958112Seric { 191067711Seric register char *q = strchr(val, ':'); 191158112Seric time_t to; 191258112Seric 191367711Seric if (q == NULL && (q = strchr(val, '=')) == NULL) 191458112Seric { 191558112Seric /* syntax error */ 191658112Seric continue; 191758112Seric } 191858112Seric *q++ = '\0'; 191958796Seric to = convtime(q, 'm'); 192058112Seric 192158112Seric if (strcasecmp(val, "initial") == 0) 192258112Seric TimeOuts.to_initial = to; 192358112Seric else if (strcasecmp(val, "mail") == 0) 192458112Seric TimeOuts.to_mail = to; 192558112Seric else if (strcasecmp(val, "rcpt") == 0) 192658112Seric TimeOuts.to_rcpt = to; 192758112Seric else if (strcasecmp(val, "datainit") == 0) 192858112Seric TimeOuts.to_datainit = to; 192958112Seric else if (strcasecmp(val, "datablock") == 0) 193058112Seric TimeOuts.to_datablock = to; 193158112Seric else if (strcasecmp(val, "datafinal") == 0) 193258112Seric TimeOuts.to_datafinal = to; 193358112Seric else if (strcasecmp(val, "command") == 0) 193458112Seric TimeOuts.to_nextcommand = to; 193558112Seric else if (strcasecmp(val, "rset") == 0) 193658112Seric TimeOuts.to_rset = to; 193758112Seric else if (strcasecmp(val, "helo") == 0) 193858112Seric TimeOuts.to_helo = to; 193958112Seric else if (strcasecmp(val, "quit") == 0) 194058112Seric TimeOuts.to_quit = to; 194158112Seric else if (strcasecmp(val, "misc") == 0) 194258112Seric TimeOuts.to_miscshort = to; 194364255Seric else if (strcasecmp(val, "ident") == 0) 194464255Seric TimeOuts.to_ident = to; 194567711Seric else if (strcasecmp(val, "fileopen") == 0) 194667711Seric TimeOuts.to_fileopen = to; 194767711Seric else if (strcasecmp(val, "queuewarn") == 0) 194867730Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 194967711Seric else if (strcasecmp(val, "queuereturn") == 0) 195067730Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 195167730Seric else if (strcasecmp(val, "queuewarn.normal") == 0) 195267730Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 195367730Seric else if (strcasecmp(val, "queuereturn.normal") == 0) 195467730Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 195567730Seric else if (strcasecmp(val, "queuewarn.urgent") == 0) 195667730Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 195767730Seric else if (strcasecmp(val, "queuereturn.urgent") == 0) 195867730Seric TimeOuts.to_q_return[TOC_URGENT] = to; 195967730Seric else if (strcasecmp(val, "queuewarn.non-urgent") == 0) 196067730Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 196167730Seric else if (strcasecmp(val, "queuereturn.non-urgent") == 0) 196267730Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 196358112Seric else 196458112Seric syserr("settimeouts: invalid timeout %s", val); 196558112Seric } 196658112Seric } 196758112Seric } 1968