|
|
dc8c34 |
From c7f195fdf33ae995c12ff43f5b9c03da3d25b8da Mon Sep 17 00:00:00 2001
|
|
|
dc8c34 |
From: Mark Reynolds <mreynolds@redhat.com>
|
|
|
dc8c34 |
Date: Tue, 3 May 2016 09:57:36 -0400
|
|
|
dc8c34 |
Subject: [PATCH 381/382] Ticket 48813 - password history is not updated when
|
|
|
dc8c34 |
an admin resets the password
|
|
|
dc8c34 |
|
|
|
dc8c34 |
Bug Description: When an admin resets a password the current password is not
|
|
|
dc8c34 |
stored in the password history. This incorrectly allows the
|
|
|
dc8c34 |
user to reuse the previous password after the reset.
|
|
|
dc8c34 |
|
|
|
dc8c34 |
Fix Description: When a password is being reset by an "admin", still grab the
|
|
|
dc8c34 |
old password so we can correctly update the password history.
|
|
|
dc8c34 |
|
|
|
dc8c34 |
https://fedorahosted.org/389/ticket/48813
|
|
|
dc8c34 |
|
|
|
dc8c34 |
Reviewed by: nhosoi(Thanks!)
|
|
|
dc8c34 |
|
|
|
dc8c34 |
(cherry picked from commit 9c310b09c481a32b1a012371c688c65156b33472)
|
|
|
dc8c34 |
(cherry picked from commit b357e443d06f32bcad2f410868299d43153dca62)
|
|
|
dc8c34 |
(cherry picked from commit 0a5047043051701d5b361500f605d782a2befa1d)
|
|
|
dc8c34 |
---
|
|
|
dc8c34 |
.../tests/suites/password/pwp_history_test.py | 264 +++++++++++++++++++++
|
|
|
dc8c34 |
ldap/servers/slapd/modify.c | 4 +
|
|
|
dc8c34 |
ldap/servers/slapd/proto-slap.h | 1 +
|
|
|
dc8c34 |
ldap/servers/slapd/pw.c | 29 +++
|
|
|
dc8c34 |
4 files changed, 298 insertions(+)
|
|
|
dc8c34 |
create mode 100644 dirsrvtests/tests/suites/password/pwp_history_test.py
|
|
|
dc8c34 |
|
|
|
dc8c34 |
diff --git a/dirsrvtests/tests/suites/password/pwp_history_test.py b/dirsrvtests/tests/suites/password/pwp_history_test.py
|
|
|
dc8c34 |
new file mode 100644
|
|
|
dc8c34 |
index 0000000..3f66efd
|
|
|
dc8c34 |
--- /dev/null
|
|
|
dc8c34 |
+++ b/dirsrvtests/tests/suites/password/pwp_history_test.py
|
|
|
dc8c34 |
@@ -0,0 +1,264 @@
|
|
|
dc8c34 |
+import os
|
|
|
dc8c34 |
+import ldap
|
|
|
dc8c34 |
+import logging
|
|
|
dc8c34 |
+import pytest
|
|
|
dc8c34 |
+from lib389 import DirSrv, Entry
|
|
|
dc8c34 |
+from lib389._constants import *
|
|
|
dc8c34 |
+from lib389.properties import *
|
|
|
dc8c34 |
+from lib389.tasks import *
|
|
|
dc8c34 |
+from lib389.utils import *
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+logging.getLogger(__name__).setLevel(logging.DEBUG)
|
|
|
dc8c34 |
+log = logging.getLogger(__name__)
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+class TopologyStandalone(object):
|
|
|
dc8c34 |
+ """ Topology class """
|
|
|
dc8c34 |
+ def __init__(self, standalone):
|
|
|
dc8c34 |
+ """ init """
|
|
|
dc8c34 |
+ standalone.open()
|
|
|
dc8c34 |
+ self.standalone = standalone
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+@pytest.fixture(scope="module")
|
|
|
dc8c34 |
+def topology(request):
|
|
|
dc8c34 |
+ """
|
|
|
dc8c34 |
+ Creating standalone instance ...
|
|
|
dc8c34 |
+ """
|
|
|
dc8c34 |
+ standalone = DirSrv(verbose=False)
|
|
|
dc8c34 |
+ args_instance[SER_HOST] = HOST_STANDALONE
|
|
|
dc8c34 |
+ args_instance[SER_PORT] = PORT_STANDALONE
|
|
|
dc8c34 |
+ args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
|
|
|
dc8c34 |
+ args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX
|
|
|
dc8c34 |
+ args_standalone = args_instance.copy()
|
|
|
dc8c34 |
+ standalone.allocate(args_standalone)
|
|
|
dc8c34 |
+ instance_standalone = standalone.exists()
|
|
|
dc8c34 |
+ if instance_standalone:
|
|
|
dc8c34 |
+ standalone.delete()
|
|
|
dc8c34 |
+ standalone.create()
|
|
|
dc8c34 |
+ standalone.open()
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ # Delete each instance in the end
|
|
|
dc8c34 |
+ def fin():
|
|
|
dc8c34 |
+ """ Clean up instance """
|
|
|
dc8c34 |
+ standalone.delete()
|
|
|
dc8c34 |
+ request.addfinalizer(fin)
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ # Clear out the tmp dir
|
|
|
dc8c34 |
+ standalone.clearTmpDir(__file__)
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ return TopologyStandalone(standalone)
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+def test_pwp_history_test(topology):
|
|
|
dc8c34 |
+ """
|
|
|
dc8c34 |
+ Test password policy history feature:
|
|
|
dc8c34 |
+ - Test password history is enforced
|
|
|
dc8c34 |
+ - Test password history works after an Admin resets the password
|
|
|
dc8c34 |
+ - Test that the correct number of passwords are stored in history
|
|
|
dc8c34 |
+ """
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ USER_DN = 'uid=testuser,' + DEFAULT_SUFFIX
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ #
|
|
|
dc8c34 |
+ # Configure password history policy and add a test user
|
|
|
dc8c34 |
+ #
|
|
|
dc8c34 |
+ try:
|
|
|
dc8c34 |
+ topology.standalone.modify_s("cn=config",
|
|
|
dc8c34 |
+ [(ldap.MOD_REPLACE,
|
|
|
dc8c34 |
+ 'passwordHistory', 'on'),
|
|
|
dc8c34 |
+ (ldap.MOD_REPLACE,
|
|
|
dc8c34 |
+ 'passwordInHistory', '3'),
|
|
|
dc8c34 |
+ (ldap.MOD_REPLACE,
|
|
|
dc8c34 |
+ 'passwordChange', 'on'),
|
|
|
dc8c34 |
+ (ldap.MOD_REPLACE,
|
|
|
dc8c34 |
+ 'passwordStorageScheme', 'CLEAR')])
|
|
|
dc8c34 |
+ log.info('Configured password policy.')
|
|
|
dc8c34 |
+ except ldap.LDAPError as e:
|
|
|
dc8c34 |
+ log.fatal('Failed to configure password policy: ' + str(e))
|
|
|
dc8c34 |
+ assert False
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ try:
|
|
|
dc8c34 |
+ topology.standalone.add_s(Entry((USER_DN, {
|
|
|
dc8c34 |
+ 'objectclass': ['top', 'extensibleObject'],
|
|
|
dc8c34 |
+ 'sn': 'user',
|
|
|
dc8c34 |
+ 'cn': 'test user',
|
|
|
dc8c34 |
+ 'uid': 'testuser',
|
|
|
dc8c34 |
+ 'userpassword': 'password'})))
|
|
|
dc8c34 |
+ except ldap.LDAPError as e:
|
|
|
dc8c34 |
+ log.fatal('Failed to add test user' + USER_DN + ': error ' + str(e))
|
|
|
dc8c34 |
+ assert False
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ #
|
|
|
dc8c34 |
+ # Test that password history is enforced.
|
|
|
dc8c34 |
+ #
|
|
|
dc8c34 |
+ try:
|
|
|
dc8c34 |
+ topology.standalone.simple_bind_s(USER_DN, 'password')
|
|
|
dc8c34 |
+ except ldap.LDAPError as e:
|
|
|
dc8c34 |
+ log.fatal('Failed to bind as user: ' + str(e))
|
|
|
dc8c34 |
+ assert False
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ # Attempt to change password to the same password
|
|
|
dc8c34 |
+ try:
|
|
|
dc8c34 |
+ topology.standalone.modify_s(USER_DN, [(ldap.MOD_REPLACE,
|
|
|
dc8c34 |
+ 'userpassword', 'password')])
|
|
|
dc8c34 |
+ log.info('Incorrectly able to to set password to existing password.')
|
|
|
dc8c34 |
+ assert False
|
|
|
dc8c34 |
+ except ldap.CONSTRAINT_VIOLATION:
|
|
|
dc8c34 |
+ log.info('Password change correctly rejected')
|
|
|
dc8c34 |
+ except ldap.LDAPError as e:
|
|
|
dc8c34 |
+ log.fatal('Failed to attempt to change password: ' + str(e))
|
|
|
dc8c34 |
+ assert False
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ #
|
|
|
dc8c34 |
+ # Keep changing password until we fill the password history (3)
|
|
|
dc8c34 |
+ #
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ # password1
|
|
|
dc8c34 |
+ try:
|
|
|
dc8c34 |
+ topology.standalone.modify_s(USER_DN, [(ldap.MOD_REPLACE,
|
|
|
dc8c34 |
+ 'userpassword', 'password1')])
|
|
|
dc8c34 |
+ except ldap.LDAPError as e:
|
|
|
dc8c34 |
+ log.fatal('Failed to change password: ' + str(e))
|
|
|
dc8c34 |
+ assert False
|
|
|
dc8c34 |
+ try:
|
|
|
dc8c34 |
+ topology.standalone.simple_bind_s(USER_DN, 'password1')
|
|
|
dc8c34 |
+ except ldap.LDAPError as e:
|
|
|
dc8c34 |
+ log.fatal('Failed to bind as user using "password1": ' + str(e))
|
|
|
dc8c34 |
+ assert False
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ # password2
|
|
|
dc8c34 |
+ try:
|
|
|
dc8c34 |
+ topology.standalone.modify_s(USER_DN, [(ldap.MOD_REPLACE,
|
|
|
dc8c34 |
+ 'userpassword', 'password2')])
|
|
|
dc8c34 |
+ except ldap.LDAPError as e:
|
|
|
dc8c34 |
+ log.fatal('Failed to change password: ' + str(e))
|
|
|
dc8c34 |
+ assert False
|
|
|
dc8c34 |
+ try:
|
|
|
dc8c34 |
+ topology.standalone.simple_bind_s(USER_DN, 'password2')
|
|
|
dc8c34 |
+ except ldap.LDAPError as e:
|
|
|
dc8c34 |
+ log.fatal('Failed to bind as user using "password2": ' + str(e))
|
|
|
dc8c34 |
+ assert False
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ # password3
|
|
|
dc8c34 |
+ try:
|
|
|
dc8c34 |
+ topology.standalone.modify_s(USER_DN, [(ldap.MOD_REPLACE,
|
|
|
dc8c34 |
+ 'userpassword', 'password3')])
|
|
|
dc8c34 |
+ except ldap.LDAPError as e:
|
|
|
dc8c34 |
+ log.fatal('Failed to change password: ' + str(e))
|
|
|
dc8c34 |
+ assert False
|
|
|
dc8c34 |
+ try:
|
|
|
dc8c34 |
+ topology.standalone.simple_bind_s(USER_DN, 'password3')
|
|
|
dc8c34 |
+ except ldap.LDAPError as e:
|
|
|
dc8c34 |
+ log.fatal('Failed to bind as user using "password3": ' + str(e))
|
|
|
dc8c34 |
+ assert False
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ # password4
|
|
|
dc8c34 |
+ try:
|
|
|
dc8c34 |
+ topology.standalone.modify_s(USER_DN, [(ldap.MOD_REPLACE,
|
|
|
dc8c34 |
+ 'userpassword', 'password4')])
|
|
|
dc8c34 |
+ except ldap.LDAPError as e:
|
|
|
dc8c34 |
+ log.fatal('Failed to change password: ' + str(e))
|
|
|
dc8c34 |
+ assert False
|
|
|
dc8c34 |
+ try:
|
|
|
dc8c34 |
+ topology.standalone.simple_bind_s(USER_DN, 'password4')
|
|
|
dc8c34 |
+ except ldap.LDAPError as e:
|
|
|
dc8c34 |
+ log.fatal('Failed to bind as user using "password4": ' + str(e))
|
|
|
dc8c34 |
+ assert False
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ #
|
|
|
dc8c34 |
+ # Check that we only have 3 passwords stored in history\
|
|
|
dc8c34 |
+ #
|
|
|
dc8c34 |
+ try:
|
|
|
dc8c34 |
+ entry = topology.standalone.search_s(USER_DN, ldap.SCOPE_BASE,
|
|
|
dc8c34 |
+ 'objectclass=*',
|
|
|
dc8c34 |
+ ['passwordHistory'])
|
|
|
dc8c34 |
+ pwds = entry[0].getValues('passwordHistory')
|
|
|
dc8c34 |
+ if len(pwds) != 3:
|
|
|
dc8c34 |
+ log.fatal('Incorrect number of passwords stored in histry: %d' %
|
|
|
dc8c34 |
+ len(pwds))
|
|
|
dc8c34 |
+ assert False
|
|
|
dc8c34 |
+ else:
|
|
|
dc8c34 |
+ log.info('Correct number of passwords found in history.')
|
|
|
dc8c34 |
+ except ldap.LDAPError as e:
|
|
|
dc8c34 |
+ log.fatal('Failed to get user entry: ' + str(e))
|
|
|
dc8c34 |
+ assert False
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ #
|
|
|
dc8c34 |
+ # Attempt to change the password to previous passwords
|
|
|
dc8c34 |
+ #
|
|
|
dc8c34 |
+ try:
|
|
|
dc8c34 |
+ topology.standalone.modify_s(USER_DN, [(ldap.MOD_REPLACE,
|
|
|
dc8c34 |
+ 'userpassword', 'password1')])
|
|
|
dc8c34 |
+ log.info('Incorrectly able to to set password to previous password1.')
|
|
|
dc8c34 |
+ assert False
|
|
|
dc8c34 |
+ except ldap.CONSTRAINT_VIOLATION:
|
|
|
dc8c34 |
+ log.info('Password change correctly rejected')
|
|
|
dc8c34 |
+ except ldap.LDAPError as e:
|
|
|
dc8c34 |
+ log.fatal('Failed to attempt to change password: ' + str(e))
|
|
|
dc8c34 |
+ assert False
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ try:
|
|
|
dc8c34 |
+ topology.standalone.modify_s(USER_DN, [(ldap.MOD_REPLACE,
|
|
|
dc8c34 |
+ 'userpassword', 'password2')])
|
|
|
dc8c34 |
+ log.info('Incorrectly able to to set password to previous password2.')
|
|
|
dc8c34 |
+ assert False
|
|
|
dc8c34 |
+ except ldap.CONSTRAINT_VIOLATION:
|
|
|
dc8c34 |
+ log.info('Password change correctly rejected')
|
|
|
dc8c34 |
+ except ldap.LDAPError as e:
|
|
|
dc8c34 |
+ log.fatal('Failed to attempt to change password: ' + str(e))
|
|
|
dc8c34 |
+ assert False
|
|
|
dc8c34 |
+ try:
|
|
|
dc8c34 |
+ topology.standalone.modify_s(USER_DN, [(ldap.MOD_REPLACE,
|
|
|
dc8c34 |
+ 'userpassword', 'password3')])
|
|
|
dc8c34 |
+ log.info('Incorrectly able to to set password to previous password3.')
|
|
|
dc8c34 |
+ assert False
|
|
|
dc8c34 |
+ except ldap.CONSTRAINT_VIOLATION:
|
|
|
dc8c34 |
+ log.info('Password change correctly rejected')
|
|
|
dc8c34 |
+ except ldap.LDAPError as e:
|
|
|
dc8c34 |
+ log.fatal('Failed to attempt to change password: ' + str(e))
|
|
|
dc8c34 |
+ assert False
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ #
|
|
|
dc8c34 |
+ # Reset password by Directory Manager(admin reset)
|
|
|
dc8c34 |
+ #
|
|
|
dc8c34 |
+ try:
|
|
|
dc8c34 |
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
|
|
|
dc8c34 |
+ except ldap.LDAPError as e:
|
|
|
dc8c34 |
+ log.fatal('Failed to bind as rootDN: ' + str(e))
|
|
|
dc8c34 |
+ assert False
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ try:
|
|
|
dc8c34 |
+ topology.standalone.modify_s(USER_DN, [(ldap.MOD_REPLACE,
|
|
|
dc8c34 |
+ 'userpassword',
|
|
|
dc8c34 |
+ 'password-reset')])
|
|
|
dc8c34 |
+ except ldap.LDAPError as e:
|
|
|
dc8c34 |
+ log.fatal('Failed to attempt to reset password: ' + str(e))
|
|
|
dc8c34 |
+ assert False
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ # Try and change the password to the previous password before the reset
|
|
|
dc8c34 |
+ try:
|
|
|
dc8c34 |
+ topology.standalone.simple_bind_s(USER_DN, 'password-reset')
|
|
|
dc8c34 |
+ except ldap.LDAPError as e:
|
|
|
dc8c34 |
+ log.fatal('Failed to bind as user: ' + str(e))
|
|
|
dc8c34 |
+ assert False
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ try:
|
|
|
dc8c34 |
+ topology.standalone.modify_s(USER_DN, [(ldap.MOD_REPLACE,
|
|
|
dc8c34 |
+ 'userpassword', 'password4')])
|
|
|
dc8c34 |
+ log.info('Incorrectly able to to set password to previous password4.')
|
|
|
dc8c34 |
+ assert False
|
|
|
dc8c34 |
+ except ldap.CONSTRAINT_VIOLATION:
|
|
|
dc8c34 |
+ log.info('Password change correctly rejected')
|
|
|
dc8c34 |
+ except ldap.LDAPError as e:
|
|
|
dc8c34 |
+ log.fatal('Failed to attempt to change password: ' + str(e))
|
|
|
dc8c34 |
+ assert False
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ log.info('Test suite PASSED.')
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+if __name__ == '__main__':
|
|
|
dc8c34 |
+ # Run isolated
|
|
|
dc8c34 |
+ # -s for DEBUG mode
|
|
|
dc8c34 |
+ CURRENT_FILE = os.path.realpath(__file__)
|
|
|
dc8c34 |
+ pytest.main("-s %s" % CURRENT_FILE)
|
|
|
dc8c34 |
diff --git a/ldap/servers/slapd/modify.c b/ldap/servers/slapd/modify.c
|
|
|
dc8c34 |
index c67ef14..4bcc827 100644
|
|
|
dc8c34 |
--- a/ldap/servers/slapd/modify.c
|
|
|
dc8c34 |
+++ b/ldap/servers/slapd/modify.c
|
|
|
dc8c34 |
@@ -1259,6 +1259,10 @@ static int op_shared_allow_pw_change (Slapi_PBlock *pb, LDAPMod *mod, char **old
|
|
|
dc8c34 |
* just return success.
|
|
|
dc8c34 |
*/
|
|
|
dc8c34 |
if(pw_is_pwp_admin(pb, pwpolicy)){
|
|
|
dc8c34 |
+ if (!SLAPI_IS_MOD_DELETE(mod->mod_op) && pwpolicy->pw_history){
|
|
|
dc8c34 |
+ /* Updating pw history, get the old password */
|
|
|
dc8c34 |
+ get_old_pw(pb, &sdn, old_pw);
|
|
|
dc8c34 |
+ }
|
|
|
dc8c34 |
rc = 1;
|
|
|
dc8c34 |
goto done;
|
|
|
dc8c34 |
}
|
|
|
dc8c34 |
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
|
|
|
dc8c34 |
index decc29e..3b00c80 100644
|
|
|
dc8c34 |
--- a/ldap/servers/slapd/proto-slap.h
|
|
|
dc8c34 |
+++ b/ldap/servers/slapd/proto-slap.h
|
|
|
dc8c34 |
@@ -906,6 +906,7 @@ int check_pw_syntax( Slapi_PBlock *pb, const Slapi_DN *sdn, Slapi_Value **vals,
|
|
|
dc8c34 |
char **old_pw, Slapi_Entry *e, int mod_op );
|
|
|
dc8c34 |
int check_pw_syntax_ext( Slapi_PBlock *pb, const Slapi_DN *sdn, Slapi_Value **vals,
|
|
|
dc8c34 |
char **old_pw, Slapi_Entry *e, int mod_op, Slapi_Mods *smods );
|
|
|
dc8c34 |
+void get_old_pw( Slapi_PBlock *pb, const Slapi_DN *sdn, char **old_pw);
|
|
|
dc8c34 |
int check_account_lock( Slapi_PBlock *pb, Slapi_Entry * bind_target_entry, int pwresponse_req, int account_inactivation_only /*no wire/no pw policy*/);
|
|
|
dc8c34 |
int check_pw_minage( Slapi_PBlock *pb, const Slapi_DN *sdn, struct berval **vals) ;
|
|
|
dc8c34 |
void add_password_attrs( Slapi_PBlock *pb, Operation *op, Slapi_Entry *e );
|
|
|
dc8c34 |
diff --git a/ldap/servers/slapd/pw.c b/ldap/servers/slapd/pw.c
|
|
|
dc8c34 |
index dea949c..ab624e7 100644
|
|
|
dc8c34 |
--- a/ldap/servers/slapd/pw.c
|
|
|
dc8c34 |
+++ b/ldap/servers/slapd/pw.c
|
|
|
dc8c34 |
@@ -1084,6 +1084,35 @@ retry:
|
|
|
dc8c34 |
}
|
|
|
dc8c34 |
|
|
|
dc8c34 |
/*
|
|
|
dc8c34 |
+ * Get the old password -used by password admin so we properly
|
|
|
dc8c34 |
+ * update pw history when reseting a password.
|
|
|
dc8c34 |
+ */
|
|
|
dc8c34 |
+void
|
|
|
dc8c34 |
+get_old_pw( Slapi_PBlock *pb, const Slapi_DN *sdn, char **old_pw )
|
|
|
dc8c34 |
+{
|
|
|
dc8c34 |
+ Slapi_Entry *e = NULL;
|
|
|
dc8c34 |
+ Slapi_Value **va = NULL;
|
|
|
dc8c34 |
+ Slapi_Attr *attr = NULL;
|
|
|
dc8c34 |
+ char *dn = (char*)slapi_sdn_get_ndn(sdn);
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ e = get_entry ( pb, dn );
|
|
|
dc8c34 |
+ if ( e == NULL ) {
|
|
|
dc8c34 |
+ return;
|
|
|
dc8c34 |
+ }
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ /* get current password, and remember it */
|
|
|
dc8c34 |
+ attr = attrlist_find(e->e_attrs, "userpassword");
|
|
|
dc8c34 |
+ if ( attr && !valueset_isempty(&attr->a_present_values) ) {
|
|
|
dc8c34 |
+ va = valueset_get_valuearray(&attr->a_present_values);
|
|
|
dc8c34 |
+ *old_pw = slapi_ch_strdup(slapi_value_get_string(va[0]));
|
|
|
dc8c34 |
+ } else {
|
|
|
dc8c34 |
+ *old_pw = NULL;
|
|
|
dc8c34 |
+ }
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ slapi_entry_free(e);
|
|
|
dc8c34 |
+}
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+/*
|
|
|
dc8c34 |
* Basically, h0 and h1 must be longer than GENERALIZED_TIME_LENGTH.
|
|
|
dc8c34 |
*/
|
|
|
dc8c34 |
static int
|
|
|
dc8c34 |
--
|
|
|
dc8c34 |
2.4.11
|
|
|
dc8c34 |
|