2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-29 13:18:12 +00:00

postfix-2.9-20111120

This commit is contained in:
Wietse Venema 2011-11-20 00:00:00 -05:00 committed by Viktor Dukhovni
parent 2cfc3431dc
commit 38b0a080dc
13 changed files with 309 additions and 204 deletions

1
postfix/.indent.pro vendored
View File

@ -186,6 +186,7 @@
-TNAME_CODE -TNAME_CODE
-TNAME_MASK -TNAME_MASK
-TNBBIO -TNBBIO
-TPC_MASTER_ENT
-TPC_SERVICE_DEF -TPC_SERVICE_DEF
-TPC_STRING_NV -TPC_STRING_NV
-TPEER_NAME -TPEER_NAME

View File

@ -17109,3 +17109,13 @@ Apologies for any names omitted.
Cleanup: "postconf" commands in postfix-install needed to Cleanup: "postconf" commands in postfix-install needed to
be updated before master.cf was installed. Reported by be updated before master.cf was installed. Reported by
Sahil Tandon. File: postfix-install. Sahil Tandon. File: postfix-install.
20111120
Cleanup: support for parameter name spaces for master.cf
entries. With this, postconf should no longer log false
warnings for "-o user-defined-name=value" in master.cf. As
a benefit, it will warn for user-defined parameters with
"name=value" entries that are unused because they are hidden
by master.cf "-o name=value" entries with the same parameter
name. File: postconf/postconf.c.

View File

@ -14,6 +14,14 @@ specifies the release date of a stable release or snapshot release.
If you upgrade from Postfix 2.7 or earlier, read RELEASE_NOTES-2.8 If you upgrade from Postfix 2.7 or earlier, read RELEASE_NOTES-2.8
before proceeding. before proceeding.
Major changes with snapshot 20111120
====================================
Eliminated the postconf limitation documented on 20111113 as "lack
of support for per-service parameter name spaces in master.cf,
meaning that "-o user-defined-name=value" always results in an
"unused parameter" warning".
Major changes with snapshot 20111118 Major changes with snapshot 20111118
==================================== ====================================

View File

@ -22,12 +22,14 @@ POSTCONF(1) POSTCONF(1)
<b>postconf</b> [<b>-fMv</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] [<i>service ...</i>] <b>postconf</b> [<b>-fMv</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] [<i>service ...</i>]
<b>Managing bounce message templates:</b>
<b>postconf</b> [<b>-btv</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] [<i>template</i><b>_</b><i>file</i>]
<b>Managing other configuration:</b> <b>Managing other configuration:</b>
<b>postconf</b> [<b>-aAlmv</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] <b>postconf</b> [<b>-aAlmv</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>]
<b>postconf</b> [<b>-btv</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] [<i>template</i><b>_</b><i>file</i>]
<b>DESCRIPTION</b> <b>DESCRIPTION</b>
By default, the <a href="postconf.1.html"><b>postconf</b>(1)</a> command displays the values of By default, the <a href="postconf.1.html"><b>postconf</b>(1)</a> command displays the values of
<a href="postconf.5.html"><b>main.cf</b></a> configuration parameters, and warns about possible <a href="postconf.5.html"><b>main.cf</b></a> configuration parameters, and warns about possible
@ -133,7 +135,7 @@ POSTCONF(1) POSTCONF(1)
human readability. human readability.
If <i>service ...</i> is specified, only the matching ser- If <i>service ...</i> is specified, only the matching ser-
vices will be output. For example, a <i>service</i> <b>of</b> vices will be output. For example, a <i>service</i> of
<b>inet</b> will match all services that listen on the <b>inet</b> will match all services that listen on the
network. network.
@ -287,29 +289,23 @@ POSTCONF(1) POSTCONF(1)
<b>DIAGNOSTICS</b> <b>DIAGNOSTICS</b>
Problems are reported to the standard error stream. Problems are reported to the standard error stream.
<b>BUGS</b>
<a href="postconf.1.html"><b>postconf</b>(1)</a> may log "unused parameter" warnings for <b>mas-</b>
<b>ter.cf</b> entries with "-o user-defined-name=value".
Addressing this limitation requires support for per-ser-
vice parameter name spaces.
<b>ENVIRONMENT</b> <b>ENVIRONMENT</b>
<b>MAIL_CONFIG</b> <b>MAIL_CONFIG</b>
Directory with Postfix configuration files. Directory with Postfix configuration files.
<b>CONFIGURATION PARAMETERS</b> <b>CONFIGURATION PARAMETERS</b>
The following <a href="postconf.5.html"><b>main.cf</b></a> parameters are especially relevant The following <a href="postconf.5.html"><b>main.cf</b></a> parameters are especially relevant
to this program. to this program.
The text below provides only a parameter summary. See The text below provides only a parameter summary. See
<a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including examples. <a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including examples.
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b> <b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
The default location of the Postfix <a href="postconf.5.html">main.cf</a> and The default location of the Postfix <a href="postconf.5.html">main.cf</a> and
<a href="master.5.html">master.cf</a> configuration files. <a href="master.5.html">master.cf</a> configuration files.
<b><a href="postconf.5.html#bounce_template_file">bounce_template_file</a> (empty)</b> <b><a href="postconf.5.html#bounce_template_file">bounce_template_file</a> (empty)</b>
Pathname of a configuration file with bounce mes- Pathname of a configuration file with bounce mes-
sage templates. sage templates.
<b>FILES</b> <b>FILES</b>
@ -324,7 +320,7 @@ POSTCONF(1) POSTCONF(1)
<a href="DATABASE_README.html">DATABASE_README</a>, Postfix lookup table overview <a href="DATABASE_README.html">DATABASE_README</a>, Postfix lookup table overview
<b>LICENSE</b> <b>LICENSE</b>
The Secure Mailer license must be distributed with this The Secure Mailer license must be distributed with this
software. software.
<b>AUTHOR(S)</b> <b>AUTHOR(S)</b>

