]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-3.1-20150523
authorWietse Venema <wietse@porcupine.org>
Sat, 23 May 2015 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <postfix-users@dukhovni.org>
Tue, 9 Jun 2015 04:31:53 +0000 (00:31 -0400)
34 files changed:
postfix/HISTORY
postfix/README_FILES/MILTER_README
postfix/WISHLIST
postfix/html/MILTER_README.html
postfix/html/cleanup.8.html
postfix/html/postconf.5.html
postfix/html/smtpd.8.html
postfix/makedefs
postfix/man/man5/postconf.5
postfix/man/man8/cleanup.8
postfix/man/man8/smtpd.8
postfix/mantools/postlink
postfix/proto/MILTER_README.html
postfix/proto/postconf.proto
postfix/src/cleanup/cleanup.c
postfix/src/cleanup/cleanup_init.c
postfix/src/cleanup/cleanup_milter.c
postfix/src/global/mail_params.h
postfix/src/global/mail_version.h
postfix/src/milter/milter.c
postfix/src/milter/milter.h
postfix/src/smtpd/smtpd.c
postfix/src/smtpd/smtpd_milter.c
postfix/src/util/attr.h
postfix/src/util/attr_print0.c
postfix/src/util/attr_print64.c
postfix/src/util/attr_print_plain.c
postfix/src/util/attr_scan0.c
postfix/src/util/attr_scan0.ref
postfix/src/util/attr_scan64.c
postfix/src/util/attr_scan64.ref
postfix/src/util/attr_scan_plain.c
postfix/src/util/attr_scan_plain.ref
postfix/src/util/sys_defs.h

index 8271d81c88a748a0cb32ae2efec8efcdce08120f..8ac693bcd76a4c804e0d435af0695fe9ecce7095 100644 (file)
@@ -21727,3 +21727,33 @@ Apologies for any names omitted.
        Bugfix (introduced: 19970309): reset errno before calling
        readdir(), in order to distinguish between end-of-directory and
        an error condition. File: scandir,c,
+
+20150426
+
+       Cleanup: when transmitting an attribute-value sequence
+       between Postfix processes, a hash table may now appear at
+       any position instead of only at the end.  Files:
+       util/attr_scan{0,64,plain}.c, util/attr_print{0,64,plain}.c,
+       util/attr_scan{0,64,plain}.ref.
+
+       Feature: milter_macro_defaults, an optional list of macro
+       name=value pairs that specify default values for Milter
+       macros.  When a macro is to be sent to a Milter application,
+       Postfix will send its default value when no value is available
+       from the mail delivery context. For example, with
+       "milter_macro_defaults = auth_type=TLS", Postfix will send
+       an auth_type of "TLS" unless a remote client authenticates
+       with SASL. Files: mantools/postlink, proto/MILTER_README.html,
+       proto/postconf.proto, cleanup/cleanup.c, cleanup/cleanup_init.c,
+       cleanup/cleanup_milter.c, global/mail_params.h, milter/milter.c,
+       milter/milter.h, smtpd/smtpd.c, smtpd/smtpd_milter.c.
+
+20150501
+
+       Support for Linux 4.*, and some simplification for future
+       makedefs files. Files: makedefs, util/sys_defs.h.
+
+20150502
+
+       Cleanup: updated the examples in MILTER_README.  File:
+       proto/MILTER_README.html
index e816dba89c15a180d2b9abd3953d2490a98983f8..730aa5b00501b16d2cab1268e4f94e3daa4387ba 100644 (file)
@@ -12,11 +12,9 @@ is queued.
 
 The reason for adding Milter support to Postfix is that there exists a large
 collection of applications, not only to block unwanted mail, but also to verify
-authenticity (examples: OpenDKIM, DomainKeys Identified Mail (DKIM),
-SenderID+SPF and DomainKeys) or to digitally sign mail (examples: OpenDKIM,
-DomainKeys Identified Mail (DKIM), DomainKeys). Having yet another Postfix-
-specific version of all that software is a poor use of human and system
-resources.
+authenticity (examples: OpenDKIM and DMARC) or to digitally sign mail (example:
+OpenDKIM). Having yet another Postfix-specific version of all that software is
+a poor use of human and system resources.
 
 The Milter protocol has evolved over time, and different Postfix versions
 implement different feature sets. See the workarounds and limitations sections
@@ -89,51 +87,26 @@ deals with C applications only. For these, you need an object library that
 implements the Sendmail 8 Milter protocol. Postfix currently does not provide
 such a library, but Sendmail does.
 
-  * The first option is to use a pre-compiled library. Some systems install the
-    Sendmail libmilter library by default. With other systems, libmilter may be
-    provided by a package (called "sendmail-devel" on some Linux systems).
+Some systems install the Sendmail libmilter library by default. With other
+systems, libmilter may be provided by a package (called "sendmail-devel" on
+some Linux systems).
 
-    Once libmilter is installed, applications such as OpenDKIM, dkim-milter and
-    sid-milter build out of the box without requiring any tinkering:
+Once libmilter is installed, applications such as OpenDKIM and OpenDMARC build
+out of the box without requiring any tinkering:
 
