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*67787Seric static char sccsid[] = "@(#)readcf.c 8.39 (Berkeley) 10/08/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]; 8710709Seric extern char *munchstring(); 8853654Seric extern void makemapentry(); 893308Seric 9052647Seric FileName = cfname; 9152647Seric LineNumber = 0; 9252647Seric 933308Seric cf = fopen(cfname, "r"); 943308Seric if (cf == NULL) 953308Seric { 9652647Seric syserr("cannot open"); 973308Seric exit(EX_OSFILE); 983308Seric } 993308Seric 10052647Seric if (fstat(fileno(cf), &statb) < 0) 10152647Seric { 10252647Seric syserr("cannot fstat"); 10352647Seric exit(EX_OSFILE); 10452647Seric } 10552647Seric 10652647Seric if (!S_ISREG(statb.st_mode)) 10752647Seric { 10852647Seric syserr("not a plain file"); 10952647Seric exit(EX_OSFILE); 11052647Seric } 11152647Seric 11252647Seric if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode)) 11352647Seric { 11453037Seric if (OpMode == MD_DAEMON || OpMode == MD_FREEZE) 11553037Seric fprintf(stderr, "%s: WARNING: dangerous write permissions\n", 11653037Seric FileName); 11753037Seric #ifdef LOG 11853037Seric if (LogLevel > 0) 11953037Seric syslog(LOG_CRIT, "%s: WARNING: dangerous write permissions", 12053037Seric FileName); 12153037Seric #endif 12252647Seric } 12352647Seric 12459254Seric #ifdef XLA 12559254Seric xla_zero(); 12659254Seric #endif 12759254Seric 12857135Seric while ((bp = fgetfolded(buf, sizeof buf, cf)) != NULL) 1293308Seric { 13057135Seric if (bp[0] == '#') 13157135Seric { 13257135Seric if (bp != buf) 13357135Seric free(bp); 13452637Seric continue; 13557135Seric } 13652637Seric 13767769Seric /* do macro expansion mappings */ 13857135Seric for (p = bp; *p != '\0'; p++) 13916157Seric { 14057135Seric if (*p == '#' && p > bp && ConfigLevel >= 3) 14152647Seric { 14252647Seric /* this is an on-line comment */ 14352647Seric register char *e; 14452647Seric 14558050Seric switch (*--p & 0377) 14652647Seric { 14758050Seric case MACROEXPAND: 14852647Seric /* it's from $# -- let it go through */ 14952647Seric p++; 15052647Seric break; 15152647Seric 15252647Seric case '\\': 15352647Seric /* it's backslash escaped */ 15452647Seric (void) strcpy(p, p + 1); 15552647Seric break; 15652647Seric 15752647Seric default: 15852647Seric /* delete preceeding white space */ 15958050Seric while (isascii(*p) && isspace(*p) && p > bp) 16052647Seric p--; 16156795Seric if ((e = strchr(++p, '\n')) != NULL) 16252647Seric (void) strcpy(p, e); 16352647Seric else 16452647Seric p[0] = p[1] = '\0'; 16552647Seric break; 16652647Seric } 16752647Seric continue; 16852647Seric } 16952647Seric 17067769Seric if (*p != '$' || p[1] == '\0') 17116157Seric continue; 17216157Seric 17316157Seric if (p[1] == '$') 17416157Seric { 17516157Seric /* actual dollar sign.... */ 17623111Seric (void) strcpy(p, p + 1); 17716157Seric continue; 17816157Seric } 17916157Seric 18016157Seric /* convert to macro expansion character */ 18167769Seric *p++ = MACROEXPAND; 18267769Seric 18367769Seric /* convert macro name to code */ 18467769Seric *p = macid(p, &ep); 18567769Seric if (ep != p) 18667769Seric strcpy(p + 1, ep); 18716157Seric } 18816157Seric 18916157Seric /* interpret this line */ 19064718Seric errno = 0; 19157135Seric switch (bp[0]) 1923308Seric { 1933308Seric case '\0': 1943308Seric case '#': /* comment */ 1953308Seric break; 1963308Seric 1973308Seric case 'R': /* rewriting rule */ 19857135Seric for (p = &bp[1]; *p != '\0' && *p != '\t'; p++) 1993308Seric continue; 2003308Seric 2013308Seric if (*p == '\0') 2025909Seric { 20365821Seric syserr("invalid rewrite line \"%s\" (tab expected)", bp); 2045909Seric break; 2055909Seric } 2065909Seric 2075909Seric /* allocate space for the rule header */ 2085909Seric if (rwp == NULL) 2095909Seric { 2105909Seric RewriteRules[ruleset] = rwp = 2115909Seric (struct rewrite *) xalloc(sizeof *rwp); 2125909Seric } 2133308Seric else 2143308Seric { 2155909Seric rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp); 2165909Seric rwp = rwp->r_next; 2175909Seric } 2185909Seric rwp->r_next = NULL; 2193308Seric 2205909Seric /* expand and save the LHS */ 2215909Seric *p = '\0'; 22257135Seric expand(&bp[1], exbuf, &exbuf[sizeof exbuf], e); 22365066Seric rwp->r_lhs = prescan(exbuf, '\t', pvpbuf, 22465066Seric sizeof pvpbuf, NULL); 22557589Seric nfuzzy = 0; 2265909Seric if (rwp->r_lhs != NULL) 22757589Seric { 22857589Seric register char **ap; 22957589Seric 2305909Seric rwp->r_lhs = copyplist(rwp->r_lhs, TRUE); 23157589Seric 23257589Seric /* count the number of fuzzy matches in LHS */ 23357589Seric for (ap = rwp->r_lhs; *ap != NULL; ap++) 23457589Seric { 23558148Seric char *botch; 23658148Seric 23758148Seric botch = NULL; 23858050Seric switch (**ap & 0377) 23957589Seric { 24057589Seric case MATCHZANY: 24157589Seric case MATCHANY: 24257589Seric case MATCHONE: 24357589Seric case MATCHCLASS: 24457589Seric case MATCHNCLASS: 24557589Seric nfuzzy++; 24658148Seric break; 24758148Seric 24858148Seric case MATCHREPL: 24958148Seric botch = "$0-$9"; 25058148Seric break; 25158148Seric 25258148Seric case CANONNET: 25358148Seric botch = "$#"; 25458148Seric break; 25558148Seric 25658148Seric case CANONUSER: 25758148Seric botch = "$:"; 25858148Seric break; 25958148Seric 26058148Seric case CALLSUBR: 26158148Seric botch = "$>"; 26258148Seric break; 26358148Seric 26458148Seric case CONDIF: 26558148Seric botch = "$?"; 26658148Seric break; 26758148Seric 26858148Seric case CONDELSE: 26958148Seric botch = "$|"; 27058148Seric break; 27158148Seric 27258148Seric case CONDFI: 27358148Seric botch = "$."; 27458148Seric break; 27558148Seric 27658148Seric case HOSTBEGIN: 27758148Seric botch = "$["; 27858148Seric break; 27958148Seric 28058148Seric case HOSTEND: 28158148Seric botch = "$]"; 28258148Seric break; 28358148Seric 28458148Seric case LOOKUPBEGIN: 28558148Seric botch = "$("; 28658148Seric break; 28758148Seric 28858148Seric case LOOKUPEND: 28958148Seric botch = "$)"; 29058148Seric break; 29157589Seric } 29258148Seric if (botch != NULL) 29358148Seric syserr("Inappropriate use of %s on LHS", 29458148Seric botch); 29557589Seric } 29657589Seric } 29756678Seric else 29856678Seric syserr("R line: null LHS"); 2995909Seric 3005909Seric /* expand and save the RHS */ 3015909Seric while (*++p == '\t') 3025909Seric continue; 3037231Seric q = p; 3047231Seric while (*p != '\0' && *p != '\t') 3057231Seric p++; 3067231Seric *p = '\0'; 30755012Seric expand(q, exbuf, &exbuf[sizeof exbuf], e); 30865066Seric rwp->r_rhs = prescan(exbuf, '\t', pvpbuf, 30965066Seric sizeof pvpbuf, NULL); 3105909Seric if (rwp->r_rhs != NULL) 31157589Seric { 31257589Seric register char **ap; 31357589Seric 3145909Seric rwp->r_rhs = copyplist(rwp->r_rhs, TRUE); 31557589Seric 31657589Seric /* check no out-of-bounds replacements */ 31757589Seric nfuzzy += '0'; 31857589Seric for (ap = rwp->r_rhs; *ap != NULL; ap++) 31957589Seric { 32058148Seric char *botch; 32158148Seric 32258148Seric botch = NULL; 32358148Seric switch (**ap & 0377) 32457589Seric { 32558148Seric case MATCHREPL: 32658148Seric if ((*ap)[1] <= '0' || (*ap)[1] > nfuzzy) 32758148Seric { 32858148Seric syserr("replacement $%c out of bounds", 32958148Seric (*ap)[1]); 33058148Seric } 33158148Seric break; 33258148Seric 33358148Seric case MATCHZANY: 33458148Seric botch = "$*"; 33558148Seric break; 33658148Seric 33758148Seric case MATCHANY: 33858148Seric botch = "$+"; 33958148Seric break; 34058148Seric 34158148Seric case MATCHONE: 34258148Seric botch = "$-"; 34358148Seric break; 34458148Seric 34558148Seric case MATCHCLASS: 34658148Seric botch = "$="; 34758148Seric break; 34858148Seric 34958148Seric case MATCHNCLASS: 35058148Seric botch = "$~"; 35158148Seric break; 35257589Seric } 35358148Seric if (botch != NULL) 35458148Seric syserr("Inappropriate use of %s on RHS", 35558148Seric botch); 35657589Seric } 35757589Seric } 35856678Seric else 35956678Seric syserr("R line: null RHS"); 3603308Seric break; 3613308Seric 3624072Seric case 'S': /* select rewriting set */ 36364440Seric for (p = &bp[1]; isascii(*p) && isspace(*p); p++) 36464440Seric continue; 36564440Seric if (!isascii(*p) || !isdigit(*p)) 36664440Seric { 36764440Seric syserr("invalid argument to S line: \"%.20s\"", 36864440Seric &bp[1]); 36964440Seric break; 37064440Seric } 37164440Seric ruleset = atoi(p); 3728056Seric if (ruleset >= MAXRWSETS || ruleset < 0) 3738056Seric { 3749381Seric syserr("bad ruleset %d (%d max)", ruleset, MAXRWSETS); 3758056Seric ruleset = 0; 3768056Seric } 3774072Seric rwp = NULL; 3784072Seric break; 3794072Seric 3803308Seric case 'D': /* macro definition */ 38167769Seric mid = macid(&bp[1], &ep); 38267769Seric p = munchstring(ep, NULL); 38367769Seric define(mid, newstr(p), e); 3843308Seric break; 3853308Seric 3863387Seric case 'H': /* required header line */ 38757135Seric (void) chompheader(&bp[1], TRUE, e); 3883387Seric break; 3893387Seric 3904061Seric case 'C': /* word class */ 3914432Seric /* scan the list of words and set class for all */ 39267769Seric mid = macid(&bp[1], &ep); 39367769Seric expand(ep, exbuf, &exbuf[sizeof exbuf], e); 39464121Seric for (p = exbuf; *p != '\0'; ) 3954061Seric { 3964061Seric register char *wd; 3974061Seric char delim; 3984061Seric 39958050Seric while (*p != '\0' && isascii(*p) && isspace(*p)) 4004061Seric p++; 4014061Seric wd = p; 40258050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 4034061Seric p++; 4044061Seric delim = *p; 4054061Seric *p = '\0'; 4064061Seric if (wd[0] != '\0') 40767769Seric setclass(mid, wd); 4084061Seric *p = delim; 4094061Seric } 4104061Seric break; 4114061Seric 41259272Seric case 'F': /* word class from file */ 41367769Seric mid = macid(&bp[1], &ep); 41467769Seric for (p = ep; isascii(*p) && isspace(*p); ) 41564133Seric p++; 41664133Seric if (p[0] == '-' && p[1] == 'o') 41764133Seric { 41864133Seric optional = TRUE; 41964133Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 42064133Seric p++; 42164133Seric while (isascii(*p) && isspace(*p)) 42267615Seric p++; 42364133Seric } 42464133Seric else 42564133Seric optional = FALSE; 42664133Seric file = p; 42764133Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 42864133Seric p++; 42959272Seric if (*p == '\0') 43059272Seric p = "%s"; 43159272Seric else 43259272Seric { 43359272Seric *p = '\0'; 43459272Seric while (isascii(*++p) && isspace(*p)) 43559272Seric continue; 43659272Seric } 43764133Seric fileclass(bp[1], file, p, safe, optional); 43859272Seric break; 43959272Seric 44059156Seric #ifdef XLA 44159156Seric case 'L': /* extended load average description */ 44259156Seric xla_init(&bp[1]); 44359156Seric break; 44459156Seric #endif 44559156Seric 4464096Seric case 'M': /* define mailer */ 44757135Seric makemailer(&bp[1]); 4484096Seric break; 4494096Seric 4508252Seric case 'O': /* set option */ 45158734Seric setoption(bp[1], &bp[2], safe, FALSE, e); 4528252Seric break; 4538252Seric 4548252Seric case 'P': /* set precedence */ 4558252Seric if (NumPriorities >= MAXPRIORITIES) 4568252Seric { 4578547Seric toomany('P', MAXPRIORITIES); 4588252Seric break; 4598252Seric } 46057135Seric for (p = &bp[1]; *p != '\0' && *p != '=' && *p != '\t'; p++) 4618252Seric continue; 4628252Seric if (*p == '\0') 4638252Seric goto badline; 4648252Seric *p = '\0'; 46557135Seric Priorities[NumPriorities].pri_name = newstr(&bp[1]); 4668252Seric Priorities[NumPriorities].pri_val = atoi(++p); 4678252Seric NumPriorities++; 4688252Seric break; 4698252Seric 4708547Seric case 'T': /* trusted user(s) */ 47158161Seric /* this option is obsolete, but will be ignored */ 4728547Seric break; 4738547Seric 47452645Seric case 'V': /* configuration syntax version */ 47564440Seric for (p = &bp[1]; isascii(*p) && isspace(*p); p++) 47664440Seric continue; 47764440Seric if (!isascii(*p) || !isdigit(*p)) 47864440Seric { 47964440Seric syserr("invalid argument to V line: \"%.20s\"", 48064440Seric &bp[1]); 48164440Seric break; 48264440Seric } 48364718Seric ConfigLevel = strtol(p, &ep, 10); 48464279Seric if (ConfigLevel >= 5) 48564279Seric { 48664279Seric /* level 5 configs have short name in $w */ 48764279Seric p = macvalue('w', e); 48864279Seric if (p != NULL && (p = strchr(p, '.')) != NULL) 48964279Seric *p = '\0'; 49064279Seric } 49164718Seric if (*ep++ == '/') 49264718Seric { 49364718Seric /* extract vendor code */ 49464718Seric for (p = ep; isascii(*p) && isalpha(*p); ) 49564718Seric p++; 49664718Seric *p = '\0'; 49764718Seric 49864718Seric if (!setvendor(ep)) 49964718Seric syserr("invalid V line vendor code: \"%s\"", 50064718Seric ep); 50164718Seric } 50252645Seric break; 50352645Seric 50453654Seric case 'K': 50557135Seric makemapentry(&bp[1]); 50653654Seric break; 50753654Seric 5083308Seric default: 5094061Seric badline: 51057135Seric syserr("unknown control line \"%s\"", bp); 5113308Seric } 51257135Seric if (bp != buf) 51357135Seric free(bp); 5143308Seric } 51552637Seric if (ferror(cf)) 51652637Seric { 51752647Seric syserr("I/O read error", cfname); 51852637Seric exit(EX_OSFILE); 51952637Seric } 52052637Seric fclose(cf); 5219381Seric FileName = NULL; 52256836Seric 52367730Seric /* initialize host maps from local service tables */ 52467730Seric inithostmaps(); 52567730Seric 52657076Seric if (stab("host", ST_MAP, ST_FIND) == NULL) 52757076Seric { 52857076Seric /* user didn't initialize: set up host map */ 52957076Seric strcpy(buf, "host host"); 53066334Seric #if NAMED_BIND 53157076Seric if (ConfigLevel >= 2) 53257076Seric strcat(buf, " -a."); 53364947Seric #endif 53457076Seric makemapentry(buf); 53557076Seric } 5364096Seric } 5374096Seric /* 5388547Seric ** TOOMANY -- signal too many of some option 5398547Seric ** 5408547Seric ** Parameters: 5418547Seric ** id -- the id of the error line 5428547Seric ** maxcnt -- the maximum possible values 5438547Seric ** 5448547Seric ** Returns: 5458547Seric ** none. 5468547Seric ** 5478547Seric ** Side Effects: 5488547Seric ** gives a syserr. 5498547Seric */ 5508547Seric 5518547Seric toomany(id, maxcnt) 5528547Seric char id; 5538547Seric int maxcnt; 5548547Seric { 5559381Seric syserr("too many %c lines, %d max", id, maxcnt); 5568547Seric } 5578547Seric /* 5584432Seric ** FILECLASS -- read members of a class from a file 5594432Seric ** 5604432Seric ** Parameters: 5614432Seric ** class -- class to define. 5624432Seric ** filename -- name of file to read. 5634432Seric ** fmt -- scanf string to use for match. 56464133Seric ** safe -- if set, this is a safe read. 56564133Seric ** optional -- if set, it is not an error for the file to 56664133Seric ** not exist. 5674432Seric ** 5684432Seric ** Returns: 5694432Seric ** none 5704432Seric ** 5714432Seric ** Side Effects: 5724432Seric ** 5734432Seric ** puts all lines in filename that match a scanf into 5744432Seric ** the named class. 5754432Seric */ 5764432Seric 57764133Seric fileclass(class, filename, fmt, safe, optional) 5784432Seric int class; 5794432Seric char *filename; 5804432Seric char *fmt; 58154973Seric bool safe; 58264133Seric bool optional; 5834432Seric { 58425808Seric FILE *f; 58554973Seric struct stat stbuf; 5864432Seric char buf[MAXLINE]; 5874432Seric 58866101Seric if (tTd(37, 2)) 58966101Seric printf("fileclass(%s, fmt=%s)\n", filename, fmt); 59066101Seric 59166031Seric if (filename[0] == '|') 59266031Seric { 59366031Seric syserr("fileclass: pipes (F%c%s) not supported due to security problems", 59466031Seric class, filename); 59566031Seric return; 59666031Seric } 59754973Seric if (stat(filename, &stbuf) < 0) 59854973Seric { 59966101Seric if (tTd(37, 2)) 60066101Seric printf(" cannot stat (%s)\n", errstring(errno)); 60164133Seric if (!optional) 60264133Seric syserr("fileclass: cannot stat %s", filename); 60354973Seric return; 60454973Seric } 60554973Seric if (!S_ISREG(stbuf.st_mode)) 60654973Seric { 60754973Seric syserr("fileclass: %s not a regular file", filename); 60854973Seric return; 60954973Seric } 61054973Seric if (!safe && access(filename, R_OK) < 0) 61154973Seric { 61254973Seric syserr("fileclass: access denied on %s", filename); 61354973Seric return; 61454973Seric } 61554973Seric f = fopen(filename, "r"); 6164432Seric if (f == NULL) 6174432Seric { 61854973Seric syserr("fileclass: cannot open %s", filename); 6194432Seric return; 6204432Seric } 6214432Seric 6224432Seric while (fgets(buf, sizeof buf, f) != NULL) 6234432Seric { 6244432Seric register STAB *s; 62525808Seric register char *p; 62625808Seric # ifdef SCANF 6274432Seric char wordbuf[MAXNAME+1]; 6284432Seric 6294432Seric if (sscanf(buf, fmt, wordbuf) != 1) 6304432Seric continue; 63125808Seric p = wordbuf; 63256795Seric # else /* SCANF */ 63325808Seric p = buf; 63456795Seric # endif /* SCANF */ 63525808Seric 63625808Seric /* 63725808Seric ** Break up the match into words. 63825808Seric */ 63925808Seric 64025808Seric while (*p != '\0') 64125808Seric { 64225808Seric register char *q; 64325808Seric 64425808Seric /* strip leading spaces */ 64558050Seric while (isascii(*p) && isspace(*p)) 64625808Seric p++; 64725808Seric if (*p == '\0') 64825808Seric break; 64925808Seric 65025808Seric /* find the end of the word */ 65125808Seric q = p; 65258050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 65325808Seric p++; 65425808Seric if (*p != '\0') 65525808Seric *p++ = '\0'; 65625808Seric 65725808Seric /* enter the word in the symbol table */ 65866101Seric setclass(class, q); 65925808Seric } 6604432Seric } 6614432Seric 66254973Seric (void) fclose(f); 6634432Seric } 6644432Seric /* 6654096Seric ** MAKEMAILER -- define a new mailer. 6664096Seric ** 6674096Seric ** Parameters: 66810327Seric ** line -- description of mailer. This is in labeled 66910327Seric ** fields. The fields are: 67010327Seric ** P -- the path to the mailer 67110327Seric ** F -- the flags associated with the mailer 67210327Seric ** A -- the argv for this mailer 67310327Seric ** S -- the sender rewriting set 67410327Seric ** R -- the recipient rewriting set 67510327Seric ** E -- the eol string 67610327Seric ** The first word is the canonical name of the mailer. 6774096Seric ** 6784096Seric ** Returns: 6794096Seric ** none. 6804096Seric ** 6814096Seric ** Side Effects: 6824096Seric ** enters the mailer into the mailer table. 6834096Seric */ 6843308Seric 68521066Seric makemailer(line) 6864096Seric char *line; 6874096Seric { 6884096Seric register char *p; 6898067Seric register struct mailer *m; 6908067Seric register STAB *s; 6918067Seric int i; 69210327Seric char fcode; 69358020Seric auto char *endp; 6944096Seric extern int NextMailer; 69510327Seric extern char **makeargv(); 69610327Seric extern char *munchstring(); 69710701Seric extern long atol(); 6984096Seric 69910327Seric /* allocate a mailer and set up defaults */ 70010327Seric m = (struct mailer *) xalloc(sizeof *m); 70110327Seric bzero((char *) m, sizeof *m); 70210327Seric m->m_eol = "\n"; 70367604Seric m->m_uid = m->m_gid = 0; 70410327Seric 70510327Seric /* collect the mailer name */ 70658050Seric for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++) 70710327Seric continue; 70810327Seric if (*p != '\0') 70910327Seric *p++ = '\0'; 71010327Seric m->m_name = newstr(line); 71110327Seric 71210327Seric /* now scan through and assign info from the fields */ 71310327Seric while (*p != '\0') 71410327Seric { 71558333Seric auto char *delimptr; 71658333Seric 71758050Seric while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p)))) 71810327Seric p++; 71910327Seric 72010327Seric /* p now points to field code */ 72110327Seric fcode = *p; 72210327Seric while (*p != '\0' && *p != '=' && *p != ',') 72310327Seric p++; 72410327Seric if (*p++ != '=') 72510327Seric { 72652637Seric syserr("mailer %s: `=' expected", m->m_name); 72710327Seric return; 72810327Seric } 72958050Seric while (isascii(*p) && isspace(*p)) 73010327Seric p++; 73110327Seric 73210327Seric /* p now points to the field body */ 73358333Seric p = munchstring(p, &delimptr); 73410327Seric 73510327Seric /* install the field into the mailer struct */ 73610327Seric switch (fcode) 73710327Seric { 73810327Seric case 'P': /* pathname */ 73910327Seric m->m_mailer = newstr(p); 74010327Seric break; 74110327Seric 74210327Seric case 'F': /* flags */ 74310687Seric for (; *p != '\0'; p++) 74458050Seric if (!(isascii(*p) && isspace(*p))) 74552637Seric setbitn(*p, m->m_flags); 74610327Seric break; 74710327Seric 74810327Seric case 'S': /* sender rewriting ruleset */ 74910327Seric case 'R': /* recipient rewriting ruleset */ 75058020Seric i = strtol(p, &endp, 10); 75110327Seric if (i < 0 || i >= MAXRWSETS) 75210327Seric { 75310327Seric syserr("invalid rewrite set, %d max", MAXRWSETS); 75410327Seric return; 75510327Seric } 75610327Seric if (fcode == 'S') 75758020Seric m->m_sh_rwset = m->m_se_rwset = i; 75810327Seric else 75958020Seric m->m_rh_rwset = m->m_re_rwset = i; 76058020Seric 76158020Seric p = endp; 76259985Seric if (*p++ == '/') 76358020Seric { 76458020Seric i = strtol(p, NULL, 10); 76558020Seric if (i < 0 || i >= MAXRWSETS) 76658020Seric { 76758020Seric syserr("invalid rewrite set, %d max", 76858020Seric MAXRWSETS); 76958020Seric return; 77058020Seric } 77158020Seric if (fcode == 'S') 77258020Seric m->m_sh_rwset = i; 77358020Seric else 77458020Seric m->m_rh_rwset = i; 77558020Seric } 77610327Seric break; 77710327Seric 77810327Seric case 'E': /* end of line string */ 77910327Seric m->m_eol = newstr(p); 78010327Seric break; 78110327Seric 78210327Seric case 'A': /* argument vector */ 78310327Seric m->m_argv = makeargv(p); 78410327Seric break; 78510701Seric 78610701Seric case 'M': /* maximum message size */ 78710701Seric m->m_maxsize = atol(p); 78810701Seric break; 78952106Seric 79052106Seric case 'L': /* maximum line length */ 79152106Seric m->m_linelimit = atoi(p); 79252106Seric break; 79358935Seric 79458935Seric case 'D': /* working directory */ 79558935Seric m->m_execdir = newstr(p); 79658935Seric break; 79767604Seric 79867604Seric case 'U': /* user id */ 79967604Seric if (isascii(*p) && !isdigit(*p)) 80067604Seric { 80167604Seric char *q = p; 80267604Seric struct passwd *pw; 80367604Seric 80467604Seric while (isascii(*p) && isalnum(*p)) 80567604Seric p++; 80667604Seric while (isascii(*p) && isspace(*p)) 80767604Seric *p++ = '\0'; 80867604Seric if (*p != '\0') 80967604Seric *p++ = '\0'; 81067604Seric pw = getpwnam(q); 81167604Seric if (pw == NULL) 81267604Seric syserr("readcf: mailer U= flag: unknown user %s", q); 81367604Seric else 81467604Seric { 81567604Seric m->m_uid = pw->pw_uid; 81667604Seric m->m_gid = pw->pw_gid; 81767604Seric } 81867604Seric } 81967604Seric else 82067604Seric { 82167604Seric auto char *q; 82267604Seric 82367604Seric m->m_uid = strtol(p, &q, 0); 82467604Seric p = q; 82567604Seric } 82667604Seric while (isascii(*p) && isspace(*p)) 82767604Seric p++; 82867604Seric if (*p == '\0') 82967604Seric break; 83067604Seric if (isascii(*p) && !isdigit(*p)) 83167604Seric { 83267604Seric char *q = p; 83367604Seric struct group *gr; 83467604Seric 83567604Seric while (isascii(*p) && isalnum(*p)) 83667604Seric p++; 83767604Seric *p++ = '\0'; 83867604Seric gr = getgrnam(q); 83967604Seric if (gr == NULL) 84067604Seric syserr("readcf: mailer U= flag: unknown group %s", q); 84167604Seric else 84267604Seric m->m_gid = gr->gr_gid; 84367604Seric } 84467604Seric else 84567604Seric { 84667604Seric m->m_gid = strtol(p, NULL, 0); 84767604Seric } 84867604Seric break; 84910327Seric } 85010327Seric 85158333Seric p = delimptr; 85210327Seric } 85310327Seric 85452106Seric /* do some heuristic cleanup for back compatibility */ 85552106Seric if (bitnset(M_LIMITS, m->m_flags)) 85652106Seric { 85752106Seric if (m->m_linelimit == 0) 85852106Seric m->m_linelimit = SMTPLINELIM; 85955418Seric if (ConfigLevel < 2) 86052106Seric setbitn(M_7BITS, m->m_flags); 86152106Seric } 86252106Seric 86358321Seric /* do some rationality checking */ 86458321Seric if (m->m_argv == NULL) 86558321Seric { 86658321Seric syserr("M%s: A= argument required", m->m_name); 86758321Seric return; 86858321Seric } 86958321Seric if (m->m_mailer == NULL) 87058321Seric { 87158321Seric syserr("M%s: P= argument required", m->m_name); 87258321Seric return; 87358321Seric } 87458321Seric 8754096Seric if (NextMailer >= MAXMAILERS) 8764096Seric { 8779381Seric syserr("too many mailers defined (%d max)", MAXMAILERS); 8784096Seric return; 8794096Seric } 88057402Seric 88110327Seric s = stab(m->m_name, ST_MAILER, ST_ENTER); 88257402Seric if (s->s_mailer != NULL) 88357402Seric { 88457402Seric i = s->s_mailer->m_mno; 88557402Seric free(s->s_mailer); 88657402Seric } 88757402Seric else 88857402Seric { 88957402Seric i = NextMailer++; 89057402Seric } 89157402Seric Mailer[i] = s->s_mailer = m; 89257454Seric m->m_mno = i; 89310327Seric } 89410327Seric /* 89510327Seric ** MUNCHSTRING -- translate a string into internal form. 89610327Seric ** 89710327Seric ** Parameters: 89810327Seric ** p -- the string to munch. 89958333Seric ** delimptr -- if non-NULL, set to the pointer of the 90058333Seric ** field delimiter character. 90110327Seric ** 90210327Seric ** Returns: 90310327Seric ** the munched string. 90410327Seric */ 9054096Seric 90610327Seric char * 90758333Seric munchstring(p, delimptr) 90810327Seric register char *p; 90958333Seric char **delimptr; 91010327Seric { 91110327Seric register char *q; 91210327Seric bool backslash = FALSE; 91310327Seric bool quotemode = FALSE; 91410327Seric static char buf[MAXLINE]; 9154096Seric 91610327Seric for (q = buf; *p != '\0'; p++) 9174096Seric { 91810327Seric if (backslash) 91910327Seric { 92010327Seric /* everything is roughly literal */ 92110357Seric backslash = FALSE; 92210327Seric switch (*p) 92310327Seric { 92410327Seric case 'r': /* carriage return */ 92510327Seric *q++ = '\r'; 92610327Seric continue; 92710327Seric 92810327Seric case 'n': /* newline */ 92910327Seric *q++ = '\n'; 93010327Seric continue; 93110327Seric 93210327Seric case 'f': /* form feed */ 93310327Seric *q++ = '\f'; 93410327Seric continue; 93510327Seric 93610327Seric case 'b': /* backspace */ 93710327Seric *q++ = '\b'; 93810327Seric continue; 93910327Seric } 94010327Seric *q++ = *p; 94110327Seric } 94210327Seric else 94310327Seric { 94410327Seric if (*p == '\\') 94510327Seric backslash = TRUE; 94610327Seric else if (*p == '"') 94710327Seric quotemode = !quotemode; 94810327Seric else if (quotemode || *p != ',') 94910327Seric *q++ = *p; 95010327Seric else 95110327Seric break; 95210327Seric } 9534096Seric } 9544096Seric 95558333Seric if (delimptr != NULL) 95658333Seric *delimptr = p; 95710327Seric *q++ = '\0'; 95810327Seric return (buf); 95910327Seric } 96010327Seric /* 96110327Seric ** MAKEARGV -- break up a string into words 96210327Seric ** 96310327Seric ** Parameters: 96410327Seric ** p -- the string to break up. 96510327Seric ** 96610327Seric ** Returns: 96710327Seric ** a char **argv (dynamically allocated) 96810327Seric ** 96910327Seric ** Side Effects: 97010327Seric ** munges p. 97110327Seric */ 9724096Seric 97310327Seric char ** 97410327Seric makeargv(p) 97510327Seric register char *p; 97610327Seric { 97710327Seric char *q; 97810327Seric int i; 97910327Seric char **avp; 98010327Seric char *argv[MAXPV + 1]; 98110327Seric 98210327Seric /* take apart the words */ 98310327Seric i = 0; 98410327Seric while (*p != '\0' && i < MAXPV) 9854096Seric { 98610327Seric q = p; 98758050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 98810327Seric p++; 98958050Seric while (isascii(*p) && isspace(*p)) 99010327Seric *p++ = '\0'; 99110327Seric argv[i++] = newstr(q); 9924096Seric } 99310327Seric argv[i++] = NULL; 9944096Seric 99510327Seric /* now make a copy of the argv */ 99610327Seric avp = (char **) xalloc(sizeof *avp * i); 99716893Seric bcopy((char *) argv, (char *) avp, sizeof *avp * i); 99810327Seric 99910327Seric return (avp); 10003308Seric } 10013308Seric /* 10023308Seric ** PRINTRULES -- print rewrite rules (for debugging) 10033308Seric ** 10043308Seric ** Parameters: 10053308Seric ** none. 10063308Seric ** 10073308Seric ** Returns: 10083308Seric ** none. 10093308Seric ** 10103308Seric ** Side Effects: 10113308Seric ** prints rewrite rules. 10123308Seric */ 10133308Seric 10143308Seric printrules() 10153308Seric { 10163308Seric register struct rewrite *rwp; 10174072Seric register int ruleset; 10183308Seric 10194072Seric for (ruleset = 0; ruleset < 10; ruleset++) 10203308Seric { 10214072Seric if (RewriteRules[ruleset] == NULL) 10224072Seric continue; 10238067Seric printf("\n----Rule Set %d:", ruleset); 10243308Seric 10254072Seric for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 10263308Seric { 10278067Seric printf("\nLHS:"); 10288067Seric printav(rwp->r_lhs); 10298067Seric printf("RHS:"); 10308067Seric printav(rwp->r_rhs); 10313308Seric } 10323308Seric } 10333308Seric } 10344319Seric 10354096Seric /* 10368256Seric ** SETOPTION -- set global processing option 10378256Seric ** 10388256Seric ** Parameters: 10398256Seric ** opt -- option name. 10408256Seric ** val -- option value (as a text string). 104121755Seric ** safe -- set if this came from a configuration file. 104221755Seric ** Some options (if set from the command line) will 104321755Seric ** reset the user id to avoid security problems. 10448269Seric ** sticky -- if set, don't let other setoptions override 10458269Seric ** this value. 104658734Seric ** e -- the main envelope. 10478256Seric ** 10488256Seric ** Returns: 10498256Seric ** none. 10508256Seric ** 10518256Seric ** Side Effects: 10528256Seric ** Sets options as implied by the arguments. 10538256Seric */ 10548256Seric 105510687Seric static BITMAP StickyOpt; /* set if option is stuck */ 10568269Seric 105757207Seric 105866334Seric #if NAMED_BIND 105957207Seric 106057207Seric struct resolverflags 106157207Seric { 106257207Seric char *rf_name; /* name of the flag */ 106357207Seric long rf_bits; /* bits to set/clear */ 106457207Seric } ResolverFlags[] = 106557207Seric { 106657207Seric "debug", RES_DEBUG, 106757207Seric "aaonly", RES_AAONLY, 106857207Seric "usevc", RES_USEVC, 106957207Seric "primary", RES_PRIMARY, 107057207Seric "igntc", RES_IGNTC, 107157207Seric "recurse", RES_RECURSE, 107257207Seric "defnames", RES_DEFNAMES, 107357207Seric "stayopen", RES_STAYOPEN, 107457207Seric "dnsrch", RES_DNSRCH, 107565583Seric "true", 0, /* to avoid error on old syntax */ 107657207Seric NULL, 0 107757207Seric }; 107857207Seric 107957207Seric #endif 108057207Seric 108167614Seric struct optioninfo 108267614Seric { 108367614Seric char *o_name; /* long name of option */ 1084*67787Seric u_char o_code; /* short name of option */ 108567614Seric bool o_safe; /* safe for random people to use */ 108667614Seric } OptionTab[] = 108767614Seric { 108867707Seric "SevenBitInput", '7', TRUE, 108967707Seric "EightBitMode", '8', TRUE, 109067707Seric "AliasFile", 'A', FALSE, 109167707Seric "AliasWait", 'a', FALSE, 109267707Seric "BlankSub", 'B', FALSE, 109367707Seric "MinFreeBlocks", 'b', TRUE, 109467707Seric "CheckpointInterval", 'C', TRUE, 109567707Seric "HoldExpensive", 'c', FALSE, 109667707Seric "AutoRebuildAliases", 'D', FALSE, 109767707Seric "DeliveryMode", 'd', TRUE, 109867707Seric "ErrorHeader", 'E', FALSE, 109967707Seric "ErrorMode", 'e', TRUE, 110067707Seric "TempFileMode", 'F', FALSE, 110167707Seric "SaveFromLine", 'f', FALSE, 110267707Seric "MatchGECOS", 'G', FALSE, 110367707Seric "HelpFile", 'H', FALSE, 110467707Seric "MaxHopCount", 'h', FALSE, 110567707Seric "NameServerOptions", 'I', FALSE, 110667707Seric "IgnoreDots", 'i', TRUE, 110767707Seric "ForwardPath", 'J', FALSE, 110867707Seric "SendMimeErrors", 'j', TRUE, 110967707Seric "ConnectionCacheSize", 'k', FALSE, 111067707Seric "ConnectionCacheTimeout", 'K', FALSE, 111167707Seric "UseErrorsTo", 'l', FALSE, 111267707Seric "LogLevel", 'L', FALSE, 111367707Seric "MeToo", 'm', TRUE, 111467707Seric "CheckAliases", 'n', FALSE, 111567707Seric "OldStyleHeaders", 'o', TRUE, 111667707Seric "DaemonPortOptions", 'O', FALSE, 111767707Seric "PrivacyOptions", 'p', TRUE, 111867707Seric "PostmasterCopy", 'P', FALSE, 111967707Seric "QueueFactor", 'q', FALSE, 112067707Seric "QueueDirectory", 'Q', FALSE, 112167707Seric "DontPruneRoutes", 'R', FALSE, 112267711Seric "Timeouts", 'r', TRUE, 112367707Seric "StatusFile", 'S', FALSE, 112467707Seric "SuperSafe", 's', TRUE, 112567707Seric "QueueTimeout", 'T', FALSE, 112667707Seric "TimeZoneSpec", 't', FALSE, 112767707Seric "UserDatabaseSpec", 'U', FALSE, 112867707Seric "DefaultUser", 'u', FALSE, 112967707Seric "FallbackMXhost", 'V', FALSE, 113067707Seric "Verbose", 'v', TRUE, 113167707Seric "TryNullMXList", 'w', TRUE, 113267707Seric "QueueLA", 'x', FALSE, 113367707Seric "RefuseLA", 'X', FALSE, 113467707Seric "RecipientFactor", 'y', FALSE, 113567707Seric "ForkQueueRuns", 'Y', FALSE, 113667707Seric "ClassFactor", 'z', FALSE, 113767707Seric "TimeFactor", 'Z', FALSE, 113867707Seric #define O_BSP 0x80 113967707Seric "BrokenSmtpPeers", O_BSP, TRUE, 114067707Seric #define O_SQBH 0x81 114167707Seric "SortQueueByHost", O_SQBH, TRUE, 114267707Seric #define O_DNICE 0x82 114367707Seric "DeliveryNiceness", O_DNICE, TRUE, 114467707Seric #define O_MQA 0x83 114567707Seric "MinQueueAge", O_MQA, TRUE, 114667707Seric #define O_MHSA 0x84 114767707Seric "MaxHostStatAge", O_MHSA, TRUE, 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) 1209*67787Seric { 121067614Seric syserr("readcf: unknown option name %s", val); 1211*67787Seric return; 1212*67787Seric } 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 */ 142364133Seric if (isascii(*val) && isdigit(*val)) 142464133Seric DefGid = atoi(val); 142564133Seric else 142664133Seric { 142764133Seric register struct group *gr; 142864133Seric 142964133Seric DefGid = -1; 143064133Seric gr = getgrnam(val); 143164133Seric if (gr == NULL) 143264133Seric syserr("readcf: option g: unknown group %s", val); 143364133Seric else 143464133Seric DefGid = gr->gr_gid; 143564133Seric } 14368256Seric break; 14378256Seric 14388256Seric case 'H': /* help file */ 14399381Seric if (val[0] == '\0') 14408269Seric HelpFile = "sendmail.hf"; 14419381Seric else 14429381Seric HelpFile = newstr(val); 14438256Seric break; 14448256Seric 144551305Seric case 'h': /* maximum hop count */ 144651305Seric MaxHopCount = atoi(val); 144751305Seric break; 144851305Seric 144935651Seric case 'I': /* use internet domain name server */ 145066334Seric #if NAMED_BIND 145157207Seric UseNameServer = TRUE; 145257207Seric for (p = val; *p != 0; ) 145357207Seric { 145457207Seric bool clearmode; 145557207Seric char *q; 145657207Seric struct resolverflags *rfp; 145757207Seric 145857207Seric while (*p == ' ') 145957207Seric p++; 146057207Seric if (*p == '\0') 146157207Seric break; 146257207Seric clearmode = FALSE; 146357207Seric if (*p == '-') 146457207Seric clearmode = TRUE; 146557207Seric else if (*p != '+') 146657207Seric p--; 146757207Seric p++; 146857207Seric q = p; 146958050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 147057207Seric p++; 147157207Seric if (*p != '\0') 147257207Seric *p++ = '\0'; 147357207Seric for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 147457207Seric { 147557207Seric if (strcasecmp(q, rfp->rf_name) == 0) 147657207Seric break; 147757207Seric } 147864923Seric if (rfp->rf_name == NULL) 147964923Seric syserr("readcf: I option value %s unrecognized", q); 148064923Seric else if (clearmode) 148157207Seric _res.options &= ~rfp->rf_bits; 148257207Seric else 148357207Seric _res.options |= rfp->rf_bits; 148457207Seric } 148557207Seric if (tTd(8, 2)) 148657207Seric printf("_res.options = %x\n", _res.options); 148757207Seric #else 148857207Seric usrerr("name server (I option) specified but BIND not compiled in"); 148957207Seric #endif 149035651Seric break; 149135651Seric 14928269Seric case 'i': /* ignore dot lines in message */ 14939381Seric IgnrDot = atobool(val); 14948269Seric break; 14958269Seric 149659730Seric case 'j': /* send errors in MIME (RFC 1341) format */ 149759730Seric SendMIMEErrors = atobool(val); 149859730Seric break; 149959730Seric 150057136Seric case 'J': /* .forward search path */ 150157136Seric ForwardPath = newstr(val); 150257136Seric break; 150357136Seric 150454967Seric case 'k': /* connection cache size */ 150554967Seric MaxMciCache = atoi(val); 150656215Seric if (MaxMciCache < 0) 150756215Seric MaxMciCache = 0; 150854967Seric break; 150954967Seric 151054967Seric case 'K': /* connection cache timeout */ 151158796Seric MciCacheTimeout = convtime(val, 'm'); 151254967Seric break; 151354967Seric 151461104Seric case 'l': /* use Errors-To: header */ 151561104Seric UseErrorsTo = atobool(val); 151661104Seric break; 151761104Seric 15188256Seric case 'L': /* log level */ 151964140Seric if (safe || LogLevel < atoi(val)) 152064140Seric LogLevel = atoi(val); 15218256Seric break; 15228256Seric 15238269Seric case 'M': /* define macro */ 15249381Seric define(val[0], newstr(&val[1]), CurEnv); 152516878Seric sticky = FALSE; 15268269Seric break; 15278269Seric 15288269Seric case 'm': /* send to me too */ 15299381Seric MeToo = atobool(val); 15308269Seric break; 15318269Seric 153225820Seric case 'n': /* validate RHS in newaliases */ 153325820Seric CheckAliases = atobool(val); 153425820Seric break; 153525820Seric 153661104Seric /* 'N' available -- was "net name" */ 153761104Seric 153858851Seric case 'O': /* daemon options */ 153958851Seric setdaemonoptions(val); 154058851Seric break; 154158851Seric 15428269Seric case 'o': /* assume old style headers */ 15439381Seric if (atobool(val)) 15449341Seric CurEnv->e_flags |= EF_OLDSTYLE; 15459341Seric else 15469341Seric CurEnv->e_flags &= ~EF_OLDSTYLE; 15478269Seric break; 15488269Seric 154958082Seric case 'p': /* select privacy level */ 155058082Seric p = val; 155158082Seric for (;;) 155258082Seric { 155358082Seric register struct prival *pv; 155458082Seric extern struct prival PrivacyValues[]; 155558082Seric 155658082Seric while (isascii(*p) && (isspace(*p) || ispunct(*p))) 155758082Seric p++; 155858082Seric if (*p == '\0') 155958082Seric break; 156058082Seric val = p; 156158082Seric while (isascii(*p) && isalnum(*p)) 156258082Seric p++; 156358082Seric if (*p != '\0') 156458082Seric *p++ = '\0'; 156558082Seric 156658082Seric for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 156758082Seric { 156858082Seric if (strcasecmp(val, pv->pv_name) == 0) 156958082Seric break; 157058082Seric } 157158886Seric if (pv->pv_name == NULL) 157258886Seric syserr("readcf: Op line: %s unrecognized", val); 157358082Seric PrivacyFlags |= pv->pv_flag; 157458082Seric } 157558082Seric break; 157658082Seric 157724944Seric case 'P': /* postmaster copy address for returned mail */ 157824944Seric PostMasterCopy = newstr(val); 157924944Seric break; 158024944Seric 158124944Seric case 'q': /* slope of queue only function */ 158224944Seric QueueFactor = atoi(val); 158324944Seric break; 158424944Seric 15858256Seric case 'Q': /* queue directory */ 15869381Seric if (val[0] == '\0') 15878269Seric QueueDir = "mqueue"; 15889381Seric else 15899381Seric QueueDir = newstr(val); 159058789Seric if (RealUid != 0 && !safe) 159164718Seric Warn_Q_option = TRUE; 15928256Seric break; 15938256Seric 159458148Seric case 'R': /* don't prune routes */ 159558148Seric DontPruneRoutes = atobool(val); 159658148Seric break; 159758148Seric 15988256Seric case 'r': /* read timeout */ 159958112Seric settimeouts(val); 16008256Seric break; 16018256Seric 16028256Seric case 'S': /* status file */ 16039381Seric if (val[0] == '\0') 16048269Seric StatFile = "sendmail.st"; 16059381Seric else 16069381Seric StatFile = newstr(val); 16078256Seric break; 16088256Seric 16098265Seric case 's': /* be super safe, even if expensive */ 16109381Seric SuperSafe = atobool(val); 16118256Seric break; 16128256Seric 16138256Seric case 'T': /* queue timeout */ 161458737Seric p = strchr(val, '/'); 161558737Seric if (p != NULL) 161658737Seric { 161758737Seric *p++ = '\0'; 161867730Seric TimeOuts.to_q_warning[TOC_NORMAL] = convtime(p, 'd'); 161958737Seric } 162067730Seric TimeOuts.to_q_return[TOC_NORMAL] = convtime(val, 'h'); 162154967Seric break; 16228256Seric 16238265Seric case 't': /* time zone name */ 162452106Seric TimeZoneSpec = newstr(val); 16258265Seric break; 16268265Seric 162750556Seric case 'U': /* location of user database */ 162851360Seric UdbSpec = newstr(val); 162950556Seric break; 163050556Seric 16318256Seric case 'u': /* set default uid */ 163264133Seric if (isascii(*val) && isdigit(*val)) 163364133Seric DefUid = atoi(val); 163464133Seric else 163564133Seric { 163664133Seric register struct passwd *pw; 163764133Seric 163864133Seric DefUid = -1; 163964133Seric pw = getpwnam(val); 164064133Seric if (pw == NULL) 164164133Seric syserr("readcf: option u: unknown user %s", val); 164264133Seric else 164364133Seric DefUid = pw->pw_uid; 164464133Seric } 164540973Sbostic setdefuser(); 16468256Seric break; 16478256Seric 164858851Seric case 'V': /* fallback MX host */ 164958851Seric FallBackMX = newstr(val); 165058851Seric break; 165158851Seric 16528269Seric case 'v': /* run in verbose mode */ 16539381Seric Verbose = atobool(val); 16548256Seric break; 16558256Seric 165663837Seric case 'w': /* if we are best MX, try host directly */ 165763837Seric TryNullMXList = atobool(val); 165863837Seric break; 165961104Seric 166061104Seric /* 'W' available -- was wizard password */ 166161104Seric 166214879Seric case 'x': /* load avg at which to auto-queue msgs */ 166314879Seric QueueLA = atoi(val); 166414879Seric break; 166514879Seric 166614879Seric case 'X': /* load avg at which to auto-reject connections */ 166714879Seric RefuseLA = atoi(val); 166814879Seric break; 166914879Seric 167024981Seric case 'y': /* work recipient factor */ 167124981Seric WkRecipFact = atoi(val); 167224981Seric break; 167324981Seric 167424981Seric case 'Y': /* fork jobs during queue runs */ 167524952Seric ForkQueueRuns = atobool(val); 167624952Seric break; 167724952Seric 167824981Seric case 'z': /* work message class factor */ 167924981Seric WkClassFact = atoi(val); 168024981Seric break; 168124981Seric 168224981Seric case 'Z': /* work time factor */ 168324981Seric WkTimeFact = atoi(val); 168424981Seric break; 168524981Seric 168667614Seric case O_BSP: /* SMTP Peers can't handle 2-line greeting */ 168767614Seric BrokenSmtpPeers = atobool(val); 168867614Seric break; 168967614Seric 169067614Seric case O_SQBH: /* sort work queue by host first */ 169167614Seric SortQueueByHost = atobool(val); 169267614Seric break; 169367614Seric 169467707Seric case O_DNICE: /* delivery nice value */ 169567707Seric DeliveryNiceness = atoi(val); 169667707Seric break; 169767707Seric 169867707Seric case O_MQA: /* minimum queue age between deliveries */ 169967707Seric MinQueueAge = convtime(val, 'm'); 170067707Seric break; 170167707Seric 170267707Seric case O_MHSA: /* maximum age of cached host status */ 170367707Seric MaxHostStatAge = convtime(val, 'm'); 170467707Seric break; 170567707Seric 17068256Seric default: 17078256Seric break; 17088256Seric } 170916878Seric if (sticky) 171016878Seric setbitn(opt, StickyOpt); 17119188Seric return; 17128256Seric } 171310687Seric /* 171410687Seric ** SETCLASS -- set a word into a class 171510687Seric ** 171610687Seric ** Parameters: 171710687Seric ** class -- the class to put the word in. 171810687Seric ** word -- the word to enter 171910687Seric ** 172010687Seric ** Returns: 172110687Seric ** none. 172210687Seric ** 172310687Seric ** Side Effects: 172410687Seric ** puts the word into the symbol table. 172510687Seric */ 172610687Seric 172710687Seric setclass(class, word) 172810687Seric int class; 172910687Seric char *word; 173010687Seric { 173110687Seric register STAB *s; 173210687Seric 173357943Seric if (tTd(37, 8)) 173464326Seric printf("setclass(%c, %s)\n", class, word); 173510687Seric s = stab(word, ST_CLASS, ST_ENTER); 173610687Seric setbitn(class, s->s_class); 173710687Seric } 173853654Seric /* 173953654Seric ** MAKEMAPENTRY -- create a map entry 174053654Seric ** 174153654Seric ** Parameters: 174253654Seric ** line -- the config file line 174353654Seric ** 174453654Seric ** Returns: 174553654Seric ** TRUE if it successfully entered the map entry. 174653654Seric ** FALSE otherwise (usually syntax error). 174753654Seric ** 174853654Seric ** Side Effects: 174953654Seric ** Enters the map into the dictionary. 175053654Seric */ 175153654Seric 175253654Seric void 175353654Seric makemapentry(line) 175453654Seric char *line; 175553654Seric { 175653654Seric register char *p; 175753654Seric char *mapname; 175853654Seric char *classname; 175964078Seric register STAB *s; 176053654Seric STAB *class; 176153654Seric 176258050Seric for (p = line; isascii(*p) && isspace(*p); p++) 176353654Seric continue; 176458050Seric if (!(isascii(*p) && isalnum(*p))) 176553654Seric { 176653654Seric syserr("readcf: config K line: no map name"); 176753654Seric return; 176853654Seric } 176953654Seric 177053654Seric mapname = p; 177158050Seric while (isascii(*++p) && isalnum(*p)) 177253654Seric continue; 177353654Seric if (*p != '\0') 177453654Seric *p++ = '\0'; 177558050Seric while (isascii(*p) && isspace(*p)) 177653654Seric p++; 177758050Seric if (!(isascii(*p) && isalnum(*p))) 177853654Seric { 177953654Seric syserr("readcf: config K line, map %s: no map class", mapname); 178053654Seric return; 178153654Seric } 178253654Seric classname = p; 178358050Seric while (isascii(*++p) && isalnum(*p)) 178453654Seric continue; 178553654Seric if (*p != '\0') 178653654Seric *p++ = '\0'; 178758050Seric while (isascii(*p) && isspace(*p)) 178853654Seric p++; 178953654Seric 179053654Seric /* look up the class */ 179153654Seric class = stab(classname, ST_MAPCLASS, ST_FIND); 179253654Seric if (class == NULL) 179353654Seric { 179453654Seric syserr("readcf: map %s: class %s not available", mapname, classname); 179553654Seric return; 179653654Seric } 179753654Seric 179853654Seric /* enter the map */ 179964078Seric s = stab(mapname, ST_MAP, ST_ENTER); 180064078Seric s->s_map.map_class = &class->s_mapclass; 180164078Seric s->s_map.map_mname = newstr(mapname); 180253654Seric 180364078Seric if (class->s_mapclass.map_parse(&s->s_map, p)) 180464078Seric s->s_map.map_mflags |= MF_VALID; 180564078Seric 180664078Seric if (tTd(37, 5)) 180764078Seric { 180864078Seric printf("map %s, class %s, flags %x, file %s,\n", 180964078Seric s->s_map.map_mname, s->s_map.map_class->map_cname, 181064078Seric s->s_map.map_mflags, 181164078Seric s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 181264078Seric printf("\tapp %s, domain %s, rebuild %s\n", 181364078Seric s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 181464078Seric s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 181564078Seric s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 181664078Seric } 181753654Seric } 181858112Seric /* 181958112Seric ** SETTIMEOUTS -- parse and set timeout values 182058112Seric ** 182158112Seric ** Parameters: 182258112Seric ** val -- a pointer to the values. If NULL, do initial 182358112Seric ** settings. 182458112Seric ** 182558112Seric ** Returns: 182658112Seric ** none. 182758112Seric ** 182858112Seric ** Side Effects: 182958112Seric ** Initializes the TimeOuts structure 183058112Seric */ 183158112Seric 183264255Seric #define SECONDS 183358112Seric #define MINUTES * 60 183458112Seric #define HOUR * 3600 183558112Seric 183658112Seric settimeouts(val) 183758112Seric register char *val; 183858112Seric { 183958112Seric register char *p; 184058671Seric extern time_t convtime(); 184158112Seric 184258112Seric if (val == NULL) 184358112Seric { 184458112Seric TimeOuts.to_initial = (time_t) 5 MINUTES; 184558112Seric TimeOuts.to_helo = (time_t) 5 MINUTES; 184658112Seric TimeOuts.to_mail = (time_t) 10 MINUTES; 184758112Seric TimeOuts.to_rcpt = (time_t) 1 HOUR; 184858112Seric TimeOuts.to_datainit = (time_t) 5 MINUTES; 184958112Seric TimeOuts.to_datablock = (time_t) 1 HOUR; 185058112Seric TimeOuts.to_datafinal = (time_t) 1 HOUR; 185158112Seric TimeOuts.to_rset = (time_t) 5 MINUTES; 185258112Seric TimeOuts.to_quit = (time_t) 2 MINUTES; 185358112Seric TimeOuts.to_nextcommand = (time_t) 1 HOUR; 185458112Seric TimeOuts.to_miscshort = (time_t) 2 MINUTES; 185564255Seric TimeOuts.to_ident = (time_t) 30 SECONDS; 185667711Seric TimeOuts.to_fileopen = (time_t) 60 SECONDS; 185758112Seric return; 185858112Seric } 185958112Seric 186058112Seric for (;; val = p) 186158112Seric { 186258112Seric while (isascii(*val) && isspace(*val)) 186358112Seric val++; 186458112Seric if (*val == '\0') 186558112Seric break; 186658112Seric for (p = val; *p != '\0' && *p != ','; p++) 186758112Seric continue; 186858112Seric if (*p != '\0') 186958112Seric *p++ = '\0'; 187058112Seric 187158112Seric if (isascii(*val) && isdigit(*val)) 187258112Seric { 187358112Seric /* old syntax -- set everything */ 187458796Seric TimeOuts.to_mail = convtime(val, 'm'); 187558112Seric TimeOuts.to_rcpt = TimeOuts.to_mail; 187658112Seric TimeOuts.to_datainit = TimeOuts.to_mail; 187758112Seric TimeOuts.to_datablock = TimeOuts.to_mail; 187858112Seric TimeOuts.to_datafinal = TimeOuts.to_mail; 187958112Seric TimeOuts.to_nextcommand = TimeOuts.to_mail; 188058112Seric continue; 188158112Seric } 188258112Seric else 188358112Seric { 188467711Seric register char *q = strchr(val, ':'); 188558112Seric time_t to; 188658112Seric 188767711Seric if (q == NULL && (q = strchr(val, '=')) == NULL) 188858112Seric { 188958112Seric /* syntax error */ 189058112Seric continue; 189158112Seric } 189258112Seric *q++ = '\0'; 189358796Seric to = convtime(q, 'm'); 189458112Seric 189558112Seric if (strcasecmp(val, "initial") == 0) 189658112Seric TimeOuts.to_initial = to; 189758112Seric else if (strcasecmp(val, "mail") == 0) 189858112Seric TimeOuts.to_mail = to; 189958112Seric else if (strcasecmp(val, "rcpt") == 0) 190058112Seric TimeOuts.to_rcpt = to; 190158112Seric else if (strcasecmp(val, "datainit") == 0) 190258112Seric TimeOuts.to_datainit = to; 190358112Seric else if (strcasecmp(val, "datablock") == 0) 190458112Seric TimeOuts.to_datablock = to; 190558112Seric else if (strcasecmp(val, "datafinal") == 0) 190658112Seric TimeOuts.to_datafinal = to; 190758112Seric else if (strcasecmp(val, "command") == 0) 190858112Seric TimeOuts.to_nextcommand = to; 190958112Seric else if (strcasecmp(val, "rset") == 0) 191058112Seric TimeOuts.to_rset = to; 191158112Seric else if (strcasecmp(val, "helo") == 0) 191258112Seric TimeOuts.to_helo = to; 191358112Seric else if (strcasecmp(val, "quit") == 0) 191458112Seric TimeOuts.to_quit = to; 191558112Seric else if (strcasecmp(val, "misc") == 0) 191658112Seric TimeOuts.to_miscshort = to; 191764255Seric else if (strcasecmp(val, "ident") == 0) 191864255Seric TimeOuts.to_ident = to; 191967711Seric else if (strcasecmp(val, "fileopen") == 0) 192067711Seric TimeOuts.to_fileopen = to; 192167711Seric else if (strcasecmp(val, "queuewarn") == 0) 192267730Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 192367711Seric else if (strcasecmp(val, "queuereturn") == 0) 192467730Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 192567730Seric else if (strcasecmp(val, "queuewarn.normal") == 0) 192667730Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 192767730Seric else if (strcasecmp(val, "queuereturn.normal") == 0) 192867730Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 192967730Seric else if (strcasecmp(val, "queuewarn.urgent") == 0) 193067730Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 193167730Seric else if (strcasecmp(val, "queuereturn.urgent") == 0) 193267730Seric TimeOuts.to_q_return[TOC_URGENT] = to; 193367730Seric else if (strcasecmp(val, "queuewarn.non-urgent") == 0) 193467730Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 193567730Seric else if (strcasecmp(val, "queuereturn.non-urgent") == 0) 193667730Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 193758112Seric else 193858112Seric syserr("settimeouts: invalid timeout %s", val); 193958112Seric } 194058112Seric } 194158112Seric } 1942