View File

@ -25,11 +25,13 @@ Postfix configuration utility
\fBpostconf\fR [\fB-fMv\fR] [\fB-c \fIconfig_dir\fR] \fBpostconf\fR [\fB-fMv\fR] [\fB-c \fIconfig_dir\fR]
[\fIservice ...\fR] [\fIservice ...\fR]
\fBManaging bounce message templates:\fR
\fBpostconf\fR [\fB-btv\fR] [\fB-c \fIconfig_dir\fR] [\fItemplate_file\fR]
\fBManaging other configuration:\fR \fBManaging other configuration:\fR
\fBpostconf\fR [\fB-aAlmv\fR] [\fB-c \fIconfig_dir\fR] \fBpostconf\fR [\fB-aAlmv\fR] [\fB-c \fIconfig_dir\fR]
\fBpostconf\fR [\fB-btv\fR] [\fB-c \fIconfig_dir\fR] [\fItemplate_file\fR]
.SH DESCRIPTION .SH DESCRIPTION
.ad .ad
.fi .fi
@ -124,7 +126,7 @@ file contents. Use \fB-Mf\fR to fold long lines for human
readability. readability.
If \fIservice ...\fR is specified, only the matching services If \fIservice ...\fR is specified, only the matching services
will be output. For example, a \fIservice\fB of \fBinet\fR will be output. For example, a \fIservice\fR of \fBinet\fR
will match all services that listen on the network. will match all services that listen on the network.
Specify zero or more arguments, each with a \fIservice-type\fR Specify zero or more arguments, each with a \fIservice-type\fR
@ -244,13 +246,6 @@ This feature is available with Postfix 2.6 and later.
.ad .ad
.fi .fi
Problems are reported to the standard error stream. Problems are reported to the standard error stream.
.SH BUGS
.ad
.fi
\fBpostconf\fR(1) may log "unused parameter" warnings for
\fBmaster.cf\fR entries with "-o user-defined-name=value".
Addressing this limitation requires support for per-service
parameter name spaces.
.SH "ENVIRONMENT" .SH "ENVIRONMENT"
.na .na
.nf .nf

View File

@ -20,7 +20,7 @@
* Patches change both the patchlevel and the release date. Snapshots have no * Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only. * patchlevel; they change the release date only.
*/ */
#define MAIL_RELEASE_DATE "20111119" #define MAIL_RELEASE_DATE "20111120"
#define MAIL_VERSION_NUMBER "2.9" #define MAIL_VERSION_NUMBER "2.9"
#ifdef SNAPSHOT #ifdef SNAPSHOT

View File