-        $ g\bgz\bzc\bca\bat\bt o\bop\bpe\ben\bnd\bdk\bki\bim\bm-\b-x\bx.\b.y\by.\b.z\bz.\b.t\bta\bar\br.\b.g\bgz\bz |\b| t\bta\bar\br x\bxf\bf -\b-
-        $ c\bcd\bd o\bop\bpe\ben\bnd\bdk\bki\bim\bm-\b-x\bx.\b.y\by.\b.z\bz
-        $ .\b./\b/c\bco\bon\bnf\bfi\big\bgu\bur\bre\be .\b..\b..\b.o\bop\bpt\bti\bio\bon\bns\bs.\b..\b..\b.
-        $ m\bma\bak\bke\be
-        [...lots of output omitted...]
-        $ m\bma\bak\bke\be i\bin\bns\bst\bta\bal\bll\bl
-
-        $ g\bgz\bzc\bca\bat\bt d\bdk\bki\bim\bm-\b-m\bmi\bil\blt\bte\ber\br-\b-x\bx.\b.y\by.\b.z\bz.\b.t\bta\bar\br.\b.g\bgz\bz |\b| t\bta\bar\br x\bxf\bf -\b-
-        $ c\bcd\bd d\bdk\bki\bim\bm-\b-m\bmi\bil\blt\bte\ber\br-\b-x\bx.\b.y\by.\b.z\bz
-        $ m\bma\bak\bke\be
-        [...lots of output omitted...]
-
-  * The other option is to build the libmilter library from Sendmail source
-    code:
-
-        $ g\bgz\bzc\bca\bat\bt s\bse\ben\bnd\bdm\bma\bai\bil\bl-\b-x\bx.\b.y\by.\b.z\bz.\b.t\bta\bar\br.\b.g\bgz\bz |\b| t\bta\bar\br x\bxf\bf -\b-
-        $ c\bcd\bd s\bse\ben\bnd\bdm\bma\bai\bil\bl-\b-x\bx.\b.y\by.\b.z\bz/\b/l\bli\bib\bbm\bmi\bil\blt\bte\ber\br
-        $ m\bma\bak\bke\be
-        [...lots of output omitted...]
-
-    After building your own libmilter library, follow the installation
-    instructions in the Milter application source distribution to specify the
-    location of the libmilter include files and object library. Typically,
-    these settings are configured in a file named sid-filter/Makefile.m4 or
-    similar:
-
-        APPENDDEF(`confINCDIRS', `-I/some/where/sendmail-x.y.z/include')
-        APPENDDEF(`confLIBDIRS', `-L/some/where/sendmail-x.y.z/obj.systemtype/
-        libmilter')
-
-    Then build the Milter application.
+    $ g\bgz\bzc\bca\bat\bt o\bop\bpe\ben\bnd\bdk\bki\bim\bm-\b-x\bx.\b.y\by.\b.z\bz.\b.t\bta\bar\br.\b.g\bgz\bz |\b| t\bta\bar\br x\bxf\bf -\b-
+    $ c\bcd\bd o\bop\bpe\ben\bnd\bdk\bki\bim\bm-\b-x\bx.\b.y\by.\b.z\bz
+    $ .\b./\b/c\bco\bon\bnf\bfi\big\bgu\bur\bre\be .\b..\b..\b.o\bop\bpt\bti\bio\bon\bns\bs.\b..\b..\b.
+    $ m\bma\bak\bke\be
+    [...lots of output omitted...]
+    $ m\bma\bak\bke\be i\bin\bns\bst\bta\bal\bll\bl
 
 R\bRu\bun\bnn\bni\bin\bng\bg M\bMi\bil\blt\bte\ber\br a\bap\bpp\bpl\bli\bic\bca\bat\bti\bio\bon\bns\bs
 
 To run a Milter application, see the documentation of the filter for options. A
 typical command looks like this:
 
-    # /\b/s\bso\bom\bme\be/\b/w\bwh\bhe\ber\bre\be/\b/d\bdk\bki\bim\bm-\b-f\bfi\bil\blt\bte\ber\br -\b-u\bu u\bus\bse\ber\bri\bid\bd -\b-p\bp i\bin\bne\bet\bt:\b:p\bpo\bor\brt\btn\bnu\bum\bmb\bbe\ber\br@\b@l\blo\boc\bca\bal\blh\bho\bos\bst\bt .\b..\b..\b.o\bot\bth\bhe\ber\br
+    # /\b/s\bso\bom\bme\be/\b/w\bwh\bhe\ber\bre\be/\b/o\bop\bpe\ben\bnd\bdk\bki\bim\bm -\b-l\bl -\b-u\bu u\bus\bse\ber\bri\bid\bd -\b-p\bp i\bin\bne\bet\bt:\b:p\bpo\bor\brt\btn\bnu\bum\bmb\bbe\ber\br@\b@l\blo\boc\bca\bal\blh\bho\bos\bst\bt .\b..\b..\b.o\bot\bth\bhe\ber\br
     o\bop\bpt\bti\bio\bon\bns\bs.\b..\b..\b.
 
 Please specify a userid value that isn't used for other applications (not
@@ -155,6 +128,7 @@ Information in this section:
   * Milter protocol timeouts
   * Different settings for different Milter applications
   * Sendmail macro emulation
+  * What macros will Postfix send to Milters?
 
 S\bSM\bMT\bTP\bP-\b-O\bOn\bnl\bly\by M\bMi\bil\blt\bte\ber\br a\bap\bpp\bpl\bli\bic\bca\bat\bti\bio\bon\bns\bs
 
@@ -164,10 +138,11 @@ mail from authorized SMTP clients. Mail that arrives via the Postfix smtpd(8)
 server is not filtered by the non-SMTP filters that are described in the next
 section.
 
-NOTE: Do not use the header_checks(5) IGNORE action to remove Postfix's own
-Received: message header. This causes problems with mail signing filters.
-Instead, keep Postfix's own Received: message header and use the header_checks
-(5) REPLACE action to sanitize information.
+    NOTE for Postfix versions that have a mail_release_date before 20141018: do
+    not use the header_checks(5) IGNORE action to remove Postfix's own
+    Received: message header. This causes problems with mail signing filters.
+    Instead, keep Postfix's own Received: message header and use the
+    header_checks(5) REPLACE action to sanitize information.
 
 You specify SMTP-only Milter applications (there can be more than one) with the
 smtpd_milters parameter. Each Milter application is identified by the name of
@@ -365,7 +340,9 @@ Instead of a server endpoint, we now have a list enclosed in {}.
 
   * Line 3: The remainder of the list contains per-Milter settings. These
     settings override global main.cf parameters, and have the same name as
-    those parameters, without the "milter_" prefix.
+    those parameters, without the "milter_" prefix. The per-Milter settings
+    that are supported as of Postfix 3.0 are command_timeout, connect_timeout,
+    content_timeout, default_action, and protocol.
 
 Inside the list, syntax is similar to what we already know from main.cf: items
 separated by space or comma. There is one difference: y\byo\bou\bu m\bmu\bus\bst\bt e\ben\bnc\bcl\blo\bos\bse\be a\ba
@@ -462,10 +439,12 @@ Sendmail. See the workarounds section below for solutions.
     |v                   |Always                   |value of milter_macro_v   |
     |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
 
+W\bWh\bha\bat\bt m\bma\bac\bcr\bro\bos\bs w\bwi\bil\bll\bl P\bPo\bos\bst\btf\bfi\bix\bx s\bse\ben\bnd\bd t\bto\bo M\bMi\bil\blt\bte\ber\brs\bs?\b?
+
 Postfix sends specific sets of macros at different Milter protocol stages. The
-sets are configured with the parameters as described in the table (EOH = end of
-headers; EOM = end of message). The protocol version is a number that Postfix
-sends at the beginning of the Milter protocol handshake.
+sets are configured with the parameters as shown in the table below (EOH = end
+of headers; EOM = end of message). The protocol version is a number that
+Postfix sends at the beginning of the Milter protocol handshake.
 
 As of Sendmail 8.14.0, Milter applications can specify what macros they want to
 receive at different Milter protocol stages. An application-specified list
@@ -492,6 +471,16 @@ takes precedence over a Postfix-specified list.
     |milter_unknown_command_macros|3 or higher    |unknown command      |
     |_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b|_\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b _\b |
 
+By default, Postfix will send only macros whose values have been updated with
+information from main.cf or master.cf, from an SMTP session (for example; SASL
+login, or TLS certificates) or from a Mail delivery transaction (for example;
+queue ID, sender, or recipient).
+
+To force a macro to be sent even when its value has not been updated, you may
+specify macro default values with the milter_macro_defaults parameter. Specify
+zero or more name=value pairs separated by comma or whitespace; you may even
+specify macro names that Postfix does know about!
+
 W\bWo\bor\brk\bka\bar\bro\bou\bun\bnd\bds\bs
 
   * To avoid breaking DKIM etc. signatures with an SMTP-based content filter,
index e347e2d3d2f59e02d1935f0f4897f6cc6c7a4311..aa4d8524383ba1c1ad5169bf64ff688587e5fb4b 100644 (file)
@@ -10,10 +10,22 @@ Wish list:
 
        Things to do after the stable release:
 
+       TLS certificate provenance: indicate whether a subject
+       name/issuer are verified or not (for example, change the
+       attribute name to unverified_ccert_subject etc.).  This is
+       relevant only for fingerprint-based authentication including
+       DANE, and affects logging, SMTPD policy, and Milters.
+
+       Exploit GCC 3.4+ __attribute__((warn_unused_result)) to
+       warn about unused function result values.
+
        Generalize the daemon '-S' stand-alone mode, so that it can
        be used with custom configuration files for request/reply
        regression testing.
 
+       Update the list of Sendmail macros that Postfix can send
+       to Milters (auth_ssf and TLS-related).
+
        replace str*casecmp() calls with _utf8() equivalents
        for trivial-rewrite lookups.
 
index b6b6f64782578b300e9873383970a9de1ef2e8bb..7494e592b62c3972d23841c14ba552466544f5fb 100644 (file)
@@ -28,16 +28,10 @@ SMTP commands (HELO, MAIL FROM, etc.) as well as mail content
 <p> The reason for adding Milter support to Postfix is that there
 exists a large collection of applications, not only to block unwanted
 mail, but also to verify authenticity (examples: <a
-href="http://www.opendkim.org/">OpenDKIM</a>, <a
-href="http://sourceforge.net/projects/dkim-milter/">DomainKeys
-Identified Mail (DKIM)</a>, <a
-href="http://sourceforge.net/projects/sid-milter/">SenderID+SPF</a> and
-<a href="http://sourceforge.net/projects/dk-milter/">DomainKeys</a>)
-or to digitally sign mail (examples: <a
-href="http://www.opendkim.org/">OpenDKIM</a>, <a
-href="http://sourceforge.net/projects/dkim-milter/">DomainKeys
-Identified Mail (DKIM)</a>, <a
-href="http://sourceforge.net/projects/dk-milter/">DomainKeys</a>).
+href="http://www.opendkim.org/">OpenDKIM</a> and <a
+href="http://www.trusteddomain.org/opendmarc/">DMARC </a>)
+or to digitally sign mail (example: <a
+href="http://www.opendkim.org/">OpenDKIM</a>).
 Having yet another Postfix-specific version of all that software
 is a poor use of human and system resources. </p>
 
@@ -206,17 +200,14 @@ an object library that implements the Sendmail 8 Milter protocol.
 Postfix currently does not provide such a library, but Sendmail
 does. </p>
 
-<ul>
-
-<li> <p> The first option is to use a pre-compiled library. Some
+<p> Some
 systems install the Sendmail libmilter library by default.  With
 other systems, libmilter may be provided by a package (called
 "sendmail-devel" on some Linux systems).  </p>
 
 <p> Once libmilter is installed, applications such as <a
-href="http://www.opendkim.org/">OpenDKIM</a>, <a
-href="http://sourceforge.net/projects/dkim-milter/">dkim-milter</a> and
-<a href="http://sourceforge.net/projects/sid-milter/">sid-milter</a>
+href="http://www.opendkim.org/">OpenDKIM</a> and
+<a href="http://www.trusteddomain.org/opendmarc/">OpenDMARC</a>
 build out of the box without requiring any tinkering:</p>
 
 <blockquote>
@@ -230,44 +221,6 @@ $ <b>make install</b>
 </pre>
 </blockquote>
 
-<blockquote>
-<pre>
-$ <b>gzcat dkim-milter-<i>x.y.z</i>.tar.gz | tar xf -</b>
-$ <b>cd dkim-milter-<i>x.y.z</i></b>
-$ <b>make</b>
-[...<i>lots of output omitted</i>...]
-</pre>
-</blockquote>
-
-<li> <p> The other option is to build the libmilter library from
-Sendmail source code: </p>
-
-<blockquote>
-<pre>
-$ <b>gzcat sendmail-<i>x.y.z</i>.tar.gz | tar xf -</b>
-$ <b>cd sendmail-<i>x.y.z</i>/libmilter</b>
-$ <b>make</b>
-[...<i>lots of output omitted</i>...]
-</pre>
-</blockquote>
-
-<p> After building your own libmilter library, follow the installation
-instructions in the Milter application source distribution to specify
-the location of the libmilter include files and object library.
-Typically, these settings are configured in a file named
-<tt>sid-filter/Makefile.m4</tt> or similar:
-
-<blockquote>
-<pre>
-APPENDDEF(`confINCDIRS', `-I/some/where/sendmail-x.y.z/include')
-APPENDDEF(`confLIBDIRS', `-L/some/where/sendmail-x.y.z/obj.<i>systemtype</i>/libmilter')
-</pre>
-</blockquote>
-
-<p>Then build the Milter application. </p>
-
-</ul>
-
 <h2><a name="running">Running Milter applications</a></h2>
 
 <p> To run a Milter application, see the documentation of the filter
@@ -275,7 +228,7 @@ for options.  A typical command looks like this:</p>
 
 <blockquote>
 <pre>
-# <b>/some/where/dkim-filter -u <i>userid</i> -p inet:<i>portnumber</i>@localhost ...<i>other options</i>...</b>
+# <b>/some/where/opendkim -l -u <i>userid</i> -p inet:<i>portnumber</i>@localhost ...<i>other options</i>...</b>
 </pre>
 </blockquote>
 
@@ -308,6 +261,8 @@ applications </a>
 
 <li><a href="#macros">Sendmail macro emulation</a>
 
+<li><a href="#send-macros">What macros will Postfix send to Milters?</a>
+
 </ul>
 
 <h3><a name="smtp-only-milters">SMTP-Only Milter applications</a></h3>
@@ -318,11 +273,12 @@ unwanted mail, and to sign mail from authorized SMTP clients.  Mail
 that arrives via the Postfix <a href="smtpd.8.html">smtpd(8)</a> server is not filtered by the
 non-SMTP filters that are described in the next section. </p>
 
-<p> NOTE: Do not use the <a href="header_checks.5.html">header_checks(5)</a> IGNORE action to remove
+<blockquote> NOTE for Postfix versions that have a <a href="postconf.5.html#mail_release_date">mail_release_date</a>
+before 20141018: do not use the <a href="header_checks.5.html">header_checks(5)</a> IGNORE action to remove
 Postfix's own Received: message header. This causes problems with
 mail signing filters. Instead, keep Postfix's own Received: message
 header and use the <a href="header_checks.5.html">header_checks(5)</a> REPLACE action to sanitize
-information. </p>
+information. </blockquote>
 
 <p> You specify SMTP-only Milter applications (there can be more
 than one) with the <a href="postconf.5.html#smtpd_milters">smtpd_milters</a> parameter.  Each Milter application
@@ -596,7 +552,9 @@ earlier. </p>
 <li> <p> Line 3: The remainder of the list contains per-Milter
 settings. These settings override global <a href="postconf.5.html">main.cf</a> parameters, and
 have the same name as those parameters, without the "milter_" prefix.
-</p>
+The per-Milter settings that are supported as of Postfix 3.0 are
+command_timeout, connect_timeout, content_timeout, default_action,
+and protocol.  </p>
 
 </ul>
 
@@ -706,9 +664,11 @@ With rejected recipient: "error" </td> </tr>
 
 </blockquote>
 
+<h3><a name="send-macros">What macros will Postfix send to Milters?</a></h3>
+
 <p> Postfix sends specific sets of macros at different Milter protocol
-stages.  The sets are configured with the parameters as described
-in the table (EOH = end of headers; EOM = end of message). The
+stages.  The sets are configured with the parameters as shown in the
+table below (EOH = end of headers; EOM = end of message). The
 protocol version is a number that Postfix sends at the beginning
 of the Milter protocol handshake. </p>
 
@@ -752,6 +712,17 @@ TO </td> </tr>
 
 </blockquote>
 
+<p> By default, Postfix will send only macros whose values have been
+updated with information from <a href="postconf.5.html">main.cf</a> or <a href="master.5.html">master.cf</a>, from an SMTP session
+(for example; SASL login, or TLS certificates) or from a Mail delivery
+transaction (for example; queue ID, sender, or recipient). </p>
+
+<p> To force a macro to be sent even when its value has not been updated,
+you may specify macro default values with the <a href="postconf.5.html#milter_macro_defaults">milter_macro_defaults</a>
+parameter. Specify zero or more <i>name=value</i> pairs separated by
+comma or whitespace; you may even specify macro names that Postfix does
+know about! </p>
+
 <h2><a name="workarounds">Workarounds</a></h2>
 
 <ul>
index 5f23b3cbe5a536db960a5ebd4617a52f96f2b75d..225f590f0d29cd9ad9b51da1200bdd96f61eb777 100644 (file)
@@ -224,6 +224,13 @@ CLEANUP(8)                                                          CLEANUP(8)
               Optional lookup tables for content inspection of message headers
               that are produced by Milter applications.
 
+       Available in Postfix version 3.1 and later:
+
+       <b><a href="postconf.5.html#milter_macro_defaults">milter_macro_defaults</a> (empty)</b>
+              Optional  list  of  <i>name=value</i> pairs that specify default values
+              for arbitrary macros that Postfix may send  to  Milter  applica-
+              tions.
+
 <b>MIME PROCESSING CONTROLS</b>
        Available in Postfix version 2.0 and later:
 
index 5c31ff7d2ff7b9f53109cd65309b446ad7066f74..c14c4ea3b70273186fbaa87f330f75992ba75226 100644 (file)
@@ -6574,6 +6574,24 @@ meanings.  </p>
 <p> This feature is available in Postfix 2.3 and later. </p>
 
 
+</DD>
+
+<DT><b><a name="milter_macro_defaults">milter_macro_defaults</a>
+(default: empty)</b></DT><DD>
+
+<p> Optional list of <i>name=value</i> pairs that specify default
+values for arbitrary macros that Postfix may send to Milter
+applications.  These defaults are used when there is no corresponding
+information from the message delivery context. </p>
+
+<p> Specify <i>name=value</i> or <i>{name}=value</i> pairs separated
+by comma or whitespace.  Enclose a pair in "{}" when a value contains
+comma or whitespace (this form ignores whitespace after the enclosing
+"{", around the "=", and before the enclosing "}"). </p>
+
+<p> This feature is available in Postfix 3.1 and later.  </p>
+
+
 </DD>
 
 <DT><b><a name="milter_macro_v">milter_macro_v</a>
index c4b69df50ab0272ac2954fec9d7fe2bacbfe14b7..138b2bfad4c339764045c7e4cdf792fd967c944a 100644 (file)
@@ -289,6 +289,13 @@ SMTPD(8)                                                              SMTPD(8)
               The  macros  that  are sent to Milter (mail filter) applications
               after the message end-of-data.
 
+       Available in Postfix version 3.1 and later:
+
+       <b><a href="postconf.5.html#milter_macro_defaults">milter_macro_defaults</a> (empty)</b>
+              Optional list of <i>name=value</i> pairs that  specify  default  values
+              for  arbitrary  macros  that Postfix may send to Milter applica-
+              tions.
+
 <b>GENERAL CONTENT INSPECTION CONTROLS</b>
        The following parameters are applicable for both built-in and  external
        content filters.
index 11698444e645a0ffbd43fdd4338a4da747aea026..052cf9b98b00723072ee25917bbfb0f6f3077bcd 100644 (file)
@@ -192,6 +192,8 @@ case $# in
  # Officially supported usage.
  0) SYSTEM=`(uname -s) 2>/dev/null`
     RELEASE=`(uname -r) 2>/dev/null`
+    # No ${x%%y} support in Solaris 11 /bin/sh
+    RELEASE_MAJOR=`expr "$RELEASE" : '\([0-9]*\)'` || exit 1
     VERSION=`(uname -v) 2>/dev/null`
     case "$VERSION" in
      dcosx*) SYSTEM=$VERSION;;
@@ -500,7 +502,7 @@ EOF
                : ${SHLIB_ENV="LD_LIBRARY_PATH=`pwd`/lib"}
                : ${PLUGIN_LD="${CC-gcc} -shared"}
                ;;
-    Linux.3*)  SYSTYPE=LINUX3
+  Linux.[34].*)        SYSTYPE=LINUX$RELEASE_MAJOR
                case "$CCARGS" in
                 *-DNO_DB*) ;;
                 *-DHAS_DB*) ;;
