Re: [exim] Testing sender and recipient domains in MIME ACL

Top Page
Delete this message
Reply to this message
Author: Mike Tubby
Date:  
To: exim-users
Subject: Re: [exim] Testing sender and recipient domains in MIME ACL


On 27/05/2020 20:58, Jeremy Harris via Exim-users wrote:
> On 26/05/2020 07:53, Mike Tubby via Exim-users wrote:
>> I need to make business logic decisions in the MIME ACL on how to screen
>> MIME content based on the sender domain and recipient domain
> The message could have multiple recipients, having different domains.
> Therefore, in general, the recipient domain is not well-defined in
> any ACL apart from the RCPT ACL.


I hadn't considered the issue w.r.t. multiple recipients to be honest
... but my primary interest is the sender address as its the sender
domain that I want to whitelist.

So I can do things like no ZIP files unless sender's domain is
"special_customer.com".


>
> If you have coded the RCPT ACL to enforce single-recipient messages
> (destroying the efficiency of SMTP), by deferring and after the first,
> then you could use ${domain:$recipients}. You could do slightly better
> by permitting multiple recipients of a single recipient domain, but
> then you'd have to pick off the first one:
> ${domain:${extract {1}{,}{$recipients}}}


I was hoping to use the $sender_address / $sender_address_domain  to
drive MIME checking business logic in the MIME ACL.


Right now I' doing this in the RCPT ACL:

acl_check_rcpt:

        #
        # Check if sender is whitelisted to disable MIME content checks, if
        # so remember in a macro here for use in the MIME ACL later
        #
        warn    set acl_m0      = 1
                sender_domains  = +whitelist_sender_domains
                logwrite        = RCPT: Sender $sender_address is
whitelisted disabling MIME content checks

        warn    set acl_m0      = 0
                sender_domains  = ! +whitelist_sender_domains
                logwrite        = RCPT: Sender $sender_address is not
whitelisted - MIME checks enabled

        #
        # Accept mail to postmaster in any local domain without
verifying the sender
        #
        accept  local_parts     = postmaster
                domains         = +local_domains
                logwrite        = RCPT: Accept postmaster always

        ...    ...    ...


where whitelist_sender_domains is a domain list from MySQL:

    #
    # whitelist_sender_domains - domains that are always allowed to
send to us, i.e. skip content checks
    #
    domainlist whitelist_sender_domains = ${lookup mysql{SELECT domain
FROM whitelist_sender_domains WHERE active='1'}{${sg{$value}{\\n}{ : }} }}


and this in the MIME ACL:


acl_check_mime:

        #
        # Debugging... ACL variable $acl_m0 = 1 if the sender address
is whitelisted to
        # skip content or 0 for normal content checking
        #
        warn    condition = ${if ={$acl_m0}{0}{true}{false}}
                log_message = MIME: Content checks performed as sender
domain not whitelisted

        #
        # Accept mail if macro m1 is true - set in RCPT processing for
        # whitelisted senders as we cannot test $sender_address here!
        #
        accept  condition = ${if ={$acl_m0}{1}{true}{false}}
                log_message = MIME: Content checks skipped as sender
domain whitelisted

        #
        # Decode MIME parts to disk. This will support virus scanners
later.
        #
        deny    decode      = default
                condition   = ${if > {$mime_anomaly_level}{2}{true}{false}}
                message     = This message contains a MIME error
($mime_anomaly_text)
                log_message = MIME: Error in MIME attachment:
$mime_anomaly_text

        #
        # Too many MIME parts
        #
        deny    condition   = ${if >{$mime_part_count}{200}{yes}{no}}
                message     = Too many MIME encoded parts in message
                log_message = MIME: Too many MIME parts:
$mime_part_count max: 200

        #
        # Excessive line length
        #
        deny    regex       = ^.{8000}
                message     = Line length in MIME message is too long
                log_message = MIME: Maximum line length exceeded (8000
chars)

        #
        # Partial message
        #
        deny    condition   = ${if eq
{$mime_content_type}{message/partial}{yes}{no}}
                message     = MIME type message/partial not allowed
                log_message = MIME type message/partial not allowed

        #
        # Filename length too short ( < 3 characters)
        #
        deny    condition   = ${if def:mime_filename {1}{0}}
                condition   = ${if <{${strlen:$mime_filename}}{3}{yes}{no}}
                message     = MIME attachment filename less than 3
characters
                log_message = MIME: File name is too short (min 3 chars)

        #
        # Filename length too long ( > 255 characters)
        #
        deny    condition   = ${if def:mime_filename {1}{0}}
                condition   = ${if
>{${strlen:$mime_filename}}{255}{yes}{no}}

                message     = MIME attachment filename exceeds 255
characters
                log_message = MIME: File name is too long (max 255 chars)

        #
        # MIME boundary length too long (> 1024)
        #
        deny    condition   = ${if
>{${strlen:$mime_boundary}}{1024}{yes}{no}}

                message     = MIME boundary length exceed 1024 characters
                log_message = MIME: boundary length too long (max 1024)

        #
        # debugging ...
        #
        warn    condition = ${if def:mime_filename {1}{0}}
                log_message = MIME: Check MIME filename: $mime_filename

        #
        # Check MIME filename/extension against the database blacklist, but
        # only if the $mime_filename is set - won't be set for inline
        #
        deny    condition = ${if def:mime_filename {1}{0}}
                condition = ${lookup mysql{SELECT file_extension FROM
blacklist_file_extensions \
                        WHERE
file_extension=SUBSTRING_INDEX(LCASE('${quote_mysql:$mime_filename}'),
".", -1) \
                        AND active=1}{yes}{no}}
                message = MIME filename/extension $mime_filename not
acceptable here
                log_message = MIME: Rejected attachment $mime_filename
(bad file extension)

        #
        # debugging ...
        #
        warn    condition = ${if def:mime_content_type {1}{0}}
                log_message = MIME: Check MIME content-type:
$mime_content_type

        #
        # Check MIME content type against the database blacklist
        #
        deny    condition = ${if def:mime_content_type {1}{0}}
                condition = ${lookup mysql{SELECT mime_type FROM
blacklist_file_extensions \
                        WHERE
mime_type='${quote_mysql:$mime_content_type}' \
                        AND active=1}{yes}{no}}
                message = MIME content type $mime_content_type not
acceptable here
                log_message = MIME: Rejected MIME content type:
$mime_content_type

        #
        # accept if we get here
        #
        accept


The debugging bits are temporary while I watch the affect of my ACLs on
traffic



Mike