[exim] server compromised: "SPA: fail" but uknown spammer is…

トップ ページ
このメッセージを削除
このメッセージに返信
著者: jan.catrysse
日付:  
To: 'Exim-users'
題目: [exim] server compromised: "SPA: fail" but uknown spammer is sending mails anyway. Config issue?
Hello,

I am having an Exim configuration running for years without any issues, but
lately I am seeing my server being abused as a relay.

A few things that are boggling my mind:
It is my understanding that the abuse happens after an SPA authentication
but the SPA authentication has failed. Normally I only allow authenticated
external users.
I don't understand this warning: Warning: ACL "warn" statement skipped:
condition test deferred: Could not complete sender verify callout

Would someone be so kind to take a look at my log and config, here below? I
don't understand very well why this abuse is happening.

Thank you!
Jan

This is an example of what I can find in my logfile. Mind the SPA:fail lines
and the ACL "warn" error.
2021-08-04 15:06:57 no host name found for IP address 93.122.252.1
2021-08-04 15:06:58 H=(213.233.88.90) [93.122.252.1] Warning: HELO
(213.233.88.90) is IP only (See RFC2821 4.1.3)
2021-08-04 15:06:58 H=(213.233.88.90) [93.122.252.1] Warning: HELO
(213.233.88.90) is IP only (See RFC2821 4.1.3)
2021-08-04 15:06:58 H=(213.233.88.90) [93.122.252.1] Warning: HELO
(213.233.88.90) is IP only (See RFC2821 4.1.3)
2021-08-04 15:06:58 H=(213.233.88.90) [93.122.252.1] sender verify fail for
<xfinity@???>: all relevant MX records point to non-existent
hosts
2021-08-04 15:06:58 H=(213.233.88.90) [93.122.252.1]
X=TLS1.2:ECDHE-RSA-AES256-GCM-SHA384:256 CV=no F=<xfinity@???>
A=SPA:fail rejected RCPT <txbutterfly@???>: Sender verify failed
2021-08-04 15:06:58 unexpected disconnection while reading SMTP command from
(213.233.88.90) [93.122.252.1] D=1s
2021-08-04 15:06:58 no host name found for IP address 93.122.252.1
2021-08-04 15:07:00 H=(213.233.88.90) [93.122.252.1] Warning: HELO
(213.233.88.90) is IP only (See RFC2821 4.1.3)
2021-08-04 15:07:01 [66.96.140.174] SSL verify error (during S-verify for
[93.122.252.1]): depth=1 error=self signed certificate in certificate chain
cert=/C=US/O=Sample, Inc./OU=IT Team
20210129161416/OU=bosimpinc03.eigbox.net.eigbox.net/CN=CA
2021-08-04 15:07:01 [66.96.140.174] SSL verify error (during S-verify for
[93.122.252.1]): certificate name mismatch: DN="/C=US/O=Sample, Inc./OU=IT
Team
20210129161416/OU=bosimpinc03.eigbox.net.eigbox.net/CN=bosimpinc03.eigbox.ne
t.eigbox.net" H="mx.easygreenonions.com"
2021-08-04 15:07:02 H=(213.233.88.90) [93.122.252.1] Warning: Sender
(xfinity@???) could not be verified using callout: Sender
verify failed ()
2021-08-04 15:07:03 [103.141.97.82] SSL verify error (during S-verify for
[93.122.252.1]): certificate name mismatch: DN="/CN=*.xserver.jp"
H="tarochan06.com"
2021-08-04 15:07:03 [66.96.140.175] SSL verify error (during S-verify for
[93.122.252.1]): depth=1 error=self signed certificate in certificate chain
cert=/C=US/O=Sample, Inc./OU=IT Team
20210129161416/OU=bosimpinc03.eigbox.net.eigbox.net/CN=CA
2021-08-04 15:07:03 [66.96.140.175] SSL verify error (during S-verify for
[93.122.252.1]): certificate name mismatch: DN="/C=US/O=Sample, Inc./OU=IT
Team
20210129161416/OU=bosimpinc03.eigbox.net.eigbox.net/CN=bosimpinc03.eigbox.ne
t.eigbox.net" H="mx.easygreenonions.com"
2021-08-04 15:07:04 1mBGbw-000GYn-GT Header Message-ID:
<004e07ac4784aea09cc97fd430143e391254b0@???>
2021-08-04 15:07:04 1mBGbw-000GYn-GT Header From:        Xfinity
<xfinity@???>\n
2021-08-04 15:07:04 1mBGbw-000GYn-GT Header Subject:     Important Update\n
2021-08-04 15:07:04 1mBGbw-000GYn-GT Header To:    jsstro@???
2021-08-04 15:07:04 1mBGbw-000GYn-GT <= xfinity@???
H=(213.233.88.90) [93.122.252.1] P=esmtpsa
X=TLS1.2:ECDHE-RSA-AES256-GCM-SHA384:256 CV=no A=SPA:fail S=8666
id=004e07ac4784aea09cc97fd430143e391254b0@??? T="Important
Update" from <xfinity@???> for jsstro@???
2021-08-04 15:07:06 H=(213.233.88.90) [93.122.252.1] Warning: HELO
(213.233.88.90) is IP only (See RFC2821 4.1.3)
2021-08-04 15:07:07 H=(213.233.88.90) [93.122.252.1] Warning: ACL "warn"
statement skipped: condition test deferred: Could not complete sender verify
callout
2021-08-04 15:07:09 [103.141.97.82] SSL verify error (during S-verify for
[93.122.252.1]): certificate name mismatch: DN="/CN=*.xserver.jp"
H="tarochan06.com"
2021-08-04 15:07:10 H=(213.233.88.90) [93.122.252.1] Warning: ACL "warn"
statement skipped: condition test deferred: Could not complete sender verify
callout
2021-08-04 15:07:10 1mBGc2-000GYl-A5 Header Message-ID:
<26f831897db98d0a2986d0848f4b719ab91f403cfc@???>
2021-08-04 15:07:10 1mBGc2-000GYl-A5 Header From:        Xfinity
<xfinity@???>\n
2021-08-04 15:07:10 1mBGc2-000GYl-A5 Header Subject:     Important Update\n
2021-08-04 15:07:10 1mBGc2-000GYl-A5 Header To:    tomnewsom@???
2021-08-04 15:07:10 1mBGc2-000GYl-A5 <= xfinity@???
H=(213.233.88.90) [93.122.252.1] P=esmtpsa
X=TLS1.2:ECDHE-RSA-AES256-GCM-SHA384:256 CV=no A=SPA:fail S=8630
id=26f831897db98d0a2986d0848f4b719ab91f403cfc@??? T="Important
Update" from <xfinity@???> for tomnewsom@???
2021-08-04 15:07:10 1mBGbw-000GYn-GT => jsstro@??? R=dnslookup
T=remote_smtp H=mx2.comcast.net [68.87.20.5] TFO
X=TLS1.2:ECDHE-RSA-AES256-GCM-SHA384:256 CV=dane
DN="/C=US/postalCode=19103/ST=Pennsylvania/L=Philadelphia/street=1 Comcast
Center/O=Comcast Corporation/OU=Business Center/CN=mx2.comcast.net" C="250
2.0.0 BGbymNa8vcIgCBGc1mwY4F mail accepted for delivery"
2021-08-04 15:07:10 1mBGbw-000GYn-GT Completed
<cut some lines>
2021-08-04 15:07:22 1mBGc2-000GYl-A5 => tomnewsom@??? R=dnslookup
T=remote_smtp H=mx1.comcast.net [96.114.157.80] TFO
X=TLS1.2:ECDHE-RSA-AES256-GCM-SHA384:256 CV=dane
DN="/C=US/postalCode=19103/ST=Pennsylvania/L=Philadelphia/street=1 Comcast
Center/O=Comcast Corporation/OU=Business Center/CN=mx1.comcast.net" C="250
2.0.0 BGc3meFVNUMphBGc8mFklE mail accepted for delivery"
2021-08-04 15:07:22 1mBGc2-000GYl-A5 Completed


