]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.9-20111120
authorWietse Venema <wietse@porcupine.org>
Sun, 20 Nov 2011 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:37:38 +0000 (06:37 +0000)
13 files changed:
postfix/.indent.pro
postfix/HISTORY
postfix/RELEASE_NOTES
postfix/html/postconf.1.html
postfix/man/man1/postconf.1
postfix/src/global/mail_version.h
postfix/src/postconf/Makefile.in
postfix/src/postconf/postconf.c
postfix/src/postconf/test12.ref [new file with mode: 0644]
postfix/src/postconf/test13.ref [new file with mode: 0644]
postfix/src/postconf/test14.ref [new file with mode: 0644]
postfix/src/postconf/test15.ref [new file with mode: 0644]
postfix/src/postconf/test5.ref

index 789741ca48476f734c63266e1dceee823c4cf129..32e60db68fbd8f435d01d9915853b4551005c6eb 100644 (file)
 -TNAME_CODE
 -TNAME_MASK
 -TNBBIO
+-TPC_MASTER_ENT
 -TPC_SERVICE_DEF
 -TPC_STRING_NV
 -TPEER_NAME
index 5dcb4d224f3bb940a0590381d35cc24af12ba0a3..1febd671563b6b98de27b211ec32fe41189d32e0 100644 (file)
@@ -17109,3 +17109,13 @@ Apologies for any names omitted.
        Cleanup: "postconf" commands in postfix-install needed to
        be updated before master.cf was installed.  Reported by
        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.
