📄 readcf.c
字号:
/*
* Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*
*/
#ifndef lint
static char id[] = "@(#)$Id: readcf.c,v 8.382.4.27 2000/09/28 01:31:16 gshapiro Exp $";
#endif /* ! lint */
#include <sendmail.h>
#if NETINET || NETINET6
# include <arpa/inet.h>
#endif /* NETINET || NETINET6 */
#define SECONDS
#define MINUTES * 60
#define HOUR * 3600
#define HOURS HOUR
static void fileclass __P((int, char *, char *, bool, bool));
static char **makeargv __P((char *));
static void settimeout __P((char *, char *, bool));
static void toomany __P((int, int));
/*
** READCF -- read configuration file.
**
** This routine reads the configuration file and builds the internal
** form.
**
** The file is formatted as a sequence of lines, each taken
** atomically. The first character of each line describes how
** the line is to be interpreted. The lines are:
** Dxval Define macro x to have value val.
** Cxword Put word into class x.
** Fxfile [fmt] Read file for lines to put into
** class x. Use scanf string 'fmt'
** or "%s" if not present. Fmt should
** only produce one string-valued result.
** Hname: value Define header with field-name 'name'
** and value as specified; this will be
** macro expanded immediately before
** use.
** Sn Use rewriting set n.
** Rlhs rhs Rewrite addresses that match lhs to
** be rhs.
** Mn arg=val... Define mailer. n is the internal name.
** Args specify mailer parameters.
** Oxvalue Set option x to value.
** Pname=value Set precedence name to value.
** Vversioncode[/vendorcode]
** Version level/vendor name of
** configuration syntax.
** Kmapname mapclass arguments....
** Define keyed lookup of a given class.
** Arguments are class dependent.
** Eenvar=value Set the environment value to the given value.
**
** Parameters:
** cfname -- configuration file name.
** safe -- TRUE if this is the system config file;
** FALSE otherwise.
** e -- the main envelope.
**
** Returns:
** none.
**
** Side Effects:
** Builds several internal tables.
*/
void
readcf(cfname, safe, e)
char *cfname;
bool safe;
register ENVELOPE *e;
{
FILE *cf;
int ruleset = -1;
char *q;
struct rewrite *rwp = NULL;
char *bp;
auto char *ep;
int nfuzzy;
char *file;
bool optional;
int mid;
register char *p;
long sff = SFF_OPENASROOT;
struct stat statb;
char buf[MAXLINE];
char exbuf[MAXLINE];
char pvpbuf[MAXLINE + MAXATOM];
static char *null_list[1] = { NULL };
extern u_char TokTypeNoC[];
FileName = cfname;
LineNumber = 0;
if (DontLockReadFiles)
sff |= SFF_NOLOCK;
cf = safefopen(cfname, O_RDONLY, 0444, sff);
if (cf == NULL)
{
syserr("cannot open");
finis(FALSE, EX_OSFILE);
}
if (fstat(fileno(cf), &statb) < 0)
{
syserr("cannot fstat");
finis(FALSE, EX_OSFILE);
}
if (!S_ISREG(statb.st_mode))
{
syserr("not a plain file");
finis(FALSE, EX_OSFILE);
}
if (OpMode != MD_TEST && bitset(S_IWGRP|S_IWOTH, statb.st_mode))
{
if (OpMode == MD_DAEMON || OpMode == MD_INITALIAS)
fprintf(stderr, "%s: WARNING: dangerous write permissions\n",
FileName);
if (LogLevel > 0)
sm_syslog(LOG_CRIT, NOQID,
"%s: WARNING: dangerous write permissions",
FileName);
}
#ifdef XLA
xla_zero();
#endif /* XLA */
while ((bp = fgetfolded(buf, sizeof buf, cf)) != NULL)
{
if (bp[0] == '#')
{
if (bp != buf)
free(bp);
continue;
}
/* do macro expansion mappings */
translate_dollars(bp);
/* interpret this line */
errno = 0;
switch (bp[0])
{
case '\0':
case '#': /* comment */
break;
case 'R': /* rewriting rule */
if (ruleset < 0)
{
syserr("missing valid ruleset for \"%s\"", bp);
break;
}
for (p = &bp[1]; *p != '\0' && *p != '\t'; p++)
continue;
if (*p == '\0')
{
syserr("invalid rewrite line \"%s\" (tab expected)", bp);
break;
}
/* allocate space for the rule header */
if (rwp == NULL)
{
RewriteRules[ruleset] = rwp =
(struct rewrite *) xalloc(sizeof *rwp);
}
else
{
rwp->r_next = (struct rewrite *) xalloc(sizeof *rwp);
rwp = rwp->r_next;
}
rwp->r_next = NULL;
/* expand and save the LHS */
*p = '\0';
expand(&bp[1], exbuf, sizeof exbuf, e);
rwp->r_lhs = prescan(exbuf, '\t', pvpbuf,
sizeof pvpbuf, NULL,
ConfigLevel >= 9 ? TokTypeNoC : NULL);
nfuzzy = 0;
if (rwp->r_lhs != NULL)
{
register char **ap;
rwp->r_lhs = copyplist(rwp->r_lhs, TRUE);
/* count the number of fuzzy matches in LHS */
for (ap = rwp->r_lhs; *ap != NULL; ap++)
{
char *botch;
botch = NULL;
switch (**ap & 0377)
{
case MATCHZANY:
case MATCHANY:
case MATCHONE:
case MATCHCLASS:
case MATCHNCLASS:
nfuzzy++;
break;
case MATCHREPL:
botch = "$0-$9";
break;
case CANONUSER:
botch = "$:";
break;
case CALLSUBR:
botch = "$>";
break;
case CONDIF:
botch = "$?";
break;
case CONDFI:
botch = "$.";
break;
case HOSTBEGIN:
botch = "$[";
break;
case HOSTEND:
botch = "$]";
break;
case LOOKUPBEGIN:
botch = "$(";
break;
case LOOKUPEND:
botch = "$)";
break;
}
if (botch != NULL)
syserr("Inappropriate use of %s on LHS",
botch);
}
rwp->r_line = LineNumber;
}
else
{
syserr("R line: null LHS");
rwp->r_lhs = null_list;
}
/* expand and save the RHS */
while (*++p == '\t')
continue;
q = p;
while (*p != '\0' && *p != '\t')
p++;
*p = '\0';
expand(q, exbuf, sizeof exbuf, e);
rwp->r_rhs = prescan(exbuf, '\t', pvpbuf,
sizeof pvpbuf, NULL,
ConfigLevel >= 9 ? TokTypeNoC : NULL);
if (rwp->r_rhs != NULL)
{
register char **ap;
rwp->r_rhs = copyplist(rwp->r_rhs, TRUE);
/* check no out-of-bounds replacements */
nfuzzy += '0';
for (ap = rwp->r_rhs; *ap != NULL; ap++)
{
char *botch;
botch = NULL;
switch (**ap & 0377)
{
case MATCHREPL:
if ((*ap)[1] <= '0' || (*ap)[1] > nfuzzy)
{
syserr("replacement $%c out of bounds",
(*ap)[1]);
}
break;
case MATCHZANY:
botch = "$*";
break;
case MATCHANY:
botch = "$+";
break;
case MATCHONE:
botch = "$-";
break;
case MATCHCLASS:
botch = "$=";
break;
case MATCHNCLASS:
botch = "$~";
break;
}
if (botch != NULL)
syserr("Inappropriate use of %s on RHS",
botch);
}
}
else
{
syserr("R line: null RHS");
rwp->r_rhs = null_list;
}
break;
case 'S': /* select rewriting set */
expand(&bp[1], exbuf, sizeof exbuf, e);
ruleset = strtorwset(exbuf, NULL, ST_ENTER);
if (ruleset < 0)
break;
rwp = RewriteRules[ruleset];
if (rwp != NULL)
{
if (OpMode == MD_TEST)
printf("WARNING: Ruleset %s has multiple definitions\n",
&bp[1]);
if (tTd(37, 1))
dprintf("WARNING: Ruleset %s has multiple definitions\n",
&bp[1]);
while (rwp->r_next != NULL)
rwp = rwp->r_next;
}
break;
case 'D': /* macro definition */
mid = macid(&bp[1], &ep);
p = munchstring(ep, NULL, '\0');
define(mid, newstr(p), e);
break;
case 'H': /* required header line */
(void) chompheader(&bp[1], CHHDR_DEF, NULL, e);
break;
case 'C': /* word class */
case 'T': /* trusted user (set class `t') */
if (bp[0] == 'C')
{
mid = macid(&bp[1], &ep);
expand(ep, exbuf, sizeof exbuf, e);
p = exbuf;
}
else
{
mid = 't';
p = &bp[1];
}
while (*p != '\0')
{
register char *wd;
char delim;
while (*p != '\0' && isascii(*p) && isspace(*p))
p++;
wd = p;
while (*p != '\0' && !(isascii(*p) && isspace(*p)))
p++;
delim = *p;
*p = '\0';
if (wd[0] != '\0')
setclass(mid, wd);
*p = delim;
}
break;
case 'F': /* word class from file */
mid = macid(&bp[1], &ep);
for (p = ep; isascii(*p) && isspace(*p); )
p++;
if (p[0] == '-' && p[1] == 'o')
{
optional = TRUE;
while (*p != '\0' && !(isascii(*p) && isspace(*p)))
p++;
while (isascii(*p) && isspace(*p))
p++;
}
else
optional = FALSE;
file = p;
q = p;
while (*q != '\0' && !(isascii(*q) && isspace(*q)))
q++;
if (*file == '|')
p = "%s";
else
{
p = q;
if (*p == '\0')
p = "%s";
else
{
*p = '\0';
while (isascii(*++p) && isspace(*p))
continue;
}
}
fileclass(mid, file, p, safe, optional);
break;
#ifdef XLA
case 'L': /* extended load average description */
xla_init(&bp[1]);
break;
#endif /* XLA */
#if defined(SUN_EXTENSIONS) && defined(SUN_LOOKUP_MACRO)
case 'L': /* lookup macro */
case 'G': /* lookup class */
/* reserved for Sun -- NIS+ database lookup */
if (VendorCode != VENDOR_SUN)
goto badline;
sun_lg_config_line(bp, e);
break;
#endif /* defined(SUN_EXTENSIONS) && defined(SUN_LOOKUP_MACRO) */
case 'M': /* define mailer */
makemailer(&bp[1]);
break;
case 'O': /* set option */
setoption(bp[1], &bp[2], safe, FALSE, e);
break;
case 'P': /* set precedence */
if (NumPriorities >= MAXPRIORITIES)
{
toomany('P', MAXPRIORITIES);
break;
}
for (p = &bp[1]; *p != '\0' && *p != '='; p++)
continue;
if (*p == '\0')
goto badline;
*p = '\0';
Priorities[NumPriorities].pri_name = newstr(&bp[1]);
Priorities[NumPriorities].pri_val = atoi(++p);
NumPriorities++;
break;
case 'V': /* configuration syntax version */
for (p = &bp[1]; isascii(*p) && isspace(*p); p++)
continue;
if (!isascii(*p) || !isdigit(*p))
{
syserr("invalid argument to V line: \"%.20s\"",
&bp[1]);
break;
}
ConfigLevel = strtol(p, &ep, 10);
/*
** Do heuristic tweaking for back compatibility.
*/
if (ConfigLevel >= 5)
{
/* level 5 configs have short name in $w */
p = macvalue('w', e);
if (p != NULL && (p = strchr(p, '.')) != NULL)
*p = '\0';
define('w', macvalue('w', e), e);
}
if (ConfigLevel >= 6)
{
ColonOkInAddr = FALSE;
}
/*
** Look for vendor code.
*/
if (*ep++ == '/')
{
/* extract vendor code */
for (p = ep; isascii(*p) && isalpha(*p); )
p++;
*p = '\0';
if (!setvendor(ep))
syserr("invalid V line vendor code: \"%s\"",
ep);
}
break;
case 'K':
expand(&bp[1], exbuf, sizeof exbuf, e);
(void) makemapentry(exbuf);
break;
case 'E':
p = strchr(bp, '=');
if (p != NULL)
*p++ = '\0';
setuserenv(&bp[1], p);
break;
#if _FFR_MILTER
case 'X': /* mail filter */
milter_setup(&bp[1]);
break;
#endif /* _FFR_MILTER */
default:
badline:
syserr("unknown configuration line \"%s\"", bp);
}
if (bp != buf)
free(bp);
}
if (ferror(cf))
{
syserr("I/O read error");
finis(FALSE, EX_OSFILE);
}
(void) fclose(cf);
FileName = NULL;
/* initialize host maps from local service tables */
inithostmaps();
/* initialize daemon (if not defined yet) */
initdaemon();
/* determine if we need to do special name-server frotz */
{
int nmaps;
char *maptype[MAXMAPSTACK];
short mapreturn[MAXMAPACTIONS];
nmaps = switch_map_find("hosts", maptype, mapreturn);
UseNameServer = FALSE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -