Blame SOURCES/0001-Issue-4383-Do-not-normalize-escaped-spaces-in-a-DN.patch

47c2e9
From 81dcaf1c37c2de24c46672df8d4f968c2fb40a6e Mon Sep 17 00:00:00 2001
47c2e9
From: Mark Reynolds <mreynolds@redhat.com>
47c2e9
Date: Wed, 11 Nov 2020 08:59:18 -0500
47c2e9
Subject: [PATCH 1/3] Issue 4383 - Do not normalize escaped spaces in a DN
47c2e9
47c2e9
Bug Description:  Adding an entry with an escaped leading space leads to many
47c2e9
                  problems.  Mainly id2entry can get corrupted during an
47c2e9
                  import of such an entry, and the entryrdn index is not
47c2e9
                  updated correctly
47c2e9
47c2e9
Fix Description:  In slapi_dn_normalize_ext() leave an escaped space intact.
47c2e9
47c2e9
Relates: https://github.com/389ds/389-ds-base/issues/4383
47c2e9
47c2e9
Reviewed by: firstyear, progier, and tbordaz (Thanks!!!)
47c2e9
---
47c2e9
 .../tests/suites/syntax/acceptance_test.py    | 75 ++++++++++++++++++-
47c2e9
 ldap/servers/slapd/dn.c                       |  8 +-
47c2e9
 2 files changed, 77 insertions(+), 6 deletions(-)
47c2e9
47c2e9
diff --git a/dirsrvtests/tests/suites/syntax/acceptance_test.py b/dirsrvtests/tests/suites/syntax/acceptance_test.py
47c2e9
index 543718689..7939a99a7 100644
47c2e9
--- a/dirsrvtests/tests/suites/syntax/acceptance_test.py
47c2e9
+++ b/dirsrvtests/tests/suites/syntax/acceptance_test.py
47c2e9
@@ -1,5 +1,5 @@
47c2e9
 # --- BEGIN COPYRIGHT BLOCK ---
47c2e9
-# Copyright (C) 2019 Red Hat, Inc.
47c2e9
+# Copyright (C) 2020 Red Hat, Inc.
47c2e9
 # All rights reserved.
47c2e9
 #
47c2e9
 # License: GPL (version 3 or any later version).
47c2e9
@@ -7,13 +7,12 @@
47c2e9
 # --- END COPYRIGHT BLOCK ---
47c2e9
 
47c2e9
 import ldap
47c2e9
-import logging
47c2e9
 import pytest
47c2e9
 import os
47c2e9
 from lib389.schema import Schema
47c2e9
 from lib389.config import Config
47c2e9
 from lib389.idm.user import UserAccounts
47c2e9
-from lib389.idm.group import Groups
47c2e9
+from lib389.idm.group import Group, Groups
47c2e9
 from lib389._constants import DEFAULT_SUFFIX
47c2e9
 from lib389.topologies import log, topology_st as topo
47c2e9
 
47c2e9
@@ -127,7 +126,7 @@ def test_invalid_dn_syntax_crash(topo):
47c2e9
         4. Success
