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:

Post a Comment