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*67813Seric static char sccsid[] = "@(#)readcf.c 8.40 (Berkeley) 10/15/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 */ 108467787Seric 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, 1148*67813Seric #define O_DEFCHARSET 0x85 1149*67813Seric "DefaultCharSet", O_DEFCHARSET, TRUE, 115067707Seric 115167707Seric NULL, '\0', FALSE, 115267614Seric }; 115367614Seric 115467614Seric 115567614Seric 115658734Seric setoption(opt, val, safe, sticky, e) 115767614Seric u_char opt; 11588256Seric char *val; 115921755Seric bool safe; 11608269Seric bool sticky; 116158734Seric register ENVELOPE *e; 11628256Seric { 116357207Seric register char *p; 116467614Seric register struct optioninfo *o; 11658265Seric extern bool atobool(); 116612633Seric extern time_t convtime(); 116714879Seric extern int QueueLA; 116814879Seric extern int RefuseLA; 116964718Seric extern bool Warn_Q_option; 11708256Seric 117167736Seric errno = 0; 117267614Seric if (opt == ' ') 117367614Seric { 117467614Seric /* full word options */ 117567736Seric struct optioninfo *sel; 117667614Seric 117767614Seric p = strchr(val, '='); 117867614Seric if (p == NULL) 117967614Seric p = &val[strlen(val)]; 118067614Seric while (*--p == ' ') 118167614Seric continue; 118267614Seric while (*++p == ' ') 118367614Seric *p = '\0'; 118467731Seric if (p == val) 118567731Seric { 118667731Seric syserr("readcf: null option name"); 118767731Seric return; 118867731Seric } 118967614Seric if (*p == '=') 119067614Seric *p++ = '\0'; 119167614Seric while (*p == ' ') 119267614Seric p++; 119367736Seric sel = NULL; 119467614Seric for (o = OptionTab; o->o_name != NULL; o++) 119567614Seric { 119667736Seric if (strncasecmp(o->o_name, val, strlen(val)) != 0) 119767736Seric continue; 119867736Seric if (strlen(o->o_name) == strlen(val)) 119967736Seric { 120067736Seric /* completely specified -- this must be it */ 120167736Seric sel = NULL; 120267614Seric break; 120367736Seric } 120467736Seric if (sel != NULL) 120567736Seric break; 120667736Seric sel = o; 120767614Seric } 120867736Seric if (sel != NULL && o->o_name == NULL) 120967736Seric o = sel; 121067736Seric else if (o->o_name == NULL) 121167787Seric { 121267614Seric syserr("readcf: unknown option name %s", val); 121367787Seric return; 121467787Seric } 121567736Seric else if (sel != NULL) 121667736Seric { 121767736Seric syserr("readcf: ambiguous option name %s (matches %s and %s)", 121867736Seric val, sel->o_name, o->o_name); 121967736Seric return; 122067736Seric } 122167736Seric if (strlen(val) != strlen(o->o_name)) 122267736Seric { 122367736Seric bool oldVerbose = Verbose; 122467736Seric 122567736Seric Verbose = TRUE; 122667736Seric message("Option %s used as abbreviation for %s", 122767736Seric val, o->o_name); 122867736Seric Verbose = oldVerbose; 122967736Seric } 123067614Seric opt = o->o_code; 123167614Seric val = p; 123267614Seric } 123367614Seric else 123467614Seric { 123567614Seric for (o = OptionTab; o->o_name != NULL; o++) 123667614Seric { 123767614Seric if (o->o_code == opt) 123867614Seric break; 123967614Seric } 124067614Seric } 124167614Seric 12428256Seric if (tTd(37, 1)) 124367731Seric { 124467731Seric printf(isascii(opt) && isprint(opt) ? 124567731Seric "setoption %s (%c)=%s" : "setoption %s (0x%x)=%s", 124667614Seric o->o_name == NULL ? "<unknown>" : o->o_name, 124767614Seric opt, val); 124867731Seric } 12498256Seric 12508256Seric /* 12518269Seric ** See if this option is preset for us. 12528256Seric */ 12538256Seric 125459731Seric if (!sticky && bitnset(opt, StickyOpt)) 12558269Seric { 12569341Seric if (tTd(37, 1)) 12579341Seric printf(" (ignored)\n"); 12588269Seric return; 12598269Seric } 12608269Seric 126121755Seric /* 126221755Seric ** Check to see if this option can be specified by this user. 126321755Seric */ 126421755Seric 126563787Seric if (!safe && RealUid == 0) 126621755Seric safe = TRUE; 126767614Seric if (!safe && !o->o_safe) 126821755Seric { 126939111Srick if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 127021755Seric { 127136582Sbostic if (tTd(37, 1)) 127236582Sbostic printf(" (unsafe)"); 127363787Seric if (RealUid != geteuid()) 127436582Sbostic { 127551210Seric if (tTd(37, 1)) 127651210Seric printf("(Resetting uid)"); 127763787Seric (void) setgid(RealGid); 127863787Seric (void) setuid(RealUid); 127936582Sbostic } 128021755Seric } 128121755Seric } 128251210Seric if (tTd(37, 1)) 128317985Seric printf("\n"); 12848269Seric 128567614Seric switch (opt & 0xff) 12868256Seric { 128759709Seric case '7': /* force seven-bit input */ 128867546Seric SevenBitInput = atobool(val); 128952106Seric break; 129052106Seric 129167546Seric case '8': /* handling of 8-bit input */ 129267546Seric switch (*val) 129367546Seric { 129467547Seric case 'r': /* reject 8-bit, don't convert MIME */ 129567546Seric MimeMode = 0; 129667546Seric break; 129767546Seric 129867547Seric case 'm': /* convert 8-bit, convert MIME */ 129967546Seric MimeMode = MM_CVTMIME|MM_MIME8BIT; 130067546Seric break; 130167546Seric 130267547Seric case 'j': /* "just send 8" */ 130367546Seric MimeMode = MM_PASS8BIT; 130467546Seric break; 130567546Seric 130667546Seric case 'p': /* pass 8 bit, convert MIME */ 130767546Seric MimeMode = MM_PASS8BIT|MM_CVTMIME; 130867546Seric break; 130967546Seric 131067546Seric case 's': /* strict adherence */ 131167546Seric MimeMode = MM_CVTMIME; 131267546Seric break; 131367546Seric 131467547Seric case 'a': /* encode 8 bit if available */ 131567546Seric MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 131667546Seric break; 131767546Seric 131867547Seric case 'c': /* convert 8 bit to MIME, never 7 bit */ 131967547Seric MimeMode = MM_MIME8BIT; 132067547Seric break; 132167547Seric 132267546Seric default: 132367546Seric syserr("Unknown 8-bit mode %c", *val); 132467546Seric exit(EX_USAGE); 132567546Seric } 132667546Seric break; 132767546Seric 13288256Seric case 'A': /* set default alias file */ 13299381Seric if (val[0] == '\0') 133059672Seric setalias("aliases"); 13319381Seric else 133259672Seric setalias(val); 13338256Seric break; 13348256Seric 133517474Seric case 'a': /* look N minutes for "@:@" in alias file */ 133617474Seric if (val[0] == '\0') 133764796Seric SafeAlias = 5 * 60; /* five minutes */ 133817474Seric else 133964796Seric SafeAlias = convtime(val, 'm'); 134017474Seric break; 134117474Seric 134216843Seric case 'B': /* substitution for blank character */ 134316843Seric SpaceSub = val[0]; 134416843Seric if (SpaceSub == '\0') 134516843Seric SpaceSub = ' '; 134616843Seric break; 134716843Seric 134859283Seric case 'b': /* min blocks free on queue fs/max msg size */ 134959283Seric p = strchr(val, '/'); 135059283Seric if (p != NULL) 135159283Seric { 135259283Seric *p++ = '\0'; 135359283Seric MaxMessageSize = atol(p); 135459283Seric } 135558082Seric MinBlocksFree = atol(val); 135658082Seric break; 135758082Seric 13589284Seric case 'c': /* don't connect to "expensive" mailers */ 13599381Seric NoConnect = atobool(val); 13609284Seric break; 13619284Seric 136251305Seric case 'C': /* checkpoint every N addresses */ 136351305Seric CheckpointInterval = atoi(val); 136424944Seric break; 136524944Seric 13669284Seric case 'd': /* delivery mode */ 13679284Seric switch (*val) 13688269Seric { 13699284Seric case '\0': 137058734Seric e->e_sendmode = SM_DELIVER; 13718269Seric break; 13728269Seric 137310755Seric case SM_QUEUE: /* queue only */ 137410755Seric #ifndef QUEUE 137510755Seric syserr("need QUEUE to set -odqueue"); 137656795Seric #endif /* QUEUE */ 137710755Seric /* fall through..... */ 137810755Seric 13799284Seric case SM_DELIVER: /* do everything */ 13809284Seric case SM_FORK: /* fork after verification */ 138158734Seric e->e_sendmode = *val; 13828269Seric break; 13838269Seric 13848269Seric default: 13859284Seric syserr("Unknown delivery mode %c", *val); 13868269Seric exit(EX_USAGE); 13878269Seric } 13888269Seric break; 13898269Seric 13909146Seric case 'D': /* rebuild alias database as needed */ 13919381Seric AutoRebuild = atobool(val); 13929146Seric break; 13939146Seric 139455372Seric case 'E': /* error message header/header file */ 139555379Seric if (*val != '\0') 139655379Seric ErrMsgFile = newstr(val); 139755372Seric break; 139855372Seric 13998269Seric case 'e': /* set error processing mode */ 14008269Seric switch (*val) 14018269Seric { 14029381Seric case EM_QUIET: /* be silent about it */ 14039381Seric case EM_MAIL: /* mail back */ 14049381Seric case EM_BERKNET: /* do berknet error processing */ 14059381Seric case EM_WRITE: /* write back (or mail) */ 14069381Seric case EM_PRINT: /* print errors normally (default) */ 140758734Seric e->e_errormode = *val; 14088269Seric break; 14098269Seric } 14108269Seric break; 14118269Seric 14129049Seric case 'F': /* file mode */ 141317975Seric FileMode = atooct(val) & 0777; 14149049Seric break; 14159049Seric 14168269Seric case 'f': /* save Unix-style From lines on front */ 14179381Seric SaveFrom = atobool(val); 14188269Seric break; 14198269Seric 142053735Seric case 'G': /* match recipients against GECOS field */ 142153735Seric MatchGecos = atobool(val); 142253735Seric break; 142353735Seric 14248256Seric case 'g': /* default gid */ 142564133Seric if (isascii(*val) && isdigit(*val)) 142664133Seric DefGid = atoi(val); 142764133Seric else 142864133Seric { 142964133Seric register struct group *gr; 143064133Seric 143164133Seric DefGid = -1; 143264133Seric gr = getgrnam(val); 143364133Seric if (gr == NULL) 143464133Seric syserr("readcf: option g: unknown group %s", val); 143564133Seric else 143664133Seric DefGid = gr->gr_gid; 143764133Seric } 14388256Seric break; 14398256Seric 14408256Seric case 'H': /* help file */ 14419381Seric if (val[0] == '\0') 14428269Seric HelpFile = "sendmail.hf"; 14439381Seric else 14449381Seric HelpFile = newstr(val); 14458256Seric break; 14468256Seric 144751305Seric case 'h': /* maximum hop count */ 144851305Seric MaxHopCount = atoi(val); 144951305Seric break; 145051305Seric 145135651Seric case 'I': /* use internet domain name server */ 145266334Seric #if NAMED_BIND 145357207Seric UseNameServer = TRUE; 145457207Seric for (p = val; *p != 0; ) 145557207Seric { 145657207Seric bool clearmode; 145757207Seric char *q; 145857207Seric struct resolverflags *rfp; 145957207Seric 146057207Seric while (*p == ' ') 146157207Seric p++; 146257207Seric if (*p == '\0') 146357207Seric break; 146457207Seric clearmode = FALSE; 146557207Seric if (*p == '-') 146657207Seric clearmode = TRUE; 146757207Seric else if (*p != '+') 146857207Seric p--; 146957207Seric p++; 147057207Seric q = p; 147158050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 147257207Seric p++; 147357207Seric if (*p != '\0') 147457207Seric *p++ = '\0'; 147557207Seric for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 147657207Seric { 147757207Seric if (strcasecmp(q, rfp->rf_name) == 0) 147857207Seric break; 147957207Seric } 148064923Seric if (rfp->rf_name == NULL) 148164923Seric syserr("readcf: I option value %s unrecognized", q); 148264923Seric else if (clearmode) 148357207Seric _res.options &= ~rfp->rf_bits; 148457207Seric else 148557207Seric _res.options |= rfp->rf_bits; 148657207Seric } 148757207Seric if (tTd(8, 2)) 148857207Seric printf("_res.options = %x\n", _res.options); 148957207Seric #else 149057207Seric usrerr("name server (I option) specified but BIND not compiled in"); 149157207Seric #endif 149235651Seric break; 149335651Seric 14948269Seric case 'i': /* ignore dot lines in message */ 14959381Seric IgnrDot = atobool(val); 14968269Seric break; 14978269Seric 149859730Seric case 'j': /* send errors in MIME (RFC 1341) format */ 149959730Seric SendMIMEErrors = atobool(val); 150059730Seric break; 150159730Seric 150257136Seric case 'J': /* .forward search path */ 150357136Seric ForwardPath = newstr(val); 150457136Seric break; 150557136Seric 150654967Seric case 'k': /* connection cache size */ 150754967Seric MaxMciCache = atoi(val); 150856215Seric if (MaxMciCache < 0) 150956215Seric MaxMciCache = 0; 151054967Seric break; 151154967Seric 151254967Seric case 'K': /* connection cache timeout */ 151358796Seric MciCacheTimeout = convtime(val, 'm'); 151454967Seric break; 151554967Seric 151661104Seric case 'l': /* use Errors-To: header */ 151761104Seric UseErrorsTo = atobool(val); 151861104Seric break; 151961104Seric 15208256Seric case 'L': /* log level */ 152164140Seric if (safe || LogLevel < atoi(val)) 152264140Seric LogLevel = atoi(val); 15238256Seric break; 15248256Seric 15258269Seric case 'M': /* define macro */ 15269381Seric define(val[0], newstr(&val[1]), CurEnv); 152716878Seric sticky = FALSE; 15288269Seric break; 15298269Seric 15308269Seric case 'm': /* send to me too */ 15319381Seric MeToo = atobool(val); 15328269Seric break; 15338269Seric 153425820Seric case 'n': /* validate RHS in newaliases */ 153525820Seric CheckAliases = atobool(val); 153625820Seric break; 153725820Seric 153861104Seric /* 'N' available -- was "net name" */ 153961104Seric 154058851Seric case 'O': /* daemon options */ 154158851Seric setdaemonoptions(val); 154258851Seric break; 154358851Seric 15448269Seric case 'o': /* assume old style headers */ 15459381Seric if (atobool(val)) 15469341Seric CurEnv->e_flags |= EF_OLDSTYLE; 15479341Seric else 15489341Seric CurEnv->e_flags &= ~EF_OLDSTYLE; 15498269Seric break; 15508269Seric 155158082Seric case 'p': /* select privacy level */ 155258082Seric p = val; 155358082Seric for (;;) 155458082Seric { 155558082Seric register struct prival *pv; 155658082Seric extern struct prival PrivacyValues[]; 155758082Seric 155858082Seric while (isascii(*p) && (isspace(*p) || ispunct(*p))) 155958082Seric p++; 156058082Seric if (*p == '\0') 156158082Seric break; 156258082Seric val = p; 156358082Seric while (isascii(*p) && isalnum(*p)) 156458082Seric p++; 156558082Seric if (*p != '\0') 156658082Seric *p++ = '\0'; 156758082Seric 156858082Seric for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 156958082Seric { 157058082Seric if (strcasecmp(val, pv->pv_name) == 0) 157158082Seric break; 157258082Seric } 157358886Seric if (pv->pv_name == NULL) 157458886Seric syserr("readcf: Op line: %s unrecognized", val); 157558082Seric PrivacyFlags |= pv->pv_flag; 157658082Seric } 157758082Seric break; 157858082Seric 157924944Seric case 'P': /* postmaster copy address for returned mail */ 158024944Seric PostMasterCopy = newstr(val); 158124944Seric break; 158224944Seric 158324944Seric case 'q': /* slope of queue only function */ 158424944Seric QueueFactor = atoi(val); 158524944Seric break; 158624944Seric 15878256Seric case 'Q': /* queue directory */ 15889381Seric if (val[0] == '\0') 15898269Seric QueueDir = "mqueue"; 15909381Seric else 15919381Seric QueueDir = newstr(val); 159258789Seric if (RealUid != 0 && !safe) 159364718Seric Warn_Q_option = TRUE; 15948256Seric break; 15958256Seric 159658148Seric case 'R': /* don't prune routes */ 159758148Seric DontPruneRoutes = atobool(val); 159858148Seric break; 159958148Seric 16008256Seric case 'r': /* read timeout */ 160158112Seric settimeouts(val); 16028256Seric break; 16038256Seric 16048256Seric case 'S': /* status file */ 16059381Seric if (val[0] == '\0') 16068269Seric StatFile = "sendmail.st"; 16079381Seric else 16089381Seric StatFile = newstr(val); 16098256Seric break; 16108256Seric 16118265Seric case 's': /* be super safe, even if expensive */ 16129381Seric SuperSafe = atobool(val); 16138256Seric break; 16148256Seric 16158256Seric case 'T': /* queue timeout */ 161658737Seric p = strchr(val, '/'); 161758737Seric if (p != NULL) 161858737Seric { 161958737Seric *p++ = '\0'; 162067730Seric TimeOuts.to_q_warning[TOC_NORMAL] = convtime(p, 'd'); 162158737Seric } 162267730Seric TimeOuts.to_q_return[TOC_NORMAL] = convtime(val, 'h'); 162354967Seric break; 16248256Seric 16258265Seric case 't': /* time zone name */ 162652106Seric TimeZoneSpec = newstr(val); 16278265Seric break; 16288265Seric 162950556Seric case 'U': /* location of user database */ 163051360Seric UdbSpec = newstr(val); 163150556Seric break; 163250556Seric 16338256Seric case 'u': /* set default uid */ 163464133Seric if (isascii(*val) && isdigit(*val)) 163564133Seric DefUid = atoi(val); 163664133Seric else 163764133Seric { 163864133Seric register struct passwd *pw; 163964133Seric 164064133Seric DefUid = -1; 164164133Seric pw = getpwnam(val); 164264133Seric if (pw == NULL) 164364133Seric syserr("readcf: option u: unknown user %s", val); 164464133Seric else 164564133Seric DefUid = pw->pw_uid; 164664133Seric } 164740973Sbostic setdefuser(); 16488256Seric break; 16498256Seric 165058851Seric case 'V': /* fallback MX host */ 165158851Seric FallBackMX = newstr(val); 165258851Seric break; 165358851Seric 16548269Seric case 'v': /* run in verbose mode */ 16559381Seric Verbose = atobool(val); 16568256Seric break; 16578256Seric 165863837Seric case 'w': /* if we are best MX, try host directly */ 165963837Seric TryNullMXList = atobool(val); 166063837Seric break; 166161104Seric 166261104Seric /* 'W' available -- was wizard password */ 166361104Seric 166414879Seric case 'x': /* load avg at which to auto-queue msgs */ 166514879Seric QueueLA = atoi(val); 166614879Seric break; 166714879Seric 166814879Seric case 'X': /* load avg at which to auto-reject connections */ 166914879Seric RefuseLA = atoi(val); 167014879Seric break; 167114879Seric 167224981Seric case 'y': /* work recipient factor */ 167324981Seric WkRecipFact = atoi(val); 167424981Seric break; 167524981Seric 167624981Seric case 'Y': /* fork jobs during queue runs */ 167724952Seric ForkQueueRuns = atobool(val); 167824952Seric break; 167924952Seric 168024981Seric case 'z': /* work message class factor */ 168124981Seric WkClassFact = atoi(val); 168224981Seric break; 168324981Seric 168424981Seric case 'Z': /* work time factor */ 168524981Seric WkTimeFact = atoi(val); 168624981Seric break; 168724981Seric 168867614Seric case O_BSP: /* SMTP Peers can't handle 2-line greeting */ 168967614Seric BrokenSmtpPeers = atobool(val); 169067614Seric break; 169167614Seric 169267614Seric case O_SQBH: /* sort work queue by host first */ 169367614Seric SortQueueByHost = atobool(val); 169467614Seric break; 169567614Seric 169667707Seric case O_DNICE: /* delivery nice value */ 169767707Seric DeliveryNiceness = atoi(val); 169867707Seric break; 169967707Seric 170067707Seric case O_MQA: /* minimum queue age between deliveries */ 170167707Seric MinQueueAge = convtime(val, 'm'); 170267707Seric break; 170367707Seric 170467707Seric case O_MHSA: /* maximum age of cached host status */ 170567707Seric MaxHostStatAge = convtime(val, 'm'); 170667707Seric break; 170767707Seric 1708*67813Seric case O_DEFCHARSET: /* default character set for mimefying */ 1709*67813Seric DefCharSet = newstr(val); 1710*67813Seric break; 1711*67813Seric 17128256Seric default: 17138256Seric break; 17148256Seric } 171516878Seric if (sticky) 171616878Seric setbitn(opt, StickyOpt); 17179188Seric return; 17188256Seric } 171910687Seric /* 172010687Seric ** SETCLASS -- set a word into a class 172110687Seric ** 172210687Seric ** Parameters: 172310687Seric ** class -- the class to put the word in. 172410687Seric ** word -- the word to enter 172510687Seric ** 172610687Seric ** Returns: 172710687Seric ** none. 172810687Seric ** 172910687Seric ** Side Effects: 173010687Seric ** puts the word into the symbol table. 173110687Seric */ 173210687Seric 173310687Seric setclass(class, word) 173410687Seric int class; 173510687Seric char *word; 173610687Seric { 173710687Seric register STAB *s; 173810687Seric 173957943Seric if (tTd(37, 8)) 174064326Seric printf("setclass(%c, %s)\n", class, word); 174110687Seric s = stab(word, ST_CLASS, ST_ENTER); 174210687Seric setbitn(class, s->s_class); 174310687Seric } 174453654Seric /* 174553654Seric ** MAKEMAPENTRY -- create a map entry 174653654Seric ** 174753654Seric ** Parameters: 174853654Seric ** line -- the config file line 174953654Seric ** 175053654Seric ** Returns: 175153654Seric ** TRUE if it successfully entered the map entry. 175253654Seric ** FALSE otherwise (usually syntax error). 175353654Seric ** 175453654Seric ** Side Effects: 175553654Seric ** Enters the map into the dictionary. 175653654Seric */ 175753654Seric 175853654Seric void 175953654Seric makemapentry(line) 176053654Seric char *line; 176153654Seric { 176253654Seric register char *p; 176353654Seric char *mapname; 176453654Seric char *classname; 176564078Seric register STAB *s; 176653654Seric STAB *class; 176753654Seric 176858050Seric for (p = line; isascii(*p) && isspace(*p); p++) 176953654Seric continue; 177058050Seric if (!(isascii(*p) && isalnum(*p))) 177153654Seric { 177253654Seric syserr("readcf: config K line: no map name"); 177353654Seric return; 177453654Seric } 177553654Seric 177653654Seric mapname = p; 177758050Seric while (isascii(*++p) && isalnum(*p)) 177853654Seric continue; 177953654Seric if (*p != '\0') 178053654Seric *p++ = '\0'; 178158050Seric while (isascii(*p) && isspace(*p)) 178253654Seric p++; 178358050Seric if (!(isascii(*p) && isalnum(*p))) 178453654Seric { 178553654Seric syserr("readcf: config K line, map %s: no map class", mapname); 178653654Seric return; 178753654Seric } 178853654Seric classname = p; 178958050Seric while (isascii(*++p) && isalnum(*p)) 179053654Seric continue; 179153654Seric if (*p != '\0') 179253654Seric *p++ = '\0'; 179358050Seric while (isascii(*p) && isspace(*p)) 179453654Seric p++; 179553654Seric 179653654Seric /* look up the class */ 179753654Seric class = stab(classname, ST_MAPCLASS, ST_FIND); 179853654Seric if (class == NULL) 179953654Seric { 180053654Seric syserr("readcf: map %s: class %s not available", mapname, classname); 180153654Seric return; 180253654Seric } 180353654Seric 180453654Seric /* enter the map */ 180564078Seric s = stab(mapname, ST_MAP, ST_ENTER); 180664078Seric s->s_map.map_class = &class->s_mapclass; 180764078Seric s->s_map.map_mname = newstr(mapname); 180853654Seric 180964078Seric if (class->s_mapclass.map_parse(&s->s_map, p)) 181064078Seric s->s_map.map_mflags |= MF_VALID; 181164078Seric 181264078Seric if (tTd(37, 5)) 181364078Seric { 181464078Seric printf("map %s, class %s, flags %x, file %s,\n", 181564078Seric s->s_map.map_mname, s->s_map.map_class->map_cname, 181664078Seric s->s_map.map_mflags, 181764078Seric s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 181864078Seric printf("\tapp %s, domain %s, rebuild %s\n", 181964078Seric s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 182064078Seric s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 182164078Seric s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 182264078Seric } 182353654Seric } 182458112Seric /* 182558112Seric ** SETTIMEOUTS -- parse and set timeout values 182658112Seric ** 182758112Seric ** Parameters: 182858112Seric ** val -- a pointer to the values. If NULL, do initial 182958112Seric ** settings. 183058112Seric ** 183158112Seric ** Returns: 183258112Seric ** none. 183358112Seric ** 183458112Seric ** Side Effects: 183558112Seric ** Initializes the TimeOuts structure 183658112Seric */ 183758112Seric 183864255Seric #define SECONDS 183958112Seric #define MINUTES * 60 184058112Seric #define HOUR * 3600 184158112Seric 184258112Seric settimeouts(val) 184358112Seric register char *val; 184458112Seric { 184558112Seric register char *p; 184658671Seric extern time_t convtime(); 184758112Seric 184858112Seric if (val == NULL) 184958112Seric { 185058112Seric TimeOuts.to_initial = (time_t) 5 MINUTES; 185158112Seric TimeOuts.to_helo = (time_t) 5 MINUTES; 185258112Seric TimeOuts.to_mail = (time_t) 10 MINUTES; 185358112Seric TimeOuts.to_rcpt = (time_t) 1 HOUR; 185458112Seric TimeOuts.to_datainit = (time_t) 5 MINUTES; 185558112Seric TimeOuts.to_datablock = (time_t) 1 HOUR; 185658112Seric TimeOuts.to_datafinal = (time_t) 1 HOUR; 185758112Seric TimeOuts.to_rset = (time_t) 5 MINUTES; 185858112Seric TimeOuts.to_quit = (time_t) 2 MINUTES; 185958112Seric TimeOuts.to_nextcommand = (time_t) 1 HOUR; 186058112Seric TimeOuts.to_miscshort = (time_t) 2 MINUTES; 186164255Seric TimeOuts.to_ident = (time_t) 30 SECONDS; 186267711Seric TimeOuts.to_fileopen = (time_t) 60 SECONDS; 186358112Seric return; 186458112Seric } 186558112Seric 186658112Seric for (;; val = p) 186758112Seric { 186858112Seric while (isascii(*val) && isspace(*val)) 186958112Seric val++; 187058112Seric if (*val == '\0') 187158112Seric break; 187258112Seric for (p = val; *p != '\0' && *p != ','; p++) 187358112Seric continue; 187458112Seric if (*p != '\0') 187558112Seric *p++ = '\0'; 187658112Seric 187758112Seric if (isascii(*val) && isdigit(*val)) 187858112Seric { 187958112Seric /* old syntax -- set everything */ 188058796Seric TimeOuts.to_mail = convtime(val, 'm'); 188158112Seric TimeOuts.to_rcpt = TimeOuts.to_mail; 188258112Seric TimeOuts.to_datainit = TimeOuts.to_mail; 188358112Seric TimeOuts.to_datablock = TimeOuts.to_mail; 188458112Seric TimeOuts.to_datafinal = TimeOuts.to_mail; 188558112Seric TimeOuts.to_nextcommand = TimeOuts.to_mail; 188658112Seric continue; 188758112Seric } 188858112Seric else 188958112Seric { 189067711Seric register char *q = strchr(val, ':'); 189158112Seric time_t to; 189258112Seric 189367711Seric if (q == NULL && (q = strchr(val, '=')) == NULL) 189458112Seric { 189558112Seric /* syntax error */ 189658112Seric continue; 189758112Seric } 189858112Seric *q++ = '\0'; 189958796Seric to = convtime(q, 'm'); 190058112Seric 190158112Seric if (strcasecmp(val, "initial") == 0) 190258112Seric TimeOuts.to_initial = to; 190358112Seric else if (strcasecmp(val, "mail") == 0) 190458112Seric TimeOuts.to_mail = to; 190558112Seric else if (strcasecmp(val, "rcpt") == 0) 190658112Seric TimeOuts.to_rcpt = to; 190758112Seric else if (strcasecmp(val, "datainit") == 0) 190858112Seric TimeOuts.to_datainit = to; 190958112Seric else if (strcasecmp(val, "datablock") == 0) 191058112Seric TimeOuts.to_datablock = to; 191158112Seric else if (strcasecmp(val, "datafinal") == 0) 191258112Seric TimeOuts.to_datafinal = to; 191358112Seric else if (strcasecmp(val, "command") == 0) 191458112Seric TimeOuts.to_nextcommand = to; 191558112Seric else if (strcasecmp(val, "rset") == 0) 191658112Seric TimeOuts.to_rset = to; 191758112Seric else if (strcasecmp(val, "helo") == 0) 191858112Seric TimeOuts.to_helo = to; 191958112Seric else if (strcasecmp(val, "quit") == 0) 192058112Seric TimeOuts.to_quit = to; 192158112Seric else if (strcasecmp(val, "misc") == 0) 192258112Seric TimeOuts.to_miscshort = to; 192364255Seric else if (strcasecmp(val, "ident") == 0) 192464255Seric TimeOuts.to_ident = to; 192567711Seric else if (strcasecmp(val, "fileopen") == 0) 192667711Seric TimeOuts.to_fileopen = to; 192767711Seric else if (strcasecmp(val, "queuewarn") == 0) 192867730Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 192967711Seric else if (strcasecmp(val, "queuereturn") == 0) 193067730Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 193167730Seric else if (strcasecmp(val, "queuewarn.normal") == 0) 193267730Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 193367730Seric else if (strcasecmp(val, "queuereturn.normal") == 0) 193467730Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 193567730Seric else if (strcasecmp(val, "queuewarn.urgent") == 0) 193667730Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 193767730Seric else if (strcasecmp(val, "queuereturn.urgent") == 0) 193867730Seric TimeOuts.to_q_return[TOC_URGENT] = to; 193967730Seric else if (strcasecmp(val, "queuewarn.non-urgent") == 0) 194067730Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 194167730Seric else if (strcasecmp(val, "queuereturn.non-urgent") == 0) 194267730Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 194358112Seric else 194458112Seric syserr("settimeouts: invalid timeout %s", val); 194558112Seric } 194658112Seric } 194758112Seric } 1948