|
|
cb1cc6 |
From 63e1ceac74cdfda7cf432537a18670e9562b58df Mon Sep 17 00:00:00 2001
|
|
|
cb1cc6 |
From: progier389 <progier@redhat.com>
|
|
|
cb1cc6 |
Date: Mon, 2 May 2022 18:43:25 +0200
|
|
|
cb1cc6 |
Subject: [PATCH] Issue 5126 - Memory leak in slapi_ldap_get_lderrno (#5153)
|
|
|
cb1cc6 |
MIME-Version: 1.0
|
|
|
cb1cc6 |
Content-Type: text/plain; charset=UTF-8
|
|
|
cb1cc6 |
Content-Transfer-Encoding: 8bit
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
* Issue 5126 - Memory leak in slapi_ldap_get_lderrno
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
The problem is that some time ago libldap API replaced ​LDAP_OPT_ERROR_STRING whose data should not be freed by
|
|
|
cb1cc6 |
LDAP_OPT_DIAGNOSTIC_MESSAGE whose data must be freed.
|
|
|
cb1cc6 |
slapi_ldap_get_lderrno was adapted to use the new option but the callers were not modified to free the value.
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
The Solution:
|
|
|
cb1cc6 |
Insure that we also need to free slapi_ldap_get_lderrno value if legacy LDAP_OPT_ERROR_STRING is used (by duping the value)
|
|
|
cb1cc6 |
Insure that the callers free the value.
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
Added test case about replication using SASL/Digest-md5 authentication
|
|
|
cb1cc6 |
Added test case to check this leak
|
|
|
cb1cc6 |
Also updated test case about SASL/GSSAPI to be comapatible with current lib389 framework but marked as skipped because it requires a specific configuration (This path should be tested by IPA tests)
|
|
|
cb1cc6 |
Fixed valgrind lib389 function to run on prefixed installation without needing to be root.
|
|
|
cb1cc6 |
At last I also improved lib389 mapped object to have a better diagnostic when LDAP operation fails (by adding the request within the exception)
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
issue: 5126 https://github.com/389ds/389-ds-base/issues/5126
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
Reviewd by: @droideck
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
(cherry picked from commit 4d89e11494233d8297896540bc752cfdbab2cc69)
|
|
|
cb1cc6 |
---
|
|
|
cb1cc6 |
.../suites/gssapi_repl/gssapi_repl_test.py | 31 ++-
|
|
|
cb1cc6 |
.../tests/suites/replication/sasl_m2_test.py | 185 ++++++++++++++++++
|
|
|
cb1cc6 |
ldap/servers/plugins/chainingdb/cb_search.c | 6 +-
|
|
|
cb1cc6 |
ldap/servers/plugins/passthru/ptbind.c | 2 +
|
|
|
cb1cc6 |
.../plugins/replication/repl5_connection.c | 4 +
|
|
|
cb1cc6 |
.../plugins/replication/windows_connection.c | 3 +
|
|
|
cb1cc6 |
ldap/servers/slapd/ldaputil.c | 6 +
|
|
|
cb1cc6 |
src/lib389/lib389/_mapped_object.py | 76 ++++---
|
|
|
cb1cc6 |
src/lib389/lib389/utils.py | 40 +++-
|
|
|
cb1cc6 |
9 files changed, 311 insertions(+), 42 deletions(-)
|
|
|
cb1cc6 |
create mode 100644 dirsrvtests/tests/suites/replication/sasl_m2_test.py
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
diff --git a/dirsrvtests/tests/suites/gssapi_repl/gssapi_repl_test.py b/dirsrvtests/tests/suites/gssapi_repl/gssapi_repl_test.py
|
|
|
cb1cc6 |
index 41f323c06..402684aab 100644
|
|
|
cb1cc6 |
--- a/dirsrvtests/tests/suites/gssapi_repl/gssapi_repl_test.py
|
|
|
cb1cc6 |
+++ b/dirsrvtests/tests/suites/gssapi_repl/gssapi_repl_test.py
|
|
|
cb1cc6 |
@@ -9,6 +9,7 @@
|
|
|
cb1cc6 |
import pytest
|
|
|
cb1cc6 |
from lib389.tasks import *
|
|
|
cb1cc6 |
from lib389.utils import *
|
|
|
cb1cc6 |
+from lib389.agreement import *
|
|
|
cb1cc6 |
from lib389.topologies import topology_m2
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
pytestmark = pytest.mark.tier2
|
|
|
cb1cc6 |
@@ -65,10 +66,27 @@ def _allow_machine_account(inst, name):
|
|
|
cb1cc6 |
# First we need to get the mapping tree dn
|
|
|
cb1cc6 |
mt = inst.mappingtree.list(suffix=DEFAULT_SUFFIX)[0]
|
|
|
cb1cc6 |
inst.modify_s('cn=replica,%s' % mt.dn, [
|
|
|
cb1cc6 |
- (ldap.MOD_REPLACE, 'nsDS5ReplicaBindDN', "uid=%s,ou=Machines,%s" % (name, DEFAULT_SUFFIX))
|
|
|
cb1cc6 |
+ (ldap.MOD_REPLACE, 'nsDS5ReplicaBindDN', f"uid={name},ou=Machines,{DEFAULT_SUFFIX}".encode('utf-8'))
|
|
|
cb1cc6 |
])
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
-
|
|
|
cb1cc6 |
+def _verify_etc_hosts():
|
|
|
cb1cc6 |
+ #Check if /etc/hosts is compatible with the test
|
|
|
cb1cc6 |
+ NEEDED_HOSTS = ( ('ldapkdc.example.com', '127.0.0.1'),
|
|
|
cb1cc6 |
+ ('ldapkdc1.example.com', '127.0.1.1'),
|
|
|
cb1cc6 |
+ ('ldapkdc2.example.com', '127.0.2.1'))
|
|
|
cb1cc6 |
+ found_hosts = {}
|
|
|
cb1cc6 |
+ with open('/etc/hosts','r') as f:
|
|
|
cb1cc6 |
+ for l in f:
|
|
|
cb1cc6 |
+ s = l.split()
|
|
|
cb1cc6 |
+ if len(s) < 2:
|
|
|
cb1cc6 |
+ continue
|
|
|
cb1cc6 |
+ for nh in NEEDED_HOSTS:
|
|
|
cb1cc6 |
+ if (s[0] == nh[1] and s[1] == nh[0]):
|
|
|
cb1cc6 |
+ found_hosts[s[1]] = True
|
|
|
cb1cc6 |
+ return len(found_hosts) == len(NEEDED_HOSTS)
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+@pytest.mark.skipif(not _verify_etc_hosts(), reason="/etc/hosts does not contains the needed hosts.")
|
|
|
cb1cc6 |
+@pytest.mark.skipif(True, reason="Test disabled because it requires specific kerberos requirement (server principal, keytab, etc ...")
|
|
|
cb1cc6 |
def test_gssapi_repl(topology_m2):
|
|
|
cb1cc6 |
"""Test gssapi authenticated replication agreement of two suppliers using KDC
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
@@ -94,8 +112,6 @@ def test_gssapi_repl(topology_m2):
|
|
|
cb1cc6 |
6. Test User should be created on M1 and M2 both
|
|
|
cb1cc6 |
7. Test User should be created on M1 and M2 both
|
|
|
cb1cc6 |
"""
|
|
|
cb1cc6 |
-
|
|
|
cb1cc6 |
- return
|
|
|
cb1cc6 |
supplier1 = topology_m2.ms["supplier1"]
|
|
|
cb1cc6 |
supplier2 = topology_m2.ms["supplier2"]
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
@@ -121,6 +137,7 @@ def test_gssapi_repl(topology_m2):
|
|
|
cb1cc6 |
properties = {RA_NAME: r'meTo_$host:$port',
|
|
|
cb1cc6 |
RA_METHOD: 'SASL/GSSAPI',
|
|
|
cb1cc6 |
RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
|
|
|
cb1cc6 |
+ supplier1.agreement.delete(suffix=SUFFIX, consumer_host=supplier2.host, consumer_port=supplier2.port)
|
|
|
cb1cc6 |
m1_m2_agmt = supplier1.agreement.create(suffix=SUFFIX, host=supplier2.host, port=supplier2.port, properties=properties)
|
|
|
cb1cc6 |
if not m1_m2_agmt:
|
|
|
cb1cc6 |
log.fatal("Fail to create a supplier -> supplier replica agreement")
|
|
|
cb1cc6 |
@@ -133,6 +150,7 @@ def test_gssapi_repl(topology_m2):
|
|
|
cb1cc6 |
properties = {RA_NAME: r'meTo_$host:$port',
|
|
|
cb1cc6 |
RA_METHOD: 'SASL/GSSAPI',
|
|
|
cb1cc6 |
RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
|
|
|
cb1cc6 |
+ supplier2.agreement.delete(suffix=SUFFIX, consumer_host=supplier1.host, consumer_port=supplier1.port)
|
|
|
cb1cc6 |
m2_m1_agmt = supplier2.agreement.create(suffix=SUFFIX, host=supplier1.host, port=supplier1.port, properties=properties)
|
|
|
cb1cc6 |
if not m2_m1_agmt:
|
|
|
cb1cc6 |
log.fatal("Fail to create a supplier -> supplier replica agreement")
|
|
|
cb1cc6 |
@@ -145,8 +163,9 @@ def test_gssapi_repl(topology_m2):
|
|
|
cb1cc6 |
#
|
|
|
cb1cc6 |
# Initialize all the agreements
|
|
|
cb1cc6 |
#
|
|
|
cb1cc6 |
- supplier1.agreement.init(SUFFIX, HOST_SUPPLIER_2, PORT_SUPPLIER_2)
|
|
|
cb1cc6 |
- supplier1.waitForReplInit(m1_m2_agmt)
|
|
|
cb1cc6 |
+ agmt = Agreement(supplier1, m1_m2_agmt)
|
|
|
cb1cc6 |
+ agmt.begin_reinit()
|
|
|
cb1cc6 |
+ agmt.wait_reinit()
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
# Check replication is working...
|
|
|
cb1cc6 |
if supplier1.testReplication(DEFAULT_SUFFIX, supplier2):
|
|
|
cb1cc6 |
diff --git a/dirsrvtests/tests/suites/replication/sasl_m2_test.py b/dirsrvtests/tests/suites/replication/sasl_m2_test.py
|
|
|
cb1cc6 |
new file mode 100644
|
|
|
cb1cc6 |
index 000000000..d7406ac7e
|
|
|
cb1cc6 |
--- /dev/null
|
|
|
cb1cc6 |
+++ b/dirsrvtests/tests/suites/replication/sasl_m2_test.py
|
|
|
cb1cc6 |
@@ -0,0 +1,185 @@
|
|
|
cb1cc6 |
+# --- BEGIN COPYRIGHT BLOCK ---
|
|
|
cb1cc6 |
+# Copyright (C) 2022 Red Hat, Inc.
|
|
|
cb1cc6 |
+# All rights reserved.
|
|
|
cb1cc6 |
+#
|
|
|
cb1cc6 |
+# License: GPL (version 3 or any later version).
|
|
|
cb1cc6 |
+# See LICENSE for details.
|
|
|
cb1cc6 |
+# --- END COPYRIGHT BLOCK ---
|
|
|
cb1cc6 |
+#
|
|
|
cb1cc6 |
+import logging
|
|
|
cb1cc6 |
+import os
|
|
|
cb1cc6 |
+import pytest
|
|
|
cb1cc6 |
+import ldap
|
|
|
cb1cc6 |
+import uuid
|
|
|
cb1cc6 |
+from lib389.utils import ds_is_older, valgrind_enable, valgrind_disable, valgrind_get_results_file, valgrind_check_file
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+from lib389.idm.services import ServiceAccounts
|
|
|
cb1cc6 |
+from lib389.idm.group import Groups
|
|
|
cb1cc6 |
+from lib389.config import CertmapLegacy, Config
|
|
|
cb1cc6 |
+from lib389._constants import DEFAULT_SUFFIX
|
|
|
cb1cc6 |
+from lib389.agreement import Agreements
|
|
|
cb1cc6 |
+from lib389._mapped_object import DSLdapObject
|
|
|
cb1cc6 |
+from lib389.replica import ReplicationManager, Replicas, BootstrapReplicationManager
|
|
|
cb1cc6 |
+from lib389.topologies import topology_m2 as topo_m2
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+pytestmark = pytest.mark.tier1
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+DEBUGGING = os.getenv("DEBUGGING", default=False)
|
|
|
cb1cc6 |
+if DEBUGGING:
|
|
|
cb1cc6 |
+ logging.getLogger(__name__).setLevel(logging.DEBUG)
|
|
|
cb1cc6 |
+else:
|
|
|
cb1cc6 |
+ logging.getLogger(__name__).setLevel(logging.INFO)
|
|
|
cb1cc6 |
+log = logging.getLogger(__name__)
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+def set_sasl_md5_client_auth(inst, to):
|
|
|
cb1cc6 |
+ # Create the certmap before we restart
|
|
|
cb1cc6 |
+ cm = CertmapLegacy(to)
|
|
|
cb1cc6 |
+ certmaps = cm.list()
|
|
|
cb1cc6 |
+ certmaps['default']['nsSaslMapRegexString'] = '^dn:\\(.*\\)'
|
|
|
cb1cc6 |
+ certmaps['default']['nsSaslMapBaseDNTemplate'] = 'cn=config'
|
|
|
cb1cc6 |
+ certmaps['default']['nsSaslMapFilterTemplate'] = '(objectclass=*)'
|
|
|
cb1cc6 |
+ cm.set(certmaps)
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+ Config(to).replace("passwordStorageScheme", 'CLEAR')
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+ # Create a repl manager on the replica
|
|
|
cb1cc6 |
+ replication_manager_pwd = 'secret12'
|
|
|
cb1cc6 |
+ brm = BootstrapReplicationManager(to)
|
|
|
cb1cc6 |
+ try:
|
|
|
cb1cc6 |
+ brm.delete()
|
|
|
cb1cc6 |
+ except ldap.NO_SUCH_OBJECT:
|
|
|
cb1cc6 |
+ pass
|
|
|
cb1cc6 |
+ brm.create(properties={
|
|
|
cb1cc6 |
+ 'cn': brm.common_name,
|
|
|
cb1cc6 |
+ 'userPassword': replication_manager_pwd
|
|
|
cb1cc6 |
+ })
|
|
|
cb1cc6 |
+ replication_manager_dn = brm.dn
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+ replica = Replicas(inst).get(DEFAULT_SUFFIX)
|
|
|
cb1cc6 |
+ replica.set('nsDS5ReplicaBindDN', brm.dn)
|
|
|
cb1cc6 |
+ replica.remove_all('nsDS5ReplicaBindDNgroup')
|
|
|
cb1cc6 |
+ agmt = replica.get_agreements().list()[0]
|
|
|
cb1cc6 |
+ agmt.replace_many(
|
|
|
cb1cc6 |
+ ('nsDS5ReplicaBindMethod', 'SASL/DIGEST-MD5'),
|
|
|
cb1cc6 |
+ ('nsDS5ReplicaTransportInfo', 'LDAP'),
|
|
|
cb1cc6 |
+ ('nsDS5ReplicaPort', str(to.port)),
|
|
|
cb1cc6 |
+ ('nsDS5ReplicaBindDN', replication_manager_dn),
|
|
|
cb1cc6 |
+ ('nsDS5ReplicaCredentials', replication_manager_pwd),
|
|
|
cb1cc6 |
+ )
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+def gen_valgrind_wrapper(dir):
|
|
|
cb1cc6 |
+ name=f"{dir}/VALGRIND"
|
|
|
cb1cc6 |
+ with open(name, 'w') as f:
|
|
|
cb1cc6 |
+ f.write('#!/bin/sh\n')
|
|
|
cb1cc6 |
+ f.write('export SASL_PATH=foo\n')
|
|
|
cb1cc6 |
+ f.write(f'valgrind -q --tool=memcheck --leak-check=yes --leak-resolution=high --num-callers=50 --log-file=/var/tmp/slapd.vg.$$ {dir}/ns-slapd.original "$@"\n')
|
|
|
cb1cc6 |
+ os.chmod(name, 0o755)
|
|
|
cb1cc6 |
+ return name
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+@pytest.fixture
|
|
|
cb1cc6 |
+def use_valgrind(topo_m2, request):
|
|
|
cb1cc6 |
+ """Adds entries to the supplier1"""
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+ log.info("Enable valgrind")
|
|
|
cb1cc6 |
+ m1 = topo_m2.ms['supplier1']
|
|
|
cb1cc6 |
+ m2 = topo_m2.ms['supplier2']
|
|
|
cb1cc6 |
+ if m1.has_asan():
|
|
|
cb1cc6 |
+ pytest.skip('Tescase using valgring cannot run on asan enabled build')
|
|
|
cb1cc6 |
+ return
|
|
|
cb1cc6 |
+ set_sasl_md5_client_auth(m1, m2)
|
|
|
cb1cc6 |
+ set_sasl_md5_client_auth(m2, m1)
|
|
|
cb1cc6 |
+ m1.stop()
|
|
|
cb1cc6 |
+ m2.stop()
|
|
|
cb1cc6 |
+ m1.systemd_override = False
|
|
|
cb1cc6 |
+ m2.systemd_override = False
|
|
|
cb1cc6 |
+ valgrind_enable(m1.ds_paths.sbin_dir, gen_valgrind_wrapper(m1.ds_paths.sbin_dir))
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+ def fin():
|
|
|
cb1cc6 |
+ log.info("Disable valgrind")
|
|
|
cb1cc6 |
+ valgrind_disable(m1.ds_paths.sbin_dir)
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+ request.addfinalizer(fin)
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+def test_repl_sasl_md5_auth(topo_m2):
|
|
|
cb1cc6 |
+ """Test replication with SASL digest-md5 authentication
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+ :id: 922d16f8-662a-4915-a39e-0aecd7c8e6e2
|
|
|
cb1cc6 |
+ :setup: Two supplier replication
|
|
|
cb1cc6 |
+ :steps:
|
|
|
cb1cc6 |
+ 1. Set sasl digest/md4 on both suppliers
|
|
|
cb1cc6 |
+ 2. Restart the instance
|
|
|
cb1cc6 |
+ 3. Check that replication works
|
|
|
cb1cc6 |
+ :expectedresults:
|
|
|
cb1cc6 |
+ 1. Success
|
|
|
cb1cc6 |
+ 2. Success
|
|
|
cb1cc6 |
+ 3. Replication works
|
|
|
cb1cc6 |
+ """
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+ m1 = topo_m2.ms['supplier1']
|
|
|
cb1cc6 |
+ m2 = topo_m2.ms['supplier2']
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+ set_sasl_md5_client_auth(m1, m2)
|
|
|
cb1cc6 |
+ set_sasl_md5_client_auth(m2, m1)
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+ m1.restart()
|
|
|
cb1cc6 |
+ m2.restart()
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+ repl = ReplicationManager(DEFAULT_SUFFIX)
|
|
|
cb1cc6 |
+ repl.test_replication_topology(topo_m2)
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+@pytest.mark.skipif(not os.path.exists('/usr/bin/valgrind'), reason="valgrind is not installed.")
|
|
|
cb1cc6 |
+def test_repl_sasl_leak(topo_m2, use_valgrind):
|
|
|
cb1cc6 |
+ """Test replication with SASL digest-md5 authentication
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+ :id: 180e088e-841c-11ec-af4f-482ae39447e5
|
|
|
cb1cc6 |
+ :setup: Two supplier replication, valgrind
|
|
|
cb1cc6 |
+ :steps:
|
|
|
cb1cc6 |
+ 1. Set sasl digest/md4 on both suppliers
|
|
|
cb1cc6 |
+ 2. Break sasl by setting invalid PATH
|
|
|
cb1cc6 |
+ 3. Restart the instances
|
|
|
cb1cc6 |
+ 4. Perform a change
|
|
|
cb1cc6 |
+ 5. Poke replication 100 times
|
|
|
cb1cc6 |
+ 6. Stop server
|
|
|
cb1cc6 |
+ 7. Check presence of "SASL(-4): no mechanism available: No worthy mechs found" message in error log
|
|
|
cb1cc6 |
+ 8 Check that there is no leak about slapi_ldap_get_lderrno
|
|
|
cb1cc6 |
+ :expectedresults:
|
|
|
cb1cc6 |
+ 1. Success
|
|
|
cb1cc6 |
+ 2. Success
|
|
|
cb1cc6 |
+ 2. Success
|
|
|
cb1cc6 |
+ 4. Success
|
|
|
cb1cc6 |
+ 5. Success
|
|
|
cb1cc6 |
+ 6. Success
|
|
|
cb1cc6 |
+ 7. Success
|
|
|
cb1cc6 |
+ 8. Success
|
|
|
cb1cc6 |
+ """
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+ m1 = topo_m2.ms['supplier1']
|
|
|
cb1cc6 |
+ m2 = topo_m2.ms['supplier2']
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+ os.environ["SASL_PATH"] = 'foo'
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+ m1.start()
|
|
|
cb1cc6 |
+ m2.start()
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+ resfile=valgrind_get_results_file(m1)
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+ # Perform a change
|
|
|
cb1cc6 |
+ from_groups = Groups(m1, basedn=DEFAULT_SUFFIX, rdn=None)
|
|
|
cb1cc6 |
+ from_group = from_groups.get('replication_managers')
|
|
|
cb1cc6 |
+ change = str(uuid.uuid4())
|
|
|
cb1cc6 |
+ from_group.replace('description', change)
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+ # Poke replication to trigger thev leak
|
|
|
cb1cc6 |
+ replica = Replicas(m1).get(DEFAULT_SUFFIX)
|
|
|
cb1cc6 |
+ agmt = Agreements(m1, replica.dn).list()[0]
|
|
|
cb1cc6 |
+ for i in range(0, 100):
|
|
|
cb1cc6 |
+ agmt.pause()
|
|
|
cb1cc6 |
+ agmt.resume()
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+ m1.stop()
|
|
|
cb1cc6 |
+ assert m1.searchErrorsLog("worthy")
|
|
|
cb1cc6 |
+ assert not valgrind_check_file(resfile, 'slapi_ldap_get_lderrno');
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
diff --git a/ldap/servers/plugins/chainingdb/cb_search.c b/ldap/servers/plugins/chainingdb/cb_search.c
|
|
|
cb1cc6 |
index ffc8f56f8..d6f30b357 100644
|
|
|
cb1cc6 |
--- a/ldap/servers/plugins/chainingdb/cb_search.c
|
|
|
cb1cc6 |
+++ b/ldap/servers/plugins/chainingdb/cb_search.c
|
|
|
cb1cc6 |
@@ -348,10 +348,9 @@ chainingdb_build_candidate_list(Slapi_PBlock *pb)
|
|
|
cb1cc6 |
warned_rc = 1;
|
|
|
cb1cc6 |
}
|
|
|
cb1cc6 |
cb_send_ldap_result(pb, rc, NULL, ENDUSERMSG, 0, NULL);
|
|
|
cb1cc6 |
- /* BEWARE: matched_msg and error_msg points */
|
|
|
cb1cc6 |
+ /* BEWARE: matched_msg points */
|
|
|
cb1cc6 |
/* to ld fields. */
|
|
|
cb1cc6 |
matched_msg = NULL;
|
|
|
cb1cc6 |
- error_msg = NULL;
|
|
|
cb1cc6 |
rc = -1;
|
|
|
cb1cc6 |
}
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
@@ -695,10 +694,9 @@ chainingdb_next_search_entry(Slapi_PBlock *pb)
|
|
|
cb1cc6 |
}
|
|
|
cb1cc6 |
cb_send_ldap_result(pb, rc, matched_msg, ENDUSERMSG, 0, NULL);
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
- /* BEWARE: Don't free matched_msg && error_msg */
|
|
|
cb1cc6 |
+ /* BEWARE: Don't free matched_msg */
|
|
|
cb1cc6 |
/* Points to the ld fields */
|
|
|
cb1cc6 |
matched_msg = NULL;
|
|
|
cb1cc6 |
- error_msg = NULL;
|
|
|
cb1cc6 |
retcode = -1;
|
|
|
cb1cc6 |
} else {
|
|
|
cb1cc6 |
/* Add control response sent by the farm server */
|
|
|
cb1cc6 |
diff --git a/ldap/servers/plugins/passthru/ptbind.c b/ldap/servers/plugins/passthru/ptbind.c
|
|
|
cb1cc6 |
index 705ab2c3a..3e79b47f6 100644
|
|
|
cb1cc6 |
--- a/ldap/servers/plugins/passthru/ptbind.c
|
|
|
cb1cc6 |
+++ b/ldap/servers/plugins/passthru/ptbind.c
|
|
|
cb1cc6 |
@@ -33,6 +33,8 @@ passthru_simple_bind_once_s(PassThruServer *srvr, const char *dn, struct berval
|
|
|
cb1cc6 |
* are only interested in recovering silently when the remote server is up
|
|
|
cb1cc6 |
* but decided to close our connection, we retry without pausing between
|
|
|
cb1cc6 |
* attempts.
|
|
|
cb1cc6 |
+ *
|
|
|
cb1cc6 |
+ * Note that errmsgp must be freed by the caller.
|
|
|
cb1cc6 |
*/
|
|
|
cb1cc6 |
int
|
|
|
cb1cc6 |
passthru_simple_bind_s(Slapi_PBlock *pb, PassThruServer *srvr, int tries, const char *dn, struct berval *creds, LDAPControl **reqctrls, int *lderrnop, char **matcheddnp, char **errmsgp, struct berval ***refurlsp, LDAPControl ***resctrlsp)
|
|
|
cb1cc6 |
diff --git a/ldap/servers/plugins/replication/repl5_connection.c b/ldap/servers/plugins/replication/repl5_connection.c
|
|
|
cb1cc6 |
index 2dd74f9e7..b6bc21c46 100644
|
|
|
cb1cc6 |
--- a/ldap/servers/plugins/replication/repl5_connection.c
|
|
|
cb1cc6 |
+++ b/ldap/servers/plugins/replication/repl5_connection.c
|
|
|
cb1cc6 |
@@ -244,6 +244,7 @@ conn_delete_internal(Repl_Connection *conn)
|
|
|
cb1cc6 |
PR_ASSERT(NULL != conn);
|
|
|
cb1cc6 |
close_connection_internal(conn);
|
|
|
cb1cc6 |
/* slapi_ch_free accepts NULL pointer */
|
|
|
cb1cc6 |
+ slapi_ch_free_string(&conn->last_ldap_errmsg);
|
|
|
cb1cc6 |
slapi_ch_free((void **)&conn->hostname);
|
|
|
cb1cc6 |
slapi_ch_free((void **)&conn->binddn);
|
|
|
cb1cc6 |
slapi_ch_free((void **)&conn->plain);
|
|
|
cb1cc6 |
@@ -450,6 +451,7 @@ conn_read_result_ex(Repl_Connection *conn, char **retoidp, struct berval **retda
|
|
|
cb1cc6 |
char *s = NULL;
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
rc = slapi_ldap_get_lderrno(conn->ld, NULL, &s);
|
|
|
cb1cc6 |
+ slapi_ch_free_string(&conn->last_ldap_errmsg);
|
|
|
cb1cc6 |
conn->last_ldap_errmsg = s;
|
|
|
cb1cc6 |
conn->last_ldap_error = rc;
|
|
|
cb1cc6 |
/* some errors will require a disconnect and retry the connection
|
|
|
cb1cc6 |
@@ -1937,6 +1939,7 @@ bind_and_check_pwp(Repl_Connection *conn, char *binddn, char *password)
|
|
|
cb1cc6 |
agmt_get_long_name(conn->agmt),
|
|
|
cb1cc6 |
mech ? mech : "SIMPLE", rc,
|
|
|
cb1cc6 |
ldap_err2string(rc), errmsg ? errmsg : "");
|
|
|
cb1cc6 |
+ slapi_ch_free_string(&errmsg);
|
|
|
cb1cc6 |
} else {
|
|
|
cb1cc6 |
char *errmsg = NULL;
|
|
|
cb1cc6 |
/* errmsg is a pointer directly into the ld structure - do not free */
|
|
|
cb1cc6 |
@@ -1946,6 +1949,7 @@ bind_and_check_pwp(Repl_Connection *conn, char *binddn, char *password)
|
|
|
cb1cc6 |
agmt_get_long_name(conn->agmt),
|
|
|
cb1cc6 |
mech ? mech : "SIMPLE", rc,
|
|
|
cb1cc6 |
ldap_err2string(rc), errmsg ? errmsg : "");
|
|
|
cb1cc6 |
+ slapi_ch_free_string(&errmsg);
|
|
|
cb1cc6 |
}
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
return (CONN_OPERATION_FAILED);
|
|
|
cb1cc6 |
diff --git a/ldap/servers/plugins/replication/windows_connection.c b/ldap/servers/plugins/replication/windows_connection.c
|
|
|
cb1cc6 |
index 5eca5fad1..d3f6a4e93 100644
|
|
|
cb1cc6 |
--- a/ldap/servers/plugins/replication/windows_connection.c
|
|
|
cb1cc6 |
+++ b/ldap/servers/plugins/replication/windows_connection.c
|
|
|
cb1cc6 |
@@ -331,6 +331,7 @@ windows_perform_operation(Repl_Connection *conn, int optype, const char *dn, LDA
|
|
|
cb1cc6 |
"windows_perform_operation - %s: Received error %d: %s for %s operation\n",
|
|
|
cb1cc6 |
agmt_get_long_name(conn->agmt),
|
|
|
cb1cc6 |
rc, s ? s : "NULL", op_string);
|
|
|
cb1cc6 |
+ slapi_ch_free_string(&s);
|
|
|
cb1cc6 |
conn->last_ldap_error = rc;
|
|
|
cb1cc6 |
/* some errors will require a disconnect and retry the connection
|
|
|
cb1cc6 |
later */
|
|
|
cb1cc6 |
@@ -1709,6 +1710,7 @@ bind_and_check_pwp(Repl_Connection *conn, char *binddn, char *password)
|
|
|
cb1cc6 |
agmt_get_long_name(conn->agmt),
|
|
|
cb1cc6 |
mech ? mech : "SIMPLE", rc,
|
|
|
cb1cc6 |
ldap_err2string(rc), errmsg);
|
|
|
cb1cc6 |
+ slapi_ch_free_string(&errmsg);
|
|
|
cb1cc6 |
} else {
|
|
|
cb1cc6 |
char *errmsg = NULL;
|
|
|
cb1cc6 |
/* errmsg is a pointer directly into the ld structure - do not free */
|
|
|
cb1cc6 |
@@ -1718,6 +1720,7 @@ bind_and_check_pwp(Repl_Connection *conn, char *binddn, char *password)
|
|
|
cb1cc6 |
agmt_get_long_name(conn->agmt),
|
|
|
cb1cc6 |
mech ? mech : "SIMPLE", rc,
|
|
|
cb1cc6 |
ldap_err2string(rc), errmsg);
|
|
|
cb1cc6 |
+ slapi_ch_free_string(&errmsg);
|
|
|
cb1cc6 |
}
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
slapi_log_err(SLAPI_LOG_TRACE, windows_repl_plugin_name, "<= bind_and_check_pwp - CONN_OPERATION_FAILED\n");
|
|
|
cb1cc6 |
diff --git a/ldap/servers/slapd/ldaputil.c b/ldap/servers/slapd/ldaputil.c
|
|
|
cb1cc6 |
index 336ca3912..db3300e30 100644
|
|
|
cb1cc6 |
--- a/ldap/servers/slapd/ldaputil.c
|
|
|
cb1cc6 |
+++ b/ldap/servers/slapd/ldaputil.c
|
|
|
cb1cc6 |
@@ -375,6 +375,8 @@ slapi_ldap_url_parse(const char *url, LDAPURLDesc **ludpp, int require_dn, int *
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
#include <sasl/sasl.h>
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+/* Warning: caller must free s (if not NULL) */
|
|
|
cb1cc6 |
int
|
|
|
cb1cc6 |
slapi_ldap_get_lderrno(LDAP *ld, char **m, char **s)
|
|
|
cb1cc6 |
{
|
|
|
cb1cc6 |
@@ -389,6 +391,9 @@ slapi_ldap_get_lderrno(LDAP *ld, char **m, char **s)
|
|
|
cb1cc6 |
ldap_get_option(ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, s);
|
|
|
cb1cc6 |
#else
|
|
|
cb1cc6 |
ldap_get_option(ld, LDAP_OPT_ERROR_STRING, s);
|
|
|
cb1cc6 |
+ if (*s) {
|
|
|
cb1cc6 |
+ *s = slapi_ch_strdup(*s);
|
|
|
cb1cc6 |
+ }
|
|
|
cb1cc6 |
#endif
|
|
|
cb1cc6 |
}
|
|
|
cb1cc6 |
return rc;
|
|
|
cb1cc6 |
@@ -1517,6 +1522,7 @@ slapd_ldap_sasl_interactive_bind(
|
|
|
cb1cc6 |
mech ? mech : "SIMPLE",
|
|
|
cb1cc6 |
rc, ldap_err2string(rc), errmsg,
|
|
|
cb1cc6 |
errno, slapd_system_strerror(errno));
|
|
|
cb1cc6 |
+ slapi_ch_free_string(&errmsg);
|
|
|
cb1cc6 |
if (can_retry_bind(ld, mech, bindid, creds, rc, errmsg)) {
|
|
|
cb1cc6 |
; /* pass through to retry one time */
|
|
|
cb1cc6 |
} else {
|
|
|
cb1cc6 |
diff --git a/src/lib389/lib389/_mapped_object.py b/src/lib389/lib389/_mapped_object.py
|
|
|
cb1cc6 |
index 48d3879a3..1c314322b 100644
|
|
|
cb1cc6 |
--- a/src/lib389/lib389/_mapped_object.py
|
|
|
cb1cc6 |
+++ b/src/lib389/lib389/_mapped_object.py
|
|
|
cb1cc6 |
@@ -67,6 +67,34 @@ def _gen_filter(attrtypes, values, extra=None):
|
|
|
cb1cc6 |
return filt
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
+# Define wrappers around the ldap operation to have a clear diagnostic
|
|
|
cb1cc6 |
+def _ldap_op_s(inst, f, fname, *args, **kwargs):
|
|
|
cb1cc6 |
+ # f.__name__ says 'inner' so the wanted name is provided as argument
|
|
|
cb1cc6 |
+ try:
|
|
|
cb1cc6 |
+ return f(*args, **kwargs)
|
|
|
cb1cc6 |
+ except ldap.LDAPError as e:
|
|
|
cb1cc6 |
+ new_desc = f"{fname}({args},{kwargs}) on instance {inst.serverid}";
|
|
|
cb1cc6 |
+ if len(e.args) >= 1:
|
|
|
cb1cc6 |
+ e.args[0]['ldap_request'] = new_desc
|
|
|
cb1cc6 |
+ logging.getLogger().error(f"args={e.args}")
|
|
|
cb1cc6 |
+ raise
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+def _add_ext_s(inst, *args, **kwargs):
|
|
|
cb1cc6 |
+ return _ldap_op_s(inst, inst.add_ext_s, 'add_ext_s', *args, **kwargs)
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+def _modify_ext_s(inst, *args, **kwargs):
|
|
|
cb1cc6 |
+ return _ldap_op_s(inst, inst.modify_ext_s, 'modify_ext_s', *args, **kwargs)
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+def _delete_ext_s(inst, *args, **kwargs):
|
|
|
cb1cc6 |
+ return _ldap_op_s(inst, inst.delete_ext_s, 'delete_ext_s', *args, **kwargs)
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+def _search_ext_s(inst, *args, **kwargs):
|
|
|
cb1cc6 |
+ return _ldap_op_s(inst, inst.search_ext_s, 'search_ext_s', *args, **kwargs)
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+def _search_s(inst, *args, **kwargs):
|
|
|
cb1cc6 |
+ return _ldap_op_s(inst, inst.search_s, 'search_s', *args, **kwargs)
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
class DSLogging(object):
|
|
|
cb1cc6 |
"""The benefit of this is automatic name detection, and correct application
|
|
|
cb1cc6 |
of level and verbosity to the object.
|
|
|
cb1cc6 |
@@ -129,7 +157,7 @@ class DSLdapObject(DSLogging, DSLint):
|
|
|
cb1cc6 |
:returns: Entry object
|
|
|
cb1cc6 |
"""
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
- return self._instance.search_ext_s(self._dn, ldap.SCOPE_BASE, self._object_filter, attrlist=["*"],
|
|
|
cb1cc6 |
+ return _search_ext_s(self._instance,self._dn, ldap.SCOPE_BASE, self._object_filter, attrlist=["*"],
|
|
|
cb1cc6 |
serverctrls=self._server_controls, clientctrls=self._client_controls,
|
|
|
cb1cc6 |
escapehatch='i am sure')[0]
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
@@ -140,7 +168,7 @@ class DSLdapObject(DSLogging, DSLint):
|
|
|
cb1cc6 |
"""
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
try:
|
|
|
cb1cc6 |
- self._instance.search_ext_s(self._dn, ldap.SCOPE_BASE, self._object_filter, attrsonly=1,
|
|
|
cb1cc6 |
+ _search_ext_s(self._instance,self._dn, ldap.SCOPE_BASE, self._object_filter, attrsonly=1,
|
|
|
cb1cc6 |
serverctrls=self._server_controls, clientctrls=self._client_controls,
|
|
|
cb1cc6 |
escapehatch='i am sure')
|
|
|
cb1cc6 |
except ldap.NO_SUCH_OBJECT:
|
|
|
cb1cc6 |
@@ -156,7 +184,7 @@ class DSLdapObject(DSLogging, DSLint):
|
|
|
cb1cc6 |
search_scope = ldap.SCOPE_ONE
|
|
|
cb1cc6 |
elif scope == 'subtree':
|
|
|
cb1cc6 |
search_scope = ldap.SCOPE_SUBTREE
|
|
|
cb1cc6 |
- return self._instance.search_ext_s(self._dn, search_scope, filter,
|
|
|
cb1cc6 |
+ return _search_ext_s(self._instance,self._dn, search_scope, filter,
|
|
|
cb1cc6 |
serverctrls=self._server_controls,
|
|
|
cb1cc6 |
clientctrls=self._client_controls,
|
|
|
cb1cc6 |
escapehatch='i am sure')
|
|
|
cb1cc6 |
@@ -166,7 +194,7 @@ class DSLdapObject(DSLogging, DSLint):
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
:returns: LDIF formatted string
|
|
|
cb1cc6 |
"""
|
|
|
cb1cc6 |
- e = self._instance.search_ext_s(self._dn, ldap.SCOPE_BASE, self._object_filter, attrlist=attrlist,
|
|
|
cb1cc6 |
+ e = _search_ext_s(self._instance,self._dn, ldap.SCOPE_BASE, self._object_filter, attrlist=attrlist,
|
|
|
cb1cc6 |
serverctrls=self._server_controls, clientctrls=self._client_controls,
|
|
|
cb1cc6 |
escapehatch='i am sure')[0]
|
|
|
cb1cc6 |
return e.__repr__()
|
|
|
cb1cc6 |
@@ -258,7 +286,7 @@ class DSLdapObject(DSLogging, DSLint):
|
|
|
cb1cc6 |
raise ValueError("Invalid state. Cannot get presence on instance that is not ONLINE")
|
|
|
cb1cc6 |
self._log.debug("%s present(%r) %s" % (self._dn, attr, value))
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
- self._instance.search_ext_s(self._dn, ldap.SCOPE_BASE, self._object_filter, attrlist=[attr, ],
|
|
|
cb1cc6 |
+ _search_ext_s(self._instance,self._dn, ldap.SCOPE_BASE, self._object_filter, attrlist=[attr, ],
|
|
|
cb1cc6 |
serverctrls=self._server_controls, clientctrls=self._client_controls,
|
|
|
cb1cc6 |
escapehatch='i am sure')[0]
|
|
|
cb1cc6 |
values = self.get_attr_vals_bytes(attr)
|
|
|
cb1cc6 |
@@ -313,7 +341,7 @@ class DSLdapObject(DSLogging, DSLint):
|
|
|
cb1cc6 |
else:
|
|
|
cb1cc6 |
value = [ensure_bytes(arg[1])]
|
|
|
cb1cc6 |
mods.append((ldap.MOD_REPLACE, ensure_str(arg[0]), value))
|
|
|
cb1cc6 |
- return self._instance.modify_ext_s(self._dn, mods, serverctrls=self._server_controls,
|
|
|
cb1cc6 |
+ return _modify_ext_s(self._instance,self._dn, mods, serverctrls=self._server_controls,
|
|
|
cb1cc6 |
clientctrls=self._client_controls, escapehatch='i am sure')
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
# This needs to work on key + val, and key
|
|
|
cb1cc6 |
@@ -457,7 +485,7 @@ class DSLdapObject(DSLogging, DSLint):
|
|
|
cb1cc6 |
elif value is not None:
|
|
|
cb1cc6 |
value = [ensure_bytes(value)]
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
- return self._instance.modify_ext_s(self._dn, [(action, key, value)],
|
|
|
cb1cc6 |
+ return _modify_ext_s(self._instance,self._dn, [(action, key, value)],
|
|
|
cb1cc6 |
serverctrls=self._server_controls, clientctrls=self._client_controls,
|
|
|
cb1cc6 |
escapehatch='i am sure')
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
@@ -497,7 +525,7 @@ class DSLdapObject(DSLogging, DSLint):
|
|
|
cb1cc6 |
else:
|
|
|
cb1cc6 |
# Error too many items
|
|
|
cb1cc6 |
raise ValueError('Too many arguments in the mod op')
|
|
|
cb1cc6 |
- return self._instance.modify_ext_s(self._dn, mod_list, serverctrls=self._server_controls, clientctrls=self._client_controls, escapehatch='i am sure')
|
|
|
cb1cc6 |
+ return _modify_ext_s(self._instance,self._dn, mod_list, serverctrls=self._server_controls, clientctrls=self._client_controls, escapehatch='i am sure')
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
def _unsafe_compare_attribute(self, other):
|
|
|
cb1cc6 |
"""Compare two attributes from two objects. This is currently marked unsafe as it's
|
|
|
cb1cc6 |
@@ -593,7 +621,7 @@ class DSLdapObject(DSLogging, DSLint):
|
|
|
cb1cc6 |
raise ValueError("Invalid state. Cannot get properties on instance that is not ONLINE")
|
|
|
cb1cc6 |
else:
|
|
|
cb1cc6 |
# retrieving real(*) and operational attributes(+)
|
|
|
cb1cc6 |
- attrs_entry = self._instance.search_ext_s(self._dn, ldap.SCOPE_BASE, self._object_filter,
|
|
|
cb1cc6 |
+ attrs_entry = _search_ext_s(self._instance,self._dn, ldap.SCOPE_BASE, self._object_filter,
|
|
|
cb1cc6 |
attrlist=["*", "+"], serverctrls=self._server_controls,
|
|
|
cb1cc6 |
clientctrls=self._client_controls, escapehatch='i am sure')[0]
|
|
|
cb1cc6 |
# getting dict from 'entry' object
|
|
|
cb1cc6 |
@@ -613,7 +641,7 @@ class DSLdapObject(DSLogging, DSLint):
|
|
|
cb1cc6 |
raise ValueError("Invalid state. Cannot get properties on instance that is not ONLINE")
|
|
|
cb1cc6 |
else:
|
|
|
cb1cc6 |
# retrieving real(*) and operational attributes(+)
|
|
|
cb1cc6 |
- attrs_entry = self._instance.search_ext_s(self._dn, ldap.SCOPE_BASE, self._object_filter,
|
|
|
cb1cc6 |
+ attrs_entry = _search_ext_s(self._instance,self._dn, ldap.SCOPE_BASE, self._object_filter,
|
|
|
cb1cc6 |
attrlist=["*", "+"], serverctrls=self._server_controls,
|
|
|
cb1cc6 |
clientctrls=self._client_controls, escapehatch='i am sure')[0]
|
|
|
cb1cc6 |
# getting dict from 'entry' object
|
|
|
cb1cc6 |
@@ -627,7 +655,7 @@ class DSLdapObject(DSLogging, DSLint):
|
|
|
cb1cc6 |
if self._instance.state != DIRSRV_STATE_ONLINE:
|
|
|
cb1cc6 |
raise ValueError("Invalid state. Cannot get properties on instance that is not ONLINE")
|
|
|
cb1cc6 |
else:
|
|
|
cb1cc6 |
- entry = self._instance.search_ext_s(self._dn, ldap.SCOPE_BASE, self._object_filter,
|
|
|
cb1cc6 |
+ entry = _search_ext_s(self._instance,self._dn, ldap.SCOPE_BASE, self._object_filter,
|
|
|
cb1cc6 |
attrlist=keys, serverctrls=self._server_controls,
|
|
|
cb1cc6 |
clientctrls=self._client_controls, escapehatch='i am sure')[0]
|
|
|
cb1cc6 |
return entry.getValuesSet(keys)
|
|
|
cb1cc6 |
@@ -636,7 +664,7 @@ class DSLdapObject(DSLogging, DSLint):
|
|
|
cb1cc6 |
self._log.debug("%s get_attrs_vals_utf8(%r)" % (self._dn, keys))
|
|
|
cb1cc6 |
if self._instance.state != DIRSRV_STATE_ONLINE:
|
|
|
cb1cc6 |
raise ValueError("Invalid state. Cannot get properties on instance that is not ONLINE")
|
|
|
cb1cc6 |
- entry = self._instance.search_ext_s(self._dn, ldap.SCOPE_BASE, self._object_filter, attrlist=keys,
|
|
|
cb1cc6 |
+ entry = _search_ext_s(self._instance,self._dn, ldap.SCOPE_BASE, self._object_filter, attrlist=keys,
|
|
|
cb1cc6 |
serverctrls=self._server_controls, clientctrls=self._client_controls,
|
|
|
cb1cc6 |
escapehatch='i am sure')[0]
|
|
|
cb1cc6 |
vset = entry.getValuesSet(keys)
|
|
|
cb1cc6 |
@@ -655,7 +683,7 @@ class DSLdapObject(DSLogging, DSLint):
|
|
|
cb1cc6 |
else:
|
|
|
cb1cc6 |
# It would be good to prevent the entry code intercepting this ....
|
|
|
cb1cc6 |
# We have to do this in this method, because else we ignore the scope base.
|
|
|
cb1cc6 |
- entry = self._instance.search_ext_s(self._dn, ldap.SCOPE_BASE, self._object_filter,
|
|
|
cb1cc6 |
+ entry = _search_ext_s(self._instance,self._dn, ldap.SCOPE_BASE, self._object_filter,
|
|
|
cb1cc6 |
attrlist=[key], serverctrls=self._server_controls,
|
|
|
cb1cc6 |
clientctrls=self._client_controls, escapehatch='i am sure')[0]
|
|
|
cb1cc6 |
vals = entry.getValues(key)
|
|
|
cb1cc6 |
@@ -675,7 +703,7 @@ class DSLdapObject(DSLogging, DSLint):
|
|
|
cb1cc6 |
# In the future, I plan to add a mode where if local == true, we
|
|
|
cb1cc6 |
# can use get on dse.ldif to get values offline.
|
|
|
cb1cc6 |
else:
|
|
|
cb1cc6 |
- entry = self._instance.search_ext_s(self._dn, ldap.SCOPE_BASE, self._object_filter,
|
|
|
cb1cc6 |
+ entry = _search_ext_s(self._instance,self._dn, ldap.SCOPE_BASE, self._object_filter,
|
|
|
cb1cc6 |
attrlist=[key], serverctrls=self._server_controls,
|
|
|
cb1cc6 |
clientctrls=self._client_controls, escapehatch='i am sure')[0]
|
|
|
cb1cc6 |
return entry.getValue(key)
|
|
|
cb1cc6 |
@@ -831,11 +859,11 @@ class DSLdapObject(DSLogging, DSLint):
|
|
|
cb1cc6 |
# Is there a way to mark this as offline and kill it
|
|
|
cb1cc6 |
if recursive:
|
|
|
cb1cc6 |
filterstr = "(|(objectclass=*)(objectclass=ldapsubentry))"
|
|
|
cb1cc6 |
- ents = self._instance.search_s(self._dn, ldap.SCOPE_SUBTREE, filterstr, escapehatch='i am sure')
|
|
|
cb1cc6 |
+ ents = _search_s(self._instance, self._dn, ldap.SCOPE_SUBTREE, filterstr, escapehatch='i am sure')
|
|
|
cb1cc6 |
for ent in sorted(ents, key=lambda e: len(e.dn), reverse=True):
|
|
|
cb1cc6 |
- self._instance.delete_ext_s(ent.dn, serverctrls=self._server_controls, clientctrls=self._client_controls, escapehatch='i am sure')
|
|
|
cb1cc6 |
+ _delete_ext_s(self._instance, ent.dn, serverctrls=self._server_controls, clientctrls=self._client_controls, escapehatch='i am sure')
|
|
|
cb1cc6 |
else:
|
|
|
cb1cc6 |
- self._instance.delete_ext_s(self._dn, serverctrls=self._server_controls, clientctrls=self._client_controls, escapehatch='i am sure')
|
|
|
cb1cc6 |
+ _delete_ext_s(self._instance, self._dn, serverctrls=self._server_controls, clientctrls=self._client_controls, escapehatch='i am sure')
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
def _validate(self, rdn, properties, basedn):
|
|
|
cb1cc6 |
"""Used to validate a create request.
|
|
|
cb1cc6 |
@@ -933,7 +961,7 @@ class DSLdapObject(DSLogging, DSLint):
|
|
|
cb1cc6 |
# If we are running in stateful ensure mode, we need to check if the object exists, and
|
|
|
cb1cc6 |
# we can see the state that it is in.
|
|
|
cb1cc6 |
try:
|
|
|
cb1cc6 |
- self._instance.search_ext_s(dn, ldap.SCOPE_BASE, self._object_filter, attrsonly=1, serverctrls=self._server_controls, clientctrls=self._client_controls, escapehatch='i am sure')
|
|
|
cb1cc6 |
+ _search_ext_s(self._instance,dn, ldap.SCOPE_BASE, self._object_filter, attrsonly=1, serverctrls=self._server_controls, clientctrls=self._client_controls, escapehatch='i am sure')
|
|
|
cb1cc6 |
exists = True
|
|
|
cb1cc6 |
except ldap.NO_SUCH_OBJECT:
|
|
|
cb1cc6 |
pass
|
|
|
cb1cc6 |
@@ -946,7 +974,7 @@ class DSLdapObject(DSLogging, DSLint):
|
|
|
cb1cc6 |
mods = []
|
|
|
cb1cc6 |
for k, v in list(valid_props.items()):
|
|
|
cb1cc6 |
mods.append((ldap.MOD_REPLACE, k, v))
|
|
|
cb1cc6 |
- self._instance.modify_ext_s(self._dn, mods, serverctrls=self._server_controls, clientctrls=self._client_controls, escapehatch='i am sure')
|
|
|
cb1cc6 |
+ _modify_ext_s(self._instance,self._dn, mods, serverctrls=self._server_controls, clientctrls=self._client_controls, escapehatch='i am sure')
|
|
|
cb1cc6 |
elif not exists:
|
|
|
cb1cc6 |
# This case is reached in two cases. One is we are in ensure mode, and we KNOW the entry
|
|
|
cb1cc6 |
# doesn't exist.
|
|
|
cb1cc6 |
@@ -957,7 +985,7 @@ class DSLdapObject(DSLogging, DSLint):
|
|
|
cb1cc6 |
e.update({'objectclass': ensure_list_bytes(self._create_objectclasses)})
|
|
|
cb1cc6 |
e.update(valid_props)
|
|
|
cb1cc6 |
# We rely on exceptions here to indicate failure to the parent.
|
|
|
cb1cc6 |
- self._instance.add_ext_s(e, serverctrls=self._server_controls, clientctrls=self._client_controls, escapehatch='i am sure')
|
|
|
cb1cc6 |
+ _add_ext_s(self._instance, e, serverctrls=self._server_controls, clientctrls=self._client_controls, escapehatch='i am sure')
|
|
|
cb1cc6 |
self._log.debug('Created entry %s : %s' % (dn, display_log_data(e.data)))
|
|
|
cb1cc6 |
# If it worked, we need to fix our instance dn for the object's self reference. Because
|
|
|
cb1cc6 |
# we may not have a self reference yet (just created), it may have changed (someone
|
|
|
cb1cc6 |
@@ -1104,7 +1132,7 @@ class DSLdapObjects(DSLogging, DSLints):
|
|
|
cb1cc6 |
else:
|
|
|
cb1cc6 |
# If not paged
|
|
|
cb1cc6 |
try:
|
|
|
cb1cc6 |
- results = self._instance.search_ext_s(
|
|
|
cb1cc6 |
+ results = _search_ext_s(self._instance,
|
|
|
cb1cc6 |
base=self._basedn,
|
|
|
cb1cc6 |
scope=self._scope,
|
|
|
cb1cc6 |
filterstr=filterstr,
|
|
|
cb1cc6 |
@@ -1172,7 +1200,7 @@ class DSLdapObjects(DSLogging, DSLints):
|
|
|
cb1cc6 |
filterstr = self._get_objectclass_filter()
|
|
|
cb1cc6 |
self._log.debug('_gen_dn filter = %s' % filterstr)
|
|
|
cb1cc6 |
self._log.debug('_gen_dn dn = %s' % dn)
|
|
|
cb1cc6 |
- return self._instance.search_ext_s(
|
|
|
cb1cc6 |
+ return _search_ext_s(self._instance,
|
|
|
cb1cc6 |
base=dn,
|
|
|
cb1cc6 |
scope=ldap.SCOPE_BASE,
|
|
|
cb1cc6 |
filterstr=filterstr,
|
|
|
cb1cc6 |
@@ -1187,7 +1215,7 @@ class DSLdapObjects(DSLogging, DSLints):
|
|
|
cb1cc6 |
# This will yield and & filter for objectClass with as many terms as needed.
|
|
|
cb1cc6 |
filterstr = self._get_selector_filter(selector)
|
|
|
cb1cc6 |
self._log.debug('_gen_selector filter = %s' % filterstr)
|
|
|
cb1cc6 |
- return self._instance.search_ext_s(
|
|
|
cb1cc6 |
+ return _search_ext_s(self._instance,
|
|
|
cb1cc6 |
base=self._basedn,
|
|
|
cb1cc6 |
scope=self._scope,
|
|
|
cb1cc6 |
filterstr=filterstr,
|
|
|
cb1cc6 |
@@ -1261,7 +1289,7 @@ class DSLdapObjects(DSLogging, DSLints):
|
|
|
cb1cc6 |
self._list_attrlist = attrlist
|
|
|
cb1cc6 |
self._log.debug(f'list filter = {search_filter} with scope {scope} and attribute list {attrlist}')
|
|
|
cb1cc6 |
try:
|
|
|
cb1cc6 |
- results = self._instance.search_ext_s(
|
|
|
cb1cc6 |
+ results = _search_ext_s(self._instance,
|
|
|
cb1cc6 |
base=self._basedn,
|
|
|
cb1cc6 |
scope=scope,
|
|
|
cb1cc6 |
filterstr=search_filter,
|
|
|
cb1cc6 |
diff --git a/src/lib389/lib389/utils.py b/src/lib389/lib389/utils.py
|
|
|
cb1cc6 |
index 6eba2d7b9..da966ed97 100644
|
|
|
cb1cc6 |
--- a/src/lib389/lib389/utils.py
|
|
|
cb1cc6 |
+++ b/src/lib389/lib389/utils.py
|
|
|
cb1cc6 |
@@ -52,7 +52,7 @@ from ldapurl import LDAPUrl
|
|
|
cb1cc6 |
from contextlib import closing
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
import lib389
|
|
|
cb1cc6 |
-from lib389.paths import Paths
|
|
|
cb1cc6 |
+from lib389.paths import ( Paths, DEFAULTS_PATH )
|
|
|
cb1cc6 |
from lib389.dseldif import DSEldif
|
|
|
cb1cc6 |
from lib389._constants import (
|
|
|
cb1cc6 |
DEFAULT_USER, VALGRIND_WRAPPER, DN_CONFIG, CFGSUFFIX, LOCALHOST,
|
|
|
cb1cc6 |
@@ -495,8 +495,10 @@ def valgrind_enable(sbin_dir, wrapper=None):
|
|
|
cb1cc6 |
:raise EnvironmentError: If script is not run as 'root'
|
|
|
cb1cc6 |
'''
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
- if os.geteuid() != 0:
|
|
|
cb1cc6 |
- log.error('This script must be run as root to use valgrind')
|
|
|
cb1cc6 |
+ if not os.access(sbin_dir, os.W_OK):
|
|
|
cb1cc6 |
+ # Note: valgrind has no limitation but ns-slapd must be replaced
|
|
|
cb1cc6 |
+ # This check allows non root user to use custom install prefix
|
|
|
cb1cc6 |
+ log.error('This script must be run as root to use valgrind (Should at least be able to write in {sbin_dir})')
|
|
|
cb1cc6 |
raise EnvironmentError
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
if not wrapper:
|
|
|
cb1cc6 |
@@ -542,7 +544,20 @@ def valgrind_enable(sbin_dir, wrapper=None):
|
|
|
cb1cc6 |
e.strerror)
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
# Disable selinux
|
|
|
cb1cc6 |
- os.system('setenforce 0')
|
|
|
cb1cc6 |
+ if os.geteuid() == 0:
|
|
|
cb1cc6 |
+ os.system('setenforce 0')
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+ # Disable systemd by turning off with_system in .inf file
|
|
|
cb1cc6 |
+ old_path = Paths()._get_defaults_loc(DEFAULTS_PATH)
|
|
|
cb1cc6 |
+ new_path = f'{old_path}.orig'
|
|
|
cb1cc6 |
+ os.rename(old_path, new_path)
|
|
|
cb1cc6 |
+ with open(new_path, 'rt') as fin:
|
|
|
cb1cc6 |
+ with open(old_path, 'wt') as fout:
|
|
|
cb1cc6 |
+ for line in fin:
|
|
|
cb1cc6 |
+ if line.startswith('with_systemd'):
|
|
|
cb1cc6 |
+ fout.write('with_systemd = 0\n')
|
|
|
cb1cc6 |
+ else:
|
|
|
cb1cc6 |
+ fout.write(line)
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
log.info('Valgrind is now enabled.')
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
@@ -559,8 +574,10 @@ def valgrind_disable(sbin_dir):
|
|
|
cb1cc6 |
:raise EnvironmentError: If script is not run as 'root'
|
|
|
cb1cc6 |
'''
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
- if os.geteuid() != 0:
|
|
|
cb1cc6 |
- log.error('This script must be run as root to use valgrind')
|
|
|
cb1cc6 |
+ if not os.access(sbin_dir, os.W_OK):
|
|
|
cb1cc6 |
+ # Note: valgrind has no limitation but ns-slapd must be replaced
|
|
|
cb1cc6 |
+ # This check allows non root user to use custom install prefix
|
|
|
cb1cc6 |
+ log.error('This script must be run as root to use valgrind (Should at least be able to write in {sbin_dir})')
|
|
|
cb1cc6 |
raise EnvironmentError
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
nsslapd_orig = '%s/ns-slapd' % sbin_dir
|
|
|
cb1cc6 |
@@ -584,7 +601,14 @@ def valgrind_disable(sbin_dir):
|
|
|
cb1cc6 |
e.strerror)
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
# Enable selinux
|
|
|
cb1cc6 |
- os.system('setenforce 1')
|
|
|
cb1cc6 |
+ if os.geteuid() == 0:
|
|
|
cb1cc6 |
+ os.system('setenforce 1')
|
|
|
cb1cc6 |
+
|
|
|
cb1cc6 |
+ # Restore .inf file (for systemd)
|
|
|
cb1cc6 |
+ new_path = Paths()._get_defaults_loc(DEFAULTS_PATH)
|
|
|
cb1cc6 |
+ old_path = f'{new_path}.orig'
|
|
|
cb1cc6 |
+ if os.path.exists(old_path):
|
|
|
cb1cc6 |
+ os.replace(old_path, new_path)
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
log.info('Valgrind is now disabled.')
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
@@ -610,7 +634,7 @@ def valgrind_get_results_file(dirsrv_inst):
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
# Run the command and grab the output
|
|
|
cb1cc6 |
p = os.popen(cmd)
|
|
|
cb1cc6 |
- results_file = p.readline()
|
|
|
cb1cc6 |
+ results_file = p.readline().strip()
|
|
|
cb1cc6 |
p.close()
|
|
|
cb1cc6 |
|
|
|
cb1cc6 |
return results_file
|
|
|
cb1cc6 |
--
|
|
|
cb1cc6 |
2.31.1
|
|
|
cb1cc6 |
|