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*67823Seric static char sccsid[] = "@(#)readcf.c 8.42 (Berkeley) 10/16/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, 114867813Seric #define O_DEFCHARSET 0x85 114967813Seric "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 */ 1425*67823Seric g_opt: 142664133Seric if (isascii(*val) && isdigit(*val)) 142764133Seric DefGid = atoi(val); 142864133Seric else 142964133Seric { 143064133Seric register struct group *gr; 143164133Seric 143264133Seric DefGid = -1; 143364133Seric gr = getgrnam(val); 143464133Seric if (gr == NULL) 1435*67823Seric syserr("readcf: option %c: unknown group %s", 1436*67823Seric opt, val); 143764133Seric else 143864133Seric DefGid = gr->gr_gid; 143964133Seric } 14408256Seric break; 14418256Seric 14428256Seric case 'H': /* help file */ 14439381Seric if (val[0] == '\0') 14448269Seric HelpFile = "sendmail.hf"; 14459381Seric else 14469381Seric HelpFile = newstr(val); 14478256Seric break; 14488256Seric 144951305Seric case 'h': /* maximum hop count */ 145051305Seric MaxHopCount = atoi(val); 145151305Seric break; 145251305Seric 145335651Seric case 'I': /* use internet domain name server */ 145466334Seric #if NAMED_BIND 145557207Seric UseNameServer = TRUE; 145657207Seric for (p = val; *p != 0; ) 145757207Seric { 145857207Seric bool clearmode; 145957207Seric char *q; 146057207Seric struct resolverflags *rfp; 146157207Seric 146257207Seric while (*p == ' ') 146357207Seric p++; 146457207Seric if (*p == '\0') 146557207Seric break; 146657207Seric clearmode = FALSE; 146757207Seric if (*p == '-') 146857207Seric clearmode = TRUE; 146957207Seric else if (*p != '+') 147057207Seric p--; 147157207Seric p++; 147257207Seric q = p; 147358050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 147457207Seric p++; 147557207Seric if (*p != '\0') 147657207Seric *p++ = '\0'; 147757207Seric for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 147857207Seric { 147957207Seric if (strcasecmp(q, rfp->rf_name) == 0) 148057207Seric break; 148157207Seric } 148264923Seric if (rfp->rf_name == NULL) 148364923Seric syserr("readcf: I option value %s unrecognized", q); 148464923Seric else if (clearmode) 148557207Seric _res.options &= ~rfp->rf_bits; 148657207Seric else 148757207Seric _res.options |= rfp->rf_bits; 148857207Seric } 148957207Seric if (tTd(8, 2)) 149057207Seric printf("_res.options = %x\n", _res.options); 149157207Seric #else 149257207Seric usrerr("name server (I option) specified but BIND not compiled in"); 149357207Seric #endif 149435651Seric break; 149535651Seric 14968269Seric case 'i': /* ignore dot lines in message */ 14979381Seric IgnrDot = atobool(val); 14988269Seric break; 14998269Seric 150059730Seric case 'j': /* send errors in MIME (RFC 1341) format */ 150159730Seric SendMIMEErrors = atobool(val); 150259730Seric break; 150359730Seric 150457136Seric case 'J': /* .forward search path */ 150557136Seric ForwardPath = newstr(val); 150657136Seric break; 150757136Seric 150854967Seric case 'k': /* connection cache size */ 150954967Seric MaxMciCache = atoi(val); 151056215Seric if (MaxMciCache < 0) 151156215Seric MaxMciCache = 0; 151254967Seric break; 151354967Seric 151454967Seric case 'K': /* connection cache timeout */ 151558796Seric MciCacheTimeout = convtime(val, 'm'); 151654967Seric break; 151754967Seric 151861104Seric case 'l': /* use Errors-To: header */ 151961104Seric UseErrorsTo = atobool(val); 152061104Seric break; 152161104Seric 15228256Seric case 'L': /* log level */ 152364140Seric if (safe || LogLevel < atoi(val)) 152464140Seric LogLevel = atoi(val); 15258256Seric break; 15268256Seric 15278269Seric case 'M': /* define macro */ 15289381Seric define(val[0], newstr(&val[1]), CurEnv); 152916878Seric sticky = FALSE; 15308269Seric break; 15318269Seric 15328269Seric case 'm': /* send to me too */ 15339381Seric MeToo = atobool(val); 15348269Seric break; 15358269Seric 153625820Seric case 'n': /* validate RHS in newaliases */ 153725820Seric CheckAliases = atobool(val); 153825820Seric break; 153925820Seric 154061104Seric /* 'N' available -- was "net name" */ 154161104Seric 154258851Seric case 'O': /* daemon options */ 154358851Seric setdaemonoptions(val); 154458851Seric break; 154558851Seric 15468269Seric case 'o': /* assume old style headers */ 15479381Seric if (atobool(val)) 15489341Seric CurEnv->e_flags |= EF_OLDSTYLE; 15499341Seric else 15509341Seric CurEnv->e_flags &= ~EF_OLDSTYLE; 15518269Seric break; 15528269Seric 155358082Seric case 'p': /* select privacy level */ 155458082Seric p = val; 155558082Seric for (;;) 155658082Seric { 155758082Seric register struct prival *pv; 155858082Seric extern struct prival PrivacyValues[]; 155958082Seric 156058082Seric while (isascii(*p) && (isspace(*p) || ispunct(*p))) 156158082Seric p++; 156258082Seric if (*p == '\0') 156358082Seric break; 156458082Seric val = p; 156558082Seric while (isascii(*p) && isalnum(*p)) 156658082Seric p++; 156758082Seric if (*p != '\0') 156858082Seric *p++ = '\0'; 156958082Seric 157058082Seric for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 157158082Seric { 157258082Seric if (strcasecmp(val, pv->pv_name) == 0) 157358082Seric break; 157458082Seric } 157558886Seric if (pv->pv_name == NULL) 157658886Seric syserr("readcf: Op line: %s unrecognized", val); 157758082Seric PrivacyFlags |= pv->pv_flag; 157858082Seric } 157958082Seric break; 158058082Seric 158124944Seric case 'P': /* postmaster copy address for returned mail */ 158224944Seric PostMasterCopy = newstr(val); 158324944Seric break; 158424944Seric 158524944Seric case 'q': /* slope of queue only function */ 158624944Seric QueueFactor = atoi(val); 158724944Seric break; 158824944Seric 15898256Seric case 'Q': /* queue directory */ 15909381Seric if (val[0] == '\0') 15918269Seric QueueDir = "mqueue"; 15929381Seric else 15939381Seric QueueDir = newstr(val); 159458789Seric if (RealUid != 0 && !safe) 159564718Seric Warn_Q_option = TRUE; 15968256Seric break; 15978256Seric 159858148Seric case 'R': /* don't prune routes */ 159958148Seric DontPruneRoutes = atobool(val); 160058148Seric break; 160158148Seric 16028256Seric case 'r': /* read timeout */ 160358112Seric settimeouts(val); 16048256Seric break; 16058256Seric 16068256Seric case 'S': /* status file */ 16079381Seric if (val[0] == '\0') 16088269Seric StatFile = "sendmail.st"; 16099381Seric else 16109381Seric StatFile = newstr(val); 16118256Seric break; 16128256Seric 16138265Seric case 's': /* be super safe, even if expensive */ 16149381Seric SuperSafe = atobool(val); 16158256Seric break; 16168256Seric 16178256Seric case 'T': /* queue timeout */ 161858737Seric p = strchr(val, '/'); 161958737Seric if (p != NULL) 162058737Seric { 162158737Seric *p++ = '\0'; 162267730Seric TimeOuts.to_q_warning[TOC_NORMAL] = convtime(p, 'd'); 162358737Seric } 162467730Seric TimeOuts.to_q_return[TOC_NORMAL] = convtime(val, 'h'); 162554967Seric break; 16268256Seric 16278265Seric case 't': /* time zone name */ 162852106Seric TimeZoneSpec = newstr(val); 16298265Seric break; 16308265Seric 163150556Seric case 'U': /* location of user database */ 163251360Seric UdbSpec = newstr(val); 163350556Seric break; 163450556Seric 16358256Seric case 'u': /* set default uid */ 1636*67823Seric for (p = val; *p != '\0'; p++) 1637*67823Seric { 1638*67823Seric if (*p == '.' || *p == '/' || *p == ':') 1639*67823Seric { 1640*67823Seric *p++ = '\0'; 1641*67823Seric break; 1642*67823Seric } 1643*67823Seric } 164464133Seric if (isascii(*val) && isdigit(*val)) 164564133Seric DefUid = atoi(val); 164664133Seric else 164764133Seric { 164864133Seric register struct passwd *pw; 164964133Seric 165064133Seric DefUid = -1; 165164133Seric pw = getpwnam(val); 165264133Seric if (pw == NULL) 165364133Seric syserr("readcf: option u: unknown user %s", val); 165464133Seric else 1655*67823Seric { 165664133Seric DefUid = pw->pw_uid; 1657*67823Seric DefGid = pw->pw_gid; 1658*67823Seric } 165964133Seric } 166040973Sbostic setdefuser(); 16618256Seric 1662*67823Seric /* handle the group if it is there */ 1663*67823Seric if (*p == '\0') 1664*67823Seric break; 1665*67823Seric val = p; 1666*67823Seric goto g_opt; 1667*67823Seric 166858851Seric case 'V': /* fallback MX host */ 166958851Seric FallBackMX = newstr(val); 167058851Seric break; 167158851Seric 16728269Seric case 'v': /* run in verbose mode */ 16739381Seric Verbose = atobool(val); 16748256Seric break; 16758256Seric 167663837Seric case 'w': /* if we are best MX, try host directly */ 167763837Seric TryNullMXList = atobool(val); 167863837Seric break; 167961104Seric 168061104Seric /* 'W' available -- was wizard password */ 168161104Seric 168214879Seric case 'x': /* load avg at which to auto-queue msgs */ 168314879Seric QueueLA = atoi(val); 168414879Seric break; 168514879Seric 168614879Seric case 'X': /* load avg at which to auto-reject connections */ 168714879Seric RefuseLA = atoi(val); 168814879Seric break; 168914879Seric 169024981Seric case 'y': /* work recipient factor */ 169124981Seric WkRecipFact = atoi(val); 169224981Seric break; 169324981Seric 169424981Seric case 'Y': /* fork jobs during queue runs */ 169524952Seric ForkQueueRuns = atobool(val); 169624952Seric break; 169724952Seric 169824981Seric case 'z': /* work message class factor */ 169924981Seric WkClassFact = atoi(val); 170024981Seric break; 170124981Seric 170224981Seric case 'Z': /* work time factor */ 170324981Seric WkTimeFact = atoi(val); 170424981Seric break; 170524981Seric 170667614Seric case O_BSP: /* SMTP Peers can't handle 2-line greeting */ 170767614Seric BrokenSmtpPeers = atobool(val); 170867614Seric break; 170967614Seric 171067614Seric case O_SQBH: /* sort work queue by host first */ 171167614Seric SortQueueByHost = atobool(val); 171267614Seric break; 171367614Seric 171467707Seric case O_DNICE: /* delivery nice value */ 171567707Seric DeliveryNiceness = atoi(val); 171667707Seric break; 171767707Seric 171867707Seric case O_MQA: /* minimum queue age between deliveries */ 171967707Seric MinQueueAge = convtime(val, 'm'); 172067707Seric break; 172167707Seric 172267707Seric case O_MHSA: /* maximum age of cached host status */ 172367707Seric MaxHostStatAge = convtime(val, 'm'); 172467707Seric break; 172567707Seric 172667813Seric case O_DEFCHARSET: /* default character set for mimefying */ 172767814Seric DefaultCharSet = newstr(val); 172867813Seric break; 172967813Seric 17308256Seric default: 17318256Seric break; 17328256Seric } 173316878Seric if (sticky) 173416878Seric setbitn(opt, StickyOpt); 17359188Seric return; 17368256Seric } 173710687Seric /* 173810687Seric ** SETCLASS -- set a word into a class 173910687Seric ** 174010687Seric ** Parameters: 174110687Seric ** class -- the class to put the word in. 174210687Seric ** word -- the word to enter 174310687Seric ** 174410687Seric ** Returns: 174510687Seric ** none. 174610687Seric ** 174710687Seric ** Side Effects: 174810687Seric ** puts the word into the symbol table. 174910687Seric */ 175010687Seric 175110687Seric setclass(class, word) 175210687Seric int class; 175310687Seric char *word; 175410687Seric { 175510687Seric register STAB *s; 175610687Seric 175757943Seric if (tTd(37, 8)) 175864326Seric printf("setclass(%c, %s)\n", class, word); 175910687Seric s = stab(word, ST_CLASS, ST_ENTER); 176010687Seric setbitn(class, s->s_class); 176110687Seric } 176253654Seric /* 176353654Seric ** MAKEMAPENTRY -- create a map entry 176453654Seric ** 176553654Seric ** Parameters: 176653654Seric ** line -- the config file line 176753654Seric ** 176853654Seric ** Returns: 176953654Seric ** TRUE if it successfully entered the map entry. 177053654Seric ** FALSE otherwise (usually syntax error). 177153654Seric ** 177253654Seric ** Side Effects: 177353654Seric ** Enters the map into the dictionary. 177453654Seric */ 177553654Seric 177653654Seric void 177753654Seric makemapentry(line) 177853654Seric char *line; 177953654Seric { 178053654Seric register char *p; 178153654Seric char *mapname; 178253654Seric char *classname; 178364078Seric register STAB *s; 178453654Seric STAB *class; 178553654Seric 178658050Seric for (p = line; isascii(*p) && isspace(*p); p++) 178753654Seric continue; 178858050Seric if (!(isascii(*p) && isalnum(*p))) 178953654Seric { 179053654Seric syserr("readcf: config K line: no map name"); 179153654Seric return; 179253654Seric } 179353654Seric 179453654Seric mapname = p; 179558050Seric while (isascii(*++p) && isalnum(*p)) 179653654Seric continue; 179753654Seric if (*p != '\0') 179853654Seric *p++ = '\0'; 179958050Seric while (isascii(*p) && isspace(*p)) 180053654Seric p++; 180158050Seric if (!(isascii(*p) && isalnum(*p))) 180253654Seric { 180353654Seric syserr("readcf: config K line, map %s: no map class", mapname); 180453654Seric return; 180553654Seric } 180653654Seric classname = p; 180758050Seric while (isascii(*++p) && isalnum(*p)) 180853654Seric continue; 180953654Seric if (*p != '\0') 181053654Seric *p++ = '\0'; 181158050Seric while (isascii(*p) && isspace(*p)) 181253654Seric p++; 181353654Seric 181453654Seric /* look up the class */ 181553654Seric class = stab(classname, ST_MAPCLASS, ST_FIND); 181653654Seric if (class == NULL) 181753654Seric { 181853654Seric syserr("readcf: map %s: class %s not available", mapname, classname); 181953654Seric return; 182053654Seric } 182153654Seric 182253654Seric /* enter the map */ 182364078Seric s = stab(mapname, ST_MAP, ST_ENTER); 182464078Seric s->s_map.map_class = &class->s_mapclass; 182564078Seric s->s_map.map_mname = newstr(mapname); 182653654Seric 182764078Seric if (class->s_mapclass.map_parse(&s->s_map, p)) 182864078Seric s->s_map.map_mflags |= MF_VALID; 182964078Seric 183064078Seric if (tTd(37, 5)) 183164078Seric { 183264078Seric printf("map %s, class %s, flags %x, file %s,\n", 183364078Seric s->s_map.map_mname, s->s_map.map_class->map_cname, 183464078Seric s->s_map.map_mflags, 183564078Seric s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 183664078Seric printf("\tapp %s, domain %s, rebuild %s\n", 183764078Seric s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 183864078Seric s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 183964078Seric s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 184064078Seric } 184153654Seric } 184258112Seric /* 184358112Seric ** SETTIMEOUTS -- parse and set timeout values 184458112Seric ** 184558112Seric ** Parameters: 184658112Seric ** val -- a pointer to the values. If NULL, do initial 184758112Seric ** settings. 184858112Seric ** 184958112Seric ** Returns: 185058112Seric ** none. 185158112Seric ** 185258112Seric ** Side Effects: 185358112Seric ** Initializes the TimeOuts structure 185458112Seric */ 185558112Seric 185664255Seric #define SECONDS 185758112Seric #define MINUTES * 60 185858112Seric #define HOUR * 3600 185958112Seric 186058112Seric settimeouts(val) 186158112Seric register char *val; 186258112Seric { 186358112Seric register char *p; 186458671Seric extern time_t convtime(); 186558112Seric 186658112Seric if (val == NULL) 186758112Seric { 186858112Seric TimeOuts.to_initial = (time_t) 5 MINUTES; 186958112Seric TimeOuts.to_helo = (time_t) 5 MINUTES; 187058112Seric TimeOuts.to_mail = (time_t) 10 MINUTES; 187158112Seric TimeOuts.to_rcpt = (time_t) 1 HOUR; 187258112Seric TimeOuts.to_datainit = (time_t) 5 MINUTES; 187358112Seric TimeOuts.to_datablock = (time_t) 1 HOUR; 187458112Seric TimeOuts.to_datafinal = (time_t) 1 HOUR; 187558112Seric TimeOuts.to_rset = (time_t) 5 MINUTES; 187658112Seric TimeOuts.to_quit = (time_t) 2 MINUTES; 187758112Seric TimeOuts.to_nextcommand = (time_t) 1 HOUR; 187858112Seric TimeOuts.to_miscshort = (time_t) 2 MINUTES; 187964255Seric TimeOuts.to_ident = (time_t) 30 SECONDS; 188067711Seric TimeOuts.to_fileopen = (time_t) 60 SECONDS; 188158112Seric return; 188258112Seric } 188358112Seric 188458112Seric for (;; val = p) 188558112Seric { 188658112Seric while (isascii(*val) && isspace(*val)) 188758112Seric val++; 188858112Seric if (*val == '\0') 188958112Seric break; 189058112Seric for (p = val; *p != '\0' && *p != ','; p++) 189158112Seric continue; 189258112Seric if (*p != '\0') 189358112Seric *p++ = '\0'; 189458112Seric 189558112Seric if (isascii(*val) && isdigit(*val)) 189658112Seric { 189758112Seric /* old syntax -- set everything */ 189858796Seric TimeOuts.to_mail = convtime(val, 'm'); 189958112Seric TimeOuts.to_rcpt = TimeOuts.to_mail; 190058112Seric TimeOuts.to_datainit = TimeOuts.to_mail; 190158112Seric TimeOuts.to_datablock = TimeOuts.to_mail; 190258112Seric TimeOuts.to_datafinal = TimeOuts.to_mail; 190358112Seric TimeOuts.to_nextcommand = TimeOuts.to_mail; 190458112Seric continue; 190558112Seric } 190658112Seric else 190758112Seric { 190867711Seric register char *q = strchr(val, ':'); 190958112Seric time_t to; 191058112Seric 191167711Seric if (q == NULL && (q = strchr(val, '=')) == NULL) 191258112Seric { 191358112Seric /* syntax error */ 191458112Seric continue; 191558112Seric } 191658112Seric *q++ = '\0'; 191758796Seric to = convtime(q, 'm'); 191858112Seric 191958112Seric if (strcasecmp(val, "initial") == 0) 192058112Seric TimeOuts.to_initial = to; 192158112Seric else if (strcasecmp(val, "mail") == 0) 192258112Seric TimeOuts.to_mail = to; 192358112Seric else if (strcasecmp(val, "rcpt") == 0) 192458112Seric TimeOuts.to_rcpt = to; 192558112Seric else if (strcasecmp(val, "datainit") == 0) 192658112Seric TimeOuts.to_datainit = to; 192758112Seric else if (strcasecmp(val, "datablock") == 0) 192858112Seric TimeOuts.to_datablock = to; 192958112Seric else if (strcasecmp(val, "datafinal") == 0) 193058112Seric TimeOuts.to_datafinal = to; 193158112Seric else if (strcasecmp(val, "command") == 0) 193258112Seric TimeOuts.to_nextcommand = to; 193358112Seric else if (strcasecmp(val, "rset") == 0) 193458112Seric TimeOuts.to_rset = to; 193558112Seric else if (strcasecmp(val, "helo") == 0) 193658112Seric TimeOuts.to_helo = to; 193758112Seric else if (strcasecmp(val, "quit") == 0) 193858112Seric TimeOuts.to_quit = to; 193958112Seric else if (strcasecmp(val, "misc") == 0) 194058112Seric TimeOuts.to_miscshort = to; 194164255Seric else if (strcasecmp(val, "ident") == 0) 194264255Seric TimeOuts.to_ident = to; 194367711Seric else if (strcasecmp(val, "fileopen") == 0) 194467711Seric TimeOuts.to_fileopen = to; 194567711Seric else if (strcasecmp(val, "queuewarn") == 0) 194667730Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 194767711Seric else if (strcasecmp(val, "queuereturn") == 0) 194867730Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 194967730Seric else if (strcasecmp(val, "queuewarn.normal") == 0) 195067730Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 195167730Seric else if (strcasecmp(val, "queuereturn.normal") == 0) 195267730Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 195367730Seric else if (strcasecmp(val, "queuewarn.urgent") == 0) 195467730Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 195567730Seric else if (strcasecmp(val, "queuereturn.urgent") == 0) 195667730Seric TimeOuts.to_q_return[TOC_URGENT] = to; 195767730Seric else if (strcasecmp(val, "queuewarn.non-urgent") == 0) 195867730Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 195967730Seric else if (strcasecmp(val, "queuereturn.non-urgent") == 0) 196067730Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 196158112Seric else 196258112Seric syserr("settimeouts: invalid timeout %s", val); 196358112Seric } 196458112Seric } 196558112Seric } 1966