bdd565
From 23956cfb86a312318667fb9376322574fa8ec7f4 Mon Sep 17 00:00:00 2001
bdd565
From: James Chapman <jachapma@redhat.com>
bdd565
Date: Wed, 1 May 2024 15:01:33 +0100
bdd565
Subject: [PATCH] CVE-2024-2199
bdd565
bdd565
---
bdd565
 .../tests/suites/password/password_test.py    | 56 +++++++++++++++++++
bdd565
 ldap/servers/slapd/modify.c                   |  8 ++-
bdd565
 2 files changed, 62 insertions(+), 2 deletions(-)
bdd565
bdd565
diff --git a/dirsrvtests/tests/suites/password/password_test.py b/dirsrvtests/tests/suites/password/password_test.py
bdd565
index 1245feb31..e4abd9907 100644
bdd565
--- a/dirsrvtests/tests/suites/password/password_test.py
bdd565
+++ b/dirsrvtests/tests/suites/password/password_test.py
bdd565
@@ -63,6 +63,62 @@ def test_password_delete_specific_password(topology_st):
bdd565
     log.info('test_password_delete_specific_password: PASSED')
bdd565
 
bdd565
 
bdd565
+def test_password_modify_non_utf8(topology_st):
bdd565
+    """Attempt a modify of the userPassword attribute with
bdd565
+    an invalid non utf8 value
bdd565
+
bdd565
+    :id: a31af9d5-d665-42b9-8d6e-fea3d0837d36
bdd565
+    :setup: Standalone instance
bdd565
+    :steps:
bdd565
+        1. Add a user if it doesnt exist and set its password
bdd565
+        2. Verify password with a bind
bdd565
+        3. Modify userPassword attr with invalid value
bdd565
+        4. Attempt a bind with invalid password value
bdd565
+        5. Verify original password with a bind
bdd565
+    :expectedresults:
bdd565
+        1. The user with userPassword should be added successfully
bdd565
+        2. Operation should be successful
bdd565
+        3. Server returns ldap.UNWILLING_TO_PERFORM
bdd565
+        4. Server returns ldap.INVALID_CREDENTIALS
bdd565
+        5. Operation should be successful
bdd565
+     """
bdd565
+
bdd565
+    log.info('Running test_password_modify_non_utf8...')
bdd565
+
bdd565
+    # Create user and set password
bdd565
+    standalone = topology_st.standalone
bdd565
+    users = UserAccounts(standalone, DEFAULT_SUFFIX)
bdd565
+    if not users.exists(TEST_USER_PROPERTIES['uid'][0]):
bdd565
+        user = users.create(properties=TEST_USER_PROPERTIES)
bdd565
+    else:
bdd565
+        user = users.get(TEST_USER_PROPERTIES['uid'][0])
bdd565
+    user.set('userpassword', PASSWORD)
bdd565
+
bdd565
+    # Verify password
bdd565
+    try:
bdd565
+        user.bind(PASSWORD)
bdd565
+    except ldap.LDAPError as e:
bdd565
+        log.fatal('Failed to bind as {}, error: '.format(user.dn) + e.args[0]['desc'])
bdd565
+        assert False
bdd565
+
bdd565
+    # Modify userPassword with an invalid value
bdd565
+    password = b'tes\x82t-password' # A non UTF-8 encoded password
bdd565
+    with pytest.raises(ldap.UNWILLING_TO_PERFORM):
bdd565
+        user.replace('userpassword', password)
bdd565
+
bdd565
+    # Verify a bind fails with invalid pasword
bdd565
+    with pytest.raises(ldap.INVALID_CREDENTIALS):
bdd565
+        user.bind(password)
bdd565
+
bdd565
+    # Verify we can still bind with original password
bdd565
+    try:
bdd565
+        user.bind(PASSWORD)
bdd565
+    except ldap.LDAPError as e:
bdd565
+        log.fatal('Failed to bind as {}, error: '.format(user.dn) + e.args[0]['desc'])
bdd565
+        assert False
bdd565
+
bdd565
+    log.info('test_password_modify_non_utf8: PASSED')
bdd565
+
bdd565
 if __name__ == '__main__':
bdd565
     # Run isolated
bdd565
     # -s for DEBUG mode
bdd565
diff --git a/ldap/servers/slapd/modify.c b/ldap/servers/slapd/modify.c
bdd565
index a20984e0b..fb65d58b3 100644
bdd565
--- a/ldap/servers/slapd/modify.c
bdd565
+++ b/ldap/servers/slapd/modify.c
bdd565
@@ -762,8 +762,10 @@ op_shared_modify(Slapi_PBlock *pb, int pw_change, char *old_pw)
bdd565
      * flagged - leave mod attributes alone */
bdd565
     if (!repl_op && !skip_modified_attrs && lastmod) {
bdd565
         modify_update_last_modified_attr(pb, &smods);
bdd565
+        slapi_pblock_set(pb, SLAPI_MODIFY_MODS, slapi_mods_get_ldapmods_byref(&smods));
bdd565
     }
bdd565
 
bdd565
+
bdd565
     if (0 == slapi_mods_get_num_mods(&smods)) {
bdd565
         /* nothing to do - no mods - this is not an error - just
bdd565
            send back LDAP_SUCCESS */
bdd565
@@ -930,8 +932,10 @@ op_shared_modify(Slapi_PBlock *pb, int pw_change, char *old_pw)
bdd565
 
bdd565
             /* encode password */
bdd565
             if (pw_encodevals_ext(pb, sdn, va)) {
bdd565
-                slapi_log_err(SLAPI_LOG_CRIT, "op_shared_modify", "Unable to hash userPassword attribute for %s.\n", slapi_entry_get_dn_const(e));
bdd565
-                send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL, "Unable to store attribute \"userPassword\" correctly\n", 0, NULL);
bdd565
+                slapi_log_err(SLAPI_LOG_CRIT, "op_shared_modify", "Unable to hash userPassword attribute for %s, "
bdd565
+                    "check value is utf8 string.\n", slapi_entry_get_dn_const(e));
bdd565
+                send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL, "Unable to hash \"userPassword\" attribute, "
bdd565
+                    "check value is utf8 string.\n", 0, NULL);
bdd565
                 valuearray_free(&va);
bdd565
                 goto free_and_return;
bdd565
             }
bdd565
-- 
bdd565
2.41.0
bdd565