[Dovecot] How to authenticate against SQL DB with custom-ciphered passwords?

Nicolay Vizovitin vizovitin at gmail.com
Sun Sep 29 11:54:14 EEST 2013

Thanks a lot for your answers!

Unfortunately I didn't have a chance to sit down and implement the thing
yet, but after looking through the Dovecot code I have some additional
questions. Please see inline below.

On Fri, Sep 27, 2013 at 10:13 PM, Timo Sirainen <tss at iki.fi> wrote:

> On 26.9.2013, at 10.01, Nicolay Vizovitin <vizovitin at gmail.com> wrote:
> > I'm about to start developing authentication/password-scheme module for
> > Dovecot. So I would like to get some advice before actually committing to
> > doing things in particular way. Hope somebody will be able to help me :)
> >
> > For the record, I am currently targeting latest stable Dovecot version
> > 2.2.5.
> >
> > I have an SQL DB with mail users' authentication data. Passwords are
> stored
> > either encrypted via system crypt(3) or ciphered with some custom
> algorithm
> > (think something symmetrical like AES, so passwords can be decrypted into
> > plain form). I want to use this DB as both userdb and passdb backend. The
> > issue, of course, is with ciphered passwords support.
> >
> > 1) Is it feasible to just implement a new password scheme for ciphered
> > passwords support and still use stock passdb driver in Dovecot for SQL DB
> > access?
> Plugins can implement new password schemes.
> http://dovecot.org/patches/password-scheme-lmpass.c is an example,
> although I'm not sure if it compiles with v2.2.
> > So that passwords in this scheme would be treated as PLAIN (in a
> > sense that both cleartext and shared secret authentication methods would
> > work).
> You could do that in a slightly ugly way by setting
> password_generate=plain_generate(), so password_scheme_is_alias() returns
> TRUE for that.

OK, I figured I had to use something like that. However, after looking
through the code I don't think it'll work with shared-secret authentication
mechanisms. Looking at struct password_scheme definition:

        int (*password_verify)(const char *plaintext, const char *user,
                               const unsigned char *raw_password, size_t
                               const char **error_r);
        void (*password_generate)(const char *plaintext, const char *user,
                                  const unsigned char **raw_password_r,
                                  size_t *size_r);

password_generate would have to be equal to plain_generate(). So I'm left
with password_verify, but its signature implies that it is called only when
plaintext password is available from client, which is not the case with
shared-secret mechanisms.

A simple question to verify my hypothesis: would PLAIN-TRUNC password
scheme work with CRAM-MD5 authentication? My understanding of CRAM-MD5 and
what PLAIN-TRUNC does tells me it cannot work even in theory.

Something tells me that I rather need a new password encoding than just a
password scheme. Yet there is no way to extend password encodings, as far
as I can tell (at least from looking at password_decode()).

So I guess I can't use new password scheme to solve my problem without
patching Dovecot, can I?

>  > 2) Provided I implement custom password scheme for ciphered passwords,
> what
> > is the best way to be capable to perform authentication against both
> > ciphered and encrypted passwords? Ciphered and encrypted passwords are
> > stored in different fields of SQL table (one of them is NULL when the
> other
> > one is set).
> >    a) Do I define two passdb clauses with their own default_pass_scheme
> > (equal to my new scheme or CRYPT for encrypted passwords) and use
> fallback
> > to effectively check both of them?
> >    b) Do I modify SQL query so that it prefixes existing password with
> > correct scheme (I'm not sure this will be easy enough to do)?
> By "ciphered" I understand you mean encrypted, and by "encrypted" you mean
> hashed.. Scheme prefix would work, mysql and postgresql have complex enough
> string manipulation functions to make this possible I think.

Well, yes, I meant exactly that. :)

>  > 3) Is it mandatory to provide password generation routine for custom
> > password scheme? When it will be used?
> doveadm pw command would use it for example. But as mentioned, you should
> set it to plain_generate.
> > 4) Maybe it's better to just implement a plugin that serves as both
> userdb
> > and passdb driver (in other words a kind of generic authentication
> module)?
> > What are advantages and disadvantages of each method - custom password
> > scheme + stock SQL driver VS. custom userdb and passdb driver?
> Fortunately,
> > I already have all the required credentials lookup and verification code.
> > So in any case the question is only in figuring out suitable Dovecot APIs
> > and integrating the existing code.
> Implementing yet another sql passdb sounds like quite a lot of work.

I guess it is. But I'd rather trade more work now for more maintainability
later (if implementing passdb would help). I don't really want to patch
Dovecot as future changes may render the patch incompatible. I could invest
some time into the patch provided there is a chance it would get merged
into upstream. Otherwise I'd rather use my existing code for accessing SQL
DB and password verification/lookup and integrate it into passdb code.

BTW, is there anything else passdb/userdb plugin can do other than its
direct responsibilities and returning extra userdb fields? In other words,
are there any (theoretical) advantages to implementing passdb instead of
password scheme?

>  > 7) Somewhat unrelated question: what is the best way to test IMAP (and
> > maybe POP3 as well) server performance and compare it to another server?
> > I'm interested in both login performance (the part I will influence) and
> > performance with many mails in mailbox. I heard imaptest is suitable for
> > this task. Are there any recipes or example testing scenarios you might
> > share? ;)
> There are only bad non-realistic benchmarks available currently. With
> imaptest you can easily test the login performance though:
> imaptest user=test%d.%d - select=0 clients=100
Thanks, will try it out later.

Best regards,

More information about the dovecot mailing list