On 07/11/2020 23:30, Michael Haardt via Exim-users wrote:
>> Ok, have had a 5 minute scan read ... seems that tainted data is a
>> {potential} problem, but in my case the variables that I use to build a
>> path in transport 'local_delivery':
>> [...]
>> have already been used as keys in a database look-up previously in the
>> router that cause the transport to be called:
> That's not how things work. The variable will stay tainted even when
> looked up.
Agreed - but see below.
>
>> Can we have, instead, a directive that allows us to assert 'untainted'
>> over one or more variables:
> Previously, a single lookup that checked both local part and domain to
> let the router match was popular. Now that's fighting against the design.
>
> Use two lookups, one for local_parts and one for domains, even if both
> perform the same lookup, to set $local_part_data and $domain_data as
> side effect, and things are easy from there. It's a new way of thinking
> about routers: You do not just need a condition to let the router match
> the address, you also need to set the *_data variables as side effect.
>
> You can work around the *_data variables, but it will make everything
> complicated.
>
> Just untainting variables without verification is a bad idea.
Agreed, but in my case they are verified (see below)
> One could
> argue if there shouldn't be a verifier option for variables instead of
> setting the *_data copies, so a single lookup could verify und untaint
> two variables, but some check is required. Before I used generic
> conditions to verify variables and another condition to match the router,
> now I use local_parts and domains, which I never did before. It is about
> as readable, once you get used to it.
I get the purpose of tainted data and preventing its use, however if you
look at my router:
#
# Normal local delivery
#
local_delivery:
driver = accept
condition = ${lookup mysql{SELECT
CONCAT(users.username,'@',domains.domain) AS email FROM \
users LEFT JOIN domains ON users.domain_id=domains.id
WHERE \
users.username='${quote_mysql:$local_part}' AND \
domains.domain='${quote_mysql:$domain}' AND \
users.active=1 AND \
domains.active=1}{yes}{no}}
transport = local_delivery
user = mail
group = mail
when the condition checks my work email address (mike.tubby@???):
users.username == mike.tubby
domains.domain == thorcom.co.uk
and it has to be a perfect match, character for character, hence my
assertion is that transport = local_delivery is only ever called if the
condition is true and for the condition to be true $local_part and
$domain have matched what is in my database and are therefore 'verified'
safe. Well this is true for my use case, at least.
Now it looks like I have to use additional look-ups, perhaps something
like this:
$domain_data = ${lookup mysql{SELECT domains.domain AS domain FROM \
users LEFT JOIN domains ON users.domain_id=domains.id
WHERE \
users.username='${quote_mysql:$local_part}' AND \
domains.domain='${quote_mysql:$domain}' AND \
users.active=1 AND \
domains.active=1}}
$local_part_data = ${lookup mysql{SELECT users.username AS username
FROM \
users LEFT JOIN domains ON users.domain_id=domains.id
WHERE \
users.username='${quote_mysql:$local_part}' AND \
domains.domain='${quote_mysql:$domain}' AND \
users.active=1 AND \
domains.active=1}}
to simply send my 'already known good' keys $local_part and $domain
round in circles and get the duplicate data (same values) from the
database rather than use them, directly?
Mike
> Michael
>