Exim4 already does some standard checks on the envelope sender, From: and Sender: of the locally submitted messages (cf. trusted users). Since you want to extend this validation you should:
For messages submitted through sendmail (i.e. exim4 -bm), add to the main configuration section:
# allow untrusted users to set an envelope sender
untrusted_set_sender = *
# don't delete the Sender: header
local_sender_retain = true
# don't add Sender: header
local_from_check = false
For messages submitted through SMTP you need to add the control = submission/sender_retain modifier. E.g. Debian has in the MAIL acl a rule:
accept
authenticated = *
control = submission/sender_retain
control = dkim_disable_verify
To configure your check you need to add a couple of ACL rules at different stages of mail processing. Since these rules need to be applied to different ways of message submission you can create a new named ACL (I assume that all your /etc/exim4/virtual/<domain> files return username@localhost as value):
# Requires system user id in $acl_arg1
acl_check_sender:
# Users with default domain
accept
condition = ${if eq{$sender_address}{$acl_arg1@$qualify_domain}}
condition = ${if eq{${address:$h_from:}}{$acl_arg1@$qualify_domain}}
condition = ${if match_address{${address:$h_sender:}}{:$acl_arg1@$qualify_domain}}
deny
! condition = ${if and{\
{exists{/etc/exim4/virtual/${domain:${address:$h_from:}}}}\
{eq {${acl_arg1}@localhost}\
{${lookup {${local_part:${address:$h_from:}}}\
lsearch{/etc/exim4/virtual/${domain:${address:$h_from:}}}\
}}\
}\
}}
message = Spoofed From: header.
# Most messages don't have a Sender: header, but if it is not empty, check it.
deny
! condition = ${if or{\
{eq {$h_sender:}{}}\
{and{\
{exists{/etc/exim4/virtual/${domain:${address:$h_sender:}}}}\
{eq {${acl_arg1}@localhost}\
{${lookup {${local_part:${address:$h_sender:}}}\
lsearch{/etc/exim4/virtual/${domain:${address:$h_sender:}}}\
}}\
}\
}}\
}}
message = Spoofed Sender: header.
deny
! condition = ${if and{\
{exists{/etc/exim4/virtual/$sender_address_domain}}\
{eq {${acl_arg1}@localhost}\
{${lookup {$sender_address_local_part}\
lsearch{/etc/exim4/virtual/$sender_address_domain}\
}}\
}\
}}
message = Spoofed envelope sender.
accept
For the syntax of string expansion (quite full of braces), check chapter 11 of Exim's documentation. You can use exim4 -bem <message> <expansion_string> to test them (the envelope sender is passed in the message like the mbox format).
You can apply it to different situations:
For messages submitted through exim4 -bm, add to the acl_not_smtp ACL the following rule:
deny
! acl = acl_check_sender ${sender_ident}
For messages submitted by authenticated users through SMTP add to the acl_smtp_data ACL something like:
deny
authenticated = *
! acl = acl_check_sender ${authenticated_id}
Some programs submit messages using a non-authenticated SMTP connection to localhost (or exim -bs). For them you can add to the acl_smtp_data ACL:
deny
hosts = : localhost
! acl = acl_check_sender ${sender_ident}
and install some identd on the server.
FromandSenderheaders. – Piotr P. Karwasz Apr 04 '20 at 21:13