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*67903Seric static char sccsid[] = "@(#)readcf.c 8.46 (Berkeley) 11/12/94"; 1133731Sbostic #endif /* not lint */ 1222709Sdist 133313Seric # include "sendmail.h" 1464133Seric # include <pwd.h> 1564133Seric # include <grp.h> 1666334Seric #if NAMED_BIND 1757207Seric # include <resolv.h> 1857207Seric #endif 193308Seric 203308Seric /* 213308Seric ** READCF -- read control file. 223308Seric ** 233308Seric ** This routine reads the control file and builds the internal 243308Seric ** form. 253308Seric ** 264432Seric ** The file is formatted as a sequence of lines, each taken 274432Seric ** atomically. The first character of each line describes how 284432Seric ** the line is to be interpreted. The lines are: 294432Seric ** Dxval Define macro x to have value val. 304432Seric ** Cxword Put word into class x. 314432Seric ** Fxfile [fmt] Read file for lines to put into 324432Seric ** class x. Use scanf string 'fmt' 334432Seric ** or "%s" if not present. Fmt should 344432Seric ** only produce one string-valued result. 354432Seric ** Hname: value Define header with field-name 'name' 364432Seric ** and value as specified; this will be 374432Seric ** macro expanded immediately before 384432Seric ** use. 394432Seric ** Sn Use rewriting set n. 404432Seric ** Rlhs rhs Rewrite addresses that match lhs to 414432Seric ** be rhs. 4224944Seric ** Mn arg=val... Define mailer. n is the internal name. 4324944Seric ** Args specify mailer parameters. 448252Seric ** Oxvalue Set option x to value. 458252Seric ** Pname=value Set precedence name to value. 4664718Seric ** Vversioncode[/vendorcode] 4764718Seric ** Version level/vendor name of 4864718Seric ** configuration syntax. 4953654Seric ** Kmapname mapclass arguments.... 5053654Seric ** Define keyed lookup of a given class. 5153654Seric ** Arguments are class dependent. 524432Seric ** 533308Seric ** Parameters: 543308Seric ** cfname -- control file name. 5554973Seric ** safe -- TRUE if this is the system config file; 5654973Seric ** FALSE otherwise. 5755012Seric ** e -- the main envelope. 583308Seric ** 593308Seric ** Returns: 603308Seric ** none. 613308Seric ** 623308Seric ** Side Effects: 633308Seric ** Builds several internal tables. 643308Seric */ 653308Seric 6655012Seric readcf(cfname, safe, e) 673308Seric char *cfname; 6854973Seric bool safe; 6955012Seric register ENVELOPE *e; 703308Seric { 713308Seric FILE *cf; 728547Seric int ruleset = 0; 738547Seric char *q; 749350Seric struct rewrite *rwp = NULL; 7557135Seric char *bp; 7664718Seric auto char *ep; 7757589Seric int nfuzzy; 7864133Seric char *file; 7964133Seric bool optional; 8067769Seric int mid; 813308Seric char buf[MAXLINE]; 823308Seric register char *p; 833308Seric extern char **copyplist(); 8452647Seric struct stat statb; 855909Seric char exbuf[MAXLINE]; 8665066Seric char pvpbuf[MAXLINE + MAXATOM]; 8767826Seric static char *null_list[1] = { NULL }; 8810709Seric extern char *munchstring(); 8953654Seric extern void makemapentry(); 903308Seric 9152647Seric FileName = cfname; 9252647Seric LineNumber = 0; 9352647Seric 943308Seric cf = fopen(cfname, "r"); 953308Seric if (cf == NULL) 963308Seric { 9752647Seric syserr("cannot open"); 983308Seric exit(EX_OSFILE); 993308Seric } 1003308Seric 10152647Seric if (fstat(fileno(cf), &statb) < 0) 10252647Seric { 10352647Seric syserr("cannot fstat"); 10452647Seric exit(EX_OSFILE); 10552647Seric } 10652647Seric 10752647Seric if (!S_ISREG(statb.st_mode)) 10852647Seric { 10952647Seric syserr("not a plain file"); 11052647Seric exit(EX_OSFILE); 11152647Seric } 11252647Seric 11352647Seric if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode)) 11452647Seric { 11553037Seric if (OpMode == MD_DAEMON || OpMode == MD_FREEZE) 11653037Seric fprintf(stderr, "%s: WARNING: dangerous write permissions\n", 11753037Seric FileName); 11853037Seric #ifdef LOG 11953037Seric if (LogLevel > 0) 12053037Seric syslog(LOG_CRIT, "%s: WARNING: dangerous write permissions", 12153037Seric FileName); 12253037Seric #endif 12352647Seric } 12452647Seric 12559254Seric #ifdef XLA 12659254Seric xla_zero(); 12759254Seric #endif 12859254Seric 12957135Seric while ((bp = fgetfolded(buf, sizeof buf, cf)) != NULL) 1303308Seric { 13157135Seric if (bp[0] == '#') 13257135Seric { 13357135Seric if (bp != buf) 13457135Seric free(bp); 13552637Seric continue; 13657135Seric } 13752637Seric 13867769Seric /* do macro expansion mappings */ 13957135Seric for (p = bp; *p != '\0'; p++) 14016157Seric { 14157135Seric if (*p == '#' && p > bp && ConfigLevel >= 3) 14252647Seric { 14352647Seric /* this is an on-line comment */ 14452647Seric register char *e; 14552647Seric 14658050Seric switch (*--p & 0377) 14752647Seric { 14858050Seric case MACROEXPAND: 14952647Seric /* it's from $# -- let it go through */ 15052647Seric p++; 15152647Seric break; 15252647Seric 15352647Seric case '\\': 15452647Seric /* it's backslash escaped */ 15552647Seric (void) strcpy(p, p + 1); 15652647Seric break; 15752647Seric 15852647Seric default: 15952647Seric /* delete preceeding white space */ 16058050Seric while (isascii(*p) && isspace(*p) && p > bp) 16152647Seric p--; 16256795Seric if ((e = strchr(++p, '\n')) != NULL) 16352647Seric (void) strcpy(p, e); 16452647Seric else 16552647Seric p[0] = p[1] = '\0'; 16652647Seric break; 16752647Seric } 16852647Seric continue; 16952647Seric } 17052647Seric 17167769Seric if (*p != '$' || p[1] == '\0') 17216157Seric continue; 17316157Seric 17416157Seric if (p[1] == '$') 17516157Seric { 17616157Seric /* actual dollar sign.... */ 17723111Seric (void) strcpy(p, p + 1); 17816157Seric continue; 17916157Seric } 18016157Seric 18116157Seric /* convert to macro expansion character */ 18267769Seric *p++ = MACROEXPAND; 18367769Seric 18467769Seric /* convert macro name to code */ 18567769Seric *p = macid(p, &ep); 18667769Seric if (ep != p) 18767769Seric strcpy(p + 1, ep); 18816157Seric } 18916157Seric 19016157Seric /* interpret this line */ 19164718Seric errno = 0; 19257135Seric switch (bp[0]) 1933308Seric { 1943308Seric case '\0': 1953308Seric case '#': /* comment */ 1963308Seric break; 1973308Seric 1983308Seric case 'R': /* rewriting rule */ 19957135Seric for (p = &bp[1]; *p != '\0' && *p != '\t'; p++) 2003308Seric continue; 2013308Seric 2023308Seric if (*p == '\0') 2035909Seric { 20465821Seric syserr("invalid rewrite line \"%s\" (tab expected)", bp); 2055909Seric break; 2065909Seric } 2075909Seric 2085909Seric /* allocate space for the rule header */ 2095909Seric if (rwp == NULL) 2105909Seric { 2115909Seric RewriteRules[ruleset] = rwp = 2125909Seric (struct rewrite *) xalloc(sizeof *rwp); 2135909Seric } 2143308Seric else 2153308Seric { 2165909Seric rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp); 2175909Seric rwp = rwp->r_next; 2185909Seric } 2195909Seric rwp->r_next = NULL; 2203308Seric 2215909Seric /* expand and save the LHS */ 2225909Seric *p = '\0'; 22357135Seric expand(&bp[1], exbuf, &exbuf[sizeof exbuf], e); 22465066Seric rwp->r_lhs = prescan(exbuf, '\t', pvpbuf, 22565066Seric sizeof pvpbuf, NULL); 22657589Seric nfuzzy = 0; 2275909Seric if (rwp->r_lhs != NULL) 22857589Seric { 22957589Seric register char **ap; 23057589Seric 2315909Seric rwp->r_lhs = copyplist(rwp->r_lhs, TRUE); 23257589Seric 23357589Seric /* count the number of fuzzy matches in LHS */ 23457589Seric for (ap = rwp->r_lhs; *ap != NULL; ap++) 23557589Seric { 23658148Seric char *botch; 23758148Seric 23858148Seric botch = NULL; 23958050Seric switch (**ap & 0377) 24057589Seric { 24157589Seric case MATCHZANY: 24257589Seric case MATCHANY: 24357589Seric case MATCHONE: 24457589Seric case MATCHCLASS: 24557589Seric case MATCHNCLASS: 24657589Seric nfuzzy++; 24758148Seric break; 24858148Seric 24958148Seric case MATCHREPL: 25058148Seric botch = "$0-$9"; 25158148Seric break; 25258148Seric 25358148Seric case CANONNET: 25458148Seric botch = "$#"; 25558148Seric break; 25658148Seric 25758148Seric case CANONUSER: 25858148Seric botch = "$:"; 25958148Seric break; 26058148Seric 26158148Seric case CALLSUBR: 26258148Seric botch = "$>"; 26358148Seric break; 26458148Seric 26558148Seric case CONDIF: 26658148Seric botch = "$?"; 26758148Seric break; 26858148Seric 26958148Seric case CONDELSE: 27058148Seric botch = "$|"; 27158148Seric break; 27258148Seric 27358148Seric case CONDFI: 27458148Seric botch = "$."; 27558148Seric break; 27658148Seric 27758148Seric case HOSTBEGIN: 27858148Seric botch = "$["; 27958148Seric break; 28058148Seric 28158148Seric case HOSTEND: 28258148Seric botch = "$]"; 28358148Seric break; 28458148Seric 28558148Seric case LOOKUPBEGIN: 28658148Seric botch = "$("; 28758148Seric break; 28858148Seric 28958148Seric case LOOKUPEND: 29058148Seric botch = "$)"; 29158148Seric break; 29257589Seric } 29358148Seric if (botch != NULL) 29458148Seric syserr("Inappropriate use of %s on LHS", 29558148Seric botch); 29657589Seric } 29757589Seric } 29856678Seric else 29967826Seric { 30056678Seric syserr("R line: null LHS"); 30167826Seric rwp->r_lhs = null_list; 30267826Seric } 3035909Seric 3045909Seric /* expand and save the RHS */ 3055909Seric while (*++p == '\t') 3065909Seric continue; 3077231Seric q = p; 3087231Seric while (*p != '\0' && *p != '\t') 3097231Seric p++; 3107231Seric *p = '\0'; 31155012Seric expand(q, exbuf, &exbuf[sizeof exbuf], e); 31265066Seric rwp->r_rhs = prescan(exbuf, '\t', pvpbuf, 31365066Seric sizeof pvpbuf, NULL); 3145909Seric if (rwp->r_rhs != NULL) 31557589Seric { 31657589Seric register char **ap; 31757589Seric 3185909Seric rwp->r_rhs = copyplist(rwp->r_rhs, TRUE); 31957589Seric 32057589Seric /* check no out-of-bounds replacements */ 32157589Seric nfuzzy += '0'; 32257589Seric for (ap = rwp->r_rhs; *ap != NULL; ap++) 32357589Seric { 32458148Seric char *botch; 32558148Seric 32658148Seric botch = NULL; 32758148Seric switch (**ap & 0377) 32857589Seric { 32958148Seric case MATCHREPL: 33058148Seric if ((*ap)[1] <= '0' || (*ap)[1] > nfuzzy) 33158148Seric { 33258148Seric syserr("replacement $%c out of bounds", 33358148Seric (*ap)[1]); 33458148Seric } 33558148Seric break; 33658148Seric 33758148Seric case MATCHZANY: 33858148Seric botch = "$*"; 33958148Seric break; 34058148Seric 34158148Seric case MATCHANY: 34258148Seric botch = "$+"; 34358148Seric break; 34458148Seric 34558148Seric case MATCHONE: 34658148Seric botch = "$-"; 34758148Seric break; 34858148Seric 34958148Seric case MATCHCLASS: 35058148Seric botch = "$="; 35158148Seric break; 35258148Seric 35358148Seric case MATCHNCLASS: 35458148Seric botch = "$~"; 35558148Seric break; 35657589Seric } 35758148Seric if (botch != NULL) 35858148Seric syserr("Inappropriate use of %s on RHS", 35958148Seric botch); 36057589Seric } 36157589Seric } 36256678Seric else 36367826Seric { 36456678Seric syserr("R line: null RHS"); 36567826Seric rwp->r_rhs = null_list; 36667826Seric } 3673308Seric break; 3683308Seric 3694072Seric case 'S': /* select rewriting set */ 37064440Seric for (p = &bp[1]; isascii(*p) && isspace(*p); p++) 37164440Seric continue; 37264440Seric if (!isascii(*p) || !isdigit(*p)) 37364440Seric { 37464440Seric syserr("invalid argument to S line: \"%.20s\"", 37564440Seric &bp[1]); 37664440Seric break; 37764440Seric } 37864440Seric ruleset = atoi(p); 3798056Seric if (ruleset >= MAXRWSETS || ruleset < 0) 3808056Seric { 3819381Seric syserr("bad ruleset %d (%d max)", ruleset, MAXRWSETS); 3828056Seric ruleset = 0; 3838056Seric } 3844072Seric rwp = NULL; 3854072Seric break; 3864072Seric 3873308Seric case 'D': /* macro definition */ 38867769Seric mid = macid(&bp[1], &ep); 38967769Seric p = munchstring(ep, NULL); 39067769Seric define(mid, newstr(p), e); 3913308Seric break; 3923308Seric 3933387Seric case 'H': /* required header line */ 39457135Seric (void) chompheader(&bp[1], TRUE, e); 3953387Seric break; 3963387Seric 3974061Seric case 'C': /* word class */ 3984432Seric /* scan the list of words and set class for all */ 39967769Seric mid = macid(&bp[1], &ep); 40067769Seric expand(ep, exbuf, &exbuf[sizeof exbuf], e); 40164121Seric for (p = exbuf; *p != '\0'; ) 4024061Seric { 4034061Seric register char *wd; 4044061Seric char delim; 4054061Seric 40658050Seric while (*p != '\0' && isascii(*p) && isspace(*p)) 4074061Seric p++; 4084061Seric wd = p; 40958050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 4104061Seric p++; 4114061Seric delim = *p; 4124061Seric *p = '\0'; 4134061Seric if (wd[0] != '\0') 41467769Seric setclass(mid, wd); 4154061Seric *p = delim; 4164061Seric } 4174061Seric break; 4184061Seric 41959272Seric case 'F': /* word class from file */ 42067769Seric mid = macid(&bp[1], &ep); 42167769Seric for (p = ep; isascii(*p) && isspace(*p); ) 42264133Seric p++; 42364133Seric if (p[0] == '-' && p[1] == 'o') 42464133Seric { 42564133Seric optional = TRUE; 42664133Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 42764133Seric p++; 42864133Seric while (isascii(*p) && isspace(*p)) 42967615Seric p++; 43064133Seric } 43164133Seric else 43264133Seric optional = FALSE; 43364133Seric file = p; 43464133Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 43564133Seric p++; 43659272Seric if (*p == '\0') 43759272Seric p = "%s"; 43859272Seric else 43959272Seric { 44059272Seric *p = '\0'; 44159272Seric while (isascii(*++p) && isspace(*p)) 44259272Seric continue; 44359272Seric } 44464133Seric fileclass(bp[1], file, p, safe, optional); 44559272Seric break; 44659272Seric 44759156Seric #ifdef XLA 44859156Seric case 'L': /* extended load average description */ 44959156Seric xla_init(&bp[1]); 45059156Seric break; 45159156Seric #endif 45259156Seric 4534096Seric case 'M': /* define mailer */ 45457135Seric makemailer(&bp[1]); 4554096Seric break; 4564096Seric 4578252Seric case 'O': /* set option */ 45858734Seric setoption(bp[1], &bp[2], safe, FALSE, e); 4598252Seric break; 4608252Seric 4618252Seric case 'P': /* set precedence */ 4628252Seric if (NumPriorities >= MAXPRIORITIES) 4638252Seric { 4648547Seric toomany('P', MAXPRIORITIES); 4658252Seric break; 4668252Seric } 46757135Seric for (p = &bp[1]; *p != '\0' && *p != '=' && *p != '\t'; p++) 4688252Seric continue; 4698252Seric if (*p == '\0') 4708252Seric goto badline; 4718252Seric *p = '\0'; 47257135Seric Priorities[NumPriorities].pri_name = newstr(&bp[1]); 4738252Seric Priorities[NumPriorities].pri_val = atoi(++p); 4748252Seric NumPriorities++; 4758252Seric break; 4768252Seric 4778547Seric case 'T': /* trusted user(s) */ 47858161Seric /* this option is obsolete, but will be ignored */ 4798547Seric break; 4808547Seric 48152645Seric case 'V': /* configuration syntax version */ 48264440Seric for (p = &bp[1]; isascii(*p) && isspace(*p); p++) 48364440Seric continue; 48464440Seric if (!isascii(*p) || !isdigit(*p)) 48564440Seric { 48664440Seric syserr("invalid argument to V line: \"%.20s\"", 48764440Seric &bp[1]); 48864440Seric break; 48964440Seric } 49064718Seric ConfigLevel = strtol(p, &ep, 10); 49164279Seric if (ConfigLevel >= 5) 49264279Seric { 49364279Seric /* level 5 configs have short name in $w */ 49464279Seric p = macvalue('w', e); 49564279Seric if (p != NULL && (p = strchr(p, '.')) != NULL) 49664279Seric *p = '\0'; 49764279Seric } 49864718Seric if (*ep++ == '/') 49964718Seric { 50064718Seric /* extract vendor code */ 50164718Seric for (p = ep; isascii(*p) && isalpha(*p); ) 50264718Seric p++; 50364718Seric *p = '\0'; 50464718Seric 50564718Seric if (!setvendor(ep)) 50664718Seric syserr("invalid V line vendor code: \"%s\"", 50764718Seric ep); 50864718Seric } 50952645Seric break; 51052645Seric 51153654Seric case 'K': 51257135Seric makemapentry(&bp[1]); 51353654Seric break; 51453654Seric 5153308Seric default: 5164061Seric badline: 51757135Seric syserr("unknown control line \"%s\"", bp); 5183308Seric } 51957135Seric if (bp != buf) 52057135Seric free(bp); 5213308Seric } 52252637Seric if (ferror(cf)) 52352637Seric { 52452647Seric syserr("I/O read error", cfname); 52552637Seric exit(EX_OSFILE); 52652637Seric } 52752637Seric fclose(cf); 5289381Seric FileName = NULL; 52956836Seric 53067730Seric /* initialize host maps from local service tables */ 53167730Seric inithostmaps(); 5324096Seric } 5334096Seric /* 5348547Seric ** TOOMANY -- signal too many of some option 5358547Seric ** 5368547Seric ** Parameters: 5378547Seric ** id -- the id of the error line 5388547Seric ** maxcnt -- the maximum possible values 5398547Seric ** 5408547Seric ** Returns: 5418547Seric ** none. 5428547Seric ** 5438547Seric ** Side Effects: 5448547Seric ** gives a syserr. 5458547Seric */ 5468547Seric 5478547Seric toomany(id, maxcnt) 5488547Seric char id; 5498547Seric int maxcnt; 5508547Seric { 5519381Seric syserr("too many %c lines, %d max", id, maxcnt); 5528547Seric } 5538547Seric /* 5544432Seric ** FILECLASS -- read members of a class from a file 5554432Seric ** 5564432Seric ** Parameters: 5574432Seric ** class -- class to define. 5584432Seric ** filename -- name of file to read. 5594432Seric ** fmt -- scanf string to use for match. 56064133Seric ** safe -- if set, this is a safe read. 56164133Seric ** optional -- if set, it is not an error for the file to 56264133Seric ** not exist. 5634432Seric ** 5644432Seric ** Returns: 5654432Seric ** none 5664432Seric ** 5674432Seric ** Side Effects: 5684432Seric ** 5694432Seric ** puts all lines in filename that match a scanf into 5704432Seric ** the named class. 5714432Seric */ 5724432Seric 57364133Seric fileclass(class, filename, fmt, safe, optional) 5744432Seric int class; 5754432Seric char *filename; 5764432Seric char *fmt; 57754973Seric bool safe; 57864133Seric bool optional; 5794432Seric { 58025808Seric FILE *f; 58154973Seric struct stat stbuf; 5824432Seric char buf[MAXLINE]; 5834432Seric 58466101Seric if (tTd(37, 2)) 58566101Seric printf("fileclass(%s, fmt=%s)\n", filename, fmt); 58666101Seric 58766031Seric if (filename[0] == '|') 58866031Seric { 58966031Seric syserr("fileclass: pipes (F%c%s) not supported due to security problems", 59066031Seric class, filename); 59166031Seric return; 59266031Seric } 59354973Seric if (stat(filename, &stbuf) < 0) 59454973Seric { 59566101Seric if (tTd(37, 2)) 59666101Seric printf(" cannot stat (%s)\n", errstring(errno)); 59764133Seric if (!optional) 59864133Seric syserr("fileclass: cannot stat %s", filename); 59954973Seric return; 60054973Seric } 60154973Seric if (!S_ISREG(stbuf.st_mode)) 60254973Seric { 60354973Seric syserr("fileclass: %s not a regular file", filename); 60454973Seric return; 60554973Seric } 60654973Seric if (!safe && access(filename, R_OK) < 0) 60754973Seric { 60854973Seric syserr("fileclass: access denied on %s", filename); 60954973Seric return; 61054973Seric } 61154973Seric f = fopen(filename, "r"); 6124432Seric if (f == NULL) 6134432Seric { 61454973Seric syserr("fileclass: cannot open %s", filename); 6154432Seric return; 6164432Seric } 6174432Seric 6184432Seric while (fgets(buf, sizeof buf, f) != NULL) 6194432Seric { 6204432Seric register STAB *s; 62125808Seric register char *p; 62225808Seric # ifdef SCANF 6234432Seric char wordbuf[MAXNAME+1]; 6244432Seric 6254432Seric if (sscanf(buf, fmt, wordbuf) != 1) 6264432Seric continue; 62725808Seric p = wordbuf; 62856795Seric # else /* SCANF */ 62925808Seric p = buf; 63056795Seric # endif /* SCANF */ 63125808Seric 63225808Seric /* 63325808Seric ** Break up the match into words. 63425808Seric */ 63525808Seric 63625808Seric while (*p != '\0') 63725808Seric { 63825808Seric register char *q; 63925808Seric 64025808Seric /* strip leading spaces */ 64158050Seric while (isascii(*p) && isspace(*p)) 64225808Seric p++; 64325808Seric if (*p == '\0') 64425808Seric break; 64525808Seric 64625808Seric /* find the end of the word */ 64725808Seric q = p; 64858050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 64925808Seric p++; 65025808Seric if (*p != '\0') 65125808Seric *p++ = '\0'; 65225808Seric 65325808Seric /* enter the word in the symbol table */ 65466101Seric setclass(class, q); 65525808Seric } 6564432Seric } 6574432Seric 65854973Seric (void) fclose(f); 6594432Seric } 6604432Seric /* 6614096Seric ** MAKEMAILER -- define a new mailer. 6624096Seric ** 6634096Seric ** Parameters: 66410327Seric ** line -- description of mailer. This is in labeled 66510327Seric ** fields. The fields are: 66610327Seric ** P -- the path to the mailer 66710327Seric ** F -- the flags associated with the mailer 66810327Seric ** A -- the argv for this mailer 66910327Seric ** S -- the sender rewriting set 67010327Seric ** R -- the recipient rewriting set 67110327Seric ** E -- the eol string 67210327Seric ** The first word is the canonical name of the mailer. 6734096Seric ** 6744096Seric ** Returns: 6754096Seric ** none. 6764096Seric ** 6774096Seric ** Side Effects: 6784096Seric ** enters the mailer into the mailer table. 6794096Seric */ 6803308Seric 68121066Seric makemailer(line) 6824096Seric char *line; 6834096Seric { 6844096Seric register char *p; 6858067Seric register struct mailer *m; 6868067Seric register STAB *s; 6878067Seric int i; 68810327Seric char fcode; 68958020Seric auto char *endp; 6904096Seric extern int NextMailer; 69110327Seric extern char **makeargv(); 69210327Seric extern char *munchstring(); 69310701Seric extern long atol(); 6944096Seric 69510327Seric /* allocate a mailer and set up defaults */ 69610327Seric m = (struct mailer *) xalloc(sizeof *m); 69710327Seric bzero((char *) m, sizeof *m); 69810327Seric m->m_eol = "\n"; 69967604Seric m->m_uid = m->m_gid = 0; 70010327Seric 70110327Seric /* collect the mailer name */ 70258050Seric for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++) 70310327Seric continue; 70410327Seric if (*p != '\0') 70510327Seric *p++ = '\0'; 70610327Seric m->m_name = newstr(line); 70710327Seric 70810327Seric /* now scan through and assign info from the fields */ 70910327Seric while (*p != '\0') 71010327Seric { 71158333Seric auto char *delimptr; 71258333Seric 71358050Seric while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p)))) 71410327Seric p++; 71510327Seric 71610327Seric /* p now points to field code */ 71710327Seric fcode = *p; 71810327Seric while (*p != '\0' && *p != '=' && *p != ',') 71910327Seric p++; 72010327Seric if (*p++ != '=') 72110327Seric { 72252637Seric syserr("mailer %s: `=' expected", m->m_name); 72310327Seric return; 72410327Seric } 72558050Seric while (isascii(*p) && isspace(*p)) 72610327Seric p++; 72710327Seric 72810327Seric /* p now points to the field body */ 72958333Seric p = munchstring(p, &delimptr); 73010327Seric 73110327Seric /* install the field into the mailer struct */ 73210327Seric switch (fcode) 73310327Seric { 73410327Seric case 'P': /* pathname */ 73510327Seric m->m_mailer = newstr(p); 73610327Seric break; 73710327Seric 73810327Seric case 'F': /* flags */ 73910687Seric for (; *p != '\0'; p++) 74058050Seric if (!(isascii(*p) && isspace(*p))) 74152637Seric setbitn(*p, m->m_flags); 74210327Seric break; 74310327Seric 74410327Seric case 'S': /* sender rewriting ruleset */ 74510327Seric case 'R': /* recipient rewriting ruleset */ 74658020Seric i = strtol(p, &endp, 10); 74710327Seric if (i < 0 || i >= MAXRWSETS) 74810327Seric { 74910327Seric syserr("invalid rewrite set, %d max", MAXRWSETS); 75010327Seric return; 75110327Seric } 75210327Seric if (fcode == 'S') 75358020Seric m->m_sh_rwset = m->m_se_rwset = i; 75410327Seric else 75558020Seric m->m_rh_rwset = m->m_re_rwset = i; 75658020Seric 75758020Seric p = endp; 75859985Seric if (*p++ == '/') 75958020Seric { 76058020Seric i = strtol(p, NULL, 10); 76158020Seric if (i < 0 || i >= MAXRWSETS) 76258020Seric { 76358020Seric syserr("invalid rewrite set, %d max", 76458020Seric MAXRWSETS); 76558020Seric return; 76658020Seric } 76758020Seric if (fcode == 'S') 76858020Seric m->m_sh_rwset = i; 76958020Seric else 77058020Seric m->m_rh_rwset = i; 77158020Seric } 77210327Seric break; 77310327Seric 77410327Seric case 'E': /* end of line string */ 77510327Seric m->m_eol = newstr(p); 77610327Seric break; 77710327Seric 77810327Seric case 'A': /* argument vector */ 77910327Seric m->m_argv = makeargv(p); 78010327Seric break; 78110701Seric 78210701Seric case 'M': /* maximum message size */ 78310701Seric m->m_maxsize = atol(p); 78410701Seric break; 78552106Seric 78652106Seric case 'L': /* maximum line length */ 78752106Seric m->m_linelimit = atoi(p); 78852106Seric break; 78958935Seric 79058935Seric case 'D': /* working directory */ 79158935Seric m->m_execdir = newstr(p); 79258935Seric break; 79367604Seric 79467896Seric case 'C': /* default charset */ 79567896Seric m->m_defcharset = newstr(p); 79667896Seric break; 79767896Seric 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, 115067848Seric #define O_SSFILE 0x86 115167848Seric "ServiceSwitchFile", O_SSFILE, FALSE, 115267707Seric 115367707Seric NULL, '\0', FALSE, 115467614Seric }; 115567614Seric 115667614Seric 115767614Seric 115858734Seric setoption(opt, val, safe, sticky, e) 115967614Seric u_char opt; 11608256Seric char *val; 116121755Seric bool safe; 11628269Seric bool sticky; 116358734Seric register ENVELOPE *e; 11648256Seric { 116557207Seric register char *p; 116667614Seric register struct optioninfo *o; 1167*67903Seric char *subopt; 11688265Seric extern bool atobool(); 116912633Seric extern time_t convtime(); 117014879Seric extern int QueueLA; 117114879Seric extern int RefuseLA; 117264718Seric extern bool Warn_Q_option; 11738256Seric 117467736Seric errno = 0; 117567614Seric if (opt == ' ') 117667614Seric { 117767614Seric /* full word options */ 117867736Seric struct optioninfo *sel; 117967614Seric 118067614Seric p = strchr(val, '='); 118167614Seric if (p == NULL) 118267614Seric p = &val[strlen(val)]; 118367614Seric while (*--p == ' ') 118467614Seric continue; 118567614Seric while (*++p == ' ') 118667614Seric *p = '\0'; 118767731Seric if (p == val) 118867731Seric { 118967731Seric syserr("readcf: null option name"); 119067731Seric return; 119167731Seric } 119267614Seric if (*p == '=') 119367614Seric *p++ = '\0'; 119467614Seric while (*p == ' ') 119567614Seric p++; 1196*67903Seric subopt = strchr(val, '.'); 1197*67903Seric if (subopt != NULL) 1198*67903Seric *subopt++ = '\0'; 119967736Seric sel = NULL; 120067614Seric for (o = OptionTab; o->o_name != NULL; o++) 120167614Seric { 120267736Seric if (strncasecmp(o->o_name, val, strlen(val)) != 0) 120367736Seric continue; 120467736Seric if (strlen(o->o_name) == strlen(val)) 120567736Seric { 120667736Seric /* completely specified -- this must be it */ 120767736Seric sel = NULL; 120867614Seric break; 120967736Seric } 121067736Seric if (sel != NULL) 121167736Seric break; 121267736Seric sel = o; 121367614Seric } 121467736Seric if (sel != NULL && o->o_name == NULL) 121567736Seric o = sel; 121667736Seric else if (o->o_name == NULL) 121767787Seric { 121867614Seric syserr("readcf: unknown option name %s", val); 121967787Seric return; 122067787Seric } 122167736Seric else if (sel != NULL) 122267736Seric { 122367736Seric syserr("readcf: ambiguous option name %s (matches %s and %s)", 122467736Seric val, sel->o_name, o->o_name); 122567736Seric return; 122667736Seric } 122767736Seric if (strlen(val) != strlen(o->o_name)) 122867736Seric { 122967736Seric bool oldVerbose = Verbose; 123067736Seric 123167736Seric Verbose = TRUE; 123267736Seric message("Option %s used as abbreviation for %s", 123367736Seric val, o->o_name); 123467736Seric Verbose = oldVerbose; 123567736Seric } 123667614Seric opt = o->o_code; 123767614Seric val = p; 123867614Seric } 123967614Seric else 124067614Seric { 124167614Seric for (o = OptionTab; o->o_name != NULL; o++) 124267614Seric { 124367614Seric if (o->o_code == opt) 124467614Seric break; 124567614Seric } 1246*67903Seric subopt = NULL; 124767614Seric } 124867614Seric 12498256Seric if (tTd(37, 1)) 125067731Seric { 125167731Seric printf(isascii(opt) && isprint(opt) ? 1252*67903Seric "setoption %s (%c).%s=%s" : 1253*67903Seric "setoption %s (0x%x).%s=%s", 125467614Seric o->o_name == NULL ? "<unknown>" : o->o_name, 1255*67903Seric opt, 1256*67903Seric subopt == NULL ? "" : subopt, 1257*67903Seric val); 125867731Seric } 12598256Seric 12608256Seric /* 12618269Seric ** See if this option is preset for us. 12628256Seric */ 12638256Seric 126459731Seric if (!sticky && bitnset(opt, StickyOpt)) 12658269Seric { 12669341Seric if (tTd(37, 1)) 12679341Seric printf(" (ignored)\n"); 12688269Seric return; 12698269Seric } 12708269Seric 127121755Seric /* 127221755Seric ** Check to see if this option can be specified by this user. 127321755Seric */ 127421755Seric 127563787Seric if (!safe && RealUid == 0) 127621755Seric safe = TRUE; 127767614Seric if (!safe && !o->o_safe) 127821755Seric { 127939111Srick if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 128021755Seric { 128136582Sbostic if (tTd(37, 1)) 128236582Sbostic printf(" (unsafe)"); 128363787Seric if (RealUid != geteuid()) 128436582Sbostic { 128551210Seric if (tTd(37, 1)) 128651210Seric printf("(Resetting uid)"); 128763787Seric (void) setgid(RealGid); 128863787Seric (void) setuid(RealUid); 128936582Sbostic } 129021755Seric } 129121755Seric } 129251210Seric if (tTd(37, 1)) 129317985Seric printf("\n"); 12948269Seric 129567614Seric switch (opt & 0xff) 12968256Seric { 129759709Seric case '7': /* force seven-bit input */ 129867546Seric SevenBitInput = atobool(val); 129952106Seric break; 130052106Seric 130167546Seric case '8': /* handling of 8-bit input */ 130267546Seric switch (*val) 130367546Seric { 130467547Seric case 'r': /* reject 8-bit, don't convert MIME */ 130567546Seric MimeMode = 0; 130667546Seric break; 130767546Seric 130867547Seric case 'm': /* convert 8-bit, convert MIME */ 130967546Seric MimeMode = MM_CVTMIME|MM_MIME8BIT; 131067546Seric break; 131167546Seric 131267547Seric case 'j': /* "just send 8" */ 131367546Seric MimeMode = MM_PASS8BIT; 131467546Seric break; 131567546Seric 131667546Seric case 'p': /* pass 8 bit, convert MIME */ 131767546Seric MimeMode = MM_PASS8BIT|MM_CVTMIME; 131867546Seric break; 131967546Seric 132067546Seric case 's': /* strict adherence */ 132167546Seric MimeMode = MM_CVTMIME; 132267546Seric break; 132367546Seric 132467547Seric case 'a': /* encode 8 bit if available */ 132567546Seric MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 132667546Seric break; 132767546Seric 132867547Seric case 'c': /* convert 8 bit to MIME, never 7 bit */ 132967547Seric MimeMode = MM_MIME8BIT; 133067547Seric break; 133167547Seric 133267546Seric default: 133367546Seric syserr("Unknown 8-bit mode %c", *val); 133467546Seric exit(EX_USAGE); 133567546Seric } 133667546Seric break; 133767546Seric 13388256Seric case 'A': /* set default alias file */ 13399381Seric if (val[0] == '\0') 134059672Seric setalias("aliases"); 13419381Seric else 134259672Seric setalias(val); 13438256Seric break; 13448256Seric 134517474Seric case 'a': /* look N minutes for "@:@" in alias file */ 134617474Seric if (val[0] == '\0') 134764796Seric SafeAlias = 5 * 60; /* five minutes */ 134817474Seric else 134964796Seric SafeAlias = convtime(val, 'm'); 135017474Seric break; 135117474Seric 135216843Seric case 'B': /* substitution for blank character */ 135316843Seric SpaceSub = val[0]; 135416843Seric if (SpaceSub == '\0') 135516843Seric SpaceSub = ' '; 135616843Seric break; 135716843Seric 135859283Seric case 'b': /* min blocks free on queue fs/max msg size */ 135959283Seric p = strchr(val, '/'); 136059283Seric if (p != NULL) 136159283Seric { 136259283Seric *p++ = '\0'; 136359283Seric MaxMessageSize = atol(p); 136459283Seric } 136558082Seric MinBlocksFree = atol(val); 136658082Seric break; 136758082Seric 13689284Seric case 'c': /* don't connect to "expensive" mailers */ 13699381Seric NoConnect = atobool(val); 13709284Seric break; 13719284Seric 137251305Seric case 'C': /* checkpoint every N addresses */ 137351305Seric CheckpointInterval = atoi(val); 137424944Seric break; 137524944Seric 13769284Seric case 'd': /* delivery mode */ 13779284Seric switch (*val) 13788269Seric { 13799284Seric case '\0': 138058734Seric e->e_sendmode = SM_DELIVER; 13818269Seric break; 13828269Seric 138310755Seric case SM_QUEUE: /* queue only */ 138410755Seric #ifndef QUEUE 138510755Seric syserr("need QUEUE to set -odqueue"); 138656795Seric #endif /* QUEUE */ 138710755Seric /* fall through..... */ 138810755Seric 13899284Seric case SM_DELIVER: /* do everything */ 13909284Seric case SM_FORK: /* fork after verification */ 139158734Seric e->e_sendmode = *val; 13928269Seric break; 13938269Seric 13948269Seric default: 13959284Seric syserr("Unknown delivery mode %c", *val); 13968269Seric exit(EX_USAGE); 13978269Seric } 13988269Seric break; 13998269Seric 14009146Seric case 'D': /* rebuild alias database as needed */ 14019381Seric AutoRebuild = atobool(val); 14029146Seric break; 14039146Seric 140455372Seric case 'E': /* error message header/header file */ 140555379Seric if (*val != '\0') 140655379Seric ErrMsgFile = newstr(val); 140755372Seric break; 140855372Seric 14098269Seric case 'e': /* set error processing mode */ 14108269Seric switch (*val) 14118269Seric { 14129381Seric case EM_QUIET: /* be silent about it */ 14139381Seric case EM_MAIL: /* mail back */ 14149381Seric case EM_BERKNET: /* do berknet error processing */ 14159381Seric case EM_WRITE: /* write back (or mail) */ 14169381Seric case EM_PRINT: /* print errors normally (default) */ 141758734Seric e->e_errormode = *val; 14188269Seric break; 14198269Seric } 14208269Seric break; 14218269Seric 14229049Seric case 'F': /* file mode */ 142317975Seric FileMode = atooct(val) & 0777; 14249049Seric break; 14259049Seric 14268269Seric case 'f': /* save Unix-style From lines on front */ 14279381Seric SaveFrom = atobool(val); 14288269Seric break; 14298269Seric 143053735Seric case 'G': /* match recipients against GECOS field */ 143153735Seric MatchGecos = atobool(val); 143253735Seric break; 143353735Seric 14348256Seric case 'g': /* default gid */ 143567823Seric g_opt: 143664133Seric if (isascii(*val) && isdigit(*val)) 143764133Seric DefGid = atoi(val); 143864133Seric else 143964133Seric { 144064133Seric register struct group *gr; 144164133Seric 144264133Seric DefGid = -1; 144364133Seric gr = getgrnam(val); 144464133Seric if (gr == NULL) 144567823Seric syserr("readcf: option %c: unknown group %s", 144667823Seric opt, val); 144764133Seric else 144864133Seric DefGid = gr->gr_gid; 144964133Seric } 14508256Seric break; 14518256Seric 14528256Seric case 'H': /* help file */ 14539381Seric if (val[0] == '\0') 14548269Seric HelpFile = "sendmail.hf"; 14559381Seric else 14569381Seric HelpFile = newstr(val); 14578256Seric break; 14588256Seric 145951305Seric case 'h': /* maximum hop count */ 146051305Seric MaxHopCount = atoi(val); 146151305Seric break; 146251305Seric 146335651Seric case 'I': /* use internet domain name server */ 146466334Seric #if NAMED_BIND 146557207Seric UseNameServer = TRUE; 146657207Seric for (p = val; *p != 0; ) 146757207Seric { 146857207Seric bool clearmode; 146957207Seric char *q; 147057207Seric struct resolverflags *rfp; 147157207Seric 147257207Seric while (*p == ' ') 147357207Seric p++; 147457207Seric if (*p == '\0') 147557207Seric break; 147657207Seric clearmode = FALSE; 147757207Seric if (*p == '-') 147857207Seric clearmode = TRUE; 147957207Seric else if (*p != '+') 148057207Seric p--; 148157207Seric p++; 148257207Seric q = p; 148358050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 148457207Seric p++; 148557207Seric if (*p != '\0') 148657207Seric *p++ = '\0'; 148757207Seric for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 148857207Seric { 148957207Seric if (strcasecmp(q, rfp->rf_name) == 0) 149057207Seric break; 149157207Seric } 149264923Seric if (rfp->rf_name == NULL) 149364923Seric syserr("readcf: I option value %s unrecognized", q); 149464923Seric else if (clearmode) 149557207Seric _res.options &= ~rfp->rf_bits; 149657207Seric else 149757207Seric _res.options |= rfp->rf_bits; 149857207Seric } 149957207Seric if (tTd(8, 2)) 150057207Seric printf("_res.options = %x\n", _res.options); 150157207Seric #else 150257207Seric usrerr("name server (I option) specified but BIND not compiled in"); 150357207Seric #endif 150435651Seric break; 150535651Seric 15068269Seric case 'i': /* ignore dot lines in message */ 15079381Seric IgnrDot = atobool(val); 15088269Seric break; 15098269Seric 151059730Seric case 'j': /* send errors in MIME (RFC 1341) format */ 151159730Seric SendMIMEErrors = atobool(val); 151259730Seric break; 151359730Seric 151457136Seric case 'J': /* .forward search path */ 151557136Seric ForwardPath = newstr(val); 151657136Seric break; 151757136Seric 151854967Seric case 'k': /* connection cache size */ 151954967Seric MaxMciCache = atoi(val); 152056215Seric if (MaxMciCache < 0) 152156215Seric MaxMciCache = 0; 152254967Seric break; 152354967Seric 152454967Seric case 'K': /* connection cache timeout */ 152558796Seric MciCacheTimeout = convtime(val, 'm'); 152654967Seric break; 152754967Seric 152861104Seric case 'l': /* use Errors-To: header */ 152961104Seric UseErrorsTo = atobool(val); 153061104Seric break; 153161104Seric 15328256Seric case 'L': /* log level */ 153364140Seric if (safe || LogLevel < atoi(val)) 153464140Seric LogLevel = atoi(val); 15358256Seric break; 15368256Seric 15378269Seric case 'M': /* define macro */ 15389381Seric define(val[0], newstr(&val[1]), CurEnv); 153916878Seric sticky = FALSE; 15408269Seric break; 15418269Seric 15428269Seric case 'm': /* send to me too */ 15439381Seric MeToo = atobool(val); 15448269Seric break; 15458269Seric 154625820Seric case 'n': /* validate RHS in newaliases */ 154725820Seric CheckAliases = atobool(val); 154825820Seric break; 154925820Seric 155061104Seric /* 'N' available -- was "net name" */ 155161104Seric 155258851Seric case 'O': /* daemon options */ 155358851Seric setdaemonoptions(val); 155458851Seric break; 155558851Seric 15568269Seric case 'o': /* assume old style headers */ 15579381Seric if (atobool(val)) 15589341Seric CurEnv->e_flags |= EF_OLDSTYLE; 15599341Seric else 15609341Seric CurEnv->e_flags &= ~EF_OLDSTYLE; 15618269Seric break; 15628269Seric 156358082Seric case 'p': /* select privacy level */ 156458082Seric p = val; 156558082Seric for (;;) 156658082Seric { 156758082Seric register struct prival *pv; 156858082Seric extern struct prival PrivacyValues[]; 156958082Seric 157058082Seric while (isascii(*p) && (isspace(*p) || ispunct(*p))) 157158082Seric p++; 157258082Seric if (*p == '\0') 157358082Seric break; 157458082Seric val = p; 157558082Seric while (isascii(*p) && isalnum(*p)) 157658082Seric p++; 157758082Seric if (*p != '\0') 157858082Seric *p++ = '\0'; 157958082Seric 158058082Seric for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 158158082Seric { 158258082Seric if (strcasecmp(val, pv->pv_name) == 0) 158358082Seric break; 158458082Seric } 158558886Seric if (pv->pv_name == NULL) 158658886Seric syserr("readcf: Op line: %s unrecognized", val); 158758082Seric PrivacyFlags |= pv->pv_flag; 158858082Seric } 158958082Seric break; 159058082Seric 159124944Seric case 'P': /* postmaster copy address for returned mail */ 159224944Seric PostMasterCopy = newstr(val); 159324944Seric break; 159424944Seric 159524944Seric case 'q': /* slope of queue only function */ 159624944Seric QueueFactor = atoi(val); 159724944Seric break; 159824944Seric 15998256Seric case 'Q': /* queue directory */ 16009381Seric if (val[0] == '\0') 16018269Seric QueueDir = "mqueue"; 16029381Seric else 16039381Seric QueueDir = newstr(val); 160458789Seric if (RealUid != 0 && !safe) 160564718Seric Warn_Q_option = TRUE; 16068256Seric break; 16078256Seric 160858148Seric case 'R': /* don't prune routes */ 160958148Seric DontPruneRoutes = atobool(val); 161058148Seric break; 161158148Seric 16128256Seric case 'r': /* read timeout */ 1613*67903Seric if (subopt == NULL) 1614*67903Seric inittimeouts(val); 1615*67903Seric else 1616*67903Seric settimeout(subopt, val); 16178256Seric break; 16188256Seric 16198256Seric case 'S': /* status file */ 16209381Seric if (val[0] == '\0') 16218269Seric StatFile = "sendmail.st"; 16229381Seric else 16239381Seric StatFile = newstr(val); 16248256Seric break; 16258256Seric 16268265Seric case 's': /* be super safe, even if expensive */ 16279381Seric SuperSafe = atobool(val); 16288256Seric break; 16298256Seric 16308256Seric case 'T': /* queue timeout */ 163158737Seric p = strchr(val, '/'); 163258737Seric if (p != NULL) 163358737Seric { 163458737Seric *p++ = '\0'; 1635*67903Seric settimeout("queuewarn", p); 163658737Seric } 1637*67903Seric settimeout("queuereturn", val); 163854967Seric break; 16398256Seric 16408265Seric case 't': /* time zone name */ 164152106Seric TimeZoneSpec = newstr(val); 16428265Seric break; 16438265Seric 164450556Seric case 'U': /* location of user database */ 164551360Seric UdbSpec = newstr(val); 164650556Seric break; 164750556Seric 16488256Seric case 'u': /* set default uid */ 164967823Seric for (p = val; *p != '\0'; p++) 165067823Seric { 165167823Seric if (*p == '.' || *p == '/' || *p == ':') 165267823Seric { 165367823Seric *p++ = '\0'; 165467823Seric break; 165567823Seric } 165667823Seric } 165764133Seric if (isascii(*val) && isdigit(*val)) 165864133Seric DefUid = atoi(val); 165964133Seric else 166064133Seric { 166164133Seric register struct passwd *pw; 166264133Seric 166364133Seric DefUid = -1; 166464133Seric pw = getpwnam(val); 166564133Seric if (pw == NULL) 166664133Seric syserr("readcf: option u: unknown user %s", val); 166764133Seric else 166867823Seric { 166964133Seric DefUid = pw->pw_uid; 167067823Seric DefGid = pw->pw_gid; 167167823Seric } 167264133Seric } 167340973Sbostic setdefuser(); 16748256Seric 167567823Seric /* handle the group if it is there */ 167667823Seric if (*p == '\0') 167767823Seric break; 167867823Seric val = p; 167967823Seric goto g_opt; 168067823Seric 168158851Seric case 'V': /* fallback MX host */ 168258851Seric FallBackMX = newstr(val); 168358851Seric break; 168458851Seric 16858269Seric case 'v': /* run in verbose mode */ 16869381Seric Verbose = atobool(val); 16878256Seric break; 16888256Seric 168963837Seric case 'w': /* if we are best MX, try host directly */ 169063837Seric TryNullMXList = atobool(val); 169163837Seric break; 169261104Seric 169361104Seric /* 'W' available -- was wizard password */ 169461104Seric 169514879Seric case 'x': /* load avg at which to auto-queue msgs */ 169614879Seric QueueLA = atoi(val); 169714879Seric break; 169814879Seric 169914879Seric case 'X': /* load avg at which to auto-reject connections */ 170014879Seric RefuseLA = atoi(val); 170114879Seric break; 170214879Seric 170324981Seric case 'y': /* work recipient factor */ 170424981Seric WkRecipFact = atoi(val); 170524981Seric break; 170624981Seric 170724981Seric case 'Y': /* fork jobs during queue runs */ 170824952Seric ForkQueueRuns = atobool(val); 170924952Seric break; 171024952Seric 171124981Seric case 'z': /* work message class factor */ 171224981Seric WkClassFact = atoi(val); 171324981Seric break; 171424981Seric 171524981Seric case 'Z': /* work time factor */ 171624981Seric WkTimeFact = atoi(val); 171724981Seric break; 171824981Seric 171967614Seric case O_BSP: /* SMTP Peers can't handle 2-line greeting */ 172067614Seric BrokenSmtpPeers = atobool(val); 172167614Seric break; 172267614Seric 172367614Seric case O_SQBH: /* sort work queue by host first */ 172467614Seric SortQueueByHost = atobool(val); 172567614Seric break; 172667614Seric 172767707Seric case O_DNICE: /* delivery nice value */ 172867707Seric DeliveryNiceness = atoi(val); 172967707Seric break; 173067707Seric 173167707Seric case O_MQA: /* minimum queue age between deliveries */ 173267707Seric MinQueueAge = convtime(val, 'm'); 173367707Seric break; 173467707Seric 173567707Seric case O_MHSA: /* maximum age of cached host status */ 173667707Seric MaxHostStatAge = convtime(val, 'm'); 173767707Seric break; 173867707Seric 173967813Seric case O_DEFCHARSET: /* default character set for mimefying */ 174067814Seric DefaultCharSet = newstr(val); 174167813Seric break; 174267813Seric 174367848Seric case O_SSFILE: /* service switch file */ 174467848Seric ServiceSwitchFile = newstr(val); 174567848Seric break; 174667848Seric 17478256Seric default: 17488256Seric break; 17498256Seric } 175016878Seric if (sticky) 175116878Seric setbitn(opt, StickyOpt); 17529188Seric return; 17538256Seric } 175410687Seric /* 175510687Seric ** SETCLASS -- set a word into a class 175610687Seric ** 175710687Seric ** Parameters: 175810687Seric ** class -- the class to put the word in. 175910687Seric ** word -- the word to enter 176010687Seric ** 176110687Seric ** Returns: 176210687Seric ** none. 176310687Seric ** 176410687Seric ** Side Effects: 176510687Seric ** puts the word into the symbol table. 176610687Seric */ 176710687Seric 176810687Seric setclass(class, word) 176910687Seric int class; 177010687Seric char *word; 177110687Seric { 177210687Seric register STAB *s; 177310687Seric 177457943Seric if (tTd(37, 8)) 177564326Seric printf("setclass(%c, %s)\n", class, word); 177610687Seric s = stab(word, ST_CLASS, ST_ENTER); 177710687Seric setbitn(class, s->s_class); 177810687Seric } 177953654Seric /* 178053654Seric ** MAKEMAPENTRY -- create a map entry 178153654Seric ** 178253654Seric ** Parameters: 178353654Seric ** line -- the config file line 178453654Seric ** 178553654Seric ** Returns: 178653654Seric ** TRUE if it successfully entered the map entry. 178753654Seric ** FALSE otherwise (usually syntax error). 178853654Seric ** 178953654Seric ** Side Effects: 179053654Seric ** Enters the map into the dictionary. 179153654Seric */ 179253654Seric 179353654Seric void 179453654Seric makemapentry(line) 179553654Seric char *line; 179653654Seric { 179753654Seric register char *p; 179853654Seric char *mapname; 179953654Seric char *classname; 180064078Seric register STAB *s; 180153654Seric STAB *class; 180253654Seric 180358050Seric for (p = line; isascii(*p) && isspace(*p); p++) 180453654Seric continue; 180558050Seric if (!(isascii(*p) && isalnum(*p))) 180653654Seric { 180753654Seric syserr("readcf: config K line: no map name"); 180853654Seric return; 180953654Seric } 181053654Seric 181153654Seric mapname = p; 181267848Seric while ((isascii(*++p) && isalnum(*p)) || *p == '.') 181353654Seric continue; 181453654Seric if (*p != '\0') 181553654Seric *p++ = '\0'; 181658050Seric while (isascii(*p) && isspace(*p)) 181753654Seric p++; 181858050Seric if (!(isascii(*p) && isalnum(*p))) 181953654Seric { 182053654Seric syserr("readcf: config K line, map %s: no map class", mapname); 182153654Seric return; 182253654Seric } 182353654Seric classname = p; 182458050Seric while (isascii(*++p) && isalnum(*p)) 182553654Seric continue; 182653654Seric if (*p != '\0') 182753654Seric *p++ = '\0'; 182858050Seric while (isascii(*p) && isspace(*p)) 182953654Seric p++; 183053654Seric 183153654Seric /* look up the class */ 183253654Seric class = stab(classname, ST_MAPCLASS, ST_FIND); 183353654Seric if (class == NULL) 183453654Seric { 183553654Seric syserr("readcf: map %s: class %s not available", mapname, classname); 183653654Seric return; 183753654Seric } 183853654Seric 183953654Seric /* enter the map */ 184064078Seric s = stab(mapname, ST_MAP, ST_ENTER); 184164078Seric s->s_map.map_class = &class->s_mapclass; 184264078Seric s->s_map.map_mname = newstr(mapname); 184353654Seric 184464078Seric if (class->s_mapclass.map_parse(&s->s_map, p)) 184564078Seric s->s_map.map_mflags |= MF_VALID; 184664078Seric 184764078Seric if (tTd(37, 5)) 184864078Seric { 184964078Seric printf("map %s, class %s, flags %x, file %s,\n", 185064078Seric s->s_map.map_mname, s->s_map.map_class->map_cname, 185164078Seric s->s_map.map_mflags, 185264078Seric s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 185364078Seric printf("\tapp %s, domain %s, rebuild %s\n", 185464078Seric s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 185564078Seric s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 185664078Seric s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 185764078Seric } 185853654Seric } 185958112Seric /* 1860*67903Seric ** INITTIMEOUTS -- parse and set timeout values 186158112Seric ** 186258112Seric ** Parameters: 186358112Seric ** val -- a pointer to the values. If NULL, do initial 186458112Seric ** settings. 186558112Seric ** 186658112Seric ** Returns: 186758112Seric ** none. 186858112Seric ** 186958112Seric ** Side Effects: 187058112Seric ** Initializes the TimeOuts structure 187158112Seric */ 187258112Seric 187364255Seric #define SECONDS 187458112Seric #define MINUTES * 60 187558112Seric #define HOUR * 3600 187658112Seric 1877*67903Seric inittimeouts(val) 187858112Seric register char *val; 187958112Seric { 188058112Seric register char *p; 188158671Seric extern time_t convtime(); 188258112Seric 188358112Seric if (val == NULL) 188458112Seric { 188558112Seric TimeOuts.to_initial = (time_t) 5 MINUTES; 188658112Seric TimeOuts.to_helo = (time_t) 5 MINUTES; 188758112Seric TimeOuts.to_mail = (time_t) 10 MINUTES; 188858112Seric TimeOuts.to_rcpt = (time_t) 1 HOUR; 188958112Seric TimeOuts.to_datainit = (time_t) 5 MINUTES; 189058112Seric TimeOuts.to_datablock = (time_t) 1 HOUR; 189158112Seric TimeOuts.to_datafinal = (time_t) 1 HOUR; 189258112Seric TimeOuts.to_rset = (time_t) 5 MINUTES; 189358112Seric TimeOuts.to_quit = (time_t) 2 MINUTES; 189458112Seric TimeOuts.to_nextcommand = (time_t) 1 HOUR; 189558112Seric TimeOuts.to_miscshort = (time_t) 2 MINUTES; 189664255Seric TimeOuts.to_ident = (time_t) 30 SECONDS; 189767711Seric TimeOuts.to_fileopen = (time_t) 60 SECONDS; 189858112Seric return; 189958112Seric } 190058112Seric 190158112Seric for (;; val = p) 190258112Seric { 190358112Seric while (isascii(*val) && isspace(*val)) 190458112Seric val++; 190558112Seric if (*val == '\0') 190658112Seric break; 190758112Seric for (p = val; *p != '\0' && *p != ','; p++) 190858112Seric continue; 190958112Seric if (*p != '\0') 191058112Seric *p++ = '\0'; 191158112Seric 191258112Seric if (isascii(*val) && isdigit(*val)) 191358112Seric { 191458112Seric /* old syntax -- set everything */ 191558796Seric TimeOuts.to_mail = convtime(val, 'm'); 191658112Seric TimeOuts.to_rcpt = TimeOuts.to_mail; 191758112Seric TimeOuts.to_datainit = TimeOuts.to_mail; 191858112Seric TimeOuts.to_datablock = TimeOuts.to_mail; 191958112Seric TimeOuts.to_datafinal = TimeOuts.to_mail; 192058112Seric TimeOuts.to_nextcommand = TimeOuts.to_mail; 192158112Seric continue; 192258112Seric } 192358112Seric else 192458112Seric { 192567711Seric register char *q = strchr(val, ':'); 192658112Seric 192767711Seric if (q == NULL && (q = strchr(val, '=')) == NULL) 192858112Seric { 192958112Seric /* syntax error */ 193058112Seric continue; 193158112Seric } 193258112Seric *q++ = '\0'; 1933*67903Seric settimeout(val, q); 1934*67903Seric } 1935*67903Seric } 1936*67903Seric } 1937*67903Seric /* 1938*67903Seric ** SETTIMEOUT -- set an individual timeout 1939*67903Seric ** 1940*67903Seric ** Parameters: 1941*67903Seric ** name -- the name of the timeout. 1942*67903Seric ** val -- the value of the timeout. 1943*67903Seric ** 1944*67903Seric ** Returns: 1945*67903Seric ** none. 1946*67903Seric */ 194758112Seric 1948*67903Seric settimeout(name, val) 1949*67903Seric char *name; 1950*67903Seric char *val; 1951*67903Seric { 1952*67903Seric register char *p; 1953*67903Seric time_t to; 1954*67903Seric extern time_t convtime(); 1955*67903Seric 1956*67903Seric to = convtime(val, 'm'); 1957*67903Seric p = strchr(name, '.'); 1958*67903Seric if (p != NULL) 1959*67903Seric *p++ = '\0'; 1960*67903Seric 1961*67903Seric if (strcasecmp(name, "initial") == 0) 1962*67903Seric TimeOuts.to_initial = to; 1963*67903Seric else if (strcasecmp(name, "mail") == 0) 1964*67903Seric TimeOuts.to_mail = to; 1965*67903Seric else if (strcasecmp(name, "rcpt") == 0) 1966*67903Seric TimeOuts.to_rcpt = to; 1967*67903Seric else if (strcasecmp(name, "datainit") == 0) 1968*67903Seric TimeOuts.to_datainit = to; 1969*67903Seric else if (strcasecmp(name, "datablock") == 0) 1970*67903Seric TimeOuts.to_datablock = to; 1971*67903Seric else if (strcasecmp(name, "datafinal") == 0) 1972*67903Seric TimeOuts.to_datafinal = to; 1973*67903Seric else if (strcasecmp(name, "command") == 0) 1974*67903Seric TimeOuts.to_nextcommand = to; 1975*67903Seric else if (strcasecmp(name, "rset") == 0) 1976*67903Seric TimeOuts.to_rset = to; 1977*67903Seric else if (strcasecmp(name, "helo") == 0) 1978*67903Seric TimeOuts.to_helo = to; 1979*67903Seric else if (strcasecmp(name, "quit") == 0) 1980*67903Seric TimeOuts.to_quit = to; 1981*67903Seric else if (strcasecmp(name, "misc") == 0) 1982*67903Seric TimeOuts.to_miscshort = to; 1983*67903Seric else if (strcasecmp(name, "ident") == 0) 1984*67903Seric TimeOuts.to_ident = to; 1985*67903Seric else if (strcasecmp(name, "fileopen") == 0) 1986*67903Seric TimeOuts.to_fileopen = to; 1987*67903Seric else if (strcasecmp(name, "queuewarn") == 0) 1988*67903Seric { 1989*67903Seric to = convtime(val, 'h'); 1990*67903Seric if (p == NULL || strcmp(p, "*") == NULL) 1991*67903Seric { 1992*67903Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 1993*67903Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 1994*67903Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 199558112Seric } 1996*67903Seric else if (strcasecmp(p, "normal") == 0) 1997*67903Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 1998*67903Seric else if (strcasecmp(p, "urgent") == 0) 1999*67903Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 2000*67903Seric else if (strcasecmp(p, "non-urgent") == 0) 2001*67903Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 2002*67903Seric else 2003*67903Seric syserr("settimeout: invalid queuewarn subtimeout %s", p); 200458112Seric } 2005*67903Seric else if (strcasecmp(name, "queuereturn") == 0) 2006*67903Seric { 2007*67903Seric to = convtime(val, 'd'); 2008*67903Seric if (p == NULL || strcmp(p, "*") == 0) 2009*67903Seric { 2010*67903Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 2011*67903Seric TimeOuts.to_q_return[TOC_URGENT] = to; 2012*67903Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 2013*67903Seric } 2014*67903Seric else if (strcasecmp(p, "normal") == 0) 2015*67903Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 2016*67903Seric else if (strcasecmp(p, "urgent") == 0) 2017*67903Seric TimeOuts.to_q_return[TOC_URGENT] = to; 2018*67903Seric else if (strcasecmp(p, "non-urgent") == 0) 2019*67903Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 2020*67903Seric else 2021*67903Seric syserr("settimeout: invalid queuereturn subtimeout %s", p); 2022*67903Seric } 2023*67903Seric else 2024*67903Seric syserr("settimeout: invalid timeout %s", name); 202558112Seric } 2026