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*67736Seric static char sccsid[] = "@(#)readcf.c 8.37 (Berkeley) 08/23/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; 803308Seric char buf[MAXLINE]; 813308Seric register char *p; 823308Seric extern char **copyplist(); 8352647Seric struct stat statb; 845909Seric char exbuf[MAXLINE]; 8565066Seric char pvpbuf[MAXLINE + MAXATOM]; 8610709Seric extern char *munchstring(); 8753654Seric extern void makemapentry(); 883308Seric 8952647Seric FileName = cfname; 9052647Seric LineNumber = 0; 9152647Seric 923308Seric cf = fopen(cfname, "r"); 933308Seric if (cf == NULL) 943308Seric { 9552647Seric syserr("cannot open"); 963308Seric exit(EX_OSFILE); 973308Seric } 983308Seric 9952647Seric if (fstat(fileno(cf), &statb) < 0) 10052647Seric { 10152647Seric syserr("cannot fstat"); 10252647Seric exit(EX_OSFILE); 10352647Seric } 10452647Seric 10552647Seric if (!S_ISREG(statb.st_mode)) 10652647Seric { 10752647Seric syserr("not a plain file"); 10852647Seric exit(EX_OSFILE); 10952647Seric } 11052647Seric 11152647Seric if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode)) 11252647Seric { 11353037Seric if (OpMode == MD_DAEMON || OpMode == MD_FREEZE) 11453037Seric fprintf(stderr, "%s: WARNING: dangerous write permissions\n", 11553037Seric FileName); 11653037Seric #ifdef LOG 11753037Seric if (LogLevel > 0) 11853037Seric syslog(LOG_CRIT, "%s: WARNING: dangerous write permissions", 11953037Seric FileName); 12053037Seric #endif 12152647Seric } 12252647Seric 12359254Seric #ifdef XLA 12459254Seric xla_zero(); 12559254Seric #endif 12659254Seric 12757135Seric while ((bp = fgetfolded(buf, sizeof buf, cf)) != NULL) 1283308Seric { 12957135Seric if (bp[0] == '#') 13057135Seric { 13157135Seric if (bp != buf) 13257135Seric free(bp); 13352637Seric continue; 13457135Seric } 13552637Seric 13658050Seric /* map $ into \201 for macro expansion */ 13757135Seric for (p = bp; *p != '\0'; p++) 13816157Seric { 13957135Seric if (*p == '#' && p > bp && ConfigLevel >= 3) 14052647Seric { 14152647Seric /* this is an on-line comment */ 14252647Seric register char *e; 14352647Seric 14458050Seric switch (*--p & 0377) 14552647Seric { 14658050Seric case MACROEXPAND: 14752647Seric /* it's from $# -- let it go through */ 14852647Seric p++; 14952647Seric break; 15052647Seric 15152647Seric case '\\': 15252647Seric /* it's backslash escaped */ 15352647Seric (void) strcpy(p, p + 1); 15452647Seric break; 15552647Seric 15652647Seric default: 15752647Seric /* delete preceeding white space */ 15858050Seric while (isascii(*p) && isspace(*p) && p > bp) 15952647Seric p--; 16056795Seric if ((e = strchr(++p, '\n')) != NULL) 16152647Seric (void) strcpy(p, e); 16252647Seric else 16352647Seric p[0] = p[1] = '\0'; 16452647Seric break; 16552647Seric } 16652647Seric continue; 16752647Seric } 16852647Seric 16916157Seric if (*p != '$') 17016157Seric continue; 17116157Seric 17216157Seric if (p[1] == '$') 17316157Seric { 17416157Seric /* actual dollar sign.... */ 17523111Seric (void) strcpy(p, p + 1); 17616157Seric continue; 17716157Seric } 17816157Seric 17916157Seric /* convert to macro expansion character */ 18058050Seric *p = MACROEXPAND; 18116157Seric } 18216157Seric 18316157Seric /* interpret this line */ 18464718Seric errno = 0; 18557135Seric switch (bp[0]) 1863308Seric { 1873308Seric case '\0': 1883308Seric case '#': /* comment */ 1893308Seric break; 1903308Seric 1913308Seric case 'R': /* rewriting rule */ 19257135Seric for (p = &bp[1]; *p != '\0' && *p != '\t'; p++) 1933308Seric continue; 1943308Seric 1953308Seric if (*p == '\0') 1965909Seric { 19765821Seric syserr("invalid rewrite line \"%s\" (tab expected)", bp); 1985909Seric break; 1995909Seric } 2005909Seric 2015909Seric /* allocate space for the rule header */ 2025909Seric if (rwp == NULL) 2035909Seric { 2045909Seric RewriteRules[ruleset] = rwp = 2055909Seric (struct rewrite *) xalloc(sizeof *rwp); 2065909Seric } 2073308Seric else 2083308Seric { 2095909Seric rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp); 2105909Seric rwp = rwp->r_next; 2115909Seric } 2125909Seric rwp->r_next = NULL; 2133308Seric 2145909Seric /* expand and save the LHS */ 2155909Seric *p = '\0'; 21657135Seric expand(&bp[1], exbuf, &exbuf[sizeof exbuf], e); 21765066Seric rwp->r_lhs = prescan(exbuf, '\t', pvpbuf, 21865066Seric sizeof pvpbuf, NULL); 21957589Seric nfuzzy = 0; 2205909Seric if (rwp->r_lhs != NULL) 22157589Seric { 22257589Seric register char **ap; 22357589Seric 2245909Seric rwp->r_lhs = copyplist(rwp->r_lhs, TRUE); 22557589Seric 22657589Seric /* count the number of fuzzy matches in LHS */ 22757589Seric for (ap = rwp->r_lhs; *ap != NULL; ap++) 22857589Seric { 22958148Seric char *botch; 23058148Seric 23158148Seric botch = NULL; 23258050Seric switch (**ap & 0377) 23357589Seric { 23457589Seric case MATCHZANY: 23557589Seric case MATCHANY: 23657589Seric case MATCHONE: 23757589Seric case MATCHCLASS: 23857589Seric case MATCHNCLASS: 23957589Seric nfuzzy++; 24058148Seric break; 24158148Seric 24258148Seric case MATCHREPL: 24358148Seric botch = "$0-$9"; 24458148Seric break; 24558148Seric 24658148Seric case CANONNET: 24758148Seric botch = "$#"; 24858148Seric break; 24958148Seric 25058148Seric case CANONUSER: 25158148Seric botch = "$:"; 25258148Seric break; 25358148Seric 25458148Seric case CALLSUBR: 25558148Seric botch = "$>"; 25658148Seric break; 25758148Seric 25858148Seric case CONDIF: 25958148Seric botch = "$?"; 26058148Seric break; 26158148Seric 26258148Seric case CONDELSE: 26358148Seric botch = "$|"; 26458148Seric break; 26558148Seric 26658148Seric case CONDFI: 26758148Seric botch = "$."; 26858148Seric break; 26958148Seric 27058148Seric case HOSTBEGIN: 27158148Seric botch = "$["; 27258148Seric break; 27358148Seric 27458148Seric case HOSTEND: 27558148Seric botch = "$]"; 27658148Seric break; 27758148Seric 27858148Seric case LOOKUPBEGIN: 27958148Seric botch = "$("; 28058148Seric break; 28158148Seric 28258148Seric case LOOKUPEND: 28358148Seric botch = "$)"; 28458148Seric break; 28557589Seric } 28658148Seric if (botch != NULL) 28758148Seric syserr("Inappropriate use of %s on LHS", 28858148Seric botch); 28957589Seric } 29057589Seric } 29156678Seric else 29256678Seric syserr("R line: null LHS"); 2935909Seric 2945909Seric /* expand and save the RHS */ 2955909Seric while (*++p == '\t') 2965909Seric continue; 2977231Seric q = p; 2987231Seric while (*p != '\0' && *p != '\t') 2997231Seric p++; 3007231Seric *p = '\0'; 30155012Seric expand(q, exbuf, &exbuf[sizeof exbuf], e); 30265066Seric rwp->r_rhs = prescan(exbuf, '\t', pvpbuf, 30365066Seric sizeof pvpbuf, NULL); 3045909Seric if (rwp->r_rhs != NULL) 30557589Seric { 30657589Seric register char **ap; 30757589Seric 3085909Seric rwp->r_rhs = copyplist(rwp->r_rhs, TRUE); 30957589Seric 31057589Seric /* check no out-of-bounds replacements */ 31157589Seric nfuzzy += '0'; 31257589Seric for (ap = rwp->r_rhs; *ap != NULL; ap++) 31357589Seric { 31458148Seric char *botch; 31558148Seric 31658148Seric botch = NULL; 31758148Seric switch (**ap & 0377) 31857589Seric { 31958148Seric case MATCHREPL: 32058148Seric if ((*ap)[1] <= '0' || (*ap)[1] > nfuzzy) 32158148Seric { 32258148Seric syserr("replacement $%c out of bounds", 32358148Seric (*ap)[1]); 32458148Seric } 32558148Seric break; 32658148Seric 32758148Seric case MATCHZANY: 32858148Seric botch = "$*"; 32958148Seric break; 33058148Seric 33158148Seric case MATCHANY: 33258148Seric botch = "$+"; 33358148Seric break; 33458148Seric 33558148Seric case MATCHONE: 33658148Seric botch = "$-"; 33758148Seric break; 33858148Seric 33958148Seric case MATCHCLASS: 34058148Seric botch = "$="; 34158148Seric break; 34258148Seric 34358148Seric case MATCHNCLASS: 34458148Seric botch = "$~"; 34558148Seric break; 34657589Seric } 34758148Seric if (botch != NULL) 34858148Seric syserr("Inappropriate use of %s on RHS", 34958148Seric botch); 35057589Seric } 35157589Seric } 35256678Seric else 35356678Seric syserr("R line: null RHS"); 3543308Seric break; 3553308Seric 3564072Seric case 'S': /* select rewriting set */ 35764440Seric for (p = &bp[1]; isascii(*p) && isspace(*p); p++) 35864440Seric continue; 35964440Seric if (!isascii(*p) || !isdigit(*p)) 36064440Seric { 36164440Seric syserr("invalid argument to S line: \"%.20s\"", 36264440Seric &bp[1]); 36364440Seric break; 36464440Seric } 36564440Seric ruleset = atoi(p); 3668056Seric if (ruleset >= MAXRWSETS || ruleset < 0) 3678056Seric { 3689381Seric syserr("bad ruleset %d (%d max)", ruleset, MAXRWSETS); 3698056Seric ruleset = 0; 3708056Seric } 3714072Seric rwp = NULL; 3724072Seric break; 3734072Seric 3743308Seric case 'D': /* macro definition */ 37564086Seric p = munchstring(&bp[2], NULL); 37664086Seric define(bp[1], newstr(p), e); 3773308Seric break; 3783308Seric 3793387Seric case 'H': /* required header line */ 38057135Seric (void) chompheader(&bp[1], TRUE, e); 3813387Seric break; 3823387Seric 3834061Seric case 'C': /* word class */ 3844432Seric /* scan the list of words and set class for all */ 38564121Seric expand(&bp[2], exbuf, &exbuf[sizeof exbuf], e); 38664121Seric for (p = exbuf; *p != '\0'; ) 3874061Seric { 3884061Seric register char *wd; 3894061Seric char delim; 3904061Seric 39158050Seric while (*p != '\0' && isascii(*p) && isspace(*p)) 3924061Seric p++; 3934061Seric wd = p; 39458050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 3954061Seric p++; 3964061Seric delim = *p; 3974061Seric *p = '\0'; 3984061Seric if (wd[0] != '\0') 39957135Seric setclass(bp[1], wd); 4004061Seric *p = delim; 4014061Seric } 4024061Seric break; 4034061Seric 40459272Seric case 'F': /* word class from file */ 40564133Seric for (p = &bp[2]; isascii(*p) && isspace(*p); ) 40664133Seric p++; 40764133Seric if (p[0] == '-' && p[1] == 'o') 40864133Seric { 40964133Seric optional = TRUE; 41064133Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 41164133Seric p++; 41264133Seric while (isascii(*p) && isspace(*p)) 41367615Seric p++; 41464133Seric } 41564133Seric else 41664133Seric optional = FALSE; 41764133Seric file = p; 41864133Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 41964133Seric p++; 42059272Seric if (*p == '\0') 42159272Seric p = "%s"; 42259272Seric else 42359272Seric { 42459272Seric *p = '\0'; 42559272Seric while (isascii(*++p) && isspace(*p)) 42659272Seric continue; 42759272Seric } 42864133Seric fileclass(bp[1], file, p, safe, optional); 42959272Seric break; 43059272Seric 43159156Seric #ifdef XLA 43259156Seric case 'L': /* extended load average description */ 43359156Seric xla_init(&bp[1]); 43459156Seric break; 43559156Seric #endif 43659156Seric 4374096Seric case 'M': /* define mailer */ 43857135Seric makemailer(&bp[1]); 4394096Seric break; 4404096Seric 4418252Seric case 'O': /* set option */ 44258734Seric setoption(bp[1], &bp[2], safe, FALSE, e); 4438252Seric break; 4448252Seric 4458252Seric case 'P': /* set precedence */ 4468252Seric if (NumPriorities >= MAXPRIORITIES) 4478252Seric { 4488547Seric toomany('P', MAXPRIORITIES); 4498252Seric break; 4508252Seric } 45157135Seric for (p = &bp[1]; *p != '\0' && *p != '=' && *p != '\t'; p++) 4528252Seric continue; 4538252Seric if (*p == '\0') 4548252Seric goto badline; 4558252Seric *p = '\0'; 45657135Seric Priorities[NumPriorities].pri_name = newstr(&bp[1]); 4578252Seric Priorities[NumPriorities].pri_val = atoi(++p); 4588252Seric NumPriorities++; 4598252Seric break; 4608252Seric 4618547Seric case 'T': /* trusted user(s) */ 46258161Seric /* this option is obsolete, but will be ignored */ 4638547Seric break; 4648547Seric 46552645Seric case 'V': /* configuration syntax version */ 46664440Seric for (p = &bp[1]; isascii(*p) && isspace(*p); p++) 46764440Seric continue; 46864440Seric if (!isascii(*p) || !isdigit(*p)) 46964440Seric { 47064440Seric syserr("invalid argument to V line: \"%.20s\"", 47164440Seric &bp[1]); 47264440Seric break; 47364440Seric } 47464718Seric ConfigLevel = strtol(p, &ep, 10); 47564279Seric if (ConfigLevel >= 5) 47664279Seric { 47764279Seric /* level 5 configs have short name in $w */ 47864279Seric p = macvalue('w', e); 47964279Seric if (p != NULL && (p = strchr(p, '.')) != NULL) 48064279Seric *p = '\0'; 48164279Seric } 48264718Seric if (*ep++ == '/') 48364718Seric { 48464718Seric /* extract vendor code */ 48564718Seric for (p = ep; isascii(*p) && isalpha(*p); ) 48664718Seric p++; 48764718Seric *p = '\0'; 48864718Seric 48964718Seric if (!setvendor(ep)) 49064718Seric syserr("invalid V line vendor code: \"%s\"", 49164718Seric ep); 49264718Seric } 49352645Seric break; 49452645Seric 49553654Seric case 'K': 49657135Seric makemapentry(&bp[1]); 49753654Seric break; 49853654Seric 4993308Seric default: 5004061Seric badline: 50157135Seric syserr("unknown control line \"%s\"", bp); 5023308Seric } 50357135Seric if (bp != buf) 50457135Seric free(bp); 5053308Seric } 50652637Seric if (ferror(cf)) 50752637Seric { 50852647Seric syserr("I/O read error", cfname); 50952637Seric exit(EX_OSFILE); 51052637Seric } 51152637Seric fclose(cf); 5129381Seric FileName = NULL; 51356836Seric 51467730Seric /* initialize host maps from local service tables */ 51567730Seric inithostmaps(); 51667730Seric 51757076Seric if (stab("host", ST_MAP, ST_FIND) == NULL) 51857076Seric { 51957076Seric /* user didn't initialize: set up host map */ 52057076Seric strcpy(buf, "host host"); 52166334Seric #if NAMED_BIND 52257076Seric if (ConfigLevel >= 2) 52357076Seric strcat(buf, " -a."); 52464947Seric #endif 52557076Seric makemapentry(buf); 52657076Seric } 5274096Seric } 5284096Seric /* 5298547Seric ** TOOMANY -- signal too many of some option 5308547Seric ** 5318547Seric ** Parameters: 5328547Seric ** id -- the id of the error line 5338547Seric ** maxcnt -- the maximum possible values 5348547Seric ** 5358547Seric ** Returns: 5368547Seric ** none. 5378547Seric ** 5388547Seric ** Side Effects: 5398547Seric ** gives a syserr. 5408547Seric */ 5418547Seric 5428547Seric toomany(id, maxcnt) 5438547Seric char id; 5448547Seric int maxcnt; 5458547Seric { 5469381Seric syserr("too many %c lines, %d max", id, maxcnt); 5478547Seric } 5488547Seric /* 5494432Seric ** FILECLASS -- read members of a class from a file 5504432Seric ** 5514432Seric ** Parameters: 5524432Seric ** class -- class to define. 5534432Seric ** filename -- name of file to read. 5544432Seric ** fmt -- scanf string to use for match. 55564133Seric ** safe -- if set, this is a safe read. 55664133Seric ** optional -- if set, it is not an error for the file to 55764133Seric ** not exist. 5584432Seric ** 5594432Seric ** Returns: 5604432Seric ** none 5614432Seric ** 5624432Seric ** Side Effects: 5634432Seric ** 5644432Seric ** puts all lines in filename that match a scanf into 5654432Seric ** the named class. 5664432Seric */ 5674432Seric 56864133Seric fileclass(class, filename, fmt, safe, optional) 5694432Seric int class; 5704432Seric char *filename; 5714432Seric char *fmt; 57254973Seric bool safe; 57364133Seric bool optional; 5744432Seric { 57525808Seric FILE *f; 57654973Seric struct stat stbuf; 5774432Seric char buf[MAXLINE]; 5784432Seric 57966101Seric if (tTd(37, 2)) 58066101Seric printf("fileclass(%s, fmt=%s)\n", filename, fmt); 58166101Seric 58266031Seric if (filename[0] == '|') 58366031Seric { 58466031Seric syserr("fileclass: pipes (F%c%s) not supported due to security problems", 58566031Seric class, filename); 58666031Seric return; 58766031Seric } 58854973Seric if (stat(filename, &stbuf) < 0) 58954973Seric { 59066101Seric if (tTd(37, 2)) 59166101Seric printf(" cannot stat (%s)\n", errstring(errno)); 59264133Seric if (!optional) 59364133Seric syserr("fileclass: cannot stat %s", filename); 59454973Seric return; 59554973Seric } 59654973Seric if (!S_ISREG(stbuf.st_mode)) 59754973Seric { 59854973Seric syserr("fileclass: %s not a regular file", filename); 59954973Seric return; 60054973Seric } 60154973Seric if (!safe && access(filename, R_OK) < 0) 60254973Seric { 60354973Seric syserr("fileclass: access denied on %s", filename); 60454973Seric return; 60554973Seric } 60654973Seric f = fopen(filename, "r"); 6074432Seric if (f == NULL) 6084432Seric { 60954973Seric syserr("fileclass: cannot open %s", filename); 6104432Seric return; 6114432Seric } 6124432Seric 6134432Seric while (fgets(buf, sizeof buf, f) != NULL) 6144432Seric { 6154432Seric register STAB *s; 61625808Seric register char *p; 61725808Seric # ifdef SCANF 6184432Seric char wordbuf[MAXNAME+1]; 6194432Seric 6204432Seric if (sscanf(buf, fmt, wordbuf) != 1) 6214432Seric continue; 62225808Seric p = wordbuf; 62356795Seric # else /* SCANF */ 62425808Seric p = buf; 62556795Seric # endif /* SCANF */ 62625808Seric 62725808Seric /* 62825808Seric ** Break up the match into words. 62925808Seric */ 63025808Seric 63125808Seric while (*p != '\0') 63225808Seric { 63325808Seric register char *q; 63425808Seric 63525808Seric /* strip leading spaces */ 63658050Seric while (isascii(*p) && isspace(*p)) 63725808Seric p++; 63825808Seric if (*p == '\0') 63925808Seric break; 64025808Seric 64125808Seric /* find the end of the word */ 64225808Seric q = p; 64358050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 64425808Seric p++; 64525808Seric if (*p != '\0') 64625808Seric *p++ = '\0'; 64725808Seric 64825808Seric /* enter the word in the symbol table */ 64966101Seric setclass(class, q); 65025808Seric } 6514432Seric } 6524432Seric 65354973Seric (void) fclose(f); 6544432Seric } 6554432Seric /* 6564096Seric ** MAKEMAILER -- define a new mailer. 6574096Seric ** 6584096Seric ** Parameters: 65910327Seric ** line -- description of mailer. This is in labeled 66010327Seric ** fields. The fields are: 66110327Seric ** P -- the path to the mailer 66210327Seric ** F -- the flags associated with the mailer 66310327Seric ** A -- the argv for this mailer 66410327Seric ** S -- the sender rewriting set 66510327Seric ** R -- the recipient rewriting set 66610327Seric ** E -- the eol string 66710327Seric ** The first word is the canonical name of the mailer. 6684096Seric ** 6694096Seric ** Returns: 6704096Seric ** none. 6714096Seric ** 6724096Seric ** Side Effects: 6734096Seric ** enters the mailer into the mailer table. 6744096Seric */ 6753308Seric 67621066Seric makemailer(line) 6774096Seric char *line; 6784096Seric { 6794096Seric register char *p; 6808067Seric register struct mailer *m; 6818067Seric register STAB *s; 6828067Seric int i; 68310327Seric char fcode; 68458020Seric auto char *endp; 6854096Seric extern int NextMailer; 68610327Seric extern char **makeargv(); 68710327Seric extern char *munchstring(); 68810701Seric extern long atol(); 6894096Seric 69010327Seric /* allocate a mailer and set up defaults */ 69110327Seric m = (struct mailer *) xalloc(sizeof *m); 69210327Seric bzero((char *) m, sizeof *m); 69310327Seric m->m_eol = "\n"; 69467604Seric m->m_uid = m->m_gid = 0; 69510327Seric 69610327Seric /* collect the mailer name */ 69758050Seric for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++) 69810327Seric continue; 69910327Seric if (*p != '\0') 70010327Seric *p++ = '\0'; 70110327Seric m->m_name = newstr(line); 70210327Seric 70310327Seric /* now scan through and assign info from the fields */ 70410327Seric while (*p != '\0') 70510327Seric { 70658333Seric auto char *delimptr; 70758333Seric 70858050Seric while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p)))) 70910327Seric p++; 71010327Seric 71110327Seric /* p now points to field code */ 71210327Seric fcode = *p; 71310327Seric while (*p != '\0' && *p != '=' && *p != ',') 71410327Seric p++; 71510327Seric if (*p++ != '=') 71610327Seric { 71752637Seric syserr("mailer %s: `=' expected", m->m_name); 71810327Seric return; 71910327Seric } 72058050Seric while (isascii(*p) && isspace(*p)) 72110327Seric p++; 72210327Seric 72310327Seric /* p now points to the field body */ 72458333Seric p = munchstring(p, &delimptr); 72510327Seric 72610327Seric /* install the field into the mailer struct */ 72710327Seric switch (fcode) 72810327Seric { 72910327Seric case 'P': /* pathname */ 73010327Seric m->m_mailer = newstr(p); 73110327Seric break; 73210327Seric 73310327Seric case 'F': /* flags */ 73410687Seric for (; *p != '\0'; p++) 73558050Seric if (!(isascii(*p) && isspace(*p))) 73652637Seric setbitn(*p, m->m_flags); 73710327Seric break; 73810327Seric 73910327Seric case 'S': /* sender rewriting ruleset */ 74010327Seric case 'R': /* recipient rewriting ruleset */ 74158020Seric i = strtol(p, &endp, 10); 74210327Seric if (i < 0 || i >= MAXRWSETS) 74310327Seric { 74410327Seric syserr("invalid rewrite set, %d max", MAXRWSETS); 74510327Seric return; 74610327Seric } 74710327Seric if (fcode == 'S') 74858020Seric m->m_sh_rwset = m->m_se_rwset = i; 74910327Seric else 75058020Seric m->m_rh_rwset = m->m_re_rwset = i; 75158020Seric 75258020Seric p = endp; 75359985Seric if (*p++ == '/') 75458020Seric { 75558020Seric i = strtol(p, NULL, 10); 75658020Seric if (i < 0 || i >= MAXRWSETS) 75758020Seric { 75858020Seric syserr("invalid rewrite set, %d max", 75958020Seric MAXRWSETS); 76058020Seric return; 76158020Seric } 76258020Seric if (fcode == 'S') 76358020Seric m->m_sh_rwset = i; 76458020Seric else 76558020Seric m->m_rh_rwset = i; 76658020Seric } 76710327Seric break; 76810327Seric 76910327Seric case 'E': /* end of line string */ 77010327Seric m->m_eol = newstr(p); 77110327Seric break; 77210327Seric 77310327Seric case 'A': /* argument vector */ 77410327Seric m->m_argv = makeargv(p); 77510327Seric break; 77610701Seric 77710701Seric case 'M': /* maximum message size */ 77810701Seric m->m_maxsize = atol(p); 77910701Seric break; 78052106Seric 78152106Seric case 'L': /* maximum line length */ 78252106Seric m->m_linelimit = atoi(p); 78352106Seric break; 78458935Seric 78558935Seric case 'D': /* working directory */ 78658935Seric m->m_execdir = newstr(p); 78758935Seric break; 78867604Seric 78967604Seric case 'U': /* user id */ 79067604Seric if (isascii(*p) && !isdigit(*p)) 79167604Seric { 79267604Seric char *q = p; 79367604Seric struct passwd *pw; 79467604Seric 79567604Seric while (isascii(*p) && isalnum(*p)) 79667604Seric p++; 79767604Seric while (isascii(*p) && isspace(*p)) 79867604Seric *p++ = '\0'; 79967604Seric if (*p != '\0') 80067604Seric *p++ = '\0'; 80167604Seric pw = getpwnam(q); 80267604Seric if (pw == NULL) 80367604Seric syserr("readcf: mailer U= flag: unknown user %s", q); 80467604Seric else 80567604Seric { 80667604Seric m->m_uid = pw->pw_uid; 80767604Seric m->m_gid = pw->pw_gid; 80867604Seric } 80967604Seric } 81067604Seric else 81167604Seric { 81267604Seric auto char *q; 81367604Seric 81467604Seric m->m_uid = strtol(p, &q, 0); 81567604Seric p = q; 81667604Seric } 81767604Seric while (isascii(*p) && isspace(*p)) 81867604Seric p++; 81967604Seric if (*p == '\0') 82067604Seric break; 82167604Seric if (isascii(*p) && !isdigit(*p)) 82267604Seric { 82367604Seric char *q = p; 82467604Seric struct group *gr; 82567604Seric 82667604Seric while (isascii(*p) && isalnum(*p)) 82767604Seric p++; 82867604Seric *p++ = '\0'; 82967604Seric gr = getgrnam(q); 83067604Seric if (gr == NULL) 83167604Seric syserr("readcf: mailer U= flag: unknown group %s", q); 83267604Seric else 83367604Seric m->m_gid = gr->gr_gid; 83467604Seric } 83567604Seric else 83667604Seric { 83767604Seric m->m_gid = strtol(p, NULL, 0); 83867604Seric } 83967604Seric break; 84010327Seric } 84110327Seric 84258333Seric p = delimptr; 84310327Seric } 84410327Seric 84552106Seric /* do some heuristic cleanup for back compatibility */ 84652106Seric if (bitnset(M_LIMITS, m->m_flags)) 84752106Seric { 84852106Seric if (m->m_linelimit == 0) 84952106Seric m->m_linelimit = SMTPLINELIM; 85055418Seric if (ConfigLevel < 2) 85152106Seric setbitn(M_7BITS, m->m_flags); 85252106Seric } 85352106Seric 85458321Seric /* do some rationality checking */ 85558321Seric if (m->m_argv == NULL) 85658321Seric { 85758321Seric syserr("M%s: A= argument required", m->m_name); 85858321Seric return; 85958321Seric } 86058321Seric if (m->m_mailer == NULL) 86158321Seric { 86258321Seric syserr("M%s: P= argument required", m->m_name); 86358321Seric return; 86458321Seric } 86558321Seric 8664096Seric if (NextMailer >= MAXMAILERS) 8674096Seric { 8689381Seric syserr("too many mailers defined (%d max)", MAXMAILERS); 8694096Seric return; 8704096Seric } 87157402Seric 87210327Seric s = stab(m->m_name, ST_MAILER, ST_ENTER); 87357402Seric if (s->s_mailer != NULL) 87457402Seric { 87557402Seric i = s->s_mailer->m_mno; 87657402Seric free(s->s_mailer); 87757402Seric } 87857402Seric else 87957402Seric { 88057402Seric i = NextMailer++; 88157402Seric } 88257402Seric Mailer[i] = s->s_mailer = m; 88357454Seric m->m_mno = i; 88410327Seric } 88510327Seric /* 88610327Seric ** MUNCHSTRING -- translate a string into internal form. 88710327Seric ** 88810327Seric ** Parameters: 88910327Seric ** p -- the string to munch. 89058333Seric ** delimptr -- if non-NULL, set to the pointer of the 89158333Seric ** field delimiter character. 89210327Seric ** 89310327Seric ** Returns: 89410327Seric ** the munched string. 89510327Seric */ 8964096Seric 89710327Seric char * 89858333Seric munchstring(p, delimptr) 89910327Seric register char *p; 90058333Seric char **delimptr; 90110327Seric { 90210327Seric register char *q; 90310327Seric bool backslash = FALSE; 90410327Seric bool quotemode = FALSE; 90510327Seric static char buf[MAXLINE]; 9064096Seric 90710327Seric for (q = buf; *p != '\0'; p++) 9084096Seric { 90910327Seric if (backslash) 91010327Seric { 91110327Seric /* everything is roughly literal */ 91210357Seric backslash = FALSE; 91310327Seric switch (*p) 91410327Seric { 91510327Seric case 'r': /* carriage return */ 91610327Seric *q++ = '\r'; 91710327Seric continue; 91810327Seric 91910327Seric case 'n': /* newline */ 92010327Seric *q++ = '\n'; 92110327Seric continue; 92210327Seric 92310327Seric case 'f': /* form feed */ 92410327Seric *q++ = '\f'; 92510327Seric continue; 92610327Seric 92710327Seric case 'b': /* backspace */ 92810327Seric *q++ = '\b'; 92910327Seric continue; 93010327Seric } 93110327Seric *q++ = *p; 93210327Seric } 93310327Seric else 93410327Seric { 93510327Seric if (*p == '\\') 93610327Seric backslash = TRUE; 93710327Seric else if (*p == '"') 93810327Seric quotemode = !quotemode; 93910327Seric else if (quotemode || *p != ',') 94010327Seric *q++ = *p; 94110327Seric else 94210327Seric break; 94310327Seric } 9444096Seric } 9454096Seric 94658333Seric if (delimptr != NULL) 94758333Seric *delimptr = p; 94810327Seric *q++ = '\0'; 94910327Seric return (buf); 95010327Seric } 95110327Seric /* 95210327Seric ** MAKEARGV -- break up a string into words 95310327Seric ** 95410327Seric ** Parameters: 95510327Seric ** p -- the string to break up. 95610327Seric ** 95710327Seric ** Returns: 95810327Seric ** a char **argv (dynamically allocated) 95910327Seric ** 96010327Seric ** Side Effects: 96110327Seric ** munges p. 96210327Seric */ 9634096Seric 96410327Seric char ** 96510327Seric makeargv(p) 96610327Seric register char *p; 96710327Seric { 96810327Seric char *q; 96910327Seric int i; 97010327Seric char **avp; 97110327Seric char *argv[MAXPV + 1]; 97210327Seric 97310327Seric /* take apart the words */ 97410327Seric i = 0; 97510327Seric while (*p != '\0' && i < MAXPV) 9764096Seric { 97710327Seric q = p; 97858050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 97910327Seric p++; 98058050Seric while (isascii(*p) && isspace(*p)) 98110327Seric *p++ = '\0'; 98210327Seric argv[i++] = newstr(q); 9834096Seric } 98410327Seric argv[i++] = NULL; 9854096Seric 98610327Seric /* now make a copy of the argv */ 98710327Seric avp = (char **) xalloc(sizeof *avp * i); 98816893Seric bcopy((char *) argv, (char *) avp, sizeof *avp * i); 98910327Seric 99010327Seric return (avp); 9913308Seric } 9923308Seric /* 9933308Seric ** PRINTRULES -- print rewrite rules (for debugging) 9943308Seric ** 9953308Seric ** Parameters: 9963308Seric ** none. 9973308Seric ** 9983308Seric ** Returns: 9993308Seric ** none. 10003308Seric ** 10013308Seric ** Side Effects: 10023308Seric ** prints rewrite rules. 10033308Seric */ 10043308Seric 10053308Seric printrules() 10063308Seric { 10073308Seric register struct rewrite *rwp; 10084072Seric register int ruleset; 10093308Seric 10104072Seric for (ruleset = 0; ruleset < 10; ruleset++) 10113308Seric { 10124072Seric if (RewriteRules[ruleset] == NULL) 10134072Seric continue; 10148067Seric printf("\n----Rule Set %d:", ruleset); 10153308Seric 10164072Seric for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 10173308Seric { 10188067Seric printf("\nLHS:"); 10198067Seric printav(rwp->r_lhs); 10208067Seric printf("RHS:"); 10218067Seric printav(rwp->r_rhs); 10223308Seric } 10233308Seric } 10243308Seric } 10254319Seric 10264096Seric /* 10278256Seric ** SETOPTION -- set global processing option 10288256Seric ** 10298256Seric ** Parameters: 10308256Seric ** opt -- option name. 10318256Seric ** val -- option value (as a text string). 103221755Seric ** safe -- set if this came from a configuration file. 103321755Seric ** Some options (if set from the command line) will 103421755Seric ** reset the user id to avoid security problems. 10358269Seric ** sticky -- if set, don't let other setoptions override 10368269Seric ** this value. 103758734Seric ** e -- the main envelope. 10388256Seric ** 10398256Seric ** Returns: 10408256Seric ** none. 10418256Seric ** 10428256Seric ** Side Effects: 10438256Seric ** Sets options as implied by the arguments. 10448256Seric */ 10458256Seric 104610687Seric static BITMAP StickyOpt; /* set if option is stuck */ 10478269Seric 104857207Seric 104966334Seric #if NAMED_BIND 105057207Seric 105157207Seric struct resolverflags 105257207Seric { 105357207Seric char *rf_name; /* name of the flag */ 105457207Seric long rf_bits; /* bits to set/clear */ 105557207Seric } ResolverFlags[] = 105657207Seric { 105757207Seric "debug", RES_DEBUG, 105857207Seric "aaonly", RES_AAONLY, 105957207Seric "usevc", RES_USEVC, 106057207Seric "primary", RES_PRIMARY, 106157207Seric "igntc", RES_IGNTC, 106257207Seric "recurse", RES_RECURSE, 106357207Seric "defnames", RES_DEFNAMES, 106457207Seric "stayopen", RES_STAYOPEN, 106557207Seric "dnsrch", RES_DNSRCH, 106665583Seric "true", 0, /* to avoid error on old syntax */ 106757207Seric NULL, 0 106857207Seric }; 106957207Seric 107057207Seric #endif 107157207Seric 107267614Seric struct optioninfo 107367614Seric { 107467614Seric char *o_name; /* long name of option */ 107567614Seric char o_code; /* short name of option */ 107667614Seric bool o_safe; /* safe for random people to use */ 107767614Seric } OptionTab[] = 107867614Seric { 107967707Seric "SevenBitInput", '7', TRUE, 108067707Seric "EightBitMode", '8', TRUE, 108167707Seric "AliasFile", 'A', FALSE, 108267707Seric "AliasWait", 'a', FALSE, 108367707Seric "BlankSub", 'B', FALSE, 108467707Seric "MinFreeBlocks", 'b', TRUE, 108567707Seric "CheckpointInterval", 'C', TRUE, 108667707Seric "HoldExpensive", 'c', FALSE, 108767707Seric "AutoRebuildAliases", 'D', FALSE, 108867707Seric "DeliveryMode", 'd', TRUE, 108967707Seric "ErrorHeader", 'E', FALSE, 109067707Seric "ErrorMode", 'e', TRUE, 109167707Seric "TempFileMode", 'F', FALSE, 109267707Seric "SaveFromLine", 'f', FALSE, 109367707Seric "MatchGECOS", 'G', FALSE, 109467707Seric "HelpFile", 'H', FALSE, 109567707Seric "MaxHopCount", 'h', FALSE, 109667707Seric "NameServerOptions", 'I', FALSE, 109767707Seric "IgnoreDots", 'i', TRUE, 109867707Seric "ForwardPath", 'J', FALSE, 109967707Seric "SendMimeErrors", 'j', TRUE, 110067707Seric "ConnectionCacheSize", 'k', FALSE, 110167707Seric "ConnectionCacheTimeout", 'K', FALSE, 110267707Seric "UseErrorsTo", 'l', FALSE, 110367707Seric "LogLevel", 'L', FALSE, 110467707Seric "MeToo", 'm', TRUE, 110567707Seric "CheckAliases", 'n', FALSE, 110667707Seric "OldStyleHeaders", 'o', TRUE, 110767707Seric "DaemonPortOptions", 'O', FALSE, 110867707Seric "PrivacyOptions", 'p', TRUE, 110967707Seric "PostmasterCopy", 'P', FALSE, 111067707Seric "QueueFactor", 'q', FALSE, 111167707Seric "QueueDirectory", 'Q', FALSE, 111267707Seric "DontPruneRoutes", 'R', FALSE, 111367711Seric "Timeouts", 'r', TRUE, 111467707Seric "StatusFile", 'S', FALSE, 111567707Seric "SuperSafe", 's', TRUE, 111667707Seric "QueueTimeout", 'T', FALSE, 111767707Seric "TimeZoneSpec", 't', FALSE, 111867707Seric "UserDatabaseSpec", 'U', FALSE, 111967707Seric "DefaultUser", 'u', FALSE, 112067707Seric "FallbackMXhost", 'V', FALSE, 112167707Seric "Verbose", 'v', TRUE, 112267707Seric "TryNullMXList", 'w', TRUE, 112367707Seric "QueueLA", 'x', FALSE, 112467707Seric "RefuseLA", 'X', FALSE, 112567707Seric "RecipientFactor", 'y', FALSE, 112667707Seric "ForkQueueRuns", 'Y', FALSE, 112767707Seric "ClassFactor", 'z', FALSE, 112867707Seric "TimeFactor", 'Z', FALSE, 112967707Seric #define O_BSP 0x80 113067707Seric "BrokenSmtpPeers", O_BSP, TRUE, 113167707Seric #define O_SQBH 0x81 113267707Seric "SortQueueByHost", O_SQBH, TRUE, 113367707Seric #define O_DNICE 0x82 113467707Seric "DeliveryNiceness", O_DNICE, TRUE, 113567707Seric #define O_MQA 0x83 113667707Seric "MinQueueAge", O_MQA, TRUE, 113767707Seric #define O_MHSA 0x84 113867707Seric "MaxHostStatAge", O_MHSA, TRUE, 113967707Seric 114067707Seric NULL, '\0', FALSE, 114167614Seric }; 114267614Seric 114367614Seric 114467614Seric 114558734Seric setoption(opt, val, safe, sticky, e) 114667614Seric u_char opt; 11478256Seric char *val; 114821755Seric bool safe; 11498269Seric bool sticky; 115058734Seric register ENVELOPE *e; 11518256Seric { 115257207Seric register char *p; 115367614Seric register struct optioninfo *o; 11548265Seric extern bool atobool(); 115512633Seric extern time_t convtime(); 115614879Seric extern int QueueLA; 115714879Seric extern int RefuseLA; 115864718Seric extern bool Warn_Q_option; 11598256Seric 1160*67736Seric errno = 0; 116167614Seric if (opt == ' ') 116267614Seric { 116367614Seric /* full word options */ 1164*67736Seric struct optioninfo *sel; 116567614Seric 116667614Seric p = strchr(val, '='); 116767614Seric if (p == NULL) 116867614Seric p = &val[strlen(val)]; 116967614Seric while (*--p == ' ') 117067614Seric continue; 117167614Seric while (*++p == ' ') 117267614Seric *p = '\0'; 117367731Seric if (p == val) 117467731Seric { 117567731Seric syserr("readcf: null option name"); 117667731Seric return; 117767731Seric } 117867614Seric if (*p == '=') 117967614Seric *p++ = '\0'; 118067614Seric while (*p == ' ') 118167614Seric p++; 1182*67736Seric sel = NULL; 118367614Seric for (o = OptionTab; o->o_name != NULL; o++) 118467614Seric { 1185*67736Seric if (strncasecmp(o->o_name, val, strlen(val)) != 0) 1186*67736Seric continue; 1187*67736Seric if (strlen(o->o_name) == strlen(val)) 1188*67736Seric { 1189*67736Seric /* completely specified -- this must be it */ 1190*67736Seric sel = NULL; 119167614Seric break; 1192*67736Seric } 1193*67736Seric if (sel != NULL) 1194*67736Seric break; 1195*67736Seric sel = o; 119667614Seric } 1197*67736Seric if (sel != NULL && o->o_name == NULL) 1198*67736Seric o = sel; 1199*67736Seric else if (o->o_name == NULL) 120067614Seric syserr("readcf: unknown option name %s", val); 1201*67736Seric else if (sel != NULL) 1202*67736Seric { 1203*67736Seric syserr("readcf: ambiguous option name %s (matches %s and %s)", 1204*67736Seric val, sel->o_name, o->o_name); 1205*67736Seric return; 1206*67736Seric } 1207*67736Seric if (strlen(val) != strlen(o->o_name)) 1208*67736Seric { 1209*67736Seric bool oldVerbose = Verbose; 1210*67736Seric 1211*67736Seric Verbose = TRUE; 1212*67736Seric message("Option %s used as abbreviation for %s", 1213*67736Seric val, o->o_name); 1214*67736Seric Verbose = oldVerbose; 1215*67736Seric } 121667614Seric opt = o->o_code; 121767614Seric val = p; 121867614Seric } 121967614Seric else 122067614Seric { 122167614Seric for (o = OptionTab; o->o_name != NULL; o++) 122267614Seric { 122367614Seric if (o->o_code == opt) 122467614Seric break; 122567614Seric } 122667614Seric } 122767614Seric 12288256Seric if (tTd(37, 1)) 122967731Seric { 123067731Seric printf(isascii(opt) && isprint(opt) ? 123167731Seric "setoption %s (%c)=%s" : "setoption %s (0x%x)=%s", 123267614Seric o->o_name == NULL ? "<unknown>" : o->o_name, 123367614Seric opt, val); 123467731Seric } 12358256Seric 12368256Seric /* 12378269Seric ** See if this option is preset for us. 12388256Seric */ 12398256Seric 124059731Seric if (!sticky && bitnset(opt, StickyOpt)) 12418269Seric { 12429341Seric if (tTd(37, 1)) 12439341Seric printf(" (ignored)\n"); 12448269Seric return; 12458269Seric } 12468269Seric 124721755Seric /* 124821755Seric ** Check to see if this option can be specified by this user. 124921755Seric */ 125021755Seric 125163787Seric if (!safe && RealUid == 0) 125221755Seric safe = TRUE; 125367614Seric if (!safe && !o->o_safe) 125421755Seric { 125539111Srick if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 125621755Seric { 125736582Sbostic if (tTd(37, 1)) 125836582Sbostic printf(" (unsafe)"); 125963787Seric if (RealUid != geteuid()) 126036582Sbostic { 126151210Seric if (tTd(37, 1)) 126251210Seric printf("(Resetting uid)"); 126363787Seric (void) setgid(RealGid); 126463787Seric (void) setuid(RealUid); 126536582Sbostic } 126621755Seric } 126721755Seric } 126851210Seric if (tTd(37, 1)) 126917985Seric printf("\n"); 12708269Seric 127167614Seric switch (opt & 0xff) 12728256Seric { 127359709Seric case '7': /* force seven-bit input */ 127467546Seric SevenBitInput = atobool(val); 127552106Seric break; 127652106Seric 127767546Seric case '8': /* handling of 8-bit input */ 127867546Seric switch (*val) 127967546Seric { 128067547Seric case 'r': /* reject 8-bit, don't convert MIME */ 128167546Seric MimeMode = 0; 128267546Seric break; 128367546Seric 128467547Seric case 'm': /* convert 8-bit, convert MIME */ 128567546Seric MimeMode = MM_CVTMIME|MM_MIME8BIT; 128667546Seric break; 128767546Seric 128867547Seric case 'j': /* "just send 8" */ 128967546Seric MimeMode = MM_PASS8BIT; 129067546Seric break; 129167546Seric 129267546Seric case 'p': /* pass 8 bit, convert MIME */ 129367546Seric MimeMode = MM_PASS8BIT|MM_CVTMIME; 129467546Seric break; 129567546Seric 129667546Seric case 's': /* strict adherence */ 129767546Seric MimeMode = MM_CVTMIME; 129867546Seric break; 129967546Seric 130067547Seric case 'a': /* encode 8 bit if available */ 130167546Seric MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 130267546Seric break; 130367546Seric 130467547Seric case 'c': /* convert 8 bit to MIME, never 7 bit */ 130567547Seric MimeMode = MM_MIME8BIT; 130667547Seric break; 130767547Seric 130867546Seric default: 130967546Seric syserr("Unknown 8-bit mode %c", *val); 131067546Seric exit(EX_USAGE); 131167546Seric } 131267546Seric break; 131367546Seric 13148256Seric case 'A': /* set default alias file */ 13159381Seric if (val[0] == '\0') 131659672Seric setalias("aliases"); 13179381Seric else 131859672Seric setalias(val); 13198256Seric break; 13208256Seric 132117474Seric case 'a': /* look N minutes for "@:@" in alias file */ 132217474Seric if (val[0] == '\0') 132364796Seric SafeAlias = 5 * 60; /* five minutes */ 132417474Seric else 132564796Seric SafeAlias = convtime(val, 'm'); 132617474Seric break; 132717474Seric 132816843Seric case 'B': /* substitution for blank character */ 132916843Seric SpaceSub = val[0]; 133016843Seric if (SpaceSub == '\0') 133116843Seric SpaceSub = ' '; 133216843Seric break; 133316843Seric 133459283Seric case 'b': /* min blocks free on queue fs/max msg size */ 133559283Seric p = strchr(val, '/'); 133659283Seric if (p != NULL) 133759283Seric { 133859283Seric *p++ = '\0'; 133959283Seric MaxMessageSize = atol(p); 134059283Seric } 134158082Seric MinBlocksFree = atol(val); 134258082Seric break; 134358082Seric 13449284Seric case 'c': /* don't connect to "expensive" mailers */ 13459381Seric NoConnect = atobool(val); 13469284Seric break; 13479284Seric 134851305Seric case 'C': /* checkpoint every N addresses */ 134951305Seric CheckpointInterval = atoi(val); 135024944Seric break; 135124944Seric 13529284Seric case 'd': /* delivery mode */ 13539284Seric switch (*val) 13548269Seric { 13559284Seric case '\0': 135658734Seric e->e_sendmode = SM_DELIVER; 13578269Seric break; 13588269Seric 135910755Seric case SM_QUEUE: /* queue only */ 136010755Seric #ifndef QUEUE 136110755Seric syserr("need QUEUE to set -odqueue"); 136256795Seric #endif /* QUEUE */ 136310755Seric /* fall through..... */ 136410755Seric 13659284Seric case SM_DELIVER: /* do everything */ 13669284Seric case SM_FORK: /* fork after verification */ 136758734Seric e->e_sendmode = *val; 13688269Seric break; 13698269Seric 13708269Seric default: 13719284Seric syserr("Unknown delivery mode %c", *val); 13728269Seric exit(EX_USAGE); 13738269Seric } 13748269Seric break; 13758269Seric 13769146Seric case 'D': /* rebuild alias database as needed */ 13779381Seric AutoRebuild = atobool(val); 13789146Seric break; 13799146Seric 138055372Seric case 'E': /* error message header/header file */ 138155379Seric if (*val != '\0') 138255379Seric ErrMsgFile = newstr(val); 138355372Seric break; 138455372Seric 13858269Seric case 'e': /* set error processing mode */ 13868269Seric switch (*val) 13878269Seric { 13889381Seric case EM_QUIET: /* be silent about it */ 13899381Seric case EM_MAIL: /* mail back */ 13909381Seric case EM_BERKNET: /* do berknet error processing */ 13919381Seric case EM_WRITE: /* write back (or mail) */ 13929381Seric case EM_PRINT: /* print errors normally (default) */ 139358734Seric e->e_errormode = *val; 13948269Seric break; 13958269Seric } 13968269Seric break; 13978269Seric 13989049Seric case 'F': /* file mode */ 139917975Seric FileMode = atooct(val) & 0777; 14009049Seric break; 14019049Seric 14028269Seric case 'f': /* save Unix-style From lines on front */ 14039381Seric SaveFrom = atobool(val); 14048269Seric break; 14058269Seric 140653735Seric case 'G': /* match recipients against GECOS field */ 140753735Seric MatchGecos = atobool(val); 140853735Seric break; 140953735Seric 14108256Seric case 'g': /* default gid */ 141164133Seric if (isascii(*val) && isdigit(*val)) 141264133Seric DefGid = atoi(val); 141364133Seric else 141464133Seric { 141564133Seric register struct group *gr; 141664133Seric 141764133Seric DefGid = -1; 141864133Seric gr = getgrnam(val); 141964133Seric if (gr == NULL) 142064133Seric syserr("readcf: option g: unknown group %s", val); 142164133Seric else 142264133Seric DefGid = gr->gr_gid; 142364133Seric } 14248256Seric break; 14258256Seric 14268256Seric case 'H': /* help file */ 14279381Seric if (val[0] == '\0') 14288269Seric HelpFile = "sendmail.hf"; 14299381Seric else 14309381Seric HelpFile = newstr(val); 14318256Seric break; 14328256Seric 143351305Seric case 'h': /* maximum hop count */ 143451305Seric MaxHopCount = atoi(val); 143551305Seric break; 143651305Seric 143735651Seric case 'I': /* use internet domain name server */ 143866334Seric #if NAMED_BIND 143957207Seric UseNameServer = TRUE; 144057207Seric for (p = val; *p != 0; ) 144157207Seric { 144257207Seric bool clearmode; 144357207Seric char *q; 144457207Seric struct resolverflags *rfp; 144557207Seric 144657207Seric while (*p == ' ') 144757207Seric p++; 144857207Seric if (*p == '\0') 144957207Seric break; 145057207Seric clearmode = FALSE; 145157207Seric if (*p == '-') 145257207Seric clearmode = TRUE; 145357207Seric else if (*p != '+') 145457207Seric p--; 145557207Seric p++; 145657207Seric q = p; 145758050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 145857207Seric p++; 145957207Seric if (*p != '\0') 146057207Seric *p++ = '\0'; 146157207Seric for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 146257207Seric { 146357207Seric if (strcasecmp(q, rfp->rf_name) == 0) 146457207Seric break; 146557207Seric } 146664923Seric if (rfp->rf_name == NULL) 146764923Seric syserr("readcf: I option value %s unrecognized", q); 146864923Seric else if (clearmode) 146957207Seric _res.options &= ~rfp->rf_bits; 147057207Seric else 147157207Seric _res.options |= rfp->rf_bits; 147257207Seric } 147357207Seric if (tTd(8, 2)) 147457207Seric printf("_res.options = %x\n", _res.options); 147557207Seric #else 147657207Seric usrerr("name server (I option) specified but BIND not compiled in"); 147757207Seric #endif 147835651Seric break; 147935651Seric 14808269Seric case 'i': /* ignore dot lines in message */ 14819381Seric IgnrDot = atobool(val); 14828269Seric break; 14838269Seric 148459730Seric case 'j': /* send errors in MIME (RFC 1341) format */ 148559730Seric SendMIMEErrors = atobool(val); 148659730Seric break; 148759730Seric 148857136Seric case 'J': /* .forward search path */ 148957136Seric ForwardPath = newstr(val); 149057136Seric break; 149157136Seric 149254967Seric case 'k': /* connection cache size */ 149354967Seric MaxMciCache = atoi(val); 149456215Seric if (MaxMciCache < 0) 149556215Seric MaxMciCache = 0; 149654967Seric break; 149754967Seric 149854967Seric case 'K': /* connection cache timeout */ 149958796Seric MciCacheTimeout = convtime(val, 'm'); 150054967Seric break; 150154967Seric 150261104Seric case 'l': /* use Errors-To: header */ 150361104Seric UseErrorsTo = atobool(val); 150461104Seric break; 150561104Seric 15068256Seric case 'L': /* log level */ 150764140Seric if (safe || LogLevel < atoi(val)) 150864140Seric LogLevel = atoi(val); 15098256Seric break; 15108256Seric 15118269Seric case 'M': /* define macro */ 15129381Seric define(val[0], newstr(&val[1]), CurEnv); 151316878Seric sticky = FALSE; 15148269Seric break; 15158269Seric 15168269Seric case 'm': /* send to me too */ 15179381Seric MeToo = atobool(val); 15188269Seric break; 15198269Seric 152025820Seric case 'n': /* validate RHS in newaliases */ 152125820Seric CheckAliases = atobool(val); 152225820Seric break; 152325820Seric 152461104Seric /* 'N' available -- was "net name" */ 152561104Seric 152658851Seric case 'O': /* daemon options */ 152758851Seric setdaemonoptions(val); 152858851Seric break; 152958851Seric 15308269Seric case 'o': /* assume old style headers */ 15319381Seric if (atobool(val)) 15329341Seric CurEnv->e_flags |= EF_OLDSTYLE; 15339341Seric else 15349341Seric CurEnv->e_flags &= ~EF_OLDSTYLE; 15358269Seric break; 15368269Seric 153758082Seric case 'p': /* select privacy level */ 153858082Seric p = val; 153958082Seric for (;;) 154058082Seric { 154158082Seric register struct prival *pv; 154258082Seric extern struct prival PrivacyValues[]; 154358082Seric 154458082Seric while (isascii(*p) && (isspace(*p) || ispunct(*p))) 154558082Seric p++; 154658082Seric if (*p == '\0') 154758082Seric break; 154858082Seric val = p; 154958082Seric while (isascii(*p) && isalnum(*p)) 155058082Seric p++; 155158082Seric if (*p != '\0') 155258082Seric *p++ = '\0'; 155358082Seric 155458082Seric for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 155558082Seric { 155658082Seric if (strcasecmp(val, pv->pv_name) == 0) 155758082Seric break; 155858082Seric } 155958886Seric if (pv->pv_name == NULL) 156058886Seric syserr("readcf: Op line: %s unrecognized", val); 156158082Seric PrivacyFlags |= pv->pv_flag; 156258082Seric } 156358082Seric break; 156458082Seric 156524944Seric case 'P': /* postmaster copy address for returned mail */ 156624944Seric PostMasterCopy = newstr(val); 156724944Seric break; 156824944Seric 156924944Seric case 'q': /* slope of queue only function */ 157024944Seric QueueFactor = atoi(val); 157124944Seric break; 157224944Seric 15738256Seric case 'Q': /* queue directory */ 15749381Seric if (val[0] == '\0') 15758269Seric QueueDir = "mqueue"; 15769381Seric else 15779381Seric QueueDir = newstr(val); 157858789Seric if (RealUid != 0 && !safe) 157964718Seric Warn_Q_option = TRUE; 15808256Seric break; 15818256Seric 158258148Seric case 'R': /* don't prune routes */ 158358148Seric DontPruneRoutes = atobool(val); 158458148Seric break; 158558148Seric 15868256Seric case 'r': /* read timeout */ 158758112Seric settimeouts(val); 15888256Seric break; 15898256Seric 15908256Seric case 'S': /* status file */ 15919381Seric if (val[0] == '\0') 15928269Seric StatFile = "sendmail.st"; 15939381Seric else 15949381Seric StatFile = newstr(val); 15958256Seric break; 15968256Seric 15978265Seric case 's': /* be super safe, even if expensive */ 15989381Seric SuperSafe = atobool(val); 15998256Seric break; 16008256Seric 16018256Seric case 'T': /* queue timeout */ 160258737Seric p = strchr(val, '/'); 160358737Seric if (p != NULL) 160458737Seric { 160558737Seric *p++ = '\0'; 160667730Seric TimeOuts.to_q_warning[TOC_NORMAL] = convtime(p, 'd'); 160758737Seric } 160867730Seric TimeOuts.to_q_return[TOC_NORMAL] = convtime(val, 'h'); 160954967Seric break; 16108256Seric 16118265Seric case 't': /* time zone name */ 161252106Seric TimeZoneSpec = newstr(val); 16138265Seric break; 16148265Seric 161550556Seric case 'U': /* location of user database */ 161651360Seric UdbSpec = newstr(val); 161750556Seric break; 161850556Seric 16198256Seric case 'u': /* set default uid */ 162064133Seric if (isascii(*val) && isdigit(*val)) 162164133Seric DefUid = atoi(val); 162264133Seric else 162364133Seric { 162464133Seric register struct passwd *pw; 162564133Seric 162664133Seric DefUid = -1; 162764133Seric pw = getpwnam(val); 162864133Seric if (pw == NULL) 162964133Seric syserr("readcf: option u: unknown user %s", val); 163064133Seric else 163164133Seric DefUid = pw->pw_uid; 163264133Seric } 163340973Sbostic setdefuser(); 16348256Seric break; 16358256Seric 163658851Seric case 'V': /* fallback MX host */ 163758851Seric FallBackMX = newstr(val); 163858851Seric break; 163958851Seric 16408269Seric case 'v': /* run in verbose mode */ 16419381Seric Verbose = atobool(val); 16428256Seric break; 16438256Seric 164463837Seric case 'w': /* if we are best MX, try host directly */ 164563837Seric TryNullMXList = atobool(val); 164663837Seric break; 164761104Seric 164861104Seric /* 'W' available -- was wizard password */ 164961104Seric 165014879Seric case 'x': /* load avg at which to auto-queue msgs */ 165114879Seric QueueLA = atoi(val); 165214879Seric break; 165314879Seric 165414879Seric case 'X': /* load avg at which to auto-reject connections */ 165514879Seric RefuseLA = atoi(val); 165614879Seric break; 165714879Seric 165824981Seric case 'y': /* work recipient factor */ 165924981Seric WkRecipFact = atoi(val); 166024981Seric break; 166124981Seric 166224981Seric case 'Y': /* fork jobs during queue runs */ 166324952Seric ForkQueueRuns = atobool(val); 166424952Seric break; 166524952Seric 166624981Seric case 'z': /* work message class factor */ 166724981Seric WkClassFact = atoi(val); 166824981Seric break; 166924981Seric 167024981Seric case 'Z': /* work time factor */ 167124981Seric WkTimeFact = atoi(val); 167224981Seric break; 167324981Seric 167467614Seric case O_BSP: /* SMTP Peers can't handle 2-line greeting */ 167567614Seric BrokenSmtpPeers = atobool(val); 167667614Seric break; 167767614Seric 167867614Seric case O_SQBH: /* sort work queue by host first */ 167967614Seric SortQueueByHost = atobool(val); 168067614Seric break; 168167614Seric 168267707Seric case O_DNICE: /* delivery nice value */ 168367707Seric DeliveryNiceness = atoi(val); 168467707Seric break; 168567707Seric 168667707Seric case O_MQA: /* minimum queue age between deliveries */ 168767707Seric MinQueueAge = convtime(val, 'm'); 168867707Seric break; 168967707Seric 169067707Seric case O_MHSA: /* maximum age of cached host status */ 169167707Seric MaxHostStatAge = convtime(val, 'm'); 169267707Seric break; 169367707Seric 16948256Seric default: 16958256Seric break; 16968256Seric } 169716878Seric if (sticky) 169816878Seric setbitn(opt, StickyOpt); 16999188Seric return; 17008256Seric } 170110687Seric /* 170210687Seric ** SETCLASS -- set a word into a class 170310687Seric ** 170410687Seric ** Parameters: 170510687Seric ** class -- the class to put the word in. 170610687Seric ** word -- the word to enter 170710687Seric ** 170810687Seric ** Returns: 170910687Seric ** none. 171010687Seric ** 171110687Seric ** Side Effects: 171210687Seric ** puts the word into the symbol table. 171310687Seric */ 171410687Seric 171510687Seric setclass(class, word) 171610687Seric int class; 171710687Seric char *word; 171810687Seric { 171910687Seric register STAB *s; 172010687Seric 172157943Seric if (tTd(37, 8)) 172264326Seric printf("setclass(%c, %s)\n", class, word); 172310687Seric s = stab(word, ST_CLASS, ST_ENTER); 172410687Seric setbitn(class, s->s_class); 172510687Seric } 172653654Seric /* 172753654Seric ** MAKEMAPENTRY -- create a map entry 172853654Seric ** 172953654Seric ** Parameters: 173053654Seric ** line -- the config file line 173153654Seric ** 173253654Seric ** Returns: 173353654Seric ** TRUE if it successfully entered the map entry. 173453654Seric ** FALSE otherwise (usually syntax error). 173553654Seric ** 173653654Seric ** Side Effects: 173753654Seric ** Enters the map into the dictionary. 173853654Seric */ 173953654Seric 174053654Seric void 174153654Seric makemapentry(line) 174253654Seric char *line; 174353654Seric { 174453654Seric register char *p; 174553654Seric char *mapname; 174653654Seric char *classname; 174764078Seric register STAB *s; 174853654Seric STAB *class; 174953654Seric 175058050Seric for (p = line; isascii(*p) && isspace(*p); p++) 175153654Seric continue; 175258050Seric if (!(isascii(*p) && isalnum(*p))) 175353654Seric { 175453654Seric syserr("readcf: config K line: no map name"); 175553654Seric return; 175653654Seric } 175753654Seric 175853654Seric mapname = p; 175958050Seric while (isascii(*++p) && isalnum(*p)) 176053654Seric continue; 176153654Seric if (*p != '\0') 176253654Seric *p++ = '\0'; 176358050Seric while (isascii(*p) && isspace(*p)) 176453654Seric p++; 176558050Seric if (!(isascii(*p) && isalnum(*p))) 176653654Seric { 176753654Seric syserr("readcf: config K line, map %s: no map class", mapname); 176853654Seric return; 176953654Seric } 177053654Seric classname = p; 177158050Seric while (isascii(*++p) && isalnum(*p)) 177253654Seric continue; 177353654Seric if (*p != '\0') 177453654Seric *p++ = '\0'; 177558050Seric while (isascii(*p) && isspace(*p)) 177653654Seric p++; 177753654Seric 177853654Seric /* look up the class */ 177953654Seric class = stab(classname, ST_MAPCLASS, ST_FIND); 178053654Seric if (class == NULL) 178153654Seric { 178253654Seric syserr("readcf: map %s: class %s not available", mapname, classname); 178353654Seric return; 178453654Seric } 178553654Seric 178653654Seric /* enter the map */ 178764078Seric s = stab(mapname, ST_MAP, ST_ENTER); 178864078Seric s->s_map.map_class = &class->s_mapclass; 178964078Seric s->s_map.map_mname = newstr(mapname); 179053654Seric 179164078Seric if (class->s_mapclass.map_parse(&s->s_map, p)) 179264078Seric s->s_map.map_mflags |= MF_VALID; 179364078Seric 179464078Seric if (tTd(37, 5)) 179564078Seric { 179664078Seric printf("map %s, class %s, flags %x, file %s,\n", 179764078Seric s->s_map.map_mname, s->s_map.map_class->map_cname, 179864078Seric s->s_map.map_mflags, 179964078Seric s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 180064078Seric printf("\tapp %s, domain %s, rebuild %s\n", 180164078Seric s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 180264078Seric s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 180364078Seric s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 180464078Seric } 180553654Seric } 180658112Seric /* 180758112Seric ** SETTIMEOUTS -- parse and set timeout values 180858112Seric ** 180958112Seric ** Parameters: 181058112Seric ** val -- a pointer to the values. If NULL, do initial 181158112Seric ** settings. 181258112Seric ** 181358112Seric ** Returns: 181458112Seric ** none. 181558112Seric ** 181658112Seric ** Side Effects: 181758112Seric ** Initializes the TimeOuts structure 181858112Seric */ 181958112Seric 182064255Seric #define SECONDS 182158112Seric #define MINUTES * 60 182258112Seric #define HOUR * 3600 182358112Seric 182458112Seric settimeouts(val) 182558112Seric register char *val; 182658112Seric { 182758112Seric register char *p; 182858671Seric extern time_t convtime(); 182958112Seric 183058112Seric if (val == NULL) 183158112Seric { 183258112Seric TimeOuts.to_initial = (time_t) 5 MINUTES; 183358112Seric TimeOuts.to_helo = (time_t) 5 MINUTES; 183458112Seric TimeOuts.to_mail = (time_t) 10 MINUTES; 183558112Seric TimeOuts.to_rcpt = (time_t) 1 HOUR; 183658112Seric TimeOuts.to_datainit = (time_t) 5 MINUTES; 183758112Seric TimeOuts.to_datablock = (time_t) 1 HOUR; 183858112Seric TimeOuts.to_datafinal = (time_t) 1 HOUR; 183958112Seric TimeOuts.to_rset = (time_t) 5 MINUTES; 184058112Seric TimeOuts.to_quit = (time_t) 2 MINUTES; 184158112Seric TimeOuts.to_nextcommand = (time_t) 1 HOUR; 184258112Seric TimeOuts.to_miscshort = (time_t) 2 MINUTES; 184364255Seric TimeOuts.to_ident = (time_t) 30 SECONDS; 184467711Seric TimeOuts.to_fileopen = (time_t) 60 SECONDS; 184558112Seric return; 184658112Seric } 184758112Seric 184858112Seric for (;; val = p) 184958112Seric { 185058112Seric while (isascii(*val) && isspace(*val)) 185158112Seric val++; 185258112Seric if (*val == '\0') 185358112Seric break; 185458112Seric for (p = val; *p != '\0' && *p != ','; p++) 185558112Seric continue; 185658112Seric if (*p != '\0') 185758112Seric *p++ = '\0'; 185858112Seric 185958112Seric if (isascii(*val) && isdigit(*val)) 186058112Seric { 186158112Seric /* old syntax -- set everything */ 186258796Seric TimeOuts.to_mail = convtime(val, 'm'); 186358112Seric TimeOuts.to_rcpt = TimeOuts.to_mail; 186458112Seric TimeOuts.to_datainit = TimeOuts.to_mail; 186558112Seric TimeOuts.to_datablock = TimeOuts.to_mail; 186658112Seric TimeOuts.to_datafinal = TimeOuts.to_mail; 186758112Seric TimeOuts.to_nextcommand = TimeOuts.to_mail; 186858112Seric continue; 186958112Seric } 187058112Seric else 187158112Seric { 187267711Seric register char *q = strchr(val, ':'); 187358112Seric time_t to; 187458112Seric 187567711Seric if (q == NULL && (q = strchr(val, '=')) == NULL) 187658112Seric { 187758112Seric /* syntax error */ 187858112Seric continue; 187958112Seric } 188058112Seric *q++ = '\0'; 188158796Seric to = convtime(q, 'm'); 188258112Seric 188358112Seric if (strcasecmp(val, "initial") == 0) 188458112Seric TimeOuts.to_initial = to; 188558112Seric else if (strcasecmp(val, "mail") == 0) 188658112Seric TimeOuts.to_mail = to; 188758112Seric else if (strcasecmp(val, "rcpt") == 0) 188858112Seric TimeOuts.to_rcpt = to; 188958112Seric else if (strcasecmp(val, "datainit") == 0) 189058112Seric TimeOuts.to_datainit = to; 189158112Seric else if (strcasecmp(val, "datablock") == 0) 189258112Seric TimeOuts.to_datablock = to; 189358112Seric else if (strcasecmp(val, "datafinal") == 0) 189458112Seric TimeOuts.to_datafinal = to; 189558112Seric else if (strcasecmp(val, "command") == 0) 189658112Seric TimeOuts.to_nextcommand = to; 189758112Seric else if (strcasecmp(val, "rset") == 0) 189858112Seric TimeOuts.to_rset = to; 189958112Seric else if (strcasecmp(val, "helo") == 0) 190058112Seric TimeOuts.to_helo = to; 190158112Seric else if (strcasecmp(val, "quit") == 0) 190258112Seric TimeOuts.to_quit = to; 190358112Seric else if (strcasecmp(val, "misc") == 0) 190458112Seric TimeOuts.to_miscshort = to; 190564255Seric else if (strcasecmp(val, "ident") == 0) 190664255Seric TimeOuts.to_ident = to; 190767711Seric else if (strcasecmp(val, "fileopen") == 0) 190867711Seric TimeOuts.to_fileopen = to; 190967711Seric else if (strcasecmp(val, "queuewarn") == 0) 191067730Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 191167711Seric else if (strcasecmp(val, "queuereturn") == 0) 191267730Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 191367730Seric else if (strcasecmp(val, "queuewarn.normal") == 0) 191467730Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 191567730Seric else if (strcasecmp(val, "queuereturn.normal") == 0) 191667730Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 191767730Seric else if (strcasecmp(val, "queuewarn.urgent") == 0) 191867730Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 191967730Seric else if (strcasecmp(val, "queuereturn.urgent") == 0) 192067730Seric TimeOuts.to_q_return[TOC_URGENT] = to; 192167730Seric else if (strcasecmp(val, "queuewarn.non-urgent") == 0) 192267730Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 192367730Seric else if (strcasecmp(val, "queuereturn.non-urgent") == 0) 192467730Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 192558112Seric else 192658112Seric syserr("settimeouts: invalid timeout %s", val); 192758112Seric } 192858112Seric } 192958112Seric } 1930