index f58853c7617042100e626e6946b13f1973622b1a..4c303432a45caeacb1c16df3412e3667f2371a3c 100644 (file)
@@ -3959,6 +3959,18 @@ See MILTER_README for a list of available macro names and their
 meanings.
 .PP
 This feature is available in Postfix 2.3 and later.
+.SH milter_macro_defaults (default: empty)
+Optional list of \fIname=value\fR pairs that specify default
+values for arbitrary macros that Postfix may send to Milter
+applications.  These defaults are used when there is no corresponding
+information from the message delivery context.
+.PP
+Specify \fIname=value\fR or \fI{name}=value\fR pairs separated
+by comma or whitespace.  Enclose a pair in "{}" when a value contains
+comma or whitespace (this form ignores whitespace after the enclosing
+"{", around the "=", and before the enclosing "}").
+.PP
+This feature is available in Postfix 3.1 and later.
 .SH milter_macro_v (default: $mail_name $mail_version)
 The {v} macro value for Milter (mail filter) applications.
 See MILTER_README for a list of available macro names and their
index c4d520eb81045785007ba58fea29d012bf843a71..f59a0da123d6653562b4648c67bc72284fb8ca93 100644 (file)
@@ -209,6 +209,12 @@ Available in Postfix version 2.7 and later:
 .IP "\fBmilter_header_checks (empty)\fR"
 Optional lookup tables for content inspection of message headers
 that are produced by Milter applications.
+.PP
+Available in Postfix version 3.1 and later:
+.IP "\fBmilter_macro_defaults (empty)\fR"
+Optional list of \fIname=value\fR pairs that specify default
+values for arbitrary macros that Postfix may send to Milter
+applications.
 .SH "MIME PROCESSING CONTROLS"
 .na
 .nf
index 35c45d58a8b65663b6f7e9991cc60e2a0206ec62..6d9553df3e21ef4c0df877705b89ff0c1fd52f00 100644 (file)
@@ -277,6 +277,12 @@ after the end of the message header.
 .IP "\fBmilter_end_of_data_macros (see 'postconf -d' output)\fR"
 The macros that are sent to Milter (mail filter) applications
 after the message end\-of\-data.
+.PP
+Available in Postfix version 3.1 and later:
+.IP "\fBmilter_macro_defaults (empty)\fR"
+Optional list of \fIname=value\fR pairs that specify default
+values for arbitrary macros that Postfix may send to Milter
+applications.
 .SH "GENERAL CONTENT INSPECTION CONTROLS"
 .na
 .nf
index 049c6f9385c293865ed1cb89806e9e39ab07b1a6..fd55bb7a0bed3aa20bc915b682399acd8ddbbe20 100755 (executable)
@@ -970,6 +970,7 @@ while (<>) {
     s;\bmilter_end_of_data_macros\b;<a href="postconf.5.html#milter_end_of_data_macros">$&</a>;g;
     s;\bmilter_end_of_header_macros\b;<a href="postconf.5.html#milter_end_of_header_macros">$&</a>;g;
     s;\bmilter_header_checks\b;<a href="postconf.5.html#milter_header_checks">$&</a>;g;
+    s;\bmilter_macro_defaults\b;<a href="postconf.5.html#milter_macro_defaults">$&</a>;g;
 
     # Multi-instance support
     s;\bmulti_instance_directo[-</bB>]*\n*[ <bB>]*ries\b;<a href="postconf.5.html#multi_instance_directories">$&</a>;g;
index 72827c45715d235cc43bfbe8225c47ee8642d855..c7031d48ec8a1e84d3fd120304b0bbf3fbd5c9a8 100644 (file)
@@ -28,16 +28,10 @@ SMTP commands (HELO, MAIL FROM, etc.) as well as mail content
 <p> The reason for adding Milter support to Postfix is that there
 exists a large collection of applications, not only to block unwanted
 mail, but also to verify authenticity (examples: <a
-href="http://www.opendkim.org/">OpenDKIM</a>, <a
-href="http://sourceforge.net/projects/dkim-milter/">DomainKeys
-Identified Mail (DKIM)</a>, <a
-href="http://sourceforge.net/projects/sid-milter/">SenderID+SPF</a> and
-<a href="http://sourceforge.net/projects/dk-milter/">DomainKeys</a>)
-or to digitally sign mail (examples: <a
-href="http://www.opendkim.org/">OpenDKIM</a>, <a
-href="http://sourceforge.net/projects/dkim-milter/">DomainKeys
-Identified Mail (DKIM)</a>, <a
-href="http://sourceforge.net/projects/dk-milter/">DomainKeys</a>).
+href="http://www.opendkim.org/">OpenDKIM</a> and <a
+href="http://www.trusteddomain.org/opendmarc/">DMARC </a>)
+or to digitally sign mail (example: <a
+href="http://www.opendkim.org/">OpenDKIM</a>).
 Having yet another Postfix-specific version of all that software
 is a poor use of human and system resources. </p>
 
@@ -206,17 +200,14 @@ an object library that implements the Sendmail 8 Milter protocol.
 Postfix currently does not provide such a library, but Sendmail
 does. </p>
 
-<ul>
-
-<li> <p> The first option is to use a pre-compiled library. Some
+<p> Some
 systems install the Sendmail libmilter library by default.  With
 other systems, libmilter may be provided by a package (called
 "sendmail-devel" on some Linux systems).  </p>
 
 <p> Once libmilter is installed, applications such as <a
-href="http://www.opendkim.org/">OpenDKIM</a>, <a
-href="http://sourceforge.net/projects/dkim-milter/">dkim-milter</a> and
-<a href="http://sourceforge.net/projects/sid-milter/">sid-milter</a>
+href="http://www.opendkim.org/">OpenDKIM</a> and
+<a href="http://www.trusteddomain.org/opendmarc/">OpenDMARC</a>
 build out of the box without requiring any tinkering:</p>
 
 <blockquote>
@@ -230,44 +221,6 @@ $ <b>make install</b>
 </pre>
 </blockquote>
 
