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

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