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*68147Seric static char sccsid[] = "@(#)readcf.c 8.59 (Berkeley) 01/07/95"; 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: 68667998Seric ** A -- the argv for this mailer 68767998Seric ** C -- the character set for MIME conversions 68867998Seric ** D -- the directory to run in 68967998Seric ** E -- the eol string 69067998Seric ** F -- the flags associated with the mailer 69167998Seric ** L -- the maximum line length 69267998Seric ** M -- the maximum message size 69310327Seric ** P -- the path to the mailer 69467998Seric ** R -- the recipient rewriting set 69510327Seric ** S -- the sender rewriting set 69667998Seric ** T -- the mailer type (for DSNs) 69767998Seric ** U -- the uid to run as 69810327Seric ** The first word is the canonical name of the mailer. 6994096Seric ** 7004096Seric ** Returns: 7014096Seric ** none. 7024096Seric ** 7034096Seric ** Side Effects: 7044096Seric ** enters the mailer into the mailer table. 7054096Seric */ 7063308Seric 70721066Seric makemailer(line) 7084096Seric char *line; 7094096Seric { 7104096Seric register char *p; 7118067Seric register struct mailer *m; 7128067Seric register STAB *s; 7138067Seric int i; 71410327Seric char fcode; 71558020Seric auto char *endp; 7164096Seric extern int NextMailer; 71710327Seric extern char **makeargv(); 71810327Seric extern char *munchstring(); 71910701Seric extern long atol(); 7204096Seric 72110327Seric /* allocate a mailer and set up defaults */ 72210327Seric m = (struct mailer *) xalloc(sizeof *m); 72310327Seric bzero((char *) m, sizeof *m); 72410327Seric m->m_eol = "\n"; 72567604Seric m->m_uid = m->m_gid = 0; 72610327Seric 72710327Seric /* collect the mailer name */ 72858050Seric for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++) 72910327Seric continue; 73010327Seric if (*p != '\0') 73110327Seric *p++ = '\0'; 73210327Seric m->m_name = newstr(line); 73310327Seric 73410327Seric /* now scan through and assign info from the fields */ 73510327Seric while (*p != '\0') 73610327Seric { 73758333Seric auto char *delimptr; 73858333Seric 73958050Seric while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p)))) 74010327Seric p++; 74110327Seric 74210327Seric /* p now points to field code */ 74310327Seric fcode = *p; 74410327Seric while (*p != '\0' && *p != '=' && *p != ',') 74510327Seric p++; 74610327Seric if (*p++ != '=') 74710327Seric { 74852637Seric syserr("mailer %s: `=' expected", m->m_name); 74910327Seric return; 75010327Seric } 75158050Seric while (isascii(*p) && isspace(*p)) 75210327Seric p++; 75310327Seric 75410327Seric /* p now points to the field body */ 75558333Seric p = munchstring(p, &delimptr); 75610327Seric 75710327Seric /* install the field into the mailer struct */ 75810327Seric switch (fcode) 75910327Seric { 76010327Seric case 'P': /* pathname */ 76110327Seric m->m_mailer = newstr(p); 76210327Seric break; 76310327Seric 76410327Seric case 'F': /* flags */ 76510687Seric for (; *p != '\0'; p++) 76658050Seric if (!(isascii(*p) && isspace(*p))) 76752637Seric setbitn(*p, m->m_flags); 76810327Seric break; 76910327Seric 77010327Seric case 'S': /* sender rewriting ruleset */ 77110327Seric case 'R': /* recipient rewriting ruleset */ 77258020Seric i = strtol(p, &endp, 10); 77310327Seric if (i < 0 || i >= MAXRWSETS) 77410327Seric { 77510327Seric syserr("invalid rewrite set, %d max", MAXRWSETS); 77610327Seric return; 77710327Seric } 77810327Seric if (fcode == 'S') 77958020Seric m->m_sh_rwset = m->m_se_rwset = i; 78010327Seric else 78158020Seric m->m_rh_rwset = m->m_re_rwset = i; 78258020Seric 78358020Seric p = endp; 78459985Seric if (*p++ == '/') 78558020Seric { 78658020Seric i = strtol(p, NULL, 10); 78758020Seric if (i < 0 || i >= MAXRWSETS) 78858020Seric { 78958020Seric syserr("invalid rewrite set, %d max", 79058020Seric MAXRWSETS); 79158020Seric return; 79258020Seric } 79358020Seric if (fcode == 'S') 79458020Seric m->m_sh_rwset = i; 79558020Seric else 79658020Seric m->m_rh_rwset = i; 79758020Seric } 79810327Seric break; 79910327Seric 80010327Seric case 'E': /* end of line string */ 80110327Seric m->m_eol = newstr(p); 80210327Seric break; 80310327Seric 80410327Seric case 'A': /* argument vector */ 80510327Seric m->m_argv = makeargv(p); 80610327Seric break; 80710701Seric 80810701Seric case 'M': /* maximum message size */ 80910701Seric m->m_maxsize = atol(p); 81010701Seric break; 81152106Seric 81252106Seric case 'L': /* maximum line length */ 81352106Seric m->m_linelimit = atoi(p); 81452106Seric break; 81558935Seric 81658935Seric case 'D': /* working directory */ 81758935Seric m->m_execdir = newstr(p); 81858935Seric break; 81967604Seric 82067896Seric case 'C': /* default charset */ 82167896Seric m->m_defcharset = newstr(p); 82267896Seric break; 82367896Seric 82467990Seric case 'T': /* MTS Type */ 82567990Seric m->m_mtstype = newstr(p); 82667990Seric break; 82767990Seric 82867604Seric case 'U': /* user id */ 82967604Seric if (isascii(*p) && !isdigit(*p)) 83067604Seric { 83167604Seric char *q = p; 83267604Seric struct passwd *pw; 83367604Seric 83467604Seric while (isascii(*p) && isalnum(*p)) 83567604Seric p++; 83667604Seric while (isascii(*p) && isspace(*p)) 83767604Seric *p++ = '\0'; 83867604Seric if (*p != '\0') 83967604Seric *p++ = '\0'; 84067604Seric pw = getpwnam(q); 84167604Seric if (pw == NULL) 84267604Seric syserr("readcf: mailer U= flag: unknown user %s", q); 84367604Seric else 84467604Seric { 84567604Seric m->m_uid = pw->pw_uid; 84667604Seric m->m_gid = pw->pw_gid; 84767604Seric } 84867604Seric } 84967604Seric else 85067604Seric { 85167604Seric auto char *q; 85267604Seric 85367604Seric m->m_uid = strtol(p, &q, 0); 85467604Seric p = q; 85567604Seric } 85667604Seric while (isascii(*p) && isspace(*p)) 85767604Seric p++; 85867604Seric if (*p == '\0') 85967604Seric break; 86067604Seric if (isascii(*p) && !isdigit(*p)) 86167604Seric { 86267604Seric char *q = p; 86367604Seric struct group *gr; 86467604Seric 86567604Seric while (isascii(*p) && isalnum(*p)) 86667604Seric p++; 86767604Seric *p++ = '\0'; 86867604Seric gr = getgrnam(q); 86967604Seric if (gr == NULL) 87067604Seric syserr("readcf: mailer U= flag: unknown group %s", q); 87167604Seric else 87267604Seric m->m_gid = gr->gr_gid; 87367604Seric } 87467604Seric else 87567604Seric { 87667604Seric m->m_gid = strtol(p, NULL, 0); 87767604Seric } 87867604Seric break; 87910327Seric } 88010327Seric 88158333Seric p = delimptr; 88210327Seric } 88310327Seric 88458321Seric /* do some rationality checking */ 88558321Seric if (m->m_argv == NULL) 88658321Seric { 88758321Seric syserr("M%s: A= argument required", m->m_name); 88858321Seric return; 88958321Seric } 89058321Seric if (m->m_mailer == NULL) 89158321Seric { 89258321Seric syserr("M%s: P= argument required", m->m_name); 89358321Seric return; 89458321Seric } 89558321Seric 8964096Seric if (NextMailer >= MAXMAILERS) 8974096Seric { 8989381Seric syserr("too many mailers defined (%d max)", MAXMAILERS); 8994096Seric return; 9004096Seric } 90157402Seric 90267998Seric /* do some heuristic cleanup for back compatibility */ 90367998Seric if (bitnset(M_LIMITS, m->m_flags)) 90467998Seric { 90567998Seric if (m->m_linelimit == 0) 90667998Seric m->m_linelimit = SMTPLINELIM; 90767998Seric if (ConfigLevel < 2) 90867998Seric setbitn(M_7BITS, m->m_flags); 90967998Seric } 91067998Seric 91167998Seric if (ConfigLevel < 6 && m->m_mtstype == NULL && 91267998Seric (strcmp(m->m_mailer, "[IPC]") == 0 || 91368092Seric strcmp(m->m_mailer, "[TCP]") == 0)) 91467998Seric m->m_mtstype = "Internet"; 91567998Seric 91667998Seric /* enter the mailer into the symbol table */ 91710327Seric s = stab(m->m_name, ST_MAILER, ST_ENTER); 91857402Seric if (s->s_mailer != NULL) 91957402Seric { 92057402Seric i = s->s_mailer->m_mno; 92157402Seric free(s->s_mailer); 92257402Seric } 92357402Seric else 92457402Seric { 92557402Seric i = NextMailer++; 92657402Seric } 92757402Seric Mailer[i] = s->s_mailer = m; 92857454Seric m->m_mno = i; 92910327Seric } 93010327Seric /* 93110327Seric ** MUNCHSTRING -- translate a string into internal form. 93210327Seric ** 93310327Seric ** Parameters: 93410327Seric ** p -- the string to munch. 93558333Seric ** delimptr -- if non-NULL, set to the pointer of the 93658333Seric ** field delimiter character. 93710327Seric ** 93810327Seric ** Returns: 93910327Seric ** the munched string. 94010327Seric */ 9414096Seric 94210327Seric char * 94358333Seric munchstring(p, delimptr) 94410327Seric register char *p; 94558333Seric char **delimptr; 94610327Seric { 94710327Seric register char *q; 94810327Seric bool backslash = FALSE; 94910327Seric bool quotemode = FALSE; 95010327Seric static char buf[MAXLINE]; 9514096Seric 95210327Seric for (q = buf; *p != '\0'; p++) 9534096Seric { 95410327Seric if (backslash) 95510327Seric { 95610327Seric /* everything is roughly literal */ 95710357Seric backslash = FALSE; 95810327Seric switch (*p) 95910327Seric { 96010327Seric case 'r': /* carriage return */ 96110327Seric *q++ = '\r'; 96210327Seric continue; 96310327Seric 96410327Seric case 'n': /* newline */ 96510327Seric *q++ = '\n'; 96610327Seric continue; 96710327Seric 96810327Seric case 'f': /* form feed */ 96910327Seric *q++ = '\f'; 97010327Seric continue; 97110327Seric 97210327Seric case 'b': /* backspace */ 97310327Seric *q++ = '\b'; 97410327Seric continue; 97510327Seric } 97610327Seric *q++ = *p; 97710327Seric } 97810327Seric else 97910327Seric { 98010327Seric if (*p == '\\') 98110327Seric backslash = TRUE; 98210327Seric else if (*p == '"') 98310327Seric quotemode = !quotemode; 98410327Seric else if (quotemode || *p != ',') 98510327Seric *q++ = *p; 98610327Seric else 98710327Seric break; 98810327Seric } 9894096Seric } 9904096Seric 99158333Seric if (delimptr != NULL) 99258333Seric *delimptr = p; 99310327Seric *q++ = '\0'; 99410327Seric return (buf); 99510327Seric } 99610327Seric /* 99710327Seric ** MAKEARGV -- break up a string into words 99810327Seric ** 99910327Seric ** Parameters: 100010327Seric ** p -- the string to break up. 100110327Seric ** 100210327Seric ** Returns: 100310327Seric ** a char **argv (dynamically allocated) 100410327Seric ** 100510327Seric ** Side Effects: 100610327Seric ** munges p. 100710327Seric */ 10084096Seric 100910327Seric char ** 101010327Seric makeargv(p) 101110327Seric register char *p; 101210327Seric { 101310327Seric char *q; 101410327Seric int i; 101510327Seric char **avp; 101610327Seric char *argv[MAXPV + 1]; 101710327Seric 101810327Seric /* take apart the words */ 101910327Seric i = 0; 102010327Seric while (*p != '\0' && i < MAXPV) 10214096Seric { 102210327Seric q = p; 102358050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 102410327Seric p++; 102558050Seric while (isascii(*p) && isspace(*p)) 102610327Seric *p++ = '\0'; 102710327Seric argv[i++] = newstr(q); 10284096Seric } 102910327Seric argv[i++] = NULL; 10304096Seric 103110327Seric /* now make a copy of the argv */ 103210327Seric avp = (char **) xalloc(sizeof *avp * i); 103316893Seric bcopy((char *) argv, (char *) avp, sizeof *avp * i); 103410327Seric 103510327Seric return (avp); 10363308Seric } 10373308Seric /* 10383308Seric ** PRINTRULES -- print rewrite rules (for debugging) 10393308Seric ** 10403308Seric ** Parameters: 10413308Seric ** none. 10423308Seric ** 10433308Seric ** Returns: 10443308Seric ** none. 10453308Seric ** 10463308Seric ** Side Effects: 10473308Seric ** prints rewrite rules. 10483308Seric */ 10493308Seric 10503308Seric printrules() 10513308Seric { 10523308Seric register struct rewrite *rwp; 10534072Seric register int ruleset; 10543308Seric 10554072Seric for (ruleset = 0; ruleset < 10; ruleset++) 10563308Seric { 10574072Seric if (RewriteRules[ruleset] == NULL) 10584072Seric continue; 10598067Seric printf("\n----Rule Set %d:", ruleset); 10603308Seric 10614072Seric for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 10623308Seric { 10638067Seric printf("\nLHS:"); 10648067Seric printav(rwp->r_lhs); 10658067Seric printf("RHS:"); 10668067Seric printav(rwp->r_rhs); 10673308Seric } 10683308Seric } 10693308Seric } 107067994Seric /* 107167994Seric ** PRINTMAILER -- print mailer structure (for debugging) 107267994Seric ** 107367994Seric ** Parameters: 107467994Seric ** m -- the mailer to print 107567994Seric ** 107667994Seric ** Returns: 107767994Seric ** none. 107867994Seric */ 10794319Seric 108067994Seric printmailer(m) 108167994Seric register MAILER *m; 108267994Seric { 108367994Seric int j; 108467994Seric 108567994Seric printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld U=%d:%d F=", 108667994Seric m->m_mno, m->m_name, 108767994Seric m->m_mailer, m->m_se_rwset, m->m_sh_rwset, 108867994Seric m->m_re_rwset, m->m_rh_rwset, m->m_maxsize, 108967994Seric m->m_uid, m->m_gid); 109067994Seric for (j = '\0'; j <= '\177'; j++) 109167994Seric if (bitnset(j, m->m_flags)) 109267994Seric (void) putchar(j); 109367994Seric printf(" L=%d E=", m->m_linelimit); 109467994Seric xputs(m->m_eol); 109567994Seric if (m->m_defcharset != NULL) 109667994Seric printf(" C=%s", m->m_defcharset); 109767994Seric if (m->m_mtstype != NULL) 109867994Seric printf(" T=%s", m->m_mtstype); 109967994Seric if (m->m_argv != NULL) 110067994Seric { 110167994Seric char **a = m->m_argv; 110267994Seric 110367994Seric printf(" A="); 110467994Seric while (*a != NULL) 110567994Seric { 110667994Seric if (a != m->m_argv) 110767994Seric printf(" "); 110867994Seric xputs(*a++); 110967994Seric } 111067994Seric } 111167994Seric printf("\n"); 111267994Seric } 11134096Seric /* 11148256Seric ** SETOPTION -- set global processing option 11158256Seric ** 11168256Seric ** Parameters: 11178256Seric ** opt -- option name. 11188256Seric ** val -- option value (as a text string). 111921755Seric ** safe -- set if this came from a configuration file. 112021755Seric ** Some options (if set from the command line) will 112121755Seric ** reset the user id to avoid security problems. 11228269Seric ** sticky -- if set, don't let other setoptions override 11238269Seric ** this value. 112458734Seric ** e -- the main envelope. 11258256Seric ** 11268256Seric ** Returns: 11278256Seric ** none. 11288256Seric ** 11298256Seric ** Side Effects: 11308256Seric ** Sets options as implied by the arguments. 11318256Seric */ 11328256Seric 113310687Seric static BITMAP StickyOpt; /* set if option is stuck */ 11348269Seric 113557207Seric 113666334Seric #if NAMED_BIND 113757207Seric 113857207Seric struct resolverflags 113957207Seric { 114057207Seric char *rf_name; /* name of the flag */ 114157207Seric long rf_bits; /* bits to set/clear */ 114257207Seric } ResolverFlags[] = 114357207Seric { 114457207Seric "debug", RES_DEBUG, 114557207Seric "aaonly", RES_AAONLY, 114657207Seric "usevc", RES_USEVC, 114757207Seric "primary", RES_PRIMARY, 114857207Seric "igntc", RES_IGNTC, 114957207Seric "recurse", RES_RECURSE, 115057207Seric "defnames", RES_DEFNAMES, 115157207Seric "stayopen", RES_STAYOPEN, 115257207Seric "dnsrch", RES_DNSRCH, 115365583Seric "true", 0, /* to avoid error on old syntax */ 115457207Seric NULL, 0 115557207Seric }; 115657207Seric 115757207Seric #endif 115857207Seric 115967614Seric struct optioninfo 116067614Seric { 116167614Seric char *o_name; /* long name of option */ 116267787Seric u_char o_code; /* short name of option */ 116367614Seric bool o_safe; /* safe for random people to use */ 116467614Seric } OptionTab[] = 116567614Seric { 116667707Seric "SevenBitInput", '7', TRUE, 116767707Seric "EightBitMode", '8', TRUE, 116867707Seric "AliasFile", 'A', FALSE, 116967707Seric "AliasWait", 'a', FALSE, 117067707Seric "BlankSub", 'B', FALSE, 117167707Seric "MinFreeBlocks", 'b', TRUE, 117267707Seric "CheckpointInterval", 'C', TRUE, 117367707Seric "HoldExpensive", 'c', FALSE, 117467707Seric "AutoRebuildAliases", 'D', FALSE, 117567707Seric "DeliveryMode", 'd', TRUE, 117667707Seric "ErrorHeader", 'E', FALSE, 117767707Seric "ErrorMode", 'e', TRUE, 117867707Seric "TempFileMode", 'F', FALSE, 117967707Seric "SaveFromLine", 'f', FALSE, 118067707Seric "MatchGECOS", 'G', FALSE, 118167707Seric "HelpFile", 'H', FALSE, 118267707Seric "MaxHopCount", 'h', FALSE, 118367707Seric "NameServerOptions", 'I', FALSE, 118467707Seric "IgnoreDots", 'i', TRUE, 118567707Seric "ForwardPath", 'J', FALSE, 118667707Seric "SendMimeErrors", 'j', TRUE, 118767707Seric "ConnectionCacheSize", 'k', FALSE, 118867707Seric "ConnectionCacheTimeout", 'K', FALSE, 118967707Seric "UseErrorsTo", 'l', FALSE, 119067707Seric "LogLevel", 'L', FALSE, 119167707Seric "MeToo", 'm', TRUE, 119267707Seric "CheckAliases", 'n', FALSE, 119367707Seric "OldStyleHeaders", 'o', TRUE, 119467707Seric "DaemonPortOptions", 'O', FALSE, 119567707Seric "PrivacyOptions", 'p', TRUE, 119667707Seric "PostmasterCopy", 'P', FALSE, 119767707Seric "QueueFactor", 'q', FALSE, 119867707Seric "QueueDirectory", 'Q', FALSE, 119967707Seric "DontPruneRoutes", 'R', FALSE, 120068109Seric "Timeout", 'r', TRUE, 120167707Seric "StatusFile", 'S', FALSE, 120267707Seric "SuperSafe", 's', TRUE, 120367707Seric "QueueTimeout", 'T', FALSE, 120467707Seric "TimeZoneSpec", 't', FALSE, 120567707Seric "UserDatabaseSpec", 'U', FALSE, 120667707Seric "DefaultUser", 'u', FALSE, 120767707Seric "FallbackMXhost", 'V', FALSE, 120867707Seric "Verbose", 'v', TRUE, 120967707Seric "TryNullMXList", 'w', TRUE, 121067707Seric "QueueLA", 'x', FALSE, 121167707Seric "RefuseLA", 'X', FALSE, 121267707Seric "RecipientFactor", 'y', FALSE, 121367707Seric "ForkQueueRuns", 'Y', FALSE, 121467707Seric "ClassFactor", 'z', FALSE, 121567707Seric "TimeFactor", 'Z', FALSE, 121667707Seric #define O_BSP 0x80 121767707Seric "BrokenSmtpPeers", O_BSP, TRUE, 121868107Seric #define O_QUEUESORTORD 0x81 121968105Seric "QueueSortOrder", O_QUEUESORTORD, TRUE, 122067707Seric #define O_MQA 0x83 122167707Seric "MinQueueAge", O_MQA, TRUE, 122267707Seric #define O_MHSA 0x84 122368132Seric /* 122467707Seric "MaxHostStatAge", O_MHSA, TRUE, 122568132Seric */ 122667813Seric #define O_DEFCHARSET 0x85 122767813Seric "DefaultCharSet", O_DEFCHARSET, TRUE, 122867848Seric #define O_SSFILE 0x86 122967848Seric "ServiceSwitchFile", O_SSFILE, FALSE, 123068034Seric #define O_DIALDELAY 0x87 123168034Seric "DialDelay", O_DIALDELAY, TRUE, 123267707Seric 123367707Seric NULL, '\0', FALSE, 123467614Seric }; 123567614Seric 123667614Seric 123767614Seric 123858734Seric setoption(opt, val, safe, sticky, e) 123967614Seric u_char opt; 12408256Seric char *val; 124121755Seric bool safe; 12428269Seric bool sticky; 124358734Seric register ENVELOPE *e; 12448256Seric { 124557207Seric register char *p; 124667614Seric register struct optioninfo *o; 124767903Seric char *subopt; 12488265Seric extern bool atobool(); 124912633Seric extern time_t convtime(); 125014879Seric extern int QueueLA; 125114879Seric extern int RefuseLA; 125264718Seric extern bool Warn_Q_option; 12538256Seric 125467736Seric errno = 0; 125567614Seric if (opt == ' ') 125667614Seric { 125767614Seric /* full word options */ 125867736Seric struct optioninfo *sel; 125967614Seric 126067614Seric p = strchr(val, '='); 126167614Seric if (p == NULL) 126267614Seric p = &val[strlen(val)]; 126367614Seric while (*--p == ' ') 126467614Seric continue; 126567614Seric while (*++p == ' ') 126667614Seric *p = '\0'; 126767731Seric if (p == val) 126867731Seric { 126967731Seric syserr("readcf: null option name"); 127067731Seric return; 127167731Seric } 127267614Seric if (*p == '=') 127367614Seric *p++ = '\0'; 127467614Seric while (*p == ' ') 127567614Seric p++; 127667903Seric subopt = strchr(val, '.'); 127767903Seric if (subopt != NULL) 127867903Seric *subopt++ = '\0'; 127967736Seric sel = NULL; 128067614Seric for (o = OptionTab; o->o_name != NULL; o++) 128167614Seric { 128267736Seric if (strncasecmp(o->o_name, val, strlen(val)) != 0) 128367736Seric continue; 128467736Seric if (strlen(o->o_name) == strlen(val)) 128567736Seric { 128667736Seric /* completely specified -- this must be it */ 128767736Seric sel = NULL; 128867614Seric break; 128967736Seric } 129067736Seric if (sel != NULL) 129167736Seric break; 129267736Seric sel = o; 129367614Seric } 129467736Seric if (sel != NULL && o->o_name == NULL) 129567736Seric o = sel; 129667736Seric else if (o->o_name == NULL) 129767787Seric { 129867614Seric syserr("readcf: unknown option name %s", val); 129967787Seric return; 130067787Seric } 130167736Seric else if (sel != NULL) 130267736Seric { 130367736Seric syserr("readcf: ambiguous option name %s (matches %s and %s)", 130467736Seric val, sel->o_name, o->o_name); 130567736Seric return; 130667736Seric } 130767736Seric if (strlen(val) != strlen(o->o_name)) 130867736Seric { 130967736Seric bool oldVerbose = Verbose; 131067736Seric 131167736Seric Verbose = TRUE; 131267736Seric message("Option %s used as abbreviation for %s", 131367736Seric val, o->o_name); 131467736Seric Verbose = oldVerbose; 131567736Seric } 131667614Seric opt = o->o_code; 131767614Seric val = p; 131867614Seric } 131967614Seric else 132067614Seric { 132167614Seric for (o = OptionTab; o->o_name != NULL; o++) 132267614Seric { 132367614Seric if (o->o_code == opt) 132467614Seric break; 132567614Seric } 132667903Seric subopt = NULL; 132767614Seric } 132867614Seric 13298256Seric if (tTd(37, 1)) 133067731Seric { 133167731Seric printf(isascii(opt) && isprint(opt) ? 133267903Seric "setoption %s (%c).%s=%s" : 133367903Seric "setoption %s (0x%x).%s=%s", 133467614Seric o->o_name == NULL ? "<unknown>" : o->o_name, 133567903Seric opt, 133667903Seric subopt == NULL ? "" : subopt, 133767903Seric val); 133867731Seric } 13398256Seric 13408256Seric /* 13418269Seric ** See if this option is preset for us. 13428256Seric */ 13438256Seric 134459731Seric if (!sticky && bitnset(opt, StickyOpt)) 13458269Seric { 13469341Seric if (tTd(37, 1)) 13479341Seric printf(" (ignored)\n"); 13488269Seric return; 13498269Seric } 13508269Seric 135121755Seric /* 135221755Seric ** Check to see if this option can be specified by this user. 135321755Seric */ 135421755Seric 135563787Seric if (!safe && RealUid == 0) 135621755Seric safe = TRUE; 135767614Seric if (!safe && !o->o_safe) 135821755Seric { 135939111Srick if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 136021755Seric { 136136582Sbostic if (tTd(37, 1)) 136236582Sbostic printf(" (unsafe)"); 136363787Seric if (RealUid != geteuid()) 136436582Sbostic { 136551210Seric if (tTd(37, 1)) 136651210Seric printf("(Resetting uid)"); 136763787Seric (void) setgid(RealGid); 136863787Seric (void) setuid(RealUid); 136936582Sbostic } 137021755Seric } 137121755Seric } 137251210Seric if (tTd(37, 1)) 137317985Seric printf("\n"); 13748269Seric 137567614Seric switch (opt & 0xff) 13768256Seric { 137759709Seric case '7': /* force seven-bit input */ 137867546Seric SevenBitInput = atobool(val); 137952106Seric break; 138052106Seric 138167546Seric case '8': /* handling of 8-bit input */ 138267546Seric switch (*val) 138367546Seric { 138467547Seric case 'r': /* reject 8-bit, don't convert MIME */ 138567546Seric MimeMode = 0; 138667546Seric break; 138767546Seric 138867547Seric case 'm': /* convert 8-bit, convert MIME */ 138967546Seric MimeMode = MM_CVTMIME|MM_MIME8BIT; 139067546Seric break; 139167546Seric 139267547Seric case 'j': /* "just send 8" */ 139367546Seric MimeMode = MM_PASS8BIT; 139467546Seric break; 139567546Seric 139667546Seric case 'p': /* pass 8 bit, convert MIME */ 139767546Seric MimeMode = MM_PASS8BIT|MM_CVTMIME; 139867546Seric break; 139967546Seric 140067546Seric case 's': /* strict adherence */ 140167546Seric MimeMode = MM_CVTMIME; 140267546Seric break; 140367546Seric 140467547Seric case 'a': /* encode 8 bit if available */ 140567546Seric MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 140667546Seric break; 140767546Seric 140867547Seric case 'c': /* convert 8 bit to MIME, never 7 bit */ 140967547Seric MimeMode = MM_MIME8BIT; 141067547Seric break; 141167547Seric 141267546Seric default: 141367546Seric syserr("Unknown 8-bit mode %c", *val); 141467546Seric exit(EX_USAGE); 141567546Seric } 141667546Seric break; 141767546Seric 14188256Seric case 'A': /* set default alias file */ 14199381Seric if (val[0] == '\0') 142059672Seric setalias("aliases"); 14219381Seric else 142259672Seric setalias(val); 14238256Seric break; 14248256Seric 142517474Seric case 'a': /* look N minutes for "@:@" in alias file */ 142617474Seric if (val[0] == '\0') 142764796Seric SafeAlias = 5 * 60; /* five minutes */ 142817474Seric else 142964796Seric SafeAlias = convtime(val, 'm'); 143017474Seric break; 143117474Seric 143216843Seric case 'B': /* substitution for blank character */ 143316843Seric SpaceSub = val[0]; 143416843Seric if (SpaceSub == '\0') 143516843Seric SpaceSub = ' '; 143616843Seric break; 143716843Seric 143859283Seric case 'b': /* min blocks free on queue fs/max msg size */ 143959283Seric p = strchr(val, '/'); 144059283Seric if (p != NULL) 144159283Seric { 144259283Seric *p++ = '\0'; 144359283Seric MaxMessageSize = atol(p); 144459283Seric } 144558082Seric MinBlocksFree = atol(val); 144658082Seric break; 144758082Seric 14489284Seric case 'c': /* don't connect to "expensive" mailers */ 14499381Seric NoConnect = atobool(val); 14509284Seric break; 14519284Seric 145251305Seric case 'C': /* checkpoint every N addresses */ 145351305Seric CheckpointInterval = atoi(val); 145424944Seric break; 145524944Seric 14569284Seric case 'd': /* delivery mode */ 14579284Seric switch (*val) 14588269Seric { 14599284Seric case '\0': 146058734Seric e->e_sendmode = SM_DELIVER; 14618269Seric break; 14628269Seric 146310755Seric case SM_QUEUE: /* queue only */ 146410755Seric #ifndef QUEUE 146510755Seric syserr("need QUEUE to set -odqueue"); 146656795Seric #endif /* QUEUE */ 146710755Seric /* fall through..... */ 146810755Seric 14699284Seric case SM_DELIVER: /* do everything */ 14709284Seric case SM_FORK: /* fork after verification */ 147158734Seric e->e_sendmode = *val; 14728269Seric break; 14738269Seric 14748269Seric default: 14759284Seric syserr("Unknown delivery mode %c", *val); 14768269Seric exit(EX_USAGE); 14778269Seric } 14788269Seric break; 14798269Seric 14809146Seric case 'D': /* rebuild alias database as needed */ 14819381Seric AutoRebuild = atobool(val); 14829146Seric break; 14839146Seric 148455372Seric case 'E': /* error message header/header file */ 148555379Seric if (*val != '\0') 148655379Seric ErrMsgFile = newstr(val); 148755372Seric break; 148855372Seric 14898269Seric case 'e': /* set error processing mode */ 14908269Seric switch (*val) 14918269Seric { 14929381Seric case EM_QUIET: /* be silent about it */ 14939381Seric case EM_MAIL: /* mail back */ 14949381Seric case EM_BERKNET: /* do berknet error processing */ 14959381Seric case EM_WRITE: /* write back (or mail) */ 14969381Seric case EM_PRINT: /* print errors normally (default) */ 149758734Seric e->e_errormode = *val; 14988269Seric break; 14998269Seric } 15008269Seric break; 15018269Seric 15029049Seric case 'F': /* file mode */ 150317975Seric FileMode = atooct(val) & 0777; 15049049Seric break; 15059049Seric 15068269Seric case 'f': /* save Unix-style From lines on front */ 15079381Seric SaveFrom = atobool(val); 15088269Seric break; 15098269Seric 151053735Seric case 'G': /* match recipients against GECOS field */ 151153735Seric MatchGecos = atobool(val); 151253735Seric break; 151353735Seric 15148256Seric case 'g': /* default gid */ 151567823Seric g_opt: 151664133Seric if (isascii(*val) && isdigit(*val)) 151764133Seric DefGid = atoi(val); 151864133Seric else 151964133Seric { 152064133Seric register struct group *gr; 152164133Seric 152264133Seric DefGid = -1; 152364133Seric gr = getgrnam(val); 152464133Seric if (gr == NULL) 152567823Seric syserr("readcf: option %c: unknown group %s", 152667823Seric opt, val); 152764133Seric else 152864133Seric DefGid = gr->gr_gid; 152964133Seric } 15308256Seric break; 15318256Seric 15328256Seric case 'H': /* help file */ 15339381Seric if (val[0] == '\0') 15348269Seric HelpFile = "sendmail.hf"; 15359381Seric else 15369381Seric HelpFile = newstr(val); 15378256Seric break; 15388256Seric 153951305Seric case 'h': /* maximum hop count */ 154051305Seric MaxHopCount = atoi(val); 154151305Seric break; 154251305Seric 154335651Seric case 'I': /* use internet domain name server */ 154466334Seric #if NAMED_BIND 154557207Seric for (p = val; *p != 0; ) 154657207Seric { 154757207Seric bool clearmode; 154857207Seric char *q; 154957207Seric struct resolverflags *rfp; 155057207Seric 155157207Seric while (*p == ' ') 155257207Seric p++; 155357207Seric if (*p == '\0') 155457207Seric break; 155557207Seric clearmode = FALSE; 155657207Seric if (*p == '-') 155757207Seric clearmode = TRUE; 155857207Seric else if (*p != '+') 155957207Seric p--; 156057207Seric p++; 156157207Seric q = p; 156258050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 156357207Seric p++; 156457207Seric if (*p != '\0') 156557207Seric *p++ = '\0'; 156657207Seric for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 156757207Seric { 156857207Seric if (strcasecmp(q, rfp->rf_name) == 0) 156957207Seric break; 157057207Seric } 157164923Seric if (rfp->rf_name == NULL) 157264923Seric syserr("readcf: I option value %s unrecognized", q); 157364923Seric else if (clearmode) 157457207Seric _res.options &= ~rfp->rf_bits; 157557207Seric else 157657207Seric _res.options |= rfp->rf_bits; 157757207Seric } 157857207Seric if (tTd(8, 2)) 157957207Seric printf("_res.options = %x\n", _res.options); 158057207Seric #else 158157207Seric usrerr("name server (I option) specified but BIND not compiled in"); 158257207Seric #endif 158335651Seric break; 158435651Seric 15858269Seric case 'i': /* ignore dot lines in message */ 15869381Seric IgnrDot = atobool(val); 15878269Seric break; 15888269Seric 158959730Seric case 'j': /* send errors in MIME (RFC 1341) format */ 159059730Seric SendMIMEErrors = atobool(val); 159159730Seric break; 159259730Seric 159357136Seric case 'J': /* .forward search path */ 159457136Seric ForwardPath = newstr(val); 159557136Seric break; 159657136Seric 159754967Seric case 'k': /* connection cache size */ 159854967Seric MaxMciCache = atoi(val); 159956215Seric if (MaxMciCache < 0) 160056215Seric MaxMciCache = 0; 160154967Seric break; 160254967Seric 160354967Seric case 'K': /* connection cache timeout */ 160458796Seric MciCacheTimeout = convtime(val, 'm'); 160554967Seric break; 160654967Seric 160761104Seric case 'l': /* use Errors-To: header */ 160861104Seric UseErrorsTo = atobool(val); 160961104Seric break; 161061104Seric 16118256Seric case 'L': /* log level */ 161264140Seric if (safe || LogLevel < atoi(val)) 161364140Seric LogLevel = atoi(val); 16148256Seric break; 16158256Seric 16168269Seric case 'M': /* define macro */ 16179381Seric define(val[0], newstr(&val[1]), CurEnv); 161816878Seric sticky = FALSE; 16198269Seric break; 16208269Seric 16218269Seric case 'm': /* send to me too */ 16229381Seric MeToo = atobool(val); 16238269Seric break; 16248269Seric 162525820Seric case 'n': /* validate RHS in newaliases */ 162625820Seric CheckAliases = atobool(val); 162725820Seric break; 162825820Seric 162961104Seric /* 'N' available -- was "net name" */ 163061104Seric 163158851Seric case 'O': /* daemon options */ 163258851Seric setdaemonoptions(val); 163358851Seric break; 163458851Seric 16358269Seric case 'o': /* assume old style headers */ 16369381Seric if (atobool(val)) 16379341Seric CurEnv->e_flags |= EF_OLDSTYLE; 16389341Seric else 16399341Seric CurEnv->e_flags &= ~EF_OLDSTYLE; 16408269Seric break; 16418269Seric 164258082Seric case 'p': /* select privacy level */ 164358082Seric p = val; 164458082Seric for (;;) 164558082Seric { 164658082Seric register struct prival *pv; 164758082Seric extern struct prival PrivacyValues[]; 164858082Seric 164958082Seric while (isascii(*p) && (isspace(*p) || ispunct(*p))) 165058082Seric p++; 165158082Seric if (*p == '\0') 165258082Seric break; 165358082Seric val = p; 165458082Seric while (isascii(*p) && isalnum(*p)) 165558082Seric p++; 165658082Seric if (*p != '\0') 165758082Seric *p++ = '\0'; 165858082Seric 165958082Seric for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 166058082Seric { 166158082Seric if (strcasecmp(val, pv->pv_name) == 0) 166258082Seric break; 166358082Seric } 166458886Seric if (pv->pv_name == NULL) 166558886Seric syserr("readcf: Op line: %s unrecognized", val); 166658082Seric PrivacyFlags |= pv->pv_flag; 166758082Seric } 166858082Seric break; 166958082Seric 167024944Seric case 'P': /* postmaster copy address for returned mail */ 167124944Seric PostMasterCopy = newstr(val); 167224944Seric break; 167324944Seric 167424944Seric case 'q': /* slope of queue only function */ 167524944Seric QueueFactor = atoi(val); 167624944Seric break; 167724944Seric 16788256Seric case 'Q': /* queue directory */ 16799381Seric if (val[0] == '\0') 16808269Seric QueueDir = "mqueue"; 16819381Seric else 16829381Seric QueueDir = newstr(val); 168358789Seric if (RealUid != 0 && !safe) 168464718Seric Warn_Q_option = TRUE; 16858256Seric break; 16868256Seric 168758148Seric case 'R': /* don't prune routes */ 168858148Seric DontPruneRoutes = atobool(val); 168958148Seric break; 169058148Seric 16918256Seric case 'r': /* read timeout */ 169267903Seric if (subopt == NULL) 169367903Seric inittimeouts(val); 169467903Seric else 169567903Seric settimeout(subopt, val); 16968256Seric break; 16978256Seric 16988256Seric case 'S': /* status file */ 16999381Seric if (val[0] == '\0') 17008269Seric StatFile = "sendmail.st"; 17019381Seric else 17029381Seric StatFile = newstr(val); 17038256Seric break; 17048256Seric 17058265Seric case 's': /* be super safe, even if expensive */ 17069381Seric SuperSafe = atobool(val); 17078256Seric break; 17088256Seric 17098256Seric case 'T': /* queue timeout */ 171058737Seric p = strchr(val, '/'); 171158737Seric if (p != NULL) 171258737Seric { 171358737Seric *p++ = '\0'; 171467903Seric settimeout("queuewarn", p); 171558737Seric } 171667903Seric settimeout("queuereturn", val); 171754967Seric break; 17188256Seric 17198265Seric case 't': /* time zone name */ 172052106Seric TimeZoneSpec = newstr(val); 17218265Seric break; 17228265Seric 172350556Seric case 'U': /* location of user database */ 172451360Seric UdbSpec = newstr(val); 172550556Seric break; 172650556Seric 17278256Seric case 'u': /* set default uid */ 172867823Seric for (p = val; *p != '\0'; p++) 172967823Seric { 173067823Seric if (*p == '.' || *p == '/' || *p == ':') 173167823Seric { 173267823Seric *p++ = '\0'; 173367823Seric break; 173467823Seric } 173567823Seric } 173664133Seric if (isascii(*val) && isdigit(*val)) 173764133Seric DefUid = atoi(val); 173864133Seric else 173964133Seric { 174064133Seric register struct passwd *pw; 174164133Seric 174264133Seric DefUid = -1; 174364133Seric pw = getpwnam(val); 174464133Seric if (pw == NULL) 174564133Seric syserr("readcf: option u: unknown user %s", val); 174664133Seric else 174767823Seric { 174864133Seric DefUid = pw->pw_uid; 174967823Seric DefGid = pw->pw_gid; 175067823Seric } 175164133Seric } 175240973Sbostic setdefuser(); 17538256Seric 175467823Seric /* handle the group if it is there */ 175567823Seric if (*p == '\0') 175667823Seric break; 175767823Seric val = p; 175867823Seric goto g_opt; 175967823Seric 176058851Seric case 'V': /* fallback MX host */ 176158851Seric FallBackMX = newstr(val); 176258851Seric break; 176358851Seric 17648269Seric case 'v': /* run in verbose mode */ 17659381Seric Verbose = atobool(val); 17668256Seric break; 17678256Seric 176863837Seric case 'w': /* if we are best MX, try host directly */ 176963837Seric TryNullMXList = atobool(val); 177063837Seric break; 177161104Seric 177261104Seric /* 'W' available -- was wizard password */ 177361104Seric 177414879Seric case 'x': /* load avg at which to auto-queue msgs */ 177514879Seric QueueLA = atoi(val); 177614879Seric break; 177714879Seric 177814879Seric case 'X': /* load avg at which to auto-reject connections */ 177914879Seric RefuseLA = atoi(val); 178014879Seric break; 178114879Seric 178224981Seric case 'y': /* work recipient factor */ 178324981Seric WkRecipFact = atoi(val); 178424981Seric break; 178524981Seric 178624981Seric case 'Y': /* fork jobs during queue runs */ 178724952Seric ForkQueueRuns = atobool(val); 178824952Seric break; 178924952Seric 179024981Seric case 'z': /* work message class factor */ 179124981Seric WkClassFact = atoi(val); 179224981Seric break; 179324981Seric 179424981Seric case 'Z': /* work time factor */ 179524981Seric WkTimeFact = atoi(val); 179624981Seric break; 179724981Seric 179867614Seric case O_BSP: /* SMTP Peers can't handle 2-line greeting */ 179967614Seric BrokenSmtpPeers = atobool(val); 180067614Seric break; 180167614Seric 180268105Seric case O_QUEUESORTORD: /* queue sorting order */ 180368105Seric switch (*val) 180468105Seric { 180568105Seric case 'h': /* Host first */ 180668105Seric case 'H': 180768105Seric QueueSortOrder = QS_BYHOST; 180868105Seric break; 180968105Seric 181068105Seric case 'p': /* Priority order */ 181168105Seric case 'P': 181268105Seric QueueSortOrder = QS_BYPRIORITY; 181368105Seric break; 181468105Seric 181568105Seric default: 181668105Seric syserr("Invalid queue sort order \"%s\"", val); 181768105Seric } 181867614Seric break; 181967614Seric 182067707Seric case O_MQA: /* minimum queue age between deliveries */ 182167707Seric MinQueueAge = convtime(val, 'm'); 182267707Seric break; 182367707Seric 182467707Seric case O_MHSA: /* maximum age of cached host status */ 182567707Seric MaxHostStatAge = convtime(val, 'm'); 182667707Seric break; 182767707Seric 182867813Seric case O_DEFCHARSET: /* default character set for mimefying */ 182967814Seric DefaultCharSet = newstr(val); 183067813Seric break; 183167813Seric 183267848Seric case O_SSFILE: /* service switch file */ 183367848Seric ServiceSwitchFile = newstr(val); 183467848Seric break; 183567848Seric 183668034Seric case O_DIALDELAY: /* delay for dial-on-demand operation */ 183768034Seric DialDelay = convtime(val, 's'); 183868034Seric break; 183968034Seric 18408256Seric default: 184168132Seric if (tTd(37, 1)) 184268132Seric { 184368132Seric if (isascii(opt) && isprint(opt)) 184468132Seric printf("Warning: option %c unknown\n", opt); 184568132Seric else 184668132Seric printf("Warning: option 0x%x unknown\n", opt); 184768132Seric } 18488256Seric break; 18498256Seric } 185016878Seric if (sticky) 185116878Seric setbitn(opt, StickyOpt); 18529188Seric return; 18538256Seric } 185410687Seric /* 185510687Seric ** SETCLASS -- set a word into a class 185610687Seric ** 185710687Seric ** Parameters: 185810687Seric ** class -- the class to put the word in. 185910687Seric ** word -- the word to enter 186010687Seric ** 186110687Seric ** Returns: 186210687Seric ** none. 186310687Seric ** 186410687Seric ** Side Effects: 186510687Seric ** puts the word into the symbol table. 186610687Seric */ 186710687Seric 186810687Seric setclass(class, word) 186910687Seric int class; 187010687Seric char *word; 187110687Seric { 187210687Seric register STAB *s; 187310687Seric 187457943Seric if (tTd(37, 8)) 187564326Seric printf("setclass(%c, %s)\n", class, word); 187610687Seric s = stab(word, ST_CLASS, ST_ENTER); 187710687Seric setbitn(class, s->s_class); 187810687Seric } 187953654Seric /* 188053654Seric ** MAKEMAPENTRY -- create a map entry 188153654Seric ** 188253654Seric ** Parameters: 188353654Seric ** line -- the config file line 188453654Seric ** 188553654Seric ** Returns: 188653654Seric ** TRUE if it successfully entered the map entry. 188753654Seric ** FALSE otherwise (usually syntax error). 188853654Seric ** 188953654Seric ** Side Effects: 189053654Seric ** Enters the map into the dictionary. 189153654Seric */ 189253654Seric 189353654Seric void 189453654Seric makemapentry(line) 189553654Seric char *line; 189653654Seric { 189753654Seric register char *p; 189853654Seric char *mapname; 189953654Seric char *classname; 190064078Seric register STAB *s; 190153654Seric STAB *class; 190253654Seric 190358050Seric for (p = line; isascii(*p) && isspace(*p); p++) 190453654Seric continue; 190558050Seric if (!(isascii(*p) && isalnum(*p))) 190653654Seric { 190753654Seric syserr("readcf: config K line: no map name"); 190853654Seric return; 190953654Seric } 191053654Seric 191153654Seric mapname = p; 191267848Seric while ((isascii(*++p) && isalnum(*p)) || *p == '.') 191353654Seric continue; 191453654Seric if (*p != '\0') 191553654Seric *p++ = '\0'; 191658050Seric while (isascii(*p) && isspace(*p)) 191753654Seric p++; 191858050Seric if (!(isascii(*p) && isalnum(*p))) 191953654Seric { 192053654Seric syserr("readcf: config K line, map %s: no map class", mapname); 192153654Seric return; 192253654Seric } 192353654Seric classname = p; 192458050Seric while (isascii(*++p) && isalnum(*p)) 192553654Seric continue; 192653654Seric if (*p != '\0') 192753654Seric *p++ = '\0'; 192858050Seric while (isascii(*p) && isspace(*p)) 192953654Seric p++; 193053654Seric 193153654Seric /* look up the class */ 193253654Seric class = stab(classname, ST_MAPCLASS, ST_FIND); 193353654Seric if (class == NULL) 193453654Seric { 193553654Seric syserr("readcf: map %s: class %s not available", mapname, classname); 193653654Seric return; 193753654Seric } 193853654Seric 193953654Seric /* enter the map */ 194064078Seric s = stab(mapname, ST_MAP, ST_ENTER); 194164078Seric s->s_map.map_class = &class->s_mapclass; 194264078Seric s->s_map.map_mname = newstr(mapname); 194353654Seric 194464078Seric if (class->s_mapclass.map_parse(&s->s_map, p)) 194564078Seric s->s_map.map_mflags |= MF_VALID; 194664078Seric 194764078Seric if (tTd(37, 5)) 194864078Seric { 194964078Seric printf("map %s, class %s, flags %x, file %s,\n", 195064078Seric s->s_map.map_mname, s->s_map.map_class->map_cname, 195164078Seric s->s_map.map_mflags, 195264078Seric s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 195364078Seric printf("\tapp %s, domain %s, rebuild %s\n", 195464078Seric s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 195564078Seric s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 195664078Seric s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 195764078Seric } 195853654Seric } 195958112Seric /* 196067903Seric ** INITTIMEOUTS -- parse and set timeout values 196158112Seric ** 196258112Seric ** Parameters: 196358112Seric ** val -- a pointer to the values. If NULL, do initial 196458112Seric ** settings. 196558112Seric ** 196658112Seric ** Returns: 196758112Seric ** none. 196858112Seric ** 196958112Seric ** Side Effects: 197058112Seric ** Initializes the TimeOuts structure 197158112Seric */ 197258112Seric 197364255Seric #define SECONDS 197458112Seric #define MINUTES * 60 197558112Seric #define HOUR * 3600 197658112Seric 197767903Seric inittimeouts(val) 197858112Seric register char *val; 197958112Seric { 198058112Seric register char *p; 198158671Seric extern time_t convtime(); 198258112Seric 198358112Seric if (val == NULL) 198458112Seric { 198558112Seric TimeOuts.to_initial = (time_t) 5 MINUTES; 198658112Seric TimeOuts.to_helo = (time_t) 5 MINUTES; 198758112Seric TimeOuts.to_mail = (time_t) 10 MINUTES; 198858112Seric TimeOuts.to_rcpt = (time_t) 1 HOUR; 198958112Seric TimeOuts.to_datainit = (time_t) 5 MINUTES; 199058112Seric TimeOuts.to_datablock = (time_t) 1 HOUR; 199158112Seric TimeOuts.to_datafinal = (time_t) 1 HOUR; 199258112Seric TimeOuts.to_rset = (time_t) 5 MINUTES; 199358112Seric TimeOuts.to_quit = (time_t) 2 MINUTES; 199458112Seric TimeOuts.to_nextcommand = (time_t) 1 HOUR; 199558112Seric TimeOuts.to_miscshort = (time_t) 2 MINUTES; 1996*68147Seric #if IDENTPROTO 199764255Seric TimeOuts.to_ident = (time_t) 30 SECONDS; 1998*68147Seric #else 1999*68147Seric TimeOuts.to_ident = (time_t) 0 SECONDS; 2000*68147Seric #endif 200167711Seric TimeOuts.to_fileopen = (time_t) 60 SECONDS; 200258112Seric return; 200358112Seric } 200458112Seric 200558112Seric for (;; val = p) 200658112Seric { 200758112Seric while (isascii(*val) && isspace(*val)) 200858112Seric val++; 200958112Seric if (*val == '\0') 201058112Seric break; 201158112Seric for (p = val; *p != '\0' && *p != ','; p++) 201258112Seric continue; 201358112Seric if (*p != '\0') 201458112Seric *p++ = '\0'; 201558112Seric 201658112Seric if (isascii(*val) && isdigit(*val)) 201758112Seric { 201858112Seric /* old syntax -- set everything */ 201958796Seric TimeOuts.to_mail = convtime(val, 'm'); 202058112Seric TimeOuts.to_rcpt = TimeOuts.to_mail; 202158112Seric TimeOuts.to_datainit = TimeOuts.to_mail; 202258112Seric TimeOuts.to_datablock = TimeOuts.to_mail; 202358112Seric TimeOuts.to_datafinal = TimeOuts.to_mail; 202458112Seric TimeOuts.to_nextcommand = TimeOuts.to_mail; 202558112Seric continue; 202658112Seric } 202758112Seric else 202858112Seric { 202967711Seric register char *q = strchr(val, ':'); 203058112Seric 203167711Seric if (q == NULL && (q = strchr(val, '=')) == NULL) 203258112Seric { 203358112Seric /* syntax error */ 203458112Seric continue; 203558112Seric } 203658112Seric *q++ = '\0'; 203767903Seric settimeout(val, q); 203867903Seric } 203967903Seric } 204067903Seric } 204167903Seric /* 204267903Seric ** SETTIMEOUT -- set an individual timeout 204367903Seric ** 204467903Seric ** Parameters: 204567903Seric ** name -- the name of the timeout. 204667903Seric ** val -- the value of the timeout. 204767903Seric ** 204867903Seric ** Returns: 204967903Seric ** none. 205067903Seric */ 205158112Seric 205267903Seric settimeout(name, val) 205367903Seric char *name; 205467903Seric char *val; 205567903Seric { 205667903Seric register char *p; 205767903Seric time_t to; 205867903Seric extern time_t convtime(); 205967903Seric 206067903Seric to = convtime(val, 'm'); 206167903Seric p = strchr(name, '.'); 206267903Seric if (p != NULL) 206367903Seric *p++ = '\0'; 206467903Seric 206567903Seric if (strcasecmp(name, "initial") == 0) 206667903Seric TimeOuts.to_initial = to; 206767903Seric else if (strcasecmp(name, "mail") == 0) 206867903Seric TimeOuts.to_mail = to; 206967903Seric else if (strcasecmp(name, "rcpt") == 0) 207067903Seric TimeOuts.to_rcpt = to; 207167903Seric else if (strcasecmp(name, "datainit") == 0) 207267903Seric TimeOuts.to_datainit = to; 207367903Seric else if (strcasecmp(name, "datablock") == 0) 207467903Seric TimeOuts.to_datablock = to; 207567903Seric else if (strcasecmp(name, "datafinal") == 0) 207667903Seric TimeOuts.to_datafinal = to; 207767903Seric else if (strcasecmp(name, "command") == 0) 207867903Seric TimeOuts.to_nextcommand = to; 207967903Seric else if (strcasecmp(name, "rset") == 0) 208067903Seric TimeOuts.to_rset = to; 208167903Seric else if (strcasecmp(name, "helo") == 0) 208267903Seric TimeOuts.to_helo = to; 208367903Seric else if (strcasecmp(name, "quit") == 0) 208467903Seric TimeOuts.to_quit = to; 208567903Seric else if (strcasecmp(name, "misc") == 0) 208667903Seric TimeOuts.to_miscshort = to; 208767903Seric else if (strcasecmp(name, "ident") == 0) 208867903Seric TimeOuts.to_ident = to; 208967903Seric else if (strcasecmp(name, "fileopen") == 0) 209067903Seric TimeOuts.to_fileopen = to; 209167903Seric else if (strcasecmp(name, "queuewarn") == 0) 209267903Seric { 209367903Seric to = convtime(val, 'h'); 209467946Seric if (p == NULL || strcmp(p, "*") == 0) 209567903Seric { 209667903Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 209767903Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 209867903Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 209958112Seric } 210067903Seric else if (strcasecmp(p, "normal") == 0) 210167903Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 210267903Seric else if (strcasecmp(p, "urgent") == 0) 210367903Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 210467903Seric else if (strcasecmp(p, "non-urgent") == 0) 210567903Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 210667903Seric else 210767903Seric syserr("settimeout: invalid queuewarn subtimeout %s", p); 210858112Seric } 210967903Seric else if (strcasecmp(name, "queuereturn") == 0) 211067903Seric { 211167903Seric to = convtime(val, 'd'); 211267903Seric if (p == NULL || strcmp(p, "*") == 0) 211367903Seric { 211467903Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 211567903Seric TimeOuts.to_q_return[TOC_URGENT] = to; 211667903Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 211767903Seric } 211867903Seric else if (strcasecmp(p, "normal") == 0) 211967903Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 212067903Seric else if (strcasecmp(p, "urgent") == 0) 212167903Seric TimeOuts.to_q_return[TOC_URGENT] = to; 212267903Seric else if (strcasecmp(p, "non-urgent") == 0) 212367903Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 212467903Seric else 212567903Seric syserr("settimeout: invalid queuereturn subtimeout %s", p); 212667903Seric } 212767903Seric else 212867903Seric syserr("settimeout: invalid timeout %s", name); 212958112Seric } 2130