andykimpe / rpms / 389-ds-base

Forked from rpms/389-ds-base 5 months ago
Clone

Blame SOURCES/0020-Issue-4447-Crash-when-the-Referential-Integrity-log-.patch

5d81fc
From 7b7217538908ae58df864ef5cd82e1d3303c189f Mon Sep 17 00:00:00 2001
5d81fc
From: Mark Reynolds <mreynolds@redhat.com>
5d81fc
Date: Mon, 7 Jun 2021 12:58:42 -0400
5d81fc
Subject: [PATCH] Issue 4447 - Crash when the Referential Integrity log is
5d81fc
 manually edited
5d81fc
5d81fc
Bug Description:  If the referint log is manually edited with a string
5d81fc
                  that is not a DN the server will crash when processing
5d81fc
                  the log.
5d81fc
5d81fc
Fix Description:  Check for NULL pointers when strtoking the file line.
5d81fc
5d81fc
relates: https://github.com/389ds/389-ds-base/issues/4447
5d81fc
5d81fc
Reviewed by: firstyear(Thanks!)
5d81fc
---
5d81fc
 .../tests/suites/plugins/referint_test.py     | 72 +++++++++++++++----
5d81fc
 ldap/servers/plugins/referint/referint.c      |  7 ++
5d81fc
 src/lib389/lib389/plugins.py                  | 15 ++++
5d81fc
 3 files changed, 80 insertions(+), 14 deletions(-)
5d81fc
5d81fc
diff --git a/dirsrvtests/tests/suites/plugins/referint_test.py b/dirsrvtests/tests/suites/plugins/referint_test.py
5d81fc
index 02b985767..fda602545 100644
5d81fc
--- a/dirsrvtests/tests/suites/plugins/referint_test.py
5d81fc
+++ b/dirsrvtests/tests/suites/plugins/referint_test.py
5d81fc
@@ -1,5 +1,5 @@
5d81fc
 # --- BEGIN COPYRIGHT BLOCK ---
5d81fc
-# Copyright (C) 2016 Red Hat, Inc.
5d81fc
+# Copyright (C) 2021 Red Hat, Inc.
5d81fc
 # All rights reserved.
5d81fc
 #
5d81fc
 # License: GPL (version 3 or any later version).
5d81fc
@@ -12,13 +12,11 @@ Created on Dec 12, 2019
5d81fc
 @author: tbordaz