index 6e8ce5ad17af15361bf4c6073d0c1a72aba24722..2b03dba0b018eb0a2c9d245cbeede525f2defa0b 100644 (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
 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
 ====================================
 
index 0c4ed0a047496d9627d673f31ba9cb303cf153a4..b966b6a6241c60499011e44a9ac4b6a62c31ad43 100644 (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>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>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>
        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
@@ -133,7 +135,7 @@ POSTCONF(1)                                                        POSTCONF(1)
               human readability.
 
               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
               network.
 
@@ -287,29 +289,23 @@ POSTCONF(1)                                                        POSTCONF(1)
 <b>DIAGNOSTICS</b>
        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>MAIL_CONFIG</b>
               Directory with Postfix configuration files.
 
 <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.
 
-       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.
 
        <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.
 
        <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.
 
 <b>FILES</b>
@@ -324,7 +320,7 @@ POSTCONF(1)                                                        POSTCONF(1)
        <a href="DATABASE_README.html">DATABASE_README</a>, Postfix lookup table overview
 
 <b>LICENSE</b>
-       The  Secure  Mailer  license must be distributed with this
+       The Secure Mailer license must be  distributed  with  this
        software.
 
 <b>AUTHOR(S)</b>
index e572dd5a8a31063ba304eaf469195850b3e6d773..fbcf98f69ec839d12f4eb9219e4353df429aa7ac 100644 (file)
@@ -25,11 +25,13 @@ Postfix configuration utility
 \fBpostconf\fR [\fB-fMv\fR] [\fB-c \fIconfig_dir\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
 
 \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
 .ad
 .fi
@@ -124,7 +126,7 @@ file contents.  Use \fB-Mf\fR to fold long lines for human
 readability.
 
 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.
 
 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
 .fi
 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"
 .na
 .nf
index f92a34a8271e6d6432bf72ab3a434fe528464c8c..07aee6e5dca8b4aac7cfd569e3c89c115c64e77f 100644 (file)
@@ -20,7 +20,7 @@
   * Patches change both the patchlevel and the release date. Snapshots have no
   * patchlevel; they change the release date only.
   */
-#define MAIL_RELEASE_DATE      "20111119"
+#define MAIL_RELEASE_DATE      "20111120"
 #define MAIL_VERSION_NUMBER    "2.9"
 
 #ifdef SNAPSHOT
index 63701be546360e2814ca2a4d44257b13ecbf0a50..ca31397cd45a7bcb6df070a054748ee5af43b23a 100644 (file)
@@ -36,7 +36,8 @@ Makefile: Makefile.in
 
 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:
 
@@ -100,9 +101,7 @@ test4:      $(PROG) test4.ref
        rm -f main.cf master.cf test4.tmp
 
 # Define one user-defined parameter with name=value in master.cf,
-# validate it with known_parameter=$name in master.cf.  Currently,
-# user-defined parameter definitions in master.cf are not recognized
-# as definitions, and result in an "unused parameter" warning.
+# validate it with known_parameter=$name in master.cf.
 
 test5: $(PROG) test5.ref
        rm -f main.cf master.cf
@@ -169,6 +168,58 @@ test11:    $(PROG) test11.ref
        diff test11.ref 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)
        rm -rf printfck
        mkdir printfck
index ac96720cafa71a53a5033e1aebcca3fe9280b8fd..6c8108db2ac59958672364d4c34d65f5dd1610b5 100644 (file)
 /*     \fBpostconf\fR [\fB-fMv\fR] [\fB-c \fIconfig_dir\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
 /*
 /*     \fBpostconf\fR [\fB-aAlmv\fR] [\fB-c \fIconfig_dir\fR]
-/*
-/*     \fBpostconf\fR [\fB-btv\fR] [\fB-c \fIconfig_dir\fR] [\fItemplate_file\fR]
 /* DESCRIPTION
 /*     By default, the \fBpostconf\fR(1) command displays the
 /*     values of \fBmain.cf\fR configuration parameters, and warns
 /*     readability.
 /*
 /*     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.
 /*
 /*     Specify zero or more arguments, each with a \fIservice-type\fR
 /*     This feature is available with Postfix 2.6 and later.
 /* DIAGNOSTICS
 /*     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
 /* .ad
 /* .fi
 #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
   * objects with print methods.
 HTABLE *param_table;
 
  /*
-  * Lookup table for master.cf info.
-  * 
-  * 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.
+  * Global restriction_classes hash.
   */
-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
@@ -458,24 +463,25 @@ static ssize_t serv_param_tablen;
   * 
   * There are three categories of known parameters: built-in, service-defined
   * (see previous comment), and valid user-defined. In addition there are
-  * multiple name spaces: the global main.cf name space, and the per-service
-  * name space of each master.cf entry.
+  * multiple name spaces: the global main.cf name space, and the local name
+  * space of each master.cf entry.
   * 
   * There are two categories of valid user-defined parameters:
   * 
-  * - Parameters whose name appears in the value of smtpd_restriction_classes in
-  * main.cf, and whose name has a "name=value" entry in main.cf (todo:
-  * support for creating names with "-o smtpd_restriction_classes=name"
-  * within a master.cf per-service name space).
+  * - Parameters whose user-defined-name appears in the value of
+  * smtpd_restriction_classes in main.cf or master.cf, and that have a
+  * "user-defined-name=value" entry in main.cf or master.cf.
   * 
-  * - Parameters whose $name (macro expansion) appears in the value of a
-  * "name=value" entry in main.cf or master.cf of a "known" parameter, and
-  * whose name has a "name=value" entry in main.cf (todo: master.cf).
+  * - Parameters whose $user-defined-name appears in the value of a "name=value"
+  * entry in main.cf or master.cf, and whose user-defined-name has a
+  * "name=value" entry in main.cf or master.cf.
   * 
-  * All other user-defined parameters are invalid. We currently log a warning
-  * 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.
+  * Other user-defined parameters are flagged as "unused".
+  */
+
+ /*
+  * 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 ssize_t user_param_tablen;
@@ -820,10 +826,12 @@ static void read_master(void)
     path = concatenate(var_config_dir, "/", MASTER_CONF_FILE, (char *) 0);
 
     /*
-     * We can't use the master_ent routines in their current form. They
-     * convert everything to internal form, and they skip disabled services.
-     * We need to be able to show default fields as "-", and we need to know
-     * about all service names so that we can generate service-dependent
+     * We can't use the master daemon's master_ent routines in their current
+     * form. They convert everything to internal form, and they skip disabled
+     * services.
+     * 
+     * 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.).
      */
 #define MASTER_BLANKS  " \t\r\n"               /* XXX */
@@ -832,7 +840,7 @@ static void read_master(void)
     /*
      * 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.
@@ -840,14 +848,23 @@ static void read_master(void)
     if ((fp = vstream_fopen(path, O_RDONLY, 0)) == 0)
        msg_fatal("open %s: %m", path);
     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));
        argv = argv_split(STR(buf), MASTER_BLANKS);
        if (argv->argc < MASTER_FIELD_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);
     myfree(path);
     vstring_free(buf);
@@ -938,7 +955,7 @@ static void add_service_parameters(void)
     const PC_STRING_NV *sp;
     const char *progname;
     const char *service;
-    ARGV  **argvp;
+    PC_MASTER_ENT *masterp;
     ARGV   *argv;
     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
      * 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
@@ -978,118 +995,152 @@ static void add_service_parameters(void)
            htable_enter(param_table, sp->name, (char *) sp);
 }
 
-/* add_user_parameter - add one user-defined parameter name */
-
-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 */
+/* scan_user_parameter_value - examine macro names in parameter value */
 
 #define NO_SCAN_RESULT ((VSTRING *) 0)
 #define NO_SCAN_FILTER ((char *) 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, \
-                   NO_SCAN_FILTER, check_user_parameter, NO_SCAN_CONTEXT); \
+                   NO_SCAN_FILTER, check_user_parameter, (context)); \
 } 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,
                                                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"
