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*67994Seric static char sccsid[] = "@(#)readcf.c 8.50 (Berkeley) 11/27/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(); 53267905Seric 53367905Seric /* determine if we need to do special name-server frotz */ 53467905Seric { 53567905Seric int nmaps; 53667905Seric char *maptype[MAXMAPSTACK]; 53767905Seric short mapreturn[MAXMAPACTIONS]; 53867905Seric 53967905Seric nmaps = switch_map_find("hosts", maptype, mapreturn); 54067905Seric UseNameServer = FALSE; 54167905Seric if (nmaps > 0 && nmaps <= MAXMAPSTACK) 54267905Seric { 54367905Seric register int mapno; 54467905Seric 54567905Seric for (mapno = 0; mapno < nmaps && !UseNameServer; mapno++) 54667905Seric { 54767905Seric if (strcmp(maptype[mapno], "dns") == 0) 54867905Seric UseNameServer = TRUE; 54967905Seric } 55067905Seric } 55167905Seric } 5524096Seric } 5534096Seric /* 5548547Seric ** TOOMANY -- signal too many of some option 5558547Seric ** 5568547Seric ** Parameters: 5578547Seric ** id -- the id of the error line 5588547Seric ** maxcnt -- the maximum possible values 5598547Seric ** 5608547Seric ** Returns: 5618547Seric ** none. 5628547Seric ** 5638547Seric ** Side Effects: 5648547Seric ** gives a syserr. 5658547Seric */ 5668547Seric 5678547Seric toomany(id, maxcnt) 5688547Seric char id; 5698547Seric int maxcnt; 5708547Seric { 5719381Seric syserr("too many %c lines, %d max", id, maxcnt); 5728547Seric } 5738547Seric /* 5744432Seric ** FILECLASS -- read members of a class from a file 5754432Seric ** 5764432Seric ** Parameters: 5774432Seric ** class -- class to define. 5784432Seric ** filename -- name of file to read. 5794432Seric ** fmt -- scanf string to use for match. 58064133Seric ** safe -- if set, this is a safe read. 58164133Seric ** optional -- if set, it is not an error for the file to 58264133Seric ** not exist. 5834432Seric ** 5844432Seric ** Returns: 5854432Seric ** none 5864432Seric ** 5874432Seric ** Side Effects: 5884432Seric ** 5894432Seric ** puts all lines in filename that match a scanf into 5904432Seric ** the named class. 5914432Seric */ 5924432Seric 59364133Seric fileclass(class, filename, fmt, safe, optional) 5944432Seric int class; 5954432Seric char *filename; 5964432Seric char *fmt; 59754973Seric bool safe; 59864133Seric bool optional; 5994432Seric { 60025808Seric FILE *f; 60154973Seric struct stat stbuf; 6024432Seric char buf[MAXLINE]; 6034432Seric 60466101Seric if (tTd(37, 2)) 60566101Seric printf("fileclass(%s, fmt=%s)\n", filename, fmt); 60666101Seric 60766031Seric if (filename[0] == '|') 60866031Seric { 60966031Seric syserr("fileclass: pipes (F%c%s) not supported due to security problems", 61066031Seric class, filename); 61166031Seric return; 61266031Seric } 61354973Seric if (stat(filename, &stbuf) < 0) 61454973Seric { 61566101Seric if (tTd(37, 2)) 61666101Seric printf(" cannot stat (%s)\n", errstring(errno)); 61764133Seric if (!optional) 61864133Seric syserr("fileclass: cannot stat %s", filename); 61954973Seric return; 62054973Seric } 62154973Seric if (!S_ISREG(stbuf.st_mode)) 62254973Seric { 62354973Seric syserr("fileclass: %s not a regular file", filename); 62454973Seric return; 62554973Seric } 62654973Seric if (!safe && access(filename, R_OK) < 0) 62754973Seric { 62854973Seric syserr("fileclass: access denied on %s", filename); 62954973Seric return; 63054973Seric } 63154973Seric f = fopen(filename, "r"); 6324432Seric if (f == NULL) 6334432Seric { 63454973Seric syserr("fileclass: cannot open %s", filename); 6354432Seric return; 6364432Seric } 6374432Seric 6384432Seric while (fgets(buf, sizeof buf, f) != NULL) 6394432Seric { 6404432Seric register STAB *s; 64125808Seric register char *p; 64225808Seric # ifdef SCANF 6434432Seric char wordbuf[MAXNAME+1]; 6444432Seric 6454432Seric if (sscanf(buf, fmt, wordbuf) != 1) 6464432Seric continue; 64725808Seric p = wordbuf; 64856795Seric # else /* SCANF */ 64925808Seric p = buf; 65056795Seric # endif /* SCANF */ 65125808Seric 65225808Seric /* 65325808Seric ** Break up the match into words. 65425808Seric */ 65525808Seric 65625808Seric while (*p != '\0') 65725808Seric { 65825808Seric register char *q; 65925808Seric 66025808Seric /* strip leading spaces */ 66158050Seric while (isascii(*p) && isspace(*p)) 66225808Seric p++; 66325808Seric if (*p == '\0') 66425808Seric break; 66525808Seric 66625808Seric /* find the end of the word */ 66725808Seric q = p; 66858050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 66925808Seric p++; 67025808Seric if (*p != '\0') 67125808Seric *p++ = '\0'; 67225808Seric 67325808Seric /* enter the word in the symbol table */ 67466101Seric setclass(class, q); 67525808Seric } 6764432Seric } 6774432Seric 67854973Seric (void) fclose(f); 6794432Seric } 6804432Seric /* 6814096Seric ** MAKEMAILER -- define a new mailer. 6824096Seric ** 6834096Seric ** Parameters: 68410327Seric ** line -- description of mailer. This is in labeled 68510327Seric ** fields. The fields are: 68610327Seric ** P -- the path to the mailer 68710327Seric ** F -- the flags associated with the mailer 68810327Seric ** A -- the argv for this mailer 68910327Seric ** S -- the sender rewriting set 69010327Seric ** R -- the recipient rewriting set 69110327Seric ** E -- the eol string 69210327Seric ** The first word is the canonical name of the mailer. 6934096Seric ** 6944096Seric ** Returns: 6954096Seric ** none. 6964096Seric ** 6974096Seric ** Side Effects: 6984096Seric ** enters the mailer into the mailer table. 6994096Seric */ 7003308Seric 70121066Seric makemailer(line) 7024096Seric char *line; 7034096Seric { 7044096Seric register char *p; 7058067Seric register struct mailer *m; 7068067Seric register STAB *s; 7078067Seric int i; 70810327Seric char fcode; 70958020Seric auto char *endp; 7104096Seric extern int NextMailer; 71110327Seric extern char **makeargv(); 71210327Seric extern char *munchstring(); 71310701Seric extern long atol(); 7144096Seric 71510327Seric /* allocate a mailer and set up defaults */ 71610327Seric m = (struct mailer *) xalloc(sizeof *m); 71710327Seric bzero((char *) m, sizeof *m); 71810327Seric m->m_eol = "\n"; 71967604Seric m->m_uid = m->m_gid = 0; 72010327Seric 72110327Seric /* collect the mailer name */ 72258050Seric for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++) 72310327Seric continue; 72410327Seric if (*p != '\0') 72510327Seric *p++ = '\0'; 72610327Seric m->m_name = newstr(line); 72710327Seric 72810327Seric /* now scan through and assign info from the fields */ 72910327Seric while (*p != '\0') 73010327Seric { 73158333Seric auto char *delimptr; 73258333Seric 73358050Seric while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p)))) 73410327Seric p++; 73510327Seric 73610327Seric /* p now points to field code */ 73710327Seric fcode = *p; 73810327Seric while (*p != '\0' && *p != '=' && *p != ',') 73910327Seric p++; 74010327Seric if (*p++ != '=') 74110327Seric { 74252637Seric syserr("mailer %s: `=' expected", m->m_name); 74310327Seric return; 74410327Seric } 74558050Seric while (isascii(*p) && isspace(*p)) 74610327Seric p++; 74710327Seric 74810327Seric /* p now points to the field body */ 74958333Seric p = munchstring(p, &delimptr); 75010327Seric 75110327Seric /* install the field into the mailer struct */ 75210327Seric switch (fcode) 75310327Seric { 75410327Seric case 'P': /* pathname */ 75510327Seric m->m_mailer = newstr(p); 75610327Seric break; 75710327Seric 75810327Seric case 'F': /* flags */ 75910687Seric for (; *p != '\0'; p++) 76058050Seric if (!(isascii(*p) && isspace(*p))) 76152637Seric setbitn(*p, m->m_flags); 76210327Seric break; 76310327Seric 76410327Seric case 'S': /* sender rewriting ruleset */ 76510327Seric case 'R': /* recipient rewriting ruleset */ 76658020Seric i = strtol(p, &endp, 10); 76710327Seric if (i < 0 || i >= MAXRWSETS) 76810327Seric { 76910327Seric syserr("invalid rewrite set, %d max", MAXRWSETS); 77010327Seric return; 77110327Seric } 77210327Seric if (fcode == 'S') 77358020Seric m->m_sh_rwset = m->m_se_rwset = i; 77410327Seric else 77558020Seric m->m_rh_rwset = m->m_re_rwset = i; 77658020Seric 77758020Seric p = endp; 77859985Seric if (*p++ == '/') 77958020Seric { 78058020Seric i = strtol(p, NULL, 10); 78158020Seric if (i < 0 || i >= MAXRWSETS) 78258020Seric { 78358020Seric syserr("invalid rewrite set, %d max", 78458020Seric MAXRWSETS); 78558020Seric return; 78658020Seric } 78758020Seric if (fcode == 'S') 78858020Seric m->m_sh_rwset = i; 78958020Seric else 79058020Seric m->m_rh_rwset = i; 79158020Seric } 79210327Seric break; 79310327Seric 79410327Seric case 'E': /* end of line string */ 79510327Seric m->m_eol = newstr(p); 79610327Seric break; 79710327Seric 79810327Seric case 'A': /* argument vector */ 79910327Seric m->m_argv = makeargv(p); 80010327Seric break; 80110701Seric 80210701Seric case 'M': /* maximum message size */ 80310701Seric m->m_maxsize = atol(p); 80410701Seric break; 80552106Seric 80652106Seric case 'L': /* maximum line length */ 80752106Seric m->m_linelimit = atoi(p); 80852106Seric break; 80958935Seric 81058935Seric case 'D': /* working directory */ 81158935Seric m->m_execdir = newstr(p); 81258935Seric break; 81367604Seric 81467896Seric case 'C': /* default charset */ 81567896Seric m->m_defcharset = newstr(p); 81667896Seric break; 81767896Seric 81867990Seric case 'T': /* MTS Type */ 81967990Seric m->m_mtstype = newstr(p); 82067990Seric break; 82167990Seric 82267604Seric case 'U': /* user id */ 82367604Seric if (isascii(*p) && !isdigit(*p)) 82467604Seric { 82567604Seric char *q = p; 82667604Seric struct passwd *pw; 82767604Seric 82867604Seric while (isascii(*p) && isalnum(*p)) 82967604Seric p++; 83067604Seric while (isascii(*p) && isspace(*p)) 83167604Seric *p++ = '\0'; 83267604Seric if (*p != '\0') 83367604Seric *p++ = '\0'; 83467604Seric pw = getpwnam(q); 83567604Seric if (pw == NULL) 83667604Seric syserr("readcf: mailer U= flag: unknown user %s", q); 83767604Seric else 83867604Seric { 83967604Seric m->m_uid = pw->pw_uid; 84067604Seric m->m_gid = pw->pw_gid; 84167604Seric } 84267604Seric } 84367604Seric else 84467604Seric { 84567604Seric auto char *q; 84667604Seric 84767604Seric m->m_uid = strtol(p, &q, 0); 84867604Seric p = q; 84967604Seric } 85067604Seric while (isascii(*p) && isspace(*p)) 85167604Seric p++; 85267604Seric if (*p == '\0') 85367604Seric break; 85467604Seric if (isascii(*p) && !isdigit(*p)) 85567604Seric { 85667604Seric char *q = p; 85767604Seric struct group *gr; 85867604Seric 85967604Seric while (isascii(*p) && isalnum(*p)) 86067604Seric p++; 86167604Seric *p++ = '\0'; 86267604Seric gr = getgrnam(q); 86367604Seric if (gr == NULL) 86467604Seric syserr("readcf: mailer U= flag: unknown group %s", q); 86567604Seric else 86667604Seric m->m_gid = gr->gr_gid; 86767604Seric } 86867604Seric else 86967604Seric { 87067604Seric m->m_gid = strtol(p, NULL, 0); 87167604Seric } 87267604Seric break; 87310327Seric } 87410327Seric 87558333Seric p = delimptr; 87610327Seric } 87710327Seric 87852106Seric /* do some heuristic cleanup for back compatibility */ 87952106Seric if (bitnset(M_LIMITS, m->m_flags)) 88052106Seric { 88152106Seric if (m->m_linelimit == 0) 88252106Seric m->m_linelimit = SMTPLINELIM; 88355418Seric if (ConfigLevel < 2) 88452106Seric setbitn(M_7BITS, m->m_flags); 88552106Seric } 88652106Seric 88758321Seric /* do some rationality checking */ 88858321Seric if (m->m_argv == NULL) 88958321Seric { 89058321Seric syserr("M%s: A= argument required", m->m_name); 89158321Seric return; 89258321Seric } 89358321Seric if (m->m_mailer == NULL) 89458321Seric { 89558321Seric syserr("M%s: P= argument required", m->m_name); 89658321Seric return; 89758321Seric } 89858321Seric 8994096Seric if (NextMailer >= MAXMAILERS) 9004096Seric { 9019381Seric syserr("too many mailers defined (%d max)", MAXMAILERS); 9024096Seric return; 9034096Seric } 90457402Seric 90510327Seric s = stab(m->m_name, ST_MAILER, ST_ENTER); 90657402Seric if (s->s_mailer != NULL) 90757402Seric { 90857402Seric i = s->s_mailer->m_mno; 90957402Seric free(s->s_mailer); 91057402Seric } 91157402Seric else 91257402Seric { 91357402Seric i = NextMailer++; 91457402Seric } 91557402Seric Mailer[i] = s->s_mailer = m; 91657454Seric m->m_mno = i; 91710327Seric } 91810327Seric /* 91910327Seric ** MUNCHSTRING -- translate a string into internal form. 92010327Seric ** 92110327Seric ** Parameters: 92210327Seric ** p -- the string to munch. 92358333Seric ** delimptr -- if non-NULL, set to the pointer of the 92458333Seric ** field delimiter character. 92510327Seric ** 92610327Seric ** Returns: 92710327Seric ** the munched string. 92810327Seric */ 9294096Seric 93010327Seric char * 93158333Seric munchstring(p, delimptr) 93210327Seric register char *p; 93358333Seric char **delimptr; 93410327Seric { 93510327Seric register char *q; 93610327Seric bool backslash = FALSE; 93710327Seric bool quotemode = FALSE; 93810327Seric static char buf[MAXLINE]; 9394096Seric 94010327Seric for (q = buf; *p != '\0'; p++) 9414096Seric { 94210327Seric if (backslash) 94310327Seric { 94410327Seric /* everything is roughly literal */ 94510357Seric backslash = FALSE; 94610327Seric switch (*p) 94710327Seric { 94810327Seric case 'r': /* carriage return */ 94910327Seric *q++ = '\r'; 95010327Seric continue; 95110327Seric 95210327Seric case 'n': /* newline */ 95310327Seric *q++ = '\n'; 95410327Seric continue; 95510327Seric 95610327Seric case 'f': /* form feed */ 95710327Seric *q++ = '\f'; 95810327Seric continue; 95910327Seric 96010327Seric case 'b': /* backspace */ 96110327Seric *q++ = '\b'; 96210327Seric continue; 96310327Seric } 96410327Seric *q++ = *p; 96510327Seric } 96610327Seric else 96710327Seric { 96810327Seric if (*p == '\\') 96910327Seric backslash = TRUE; 97010327Seric else if (*p == '"') 97110327Seric quotemode = !quotemode; 97210327Seric else if (quotemode || *p != ',') 97310327Seric *q++ = *p; 97410327Seric else 97510327Seric break; 97610327Seric } 9774096Seric } 9784096Seric 97958333Seric if (delimptr != NULL) 98058333Seric *delimptr = p; 98110327Seric *q++ = '\0'; 98210327Seric return (buf); 98310327Seric } 98410327Seric /* 98510327Seric ** MAKEARGV -- break up a string into words 98610327Seric ** 98710327Seric ** Parameters: 98810327Seric ** p -- the string to break up. 98910327Seric ** 99010327Seric ** Returns: 99110327Seric ** a char **argv (dynamically allocated) 99210327Seric ** 99310327Seric ** Side Effects: 99410327Seric ** munges p. 99510327Seric */ 9964096Seric 99710327Seric char ** 99810327Seric makeargv(p) 99910327Seric register char *p; 100010327Seric { 100110327Seric char *q; 100210327Seric int i; 100310327Seric char **avp; 100410327Seric char *argv[MAXPV + 1]; 100510327Seric 100610327Seric /* take apart the words */ 100710327Seric i = 0; 100810327Seric while (*p != '\0' && i < MAXPV) 10094096Seric { 101010327Seric q = p; 101158050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 101210327Seric p++; 101358050Seric while (isascii(*p) && isspace(*p)) 101410327Seric *p++ = '\0'; 101510327Seric argv[i++] = newstr(q); 10164096Seric } 101710327Seric argv[i++] = NULL; 10184096Seric 101910327Seric /* now make a copy of the argv */ 102010327Seric avp = (char **) xalloc(sizeof *avp * i); 102116893Seric bcopy((char *) argv, (char *) avp, sizeof *avp * i); 102210327Seric 102310327Seric return (avp); 10243308Seric } 10253308Seric /* 10263308Seric ** PRINTRULES -- print rewrite rules (for debugging) 10273308Seric ** 10283308Seric ** Parameters: 10293308Seric ** none. 10303308Seric ** 10313308Seric ** Returns: 10323308Seric ** none. 10333308Seric ** 10343308Seric ** Side Effects: 10353308Seric ** prints rewrite rules. 10363308Seric */ 10373308Seric 10383308Seric printrules() 10393308Seric { 10403308Seric register struct rewrite *rwp; 10414072Seric register int ruleset; 10423308Seric 10434072Seric for (ruleset = 0; ruleset < 10; ruleset++) 10443308Seric { 10454072Seric if (RewriteRules[ruleset] == NULL) 10464072Seric continue; 10478067Seric printf("\n----Rule Set %d:", ruleset); 10483308Seric 10494072Seric for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 10503308Seric { 10518067Seric printf("\nLHS:"); 10528067Seric printav(rwp->r_lhs); 10538067Seric printf("RHS:"); 10548067Seric printav(rwp->r_rhs); 10553308Seric } 10563308Seric } 10573308Seric } 1058*67994Seric /* 1059*67994Seric ** PRINTMAILER -- print mailer structure (for debugging) 1060*67994Seric ** 1061*67994Seric ** Parameters: 1062*67994Seric ** m -- the mailer to print 1063*67994Seric ** 1064*67994Seric ** Returns: 1065*67994Seric ** none. 1066*67994Seric */ 10674319Seric 1068*67994Seric printmailer(m) 1069*67994Seric register MAILER *m; 1070*67994Seric { 1071*67994Seric int j; 1072*67994Seric 1073*67994Seric printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld U=%d:%d F=", 1074*67994Seric m->m_mno, m->m_name, 1075*67994Seric m->m_mailer, m->m_se_rwset, m->m_sh_rwset, 1076*67994Seric m->m_re_rwset, m->m_rh_rwset, m->m_maxsize, 1077*67994Seric m->m_uid, m->m_gid); 1078*67994Seric for (j = '\0'; j <= '\177'; j++) 1079*67994Seric if (bitnset(j, m->m_flags)) 1080*67994Seric (void) putchar(j); 1081*67994Seric printf(" L=%d E=", m->m_linelimit); 1082*67994Seric xputs(m->m_eol); 1083*67994Seric if (m->m_defcharset != NULL) 1084*67994Seric printf(" C=%s", m->m_defcharset); 1085*67994Seric if (m->m_mtstype != NULL) 1086*67994Seric printf(" T=%s", m->m_mtstype); 1087*67994Seric if (m->m_argv != NULL) 1088*67994Seric { 1089*67994Seric char **a = m->m_argv; 1090*67994Seric 1091*67994Seric printf(" A="); 1092*67994Seric while (*a != NULL) 1093*67994Seric { 1094*67994Seric if (a != m->m_argv) 1095*67994Seric printf(" "); 1096*67994Seric xputs(*a++); 1097*67994Seric } 1098*67994Seric } 1099*67994Seric printf("\n"); 1100*67994Seric } 11014096Seric /* 11028256Seric ** SETOPTION -- set global processing option 11038256Seric ** 11048256Seric ** Parameters: 11058256Seric ** opt -- option name. 11068256Seric ** val -- option value (as a text string). 110721755Seric ** safe -- set if this came from a configuration file. 110821755Seric ** Some options (if set from the command line) will 110921755Seric ** reset the user id to avoid security problems. 11108269Seric ** sticky -- if set, don't let other setoptions override 11118269Seric ** this value. 111258734Seric ** e -- the main envelope. 11138256Seric ** 11148256Seric ** Returns: 11158256Seric ** none. 11168256Seric ** 11178256Seric ** Side Effects: 11188256Seric ** Sets options as implied by the arguments. 11198256Seric */ 11208256Seric 112110687Seric static BITMAP StickyOpt; /* set if option is stuck */ 11228269Seric 112357207Seric 112466334Seric #if NAMED_BIND 112557207Seric 112657207Seric struct resolverflags 112757207Seric { 112857207Seric char *rf_name; /* name of the flag */ 112957207Seric long rf_bits; /* bits to set/clear */ 113057207Seric } ResolverFlags[] = 113157207Seric { 113257207Seric "debug", RES_DEBUG, 113357207Seric "aaonly", RES_AAONLY, 113457207Seric "usevc", RES_USEVC, 113557207Seric "primary", RES_PRIMARY, 113657207Seric "igntc", RES_IGNTC, 113757207Seric "recurse", RES_RECURSE, 113857207Seric "defnames", RES_DEFNAMES, 113957207Seric "stayopen", RES_STAYOPEN, 114057207Seric "dnsrch", RES_DNSRCH, 114165583Seric "true", 0, /* to avoid error on old syntax */ 114257207Seric NULL, 0 114357207Seric }; 114457207Seric 114557207Seric #endif 114657207Seric 114767614Seric struct optioninfo 114867614Seric { 114967614Seric char *o_name; /* long name of option */ 115067787Seric u_char o_code; /* short name of option */ 115167614Seric bool o_safe; /* safe for random people to use */ 115267614Seric } OptionTab[] = 115367614Seric { 115467707Seric "SevenBitInput", '7', TRUE, 115567707Seric "EightBitMode", '8', TRUE, 115667707Seric "AliasFile", 'A', FALSE, 115767707Seric "AliasWait", 'a', FALSE, 115867707Seric "BlankSub", 'B', FALSE, 115967707Seric "MinFreeBlocks", 'b', TRUE, 116067707Seric "CheckpointInterval", 'C', TRUE, 116167707Seric "HoldExpensive", 'c', FALSE, 116267707Seric "AutoRebuildAliases", 'D', FALSE, 116367707Seric "DeliveryMode", 'd', TRUE, 116467707Seric "ErrorHeader", 'E', FALSE, 116567707Seric "ErrorMode", 'e', TRUE, 116667707Seric "TempFileMode", 'F', FALSE, 116767707Seric "SaveFromLine", 'f', FALSE, 116867707Seric "MatchGECOS", 'G', FALSE, 116967707Seric "HelpFile", 'H', FALSE, 117067707Seric "MaxHopCount", 'h', FALSE, 117167707Seric "NameServerOptions", 'I', FALSE, 117267707Seric "IgnoreDots", 'i', TRUE, 117367707Seric "ForwardPath", 'J', FALSE, 117467707Seric "SendMimeErrors", 'j', TRUE, 117567707Seric "ConnectionCacheSize", 'k', FALSE, 117667707Seric "ConnectionCacheTimeout", 'K', FALSE, 117767707Seric "UseErrorsTo", 'l', FALSE, 117867707Seric "LogLevel", 'L', FALSE, 117967707Seric "MeToo", 'm', TRUE, 118067707Seric "CheckAliases", 'n', FALSE, 118167707Seric "OldStyleHeaders", 'o', TRUE, 118267707Seric "DaemonPortOptions", 'O', FALSE, 118367707Seric "PrivacyOptions", 'p', TRUE, 118467707Seric "PostmasterCopy", 'P', FALSE, 118567707Seric "QueueFactor", 'q', FALSE, 118667707Seric "QueueDirectory", 'Q', FALSE, 118767707Seric "DontPruneRoutes", 'R', FALSE, 118867711Seric "Timeouts", 'r', TRUE, 118967707Seric "StatusFile", 'S', FALSE, 119067707Seric "SuperSafe", 's', TRUE, 119167707Seric "QueueTimeout", 'T', FALSE, 119267707Seric "TimeZoneSpec", 't', FALSE, 119367707Seric "UserDatabaseSpec", 'U', FALSE, 119467707Seric "DefaultUser", 'u', FALSE, 119567707Seric "FallbackMXhost", 'V', FALSE, 119667707Seric "Verbose", 'v', TRUE, 119767707Seric "TryNullMXList", 'w', TRUE, 119867707Seric "QueueLA", 'x', FALSE, 119967707Seric "RefuseLA", 'X', FALSE, 120067707Seric "RecipientFactor", 'y', FALSE, 120167707Seric "ForkQueueRuns", 'Y', FALSE, 120267707Seric "ClassFactor", 'z', FALSE, 120367707Seric "TimeFactor", 'Z', FALSE, 120467707Seric #define O_BSP 0x80 120567707Seric "BrokenSmtpPeers", O_BSP, TRUE, 120667707Seric #define O_SQBH 0x81 120767707Seric "SortQueueByHost", O_SQBH, TRUE, 120867707Seric #define O_DNICE 0x82 120967707Seric "DeliveryNiceness", O_DNICE, TRUE, 121067707Seric #define O_MQA 0x83 121167707Seric "MinQueueAge", O_MQA, TRUE, 121267707Seric #define O_MHSA 0x84 121367707Seric "MaxHostStatAge", O_MHSA, TRUE, 121467813Seric #define O_DEFCHARSET 0x85 121567813Seric "DefaultCharSet", O_DEFCHARSET, TRUE, 121667848Seric #define O_SSFILE 0x86 121767848Seric "ServiceSwitchFile", O_SSFILE, FALSE, 121867707Seric 121967707Seric NULL, '\0', FALSE, 122067614Seric }; 122167614Seric 122267614Seric 122367614Seric 122458734Seric setoption(opt, val, safe, sticky, e) 122567614Seric u_char opt; 12268256Seric char *val; 122721755Seric bool safe; 12288269Seric bool sticky; 122958734Seric register ENVELOPE *e; 12308256Seric { 123157207Seric register char *p; 123267614Seric register struct optioninfo *o; 123367903Seric char *subopt; 12348265Seric extern bool atobool(); 123512633Seric extern time_t convtime(); 123614879Seric extern int QueueLA; 123714879Seric extern int RefuseLA; 123864718Seric extern bool Warn_Q_option; 12398256Seric 124067736Seric errno = 0; 124167614Seric if (opt == ' ') 124267614Seric { 124367614Seric /* full word options */ 124467736Seric struct optioninfo *sel; 124567614Seric 124667614Seric p = strchr(val, '='); 124767614Seric if (p == NULL) 124867614Seric p = &val[strlen(val)]; 124967614Seric while (*--p == ' ') 125067614Seric continue; 125167614Seric while (*++p == ' ') 125267614Seric *p = '\0'; 125367731Seric if (p == val) 125467731Seric { 125567731Seric syserr("readcf: null option name"); 125667731Seric return; 125767731Seric } 125867614Seric if (*p == '=') 125967614Seric *p++ = '\0'; 126067614Seric while (*p == ' ') 126167614Seric p++; 126267903Seric subopt = strchr(val, '.'); 126367903Seric if (subopt != NULL) 126467903Seric *subopt++ = '\0'; 126567736Seric sel = NULL; 126667614Seric for (o = OptionTab; o->o_name != NULL; o++) 126767614Seric { 126867736Seric if (strncasecmp(o->o_name, val, strlen(val)) != 0) 126967736Seric continue; 127067736Seric if (strlen(o->o_name) == strlen(val)) 127167736Seric { 127267736Seric /* completely specified -- this must be it */ 127367736Seric sel = NULL; 127467614Seric break; 127567736Seric } 127667736Seric if (sel != NULL) 127767736Seric break; 127867736Seric sel = o; 127967614Seric } 128067736Seric if (sel != NULL && o->o_name == NULL) 128167736Seric o = sel; 128267736Seric else if (o->o_name == NULL) 128367787Seric { 128467614Seric syserr("readcf: unknown option name %s", val); 128567787Seric return; 128667787Seric } 128767736Seric else if (sel != NULL) 128867736Seric { 128967736Seric syserr("readcf: ambiguous option name %s (matches %s and %s)", 129067736Seric val, sel->o_name, o->o_name); 129167736Seric return; 129267736Seric } 129367736Seric if (strlen(val) != strlen(o->o_name)) 129467736Seric { 129567736Seric bool oldVerbose = Verbose; 129667736Seric 129767736Seric Verbose = TRUE; 129867736Seric message("Option %s used as abbreviation for %s", 129967736Seric val, o->o_name); 130067736Seric Verbose = oldVerbose; 130167736Seric } 130267614Seric opt = o->o_code; 130367614Seric val = p; 130467614Seric } 130567614Seric else 130667614Seric { 130767614Seric for (o = OptionTab; o->o_name != NULL; o++) 130867614Seric { 130967614Seric if (o->o_code == opt) 131067614Seric break; 131167614Seric } 131267903Seric subopt = NULL; 131367614Seric } 131467614Seric 13158256Seric if (tTd(37, 1)) 131667731Seric { 131767731Seric printf(isascii(opt) && isprint(opt) ? 131867903Seric "setoption %s (%c).%s=%s" : 131967903Seric "setoption %s (0x%x).%s=%s", 132067614Seric o->o_name == NULL ? "<unknown>" : o->o_name, 132167903Seric opt, 132267903Seric subopt == NULL ? "" : subopt, 132367903Seric val); 132467731Seric } 13258256Seric 13268256Seric /* 13278269Seric ** See if this option is preset for us. 13288256Seric */ 13298256Seric 133059731Seric if (!sticky && bitnset(opt, StickyOpt)) 13318269Seric { 13329341Seric if (tTd(37, 1)) 13339341Seric printf(" (ignored)\n"); 13348269Seric return; 13358269Seric } 13368269Seric 133721755Seric /* 133821755Seric ** Check to see if this option can be specified by this user. 133921755Seric */ 134021755Seric 134163787Seric if (!safe && RealUid == 0) 134221755Seric safe = TRUE; 134367614Seric if (!safe && !o->o_safe) 134421755Seric { 134539111Srick if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 134621755Seric { 134736582Sbostic if (tTd(37, 1)) 134836582Sbostic printf(" (unsafe)"); 134963787Seric if (RealUid != geteuid()) 135036582Sbostic { 135151210Seric if (tTd(37, 1)) 135251210Seric printf("(Resetting uid)"); 135363787Seric (void) setgid(RealGid); 135463787Seric (void) setuid(RealUid); 135536582Sbostic } 135621755Seric } 135721755Seric } 135851210Seric if (tTd(37, 1)) 135917985Seric printf("\n"); 13608269Seric 136167614Seric switch (opt & 0xff) 13628256Seric { 136359709Seric case '7': /* force seven-bit input */ 136467546Seric SevenBitInput = atobool(val); 136552106Seric break; 136652106Seric 136767546Seric case '8': /* handling of 8-bit input */ 136867546Seric switch (*val) 136967546Seric { 137067547Seric case 'r': /* reject 8-bit, don't convert MIME */ 137167546Seric MimeMode = 0; 137267546Seric break; 137367546Seric 137467547Seric case 'm': /* convert 8-bit, convert MIME */ 137567546Seric MimeMode = MM_CVTMIME|MM_MIME8BIT; 137667546Seric break; 137767546Seric 137867547Seric case 'j': /* "just send 8" */ 137967546Seric MimeMode = MM_PASS8BIT; 138067546Seric break; 138167546Seric 138267546Seric case 'p': /* pass 8 bit, convert MIME */ 138367546Seric MimeMode = MM_PASS8BIT|MM_CVTMIME; 138467546Seric break; 138567546Seric 138667546Seric case 's': /* strict adherence */ 138767546Seric MimeMode = MM_CVTMIME; 138867546Seric break; 138967546Seric 139067547Seric case 'a': /* encode 8 bit if available */ 139167546Seric MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 139267546Seric break; 139367546Seric 139467547Seric case 'c': /* convert 8 bit to MIME, never 7 bit */ 139567547Seric MimeMode = MM_MIME8BIT; 139667547Seric break; 139767547Seric 139867546Seric default: 139967546Seric syserr("Unknown 8-bit mode %c", *val); 140067546Seric exit(EX_USAGE); 140167546Seric } 140267546Seric break; 140367546Seric 14048256Seric case 'A': /* set default alias file */ 14059381Seric if (val[0] == '\0') 140659672Seric setalias("aliases"); 14079381Seric else 140859672Seric setalias(val); 14098256Seric break; 14108256Seric 141117474Seric case 'a': /* look N minutes for "@:@" in alias file */ 141217474Seric if (val[0] == '\0') 141364796Seric SafeAlias = 5 * 60; /* five minutes */ 141417474Seric else 141564796Seric SafeAlias = convtime(val, 'm'); 141617474Seric break; 141717474Seric 141816843Seric case 'B': /* substitution for blank character */ 141916843Seric SpaceSub = val[0]; 142016843Seric if (SpaceSub == '\0') 142116843Seric SpaceSub = ' '; 142216843Seric break; 142316843Seric 142459283Seric case 'b': /* min blocks free on queue fs/max msg size */ 142559283Seric p = strchr(val, '/'); 142659283Seric if (p != NULL) 142759283Seric { 142859283Seric *p++ = '\0'; 142959283Seric MaxMessageSize = atol(p); 143059283Seric } 143158082Seric MinBlocksFree = atol(val); 143258082Seric break; 143358082Seric 14349284Seric case 'c': /* don't connect to "expensive" mailers */ 14359381Seric NoConnect = atobool(val); 14369284Seric break; 14379284Seric 143851305Seric case 'C': /* checkpoint every N addresses */ 143951305Seric CheckpointInterval = atoi(val); 144024944Seric break; 144124944Seric 14429284Seric case 'd': /* delivery mode */ 14439284Seric switch (*val) 14448269Seric { 14459284Seric case '\0': 144658734Seric e->e_sendmode = SM_DELIVER; 14478269Seric break; 14488269Seric 144910755Seric case SM_QUEUE: /* queue only */ 145010755Seric #ifndef QUEUE 145110755Seric syserr("need QUEUE to set -odqueue"); 145256795Seric #endif /* QUEUE */ 145310755Seric /* fall through..... */ 145410755Seric 14559284Seric case SM_DELIVER: /* do everything */ 14569284Seric case SM_FORK: /* fork after verification */ 145758734Seric e->e_sendmode = *val; 14588269Seric break; 14598269Seric 14608269Seric default: 14619284Seric syserr("Unknown delivery mode %c", *val); 14628269Seric exit(EX_USAGE); 14638269Seric } 14648269Seric break; 14658269Seric 14669146Seric case 'D': /* rebuild alias database as needed */ 14679381Seric AutoRebuild = atobool(val); 14689146Seric break; 14699146Seric 147055372Seric case 'E': /* error message header/header file */ 147155379Seric if (*val != '\0') 147255379Seric ErrMsgFile = newstr(val); 147355372Seric break; 147455372Seric 14758269Seric case 'e': /* set error processing mode */ 14768269Seric switch (*val) 14778269Seric { 14789381Seric case EM_QUIET: /* be silent about it */ 14799381Seric case EM_MAIL: /* mail back */ 14809381Seric case EM_BERKNET: /* do berknet error processing */ 14819381Seric case EM_WRITE: /* write back (or mail) */ 14829381Seric case EM_PRINT: /* print errors normally (default) */ 148358734Seric e->e_errormode = *val; 14848269Seric break; 14858269Seric } 14868269Seric break; 14878269Seric 14889049Seric case 'F': /* file mode */ 148917975Seric FileMode = atooct(val) & 0777; 14909049Seric break; 14919049Seric 14928269Seric case 'f': /* save Unix-style From lines on front */ 14939381Seric SaveFrom = atobool(val); 14948269Seric break; 14958269Seric 149653735Seric case 'G': /* match recipients against GECOS field */ 149753735Seric MatchGecos = atobool(val); 149853735Seric break; 149953735Seric 15008256Seric case 'g': /* default gid */ 150167823Seric g_opt: 150264133Seric if (isascii(*val) && isdigit(*val)) 150364133Seric DefGid = atoi(val); 150464133Seric else 150564133Seric { 150664133Seric register struct group *gr; 150764133Seric 150864133Seric DefGid = -1; 150964133Seric gr = getgrnam(val); 151064133Seric if (gr == NULL) 151167823Seric syserr("readcf: option %c: unknown group %s", 151267823Seric opt, val); 151364133Seric else 151464133Seric DefGid = gr->gr_gid; 151564133Seric } 15168256Seric break; 15178256Seric 15188256Seric case 'H': /* help file */ 15199381Seric if (val[0] == '\0') 15208269Seric HelpFile = "sendmail.hf"; 15219381Seric else 15229381Seric HelpFile = newstr(val); 15238256Seric break; 15248256Seric 152551305Seric case 'h': /* maximum hop count */ 152651305Seric MaxHopCount = atoi(val); 152751305Seric break; 152851305Seric 152935651Seric case 'I': /* use internet domain name server */ 153066334Seric #if NAMED_BIND 153157207Seric for (p = val; *p != 0; ) 153257207Seric { 153357207Seric bool clearmode; 153457207Seric char *q; 153557207Seric struct resolverflags *rfp; 153657207Seric 153757207Seric while (*p == ' ') 153857207Seric p++; 153957207Seric if (*p == '\0') 154057207Seric break; 154157207Seric clearmode = FALSE; 154257207Seric if (*p == '-') 154357207Seric clearmode = TRUE; 154457207Seric else if (*p != '+') 154557207Seric p--; 154657207Seric p++; 154757207Seric q = p; 154858050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 154957207Seric p++; 155057207Seric if (*p != '\0') 155157207Seric *p++ = '\0'; 155257207Seric for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 155357207Seric { 155457207Seric if (strcasecmp(q, rfp->rf_name) == 0) 155557207Seric break; 155657207Seric } 155764923Seric if (rfp->rf_name == NULL) 155864923Seric syserr("readcf: I option value %s unrecognized", q); 155964923Seric else if (clearmode) 156057207Seric _res.options &= ~rfp->rf_bits; 156157207Seric else 156257207Seric _res.options |= rfp->rf_bits; 156357207Seric } 156457207Seric if (tTd(8, 2)) 156557207Seric printf("_res.options = %x\n", _res.options); 156657207Seric #else 156757207Seric usrerr("name server (I option) specified but BIND not compiled in"); 156857207Seric #endif 156935651Seric break; 157035651Seric 15718269Seric case 'i': /* ignore dot lines in message */ 15729381Seric IgnrDot = atobool(val); 15738269Seric break; 15748269Seric 157559730Seric case 'j': /* send errors in MIME (RFC 1341) format */ 157659730Seric SendMIMEErrors = atobool(val); 157759730Seric break; 157859730Seric 157957136Seric case 'J': /* .forward search path */ 158057136Seric ForwardPath = newstr(val); 158157136Seric break; 158257136Seric 158354967Seric case 'k': /* connection cache size */ 158454967Seric MaxMciCache = atoi(val); 158556215Seric if (MaxMciCache < 0) 158656215Seric MaxMciCache = 0; 158754967Seric break; 158854967Seric 158954967Seric case 'K': /* connection cache timeout */ 159058796Seric MciCacheTimeout = convtime(val, 'm'); 159154967Seric break; 159254967Seric 159361104Seric case 'l': /* use Errors-To: header */ 159461104Seric UseErrorsTo = atobool(val); 159561104Seric break; 159661104Seric 15978256Seric case 'L': /* log level */ 159864140Seric if (safe || LogLevel < atoi(val)) 159964140Seric LogLevel = atoi(val); 16008256Seric break; 16018256Seric 16028269Seric case 'M': /* define macro */ 16039381Seric define(val[0], newstr(&val[1]), CurEnv); 160416878Seric sticky = FALSE; 16058269Seric break; 16068269Seric 16078269Seric case 'm': /* send to me too */ 16089381Seric MeToo = atobool(val); 16098269Seric break; 16108269Seric 161125820Seric case 'n': /* validate RHS in newaliases */ 161225820Seric CheckAliases = atobool(val); 161325820Seric break; 161425820Seric 161561104Seric /* 'N' available -- was "net name" */ 161661104Seric 161758851Seric case 'O': /* daemon options */ 161858851Seric setdaemonoptions(val); 161958851Seric break; 162058851Seric 16218269Seric case 'o': /* assume old style headers */ 16229381Seric if (atobool(val)) 16239341Seric CurEnv->e_flags |= EF_OLDSTYLE; 16249341Seric else 16259341Seric CurEnv->e_flags &= ~EF_OLDSTYLE; 16268269Seric break; 16278269Seric 162858082Seric case 'p': /* select privacy level */ 162958082Seric p = val; 163058082Seric for (;;) 163158082Seric { 163258082Seric register struct prival *pv; 163358082Seric extern struct prival PrivacyValues[]; 163458082Seric 163558082Seric while (isascii(*p) && (isspace(*p) || ispunct(*p))) 163658082Seric p++; 163758082Seric if (*p == '\0') 163858082Seric break; 163958082Seric val = p; 164058082Seric while (isascii(*p) && isalnum(*p)) 164158082Seric p++; 164258082Seric if (*p != '\0') 164358082Seric *p++ = '\0'; 164458082Seric 164558082Seric for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 164658082Seric { 164758082Seric if (strcasecmp(val, pv->pv_name) == 0) 164858082Seric break; 164958082Seric } 165058886Seric if (pv->pv_name == NULL) 165158886Seric syserr("readcf: Op line: %s unrecognized", val); 165258082Seric PrivacyFlags |= pv->pv_flag; 165358082Seric } 165458082Seric break; 165558082Seric 165624944Seric case 'P': /* postmaster copy address for returned mail */ 165724944Seric PostMasterCopy = newstr(val); 165824944Seric break; 165924944Seric 166024944Seric case 'q': /* slope of queue only function */ 166124944Seric QueueFactor = atoi(val); 166224944Seric break; 166324944Seric 16648256Seric case 'Q': /* queue directory */ 16659381Seric if (val[0] == '\0') 16668269Seric QueueDir = "mqueue"; 16679381Seric else 16689381Seric QueueDir = newstr(val); 166958789Seric if (RealUid != 0 && !safe) 167064718Seric Warn_Q_option = TRUE; 16718256Seric break; 16728256Seric 167358148Seric case 'R': /* don't prune routes */ 167458148Seric DontPruneRoutes = atobool(val); 167558148Seric break; 167658148Seric 16778256Seric case 'r': /* read timeout */ 167867903Seric if (subopt == NULL) 167967903Seric inittimeouts(val); 168067903Seric else 168167903Seric settimeout(subopt, val); 16828256Seric break; 16838256Seric 16848256Seric case 'S': /* status file */ 16859381Seric if (val[0] == '\0') 16868269Seric StatFile = "sendmail.st"; 16879381Seric else 16889381Seric StatFile = newstr(val); 16898256Seric break; 16908256Seric 16918265Seric case 's': /* be super safe, even if expensive */ 16929381Seric SuperSafe = atobool(val); 16938256Seric break; 16948256Seric 16958256Seric case 'T': /* queue timeout */ 169658737Seric p = strchr(val, '/'); 169758737Seric if (p != NULL) 169858737Seric { 169958737Seric *p++ = '\0'; 170067903Seric settimeout("queuewarn", p); 170158737Seric } 170267903Seric settimeout("queuereturn", val); 170354967Seric break; 17048256Seric 17058265Seric case 't': /* time zone name */ 170652106Seric TimeZoneSpec = newstr(val); 17078265Seric break; 17088265Seric 170950556Seric case 'U': /* location of user database */ 171051360Seric UdbSpec = newstr(val); 171150556Seric break; 171250556Seric 17138256Seric case 'u': /* set default uid */ 171467823Seric for (p = val; *p != '\0'; p++) 171567823Seric { 171667823Seric if (*p == '.' || *p == '/' || *p == ':') 171767823Seric { 171867823Seric *p++ = '\0'; 171967823Seric break; 172067823Seric } 172167823Seric } 172264133Seric if (isascii(*val) && isdigit(*val)) 172364133Seric DefUid = atoi(val); 172464133Seric else 172564133Seric { 172664133Seric register struct passwd *pw; 172764133Seric 172864133Seric DefUid = -1; 172964133Seric pw = getpwnam(val); 173064133Seric if (pw == NULL) 173164133Seric syserr("readcf: option u: unknown user %s", val); 173264133Seric else 173367823Seric { 173464133Seric DefUid = pw->pw_uid; 173567823Seric DefGid = pw->pw_gid; 173667823Seric } 173764133Seric } 173840973Sbostic setdefuser(); 17398256Seric 174067823Seric /* handle the group if it is there */ 174167823Seric if (*p == '\0') 174267823Seric break; 174367823Seric val = p; 174467823Seric goto g_opt; 174567823Seric 174658851Seric case 'V': /* fallback MX host */ 174758851Seric FallBackMX = newstr(val); 174858851Seric break; 174958851Seric 17508269Seric case 'v': /* run in verbose mode */ 17519381Seric Verbose = atobool(val); 17528256Seric break; 17538256Seric 175463837Seric case 'w': /* if we are best MX, try host directly */ 175563837Seric TryNullMXList = atobool(val); 175663837Seric break; 175761104Seric 175861104Seric /* 'W' available -- was wizard password */ 175961104Seric 176014879Seric case 'x': /* load avg at which to auto-queue msgs */ 176114879Seric QueueLA = atoi(val); 176214879Seric break; 176314879Seric 176414879Seric case 'X': /* load avg at which to auto-reject connections */ 176514879Seric RefuseLA = atoi(val); 176614879Seric break; 176714879Seric 176824981Seric case 'y': /* work recipient factor */ 176924981Seric WkRecipFact = atoi(val); 177024981Seric break; 177124981Seric 177224981Seric case 'Y': /* fork jobs during queue runs */ 177324952Seric ForkQueueRuns = atobool(val); 177424952Seric break; 177524952Seric 177624981Seric case 'z': /* work message class factor */ 177724981Seric WkClassFact = atoi(val); 177824981Seric break; 177924981Seric 178024981Seric case 'Z': /* work time factor */ 178124981Seric WkTimeFact = atoi(val); 178224981Seric break; 178324981Seric 178467614Seric case O_BSP: /* SMTP Peers can't handle 2-line greeting */ 178567614Seric BrokenSmtpPeers = atobool(val); 178667614Seric break; 178767614Seric 178867614Seric case O_SQBH: /* sort work queue by host first */ 178967614Seric SortQueueByHost = atobool(val); 179067614Seric break; 179167614Seric 179267707Seric case O_DNICE: /* delivery nice value */ 179367707Seric DeliveryNiceness = atoi(val); 179467707Seric break; 179567707Seric 179667707Seric case O_MQA: /* minimum queue age between deliveries */ 179767707Seric MinQueueAge = convtime(val, 'm'); 179867707Seric break; 179967707Seric 180067707Seric case O_MHSA: /* maximum age of cached host status */ 180167707Seric MaxHostStatAge = convtime(val, 'm'); 180267707Seric break; 180367707Seric 180467813Seric case O_DEFCHARSET: /* default character set for mimefying */ 180567814Seric DefaultCharSet = newstr(val); 180667813Seric break; 180767813Seric 180867848Seric case O_SSFILE: /* service switch file */ 180967848Seric ServiceSwitchFile = newstr(val); 181067848Seric break; 181167848Seric 18128256Seric default: 18138256Seric break; 18148256Seric } 181516878Seric if (sticky) 181616878Seric setbitn(opt, StickyOpt); 18179188Seric return; 18188256Seric } 181910687Seric /* 182010687Seric ** SETCLASS -- set a word into a class 182110687Seric ** 182210687Seric ** Parameters: 182310687Seric ** class -- the class to put the word in. 182410687Seric ** word -- the word to enter 182510687Seric ** 182610687Seric ** Returns: 182710687Seric ** none. 182810687Seric ** 182910687Seric ** Side Effects: 183010687Seric ** puts the word into the symbol table. 183110687Seric */ 183210687Seric 183310687Seric setclass(class, word) 183410687Seric int class; 183510687Seric char *word; 183610687Seric { 183710687Seric register STAB *s; 183810687Seric 183957943Seric if (tTd(37, 8)) 184064326Seric printf("setclass(%c, %s)\n", class, word); 184110687Seric s = stab(word, ST_CLASS, ST_ENTER); 184210687Seric setbitn(class, s->s_class); 184310687Seric } 184453654Seric /* 184553654Seric ** MAKEMAPENTRY -- create a map entry 184653654Seric ** 184753654Seric ** Parameters: 184853654Seric ** line -- the config file line 184953654Seric ** 185053654Seric ** Returns: 185153654Seric ** TRUE if it successfully entered the map entry. 185253654Seric ** FALSE otherwise (usually syntax error). 185353654Seric ** 185453654Seric ** Side Effects: 185553654Seric ** Enters the map into the dictionary. 185653654Seric */ 185753654Seric 185853654Seric void 185953654Seric makemapentry(line) 186053654Seric char *line; 186153654Seric { 186253654Seric register char *p; 186353654Seric char *mapname; 186453654Seric char *classname; 186564078Seric register STAB *s; 186653654Seric STAB *class; 186753654Seric 186858050Seric for (p = line; isascii(*p) && isspace(*p); p++) 186953654Seric continue; 187058050Seric if (!(isascii(*p) && isalnum(*p))) 187153654Seric { 187253654Seric syserr("readcf: config K line: no map name"); 187353654Seric return; 187453654Seric } 187553654Seric 187653654Seric mapname = p; 187767848Seric while ((isascii(*++p) && isalnum(*p)) || *p == '.') 187853654Seric continue; 187953654Seric if (*p != '\0') 188053654Seric *p++ = '\0'; 188158050Seric while (isascii(*p) && isspace(*p)) 188253654Seric p++; 188358050Seric if (!(isascii(*p) && isalnum(*p))) 188453654Seric { 188553654Seric syserr("readcf: config K line, map %s: no map class", mapname); 188653654Seric return; 188753654Seric } 188853654Seric classname = p; 188958050Seric while (isascii(*++p) && isalnum(*p)) 189053654Seric continue; 189153654Seric if (*p != '\0') 189253654Seric *p++ = '\0'; 189358050Seric while (isascii(*p) && isspace(*p)) 189453654Seric p++; 189553654Seric 189653654Seric /* look up the class */ 189753654Seric class = stab(classname, ST_MAPCLASS, ST_FIND); 189853654Seric if (class == NULL) 189953654Seric { 190053654Seric syserr("readcf: map %s: class %s not available", mapname, classname); 190153654Seric return; 190253654Seric } 190353654Seric 190453654Seric /* enter the map */ 190564078Seric s = stab(mapname, ST_MAP, ST_ENTER); 190664078Seric s->s_map.map_class = &class->s_mapclass; 190764078Seric s->s_map.map_mname = newstr(mapname); 190853654Seric 190964078Seric if (class->s_mapclass.map_parse(&s->s_map, p)) 191064078Seric s->s_map.map_mflags |= MF_VALID; 191164078Seric 191264078Seric if (tTd(37, 5)) 191364078Seric { 191464078Seric printf("map %s, class %s, flags %x, file %s,\n", 191564078Seric s->s_map.map_mname, s->s_map.map_class->map_cname, 191664078Seric s->s_map.map_mflags, 191764078Seric s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 191864078Seric printf("\tapp %s, domain %s, rebuild %s\n", 191964078Seric s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 192064078Seric s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 192164078Seric s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 192264078Seric } 192353654Seric } 192458112Seric /* 192567903Seric ** INITTIMEOUTS -- parse and set timeout values 192658112Seric ** 192758112Seric ** Parameters: 192858112Seric ** val -- a pointer to the values. If NULL, do initial 192958112Seric ** settings. 193058112Seric ** 193158112Seric ** Returns: 193258112Seric ** none. 193358112Seric ** 193458112Seric ** Side Effects: 193558112Seric ** Initializes the TimeOuts structure 193658112Seric */ 193758112Seric 193864255Seric #define SECONDS 193958112Seric #define MINUTES * 60 194058112Seric #define HOUR * 3600 194158112Seric 194267903Seric inittimeouts(val) 194358112Seric register char *val; 194458112Seric { 194558112Seric register char *p; 194658671Seric extern time_t convtime(); 194758112Seric 194858112Seric if (val == NULL) 194958112Seric { 195058112Seric TimeOuts.to_initial = (time_t) 5 MINUTES; 195158112Seric TimeOuts.to_helo = (time_t) 5 MINUTES; 195258112Seric TimeOuts.to_mail = (time_t) 10 MINUTES; 195358112Seric TimeOuts.to_rcpt = (time_t) 1 HOUR; 195458112Seric TimeOuts.to_datainit = (time_t) 5 MINUTES; 195558112Seric TimeOuts.to_datablock = (time_t) 1 HOUR; 195658112Seric TimeOuts.to_datafinal = (time_t) 1 HOUR; 195758112Seric TimeOuts.to_rset = (time_t) 5 MINUTES; 195858112Seric TimeOuts.to_quit = (time_t) 2 MINUTES; 195958112Seric TimeOuts.to_nextcommand = (time_t) 1 HOUR; 196058112Seric TimeOuts.to_miscshort = (time_t) 2 MINUTES; 196164255Seric TimeOuts.to_ident = (time_t) 30 SECONDS; 196267711Seric TimeOuts.to_fileopen = (time_t) 60 SECONDS; 196358112Seric return; 196458112Seric } 196558112Seric 196658112Seric for (;; val = p) 196758112Seric { 196858112Seric while (isascii(*val) && isspace(*val)) 196958112Seric val++; 197058112Seric if (*val == '\0') 197158112Seric break; 197258112Seric for (p = val; *p != '\0' && *p != ','; p++) 197358112Seric continue; 197458112Seric if (*p != '\0') 197558112Seric *p++ = '\0'; 197658112Seric 197758112Seric if (isascii(*val) && isdigit(*val)) 197858112Seric { 197958112Seric /* old syntax -- set everything */ 198058796Seric TimeOuts.to_mail = convtime(val, 'm'); 198158112Seric TimeOuts.to_rcpt = TimeOuts.to_mail; 198258112Seric TimeOuts.to_datainit = TimeOuts.to_mail; 198358112Seric TimeOuts.to_datablock = TimeOuts.to_mail; 198458112Seric TimeOuts.to_datafinal = TimeOuts.to_mail; 198558112Seric TimeOuts.to_nextcommand = TimeOuts.to_mail; 198658112Seric continue; 198758112Seric } 198858112Seric else 198958112Seric { 199067711Seric register char *q = strchr(val, ':'); 199158112Seric 199267711Seric if (q == NULL && (q = strchr(val, '=')) == NULL) 199358112Seric { 199458112Seric /* syntax error */ 199558112Seric continue; 199658112Seric } 199758112Seric *q++ = '\0'; 199867903Seric settimeout(val, q); 199967903Seric } 200067903Seric } 200167903Seric } 200267903Seric /* 200367903Seric ** SETTIMEOUT -- set an individual timeout 200467903Seric ** 200567903Seric ** Parameters: 200667903Seric ** name -- the name of the timeout. 200767903Seric ** val -- the value of the timeout. 200867903Seric ** 200967903Seric ** Returns: 201067903Seric ** none. 201167903Seric */ 201258112Seric 201367903Seric settimeout(name, val) 201467903Seric char *name; 201567903Seric char *val; 201667903Seric { 201767903Seric register char *p; 201867903Seric time_t to; 201967903Seric extern time_t convtime(); 202067903Seric 202167903Seric to = convtime(val, 'm'); 202267903Seric p = strchr(name, '.'); 202367903Seric if (p != NULL) 202467903Seric *p++ = '\0'; 202567903Seric 202667903Seric if (strcasecmp(name, "initial") == 0) 202767903Seric TimeOuts.to_initial = to; 202867903Seric else if (strcasecmp(name, "mail") == 0) 202967903Seric TimeOuts.to_mail = to; 203067903Seric else if (strcasecmp(name, "rcpt") == 0) 203167903Seric TimeOuts.to_rcpt = to; 203267903Seric else if (strcasecmp(name, "datainit") == 0) 203367903Seric TimeOuts.to_datainit = to; 203467903Seric else if (strcasecmp(name, "datablock") == 0) 203567903Seric TimeOuts.to_datablock = to; 203667903Seric else if (strcasecmp(name, "datafinal") == 0) 203767903Seric TimeOuts.to_datafinal = to; 203867903Seric else if (strcasecmp(name, "command") == 0) 203967903Seric TimeOuts.to_nextcommand = to; 204067903Seric else if (strcasecmp(name, "rset") == 0) 204167903Seric TimeOuts.to_rset = to; 204267903Seric else if (strcasecmp(name, "helo") == 0) 204367903Seric TimeOuts.to_helo = to; 204467903Seric else if (strcasecmp(name, "quit") == 0) 204567903Seric TimeOuts.to_quit = to; 204667903Seric else if (strcasecmp(name, "misc") == 0) 204767903Seric TimeOuts.to_miscshort = to; 204867903Seric else if (strcasecmp(name, "ident") == 0) 204967903Seric TimeOuts.to_ident = to; 205067903Seric else if (strcasecmp(name, "fileopen") == 0) 205167903Seric TimeOuts.to_fileopen = to; 205267903Seric else if (strcasecmp(name, "queuewarn") == 0) 205367903Seric { 205467903Seric to = convtime(val, 'h'); 205567946Seric if (p == NULL || strcmp(p, "*") == 0) 205667903Seric { 205767903Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 205867903Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 205967903Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 206058112Seric } 206167903Seric else if (strcasecmp(p, "normal") == 0) 206267903Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 206367903Seric else if (strcasecmp(p, "urgent") == 0) 206467903Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 206567903Seric else if (strcasecmp(p, "non-urgent") == 0) 206667903Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 206767903Seric else 206867903Seric syserr("settimeout: invalid queuewarn subtimeout %s", p); 206958112Seric } 207067903Seric else if (strcasecmp(name, "queuereturn") == 0) 207167903Seric { 207267903Seric to = convtime(val, 'd'); 207367903Seric if (p == NULL || strcmp(p, "*") == 0) 207467903Seric { 207567903Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 207667903Seric TimeOuts.to_q_return[TOC_URGENT] = to; 207767903Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 207867903Seric } 207967903Seric else if (strcasecmp(p, "normal") == 0) 208067903Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 208167903Seric else if (strcasecmp(p, "urgent") == 0) 208267903Seric TimeOuts.to_q_return[TOC_URGENT] = to; 208367903Seric else if (strcasecmp(p, "non-urgent") == 0) 208467903Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 208567903Seric else 208667903Seric syserr("settimeout: invalid queuereturn subtimeout %s", p); 208767903Seric } 208867903Seric else 208967903Seric syserr("settimeout: invalid timeout %s", name); 209058112Seric } 2091