Here is my try at configuring an envelope signature with an expiring
hash
It is freely inspired by the great article made by Tor at slett.net
Please read his article before even attempting at reproducing this.
It is under early alpha development, so implement at your own risk. It
has some known flaws and is not very clean.
It uses a MySQL database like this one:
CREATE TABLE `exim_signature_hash` (
`id` bigint(20) NOT NULL auto_increment,
`sender_address_local_part` varchar(255) default NULL,
`local_part` varchar(255) default NULL,
`hash_expires` datetime NOT NULL default '0000-00-00 00:00:00',
`hash` varchar(8) default NULL,
`domain` varchar(255) default NULL,
`sender_address_domain` varchar(255) default NULL,
PRIMARY KEY (`id`)
) TYPE=MyISAM;
#Some Macros
###############################################################################
HASH_LIFETIME = 5 DAY
HASH_TABLE = exim_signature_hash
HASH_ADD = INSERT INTO HASH_TABLE \
( sender_address_local_part, local_part, domain,
sender_address_domain, hash_expires, hash) \
VALUES ( \
'${quote_mysql:$sender_address_local_part}', \
'${quote_mysql:$local_part}', \
'${quote_mysql:$domain}', \
'${quote_mysql:$sender_address_domain}', \
DATE_ADD(now(), INTERVAL HASH_LIFETIME), \
'${quote_mysql:${hash_8:${hmac{md5}{SECRET}{${lc:$sender_address_local_part=$local_part=$domain=$tod_full}}}}}'
\
)
HASH_GET_HASH = SELECT hash FROM HASH_TABLE WHERE id = LAST_INSERT_ID()
HASH_CLEAN = DELETE FROM HASH_TABLE WHERE now() > hash_expires
HASH_CHECK_local_part = SELECT CASE \
WHEN id IS NOT NULL THEN "true" \
ELSE "false" \
END \
FROM HASH_TABLE WHERE hash = '${quote_mysql:$acl_c9}'
HASH_RECEIVED = DELETE FROM HASH_TABLE WHERE hash =
'${quote_mysql:$acl_c9}'
################################################################################
#some acl
begin acl
hash_acl:
warn
condition = ${lookup
mysql{HASH_ADD}}
warn
set
acl_c9 = ${lookup mysql{HASH_GET_HASH}}
warn
condition = ${lookup
mysql{HASH_CLEAN}}
################################################################################
acl_check_rcpt:
warn
sender_domains =
+local_domains
acl
= hash_acl
accept
domains = +local_domains
set
acl_c9 = ${if and { {
match{${lc:$local_part}} {^(.*)=(.*)} } { match{${lc:$local_part}}
{^(.*)=(.*)} }} {$2}{false}}
condition = ${lookup
mysql{HASH_CHECK_local_part}}
warn
senders = : postmaster@*
domains = +local_domains
set
acl_c2 = The recipient address
<$local_part@$domain> does not match a valid, signed return path
from here.\n You are responding to a forged sender address.
set
acl_c3 = bogus bounce for
<$local_part@$domain>.
################################################################################
acl_check_data:
deny
message = $acl_c2
log_message = $acl_c3
condition = ${if and
{{def:acl_c2}{def:acl_c3}} {true}}
################################################################################
begin routers
dnslookup_signed:
debug_print = "R: dnslookup_signed for
$local_part@$domain"
driver = dnslookup
transport = remote_smtp_signed
senders = ! : *
domains = !
+local_domains : !+relay_to_domains
no_more
hashed_local:
debug_print = "R: hashed_local for
$local_part@$domain"
driver = redirect
domains = +local_domains
local_part_suffix = =*
data
= $local_part@$domain
################################################################################
remote_smtp_signed:
debug_print = "T: remote_smtp_signed for
$local_part@$domain"
driver = smtp
max_rcpt = 1
return_path =
$sender_address_local_part=$local_part=$domain=$acl_c9@$sender_address_domain