*/
#ifndef lint
-static char sccsid[] = "@(#)readcf.c 8.1 (Berkeley) 6/7/93";
+static char sccsid[] = "@(#)readcf.c 8.23 (Berkeley) 3/18/94";
#endif /* not lint */
# include "sendmail.h"
-#ifdef NAMED_BIND
+# include <pwd.h>
+# include <grp.h>
+#if NAMED_BIND
# include <arpa/nameser.h>
# include <resolv.h>
#endif
** Args specify mailer parameters.
** Oxvalue Set option x to value.
** Pname=value Set precedence name to value.
-** Vversioncode Version level of configuration syntax.
+** Vversioncode[/vendorcode]
+** Version level/vendor name of
+** configuration syntax.
** Kmapname mapclass arguments....
** Define keyed lookup of a given class.
** Arguments are class dependent.
char *q;
struct rewrite *rwp = NULL;
char *bp;
+ auto char *ep;
int nfuzzy;
+ char *file;
+ bool optional;
char buf[MAXLINE];
register char *p;
extern char **copyplist();
struct stat statb;
char exbuf[MAXLINE];
- char pvpbuf[PSBUFSIZE];
+ char pvpbuf[MAXLINE + MAXATOM];
extern char *munchstring();
extern void makemapentry();
}
/* interpret this line */
+ errno = 0;
switch (bp[0])
{
case '\0':
if (*p == '\0')
{
- syserr("invalid rewrite line \"%s\"", bp);
+ syserr("invalid rewrite line \"%s\" (tab expected)", bp);
break;
}
/* expand and save the LHS */
*p = '\0';
expand(&bp[1], exbuf, &exbuf[sizeof exbuf], e);
- rwp->r_lhs = prescan(exbuf, '\t', pvpbuf, NULL);
+ rwp->r_lhs = prescan(exbuf, '\t', pvpbuf,
+ sizeof pvpbuf, NULL);
nfuzzy = 0;
if (rwp->r_lhs != NULL)
{
p++;
*p = '\0';
expand(q, exbuf, &exbuf[sizeof exbuf], e);
- rwp->r_rhs = prescan(exbuf, '\t', pvpbuf, NULL);
+ rwp->r_rhs = prescan(exbuf, '\t', pvpbuf,
+ sizeof pvpbuf, NULL);
if (rwp->r_rhs != NULL)
{
register char **ap;
break;
case 'S': /* select rewriting set */
- ruleset = atoi(&bp[1]);
+ for (p = &bp[1]; isascii(*p) && isspace(*p); p++)
+ continue;
+ if (!isascii(*p) || !isdigit(*p))
+ {
+ syserr("invalid argument to S line: \"%.20s\"",
+ &bp[1]);
+ break;
+ }
+ ruleset = atoi(p);
if (ruleset >= MAXRWSETS || ruleset < 0)
{
syserr("bad ruleset %d (%d max)", ruleset, MAXRWSETS);
break;
case 'D': /* macro definition */
- define(bp[1], newstr(munchstring(&bp[2], NULL)), e);
+ p = munchstring(&bp[2], NULL);
+ define(bp[1], newstr(p), e);
break;
case 'H': /* required header line */
case 'C': /* word class */
/* scan the list of words and set class for all */
- for (p = &bp[2]; *p != '\0'; )
+ expand(&bp[2], exbuf, &exbuf[sizeof exbuf], e);
+ for (p = exbuf; *p != '\0'; )
{
register char *wd;
char delim;
delim = *p;
*p = '\0';
if (wd[0] != '\0')
- {
- if (tTd(37, 2))
- printf("setclass(%c, %s)\n",
- bp[1], wd);
setclass(bp[1], wd);
- }
*p = delim;
}
break;
case 'F': /* word class from file */
- /* read list of words from argument or file */
- /* read from file */
- for (p = &bp[2];
- *p != '\0' && !(isascii(*p) && isspace(*p));
- p++)
- continue;
+ for (p = &bp[2]; 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;
+ while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+ p++;
if (*p == '\0')
p = "%s";
else
while (isascii(*++p) && isspace(*p))
continue;
}
- fileclass(bp[1], &bp[2], p, safe);
+ fileclass(bp[1], file, p, safe, optional);
break;
#ifdef XLA
break;
case 'V': /* configuration syntax version */
- ConfigLevel = atoi(&bp[1]);
+ 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);
+ if (ConfigLevel >= 5)
+ {
+ /* level 5 configs have short name in $w */
+ p = macvalue('w', e);
+ if (p != NULL && (p = strchr(p, '.')) != NULL)
+ *p = '\0';
+ }
+ 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':
{
/* user didn't initialize: set up host map */
strcpy(buf, "host host");
+#if NAMED_BIND
if (ConfigLevel >= 2)
strcat(buf, " -a.");
+#endif
makemapentry(buf);
}
}
** class -- class to define.
** filename -- name of file to read.
** fmt -- scanf string to use for match.
+** safe -- if set, this is a safe read.
+** optional -- if set, it is not an error for the file to
+** not exist.
**
** Returns:
** none
** the named class.
*/
-fileclass(class, filename, fmt, safe)
+fileclass(class, filename, fmt, safe, optional)
int class;
char *filename;
char *fmt;
bool safe;
+ bool optional;
{
FILE *f;
struct stat stbuf;
char buf[MAXLINE];
+ if (tTd(37, 2))
+ printf("fileclass(%s, fmt=%s)\n", filename, fmt);
+
+ if (filename[0] == '|')
+ {
+ syserr("fileclass: pipes (F%c%s) not supported due to security problems",
+ class, filename);
+ return;
+ }
if (stat(filename, &stbuf) < 0)
{
- syserr("fileclass: cannot stat %s", filename);
+ if (tTd(37, 2))
+ printf(" cannot stat (%s)\n", errstring(errno));
+ if (!optional)
+ syserr("fileclass: cannot stat %s", filename);
return;
}
if (!S_ISREG(stbuf.st_mode))
*p++ = '\0';
/* enter the word in the symbol table */
- s = stab(q, ST_CLASS, ST_ENTER);
- setbitn(class, s->s_class);
+ setclass(class, q);
}
}
static BITMAP StickyOpt; /* set if option is stuck */
-#ifdef NAMED_BIND
+#if NAMED_BIND
struct resolverflags
{
"defnames", RES_DEFNAMES,
"stayopen", RES_STAYOPEN,
"dnsrch", RES_DNSRCH,
+ "true", 0, /* to avoid error on old syntax */
NULL, 0
};
extern time_t convtime();
extern int QueueLA;
extern int RefuseLA;
+ extern bool Warn_Q_option;
extern bool trusteduser();
if (tTd(37, 1))
** Check to see if this option can be specified by this user.
*/
- if (!safe && getuid() == 0)
+ if (!safe && RealUid == 0)
safe = TRUE;
- if (!safe && strchr("bdeEijLmoprsvC7", opt) == NULL)
+ if (!safe && strchr("bCdeijLmoprsvw7", opt) == NULL)
{
if (opt != 'M' || (val[0] != 'r' && val[0] != 's'))
{
if (tTd(37, 1))
printf(" (unsafe)");
- if (getuid() != geteuid())
+ if (RealUid != geteuid())
{
if (tTd(37, 1))
printf("(Resetting uid)");
- (void) setgid(getgid());
- (void) setuid(getuid());
+ (void) setgid(RealGid);
+ (void) setuid(RealUid);
}
}
}
case 'a': /* look N minutes for "@:@" in alias file */
if (val[0] == '\0')
- SafeAlias = 5;
+ SafeAlias = 5 * 60; /* five minutes */
else
- SafeAlias = atoi(val);
+ SafeAlias = convtime(val, 'm');
break;
case 'B': /* substitution for blank character */
break;
case 'g': /* default gid */
- DefGid = atoi(val);
+ if (isascii(*val) && isdigit(*val))
+ DefGid = atoi(val);
+ else
+ {
+ register struct group *gr;
+
+ DefGid = -1;
+ gr = getgrnam(val);
+ if (gr == NULL)
+ syserr("readcf: option g: unknown group %s", val);
+ else
+ DefGid = gr->gr_gid;
+ }
break;
case 'H': /* help file */
break;
case 'I': /* use internet domain name server */
-#ifdef NAMED_BIND
+#if NAMED_BIND
UseNameServer = TRUE;
for (p = val; *p != 0; )
{
if (strcasecmp(q, rfp->rf_name) == 0)
break;
}
- if (clearmode)
+ if (rfp->rf_name == NULL)
+ syserr("readcf: I option value %s unrecognized", q);
+ else if (clearmode)
_res.options &= ~rfp->rf_bits;
else
_res.options |= rfp->rf_bits;
break;
case 'L': /* log level */
- LogLevel = atoi(val);
+ if (safe || LogLevel < atoi(val))
+ LogLevel = atoi(val);
break;
case 'M': /* define macro */
else
QueueDir = newstr(val);
if (RealUid != 0 && !safe)
- auth_warning(e, "Processed from queue %s", QueueDir);
+ Warn_Q_option = TRUE;
break;
case 'R': /* don't prune routes */
break;
case 'u': /* set default uid */
- DefUid = atoi(val);
+ if (isascii(*val) && isdigit(*val))
+ DefUid = atoi(val);
+ else
+ {
+ register struct passwd *pw;
+
+ DefUid = -1;
+ pw = getpwnam(val);
+ if (pw == NULL)
+ syserr("readcf: option u: unknown user %s", val);
+ else
+ DefUid = pw->pw_uid;
+ }
setdefuser();
break;
Verbose = atobool(val);
break;
- /* 'w' available -- was "no wildcard MX matching" */
+ case 'w': /* if we are best MX, try host directly */
+ TryNullMXList = atobool(val);
+ break;
/* 'W' available -- was wizard password */
register STAB *s;
if (tTd(37, 8))
- printf("%s added to class %c\n", word, class);
+ printf("setclass(%c, %s)\n", class, word);
s = stab(word, ST_CLASS, ST_ENTER);
setbitn(class, s->s_class);
}
register char *p;
char *mapname;
char *classname;
- register STAB *map;
+ register STAB *s;
STAB *class;
for (p = line; isascii(*p) && isspace(*p); p++)
}
/* enter the map */
- map = stab(mapname, ST_MAP, ST_ENTER);
- map->s_map.map_class = &class->s_mapclass;
- map->s_map.map_mname = newstr(mapname);
+ s = stab(mapname, ST_MAP, ST_ENTER);
+ s->s_map.map_class = &class->s_mapclass;
+ s->s_map.map_mname = newstr(mapname);
- if (class->s_mapclass.map_parse(&map->s_map, p))
- map->s_map.map_mflags |= MF_VALID;
+ if (class->s_mapclass.map_parse(&s->s_map, p))
+ s->s_map.map_mflags |= MF_VALID;
+
+ if (tTd(37, 5))
+ {
+ printf("map %s, class %s, flags %x, file %s,\n",
+ s->s_map.map_mname, s->s_map.map_class->map_cname,
+ s->s_map.map_mflags,
+ s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file);
+ printf("\tapp %s, domain %s, rebuild %s\n",
+ s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app,
+ s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain,
+ s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild);
+ }
}
\f/*
** SETTIMEOUTS -- parse and set timeout values
** Initializes the TimeOuts structure
*/
+#define SECONDS
#define MINUTES * 60
#define HOUR * 3600
TimeOuts.to_quit = (time_t) 2 MINUTES;
TimeOuts.to_nextcommand = (time_t) 1 HOUR;
TimeOuts.to_miscshort = (time_t) 2 MINUTES;
+ TimeOuts.to_ident = (time_t) 30 SECONDS;
return;
}
TimeOuts.to_quit = to;
else if (strcasecmp(val, "misc") == 0)
TimeOuts.to_miscshort = to;
+ else if (strcasecmp(val, "ident") == 0)
+ TimeOuts.to_ident = to;
else
syserr("settimeouts: invalid timeout %s", val);
}