Exim4 and authenticating from a database
April 27th, 2010 | by jim |The exim authenticators take care of collecting a username/password from the user during the SMTP conversation, and are often used to check against a database to see if they are ‘correct’. The syntax for this check gets a few people confused, so here’s a description …
Your database is storing an encrypted password I hope; if it is not you have other issues. You should also be following standards and prefixing the password with the name of the encryption scheme, so the DB value looks like :- {md5}CY9rzUYh03PK3k6DJie09g==
However, if you are simply storing the encrypted data without the scheme name (as I was until I started writing this!) you need to stick to a single scheme and hard-code this into the exim authentication config, which is a big source of confusion.
How it all works :-
The authentication session provides an actual password (it was lightly encoded with base64 during the SMTP session, but this has been taken care of automatically). Under PLAIN authentication, for example, $3 will contain the actual user password.
A DB query such as ${lookup mysql{...}} returns “encrypted-password” (not “{scheme}encrypted-password”)
Therefore in order to compare the password with the encrypted password, we have to say what encryption scheme the database is using — md5, sha1, whatever. We cannot decrypt what the database returns, so we must encrypt the password — but the difference is invisible to us, Exim does the right thing.
In order to encrypt the password, we need to tell crypteq which encryption scheme to use — “sha1″ normally. We need to tell crypteq explicitly what scheme we’re using, it cannot guess by looking at the values. Exim is expecting “{scheme}data”, but our DB isn’t returning that …
Also, crypteq’s *syntax* is confusing because it doesn’t read like “encrypt the password with ’sha1′ and compare that to what’s in the database”, it reads “compare the password with the ’sha1′-encrypted data from the database”.
And, for good measure, the way you say “sha1″ demands curly brackets, which are *not* part of the command syntax, and therefore need to have backslashes in front of them …
crypteq takes two strings, the unencrypted password in one, and the encrypted password PLUS the encryption scheme name in the second. We need to explicitly say \{sha1\} in front of the SQL lookup.
crypteq {$3}{\{sha1\}${lookup …}}
${if} takes three values; the query (the entire crypteq thing from above), and the two results.
server_condition = ${if crypteq {$3}{\{sha1\}${lookup …}}{yes}{no}}
read more about crypteq: http://www.exim.org/exim-html-4.40/doc/html/spec_11.html
Here’s a full authenticator for PLAIN …
begin authenticators
plain:
driver = plaintext
public_name = PLAIN
server_advertise_condition = ${if eq{$tls_cipher}{}{no}{yes}}
server_condition = ${if crypteq {$3}{${lookup sqlite {DB \
select password from users where username = '$2';}}}{yes}{no}}
server_set_id = $2
Tags: exim4