Config:
primary_hostname = my_local_domain.be

domainlist local_domains = @ : r420.my_local_domain.be : ${tr {${lookup
mysql {\
                        SELECT `domain` FROM `users` WHERE `domain` != '' &&
`domain` IS NOT NULL \
                                    UNION \
                        SELECT `domain` FROM `alias` WHERE `domain` != '' &&
`domain` IS NOT NULL \
                                    UNION \
                        SELECT `domain` FROM `catchall` WHERE `domain` != ''
&& `domain` IS NOT NULL \
                        }}} {"\n"} {:} }


domainlist relay_to_domains =
domainlist fwd_to_pxm_domains = pxm.fr : pxm.com
hostlist relay_from_hosts = localhost : 192.168.0.0/16

acl_not_smtp  = acl_log_message_id
acl_smtp_rcpt = acl_check_rcpt
.ifdef _HAVE_PRDR
    acl_smtp_data_prdr = acl_check_prdr
.endif
acl_smtp_data = acl_check_data
acl_smtp_dkim = acl_check_dkim


.ifndef MAIN_ACL_CHECK_MIME
    MAIN_ACL_CHECK_MIME = acl_check_mime
.endif
acl_smtp_mime = MAIN_ACL_CHECK_MIME


av_scanner = $acl_m0