-<blockquote>
-<pre>
-$ <b>gzcat dkim-milter-<i>x.y.z</i>.tar.gz | tar xf -</b>
-$ <b>cd dkim-milter-<i>x.y.z</i></b>
-$ <b>make</b>
-[...<i>lots of output omitted</i>...]
-</pre>
-</blockquote>
-
-<li> <p> The other option is to build the libmilter library from
-Sendmail source code: </p>
-
-<blockquote>
-<pre>
-$ <b>gzcat sendmail-<i>x.y.z</i>.tar.gz | tar xf -</b>
-$ <b>cd sendmail-<i>x.y.z</i>/libmilter</b>
-$ <b>make</b>
-[...<i>lots of output omitted</i>...]
-</pre>
-</blockquote>
-
-<p> After building your own libmilter library, follow the installation
-instructions in the Milter application source distribution to specify
-the location of the libmilter include files and object library.
-Typically, these settings are configured in a file named
-<tt>sid-filter/Makefile.m4</tt> or similar:
-
-<blockquote>
-<pre>
-APPENDDEF(`confINCDIRS', `-I/some/where/sendmail-x.y.z/include')
-APPENDDEF(`confLIBDIRS', `-L/some/where/sendmail-x.y.z/obj.<i>systemtype</i>/libmilter')
-</pre>
-</blockquote>
-
-<p>Then build the Milter application. </p>
-
-</ul>
-
 <h2><a name="running">Running Milter applications</a></h2>
 
 <p> To run a Milter application, see the documentation of the filter
@@ -275,7 +228,7 @@ for options.  A typical command looks like this:</p>
 
 <blockquote>
 <pre>
-# <b>/some/where/dkim-filter -u <i>userid</i> -p inet:<i>portnumber</i>@localhost ...<i>other options</i>...</b>
+# <b>/some/where/opendkim -l -u <i>userid</i> -p inet:<i>portnumber</i>@localhost ...<i>other options</i>...</b>
 </pre>
 </blockquote>
 
@@ -308,6 +261,8 @@ applications </a>
 
 <li><a href="#macros">Sendmail macro emulation</a>
 
+<li><a href="#send-macros">What macros will Postfix send to Milters?</a>
+
 </ul>
 
 <h3><a name="smtp-only-milters">SMTP-Only Milter applications</a></h3>
@@ -318,11 +273,12 @@ unwanted mail, and to sign mail from authorized SMTP clients.  Mail
 that arrives via the Postfix smtpd(8) server is not filtered by the
 non-SMTP filters that are described in the next section. </p>
 
-<p> NOTE: Do not use the header_checks(5) IGNORE action to remove
+<blockquote> NOTE for Postfix versions that have a mail_release_date
+before 20141018: do not use the header_checks(5) IGNORE action to remove
 Postfix's own Received: message header. This causes problems with
 mail signing filters. Instead, keep Postfix's own Received: message
 header and use the header_checks(5) REPLACE action to sanitize
-information. </p>
+information. </blockquote>
 
 <p> You specify SMTP-only Milter applications (there can be more
 than one) with the smtpd_milters parameter.  Each Milter application
@@ -596,7 +552,9 @@ earlier. </p>
 <li> <p> Line 3: The remainder of the list contains per-Milter
 settings. These settings override global main.cf parameters, and
 have the same name as those parameters, without the "milter_" prefix.
-</p>
+The per-Milter settings that are supported as of Postfix 3.0 are
+command_timeout, connect_timeout, content_timeout, default_action,
+and protocol.  </p>
 
 </ul>
 
@@ -706,9 +664,11 @@ With rejected recipient: "error" </td> </tr>
 
 </blockquote>
 
+<h3><a name="send-macros">What macros will Postfix send to Milters?</a></h3>
+
 <p> Postfix sends specific sets of macros at different Milter protocol
-stages.  The sets are configured with the parameters as described
-in the table (EOH = end of headers; EOM = end of message). The
+stages.  The sets are configured with the parameters as shown in the
+table below (EOH = end of headers; EOM = end of message). The
 protocol version is a number that Postfix sends at the beginning
 of the Milter protocol handshake. </p>
 
@@ -752,6 +712,17 @@ TO </td> </tr>
 
 </blockquote>
 
+<p> By default, Postfix will send only macros whose values have been
+updated with information from main.cf or master.cf, from an SMTP session
+(for example; SASL login, or TLS certificates) or from a Mail delivery
+transaction (for example; queue ID, sender, or recipient). </p>
+
+<p> To force a macro to be sent even when its value has not been updated,
+you may specify macro default values with the milter_macro_defaults
+parameter. Specify zero or more <i>name=value</i> pairs separated by
+comma or whitespace; you may even specify macro names that Postfix does
+know about! </p>
+
 <h2><a name="workarounds">Workarounds</a></h2>
 
 <ul>
index edb85cf2d2dcdf6d382660de65589dd52b345618..d710b6d9a96c85cf04346a237de775a3f77f6529 100644 (file)
@@ -11678,6 +11678,20 @@ meanings.  </p>
 
 <p> This feature is available in Postfix 2.3 and later. </p>
 
+%PARAM milter_macro_defaults
+
+<p> Optional list of <i>name=value</i> pairs that specify default
+values for arbitrary macros that Postfix may send to Milter
+applications.  These defaults are used when there is no corresponding
+information from the message delivery context. </p>
+
+<p> Specify <i>name=value</i> or <i>{name}=value</i> pairs separated
+by comma or whitespace.  Enclose a pair in "{}" when a value contains
+comma or whitespace (this form ignores whitespace after the enclosing
+"{", around the "=", and before the enclosing "}"). </p>
+
+<p> This feature is available in Postfix 3.1 and later.  </p>
+
 %PARAM milter_macro_v $mail_name $mail_version
 
 <p> The {v} macro value for Milter (mail filter) applications.
index c48a41047b3546c29f4fad5a62142510dc75248d..e81dfab6ec5c8973ee129f3e7f32a0769749eca5 100644 (file)
 /* .IP "\fBmilter_header_checks (empty)\fR"
 /*     Optional lookup tables for content inspection of message headers
 /*     that are produced by Milter applications.
+/* .PP
+/*     Available in Postfix version 3.1 and later:
+/* .IP "\fBmilter_macro_defaults (empty)\fR"
+/*     Optional list of \fIname=value\fR pairs that specify default
+/*     values for arbitrary macros that Postfix may send to Milter
+/*     applications.
 /* MIME PROCESSING CONTROLS
 /* .ad
 /* .fi
index 37ec5b0f7a5adc4551c44649bb2ed8897613a84e..5bae3587b151156c244f2c4b3f1916081079713d 100644 (file)
@@ -162,6 +162,7 @@ char   *var_milt_eod_macros;                /* end-of-data macros */
 char   *var_milt_unk_macros;           /* unknown command macros */
 char   *var_cleanup_milters;           /* non-SMTP mail */
 char   *var_milt_head_checks;          /* post-Milter header checks */
+char   *var_milt_macro_deflts;         /* default macro settings */
 int     var_auto_8bit_enc_hdr;         /* auto-detect 8bit encoding header */
 int     var_always_add_hdrs;           /* always add missing headers */
 int     var_virt_addrlen_limit;                /* stop exponential growth */
@@ -231,6 +232,7 @@ const CONFIG_STR_TABLE cleanup_str_table[] = {
     VAR_MILT_UNK_MACROS, DEF_MILT_UNK_MACROS, &var_milt_unk_macros, 0, 0,
     VAR_CLEANUP_MILTERS, DEF_CLEANUP_MILTERS, &var_cleanup_milters, 0, 0,
     VAR_MILT_HEAD_CHECKS, DEF_MILT_HEAD_CHECKS, &var_milt_head_checks, 0, 0,
+    VAR_MILT_MACRO_DEFLTS, DEF_MILT_MACRO_DEFLTS, &var_milt_macro_deflts, 0, 0,
     0,
 };
 
@@ -410,7 +412,8 @@ void    cleanup_pre_jail(char *unused_name, char **unused_argv)
                                        var_milt_data_macros,
                                        var_milt_eoh_macros,
                                        var_milt_eod_macros,
-                                       var_milt_unk_macros);
+                                       var_milt_unk_macros,
+                                       var_milt_macro_deflts);
 
     flush_init();
 }
index cc60f3595370d4d4f26469a83f4b14b516f8537c..fb371222e8a4ce9ff3009dcc1ba06f003c434624 100644 (file)
@@ -1801,14 +1801,6 @@ static const char *cleanup_milter_eval(const char *name, void *ptr)
      * that we forward all Sendmail macros via XFORWARD.
      */
 
-    /*
-     * Canonicalize the name.
-     */
-    if (*name != '{') {                                /* } */
-       vstring_sprintf(state->temp1, "{%s}", name);
-       name = STR(state->temp1);
-    }
-
     /*
      * System macros.
      */
index 54a70e25ffaf1185a44956c6af1d2957e45568c1..823fc0c85d572473ce245cf67a9a7b703ffba011 100644 (file)
@@ -3300,6 +3300,10 @@ extern char *var_milt_v;
 #define DEF_MILT_HEAD_CHECKS           ""
 extern char *var_milt_head_checks;
 
+#define VAR_MILT_MACRO_DEFLTS          "milter_macro_defaults"
+#define DEF_MILT_MACRO_DEFLTS          ""
+extern char *var_milt_macro_deflts;
+
  /*
   * What internal mail do we inspect/stamp/etc.? This is not yet safe enough
   * to enable world-wide.
index 0ed0e08c5f49e65eb9c96e0385dbed68d36af005..b663dfcdae437d7d3b2dfa7ad98c74eaee9731da 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      "20150421"
+#define MAIL_RELEASE_DATE      "20150523"
 #define MAIL_VERSION_NUMBER    "3.1"
 
 #ifdef SNAPSHOT
index c889d98b84c06015a6b39cd1cf2b28fa32280321..969feef3579217552709636ad27fead40a4a17bf 100644 (file)
@@ -11,7 +11,8 @@
 /*                                     conn_macros, helo_macros,
 /*                                     mail_macros, rcpt_macros,
 /*                                     data_macros, eoh_macros,
-/*                                     eod_macros, unk_macros)
+/*                                     eod_macros, unk_macros,
+/*                                     macro_deflts)
 /*     const char *milter_names;
 /*     int     conn_timeout;
 /*     int     cmd_timeout;
@@ -26,6 +27,7 @@
 /*     const char *eoh_macros;
 /*     const char *eod_macros;
 /*     const char *unk_macros;
+/*     const char *macro_deflts;
 /*
 /*     void    milter_free(milters)
 /*     MILTERS *milters;
 /*     milter_create() instantiates the milter clients specified
 /*     with the milter_names argument.  The conn_macros etc.
 /*     arguments specify the names of macros that are sent to the
-/*     mail filter applications upon a connect etc. event. This
+/*     mail filter applications upon a connect etc. event, and the
+/*     macro_deflts argument specifies macro defaults that will be used
+/*     only if the application's lookup call-back returns null. This
 /*     function should be called during process initialization,
 /*     before entering a chroot jail. The timeout parameters specify
 /*     time limits for the completion of the specified request
 #include <stringops.h>
 #include <argv.h>
 #include <attr.h>
+#include <htable.h>
 
 /* Global library. */
 
   */
 #define STR(x) vstring_str(x)
 
+/* milter_macro_defaults_create - parse default macro entries */
+
+HTABLE *milter_macro_defaults_create(const char *macro_defaults)
+{
+    const char myname[] = "milter_macro_defaults_create";
+    char   *saved_defaults = mystrdup(macro_defaults);
+    char   *cp = saved_defaults;
+    HTABLE *table = 0;
+    VSTRING *canon_buf = 0;
+    char   *nameval;
+
+    while ((nameval = mystrtokq(&cp, CHARS_COMMA_SP, CHARS_BRACE)) != 0) {
+       const char *err;
+       char   *name;
+       char   *value;
+
+       /*
+        * Split the input into (name, value) pairs. Allow the forms
+        * name=value and  { name = value }, where the last form ignores
+        * whitespace after the opening "{", around the "=", and before the
+        * closing "}". A name may also be specified as {name}.
+        * 
+        * Use the form {name} for table lookups, because that is the form of
+        * the S8_MAC_* macro names.
+        */
+       if (*nameval == CHARS_BRACE[0]
+           && nameval[balpar(nameval, CHARS_BRACE)] != '='
+           && (err = extpar(&nameval, CHARS_BRACE, EXTPAR_FLAG_NONE)) != 0)
+           msg_fatal("malformed default macro entry: %s in \"%s\"",
+                     err, macro_defaults);
+       if ((err = split_nameval(nameval, &name, &value)) != 0)
+           msg_fatal("malformed default macro entry: %s in \"%s\"",
+                     err, macro_defaults);
+       if (*name != '{')                       /* } */
+           name = STR(vstring_sprintf(canon_buf ? canon_buf :
+                           (canon_buf = vstring_alloc(20)), "{%s}", name));
+       if (table == 0)
+           table = htable_create(1);
+       if (htable_find(table, name) != 0) {
+           msg_warn("ignoring multiple default macro entries for %s in \"%s\"",
+                    name, macro_defaults);
+       } else {
+           (void) htable_enter(table, name, mystrdup(value));
+           if (msg_verbose)
+               msg_info("%s: add name=%s default=%s", myname, name, value);
+       }
+    }
+    myfree(saved_defaults);
+    if (canon_buf)
+       vstring_free(canon_buf);
+    return (table);
+}
+
 /* milter_macro_lookup - look up macros */
 
 static ARGV *milter_macro_lookup(MILTERS *milters, const char *macro_names)