@ -36,7 +36,8 @@ Makefile: Makefile.in
test: $(TESTPROG) test: $(TESTPROG)
tests: test1 test2 test3 test4 test5 test6 test7 test8 test9 test10 test11 tests: test1 test2 test3 test4 test5 test6 test7 test8 test9 test10 test11 \
test12 test13 test14 test15
root_tests: root_tests:
@ -100,9 +101,7 @@ test4: $(PROG) test4.ref
rm -f main.cf master.cf test4.tmp rm -f main.cf master.cf test4.tmp
# Define one user-defined parameter with name=value in master.cf, # Define one user-defined parameter with name=value in master.cf,
# validate it with known_parameter=$name in master.cf. Currently, # validate it with known_parameter=$name in master.cf.
# user-defined parameter definitions in master.cf are not recognized
# as definitions, and result in an "unused parameter" warning.
test5: $(PROG) test5.ref test5: $(PROG) test5.ref
rm -f main.cf master.cf rm -f main.cf master.cf
@ -169,6 +168,58 @@ test11: $(PROG) test11.ref
diff test11.ref test11.tmp diff test11.ref test11.tmp
rm -f main.cf master.cf test11.tmp rm -f main.cf master.cf test11.tmp
# Duplicate service entry.
test12: $(PROG) test12.ref
rm -f main.cf master.cf
touch main.cf master.cf
echo bar=yes >> main.cf
echo foo inet - n n - 0 spawn >> master.cf
echo ' -o always_bcc=$$bar -o' >> master.cf
echo foo inet - n n - 0 spawn >> master.cf
echo ' -o always_bcc=$$bar -o' >> master.cf
./$(PROG) -c . -M >test12.tmp 2>&1
diff test12.ref test12.tmp
rm -f main.cf master.cf test12.tmp
# Define parameter with restriction_classes in master.cf, validate in main.cf.
test13: $(PROG) test13.ref
rm -f main.cf master.cf
touch main.cf master.cf
echo bar=yes >> main.cf
echo baz=xx >> main.cf
echo foo inet - n n - 0 spawn >> master.cf
echo ' -o smtpd_restriction_classes=bar' >> master.cf
./$(PROG) -nc . >test13.tmp 2>&1
diff test13.ref test13.tmp
rm -f main.cf master.cf test13.tmp
# Define parameter with restriction_classes in main.cf, validate in master.cf.
test14: $(PROG) test14.ref
rm -f main.cf master.cf
touch main.cf master.cf
echo smtpd_restriction_classes=bar >> main.cf
echo foo inet - n n - 0 spawn >> master.cf
echo ' -o bar=yes -o baz=xx' >> master.cf
./$(PROG) -nc . >test14.tmp 2>&1
diff test14.ref test14.tmp
rm -f main.cf master.cf test14.tmp
# Define two parameters, one is hidden by master.cf.
test15: $(PROG) test15.ref
rm -f main.cf master.cf
touch main.cf master.cf
echo bar=xx >> main.cf
echo baz=yy >> main.cf
echo foo inet - n n - 0 spawn >> master.cf
echo ' -o bar=yes -o always_bcc=$$bar$$baz' >> master.cf
./$(PROG) -nc . >test15.tmp 2>&1
diff test15.ref test15.tmp
rm -f main.cf master.cf test15.tmp
printfck: $(OBJS) $(PROG) printfck: $(OBJS) $(PROG)
rm -rf printfck rm -rf printfck
mkdir printfck mkdir printfck

View File

