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*68204Seric static char sccsid[] = "@(#)readcf.c 8.60 (Berkeley) 01/25/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 } 551*68204Seric 552*68204Seric #ifdef HESIOD 553*68204Seric nmaps = switch_map_find("passwd", maptype, mapreturn); 554*68204Seric UseHesiod = FALSE; 555*68204Seric if (nmaps > 0 && nmaps <= MAXMAPSTACK) 556*68204Seric { 557*68204Seric register int mapno; 558*68204Seric 559*68204Seric for (mapno = 0; mapno < nmaps && !UseHesiod; mapno++) 560*68204Seric { 561*68204Seric if (strcmp(maptype[mapno], "hesiod") == 0) 562*68204Seric UseHesiod = TRUE; 563*68204Seric } 564*68204Seric } 565*68204Seric #endif 56667905Seric } 5674096Seric } 5684096Seric /* 5698547Seric ** TOOMANY -- signal too many of some option 5708547Seric ** 5718547Seric ** Parameters: 5728547Seric ** id -- the id of the error line 5738547Seric ** maxcnt -- the maximum possible values 5748547Seric ** 5758547Seric ** Returns: 5768547Seric ** none. 5778547Seric ** 5788547Seric ** Side Effects: 5798547Seric ** gives a syserr. 5808547Seric */ 5818547Seric 5828547Seric toomany(id, maxcnt) 5838547Seric char id; 5848547Seric int maxcnt; 5858547Seric { 5869381Seric syserr("too many %c lines, %d max", id, maxcnt); 5878547Seric } 5888547Seric /* 5894432Seric ** FILECLASS -- read members of a class from a file 5904432Seric ** 5914432Seric ** Parameters: 5924432Seric ** class -- class to define. 5934432Seric ** filename -- name of file to read. 5944432Seric ** fmt -- scanf string to use for match. 59564133Seric ** safe -- if set, this is a safe read. 59664133Seric ** optional -- if set, it is not an error for the file to 59764133Seric ** not exist. 5984432Seric ** 5994432Seric ** Returns: 6004432Seric ** none 6014432Seric ** 6024432Seric ** Side Effects: 6034432Seric ** 6044432Seric ** puts all lines in filename that match a scanf into 6054432Seric ** the named class. 6064432Seric */ 6074432Seric 60864133Seric fileclass(class, filename, fmt, safe, optional) 6094432Seric int class; 6104432Seric char *filename; 6114432Seric char *fmt; 61254973Seric bool safe; 61364133Seric bool optional; 6144432Seric { 61525808Seric FILE *f; 61654973Seric struct stat stbuf; 6174432Seric char buf[MAXLINE]; 6184432Seric 61966101Seric if (tTd(37, 2)) 62066101Seric printf("fileclass(%s, fmt=%s)\n", filename, fmt); 62166101Seric 62266031Seric if (filename[0] == '|') 62366031Seric { 62466031Seric syserr("fileclass: pipes (F%c%s) not supported due to security problems", 62566031Seric class, filename); 62666031Seric return; 62766031Seric } 62854973Seric if (stat(filename, &stbuf) < 0) 62954973Seric { 63066101Seric if (tTd(37, 2)) 63166101Seric printf(" cannot stat (%s)\n", errstring(errno)); 63264133Seric if (!optional) 63364133Seric syserr("fileclass: cannot stat %s", filename); 63454973Seric return; 63554973Seric } 63654973Seric if (!S_ISREG(stbuf.st_mode)) 63754973Seric { 63854973Seric syserr("fileclass: %s not a regular file", filename); 63954973Seric return; 64054973Seric } 64154973Seric if (!safe && access(filename, R_OK) < 0) 64254973Seric { 64354973Seric syserr("fileclass: access denied on %s", filename); 64454973Seric return; 64554973Seric } 64654973Seric f = fopen(filename, "r"); 6474432Seric if (f == NULL) 6484432Seric { 64954973Seric syserr("fileclass: cannot open %s", filename); 6504432Seric return; 6514432Seric } 6524432Seric 6534432Seric while (fgets(buf, sizeof buf, f) != NULL) 6544432Seric { 6554432Seric register STAB *s; 65625808Seric register char *p; 65725808Seric # ifdef SCANF 6584432Seric char wordbuf[MAXNAME+1]; 6594432Seric 6604432Seric if (sscanf(buf, fmt, wordbuf) != 1) 6614432Seric continue; 66225808Seric p = wordbuf; 66356795Seric # else /* SCANF */ 66425808Seric p = buf; 66556795Seric # endif /* SCANF */ 66625808Seric 66725808Seric /* 66825808Seric ** Break up the match into words. 66925808Seric */ 67025808Seric 67125808Seric while (*p != '\0') 67225808Seric { 67325808Seric register char *q; 67425808Seric 67525808Seric /* strip leading spaces */ 67658050Seric while (isascii(*p) && isspace(*p)) 67725808Seric p++; 67825808Seric if (*p == '\0') 67925808Seric break; 68025808Seric 68125808Seric /* find the end of the word */ 68225808Seric q = p; 68358050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 68425808Seric p++; 68525808Seric if (*p != '\0') 68625808Seric *p++ = '\0'; 68725808Seric 68825808Seric /* enter the word in the symbol table */ 68966101Seric setclass(class, q); 69025808Seric } 6914432Seric } 6924432Seric 69354973Seric (void) fclose(f); 6944432Seric } 6954432Seric /* 6964096Seric ** MAKEMAILER -- define a new mailer. 6974096Seric ** 6984096Seric ** Parameters: 69910327Seric ** line -- description of mailer. This is in labeled 70010327Seric ** fields. The fields are: 70167998Seric ** A -- the argv for this mailer 70267998Seric ** C -- the character set for MIME conversions 70367998Seric ** D -- the directory to run in 70467998Seric ** E -- the eol string 70567998Seric ** F -- the flags associated with the mailer 70667998Seric ** L -- the maximum line length 70767998Seric ** M -- the maximum message size 70810327Seric ** P -- the path to the mailer 70967998Seric ** R -- the recipient rewriting set 71010327Seric ** S -- the sender rewriting set 71167998Seric ** T -- the mailer type (for DSNs) 71267998Seric ** U -- the uid to run as 71310327Seric ** The first word is the canonical name of the mailer. 7144096Seric ** 7154096Seric ** Returns: 7164096Seric ** none. 7174096Seric ** 7184096Seric ** Side Effects: 7194096Seric ** enters the mailer into the mailer table. 7204096Seric */ 7213308Seric 72221066Seric makemailer(line) 7234096Seric char *line; 7244096Seric { 7254096Seric register char *p; 7268067Seric register struct mailer *m; 7278067Seric register STAB *s; 7288067Seric int i; 72910327Seric char fcode; 73058020Seric auto char *endp; 7314096Seric extern int NextMailer; 73210327Seric extern char **makeargv(); 73310327Seric extern char *munchstring(); 73410701Seric extern long atol(); 7354096Seric 73610327Seric /* allocate a mailer and set up defaults */ 73710327Seric m = (struct mailer *) xalloc(sizeof *m); 73810327Seric bzero((char *) m, sizeof *m); 73910327Seric m->m_eol = "\n"; 74067604Seric m->m_uid = m->m_gid = 0; 74110327Seric 74210327Seric /* collect the mailer name */ 74358050Seric for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++) 74410327Seric continue; 74510327Seric if (*p != '\0') 74610327Seric *p++ = '\0'; 74710327Seric m->m_name = newstr(line); 74810327Seric 74910327Seric /* now scan through and assign info from the fields */ 75010327Seric while (*p != '\0') 75110327Seric { 75258333Seric auto char *delimptr; 75358333Seric 75458050Seric while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p)))) 75510327Seric p++; 75610327Seric 75710327Seric /* p now points to field code */ 75810327Seric fcode = *p; 75910327Seric while (*p != '\0' && *p != '=' && *p != ',') 76010327Seric p++; 76110327Seric if (*p++ != '=') 76210327Seric { 76352637Seric syserr("mailer %s: `=' expected", m->m_name); 76410327Seric return; 76510327Seric } 76658050Seric while (isascii(*p) && isspace(*p)) 76710327Seric p++; 76810327Seric 76910327Seric /* p now points to the field body */ 77058333Seric p = munchstring(p, &delimptr); 77110327Seric 77210327Seric /* install the field into the mailer struct */ 77310327Seric switch (fcode) 77410327Seric { 77510327Seric case 'P': /* pathname */ 77610327Seric m->m_mailer = newstr(p); 77710327Seric break; 77810327Seric 77910327Seric case 'F': /* flags */ 78010687Seric for (; *p != '\0'; p++) 78158050Seric if (!(isascii(*p) && isspace(*p))) 78252637Seric setbitn(*p, m->m_flags); 78310327Seric break; 78410327Seric 78510327Seric case 'S': /* sender rewriting ruleset */ 78610327Seric case 'R': /* recipient rewriting ruleset */ 78758020Seric i = strtol(p, &endp, 10); 78810327Seric if (i < 0 || i >= MAXRWSETS) 78910327Seric { 79010327Seric syserr("invalid rewrite set, %d max", MAXRWSETS); 79110327Seric return; 79210327Seric } 79310327Seric if (fcode == 'S') 79458020Seric m->m_sh_rwset = m->m_se_rwset = i; 79510327Seric else 79658020Seric m->m_rh_rwset = m->m_re_rwset = i; 79758020Seric 79858020Seric p = endp; 79959985Seric if (*p++ == '/') 80058020Seric { 80158020Seric i = strtol(p, NULL, 10); 80258020Seric if (i < 0 || i >= MAXRWSETS) 80358020Seric { 80458020Seric syserr("invalid rewrite set, %d max", 80558020Seric MAXRWSETS); 80658020Seric return; 80758020Seric } 80858020Seric if (fcode == 'S') 80958020Seric m->m_sh_rwset = i; 81058020Seric else 81158020Seric m->m_rh_rwset = i; 81258020Seric } 81310327Seric break; 81410327Seric 81510327Seric case 'E': /* end of line string */ 81610327Seric m->m_eol = newstr(p); 81710327Seric break; 81810327Seric 81910327Seric case 'A': /* argument vector */ 82010327Seric m->m_argv = makeargv(p); 82110327Seric break; 82210701Seric 82310701Seric case 'M': /* maximum message size */ 82410701Seric m->m_maxsize = atol(p); 82510701Seric break; 82652106Seric 82752106Seric case 'L': /* maximum line length */ 82852106Seric m->m_linelimit = atoi(p); 82952106Seric break; 83058935Seric 83158935Seric case 'D': /* working directory */ 83258935Seric m->m_execdir = newstr(p); 83358935Seric break; 83467604Seric 83567896Seric case 'C': /* default charset */ 83667896Seric m->m_defcharset = newstr(p); 83767896Seric break; 83867896Seric 83967990Seric case 'T': /* MTS Type */ 84067990Seric m->m_mtstype = newstr(p); 84167990Seric break; 84267990Seric 84367604Seric case 'U': /* user id */ 84467604Seric if (isascii(*p) && !isdigit(*p)) 84567604Seric { 84667604Seric char *q = p; 84767604Seric struct passwd *pw; 84867604Seric 84967604Seric while (isascii(*p) && isalnum(*p)) 85067604Seric p++; 85167604Seric while (isascii(*p) && isspace(*p)) 85267604Seric *p++ = '\0'; 85367604Seric if (*p != '\0') 85467604Seric *p++ = '\0'; 85567604Seric pw = getpwnam(q); 85667604Seric if (pw == NULL) 85767604Seric syserr("readcf: mailer U= flag: unknown user %s", q); 85867604Seric else 85967604Seric { 86067604Seric m->m_uid = pw->pw_uid; 86167604Seric m->m_gid = pw->pw_gid; 86267604Seric } 86367604Seric } 86467604Seric else 86567604Seric { 86667604Seric auto char *q; 86767604Seric 86867604Seric m->m_uid = strtol(p, &q, 0); 86967604Seric p = q; 87067604Seric } 87167604Seric while (isascii(*p) && isspace(*p)) 87267604Seric p++; 87367604Seric if (*p == '\0') 87467604Seric break; 87567604Seric if (isascii(*p) && !isdigit(*p)) 87667604Seric { 87767604Seric char *q = p; 87867604Seric struct group *gr; 87967604Seric 88067604Seric while (isascii(*p) && isalnum(*p)) 88167604Seric p++; 88267604Seric *p++ = '\0'; 88367604Seric gr = getgrnam(q); 88467604Seric if (gr == NULL) 88567604Seric syserr("readcf: mailer U= flag: unknown group %s", q); 88667604Seric else 88767604Seric m->m_gid = gr->gr_gid; 88867604Seric } 88967604Seric else 89067604Seric { 89167604Seric m->m_gid = strtol(p, NULL, 0); 89267604Seric } 89367604Seric break; 89410327Seric } 89510327Seric 89658333Seric p = delimptr; 89710327Seric } 89810327Seric 89958321Seric /* do some rationality checking */ 90058321Seric if (m->m_argv == NULL) 90158321Seric { 90258321Seric syserr("M%s: A= argument required", m->m_name); 90358321Seric return; 90458321Seric } 90558321Seric if (m->m_mailer == NULL) 90658321Seric { 90758321Seric syserr("M%s: P= argument required", m->m_name); 90858321Seric return; 90958321Seric } 91058321Seric 9114096Seric if (NextMailer >= MAXMAILERS) 9124096Seric { 9139381Seric syserr("too many mailers defined (%d max)", MAXMAILERS); 9144096Seric return; 9154096Seric } 91657402Seric 91767998Seric /* do some heuristic cleanup for back compatibility */ 91867998Seric if (bitnset(M_LIMITS, m->m_flags)) 91967998Seric { 92067998Seric if (m->m_linelimit == 0) 92167998Seric m->m_linelimit = SMTPLINELIM; 92267998Seric if (ConfigLevel < 2) 92367998Seric setbitn(M_7BITS, m->m_flags); 92467998Seric } 92567998Seric 92667998Seric if (ConfigLevel < 6 && m->m_mtstype == NULL && 92767998Seric (strcmp(m->m_mailer, "[IPC]") == 0 || 92868092Seric strcmp(m->m_mailer, "[TCP]") == 0)) 92967998Seric m->m_mtstype = "Internet"; 93067998Seric 93167998Seric /* enter the mailer into the symbol table */ 93210327Seric s = stab(m->m_name, ST_MAILER, ST_ENTER); 93357402Seric if (s->s_mailer != NULL) 93457402Seric { 93557402Seric i = s->s_mailer->m_mno; 93657402Seric free(s->s_mailer); 93757402Seric } 93857402Seric else 93957402Seric { 94057402Seric i = NextMailer++; 94157402Seric } 94257402Seric Mailer[i] = s->s_mailer = m; 94357454Seric m->m_mno = i; 94410327Seric } 94510327Seric /* 94610327Seric ** MUNCHSTRING -- translate a string into internal form. 94710327Seric ** 94810327Seric ** Parameters: 94910327Seric ** p -- the string to munch. 95058333Seric ** delimptr -- if non-NULL, set to the pointer of the 95158333Seric ** field delimiter character. 95210327Seric ** 95310327Seric ** Returns: 95410327Seric ** the munched string. 95510327Seric */ 9564096Seric 95710327Seric char * 95858333Seric munchstring(p, delimptr) 95910327Seric register char *p; 96058333Seric char **delimptr; 96110327Seric { 96210327Seric register char *q; 96310327Seric bool backslash = FALSE; 96410327Seric bool quotemode = FALSE; 96510327Seric static char buf[MAXLINE]; 9664096Seric 96710327Seric for (q = buf; *p != '\0'; p++) 9684096Seric { 96910327Seric if (backslash) 97010327Seric { 97110327Seric /* everything is roughly literal */ 97210357Seric backslash = FALSE; 97310327Seric switch (*p) 97410327Seric { 97510327Seric case 'r': /* carriage return */ 97610327Seric *q++ = '\r'; 97710327Seric continue; 97810327Seric 97910327Seric case 'n': /* newline */ 98010327Seric *q++ = '\n'; 98110327Seric continue; 98210327Seric 98310327Seric case 'f': /* form feed */ 98410327Seric *q++ = '\f'; 98510327Seric continue; 98610327Seric 98710327Seric case 'b': /* backspace */ 98810327Seric *q++ = '\b'; 98910327Seric continue; 99010327Seric } 99110327Seric *q++ = *p; 99210327Seric } 99310327Seric else 99410327Seric { 99510327Seric if (*p == '\\') 99610327Seric backslash = TRUE; 99710327Seric else if (*p == '"') 99810327Seric quotemode = !quotemode; 99910327Seric else if (quotemode || *p != ',') 100010327Seric *q++ = *p; 100110327Seric else 100210327Seric break; 100310327Seric } 10044096Seric } 10054096Seric 100658333Seric if (delimptr != NULL) 100758333Seric *delimptr = p; 100810327Seric *q++ = '\0'; 100910327Seric return (buf); 101010327Seric } 101110327Seric /* 101210327Seric ** MAKEARGV -- break up a string into words 101310327Seric ** 101410327Seric ** Parameters: 101510327Seric ** p -- the string to break up. 101610327Seric ** 101710327Seric ** Returns: 101810327Seric ** a char **argv (dynamically allocated) 101910327Seric ** 102010327Seric ** Side Effects: 102110327Seric ** munges p. 102210327Seric */ 10234096Seric 102410327Seric char ** 102510327Seric makeargv(p) 102610327Seric register char *p; 102710327Seric { 102810327Seric char *q; 102910327Seric int i; 103010327Seric char **avp; 103110327Seric char *argv[MAXPV + 1]; 103210327Seric 103310327Seric /* take apart the words */ 103410327Seric i = 0; 103510327Seric while (*p != '\0' && i < MAXPV) 10364096Seric { 103710327Seric q = p; 103858050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 103910327Seric p++; 104058050Seric while (isascii(*p) && isspace(*p)) 104110327Seric *p++ = '\0'; 104210327Seric argv[i++] = newstr(q); 10434096Seric } 104410327Seric argv[i++] = NULL; 10454096Seric 104610327Seric /* now make a copy of the argv */ 104710327Seric avp = (char **) xalloc(sizeof *avp * i); 104816893Seric bcopy((char *) argv, (char *) avp, sizeof *avp * i); 104910327Seric 105010327Seric return (avp); 10513308Seric } 10523308Seric /* 10533308Seric ** PRINTRULES -- print rewrite rules (for debugging) 10543308Seric ** 10553308Seric ** Parameters: 10563308Seric ** none. 10573308Seric ** 10583308Seric ** Returns: 10593308Seric ** none. 10603308Seric ** 10613308Seric ** Side Effects: 10623308Seric ** prints rewrite rules. 10633308Seric */ 10643308Seric 10653308Seric printrules() 10663308Seric { 10673308Seric register struct rewrite *rwp; 10684072Seric register int ruleset; 10693308Seric 10704072Seric for (ruleset = 0; ruleset < 10; ruleset++) 10713308Seric { 10724072Seric if (RewriteRules[ruleset] == NULL) 10734072Seric continue; 10748067Seric printf("\n----Rule Set %d:", ruleset); 10753308Seric 10764072Seric for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 10773308Seric { 10788067Seric printf("\nLHS:"); 10798067Seric printav(rwp->r_lhs); 10808067Seric printf("RHS:"); 10818067Seric printav(rwp->r_rhs); 10823308Seric } 10833308Seric } 10843308Seric } 108567994Seric /* 108667994Seric ** PRINTMAILER -- print mailer structure (for debugging) 108767994Seric ** 108867994Seric ** Parameters: 108967994Seric ** m -- the mailer to print 109067994Seric ** 109167994Seric ** Returns: 109267994Seric ** none. 109367994Seric */ 10944319Seric 109567994Seric printmailer(m) 109667994Seric register MAILER *m; 109767994Seric { 109867994Seric int j; 109967994Seric 110067994Seric printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld U=%d:%d F=", 110167994Seric m->m_mno, m->m_name, 110267994Seric m->m_mailer, m->m_se_rwset, m->m_sh_rwset, 110367994Seric m->m_re_rwset, m->m_rh_rwset, m->m_maxsize, 110467994Seric m->m_uid, m->m_gid); 110567994Seric for (j = '\0'; j <= '\177'; j++) 110667994Seric if (bitnset(j, m->m_flags)) 110767994Seric (void) putchar(j); 110867994Seric printf(" L=%d E=", m->m_linelimit); 110967994Seric xputs(m->m_eol); 111067994Seric if (m->m_defcharset != NULL) 111167994Seric printf(" C=%s", m->m_defcharset); 111267994Seric if (m->m_mtstype != NULL) 111367994Seric printf(" T=%s", m->m_mtstype); 111467994Seric if (m->m_argv != NULL) 111567994Seric { 111667994Seric char **a = m->m_argv; 111767994Seric 111867994Seric printf(" A="); 111967994Seric while (*a != NULL) 112067994Seric { 112167994Seric if (a != m->m_argv) 112267994Seric printf(" "); 112367994Seric xputs(*a++); 112467994Seric } 112567994Seric } 112667994Seric printf("\n"); 112767994Seric } 11284096Seric /* 11298256Seric ** SETOPTION -- set global processing option 11308256Seric ** 11318256Seric ** Parameters: 11328256Seric ** opt -- option name. 11338256Seric ** val -- option value (as a text string). 113421755Seric ** safe -- set if this came from a configuration file. 113521755Seric ** Some options (if set from the command line) will 113621755Seric ** reset the user id to avoid security problems. 11378269Seric ** sticky -- if set, don't let other setoptions override 11388269Seric ** this value. 113958734Seric ** e -- the main envelope. 11408256Seric ** 11418256Seric ** Returns: 11428256Seric ** none. 11438256Seric ** 11448256Seric ** Side Effects: 11458256Seric ** Sets options as implied by the arguments. 11468256Seric */ 11478256Seric 114810687Seric static BITMAP StickyOpt; /* set if option is stuck */ 11498269Seric 115057207Seric 115166334Seric #if NAMED_BIND 115257207Seric 115357207Seric struct resolverflags 115457207Seric { 115557207Seric char *rf_name; /* name of the flag */ 115657207Seric long rf_bits; /* bits to set/clear */ 115757207Seric } ResolverFlags[] = 115857207Seric { 115957207Seric "debug", RES_DEBUG, 116057207Seric "aaonly", RES_AAONLY, 116157207Seric "usevc", RES_USEVC, 116257207Seric "primary", RES_PRIMARY, 116357207Seric "igntc", RES_IGNTC, 116457207Seric "recurse", RES_RECURSE, 116557207Seric "defnames", RES_DEFNAMES, 116657207Seric "stayopen", RES_STAYOPEN, 116757207Seric "dnsrch", RES_DNSRCH, 116865583Seric "true", 0, /* to avoid error on old syntax */ 116957207Seric NULL, 0 117057207Seric }; 117157207Seric 117257207Seric #endif 117357207Seric 117467614Seric struct optioninfo 117567614Seric { 117667614Seric char *o_name; /* long name of option */ 117767787Seric u_char o_code; /* short name of option */ 117867614Seric bool o_safe; /* safe for random people to use */ 117967614Seric } OptionTab[] = 118067614Seric { 118167707Seric "SevenBitInput", '7', TRUE, 118267707Seric "EightBitMode", '8', TRUE, 118367707Seric "AliasFile", 'A', FALSE, 118467707Seric "AliasWait", 'a', FALSE, 118567707Seric "BlankSub", 'B', FALSE, 118667707Seric "MinFreeBlocks", 'b', TRUE, 118767707Seric "CheckpointInterval", 'C', TRUE, 118867707Seric "HoldExpensive", 'c', FALSE, 118967707Seric "AutoRebuildAliases", 'D', FALSE, 119067707Seric "DeliveryMode", 'd', TRUE, 119167707Seric "ErrorHeader", 'E', FALSE, 119267707Seric "ErrorMode", 'e', TRUE, 119367707Seric "TempFileMode", 'F', FALSE, 119467707Seric "SaveFromLine", 'f', FALSE, 119567707Seric "MatchGECOS", 'G', FALSE, 119667707Seric "HelpFile", 'H', FALSE, 119767707Seric "MaxHopCount", 'h', FALSE, 119867707Seric "NameServerOptions", 'I', FALSE, 119967707Seric "IgnoreDots", 'i', TRUE, 120067707Seric "ForwardPath", 'J', FALSE, 120167707Seric "SendMimeErrors", 'j', TRUE, 120267707Seric "ConnectionCacheSize", 'k', FALSE, 120367707Seric "ConnectionCacheTimeout", 'K', FALSE, 120467707Seric "UseErrorsTo", 'l', FALSE, 120567707Seric "LogLevel", 'L', FALSE, 120667707Seric "MeToo", 'm', TRUE, 120767707Seric "CheckAliases", 'n', FALSE, 120867707Seric "OldStyleHeaders", 'o', TRUE, 120967707Seric "DaemonPortOptions", 'O', FALSE, 121067707Seric "PrivacyOptions", 'p', TRUE, 121167707Seric "PostmasterCopy", 'P', FALSE, 121267707Seric "QueueFactor", 'q', FALSE, 121367707Seric "QueueDirectory", 'Q', FALSE, 121467707Seric "DontPruneRoutes", 'R', FALSE, 121568109Seric "Timeout", 'r', TRUE, 121667707Seric "StatusFile", 'S', FALSE, 121767707Seric "SuperSafe", 's', TRUE, 121867707Seric "QueueTimeout", 'T', FALSE, 121967707Seric "TimeZoneSpec", 't', FALSE, 122067707Seric "UserDatabaseSpec", 'U', FALSE, 122167707Seric "DefaultUser", 'u', FALSE, 122267707Seric "FallbackMXhost", 'V', FALSE, 122367707Seric "Verbose", 'v', TRUE, 122467707Seric "TryNullMXList", 'w', TRUE, 122567707Seric "QueueLA", 'x', FALSE, 122667707Seric "RefuseLA", 'X', FALSE, 122767707Seric "RecipientFactor", 'y', FALSE, 122867707Seric "ForkQueueRuns", 'Y', FALSE, 122967707Seric "ClassFactor", 'z', FALSE, 123067707Seric "TimeFactor", 'Z', FALSE, 123167707Seric #define O_BSP 0x80 123267707Seric "BrokenSmtpPeers", O_BSP, TRUE, 123368107Seric #define O_QUEUESORTORD 0x81 123468105Seric "QueueSortOrder", O_QUEUESORTORD, TRUE, 123567707Seric #define O_MQA 0x83 123667707Seric "MinQueueAge", O_MQA, TRUE, 123767707Seric #define O_MHSA 0x84 123868132Seric /* 123967707Seric "MaxHostStatAge", O_MHSA, TRUE, 124068132Seric */ 124167813Seric #define O_DEFCHARSET 0x85 124267813Seric "DefaultCharSet", O_DEFCHARSET, TRUE, 124367848Seric #define O_SSFILE 0x86 124467848Seric "ServiceSwitchFile", O_SSFILE, FALSE, 124568034Seric #define O_DIALDELAY 0x87 124668034Seric "DialDelay", O_DIALDELAY, TRUE, 124767707Seric 124867707Seric NULL, '\0', FALSE, 124967614Seric }; 125067614Seric 125167614Seric 125267614Seric 125358734Seric setoption(opt, val, safe, sticky, e) 125467614Seric u_char opt; 12558256Seric char *val; 125621755Seric bool safe; 12578269Seric bool sticky; 125858734Seric register ENVELOPE *e; 12598256Seric { 126057207Seric register char *p; 126167614Seric register struct optioninfo *o; 126267903Seric char *subopt; 12638265Seric extern bool atobool(); 126412633Seric extern time_t convtime(); 126514879Seric extern int QueueLA; 126614879Seric extern int RefuseLA; 126764718Seric extern bool Warn_Q_option; 12688256Seric 126967736Seric errno = 0; 127067614Seric if (opt == ' ') 127167614Seric { 127267614Seric /* full word options */ 127367736Seric struct optioninfo *sel; 127467614Seric 127567614Seric p = strchr(val, '='); 127667614Seric if (p == NULL) 127767614Seric p = &val[strlen(val)]; 127867614Seric while (*--p == ' ') 127967614Seric continue; 128067614Seric while (*++p == ' ') 128167614Seric *p = '\0'; 128267731Seric if (p == val) 128367731Seric { 128467731Seric syserr("readcf: null option name"); 128567731Seric return; 128667731Seric } 128767614Seric if (*p == '=') 128867614Seric *p++ = '\0'; 128967614Seric while (*p == ' ') 129067614Seric p++; 129167903Seric subopt = strchr(val, '.'); 129267903Seric if (subopt != NULL) 129367903Seric *subopt++ = '\0'; 129467736Seric sel = NULL; 129567614Seric for (o = OptionTab; o->o_name != NULL; o++) 129667614Seric { 129767736Seric if (strncasecmp(o->o_name, val, strlen(val)) != 0) 129867736Seric continue; 129967736Seric if (strlen(o->o_name) == strlen(val)) 130067736Seric { 130167736Seric /* completely specified -- this must be it */ 130267736Seric sel = NULL; 130367614Seric break; 130467736Seric } 130567736Seric if (sel != NULL) 130667736Seric break; 130767736Seric sel = o; 130867614Seric } 130967736Seric if (sel != NULL && o->o_name == NULL) 131067736Seric o = sel; 131167736Seric else if (o->o_name == NULL) 131267787Seric { 131367614Seric syserr("readcf: unknown option name %s", val); 131467787Seric return; 131567787Seric } 131667736Seric else if (sel != NULL) 131767736Seric { 131867736Seric syserr("readcf: ambiguous option name %s (matches %s and %s)", 131967736Seric val, sel->o_name, o->o_name); 132067736Seric return; 132167736Seric } 132267736Seric if (strlen(val) != strlen(o->o_name)) 132367736Seric { 132467736Seric bool oldVerbose = Verbose; 132567736Seric 132667736Seric Verbose = TRUE; 132767736Seric message("Option %s used as abbreviation for %s", 132867736Seric val, o->o_name); 132967736Seric Verbose = oldVerbose; 133067736Seric } 133167614Seric opt = o->o_code; 133267614Seric val = p; 133367614Seric } 133467614Seric else 133567614Seric { 133667614Seric for (o = OptionTab; o->o_name != NULL; o++) 133767614Seric { 133867614Seric if (o->o_code == opt) 133967614Seric break; 134067614Seric } 134167903Seric subopt = NULL; 134267614Seric } 134367614Seric 13448256Seric if (tTd(37, 1)) 134567731Seric { 134667731Seric printf(isascii(opt) && isprint(opt) ? 134767903Seric "setoption %s (%c).%s=%s" : 134867903Seric "setoption %s (0x%x).%s=%s", 134967614Seric o->o_name == NULL ? "<unknown>" : o->o_name, 135067903Seric opt, 135167903Seric subopt == NULL ? "" : subopt, 135267903Seric val); 135367731Seric } 13548256Seric 13558256Seric /* 13568269Seric ** See if this option is preset for us. 13578256Seric */ 13588256Seric 135959731Seric if (!sticky && bitnset(opt, StickyOpt)) 13608269Seric { 13619341Seric if (tTd(37, 1)) 13629341Seric printf(" (ignored)\n"); 13638269Seric return; 13648269Seric } 13658269Seric 136621755Seric /* 136721755Seric ** Check to see if this option can be specified by this user. 136821755Seric */ 136921755Seric 137063787Seric if (!safe && RealUid == 0) 137121755Seric safe = TRUE; 137267614Seric if (!safe && !o->o_safe) 137321755Seric { 137439111Srick if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 137521755Seric { 137636582Sbostic if (tTd(37, 1)) 137736582Sbostic printf(" (unsafe)"); 137863787Seric if (RealUid != geteuid()) 137936582Sbostic { 138051210Seric if (tTd(37, 1)) 138151210Seric printf("(Resetting uid)"); 138263787Seric (void) setgid(RealGid); 138363787Seric (void) setuid(RealUid); 138436582Sbostic } 138521755Seric } 138621755Seric } 138751210Seric if (tTd(37, 1)) 138817985Seric printf("\n"); 13898269Seric 139067614Seric switch (opt & 0xff) 13918256Seric { 139259709Seric case '7': /* force seven-bit input */ 139367546Seric SevenBitInput = atobool(val); 139452106Seric break; 139552106Seric 139667546Seric case '8': /* handling of 8-bit input */ 139767546Seric switch (*val) 139867546Seric { 139967547Seric case 'r': /* reject 8-bit, don't convert MIME */ 140067546Seric MimeMode = 0; 140167546Seric break; 140267546Seric 140367547Seric case 'm': /* convert 8-bit, convert MIME */ 140467546Seric MimeMode = MM_CVTMIME|MM_MIME8BIT; 140567546Seric break; 140667546Seric 140767547Seric case 'j': /* "just send 8" */ 140867546Seric MimeMode = MM_PASS8BIT; 140967546Seric break; 141067546Seric 141167546Seric case 'p': /* pass 8 bit, convert MIME */ 141267546Seric MimeMode = MM_PASS8BIT|MM_CVTMIME; 141367546Seric break; 141467546Seric 141567546Seric case 's': /* strict adherence */ 141667546Seric MimeMode = MM_CVTMIME; 141767546Seric break; 141867546Seric 141967547Seric case 'a': /* encode 8 bit if available */ 142067546Seric MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 142167546Seric break; 142267546Seric 142367547Seric case 'c': /* convert 8 bit to MIME, never 7 bit */ 142467547Seric MimeMode = MM_MIME8BIT; 142567547Seric break; 142667547Seric 142767546Seric default: 142867546Seric syserr("Unknown 8-bit mode %c", *val); 142967546Seric exit(EX_USAGE); 143067546Seric } 143167546Seric break; 143267546Seric 14338256Seric case 'A': /* set default alias file */ 14349381Seric if (val[0] == '\0') 143559672Seric setalias("aliases"); 14369381Seric else 143759672Seric setalias(val); 14388256Seric break; 14398256Seric 144017474Seric case 'a': /* look N minutes for "@:@" in alias file */ 144117474Seric if (val[0] == '\0') 144264796Seric SafeAlias = 5 * 60; /* five minutes */ 144317474Seric else 144464796Seric SafeAlias = convtime(val, 'm'); 144517474Seric break; 144617474Seric 144716843Seric case 'B': /* substitution for blank character */ 144816843Seric SpaceSub = val[0]; 144916843Seric if (SpaceSub == '\0') 145016843Seric SpaceSub = ' '; 145116843Seric break; 145216843Seric 145359283Seric case 'b': /* min blocks free on queue fs/max msg size */ 145459283Seric p = strchr(val, '/'); 145559283Seric if (p != NULL) 145659283Seric { 145759283Seric *p++ = '\0'; 145859283Seric MaxMessageSize = atol(p); 145959283Seric } 146058082Seric MinBlocksFree = atol(val); 146158082Seric break; 146258082Seric 14639284Seric case 'c': /* don't connect to "expensive" mailers */ 14649381Seric NoConnect = atobool(val); 14659284Seric break; 14669284Seric 146751305Seric case 'C': /* checkpoint every N addresses */ 146851305Seric CheckpointInterval = atoi(val); 146924944Seric break; 147024944Seric 14719284Seric case 'd': /* delivery mode */ 14729284Seric switch (*val) 14738269Seric { 14749284Seric case '\0': 147558734Seric e->e_sendmode = SM_DELIVER; 14768269Seric break; 14778269Seric 147810755Seric case SM_QUEUE: /* queue only */ 147910755Seric #ifndef QUEUE 148010755Seric syserr("need QUEUE to set -odqueue"); 148156795Seric #endif /* QUEUE */ 148210755Seric /* fall through..... */ 148310755Seric 14849284Seric case SM_DELIVER: /* do everything */ 14859284Seric case SM_FORK: /* fork after verification */ 148658734Seric e->e_sendmode = *val; 14878269Seric break; 14888269Seric 14898269Seric default: 14909284Seric syserr("Unknown delivery mode %c", *val); 14918269Seric exit(EX_USAGE); 14928269Seric } 14938269Seric break; 14948269Seric 14959146Seric case 'D': /* rebuild alias database as needed */ 14969381Seric AutoRebuild = atobool(val); 14979146Seric break; 14989146Seric 149955372Seric case 'E': /* error message header/header file */ 150055379Seric if (*val != '\0') 150155379Seric ErrMsgFile = newstr(val); 150255372Seric break; 150355372Seric 15048269Seric case 'e': /* set error processing mode */ 15058269Seric switch (*val) 15068269Seric { 15079381Seric case EM_QUIET: /* be silent about it */ 15089381Seric case EM_MAIL: /* mail back */ 15099381Seric case EM_BERKNET: /* do berknet error processing */ 15109381Seric case EM_WRITE: /* write back (or mail) */ 15119381Seric case EM_PRINT: /* print errors normally (default) */ 151258734Seric e->e_errormode = *val; 15138269Seric break; 15148269Seric } 15158269Seric break; 15168269Seric 15179049Seric case 'F': /* file mode */ 151817975Seric FileMode = atooct(val) & 0777; 15199049Seric break; 15209049Seric 15218269Seric case 'f': /* save Unix-style From lines on front */ 15229381Seric SaveFrom = atobool(val); 15238269Seric break; 15248269Seric 152553735Seric case 'G': /* match recipients against GECOS field */ 152653735Seric MatchGecos = atobool(val); 152753735Seric break; 152853735Seric 15298256Seric case 'g': /* default gid */ 153067823Seric g_opt: 153164133Seric if (isascii(*val) && isdigit(*val)) 153264133Seric DefGid = atoi(val); 153364133Seric else 153464133Seric { 153564133Seric register struct group *gr; 153664133Seric 153764133Seric DefGid = -1; 153864133Seric gr = getgrnam(val); 153964133Seric if (gr == NULL) 154067823Seric syserr("readcf: option %c: unknown group %s", 154167823Seric opt, val); 154264133Seric else 154364133Seric DefGid = gr->gr_gid; 154464133Seric } 15458256Seric break; 15468256Seric 15478256Seric case 'H': /* help file */ 15489381Seric if (val[0] == '\0') 15498269Seric HelpFile = "sendmail.hf"; 15509381Seric else 15519381Seric HelpFile = newstr(val); 15528256Seric break; 15538256Seric 155451305Seric case 'h': /* maximum hop count */ 155551305Seric MaxHopCount = atoi(val); 155651305Seric break; 155751305Seric 155835651Seric case 'I': /* use internet domain name server */ 155966334Seric #if NAMED_BIND 156057207Seric for (p = val; *p != 0; ) 156157207Seric { 156257207Seric bool clearmode; 156357207Seric char *q; 156457207Seric struct resolverflags *rfp; 156557207Seric 156657207Seric while (*p == ' ') 156757207Seric p++; 156857207Seric if (*p == '\0') 156957207Seric break; 157057207Seric clearmode = FALSE; 157157207Seric if (*p == '-') 157257207Seric clearmode = TRUE; 157357207Seric else if (*p != '+') 157457207Seric p--; 157557207Seric p++; 157657207Seric q = p; 157758050Seric while (*p != '\0' && !(isascii(*p) && isspace(*p))) 157857207Seric p++; 157957207Seric if (*p != '\0') 158057207Seric *p++ = '\0'; 158157207Seric for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 158257207Seric { 158357207Seric if (strcasecmp(q, rfp->rf_name) == 0) 158457207Seric break; 158557207Seric } 158664923Seric if (rfp->rf_name == NULL) 158764923Seric syserr("readcf: I option value %s unrecognized", q); 158864923Seric else if (clearmode) 158957207Seric _res.options &= ~rfp->rf_bits; 159057207Seric else 159157207Seric _res.options |= rfp->rf_bits; 159257207Seric } 159357207Seric if (tTd(8, 2)) 159457207Seric printf("_res.options = %x\n", _res.options); 159557207Seric #else 159657207Seric usrerr("name server (I option) specified but BIND not compiled in"); 159757207Seric #endif 159835651Seric break; 159935651Seric 16008269Seric case 'i': /* ignore dot lines in message */ 16019381Seric IgnrDot = atobool(val); 16028269Seric break; 16038269Seric 160459730Seric case 'j': /* send errors in MIME (RFC 1341) format */ 160559730Seric SendMIMEErrors = atobool(val); 160659730Seric break; 160759730Seric 160857136Seric case 'J': /* .forward search path */ 160957136Seric ForwardPath = newstr(val); 161057136Seric break; 161157136Seric 161254967Seric case 'k': /* connection cache size */ 161354967Seric MaxMciCache = atoi(val); 161456215Seric if (MaxMciCache < 0) 161556215Seric MaxMciCache = 0; 161654967Seric break; 161754967Seric 161854967Seric case 'K': /* connection cache timeout */ 161958796Seric MciCacheTimeout = convtime(val, 'm'); 162054967Seric break; 162154967Seric 162261104Seric case 'l': /* use Errors-To: header */ 162361104Seric UseErrorsTo = atobool(val); 162461104Seric break; 162561104Seric 16268256Seric case 'L': /* log level */ 162764140Seric if (safe || LogLevel < atoi(val)) 162864140Seric LogLevel = atoi(val); 16298256Seric break; 16308256Seric 16318269Seric case 'M': /* define macro */ 16329381Seric define(val[0], newstr(&val[1]), CurEnv); 163316878Seric sticky = FALSE; 16348269Seric break; 16358269Seric 16368269Seric case 'm': /* send to me too */ 16379381Seric MeToo = atobool(val); 16388269Seric break; 16398269Seric 164025820Seric case 'n': /* validate RHS in newaliases */ 164125820Seric CheckAliases = atobool(val); 164225820Seric break; 164325820Seric 164461104Seric /* 'N' available -- was "net name" */ 164561104Seric 164658851Seric case 'O': /* daemon options */ 164758851Seric setdaemonoptions(val); 164858851Seric break; 164958851Seric 16508269Seric case 'o': /* assume old style headers */ 16519381Seric if (atobool(val)) 16529341Seric CurEnv->e_flags |= EF_OLDSTYLE; 16539341Seric else 16549341Seric CurEnv->e_flags &= ~EF_OLDSTYLE; 16558269Seric break; 16568269Seric 165758082Seric case 'p': /* select privacy level */ 165858082Seric p = val; 165958082Seric for (;;) 166058082Seric { 166158082Seric register struct prival *pv; 166258082Seric extern struct prival PrivacyValues[]; 166358082Seric 166458082Seric while (isascii(*p) && (isspace(*p) || ispunct(*p))) 166558082Seric p++; 166658082Seric if (*p == '\0') 166758082Seric break; 166858082Seric val = p; 166958082Seric while (isascii(*p) && isalnum(*p)) 167058082Seric p++; 167158082Seric if (*p != '\0') 167258082Seric *p++ = '\0'; 167358082Seric 167458082Seric for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 167558082Seric { 167658082Seric if (strcasecmp(val, pv->pv_name) == 0) 167758082Seric break; 167858082Seric } 167958886Seric if (pv->pv_name == NULL) 168058886Seric syserr("readcf: Op line: %s unrecognized", val); 168158082Seric PrivacyFlags |= pv->pv_flag; 168258082Seric } 168358082Seric break; 168458082Seric 168524944Seric case 'P': /* postmaster copy address for returned mail */ 168624944Seric PostMasterCopy = newstr(val); 168724944Seric break; 168824944Seric 168924944Seric case 'q': /* slope of queue only function */ 169024944Seric QueueFactor = atoi(val); 169124944Seric break; 169224944Seric 16938256Seric case 'Q': /* queue directory */ 16949381Seric if (val[0] == '\0') 16958269Seric QueueDir = "mqueue"; 16969381Seric else 16979381Seric QueueDir = newstr(val); 169858789Seric if (RealUid != 0 && !safe) 169964718Seric Warn_Q_option = TRUE; 17008256Seric break; 17018256Seric 170258148Seric case 'R': /* don't prune routes */ 170358148Seric DontPruneRoutes = atobool(val); 170458148Seric break; 170558148Seric 17068256Seric case 'r': /* read timeout */ 170767903Seric if (subopt == NULL) 170867903Seric inittimeouts(val); 170967903Seric else 171067903Seric settimeout(subopt, val); 17118256Seric break; 17128256Seric 17138256Seric case 'S': /* status file */ 17149381Seric if (val[0] == '\0') 17158269Seric StatFile = "sendmail.st"; 17169381Seric else 17179381Seric StatFile = newstr(val); 17188256Seric break; 17198256Seric 17208265Seric case 's': /* be super safe, even if expensive */ 17219381Seric SuperSafe = atobool(val); 17228256Seric break; 17238256Seric 17248256Seric case 'T': /* queue timeout */ 172558737Seric p = strchr(val, '/'); 172658737Seric if (p != NULL) 172758737Seric { 172858737Seric *p++ = '\0'; 172967903Seric settimeout("queuewarn", p); 173058737Seric } 173167903Seric settimeout("queuereturn", val); 173254967Seric break; 17338256Seric 17348265Seric case 't': /* time zone name */ 173552106Seric TimeZoneSpec = newstr(val); 17368265Seric break; 17378265Seric 173850556Seric case 'U': /* location of user database */ 173951360Seric UdbSpec = newstr(val); 174050556Seric break; 174150556Seric 17428256Seric case 'u': /* set default uid */ 174367823Seric for (p = val; *p != '\0'; p++) 174467823Seric { 174567823Seric if (*p == '.' || *p == '/' || *p == ':') 174667823Seric { 174767823Seric *p++ = '\0'; 174867823Seric break; 174967823Seric } 175067823Seric } 175164133Seric if (isascii(*val) && isdigit(*val)) 175264133Seric DefUid = atoi(val); 175364133Seric else 175464133Seric { 175564133Seric register struct passwd *pw; 175664133Seric 175764133Seric DefUid = -1; 175864133Seric pw = getpwnam(val); 175964133Seric if (pw == NULL) 176064133Seric syserr("readcf: option u: unknown user %s", val); 176164133Seric else 176267823Seric { 176364133Seric DefUid = pw->pw_uid; 176467823Seric DefGid = pw->pw_gid; 176567823Seric } 176664133Seric } 176740973Sbostic setdefuser(); 17688256Seric 176967823Seric /* handle the group if it is there */ 177067823Seric if (*p == '\0') 177167823Seric break; 177267823Seric val = p; 177367823Seric goto g_opt; 177467823Seric 177558851Seric case 'V': /* fallback MX host */ 177658851Seric FallBackMX = newstr(val); 177758851Seric break; 177858851Seric 17798269Seric case 'v': /* run in verbose mode */ 17809381Seric Verbose = atobool(val); 17818256Seric break; 17828256Seric 178363837Seric case 'w': /* if we are best MX, try host directly */ 178463837Seric TryNullMXList = atobool(val); 178563837Seric break; 178661104Seric 178761104Seric /* 'W' available -- was wizard password */ 178861104Seric 178914879Seric case 'x': /* load avg at which to auto-queue msgs */ 179014879Seric QueueLA = atoi(val); 179114879Seric break; 179214879Seric 179314879Seric case 'X': /* load avg at which to auto-reject connections */ 179414879Seric RefuseLA = atoi(val); 179514879Seric break; 179614879Seric 179724981Seric case 'y': /* work recipient factor */ 179824981Seric WkRecipFact = atoi(val); 179924981Seric break; 180024981Seric 180124981Seric case 'Y': /* fork jobs during queue runs */ 180224952Seric ForkQueueRuns = atobool(val); 180324952Seric break; 180424952Seric 180524981Seric case 'z': /* work message class factor */ 180624981Seric WkClassFact = atoi(val); 180724981Seric break; 180824981Seric 180924981Seric case 'Z': /* work time factor */ 181024981Seric WkTimeFact = atoi(val); 181124981Seric break; 181224981Seric 181367614Seric case O_BSP: /* SMTP Peers can't handle 2-line greeting */ 181467614Seric BrokenSmtpPeers = atobool(val); 181567614Seric break; 181667614Seric 181768105Seric case O_QUEUESORTORD: /* queue sorting order */ 181868105Seric switch (*val) 181968105Seric { 182068105Seric case 'h': /* Host first */ 182168105Seric case 'H': 182268105Seric QueueSortOrder = QS_BYHOST; 182368105Seric break; 182468105Seric 182568105Seric case 'p': /* Priority order */ 182668105Seric case 'P': 182768105Seric QueueSortOrder = QS_BYPRIORITY; 182868105Seric break; 182968105Seric 183068105Seric default: 183168105Seric syserr("Invalid queue sort order \"%s\"", val); 183268105Seric } 183367614Seric break; 183467614Seric 183567707Seric case O_MQA: /* minimum queue age between deliveries */ 183667707Seric MinQueueAge = convtime(val, 'm'); 183767707Seric break; 183867707Seric 183967707Seric case O_MHSA: /* maximum age of cached host status */ 184067707Seric MaxHostStatAge = convtime(val, 'm'); 184167707Seric break; 184267707Seric 184367813Seric case O_DEFCHARSET: /* default character set for mimefying */ 184467814Seric DefaultCharSet = newstr(val); 184567813Seric break; 184667813Seric 184767848Seric case O_SSFILE: /* service switch file */ 184867848Seric ServiceSwitchFile = newstr(val); 184967848Seric break; 185067848Seric 185168034Seric case O_DIALDELAY: /* delay for dial-on-demand operation */ 185268034Seric DialDelay = convtime(val, 's'); 185368034Seric break; 185468034Seric 18558256Seric default: 185668132Seric if (tTd(37, 1)) 185768132Seric { 185868132Seric if (isascii(opt) && isprint(opt)) 185968132Seric printf("Warning: option %c unknown\n", opt); 186068132Seric else 186168132Seric printf("Warning: option 0x%x unknown\n", opt); 186268132Seric } 18638256Seric break; 18648256Seric } 186516878Seric if (sticky) 186616878Seric setbitn(opt, StickyOpt); 18679188Seric return; 18688256Seric } 186910687Seric /* 187010687Seric ** SETCLASS -- set a word into a class 187110687Seric ** 187210687Seric ** Parameters: 187310687Seric ** class -- the class to put the word in. 187410687Seric ** word -- the word to enter 187510687Seric ** 187610687Seric ** Returns: 187710687Seric ** none. 187810687Seric ** 187910687Seric ** Side Effects: 188010687Seric ** puts the word into the symbol table. 188110687Seric */ 188210687Seric 188310687Seric setclass(class, word) 188410687Seric int class; 188510687Seric char *word; 188610687Seric { 188710687Seric register STAB *s; 188810687Seric 188957943Seric if (tTd(37, 8)) 189064326Seric printf("setclass(%c, %s)\n", class, word); 189110687Seric s = stab(word, ST_CLASS, ST_ENTER); 189210687Seric setbitn(class, s->s_class); 189310687Seric } 189453654Seric /* 189553654Seric ** MAKEMAPENTRY -- create a map entry 189653654Seric ** 189753654Seric ** Parameters: 189853654Seric ** line -- the config file line 189953654Seric ** 190053654Seric ** Returns: 190153654Seric ** TRUE if it successfully entered the map entry. 190253654Seric ** FALSE otherwise (usually syntax error). 190353654Seric ** 190453654Seric ** Side Effects: 190553654Seric ** Enters the map into the dictionary. 190653654Seric */ 190753654Seric 190853654Seric void 190953654Seric makemapentry(line) 191053654Seric char *line; 191153654Seric { 191253654Seric register char *p; 191353654Seric char *mapname; 191453654Seric char *classname; 191564078Seric register STAB *s; 191653654Seric STAB *class; 191753654Seric 191858050Seric for (p = line; isascii(*p) && isspace(*p); p++) 191953654Seric continue; 192058050Seric if (!(isascii(*p) && isalnum(*p))) 192153654Seric { 192253654Seric syserr("readcf: config K line: no map name"); 192353654Seric return; 192453654Seric } 192553654Seric 192653654Seric mapname = p; 192767848Seric while ((isascii(*++p) && isalnum(*p)) || *p == '.') 192853654Seric continue; 192953654Seric if (*p != '\0') 193053654Seric *p++ = '\0'; 193158050Seric while (isascii(*p) && isspace(*p)) 193253654Seric p++; 193358050Seric if (!(isascii(*p) && isalnum(*p))) 193453654Seric { 193553654Seric syserr("readcf: config K line, map %s: no map class", mapname); 193653654Seric return; 193753654Seric } 193853654Seric classname = p; 193958050Seric while (isascii(*++p) && isalnum(*p)) 194053654Seric continue; 194153654Seric if (*p != '\0') 194253654Seric *p++ = '\0'; 194358050Seric while (isascii(*p) && isspace(*p)) 194453654Seric p++; 194553654Seric 194653654Seric /* look up the class */ 194753654Seric class = stab(classname, ST_MAPCLASS, ST_FIND); 194853654Seric if (class == NULL) 194953654Seric { 195053654Seric syserr("readcf: map %s: class %s not available", mapname, classname); 195153654Seric return; 195253654Seric } 195353654Seric 195453654Seric /* enter the map */ 195564078Seric s = stab(mapname, ST_MAP, ST_ENTER); 195664078Seric s->s_map.map_class = &class->s_mapclass; 195764078Seric s->s_map.map_mname = newstr(mapname); 195853654Seric 195964078Seric if (class->s_mapclass.map_parse(&s->s_map, p)) 196064078Seric s->s_map.map_mflags |= MF_VALID; 196164078Seric 196264078Seric if (tTd(37, 5)) 196364078Seric { 196464078Seric printf("map %s, class %s, flags %x, file %s,\n", 196564078Seric s->s_map.map_mname, s->s_map.map_class->map_cname, 196664078Seric s->s_map.map_mflags, 196764078Seric s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 196864078Seric printf("\tapp %s, domain %s, rebuild %s\n", 196964078Seric s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 197064078Seric s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 197164078Seric s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 197264078Seric } 197353654Seric } 197458112Seric /* 197567903Seric ** INITTIMEOUTS -- parse and set timeout values 197658112Seric ** 197758112Seric ** Parameters: 197858112Seric ** val -- a pointer to the values. If NULL, do initial 197958112Seric ** settings. 198058112Seric ** 198158112Seric ** Returns: 198258112Seric ** none. 198358112Seric ** 198458112Seric ** Side Effects: 198558112Seric ** Initializes the TimeOuts structure 198658112Seric */ 198758112Seric 198864255Seric #define SECONDS 198958112Seric #define MINUTES * 60 199058112Seric #define HOUR * 3600 199158112Seric 199267903Seric inittimeouts(val) 199358112Seric register char *val; 199458112Seric { 199558112Seric register char *p; 199658671Seric extern time_t convtime(); 199758112Seric 199858112Seric if (val == NULL) 199958112Seric { 200058112Seric TimeOuts.to_initial = (time_t) 5 MINUTES; 200158112Seric TimeOuts.to_helo = (time_t) 5 MINUTES; 200258112Seric TimeOuts.to_mail = (time_t) 10 MINUTES; 200358112Seric TimeOuts.to_rcpt = (time_t) 1 HOUR; 200458112Seric TimeOuts.to_datainit = (time_t) 5 MINUTES; 200558112Seric TimeOuts.to_datablock = (time_t) 1 HOUR; 200658112Seric TimeOuts.to_datafinal = (time_t) 1 HOUR; 200758112Seric TimeOuts.to_rset = (time_t) 5 MINUTES; 200858112Seric TimeOuts.to_quit = (time_t) 2 MINUTES; 200958112Seric TimeOuts.to_nextcommand = (time_t) 1 HOUR; 201058112Seric TimeOuts.to_miscshort = (time_t) 2 MINUTES; 201168147Seric #if IDENTPROTO 201264255Seric TimeOuts.to_ident = (time_t) 30 SECONDS; 201368147Seric #else 201468147Seric TimeOuts.to_ident = (time_t) 0 SECONDS; 201568147Seric #endif 201667711Seric TimeOuts.to_fileopen = (time_t) 60 SECONDS; 201758112Seric return; 201858112Seric } 201958112Seric 202058112Seric for (;; val = p) 202158112Seric { 202258112Seric while (isascii(*val) && isspace(*val)) 202358112Seric val++; 202458112Seric if (*val == '\0') 202558112Seric break; 202658112Seric for (p = val; *p != '\0' && *p != ','; p++) 202758112Seric continue; 202858112Seric if (*p != '\0') 202958112Seric *p++ = '\0'; 203058112Seric 203158112Seric if (isascii(*val) && isdigit(*val)) 203258112Seric { 203358112Seric /* old syntax -- set everything */ 203458796Seric TimeOuts.to_mail = convtime(val, 'm'); 203558112Seric TimeOuts.to_rcpt = TimeOuts.to_mail; 203658112Seric TimeOuts.to_datainit = TimeOuts.to_mail; 203758112Seric TimeOuts.to_datablock = TimeOuts.to_mail; 203858112Seric TimeOuts.to_datafinal = TimeOuts.to_mail; 203958112Seric TimeOuts.to_nextcommand = TimeOuts.to_mail; 204058112Seric continue; 204158112Seric } 204258112Seric else 204358112Seric { 204467711Seric register char *q = strchr(val, ':'); 204558112Seric 204667711Seric if (q == NULL && (q = strchr(val, '=')) == NULL) 204758112Seric { 204858112Seric /* syntax error */ 204958112Seric continue; 205058112Seric } 205158112Seric *q++ = '\0'; 205267903Seric settimeout(val, q); 205367903Seric } 205467903Seric } 205567903Seric } 205667903Seric /* 205767903Seric ** SETTIMEOUT -- set an individual timeout 205867903Seric ** 205967903Seric ** Parameters: 206067903Seric ** name -- the name of the timeout. 206167903Seric ** val -- the value of the timeout. 206267903Seric ** 206367903Seric ** Returns: 206467903Seric ** none. 206567903Seric */ 206658112Seric 206767903Seric settimeout(name, val) 206867903Seric char *name; 206967903Seric char *val; 207067903Seric { 207167903Seric register char *p; 207267903Seric time_t to; 207367903Seric extern time_t convtime(); 207467903Seric 207567903Seric to = convtime(val, 'm'); 207667903Seric p = strchr(name, '.'); 207767903Seric if (p != NULL) 207867903Seric *p++ = '\0'; 207967903Seric 208067903Seric if (strcasecmp(name, "initial") == 0) 208167903Seric TimeOuts.to_initial = to; 208267903Seric else if (strcasecmp(name, "mail") == 0) 208367903Seric TimeOuts.to_mail = to; 208467903Seric else if (strcasecmp(name, "rcpt") == 0) 208567903Seric TimeOuts.to_rcpt = to; 208667903Seric else if (strcasecmp(name, "datainit") == 0) 208767903Seric TimeOuts.to_datainit = to; 208867903Seric else if (strcasecmp(name, "datablock") == 0) 208967903Seric TimeOuts.to_datablock = to; 209067903Seric else if (strcasecmp(name, "datafinal") == 0) 209167903Seric TimeOuts.to_datafinal = to; 209267903Seric else if (strcasecmp(name, "command") == 0) 209367903Seric TimeOuts.to_nextcommand = to; 209467903Seric else if (strcasecmp(name, "rset") == 0) 209567903Seric TimeOuts.to_rset = to; 209667903Seric else if (strcasecmp(name, "helo") == 0) 209767903Seric TimeOuts.to_helo = to; 209867903Seric else if (strcasecmp(name, "quit") == 0) 209967903Seric TimeOuts.to_quit = to; 210067903Seric else if (strcasecmp(name, "misc") == 0) 210167903Seric TimeOuts.to_miscshort = to; 210267903Seric else if (strcasecmp(name, "ident") == 0) 210367903Seric TimeOuts.to_ident = to; 210467903Seric else if (strcasecmp(name, "fileopen") == 0) 210567903Seric TimeOuts.to_fileopen = to; 210667903Seric else if (strcasecmp(name, "queuewarn") == 0) 210767903Seric { 210867903Seric to = convtime(val, 'h'); 210967946Seric if (p == NULL || strcmp(p, "*") == 0) 211067903Seric { 211167903Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 211267903Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 211367903Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 211458112Seric } 211567903Seric else if (strcasecmp(p, "normal") == 0) 211667903Seric TimeOuts.to_q_warning[TOC_NORMAL] = to; 211767903Seric else if (strcasecmp(p, "urgent") == 0) 211867903Seric TimeOuts.to_q_warning[TOC_URGENT] = to; 211967903Seric else if (strcasecmp(p, "non-urgent") == 0) 212067903Seric TimeOuts.to_q_warning[TOC_NONURGENT] = to; 212167903Seric else 212267903Seric syserr("settimeout: invalid queuewarn subtimeout %s", p); 212358112Seric } 212467903Seric else if (strcasecmp(name, "queuereturn") == 0) 212567903Seric { 212667903Seric to = convtime(val, 'd'); 212767903Seric if (p == NULL || strcmp(p, "*") == 0) 212867903Seric { 212967903Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 213067903Seric TimeOuts.to_q_return[TOC_URGENT] = to; 213167903Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 213267903Seric } 213367903Seric else if (strcasecmp(p, "normal") == 0) 213467903Seric TimeOuts.to_q_return[TOC_NORMAL] = to; 213567903Seric else if (strcasecmp(p, "urgent") == 0) 213667903Seric TimeOuts.to_q_return[TOC_URGENT] = to; 213767903Seric else if (strcasecmp(p, "non-urgent") == 0) 213867903Seric TimeOuts.to_q_return[TOC_NONURGENT] = to; 213967903Seric else 214067903Seric syserr("settimeout: invalid queuereturn subtimeout %s", p); 214167903Seric } 214267903Seric else 214367903Seric syserr("settimeout: invalid timeout %s", name); 214458112Seric } 2145