@@ -267,19 +325,28 @@ static ARGV *milter_macro_lookup(MILTERS *milters, const char *macro_names)
     char   *saved_names = mystrdup(macro_names);
     char   *cp = saved_names;
     ARGV   *argv = argv_alloc(10);
+    VSTRING *canon_buf = vstring_alloc(20);
     const char *value;
     const char *name;
 
     while ((name = mystrtok(&cp, CHARS_COMMA_SP)) != 0) {
        if (msg_verbose)
            msg_info("%s: \"%s\"", myname, name);
+       if (*name != '{')                       /* } */
+           name = STR(vstring_sprintf(canon_buf, "{%s}", name));
        if ((value = milters->mac_lookup(name, milters->mac_context)) != 0) {
            if (msg_verbose)
                msg_info("%s: result \"%s\"", myname, value);
            argv_add(argv, name, value, (char *) 0);
+       } else if (milters->macro_defaults != 0
+            && (value = htable_find(milters->macro_defaults, name)) != 0) {
+           if (msg_verbose)
+               msg_info("%s: using default \"%s\"", myname, value);
+           argv_add(argv, name, value, (char *) 0);
        }
     }
     myfree(saved_names);
+    vstring_free(canon_buf);
     return (argv);
 }
 
@@ -572,7 +639,8 @@ MILTERS *milter_new(const char *names,
                            int msg_timeout,
                            const char *protocol,
                            const char *def_action,
-                           MILTER_MACROS *macros)
+                           MILTER_MACROS *macros,
+                           HTABLE *macro_defaults)
 {
     MILTERS *milters;
     MILTER *head = 0;
@@ -642,6 +710,7 @@ MILTERS *milter_new(const char *names,
     milters->mac_lookup = 0;
     milters->mac_context = 0;
     milters->macros = macros;
+    milters->macro_defaults = macro_defaults;
     milters->add_header = 0;
     milters->upd_header = milters->ins_header = 0;
     milters->del_header = 0;
@@ -664,6 +733,8 @@ void    milter_free(MILTERS *milters)
        next = m->next, m->free(m);
     if (milters->macros)
        milter_macros_free(milters->macros);
+    if (milters->macro_defaults)
+       htable_free(milters->macro_defaults, myfree);
     myfree((void *) milters);
 }
 
@@ -720,6 +791,18 @@ int     milter_send(MILTERS *milters, VSTREAM *stream)
                                     (void *) milters->macros),
                      ATTR_TYPE_END);
 
+    /*
+     * Send the filter macro defaults.
+     */
+    count = milters->macro_defaults ? milters->macro_defaults->used : 0;
+    (void) attr_print(stream, ATTR_FLAG_MORE,
+                     SEND_ATTR_INT(MAIL_ATTR_SIZE, count),
+                     ATTR_TYPE_END);
+    if (count > 0)
+       (void) attr_print(stream, ATTR_FLAG_MORE,
+                         SEND_ATTR_HASH(milters->macro_defaults),
+                         ATTR_TYPE_END);
+
     /*
      * Send the filter instances.
      */
@@ -749,6 +832,7 @@ MILTERS *milter_receive(VSTREAM *stream, int count)
     MILTER *head = 0;
     MILTER *tail = 0;
     MILTER *milter = 0;
+    int     macro_default_count;
 
     if (msg_verbose)
        msg_info("receive %d milters", count);
@@ -763,9 +847,10 @@ MILTERS *milter_receive(VSTREAM *stream, int count)
 #define NO_PROTOCOL    ((char *) 0)
 #define NO_ACTION      ((char *) 0)
 #define NO_MACROS      ((MILTER_MACROS *) 0)
+#define NO_MACRO_DEFLTS        ((HTABLE *) 0)
 
     milters = milter_new(NO_MILTERS, NO_TIMEOUTS, NO_PROTOCOL, NO_ACTION,
-                        NO_MACROS);
+                        NO_MACROS, NO_MACRO_DEFLTS);
 
     /*
      * XXX Optimization: don't send or receive further information when there
@@ -786,6 +871,21 @@ MILTERS *milter_receive(VSTREAM *stream, int count)
        return (0);
     }
 
+    /*
+     * Receive the filter macro defaults.
+     */
+    if (attr_scan(stream, ATTR_FLAG_STRICT | ATTR_FLAG_MORE,
+                 RECV_ATTR_INT(MAIL_ATTR_SIZE, &macro_default_count),
+                 ATTR_TYPE_END) != 1
+       || (macro_default_count > 0
+           && attr_scan(stream, ATTR_FLAG_STRICT | ATTR_FLAG_MORE,
+                        RECV_ATTR_HASH(milters->macro_defaults
+                                       = htable_create(1)),
+                        ATTR_TYPE_END) != macro_default_count)) {
+       milter_free(milters);
+       return (0);
+    }
+
     /*
      * Receive the filters.
      */
@@ -872,6 +972,7 @@ int     main(int argc, char **argv)
     MILTERS *milters = 0;
     char   *conn_macros, *helo_macros, *mail_macros, *rcpt_macros;
     char   *data_macros, *eoh_macros, *eod_macros, *unk_macros;
+    char   *macro_deflts;
     VSTRING *inbuf = vstring_alloc(100);
     char   *bufp;
     char   *cmd;
@@ -879,7 +980,7 @@ int     main(int argc, char **argv)
     int     istty = isatty(vstream_fileno(VSTREAM_IN));
 
     conn_macros = helo_macros = mail_macros = rcpt_macros = data_macros
