import 389-ds-base-2.4.5-5.el9_4

c9 imports/c9/389-ds-base-2.4.5-5.el9_4
MSVSphere Packaging Team 6 months ago
parent 2aa7eff4d8
commit 45fbcde2df

@ -1,2 +1,2 @@
09d78ce7b3e2f3d5d28c889cabd56720a573ade3 SOURCES/389-ds-base-2.3.6.tar.bz2 e1146536caf20cdf178f8b9bca4f01be89dbcacb SOURCES/389-ds-base-2.4.5.tar.bz2
1c8f2d0dfbf39fa8cd86363bf3314351ab21f8d4 SOURCES/jemalloc-5.3.0.tar.bz2 1c8f2d0dfbf39fa8cd86363bf3314351ab21f8d4 SOURCES/jemalloc-5.3.0.tar.bz2

2
.gitignore vendored

@ -1,2 +1,2 @@
SOURCES/389-ds-base-2.3.6.tar.bz2 SOURCES/389-ds-base-2.4.5.tar.bz2
SOURCES/jemalloc-5.3.0.tar.bz2 SOURCES/jemalloc-5.3.0.tar.bz2

@ -0,0 +1,83 @@
From fcdeec3b876a28e06bb53a60fe502cb702403931 Mon Sep 17 00:00:00 2001
From: Simon Pichugin <spichugi@redhat.com>
Date: Tue, 27 Feb 2024 16:30:47 -0800
Subject: [PATCH] Issue 3527 - Support HAProxy and Instance on the same machine
configuration (#6107)
Description: Improve how we handle HAProxy connections to work better when
the DS and HAProxy are on the same machine.
Ensure the client and header destination IPs are checked against the trusted IP list.
Additionally, this change will also allow configuration having
HAProxy is listening on a different subnet than the one used to forward the request.
Related: https://github.com/389ds/389-ds-base/issues/3527
Reviewed by: @progier389, @jchapma (Thanks!)
---
ldap/servers/slapd/connection.c | 35 +++++++++++++++++++++++++--------
1 file changed, 27 insertions(+), 8 deletions(-)
diff --git a/ldap/servers/slapd/connection.c b/ldap/servers/slapd/connection.c
index a30511c97..07d629475 100644
--- a/ldap/servers/slapd/connection.c
+++ b/ldap/servers/slapd/connection.c
@@ -1187,6 +1187,8 @@ connection_read_operation(Connection *conn, Operation *op, ber_tag_t *tag, int *
char str_ip[INET6_ADDRSTRLEN + 1] = {0};
char str_haproxy_ip[INET6_ADDRSTRLEN + 1] = {0};
char str_haproxy_destip[INET6_ADDRSTRLEN + 1] = {0};
+ int trusted_matches_ip_found = 0;
+ int trusted_matches_destip_found = 0;
struct berval **bvals = NULL;
int proxy_connection = 0;
@@ -1245,21 +1247,38 @@ connection_read_operation(Connection *conn, Operation *op, ber_tag_t *tag, int *
normalize_IPv4(conn->cin_addr, buf_ip, sizeof(buf_ip), str_ip, sizeof(str_ip));
normalize_IPv4(&pr_netaddr_dest, buf_haproxy_destip, sizeof(buf_haproxy_destip),
str_haproxy_destip, sizeof(str_haproxy_destip));
+ size_t ip_len = strlen(buf_ip);
+ size_t destip_len = strlen(buf_haproxy_destip);
/* Now, reset RC and set it to 0 only if a match is found */
haproxy_rc = -1;
- /* Allow only:
- * Trusted IP == Original Client IP == HAProxy Header Destination IP */
+ /*
+ * We need to allow a configuration where DS instance and HAProxy are on the same machine.
+ * In this case, we need to check if
+ * the HAProxy client IP (which will be a loopback address) matches one of the the trusted IP addresses,
+ * while still checking that
+ * the HAProxy header destination IP address matches one of the trusted IP addresses.
+ * Additionally, this change will also allow configuration having
+ * HAProxy listening on a different subnet than one used to forward the request.
+ */
for (size_t i = 0; bvals[i] != NULL; ++i) {
- if ((strlen(bvals[i]->bv_val) == strlen(buf_ip)) &&
- (strlen(bvals[i]->bv_val) == strlen(buf_haproxy_destip)) &&
- (strncasecmp(bvals[i]->bv_val, buf_ip, strlen(buf_ip)) == 0) &&
- (strncasecmp(bvals[i]->bv_val, buf_haproxy_destip, strlen(buf_haproxy_destip)) == 0)) {
- haproxy_rc = 0;
- break;
+ size_t bval_len = strlen(bvals[i]->bv_val);
+
+ /* Check if the Client IP (HAProxy's machine IP) address matches the trusted IP address */
+ if (!trusted_matches_ip_found) {
+ trusted_matches_ip_found = (bval_len == ip_len) && (strncasecmp(bvals[i]->bv_val, buf_ip, ip_len) == 0);
+ }
+ /* Check if the HAProxy header destination IP address matches the trusted IP address */
+ if (!trusted_matches_destip_found) {
+ trusted_matches_destip_found = (bval_len == destip_len) && (strncasecmp(bvals[i]->bv_val, buf_haproxy_destip, destip_len) == 0);
}
}
+
+ if (trusted_matches_ip_found && trusted_matches_destip_found) {
+ haproxy_rc = 0;
+ }
+
if (haproxy_rc == -1) {
slapi_log_err(SLAPI_LOG_CONNS, "connection_read_operation", "HAProxy header received from unknown source.\n");
disconnect_server_nomutex(conn, conn->c_connid, -1, SLAPD_DISCONNECT_PROXY_UNKNOWN, EPROTO);
--
2.43.0

@ -1,119 +0,0 @@
From d9784b09531b19f6541602a31cfd49c9878ef2ca Mon Sep 17 00:00:00 2001
From: Simon Pichugin <spichugi@redhat.com>
Date: Thu, 31 Aug 2023 11:19:05 -0700
Subject: [PATCH] Issue 5848 - Fix condition and add a CI test (#5916)
Description: Add a "positive" test for the issue and fix the condition
to make sure that 65535 and no --replica-id are correctly accepted.
Related: https://github.com/389ds/389-ds-base/issues/5848
Reviewed by: @mreynolds389 @tbordaz (Thanks!)
---
dirsrvtests/tests/suites/clu/dsconf_test.py | 34 ++++++++++++++++++++-
src/lib389/lib389/cli_conf/replication.py | 23 ++++++++------
2 files changed, 47 insertions(+), 10 deletions(-)
diff --git a/dirsrvtests/tests/suites/clu/dsconf_test.py b/dirsrvtests/tests/suites/clu/dsconf_test.py
index eb3c426c7..4f7da0b58 100644
--- a/dirsrvtests/tests/suites/clu/dsconf_test.py
+++ b/dirsrvtests/tests/suites/clu/dsconf_test.py
@@ -99,7 +99,7 @@ def test_dsconf_with_ldaps(topology_st, enable_config, config_type):
@pytest.mark.parametrize('instance_role', ('consumer', 'hub'))
-def test_check_replica_id_rejected (instance_role):
+def test_check_replica_id_rejected_hub_consumer(instance_role):
"""Test dsconf CLI does not accept replica-id parameter for comsumer and hubs
:id: 274b47f8-111a-11ee-8321-98fa9ba19b65
@@ -129,3 +129,35 @@ def test_check_replica_id_rejected (instance_role):
log.info(f'output message : {msg}')
assert "Replication successfully enabled for" not in msg, f"Test Failed: --replica-id option is accepted....It shouldn't for {instance_role}"
log.info(f"Test PASSED: --replica-id option is NOT accepted for {instance_role}.")
+
+
+@pytest.mark.parametrize('instance_role, replica_id',
+ [('consumer', None), ('hub', None), ('consumer', "65535"), ('hub', "65535")])
+def test_check_replica_id_accepted_hub_consumer(topology_st, instance_role, replica_id):
+ """Test dsconf CLI accepts 65535 replica-id parameter for comsumer and hubs
+
+ :id: e0a1a1e6-11c1-40e6-92fe-cb550fb2170d
+ :parametrized: yes
+ :customerscenario: True
+ :setup: Create DS instance
+ :steps:
+ 1. Create ldap instance
+ 2. Use dsconf cli to create replica and don't specify replica id for a consumer or hub
+ 3. Use dsconf cli to create replica and specify replica id for a consumer or hub
+ :expectedresults:
+ 1. Success
+ 2. Success
+ 3. Success
+ """
+ print("DN_DM {}".format(DN_DM))
+ cmdline = ['/usr/sbin/dsconf', 'standalone1', '-D', DN_DM, '-w', 'password', 'replication', 'enable', '--suffix', DEFAULT_SUFFIX, '--role', instance_role]
+ if replica_id is not None:
+ cmdline.append(f'--replica-id={replica_id}')
+ log.info(f'Command used : {cmdline}')
+ proc = subprocess.Popen(cmdline, stdout=subprocess.PIPE)
+
+ msg = proc.communicate()
+ msg = msg[0].decode('utf-8')
+ log.info(f'output message : {msg}')
+ assert "Replication successfully enabled for" in msg
+ log.info(f"Test PASSED: --replica-id option is accepted for {instance_role}.")
diff --git a/src/lib389/lib389/cli_conf/replication.py b/src/lib389/lib389/cli_conf/replication.py
index a75774ca0..2e2803ced 100644
--- a/src/lib389/lib389/cli_conf/replication.py
+++ b/src/lib389/lib389/cli_conf/replication.py
@@ -154,6 +154,17 @@ def enable_replication(inst, basedn, log, args):
# error - unknown type
raise ValueError(f"Unknown replication role ({role}), you must use \"supplier\", \"hub\", or \"consumer\"")
+ if args.replica_id is not None:
+ # is it a number?
+ try:
+ rid_num = int(rid)
+ except ValueError:
+ raise ValueError("--replica-id expects a number between 1 and 65535")
+
+ # Is it in range?
+ if rid_num < 1 or rid_num > 65535:
+ raise ValueError("--replica-id expects a number between 1 and 65535")
+
# Start the propeties and update them as needed
repl_properties = {
'cn': 'replica',
@@ -170,15 +181,9 @@ def enable_replication(inst, basedn, log, args):
# Error, supplier needs a rid TODO
raise ValueError('You must specify the replica ID (--replica-id) when enabling a \"supplier\" replica')
- # is it a number?
- try:
- rid_num = int(rid)
- except ValueError:
- raise ValueError("--replica-id expects a number between 1 and 65534")
-
# Is it in range?
if rid_num < 1 or rid_num > 65534:
- raise ValueError("--replica-id expects a number between 1 and 65534")
+ raise ValueError("--replica-id expects a number between 1 and 65534 for supplier role")
# rid is good add it to the props
repl_properties['nsDS5ReplicaId'] = args.replica_id
@@ -186,9 +191,9 @@ def enable_replication(inst, basedn, log, args):
# Validate consumer and hub settings
elif role == "consumer" or role == "hub":
# Check Replica ID
- if args.replica_id is not None or args.replica_id != 65535:
+ if args.replica_id is not None and rid_num != 65535:
# Error, Replica ID cannot be specified for consumer and hub roles
- raise ValueError('Replica ID cannot be specified for consumer and hub roles')
+ raise ValueError('Replica ID other than 65535 cannot be specified for consumer and hub roles')
# Bind DN or Bind DN Group?
if args.bind_group_dn:
--
2.41.0

@ -1,50 +0,0 @@
From b2194c95f9d02965b2ad3d0dcf333e74881347d0 Mon Sep 17 00:00:00 2001
From: James Chapman <jachapma@redhat.com>
Date: Thu, 31 Aug 2023 14:05:31 +0000
Subject: [PATCH] Issue 5909 - Multi listener hang with 20k connections (#5917)
Bug Description: A fix for connection sub-table to freelist mapping results
in an uninitialised head of the sub-table linked list.
Fix Description: During connection table creation, initialise all elements but
skip the list head during the mapping phase.
Fixes: https//github.com/389ds/389-ds-base/issues/5909
Reviewed by: @progier389 @tbordaz (Thank you)
---
ldap/servers/slapd/conntable.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/ldap/servers/slapd/conntable.c b/ldap/servers/slapd/conntable.c
index b1c66cf42..11e997432 100644
--- a/ldap/servers/slapd/conntable.c
+++ b/ldap/servers/slapd/conntable.c
@@ -172,9 +172,9 @@ connection_table_new(int table_size)
/* all connections start out invalid */
ct->fd[ct_list][i].fd = SLAPD_INVALID_SOCKET;
- /* The connection table has a double linked list running through it.
+ /* The connection sub-tables have a double linked list running through them.
* This is used to find out which connections should be looked at
- * in the poll loop. Slot 0 in the table is always the head of
+ * in the poll loop. Slot 0 in each sub-table is always the head of
* the linked list. Each slot has a c_next and c_prev which are
* pointers back into the array of connection slots. */
ct->c[ct_list][i].c_next = NULL;
@@ -196,8 +196,10 @@ connection_table_new(int table_size)
/* Ready to rock, mark as such. */
ct->c[ct_list][i].c_state = CONN_STATE_INIT;
- /* Map multiple ct lists to a single freelist. */
- ct->c_freelist[free_idx++] = &(ct->c[ct_list][i]);
+ /* Map multiple ct lists to a single freelist, but skip slot 0 of each list. */
+ if (i != 0) {
+ ct->c_freelist[free_idx++] = &(ct->c[ct_list][i]);
+ }
}
}
--
2.41.0

@ -1,629 +0,0 @@
From 26716f0edefe4690d9fd9143d07156e01321020c Mon Sep 17 00:00:00 2001
From: progier389 <progier@redhat.com>
Date: Thu, 28 Sep 2023 12:15:25 +0200
Subject: [PATCH] issue 5924 - ASAN server build crash when looping
opening/closing connections (#5926)
* issue 5924 - ASAN server build crash when looping opening/closing connections
Issue: Got a crash due to:
1. Failure to get a connection slot because connection freelist is misshandled.
2. A confusion between listening and acceptedfd descriptor leaded to
close the listening descriptor while handing the error.
Solution:
Rename clearly the file descriptor variables
Close the accepted file descriptor in error handler
Rewrite the freelist management so that first connection chosen is the last released one.
(Code is simpler, this fix the end of list issue, and it avoid to spread the open connection over too much memory)
Issue: #5924
Reviewed by: @Firstyear, @vashirov, @droideck (Thanks !)
(cherry picked from commit 02d333251419ff3c4d0384595e9fe7ded5bcd8fc)
---
dirsrvtests/tests/suites/basic/basic_test.py | 287 +++++++++++++++++++
ldap/servers/slapd/conntable.c | 100 +++----
ldap/servers/slapd/daemon.c | 35 ++-
ldap/servers/slapd/fe.h | 1 -
4 files changed, 351 insertions(+), 72 deletions(-)
diff --git a/dirsrvtests/tests/suites/basic/basic_test.py b/dirsrvtests/tests/suites/basic/basic_test.py
index fac0f7371..f4525e184 100644
--- a/dirsrvtests/tests/suites/basic/basic_test.py
+++ b/dirsrvtests/tests/suites/basic/basic_test.py
@@ -28,7 +28,15 @@ from lib389.replica import Replicas, Changelog
from lib389.backend import Backends
from lib389.idm.domain import Domain
from lib389.nss_ssl import NssSsl
+from lib389._constants import *
+from lib389 import DirSrv
+from lib389.instance.setup import SetupDs
+from lib389.instance.options import General2Base, Slapd2Base
import os
+import random
+import ldap
+import time
+import subprocess
pytestmark = pytest.mark.tier0
@@ -36,6 +44,7 @@ pytestmark = pytest.mark.tier0
default_paths = Paths()
log = logging.getLogger(__name__)
+DEBUGGING = os.getenv("DEBUGGING", default=False)
# Globals
USER1_DN = 'uid=user1,' + DEFAULT_SUFFIX
@@ -51,6 +60,190 @@ ROOTDSE_DEF_ATTR_LIST = ('namingContexts',
'vendorName',
'vendorVersion')
+# This MAX_FDS value left about 22 connections available with bdb
+# (should have more connections with lmdb)
+MAX_FDS = 150
+
+
+
+default_paths = Paths()
+
+
+
+log = logging.getLogger(__name__)
+DEBUGGING = os.getenv("DEBUGGING", default=False)
+
+
+class CustomSetup():
+ DEFAULT_GENERAL = { 'config_version': 2,
+ 'full_machine_name': 'localhost.localdomain',
+ 'strict_host_checking': False,
+ # Not setting 'systemd' because it is not used.
+ # (that is the global default.inf setting that matters)
+ }
+ DEFAULT_SLAPD = { 'root_password': PW_DM,
+ 'defaults': INSTALL_LATEST_CONFIG,
+ }
+ DEFAULT_BACKENDS = [ {
+ 'cn': 'userroot',
+ 'nsslapd-suffix': DEFAULT_SUFFIX,
+ 'sample_entries': 'yes',
+ BACKEND_SAMPLE_ENTRIES: INSTALL_LATEST_CONFIG,
+ }, ]
+
+ WRAPPER_FORMAT = '''#!/bin/sh
+{wrapper_options}
+exec {nsslapd} -D {cfgdir} -i {pidfile}
+'''
+
+
+ class CustomDirSrv(DirSrv):
+ def __init__(self, verbose=False, external_log=log):
+ super().__init__(verbose=verbose, external_log=external_log)
+ self.wrapper = None # placeholder for the wrapper file name
+
+ def _reset_systemd(self):
+ self.systemd_override = False
+
+ def status(self):
+ self._reset_systemd()
+ return super().status()
+
+ def start(self, timeout=120, *args):
+ if self.status():
+ return
+ tmp_env = os.environ
+ # Unset PYTHONPATH to avoid mixing old CLI tools and new lib389
+ if "PYTHONPATH" in tmp_env:
+ del tmp_env["PYTHONPATH"]
+ try:
+ subprocess.check_call([
+ '/usr/bin/sh',
+ self.wrapper
+ ], env=tmp_env, stderr=subprocess.STDOUT)
+ except subprocess.CalledProcessError as e:
+ log.fatal("%s failed! Error (%s) %s" % (self.wrapper, e.returncode, e.output))
+ raise e from None
+ for count in range(timeout):
+ if self.status():
+ return
+ time.sleep(1)
+ raise TimeoutException('Failed to start ns-slpad')
+
+ def stop(self, timeout=120):
+ self._reset_systemd()
+ super().stop(timeout=timeout)
+
+
+ def _search_be(belist, beinfo):
+ for be in belist:
+ if be['cn'] == beinfo['cn']:
+ return be
+ return None
+
+ def __init__(self, serverid, general=None, slapd=None, backends=None, log=log):
+ verbose = log.level > logging.DEBUG
+ self.log = log
+ self.serverid = serverid
+ self.verbose = verbose
+ self.wrapper = f'/tmp/ds_{serverid}_wrapper.sh'
+ if serverid.startswith('slapd-'):
+ self.instname = server.id
+ else:
+ self.instname = 'slapd-'+serverid
+ self.ldapi = None
+ self.pid_file = None
+ self.inst = None
+
+ # Lets prepare the options
+ general_options = General2Base(log)
+ for d in (CustomSetup.DEFAULT_GENERAL, general):
+ if d:
+ for key,val in d.items():
+ general_options.set(key,val)
+ log.debug('[general]: %s' % general_options._options)
+ self.general = general_options
+
+ slapd_options = Slapd2Base(self.log)
+ slapd_options.set('instance_name', serverid)
+ for d in (CustomSetup.DEFAULT_SLAPD, slapd):
+ if d:
+ for key,val in d.items():
+ slapd_options.set(key,val)
+ log.debug('[slapd]: %s' % slapd_options._options)
+ self.slapd = slapd_options
+
+ backend_options = []
+ for backend_list in (CustomSetup.DEFAULT_BACKENDS, backends):
+ if not backend_list:
+ continue
+ for backend in backend_list:
+ target_be = CustomSetup._search_be(backend_options, backend)
+ if not target_be:
+ target_be = {}
+ backend_options.append(target_be)
+ for key,val in backend.items():
+ target_be[key] = val
+ log.debug('[backends]: %s' % backend_options)
+ self.backends = backend_options
+
+ def _to_dirsrv_args(self):
+ args = {}
+ slapd = self.slapd.collect()
+ general = self.general.collect()
+ args["SER_HOST"] = general['full_machine_name']
+ args["SER_PORT"] = slapd['port']
+ args["SER_SECURE_PORT"] = slapd['secure_port']
+ args["SER_SERVERID_PROP"] = self.serverid
+ return args
+
+ def create_instance(self):
+ sds = SetupDs(verbose=self.verbose, dryrun=False, log=self.log)
+ self.general.verify()
+ general = self.general.collect()
+ self.slapd.verify()
+ slapd = self.slapd.collect()
+ sds.create_from_args(general, slapd, self.backends, None)
+ self.ldapi = get_ldapurl_from_serverid(self.serverid)[0]
+ args = self._to_dirsrv_args()
+ log.debug('DirSrv.allocate args = %s' % str(args))
+ log.debug('ldapi = %s' % str(self.ldapi))
+ root_dn = slapd['root_dn']
+ root_password = slapd['root_password']
+ inst = DirSrv(verbose=self.verbose, external_log=self.log)
+ inst.local_simple_allocate(self.serverid, ldapuri=self.ldapi, binddn=root_dn, password=root_password)
+ self.pid_file = inst.pid_file()
+ # inst.setup_ldapi()
+ log.debug('DirSrv = %s' % str(inst.__dict__))
+ inst.open()
+ inst.stop()
+ inst = CustomSetup.CustomDirSrv(verbose=self.verbose, external_log=self.log)
+ inst.local_simple_allocate(self.serverid, ldapuri=self.ldapi, binddn=root_dn, password=root_password)
+ self.inst = inst
+ return inst
+
+ def create_wrapper(self, maxfds=None):
+ self.inst.wrapper = self.wrapper
+ slapd = self.slapd.collect()
+ sbin_dir = slapd['sbin_dir']
+ config_dir = slapd['config_dir']
+ fmtvalues = {
+ 'nsslapd': f'{sbin_dir}/ns-slapd',
+ 'cfgdir': config_dir.format(instance_name=self.instname),
+ 'pidfile': self.pid_file,
+ 'wrapper_options': ''
+ }
+ if maxfds:
+ fmtvalues['wrapper_options']=f'ulimit -n {maxfds}\nulimit -H -n {maxfds}'
+ with open(self.wrapper, 'w') as f:
+ f.write(CustomSetup.WRAPPER_FORMAT.format(**fmtvalues))
+
+ def cleanup(self):
+ self.inst.stop()
+ self.inst.delete()
+ if os.path.exists(self.wrapper):
+ os.remove(self.wrapper)
+
@pytest.fixture(scope="function")
def _reset_attr(request, topology_st):
@@ -2222,6 +2415,100 @@ def test_dscreate_with_different_rdn(dscreate_test_rdn_value):
assert True
+@pytest.fixture(scope="module")
+def dscreate_custom_instance(request):
+ topo = CustomSetup('custom')
+
+ def fin():
+ topo.cleanup()
+
+ request.addfinalizer(fin)
+ topo.create_instance()
+ # Return CustomSetup object associated with
+ # a stopped instance named "custom"
+ return topo
+
+ obj.create_wrapper(maxfds=150)
+ log.info("Starting wrapper")
+ inst.start()
+ log.info("Server is started.")
+ log.info("Open connection")
+ inst.open()
+
+
+@pytest.fixture(scope="module", params=set(range(1,5)))
+def dscreate_with_numlistener(request, dscreate_custom_instance):
+ numlisteners = request.param
+ dscreate_custom_instance.create_wrapper(maxfds=MAX_FDS)
+ inst = dscreate_custom_instance.inst
+ inst.stop()
+ dse_ldif = DSEldif(inst)
+ dse_ldif.replace('cn=config', 'nsslapd-numlisteners', str(numlisteners))
+ inst.start()
+ inst.open()
+ return inst
+
+
+@pytest.mark.skipif(ds_is_older('2.2.0.0'),
+ reason="This test is only required with multiple listener support.")
+def test_conn_limits(dscreate_with_numlistener):
+ """Check the connections limits for various number of listeners.
+
+ :id: 7be2eb5c-4d8f-11ee-ae3d-482ae39447e5
+ :parametrized: yes
+ :setup: Setup an instance then set nsslapd-numlisteners and maximum file descriptors
+ :steps:
+ 1. Loops on:
+ Open new connection and perform search until timeout expires
+ 2. Close one of the previously open connections
+ 3. Loops MAX_FDS times on:
+ - opening a new connection
+ - perform a search
+ - close the connection
+ 4. Close all open connections
+ 5. Remove the instance
+ :expectedresults:
+ 1. Should get a timeout (because the server has no more any connections)
+ 2. Should success
+ 3. Should success (otherwise issue #5924 has probably been hit)
+ 4. Should success
+ 5. Should success
+ """
+ inst = dscreate_with_numlistener
+
+ conns = []
+ timeout_occured = False
+ for i in range(MAX_FDS):
+ try:
+ ldc = ldap.initialize(f'ldap://localhost:{inst.port}')
+ ldc.set_option(ldap.OPT_TIMEOUT, 5)
+ ldc.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, "(uid=demo)")
+ conns.append(ldc)
+ except ldap.TIMEOUT:
+ timeout_occured = True
+ break
+ # Should not be able to open MAX_FDS connections (some file descriptor are
+ # reserved (for example for the listening socket )
+ assert timeout_occured
+
+ conn = random.choice(conns)
+ conn.unbind()
+ conns.remove(conn)
+
+ # Should loop enough time so trigger issue #5924 if it is not fixed.
+ for i in range(MAX_FDS):
+ ldc = ldap.initialize(f'ldap://localhost:{inst.port}')
+ # Set a timeout long enough so that the test fails if server is unresponsive
+ ldc.set_option(ldap.OPT_TIMEOUT, 60)
+ ldc.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, "(uid=demo)")
+ ldc.unbind()
+
+ # Close all open connections
+ for c in conns:
+ c.unbind()
+
+ # Step 6 is done in teardown phase by dscreate_instance finalizer
+
if __name__ == '__main__':
# Run isolated
# -s for DEBUG mode
diff --git a/ldap/servers/slapd/conntable.c b/ldap/servers/slapd/conntable.c
index 11e997432..1ca60e0e5 100644
--- a/ldap/servers/slapd/conntable.c
+++ b/ldap/servers/slapd/conntable.c
@@ -48,69 +48,59 @@
* under the connection table lock. This should move the allocation algorithm from O(n) worst case
* to O(1) worst case as we always recieve and empty slot *or* ct full. It also reduces lock/atomic
* contention on the CPU to improve things.
+ * Lastly a change was done: Instead of having a sliding windows that tend to get a never used
+ * slot for each new connection, it nows reuse last freed one. That has several benefits:
+ * - Fix a bug because the last free list slots may not be alloced.
+ * - Avoid to grow the memory footprint when there is no much load
+ * - Simplify the code (as only a single is needed. )
*
- * The freelist is a ringbuffer of pointers to the connection table. On a small scale it looks like:
+ * The freelist is a stack of pointers to the connection table.
+ * It is NULL terminated. On a small scale it looks like:
*
* |--------------------------------------------|
- * | slot 1 | slot 2 | slot 3 | slot 4 | slot 5 |
- * | _ ptr | _ ptr | _ ptr | _ ptr | _ ptr |
+ * | slot 0 | slot 1 | slot 2 | slot 3 | slot 4 |
+ * | _ ptr | _ ptr | _ ptr | _ ptr | NULL |
* |--------------------------------------------|
- * ^ ^- conn_next
- * |
- * \-- conn_free
+ * ^- conn_next
*
- * As we allocate, we shift conn_next through the list, yielding the ptr that was stored (and
- * setting it to NULL as we proceed)
+ * To allocate, we pop one of the stored connection ptr out of the stack (yield the ptr, set
+ * its slot to NULL then increase conn_next)
*
* |--------------------------------------------|
- * | slot 1 | slot 2 | slot 3 | slot 4 | slot 5 |
- * | _NULL | _NULL | _ ptr | _ ptr | _ ptr |
+ * | slot 0 | slot 1 | slot 2 | slot 3 | slot 4 |
+ * | _NULL | _NULL | _ ptr | _ ptr | NULL |
* |--------------------------------------------|
- * ^ ^- conn_next
- * |
- * \-- conn_free
+ * ^- conn_next
*
- * When a connection is "freed" we return it to conn_free, which is then also slid up.
+ * When a connection is "freed" we push it back in the stack after decreasing conn_next
*
* |--------------------------------------------|
- * | slot 1 | slot 2 | slot 3 | slot 4 | slot 5 |
- * | _ ptr | _NULL | _ ptr | _ ptr | _ ptr |
+ * | slot 0 | slot 1 | slot 2 | slot 3 | slot 4 |
+ * | _NULL | _ ptr | _ ptr | _ ptr | NULL |
* |--------------------------------------------|
- * ^ ^- conn_next
- * |
- * \-- conn_free
+ * ^- conn_next
*
- * If all connections are exhausted, conn_next will == conn_next, as conn_next must have proceeded
- * to the end of the ring, and then wrapped back allocating all previous until we meet with conn_free.
+ * If all connections are exhausted, freelist[conn_next] is NULL
*
* |--------------------------------------------|
- * | slot 1 | slot 2 | slot 3 | slot 4 | slot 5 |
+ * | slot 0 | slot 1 | slot 2 | slot 3 | slot 4 |
* | _NULL | _NULL | _NULL | _NULL | _NULL |
* |--------------------------------------------|
- * ^ ^- conn_next
- * |
- * \-- conn_free
+ * ^- conn_next
*
* This means allocations of conns will keep failing until a connection is returned.
*
* |--------------------------------------------|
- * | slot 1 | slot 2 | slot 3 | slot 4 | slot 5 |
- * | _NULL | _ ptr | _NULL | _NULL | _NULL |
+ * | slot 0 | slot 1 | slot 2 | slot 3 | slot 4 |
+ * | _NULL | _NULL | _NULL | _ ptr | NULL |
* |--------------------------------------------|
- * ^- conn_next ^
- * |
- * \-- conn_free
+ * ^- conn_next
*
* And now conn_next can begin to allocate again.
*
*
* -- invariants
- * * when conn_free is slid back to meet conn_next, there can be no situation where another
- * connection is returned, as none must allocated -if they were allocated, conn_free would have
- * moved_along.
- * * the ring buffer must be as large as conntable.
- * * We do not check conn_next == conn_free (that's the starting state), but we check if the
- * slot at conn_next is NULL, which must imply that conn_free has nothing to return.
+ * * the stack must be as large as conntable.
* * connection_table_move_connection_out_of_active_list is the only function able to return a
* connection to the freelist, as it is the function that is called when the event system has
* determined all IO's are complete, or unable to complete. This function is what prepares the
@@ -136,11 +126,9 @@ connection_table_new(int table_size)
ct->c = (Connection **)slapi_ch_calloc(1, ct->size * sizeof(Connection *));
ct->fd = (struct POLL_STRUCT **)slapi_ch_calloc(1, ct->list_num * sizeof(struct POLL_STRUCT*));
ct->table_mutex = PR_NewLock();
- /* Allocate the freelist */
- ct->c_freelist = (Connection **)slapi_ch_calloc(1, ct->size * sizeof(Connection *));
- /* NEVER use slot 0, this is a list pointer */
- ct->conn_next_offset = 1;
- ct->conn_free_offset = 1;
+ /* Allocate the freelist (a slot for each connection plus another slot for the final NULL pointer) */
+ ct->c_freelist = (Connection **)slapi_ch_calloc(1, (ct->size+1) * sizeof(Connection *));
+ ct->conn_next_offset = 0;
slapi_log_err(SLAPI_LOG_INFO, "connection_table_new", "Number of connection sub-tables %d, each containing %d slots.\n",
ct->list_num, ct->list_size);
@@ -273,22 +261,22 @@ connection_table_get_connection(Connection_Table *ct, int sd)
{
PR_Lock(ct->table_mutex);
- PR_ASSERT(ct->conn_next_offset != 0);
Connection *c = ct->c_freelist[ct->conn_next_offset];
if (c != NULL) {
/* We allocated it, so now NULL the slot and move forward. */
- ct->c_freelist[ct->conn_next_offset] = NULL;
- /* Handle overflow. */
- ct->conn_next_offset = (ct->conn_next_offset + 1) % ct->size;
- if (ct->conn_next_offset == 0) {
- /* Never use slot 0 */
- ct->conn_next_offset += 1;
- }
+ PR_ASSERT(ct->conn_next_offset>=0 && ct->conn_next_offset<ct->size);
+ ct->c_freelist[ct->conn_next_offset++] = NULL;
PR_Unlock(ct->table_mutex);
} else {
/* couldn't find a Connection, table must be full */
- slapi_log_err(SLAPI_LOG_CONNS, "connection_table_get_connection", "Max open connections reached\n");
PR_Unlock(ct->table_mutex);
+ static time_t last_err_msg_time = 0;
+ time_t curtime = slapi_current_utc_time();
+ /* Logs the message only once per seconds */
+ if (curtime != last_err_msg_time) {
+ slapi_log_err(SLAPI_LOG_ERR, "connection_table_get_connection", "Max open connections reached\n");
+ last_err_msg_time = curtime;
+ }
return NULL;
}
@@ -461,14 +449,10 @@ connection_table_move_connection_out_of_active_list(Connection_Table *ct, Connec
/* Finally, place the connection back into the freelist for use */
PR_ASSERT(c->c_refcnt == 0);
- PR_ASSERT(ct->conn_free_offset != 0);
- PR_ASSERT(ct->c_freelist[ct->conn_free_offset] == NULL);
- ct->c_freelist[ct->conn_free_offset] = c;
- ct->conn_free_offset = (ct->conn_free_offset + 1) % ct->size;
- if (ct->conn_free_offset == 0) {
- /* Never use slot 0 */
- ct->conn_free_offset += 1;
- }
+ PR_ASSERT(ct->conn_next_offset != 0);
+ ct->conn_next_offset--;
+ PR_ASSERT(ct->c_freelist[ct->conn_next_offset] == NULL);
+ ct->c_freelist[ct->conn_next_offset] = c;
PR_Unlock(ct->table_mutex);
diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
index e8b979aca..10aabed6d 100644
--- a/ldap/servers/slapd/daemon.c
+++ b/ldap/servers/slapd/daemon.c
@@ -135,19 +135,25 @@ get_pid_file(void)
}
static int
-accept_and_configure(int s __attribute__((unused)), PRFileDesc *pr_acceptfd, PRNetAddr *pr_netaddr, int addrlen __attribute__((unused)), int secure, int local, PRFileDesc **pr_clonefd)
+accept_and_configure(int s __attribute__((unused)), PRFileDesc *listenfd, PRNetAddr *pr_netaddr, int addrlen __attribute__((unused)), int secure, int local, PRFileDesc **pr_accepted_fd)
{
int ns = 0;
PRIntervalTime pr_timeout = PR_MillisecondsToInterval(slapd_accept_wakeup_timer);
- (*pr_clonefd) = PR_Accept(pr_acceptfd, pr_netaddr, pr_timeout);
- if (!(*pr_clonefd)) {
+ (*pr_accepted_fd) = PR_Accept(listenfd, pr_netaddr, pr_timeout);
+ if (!(*pr_accepted_fd)) {
PRErrorCode prerr = PR_GetError();
- slapi_log_err(SLAPI_LOG_ERR, "accept_and_configure", "PR_Accept() failed, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
- prerr, slapd_pr_strerror(prerr));
+ static time_t last_err_msg_time = 0;
+ time_t curtime = slapi_current_utc_time();
+ /* Logs the message only once per seconds */
+ if (curtime != last_err_msg_time) {
+ slapi_log_err(SLAPI_LOG_ERR, "accept_and_configure", "PR_Accept() failed, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ prerr, slapd_pr_strerror(prerr));
+ last_err_msg_time = curtime;
+ }
return (SLAPD_INVALID_SOCKET);
}
- ns = configure_pr_socket(pr_clonefd, secure, local);
+ ns = configure_pr_socket(pr_accepted_fd, secure, local);
return ns;
}
@@ -155,7 +161,7 @@ accept_and_configure(int s __attribute__((unused)), PRFileDesc *pr_acceptfd, PRN
/*
* This is the shiny new re-born daemon function, without all the hair
*/
-static int handle_new_connection(Connection_Table *ct, int tcps, PRFileDesc *pr_acceptfd, int secure, int local, Connection **newconn);
+static int handle_new_connection(Connection_Table *ct, int tcps, PRFileDesc *listenfd, int secure, int local, Connection **newconn);
static void handle_pr_read_ready(Connection_Table *ct, int list_id, PRIntn num_poll);
static int clear_signal(struct POLL_STRUCT *fds, int list_id);
static void unfurl_banners(Connection_Table *ct, daemon_ports_t *ports, PRFileDesc **n_tcps, PRFileDesc **s_tcps, PRFileDesc **i_unix);
@@ -831,6 +837,7 @@ accept_thread(void *vports)
}
/* Need a sleep delay here. */
PR_Sleep(pr_timeout);
+ last_accept_new_connections = accept_new_connections;
continue;
} else {
/* Log that we are now listening again */
@@ -1846,28 +1853,30 @@ handle_closed_connection(Connection *conn)
* this function returns the connection table list the new connection is in
*/
static int
-handle_new_connection(Connection_Table *ct, int tcps, PRFileDesc *pr_acceptfd, int secure, int local, Connection **newconn)
+handle_new_connection(Connection_Table *ct, int tcps, PRFileDesc *listenfd, int secure, int local, Connection **newconn)
{
int ns = 0;
Connection *conn = NULL;
/* struct sockaddr_in from;*/
PRNetAddr from = {{0}};
- PRFileDesc *pr_clonefd = NULL;
+ PRFileDesc *pr_accepted_fd = NULL;
slapdFrontendConfig_t *fecfg = getFrontendConfig();
ber_len_t maxbersize;
if (newconn) {
*newconn = NULL;
}
- if ((ns = accept_and_configure(tcps, pr_acceptfd, &from,
- sizeof(from), secure, local, &pr_clonefd)) == SLAPD_INVALID_SOCKET) {
+ if ((ns = accept_and_configure(tcps, listenfd, &from,
+ sizeof(from), secure, local, &pr_accepted_fd)) == SLAPD_INVALID_SOCKET) {
return -1;
}
/* get a new Connection from the Connection Table */
conn = connection_table_get_connection(ct, ns);
if (conn == NULL) {
- PR_Close(pr_acceptfd);
+ if (pr_accepted_fd) {
+ PR_Close(pr_accepted_fd);
+ }
return -1;
}
pthread_mutex_lock(&(conn->c_mutex));
@@ -1879,7 +1888,7 @@ handle_new_connection(Connection_Table *ct, int tcps, PRFileDesc *pr_acceptfd, i
conn->c_idletimeout = fecfg->idletimeout;
conn->c_idletimeout_handle = idletimeout_reslimit_handle;
conn->c_sd = ns;
- conn->c_prfd = pr_clonefd;
+ conn->c_prfd = pr_accepted_fd;
conn->c_flags &= ~CONN_FLAG_CLOSING;
/* Set per connection static config */
diff --git a/ldap/servers/slapd/fe.h b/ldap/servers/slapd/fe.h
index 64c6645e7..95dfeeb89 100644
--- a/ldap/servers/slapd/fe.h
+++ b/ldap/servers/slapd/fe.h
@@ -88,7 +88,6 @@ struct connection_table
/* An array of free connections awaiting allocation. */;
Connection **c_freelist;
size_t conn_next_offset;
- size_t conn_free_offset;
struct POLL_STRUCT **fd;
PRLock *table_mutex;
};
--
2.41.0

@ -1,388 +0,0 @@
From dc091325814d9ac74d238c7e14cac8b9112b3271 Mon Sep 17 00:00:00 2001
From: progier389 <progier@redhat.com>
Date: Fri, 17 Nov 2023 14:41:51 +0100
Subject: [PATCH] Issue 5984 - Crash when paged result search are abandoned
(#5985)
* Issue 5984 - Crash when paged result search are abandoned
Problem:
Fix #4551 has changed the lock that protects the paged result data
within a connection. But the abandon operation attempts to free
the paged search result with the connection lock.
This leads to race condition and double free causing an heap
corruption and a SIGSEGV.
Solution:
- Get a copy of the operation data that needs to be logged.
- Unlock the connection mutex (to avoid deadlock risk)
- Free the paged result while holding the paged result lock.
Issue: 5984
Reviewed by: @tbordaz (Thanks!)
(cherry picked from commit 06bd0862956672eb76276cab5c1dd906fe5a7eec)
---
.../paged_results/paged_results_test.py | 107 ++++++++++++++++--
ldap/servers/slapd/abandon.c | 23 ++--
ldap/servers/slapd/opshared.c | 4 +-
ldap/servers/slapd/pagedresults.c | 8 +-
ldap/servers/slapd/proto-slap.h | 2 +-
src/lib389/lib389/__init__.py | 27 ++++-
6 files changed, 150 insertions(+), 21 deletions(-)
diff --git a/dirsrvtests/tests/suites/paged_results/paged_results_test.py b/dirsrvtests/tests/suites/paged_results/paged_results_test.py
index d490c4af2..cdafa834a 100644
--- a/dirsrvtests/tests/suites/paged_results/paged_results_test.py
+++ b/dirsrvtests/tests/suites/paged_results/paged_results_test.py
@@ -7,7 +7,8 @@
# --- END COPYRIGHT BLOCK ---
#
import socket
-from random import sample
+from random import sample, randrange
+
import pytest
from ldap.controls import SimplePagedResultsControl, GetEffectiveRightsControl
from lib389.tasks import *
@@ -16,6 +17,10 @@ from lib389.topologies import topology_st
from lib389._constants import DN_LDBM, DN_DM, DEFAULT_SUFFIX
from lib389._controls import SSSRequestControl
from lib389.idm.user import UserAccount, UserAccounts
+from lib389.cli_base import FakeArgs
+from lib389.config import LDBMConfig
+from lib389.dbgen import dbgen_users
+
from lib389.idm.organization import Organization
from lib389.idm.organizationalunit import OrganizationalUnit
from lib389.backend import Backends
@@ -42,11 +47,56 @@ NEW_BACKEND_1 = 'parent_base'
NEW_BACKEND_2 = 'child_base'
OLD_HOSTNAME = socket.gethostname()
-socket.sethostname('localhost')
+if os.getuid() == 0:
+ socket.sethostname('localhost')
HOSTNAME = socket.gethostname()
IP_ADDRESS = socket.gethostbyname(HOSTNAME)
OLD_IP_ADDRESS = socket.gethostbyname(OLD_HOSTNAME)
+
+@pytest.fixture(scope="module")
+def create_40k_users(topology_st, request):
+ inst = topology_st.standalone
+
+ # Prepare return value
+ retval = FakeArgs()
+ retval.inst = inst
+ retval.bename = '40k'
+ retval.suffix = f'o={retval.bename}'
+ retval.ldif_file = f'{inst.get_ldif_dir()}/{retval.bename}.ldif'
+
+ # Create new backend
+ bes = Backends(inst)
+ be_1 = bes.create(properties={
+ 'cn': retval.bename,
+ 'nsslapd-suffix': retval.suffix,
+ })
+
+ # Set paged search lookthrough limit
+ ldbmconfig = LDBMConfig(inst)
+ ldbmconfig.replace('nsslapd-pagedlookthroughlimit', b'100000')
+
+ # Create ldif and import it.
+ dbgen_users(inst, 40000, retval.ldif_file, retval.suffix)
+ # tasks = Tasks(inst)
+ # args = {TASK_WAIT: True}
+ # tasks.importLDIF(retval.suffix, None, retval.ldif_file, args)
+ inst.stop()
+ assert inst.ldif2db(retval.bename, None, None, None, retval.ldif_file, None)
+ inst.start()
+
+ # And set an aci allowing anonymous read
+ log.info('Adding ACI to allow our test user to search')
+ ACI_TARGET = '(targetattr != "userPassword || aci")'
+ ACI_ALLOW = '(version 3.0; acl "Enable anonymous access";allow (read, search, compare)'
+ ACI_SUBJECT = '(userdn = "ldap:///anyone");)'
+ ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT
+ o_1 = Organization(inst, retval.suffix)
+ o_1.set('aci', ACI_BODY)
+
+ return retval
+
+
@pytest.fixture(scope="module")
def create_user(topology_st, request):
"""User for binding operation"""
@@ -71,8 +121,10 @@ def create_user(topology_st, request):
def fin():
log.info('Deleting user simplepaged_test')
- user.delete()
- socket.sethostname(OLD_HOSTNAME)
+ if not DEBUGGING:
+ user.delete()
+ if os.getuid() == 0:
+ socket.sethostname(OLD_HOSTNAME)
request.addfinalizer(fin)
@@ -175,7 +227,7 @@ def change_conf_attr(topology_st, suffix, attr_name, attr_value):
return attr_value_bck
-def paged_search(conn, suffix, controls, search_flt, searchreq_attrlist):
+def paged_search(conn, suffix, controls, search_flt, searchreq_attrlist, abandon_rate=0):
"""Search at the DEFAULT_SUFFIX with ldap.SCOPE_SUBTREE
using Simple Paged Control(should the first item in the
list controls.
@@ -195,9 +247,16 @@ def paged_search(conn, suffix, controls, search_flt, searchreq_attrlist):
req_pr_ctrl.size,
str(controls)))
msgid = conn.search_ext(suffix, ldap.SCOPE_SUBTREE, search_flt, searchreq_attrlist, serverctrls=controls)
+ log.info('Getting page %d' % (pages,))
while True:
- log.info('Getting page %d' % (pages,))
- rtype, rdata, rmsgid, rctrls = conn.result3(msgid)
+ try:
+ rtype, rdata, rmsgid, rctrls = conn.result3(msgid, timeout=0.001)
+ except ldap.TIMEOUT:
+ if pages > 0 and abandon_rate>0 and randrange(100)<abandon_rate:
+ conn.abandon(msgid)
+ log.info('Paged result search is abandonned.')
+ return all_results
+ continue
log.debug('Data: {}'.format(rdata))
all_results.extend(rdata)
pages += 1
@@ -217,6 +276,7 @@ def paged_search(conn, suffix, controls, search_flt, searchreq_attrlist):
break # No more pages available
else:
break
+ log.info('Getting page %d' % (pages,))
assert not pctrls[0].cookie
return all_results
@@ -1191,6 +1251,39 @@ def test_maxsimplepaged_per_conn_failure(topology_st, create_user, conf_attr_val
del_users(users_list)
change_conf_attr(topology_st, DN_CONFIG, 'nsslapd-maxsimplepaged-per-conn', max_per_con_bck)
+
+def test_search_stress_abandon(create_40k_users, create_user):
+ """Verify that search with a simple paged results control
+ returns all entries it should without errors.
+
+ :id: e154b24a-83d6-11ee-90d1-482ae39447e5
+ :customerscenario: True
+ :feature: Simple paged results
+ :setup: Standalone instance, test user for binding,
+ 40K users in a second backend
+ :steps:
+ 1. Bind as test user
+ 2. Loops a number of times doing:
+ - search through added users with a simple paged control
+ - randomly abandoning the search after a few ms.
+ :expectedresults:
+ 1. Bind should be successful
+ 2. The loop should complete successfully.
+ """
+
+ abandon_rate = 10
+ page_size = 500
+ nbloops = 1000
+ search_flt = r'(uid=*)'
+ searchreq_attrlist = ['dn', 'sn']
+ log.info('Set user bind %s ' % create_user)
+ conn = create_user.bind(TEST_USER_PWD)
+ for idx in range(nbloops):
+ req_ctrl = SimplePagedResultsControl(True, size=page_size, cookie='')
+ # If the issue #5984 is not fixed the server crashs and the paged search fails with ldap.SERVER_DOWN exception
+ paged_search(conn, create_40k_users.suffix, [req_ctrl], search_flt, searchreq_attrlist, abandon_rate=abandon_rate)
+
+
if __name__ == '__main__':
# Run isolated
# -s for DEBUG mode
diff --git a/ldap/servers/slapd/abandon.c b/ldap/servers/slapd/abandon.c
index 26a2e7bf8..964d28836 100644
--- a/ldap/servers/slapd/abandon.c
+++ b/ldap/servers/slapd/abandon.c
@@ -38,6 +38,12 @@ do_abandon(Slapi_PBlock *pb)
Connection *pb_conn = NULL;
Operation *pb_op = NULL;
Operation *o;
+ /* Keep a copy of some data because o may vanish once conn is unlocked */
+ struct {
+ struct timespec hr_time_end;
+ int nentries;
+ int opid;
+ } o_copy;
slapi_pblock_get(pb, SLAPI_OPERATION, &pb_op);
slapi_pblock_get(pb, SLAPI_CONNECTION, &pb_conn);
@@ -90,8 +96,12 @@ do_abandon(Slapi_PBlock *pb)
pthread_mutex_lock(&(pb_conn->c_mutex));
for (o = pb_conn->c_ops; o != NULL; o = o->o_next) {
- if (o->o_msgid == id && o != pb_op)
+ if (o->o_msgid == id && o != pb_op) {
+ slapi_operation_time_elapsed(o, &o_copy.hr_time_end);
+ o_copy.nentries = o->o_results.r.r_search.nentries;
+ o_copy.opid = o->o_opid;
break;
+ }
}
if (o != NULL) {
@@ -130,7 +140,8 @@ do_abandon(Slapi_PBlock *pb)
slapi_log_err(SLAPI_LOG_TRACE, "do_abandon", "op not found\n");
}
- if (0 == pagedresults_free_one_msgid_nolock(pb_conn, id)) {
+ pthread_mutex_unlock(&(pb_conn->c_mutex));
+ if (0 == pagedresults_free_one_msgid(pb_conn, id, pageresult_lock_get_addr(pb_conn))) {
slapi_log_access(LDAP_DEBUG_STATS, "conn=%" PRIu64
" op=%d ABANDON targetop=Simple Paged Results msgid=%d\n",
pb_conn->c_connid, pb_op->o_opid, id);
@@ -143,15 +154,11 @@ do_abandon(Slapi_PBlock *pb)
" targetop=SUPPRESSED-BY-PLUGIN msgid=%d\n",
pb_conn->c_connid, pb_op->o_opid, id);
} else {
- struct timespec o_hr_time_end;
- slapi_operation_time_elapsed(o, &o_hr_time_end);
slapi_log_access(LDAP_DEBUG_STATS, "conn=%" PRIu64 " op=%d ABANDON"
" targetop=%d msgid=%d nentries=%d etime=%" PRId64 ".%010" PRId64 "\n",
- pb_conn->c_connid, pb_op->o_opid, o->o_opid, id,
- o->o_results.r.r_search.nentries, (int64_t)o_hr_time_end.tv_sec, (int64_t)o_hr_time_end.tv_nsec);
+ pb_conn->c_connid, pb_op->o_opid, o_copy.opid, id,
+ o_copy.nentries, (int64_t)o_copy.hr_time_end.tv_sec, (int64_t)o_copy.hr_time_end.tv_nsec);
}
-
- pthread_mutex_unlock(&(pb_conn->c_mutex));
/*
* Wake up the persistent searches, so they
* can notice if they've been abandoned.
diff --git a/ldap/servers/slapd/opshared.c b/ldap/servers/slapd/opshared.c
index a842d4249..f77043afa 100644
--- a/ldap/servers/slapd/opshared.c
+++ b/ldap/servers/slapd/opshared.c
@@ -921,9 +921,7 @@ op_shared_search(Slapi_PBlock *pb, int send_result)
next_be = NULL; /* to break the loop */
if (operation->o_status & SLAPI_OP_STATUS_ABANDONED) {
/* It turned out this search was abandoned. */
- pthread_mutex_lock(pagedresults_mutex);
- pagedresults_free_one_msgid_nolock(pb_conn, operation->o_msgid);
- pthread_mutex_unlock(pagedresults_mutex);
+ pagedresults_free_one_msgid(pb_conn, operation->o_msgid, pagedresults_mutex);
/* paged-results-request was abandoned; making an empty cookie. */
pagedresults_set_response_control(pb, 0, estimate, -1, pr_idx);
send_ldap_result(pb, 0, NULL, "Simple Paged Results Search abandoned", 0, NULL);
diff --git a/ldap/servers/slapd/pagedresults.c b/ldap/servers/slapd/pagedresults.c
index fc15f6bec..9959c927e 100644
--- a/ldap/servers/slapd/pagedresults.c
+++ b/ldap/servers/slapd/pagedresults.c
@@ -34,6 +34,10 @@ pageresult_lock_cleanup()
slapi_ch_free((void**)&lock_hash);
}
+/* Beware to the lock order with c_mutex:
+ * c_mutex is sometime locked while holding pageresult_lock
+ * ==> Do not lock pageresult_lock when holing c_mutex
+ */
pthread_mutex_t *
pageresult_lock_get_addr(Connection *conn)
{
@@ -350,7 +354,7 @@ pagedresults_free_one(Connection *conn, Operation *op, int index)
* Used for abandoning - pageresult_lock_get_addr(conn) is already locked in do_abandone.
*/
int
-pagedresults_free_one_msgid_nolock(Connection *conn, ber_int_t msgid)
+pagedresults_free_one_msgid(Connection *conn, ber_int_t msgid, pthread_mutex_t *mutex)
{
int rc = -1;
int i;
@@ -361,6 +365,7 @@ pagedresults_free_one_msgid_nolock(Connection *conn, ber_int_t msgid)
} else {
slapi_log_err(SLAPI_LOG_TRACE,
"pagedresults_free_one_msgid_nolock", "=> msgid=%d\n", msgid);
+ pthread_mutex_lock(mutex);
for (i = 0; i < conn->c_pagedresults.prl_maxlen; i++) {
if (conn->c_pagedresults.prl_list[i].pr_msgid == msgid) {
PagedResults *prp = conn->c_pagedresults.prl_list + i;
@@ -375,6 +380,7 @@ pagedresults_free_one_msgid_nolock(Connection *conn, ber_int_t msgid)
break;
}
}
+ pthread_mutex_unlock(mutex);
slapi_log_err(SLAPI_LOG_TRACE,
"pagedresults_free_one_msgid_nolock", "<= %d\n", rc);
}
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
index c7389fe2e..e8adbc254 100644
--- a/ldap/servers/slapd/proto-slap.h
+++ b/ldap/servers/slapd/proto-slap.h
@@ -1614,7 +1614,7 @@ int pagedresults_is_timedout_nolock(Connection *conn);
int pagedresults_reset_timedout_nolock(Connection *conn);
int pagedresults_in_use_nolock(Connection *conn);
int pagedresults_free_one(Connection *conn, Operation *op, int index);
-int pagedresults_free_one_msgid_nolock(Connection *conn, ber_int_t msgid);
+int pagedresults_free_one_msgid(Connection *conn, ber_int_t msgid, pthread_mutex_t *mutex);
int op_is_pagedresults(Operation *op);
int pagedresults_cleanup_all(Connection *conn, int needlock);
void op_set_pagedresults(Operation *op);
diff --git a/src/lib389/lib389/__init__.py b/src/lib389/lib389/__init__.py
index 7590ec442..6a941dbe7 100644
--- a/src/lib389/lib389/__init__.py
+++ b/src/lib389/lib389/__init__.py
@@ -1048,6 +1048,24 @@ class DirSrv(SimpleLDAPObject, object):
self.state = DIRSRV_STATE_OFFLINE
+ def dump_errorlog(self):
+ '''
+ Its logs all errors messages within the error log that occured
+ after the last startup.
+ '''
+ if os.path.isfile(self.errlog):
+ lines = []
+ with open(self.errlog, 'r') as file:
+ for line in file:
+ if "starting up" in line:
+ lines = []
+ for key in ( 'DEBUG', 'INFO', 'NOTICE', 'WARN' ):
+ if key in line:
+ lines.append(line)
+ break
+ for line in lines:
+ self.log.error(line)
+
def start(self, timeout=120, post_open=True):
'''
It starts an instance and rebind it. Its final state after rebind
@@ -1071,7 +1089,13 @@ class DirSrv(SimpleLDAPObject, object):
if self.with_systemd():
self.log.debug("systemd status -> True")
# Do systemd things here ...
- subprocess.check_output(["systemctl", "start", "dirsrv@%s" % self.serverid], stderr=subprocess.STDOUT)
+ try:
+ subprocess.check_output(["systemctl", "start", "dirsrv@%s" % self.serverid], stderr=subprocess.STDOUT)
+ except subprocess.CalledProcessError as e:
+ self.dump_errorlog()
+ self.log.error('Failed to start dirsrv@%s: "%s"' % (self.serverid, e.output.decode()))
+ self.log.error(e)
+ raise ValueError('Failed to start DS')
else:
self.log.debug("systemd status -> False")
# Start the process.
@@ -1095,6 +1119,7 @@ class DirSrv(SimpleLDAPObject, object):
self.log.debug("DEBUG: starting with %s" % cmd)
output = subprocess.check_output(*cmd, env=env, stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as e:
+ self.dump_errorlog()
self.log.error('Failed to start ns-slapd: "%s"' % e.output.decode())
self.log.error(e)
raise ValueError('Failed to start DS')
--
2.41.0

@ -1,91 +0,0 @@
From 382003bde3db1c82989dfe25c5a1ddb457473186 Mon Sep 17 00:00:00 2001
From: progier389 <progier@redhat.com>
Date: Tue, 21 Nov 2023 11:57:44 +0100
Subject: [PATCH] Issue 5984 - Crash when paged result search are abandoned -
fix2 (#5987)
Chasing several rabbits at the same time is a bad idea !
and I mixed branches and unwillingly pushed one commit for #5980 in #5984
just before the PR #5985 merge ! -:(
Hopefully it does not break anything but just logs some useless crap if instance fails to starts.
Anyway This commit reverts the change about __init.py
and also do a minor code cleanup (removed a trailing space) in abandon.c
Issue #5984
Reviewed by: @tbordaz Thanks !
(cherry picked from commit df7dd8320424f7ab616c9ad8086a6874ff8bf859)
---
ldap/servers/slapd/abandon.c | 2 +-
src/lib389/lib389/__init__.py | 27 +--------------------------
2 files changed, 2 insertions(+), 27 deletions(-)
diff --git a/ldap/servers/slapd/abandon.c b/ldap/servers/slapd/abandon.c
index 964d28836..2dd1ee320 100644
--- a/ldap/servers/slapd/abandon.c
+++ b/ldap/servers/slapd/abandon.c
@@ -43,7 +43,7 @@ do_abandon(Slapi_PBlock *pb)
struct timespec hr_time_end;
int nentries;
int opid;
- } o_copy;
+ } o_copy;
slapi_pblock_get(pb, SLAPI_OPERATION, &pb_op);
slapi_pblock_get(pb, SLAPI_CONNECTION, &pb_conn);
diff --git a/src/lib389/lib389/__init__.py b/src/lib389/lib389/__init__.py
index 6a941dbe7..7590ec442 100644
--- a/src/lib389/lib389/__init__.py
+++ b/src/lib389/lib389/__init__.py
@@ -1048,24 +1048,6 @@ class DirSrv(SimpleLDAPObject, object):
self.state = DIRSRV_STATE_OFFLINE
- def dump_errorlog(self):
- '''
- Its logs all errors messages within the error log that occured
- after the last startup.
- '''
- if os.path.isfile(self.errlog):
- lines = []
- with open(self.errlog, 'r') as file:
- for line in file:
- if "starting up" in line:
- lines = []
- for key in ( 'DEBUG', 'INFO', 'NOTICE', 'WARN' ):
- if key in line:
- lines.append(line)
- break
- for line in lines:
- self.log.error(line)
-
def start(self, timeout=120, post_open=True):
'''
It starts an instance and rebind it. Its final state after rebind
@@ -1089,13 +1071,7 @@ class DirSrv(SimpleLDAPObject, object):
if self.with_systemd():
self.log.debug("systemd status -> True")
# Do systemd things here ...
- try:
- subprocess.check_output(["systemctl", "start", "dirsrv@%s" % self.serverid], stderr=subprocess.STDOUT)
- except subprocess.CalledProcessError as e:
- self.dump_errorlog()
- self.log.error('Failed to start dirsrv@%s: "%s"' % (self.serverid, e.output.decode()))
- self.log.error(e)
- raise ValueError('Failed to start DS')
+ subprocess.check_output(["systemctl", "start", "dirsrv@%s" % self.serverid], stderr=subprocess.STDOUT)
else:
self.log.debug("systemd status -> False")
# Start the process.
@@ -1119,7 +1095,6 @@ class DirSrv(SimpleLDAPObject, object):
self.log.debug("DEBUG: starting with %s" % cmd)
output = subprocess.check_output(*cmd, env=env, stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as e:
- self.dump_errorlog()
self.log.error('Failed to start ns-slapd: "%s"' % e.output.decode())
self.log.error(e)
raise ValueError('Failed to start DS')
--
2.41.0

@ -46,9 +46,9 @@ ExcludeArch: i686
Summary: 389 Directory Server (base) Summary: 389 Directory Server (base)
Name: 389-ds-base Name: 389-ds-base
Version: 2.3.6 Version: 2.4.5
Release: 5%{?dist} Release: 5%{?dist}
License: GPLv3+ and MIT and ASL 2.0 License: GPLv3+ and (ASL 2.0 or MIT) and MIT and (Unlicense or MIT) and (0BSD or MIT or ASL 2.0) and MPLv2.0 and ASL 2.0 and (MIT or zlib or ASL 2.0) and ((MIT or ASL 2.0) and Unicode-DFS-2016) and (ASL 2.0 or Boost) and BSD
URL: https://www.port389.org URL: https://www.port389.org
Conflicts: selinux-policy-base < 3.9.8 Conflicts: selinux-policy-base < 3.9.8
Conflicts: freeipa-server < 4.0.3 Conflicts: freeipa-server < 4.0.3
@ -58,94 +58,92 @@ Obsoletes: %{name}-legacy-tools-debuginfo < 1.4.4.6
Provides: ldif2ldbm >= 0 Provides: ldif2ldbm >= 0
##### Bundled cargo crates list - START ##### ##### Bundled cargo crates list - START #####
Provides: bundled(crate(addr2line)) = 0.20.0 Provides: bundled(crate(addr2line)) = 0.21.0
Provides: bundled(crate(adler)) = 1.0.2 Provides: bundled(crate(adler)) = 1.0.2
Provides: bundled(crate(ahash)) = 0.7.6 Provides: bundled(crate(ahash)) = 0.7.7
Provides: bundled(crate(ansi_term)) = 0.12.1 Provides: bundled(crate(ansi_term)) = 0.12.1
Provides: bundled(crate(atty)) = 0.2.14 Provides: bundled(crate(atty)) = 0.2.14
Provides: bundled(crate(autocfg)) = 1.1.0 Provides: bundled(crate(autocfg)) = 1.1.0
Provides: bundled(crate(backtrace)) = 0.3.68 Provides: bundled(crate(backtrace)) = 0.3.69
Provides: bundled(crate(base64)) = 0.13.1 Provides: bundled(crate(base64)) = 0.13.1
Provides: bundled(crate(bitflags)) = 1.3.2 Provides: bundled(crate(bitflags)) = 1.3.2
Provides: bundled(crate(bitflags)) = 2.3.3 Provides: bundled(crate(bitflags)) = 2.4.1
Provides: bundled(crate(byteorder)) = 1.4.3 Provides: bundled(crate(byteorder)) = 1.5.0
Provides: bundled(crate(cbindgen)) = 0.9.1 Provides: bundled(crate(cbindgen)) = 0.9.1
Provides: bundled(crate(cc)) = 1.0.82 Provides: bundled(crate(cc)) = 1.0.83
Provides: bundled(crate(cfg-if)) = 1.0.0 Provides: bundled(crate(cfg-if)) = 1.0.0
Provides: bundled(crate(clap)) = 2.34.0 Provides: bundled(crate(clap)) = 2.34.0
Provides: bundled(crate(concread)) = 0.2.21 Provides: bundled(crate(concread)) = 0.2.21
Provides: bundled(crate(crossbeam)) = 0.8.2 Provides: bundled(crate(crossbeam)) = 0.8.4
Provides: bundled(crate(crossbeam-channel)) = 0.5.8 Provides: bundled(crate(crossbeam-channel)) = 0.5.11
Provides: bundled(crate(crossbeam-deque)) = 0.8.3 Provides: bundled(crate(crossbeam-deque)) = 0.8.5
Provides: bundled(crate(crossbeam-epoch)) = 0.9.15 Provides: bundled(crate(crossbeam-epoch)) = 0.9.18
Provides: bundled(crate(crossbeam-queue)) = 0.3.8 Provides: bundled(crate(crossbeam-queue)) = 0.3.11
Provides: bundled(crate(crossbeam-utils)) = 0.8.16 Provides: bundled(crate(crossbeam-utils)) = 0.8.19
Provides: bundled(crate(entryuuid)) = 0.1.0 Provides: bundled(crate(entryuuid)) = 0.1.0
Provides: bundled(crate(entryuuid_syntax)) = 0.1.0 Provides: bundled(crate(entryuuid_syntax)) = 0.1.0
Provides: bundled(crate(errno)) = 0.3.2 Provides: bundled(crate(errno)) = 0.3.8
Provides: bundled(crate(errno-dragonfly)) = 0.1.2 Provides: bundled(crate(fastrand)) = 2.0.1
Provides: bundled(crate(fastrand)) = 2.0.0
Provides: bundled(crate(fernet)) = 0.1.4 Provides: bundled(crate(fernet)) = 0.1.4
Provides: bundled(crate(foreign-types)) = 0.3.2 Provides: bundled(crate(foreign-types)) = 0.3.2
Provides: bundled(crate(foreign-types-shared)) = 0.1.1 Provides: bundled(crate(foreign-types-shared)) = 0.1.1
Provides: bundled(crate(getrandom)) = 0.2.10 Provides: bundled(crate(getrandom)) = 0.2.12
Provides: bundled(crate(gimli)) = 0.27.3 Provides: bundled(crate(gimli)) = 0.28.1
Provides: bundled(crate(hashbrown)) = 0.12.3 Provides: bundled(crate(hashbrown)) = 0.12.3
Provides: bundled(crate(hermit-abi)) = 0.1.19 Provides: bundled(crate(hermit-abi)) = 0.1.19
Provides: bundled(crate(instant)) = 0.1.12 Provides: bundled(crate(instant)) = 0.1.12
Provides: bundled(crate(itoa)) = 1.0.9 Provides: bundled(crate(itoa)) = 1.0.10
Provides: bundled(crate(jobserver)) = 0.1.26 Provides: bundled(crate(jobserver)) = 0.1.27
Provides: bundled(crate(libc)) = 0.2.147 Provides: bundled(crate(libc)) = 0.2.152
Provides: bundled(crate(librnsslapd)) = 0.1.0 Provides: bundled(crate(librnsslapd)) = 0.1.0
Provides: bundled(crate(librslapd)) = 0.1.0 Provides: bundled(crate(librslapd)) = 0.1.0
Provides: bundled(crate(linux-raw-sys)) = 0.4.5 Provides: bundled(crate(linux-raw-sys)) = 0.4.12
Provides: bundled(crate(lock_api)) = 0.4.10 Provides: bundled(crate(lock_api)) = 0.4.11
Provides: bundled(crate(log)) = 0.4.19 Provides: bundled(crate(log)) = 0.4.20
Provides: bundled(crate(lru)) = 0.7.8 Provides: bundled(crate(lru)) = 0.7.8
Provides: bundled(crate(memchr)) = 2.5.0 Provides: bundled(crate(memchr)) = 2.7.1
Provides: bundled(crate(memoffset)) = 0.9.0
Provides: bundled(crate(miniz_oxide)) = 0.7.1 Provides: bundled(crate(miniz_oxide)) = 0.7.1
Provides: bundled(crate(object)) = 0.31.1 Provides: bundled(crate(object)) = 0.32.2
Provides: bundled(crate(once_cell)) = 1.18.0 Provides: bundled(crate(once_cell)) = 1.19.0
Provides: bundled(crate(openssl)) = 0.10.56 Provides: bundled(crate(openssl)) = 0.10.62
Provides: bundled(crate(openssl-macros)) = 0.1.1 Provides: bundled(crate(openssl-macros)) = 0.1.1
Provides: bundled(crate(openssl-sys)) = 0.9.91 Provides: bundled(crate(openssl-sys)) = 0.9.98
Provides: bundled(crate(parking_lot)) = 0.11.2 Provides: bundled(crate(parking_lot)) = 0.11.2
Provides: bundled(crate(parking_lot_core)) = 0.8.6 Provides: bundled(crate(parking_lot_core)) = 0.8.6
Provides: bundled(crate(paste)) = 0.1.18 Provides: bundled(crate(paste)) = 0.1.18
Provides: bundled(crate(paste-impl)) = 0.1.18 Provides: bundled(crate(paste-impl)) = 0.1.18
Provides: bundled(crate(pin-project-lite)) = 0.2.11 Provides: bundled(crate(pin-project-lite)) = 0.2.13
Provides: bundled(crate(pkg-config)) = 0.3.27 Provides: bundled(crate(pkg-config)) = 0.3.28
Provides: bundled(crate(ppv-lite86)) = 0.2.17 Provides: bundled(crate(ppv-lite86)) = 0.2.17
Provides: bundled(crate(proc-macro-hack)) = 0.5.20+deprecated Provides: bundled(crate(proc-macro-hack)) = 0.5.20+deprecated
Provides: bundled(crate(proc-macro2)) = 1.0.66 Provides: bundled(crate(proc-macro2)) = 1.0.76
Provides: bundled(crate(pwdchan)) = 0.1.0 Provides: bundled(crate(pwdchan)) = 0.1.0
Provides: bundled(crate(quote)) = 1.0.32 Provides: bundled(crate(quote)) = 1.0.35
Provides: bundled(crate(rand)) = 0.8.5 Provides: bundled(crate(rand)) = 0.8.5
Provides: bundled(crate(rand_chacha)) = 0.3.1 Provides: bundled(crate(rand_chacha)) = 0.3.1
Provides: bundled(crate(rand_core)) = 0.6.4 Provides: bundled(crate(rand_core)) = 0.6.4
Provides: bundled(crate(redox_syscall)) = 0.2.16 Provides: bundled(crate(redox_syscall)) = 0.2.16
Provides: bundled(crate(redox_syscall)) = 0.3.5 Provides: bundled(crate(redox_syscall)) = 0.4.1
Provides: bundled(crate(rustc-demangle)) = 0.1.23 Provides: bundled(crate(rustc-demangle)) = 0.1.23
Provides: bundled(crate(rustix)) = 0.38.7 Provides: bundled(crate(rustix)) = 0.38.28
Provides: bundled(crate(ryu)) = 1.0.15 Provides: bundled(crate(ryu)) = 1.0.16
Provides: bundled(crate(scopeguard)) = 1.2.0 Provides: bundled(crate(scopeguard)) = 1.2.0
Provides: bundled(crate(serde)) = 1.0.183 Provides: bundled(crate(serde)) = 1.0.195
Provides: bundled(crate(serde_derive)) = 1.0.183 Provides: bundled(crate(serde_derive)) = 1.0.195
Provides: bundled(crate(serde_json)) = 1.0.104 Provides: bundled(crate(serde_json)) = 1.0.111
Provides: bundled(crate(slapd)) = 0.1.0 Provides: bundled(crate(slapd)) = 0.1.0
Provides: bundled(crate(slapi_r_plugin)) = 0.1.0 Provides: bundled(crate(slapi_r_plugin)) = 0.1.0
Provides: bundled(crate(smallvec)) = 1.11.0 Provides: bundled(crate(smallvec)) = 1.11.2
Provides: bundled(crate(strsim)) = 0.8.0 Provides: bundled(crate(strsim)) = 0.8.0
Provides: bundled(crate(syn)) = 1.0.109 Provides: bundled(crate(syn)) = 1.0.109
Provides: bundled(crate(syn)) = 2.0.28 Provides: bundled(crate(syn)) = 2.0.48
Provides: bundled(crate(tempfile)) = 3.7.1 Provides: bundled(crate(tempfile)) = 3.9.0
Provides: bundled(crate(textwrap)) = 0.11.0 Provides: bundled(crate(textwrap)) = 0.11.0
Provides: bundled(crate(tokio)) = 1.29.1 Provides: bundled(crate(tokio)) = 1.35.1
Provides: bundled(crate(tokio-macros)) = 2.1.0 Provides: bundled(crate(tokio-macros)) = 2.2.0
Provides: bundled(crate(toml)) = 0.5.11 Provides: bundled(crate(toml)) = 0.5.11
Provides: bundled(crate(unicode-ident)) = 1.0.11 Provides: bundled(crate(unicode-ident)) = 1.0.12
Provides: bundled(crate(unicode-width)) = 0.1.10 Provides: bundled(crate(unicode-width)) = 0.1.11
Provides: bundled(crate(uuid)) = 0.8.2 Provides: bundled(crate(uuid)) = 0.8.2
Provides: bundled(crate(vcpkg)) = 0.2.15 Provides: bundled(crate(vcpkg)) = 0.2.15
Provides: bundled(crate(vec_map)) = 0.8.2 Provides: bundled(crate(vec_map)) = 0.8.2
@ -154,16 +152,16 @@ Provides: bundled(crate(wasi)) = 0.11.0+wasi_snapshot_preview1
Provides: bundled(crate(winapi)) = 0.3.9 Provides: bundled(crate(winapi)) = 0.3.9
Provides: bundled(crate(winapi-i686-pc-windows-gnu)) = 0.4.0 Provides: bundled(crate(winapi-i686-pc-windows-gnu)) = 0.4.0
Provides: bundled(crate(winapi-x86_64-pc-windows-gnu)) = 0.4.0 Provides: bundled(crate(winapi-x86_64-pc-windows-gnu)) = 0.4.0
Provides: bundled(crate(windows-sys)) = 0.48.0 Provides: bundled(crate(windows-sys)) = 0.52.0
Provides: bundled(crate(windows-targets)) = 0.48.1 Provides: bundled(crate(windows-targets)) = 0.52.0
Provides: bundled(crate(windows_aarch64_gnullvm)) = 0.48.0 Provides: bundled(crate(windows_aarch64_gnullvm)) = 0.52.0
Provides: bundled(crate(windows_aarch64_msvc)) = 0.48.0 Provides: bundled(crate(windows_aarch64_msvc)) = 0.52.0
Provides: bundled(crate(windows_i686_gnu)) = 0.48.0 Provides: bundled(crate(windows_i686_gnu)) = 0.52.0
Provides: bundled(crate(windows_i686_msvc)) = 0.48.0 Provides: bundled(crate(windows_i686_msvc)) = 0.52.0
Provides: bundled(crate(windows_x86_64_gnu)) = 0.48.0 Provides: bundled(crate(windows_x86_64_gnu)) = 0.52.0
Provides: bundled(crate(windows_x86_64_gnullvm)) = 0.48.0 Provides: bundled(crate(windows_x86_64_gnullvm)) = 0.52.0
Provides: bundled(crate(windows_x86_64_msvc)) = 0.48.0 Provides: bundled(crate(windows_x86_64_msvc)) = 0.52.0
Provides: bundled(crate(zeroize)) = 1.6.0 Provides: bundled(crate(zeroize)) = 1.7.0
Provides: bundled(crate(zeroize_derive)) = 1.4.2 Provides: bundled(crate(zeroize_derive)) = 1.4.2
##### Bundled cargo crates list - END ##### ##### Bundled cargo crates list - END #####
@ -294,12 +292,8 @@ Source2: %{name}-devel.README
Source3: https://github.com/jemalloc/%{jemalloc_name}/releases/download/%{jemalloc_ver}/%{jemalloc_name}-%{jemalloc_ver}.tar.bz2 Source3: https://github.com/jemalloc/%{jemalloc_name}/releases/download/%{jemalloc_ver}/%{jemalloc_name}-%{jemalloc_ver}.tar.bz2
%endif %endif
Source4: 389-ds-base.sysusers Source4: 389-ds-base.sysusers
Patch0: 0001-Issue-3527-Support-HAProxy-and-Instance-on-the-same-.patch
Patch1: 0001-Issue-5848-Fix-condition-and-add-a-CI-test-5916.patch
Patch2: 0002-Issue-5909-Multi-listener-hang-with-20k-connections-.patch
Patch3: 0002-issue-5924-ASAN-server-build-crash-when-looping-open.patch
Patch4: 0003-Issue-5984-Crash-when-paged-result-search-are-abando.patch
Patch5: 0004-Issue-5984-Crash-when-paged-result-search-are-abando.patch
%description %description
389 Directory Server is an LDAPv3 compliant server. The base package includes 389 Directory Server is an LDAPv3 compliant server. The base package includes
@ -484,6 +478,7 @@ autoreconf -fiv
# lib389 # lib389
make src/lib389/setup.py
pushd ./src/lib389 pushd ./src/lib389
%py3_build %py3_build
popd popd
@ -741,15 +736,38 @@ exit 0
%endif %endif
%changelog %changelog
* Fri Dec 01 2023 Thierry Bordaz <tbordaz@redhat.com> - 2.3.6-5 * Mon Mar 18 2024 Simon Pichugin <spichugi@redhat.com> - 2.4.5-5
- Bump version to 2.3.6-5 - Bump version to 2.4.5-5
- Resolves: RHEL-17178 - Crash on open/close connections - Rebuild for exception phase
- Resolves: RHEL-16833 - ns-slapd crash in slapi_attr_basetype
* Thu Mar 14 2024 Simon Pichugin <spichugi@redhat.com> - 2.4.5-4
* Thu Nov 30 2023 Thierry Bordaz <tbordaz@redhat.com> - 2.3.6-4 - Bump version to 2.4.5-4
- Bump version to 2.3.6-4 - Resolves: RHEL-5130 - RFE Add PROXY protocol support to 389-ds-base via confiuration item - similar to Postfix
- Resolves: RHEL-17178 - Crash on open/close connections
- Resolves: RHEL-16833 - ns-slapd crash in slapi_attr_basetype * Fri Jan 19 2024 Viktor Ashirov <vashirov@redhat.com> - 2.4.5-3
- Bump version to 2.4.5-3
- Fix License tag
* Mon Jan 15 2024 James Chapman <jachapma@redhat.com> - 2.4.5-2
- Bump version to 2.4.5-2
- Resolves: RHEL-15907 - Rebase 389-ds-base in RHEL 9.4
- Resolves: RHEL-5142 - RFE Disable Transparent Huge Pages when using large caches
- Resolves: RHEL-5130 - RFE Add PROXY protocol support to 389-ds-base via confiuration item - similar to Postfix
- Resolves: RHEL-5133 - RFE Provide a history for 'LastLoginTime'
- Resolves: RHEL-16984 - RFE inChain Matching Rule
* Fri Jan 12 2024 James Chapman <jachapma@redhat.com> - 2.4.5-1
- Bump version to 2.4.5-1
- Resolves: RHEL-15907 - Rebase 389-ds-base in RHEL 9.4
- Resolves: RHEL-5142 - RFE Disable Transparent Huge Pages when using large caches
- Resolves: RHEL-5130 - RFE Add PROXY protocol support to 389-ds-base via confiuration item - similar to Postfix
- Resolves: RHEL-5133 - RFE Provide a history for 'LastLoginTime'
- Resolves: RHEL-16984 - RFE inChain Matching Rule
* Tue Nov 21 2023 James Chapman <jachapma@redhat.com> - 2.4.4-1
- Bump version to 2.4.4-1
- Resolves: RHEL-15907 - Rebase 389-ds-base-2.4 in RHEL 9.4
- Resolves: RHEL-16830 - ns-slapd crash in slapi_attr_basetype
* Thu Sep 7 2023 Simon Pichugin <spichugi@redhat.com> - 2.3.6-3 * Thu Sep 7 2023 Simon Pichugin <spichugi@redhat.com> - 2.3.6-3
- Bump version to 2.3.6-3 - Bump version to 2.3.6-3

Loading…
Cancel
Save