ACL: patterns for remove_headers. Bug 2985
authorJeremy Harris <jgh146exb@wizmail.org>
Fri, 17 Mar 2023 18:39:46 +0000 (18:39 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Fri, 17 Mar 2023 18:39:46 +0000 (18:39 +0000)
doc/doc-docbook/spec.xfpt
doc/doc-txt/NewStuff
doc/doc-txt/experimental-spec.txt
src/src/header.c
src/src/local_scan.h
src/src/receive.c
test/confs/0567
test/mail/0567.rcptok
test/scripts/0000-Basic/0567

index bdc0eb30eed9ddf6301736720acbfb913b289373..08a197bd707c4dd0fa002fbb5ed23b6964395155 100644 (file)
@@ -32134,8 +32134,24 @@ Headers will not be removed from the message if the modifier is used in
 DATA, MIME or DKIM ACLs for a message delivered by cutthrough routing.
 
 More than one header can be removed at the same time by using a colon separated
-list of header names. The header matching is case insensitive. Wildcards are
-not permitted, nor is list expansion performed, so you cannot use hostlists to
+list of header specifiers.
+.new
+If a specifier does not start with a circumflex (^)
+then it is treated as a header name.
+The header name matching is case insensitive.
+If it does, then it is treated as a (front-anchored)
+regular expression applied to the whole header.
+
+&*Note*&: The colon terminating a header name will need to be doubled
+if used in an RE, and there can legitimately be whitepace before it.
+
+Example:
+.code
+remove_header = \N^(?i)Authentication-Results\s*::\s*example.org;\N
+.endd
+.wen
+
+List expansion is not performed, so you cannot use hostlists to
 create a list of headers, however both connection and message variable expansion
 are performed (&%$acl_c_*%& and &%$acl_m_*%&), illustrated in this example:
 .code
@@ -32144,14 +32160,14 @@ warn   hosts           = +internal_hosts
 warn   message         = Remove internal headers
        remove_header   = $acl_c_ihdrs
 .endd
-Header names for removal are accumulated during the MAIL, RCPT, and predata ACLs.
+Header specifiers for removal are accumulated during the MAIL, RCPT, and predata ACLs.
 Matching header lines are removed from the message before processing the DATA and MIME ACLs.
 If multiple header lines match, all are removed.
 There is no harm in attempting to remove the same header twice nor in removing
-a non-existent header. Further header lines to be removed may be accumulated
-during the DATA and MIME ACLs, after which they are removed from the message,
-if present. In the case of non-SMTP messages, headers to be removed are
-accumulated during the non-SMTP ACLs, and are removed from the message after
+a non-existent header. Further header specifiers for removal may be accumulated
+during the DATA and MIME ACLs, after which matching headers are removed
+if present. In the case of non-SMTP messages, remove speifiers are
+accumulated during the non-SMTP ACLs, and are acted on after
 all the ACLs have run. If a message is rejected after DATA or by the non-SMTP
 ACL, there really is no effect because there is no logging of what headers
 would have been removed.
index 84db8ea589bf5bf94d588cf3d57471adc31729b0..991bcf74187143148ccfbeec2136efc90ff6e648 100644 (file)
@@ -31,6 +31,8 @@ Version 4.97
 
  11. An option for the ${readsocket } expansion to set an SNI for TLS.
 
+ 12. The ACL remove_header modifier can take a pattern.
+
 Version 4.96
 ------------
 
index dbd57d698cac6b6af0cdd0164c3e37a61ce237a6..aac8ca77d622f976d509230bac666723c745ef79 100644 (file)
@@ -513,7 +513,9 @@ standard header.
   add_header = :at_start:${authresults {<admd-identifier>}}
 
        Note that it would be wise to strip incoming messages of A-R headers
-       that claim to be from our own <admd-identifier>.
+       that claim to be from our own <admd-identifier>.  Eg:
+
+  remove_header = \N^(?i)Authentication-Results\s*::\s*example.org;\N
 
 There are four new variables:
 
index d5f1dcd6bfd1058b667a03eb99f66c7b5a0fdc20..59a9a13b304d4eba2e800bb0db952ffe284c8b5f 100644 (file)
@@ -30,11 +30,12 @@ Returns:    TRUE or FALSE
 */
 
 BOOL
-header_testname(header_line *h, const uschar *name, int len, BOOL notdel)
+header_testname(const header_line * h, const uschar * name, int len,
+  BOOL notdel)
 {
 uschar *tt;
 if (h->type == '*' && notdel) return FALSE;
-if (h->text == NULL || strncmpic(h->text, name, len) != 0) return FALSE;
+if (!h->text || strncmpic(h->text, name, len) != 0) return FALSE;
 tt = h->text + len;
 while (*tt == ' ' || *tt == '\t') tt++;
 return *tt == ':';
@@ -46,11 +47,11 @@ return *tt == ':';
    header_testname() above. */
 
 BOOL
-header_testname_incomplete(header_line *h, const uschar *name,
+header_testname_incomplete(const header_line * h, const uschar * name,
     int len, BOOL notdel)
 {
 if (h->type == '*' && notdel) return FALSE;
-if (h->text == NULL || strncmpic(h->text, name, len) != 0) return FALSE;
+if (!h->text || strncmpic(h->text, name, len) != 0) return FALSE;
 return TRUE;
 }
 
index c8899444237137a66418b2a6346eddbf5be20fa1..72f2ac47d87b058027a701c298ce2f2ac2f3809c 100644 (file)
@@ -188,8 +188,8 @@ extern uschar *expand_string(uschar *);
 extern void    header_add(int, const char *, ...);
 extern void    header_add_at_position(BOOL, uschar *, BOOL, int, const char *, ...);
 extern void    header_remove(int, const uschar *);
-extern BOOL    header_testname(header_line *, const uschar *, int, BOOL);
-extern BOOL    header_testname_incomplete(header_line *, const uschar *, int, BOOL);
+extern BOOL    header_testname(const header_line *, const uschar *, int, BOOL);
+extern BOOL    header_testname_incomplete(const header_line *, const uschar *, int, BOOL);
 extern void    log_write(unsigned int, int, const char *format, ...) PRINTF_FUNCTION(3,4);
 extern int     lss_b64decode(uschar *, uschar **);
 extern uschar *lss_b64encode(uschar *, int);
index 77665d89f6d3e3c61ac4d359fcc40248c237e4c8..94fa6d5deb129cd645adc184d2909a6d2677ae8a 100644 (file)
@@ -1230,9 +1230,9 @@ Returns:     nothing
 */
 
 static void
-add_acl_headers(int where, uschar *acl_name)
+add_acl_headers(int where, uschar * acl_name)
 {
-header_line *last_received = NULL;
+header_line * last_received = NULL;
 
 switch(where)
   {
@@ -1254,15 +1254,22 @@ if (acl_removed_headers)
 
   for (header_line * h = header_list; h; h = h->next) if (h->type != htype_old)
     {
-    const uschar * list = acl_removed_headers;
+    const uschar * list = acl_removed_headers, * s;
     int sep = ':';         /* This is specified as a colon-separated list */
-    uschar *s;
 
+    /* If a list element has a leading '^' then it is an RE for
+    the whole header, else just a header name. */
     while ((s = string_nextinlist(&list, &sep, NULL, 0)))
-      if (header_testname(h, s, Ustrlen(s), FALSE))
+      if (  (  *s == '^'
+           && regex_match(
+               regex_must_compile(s, MCS_CACHEABLE, FALSE),
+               h->text, h->slen, NULL)
+            )
+        || header_testname(h, s, Ustrlen(s), FALSE)
+        )
        {
        h->type = htype_old;
-        DEBUG(D_receive|D_acl) debug_printf_indent("  %s", h->text);
+       DEBUG(D_receive|D_acl) debug_printf_indent("  %s", h->text);
        }
     }
   acl_removed_headers = NULL;
index 6ee678899ab61cd0217457866e4c7ab89ced11a9..b85f3b5fe0f00a51cf3eca0fbcef16adfb2a0da4 100644 (file)
@@ -58,6 +58,7 @@ data:
          remove_header = x-data-2
   warn   log_message   = Verified removed header X-Data-3 in this ACL still visible
          condition     = ${if !eq{$h_x-data-3:}{}}
+  warn  remove_header = \N^(?i)Authentication-Results\s*::\s*remove.org;\N
   accept
 
 notsmtp:
index 48d5f3cbe4a3953f1eb42a9edc8f6142b5af9369..e31f56347bb38c35f6295099888c5da77fd0fcc8 100644 (file)
@@ -24,6 +24,9 @@ X-Predata-2: Line nineteen
 X-NotSMTP-1: Line twenty-one
 X-NotSMTP-2: Line twenty-two
 X-NotSMTP-3: Line twenty-three
+Authentication-Results: keep.org; baz barf
+Authentication-Results: keep.org;
+       multiline
 Message-Id: <E10HmaX-0005vi-00@myhost.test.ex>
 From: mailok@test.ex
 Date: Tue, 2 Mar 1999 09:44:33 +0000
index a7a43489a6947c17fc0a218ed1d1b1b2e8772b68..21374436ff244d2726175d3e3711d1c8ad1e1046 100644 (file)
@@ -33,6 +33,12 @@ X-Predata-1: Line twenty
 X-NotSMTP-1: Line twenty-one
 X-NotSMTP-2: Line twenty-two
 X-NotSMTP-3: Line twenty-three
+Authentication-Results: remove.org; foo bar
+Authentication-Results: keep.org; baz barf
+authentication-Results : REMOVE.ORG;
+       foo bar multiline
+Authentication-Results: keep.org;
+       multiline
 
 Test message
 .