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*67990Seric static char sccsid[] = "@(#)readcf.c 8.49 (Berkeley) 11/25/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 818*67990Seric case 'T': /* MTS Type */ 819*67990Seric m->m_mtstype = newstr(p); 820*67990Seric break; 821*67990Seric 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 } 10584319Seric 10594096Seric /* 10608256Seric ** SETOPTION -- set global processing option 10618256Seric ** 10628256Seric ** Parameters: 10638256Seric ** opt -- option name. 10648256Seric ** val -- option value (as a text string). 106521755Seric ** safe -- set if this came from a configuration file. 106621755Seric ** Some options (if set from the command line) will 106721755Seric ** reset the user id to avoid security problems. 10688269Seric ** sticky -- if set, don't let other setoptions override 10698269Seric ** this value. 107058734Seric ** e -- the main envelope. 10718256Seric ** 10728256Seric ** Returns: 10738256Seric ** none. 10748256Seric ** 10758256Seric ** Side Effects: 10768256Seric ** Sets options as implied by the arguments. 10778256Seric */ 10788256Seric 107910687Seric static BITMAP StickyOpt; /* set if option is stuck */ 10808269Seric 108157207Seric 108266334Seric #if NAMED_BIND 108357207Seric 108457207Seric struct resolverflags 108557207Seric { 108657207Seric char *rf_name; /* name of the flag */ 108757207Seric long rf_bits; /* bits to set/clear */ 108857207Seric } ResolverFlags[] = 108957207Seric { 109057207Seric "debug", RES_DEBUG, 109157207Seric "aaonly", RES_AAONLY, 109257207Seric "usevc", RES_USEVC, 109357207Seric "primary", RES_PRIMARY, 109457207Seric "igntc", RES_IGNTC, 109557207Seric "recurse", RES_RECURSE, 109657207Seric "defnames", RES_DEFNAMES, 109757207Seric "stayopen", RES_STAYOPEN, 109857207Seric "dnsrch", RES_DNSRCH, 109965583Seric "true", 0, /* to avoid error on old syntax */ 110057207Seric NULL, 0 110157207Seric }; 110257207Seric 110357207Seric #endif 110457207Seric 110567614Seric struct optioninfo 110667614Seric { 110767614Seric char *o_name; /* long name of option */ 110867787Seric u_char o_code; /* short name of option */ 110967614Seric bool o_safe; /* safe for random people to use */ 111067614Seric } OptionTab[] = 111167614Seric { 111267707Seric "SevenBitInput", '7', TRUE, 111367707Seric "EightBitMode", '8', TRUE, 111467707Seric "AliasFile", 'A', FALSE, 111567707Seric "AliasWait", 'a', FALSE, 111667707Seric "BlankSub", 'B', FALSE, 111767707Seric "MinFreeBlocks", 'b', TRUE, 111867707Seric "CheckpointInterval", 'C', TRUE, 111967707Seric "HoldExpensive", 'c', FALSE, 112067707Seric "AutoRebuildAliases", 'D', FALSE, 112167707Seric "DeliveryMode", 'd', TRUE, 112267707Seric "ErrorHeader", 'E', FALSE, 112367707Seric "ErrorMode", 'e', TRUE, 112467707Seric "TempFileMode", 'F', FALSE, 112567707Seric "SaveFromLine", 'f', FALSE, 112667707Seric "MatchGECOS", 'G', FALSE, 112767707Seric "HelpFile", 'H', FALSE, 112867707Seric "MaxHopCount", 'h', FALSE, 112967707Seric "NameServerOptions", 'I', FALSE, 113067707Seric "IgnoreDots", 'i', TRUE, 113167707Seric "ForwardPath", 'J', FALSE, 113267707Seric "SendMimeErrors", 'j', TRUE, 113367707Seric "ConnectionCacheSize", 'k', FALSE, 113467707Seric "ConnectionCacheTimeout", 'K', FALSE, 113567707Seric "UseErrorsTo", 'l', FALSE, 113667707Seric "LogLevel", 'L', FALSE, 113767707Seric "MeToo", 'm', TRUE, 113867707Seric "CheckAliases", 'n', FALSE, 113967707Seric "OldStyleHeaders", 'o', TRUE, 114067707Seric "DaemonPortOptions", 'O', FALSE, 114167707Seric "PrivacyOptions", 'p', TRUE, 114267707Seric "PostmasterCopy", 'P', FALSE, 114367707Seric "QueueFactor", 'q', FALSE, 114467707Seric "QueueDirectory", 'Q', FALSE, 114567707Seric "DontPruneRoutes", 'R', FALSE, 114667711Seric "Timeouts", 'r', TRUE, 114767707Seric "StatusFile", 'S', FALSE, 114867707Seric "SuperSafe", 's', TRUE, 114967707Seric "QueueTimeout", 'T', FALSE, 115067707Seric "TimeZoneSpec", 't', FALSE, 115167707Seric "UserDatabaseSpec", 'U', FALSE, 115267707Seric "DefaultUser", 'u', FALSE, 115367707Seric "FallbackMXhost", 'V', FALSE, 115467707Seric "Verbose", 'v', TRUE, 115567707Seric "TryNullMXList", 'w', TRUE, 115667707Seric "QueueLA", 'x', FALSE, 115767707Seric "RefuseLA", 'X', FALSE, 115867707Seric "RecipientFactor", 'y', FALSE, 115967707Seric "ForkQueueRuns", 'Y', FALSE, 116067707Seric "ClassFactor", 'z', FALSE, 116167707Seric "TimeFactor", 'Z', FALSE, 116267707Seric #define O_BSP 0x80 116367707Seric "BrokenSmtpPeers", O_BSP, TRUE, 116467707Seric #define O_SQBH 0x81 116567707Seric "SortQueueByHost", O_SQBH, TRUE, 116667707Seric #define O_DNICE 0x82 116767707Seric "DeliveryNiceness", O_DNICE, TRUE, 116867707Seric #define O_MQA 0x83 116967707Seric "MinQueueAge", O_MQA, TRUE, 117067707Seric #define O_MHSA 0x84 117167707Seric "MaxHostStatAge", O_MHSA, TRUE, 117267813Seric #define O_DEFCHARSET 0x85 117367813Seric "DefaultCharSet", O_DEFCHARSET, TRUE, 117467848Seric #define O_SSFILE 0x86 117567848Seric "ServiceSwitchFile", O_SSFILE, FALSE, 117667707Seric 117767707Seric NULL, '\0', FALSE, 117867614Seric }; 117967614Seric 118067614Seric 118167614Seric 118258734Seric setoption(opt, val, safe, sticky, e) 118367614Seric u_char opt; 11848256Seric char *val; 118521755Seric bool safe; 11868269Seric bool sticky; 118758734Seric register ENVELOPE *e; 11888256Seric { 118957207Seric register char *p; 119067614Seric register struct optioninfo *o; 119167903Seric char *subopt; 11928265Seric extern bool atobool(); 119312633Seric extern time_t convtime(); 119414879Seric extern int QueueLA; 119514879Seric extern int RefuseLA; 119664718Seric extern bool Warn_Q_option; 11978256Seric 119867736Seric errno = 0; 119967614Seric if (opt == ' ') 120067614Seric { 120167614Seric /* full word options */ 120267736Seric struct optioninfo *sel; 120367614Seric 120467614Seric p = strchr(val, '='); 120567614Seric if (p == NULL) 120667614Seric p = &val[strlen(val)]; 120767614Seric while (*--p == ' ') 120867614Seric continue; 120967614Seric while (*++p == ' ') 121067614Seric *p = '\0'; 121167731Seric if (p == val) 121267731Seric { 121367731Seric syserr("readcf: null option name"); 121467731Seric return; 121567731Seric } 121667614Seric if (*p == '=') 121767614Seric *p++ = '\0'; 121867614Seric while (*p == ' ') 121967614Seric p++; 122067903Seric subopt = strchr(val, '.'); 122167903Seric if (subopt != NULL) 122267903Seric *subopt++ = '\0'; 122367736Seric sel = NULL; 122467614Seric for (o = OptionTab; o->o_name != NULL; o++) 122567614Seric { 122667736Seric if (strncasecmp(o->o_name, val, strlen(val)) != 0) 122767736Seric continue; 122867736Seric if (strlen(o->o_name) == strlen(val)) 122967736Seric { 123067736Seric /* completely specified -- this must be it */ 123167736Seric sel = NULL; 123267614Seric break; 123367736Seric } 123467736Seric if (sel != NULL) 123567736Seric break; 123667736Seric sel = o; 123767614Seric } 123867736Seric if (sel != NULL && o->o_name == NULL) 123967736Seric o = sel; 124067736Seric else if (o->o_name == NULL) 124167787Seric { 124267614Seric syserr("readcf: unknown option name %s", val); 124367787Seric return; 124467787Seric } 124567736Seric else if (sel != NULL) 124667736Seric { 124767736Seric syserr("readcf: ambiguous option name %s (matches %s and %s)", 124867736Seric val, sel->o_name, o->o_name); 124967736Seric return; 125067736Seric } 125167736Seric if (strlen(val) != strlen(o->o_name)) 125267736Seric { 125367736Seric bool oldVerbose = Verbose; 125467736Seric 125567736Seric Verbose = TRUE; 125667736Seric message("Option %s used as abbreviation for %s", 125767736Seric val, o->o_name); 125867736Seric Verbose = oldVerbose; 125967736Seric } 126067614Seric opt = o->o_code; 126167614Seric val = p; 126267614Seric } 126367614Seric else 126467614Seric { 126567614Seric for (o = OptionTab; o->o_name != NULL; o++) 126667614Seric { 126767614Seric if (o->o_code == opt) 126867614Seric break; 126967614Seric } 127067903Seric subopt = NULL; 127167614Seric } 127267614Seric 12738256Seric if (tTd(37, 1)) 127467731Seric { 127567731Seric printf(isascii(opt) && isprint(opt) ? 127667903Seric "setoption %s (%c).%s=%s" : 127767903Seric "setoption %s (0x%x).%s=%s", 127867614Seric o->o_name == NULL ? "<unknown>" : o->o_name, 127967903Seric opt, 128067903Seric subopt == NULL ? "" : subopt, 128167903Seric val); 128267731Seric } 12838256Seric 12848256Seric /* 12858269Seric ** See if this option is preset for us. 12868256Seric */ 12878256Seric 128859731Seric if (!sticky && bitnset(opt, StickyOpt)) 12898269Seric { 12909341Seric if (tTd(37, 1)) 12919341Seric printf(" (ignored)\n"); 12928269Seric return; 12938269Seric } 12948269Seric 129521755Seric /* 129621755Seric ** Check to see if this option can be specified by this user. 129721755Seric */ 129821755Seric 129963787Seric if (!safe && RealUid == 0) 130021755Seric safe = TRUE; 130167614Seric if (!safe && !o->o_safe) 130221755Seric { 130339111Srick if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 130421755Seric { 130536582Sbostic if (tTd(37, 1)) 130636582Sbostic printf(" (unsafe)"); 130763787Seric if (RealUid != geteuid()) 130836582Sbostic { 130951210Seric if (tTd(37, 1)) 131051210Seric printf("(Resetting uid)"); 131163787Seric (void) setgid(RealGid); 131263787Seric (void) setuid(RealUid); 131336582Sbostic } 131421755Seric } 131521755Seric } 131651210Seric if (tTd(37, 1)) 131717985Seric printf("\n"); 13188269Seric 131967614Seric switch (opt & 0xff) 13208256Seric { 132159709Seric case '7': /* force seven-bit input */ 132267546Seric SevenBitInput = atobool(val); 132352106Seric break; 132452106Seric 132567546Seric case '8': /* handling of 8-bit input */ 132667546Seric switch (*val) 132767546Seric { 132867547Seric case 'r': /* reject 8-bit, don't convert MIME */ 132967546Seric MimeMode = 0; 133067546Seric break; 133167546Seric 133267547Seric case 'm': /* convert 8-bit, convert MIME */ 133367546Seric MimeMode = MM_CVTMIME|MM_MIME8BIT; 133467546Seric break; 133567546Seric 133667547Seric case 'j': /* "just send 8" */ 133767546Seric MimeMode = MM_PASS8BIT; 133867546Seric break; 133967546Seric 134067546Seric case 'p': /* pass 8 bit, convert MIME */ 134167546Seric MimeMode = MM_PASS8BIT|MM_CVTMIME; 134267546Seric break; 134367546Seric 134467546Seric case 's': /* strict adherence */ 134567546Seric MimeMode = MM_CVTMIME; 134667546Seric break; 134767546Seric 134867547Seric case 'a': /* encode 8 bit if available */ 134967546Seric MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 135067546Seric break; 135167546Seric 135267547Seric case 'c': /* convert 8 bit to MIME, never 7 bit */ 135367547Seric MimeMode = MM_MIME8BIT; 135467547Seric break; 135567547Seric 135667546Seric default: 135767546Seric syserr("Unknown 8-bit mode %c", *val); 135867546Seric exit(EX_USAGE); 135967546Seric } 136067546Seric break; 136167546Seric 13628256Seric case 'A': /* set default alias file */ 13639381Seric if (val[0] == '\0') 136459672Seric setalias("aliases"); 13659381Seric else 136659672Seric setalias(val); 13678256Seric break; 13688256Seric 136917474Seric case 'a': /* look N minutes for "@:@" in alias file */ 137017474Seric if (val[0] == '\0') 137164796Seric SafeAlias = 5 * 60; /* five minutes */ 137217474Seric else 137364796Seric SafeAlias = convtime(val, 'm'); 137417474Seric break; 137517474Seric 137616843Seric case 'B': /* substitution for blank character */ 137716843Seric SpaceSub = val[0]; 137816843Seric if (SpaceSub == '\0') 137916843Seric SpaceSub = ' '; 138016843Seric break; 138116843Seric 138259283Seric case 'b': /* min blocks free on queue fs/max msg size */ 138359283Seric p = strchr(val, '/'); 138459283Seric if (p != NULL) 138559283Seric { 138659283Seric *p++ = '\0'; 138759283Seric MaxMessageSize = atol(p); 138859283Seric } 138958082Seric MinBlocksFree = atol(val); 139058082Seric break; 139158082Seric 13929284Seric case 'c': /* don't connect to "expensive" mailers */ 13939381Seric NoConnect = atobool(val); 13949284Seric break; 13959284Seric 139651305Seric case 'C': /* checkpoint every N addresses */ 139751305Seric CheckpointInterval = atoi(val); 139824944Seric break; 139924944Seric 14009284Seric case 'd': /* delivery mode */ 14019284Seric switch (*val) 14028269Seric { 14039284Seric case '\0': 140458734Seric e->e_sendmode = SM_DELIVER; 14058269Seric break; 14068269Seric 140710755Seric case SM_QUEUE: /* queue only */ 140810755Seric #ifndef QUEUE 140910755Seric syserr("need QUEUE to set -odqueue"); 141056795Seric #endif /* QUEUE */ 141110755Seric /* fall through..... */ 141210755Seric 14139284Seric case SM_DELIVER: /* do everything */ 14149284Seric case SM_FORK: /* fork after verification */ 141558734Seric e->e_sendmode = *val; 14168269Seric break; 14178269Seric 14188269Seric default: 14199284Seric syserr("Unknown delivery mode %c", *val); 14208269Seric exit(EX_USAGE); 14218269Seric } 14228269Seric break; 14238269Seric 14249146Seric case 'D': /* rebuild alias database as needed */ 14259381Seric AutoRebuild = atobool(val); 14269146Seric break; 14279146Seric 142855372Seric case 'E': /* error message header/header file */ 142955379Seric if (*val != '\0') 143055379Seric ErrMsgFile = newstr(val); 143155372Seric break; 143255372Seric 14338269Seric case 'e': /* set error processing mode */ 14348269Seric switch (*val) 14358269Seric { 14369381Seric case EM_QUIET: /* be silent about it */ 14379381Seric case EM_MAIL: /* mail back */ 14389381Seric case EM_BERKNET: /* do berknet error processing */ 14399381Seric case EM_WRITE: /* write back (or mail) */ 14409381Seric case EM_PRINT: /* print errors normally (default) */ 144158734Seric e->e_errormode = *val; 14428269Seric break; 14438269Seric } 14448269Seric break; 14458269Seric 14469049Seric case 'F': /* file mode */ 144717975Seric FileMode = atooct(val) & 0777; 14489049Seric break; 14499049Seric 14508269Seric case 'f': /* save Unix-style From lines on front */ 14519381Seric SaveFrom = atobool(val); 14528269Seric break; 14538269Seric 145453735Seric case 'G': /* match recipients against GECOS field */ 145553735Seric MatchGecos = atobool(val); 145653735Seric break; 145753735Seric 14588256Seric case 'g': /* default gid */ 145967823Seric g_opt: 146064133Seric if (isascii(*val) && isdigit(*val)) 146164133Seric DefGid = atoi(val); 146264133Seric else 146364133Seric { 146464133Seric register struct group *gr; 146564133Seric 146664133Seric DefGid = -1; 146764133Seric gr = getgrnam(val); 146864133Seric if (gr == NULL) 146967823Seric syserr("readcf: option %c: unknown group %s", 147067823Seric opt, val); 147164133Seric else 147264133Seric DefGid = gr->gr_gid; 147364133Seric } 14748256Seric break; 14758256Seric 14768256Seric case 'H': /* help file */ 14779381Seric if (val[0] == '\0') 14788269Seric HelpFile = "sendmail.hf"; 14799381Seric else 14809381Seric HelpFile = newstr(val); 14818256Seric break; 14828256Seric 148351305Seric case 'h': /* maximum hop count */ 148451305Seric MaxHopCount = atoi(val); 148551305Seric break; 148651305Seric 148735651Seric case 'I': /* use internet domain name server */ 148866334Seric #if NAMED_BIND 148957207Seric for (p = val; *p != 0; ) 149057207Seric { 149157207Seric bool clearmode; 149257207Seric char *q; 149357207Seric struct resolverflags *rfp; 149457207Seric 149557207Seric while (*p == ' ') 149657207Seric p++; 149757207Seric if (*p == '\0') 149857207Seric break; 149957207Seric clearmode = FALSE; 150057207Seric if (*p == '-') 150157207Seric clearmode = TRUE; 150257207Seric else if (*p != '+') 150357207Seric p--; 150457207Seric p++; 150557207Seric q = p; 150658050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 150757207Seric p++; 150857207Seric if (*p != '\0') 150957207Seric *p++ = '\0'; 151057207Seric for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 151157207Seric { 151257207Seric if (strcasecmp(q, rfp->rf_name) == 0) 151357207Seric break; 151457207Seric } 151564923Seric if (rfp->rf_name == NULL) 151664923Seric syserr("readcf: I option value %s unrecognized", q); 151764923Seric else if (clearmode) 151857207Seric _res.options &= ~rfp->rf_bits; 151957207Seric else 152057207Seric _res.options |= rfp->rf_bits; 152157207Seric } 152257207Seric if (tTd(8, 2)) 152357207Seric printf("_res.options = %x\n", _res.options); 152457207Seric #else 152557207Seric usrerr("name server (I option) specified but BIND not compiled in"); 152657207Seric #endif 152735651Seric break; 152835651Seric 15298269Seric case 'i': /* ignore dot lines in message */ 15309381Seric IgnrDot = atobool(val); 15318269Seric break; 15328269Seric 153359730Seric case 'j': /* send errors in MIME (RFC 1341) format */ 153459730Seric SendMIMEErrors = atobool(val); 153559730Seric break; 153659730Seric 153757136Seric case 'J': /* .forward search path */ 153857136Seric ForwardPath = newstr(val); 153957136Seric break; 154057136Seric 154154967Seric case 'k': /* connection cache size */ 154254967Seric MaxMciCache = atoi(val); 154356215Seric if (MaxMciCache < 0) 154456215Seric MaxMciCache = 0; 154554967Seric break; 154654967Seric 154754967Seric case 'K': /* connection cache timeout */ 154858796Seric MciCacheTimeout = convtime(val, 'm'); 154954967Seric break; 155054967Seric 155161104Seric case 'l': /* use Errors-To: header */ 155261104Seric UseErrorsTo = atobool(val); 155361104Seric break; 155461104Seric 15558256Seric case 'L': /* log level */ 155664140Seric if (safe || LogLevel < atoi(val)) 155764140Seric LogLevel = atoi(val); 15588256Seric break; 15598256Seric 15608269Seric case 'M': /* define macro */ 15619381Seric define(val[0], newstr(&val[1]), CurEnv); 156216878Seric sticky = FALSE; 15638269Seric break; 15648269Seric 15658269Seric case 'm': /* send to me too */ 15669381Seric MeToo = atobool(val); 15678269Seric break; 15688269Seric 156925820Seric case 'n': /* validate RHS in newaliases */ 157025820Seric CheckAliases = atobool(val); 157125820Seric break; 157225820Seric 157361104Seric /* 'N' available -- was "net name" */ 157461104Seric 157558851Seric case 'O': /* daemon options */ 157658851Seric setdaemonoptions(val); 157758851Seric break; 157858851Seric 15798269Seric case 'o': /* assume old style headers */ 15809381Seric if (atobool(val)) 15819341Seric CurEnv->e_flags |= EF_OLDSTYLE; 15829341Seric else 15839341Seric CurEnv->e_flags &= ~EF_OLDSTYLE; 15848269Seric break; 15858269Seric 158658082Seric case 'p': /* select privacy level */ 158758082Seric p = val; 158858082Seric for (;;) 158958082Seric { 159058082Seric register struct prival *pv; 159158082Seric extern struct prival PrivacyValues[]; 159258082Seric 159358082Seric while (isascii(*p) && (isspace(*p) || ispunct(*p))) 159458082Seric p++; 159558082Seric if (*p == '\0') 159658082Seric break; 159758082Seric val = p; 159858082Seric while (isascii(*p) && isalnum(*p)) 159958082Seric p++; 160058082Seric if (*p != '\0') 160158082Seric *p++ = '\0'; 160258082Seric 160358082Seric for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 160458082Seric { 160558082Seric if (strcasecmp(val, pv->pv_name) == 0) 160658082Seric break; 160758082Seric } 160858886Seric if (pv->pv_name == NULL) 160958886Seric syserr("readcf: Op line: %s unrecognized", val); 161058082Seric PrivacyFlags |= pv->pv_flag; 161158082Seric } 161258082Seric break; 161358082Seric 161424944Seric case 'P': /* postmaster copy address for returned mail */ 161524944Seric PostMasterCopy = newstr(val); 161624944Seric break; 161724944Seric 161824944Seric case 'q': /* slope of queue only function */ 161924944Seric QueueFactor = atoi(val); 162024944Seric break; 162124944Seric 16228256Seric case 'Q': /* queue directory */ 16239381Seric if (val[0] == '\0') 16248269Seric QueueDir = "mqueue"; 16259381Seric else 16269381Seric QueueDir = newstr(val); 162758789Seric if (RealUid != 0 && !safe) 162864718Seric Warn_Q_option = TRUE; 16298256Seric break; 16308256Seric 163158148Seric case 'R': /* don't prune routes */ 163258148Seric DontPruneRoutes = atobool(val); 163358148Seric break; 163458148Seric 16358256Seric case 'r': /* read timeout */ 163667903Seric if (subopt == NULL) 163767903Seric inittimeouts(val); 163867903Seric else 163967903Seric settimeout(subopt, val); 16408256Seric break; 16418256Seric 16428256Seric case 'S': /* status file */ 16439381Seric if (val[0] == '\0') 16448269Seric StatFile = "sendmail.st"; 16459381Seric else 16469381Seric StatFile = newstr(val); 16478256Seric break; 16488256Seric 16498265Seric case 's': /* be super safe, even if expensive */ 16509381Seric SuperSafe = atobool(val); 16518256Seric break; 16528256Seric 16538256Seric case 'T': /* queue timeout */ 165458737Seric p = strchr(val, '/'); 165558737Seric if (p != NULL) 165658737Seric { 165758737Seric *p++ = '\0'; 165867903Seric settimeout("queuewarn", p); 165958737Seric } 166067903Seric settimeout("queuereturn", val); 166154967Seric break; 16628256Seric 16638265Seric case 't': /* time zone name */ 166452106Seric TimeZoneSpec = newstr(val); 16658265Seric break; 16668265Seric 166750556Seric case 'U': /* location of user database */ 166851360Seric UdbSpec = newstr(val); 166950556Seric break; 167050556Seric 16718256Seric case 'u': /* set default uid */ 167267823Seric for (p = val; *p != '\0'; p++) 167367823Seric { 167467823Seric if (*p == '.' || *p == '/' || *p == ':') 167567823Seric { 167667823Seric *p++ = '\0'; 167767823Seric break; 167867823Seric } 167967823Seric } 168064133Seric if (isascii(*val) && isdigit(*val)) 168164133Seric DefUid = atoi(val); 168264133Seric else 168364133Seric { 168464133Seric register struct passwd *pw; 168564133Seric 168664133Seric DefUid = -1; 168764133Seric pw = getpwnam(val); 168864133Seric if (pw == NULL) 168964133Seric syserr("readcf: option u: unknown user %s", val); 169064133Seric else 169167823Seric { 169264133Seric DefUid = pw->pw_uid; 169367823Seric DefGid = pw->pw_gid; 169467823Seric } 169564133Seric } 169640973Sbostic setdefuser(); 16978256Seric 169867823Seric /* handle the group if it is there */ 169967823Seric if (*p == '\0') 170067823Seric break; 170167823Seric val = p; 170267823Seric goto g_opt; 170367823Seric 170458851Seric case 'V': /* fallback MX host */ 170558851Seric FallBackMX = newstr(val); 170658851Seric break; 170758851Seric 17088269Seric case 'v': /* run in verbose mode */ 17099381Seric Verbose = atobool(val); 17108256Seric break; 17118256Seric 171263837Seric case 'w': /* if we are best MX, try host directly */ 171363837Seric TryNullMXList = atobool(val); 171463837Seric break; 171561104Seric 171661104Seric /* 'W' available -- was wizard password */ 171761104Seric 171814879Seric case 'x': /* load avg at which to auto-queue msgs */ 171914879Seric QueueLA = atoi(val); 172014879Seric break; 172114879Seric 172214879Seric case 'X': /* load avg at which to auto-reject connections */ 172314879Seric RefuseLA = atoi(val); 172414879Seric break; 172514879Seric 172624981Seric case 'y': /* work recipient factor */ 172724981Seric WkRecipFact = atoi(val); 172824981Seric break; 172924981Seric 173024981Seric case 'Y': /* fork jobs during queue runs */ 173124952Seric ForkQueueRuns = atobool(val); 173224952Seric break; 173324952Seric 173424981Seric case 'z': /* work message class factor */ 173524981Seric WkClassFact = atoi(val); 173624981Seric break; 173724981Seric 173824981Seric case 'Z': /* work time factor */ 173924981Seric WkTimeFact = atoi(val); 174024981Seric break; 174124981Seric 174267614Seric case O_BSP: /* SMTP Peers can't handle 2-line greeting */ 174367614Seric BrokenSmtpPeers = atobool(val); 174467614Seric break; 174567614Seric 174667614Seric case O_SQBH: /* sort work queue by host first */ 174767614Seric SortQueueByHost = atobool(val); 174867614Seric break; 174967614Seric 175067707Seric case O_DNICE: /* delivery nice value */ 175167707Seric DeliveryNiceness = atoi(val); 175267707Seric break; 175367707Seric 175467707Seric case O_MQA: /* minimum queue age between deliveries */ 175567707Seric MinQueueAge = convtime(val, 'm'); 175667707Seric break; 175767707Seric 175867707Seric case O_MHSA: /* maximum age of cached host status */ 175967707Seric MaxHostStatAge = convtime(val, 'm'); 176067707Seric break; 176167707Seric 176267813Seric case O_DEFCHARSET: /* default character set for mimefying */ 176367814Seric DefaultCharSet = newstr(val); 176467813Seric break; 176567813Seric 176667848Seric case O_SSFILE: /* service switch file */ 176767848Seric ServiceSwitchFile = newstr(val); 176867848Seric break; 176967848Seric 17708256Seric default: 17718256Seric break; 17728256Seric } 177316878Seric if (sticky) 177416878Seric setbitn(opt, StickyOpt); 17759188Seric return; 17768256Seric } 177710687Seric /* 177810687Seric ** SETCLASS -- set a word into a class 177910687Seric ** 178010687Seric ** Parameters: 178110687Seric ** class -- the class to put the word in. 178210687Seric ** word -- the word to enter 178310687Seric ** 178410687Seric ** Returns: 178510687Seric ** none. 178610687Seric ** 178710687Seric ** Side Effects: 178810687Seric ** puts the word into the symbol table. 178910687Seric */ 179010687Seric 179110687Seric setclass(class, word) 179210687Seric int class; 179310687Seric char *word; 179410687Seric { 179510687Seric register STAB *s; 179610687Seric 179757943Seric if (tTd(37, 8)) 179864326Seric printf("setclass(%c, %s)\n", class, word); 179910687Seric s = stab(word, ST_CLASS, ST_ENTER); 180010687Seric setbitn(class, s->s_class); 180110687Seric } 180253654Seric /* 180353654Seric ** MAKEMAPENTRY -- create a map entry 180453654Seric ** 180553654Seric ** Parameters: 180653654Seric ** line -- the config file line 180753654Seric ** 180853654Seric ** Returns: 180953654Seric ** TRUE if it successfully entered the map entry. 181053654Seric ** FALSE otherwise (usually syntax error). 181153654Seric ** 181253654Seric ** Side Effects: 181353654Seric ** Enters the map into the dictionary. 181453654Seric */ 181553654Seric 181653654Seric void 181753654Seric makemapentry(line) 181853654Seric char *line; 181953654Seric { 182053654Seric register char *p; 182153654Seric char *mapname; 182253654Seric char *classname; 182364078Seric register STAB *s; 182453654Seric STAB *class; 182553654Seric 182658050Seric for (p = line; isascii(*p) && isspace(*p); p++) 182753654Seric continue; 182858050Seric if (!(isascii(*p) && isalnum(*p))) 182953654Seric { 183053654Seric syserr("readcf: config K line: no map name"); 183153654Seric return; 183253654Seric } 183353654Seric 183453654Seric mapname = p; 183567848Seric while ((isascii(*++p) && isalnum(*p)) || *p == '.') 183653654Seric continue; 183753654Seric if (*p != '\0') 183853654Seric *p++ = '\0'; 183958050Seric while (isascii(*p) && isspace(*p)) 184053654Seric p++; 184158050Seric if (!(isascii(*p) && isalnum(*p))) 184253654Seric { 184353654Seric syserr("readcf: config K line, map %s: no map class", mapname); 184453654Seric return; 184553654Seric } 184653654Seric classname = p; 184758050Seric while (isascii(*++p) && isalnum(*p)) 184853654Seric continue; 184953654Seric if (*p != '\0') 185053654Seric *p++ = '\0'; 185158050Seric while (isascii(*p) && isspace(*p)) 185253654Seric p++; 185353654Seric 185453654Seric /* look up the class */ 185553654Seric class = stab(classname, ST_MAPCLASS, ST_FIND); 185653654Seric if (class == NULL) 185753654Seric { 185853654Seric syserr("readcf: map %s: class %s not available", mapname, classname); 185953654Seric return; 186053654Seric } 186153654Seric 186253654Seric /* enter the map */ 186364078Seric s = stab(mapname, ST_MAP, ST_ENTER); 186464078Seric s->s_map.map_class = &class->s_mapclass; 186564078Seric s->s_map.map_mname = newstr(mapname); 186653654Seric 186764078Seric if (class->s_mapclass.map_parse(&s->s_map, p)) 186864078Seric s->s_map.map_mflags |= MF_VALID; 186964078Seric 187064078Seric if (tTd(37, 5)) 187164078Seric { 187264078Seric printf("map %s, class %s, flags %x, file %s,\n", 187364078Seric s->s_map.map_mname, s->s_map.map_class->map_cname, 187464078Seric s->s_map.map_mflags, 187564078Seric s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 187664078Seric printf("\tapp %s, domain %s, rebuild %s\n", 187764078Seric s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 187864078Seric s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 187964078Seric s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 188064078Seric } 188153654Seric } 188258112Seric /* 188367903Seric ** INITTIMEOUTS -- parse and set timeout values 188458112Seric ** 188558112Seric ** Parameters: 188658112Seric ** val -- a pointer to the values. If NULL, do initial 188758112Seric ** settings. 188858112Seric ** 188958112Seric ** Returns: 189058112Seric ** none. 189158112Seric ** 189258112Seric ** Side Effects: 189358112Seric ** Initializes the TimeOuts structure 189458112Seric */ 189558112Seric 189664255Seric #define SECONDS 189758112Seric #define MINUTES * 60 189858112Seric #define HOUR * 3600 189958112Seric 190067903Seric inittimeouts(val) 190158112Seric register char *val; 190258112Seric { 190358112Seric register char *p; 190458671Seric extern time_t convtime(); 190558112Seric 190658112Seric if (val == NULL) 190758112Seric { 190858112Seric TimeOuts.to_initial = (time_t) 5 MINUTES; 190958112Seric TimeOuts.to_helo = (time_t) 5 MINUTES; 191058112Seric TimeOuts.to_mail = (time_t) 10 MINUTES; 191158112Seric TimeOuts.to_rcpt = (time_t) 1 HOUR; 191258112Seric TimeOuts.to_datainit = (time_t) 5 MINUTES; 191358112Seric TimeOuts.to_datablock = (time_t) 1 HOUR; 191458112Seric TimeOuts.to_datafinal = (time_t) 1 HOUR; 191558112Seric TimeOuts.to_rset = (time_t) 5 MINUTES; 191658112Seric TimeOuts.to_quit = (time_t) 2 MINUTES; 191758112Seric TimeOuts.to_nextcommand = (time_t) 1 HOUR; 191858112Seric TimeOuts.to_miscshort = (time_t) 2 MINUTES; 191964255Seric TimeOuts.to_ident = (time_t) 30 SECONDS; 192067711Seric TimeOuts.to_fileopen = (time_t) 60 SECONDS; 192158112Seric return; 192258112Seric } 192358112Seric 192458112Seric for (;; val = p) 192558112Seric { 192658112Seric while (isascii(*val) && isspace(*val)) 192758112Seric val++; 192858112Seric if (*val == '\0') 192958112Seric break; 193058112Seric for (p = val; *p != '\0' && *p != ','; p++) 193158112Seric continue; 193258112Seric if (*p != '\0') 193358112Seric *p++ = '\0'; 193458112Seric 193558112Seric if (isascii(*val) && isdigit(*val)) 193658112Seric { 193758112Seric /* old syntax -- set everything */ 193858796Seric TimeOuts.to_mail = convtime(val, 'm'); 193958112Seric TimeOuts.to_rcpt = TimeOuts.to_mail; 194058112Seric TimeOuts.to_datainit = TimeOuts.to_mail; 194158112Seric TimeOuts.to_datablock = TimeOuts.to_mail; 194258112Seric TimeOuts.to_datafinal = TimeOuts.to_mail; 194358112Seric TimeOuts.to_nextcommand = TimeOuts.to_mail; 194458112Seric continue; 194558112Seric } 194658112Seric else 194758112Seric { 194867711Seric register char *q = strchr(val, ':'); 194958112Seric 195067711Seric if (q == NULL && (q = strchr(val, '=')) == NULL) 195158112Seric { 195258112Seric /* syntax error */ 195358112Seric continue; 195458112Seric } 195558112Seric *q++ = '\0'; 195667903Seric settimeout(val, q); 195767903Seric } 195867903Seric } 195967903Seric } 196067903Seric /* 196167903Seric ** SETTIMEOUT -- set an individual timeout 196267903Seric ** 196367903Seric ** Parameters: 196467903Seric ** name -- the name of the timeout. 196567903Seric ** val -- the value of the timeout. 196667903Seric ** 196767903Seric ** Returns: 196867903Seric ** none. 196967903Seric */ 197058112Seric 197167903Seric settimeout(name, val) 197267903Seric char *name; 197367903Seric char *val; 197467903Seric { 197567903Seric register char *p; 197667903Seric time_t to; 197767903Seric extern time_t convtime(); 197867903Seric 197967903Seric to = convtime(val, 'm'); 198067903Seric p = strchr(name, '.'); 198167903Seric if (p != NULL) 198267903Seric *p++ = '\0'; 198367903Seric 198467903Seric if (strcasecmp(name, "initial") == 0) 198567903Seric TimeOuts.to_initial = to; 198667903Seric else if (strcasecmp(name, "mail") == 0) 198767903Seric TimeOuts.to_mail = to; 198867903Seric else if (strcasecmp(name, "rcpt") == 0) 198967903Seric TimeOuts.to_rcpt = to; 199067903Seric else if (strcasecmp(name, "datainit") == 0) 199167903Seric TimeOuts.to_datainit = to; 199267903Seric else if (strcasecmp(name, "datablock") == 0) 199367903Seric TimeOuts.to_datablock = to; 199467903Seric else if (strcasecmp(name, "datafinal") == 0) 199567903Seric TimeOuts.to_datafinal = to; 199667903Seric else if (strcasecmp(name, "command") == 0) 199767903Seric TimeOuts.to_nextcommand = to; 199867903Seric else if (strcasecmp(name, "rset") == 0) 199967903Seric TimeOuts.to_rset = to; 200067903Seric else if (strcasecmp(name, "helo") == 0) 200167903Seric TimeOuts.to_helo = to; 200267903Seric else if (strcasecmp(name, "quit") == 0) 200367903Seric TimeOuts.to_quit = to; 200467903Seric else if (strcasecmp(name, "misc") == 0) 200567903Seric TimeOuts.to_miscshort = to; 200667903Seric else if (strcasecmp(name, "ident") == 0) 200767903Seric TimeOuts.to_ident = to; 200867903Seric else if (strcasecmp(name, "fileopen") == 0) 200967903Seric TimeOuts.to_fileopen = to; 201067903Seric else if (strcasecmp(name, "queuewarn") == 0) 201167903Seric { 201267903Seric to = convtime(val, 'h'); 201367946Seric if (p == NULL || strcmp(p, "*") == 0) 201467903Seric { 201567903Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 201667903Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 201767903Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 201858112Seric } 201967903Seric else if (strcasecmp(p, "normal") == 0) 202067903Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 202167903Seric else if (strcasecmp(p, "urgent") == 0) 202267903Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 202367903Seric else if (strcasecmp(p, "non-urgent") == 0) 202467903Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 202567903Seric else 202667903Seric syserr("settimeout: invalid queuewarn subtimeout %s", p); 202758112Seric } 202867903Seric else if (strcasecmp(name, "queuereturn") == 0) 202967903Seric { 203067903Seric to = convtime(val, 'd'); 203167903Seric if (p == NULL || strcmp(p, "*") == 0) 203267903Seric { 203367903Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 203467903Seric TimeOuts.to_q_return[TOC_URGENT] = to; 203567903Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 203667903Seric } 203767903Seric else if (strcasecmp(p, "normal") == 0) 203867903Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 203967903Seric else if (strcasecmp(p, "urgent") == 0) 204067903Seric TimeOuts.to_q_return[TOC_URGENT] = to; 204167903Seric else if (strcasecmp(p, "non-urgent") == 0) 204267903Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 204367903Seric else 204467903Seric syserr("settimeout: invalid queuereturn subtimeout %s", p); 204567903Seric } 204667903Seric else 204767903Seric syserr("settimeout: invalid timeout %s", name); 204858112Seric } 2049