From: Ondřej Kuzník Date: Thu, 31 Jul 2025 14:09:16 +0000 (+0100) Subject: ITS#10254 Fix rehashing logic and add tests X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=06480123b16abb490488b751895894147bc13b36;p=thirdparty%2Fopenldap.git ITS#10254 Fix rehashing logic and add tests --- diff --git a/servers/slapd/overlays/ppolicy.c b/servers/slapd/overlays/ppolicy.c index c5d017a3bb..a0a17d8019 100644 --- a/servers/slapd/overlays/ppolicy.c +++ b/servers/slapd/overlays/ppolicy.c @@ -3085,31 +3085,32 @@ ppolicy_bind_response( Operation *op, SlapReply *rs ) /* * Check if we're expected to rewrite the stored hash */ - if ( ppb->pp.pwdRehashOnBind && op->o_tag == LDAP_REQ_BIND && - op->orb_method == LDAP_AUTH_SIMPLE && + struct berval newpw = BER_BVNULL; + + if ( op->o_tag == LDAP_REQ_COMPARE ) { + /* Compare of userPassword not currently implemented, but the + * draft mentions it, have it ready once it is */ + newpw = op->orc_ava->aa_value; + } else if ( op->o_tag == LDAP_REQ_BIND && + op->orb_method == LDAP_AUTH_SIMPLE ) { + newpw = op->orb_cred; + } + + if ( ppb->pp.pwdRehashOnBind && !BER_BVISNULL( &newpw ) && !BER_BVISNULL( &ppb->pp.pwdDefaultHash ) && ber_bvstrcasecmp( &scheme, &ppb->pp.pwdDefaultHash ) ) { - struct berval newpw = BER_BVNULL, newhash = BER_BVNULL; - - if ( op->o_tag == LDAP_REQ_COMPARE ) { - newpw = op->orc_ava->aa_value; - } else if ( op->o_tag == LDAP_REQ_BIND && - op->orb_method == LDAP_AUTH_SIMPLE ) { - newpw = op->orb_cred; - } - - if ( !BER_BVISNULL( &newpw ) ) { - const char *txt; - slap_passwd_hash_type( &newpw, &newhash, - ppb->pp.pwdDefaultHash.bv_val, &txt ); - if ( BER_BVISNULL( &newhash ) ) { - Debug( LDAP_DEBUG_ANY, "ppolicy_bind_response: " - "rehashing password for user %s failed: %s\n", - op->o_req_dn.bv_val, txt ); - } - } - - if ( !BER_BVISNULL( &newhash ) ) { + struct berval newhash = BER_BVNULL; + const char *txt; + + Debug(LDAP_DEBUG_ANY, "%s rehashing password with %s\n", + op->o_log_prefix, ppb->pp.pwdDefaultHash.bv_val ); + slap_passwd_hash_type( &newpw, &newhash, + ppb->pp.pwdDefaultHash.bv_val, &txt ); + if ( BER_BVISNULL( &newhash ) ) { + Debug( LDAP_DEBUG_ANY, "ppolicy_bind_response: " + "rehashing password for user %s failed: %s\n", + op->o_req_dn.bv_val, txt ); + } else { m = ch_calloc( sizeof(Modifications), 1 ); m->sml_op = LDAP_MOD_ADD; m->sml_flags = SLAP_MOD_INTERNAL; @@ -3127,6 +3128,7 @@ ppolicy_bind_response( Operation *op, SlapReply *rs ) m->sml_flags = SLAP_MOD_INTERNAL; m->sml_desc = ppb->pp.ad; m->sml_type = ppb->pp.ad->ad_cname; + m->sml_next = mod; m->sml_numvals = 1; m->sml_values = ch_calloc( sizeof( struct berval ), 2 ); ber_dupbv( &m->sml_values[0], &oldpw ); diff --git a/tests/data/ppolicy.ldif b/tests/data/ppolicy.ldif index 82601ef88f..a13fe9b134 100644 --- a/tests/data/ppolicy.ldif +++ b/tests/data/ppolicy.ldif @@ -99,6 +99,16 @@ objectClass: pwdPolicy cn: Test Policy pwdAttribute: 2.5.4.35 +dn: cn=Hashing Policy, ou=Policies, dc=example, dc=com +objectClass: top +objectClass: device +objectClass: pwdPolicy +objectClass: pwdHashingPolicy +cn: Hashing Policy +pwdAttribute: 2.5.4.35 +pwdDefaultHash: {SHA} +pwdRehashOnBind: TRUE + dn: uid=nd, ou=People, dc=example, dc=com objectClass: top objectClass: person @@ -130,6 +140,17 @@ givenName: Test userPassword: kfhgkjhfdgkfd pwdPolicySubEntry: cn=No Policy, ou=Policies, dc=example, dc=com +dn: uid=hashed, ou=People, dc=example, dc=com +objectClass: top +objectClass: person +objectClass: inetOrgPerson +cn: password gets rehashed +uid: hashed +sn: Hashed +givenName: hashed +userPassword: hashed +pwdPolicySubEntry: cn=Hashing Policy, ou=Policies, dc=example, dc=com + dn: uid=another, ou=People, dc=example, dc=com objectClass: top objectClass: person diff --git a/tests/data/slapd-ppolicy.conf b/tests/data/slapd-ppolicy.conf index 5f40e60061..0b7bcb85b1 100644 --- a/tests/data/slapd-ppolicy.conf +++ b/tests/data/slapd-ppolicy.conf @@ -46,6 +46,7 @@ ppolicy_rules filter="(description=idle)" policy_dn="cn=Idle Expiration Policy, ou=Policies, dc=example, dc=com" ppolicy_default "cn=Standard Policy,ou=Policies,dc=example,dc=com" ppolicy_use_lockout +ppolicy_hash_cleartext access to attrs=userpassword by self write diff --git a/tests/scripts/test022-ppolicy b/tests/scripts/test022-ppolicy index 1a679381b7..01f9541fee 100755 --- a/tests/scripts/test022-ppolicy +++ b/tests/scripts/test022-ppolicy @@ -546,6 +546,63 @@ if test $RC != 49 ; then exit 1 fi +echo "Listing a password hashed with a custom default, then rehashing..." + +# {SHA} is good that it doesn't use salt, we don't expect the base64 binary on +# all systems we support, so we precomputed the expected value: +# passwd -h '{SHA}' -s hashed -n | base64 +$LDAPSEARCH -o ldif-wrap=no -H $URI1 -D "$MANAGERDN" -w $PASSWD \ + -b "uid=hashed, ou=People, dc=example, dc=com" userPassword | \ + grep -q "userPassword:: e1NIQX1ZeGhWT0puYXJpbEJjWXdDVUlydTZUaXZHaHc9" +RC=$? +if test $RC != 0 ; then + echo "Unexpected password hash returned!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +$LDAPMODIFY -v -D "$MANAGERDN" -H $URI1 -w $PASSWD >> \ + $TESTOUT 2>&1 << EOMODS +dn: cn=Hashing Policy, ou=Policies, dc=example, dc=com +changetype: modify +replace: pwdDefaultHash +pwdDefaultHash: {SSHA} + +EOMODS +RC=$? +if test $RC != 0 ; then + echo "ldapmodify failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +# '{SSHA}' fits nicely onto base64 chunk length, we don't have to work too hard +# to check it as a prefix +$LDAPSEARCH -H $URI1 -D "uid=hashed, ou=People, dc=example, dc=com" -w hashed \ + -b "uid=hashed, ou=People, dc=example, dc=com" | \ + grep -q '^userPassword:: e1NTSEF9' +RC=$? +if test $RC != 0 ; then + echo "Password not rehashed as configured!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit $RC +fi + +$LDAPCOMPARE -D "$MANAGERDN" -H $URI1 -w $PASSWD \ + "uid=hashed, ou=People, dc=example, dc=com" "pwdReset:FALSE" \ + >> $TESTOUT 2>&1 +RC=$? +case $RC in +6) + ;; +16) + ;; +*) + echo "ldapcompare failed ($RC)!" + test $KILLSERVERS != no && kill -HUP $KILLPIDS + exit 1 +esac + echo "Reverting to Standard policy..." $LDAPMODIFY -v -D "$MANAGERDN" -H $URI1 -w $PASSWD >> \ $TESTOUT 2>&1 << EOMODS