got a problem when configured passdb with username_filter — looks like the option doesn't work OS: FreeBSD 13 and 14. Dovecot version: 2.3.21 Part of config: passdb { args = /usr/local/bin/php /usr/local/dovecot/bin/checkpassword.php driver = checkpassword } passdb { args = /usr/local/bin/php /usr/local/dovecot/bin/checkpassword.php driver = checkpassword username_filter = user1@postmaster.local.one default_fields = domain=local.one override_fields = user=postmaster@local.one } passdb { args = /usr/local/bin/php /usr/local/dovecot/bin/checkpassword.php driver = checkpassword username_filter = user3@user2.local.one default_fields = domain=local.one override_fields = user=user2@local.one }
When I try command "doveadm auth test user1@postmaster.local.one" and enter a password of user1 — it works as planned — change user1@postmaster.local.one to user1@local.one check it's password and override user to postmaster@local.one But when I try "doveadm auth test user3@user2.local.one" — it also change user3@user2.local.one to user3@local.one, and after password check — override it to postmaster@local.one
Debug logs, when I try "doveadm auth test user3@user2.local.one":
Aug 1 11:01:03 auth: Debug: Loading modules from directory: /usr/local/lib/dovecot/auth Aug 1 11:01:03 auth: Debug: Module loaded: /usr/local/lib/dovecot/auth/lib20_auth_var_expand_crypt.so Aug 1 11:01:03 auth: Debug: Read auth token secret from /var/run/dovecot/auth-token-secret.dat Aug 1 11:01:03 auth: Debug: passwd-file /usr/local/etc/dovecot.users.list:Read 7 users in 0 secs Aug 1 11:01:03 auth: Debug: auth client connected (pid=0) Aug 1 11:01:03 auth: Debug: client in: AUTH 1 PLAIN service=doveadm debug resp=<hidden> Aug 1 11:01:03 auth: Debug: checkpassword(user3@user2.local.one): Performing passdb lookup Aug 1 11:01:03 auth: Debug: checkpassword(user3@user2.local.one): execute: /usr/local/bin/php /usr/local/dovecot/bin/checkpassword.php /usr/local/libexec/dovecot/checkpassword-reply Aug 1 11:01:03 auth: Debug: checkpassword(user3@user2.local.one): Received input: Aug 1 11:01:03 auth: Debug: checkpassword(user3@user2.local.one): exit_status=1 Aug 1 11:01:03 auth: checkpassword(user3@user2.local.one): Login failed (status=1) Aug 1 11:01:03 auth: Debug: checkpassword(user3@user2.local.one): Finished passdb lookup Aug 1 11:01:03 auth: Debug: checkpassword(user3@user2.local.one): Performing passdb lookup Aug 1 11:01:03 auth: Debug: checkpassword(user3@user2.local.one): username changed user3@user2.local.one -> user3@local.one Aug 1 11:01:03 auth: Debug: checkpassword(user3@local.one): execute: /usr/local/bin/php /usr/local/dovecot/bin/checkpassword.php /usr/local/libexec/dovecot/checkpassword-reply Aug 1 11:01:03 auth: Debug: checkpassword(user3@local.one): Received input: user=user3@local.one userdb_home=/var/spool/mail/ userdb_uid=dovecot userdb_gid=dovecot Aug 1 11:01:03 auth: Debug: checkpassword(user3@local.one): exit_status=0 Aug 1 11:01:03 auth: Debug: checkpassword(user3@local.one): username changed user3@local.one -> postmaster@local.one Aug 1 11:01:03 auth: Debug: checkpassword(postmaster@local.one): Finished passdb lookup Aug 1 11:01:03 auth: Debug: auth(postmaster@local.one): Auth request finished Aug 1 11:01:03 auth: Debug: client passdb out: OK 1 user=postmaster@local.one original_user=user3@user2.local.one
I've checked sources and find in " core/src/auth/auth-request.c (from line 617) " code that check username_filter and should send "skipping passdb: username filtered" message in debug, but it doesn't do it.
Is it a bug or I've missed something in setup?
try changing your config so that it reads
passdb passb1 { }
passdb passdb2 { }
passdb passdb3 { }
and try again. this should make it more clear what happens.
Aki
On 01/08/2024 14:51 EEST zaxwat93--- via dovecot dovecot@dovecot.org wrote:
got a problem when configured passdb with username_filter — looks like the option doesn't work OS: FreeBSD 13 and 14. Dovecot version: 2.3.21 Part of config: passdb { args = /usr/local/bin/php /usr/local/dovecot/bin/checkpassword.php driver = checkpassword } passdb { args = /usr/local/bin/php /usr/local/dovecot/bin/checkpassword.php driver = checkpassword username_filter = user1@postmaster.local.one default_fields = domain=local.one override_fields = user=postmaster@local.one } passdb { args = /usr/local/bin/php /usr/local/dovecot/bin/checkpassword.php driver = checkpassword username_filter = user3@user2.local.one default_fields = domain=local.one override_fields = user=user2@local.one }
When I try command "doveadm auth test user1@postmaster.local.one" and enter a password of user1 — it works as planned — change user1@postmaster.local.one to user1@local.one check it's password and override user to postmaster@local.one But when I try "doveadm auth test user3@user2.local.one" — it also change user3@user2.local.one to user3@local.one, and after password check — override it to postmaster@local.one
Debug logs, when I try "doveadm auth test user3@user2.local.one":
Aug 1 11:01:03 auth: Debug: Loading modules from directory: /usr/local/lib/dovecot/auth Aug 1 11:01:03 auth: Debug: Module loaded: /usr/local/lib/dovecot/auth/lib20_auth_var_expand_crypt.so Aug 1 11:01:03 auth: Debug: Read auth token secret from /var/run/dovecot/auth-token-secret.dat Aug 1 11:01:03 auth: Debug: passwd-file /usr/local/etc/dovecot.users.list:Read 7 users in 0 secs Aug 1 11:01:03 auth: Debug: auth client connected (pid=0) Aug 1 11:01:03 auth: Debug: client in: AUTH 1 PLAIN service=doveadm debug resp=<hidden> Aug 1 11:01:03 auth: Debug: checkpassword(user3@user2.local.one): Performing passdb lookup Aug 1 11:01:03 auth: Debug: checkpassword(user3@user2.local.one): execute: /usr/local/bin/php /usr/local/dovecot/bin/checkpassword.php /usr/local/libexec/dovecot/checkpassword-reply Aug 1 11:01:03 auth: Debug: checkpassword(user3@user2.local.one): Received input: Aug 1 11:01:03 auth: Debug: checkpassword(user3@user2.local.one): exit_status=1 Aug 1 11:01:03 auth: checkpassword(user3@user2.local.one): Login failed (status=1) Aug 1 11:01:03 auth: Debug: checkpassword(user3@user2.local.one): Finished passdb lookup Aug 1 11:01:03 auth: Debug: checkpassword(user3@user2.local.one): Performing passdb lookup Aug 1 11:01:03 auth: Debug: checkpassword(user3@user2.local.one): username changed user3@user2.local.one -> user3@local.one Aug 1 11:01:03 auth: Debug: checkpassword(user3@local.one): execute: /usr/local/bin/php /usr/local/dovecot/bin/checkpassword.php /usr/local/libexec/dovecot/checkpassword-reply Aug 1 11:01:03 auth: Debug: checkpassword(user3@local.one): Received input: user=user3@local.one userdb_home=/var/spool/mail/ userdb_uid=dovecot userdb_gid=dovecot Aug 1 11:01:03 auth: Debug: checkpassword(user3@local.one): exit_status=0 Aug 1 11:01:03 auth: Debug: checkpassword(user3@local.one): username changed user3@local.one -> postmaster@local.one Aug 1 11:01:03 auth: Debug: checkpassword(postmaster@local.one): Finished passdb lookup Aug 1 11:01:03 auth: Debug: auth(postmaster@local.one): Auth request finished Aug 1 11:01:03 auth: Debug: client passdb out: OK 1 user=postmaster@local.one original_user=user3@user2.local.one
I've checked sources and find in " core/src/auth/auth-request.c (from line 617) " code that check username_filter and should send "skipping passdb: username filtered" message in debug, but it doesn't do it.
Is it a bug or I've missed something in setup?
dovecot mailing list -- dovecot@dovecot.org To unsubscribe send an email to dovecot-leave@dovecot.org
added names: passdb allusers { ... } passdb postmasterfilter { ... username_filter = user1@postmaster.local.one ... } passdb user2filter { .... username_filter = user3@user2.local.one ,,, }
try "doveadm auth test user3@user2.local.one" and got logs: Aug 1 16:08:02 auth: Debug: auth client connected (pid=0) Aug 1 16:08:02 auth: Debug: client in: AUTH 1 PLAIN service=doveadm debug resp=<hidden> Aug 1 16:08:02 auth: Debug: allusers(user3@user2.local.one): Performing passdb lookup Aug 1 16:08:02 auth: Debug: allusers(user3@user2.local.one): execute: /usr/local/bin/php /usr/local/dovecot/bin/checkpassword.php /usr/local/libexec/dovecot/checkpassword-reply Aug 1 16:08:02 auth: Debug: allusers(user3@user2.local.one): Received input: Aug 1 16:08:02 auth: Debug: allusers(user3@user2.local.one): exit_status=1 Aug 1 16:08:02 auth: allusers(user3@user2.local.one): Login failed (status=1) Aug 1 16:08:02 auth: Debug: allusers(user3@user2.local.one): Finished passdb lookup Aug 1 16:08:02 auth: Debug: postmasterfilter(user3@user2.local.one): Performing passdb lookup Aug 1 16:08:02 auth: Debug: postmasterfilter(user3@user2.local.one): username changed user3@user2.local.one -> user3@local.one Aug 1 16:08:02 auth: Debug: postmasterfilter(user3@local.one): execute: /usr/local/bin/php /usr/local/dovecot/bin/checkpassword.php /usr/local/libexec/dovecot/checkpassword-reply Aug 1 16:08:02 auth: Debug: postmasterfilter(user3@local.one): Received input: user=user3@local.one userdb_home=/var/spool/mail/ userdb_uid=dovecot userdb_gid=dovecot Aug 1 16:08:02 auth: Debug: postmasterfilter(user3@local.one): exit_status=0 Aug 1 16:08:02 auth: Debug: postmasterfilter(user3@local.one): username changed user3@local.one -> postmaster@local.one Aug 1 16:08:02 auth: Debug: postmasterfilter(postmaster@local.one): Finished passdb lookup Aug 1 16:08:02 auth: Debug: auth(postmaster@local.one): Auth request finished Aug 1 16:08:02 auth: Debug: client passdb out: OK 1 user=postmaster@local.one original_user=user3@user2.local.one
Same result: it should skip postmasterfilter passdb and work with user2filter, but it didn't
Hi
in my opinion you found a bug. In the function passdb_preinit(..) in file src/auth/passdb.c the username_filters are copied from set->username_filter to passdb->username_filter. However that code only gets to be executed if this line returns NULL
passdb = passdb_find(set->driver, set->args, &idx);
For some reason this code finds a match (i.e. != NULL) for your second passdb (postmasterfilter) so it never reaches the code to setup the filter correctly. Strange to say for the third db it doesn't find a match and does setup the filter.
I would guess that the main reason this hasn't been noticed is that most use cases of multiple passdb's use different drivers. Either this should be treated as a bug or the documentation should be updated to state that multiple passdb's should not use the same driver.
As a workaround to this problem, given that you are handing off authentication to a php script, my suggestion would be to update that script so that it handles all the use cases directly. In Dovecot you will only need to define one passdb that calls the script.
John
On 01/08/2024 15:17, zaxwat93--- via dovecot wrote:
added names: passdb allusers { ... } passdb postmasterfilter { ... username_filter =user1@postmaster.local.one
... } passdb user2filter { .... username_filter =user3@user2.local.one
,,, }try "doveadm auth testuser3@user2.local.one" and got logs: Aug 1 16:08:02 auth: Debug: auth client connected (pid=0) Aug 1 16:08:02 auth: Debug: client in: AUTH 1 PLAIN service=doveadm debug resp=<hidden> Aug 1 16:08:02 auth: Debug: allusers(user3@user2.local.one): Performing passdb lookup Aug 1 16:08:02 auth: Debug: allusers(user3@user2.local.one): execute: /usr/local/bin/php /usr/local/dovecot/bin/checkpassword.php /usr/local/libexec/dovecot/checkpassword-reply Aug 1 16:08:02 auth: Debug: allusers(user3@user2.local.one): Received input: Aug 1 16:08:02 auth: Debug: allusers(user3@user2.local.one): exit_status=1 Aug 1 16:08:02 auth: allusers(user3@user2.local.one): Login failed (status=1) Aug 1 16:08:02 auth: Debug: allusers(user3@user2.local.one): Finished passdb lookup Aug 1 16:08:02 auth: Debug: postmasterfilter(user3@user2.local.one): Performing passdb lookup Aug 1 16:08:02 auth: Debug: postmasterfilter(user3@user2.local.one): username changeduser3@user2.local.one ->user3@local.one Aug 1 16:08:02 auth: Debug: postmasterfilter(user3@local.one): execute: /usr/local/bin/php /usr/local/dovecot/bin/checkpassword.php /usr/local/libexec/dovecot/checkpassword-reply Aug 1 16:08:02 auth: Debug: postmasterfilter(user3@local.one): Received input:user=user3@local.one userdb_home=/var/spool/mail/ userdb_uid=dovecot userdb_gid=dovecot Aug 1 16:08:02 auth: Debug: postmasterfilter(user3@local.one): exit_status=0 Aug 1 16:08:02 auth: Debug: postmasterfilter(user3@local.one): username changeduser3@local.one ->postmaster@local.one Aug 1 16:08:02 auth: Debug: postmasterfilter(postmaster@local.one): Finished passdb lookup Aug 1 16:08:02 auth: Debug: auth(postmaster@local.one): Auth request finished Aug 1 16:08:02 auth: Debug: client passdb out: OK 1user=postmaster@local.one original_user=user3@user2.local.one
Same result: it should skip postmasterfilter passdb and work with user2filter, but it didn't
dovecot mailing list --dovecot@dovecot.org To unsubscribe send an email todovecot-leave@dovecot.org
Hi!
Thanks John for triage, we'll take a look at this.
Aki
On 05/08/2024 05:50 EEST John Fawcett via dovecot dovecot@dovecot.org wrote:
Hi
in my opinion you found a bug. In the function passdb_preinit(..) in file src/auth/passdb.c the username_filters are copied from set->username_filter to passdb->username_filter. However that code only gets to be executed if this line returns NULL
passdb = passdb_find(set->driver, set->args, &idx);
For some reason this code finds a match (i.e. != NULL) for your second passdb (postmasterfilter) so it never reaches the code to setup the filter correctly. Strange to say for the third db it doesn't find a match and does setup the filter.
I would guess that the main reason this hasn't been noticed is that most use cases of multiple passdb's use different drivers. Either this should be treated as a bug or the documentation should be updated to state that multiple passdb's should not use the same driver.
As a workaround to this problem, given that you are handing off authentication to a php script, my suggestion would be to update that script so that it handles all the use cases directly. In Dovecot you will only need to define one passdb that calls the script.
John
On 01/08/2024 15:17, zaxwat93--- via dovecot wrote:
added names: passdb allusers { ... } passdb postmasterfilter { ... username_filter =user1@postmaster.local.one
... } passdb user2filter { .... username_filter =user3@user2.local.one
,,, }try "doveadm auth testuser3@user2.local.one" and got logs: Aug 1 16:08:02 auth: Debug: auth client connected (pid=0) Aug 1 16:08:02 auth: Debug: client in: AUTH 1 PLAIN service=doveadm debug resp=<hidden> Aug 1 16:08:02 auth: Debug: allusers(user3@user2.local.one): Performing passdb lookup Aug 1 16:08:02 auth: Debug: allusers(user3@user2.local.one): execute: /usr/local/bin/php /usr/local/dovecot/bin/checkpassword.php /usr/local/libexec/dovecot/checkpassword-reply Aug 1 16:08:02 auth: Debug: allusers(user3@user2.local.one): Received input: Aug 1 16:08:02 auth: Debug: allusers(user3@user2.local.one): exit_status=1 Aug 1 16:08:02 auth: allusers(user3@user2.local.one): Login failed (status=1) Aug 1 16:08:02 auth: Debug: allusers(user3@user2.local.one): Finished passdb lookup Aug 1 16:08:02 auth: Debug: postmasterfilter(user3@user2.local.one): Performing passdb lookup Aug 1 16:08:02 auth: Debug: postmasterfilter(user3@user2.local.one): username changeduser3@user2.local.one ->user3@local.one Aug 1 16:08:02 auth: Debug: postmasterfilter(user3@local.one): execute: /usr/local/bin/php /usr/local/dovecot/bin/checkpassword.php /usr/local/libexec/dovecot/checkpassword-reply Aug 1 16:08:02 auth: Debug: postmasterfilter(user3@local.one): Received input:user=user3@local.one userdb_home=/var/spool/mail/ userdb_uid=dovecot userdb_gid=dovecot Aug 1 16:08:02 auth: Debug: postmasterfilter(user3@local.one): exit_status=0 Aug 1 16:08:02 auth: Debug: postmasterfilter(user3@local.one): username changeduser3@local.one ->postmaster@local.one Aug 1 16:08:02 auth: Debug: postmasterfilter(postmaster@local.one): Finished passdb lookup Aug 1 16:08:02 auth: Debug: auth(postmaster@local.one): Auth request finished Aug 1 16:08:02 auth: Debug: client passdb out: OK 1user=postmaster@local.one original_user=user3@user2.local.one
Same result: it should skip postmasterfilter passdb and work with user2filter, but it didn't
dovecot mailing list --dovecot@dovecot.org To unsubscribe send an email todovecot-leave@dovecot.org
dovecot mailing list -- dovecot@dovecot.org To unsubscribe send an email to dovecot-leave@dovecot.org
This is fixed in main with https://github.com/dovecot/core/commit/7bad6a24160e34bce8f10e73dbbf9e5fbbcd1...
and will be fixed in 2.4.0
Aki
On 05/08/2024 09:07 EEST Aki Tuomi via dovecot dovecot@dovecot.org wrote:
Hi!
Thanks John for triage, we'll take a look at this.
Aki
On 05/08/2024 05:50 EEST John Fawcett via dovecot dovecot@dovecot.org wrote:
Hi
in my opinion you found a bug. In the function passdb_preinit(..) in file src/auth/passdb.c the username_filters are copied from set->username_filter to passdb->username_filter. However that code only gets to be executed if this line returns NULL
passdb = passdb_find(set->driver, set->args, &idx);
For some reason this code finds a match (i.e. != NULL) for your second passdb (postmasterfilter) so it never reaches the code to setup the filter correctly. Strange to say for the third db it doesn't find a match and does setup the filter.
I would guess that the main reason this hasn't been noticed is that most use cases of multiple passdb's use different drivers. Either this should be treated as a bug or the documentation should be updated to state that multiple passdb's should not use the same driver.
As a workaround to this problem, given that you are handing off authentication to a php script, my suggestion would be to update that script so that it handles all the use cases directly. In Dovecot you will only need to define one passdb that calls the script.
John
On 01/08/2024 15:17, zaxwat93--- via dovecot wrote:
added names: passdb allusers { ... } passdb postmasterfilter { ... username_filter =user1@postmaster.local.one
... } passdb user2filter { .... username_filter =user3@user2.local.one
,,, }try "doveadm auth testuser3@user2.local.one" and got logs: Aug 1 16:08:02 auth: Debug: auth client connected (pid=0) Aug 1 16:08:02 auth: Debug: client in: AUTH 1 PLAIN service=doveadm debug resp=<hidden> Aug 1 16:08:02 auth: Debug: allusers(user3@user2.local.one): Performing passdb lookup Aug 1 16:08:02 auth: Debug: allusers(user3@user2.local.one): execute: /usr/local/bin/php /usr/local/dovecot/bin/checkpassword.php /usr/local/libexec/dovecot/checkpassword-reply Aug 1 16:08:02 auth: Debug: allusers(user3@user2.local.one): Received input: Aug 1 16:08:02 auth: Debug: allusers(user3@user2.local.one): exit_status=1 Aug 1 16:08:02 auth: allusers(user3@user2.local.one): Login failed (status=1) Aug 1 16:08:02 auth: Debug: allusers(user3@user2.local.one): Finished passdb lookup Aug 1 16:08:02 auth: Debug: postmasterfilter(user3@user2.local.one): Performing passdb lookup Aug 1 16:08:02 auth: Debug: postmasterfilter(user3@user2.local.one): username changeduser3@user2.local.one ->user3@local.one Aug 1 16:08:02 auth: Debug: postmasterfilter(user3@local.one): execute: /usr/local/bin/php /usr/local/dovecot/bin/checkpassword.php /usr/local/libexec/dovecot/checkpassword-reply Aug 1 16:08:02 auth: Debug: postmasterfilter(user3@local.one): Received input:user=user3@local.one userdb_home=/var/spool/mail/ userdb_uid=dovecot userdb_gid=dovecot Aug 1 16:08:02 auth: Debug: postmasterfilter(user3@local.one): exit_status=0 Aug 1 16:08:02 auth: Debug: postmasterfilter(user3@local.one): username changeduser3@local.one ->postmaster@local.one Aug 1 16:08:02 auth: Debug: postmasterfilter(postmaster@local.one): Finished passdb lookup Aug 1 16:08:02 auth: Debug: auth(postmaster@local.one): Auth request finished Aug 1 16:08:02 auth: Debug: client passdb out: OK 1user=postmaster@local.one original_user=user3@user2.local.one
Same result: it should skip postmasterfilter passdb and work with user2filter, but it didn't
dovecot mailing list --dovecot@dovecot.org To unsubscribe send an email todovecot-leave@dovecot.org
dovecot mailing list -- dovecot@dovecot.org To unsubscribe send an email to dovecot-leave@dovecot.org
dovecot mailing list -- dovecot@dovecot.org To unsubscribe send an email to dovecot-leave@dovecot.org
Thank you for explanation. Unfortunately it is better not to touch this script, so I will wait for the fix
On 05/08/2024 10:00, zaxwat93--- via dovecot wrote:
Thank you for explanation. Unfortunately it is better not to touch this script, so I will wait for the fix
dovecot mailing list --dovecot@dovecot.org To unsubscribe send an email todovecot-leave@dovecot.org
Hi
I stated one thing wrong in my summary "Strange to say for the third db it doesn't find a match and does setup the filter."
That part was not correct since I had maybe a typo in my config. But that gave me a clue for another workaround. If the "args" parameter is different in each passdb, the current code seems to be working.
You can duplicate the script under different names or even create 2 symlinks to the same script. I didn't try it with php which I don't have installed.
passdb db1 { driver = checkpassword args = /usr/local/libexec/dovecot/checkpassword }
passdb db2 { driver = checkpassword args = /usr/local/libexec/dovecot/checkpassword1 username_filter = user1@postmaster.local.one default_fields = domain=local.one override_fields = user=postmaster@local.one }
passdb db3 { driver = checkpassword args = /usr/local/libexec/dovecot/checkpassword2 username_filter = user3@user2.local.one default_fields = domain=local.one override_fields = user=user2@local.one }
John
I also tried to add filter to passdb allusers: passdb allusers { ... username_filter = !user3@user2.local.one !user1@postmaster.local.one ... } passdb postmasterfilter { ... username_filter = user1@postmaster.local.one ... } passdb user2filter { .... username_filter = user3@user2.local.one ,,, } and got strange error in logs (still testing user3@user2.local.one): Aug 2 14:36:13 auth: Debug: Loading modules from directory: /usr/local/lib/dovecot/auth Aug 2 14:36:13 auth: Debug: Module loaded: /usr/local/lib/dovecot/auth/lib20_auth_var_expand_crypt.so Aug 2 14:36:13 auth: Debug: Read auth token secret from /var/run/dovecot/auth-token-secret.dat Aug 2 14:36:13 auth: Debug: passwd-file /usr/local/etc/dovecot.users.list:Read 7 users in 0 secs Aug 2 14:36:13 auth: Debug: auth client connected (pid=0) Aug 2 14:36:13 auth: Debug: client in: AUTH 1 PLAIN service=doveadm debug resp=<hidden> Aug 2 14:36:13 auth: Debug: plain(user3@user2.local.one): skipping passdb: username filtered Aug 2 14:36:13 auth: Error: plain(user3@user2.local.one): All password databases were skipped Aug 2 14:36:13 auth: Debug: auth(user3@user2.local.one): Auth request finished Aug 2 14:36:15 auth: Debug: client passdb out: FAIL 1 user=user3@user2.local.one code=temp_fail
Looks like filter worked for allusers passdb, but than skipped all other passdbs
participants (3)
-
Aki Tuomi
-
John Fawcett
-
zaxwat93@gmail.com