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*68109Seric static char sccsid[] = "@(#)readcf.c 8.57 (Berkeley) 12/30/94"; 1133731Sbostic #endif /* not lint */ 1222709Sdist 133313Seric # include "sendmail.h" 1464133Seric # include <pwd.h> 1564133Seric # include <grp.h> 1666334Seric #if NAMED_BIND 1757207Seric # include <resolv.h> 1857207Seric #endif 193308Seric 203308Seric /* 213308Seric ** READCF -- read control file. 223308Seric ** 233308Seric ** This routine reads the control file and builds the internal 243308Seric ** form. 253308Seric ** 264432Seric ** The file is formatted as a sequence of lines, each taken 274432Seric ** atomically. The first character of each line describes how 284432Seric ** the line is to be interpreted. The lines are: 294432Seric ** Dxval Define macro x to have value val. 304432Seric ** Cxword Put word into class x. 314432Seric ** Fxfile [fmt] Read file for lines to put into 324432Seric ** class x. Use scanf string 'fmt' 334432Seric ** or "%s" if not present. Fmt should 344432Seric ** only produce one string-valued result. 354432Seric ** Hname: value Define header with field-name 'name' 364432Seric ** and value as specified; this will be 374432Seric ** macro expanded immediately before 384432Seric ** use. 394432Seric ** Sn Use rewriting set n. 404432Seric ** Rlhs rhs Rewrite addresses that match lhs to 414432Seric ** be rhs. 4224944Seric ** Mn arg=val... Define mailer. n is the internal name. 4324944Seric ** Args specify mailer parameters. 448252Seric ** Oxvalue Set option x to value. 458252Seric ** Pname=value Set precedence name to value. 4664718Seric ** Vversioncode[/vendorcode] 4764718Seric ** Version level/vendor name of 4864718Seric ** configuration syntax. 4953654Seric ** Kmapname mapclass arguments.... 5053654Seric ** Define keyed lookup of a given class. 5153654Seric ** Arguments are class dependent. 524432Seric ** 533308Seric ** Parameters: 543308Seric ** cfname -- control file name. 5554973Seric ** safe -- TRUE if this is the system config file; 5654973Seric ** FALSE otherwise. 5755012Seric ** e -- the main envelope. 583308Seric ** 593308Seric ** Returns: 603308Seric ** none. 613308Seric ** 623308Seric ** Side Effects: 633308Seric ** Builds several internal tables. 643308Seric */ 653308Seric 6655012Seric readcf(cfname, safe, e) 673308Seric char *cfname; 6854973Seric bool safe; 6955012Seric register ENVELOPE *e; 703308Seric { 713308Seric FILE *cf; 728547Seric int ruleset = 0; 738547Seric char *q; 749350Seric struct rewrite *rwp = NULL; 7557135Seric char *bp; 7664718Seric auto char *ep; 7757589Seric int nfuzzy; 7864133Seric char *file; 7964133Seric bool optional; 8067769Seric int mid; 813308Seric char buf[MAXLINE]; 823308Seric register char *p; 833308Seric extern char **copyplist(); 8452647Seric struct stat statb; 855909Seric char exbuf[MAXLINE]; 8665066Seric char pvpbuf[MAXLINE + MAXATOM]; 8767826Seric static char *null_list[1] = { NULL }; 8810709Seric extern char *munchstring(); 8953654Seric extern void makemapentry(); 903308Seric 9152647Seric FileName = cfname; 9252647Seric LineNumber = 0; 9352647Seric 943308Seric cf = fopen(cfname, "r"); 953308Seric if (cf == NULL) 963308Seric { 9752647Seric syserr("cannot open"); 983308Seric exit(EX_OSFILE); 993308Seric } 1003308Seric 10152647Seric if (fstat(fileno(cf), &statb) < 0) 10252647Seric { 10352647Seric syserr("cannot fstat"); 10452647Seric exit(EX_OSFILE); 10552647Seric } 10652647Seric 10752647Seric if (!S_ISREG(statb.st_mode)) 10852647Seric { 10952647Seric syserr("not a plain file"); 11052647Seric exit(EX_OSFILE); 11152647Seric } 11252647Seric 11352647Seric if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode)) 11452647Seric { 11553037Seric if (OpMode == MD_DAEMON || OpMode == MD_FREEZE) 11653037Seric fprintf(stderr, "%s: WARNING: dangerous write permissions\n", 11753037Seric FileName); 11853037Seric #ifdef LOG 11953037Seric if (LogLevel > 0) 12053037Seric syslog(LOG_CRIT, "%s: WARNING: dangerous write permissions", 12153037Seric FileName); 12253037Seric #endif 12352647Seric } 12452647Seric 12559254Seric #ifdef XLA 12659254Seric xla_zero(); 12759254Seric #endif 12859254Seric 12957135Seric while ((bp = fgetfolded(buf, sizeof buf, cf)) != NULL) 1303308Seric { 13157135Seric if (bp[0] == '#') 13257135Seric { 13357135Seric if (bp != buf) 13457135Seric free(bp); 13552637Seric continue; 13657135Seric } 13752637Seric 13867769Seric /* do macro expansion mappings */ 13957135Seric for (p = bp; *p != '\0'; p++) 14016157Seric { 14157135Seric if (*p == '#' && p > bp && ConfigLevel >= 3) 14252647Seric { 14352647Seric /* this is an on-line comment */ 14452647Seric register char *e; 14552647Seric 14658050Seric switch (*--p & 0377) 14752647Seric { 14858050Seric case MACROEXPAND: 14952647Seric /* it's from $# -- let it go through */ 15052647Seric p++; 15152647Seric break; 15252647Seric 15352647Seric case '\\': 15452647Seric /* it's backslash escaped */ 15552647Seric (void) strcpy(p, p + 1); 15652647Seric break; 15752647Seric 15852647Seric default: 15952647Seric /* delete preceeding white space */ 16058050Seric while (isascii(*p) && isspace(*p) && p > bp) 16152647Seric p--; 16256795Seric if ((e = strchr(++p, '\n')) != NULL) 16352647Seric (void) strcpy(p, e); 16452647Seric else 16552647Seric p[0] = p[1] = '\0'; 16652647Seric break; 16752647Seric } 16852647Seric continue; 16952647Seric } 17052647Seric 17167769Seric if (*p != '$' || p[1] == '\0') 17216157Seric continue; 17316157Seric 17416157Seric if (p[1] == '$') 17516157Seric { 17616157Seric /* actual dollar sign.... */ 17723111Seric (void) strcpy(p, p + 1); 17816157Seric continue; 17916157Seric } 18016157Seric 18116157Seric /* convert to macro expansion character */ 18267769Seric *p++ = MACROEXPAND; 18367769Seric 18467769Seric /* convert macro name to code */ 18567769Seric *p = macid(p, &ep); 18667769Seric if (ep != p) 18767769Seric strcpy(p + 1, ep); 18816157Seric } 18916157Seric 19016157Seric /* interpret this line */ 19164718Seric errno = 0; 19257135Seric switch (bp[0]) 1933308Seric { 1943308Seric case '\0': 1953308Seric case '#': /* comment */ 1963308Seric break; 1973308Seric 1983308Seric case 'R': /* rewriting rule */ 19957135Seric for (p = &bp[1]; *p != '\0' && *p != '\t'; p++) 2003308Seric continue; 2013308Seric 2023308Seric if (*p == '\0') 2035909Seric { 20465821Seric syserr("invalid rewrite line \"%s\" (tab expected)", bp); 2055909Seric break; 2065909Seric } 2075909Seric 2085909Seric /* allocate space for the rule header */ 2095909Seric if (rwp == NULL) 2105909Seric { 2115909Seric RewriteRules[ruleset] = rwp = 2125909Seric (struct rewrite *) xalloc(sizeof *rwp); 2135909Seric } 2143308Seric else 2153308Seric { 2165909Seric rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp); 2175909Seric rwp = rwp->r_next; 2185909Seric } 2195909Seric rwp->r_next = NULL; 2203308Seric 2215909Seric /* expand and save the LHS */ 2225909Seric *p = '\0'; 22357135Seric expand(&bp[1], exbuf, &exbuf[sizeof exbuf], e); 22465066Seric rwp->r_lhs = prescan(exbuf, '\t', pvpbuf, 22565066Seric sizeof pvpbuf, NULL); 22657589Seric nfuzzy = 0; 2275909Seric if (rwp->r_lhs != NULL) 22857589Seric { 22957589Seric register char **ap; 23057589Seric 2315909Seric rwp->r_lhs = copyplist(rwp->r_lhs, TRUE); 23257589Seric 23357589Seric /* count the number of fuzzy matches in LHS */ 23457589Seric for (ap = rwp->r_lhs; *ap != NULL; ap++) 23557589Seric { 23658148Seric char *botch; 23758148Seric 23858148Seric botch = NULL; 23958050Seric switch (**ap & 0377) 24057589Seric { 24157589Seric case MATCHZANY: 24257589Seric case MATCHANY: 24357589Seric case MATCHONE: 24457589Seric case MATCHCLASS: 24557589Seric case MATCHNCLASS: 24657589Seric nfuzzy++; 24758148Seric break; 24858148Seric 24958148Seric case MATCHREPL: 25058148Seric botch = "$0-$9"; 25158148Seric break; 25258148Seric 25358148Seric case CANONNET: 25458148Seric botch = "$#"; 25558148Seric break; 25658148Seric 25758148Seric case CANONUSER: 25858148Seric botch = "$:"; 25958148Seric break; 26058148Seric 26158148Seric case CALLSUBR: 26258148Seric botch = "$>"; 26358148Seric break; 26458148Seric 26558148Seric case CONDIF: 26658148Seric botch = "$?"; 26758148Seric break; 26858148Seric 26958148Seric case CONDELSE: 27058148Seric botch = "$|"; 27158148Seric break; 27258148Seric 27358148Seric case CONDFI: 27458148Seric botch = "$."; 27558148Seric break; 27658148Seric 27758148Seric case HOSTBEGIN: 27858148Seric botch = "$["; 27958148Seric break; 28058148Seric 28158148Seric case HOSTEND: 28258148Seric botch = "$]"; 28358148Seric break; 28458148Seric 28558148Seric case LOOKUPBEGIN: 28658148Seric botch = "$("; 28758148Seric break; 28858148Seric 28958148Seric case LOOKUPEND: 29058148Seric botch = "$)"; 29158148Seric break; 29257589Seric } 29358148Seric if (botch != NULL) 29458148Seric syserr("Inappropriate use of %s on LHS", 29558148Seric botch); 29657589Seric } 29757589Seric } 29856678Seric else 29967826Seric { 30056678Seric syserr("R line: null LHS"); 30167826Seric rwp->r_lhs = null_list; 30267826Seric } 3035909Seric 3045909Seric /* expand and save the RHS */ 3055909Seric while (*++p == '\t') 3065909Seric continue; 3077231Seric q = p; 3087231Seric while (*p != '\0' && *p != '\t') 3097231Seric p++; 3107231Seric *p = '\0'; 31155012Seric expand(q, exbuf, &exbuf[sizeof exbuf], e); 31265066Seric rwp->r_rhs = prescan(exbuf, '\t', pvpbuf, 31365066Seric sizeof pvpbuf, NULL); 3145909Seric if (rwp->r_rhs != NULL) 31557589Seric { 31657589Seric register char **ap; 31757589Seric 3185909Seric rwp->r_rhs = copyplist(rwp->r_rhs, TRUE); 31957589Seric 32057589Seric /* check no out-of-bounds replacements */ 32157589Seric nfuzzy += '0'; 32257589Seric for (ap = rwp->r_rhs; *ap != NULL; ap++) 32357589Seric { 32458148Seric char *botch; 32558148Seric 32658148Seric botch = NULL; 32758148Seric switch (**ap & 0377) 32857589Seric { 32958148Seric case MATCHREPL: 33058148Seric if ((*ap)[1] <= '0' || (*ap)[1] > nfuzzy) 33158148Seric { 33258148Seric syserr("replacement $%c out of bounds", 33358148Seric (*ap)[1]); 33458148Seric } 33558148Seric break; 33658148Seric 33758148Seric case MATCHZANY: 33858148Seric botch = "$*"; 33958148Seric break; 34058148Seric 34158148Seric case MATCHANY: 34258148Seric botch = "$+"; 34358148Seric break; 34458148Seric 34558148Seric case MATCHONE: 34658148Seric botch = "$-"; 34758148Seric break; 34858148Seric 34958148Seric case MATCHCLASS: 35058148Seric botch = "$="; 35158148Seric break; 35258148Seric 35358148Seric case MATCHNCLASS: 35458148Seric botch = "$~"; 35558148Seric break; 35657589Seric } 35758148Seric if (botch != NULL) 35858148Seric syserr("Inappropriate use of %s on RHS", 35958148Seric botch); 36057589Seric } 36157589Seric } 36256678Seric else 36367826Seric { 36456678Seric syserr("R line: null RHS"); 36567826Seric rwp->r_rhs = null_list; 36667826Seric } 3673308Seric break; 3683308Seric 3694072Seric case 'S': /* select rewriting set */ 37064440Seric for (p = &bp[1]; isascii(*p) && isspace(*p); p++) 37164440Seric continue; 37264440Seric if (!isascii(*p) || !isdigit(*p)) 37364440Seric { 37464440Seric syserr("invalid argument to S line: \"%.20s\"", 37564440Seric &bp[1]); 37664440Seric break; 37764440Seric } 37864440Seric ruleset = atoi(p); 3798056Seric if (ruleset >= MAXRWSETS || ruleset < 0) 3808056Seric { 3819381Seric syserr("bad ruleset %d (%d max)", ruleset, MAXRWSETS); 3828056Seric ruleset = 0; 3838056Seric } 3844072Seric rwp = NULL; 3854072Seric break; 3864072Seric 3873308Seric case 'D': /* macro definition */ 38867769Seric mid = macid(&bp[1], &ep); 38967769Seric p = munchstring(ep, NULL); 39067769Seric define(mid, newstr(p), e); 3913308Seric break; 3923308Seric 3933387Seric case 'H': /* required header line */ 39457135Seric (void) chompheader(&bp[1], TRUE, e); 3953387Seric break; 3963387Seric 3974061Seric case 'C': /* word class */ 3984432Seric /* scan the list of words and set class for all */ 39967769Seric mid = macid(&bp[1], &ep); 40067769Seric expand(ep, exbuf, &exbuf[sizeof exbuf], e); 40164121Seric for (p = exbuf; *p != '\0'; ) 4024061Seric { 4034061Seric register char *wd; 4044061Seric char delim; 4054061Seric 40658050Seric while (*p != '\0' && isascii(*p) && isspace(*p)) 4074061Seric p++; 4084061Seric wd = p; 40958050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 4104061Seric p++; 4114061Seric delim = *p; 4124061Seric *p = '\0'; 4134061Seric if (wd[0] != '\0') 41467769Seric setclass(mid, wd); 4154061Seric *p = delim; 4164061Seric } 4174061Seric break; 4184061Seric 41959272Seric case 'F': /* word class from file */ 42067769Seric mid = macid(&bp[1], &ep); 42167769Seric for (p = ep; isascii(*p) && isspace(*p); ) 42264133Seric p++; 42364133Seric if (p[0] == '-' && p[1] == 'o') 42464133Seric { 42564133Seric optional = TRUE; 42664133Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 42764133Seric p++; 42864133Seric while (isascii(*p) && isspace(*p)) 42967615Seric p++; 43064133Seric } 43164133Seric else 43264133Seric optional = FALSE; 43364133Seric file = p; 43464133Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 43564133Seric p++; 43659272Seric if (*p == '\0') 43759272Seric p = "%s"; 43859272Seric else 43959272Seric { 44059272Seric *p = '\0'; 44159272Seric while (isascii(*++p) && isspace(*p)) 44259272Seric continue; 44359272Seric } 44464133Seric fileclass(bp[1], file, p, safe, optional); 44559272Seric break; 44659272Seric 44759156Seric #ifdef XLA 44859156Seric case 'L': /* extended load average description */ 44959156Seric xla_init(&bp[1]); 45059156Seric break; 45159156Seric #endif 45259156Seric 4534096Seric case 'M': /* define mailer */ 45457135Seric makemailer(&bp[1]); 4554096Seric break; 4564096Seric 4578252Seric case 'O': /* set option */ 45858734Seric setoption(bp[1], &bp[2], safe, FALSE, e); 4598252Seric break; 4608252Seric 4618252Seric case 'P': /* set precedence */ 4628252Seric if (NumPriorities >= MAXPRIORITIES) 4638252Seric { 4648547Seric toomany('P', MAXPRIORITIES); 4658252Seric break; 4668252Seric } 46757135Seric for (p = &bp[1]; *p != '\0' && *p != '=' && *p != '\t'; p++) 4688252Seric continue; 4698252Seric if (*p == '\0') 4708252Seric goto badline; 4718252Seric *p = '\0'; 47257135Seric Priorities[NumPriorities].pri_name = newstr(&bp[1]); 4738252Seric Priorities[NumPriorities].pri_val = atoi(++p); 4748252Seric NumPriorities++; 4758252Seric break; 4768252Seric 4778547Seric case 'T': /* trusted user(s) */ 47858161Seric /* this option is obsolete, but will be ignored */ 4798547Seric break; 4808547Seric 48152645Seric case 'V': /* configuration syntax version */ 48264440Seric for (p = &bp[1]; isascii(*p) && isspace(*p); p++) 48364440Seric continue; 48464440Seric if (!isascii(*p) || !isdigit(*p)) 48564440Seric { 48664440Seric syserr("invalid argument to V line: \"%.20s\"", 48764440Seric &bp[1]); 48864440Seric break; 48964440Seric } 49064718Seric ConfigLevel = strtol(p, &ep, 10); 49164279Seric if (ConfigLevel >= 5) 49264279Seric { 49364279Seric /* level 5 configs have short name in $w */ 49464279Seric p = macvalue('w', e); 49564279Seric if (p != NULL && (p = strchr(p, '.')) != NULL) 49664279Seric *p = '\0'; 49764279Seric } 49864718Seric if (*ep++ == '/') 49964718Seric { 50064718Seric /* extract vendor code */ 50164718Seric for (p = ep; isascii(*p) && isalpha(*p); ) 50264718Seric p++; 50364718Seric *p = '\0'; 50464718Seric 50564718Seric if (!setvendor(ep)) 50664718Seric syserr("invalid V line vendor code: \"%s\"", 50764718Seric ep); 50864718Seric } 50952645Seric break; 51052645Seric 51153654Seric case 'K': 51257135Seric makemapentry(&bp[1]); 51353654Seric break; 51453654Seric 5153308Seric default: 5164061Seric badline: 51757135Seric syserr("unknown control line \"%s\"", bp); 5183308Seric } 51957135Seric if (bp != buf) 52057135Seric free(bp); 5213308Seric } 52252637Seric if (ferror(cf)) 52352637Seric { 52452647Seric syserr("I/O read error", cfname); 52552637Seric exit(EX_OSFILE); 52652637Seric } 52752637Seric fclose(cf); 5289381Seric FileName = NULL; 52956836Seric 53067730Seric /* initialize host maps from local service tables */ 53167730Seric inithostmaps(); 53267905Seric 53367905Seric /* determine if we need to do special name-server frotz */ 53467905Seric { 53567905Seric int nmaps; 53667905Seric char *maptype[MAXMAPSTACK]; 53767905Seric short mapreturn[MAXMAPACTIONS]; 53867905Seric 53967905Seric nmaps = switch_map_find("hosts", maptype, mapreturn); 54067905Seric UseNameServer = FALSE; 54167905Seric if (nmaps > 0 && nmaps <= MAXMAPSTACK) 54267905Seric { 54367905Seric register int mapno; 54467905Seric 54567905Seric for (mapno = 0; mapno < nmaps && !UseNameServer; mapno++) 54667905Seric { 54767905Seric if (strcmp(maptype[mapno], "dns") == 0) 54867905Seric UseNameServer = TRUE; 54967905Seric } 55067905Seric } 55167905Seric } 5524096Seric } 5534096Seric /* 5548547Seric ** TOOMANY -- signal too many of some option 5558547Seric ** 5568547Seric ** Parameters: 5578547Seric ** id -- the id of the error line 5588547Seric ** maxcnt -- the maximum possible values 5598547Seric ** 5608547Seric ** Returns: 5618547Seric ** none. 5628547Seric ** 5638547Seric ** Side Effects: 5648547Seric ** gives a syserr. 5658547Seric */ 5668547Seric 5678547Seric toomany(id, maxcnt) 5688547Seric char id; 5698547Seric int maxcnt; 5708547Seric { 5719381Seric syserr("too many %c lines, %d max", id, maxcnt); 5728547Seric } 5738547Seric /* 5744432Seric ** FILECLASS -- read members of a class from a file 5754432Seric ** 5764432Seric ** Parameters: 5774432Seric ** class -- class to define. 5784432Seric ** filename -- name of file to read. 5794432Seric ** fmt -- scanf string to use for match. 58064133Seric ** safe -- if set, this is a safe read. 58164133Seric ** optional -- if set, it is not an error for the file to 58264133Seric ** not exist. 5834432Seric ** 5844432Seric ** Returns: 5854432Seric ** none 5864432Seric ** 5874432Seric ** Side Effects: 5884432Seric ** 5894432Seric ** puts all lines in filename that match a scanf into 5904432Seric ** the named class. 5914432Seric */ 5924432Seric 59364133Seric fileclass(class, filename, fmt, safe, optional) 5944432Seric int class; 5954432Seric char *filename; 5964432Seric char *fmt; 59754973Seric bool safe; 59864133Seric bool optional; 5994432Seric { 60025808Seric FILE *f; 60154973Seric struct stat stbuf; 6024432Seric char buf[MAXLINE]; 6034432Seric 60466101Seric if (tTd(37, 2)) 60566101Seric printf("fileclass(%s, fmt=%s)\n", filename, fmt); 60666101Seric 60766031Seric if (filename[0] == '|') 60866031Seric { 60966031Seric syserr("fileclass: pipes (F%c%s) not supported due to security problems", 61066031Seric class, filename); 61166031Seric return; 61266031Seric } 61354973Seric if (stat(filename, &stbuf) < 0) 61454973Seric { 61566101Seric if (tTd(37, 2)) 61666101Seric printf(" cannot stat (%s)\n", errstring(errno)); 61764133Seric if (!optional) 61864133Seric syserr("fileclass: cannot stat %s", filename); 61954973Seric return; 62054973Seric } 62154973Seric if (!S_ISREG(stbuf.st_mode)) 62254973Seric { 62354973Seric syserr("fileclass: %s not a regular file", filename); 62454973Seric return; 62554973Seric } 62654973Seric if (!safe && access(filename, R_OK) < 0) 62754973Seric { 62854973Seric syserr("fileclass: access denied on %s", filename); 62954973Seric return; 63054973Seric } 63154973Seric f = fopen(filename, "r"); 6324432Seric if (f == NULL) 6334432Seric { 63454973Seric syserr("fileclass: cannot open %s", filename); 6354432Seric return; 6364432Seric } 6374432Seric 6384432Seric while (fgets(buf, sizeof buf, f) != NULL) 6394432Seric { 6404432Seric register STAB *s; 64125808Seric register char *p; 64225808Seric # ifdef SCANF 6434432Seric char wordbuf[MAXNAME+1]; 6444432Seric 6454432Seric if (sscanf(buf, fmt, wordbuf) != 1) 6464432Seric continue; 64725808Seric p = wordbuf; 64856795Seric # else /* SCANF */ 64925808Seric p = buf; 65056795Seric # endif /* SCANF */ 65125808Seric 65225808Seric /* 65325808Seric ** Break up the match into words. 65425808Seric */ 65525808Seric 65625808Seric while (*p != '\0') 65725808Seric { 65825808Seric register char *q; 65925808Seric 66025808Seric /* strip leading spaces */ 66158050Seric while (isascii(*p) && isspace(*p)) 66225808Seric p++; 66325808Seric if (*p == '\0') 66425808Seric break; 66525808Seric 66625808Seric /* find the end of the word */ 66725808Seric q = p; 66858050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 66925808Seric p++; 67025808Seric if (*p != '\0') 67125808Seric *p++ = '\0'; 67225808Seric 67325808Seric /* enter the word in the symbol table */ 67466101Seric setclass(class, q); 67525808Seric } 6764432Seric } 6774432Seric 67854973Seric (void) fclose(f); 6794432Seric } 6804432Seric /* 6814096Seric ** MAKEMAILER -- define a new mailer. 6824096Seric ** 6834096Seric ** Parameters: 68410327Seric ** line -- description of mailer. This is in labeled 68510327Seric ** fields. The fields are: 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, 1200*68109Seric "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 122367707Seric "MaxHostStatAge", O_MHSA, TRUE, 122467813Seric #define O_DEFCHARSET 0x85 122567813Seric "DefaultCharSet", O_DEFCHARSET, TRUE, 122667848Seric #define O_SSFILE 0x86 122767848Seric "ServiceSwitchFile", O_SSFILE, FALSE, 122868034Seric #define O_DIALDELAY 0x87 122968034Seric "DialDelay", O_DIALDELAY, TRUE, 123067707Seric 123167707Seric NULL, '\0', FALSE, 123267614Seric }; 123367614Seric 123467614Seric 123567614Seric 123658734Seric setoption(opt, val, safe, sticky, e) 123767614Seric u_char opt; 12388256Seric char *val; 123921755Seric bool safe; 12408269Seric bool sticky; 124158734Seric register ENVELOPE *e; 12428256Seric { 124357207Seric register char *p; 124467614Seric register struct optioninfo *o; 124567903Seric char *subopt; 12468265Seric extern bool atobool(); 124712633Seric extern time_t convtime(); 124814879Seric extern int QueueLA; 124914879Seric extern int RefuseLA; 125064718Seric extern bool Warn_Q_option; 12518256Seric 125267736Seric errno = 0; 125367614Seric if (opt == ' ') 125467614Seric { 125567614Seric /* full word options */ 125667736Seric struct optioninfo *sel; 125767614Seric 125867614Seric p = strchr(val, '='); 125967614Seric if (p == NULL) 126067614Seric p = &val[strlen(val)]; 126167614Seric while (*--p == ' ') 126267614Seric continue; 126367614Seric while (*++p == ' ') 126467614Seric *p = '\0'; 126567731Seric if (p == val) 126667731Seric { 126767731Seric syserr("readcf: null option name"); 126867731Seric return; 126967731Seric } 127067614Seric if (*p == '=') 127167614Seric *p++ = '\0'; 127267614Seric while (*p == ' ') 127367614Seric p++; 127467903Seric subopt = strchr(val, '.'); 127567903Seric if (subopt != NULL) 127667903Seric *subopt++ = '\0'; 127767736Seric sel = NULL; 127867614Seric for (o = OptionTab; o->o_name != NULL; o++) 127967614Seric { 128067736Seric if (strncasecmp(o->o_name, val, strlen(val)) != 0) 128167736Seric continue; 128267736Seric if (strlen(o->o_name) == strlen(val)) 128367736Seric { 128467736Seric /* completely specified -- this must be it */ 128567736Seric sel = NULL; 128667614Seric break; 128767736Seric } 128867736Seric if (sel != NULL) 128967736Seric break; 129067736Seric sel = o; 129167614Seric } 129267736Seric if (sel != NULL && o->o_name == NULL) 129367736Seric o = sel; 129467736Seric else if (o->o_name == NULL) 129567787Seric { 129667614Seric syserr("readcf: unknown option name %s", val); 129767787Seric return; 129867787Seric } 129967736Seric else if (sel != NULL) 130067736Seric { 130167736Seric syserr("readcf: ambiguous option name %s (matches %s and %s)", 130267736Seric val, sel->o_name, o->o_name); 130367736Seric return; 130467736Seric } 130567736Seric if (strlen(val) != strlen(o->o_name)) 130667736Seric { 130767736Seric bool oldVerbose = Verbose; 130867736Seric 130967736Seric Verbose = TRUE; 131067736Seric message("Option %s used as abbreviation for %s", 131167736Seric val, o->o_name); 131267736Seric Verbose = oldVerbose; 131367736Seric } 131467614Seric opt = o->o_code; 131567614Seric val = p; 131667614Seric } 131767614Seric else 131867614Seric { 131967614Seric for (o = OptionTab; o->o_name != NULL; o++) 132067614Seric { 132167614Seric if (o->o_code == opt) 132267614Seric break; 132367614Seric } 132467903Seric subopt = NULL; 132567614Seric } 132667614Seric 13278256Seric if (tTd(37, 1)) 132867731Seric { 132967731Seric printf(isascii(opt) && isprint(opt) ? 133067903Seric "setoption %s (%c).%s=%s" : 133167903Seric "setoption %s (0x%x).%s=%s", 133267614Seric o->o_name == NULL ? "<unknown>" : o->o_name, 133367903Seric opt, 133467903Seric subopt == NULL ? "" : subopt, 133567903Seric val); 133667731Seric } 13378256Seric 13388256Seric /* 13398269Seric ** See if this option is preset for us. 13408256Seric */ 13418256Seric 134259731Seric if (!sticky && bitnset(opt, StickyOpt)) 13438269Seric { 13449341Seric if (tTd(37, 1)) 13459341Seric printf(" (ignored)\n"); 13468269Seric return; 13478269Seric } 13488269Seric 134921755Seric /* 135021755Seric ** Check to see if this option can be specified by this user. 135121755Seric */ 135221755Seric 135363787Seric if (!safe && RealUid == 0) 135421755Seric safe = TRUE; 135567614Seric if (!safe && !o->o_safe) 135621755Seric { 135739111Srick if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 135821755Seric { 135936582Sbostic if (tTd(37, 1)) 136036582Sbostic printf(" (unsafe)"); 136163787Seric if (RealUid != geteuid()) 136236582Sbostic { 136351210Seric if (tTd(37, 1)) 136451210Seric printf("(Resetting uid)"); 136563787Seric (void) setgid(RealGid); 136663787Seric (void) setuid(RealUid); 136736582Sbostic } 136821755Seric } 136921755Seric } 137051210Seric if (tTd(37, 1)) 137117985Seric printf("\n"); 13728269Seric 137367614Seric switch (opt & 0xff) 13748256Seric { 137559709Seric case '7': /* force seven-bit input */ 137667546Seric SevenBitInput = atobool(val); 137752106Seric break; 137852106Seric 137967546Seric case '8': /* handling of 8-bit input */ 138067546Seric switch (*val) 138167546Seric { 138267547Seric case 'r': /* reject 8-bit, don't convert MIME */ 138367546Seric MimeMode = 0; 138467546Seric break; 138567546Seric 138667547Seric case 'm': /* convert 8-bit, convert MIME */ 138767546Seric MimeMode = MM_CVTMIME|MM_MIME8BIT; 138867546Seric break; 138967546Seric 139067547Seric case 'j': /* "just send 8" */ 139167546Seric MimeMode = MM_PASS8BIT; 139267546Seric break; 139367546Seric 139467546Seric case 'p': /* pass 8 bit, convert MIME */ 139567546Seric MimeMode = MM_PASS8BIT|MM_CVTMIME; 139667546Seric break; 139767546Seric 139867546Seric case 's': /* strict adherence */ 139967546Seric MimeMode = MM_CVTMIME; 140067546Seric break; 140167546Seric 140267547Seric case 'a': /* encode 8 bit if available */ 140367546Seric MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 140467546Seric break; 140567546Seric 140667547Seric case 'c': /* convert 8 bit to MIME, never 7 bit */ 140767547Seric MimeMode = MM_MIME8BIT; 140867547Seric break; 140967547Seric 141067546Seric default: 141167546Seric syserr("Unknown 8-bit mode %c", *val); 141267546Seric exit(EX_USAGE); 141367546Seric } 141467546Seric break; 141567546Seric 14168256Seric case 'A': /* set default alias file */ 14179381Seric if (val[0] == '\0') 141859672Seric setalias("aliases"); 14199381Seric else 142059672Seric setalias(val); 14218256Seric break; 14228256Seric 142317474Seric case 'a': /* look N minutes for "@:@" in alias file */ 142417474Seric if (val[0] == '\0') 142564796Seric SafeAlias = 5 * 60; /* five minutes */ 142617474Seric else 142764796Seric SafeAlias = convtime(val, 'm'); 142817474Seric break; 142917474Seric 143016843Seric case 'B': /* substitution for blank character */ 143116843Seric SpaceSub = val[0]; 143216843Seric if (SpaceSub == '\0') 143316843Seric SpaceSub = ' '; 143416843Seric break; 143516843Seric 143659283Seric case 'b': /* min blocks free on queue fs/max msg size */ 143759283Seric p = strchr(val, '/'); 143859283Seric if (p != NULL) 143959283Seric { 144059283Seric *p++ = '\0'; 144159283Seric MaxMessageSize = atol(p); 144259283Seric } 144358082Seric MinBlocksFree = atol(val); 144458082Seric break; 144558082Seric 14469284Seric case 'c': /* don't connect to "expensive" mailers */ 14479381Seric NoConnect = atobool(val); 14489284Seric break; 14499284Seric 145051305Seric case 'C': /* checkpoint every N addresses */ 145151305Seric CheckpointInterval = atoi(val); 145224944Seric break; 145324944Seric 14549284Seric case 'd': /* delivery mode */ 14559284Seric switch (*val) 14568269Seric { 14579284Seric case '\0': 145858734Seric e->e_sendmode = SM_DELIVER; 14598269Seric break; 14608269Seric 146110755Seric case SM_QUEUE: /* queue only */ 146210755Seric #ifndef QUEUE 146310755Seric syserr("need QUEUE to set -odqueue"); 146456795Seric #endif /* QUEUE */ 146510755Seric /* fall through..... */ 146610755Seric 14679284Seric case SM_DELIVER: /* do everything */ 14689284Seric case SM_FORK: /* fork after verification */ 146958734Seric e->e_sendmode = *val; 14708269Seric break; 14718269Seric 14728269Seric default: 14739284Seric syserr("Unknown delivery mode %c", *val); 14748269Seric exit(EX_USAGE); 14758269Seric } 14768269Seric break; 14778269Seric 14789146Seric case 'D': /* rebuild alias database as needed */ 14799381Seric AutoRebuild = atobool(val); 14809146Seric break; 14819146Seric 148255372Seric case 'E': /* error message header/header file */ 148355379Seric if (*val != '\0') 148455379Seric ErrMsgFile = newstr(val); 148555372Seric break; 148655372Seric 14878269Seric case 'e': /* set error processing mode */ 14888269Seric switch (*val) 14898269Seric { 14909381Seric case EM_QUIET: /* be silent about it */ 14919381Seric case EM_MAIL: /* mail back */ 14929381Seric case EM_BERKNET: /* do berknet error processing */ 14939381Seric case EM_WRITE: /* write back (or mail) */ 14949381Seric case EM_PRINT: /* print errors normally (default) */ 149558734Seric e->e_errormode = *val; 14968269Seric break; 14978269Seric } 14988269Seric break; 14998269Seric 15009049Seric case 'F': /* file mode */ 150117975Seric FileMode = atooct(val) & 0777; 15029049Seric break; 15039049Seric 15048269Seric case 'f': /* save Unix-style From lines on front */ 15059381Seric SaveFrom = atobool(val); 15068269Seric break; 15078269Seric 150853735Seric case 'G': /* match recipients against GECOS field */ 150953735Seric MatchGecos = atobool(val); 151053735Seric break; 151153735Seric 15128256Seric case 'g': /* default gid */ 151367823Seric g_opt: 151464133Seric if (isascii(*val) && isdigit(*val)) 151564133Seric DefGid = atoi(val); 151664133Seric else 151764133Seric { 151864133Seric register struct group *gr; 151964133Seric 152064133Seric DefGid = -1; 152164133Seric gr = getgrnam(val); 152264133Seric if (gr == NULL) 152367823Seric syserr("readcf: option %c: unknown group %s", 152467823Seric opt, val); 152564133Seric else 152664133Seric DefGid = gr->gr_gid; 152764133Seric } 15288256Seric break; 15298256Seric 15308256Seric case 'H': /* help file */ 15319381Seric if (val[0] == '\0') 15328269Seric HelpFile = "sendmail.hf"; 15339381Seric else 15349381Seric HelpFile = newstr(val); 15358256Seric break; 15368256Seric 153751305Seric case 'h': /* maximum hop count */ 153851305Seric MaxHopCount = atoi(val); 153951305Seric break; 154051305Seric 154135651Seric case 'I': /* use internet domain name server */ 154266334Seric #if NAMED_BIND 154357207Seric for (p = val; *p != 0; ) 154457207Seric { 154557207Seric bool clearmode; 154657207Seric char *q; 154757207Seric struct resolverflags *rfp; 154857207Seric 154957207Seric while (*p == ' ') 155057207Seric p++; 155157207Seric if (*p == '\0') 155257207Seric break; 155357207Seric clearmode = FALSE; 155457207Seric if (*p == '-') 155557207Seric clearmode = TRUE; 155657207Seric else if (*p != '+') 155757207Seric p--; 155857207Seric p++; 155957207Seric q = p; 156058050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 156157207Seric p++; 156257207Seric if (*p != '\0') 156357207Seric *p++ = '\0'; 156457207Seric for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 156557207Seric { 156657207Seric if (strcasecmp(q, rfp->rf_name) == 0) 156757207Seric break; 156857207Seric } 156964923Seric if (rfp->rf_name == NULL) 157064923Seric syserr("readcf: I option value %s unrecognized", q); 157164923Seric else if (clearmode) 157257207Seric _res.options &= ~rfp->rf_bits; 157357207Seric else 157457207Seric _res.options |= rfp->rf_bits; 157557207Seric } 157657207Seric if (tTd(8, 2)) 157757207Seric printf("_res.options = %x\n", _res.options); 157857207Seric #else 157957207Seric usrerr("name server (I option) specified but BIND not compiled in"); 158057207Seric #endif 158135651Seric break; 158235651Seric 15838269Seric case 'i': /* ignore dot lines in message */ 15849381Seric IgnrDot = atobool(val); 15858269Seric break; 15868269Seric 158759730Seric case 'j': /* send errors in MIME (RFC 1341) format */ 158859730Seric SendMIMEErrors = atobool(val); 158959730Seric break; 159059730Seric 159157136Seric case 'J': /* .forward search path */ 159257136Seric ForwardPath = newstr(val); 159357136Seric break; 159457136Seric 159554967Seric case 'k': /* connection cache size */ 159654967Seric MaxMciCache = atoi(val); 159756215Seric if (MaxMciCache < 0) 159856215Seric MaxMciCache = 0; 159954967Seric break; 160054967Seric 160154967Seric case 'K': /* connection cache timeout */ 160258796Seric MciCacheTimeout = convtime(val, 'm'); 160354967Seric break; 160454967Seric 160561104Seric case 'l': /* use Errors-To: header */ 160661104Seric UseErrorsTo = atobool(val); 160761104Seric break; 160861104Seric 16098256Seric case 'L': /* log level */ 161064140Seric if (safe || LogLevel < atoi(val)) 161164140Seric LogLevel = atoi(val); 16128256Seric break; 16138256Seric 16148269Seric case 'M': /* define macro */ 16159381Seric define(val[0], newstr(&val[1]), CurEnv); 161616878Seric sticky = FALSE; 16178269Seric break; 16188269Seric 16198269Seric case 'm': /* send to me too */ 16209381Seric MeToo = atobool(val); 16218269Seric break; 16228269Seric 162325820Seric case 'n': /* validate RHS in newaliases */ 162425820Seric CheckAliases = atobool(val); 162525820Seric break; 162625820Seric 162761104Seric /* 'N' available -- was "net name" */ 162861104Seric 162958851Seric case 'O': /* daemon options */ 163058851Seric setdaemonoptions(val); 163158851Seric break; 163258851Seric 16338269Seric case 'o': /* assume old style headers */ 16349381Seric if (atobool(val)) 16359341Seric CurEnv->e_flags |= EF_OLDSTYLE; 16369341Seric else 16379341Seric CurEnv->e_flags &= ~EF_OLDSTYLE; 16388269Seric break; 16398269Seric 164058082Seric case 'p': /* select privacy level */ 164158082Seric p = val; 164258082Seric for (;;) 164358082Seric { 164458082Seric register struct prival *pv; 164558082Seric extern struct prival PrivacyValues[]; 164658082Seric 164758082Seric while (isascii(*p) && (isspace(*p) || ispunct(*p))) 164858082Seric p++; 164958082Seric if (*p == '\0') 165058082Seric break; 165158082Seric val = p; 165258082Seric while (isascii(*p) && isalnum(*p)) 165358082Seric p++; 165458082Seric if (*p != '\0') 165558082Seric *p++ = '\0'; 165658082Seric 165758082Seric for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 165858082Seric { 165958082Seric if (strcasecmp(val, pv->pv_name) == 0) 166058082Seric break; 166158082Seric } 166258886Seric if (pv->pv_name == NULL) 166358886Seric syserr("readcf: Op line: %s unrecognized", val); 166458082Seric PrivacyFlags |= pv->pv_flag; 166558082Seric } 166658082Seric break; 166758082Seric 166824944Seric case 'P': /* postmaster copy address for returned mail */ 166924944Seric PostMasterCopy = newstr(val); 167024944Seric break; 167124944Seric 167224944Seric case 'q': /* slope of queue only function */ 167324944Seric QueueFactor = atoi(val); 167424944Seric break; 167524944Seric 16768256Seric case 'Q': /* queue directory */ 16779381Seric if (val[0] == '\0') 16788269Seric QueueDir = "mqueue"; 16799381Seric else 16809381Seric QueueDir = newstr(val); 168158789Seric if (RealUid != 0 && !safe) 168264718Seric Warn_Q_option = TRUE; 16838256Seric break; 16848256Seric 168558148Seric case 'R': /* don't prune routes */ 168658148Seric DontPruneRoutes = atobool(val); 168758148Seric break; 168858148Seric 16898256Seric case 'r': /* read timeout */ 169067903Seric if (subopt == NULL) 169167903Seric inittimeouts(val); 169267903Seric else 169367903Seric settimeout(subopt, val); 16948256Seric break; 16958256Seric 16968256Seric case 'S': /* status file */ 16979381Seric if (val[0] == '\0') 16988269Seric StatFile = "sendmail.st"; 16999381Seric else 17009381Seric StatFile = newstr(val); 17018256Seric break; 17028256Seric 17038265Seric case 's': /* be super safe, even if expensive */ 17049381Seric SuperSafe = atobool(val); 17058256Seric break; 17068256Seric 17078256Seric case 'T': /* queue timeout */ 170858737Seric p = strchr(val, '/'); 170958737Seric if (p != NULL) 171058737Seric { 171158737Seric *p++ = '\0'; 171267903Seric settimeout("queuewarn", p); 171358737Seric } 171467903Seric settimeout("queuereturn", val); 171554967Seric break; 17168256Seric 17178265Seric case 't': /* time zone name */ 171852106Seric TimeZoneSpec = newstr(val); 17198265Seric break; 17208265Seric 172150556Seric case 'U': /* location of user database */ 172251360Seric UdbSpec = newstr(val); 172350556Seric break; 172450556Seric 17258256Seric case 'u': /* set default uid */ 172667823Seric for (p = val; *p != '\0'; p++) 172767823Seric { 172867823Seric if (*p == '.' || *p == '/' || *p == ':') 172967823Seric { 173067823Seric *p++ = '\0'; 173167823Seric break; 173267823Seric } 173367823Seric } 173464133Seric if (isascii(*val) && isdigit(*val)) 173564133Seric DefUid = atoi(val); 173664133Seric else 173764133Seric { 173864133Seric register struct passwd *pw; 173964133Seric 174064133Seric DefUid = -1; 174164133Seric pw = getpwnam(val); 174264133Seric if (pw == NULL) 174364133Seric syserr("readcf: option u: unknown user %s", val); 174464133Seric else 174567823Seric { 174664133Seric DefUid = pw->pw_uid; 174767823Seric DefGid = pw->pw_gid; 174867823Seric } 174964133Seric } 175040973Sbostic setdefuser(); 17518256Seric 175267823Seric /* handle the group if it is there */ 175367823Seric if (*p == '\0') 175467823Seric break; 175567823Seric val = p; 175667823Seric goto g_opt; 175767823Seric 175858851Seric case 'V': /* fallback MX host */ 175958851Seric FallBackMX = newstr(val); 176058851Seric break; 176158851Seric 17628269Seric case 'v': /* run in verbose mode */ 17639381Seric Verbose = atobool(val); 17648256Seric break; 17658256Seric 176663837Seric case 'w': /* if we are best MX, try host directly */ 176763837Seric TryNullMXList = atobool(val); 176863837Seric break; 176961104Seric 177061104Seric /* 'W' available -- was wizard password */ 177161104Seric 177214879Seric case 'x': /* load avg at which to auto-queue msgs */ 177314879Seric QueueLA = atoi(val); 177414879Seric break; 177514879Seric 177614879Seric case 'X': /* load avg at which to auto-reject connections */ 177714879Seric RefuseLA = atoi(val); 177814879Seric break; 177914879Seric 178024981Seric case 'y': /* work recipient factor */ 178124981Seric WkRecipFact = atoi(val); 178224981Seric break; 178324981Seric 178424981Seric case 'Y': /* fork jobs during queue runs */ 178524952Seric ForkQueueRuns = atobool(val); 178624952Seric break; 178724952Seric 178824981Seric case 'z': /* work message class factor */ 178924981Seric WkClassFact = atoi(val); 179024981Seric break; 179124981Seric 179224981Seric case 'Z': /* work time factor */ 179324981Seric WkTimeFact = atoi(val); 179424981Seric break; 179524981Seric 179667614Seric case O_BSP: /* SMTP Peers can't handle 2-line greeting */ 179767614Seric BrokenSmtpPeers = atobool(val); 179867614Seric break; 179967614Seric 180068105Seric case O_QUEUESORTORD: /* queue sorting order */ 180168105Seric switch (*val) 180268105Seric { 180368105Seric case 'h': /* Host first */ 180468105Seric case 'H': 180568105Seric QueueSortOrder = QS_BYHOST; 180668105Seric break; 180768105Seric 180868105Seric case 'p': /* Priority order */ 180968105Seric case 'P': 181068105Seric QueueSortOrder = QS_BYPRIORITY; 181168105Seric break; 181268105Seric 181368105Seric default: 181468105Seric syserr("Invalid queue sort order \"%s\"", val); 181568105Seric } 181667614Seric break; 181767614Seric 181867707Seric case O_MQA: /* minimum queue age between deliveries */ 181967707Seric MinQueueAge = convtime(val, 'm'); 182067707Seric break; 182167707Seric 182267707Seric case O_MHSA: /* maximum age of cached host status */ 182367707Seric MaxHostStatAge = convtime(val, 'm'); 182467707Seric break; 182567707Seric 182667813Seric case O_DEFCHARSET: /* default character set for mimefying */ 182767814Seric DefaultCharSet = newstr(val); 182867813Seric break; 182967813Seric 183067848Seric case O_SSFILE: /* service switch file */ 183167848Seric ServiceSwitchFile = newstr(val); 183267848Seric break; 183367848Seric 183468034Seric case O_DIALDELAY: /* delay for dial-on-demand operation */ 183568034Seric DialDelay = convtime(val, 's'); 183668034Seric break; 183768034Seric 18388256Seric default: 18398256Seric break; 18408256Seric } 184116878Seric if (sticky) 184216878Seric setbitn(opt, StickyOpt); 18439188Seric return; 18448256Seric } 184510687Seric /* 184610687Seric ** SETCLASS -- set a word into a class 184710687Seric ** 184810687Seric ** Parameters: 184910687Seric ** class -- the class to put the word in. 185010687Seric ** word -- the word to enter 185110687Seric ** 185210687Seric ** Returns: 185310687Seric ** none. 185410687Seric ** 185510687Seric ** Side Effects: 185610687Seric ** puts the word into the symbol table. 185710687Seric */ 185810687Seric 185910687Seric setclass(class, word) 186010687Seric int class; 186110687Seric char *word; 186210687Seric { 186310687Seric register STAB *s; 186410687Seric 186557943Seric if (tTd(37, 8)) 186664326Seric printf("setclass(%c, %s)\n", class, word); 186710687Seric s = stab(word, ST_CLASS, ST_ENTER); 186810687Seric setbitn(class, s->s_class); 186910687Seric } 187053654Seric /* 187153654Seric ** MAKEMAPENTRY -- create a map entry 187253654Seric ** 187353654Seric ** Parameters: 187453654Seric ** line -- the config file line 187553654Seric ** 187653654Seric ** Returns: 187753654Seric ** TRUE if it successfully entered the map entry. 187853654Seric ** FALSE otherwise (usually syntax error). 187953654Seric ** 188053654Seric ** Side Effects: 188153654Seric ** Enters the map into the dictionary. 188253654Seric */ 188353654Seric 188453654Seric void 188553654Seric makemapentry(line) 188653654Seric char *line; 188753654Seric { 188853654Seric register char *p; 188953654Seric char *mapname; 189053654Seric char *classname; 189164078Seric register STAB *s; 189253654Seric STAB *class; 189353654Seric 189458050Seric for (p = line; isascii(*p) && isspace(*p); p++) 189553654Seric continue; 189658050Seric if (!(isascii(*p) && isalnum(*p))) 189753654Seric { 189853654Seric syserr("readcf: config K line: no map name"); 189953654Seric return; 190053654Seric } 190153654Seric 190253654Seric mapname = p; 190367848Seric while ((isascii(*++p) && isalnum(*p)) || *p == '.') 190453654Seric continue; 190553654Seric if (*p != '\0') 190653654Seric *p++ = '\0'; 190758050Seric while (isascii(*p) && isspace(*p)) 190853654Seric p++; 190958050Seric if (!(isascii(*p) && isalnum(*p))) 191053654Seric { 191153654Seric syserr("readcf: config K line, map %s: no map class", mapname); 191253654Seric return; 191353654Seric } 191453654Seric classname = p; 191558050Seric while (isascii(*++p) && isalnum(*p)) 191653654Seric continue; 191753654Seric if (*p != '\0') 191853654Seric *p++ = '\0'; 191958050Seric while (isascii(*p) && isspace(*p)) 192053654Seric p++; 192153654Seric 192253654Seric /* look up the class */ 192353654Seric class = stab(classname, ST_MAPCLASS, ST_FIND); 192453654Seric if (class == NULL) 192553654Seric { 192653654Seric syserr("readcf: map %s: class %s not available", mapname, classname); 192753654Seric return; 192853654Seric } 192953654Seric 193053654Seric /* enter the map */ 193164078Seric s = stab(mapname, ST_MAP, ST_ENTER); 193264078Seric s->s_map.map_class = &class->s_mapclass; 193364078Seric s->s_map.map_mname = newstr(mapname); 193453654Seric 193564078Seric if (class->s_mapclass.map_parse(&s->s_map, p)) 193664078Seric s->s_map.map_mflags |= MF_VALID; 193764078Seric 193864078Seric if (tTd(37, 5)) 193964078Seric { 194064078Seric printf("map %s, class %s, flags %x, file %s,\n", 194164078Seric s->s_map.map_mname, s->s_map.map_class->map_cname, 194264078Seric s->s_map.map_mflags, 194364078Seric s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 194464078Seric printf("\tapp %s, domain %s, rebuild %s\n", 194564078Seric s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 194664078Seric s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 194764078Seric s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 194864078Seric } 194953654Seric } 195058112Seric /* 195167903Seric ** INITTIMEOUTS -- parse and set timeout values 195258112Seric ** 195358112Seric ** Parameters: 195458112Seric ** val -- a pointer to the values. If NULL, do initial 195558112Seric ** settings. 195658112Seric ** 195758112Seric ** Returns: 195858112Seric ** none. 195958112Seric ** 196058112Seric ** Side Effects: 196158112Seric ** Initializes the TimeOuts structure 196258112Seric */ 196358112Seric 196464255Seric #define SECONDS 196558112Seric #define MINUTES * 60 196658112Seric #define HOUR * 3600 196758112Seric 196867903Seric inittimeouts(val) 196958112Seric register char *val; 197058112Seric { 197158112Seric register char *p; 197258671Seric extern time_t convtime(); 197358112Seric 197458112Seric if (val == NULL) 197558112Seric { 197658112Seric TimeOuts.to_initial = (time_t) 5 MINUTES; 197758112Seric TimeOuts.to_helo = (time_t) 5 MINUTES; 197858112Seric TimeOuts.to_mail = (time_t) 10 MINUTES; 197958112Seric TimeOuts.to_rcpt = (time_t) 1 HOUR; 198058112Seric TimeOuts.to_datainit = (time_t) 5 MINUTES; 198158112Seric TimeOuts.to_datablock = (time_t) 1 HOUR; 198258112Seric TimeOuts.to_datafinal = (time_t) 1 HOUR; 198358112Seric TimeOuts.to_rset = (time_t) 5 MINUTES; 198458112Seric TimeOuts.to_quit = (time_t) 2 MINUTES; 198558112Seric TimeOuts.to_nextcommand = (time_t) 1 HOUR; 198658112Seric TimeOuts.to_miscshort = (time_t) 2 MINUTES; 198764255Seric TimeOuts.to_ident = (time_t) 30 SECONDS; 198867711Seric TimeOuts.to_fileopen = (time_t) 60 SECONDS; 198958112Seric return; 199058112Seric } 199158112Seric 199258112Seric for (;; val = p) 199358112Seric { 199458112Seric while (isascii(*val) && isspace(*val)) 199558112Seric val++; 199658112Seric if (*val == '\0') 199758112Seric break; 199858112Seric for (p = val; *p != '\0' && *p != ','; p++) 199958112Seric continue; 200058112Seric if (*p != '\0') 200158112Seric *p++ = '\0'; 200258112Seric 200358112Seric if (isascii(*val) && isdigit(*val)) 200458112Seric { 200558112Seric /* old syntax -- set everything */ 200658796Seric TimeOuts.to_mail = convtime(val, 'm'); 200758112Seric TimeOuts.to_rcpt = TimeOuts.to_mail; 200858112Seric TimeOuts.to_datainit = TimeOuts.to_mail; 200958112Seric TimeOuts.to_datablock = TimeOuts.to_mail; 201058112Seric TimeOuts.to_datafinal = TimeOuts.to_mail; 201158112Seric TimeOuts.to_nextcommand = TimeOuts.to_mail; 201258112Seric continue; 201358112Seric } 201458112Seric else 201558112Seric { 201667711Seric register char *q = strchr(val, ':'); 201758112Seric 201867711Seric if (q == NULL && (q = strchr(val, '=')) == NULL) 201958112Seric { 202058112Seric /* syntax error */ 202158112Seric continue; 202258112Seric } 202358112Seric *q++ = '\0'; 202467903Seric settimeout(val, q); 202567903Seric } 202667903Seric } 202767903Seric } 202867903Seric /* 202967903Seric ** SETTIMEOUT -- set an individual timeout 203067903Seric ** 203167903Seric ** Parameters: 203267903Seric ** name -- the name of the timeout. 203367903Seric ** val -- the value of the timeout. 203467903Seric ** 203567903Seric ** Returns: 203667903Seric ** none. 203767903Seric */ 203858112Seric 203967903Seric settimeout(name, val) 204067903Seric char *name; 204167903Seric char *val; 204267903Seric { 204367903Seric register char *p; 204467903Seric time_t to; 204567903Seric extern time_t convtime(); 204667903Seric 204767903Seric to = convtime(val, 'm'); 204867903Seric p = strchr(name, '.'); 204967903Seric if (p != NULL) 205067903Seric *p++ = '\0'; 205167903Seric 205267903Seric if (strcasecmp(name, "initial") == 0) 205367903Seric TimeOuts.to_initial = to; 205467903Seric else if (strcasecmp(name, "mail") == 0) 205567903Seric TimeOuts.to_mail = to; 205667903Seric else if (strcasecmp(name, "rcpt") == 0) 205767903Seric TimeOuts.to_rcpt = to; 205867903Seric else if (strcasecmp(name, "datainit") == 0) 205967903Seric TimeOuts.to_datainit = to; 206067903Seric else if (strcasecmp(name, "datablock") == 0) 206167903Seric TimeOuts.to_datablock = to; 206267903Seric else if (strcasecmp(name, "datafinal") == 0) 206367903Seric TimeOuts.to_datafinal = to; 206467903Seric else if (strcasecmp(name, "command") == 0) 206567903Seric TimeOuts.to_nextcommand = to; 206667903Seric else if (strcasecmp(name, "rset") == 0) 206767903Seric TimeOuts.to_rset = to; 206867903Seric else if (strcasecmp(name, "helo") == 0) 206967903Seric TimeOuts.to_helo = to; 207067903Seric else if (strcasecmp(name, "quit") == 0) 207167903Seric TimeOuts.to_quit = to; 207267903Seric else if (strcasecmp(name, "misc") == 0) 207367903Seric TimeOuts.to_miscshort = to; 207467903Seric else if (strcasecmp(name, "ident") == 0) 207567903Seric TimeOuts.to_ident = to; 207667903Seric else if (strcasecmp(name, "fileopen") == 0) 207767903Seric TimeOuts.to_fileopen = to; 207867903Seric else if (strcasecmp(name, "queuewarn") == 0) 207967903Seric { 208067903Seric to = convtime(val, 'h'); 208167946Seric if (p == NULL || strcmp(p, "*") == 0) 208267903Seric { 208367903Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 208467903Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 208567903Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 208658112Seric } 208767903Seric else if (strcasecmp(p, "normal") == 0) 208867903Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 208967903Seric else if (strcasecmp(p, "urgent") == 0) 209067903Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 209167903Seric else if (strcasecmp(p, "non-urgent") == 0) 209267903Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 209367903Seric else 209467903Seric syserr("settimeout: invalid queuewarn subtimeout %s", p); 209558112Seric } 209667903Seric else if (strcasecmp(name, "queuereturn") == 0) 209767903Seric { 209867903Seric to = convtime(val, 'd'); 209967903Seric if (p == NULL || strcmp(p, "*") == 0) 210067903Seric { 210167903Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 210267903Seric TimeOuts.to_q_return[TOC_URGENT] = to; 210367903Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 210467903Seric } 210567903Seric else if (strcasecmp(p, "normal") == 0) 210667903Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 210767903Seric else if (strcasecmp(p, "urgent") == 0) 210867903Seric TimeOuts.to_q_return[TOC_URGENT] = to; 210967903Seric else if (strcasecmp(p, "non-urgent") == 0) 211067903Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 211167903Seric else 211267903Seric syserr("settimeout: invalid queuereturn subtimeout %s", p); 211367903Seric } 211467903Seric else 211567903Seric syserr("settimeout: invalid timeout %s", name); 211658112Seric } 2117