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*67905Seric static char sccsid[] = "@(#)readcf.c 8.47 (Berkeley) 11/13/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(); 532*67905Seric 533*67905Seric /* determine if we need to do special name-server frotz */ 534*67905Seric { 535*67905Seric int nmaps; 536*67905Seric char *maptype[MAXMAPSTACK]; 537*67905Seric short mapreturn[MAXMAPACTIONS]; 538*67905Seric 539*67905Seric nmaps = switch_map_find("hosts", maptype, mapreturn); 540*67905Seric UseNameServer = FALSE; 541*67905Seric if (nmaps > 0 && nmaps <= MAXMAPSTACK) 542*67905Seric { 543*67905Seric register int mapno; 544*67905Seric 545*67905Seric for (mapno = 0; mapno < nmaps && !UseNameServer; mapno++) 546*67905Seric { 547*67905Seric if (strcmp(maptype[mapno], "dns") == 0) 548*67905Seric UseNameServer = TRUE; 549*67905Seric } 550*67905Seric } 551*67905Seric } 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 81867604Seric case 'U': /* user id */ 81967604Seric if (isascii(*p) && !isdigit(*p)) 82067604Seric { 82167604Seric char *q = p; 82267604Seric struct passwd *pw; 82367604Seric 82467604Seric while (isascii(*p) && isalnum(*p)) 82567604Seric p++; 82667604Seric while (isascii(*p) && isspace(*p)) 82767604Seric *p++ = '\0'; 82867604Seric if (*p != '\0') 82967604Seric *p++ = '\0'; 83067604Seric pw = getpwnam(q); 83167604Seric if (pw == NULL) 83267604Seric syserr("readcf: mailer U= flag: unknown user %s", q); 83367604Seric else 83467604Seric { 83567604Seric m->m_uid = pw->pw_uid; 83667604Seric m->m_gid = pw->pw_gid; 83767604Seric } 83867604Seric } 83967604Seric else 84067604Seric { 84167604Seric auto char *q; 84267604Seric 84367604Seric m->m_uid = strtol(p, &q, 0); 84467604Seric p = q; 84567604Seric } 84667604Seric while (isascii(*p) && isspace(*p)) 84767604Seric p++; 84867604Seric if (*p == '\0') 84967604Seric break; 85067604Seric if (isascii(*p) && !isdigit(*p)) 85167604Seric { 85267604Seric char *q = p; 85367604Seric struct group *gr; 85467604Seric 85567604Seric while (isascii(*p) && isalnum(*p)) 85667604Seric p++; 85767604Seric *p++ = '\0'; 85867604Seric gr = getgrnam(q); 85967604Seric if (gr == NULL) 86067604Seric syserr("readcf: mailer U= flag: unknown group %s", q); 86167604Seric else 86267604Seric m->m_gid = gr->gr_gid; 86367604Seric } 86467604Seric else 86567604Seric { 86667604Seric m->m_gid = strtol(p, NULL, 0); 86767604Seric } 86867604Seric break; 86910327Seric } 87010327Seric 87158333Seric p = delimptr; 87210327Seric } 87310327Seric 87452106Seric /* do some heuristic cleanup for back compatibility */ 87552106Seric if (bitnset(M_LIMITS, m->m_flags)) 87652106Seric { 87752106Seric if (m->m_linelimit == 0) 87852106Seric m->m_linelimit = SMTPLINELIM; 87955418Seric if (ConfigLevel < 2) 88052106Seric setbitn(M_7BITS, m->m_flags); 88152106Seric } 88252106Seric 88358321Seric /* do some rationality checking */ 88458321Seric if (m->m_argv == NULL) 88558321Seric { 88658321Seric syserr("M%s: A= argument required", m->m_name); 88758321Seric return; 88858321Seric } 88958321Seric if (m->m_mailer == NULL) 89058321Seric { 89158321Seric syserr("M%s: P= argument required", m->m_name); 89258321Seric return; 89358321Seric } 89458321Seric 8954096Seric if (NextMailer >= MAXMAILERS) 8964096Seric { 8979381Seric syserr("too many mailers defined (%d max)", MAXMAILERS); 8984096Seric return; 8994096Seric } 90057402Seric 90110327Seric s = stab(m->m_name, ST_MAILER, ST_ENTER); 90257402Seric if (s->s_mailer != NULL) 90357402Seric { 90457402Seric i = s->s_mailer->m_mno; 90557402Seric free(s->s_mailer); 90657402Seric } 90757402Seric else 90857402Seric { 90957402Seric i = NextMailer++; 91057402Seric } 91157402Seric Mailer[i] = s->s_mailer = m; 91257454Seric m->m_mno = i; 91310327Seric } 91410327Seric /* 91510327Seric ** MUNCHSTRING -- translate a string into internal form. 91610327Seric ** 91710327Seric ** Parameters: 91810327Seric ** p -- the string to munch. 91958333Seric ** delimptr -- if non-NULL, set to the pointer of the 92058333Seric ** field delimiter character. 92110327Seric ** 92210327Seric ** Returns: 92310327Seric ** the munched string. 92410327Seric */ 9254096Seric 92610327Seric char * 92758333Seric munchstring(p, delimptr) 92810327Seric register char *p; 92958333Seric char **delimptr; 93010327Seric { 93110327Seric register char *q; 93210327Seric bool backslash = FALSE; 93310327Seric bool quotemode = FALSE; 93410327Seric static char buf[MAXLINE]; 9354096Seric 93610327Seric for (q = buf; *p != '\0'; p++) 9374096Seric { 93810327Seric if (backslash) 93910327Seric { 94010327Seric /* everything is roughly literal */ 94110357Seric backslash = FALSE; 94210327Seric switch (*p) 94310327Seric { 94410327Seric case 'r': /* carriage return */ 94510327Seric *q++ = '\r'; 94610327Seric continue; 94710327Seric 94810327Seric case 'n': /* newline */ 94910327Seric *q++ = '\n'; 95010327Seric continue; 95110327Seric 95210327Seric case 'f': /* form feed */ 95310327Seric *q++ = '\f'; 95410327Seric continue; 95510327Seric 95610327Seric case 'b': /* backspace */ 95710327Seric *q++ = '\b'; 95810327Seric continue; 95910327Seric } 96010327Seric *q++ = *p; 96110327Seric } 96210327Seric else 96310327Seric { 96410327Seric if (*p == '\\') 96510327Seric backslash = TRUE; 96610327Seric else if (*p == '"') 96710327Seric quotemode = !quotemode; 96810327Seric else if (quotemode || *p != ',') 96910327Seric *q++ = *p; 97010327Seric else 97110327Seric break; 97210327Seric } 9734096Seric } 9744096Seric 97558333Seric if (delimptr != NULL) 97658333Seric *delimptr = p; 97710327Seric *q++ = '\0'; 97810327Seric return (buf); 97910327Seric } 98010327Seric /* 98110327Seric ** MAKEARGV -- break up a string into words 98210327Seric ** 98310327Seric ** Parameters: 98410327Seric ** p -- the string to break up. 98510327Seric ** 98610327Seric ** Returns: 98710327Seric ** a char **argv (dynamically allocated) 98810327Seric ** 98910327Seric ** Side Effects: 99010327Seric ** munges p. 99110327Seric */ 9924096Seric 99310327Seric char ** 99410327Seric makeargv(p) 99510327Seric register char *p; 99610327Seric { 99710327Seric char *q; 99810327Seric int i; 99910327Seric char **avp; 100010327Seric char *argv[MAXPV + 1]; 100110327Seric 100210327Seric /* take apart the words */ 100310327Seric i = 0; 100410327Seric while (*p != '\0' && i < MAXPV) 10054096Seric { 100610327Seric q = p; 100758050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 100810327Seric p++; 100958050Seric while (isascii(*p) && isspace(*p)) 101010327Seric *p++ = '\0'; 101110327Seric argv[i++] = newstr(q); 10124096Seric } 101310327Seric argv[i++] = NULL; 10144096Seric 101510327Seric /* now make a copy of the argv */ 101610327Seric avp = (char **) xalloc(sizeof *avp * i); 101716893Seric bcopy((char *) argv, (char *) avp, sizeof *avp * i); 101810327Seric 101910327Seric return (avp); 10203308Seric } 10213308Seric /* 10223308Seric ** PRINTRULES -- print rewrite rules (for debugging) 10233308Seric ** 10243308Seric ** Parameters: 10253308Seric ** none. 10263308Seric ** 10273308Seric ** Returns: 10283308Seric ** none. 10293308Seric ** 10303308Seric ** Side Effects: 10313308Seric ** prints rewrite rules. 10323308Seric */ 10333308Seric 10343308Seric printrules() 10353308Seric { 10363308Seric register struct rewrite *rwp; 10374072Seric register int ruleset; 10383308Seric 10394072Seric for (ruleset = 0; ruleset < 10; ruleset++) 10403308Seric { 10414072Seric if (RewriteRules[ruleset] == NULL) 10424072Seric continue; 10438067Seric printf("\n----Rule Set %d:", ruleset); 10443308Seric 10454072Seric for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 10463308Seric { 10478067Seric printf("\nLHS:"); 10488067Seric printav(rwp->r_lhs); 10498067Seric printf("RHS:"); 10508067Seric printav(rwp->r_rhs); 10513308Seric } 10523308Seric } 10533308Seric } 10544319Seric 10554096Seric /* 10568256Seric ** SETOPTION -- set global processing option 10578256Seric ** 10588256Seric ** Parameters: 10598256Seric ** opt -- option name. 10608256Seric ** val -- option value (as a text string). 106121755Seric ** safe -- set if this came from a configuration file. 106221755Seric ** Some options (if set from the command line) will 106321755Seric ** reset the user id to avoid security problems. 10648269Seric ** sticky -- if set, don't let other setoptions override 10658269Seric ** this value. 106658734Seric ** e -- the main envelope. 10678256Seric ** 10688256Seric ** Returns: 10698256Seric ** none. 10708256Seric ** 10718256Seric ** Side Effects: 10728256Seric ** Sets options as implied by the arguments. 10738256Seric */ 10748256Seric 107510687Seric static BITMAP StickyOpt; /* set if option is stuck */ 10768269Seric 107757207Seric 107866334Seric #if NAMED_BIND 107957207Seric 108057207Seric struct resolverflags 108157207Seric { 108257207Seric char *rf_name; /* name of the flag */ 108357207Seric long rf_bits; /* bits to set/clear */ 108457207Seric } ResolverFlags[] = 108557207Seric { 108657207Seric "debug", RES_DEBUG, 108757207Seric "aaonly", RES_AAONLY, 108857207Seric "usevc", RES_USEVC, 108957207Seric "primary", RES_PRIMARY, 109057207Seric "igntc", RES_IGNTC, 109157207Seric "recurse", RES_RECURSE, 109257207Seric "defnames", RES_DEFNAMES, 109357207Seric "stayopen", RES_STAYOPEN, 109457207Seric "dnsrch", RES_DNSRCH, 109565583Seric "true", 0, /* to avoid error on old syntax */ 109657207Seric NULL, 0 109757207Seric }; 109857207Seric 109957207Seric #endif 110057207Seric 110167614Seric struct optioninfo 110267614Seric { 110367614Seric char *o_name; /* long name of option */ 110467787Seric u_char o_code; /* short name of option */ 110567614Seric bool o_safe; /* safe for random people to use */ 110667614Seric } OptionTab[] = 110767614Seric { 110867707Seric "SevenBitInput", '7', TRUE, 110967707Seric "EightBitMode", '8', TRUE, 111067707Seric "AliasFile", 'A', FALSE, 111167707Seric "AliasWait", 'a', FALSE, 111267707Seric "BlankSub", 'B', FALSE, 111367707Seric "MinFreeBlocks", 'b', TRUE, 111467707Seric "CheckpointInterval", 'C', TRUE, 111567707Seric "HoldExpensive", 'c', FALSE, 111667707Seric "AutoRebuildAliases", 'D', FALSE, 111767707Seric "DeliveryMode", 'd', TRUE, 111867707Seric "ErrorHeader", 'E', FALSE, 111967707Seric "ErrorMode", 'e', TRUE, 112067707Seric "TempFileMode", 'F', FALSE, 112167707Seric "SaveFromLine", 'f', FALSE, 112267707Seric "MatchGECOS", 'G', FALSE, 112367707Seric "HelpFile", 'H', FALSE, 112467707Seric "MaxHopCount", 'h', FALSE, 112567707Seric "NameServerOptions", 'I', FALSE, 112667707Seric "IgnoreDots", 'i', TRUE, 112767707Seric "ForwardPath", 'J', FALSE, 112867707Seric "SendMimeErrors", 'j', TRUE, 112967707Seric "ConnectionCacheSize", 'k', FALSE, 113067707Seric "ConnectionCacheTimeout", 'K', FALSE, 113167707Seric "UseErrorsTo", 'l', FALSE, 113267707Seric "LogLevel", 'L', FALSE, 113367707Seric "MeToo", 'm', TRUE, 113467707Seric "CheckAliases", 'n', FALSE, 113567707Seric "OldStyleHeaders", 'o', TRUE, 113667707Seric "DaemonPortOptions", 'O', FALSE, 113767707Seric "PrivacyOptions", 'p', TRUE, 113867707Seric "PostmasterCopy", 'P', FALSE, 113967707Seric "QueueFactor", 'q', FALSE, 114067707Seric "QueueDirectory", 'Q', FALSE, 114167707Seric "DontPruneRoutes", 'R', FALSE, 114267711Seric "Timeouts", 'r', TRUE, 114367707Seric "StatusFile", 'S', FALSE, 114467707Seric "SuperSafe", 's', TRUE, 114567707Seric "QueueTimeout", 'T', FALSE, 114667707Seric "TimeZoneSpec", 't', FALSE, 114767707Seric "UserDatabaseSpec", 'U', FALSE, 114867707Seric "DefaultUser", 'u', FALSE, 114967707Seric "FallbackMXhost", 'V', FALSE, 115067707Seric "Verbose", 'v', TRUE, 115167707Seric "TryNullMXList", 'w', TRUE, 115267707Seric "QueueLA", 'x', FALSE, 115367707Seric "RefuseLA", 'X', FALSE, 115467707Seric "RecipientFactor", 'y', FALSE, 115567707Seric "ForkQueueRuns", 'Y', FALSE, 115667707Seric "ClassFactor", 'z', FALSE, 115767707Seric "TimeFactor", 'Z', FALSE, 115867707Seric #define O_BSP 0x80 115967707Seric "BrokenSmtpPeers", O_BSP, TRUE, 116067707Seric #define O_SQBH 0x81 116167707Seric "SortQueueByHost", O_SQBH, TRUE, 116267707Seric #define O_DNICE 0x82 116367707Seric "DeliveryNiceness", O_DNICE, TRUE, 116467707Seric #define O_MQA 0x83 116567707Seric "MinQueueAge", O_MQA, TRUE, 116667707Seric #define O_MHSA 0x84 116767707Seric "MaxHostStatAge", O_MHSA, TRUE, 116867813Seric #define O_DEFCHARSET 0x85 116967813Seric "DefaultCharSet", O_DEFCHARSET, TRUE, 117067848Seric #define O_SSFILE 0x86 117167848Seric "ServiceSwitchFile", O_SSFILE, FALSE, 117267707Seric 117367707Seric NULL, '\0', FALSE, 117467614Seric }; 117567614Seric 117667614Seric 117767614Seric 117858734Seric setoption(opt, val, safe, sticky, e) 117967614Seric u_char opt; 11808256Seric char *val; 118121755Seric bool safe; 11828269Seric bool sticky; 118358734Seric register ENVELOPE *e; 11848256Seric { 118557207Seric register char *p; 118667614Seric register struct optioninfo *o; 118767903Seric char *subopt; 11888265Seric extern bool atobool(); 118912633Seric extern time_t convtime(); 119014879Seric extern int QueueLA; 119114879Seric extern int RefuseLA; 119264718Seric extern bool Warn_Q_option; 11938256Seric 119467736Seric errno = 0; 119567614Seric if (opt == ' ') 119667614Seric { 119767614Seric /* full word options */ 119867736Seric struct optioninfo *sel; 119967614Seric 120067614Seric p = strchr(val, '='); 120167614Seric if (p == NULL) 120267614Seric p = &val[strlen(val)]; 120367614Seric while (*--p == ' ') 120467614Seric continue; 120567614Seric while (*++p == ' ') 120667614Seric *p = '\0'; 120767731Seric if (p == val) 120867731Seric { 120967731Seric syserr("readcf: null option name"); 121067731Seric return; 121167731Seric } 121267614Seric if (*p == '=') 121367614Seric *p++ = '\0'; 121467614Seric while (*p == ' ') 121567614Seric p++; 121667903Seric subopt = strchr(val, '.'); 121767903Seric if (subopt != NULL) 121867903Seric *subopt++ = '\0'; 121967736Seric sel = NULL; 122067614Seric for (o = OptionTab; o->o_name != NULL; o++) 122167614Seric { 122267736Seric if (strncasecmp(o->o_name, val, strlen(val)) != 0) 122367736Seric continue; 122467736Seric if (strlen(o->o_name) == strlen(val)) 122567736Seric { 122667736Seric /* completely specified -- this must be it */ 122767736Seric sel = NULL; 122867614Seric break; 122967736Seric } 123067736Seric if (sel != NULL) 123167736Seric break; 123267736Seric sel = o; 123367614Seric } 123467736Seric if (sel != NULL && o->o_name == NULL) 123567736Seric o = sel; 123667736Seric else if (o->o_name == NULL) 123767787Seric { 123867614Seric syserr("readcf: unknown option name %s", val); 123967787Seric return; 124067787Seric } 124167736Seric else if (sel != NULL) 124267736Seric { 124367736Seric syserr("readcf: ambiguous option name %s (matches %s and %s)", 124467736Seric val, sel->o_name, o->o_name); 124567736Seric return; 124667736Seric } 124767736Seric if (strlen(val) != strlen(o->o_name)) 124867736Seric { 124967736Seric bool oldVerbose = Verbose; 125067736Seric 125167736Seric Verbose = TRUE; 125267736Seric message("Option %s used as abbreviation for %s", 125367736Seric val, o->o_name); 125467736Seric Verbose = oldVerbose; 125567736Seric } 125667614Seric opt = o->o_code; 125767614Seric val = p; 125867614Seric } 125967614Seric else 126067614Seric { 126167614Seric for (o = OptionTab; o->o_name != NULL; o++) 126267614Seric { 126367614Seric if (o->o_code == opt) 126467614Seric break; 126567614Seric } 126667903Seric subopt = NULL; 126767614Seric } 126867614Seric 12698256Seric if (tTd(37, 1)) 127067731Seric { 127167731Seric printf(isascii(opt) && isprint(opt) ? 127267903Seric "setoption %s (%c).%s=%s" : 127367903Seric "setoption %s (0x%x).%s=%s", 127467614Seric o->o_name == NULL ? "<unknown>" : o->o_name, 127567903Seric opt, 127667903Seric subopt == NULL ? "" : subopt, 127767903Seric val); 127867731Seric } 12798256Seric 12808256Seric /* 12818269Seric ** See if this option is preset for us. 12828256Seric */ 12838256Seric 128459731Seric if (!sticky && bitnset(opt, StickyOpt)) 12858269Seric { 12869341Seric if (tTd(37, 1)) 12879341Seric printf(" (ignored)\n"); 12888269Seric return; 12898269Seric } 12908269Seric 129121755Seric /* 129221755Seric ** Check to see if this option can be specified by this user. 129321755Seric */ 129421755Seric 129563787Seric if (!safe && RealUid == 0) 129621755Seric safe = TRUE; 129767614Seric if (!safe && !o->o_safe) 129821755Seric { 129939111Srick if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 130021755Seric { 130136582Sbostic if (tTd(37, 1)) 130236582Sbostic printf(" (unsafe)"); 130363787Seric if (RealUid != geteuid()) 130436582Sbostic { 130551210Seric if (tTd(37, 1)) 130651210Seric printf("(Resetting uid)"); 130763787Seric (void) setgid(RealGid); 130863787Seric (void) setuid(RealUid); 130936582Sbostic } 131021755Seric } 131121755Seric } 131251210Seric if (tTd(37, 1)) 131317985Seric printf("\n"); 13148269Seric 131567614Seric switch (opt & 0xff) 13168256Seric { 131759709Seric case '7': /* force seven-bit input */ 131867546Seric SevenBitInput = atobool(val); 131952106Seric break; 132052106Seric 132167546Seric case '8': /* handling of 8-bit input */ 132267546Seric switch (*val) 132367546Seric { 132467547Seric case 'r': /* reject 8-bit, don't convert MIME */ 132567546Seric MimeMode = 0; 132667546Seric break; 132767546Seric 132867547Seric case 'm': /* convert 8-bit, convert MIME */ 132967546Seric MimeMode = MM_CVTMIME|MM_MIME8BIT; 133067546Seric break; 133167546Seric 133267547Seric case 'j': /* "just send 8" */ 133367546Seric MimeMode = MM_PASS8BIT; 133467546Seric break; 133567546Seric 133667546Seric case 'p': /* pass 8 bit, convert MIME */ 133767546Seric MimeMode = MM_PASS8BIT|MM_CVTMIME; 133867546Seric break; 133967546Seric 134067546Seric case 's': /* strict adherence */ 134167546Seric MimeMode = MM_CVTMIME; 134267546Seric break; 134367546Seric 134467547Seric case 'a': /* encode 8 bit if available */ 134567546Seric MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 134667546Seric break; 134767546Seric 134867547Seric case 'c': /* convert 8 bit to MIME, never 7 bit */ 134967547Seric MimeMode = MM_MIME8BIT; 135067547Seric break; 135167547Seric 135267546Seric default: 135367546Seric syserr("Unknown 8-bit mode %c", *val); 135467546Seric exit(EX_USAGE); 135567546Seric } 135667546Seric break; 135767546Seric 13588256Seric case 'A': /* set default alias file */ 13599381Seric if (val[0] == '\0') 136059672Seric setalias("aliases"); 13619381Seric else 136259672Seric setalias(val); 13638256Seric break; 13648256Seric 136517474Seric case 'a': /* look N minutes for "@:@" in alias file */ 136617474Seric if (val[0] == '\0') 136764796Seric SafeAlias = 5 * 60; /* five minutes */ 136817474Seric else 136964796Seric SafeAlias = convtime(val, 'm'); 137017474Seric break; 137117474Seric 137216843Seric case 'B': /* substitution for blank character */ 137316843Seric SpaceSub = val[0]; 137416843Seric if (SpaceSub == '\0') 137516843Seric SpaceSub = ' '; 137616843Seric break; 137716843Seric 137859283Seric case 'b': /* min blocks free on queue fs/max msg size */ 137959283Seric p = strchr(val, '/'); 138059283Seric if (p != NULL) 138159283Seric { 138259283Seric *p++ = '\0'; 138359283Seric MaxMessageSize = atol(p); 138459283Seric } 138558082Seric MinBlocksFree = atol(val); 138658082Seric break; 138758082Seric 13889284Seric case 'c': /* don't connect to "expensive" mailers */ 13899381Seric NoConnect = atobool(val); 13909284Seric break; 13919284Seric 139251305Seric case 'C': /* checkpoint every N addresses */ 139351305Seric CheckpointInterval = atoi(val); 139424944Seric break; 139524944Seric 13969284Seric case 'd': /* delivery mode */ 13979284Seric switch (*val) 13988269Seric { 13999284Seric case '\0': 140058734Seric e->e_sendmode = SM_DELIVER; 14018269Seric break; 14028269Seric 140310755Seric case SM_QUEUE: /* queue only */ 140410755Seric #ifndef QUEUE 140510755Seric syserr("need QUEUE to set -odqueue"); 140656795Seric #endif /* QUEUE */ 140710755Seric /* fall through..... */ 140810755Seric 14099284Seric case SM_DELIVER: /* do everything */ 14109284Seric case SM_FORK: /* fork after verification */ 141158734Seric e->e_sendmode = *val; 14128269Seric break; 14138269Seric 14148269Seric default: 14159284Seric syserr("Unknown delivery mode %c", *val); 14168269Seric exit(EX_USAGE); 14178269Seric } 14188269Seric break; 14198269Seric 14209146Seric case 'D': /* rebuild alias database as needed */ 14219381Seric AutoRebuild = atobool(val); 14229146Seric break; 14239146Seric 142455372Seric case 'E': /* error message header/header file */ 142555379Seric if (*val != '\0') 142655379Seric ErrMsgFile = newstr(val); 142755372Seric break; 142855372Seric 14298269Seric case 'e': /* set error processing mode */ 14308269Seric switch (*val) 14318269Seric { 14329381Seric case EM_QUIET: /* be silent about it */ 14339381Seric case EM_MAIL: /* mail back */ 14349381Seric case EM_BERKNET: /* do berknet error processing */ 14359381Seric case EM_WRITE: /* write back (or mail) */ 14369381Seric case EM_PRINT: /* print errors normally (default) */ 143758734Seric e->e_errormode = *val; 14388269Seric break; 14398269Seric } 14408269Seric break; 14418269Seric 14429049Seric case 'F': /* file mode */ 144317975Seric FileMode = atooct(val) & 0777; 14449049Seric break; 14459049Seric 14468269Seric case 'f': /* save Unix-style From lines on front */ 14479381Seric SaveFrom = atobool(val); 14488269Seric break; 14498269Seric 145053735Seric case 'G': /* match recipients against GECOS field */ 145153735Seric MatchGecos = atobool(val); 145253735Seric break; 145353735Seric 14548256Seric case 'g': /* default gid */ 145567823Seric g_opt: 145664133Seric if (isascii(*val) && isdigit(*val)) 145764133Seric DefGid = atoi(val); 145864133Seric else 145964133Seric { 146064133Seric register struct group *gr; 146164133Seric 146264133Seric DefGid = -1; 146364133Seric gr = getgrnam(val); 146464133Seric if (gr == NULL) 146567823Seric syserr("readcf: option %c: unknown group %s", 146667823Seric opt, val); 146764133Seric else 146864133Seric DefGid = gr->gr_gid; 146964133Seric } 14708256Seric break; 14718256Seric 14728256Seric case 'H': /* help file */ 14739381Seric if (val[0] == '\0') 14748269Seric HelpFile = "sendmail.hf"; 14759381Seric else 14769381Seric HelpFile = newstr(val); 14778256Seric break; 14788256Seric 147951305Seric case 'h': /* maximum hop count */ 148051305Seric MaxHopCount = atoi(val); 148151305Seric break; 148251305Seric 148335651Seric case 'I': /* use internet domain name server */ 148466334Seric #if NAMED_BIND 148557207Seric for (p = val; *p != 0; ) 148657207Seric { 148757207Seric bool clearmode; 148857207Seric char *q; 148957207Seric struct resolverflags *rfp; 149057207Seric 149157207Seric while (*p == ' ') 149257207Seric p++; 149357207Seric if (*p == '\0') 149457207Seric break; 149557207Seric clearmode = FALSE; 149657207Seric if (*p == '-') 149757207Seric clearmode = TRUE; 149857207Seric else if (*p != '+') 149957207Seric p--; 150057207Seric p++; 150157207Seric q = p; 150258050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 150357207Seric p++; 150457207Seric if (*p != '\0') 150557207Seric *p++ = '\0'; 150657207Seric for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 150757207Seric { 150857207Seric if (strcasecmp(q, rfp->rf_name) == 0) 150957207Seric break; 151057207Seric } 151164923Seric if (rfp->rf_name == NULL) 151264923Seric syserr("readcf: I option value %s unrecognized", q); 151364923Seric else if (clearmode) 151457207Seric _res.options &= ~rfp->rf_bits; 151557207Seric else 151657207Seric _res.options |= rfp->rf_bits; 151757207Seric } 151857207Seric if (tTd(8, 2)) 151957207Seric printf("_res.options = %x\n", _res.options); 152057207Seric #else 152157207Seric usrerr("name server (I option) specified but BIND not compiled in"); 152257207Seric #endif 152335651Seric break; 152435651Seric 15258269Seric case 'i': /* ignore dot lines in message */ 15269381Seric IgnrDot = atobool(val); 15278269Seric break; 15288269Seric 152959730Seric case 'j': /* send errors in MIME (RFC 1341) format */ 153059730Seric SendMIMEErrors = atobool(val); 153159730Seric break; 153259730Seric 153357136Seric case 'J': /* .forward search path */ 153457136Seric ForwardPath = newstr(val); 153557136Seric break; 153657136Seric 153754967Seric case 'k': /* connection cache size */ 153854967Seric MaxMciCache = atoi(val); 153956215Seric if (MaxMciCache < 0) 154056215Seric MaxMciCache = 0; 154154967Seric break; 154254967Seric 154354967Seric case 'K': /* connection cache timeout */ 154458796Seric MciCacheTimeout = convtime(val, 'm'); 154554967Seric break; 154654967Seric 154761104Seric case 'l': /* use Errors-To: header */ 154861104Seric UseErrorsTo = atobool(val); 154961104Seric break; 155061104Seric 15518256Seric case 'L': /* log level */ 155264140Seric if (safe || LogLevel < atoi(val)) 155364140Seric LogLevel = atoi(val); 15548256Seric break; 15558256Seric 15568269Seric case 'M': /* define macro */ 15579381Seric define(val[0], newstr(&val[1]), CurEnv); 155816878Seric sticky = FALSE; 15598269Seric break; 15608269Seric 15618269Seric case 'm': /* send to me too */ 15629381Seric MeToo = atobool(val); 15638269Seric break; 15648269Seric 156525820Seric case 'n': /* validate RHS in newaliases */ 156625820Seric CheckAliases = atobool(val); 156725820Seric break; 156825820Seric 156961104Seric /* 'N' available -- was "net name" */ 157061104Seric 157158851Seric case 'O': /* daemon options */ 157258851Seric setdaemonoptions(val); 157358851Seric break; 157458851Seric 15758269Seric case 'o': /* assume old style headers */ 15769381Seric if (atobool(val)) 15779341Seric CurEnv->e_flags |= EF_OLDSTYLE; 15789341Seric else 15799341Seric CurEnv->e_flags &= ~EF_OLDSTYLE; 15808269Seric break; 15818269Seric 158258082Seric case 'p': /* select privacy level */ 158358082Seric p = val; 158458082Seric for (;;) 158558082Seric { 158658082Seric register struct prival *pv; 158758082Seric extern struct prival PrivacyValues[]; 158858082Seric 158958082Seric while (isascii(*p) && (isspace(*p) || ispunct(*p))) 159058082Seric p++; 159158082Seric if (*p == '\0') 159258082Seric break; 159358082Seric val = p; 159458082Seric while (isascii(*p) && isalnum(*p)) 159558082Seric p++; 159658082Seric if (*p != '\0') 159758082Seric *p++ = '\0'; 159858082Seric 159958082Seric for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 160058082Seric { 160158082Seric if (strcasecmp(val, pv->pv_name) == 0) 160258082Seric break; 160358082Seric } 160458886Seric if (pv->pv_name == NULL) 160558886Seric syserr("readcf: Op line: %s unrecognized", val); 160658082Seric PrivacyFlags |= pv->pv_flag; 160758082Seric } 160858082Seric break; 160958082Seric 161024944Seric case 'P': /* postmaster copy address for returned mail */ 161124944Seric PostMasterCopy = newstr(val); 161224944Seric break; 161324944Seric 161424944Seric case 'q': /* slope of queue only function */ 161524944Seric QueueFactor = atoi(val); 161624944Seric break; 161724944Seric 16188256Seric case 'Q': /* queue directory */ 16199381Seric if (val[0] == '\0') 16208269Seric QueueDir = "mqueue"; 16219381Seric else 16229381Seric QueueDir = newstr(val); 162358789Seric if (RealUid != 0 && !safe) 162464718Seric Warn_Q_option = TRUE; 16258256Seric break; 16268256Seric 162758148Seric case 'R': /* don't prune routes */ 162858148Seric DontPruneRoutes = atobool(val); 162958148Seric break; 163058148Seric 16318256Seric case 'r': /* read timeout */ 163267903Seric if (subopt == NULL) 163367903Seric inittimeouts(val); 163467903Seric else 163567903Seric settimeout(subopt, val); 16368256Seric break; 16378256Seric 16388256Seric case 'S': /* status file */ 16399381Seric if (val[0] == '\0') 16408269Seric StatFile = "sendmail.st"; 16419381Seric else 16429381Seric StatFile = newstr(val); 16438256Seric break; 16448256Seric 16458265Seric case 's': /* be super safe, even if expensive */ 16469381Seric SuperSafe = atobool(val); 16478256Seric break; 16488256Seric 16498256Seric case 'T': /* queue timeout */ 165058737Seric p = strchr(val, '/'); 165158737Seric if (p != NULL) 165258737Seric { 165358737Seric *p++ = '\0'; 165467903Seric settimeout("queuewarn", p); 165558737Seric } 165667903Seric settimeout("queuereturn", val); 165754967Seric break; 16588256Seric 16598265Seric case 't': /* time zone name */ 166052106Seric TimeZoneSpec = newstr(val); 16618265Seric break; 16628265Seric 166350556Seric case 'U': /* location of user database */ 166451360Seric UdbSpec = newstr(val); 166550556Seric break; 166650556Seric 16678256Seric case 'u': /* set default uid */ 166867823Seric for (p = val; *p != '\0'; p++) 166967823Seric { 167067823Seric if (*p == '.' || *p == '/' || *p == ':') 167167823Seric { 167267823Seric *p++ = '\0'; 167367823Seric break; 167467823Seric } 167567823Seric } 167664133Seric if (isascii(*val) && isdigit(*val)) 167764133Seric DefUid = atoi(val); 167864133Seric else 167964133Seric { 168064133Seric register struct passwd *pw; 168164133Seric 168264133Seric DefUid = -1; 168364133Seric pw = getpwnam(val); 168464133Seric if (pw == NULL) 168564133Seric syserr("readcf: option u: unknown user %s", val); 168664133Seric else 168767823Seric { 168864133Seric DefUid = pw->pw_uid; 168967823Seric DefGid = pw->pw_gid; 169067823Seric } 169164133Seric } 169240973Sbostic setdefuser(); 16938256Seric 169467823Seric /* handle the group if it is there */ 169567823Seric if (*p == '\0') 169667823Seric break; 169767823Seric val = p; 169867823Seric goto g_opt; 169967823Seric 170058851Seric case 'V': /* fallback MX host */ 170158851Seric FallBackMX = newstr(val); 170258851Seric break; 170358851Seric 17048269Seric case 'v': /* run in verbose mode */ 17059381Seric Verbose = atobool(val); 17068256Seric break; 17078256Seric 170863837Seric case 'w': /* if we are best MX, try host directly */ 170963837Seric TryNullMXList = atobool(val); 171063837Seric break; 171161104Seric 171261104Seric /* 'W' available -- was wizard password */ 171361104Seric 171414879Seric case 'x': /* load avg at which to auto-queue msgs */ 171514879Seric QueueLA = atoi(val); 171614879Seric break; 171714879Seric 171814879Seric case 'X': /* load avg at which to auto-reject connections */ 171914879Seric RefuseLA = atoi(val); 172014879Seric break; 172114879Seric 172224981Seric case 'y': /* work recipient factor */ 172324981Seric WkRecipFact = atoi(val); 172424981Seric break; 172524981Seric 172624981Seric case 'Y': /* fork jobs during queue runs */ 172724952Seric ForkQueueRuns = atobool(val); 172824952Seric break; 172924952Seric 173024981Seric case 'z': /* work message class factor */ 173124981Seric WkClassFact = atoi(val); 173224981Seric break; 173324981Seric 173424981Seric case 'Z': /* work time factor */ 173524981Seric WkTimeFact = atoi(val); 173624981Seric break; 173724981Seric 173867614Seric case O_BSP: /* SMTP Peers can't handle 2-line greeting */ 173967614Seric BrokenSmtpPeers = atobool(val); 174067614Seric break; 174167614Seric 174267614Seric case O_SQBH: /* sort work queue by host first */ 174367614Seric SortQueueByHost = atobool(val); 174467614Seric break; 174567614Seric 174667707Seric case O_DNICE: /* delivery nice value */ 174767707Seric DeliveryNiceness = atoi(val); 174867707Seric break; 174967707Seric 175067707Seric case O_MQA: /* minimum queue age between deliveries */ 175167707Seric MinQueueAge = convtime(val, 'm'); 175267707Seric break; 175367707Seric 175467707Seric case O_MHSA: /* maximum age of cached host status */ 175567707Seric MaxHostStatAge = convtime(val, 'm'); 175667707Seric break; 175767707Seric 175867813Seric case O_DEFCHARSET: /* default character set for mimefying */ 175967814Seric DefaultCharSet = newstr(val); 176067813Seric break; 176167813Seric 176267848Seric case O_SSFILE: /* service switch file */ 176367848Seric ServiceSwitchFile = newstr(val); 176467848Seric break; 176567848Seric 17668256Seric default: 17678256Seric break; 17688256Seric } 176916878Seric if (sticky) 177016878Seric setbitn(opt, StickyOpt); 17719188Seric return; 17728256Seric } 177310687Seric /* 177410687Seric ** SETCLASS -- set a word into a class 177510687Seric ** 177610687Seric ** Parameters: 177710687Seric ** class -- the class to put the word in. 177810687Seric ** word -- the word to enter 177910687Seric ** 178010687Seric ** Returns: 178110687Seric ** none. 178210687Seric ** 178310687Seric ** Side Effects: 178410687Seric ** puts the word into the symbol table. 178510687Seric */ 178610687Seric 178710687Seric setclass(class, word) 178810687Seric int class; 178910687Seric char *word; 179010687Seric { 179110687Seric register STAB *s; 179210687Seric 179357943Seric if (tTd(37, 8)) 179464326Seric printf("setclass(%c, %s)\n", class, word); 179510687Seric s = stab(word, ST_CLASS, ST_ENTER); 179610687Seric setbitn(class, s->s_class); 179710687Seric } 179853654Seric /* 179953654Seric ** MAKEMAPENTRY -- create a map entry 180053654Seric ** 180153654Seric ** Parameters: 180253654Seric ** line -- the config file line 180353654Seric ** 180453654Seric ** Returns: 180553654Seric ** TRUE if it successfully entered the map entry. 180653654Seric ** FALSE otherwise (usually syntax error). 180753654Seric ** 180853654Seric ** Side Effects: 180953654Seric ** Enters the map into the dictionary. 181053654Seric */ 181153654Seric 181253654Seric void 181353654Seric makemapentry(line) 181453654Seric char *line; 181553654Seric { 181653654Seric register char *p; 181753654Seric char *mapname; 181853654Seric char *classname; 181964078Seric register STAB *s; 182053654Seric STAB *class; 182153654Seric 182258050Seric for (p = line; isascii(*p) && isspace(*p); p++) 182353654Seric continue; 182458050Seric if (!(isascii(*p) && isalnum(*p))) 182553654Seric { 182653654Seric syserr("readcf: config K line: no map name"); 182753654Seric return; 182853654Seric } 182953654Seric 183053654Seric mapname = p; 183167848Seric while ((isascii(*++p) && isalnum(*p)) || *p == '.') 183253654Seric continue; 183353654Seric if (*p != '\0') 183453654Seric *p++ = '\0'; 183558050Seric while (isascii(*p) && isspace(*p)) 183653654Seric p++; 183758050Seric if (!(isascii(*p) && isalnum(*p))) 183853654Seric { 183953654Seric syserr("readcf: config K line, map %s: no map class", mapname); 184053654Seric return; 184153654Seric } 184253654Seric classname = p; 184358050Seric while (isascii(*++p) && isalnum(*p)) 184453654Seric continue; 184553654Seric if (*p != '\0') 184653654Seric *p++ = '\0'; 184758050Seric while (isascii(*p) && isspace(*p)) 184853654Seric p++; 184953654Seric 185053654Seric /* look up the class */ 185153654Seric class = stab(classname, ST_MAPCLASS, ST_FIND); 185253654Seric if (class == NULL) 185353654Seric { 185453654Seric syserr("readcf: map %s: class %s not available", mapname, classname); 185553654Seric return; 185653654Seric } 185753654Seric 185853654Seric /* enter the map */ 185964078Seric s = stab(mapname, ST_MAP, ST_ENTER); 186064078Seric s->s_map.map_class = &class->s_mapclass; 186164078Seric s->s_map.map_mname = newstr(mapname); 186253654Seric 186364078Seric if (class->s_mapclass.map_parse(&s->s_map, p)) 186464078Seric s->s_map.map_mflags |= MF_VALID; 186564078Seric 186664078Seric if (tTd(37, 5)) 186764078Seric { 186864078Seric printf("map %s, class %s, flags %x, file %s,\n", 186964078Seric s->s_map.map_mname, s->s_map.map_class->map_cname, 187064078Seric s->s_map.map_mflags, 187164078Seric s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 187264078Seric printf("\tapp %s, domain %s, rebuild %s\n", 187364078Seric s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 187464078Seric s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 187564078Seric s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 187664078Seric } 187753654Seric } 187858112Seric /* 187967903Seric ** INITTIMEOUTS -- parse and set timeout values 188058112Seric ** 188158112Seric ** Parameters: 188258112Seric ** val -- a pointer to the values. If NULL, do initial 188358112Seric ** settings. 188458112Seric ** 188558112Seric ** Returns: 188658112Seric ** none. 188758112Seric ** 188858112Seric ** Side Effects: 188958112Seric ** Initializes the TimeOuts structure 189058112Seric */ 189158112Seric 189264255Seric #define SECONDS 189358112Seric #define MINUTES * 60 189458112Seric #define HOUR * 3600 189558112Seric 189667903Seric inittimeouts(val) 189758112Seric register char *val; 189858112Seric { 189958112Seric register char *p; 190058671Seric extern time_t convtime(); 190158112Seric 190258112Seric if (val == NULL) 190358112Seric { 190458112Seric TimeOuts.to_initial = (time_t) 5 MINUTES; 190558112Seric TimeOuts.to_helo = (time_t) 5 MINUTES; 190658112Seric TimeOuts.to_mail = (time_t) 10 MINUTES; 190758112Seric TimeOuts.to_rcpt = (time_t) 1 HOUR; 190858112Seric TimeOuts.to_datainit = (time_t) 5 MINUTES; 190958112Seric TimeOuts.to_datablock = (time_t) 1 HOUR; 191058112Seric TimeOuts.to_datafinal = (time_t) 1 HOUR; 191158112Seric TimeOuts.to_rset = (time_t) 5 MINUTES; 191258112Seric TimeOuts.to_quit = (time_t) 2 MINUTES; 191358112Seric TimeOuts.to_nextcommand = (time_t) 1 HOUR; 191458112Seric TimeOuts.to_miscshort = (time_t) 2 MINUTES; 191564255Seric TimeOuts.to_ident = (time_t) 30 SECONDS; 191667711Seric TimeOuts.to_fileopen = (time_t) 60 SECONDS; 191758112Seric return; 191858112Seric } 191958112Seric 192058112Seric for (;; val = p) 192158112Seric { 192258112Seric while (isascii(*val) && isspace(*val)) 192358112Seric val++; 192458112Seric if (*val == '\0') 192558112Seric break; 192658112Seric for (p = val; *p != '\0' && *p != ','; p++) 192758112Seric continue; 192858112Seric if (*p != '\0') 192958112Seric *p++ = '\0'; 193058112Seric 193158112Seric if (isascii(*val) && isdigit(*val)) 193258112Seric { 193358112Seric /* old syntax -- set everything */ 193458796Seric TimeOuts.to_mail = convtime(val, 'm'); 193558112Seric TimeOuts.to_rcpt = TimeOuts.to_mail; 193658112Seric TimeOuts.to_datainit = TimeOuts.to_mail; 193758112Seric TimeOuts.to_datablock = TimeOuts.to_mail; 193858112Seric TimeOuts.to_datafinal = TimeOuts.to_mail; 193958112Seric TimeOuts.to_nextcommand = TimeOuts.to_mail; 194058112Seric continue; 194158112Seric } 194258112Seric else 194358112Seric { 194467711Seric register char *q = strchr(val, ':'); 194558112Seric 194667711Seric if (q == NULL && (q = strchr(val, '=')) == NULL) 194758112Seric { 194858112Seric /* syntax error */ 194958112Seric continue; 195058112Seric } 195158112Seric *q++ = '\0'; 195267903Seric settimeout(val, q); 195367903Seric } 195467903Seric } 195567903Seric } 195667903Seric /* 195767903Seric ** SETTIMEOUT -- set an individual timeout 195867903Seric ** 195967903Seric ** Parameters: 196067903Seric ** name -- the name of the timeout. 196167903Seric ** val -- the value of the timeout. 196267903Seric ** 196367903Seric ** Returns: 196467903Seric ** none. 196567903Seric */ 196658112Seric 196767903Seric settimeout(name, val) 196867903Seric char *name; 196967903Seric char *val; 197067903Seric { 197167903Seric register char *p; 197267903Seric time_t to; 197367903Seric extern time_t convtime(); 197467903Seric 197567903Seric to = convtime(val, 'm'); 197667903Seric p = strchr(name, '.'); 197767903Seric if (p != NULL) 197867903Seric *p++ = '\0'; 197967903Seric 198067903Seric if (strcasecmp(name, "initial") == 0) 198167903Seric TimeOuts.to_initial = to; 198267903Seric else if (strcasecmp(name, "mail") == 0) 198367903Seric TimeOuts.to_mail = to; 198467903Seric else if (strcasecmp(name, "rcpt") == 0) 198567903Seric TimeOuts.to_rcpt = to; 198667903Seric else if (strcasecmp(name, "datainit") == 0) 198767903Seric TimeOuts.to_datainit = to; 198867903Seric else if (strcasecmp(name, "datablock") == 0) 198967903Seric TimeOuts.to_datablock = to; 199067903Seric else if (strcasecmp(name, "datafinal") == 0) 199167903Seric TimeOuts.to_datafinal = to; 199267903Seric else if (strcasecmp(name, "command") == 0) 199367903Seric TimeOuts.to_nextcommand = to; 199467903Seric else if (strcasecmp(name, "rset") == 0) 199567903Seric TimeOuts.to_rset = to; 199667903Seric else if (strcasecmp(name, "helo") == 0) 199767903Seric TimeOuts.to_helo = to; 199867903Seric else if (strcasecmp(name, "quit") == 0) 199967903Seric TimeOuts.to_quit = to; 200067903Seric else if (strcasecmp(name, "misc") == 0) 200167903Seric TimeOuts.to_miscshort = to; 200267903Seric else if (strcasecmp(name, "ident") == 0) 200367903Seric TimeOuts.to_ident = to; 200467903Seric else if (strcasecmp(name, "fileopen") == 0) 200567903Seric TimeOuts.to_fileopen = to; 200667903Seric else if (strcasecmp(name, "queuewarn") == 0) 200767903Seric { 200867903Seric to = convtime(val, 'h'); 200967903Seric if (p == NULL || strcmp(p, "*") == NULL) 201067903Seric { 201167903Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 201267903Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 201367903Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 201458112Seric } 201567903Seric else if (strcasecmp(p, "normal") == 0) 201667903Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 201767903Seric else if (strcasecmp(p, "urgent") == 0) 201867903Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 201967903Seric else if (strcasecmp(p, "non-urgent") == 0) 202067903Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 202167903Seric else 202267903Seric syserr("settimeout: invalid queuewarn subtimeout %s", p); 202358112Seric } 202467903Seric else if (strcasecmp(name, "queuereturn") == 0) 202567903Seric { 202667903Seric to = convtime(val, 'd'); 202767903Seric if (p == NULL || strcmp(p, "*") == 0) 202867903Seric { 202967903Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 203067903Seric TimeOuts.to_q_return[TOC_URGENT] = to; 203167903Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 203267903Seric } 203367903Seric else if (strcasecmp(p, "normal") == 0) 203467903Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 203567903Seric else if (strcasecmp(p, "urgent") == 0) 203667903Seric TimeOuts.to_q_return[TOC_URGENT] = to; 203767903Seric else if (strcasecmp(p, "non-urgent") == 0) 203867903Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 203967903Seric else 204067903Seric syserr("settimeout: invalid queuereturn subtimeout %s", p); 204167903Seric } 204267903Seric else 204367903Seric syserr("settimeout: invalid timeout %s", name); 204458112Seric } 2045