spamd_address = /var/run/spamd/spamd.sock

tls_advertise_hosts = *

tls_certificate = /etc/ssl/my_local_domain.be/exim/my_local_domain.be.pem

daemon_smtp_ports = 25 : 465 : 587
tls_on_connect_ports = 465

exim_user = mailnull
exim_group = mail
never_users = root
trusted_users = www : fetchmail : dovecot : spamd

host_lookup = *

dns_dnssec_ok = 1

.ifdef _HAVE_PRDR
prdr_enable = true
.endif

log_selector = +smtp_protocol_error +smtp_syntax_error \
               +tls_certificate_verified +address_rewrite +subject \
               +all_parents +received_recipients +received_sender
+tls_cipher \
               +tls_peerdn


ignore_bounce_errors_after = 2d

timeout_frozen_after = 7d

message_size_limit = 100M

keep_environment = ^LDAP
add_environment =
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin

hide srs_secrets = g9H__xxxxxxxxxxxxxxxxxxxx

CHECK_RCPT_SPF = true

dmarc_tld_file = /usr/local/etc/exim/public_suffix_list.dat
dmarc_history_file = /var/spool/exim/opendmarc.dat
dmarc_forensic_sender = do-not-reply@my_local_domain.be

SPAM_FILESIZE_LIMIT = 1M

VIRUS_FILESIZE_LIMIT = 5M

CHECK_RCPT_IP_DNSBLS =
cbl.abuseat.org:zen.spamhaus.org:psbl.surriel.com:b.barracudacentral.org:dns
bl.sorbs.net:spamsources.fabel.dk

begin acl

acl_log_message_id:
    accept  logwrite = Header Message-ID: $h_message-id:
            logwrite = Header From:       $rh_from:
            logwrite = Header Subject:    $rh_subject:
            logwrite = Header To:         $h_to:


acl_check_dkim:
    deny    message        = DKIM fail?
            sender_domains = *
            dkim_signers   = *
            dkim_status    = fail


    deny    message        = DKIM fail?
            sender_domains = gmail.com
            dkim_signers   = gmail.com
            dkim_status    = none:invalid:fail


    accept


acl_check_rcpt:
  accept  hosts           = :
          control         = dkim_disable_verify
          control         = dmarc_disable_verify


  deny    message         = Sender claims to have a local address, but is
