Resolves: RHEL-101727 - The numSubordinates value is not matching the number of direct children.
- Resolves: RHEL-101783 - RHDS12: Web console doesn't show Server Version - Resolves: RHEL-109018 - Allow Uniqueness plugin to search uniqueness attributes using custom matching rules - Resolves: RHEL-111224 - Error showing local password policy on web UI - Resolves: RHEL-112675 - Statistics about index lookup report a wrong duration - Resolves: RHEL-112689 - Crash if repl keep alive entry can not be created - Resolves: RHEL-112722 - Exception thrown by dsconf instance repl get_ruv - Resolves: RHEL-113969 - AddressSanitizer: memory leak in memberof_add_memberof_attr
This commit is contained in:
parent
23917c9198
commit
4d8c2a143b
268
0037-Issue-6940-dsconf-monitor-server-fails-with-ldapi-du.patch
Normal file
268
0037-Issue-6940-dsconf-monitor-server-fails-with-ldapi-du.patch
Normal file
@ -0,0 +1,268 @@
|
||||
From 7423f0a0b90bac39a23b5ce54a1c61439d0ebcb6 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Pichugin <spichugi@redhat.com>
|
||||
Date: Tue, 19 Aug 2025 16:10:09 -0700
|
||||
Subject: [PATCH] Issue 6940 - dsconf monitor server fails with ldapi:// due to
|
||||
absent server ID (#6941)
|
||||
|
||||
Description: The dsconf monitor server command fails when using ldapi://
|
||||
protocol because the server ID is not set, preventing PID retrieval from
|
||||
defaults.inf. This causes the Web console to fail displaying the "Server
|
||||
Version" field and potentially other CLI/WebUI issues.
|
||||
|
||||
The fix attempts to derive the server ID from the LDAPI socket path when
|
||||
not explicitly provided. This covers the common case where the socket name
|
||||
contains the instance name (e.g., slapd-instance.socket).
|
||||
If that's not possible, it also attempts to derive the server ID from the
|
||||
nsslapd-instancedir configuration attribute. The derived server ID
|
||||
is validated against actual system instances to ensure it exists.
|
||||
Note that socket names can vary and nsslapd-instancedir can be changed.
|
||||
This is a best-effort approach for the common naming pattern.
|
||||
|
||||
Also fixes the LDAPI socket path extraction which was incorrectly using
|
||||
offset 9 instead of 8 for ldapi:// URIs.
|
||||
|
||||
The monitor command now handles missing PIDs gracefully, returning zero
|
||||
values for process-specific stats instead of failing completely.
|
||||
|
||||
Fixes: https://github.com/389ds/389-ds-base/issues/6940
|
||||
|
||||
Reviewed by: @vashirov, @mreynolds389 (Thanks!!)
|
||||
---
|
||||
src/lib389/lib389/__init__.py | 93 +++++++++++++++++++++++++++---
|
||||
src/lib389/lib389/cli_base/dsrc.py | 4 +-
|
||||
src/lib389/lib389/monitor.py | 50 ++++++++++++----
|
||||
3 files changed, 124 insertions(+), 23 deletions(-)
|
||||
|
||||
diff --git a/src/lib389/lib389/__init__.py b/src/lib389/lib389/__init__.py
|
||||
index 0ddfca8ae..23a20739f 100644
|
||||
--- a/src/lib389/lib389/__init__.py
|
||||
+++ b/src/lib389/lib389/__init__.py
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
import sys
|
||||
import os
|
||||
-from urllib.parse import urlparse
|
||||
+from urllib.parse import urlparse, unquote
|
||||
import stat
|
||||
import pwd
|
||||
import grp
|
||||
@@ -67,7 +67,8 @@ from lib389.utils import (
|
||||
get_default_db_lib,
|
||||
selinux_present,
|
||||
selinux_label_port,
|
||||
- get_user_is_root)
|
||||
+ get_user_is_root,
|
||||
+ get_instance_list)
|
||||
from lib389.paths import Paths
|
||||
from lib389.nss_ssl import NssSsl
|
||||
from lib389.tasks import BackupTask, RestoreTask, Task
|
||||
@@ -249,6 +250,57 @@ class DirSrv(SimpleLDAPObject, object):
|
||||
self.dbdir = self.ds_paths.db_dir
|
||||
self.changelogdir = os.path.join(os.path.dirname(self.dbdir), DEFAULT_CHANGELOG_DB)
|
||||
|
||||
+ def _extract_serverid_from_string(self, text):
|
||||
+ """Extract serverid from a string containing 'slapd-<serverid>' pattern.
|
||||
+ Returns the serverid or None if not found or validation fails.
|
||||
+ Only attempts derivation if serverid is currently None.
|
||||
+ """
|
||||
+ if getattr(self, 'serverid', None) is not None:
|
||||
+ return None
|
||||
+ if not text:
|
||||
+ return None
|
||||
+
|
||||
+ # Use regex to extract serverid from "slapd-<serverid>" or "slapd-<serverid>.socket"
|
||||
+ match = re.search(r'slapd-([A-Za-z0-9._-]+?)(?:\.socket)?(?:$|/)', text)
|
||||
+ if not match:
|
||||
+ return None
|
||||
+ candidate = match.group(1)
|
||||
+
|
||||
+ self.serverid = candidate
|
||||
+ try:
|
||||
+ insts = get_instance_list()
|
||||
+ except Exception:
|
||||
+ self.serverid = None
|
||||
+ return None
|
||||
+ if f'slapd-{candidate}' in insts or candidate in insts:
|
||||
+ return candidate
|
||||
+ # restore original and report failure
|
||||
+ self.serverid = None
|
||||
+ return None
|
||||
+
|
||||
+ def _derive_serverid_from_ldapi(self):
|
||||
+ """Attempt to derive serverid from an LDAPI socket path or URI and
|
||||
+ verify it exists on the system. Returns the serverid or None.
|
||||
+ """
|
||||
+ socket_path = None
|
||||
+ if hasattr(self, 'ldapi_socket') and self.ldapi_socket:
|
||||
+ socket_path = unquote(self.ldapi_socket)
|
||||
+ elif hasattr(self, 'ldapuri') and isinstance(self.ldapuri, str) and self.ldapuri.startswith('ldapi://'):
|
||||
+ socket_path = unquote(self.ldapuri[len('ldapi://'):])
|
||||
+
|
||||
+ return self._extract_serverid_from_string(socket_path)
|
||||
+
|
||||
+ def _derive_serverid_from_instancedir(self):
|
||||
+ """Extract serverid from nsslapd-instancedir path like '/usr/lib64/dirsrv/slapd-<serverid>'"""
|
||||
+ try:
|
||||
+ from lib389.config import Config
|
||||
+ config = Config(self)
|
||||
+ instancedir = config.get_attr_val_utf8_l("nsslapd-instancedir")
|
||||
+ except Exception:
|
||||
+ return None
|
||||
+
|
||||
+ return self._extract_serverid_from_string(instancedir)
|
||||
+
|
||||
def rebind(self):
|
||||
"""Reconnect to the DS
|
||||
|
||||
@@ -528,6 +580,15 @@ class DirSrv(SimpleLDAPObject, object):
|
||||
self.ldapi_autobind = args.get(SER_LDAPI_AUTOBIND, 'off')
|
||||
self.isLocal = True
|
||||
self.log.debug("Allocate %s with %s", self.__class__, self.ldapi_socket)
|
||||
+ elif self.ldapuri is not None and isinstance(self.ldapuri, str) and self.ldapuri.startswith('ldapi://'):
|
||||
+ # Try to learn serverid from ldapi uri
|
||||
+ try:
|
||||
+ self.ldapi_enabled = 'on'
|
||||
+ self.ldapi_socket = unquote(self.ldapuri[len('ldapi://'):])
|
||||
+ self.ldapi_autobind = args.get(SER_LDAPI_AUTOBIND, 'off')
|
||||
+ self.isLocal = True
|
||||
+ except Exception:
|
||||
+ pass
|
||||
# Settings from args of server attributes
|
||||
self.strict_hostname = args.get(SER_STRICT_HOSTNAME_CHECKING, False)
|
||||
if self.strict_hostname is True:
|
||||
@@ -548,9 +609,16 @@ class DirSrv(SimpleLDAPObject, object):
|
||||
|
||||
self.log.debug("Allocate %s with %s:%s", self.__class__, self.host, (self.sslport or self.port))
|
||||
|
||||
- if SER_SERVERID_PROP in args:
|
||||
- self.ds_paths = Paths(serverid=args[SER_SERVERID_PROP], instance=self, local=self.isLocal)
|
||||
+ # Try to determine serverid if not provided
|
||||
+ if SER_SERVERID_PROP in args and args.get(SER_SERVERID_PROP) is not None:
|
||||
self.serverid = args.get(SER_SERVERID_PROP, None)
|
||||
+ elif getattr(self, 'serverid', None) is None and self.isLocal:
|
||||
+ sid = self._derive_serverid_from_ldapi()
|
||||
+ if sid:
|
||||
+ self.serverid = sid
|
||||
+
|
||||
+ if getattr(self, 'serverid', None):
|
||||
+ self.ds_paths = Paths(serverid=self.serverid, instance=self, local=self.isLocal)
|
||||
else:
|
||||
self.ds_paths = Paths(instance=self, local=self.isLocal)
|
||||
|
||||
@@ -989,6 +1057,17 @@ class DirSrv(SimpleLDAPObject, object):
|
||||
self.__initPart2()
|
||||
self.state = DIRSRV_STATE_ONLINE
|
||||
# Now that we're online, some of our methods may try to query the version online.
|
||||
+
|
||||
+ # After transitioning online, attempt to derive serverid if still unknown.
|
||||
+ # If we find it, refresh ds_paths and rerun __initPart2
|
||||
+ if getattr(self, 'serverid', None) is None and self.isLocal:
|
||||
+ sid = self._derive_serverid_from_instancedir()
|
||||
+ if sid:
|
||||
+ self.serverid = sid
|
||||
+ # Reinitialize paths with the new serverid
|
||||
+ self.ds_paths = Paths(serverid=self.serverid, instance=self, local=self.isLocal)
|
||||
+ if not connOnly:
|
||||
+ self.__initPart2()
|
||||
self.__add_brookers__()
|
||||
|
||||
def close(self):
|
||||
@@ -3537,8 +3616,4 @@ class DirSrv(SimpleLDAPObject, object):
|
||||
"""
|
||||
Get the pid of the running server
|
||||
"""
|
||||
- pid = pid_from_file(self.pid_file())
|
||||
- if pid == 0 or pid is None:
|
||||
- return 0
|
||||
- else:
|
||||
- return pid
|
||||
+ return pid_from_file(self.pid_file())
|
||||
diff --git a/src/lib389/lib389/cli_base/dsrc.py b/src/lib389/lib389/cli_base/dsrc.py
|
||||
index 84567b990..498228ce0 100644
|
||||
--- a/src/lib389/lib389/cli_base/dsrc.py
|
||||
+++ b/src/lib389/lib389/cli_base/dsrc.py
|
||||
@@ -56,7 +56,7 @@ def dsrc_arg_concat(args, dsrc_inst):
|
||||
new_dsrc_inst['args'][SER_ROOT_DN] = new_dsrc_inst['binddn']
|
||||
if new_dsrc_inst['uri'][0:8] == 'ldapi://':
|
||||
new_dsrc_inst['args'][SER_LDAPI_ENABLED] = "on"
|
||||
- new_dsrc_inst['args'][SER_LDAPI_SOCKET] = new_dsrc_inst['uri'][9:]
|
||||
+ new_dsrc_inst['args'][SER_LDAPI_SOCKET] = new_dsrc_inst['uri'][8:]
|
||||
new_dsrc_inst['args'][SER_LDAPI_AUTOBIND] = "on"
|
||||
|
||||
# Make new
|
||||
@@ -170,7 +170,7 @@ def dsrc_to_ldap(path, instance_name, log):
|
||||
dsrc_inst['args'][SER_ROOT_DN] = dsrc_inst['binddn']
|
||||
if dsrc_inst['uri'][0:8] == 'ldapi://':
|
||||
dsrc_inst['args'][SER_LDAPI_ENABLED] = "on"
|
||||
- dsrc_inst['args'][SER_LDAPI_SOCKET] = dsrc_inst['uri'][9:]
|
||||
+ dsrc_inst['args'][SER_LDAPI_SOCKET] = dsrc_inst['uri'][8:]
|
||||
dsrc_inst['args'][SER_LDAPI_AUTOBIND] = "on"
|
||||
|
||||
# Return the dict.
|
||||
diff --git a/src/lib389/lib389/monitor.py b/src/lib389/lib389/monitor.py
|
||||
index 27b99a7e3..bf3e1df76 100644
|
||||
--- a/src/lib389/lib389/monitor.py
|
||||
+++ b/src/lib389/lib389/monitor.py
|
||||
@@ -92,21 +92,47 @@ class Monitor(DSLdapObject):
|
||||
Get CPU and memory stats
|
||||
"""
|
||||
stats = {}
|
||||
- pid = self._instance.get_pid()
|
||||
+ try:
|
||||
+ pid = self._instance.get_pid()
|
||||
+ except Exception:
|
||||
+ pid = None
|
||||
total_mem = psutil.virtual_memory()[0]
|
||||
- p = psutil.Process(pid)
|
||||
- memory_stats = p.memory_full_info()
|
||||
|
||||
- # Get memory & CPU stats
|
||||
+ # Always include total system memory
|
||||
stats['total_mem'] = [str(total_mem)]
|
||||
- stats['rss'] = [str(memory_stats[0])]
|
||||
- stats['vms'] = [str(memory_stats[1])]
|
||||
- stats['swap'] = [str(memory_stats[9])]
|
||||
- stats['mem_rss_percent'] = [str(round(p.memory_percent("rss")))]
|
||||
- stats['mem_vms_percent'] = [str(round(p.memory_percent("vms")))]
|
||||
- stats['mem_swap_percent'] = [str(round(p.memory_percent("swap")))]
|
||||
- stats['total_threads'] = [str(p.num_threads())]
|
||||
- stats['cpu_usage'] = [str(round(p.cpu_percent(interval=0.1)))]
|
||||
+
|
||||
+ # Process-specific stats - only if process is running (pid is not None)
|
||||
+ if pid is not None:
|
||||
+ try:
|
||||
+ p = psutil.Process(pid)
|
||||
+ memory_stats = p.memory_full_info()
|
||||
+
|
||||
+ # Get memory & CPU stats
|
||||
+ stats['rss'] = [str(memory_stats[0])]
|
||||
+ stats['vms'] = [str(memory_stats[1])]
|
||||
+ stats['swap'] = [str(memory_stats[9])]
|
||||
+ stats['mem_rss_percent'] = [str(round(p.memory_percent("rss")))]
|
||||
+ stats['mem_vms_percent'] = [str(round(p.memory_percent("vms")))]
|
||||
+ stats['mem_swap_percent'] = [str(round(p.memory_percent("swap")))]
|
||||
+ stats['total_threads'] = [str(p.num_threads())]
|
||||
+ stats['cpu_usage'] = [str(round(p.cpu_percent(interval=0.1)))]
|
||||
+ except (psutil.NoSuchProcess, psutil.AccessDenied):
|
||||
+ # Process exists in PID file but is not accessible or doesn't exist
|
||||
+ pid = None
|
||||
+
|
||||
+ # If no valid PID, provide zero values for process stats
|
||||
+ if pid is None:
|
||||
+ stats['rss'] = ['0']
|
||||
+ stats['vms'] = ['0']
|
||||
+ stats['swap'] = ['0']
|
||||
+ stats['mem_rss_percent'] = ['0']
|
||||
+ stats['mem_vms_percent'] = ['0']
|
||||
+ stats['mem_swap_percent'] = ['0']
|
||||
+ stats['total_threads'] = ['0']
|
||||
+ stats['cpu_usage'] = ['0']
|
||||
+ stats['server_status'] = ['PID unavailable']
|
||||
+ else:
|
||||
+ stats['server_status'] = ['Server running']
|
||||
|
||||
# Connections to DS
|
||||
if self._instance.port == "0":
|
||||
--
|
||||
2.49.0
|
||||
|
||||
569
0038-Issue-6936-Make-user-subtree-policy-creation-idempot.patch
Normal file
569
0038-Issue-6936-Make-user-subtree-policy-creation-idempot.patch
Normal file
@ -0,0 +1,569 @@
|
||||
From 594333d1a6a8bba4d485b8227c4474e4ca2aa6a4 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Pichugin <spichugi@redhat.com>
|
||||
Date: Tue, 19 Aug 2025 14:30:15 -0700
|
||||
Subject: [PATCH] Issue 6936 - Make user/subtree policy creation idempotent
|
||||
(#6937)
|
||||
|
||||
Description: Correct the CLI mapping typo to use 'nsslapd-pwpolicy-local',
|
||||
rework subtree policy detection to validate CoS templates and add user-policy detection.
|
||||
Make user/subtree policy creation idempotent via ensure_state, and improve deletion
|
||||
logic to distinguish subtree vs user policies and fail if none exist.
|
||||
|
||||
Add a test suite (pwp_history_local_override_test.py) exercising global-only and local-only
|
||||
history enforcement, local overriding global counts, immediate effect of dsconf updates,
|
||||
and fallback to global after removing a user policy, ensuring reliable behavior
|
||||
and preventing regressions.
|
||||
|
||||
Fixes: https://github.com/389ds/389-ds-base/issues/6936
|
||||
|
||||
Reviewed by: @mreynolds389 (Thanks!)
|
||||
---
|
||||
.../pwp_history_local_override_test.py | 351 ++++++++++++++++++
|
||||
src/lib389/lib389/cli_conf/pwpolicy.py | 4 +-
|
||||
src/lib389/lib389/pwpolicy.py | 107 ++++--
|
||||
3 files changed, 424 insertions(+), 38 deletions(-)
|
||||
create mode 100644 dirsrvtests/tests/suites/password/pwp_history_local_override_test.py
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/password/pwp_history_local_override_test.py b/dirsrvtests/tests/suites/password/pwp_history_local_override_test.py
|
||||
new file mode 100644
|
||||
index 000000000..6d72725fa
|
||||
--- /dev/null
|
||||
+++ b/dirsrvtests/tests/suites/password/pwp_history_local_override_test.py
|
||||
@@ -0,0 +1,351 @@
|
||||
+# --- BEGIN COPYRIGHT BLOCK ---
|
||||
+# Copyright (C) 2025 Red Hat, Inc.
|
||||
+# All rights reserved.
|
||||
+#
|
||||
+# License: GPL (version 3 or any later version).
|
||||
+# See LICENSE for details.
|
||||
+# --- END COPYRIGHT BLOCK ---
|
||||
+#
|
||||
+import os
|
||||
+import time
|
||||
+import ldap
|
||||
+import pytest
|
||||
+import subprocess
|
||||
+import logging
|
||||
+
|
||||
+from lib389._constants import DEFAULT_SUFFIX, DN_DM, PASSWORD, DN_CONFIG
|
||||
+from lib389.topologies import topology_st
|
||||
+from lib389.idm.user import UserAccounts
|
||||
+from lib389.idm.domain import Domain
|
||||
+from lib389.pwpolicy import PwPolicyManager
|
||||
+
|
||||
+pytestmark = pytest.mark.tier1
|
||||
+
|
||||
+DEBUGGING = os.getenv("DEBUGGING", default=False)
|
||||
+if DEBUGGING:
|
||||
+ logging.getLogger(__name__).setLevel(logging.DEBUG)
|
||||
+else:
|
||||
+ logging.getLogger(__name__).setLevel(logging.INFO)
|
||||
+log = logging.getLogger(__name__)
|
||||
+
|
||||
+OU_DN = f"ou=People,{DEFAULT_SUFFIX}"
|
||||
+USER_ACI = '(targetattr="userpassword || passwordHistory")(version 3.0; acl "pwp test"; allow (all) userdn="ldap:///self";)'
|
||||
+
|
||||
+
|
||||
+@pytest.fixture(autouse=True, scope="function")
|
||||
+def restore_global_policy(topology_st, request):
|
||||
+ """Snapshot and restore global password policy around each test in this file."""
|
||||
+ inst = topology_st.standalone
|
||||
+ inst.simple_bind_s(DN_DM, PASSWORD)
|
||||
+
|
||||
+ attrs = [
|
||||
+ 'nsslapd-pwpolicy-local',
|
||||
+ 'nsslapd-pwpolicy-inherit-global',
|
||||
+ 'passwordHistory',
|
||||
+ 'passwordInHistory',
|
||||
+ 'passwordChange',
|
||||
+ ]
|
||||
+
|
||||
+ entry = inst.getEntry(DN_CONFIG, ldap.SCOPE_BASE, '(objectClass=*)', attrs)
|
||||
+ saved = {attr: entry.getValue(attr) for attr in attrs}
|
||||
+
|
||||
+ def fin():
|
||||
+ inst.simple_bind_s(DN_DM, PASSWORD)
|
||||
+ for attr, value in saved.items():
|
||||
+ inst.config.replace(attr, value)
|
||||
+
|
||||
+ request.addfinalizer(fin)
|
||||
+
|
||||
+
|
||||
+@pytest.fixture(scope="function")
|
||||
+def setup_entries(topology_st, request):
|
||||
+ """Create test OU and user, and install an ACI for self password changes."""
|
||||
+
|
||||
+ inst = topology_st.standalone
|
||||
+
|
||||
+ suffix = Domain(inst, DEFAULT_SUFFIX)
|
||||
+ suffix.add('aci', USER_ACI)
|
||||
+
|
||||
+ users = UserAccounts(inst, DEFAULT_SUFFIX)
|
||||
+ try:
|
||||
+ user = users.create_test_user(uid=1)
|
||||
+ except ldap.ALREADY_EXISTS:
|
||||
+ user = users.get("test_user_1")
|
||||
+
|
||||
+ def fin():
|
||||
+ pwp = PwPolicyManager(inst)
|
||||
+ try:
|
||||
+ pwp.delete_local_policy(OU_DN)
|
||||
+ except Exception as e:
|
||||
+ if "No password policy" in str(e):
|
||||
+ pass
|
||||
+ else:
|
||||
+ raise e
|
||||
+ try:
|
||||
+ pwp.delete_local_policy(user.dn)
|
||||
+ except Exception as e:
|
||||
+ if "No password policy" in str(e):
|
||||
+ pass
|
||||
+ else:
|
||||
+ raise e
|
||||
+ suffix.remove('aci', USER_ACI)
|
||||
+ request.addfinalizer(fin)
|
||||
+
|
||||
+ return user
|
||||
+
|
||||
+
|
||||
+def set_user_password(inst, user, new_password, bind_as_user_password=None, expect_violation=False):
|
||||
+ if bind_as_user_password is not None:
|
||||
+ user.rebind(bind_as_user_password)
|
||||
+ try:
|
||||
+ user.reset_password(new_password)
|
||||
+ if expect_violation:
|
||||
+ pytest.fail("Password change unexpectedly succeeded")
|
||||
+ except ldap.CONSTRAINT_VIOLATION:
|
||||
+ if not expect_violation:
|
||||
+ pytest.fail("Password change unexpectedly rejected with CONSTRAINT_VIOLATION")
|
||||
+ finally:
|
||||
+ inst.simple_bind_s(DN_DM, PASSWORD)
|
||||
+ time.sleep(1)
|
||||
+
|
||||
+
|
||||
+def set_global_history(inst, enabled: bool, count: int, inherit_global: str = 'on'):
|
||||
+ inst.simple_bind_s(DN_DM, PASSWORD)
|
||||
+ inst.config.replace('nsslapd-pwpolicy-local', 'on')
|
||||
+ inst.config.replace('nsslapd-pwpolicy-inherit-global', inherit_global)
|
||||
+ inst.config.replace('passwordHistory', 'on' if enabled else 'off')
|
||||
+ inst.config.replace('passwordInHistory', str(count))
|
||||
+ inst.config.replace('passwordChange', 'on')
|
||||
+ time.sleep(1)
|
||||
+
|
||||
+
|
||||
+def ensure_local_subtree_policy(inst, count: int, track_update_time: str = 'on'):
|
||||
+ pwp = PwPolicyManager(inst)
|
||||
+ pwp.create_subtree_policy(OU_DN, {
|
||||
+ 'passwordChange': 'on',
|
||||
+ 'passwordHistory': 'on',
|
||||
+ 'passwordInHistory': str(count),
|
||||
+ 'passwordTrackUpdateTime': track_update_time,
|
||||
+ })
|
||||
+ time.sleep(1)
|
||||
+
|
||||
+
|
||||
+def set_local_history_via_cli(inst, count: int):
|
||||
+ sbin_dir = inst.get_sbin_dir()
|
||||
+ inst_name = inst.serverid
|
||||
+ cmd = [f"{sbin_dir}/dsconf", inst_name, "localpwp", "set", f"--pwdhistorycount={count}", OU_DN]
|
||||
+ rc = subprocess.call(cmd)
|
||||
+ assert rc == 0, f"dsconf command failed rc={rc}: {' '.join(cmd)}"
|
||||
+ time.sleep(1)
|
||||
+
|
||||
+
|
||||
+def test_global_history_only_enforced(topology_st, setup_entries):
|
||||
+ """Global-only history enforcement with count 2
|
||||
+
|
||||
+ :id: 3d8cf35b-4a33-4587-9814-ebe18b7a1f92
|
||||
+ :setup: Standalone instance, test OU and user, ACI for self password changes
|
||||
+ :steps:
|
||||
+ 1. Remove local policies
|
||||
+ 2. Set global policy: passwordHistory=on, passwordInHistory=2
|
||||
+ 3. Set password to Alpha1, then change to Alpha2 and Alpha3 as the user
|
||||
+ 4. Attempt to change to Alpha1 and Alpha2
|
||||
+ 5. Attempt to change to Alpha4
|
||||
+ :expectedresults:
|
||||
+ 1. Success
|
||||
+ 2. Success
|
||||
+ 3. Success
|
||||
+ 4. Changes to Welcome1 and Welcome2 are rejected with CONSTRAINT_VIOLATION
|
||||
+ 5. Change to Welcome4 is accepted
|
||||
+ """
|
||||
+ inst = topology_st.standalone
|
||||
+ inst.simple_bind_s(DN_DM, PASSWORD)
|
||||
+
|
||||
+ set_global_history(inst, enabled=True, count=2)
|
||||
+
|
||||
+ user = setup_entries
|
||||
+ user.reset_password('Alpha1')
|
||||
+ set_user_password(inst, user, 'Alpha2', bind_as_user_password='Alpha1')
|
||||
+ set_user_password(inst, user, 'Alpha3', bind_as_user_password='Alpha2')
|
||||
+
|
||||
+ # Within last 2
|
||||
+ set_user_password(inst, user, 'Alpha2', bind_as_user_password='Alpha3', expect_violation=True)
|
||||
+ set_user_password(inst, user, 'Alpha1', bind_as_user_password='Alpha3', expect_violation=True)
|
||||
+
|
||||
+ # New password should be allowed
|
||||
+ set_user_password(inst, user, 'Alpha4', bind_as_user_password='Alpha3', expect_violation=False)
|
||||
+
|
||||
+
|
||||
+def test_local_overrides_global_history(topology_st, setup_entries):
|
||||
+ """Local subtree policy (history=3) overrides global (history=1)
|
||||
+
|
||||
+ :id: 97c22f56-5ea6-40c1-8d8c-1cece3bf46fd
|
||||
+ :setup: Standalone instance, test OU and user
|
||||
+ :steps:
|
||||
+ 1. Set global policy passwordInHistory=1
|
||||
+ 2. Create local subtree policy on the OU with passwordInHistory=3
|
||||
+ 3. Set password to Bravo1, then change to Bravo2 and Bravo3 as the user
|
||||
+ 4. Attempt to change to Bravo1
|
||||
+ 5. Attempt to change to Bravo5
|
||||
+ :expectedresults:
|
||||
+ 1. Success
|
||||
+ 2. Success
|
||||
+ 3. Success
|
||||
+ 4. Change to Welcome1 is rejected (local policy wins)
|
||||
+ 5. Change to Welcome5 is accepted
|
||||
+ """
|
||||
+ inst = topology_st.standalone
|
||||
+ inst.simple_bind_s(DN_DM, PASSWORD)
|
||||
+
|
||||
+ set_global_history(inst, enabled=True, count=1, inherit_global='on')
|
||||
+
|
||||
+ ensure_local_subtree_policy(inst, count=3)
|
||||
+
|
||||
+ user = setup_entries
|
||||
+ user.reset_password('Bravo1')
|
||||
+ set_user_password(inst, user, 'Bravo2', bind_as_user_password='Bravo1')
|
||||
+ set_user_password(inst, user, 'Bravo3', bind_as_user_password='Bravo2')
|
||||
+
|
||||
+ # Third prior should be rejected under local policy count=3
|
||||
+ set_user_password(inst, user, 'Bravo1', bind_as_user_password='Bravo3', expect_violation=True)
|
||||
+
|
||||
+ # New password allowed
|
||||
+ set_user_password(inst, user, 'Bravo5', bind_as_user_password='Bravo3', expect_violation=False)
|
||||
+
|
||||
+
|
||||
+def test_change_local_history_via_cli_affects_enforcement(topology_st, setup_entries):
|
||||
+ """Changing local policy via CLI is enforced immediately
|
||||
+
|
||||
+ :id: 5a6d0d14-4009-4bad-86e1-cde5000c43dc
|
||||
+ :setup: Standalone instance, test OU and user, dsconf available
|
||||
+ :steps:
|
||||
+ 1. Ensure local subtree policy passwordInHistory=3
|
||||
+ 2. Set password to Charlie1, then change to Charlie2 and Charlie3 as the user
|
||||
+ 3. Attempt to change to Charlie1 (within last 3)
|
||||
+ 4. Run: dsconf <inst> localpwp set --pwdhistorycount=1 "ou=product testing,<suffix>"
|
||||
+ 5. Attempt to change to Charlie1 again
|
||||
+ :expectedresults:
|
||||
+ 1. Success
|
||||
+ 2. Success
|
||||
+ 3. Change to Welcome1 is rejected
|
||||
+ 4. CLI command succeeds
|
||||
+ 5. Change to Welcome1 now succeeds (only last 1 is disallowed)
|
||||
+ """
|
||||
+ inst = topology_st.standalone
|
||||
+ inst.simple_bind_s(DN_DM, PASSWORD)
|
||||
+
|
||||
+ ensure_local_subtree_policy(inst, count=3)
|
||||
+
|
||||
+ user = setup_entries
|
||||
+ user.reset_password('Charlie1')
|
||||
+ set_user_password(inst, user, 'Charlie2', bind_as_user_password='Charlie1', expect_violation=False)
|
||||
+ set_user_password(inst, user, 'Charlie3', bind_as_user_password='Charlie2', expect_violation=False)
|
||||
+
|
||||
+ # With count=3, Welcome1 is within history
|
||||
+ set_user_password(inst, user, 'Charlie1', bind_as_user_password='Charlie3', expect_violation=True)
|
||||
+
|
||||
+ # Reduce local count to 1 via CLI to exercise CLI mapping and updated code
|
||||
+ set_local_history_via_cli(inst, count=1)
|
||||
+
|
||||
+ # Now Welcome1 should be allowed
|
||||
+ set_user_password(inst, user, 'Charlie1', bind_as_user_password='Charlie3', expect_violation=False)
|
||||
+
|
||||
+
|
||||
+def test_history_local_only_enforced(topology_st, setup_entries):
|
||||
+ """Local-only history enforcement with count 3
|
||||
+
|
||||
+ :id: af6ff34d-ac94-4108-a7b6-2b589c960154
|
||||
+ :setup: Standalone instance, test OU and user
|
||||
+ :steps:
|
||||
+ 1. Disable global password history (passwordHistory=off, passwordInHistory=0, inherit off)
|
||||
+ 2. Ensure local subtree policy with passwordInHistory=3
|
||||
+ 3. Set password to Delta1, then change to Delta2 and Delta3 as the user
|
||||
+ 4. Attempt to change to Delta1
|
||||
+ 5. Attempt to change to Delta5
|
||||
+ 6. Change once more to Delta6, then change to Delta1
|
||||
+ :expectedresults:
|
||||
+ 1. Success
|
||||
+ 2. Success
|
||||
+ 3. Success
|
||||
+ 4. Change to Welcome1 is rejected (within last 3)
|
||||
+ 5. Change to Welcome5 is accepted
|
||||
+ 6. Welcome1 is now older than the last 3 and is accepted
|
||||
+ """
|
||||
+ inst = topology_st.standalone
|
||||
+ inst.simple_bind_s(DN_DM, PASSWORD)
|
||||
+
|
||||
+ set_global_history(inst, enabled=False, count=0, inherit_global='off')
|
||||
+
|
||||
+ ensure_local_subtree_policy(inst, count=3)
|
||||
+
|
||||
+ user = setup_entries
|
||||
+ user.reset_password('Delta1')
|
||||
+ set_user_password(inst, user, 'Delta2', bind_as_user_password='Delta1')
|
||||
+ set_user_password(inst, user, 'Delta3', bind_as_user_password='Delta2')
|
||||
+
|
||||
+ # Within last 2
|
||||
+ set_user_password(inst, user, 'Delta1', bind_as_user_password='Delta3', expect_violation=True)
|
||||
+
|
||||
+ # New password allowed
|
||||
+ set_user_password(inst, user, 'Delta5', bind_as_user_password='Delta3', expect_violation=False)
|
||||
+
|
||||
+ # Now Welcome1 is older than last 2 after one more change
|
||||
+ set_user_password(inst, user, 'Delta6', bind_as_user_password='Delta5', expect_violation=False)
|
||||
+ set_user_password(inst, user, 'Delta1', bind_as_user_password='Delta6', expect_violation=False)
|
||||
+
|
||||
+
|
||||
+def test_user_policy_detection_and_enforcement(topology_st, setup_entries):
|
||||
+ """User local policy is detected and enforced; removal falls back to global policy
|
||||
+
|
||||
+ :id: 2213126a-1f47-468c-8337-0d2ee5d2d585
|
||||
+ :setup: Standalone instance, test OU and user
|
||||
+ :steps:
|
||||
+ 1. Set global policy passwordInHistory=1
|
||||
+ 2. Create a user local password policy on the user with passwordInHistory=3
|
||||
+ 3. Verify is_user_policy(USER_DN) is True
|
||||
+ 4. Set password to Echo1, then change to Echo2 and Echo3 as the user
|
||||
+ 5. Attempt to change to Echo1 (within last 3)
|
||||
+ 6. Delete the user local policy
|
||||
+ 7. Verify is_user_policy(USER_DN) is False
|
||||
+ 8. Attempt to change to Echo1 again (now only last 1 disallowed by global)
|
||||
+ :expectedresults:
|
||||
+ 1. Success
|
||||
+ 2. Success
|
||||
+ 3. is_user_policy returns True
|
||||
+ 4. Success
|
||||
+ 5. Change to Welcome1 is rejected
|
||||
+ 6. Success
|
||||
+ 7. is_user_policy returns False
|
||||
+ 8. Change to Welcome1 succeeds (two back is allowed by global=1)
|
||||
+ """
|
||||
+ inst = topology_st.standalone
|
||||
+ inst.simple_bind_s(DN_DM, PASSWORD)
|
||||
+
|
||||
+ set_global_history(inst, enabled=True, count=1, inherit_global='on')
|
||||
+
|
||||
+ pwp = PwPolicyManager(inst)
|
||||
+ user = setup_entries
|
||||
+ pwp.create_user_policy(user.dn, {
|
||||
+ 'passwordChange': 'on',
|
||||
+ 'passwordHistory': 'on',
|
||||
+ 'passwordInHistory': '3',
|
||||
+ })
|
||||
+
|
||||
+ assert pwp.is_user_policy(user.dn) is True
|
||||
+
|
||||
+ user.reset_password('Echo1')
|
||||
+ set_user_password(inst, user, 'Echo2', bind_as_user_password='Echo1', expect_violation=False)
|
||||
+ set_user_password(inst, user, 'Echo3', bind_as_user_password='Echo2', expect_violation=False)
|
||||
+ set_user_password(inst, user, 'Echo1', bind_as_user_password='Echo3', expect_violation=True)
|
||||
+
|
||||
+ pwp.delete_local_policy(user.dn)
|
||||
+ assert pwp.is_user_policy(user.dn) is False
|
||||
+
|
||||
+ # With only global=1, Echo1 (two back) is allowed
|
||||
+ set_user_password(inst, user, 'Echo1', bind_as_user_password='Echo3', expect_violation=False)
|
||||
+
|
||||
+
|
||||
+if __name__ == '__main__':
|
||||
+ # Run isolated
|
||||
+ # -s for DEBUG mode
|
||||
+ CURRENT_FILE = os.path.realpath(__file__)
|
||||
+ pytest.main("-s %s" % CURRENT_FILE)
|
||||
diff --git a/src/lib389/lib389/cli_conf/pwpolicy.py b/src/lib389/lib389/cli_conf/pwpolicy.py
|
||||
index 2d4ba9b21..a3e59a90c 100644
|
||||
--- a/src/lib389/lib389/cli_conf/pwpolicy.py
|
||||
+++ b/src/lib389/lib389/cli_conf/pwpolicy.py
|
||||
@@ -1,5 +1,5 @@
|
||||
# --- BEGIN COPYRIGHT BLOCK ---
|
||||
-# Copyright (C) 2023 Red Hat, Inc.
|
||||
+# Copyright (C) 2025 Red Hat, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# License: GPL (version 3 or any later version).
|
||||
@@ -43,7 +43,7 @@ def _get_pw_policy(inst, targetdn, log, use_json=None):
|
||||
targetdn = 'cn=config'
|
||||
policydn = targetdn
|
||||
basedn = targetdn
|
||||
- attr_list.extend(['passwordisglobalpolicy', 'nsslapd-pwpolicy_local'])
|
||||
+ attr_list.extend(['passwordisglobalpolicy', 'nsslapd-pwpolicy-local'])
|
||||
all_attrs = inst.config.get_attrs_vals_utf8(attr_list)
|
||||
attrs = {k: v for k, v in all_attrs.items() if len(v) > 0}
|
||||
else:
|
||||
diff --git a/src/lib389/lib389/pwpolicy.py b/src/lib389/lib389/pwpolicy.py
|
||||
index 6a47a44fe..539c230a9 100644
|
||||
--- a/src/lib389/lib389/pwpolicy.py
|
||||
+++ b/src/lib389/lib389/pwpolicy.py
|
||||
@@ -1,5 +1,5 @@
|
||||
# --- BEGIN COPYRIGHT BLOCK ---
|
||||
-# Copyright (C) 2018 Red Hat, Inc.
|
||||
+# Copyright (C) 2025 Red Hat, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# License: GPL (version 3 or any later version).
|
||||
@@ -7,6 +7,7 @@
|
||||
# --- END COPYRIGHT BLOCK ---
|
||||
|
||||
import ldap
|
||||
+from ldap import filter as ldap_filter
|
||||
from lib389._mapped_object import DSLdapObject, DSLdapObjects
|
||||
from lib389.backend import Backends
|
||||
from lib389.config import Config
|
||||
@@ -74,19 +75,56 @@ class PwPolicyManager(object):
|
||||
}
|
||||
|
||||
def is_subtree_policy(self, dn):
|
||||
- """Check if the entry has a subtree password policy. If we can find a
|
||||
- template entry it is subtree policy
|
||||
+ """Check if a subtree password policy exists for a given entry DN.
|
||||
|
||||
- :param dn: Entry DN with PwPolicy set up
|
||||
+ A subtree policy is indicated by the presence of any CoS template
|
||||
+ (under `cn=nsPwPolicyContainer,<dn>`) that has a `pwdpolicysubentry`
|
||||
+ attribute pointing to an existing entry with objectClass `passwordpolicy`.
|
||||
+
|
||||
+ :param dn: Entry DN to check for subtree policy
|
||||
:type dn: str
|
||||
|
||||
- :returns: True if the entry has a subtree policy, False otherwise
|
||||
+ :returns: True if a subtree policy exists, False otherwise
|
||||
+ :rtype: bool
|
||||
"""
|
||||
- cos_templates = CosTemplates(self._instance, 'cn=nsPwPolicyContainer,{}'.format(dn))
|
||||
try:
|
||||
- cos_templates.get('cn=nsPwTemplateEntry,%s' % dn)
|
||||
- return True
|
||||
- except:
|
||||
+ container_basedn = 'cn=nsPwPolicyContainer,{}'.format(dn)
|
||||
+ templates = CosTemplates(self._instance, container_basedn).list()
|
||||
+ for tmpl in templates:
|
||||
+ pwp_dn = tmpl.get_attr_val_utf8('pwdpolicysubentry')
|
||||
+ if not pwp_dn:
|
||||
+ continue
|
||||
+ # Validate that the referenced entry exists and is a passwordpolicy
|
||||
+ pwp_entry = PwPolicyEntry(self._instance, pwp_dn)
|
||||
+ if pwp_entry.exists() and pwp_entry.present('objectClass', 'passwordpolicy'):
|
||||
+ return True
|
||||
+ except ldap.LDAPError:
|
||||
+ pass
|
||||
+ return False
|
||||
+
|
||||
+ def is_user_policy(self, dn):
|
||||
+ """Check if the entry has a user password policy.
|
||||
+
|
||||
+ A user policy is indicated by the target entry having a
|
||||
+ `pwdpolicysubentry` attribute that points to an existing
|
||||
+ entry with objectClass `passwordpolicy`.
|
||||
+
|
||||
+ :param dn: Entry DN to check
|
||||
+ :type dn: str
|
||||
+
|
||||
+ :returns: True if the entry has a user policy, False otherwise
|
||||
+ :rtype: bool
|
||||
+ """
|
||||
+ try:
|
||||
+ entry = Account(self._instance, dn)
|
||||
+ if not entry.exists():
|
||||
+ return False
|
||||
+ pwp_dn = entry.get_attr_val_utf8('pwdpolicysubentry')
|
||||
+ if not pwp_dn:
|
||||
+ return False
|
||||
+ pwp_entry = PwPolicyEntry(self._instance, pwp_dn)
|
||||
+ return pwp_entry.exists() and pwp_entry.present('objectClass', 'passwordpolicy')
|
||||
+ except ldap.LDAPError:
|
||||
return False
|
||||
|
||||
def create_user_policy(self, dn, properties):
|
||||
@@ -114,10 +152,10 @@ class PwPolicyManager(object):
|
||||
pwp_containers = nsContainers(self._instance, basedn=parentdn)
|
||||
pwp_container = pwp_containers.ensure_state(properties={'cn': 'nsPwPolicyContainer'})
|
||||
|
||||
- # Create policy entry
|
||||
+ # Create or update the policy entry
|
||||
properties['cn'] = 'cn=nsPwPolicyEntry_user,%s' % dn
|
||||
pwp_entries = PwPolicyEntries(self._instance, pwp_container.dn)
|
||||
- pwp_entry = pwp_entries.create(properties=properties)
|
||||
+ pwp_entry = pwp_entries.ensure_state(properties=properties)
|
||||
try:
|
||||
# Add policy to the entry
|
||||
user_entry.replace('pwdpolicysubentry', pwp_entry.dn)
|
||||
@@ -152,32 +190,27 @@ class PwPolicyManager(object):
|
||||
pwp_containers = nsContainers(self._instance, basedn=dn)
|
||||
pwp_container = pwp_containers.ensure_state(properties={'cn': 'nsPwPolicyContainer'})
|
||||
|
||||
- # Create policy entry
|
||||
- pwp_entry = None
|
||||
+ # Create or update the policy entry
|
||||
properties['cn'] = 'cn=nsPwPolicyEntry_subtree,%s' % dn
|
||||
pwp_entries = PwPolicyEntries(self._instance, pwp_container.dn)
|
||||
- pwp_entry = pwp_entries.create(properties=properties)
|
||||
- try:
|
||||
- # The CoS template entry (nsPwTemplateEntry) that has the pwdpolicysubentry
|
||||
- # value pointing to the above (nsPwPolicyEntry) entry
|
||||
- cos_template = None
|
||||
- cos_templates = CosTemplates(self._instance, pwp_container.dn)
|
||||
- cos_template = cos_templates.create(properties={'cosPriority': '1',
|
||||
- 'pwdpolicysubentry': pwp_entry.dn,
|
||||
- 'cn': 'cn=nsPwTemplateEntry,%s' % dn})
|
||||
-
|
||||
- # The CoS specification entry at the subtree level
|
||||
- cos_pointer_defs = CosPointerDefinitions(self._instance, dn)
|
||||
- cos_pointer_defs.create(properties={'cosAttribute': 'pwdpolicysubentry default operational-default',
|
||||
- 'cosTemplateDn': cos_template.dn,
|
||||
- 'cn': 'nsPwPolicy_CoS'})
|
||||
- except ldap.LDAPError as e:
|
||||
- # Something went wrong, remove what we have done
|
||||
- if pwp_entry is not None:
|
||||
- pwp_entry.delete()
|
||||
- if cos_template is not None:
|
||||
- cos_template.delete()
|
||||
- raise e
|
||||
+ pwp_entry = pwp_entries.ensure_state(properties=properties)
|
||||
+
|
||||
+ # Ensure the CoS template entry (nsPwTemplateEntry) that points to the
|
||||
+ # password policy entry
|
||||
+ cos_templates = CosTemplates(self._instance, pwp_container.dn)
|
||||
+ cos_template = cos_templates.ensure_state(properties={
|
||||
+ 'cosPriority': '1',
|
||||
+ 'pwdpolicysubentry': pwp_entry.dn,
|
||||
+ 'cn': 'cn=nsPwTemplateEntry,%s' % dn
|
||||
+ })
|
||||
+
|
||||
+ # Ensure the CoS specification entry at the subtree level
|
||||
+ cos_pointer_defs = CosPointerDefinitions(self._instance, dn)
|
||||
+ cos_pointer_defs.ensure_state(properties={
|
||||
+ 'cosAttribute': 'pwdpolicysubentry default operational-default',
|
||||
+ 'cosTemplateDn': cos_template.dn,
|
||||
+ 'cn': 'nsPwPolicy_CoS'
|
||||
+ })
|
||||
|
||||
# make sure that local policies are enabled
|
||||
self.set_global_policy({'nsslapd-pwpolicy-local': 'on'})
|
||||
@@ -244,10 +277,12 @@ class PwPolicyManager(object):
|
||||
if self.is_subtree_policy(entry.dn):
|
||||
parentdn = dn
|
||||
subtree = True
|
||||
- else:
|
||||
+ elif self.is_user_policy(entry.dn):
|
||||
dn_comps = ldap.dn.explode_dn(dn)
|
||||
dn_comps.pop(0)
|
||||
parentdn = ",".join(dn_comps)
|
||||
+ else:
|
||||
+ raise ValueError('The target entry dn does not have a password policy')
|
||||
|
||||
# Starting deleting the policy, ignore the parts that might already have been removed
|
||||
pwp_container = nsContainer(self._instance, 'cn=nsPwPolicyContainer,%s' % parentdn)
|
||||
--
|
||||
2.49.0
|
||||
|
||||
1460
0039-Issue-6919-numSubordinates-tombstoneNumSubordinates-.patch
Normal file
1460
0039-Issue-6919-numSubordinates-tombstoneNumSubordinates-.patch
Normal file
File diff suppressed because it is too large
Load Diff
574
0040-Issue-6910-Fix-latest-coverity-issues.patch
Normal file
574
0040-Issue-6910-Fix-latest-coverity-issues.patch
Normal file
@ -0,0 +1,574 @@
|
||||
From 5d2dc7f78f0a834e46d5665f0c12024da5ddda9e Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
Date: Mon, 28 Jul 2025 17:12:33 -0400
|
||||
Subject: [PATCH] Issue 6910 - Fix latest coverity issues
|
||||
|
||||
Description:
|
||||
|
||||
Fix various coverity/ASAN warnings:
|
||||
|
||||
- CID 1618837: Out-of-bounds read (OVERRUN) - bdb_bdbreader_glue.c
|
||||
- CID 1618831: Resource leak (RESOURCE_LEAK) - bdb_layer.c
|
||||
- CID 1612606: Resource leak (RESOURCE_LEAK) - log.c
|
||||
- CID 1611461: Uninitialized pointer read (UNINIT) - repl5_agmt.c
|
||||
- CID 1568589: Dereference before null check (REVERSE_INULL) - repl5_agmt.c
|
||||
- CID 1590353: Logically dead code (DEADCODE) - repl5_agmt.c
|
||||
- CID 1611460: Logically dead code (DEADCODE) - control.c
|
||||
- CID 1610568: Dereference after null check (FORWARD_NULL) - modify.c
|
||||
- CID 1591259: Out-of-bounds read (OVERRUN) - memberof.c
|
||||
- CID 1550231: Unsigned compared against 0 (NO_EFFECT) - memberof_config.c
|
||||
- CID 1548904: Overflowed constant (INTEGER_OVERFLOW) - ch_malloc.c
|
||||
- CID 1548902: Overflowed constant (INTEGER_OVERFLOW) - dse.lc
|
||||
- CID 1548900: Overflowed return value (INTEGER_OVERFLOW) - acct_util.c
|
||||
- CID 1548898: Overflowed constant (INTEGER_OVERFLOW) - parents.c
|
||||
- CID 1546849: Resource leak (RESOURCE_LEAK) - referint.c
|
||||
- ASAN - Use after free - automember.c
|
||||
|
||||
Relates: http://github.com/389ds/389-ds-base/issues/6910
|
||||
|
||||
Reviewed by: progier & spichugi(Thanks!)
|
||||
---
|
||||
ldap/servers/plugins/acctpolicy/acct_util.c | 6 ++-
|
||||
ldap/servers/plugins/automember/automember.c | 9 ++--
|
||||
ldap/servers/plugins/memberof/memberof.c | 15 +++++--
|
||||
.../plugins/memberof/memberof_config.c | 11 +++--
|
||||
ldap/servers/plugins/referint/referint.c | 4 +-
|
||||
ldap/servers/plugins/replication/repl5_agmt.c | 41 ++++++++-----------
|
||||
.../slapd/back-ldbm/db-bdb/bdb_import.c | 5 ++-
|
||||
.../back-ldbm/db-bdb/bdb_instance_config.c | 3 +-
|
||||
.../slapd/back-ldbm/db-bdb/bdb_layer.c | 13 ++++--
|
||||
ldap/servers/slapd/back-ldbm/parents.c | 4 +-
|
||||
ldap/servers/slapd/ch_malloc.c | 4 +-
|
||||
ldap/servers/slapd/control.c | 5 +--
|
||||
ldap/servers/slapd/dse.c | 4 +-
|
||||
ldap/servers/slapd/log.c | 5 ++-
|
||||
ldap/servers/slapd/modify.c | 6 +--
|
||||
ldap/servers/slapd/passwd_extop.c | 2 +-
|
||||
ldap/servers/slapd/unbind.c | 12 ++++--
|
||||
17 files changed, 88 insertions(+), 61 deletions(-)
|
||||
|
||||
diff --git a/ldap/servers/plugins/acctpolicy/acct_util.c b/ldap/servers/plugins/acctpolicy/acct_util.c
|
||||
index b27eeaff1..7735d10e6 100644
|
||||
--- a/ldap/servers/plugins/acctpolicy/acct_util.c
|
||||
+++ b/ldap/servers/plugins/acctpolicy/acct_util.c
|
||||
@@ -17,7 +17,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
Contributors:
|
||||
Hewlett-Packard Development Company, L.P.
|
||||
|
||||
-Copyright (C) 2021 Red Hat, Inc.
|
||||
+Copyright (C) 2025 Red Hat, Inc.
|
||||
******************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -248,6 +248,10 @@ gentimeToEpochtime(char *gentimestr)
|
||||
|
||||
/* Turn tm object into local epoch time */
|
||||
epochtime = mktime(&t);
|
||||
+ if (epochtime == (time_t) -1) {
|
||||
+ /* mktime failed */
|
||||
+ return 0;
|
||||
+ }
|
||||
|
||||
/* Turn local epoch time into GMT epoch time */
|
||||
epochtime -= zone_offset;
|
||||
diff --git a/ldap/servers/plugins/automember/automember.c b/ldap/servers/plugins/automember/automember.c
|
||||
index f900db7f2..9eade495e 100644
|
||||
--- a/ldap/servers/plugins/automember/automember.c
|
||||
+++ b/ldap/servers/plugins/automember/automember.c
|
||||
@@ -1,5 +1,5 @@
|
||||
/** BEGIN COPYRIGHT BLOCK
|
||||
- * Copyright (C) 2022 Red Hat, Inc.
|
||||
+ * Copyright (C) 2025 Red Hat, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* License: GPL (version 3 or any later version).
|
||||
@@ -1756,9 +1756,10 @@ automember_update_member_value(Slapi_Entry *member_e, const char *group_dn, char
|
||||
|
||||
mod_pb = slapi_pblock_new();
|
||||
/* Do a single mod with error overrides for DEL/ADD */
|
||||
- result = slapi_single_modify_internal_override(mod_pb, slapi_sdn_new_dn_byval(group_dn), mods,
|
||||
- automember_get_plugin_id(), 0);
|
||||
-
|
||||
+ Slapi_DN *sdn = slapi_sdn_new_normdn_byref(group_dn);
|
||||
+ result = slapi_single_modify_internal_override(mod_pb, sdn, mods,
|
||||
+ automember_get_plugin_id(), 0);
|
||||
+ slapi_sdn_free(&sdn);
|
||||
if(add){
|
||||
if (result != LDAP_SUCCESS) {
|
||||
slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
diff --git a/ldap/servers/plugins/memberof/memberof.c b/ldap/servers/plugins/memberof/memberof.c
|
||||
index 073d8d938..cfda977f0 100644
|
||||
--- a/ldap/servers/plugins/memberof/memberof.c
|
||||
+++ b/ldap/servers/plugins/memberof/memberof.c
|
||||
@@ -1,5 +1,5 @@
|
||||
/** BEGIN COPYRIGHT BLOCK
|
||||
- * Copyright (C) 2021 Red Hat, Inc.
|
||||
+ * Copyright (C) 2025 Red Hat, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* License: GPL (version 3 or any later version).
|
||||
@@ -1655,6 +1655,7 @@ memberof_call_foreach_dn(Slapi_PBlock *pb __attribute__((unused)), Slapi_DN *sdn
|
||||
/* We already did the search for this backend, don't
|
||||
* do it again when we fall through */
|
||||
do_suffix_search = PR_FALSE;
|
||||
+ slapi_pblock_init(search_pb);
|
||||
}
|
||||
}
|
||||
} else if (!all_backends) {
|
||||
@@ -3763,6 +3764,10 @@ memberof_replace_list(Slapi_PBlock *pb, MemberOfConfig *config, Slapi_DN *group_
|
||||
|
||||
pre_index++;
|
||||
} else {
|
||||
+ if (pre_index >= pre_total || post_index >= post_total) {
|
||||
+ /* Don't overrun pre_array/post_array */
|
||||
+ break;
|
||||
+ }
|
||||
/* decide what to do */
|
||||
int cmp = memberof_compare(
|
||||
config,
|
||||
@@ -4453,10 +4458,12 @@ memberof_add_memberof_attr(LDAPMod **mods, const char *dn, char *add_oc)
|
||||
|
||||
while (1) {
|
||||
slapi_pblock_init(mod_pb);
|
||||
-
|
||||
+ Slapi_DN *sdn = slapi_sdn_new_normdn_byref(dn);
|
||||
/* Internal mod with error overrides for DEL/ADD */
|
||||
- rc = slapi_single_modify_internal_override(mod_pb, slapi_sdn_new_normdn_byref(dn), single_mod,
|
||||
- memberof_get_plugin_id(), SLAPI_OP_FLAG_BYPASS_REFERRALS);
|
||||
+ rc = slapi_single_modify_internal_override(mod_pb, sdn, single_mod,
|
||||
+ memberof_get_plugin_id(),
|
||||
+ SLAPI_OP_FLAG_BYPASS_REFERRALS);
|
||||
+ slapi_sdn_free(&sdn);
|
||||
if (rc == LDAP_OBJECT_CLASS_VIOLATION) {
|
||||
if (!add_oc || added_oc) {
|
||||
/*
|
||||
diff --git a/ldap/servers/plugins/memberof/memberof_config.c b/ldap/servers/plugins/memberof/memberof_config.c
|
||||
index 1e83ba6e0..e4da351d9 100644
|
||||
--- a/ldap/servers/plugins/memberof/memberof_config.c
|
||||
+++ b/ldap/servers/plugins/memberof/memberof_config.c
|
||||
@@ -1,5 +1,5 @@
|
||||
/** BEGIN COPYRIGHT BLOCK
|
||||
- * Copyright (C) 2021 Red Hat, Inc.
|
||||
+ * Copyright (C) 2025 Red Hat, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* License: GPL (version 3 or any later version).
|
||||
@@ -570,21 +570,24 @@ memberof_apply_config(Slapi_PBlock *pb __attribute__((unused)),
|
||||
if (num_groupattrs > 1) {
|
||||
size_t bytes_out = 0;
|
||||
size_t filter_str_len = groupattr_name_len + (num_groupattrs * 4) + 4;
|
||||
+ int32_t rc = 0;
|
||||
|
||||
/* Allocate enough space for the filter */
|
||||
filter_str = slapi_ch_malloc(filter_str_len);
|
||||
|
||||
/* Add beginning of filter. */
|
||||
- bytes_out = snprintf(filter_str, filter_str_len - bytes_out, "(|");
|
||||
- if (bytes_out<0) {
|
||||
+ rc = snprintf(filter_str, filter_str_len - bytes_out, "(|");
|
||||
+ if (rc < 0) {
|
||||
slapi_log_err(SLAPI_LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM, "snprintf unexpectly failed in memberof_apply_config.\n");
|
||||
*returncode = LDAP_UNWILLING_TO_PERFORM;
|
||||
goto done;
|
||||
+ } else {
|
||||
+ bytes_out = rc;
|
||||
}
|
||||
|
||||
/* Add filter section for each groupattr. */
|
||||
for (size_t i=0; theConfig.groupattrs && theConfig.groupattrs[i]; i++) {
|
||||
- size_t bytes_read = snprintf(filter_str + bytes_out, filter_str_len - bytes_out, "(%s=*)", theConfig.groupattrs[i]);
|
||||
+ int32_t bytes_read = snprintf(filter_str + bytes_out, filter_str_len - bytes_out, "(%s=*)", theConfig.groupattrs[i]);
|
||||
if (bytes_read<0) {
|
||||
slapi_log_err(SLAPI_LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM, "snprintf unexpectly failed in memberof_apply_config.\n");
|
||||
*returncode = LDAP_UNWILLING_TO_PERFORM;
|
||||
diff --git a/ldap/servers/plugins/referint/referint.c b/ldap/servers/plugins/referint/referint.c
|
||||
index 5d7f9e5dd..5746b913f 100644
|
||||
--- a/ldap/servers/plugins/referint/referint.c
|
||||
+++ b/ldap/servers/plugins/referint/referint.c
|
||||
@@ -1,6 +1,6 @@
|
||||
/** BEGIN COPYRIGHT BLOCK
|
||||
* Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
|
||||
- * Copyright (C) 2021 Red Hat, Inc.
|
||||
+ * Copyright (C) 2025 Red Hat, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* License: GPL (version 3 or any later version).
|
||||
@@ -1499,6 +1499,8 @@ referint_thread_func(void *arg __attribute__((unused)))
|
||||
slapi_sdn_free(&sdn);
|
||||
continue;
|
||||
}
|
||||
+
|
||||
+ slapi_sdn_free(&tmpsuperior);
|
||||
if (!strcasecmp(ptoken, "NULL")) {
|
||||
tmpsuperior = NULL;
|
||||
} else {
|
||||
diff --git a/ldap/servers/plugins/replication/repl5_agmt.c b/ldap/servers/plugins/replication/repl5_agmt.c
|
||||
index 0a81167b7..eed97578e 100644
|
||||
--- a/ldap/servers/plugins/replication/repl5_agmt.c
|
||||
+++ b/ldap/servers/plugins/replication/repl5_agmt.c
|
||||
@@ -1,6 +1,6 @@
|
||||
/** BEGIN COPYRIGHT BLOCK
|
||||
* Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
|
||||
- * Copyright (C) 2021 Red Hat, Inc.
|
||||
+ * Copyright (C) 2025 Red Hat, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* License: GPL (version 3 or any later version).
|
||||
@@ -202,7 +202,7 @@ agmt_init_session_id(Repl_Agmt *ra)
|
||||
char *host = NULL; /* e.g. localhost.domain */
|
||||
char port[10]; /* e.g. 389 */
|
||||
char sport[10]; /* e.g. 636 */
|
||||
- char *hash_in;
|
||||
+ char *hash_in = NULL;
|
||||
int32_t max_str_sid = SESSION_ID_STR_SZ - 4;
|
||||
|
||||
if (ra == NULL) {
|
||||
@@ -2718,31 +2718,26 @@ agmt_update_init_status(Repl_Agmt *ra)
|
||||
mod_idx++;
|
||||
}
|
||||
|
||||
- if (nb_mods) {
|
||||
- /* it is ok to release the lock here because we are done with the agreement data.
|
||||
- we have to do it before issuing the modify operation because it causes
|
||||
- agmtlist_notify_all to be called which uses the same lock - hence the deadlock */
|
||||
- PR_Unlock(ra->lock);
|
||||
-
|
||||
- pb = slapi_pblock_new();
|
||||
- mods[nb_mods] = NULL;
|
||||
+ /* it is ok to release the lock here because we are done with the agreement data.
|
||||
+ we have to do it before issuing the modify operation because it causes
|
||||
+ agmtlist_notify_all to be called which uses the same lock - hence the deadlock */
|
||||
+ PR_Unlock(ra->lock);
|
||||
|
||||
- slapi_modify_internal_set_pb_ext(pb, ra->dn, mods, NULL, NULL,
|
||||
- repl_get_plugin_identity(PLUGIN_MULTISUPPLIER_REPLICATION), 0);
|
||||
- slapi_modify_internal_pb(pb);
|
||||
+ pb = slapi_pblock_new();
|
||||
+ mods[nb_mods] = NULL;
|
||||
|
||||
- slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
|
||||
- if (rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_ATTRIBUTE) {
|
||||
- slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "agmt_update_consumer_ruv - "
|
||||
- "%s: agmt_update_consumer_ruv: "
|
||||
- "failed to update consumer's RUV; LDAP error - %d\n",
|
||||
- ra->long_name, rc);
|
||||
- }
|
||||
+ slapi_modify_internal_set_pb_ext(pb, ra->dn, mods, NULL, NULL,
|
||||
+ repl_get_plugin_identity(PLUGIN_MULTISUPPLIER_REPLICATION), 0);
|
||||
+ slapi_modify_internal_pb(pb);
|
||||
|
||||
- slapi_pblock_destroy(pb);
|
||||
- } else {
|
||||
- PR_Unlock(ra->lock);
|
||||
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
|
||||
+ if (rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_ATTRIBUTE) {
|
||||
+ slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "agmt_update_consumer_ruv - "
|
||||
+ "%s: agmt_update_consumer_ruv: failed to update consumer's RUV; LDAP error - %d\n",
|
||||
+ ra->long_name, rc);
|
||||
}
|
||||
+
|
||||
+ slapi_pblock_destroy(pb);
|
||||
slapi_ch_free((void **)&mods);
|
||||
slapi_mod_done(&smod_start_time);
|
||||
slapi_mod_done(&smod_end_time);
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/db-bdb/bdb_import.c b/ldap/servers/slapd/back-ldbm/db-bdb/bdb_import.c
|
||||
index 46c80ec3d..0127bf2f9 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/db-bdb/bdb_import.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/db-bdb/bdb_import.c
|
||||
@@ -1,5 +1,5 @@
|
||||
/** BEGIN COPYRIGHT BLOCK
|
||||
- * Copyright (C) 2020 Red Hat, Inc.
|
||||
+ * Copyright (C) 2025 Red Hat, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* License: GPL (version 3 or any later version).
|
||||
@@ -947,6 +947,7 @@ bdb_ancestorid_new_idl_create_index(backend *be, ImportJob *job)
|
||||
EQ_PREFIX, (u_long)id);
|
||||
key.size++; /* include the null terminator */
|
||||
ret = NEW_IDL_NO_ALLID;
|
||||
+ idl_free(&children);
|
||||
children = idl_fetch(be, db_pid, &key, txn, ai_pid, &ret);
|
||||
if (ret != 0) {
|
||||
ldbm_nasty("bdb_ancestorid_new_idl_create_index", sourcefile, 13070, ret);
|
||||
@@ -957,6 +958,7 @@ bdb_ancestorid_new_idl_create_index(backend *be, ImportJob *job)
|
||||
if (job->flags & FLAG_ABORT) {
|
||||
import_log_notice(job, SLAPI_LOG_ERR, "bdb_ancestorid_new_idl_create_index",
|
||||
"ancestorid creation aborted.");
|
||||
+ idl_free(&children);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
@@ -1290,6 +1292,7 @@ bdb_update_subordinatecounts(backend *be, ImportJob *job, DB_TXN *txn)
|
||||
}
|
||||
bdb_close_subcount_cursor(&c_entryrdn);
|
||||
bdb_close_subcount_cursor(&c_objectclass);
|
||||
+
|
||||
return ret;
|
||||
}
|
||||
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/db-bdb/bdb_instance_config.c b/ldap/servers/slapd/back-ldbm/db-bdb/bdb_instance_config.c
|
||||
index bb515a23f..44a624fde 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/db-bdb/bdb_instance_config.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/db-bdb/bdb_instance_config.c
|
||||
@@ -1,5 +1,5 @@
|
||||
/** BEGIN COPYRIGHT BLOCK
|
||||
- * Copyright (C) 2020 Red Hat, Inc.
|
||||
+ * Copyright (C) 2025 Red Hat, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* License: GPL (version 3 or any later version).
|
||||
@@ -261,6 +261,7 @@ bdb_instance_cleanup(struct ldbm_instance *inst)
|
||||
if (inst_dirp && *inst_dir) {
|
||||
return_value = env->remove(env, inst_dirp, 0);
|
||||
} else {
|
||||
+ slapi_ch_free((void **)&env);
|
||||
return_value = -1;
|
||||
}
|
||||
if (return_value == EBUSY) {
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/db-bdb/bdb_layer.c b/ldap/servers/slapd/back-ldbm/db-bdb/bdb_layer.c
|
||||
index 53f1cde69..b1e44a919 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/db-bdb/bdb_layer.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/db-bdb/bdb_layer.c
|
||||
@@ -1,5 +1,5 @@
|
||||
/** BEGIN COPYRIGHT BLOCK
|
||||
- * Copyright (C) 2023 Red Hat, Inc.
|
||||
+ * Copyright (C) 2025 Red Hat, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* License: GPL (version 3 or any later version).
|
||||
@@ -2027,9 +2027,13 @@ bdb_pre_close(struct ldbminfo *li)
|
||||
conf = (bdb_config *)li->li_dblayer_config;
|
||||
bdb_db_env *pEnv = (bdb_db_env *)priv->dblayer_env;
|
||||
|
||||
+ if (pEnv == NULL) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
pthread_mutex_lock(&pEnv->bdb_thread_count_lock);
|
||||
|
||||
- if (conf->bdb_stop_threads || !pEnv) {
|
||||
+ if (conf->bdb_stop_threads) {
|
||||
/* already stopped. do nothing... */
|
||||
goto timeout_escape;
|
||||
}
|
||||
@@ -2203,6 +2207,7 @@ bdb_remove_env(struct ldbminfo *li)
|
||||
}
|
||||
if (NULL == li) {
|
||||
slapi_log_err(SLAPI_LOG_ERR, "bdb_remove_env", "No ldbm info is given\n");
|
||||
+ slapi_ch_free((void **)&env);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -2212,10 +2217,11 @@ bdb_remove_env(struct ldbminfo *li)
|
||||
if (rc) {
|
||||
slapi_log_err(SLAPI_LOG_ERR,
|
||||
"bdb_remove_env", "Failed to remove DB environment files. "
|
||||
- "Please remove %s/__db.00# (# is 1 through 6)\n",
|
||||
+ "Please remove %s/__db.00# (# is 1 through 6)\n",
|
||||
home_dir);
|
||||
}
|
||||
}
|
||||
+ slapi_ch_free((void **)&env);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -6341,6 +6347,7 @@ bdb_back_ctrl(Slapi_Backend *be, int cmd, void *info)
|
||||
db->close(db, 0);
|
||||
rc = bdb_db_remove_ex((bdb_db_env *)priv->dblayer_env, path, NULL, PR_TRUE);
|
||||
inst->inst_changelog = NULL;
|
||||
+ slapi_ch_free_string(&path);
|
||||
slapi_ch_free_string(&instancedir);
|
||||
}
|
||||
}
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/parents.c b/ldap/servers/slapd/back-ldbm/parents.c
|
||||
index 31107591e..52c665ca4 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/parents.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/parents.c
|
||||
@@ -1,6 +1,6 @@
|
||||
/** BEGIN COPYRIGHT BLOCK
|
||||
* Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
|
||||
- * Copyright (C) 2005 Red Hat, Inc.
|
||||
+ * Copyright (C) 2025 Red Hat, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* License: GPL (version 3 or any later version).
|
||||
@@ -123,7 +123,7 @@ parent_update_on_childchange(modify_context *mc, int op, size_t *new_sub_count)
|
||||
/* Now compute the new value */
|
||||
if ((PARENTUPDATE_ADD == op) || (PARENTUPDATE_RESURECT == op)) {
|
||||
current_sub_count++;
|
||||
- } else {
|
||||
+ } else if (current_sub_count > 0) {
|
||||
current_sub_count--;
|
||||
}
|
||||
|
||||
diff --git a/ldap/servers/slapd/ch_malloc.c b/ldap/servers/slapd/ch_malloc.c
|
||||
index cbab1d170..27ed546a5 100644
|
||||
--- a/ldap/servers/slapd/ch_malloc.c
|
||||
+++ b/ldap/servers/slapd/ch_malloc.c
|
||||
@@ -1,6 +1,6 @@
|
||||
/** BEGIN COPYRIGHT BLOCK
|
||||
* Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
|
||||
- * Copyright (C) 2005 Red Hat, Inc.
|
||||
+ * Copyright (C) 2025 Red Hat, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* License: GPL (version 3 or any later version).
|
||||
@@ -254,7 +254,7 @@ slapi_ch_bvecdup(struct berval **v)
|
||||
++i;
|
||||
newberval = (struct berval **)slapi_ch_malloc((i + 1) * sizeof(struct berval *));
|
||||
newberval[i] = NULL;
|
||||
- while (i-- > 0) {
|
||||
+ while (i > 0 && i-- > 0) {
|
||||
newberval[i] = slapi_ch_bvdup(v[i]);
|
||||
}
|
||||
}
|
||||
diff --git a/ldap/servers/slapd/control.c b/ldap/servers/slapd/control.c
|
||||
index 7aeeba885..d661dc6e1 100644
|
||||
--- a/ldap/servers/slapd/control.c
|
||||
+++ b/ldap/servers/slapd/control.c
|
||||
@@ -174,7 +174,6 @@ create_sessiontracking_ctrl(const char *session_tracking_id, LDAPControl **sessi
|
||||
char *undefined_sid = "undefined sid";
|
||||
const char *sid;
|
||||
int rc = 0;
|
||||
- int tag;
|
||||
LDAPControl *ctrl = NULL;
|
||||
|
||||
if (session_tracking_id) {
|
||||
@@ -183,9 +182,7 @@ create_sessiontracking_ctrl(const char *session_tracking_id, LDAPControl **sessi
|
||||
sid = undefined_sid;
|
||||
}
|
||||
ctrlber = ber_alloc();
|
||||
- tag = ber_printf( ctrlber, "{nnno}", sid, strlen(sid));
|
||||
- if (rc == LBER_ERROR) {
|
||||
- tag = -1;
|
||||
+ if ((rc = ber_printf( ctrlber, "{nnno}", sid, strlen(sid)) == LBER_ERROR)) {
|
||||
goto done;
|
||||
}
|
||||
slapi_build_control(LDAP_CONTROL_X_SESSION_TRACKING, ctrlber, 0, &ctrl);
|
||||
diff --git a/ldap/servers/slapd/dse.c b/ldap/servers/slapd/dse.c
|
||||
index b788054db..bec3e32f4 100644
|
||||
--- a/ldap/servers/slapd/dse.c
|
||||
+++ b/ldap/servers/slapd/dse.c
|
||||
@@ -1,6 +1,6 @@
|
||||
/** BEGIN COPYRIGHT BLOCK
|
||||
* Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
|
||||
- * Copyright (C) 2005 Red Hat, Inc.
|
||||
+ * Copyright (C) 2025 Red Hat, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* License: GPL (version 3 or any later version).
|
||||
@@ -637,7 +637,7 @@ dse_updateNumSubordinates(Slapi_Entry *entry, int op)
|
||||
/* Now compute the new value */
|
||||
if (SLAPI_OPERATION_ADD == op) {
|
||||
current_sub_count++;
|
||||
- } else {
|
||||
+ } else if (current_sub_count > 0) {
|
||||
current_sub_count--;
|
||||
}
|
||||
{
|
||||
diff --git a/ldap/servers/slapd/log.c b/ldap/servers/slapd/log.c
|
||||
index 91ba23047..a9a5f3b3f 100644
|
||||
--- a/ldap/servers/slapd/log.c
|
||||
+++ b/ldap/servers/slapd/log.c
|
||||
@@ -1,6 +1,6 @@
|
||||
/** BEGIN COPYRIGHT BLOCK
|
||||
* Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
|
||||
- * Copyright (C) 2005-2024 Red Hat, Inc.
|
||||
+ * Copyright (C) 2025 Red Hat, Inc.
|
||||
* Copyright (C) 2010 Hewlett-Packard Development Company, L.P.
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -201,6 +201,7 @@ compress_log_file(char *log_name, int32_t mode)
|
||||
|
||||
if ((source = fopen(log_name, "r")) == NULL) {
|
||||
/* Failed to open log file */
|
||||
+ /* coverity[leaked_storage] gzclose does close FD */
|
||||
gzclose(outfile);
|
||||
return -1;
|
||||
}
|
||||
@@ -211,11 +212,13 @@ compress_log_file(char *log_name, int32_t mode)
|
||||
if (bytes_written == 0)
|
||||
{
|
||||
fclose(source);
|
||||
+ /* coverity[leaked_storage] gzclose does close FD */
|
||||
gzclose(outfile);
|
||||
return -1;
|
||||
}
|
||||
bytes_read = fread(buf, 1, LOG_CHUNK, source);
|
||||
}
|
||||
+ /* coverity[leaked_storage] gzclose does close FD */
|
||||
gzclose(outfile);
|
||||
fclose(source);
|
||||
PR_Delete(log_name); /* remove the old uncompressed log */
|
||||
diff --git a/ldap/servers/slapd/modify.c b/ldap/servers/slapd/modify.c
|
||||
index 0a351d46a..9e5bce80b 100644
|
||||
--- a/ldap/servers/slapd/modify.c
|
||||
+++ b/ldap/servers/slapd/modify.c
|
||||
@@ -1,6 +1,6 @@
|
||||
/** BEGIN COPYRIGHT BLOCK
|
||||
* Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
|
||||
- * Copyright (C) 2009 Red Hat, Inc.
|
||||
+ * Copyright (C) 2025 Red Hat, Inc.
|
||||
* Copyright (C) 2009, 2010 Hewlett-Packard Development Company, L.P.
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -498,7 +498,7 @@ slapi_modify_internal_set_pb_ext(Slapi_PBlock *pb, const Slapi_DN *sdn, LDAPMod
|
||||
*
|
||||
* Any other errors encountered during the operation will be returned as-is.
|
||||
*/
|
||||
-int
|
||||
+int
|
||||
slapi_single_modify_internal_override(Slapi_PBlock *pb, const Slapi_DN *sdn, LDAPMod **mod, Slapi_ComponentId *plugin_id, int op_flags)
|
||||
{
|
||||
int rc = 0;
|
||||
@@ -512,7 +512,7 @@ slapi_single_modify_internal_override(Slapi_PBlock *pb, const Slapi_DN *sdn, LDA
|
||||
!pb ? "pb " : "",
|
||||
!sdn ? "sdn " : "",
|
||||
!mod ? "mod " : "",
|
||||
- !mod[0] ? "mod[0] " : "");
|
||||
+ !mod || !mod[0] ? "mod[0] " : "");
|
||||
|
||||
return LDAP_PARAM_ERROR;
|
||||
}
|
||||
diff --git a/ldap/servers/slapd/passwd_extop.c b/ldap/servers/slapd/passwd_extop.c
|
||||
index 69bb3494c..5f05cf74e 100644
|
||||
--- a/ldap/servers/slapd/passwd_extop.c
|
||||
+++ b/ldap/servers/slapd/passwd_extop.c
|
||||
@@ -1,5 +1,5 @@
|
||||
/** BEGIN COPYRIGHT BLOCK
|
||||
- * Copyright (C) 2005 Red Hat, Inc.
|
||||
+ * Copyright (C) 2025 Red Hat, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* License: GPL (version 3 or any later version).
|
||||
diff --git a/ldap/servers/slapd/unbind.c b/ldap/servers/slapd/unbind.c
|
||||
index fa8cd649f..c4e7a5efd 100644
|
||||
--- a/ldap/servers/slapd/unbind.c
|
||||
+++ b/ldap/servers/slapd/unbind.c
|
||||
@@ -1,6 +1,6 @@
|
||||
/** BEGIN COPYRIGHT BLOCK
|
||||
* Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
|
||||
- * Copyright (C) 2005 Red Hat, Inc.
|
||||
+ * Copyright (C) 2025 Red Hat, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* License: GPL (version 3 or any later version).
|
||||
@@ -112,8 +112,12 @@ do_unbind(Slapi_PBlock *pb)
|
||||
/* pass the unbind to all backends */
|
||||
be_unbindall(pb_conn, operation);
|
||||
|
||||
-free_and_return:;
|
||||
+free_and_return:
|
||||
|
||||
- /* close the connection to the client */
|
||||
- disconnect_server(pb_conn, operation->o_connid, operation->o_opid, SLAPD_DISCONNECT_UNBIND, 0);
|
||||
+ /* close the connection to the client after refreshing the operation */
|
||||
+ slapi_pblock_get(pb, SLAPI_OPERATION, &operation);
|
||||
+ disconnect_server(pb_conn,
|
||||
+ operation ? operation->o_connid : -1,
|
||||
+ operation ? operation->o_opid : -1,
|
||||
+ SLAPD_DISCONNECT_UNBIND, 0);
|
||||
}
|
||||
--
|
||||
2.49.0
|
||||
|
||||
@ -0,0 +1,35 @@
|
||||
From ea62e862c8ca7e036f7d1e23ec3a27bffbc39bdf Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
Date: Mon, 11 Aug 2025 13:19:13 +0200
|
||||
Subject: [PATCH] Issue 6929 - Compilation failure with rust-1.89 on Fedora ELN
|
||||
|
||||
Bug Description:
|
||||
The `ValueArrayRefIter` struct has a lifetime parameter `'a`.
|
||||
But in the `iter` method the return type doesn't specify the lifetime parameter.
|
||||
|
||||
Fix Description:
|
||||
Make the lifetime explicit.
|
||||
|
||||
Fixes: https://github.com/389ds/389-ds-base/issues/6929
|
||||
|
||||
Reviewed by: @droideck (Thanks!)
|
||||
---
|
||||
src/slapi_r_plugin/src/value.rs | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/slapi_r_plugin/src/value.rs b/src/slapi_r_plugin/src/value.rs
|
||||
index 2fd35c808..fec74ac25 100644
|
||||
--- a/src/slapi_r_plugin/src/value.rs
|
||||
+++ b/src/slapi_r_plugin/src/value.rs
|
||||
@@ -61,7 +61,7 @@ impl ValueArrayRef {
|
||||
ValueArrayRef { raw_slapi_val }
|
||||
}
|
||||
|
||||
- pub fn iter(&self) -> ValueArrayRefIter {
|
||||
+ pub fn iter(&self) -> ValueArrayRefIter<'_> {
|
||||
ValueArrayRefIter {
|
||||
idx: 0,
|
||||
va_ref: &self,
|
||||
--
|
||||
2.49.0
|
||||
|
||||
@ -333,6 +333,11 @@ Patch: 0033-Issue-6768-ns-slapd-crashes-when-a-referral-is-added.patc
|
||||
Patch: 0034-Issues-6913-6886-6250-Adjust-xfail-marks-6914.patch
|
||||
Patch: 0035-Issue-6875-Fix-dsidm-tests.patch
|
||||
Patch: 0036-Issue-6519-Add-basic-dsidm-account-tests.patch
|
||||
Patch: 0037-Issue-6940-dsconf-monitor-server-fails-with-ldapi-du.patch
|
||||
Patch: 0038-Issue-6936-Make-user-subtree-policy-creation-idempot.patch
|
||||
Patch: 0039-Issue-6919-numSubordinates-tombstoneNumSubordinates-.patch
|
||||
Patch: 0040-Issue-6910-Fix-latest-coverity-issues.patch
|
||||
Patch: 0041-Issue-6929-Compilation-failure-with-rust-1.89-on-Fed.patch
|
||||
|
||||
%description
|
||||
389 Directory Server is an LDAPv3 compliant server. The base package includes
|
||||
|
||||
@ -1,4 +1,9 @@
|
||||
---
|
||||
abidiff:
|
||||
ignore:
|
||||
- /usr/lib64/dirsrv/plugins/*.so
|
||||
- /usr/lib64/dirsrv/libsds.so*
|
||||
- /usr/lib64/dirsrv/libslapd.so*
|
||||
specname:
|
||||
match: suffix
|
||||
runpath:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user