noirello / bonsai

Simple Python 3 module for LDAP, using libldap2 and winldap C libraries.
MIT License
116 stars 32 forks source link

`modify_password` does not work with OpenLDAP when a new password is set #57

Closed morian closed 2 years ago

morian commented 2 years ago

Hi!

While trying to use bonsai to change a password on a OpenLDAP server I encountered a weird failure.

From a python point of view I get the following backtrace:

(venv) $ python update_password.py
Traceback (most recent call last):
  File "/home/lab/update_password.py", line 18, in <module>
    res = conn.modify_password(
  File "/home/lab/venv/lib/python3.9/site-packages/bonsai/ldapconnection.py", line 394, in modify_password
    return super().modify_password(user, new_password, old_password, timeout)
  File "/home/lab/venv/lib/python3.9/site-packages/bonsai/ldapconnection.py", line 64, in modify_password
    return self._evaluate(
  File "/home/lab/venv/lib/python3.9/site-packages/bonsai/ldapconnection.py", line 246, in _evaluate
    return self.get_result(msg_id, timeout)
bonsai.errors.LDAPError: password hash failed. (0x0050 [80])

This test program close to no interrest here as many tests were performed to pinpoint the origin of this issue. On the server side, nothing seems unusual except for these few lines in the (verbose) log:

Nov  1 22:21:44 ldap slapd[8174]: send_ldap_extended: err=80 oid= len=0
Nov  1 22:21:44 ldap slapd[8174]: send_ldap_response: msgid=2 tag=120 err=80
Nov  1 22:21:44 ldap slapd[8174]: conn=1015 op=1 RESULT oid= err=80 text=password hash failed

The server runs on Ubuntu 18.04.6 LTS with OpenLDAP 2.4.45+dfsg-1ubuntu1.10. It uses and requires SSL, and the password strategy is so that it is stored hashed using sha512crypt.

I can already update passwords when using pam from another connected server on the network. I can also successfully get a new password when new_password is not provided to modify_password, in which case the new password is gathered from the server response.

After more digging it seems to come from the following line: https://github.com/noirello/bonsai/blob/034ec671b60e41f1181a64ea4a7fe3d1dff7967a/src/_bonsai/ldapconnection.c#L744

    ber_printf(ber, "n}");

When replaced by the following, everything now works as expected:

    ber_printf(ber, "}");

There were already some discussions on samba's bugtracker about this: https://bugzilla.samba.org/show_bug.cgi?id=5886 This attachment caught my interest (fix for smbpasswd to work with OpenLDAP 2.4): https://bugzilla.samba.org/attachment.cgi?id=5461

Their current implementation even removed the N: https://github.com/samba-team/samba/blob/master/source3/passdb/pdb_ldap.c#L1762

Here is the same line for pam_ldap: https://github.com/PADL/pam_ldap/blob/master/pam_ldap.c#L3267 And here is the line in OpenLDAP implementation: https://git.openldap.org/openldap/openldap/-/blob/master/clients/tools/ldappasswd.c#L299

It seems like N does not work on windows as stated in commit 32f66de96c. With OpenLDAP headers, this seems to be a debug modifier (ignored in production): https://git.openldap.org/openldap/openldap/-/blob/master/libraries/liblber/encode.c#L553

Should this fix be working on windows, I suggest to use the fix mentioned earlier! I will open a merge request attached to this issue.

Thanks!

Romain

noirello commented 2 years ago

Thank you for reporting this and for the PR as well.

One thing I don't understand that why has this test never failed for me?

morian commented 2 years ago

Mmmh, I would say my configuration differs from the test one on these points:

Maybe somehow the extra null byte ends up in a string that needs to be hashed by this module? At this point I don't really know how things are being called on the server side.

noirello commented 2 years ago

Thanks for the config details and for the PR as well. It merged to dev.