-     * definition in main.cf (todo: master.cf). Do not promote parameters
-     * whose name appears only as a macro expansion; this is how Postfix
-     * implements backwards compatibility after a feature name change.
+     * definition. If the name=value exists in the local scope, update the
+     * local "valid" parameter name table, otherwise update the global one.
+     * 
+     * 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 parameters that are already in the param_table hash.
+     * Skip global names that are already in the param_table hash.
      */
-    if (htable_locate(param_table, mac_name) == 0) {
-       mac_value = mail_conf_lookup(mac_name);
-       if (mac_value != 0) {
-           add_user_parameter(mac_name);
-           /* Promote parameter names recursively. */
-           scan_user_parameter_value(mac_value);
+    if (local_scope && dict_get(local_scope->all_params, mac_name)) {
+       if (htable_locate(local_scope->valid_names, mac_name) == 0)
+           htable_enter(local_scope->valid_names, mac_name, "");
+    } else if (htable_locate(param_table, mac_name) == 0) {
+       if (mail_conf_lookup(mac_name) != 0) {
+           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);
 }
 
-/* add_user_parameters - add parameters with user-defined names */
+/* pc_lookup_eval - generalized mail_conf_lookup_eval */
 
-static void add_user_parameters(void)
+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;
-    HTABLE_INFO **ht_info;
-    HTABLE_INFO **ht;
-    ARGV  **argvp;
+
+    /*
+     * 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 */
+
+static void add_user_parameters(void)
+{
+    PC_MASTER_ENT *masterp;
     ARGV   *argv;
     char   *arg;
     int     field;
     char   *saved_arg;
     char   *param_name;
     char   *param_value;
+    DICT   *dict;
     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_tablen = 0;
+    rest_class_table = htable_create(1);
 
     /*
-     * Add parameters whose names are defined with smtpd_restriction_classes,
-     * 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.
+     * Scan the explicit name=value entries in the global name space.
      */
-    if ((class_list = mail_conf_lookup_eval(VAR_REST_CLASSES)) != 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);
-    }
+    scan_user_parameter_namespace(CONFIG_DICT, (PC_MASTER_ENT *) 0);
 
     /*
-     * Parse the "name=value" instances in main.cf of built-in and service
-     * 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.
+     * Scan the "-o parameter=value" instances in each master.cf name space.
      */
-    for (ht_info = ht = htable_list(param_table); *ht; ht++)
-       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 (masterp = master_table; (argv = masterp->argv) != 0; masterp++) {
        for (field = MASTER_FIELD_COUNT; argv->argv[field] != 0; field++) {
            arg = argv->argv[field];
            if (arg[0] != '-')
@@ -1097,11 +1148,16 @@ static void add_user_parameters(void)
            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)
-                   scan_user_parameter_value(param_value);
+                   dict_update(masterp->name_space, param_name, param_value);
                myfree(saved_arg);
                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)
 {
-    ARGV  **argvp;
+    PC_MASTER_ENT *masterp;
     ARGV   *argv;
-    VSTRING *service_name = 0;
     ARGV   *service_filter = 0;
 
     /*
      * Initialize the service filter.
      */
-    if (filters[0]) {
-       service_name = vstring_alloc(10);
+    if (filters[0])
        service_filter = match_service_init_argv(filters);
-    }
 
     /*
      * Iterate over the master table.
      */
-    for (argvp = master_table; (argv = *argvp) != 0; argvp++) {
-       if (service_filter) {
-           vstring_sprintf(service_name, "%s.%s",
-                           argv->argv[0], argv->argv[1]);
-           if (match_service_match(service_filter, STR(service_name)) == 0)
-               continue;
-       }
-       print_master_line(mode, argv);
-    }
-    if (service_filter) {
+    for (masterp = master_table; (argv = masterp->argv) != 0; masterp++)
+       if (service_filter == 0
+           || match_service_match(service_filter, masterp->name_space) != 0)
+           print_master_line(mode, argv);
+    if (service_filter != 0)
        argv_free(service_filter);
-       vstring_free(service_name);
-    }
 }
 
 /* show_sasl - show SASL plug-in types */
@@ -1801,79 +1847,67 @@ static void show_sasl(int what)
     argv_free(sasl_argv);
 }
 
-/* flag_unused_main_parameters - warn about unused parameters */
+/* flag_unused_parameters - warn about unused parameters */
 
-static void flag_unused_main_parameters(void)
+static void flag_unused_parameters(DICT *dict, const char *conf_name,
+                                          PC_MASTER_ENT *local_scope)
 {
-    const char *myname = "flag_unused_main_parameters";
-    DICT   *dict;
+    const char *myname = "flag_unused_parameters";
     const char *param_name;
     const char *param_value;
     int     how;
 
     /*
-     * 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.
+     * 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 = dict_handle(CONFIG_DICT)) == 0)
-       msg_panic("%s: parameter dictionary %s not found",
-                 myname, CONFIG_DICT);
     if (dict->sequence == 0)
        msg_panic("%s: parameter dictionary %s has no iterator",
-                 myname, CONFIG_DICT);
+                 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) {
+       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/" MAIN_CONF_FILE ": unused parameter: %s=%s",
-                    var_config_dir, param_name, param_value);
+           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 */
+
+static void flag_unused_main_parameters(void)
+{
+    const char *myname = "flag_unused_main_parameters";
+    DICT   *dict;
+
+    /*
+     * Iterate over all main.cf entries, and flag parameter names that aren't
+     * used anywhere.
+     */
+    if ((dict = dict_handle(CONFIG_DICT)) == 0)
+       msg_panic("%s: parameter dictionary %s not found",
+                 myname, CONFIG_DICT);
+    flag_unused_parameters(dict, MAIN_CONF_FILE, (PC_MASTER_ENT *) 0);
+}
+
 /* flag_unused_master_parameters - warn about unused parameters */
 
 static void flag_unused_master_parameters(void)
 {
-    ARGV  **argvp;
-    ARGV   *argv;
-    int     field;
-    char   *arg;
-    char   *saved_arg;
-    char   *param_name;
-    char   *param_value;
+    PC_MASTER_ENT *masterp;
+    DICT   *dict;
 
     /*
      * Iterate over all master.cf entries, and flag parameter names that
-     * aren't used anywhere. Show the warning message at the end of the
-     * 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.
+     * aren't used anywhere.
      */
-    for (argvp = master_table; (argv = *argvp) != 0; argvp++) {
-       for (field = MASTER_FIELD_COUNT; argv->argv[field] != 0; field++) {
-           arg = argv->argv[field];
-           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;
-           }
-       }
-    }
+    for (masterp = master_table; masterp->argv != 0; masterp++)
+       if ((dict = masterp->all_params) != 0)
+           flag_unused_parameters(dict, MASTER_CONF_FILE, masterp);
 }
 
 MAIL_VERSION_STAMP_DECLARE;
diff --git a/postfix/src/postconf/test12.ref b/postfix/src/postconf/test12.ref
new file mode 100644 (file)
index 0000000..a9f5eb4
--- /dev/null
@@ -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
diff --git a/postfix/src/postconf/test13.ref b/postfix/src/postconf/test13.ref
new file mode 100644 (file)
index 0000000..09787fa
--- /dev/null
@@ -0,0 +1,3 @@
+bar = yes
+config_directory = .
+./postconf: warning: ./main.cf: unused parameter: baz=xx
diff --git a/postfix/src/postconf/test14.ref b/postfix/src/postconf/test14.ref
new file mode 100644 (file)
index 0000000..98884f3
--- /dev/null
@@ -0,0 +1,3 @@
+config_directory = .
+smtpd_restriction_classes = bar
+./postconf: warning: ./master.cf: unused parameter: baz=xx
diff --git a/postfix/src/postconf/test15.ref b/postfix/src/postconf/test15.ref
new file mode 100644 (file)
index 0000000..2a15ca8
--- /dev/null
@@ -0,0 +1,3 @@
+baz = yy
+config_directory = .
+./postconf: warning: ./main.cf: unused parameter: bar=xx
index 3c853fff16ba1b93e78d0e367b53e651df7708b7..41bee93ae91ac650877535b987624d69d3ac5481 100644 (file)
@@ -1,2 +1 @@
 config_directory = .
-./postconf: warning: ./master.cf: unused parameter: bar=yes