[Dovecot] Bug in driver-mysql.c + fix

Timo Sirainen tss at iki.fi
Wed Mar 10 16:18:19 EET 2010

Sorry, been busy + also this mail somehow got marked as read.

On Fri, 2010-03-05 at 23:44 +0000, Alain Williams wrote:
> I tried to use MySQL stored procedures from dovecot:
> 	password_query = CALL user_pass_check('%n', '%d', '%w')
> 	user_query = CALL user_info('%n', '%d')
> This failed with the message:
> 	User query failed: PROCEDURE imap.user_info can't return a result set in the given context

I thought it was possible to avoid that error by implementing the MySQL
procedure in a specific way?..

> The root of this problem is that mysql_real_connect() needs to be called with option CLIENT_MULTI_RESULTS

The problem with doing that is that 1) it's not normally necessary and
more importantly 2) doing that makes any potential SQL injection
security holes a lot easier to exploit. So I'm not all that eager in
adding such code, especially if it can be worked around another way..

> I am looking to use mysql procedures, there are some interesting things that can be done.
> Two suggestions that I have will help with this:
> 1) There be variable (say) %o - this be the obscured password, ie what password_query returns.
> 2) that dovecot look for either ''password_query'' as above, or ''password_check''.
>    password_check would NOT return a password, but would be given %o and determine
>    itself if the password is correct.
>    It would return the other values (user, userdb_home, ...) and auth_result
>    that would encode success/retry/fail (0, 1, 2 - or maybe more structured [**])
>    and auth_reason some human readable reason.
>    The ''nologin'' value encodes some of this.
> The motivation for this is that my stored procedure will record the number of successive
> login failures and lock the account after 3 of them. It would also be possible to
> do time based restrictions & the such.
> Also: by passing %o the password is not sent in plain to the database server - which
> will increase security.

So what kind of obscuring where you thinking about? You could already
use "%Mw", which gives you MD5 of the password.

And password_query can already do basically what you were thinking about
with password_check:

password_query = select NULL as password, 'Y' as nopassword FROM users
WHERE username = '%u' and password = '%w'

or something. The main problem with that is that it can't differentiate
between "wrong password" and "user doesn't exist", so it logs all
password failures as "user doesn't exist".
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: This is a digitally signed message part
Url : http://dovecot.org/pipermail/dovecot/attachments/20100310/328341a7/attachment.bin 

More information about the dovecot mailing list