### Global settings.
SECTION(global, priv)m4_dnl
-admin_groups = root : adm
+admin_groups = CONF_admin_groups
prod_requires_admin = false
SECTION(global, logging)m4_dnl
SECTION(global, incoming)m4_dnl
received_header_text = Received: \
- ${if def:sender_rcvhost {from $sender_rcvhost\n\t} \
+ ${if def:sender_rcvhost \
+ {from $sender_rcvhost\n\t} \
{${if def:sender_ident \
- {from ${quote_local_part:$sender_ident} }}\
- ${if def:sender_helo_name \
- {(helo=$sender_helo_name)\n\t}}}}\
+ {from ${quote_local_part:$sender_ident} }}}}\
by $primary_hostname \
(Exim $version_number)\
${if def:tls_cipher {\n\t} { }}\
{with $received_protocol \
${if def:tls_cipher {(cipher=$tls_cipher)}}}}\n\t\
${if def:sender_address \
- {(envelope-from <$sender_address>\
+ {(envelope-from $sender_address\
${if def:authenticated_id \
{; auth=$authenticated_id}})\n\t}}\
id $message_exim_id\
SECTION(global, bounce)m4_dnl
delay_warning = 1h : 24h : 2d
+SECTION(global, tls)m4_dnl
+tls_certificate = CONF_sysconf_dir/server.cert
+tls_privatekey = CONF_sysconf_dir/server.key
+tls_advertise_hosts = ${if exists {CONF_sysconf_dir/server.key} {*}{}}
+tls_dhparam = CONF_ca_dir/dh-param-2048.pem
+tls_require_ciphers = ${if or {{={$received_port}{CONF_submission_port}} \
+ {match_ip {$sender_host_address}{+trusted}}} \
+ {CONF_good_ciphers} \
+ {CONF_acceptable_ciphers}}
+tls_verify_certificates = CONF_ca_dir/ca.cert
+tls_verify_hosts = ${if eq{$acl_c_mode}{submission} {} {+allnets}}
+
DIVERT(null)
###--------------------------------------------------------------------------
### Access control lists.
acl_smtp_helo = helo
SECTION(acl, misc)m4_dnl
helo:
- require message = The other one has bells on
- verify = helo
+ ## Check that the caller's claimed identity is actually plausible.
+ ## This seems like it's a fairly effective filter on spamminess, but
+ ## it's too blunt a tool. Rather than reject, add a warning header.
+ ## Only we can't do this the easy way, so save it up for use in MAIL.
+ ## Also, we're liable to get a subsequent HELO (e.g., after STARTTLS)
+ ## and we should only care about the most recent one.
+ warn set acl_c_helo_warning = false
+ !condition = \
+ ${if and {{match_ip {$sender_host_address} \
+ {<; 127.0.0.0/8 ; ::1}} \
+ {match_domain {$sender_helo_name} \
+ {localhost : +thishost}}}}
+ !condition = \
+ ${if exists {CONF_sysconf_dir/helo.conf} \
+ {${lookup {$sender_helo_name} \
+ partial0-lsearch \
+ {CONF_sysconf_dir/helo.conf} \
+ {${if match_ip \
+ {$sender_host_address} \
+ {$value}}}}}}
+ !verify = helo
+ set acl_c_helo_warning = true
+
+ accept
+SECTION(global, acl)m4_dnl
+acl_not_smtp_start = not_smtp_start
+SECTION(acl, misc)m4_dnl
+not_smtp_start:
+ ## Record the user's name.
+ warn set acl_c_user = $sender_ident
+
+ ## Done.
accept
SECTION(global, acl)m4_dnl
SECTION(acl, mail)m4_dnl
mail:
+ ## If we stashed a warning header about HELO from earlier, we should
+ ## add it now.
+ warn condition = $acl_c_helo_warning
+ add_header = :after_received:X-Distorted-Warning: \
+ BADHELO \
+ Client's HELO doesn't match its IP address.\n\t\
+ helo-name=$sender_helo_name \
+ address=$sender_host_address
+
## Always allow the empty sender, so that we can receive bounces.
accept senders = :
warn condition = ${if eq{$acl_c_mode}{submission}}
control = submission
+ ## Insist that a local client connect through TLS.
+ deny message = Hosts within CONF_master_domain must use TLS
+ !condition = ${if eq{$acl_c_mode}{submission}}
+ hosts = +allnets
+ !encrypted = *
+
+ ## Check that a submitted message's sender address is allowable.
+ require acl = mail_check_auth
+
SECTION(acl, mail-tail)m4_dnl
## And we're done.
accept
check_submission:
## See whether this message needs hacking on.
- accept !hosts = +localnet
+ accept !hosts = +thishost
!condition = ${if ={$received_port}{CONF_submission_port}}
set acl_c_mode = relay
## Reject if the client isn't allowed to relay and the recipient
## isn't in one of our known domains.
- deny message = Relaying not permitted
- !hosts = CONF_relay_clients
- !authenticated = *
- !domains = +known
+ require message = Relaying not permitted
+ acl = check_relay
## Ensure that the recipient is routable.
require message = Invalid recipient \
($recipient_verify_failure; $acl_verify_message)
verify = recipient
+SECTION(acl, misc)m4_dnl
+check_relay:
+ ## Accept either if the client is allowed to relay through us, or if
+ ## we're the correct place to send this mail.
+
+ ## Known clients and authenticated users are OK.
+ accept hosts = CONF_relay_clients
+ accept authenticated = *
+
+ ## Known domains are OK.
+ accept domains = +public
+
+ ## Finally, domains in our table are OK, unless they say they aren't.
+ accept domains = \
+ ${if exists{CONF_sysconf_dir/domains.conf} \
+ {partial0-lsearch; CONF_sysconf_dir/domains.conf}}
+ condition = DOMKV(service, {$value}{true})
+
+ ## Nope, that's not allowed.
+ deny
+
SECTION(acl, rcpt-tail)m4_dnl
## Everything checks out OK: let this one go through.
accept
accept hosts = +trusted
deny message = Suck it and see
+DIVERT(null)
+###--------------------------------------------------------------------------
+### Verification of sender address.
+
+SECTION(acl, misc)m4_dnl
+mail_check_auth:
+
+ ## If this isn't a submission then it doesn't need checking.
+ accept condition = ${if !eq{$acl_c_mode}{submission}}
+
+ ## If the caller hasn't formally authenticated, but this is a
+ ## loopback connection, then we can trust identd to tell us the right
+ ## answer. So we should stash the right name somewhere consistent.
+ warn set acl_c_user = $authenticated_id
+ hosts = +thishost
+ !authenticated = *
+ condition = ${if def:sender_ident}
+ set acl_c_user = $sender_ident
+
+ ## User must be authenticated by now.
+ deny message = Sender not authenticated
+ condition = ${if !def:acl_c_user}
+
+ ## Make sure that the local part is one that the authenticated sender
+ ## is allowed to claim.
+ deny message = Sender address forbidden to calling user
+ !condition = \
+ ${if exists {CONF_sysconf_dir/auth-sender.conf} \
+ {${lookup {$acl_c_user} \
+ lsearch \
+ {CONF_sysconf_dir/auth-sender.conf} \
+ {${if match_address \
+ {$sender_address} \
+ {+value}}} \
+ {false}}}}
+ !condition = ${LOOKUP_DOMAIN($sender_address_domain,
+ {${if and {{match_local_part \
+ {$acl_c_user} \
+ {+dom_users}} \
+ {match_local_part \
+ {$sender_address_local_part} \
+ {+dom_locals}}}}},
+ {${if and {{match_local_part \
+ {$sender_address_local_part} \
+ {+user_extaddr}} \
+ {or {{eq {$sender_address_domain} \
+ {}} \
+ {match_domain \
+ {$sender_address_domain} \
+ {+public}}}}}}})}
+
+ ## All done.
+ accept
+
DIVERT(null)
###--------------------------------------------------------------------------
### Common options for forwarding routers.
pipe_transport = pipe
reply_transport = reply:>)
+m4_define(<:FILTER_ROUTER:>,
+<:$1_vrf:
+ $2
+ FILTER_VERIFY<::>$3
+$1:
+ $2
+ verify = no
+ FILTER_TRANSPORTS<::>$4:>)
+
DIVERT(null)
###--------------------------------------------------------------------------
### Some standard transports.
return_path_add = true:>)
SECTION(transports)m4_dnl
-## A standard transport for remote delivery. Try to do TLS, and don't worry
-## too much if it's not very secure: the alternative is sending in plaintext
-## anyway.
+## 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
+## in plaintext anyway. But all of this can be overridden from the
+## `domains.conf' file. Annoyingly, the `tls_dh_min_bits' setting isn't
+## expanded before use, so we can't set it the obvious way. Instead, encode
+## it into the transport name. This is very unpleasant, of course.
smtp:
driver = smtp
tls_require_ciphers = CONF_acceptable_ciphers
tls_dh_min_bits = 1020
tls_tempfail_tryclear = true
+m4_define(<:SMTP_TRANS_DHBITS:>,
+ <:driver = smtp
+ hosts_try_auth = *
+ hosts_require_tls = DOMKV(tls-peer-ca, {*}{})
+ hosts_require_auth = \
+ ${if bool {DOMKV(require-auth, {$value}{false})} {*}{}}
+ tls_certificate = DOMKV(tls-certificate, {${expand:$value}}fail)
+ tls_privatekey = DOMKV(tls-private-key, {${expand:$value}}fail)
+ tls_verify_certificates = DOMKV(tls-peer-ca, {${expand:$value}}fail)
+ tls_require_ciphers = \
+ DOMKV(tls-ciphers,
+ {${extract {${expand:$value}} \
+ { good = CONF_good_ciphers \
+ any = CONF_acceptable_ciphers } \
+ {$value} \
+ {${expand:$value}}}} \
+ {CONF_acceptable_ciphers})
+ tls_dh_min_bits = $1
+ tls_tempfail_tryclear = true:>)m4_dnl
+smtp_dhbits_1024:
+ SMTP_TRANS_DHBITS(1020)
+smtp_dhbits_2048:
+ SMTP_TRANS_DHBITS(2046)
+
## Transport to a local SMTP server; use TLS and perform client
## authentication.
smtp_local:
tls_privatekey = CONF_sysconf_dir/client.key
tls_verify_certificates = CONF_ca_dir/ca.cert
tls_require_ciphers = CONF_good_ciphers
- tls_dh_min_bits = 3070
+ tls_dh_min_bits = 2046
tls_tempfail_tryclear = false
authenticated_sender = ${if def:authenticated_id \
- ${authenticated_id@CONF_master_domain} \
+ {$authenticated_id@CONF_master_domain} \
fail}
## A standard transport for local delivery.