neither authenticated nor relayed (try using SMTP-AUTH!)
          log_message     = Forged Sender address (claims to be local user
[${sender_address}], but isn't authenticated)
          !hosts          = +relay_from_hosts
          !authenticated  = *
          condition       = ${if
match_domain{$sender_address_domain}{+local_domains}}


  warn    message         = You cannot be localhost.localdomain in the
internet
          log_message     = HELO is faked as localhost.localdomain
          condition       = ${if
match{$sender_helo_name}{\Nlocalhost\.localdomain\N}}


  warn    message         = X-Invalid-HELO: HELO is IP only (See RFC2821
4.1.3)
          log_message     = HELO ($sender_helo_name) is IP only (See RFC2821
4.1.3)
          condition       = ${if isip{$sender_helo_name}}


  warn    message         = X-Invalid-HELO: HELO is no FQDN (contains no
dot) (See RFC2821 4.1.1.1)
          log_message     = HELO ($sender_helo_name) is no FQDN (contains no
dot) (See RFC2821 4.1.1.1)
          condition       = ${if match{$sender_helo_name}{\N^\[\N}{no}{yes}}
          condition       = ${if match{$sender_helo_name}{\N\.\N}{no}{yes}}


  warn    message         = X-Invalid-HELO: HELO is no FQDN (ends in dot)
(See RFC2821 4.1.1.1)
          log_message     = HELO ($sender_helo_name) is no FQDN (ends in
dot) (See RFC2821 4.1.1.1)
          condition       = ${if match{$sender_helo_name}{\N\.$\N}}


  warn    message         = X-Invalid-HELO: HELO is no FQDN (contains double
dot) (See RFC2821 4.1.1.1)
          log_message     = HELO ($sender_helo_name) is no FQDN (contains
double dot) (See RFC2821 4.1.1.1)
          condition       = ${if match{$sender_helo_name}{\N\.\.\N}}


  warn    message         = X-Invalid-HELO: Host impersonating
[$primary_hostname]
          log_message     = HELO ($sender_helo_name) impersonating
[$primary_hostname]
          !hosts          = 127.0.0.1
          condition       = ${if
match{$sender_helo_name}{$primary_hostname}{yes}{no}}


  warn    message         = X-Invalid-HELO: $interface_address is _my_
address
          log_message     = HELO ($sender_helo_name) uses _my_ address
($interface_address)
          condition       = ${if or{{\


eq{[$interface_address]}{$sender_helo_name}\
                            }{\
                                  eq{$interface_address}{$sender_helo_name}\
                            }}}


  warn    message         = X-Invalid-HELO: no HELO
          log_message     = no HELO ($sender_helo_name)
          condition       = ${if !def:sender_helo_name}


  deny    message         = Restricted characters in address
          domains         = +local_domains
          local_parts     = ^[.] : ^.*[@%!/|]


  deny    message         = Restricted characters in address
          domains         = !+local_domains
          local_parts     = ^[./|] : ^.*[@%!] : ^.*/\\.\\./


  accept  local_parts     = postmaster
          domains         = +local_domains


  accept  condition       = ${lookup mysql{ \
                                  SELECT CONCAT(`username`,'@',`domain`) AS
`email` \
                                  FROM `alias` \
                                  WHERE `username` =
'${quote_mysql:$local_part}' \
                                  AND `domain` = '${quote_mysql:$domain}' \
                                  AND `sendto` LIKE '|%' \
                            }{true}{false}}
          control         = dkim_disable_verify
          control         = dmarc_disable_verify


  deny    message         = [SPF] $sender_host_address is not allowed to
send mail from $sender_address_domain
          log_message     = SPF check failed.
          !authenticated  = *
          hosts           = !+relay_from_hosts
          spf             = fail


  warn    message         = $spf_received


  require verify          = sender


  warn    message         = X-Sender-Verify: FAILED ($sender_verify_failure)
          log_message     = Sender ($sender_address) could not be verified
using callout: $acl_verify_message ($sender_verify_failure)
          !verify         = sender/callout=30s,random


  warn    message         = X-Sender-Verify: SUCCEEDED (sender exists &
accepts mail)
          verify          = sender/callout=30s,random


  accept  authenticated   = *
          control         = submission/sender_retain/domain=
          control         = dkim_disable_verify
          control         = dmarc_disable_verify


  accept  hosts           = +relay_from_hosts
          control         = submission
          control         = dkim_disable_verify
          control         = dmarc_disable_verify


  require message         = nice hosts say HELO first
          condition       = ${if def:sender_helo_name}


  require message         = relay not permitted
          domains         = +local_domains : +relay_to_domains


  require verify          = recipient


  deny message            = ${sender_host_address} is listed at
${dnslist_domain}; See ${dnslist_text}
       !hosts             = +relay_from_hosts
       !authenticated     = *
       dnslists           = CHECK_RCPT_IP_DNSBLS


accept

.ifdef _HAVE_PRDR
acl_check_prdr:
warn set acl_m_did_prdr = y
.endif

accept

acl_check_mime:
  deny
        decode      = default
        condition   = ${if > {$mime_anomaly_level}{2} \
                            {true}{false}}
        message     = This message contains a MIME error
($mime_anomaly_text)
        log_message = DENY: MIME Error ($mime_anomaly_text)


  deny
        condition   = ${if >{$mime_part_count}{1024}{yes}{no}}
        message     = MIME error: Too many parts (max 1024)
        log_message = DENY: MIME Error (Too many MIME parts:
$mime_part_count)


  deny
        regex       = ^.{8000}
        message     = MIME error: Line length in message or single header
exceeds 8000.
        log_message = DENY: MIME Error (Maximum line length exceeded)


  deny
        condition   = ${if eq
{$mime_content_type}{message/partial}{yes}{no}}
        message     = MIME error: MIME type message/partial not allowed here
        log_message = DENY: MIME Error (MIME type message/partial found)


  deny
        condition   = ${if >{${strlen:$mime_filename}}{255}{yes}{no}}
        message     = MIME error: Proposed filename exceeds 255 characters
        log_message = DENY: MIME Error (Proposed filename too long)


  deny
        condition   = ${if >{${strlen:$mime_boundary}}{1024}{yes}{no}}
        message     = MIME error: MIME boundary length exceed 1024
characters
        log_message = DENY: MIME Error (Boundary length too long)


  deny
        condition   = ${if match \
                        {${lc:$mime_filename}} \


{\N(\.bat|\.btm|\.cmd|\.com|\.cpl|\.dll|\.exe|\.lnk|\.msi|\.pif|\.prf|\.reg|
\.scr|\.vbs|\.url)$\N} \
                        {1}{0}}
        message     = Blacklisted file extension detected in
"$mime_filename". If you legitimately need to send these files please zip
them first.
        log_message = DENY: Blacklisted extension ("$mime_filename")


accept

acl_check_data:
  deny    message              = maximum allowed line length is 998 octets,
\
                                 got $max_received_linelength
          condition            = ${if > {$max_received_linelength}{998}}


  deny    !verify              = header_syntax
          message              = header syntax
          log_message          = header syntax ($acl_verify_message)


  warn    dmarc_status         = accept : none : off
          !authenticated       = *
          log_message          = DMARC DEBUG: $dmarc_status for
$dmarc_used_domain
          add_header           = :at_start:${authresults
{$primary_hostname}}


  warn    dmarc_status         = !accept
          !authenticated       = *
          log_message          = DMARC DEBUG: $dmarc_status for
$dmarc_used_domain
          add_header           = :at_start:${authresults
{$primary_hostname}}


  warn    dmarc_status         = quarantine
          !authenticated       = *
          log_message          = DMARC DEBUG: $dmarc_status for
$dmarc_used_domain
          add_header           = :at_start:${authresults
{$primary_hostname}}
          set acl_m_quarantine = 1


  deny    dmarc_status         = reject
          !authenticated       = *
          !hosts               = +relay_from_hosts
          message              = Message from $dmarc_used_domain failed
sender's DMARC policy, REJECT


  warn    set acl_m0           = clamd:/var/run/clamav/clamd.sock
          malware              = *
          message              = This message contains a VIRUS
($malware_name) from $sender_address to $recipients (ClamAV)
          log_message          = warned about VIRUS ($malware_name) from
$sender_address to $recipients (ClamAV)
          remove_header        = Subject
          add_header           = Subject: ***VIRUS***$rh_subject:
          set acl_m0           = clamd:/var/run/clamav/clamd.sock
          condition            = ${if <
{$message_size}{VIRUS_FILESIZE_LIMIT}}


  warn    message              = X-Spam-Score: $spam_score\n\
                                 X-Spam-Score-Int: $spam_score_int\n\
                                 X-Spam-Bar: $spam_bar\n\
                                 X-Spam-Report: $spam_report
          log_message          = spam scanned: $spam_score (Spamassassin)
          !authenticated       = *
          condition            = ${if <
{$message_size}{SPAM_FILESIZE_LIMIT}}
          spam                 = spamd:true


  warn    add_header           = X-Exim-Version: $version_number (build at
$compile_date)\n\
                                 X-Date: $tod_log\n\
                                 X-Connected-IP:
$sender_host_address:$sender_host_port

                        
  warn    add_header           = X-Message-Linecount: $message_linecount\n\
                                 X-Body-Linecount: $body_linecount\n\
                                 X-Message-Size: $message_size\n\
                                 X-Body-Size: $message_body_size\n\
                                 X-Received-Count: $received_count\n\
                                 X-Recipient-Count: $recipients_count\n\
                                 X-Local-Recipient-Count: $rcpt_count\n\
                                 X-Local-Recipient-Defer-Count:
$rcpt_defer_count\n\
                                 X-Local-Recipient-Fail-Count:
$rcpt_fail_count

        
  accept  logwrite              = Header Message-ID: $h_message-id:
          logwrite              = Header From:       $rh_from:
          logwrite              = Header Subject:    $rh_subject:
          logwrite              = Header To:         $h_to:


begin routers
fwd_to_pxm:
driver = manualroute
domains = +fwd_to_pxm_domains
transport = remote_smtp
route_list = * smtp.xxxxxxx.com

dnslookup:
driver = dnslookup
domains = ! +local_domains
transport = remote_smtp
ignore_target_hosts = 0.0.0.0 : 127.0.0.0/8

dnssec_request_domains = *
no_more

mysql_all_domain_alias:
  driver        = redirect
  domains       = +local_domains
  local_parts   = alle
  data          = ${lookup mysql{ \
                        SELECT CONCAT(`username`,'@',`domain`) AS `sendto` \
                        FROM `users` \
                        WHERE `domain` = '${quote_mysql:$domain}' \
                        AND `SMTP_allowed` = 'YES' \
                  }}
  condition     = ${if or {{\
                        def:authenticated_id\
                    }{\
                        eq {$sender_host_address}{127.0.0.1}\
                    }}\
                  }
  file_transport = address_file
  pipe_transport = address_pipe


mysql_alias:
  driver                = redirect
  domains               = +local_domains
  file_transport        = address_file
  pipe_transport        = address_pipe
  data                  = ${if or {{\
                                def:authenticated_id\
                          }{\
                                eq {$sender_host_address}{127.0.0.1}\
                          }}{\
                                ${lookup mysql{ \
                                        SELECT `sendto` \
                                        FROM `alias` \
                                        WHERE ( `username` =
'${quote_mysql:$local_part}' \
                                        AND (`domain` =
'${quote_mysql:$domain}' OR `domain` = '') )}}\
                          } {\
                                ${lookup mysql{ \
                                        SELECT `sendto` \
                                        FROM `alias` \
                                        WHERE ( ( `username` =
'${quote_mysql:$local_part}' AND (`domain` = '${quote_mysql:$domain}' OR
`domain` = '') ) \
                                        AND internal='NO' )}}\
                          }}
  local_part_suffix     = +*
  local_part_suffix_optional
  srs = forward
  srs_dbinsert = ${lookup mysql{INSERT INTO `SRS` (`Key`, `Address`, `Time`)
VALUES ('${srs_db_key}', '${srs_db_address}', NOW())}}
  headers_add = "X-SRS: Sender address rewritten from <$sender_address> by
$primary_hostname."
  debug_print = "R: srs_forward for $local_part@$domain"


mysql_user_condition:
  driver                = accept
  domains               = +local_domains
  caseful_local_part    = true
  condition             = ${if and {{\


                                        eq {${lookup mysql{ \
                                                SELECT
CONCAT(`username`,'@',`domain`) AS `email` \
                                                FROM `users` \
                                                WHERE `username` =
'${quote_mysql:$local_part}' \
                                                AND `domain` =
'${quote_mysql:$domain}' \
                                                AND `SMTP_allowed` = 'YES' \
                                        }{true}{false}}}{true}\
                                   }{\


                                        or {{\


                                                and {{\
                                                        eq
{${sg{$local_part_suffix}{^#([^#]+)#[0-9]\{8\}\$}{\$1}}}{before}\
                                                }{\
                                                        lt
{$tod_logfile}{${sg{$local_part_suffix}{^#[^#]+#([0-9]\{8\})\$}{\$1}}}\
                                                }\
                                           }\
                                           }{\


                                                and {{\
                                                        eq
{${sg{$local_part_suffix}{^#([^#]+)#.*\$}{\$1}}}{fromdomain}\
                                                    }{\
                                                        eq
{$sender_address_domain}{${sg{$local_part_suffix}{^#[^#]+#(.*)\$}{\$1}}}\
                                                    }\
                                                }\
                                           }{\


                                                and {{\
                                                        eq
{${sg{$local_part_suffix}{^#([^#]+)#.*\$}{\$1}}}{b64from}\
                                                    }{\
                                                        eq
{${str2b64:$sender_address}}{${sg{$local_part_suffix}{^#[^#]+#(.*)\$}{\$1}}}
\
                                                    }\
                                                }\
                                           }\
                                        }\
                                   }\
                          }\
                          }
  local_part_suffix     = #*
  transport             = local_mysql_delivery


mysql_user:
  driver                = accept
  domains               = +local_domains
  condition             = ${lookup mysql{ \
                                SELECT CONCAT(`username`,'@',`domain`) AS
`email` \
                                FROM `users` \
                                WHERE `username` =
'${quote_mysql:$local_part}' \
                                AND `domain` = '${quote_mysql:$domain}' \
                                AND `SMTP_allowed` = 'YES' \
                          }{true}{false}}
  local_part_suffix     = +*
  local_part_suffix_optional
  transport             = local_mysql_delivery
  no_more


mysql_catchall:
  driver                = redirect
  domains               = +local_domains
  file_transport        = address_file
  pipe_transport        = address_pipe
  data                  = ${lookup mysql{ \
                                SELECT `sendto` \
                                FROM `catchall` \
                                WHERE `domain` = '${quote_mysql:$domain}' \
                          }}
  srs = forward
  srs_dbinsert = ${lookup mysql{INSERT INTO `SRS` (`Key`, `Address`, `Time`)
VALUES ('${srs_db_key}', '${srs_db_address}', NOW())}}
  headers_add = "X-SRS: Sender address rewritten from <$sender_address> by
$primary_hostname."
  debug_print = "R: srs_forward for $local_part@$domain"


system_aliases:
driver = redirect
allow_fail
allow_defer
data = ${lookup{$local_part}lsearch{/etc/aliases}}
user = mailnull
group = mail
file_transport = address_file
pipe_transport = address_pipe
srs = forward
srs_dbinsert = ${lookup mysql{INSERT INTO `SRS` (`Key`, `Address`, `Time`)
VALUES ('${srs_db_key}', '${srs_db_address}', NOW())}}
headers_add = "X-SRS: Sender address rewritten from <$sender_address> by
$primary_hostname."
debug_print = "R: srs_forward for $local_part@$domain"

userforward:
driver = redirect
check_local_user
file = $home/.forward
no_verify
no_expn
check_ancestor
file_transport = address_file
pipe_transport = address_pipe
reply_transport = address_reply
condition = ${if exists{$home/.forward} {yes} {no}}
srs = forward
srs_dbinsert = ${lookup mysql{INSERT INTO `SRS` (`Key`, `Address`, `Time`)
VALUES ('${srs_db_key}', '${srs_db_address}', NOW())}}
headers_add = "X-SRS: Sender address rewritten from <$sender_address> by
$primary_hostname."
debug_print = "R: srs_forward for $local_part@$domain"

localuser:
driver = accept
check_local_user
transport = local_delivery
cannot_route_message = Unknown user

srs_router:
driver = redirect
srs = reverseandforward
srs_dbinsert = ${lookup mysql{INSERT INTO `SRS` (`Key`, `Address`, `Time`)
VALUES ('${srs_db_key}', '${srs_db_address}', NOW())}}
srs_dbselect = ${lookup mysql{SELECT `Address` FROM `SRS` WHERE `Key` =
'${srs_db_key}' AND `Time` > SUBDATE(NOW(), INTERVAL 1 month) LIMIT 1}}
data = ${srs_recipient}

begin transports

remote_smtp:
driver = smtp
message_size_limit = ${if > {$max_received_linelength}{998} {1}{0}}
headers_remove = X-Spam-Flag : X-Spam-Score-Int : X-Spam-Score :
X-Spam-Bar : X-Spam-Report : X-Sender-Verify : X-Warning :
X-Message-Linecount : X-Body-Linecount : X-Message-Size : X-Body-Size :
X-Received-Count : X-Recipient-Count : X-Local-Recipient-Count :
X-Local-Recipient-Defer-Count : X-Local-Recipient-Fail-Count
dkim_domain =
${lookup{$sender_address_domain.private.pem}dsearch{/usr/local/etc/exim/dkim
_keys}{$sender_address_domain}{}}
dkim_private_key =
/usr/local/etc/exim/dkim_keys/${lookup{$sender_address_domain.private.pem}ds
earch{/usr/local/etc/exim/dkim_keys}}
dkim_selector = exim
dkim_canon = relaxed
dkim_strict = false

.ifdef _HAVE_DANE
dnssec_request_domains = *
hosts_try_dane = *
.endif
.ifdef _HAVE_PRDR
hosts_try_prdr = *
.endif

smarthost_smtp:
driver = smtp
message_size_limit = ${if > {$max_received_linelength}{998} {1}{0}}
multi_domain

.ifdef _HAVE_TLS
hosts_require_tls = *
tls_verify_hosts = *
tls_try_verify_hosts = *
tls_sni = ROUTER_SMARTHOST
.ifdef _HAVE_OPENSSL
tls_require_ciphers = HIGH:!aNULL:@STRENGTH
.endif
.ifdef _HAVE_GNUTLS
tls_require_ciphers = SECURE192:-VERS-SSL3.0:-VERS-TLS1.0:-VERS-TLS1.1
.endif
.endif
.ifdef _HAVE_PRDR
hosts_try_prdr = *
.endif

local_delivery:
driver = appendfile
file = /var/mail/$local_part
delivery_date_add
envelope_to_add
return_path_add
group = mail
user = $local_part
mode = 0660
no_mode_fail_narrower

address_pipe:
driver = pipe
return_output

address_file:
driver = appendfile
delivery_date_add
envelope_to_add
return_path_add

address_reply:
driver = autoreply

local_mysql_delivery:
  debug_print = "T: dovecot LMTP for $local_part@$domain"
  driver = lmtp
  socket = /var/run/dovecot/lmtp
  batch_max = 200
  headers_remove = Subject : X-Spam-Flag : X-Spam-Score-Int : X-Spam-Score :
X-Spam-Bar : X-Spam-Report
  headers_add   = "X-Spam-Threshold: ${lookup mysql{ \
                        SELECT spam_threshold \
                    FROM users \
                    WHERE username='${quote_mysql:$local_part}' \
                    AND domain='${quote_mysql:$domain}' \
                    AND SMTP_allowed='YES' \
                      }{$value}{ERROR}}\n\
          X-Spam-Score: $header_X-Spam-Score:\n\
          X-Spam-Score-Int: $header_X-Spam-Score-Int:\n\
          X-Spam-Bar: $header_X-Spam-Bar:\n\
          X-Spam-Report: $header_X-Spam-Report:\n\
                  X-Spam-Flag: ${if def:header_X-Spam-Score-Int:{\
                    ${if >={$header_X-Spam-Score-Int:}\
                        {${lookup mysql{ \
                            SELECT spam_threshold*10 \
                            FROM users \
                            WHERE username='${quote_mysql:$local_part}' \
                            AND domain='${quote_mysql:$domain}' \
                            AND SMTP_allowed='YES' \
                        }{$value}{ERROR}}}{YES}{NO}}\
                    }{\
                    UNKNOWN\
                }}\n\
          Subject: ${if def:header_X-Spam-Score-Int:{\
                    ${if >={$header_X-Spam-Score-Int:}\
                        {${lookup mysql{ \
                            SELECT spam_threshold*10 \
                            FROM users \
                            WHERE username='${quote_mysql:$local_part}' \
                            AND domain='${quote_mysql:$domain}' \
                            AND SMTP_allowed='YES' \
                        }{$value}{ERROR}}}{${lookup mysql{ \
                                    SELECT spam_tag \
                                    FROM users \
                                    WHERE
username='${quote_mysql:$local_part}' \
                                    AND domain='${quote_mysql:$domain}' \
                                    AND SMTP_allowed='YES' \


}{$value}{ERROR}}$rh_subject:}{$rh_subject:}}\
                }{$rh_subject:}}\n\
          X-Delivered-To: $original_local_part@$original_domain
($local_part@$domain)\n\
          X-Message-Age: $message_age"


begin retry

*                      *           F,2h,15m; G,16h,1h,1.5; F,4d,6h


begin rewrite

begin authenticators

PLAIN:
  driver                        = plaintext
  public_name                   = PLAIN
  server_prompts                = :
  server_advertise_condition    = ${if def:tls_cipher}
  server_condition              = ${if eq {$auth3}{${lookup mysql{ SELECT
`password` FROM `users` WHERE CONCAT_WS('@', `username`, `domain`) =
'${quote_mysql:$auth2}' AND `SMTPAUTH_allowed` = 'YES'}}}{yes}{no}}
  server_set_id                 = $auth2
  server_debug_print            = "Running PLAIN auth: $auth2 | $auth3"


LOGIN:
  driver                        = plaintext
  public_name                   = LOGIN
  server_prompts                = <| Username: | Password:
  server_advertise_condition    = ${if def:tls_cipher}
  server_condition              = ${if eq {$auth2}{${lookup mysql{SELECT
`password` FROM `users` WHERE CONCAT_WS('@', `username`, `domain`) =
'${quote_mysql:$auth1}' AND `SMTPAUTH_allowed` = 'YES'}}}{yes}{no}}
  server_set_id                 = $auth1
  server_debug_print            = "Running LOGIN auth: $auth1 | $auth2"


CRAM:
  driver             = cram_md5
  public_name        = CRAM-MD5
  server_secret      = ${lookup mysql{SELECT `password` FROM `users` WHERE
CONCAT_WS('@', `username`, `domain`) = '${quote_mysql:$auth1}' AND
`SMTPAUTH_allowed` = 'YES';}{$value}{fail}}
  server_set_id      = $auth1
  server_debug_print = "Running CRAM-MD5 auth: $auth1"


SPA:
  driver             = spa
  public_name        = NTLM
  server_password    = ${lookup mysql{SELECT `password` FROM `users` WHERE
CONCAT_WS('@', `username`, `domain`) = '${quote_mysql:$auth1}' AND
`SMTPAUTH_allowed` = 'YES' AND '${quote_mysql:$auth1}' !=
'';}{$value}{fail}}
  server_set_id      = $auth1
  server_debug_print = "Running SPA auth: $auth1"