-       = eoh_macros = eod_macros = unk_macros = "";
+       = eoh_macros = eod_macros = unk_macros = macro_deflts = "";
 
     msg_vstream_init(argv[0], VSTREAM_ERR);
     while ((ch = GETOPT(argc, argv, "V:v")) > 0) {
@@ -934,7 +1035,7 @@ int     main(int argc, char **argv)
                                    var_milt_protocol, var_milt_def_action,
                                    conn_macros, helo_macros, mail_macros,
                                    rcpt_macros, data_macros, eoh_macros,
-                                   eod_macros, unk_macros);
+                                   eod_macros, unk_macros, macro_deflts);
        } else if (strcmp(cmd, "free") == 0 && argv->argc == 0) {
            if (milters == 0) {
                msg_warn("no milters");
index bf25fccc040ef9b08832f9be6c98a5c02e1926cd..9ef5d35cbc835d9d8287644de8902eb1817ab3cc 100644 (file)
@@ -84,6 +84,11 @@ extern int milter_macros_scan(ATTR_SCAN_MASTER_FN, VSTREAM *, int, void *);
 #define MILTER_MACROS_ALLOC_ZERO       1       /* null pointer */
 #define MILTER_MACROS_ALLOC_EMPTY      2       /* mystrdup(""); */
 
+ /*
+  * Helper to parse list of name=value default macro settings.
+  */
+extern struct HTABLE *milter_macro_defaults_create(const char *);
+
  /*
   * A bunch of Milters.
   */
@@ -101,6 +106,7 @@ typedef struct MILTERS {
     MILTER_MAC_LOOKUP_FN mac_lookup;
     void   *mac_context;               /* macro lookup context */
     struct MILTER_MACROS *macros;
+    struct HTABLE *macro_defaults;
     void   *chg_context;               /* context for queue file changes */
     MILTER_ADD_HEADER_FN add_header;
     MILTER_EDIT_HEADER_FN upd_header;
@@ -116,14 +122,16 @@ typedef struct MILTERS {
 #define milter_create(milter_names, conn_timeout, cmd_timeout, msg_timeout, \
                        protocol, def_action, conn_macros, helo_macros, \
                        mail_macros, rcpt_macros, data_macros, eoh_macros, \
-                       eod_macros, unk_macros) \
+                       eod_macros, unk_macros, macro_deflts) \
        milter_new(milter_names, conn_timeout, cmd_timeout, msg_timeout, \
                    protocol, def_action, milter_macros_create(conn_macros, \
                    helo_macros, mail_macros, rcpt_macros, data_macros, \
-                   eoh_macros, eod_macros, unk_macros))
+                   eoh_macros, eod_macros, unk_macros), \
+                   milter_macro_defaults_create(macro_deflts))
 
 extern MILTERS *milter_new(const char *, int, int, int, const char *,
-                                  const char *, MILTER_MACROS *);
+                                  const char *, MILTER_MACROS *,
+                                  struct HTABLE *);
 extern void milter_macro_callback(MILTERS *, MILTER_MAC_LOOKUP_FN, void *);
 extern void milter_edit_callback(MILTERS *milters, MILTER_ADD_HEADER_FN,
                               MILTER_EDIT_HEADER_FN, MILTER_EDIT_HEADER_FN,
index 4208795fb6c51e482491f59d26345cabbe227a02..a8d55cc5ab68de04997d1dd34b6c94952b36307a 100644 (file)
 /* .IP "\fBmilter_end_of_data_macros (see 'postconf -d' output)\fR"
 /*     The macros that are sent to Milter (mail filter) applications
 /*     after the message end-of-data.
+/* .PP
+/*     Available in Postfix version 3.1 and later:
+/* .IP "\fBmilter_macro_defaults (empty)\fR"
+/*     Optional list of \fIname=value\fR pairs that specify default
+/*     values for arbitrary macros that Postfix may send to Milter
+/*     applications.
 /* GENERAL CONTENT INSPECTION CONTROLS
 /* .ad
 /* .fi
@@ -1343,6 +1349,7 @@ char   *var_milt_data_macros;
 char   *var_milt_eoh_macros;
 char   *var_milt_eod_macros;
 char   *var_milt_unk_macros;
+char   *var_milt_macro_deflts;
 bool    var_smtpd_client_port_log;
 char   *var_stress;
 
@@ -5538,7 +5545,8 @@ static void post_jail_init(char *unused_name, char **unused_argv)
                                          var_milt_data_macros,
                                          var_milt_eoh_macros,
                                          var_milt_eod_macros,
-                                         var_milt_unk_macros);
+                                         var_milt_unk_macros,
+                                         var_milt_macro_deflts);
        else
            smtpd_input_transp_mask |= INPUT_TRANSP_MILTER;
     }
@@ -5750,6 +5758,7 @@ int     main(int argc, char **argv)
        VAR_MILT_DEF_ACTION, DEF_MILT_DEF_ACTION, &var_milt_def_action, 1, 0,
        VAR_MILT_DAEMON_NAME, DEF_MILT_DAEMON_NAME, &var_milt_daemon_name, 1, 0,
        VAR_MILT_V, DEF_MILT_V, &var_milt_v, 1, 0,
+       VAR_MILT_MACRO_DEFLTS, DEF_MILT_MACRO_DEFLTS, &var_milt_macro_deflts, 0, 0,
        VAR_STRESS, DEF_STRESS, &var_stress, 0, 0,
        VAR_UNV_FROM_WHY, DEF_UNV_FROM_WHY, &var_unv_from_why, 0, 0,
        VAR_UNV_RCPT_WHY, DEF_UNV_RCPT_WHY, &var_unv_rcpt_why, 0, 0,
index 833148a7e65bd48a0a6df7eed6770405204628e9..bd0fb2c139c1eca8e2b4a48b75623dec35caea7f 100644 (file)
@@ -71,14 +71,6 @@ const char *smtpd_milter_eval(const char *name, void *ptr)
     if (state->expand_buf == 0)
        state->expand_buf = vstring_alloc(10);
 
-    /*
-     * Canonicalize the name.
-     */
-    if (*name != '{') {                                /* } */
-       vstring_sprintf(state->expand_buf, "{%s}", name);
-       name = STR(state->expand_buf);
-    }
-
     /*
      * System macros.
      */
@@ -143,7 +135,7 @@ const char *smtpd_milter_eval(const char *name, void *ptr)
     /*
      * MAIL FROM macros.
      */
-#define IF_SASL_ENABLED(s) (smtpd_sasl_is_active(state) && (s) ? (s) : 0)
+#define IF_SASL_ENABLED(s) ((s) ? (s) : 0)
 
     if (strcmp(name, S8_MAC_I) == 0)
        return (state->queue_id);
index cb9b64991b8ea02b0b232e786195378d142f4ebe..a08e6774f776d59449caade7ac4eb63a7ec049fc 100644 (file)
 #define ATTR_TYPE_DATA         5       /* Binary data */
 #define ATTR_TYPE_FUNC         6       /* Function pointer */
 
+ /*
+  * Optional sender-specified grouping for hash or nameval tables.
+  */
+#define ATTR_TYPE_OPEN         '{'
+#define ATTR_TYPE_CLOSE                '}'
+#define ATTR_NAME_OPEN         "{"
+#define ATTR_NAME_CLOSE                "}"
+
 #define ATTR_HASH_LIMIT                1024    /* Size of hash table */
 
  /*
index 44238f5c770080ac41e0df7cbb4f3d77fb7f0f47..a916bca7b0d1643a1b32d813fb626008a86990d8 100644 (file)
@@ -174,6 +174,7 @@ int     attr_vprint0(VSTREAM *fp, int flags, va_list ap)
            print_fn(attr_print0, fp, flags | ATTR_FLAG_MORE, print_arg);
            break;
        case ATTR_TYPE_HASH:
+           vstream_fwrite(fp, ATTR_NAME_OPEN, sizeof(ATTR_NAME_OPEN));
            ht_info_list = htable_list(va_arg(ap, HTABLE *));
            for (ht = ht_info_list; *ht; ht++) {
                vstream_fwrite(fp, ht[0]->key, strlen(ht[0]->key) + 1);
@@ -183,6 +184,7 @@ int     attr_vprint0(VSTREAM *fp, int flags, va_list ap)
                             ht[0]->key, (char *) ht[0]->value);
            }
            myfree((void *) ht_info_list);
+           vstream_fwrite(fp, ATTR_NAME_CLOSE, sizeof(ATTR_NAME_CLOSE));
            break;
        default:
            msg_panic("%s: unknown type code: %d", myname, attr_type);
@@ -226,6 +228,7 @@ int     main(int unused_argc, char **argv)
                SEND_ATTR_STR(ATTR_NAME_STR, "whoopee"),
                SEND_ATTR_DATA(ATTR_NAME_DATA, strlen("whoopee"), "whoopee"),
                SEND_ATTR_HASH(table),
+               SEND_ATTR_LONG(ATTR_NAME_LONG, 4321L),
                ATTR_TYPE_END);
     attr_print0(VSTREAM_OUT, ATTR_FLAG_NONE,
                SEND_ATTR_INT(ATTR_NAME_INT, 4711),
index 63871a048962fc236445b9dbfc19c6fd795e44ee..fc3442ec9cbf5ceab5e3641c03e72de94a0dc84a 100644 (file)
@@ -211,6 +211,8 @@ int     attr_vprint64(VSTREAM *fp, int flags, va_list ap)
            print_fn(attr_print64, fp, flags | ATTR_FLAG_MORE, print_arg);
            break;
        case ATTR_TYPE_HASH:
+           attr_print64_str(fp, ATTR_NAME_OPEN, sizeof(ATTR_NAME_OPEN) - 1);
+           VSTREAM_PUTC('\n', fp);
            ht_info_list = htable_list(va_arg(ap, HTABLE *));
            for (ht = ht_info_list; *ht; ht++) {
                attr_print64_str(fp, ht[0]->key, strlen(ht[0]->key));
@@ -222,6 +224,8 @@ int     attr_vprint64(VSTREAM *fp, int flags, va_list ap)
                             ht[0]->key, (char *) ht[0]->value);
            }
            myfree((void *) ht_info_list);
+           attr_print64_str(fp, ATTR_NAME_CLOSE, sizeof(ATTR_NAME_CLOSE) - 1);
+           VSTREAM_PUTC('\n', fp);
            break;
        default:
            msg_panic("%s: unknown type code: %d", myname, attr_type);
@@ -265,6 +269,7 @@ int     main(int unused_argc, char **argv)
                 SEND_ATTR_STR(ATTR_NAME_STR, "whoopee"),
               SEND_ATTR_DATA(ATTR_NAME_DATA, strlen("whoopee"), "whoopee"),
                 SEND_ATTR_HASH(table),
+                SEND_ATTR_LONG(ATTR_NAME_LONG, 4321L),
                 ATTR_TYPE_END);
     attr_print64(VSTREAM_OUT, ATTR_FLAG_NONE,
                 SEND_ATTR_INT(ATTR_NAME_INT, 4711),
index f94afb9af9781c36ddd8c407008e9b7883edc75c..12cde7235f2b5caf6d7abe8fe99b1be8b9dc8ef5 100644 (file)
@@ -169,6 +169,8 @@ int     attr_vprint_plain(VSTREAM *fp, int flags, va_list ap)
            print_fn(attr_print_plain, fp, flags | ATTR_FLAG_MORE, print_arg);
            break;
        case ATTR_TYPE_HASH:
+           vstream_fwrite(fp, ATTR_NAME_OPEN, sizeof(ATTR_NAME_OPEN));
+           VSTREAM_PUTC('\n', fp);
            ht_info_list = htable_list(va_arg(ap, HTABLE *));
            for (ht = ht_info_list; *ht; ht++) {
                vstream_fprintf(fp, "%s=%s\n", ht[0]->key, (char *) ht[0]->value);
@@ -177,6 +179,8 @@ int     attr_vprint_plain(VSTREAM *fp, int flags, va_list ap)
                             ht[0]->key, (char *) ht[0]->value);
            }
            myfree((void *) ht_info_list);
+           vstream_fwrite(fp, ATTR_NAME_CLOSE, sizeof(ATTR_NAME_CLOSE));
+           VSTREAM_PUTC('\n', fp);
            break;
        default:
            msg_panic("%s: unknown type code: %d", myname, attr_type);
@@ -220,6 +224,7 @@ int     main(int unused_argc, char **argv)
                     SEND_ATTR_STR(ATTR_NAME_STR, "whoopee"),
               SEND_ATTR_DATA(ATTR_NAME_DATA, strlen("whoopee"), "whoopee"),
                     SEND_ATTR_HASH(table),
+                    SEND_ATTR_LONG(ATTR_NAME_LONG, 4321L),
                     ATTR_TYPE_END);
     attr_print_plain(VSTREAM_OUT, ATTR_FLAG_NONE,
                     SEND_ATTR_INT(ATTR_NAME_INT, 4711),
index 89bbd41fe01ef399ffdcffa5d6600dd5c1d4a9ee..b1f301610df988a4278178f51c1a8aa62e34a7c4 100644 (file)
@@ -29,7 +29,9 @@
 /*     (item1 | item2) stands for choice:
 /*
 /* .in +5
-/*     attr-list :== simple-attr* null
+/*     attr-list :== (simple-attr | multi-attr)* null
+/* .br
+/*     multi-attr :== "{" null simple-attr* "}" null
 /* .br
 /*     simple-attr :== attr-name null attr-value null
 /* .br
 /*     error.
 /* .IP "RECV_ATTR_HASH(HTABLE *table)"
 /* .IP "RECV_ATTR_NAMEVAL(NVTABLE *table)"
-/*     All further input attributes are processed as string attributes.
-/*     No specific attribute sequence is enforced.
-/*     All attributes up to the attribute list terminator are read,
-/*     but only the first instance of each attribute is stored.
+/*     Receive a sequence of attribute names and string values.
 /*     There can be no more than 1024 attributes in a hash table.
 /* .sp
 /*     The attribute string values are stored in the hash table under
 /*     Values from the input stream are added to the hash table. Existing
 /*     hash table entries are not replaced.
 /* .sp
-/*     N.B. This construct must be followed by an ATTR_TYPE_END argument.
+/*     Note: the SEND_ATTR_HASH or SEND_ATTR_NAMEVAL requests
+/*     format their payload as a multi-attr sequence (see syntax
+/*     above). When the receiver's input does not start with a
+/*     multi-attr delimiter (i.e. the sender did not request
+/*     SEND_ATTR_HASH or SEND_ATTR_NAMEVAL), the receiver will
+/*     store all attribute names and values up to the attribute
+/*     list terminator. In terms of code, this means that the
+/*     RECV_ATTR_HASH or RECV_ATTR_NAMEVAL request must be followed
+/*     by ATTR_TYPE_END.
 /* .IP ATTR_TYPE_END
 /*     This argument terminates the requested attribute list.
 /* .RE
@@ -294,7 +301,8 @@ int     attr_vscan0(VSTREAM *fp, int flags, va_list ap)
         * from the input stream instead. This is secure only when the
         * resulting table is queried with known to be good attribute names.
         */
-       if (wanted_type != ATTR_TYPE_HASH) {
+       if (wanted_type != ATTR_TYPE_HASH
+           && wanted_type != ATTR_TYPE_CLOSE) {
            wanted_type = va_arg(ap, int);
            if (wanted_type == ATTR_TYPE_END) {
                if ((flags & ATTR_FLAG_MORE) != 0)
@@ -303,9 +311,6 @@ int     attr_vscan0(VSTREAM *fp, int flags, va_list ap)
            } else if (wanted_type == ATTR_TYPE_HASH) {
                wanted_name = "(any attribute name or list terminator)";
                hash_table = va_arg(ap, HTABLE *);
-               if (va_arg(ap, int) !=ATTR_TYPE_END)
-                   msg_panic("%s: ATTR_TYPE_HASH not followed by ATTR_TYPE_END",
-                             myname);
            } else if (wanted_type != ATTR_TYPE_FUNC) {
                wanted_name = va_arg(ap, char *);
            }
@@ -340,7 +345,20 @@ int     attr_vscan0(VSTREAM *fp, int flags, va_list ap)
            /*
             * See if the caller asks for this attribute.
             */
+           if (wanted_type == ATTR_TYPE_HASH 
+               && strcmp(ATTR_NAME_OPEN, STR(name_buf)) == 0) {
+               wanted_type = ATTR_TYPE_CLOSE;
+               wanted_name = "(any attribute name or '}')";
+               /* Advance in the input stream. */
+               continue;
+           } else if (wanted_type == ATTR_TYPE_CLOSE
+               && strcmp(ATTR_NAME_CLOSE, STR(name_buf)) == 0) {
+               /* Advance in the argument list. */
+               wanted_type = -1;
+               break;
+           }
            if (wanted_type == ATTR_TYPE_HASH
+               || wanted_type == ATTR_TYPE_CLOSE
                || (wanted_type != ATTR_TYPE_END
                    && strcmp(wanted_name, STR(name_buf)) == 0))
                break;
@@ -391,6 +409,7 @@ int     attr_vscan0(VSTREAM *fp, int flags, va_list ap)
                return (-1);
            break;
        case ATTR_TYPE_HASH:
+       case ATTR_TYPE_CLOSE:
            if ((ch = attr_scan0_string(fp, str_buf,
                                        "input attribute value")) < 0)
                return (-1);
@@ -409,6 +428,9 @@ int     attr_vscan0(VSTREAM *fp, int flags, va_list ap)
                             mystrdup(STR(str_buf)));
            }
            break;
+       case -1:
+           conversions -= 1;
+           break;
        default:
            msg_panic("%s: unknown type code: %d", myname, wanted_type);
        }
