|
|
fc2009 |
From 70fd6e1fa6667734f39146cef53de6e3ff22d765 Mon Sep 17 00:00:00 2001
|
|
|
fc2009 |
From: Thierry Bordaz <tbordaz@redhat.com>
|
|
|
fc2009 |
Date: Fri, 9 Nov 2018 17:07:11 +0100
|
|
|
fc2009 |
Subject: [PATCH] Ticket 50020 - during MODRDN referential integrity can fail
|
|
|
fc2009 |
erronously while updating large groups
|
|
|
fc2009 |
|
|
|
fc2009 |
Bug Description:
|
|
|
fc2009 |
During a MODRDN of a group member, referential integrity will update the groups containing this member.
|
|
|
fc2009 |
Under specific conditions, the MODRDN can fail (err=1).
|
|
|
fc2009 |
|
|
|
fc2009 |
on MODRDN Referential integrity checks if the original DN of the target MODRDN entry is
|
|
|
fc2009 |
member of a given group. If it is then it updates the group.
|
|
|
fc2009 |
The returned code of the group update is using the variable 'rc'.
|
|
|
fc2009 |
It does a normalized DN comparison to compare original DN with members DN, to determine if
|
|
|
fc2009 |
a group needs to be updated.
|
|
|
fc2009 |
If the group does not need to be updated, 'rc' is not set.
|
|
|
fc2009 |
The bug is that it uses 'rc' to normalize the DN and if the group is not updated
|
|
|
fc2009 |
the returned code reflects the normalization returned code rather that the group update.
|
|
|
fc2009 |
|
|
|
fc2009 |
The bug is hit in specific conditions
|
|
|
fc2009 |
|
|
|
fc2009 |
One of the evaluated group contains more than 128 members
|
|
|
fc2009 |
the last member (last value) of the group is not the moved entry
|
|
|
fc2009 |
the last member (last value) of the group is a DN value that contains escaped chars
|
|
|
fc2009 |
|
|
|
fc2009 |
Fix Description:
|
|
|
fc2009 |
Use a local variable to check the result of the DN normalization
|
|
|
fc2009 |
|
|
|
fc2009 |
https://pagure.io/389-ds-base/issue/50020
|
|
|
fc2009 |
|
|
|
fc2009 |
Reviewed by: Simon Pichugin, Mark Reynolds (thanks)
|
|
|
fc2009 |
|
|
|
fc2009 |
Platforms tested: F27
|
|
|
fc2009 |
|
|
|
fc2009 |
Flag Day: no
|
|
|
fc2009 |
---
|
|
|
fc2009 |
.../tests/suites/plugins/referint_test.py | 103 ++++++++++++++++++
|
|
|
fc2009 |
ldap/servers/plugins/referint/referint.c | 18 +--
|
|
|
fc2009 |
2 files changed, 113 insertions(+), 8 deletions(-)
|
|
|
fc2009 |
create mode 100644 dirsrvtests/tests/suites/plugins/referint_test.py
|
|
|
fc2009 |
|
|
|
fc2009 |
diff --git a/dirsrvtests/tests/suites/plugins/referint_test.py b/dirsrvtests/tests/suites/plugins/referint_test.py
|
|
|
fc2009 |
new file mode 100644
|
|
|
fc2009 |
index 000000000..67a11de9e
|
|
|
fc2009 |
--- /dev/null
|
|
|
fc2009 |
+++ b/dirsrvtests/tests/suites/plugins/referint_test.py
|
|
|
fc2009 |
@@ -0,0 +1,103 @@
|
|
|
fc2009 |
+# --- BEGIN COPYRIGHT BLOCK ---
|
|
|
fc2009 |
+# Copyright (C) 2016 Red Hat, Inc.
|
|
|
fc2009 |
+# All rights reserved.
|
|
|
fc2009 |
+#
|
|
|
fc2009 |
+# License: GPL (version 3 or any later version).
|
|
|
fc2009 |
+# See LICENSE for details.
|
|
|
fc2009 |
+# --- END COPYRIGHT BLOCK ---
|
|
|
fc2009 |
+#
|
|
|
fc2009 |
+'''
|
|
|
fc2009 |
+Created on Dec 12, 2019
|
|
|
fc2009 |
+
|
|
|
fc2009 |
+@author: tbordaz
|
|
|
fc2009 |
+'''
|
|
|
fc2009 |
+import logging
|
|
|
fc2009 |
+import subprocess
|
|
|
fc2009 |
+import pytest
|
|
|
fc2009 |
+from lib389 import Entry
|
|
|
fc2009 |
+from lib389.utils import *
|
|
|
fc2009 |
+from lib389.plugins import *
|
|
|
fc2009 |
+from lib389._constants import *
|
|
|
fc2009 |
+from lib389.idm.user import UserAccounts, UserAccount
|
|
|
fc2009 |
+from lib389.idm.group import Groups
|
|
|
fc2009 |
+from lib389.topologies import topology_st as topo
|
|
|
fc2009 |
+
|
|
|
fc2009 |
+log = logging.getLogger(__name__)
|
|
|
fc2009 |
+
|
|
|
fc2009 |
+ESCAPED_RDN_BASE = "foo\,oo"
|
|
|
fc2009 |
+def _user_get_dn(no):
|
|
|
fc2009 |
+ uid = '%s%d' % (ESCAPED_RDN_BASE, no)
|
|
|
fc2009 |
+ dn = 'uid=%s,%s' % (uid, SUFFIX)
|
|
|
fc2009 |
+ return (uid, dn)
|
|
|
fc2009 |
+
|
|
|
fc2009 |
+def add_escaped_user(server, no):
|
|
|
fc2009 |
+ (uid, dn) = _user_get_dn(no)
|
|
|
fc2009 |
+ log.fatal('Adding user (%s): ' % dn)
|
|
|
fc2009 |
+ server.add_s(Entry((dn, {'objectclass': ['top', 'person', 'organizationalPerson', 'inetOrgPerson'],
|
|
|
fc2009 |
+ 'uid': [uid],
|
|
|
fc2009 |
+ 'sn' : [uid],
|
|
|
fc2009 |
+ 'cn' : [uid]})))
|
|
|
fc2009 |
+ return dn
|
|
|
fc2009 |
+
|
|
|
fc2009 |
+@pytest.mark.ds50020
|
|
|
fc2009 |
+def test_referential_false_failure(topo):
|
|
|
fc2009 |
+ """On MODRDN referential integrity can erronously fail
|
|
|
fc2009 |
+
|
|
|
fc2009 |
+ :id: f77aeb80-c4c4-471b-8c1b-4733b714778b
|
|
|
fc2009 |
+ :setup: Standalone Instance
|
|
|
fc2009 |
+ :steps:
|
|
|
fc2009 |
+ 1. Configure the plugin
|
|
|
fc2009 |
+ 2. Create a group
|
|
|
fc2009 |
+ - 1rst member the one that will be move
|
|
|
fc2009 |
+ - more than 128 members
|
|
|
fc2009 |
+ - last member is a DN containing escaped char
|
|
|
fc2009 |
+ 3. Rename the 1rst member
|
|
|
fc2009 |
+ :expectedresults:
|
|
|
fc2009 |
+ 1. should succeed
|
|
|
fc2009 |
+ 2. should succeed
|
|
|
fc2009 |
+ 3. should succeed
|
|
|
fc2009 |
+ """
|
|
|
fc2009 |
+
|
|
|
fc2009 |
+ inst = topo[0]
|
|
|
fc2009 |
+
|
|
|
fc2009 |
+ # stop the plugin, and start it
|
|
|
fc2009 |
+ plugin = ReferentialIntegrityPlugin(inst)
|
|
|
fc2009 |
+ plugin.disable()
|
|
|
fc2009 |
+ plugin.enable()
|
|
|
fc2009 |
+
|
|
|
fc2009 |
+ ############################################################################
|
|
|
fc2009 |
+ # Configure plugin
|
|
|
fc2009 |
+ ############################################################################
|
|
|
fc2009 |
+ GROUP_CONTAINER = "ou=groups,%s" % DEFAULT_SUFFIX
|
|
|
fc2009 |
+ plugin.replace('referint-membership-attr', 'member')
|
|
|
fc2009 |
+ plugin.replace('nsslapd-plugincontainerscope', GROUP_CONTAINER)
|
|
|
fc2009 |
+
|
|
|
fc2009 |
+ ############################################################################
|
|
|
fc2009 |
+ # Creates a group with members having escaped DN
|
|
|
fc2009 |
+ ############################################################################
|
|
|
fc2009 |
+ # Add some users and a group
|
|
|
fc2009 |
+ users = UserAccounts(inst, DEFAULT_SUFFIX, None)
|
|
|
fc2009 |
+ user1 = users.create_test_user(uid=1001)
|
|
|
fc2009 |
+ user2 = users.create_test_user(uid=1002)
|
|
|
fc2009 |
+
|
|
|
fc2009 |
+ groups = Groups(inst, GROUP_CONTAINER, None)
|
|
|
fc2009 |
+ group = groups.create(properties={'cn': 'group'})
|
|
|
fc2009 |
+ group.add('member', user2.dn)
|
|
|
fc2009 |
+ group.add('member', user1.dn)
|
|
|
fc2009 |
+
|
|
|
fc2009 |
+ # Add more than 128 members so that referint follows the buggy path
|
|
|
fc2009 |
+ for i in range(130):
|
|
|
fc2009 |
+ escaped_user = add_escaped_user(inst, i)
|
|
|
fc2009 |
+ group.add('member', escaped_user)
|
|
|
fc2009 |
+
|
|
|
fc2009 |
+ ############################################################################
|
|
|
fc2009 |
+ # Check that the MODRDN succeeds
|
|
|
fc2009 |
+ ###########################################################################
|
|
|
fc2009 |
+ # Here we need to restart so that member values are taken in the right order
|
|
|
fc2009 |
+ # the last value is the escaped one
|
|
|
fc2009 |
+ inst.restart()
|
|
|
fc2009 |
+
|
|
|
fc2009 |
+ # Here if the bug is fixed, referential is able to update the member value
|
|
|
fc2009 |
+ inst.rename_s(user1.dn, 'uid=new_test_user_1001', newsuperior=SUFFIX, delold=0)
|
|
|
fc2009 |
+
|
|
|
fc2009 |
+
|
|
|
fc2009 |
diff --git a/ldap/servers/plugins/referint/referint.c b/ldap/servers/plugins/referint/referint.c
|
|
|
fc2009 |
index f6d1c27a2..9e4e680d3 100644
|
|
|
fc2009 |
--- a/ldap/servers/plugins/referint/referint.c
|
|
|
fc2009 |
+++ b/ldap/servers/plugins/referint/referint.c
|
|
|
fc2009 |
@@ -824,20 +824,21 @@ _update_one_per_mod(Slapi_DN *entrySDN, /* DN of the searched entry */
|
|
|
fc2009 |
*/
|
|
|
fc2009 |
for (nval = slapi_attr_first_value(attr, &v); nval != -1;
|
|
|
fc2009 |
nval = slapi_attr_next_value(attr, nval, &v)) {
|
|
|
fc2009 |
+ int normalize_rc;
|
|
|
fc2009 |
p = NULL;
|
|
|
fc2009 |
dnlen = 0;
|
|
|
fc2009 |
|
|
|
fc2009 |
/* DN syntax, which should be a string */
|
|
|
fc2009 |
sval = slapi_ch_strdup(slapi_value_get_string(v));
|
|
|
fc2009 |
- rc = slapi_dn_normalize_case_ext(sval, 0, &p, &dnlen);
|
|
|
fc2009 |
- if (rc == 0) { /* sval is passed in; not terminated */
|
|
|
fc2009 |
+ normalize_rc = slapi_dn_normalize_case_ext(sval, 0, &p, &dnlen);
|
|
|
fc2009 |
+ if (normalize_rc == 0) { /* sval is passed in; not terminated */
|
|
|
fc2009 |
*(p + dnlen) = '\0';
|
|
|
fc2009 |
sval = p;
|
|
|
fc2009 |
- } else if (rc > 0) {
|
|
|
fc2009 |
+ } else if (normalize_rc > 0) {
|
|
|
fc2009 |
slapi_ch_free_string(&sval);
|
|
|
fc2009 |
sval = p;
|
|
|
fc2009 |
}
|
|
|
fc2009 |
- /* else: (rc < 0) Ignore the DN normalization error for now. */
|
|
|
fc2009 |
+ /* else: (normalize_rc < 0) Ignore the DN normalization error for now. */
|
|
|
fc2009 |
|
|
|
fc2009 |
p = PL_strstr(sval, slapi_sdn_get_ndn(origDN));
|
|
|
fc2009 |
if (p == sval) {
|
|
|
fc2009 |
@@ -1013,20 +1014,21 @@ _update_all_per_mod(Slapi_DN *entrySDN, /* DN of the searched entry */
|
|
|
fc2009 |
for (nval = slapi_attr_first_value(attr, &v);
|
|
|
fc2009 |
nval != -1;
|
|
|
fc2009 |
nval = slapi_attr_next_value(attr, nval, &v)) {
|
|
|
fc2009 |
+ int normalize_rc;
|
|
|
fc2009 |
p = NULL;
|
|
|
fc2009 |
dnlen = 0;
|
|
|
fc2009 |
|
|
|
fc2009 |
/* DN syntax, which should be a string */
|
|
|
fc2009 |
sval = slapi_ch_strdup(slapi_value_get_string(v));
|
|
|
fc2009 |
- rc = slapi_dn_normalize_case_ext(sval, 0, &p, &dnlen);
|
|
|
fc2009 |
- if (rc == 0) { /* sval is passed in; not terminated */
|
|
|
fc2009 |
+ normalize_rc = slapi_dn_normalize_case_ext(sval, 0, &p, &dnlen);
|
|
|
fc2009 |
+ if (normalize_rc == 0) { /* sval is passed in; not terminated */
|
|
|
fc2009 |
*(p + dnlen) = '\0';
|
|
|
fc2009 |
sval = p;
|
|
|
fc2009 |
- } else if (rc > 0) {
|
|
|
fc2009 |
+ } else if (normalize_rc > 0) {
|
|
|
fc2009 |
slapi_ch_free_string(&sval);
|
|
|
fc2009 |
sval = p;
|
|
|
fc2009 |
}
|
|
|
fc2009 |
- /* else: (rc < 0) Ignore the DN normalization error for now. */
|
|
|
fc2009 |
+ /* else: normalize_rc < 0) Ignore the DN normalization error for now. */
|
|
|
fc2009 |
|
|
|
fc2009 |
p = PL_strstr(sval, slapi_sdn_get_ndn(origDN));
|
|
|
fc2009 |
if (p == sval) {
|
|
|
fc2009 |
--
|
|
|
fc2009 |
2.17.2
|
|
|
fc2009 |
|