@ -21,11 +21,13 @@
/* \fBpostconf\fR [\fB-fMv\fR] [\fB-c \fIconfig_dir\fR] /* \fBpostconf\fR [\fB-fMv\fR] [\fB-c \fIconfig_dir\fR]
/* [\fIservice ...\fR] /* [\fIservice ...\fR]
/* /*
/* \fBManaging bounce message templates:\fR
/*
/* \fBpostconf\fR [\fB-btv\fR] [\fB-c \fIconfig_dir\fR] [\fItemplate_file\fR]
/*
/* \fBManaging other configuration:\fR /* \fBManaging other configuration:\fR
/* /*
/* \fBpostconf\fR [\fB-aAlmv\fR] [\fB-c \fIconfig_dir\fR] /* \fBpostconf\fR [\fB-aAlmv\fR] [\fB-c \fIconfig_dir\fR]
/*
/* \fBpostconf\fR [\fB-btv\fR] [\fB-c \fIconfig_dir\fR] [\fItemplate_file\fR]
/* DESCRIPTION /* DESCRIPTION
/* By default, the \fBpostconf\fR(1) command displays the /* By default, the \fBpostconf\fR(1) command displays the
/* values of \fBmain.cf\fR configuration parameters, and warns /* values of \fBmain.cf\fR configuration parameters, and warns
@ -118,7 +120,7 @@
/* readability. /* readability.
/* /*
/* If \fIservice ...\fR is specified, only the matching services /* If \fIservice ...\fR is specified, only the matching services
/* will be output. For example, a \fIservice\fB of \fBinet\fR /* will be output. For example, a \fIservice\fR of \fBinet\fR
/* will match all services that listen on the network. /* will match all services that listen on the network.
/* /*
/* Specify zero or more arguments, each with a \fIservice-type\fR /* Specify zero or more arguments, each with a \fIservice-type\fR
@ -236,11 +238,6 @@
/* This feature is available with Postfix 2.6 and later. /* This feature is available with Postfix 2.6 and later.
/* DIAGNOSTICS /* DIAGNOSTICS
/* Problems are reported to the standard error stream. /* Problems are reported to the standard error stream.
/* BUGS
/* \fBpostconf\fR(1) may log "unused parameter" warnings for
/* \fBmaster.cf\fR entries with "-o user-defined-name=value".
/* Addressing this limitation requires support for per-service
/* parameter name spaces.
/* ENVIRONMENT /* ENVIRONMENT
/* .ad /* .ad
/* .fi /* .fi
@ -358,7 +355,7 @@
#define FOLD_LINE (1<<11) /* fold long *.cf entries */ #define FOLD_LINE (1<<11) /* fold long *.cf entries */
/* /*
* Lookup table for in-core parameter info. * Lookup table for global parameter info.
* *
* XXX Change the value pointers from table indices into pointers to parameter * XXX Change the value pointers from table indices into pointers to parameter
* objects with print methods. * objects with print methods.
@ -366,13 +363,21 @@
HTABLE *param_table; HTABLE *param_table;
/* /*
* Lookup table for master.cf info. * Global restriction_classes hash.
*
* XXX Replace by data structures with per-entry hashes for "-o name=value", so
* that we can properly handle name=value definitions in per-service name
* spaces.
*/ */
static ARGV **master_table; HTABLE *rest_class_table;
/*
* Lookup table for master.cf info. The table is null-terminated.
*/
typedef struct {
char *name_space; /* service.type, parameter name space */
ARGV *argv; /* terminator, or master.cf fields */
DICT *all_params; /* all name=value entries */
HTABLE *valid_names; /* "blessed" parameters */
} PC_MASTER_ENT;
static PC_MASTER_ENT *master_table;
/* /*
* Support for built-in parameters: declarations generated by scanning * Support for built-in parameters: declarations generated by scanning
@ -458,24 +463,25 @@ static ssize_t serv_param_tablen;
* *
* There are three categories of known parameters: built-in, service-defined * There are three categories of known parameters: built-in, service-defined
* (see previous comment), and valid user-defined. In addition there are * (see previous comment), and valid user-defined. In addition there are
* multiple name spaces: the global main.cf name space, and the per-service * multiple name spaces: the global main.cf name space, and the local name
* name space of each master.cf entry. * space of each master.cf entry.
* *
* There are two categories of valid user-defined parameters: * There are two categories of valid user-defined parameters:
* *
* - Parameters whose name appears in the value of smtpd_restriction_classes in * - Parameters whose user-defined-name appears in the value of
* main.cf, and whose name has a "name=value" entry in main.cf (todo: * smtpd_restriction_classes in main.cf or master.cf, and that have a
* support for creating names with "-o smtpd_restriction_classes=name" * "user-defined-name=value" entry in main.cf or master.cf.
* within a master.cf per-service name space).
* *
* - Parameters whose $name (macro expansion) appears in the value of a * - Parameters whose $user-defined-name appears in the value of a "name=value"
* "name=value" entry in main.cf or master.cf of a "known" parameter, and * entry in main.cf or master.cf, and whose user-defined-name has a
* whose name has a "name=value" entry in main.cf (todo: master.cf). * "name=value" entry in main.cf or master.cf.
* *
* All other user-defined parameters are invalid. We currently log a warning * Other user-defined parameters are flagged as "unused".
* for "name=value" entries in main.cf or master.cf whose $name does not */
* appear in the value of a main.cf or master.cf "name=value" entry of a
* "known" parameter. /*
* Global-scope valid user-defined parameter names. The local-scope valid
* user-defined names are kept in the table with master.cf entries.
*/ */
static char **user_param_table; static char **user_param_table;
static ssize_t user_param_tablen; static ssize_t user_param_tablen;
@ -820,10 +826,12 @@ static void read_master(void)
path = concatenate(var_config_dir, "/", MASTER_CONF_FILE, (char *) 0); path = concatenate(var_config_dir, "/", MASTER_CONF_FILE, (char *) 0);
/* /*
* We can't use the master_ent routines in their current form. They * We can't use the master daemon's master_ent routines in their current
* convert everything to internal form, and they skip disabled services. * form. They convert everything to internal form, and they skip disabled
* We need to be able to show default fields as "-", and we need to know * services.
* about all service names so that we can generate service-dependent *
* The postconf command needs to show default fields as "-", and needs to
* know about all service names so that it can generate service-dependent
* parameter names (transport-dependent etc.). * parameter names (transport-dependent etc.).
*/ */
#define MASTER_BLANKS " \t\r\n" /* XXX */ #define MASTER_BLANKS " \t\r\n" /* XXX */
@ -832,7 +840,7 @@ static void read_master(void)
/* /*
* Initialize the in-memory master table. * Initialize the in-memory master table.
*/ */
master_table = (ARGV **) mymalloc(sizeof(*master_table)); master_table = (PC_MASTER_ENT *) mymalloc(sizeof(*master_table));
/* /*
* Skip blank lines and comment lines. * Skip blank lines and comment lines.
@ -840,14 +848,23 @@ static void read_master(void)
if ((fp = vstream_fopen(path, O_RDONLY, 0)) == 0) if ((fp = vstream_fopen(path, O_RDONLY, 0)) == 0)
msg_fatal("open %s: %m", path); msg_fatal("open %s: %m", path);
while (readlline(buf, fp, &line_count) != 0) { while (readlline(buf, fp, &line_count) != 0) {
master_table = (ARGV **) myrealloc((char *) master_table, master_table = (PC_MASTER_ENT *) myrealloc((char *) master_table,
(entry_count + 2) * sizeof(*master_table)); (entry_count + 2) * sizeof(*master_table));
argv = argv_split(STR(buf), MASTER_BLANKS); argv = argv_split(STR(buf), MASTER_BLANKS);
if (argv->argc < MASTER_FIELD_COUNT) if (argv->argc < MASTER_FIELD_COUNT)
msg_fatal("file %s: line %d: bad field count", path, line_count); msg_fatal("file %s: line %d: bad field count", path, line_count);
master_table[entry_count++] = argv; master_table[entry_count].name_space =
concatenate(argv->argv[0], ".", argv->argv[1], (char *) 0);
master_table[entry_count].argv = argv;
master_table[entry_count].valid_names = 0;
master_table[entry_count].all_params = 0;
entry_count += 1;
} }
master_table[entry_count] = 0;
/*
* Null-terminate the master table and clean up.
*/
master_table[entry_count].argv = 0;
vstream_fclose(fp); vstream_fclose(fp);
myfree(path); myfree(path);
vstring_free(buf); vstring_free(buf);
@ -938,7 +955,7 @@ static void add_service_parameters(void)
const PC_STRING_NV *sp; const PC_STRING_NV *sp;
const char *progname; const char *progname;
const char *service; const char *service;
ARGV **argvp; PC_MASTER_ENT *masterp;
ARGV *argv; ARGV *argv;
const PC_SERVICE_DEF *sd; const PC_SERVICE_DEF *sd;
@ -952,7 +969,7 @@ static void add_service_parameters(void)
* Extract service names from master.cf and generate service parameter * Extract service names from master.cf and generate service parameter
* information. * information.
*/ */
for (argvp = master_table; (argv = *argvp) != 0; argvp++) { for (masterp = master_table; (argv = masterp->argv) != 0; masterp++) {
/* /*
* Add service parameters for message delivery transports or spawn * Add service parameters for message delivery transports or spawn
@ -978,118 +995,152 @@ static void add_service_parameters(void)
htable_enter(param_table, sp->name, (char *) sp); htable_enter(param_table, sp->name, (char *) sp);
} }
/* add_user_parameter - add one user-defined parameter name */ /* scan_user_parameter_value - examine macro names in parameter value */
static void add_user_parameter(const char *name)
{
/* XXX Merge this with check_parameter_value() */
user_param_table = (char **)
myrealloc((char *) user_param_table,
(user_param_tablen + 1) * sizeof(*user_param_table));
user_param_table[user_param_tablen] = mystrdup(name);
user_param_tablen += 1;
}
/* scan_user_parameter_value - extract macro names from parameter value */
#define NO_SCAN_RESULT ((VSTRING *) 0) #define NO_SCAN_RESULT ((VSTRING *) 0)
#define NO_SCAN_FILTER ((char *) 0) #define NO_SCAN_FILTER ((char *) 0)
#define NO_SCAN_MODE (0) #define NO_SCAN_MODE (0)
#define NO_SCAN_CONTEXT ((char *) 0)
#define scan_user_parameter_value(value) do { \ #define scan_user_parameter_value(value, context) do { \
(void) mac_expand(NO_SCAN_RESULT, (value), MAC_EXP_FLAG_SCAN, \ (void) mac_expand(NO_SCAN_RESULT, (value), MAC_EXP_FLAG_SCAN, \
NO_SCAN_FILTER, check_user_parameter, NO_SCAN_CONTEXT); \ NO_SCAN_FILTER, check_user_parameter, (context)); \
} while (0) } while (0)
/* check_user_parameter - try to promote user-defined parameter */ /* check_user_parameter - promote user-defined name if it has name=value */
static const char *check_user_parameter(const char *mac_name, static const char *check_user_parameter(const char *mac_name,
int unused_mode, int unused_mode,
char *unused_context) char *context)
{ {
const char *mac_value; PC_MASTER_ENT *local_scope = (PC_MASTER_ENT *) context;
/* /*
* Promote only user-defined parameters with an explicit "name=value" * Promote only user-defined parameters with an explicit "name=value"
* definition in main.cf (todo: master.cf). Do not promote parameters * definition. If the name=value exists in the local scope, update the
* whose name appears only as a macro expansion; this is how Postfix * local "valid" parameter name table, otherwise update the global one.
* implements backwards compatibility after a feature name change.
* *
* Skip parameters that are already in the param_table hash. * Do not promote user-defined parameters whose name appears only as macro
* expansion; this is how Postfix implements backwards compatibility
* after a feature name change.
*
* Skip global names that are already in the param_table hash.
*/ */
if (htable_locate(param_table, mac_name) == 0) { if (local_scope && dict_get(local_scope->all_params, mac_name)) {
mac_value = mail_conf_lookup(mac_name); if (htable_locate(local_scope->valid_names, mac_name) == 0)
if (mac_value != 0) { htable_enter(local_scope->valid_names, mac_name, "");
add_user_parameter(mac_name); } else if (htable_locate(param_table, mac_name) == 0) {
/* Promote parameter names recursively. */ if (mail_conf_lookup(mac_name) != 0) {
scan_user_parameter_value(mac_value); user_param_table = (char **)
myrealloc((char *) user_param_table,
(user_param_tablen + 1) * sizeof(*user_param_table));
user_param_table[user_param_tablen] = mystrdup(mac_name);
user_param_tablen += 1;
} }
} }
return (0); return (0);
} }
/* pc_lookup_eval - generalized mail_conf_lookup_eval */
static const char *pc_lookup_eval(const char *dict_name, const char *name)
{
const char *value;
#define RECURSIVE 1
if ((value = dict_lookup(dict_name, name)) != 0)
value = dict_eval(dict_name, value, RECURSIVE);
return (value);
}
/* scan_user_parameter_namespace - scan parameters in name space */
static void scan_user_parameter_namespace(const char *dict_name,
PC_MASTER_ENT *local_scope)
{
const char *myname = "scan_user_parameter_namespace";
const char *class_list;
char *saved_class_list;
char *cp;
DICT *dict;
char *param_name;
int how;
const char *cparam_name;
const char *cparam_value;
/*
* Add parameters whose names are defined with smtpd_restriction_classes,
* but only if they have a "name=value" entry. If we are in the global
* scope, update the global restriction class name table, so that we can
* query the table from within a local master.cf name space.
*/
if ((class_list = pc_lookup_eval(dict_name, VAR_REST_CLASSES)) != 0) {
cp = saved_class_list = mystrdup(class_list);
while ((param_name = mystrtok(&cp, ", \t\r\n")) != 0) {
if (local_scope == 0
&& htable_locate(rest_class_table, param_name) == 0)
htable_enter(rest_class_table, param_name, "");
check_user_parameter(param_name, NO_SCAN_MODE,
(char *) local_scope);
}
myfree(saved_class_list);
}
/*
* For all "name=value" instances: a) if the scope is local and the name
* appears in the global restriction class table, flag the name as
* "valid" in the local scope; b) scan the value for macro expansions of
* unknown parameter names, and flag those parameter names as "valid" if
* they have a "name=value" entry.
*/
if ((dict = dict_handle(dict_name)) == 0)
msg_panic("%s: parameter dictionary %s not found",
myname, dict_name);
if (dict->sequence == 0)
msg_panic("%s: parameter dictionary %s has no iterator",
myname, dict_name);
for (how = DICT_SEQ_FUN_FIRST;
dict->sequence(dict, how, &cparam_name, &cparam_value) == 0;
how = DICT_SEQ_FUN_NEXT) {
if (local_scope != 0
&& htable_locate(local_scope->valid_names, cparam_name) == 0
&& htable_locate(rest_class_table, cparam_name) != 0)
htable_enter(local_scope->valid_names, cparam_name, "");
scan_user_parameter_value(cparam_value, (char *) local_scope);
}
}
/* add_user_parameters - add parameters with user-defined names */ /* add_user_parameters - add parameters with user-defined names */
static void add_user_parameters(void) static void add_user_parameters(void)
{ {
const char *class_list; PC_MASTER_ENT *masterp;
char *saved_class_list;
char *cp;
const char *cparam_value;
HTABLE_INFO **ht_info;
HTABLE_INFO **ht;
ARGV **argvp;
ARGV *argv; ARGV *argv;
char *arg; char *arg;
int field; int field;
char *saved_arg; char *saved_arg;
char *param_name; char *param_name;
char *param_value; char *param_value;
DICT *dict;
char **up; char **up;
/* /*
* Initialize the table with user-defined parameter names and values. * Initialize the global table with user-defined parameter names, and the
* table with global restriction class names.
*/ */
user_param_table = (char **) mymalloc(1); user_param_table = (char **) mymalloc(1);
user_param_tablen = 0; user_param_tablen = 0;
rest_class_table = htable_create(1);
/* /*
* Add parameters whose names are defined with smtpd_restriction_classes, * Scan the explicit name=value entries in the global name space.
* but only if they have a "name=value" entry in main.cf.
*
* XXX It is possible that a user-defined parameter is defined in master.cf
* with "-o smtpd_restriction_classes=name -o name=value". This requires
* name space support for master.cf entries. Without this, we always log
* "unused parameter" warnings for "-o user-defined-name=value" entries.
*/ */
if ((class_list = mail_conf_lookup_eval(VAR_REST_CLASSES)) != 0) { scan_user_parameter_namespace(CONFIG_DICT, (PC_MASTER_ENT *) 0);
cp = saved_class_list = mystrdup(class_list);
while ((param_name = mystrtok(&cp, ", \t\r\n")) != 0)
check_user_parameter(param_name, NO_SCAN_MODE, NO_SCAN_CONTEXT);
myfree(saved_class_list);
}
/* /*
* Parse the "name=value" instances in main.cf of built-in and service * Scan the "-o parameter=value" instances in each master.cf name space.
* parameters only, look for macro expansions of unknown parameter names,
* and flag those parameter names as "known" if they have a "name=value"
* entry in main.cf. Recursively apply the procedure to the values of
* newly-flagged parameters.
*/ */
for (ht_info = ht = htable_list(param_table); *ht; ht++) for (masterp = master_table; (argv = masterp->argv) != 0; masterp++) {
if ((cparam_value = mail_conf_lookup(ht[0]->key)) != 0)
scan_user_parameter_value(cparam_value);
myfree((char *) ht_info);
/*
* Parse all "-o parameter=value" instances in master.cf, look for macro
* expansions of unknown parameter names, and flag those parameter names
* as "known" if they have a "name=value" entry in main.cf (XXX todo: in
* master.cf; without master.cf name space support we always log "unused
* parameter" warnings for "-o user-defined-name=value" entries).
*/
for (argvp = master_table; (argv = *argvp) != 0; argvp++) {
for (field = MASTER_FIELD_COUNT; argv->argv[field] != 0; field++) { for (field = MASTER_FIELD_COUNT; argv->argv[field] != 0; field++) {
arg = argv->argv[field]; arg = argv->argv[field];
if (arg[0] != '-') if (arg[0] != '-')
@ -1097,11 +1148,16 @@ static void add_user_parameters(void)
if (strcmp(arg, "-o") == 0 && (arg = argv->argv[field + 1]) != 0) { if (strcmp(arg, "-o") == 0 && (arg = argv->argv[field + 1]) != 0) {
saved_arg = mystrdup(arg); saved_arg = mystrdup(arg);
if (split_nameval(saved_arg, &param_name, &param_value) == 0) if (split_nameval(saved_arg, &param_name, &param_value) == 0)
scan_user_parameter_value(param_value); dict_update(masterp->name_space, param_name, param_value);
myfree(saved_arg); myfree(saved_arg);
field += 1; field += 1;
} }
} }
if ((dict = dict_handle(masterp->name_space)) != 0) {
masterp->all_params = dict;
masterp->valid_names = htable_create(1);
scan_user_parameter_namespace(masterp->name_space, masterp);
}
} }
/* /*
@ -1756,35 +1812,25 @@ static void print_master_line(int mode, ARGV *argv)
static void show_master(int mode, char **filters) static void show_master(int mode, char **filters)
{ {
ARGV **argvp; PC_MASTER_ENT *masterp;
ARGV *argv; ARGV *argv;
VSTRING *service_name = 0;
ARGV *service_filter = 0; ARGV *service_filter = 0;
/* /*
* Initialize the service filter. * Initialize the service filter.
*/ */
if (filters[0]) { if (filters[0])
service_name = vstring_alloc(10);
service_filter = match_service_init_argv(filters); service_filter = match_service_init_argv(filters);
}
/* /*
* Iterate over the master table. * Iterate over the master table.
*/ */
for (argvp = master_table; (argv = *argvp) != 0; argvp++) { for (masterp = master_table; (argv = masterp->argv) != 0; masterp++)
if (service_filter) { if (service_filter == 0
vstring_sprintf(service_name, "%s.%s", || match_service_match(service_filter, masterp->name_space) != 0)
argv->argv[0], argv->argv[1]); print_master_line(mode, argv);
if (match_service_match(service_filter, STR(service_name)) == 0) if (service_filter != 0)
continue;
}
print_master_line(mode, argv);
}
if (service_filter) {
argv_free(service_filter); argv_free(service_filter);
vstring_free(service_name);
}
} }
/* show_sasl - show SASL plug-in types */ /* show_sasl - show SASL plug-in types */
@ -1801,79 +1847,67 @@ static void show_sasl(int what)
argv_free(sasl_argv); argv_free(sasl_argv);
} }
/* flag_unused_parameters - warn about unused parameters */
static void flag_unused_parameters(DICT *dict, const char *conf_name,
PC_MASTER_ENT *local_scope)
{
const char *myname = "flag_unused_parameters";
const char *param_name;
const char *param_value;
int how;
/*
* Iterate over all entries, and flag parameter names that aren't used
* anywhere. Show the warning message at the end of the output.
*/
if (dict->sequence == 0)
msg_panic("%s: parameter dictionary %s has no iterator",
myname, conf_name);
for (how = DICT_SEQ_FUN_FIRST;
dict->sequence(dict, how, &param_name, &param_value) == 0;
how = DICT_SEQ_FUN_NEXT) {
if (htable_locate(param_table, param_name) == 0
&& (local_scope == 0
|| htable_locate(local_scope->valid_names, param_name) == 0)) {
vstream_fflush(VSTREAM_OUT);
msg_warn("%s/%s: unused parameter: %s=%s",
var_config_dir, conf_name, param_name, param_value);
}
}
}
/* flag_unused_main_parameters - warn about unused parameters */ /* flag_unused_main_parameters - warn about unused parameters */
static void flag_unused_main_parameters(void) static void flag_unused_main_parameters(void)
{ {
const char *myname = "flag_unused_main_parameters"; const char *myname = "flag_unused_main_parameters";
DICT *dict; DICT *dict;
const char *param_name;
const char *param_value;
int how;
/* /*
* Iterate over all main.cf entries, and flag parameter names that aren't * Iterate over all main.cf entries, and flag parameter names that aren't
* used anywhere. Show the warning message at the end of the output. * used anywhere.
*/ */
if ((dict = dict_handle(CONFIG_DICT)) == 0) if ((dict = dict_handle(CONFIG_DICT)) == 0)
msg_panic("%s: parameter dictionary %s not found", msg_panic("%s: parameter dictionary %s not found",
myname, CONFIG_DICT); myname, CONFIG_DICT);
if (dict->sequence == 0) flag_unused_parameters(dict, MAIN_CONF_FILE, (PC_MASTER_ENT *) 0);
msg_panic("%s: parameter dictionary %s has no iterator",
myname, CONFIG_DICT);
for (how = DICT_SEQ_FUN_FIRST;
dict->sequence(dict, how, &param_name, &param_value) == 0;
how = DICT_SEQ_FUN_NEXT) {
if (htable_locate(param_table, param_name) == 0) {
vstream_fflush(VSTREAM_OUT);
msg_warn("%s/" MAIN_CONF_FILE ": unused parameter: %s=%s",
var_config_dir, param_name, param_value);
}
}
} }
/* flag_unused_master_parameters - warn about unused parameters */ /* flag_unused_master_parameters - warn about unused parameters */
static void flag_unused_master_parameters(void) static void flag_unused_master_parameters(void)
{ {
ARGV **argvp; PC_MASTER_ENT *masterp;
ARGV *argv; DICT *dict;
int field;
char *arg;
char *saved_arg;
char *param_name;
char *param_value;
/* /*
* Iterate over all master.cf entries, and flag parameter names that * Iterate over all master.cf entries, and flag parameter names that
* aren't used anywhere. Show the warning message at the end of the * aren't used anywhere.
* output.
*
* XXX It is possible that a user-defined parameter is defined in master.cf
* with "-o smtpd_restriction_classes=name", or with "-o name1=value1"
* and then used in a "-o name2=$name1" macro expansion in that same
* master.cf entry. To handle this we need to give each master.cf entry
* its own name space. Until then, we always log "unused parameter"
* warnings for "-o user-defined-name=value" entries.
*/ */
for (argvp = master_table; (argv = *argvp) != 0; argvp++) { for (masterp = master_table; masterp->argv != 0; masterp++)
for (field = MASTER_FIELD_COUNT; argv->argv[field] != 0; field++) { if ((dict = masterp->all_params) != 0)
arg = argv->argv[field]; flag_unused_parameters(dict, MASTER_CONF_FILE, masterp);
if (arg[0] != '-')
break;
if (strcmp(arg, "-o") == 0 && (arg = argv->argv[field + 1]) != 0) {
saved_arg = mystrdup(arg);
if (split_nameval(saved_arg, &param_name, &param_value) == 0
&& htable_locate(param_table, param_name) == 0) {
vstream_fflush(VSTREAM_OUT);
msg_warn("%s/" MASTER_CONF_FILE ": unused parameter: %s=%s",
var_config_dir, param_name, param_value);
}
myfree(saved_arg);
field += 1;
}
}
}
} }
MAIL_VERSION_STAMP_DECLARE; MAIL_VERSION_STAMP_DECLARE;

View File

@ -0,0 +1,2 @@
foo inet - n n - 0 spawn -o always_bcc=$bar -o
foo inet - n n - 0 spawn -o always_bcc=$bar -o

View File

@ -0,0 +1,3 @@
bar = yes
config_directory = .
./postconf: warning: ./main.cf: unused parameter: baz=xx

View File

@ -0,0 +1,3 @@
config_directory = .
smtpd_restriction_classes = bar
./postconf: warning: ./master.cf: unused parameter: baz=xx

View File

@ -0,0 +1,3 @@
baz = yy
config_directory = .
./postconf: warning: ./main.cf: unused parameter: bar=xx

View File

@ -1,2 +1 @@
config_directory = . config_directory = .
./postconf: warning: ./master.cf: unused parameter: bar=yes