@@ -447,6 +469,7 @@ int     main(int unused_argc, char **used_argv)
     HTABLE_INFO **ht;
     int     int_val;
     long    long_val;
+    long    long_val2;
     int     ret;
 
     msg_verbose = 1;
@@ -458,6 +481,7 @@ int     main(int unused_argc, char **used_argv)
                          RECV_ATTR_STR(ATTR_NAME_STR, str_val),
                          RECV_ATTR_DATA(ATTR_NAME_DATA, data_val),
                          RECV_ATTR_HASH(table),
+                         RECV_ATTR_LONG(ATTR_NAME_LONG, &long_val2),
                          ATTR_TYPE_END)) > 4) {
        vstream_printf("%s %d\n", ATTR_NAME_INT, int_val);
        vstream_printf("%s %ld\n", ATTR_NAME_LONG, long_val);
@@ -467,6 +491,7 @@ int     main(int unused_argc, char **used_argv)
        for (ht = ht_info_list; *ht; ht++)
            vstream_printf("(hash) %s %s\n", ht[0]->key, (char *) ht[0]->value);
        myfree((void *) ht_info_list);
+       vstream_printf("%s %ld\n", ATTR_NAME_LONG, long_val2);
     } else {
        vstream_printf("return: %d\n", ret);
     }
index a9e211d82d619920e94067cfd7daf5559d1cd0e6..125faeb5965760b112a9e7368636f50736020292 100644 (file)
@@ -4,6 +4,7 @@
 ./attr_print0: send attr data = [data 7 bytes]
 ./attr_print0: send attr name foo-name value foo-value
 ./attr_print0: send attr name bar-name value bar-value
+./attr_print0: send attr long_number = 4321
 ./attr_print0: send attr number = 4711
 ./attr_print0: send attr long_number = 1234
 ./attr_print0: send attr string = whoopee
 ./attr_scan0: input attribute name: data
 ./attr_scan0: input attribute value: d2hvb3BlZQ==
 ./attr_scan0: unknown_stream: wanted attribute: (any attribute name or list terminator)
+./attr_scan0: input attribute name: {
+./attr_scan0: unknown_stream: wanted attribute: (any attribute name or '}')
 ./attr_scan0: input attribute name: foo-name
 ./attr_scan0: input attribute value: foo-value
-./attr_scan0: unknown_stream: wanted attribute: (any attribute name or list terminator)
+./attr_scan0: unknown_stream: wanted attribute: (any attribute name or '}')
 ./attr_scan0: input attribute name: bar-name
 ./attr_scan0: input attribute value: bar-value
-./attr_scan0: unknown_stream: wanted attribute: (any attribute name or list terminator)
+./attr_scan0: unknown_stream: wanted attribute: (any attribute name or '}')
+./attr_scan0: input attribute name: }
+./attr_scan0: unknown_stream: wanted attribute: long_number
+./attr_scan0: input attribute name: long_number
+./attr_scan0: input attribute value: 4321
+./attr_scan0: unknown_stream: wanted attribute: (list terminator)
 ./attr_scan0: input attribute name: (end)
 ./attr_scan0: unknown_stream: wanted attribute: number
 ./attr_scan0: input attribute name: number
@@ -48,6 +56,7 @@ string whoopee
 data whoopee
 (hash) foo-name foo-value
 (hash) bar-name bar-value
+long_number 4321
 number 4711
 long_number 1234
 string whoopee
index 488c4c5f575c89faff58c208ef29ba9ae35f9fd2..0880d83ad2e95363fa80560bc8924e52d71ae97f 100644 (file)
@@ -29,7 +29,9 @@
 /*     (item1 | item2) stands for choice:
 /*
 /* .in +5
-/*     attr-list :== simple-attr* newline
+/*     attr-list :== (simple-attr | multi-attr)* newline
+/* .br
+/*     multi-attr :== "{" newline simple-attr* "}" newline
 /* .br
 /*     simple-attr :== attr-name colon attr-value newline
 /* .br
 /*     error.
 /* .IP "RECV_ATTR_HASH(HTABLE *table)"
 /* .IP "RECV_ATTR_NAMEVAL(NVTABLE *table)"
-/*     All further input attributes are processed as string attributes.
-/*     No specific attribute sequence is enforced.
-/*     All attributes up to the attribute list terminator are read,
-/*     but only the first instance of each attribute is stored.
+/*     Receive a sequence of attribute names and string values.
 /*     There can be no more than 1024 attributes in a hash table.
 /* .sp
 /*     The attribute string values are stored in the hash table under
 /*     Values from the input stream are added to the hash table. Existing
 /*     hash table entries are not replaced.
 /* .sp
-/*     N.B. This construct must be followed by an ATTR_TYPE_END argument.
+/*     Note: the SEND_ATTR_HASH or SEND_ATTR_NAMEVAL requests
+/*     format their payload as a multi-attr sequence (see syntax
+/*     above). When the receiver's input does not start with a
+/*     multi-attr delimiter (i.e. the sender did not request
+/*     SEND_ATTR_HASH or SEND_ATTR_NAMEVAL), the receiver will
+/*     store all attribute names and values up to the attribute
+/*     list terminator. In terms of code, this means that the
+/*     RECV_ATTR_HASH or RECV_ATTR_NAMEVAL request must be followed
+/*     by ATTR_TYPE_END.
 /* .IP ATTR_TYPE_END
 /*     This argument terminates the requested attribute list.
 /* .RE
@@ -297,7 +304,8 @@ int     attr_vscan64(VSTREAM *fp, int flags, va_list ap)
         * from the input stream instead. This is secure only when the
         * resulting table is queried with known to be good attribute names.
         */
-       if (wanted_type != ATTR_TYPE_HASH) {
+       if (wanted_type != ATTR_TYPE_HASH
+           && wanted_type != ATTR_TYPE_CLOSE) {
            wanted_type = va_arg(ap, int);
            if (wanted_type == ATTR_TYPE_END) {
                if ((flags & ATTR_FLAG_MORE) != 0)
@@ -306,9 +314,6 @@ int     attr_vscan64(VSTREAM *fp, int flags, va_list ap)
            } else if (wanted_type == ATTR_TYPE_HASH) {
                wanted_name = "(any attribute name or list terminator)";
                hash_table = va_arg(ap, HTABLE *);
-               if (va_arg(ap, int) !=ATTR_TYPE_END)
-                   msg_panic("%s: ATTR_TYPE_HASH not followed by ATTR_TYPE_END",
-                             myname);
            } else if (wanted_type != ATTR_TYPE_FUNC) {
                wanted_name = va_arg(ap, char *);
            }
@@ -343,7 +348,20 @@ int     attr_vscan64(VSTREAM *fp, int flags, va_list ap)
            /*
             * See if the caller asks for this attribute.
             */
+           if (wanted_type == ATTR_TYPE_HASH 
+               && ch == '\n' && strcmp(ATTR_NAME_OPEN, STR(name_buf)) == 0) {
+               wanted_type = ATTR_TYPE_CLOSE;
+               wanted_name = "(any attribute name or '}')";
+               /* Advance in the input stream. */
+               continue;
+           } else if (wanted_type == ATTR_TYPE_CLOSE
+               && ch == '\n' && strcmp(ATTR_NAME_CLOSE, STR(name_buf)) == 0) {
+               /* Advance in the argument list. */
+               wanted_type = -1;
+               break;
+           }
            if (wanted_type == ATTR_TYPE_HASH
+               || wanted_type == ATTR_TYPE_CLOSE
                || (wanted_type != ATTR_TYPE_END
                    && strcmp(wanted_name, STR(name_buf)) == 0))
                break;
@@ -440,6 +458,7 @@ int     attr_vscan64(VSTREAM *fp, int flags, va_list ap)
                return (-1);
            break;
        case ATTR_TYPE_HASH:
+       case ATTR_TYPE_CLOSE:
            if (ch != ':') {
                msg_warn("missing value for string attribute %s from %s",
                         STR(name_buf), VSTREAM_PATH(fp));
@@ -468,6 +487,9 @@ int     attr_vscan64(VSTREAM *fp, int flags, va_list ap)
                             mystrdup(STR(str_buf)));
            }
            break;
+       case -1:
+           conversions -= 1;
+           break;
        default:
            msg_panic("%s: unknown type code: %d", myname, wanted_type);
        }
@@ -506,6 +528,7 @@ int     main(int unused_argc, char **used_argv)
     HTABLE_INFO **ht;
     int     int_val;
     long    long_val;
+    long    long_val2;
     int     ret;
 
     msg_verbose = 1;
@@ -517,6 +540,7 @@ int     main(int unused_argc, char **used_argv)
                           RECV_ATTR_STR(ATTR_NAME_STR, str_val),
                           RECV_ATTR_DATA(ATTR_NAME_DATA, data_val),
                           RECV_ATTR_HASH(table),
+                          RECV_ATTR_LONG(ATTR_NAME_LONG, &long_val2),
                           ATTR_TYPE_END)) > 4) {
        vstream_printf("%s %d\n", ATTR_NAME_INT, int_val);
        vstream_printf("%s %ld\n", ATTR_NAME_LONG, long_val);
@@ -526,6 +550,7 @@ int     main(int unused_argc, char **used_argv)
        for (ht = ht_info_list; *ht; ht++)
            vstream_printf("(hash) %s %s\n", ht[0]->key, (char *) ht[0]->value);
        myfree((void *) ht_info_list);
+       vstream_printf("%s %ld\n", ATTR_NAME_LONG, long_val2);
     } else {
        vstream_printf("return: %d\n", ret);
     }