5d81fc
 '''
5d81fc
 import logging
5d81fc
-import subprocess
5d81fc
 import pytest
5d81fc
 from lib389 import Entry
5d81fc
-from lib389.utils import *
5d81fc
-from lib389.plugins import *
5d81fc
-from lib389._constants import *
5d81fc
-from lib389.idm.user import UserAccounts, UserAccount
5d81fc
+from lib389.plugins import ReferentialIntegrityPlugin
5d81fc
+from lib389._constants import DEFAULT_SUFFIX
5d81fc
+from lib389.idm.user import UserAccounts
5d81fc
 from lib389.idm.group import Groups
5d81fc
 from lib389.topologies import topology_st as topo
5d81fc
 
5d81fc
@@ -29,21 +27,27 @@ log = logging.getLogger(__name__)
5d81fc
 ESCAPED_RDN_BASE = "foo\\,oo"
5d81fc
 def _user_get_dn(no):
5d81fc
     uid = '%s%d' % (ESCAPED_RDN_BASE, no)
5d81fc
-    dn = 'uid=%s,%s' % (uid, SUFFIX)
5d81fc
+    dn = 'uid=%s,%s' % (uid, DEFAULT_SUFFIX)
5d81fc
     return (uid, dn)
5d81fc
 
5d81fc
 def add_escaped_user(server, no):
5d81fc
     (uid, dn) = _user_get_dn(no)
5d81fc
     log.fatal('Adding user (%s): ' % dn)
5d81fc
-    server.add_s(Entry((dn, {'objectclass': ['top', 'person', 'organizationalPerson', 'inetOrgPerson'],
5d81fc
-                             'uid': [uid],
5d81fc
-                             'sn' : [uid],
5d81fc
-                             'cn' : [uid]})))
5d81fc
+    users = UserAccounts(server, DEFAULT_SUFFIX, None)
5d81fc
+    user_properties = {
5d81fc
+        'objectclass': ['top', 'person', 'organizationalPerson', 'inetOrgPerson', 'posixAccount'],
5d81fc
+        'uid': uid,
5d81fc
+        'cn' : uid,
5d81fc
+        'sn' : uid,
5d81fc
+        'uidNumber' : '1000',
5d81fc
+        'gidNumber' : '2000',
5d81fc
+        'homeDirectory' : '/home/testuser',
5d81fc
+    }
5d81fc
+    users.create(properties=user_properties)
5d81fc
     return dn
5d81fc
 
5d81fc
-@pytest.mark.ds50020
5d81fc
 def test_referential_false_failure(topo):
5d81fc
-    """On MODRDN referential integrity can erronously fail
5d81fc
+    """On MODRDN referential integrity can erroneously fail
5d81fc
 
5d81fc
     :id: f77aeb80-c4c4-471b-8c1b-4733b714778b
5d81fc
     :setup: Standalone Instance
5d81fc
@@ -100,6 +104,46 @@ def test_referential_false_failure(topo):
5d81fc
     inst.restart()
5d81fc
 
5d81fc
     # Here if the bug is fixed, referential is able to update the member value
5d81fc
-    inst.rename_s(user1.dn, 'uid=new_test_user_1001', newsuperior=SUFFIX, delold=0)
5d81fc
+    user1.rename('uid=new_test_user_1001', newsuperior=DEFAULT_SUFFIX, deloldrdn=False)
5d81fc
 
5d81fc
 
5d81fc
+def test_invalid_referint_log(topo):
5d81fc
+    """If there is an invalid log line in the referint log, make sure the server
5d81fc
+    does not crash at startup
5d81fc
+
5d81fc
+    :id: 34807b5a-ab17-4281-ae48-4e3513e19145
5d81fc
+    :setup: Standalone Instance
5d81fc
+    :steps:
5d81fc
+        1. Set the referint log delay
5d81fc
+        2. Create invalid log
5d81fc
+        3. Start the server (no crash)
5d81fc
+    :expectedresults:
5d81fc
+        1. Success
5d81fc
+        2. Success
5d81fc
+        3. Success
5d81fc
+    """
5d81fc
+
5d81fc
+    inst = topo.standalone
5d81fc
+
5d81fc
+    # Set delay - required for log parsing at server startup
5d81fc
+    plugin = ReferentialIntegrityPlugin(inst)
5d81fc
+    plugin.enable()
5d81fc
+    plugin.set_update_delay('2')
5d81fc
+    logfile = plugin.get_log_file()
5d81fc
+    inst.restart()
5d81fc
+
5d81fc
+    # Create invalid log
5d81fc
+    inst.stop()
5d81fc
+    with open(logfile, 'w') as log_fh:
5d81fc
+        log_fh.write("CRASH\n")
5d81fc
+
5d81fc
+    # Start the instance
5d81fc
+    inst.start()
5d81fc
+    assert inst.status()
5d81fc
+
5d81fc
+
5d81fc
+if __name__ == '__main__':
5d81fc
+    # Run isolated
5d81fc
+    # -s for DEBUG mode
5d81fc
+    CURRENT_FILE = os.path.realpath(__file__)
5d81fc
+    pytest.main("-s %s" % CURRENT_FILE)
5d81fc
diff --git a/ldap/servers/plugins/referint/referint.c b/ldap/servers/plugins/referint/referint.c
5d81fc
index fd5356d72..28240c1f6 100644
5d81fc
--- a/ldap/servers/plugins/referint/referint.c
5d81fc
+++ b/ldap/servers/plugins/referint/referint.c
5d81fc
@@ -1447,6 +1447,13 @@ referint_thread_func(void *arg __attribute__((unused)))
5d81fc
             sdn = slapi_sdn_new_normdn_byref(ptoken);
5d81fc
             ptoken = ldap_utf8strtok_r(NULL, delimiter, &iter);
5d81fc
 
5d81fc
+            if (ptoken == NULL) {
5d81fc
+                /* Invalid line in referint log, skip it */
5d81fc
+                slapi_log_err(SLAPI_LOG_ERR, REFERINT_PLUGIN_SUBSYSTEM,
5d81fc
+                        "Skipping invalid referint log line: (%s)\n", thisline);
5d81fc
+                slapi_sdn_free(&sdn;;
5d81fc
+                continue;
5d81fc
+            }
5d81fc
             if (!strcasecmp(ptoken, "NULL")) {
5d81fc
                 tmprdn = NULL;
5d81fc
             } else {
5d81fc
diff --git a/src/lib389/lib389/plugins.py b/src/lib389/lib389/plugins.py
5d81fc
index 2d88e60bd..b07e80022 100644
5d81fc
--- a/src/lib389/lib389/plugins.py
5d81fc
+++ b/src/lib389/lib389/plugins.py
5d81fc
@@ -518,6 +518,21 @@ class ReferentialIntegrityPlugin(Plugin):
5d81fc
 
5d81fc
         self.set('referint-update-delay', str(value))
5d81fc
 
5d81fc
+    def get_log_file(self):
5d81fc
+        """Get referint log file"""
5d81fc
+
5d81fc
+        return self.get_attr_val_utf8('referint-logfile')
5d81fc
+
5d81fc
+    def get_log_file_formatted(self):
5d81fc
+        """Get referint log file"""
5d81fc
+
5d81fc
+        return self.display_attr('referint-logfile')
5d81fc
+
5d81fc
+    def set_log_file(self, value):
5d81fc
+        """Set referint log file"""
5d81fc
+
5d81fc
+        self.set('referint-logfile', value)
5d81fc
+
5d81fc
     def get_membership_attr(self, formatted=False):
5d81fc
         """Get referint-membership-attr attribute"""
5d81fc
 
5d81fc
-- 
5d81fc
2.31.1
5d81fc