]> git.ipfire.org Git - thirdparty/openldap.git/commitdiff
ITS#10254 Fix rehashing logic and add tests
authorOndřej Kuzník <ondra@mistotebe.net>
Thu, 31 Jul 2025 14:09:16 +0000 (15:09 +0100)
committerQuanah Gibson-Mount <quanah@openldap.org>
Tue, 5 Aug 2025 15:35:34 +0000 (15:35 +0000)
servers/slapd/overlays/ppolicy.c
tests/data/ppolicy.ldif
tests/data/slapd-ppolicy.conf
tests/scripts/test022-ppolicy

index c5d017a3bb4cf89777bc8aa476a27c503dace1be..a0a17d80196176e76ffc80583eb38e907257a9ae 100644 (file)
@@ -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 );
index 82601ef88f935c171b4114f6a2669b2e472134e9..a13fe9b134cae85b89c8b98b67f3e87c3dfc4d4a 100644 (file)
@@ -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
index 5f40e600615f14451d29456f69a7c201e2b6f47f..0b7bcb85b1091aa0eae14707280991f2cba80c14 100644 (file)
@@ -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
index 1a679381b7bc070ac6da52be2599453456df05b1..01f9541fee0475310fa87fd01e51d69ddc5cf3f1 100755 (executable)
@@ -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