Re: [exim] Emails starting with a byte order mark (BOM)

Top Page
Delete this message
Reply to this message
Author: Michael Fischer v. Mollard
Date:  
To: exim-users
Subject: Re: [exim] Emails starting with a byte order mark (BOM)
On 27.02.2014 10:33, Michael Fischer v. Mollard wrote:
>
>
> -- Am 02/26/14 14:02:08 +0100 schrieb Wolfgang Breyha:
>
>> Jan Ingvoldstad wrote, on 26/02/14 13:45:
>>> Perhaps it would be relevant to check for other byte order marks as
>>> well:
>>>
>>> http://en.wikipedia.org/wiki/Byte_order_mark#Representations_of_byte_ord
>>>
>>> er_marks_by_encoding
>>
>> I crosschecked with my cyrus logs ("invalid header characters")
>> meanwhile
>> and blocking only the UTF8 BOM seems to catch them all upfront. It looks
>> like a broken script spamming from several hacked webhosts.
>>
>> currently I use
>>   # check for UTF-8 BOM (coming from SPAM)
>>   warn    condition   = ${if
>> match{$message_headers_raw}{\N\xEF\xBB\xBF\N}} control     =
>> freeze/no_tell
>>           log_message = BOM detected
>> to get some more samples.

>>
>> Will change that to
>>   deny    condition   = ${if
>> match{$message_headers_raw}{\N\xEF\xBB\xBF\N}} message     =
>> Headers contain illegal BOM
>>           log_message = BOM detected
>> later.

>
> Hi,
>
> that's a good idea. Thanks a lot.
>
> But nevertheless it might be a good idea to block 8 bit characters in
> header names via an ACL test as even RFC 6532 does not allow that.
>


Hello,

I attached a patch which implements a „verify = header_names“ test as
suggested above. At least it should be useful to users of cyrus imapd as
cyrus won't accept such mails.

Michael

diff --git a/src/src/acl.c b/src/src/acl.c
index 29e0617..eb9b962 100644
--- a/src/src/acl.c
+++ b/src/src/acl.c
@@ -1650,7 +1650,7 @@ switch (dns_lookup(&dnsa, target, type, NULL))
*************************************************/

 enum { VERIFY_REV_HOST_LKUP, VERIFY_CERT, VERIFY_HELO, VERIFY_CSA, VERIFY_HDR_SYNTAX,
-  VERIFY_NOT_BLIND, VERIFY_HDR_SNDR, VERIFY_SNDR, VERIFY_RCPT
+       VERIFY_NOT_BLIND, VERIFY_HDR_SNDR, VERIFY_SNDR, VERIFY_RCPT,VERIFY_HDR_NAMES
   };
 typedef struct {
   uschar * name;
@@ -1670,7 +1670,8 @@ static verify_type_t verify_type_list[] = {
     { US"sender",          VERIFY_SNDR,        (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)
             |(1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP),
                                         FALSE, 6 },
-    { US"recipient",          VERIFY_RCPT,         (1<<ACL_WHERE_RCPT),    FALSE, 0 }
+    { US"recipient",          VERIFY_RCPT,         (1<<ACL_WHERE_RCPT),    FALSE, 0 },
+    { US"header_names",            VERIFY_HDR_NAMES,     (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP), TRUE, 0 }
   };



@@ -1820,6 +1821,15 @@ switch(vp->value)
       *user_msgptr = string_sprintf("Rejected after DATA: %s", *log_msgptr);
     return rc;


+  case VERIFY_HDR_NAMES:
+    /* Check that all header names are true 7 bit strings 
+    See RFC 5322, 2.2. and RFC 6532, 3. */
+
+    rc = verify_check_header_names(log_msgptr);
+    if (rc != OK && smtp_return_error_details && *log_msgptr != NULL)
+      *user_msgptr = string_sprintf("Rejected after DATA: %s", *log_msgptr);
+    return rc;
+
   case VERIFY_NOT_BLIND:
     /* Check that no recipient of this message is "blind", that is, every envelope
     recipient must be mentioned in either To: or Cc:. */
@@ -2202,7 +2212,7 @@ return rc;


BAD_VERIFY:
*log_msgptr = string_sprintf("expected \"sender[=address]\", \"recipient\", "
- "\"helo\", \"header_syntax\", \"header_sender\" or "
+ "\"helo\", \"header_syntax\", \"header_sender\", \"header_names\" or "
"\"reverse_host_lookup\" at start of ACL condition "
"\"verify %s\"", arg);
return ERROR;
diff --git a/src/src/verify.c b/src/src/verify.c
index 711b3af..b77af03 100644
--- a/src/src/verify.c
+++ b/src/src/verify.c
@@ -2155,6 +2155,41 @@ return yield;
}


+/*************************************************
+*      Check header names for 8-bit characters   *
+*************************************************/
+
+/* This function checks for invalid charcters in header names. See
+RFC 5322, 2.2. and RFC 6532, 3.
+
+Arguments:
+  msgptr     where to put an error message
+
+Returns:     OK
+             FAIL
+*/
+
+int
+verify_check_header_names(uschar **msgptr)
+{
+header_line *h;
+uschar *colon, *s;
+
+for (h = header_list; h != NULL; h = h->next)
+  {
+   colon = Ustrchr(h->text, ':');
+   for(s = h->text; s < colon; s++)
+     {
+        if ((*s < 33) || (*s > 126)) 
+        {
+                *msgptr = string_sprintf("Invalid character in header \"%.*s\" found",
+                                         colon - h->text, h->text);
+                return FAIL;
+        }
+     }
+  }
+return OK;
+}


 /*************************************************
 *          Check for blind recipients            *