Delay ACL header edits until transport time.
authorMark Wooding <mdw@distorted.org.uk>
Sun, 14 Jun 2015 12:51:55 +0000 (13:51 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Sun, 14 Jun 2015 12:51:55 +0000 (13:51 +0100)
Don't use the `add_header' ACL control any more.  Instead, just
accumulate the desired header additions and removals in variables, and
apply them at transport time.

This way, the headers we see in the message are the unmodified ones, as
the message was originally given to us.  We can therefore apply header
/removals/ (which aren't allowed in ACLs, so have to be delayed to
routing/transport time) coherently, without the risk of clobbering
the headers we've added ourselves.

base.m4
defs.m4
exchange.m4
spam.m4

diff --git a/base.m4 b/base.m4
index 506c4e0..39e302b 100644 (file)
--- a/base.m4
+++ b/base.m4
@@ -160,11 +160,11 @@ mail:
        warn     condition = $acl_c_helo_warning
                !condition = ${if eq{$acl_c_mode}{submission}}
                !hosts = +allnets
-                add_header = :after_received:X-CONF_header_token-Warning: \
+                ADD_HEADER(<:X-CONF_header_token-Warning: \
                        BADHELO \
                        Client's HELO doesn't match its IP address.\n\t\
                        helo-name=$sender_helo_name \
-                       address=$sender_host_address
+                       address=$sender_host_address:>)
 
        ## Always allow the empty sender, so that we can receive bounces.
        accept   senders = :
@@ -382,6 +382,16 @@ m4_define(<:USER_DELIVERY:>,
        envelope_to_add = true
        return_path_add = true:>)
 
+m4_define(<:APPLY_HEADER_CHANGES:>,
+       <:headers_add = m4_ifelse(<:$1:>, <::>,
+               <:$acl_m_hdradd:>,
+               <:${if def:acl_m_hdradd{$acl_m_hdradd\n}}\
+               $1:>)
+       headers_remove = m4_ifelse(<:$2:>, <::>,
+               <:$acl_m_hdrrm:>,
+               <:${if def:acl_m_hdrrm{$acl_m_hdrrm:}}\
+               $2:>):>)
+
 SECTION(transports)m4_dnl
 ## A standard transport for remote delivery.  By default, try to do TLS, and
 ## don't worry too much if it's not very secure: the alternative is sending
@@ -391,12 +401,14 @@ SECTION(transports)m4_dnl
 ## it into the transport name.  This is very unpleasant, of course.
 smtp:
        driver = smtp
+       APPLY_HEADER_CHANGES
        tls_require_ciphers = CONF_acceptable_ciphers
        tls_dh_min_bits = 1020
        tls_tempfail_tryclear = true
 
 m4_define(<:SMTP_TRANS_DHBITS:>,
        <:driver = smtp
+       APPLY_HEADER_CHANGES
        hosts_try_auth = *
        hosts_require_tls = DOMKV(tls-peer-ca, {*}{})
        hosts_require_auth = \
@@ -423,6 +435,7 @@ smtp_dhbits_2048:
 ## authentication.
 smtp_local:
        driver = smtp
+       APPLY_HEADER_CHANGES
        hosts_require_tls = *
        tls_certificate = CONF_sysconf_dir/client.certlist
        tls_privatekey = CONF_sysconf_dir/client.key
@@ -437,6 +450,7 @@ smtp_local:
 ## A standard transport for local delivery.
 deliver:
        driver = appendfile
+       APPLY_HEADER_CHANGES
        file = /var/mail/$local_part
        group = mail
        mode = 0600
@@ -446,17 +460,20 @@ deliver:
 ## Transports for user filters.
 mailbox:
        driver = appendfile
+       APPLY_HEADER_CHANGES
        initgroups = true
        USER_DELIVERY
 
 maildir:
        driver = appendfile
+       APPLY_HEADER_CHANGES
        maildir_format = true
        initgroups = true
        USER_DELIVERY
 
 pipe:
        driver = pipe
+       APPLY_HEADER_CHANGES
        path = ${if and {{def:home} {exists{$home/bin}}} {$home/bin:} {}}\
                /usr/local/bin:/usr/local/sbin:\
                /usr/bin:/usr/sbin:/bin:/sbin
diff --git a/defs.m4 b/defs.m4
index 8ece5d4..370c2d3 100644 (file)
--- a/defs.m4
+++ b/defs.m4
@@ -112,6 +112,13 @@ m4_ifdef(<:_done:$1/$2:>, <::>, <:m4_dnl
 m4_ifdef(<:_head:$1/$2:>, <:<:##:> m4_indir(<:_head:$1/$2:>)
 :>)m4_define(<:_done:$1/$2:>):>):>):>)
 
+## ADD_HEADER(hdrs)
+##
+## An ACL action to add the given HDRS, which are a `\n'-terminated list of
+## new header lines.
+m4_define(<:ADD_HEADER:>, <:m4_dnl
+ set   acl_m_hdradd = ${if def:acl_m_hdradd{$acl_m_hdradd}{}}$1\n:>)
+
 ## RENAME_HEADERS_ADD(list)
 ##
 ## Return a newline-separated list of message header additions of the form
index 1dc58f0..9f8324a 100644 (file)
@@ -52,12 +52,12 @@ mail_client_addr:
                           {${if match_domain {$sender_address_domain} \
                                              {+public} \
                                 {+allnets}{! +allnets}}})}
-                add_header = :after_received:X-CONF_header_token-Warning: \
+                ADD_HEADER(<:X-CONF_header_token-Warning: \
                        RCLNTLSNDR \
                        Apparently local sender, but received from remote \
                        server.\n\t\
                        sender=$sender_address \
-                       host=$sender_host_address
+                       host=$sender_host_address:>)
 
        ## OK.
        accept
diff --git a/spam.m4 b/spam.m4
index bae1686..a1134e5 100644 (file)
--- a/spam.m4
+++ b/spam.m4
@@ -205,13 +205,13 @@ data_spam:
                 set acl_m_spam_tests = ${sg{$acl_m_spam_tests}{!(.)}{\$1}}
 
                 ## Insert the headers.
-                add_header = X-CONF_header_token-SpamAssassin-Score: \
+                ADD_HEADER(<:X-CONF_header_token-SpamAssassin-Score: \
                        $spam_score/$acl_m_spam_limit_presentation \
-                       ($spam_bar)
-                add_header = X-CONF_header_token-SpamAssassin-Status: \
+                       ($spam_bar):>)
+                ADD_HEADER(<:X-CONF_header_token-SpamAssassin-Status: \
                        score=$spam_score, \
                        limit=$acl_m_spam_limit_presentation, \n\t\
-                       tests=$acl_m_spam_tests
+                       tests=$acl_m_spam_tests:>)
 
        ## We're good.
        accept