index 0f1915bc74172cdf2caa6b64a95dfcb919ed4531..2fe353f802e2b353b8d176c51dd1b31efae1032f 100644 (file)
@@ -4,6 +4,7 @@
 ./attr_print64: send attr data = [data 7 bytes]
 ./attr_print64: send attr name foo-name value foo-value
 ./attr_print64: send attr name bar-name value bar-value
+./attr_print64: send attr long_number = 4321
 ./attr_print64: send attr number = 4711
 ./attr_print64: send attr long_number = 1234
 ./attr_print64: send attr string = whoopee
 ./attr_scan64: input attribute name: data
 ./attr_scan64: input attribute value: whoopee
 ./attr_scan64: unknown_stream: wanted attribute: (any attribute name or list terminator)
+./attr_scan64: input attribute name: {
+./attr_scan64: unknown_stream: wanted attribute: (any attribute name or '}')
 ./attr_scan64: input attribute name: foo-name
 ./attr_scan64: input attribute value: foo-value
-./attr_scan64: unknown_stream: wanted attribute: (any attribute name or list terminator)
+./attr_scan64: unknown_stream: wanted attribute: (any attribute name or '}')
 ./attr_scan64: input attribute name: bar-name
 ./attr_scan64: input attribute value: bar-value
-./attr_scan64: unknown_stream: wanted attribute: (any attribute name or list terminator)
+./attr_scan64: unknown_stream: wanted attribute: (any attribute name or '}')
+./attr_scan64: input attribute name: }
+./attr_scan64: unknown_stream: wanted attribute: long_number
+./attr_scan64: input attribute name: long_number
+./attr_scan64: input attribute value: 4321
+./attr_scan64: unknown_stream: wanted attribute: (list terminator)
 ./attr_scan64: input attribute name: (end)
 ./attr_scan64: unknown_stream: wanted attribute: number
 ./attr_scan64: input attribute name: number
@@ -48,6 +56,7 @@ string whoopee
 data whoopee
 (hash) foo-name foo-value
 (hash) bar-name bar-value
+long_number 4321
 number 4711
 long_number 1234
 string whoopee
index 4a99f5cdfa0b9eb869e8b3c70a09208aa83242fc..fed76cddd35818bb2672e288d9d4aca79e18a1d6 100644 (file)
@@ -29,7 +29,9 @@
 /*     (item1 | item2) stands for choice:
 /*
 /* .in +5
-/*     attr-list :== simple-attr* newline
+/*     attr-list :== (simple-attr | multi-attr)* newline
+/* .br
+/*     multi-attr :== "{" newline simple-attr* "}" newline
 /* .br
 /*     simple-attr :== attr-name "=" attr-value newline
 /* .br
 /*     error.
 /* .IP "RECV_ATTR_HASH(HTABLE *table)"
 /* .IP "RECV_ATTR_NAMEVAL(NVTABLE *table)"
-/*     All further input attributes are processed as string attributes.
-/*     No specific attribute sequence is enforced.
-/*     All attributes up to the attribute list terminator are read,
-/*     but only the first instance of each attribute is stored.
+/*     Receive a sequence of attribute names and string values.
 /*     There can be no more than 1024 attributes in a hash table.
 /* .sp
 /*     The attribute string values are stored in the hash table under
 /*     Values from the input stream are added to the hash table. Existing
 /*     hash table entries are not replaced.
 /* .sp
-/*     N.B. This construct must be followed by an ATTR_TYPE_END argument.
+/*     Note: the SEND_ATTR_HASH or SEND_ATTR_NAMEVAL requests
+/*     format their payload as a multi-attr sequence (see syntax
+/*     above). When the receiver's input does not start with a
+/*     multi-attr delimiter (i.e. the sender did not request
+/*     SEND_ATTR_HASH or SEND_ATTR_NAMEVAL), the receiver will
+/*     store all attribute names and values up to the attribute
+/*     list terminator. In terms of code, this means that the
+/*     RECV_ATTR_HASH or RECV_ATTR_NAMEVAL request must be followed
+/*     by ATTR_TYPE_END.
 /* .IP ATTR_TYPE_END
 /*     This argument terminates the requested attribute list.
 /* .RE
@@ -310,7 +317,8 @@ int     attr_vscan_plain(VSTREAM *fp, int flags, va_list ap)
         * from the input stream instead. This is secure only when the
         * resulting table is queried with known to be good attribute names.
         */
-       if (wanted_type != ATTR_TYPE_HASH) {
+       if (wanted_type != ATTR_TYPE_HASH
+           && wanted_type != ATTR_TYPE_CLOSE) {
            wanted_type = va_arg(ap, int);
            if (wanted_type == ATTR_TYPE_END) {
                if ((flags & ATTR_FLAG_MORE) != 0)
@@ -319,9 +327,6 @@ int     attr_vscan_plain(VSTREAM *fp, int flags, va_list ap)
            } else if (wanted_type == ATTR_TYPE_HASH) {
                wanted_name = "(any attribute name or list terminator)";
                hash_table = va_arg(ap, HTABLE *);
-               if (va_arg(ap, int) !=ATTR_TYPE_END)
-                   msg_panic("%s: ATTR_TYPE_HASH not followed by ATTR_TYPE_END",
-                             myname);
            } else if (wanted_type != ATTR_TYPE_FUNC) {
                wanted_name = va_arg(ap, char *);
            }
@@ -356,7 +361,20 @@ int     attr_vscan_plain(VSTREAM *fp, int flags, va_list ap)
            /*
             * See if the caller asks for this attribute.
             */
+           if (wanted_type == ATTR_TYPE_HASH 
+               && ch == '\n' && strcmp(ATTR_NAME_OPEN, STR(name_buf)) == 0) {
+               wanted_type = ATTR_TYPE_CLOSE;
+               wanted_name = "(any attribute name or '}')";
+               /* Advance in the input stream. */
+               continue;
+           } else if (wanted_type == ATTR_TYPE_CLOSE
+               && ch == '\n' && strcmp(ATTR_NAME_CLOSE, STR(name_buf)) == 0) {
+               /* Advance in the argument list. */
+               wanted_type = -1;
+               break;
+           }
            if (wanted_type == ATTR_TYPE_HASH
+               || wanted_type == ATTR_TYPE_CLOSE
                || (wanted_type != ATTR_TYPE_END
                    && strcmp(wanted_name, STR(name_buf)) == 0))
                break;
@@ -428,6 +446,7 @@ int     attr_vscan_plain(VSTREAM *fp, int flags, va_list ap)
                return (-1);
            break;
        case ATTR_TYPE_HASH:
+       case ATTR_TYPE_CLOSE:
            if (ch != '=') {
                msg_warn("missing value for string attribute %s from %s",
                         STR(name_buf), VSTREAM_PATH(fp));
@@ -451,6 +470,9 @@ int     attr_vscan_plain(VSTREAM *fp, int flags, va_list ap)
                             mystrdup(STR(str_buf)));
            }
            break;
+       case -1:
+           conversions -= 1;
+           break;
        default:
            msg_panic("%s: unknown type code: %d", myname, wanted_type);
        }
@@ -489,6 +511,7 @@ int     main(int unused_argc, char **used_argv)
     HTABLE_INFO **ht;
     int     int_val;
     long    long_val;
+    long    long_val2;
     int     ret;
 
     msg_verbose = 1;
@@ -500,6 +523,7 @@ int     main(int unused_argc, char **used_argv)
                               RECV_ATTR_STR(ATTR_NAME_STR, str_val),
                               RECV_ATTR_DATA(ATTR_NAME_DATA, data_val),
                               RECV_ATTR_HASH(table),
+                              RECV_ATTR_LONG(ATTR_NAME_LONG, &long_val2),
                               ATTR_TYPE_END)) > 4) {
        vstream_printf("%s %d\n", ATTR_NAME_INT, int_val);
        vstream_printf("%s %ld\n", ATTR_NAME_LONG, long_val);
@@ -509,6 +533,7 @@ int     main(int unused_argc, char **used_argv)
        for (ht = ht_info_list; *ht; ht++)
            vstream_printf("(hash) %s %s\n", ht[0]->key, (char *) ht[0]->value);
        myfree((void *) ht_info_list);
+       vstream_printf("%s %ld\n", ATTR_NAME_LONG, long_val2);
     } else {
        vstream_printf("return: %d\n", ret);
     }
index eee95eb546466b5298a1a744fbad62bdd12a7a20..6e962c81fd1de76c1830a9f997f5d28012f8c3ee 100644 (file)
@@ -4,6 +4,7 @@
 ./attr_print_plain: send attr data = [data 7 bytes]
 ./attr_print_plain: send attr name foo-name value foo-value
 ./attr_print_plain: send attr name bar-name value bar-value
+./attr_print_plain: send attr long_number = 4321
 ./attr_print_plain: send attr number = 4711
 ./attr_print_plain: send attr long_number = 1234
 ./attr_print_plain: send attr string = whoopee
 ./attr_scan_plain: input attribute name: data
 ./attr_scan_plain: input attribute value: d2hvb3BlZQ==
 ./attr_scan_plain: unknown_stream: wanted attribute: (any attribute name or list terminator)
+./attr_scan_plain: input attribute name: {
+./attr_scan_plain: unknown_stream: wanted attribute: (any attribute name or '}')
 ./attr_scan_plain: input attribute name: foo-name
 ./attr_scan_plain: input attribute value: foo-value
-./attr_scan_plain: unknown_stream: wanted attribute: (any attribute name or list terminator)
+./attr_scan_plain: unknown_stream: wanted attribute: (any attribute name or '}')
 ./attr_scan_plain: input attribute name: bar-name
 ./attr_scan_plain: input attribute value: bar-value
-./attr_scan_plain: unknown_stream: wanted attribute: (any attribute name or list terminator)
+./attr_scan_plain: unknown_stream: wanted attribute: (any attribute name or '}')
+./attr_scan_plain: input attribute name: }
+./attr_scan_plain: unknown_stream: wanted attribute: long_number
+./attr_scan_plain: input attribute name: long_number
+./attr_scan_plain: input attribute value: 4321
+./attr_scan_plain: unknown_stream: wanted attribute: (list terminator)
 ./attr_scan_plain: input attribute name: (end)
 ./attr_scan_plain: unknown_stream: wanted attribute: number
 ./attr_scan_plain: input attribute name: number
@@ -48,6 +56,7 @@ string whoopee
 data whoopee
 (hash) foo-name foo-value
 (hash) bar-name bar-value
+long_number 4321
 number 4711
 long_number 1234
 string whoopee
index 497c216fd1eae90592166d728a01e971d08daac3..5b381af4032c2e651cbc338b00bd39e5a80fcc51 100644 (file)
@@ -756,7 +756,7 @@ extern int initgroups(const char *, int);
  /*
   * LINUX.
   */
-#if defined(LINUX2) || defined(LINUX3)
+#if defined(LINUX2) || defined(LINUX3) || defined(LINUX4)
 #define SUPPORTED
 #include <sys/types.h>
 #define UINT32_TYPE    unsigned int