readcf.c revision 82017
138032Speter/* 273188Sgshapiro * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. 364562Sgshapiro * All rights reserved. 438032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 538032Speter * Copyright (c) 1988, 1993 638032Speter * The Regents of the University of California. All rights reserved. 738032Speter * 838032Speter * By using this file, you agree to the terms and conditions set 938032Speter * forth in the LICENSE file which can be found at the top level of 1038032Speter * the sendmail distribution. 1138032Speter * 1238032Speter */ 1338032Speter 1438032Speter#ifndef lint 1582017Sgshapirostatic char id[] = "@(#)$Id: readcf.c,v 8.382.4.43 2001/08/14 23:08:13 ca Exp $"; 1664562Sgshapiro#endif /* ! lint */ 1738032Speter 1864562Sgshapiro#include <sendmail.h> 1938032Speter 2064562Sgshapiro 2164562Sgshapiro#if NETINET || NETINET6 2264562Sgshapiro# include <arpa/inet.h> 2364562Sgshapiro#endif /* NETINET || NETINET6 */ 2464562Sgshapiro 2564562Sgshapiro#define SECONDS 2664562Sgshapiro#define MINUTES * 60 2764562Sgshapiro#define HOUR * 3600 2864562Sgshapiro#define HOURS HOUR 2964562Sgshapiro 3064562Sgshapirostatic void fileclass __P((int, char *, char *, bool, bool)); 3164562Sgshapirostatic char **makeargv __P((char *)); 3264562Sgshapirostatic void settimeout __P((char *, char *, bool)); 3364562Sgshapirostatic void toomany __P((int, int)); 3464562Sgshapiro 3538032Speter/* 3638032Speter** READCF -- read configuration file. 3738032Speter** 3838032Speter** This routine reads the configuration file and builds the internal 3938032Speter** form. 4038032Speter** 4138032Speter** The file is formatted as a sequence of lines, each taken 4238032Speter** atomically. The first character of each line describes how 4338032Speter** the line is to be interpreted. The lines are: 4438032Speter** Dxval Define macro x to have value val. 4538032Speter** Cxword Put word into class x. 4638032Speter** Fxfile [fmt] Read file for lines to put into 4738032Speter** class x. Use scanf string 'fmt' 4838032Speter** or "%s" if not present. Fmt should 4938032Speter** only produce one string-valued result. 5038032Speter** Hname: value Define header with field-name 'name' 5138032Speter** and value as specified; this will be 5238032Speter** macro expanded immediately before 5338032Speter** use. 5438032Speter** Sn Use rewriting set n. 5538032Speter** Rlhs rhs Rewrite addresses that match lhs to 5638032Speter** be rhs. 5738032Speter** Mn arg=val... Define mailer. n is the internal name. 5838032Speter** Args specify mailer parameters. 5938032Speter** Oxvalue Set option x to value. 6038032Speter** Pname=value Set precedence name to value. 6138032Speter** Vversioncode[/vendorcode] 6238032Speter** Version level/vendor name of 6338032Speter** configuration syntax. 6438032Speter** Kmapname mapclass arguments.... 6538032Speter** Define keyed lookup of a given class. 6638032Speter** Arguments are class dependent. 6738032Speter** Eenvar=value Set the environment value to the given value. 6838032Speter** 6938032Speter** Parameters: 7038032Speter** cfname -- configuration file name. 7138032Speter** safe -- TRUE if this is the system config file; 7238032Speter** FALSE otherwise. 7338032Speter** e -- the main envelope. 7438032Speter** 7538032Speter** Returns: 7638032Speter** none. 7738032Speter** 7838032Speter** Side Effects: 7938032Speter** Builds several internal tables. 8038032Speter*/ 8138032Speter 8238032Spetervoid 8338032Speterreadcf(cfname, safe, e) 8438032Speter char *cfname; 8538032Speter bool safe; 8638032Speter register ENVELOPE *e; 8738032Speter{ 8838032Speter FILE *cf; 8964562Sgshapiro int ruleset = -1; 9038032Speter char *q; 9138032Speter struct rewrite *rwp = NULL; 9238032Speter char *bp; 9338032Speter auto char *ep; 9438032Speter int nfuzzy; 9538032Speter char *file; 9638032Speter bool optional; 9738032Speter int mid; 9838032Speter register char *p; 9964562Sgshapiro long sff = SFF_OPENASROOT; 10038032Speter struct stat statb; 10138032Speter char buf[MAXLINE]; 10238032Speter char exbuf[MAXLINE]; 10338032Speter char pvpbuf[MAXLINE + MAXATOM]; 10438032Speter static char *null_list[1] = { NULL }; 10564562Sgshapiro extern u_char TokTypeNoC[]; 10638032Speter 10738032Speter FileName = cfname; 10838032Speter LineNumber = 0; 10938032Speter 11038032Speter if (DontLockReadFiles) 11138032Speter sff |= SFF_NOLOCK; 11238032Speter cf = safefopen(cfname, O_RDONLY, 0444, sff); 11338032Speter if (cf == NULL) 11438032Speter { 11538032Speter syserr("cannot open"); 11642575Speter finis(FALSE, EX_OSFILE); 11738032Speter } 11838032Speter 11938032Speter if (fstat(fileno(cf), &statb) < 0) 12038032Speter { 12138032Speter syserr("cannot fstat"); 12242575Speter finis(FALSE, EX_OSFILE); 12338032Speter } 12438032Speter 12538032Speter if (!S_ISREG(statb.st_mode)) 12638032Speter { 12738032Speter syserr("not a plain file"); 12842575Speter finis(FALSE, EX_OSFILE); 12938032Speter } 13038032Speter 13138032Speter if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode)) 13238032Speter { 13338032Speter if (OpMode == MD_DAEMON || OpMode == MD_INITALIAS) 13438032Speter fprintf(stderr, "%s: WARNING: dangerous write permissions\n", 13538032Speter FileName); 13638032Speter if (LogLevel > 0) 13738032Speter sm_syslog(LOG_CRIT, NOQID, 13864562Sgshapiro "%s: WARNING: dangerous write permissions", 13964562Sgshapiro FileName); 14038032Speter } 14138032Speter 14238032Speter#ifdef XLA 14338032Speter xla_zero(); 14464562Sgshapiro#endif /* XLA */ 14538032Speter 14638032Speter while ((bp = fgetfolded(buf, sizeof buf, cf)) != NULL) 14738032Speter { 14838032Speter if (bp[0] == '#') 14938032Speter { 15038032Speter if (bp != buf) 15177349Sgshapiro sm_free(bp); 15238032Speter continue; 15338032Speter } 15438032Speter 15538032Speter /* do macro expansion mappings */ 15638032Speter translate_dollars(bp); 15738032Speter 15838032Speter /* interpret this line */ 15938032Speter errno = 0; 16038032Speter switch (bp[0]) 16138032Speter { 16238032Speter case '\0': 16338032Speter case '#': /* comment */ 16438032Speter break; 16538032Speter 16638032Speter case 'R': /* rewriting rule */ 16764562Sgshapiro if (ruleset < 0) 16864562Sgshapiro { 16964562Sgshapiro syserr("missing valid ruleset for \"%s\"", bp); 17064562Sgshapiro break; 17164562Sgshapiro } 17238032Speter for (p = &bp[1]; *p != '\0' && *p != '\t'; p++) 17338032Speter continue; 17438032Speter 17538032Speter if (*p == '\0') 17638032Speter { 17738032Speter syserr("invalid rewrite line \"%s\" (tab expected)", bp); 17838032Speter break; 17938032Speter } 18038032Speter 18138032Speter /* allocate space for the rule header */ 18238032Speter if (rwp == NULL) 18338032Speter { 18438032Speter RewriteRules[ruleset] = rwp = 18538032Speter (struct rewrite *) xalloc(sizeof *rwp); 18638032Speter } 18738032Speter else 18838032Speter { 18938032Speter rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp); 19038032Speter rwp = rwp->r_next; 19138032Speter } 19238032Speter rwp->r_next = NULL; 19338032Speter 19438032Speter /* expand and save the LHS */ 19538032Speter *p = '\0'; 19638032Speter expand(&bp[1], exbuf, sizeof exbuf, e); 19738032Speter rwp->r_lhs = prescan(exbuf, '\t', pvpbuf, 19864562Sgshapiro sizeof pvpbuf, NULL, 19964562Sgshapiro ConfigLevel >= 9 ? TokTypeNoC : NULL); 20038032Speter nfuzzy = 0; 20138032Speter if (rwp->r_lhs != NULL) 20238032Speter { 20338032Speter register char **ap; 20438032Speter 20538032Speter rwp->r_lhs = copyplist(rwp->r_lhs, TRUE); 20638032Speter 20738032Speter /* count the number of fuzzy matches in LHS */ 20838032Speter for (ap = rwp->r_lhs; *ap != NULL; ap++) 20938032Speter { 21038032Speter char *botch; 21138032Speter 21238032Speter botch = NULL; 21338032Speter switch (**ap & 0377) 21438032Speter { 21538032Speter case MATCHZANY: 21638032Speter case MATCHANY: 21738032Speter case MATCHONE: 21838032Speter case MATCHCLASS: 21938032Speter case MATCHNCLASS: 22038032Speter nfuzzy++; 22138032Speter break; 22238032Speter 22338032Speter case MATCHREPL: 22438032Speter botch = "$0-$9"; 22538032Speter break; 22638032Speter 22738032Speter case CANONUSER: 22838032Speter botch = "$:"; 22938032Speter break; 23038032Speter 23138032Speter case CALLSUBR: 23238032Speter botch = "$>"; 23338032Speter break; 23438032Speter 23538032Speter case CONDIF: 23638032Speter botch = "$?"; 23738032Speter break; 23838032Speter 23938032Speter case CONDFI: 24038032Speter botch = "$."; 24138032Speter break; 24238032Speter 24338032Speter case HOSTBEGIN: 24438032Speter botch = "$["; 24538032Speter break; 24638032Speter 24738032Speter case HOSTEND: 24838032Speter botch = "$]"; 24938032Speter break; 25038032Speter 25138032Speter case LOOKUPBEGIN: 25238032Speter botch = "$("; 25338032Speter break; 25438032Speter 25538032Speter case LOOKUPEND: 25638032Speter botch = "$)"; 25738032Speter break; 25838032Speter } 25938032Speter if (botch != NULL) 26038032Speter syserr("Inappropriate use of %s on LHS", 26138032Speter botch); 26238032Speter } 26364562Sgshapiro rwp->r_line = LineNumber; 26438032Speter } 26538032Speter else 26638032Speter { 26738032Speter syserr("R line: null LHS"); 26838032Speter rwp->r_lhs = null_list; 26938032Speter } 27082017Sgshapiro if (nfuzzy > MAXMATCH) 27182017Sgshapiro { 27282017Sgshapiro syserr("R line: too many wildcards"); 27382017Sgshapiro rwp->r_lhs = null_list; 27482017Sgshapiro } 27538032Speter 27638032Speter /* expand and save the RHS */ 27738032Speter while (*++p == '\t') 27838032Speter continue; 27938032Speter q = p; 28038032Speter while (*p != '\0' && *p != '\t') 28138032Speter p++; 28238032Speter *p = '\0'; 28338032Speter expand(q, exbuf, sizeof exbuf, e); 28438032Speter rwp->r_rhs = prescan(exbuf, '\t', pvpbuf, 28564562Sgshapiro sizeof pvpbuf, NULL, 28664562Sgshapiro ConfigLevel >= 9 ? TokTypeNoC : NULL); 28738032Speter if (rwp->r_rhs != NULL) 28838032Speter { 28938032Speter register char **ap; 29038032Speter 29138032Speter rwp->r_rhs = copyplist(rwp->r_rhs, TRUE); 29238032Speter 29338032Speter /* check no out-of-bounds replacements */ 29438032Speter nfuzzy += '0'; 29538032Speter for (ap = rwp->r_rhs; *ap != NULL; ap++) 29638032Speter { 29738032Speter char *botch; 29838032Speter 29938032Speter botch = NULL; 30038032Speter switch (**ap & 0377) 30138032Speter { 30238032Speter case MATCHREPL: 30338032Speter if ((*ap)[1] <= '0' || (*ap)[1] > nfuzzy) 30438032Speter { 30538032Speter syserr("replacement $%c out of bounds", 30638032Speter (*ap)[1]); 30738032Speter } 30838032Speter break; 30938032Speter 31038032Speter case MATCHZANY: 31138032Speter botch = "$*"; 31238032Speter break; 31338032Speter 31438032Speter case MATCHANY: 31538032Speter botch = "$+"; 31638032Speter break; 31738032Speter 31838032Speter case MATCHONE: 31938032Speter botch = "$-"; 32038032Speter break; 32138032Speter 32238032Speter case MATCHCLASS: 32338032Speter botch = "$="; 32438032Speter break; 32538032Speter 32638032Speter case MATCHNCLASS: 32738032Speter botch = "$~"; 32838032Speter break; 32938032Speter } 33038032Speter if (botch != NULL) 33138032Speter syserr("Inappropriate use of %s on RHS", 33238032Speter botch); 33338032Speter } 33438032Speter } 33538032Speter else 33638032Speter { 33738032Speter syserr("R line: null RHS"); 33838032Speter rwp->r_rhs = null_list; 33938032Speter } 34038032Speter break; 34138032Speter 34238032Speter case 'S': /* select rewriting set */ 34338032Speter expand(&bp[1], exbuf, sizeof exbuf, e); 34438032Speter ruleset = strtorwset(exbuf, NULL, ST_ENTER); 34538032Speter if (ruleset < 0) 34638032Speter break; 34764562Sgshapiro 34838032Speter rwp = RewriteRules[ruleset]; 34938032Speter if (rwp != NULL) 35038032Speter { 35164562Sgshapiro if (OpMode == MD_TEST) 35238032Speter printf("WARNING: Ruleset %s has multiple definitions\n", 35364562Sgshapiro &bp[1]); 35464562Sgshapiro if (tTd(37, 1)) 35564562Sgshapiro dprintf("WARNING: Ruleset %s has multiple definitions\n", 35638032Speter &bp[1]); 35738032Speter while (rwp->r_next != NULL) 35838032Speter rwp = rwp->r_next; 35938032Speter } 36038032Speter break; 36138032Speter 36238032Speter case 'D': /* macro definition */ 36338032Speter mid = macid(&bp[1], &ep); 36471345Sgshapiro if (mid == 0) 36571345Sgshapiro break; 36638032Speter p = munchstring(ep, NULL, '\0'); 36738032Speter define(mid, newstr(p), e); 36838032Speter break; 36938032Speter 37038032Speter case 'H': /* required header line */ 37164562Sgshapiro (void) chompheader(&bp[1], CHHDR_DEF, NULL, e); 37238032Speter break; 37338032Speter 37438032Speter case 'C': /* word class */ 37538032Speter case 'T': /* trusted user (set class `t') */ 37638032Speter if (bp[0] == 'C') 37738032Speter { 37838032Speter mid = macid(&bp[1], &ep); 37971345Sgshapiro if (mid == 0) 38071345Sgshapiro break; 38138032Speter expand(ep, exbuf, sizeof exbuf, e); 38238032Speter p = exbuf; 38338032Speter } 38438032Speter else 38538032Speter { 38638032Speter mid = 't'; 38738032Speter p = &bp[1]; 38838032Speter } 38938032Speter while (*p != '\0') 39038032Speter { 39138032Speter register char *wd; 39238032Speter char delim; 39338032Speter 39438032Speter while (*p != '\0' && isascii(*p) && isspace(*p)) 39538032Speter p++; 39638032Speter wd = p; 39738032Speter while (*p != '\0' && !(isascii(*p) && isspace(*p))) 39838032Speter p++; 39938032Speter delim = *p; 40038032Speter *p = '\0'; 40138032Speter if (wd[0] != '\0') 40238032Speter setclass(mid, wd); 40338032Speter *p = delim; 40438032Speter } 40538032Speter break; 40638032Speter 40738032Speter case 'F': /* word class from file */ 40838032Speter mid = macid(&bp[1], &ep); 40971345Sgshapiro if (mid == 0) 41071345Sgshapiro break; 41138032Speter for (p = ep; isascii(*p) && isspace(*p); ) 41238032Speter p++; 41338032Speter if (p[0] == '-' && p[1] == 'o') 41438032Speter { 41538032Speter optional = TRUE; 41638032Speter while (*p != '\0' && !(isascii(*p) && isspace(*p))) 41738032Speter p++; 41838032Speter while (isascii(*p) && isspace(*p)) 41938032Speter p++; 42038032Speter } 42138032Speter else 42238032Speter optional = FALSE; 42364562Sgshapiro 42438032Speter file = p; 42564562Sgshapiro q = p; 42664562Sgshapiro while (*q != '\0' && !(isascii(*q) && isspace(*q))) 42764562Sgshapiro q++; 42838032Speter if (*file == '|') 42938032Speter p = "%s"; 43038032Speter else 43138032Speter { 43264562Sgshapiro p = q; 43338032Speter if (*p == '\0') 43438032Speter p = "%s"; 43538032Speter else 43638032Speter { 43738032Speter *p = '\0'; 43838032Speter while (isascii(*++p) && isspace(*p)) 43938032Speter continue; 44038032Speter } 44138032Speter } 44238032Speter fileclass(mid, file, p, safe, optional); 44338032Speter break; 44438032Speter 44538032Speter#ifdef XLA 44638032Speter case 'L': /* extended load average description */ 44738032Speter xla_init(&bp[1]); 44838032Speter break; 44964562Sgshapiro#endif /* XLA */ 45038032Speter 45138032Speter#if defined(SUN_EXTENSIONS) && defined(SUN_LOOKUP_MACRO) 45238032Speter case 'L': /* lookup macro */ 45338032Speter case 'G': /* lookup class */ 45438032Speter /* reserved for Sun -- NIS+ database lookup */ 45538032Speter if (VendorCode != VENDOR_SUN) 45638032Speter goto badline; 45738032Speter sun_lg_config_line(bp, e); 45838032Speter break; 45964562Sgshapiro#endif /* defined(SUN_EXTENSIONS) && defined(SUN_LOOKUP_MACRO) */ 46038032Speter 46138032Speter case 'M': /* define mailer */ 46238032Speter makemailer(&bp[1]); 46338032Speter break; 46438032Speter 46538032Speter case 'O': /* set option */ 46638032Speter setoption(bp[1], &bp[2], safe, FALSE, e); 46738032Speter break; 46838032Speter 46938032Speter case 'P': /* set precedence */ 47038032Speter if (NumPriorities >= MAXPRIORITIES) 47138032Speter { 47238032Speter toomany('P', MAXPRIORITIES); 47338032Speter break; 47438032Speter } 47538032Speter for (p = &bp[1]; *p != '\0' && *p != '='; p++) 47638032Speter continue; 47738032Speter if (*p == '\0') 47838032Speter goto badline; 47938032Speter *p = '\0'; 48038032Speter Priorities[NumPriorities].pri_name = newstr(&bp[1]); 48138032Speter Priorities[NumPriorities].pri_val = atoi(++p); 48238032Speter NumPriorities++; 48338032Speter break; 48438032Speter 48538032Speter case 'V': /* configuration syntax version */ 48638032Speter for (p = &bp[1]; isascii(*p) && isspace(*p); p++) 48738032Speter continue; 48838032Speter if (!isascii(*p) || !isdigit(*p)) 48938032Speter { 49064562Sgshapiro syserr("invalid argument to V line: \"%.20s\"", 49138032Speter &bp[1]); 49238032Speter break; 49338032Speter } 49438032Speter ConfigLevel = strtol(p, &ep, 10); 49538032Speter 49638032Speter /* 49738032Speter ** Do heuristic tweaking for back compatibility. 49838032Speter */ 49938032Speter 50038032Speter if (ConfigLevel >= 5) 50138032Speter { 50238032Speter /* level 5 configs have short name in $w */ 50338032Speter p = macvalue('w', e); 50438032Speter if (p != NULL && (p = strchr(p, '.')) != NULL) 50538032Speter *p = '\0'; 50638032Speter define('w', macvalue('w', e), e); 50738032Speter } 50838032Speter if (ConfigLevel >= 6) 50938032Speter { 51038032Speter ColonOkInAddr = FALSE; 51138032Speter } 51238032Speter 51338032Speter /* 51438032Speter ** Look for vendor code. 51538032Speter */ 51638032Speter 51738032Speter if (*ep++ == '/') 51838032Speter { 51938032Speter /* extract vendor code */ 52038032Speter for (p = ep; isascii(*p) && isalpha(*p); ) 52138032Speter p++; 52238032Speter *p = '\0'; 52338032Speter 52438032Speter if (!setvendor(ep)) 52538032Speter syserr("invalid V line vendor code: \"%s\"", 52638032Speter ep); 52738032Speter } 52838032Speter break; 52938032Speter 53038032Speter case 'K': 53138032Speter expand(&bp[1], exbuf, sizeof exbuf, e); 53238032Speter (void) makemapentry(exbuf); 53338032Speter break; 53438032Speter 53538032Speter case 'E': 53638032Speter p = strchr(bp, '='); 53738032Speter if (p != NULL) 53838032Speter *p++ = '\0'; 53938032Speter setuserenv(&bp[1], p); 54038032Speter break; 54138032Speter 54264562Sgshapiro#if _FFR_MILTER 54364562Sgshapiro case 'X': /* mail filter */ 54464562Sgshapiro milter_setup(&bp[1]); 54564562Sgshapiro break; 54664562Sgshapiro#endif /* _FFR_MILTER */ 54764562Sgshapiro 54838032Speter default: 54938032Speter badline: 55038032Speter syserr("unknown configuration line \"%s\"", bp); 55138032Speter } 55238032Speter if (bp != buf) 55377349Sgshapiro sm_free(bp); 55438032Speter } 55538032Speter if (ferror(cf)) 55638032Speter { 55738032Speter syserr("I/O read error"); 55842575Speter finis(FALSE, EX_OSFILE); 55938032Speter } 56064562Sgshapiro (void) fclose(cf); 56138032Speter FileName = NULL; 56238032Speter 56338032Speter /* initialize host maps from local service tables */ 56438032Speter inithostmaps(); 56538032Speter 56664562Sgshapiro /* initialize daemon (if not defined yet) */ 56764562Sgshapiro initdaemon(); 56864562Sgshapiro 56938032Speter /* determine if we need to do special name-server frotz */ 57038032Speter { 57138032Speter int nmaps; 57238032Speter char *maptype[MAXMAPSTACK]; 57338032Speter short mapreturn[MAXMAPACTIONS]; 57438032Speter 57538032Speter nmaps = switch_map_find("hosts", maptype, mapreturn); 57638032Speter UseNameServer = FALSE; 57738032Speter if (nmaps > 0 && nmaps <= MAXMAPSTACK) 57838032Speter { 57938032Speter register int mapno; 58038032Speter 58138032Speter for (mapno = 0; mapno < nmaps && !UseNameServer; mapno++) 58238032Speter { 58338032Speter if (strcmp(maptype[mapno], "dns") == 0) 58438032Speter UseNameServer = TRUE; 58538032Speter } 58638032Speter } 58738032Speter 58838032Speter#ifdef HESIOD 58938032Speter nmaps = switch_map_find("passwd", maptype, mapreturn); 59038032Speter UseHesiod = FALSE; 59138032Speter if (nmaps > 0 && nmaps <= MAXMAPSTACK) 59238032Speter { 59338032Speter register int mapno; 59438032Speter 59538032Speter for (mapno = 0; mapno < nmaps && !UseHesiod; mapno++) 59638032Speter { 59738032Speter if (strcmp(maptype[mapno], "hesiod") == 0) 59838032Speter UseHesiod = TRUE; 59938032Speter } 60038032Speter } 60164562Sgshapiro#endif /* HESIOD */ 60238032Speter } 60338032Speter} 60438032Speter/* 60538032Speter** TRANSLATE_DOLLARS -- convert $x into internal form 60638032Speter** 60738032Speter** Actually does all appropriate pre-processing of a config line 60838032Speter** to turn it into internal form. 60938032Speter** 61038032Speter** Parameters: 61138032Speter** bp -- the buffer to translate. 61238032Speter** 61338032Speter** Returns: 61438032Speter** None. The buffer is translated in place. Since the 61538032Speter** translations always make the buffer shorter, this is 61638032Speter** safe without a size parameter. 61738032Speter*/ 61838032Speter 61938032Spetervoid 62038032Spetertranslate_dollars(bp) 62138032Speter char *bp; 62238032Speter{ 62338032Speter register char *p; 62438032Speter auto char *ep; 62538032Speter 62638032Speter for (p = bp; *p != '\0'; p++) 62738032Speter { 62838032Speter if (*p == '#' && p > bp && ConfigLevel >= 3) 62938032Speter { 63038032Speter /* this is an on-line comment */ 63138032Speter register char *e; 63238032Speter 63338032Speter switch (*--p & 0377) 63438032Speter { 63538032Speter case MACROEXPAND: 63638032Speter /* it's from $# -- let it go through */ 63738032Speter p++; 63838032Speter break; 63938032Speter 64038032Speter case '\\': 64138032Speter /* it's backslash escaped */ 64264562Sgshapiro (void) strlcpy(p, p + 1, strlen(p)); 64338032Speter break; 64438032Speter 64538032Speter default: 64664562Sgshapiro /* delete leading white space */ 64738032Speter while (isascii(*p) && isspace(*p) && 64838032Speter *p != '\n' && p > bp) 64938032Speter p--; 65038032Speter if ((e = strchr(++p, '\n')) != NULL) 65164562Sgshapiro (void) strlcpy(p, e, strlen(p)); 65238032Speter else 65338032Speter *p-- = '\0'; 65438032Speter break; 65538032Speter } 65638032Speter continue; 65738032Speter } 65838032Speter 65938032Speter if (*p != '$' || p[1] == '\0') 66038032Speter continue; 66138032Speter 66238032Speter if (p[1] == '$') 66338032Speter { 66438032Speter /* actual dollar sign.... */ 66564562Sgshapiro (void) strlcpy(p, p + 1, strlen(p)); 66638032Speter continue; 66738032Speter } 66838032Speter 66938032Speter /* convert to macro expansion character */ 67038032Speter *p++ = MACROEXPAND; 67138032Speter 67238032Speter /* special handling for $=, $~, $&, and $? */ 67338032Speter if (*p == '=' || *p == '~' || *p == '&' || *p == '?') 67438032Speter p++; 67538032Speter 67638032Speter /* convert macro name to code */ 67738032Speter *p = macid(p, &ep); 67864562Sgshapiro if (ep != p + 1) 67964562Sgshapiro (void) strlcpy(p + 1, ep, strlen(p + 1)); 68038032Speter } 68138032Speter 68238032Speter /* strip trailing white space from the line */ 68338032Speter while (--p > bp && isascii(*p) && isspace(*p)) 68438032Speter *p = '\0'; 68538032Speter} 68638032Speter/* 68738032Speter** TOOMANY -- signal too many of some option 68838032Speter** 68938032Speter** Parameters: 69038032Speter** id -- the id of the error line 69138032Speter** maxcnt -- the maximum possible values 69238032Speter** 69338032Speter** Returns: 69438032Speter** none. 69538032Speter** 69638032Speter** Side Effects: 69738032Speter** gives a syserr. 69838032Speter*/ 69938032Speter 70064562Sgshapirostatic void 70138032Spetertoomany(id, maxcnt) 70238032Speter int id; 70338032Speter int maxcnt; 70438032Speter{ 70538032Speter syserr("too many %c lines, %d max", id, maxcnt); 70638032Speter} 70738032Speter/* 70838032Speter** FILECLASS -- read members of a class from a file 70938032Speter** 71038032Speter** Parameters: 71138032Speter** class -- class to define. 71238032Speter** filename -- name of file to read. 71338032Speter** fmt -- scanf string to use for match. 71438032Speter** safe -- if set, this is a safe read. 71538032Speter** optional -- if set, it is not an error for the file to 71638032Speter** not exist. 71738032Speter** 71838032Speter** Returns: 71938032Speter** none 72038032Speter** 72138032Speter** Side Effects: 72238032Speter** 72338032Speter** puts all lines in filename that match a scanf into 72438032Speter** the named class. 72538032Speter*/ 72638032Speter 72764562Sgshapirostatic void 72838032Speterfileclass(class, filename, fmt, safe, optional) 72938032Speter int class; 73038032Speter char *filename; 73138032Speter char *fmt; 73238032Speter bool safe; 73338032Speter bool optional; 73438032Speter{ 73538032Speter FILE *f; 73664562Sgshapiro long sff; 73738032Speter pid_t pid; 73838032Speter register char *p; 73938032Speter char buf[MAXLINE]; 74038032Speter 74138032Speter if (tTd(37, 2)) 74264562Sgshapiro dprintf("fileclass(%s, fmt=%s)\n", filename, fmt); 74338032Speter 74438032Speter if (filename[0] == '|') 74538032Speter { 74638032Speter auto int fd; 74738032Speter int i; 74838032Speter char *argv[MAXPV + 1]; 74938032Speter 75038032Speter i = 0; 75138032Speter for (p = strtok(&filename[1], " \t"); p != NULL; p = strtok(NULL, " \t")) 75238032Speter { 75338032Speter if (i >= MAXPV) 75438032Speter break; 75538032Speter argv[i++] = p; 75638032Speter } 75738032Speter argv[i] = NULL; 75838032Speter pid = prog_open(argv, &fd, CurEnv); 75938032Speter if (pid < 0) 76038032Speter f = NULL; 76138032Speter else 76238032Speter f = fdopen(fd, "r"); 76338032Speter } 76438032Speter else 76538032Speter { 76638032Speter pid = -1; 76738032Speter sff = SFF_REGONLY; 76864562Sgshapiro if (!bitnset(DBS_CLASSFILEINUNSAFEDIRPATH, DontBlameSendmail)) 76938032Speter sff |= SFF_SAFEDIRPATH; 77064562Sgshapiro if (!bitnset(DBS_LINKEDCLASSFILEINWRITABLEDIR, 77164562Sgshapiro DontBlameSendmail)) 77238032Speter sff |= SFF_NOWLINK; 77338032Speter if (safe) 77438032Speter sff |= SFF_OPENASROOT; 77538032Speter if (DontLockReadFiles) 77638032Speter sff |= SFF_NOLOCK; 77738032Speter f = safefopen(filename, O_RDONLY, 0, sff); 77838032Speter } 77938032Speter if (f == NULL) 78038032Speter { 78138032Speter if (!optional) 78264562Sgshapiro syserr("fileclass: cannot open '%s'", filename); 78338032Speter return; 78438032Speter } 78538032Speter 78638032Speter while (fgets(buf, sizeof buf, f) != NULL) 78738032Speter { 78864562Sgshapiro#if SCANF 78938032Speter char wordbuf[MAXLINE + 1]; 79064562Sgshapiro#endif /* SCANF */ 79138032Speter 79238032Speter if (buf[0] == '#') 79338032Speter continue; 79464562Sgshapiro#if SCANF 79538032Speter if (sscanf(buf, fmt, wordbuf) != 1) 79638032Speter continue; 79738032Speter p = wordbuf; 79864562Sgshapiro#else /* SCANF */ 79938032Speter p = buf; 80064562Sgshapiro#endif /* SCANF */ 80138032Speter 80238032Speter /* 80338032Speter ** Break up the match into words. 80438032Speter */ 80538032Speter 80638032Speter while (*p != '\0') 80738032Speter { 80838032Speter register char *q; 80938032Speter 81038032Speter /* strip leading spaces */ 81138032Speter while (isascii(*p) && isspace(*p)) 81238032Speter p++; 81338032Speter if (*p == '\0') 81438032Speter break; 81538032Speter 81638032Speter /* find the end of the word */ 81738032Speter q = p; 81838032Speter while (*p != '\0' && !(isascii(*p) && isspace(*p))) 81938032Speter p++; 82038032Speter if (*p != '\0') 82138032Speter *p++ = '\0'; 82238032Speter 82338032Speter /* enter the word in the symbol table */ 82438032Speter setclass(class, q); 82538032Speter } 82638032Speter } 82738032Speter 82838032Speter (void) fclose(f); 82938032Speter if (pid > 0) 83038032Speter (void) waitfor(pid); 83138032Speter} 83238032Speter/* 83338032Speter** MAKEMAILER -- define a new mailer. 83438032Speter** 83538032Speter** Parameters: 83638032Speter** line -- description of mailer. This is in labeled 83738032Speter** fields. The fields are: 83838032Speter** A -- the argv for this mailer 83938032Speter** C -- the character set for MIME conversions 84038032Speter** D -- the directory to run in 84138032Speter** E -- the eol string 84238032Speter** F -- the flags associated with the mailer 84338032Speter** L -- the maximum line length 84438032Speter** M -- the maximum message size 84538032Speter** N -- the niceness at which to run 84638032Speter** P -- the path to the mailer 84738032Speter** R -- the recipient rewriting set 84838032Speter** S -- the sender rewriting set 84938032Speter** T -- the mailer type (for DSNs) 85038032Speter** U -- the uid to run as 85164562Sgshapiro** W -- the time to wait at the end 85273188Sgshapiro** m -- maximum messages per connection 85373188Sgshapiro** / -- new root directory 85438032Speter** The first word is the canonical name of the mailer. 85538032Speter** 85638032Speter** Returns: 85738032Speter** none. 85838032Speter** 85938032Speter** Side Effects: 86038032Speter** enters the mailer into the mailer table. 86138032Speter*/ 86238032Speter 86338032Spetervoid 86438032Spetermakemailer(line) 86538032Speter char *line; 86638032Speter{ 86738032Speter register char *p; 86838032Speter register struct mailer *m; 86938032Speter register STAB *s; 87038032Speter int i; 87138032Speter char fcode; 87238032Speter auto char *endp; 87338032Speter extern int NextMailer; 87438032Speter 87538032Speter /* allocate a mailer and set up defaults */ 87638032Speter m = (struct mailer *) xalloc(sizeof *m); 87764562Sgshapiro memset((char *) m, '\0', sizeof *m); 87838032Speter 87938032Speter /* collect the mailer name */ 88038032Speter for (p = line; *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); p++) 88138032Speter continue; 88238032Speter if (*p != '\0') 88338032Speter *p++ = '\0'; 88438032Speter if (line[0] == '\0') 88571345Sgshapiro { 88638032Speter syserr("name required for mailer"); 88771345Sgshapiro return; 88871345Sgshapiro } 88938032Speter m->m_name = newstr(line); 89038032Speter 89138032Speter /* now scan through and assign info from the fields */ 89238032Speter while (*p != '\0') 89338032Speter { 89438032Speter auto char *delimptr; 89538032Speter 89638032Speter while (*p != '\0' && (*p == ',' || (isascii(*p) && isspace(*p)))) 89738032Speter p++; 89838032Speter 89938032Speter /* p now points to field code */ 90038032Speter fcode = *p; 90138032Speter while (*p != '\0' && *p != '=' && *p != ',') 90238032Speter p++; 90338032Speter if (*p++ != '=') 90438032Speter { 90538032Speter syserr("mailer %s: `=' expected", m->m_name); 90638032Speter return; 90738032Speter } 90838032Speter while (isascii(*p) && isspace(*p)) 90938032Speter p++; 91038032Speter 91138032Speter /* p now points to the field body */ 91238032Speter p = munchstring(p, &delimptr, ','); 91338032Speter 91438032Speter /* install the field into the mailer struct */ 91538032Speter switch (fcode) 91638032Speter { 91738032Speter case 'P': /* pathname */ 91838032Speter if (*p == '\0') 91938032Speter syserr("mailer %s: empty path name", m->m_name); 92071345Sgshapiro else 92171345Sgshapiro m->m_mailer = newstr(p); 92238032Speter break; 92338032Speter 92438032Speter case 'F': /* flags */ 92538032Speter for (; *p != '\0'; p++) 92638032Speter if (!(isascii(*p) && isspace(*p))) 92771345Sgshapiro setbitn(bitidx(*p), m->m_flags); 92838032Speter break; 92938032Speter 93038032Speter case 'S': /* sender rewriting ruleset */ 93138032Speter case 'R': /* recipient rewriting ruleset */ 93238032Speter i = strtorwset(p, &endp, ST_ENTER); 93338032Speter if (i < 0) 93438032Speter return; 93538032Speter if (fcode == 'S') 93638032Speter m->m_sh_rwset = m->m_se_rwset = i; 93738032Speter else 93838032Speter m->m_rh_rwset = m->m_re_rwset = i; 93938032Speter 94038032Speter p = endp; 94138032Speter if (*p++ == '/') 94238032Speter { 94338032Speter i = strtorwset(p, NULL, ST_ENTER); 94438032Speter if (i < 0) 94538032Speter return; 94638032Speter if (fcode == 'S') 94738032Speter m->m_sh_rwset = i; 94838032Speter else 94938032Speter m->m_rh_rwset = i; 95038032Speter } 95138032Speter break; 95238032Speter 95338032Speter case 'E': /* end of line string */ 95438032Speter if (*p == '\0') 95538032Speter syserr("mailer %s: null end-of-line string", 95638032Speter m->m_name); 95771345Sgshapiro else 95871345Sgshapiro m->m_eol = newstr(p); 95938032Speter break; 96038032Speter 96138032Speter case 'A': /* argument vector */ 96238032Speter if (*p == '\0') 96338032Speter syserr("mailer %s: null argument vector", 96438032Speter m->m_name); 96571345Sgshapiro else 96671345Sgshapiro m->m_argv = makeargv(p); 96738032Speter break; 96838032Speter 96938032Speter case 'M': /* maximum message size */ 97038032Speter m->m_maxsize = atol(p); 97138032Speter break; 97238032Speter 97364562Sgshapiro case 'm': /* maximum messages per connection */ 97464562Sgshapiro m->m_maxdeliveries = atoi(p); 97564562Sgshapiro break; 97664562Sgshapiro 97764562Sgshapiro#if _FFR_DYNAMIC_TOBUF 97864562Sgshapiro case 'r': /* max recipient per envelope */ 97964562Sgshapiro m->m_maxrcpt = atoi(p); 98064562Sgshapiro break; 98164562Sgshapiro#endif /* _FFR_DYNAMIC_TOBUF */ 98264562Sgshapiro 98338032Speter case 'L': /* maximum line length */ 98438032Speter m->m_linelimit = atoi(p); 98538032Speter if (m->m_linelimit < 0) 98638032Speter m->m_linelimit = 0; 98738032Speter break; 98838032Speter 98938032Speter case 'N': /* run niceness */ 99038032Speter m->m_nice = atoi(p); 99138032Speter break; 99238032Speter 99338032Speter case 'D': /* working directory */ 99438032Speter if (*p == '\0') 99538032Speter syserr("mailer %s: null working directory", 99638032Speter m->m_name); 99771345Sgshapiro else 99871345Sgshapiro m->m_execdir = newstr(p); 99938032Speter break; 100038032Speter 100138032Speter case 'C': /* default charset */ 100238032Speter if (*p == '\0') 100338032Speter syserr("mailer %s: null charset", m->m_name); 100471345Sgshapiro else 100571345Sgshapiro m->m_defcharset = newstr(p); 100638032Speter break; 100738032Speter 100838032Speter case 'T': /* MTA-Name/Address/Diagnostic types */ 100938032Speter /* extract MTA name type; default to "dns" */ 101038032Speter m->m_mtatype = newstr(p); 101138032Speter p = strchr(m->m_mtatype, '/'); 101238032Speter if (p != NULL) 101338032Speter { 101438032Speter *p++ = '\0'; 101538032Speter if (*p == '\0') 101638032Speter p = NULL; 101738032Speter } 101838032Speter if (*m->m_mtatype == '\0') 101938032Speter m->m_mtatype = "dns"; 102038032Speter 102138032Speter /* extract address type; default to "rfc822" */ 102238032Speter m->m_addrtype = p; 102338032Speter if (p != NULL) 102438032Speter p = strchr(p, '/'); 102538032Speter if (p != NULL) 102638032Speter { 102738032Speter *p++ = '\0'; 102838032Speter if (*p == '\0') 102938032Speter p = NULL; 103038032Speter } 103138032Speter if (m->m_addrtype == NULL || *m->m_addrtype == '\0') 103238032Speter m->m_addrtype = "rfc822"; 103338032Speter 103438032Speter /* extract diagnostic type; default to "smtp" */ 103538032Speter m->m_diagtype = p; 103638032Speter if (m->m_diagtype == NULL || *m->m_diagtype == '\0') 103738032Speter m->m_diagtype = "smtp"; 103838032Speter break; 103938032Speter 104038032Speter case 'U': /* user id */ 104138032Speter if (isascii(*p) && !isdigit(*p)) 104238032Speter { 104338032Speter char *q = p; 104438032Speter struct passwd *pw; 104538032Speter 104638032Speter while (*p != '\0' && isascii(*p) && 104738032Speter (isalnum(*p) || strchr("-_", *p) != NULL)) 104838032Speter p++; 104938032Speter while (isascii(*p) && isspace(*p)) 105038032Speter *p++ = '\0'; 105138032Speter if (*p != '\0') 105238032Speter *p++ = '\0'; 105338032Speter if (*q == '\0') 105471345Sgshapiro { 105538032Speter syserr("mailer %s: null user name", 105638032Speter m->m_name); 105771345Sgshapiro break; 105871345Sgshapiro } 105938032Speter pw = sm_getpwnam(q); 106038032Speter if (pw == NULL) 106171345Sgshapiro { 106238032Speter syserr("readcf: mailer U= flag: unknown user %s", q); 106371345Sgshapiro break; 106471345Sgshapiro } 106538032Speter else 106638032Speter { 106738032Speter m->m_uid = pw->pw_uid; 106838032Speter m->m_gid = pw->pw_gid; 106938032Speter } 107038032Speter } 107138032Speter else 107238032Speter { 107338032Speter auto char *q; 107438032Speter 107538032Speter m->m_uid = strtol(p, &q, 0); 107638032Speter p = q; 107738032Speter while (isascii(*p) && isspace(*p)) 107838032Speter p++; 107938032Speter if (*p != '\0') 108038032Speter p++; 108138032Speter } 108238032Speter while (isascii(*p) && isspace(*p)) 108338032Speter p++; 108438032Speter if (*p == '\0') 108538032Speter break; 108638032Speter if (isascii(*p) && !isdigit(*p)) 108738032Speter { 108838032Speter char *q = p; 108938032Speter struct group *gr; 109038032Speter 109138032Speter while (isascii(*p) && isalnum(*p)) 109238032Speter p++; 109338032Speter *p++ = '\0'; 109438032Speter if (*q == '\0') 109571345Sgshapiro { 109638032Speter syserr("mailer %s: null group name", 109738032Speter m->m_name); 109871345Sgshapiro break; 109971345Sgshapiro } 110038032Speter gr = getgrnam(q); 110138032Speter if (gr == NULL) 110271345Sgshapiro { 110338032Speter syserr("readcf: mailer U= flag: unknown group %s", q); 110471345Sgshapiro break; 110571345Sgshapiro } 110638032Speter else 110738032Speter m->m_gid = gr->gr_gid; 110838032Speter } 110938032Speter else 111038032Speter { 111138032Speter m->m_gid = strtol(p, NULL, 0); 111238032Speter } 111338032Speter break; 111464562Sgshapiro 111564562Sgshapiro case 'W': /* wait timeout */ 111664562Sgshapiro m->m_wait = convtime(p, 's'); 111764562Sgshapiro break; 111864562Sgshapiro 111964562Sgshapiro case '/': /* new root directory */ 112064562Sgshapiro if (*p == '\0') 112164562Sgshapiro syserr("mailer %s: null root directory", 112264562Sgshapiro m->m_name); 112364562Sgshapiro else 112464562Sgshapiro m->m_rootdir = newstr(p); 112564562Sgshapiro break; 112664562Sgshapiro 112764562Sgshapiro default: 112864562Sgshapiro syserr("M%s: unknown mailer equate %c=", 112964562Sgshapiro m->m_name, fcode); 113064562Sgshapiro break; 113138032Speter } 113238032Speter 113338032Speter p = delimptr; 113438032Speter } 113538032Speter 113638032Speter /* do some rationality checking */ 113738032Speter if (m->m_argv == NULL) 113838032Speter { 113938032Speter syserr("M%s: A= argument required", m->m_name); 114038032Speter return; 114138032Speter } 114238032Speter if (m->m_mailer == NULL) 114338032Speter { 114438032Speter syserr("M%s: P= argument required", m->m_name); 114538032Speter return; 114638032Speter } 114738032Speter 114838032Speter if (NextMailer >= MAXMAILERS) 114938032Speter { 115038032Speter syserr("too many mailers defined (%d max)", MAXMAILERS); 115138032Speter return; 115238032Speter } 115338032Speter 115464562Sgshapiro#if _FFR_DYNAMIC_TOBUF 115564562Sgshapiro if (m->m_maxrcpt <= 0) 115664562Sgshapiro m->m_maxrcpt = DEFAULT_MAX_RCPT; 115764562Sgshapiro#endif /* _FFR_DYNAMIC_TOBUF */ 115864562Sgshapiro 115938032Speter /* do some heuristic cleanup for back compatibility */ 116038032Speter if (bitnset(M_LIMITS, m->m_flags)) 116138032Speter { 116238032Speter if (m->m_linelimit == 0) 116338032Speter m->m_linelimit = SMTPLINELIM; 116438032Speter if (ConfigLevel < 2) 116538032Speter setbitn(M_7BITS, m->m_flags); 116638032Speter } 116738032Speter 116864562Sgshapiro if (strcmp(m->m_mailer, "[TCP]") == 0) 116938032Speter { 117066494Sgshapiro#if _FFR_REMOVE_TCP_MAILER_PATH 117164562Sgshapiro syserr("M%s: P=[TCP] is deprecated, use P=[IPC] instead\n", 117264562Sgshapiro m->m_name); 117371345Sgshapiro return; 117466494Sgshapiro#else /* _FFR_REMOVE_TCP_MAILER_PATH */ 117564562Sgshapiro printf("M%s: Warning: P=[TCP] is deprecated, use P=[IPC] instead\n", 117664562Sgshapiro m->m_name); 117766494Sgshapiro#endif /* _FFR_REMOVE_TCP_MAILER_PATH */ 117838032Speter } 117938032Speter 118066494Sgshapiro if (strcmp(m->m_mailer, "[IPC]") == 0 118164562Sgshapiro#if !_FFR_REMOVE_TCP_MAILER_PATH 118266494Sgshapiro || strcmp(m->m_mailer, "[TCP]") == 0 118364562Sgshapiro#endif /* !_FFR_REMOVE_TCP_MAILER_PATH */ 118464562Sgshapiro ) 118538032Speter { 118664562Sgshapiro /* Use the second argument for host or path to socket */ 118764562Sgshapiro if (m->m_argv[0] == NULL || m->m_argv[1] == NULL || 118864562Sgshapiro m->m_argv[1][0] == '\0') 118964562Sgshapiro { 119064562Sgshapiro syserr("M%s: too few parameters for %s mailer", 119164562Sgshapiro m->m_name, m->m_mailer); 119271345Sgshapiro return; 119364562Sgshapiro } 119466494Sgshapiro if (strcmp(m->m_argv[0], "TCP") != 0 119564562Sgshapiro#if NETUNIX 119666494Sgshapiro && strcmp(m->m_argv[0], "FILE") != 0 119764562Sgshapiro#endif /* NETUNIX */ 119864562Sgshapiro#if !_FFR_DEPRECATE_IPC_MAILER_ARG 119966494Sgshapiro && strcmp(m->m_argv[0], "IPC") != 0 120064562Sgshapiro#endif /* !_FFR_DEPRECATE_IPC_MAILER_ARG */ 120164562Sgshapiro ) 120264562Sgshapiro { 120364562Sgshapiro printf("M%s: Warning: first argument in %s mailer must be %s\n", 120464562Sgshapiro m->m_name, m->m_mailer, 120564562Sgshapiro#if NETUNIX 120664562Sgshapiro "TCP or FILE" 120764562Sgshapiro#else /* NETUNIX */ 120864562Sgshapiro "TCP" 120964562Sgshapiro#endif /* NETUNIX */ 121064562Sgshapiro ); 121164562Sgshapiro } 121264562Sgshapiro 121364562Sgshapiro } 121464562Sgshapiro else if (strcmp(m->m_mailer, "[FILE]") == 0) 121564562Sgshapiro { 121638032Speter /* Use the second argument for filename */ 121738032Speter if (m->m_argv[0] == NULL || m->m_argv[1] == NULL || 121838032Speter m->m_argv[2] != NULL) 121938032Speter { 122038032Speter syserr("M%s: too %s parameters for [FILE] mailer", 122138032Speter m->m_name, 122238032Speter (m->m_argv[0] == NULL || 122338032Speter m->m_argv[1] == NULL) ? "few" : "many"); 122471345Sgshapiro return; 122538032Speter } 122638032Speter else if (strcmp(m->m_argv[0], "FILE") != 0) 122738032Speter { 122838032Speter syserr("M%s: first argument in [FILE] mailer must be FILE", 122938032Speter m->m_name); 123071345Sgshapiro return; 123138032Speter } 123238032Speter } 123338032Speter 123464562Sgshapiro if (strcmp(m->m_mailer, "[IPC]") == 0 || 123564562Sgshapiro strcmp(m->m_mailer, "[TCP]") == 0) 123664562Sgshapiro { 123764562Sgshapiro if (m->m_mtatype == NULL) 123864562Sgshapiro m->m_mtatype = "dns"; 123964562Sgshapiro if (m->m_addrtype == NULL) 124064562Sgshapiro m->m_addrtype = "rfc822"; 124164562Sgshapiro if (m->m_diagtype == NULL) 124264562Sgshapiro { 124364562Sgshapiro if (m->m_argv[0] != NULL && 124464562Sgshapiro strcmp(m->m_argv[0], "FILE") == 0) 124564562Sgshapiro m->m_diagtype = "x-unix"; 124664562Sgshapiro else 124764562Sgshapiro m->m_diagtype = "smtp"; 124864562Sgshapiro } 124964562Sgshapiro } 125064562Sgshapiro 125138032Speter if (m->m_eol == NULL) 125238032Speter { 125338032Speter char **pp; 125438032Speter 125538032Speter /* default for SMTP is \r\n; use \n for local delivery */ 125638032Speter for (pp = m->m_argv; *pp != NULL; pp++) 125738032Speter { 125838032Speter for (p = *pp; *p != '\0'; ) 125938032Speter { 126038032Speter if ((*p++ & 0377) == MACROEXPAND && *p == 'u') 126138032Speter break; 126238032Speter } 126338032Speter if (*p != '\0') 126438032Speter break; 126538032Speter } 126638032Speter if (*pp == NULL) 126738032Speter m->m_eol = "\r\n"; 126838032Speter else 126938032Speter m->m_eol = "\n"; 127038032Speter } 127138032Speter 127238032Speter /* enter the mailer into the symbol table */ 127338032Speter s = stab(m->m_name, ST_MAILER, ST_ENTER); 127438032Speter if (s->s_mailer != NULL) 127538032Speter { 127638032Speter i = s->s_mailer->m_mno; 127777349Sgshapiro sm_free(s->s_mailer); 127838032Speter } 127938032Speter else 128038032Speter { 128138032Speter i = NextMailer++; 128238032Speter } 128338032Speter Mailer[i] = s->s_mailer = m; 128438032Speter m->m_mno = i; 128538032Speter} 128638032Speter/* 128738032Speter** MUNCHSTRING -- translate a string into internal form. 128838032Speter** 128938032Speter** Parameters: 129038032Speter** p -- the string to munch. 129138032Speter** delimptr -- if non-NULL, set to the pointer of the 129238032Speter** field delimiter character. 129338032Speter** delim -- the delimiter for the field. 129438032Speter** 129538032Speter** Returns: 129638032Speter** the munched string. 129764562Sgshapiro** 129864562Sgshapiro** Side Effects: 129964562Sgshapiro** the munched string is a local static buffer. 130064562Sgshapiro** it must be copied before the function is called again. 130138032Speter*/ 130238032Speter 130338032Speterchar * 130438032Spetermunchstring(p, delimptr, delim) 130538032Speter register char *p; 130638032Speter char **delimptr; 130738032Speter int delim; 130838032Speter{ 130938032Speter register char *q; 131038032Speter bool backslash = FALSE; 131138032Speter bool quotemode = FALSE; 131238032Speter static char buf[MAXLINE]; 131338032Speter 131438032Speter for (q = buf; *p != '\0' && q < &buf[sizeof buf - 1]; p++) 131538032Speter { 131638032Speter if (backslash) 131738032Speter { 131838032Speter /* everything is roughly literal */ 131938032Speter backslash = FALSE; 132038032Speter switch (*p) 132138032Speter { 132238032Speter case 'r': /* carriage return */ 132338032Speter *q++ = '\r'; 132438032Speter continue; 132538032Speter 132638032Speter case 'n': /* newline */ 132738032Speter *q++ = '\n'; 132838032Speter continue; 132938032Speter 133038032Speter case 'f': /* form feed */ 133138032Speter *q++ = '\f'; 133238032Speter continue; 133338032Speter 133438032Speter case 'b': /* backspace */ 133538032Speter *q++ = '\b'; 133638032Speter continue; 133738032Speter } 133838032Speter *q++ = *p; 133938032Speter } 134038032Speter else 134138032Speter { 134238032Speter if (*p == '\\') 134338032Speter backslash = TRUE; 134438032Speter else if (*p == '"') 134538032Speter quotemode = !quotemode; 134638032Speter else if (quotemode || *p != delim) 134738032Speter *q++ = *p; 134838032Speter else 134938032Speter break; 135038032Speter } 135138032Speter } 135238032Speter 135338032Speter if (delimptr != NULL) 135438032Speter *delimptr = p; 135538032Speter *q++ = '\0'; 135664562Sgshapiro return buf; 135738032Speter} 135838032Speter/* 135938032Speter** MAKEARGV -- break up a string into words 136038032Speter** 136138032Speter** Parameters: 136238032Speter** p -- the string to break up. 136338032Speter** 136438032Speter** Returns: 136538032Speter** a char **argv (dynamically allocated) 136638032Speter** 136738032Speter** Side Effects: 136838032Speter** munges p. 136938032Speter*/ 137038032Speter 137164562Sgshapirostatic char ** 137238032Spetermakeargv(p) 137338032Speter register char *p; 137438032Speter{ 137538032Speter char *q; 137638032Speter int i; 137738032Speter char **avp; 137838032Speter char *argv[MAXPV + 1]; 137938032Speter 138038032Speter /* take apart the words */ 138138032Speter i = 0; 138238032Speter while (*p != '\0' && i < MAXPV) 138338032Speter { 138438032Speter q = p; 138538032Speter while (*p != '\0' && !(isascii(*p) && isspace(*p))) 138638032Speter p++; 138738032Speter while (isascii(*p) && isspace(*p)) 138838032Speter *p++ = '\0'; 138938032Speter argv[i++] = newstr(q); 139038032Speter } 139138032Speter argv[i++] = NULL; 139238032Speter 139338032Speter /* now make a copy of the argv */ 139438032Speter avp = (char **) xalloc(sizeof *avp * i); 139564562Sgshapiro memmove((char *) avp, (char *) argv, sizeof *avp * i); 139638032Speter 139764562Sgshapiro return avp; 139838032Speter} 139938032Speter/* 140038032Speter** PRINTRULES -- print rewrite rules (for debugging) 140138032Speter** 140238032Speter** Parameters: 140338032Speter** none. 140438032Speter** 140538032Speter** Returns: 140638032Speter** none. 140738032Speter** 140838032Speter** Side Effects: 140938032Speter** prints rewrite rules. 141038032Speter*/ 141138032Speter 141238032Spetervoid 141338032Speterprintrules() 141438032Speter{ 141538032Speter register struct rewrite *rwp; 141638032Speter register int ruleset; 141738032Speter 141838032Speter for (ruleset = 0; ruleset < 10; ruleset++) 141938032Speter { 142038032Speter if (RewriteRules[ruleset] == NULL) 142138032Speter continue; 142238032Speter printf("\n----Rule Set %d:", ruleset); 142338032Speter 142438032Speter for (rwp = RewriteRules[ruleset]; rwp != NULL; rwp = rwp->r_next) 142538032Speter { 142638032Speter printf("\nLHS:"); 142738032Speter printav(rwp->r_lhs); 142838032Speter printf("RHS:"); 142938032Speter printav(rwp->r_rhs); 143038032Speter } 143138032Speter } 143238032Speter} 143338032Speter/* 143438032Speter** PRINTMAILER -- print mailer structure (for debugging) 143538032Speter** 143638032Speter** Parameters: 143738032Speter** m -- the mailer to print 143838032Speter** 143938032Speter** Returns: 144038032Speter** none. 144138032Speter*/ 144238032Speter 144338032Spetervoid 144438032Speterprintmailer(m) 144538032Speter register MAILER *m; 144638032Speter{ 144738032Speter int j; 144838032Speter 144964562Sgshapiro printf("mailer %d (%s): P=%s S=", m->m_mno, m->m_name, m->m_mailer); 145064562Sgshapiro if (RuleSetNames[m->m_se_rwset] == NULL) 145164562Sgshapiro printf("%d/", m->m_se_rwset); 145264562Sgshapiro else 145364562Sgshapiro printf("%s/", RuleSetNames[m->m_se_rwset]); 145464562Sgshapiro if (RuleSetNames[m->m_sh_rwset] == NULL) 145564562Sgshapiro printf("%d R=", m->m_sh_rwset); 145664562Sgshapiro else 145764562Sgshapiro printf("%s R=", RuleSetNames[m->m_sh_rwset]); 145864562Sgshapiro if (RuleSetNames[m->m_re_rwset] == NULL) 145964562Sgshapiro printf("%d/", m->m_re_rwset); 146064562Sgshapiro else 146164562Sgshapiro printf("%s/", RuleSetNames[m->m_re_rwset]); 146264562Sgshapiro if (RuleSetNames[m->m_rh_rwset] == NULL) 146364562Sgshapiro printf("%d ", m->m_rh_rwset); 146464562Sgshapiro else 146564562Sgshapiro printf("%s ", RuleSetNames[m->m_rh_rwset]); 146664562Sgshapiro printf("M=%ld U=%d:%d F=", m->m_maxsize, 146764562Sgshapiro (int) m->m_uid, (int) m->m_gid); 146838032Speter for (j = '\0'; j <= '\177'; j++) 146938032Speter if (bitnset(j, m->m_flags)) 147038032Speter (void) putchar(j); 147138032Speter printf(" L=%d E=", m->m_linelimit); 147238032Speter xputs(m->m_eol); 147338032Speter if (m->m_defcharset != NULL) 147438032Speter printf(" C=%s", m->m_defcharset); 147538032Speter printf(" T=%s/%s/%s", 147638032Speter m->m_mtatype == NULL ? "<undefined>" : m->m_mtatype, 147738032Speter m->m_addrtype == NULL ? "<undefined>" : m->m_addrtype, 147838032Speter m->m_diagtype == NULL ? "<undefined>" : m->m_diagtype); 147964562Sgshapiro#if _FFR_DYNAMIC_TOBUF 148064562Sgshapiro printf(" r=%d", m->m_maxrcpt); 148164562Sgshapiro#endif /* _FFR_DYNAMIC_TOBUF */ 148238032Speter if (m->m_argv != NULL) 148338032Speter { 148438032Speter char **a = m->m_argv; 148538032Speter 148638032Speter printf(" A="); 148738032Speter while (*a != NULL) 148838032Speter { 148938032Speter if (a != m->m_argv) 149038032Speter printf(" "); 149138032Speter xputs(*a++); 149238032Speter } 149338032Speter } 149438032Speter printf("\n"); 149538032Speter} 149638032Speter/* 149738032Speter** SETOPTION -- set global processing option 149838032Speter** 149938032Speter** Parameters: 150038032Speter** opt -- option name. 150138032Speter** val -- option value (as a text string). 150238032Speter** safe -- set if this came from a configuration file. 150338032Speter** Some options (if set from the command line) will 150438032Speter** reset the user id to avoid security problems. 150538032Speter** sticky -- if set, don't let other setoptions override 150638032Speter** this value. 150738032Speter** e -- the main envelope. 150838032Speter** 150938032Speter** Returns: 151038032Speter** none. 151138032Speter** 151238032Speter** Side Effects: 151338032Speter** Sets options as implied by the arguments. 151438032Speter*/ 151538032Speter 151664562Sgshapirostatic BITMAP256 StickyOpt; /* set if option is stuck */ 151738032Speter 151838032Speter#if NAMED_BIND 151938032Speter 152064562Sgshapirostatic struct resolverflags 152138032Speter{ 152238032Speter char *rf_name; /* name of the flag */ 152338032Speter long rf_bits; /* bits to set/clear */ 152438032Speter} ResolverFlags[] = 152538032Speter{ 152638032Speter { "debug", RES_DEBUG }, 152738032Speter { "aaonly", RES_AAONLY }, 152838032Speter { "usevc", RES_USEVC }, 152938032Speter { "primary", RES_PRIMARY }, 153038032Speter { "igntc", RES_IGNTC }, 153138032Speter { "recurse", RES_RECURSE }, 153238032Speter { "defnames", RES_DEFNAMES }, 153338032Speter { "stayopen", RES_STAYOPEN }, 153438032Speter { "dnsrch", RES_DNSRCH }, 153538032Speter { "true", 0 }, /* avoid error on old syntax */ 153638032Speter { NULL, 0 } 153738032Speter}; 153838032Speter 153964562Sgshapiro#endif /* NAMED_BIND */ 154038032Speter 154164562Sgshapiro#define OI_NONE 0 /* no special treatment */ 154264562Sgshapiro#define OI_SAFE 0x0001 /* safe for random people to use */ 154364562Sgshapiro#define OI_SUBOPT 0x0002 /* option has suboptions */ 154464562Sgshapiro 154564562Sgshapirostatic struct optioninfo 154638032Speter{ 154738032Speter char *o_name; /* long name of option */ 154838032Speter u_char o_code; /* short name of option */ 154964562Sgshapiro u_short o_flags; /* option flags */ 155038032Speter} OptionTab[] = 155138032Speter{ 155264562Sgshapiro#if defined(SUN_EXTENSIONS) && defined(REMOTE_MODE) 155364562Sgshapiro { "RemoteMode", '>', OI_NONE }, 155464562Sgshapiro#endif /* defined(SUN_EXTENSIONS) && defined(REMOTE_MODE) */ 155564562Sgshapiro { "SevenBitInput", '7', OI_SAFE }, 155664562Sgshapiro { "EightBitMode", '8', OI_SAFE }, 155764562Sgshapiro { "AliasFile", 'A', OI_NONE }, 155864562Sgshapiro { "AliasWait", 'a', OI_NONE }, 155964562Sgshapiro { "BlankSub", 'B', OI_NONE }, 156064562Sgshapiro { "MinFreeBlocks", 'b', OI_SAFE }, 156164562Sgshapiro { "CheckpointInterval", 'C', OI_SAFE }, 156264562Sgshapiro { "HoldExpensive", 'c', OI_NONE }, 156364562Sgshapiro#if !_FFR_REMOVE_AUTOREBUILD 156464562Sgshapiro { "AutoRebuildAliases", 'D', OI_NONE }, 156564562Sgshapiro#endif /* !_FFR_REMOVE_AUTOREBUILD */ 156664562Sgshapiro { "DeliveryMode", 'd', OI_SAFE }, 156764562Sgshapiro { "ErrorHeader", 'E', OI_NONE }, 156864562Sgshapiro { "ErrorMode", 'e', OI_SAFE }, 156964562Sgshapiro { "TempFileMode", 'F', OI_NONE }, 157064562Sgshapiro { "SaveFromLine", 'f', OI_NONE }, 157164562Sgshapiro { "MatchGECOS", 'G', OI_NONE }, 157264562Sgshapiro { "HelpFile", 'H', OI_NONE }, 157364562Sgshapiro { "MaxHopCount", 'h', OI_NONE }, 157464562Sgshapiro { "ResolverOptions", 'I', OI_NONE }, 157564562Sgshapiro { "IgnoreDots", 'i', OI_SAFE }, 157664562Sgshapiro { "ForwardPath", 'J', OI_NONE }, 157764562Sgshapiro { "SendMimeErrors", 'j', OI_SAFE }, 157864562Sgshapiro { "ConnectionCacheSize", 'k', OI_NONE }, 157964562Sgshapiro { "ConnectionCacheTimeout", 'K', OI_NONE }, 158064562Sgshapiro { "UseErrorsTo", 'l', OI_NONE }, 158164562Sgshapiro { "LogLevel", 'L', OI_SAFE }, 158264562Sgshapiro { "MeToo", 'm', OI_SAFE }, 158364562Sgshapiro { "CheckAliases", 'n', OI_NONE }, 158464562Sgshapiro { "OldStyleHeaders", 'o', OI_SAFE }, 158564562Sgshapiro { "DaemonPortOptions", 'O', OI_NONE }, 158664562Sgshapiro { "PrivacyOptions", 'p', OI_SAFE }, 158764562Sgshapiro { "PostmasterCopy", 'P', OI_NONE }, 158864562Sgshapiro { "QueueFactor", 'q', OI_NONE }, 158964562Sgshapiro { "QueueDirectory", 'Q', OI_NONE }, 159064562Sgshapiro { "DontPruneRoutes", 'R', OI_NONE }, 159164562Sgshapiro { "Timeout", 'r', OI_SUBOPT }, 159264562Sgshapiro { "StatusFile", 'S', OI_NONE }, 159364562Sgshapiro { "SuperSafe", 's', OI_SAFE }, 159464562Sgshapiro { "QueueTimeout", 'T', OI_NONE }, 159564562Sgshapiro { "TimeZoneSpec", 't', OI_NONE }, 159664562Sgshapiro { "UserDatabaseSpec", 'U', OI_NONE }, 159764562Sgshapiro { "DefaultUser", 'u', OI_NONE }, 159864562Sgshapiro { "FallbackMXhost", 'V', OI_NONE }, 159964562Sgshapiro { "Verbose", 'v', OI_SAFE }, 160064562Sgshapiro { "TryNullMXList", 'w', OI_NONE }, 160164562Sgshapiro { "QueueLA", 'x', OI_NONE }, 160264562Sgshapiro { "RefuseLA", 'X', OI_NONE }, 160364562Sgshapiro { "RecipientFactor", 'y', OI_NONE }, 160464562Sgshapiro { "ForkEachJob", 'Y', OI_NONE }, 160564562Sgshapiro { "ClassFactor", 'z', OI_NONE }, 160664562Sgshapiro { "RetryFactor", 'Z', OI_NONE }, 160738032Speter#define O_QUEUESORTORD 0x81 160864562Sgshapiro { "QueueSortOrder", O_QUEUESORTORD, OI_SAFE }, 160938032Speter#define O_HOSTSFILE 0x82 161064562Sgshapiro { "HostsFile", O_HOSTSFILE, OI_NONE }, 161138032Speter#define O_MQA 0x83 161264562Sgshapiro { "MinQueueAge", O_MQA, OI_SAFE }, 161338032Speter#define O_DEFCHARSET 0x85 161464562Sgshapiro { "DefaultCharSet", O_DEFCHARSET, OI_SAFE }, 161538032Speter#define O_SSFILE 0x86 161664562Sgshapiro { "ServiceSwitchFile", O_SSFILE, OI_NONE }, 161738032Speter#define O_DIALDELAY 0x87 161864562Sgshapiro { "DialDelay", O_DIALDELAY, OI_SAFE }, 161938032Speter#define O_NORCPTACTION 0x88 162064562Sgshapiro { "NoRecipientAction", O_NORCPTACTION, OI_SAFE }, 162138032Speter#define O_SAFEFILEENV 0x89 162264562Sgshapiro { "SafeFileEnvironment", O_SAFEFILEENV, OI_NONE }, 162338032Speter#define O_MAXMSGSIZE 0x8a 162464562Sgshapiro { "MaxMessageSize", O_MAXMSGSIZE, OI_NONE }, 162538032Speter#define O_COLONOKINADDR 0x8b 162664562Sgshapiro { "ColonOkInAddr", O_COLONOKINADDR, OI_SAFE }, 162738032Speter#define O_MAXQUEUERUN 0x8c 162864562Sgshapiro { "MaxQueueRunSize", O_MAXQUEUERUN, OI_SAFE }, 162938032Speter#define O_MAXCHILDREN 0x8d 163064562Sgshapiro { "MaxDaemonChildren", O_MAXCHILDREN, OI_NONE }, 163138032Speter#define O_KEEPCNAMES 0x8e 163264562Sgshapiro { "DontExpandCnames", O_KEEPCNAMES, OI_NONE }, 163338032Speter#define O_MUSTQUOTE 0x8f 163464562Sgshapiro { "MustQuoteChars", O_MUSTQUOTE, OI_NONE }, 163538032Speter#define O_SMTPGREETING 0x90 163664562Sgshapiro { "SmtpGreetingMessage", O_SMTPGREETING, OI_NONE }, 163738032Speter#define O_UNIXFROM 0x91 163864562Sgshapiro { "UnixFromLine", O_UNIXFROM, OI_NONE }, 163938032Speter#define O_OPCHARS 0x92 164064562Sgshapiro { "OperatorChars", O_OPCHARS, OI_NONE }, 164138032Speter#define O_DONTINITGRPS 0x93 164264562Sgshapiro { "DontInitGroups", O_DONTINITGRPS, OI_NONE }, 164338032Speter#define O_SLFH 0x94 164464562Sgshapiro { "SingleLineFromHeader", O_SLFH, OI_SAFE }, 164538032Speter#define O_ABH 0x95 164664562Sgshapiro { "AllowBogusHELO", O_ABH, OI_SAFE }, 164738032Speter#define O_CONNTHROT 0x97 164864562Sgshapiro { "ConnectionRateThrottle", O_CONNTHROT, OI_NONE }, 164938032Speter#define O_UGW 0x99 165064562Sgshapiro { "UnsafeGroupWrites", O_UGW, OI_NONE }, 165138032Speter#define O_DBLBOUNCE 0x9a 165264562Sgshapiro { "DoubleBounceAddress", O_DBLBOUNCE, OI_NONE }, 165338032Speter#define O_HSDIR 0x9b 165464562Sgshapiro { "HostStatusDirectory", O_HSDIR, OI_NONE }, 165538032Speter#define O_SINGTHREAD 0x9c 165664562Sgshapiro { "SingleThreadDelivery", O_SINGTHREAD, OI_NONE }, 165738032Speter#define O_RUNASUSER 0x9d 165864562Sgshapiro { "RunAsUser", O_RUNASUSER, OI_NONE }, 165938032Speter#define O_DSN_RRT 0x9e 166064562Sgshapiro { "RrtImpliesDsn", O_DSN_RRT, OI_NONE }, 166138032Speter#define O_PIDFILE 0x9f 166264562Sgshapiro { "PidFile", O_PIDFILE, OI_NONE }, 166338032Speter#define O_DONTBLAMESENDMAIL 0xa0 166464562Sgshapiro { "DontBlameSendmail", O_DONTBLAMESENDMAIL, OI_NONE }, 166538032Speter#define O_DPI 0xa1 166664562Sgshapiro { "DontProbeInterfaces", O_DPI, OI_NONE }, 166738032Speter#define O_MAXRCPT 0xa2 166864562Sgshapiro { "MaxRecipientsPerMessage", O_MAXRCPT, OI_SAFE }, 166938032Speter#define O_DEADLETTER 0xa3 167064562Sgshapiro { "DeadLetterDrop", O_DEADLETTER, OI_NONE }, 167138032Speter#if _FFR_DONTLOCKFILESFORREAD_OPTION 167264562Sgshapiro# define O_DONTLOCK 0xa4 167364562Sgshapiro { "DontLockFilesForRead", O_DONTLOCK, OI_NONE }, 167464562Sgshapiro#endif /* _FFR_DONTLOCKFILESFORREAD_OPTION */ 167538032Speter#define O_MAXALIASRCSN 0xa5 167664562Sgshapiro { "MaxAliasRecursion", O_MAXALIASRCSN, OI_NONE }, 167738032Speter#define O_CNCTONLYTO 0xa6 167864562Sgshapiro { "ConnectOnlyTo", O_CNCTONLYTO, OI_NONE }, 167942575Speter#define O_TRUSTUSER 0xa7 168064562Sgshapiro { "TrustedUser", O_TRUSTUSER, OI_NONE }, 168142575Speter#define O_MAXMIMEHDRLEN 0xa8 168264562Sgshapiro { "MaxMimeHeaderLength", O_MAXMIMEHDRLEN, OI_NONE }, 168342575Speter#define O_CONTROLSOCKET 0xa9 168464562Sgshapiro { "ControlSocketName", O_CONTROLSOCKET, OI_NONE }, 168543730Speter#define O_MAXHDRSLEN 0xaa 168664562Sgshapiro { "MaxHeadersLength", O_MAXHDRSLEN, OI_NONE }, 168764562Sgshapiro#if _FFR_MAX_FORWARD_ENTRIES 168864562Sgshapiro# define O_MAXFORWARD 0xab 168964562Sgshapiro { "MaxForwardEntries", O_MAXFORWARD, OI_NONE }, 169064562Sgshapiro#endif /* _FFR_MAX_FORWARD_ENTRIES */ 169164562Sgshapiro#define O_PROCTITLEPREFIX 0xac 169264562Sgshapiro { "ProcessTitlePrefix", O_PROCTITLEPREFIX, OI_NONE }, 169364562Sgshapiro#define O_SASLINFO 0xad 169464562Sgshapiro#if _FFR_ALLOW_SASLINFO 169564562Sgshapiro { "DefaultAuthInfo", O_SASLINFO, OI_SAFE }, 169664562Sgshapiro#else /* _FFR_ALLOW_SASLINFO */ 169764562Sgshapiro { "DefaultAuthInfo", O_SASLINFO, OI_NONE }, 169864562Sgshapiro#endif /* _FFR_ALLOW_SASLINFO */ 169964562Sgshapiro#define O_SASLMECH 0xae 170064562Sgshapiro { "AuthMechanisms", O_SASLMECH, OI_NONE }, 170164562Sgshapiro#define O_CLIENTPORT 0xaf 170264562Sgshapiro { "ClientPortOptions", O_CLIENTPORT, OI_NONE }, 170364562Sgshapiro#define O_DF_BUFSIZE 0xb0 170464562Sgshapiro { "DataFileBufferSize", O_DF_BUFSIZE, OI_NONE }, 170564562Sgshapiro#define O_XF_BUFSIZE 0xb1 170664562Sgshapiro { "XscriptFileBufferSize", O_XF_BUFSIZE, OI_NONE }, 170764562Sgshapiro# define O_LDAPDEFAULTSPEC 0xb2 170864562Sgshapiro { "LDAPDefaultSpec", O_LDAPDEFAULTSPEC, OI_NONE }, 170964562Sgshapiro#if _FFR_QUEUEDELAY 171064562Sgshapiro#define O_QUEUEDELAY 0xb3 171164562Sgshapiro { "QueueDelay", O_QUEUEDELAY, OI_NONE }, 171264562Sgshapiro#endif /* _FFR_QUEUEDELAY */ 171364562Sgshapiro# define O_SRVCERTFILE 0xb4 171464562Sgshapiro { "ServerCertFile", O_SRVCERTFILE, OI_NONE }, 171564562Sgshapiro# define O_SRVKEYFILE 0xb5 171664562Sgshapiro { "Serverkeyfile", O_SRVKEYFILE, OI_NONE }, 171764562Sgshapiro# define O_CLTCERTFILE 0xb6 171864562Sgshapiro { "ClientCertFile", O_CLTCERTFILE, OI_NONE }, 171964562Sgshapiro# define O_CLTKEYFILE 0xb7 172064562Sgshapiro { "Clientkeyfile", O_CLTKEYFILE, OI_NONE }, 172164562Sgshapiro# define O_CACERTFILE 0xb8 172264562Sgshapiro { "CACERTFile", O_CACERTFILE, OI_NONE }, 172364562Sgshapiro# define O_CACERTPATH 0xb9 172464562Sgshapiro { "CACERTPath", O_CACERTPATH, OI_NONE }, 172564562Sgshapiro# define O_DHPARAMS 0xba 172664562Sgshapiro { "DHParameters", O_DHPARAMS, OI_NONE }, 172764562Sgshapiro#if _FFR_MILTER 172864562Sgshapiro#define O_INPUTMILTER 0xbb 172964562Sgshapiro { "InputMailFilters", O_INPUTMILTER, OI_NONE }, 173064562Sgshapiro#define O_MILTER 0xbc 173164562Sgshapiro { "Milter", O_MILTER, OI_SUBOPT }, 173264562Sgshapiro#endif /* _FFR_MILTER */ 173364562Sgshapiro#define O_SASLOPTS 0xbd 173464562Sgshapiro { "AuthOptions", O_SASLOPTS, OI_NONE }, 173564562Sgshapiro#if _FFR_QUEUE_FILE_MODE 173664562Sgshapiro#define O_QUEUE_FILE_MODE 0xbe 173764562Sgshapiro { "QueueFileMode", O_QUEUE_FILE_MODE, OI_NONE }, 173864562Sgshapiro#endif /* _FFR_QUEUE_FILE_MODE */ 173964562Sgshapiro# if _FFR_TLS_1 174064562Sgshapiro# define O_DHPARAMS5 0xbf 174164562Sgshapiro { "DHParameters512", O_DHPARAMS5, OI_NONE }, 174264562Sgshapiro# define O_CIPHERLIST 0xc0 174364562Sgshapiro { "CipherList", O_CIPHERLIST, OI_NONE }, 174464562Sgshapiro# endif /* _FFR_TLS_1 */ 174564562Sgshapiro# define O_RANDFILE 0xc1 174664562Sgshapiro { "RandFile", O_RANDFILE, OI_NONE }, 174764562Sgshapiro { NULL, '\0', OI_NONE } 174838032Speter}; 174938032Speter 175038032Spetervoid 175138032Spetersetoption(opt, val, safe, sticky, e) 175238032Speter int opt; 175338032Speter char *val; 175438032Speter bool safe; 175538032Speter bool sticky; 175638032Speter register ENVELOPE *e; 175738032Speter{ 175838032Speter register char *p; 175938032Speter register struct optioninfo *o; 176038032Speter char *subopt; 176138032Speter int mid; 176238032Speter bool can_setuid = RunAsUid == 0; 176338032Speter auto char *ep; 176438032Speter char buf[50]; 176538032Speter extern bool Warn_Q_option; 176664562Sgshapiro#if _FFR_ALLOW_SASLINFO 176764562Sgshapiro extern int SubmitMode; 176864562Sgshapiro#endif /* _FFR_ALLOW_SASLINFO */ 176938032Speter 177038032Speter errno = 0; 177138032Speter if (opt == ' ') 177238032Speter { 177338032Speter /* full word options */ 177438032Speter struct optioninfo *sel; 177538032Speter 177638032Speter p = strchr(val, '='); 177738032Speter if (p == NULL) 177838032Speter p = &val[strlen(val)]; 177938032Speter while (*--p == ' ') 178038032Speter continue; 178138032Speter while (*++p == ' ') 178238032Speter *p = '\0'; 178338032Speter if (p == val) 178438032Speter { 178538032Speter syserr("readcf: null option name"); 178638032Speter return; 178738032Speter } 178838032Speter if (*p == '=') 178938032Speter *p++ = '\0'; 179038032Speter while (*p == ' ') 179138032Speter p++; 179238032Speter subopt = strchr(val, '.'); 179338032Speter if (subopt != NULL) 179438032Speter *subopt++ = '\0'; 179538032Speter sel = NULL; 179638032Speter for (o = OptionTab; o->o_name != NULL; o++) 179738032Speter { 179838032Speter if (strncasecmp(o->o_name, val, strlen(val)) != 0) 179938032Speter continue; 180038032Speter if (strlen(o->o_name) == strlen(val)) 180138032Speter { 180238032Speter /* completely specified -- this must be it */ 180338032Speter sel = NULL; 180438032Speter break; 180538032Speter } 180638032Speter if (sel != NULL) 180738032Speter break; 180838032Speter sel = o; 180938032Speter } 181038032Speter if (sel != NULL && o->o_name == NULL) 181138032Speter o = sel; 181238032Speter else if (o->o_name == NULL) 181338032Speter { 181438032Speter syserr("readcf: unknown option name %s", val); 181538032Speter return; 181638032Speter } 181738032Speter else if (sel != NULL) 181838032Speter { 181938032Speter syserr("readcf: ambiguous option name %s (matches %s and %s)", 182038032Speter val, sel->o_name, o->o_name); 182138032Speter return; 182238032Speter } 182338032Speter if (strlen(val) != strlen(o->o_name)) 182438032Speter { 182538032Speter int oldVerbose = Verbose; 182638032Speter 182738032Speter Verbose = 1; 182838032Speter message("Option %s used as abbreviation for %s", 182938032Speter val, o->o_name); 183038032Speter Verbose = oldVerbose; 183138032Speter } 183238032Speter opt = o->o_code; 183338032Speter val = p; 183438032Speter } 183538032Speter else 183638032Speter { 183738032Speter for (o = OptionTab; o->o_name != NULL; o++) 183838032Speter { 183938032Speter if (o->o_code == opt) 184038032Speter break; 184138032Speter } 184238032Speter subopt = NULL; 184338032Speter } 184438032Speter 184564562Sgshapiro if (subopt != NULL && !bitset(OI_SUBOPT, o->o_flags)) 184664562Sgshapiro { 184764562Sgshapiro if (tTd(37, 1)) 184864562Sgshapiro dprintf("setoption: %s does not support suboptions, ignoring .%s\n", 184964562Sgshapiro o->o_name == NULL ? "<unknown>" : o->o_name, 185064562Sgshapiro subopt); 185164562Sgshapiro subopt = NULL; 185264562Sgshapiro } 185364562Sgshapiro 185438032Speter if (tTd(37, 1)) 185538032Speter { 185664562Sgshapiro dprintf(isascii(opt) && isprint(opt) ? 185764562Sgshapiro "setoption %s (%c)%s%s=" : 185864562Sgshapiro "setoption %s (0x%x)%s%s=", 185938032Speter o->o_name == NULL ? "<unknown>" : o->o_name, 186038032Speter opt, 186164562Sgshapiro subopt == NULL ? "" : ".", 186238032Speter subopt == NULL ? "" : subopt); 186338032Speter xputs(val); 186438032Speter } 186538032Speter 186638032Speter /* 186738032Speter ** See if this option is preset for us. 186838032Speter */ 186938032Speter 187038032Speter if (!sticky && bitnset(opt, StickyOpt)) 187138032Speter { 187238032Speter if (tTd(37, 1)) 187364562Sgshapiro dprintf(" (ignored)\n"); 187438032Speter return; 187538032Speter } 187638032Speter 187738032Speter /* 187838032Speter ** Check to see if this option can be specified by this user. 187938032Speter */ 188038032Speter 188138032Speter if (!safe && RealUid == 0) 188238032Speter safe = TRUE; 188364562Sgshapiro if (!safe && !bitset(OI_SAFE, o->o_flags)) 188438032Speter { 188538032Speter if (opt != 'M' || (val[0] != 'r' && val[0] != 's')) 188638032Speter { 188764562Sgshapiro int dp; 188864562Sgshapiro 188938032Speter if (tTd(37, 1)) 189064562Sgshapiro dprintf(" (unsafe)"); 189164562Sgshapiro dp = drop_privileges(TRUE); 189264562Sgshapiro setstat(dp); 189338032Speter } 189438032Speter } 189538032Speter if (tTd(37, 1)) 189664562Sgshapiro dprintf("\n"); 189738032Speter 189838032Speter switch (opt & 0xff) 189938032Speter { 190038032Speter case '7': /* force seven-bit input */ 190138032Speter SevenBitInput = atobool(val); 190238032Speter break; 190338032Speter 190477349Sgshapiro case '8': /* handling of 8-bit input */ 190538032Speter#if MIME8TO7 190638032Speter switch (*val) 190738032Speter { 190838032Speter case 'm': /* convert 8-bit, convert MIME */ 190938032Speter MimeMode = MM_CVTMIME|MM_MIME8BIT; 191038032Speter break; 191138032Speter 191238032Speter case 'p': /* pass 8 bit, convert MIME */ 191338032Speter MimeMode = MM_CVTMIME|MM_PASS8BIT; 191438032Speter break; 191538032Speter 191638032Speter case 's': /* strict adherence */ 191738032Speter MimeMode = MM_CVTMIME; 191838032Speter break; 191938032Speter 192064562Sgshapiro# if 0 192138032Speter case 'r': /* reject 8-bit, don't convert MIME */ 192238032Speter MimeMode = 0; 192338032Speter break; 192438032Speter 192538032Speter case 'j': /* "just send 8" */ 192638032Speter MimeMode = MM_PASS8BIT; 192738032Speter break; 192838032Speter 192938032Speter case 'a': /* encode 8 bit if available */ 193038032Speter MimeMode = MM_MIME8BIT|MM_PASS8BIT|MM_CVTMIME; 193138032Speter break; 193238032Speter 193338032Speter case 'c': /* convert 8 bit to MIME, never 7 bit */ 193438032Speter MimeMode = MM_MIME8BIT; 193538032Speter break; 193664562Sgshapiro# endif /* 0 */ 193738032Speter 193838032Speter default: 193938032Speter syserr("Unknown 8-bit mode %c", *val); 194042575Speter finis(FALSE, EX_USAGE); 194138032Speter } 194277349Sgshapiro#else /* MIME8TO7 */ 194377349Sgshapiro printf("Warning: Option EightBitMode requires MIME8TO7 support\n"); 194477349Sgshapiro#endif /* MIME8TO7 */ 194538032Speter break; 194638032Speter 194738032Speter case 'A': /* set default alias file */ 194838032Speter if (val[0] == '\0') 194938032Speter setalias("aliases"); 195038032Speter else 195138032Speter setalias(val); 195238032Speter break; 195338032Speter 195438032Speter case 'a': /* look N minutes for "@:@" in alias file */ 195538032Speter if (val[0] == '\0') 195638032Speter SafeAlias = 5 * 60; /* five minutes */ 195738032Speter else 195838032Speter SafeAlias = convtime(val, 'm'); 195938032Speter break; 196038032Speter 196138032Speter case 'B': /* substitution for blank character */ 196238032Speter SpaceSub = val[0]; 196338032Speter if (SpaceSub == '\0') 196438032Speter SpaceSub = ' '; 196538032Speter break; 196638032Speter 196738032Speter case 'b': /* min blocks free on queue fs/max msg size */ 196838032Speter p = strchr(val, '/'); 196938032Speter if (p != NULL) 197038032Speter { 197138032Speter *p++ = '\0'; 197238032Speter MaxMessageSize = atol(p); 197338032Speter } 197438032Speter MinBlocksFree = atol(val); 197538032Speter break; 197638032Speter 197738032Speter case 'c': /* don't connect to "expensive" mailers */ 197838032Speter NoConnect = atobool(val); 197938032Speter break; 198038032Speter 198138032Speter case 'C': /* checkpoint every N addresses */ 198238032Speter CheckpointInterval = atoi(val); 198338032Speter break; 198438032Speter 198538032Speter case 'd': /* delivery mode */ 198638032Speter switch (*val) 198738032Speter { 198838032Speter case '\0': 198964562Sgshapiro set_delivery_mode(SM_DELIVER, e); 199038032Speter break; 199138032Speter 199238032Speter case SM_QUEUE: /* queue only */ 199338032Speter case SM_DEFER: /* queue only and defer map lookups */ 199438032Speter#if !QUEUE 199538032Speter syserr("need QUEUE to set -odqueue or -oddefer"); 199671345Sgshapiro break; 199764562Sgshapiro#endif /* !QUEUE */ 199864562Sgshapiro /* FALLTHROUGH */ 199938032Speter 200038032Speter case SM_DELIVER: /* do everything */ 200138032Speter case SM_FORK: /* fork after verification */ 200264562Sgshapiro set_delivery_mode(*val, e); 200338032Speter break; 200438032Speter 200538032Speter default: 200638032Speter syserr("Unknown delivery mode %c", *val); 200742575Speter finis(FALSE, EX_USAGE); 200838032Speter } 200938032Speter break; 201038032Speter 201164562Sgshapiro#if !_FFR_REMOVE_AUTOREBUILD 201238032Speter case 'D': /* rebuild alias database as needed */ 201338032Speter AutoRebuild = atobool(val); 201438032Speter break; 201564562Sgshapiro#endif /* !_FFR_REMOVE_AUTOREBUILD */ 201638032Speter 201738032Speter case 'E': /* error message header/header file */ 201838032Speter if (*val != '\0') 201938032Speter ErrMsgFile = newstr(val); 202038032Speter break; 202138032Speter 202238032Speter case 'e': /* set error processing mode */ 202338032Speter switch (*val) 202438032Speter { 202538032Speter case EM_QUIET: /* be silent about it */ 202638032Speter case EM_MAIL: /* mail back */ 202738032Speter case EM_BERKNET: /* do berknet error processing */ 202838032Speter case EM_WRITE: /* write back (or mail) */ 202938032Speter case EM_PRINT: /* print errors normally (default) */ 203038032Speter e->e_errormode = *val; 203138032Speter break; 203238032Speter } 203338032Speter break; 203438032Speter 203538032Speter case 'F': /* file mode */ 203638032Speter FileMode = atooct(val) & 0777; 203738032Speter break; 203838032Speter 203938032Speter case 'f': /* save Unix-style From lines on front */ 204038032Speter SaveFrom = atobool(val); 204138032Speter break; 204238032Speter 204338032Speter case 'G': /* match recipients against GECOS field */ 204438032Speter MatchGecos = atobool(val); 204538032Speter break; 204638032Speter 204738032Speter case 'g': /* default gid */ 204838032Speter g_opt: 204938032Speter if (isascii(*val) && isdigit(*val)) 205038032Speter DefGid = atoi(val); 205138032Speter else 205238032Speter { 205338032Speter register struct group *gr; 205438032Speter 205538032Speter DefGid = -1; 205638032Speter gr = getgrnam(val); 205738032Speter if (gr == NULL) 205838032Speter syserr("readcf: option %c: unknown group %s", 205938032Speter opt, val); 206038032Speter else 206138032Speter DefGid = gr->gr_gid; 206238032Speter } 206338032Speter break; 206438032Speter 206538032Speter case 'H': /* help file */ 206638032Speter if (val[0] == '\0') 206764562Sgshapiro HelpFile = "helpfile"; 206838032Speter else 206973188Sgshapiro { 207038032Speter HelpFile = newstr(val); 207173188Sgshapiro } 207238032Speter break; 207338032Speter 207438032Speter case 'h': /* maximum hop count */ 207538032Speter MaxHopCount = atoi(val); 207638032Speter break; 207738032Speter 207838032Speter case 'I': /* use internet domain name server */ 207938032Speter#if NAMED_BIND 208038032Speter for (p = val; *p != 0; ) 208138032Speter { 208238032Speter bool clearmode; 208338032Speter char *q; 208438032Speter struct resolverflags *rfp; 208538032Speter 208638032Speter while (*p == ' ') 208738032Speter p++; 208838032Speter if (*p == '\0') 208938032Speter break; 209038032Speter clearmode = FALSE; 209138032Speter if (*p == '-') 209238032Speter clearmode = TRUE; 209338032Speter else if (*p != '+') 209438032Speter p--; 209538032Speter p++; 209638032Speter q = p; 209738032Speter while (*p != '\0' && !(isascii(*p) && isspace(*p))) 209838032Speter p++; 209938032Speter if (*p != '\0') 210038032Speter *p++ = '\0'; 210138032Speter if (strcasecmp(q, "HasWildcardMX") == 0) 210238032Speter { 210338032Speter HasWildcardMX = !clearmode; 210438032Speter continue; 210538032Speter } 210673188Sgshapiro#if _FFR_WORKAROUND_BROKEN_NAMESERVERS 210773188Sgshapiro if (sm_strcasecmp(q, "WorkAroundBrokenAAAA") == 0) 210873188Sgshapiro { 210973188Sgshapiro WorkAroundBrokenAAAA = !clearmode; 211073188Sgshapiro continue; 211173188Sgshapiro } 211273188Sgshapiro#endif /* _FFR_WORKAROUND_BROKEN_NAMESERVERS */ 211338032Speter for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++) 211438032Speter { 211538032Speter if (strcasecmp(q, rfp->rf_name) == 0) 211638032Speter break; 211738032Speter } 211838032Speter if (rfp->rf_name == NULL) 211938032Speter syserr("readcf: I option value %s unrecognized", q); 212038032Speter else if (clearmode) 212138032Speter _res.options &= ~rfp->rf_bits; 212238032Speter else 212338032Speter _res.options |= rfp->rf_bits; 212438032Speter } 212538032Speter if (tTd(8, 2)) 212664562Sgshapiro dprintf("_res.options = %x, HasWildcardMX = %d\n", 212738032Speter (u_int) _res.options, HasWildcardMX); 212864562Sgshapiro#else /* NAMED_BIND */ 212938032Speter usrerr("name server (I option) specified but BIND not compiled in"); 213064562Sgshapiro#endif /* NAMED_BIND */ 213138032Speter break; 213238032Speter 213338032Speter case 'i': /* ignore dot lines in message */ 213438032Speter IgnrDot = atobool(val); 213538032Speter break; 213638032Speter 213738032Speter case 'j': /* send errors in MIME (RFC 1341) format */ 213838032Speter SendMIMEErrors = atobool(val); 213938032Speter break; 214038032Speter 214138032Speter case 'J': /* .forward search path */ 214238032Speter ForwardPath = newstr(val); 214338032Speter break; 214438032Speter 214538032Speter case 'k': /* connection cache size */ 214638032Speter MaxMciCache = atoi(val); 214738032Speter if (MaxMciCache < 0) 214838032Speter MaxMciCache = 0; 214938032Speter break; 215038032Speter 215138032Speter case 'K': /* connection cache timeout */ 215238032Speter MciCacheTimeout = convtime(val, 'm'); 215338032Speter break; 215438032Speter 215538032Speter case 'l': /* use Errors-To: header */ 215638032Speter UseErrorsTo = atobool(val); 215738032Speter break; 215838032Speter 215938032Speter case 'L': /* log level */ 216038032Speter if (safe || LogLevel < atoi(val)) 216138032Speter LogLevel = atoi(val); 216238032Speter break; 216338032Speter 216438032Speter case 'M': /* define macro */ 216571345Sgshapiro sticky = FALSE; 216638032Speter mid = macid(val, &ep); 216771345Sgshapiro if (mid == 0) 216871345Sgshapiro break; 216938032Speter p = newstr(ep); 217038032Speter if (!safe) 217138032Speter cleanstrcpy(p, p, MAXNAME); 217238032Speter define(mid, p, CurEnv); 217338032Speter break; 217438032Speter 217538032Speter case 'm': /* send to me too */ 217638032Speter MeToo = atobool(val); 217738032Speter break; 217838032Speter 217938032Speter case 'n': /* validate RHS in newaliases */ 218038032Speter CheckAliases = atobool(val); 218138032Speter break; 218238032Speter 218338032Speter /* 'N' available -- was "net name" */ 218438032Speter 218538032Speter case 'O': /* daemon options */ 218638032Speter#if DAEMON 218764562Sgshapiro if (!setdaemonoptions(val)) 218864562Sgshapiro syserr("too many daemons defined (%d max)", MAXDAEMONS); 218964562Sgshapiro#else /* DAEMON */ 219038032Speter syserr("DaemonPortOptions (O option) set but DAEMON not compiled in"); 219164562Sgshapiro#endif /* DAEMON */ 219238032Speter break; 219338032Speter 219438032Speter case 'o': /* assume old style headers */ 219538032Speter if (atobool(val)) 219638032Speter CurEnv->e_flags |= EF_OLDSTYLE; 219738032Speter else 219838032Speter CurEnv->e_flags &= ~EF_OLDSTYLE; 219938032Speter break; 220038032Speter 220138032Speter case 'p': /* select privacy level */ 220238032Speter p = val; 220338032Speter for (;;) 220438032Speter { 220538032Speter register struct prival *pv; 220638032Speter extern struct prival PrivacyValues[]; 220738032Speter 220838032Speter while (isascii(*p) && (isspace(*p) || ispunct(*p))) 220938032Speter p++; 221038032Speter if (*p == '\0') 221138032Speter break; 221238032Speter val = p; 221338032Speter while (isascii(*p) && isalnum(*p)) 221438032Speter p++; 221538032Speter if (*p != '\0') 221638032Speter *p++ = '\0'; 221738032Speter 221838032Speter for (pv = PrivacyValues; pv->pv_name != NULL; pv++) 221938032Speter { 222038032Speter if (strcasecmp(val, pv->pv_name) == 0) 222138032Speter break; 222238032Speter } 222338032Speter if (pv->pv_name == NULL) 222438032Speter syserr("readcf: Op line: %s unrecognized", val); 222571345Sgshapiro else 222671345Sgshapiro PrivacyFlags |= pv->pv_flag; 222738032Speter } 222838032Speter sticky = FALSE; 222938032Speter break; 223038032Speter 223138032Speter case 'P': /* postmaster copy address for returned mail */ 223238032Speter PostMasterCopy = newstr(val); 223338032Speter break; 223438032Speter 223538032Speter case 'q': /* slope of queue only function */ 223638032Speter QueueFactor = atoi(val); 223738032Speter break; 223838032Speter 223938032Speter case 'Q': /* queue directory */ 224038032Speter if (val[0] == '\0') 224166494Sgshapiro { 224238032Speter QueueDir = "mqueue"; 224366494Sgshapiro } 224438032Speter else 224566494Sgshapiro { 224638032Speter QueueDir = newstr(val); 224766494Sgshapiro } 224838032Speter if (RealUid != 0 && !safe) 224938032Speter Warn_Q_option = TRUE; 225038032Speter break; 225138032Speter 225238032Speter case 'R': /* don't prune routes */ 225338032Speter DontPruneRoutes = atobool(val); 225438032Speter break; 225538032Speter 225638032Speter case 'r': /* read timeout */ 225738032Speter if (subopt == NULL) 225864562Sgshapiro inittimeouts(val, sticky); 225938032Speter else 226064562Sgshapiro settimeout(subopt, val, sticky); 226138032Speter break; 226238032Speter 226338032Speter case 'S': /* status file */ 226438032Speter if (val[0] == '\0') 226564562Sgshapiro StatFile = "statistics"; 226638032Speter else 226773188Sgshapiro { 226838032Speter StatFile = newstr(val); 226973188Sgshapiro } 227038032Speter break; 227138032Speter 227238032Speter case 's': /* be super safe, even if expensive */ 227338032Speter SuperSafe = atobool(val); 227438032Speter break; 227538032Speter 227638032Speter case 'T': /* queue timeout */ 227738032Speter p = strchr(val, '/'); 227838032Speter if (p != NULL) 227938032Speter { 228038032Speter *p++ = '\0'; 228164562Sgshapiro settimeout("queuewarn", p, sticky); 228238032Speter } 228364562Sgshapiro settimeout("queuereturn", val, sticky); 228438032Speter break; 228538032Speter 228638032Speter case 't': /* time zone name */ 228738032Speter TimeZoneSpec = newstr(val); 228838032Speter break; 228938032Speter 229038032Speter case 'U': /* location of user database */ 229138032Speter UdbSpec = newstr(val); 229238032Speter break; 229338032Speter 229438032Speter case 'u': /* set default uid */ 229538032Speter for (p = val; *p != '\0'; p++) 229638032Speter { 229738032Speter if (*p == '.' || *p == '/' || *p == ':') 229838032Speter { 229938032Speter *p++ = '\0'; 230038032Speter break; 230138032Speter } 230238032Speter } 230338032Speter if (isascii(*val) && isdigit(*val)) 230438032Speter { 230538032Speter DefUid = atoi(val); 230638032Speter setdefuser(); 230738032Speter } 230838032Speter else 230938032Speter { 231038032Speter register struct passwd *pw; 231138032Speter 231238032Speter DefUid = -1; 231338032Speter pw = sm_getpwnam(val); 231438032Speter if (pw == NULL) 231571345Sgshapiro { 231638032Speter syserr("readcf: option u: unknown user %s", val); 231771345Sgshapiro break; 231871345Sgshapiro } 231938032Speter else 232038032Speter { 232138032Speter DefUid = pw->pw_uid; 232238032Speter DefGid = pw->pw_gid; 232338032Speter DefUser = newstr(pw->pw_name); 232438032Speter } 232538032Speter } 232638032Speter 232738032Speter#ifdef UID_MAX 232838032Speter if (DefUid > UID_MAX) 232938032Speter { 233038032Speter syserr("readcf: option u: uid value (%ld) > UID_MAX (%ld); ignored", 233171345Sgshapiro (long) DefUid, (long) UID_MAX); 233271345Sgshapiro break; 233338032Speter } 233464562Sgshapiro#endif /* UID_MAX */ 233538032Speter 233638032Speter /* handle the group if it is there */ 233738032Speter if (*p == '\0') 233838032Speter break; 233938032Speter val = p; 234038032Speter goto g_opt; 234138032Speter 234238032Speter case 'V': /* fallback MX host */ 234338032Speter if (val[0] != '\0') 234438032Speter FallBackMX = newstr(val); 234538032Speter break; 234638032Speter 234738032Speter case 'v': /* run in verbose mode */ 234838032Speter Verbose = atobool(val) ? 1 : 0; 234938032Speter break; 235038032Speter 235138032Speter case 'w': /* if we are best MX, try host directly */ 235238032Speter TryNullMXList = atobool(val); 235338032Speter break; 235438032Speter 235538032Speter /* 'W' available -- was wizard password */ 235638032Speter 235738032Speter case 'x': /* load avg at which to auto-queue msgs */ 235838032Speter QueueLA = atoi(val); 235938032Speter break; 236038032Speter 236138032Speter case 'X': /* load avg at which to auto-reject connections */ 236238032Speter RefuseLA = atoi(val); 236338032Speter break; 236438032Speter 236538032Speter case 'y': /* work recipient factor */ 236638032Speter WkRecipFact = atoi(val); 236738032Speter break; 236838032Speter 236938032Speter case 'Y': /* fork jobs during queue runs */ 237038032Speter ForkQueueRuns = atobool(val); 237138032Speter break; 237238032Speter 237338032Speter case 'z': /* work message class factor */ 237438032Speter WkClassFact = atoi(val); 237538032Speter break; 237638032Speter 237738032Speter case 'Z': /* work time factor */ 237838032Speter WkTimeFact = atoi(val); 237938032Speter break; 238038032Speter 238164562Sgshapiro 238238032Speter case O_QUEUESORTORD: /* queue sorting order */ 238338032Speter switch (*val) 238438032Speter { 238538032Speter case 'h': /* Host first */ 238638032Speter case 'H': 238764562Sgshapiro QueueSortOrder = QSO_BYHOST; 238838032Speter break; 238938032Speter 239038032Speter case 'p': /* Priority order */ 239138032Speter case 'P': 239264562Sgshapiro QueueSortOrder = QSO_BYPRIORITY; 239338032Speter break; 239438032Speter 239538032Speter case 't': /* Submission time */ 239638032Speter case 'T': 239764562Sgshapiro QueueSortOrder = QSO_BYTIME; 239838032Speter break; 239938032Speter 240064562Sgshapiro case 'f': /* File Name */ 240164562Sgshapiro case 'F': 240264562Sgshapiro QueueSortOrder = QSO_BYFILENAME; 240364562Sgshapiro break; 240464562Sgshapiro 240538032Speter default: 240638032Speter syserr("Invalid queue sort order \"%s\"", val); 240738032Speter } 240838032Speter break; 240938032Speter 241064562Sgshapiro#if _FFR_QUEUEDELAY 241164562Sgshapiro case O_QUEUEDELAY: /* queue delay algorithm */ 241264562Sgshapiro switch (*val) 241364562Sgshapiro { 241464562Sgshapiro case 'e': /* exponential */ 241564562Sgshapiro case 'E': 241664562Sgshapiro QueueAlg = QD_EXP; 241764562Sgshapiro QueueInitDelay = 10 MINUTES; 241864562Sgshapiro QueueMaxDelay = 2 HOURS; 241964562Sgshapiro p = strchr(val, '/'); 242064562Sgshapiro if (p != NULL) 242164562Sgshapiro { 242264562Sgshapiro char *q; 242364562Sgshapiro 242464562Sgshapiro *p++ = '\0'; 242564562Sgshapiro q = strchr(p, '/'); 242664562Sgshapiro if (q != NULL) 242764562Sgshapiro *q++ = '\0'; 242864562Sgshapiro QueueInitDelay = convtime(p, 's'); 242964562Sgshapiro if (q != NULL) 243064562Sgshapiro { 243164562Sgshapiro QueueMaxDelay = convtime(q, 's'); 243264562Sgshapiro } 243364562Sgshapiro } 243464562Sgshapiro break; 243564562Sgshapiro 243664562Sgshapiro case 'l': /* linear */ 243764562Sgshapiro case 'L': 243864562Sgshapiro QueueAlg = QD_LINEAR; 243964562Sgshapiro break; 244064562Sgshapiro 244164562Sgshapiro default: 244264562Sgshapiro syserr("Invalid queue delay algorithm \"%s\"", val); 244364562Sgshapiro } 244464562Sgshapiro break; 244564562Sgshapiro#endif /* _FFR_QUEUEDELAY */ 244664562Sgshapiro 244738032Speter case O_HOSTSFILE: /* pathname of /etc/hosts file */ 244838032Speter HostsFile = newstr(val); 244938032Speter break; 245038032Speter 245138032Speter case O_MQA: /* minimum queue age between deliveries */ 245238032Speter MinQueueAge = convtime(val, 'm'); 245338032Speter break; 245438032Speter 245538032Speter case O_DEFCHARSET: /* default character set for mimefying */ 245638032Speter DefaultCharSet = newstr(denlstring(val, TRUE, TRUE)); 245738032Speter break; 245838032Speter 245938032Speter case O_SSFILE: /* service switch file */ 246038032Speter ServiceSwitchFile = newstr(val); 246138032Speter break; 246238032Speter 246338032Speter case O_DIALDELAY: /* delay for dial-on-demand operation */ 246438032Speter DialDelay = convtime(val, 's'); 246538032Speter break; 246638032Speter 246738032Speter case O_NORCPTACTION: /* what to do if no recipient */ 246838032Speter if (strcasecmp(val, "none") == 0) 246938032Speter NoRecipientAction = NRA_NO_ACTION; 247038032Speter else if (strcasecmp(val, "add-to") == 0) 247138032Speter NoRecipientAction = NRA_ADD_TO; 247238032Speter else if (strcasecmp(val, "add-apparently-to") == 0) 247338032Speter NoRecipientAction = NRA_ADD_APPARENTLY_TO; 247438032Speter else if (strcasecmp(val, "add-bcc") == 0) 247538032Speter NoRecipientAction = NRA_ADD_BCC; 247638032Speter else if (strcasecmp(val, "add-to-undisclosed") == 0) 247738032Speter NoRecipientAction = NRA_ADD_TO_UNDISCLOSED; 247838032Speter else 247938032Speter syserr("Invalid NoRecipientAction: %s", val); 248038032Speter break; 248138032Speter 248238032Speter case O_SAFEFILEENV: /* chroot() environ for writing to files */ 248338032Speter SafeFileEnv = newstr(val); 248438032Speter break; 248538032Speter 248638032Speter case O_MAXMSGSIZE: /* maximum message size */ 248738032Speter MaxMessageSize = atol(val); 248838032Speter break; 248938032Speter 249038032Speter case O_COLONOKINADDR: /* old style handling of colon addresses */ 249138032Speter ColonOkInAddr = atobool(val); 249238032Speter break; 249338032Speter 249438032Speter case O_MAXQUEUERUN: /* max # of jobs in a single queue run */ 249538032Speter MaxQueueRun = atol(val); 249638032Speter break; 249738032Speter 249838032Speter case O_MAXCHILDREN: /* max # of children of daemon */ 249938032Speter MaxChildren = atoi(val); 250038032Speter break; 250138032Speter 250264562Sgshapiro#if _FFR_MAX_FORWARD_ENTRIES 250364562Sgshapiro case O_MAXFORWARD: /* max # of forward entries */ 250464562Sgshapiro MaxForwardEntries = atoi(val); 250564562Sgshapiro break; 250664562Sgshapiro#endif /* _FFR_MAX_FORWARD_ENTRIES */ 250764562Sgshapiro 250838032Speter case O_KEEPCNAMES: /* don't expand CNAME records */ 250938032Speter DontExpandCnames = atobool(val); 251038032Speter break; 251138032Speter 251238032Speter case O_MUSTQUOTE: /* must quote these characters in phrases */ 251364562Sgshapiro (void) strlcpy(buf, "@,;:\\()[]", sizeof buf); 251438032Speter if (strlen(val) < (SIZE_T) sizeof buf - 10) 251564562Sgshapiro (void) strlcat(buf, val, sizeof buf); 251664562Sgshapiro else 251764562Sgshapiro printf("Warning: MustQuoteChars too long, ignored.\n"); 251838032Speter MustQuoteChars = newstr(buf); 251938032Speter break; 252038032Speter 252138032Speter case O_SMTPGREETING: /* SMTP greeting message (old $e macro) */ 252238032Speter SmtpGreeting = newstr(munchstring(val, NULL, '\0')); 252338032Speter break; 252438032Speter 252538032Speter case O_UNIXFROM: /* UNIX From_ line (old $l macro) */ 252638032Speter UnixFromLine = newstr(munchstring(val, NULL, '\0')); 252738032Speter break; 252838032Speter 252938032Speter case O_OPCHARS: /* operator characters (old $o macro) */ 253064562Sgshapiro if (OperatorChars != NULL) 253164562Sgshapiro printf("Warning: OperatorChars is being redefined.\n It should only be set before ruleset definitions.\n"); 253238032Speter OperatorChars = newstr(munchstring(val, NULL, '\0')); 253338032Speter break; 253438032Speter 253538032Speter case O_DONTINITGRPS: /* don't call initgroups(3) */ 253638032Speter DontInitGroups = atobool(val); 253738032Speter break; 253838032Speter 253938032Speter case O_SLFH: /* make sure from fits on one line */ 254038032Speter SingleLineFromHeader = atobool(val); 254138032Speter break; 254238032Speter 254338032Speter case O_ABH: /* allow HELO commands with syntax errors */ 254438032Speter AllowBogusHELO = atobool(val); 254538032Speter break; 254638032Speter 254738032Speter case O_CONNTHROT: /* connection rate throttle */ 254838032Speter ConnRateThrottle = atoi(val); 254938032Speter break; 255038032Speter 255138032Speter case O_UGW: /* group writable files are unsafe */ 255238032Speter if (!atobool(val)) 255364562Sgshapiro { 255464562Sgshapiro setbitn(DBS_GROUPWRITABLEFORWARDFILESAFE, 255564562Sgshapiro DontBlameSendmail); 255664562Sgshapiro setbitn(DBS_GROUPWRITABLEINCLUDEFILESAFE, 255764562Sgshapiro DontBlameSendmail); 255864562Sgshapiro } 255938032Speter break; 256038032Speter 256138032Speter case O_DBLBOUNCE: /* address to which to send double bounces */ 256238032Speter if (val[0] != '\0') 256338032Speter DoubleBounceAddr = newstr(val); 256438032Speter else 256538032Speter syserr("readcf: option DoubleBounceAddress: value required"); 256638032Speter break; 256738032Speter 256838032Speter case O_HSDIR: /* persistent host status directory */ 256938032Speter if (val[0] != '\0') 257073188Sgshapiro { 257138032Speter HostStatDir = newstr(val); 257273188Sgshapiro } 257338032Speter break; 257438032Speter 257538032Speter case O_SINGTHREAD: /* single thread deliveries (requires hsdir) */ 257638032Speter SingleThreadDelivery = atobool(val); 257738032Speter break; 257838032Speter 257938032Speter case O_RUNASUSER: /* run bulk of code as this user */ 258038032Speter for (p = val; *p != '\0'; p++) 258138032Speter { 258238032Speter if (*p == '.' || *p == '/' || *p == ':') 258338032Speter { 258438032Speter *p++ = '\0'; 258538032Speter break; 258638032Speter } 258738032Speter } 258838032Speter if (isascii(*val) && isdigit(*val)) 258938032Speter { 259038032Speter if (can_setuid) 259138032Speter RunAsUid = atoi(val); 259238032Speter } 259338032Speter else 259438032Speter { 259538032Speter register struct passwd *pw; 259638032Speter 259738032Speter pw = sm_getpwnam(val); 259838032Speter if (pw == NULL) 259971345Sgshapiro { 260038032Speter syserr("readcf: option RunAsUser: unknown user %s", val); 260171345Sgshapiro break; 260271345Sgshapiro } 260338032Speter else if (can_setuid) 260438032Speter { 260538032Speter if (*p == '\0') 260638032Speter RunAsUserName = newstr(val); 260738032Speter RunAsUid = pw->pw_uid; 260838032Speter RunAsGid = pw->pw_gid; 260938032Speter } 261038032Speter } 261138032Speter#ifdef UID_MAX 261238032Speter if (RunAsUid > UID_MAX) 261338032Speter { 261438032Speter syserr("readcf: option RunAsUser: uid value (%ld) > UID_MAX (%ld); ignored", 261571345Sgshapiro (long) RunAsUid, (long) UID_MAX); 261671345Sgshapiro break; 261738032Speter } 261864562Sgshapiro#endif /* UID_MAX */ 261938032Speter if (*p != '\0') 262038032Speter { 262138032Speter if (isascii(*p) && isdigit(*p)) 262238032Speter { 262338032Speter if (can_setuid) 262438032Speter RunAsGid = atoi(p); 262538032Speter } 262638032Speter else 262738032Speter { 262838032Speter register struct group *gr; 262964562Sgshapiro 263038032Speter gr = getgrnam(p); 263138032Speter if (gr == NULL) 263238032Speter syserr("readcf: option RunAsUser: unknown group %s", 263338032Speter p); 263438032Speter else if (can_setuid) 263538032Speter RunAsGid = gr->gr_gid; 263638032Speter } 263738032Speter } 263838032Speter if (tTd(47, 5)) 263964562Sgshapiro dprintf("readcf: RunAsUser = %d:%d\n", 264064562Sgshapiro (int)RunAsUid, (int)RunAsGid); 264138032Speter break; 264238032Speter 264338032Speter case O_DSN_RRT: 264438032Speter RrtImpliesDsn = atobool(val); 264538032Speter break; 264638032Speter 264738032Speter case O_PIDFILE: 264864562Sgshapiro if (PidFile != NULL) 264977349Sgshapiro sm_free(PidFile); 265038032Speter PidFile = newstr(val); 265138032Speter break; 265238032Speter 265338032Speter case O_DONTBLAMESENDMAIL: 265438032Speter p = val; 265538032Speter for (;;) 265638032Speter { 265738032Speter register struct dbsval *dbs; 265838032Speter extern struct dbsval DontBlameSendmailValues[]; 265938032Speter 266038032Speter while (isascii(*p) && (isspace(*p) || ispunct(*p))) 266138032Speter p++; 266238032Speter if (*p == '\0') 266338032Speter break; 266438032Speter val = p; 266538032Speter while (isascii(*p) && isalnum(*p)) 266638032Speter p++; 266738032Speter if (*p != '\0') 266838032Speter *p++ = '\0'; 266938032Speter 267038032Speter for (dbs = DontBlameSendmailValues; 267138032Speter dbs->dbs_name != NULL; dbs++) 267238032Speter { 267338032Speter if (strcasecmp(val, dbs->dbs_name) == 0) 267438032Speter break; 267538032Speter } 267638032Speter if (dbs->dbs_name == NULL) 267738032Speter syserr("readcf: DontBlameSendmail option: %s unrecognized", val); 267838032Speter else if (dbs->dbs_flag == DBS_SAFE) 267964562Sgshapiro clrbitmap(DontBlameSendmail); 268038032Speter else 268164562Sgshapiro setbitn(dbs->dbs_flag, DontBlameSendmail); 268238032Speter } 268338032Speter sticky = FALSE; 268438032Speter break; 268538032Speter 268638032Speter case O_DPI: 268738032Speter DontProbeInterfaces = atobool(val); 268838032Speter break; 268938032Speter 269038032Speter case O_MAXRCPT: 269138032Speter MaxRcptPerMsg = atoi(val); 269238032Speter break; 269338032Speter 269438032Speter case O_DEADLETTER: 269538032Speter if (DeadLetterDrop != NULL) 269677349Sgshapiro sm_free(DeadLetterDrop); 269738032Speter DeadLetterDrop = newstr(val); 269838032Speter break; 269938032Speter 270038032Speter#if _FFR_DONTLOCKFILESFORREAD_OPTION 270138032Speter case O_DONTLOCK: 270238032Speter DontLockReadFiles = atobool(val); 270338032Speter break; 270464562Sgshapiro#endif /* _FFR_DONTLOCKFILESFORREAD_OPTION */ 270538032Speter 270638032Speter case O_MAXALIASRCSN: 270738032Speter MaxAliasRecursion = atoi(val); 270838032Speter break; 270938032Speter 271038032Speter case O_CNCTONLYTO: 271138032Speter /* XXX should probably use gethostbyname */ 271264562Sgshapiro#if NETINET || NETINET6 271364562Sgshapiro# if NETINET6 271464562Sgshapiro if (inet_addr(val) == INADDR_NONE) 271564562Sgshapiro { 271664562Sgshapiro ConnectOnlyTo.sa.sa_family = AF_INET6; 271764562Sgshapiro if (inet_pton(AF_INET6, val, 271864562Sgshapiro &ConnectOnlyTo.sin6.sin6_addr) != 1) 271964562Sgshapiro syserr("readcf: option ConnectOnlyTo: invalid IP address %s", 272064562Sgshapiro val); 272164562Sgshapiro } 272264562Sgshapiro else 272364562Sgshapiro# endif /* NETINET6 */ 272464562Sgshapiro { 272564562Sgshapiro ConnectOnlyTo.sa.sa_family = AF_INET; 272664562Sgshapiro ConnectOnlyTo.sin.sin_addr.s_addr = inet_addr(val); 272764562Sgshapiro } 272864562Sgshapiro#endif /* NETINET || NETINET6 */ 272938032Speter break; 273038032Speter 273142575Speter case O_TRUSTUSER: 273264562Sgshapiro#if HASFCHOWN 273338032Speter if (isascii(*val) && isdigit(*val)) 273442575Speter TrustedUid = atoi(val); 273538032Speter else 273638032Speter { 273738032Speter register struct passwd *pw; 273838032Speter 273942575Speter TrustedUid = 0; 274038032Speter pw = sm_getpwnam(val); 274138032Speter if (pw == NULL) 274271345Sgshapiro { 274342575Speter syserr("readcf: option TrustedUser: unknown user %s", val); 274471345Sgshapiro break; 274571345Sgshapiro } 274638032Speter else 274742575Speter TrustedUid = pw->pw_uid; 274838032Speter } 274938032Speter 275064562Sgshapiro# ifdef UID_MAX 275142575Speter if (TrustedUid > UID_MAX) 275238032Speter { 275342575Speter syserr("readcf: option TrustedUser: uid value (%ld) > UID_MAX (%ld)", 275471345Sgshapiro (long) TrustedUid, (long) UID_MAX); 275542575Speter TrustedUid = 0; 275638032Speter } 275764562Sgshapiro# endif /* UID_MAX */ 275864562Sgshapiro#else /* HASFCHOWN */ 275964562Sgshapiro syserr("readcf: option TrustedUser: can not be used on systems which do not support fchown()"); 276064562Sgshapiro#endif /* HASFCHOWN */ 276138032Speter break; 276238032Speter 276342575Speter case O_MAXMIMEHDRLEN: 276442575Speter p = strchr(val, '/'); 276542575Speter if (p != NULL) 276642575Speter *p++ = '\0'; 276742575Speter MaxMimeHeaderLength = atoi(val); 276842575Speter if (p != NULL && *p != '\0') 276942575Speter MaxMimeFieldLength = atoi(p); 277042575Speter else 277142575Speter MaxMimeFieldLength = MaxMimeHeaderLength / 2; 277242575Speter 277342575Speter if (MaxMimeHeaderLength < 0) 277442575Speter MaxMimeHeaderLength = 0; 277542575Speter else if (MaxMimeHeaderLength < 128) 277642575Speter printf("Warning: MaxMimeHeaderLength: header length limit set lower than 128\n"); 277742575Speter 277842575Speter if (MaxMimeFieldLength < 0) 277942575Speter MaxMimeFieldLength = 0; 278042575Speter else if (MaxMimeFieldLength < 40) 278142575Speter printf("Warning: MaxMimeHeaderLength: field length limit set lower than 40\n"); 278242575Speter break; 278342575Speter 278442575Speter case O_CONTROLSOCKET: 278542575Speter if (ControlSocketName != NULL) 278677349Sgshapiro sm_free(ControlSocketName); 278742575Speter ControlSocketName = newstr(val); 278842575Speter break; 278942575Speter 279043730Speter case O_MAXHDRSLEN: 279143730Speter MaxHeadersLength = atoi(val); 279243148Speter 279343730Speter if (MaxHeadersLength > 0 && 279443730Speter MaxHeadersLength < (MAXHDRSLEN / 2)) 279564562Sgshapiro printf("Warning: MaxHeadersLength: headers length limit set lower than %d\n", (MAXHDRSLEN / 2)); 279643148Speter break; 279743148Speter 279864562Sgshapiro case O_PROCTITLEPREFIX: 279964562Sgshapiro if (ProcTitlePrefix != NULL) 280077349Sgshapiro sm_free(ProcTitlePrefix); 280164562Sgshapiro ProcTitlePrefix = newstr(val); 280264562Sgshapiro break; 280364562Sgshapiro 280464562Sgshapiro#if SASL 280564562Sgshapiro case O_SASLINFO: 280664562Sgshapiro#if _FFR_ALLOW_SASLINFO 280764562Sgshapiro /* 280864562Sgshapiro ** Allow users to select their own authinfo file. 280964562Sgshapiro ** However, this is not a "perfect" solution. 281064562Sgshapiro ** If mail is queued, the authentication info 281164562Sgshapiro ** will not be used in subsequent delivery attempts. 281264562Sgshapiro ** If we really want to support this, then it has 281364562Sgshapiro ** to be stored in the queue file. 281464562Sgshapiro */ 281564562Sgshapiro if (!bitset(SUBMIT_MSA, SubmitMode) && RealUid != 0 && 281664562Sgshapiro RunAsUid != RealUid) 281764562Sgshapiro { 281864562Sgshapiro errno = 0; 281964562Sgshapiro syserr("Error: %s only allowed with -U\n", 282064562Sgshapiro o->o_name == NULL ? "<unknown>" : o->o_name); 282164562Sgshapiro ExitStat = EX_USAGE; 282264562Sgshapiro break; 282364562Sgshapiro } 282464562Sgshapiro#endif /* _FFR_ALLOW_SASLINFO */ 282564562Sgshapiro if (SASLInfo != NULL) 282677349Sgshapiro sm_free(SASLInfo); 282764562Sgshapiro SASLInfo = newstr(val); 282864562Sgshapiro break; 282964562Sgshapiro 283064562Sgshapiro case O_SASLMECH: 283164562Sgshapiro if (AuthMechanisms != NULL) 283277349Sgshapiro sm_free(AuthMechanisms); 283364562Sgshapiro if (*val != '\0') 283464562Sgshapiro AuthMechanisms = newstr(val); 283564562Sgshapiro else 283664562Sgshapiro AuthMechanisms = NULL; 283764562Sgshapiro break; 283864562Sgshapiro 283964562Sgshapiro case O_SASLOPTS: 284064562Sgshapiro while (val != NULL && *val != '\0') 284164562Sgshapiro { 284264562Sgshapiro switch(*val) 284364562Sgshapiro { 284464562Sgshapiro case 'A': 284564562Sgshapiro SASLOpts |= SASL_AUTH_AUTH; 284664562Sgshapiro break; 284764562Sgshapiro# if _FFR_SASL_OPTS 284864562Sgshapiro case 'a': 284964562Sgshapiro SASLOpts |= SASL_SEC_NOACTIVE; 285064562Sgshapiro break; 285164562Sgshapiro case 'c': 285264562Sgshapiro SASLOpts |= SASL_SEC_PASS_CREDENTIALS; 285364562Sgshapiro break; 285464562Sgshapiro case 'd': 285564562Sgshapiro SASLOpts |= SASL_SEC_NODICTIONARY; 285664562Sgshapiro break; 285764562Sgshapiro case 'f': 285864562Sgshapiro SASLOpts |= SASL_SEC_FORWARD_SECRECY; 285964562Sgshapiro break; 286064562Sgshapiro case 'p': 286164562Sgshapiro SASLOpts |= SASL_SEC_NOPLAINTEXT; 286264562Sgshapiro break; 286364562Sgshapiro case 'y': 286464562Sgshapiro SASLOpts |= SASL_SEC_NOANONYMOUS; 286564562Sgshapiro break; 286664562Sgshapiro# endif /* _FFR_SASL_OPTS */ 286764562Sgshapiro default: 286864562Sgshapiro printf("Warning: Option: %s unknown parameter '%c'\n", 286964562Sgshapiro o->o_name == NULL ? "<unknown>" 287064562Sgshapiro : o->o_name, 287164562Sgshapiro (isascii(*val) && isprint(*val)) ? *val 287264562Sgshapiro : '?'); 287364562Sgshapiro break; 287464562Sgshapiro } 287564562Sgshapiro ++val; 287664562Sgshapiro val = strpbrk(val, ", \t"); 287764562Sgshapiro if (val != NULL) 287864562Sgshapiro ++val; 287964562Sgshapiro } 288064562Sgshapiro break; 288164562Sgshapiro 288264562Sgshapiro#else /* SASL */ 288364562Sgshapiro case O_SASLINFO: 288464562Sgshapiro case O_SASLMECH: 288564562Sgshapiro case O_SASLOPTS: 288664562Sgshapiro printf("Warning: Option: %s requires SASL support (-DSASL)\n", 288764562Sgshapiro o->o_name == NULL ? "<unknown>" : o->o_name); 288864562Sgshapiro break; 288964562Sgshapiro#endif /* SASL */ 289064562Sgshapiro 289164562Sgshapiro#if STARTTLS 289264562Sgshapiro case O_SRVCERTFILE: 289364562Sgshapiro if (SrvCERTfile != NULL) 289477349Sgshapiro sm_free(SrvCERTfile); 289564562Sgshapiro SrvCERTfile = newstr(val); 289664562Sgshapiro break; 289764562Sgshapiro 289864562Sgshapiro case O_SRVKEYFILE: 289964562Sgshapiro if (Srvkeyfile != NULL) 290077349Sgshapiro sm_free(Srvkeyfile); 290164562Sgshapiro Srvkeyfile = newstr(val); 290264562Sgshapiro break; 290364562Sgshapiro 290464562Sgshapiro case O_CLTCERTFILE: 290564562Sgshapiro if (CltCERTfile != NULL) 290677349Sgshapiro sm_free(CltCERTfile); 290764562Sgshapiro CltCERTfile = newstr(val); 290864562Sgshapiro break; 290964562Sgshapiro 291064562Sgshapiro case O_CLTKEYFILE: 291164562Sgshapiro if (Cltkeyfile != NULL) 291277349Sgshapiro sm_free(Cltkeyfile); 291364562Sgshapiro Cltkeyfile = newstr(val); 291464562Sgshapiro break; 291564562Sgshapiro 291664562Sgshapiro case O_CACERTFILE: 291764562Sgshapiro if (CACERTfile != NULL) 291877349Sgshapiro sm_free(CACERTfile); 291964562Sgshapiro CACERTfile = newstr(val); 292064562Sgshapiro break; 292164562Sgshapiro 292264562Sgshapiro case O_CACERTPATH: 292364562Sgshapiro if (CACERTpath != NULL) 292477349Sgshapiro sm_free(CACERTpath); 292564562Sgshapiro CACERTpath = newstr(val); 292664562Sgshapiro break; 292764562Sgshapiro 292864562Sgshapiro case O_DHPARAMS: 292964562Sgshapiro if (DHParams != NULL) 293077349Sgshapiro sm_free(DHParams); 293164562Sgshapiro DHParams = newstr(val); 293264562Sgshapiro break; 293364562Sgshapiro 293464562Sgshapiro# if _FFR_TLS_1 293564562Sgshapiro case O_DHPARAMS5: 293664562Sgshapiro if (DHParams5 != NULL) 293777349Sgshapiro sm_free(DHParams5); 293864562Sgshapiro DHParams5 = newstr(val); 293964562Sgshapiro break; 294064562Sgshapiro 294164562Sgshapiro case O_CIPHERLIST: 294264562Sgshapiro if (CipherList != NULL) 294377349Sgshapiro sm_free(CipherList); 294464562Sgshapiro CipherList = newstr(val); 294564562Sgshapiro break; 294664562Sgshapiro# endif /* _FFR_TLS_1 */ 294764562Sgshapiro 294864562Sgshapiro case O_RANDFILE: 294964562Sgshapiro if (RandFile != NULL) 295077349Sgshapiro sm_free(RandFile); 295164562Sgshapiro RandFile= newstr(val); 295264562Sgshapiro break; 295364562Sgshapiro 295464562Sgshapiro# else /* STARTTLS */ 295564562Sgshapiro case O_SRVCERTFILE: 295664562Sgshapiro case O_SRVKEYFILE: 295764562Sgshapiro case O_CLTCERTFILE: 295864562Sgshapiro case O_CLTKEYFILE: 295964562Sgshapiro case O_CACERTFILE: 296064562Sgshapiro case O_CACERTPATH: 296164562Sgshapiro case O_DHPARAMS: 296264562Sgshapiro# if _FFR_TLS_1 296364562Sgshapiro case O_DHPARAMS5: 296464562Sgshapiro case O_CIPHERLIST: 296564562Sgshapiro# endif /* _FFR_TLS_1 */ 296664562Sgshapiro case O_RANDFILE: 296764562Sgshapiro printf("Warning: Option: %s requires TLS support\n", 296864562Sgshapiro o->o_name == NULL ? "<unknown>" : o->o_name); 296964562Sgshapiro break; 297064562Sgshapiro 297164562Sgshapiro# endif /* STARTTLS */ 297264562Sgshapiro 297364562Sgshapiro case O_CLIENTPORT: 297464562Sgshapiro#if DAEMON 297564562Sgshapiro setclientoptions(val); 297664562Sgshapiro#else /* DAEMON */ 297764562Sgshapiro syserr("ClientPortOptions (O option) set but DAEMON not compiled in"); 297864562Sgshapiro#endif /* DAEMON */ 297964562Sgshapiro break; 298064562Sgshapiro 298164562Sgshapiro case O_DF_BUFSIZE: 298264562Sgshapiro DataFileBufferSize = atoi(val); 298364562Sgshapiro break; 298464562Sgshapiro 298564562Sgshapiro case O_XF_BUFSIZE: 298664562Sgshapiro XscriptFileBufferSize = atoi(val); 298764562Sgshapiro break; 298864562Sgshapiro 298964562Sgshapiro case O_LDAPDEFAULTSPEC: 299064562Sgshapiro#ifdef LDAPMAP 299164562Sgshapiro ldapmap_set_defaults(val); 299264562Sgshapiro#else /* LDAPMAP */ 299364562Sgshapiro printf("Warning: Option: %s requires LDAP support (-DLDAPMAP)\n", 299464562Sgshapiro o->o_name == NULL ? "<unknown>" : o->o_name); 299564562Sgshapiro#endif /* LDAPMAP */ 299664562Sgshapiro break; 299764562Sgshapiro 299864562Sgshapiro#if _FFR_MILTER 299964562Sgshapiro case O_INPUTMILTER: 300064562Sgshapiro InputFilterList = newstr(val); 300164562Sgshapiro break; 300264562Sgshapiro 300364562Sgshapiro case O_MILTER: 300464562Sgshapiro milter_set_option(subopt, val, sticky); 300564562Sgshapiro break; 300664562Sgshapiro#endif /* _FFR_MILTER */ 300764562Sgshapiro 300864562Sgshapiro#if _FFR_QUEUE_FILE_MODE 300964562Sgshapiro case O_QUEUE_FILE_MODE: /* queue file mode */ 301064562Sgshapiro QueueFileMode = atooct(val) & 0777; 301164562Sgshapiro break; 301264562Sgshapiro#endif /* _FFR_QUEUE_FILE_MODE */ 301364562Sgshapiro 301438032Speter default: 301538032Speter if (tTd(37, 1)) 301638032Speter { 301738032Speter if (isascii(opt) && isprint(opt)) 301864562Sgshapiro dprintf("Warning: option %c unknown\n", opt); 301938032Speter else 302064562Sgshapiro dprintf("Warning: option 0x%x unknown\n", opt); 302138032Speter } 302238032Speter break; 302338032Speter } 302464562Sgshapiro 302564562Sgshapiro /* 302664562Sgshapiro ** Options with suboptions are responsible for taking care 302764562Sgshapiro ** of sticky-ness (e.g., that a command line setting is kept 302864562Sgshapiro ** when reading in the sendmail.cf file). This has to be done 302964562Sgshapiro ** when the suboptions are parsed since each suboption must be 303064562Sgshapiro ** sticky, not the root option. 303164562Sgshapiro */ 303264562Sgshapiro 303364562Sgshapiro if (sticky && !bitset(OI_SUBOPT, o->o_flags)) 303438032Speter setbitn(opt, StickyOpt); 303538032Speter} 303638032Speter/* 303738032Speter** SETCLASS -- set a string into a class 303838032Speter** 303938032Speter** Parameters: 304038032Speter** class -- the class to put the string in. 304138032Speter** str -- the string to enter 304238032Speter** 304338032Speter** Returns: 304438032Speter** none. 304538032Speter** 304638032Speter** Side Effects: 304738032Speter** puts the word into the symbol table. 304838032Speter*/ 304938032Speter 305038032Spetervoid 305138032Spetersetclass(class, str) 305238032Speter int class; 305338032Speter char *str; 305438032Speter{ 305538032Speter register STAB *s; 305638032Speter 305764562Sgshapiro if ((*str & 0377) == MATCHCLASS) 305864562Sgshapiro { 305964562Sgshapiro int mid; 306064562Sgshapiro 306164562Sgshapiro str++; 306264562Sgshapiro mid = macid(str, NULL); 306371345Sgshapiro if (mid == 0) 306464562Sgshapiro return; 306564562Sgshapiro 306664562Sgshapiro if (tTd(37, 8)) 306764562Sgshapiro dprintf("setclass(%s, $=%s)\n", 306864562Sgshapiro macname(class), macname(mid)); 306964562Sgshapiro copy_class(mid, class); 307064562Sgshapiro } 307164562Sgshapiro else 307264562Sgshapiro { 307364562Sgshapiro if (tTd(37, 8)) 307464562Sgshapiro dprintf("setclass(%s, %s)\n", macname(class), str); 307564562Sgshapiro 307664562Sgshapiro s = stab(str, ST_CLASS, ST_ENTER); 307771345Sgshapiro setbitn(bitidx(class), s->s_class); 307864562Sgshapiro } 307938032Speter} 308038032Speter/* 308138032Speter** MAKEMAPENTRY -- create a map entry 308238032Speter** 308338032Speter** Parameters: 308438032Speter** line -- the config file line 308538032Speter** 308638032Speter** Returns: 308738032Speter** A pointer to the map that has been created. 308838032Speter** NULL if there was a syntax error. 308938032Speter** 309038032Speter** Side Effects: 309138032Speter** Enters the map into the dictionary. 309238032Speter*/ 309338032Speter 309438032SpeterMAP * 309538032Spetermakemapentry(line) 309638032Speter char *line; 309738032Speter{ 309838032Speter register char *p; 309938032Speter char *mapname; 310038032Speter char *classname; 310138032Speter register STAB *s; 310238032Speter STAB *class; 310338032Speter 310438032Speter for (p = line; isascii(*p) && isspace(*p); p++) 310538032Speter continue; 310638032Speter if (!(isascii(*p) && isalnum(*p))) 310738032Speter { 310838032Speter syserr("readcf: config K line: no map name"); 310938032Speter return NULL; 311038032Speter } 311138032Speter 311238032Speter mapname = p; 311338032Speter while ((isascii(*++p) && isalnum(*p)) || *p == '_' || *p == '.') 311438032Speter continue; 311538032Speter if (*p != '\0') 311638032Speter *p++ = '\0'; 311738032Speter while (isascii(*p) && isspace(*p)) 311838032Speter p++; 311938032Speter if (!(isascii(*p) && isalnum(*p))) 312038032Speter { 312138032Speter syserr("readcf: config K line, map %s: no map class", mapname); 312238032Speter return NULL; 312338032Speter } 312438032Speter classname = p; 312538032Speter while (isascii(*++p) && isalnum(*p)) 312638032Speter continue; 312738032Speter if (*p != '\0') 312838032Speter *p++ = '\0'; 312938032Speter while (isascii(*p) && isspace(*p)) 313038032Speter p++; 313138032Speter 313238032Speter /* look up the class */ 313338032Speter class = stab(classname, ST_MAPCLASS, ST_FIND); 313438032Speter if (class == NULL) 313538032Speter { 313638032Speter syserr("readcf: map %s: class %s not available", mapname, classname); 313738032Speter return NULL; 313838032Speter } 313938032Speter 314038032Speter /* enter the map */ 314138032Speter s = stab(mapname, ST_MAP, ST_ENTER); 314238032Speter s->s_map.map_class = &class->s_mapclass; 314338032Speter s->s_map.map_mname = newstr(mapname); 314438032Speter 314538032Speter if (class->s_mapclass.map_parse(&s->s_map, p)) 314638032Speter s->s_map.map_mflags |= MF_VALID; 314738032Speter 314838032Speter if (tTd(37, 5)) 314938032Speter { 315064562Sgshapiro dprintf("map %s, class %s, flags %lx, file %s,\n", 315138032Speter s->s_map.map_mname, s->s_map.map_class->map_cname, 315238032Speter s->s_map.map_mflags, 315338032Speter s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file); 315464562Sgshapiro dprintf("\tapp %s, domain %s, rebuild %s\n", 315538032Speter s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app, 315638032Speter s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain, 315738032Speter s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild); 315838032Speter } 315938032Speter 316038032Speter return &s->s_map; 316138032Speter} 316238032Speter/* 316338032Speter** STRTORWSET -- convert string to rewriting set number 316438032Speter** 316538032Speter** Parameters: 316638032Speter** p -- the pointer to the string to decode. 316738032Speter** endp -- if set, store the trailing delimiter here. 316838032Speter** stabmode -- ST_ENTER to create this entry, ST_FIND if 316938032Speter** it must already exist. 317038032Speter** 317138032Speter** Returns: 317238032Speter** The appropriate ruleset number. 317338032Speter** -1 if it is not valid (error already printed) 317438032Speter*/ 317538032Speter 317638032Speterint 317738032Speterstrtorwset(p, endp, stabmode) 317838032Speter char *p; 317938032Speter char **endp; 318038032Speter int stabmode; 318138032Speter{ 318238032Speter int ruleset; 318338032Speter static int nextruleset = MAXRWSETS; 318438032Speter 318538032Speter while (isascii(*p) && isspace(*p)) 318638032Speter p++; 318738032Speter if (!isascii(*p)) 318838032Speter { 318938032Speter syserr("invalid ruleset name: \"%.20s\"", p); 319038032Speter return -1; 319138032Speter } 319238032Speter if (isdigit(*p)) 319338032Speter { 319438032Speter ruleset = strtol(p, endp, 10); 319538032Speter if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 319638032Speter { 319738032Speter syserr("bad ruleset %d (%d max)", 319838032Speter ruleset, MAXRWSETS / 2); 319938032Speter ruleset = -1; 320038032Speter } 320138032Speter } 320238032Speter else 320338032Speter { 320438032Speter STAB *s; 320538032Speter char delim; 320664562Sgshapiro char *q = NULL; 320738032Speter 320838032Speter q = p; 320938032Speter while (*p != '\0' && isascii(*p) && 321038032Speter (isalnum(*p) || *p == '_')) 321138032Speter p++; 321238032Speter if (q == p || !(isascii(*q) && isalpha(*q))) 321338032Speter { 321438032Speter /* no valid characters */ 321538032Speter syserr("invalid ruleset name: \"%.20s\"", q); 321638032Speter return -1; 321738032Speter } 321838032Speter while (isascii(*p) && isspace(*p)) 321938032Speter *p++ = '\0'; 322038032Speter delim = *p; 322138032Speter if (delim != '\0') 322238032Speter *p = '\0'; 322338032Speter s = stab(q, ST_RULESET, stabmode); 322438032Speter if (delim != '\0') 322538032Speter *p = delim; 322638032Speter 322738032Speter if (s == NULL) 322838032Speter return -1; 322938032Speter 323038032Speter if (stabmode == ST_ENTER && delim == '=') 323138032Speter { 323238032Speter while (isascii(*++p) && isspace(*p)) 323338032Speter continue; 323438032Speter if (!(isascii(*p) && isdigit(*p))) 323538032Speter { 323638032Speter syserr("bad ruleset definition \"%s\" (number required after `=')", q); 323738032Speter ruleset = -1; 323838032Speter } 323938032Speter else 324038032Speter { 324138032Speter ruleset = strtol(p, endp, 10); 324238032Speter if (ruleset >= MAXRWSETS / 2 || ruleset < 0) 324338032Speter { 324438032Speter syserr("bad ruleset number %d in \"%s\" (%d max)", 324538032Speter ruleset, q, MAXRWSETS / 2); 324638032Speter ruleset = -1; 324738032Speter } 324838032Speter } 324938032Speter } 325038032Speter else 325138032Speter { 325238032Speter if (endp != NULL) 325338032Speter *endp = p; 325464562Sgshapiro if (s->s_ruleset >= 0) 325538032Speter ruleset = s->s_ruleset; 325638032Speter else if ((ruleset = --nextruleset) < MAXRWSETS / 2) 325738032Speter { 325838032Speter syserr("%s: too many named rulesets (%d max)", 325938032Speter q, MAXRWSETS / 2); 326038032Speter ruleset = -1; 326138032Speter } 326238032Speter } 326364562Sgshapiro if (s->s_ruleset >= 0 && 326464562Sgshapiro ruleset >= 0 && 326564562Sgshapiro ruleset != s->s_ruleset) 326638032Speter { 326738032Speter syserr("%s: ruleset changed value (old %d, new %d)", 326838032Speter q, s->s_ruleset, ruleset); 326938032Speter ruleset = s->s_ruleset; 327038032Speter } 327164562Sgshapiro else if (ruleset >= 0) 327238032Speter { 327338032Speter s->s_ruleset = ruleset; 327438032Speter } 327571345Sgshapiro if (stabmode == ST_ENTER && ruleset >= 0) 327664562Sgshapiro { 327764562Sgshapiro char *h = NULL; 327864562Sgshapiro 327964562Sgshapiro if (RuleSetNames[ruleset] != NULL) 328077349Sgshapiro sm_free(RuleSetNames[ruleset]); 328164562Sgshapiro if (delim != '\0' && (h = strchr(q, delim)) != NULL) 328264562Sgshapiro *h = '\0'; 328364562Sgshapiro RuleSetNames[ruleset] = newstr(q); 328464562Sgshapiro if (delim == '/' && h != NULL) 328564562Sgshapiro *h = delim; /* put back delim */ 328664562Sgshapiro } 328738032Speter } 328838032Speter return ruleset; 328938032Speter} 329038032Speter/* 329164562Sgshapiro** SETTIMEOUT -- set an individual timeout 329264562Sgshapiro** 329364562Sgshapiro** Parameters: 329464562Sgshapiro** name -- the name of the timeout. 329564562Sgshapiro** val -- the value of the timeout. 329664562Sgshapiro** sticky -- if set, don't let other setoptions override 329764562Sgshapiro** this value. 329864562Sgshapiro** 329964562Sgshapiro** Returns: 330064562Sgshapiro** none. 330164562Sgshapiro*/ 330264562Sgshapiro 330364562Sgshapiro/* set if Timeout sub-option is stuck */ 330464562Sgshapirostatic BITMAP256 StickyTimeoutOpt; 330564562Sgshapiro 330664562Sgshapirostatic struct timeoutinfo 330764562Sgshapiro{ 330864562Sgshapiro char *to_name; /* long name of timeout */ 330964562Sgshapiro u_char to_code; /* code for option */ 331064562Sgshapiro} TimeOutTab[] = 331164562Sgshapiro{ 331264562Sgshapiro#define TO_INITIAL 0x01 331364562Sgshapiro { "initial", TO_INITIAL }, 331464562Sgshapiro#define TO_MAIL 0x02 331564562Sgshapiro { "mail", TO_MAIL }, 331664562Sgshapiro#define TO_RCPT 0x03 331764562Sgshapiro { "rcpt", TO_RCPT }, 331864562Sgshapiro#define TO_DATAINIT 0x04 331964562Sgshapiro { "datainit", TO_DATAINIT }, 332064562Sgshapiro#define TO_DATABLOCK 0x05 332164562Sgshapiro { "datablock", TO_DATABLOCK }, 332264562Sgshapiro#define TO_DATAFINAL 0x06 332364562Sgshapiro { "datafinal", TO_DATAFINAL }, 332464562Sgshapiro#define TO_COMMAND 0x07 332564562Sgshapiro { "command", TO_COMMAND }, 332664562Sgshapiro#define TO_RSET 0x08 332764562Sgshapiro { "rset", TO_RSET }, 332864562Sgshapiro#define TO_HELO 0x09 332964562Sgshapiro { "helo", TO_HELO }, 333064562Sgshapiro#define TO_QUIT 0x0A 333164562Sgshapiro { "quit", TO_QUIT }, 333264562Sgshapiro#define TO_MISC 0x0B 333364562Sgshapiro { "misc", TO_MISC }, 333464562Sgshapiro#define TO_IDENT 0x0C 333564562Sgshapiro { "ident", TO_IDENT }, 333664562Sgshapiro#define TO_FILEOPEN 0x0D 333764562Sgshapiro { "fileopen", TO_FILEOPEN }, 333864562Sgshapiro#define TO_CONNECT 0x0E 333964562Sgshapiro { "connect", TO_CONNECT }, 334064562Sgshapiro#define TO_ICONNECT 0x0F 334164562Sgshapiro { "iconnect", TO_ICONNECT }, 334264562Sgshapiro#define TO_QUEUEWARN 0x10 334364562Sgshapiro { "queuewarn", TO_QUEUEWARN }, 334464562Sgshapiro { "queuewarn.*", TO_QUEUEWARN }, 334564562Sgshapiro#define TO_QUEUEWARN_NORMAL 0x11 334664562Sgshapiro { "queuewarn.normal", TO_QUEUEWARN_NORMAL }, 334764562Sgshapiro#define TO_QUEUEWARN_URGENT 0x12 334864562Sgshapiro { "queuewarn.urgent", TO_QUEUEWARN_URGENT }, 334964562Sgshapiro#define TO_QUEUEWARN_NON_URGENT 0x13 335064562Sgshapiro { "queuewarn.non-urgent", TO_QUEUEWARN_NON_URGENT }, 335164562Sgshapiro#define TO_QUEUERETURN 0x14 335264562Sgshapiro { "queuereturn", TO_QUEUERETURN }, 335364562Sgshapiro { "queuereturn.*", TO_QUEUERETURN }, 335464562Sgshapiro#define TO_QUEUERETURN_NORMAL 0x15 335564562Sgshapiro { "queuereturn.normal", TO_QUEUERETURN_NORMAL }, 335664562Sgshapiro#define TO_QUEUERETURN_URGENT 0x16 335764562Sgshapiro { "queuereturn.urgent", TO_QUEUERETURN_URGENT }, 335864562Sgshapiro#define TO_QUEUERETURN_NON_URGENT 0x17 335964562Sgshapiro { "queuereturn.non-urgent", TO_QUEUERETURN_NON_URGENT }, 336064562Sgshapiro#define TO_HOSTSTATUS 0x18 336164562Sgshapiro { "hoststatus", TO_HOSTSTATUS }, 336264562Sgshapiro#define TO_RESOLVER_RETRANS 0x19 336364562Sgshapiro { "resolver.retrans", TO_RESOLVER_RETRANS }, 336464562Sgshapiro#define TO_RESOLVER_RETRANS_NORMAL 0x1A 336564562Sgshapiro { "resolver.retrans.normal", TO_RESOLVER_RETRANS_NORMAL }, 336664562Sgshapiro#define TO_RESOLVER_RETRANS_FIRST 0x1B 336764562Sgshapiro { "resolver.retrans.first", TO_RESOLVER_RETRANS_FIRST }, 336864562Sgshapiro#define TO_RESOLVER_RETRY 0x1C 336964562Sgshapiro { "resolver.retry", TO_RESOLVER_RETRY }, 337064562Sgshapiro#define TO_RESOLVER_RETRY_NORMAL 0x1D 337164562Sgshapiro { "resolver.retry.normal", TO_RESOLVER_RETRY_NORMAL }, 337264562Sgshapiro#define TO_RESOLVER_RETRY_FIRST 0x1E 337364562Sgshapiro { "resolver.retry.first", TO_RESOLVER_RETRY_FIRST }, 337464562Sgshapiro#define TO_CONTROL 0x1F 337564562Sgshapiro { "control", TO_CONTROL }, 337664562Sgshapiro { NULL, 0 }, 337764562Sgshapiro}; 337864562Sgshapiro 337964562Sgshapiro 338064562Sgshapirostatic void 338164562Sgshapirosettimeout(name, val, sticky) 338264562Sgshapiro char *name; 338364562Sgshapiro char *val; 338464562Sgshapiro bool sticky; 338564562Sgshapiro{ 338664562Sgshapiro register struct timeoutinfo *to; 338764562Sgshapiro int i; 338880785Sgshapiro int addopts; 338964562Sgshapiro time_t toval; 339064562Sgshapiro 339164562Sgshapiro if (tTd(37, 2)) 339264562Sgshapiro dprintf("settimeout(%s = %s)", name, val); 339364562Sgshapiro 339464562Sgshapiro for (to = TimeOutTab; to->to_name != NULL; to++) 339564562Sgshapiro { 339664562Sgshapiro if (strcasecmp(to->to_name, name) == 0) 339764562Sgshapiro break; 339864562Sgshapiro } 339964562Sgshapiro 340064562Sgshapiro if (to->to_name == NULL) 340171345Sgshapiro { 340271345Sgshapiro errno = 0; /* avoid bogus error text */ 340364562Sgshapiro syserr("settimeout: invalid timeout %s", name); 340471345Sgshapiro return; 340571345Sgshapiro } 340664562Sgshapiro 340764562Sgshapiro /* 340864562Sgshapiro ** See if this option is preset for us. 340964562Sgshapiro */ 341064562Sgshapiro 341164562Sgshapiro if (!sticky && bitnset(to->to_code, StickyTimeoutOpt)) 341264562Sgshapiro { 341364562Sgshapiro if (tTd(37, 2)) 341464562Sgshapiro dprintf(" (ignored)\n"); 341564562Sgshapiro return; 341664562Sgshapiro } 341764562Sgshapiro 341864562Sgshapiro if (tTd(37, 2)) 341964562Sgshapiro dprintf("\n"); 342064562Sgshapiro 342164562Sgshapiro toval = convtime(val, 'm'); 342280785Sgshapiro addopts = 0; 342364562Sgshapiro 342464562Sgshapiro switch (to->to_code) 342564562Sgshapiro { 342664562Sgshapiro case TO_INITIAL: 342764562Sgshapiro TimeOuts.to_initial = toval; 342864562Sgshapiro break; 342964562Sgshapiro 343064562Sgshapiro case TO_MAIL: 343164562Sgshapiro TimeOuts.to_mail = toval; 343264562Sgshapiro break; 343364562Sgshapiro 343464562Sgshapiro case TO_RCPT: 343564562Sgshapiro TimeOuts.to_rcpt = toval; 343664562Sgshapiro break; 343764562Sgshapiro 343864562Sgshapiro case TO_DATAINIT: 343964562Sgshapiro TimeOuts.to_datainit = toval; 344064562Sgshapiro break; 344164562Sgshapiro 344264562Sgshapiro case TO_DATABLOCK: 344364562Sgshapiro TimeOuts.to_datablock = toval; 344464562Sgshapiro break; 344564562Sgshapiro 344664562Sgshapiro case TO_DATAFINAL: 344764562Sgshapiro TimeOuts.to_datafinal = toval; 344864562Sgshapiro break; 344964562Sgshapiro 345064562Sgshapiro case TO_COMMAND: 345164562Sgshapiro TimeOuts.to_nextcommand = toval; 345264562Sgshapiro break; 345364562Sgshapiro 345464562Sgshapiro case TO_RSET: 345564562Sgshapiro TimeOuts.to_rset = toval; 345664562Sgshapiro break; 345764562Sgshapiro 345864562Sgshapiro case TO_HELO: 345964562Sgshapiro TimeOuts.to_helo = toval; 346064562Sgshapiro break; 346164562Sgshapiro 346264562Sgshapiro case TO_QUIT: 346364562Sgshapiro TimeOuts.to_quit = toval; 346464562Sgshapiro break; 346564562Sgshapiro 346664562Sgshapiro case TO_MISC: 346764562Sgshapiro TimeOuts.to_miscshort = toval; 346864562Sgshapiro break; 346964562Sgshapiro 347064562Sgshapiro case TO_IDENT: 347164562Sgshapiro TimeOuts.to_ident = toval; 347264562Sgshapiro break; 347364562Sgshapiro 347464562Sgshapiro case TO_FILEOPEN: 347564562Sgshapiro TimeOuts.to_fileopen = toval; 347664562Sgshapiro break; 347764562Sgshapiro 347864562Sgshapiro case TO_CONNECT: 347964562Sgshapiro TimeOuts.to_connect = toval; 348064562Sgshapiro break; 348164562Sgshapiro 348264562Sgshapiro case TO_ICONNECT: 348364562Sgshapiro TimeOuts.to_iconnect = toval; 348464562Sgshapiro break; 348564562Sgshapiro 348664562Sgshapiro case TO_QUEUEWARN: 348764562Sgshapiro toval = convtime(val, 'h'); 348864562Sgshapiro TimeOuts.to_q_warning[TOC_NORMAL] = toval; 348964562Sgshapiro TimeOuts.to_q_warning[TOC_URGENT] = toval; 349064562Sgshapiro TimeOuts.to_q_warning[TOC_NONURGENT] = toval; 349180785Sgshapiro addopts = 2; 349264562Sgshapiro break; 349364562Sgshapiro 349464562Sgshapiro case TO_QUEUEWARN_NORMAL: 349564562Sgshapiro toval = convtime(val, 'h'); 349664562Sgshapiro TimeOuts.to_q_warning[TOC_NORMAL] = toval; 349764562Sgshapiro break; 349864562Sgshapiro 349964562Sgshapiro case TO_QUEUEWARN_URGENT: 350064562Sgshapiro toval = convtime(val, 'h'); 350164562Sgshapiro TimeOuts.to_q_warning[TOC_URGENT] = toval; 350264562Sgshapiro break; 350364562Sgshapiro 350464562Sgshapiro case TO_QUEUEWARN_NON_URGENT: 350564562Sgshapiro toval = convtime(val, 'h'); 350664562Sgshapiro TimeOuts.to_q_warning[TOC_NONURGENT] = toval; 350764562Sgshapiro break; 350864562Sgshapiro 350964562Sgshapiro case TO_QUEUERETURN: 351064562Sgshapiro toval = convtime(val, 'd'); 351164562Sgshapiro TimeOuts.to_q_return[TOC_NORMAL] = toval; 351264562Sgshapiro TimeOuts.to_q_return[TOC_URGENT] = toval; 351364562Sgshapiro TimeOuts.to_q_return[TOC_NONURGENT] = toval; 351480785Sgshapiro addopts = 2; 351564562Sgshapiro break; 351664562Sgshapiro 351764562Sgshapiro case TO_QUEUERETURN_NORMAL: 351864562Sgshapiro toval = convtime(val, 'd'); 351964562Sgshapiro TimeOuts.to_q_return[TOC_NORMAL] = toval; 352064562Sgshapiro break; 352164562Sgshapiro 352264562Sgshapiro case TO_QUEUERETURN_URGENT: 352364562Sgshapiro toval = convtime(val, 'd'); 352464562Sgshapiro TimeOuts.to_q_return[TOC_URGENT] = toval; 352564562Sgshapiro break; 352664562Sgshapiro 352764562Sgshapiro case TO_QUEUERETURN_NON_URGENT: 352864562Sgshapiro toval = convtime(val, 'd'); 352964562Sgshapiro TimeOuts.to_q_return[TOC_NONURGENT] = toval; 353064562Sgshapiro break; 353164562Sgshapiro 353264562Sgshapiro 353364562Sgshapiro case TO_HOSTSTATUS: 353464562Sgshapiro MciInfoTimeout = toval; 353564562Sgshapiro break; 353664562Sgshapiro 353764562Sgshapiro case TO_RESOLVER_RETRANS: 353864562Sgshapiro toval = convtime(val, 's'); 353964562Sgshapiro TimeOuts.res_retrans[RES_TO_DEFAULT] = toval; 354064562Sgshapiro TimeOuts.res_retrans[RES_TO_FIRST] = toval; 354164562Sgshapiro TimeOuts.res_retrans[RES_TO_NORMAL] = toval; 354280785Sgshapiro addopts = 2; 354364562Sgshapiro break; 354464562Sgshapiro 354564562Sgshapiro case TO_RESOLVER_RETRY: 354664562Sgshapiro i = atoi(val); 354764562Sgshapiro TimeOuts.res_retry[RES_TO_DEFAULT] = i; 354864562Sgshapiro TimeOuts.res_retry[RES_TO_FIRST] = i; 354964562Sgshapiro TimeOuts.res_retry[RES_TO_NORMAL] = i; 355080785Sgshapiro addopts = 2; 355164562Sgshapiro break; 355264562Sgshapiro 355364562Sgshapiro case TO_RESOLVER_RETRANS_NORMAL: 355464562Sgshapiro TimeOuts.res_retrans[RES_TO_NORMAL] = convtime(val, 's'); 355564562Sgshapiro break; 355664562Sgshapiro 355764562Sgshapiro case TO_RESOLVER_RETRY_NORMAL: 355864562Sgshapiro TimeOuts.res_retry[RES_TO_NORMAL] = atoi(val); 355964562Sgshapiro break; 356064562Sgshapiro 356164562Sgshapiro case TO_RESOLVER_RETRANS_FIRST: 356264562Sgshapiro TimeOuts.res_retrans[RES_TO_FIRST] = convtime(val, 's'); 356364562Sgshapiro break; 356464562Sgshapiro 356564562Sgshapiro case TO_RESOLVER_RETRY_FIRST: 356664562Sgshapiro TimeOuts.res_retry[RES_TO_FIRST] = atoi(val); 356764562Sgshapiro break; 356864562Sgshapiro 356964562Sgshapiro case TO_CONTROL: 357064562Sgshapiro TimeOuts.to_control = toval; 357164562Sgshapiro break; 357264562Sgshapiro 357364562Sgshapiro default: 357464562Sgshapiro syserr("settimeout: invalid timeout %s", name); 357564562Sgshapiro break; 357664562Sgshapiro } 357764562Sgshapiro 357864562Sgshapiro if (sticky) 357980785Sgshapiro { 358080785Sgshapiro for (i = 0; i <= addopts; i++) 358180785Sgshapiro setbitn(to->to_code + i, StickyTimeoutOpt); 358280785Sgshapiro } 358364562Sgshapiro} 358464562Sgshapiro/* 358538032Speter** INITTIMEOUTS -- parse and set timeout values 358638032Speter** 358738032Speter** Parameters: 358838032Speter** val -- a pointer to the values. If NULL, do initial 358938032Speter** settings. 359064562Sgshapiro** sticky -- if set, don't let other setoptions override 359164562Sgshapiro** this suboption value. 359238032Speter** 359338032Speter** Returns: 359438032Speter** none. 359538032Speter** 359638032Speter** Side Effects: 359738032Speter** Initializes the TimeOuts structure 359838032Speter*/ 359938032Speter 360038032Spetervoid 360164562Sgshapiroinittimeouts(val, sticky) 360238032Speter register char *val; 360364562Sgshapiro bool sticky; 360438032Speter{ 360538032Speter register char *p; 360638032Speter 360738032Speter if (tTd(37, 2)) 360864562Sgshapiro dprintf("inittimeouts(%s)\n", val == NULL ? "<NULL>" : val); 360938032Speter if (val == NULL) 361038032Speter { 361138032Speter TimeOuts.to_connect = (time_t) 0 SECONDS; 361238032Speter TimeOuts.to_initial = (time_t) 5 MINUTES; 361338032Speter TimeOuts.to_helo = (time_t) 5 MINUTES; 361438032Speter TimeOuts.to_mail = (time_t) 10 MINUTES; 361538032Speter TimeOuts.to_rcpt = (time_t) 1 HOUR; 361638032Speter TimeOuts.to_datainit = (time_t) 5 MINUTES; 361738032Speter TimeOuts.to_datablock = (time_t) 1 HOUR; 361838032Speter TimeOuts.to_datafinal = (time_t) 1 HOUR; 361938032Speter TimeOuts.to_rset = (time_t) 5 MINUTES; 362038032Speter TimeOuts.to_quit = (time_t) 2 MINUTES; 362138032Speter TimeOuts.to_nextcommand = (time_t) 1 HOUR; 362238032Speter TimeOuts.to_miscshort = (time_t) 2 MINUTES; 362338032Speter#if IDENTPROTO 362464562Sgshapiro TimeOuts.to_ident = (time_t) 5 SECONDS; 362564562Sgshapiro#else /* IDENTPROTO */ 362638032Speter TimeOuts.to_ident = (time_t) 0 SECONDS; 362764562Sgshapiro#endif /* IDENTPROTO */ 362838032Speter TimeOuts.to_fileopen = (time_t) 60 SECONDS; 362964562Sgshapiro TimeOuts.to_control = (time_t) 2 MINUTES; 363038032Speter if (tTd(37, 5)) 363138032Speter { 363264562Sgshapiro dprintf("Timeouts:\n"); 363364562Sgshapiro dprintf(" connect = %ld\n", (long)TimeOuts.to_connect); 363464562Sgshapiro dprintf(" initial = %ld\n", (long)TimeOuts.to_initial); 363564562Sgshapiro dprintf(" helo = %ld\n", (long)TimeOuts.to_helo); 363664562Sgshapiro dprintf(" mail = %ld\n", (long)TimeOuts.to_mail); 363764562Sgshapiro dprintf(" rcpt = %ld\n", (long)TimeOuts.to_rcpt); 363864562Sgshapiro dprintf(" datainit = %ld\n", (long)TimeOuts.to_datainit); 363964562Sgshapiro dprintf(" datablock = %ld\n", (long)TimeOuts.to_datablock); 364064562Sgshapiro dprintf(" datafinal = %ld\n", (long)TimeOuts.to_datafinal); 364164562Sgshapiro dprintf(" rset = %ld\n", (long)TimeOuts.to_rset); 364264562Sgshapiro dprintf(" quit = %ld\n", (long)TimeOuts.to_quit); 364364562Sgshapiro dprintf(" nextcommand = %ld\n", (long)TimeOuts.to_nextcommand); 364464562Sgshapiro dprintf(" miscshort = %ld\n", (long)TimeOuts.to_miscshort); 364564562Sgshapiro dprintf(" ident = %ld\n", (long)TimeOuts.to_ident); 364664562Sgshapiro dprintf(" fileopen = %ld\n", (long)TimeOuts.to_fileopen); 364764562Sgshapiro dprintf(" control = %ld\n", (long)TimeOuts.to_control); 364838032Speter } 364938032Speter return; 365038032Speter } 365138032Speter 365238032Speter for (;; val = p) 365338032Speter { 365438032Speter while (isascii(*val) && isspace(*val)) 365538032Speter val++; 365638032Speter if (*val == '\0') 365738032Speter break; 365838032Speter for (p = val; *p != '\0' && *p != ','; p++) 365938032Speter continue; 366038032Speter if (*p != '\0') 366138032Speter *p++ = '\0'; 366238032Speter 366338032Speter if (isascii(*val) && isdigit(*val)) 366438032Speter { 366538032Speter /* old syntax -- set everything */ 366638032Speter TimeOuts.to_mail = convtime(val, 'm'); 366738032Speter TimeOuts.to_rcpt = TimeOuts.to_mail; 366838032Speter TimeOuts.to_datainit = TimeOuts.to_mail; 366938032Speter TimeOuts.to_datablock = TimeOuts.to_mail; 367038032Speter TimeOuts.to_datafinal = TimeOuts.to_mail; 367138032Speter TimeOuts.to_nextcommand = TimeOuts.to_mail; 367264562Sgshapiro if (sticky) 367364562Sgshapiro { 367464562Sgshapiro setbitn(TO_MAIL, StickyTimeoutOpt); 367564562Sgshapiro setbitn(TO_RCPT, StickyTimeoutOpt); 367664562Sgshapiro setbitn(TO_DATAINIT, StickyTimeoutOpt); 367764562Sgshapiro setbitn(TO_DATABLOCK, StickyTimeoutOpt); 367864562Sgshapiro setbitn(TO_DATAFINAL, StickyTimeoutOpt); 367964562Sgshapiro setbitn(TO_COMMAND, StickyTimeoutOpt); 368064562Sgshapiro } 368138032Speter continue; 368238032Speter } 368338032Speter else 368438032Speter { 368538032Speter register char *q = strchr(val, ':'); 368638032Speter 368738032Speter if (q == NULL && (q = strchr(val, '=')) == NULL) 368838032Speter { 368938032Speter /* syntax error */ 369038032Speter continue; 369138032Speter } 369238032Speter *q++ = '\0'; 369364562Sgshapiro settimeout(val, q, sticky); 369438032Speter } 369538032Speter } 369638032Speter} 3697