47c2e9
     """
47c2e9
 
47c2e9
-    # Create group
47c2e9
+        # Create group
47c2e9
     groups = Groups(topo.standalone, DEFAULT_SUFFIX)
47c2e9
     group = groups.create(properties={'cn': ' test'})
47c2e9
 
47c2e9
@@ -145,6 +144,74 @@ def test_invalid_dn_syntax_crash(topo):
47c2e9
     groups.list()
47c2e9
 
47c2e9
 
47c2e9
+@pytest.mark.parametrize("props, rawdn", [
47c2e9
+                         ({'cn': ' leadingSpace'}, "cn=\\20leadingSpace,ou=Groups,dc=example,dc=com"),
47c2e9
+                         ({'cn': 'trailingSpace '}, "cn=trailingSpace\\20,ou=Groups,dc=example,dc=com")])
47c2e9
+def test_dn_syntax_spaces_delete(topo,  props,  rawdn):
47c2e9
+    """Test that an entry with a space as the first character in the DN can be
47c2e9
+    deleted without error.  We also want to make sure the indexes are properly
47c2e9
+    updated by repeatedly adding and deleting the entry, and that the entry cache
47c2e9
+    is properly maintained.
47c2e9
+
47c2e9
+    :id: b993f37c-c2b0-4312-992c-a9048ff98965
47c2e9
+    :parametrized: yes
47c2e9
+    :setup: Standalone Instance
47c2e9
+    :steps:
47c2e9
+        1. Create a group with a DN that has a space as the first/last
47c2e9
+           character.
47c2e9
+        2. Delete group
47c2e9
+        3. Add group
47c2e9
+        4. Modify group
47c2e9
+        5. Restart server and modify entry
47c2e9
+        6. Delete group
47c2e9
+        7. Add group back
47c2e9
+        8. Delete group using specific DN
47c2e9
+    :expectedresults:
47c2e9
+        1. Success
47c2e9
+        2. Success
47c2e9
+        3. Success
47c2e9
+        4. Success
47c2e9
+        5. Success
47c2e9
+        6. Success
47c2e9
+        7. Success
47c2e9
+        8. Success
47c2e9
+    """
47c2e9
+
47c2e9
+    # Create group
47c2e9
+    groups = Groups(topo.standalone, DEFAULT_SUFFIX)
47c2e9
+    group = groups.create(properties=props.copy())
47c2e9
+
47c2e9
+    # Delete group (verifies DN/RDN parsing works and cache is correct)
47c2e9
+    group.delete()
47c2e9
+
47c2e9
+    # Add group again (verifies entryrdn index was properly updated)
47c2e9
+    groups = Groups(topo.standalone, DEFAULT_SUFFIX)
47c2e9
+    group = groups.create(properties=props.copy())
47c2e9
+
47c2e9
+    # Modify the group (verifies dn/rdn parsing is correct)
47c2e9
+    group.replace('description', 'escaped space group')
47c2e9
+
47c2e9
+    # Restart the server.  This will pull the entry from the database and
47c2e9
+    # convert it into a cache entry, which is different than how a client
47c2e9
+    # first adds an entry and is put into the cache before being written to
47c2e9
+    # disk.
47c2e9
+    topo.standalone.restart()
47c2e9
+
47c2e9
+    # Make sure we can modify the entry (verifies cache entry was created
47c2e9
+    # correctly)
47c2e9
+    group.replace('description', 'escaped space group after restart')
47c2e9
+
47c2e9
+    # Make sure it can still be deleted (verifies cache again).
47c2e9
+    group.delete()
47c2e9
+
47c2e9
+    # Add it back so we can delete it using a specific DN (sanity test to verify
47c2e9
+    # another DN/RDN parsing variation).
47c2e9
+    groups = Groups(topo.standalone, DEFAULT_SUFFIX)
47c2e9
+    group = groups.create(properties=props.copy())
47c2e9
+    group = Group(topo.standalone, dn=rawdn)
47c2e9
+    group.delete()
47c2e9
+
47c2e9
+
47c2e9
 if __name__ == '__main__':
47c2e9
     # Run isolated
47c2e9
     # -s for DEBUG mode
47c2e9
diff --git a/ldap/servers/slapd/dn.c b/ldap/servers/slapd/dn.c
47c2e9
index 2af3f38fc..3980b897f 100644
47c2e9
--- a/ldap/servers/slapd/dn.c
47c2e9
+++ b/ldap/servers/slapd/dn.c
47c2e9
@@ -894,8 +894,7 @@ slapi_dn_normalize_ext(char *src, size_t src_len, char **dest, size_t *dest_len)
47c2e9
                             s++;
47c2e9
                         }
47c2e9
                     }
47c2e9
-                } else if (s + 2 < ends &&
47c2e9
-                           isxdigit(*(s + 1)) && isxdigit(*(s + 2))) {
47c2e9
+                } else if (s + 2 < ends && isxdigit(*(s + 1)) && isxdigit(*(s + 2))) {
47c2e9
                     /* esc hexpair ==> real character */
47c2e9
                     int n = slapi_hexchar2int(*(s + 1));
47c2e9
                     int n2 = slapi_hexchar2int(*(s + 2));
47c2e9
@@ -903,6 +902,11 @@ slapi_dn_normalize_ext(char *src, size_t src_len, char **dest, size_t *dest_len)
47c2e9
                     if (n == 0) { /* don't change \00 */
47c2e9
                         *d++ = *++s;
47c2e9
                         *d++ = *++s;
47c2e9
+                    } else if (n == 32) { /* leave \20 (space) intact */
47c2e9
+                        *d++ = *s;
47c2e9
+                        *d++ = *++s;
47c2e9
+                        *d++ = *++s;
47c2e9
+                        s++;
47c2e9
                     } else {
47c2e9
                         *d++ = n;
47c2e9
                         s += 3;
47c2e9
-- 
47c2e9
2.26.2
47c2e9