|
|
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 |
|