From d69b2bbde07fee646f9e03e76d0000c56e4b142c Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Nov 03 2020 11:59:28 +0000 Subject: import 389-ds-base-1.4.3.8-5.module+el8.3.0+7569+08175a8a --- diff --git a/.389-ds-base.metadata b/.389-ds-base.metadata index c4b1e1e..af43295 100644 --- a/.389-ds-base.metadata +++ b/.389-ds-base.metadata @@ -1,2 +1,2 @@ -fcf4e095176c048550be8838df112b8d247f34db SOURCES/389-ds-base-1.4.2.4.tar.bz2 +7e651c99e43265c678c98ac2d8e31b8c48522be6 SOURCES/389-ds-base-1.4.3.8.tar.bz2 9e06b5cc57fd185379d007696da153893cf73e30 SOURCES/jemalloc-5.2.1.tar.bz2 diff --git a/.gitignore b/.gitignore index 8e144dc..470a59e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ -SOURCES/389-ds-base-1.4.2.4.tar.bz2 +SOURCES/389-ds-base-1.4.3.8.tar.bz2 SOURCES/jemalloc-5.2.1.tar.bz2 diff --git a/SOURCES/0000-Issue-50712-Version-comparison-doesn-t-work-correctl.patch b/SOURCES/0000-Issue-50712-Version-comparison-doesn-t-work-correctl.patch deleted file mode 100644 index 5398ed4..0000000 --- a/SOURCES/0000-Issue-50712-Version-comparison-doesn-t-work-correctl.patch +++ /dev/null @@ -1,161 +0,0 @@ -From b823da0b0e3f02a7972ebec4e714877d2ee2170e Mon Sep 17 00:00:00 2001 -From: Viktor Ashirov -Date: Fri, 15 Nov 2019 11:55:07 +0100 -Subject: [PATCH 1/2] Issue 50712 - Version comparison doesn't work correctly - on git builds - -Bug Description: -`python3-packaging` is not shipped in RHEL8. But it's bundled with -`setuptools` which is present in all major distributions. - -Fix Description: -Use `pkg_resources` module from `setuptools` which provides needed -functionality, change lib389 and rpm dependencies accordingly. - -Unfortunately, `pkg_resources.parse_version()` returns different -objects for different strings too, so use `LegacyVersion` directly -from `pkg_resources.extern.packaging.version`. - -Fixes: https://pagure.io/389-ds-base/issue/50712 -Relates: https://pagure.io/389-ds-base/issue/50706 ---- - rpm/389-ds-base.spec.in | 2 +- - src/lib389/lib389/tests/utils_test.py | 29 +++++++++++++++++++++++++++ - src/lib389/lib389/utils.py | 11 +++++----- - src/lib389/requirements.txt | 2 +- - src/lib389/setup.py | 2 +- - 5 files changed, 38 insertions(+), 8 deletions(-) - -diff --git a/rpm/389-ds-base.spec.in b/rpm/389-ds-base.spec.in -index e60b0f3c5..6f4a1e1a9 100644 ---- a/rpm/389-ds-base.spec.in -+++ b/rpm/389-ds-base.spec.in -@@ -130,7 +130,6 @@ BuildRequires: python%{python3_pkgversion}-argcomplete - BuildRequires: python%{python3_pkgversion}-argparse-manpage - BuildRequires: python%{python3_pkgversion}-policycoreutils - BuildRequires: python%{python3_pkgversion}-libselinux --BuildRequires: python%{python3_pkgversion}-packaging - - # For cockpit - BuildRequires: rsync -@@ -303,6 +302,7 @@ Requires: python%{python3_pkgversion}-pyasn1-modules - Requires: python%{python3_pkgversion}-dateutil - Requires: python%{python3_pkgversion}-argcomplete - Requires: python%{python3_pkgversion}-libselinux -+Requires: python%{python3_pkgversion}-setuptools - %{?python_provide:%python_provide python%{python3_pkgversion}-lib389} - - %description -n python%{python3_pkgversion}-lib389 -diff --git a/src/lib389/lib389/tests/utils_test.py b/src/lib389/lib389/tests/utils_test.py -index 5378066b6..a696eb5c9 100644 ---- a/src/lib389/lib389/tests/utils_test.py -+++ b/src/lib389/lib389/tests/utils_test.py -@@ -145,6 +145,35 @@ def test_get_log_data(data): - assert display_log_data(before) == after - - -+@pytest.mark.parametrize('ds_ver, cmp_ver', [ -+ ('1.3.1', '1.3.2'), -+ ('1.3.1', '1.3.10'), -+ ('1.3.2', '1.3.10'), -+ ('1.3.9', ('1.3.10', '1.4.2.0')), -+ ('1.4.0.1', ('1.3.9', '1.4.1.0', '1.4.2.1')), -+ ('1.4.1', '1.4.2.0-20191115gitbadc0ffee' ), -+]) -+def test_ds_is_older_versions(ds_ver, cmp_ver): -+ if isinstance(cmp_ver, tuple): -+ assert ds_is_related('older', ds_ver, *cmp_ver) -+ else: -+ assert ds_is_related('older', ds_ver, cmp_ver) -+ -+@pytest.mark.parametrize('ds_ver, cmp_ver', [ -+ ('1.3.2', '1.3.1'), -+ ('1.3.10', '1.3.1'), -+ ('1.3.10', '1.3.2'), -+ ('1.3.10', ('1.3.9', '1.4.2.0')), -+ ('1.4.2.1', ('1.3.9', '1.4.0.1', '1.4.2.0')), -+ ('1.4.2.0-20191115gitbadc0ffee', '1.4.1' ), -+]) -+def test_ds_is_newer_versions(ds_ver, cmp_ver): -+ if isinstance(cmp_ver, tuple): -+ assert ds_is_related('newer', ds_ver, *cmp_ver) -+ else: -+ assert ds_is_related('newer', ds_ver, cmp_ver) -+ -+ - if __name__ == "__main__": - CURRENT_FILE = os.path.realpath(__file__) - pytest.main("-s -v %s" % CURRENT_FILE) -diff --git a/src/lib389/lib389/utils.py b/src/lib389/lib389/utils.py -index 3234cdccb..b9eacfdea 100644 ---- a/src/lib389/lib389/utils.py -+++ b/src/lib389/lib389/utils.py -@@ -40,7 +40,7 @@ import shlex - import operator - import subprocess - import math --from packaging.version import LegacyVersion -+from pkg_resources.extern.packaging.version import LegacyVersion - from socket import getfqdn - from ldapurl import LDAPUrl - from contextlib import closing -@@ -1067,13 +1067,12 @@ def get_ds_version(): - return p.version - - --def ds_is_related(relation, *ver): -+def ds_is_related(relation, ds_ver, *ver): - """ - Return a result of a comparison between the current version of ns-slapd and a provided version. - """ - ops = {'older': operator.lt, - 'newer': operator.ge} -- ds_ver = get_ds_version() - if len(ver) > 1: - for cmp_ver in ver: - if cmp_ver.startswith(ds_ver[:3]): -@@ -1086,14 +1085,16 @@ def ds_is_older(*ver): - """ - Return True if the current version of ns-slapd is older than a provided version - """ -- return ds_is_related('older', *ver) -+ ds_ver = get_ds_version() -+ return ds_is_related('older', ds_ver, *ver) - - - def ds_is_newer(*ver): - """ - Return True if the current version of ns-slapd is newer than a provided version - """ -- return ds_is_related('newer', *ver) -+ ds_ver = get_ds_version() -+ return ds_is_related('newer', ds_ver, *ver) - - - def gentime_to_datetime(gentime): -diff --git a/src/lib389/requirements.txt b/src/lib389/requirements.txt -index 5cce1d04b..eb2475f3b 100644 ---- a/src/lib389/requirements.txt -+++ b/src/lib389/requirements.txt -@@ -6,4 +6,4 @@ six - argcomplete - argparse-manpage - python-ldap --packaging -+setuptools -diff --git a/src/lib389/setup.py b/src/lib389/setup.py -index f2e404333..056173936 100644 ---- a/src/lib389/setup.py -+++ b/src/lib389/setup.py -@@ -82,7 +82,7 @@ setup( - 'argcomplete', - 'argparse-manpage', - 'python-ldap', -- 'packaging', -+ 'setuptools', - ], - - cmdclass={ --- -2.21.0 - diff --git a/SOURCES/0001-Issue-50499-Fix-npm-audit-issues.patch b/SOURCES/0001-Issue-50499-Fix-npm-audit-issues.patch deleted file mode 100644 index 842237e..0000000 --- a/SOURCES/0001-Issue-50499-Fix-npm-audit-issues.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 00bc5150aeb5e0d7676d0c578cd64a3977ae5d85 Mon Sep 17 00:00:00 2001 -From: Mark Reynolds -Date: Fri, 15 Nov 2019 11:04:14 -0500 -Subject: [PATCH 2/2] Issue 50499 - Fix npm audit issues - -Description: Updated npm handlebars package to 4.5.2 - -relates: https://pagure.io/389-ds-base/issue/50499 ---- - src/cockpit/389-console/package-lock.json | 12 ++++++------ - src/cockpit/389-console/package.json | 2 +- - 2 files changed, 7 insertions(+), 7 deletions(-) - -diff --git a/src/cockpit/389-console/package-lock.json b/src/cockpit/389-console/package-lock.json -index 7207e92a0..f61e48985 100644 ---- a/src/cockpit/389-console/package-lock.json -+++ b/src/cockpit/389-console/package-lock.json -@@ -6053,9 +6053,9 @@ - "integrity": "sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw==" - }, - "handlebars": { -- "version": "4.5.1", -- "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.1.tgz", -- "integrity": "sha512-C29UoFzHe9yM61lOsIlCE5/mQVGrnIOrOq7maQl76L7tYPCgC1og0Ajt6uWnX4ZTxBPnjw+CUvawphwCfJgUnA==", -+ "version": "4.5.2", -+ "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.2.tgz", -+ "integrity": "sha512-29Zxv/cynYB7mkT1rVWQnV7mGX6v7H/miQ6dbEpYTKq5eJBN7PsRB+ViYJlcT6JINTSu4dVB9kOqEun78h6Exg==", - "requires": { - "neo-async": "^2.6.0", - "optimist": "^0.6.1", -@@ -6075,9 +6075,9 @@ - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "uglify-js": { -- "version": "3.6.7", -- "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.7.tgz", -- "integrity": "sha512-4sXQDzmdnoXiO+xvmTzQsfIiwrjUCSA95rSP4SEd8tDb51W2TiDOlL76Hl+Kw0Ie42PSItCW8/t6pBNCF2R48A==", -+ "version": "3.6.9", -+ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.9.tgz", -+ "integrity": "sha512-pcnnhaoG6RtrvHJ1dFncAe8Od6Nuy30oaJ82ts6//sGSXOP5UjBMEthiProjXmMNHOfd93sqlkztifFMcb+4yw==", - "optional": true, - "requires": { - "commander": "~2.20.3", -diff --git a/src/cockpit/389-console/package.json b/src/cockpit/389-console/package.json -index ffa429d83..fb2449675 100644 ---- a/src/cockpit/389-console/package.json -+++ b/src/cockpit/389-console/package.json -@@ -52,7 +52,7 @@ - "@patternfly/react-core": "^3.58.1", - "bootstrap": "^4.3.1", - "file-loader": "^4.1.0", -- "handlebars": "^4.4.5", -+ "handlebars": "^4.5.2", - "node-sass": "4.12.0", - "patternfly": "^3.59.3", - "patternfly-react": "^2.34.3", --- -2.21.0 - diff --git a/SOURCES/0001-Issue-51076-prevent-unnecessarily-duplication-of-the.patch b/SOURCES/0001-Issue-51076-prevent-unnecessarily-duplication-of-the.patch new file mode 100644 index 0000000..cba92a9 --- /dev/null +++ b/SOURCES/0001-Issue-51076-prevent-unnecessarily-duplication-of-the.patch @@ -0,0 +1,43 @@ +From 97ecf0190f264a2d87750bc2d26ebf011542e3e1 Mon Sep 17 00:00:00 2001 +From: Mark Reynolds +Date: Fri, 8 May 2020 10:52:43 -0400 +Subject: [PATCH 01/12] Issue 51076 - prevent unnecessarily duplication of the + target entry + +Bug Description: For any update operation the MEP plugin was calling + slapi_search_internal_get_entry() which duplicates + the entry it returns. In this case the entry is just + read from and discarded, but this entry is already + in the pblock (the PRE OP ENTRY). + +Fix Description: Just grab the PRE OP ENTRY from the pblock and use + that to read the attribute values from. This saves + two entry duplications for every update operation + from MEP. + +fixes: https://pagure.io/389-ds-base/issue/51076 + +Reviewed by: tbordaz & firstyear(Thanks!!) +--- + ldap/servers/plugins/mep/mep.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/ldap/servers/plugins/mep/mep.c b/ldap/servers/plugins/mep/mep.c +index ca9a64b3b..401d95e3a 100644 +--- a/ldap/servers/plugins/mep/mep.c ++++ b/ldap/servers/plugins/mep/mep.c +@@ -2165,9 +2165,8 @@ mep_pre_op(Slapi_PBlock *pb, int modop) + if (e && free_entry) { + slapi_entry_free(e); + } +- +- slapi_search_internal_get_entry(sdn, 0, &e, mep_get_plugin_id()); +- free_entry = 1; ++ slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &e); ++ free_entry = 0; + } + + if (e && mep_is_managed_entry(e)) { +-- +2.26.2 + diff --git a/SOURCES/0002-Issue-50701-Add-additional-healthchecks-to-dsconf.patch b/SOURCES/0002-Issue-50701-Add-additional-healthchecks-to-dsconf.patch deleted file mode 100644 index dd043a5..0000000 --- a/SOURCES/0002-Issue-50701-Add-additional-healthchecks-to-dsconf.patch +++ /dev/null @@ -1,1395 +0,0 @@ -From 09326585a5561480d44beb508af2cb1da52bfff6 Mon Sep 17 00:00:00 2001 -From: Mark Reynolds -Date: Mon, 18 Nov 2019 12:02:39 -0500 -Subject: [PATCH] Issue 50701 - Add additional healthchecks to dsconf - -Description: New checks and several design changes have been implemented - - Design changes: - - Moved to a "yield" design, where a lint function can return multiple results - - Revised the lint report so it's easier to read and distiguish between multiple - errors - - Revised most lint errors to include CLI examples on how to fix the issue - - New Checks: - - Check TLS certs for expired/expiring - - Add RI plugin checks for missing indexes for RI member attributes - - Added Disk Space check - - Add Virtual Attribute index check - - Add replication agmt status check - - Add replication conflict entry check - - File System checks (/etc/revolv.conf, and NSS pin files) - - Replication changelog trimming - -relates: https://pagure.io/389-ds-base/issue/50701 - -Reviewed by: firstyear, mhonek, tbordaz, and spichugi (Thanks!!!!) - -add suggested changes - -Improved the replication agreement health checks to use the new -state levels (red, amber, green), and we use that to generate -different reports. - -Also improved report example autofilling of the values, so the exact -commands can be copied and pasted. - -Added a changelog trimming check as well. - -Updated the help section to wanr that htehealthcheck feature should -only be run on the local instance - -Moved healthcheck to dsctl and added file permission checks ---- - src/lib389/cli/dsconf | 2 - - src/lib389/cli/dsctl | 10 +- - src/lib389/lib389/_mapped_object.py | 6 +- - src/lib389/lib389/agreement.py | 67 +++++-- - src/lib389/lib389/backend.py | 122 +++++++++--- - src/lib389/lib389/cli_base/dsrc.py | 6 +- - src/lib389/lib389/cli_conf/health.py | 62 ------ - src/lib389/lib389/cli_ctl/health.py | 123 ++++++++++++ - src/lib389/lib389/config.py | 18 +- - src/lib389/lib389/dseldif.py | 43 +++- - src/lib389/lib389/lint.py | 287 +++++++++++++++++++++++---- - src/lib389/lib389/monitor.py | 14 ++ - src/lib389/lib389/nss_ssl.py | 35 +++- - src/lib389/lib389/plugins.py | 46 ++++- - src/lib389/lib389/properties.py | 1 + - src/lib389/lib389/replica.py | 70 +++++++ - 16 files changed, 746 insertions(+), 166 deletions(-) - delete mode 100644 src/lib389/lib389/cli_conf/health.py - create mode 100644 src/lib389/lib389/cli_ctl/health.py - -diff --git a/src/lib389/cli/dsconf b/src/lib389/cli/dsconf -index 6e3ef19c3..5143756c8 100755 ---- a/src/lib389/cli/dsconf -+++ b/src/lib389/cli/dsconf -@@ -21,7 +21,6 @@ from lib389.cli_conf import backend as cli_backend - from lib389.cli_conf import directory_manager as cli_directory_manager - from lib389.cli_conf import plugin as cli_plugin - from lib389.cli_conf import schema as cli_schema --from lib389.cli_conf import health as cli_health - from lib389.cli_conf import monitor as cli_monitor - from lib389.cli_conf import saslmappings as cli_sasl - from lib389.cli_conf import pwpolicy as cli_pwpolicy -@@ -80,7 +79,6 @@ cli_backup.create_parser(subparsers) - cli_chaining.create_parser(subparsers) - cli_config.create_parser(subparsers) - cli_directory_manager.create_parsers(subparsers) --cli_health.create_parser(subparsers) - cli_monitor.create_parser(subparsers) - cli_plugin.create_parser(subparsers) - cli_pwpolicy.create_parser(subparsers) -diff --git a/src/lib389/cli/dsctl b/src/lib389/cli/dsctl -index 31e906b7d..8b86629ac 100755 ---- a/src/lib389/cli/dsctl -+++ b/src/lib389/cli/dsctl -@@ -16,14 +16,17 @@ import sys - import signal - import os - from lib389.utils import get_instance_list --from lib389.cli_base import _get_arg, setup_script_logger, disconnect_instance - from lib389 import DirSrv - from lib389.cli_ctl import instance as cli_instance - from lib389.cli_ctl import dbtasks as cli_dbtasks --from lib389.cli_base import disconnect_instance, setup_script_logger --from lib389.cli_base import format_error_to_dict - from lib389.cli_ctl import tls as cli_tls -+from lib389.cli_ctl import health as cli_health - from lib389.cli_ctl.instance import instance_remove_all -+from lib389.cli_base import ( -+ _get_arg, -+ disconnect_instance, -+ setup_script_logger, -+ format_error_to_dict) - from lib389._constants import DSRC_CONTAINER - - parser = argparse.ArgumentParser() -@@ -54,6 +57,7 @@ if not os.path.exists(DSRC_CONTAINER): - cli_instance.create_parser(subparsers) - cli_dbtasks.create_parser(subparsers) - cli_tls.create_parser(subparsers) -+cli_health.create_parser(subparsers) - - argcomplete.autocomplete(parser) - -diff --git a/src/lib389/lib389/_mapped_object.py b/src/lib389/lib389/_mapped_object.py -index e331b3b27..4da112d25 100644 ---- a/src/lib389/lib389/_mapped_object.py -+++ b/src/lib389/lib389/_mapped_object.py -@@ -978,9 +978,9 @@ class DSLdapObject(DSLogging): - return None - results = [] - for fn in self._lint_functions: -- result = fn() -- if result: -- results.append(result) -+ for result in fn(): -+ if result is not None: -+ results.append(result) - return results - - -diff --git a/src/lib389/lib389/agreement.py b/src/lib389/lib389/agreement.py -index a0d4597ec..93fd72895 100644 ---- a/src/lib389/lib389/agreement.py -+++ b/src/lib389/lib389/agreement.py -@@ -105,6 +105,9 @@ class Agreement(DSLdapObject): - time.sleep(2) - return (done, error) - -+ def get_name(self): -+ return self.get_attr_val_utf8_l('cn') -+ - def get_agmt_maxcsn(self): - """Get the agreement maxcsn from the database RUV entry - :returns: CSN string if found, otherwise None is returned -@@ -202,7 +205,7 @@ class Agreement(DSLdapObject): - consumer.close() - return result_msg - -- def get_agmt_status(self, binddn=None, bindpw=None): -+ def get_agmt_status(self, binddn=None, bindpw=None, return_json=False): - """Return the status message - :param binddn: Specifies a specific bind DN to use when contacting the remote consumer - :type binddn: str -@@ -211,33 +214,55 @@ class Agreement(DSLdapObject): - :returns: A status message about the replication agreement - """ - status = "Unknown" -- -+ con_maxcsn = "Unknown" - try: - agmt_maxcsn = self.get_agmt_maxcsn() -+ agmt_status = json.loads(self.get_attr_val_utf8_l(AGMT_UPDATE_STATUS_JSON)) - if agmt_maxcsn is not None: -- con_maxcsn = self.get_consumer_maxcsn(binddn=binddn, bindpw=bindpw) -- if con_maxcsn: -- if agmt_maxcsn == con_maxcsn: -- status = "In Synchronization" -- else: -- # Not in sync - attempt to discover the cause -- repl_msg = "Unknown" -- if self.get_attr_val_utf8_l(AGMT_UPDATE_IN_PROGRESS) == 'true': -- # Replication is on going - this is normal -- repl_msg = "Replication still in progress" -- elif "can't contact ldap" in \ -- self.get_attr_val_utf8_l(AGMT_UPDATE_STATUS): -- # Consumer is down -- repl_msg = "Consumer can not be contacted" -- -- status = ("Not in Synchronization: supplier " + -- "(%s) consumer (%s) Reason(%s)" % -- (agmt_maxcsn, con_maxcsn, repl_msg)) -+ try: -+ con_maxcsn = self.get_consumer_maxcsn(binddn=binddn, bindpw=bindpw) -+ if con_maxcsn: -+ if agmt_maxcsn == con_maxcsn: -+ if return_json: -+ return json.dumps({ -+ 'msg': "In Synchronization", -+ 'agmt_maxcsn': agmt_maxcsn, -+ 'con_maxcsn': con_maxcsn, -+ 'state': agmt_status['state'], -+ 'reason': agmt_status['message'] -+ }) -+ else: -+ return "In Synchronization" -+ except: -+ pass -+ else: -+ agmt_maxcsn = "Unknown" -+ -+ # Not in sync - attempt to discover the cause -+ repl_msg = agmt_status['message'] -+ if self.get_attr_val_utf8_l(AGMT_UPDATE_IN_PROGRESS) == 'true': -+ # Replication is on going - this is normal -+ repl_msg = "Replication still in progress" -+ elif "can't contact ldap" in agmt_status['message']: -+ # Consumer is down -+ repl_msg = "Consumer can not be contacted" -+ -+ if return_json: -+ return json.dumps({ -+ 'msg': "Not in Synchronization", -+ 'agmt_maxcsn': agmt_maxcsn, -+ 'con_maxcsn': con_maxcsn, -+ 'state': agmt_status['state'], -+ 'reason': repl_msg -+ }) -+ else: -+ return ("Not in Synchronization: supplier " + -+ "(%s) consumer (%s) State (%s) Reason (%s)" % -+ (agmt_maxcsn, con_maxcsn, agmt_status['state'], repl_msg)) - except ldap.INVALID_CREDENTIALS as e: - raise(e) - except ldap.LDAPError as e: - raise ValueError(str(e)) -- return status - - def get_lag_time(self, suffix, agmt_name, binddn=None, bindpw=None): - """Get the lag time between the supplier and the consumer -diff --git a/src/lib389/lib389/backend.py b/src/lib389/lib389/backend.py -index 62fd0ae94..ac2af021c 100644 ---- a/src/lib389/lib389/backend.py -+++ b/src/lib389/lib389/backend.py -@@ -7,6 +7,7 @@ - # --- END COPYRIGHT BLOCK --- - - from datetime import datetime -+import copy - import ldap - from lib389._constants import * - from lib389.properties import * -@@ -19,6 +20,8 @@ from lib389._mapped_object import DSLdapObjects, DSLdapObject - from lib389.mappingTree import MappingTrees - from lib389.exceptions import NoSuchEntryError, InvalidArgumentError - from lib389.replica import Replicas -+from lib389.cos import (CosTemplates, CosIndirectDefinitions, -+ CosPointerDefinitions, CosClassicDefinitions) - - # We need to be a factor to the backend monitor - from lib389.monitor import MonitorBackend -@@ -30,7 +33,7 @@ from lib389.encrypted_attributes import EncryptedAttr, EncryptedAttrs - # This is for sample entry creation. - from lib389.configurations import get_sample_entries - --from lib389.lint import DSBLE0001 -+from lib389.lint import DSBLE0001, DSBLE0002, DSBLE0003, DSVIRTLE0001 - - - class BackendLegacy(object): -@@ -410,10 +413,92 @@ class Backend(DSLdapObject): - self._must_attributes = ['nsslapd-suffix', 'cn'] - self._create_objectclasses = ['top', 'extensibleObject', BACKEND_OBJECTCLASS_VALUE] - self._protected = False -- self._lint_functions = [self._lint_mappingtree] -+ self._lint_functions = [self._lint_mappingtree, self._lint_search, self._lint_virt_attrs] - # Check if a mapping tree for this suffix exists. - self._mts = MappingTrees(self._instance) - -+ def _lint_virt_attrs(self): -+ """Check if any virtual attribute are incorrectly indexed""" -+ indexes = self.get_indexes() -+ suffix = self.get_attr_val_utf8('nsslapd-suffix') -+ -+ # First check nsrole -+ try: -+ indexes.get('nsrole') -+ report = copy.deepcopy(DSVIRTLE0001) -+ report['detail'] = report['detail'].replace('ATTR', 'nsrole') -+ report['fix'] = report['fix'].replace('ATTR', 'nsrole') -+ report['fix'] = report['fix'].replace('SUFFIX', suffix) -+ report['fix'] = report['fix'].replace('YOUR_INSTANCE', self._instance.serverid) -+ report['items'].append(suffix) -+ report['items'].append('nsrole') -+ yield report -+ except: -+ pass -+ -+ # Check COS next -+ for cosDefType in [CosIndirectDefinitions, CosPointerDefinitions, CosClassicDefinitions]: -+ defs = cosDefType(self._instance, self._dn).list() -+ for cosDef in defs: -+ attrs = cosDef.get_attr_val_utf8_l("cosAttribute").split() -+ for attr in attrs: -+ if attr in ["default", "override", "operational", "operational-default", "merge-schemes"]: -+ # We are at the end, just break out -+ break -+ try: -+ indexes.get(attr) -+ # If we got here there is an index (bad) -+ report = copy.deepcopy(DSVIRTLE0001) -+ report['detail'] = report['detail'].replace('ATTR', attr) -+ report['fix'] = report['fix'].replace('ATTR', attr) -+ report['fix'] = report['fix'].replace('SUFFIX', suffix) -+ report['fix'] = report['fix'].replace('YOUR_INSTANCE', self._instance.serverid) -+ report['items'].append(suffix) -+ report['items'].append("Class Of Service (COS)") -+ report['items'].append("cosAttribute: " + attr) -+ yield report -+ except: -+ # this is what we hope for -+ pass -+ -+ def _lint_search(self): -+ """Perform a search and make sure an entry is accessible -+ """ -+ dn = self.get_attr_val_utf8('nsslapd-suffix') -+ suffix = DSLdapObject(self._instance, dn=dn) -+ try: -+ suffix.get_attr_val('objectclass') -+ except ldap.NO_SUCH_OBJECT: -+ # backend root entry not created yet -+ DSBLE0003['items'] = [dn, ] -+ yield DSBLE0003 -+ except ldap.LDAPError as e: -+ # Some other error -+ DSBLE0002['detail'] = DSBLE0002['detail'].replace('ERROR', str(e)) -+ DSBLE0002['items'] = [dn, ] -+ yield DSBLE0002 -+ -+ def _lint_mappingtree(self): -+ """Backend lint -+ -+ This should check for: -+ * missing mapping tree entries for the backend -+ * missing indices if we are local and have log access? -+ """ -+ -+ # Check for the missing mapping tree. -+ suffix = self.get_attr_val_utf8('nsslapd-suffix') -+ bename = self.get_attr_val_bytes('cn') -+ try: -+ mt = self._mts.get(suffix) -+ if mt.get_attr_val_bytes('nsslapd-backend') != bename and mt.get_attr_val('nsslapd-state') != ensure_bytes('backend'): -+ raise ldap.NO_SUCH_OBJECT("We have a matching suffix, but not a backend or correct database name.") -+ except ldap.NO_SUCH_OBJECT: -+ result = DSBLE0001 -+ result['items'] = [bename, ] -+ yield result -+ return None -+ - def create_sample_entries(self, version): - """Creates sample entries under nsslapd-suffix value - -@@ -552,27 +637,6 @@ class Backend(DSLdapObject): - # Now remove our children, this is all ldbm config - self._instance.delete_branch_s(self._dn, ldap.SCOPE_SUBTREE) - -- def _lint_mappingtree(self): -- """Backend lint -- -- This should check for: -- * missing mapping tree entries for the backend -- * missing indices if we are local and have log access? -- """ -- -- # Check for the missing mapping tree. -- suffix = self.get_attr_val_utf8('nsslapd-suffix') -- bename = self.get_attr_val_bytes('cn') -- try: -- mt = self._mts.get(suffix) -- if mt.get_attr_val_bytes('nsslapd-backend') != bename and mt.get_attr_val('nsslapd-state') != ensure_bytes('backend'): -- raise ldap.NO_SUCH_OBJECT("We have a matching suffix, but not a backend or correct database name.") -- except ldap.NO_SUCH_OBJECT: -- result = DSBLE0001 -- result['items'] = [bename, ] -- return result -- return None -- - def get_suffix(self): - return self.get_attr_val_utf8_l('nsslapd-suffix') - -@@ -753,6 +817,18 @@ class Backend(DSLdapObject): - break - return subsuffixes - -+ def get_cos_indirect_defs(self): -+ return CosIndirectDefinitions(self._instance, self._dn).list() -+ -+ def get_cos_pointer_defs(self): -+ return CosPointerDefinitions(self._instance, self._dn).list() -+ -+ def get_cos_classic_defs(self): -+ return CosClassicDefinitions(self._instance, self._dn).list() -+ -+ def get_cos_templates(self): -+ return CosTemplates(self._instance, self._dn).list() -+ - - class Backends(DSLdapObjects): - """DSLdapObjects that represents DN_LDBM base DN -diff --git a/src/lib389/lib389/cli_base/dsrc.py b/src/lib389/lib389/cli_base/dsrc.py -index bbd160e8e..20b240df5 100644 ---- a/src/lib389/lib389/cli_base/dsrc.py -+++ b/src/lib389/lib389/cli_base/dsrc.py -@@ -41,12 +41,15 @@ def dsrc_arg_concat(args, dsrc_inst): - 'uri': args.instance, - 'basedn': args.basedn, - 'binddn': args.binddn, -+ 'bindpw': None, - 'saslmech': None, - 'tls_cacertdir': None, - 'tls_cert': None, - 'tls_key': None, - 'tls_reqcert': ldap.OPT_X_TLS_HARD, - 'starttls': args.starttls, -+ 'prompt': False, -+ 'pwdfile': None, - 'args': {} - } - # Now gather the args -@@ -137,7 +140,8 @@ def dsrc_to_ldap(path, instance_name, log): - else: - dsrc_inst['tls_reqcert'] = ldap.OPT_X_TLS_HARD - dsrc_inst['starttls'] = config.getboolean(instance_name, 'starttls', fallback=False) -- -+ dsrc_inst['pwdfile'] = None -+ dsrc_inst['prompt'] = False - # Now gather the args - dsrc_inst['args'][SER_LDAP_URL] = dsrc_inst['uri'] - dsrc_inst['args'][SER_ROOT_DN] = dsrc_inst['binddn'] -diff --git a/src/lib389/lib389/cli_conf/health.py b/src/lib389/lib389/cli_conf/health.py -deleted file mode 100644 -index 040d85674..000000000 ---- a/src/lib389/lib389/cli_conf/health.py -+++ /dev/null -@@ -1,62 +0,0 @@ --# --- BEGIN COPYRIGHT BLOCK --- --# Copyright (C) 2016 Red Hat, Inc. --# All rights reserved. --# --# License: GPL (version 3 or any later version). --# See LICENSE for details. --# --- END COPYRIGHT BLOCK --- -- --from lib389.backend import Backend, Backends --from lib389.config import Encryption, Config --from lib389 import plugins -- --# These get all instances, then check them all. --CHECK_MANY_OBJECTS = [ -- Backends, --] -- --# These get single instances and check them. --CHECK_OBJECTS = [ -- Config, -- Encryption, -- plugins.ReferentialIntegrityPlugin --] -- -- --def _format_check_output(log, result): -- log.info("==== DS Lint Error: %s ====" % result['dsle']) -- log.info(" Severity: %s " % result['severity']) -- log.info(" Affects:") -- for item in result['items']: -- log.info(" -- %s" % item) -- log.info(" Details:") -- log.info(result['detail']) -- log.info(" Resolution:") -- log.info(result['fix']) -- -- --def health_check_run(inst, basedn, log, args): -- log.info("Beginning lint report, this could take a while ...") -- report = [] -- for lo in CHECK_MANY_OBJECTS: -- log.info("Checking %s ..." % lo.__name__) -- lo_inst = lo(inst) -- for clo in lo_inst.list(): -- result = clo.lint() -- if result is not None: -- report += result -- for lo in CHECK_OBJECTS: -- log.info("Checking %s ..." % lo.__name__) -- lo_inst = lo(inst) -- result = lo_inst.lint() -- if result is not None: -- report += result -- log.info("Healthcheck complete!") -- for item in report: -- _format_check_output(log, item) -- -- --def create_parser(subparsers): -- run_healthcheck_parser = subparsers.add_parser('healthcheck', help="Run a healthcheck report on your Directory Server instance. This is a safe, read only operation.") -- run_healthcheck_parser.set_defaults(func=health_check_run) -- -diff --git a/src/lib389/lib389/cli_ctl/health.py b/src/lib389/lib389/cli_ctl/health.py -new file mode 100644 -index 000000000..d8f3d732b ---- /dev/null -+++ b/src/lib389/lib389/cli_ctl/health.py -@@ -0,0 +1,123 @@ -+# --- BEGIN COPYRIGHT BLOCK --- -+# Copyright (C) 2016 Red Hat, Inc. -+# All rights reserved. -+# -+# License: GPL (version 3 or any later version). -+# See LICENSE for details. -+# --- END COPYRIGHT BLOCK --- -+ -+import json -+from getpass import getpass -+from lib389.cli_base import connect_instance, disconnect_instance, format_error_to_dict -+from lib389.cli_base.dsrc import dsrc_to_ldap, dsrc_arg_concat -+from lib389.backend import Backend, Backends -+from lib389.config import Encryption, Config -+from lib389.monitor import MonitorDiskSpace -+from lib389.replica import Replica, Changelog5 -+from lib389.nss_ssl import NssSsl -+from lib389.dseldif import FSChecks -+from lib389 import plugins -+from lib389._constants import DSRC_HOME -+ -+# These get all instances, then check them all. -+CHECK_MANY_OBJECTS = [ -+ Backends, -+] -+ -+# These get single instances and check them. -+CHECK_OBJECTS = [ -+ Config, -+ Encryption, -+ FSChecks, -+ plugins.ReferentialIntegrityPlugin, -+ MonitorDiskSpace, -+ Replica, -+ Changelog5, -+ NssSsl, -+] -+ -+ -+def _format_check_output(log, result, idx): -+ log.info("\n\n[{}] DS Lint Error: {}".format(idx, result['dsle'])) -+ log.info("-" * 80) -+ log.info("Severity: %s " % result['severity']) -+ log.info("Affects:") -+ for item in result['items']: -+ log.info(" -- %s" % item) -+ log.info("\nDetails:") -+ log.info('-----------') -+ log.info(result['detail']) -+ log.info("\nResolution:") -+ log.info('-----------') -+ log.info(result['fix']) -+ -+ -+def health_check_run(inst, log, args): -+ """Connect to the local server using LDAPI, and perform various health checks -+ """ -+ -+ # update the args for connect_instance() -+ args.basedn = None -+ args.binddn = None -+ args.bindpw = None -+ args.starttls = None -+ args.pwdfile = None -+ args.prompt = False -+ dsrc_inst = dsrc_to_ldap(DSRC_HOME, args.instance, log.getChild('dsrc')) -+ dsrc_inst = dsrc_arg_concat(args, dsrc_inst) -+ try: -+ inst = connect_instance(dsrc_inst=dsrc_inst, verbose=args.verbose, args=args) -+ except Exception as e: -+ raise ValueError('Failed to connect to Directory Server instance: ' + str(e)) -+ -+ if not args.json: -+ log.info("Beginning lint report, this could take a while ...") -+ report = [] -+ for lo in CHECK_MANY_OBJECTS: -+ if not args.json: -+ log.info("Checking %s ..." % lo.__name__) -+ lo_inst = lo(inst) -+ for clo in lo_inst.list(): -+ result = clo.lint() -+ if result is not None: -+ report += result -+ for lo in CHECK_OBJECTS: -+ if not args.json: -+ log.info("Checking %s ..." % lo.__name__) -+ lo_inst = lo(inst) -+ result = lo_inst.lint() -+ if result is not None: -+ report += result -+ if not args.json: -+ log.info("Healthcheck complete.") -+ count = len(report) -+ if count == 0: -+ if not args.json: -+ log.info("No issues found.") -+ else: -+ log.info(json.dumps(report)) -+ else: -+ plural = "" -+ if count > 1: -+ plural = "s" -+ if not args.json: -+ log.info("{} Issue{} found! Generating report ...".format(count, plural)) -+ idx = 1 -+ for item in report: -+ _format_check_output(log, item, idx) -+ idx += 1 -+ log.info('\n\n===== End Of Report ({} Issue{} found) ====='.format(count, plural)) -+ else: -+ log.info(json.dumps(report)) -+ -+ disconnect_instance(inst) -+ -+ -+def create_parser(subparsers): -+ run_healthcheck_parser = subparsers.add_parser('healthcheck', help= -+ "Run a healthcheck report on a local Directory Server instance. This " -+ "is a safe and read-only operation. Do not attempt to run this on a " -+ "remote Directory Server as this tool needs access to local resources, " -+ "otherwise the report may be inaccurate.") -+ run_healthcheck_parser.set_defaults(func=health_check_run) -+ -diff --git a/src/lib389/lib389/config.py b/src/lib389/lib389/config.py -index db5359a68..f71baf2d8 100644 ---- a/src/lib389/lib389/config.py -+++ b/src/lib389/lib389/config.py -@@ -16,6 +16,7 @@ - DirSrv.backend.methodName() - """ - -+import copy - import ldap - from lib389._constants import * - from lib389 import Entry -@@ -199,17 +200,18 @@ class Config(DSLdapObject): - def _lint_hr_timestamp(self): - hr_timestamp = self.get_attr_val('nsslapd-logging-hr-timestamps-enabled') - if ensure_bytes('on') != hr_timestamp: -- return DSCLE0001 -- pass # nsslapd-logging-hr-timestamps-enabled -+ report = copy.deepcopy(DSCLE0001) -+ report['fix'] = report['fix'].replace('YOUR_INSTANCE', self._instance.serverid) -+ yield report - - def _lint_passwordscheme(self): - allowed_schemes = ['SSHA512', 'PBKDF2_SHA256'] - u_password_scheme = self.get_attr_val_utf8('passwordStorageScheme') - u_root_scheme = self.get_attr_val_utf8('nsslapd-rootpwstoragescheme') - if u_root_scheme not in allowed_schemes or u_password_scheme not in allowed_schemes: -- return DSCLE0002 -- return None -- -+ report = copy.deepcopy(DSCLE0002) -+ report['fix'] = report['fix'].replace('YOUR_INSTANCE', self._instance.serverid) -+ yield report - - class Encryption(DSLdapObject): - """ -@@ -237,8 +239,10 @@ class Encryption(DSLdapObject): - def _lint_check_tls_version(self): - tls_min = self.get_attr_val('sslVersionMin') - if tls_min < ensure_bytes('TLS1.1'): -- return DSELE0001 -- return None -+ report = copy.deepcopy(DSELE0001) -+ report['fix'] = report['fix'].replace('YOUR_INSTANCE', self._instance.serverid) -+ yield report -+ yield None - - @property - def ciphers(self): -diff --git a/src/lib389/lib389/dseldif.py b/src/lib389/lib389/dseldif.py -index dfe3b91e2..4155abcdd 100644 ---- a/src/lib389/lib389/dseldif.py -+++ b/src/lib389/lib389/dseldif.py -@@ -1,14 +1,17 @@ - # --- BEGIN COPYRIGHT BLOCK --- --# Copyright (C) 2017 Red Hat, Inc. -+# Copyright (C) 2019 Red Hat, Inc. - # All rights reserved. - # - # License: GPL (version 3 or any later version). - # See LICENSE for details. - # --- END COPYRIGHT BLOCK --- - # -+ -+import copy - import os -+from stat import ST_MODE - from lib389.paths import Paths -- -+from lib389.lint import DSPERMLE0001, DSPERMLE0002 - - class DSEldif(object): - """A class for working with dse.ldif file -@@ -155,3 +158,39 @@ class DSEldif(object): - self._instance.log.debug("During replace operation: {}".format(e)) - self.add(entry_dn, attr, value) - self._update() -+ -+ -+class FSChecks(object): -+ """This is for the healthcheck feature, check commonly used system config files the -+ server uses. This is here for lack of a better place to add this class. -+ """ -+ def __init__(self, dirsrv=None): -+ self.dirsrv = dirsrv -+ self._certdb = self.dirsrv.get_cert_dir() -+ self.ds_files = [ -+ ('/etc/resolv.conf', '644', DSPERMLE0001), -+ (self._certdb + "/pin.txt", '600', DSPERMLE0002), -+ (self._certdb + "/pwdfile.txt", '600', DSPERMLE0002), -+ ] -+ self._lint_functions = [self._lint_file_perms] -+ -+ def lint(self): -+ results = [] -+ for fn in self._lint_functions: -+ for result in fn(): -+ if result is not None: -+ results.append(result) -+ return results -+ -+ def _lint_file_perms(self): -+ # Check file permissions are correct -+ for ds_file in self.ds_files: -+ perms = str(oct(os.stat(ds_file[0])[ST_MODE])[-3:]) -+ if perms != ds_file[1]: -+ report = copy.deepcopy(ds_file[2]) -+ report['items'].append(ds_file[0]) -+ report['detail'] = report['detail'].replace('FILE', ds_file[0]) -+ report['detail'] = report['detail'].replace('PERMS', ds_file[1]) -+ report['fix'] = report['fix'].replace('FILE', ds_file[0]) -+ report['fix'] = report['fix'].replace('PERMS', ds_file[1]) -+ yield report -diff --git a/src/lib389/lib389/lint.py b/src/lib389/lib389/lint.py -index 8c4b4dedc..515711136 100644 ---- a/src/lib389/lib389/lint.py -+++ b/src/lib389/lib389/lint.py -@@ -1,5 +1,5 @@ - # --- BEGIN COPYRIGHT BLOCK --- --# Copyright (C) 2017 Red Hat, Inc. -+# Copyright (C) 2019 Red Hat, Inc. - # All rights reserved. - # - # License: GPL (version 3 or any later version). -@@ -10,12 +10,12 @@ - # as well as some functions to help process them. - - -+# Database checks - DSBLE0001 = { - 'dsle': 'DSBLE0001', - 'severity': 'MEDIUM', - 'items' : [], -- 'detail' : """ --This backend may be missing the correct mapping tree references. Mapping Trees allow -+ 'detail' : """This backend may be missing the correct mapping tree references. Mapping Trees allow - the directory server to determine which backend an operation is routed to in the - abscence of other information. This is extremely important for correct functioning - of LDAP ADD for example. -@@ -31,20 +31,35 @@ objectClass: top - objectClass: extensibleObject - objectClass: nsMappingTree - -- """, -- 'fix' : """ --Either you need to create the mapping tree, or you need to repair the related -+""", -+ 'fix' : """Either you need to create the mapping tree, or you need to repair the related - mapping tree. You will need to do this by hand by editing cn=config, or stopping - the instance and editing dse.ldif. -- """ -+""" - } - -+DSBLE0002 = { -+ 'dsle': 'DSBLE0002', -+ 'severity': 'HIGH', -+ 'items' : [], -+ 'detail' : """Unable to querying the backend. LDAP error (ERROR)""", -+ 'fix' : """Check the server's error and access logs for more information.""" -+} -+ -+DSBLE0003 = { -+ 'dsle': 'DSBLE0002', -+ 'severity': 'LOW', -+ 'items' : [], -+ 'detail' : """The backend database has not been initialized yet""", -+ 'fix' : """You need to import an LDIF file, or create the suffix entry, in order to initialize the database.""" -+} -+ -+# Config checks - DSCLE0001 = { - 'dsle' : 'DSCLE0001', - 'severity' : 'LOW', - 'items': ['cn=config', ], -- 'detail' : """ --nsslapd-logging-hr-timestamps-enabled changes the log format in directory server from -+ 'detail' : """nsslapd-logging-hr-timestamps-enabled changes the log format in directory server from - - [07/Jun/2017:17:15:58 +1000] - -@@ -54,18 +69,18 @@ to - - This actually provides a performance improvement. Additionally, this setting will be - removed in a future release. -- """, -- 'fix' : """ --Set nsslapd-logging-hr-timestamps-enabled to on. -- """ -+""", -+ 'fix' : """Set nsslapd-logging-hr-timestamps-enabled to on. -+You can use 'dsconf' to set this attribute. Here is an example: -+ -+ # dsconf slapd-YOUR_INSTANCE config replace nsslapd-logging-hr-timestamps-enabled=on""" - } - - DSCLE0002 = { - 'dsle': 'DSCLE0002', - 'severity': 'HIGH', - 'items' : ['cn=config', ], -- 'detail' : """ --Password storage schemes in Directory Server define how passwords are hashed via a -+ 'detail' : """Password storage schemes in Directory Server define how passwords are hashed via a - one-way mathematical function for storage. Knowing the hash it is difficult to gain - the input, but knowing the input you can easily compare the hash. - -@@ -79,53 +94,253 @@ for "legacy" support (SSHA512). - - Your configuration does not use these for password storage or the root password storage - scheme. -- """, -- 'fix': """ --Perform a configuration reset of the values: -+""", -+ 'fix': """Perform a configuration reset of the values: - - passwordStorageScheme - nsslapd-rootpwstoragescheme - - IE, stop Directory Server, and in dse.ldif delete these two lines. When Directory Server - is started, they will use the server provided defaults that are secure. -- """ -+ -+You can also use 'dsconf' to replace these values. Here is an example: -+ -+ # dsconf slapd-YOUR_INSTANCE config replace passwordStorageScheme=PBKDF2_SHA256 nsslapd-rootpwstoragescheme=PBKDF2_SHA256""" - } - -+# Security checks - DSELE0001 = { - 'dsle': 'DSELE0001', - 'severity': 'MEDIUM', - 'items' : ['cn=encryption,cn=config', ], -- 'detail': """ --This Directory Server may not be using strong TLS protocol versions. TLS1.0 is known to -+ 'detail': """This Directory Server may not be using strong TLS protocol versions. TLS1.0 is known to - have a number of issues with the protocol. Please see: - - https://tools.ietf.org/html/rfc7457 - --It is advised you set this value to the maximum possible. -- """, -- 'fix' : """ --set cn=encryption,cn=config sslVersionMin to a version greater than TLS1.0 -- """ -+It is advised you set this value to the maximum possible.""", -+ 'fix' : """There are two options for setting the TLS minimum version allowed. You, -+can set "sslVersionMin" in "cn=encryption,cn=config" to a version greater than "TLS1.0" -+You can also use 'dsconf' to set this value. Here is an example: -+ -+ # dsconf slapd-YOUR_INSTANCE security set --tls-protocol-min=TLS1.2 -+ -+You must restart the Directory Server for this change to take effect. -+ -+Or, you can set the system wide crypto policy to FUTURE which will use a higher TLS -+minimum version, but doing this affects the entire system: -+ -+ # update-crypto-policies --set FUTURE""" - } - -+# RI plugin checks - DSRILE0001 = { - 'dsle': 'DSRLE0001', - 'severity': 'LOW', - 'items' : ['cn=referential integrity postoperation,cn=plugins,cn=config', ], -- 'detail': """ --The referential integrity plugin has an asynchronous processing mode. This is controlled by the update-delay flag. -- --When this value is 0, referential integrity plugin processes these changes inside of the operation that modified the entry - ie these are synchronous. -+ 'detail': """The referential integrity plugin has an asynchronous processing mode. -+This is controlled by the update-delay flag. When this value is 0, referential -+integrity plugin processes these changes inside of the operation that modified -+the entry - ie these are synchronous. - - However, when this is > 0, these are performed asynchronously. - --This leads to only having refint enabled on one master in MMR to prevent replication conflicts and loops. -+This leads to only having referint enabled on one master in MMR to prevent replication conflicts and loops. - Additionally, because these are performed in the background these updates may cause spurious update - delays to your server by batching changes rather than smaller updates during sync processing. - --We advise that you set this value to 0, and enable refint on all masters as it provides a more predictable behaviour. -- """, -- 'fix' : """ --Set referint-update-delay to 0. -- """ -+We advise that you set this value to 0, and enable referint on all masters as it provides a more predictable behaviour. -+""", -+ 'fix' : """Set referint-update-delay to 0. -+ -+You can use 'dsconf' to set this value. Here is an example: -+ -+ # dsconf slapd-YOUR_INSTANCE plugin referential-integrity set --update-delay 0 -+ -+You must restart the Directory Server for this change to take effect.""" -+} -+ -+# Note - ATTR and BACKEND are replaced by the reporting function -+DSRILE0002 = { -+ 'dsle': 'DSRLE0002', -+ 'severity': 'HIGH', -+ 'items' : ['cn=referential integrity postoperation,cn=plugins,cn=config'], -+ 'detail': """The referential integrity plugin is configured to use an attribute (ATTR) -+that does not have an "equality" index in backend (BACKEND). -+Failure to have the proper indexing will lead to unindexed searches which -+cause high CPU and can significantly slow the server down.""", -+ 'fix' : """Check the attributes set in "referint-membership-attr" to make sure they have -+an index defined that has at least the equality "eq" index type. You will -+need to reindex the database after adding the missing index type. Here is an -+example using dsconf: -+ -+ # dsconf slapd-YOUR_INSTANCE backend index --attr=ATTR --reindex --index-type=eq BACKEND -+""" -+} -+ -+# Disk Space check. Note - PARTITION is replaced by the calling function -+DSDSLE0001 = { -+ 'dsle': 'DSDSLE0001', -+ 'severity': 'HIGH', -+ 'items' : ['Server', 'cn=config'], -+ 'detail': """The disk partition used by the server (PARTITION), either for the database, the -+configuration files, or the logs is over 90% full. If the partition becomes -+completely filled serious problems can occur with the database or the server's -+stability.""", -+ 'fix' : """Attempt to free up disk space. Also try removing old rotated logs, or disable any -+verbose logging levels that might have been set. You might consider enabling -+the "Disk Monitoring" feature in cn=config to help prevent a disorderly shutdown -+of the server: -+ -+ nsslapd-disk-monitoring: on -+ -+You can use 'dsconf' to set this value. Here is an example: -+ -+ # dsconf slapd-YOUR_INSTANCE config replace nsslapd-disk-monitoring=on -+ -+You must restart the Directory Server for this change to take effect. -+ -+Please see the Administration guide for more information: -+ -+ https://access.redhat.com/documentation/en-us/red_hat_directory_server/10/html/administration_guide/diskmonitoring -+""" -+} -+ -+# Replication check. Note - AGMT and SUFFIX are replaced by the reporting function -+DSREPLLE0001 = { -+ 'dsle': 'DSREPLLE0001', -+ 'severity': 'HIGH', -+ 'items' : ['Replication', 'Agreement'], -+ 'detail': """The replication agreement (AGMT) under "SUFFIX" is not in synchronization.""", -+ 'fix' : """You may need to reinitialize this replication agreement. Please check the errors -+log for more information. If you do need to reinitialize the agreement you can do so -+using dsconf. Here is an example: -+ -+ # dsconf slapd-YOUR_INSTANCE repl-agmt init "AGMT" --suffix SUFFIX""" -+} -+ -+# Note - SUFFIX and COUNT will be replaced by the calling function -+DSREPLLE0002 = { -+ 'dsle': 'DSREPLLE0002', -+ 'severity': 'LOW', -+ 'items' : ['Replication', 'Conflict Entries'], -+ 'detail': """There were COUNT conflict entries found under the replication suffix "SUFFIX". -+Status message: MSG""", -+ 'fix' : """While conflict entries are expected to occur in an MMR environment, they -+should be resolved. In regards to conflict entries there is always the original/counterpart -+entry that has a normal DN, and then the conflict version of that entry. Technically both -+entries are valid, you as the administrator, needs to decide which entry you want to keep. -+First examine/compare both entries to determine which one you want to keep or remove. You -+can use the CLI tool "dsconf" to resolve the conflict. Here is an example: -+ -+ List the conflict entries: -+ -+ # dsconf slapd-YOUR_INSTANCE repl-conflict list dc=example,dc=com -+ -+ Examine conflict entry and its counterpart entry: -+ -+ # dsconf slapd-YOUR_INSTANCE repl-conflict compare -+ -+ Remove conflict entry and keep only the original/counterpart entry: -+ -+ # dsconf slapd-YOUR_INSTANCE repl-conflict remove -+ -+ Replace the original/counterpart entry with the conflict entry: -+ -+ # dsconf slapd-YOUR_INSTANCE repl-conflict swap -+""" -+} -+ -+DSREPLLE0003 = { -+ 'dsle': 'DSREPLLE0003', -+ 'severity': 'MEDIUM', -+ 'items' : ['Replication', 'Agreement'], -+ 'detail': """The replication agreement (AGMT) under "SUFFIX" is not in synchronization. -+Status message: MSG""", -+ 'fix' : """Replication is not in synchronization but it may recover. Continue to -+monitor this agreement.""" -+} -+ -+DSREPLLE0004 = { -+ 'dsle': 'DSREPLLE0004', -+ 'severity': 'MEDIUM', -+ 'items' : ['Replication', 'Agreement'], -+ 'detail': """Failed to get the agreement status for agreement (AGMT) under "SUFFIX". Error (ERROR).""", -+ 'fix' : """None""" -+} -+ -+DSREPLLE0005 = { -+ 'dsle': 'DSREPLLE0005', -+ 'severity': 'MEDIUM', -+ 'items' : ['Replication', 'Agreement'], -+ 'detail': """The replication agreement (AGMT) under "SUFFIX" is not in synchronization, -+because the consumer server is not reachable.""", -+ 'fix' : """Check if the consumer is running, and also check the errors log for more information.""" -+} -+ -+# Replication changelog -+DSCLLE0001 = { -+ 'dsle': 'DSCLLE0001', -+ 'severity': 'LOW', -+ 'items' : ['Replication', 'Changelog'], -+ 'detail': """The replication changelog does have any kind of trimming configured. This will -+lead to the changelog size growing indefinitely.""", -+ 'fix' : """Configure changelog trimming, preferably by setting the maximum age of a changelog -+record. Here is an example: -+ -+ # dsconf slapd-YOUR_INSTANCE replication set-changelog --max-age 30d""" -+} -+ -+# Certificate checks -+DSCERTLE0001 = { -+ 'dsle': 'DSCERTLE0001', -+ 'severity': 'MEDIUM', -+ 'items' : ['Expiring Certificate'], -+ 'detail': """The certificate (CERT) will expire in less than 30 days""", -+ 'fix' : """Renew the certificate before it expires to prevent disruptions with TLS connections.""" -+} -+ -+DSCERTLE0002 = { -+ 'dsle': 'DSCERTLE0002', -+ 'severity': 'HIGH', -+ 'items' : ['Expired Certificate'], -+ 'detail': """The certificate (CERT) has expired""", -+ 'fix' : """Renew or remove the certificate.""" -+} -+ -+# Virtual Attrs & COS. Note - ATTR and SUFFIX are replaced by the reporting function -+DSVIRTLE0001 = { -+ 'dsle': 'DSVIRTLE0001', -+ 'severity': 'HIGH', -+ 'items' : ['Virtual Attributes'], -+ 'detail': """You should not index virtual attributes, and as this will break searches that -+use the attribute in a filter.""", -+ 'fix' : """Remove the index for this attribute from the backend configuration. -+Here is an example using 'dsconf' to remove an index: -+ -+ # dsconf slapd-YOUR_INSTANCE backend index delete --attr ATTR SUFFIX""" -+} -+ -+# File permissions (resolv.conf -+DSPERMLE0001 = { -+ 'dsle': 'DSPERMLE0001', -+ 'severity': 'MEDIUM', -+ 'items' : ['File Permissions'], -+ 'detail': """The file "FILE" does not have the expected permissions (PERMS). This -+can cause issues with replication and chaining.""", -+ 'fix' : """Change the file permissions: -+ -+ # chmod PERMS FILE""" -+} -+ -+# TLS db password/pin files -+DSPERMLE0002 = { -+ 'dsle': 'DSPERMLE0002', -+ 'severity': 'HIGH', -+ 'items' : ['File Permissions'], -+ 'detail': """The file "FILE" does not have the expected permissions (PERMS). The -+security database pin/password files should only be readable by Directory Server user.""", -+ 'fix' : """Change the file permissions: -+ -+ # chmod PERMS FILE""" - } -diff --git a/src/lib389/lib389/monitor.py b/src/lib389/lib389/monitor.py -index 5ca967c64..290cad5e2 100644 ---- a/src/lib389/lib389/monitor.py -+++ b/src/lib389/lib389/monitor.py -@@ -9,6 +9,7 @@ - from lib389._constants import * - from lib389._mapped_object import DSLdapObject - from lib389.utils import (ds_is_older) -+from lib389.lint import DSDSLE0001 - - - class Monitor(DSLdapObject): -@@ -254,6 +255,19 @@ class MonitorDiskSpace(DSLdapObject): - def __init__(self, instance, dn=None): - super(MonitorDiskSpace, self).__init__(instance=instance, dn=dn) - self._dn = "cn=disk space,cn=monitor" -+ self._lint_functions = [self._lint_disk_space] -+ -+ def _lint_disk_space(self): -+ partitions = self.get_attr_vals_utf8_l("dsDisk") -+ for partition in partitions: -+ parts = partition.split() -+ percent = parts[4].split('=')[1].strip('"') -+ if int(percent) >= 90: -+ # this partition is over 90% full, not good -+ report = copy.deepcopy(DSDSLE0001) -+ report['detail'] = report['detail'].replace('PARTITION', parts[0].split('=')[1].strip('"')) -+ report['fix'] = report['fix'].replace('YOUR_INSTANCE', self._instance.serverid) -+ yield report - - def get_disks(self): - """Get an information about partitions which contains a Directory Server data""" -diff --git a/src/lib389/lib389/nss_ssl.py b/src/lib389/lib389/nss_ssl.py -index afe921385..2a7d1637c 100644 ---- a/src/lib389/lib389/nss_ssl.py -+++ b/src/lib389/lib389/nss_ssl.py -@@ -9,6 +9,7 @@ - """Helpers for managing NSS databases in Directory Server - """ - -+import copy - import os - import re - import socket -@@ -17,10 +18,10 @@ import shutil - import logging - # from nss import nss - import subprocess --from datetime import datetime, timedelta -+from datetime import datetime, timedelta, date - from subprocess import check_output - from lib389.passwd import password_generate -- -+from lib389.lint import DSCERTLE0001, DSCERTLE0002 - from lib389.utils import ensure_str, format_cmd_list - import uuid - -@@ -58,6 +59,36 @@ class NssSsl(object): - self.db_files = {"dbm_backend": ["%s/%s" % (self._certdb, f) for f in ("key3.db", "cert8.db", "secmod.db")], - "sql_backend": ["%s/%s" % (self._certdb, f) for f in ("key4.db", "cert9.db", "pkcs11.txt")], - "support": ["%s/%s" % (self._certdb, f) for f in ("noise.txt", PIN_TXT, PWD_TXT)]} -+ self._lint_functions = [self._lint_certificate_expiration,] -+ -+ def lint(self): -+ results = [] -+ for fn in self._lint_functions: -+ for result in fn(): -+ if result is not None: -+ results.append(result) -+ return results -+ -+ def _lint_certificate_expiration(self): -+ """Check all the certificates in the db if they will expire within 30 days -+ or have already expired. -+ """ -+ cert_list = [] -+ all_certs = self._rsa_cert_list() -+ for cert in all_certs: -+ cert_list.append(self.get_cert_details(cert[0])) -+ -+ for cert in cert_list: -+ if date.fromisoformat(cert[3].split()[0]) - date.today() < timedelta(days=0): -+ # Expired -+ report = copy.deepcopy(DSCERTLE0002) -+ report['detail'] = report['detail'].replace('CERT', cert[0]) -+ yield report -+ elif date.fromisoformat(cert[3].split()[0]) - date.today() < timedelta(days=30): -+ # Expiring -+ report = copy.deepcopy(DSCERTLE0001) -+ report['detail'] = report['detail'].replace('CERT', cert[0]) -+ yield report - - def detect_alt_names(self, alt_names=[]): - """Attempt to determine appropriate subject alternate names for a host. -diff --git a/src/lib389/lib389/plugins.py b/src/lib389/lib389/plugins.py -index a8b8985fc..97c5d1d3b 100644 ---- a/src/lib389/lib389/plugins.py -+++ b/src/lib389/lib389/plugins.py -@@ -10,10 +10,9 @@ import collections - import ldap - import copy - import os.path -- - from lib389 import tasks - from lib389._mapped_object import DSLdapObjects, DSLdapObject --from lib389.lint import DSRILE0001 -+from lib389.lint import DSRILE0001, DSRILE0002 - from lib389.utils import ensure_str, ensure_list_bytes - from lib389.schema import Schema - from lib389._constants import DN_PLUGIN -@@ -432,7 +431,7 @@ class ReferentialIntegrityPlugin(Plugin): - 'referint-logfile', - 'referint-membership-attr', - ]) -- self._lint_functions = [self._lint_update_delay] -+ self._lint_functions = [self._lint_update_delay, self._lint_attr_indexes] - - def create(self, rdn=None, properties=None, basedn=None): - """Create an instance of the plugin""" -@@ -448,7 +447,46 @@ class ReferentialIntegrityPlugin(Plugin): - if self.status(): - delay = self.get_attr_val_int("referint-update-delay") - if delay is not None and delay != 0: -- return DSRILE0001 -+ report = copy.deepcopy(DSRILE0001) -+ report['fix'] = report['fix'].replace('YOUR_INSTANCE', self._instance.serverid) -+ yield report -+ -+ def _lint_attr_indexes(self): -+ if self.status(): -+ from lib389.backend import Backends -+ backends = Backends(self._instance).list() -+ for backend in backends: -+ indexes = backend.get_indexes() -+ suffix = backend.get_attr_val_utf8_l('nsslapd-suffix') -+ attrs = self.get_attr_vals_utf8_l("referint-membership-attr") -+ for attr in attrs: -+ report = copy.deepcopy(DSRILE0002) -+ try: -+ index = indexes.get(attr) -+ types = index.get_attr_vals_utf8_l("nsIndexType") -+ valid = False -+ if "eq" in types: -+ valid = True -+ -+ if not valid: -+ report['detail'] = report['detail'].replace('ATTR', attr) -+ report['detail'] = report['detail'].replace('BACKEND', suffix) -+ report['fix'] = report['fix'].replace('ATTR', attr) -+ report['fix'] = report['fix'].replace('BACKEND', suffix) -+ report['fix'] = report['fix'].replace('YOUR_INSTANCE', self._instance.serverid) -+ report['items'].append(suffix) -+ report['items'].append(attr) -+ yield report -+ except: -+ # No index at all, bad -+ report['detail'] = report['detail'].replace('ATTR', attr) -+ report['detail'] = report['detail'].replace('BACKEND', suffix) -+ report['fix'] = report['fix'].replace('ATTR', attr) -+ report['fix'] = report['fix'].replace('BACKEND', suffix) -+ report['fix'] = report['fix'].replace('YOUR_INSTANCE', self._instance.serverid) -+ report['items'].append(suffix) -+ report['items'].append(attr) -+ yield report - - def get_update_delay(self): - """Get referint-update-delay attribute""" -diff --git a/src/lib389/lib389/properties.py b/src/lib389/lib389/properties.py -index d18249d20..9d7ce4161 100644 ---- a/src/lib389/lib389/properties.py -+++ b/src/lib389/lib389/properties.py -@@ -319,6 +319,7 @@ AGMT_UPDATE_START = 'nsds5replicaLastUpdateStart' - AGMT_UPDATE_END = 'nsds5replicaLastUpdateEnd' - AGMT_CHANGES_SINCE_STARTUP = 'nsds5replicaChangesSentSinceStartup' # base64 - AGMT_UPDATE_STATUS = 'nsds5replicaLastUpdateStatus' -+AGMT_UPDATE_STATUS_JSON = 'nsds5replicaLastUpdateStatusJSON' - AGMT_UPDATE_IN_PROGRESS = 'nsds5replicaUpdateInProgress' - AGMT_INIT_START = 'nsds5replicaLastInitStart' - AGMT_INIT_END = 'nsds5replicaLastInitEnd' -diff --git a/src/lib389/lib389/replica.py b/src/lib389/lib389/replica.py -index 7145e86f9..9b84d8f7e 100644 ---- a/src/lib389/lib389/replica.py -+++ b/src/lib389/lib389/replica.py -@@ -15,6 +15,7 @@ import datetime - import logging - import uuid - import json -+import copy - from operator import itemgetter - from itertools import permutations - from lib389._constants import * -@@ -31,6 +32,9 @@ from lib389.idm.domain import Domain - from lib389.idm.group import Groups - from lib389.idm.services import ServiceAccounts - from lib389.idm.organizationalunit import OrganizationalUnits -+from lib389.conflicts import ConflictEntries -+from lib389.lint import (DSREPLLE0001, DSREPLLE0002, DSREPLLE0003, DSREPLLE0004, -+ DSREPLLE0005, DSCLLE0001) - - - class ReplicaLegacy(object): -@@ -1044,6 +1048,19 @@ class Changelog5(DSLdapObject): - 'extensibleobject', - ] - self._protected = False -+ self._lint_functions = [self._lint_cl_trimming] -+ -+ def _lint_cl_trimming(self): -+ """Check that cl trimming is at least defined to prevent unbounded growth""" -+ try: -+ if self.get_attr_val_utf8('nsslapd-changelogmaxentries') is None and \ -+ self.get_attr_val_utf8('nsslapd-changelogmaxage') is None: -+ report = copy.deepcopy(DSCLLE0001) -+ report['fix'] = report['fix'].replace('YOUR_INSTANCE', self._instance.serverid) -+ yield report -+ except: -+ # No changelog -+ pass - - def set_max_entries(self, value): - """Configure the max entries the changelog can hold. -@@ -1102,6 +1119,59 @@ class Replica(DSLdapObject): - self._create_objectclasses.append('extensibleobject') - self._protected = False - self._suffix = None -+ self._lint_functions = [self._lint_agmts_status, self._lint_conflicts] -+ -+ def _lint_agmts_status(self): -+ replicas = Replicas(self._instance).list() -+ for replica in replicas: -+ agmts = replica.get_agreements().list() -+ suffix = replica.get_suffix() -+ for agmt in agmts: -+ try: -+ status = json.loads(agmt.get_agmt_status(return_json=True)) -+ if "Not in Synchronization" in status['msg'] and not "Replication still in progress" in status['reason']: -+ agmt_name = agmt.get_name() -+ if status['state'] == 'red': -+ # Serious error -+ if "Consumer can not be contacted" in status['reason']: -+ report = copy.deepcopy(DSREPLLE0005) -+ report['detail'] = report['detail'].replace('SUFFIX', suffix) -+ report['detail'] = report['detail'].replace('AGMT', agmt_name) -+ yield report -+ else: -+ report = copy.deepcopy(DSREPLLE0001) -+ report['detail'] = report['detail'].replace('SUFFIX', suffix) -+ report['detail'] = report['detail'].replace('AGMT', agmt_name) -+ report['detail'] = report['detail'].replace('MSG', status['reason']) -+ report['fix'] = report['fix'].replace('SUFFIX', suffix) -+ report['fix'] = report['fix'].replace('AGMT', agmt_name) -+ report['fix'] = report['fix'].replace('YOUR_INSTANCE', self._instance.serverid) -+ yield report -+ elif status['state'] == 'amber': -+ # Warning -+ report = copy.deepcopy(DSREPLLE0003) -+ report['detail'] = report['detail'].replace('SUFFIX', suffix) -+ report['detail'] = report['detail'].replace('AGMT', agmt_name) -+ report['detail'] = report['detail'].replace('MSG', status['reason']) -+ yield report -+ except ldap.LDAPError as e: -+ report = copy.deepcopy(DSREPLLE0004) -+ report['detail'] = report['detail'].replace('SUFFIX', suffix) -+ report['detail'] = report['detail'].replace('AGMT', agmt_name) -+ report['detail'] = report['detail'].replace('ERROR', str(e)) -+ yield report -+ -+ def _lint_conflicts(self): -+ replicas = Replicas(self._instance).list() -+ for replica in replicas: -+ conflicts = ConflictEntries(self._instance, replica.get_suffix()).list() -+ suffix = replica.get_suffix() -+ if len(conflicts) > 0: -+ report = copy.deepcopy(DSREPLLE0002) -+ report['detail'] = report['detail'].replace('SUFFIX', suffix) -+ report['detail'] = report['detail'].replace('COUNT', len(conflicts)) -+ report['fix'] = report['fix'].replace('YOUR_INSTANCE', self._instance.serverid) -+ yield report - - def _validate(self, rdn, properties, basedn): - (tdn, str_props) = super(Replica, self)._validate(rdn, properties, basedn) --- -2.21.0 - diff --git a/SOURCES/0002-Ticket-51082-abort-when-a-empty-valueset-is-freed.patch b/SOURCES/0002-Ticket-51082-abort-when-a-empty-valueset-is-freed.patch new file mode 100644 index 0000000..822c8d2 --- /dev/null +++ b/SOURCES/0002-Ticket-51082-abort-when-a-empty-valueset-is-freed.patch @@ -0,0 +1,116 @@ +From 1426f086623404ab2eacb04de7e6414177c0993a Mon Sep 17 00:00:00 2001 +From: Thierry Bordaz +Date: Mon, 11 May 2020 17:11:49 +0200 +Subject: [PATCH 02/12] Ticket 51082 - abort when a empty valueset is freed + +Bug Description: + A large valueset (more than 10 values) manages a sorted array of values. + replication purges old values from a valueset (valueset_array_purge). If it purges all the values + the valueset is freed (slapi_valueset_done). + A problem is that the counter of values, in the valueset, is still reflecting the initial number + of values (before the purge). When the valueset is freed (because empty) a safety checking + detects incoherent values based on the wrong counter. + +Fix Description: + When all the values have been purge reset the counter before freeing the valueset + +https://pagure.io/389-ds-base/issue/51082 + +Reviewed by: Mark Reynolds + +Platforms tested: F30 + +Flag Day: no + +Doc impact: no +--- + .../suites/replication/acceptance_test.py | 57 +++++++++++++++++++ + ldap/servers/slapd/valueset.c | 4 ++ + 2 files changed, 61 insertions(+) + +diff --git a/dirsrvtests/tests/suites/replication/acceptance_test.py b/dirsrvtests/tests/suites/replication/acceptance_test.py +index c8e0a4c93..5009f4e7c 100644 +--- a/dirsrvtests/tests/suites/replication/acceptance_test.py ++++ b/dirsrvtests/tests/suites/replication/acceptance_test.py +@@ -500,6 +500,63 @@ def test_warining_for_invalid_replica(topo_m4): + assert topo_m4.ms["master1"].ds_error_log.match('.*nsds5ReplicaBackoffMax.*10.*invalid.*') + + ++@pytest.mark.ds51082 ++def test_csnpurge_large_valueset(topo_m2): ++ """Test csn generator test ++ ++ :id: 63e2bdb2-0a8f-4660-9465-7b80a9f72a74 ++ :setup: MMR with 2 masters ++ :steps: ++ 1. Create a test_user ++ 2. add a large set of values (more than 10) ++ 3. delete all the values (more than 10) ++ 4. configure the replica to purge those values (purgedelay=5s) ++ 5. Waiting for 6 second ++ 6. do a series of update ++ :expectedresults: ++ 1. Should succeeds ++ 2. Should succeeds ++ 3. Should succeeds ++ 4. Should succeeds ++ 5. Should succeeds ++ 6. Should not crash ++ """ ++ m1 = topo_m2.ms["master2"] ++ ++ test_user = UserAccount(m1, TEST_ENTRY_DN) ++ if test_user.exists(): ++ log.info('Deleting entry {}'.format(TEST_ENTRY_DN)) ++ test_user.delete() ++ test_user.create(properties={ ++ 'uid': TEST_ENTRY_NAME, ++ 'cn': TEST_ENTRY_NAME, ++ 'sn': TEST_ENTRY_NAME, ++ 'userPassword': TEST_ENTRY_NAME, ++ 'uidNumber' : '1000', ++ 'gidNumber' : '2000', ++ 'homeDirectory' : '/home/mmrepl_test', ++ }) ++ ++ # create a large value set so that it is sorted ++ for i in range(1,20): ++ test_user.add('description', 'value {}'.format(str(i))) ++ ++ # delete all values of the valueset ++ for i in range(1,20): ++ test_user.remove('description', 'value {}'.format(str(i))) ++ ++ # set purging delay to 5 second and wait more that 5second ++ replicas = Replicas(m1) ++ replica = replicas.list()[0] ++ log.info('nsds5ReplicaPurgeDelay to 5') ++ replica.set('nsds5ReplicaPurgeDelay', '5') ++ time.sleep(6) ++ ++ # add some new values to the valueset containing entries that should be purged ++ for i in range(21,25): ++ test_user.add('description', 'value {}'.format(str(i))) ++ ++ + if __name__ == '__main__': + # Run isolated + # -s for DEBUG mode +diff --git a/ldap/servers/slapd/valueset.c b/ldap/servers/slapd/valueset.c +index 2af3ee18d..12027ecb8 100644 +--- a/ldap/servers/slapd/valueset.c ++++ b/ldap/servers/slapd/valueset.c +@@ -801,6 +801,10 @@ valueset_array_purge(const Slapi_Attr *a, Slapi_ValueSet *vs, const CSN *csn) + } + } + } else { ++ /* empty valueset - reset the vs->num so that further ++ * checking will not abort ++ */ ++ vs->num = 0; + slapi_valueset_done(vs); + } + +-- +2.26.2 + diff --git a/SOURCES/0003-Issue-50701-Fix-type-in-lint-report.patch b/SOURCES/0003-Issue-50701-Fix-type-in-lint-report.patch deleted file mode 100644 index ac87b47..0000000 --- a/SOURCES/0003-Issue-50701-Fix-type-in-lint-report.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 1f4955d5e09f44f19b96dc671a1462cc43ee29a8 Mon Sep 17 00:00:00 2001 -From: Mark Reynolds -Date: Mon, 25 Nov 2019 17:24:04 -0500 -Subject: [PATCH] Issue 50701 - Fix type in lint report - -Description: Fix typo introduced from the previous commit for 50701 - -relates: https://pagure.io/389-ds-base/issue/50701 - -Reviewed by: firstyear(Thanks!) ---- - src/lib389/lib389/lint.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/lib389/lib389/lint.py b/src/lib389/lib389/lint.py -index 515711136..736dffa14 100644 ---- a/src/lib389/lib389/lint.py -+++ b/src/lib389/lib389/lint.py -@@ -42,7 +42,7 @@ DSBLE0002 = { - 'dsle': 'DSBLE0002', - 'severity': 'HIGH', - 'items' : [], -- 'detail' : """Unable to querying the backend. LDAP error (ERROR)""", -+ 'detail' : """Unable to query the backend. LDAP error (ERROR)""", - 'fix' : """Check the server's error and access logs for more information.""" - } - --- -2.21.0 - diff --git a/SOURCES/0003-Issue-51091-healthcheck-json-report-fails-when-mappi.patch b/SOURCES/0003-Issue-51091-healthcheck-json-report-fails-when-mappi.patch new file mode 100644 index 0000000..b3a1a82 --- /dev/null +++ b/SOURCES/0003-Issue-51091-healthcheck-json-report-fails-when-mappi.patch @@ -0,0 +1,45 @@ +From 7a62e72b81d75ebb844835619ecc97dbf5e21058 Mon Sep 17 00:00:00 2001 +From: Mark Reynolds +Date: Thu, 14 May 2020 09:38:20 -0400 +Subject: [PATCH 03/12] Issue 51091 - healthcheck json report fails when + mapping tree is deleted + +Description: We were passing the bename in bytes and not as a utf8 string. + This caused the json dumping to fail. + +relates: https://pagure.io/389-ds-base/issue/51091 + +Reviewed by: firstyear(Thanks!) +--- + src/lib389/lib389/backend.py | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/lib389/lib389/backend.py b/src/lib389/lib389/backend.py +index e472d3de5..4f752f414 100644 +--- a/src/lib389/lib389/backend.py ++++ b/src/lib389/lib389/backend.py +@@ -11,7 +11,7 @@ import copy + import ldap + from lib389._constants import * + from lib389.properties import * +-from lib389.utils import normalizeDN, ensure_str, ensure_bytes, assert_c ++from lib389.utils import normalizeDN, ensure_str, assert_c + from lib389 import Entry + + # Need to fix this .... +@@ -488,10 +488,10 @@ class Backend(DSLdapObject): + + # Check for the missing mapping tree. + suffix = self.get_attr_val_utf8('nsslapd-suffix') +- bename = self.get_attr_val_bytes('cn') ++ bename = self.get_attr_val_utf8('cn') + try: + mt = self._mts.get(suffix) +- if mt.get_attr_val_bytes('nsslapd-backend') != bename and mt.get_attr_val('nsslapd-state') != ensure_bytes('backend'): ++ if mt.get_attr_val_utf8('nsslapd-backend') != bename and mt.get_attr_val_utf8('nsslapd-state') != 'backend': + raise ldap.NO_SUCH_OBJECT("We have a matching suffix, but not a backend or correct database name.") + except ldap.NO_SUCH_OBJECT: + result = DSBLE0001 +-- +2.26.2 + diff --git a/SOURCES/0004-Issue-50816-dsconf-allows-the-root-password-to-be-se.patch b/SOURCES/0004-Issue-50816-dsconf-allows-the-root-password-to-be-se.patch deleted file mode 100644 index 482edb9..0000000 --- a/SOURCES/0004-Issue-50816-dsconf-allows-the-root-password-to-be-se.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 44e46e0dd71567756928be3f773d09cc2cee22c2 Mon Sep 17 00:00:00 2001 -From: Mark Reynolds -Date: Mon, 13 Jan 2020 17:58:52 -0500 -Subject: [PATCH] Issue 50816 - dsconf allows the root password to be set to - nothing - -Bug Description: dsconf allows you to set the root DN password to nothing/ - -Fix Description: Do not allow the root DN password to be set to nothing - -relates: https://pagure.io/389-ds-base/issue/50816 - -Reviewed by: firstyear(Thanks!) ---- - src/lib389/lib389/idm/directorymanager.py | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/src/lib389/lib389/idm/directorymanager.py b/src/lib389/lib389/idm/directorymanager.py -index bb3b58355..4c573e7b4 100644 ---- a/src/lib389/lib389/idm/directorymanager.py -+++ b/src/lib389/lib389/idm/directorymanager.py -@@ -31,6 +31,8 @@ class DirectoryManager(Account): - self._protected = True - - def change_password(self, new_password): -+ if new_password == "": -+ raise ValueError("You can not set the Directory Manager password to nothing") - self._instance.config.set('nsslapd-rootpw', new_password) - - def bind(self, password=PW_DM, *args, **kwargs): --- -2.21.1 - diff --git a/SOURCES/0004-Issue-51076-remove-unnecessary-slapi-entry-dups.patch b/SOURCES/0004-Issue-51076-remove-unnecessary-slapi-entry-dups.patch new file mode 100644 index 0000000..c931a79 --- /dev/null +++ b/SOURCES/0004-Issue-51076-remove-unnecessary-slapi-entry-dups.patch @@ -0,0 +1,943 @@ +From f13d630ff98eb5b5505f1db3e7f207175b51b237 Mon Sep 17 00:00:00 2001 +From: Mark Reynolds +Date: Tue, 12 May 2020 13:48:30 -0400 +Subject: [PATCH 04/12] Issue 51076 - remove unnecessary slapi entry dups + +Description: So the problem is that slapi_search_internal_get_entry() + duplicates the entry twice. It does that as a convenience + where it will allocate a pblock, do the search, copy + the entry, free search results from the pblock, and then + free the pblock itself. I basically split this function + into two functions. One function allocates the pblock, + does the search and returns the entry. The other function + frees the entries and pblock. + + 99% of time when we call slapi_search_internal_get_entry() + we are just reading it and freeing it. It's not being + consumed. In these cases we can use the two function + approach eliminates an extra slapi_entry_dup(). Over the + time of an operation/connection we can save quite a bit + of mallocing/freeing. This could also help with memory + fragmentation. + +ASAN: passed + +relates: https://pagure.io/389-ds-base/issue/51076 + +Reviewed by: firstyear & tbordaz(Thanks!) +--- + ldap/servers/plugins/acctpolicy/acct_config.c | 6 +-- + ldap/servers/plugins/acctpolicy/acct_plugin.c | 36 +++++++------- + ldap/servers/plugins/acctpolicy/acct_util.c | 6 +-- + ldap/servers/plugins/automember/automember.c | 17 +++---- + ldap/servers/plugins/dna/dna.c | 23 ++++----- + ldap/servers/plugins/memberof/memberof.c | 16 +++---- + .../plugins/pam_passthru/pam_ptconfig.c | 10 ++-- + .../servers/plugins/pam_passthru/pam_ptimpl.c | 7 +-- + .../plugins/pam_passthru/pam_ptpreop.c | 9 ++-- + .../plugins/replication/repl5_tot_protocol.c | 5 +- + ldap/servers/plugins/uiduniq/uid.c | 23 ++++----- + ldap/servers/slapd/daemon.c | 11 ++--- + ldap/servers/slapd/modify.c | 12 +++-- + ldap/servers/slapd/plugin_internal_op.c | 48 +++++++++++++++++++ + ldap/servers/slapd/resourcelimit.c | 13 ++--- + ldap/servers/slapd/schema.c | 7 ++- + ldap/servers/slapd/slapi-plugin.h | 23 ++++++++- + 17 files changed, 161 insertions(+), 111 deletions(-) + +diff --git a/ldap/servers/plugins/acctpolicy/acct_config.c b/ldap/servers/plugins/acctpolicy/acct_config.c +index fe35ba5a0..01e4f319f 100644 +--- a/ldap/servers/plugins/acctpolicy/acct_config.c ++++ b/ldap/servers/plugins/acctpolicy/acct_config.c +@@ -37,6 +37,7 @@ static int acct_policy_entry2config(Slapi_Entry *e, + int + acct_policy_load_config_startup(Slapi_PBlock *pb __attribute__((unused)), void *plugin_id) + { ++ Slapi_PBlock *entry_pb = NULL; + acctPluginCfg *newcfg; + Slapi_Entry *config_entry = NULL; + Slapi_DN *config_sdn = NULL; +@@ -44,8 +45,7 @@ acct_policy_load_config_startup(Slapi_PBlock *pb __attribute__((unused)), void * + + /* Retrieve the config entry */ + config_sdn = slapi_sdn_new_normdn_byref(PLUGIN_CONFIG_DN); +- rc = slapi_search_internal_get_entry(config_sdn, NULL, &config_entry, +- plugin_id); ++ rc = slapi_search_get_entry(&entry_pb, config_sdn, NULL, &config_entry, plugin_id); + slapi_sdn_free(&config_sdn); + + if (rc != LDAP_SUCCESS || config_entry == NULL) { +@@ -60,7 +60,7 @@ acct_policy_load_config_startup(Slapi_PBlock *pb __attribute__((unused)), void * + rc = acct_policy_entry2config(config_entry, newcfg); + config_unlock(); + +- slapi_entry_free(config_entry); ++ slapi_search_get_entry_done(&entry_pb); + + return (rc); + } +diff --git a/ldap/servers/plugins/acctpolicy/acct_plugin.c b/ldap/servers/plugins/acctpolicy/acct_plugin.c +index 2a876ad72..c3c32b074 100644 +--- a/ldap/servers/plugins/acctpolicy/acct_plugin.c ++++ b/ldap/servers/plugins/acctpolicy/acct_plugin.c +@@ -209,6 +209,7 @@ done: + int + acct_bind_preop(Slapi_PBlock *pb) + { ++ Slapi_PBlock *entry_pb = NULL; + const char *dn = NULL; + Slapi_DN *sdn = NULL; + Slapi_Entry *target_entry = NULL; +@@ -236,8 +237,7 @@ acct_bind_preop(Slapi_PBlock *pb) + goto done; + } + +- ldrc = slapi_search_internal_get_entry(sdn, NULL, &target_entry, +- plugin_id); ++ ldrc = slapi_search_get_entry(&entry_pb, sdn, NULL, &target_entry, plugin_id); + + /* There was a problem retrieving the entry */ + if (ldrc != LDAP_SUCCESS) { +@@ -275,7 +275,7 @@ done: + slapi_send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL, NULL, 0, NULL); + } + +- slapi_entry_free(target_entry); ++ slapi_search_get_entry_done(&entry_pb); + + free_acctpolicy(&policy); + +@@ -293,6 +293,7 @@ done: + int + acct_bind_postop(Slapi_PBlock *pb) + { ++ Slapi_PBlock *entry_pb = NULL; + char *dn = NULL; + int ldrc, tracklogin = 0; + int rc = 0; /* Optimistic default */ +@@ -327,8 +328,7 @@ acct_bind_postop(Slapi_PBlock *pb) + covered by an account policy to decide whether we should track */ + if (tracklogin == 0) { + sdn = slapi_sdn_new_normdn_byref(dn); +- ldrc = slapi_search_internal_get_entry(sdn, NULL, &target_entry, +- plugin_id); ++ ldrc = slapi_search_get_entry(&entry_pb, sdn, NULL, &target_entry, plugin_id); + + if (ldrc != LDAP_SUCCESS) { + slapi_log_err(SLAPI_LOG_ERR, POST_PLUGIN_NAME, +@@ -355,7 +355,7 @@ done: + slapi_send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL, NULL, 0, NULL); + } + +- slapi_entry_free(target_entry); ++ slapi_search_get_entry_done(&entry_pb); + + slapi_sdn_free(&sdn); + +@@ -370,11 +370,11 @@ done: + static int + acct_pre_op(Slapi_PBlock *pb, int modop) + { ++ Slapi_PBlock *entry_pb = NULL; + Slapi_DN *sdn = 0; + Slapi_Entry *e = 0; + Slapi_Mods *smods = 0; + LDAPMod **mods; +- int free_entry = 0; + char *errstr = NULL; + int ret = SLAPI_PLUGIN_SUCCESS; + +@@ -384,28 +384,25 @@ acct_pre_op(Slapi_PBlock *pb, int modop) + + if (acct_policy_dn_is_config(sdn)) { + /* Validate config changes, but don't apply them. +- * This allows us to reject invalid config changes +- * here at the pre-op stage. Applying the config +- * needs to be done at the post-op stage. */ ++ * This allows us to reject invalid config changes ++ * here at the pre-op stage. Applying the config ++ * needs to be done at the post-op stage. */ + + if (LDAP_CHANGETYPE_ADD == modop) { + slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &e); + +- /* If the entry doesn't exist, just bail and +- * let the server handle it. */ ++ /* If the entry doesn't exist, just bail and let the server handle it. */ + if (e == NULL) { + goto bail; + } + } else if (LDAP_CHANGETYPE_MODIFY == modop) { + /* Fetch the entry being modified so we can +- * create the resulting entry for validation. */ ++ * create the resulting entry for validation. */ + if (sdn) { +- slapi_search_internal_get_entry(sdn, 0, &e, get_identity()); +- free_entry = 1; ++ slapi_search_get_entry(&entry_pb, sdn, 0, &e, get_identity()); + } + +- /* If the entry doesn't exist, just bail and +- * let the server handle it. */ ++ /* If the entry doesn't exist, just bail and let the server handle it. */ + if (e == NULL) { + goto bail; + } +@@ -418,7 +415,7 @@ acct_pre_op(Slapi_PBlock *pb, int modop) + /* Apply the mods to create the resulting entry. */ + if (mods && (slapi_entry_apply_mods(e, mods) != LDAP_SUCCESS)) { + /* The mods don't apply cleanly, so we just let this op go +- * to let the main server handle it. */ ++ * to let the main server handle it. */ + goto bailmod; + } + } else if (modop == LDAP_CHANGETYPE_DELETE) { +@@ -439,8 +436,7 @@ bailmod: + } + + bail: +- if (free_entry && e) +- slapi_entry_free(e); ++ slapi_search_get_entry_done(&entry_pb); + + if (ret) { + slapi_log_err(SLAPI_LOG_PLUGIN, PRE_PLUGIN_NAME, +diff --git a/ldap/servers/plugins/acctpolicy/acct_util.c b/ldap/servers/plugins/acctpolicy/acct_util.c +index f25a3202d..f432092fe 100644 +--- a/ldap/servers/plugins/acctpolicy/acct_util.c ++++ b/ldap/servers/plugins/acctpolicy/acct_util.c +@@ -85,6 +85,7 @@ get_attr_string_val(Slapi_Entry *target_entry, char *attr_name) + int + get_acctpolicy(Slapi_PBlock *pb __attribute__((unused)), Slapi_Entry *target_entry, void *plugin_id, acctPolicy **policy) + { ++ Slapi_PBlock *entry_pb = NULL; + Slapi_DN *sdn = NULL; + Slapi_Entry *policy_entry = NULL; + Slapi_Attr *attr; +@@ -123,8 +124,7 @@ get_acctpolicy(Slapi_PBlock *pb __attribute__((unused)), Slapi_Entry *target_ent + } + + sdn = slapi_sdn_new_dn_byref(policy_dn); +- ldrc = slapi_search_internal_get_entry(sdn, NULL, &policy_entry, +- plugin_id); ++ ldrc = slapi_search_get_entry(&entry_pb, sdn, NULL, &policy_entry, plugin_id); + slapi_sdn_free(&sdn); + + /* There should be a policy but it can't be retrieved; fatal error */ +@@ -160,7 +160,7 @@ dopolicy: + done: + config_unlock(); + slapi_ch_free_string(&policy_dn); +- slapi_entry_free(policy_entry); ++ slapi_search_get_entry_done(&entry_pb); + return (rc); + } + +diff --git a/ldap/servers/plugins/automember/automember.c b/ldap/servers/plugins/automember/automember.c +index 7c875c852..39350ad53 100644 +--- a/ldap/servers/plugins/automember/automember.c ++++ b/ldap/servers/plugins/automember/automember.c +@@ -1629,13 +1629,12 @@ automember_update_member_value(Slapi_Entry *member_e, const char *group_dn, char + char *member_value = NULL; + int rc = 0; + Slapi_DN *group_sdn; +- Slapi_Entry *group_entry = NULL; + + /* First thing check that the group still exists */ + group_sdn = slapi_sdn_new_dn_byval(group_dn); +- rc = slapi_search_internal_get_entry(group_sdn, NULL, &group_entry, automember_get_plugin_id()); ++ rc = slapi_search_internal_get_entry(group_sdn, NULL, NULL, automember_get_plugin_id()); + slapi_sdn_free(&group_sdn); +- if (rc != LDAP_SUCCESS || group_entry == NULL) { ++ if (rc != LDAP_SUCCESS) { + if (rc == LDAP_NO_SUCH_OBJECT) { + /* the automember group (default or target) does not exist, just skip this definition */ + slapi_log_err(SLAPI_LOG_INFO, AUTOMEMBER_PLUGIN_SUBSYSTEM, +@@ -1647,10 +1646,8 @@ automember_update_member_value(Slapi_Entry *member_e, const char *group_dn, char + "automember_update_member_value - group (default or target) can not be retrieved (%s) err=%d\n", + group_dn, rc); + } +- slapi_entry_free(group_entry); + return rc; + } +- slapi_entry_free(group_entry); + + /* If grouping_value is dn, we need to fetch the dn instead. */ + if (slapi_attr_type_cmp(grouping_value, "dn", SLAPI_TYPE_CMP_EXACT) == 0) { +@@ -1752,11 +1749,11 @@ out: + static int + automember_pre_op(Slapi_PBlock *pb, int modop) + { ++ Slapi_PBlock *entry_pb = NULL; + Slapi_DN *sdn = 0; + Slapi_Entry *e = 0; + Slapi_Mods *smods = 0; + LDAPMod **mods; +- int free_entry = 0; + char *errstr = NULL; + int ret = SLAPI_PLUGIN_SUCCESS; + +@@ -1784,8 +1781,7 @@ automember_pre_op(Slapi_PBlock *pb, int modop) + /* Fetch the entry being modified so we can + * create the resulting entry for validation. */ + if (sdn) { +- slapi_search_internal_get_entry(sdn, 0, &e, automember_get_plugin_id()); +- free_entry = 1; ++ slapi_search_get_entry(&entry_pb, sdn, 0, &e, automember_get_plugin_id()); + } + + /* If the entry doesn't exist, just bail and +@@ -1799,7 +1795,7 @@ automember_pre_op(Slapi_PBlock *pb, int modop) + smods = slapi_mods_new(); + slapi_mods_init_byref(smods, mods); + +- /* Apply the mods to create the resulting entry. */ ++ /* Apply the mods to create the resulting entry. */ + if (mods && (slapi_entry_apply_mods(e, mods) != LDAP_SUCCESS)) { + /* The mods don't apply cleanly, so we just let this op go + * to let the main server handle it. */ +@@ -1831,8 +1827,7 @@ bailmod: + } + + bail: +- if (free_entry && e) +- slapi_entry_free(e); ++ slapi_search_get_entry_done(&entry_pb); + + if (ret) { + slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM, +diff --git a/ldap/servers/plugins/dna/dna.c b/ldap/servers/plugins/dna/dna.c +index 1ee271359..16c625bb0 100644 +--- a/ldap/servers/plugins/dna/dna.c ++++ b/ldap/servers/plugins/dna/dna.c +@@ -1178,7 +1178,6 @@ dna_parse_config_entry(Slapi_PBlock *pb, Slapi_Entry *e, int apply) + + value = slapi_entry_attr_get_charptr(e, DNA_SHARED_CFG_DN); + if (value) { +- Slapi_Entry *shared_e = NULL; + Slapi_DN *sdn = NULL; + char *normdn = NULL; + char *attrs[2]; +@@ -1197,10 +1196,8 @@ dna_parse_config_entry(Slapi_PBlock *pb, Slapi_Entry *e, int apply) + /* We don't need attributes */ + attrs[0] = "cn"; + attrs[1] = NULL; +- slapi_search_internal_get_entry(sdn, attrs, &shared_e, getPluginID()); +- + /* Make sure that the shared config entry exists. */ +- if (!shared_e) { ++ if(slapi_search_internal_get_entry(sdn, attrs, NULL, getPluginID()) != LDAP_SUCCESS) { + /* We didn't locate the shared config container entry. Log + * a message and skip this config entry. */ + slapi_log_err(SLAPI_LOG_ERR, DNA_PLUGIN_SUBSYSTEM, +@@ -1210,9 +1207,6 @@ dna_parse_config_entry(Slapi_PBlock *pb, Slapi_Entry *e, int apply) + ret = DNA_FAILURE; + slapi_sdn_free(&sdn); + goto bail; +- } else { +- slapi_entry_free(shared_e); +- shared_e = NULL; + } + + normdn = (char *)slapi_sdn_get_dn(sdn); +@@ -1539,6 +1533,7 @@ dna_delete_shared_servers(PRCList **servers) + static int + dna_load_host_port(void) + { ++ Slapi_PBlock *pb = NULL; + int status = DNA_SUCCESS; + Slapi_Entry *e = NULL; + Slapi_DN *config_dn = NULL; +@@ -1554,7 +1549,7 @@ dna_load_host_port(void) + + config_dn = slapi_sdn_new_ndn_byref("cn=config"); + if (config_dn) { +- slapi_search_internal_get_entry(config_dn, attrs, &e, getPluginID()); ++ slapi_search_get_entry(&pb, config_dn, attrs, &e, getPluginID()); + slapi_sdn_free(&config_dn); + } + +@@ -1562,8 +1557,8 @@ dna_load_host_port(void) + hostname = slapi_entry_attr_get_charptr(e, "nsslapd-localhost"); + portnum = slapi_entry_attr_get_charptr(e, "nsslapd-port"); + secureportnum = slapi_entry_attr_get_charptr(e, "nsslapd-secureport"); +- slapi_entry_free(e); + } ++ slapi_search_get_entry_done(&pb); + + if (!hostname || !portnum) { + status = DNA_FAILURE; +@@ -2876,6 +2871,7 @@ bail: + static int + dna_is_replica_bind_dn(char *range_dn, char *bind_dn) + { ++ Slapi_PBlock *entry_pb = NULL; + char *replica_dn = NULL; + Slapi_DN *replica_sdn = NULL; + Slapi_DN *range_sdn = NULL; +@@ -2912,8 +2908,7 @@ dna_is_replica_bind_dn(char *range_dn, char *bind_dn) + attrs[2] = 0; + + /* Find cn=replica entry via search */ +- slapi_search_internal_get_entry(replica_sdn, attrs, &e, getPluginID()); +- ++ slapi_search_get_entry(&entry_pb, replica_sdn, attrs, &e, getPluginID()); + if (e) { + /* Check if the passed in bind dn matches any of the replica bind dns. */ + Slapi_Value *bind_dn_sv = slapi_value_new_string(bind_dn); +@@ -2927,6 +2922,7 @@ dna_is_replica_bind_dn(char *range_dn, char *bind_dn) + attrs[0] = "member"; + attrs[1] = "uniquemember"; + attrs[2] = 0; ++ slapi_search_get_entry_done(&entry_pb); + for (i = 0; bind_group_dn != NULL && bind_group_dn[i] != NULL; i++) { + if (ret) { + /* already found a member, just free group */ +@@ -2934,14 +2930,14 @@ dna_is_replica_bind_dn(char *range_dn, char *bind_dn) + continue; + } + bind_group_sdn = slapi_sdn_new_normdn_passin(bind_group_dn[i]); +- slapi_search_internal_get_entry(bind_group_sdn, attrs, &bind_group_entry, getPluginID()); ++ slapi_search_get_entry(&entry_pb, bind_group_sdn, attrs, &bind_group_entry, getPluginID()); + if (bind_group_entry) { + ret = slapi_entry_attr_has_syntax_value(bind_group_entry, "member", bind_dn_sv); + if (ret == 0) { + ret = slapi_entry_attr_has_syntax_value(bind_group_entry, "uniquemember", bind_dn_sv); + } + } +- slapi_entry_free(bind_group_entry); ++ slapi_search_get_entry_done(&entry_pb); + slapi_sdn_free(&bind_group_sdn); + } + slapi_ch_free((void **)&bind_group_dn); +@@ -2956,7 +2952,6 @@ dna_is_replica_bind_dn(char *range_dn, char *bind_dn) + } + + done: +- slapi_entry_free(e); + slapi_sdn_free(&range_sdn); + slapi_sdn_free(&replica_sdn); + +diff --git a/ldap/servers/plugins/memberof/memberof.c b/ldap/servers/plugins/memberof/memberof.c +index 40bd4b380..e9e1ec4c7 100644 +--- a/ldap/servers/plugins/memberof/memberof.c ++++ b/ldap/servers/plugins/memberof/memberof.c +@@ -884,7 +884,7 @@ memberof_postop_modrdn(Slapi_PBlock *pb) + pre_sdn = slapi_entry_get_sdn(pre_e); + post_sdn = slapi_entry_get_sdn(post_e); + } +- ++ + if (pre_sdn && post_sdn && slapi_sdn_compare(pre_sdn, post_sdn) == 0) { + /* Regarding memberof plugin, this rename is a no-op + * but it can be expensive to process it. So skip it +@@ -1466,6 +1466,7 @@ memberof_modop_one_r(Slapi_PBlock *pb, MemberOfConfig *config, int mod_op, Slapi + int + memberof_modop_one_replace_r(Slapi_PBlock *pb, MemberOfConfig *config, int mod_op, Slapi_DN *group_sdn, Slapi_DN *op_this_sdn, Slapi_DN *replace_with_sdn, Slapi_DN *op_to_sdn, memberofstringll *stack) + { ++ Slapi_PBlock *entry_pb = NULL; + int rc = 0; + LDAPMod mod; + LDAPMod replace_mod; +@@ -1515,8 +1516,7 @@ memberof_modop_one_replace_r(Slapi_PBlock *pb, MemberOfConfig *config, int mod_o + } + + /* determine if this is a group op or single entry */ +- slapi_search_internal_get_entry(op_to_sdn, config->groupattrs, +- &e, memberof_get_plugin_id()); ++ slapi_search_get_entry(&entry_pb, op_to_sdn, config->groupattrs, &e, memberof_get_plugin_id()); + if (!e) { + /* In the case of a delete, we need to worry about the + * missing entry being a nested group. There's a small +@@ -1751,7 +1751,7 @@ memberof_modop_one_replace_r(Slapi_PBlock *pb, MemberOfConfig *config, int mod_o + bail: + slapi_value_free(&to_dn_val); + slapi_value_free(&this_dn_val); +- slapi_entry_free(e); ++ slapi_search_get_entry_done(&entry_pb); + return rc; + } + +@@ -2368,6 +2368,7 @@ bail: + int + memberof_is_direct_member(MemberOfConfig *config, Slapi_Value *groupdn, Slapi_Value *memberdn) + { ++ Slapi_PBlock *pb = NULL; + int rc = 0; + Slapi_DN *sdn = 0; + Slapi_Entry *group_e = 0; +@@ -2376,8 +2377,8 @@ memberof_is_direct_member(MemberOfConfig *config, Slapi_Value *groupdn, Slapi_Va + + sdn = slapi_sdn_new_normdn_byref(slapi_value_get_string(groupdn)); + +- slapi_search_internal_get_entry(sdn, config->groupattrs, +- &group_e, memberof_get_plugin_id()); ++ slapi_search_get_entry(&pb, sdn, config->groupattrs, ++ &group_e, memberof_get_plugin_id()); + + if (group_e) { + /* See if memberdn is referred to by any of the group attributes. */ +@@ -2388,9 +2389,8 @@ memberof_is_direct_member(MemberOfConfig *config, Slapi_Value *groupdn, Slapi_Va + break; + } + } +- +- slapi_entry_free(group_e); + } ++ slapi_search_get_entry_done(&pb); + + slapi_sdn_free(&sdn); + return rc; +diff --git a/ldap/servers/plugins/pam_passthru/pam_ptconfig.c b/ldap/servers/plugins/pam_passthru/pam_ptconfig.c +index 46a76d884..cbec2ec40 100644 +--- a/ldap/servers/plugins/pam_passthru/pam_ptconfig.c ++++ b/ldap/servers/plugins/pam_passthru/pam_ptconfig.c +@@ -749,22 +749,22 @@ pam_passthru_get_config(Slapi_DN *bind_sdn) + if (pam_passthru_check_suffix(cfg, bind_sdn) == LDAP_SUCCESS) { + if (cfg->slapi_filter) { + /* A filter is configured, so see if the bind entry is a match. */ ++ Slapi_PBlock *entry_pb = NULL; + Slapi_Entry *test_e = NULL; + + /* Fetch the bind entry */ +- slapi_search_internal_get_entry(bind_sdn, NULL, &test_e, +- pam_passthruauth_get_plugin_identity()); ++ slapi_search_get_entry(&entry_pb, bind_sdn, NULL, &test_e, ++ pam_passthruauth_get_plugin_identity()); + + /* If the entry doesn't exist, just fall through to the main server code */ + if (test_e) { + /* Evaluate the filter. */ + if (LDAP_SUCCESS == slapi_filter_test_simple(test_e, cfg->slapi_filter)) { + /* This is a match. */ +- slapi_entry_free(test_e); ++ slapi_search_get_entry_done(&entry_pb); + goto done; + } +- +- slapi_entry_free(test_e); ++ slapi_search_get_entry_done(&entry_pb); + } + } else { + /* There is no filter to check, so this is a match. */ +diff --git a/ldap/servers/plugins/pam_passthru/pam_ptimpl.c b/ldap/servers/plugins/pam_passthru/pam_ptimpl.c +index 7f5fb02c4..5b43f8d1f 100644 +--- a/ldap/servers/plugins/pam_passthru/pam_ptimpl.c ++++ b/ldap/servers/plugins/pam_passthru/pam_ptimpl.c +@@ -81,11 +81,12 @@ derive_from_bind_dn(Slapi_PBlock *pb __attribute__((unused)), const Slapi_DN *bi + static char * + derive_from_bind_entry(Slapi_PBlock *pb, const Slapi_DN *bindsdn, MyStrBuf *pam_id, char *map_ident_attr, int *locked) + { ++ Slapi_PBlock *entry_pb = NULL; + Slapi_Entry *entry = NULL; + char *attrs[] = {NULL, NULL}; + attrs[0] = map_ident_attr; +- int rc = slapi_search_internal_get_entry((Slapi_DN *)bindsdn, attrs, &entry, +- pam_passthruauth_get_plugin_identity()); ++ int32_t rc = slapi_search_get_entry(&entry_pb, (Slapi_DN *)bindsdn, attrs, &entry, ++ pam_passthruauth_get_plugin_identity()); + + if (rc != LDAP_SUCCESS) { + slapi_log_err(SLAPI_LOG_ERR, PAM_PASSTHRU_PLUGIN_SUBSYSTEM, +@@ -108,7 +109,7 @@ derive_from_bind_entry(Slapi_PBlock *pb, const Slapi_DN *bindsdn, MyStrBuf *pam_ + init_my_str_buf(pam_id, val); + } + +- slapi_entry_free(entry); ++ slapi_search_get_entry_done(&entry_pb); + + return pam_id->str; + } +diff --git a/ldap/servers/plugins/pam_passthru/pam_ptpreop.c b/ldap/servers/plugins/pam_passthru/pam_ptpreop.c +index 3d0067531..5bca823ff 100644 +--- a/ldap/servers/plugins/pam_passthru/pam_ptpreop.c ++++ b/ldap/servers/plugins/pam_passthru/pam_ptpreop.c +@@ -526,6 +526,7 @@ done: + static int + pam_passthru_preop(Slapi_PBlock *pb, int modtype) + { ++ Slapi_PBlock *entry_pb = NULL; + Slapi_DN *sdn = NULL; + Slapi_Entry *e = NULL; + LDAPMod **mods; +@@ -555,8 +556,8 @@ pam_passthru_preop(Slapi_PBlock *pb, int modtype) + case LDAP_CHANGETYPE_MODIFY: + /* Fetch the entry being modified so we can + * create the resulting entry for validation. */ +- slapi_search_internal_get_entry(sdn, 0, &e, +- pam_passthruauth_get_plugin_identity()); ++ slapi_search_get_entry(&entry_pb, sdn, 0, &e, ++ pam_passthruauth_get_plugin_identity()); + + /* If the entry doesn't exist, just bail and + * let the server handle it. */ +@@ -576,9 +577,6 @@ pam_passthru_preop(Slapi_PBlock *pb, int modtype) + /* Don't bail here, as we need to free the entry. */ + } + } +- +- /* Free the entry. */ +- slapi_entry_free(e); + break; + case LDAP_CHANGETYPE_DELETE: + case LDAP_CHANGETYPE_MODDN: +@@ -591,6 +589,7 @@ pam_passthru_preop(Slapi_PBlock *pb, int modtype) + } + + bail: ++ slapi_search_get_entry_done(&entry_pb); + /* If we are refusing the operation, return the result to the client. */ + if (ret) { + slapi_send_ldap_result(pb, ret, NULL, returntext, 0, NULL); +diff --git a/ldap/servers/plugins/replication/repl5_tot_protocol.c b/ldap/servers/plugins/replication/repl5_tot_protocol.c +index 3b65d6b20..a25839f21 100644 +--- a/ldap/servers/plugins/replication/repl5_tot_protocol.c ++++ b/ldap/servers/plugins/replication/repl5_tot_protocol.c +@@ -469,7 +469,8 @@ retry: + */ + /* Get suffix */ + Slapi_Entry *suffix = NULL; +- rc = slapi_search_internal_get_entry(area_sdn, NULL, &suffix, repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION)); ++ Slapi_PBlock *suffix_pb = NULL; ++ rc = slapi_search_get_entry(&suffix_pb, area_sdn, NULL, &suffix, repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION)); + if (rc) { + slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "repl5_tot_run - Unable to " + "get the suffix entry \"%s\".\n", +@@ -517,7 +518,7 @@ retry: + LDAP_SCOPE_SUBTREE, "(parentid>=1)", NULL, 0, ctrls, NULL, + repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), OP_FLAG_BULK_IMPORT); + cb_data.num_entries = 0UL; +- slapi_entry_free(suffix); ++ slapi_search_get_entry_done(&suffix_pb); + } else { + /* Original total update */ + /* we need to provide managedsait control so that referral entries can +diff --git a/ldap/servers/plugins/uiduniq/uid.c b/ldap/servers/plugins/uiduniq/uid.c +index d7ccf0e07..e69012204 100644 +--- a/ldap/servers/plugins/uiduniq/uid.c ++++ b/ldap/servers/plugins/uiduniq/uid.c +@@ -1254,6 +1254,7 @@ preop_modify(Slapi_PBlock *pb) + static int + preop_modrdn(Slapi_PBlock *pb) + { ++ Slapi_PBlock *entry_pb = NULL; + int result = LDAP_SUCCESS; + Slapi_Entry *e = NULL; + Slapi_Value *sv_requiredObjectClass = NULL; +@@ -1351,7 +1352,7 @@ preop_modrdn(Slapi_PBlock *pb) + + /* Get the entry that is being renamed so we can make a dummy copy + * of what it will look like after the rename. */ +- err = slapi_search_internal_get_entry(sdn, NULL, &e, plugin_identity); ++ err = slapi_search_get_entry(&entry_pb, sdn, NULL, &e, plugin_identity); + if (err != LDAP_SUCCESS) { + result = uid_op_error(35); + /* We want to return a no such object error if the target doesn't exist. */ +@@ -1371,24 +1372,24 @@ preop_modrdn(Slapi_PBlock *pb) + + + /* +- * Check if it has the required object class +- */ ++ * Check if it has the required object class ++ */ + if (requiredObjectClass && + !slapi_entry_attr_has_syntax_value(e, SLAPI_ATTR_OBJECTCLASS, sv_requiredObjectClass)) { + break; + } + + /* +- * Find any unique attribute data in the new RDN +- */ ++ * Find any unique attribute data in the new RDN ++ */ + for (i = 0; attrNames && attrNames[i]; i++) { + err = slapi_entry_attr_find(e, attrNames[i], &attr); + if (!err) { + /* +- * Passed all the requirements - this is an operation we +- * need to enforce uniqueness on. Now find all parent entries +- * with the marker object class, and do a search for each one. +- */ ++ * Passed all the requirements - this is an operation we ++ * need to enforce uniqueness on. Now find all parent entries ++ * with the marker object class, and do a search for each one. ++ */ + if (NULL != markerObjectClass) { + /* Subtree defined by location of marker object class */ + result = findSubtreeAndSearch(slapi_entry_get_sdn(e), attrNames, attr, NULL, +@@ -1407,8 +1408,8 @@ preop_modrdn(Slapi_PBlock *pb) + END + /* Clean-up */ + slapi_value_free(&sv_requiredObjectClass); +- if (e) +- slapi_entry_free(e); ++ ++ slapi_search_get_entry_done(&entry_pb); + + if (result) { + slapi_log_err(SLAPI_LOG_PLUGIN, plugin_name, +diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c +index 65f23363a..a70f40316 100644 +--- a/ldap/servers/slapd/daemon.c ++++ b/ldap/servers/slapd/daemon.c +@@ -1916,18 +1916,13 @@ slapd_bind_local_user(Connection *conn) + char *root_dn = config_get_ldapi_root_dn(); + + if (root_dn) { ++ Slapi_PBlock *entry_pb = NULL; + Slapi_DN *edn = slapi_sdn_new_dn_byref( + slapi_dn_normalize(root_dn)); + Slapi_Entry *e = 0; + + /* root might be locked too! :) */ +- ret = slapi_search_internal_get_entry( +- edn, 0, +- &e, +- (void *)plugin_get_default_component_id() +- +- ); +- ++ ret = slapi_search_get_entry(&entry_pb, edn, 0, &e, (void *)plugin_get_default_component_id()); + if (0 == ret && e) { + ret = slapi_check_account_lock( + 0, /* pb not req */ +@@ -1955,7 +1950,7 @@ slapd_bind_local_user(Connection *conn) + root_map_free: + /* root_dn consumed by bind creds set */ + slapi_sdn_free(&edn); +- slapi_entry_free(e); ++ slapi_search_get_entry_done(&entry_pb); + ret = 0; + } + } +diff --git a/ldap/servers/slapd/modify.c b/ldap/servers/slapd/modify.c +index bbc0ab71a..259bedfff 100644 +--- a/ldap/servers/slapd/modify.c ++++ b/ldap/servers/slapd/modify.c +@@ -592,6 +592,7 @@ modify_internal_pb(Slapi_PBlock *pb) + static void + op_shared_modify(Slapi_PBlock *pb, int pw_change, char *old_pw) + { ++ Slapi_PBlock *entry_pb = NULL; + Slapi_Backend *be = NULL; + Slapi_Entry *pse; + Slapi_Entry *referral; +@@ -723,7 +724,7 @@ op_shared_modify(Slapi_PBlock *pb, int pw_change, char *old_pw) + * 2. If yes, then if the mods contain any passwdpolicy specific attributes. + * 3. If yes, then it invokes corrosponding checking function. + */ +- if (!repl_op && !internal_op && normdn && (e = get_entry(pb, normdn))) { ++ if (!repl_op && !internal_op && normdn && slapi_search_get_entry(&entry_pb, sdn, NULL, &e, NULL) == LDAP_SUCCESS) { + Slapi_Value target; + slapi_value_init(&target); + slapi_value_set_string(&target, "passwordpolicy"); +@@ -1072,7 +1073,7 @@ free_and_return : { + slapi_entry_free(epre); + slapi_entry_free(epost); + } +- slapi_entry_free(e); ++ slapi_search_get_entry_done(&entry_pb); + + if (be) + slapi_be_Unlock(be); +@@ -1202,12 +1203,13 @@ op_shared_allow_pw_change(Slapi_PBlock *pb, LDAPMod *mod, char **old_pw, Slapi_M + if (!internal_op) { + /* slapi_acl_check_mods needs an array of LDAPMods, but + * we're really only interested in the one password mod. */ ++ Slapi_PBlock *entry_pb = NULL; + LDAPMod *mods[2]; + mods[0] = mod; + mods[1] = NULL; + + /* We need to actually fetch the target here to use for ACI checking. */ +- slapi_search_internal_get_entry(&sdn, NULL, &e, (void *)plugin_get_default_component_id()); ++ slapi_search_get_entry(&entry_pb, &sdn, NULL, &e, NULL); + + /* Create a bogus entry with just the target dn if we were unable to + * find the actual entry. This will only be used for checking the ACIs. */ +@@ -1238,9 +1240,12 @@ op_shared_allow_pw_change(Slapi_PBlock *pb, LDAPMod *mod, char **old_pw, Slapi_M + } + send_ldap_result(pb, res, NULL, errtxt, 0, NULL); + slapi_ch_free_string(&errtxt); ++ slapi_search_get_entry_done(&entry_pb); + rc = -1; + goto done; + } ++ /* done with slapi entry e */ ++ slapi_search_get_entry_done(&entry_pb); + + /* + * If this mod is being performed by a password administrator/rootDN, +@@ -1353,7 +1358,6 @@ op_shared_allow_pw_change(Slapi_PBlock *pb, LDAPMod *mod, char **old_pw, Slapi_M + valuearray_free(&values); + + done: +- slapi_entry_free(e); + slapi_sdn_done(&sdn); + slapi_ch_free_string(&proxydn); + slapi_ch_free_string(&proxystr); +diff --git a/ldap/servers/slapd/plugin_internal_op.c b/ldap/servers/slapd/plugin_internal_op.c +index 9da266b61..a140e7988 100644 +--- a/ldap/servers/slapd/plugin_internal_op.c ++++ b/ldap/servers/slapd/plugin_internal_op.c +@@ -882,3 +882,51 @@ slapi_search_internal_get_entry(Slapi_DN *dn, char **attrs, Slapi_Entry **ret_en + int_search_pb = NULL; + return rc; + } ++ ++int32_t ++slapi_search_get_entry(Slapi_PBlock **pb, Slapi_DN *dn, char **attrs, Slapi_Entry **ret_entry, void *component_identity) ++{ ++ Slapi_Entry **entries = NULL; ++ int32_t rc = 0; ++ void *component = component_identity; ++ ++ if (ret_entry) { ++ *ret_entry = NULL; ++ } ++ ++ if (component == NULL) { ++ component = (void *)plugin_get_default_component_id(); ++ } ++ ++ if (*pb == NULL) { ++ *pb = slapi_pblock_new(); ++ } ++ slapi_search_internal_set_pb(*pb, slapi_sdn_get_dn(dn), LDAP_SCOPE_BASE, ++ "(|(objectclass=*)(objectclass=ldapsubentry))", ++ attrs, 0, NULL, NULL, component, 0 ); ++ slapi_search_internal_pb(*pb); ++ slapi_pblock_get(*pb, SLAPI_PLUGIN_INTOP_RESULT, &rc); ++ if (LDAP_SUCCESS == rc) { ++ slapi_pblock_get(*pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries); ++ if (NULL != entries && NULL != entries[0]) { ++ /* Only need to dup the entry if the caller passed ret_entry in. */ ++ if (ret_entry) { ++ *ret_entry = entries[0]; ++ } ++ } else { ++ rc = LDAP_NO_SUCH_OBJECT; ++ } ++ } ++ ++ return rc; ++} ++ ++void ++slapi_search_get_entry_done(Slapi_PBlock **pb) ++{ ++ if (pb && *pb) { ++ slapi_free_search_results_internal(*pb); ++ slapi_pblock_destroy(*pb); ++ *pb = NULL; ++ } ++} +diff --git a/ldap/servers/slapd/resourcelimit.c b/ldap/servers/slapd/resourcelimit.c +index 705344c84..9c2619716 100644 +--- a/ldap/servers/slapd/resourcelimit.c ++++ b/ldap/servers/slapd/resourcelimit.c +@@ -305,22 +305,17 @@ reslimit_get_ext(Slapi_Connection *conn, const char *logname, SLAPIResLimitConnD + int + reslimit_update_from_dn(Slapi_Connection *conn, Slapi_DN *dn) + { +- Slapi_Entry *e; ++ Slapi_PBlock *pb = NULL; ++ Slapi_Entry *e = NULL; + int rc; + +- e = NULL; + if (dn != NULL) { +- + char **attrs = reslimit_get_registered_attributes(); +- (void)slapi_search_internal_get_entry(dn, attrs, &e, reslimit_componentid); ++ slapi_search_get_entry(&pb, dn, attrs, &e, reslimit_componentid); + charray_free(attrs); + } +- + rc = reslimit_update_from_entry(conn, e); +- +- if (NULL != e) { +- slapi_entry_free(e); +- } ++ slapi_search_get_entry_done(&pb); + + return (rc); + } +diff --git a/ldap/servers/slapd/schema.c b/ldap/servers/slapd/schema.c +index d44b03b0e..bf7e59f75 100644 +--- a/ldap/servers/slapd/schema.c ++++ b/ldap/servers/slapd/schema.c +@@ -341,6 +341,7 @@ schema_policy_add_action(Slapi_Entry *entry, char *attrName, schema_item_t **lis + static void + schema_load_repl_policy(const char *dn, repl_schema_policy_t *replica) + { ++ Slapi_PBlock *pb = NULL; + Slapi_DN sdn; + Slapi_Entry *entry = NULL; + schema_item_t *schema_item, *next; +@@ -369,8 +370,7 @@ schema_load_repl_policy(const char *dn, repl_schema_policy_t *replica) + + /* Load the replication policy of the schema */ + slapi_sdn_init_dn_byref(&sdn, dn); +- if (slapi_search_internal_get_entry(&sdn, NULL, &entry, plugin_get_default_component_id()) == LDAP_SUCCESS) { +- ++ if (slapi_search_get_entry(&pb, &sdn, NULL, &entry, plugin_get_default_component_id()) == LDAP_SUCCESS) { + /* fill the policies (accept/reject) regarding objectclass */ + schema_policy_add_action(entry, ATTR_SCHEMA_UPDATE_OBJECTCLASS_ACCEPT, &replica->objectclasses); + schema_policy_add_action(entry, ATTR_SCHEMA_UPDATE_OBJECTCLASS_REJECT, &replica->objectclasses); +@@ -378,9 +378,8 @@ schema_load_repl_policy(const char *dn, repl_schema_policy_t *replica) + /* fill the policies (accept/reject) regarding attribute */ + schema_policy_add_action(entry, ATTR_SCHEMA_UPDATE_ATTRIBUTE_ACCEPT, &replica->attributes); + schema_policy_add_action(entry, ATTR_SCHEMA_UPDATE_ATTRIBUTE_REJECT, &replica->attributes); +- +- slapi_entry_free(entry); + } ++ slapi_search_get_entry_done(&pb); + slapi_sdn_done(&sdn); + } + +diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h +index 0e3857068..be1e52e4d 100644 +--- a/ldap/servers/slapd/slapi-plugin.h ++++ b/ldap/servers/slapd/slapi-plugin.h +@@ -5972,7 +5972,7 @@ void slapi_seq_internal_set_pb(Slapi_PBlock *pb, char *ibase, int type, char *at + + /* + * slapi_search_internal_get_entry() finds an entry given a dn. It returns +- * an LDAP error code (LDAP_SUCCESS if all goes well). ++ * an LDAP error code (LDAP_SUCCESS if all goes well). Caller must free ret_entry + */ + int slapi_search_internal_get_entry(Slapi_DN *dn, char **attrlist, Slapi_Entry **ret_entry, void *caller_identity); + +@@ -8296,6 +8296,27 @@ uint64_t slapi_atomic_decr_64(uint64_t *ptr, int memorder); + /* helper function */ + const char * slapi_fetch_attr(Slapi_Entry *e, const char *attrname, char *default_val); + ++/** ++ * Get a Slapi_Entry via an internal search. The caller then needs to call ++ * slapi_get_entry_done() to free any resources allocated to get the entry ++ * ++ * \param pb - slapi_pblock pointer (the function will allocate if necessary) ++ * \param dn - Slapi_DN of the entry to retrieve ++ * \param attrs - char list of attributes to get ++ * \param ret_entry - pointer to a Slapi_entry wer the returned entry is stored ++ * \param component_identity - plugin component ++ * ++ * \return - ldap result code ++ */ ++int32_t slapi_search_get_entry(Slapi_PBlock **pb, Slapi_DN *dn, char **attrs, Slapi_Entry **ret_entry, void *component_identity); ++ ++/** ++ * Free the resources allocated by slapi_search_get_entry() ++ * ++ * \param pb - slapi_pblock pointer ++ */ ++void slapi_search_get_entry_done(Slapi_PBlock **pb); ++ + #ifdef __cplusplus + } + #endif +-- +2.26.2 + diff --git a/SOURCES/0005-Issue-50812-dscontainer-executable-should-be-placed-.patch b/SOURCES/0005-Issue-50812-dscontainer-executable-should-be-placed-.patch deleted file mode 100644 index 46ee67d..0000000 --- a/SOURCES/0005-Issue-50812-dscontainer-executable-should-be-placed-.patch +++ /dev/null @@ -1,97 +0,0 @@ -From f570348659620a59b681e7bf315bd979cd7de497 Mon Sep 17 00:00:00 2001 -From: Mark Reynolds -Date: Mon, 13 Jan 2020 14:40:49 -0500 -Subject: [PATCH] Issue 50812 - dscontainer executable should be placed under - /usr/libexec/dirsrv/ - -Description: dscontainer is not a user-runnable executable. Per packaging - guidelines it should be placed under /usr/libexec/dirsrv/ - -relates: https://pagure.io/389-ds-base/issue/50812 - -Reviewed by: firstyear & mhonek (Thanks!!) ---- - docker/389-ds-fedora/Dockerfile | 6 +++--- - docker/389-ds-suse/Dockerfile | 4 ++-- - docker/389-ds-suse/Dockerfile.release | 2 +- - rpm/389-ds-base.spec.in | 2 +- - src/lib389/setup.py | 4 +++- - 5 files changed, 10 insertions(+), 8 deletions(-) - -diff --git a/docker/389-ds-fedora/Dockerfile b/docker/389-ds-fedora/Dockerfile -index d61df8cba..45523ccf1 100644 ---- a/docker/389-ds-fedora/Dockerfile -+++ b/docker/389-ds-fedora/Dockerfile -@@ -40,7 +40,7 @@ VOLUME /etc/dirsrv - VOLUME /var/log/dirsrv - VOLUME /var/lib/dirsrv - --# Or, run them as dirsrv --USER dirsrv --CMD ["/usr/sbin/ns-slapd", "-d", "0", "-D", "/etc/dirsrv/slapd-localhost", "-i", "/var/run/dirsrv/slapd-localhost.pid"] -+HEALTHCHECK --start-period=5m --timeout=5s --interval=5s --retries=2 \ -+ CMD /usr/libexec/dirsrv/dscontainer -H - -+CMD [ "/usr/libexec/dirsrv/dscontainer", "-r" ] -diff --git a/docker/389-ds-suse/Dockerfile b/docker/389-ds-suse/Dockerfile -index 1e56e1f5a..6022d04c6 100644 ---- a/docker/389-ds-suse/Dockerfile -+++ b/docker/389-ds-suse/Dockerfile -@@ -76,7 +76,7 @@ VOLUME /data - # USER dirsrv - - HEALTHCHECK --start-period=5m --timeout=5s --interval=5s --retries=2 \ -- CMD /usr/sbin/dscontainer -H -+ CMD /usr/libexec/dirsrv/dscontainer -H - --CMD [ "/usr/sbin/dscontainer", "-r" ] -+CMD [ "/usr/libexec/dirsrv/dscontainer", "-r" ] - -diff --git a/docker/389-ds-suse/Dockerfile.release b/docker/389-ds-suse/Dockerfile.release -index c934edaf0..6f4adf735 100644 ---- a/docker/389-ds-suse/Dockerfile.release -+++ b/docker/389-ds-suse/Dockerfile.release -@@ -69,4 +69,4 @@ VOLUME /data - # here and ds should do the right thing if a non root user runs the server. - # USER dirsrv - --CMD [ "/usr/sbin/dscontainer", "-r" ] -+CMD [ "/usr/libexec/dirsrv/dscontainer", "-r" ] -diff --git a/rpm/389-ds-base.spec.in b/rpm/389-ds-base.spec.in -index 6f4a1e1a9..6491bda00 100644 ---- a/rpm/389-ds-base.spec.in -+++ b/rpm/389-ds-base.spec.in -@@ -806,7 +806,7 @@ exit 0 - %{_mandir}/man8/dsctl.8.gz - %{_sbindir}/dsidm - %{_mandir}/man8/dsidm.8.gz --%{_sbindir}/dscontainer -+%{_libexecdir}/%{pkgname}/dscontainer - - %files -n cockpit-389-ds -f cockpit.list - %{_datarootdir}/metainfo/389-console/org.port389.cockpit_console.metainfo.xml -diff --git a/src/lib389/setup.py b/src/lib389/setup.py -index 056173936..296b555a4 100644 ---- a/src/lib389/setup.py -+++ b/src/lib389/setup.py -@@ -63,7 +63,6 @@ setup( - 'cli/dsconf', - 'cli/dscreate', - 'cli/dsidm', -- 'cli/dscontainer', - ]), - ('/usr/share/man/man8', [ - 'man/dsctl.8', -@@ -71,6 +70,9 @@ setup( - 'man/dscreate.8', - 'man/dsidm.8', - ]), -+ ('/usr/libexec/dirsrv/', [ -+ 'cli/dscontainer', -+ ]), - ], - - install_requires=[ --- -2.21.1 - diff --git a/SOURCES/0005-Issue-51086-Improve-dscreate-instance-name-validatio.patch b/SOURCES/0005-Issue-51086-Improve-dscreate-instance-name-validatio.patch new file mode 100644 index 0000000..f3d3571 --- /dev/null +++ b/SOURCES/0005-Issue-51086-Improve-dscreate-instance-name-validatio.patch @@ -0,0 +1,96 @@ +From 9710c327b3034d7a9d112306961c9cec98083df5 Mon Sep 17 00:00:00 2001 +From: Simon Pichugin +Date: Mon, 18 May 2020 22:33:45 +0200 +Subject: [PATCH 05/12] Issue 51086 - Improve dscreate instance name validation + +Bug Description: When creating an instance using dscreate, it doesn't enforce +max name length. The ldapi socket name contains name of the instance. If it's +too long, we can hit limits, and the file name will be truncated. Also, it +doesn't sanitize the instance name, it's possible to create an instance with +non-ascii symbols in its name. + +Fix Description: Add more checks to 'dscreate from-file' installation. +Add a limitation for nsslapd-ldapifilepath string lenght because it is +limited by sizeof((*ports_info.i_listenaddr)->local.path)) it is copied to. + +https://pagure.io/389-ds-base/issue/51086 + +Reviewed by: firstyear, mreynolds (Thanks!) +--- + ldap/servers/slapd/libglobs.c | 12 ++++++++++++ + src/cockpit/389-console/src/ds.jsx | 8 ++++++-- + src/lib389/lib389/instance/setup.py | 9 +++++++++ + 3 files changed, 27 insertions(+), 2 deletions(-) + +diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c +index 0d3d9a924..fbf90d92d 100644 +--- a/ldap/servers/slapd/libglobs.c ++++ b/ldap/servers/slapd/libglobs.c +@@ -2390,11 +2390,23 @@ config_set_ldapi_filename(const char *attrname, char *value, char *errorbuf, int + { + int retVal = LDAP_SUCCESS; + slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); ++ /* ++ * LDAPI file path length is limited by sizeof((*ports_info.i_listenaddr)->local.path)) ++ * which is set in main.c inside of "#if defined(ENABLE_LDAPI)" block ++ * ports_info.i_listenaddr is sizeof(PRNetAddr) and our required sizes is 8 bytes less ++ */ ++ size_t result_size = sizeof(PRNetAddr) - 8; + + if (config_value_is_null(attrname, value, errorbuf, 0)) { + return LDAP_OPERATIONS_ERROR; + } + ++ if (strlen(value) >= result_size) { ++ slapi_create_errormsg(errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, "%s: \"%s\" is invalid, its length must be less than %d", ++ attrname, value, result_size); ++ return LDAP_OPERATIONS_ERROR; ++ } ++ + if (apply) { + CFG_LOCK_WRITE(slapdFrontendConfig); + +diff --git a/src/cockpit/389-console/src/ds.jsx b/src/cockpit/389-console/src/ds.jsx +index 90d9e5abd..53aa5cb79 100644 +--- a/src/cockpit/389-console/src/ds.jsx ++++ b/src/cockpit/389-console/src/ds.jsx +@@ -793,10 +793,14 @@ class CreateInstanceModal extends React.Component { + return; + } + newServerId = newServerId.replace(/^slapd-/i, ""); // strip "slapd-" +- if (newServerId.length > 128) { ++ if (newServerId === "admin") { ++ addNotification("warning", "Instance Name 'admin' is reserved, please choose a different name"); ++ return; ++ } ++ if (newServerId.length > 80) { + addNotification( + "warning", +- "Instance name is too long, it must not exceed 128 characters" ++ "Instance name is too long, it must not exceed 80 characters" + ); + return; + } +diff --git a/src/lib389/lib389/instance/setup.py b/src/lib389/lib389/instance/setup.py +index 803992275..f5fc5495d 100644 +--- a/src/lib389/lib389/instance/setup.py ++++ b/src/lib389/lib389/instance/setup.py +@@ -567,6 +567,15 @@ class SetupDs(object): + + # We need to know the prefix before we can do the instance checks + assert_c(slapd['instance_name'] is not None, "Configuration instance_name in section [slapd] not found") ++ assert_c(len(slapd['instance_name']) <= 80, "Server identifier should not be longer than 80 symbols") ++ assert_c(all(ord(c) < 128 for c in slapd['instance_name']), "Server identifier can not contain non ascii characters") ++ assert_c(' ' not in slapd['instance_name'], "Server identifier can not contain a space") ++ assert_c(slapd['instance_name'] != 'admin', "Server identifier \"admin\" is reserved, please choose a different identifier") ++ ++ # Check that valid characters are used ++ safe = re.compile(r'^[#%:\w@_-]+$').search ++ assert_c(bool(safe(slapd['instance_name'])), "Server identifier has invalid characters, please choose a different value") ++ + # Check if the instance exists or not. + # Should I move this import? I think this prevents some recursion + from lib389 import DirSrv +-- +2.26.2 + diff --git a/SOURCES/0006-Issue-51102-RFE-ds-replcheck-make-online-timeout-con.patch b/SOURCES/0006-Issue-51102-RFE-ds-replcheck-make-online-timeout-con.patch new file mode 100644 index 0000000..5bb0635 --- /dev/null +++ b/SOURCES/0006-Issue-51102-RFE-ds-replcheck-make-online-timeout-con.patch @@ -0,0 +1,254 @@ +From c0cb15445c1434b3d317b1c06ab1a0ba8dbc6f04 Mon Sep 17 00:00:00 2001 +From: Mark Reynolds +Date: Tue, 19 May 2020 15:11:53 -0400 +Subject: [PATCH 06/12] Issue 51102 - RFE - ds-replcheck - make online timeout + configurable + +Bug Description: When doing an online check with replicas that are very + far apart the connection can time out as the hardcoded + timeout is 5 seconds. + +Fix Description: Change the default timeout to never timeout, and add an + CLI option to specify a specific timeout. + + Also caught all the possible LDAP exceptions so we can + cleanly "fail". Fixed some python syntax issues, and + improved the entry inconsistency report + +relates: https://pagure.io/389-ds-base/issue/51102 + +Reviewed by: firstyear & spichugi(Thanks!) +--- + ldap/admin/src/scripts/ds-replcheck | 90 ++++++++++++++++++----------- + 1 file changed, 57 insertions(+), 33 deletions(-) + +diff --git a/ldap/admin/src/scripts/ds-replcheck b/ldap/admin/src/scripts/ds-replcheck +index 30bcfd65d..5bb7dfce3 100755 +--- a/ldap/admin/src/scripts/ds-replcheck ++++ b/ldap/admin/src/scripts/ds-replcheck +@@ -1,7 +1,7 @@ + #!/usr/bin/python3 + + # --- BEGIN COPYRIGHT BLOCK --- +-# Copyright (C) 2018 Red Hat, Inc. ++# Copyright (C) 2020 Red Hat, Inc. + # All rights reserved. + # + # License: GPL (version 3 or any later version). +@@ -21,10 +21,9 @@ import getpass + import signal + from ldif import LDIFRecordList + from ldap.ldapobject import SimpleLDAPObject +-from ldap.cidict import cidict + from ldap.controls import SimplePagedResultsControl + from lib389._entry import Entry +-from lib389.utils import ensure_str, ensure_list_str, ensure_int ++from lib389.utils import ensure_list_str, ensure_int + + VERSION = "2.0" + RUV_FILTER = '(&(nsuniqueid=ffffffff-ffffffff-ffffffff-ffffffff)(objectclass=nstombstone))' +@@ -185,11 +184,11 @@ def report_conflict(entry, attr, opts): + report = True + + if 'nscpentrywsi' in entry.data: +- found = False + for val in entry.data['nscpentrywsi']: + if val.lower().startswith(attr + ';'): + if (opts['starttime'] - extract_time(val)) <= opts['lag']: + report = False ++ break + + return report + +@@ -321,6 +320,9 @@ def ldif_search(LDIF, dn): + count = 0 + ignore_list = ['conflictcsn', 'modifytimestamp', 'modifiersname'] + val = "" ++ attr = "" ++ state_attr = "" ++ part_dn = "" + result['entry'] = None + result['conflict'] = None + result['tombstone'] = False +@@ -570,6 +572,7 @@ def cmp_entry(mentry, rentry, opts): + if val.lower().startswith(mattr + ';'): + if not found: + diff['diff'].append(" Master:") ++ diff['diff'].append(" - Value: %s" % (val.split(':')[1].lstrip())) + diff['diff'].append(" - State Info: %s" % (val)) + diff['diff'].append(" - Date: %s\n" % (time.ctime(extract_time(val)))) + found = True +@@ -588,6 +591,7 @@ def cmp_entry(mentry, rentry, opts): + if val.lower().startswith(mattr + ';'): + if not found: + diff['diff'].append(" Replica:") ++ diff['diff'].append(" - Value: %s" % (val.split(':')[1].lstrip())) + diff['diff'].append(" - State Info: %s" % (val)) + diff['diff'].append(" - Date: %s\n" % (time.ctime(extract_time(val)))) + found = True +@@ -654,7 +658,6 @@ def do_offline_report(opts, output_file=None): + rconflicts = [] + rtombstones = 0 + mtombstones = 0 +- idx = 0 + + # Open LDIF files + try: +@@ -926,7 +929,7 @@ def validate_suffix(ldapnode, suffix, hostname): + :return - True if suffix exists, otherwise False + """ + try: +- master_basesuffix = ldapnode.search_s(suffix, ldap.SCOPE_BASE ) ++ ldapnode.search_s(suffix, ldap.SCOPE_BASE) + except ldap.NO_SUCH_OBJECT: + print("Error: Failed to validate suffix in {}. {} does not exist.".format(hostname, suffix)) + return False +@@ -968,12 +971,12 @@ def connect_to_replicas(opts): + replica = SimpleLDAPObject(ruri) + + # Set timeouts +- master.set_option(ldap.OPT_NETWORK_TIMEOUT,5.0) +- master.set_option(ldap.OPT_TIMEOUT,5.0) +- replica.set_option(ldap.OPT_NETWORK_TIMEOUT,5.0) +- replica.set_option(ldap.OPT_TIMEOUT,5.0) ++ master.set_option(ldap.OPT_NETWORK_TIMEOUT, opts['timeout']) ++ master.set_option(ldap.OPT_TIMEOUT, opts['timeout']) ++ replica.set_option(ldap.OPT_NETWORK_TIMEOUT, opts['timeout']) ++ replica.set_option(ldap.OPT_TIMEOUT, opts['timeout']) + +- # Setup Secure Conenction ++ # Setup Secure Connection + if opts['certdir'] is not None: + # Setup Master + if opts['mprotocol'] != LDAPI: +@@ -1003,7 +1006,7 @@ def connect_to_replicas(opts): + try: + master.simple_bind_s(opts['binddn'], opts['bindpw']) + except ldap.SERVER_DOWN as e: +- print("Cannot connect to %r" % muri) ++ print(f"Cannot connect to {muri} ({str(e)})") + sys.exit(1) + except ldap.LDAPError as e: + print("Error: Failed to authenticate to Master: ({}). " +@@ -1014,7 +1017,7 @@ def connect_to_replicas(opts): + try: + replica.simple_bind_s(opts['binddn'], opts['bindpw']) + except ldap.SERVER_DOWN as e: +- print("Cannot connect to %r" % ruri) ++ print(f"Cannot connect to {ruri} ({str(e)})") + sys.exit(1) + except ldap.LDAPError as e: + print("Error: Failed to authenticate to Replica: ({}). " +@@ -1218,7 +1221,6 @@ def do_online_report(opts, output_file=None): + """ + m_done = False + r_done = False +- done = False + report = {} + report['diff'] = [] + report['m_missing'] = [] +@@ -1257,15 +1259,22 @@ def do_online_report(opts, output_file=None): + + # Read the results and start comparing + while not m_done or not r_done: +- if not m_done: +- m_rtype, m_rdata, m_rmsgid, m_rctrls = master.result3(master_msgid) +- elif not r_done: +- m_rdata = [] +- +- if not r_done: +- r_rtype, r_rdata, r_rmsgid, r_rctrls = replica.result3(replica_msgid) +- elif not m_done: +- r_rdata = [] ++ try: ++ if not m_done: ++ m_rtype, m_rdata, m_rmsgid, m_rctrls = master.result3(master_msgid) ++ elif not r_done: ++ m_rdata = [] ++ except ldap.LDAPError as e: ++ print("Error: Problem getting the results from the master: %s", str(e)) ++ sys.exit(1) ++ try: ++ if not r_done: ++ r_rtype, r_rdata, r_rmsgid, r_rctrls = replica.result3(replica_msgid) ++ elif not m_done: ++ r_rdata = [] ++ except ldap.LDAPError as e: ++ print("Error: Problem getting the results from the replica: %s", str(e)) ++ sys.exit(1) + + # Convert entries + mresult = convert_entries(m_rdata) +@@ -1291,11 +1300,15 @@ def do_online_report(opts, output_file=None): + ] + if m_pctrls: + if m_pctrls[0].cookie: +- # Copy cookie from response control to request control +- req_pr_ctrl.cookie = m_pctrls[0].cookie +- master_msgid = master.search_ext(opts['suffix'], ldap.SCOPE_SUBTREE, +- "(|(objectclass=*)(objectclass=ldapsubentry))", +- ['*', 'createtimestamp', 'nscpentrywsi', 'conflictcsn', 'nsds5replconflict'], serverctrls=controls) ++ try: ++ # Copy cookie from response control to request control ++ req_pr_ctrl.cookie = m_pctrls[0].cookie ++ master_msgid = master.search_ext(opts['suffix'], ldap.SCOPE_SUBTREE, ++ "(|(objectclass=*)(objectclass=ldapsubentry))", ++ ['*', 'createtimestamp', 'nscpentrywsi', 'conflictcsn', 'nsds5replconflict'], serverctrls=controls) ++ except ldap.LDAPError as e: ++ print("Error: Problem searching the master: %s", str(e)) ++ sys.exit(1) + else: + m_done = True # No more pages available + else: +@@ -1311,11 +1324,15 @@ def do_online_report(opts, output_file=None): + + if r_pctrls: + if r_pctrls[0].cookie: +- # Copy cookie from response control to request control +- req_pr_ctrl.cookie = r_pctrls[0].cookie +- replica_msgid = replica.search_ext(opts['suffix'], ldap.SCOPE_SUBTREE, +- "(|(objectclass=*)(objectclass=ldapsubentry))", +- ['*', 'createtimestamp', 'nscpentrywsi', 'conflictcsn', 'nsds5replconflict'], serverctrls=controls) ++ try: ++ # Copy cookie from response control to request control ++ req_pr_ctrl.cookie = r_pctrls[0].cookie ++ replica_msgid = replica.search_ext(opts['suffix'], ldap.SCOPE_SUBTREE, ++ "(|(objectclass=*)(objectclass=ldapsubentry))", ++ ['*', 'createtimestamp', 'nscpentrywsi', 'conflictcsn', 'nsds5replconflict'], serverctrls=controls) ++ except ldap.LDAPError as e: ++ print("Error: Problem searching the replica: %s", str(e)) ++ sys.exit(1) + else: + r_done = True # No more pages available + else: +@@ -1426,6 +1443,9 @@ def init_online_params(args): + # prompt for password + opts['bindpw'] = getpass.getpass('Enter password: ') + ++ # lastly handle the timeout ++ opts['timeout'] = int(args.timeout) ++ + return opts + + +@@ -1553,6 +1573,8 @@ def main(): + state_parser.add_argument('-y', '--pass-file', help='A text file containing the clear text password for the bind dn', dest='pass_file', default=None) + state_parser.add_argument('-Z', '--cert-dir', help='The certificate database directory for secure connections', + dest='certdir', default=None) ++ state_parser.add_argument('-t', '--timeout', help='The timeout for the LDAP connections. Default is no timeout.', ++ type=int, dest='timeout', default=-1) + + # Online mode + online_parser = subparsers.add_parser('online', help="Compare two online replicas for differences") +@@ -1577,6 +1599,8 @@ def main(): + online_parser.add_argument('-p', '--page-size', help='The paged-search result grouping size (default 500 entries)', + dest='pagesize', default=500) + online_parser.add_argument('-o', '--out-file', help='The output file', dest='file', default=None) ++ online_parser.add_argument('-t', '--timeout', help='The timeout for the LDAP connections. Default is no timeout.', ++ type=int, dest='timeout', default=-1) + + # Offline LDIF mode + offline_parser = subparsers.add_parser('offline', help="Compare two replication LDIF files for differences (LDIF file generated by 'db2ldif -r')") +-- +2.26.2 + diff --git a/SOURCES/0006-Ticket-50741-bdb_start-Detected-Disorderly-Shutdown-.patch b/SOURCES/0006-Ticket-50741-bdb_start-Detected-Disorderly-Shutdown-.patch deleted file mode 100644 index f50b46c..0000000 --- a/SOURCES/0006-Ticket-50741-bdb_start-Detected-Disorderly-Shutdown-.patch +++ /dev/null @@ -1,74 +0,0 @@ -From b5d7a0b34d532335da7171dd7a308f95638c91c8 Mon Sep 17 00:00:00 2001 -From: Thierry Bordaz -Date: Tue, 19 Nov 2019 09:56:46 +0100 -Subject: [PATCH] Ticket 50741 - bdb_start - Detected Disorderly Shutdown last - time Directory Server was running - -Bug description: - At startup plugins are started (plugin_dependency_startall) including ldbm database - that read/remove the guardian file (bdb_start). - If one of the plugin fails to start, for example because of a missing dependency, - the statup function just exits without recreating the guardian file. - The next restart will not find the guardian file, trigger a recovery and - log the alarming message "Detected Disorderly Shutdown last time Directory Server was running..." - -Fix description: - In case the startup function fails it should call the closing function of all - started plugin: plugin_closeall - The fix also contains fixes for plugin acceptance tests. If DS startup is expected - to fail, it is caught by subprocess.CalledProcessError but actually the startup - function can also return ValueError exception - -https://pagure.io/389-ds-base/issue/50741 - -Reviewed By: Mark Reynolds ---- - dirsrvtests/tests/suites/plugins/acceptance_test.py | 6 +++--- - ldap/servers/slapd/plugin.c | 1 + - 2 files changed, 4 insertions(+), 3 deletions(-) - -diff --git a/dirsrvtests/tests/suites/plugins/acceptance_test.py b/dirsrvtests/tests/suites/plugins/acceptance_test.py -index 8aacb74be..cdb629eef 100644 ---- a/dirsrvtests/tests/suites/plugins/acceptance_test.py -+++ b/dirsrvtests/tests/suites/plugins/acceptance_test.py -@@ -64,7 +64,7 @@ def check_dependency(inst, plugin, online=True): - acct_usability.remove('nsslapd-plugin-depends-on-named', plugin.rdn) - else: - plugin.disable() -- with pytest.raises(subprocess.CalledProcessError): -+ with pytest.raises((subprocess.CalledProcessError, ValueError)): - inst.restart() - dse_ldif = DSEldif(inst) - dse_ldif.delete(acct_usability.dn, 'nsslapd-plugin-depends-on-named') -@@ -1739,14 +1739,14 @@ def test_rootdn(topo, args=None): - # First, test that invalid plugin changes are rejected - if args is None: - plugin.replace('rootdn-deny-ip', '12.12.ZZZ.12') -- with pytest.raises(subprocess.CalledProcessError): -+ with pytest.raises((subprocess.CalledProcessError, ValueError)): - inst.restart() - dse_ldif = DSEldif(inst) - dse_ldif.delete(plugin.dn, 'rootdn-deny-ip') - _rootdn_restart(inst) - - plugin.replace('rootdn-allow-host', 'host._.com') -- with pytest.raises(subprocess.CalledProcessError): -+ with pytest.raises((subprocess.CalledProcessError, ValueError)): - inst.restart() - dse_ldif = DSEldif(inst) - dse_ldif.delete(plugin.dn, 'rootdn-allow-host') -diff --git a/ldap/servers/slapd/plugin.c b/ldap/servers/slapd/plugin.c -index a77bb5aa7..b00c1bd8f 100644 ---- a/ldap/servers/slapd/plugin.c -+++ b/ldap/servers/slapd/plugin.c -@@ -1811,6 +1811,7 @@ plugin_dependency_startall(int argc, char **argv, char *errmsg __attribute__((un - } - i++; - } -+ plugin_closeall(1 /* Close Backends */, 1 /* Close Globals */); - exit(1); - } - --- -2.21.1 - diff --git a/SOURCES/0007-Issue-51110-Fix-ASAN-ODR-warnings.patch b/SOURCES/0007-Issue-51110-Fix-ASAN-ODR-warnings.patch new file mode 100644 index 0000000..df8423c --- /dev/null +++ b/SOURCES/0007-Issue-51110-Fix-ASAN-ODR-warnings.patch @@ -0,0 +1,428 @@ +From a1cd3cf8e8b6b33ab21d5338921187a76dd9dcd0 Mon Sep 17 00:00:00 2001 +From: Mark Reynolds +Date: Fri, 22 May 2020 15:41:45 -0400 +Subject: [PATCH 07/12] Issue 51110 - Fix ASAN ODR warnings + +Description: Fixed ODR issues with glboal attributes which were duplicated from + the core server into the replication and retrocl plugins. + +relates: https://pagure.io/389-ds-base/issue/51110 + +Reviewed by: firstyear(Thanks!) +--- + ldap/servers/plugins/replication/repl5.h | 17 +++--- + .../plugins/replication/repl_globals.c | 17 +++--- + ldap/servers/plugins/replication/replutil.c | 16 +++--- + ldap/servers/plugins/retrocl/retrocl.h | 22 ++++---- + ldap/servers/plugins/retrocl/retrocl_cn.c | 12 ++--- + ldap/servers/plugins/retrocl/retrocl_po.c | 52 +++++++++---------- + ldap/servers/plugins/retrocl/retrocl_trim.c | 30 +++++------ + 7 files changed, 82 insertions(+), 84 deletions(-) + +diff --git a/ldap/servers/plugins/replication/repl5.h b/ldap/servers/plugins/replication/repl5.h +index 873dd8a16..72b7089e3 100644 +--- a/ldap/servers/plugins/replication/repl5.h ++++ b/ldap/servers/plugins/replication/repl5.h +@@ -280,15 +280,14 @@ struct berval *NSDS90StartReplicationRequest_new(const char *protocol_oid, + int multimaster_extop_NSDS50ReplicationEntry(Slapi_PBlock *pb); + + /* From repl_globals.c */ +-extern char *attr_changenumber; +-extern char *attr_targetdn; +-extern char *attr_changetype; +-extern char *attr_newrdn; +-extern char *attr_deleteoldrdn; +-extern char *attr_changes; +-extern char *attr_newsuperior; +-extern char *attr_changetime; +-extern char *attr_dataversion; ++extern char *repl_changenumber; ++extern char *repl_targetdn; ++extern char *repl_changetype; ++extern char *repl_newrdn; ++extern char *repl_deleteoldrdn; ++extern char *repl_changes; ++extern char *repl_newsuperior; ++extern char *repl_changetime; + extern char *attr_csn; + extern char *changetype_add; + extern char *changetype_delete; +diff --git a/ldap/servers/plugins/replication/repl_globals.c b/ldap/servers/plugins/replication/repl_globals.c +index 355a0ffa1..c615c77da 100644 +--- a/ldap/servers/plugins/replication/repl_globals.c ++++ b/ldap/servers/plugins/replication/repl_globals.c +@@ -48,15 +48,14 @@ char *changetype_delete = CHANGETYPE_DELETE; + char *changetype_modify = CHANGETYPE_MODIFY; + char *changetype_modrdn = CHANGETYPE_MODRDN; + char *changetype_moddn = CHANGETYPE_MODDN; +-char *attr_changenumber = ATTR_CHANGENUMBER; +-char *attr_targetdn = ATTR_TARGETDN; +-char *attr_changetype = ATTR_CHANGETYPE; +-char *attr_newrdn = ATTR_NEWRDN; +-char *attr_deleteoldrdn = ATTR_DELETEOLDRDN; +-char *attr_changes = ATTR_CHANGES; +-char *attr_newsuperior = ATTR_NEWSUPERIOR; +-char *attr_changetime = ATTR_CHANGETIME; +-char *attr_dataversion = ATTR_DATAVERSION; ++char *repl_changenumber = ATTR_CHANGENUMBER; ++char *repl_targetdn = ATTR_TARGETDN; ++char *repl_changetype = ATTR_CHANGETYPE; ++char *repl_newrdn = ATTR_NEWRDN; ++char *repl_deleteoldrdn = ATTR_DELETEOLDRDN; ++char *repl_changes = ATTR_CHANGES; ++char *repl_newsuperior = ATTR_NEWSUPERIOR; ++char *repl_changetime = ATTR_CHANGETIME; + char *attr_csn = ATTR_CSN; + char *type_copyingFrom = TYPE_COPYINGFROM; + char *type_copiedFrom = TYPE_COPIEDFROM; +diff --git a/ldap/servers/plugins/replication/replutil.c b/ldap/servers/plugins/replication/replutil.c +index de1e77880..39f821d12 100644 +--- a/ldap/servers/plugins/replication/replutil.c ++++ b/ldap/servers/plugins/replication/replutil.c +@@ -64,14 +64,14 @@ get_cleattrs() + { + if (cleattrs[0] == NULL) { + cleattrs[0] = type_objectclass; +- cleattrs[1] = attr_changenumber; +- cleattrs[2] = attr_targetdn; +- cleattrs[3] = attr_changetype; +- cleattrs[4] = attr_newrdn; +- cleattrs[5] = attr_deleteoldrdn; +- cleattrs[6] = attr_changes; +- cleattrs[7] = attr_newsuperior; +- cleattrs[8] = attr_changetime; ++ cleattrs[1] = repl_changenumber; ++ cleattrs[2] = repl_targetdn; ++ cleattrs[3] = repl_changetype; ++ cleattrs[4] = repl_newrdn; ++ cleattrs[5] = repl_deleteoldrdn; ++ cleattrs[6] = repl_changes; ++ cleattrs[7] = repl_newsuperior; ++ cleattrs[8] = repl_changetime; + cleattrs[9] = NULL; + } + return cleattrs; +diff --git a/ldap/servers/plugins/retrocl/retrocl.h b/ldap/servers/plugins/retrocl/retrocl.h +index 06482a14c..2ce76fcec 100644 +--- a/ldap/servers/plugins/retrocl/retrocl.h ++++ b/ldap/servers/plugins/retrocl/retrocl.h +@@ -94,17 +94,17 @@ extern int retrocl_nattributes; + extern char **retrocl_attributes; + extern char **retrocl_aliases; + +-extern const char *attr_changenumber; +-extern const char *attr_targetdn; +-extern const char *attr_changetype; +-extern const char *attr_newrdn; +-extern const char *attr_newsuperior; +-extern const char *attr_deleteoldrdn; +-extern const char *attr_changes; +-extern const char *attr_changetime; +-extern const char *attr_objectclass; +-extern const char *attr_nsuniqueid; +-extern const char *attr_isreplicated; ++extern const char *retrocl_changenumber; ++extern const char *retrocl_targetdn; ++extern const char *retrocl_changetype; ++extern const char *retrocl_newrdn; ++extern const char *retrocl_newsuperior; ++extern const char *retrocl_deleteoldrdn; ++extern const char *retrocl_changes; ++extern const char *retrocl_changetime; ++extern const char *retrocl_objectclass; ++extern const char *retrocl_nsuniqueid; ++extern const char *retrocl_isreplicated; + + extern PRLock *retrocl_internal_lock; + extern Slapi_RWLock *retrocl_cn_lock; +diff --git a/ldap/servers/plugins/retrocl/retrocl_cn.c b/ldap/servers/plugins/retrocl/retrocl_cn.c +index 709d7a857..5fc5f586d 100644 +--- a/ldap/servers/plugins/retrocl/retrocl_cn.c ++++ b/ldap/servers/plugins/retrocl/retrocl_cn.c +@@ -62,7 +62,7 @@ handle_cnum_entry(Slapi_Entry *e, void *callback_data) + Slapi_Attr *chattr = NULL; + sval = NULL; + value = NULL; +- if (slapi_entry_attr_find(e, attr_changenumber, &chattr) == 0) { ++ if (slapi_entry_attr_find(e, retrocl_changenumber, &chattr) == 0) { + slapi_attr_first_value(chattr, &sval); + if (NULL != sval) { + value = slapi_value_get_berval(sval); +@@ -79,7 +79,7 @@ handle_cnum_entry(Slapi_Entry *e, void *callback_data) + chattr = NULL; + sval = NULL; + value = NULL; +- if (slapi_entry_attr_find(e, attr_changetime, &chattr) == 0) { ++ if (slapi_entry_attr_find(e, retrocl_changetime, &chattr) == 0) { + slapi_attr_first_value(chattr, &sval); + if (NULL != sval) { + value = slapi_value_get_berval(sval); +@@ -134,7 +134,7 @@ retrocl_get_changenumbers(void) + cr.cr_time = 0; + + slapi_seq_callback(RETROCL_CHANGELOG_DN, SLAPI_SEQ_FIRST, +- (char *)attr_changenumber, /* cast away const */ ++ (char *)retrocl_changenumber, /* cast away const */ + NULL, NULL, 0, &cr, NULL, handle_cnum_result, + handle_cnum_entry, NULL); + +@@ -144,7 +144,7 @@ retrocl_get_changenumbers(void) + slapi_ch_free((void **)&cr.cr_time); + + slapi_seq_callback(RETROCL_CHANGELOG_DN, SLAPI_SEQ_LAST, +- (char *)attr_changenumber, /* cast away const */ ++ (char *)retrocl_changenumber, /* cast away const */ + NULL, NULL, 0, &cr, NULL, handle_cnum_result, + handle_cnum_entry, NULL); + +@@ -185,7 +185,7 @@ retrocl_getchangetime(int type, int *err) + return NO_TIME; + } + slapi_seq_callback(RETROCL_CHANGELOG_DN, type, +- (char *)attr_changenumber, /* cast away const */ ++ (char *)retrocl_changenumber, /* cast away const */ + NULL, + NULL, 0, &cr, NULL, + handle_cnum_result, handle_cnum_entry, NULL); +@@ -353,7 +353,7 @@ retrocl_update_lastchangenumber(void) + cr.cr_cnum = 0; + cr.cr_time = 0; + slapi_seq_callback(RETROCL_CHANGELOG_DN, SLAPI_SEQ_LAST, +- (char *)attr_changenumber, /* cast away const */ ++ (char *)retrocl_changenumber, /* cast away const */ + NULL, NULL, 0, &cr, NULL, handle_cnum_result, + handle_cnum_entry, NULL); + +diff --git a/ldap/servers/plugins/retrocl/retrocl_po.c b/ldap/servers/plugins/retrocl/retrocl_po.c +index d2af79b31..e1488f56b 100644 +--- a/ldap/servers/plugins/retrocl/retrocl_po.c ++++ b/ldap/servers/plugins/retrocl/retrocl_po.c +@@ -25,17 +25,17 @@ modrdn2reple(Slapi_Entry *e, const char *newrdn, int deloldrdn, LDAPMod **ldm, c + + /******************************/ + +-const char *attr_changenumber = "changenumber"; +-const char *attr_targetdn = "targetdn"; +-const char *attr_changetype = "changetype"; +-const char *attr_newrdn = "newrdn"; +-const char *attr_deleteoldrdn = "deleteoldrdn"; +-const char *attr_changes = "changes"; +-const char *attr_newsuperior = "newsuperior"; +-const char *attr_changetime = "changetime"; +-const char *attr_objectclass = "objectclass"; +-const char *attr_nsuniqueid = "nsuniqueid"; +-const char *attr_isreplicated = "isreplicated"; ++const char *retrocl_changenumber = "changenumber"; ++const char *retrocl_targetdn = "targetdn"; ++const char *retrocl_changetype = "changetype"; ++const char *retrocl_newrdn = "newrdn"; ++const char *retrocl_deleteoldrdn = "deleteoldrdn"; ++const char *retrocl_changes = "changes"; ++const char *retrocl_newsuperior = "newsuperior"; ++const char *retrocl_changetime = "changetime"; ++const char *retrocl_objectclass = "objectclass"; ++const char *retrocl_nsuniqueid = "nsuniqueid"; ++const char *retrocl_isreplicated = "isreplicated"; + + /* + * Function: make_changes_string +@@ -185,7 +185,7 @@ write_replog_db( + changenum, dn); + + /* Construct the dn of this change record */ +- edn = slapi_ch_smprintf("%s=%lu,%s", attr_changenumber, changenum, RETROCL_CHANGELOG_DN); ++ edn = slapi_ch_smprintf("%s=%lu,%s", retrocl_changenumber, changenum, RETROCL_CHANGELOG_DN); + + /* + * Create the entry struct, and fill in fields common to all types +@@ -214,7 +214,7 @@ write_replog_db( + attributeAlias = attributeName; + } + +- if (strcasecmp(attributeName, attr_nsuniqueid) == 0) { ++ if (strcasecmp(attributeName, retrocl_nsuniqueid) == 0) { + Slapi_Entry *entry = NULL; + const char *uniqueId = NULL; + +@@ -236,7 +236,7 @@ write_replog_db( + + extensibleObject = 1; + +- } else if (strcasecmp(attributeName, attr_isreplicated) == 0) { ++ } else if (strcasecmp(attributeName, retrocl_isreplicated) == 0) { + int isReplicated = 0; + char *attributeValue = NULL; + +@@ -298,17 +298,17 @@ write_replog_db( + sprintf(chnobuf, "%lu", changenum); + val.bv_val = chnobuf; + val.bv_len = strlen(chnobuf); +- slapi_entry_add_values(e, attr_changenumber, vals); ++ slapi_entry_add_values(e, retrocl_changenumber, vals); + + /* Set the targetentrydn attribute */ + val.bv_val = dn; + val.bv_len = strlen(dn); +- slapi_entry_add_values(e, attr_targetdn, vals); ++ slapi_entry_add_values(e, retrocl_targetdn, vals); + + /* Set the changeTime attribute */ + val.bv_val = format_genTime(curtime); + val.bv_len = strlen(val.bv_val); +- slapi_entry_add_values(e, attr_changetime, vals); ++ slapi_entry_add_values(e, retrocl_changetime, vals); + slapi_ch_free((void **)&val.bv_val); + + /* +@@ -344,7 +344,7 @@ write_replog_db( + /* Set the changetype attribute */ + val.bv_val = "delete"; + val.bv_len = 6; +- slapi_entry_add_values(e, attr_changetype, vals); ++ slapi_entry_add_values(e, retrocl_changetype, vals); + } + break; + +@@ -422,7 +422,7 @@ entry2reple(Slapi_Entry *e, Slapi_Entry *oe, int optype) + } else { + return (1); + } +- slapi_entry_add_values(e, attr_changetype, vals); ++ slapi_entry_add_values(e, retrocl_changetype, vals); + + estr = slapi_entry2str(oe, &len); + p = estr; +@@ -435,7 +435,7 @@ entry2reple(Slapi_Entry *e, Slapi_Entry *oe, int optype) + } + val.bv_val = p; + val.bv_len = len - (p - estr); /* length + terminating \0 */ +- slapi_entry_add_values(e, attr_changes, vals); ++ slapi_entry_add_values(e, retrocl_changes, vals); + slapi_ch_free_string(&estr); + return 0; + } +@@ -471,7 +471,7 @@ mods2reple(Slapi_Entry *e, LDAPMod **ldm) + if (NULL != l) { + val.bv_val = l->ls_buf; + val.bv_len = l->ls_len + 1; /* string + terminating \0 */ +- slapi_entry_add_values(e, attr_changes, vals); ++ slapi_entry_add_values(e, retrocl_changes, vals); + lenstr_free(&l); + } + } +@@ -511,12 +511,12 @@ modrdn2reple( + + val.bv_val = "modrdn"; + val.bv_len = 6; +- slapi_entry_add_values(e, attr_changetype, vals); ++ slapi_entry_add_values(e, retrocl_changetype, vals); + + if (newrdn) { + val.bv_val = (char *)newrdn; /* cast away const */ + val.bv_len = strlen(newrdn); +- slapi_entry_add_values(e, attr_newrdn, vals); ++ slapi_entry_add_values(e, retrocl_newrdn, vals); + } + + if (deloldrdn == 0) { +@@ -526,12 +526,12 @@ modrdn2reple( + val.bv_val = "TRUE"; + val.bv_len = 4; + } +- slapi_entry_add_values(e, attr_deleteoldrdn, vals); ++ slapi_entry_add_values(e, retrocl_deleteoldrdn, vals); + + if (newsuperior) { + val.bv_val = (char *)newsuperior; /* cast away const */ + val.bv_len = strlen(newsuperior); +- slapi_entry_add_values(e, attr_newsuperior, vals); ++ slapi_entry_add_values(e, retrocl_newsuperior, vals); + } + + if (NULL != ldm) { +@@ -540,7 +540,7 @@ modrdn2reple( + if (l->ls_len) { + val.bv_val = l->ls_buf; + val.bv_len = l->ls_len; +- slapi_entry_add_values(e, attr_changes, vals); ++ slapi_entry_add_values(e, retrocl_changes, vals); + } + lenstr_free(&l); + } +diff --git a/ldap/servers/plugins/retrocl/retrocl_trim.c b/ldap/servers/plugins/retrocl/retrocl_trim.c +index 0378eb7f6..d031dc3f8 100644 +--- a/ldap/servers/plugins/retrocl/retrocl_trim.c ++++ b/ldap/servers/plugins/retrocl/retrocl_trim.c +@@ -49,15 +49,15 @@ static const char ** + get_cleattrs(void) + { + if (cleattrs[0] == NULL) { +- cleattrs[0] = attr_objectclass; +- cleattrs[1] = attr_changenumber; +- cleattrs[2] = attr_targetdn; +- cleattrs[3] = attr_changetype; +- cleattrs[4] = attr_newrdn; +- cleattrs[5] = attr_deleteoldrdn; +- cleattrs[6] = attr_changes; +- cleattrs[7] = attr_newsuperior; +- cleattrs[8] = attr_changetime; ++ cleattrs[0] = retrocl_objectclass; ++ cleattrs[1] = retrocl_changenumber; ++ cleattrs[2] = retrocl_targetdn; ++ cleattrs[3] = retrocl_changetype; ++ cleattrs[4] = retrocl_newrdn; ++ cleattrs[5] = retrocl_deleteoldrdn; ++ cleattrs[6] = retrocl_changes; ++ cleattrs[7] = retrocl_newsuperior; ++ cleattrs[8] = retrocl_changetime; + cleattrs[9] = NULL; + } + return cleattrs; +@@ -81,7 +81,7 @@ delete_changerecord(changeNumber cnum) + char *dnbuf; + int delrc; + +- dnbuf = slapi_ch_smprintf("%s=%ld, %s", attr_changenumber, cnum, ++ dnbuf = slapi_ch_smprintf("%s=%ld, %s", retrocl_changenumber, cnum, + RETROCL_CHANGELOG_DN); + pb = slapi_pblock_new(); + slapi_delete_internal_set_pb(pb, dnbuf, NULL /*controls*/, NULL /* uniqueid */, +@@ -154,7 +154,7 @@ handle_getchangetime_search(Slapi_Entry *e, void *callback_data) + if (NULL != e) { + Slapi_Value *sval = NULL; + const struct berval *val = NULL; +- rc = slapi_entry_attr_find(e, attr_changetime, &attr); ++ rc = slapi_entry_attr_find(e, retrocl_changetime, &attr); + /* Bug 624442: Logic checking for lack of timestamp was + reversed. */ + if (0 != rc || slapi_attr_first_value(attr, &sval) == -1 || +@@ -174,14 +174,14 @@ handle_getchangetime_search(Slapi_Entry *e, void *callback_data) + /* + * Function: get_changetime + * Arguments: cnum - number of change record to retrieve +- * Returns: Taking the attr_changetime of the 'cnum' entry, ++ * Returns: Taking the retrocl_changetime of the 'cnum' entry, + * it converts it into time_t (parse_localTime) and returns this time value. + * It returns 0 in the following cases: +- * - changerecord entry has not attr_changetime ++ * - changerecord entry has not retrocl_changetime + * - attr_changetime attribute has no value + * - attr_changetime attribute value is empty + * +- * Description: Retrieve attr_changetime ("changetime") from a changerecord whose number is "cnum". ++ * Description: Retrieve retrocl_changetime ("changetime") from a changerecord whose number is "cnum". + */ + static time_t + get_changetime(changeNumber cnum, int *err) +@@ -198,7 +198,7 @@ get_changetime(changeNumber cnum, int *err) + } + crtp->crt_nentries = crtp->crt_err = 0; + crtp->crt_time = 0; +- PR_snprintf(fstr, sizeof(fstr), "%s=%ld", attr_changenumber, cnum); ++ PR_snprintf(fstr, sizeof(fstr), "%s=%ld", retrocl_changenumber, cnum); + + pb = slapi_pblock_new(); + slapi_search_internal_set_pb(pb, RETROCL_CHANGELOG_DN, +-- +2.26.2 + diff --git a/SOURCES/0007-Ticket-50667-dsctl-l-did-not-respect-PREFIX.patch b/SOURCES/0007-Ticket-50667-dsctl-l-did-not-respect-PREFIX.patch deleted file mode 100644 index 071233a..0000000 --- a/SOURCES/0007-Ticket-50667-dsctl-l-did-not-respect-PREFIX.patch +++ /dev/null @@ -1,80 +0,0 @@ -From f77760fb4e39e6d5b673ee8c5388407ff1ae98be Mon Sep 17 00:00:00 2001 -From: William Brown -Date: Wed, 23 Oct 2019 12:01:04 +1000 -Subject: [PATCH] Ticket 50667 - dsctl -l did not respect PREFIX - -Bug Description: dsctl list was not coded to allow -using the paths module. - -Fix Description: Change to the paths module to allow -better and consistent CLI handling. - -https://pagure.io/389-ds-base/issue/50667 - -Author: William Brown - -Review by: mreynolds, spichugi (thanks) ---- - src/lib389/cli/dsctl | 4 ++-- - src/lib389/lib389/cli_ctl/instance.py | 2 +- - src/lib389/lib389/utils.py | 8 ++++++-- - 3 files changed, 9 insertions(+), 5 deletions(-) - -diff --git a/src/lib389/cli/dsctl b/src/lib389/cli/dsctl -index 8b86629ac..47ca8269b 100755 ---- a/src/lib389/cli/dsctl -+++ b/src/lib389/cli/dsctl -@@ -46,8 +46,8 @@ parser.add_argument('-l', '--list', - default=False, action='store_true' - ) - --parser.add_argument('--remove-all', nargs="?", default=False, const=None, -- help="Remove all instances of Directory Server (you can also provide an optional directory prefix for this argument)", -+parser.add_argument('--remove-all', default=False, action='store_true', -+ help=argparse.SUPPRESS - ) - - subparsers = parser.add_subparsers(help="action") -diff --git a/src/lib389/lib389/cli_ctl/instance.py b/src/lib389/lib389/cli_ctl/instance.py -index 95958e14c..f0111f35b 100644 ---- a/src/lib389/lib389/cli_ctl/instance.py -+++ b/src/lib389/lib389/cli_ctl/instance.py -@@ -127,7 +127,7 @@ def instance_remove_all(log, args): - """Remove all instances - clean sweep! - """ - -- inst_names = get_instance_list(args.remove_all) -+ inst_names = get_instance_list() - if len(inst_names) > 0: - answer = input("Are you sure you want to remove all the Directory Server instances? Enter \"Yes\" to continue: ") - if answer != 'Yes': -diff --git a/src/lib389/lib389/utils.py b/src/lib389/lib389/utils.py -index b9eacfdea..587c7b07b 100644 ---- a/src/lib389/lib389/utils.py -+++ b/src/lib389/lib389/utils.py -@@ -1244,9 +1244,10 @@ def get_ldapurl_from_serverid(instance): - return ("ldap://{}:{}".format(host, port), None) - - --def get_instance_list(prefix=None): -+def get_instance_list(): - # List all server instances -- conf_dir = (prefix or "") + "/etc/dirsrv/" -+ paths = Paths() -+ conf_dir = os.path.join(paths.sysconf_dir, 'dirsrv') - insts = [] - try: - for inst in os.listdir(conf_dir): -@@ -1254,6 +1255,9 @@ def get_instance_list(prefix=None): - insts.append(inst) - except OSError as e: - log.error("Failed to check directory: {} - {}".format(conf_dir, str(e))) -+ except IOError as e: -+ log.error(e) -+ log.error("Perhaps you need to be a different user?") - insts.sort() - return insts - --- -2.21.1 - diff --git a/SOURCES/0008-Issue-51095-abort-operation-if-CSN-can-not-be-genera.patch b/SOURCES/0008-Issue-51095-abort-operation-if-CSN-can-not-be-genera.patch new file mode 100644 index 0000000..a85a4bb --- /dev/null +++ b/SOURCES/0008-Issue-51095-abort-operation-if-CSN-can-not-be-genera.patch @@ -0,0 +1,466 @@ +From 8d14ff153e9335b09739438344f9c3c78a496548 Mon Sep 17 00:00:00 2001 +From: Mark Reynolds +Date: Fri, 22 May 2020 10:42:11 -0400 +Subject: [PATCH 08/12] Issue 51095 - abort operation if CSN can not be + generated + +Bug Description: If we fail to get the system time then we were using an + uninitialized timespec struct which could lead to bizarre + times in CSN's. + +Fix description: Check if the system time function fails, and if it does + then abort the update operation. + +relates: https://pagure.io/389-ds-base/issue/51095 + +Reviewed by: firstyear & tbordaz(Thanks!!) +--- + ldap/servers/plugins/replication/repl5.h | 2 +- + .../plugins/replication/repl5_replica.c | 33 ++++++++------ + ldap/servers/slapd/back-ldbm/ldbm_add.c | 8 +++- + ldap/servers/slapd/back-ldbm/ldbm_delete.c | 9 +++- + ldap/servers/slapd/back-ldbm/ldbm_modify.c | 10 ++++- + ldap/servers/slapd/back-ldbm/ldbm_modrdn.c | 8 +++- + ldap/servers/slapd/csngen.c | 18 +++++++- + ldap/servers/slapd/entrywsi.c | 15 ++++--- + ldap/servers/slapd/slap.h | 2 +- + ldap/servers/slapd/slapi-plugin.h | 8 ++++ + ldap/servers/slapd/slapi-private.h | 5 ++- + ldap/servers/slapd/time.c | 43 +++++++++++++------ + 12 files changed, 118 insertions(+), 43 deletions(-) + +diff --git a/ldap/servers/plugins/replication/repl5.h b/ldap/servers/plugins/replication/repl5.h +index 72b7089e3..638471744 100644 +--- a/ldap/servers/plugins/replication/repl5.h ++++ b/ldap/servers/plugins/replication/repl5.h +@@ -776,7 +776,7 @@ void replica_disable_replication(Replica *r); + int replica_start_agreement(Replica *r, Repl_Agmt *ra); + int windows_replica_start_agreement(Replica *r, Repl_Agmt *ra); + +-CSN *replica_generate_next_csn(Slapi_PBlock *pb, const CSN *basecsn); ++int32_t replica_generate_next_csn(Slapi_PBlock *pb, const CSN *basecsn, CSN **opcsn); + int replica_get_attr(Slapi_PBlock *pb, const char *type, void *value); + + /* mapping tree extensions manipulation */ +diff --git a/ldap/servers/plugins/replication/repl5_replica.c b/ldap/servers/plugins/replication/repl5_replica.c +index 02caa88d9..f01782330 100644 +--- a/ldap/servers/plugins/replication/repl5_replica.c ++++ b/ldap/servers/plugins/replication/repl5_replica.c +@@ -3931,11 +3931,9 @@ windows_replica_start_agreement(Replica *r, Repl_Agmt *ra) + * A callback function registered as op->o_csngen_handler and + * called by backend ops to generate opcsn. + */ +-CSN * +-replica_generate_next_csn(Slapi_PBlock *pb, const CSN *basecsn) ++int32_t ++replica_generate_next_csn(Slapi_PBlock *pb, const CSN *basecsn, CSN **opcsn) + { +- CSN *opcsn = NULL; +- + Replica *replica = replica_get_replica_for_op(pb); + if (NULL != replica) { + Slapi_Operation *op; +@@ -3946,17 +3944,26 @@ replica_generate_next_csn(Slapi_PBlock *pb, const CSN *basecsn) + CSNGen *gen = (CSNGen *)object_get_data(gen_obj); + if (NULL != gen) { + /* The new CSN should be greater than the base CSN */ +- csngen_new_csn(gen, &opcsn, PR_FALSE /* don't notify */); +- if (csn_compare(opcsn, basecsn) <= 0) { +- char opcsnstr[CSN_STRSIZE], basecsnstr[CSN_STRSIZE]; ++ if (csngen_new_csn(gen, opcsn, PR_FALSE /* don't notify */) != CSN_SUCCESS) { ++ /* Failed to generate CSN we must abort */ ++ object_release(gen_obj); ++ return -1; ++ } ++ if (csn_compare(*opcsn, basecsn) <= 0) { ++ char opcsnstr[CSN_STRSIZE]; ++ char basecsnstr[CSN_STRSIZE]; + char opcsn2str[CSN_STRSIZE]; + +- csn_as_string(opcsn, PR_FALSE, opcsnstr); ++ csn_as_string(*opcsn, PR_FALSE, opcsnstr); + csn_as_string(basecsn, PR_FALSE, basecsnstr); +- csn_free(&opcsn); ++ csn_free(opcsn); + csngen_adjust_time(gen, basecsn); +- csngen_new_csn(gen, &opcsn, PR_FALSE /* don't notify */); +- csn_as_string(opcsn, PR_FALSE, opcsn2str); ++ if (csngen_new_csn(gen, opcsn, PR_FALSE) != CSN_SUCCESS) { ++ /* Failed to generate CSN we must abort */ ++ object_release(gen_obj); ++ return -1; ++ } ++ csn_as_string(*opcsn, PR_FALSE, opcsn2str); + slapi_log_err(SLAPI_LOG_WARNING, repl_plugin_name, + "replica_generate_next_csn - " + "opcsn=%s <= basecsn=%s, adjusted opcsn=%s\n", +@@ -3966,14 +3973,14 @@ replica_generate_next_csn(Slapi_PBlock *pb, const CSN *basecsn) + * Insert opcsn into the csn pending list. + * This is the notify effect in csngen_new_csn(). + */ +- assign_csn_callback(opcsn, (void *)replica); ++ assign_csn_callback(*opcsn, (void *)replica); + } + object_release(gen_obj); + } + } + } + +- return opcsn; ++ return 0; + } + + /* +diff --git a/ldap/servers/slapd/back-ldbm/ldbm_add.c b/ldap/servers/slapd/back-ldbm/ldbm_add.c +index d0d88bf16..ee366c74c 100644 +--- a/ldap/servers/slapd/back-ldbm/ldbm_add.c ++++ b/ldap/servers/slapd/back-ldbm/ldbm_add.c +@@ -645,7 +645,13 @@ ldbm_back_add(Slapi_PBlock *pb) + * Current op is a user request. Opcsn will be assigned + * if the dn is in an updatable replica. + */ +- opcsn = entry_assign_operation_csn(pb, e, parententry ? parententry->ep_entry : NULL); ++ if (entry_assign_operation_csn(pb, e, parententry ? parententry->ep_entry : NULL, &opcsn) != 0) { ++ slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_add", ++ "failed to generate add CSN for entry (%s), aborting operation\n", ++ slapi_entry_get_dn(e)); ++ ldap_result_code = LDAP_OPERATIONS_ERROR; ++ goto error_return; ++ } + } + if (opcsn != NULL) { + entry_set_csn(e, opcsn); +diff --git a/ldap/servers/slapd/back-ldbm/ldbm_delete.c b/ldap/servers/slapd/back-ldbm/ldbm_delete.c +index 873b5b00e..fbcb57310 100644 +--- a/ldap/servers/slapd/back-ldbm/ldbm_delete.c ++++ b/ldap/servers/slapd/back-ldbm/ldbm_delete.c +@@ -464,7 +464,14 @@ replace_entry: + * by entry_assign_operation_csn() if the dn is in an + * updatable replica. + */ +- opcsn = entry_assign_operation_csn ( pb, e->ep_entry, NULL ); ++ if (entry_assign_operation_csn(pb, e->ep_entry, NULL, &opcsn) != 0) { ++ slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_delete", ++ "failed to generate delete CSN for entry (%s), aborting operation\n", ++ slapi_entry_get_dn(e->ep_entry)); ++ retval = -1; ++ ldap_result_code = LDAP_OPERATIONS_ERROR; ++ goto error_return; ++ } + } + if (opcsn != NULL) { + if (!is_fixup_operation) { +diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modify.c b/ldap/servers/slapd/back-ldbm/ldbm_modify.c +index b0c477e3f..e9d7e87e3 100644 +--- a/ldap/servers/slapd/back-ldbm/ldbm_modify.c ++++ b/ldap/servers/slapd/back-ldbm/ldbm_modify.c +@@ -598,12 +598,18 @@ ldbm_back_modify(Slapi_PBlock *pb) + goto error_return; + } + opcsn = operation_get_csn(operation); +- if (NULL == opcsn && operation->o_csngen_handler) { ++ if (opcsn == NULL && operation->o_csngen_handler) { + /* + * Current op is a user request. Opcsn will be assigned + * if the dn is in an updatable replica. + */ +- opcsn = entry_assign_operation_csn(pb, e->ep_entry, NULL); ++ if (entry_assign_operation_csn(pb, e->ep_entry, NULL, &opcsn) != 0) { ++ slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify", ++ "failed to generate modify CSN for entry (%s), aborting operation\n", ++ slapi_entry_get_dn(e->ep_entry)); ++ ldap_result_code = LDAP_OPERATIONS_ERROR; ++ goto error_return; ++ } + } + if (opcsn) { + entry_set_maxcsn(e->ep_entry, opcsn); +diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c +index 26698012a..fde83c99f 100644 +--- a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c ++++ b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c +@@ -543,7 +543,13 @@ ldbm_back_modrdn(Slapi_PBlock *pb) + * Current op is a user request. Opcsn will be assigned + * if the dn is in an updatable replica. + */ +- opcsn = entry_assign_operation_csn(pb, e->ep_entry, parententry ? parententry->ep_entry : NULL); ++ if (entry_assign_operation_csn(pb, e->ep_entry, parententry ? parententry->ep_entry : NULL, &opcsn) != 0) { ++ slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modrdn", ++ "failed to generate modrdn CSN for entry (%s), aborting operation\n", ++ slapi_entry_get_dn(e->ep_entry)); ++ ldap_result_code = LDAP_OPERATIONS_ERROR; ++ goto error_return; ++ } + } + if (opcsn != NULL) { + entry_set_maxcsn(e->ep_entry, opcsn); +diff --git a/ldap/servers/slapd/csngen.c b/ldap/servers/slapd/csngen.c +index 68dbbda8e..b08d8b25c 100644 +--- a/ldap/servers/slapd/csngen.c ++++ b/ldap/servers/slapd/csngen.c +@@ -164,6 +164,7 @@ csngen_free(CSNGen **gen) + int + csngen_new_csn(CSNGen *gen, CSN **csn, PRBool notify) + { ++ struct timespec now = {0}; + int rc = CSN_SUCCESS; + time_t cur_time; + int delta; +@@ -179,12 +180,25 @@ csngen_new_csn(CSNGen *gen, CSN **csn, PRBool notify) + return CSN_MEMORY_ERROR; + } + +- slapi_rwlock_wrlock(gen->lock); ++ if ((rc = slapi_clock_gettime(&now)) != 0) { ++ /* Failed to get system time, we must abort */ ++ slapi_log_err(SLAPI_LOG_ERR, "csngen_new_csn", ++ "Failed to get system time (%s)\n", ++ slapd_system_strerror(rc)); ++ return CSN_TIME_ERROR; ++ } ++ cur_time = now.tv_sec; + +- cur_time = slapi_current_utc_time(); ++ slapi_rwlock_wrlock(gen->lock); + + /* check if the time should be adjusted */ + delta = cur_time - gen->state.sampled_time; ++ if (delta > _SEC_PER_DAY || delta < (-1 * _SEC_PER_DAY)) { ++ /* We had a jump larger than a day */ ++ slapi_log_err(SLAPI_LOG_INFO, "csngen_new_csn", ++ "Detected large jump in CSN time. Delta: %d (current time: %ld vs previous time: %ld)\n", ++ delta, cur_time, gen->state.sampled_time); ++ } + if (delta > 0) { + rc = _csngen_adjust_local_time(gen, cur_time); + if (rc != CSN_SUCCESS) { +diff --git a/ldap/servers/slapd/entrywsi.c b/ldap/servers/slapd/entrywsi.c +index 5d1d7238a..31bf65d8e 100644 +--- a/ldap/servers/slapd/entrywsi.c ++++ b/ldap/servers/slapd/entrywsi.c +@@ -224,13 +224,12 @@ entry_add_rdn_csn(Slapi_Entry *e, const CSN *csn) + slapi_rdn_free(&rdn); + } + +-CSN * +-entry_assign_operation_csn(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *parententry) ++int32_t ++entry_assign_operation_csn(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *parententry, CSN **opcsn) + { + Slapi_Operation *op; + const CSN *basecsn = NULL; + const CSN *parententry_dncsn = NULL; +- CSN *opcsn = NULL; + + slapi_pblock_get(pb, SLAPI_OPERATION, &op); + +@@ -252,14 +251,16 @@ entry_assign_operation_csn(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *parent + basecsn = parententry_dncsn; + } + } +- opcsn = op->o_csngen_handler(pb, basecsn); ++ if(op->o_csngen_handler(pb, basecsn, opcsn) != 0) { ++ return -1; ++ } + +- if (NULL != opcsn) { +- operation_set_csn(op, opcsn); ++ if (*opcsn) { ++ operation_set_csn(op, *opcsn); + } + } + +- return opcsn; ++ return 0; + } + + /* +diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h +index a4cae784a..cef8c789c 100644 +--- a/ldap/servers/slapd/slap.h ++++ b/ldap/servers/slapd/slap.h +@@ -1480,7 +1480,7 @@ struct op; + typedef void (*result_handler)(struct conn *, struct op *, int, char *, char *, int, struct berval **); + typedef int (*search_entry_handler)(Slapi_Backend *, struct conn *, struct op *, struct slapi_entry *); + typedef int (*search_referral_handler)(Slapi_Backend *, struct conn *, struct op *, struct berval **); +-typedef CSN *(*csngen_handler)(Slapi_PBlock *pb, const CSN *basecsn); ++typedef int32_t *(*csngen_handler)(Slapi_PBlock *pb, const CSN *basecsn, CSN **opcsn); + typedef int (*replica_attr_handler)(Slapi_PBlock *pb, const char *type, void **value); + + /* +diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h +index be1e52e4d..834a98742 100644 +--- a/ldap/servers/slapd/slapi-plugin.h ++++ b/ldap/servers/slapd/slapi-plugin.h +@@ -6743,6 +6743,14 @@ int slapi_reslimit_get_integer_limit(Slapi_Connection *conn, int handle, int *li + */ + time_t slapi_current_time(void) __attribute__((deprecated)); + ++/** ++ * Get the system time and check for errors. Return ++ * ++ * \param tp - a timespec struct where the system time is set ++ * \return result code, upon success tp is set to the system time ++ */ ++int32_t slapi_clock_gettime(struct timespec *tp); ++ + /** + * Returns the current system time as a hr clock relative to uptime + * This means the clock is not affected by timezones +diff --git a/ldap/servers/slapd/slapi-private.h b/ldap/servers/slapd/slapi-private.h +index d85ee43e5..c98c1947c 100644 +--- a/ldap/servers/slapd/slapi-private.h ++++ b/ldap/servers/slapd/slapi-private.h +@@ -233,7 +233,8 @@ enum + CSN_INVALID_PARAMETER, /* invalid function argument */ + CSN_INVALID_FORMAT, /* invalid state format */ + CSN_LDAP_ERROR, /* LDAP operation failed */ +- CSN_NSPR_ERROR /* NSPR API failure */ ++ CSN_NSPR_ERROR, /* NSPR API failure */ ++ CSN_TIME_ERROR /* Error generating new CSN due to clock failure */ + }; + + typedef struct csngen CSNGen; +@@ -326,7 +327,7 @@ int slapi_entries_diff(Slapi_Entry **old_entries, Slapi_Entry **new_entries, int + void set_attr_to_protected_list(char *attr, int flag); + + /* entrywsi.c */ +-CSN *entry_assign_operation_csn(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *parententry); ++int32_t entry_assign_operation_csn(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *parententry, CSN **opcsn); + const CSN *entry_get_maxcsn(const Slapi_Entry *entry); + void entry_set_maxcsn(Slapi_Entry *entry, const CSN *csn); + const CSN *entry_get_dncsn(const Slapi_Entry *entry); +diff --git a/ldap/servers/slapd/time.c b/ldap/servers/slapd/time.c +index 8048a3359..545538404 100644 +--- a/ldap/servers/slapd/time.c ++++ b/ldap/servers/slapd/time.c +@@ -61,6 +61,25 @@ poll_current_time() + return 0; + } + ++/* ++ * Check if the time function returns an error. If so return the errno ++ */ ++int32_t ++slapi_clock_gettime(struct timespec *tp) ++{ ++ int32_t rc = 0; ++ ++ PR_ASSERT(tp && tp->tv_nsec == 0 && tp->tv_sec == 0); ++ ++ if (clock_gettime(CLOCK_REALTIME, tp) != 0) { ++ rc = errno; ++ } ++ ++ PR_ASSERT(rc == 0); ++ ++ return rc; ++} ++ + time_t + current_time(void) + { +@@ -69,7 +88,7 @@ current_time(void) + * but this should be removed in favour of the + * more accurately named slapi_current_utc_time + */ +- struct timespec now; ++ struct timespec now = {0}; + clock_gettime(CLOCK_REALTIME, &now); + return now.tv_sec; + } +@@ -83,7 +102,7 @@ slapi_current_time(void) + struct timespec + slapi_current_rel_time_hr(void) + { +- struct timespec now; ++ struct timespec now = {0}; + clock_gettime(CLOCK_MONOTONIC, &now); + return now; + } +@@ -91,7 +110,7 @@ slapi_current_rel_time_hr(void) + struct timespec + slapi_current_utc_time_hr(void) + { +- struct timespec ltnow; ++ struct timespec ltnow = {0}; + clock_gettime(CLOCK_REALTIME, <now); + return ltnow; + } +@@ -99,7 +118,7 @@ slapi_current_utc_time_hr(void) + time_t + slapi_current_utc_time(void) + { +- struct timespec ltnow; ++ struct timespec ltnow = {0}; + clock_gettime(CLOCK_REALTIME, <now); + return ltnow.tv_sec; + } +@@ -108,8 +127,8 @@ void + slapi_timestamp_utc_hr(char *buf, size_t bufsize) + { + PR_ASSERT(bufsize >= SLAPI_TIMESTAMP_BUFSIZE); +- struct timespec ltnow; +- struct tm utctm; ++ struct timespec ltnow = {0}; ++ struct tm utctm = {0}; + clock_gettime(CLOCK_REALTIME, <now); + gmtime_r(&(ltnow.tv_sec), &utctm); + strftime(buf, bufsize, "%Y%m%d%H%M%SZ", &utctm); +@@ -140,7 +159,7 @@ format_localTime_log(time_t t, int initsize __attribute__((unused)), char *buf, + { + + long tz; +- struct tm *tmsp, tms; ++ struct tm *tmsp, tms = {0}; + char tbuf[*bufsize]; + char sign; + /* make sure our buffer will be big enough. Need at least 29 */ +@@ -191,7 +210,7 @@ format_localTime_hr_log(time_t t, long nsec, int initsize __attribute__((unused) + { + + long tz; +- struct tm *tmsp, tms; ++ struct tm *tmsp, tms = {0}; + char tbuf[*bufsize]; + char sign; + /* make sure our buffer will be big enough. Need at least 39 */ +@@ -278,7 +297,7 @@ slapi_timespec_expire_check(struct timespec *expire) + if (expire->tv_sec == 0 && expire->tv_nsec == 0) { + return TIMER_CONTINUE; + } +- struct timespec now; ++ struct timespec now = {0}; + clock_gettime(CLOCK_MONOTONIC, &now); + if (now.tv_sec > expire->tv_sec || + (expire->tv_sec == now.tv_sec && now.tv_sec > expire->tv_nsec)) { +@@ -293,7 +312,7 @@ format_localTime(time_t from) + in the syntax of a generalizedTime, except without the time zone. */ + { + char *into; +- struct tm t; ++ struct tm t = {0}; + + localtime_r(&from, &t); + +@@ -362,7 +381,7 @@ format_genTime(time_t from) + in the syntax of a generalizedTime. */ + { + char *into; +- struct tm t; ++ struct tm t = {0}; + + gmtime_r(&from, &t); + into = slapi_ch_malloc(SLAPI_TIMESTAMP_BUFSIZE); +@@ -382,7 +401,7 @@ time_t + read_genTime(struct berval *from) + { + struct tm t = {0}; +- time_t retTime; ++ time_t retTime = {0}; + time_t diffsec = 0; + int i, gflag = 0, havesec = 0; + +-- +2.26.2 + diff --git a/SOURCES/0008-Ticket-50709-Several-memory-leaks-reported-by-Valgri.patch b/SOURCES/0008-Ticket-50709-Several-memory-leaks-reported-by-Valgri.patch deleted file mode 100644 index fb1c33d..0000000 --- a/SOURCES/0008-Ticket-50709-Several-memory-leaks-reported-by-Valgri.patch +++ /dev/null @@ -1,186 +0,0 @@ -From 2040a0a1e517b444fef35a30c86bc6380b03bb21 Mon Sep 17 00:00:00 2001 -From: Thierry Bordaz -Date: Fri, 8 Nov 2019 18:16:06 +0100 -Subject: [PATCH] Ticket 50709: Several memory leaks reported by Valgrind for - 389-ds 1.3.9.1-10 - -Description of the problem: - - When evaluating an ACI with 'ip' subject, it adds a PRNetAddr to the subject - property list. When the list is free (acl__done_aclpb) the property is not freed. - -Description of the fix: - - Add the property to the pblock (SLAPI_CONN_CLIENTNETADDR_ACLIP) so that it - the property is freed with acl pblock. - -https://pagure.io/389-ds-base/issue/50709 - -Reviewed by: Mark Reynolds, William Brown, Ludwig Krispenz ---- - ldap/servers/plugins/acl/acllas.c | 51 ++++++++++++++++++++----------- - ldap/servers/slapd/connection.c | 2 ++ - ldap/servers/slapd/pblock.c | 16 ++++++++++ - ldap/servers/slapd/slap.h | 1 + - ldap/servers/slapd/slapi-plugin.h | 1 + - 5 files changed, 53 insertions(+), 18 deletions(-) - -diff --git a/ldap/servers/plugins/acl/acllas.c b/ldap/servers/plugins/acl/acllas.c -index 3950fd405..dd41d41bd 100644 ---- a/ldap/servers/plugins/acl/acllas.c -+++ b/ldap/servers/plugins/acl/acllas.c -@@ -251,6 +251,7 @@ DS_LASIpGetter(NSErr_t *errp, PList_t subject, PList_t resource, PList_t auth_in - { - struct acl_pblock *aclpb = NULL; - PRNetAddr *client_praddr = NULL; -+ PRNetAddr *pb_client_praddr = NULL; - char ip_str[256]; - int rv = LAS_EVAL_TRUE; - -@@ -262,25 +263,39 @@ DS_LASIpGetter(NSErr_t *errp, PList_t subject, PList_t resource, PList_t auth_in - return LAS_EVAL_FAIL; - } - -- client_praddr = (PRNetAddr *)slapi_ch_malloc(sizeof(PRNetAddr)); -- if (client_praddr == NULL) { -- slapi_log_err(SLAPI_LOG_ERR, plugin_name, "DS_LASIpGetter - Failed to allocate client_praddr\n"); -- return (LAS_EVAL_FAIL); -- } -+ slapi_pblock_get(aclpb->aclpb_pblock, SLAPI_CONN_CLIENTNETADDR_ACLIP, &pb_client_praddr); -+ if (pb_client_praddr == NULL) { - -- if (slapi_pblock_get(aclpb->aclpb_pblock, SLAPI_CONN_CLIENTNETADDR, client_praddr) != 0) { -- slapi_log_err(SLAPI_LOG_ERR, plugin_name, "DS_LASIpGetter - Could not get client IP.\n"); -- slapi_ch_free((void **)&client_praddr); -- return (LAS_EVAL_FAIL); -- } -+ client_praddr = (PRNetAddr *) slapi_ch_malloc(sizeof (PRNetAddr)); -+ if (client_praddr == NULL) { -+ slapi_log_err(SLAPI_LOG_ERR, plugin_name, "DS_LASIpGetter - Failed to allocate client_praddr\n"); -+ return (LAS_EVAL_FAIL); -+ } - -- rv = PListInitProp(subject, 0, ACL_ATTR_IP, (void *)client_praddr, NULL); -- if (rv < 0) { -- slapi_log_err(SLAPI_LOG_ACL, plugin_name, "DS_LASIpGetter - " -- "Couldn't set the client addr property(%d)\n", -- rv); -- slapi_ch_free((void **)&client_praddr); -- return LAS_EVAL_FAIL; -+ if (slapi_pblock_get(aclpb->aclpb_pblock, SLAPI_CONN_CLIENTNETADDR, client_praddr) != 0) { -+ slapi_log_err(SLAPI_LOG_ERR, plugin_name, "DS_LASIpGetter - Could not get client IP.\n"); -+ slapi_ch_free((void **) &client_praddr); -+ return (LAS_EVAL_FAIL); -+ } -+ -+ rv = PListInitProp(subject, 0, ACL_ATTR_IP, (void *) client_praddr, NULL); -+ if (rv < 0) { -+ slapi_log_err(SLAPI_LOG_ACL, plugin_name, "DS_LASIpGetter - " -+ "Couldn't set the client addr property(%d)\n", -+ rv); -+ slapi_ch_free((void **) &client_praddr); -+ return LAS_EVAL_FAIL; -+ } -+ -+ } else { -+ client_praddr = pb_client_praddr; -+ rv = PListInitProp(subject, 0, ACL_ATTR_IP, (void *) client_praddr, NULL); -+ if (rv < 0) { -+ slapi_log_err(SLAPI_LOG_ACL, plugin_name, "DS_LASIpGetter - " -+ "Couldn't set the client addr property(%d)\n", -+ rv); -+ return LAS_EVAL_FAIL; -+ } - } - if (PR_NetAddrToString(client_praddr, ip_str, sizeof(ip_str)) == PR_SUCCESS) { - slapi_log_err(SLAPI_LOG_ACL, plugin_name, "DS_LASIpGetter - " -@@ -290,7 +305,7 @@ DS_LASIpGetter(NSErr_t *errp, PList_t subject, PList_t resource, PList_t auth_in - slapi_log_err(SLAPI_LOG_ACL, plugin_name, "DS_LASIpGetter - " - "Returning client ip address 'unknown'\n"); - } -- -+ slapi_pblock_set(aclpb->aclpb_pblock, SLAPI_CONN_CLIENTNETADDR_ACLIP, client_praddr); - return LAS_EVAL_TRUE; - } - -diff --git a/ldap/servers/slapd/connection.c b/ldap/servers/slapd/connection.c -index e124303be..da954ada6 100644 ---- a/ldap/servers/slapd/connection.c -+++ b/ldap/servers/slapd/connection.c -@@ -206,6 +206,7 @@ connection_cleanup(Connection *conn) - conn->c_isreplication_session = 0; - slapi_ch_free((void **)&conn->cin_addr); - slapi_ch_free((void **)&conn->cin_destaddr); -+ slapi_ch_free((void **)&conn->cin_addr_aclip); - slapi_ch_free_string(&conn->c_ipaddr); - if (conn->c_domain != NULL) { - ber_bvecfree(conn->c_domain); -@@ -408,6 +409,7 @@ connection_reset(Connection *conn, int ns, PRNetAddr *from, int fromLen __attrib - str_destip = str_unknown; - } - } -+ slapi_ch_free((void **)&conn->cin_addr_aclip); - - if (!in_referral_mode) { - /* create a sasl connection */ -diff --git a/ldap/servers/slapd/pblock.c b/ldap/servers/slapd/pblock.c -index cc44ace30..348cc6f1a 100644 ---- a/ldap/servers/slapd/pblock.c -+++ b/ldap/servers/slapd/pblock.c -@@ -482,6 +482,14 @@ slapi_pblock_get(Slapi_PBlock *pblock, int arg, void *value) - } - pthread_mutex_unlock(&(pblock->pb_conn->c_mutex)); - break; -+ case SLAPI_CONN_CLIENTNETADDR_ACLIP: -+ if (pblock->pb_conn == NULL) { -+ break; -+ } -+ pthread_mutex_lock(&(pblock->pb_conn->c_mutex)); -+ (*(PRNetAddr **) value) = pblock->pb_conn->cin_addr_aclip; -+ pthread_mutex_unlock(&(pblock->pb_conn->c_mutex)); -+ break; - case SLAPI_CONN_SERVERNETADDR: - if (pblock->pb_conn == NULL) { - memset(value, 0, sizeof(PRNetAddr)); -@@ -2571,6 +2579,14 @@ slapi_pblock_set(Slapi_PBlock *pblock, int arg, void *value) - pblock->pb_conn->c_authtype = slapi_ch_strdup((char *)value); - pthread_mutex_unlock(&(pblock->pb_conn->c_mutex)); - break; -+ case SLAPI_CONN_CLIENTNETADDR_ACLIP: -+ if (pblock->pb_conn == NULL) { -+ break; -+ } -+ pthread_mutex_lock(&(pblock->pb_conn->c_mutex)); -+ slapi_ch_free((void **)&pblock->pb_conn->cin_addr_aclip); -+ pblock->pb_conn->cin_addr_aclip = (PRNetAddr *)value; -+ pthread_mutex_unlock(&(pblock->pb_conn->c_mutex)); - case SLAPI_CONN_IS_REPLICATION_SESSION: - if (pblock->pb_conn == NULL) { - slapi_log_err(SLAPI_LOG_ERR, -diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h -index 0aa2dcc1a..8a2748519 100644 ---- a/ldap/servers/slapd/slap.h -+++ b/ldap/servers/slapd/slap.h -@@ -1634,6 +1634,7 @@ typedef struct conn - char *c_external_dn; /* client DN of this SSL session */ - char *c_external_authtype; /* used for c_external_dn */ - PRNetAddr *cin_addr; /* address of client on this conn */ -+ PRNetAddr *cin_addr_aclip; /* address of client allocated by acl with 'ip' subject */ - PRNetAddr *cin_destaddr; /* address client connected to */ - struct berval **c_domain; /* DNS names of client */ - Operation *c_ops; /* list of pending operations */ -diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h -index 01dcb0554..29a6238d9 100644 ---- a/ldap/servers/slapd/slapi-plugin.h -+++ b/ldap/servers/slapd/slapi-plugin.h -@@ -6930,6 +6930,7 @@ slapi_timer_result slapi_timespec_expire_check(struct timespec *expire); - #define SLAPI_CONN_DN 143 - #define SLAPI_CONN_CLIENTNETADDR 850 - #define SLAPI_CONN_SERVERNETADDR 851 -+#define SLAPI_CONN_CLIENTNETADDR_ACLIP 853 - #define SLAPI_CONN_IS_REPLICATION_SESSION 149 - #define SLAPI_CONN_IS_SSL_SESSION 747 - #define SLAPI_CONN_CERT 743 --- -2.21.1 - diff --git a/SOURCES/0009-Issue-51113-Allow-using-uid-for-replication-manager-.patch b/SOURCES/0009-Issue-51113-Allow-using-uid-for-replication-manager-.patch new file mode 100644 index 0000000..e5dbb3d --- /dev/null +++ b/SOURCES/0009-Issue-51113-Allow-using-uid-for-replication-manager-.patch @@ -0,0 +1,179 @@ +From 52ce524f7672563b543e84401665765cfa72dea5 Mon Sep 17 00:00:00 2001 +From: Mark Reynolds +Date: Tue, 26 May 2020 17:03:11 -0400 +Subject: [PATCH 09/12] Issue 51113 - Allow using uid for replication manager + entry + +Bug Description: Currently it was hardcoded to only allow "cn" as + the rdn attribute for the replication manager entry. + +Fix description: Allow setting the rdn attribute of the replication + manager DS ldap object, and include the schema that + allows "uid". + +relates: https://pagure.io/389-ds-base/issue/51113 + +Reviewed by: spichugi & firstyear(Thanks!!) +--- + src/lib389/lib389/cli_conf/replication.py | 53 ++++++++++++----------- + src/lib389/lib389/replica.py | 11 +++-- + 2 files changed, 35 insertions(+), 29 deletions(-) + +diff --git a/src/lib389/lib389/cli_conf/replication.py b/src/lib389/lib389/cli_conf/replication.py +index 09cb9b435..b9bc3d291 100644 +--- a/src/lib389/lib389/cli_conf/replication.py ++++ b/src/lib389/lib389/cli_conf/replication.py +@@ -199,19 +199,21 @@ def enable_replication(inst, basedn, log, args): + + # Create replication manager if password was provided + if args.bind_dn and args.bind_passwd: +- cn_rdn = args.bind_dn.split(",", 1)[0] +- cn_val = cn_rdn.split("=", 1)[1] +- manager = BootstrapReplicationManager(inst, dn=args.bind_dn) ++ rdn = args.bind_dn.split(",", 1)[0] ++ rdn_attr, rdn_val = rdn.split("=", 1) ++ manager = BootstrapReplicationManager(inst, dn=args.bind_dn, rdn_attr=rdn_attr) + try: + manager.create(properties={ +- 'cn': cn_val, ++ 'cn': rdn_val, ++ 'uid': rdn_val, + 'userPassword': args.bind_passwd + }) + except ldap.ALREADY_EXISTS: + # Already there, but could have different password. Delete and recreate + manager.delete() + manager.create(properties={ +- 'cn': cn_val, ++ 'cn': rdn_val, ++ 'uid': rdn_val, + 'userPassword': args.bind_passwd + }) + except ldap.NO_SUCH_OBJECT: +@@ -511,22 +513,23 @@ def get_cl(inst, basedn, log, args): + + + def create_repl_manager(inst, basedn, log, args): +- manager_cn = "replication manager" ++ manager_name = "replication manager" + repl_manager_password = "" + repl_manager_password_confirm = "" + + if args.name: +- manager_cn = args.name +- +- if is_a_dn(manager_cn): +- # A full DN was provided, make sure it uses "cn" for the RDN +- if manager_cn.split("=", 1)[0].lower() != "cn": +- raise ValueError("Replication manager DN must use \"cn\" for the rdn attribute") +- manager_dn = manager_cn +- manager_rdn = manager_dn.split(",", 1)[0] +- manager_cn = manager_rdn.split("=", 1)[1] ++ manager_name = args.name ++ ++ if is_a_dn(manager_name): ++ # A full DN was provided ++ manager_dn = manager_name ++ manager_rdn = manager_name.split(",", 1)[0] ++ manager_attr, manager_name = manager_rdn.split("=", 1) ++ if manager_attr.lower() not in ['cn', 'uid']: ++ raise ValueError(f'The RDN attribute "{manager_attr}" is not allowed, you must use "cn" or "uid"') + else: +- manager_dn = "cn={},cn=config".format(manager_cn) ++ manager_dn = "cn={},cn=config".format(manager_name) ++ manager_attr = "cn" + + if args.passwd: + repl_manager_password = args.passwd +@@ -544,10 +547,11 @@ def create_repl_manager(inst, basedn, log, args): + repl_manager_password = "" + repl_manager_password_confirm = "" + +- manager = BootstrapReplicationManager(inst, dn=manager_dn) ++ manager = BootstrapReplicationManager(inst, dn=manager_dn, rdn_attr=manager_attr) + try: + manager.create(properties={ +- 'cn': manager_cn, ++ 'cn': manager_name, ++ 'uid': manager_name, + 'userPassword': repl_manager_password + }) + if args.suffix: +@@ -564,7 +568,8 @@ def create_repl_manager(inst, basedn, log, args): + # Already there, but could have different password. Delete and recreate + manager.delete() + manager.create(properties={ +- 'cn': manager_cn, ++ 'cn': manager_name, ++ 'uid': manager_name, + 'userPassword': repl_manager_password + }) + if args.suffix: +@@ -954,6 +959,7 @@ def get_winsync_agmt_status(inst, basedn, log, args): + status = agmt.status(winsync=True, use_json=args.json) + log.info(status) + ++ + # + # Tasks + # +@@ -1347,8 +1353,7 @@ def create_parser(subparsers): + agmt_set_parser.add_argument('--wait-async-results', help="The amount of time in milliseconds the server waits if " + "the consumer is not ready before resending data") + agmt_set_parser.add_argument('--busy-wait-time', help="The amount of time in seconds a supplier should wait after " +- "a consumer sends back a busy response before making another " +- "attempt to acquire access.") ++ "a consumer sends back a busy response before making another attempt to acquire access.") + agmt_set_parser.add_argument('--session-pause-time', help="The amount of time in seconds a supplier should wait between update sessions.") + agmt_set_parser.add_argument('--flow-control-window', help="Sets the maximum number of entries and updates sent by a supplier, which are not acknowledged by the consumer.") + agmt_set_parser.add_argument('--flow-control-pause', help="The time in milliseconds to pause after reaching the number of entries and updates set in \"--flow-control-window\"") +@@ -1438,8 +1443,7 @@ def create_parser(subparsers): + winsync_agmt_add_parser.add_argument('--subtree-pair', help="Set the subtree pair: :") + winsync_agmt_add_parser.add_argument('--conn-timeout', help="The timeout used for replicaton connections") + winsync_agmt_add_parser.add_argument('--busy-wait-time', help="The amount of time in seconds a supplier should wait after " +- "a consumer sends back a busy response before making another " +- "attempt to acquire access.") ++ "a consumer sends back a busy response before making another attempt to acquire access.") + winsync_agmt_add_parser.add_argument('--session-pause-time', help="The amount of time in seconds a supplier should wait between update sessions.") + winsync_agmt_add_parser.add_argument('--init', action='store_true', default=False, help="Initialize the agreement after creating it.") + +@@ -1468,8 +1472,7 @@ def create_parser(subparsers): + winsync_agmt_set_parser.add_argument('--subtree-pair', help="Set the subtree pair: :") + winsync_agmt_set_parser.add_argument('--conn-timeout', help="The timeout used for replicaton connections") + winsync_agmt_set_parser.add_argument('--busy-wait-time', help="The amount of time in seconds a supplier should wait after " +- "a consumer sends back a busy response before making another " +- "attempt to acquire access.") ++ "a consumer sends back a busy response before making another attempt to acquire access.") + winsync_agmt_set_parser.add_argument('--session-pause-time', help="The amount of time in seconds a supplier should wait between update sessions.") + + # Get +diff --git a/src/lib389/lib389/replica.py b/src/lib389/lib389/replica.py +index e3fc7fe1f..f8adb3ce2 100644 +--- a/src/lib389/lib389/replica.py ++++ b/src/lib389/lib389/replica.py +@@ -1779,15 +1779,18 @@ class BootstrapReplicationManager(DSLdapObject): + :type instance: lib389.DirSrv + :param dn: The dn to create + :type dn: str ++ :param rdn_attr: The attribute to use for the RDN ++ :type rdn_attr: str + """ +- def __init__(self, instance, dn='cn=replication manager,cn=config'): ++ def __init__(self, instance, dn='cn=replication manager,cn=config', rdn_attr='cn'): + super(BootstrapReplicationManager, self).__init__(instance, dn) +- self._rdn_attribute = 'cn' ++ self._rdn_attribute = rdn_attr + self._must_attributes = ['cn', 'userPassword'] + self._create_objectclasses = [ + 'top', +- 'netscapeServer', +- 'nsAccount' ++ 'inetUser', # for uid ++ 'netscapeServer', # for cn ++ 'nsAccount', # for authentication attributes + ] + if ds_is_older('1.4.0'): + self._create_objectclasses.remove('nsAccount') +-- +2.26.2 + diff --git a/SOURCES/0009-Ticket-50736-RetroCL-trimming-may-crash-at-shutdown-.patch b/SOURCES/0009-Ticket-50736-RetroCL-trimming-may-crash-at-shutdown-.patch deleted file mode 100644 index 3b48ca4..0000000 --- a/SOURCES/0009-Ticket-50736-RetroCL-trimming-may-crash-at-shutdown-.patch +++ /dev/null @@ -1,125 +0,0 @@ -From 4ea3c4aa8118933fd22721dcf9b9e6c4a498736c Mon Sep 17 00:00:00 2001 -From: Thierry Bordaz -Date: Mon, 25 Nov 2019 10:59:44 +0100 -Subject: [PATCH] Ticket 50736 - RetroCL trimming may crash at shutdown if - trimming configuration is invalid - -Bug Description: - If config of retroCL trimming contains invalid value for trim-interval - and/or maxage, then the trimming initialization is skipped. - In such case the trimming structures are not allocated and if they - are freed at shutdown it triggers a crash - -Fix Description: - When trimming mechanism is stopped (at shutdown) check that - it was successfully initialized before freeing the structs - -https://pagure.io/389-ds-base/issue/50736 - -Reviewed by: Mark Reynolds - -Platforms tested: F30 - -Flag Day: no - -Doc impact: no ---- - .../suites/replication/changelog_test.py | 47 +++++++++++++++++++ - ldap/servers/plugins/retrocl/retrocl_trim.c | 17 ++++--- - 2 files changed, 58 insertions(+), 6 deletions(-) - -diff --git a/dirsrvtests/tests/suites/replication/changelog_test.py b/dirsrvtests/tests/suites/replication/changelog_test.py -index a257e0272..e648478d0 100644 ---- a/dirsrvtests/tests/suites/replication/changelog_test.py -+++ b/dirsrvtests/tests/suites/replication/changelog_test.py -@@ -16,6 +16,8 @@ from lib389.replica import Replicas - from lib389.idm.user import UserAccounts - from lib389.topologies import topology_m2 as topo - from lib389._constants import * -+from lib389.plugins import RetroChangelogPlugin -+from lib389.dseldif import DSEldif - from lib389.tasks import * - from lib389.utils import * - -@@ -452,6 +454,51 @@ def test_retrochangelog_maxage(topo, changelog_init): - - topo.ms["master1"].log.info("ticket47669 was successfully verified.") - -+@pytest.mark.ds50736 -+def test_retrochangelog_trimming_crash(topo, changelog_init): -+ """Check that when retroCL nsslapd-retrocthangelog contains invalid -+ value, then the instance does not crash at shutdown -+ -+ :id: 5d9bd7ca-e9bf-4be9-8fc8-902aa5513052 -+ :setup: Replication with two master, change nsslapd-changelogdir to -+ '/var/lib/dirsrv/slapd-master1/changelog' and -+ set cn=Retro Changelog Plugin,cn=plugins,cn=config to 'on' -+ :steps: -+ 1. Set nsslapd-changelogmaxage in cn=Retro Changelog Plugin,cn=plugins,cn=config to value '-1' -+ This value is invalid. To disable retroCL trimming it should be set to 0 -+ 2. Do several restart -+ 3. check there is no 'Detected Disorderly Shutdown' message (crash) -+ 4. restore valid value for nsslapd-changelogmaxage '1w' -+ -+ :expectedresults: -+ 1. Operation should be successful -+ 2. Operation should be successful -+ 3. Operation should be successful -+ 4. Operation should be successful -+ """ -+ log.info('1. Test retroCL trimming crash in cn=Retro Changelog Plugin,cn=plugins,cn=config') -+ -+ # set the nsslapd-changelogmaxage directly on dse.ldif -+ # because the set value is invalid -+ topo.ms["master1"].log.info("ticket50736 start verification") -+ topo.ms["master1"].stop() -+ retroPlugin = RetroChangelogPlugin(topo.ms["master1"]) -+ dse_ldif = DSEldif(topo.ms["master1"]) -+ dse_ldif.replace(retroPlugin.dn, 'nsslapd-changelogmaxage', '-1') -+ topo.ms["master1"].start() -+ -+ # The crash should be systematic, but just in case do several restart -+ # with a delay to let all plugin init -+ for i in range(5): -+ time.sleep(1) -+ topo.ms["master1"].stop() -+ topo.ms["master1"].start() -+ -+ assert not topo.ms["master1"].detectDisorderlyShutdown() -+ -+ topo.ms["master1"].log.info("ticket 50736 was successfully verified.") -+ -+ - - if __name__ == '__main__': - # Run isolated -diff --git a/ldap/servers/plugins/retrocl/retrocl_trim.c b/ldap/servers/plugins/retrocl/retrocl_trim.c -index a46534984..0378eb7f6 100644 ---- a/ldap/servers/plugins/retrocl/retrocl_trim.c -+++ b/ldap/servers/plugins/retrocl/retrocl_trim.c -@@ -481,11 +481,16 @@ retrocl_init_trimming(void) - void - retrocl_stop_trimming(void) - { -- retrocl_trimming = 0; -- if (retrocl_trim_ctx) { -- slapi_eq_cancel(retrocl_trim_ctx); -- retrocl_trim_ctx = NULL; -+ if (retrocl_trimming) { -+ /* RetroCL trimming config was valid and trimming struct allocated -+ * Let's free them -+ */ -+ retrocl_trimming = 0; -+ if (retrocl_trim_ctx) { -+ slapi_eq_cancel(retrocl_trim_ctx); -+ retrocl_trim_ctx = NULL; -+ } -+ PR_DestroyLock(ts.ts_s_trim_mutex); -+ ts.ts_s_trim_mutex = NULL; - } -- PR_DestroyLock(ts.ts_s_trim_mutex); -- ts.ts_s_trim_mutex = NULL; - } --- -2.21.1 - diff --git a/SOURCES/0010-Issue-50806-Fix-minor-issues-in-lib389-health-checks.patch b/SOURCES/0010-Issue-50806-Fix-minor-issues-in-lib389-health-checks.patch deleted file mode 100644 index f071219..0000000 --- a/SOURCES/0010-Issue-50806-Fix-minor-issues-in-lib389-health-checks.patch +++ /dev/null @@ -1,111 +0,0 @@ -From 5f4281601966e9edeabdcec0e9f934c79d4ad8ed Mon Sep 17 00:00:00 2001 -From: Mark Reynolds -Date: Fri, 10 Jan 2020 10:29:02 -0500 -Subject: [PATCH] Issue 50806 - Fix minor issues in lib389 health checks - -Description: For permissions checks, add a list of permissions - that is acceptable instead of single value. - - For RI plugin attribute indexing checks, we now check - if a container scope is specified. If it is set, we - skip all the other backends that are not in the scope. - This prevents false positives. - -relates: https://pagure.io/389-ds-base/issue/50806 - -Reviewed by: mhonek(Thanks!) ---- - src/lib389/lib389/dseldif.py | 40 +++++++++++++++++++++++++----------- - src/lib389/lib389/plugins.py | 13 ++++++++++-- - 2 files changed, 39 insertions(+), 14 deletions(-) - -diff --git a/src/lib389/lib389/dseldif.py b/src/lib389/lib389/dseldif.py -index 4155abcdd..fbb50623b 100644 ---- a/src/lib389/lib389/dseldif.py -+++ b/src/lib389/lib389/dseldif.py -@@ -168,13 +168,27 @@ class FSChecks(object): - self.dirsrv = dirsrv - self._certdb = self.dirsrv.get_cert_dir() - self.ds_files = [ -- ('/etc/resolv.conf', '644', DSPERMLE0001), -- (self._certdb + "/pin.txt", '600', DSPERMLE0002), -- (self._certdb + "/pwdfile.txt", '600', DSPERMLE0002), -+ { -+ 'name': '/etc/resolv.conf', -+ 'perms': [644], -+ 'report': DSPERMLE0001 -+ }, -+ { -+ 'name': self._certdb + "/pin.txt", -+ 'perms': [400, 600], -+ 'report': DSPERMLE0002 -+ }, -+ { -+ 'name': self._certdb + "/pwdfile.txt", -+ 'perms': [400, 600], -+ 'report': DSPERMLE0002 -+ }, - ] - self._lint_functions = [self._lint_file_perms] - - def lint(self): -+ """Run a lint/healthcheck for this class -+ """ - results = [] - for fn in self._lint_functions: - for result in fn(): -@@ -183,14 +197,16 @@ class FSChecks(object): - return results - - def _lint_file_perms(self): -- # Check file permissions are correct -+ """Test file permissions are safe -+ """ - for ds_file in self.ds_files: -- perms = str(oct(os.stat(ds_file[0])[ST_MODE])[-3:]) -- if perms != ds_file[1]: -- report = copy.deepcopy(ds_file[2]) -- report['items'].append(ds_file[0]) -- report['detail'] = report['detail'].replace('FILE', ds_file[0]) -- report['detail'] = report['detail'].replace('PERMS', ds_file[1]) -- report['fix'] = report['fix'].replace('FILE', ds_file[0]) -- report['fix'] = report['fix'].replace('PERMS', ds_file[1]) -+ perms = int(oct(os.stat(ds_file['name'])[ST_MODE])[-3:]) -+ if perms not in ds_file['perms']: -+ perms = str(ds_file['perms'][0]) -+ report = copy.deepcopy(ds_file['report']) -+ report['items'].append(ds_file['name']) -+ report['detail'] = report['detail'].replace('FILE', ds_file['name']) -+ report['detail'] = report['detail'].replace('PERMS', perms) -+ report['fix'] = report['fix'].replace('FILE', ds_file['name']) -+ report['fix'] = report['fix'].replace('PERMS', perms) - yield report -diff --git a/src/lib389/lib389/plugins.py b/src/lib389/lib389/plugins.py -index 97c5d1d3b..0775e464f 100644 ---- a/src/lib389/lib389/plugins.py -+++ b/src/lib389/lib389/plugins.py -@@ -455,10 +455,19 @@ class ReferentialIntegrityPlugin(Plugin): - if self.status(): - from lib389.backend import Backends - backends = Backends(self._instance).list() -+ attrs = self.get_attr_vals_utf8_l("referint-membership-attr") -+ container = self.get_attr_val_utf8_l("nsslapd-plugincontainerscope") - for backend in backends: -- indexes = backend.get_indexes() - suffix = backend.get_attr_val_utf8_l('nsslapd-suffix') -- attrs = self.get_attr_vals_utf8_l("referint-membership-attr") -+ if suffix == "cn=changelog": -+ # Always skip retro changelog -+ continue -+ if container is not None: -+ # Check if this backend is in the scope -+ if not container.endswith(suffix): -+ # skip this backend that is not in the scope -+ continue -+ indexes = backend.get_indexes() - for attr in attrs: - report = copy.deepcopy(DSRILE0002) - try: --- -2.21.1 - diff --git a/SOURCES/0010-Issue-50931-RFE-AD-filter-rewriter-for-ObjectCategor.patch b/SOURCES/0010-Issue-50931-RFE-AD-filter-rewriter-for-ObjectCategor.patch new file mode 100644 index 0000000..966627a --- /dev/null +++ b/SOURCES/0010-Issue-50931-RFE-AD-filter-rewriter-for-ObjectCategor.patch @@ -0,0 +1,34 @@ +From ec85e986ec5710682de883f0f40f539b2f9945fa Mon Sep 17 00:00:00 2001 +From: Viktor Ashirov +Date: Wed, 27 May 2020 15:22:18 +0200 +Subject: [PATCH 10/12] Issue 50931 - RFE AD filter rewriter for ObjectCategory + +Bug Description: +ASAN build fails on RHEL due to linking issues + +Fix Description: +Add missing libslapd.la for librewriters.la + +Relates: https://pagure.io/389-ds-base/issue/50931 + +Reviewed by: tbordaz (Thanks!) +--- + Makefile.am | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Makefile.am b/Makefile.am +index 2309f3010..0e5f04f91 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1159,7 +1159,7 @@ librewriters_la_SOURCES = \ + + librewriters_la_LDFLAGS = $(AM_LDFLAGS) + librewriters_la_CPPFLAGS = $(AM_CPPFLAGS) $(REWRITERS_INCLUDES) $(DSPLUGIN_CPPFLAGS) +-librewriters_la_LIBADD = $(NSS_LINK) $(NSPR_LINK) ++librewriters_la_LIBADD = libslapd.la $(NSS_LINK) $(NSPR_LINK) + + #------------------------ + # libsvrcore +-- +2.26.2 + diff --git a/SOURCES/0011-Issue-50599-Remove-db-region-files-prior-to-db-recov.patch b/SOURCES/0011-Issue-50599-Remove-db-region-files-prior-to-db-recov.patch deleted file mode 100644 index 9abbbc3..0000000 --- a/SOURCES/0011-Issue-50599-Remove-db-region-files-prior-to-db-recov.patch +++ /dev/null @@ -1,264 +0,0 @@ -From 74525da09050809a55e2c6bba4c42b27d5326a8f Mon Sep 17 00:00:00 2001 -From: Mark Reynolds -Date: Sun, 12 Jan 2020 20:11:07 -0500 -Subject: [PATCH] Issue 50599 - Remove db region files prior to db recovery - -Bug Description: If the server crashes then the region files can become - corrupted and this prevents the server from starting. - -Fix Description: If we encounter a disorderly shutdown, then remove - the region files so there is a clean slate to start - with. - - Also cleaned up function typo: slapi_disordely_shutdown - -relates: https://pagure.io/389-ds-base/issue/50599 - -Reviewed by: firstyear & lkrispen (Thanks!!) ---- - .../plugins/replication/repl5_replica.c | 4 +- - .../slapd/back-ldbm/db-bdb/bdb_layer.c | 88 ++++++++++--------- - ldap/servers/slapd/plugin.c | 8 +- - ldap/servers/slapd/slapi-plugin.h | 2 +- - 4 files changed, 54 insertions(+), 48 deletions(-) - -diff --git a/ldap/servers/plugins/replication/repl5_replica.c b/ldap/servers/plugins/replication/repl5_replica.c -index 94507bff8..02caa88d9 100644 ---- a/ldap/servers/plugins/replication/repl5_replica.c -+++ b/ldap/servers/plugins/replication/repl5_replica.c -@@ -1657,7 +1657,7 @@ replica_check_for_data_reload(Replica *r, void *arg __attribute__((unused))) - * sessions. - */ - -- if (slapi_disordely_shutdown(PR_FALSE)) { -+ if (slapi_disorderly_shutdown(PR_FALSE)) { - slapi_log_err(SLAPI_LOG_WARNING, repl_plugin_name, "replica_check_for_data_reload - " - "Disorderly shutdown for replica %s. Check if DB RUV needs to be updated\n", - slapi_sdn_get_dn(r->repl_root)); -@@ -1701,7 +1701,7 @@ replica_check_for_data_reload(Replica *r, void *arg __attribute__((unused))) - slapi_sdn_get_dn(r->repl_root)); - rc = 0; - } -- } /* slapi_disordely_shutdown */ -+ } /* slapi_disorderly_shutdown */ - - object_release(ruv_obj); - } else /* we have no changes currently logged for this replica */ -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 10f6d401e..2103dac38 100644 ---- a/ldap/servers/slapd/back-ldbm/db-bdb/bdb_layer.c -+++ b/ldap/servers/slapd/back-ldbm/db-bdb/bdb_layer.c -@@ -15,6 +15,8 @@ - #include - #include - #include -+#include -+ - - #define DB_OPEN(oflags, db, txnid, file, database, type, flags, mode, rval) \ - { \ -@@ -990,10 +992,9 @@ bdb_start(struct ldbminfo *li, int dbmode) - return_value = dblayer_grok_directory(region_dir, - DBLAYER_DIRECTORY_READWRITE_ACCESS); - if (0 != return_value) { -- slapi_log_err(SLAPI_LOG_CRIT, "bdb_start", "Can't start because the database " -- "directory \"%s\" either doesn't exist, or is not " -- "accessible\n", -- region_dir); -+ slapi_log_err(SLAPI_LOG_CRIT, "bdb_start", -+ "Can't start because the database directory \"%s\" either doesn't exist, or is not accessible\n", -+ region_dir); - return return_value; - } - -@@ -1003,10 +1004,9 @@ bdb_start(struct ldbminfo *li, int dbmode) - return_value = dblayer_grok_directory(log_dir, - DBLAYER_DIRECTORY_READWRITE_ACCESS); - if (0 != return_value) { -- slapi_log_err(SLAPI_LOG_CRIT, "bdb_start", "Can't start because the log " -- "directory \"%s\" either doesn't exist, or is not " -- "accessible\n", -- log_dir); -+ slapi_log_err(SLAPI_LOG_CRIT, "bdb_start", -+ "Can't start because the log directory \"%s\" either doesn't exist, or is not accessible\n", -+ log_dir); - return return_value; - } - } -@@ -1057,15 +1057,27 @@ bdb_start(struct ldbminfo *li, int dbmode) - if (conf->bdb_recovery_required) { - open_flags |= DB_RECOVER; - if (DBLAYER_RESTORE_MODE & dbmode) { -- slapi_log_err(SLAPI_LOG_NOTICE, "bdb_start", "Recovering database after restore " -- "from archive.\n"); -+ slapi_log_err(SLAPI_LOG_NOTICE, "bdb_start", -+ "Recovering database after restore from archive.\n"); - } else if (DBLAYER_CLEAN_RECOVER_MODE & dbmode) { -- slapi_log_err(SLAPI_LOG_NOTICE, "bdb_start", "Clean up db environment and start " -- "from archive.\n"); -+ slapi_log_err(SLAPI_LOG_NOTICE, "bdb_start", -+ "Clean up db environment and start from archive.\n"); - } else { -- slapi_log_err(SLAPI_LOG_NOTICE, "bdb_start", "Detected Disorderly Shutdown last " -- "time Directory Server was running, recovering database.\n"); -- slapi_disordely_shutdown(PR_TRUE); -+ glob_t globbuf; -+ char file_pattern[MAXPATHLEN]; -+ -+ slapi_log_err(SLAPI_LOG_NOTICE, "bdb_start", -+ "Detected Disorderly Shutdown last time Directory Server was running, recovering database.\n"); -+ slapi_disorderly_shutdown(PR_TRUE); -+ -+ /* Better wipe out the region files to help ensure a clean start */ -+ PR_snprintf(file_pattern, MAXPATHLEN, "%s/%s", region_dir, "__db.*"); -+ if (glob(file_pattern, GLOB_DOOFFS, NULL, &globbuf) == 0) { -+ for (size_t i = 0; i < globbuf.gl_pathc; i++) { -+ remove(globbuf.gl_pathv[i]); -+ } -+ globfree(&globbuf); -+ } - } - } - switch (dbmode & DBLAYER_RESTORE_MASK) { -@@ -1121,7 +1133,7 @@ bdb_start(struct ldbminfo *li, int dbmode) - */ - if (conf->bdb_lock_config <= BDB_LOCK_NB_MIN) { - slapi_log_err(SLAPI_LOG_NOTICE, "bdb_start", "New max db lock count is too small. " -- "Resetting it to the default value %d.\n", -+ "Resetting it to the default value %d.\n", - BDB_LOCK_NB_MIN); - conf->bdb_lock_config = BDB_LOCK_NB_MIN; - } -@@ -1165,29 +1177,26 @@ bdb_start(struct ldbminfo *li, int dbmode) - if ((open_flags & DB_RECOVER) || (open_flags & DB_RECOVER_FATAL)) { - /* Recover, then close, then open again */ - int recover_flags = open_flags & ~DB_THREAD; -- - if (DBLAYER_CLEAN_RECOVER_MODE & dbmode) /* upgrade case */ - { - DB_ENV *thisenv = pEnv->bdb_DB_ENV; - return_value = thisenv->remove(thisenv, region_dir, DB_FORCE); - if (0 != return_value) { -- slapi_log_err(SLAPI_LOG_CRIT, -- "bdb_start", "Failed to remove old db env " -- "in %s: %s\n", -- region_dir, -- dblayer_strerror(return_value)); -+ slapi_log_err(SLAPI_LOG_CRIT, "bdb_start", -+ "Failed to remove old db env in %s: %s\n", -+ region_dir, dblayer_strerror(return_value)); - return return_value; - } - dbmode = DBLAYER_NORMAL_MODE; - - if ((return_value = bdb_make_env(&pEnv, li)) != 0) { -- slapi_log_err(SLAPI_LOG_CRIT, -- "bdb_start", "Failed to create DBENV (returned: %d).\n", -- return_value); -+ slapi_log_err(SLAPI_LOG_CRIT, "bdb_start", -+ "Failed to create DBENV (returned: %d).\n", return_value); - return return_value; - } - } - -+ - return_value = (pEnv->bdb_DB_ENV->open)( - pEnv->bdb_DB_ENV, - region_dir, -@@ -1201,27 +1210,25 @@ bdb_start(struct ldbminfo *li, int dbmode) - */ - slapi_log_err(SLAPI_LOG_CRIT, - "bdb_start", "mmap in opening database environment (recovery mode) " -- "failed trying to allocate %" PRIu64 " bytes. (OS err %d - %s)\n", -+ "failed trying to allocate %" PRIu64 " bytes. (OS err %d - %s)\n", - li->li_dbcachesize, return_value, dblayer_strerror(return_value)); - bdb_free_env(&priv->dblayer_env); - priv->dblayer_env = CATASTROPHIC; - } else { - slapi_log_err(SLAPI_LOG_CRIT, "bdb_start", "Database Recovery Process FAILED. " -- "The database is not recoverable. err=%d: %s\n", -+ "The database is not recoverable. err=%d: %s\n", - return_value, dblayer_strerror(return_value)); -- slapi_log_err(SLAPI_LOG_CRIT, -- "bdb_start", "Please make sure there is enough disk space for " -- "dbcache (%" PRIu64 " bytes) and db region files\n", -- li->li_dbcachesize); -+ slapi_log_err(SLAPI_LOG_CRIT, "bdb_start", -+ "Please make sure there is enough disk space for dbcache (%" PRIu64 " bytes) and db region files\n", -+ li->li_dbcachesize); - } - return return_value; - } else { - open_flags &= ~(DB_RECOVER | DB_RECOVER_FATAL); - pEnv->bdb_DB_ENV->close(pEnv->bdb_DB_ENV, 0); - if ((return_value = bdb_make_env(&pEnv, li)) != 0) { -- slapi_log_err(SLAPI_LOG_CRIT, -- "bdb_start", "Failed to create DBENV (returned: %d).\n", -- return_value); -+ slapi_log_err(SLAPI_LOG_CRIT, "bdb_start", -+ "Failed to create DBENV (returned: %d).\n", return_value); - return return_value; - } - bdb_free_env(&priv->dblayer_env); -@@ -1288,16 +1295,15 @@ bdb_start(struct ldbminfo *li, int dbmode) - * https://blackflag.mcom.com/show_bug.cgi?id=557319 - * Crash ns-slapd while running scalab01 after restart slapd - */ -- slapi_log_err(SLAPI_LOG_CRIT, -- "bdb_start", "mmap in opening database environment " -- "failed trying to allocate %" PRIu64 " bytes. (OS err %d - %s)\n", -- li->li_dbcachesize, return_value, dblayer_strerror(return_value)); -+ slapi_log_err(SLAPI_LOG_CRIT, "bdb_start", -+ "mmap in opening database environment failed trying to allocate %" PRIu64 " bytes. (OS err %d - %s)\n", -+ li->li_dbcachesize, return_value, dblayer_strerror(return_value)); - bdb_free_env(&priv->dblayer_env); - priv->dblayer_env = CATASTROPHIC; - } else { -- slapi_log_err(SLAPI_LOG_CRIT, -- "bdb_start", "Opening database environment (%s) failed. err=%d: %s\n", -- region_dir, return_value, dblayer_strerror(return_value)); -+ slapi_log_err(SLAPI_LOG_CRIT, "bdb_start", -+ "Opening database environment (%s) failed. err=%d: %s\n", -+ region_dir, return_value, dblayer_strerror(return_value)); - } - } - return return_value; -diff --git a/ldap/servers/slapd/plugin.c b/ldap/servers/slapd/plugin.c -index b00c1bd8f..282b98738 100644 ---- a/ldap/servers/slapd/plugin.c -+++ b/ldap/servers/slapd/plugin.c -@@ -4383,14 +4383,14 @@ slapi_set_plugin_open_rootdn_bind(Slapi_PBlock *pb) - } - - PRBool --slapi_disordely_shutdown(PRBool set) -+slapi_disorderly_shutdown(PRBool set) - { -- static PRBool is_disordely_shutdown = PR_FALSE; -+ static PRBool is_disorderly_shutdown = PR_FALSE; - - if (set) { -- is_disordely_shutdown = PR_TRUE; -+ is_disorderly_shutdown = PR_TRUE; - } -- return (is_disordely_shutdown); -+ return (is_disorderly_shutdown); - } - - /* -diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h -index 29a6238d9..50b8d12c8 100644 ---- a/ldap/servers/slapd/slapi-plugin.h -+++ b/ldap/servers/slapd/slapi-plugin.h -@@ -7900,7 +7900,7 @@ uint64_t slapi_str_to_u64(const char *s); - - void slapi_set_plugin_open_rootdn_bind(Slapi_PBlock *pb); - --PRBool slapi_disordely_shutdown(PRBool set); -+PRBool slapi_disorderly_shutdown(PRBool set); - - /* - * Public entry extension getter/setter functions --- -2.21.1 - diff --git a/SOURCES/0011-Issue-50746-Add-option-to-healthcheck-to-list-all-th.patch b/SOURCES/0011-Issue-50746-Add-option-to-healthcheck-to-list-all-th.patch new file mode 100644 index 0000000..c63a63c --- /dev/null +++ b/SOURCES/0011-Issue-50746-Add-option-to-healthcheck-to-list-all-th.patch @@ -0,0 +1,1218 @@ +From 21ed5224d63e3118a39ddd5ea438367532541a8f Mon Sep 17 00:00:00 2001 +From: Matus Honek +Date: Mon, 2 Dec 2019 14:53:31 +0100 +Subject: [PATCH 11/12] Issue 50746 - Add option to healthcheck to list all the + lint reports + +Bug Description: +Healthcheck lacks a way to find out what checks are available. + +Fix Description: +Add dsctl healthcheck options to list available checks, known error +codes, and ability to run cehcks selectively. The checks are rather +hierarchically structured and in some cases matchable by patterns (by +use of asterisk). + +Fixes https://pagure.io/389-ds-base/issue/50746 + +Author: Matus Honek + +Review by: Mark, William, Simon (thanks for the patience!) + +(cherry picked from commit 4a55322c7bdb0b9ff57428ad0dc2e4d943572a69) +--- + src/lib389/cli/dsctl | 1 + + src/lib389/lib389/_mapped_object.py | 34 +--- + src/lib389/lib389/_mapped_object_lint.py | 157 ++++++++++++++++++ + src/lib389/lib389/backend.py | 13 +- + src/lib389/lib389/cli_ctl/health.py | 116 +++++++++---- + src/lib389/lib389/config.py | 13 +- + src/lib389/lib389/dseldif.py | 29 +--- + src/lib389/lib389/encrypted_attributes.py | 1 - + src/lib389/lib389/index.py | 3 - + src/lib389/lib389/lint.py | 125 ++++++++------ + src/lib389/lib389/monitor.py | 5 +- + src/lib389/lib389/nss_ssl.py | 23 ++- + src/lib389/lib389/plugins.py | 5 +- + src/lib389/lib389/replica.py | 10 +- + .../lib389/tests/mapped_object_lint_test.py | 78 +++++++++ + 15 files changed, 448 insertions(+), 165 deletions(-) + create mode 100644 src/lib389/lib389/_mapped_object_lint.py + create mode 100644 src/lib389/lib389/tests/mapped_object_lint_test.py + +diff --git a/src/lib389/cli/dsctl b/src/lib389/cli/dsctl +index fd9bd87c1..9deda7039 100755 +--- a/src/lib389/cli/dsctl ++++ b/src/lib389/cli/dsctl +@@ -64,6 +64,7 @@ cli_dbgen.create_parser(subparsers) + + argcomplete.autocomplete(parser) + ++ + # handle a control-c gracefully + def signal_handler(signal, frame): + print('\n\nExiting...') +diff --git a/src/lib389/lib389/_mapped_object.py b/src/lib389/lib389/_mapped_object.py +index ce0ebfeb8..c60837601 100644 +--- a/src/lib389/lib389/_mapped_object.py ++++ b/src/lib389/lib389/_mapped_object.py +@@ -15,6 +15,7 @@ import json + from functools import partial + from lib389._entry import Entry + from lib389._constants import DIRSRV_STATE_ONLINE ++from lib389._mapped_object_lint import DSLint, DSLints + from lib389.utils import ( + ensure_bytes, ensure_str, ensure_int, ensure_list_bytes, ensure_list_str, + ensure_list_int, display_log_value, display_log_data +@@ -82,7 +83,7 @@ class DSLogging(object): + self._log.setLevel(logging.INFO) + + +-class DSLdapObject(DSLogging): ++class DSLdapObject(DSLogging, DSLint): + """A single instance of DSLdapObjects + + :param instance: An instance +@@ -107,7 +108,6 @@ class DSLdapObject(DSLogging): + self._must_attributes = None + # attributes, we don't want to compare + self._compare_exclude = ['entryid', 'modifytimestamp', 'nsuniqueid'] +- self._lint_functions = None + self._server_controls = None + self._client_controls = None + self._object_filter = '(objectClass=*)' +@@ -985,38 +985,10 @@ class DSLdapObject(DSLogging): + """ + return self._create(rdn, properties, basedn, ensure=True) + +- def lint(self): +- """Override this to create a linter for a type. This means that we can detect +- and report common administrative errors in the server from our cli and +- rest tools. +- +- The structure of a result is:: +- +- { +- dsle: ''. dsle == ds lint error. Will be a code unique to +- this module for the error, IE DSBLE0001. +- severity: '[HIGH:MEDIUM:LOW]'. severity of the error. +- items: '(dn,dn,dn)'. List of affected DNs or names. +- detail: 'msg ...'. An explination of the error. +- fix: 'msg ...'. Steps to resolve the error. +- } +- +- :returns: An array of these dicts, on None if there are no errors. +- """ +- +- if not self._lint_functions: +- return None +- results = [] +- for fn in self._lint_functions: +- for result in fn(): +- if result is not None: +- results.append(result) +- return results +- + + # A challenge of this, is how do we manage indexes? They have two naming attributes.... + +-class DSLdapObjects(DSLogging): ++class DSLdapObjects(DSLogging, DSLints): + """The object represents the next idea: "Everything is an instance of something + that exists in this way", i.e. we unite LDAP entries by some + set of parameters with the object. +diff --git a/src/lib389/lib389/_mapped_object_lint.py b/src/lib389/lib389/_mapped_object_lint.py +new file mode 100644 +index 000000000..2d03de98f +--- /dev/null ++++ b/src/lib389/lib389/_mapped_object_lint.py +@@ -0,0 +1,157 @@ ++from abc import ABC, abstractmethod ++from functools import partial ++from inspect import signature ++from typing import ( ++ Callable, ++ List, ++ Optional, ++ Tuple, ++ Union, ++ Type, ++ Generator, ++ Any ++) ++ ++ ++DSLintSpec = Tuple[str, Callable] ++DSLintParsedSpec = Tuple[Optional[str], Optional[str]] ++DSLintClassSpec = Generator[DSLintSpec, None, None] ++DSLintMethodSpec = Union[str, None, Type[List]] ++DSLintResults = Generator[Any, None, None] ++ ++ ++class DSLint(): ++ """In a super-class, create a method with name beginning with `_lint_` ++ which would yield results (as described below). Such a method will ++ then be available to the `lint()` method of the class. ++ ++ `lint_list`: takes a spec and yields available lints, recursively ++ `lint`: takes a spac and runs lints according to it, yielding results if any ++ ++ `spec`: is a colon-separated string, with prefix matching a method name and suffix ++ being passed down to the method. ++ ++ A class inheriting from hereby class shall implement a method named `lint_uid()` which ++ returns a pretty name of the object. This is to be used by a higher level code. ++ ++ Each lint method has to have a name prefix with _lint_. It may accept an optional ++ parameter `spec` in which case: ++ - it has to accept typing.List class as a parameter, in which case it shall yield ++ all possible lint specs for that method ++ - it receives the suffix provided to the `spec` of hereby `lint` method (as mentioned above) ++ ++ This means that we can detect and report common administrative errors ++ in the server from our cli and rest tools. ++ ++ The structure of a result shall be: ++ ++ { ++ dsle: ''. dsle == ds lint error. Will be a code unique to ++ this module for the error, IE DSBLE0001. ++ severity: '[HIGH:MEDIUM:LOW]'. severity of the error. ++ items: '(dn,dn,dn)'. List of affected DNs or names. ++ detail: 'msg ...'. An explination of the error. ++ fix: 'msg ...'. Steps to resolve the error. ++ } ++ """ ++ ++ @classmethod ++ def _dslint_fname(cls, method: Callable) -> Optional[str]: ++ """Return a pretty name for a method.""" ++ if callable(method) and method.__name__.startswith('_lint_'): ++ return method.__name__[len('_lint_'):] ++ else: ++ return None ++ ++ @staticmethod ++ def _dslint_parse_spec(spec: Optional[str]) -> DSLintParsedSpec: ++ """Split `spec` to prefix and suffix.""" ++ wanted, *rest = spec.split(':', 1) if spec else (None, None) ++ return (wanted if wanted not in [None, '*'] else None, ++ rest[0] if rest else None) ++ ++ @classmethod ++ def _dslint_make_spec(cls, method: Callable, spec: Optional[str] = None) -> str: ++ """Build a new spec from prefix (`method` name) and suffix (`spec`).""" ++ fname = cls._dslint_fname(method) ++ return f'{fname}:{spec}' if spec else fname ++ ++ def lint_list(self, spec: Optional[str] = None) -> DSLintClassSpec: ++ """Yield specs the object provides. ++ ++ This yields from each lint method yielding all specs it can provide. ++ """ ++ ++ assert hasattr(self, 'lint_uid') ++ ++ # Find _lint_ methods ++ # NOTE: There is a caveat: don't you dare try to getattr on a @property, or ++ # you get it executed. That's why the following line's complexity. ++ fs = [getattr(self, f) for f in dir(self) ++ if f.startswith('_lint_') and self._dslint_fname(getattr(self, f))] ++ ++ # Filter acording to the `spec` ++ wanted, rest = self._dslint_parse_spec(spec) ++ if wanted: ++ try: ++ fs = [next(filter(lambda f: self._dslint_fname(f) == wanted, fs))] ++ except StopIteration: ++ raise ValueError('there is no such lint function') ++ ++ # Yield known specs ++ for f in fs: ++ fspec_t = signature(f).parameters.get('spec', None) ++ if fspec_t: ++ assert fspec_t.annotation == DSLintMethodSpec ++ for fspec in [rest] if rest else f(spec=List): ++ yield self._dslint_make_spec(f, fspec), partial(f, spec=fspec) ++ else: ++ yield self._dslint_make_spec(f, rest), f ++ ++ def lint(self, spec: DSLintMethodSpec = None) -> DSLintResults: ++ """Lint the object according to the `spec`.""" ++ ++ if spec == List: ++ yield from self.lint_list() ++ else: ++ for fn, f in self.lint_list(spec): ++ yield from f() ++ ++ ++class DSLints(): ++ """This is a meta class to provide lint functionality to classes that provide ++ method `list` which returns list of objects that inherit from DSLint. ++ ++ Calling `lint` or `lint_list` method yields from respective object's methods. ++ ++ The `spec` is a colon-separated string. Its prefix matches the respective object's ++ `lint_uid` (or all when asterisk); the suffix is passed down to the respective ++ object's method. ++ """ ++ ++ def lint_list(self, spec: Optional[str] = None) -> DSLintClassSpec: ++ """Yield specs the objects returned by `list` method provide.""" ++ ++ assert hasattr(self, 'list') ++ ++ # Filter acording to the `spec` ++ wanted, rest_spec = DSLint._dslint_parse_spec(spec) ++ if wanted in [None, '*']: ++ clss = self.list() ++ else: ++ clss = (cls for cls in self.list() if cls.lint_uid() == wanted) ++ ++ # Yield known specs ++ for cls in clss: ++ for fn, f in cls.lint_list(spec=rest_spec): ++ yield (f'{cls.lint_uid()}:{fn}', ++ partial(f, rest_spec) if rest_spec else f) ++ ++ def lint(self, spec: DSLintMethodSpec = None) -> DSLintResults: ++ """Lint the objects returned by `list` method according to the `spec`.""" ++ ++ if spec == List: ++ yield from self.lint_list() ++ else: ++ for obj in self.list(): ++ yield from obj.lint() +diff --git a/src/lib389/lib389/backend.py b/src/lib389/lib389/backend.py +index 4f752f414..8863ad1a8 100644 +--- a/src/lib389/lib389/backend.py ++++ b/src/lib389/lib389/backend.py +@@ -393,6 +393,10 @@ class BackendLegacy(object): + replace = [(ldap.MOD_REPLACE, 'nsslapd-require-index', 'on')] + self.modify_s(dn, replace) + ++ @classmethod ++ def lint_uid(cls): ++ return 'backends' ++ + + class Backend(DSLdapObject): + """Backend DSLdapObject with: +@@ -413,10 +417,12 @@ class Backend(DSLdapObject): + self._must_attributes = ['nsslapd-suffix', 'cn'] + self._create_objectclasses = ['top', 'extensibleObject', BACKEND_OBJECTCLASS_VALUE] + self._protected = False +- self._lint_functions = [self._lint_mappingtree, self._lint_search, self._lint_virt_attrs] + # Check if a mapping tree for this suffix exists. + self._mts = MappingTrees(self._instance) + ++ def lint_uid(self): ++ return self.get_attr_val_utf8_l('cn').lower() ++ + def _lint_virt_attrs(self): + """Check if any virtual attribute are incorrectly indexed""" + indexes = self.get_indexes() +@@ -497,7 +503,6 @@ class Backend(DSLdapObject): + result = DSBLE0001 + result['items'] = [bename, ] + yield result +- return None + + def create_sample_entries(self, version): + """Creates sample entries under nsslapd-suffix value +@@ -848,6 +853,10 @@ class Backends(DSLdapObjects): + self._childobject = Backend + self._basedn = DN_LDBM + ++ @classmethod ++ def lint_uid(cls): ++ return 'backends' ++ + def import_ldif(self, be_name, ldifs, chunk_size=None, encrypted=False, gen_uniq_id=None, only_core=False, + include_suffixes=None, exclude_suffixes=None): + """Do an import of the suffix""" +diff --git a/src/lib389/lib389/cli_ctl/health.py b/src/lib389/lib389/cli_ctl/health.py +index 3d15ad85e..6333a753a 100644 +--- a/src/lib389/lib389/cli_ctl/health.py ++++ b/src/lib389/lib389/cli_ctl/health.py +@@ -7,6 +7,9 @@ + # --- END COPYRIGHT BLOCK --- + + import json ++import re ++from lib389._mapped_object import DSLdapObjects ++from lib389._mapped_object_lint import DSLint + from lib389.cli_base import connect_instance, disconnect_instance + from lib389.cli_base.dsrc import dsrc_to_ldap, dsrc_arg_concat + from lib389.backend import Backends +@@ -15,17 +18,17 @@ from lib389.monitor import MonitorDiskSpace + from lib389.replica import Replica, Changelog5 + from lib389.nss_ssl import NssSsl + from lib389.dseldif import FSChecks, DSEldif ++from lib389 import lint + from lib389 import plugins + from lib389._constants import DSRC_HOME ++from functools import partial ++from typing import Iterable + +-# These get all instances, then check them all. +-CHECK_MANY_OBJECTS = [ +- Backends, +-] + + # These get single instances and check them. + CHECK_OBJECTS = [ + Config, ++ Backends, + Encryption, + FSChecks, + plugins.ReferentialIntegrityPlugin, +@@ -52,44 +55,51 @@ def _format_check_output(log, result, idx): + log.info(result['fix']) + + +-def health_check_run(inst, log, args): +- """Connect to the local server using LDAPI, and perform various health checks +- """ ++def _list_targets(inst): ++ for c in CHECK_OBJECTS: ++ o = c(inst) ++ yield o.lint_uid(), o ++ ++ ++def _list_errors(log): ++ for r in map(partial(getattr, lint), ++ filter(partial(re.match, r'^DS'), ++ dir(lint))): ++ log.info(f"{r['dsle']} :: {r['description']}") + +- # update the args for connect_instance() +- args.basedn = None +- args.binddn = None +- args.bindpw = None +- args.starttls = None +- args.pwdfile = None +- args.prompt = False +- dsrc_inst = dsrc_to_ldap(DSRC_HOME, args.instance, log.getChild('dsrc')) +- dsrc_inst = dsrc_arg_concat(args, dsrc_inst) +- try: +- inst = connect_instance(dsrc_inst=dsrc_inst, verbose=args.verbose, args=args) +- except Exception as e: +- raise ValueError('Failed to connect to Directory Server instance: ' + str(e)) + ++def _list_checks(inst, specs: Iterable[str]): ++ o_uids = dict(_list_targets(inst)) ++ for s in specs: ++ wanted, rest = DSLint._dslint_parse_spec(s) ++ if wanted == '*': ++ raise ValueError('Unexpected spec selector asterisk') ++ ++ if wanted in o_uids: ++ for l in o_uids[wanted].lint_list(rest): ++ yield o_uids[wanted], l ++ else: ++ raise ValueError('No such object specifier') ++ ++ ++def _print_checks(inst, specs: Iterable[str]) -> None: ++ for o, s in _list_checks(inst, specs): ++ print(f'{o.lint_uid()}:{s[0]}') ++ ++ ++def _run(inst, log, args, checks): + if not args.json: + log.info("Beginning lint report, this could take a while ...") ++ + report = [] +- for lo in CHECK_MANY_OBJECTS: ++ for o, s in checks: + if not args.json: +- log.info("Checking %s ..." % lo.__name__) +- lo_inst = lo(inst) +- for clo in lo_inst.list(): +- result = clo.lint() +- if result is not None: +- report += result +- for lo in CHECK_OBJECTS: +- if not args.json: +- log.info("Checking %s ..." % lo.__name__) +- lo_inst = lo(inst) +- result = lo_inst.lint() +- if result is not None: +- report += result ++ log.info(f"Checking {o.lint_uid()}:{s[0]} ...") ++ report += o.lint(s[0]) or [] ++ + if not args.json: + log.info("Healthcheck complete.") ++ + count = len(report) + if count == 0: + if not args.json: +@@ -110,6 +120,37 @@ def health_check_run(inst, log, args): + else: + log.info(json.dumps(report, indent=4)) + ++ ++def health_check_run(inst, log, args): ++ """Connect to the local server using LDAPI, and perform various health checks ++ """ ++ ++ if args.list_errors: ++ _list_errors(log) ++ return ++ ++ # update the args for connect_instance() ++ args.basedn = None ++ args.binddn = None ++ args.bindpw = None ++ args.starttls = None ++ args.pwdfile = None ++ args.prompt = False ++ dsrc_inst = dsrc_to_ldap(DSRC_HOME, args.instance, log.getChild('dsrc')) ++ dsrc_inst = dsrc_arg_concat(args, dsrc_inst) ++ try: ++ inst = connect_instance(dsrc_inst=dsrc_inst, verbose=args.verbose, args=args) ++ except Exception as e: ++ raise ValueError('Failed to connect to Directory Server instance: ' + str(e)) ++ ++ checks = args.check or dict(_list_targets(inst)).keys() ++ ++ if args.list_checks or args.dry_run: ++ _print_checks(inst, checks) ++ return ++ ++ _run(inst, log, args, _list_checks(inst, checks)) ++ + disconnect_instance(inst) + + +@@ -120,4 +161,9 @@ def create_parser(subparsers): + "remote Directory Server as this tool needs access to local resources, " + "otherwise the report may be inaccurate.") + run_healthcheck_parser.set_defaults(func=health_check_run) +- ++ run_healthcheck_parser.add_argument('--list-checks', action='store_true', help='List of known checks') ++ run_healthcheck_parser.add_argument('--list-errors', action='store_true', help='List of known error codes') ++ run_healthcheck_parser.add_argument('--dry-run', action='store_true', help='Do not execute the actual check, only list what would be done') ++ run_healthcheck_parser.add_argument('--check', nargs='+', default=None, ++ help='Areas to check. These can be obtained by --list-checks. Every element on the left of the colon (:)' ++ ' may be replaced by an asterisk if multiple options on the right are available.') +diff --git a/src/lib389/lib389/config.py b/src/lib389/lib389/config.py +index a29d0244c..aa4c92beb 100644 +--- a/src/lib389/lib389/config.py ++++ b/src/lib389/lib389/config.py +@@ -54,7 +54,6 @@ class Config(DSLdapObject): + ] + self._compare_exclude = self._compare_exclude + config_compare_exclude + self._rdn_attribute = 'cn' +- self._lint_functions = [self._lint_hr_timestamp, self._lint_passwordscheme] + + @property + def dn(self): +@@ -197,6 +196,10 @@ class Config(DSLdapObject): + fields = 'nsslapd-security nsslapd-ssl-check-hostname'.split() + return self._instance.getEntry(DN_CONFIG, attrlist=fields) + ++ @classmethod ++ def lint_uid(cls): ++ return 'config' ++ + def _lint_hr_timestamp(self): + hr_timestamp = self.get_attr_val('nsslapd-logging-hr-timestamps-enabled') + if ensure_bytes('on') != hr_timestamp: +@@ -242,20 +245,22 @@ class Encryption(DSLdapObject): + self._rdn_attribute = 'cn' + self._must_attributes = ['cn'] + self._protected = True +- self._lint_functions = [self._lint_check_tls_version] + + def create(self, rdn=None, properties={'cn': 'encryption', 'nsSSLClientAuth': 'allowed'}): + if rdn is not None: + self._log.debug("dn on cn=encryption is not None. This is a mistake.") + super(Encryption, self).create(properties=properties) + ++ @classmethod ++ def lint_uid(cls): ++ return 'encryption' ++ + def _lint_check_tls_version(self): + tls_min = self.get_attr_val('sslVersionMin') + if tls_min is not None and tls_min < ensure_bytes('TLS1.1'): + report = copy.deepcopy(DSELE0001) + report['fix'] = report['fix'].replace('YOUR_INSTANCE', self._instance.serverid) + yield report +- yield None + + @property + def ciphers(self): +@@ -487,7 +492,6 @@ class LDBMConfig(DSLdapObject): + self._dn = DN_CONFIG_LDBM + # config_compare_exclude = [] + self._rdn_attribute = 'cn' +- self._lint_functions = [] + self._protected = True + + +@@ -506,5 +510,4 @@ class BDB_LDBMConfig(DSLdapObject): + self._dn = DN_CONFIG_LDBM_BDB + self._config_compare_exclude = [] + self._rdn_attribute = 'cn' +- self._lint_functions = [] + self._protected = True +diff --git a/src/lib389/lib389/dseldif.py b/src/lib389/lib389/dseldif.py +index 5378e6ee9..96c9af9d1 100644 +--- a/src/lib389/lib389/dseldif.py ++++ b/src/lib389/lib389/dseldif.py +@@ -16,6 +16,7 @@ from datetime import timedelta + from stat import ST_MODE + # from lib389.utils import print_nice_time + from lib389.paths import Paths ++from lib389._mapped_object_lint import DSLint + from lib389.lint import ( + DSPERMLE0001, + DSPERMLE0002, +@@ -25,7 +26,7 @@ from lib389.lint import ( + ) + + +-class DSEldif(object): ++class DSEldif(DSLint): + """A class for working with dse.ldif file + + :param instance: An instance +@@ -58,15 +59,10 @@ class DSEldif(object): + processed_line = line + else: + processed_line = processed_line[:-1] + line[1:] +- self._lint_functions = [self._lint_nsstate] + +- def lint(self): +- results = [] +- for fn in self._lint_functions: +- for result in fn(): +- if result is not None: +- results.append(result) +- return results ++ @classmethod ++ def lint_uid(cls): ++ return 'dseldif' + + def _lint_nsstate(self): + suffixes = self.readNsState() +@@ -320,7 +316,7 @@ class DSEldif(object): + return states + + +-class FSChecks(object): ++class FSChecks(DSLint): + """This is for the healthcheck feature, check commonly used system config files the + server uses. This is here for lack of a better place to add this class. + """ +@@ -344,17 +340,10 @@ class FSChecks(object): + 'report': DSPERMLE0002 + }, + ] +- self._lint_functions = [self._lint_file_perms] + +- def lint(self): +- """Run a lint/healthcheck for this class +- """ +- results = [] +- for fn in self._lint_functions: +- for result in fn(): +- if result is not None: +- results.append(result) +- return results ++ @classmethod ++ def lint_uid(cls): ++ return 'fschecks' + + def _lint_file_perms(self): + """Test file permissions are safe +diff --git a/src/lib389/lib389/encrypted_attributes.py b/src/lib389/lib389/encrypted_attributes.py +index 9afd2e66b..2fa26cef9 100644 +--- a/src/lib389/lib389/encrypted_attributes.py ++++ b/src/lib389/lib389/encrypted_attributes.py +@@ -27,7 +27,6 @@ class EncryptedAttr(DSLdapObject): + self._must_attributes = ['cn', 'nsEncryptionAlgorithm'] + self._create_objectclasses = ['top', 'nsAttributeEncryption'] + self._protected = False +- self._lint_functions = [] + + + class EncryptedAttrs(DSLdapObjects): +diff --git a/src/lib389/lib389/index.py b/src/lib389/lib389/index.py +index 6932883b7..a3d019d27 100644 +--- a/src/lib389/lib389/index.py ++++ b/src/lib389/lib389/index.py +@@ -41,7 +41,6 @@ class Index(DSLdapObject): + self._must_attributes = ['cn', 'nsSystemIndex', 'nsIndexType'] + self._create_objectclasses = ['top', 'nsIndex'] + self._protected = False +- self._lint_functions = [] + + + class Indexes(DSLdapObjects): +@@ -77,7 +76,6 @@ class VLVSearch(DSLdapObject): + self._must_attributes = ['cn', 'vlvbase', 'vlvscope', 'vlvfilter'] + self._create_objectclasses = ['top', 'vlvSearch'] + self._protected = False +- self._lint_functions = [] + self._be_name = None + + def get_sorts(self): +@@ -163,7 +161,6 @@ class VLVIndex(DSLdapObject): + self._must_attributes = ['cn', 'vlvsort'] + self._create_objectclasses = ['top', 'vlvIndex'] + self._protected = False +- self._lint_functions = [] + + + class VLVIndexes(DSLdapObjects): +diff --git a/src/lib389/lib389/lint.py b/src/lib389/lib389/lint.py +index b5a305bc3..a103feec7 100644 +--- a/src/lib389/lib389/lint.py ++++ b/src/lib389/lib389/lint.py +@@ -14,8 +14,9 @@ + DSBLE0001 = { + 'dsle': 'DSBLE0001', + 'severity': 'MEDIUM', +- 'items' : [], +- 'detail' : """This backend may be missing the correct mapping tree references. Mapping Trees allow ++ 'description': 'Possibly incorrect mapping tree.', ++ 'items': [], ++ 'detail': """This backend may be missing the correct mapping tree references. Mapping Trees allow + the directory server to determine which backend an operation is routed to in the + abscence of other information. This is extremely important for correct functioning + of LDAP ADD for example. +@@ -32,7 +33,7 @@ objectClass: extensibleObject + objectClass: nsMappingTree + + """, +- 'fix' : """Either you need to create the mapping tree, or you need to repair the related ++ 'fix': """Either you need to create the mapping tree, or you need to repair the related + mapping tree. You will need to do this by hand by editing cn=config, or stopping + the instance and editing dse.ldif. + """ +@@ -41,25 +42,28 @@ the instance and editing dse.ldif. + DSBLE0002 = { + 'dsle': 'DSBLE0002', + 'severity': 'HIGH', +- 'items' : [], +- 'detail' : """Unable to query the backend. LDAP error (ERROR)""", +- 'fix' : """Check the server's error and access logs for more information.""" ++ 'description': 'Unable to query backend.', ++ 'items': [], ++ 'detail': """Unable to query the backend. LDAP error (ERROR)""", ++ 'fix': """Check the server's error and access logs for more information.""" + } + + DSBLE0003 = { + 'dsle': 'DSBLE0003', + 'severity': 'LOW', +- 'items' : [], +- 'detail' : """The backend database has not been initialized yet""", +- 'fix' : """You need to import an LDIF file, or create the suffix entry, in order to initialize the database.""" ++ 'description': 'Uninitialized backend database.', ++ 'items': [], ++ 'detail': """The backend database has not been initialized yet""", ++ 'fix': """You need to import an LDIF file, or create the suffix entry, in order to initialize the database.""" + } + + # Config checks + DSCLE0001 = { +- 'dsle' : 'DSCLE0001', +- 'severity' : 'LOW', ++ 'dsle': 'DSCLE0001', ++ 'severity': 'LOW', ++ 'description': 'Different log timestamp format.', + 'items': ['cn=config', ], +- 'detail' : """nsslapd-logging-hr-timestamps-enabled changes the log format in directory server from ++ 'detail': """nsslapd-logging-hr-timestamps-enabled changes the log format in directory server from + + [07/Jun/2017:17:15:58 +1000] + +@@ -70,7 +74,7 @@ to + This actually provides a performance improvement. Additionally, this setting will be + removed in a future release. + """, +- 'fix' : """Set nsslapd-logging-hr-timestamps-enabled to on. ++ 'fix': """Set nsslapd-logging-hr-timestamps-enabled to on. + You can use 'dsconf' to set this attribute. Here is an example: + + # dsconf slapd-YOUR_INSTANCE config replace nsslapd-logging-hr-timestamps-enabled=on""" +@@ -79,8 +83,9 @@ You can use 'dsconf' to set this attribute. Here is an example: + DSCLE0002 = { + 'dsle': 'DSCLE0002', + 'severity': 'HIGH', +- 'items' : ['cn=config', ], +- 'detail' : """Password storage schemes in Directory Server define how passwords are hashed via a ++ 'description': 'Weak passwordStorageScheme.', ++ 'items': ['cn=config', ], ++ 'detail': """Password storage schemes in Directory Server define how passwords are hashed via a + one-way mathematical function for storage. Knowing the hash it is difficult to gain + the input, but knowing the input you can easily compare the hash. + +@@ -112,14 +117,15 @@ You can also use 'dsconf' to replace these values. Here is an example: + DSELE0001 = { + 'dsle': 'DSELE0001', + 'severity': 'MEDIUM', +- 'items' : ['cn=encryption,cn=config', ], ++ 'description': 'Weak TLS protocol version.', ++ 'items': ['cn=encryption,cn=config', ], + 'detail': """This Directory Server may not be using strong TLS protocol versions. TLS1.0 is known to + have a number of issues with the protocol. Please see: + + https://tools.ietf.org/html/rfc7457 + + It is advised you set this value to the maximum possible.""", +- 'fix' : """There are two options for setting the TLS minimum version allowed. You, ++ 'fix': """There are two options for setting the TLS minimum version allowed. You, + can set "sslVersionMin" in "cn=encryption,cn=config" to a version greater than "TLS1.0" + You can also use 'dsconf' to set this value. Here is an example: + +@@ -137,7 +143,8 @@ minimum version, but doing this affects the entire system: + DSRILE0001 = { + 'dsle': 'DSRILE0001', + 'severity': 'LOW', +- 'items' : ['cn=referential integrity postoperation,cn=plugins,cn=config', ], ++ 'description': 'Referential integrity plugin may be slower.', ++ 'items': ['cn=referential integrity postoperation,cn=plugins,cn=config', ], + 'detail': """The referential integrity plugin has an asynchronous processing mode. + This is controlled by the update-delay flag. When this value is 0, referential + integrity plugin processes these changes inside of the operation that modified +@@ -151,7 +158,7 @@ delays to your server by batching changes rather than smaller updates during syn + + We advise that you set this value to 0, and enable referint on all masters as it provides a more predictable behaviour. + """, +- 'fix' : """Set referint-update-delay to 0. ++ 'fix': """Set referint-update-delay to 0. + + You can use 'dsconf' to set this value. Here is an example: + +@@ -164,12 +171,13 @@ You must restart the Directory Server for this change to take effect.""" + DSRILE0002 = { + 'dsle': 'DSRILE0002', + 'severity': 'HIGH', +- 'items' : ['cn=referential integrity postoperation,cn=plugins,cn=config'], ++ 'description': 'Referential integrity plugin configured with unindexed attribute.', ++ 'items': ['cn=referential integrity postoperation,cn=plugins,cn=config'], + 'detail': """The referential integrity plugin is configured to use an attribute (ATTR) + that does not have an "equality" index in backend (BACKEND). + Failure to have the proper indexing will lead to unindexed searches which + cause high CPU and can significantly slow the server down.""", +- 'fix' : """Check the attributes set in "referint-membership-attr" to make sure they have ++ 'fix': """Check the attributes set in "referint-membership-attr" to make sure they have + an index defined that has at least the equality "eq" index type. You will + need to reindex the database after adding the missing index type. Here is an + example using dsconf: +@@ -182,12 +190,13 @@ example using dsconf: + DSDSLE0001 = { + 'dsle': 'DSDSLE0001', + 'severity': 'HIGH', +- 'items' : ['Server', 'cn=config'], ++ 'description': 'Low disk space.', ++ 'items': ['Server', 'cn=config'], + 'detail': """The disk partition used by the server (PARTITION), either for the database, the + configuration files, or the logs is over 90% full. If the partition becomes + completely filled serious problems can occur with the database or the server's + stability.""", +- 'fix' : """Attempt to free up disk space. Also try removing old rotated logs, or disable any ++ 'fix': """Attempt to free up disk space. Also try removing old rotated logs, or disable any + verbose logging levels that might have been set. You might consider enabling + the "Disk Monitoring" feature in cn=config to help prevent a disorderly shutdown + of the server: +@@ -210,9 +219,10 @@ Please see the Administration guide for more information: + DSREPLLE0001 = { + 'dsle': 'DSREPLLE0001', + 'severity': 'HIGH', +- 'items' : ['Replication', 'Agreement'], ++ 'description': 'Replication agreement not set to be synchronized.', ++ 'items': ['Replication', 'Agreement'], + 'detail': """The replication agreement (AGMT) under "SUFFIX" is not in synchronization.""", +- 'fix' : """You may need to reinitialize this replication agreement. Please check the errors ++ 'fix': """You may need to reinitialize this replication agreement. Please check the errors + log for more information. If you do need to reinitialize the agreement you can do so + using dsconf. Here is an example: + +@@ -223,9 +233,10 @@ using dsconf. Here is an example: + DSREPLLE0002 = { + 'dsle': 'DSREPLLE0002', + 'severity': 'LOW', +- 'items' : ['Replication', 'Conflict Entries'], ++ 'description': 'Replication conflict entries found.', ++ 'items': ['Replication', 'Conflict Entries'], + 'detail': "There were COUNT conflict entries found under the replication suffix \"SUFFIX\".", +- 'fix' : """While conflict entries are expected to occur in an MMR environment, they ++ 'fix': """While conflict entries are expected to occur in an MMR environment, they + should be resolved. In regards to conflict entries there is always the original/counterpart + entry that has a normal DN, and then the conflict version of that entry. Technically both + entries are valid, you as the administrator, needs to decide which entry you want to keep. +@@ -253,38 +264,42 @@ can use the CLI tool "dsconf" to resolve the conflict. Here is an example: + DSREPLLE0003 = { + 'dsle': 'DSREPLLE0003', + 'severity': 'MEDIUM', +- 'items' : ['Replication', 'Agreement'], ++ 'description': 'Unsynchronized replication agreement.', ++ 'items': ['Replication', 'Agreement'], + 'detail': """The replication agreement (AGMT) under "SUFFIX" is not in synchronization. + Status message: MSG""", +- 'fix' : """Replication is not in synchronization but it may recover. Continue to ++ 'fix': """Replication is not in synchronization but it may recover. Continue to + monitor this agreement.""" + } + + DSREPLLE0004 = { + 'dsle': 'DSREPLLE0004', + 'severity': 'MEDIUM', +- 'items' : ['Replication', 'Agreement'], ++ 'description': 'Unable to get replication agreement status.', ++ 'items': ['Replication', 'Agreement'], + 'detail': """Failed to get the agreement status for agreement (AGMT) under "SUFFIX". Error (ERROR).""", +- 'fix' : """None""" ++ 'fix': """None""" + } + + DSREPLLE0005 = { + 'dsle': 'DSREPLLE0005', + 'severity': 'MEDIUM', +- 'items' : ['Replication', 'Agreement'], ++ 'description': 'Replication consumer not reachable.', ++ 'items': ['Replication', 'Agreement'], + 'detail': """The replication agreement (AGMT) under "SUFFIX" is not in synchronization, + because the consumer server is not reachable.""", +- 'fix' : """Check if the consumer is running, and also check the errors log for more information.""" ++ 'fix': """Check if the consumer is running, and also check the errors log for more information.""" + } + + # Replication changelog + DSCLLE0001 = { + 'dsle': 'DSCLLE0001', + 'severity': 'LOW', +- 'items' : ['Replication', 'Changelog'], ++ 'description': 'Changelog trimming not configured.', ++ 'items': ['Replication', 'Changelog'], + 'detail': """The replication changelog does have any kind of trimming configured. This will + lead to the changelog size growing indefinitely.""", +- 'fix' : """Configure changelog trimming, preferably by setting the maximum age of a changelog ++ 'fix': """Configure changelog trimming, preferably by setting the maximum age of a changelog + record. Here is an example: + + # dsconf slapd-YOUR_INSTANCE replication set-changelog --max-age 30d""" +@@ -294,27 +309,30 @@ record. Here is an example: + DSCERTLE0001 = { + 'dsle': 'DSCERTLE0001', + 'severity': 'MEDIUM', +- 'items' : ['Expiring Certificate'], ++ 'description': 'Certificate about to expire.', ++ 'items': ['Expiring Certificate'], + 'detail': """The certificate (CERT) will expire in less than 30 days""", +- 'fix' : """Renew the certificate before it expires to prevent disruptions with TLS connections.""" ++ 'fix': """Renew the certificate before it expires to prevent disruptions with TLS connections.""" + } + + DSCERTLE0002 = { + 'dsle': 'DSCERTLE0002', + 'severity': 'HIGH', +- 'items' : ['Expired Certificate'], ++ 'description': 'Certificate expired.', ++ 'items': ['Expired Certificate'], + 'detail': """The certificate (CERT) has expired""", +- 'fix' : """Renew or remove the certificate.""" ++ 'fix': """Renew or remove the certificate.""" + } + + # Virtual Attrs & COS. Note - ATTR and SUFFIX are replaced by the reporting function + DSVIRTLE0001 = { + 'dsle': 'DSVIRTLE0001', + 'severity': 'HIGH', +- 'items' : ['Virtual Attributes'], ++ 'description': 'Virtual attribute indexed.', ++ 'items': ['Virtual Attributes'], + 'detail': """You should not index virtual attributes, and as this will break searches that + use the attribute in a filter.""", +- 'fix' : """Remove the index for this attribute from the backend configuration. ++ 'fix': """Remove the index for this attribute from the backend configuration. + Here is an example using 'dsconf' to remove an index: + + # dsconf slapd-YOUR_INSTANCE backend index delete --attr ATTR SUFFIX""" +@@ -324,10 +342,11 @@ Here is an example using 'dsconf' to remove an index: + DSPERMLE0001 = { + 'dsle': 'DSPERMLE0001', + 'severity': 'MEDIUM', +- 'items' : ['File Permissions'], ++ 'description': 'Incorrect file permissions.', ++ 'items': ['File Permissions'], + 'detail': """The file "FILE" does not have the expected permissions (PERMS). This + can cause issues with replication and chaining.""", +- 'fix' : """Change the file permissions: ++ 'fix': """Change the file permissions: + + # chmod PERMS FILE""" + } +@@ -336,10 +355,11 @@ can cause issues with replication and chaining.""", + DSPERMLE0002 = { + 'dsle': 'DSPERMLE0002', + 'severity': 'HIGH', +- 'items' : ['File Permissions'], ++ 'description': 'Incorrect security database file permissions.', ++ 'items': ['File Permissions'], + 'detail': """The file "FILE" does not have the expected permissions (PERMS). The + security database pin/password files should only be readable by Directory Server user.""", +- 'fix' : """Change the file permissions: ++ 'fix': """Change the file permissions: + + # chmod PERMS FILE""" + } +@@ -348,11 +368,12 @@ security database pin/password files should only be readable by Directory Server + DSSKEWLE0001 = { + 'dsle': 'DSSKEWLE0001', + 'severity': 'Low', +- 'items' : ['Replication'], ++ 'description': 'Medium time skew.', ++ 'items': ['Replication'], + 'detail': """The time skew is over 6 hours. If this time skew continues to increase + to 24 hours then replication can potentially stop working. Please continue to + monitor the time skew offsets for increasing values.""", +- 'fix' : """Monitor the time skew and avoid making changes to the system time. ++ 'fix': """Monitor the time skew and avoid making changes to the system time. + Also look at https://access.redhat.com/documentation/en-us/red_hat_directory_server/11/html/administration_guide/managing_replication-troubleshooting_replication_related_problems + and find the paragraph "Too much time skew".""" + } +@@ -360,13 +381,14 @@ and find the paragraph "Too much time skew".""" + DSSKEWLE0002 = { + 'dsle': 'DSSKEWLE0002', + 'severity': 'Medium', +- 'items' : ['Replication'], ++ 'description': 'Major time skew.', ++ 'items': ['Replication'], + 'detail': """The time skew is over 12 hours. If this time skew continues to increase + to 24 hours then replication can potentially stop working. Please continue to + monitor the time skew offsets for increasing values. Setting nsslapd-ignore-time-skew + to "on" on each replica will allow replication to continue, but if the time skew + continues to increase other more serious replication problems can occur.""", +- 'fix' : """Monitor the time skew and avoid making changes to the system time. ++ 'fix': """Monitor the time skew and avoid making changes to the system time. + If you get close to 24 hours of time skew replication may stop working. + In that case configure the server to ignore the time skew until the system + times can be fixed/synchronized: +@@ -380,12 +402,13 @@ and find the paragraph "Too much time skew".""" + DSSKEWLE0003 = { + 'dsle': 'DSSKEWLE0003', + 'severity': 'High', +- 'items' : ['Replication'], ++ 'description': 'Extensive time skew.', ++ 'items': ['Replication'], + 'detail': """The time skew is over 24 hours. Setting nsslapd-ignore-time-skew + to "on" on each replica will allow replication to continue, but if the + time skew continues to increase other serious replication problems can + occur.""", +- 'fix' : """Avoid making changes to the system time, and make sure the clocks ++ 'fix': """Avoid making changes to the system time, and make sure the clocks + on all the replicas are correct. If you haven't set the server's + "ignore time skew" setting then do the following on all the replicas + until the time issues have been resolved: +diff --git a/src/lib389/lib389/monitor.py b/src/lib389/lib389/monitor.py +index 73750c3c2..4ac7d7174 100644 +--- a/src/lib389/lib389/monitor.py ++++ b/src/lib389/lib389/monitor.py +@@ -358,7 +358,10 @@ class MonitorDiskSpace(DSLdapObject): + def __init__(self, instance, dn=None): + super(MonitorDiskSpace, self).__init__(instance=instance, dn=dn) + self._dn = "cn=disk space,cn=monitor" +- self._lint_functions = [self._lint_disk_space] ++ ++ @classmethod ++ def lint_uid(cls): ++ return 'monitor-disk-space' + + def _lint_disk_space(self): + partitions = self.get_attr_vals_utf8_l("dsDisk") +diff --git a/src/lib389/lib389/nss_ssl.py b/src/lib389/lib389/nss_ssl.py +index d14e7ce6f..e257424fd 100644 +--- a/src/lib389/lib389/nss_ssl.py ++++ b/src/lib389/lib389/nss_ssl.py +@@ -21,6 +21,7 @@ import subprocess + from datetime import datetime, timedelta + from subprocess import check_output, run, PIPE + from lib389.passwd import password_generate ++from lib389._mapped_object_lint import DSLint + from lib389.lint import DSCERTLE0001, DSCERTLE0002 + from lib389.utils import ensure_str, format_cmd_list + import uuid +@@ -42,7 +43,7 @@ VALID_MIN = 61 # Days + log = logging.getLogger(__name__) + + +-class NssSsl(object): ++class NssSsl(DSLint): + def __init__(self, dirsrv=None, dbpassword=None, dbpath=None): + self.dirsrv = dirsrv + self._certdb = dbpath +@@ -56,18 +57,14 @@ class NssSsl(object): + else: + self.dbpassword = dbpassword + +- self.db_files = {"dbm_backend": ["%s/%s" % (self._certdb, f) for f in ("key3.db", "cert8.db", "secmod.db")], +- "sql_backend": ["%s/%s" % (self._certdb, f) for f in ("key4.db", "cert9.db", "pkcs11.txt")], +- "support": ["%s/%s" % (self._certdb, f) for f in ("noise.txt", PIN_TXT, PWD_TXT)]} +- self._lint_functions = [self._lint_certificate_expiration,] +- +- def lint(self): +- results = [] +- for fn in self._lint_functions: +- for result in fn(): +- if result is not None: +- results.append(result) +- return results ++ self.db_files = {group: [f"{self._certdb}/{f}" for f in files] ++ for group, files in {"dbm_backend": ("key3.db", "cert8.db", "secmod.db"), ++ "sql_backend": ("key4.db", "cert9.db", "pkcs11.txt"), ++ "support": ("noise.txt", PIN_TXT, PWD_TXT)}.items()} ++ ++ @classmethod ++ def lint_uid(cls): ++ return 'ssl' + + def _lint_certificate_expiration(self): + """Check all the certificates in the db if they will expire within 30 days +diff --git a/src/lib389/lib389/plugins.py b/src/lib389/lib389/plugins.py +index f68a1d114..89e660287 100644 +--- a/src/lib389/lib389/plugins.py ++++ b/src/lib389/lib389/plugins.py +@@ -431,7 +431,6 @@ class ReferentialIntegrityPlugin(Plugin): + 'referint-logfile', + 'referint-membership-attr', + ]) +- self._lint_functions = [self._lint_update_delay, self._lint_attr_indexes] + + def create(self, rdn=None, properties=None, basedn=None): + """Create an instance of the plugin""" +@@ -443,6 +442,10 @@ class ReferentialIntegrityPlugin(Plugin): + properties['referint-logfile'] = referint_log + return super(ReferentialIntegrityPlugin, self).create(rdn, properties, basedn) + ++ @classmethod ++ def lint_uid(cls): ++ return 'refint' ++ + def _lint_update_delay(self): + if self.status(): + delay = self.get_attr_val_int("referint-update-delay") +diff --git a/src/lib389/lib389/replica.py b/src/lib389/lib389/replica.py +index f8adb3ce2..f575e58d5 100644 +--- a/src/lib389/lib389/replica.py ++++ b/src/lib389/lib389/replica.py +@@ -1049,7 +1049,10 @@ class Changelog5(DSLdapObject): + 'extensibleobject', + ] + self._protected = False +- self._lint_functions = [self._lint_cl_trimming] ++ ++ @classmethod ++ def lint_uid(cls): ++ return 'changelog' + + def _lint_cl_trimming(self): + """Check that cl trimming is at least defined to prevent unbounded growth""" +@@ -1120,7 +1123,10 @@ class Replica(DSLdapObject): + self._create_objectclasses.append('extensibleobject') + self._protected = False + self._suffix = None +- self._lint_functions = [self._lint_agmts_status, self._lint_conflicts] ++ ++ @classmethod ++ def lint_uid(cls): ++ return 'replication' + + def _lint_agmts_status(self): + replicas = Replicas(self._instance).list() +diff --git a/src/lib389/lib389/tests/mapped_object_lint_test.py b/src/lib389/lib389/tests/mapped_object_lint_test.py +new file mode 100644 +index 000000000..a4ca0ea3c +--- /dev/null ++++ b/src/lib389/lib389/tests/mapped_object_lint_test.py +@@ -0,0 +1,78 @@ ++from typing import List ++ ++import pytest ++ ++from lib389._mapped_object_lint import ( ++ DSLint, ++ DSLints, ++ DSLintMethodSpec ++) ++ ++ ++def test_dslint(): ++ class DS(DSLint): ++ def lint_uid(self) -> str: ++ return self.param ++ ++ def __init__(self, param): ++ self.param = param ++ self.suffixes = ['suffixA', 'suffixB'] ++ ++ def _lint_nsstate(self, spec: DSLintMethodSpec = None): ++ if spec == List: ++ yield from self.suffixes ++ else: ++ to_lint = [spec] if spec else self._lint_nsstate(spec=List) ++ for tl in to_lint: ++ if tl == 'suffixA': ++ pass ++ elif tl == 'suffixB': ++ yield 'suffixB is bad' ++ else: ++ raise ValueError('There is no such suffix') ++ ++ def _lint_second(self): ++ yield from () ++ ++ def _lint_third(self): ++ yield from ['this is a fail'] ++ ++ class DSs(DSLints): ++ def list(self): ++ for i in [DS("ma"), DS("mb")]: ++ yield i ++ ++ # single ++ inst = DS("a") ++ inst_lints = {'nsstate:suffixA', 'nsstate:suffixB', 'second', 'third'} ++ ++ assert inst.param == "a" ++ ++ assert set(dict(inst.lint_list()).keys()) == inst_lints ++ ++ assert set(dict(inst.lint_list('nsstate')).keys()) \ ++ == {f'nsstate:suffix{s}' for s in "AB"} ++ ++ assert list(inst._lint_nsstate(spec=List)) == ['suffixA', 'suffixB'] ++ assert list(inst.lint()) == ['suffixB is bad', 'this is a fail'] ++ ++ assert list(inst.lint('nsstate')) == ['suffixB is bad'] ++ assert list(inst.lint('nsstate:suffixA')) == [] ++ assert list(inst.lint('nsstate:suffixB')) == ['suffixB is bad'] ++ with pytest.raises(ValueError): ++ list(inst.lint('nonexistent')) ++ ++ # multiple ++ insts = DSs() ++ ++ assert insts.lint_list ++ assert insts.lint ++ ++ assert set(dict(insts.lint_list()).keys()) \ ++ == {f'{m}:{s}' for m in ['ma', 'mb'] for s in inst_lints} ++ assert set(dict(insts.lint_list('*')).keys()) \ ++ == {f'{m}:{s}' for m in ['ma', 'mb'] for s in inst_lints} ++ assert set(dict(insts.lint_list('*:nsstate')).keys()) \ ++ == {f'{m}:nsstate:suffix{s}' for m in ['ma', 'mb'] for s in "AB"} ++ assert set(dict(insts.lint_list('mb:nsstate')).keys()) \ ++ == {f'mb:nsstate:suffix{s}' for s in "AB"} +-- +2.26.2 + diff --git a/SOURCES/0012-Issue-50798-incorrect-bytes-in-format-string-fix-imp.patch b/SOURCES/0012-Issue-50798-incorrect-bytes-in-format-string-fix-imp.patch deleted file mode 100644 index 9551d31..0000000 --- a/SOURCES/0012-Issue-50798-incorrect-bytes-in-format-string-fix-imp.patch +++ /dev/null @@ -1,45 +0,0 @@ -From d9b1b71b87517d12b88464d5475baff4c6cc25ab Mon Sep 17 00:00:00 2001 -From: Mark Reynolds -Date: Mon, 13 Jan 2020 17:17:40 -0500 -Subject: [PATCH] Issue 50798 - incorrect bytes in format string(fix import - issue) - -Description: The previous commit did not import ensure_list_str() from - utils.py - -relates: https://pagure.io/389-ds-base/issue/50798 - -Reviewed by: mreynolds (one line commit rule) ---- - src/lib389/lib389/instance/remove.py | 2 +- - src/lib389/lib389/instance/setup.py | 1 + - 2 files changed, 2 insertions(+), 1 deletion(-) - -diff --git a/src/lib389/lib389/instance/remove.py b/src/lib389/lib389/instance/remove.py -index c9a872eb7..7a69da514 100644 ---- a/src/lib389/lib389/instance/remove.py -+++ b/src/lib389/lib389/instance/remove.py -@@ -11,7 +11,7 @@ import shutil - import subprocess - import logging - from lib389.nss_ssl import NssSsl --from lib389.utils import selinux_label_port, assert_c -+from lib389.utils import selinux_label_port, assert_c, ensure_list_str - - - ######################## WARNING ############################# -diff --git a/src/lib389/lib389/instance/setup.py b/src/lib389/lib389/instance/setup.py -index bb0ff32f5..61ffc32ee 100644 ---- a/src/lib389/lib389/instance/setup.py -+++ b/src/lib389/lib389/instance/setup.py -@@ -33,6 +33,7 @@ from lib389.utils import ( - assert_c, - is_a_dn, - ensure_str, -+ ensure_list_str, - normalizeDN, - socket_check_open, - selinux_label_port, --- -2.21.1 - diff --git a/SOURCES/0012-Issue-50984-Memory-leaks-in-disk-monitoring.patch b/SOURCES/0012-Issue-50984-Memory-leaks-in-disk-monitoring.patch new file mode 100644 index 0000000..3e61905 --- /dev/null +++ b/SOURCES/0012-Issue-50984-Memory-leaks-in-disk-monitoring.patch @@ -0,0 +1,54 @@ +From 2540354b7eb6fa03db7d36a5b755001b0852aa1b Mon Sep 17 00:00:00 2001 +From: Simon Pichugin +Date: Thu, 26 Mar 2020 19:33:47 +0100 +Subject: [PATCH] Issue 50984 - Memory leaks in disk monitoring + +Description: Memory leaks are reported by the disk monitoring test suite. +The direct leak is related to char **dirs array which is not freed at all. +Free the array when we clean up or go to shutdown. +Fix disk_monitoring_test.py::test_below_half_of_the_threshold_not_starting_after_shutdown. +It should accept different exception when the instance is not started. + +https://pagure.io/389-ds-base/issue/50984 + +Reviewed by: firstyear (Thanks!) +--- + ldap/servers/slapd/daemon.c | 2 -- + ldap/servers/slapd/main.c | 1 - + 2 files changed, 3 deletions(-) + +diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c +index a70f40316..542d31037 100644 +--- a/ldap/servers/slapd/daemon.c ++++ b/ldap/servers/slapd/daemon.c +@@ -613,7 +613,6 @@ disk_monitoring_thread(void *nothing __attribute__((unused))) + } + } + slapi_ch_array_free(dirs); +- dirs = NULL; + return; + } + /* +@@ -713,7 +712,6 @@ disk_monitoring_thread(void *nothing __attribute__((unused))) + } + } + slapi_ch_array_free(dirs); +- dirs = NULL; /* now it is not needed but the code may be changed in the future and it'd better be more robust */ + g_set_shutdown(SLAPI_SHUTDOWN_DISKFULL); + return; + } +diff --git a/ldap/servers/slapd/main.c b/ldap/servers/slapd/main.c +index e54b8e1c5..1f8b01959 100644 +--- a/ldap/servers/slapd/main.c ++++ b/ldap/servers/slapd/main.c +@@ -958,7 +958,6 @@ main(int argc, char **argv) + goto cleanup; + } + slapi_ch_array_free(dirs); +- dirs = NULL; + } + /* log the max fd limit as it is typically set in env/systemd */ + slapi_log_err(SLAPI_LOG_INFO, "main", +-- +2.26.2 + diff --git a/SOURCES/0013-Issue-50824-dsctl-remove-fails-with-name-ensure_str-.patch b/SOURCES/0013-Issue-50824-dsctl-remove-fails-with-name-ensure_str-.patch deleted file mode 100644 index 7afbc3d..0000000 --- a/SOURCES/0013-Issue-50824-dsctl-remove-fails-with-name-ensure_str-.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 5f3f69533a2298cc0f2b45e17184c479b0708687 Mon Sep 17 00:00:00 2001 -From: Matus Honek -Date: Thu, 16 Jan 2020 12:21:45 +0100 -Subject: [PATCH] Issue 50824 - dsctl remove fails with "name 'ensure_str' is - not defined" - -Bug Description: -Missing import since commit c39c7bb. - -Fix Description: -Add the import. - -Fixes https://pagure.io/389-ds-base/issue/50824 - -Author: Matus Honek - -Review by: Mark (thanks!) - -(cherry picked from commit 4f9aafca9a9927812da5e37ce71d79d1fd23b25a) ---- - src/lib389/lib389/instance/remove.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/lib389/lib389/instance/remove.py b/src/lib389/lib389/instance/remove.py -index 7a69da514..77f5a45f7 100644 ---- a/src/lib389/lib389/instance/remove.py -+++ b/src/lib389/lib389/instance/remove.py -@@ -11,7 +11,7 @@ import shutil - import subprocess - import logging - from lib389.nss_ssl import NssSsl --from lib389.utils import selinux_label_port, assert_c, ensure_list_str -+from lib389.utils import selinux_label_port, assert_c, ensure_str, ensure_list_str - - - ######################## WARNING ############################# --- -2.21.1 - diff --git a/SOURCES/0013-Issue-50984-Memory-leaks-in-disk-monitoring.patch b/SOURCES/0013-Issue-50984-Memory-leaks-in-disk-monitoring.patch new file mode 100644 index 0000000..d554989 --- /dev/null +++ b/SOURCES/0013-Issue-50984-Memory-leaks-in-disk-monitoring.patch @@ -0,0 +1,52 @@ +From a720e002751815323a295e11e77c56d7ce38314e Mon Sep 17 00:00:00 2001 +From: Simon Pichugin +Date: Fri, 27 Mar 2020 11:35:55 +0100 +Subject: [PATCH] Issue 50984 - Memory leaks in disk monitoring + +Description: Reset dirs pointer every time we free it. +The code may be changed in the future so we should make it +more robust. + +https://pagure.io/389-ds-base/issue/50984 + +Reviewed by: spichugi, tbordaz (one line commit rule) +--- + ldap/servers/slapd/daemon.c | 2 ++ + ldap/servers/slapd/main.c | 1 + + 2 files changed, 3 insertions(+) + +diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c +index 542d31037..a70f40316 100644 +--- a/ldap/servers/slapd/daemon.c ++++ b/ldap/servers/slapd/daemon.c +@@ -613,6 +613,7 @@ disk_monitoring_thread(void *nothing __attribute__((unused))) + } + } + slapi_ch_array_free(dirs); ++ dirs = NULL; + return; + } + /* +@@ -712,6 +713,7 @@ disk_monitoring_thread(void *nothing __attribute__((unused))) + } + } + slapi_ch_array_free(dirs); ++ dirs = NULL; /* now it is not needed but the code may be changed in the future and it'd better be more robust */ + g_set_shutdown(SLAPI_SHUTDOWN_DISKFULL); + return; + } +diff --git a/ldap/servers/slapd/main.c b/ldap/servers/slapd/main.c +index 1f8b01959..e54b8e1c5 100644 +--- a/ldap/servers/slapd/main.c ++++ b/ldap/servers/slapd/main.c +@@ -958,6 +958,7 @@ main(int argc, char **argv) + goto cleanup; + } + slapi_ch_array_free(dirs); ++ dirs = NULL; + } + /* log the max fd limit as it is typically set in env/systemd */ + slapi_log_err(SLAPI_LOG_INFO, "main", +-- +2.26.2 + diff --git a/SOURCES/0014-Issue-50201-nsIndexIDListScanLimit-accepts-any-value.patch b/SOURCES/0014-Issue-50201-nsIndexIDListScanLimit-accepts-any-value.patch new file mode 100644 index 0000000..704cff6 --- /dev/null +++ b/SOURCES/0014-Issue-50201-nsIndexIDListScanLimit-accepts-any-value.patch @@ -0,0 +1,569 @@ +From f60364cd9472edc61e7d327d13dca67eadf0c5b2 Mon Sep 17 00:00:00 2001 +From: Simon Pichugin +Date: Tue, 28 Apr 2020 23:44:20 +0200 +Subject: [PATCH] Issue 50201 - nsIndexIDListScanLimit accepts any value + +Bug Description: Setting of nsIndexIDListScanLimit like +'limit=2 limit=3' are detected and logged in error logs. +But the invalid value is successfully applied in the config entry +and the operation itself is successful. +The impact is limited because the index will be used following +idlistscanlimit rather than invalid definition nsIndexIDListScanLimit. + +Fix Description: Print the errors to the user when he tries to add +or to modify index config entry with malformed values. +Change tests accordingly. + +https://pagure.io/389-ds-base/issue/50201 + +Reviewed by: mreynolds, tbordaz (Thanks!) +--- + .../suites/filter/filterscanlimit_test.py | 87 ++++++++----------- + ldap/servers/slapd/back-ldbm/instance.c | 4 +- + ldap/servers/slapd/back-ldbm/ldbm_attr.c | 33 ++++++- + .../slapd/back-ldbm/ldbm_index_config.c | 59 +++++++++---- + ldap/servers/slapd/back-ldbm/ldif2ldbm.c | 2 +- + .../servers/slapd/back-ldbm/proto-back-ldbm.h | 2 +- + 6 files changed, 114 insertions(+), 73 deletions(-) + +diff --git a/dirsrvtests/tests/suites/filter/filterscanlimit_test.py b/dirsrvtests/tests/suites/filter/filterscanlimit_test.py +index dd9c6ee4e..0198f6533 100644 +--- a/dirsrvtests/tests/suites/filter/filterscanlimit_test.py ++++ b/dirsrvtests/tests/suites/filter/filterscanlimit_test.py +@@ -11,6 +11,7 @@ This script will test different type of Filers. + """ + + import os ++import ldap + import pytest + + from lib389._constants import DEFAULT_SUFFIX, PW_DM +@@ -19,11 +20,10 @@ from lib389.idm.user import UserAccounts + from lib389.idm.organizationalunit import OrganizationalUnits + from lib389.index import Index + from lib389.idm.account import Accounts +-from lib389.idm.group import UniqueGroups, Group ++from lib389.idm.group import UniqueGroups + + pytestmark = pytest.mark.tier1 + +- + GIVEN_NAME = 'cn=givenname,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config' + CN_NAME = 'cn=sn,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config' + UNIQMEMBER = 'cn=uniquemember,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config' +@@ -39,7 +39,6 @@ LIST_OF_USER_ACCOUNTING = [ + "Judy Wallace", + "Marcus Ward", + "Judy McFarland", +- "Anuj Hall", + "Gern Triplett", + "Emanuel Johnson", + "Brad Walker", +@@ -57,7 +56,6 @@ LIST_OF_USER_ACCOUNTING = [ + "Randy Ulrich", + "Richard Francis", + "Morgan White", +- "Anuj Maddox", + "Jody Jensen", + "Mike Carter", + "Gern Tyler", +@@ -77,8 +75,6 @@ LIST_OF_USER_HUMAN = [ + "Robert Daugherty", + "Torrey Mason", + "Brad Talbot", +- "Anuj Jablonski", +- "Harry Miller", + "Jeffrey Campaigne", + "Stephen Triplett", + "John Falena", +@@ -107,8 +103,7 @@ LIST_OF_USER_HUMAN = [ + "Tobias Schmith", + "Jon Goldstein", + "Janet Lutz", +- "Karl Cope", +-] ++ "Karl Cope"] + + LIST_OF_USER_TESTING = [ + "Andy Bergin", +@@ -122,8 +117,7 @@ LIST_OF_USER_TESTING = [ + "Alan White", + "Daniel Ward", + "Lee Stockton", +- "Matthew Vaughan" +-] ++ "Matthew Vaughan"] + + LIST_OF_USER_DEVELOPMENT = [ + "Kelly Winters", +@@ -143,7 +137,6 @@ LIST_OF_USER_DEVELOPMENT = [ + "Timothy Kelly", + "Sue Mason", + "Chris Alexander", +- "Anuj Jensen", + "Martin Talbot", + "Scott Farmer", + "Allison Jensen", +@@ -152,9 +145,7 @@ LIST_OF_USER_DEVELOPMENT = [ + "Dan Langdon", + "Ashley Knutson", + "Jon Bourke", +- "Pete Hunt", +- +-] ++ "Pete Hunt"] + + LIST_OF_USER_PAYROLL = [ + "Ashley Chassin", +@@ -164,12 +155,17 @@ LIST_OF_USER_PAYROLL = [ + "Patricia Shelton", + "Dietrich Swain", + "Allison Hunter", +- "Anne-Louise Barnes" ++ "Anne-Louise Barnes"] + +-] ++LIST_OF_USER_PEOPLE = [ ++ 'Sam Carter', ++ 'Tom Morris', ++ 'Kevin Vaughan', ++ 'Rich Daugherty', ++ 'Harry Miller', ++ 'Sam Schmith'] + + +-@pytest.mark.skip(reason="https://pagure.io/389-ds-base/issue/50201") + def test_invalid_configuration(topo): + """" + Error handling for invalid configuration +@@ -190,10 +186,7 @@ def test_invalid_configuration(topo): + 'limit=0 flags=AND flags=AND', + 'limit=0 type=eq values=foo values=foo', + 'limit=0 type=eq values=foo,foo', +- 'limit=0 type=sub', +- 'limit=0 type=eq values=notvalid', + 'limit', +- 'limit=0 type=eq values=notavaliddn', + 'limit=0 type=pres values=bogus', + 'limit=0 type=eq,sub values=bogus', + 'limit=', +@@ -203,7 +196,8 @@ def test_invalid_configuration(topo): + 'limit=-2', + 'type=eq', + 'limit=0 type=bogus']: +- Index(topo.standalone, GIVEN_NAME).replace('nsIndexIDListScanLimit', i) ++ with pytest.raises(ldap.UNWILLING_TO_PERFORM): ++ Index(topo.standalone, GIVEN_NAME).replace('nsIndexIDListScanLimit', i) + + + def test_idlistscanlimit(topo): +@@ -247,28 +241,24 @@ def test_idlistscanlimit(topo): + (LIST_OF_USER_HUMAN, users_human), + (LIST_OF_USER_TESTING, users_testing), + (LIST_OF_USER_DEVELOPMENT, users_development), +- (LIST_OF_USER_PAYROLL, users_payroll)]: ++ (LIST_OF_USER_PAYROLL, users_payroll), ++ (LIST_OF_USER_PEOPLE, users_people)]: + for demo1 in data[0]: ++ fn = demo1.split()[0] ++ sn = demo1.split()[1] ++ uid = ''.join([fn[:1], sn]).lower() + data[1].create(properties={ +- 'uid': demo1, ++ 'uid': uid, + 'cn': demo1, +- 'sn': demo1.split()[1], ++ 'sn': sn, + 'uidNumber': str(1000), + 'gidNumber': '2000', +- 'homeDirectory': '/home/' + demo1, +- 'givenname': demo1.split()[0], +- 'userpassword': PW_DM ++ 'homeDirectory': f'/home/{uid}', ++ 'givenname': fn, ++ 'userpassword': PW_DM, ++ 'mail': f'{uid}@test.com' + }) + +- users_people.create(properties={ +- 'uid': 'scarter', +- 'cn': 'Sam Carter', +- 'sn': 'Carter', +- 'uidNumber': str(1000), +- 'gidNumber': '2000', +- 'homeDirectory': '/home/' + 'scarter', +- 'mail': 'scarter@anuj.com', +- }) + try: + # Change log levels + errorlog_value = topo.standalone.config.get_attr_val_utf8('nsslapd-errorlog-level') +@@ -297,16 +287,12 @@ def test_idlistscanlimit(topo): + + Index(topo.standalone, UNIQMEMBER).\ + replace('nsIndexIDListScanLimit', +- 'limit=0 type=eq values=uid=kvaughan,ou=People,' +- 'dc=example,dc=com,uid=rdaugherty,ou=People,dc=example,dc=com') ++ 'limit=0 type=eq values=uid=kvaughan\2Cou=People\2Cdc=example\2Cdc=com,' ++ 'uid=rdaugherty\2Cou=People\2Cdc=example\2Cdc=com') + + Index(topo.standalone, OBJECTCLASS).\ + replace('nsIndexIDListScanLimit', 'limit=0 type=eq flags=AND values=inetOrgPerson') + +- Index(topo.standalone, MAIL).\ +- replace('nsIndexIDListScanLimit', +- 'cn=mail,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config') +- + # Search with filter + for i in ['(sn=Lutz)', + '(sn=*ter)', +@@ -321,22 +307,24 @@ def test_idlistscanlimit(topo): + '(&(sn=*)(cn=*))', + '(sn=Hunter)', + '(&(givenname=Richard)(objectclass=organizationalPerson))', +- '(givenname=Anuj)', ++ '(givenname=Morgan)', + '(&(givenname=*)(cn=*))', + '(givenname=*)']: + assert Accounts(topo.standalone, DEFAULT_SUFFIX).filter(f'{i}') + +- # Creating Group +- Group(topo.standalone, 'cn=Accounting Managers,ou=groups,dc=example,dc=com').\ +- add('uniquemember', ++ # Creating Groups and adding members ++ groups = UniqueGroups(topo.standalone, DEFAULT_SUFFIX) ++ accounting_managers = groups.ensure_state(properties={'cn': 'Accounting Managers'}) ++ hr_managers = groups.ensure_state(properties={'cn': 'HR Managers'}) ++ ++ accounting_managers.add('uniquemember', + ['uid=scarter, ou=People, dc=example,dc=com', + 'uid=tmorris, ou=People, dc=example,dc=com', + 'uid=kvaughan, ou=People, dc=example,dc=com', + 'uid=rdaugherty, ou=People, dc=example,dc=com', + 'uid=hmiller, ou=People, dc=example,dc=com']) + +- Group(topo.standalone, 'cn=HR Managers,ou=groups,dc=example,dc=com').\ +- add('uniquemember', ++ hr_managers.add('uniquemember', + ['uid=kvaughan, ou=People, dc=example,dc=com', + 'uid=cschmith, ou=People, dc=example,dc=com']) + +@@ -403,10 +391,9 @@ def test_idlistscanlimit(topo): + '(&(sn=*)(cn=*))', + '(sn=Hunter)', + '(&(givenname=Richard)(objectclass=organizationalPerson))', +- '(givenname=Anuj)', ++ '(givenname=Morgan)', + '(&(givenname=*)(cn=*))', + '(givenname=*)']: +- + assert Accounts(topo.standalone, DEFAULT_SUFFIX).filter(value) + + finally: +diff --git a/ldap/servers/slapd/back-ldbm/instance.c b/ldap/servers/slapd/back-ldbm/instance.c +index 04c28ff39..07655a8ec 100644 +--- a/ldap/servers/slapd/back-ldbm/instance.c ++++ b/ldap/servers/slapd/back-ldbm/instance.c +@@ -231,7 +231,7 @@ ldbm_instance_create_default_indexes(backend *be) + + /* ldbm_instance_config_add_index_entry(inst, 2, argv); */ + e = ldbm_instance_init_config_entry(LDBM_PSEUDO_ATTR_DEFAULT, "none", 0, 0, 0); +- attr_index_config(be, "ldbm index init", 0, e, 1, 0); ++ attr_index_config(be, "ldbm index init", 0, e, 1, 0, NULL); + slapi_entry_free(e); + + if (!entryrdn_get_noancestorid()) { +@@ -240,7 +240,7 @@ ldbm_instance_create_default_indexes(backend *be) + * but we still want to use the attr index file APIs. + */ + e = ldbm_instance_init_config_entry(LDBM_ANCESTORID_STR, "eq", 0, 0, 0); +- attr_index_config(be, "ldbm index init", 0, e, 1, 0); ++ attr_index_config(be, "ldbm index init", 0, e, 1, 0, NULL); + slapi_entry_free(e); + } + +diff --git a/ldap/servers/slapd/back-ldbm/ldbm_attr.c b/ldap/servers/slapd/back-ldbm/ldbm_attr.c +index b9e130d77..f0d418572 100644 +--- a/ldap/servers/slapd/back-ldbm/ldbm_attr.c ++++ b/ldap/servers/slapd/back-ldbm/ldbm_attr.c +@@ -633,6 +633,18 @@ attr_index_idlistsize_config(Slapi_Entry *e, struct attrinfo *ai, char *returnte + return rc; + } + ++/* ++ * Function that process index attributes and modifies attrinfo structure ++ * ++ * Called while adding default indexes, during db2index execution and ++ * when we add/modify/delete index config entry ++ * ++ * If char *err_buf is not NULL, it will additionally print all error messages to STDERR ++ * It is used when we add/modify/delete index config entry, so the user would have a better verbose ++ * ++ * returns -1, 1 on a failure ++ * 0 on success ++ */ + int + attr_index_config( + backend *be, +@@ -640,7 +652,8 @@ attr_index_config( + int lineno, + Slapi_Entry *e, + int init __attribute__((unused)), +- int indextype_none) ++ int indextype_none, ++ char *err_buf) + { + ldbm_instance *inst = (ldbm_instance *)be->be_instance_info; + int j = 0; +@@ -662,6 +675,7 @@ attr_index_config( + slapi_attr_first_value(attr, &sval); + attrValue = slapi_value_get_berval(sval); + } else { ++ slapi_create_errormsg(err_buf, SLAPI_DSE_RETURNTEXT_SIZE, "Error: missing indexing arguments\n"); + slapi_log_err(SLAPI_LOG_ERR, "attr_index_config", "Missing indexing arguments\n"); + return -1; + } +@@ -705,6 +719,10 @@ attr_index_config( + } + a->ai_indexmask = INDEX_OFFLINE; /* note that the index isn't available */ + } else { ++ slapi_create_errormsg(err_buf, SLAPI_DSE_RETURNTEXT_SIZE, ++ "Error: %s: line %d: unknown index type \"%s\" (ignored) in entry (%s), " ++ "valid index types are \"pres\", \"eq\", \"approx\", or \"sub\"\n", ++ fname, lineno, attrValue->bv_val, slapi_entry_get_dn(e)); + slapi_log_err(SLAPI_LOG_ERR, "attr_index_config", + "%s: line %d: unknown index type \"%s\" (ignored) in entry (%s), " + "valid index types are \"pres\", \"eq\", \"approx\", or \"sub\"\n", +@@ -715,6 +733,7 @@ attr_index_config( + } + if (hasIndexType == 0) { + /* indexType missing, error out */ ++ slapi_create_errormsg(err_buf, SLAPI_DSE_RETURNTEXT_SIZE, "Error: missing index type\n"); + slapi_log_err(SLAPI_LOG_ERR, "attr_index_config", "Missing index type\n"); + attrinfo_delete(&a); + return -1; +@@ -873,16 +892,26 @@ attr_index_config( + slapi_ch_free((void **)&official_rules); + } + } +- + if ((return_value = attr_index_idlistsize_config(e, a, myreturntext))) { ++ slapi_create_errormsg(err_buf, SLAPI_DSE_RETURNTEXT_SIZE, ++ "Error: %s: Failed to parse idscanlimit info: %d:%s\n", ++ fname, return_value, myreturntext); + slapi_log_err(SLAPI_LOG_ERR, "attr_index_config", "%s: Failed to parse idscanlimit info: %d:%s\n", + fname, return_value, myreturntext); ++ if (err_buf != NULL) { ++ /* we are inside of a callback, we shouldn't allow malformed attributes in index entries */ ++ attrinfo_delete(&a); ++ return return_value; ++ } + } + + /* initialize the IDL code's private data */ + return_value = idl_init_private(be, a); + if (0 != return_value) { + /* fatal error, exit */ ++ slapi_create_errormsg(err_buf, SLAPI_DSE_RETURNTEXT_SIZE, ++ "Error: %s: line %d:Fatal Error: Failed to initialize attribute structure\n", ++ fname, lineno); + slapi_log_err(SLAPI_LOG_CRIT, "attr_index_config", + "%s: line %d:Fatal Error: Failed to initialize attribute structure\n", + fname, lineno); +diff --git a/ldap/servers/slapd/back-ldbm/ldbm_index_config.c b/ldap/servers/slapd/back-ldbm/ldbm_index_config.c +index 45f0034f0..720f93036 100644 +--- a/ldap/servers/slapd/back-ldbm/ldbm_index_config.c ++++ b/ldap/servers/slapd/back-ldbm/ldbm_index_config.c +@@ -25,26 +25,34 @@ int ldbm_instance_index_config_delete_callback(Slapi_PBlock *pb, Slapi_Entry *en + #define INDEXTYPE_NONE 1 + + static int +-ldbm_index_parse_entry(ldbm_instance *inst, Slapi_Entry *e, const char *trace_string, char **index_name) ++ldbm_index_parse_entry(ldbm_instance *inst, Slapi_Entry *e, const char *trace_string, char **index_name, char *err_buf) + { + Slapi_Attr *attr; + const struct berval *attrValue; + Slapi_Value *sval; ++ char *edn = slapi_entry_get_dn(e); + + /* Get the name of the attribute to index which will be the value + * of the cn attribute. */ + if (slapi_entry_attr_find(e, "cn", &attr) != 0) { +- slapi_log_err(SLAPI_LOG_ERR, "ldbm_index_parse_entry", "Malformed index entry %s\n", +- slapi_entry_get_dn(e)); ++ slapi_create_errormsg(err_buf, SLAPI_DSE_RETURNTEXT_SIZE, ++ "Error: malformed index entry %s\n", ++ edn); ++ slapi_log_err(SLAPI_LOG_ERR, ++ "ldbm_index_parse_entry", "Malformed index entry %s\n", ++ edn); + return LDAP_OPERATIONS_ERROR; + } + + slapi_attr_first_value(attr, &sval); + attrValue = slapi_value_get_berval(sval); + if (NULL == attrValue->bv_val || 0 == attrValue->bv_len) { ++ slapi_create_errormsg(err_buf, SLAPI_DSE_RETURNTEXT_SIZE, ++ "Error: malformed index entry %s -- empty index name\n", ++ edn); + slapi_log_err(SLAPI_LOG_ERR, + "ldbm_index_parse_entry", "Malformed index entry %s -- empty index name\n", +- slapi_entry_get_dn(e)); ++ edn); + return LDAP_OPERATIONS_ERROR; + } + +@@ -59,16 +67,19 @@ ldbm_index_parse_entry(ldbm_instance *inst, Slapi_Entry *e, const char *trace_st + attrValue = slapi_value_get_berval(sval); + if (NULL == attrValue->bv_val || attrValue->bv_len == 0) { + /* missing the index type, error out */ +- slapi_log_err(SLAPI_LOG_ERR, +- "ldbm_index_parse_entry", "Malformed index entry %s -- empty nsIndexType\n", +- slapi_entry_get_dn(e)); ++ slapi_create_errormsg(err_buf, SLAPI_DSE_RETURNTEXT_SIZE, ++ "Error: malformed index entry %s -- empty nsIndexType\n", ++ edn); ++ slapi_log_err(SLAPI_LOG_ERR, "ldbm_index_parse_entry", ++ "Malformed index entry %s -- empty nsIndexType\n", ++ edn); + slapi_ch_free_string(index_name); + return LDAP_OPERATIONS_ERROR; + } + } + + /* ok the entry is good to process, pass it to attr_index_config */ +- if (attr_index_config(inst->inst_be, (char *)trace_string, 0, e, 0, 0)) { ++ if (attr_index_config(inst->inst_be, (char *)trace_string, 0, e, 0, 0, err_buf)) { + slapi_ch_free_string(index_name); + return LDAP_OPERATIONS_ERROR; + } +@@ -92,7 +103,7 @@ ldbm_index_init_entry_callback(Slapi_PBlock *pb __attribute__((unused)), + ldbm_instance *inst = (ldbm_instance *)arg; + + returntext[0] = '\0'; +- *returncode = ldbm_index_parse_entry(inst, e, "from ldbm instance init", NULL); ++ *returncode = ldbm_index_parse_entry(inst, e, "from ldbm instance init", NULL, NULL); + if (*returncode == LDAP_SUCCESS) { + return SLAPI_DSE_CALLBACK_OK; + } else { +@@ -117,7 +128,7 @@ ldbm_instance_index_config_add_callback(Slapi_PBlock *pb __attribute__((unused)) + char *index_name = NULL; + + returntext[0] = '\0'; +- *returncode = ldbm_index_parse_entry(inst, e, "from DSE add", &index_name); ++ *returncode = ldbm_index_parse_entry(inst, e, "from DSE add", &index_name, returntext); + if (*returncode == LDAP_SUCCESS) { + struct attrinfo *ai = NULL; + /* if the index is a "system" index, we assume it's being added by +@@ -179,7 +190,7 @@ ldbm_instance_index_config_delete_callback(Slapi_PBlock *pb, + slapi_attr_first_value(attr, &sval); + attrValue = slapi_value_get_berval(sval); + +- attr_index_config(inst->inst_be, "From DSE delete", 0, e, 0, INDEXTYPE_NONE); ++ attr_index_config(inst->inst_be, "From DSE delete", 0, e, 0, INDEXTYPE_NONE, returntext); + + ainfo_get(inst->inst_be, attrValue->bv_val, &ainfo); + if (NULL == ainfo) { +@@ -213,14 +224,19 @@ ldbm_instance_index_config_modify_callback(Slapi_PBlock *pb __attribute__((unuse + Slapi_Value *sval; + const struct berval *attrValue; + struct attrinfo *ainfo = NULL; ++ char *edn = slapi_entry_get_dn(e); ++ char *edn_after = slapi_entry_get_dn(entryAfter); + + returntext[0] = '\0'; + *returncode = LDAP_SUCCESS; + + if (slapi_entry_attr_find(entryAfter, "cn", &attr) != 0) { ++ slapi_create_errormsg(returntext, SLAPI_DSE_RETURNTEXT_SIZE, ++ "Error: malformed index entry %s - missing cn attribute\n", ++ edn_after); + slapi_log_err(SLAPI_LOG_ERR, + "ldbm_instance_index_config_modify_callback", "Malformed index entry %s - missing cn attribute\n", +- slapi_entry_get_dn(entryAfter)); ++ edn_after); + *returncode = LDAP_OBJECT_CLASS_VIOLATION; + return SLAPI_DSE_CALLBACK_ERROR; + } +@@ -228,31 +244,40 @@ ldbm_instance_index_config_modify_callback(Slapi_PBlock *pb __attribute__((unuse + attrValue = slapi_value_get_berval(sval); + + if (NULL == attrValue->bv_val || 0 == attrValue->bv_len) { ++ slapi_create_errormsg(returntext, SLAPI_DSE_RETURNTEXT_SIZE, ++ "Error: malformed index entry %s - missing index name\n", ++ edn); + slapi_log_err(SLAPI_LOG_ERR, + "ldbm_instance_index_config_modify_callback", "Malformed index entry %s, missing index name\n", +- slapi_entry_get_dn(e)); ++ edn); + *returncode = LDAP_UNWILLING_TO_PERFORM; + return SLAPI_DSE_CALLBACK_ERROR; + } + + ainfo_get(inst->inst_be, attrValue->bv_val, &ainfo); + if (NULL == ainfo) { ++ slapi_create_errormsg(returntext, SLAPI_DSE_RETURNTEXT_SIZE, ++ "Error: malformed index entry %s - missing cn attribute info\n", ++ edn); + slapi_log_err(SLAPI_LOG_ERR, + "ldbm_instance_index_config_modify_callback", "Malformed index entry %s - missing cn attribute info\n", +- slapi_entry_get_dn(e)); ++ edn); + *returncode = LDAP_UNWILLING_TO_PERFORM; + return SLAPI_DSE_CALLBACK_ERROR; + } + + if (slapi_entry_attr_find(entryAfter, "nsIndexType", &attr) != 0) { ++ slapi_create_errormsg(returntext, SLAPI_DSE_RETURNTEXT_SIZE, ++ "Error: malformed index entry %s - missing nsIndexType attribute\n", ++ edn_after); + slapi_log_err(SLAPI_LOG_ERR, + "ldbm_instance_index_config_modify_callback", "Malformed index entry %s - missing nsIndexType attribute\n", +- slapi_entry_get_dn(entryAfter)); ++ edn_after); + *returncode = LDAP_OBJECT_CLASS_VIOLATION; + return SLAPI_DSE_CALLBACK_ERROR; + } + +- if (attr_index_config(inst->inst_be, "from DSE modify", 0, entryAfter, 0, 0)) { ++ if (attr_index_config(inst->inst_be, "from DSE modify", 0, entryAfter, 0, 0, returntext)) { + *returncode = LDAP_UNWILLING_TO_PERFORM; + return SLAPI_DSE_CALLBACK_ERROR; + } +@@ -364,7 +389,7 @@ ldbm_instance_index_config_enable_index(ldbm_instance *inst, Slapi_Entry *e) + ainfo_get(inst->inst_be, index_name, &ai); + } + if (!ai) { +- rc = ldbm_index_parse_entry(inst, e, "from DSE add", &index_name); ++ rc = ldbm_index_parse_entry(inst, e, "from DSE add", &index_name, NULL); + } + if (rc == LDAP_SUCCESS) { + /* Assume the caller knows if it is OK to go online immediately */ +diff --git a/ldap/servers/slapd/back-ldbm/ldif2ldbm.c b/ldap/servers/slapd/back-ldbm/ldif2ldbm.c +index 9d82c8228..f2ef5ecd4 100644 +--- a/ldap/servers/slapd/back-ldbm/ldif2ldbm.c ++++ b/ldap/servers/slapd/back-ldbm/ldif2ldbm.c +@@ -291,7 +291,7 @@ db2index_add_indexed_attr(backend *be, char *attrString) + } + } + +- attr_index_config(be, "from db2index()", 0, e, 0, 0); ++ attr_index_config(be, "from db2index()", 0, e, 0, 0, NULL); + slapi_entry_free(e); + + return (0); +diff --git a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h +index 9a86c752b..a07acee5e 100644 +--- a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h ++++ b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h +@@ -24,7 +24,7 @@ void attrinfo_delete(struct attrinfo **pp); + void ainfo_get(backend *be, char *type, struct attrinfo **at); + void attr_masks(backend *be, char *type, int *indexmask, int *syntaxmask); + void attr_masks_ex(backend *be, char *type, int *indexmask, int *syntaxmask, struct attrinfo **at); +-int attr_index_config(backend *be, char *fname, int lineno, Slapi_Entry *e, int init, int none); ++int attr_index_config(backend *be, char *fname, int lineno, Slapi_Entry *e, int init, int none, char *err_buf); + int db2index_add_indexed_attr(backend *be, char *attrString); + int ldbm_compute_init(void); + void attrinfo_deletetree(ldbm_instance *inst); +-- +2.26.2 + diff --git a/SOURCES/0014-Issue-50818-dsconf-pwdpolicy-get-error.patch b/SOURCES/0014-Issue-50818-dsconf-pwdpolicy-get-error.patch deleted file mode 100644 index 3ae0e71..0000000 --- a/SOURCES/0014-Issue-50818-dsconf-pwdpolicy-get-error.patch +++ /dev/null @@ -1,49 +0,0 @@ -From f05d6e7bfc4e829118e53f69f247d345a90e7796 Mon Sep 17 00:00:00 2001 -From: Mark Reynolds -Date: Mon, 13 Jan 2020 19:17:04 -0500 -Subject: [PATCH] Issue 50818 - dsconf pwdpolicy get error - -Description: When trying to retrieve a global or local policy we now see: - - policyError: 'PwPolicyManager' object has no attribute 'get_attr_list' - - Someone removed the function get_attr_list() along the way. - Added the same logic back, and improved it to only report attributes - that are set. - -relates: https://pagure.io/389-ds-base/issue/50818 - -Reviewed by: spichugi(Thanks!) ---- - src/lib389/lib389/cli_conf/pwpolicy.py | 9 +++++---- - 1 file changed, 5 insertions(+), 4 deletions(-) - -diff --git a/src/lib389/lib389/cli_conf/pwpolicy.py b/src/lib389/lib389/cli_conf/pwpolicy.py -index f911997bf..67bfd8767 100644 ---- a/src/lib389/lib389/cli_conf/pwpolicy.py -+++ b/src/lib389/lib389/cli_conf/pwpolicy.py -@@ -35,16 +35,17 @@ def _get_policy_type(inst, dn=None): - def _get_pw_policy(inst, targetdn, log, use_json=None): - pwp_manager = PwPolicyManager(inst) - policy_type = _get_policy_type(inst, targetdn) -- attr_list = pwp_manager.get_attr_list() -+ attr_list = list(pwp_manager.arg_to_attr.values()) - if "global" in policy_type.lower(): - targetdn = 'cn=config' - attr_list.extend(['passwordIsGlobalPolicy', 'nsslapd-pwpolicy_local']) -- attrs = inst.config.get_attrs_vals_utf8(attr_list) -+ 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: - policy = pwp_manager.get_pwpolicy_entry(targetdn) - targetdn = policy.dn -- attrs = policy.get_attrs_vals_utf8(attr_list) -- -+ all_attrs = policy.get_attrs_vals_utf8(attr_list) -+ attrs = {k: v for k, v in all_attrs.items() if len(v) > 0} - if use_json: - print(json.dumps({"type": "entry", "pwp_type": policy_type, "dn": ensure_str(targetdn), "attrs": attrs})) - else: --- -2.21.1 - diff --git a/SOURCES/0015-Issue-51157-Reindex-task-may-create-abandoned-index-.patch b/SOURCES/0015-Issue-51157-Reindex-task-may-create-abandoned-index-.patch new file mode 100644 index 0000000..8da8d8f --- /dev/null +++ b/SOURCES/0015-Issue-51157-Reindex-task-may-create-abandoned-index-.patch @@ -0,0 +1,213 @@ +From 3b3faee01e645577ad77ff4f38429a9e0806231b Mon Sep 17 00:00:00 2001 +From: Simon Pichugin +Date: Tue, 16 Jun 2020 20:35:05 +0200 +Subject: [PATCH] Issue 51157 - Reindex task may create abandoned index file + +Bug Description: Recreating an index for the same attribute but changing +the case of for example 1 letter, results in abandoned indexfile. + +Fix Decsription: Add a test case to a newly created 'indexes' test suite. +When we remove the index config from the backend, - remove the attribute +info from LDBM instance attributes. + +https://pagure.io/389-ds-base/issue/51157 + +Reviewed by: firstyear, mreynolds (Thanks!) +--- + dirsrvtests/tests/suites/indexes/__init__.py | 3 + + .../tests/suites/indexes/regression_test.py | 125 ++++++++++++++++++ + ldap/servers/slapd/back-ldbm/ldbm_attr.c | 7 + + .../slapd/back-ldbm/ldbm_index_config.c | 3 + + .../servers/slapd/back-ldbm/proto-back-ldbm.h | 1 + + 5 files changed, 139 insertions(+) + create mode 100644 dirsrvtests/tests/suites/indexes/__init__.py + create mode 100644 dirsrvtests/tests/suites/indexes/regression_test.py + +diff --git a/dirsrvtests/tests/suites/indexes/__init__.py b/dirsrvtests/tests/suites/indexes/__init__.py +new file mode 100644 +index 000000000..04441667e +--- /dev/null ++++ b/dirsrvtests/tests/suites/indexes/__init__.py +@@ -0,0 +1,3 @@ ++""" ++ :Requirement: 389-ds-base: Indexes ++""" +diff --git a/dirsrvtests/tests/suites/indexes/regression_test.py b/dirsrvtests/tests/suites/indexes/regression_test.py +new file mode 100644 +index 000000000..1a71f16e9 +--- /dev/null ++++ b/dirsrvtests/tests/suites/indexes/regression_test.py +@@ -0,0 +1,125 @@ ++# --- BEGIN COPYRIGHT BLOCK --- ++# Copyright (C) 2020 Red Hat, Inc. ++# All rights reserved. ++# ++# License: GPL (version 3 or any later version). ++# See LICENSE for details. ++# --- END COPYRIGHT BLOCK --- ++# ++import time ++import os ++import pytest ++import ldap ++from lib389._constants import DEFAULT_BENAME, DEFAULT_SUFFIX ++from lib389.index import Indexes ++from lib389.backend import Backends ++from lib389.idm.user import UserAccounts ++from lib389.topologies import topology_st as topo ++ ++pytestmark = pytest.mark.tier1 ++ ++ ++def test_reindex_task_creates_abandoned_index_file(topo): ++ """ ++ Recreating an index for the same attribute but changing ++ the case of for example 1 letter, results in abandoned indexfile ++ ++ :id: 07ae5274-481a-4fa8-8074-e0de50d89ac6 ++ :setup: Standalone instance ++ :steps: ++ 1. Create a user object with additional attributes: ++ objectClass: mozillaabpersonalpha ++ mozillaCustom1: xyz ++ 2. Add an index entry mozillacustom1 ++ 3. Reindex the backend ++ 4. Check the content of the index (after it has been flushed to disk) mozillacustom1.db ++ 5. Remove the index ++ 6. Notice the mozillacustom1.db is removed ++ 7. Recreate the index but now use the exact case as mentioned in the schema ++ 8. Reindex the backend ++ 9. Check the content of the index (after it has been flushed to disk) mozillaCustom1.db ++ 10. Check that an ldapsearch does not return a result (mozillacustom1=xyz) ++ 11. Check that an ldapsearch returns the results (mozillaCustom1=xyz) ++ 12. Restart the instance ++ 13. Notice that an ldapsearch does not return a result(mozillacustom1=xyz) ++ 15. Check that an ldapsearch does not return a result (mozillacustom1=xyz) ++ 16. Check that an ldapsearch returns the results (mozillaCustom1=xyz) ++ 17. Reindex the backend ++ 18. Notice the second indexfile for this attribute ++ 19. Check the content of the index (after it has been flushed to disk) no mozillacustom1.db ++ 20. Check the content of the index (after it has been flushed to disk) mozillaCustom1.db ++ :expectedresults: ++ 1. Should Success. ++ 2. Should Success. ++ 3. Should Success. ++ 4. Should Success. ++ 5. Should Success. ++ 6. Should Success. ++ 7. Should Success. ++ 8. Should Success. ++ 9. Should Success. ++ 10. Should Success. ++ 11. Should Success. ++ 12. Should Success. ++ 13. Should Success. ++ 14. Should Success. ++ 15. Should Success. ++ 16. Should Success. ++ 17. Should Success. ++ 18. Should Success. ++ 19. Should Success. ++ 20. Should Success. ++ """ ++ ++ inst = topo.standalone ++ attr_name = "mozillaCustom1" ++ attr_value = "xyz" ++ ++ users = UserAccounts(inst, DEFAULT_SUFFIX) ++ user = users.create_test_user() ++ user.add("objectClass", "mozillaabpersonalpha") ++ user.add(attr_name, attr_value) ++ ++ backends = Backends(inst) ++ backend = backends.get(DEFAULT_BENAME) ++ indexes = backend.get_indexes() ++ index = indexes.create(properties={ ++ 'cn': attr_name.lower(), ++ 'nsSystemIndex': 'false', ++ 'nsIndexType': ['eq', 'pres'] ++ }) ++ ++ backend.reindex() ++ time.sleep(3) ++ assert os.path.exists(f"{inst.ds_paths.db_home_dir}/{DEFAULT_BENAME}/{attr_name.lower()}.db") ++ index.delete() ++ assert not os.path.exists(f"{inst.ds_paths.db_home_dir}/{DEFAULT_BENAME}/{attr_name.lower()}.db") ++ ++ index = indexes.create(properties={ ++ 'cn': attr_name, ++ 'nsSystemIndex': 'false', ++ 'nsIndexType': ['eq', 'pres'] ++ }) ++ ++ backend.reindex() ++ time.sleep(3) ++ assert not os.path.exists(f"{inst.ds_paths.db_home_dir}/{DEFAULT_BENAME}/{attr_name.lower()}.db") ++ assert os.path.exists(f"{inst.ds_paths.db_home_dir}/{DEFAULT_BENAME}/{attr_name}.db") ++ ++ entries = inst.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, f"{attr_name}={attr_value}") ++ assert len(entries) > 0 ++ inst.restart() ++ entries = inst.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, f"{attr_name}={attr_value}") ++ assert len(entries) > 0 ++ ++ backend.reindex() ++ time.sleep(3) ++ assert not os.path.exists(f"{inst.ds_paths.db_home_dir}/{DEFAULT_BENAME}/{attr_name.lower()}.db") ++ assert os.path.exists(f"{inst.ds_paths.db_home_dir}/{DEFAULT_BENAME}/{attr_name}.db") ++ ++ ++if __name__ == "__main__": ++ # Run isolated ++ # -s for DEBUG mode ++ CURRENT_FILE = os.path.realpath(__file__) ++ pytest.main("-s %s" % CURRENT_FILE) +diff --git a/ldap/servers/slapd/back-ldbm/ldbm_attr.c b/ldap/servers/slapd/back-ldbm/ldbm_attr.c +index f0d418572..688c4f137 100644 +--- a/ldap/servers/slapd/back-ldbm/ldbm_attr.c ++++ b/ldap/servers/slapd/back-ldbm/ldbm_attr.c +@@ -98,6 +98,13 @@ ainfo_cmp( + return (strcasecmp(a->ai_type, b->ai_type)); + } + ++void ++attrinfo_delete_from_tree(backend *be, struct attrinfo *ai) ++{ ++ ldbm_instance *inst = (ldbm_instance *)be->be_instance_info; ++ avl_delete(&inst->inst_attrs, ai, ainfo_cmp); ++} ++ + /* + * Called when a duplicate "index" line is encountered. + * +diff --git a/ldap/servers/slapd/back-ldbm/ldbm_index_config.c b/ldap/servers/slapd/back-ldbm/ldbm_index_config.c +index 720f93036..9722d0ce7 100644 +--- a/ldap/servers/slapd/back-ldbm/ldbm_index_config.c ++++ b/ldap/servers/slapd/back-ldbm/ldbm_index_config.c +@@ -201,7 +201,10 @@ ldbm_instance_index_config_delete_callback(Slapi_PBlock *pb, + *returncode = LDAP_UNWILLING_TO_PERFORM; + rc = SLAPI_DSE_CALLBACK_ERROR; + } ++ attrinfo_delete_from_tree(inst->inst_be, ainfo); + } ++ /* Free attrinfo structure */ ++ attrinfo_delete(&ainfo); + bail: + return rc; + } +diff --git a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h +index a07acee5e..4d2524fd9 100644 +--- a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h ++++ b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h +@@ -21,6 +21,7 @@ + */ + struct attrinfo *attrinfo_new(void); + void attrinfo_delete(struct attrinfo **pp); ++void attrinfo_delete_from_tree(backend *be, struct attrinfo *ai); + void ainfo_get(backend *be, char *type, struct attrinfo **at); + void attr_masks(backend *be, char *type, int *indexmask, int *syntaxmask); + void attr_masks_ex(backend *be, char *type, int *indexmask, int *syntaxmask, struct attrinfo **at); +-- +2.26.2 + diff --git a/SOURCES/0015-Ticket-50709-cont-Several-memory-leaks-reported-by-V.patch b/SOURCES/0015-Ticket-50709-cont-Several-memory-leaks-reported-by-V.patch deleted file mode 100644 index f14ed79..0000000 --- a/SOURCES/0015-Ticket-50709-cont-Several-memory-leaks-reported-by-V.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0e216aef4bdf62c1053e827b8d4657e88fda89cf Mon Sep 17 00:00:00 2001 -From: Thierry Bordaz -Date: Mon, 20 Jan 2020 10:41:08 +0100 -Subject: [PATCH] Ticket 50709 - (cont) Several memory leaks reported by - Valgrind for 389-ds 1.3.9.1-10 - -Description of the problem: - - Original fix was incorrect as it set again in pblock (SLAPI_CONN_CLIENTNETADDR_ACLIP) - the same structure. As old structure is freed during the slapi_pblock_set, - pblock refers to a freed structure. - Later an other threads using the same aclpb contain will use it after free - (see https://pagure.io/389-ds-base/issue/50709#comment-621129) - -Description of the fix: - Only sets in pblock a newly allocated structure - -https://pagure.io/389-ds-base/issue/50709 - -Reviewed by: Mark Reynolds (Thanks !) ---- - ldap/servers/plugins/acl/acllas.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/ldap/servers/plugins/acl/acllas.c b/ldap/servers/plugins/acl/acllas.c -index dd41d41bd..a5602e198 100644 ---- a/ldap/servers/plugins/acl/acllas.c -+++ b/ldap/servers/plugins/acl/acllas.c -@@ -305,7 +305,10 @@ DS_LASIpGetter(NSErr_t *errp, PList_t subject, PList_t resource, PList_t auth_in - slapi_log_err(SLAPI_LOG_ACL, plugin_name, "DS_LASIpGetter - " - "Returning client ip address 'unknown'\n"); - } -- slapi_pblock_set(aclpb->aclpb_pblock, SLAPI_CONN_CLIENTNETADDR_ACLIP, client_praddr); -+ if (client_praddr != pb_client_praddr) { -+ /* Set it in pblock only if it is newly allocated */ -+ slapi_pblock_set(aclpb->aclpb_pblock, SLAPI_CONN_CLIENTNETADDR_ACLIP, client_praddr); -+ } - return LAS_EVAL_TRUE; - } - --- -2.21.1 - diff --git a/SOURCES/0016-Issue-50829-Disk-monitoring-rotated-log-cleanup-caus.patch b/SOURCES/0016-Issue-50829-Disk-monitoring-rotated-log-cleanup-caus.patch deleted file mode 100644 index 32df847..0000000 --- a/SOURCES/0016-Issue-50829-Disk-monitoring-rotated-log-cleanup-caus.patch +++ /dev/null @@ -1,39 +0,0 @@ -From aa65a78d49eb7c5ab1e35cd1ab2aa9c2bc6a209b Mon Sep 17 00:00:00 2001 -From: Mark Reynolds -Date: Fri, 17 Jan 2020 15:42:00 -0500 -Subject: [PATCH] Issue 50829 - Disk monitoring rotated log cleanup causes - heap-use-after-free - -Description: When Disk Monitoring finds that disk space is too low it starts - freeing up disk space by removing rotated logs. However the log - list struct was not properly reset after freeing all the files - in the list. This is what allowed the heap-use-after-free to - occur. - -relates: https://pagure.io/389-ds-base/issue/50829 - -Reviewed by: firstyear(Thanks!) ---- - ldap/servers/slapd/log.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/ldap/servers/slapd/log.c b/ldap/servers/slapd/log.c -index bfcf57475..b16e56b21 100644 ---- a/ldap/servers/slapd/log.c -+++ b/ldap/servers/slapd/log.c -@@ -3243,6 +3243,12 @@ log__delete_rotated_logs() - logp = logp->l_next; - slapi_ch_free((void **)&prev_log); - } -+ -+ /* reset the log struct */ -+ loginfo.log_access_logchain = NULL; -+ loginfo.log_audit_logchain = NULL; -+ loginfo.log_auditfail_logchain = NULL; -+ loginfo.log_error_logchain = NULL; - } - - #define ERRORSLOG 1 --- -2.21.1 - diff --git a/SOURCES/0016-Issue-51165-add-new-access-log-keywords-for-wtime-an.patch b/SOURCES/0016-Issue-51165-add-new-access-log-keywords-for-wtime-an.patch new file mode 100644 index 0000000..10c002c --- /dev/null +++ b/SOURCES/0016-Issue-51165-add-new-access-log-keywords-for-wtime-an.patch @@ -0,0 +1,668 @@ +From 282edde7950ceb2515d74fdbcc0a188131769d74 Mon Sep 17 00:00:00 2001 +From: Mark Reynolds +Date: Tue, 23 Jun 2020 16:38:55 -0400 +Subject: [PATCH] Issue 51165 - add new access log keywords for wtime and + optime + +Description: In addition to the "etime" stat in the access we can also + add the time the operation spent in the work queue, and + how long the actual operation took. We now have "wtime" + and "optime" to track these stats in the access log. + + Also updated logconf for notes=F (related to a different + ticket), and stats for wtime and optime. + +relates: https://pagure.io/389-ds-base/issue/51165 + +Reviewed by: ? +--- + ldap/admin/src/logconv.pl | 187 +++++++++++++++++++++++++++--- + ldap/servers/slapd/add.c | 3 + + ldap/servers/slapd/bind.c | 4 + + ldap/servers/slapd/delete.c | 3 + + ldap/servers/slapd/modify.c | 3 + + ldap/servers/slapd/modrdn.c | 3 + + ldap/servers/slapd/operation.c | 24 ++++ + ldap/servers/slapd/opshared.c | 3 + + ldap/servers/slapd/result.c | 49 ++++---- + ldap/servers/slapd/slap.h | 13 ++- + ldap/servers/slapd/slapi-plugin.h | 26 ++++- + 11 files changed, 269 insertions(+), 49 deletions(-) + +diff --git a/ldap/admin/src/logconv.pl b/ldap/admin/src/logconv.pl +index f4808a101..1ed44a888 100755 +--- a/ldap/admin/src/logconv.pl ++++ b/ldap/admin/src/logconv.pl +@@ -3,7 +3,7 @@ + # + # BEGIN COPYRIGHT BLOCK + # Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. +-# Copyright (C) 2013 Red Hat, Inc. ++# Copyright (C) 2020 Red Hat, Inc. + # All rights reserved. + # + # License: GPL (version 3 or any later version). +@@ -55,7 +55,7 @@ my $reportStats = ""; + my $dataLocation = "/tmp"; + my $startTLSoid = "1.3.6.1.4.1.1466.20037"; + my @statnames=qw(last last_str results srch add mod modrdn moddn cmp del abandon +- conns sslconns bind anonbind unbind notesA notesU etime); ++ conns sslconns bind anonbind unbind notesA notesU notesF etime); + my $s_stats; + my $m_stats; + my $verb = "no"; +@@ -211,6 +211,7 @@ my $sslClientBindCount = 0; + my $sslClientFailedCount = 0; + my $objectclassTopCount= 0; + my $pagedSearchCount = 0; ++my $invalidFilterCount = 0; + my $bindCount = 0; + my $filterCount = 0; + my $baseCount = 0; +@@ -258,7 +259,7 @@ map {$conn{$_} = $_} @conncodes; + # hash db-backed hashes + my @hashnames = qw(attr rc src rsrc excount conn_hash ip_hash conncount nentries + filter base ds6xbadpwd saslmech saslconnop bindlist etime oid +- start_time_of_connection end_time_of_connection ++ start_time_of_connection end_time_of_connection notesf_conn_op + notesa_conn_op notesu_conn_op etime_conn_op nentries_conn_op + optype_conn_op time_conn_op srch_conn_op del_conn_op mod_conn_op + mdn_conn_op cmp_conn_op bind_conn_op unbind_conn_op ext_conn_op +@@ -926,7 +927,7 @@ if ($verb eq "yes" || $usage =~ /u/ || $usage =~ /U/){ + } + while($op > 0){ + # The bind op is not the same as the search op that triggered the notes=A. +- # We have adjust the key by decrementing the op count until we find the last bind op. ++ # We have to adjust the key by decrementing the op count until we find the last bind op. + $op--; + $binddn_key = "$srvRstCnt,$conn,$op"; + if (exists($bind_conn_op->{$binddn_key}) && defined($bind_conn_op->{$binddn_key})) { +@@ -1049,9 +1050,60 @@ if ($verb eq "yes" || $usage =~ /u/ || $usage =~ /U/){ + } + } + } +-} # end of unindexed search report ++ print "\n"; ++} ++ ++print "Invalid Attribute Filters: $invalidFilterCount\n"; ++if ($invalidFilterCount > 0 && $verb eq "yes"){ ++ my $conn_hash = $hashes->{conn_hash}; ++ my $notesf_conn_op = $hashes->{notesf_conn_op}; ++ my $time_conn_op = $hashes->{time_conn_op}; ++ my $etime_conn_op = $hashes->{etime_conn_op}; ++ my $nentries_conn_op = $hashes->{nentries_conn_op}; ++ my $filter_conn_op = $hashes->{filter_conn_op}; ++ my $bind_conn_op = $hashes->{bind_conn_op}; ++ my $notesCount = 1; ++ my $unindexedIp; ++ my $binddn_key; ++ my %uniqFilt = (); # hash of unique filters ++ my %uniqFilter = (); # hash of unique filters bind dn ++ my %uniqBindDNs = (); # hash of unique bind dn's ++ my %uniqBindFilters = (); # hash of filters for a bind DN ++ ++ while (my ($srcnt_conn_op, $count) = each %{$notesf_conn_op}) { ++ my ($srvRstCnt, $conn, $op) = split(",", $srcnt_conn_op); ++ my $attrIp = getIPfromConn($conn, $srvRstCnt); ++ print "\n Invalid Attribute Filter #".$notesCount." (notes=F)\n"; ++ print " - Date/Time: $time_conn_op->{$srcnt_conn_op}\n"; ++ print " - Connection Number: $conn\n"; ++ print " - Operation Number: $op\n"; ++ print " - Etime: $etime_conn_op->{$srcnt_conn_op}\n"; ++ print " - Nentries: $nentries_conn_op->{$srcnt_conn_op}\n"; ++ print " - IP Address: $attrIp\n"; ++ if (exists($filter_conn_op->{$srcnt_conn_op}) && defined($filter_conn_op->{$srcnt_conn_op})) { ++ print " - Search Filter: $filter_conn_op->{$srcnt_conn_op}\n"; ++ $uniqFilt{$filter_conn_op->{$srcnt_conn_op}}++; ++ } ++ while($op > 0){ ++ # The bind op is not the same as the search op that triggered the notes=A. ++ # We have to adjust the key by decrementing the op count until we find the last bind op. ++ $op--; ++ $binddn_key = "$srvRstCnt,$conn,$op"; ++ if (exists($bind_conn_op->{$binddn_key}) && defined($bind_conn_op->{$binddn_key})) { ++ print " - Bind DN: $bind_conn_op->{$binddn_key}\n"; ++ $uniqBindDNs{$bind_conn_op->{$binddn_key}}++; ++ if( $uniqFilt{$filter_conn_op->{$srcnt_conn_op}} && defined($filter_conn_op->{$srcnt_conn_op})) { ++ $uniqBindFilters{$bind_conn_op->{$binddn_key}}{$filter_conn_op->{$srcnt_conn_op}}++; ++ $uniqFilter{$filter_conn_op->{$srcnt_conn_op}}{$bind_conn_op->{$binddn_key}}++; ++ } ++ last; ++ } ++ } ++ $notesCount++; ++ } ++ print "\n"; ++} + +-print "\n"; + print "FDs Taken: $fdTaken\n"; + print "FDs Returned: $fdReturned\n"; + print "Highest FD Taken: $highestFdTaken\n\n"; +@@ -1386,20 +1438,20 @@ if ($usage =~ /l/ || $verb eq "yes"){ + } + } + +-######################################### +-# # +-# Gather and Process the unique etimes # +-# # +-######################################### ++############################################################## ++# # ++# Gather and Process the unique etimes, wtimes, and optimes # ++# # ++############################################################## + + my $first; + if ($usage =~ /t/i || $verb eq "yes"){ ++ # Print the elapsed times (etime) ++ + my $etime = $hashes->{etime}; + my @ekeys = keys %{$etime}; +- # + # print most often etimes +- # +- print "\n\n----- Top $sizeCount Most Frequent etimes -----\n\n"; ++ print "\n\n----- Top $sizeCount Most Frequent etimes (elapsed times) -----\n\n"; + my $eloop = 0; + my $retime = 0; + foreach my $et (sort { $etime->{$b} <=> $etime->{$a} } @ekeys) { +@@ -1411,16 +1463,84 @@ if ($usage =~ /t/i || $verb eq "yes"){ + printf "%-8s %-12s\n", $etime->{ $et }, "etime=$et"; + $eloop++; + } +- # ++ if ($eloop == 0) { ++ print "None"; ++ } + # print longest etimes +- # +- print "\n\n----- Top $sizeCount Longest etimes -----\n\n"; ++ print "\n\n----- Top $sizeCount Longest etimes (elapsed times) -----\n\n"; + $eloop = 0; + foreach my $et (sort { $b <=> $a } @ekeys) { + if ($eloop == $sizeCount) { last; } + printf "%-12s %-10s\n","etime=$et",$etime->{ $et }; + $eloop++; + } ++ if ($eloop == 0) { ++ print "None"; ++ } ++ ++ # Print the wait times (wtime) ++ ++ my $wtime = $hashes->{wtime}; ++ my @wkeys = keys %{$wtime}; ++ # print most often wtimes ++ print "\n\n----- Top $sizeCount Most Frequent wtimes (wait times) -----\n\n"; ++ $eloop = 0; ++ $retime = 0; ++ foreach my $et (sort { $wtime->{$b} <=> $wtime->{$a} } @wkeys) { ++ if ($eloop == $sizeCount) { last; } ++ if ($retime ne "2"){ ++ $first = $et; ++ $retime = "2"; ++ } ++ printf "%-8s %-12s\n", $wtime->{ $et }, "wtime=$et"; ++ $eloop++; ++ } ++ if ($eloop == 0) { ++ print "None"; ++ } ++ # print longest wtimes ++ print "\n\n----- Top $sizeCount Longest wtimes (wait times) -----\n\n"; ++ $eloop = 0; ++ foreach my $et (sort { $b <=> $a } @wkeys) { ++ if ($eloop == $sizeCount) { last; } ++ printf "%-12s %-10s\n","wtime=$et",$wtime->{ $et }; ++ $eloop++; ++ } ++ if ($eloop == 0) { ++ print "None"; ++ } ++ ++ # Print the operation times (optime) ++ ++ my $optime = $hashes->{optime}; ++ my @opkeys = keys %{$optime}; ++ # print most often optimes ++ print "\n\n----- Top $sizeCount Most Frequent optimes (actual operation times) -----\n\n"; ++ $eloop = 0; ++ $retime = 0; ++ foreach my $et (sort { $optime->{$b} <=> $optime->{$a} } @opkeys) { ++ if ($eloop == $sizeCount) { last; } ++ if ($retime ne "2"){ ++ $first = $et; ++ $retime = "2"; ++ } ++ printf "%-8s %-12s\n", $optime->{ $et }, "optime=$et"; ++ $eloop++; ++ } ++ if ($eloop == 0) { ++ print "None"; ++ } ++ # print longest optimes ++ print "\n\n----- Top $sizeCount Longest optimes (actual operation times) -----\n\n"; ++ $eloop = 0; ++ foreach my $et (sort { $b <=> $a } @opkeys) { ++ if ($eloop == $sizeCount) { last; } ++ printf "%-12s %-10s\n","optime=$et",$optime->{ $et }; ++ $eloop++; ++ } ++ if ($eloop == 0) { ++ print "None"; ++ } + } + + ####################################### +@@ -2152,6 +2272,26 @@ sub parseLineNormal + if (m/ RESULT err=/ && m/ notes=[A-Z,]*P/){ + $pagedSearchCount++; + } ++ if (m/ RESULT err=/ && m/ notes=[A-Z,]*F/){ ++ $invalidFilterCount++; ++ $con = ""; ++ if ($_ =~ /conn= *([0-9A-Z]+)/i){ ++ $con = $1; ++ if ($_ =~ /op= *([0-9\-]+)/i){ $op = $1;} ++ } ++ ++ if($reportStats){ inc_stats('notesF',$s_stats,$m_stats); } ++ if ($usage =~ /u/ || $usage =~ /U/ || $verb eq "yes"){ ++ if($_ =~ /etime= *([0-9.]+)/i ){ ++ if($1 >= $minEtime){ ++ $hashes->{etime_conn_op}->{"$serverRestartCount,$con,$op"} = $1; ++ $hashes->{notesf_conn_op}->{"$serverRestartCount,$con,$op"}++; ++ if ($_ =~ / *([0-9a-z:\/]+)/i){ $hashes->{time_conn_op}->{"$serverRestartCount,$con,$op"} = $1; } ++ if ($_ =~ /nentries= *([0-9]+)/i ){ $hashes->{nentries_conn_op}->{"$serverRestartCount,$con,$op"} = $1; } ++ } ++ } ++ } ++ } + if (m/ notes=[A-Z,]*A/){ + $con = ""; + if ($_ =~ /conn= *([0-9A-Z]+)/i){ +@@ -2435,6 +2575,16 @@ sub parseLineNormal + if ($usage =~ /t/i || $verb eq "yes"){ $hashes->{etime}->{$etime_val}++; } + if ($reportStats){ inc_stats_val('etime',$etime_val,$s_stats,$m_stats); } + } ++ if ($_ =~ /wtime= *([0-9.]+)/ ) { ++ my $wtime_val = $1; ++ if ($usage =~ /t/i || $verb eq "yes"){ $hashes->{wtime}->{$wtime_val}++; } ++ if ($reportStats){ inc_stats_val('wtime',$wtime_val,$s_stats,$m_stats); } ++ } ++ if ($_ =~ /optime= *([0-9.]+)/ ) { ++ my $optime_val = $1; ++ if ($usage =~ /t/i || $verb eq "yes"){ $hashes->{optime}->{$optime_val}++; } ++ if ($reportStats){ inc_stats_val('optime',$optime_val,$s_stats,$m_stats); } ++ } + if ($_ =~ / tag=101 / || $_ =~ / tag=111 / || $_ =~ / tag=100 / || $_ =~ / tag=115 /){ + if ($_ =~ / nentries= *([0-9]+)/i ){ + my $nents = $1; +@@ -2555,7 +2705,7 @@ sub parseLineNormal + } + } + } +- if (/ RESULT err=/ && / tag=97 nentries=0 etime=/ && $_ =~ /dn=\"(.*)\"/i){ ++ if (/ RESULT err=/ && / tag=97 nentries=0 / && $_ =~ /dn=\"(.*)\"/i){ + # Check if this is a sasl bind, if see we need to add the RESULT's dn as a bind dn + my $binddn = $1; + my ($conn, $op); +@@ -2680,6 +2830,7 @@ print_stats_block + $stats->{'unbind'}, + $stats->{'notesA'}, + $stats->{'notesU'}, ++ $stats->{'notesF'}, + $stats->{'etime'}), + "\n" ); + } else { +diff --git a/ldap/servers/slapd/add.c b/ldap/servers/slapd/add.c +index 06ca1ee79..52c64fa3c 100644 +--- a/ldap/servers/slapd/add.c ++++ b/ldap/servers/slapd/add.c +@@ -441,6 +441,9 @@ op_shared_add(Slapi_PBlock *pb) + internal_op = operation_is_flag_set(operation, OP_FLAG_INTERNAL); + pwpolicy = new_passwdPolicy(pb, slapi_entry_get_dn(e)); + ++ /* Set the time we actually started the operation */ ++ slapi_operation_set_time_started(operation); ++ + /* target spec is used to decide which plugins are applicable for the operation */ + operation_set_target_spec(operation, slapi_entry_get_sdn(e)); + +diff --git a/ldap/servers/slapd/bind.c b/ldap/servers/slapd/bind.c +index 310216e89..55f865077 100644 +--- a/ldap/servers/slapd/bind.c ++++ b/ldap/servers/slapd/bind.c +@@ -87,6 +87,10 @@ do_bind(Slapi_PBlock *pb) + send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL); + goto free_and_return; + } ++ ++ /* Set the time we actually started the operation */ ++ slapi_operation_set_time_started(pb_op); ++ + ber = pb_op->o_ber; + + /* +diff --git a/ldap/servers/slapd/delete.c b/ldap/servers/slapd/delete.c +index c0e61adf1..1a7209317 100644 +--- a/ldap/servers/slapd/delete.c ++++ b/ldap/servers/slapd/delete.c +@@ -236,6 +236,9 @@ op_shared_delete(Slapi_PBlock *pb) + slapi_pblock_get(pb, SLAPI_OPERATION, &operation); + internal_op = operation_is_flag_set(operation, OP_FLAG_INTERNAL); + ++ /* Set the time we actually started the operation */ ++ slapi_operation_set_time_started(operation); ++ + sdn = slapi_sdn_new_dn_byval(rawdn); + dn = slapi_sdn_get_dn(sdn); + slapi_pblock_set(pb, SLAPI_DELETE_TARGET_SDN, (void *)sdn); +diff --git a/ldap/servers/slapd/modify.c b/ldap/servers/slapd/modify.c +index 259bedfff..a186dbde3 100644 +--- a/ldap/servers/slapd/modify.c ++++ b/ldap/servers/slapd/modify.c +@@ -626,6 +626,9 @@ op_shared_modify(Slapi_PBlock *pb, int pw_change, char *old_pw) + slapi_pblock_get(pb, SLAPI_SKIP_MODIFIED_ATTRS, &skip_modified_attrs); + slapi_pblock_get(pb, SLAPI_CONNECTION, &pb_conn); + ++ /* Set the time we actually started the operation */ ++ slapi_operation_set_time_started(operation); ++ + if (sdn) { + passin_sdn = 1; + } else { +diff --git a/ldap/servers/slapd/modrdn.c b/ldap/servers/slapd/modrdn.c +index 3efe584a7..e04916b83 100644 +--- a/ldap/servers/slapd/modrdn.c ++++ b/ldap/servers/slapd/modrdn.c +@@ -417,6 +417,9 @@ op_shared_rename(Slapi_PBlock *pb, int passin_args) + internal_op = operation_is_flag_set(operation, OP_FLAG_INTERNAL); + slapi_pblock_get(pb, SLAPI_CONNECTION, &pb_conn); + ++ /* Set the time we actually started the operation */ ++ slapi_operation_set_time_started(operation); ++ + /* + * If ownership has not been passed to this function, we replace the + * string input fields within the pblock with strdup'd copies. Why? +diff --git a/ldap/servers/slapd/operation.c b/ldap/servers/slapd/operation.c +index ff16cd906..4dd3481c7 100644 +--- a/ldap/servers/slapd/operation.c ++++ b/ldap/servers/slapd/operation.c +@@ -651,3 +651,27 @@ slapi_operation_time_expiry(Slapi_Operation *o, time_t timeout, struct timespec + { + slapi_timespec_expire_rel(timeout, &(o->o_hr_time_rel), expiry); + } ++ ++/* Set the time the operation actually started */ ++void ++slapi_operation_set_time_started(Slapi_Operation *o) ++{ ++ clock_gettime(CLOCK_MONOTONIC, &(o->o_hr_time_started_rel)); ++} ++ ++/* The time diff of how long the operation took once it actually started */ ++void ++slapi_operation_op_time_elapsed(Slapi_Operation *o, struct timespec *elapsed) ++{ ++ struct timespec o_hr_time_now; ++ clock_gettime(CLOCK_MONOTONIC, &o_hr_time_now); ++ ++ slapi_timespec_diff(&o_hr_time_now, &(o->o_hr_time_started_rel), elapsed); ++} ++ ++/* The time diff the operation waited in the work queue */ ++void ++slapi_operation_workq_time_elapsed(Slapi_Operation *o, struct timespec *elapsed) ++{ ++ slapi_timespec_diff(&(o->o_hr_time_started_rel), &(o->o_hr_time_rel), elapsed); ++} +diff --git a/ldap/servers/slapd/opshared.c b/ldap/servers/slapd/opshared.c +index 9fe78655c..c0bc5dcd0 100644 +--- a/ldap/servers/slapd/opshared.c ++++ b/ldap/servers/slapd/opshared.c +@@ -284,6 +284,9 @@ op_shared_search(Slapi_PBlock *pb, int send_result) + slapi_pblock_get(pb, SLAPI_SEARCH_TARGET_SDN, &sdn); + slapi_pblock_get(pb, SLAPI_OPERATION, &operation); + ++ /* Set the time we actually started the operation */ ++ slapi_operation_set_time_started(operation); ++ + if (NULL == sdn) { + sdn = slapi_sdn_new_dn_byval(base); + slapi_pblock_set(pb, SLAPI_SEARCH_TARGET_SDN, sdn); +diff --git a/ldap/servers/slapd/result.c b/ldap/servers/slapd/result.c +index 0b13c30e9..61efb6f8d 100644 +--- a/ldap/servers/slapd/result.c ++++ b/ldap/servers/slapd/result.c +@@ -1975,6 +1975,8 @@ log_result(Slapi_PBlock *pb, Operation *op, int err, ber_tag_t tag, int nentries + CSN *operationcsn = NULL; + char csn_str[CSN_STRSIZE + 5]; + char etime[ETIME_BUFSIZ] = {0}; ++ char wtime[ETIME_BUFSIZ] = {0}; ++ char optime[ETIME_BUFSIZ] = {0}; + int pr_idx = -1; + int pr_cookie = -1; + uint32_t operation_notes; +@@ -1982,19 +1984,26 @@ log_result(Slapi_PBlock *pb, Operation *op, int err, ber_tag_t tag, int nentries + int32_t op_id; + int32_t op_internal_id; + int32_t op_nested_count; ++ struct timespec o_hr_time_end; + + get_internal_conn_op(&connid, &op_id, &op_internal_id, &op_nested_count); +- + slapi_pblock_get(pb, SLAPI_PAGED_RESULTS_INDEX, &pr_idx); + slapi_pblock_get(pb, SLAPI_PAGED_RESULTS_COOKIE, &pr_cookie); +- + internal_op = operation_is_flag_set(op, OP_FLAG_INTERNAL); + +- struct timespec o_hr_time_end; ++ /* total elapsed time */ + slapi_operation_time_elapsed(op, &o_hr_time_end); ++ snprintf(etime, ETIME_BUFSIZ, "%" PRId64 ".%.09" PRId64 "", (int64_t)o_hr_time_end.tv_sec, (int64_t)o_hr_time_end.tv_nsec); ++ ++ /* wait time */ ++ slapi_operation_workq_time_elapsed(op, &o_hr_time_end); ++ snprintf(wtime, ETIME_BUFSIZ, "%" PRId64 ".%.09" PRId64 "", (int64_t)o_hr_time_end.tv_sec, (int64_t)o_hr_time_end.tv_nsec); ++ ++ /* op time */ ++ slapi_operation_op_time_elapsed(op, &o_hr_time_end); ++ snprintf(optime, ETIME_BUFSIZ, "%" PRId64 ".%.09" PRId64 "", (int64_t)o_hr_time_end.tv_sec, (int64_t)o_hr_time_end.tv_nsec); + + +- snprintf(etime, ETIME_BUFSIZ, "%" PRId64 ".%.09" PRId64 "", (int64_t)o_hr_time_end.tv_sec, (int64_t)o_hr_time_end.tv_nsec); + + operation_notes = slapi_pblock_get_operation_notes(pb); + +@@ -2025,16 +2034,16 @@ log_result(Slapi_PBlock *pb, Operation *op, int err, ber_tag_t tag, int nentries + if (!internal_op) { + slapi_log_access(LDAP_DEBUG_STATS, + "conn=%" PRIu64 " op=%d RESULT err=%d" +- " tag=%" BERTAG_T " nentries=%d etime=%s%s%s" ++ " tag=%" BERTAG_T " nentries=%d wtime=%s optime=%s etime=%s%s%s" + ", SASL bind in progress\n", + op->o_connid, + op->o_opid, + err, tag, nentries, +- etime, ++ wtime, optime, etime, + notes_str, csn_str); + } else { + +-#define LOG_SASLMSG_FMT " tag=%" BERTAG_T " nentries=%d etime=%s%s%s, SASL bind in progress\n" ++#define LOG_SASLMSG_FMT " tag=%" BERTAG_T " nentries=%d wtime=%s optime=%s etime=%s%s%s, SASL bind in progress\n" + slapi_log_access(LDAP_DEBUG_ARGS, + connid == 0 ? LOG_CONN_OP_FMT_INT_INT LOG_SASLMSG_FMT : + LOG_CONN_OP_FMT_EXT_INT LOG_SASLMSG_FMT, +@@ -2043,7 +2052,7 @@ log_result(Slapi_PBlock *pb, Operation *op, int err, ber_tag_t tag, int nentries + op_internal_id, + op_nested_count, + err, tag, nentries, +- etime, ++ wtime, optime, etime, + notes_str, csn_str); + } + } else if (op->o_tag == LDAP_REQ_BIND && err == LDAP_SUCCESS) { +@@ -2057,15 +2066,15 @@ log_result(Slapi_PBlock *pb, Operation *op, int err, ber_tag_t tag, int nentries + if (!internal_op) { + slapi_log_access(LDAP_DEBUG_STATS, + "conn=%" PRIu64 " op=%d RESULT err=%d" +- " tag=%" BERTAG_T " nentries=%d etime=%s%s%s" ++ " tag=%" BERTAG_T " nentries=%d wtime=%s optime=%s etime=%s%s%s" + " dn=\"%s\"\n", + op->o_connid, + op->o_opid, + err, tag, nentries, +- etime, ++ wtime, optime, etime, + notes_str, csn_str, dn ? dn : ""); + } else { +-#define LOG_BINDMSG_FMT " tag=%" BERTAG_T " nentries=%d etime=%s%s%s dn=\"%s\"\n" ++#define LOG_BINDMSG_FMT " tag=%" BERTAG_T " nentries=%d wtime=%s optime=%s etime=%s%s%s dn=\"%s\"\n" + slapi_log_access(LDAP_DEBUG_ARGS, + connid == 0 ? LOG_CONN_OP_FMT_INT_INT LOG_BINDMSG_FMT : + LOG_CONN_OP_FMT_EXT_INT LOG_BINDMSG_FMT, +@@ -2074,7 +2083,7 @@ log_result(Slapi_PBlock *pb, Operation *op, int err, ber_tag_t tag, int nentries + op_internal_id, + op_nested_count, + err, tag, nentries, +- etime, ++ wtime, optime, etime, + notes_str, csn_str, dn ? dn : ""); + } + slapi_ch_free((void **)&dn); +@@ -2083,15 +2092,15 @@ log_result(Slapi_PBlock *pb, Operation *op, int err, ber_tag_t tag, int nentries + if (!internal_op) { + slapi_log_access(LDAP_DEBUG_STATS, + "conn=%" PRIu64 " op=%d RESULT err=%d" +- " tag=%" BERTAG_T " nentries=%d etime=%s%s%s" ++ " tag=%" BERTAG_T " nentries=%d wtime=%s optime=%s etime=%s%s%s" + " pr_idx=%d pr_cookie=%d\n", + op->o_connid, + op->o_opid, + err, tag, nentries, +- etime, ++ wtime, optime, etime, + notes_str, csn_str, pr_idx, pr_cookie); + } else { +-#define LOG_PRMSG_FMT " tag=%" BERTAG_T " nentries=%d etime=%s%s%s pr_idx=%d pr_cookie=%d \n" ++#define LOG_PRMSG_FMT " tag=%" BERTAG_T " nentries=%d wtime=%s optime=%s etime=%s%s%s pr_idx=%d pr_cookie=%d \n" + slapi_log_access(LDAP_DEBUG_ARGS, + connid == 0 ? LOG_CONN_OP_FMT_INT_INT LOG_PRMSG_FMT : + LOG_CONN_OP_FMT_EXT_INT LOG_PRMSG_FMT, +@@ -2100,7 +2109,7 @@ log_result(Slapi_PBlock *pb, Operation *op, int err, ber_tag_t tag, int nentries + op_internal_id, + op_nested_count, + err, tag, nentries, +- etime, ++ wtime, optime, etime, + notes_str, csn_str, pr_idx, pr_cookie); + } + } else if (!internal_op) { +@@ -2114,11 +2123,11 @@ log_result(Slapi_PBlock *pb, Operation *op, int err, ber_tag_t tag, int nentries + } + slapi_log_access(LDAP_DEBUG_STATS, + "conn=%" PRIu64 " op=%d RESULT err=%d" +- " tag=%" BERTAG_T " nentries=%d etime=%s%s%s%s\n", ++ " tag=%" BERTAG_T " nentries=%d wtime=%s optime=%s etime=%s%s%s%s\n", + op->o_connid, + op->o_opid, + err, tag, nentries, +- etime, ++ wtime, optime, etime, + notes_str, csn_str, ext_str); + if (pbtxt) { + /* if !pbtxt ==> ext_str == "". Don't free ext_str. */ +@@ -2126,7 +2135,7 @@ log_result(Slapi_PBlock *pb, Operation *op, int err, ber_tag_t tag, int nentries + } + } else { + int optype; +-#define LOG_MSG_FMT " tag=%" BERTAG_T " nentries=%d etime=%s%s%s\n" ++#define LOG_MSG_FMT " tag=%" BERTAG_T " nentries=%d wtime=%s optime=%s etime=%s%s%s\n" + slapi_log_access(LDAP_DEBUG_ARGS, + connid == 0 ? LOG_CONN_OP_FMT_INT_INT LOG_MSG_FMT : + LOG_CONN_OP_FMT_EXT_INT LOG_MSG_FMT, +@@ -2135,7 +2144,7 @@ log_result(Slapi_PBlock *pb, Operation *op, int err, ber_tag_t tag, int nentries + op_internal_id, + op_nested_count, + err, tag, nentries, +- etime, ++ wtime, optime, etime, + notes_str, csn_str); + /* + * If this is an unindexed search we should log it in the error log if +diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h +index cef8c789c..8e76393c3 100644 +--- a/ldap/servers/slapd/slap.h ++++ b/ldap/servers/slapd/slap.h +@@ -1538,16 +1538,17 @@ typedef struct slapi_operation_results + */ + typedef struct op + { +- BerElement *o_ber; /* ber of the request */ +- ber_int_t o_msgid; /* msgid of the request */ +- ber_tag_t o_tag; /* tag of the request */ ++ BerElement *o_ber; /* ber of the request */ ++ ber_int_t o_msgid; /* msgid of the request */ ++ ber_tag_t o_tag; /* tag of the request */ + struct timespec o_hr_time_rel; /* internal system time op initiated */ + struct timespec o_hr_time_utc; /* utc system time op initiated */ +- int o_isroot; /* requestor is manager */ ++ struct timespec o_hr_time_started_rel; /* internal system time op started */ ++ int o_isroot; /* requestor is manager */ + Slapi_DN o_sdn; /* dn bound when op was initiated */ +- char *o_authtype; /* auth method used to bind dn */ ++ char *o_authtype; /* auth method used to bind dn */ + int o_ssf; /* ssf for this operation (highest between SASL and TLS/SSL) */ +- int o_opid; /* id of this operation */ ++ int o_opid; /* id of this operation */ + PRUint64 o_connid; /* id of conn initiating this op; for logging only */ + void *o_handler_data; + result_handler o_result_handler; +diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h +index 834a98742..8d9c3fa6a 100644 +--- a/ldap/servers/slapd/slapi-plugin.h ++++ b/ldap/servers/slapd/slapi-plugin.h +@@ -8210,13 +8210,29 @@ void slapi_operation_time_elapsed(Slapi_Operation *o, struct timespec *elapsed); + */ + void slapi_operation_time_initiated(Slapi_Operation *o, struct timespec *initiated); + /** +- * Given an operation and a timeout, return a populate struct with the expiry +- * time of the operation suitable for checking with slapi_timespec_expire_check ++ * Given an operation, determine the time elapsed since the op ++ * was actually started. + * +- * \param Slapi_Operation o - the operation that is in progress +- * \param time_t timeout the seconds relative to operation initiation to expiry at. +- * \param struct timespec *expiry the timespec to popluate with the relative expiry. ++ * \param Slapi_Operation o - the operation which is inprogress ++ * \param struct timespec *elapsed - location where the time difference will be ++ * placed. ++ */ ++void slapi_operation_op_time_elapsed(Slapi_Operation *o, struct timespec *elapsed); ++/** ++ * Given an operation, determine the time elapsed that the op spent ++ * in the work queue before actually being dispatched to a worker thread ++ * ++ * \param Slapi_Operation o - the operation which is inprogress ++ * \param struct timespec *elapsed - location where the time difference will be ++ * placed. ++ */ ++void slapi_operation_workq_time_elapsed(Slapi_Operation *o, struct timespec *elapsed); ++/** ++ * Set the time the operation actually started ++ * ++ * \param Slapi_Operation o - the operation which is inprogress + */ ++void slapi_operation_set_time_started(Slapi_Operation *o); + #endif + + /** +-- +2.26.2 + diff --git a/SOURCES/0017-Issue-50912-pwdReset-can-be-modified-by-a-user.patch b/SOURCES/0017-Issue-50912-pwdReset-can-be-modified-by-a-user.patch new file mode 100644 index 0000000..56b0db4 --- /dev/null +++ b/SOURCES/0017-Issue-50912-pwdReset-can-be-modified-by-a-user.patch @@ -0,0 +1,31 @@ +From ec1714c81290a03ae9aa5fd10acf3e9be71596d7 Mon Sep 17 00:00:00 2001 +From: Mark Reynolds +Date: Thu, 11 Jun 2020 15:47:43 -0400 +Subject: [PATCH] Issue 50912 - pwdReset can be modified by a user + +Description: The attribute "pwdReset" should only be allowed to be set by the + server. Update schema definition to include NO-USER-MODIFICATION + +relates: https://pagure.io/389-ds-base/issue/50912 + +Reviewed by: mreynolds(one line commit rule) +--- + ldap/schema/02common.ldif | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/ldap/schema/02common.ldif b/ldap/schema/02common.ldif +index 966636bef..c6dc074db 100644 +--- a/ldap/schema/02common.ldif ++++ b/ldap/schema/02common.ldif +@@ -76,7 +76,7 @@ attributeTypes: ( 2.16.840.1.113730.3.1.2349 NAME ( 'passwordDictCheck' 'pwdDict + attributeTypes: ( 2.16.840.1.113730.3.1.2350 NAME ( 'passwordDictPath' 'pwdDictPath' ) DESC '389 Directory Server password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN '389 Directory Server' ) + attributeTypes: ( 2.16.840.1.113730.3.1.2351 NAME ( 'passwordUserAttributes' 'pwdUserAttributes' ) DESC '389 Directory Server password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN '389 Directory Server' ) + attributeTypes: ( 2.16.840.1.113730.3.1.2352 NAME ( 'passwordBadWords' 'pwdBadWords' ) DESC '389 Directory Server password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN '389 Directory Server' ) +-attributeTypes: ( 2.16.840.1.113730.3.1.2366 NAME 'pwdReset' DESC '389 Directory Server password policy attribute type' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE USAGE directoryOperation X-ORIGIN '389 Directory Server' ) ++attributeTypes: ( 2.16.840.1.113730.3.1.2366 NAME 'pwdReset' DESC '389 Directory Server password policy attribute type' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation X-ORIGIN '389 Directory Server' ) + attributeTypes: ( 2.16.840.1.113730.3.1.198 NAME 'memberURL' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Directory Server' ) + attributeTypes: ( 2.16.840.1.113730.3.1.199 NAME 'memberCertificateDescription' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Directory Server' ) + attributeTypes: ( 2.16.840.1.113730.3.1.207 NAME 'vlvBase' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape Directory Server' ) +-- +2.26.2 + diff --git a/SOURCES/0017-Ticket-50745-ns-slapd-hangs-during-CleanAllRUV-tests.patch b/SOURCES/0017-Ticket-50745-ns-slapd-hangs-during-CleanAllRUV-tests.patch deleted file mode 100644 index 5033966..0000000 --- a/SOURCES/0017-Ticket-50745-ns-slapd-hangs-during-CleanAllRUV-tests.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 06e1fe32e47b98efaa3598629fb59e5f7791e28d Mon Sep 17 00:00:00 2001 -From: Thierry Bordaz -Date: Wed, 27 Nov 2019 14:04:14 +0100 -Subject: [PATCH] Ticket 50745: ns-slapd hangs during CleanAllRUV tests - -Bug Description: - The hang condition: - - is not systematic - - occurs in rare case, for example here during the deletion of a replica. - - a thread is waiting for a dblock that an other thread "forgot" to - release. - - have always existed, at least since 1.4.0 but likely since 1.2.x - - When deleting a replica, the replica is retrieved from - mapping tree structure (mtnode). - The replica is also retrieved through the mapping tree - when writing updates to the changelog. - - When deleting the replica, mapping tree structure is cleared - after the changelog is deleted (that can take some cycles). - There is a window where an update can retrieve the replica, - from the not yet cleared MT, while the changelog being removed. - - At the end, the update will update the changelog that is - currently removed and keeps an unfree lock in the DB. - -Fix description: - Ideally mapping tree should be protected by a lock but it - is not done systematically (e.g. slapi_get_mapping_tree_node). - Using a lock looks an overkill and can probably introduce - deadlock and performance hit. - The idea of the fix is to reduce the window, moving the - mapping tree clear before the changelog removal. - -https://pagure.io/389-ds-base/issue/50745 - -Reviewed by: Mark Reynolds, Ludwig Krispenz ---- - ldap/servers/plugins/replication/repl5_replica_config.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/ldap/servers/plugins/replication/repl5_replica_config.c b/ldap/servers/plugins/replication/repl5_replica_config.c -index 79b257564..02b36f6ad 100644 ---- a/ldap/servers/plugins/replication/repl5_replica_config.c -+++ b/ldap/servers/plugins/replication/repl5_replica_config.c -@@ -757,6 +757,10 @@ replica_config_delete(Slapi_PBlock *pb __attribute__((unused)), - if (mtnode_ext->replica) { - /* remove object from the hash */ - r = (Replica *)object_get_data(mtnode_ext->replica); -+ mtnode_ext->replica = NULL; /* moving it before deleting the CL because -+ * deletion can take some time giving the opportunity -+ * to an operation to start while CL is deleted -+ */ - PR_ASSERT(r); - /* The changelog for this replica is no longer valid, so we should remove it. */ - slapi_log_err(SLAPI_LOG_WARNING, repl_plugin_name, "replica_config_delete - " -@@ -765,7 +769,6 @@ replica_config_delete(Slapi_PBlock *pb __attribute__((unused)), - slapi_sdn_get_dn(replica_get_root(r))); - cl5DeleteDBSync(r); - replica_delete_by_name(replica_get_name(r)); -- mtnode_ext->replica = NULL; - } - - PR_Unlock(s_configLock); --- -2.21.1 - diff --git a/SOURCES/0018-Issue-50791-Healthcheck-should-look-for-notes-A-F-in.patch b/SOURCES/0018-Issue-50791-Healthcheck-should-look-for-notes-A-F-in.patch new file mode 100644 index 0000000..5f4f6a3 --- /dev/null +++ b/SOURCES/0018-Issue-50791-Healthcheck-should-look-for-notes-A-F-in.patch @@ -0,0 +1,202 @@ +From a6a52365df26edd4f6b0028056395d943344d787 Mon Sep 17 00:00:00 2001 +From: Mark Reynolds +Date: Thu, 11 Jun 2020 15:30:28 -0400 +Subject: [PATCH] Issue 50791 - Healthcheck should look for notes=A/F in access + log + +Description: Add checks for notes=A (fully unindexed search) and + notes=F (Unknown attribute in search filter) in the + current access log. + +relates: https://pagure.io/389-ds-base/issue/50791 + +Reviewed by: firstyear(Thanks!) +--- + src/lib389/lib389/cli_ctl/health.py | 4 +- + src/lib389/lib389/dirsrv_log.py | 72 +++++++++++++++++++++++++++-- + src/lib389/lib389/lint.py | 26 ++++++++++- + 3 files changed, 96 insertions(+), 6 deletions(-) + +diff --git a/src/lib389/lib389/cli_ctl/health.py b/src/lib389/lib389/cli_ctl/health.py +index 6333a753a..89484a11b 100644 +--- a/src/lib389/lib389/cli_ctl/health.py ++++ b/src/lib389/lib389/cli_ctl/health.py +@@ -1,5 +1,5 @@ + # --- BEGIN COPYRIGHT BLOCK --- +-# Copyright (C) 2019 Red Hat, Inc. ++# Copyright (C) 2020 Red Hat, Inc. + # All rights reserved. + # + # License: GPL (version 3 or any later version). +@@ -18,6 +18,7 @@ from lib389.monitor import MonitorDiskSpace + from lib389.replica import Replica, Changelog5 + from lib389.nss_ssl import NssSsl + from lib389.dseldif import FSChecks, DSEldif ++from lib389.dirsrv_log import DirsrvAccessLog + from lib389 import lint + from lib389 import plugins + from lib389._constants import DSRC_HOME +@@ -37,6 +38,7 @@ CHECK_OBJECTS = [ + Changelog5, + DSEldif, + NssSsl, ++ DirsrvAccessLog, + ] + + +diff --git a/src/lib389/lib389/dirsrv_log.py b/src/lib389/lib389/dirsrv_log.py +index baac2a3c9..7bed4bb17 100644 +--- a/src/lib389/lib389/dirsrv_log.py ++++ b/src/lib389/lib389/dirsrv_log.py +@@ -1,5 +1,5 @@ + # --- BEGIN COPYRIGHT BLOCK --- +-# Copyright (C) 2016 Red Hat, Inc. ++# Copyright (C) 2020 Red Hat, Inc. + # All rights reserved. + # + # License: GPL (version 3 or any later version). +@@ -9,12 +9,17 @@ + """Helpers for managing the directory server internal logs. + """ + ++import copy + import re + import gzip + from dateutil.parser import parse as dt_parse + from glob import glob + from lib389.utils import ensure_bytes +- ++from lib389._mapped_object_lint import DSLint ++from lib389.lint import ( ++ DSLOGNOTES0001, # Unindexed search ++ DSLOGNOTES0002, # Unknown attr in search filter ++) + + # Because many of these settings can change live, we need to check for certain + # attributes all the time. +@@ -35,7 +40,7 @@ MONTH_LOOKUP = { + } + + +-class DirsrvLog(object): ++class DirsrvLog(DSLint): + """Class of functions to working with the various DIrectory Server logs + """ + def __init__(self, dirsrv): +@@ -189,6 +194,67 @@ class DirsrvAccessLog(DirsrvLog): + self.full_regexs = [self.prog_m1, self.prog_con, self.prog_discon] + self.result_regexs = [self.prog_notes, self.prog_repl, + self.prog_result] ++ @classmethod ++ def lint_uid(cls): ++ return 'logs' ++ ++ def _log_get_search_stats(self, conn, op): ++ lines = self.match(f".* conn={conn} op={op} SRCH base=.*") ++ if len(lines) != 1: ++ return None ++ ++ quoted_vals = re.findall('"([^"]*)"', lines[0]) ++ return { ++ 'base': quoted_vals[0], ++ 'filter': quoted_vals[1], ++ 'timestamp': re.findall('\[(.*)\]', lines[0])[0], ++ 'scope': lines[0].split(' scope=', 1)[1].split(' ',1)[0] ++ } ++ ++ def _lint_notes(self): ++ """ ++ Check for notes=A (fully unindexed searches), and ++ notes=F (unknown attribute in filter) ++ """ ++ for pattern, lint_report in [(".* notes=A", DSLOGNOTES0001), (".* notes=F", DSLOGNOTES0002)]: ++ lines = self.match(pattern) ++ if len(lines) > 0: ++ count = 0 ++ searches = [] ++ for line in lines: ++ if ' RESULT err=' in line: ++ # Looks like a valid notes=A/F ++ conn = line.split(' conn=', 1)[1].split(' ',1)[0] ++ op = line.split(' op=', 1)[1].split(' ',1)[0] ++ etime = line.split(' etime=', 1)[1].split(' ',1)[0] ++ stats = self._log_get_search_stats(conn, op) ++ if stats is not None: ++ timestamp = stats['timestamp'] ++ base = stats['base'] ++ scope = stats['scope'] ++ srch_filter = stats['filter'] ++ count += 1 ++ if lint_report == DSLOGNOTES0001: ++ searches.append(f'\n [{count}] Unindexed Search\n' ++ f' - date: {timestamp}\n' ++ f' - conn/op: {conn}/{op}\n' ++ f' - base: {base}\n' ++ f' - scope: {scope}\n' ++ f' - filter: {srch_filter}\n' ++ f' - etime: {etime}\n') ++ else: ++ searches.append(f'\n [{count}] Invalid Attribute in Filter\n' ++ f' - date: {timestamp}\n' ++ f' - conn/op: {conn}/{op}\n' ++ f' - filter: {srch_filter}\n') ++ if len(searches) > 0: ++ report = copy.deepcopy(lint_report) ++ report['items'].append(self._get_log_path()) ++ report['detail'] = report['detail'].replace('NUMBER', str(count)) ++ for srch in searches: ++ report['detail'] += srch ++ yield report ++ + + def _get_log_path(self): + """Return the current log file location""" +diff --git a/src/lib389/lib389/lint.py b/src/lib389/lib389/lint.py +index a103feec7..4b1700b92 100644 +--- a/src/lib389/lib389/lint.py ++++ b/src/lib389/lib389/lint.py +@@ -1,5 +1,5 @@ + # --- BEGIN COPYRIGHT BLOCK --- +-# Copyright (C) 2019 Red Hat, Inc. ++# Copyright (C) 2020 Red Hat, Inc. + # All rights reserved. + # + # License: GPL (version 3 or any later version). +@@ -253,7 +253,7 @@ can use the CLI tool "dsconf" to resolve the conflict. Here is an example: + + Remove conflict entry and keep only the original/counterpart entry: + +- # dsconf slapd-YOUR_INSTANCE repl-conflict remove ++ # dsconf slapd-YOUR_INSTANCE repl-conflict delete + + Replace the original/counterpart entry with the conflict entry: + +@@ -418,3 +418,25 @@ until the time issues have been resolved: + Also look at https://access.redhat.com/documentation/en-us/red_hat_directory_server/11/html/administration_guide/managing_replication-troubleshooting_replication_related_problems + and find the paragraph "Too much time skew".""" + } ++ ++DSLOGNOTES0001 = { ++ 'dsle': 'DSLOGNOTES0001', ++ 'severity': 'Medium', ++ 'description': 'Unindexed Search', ++ 'items': ['Performance'], ++ 'detail': """Found NUMBER fully unindexed searches in the current access log. ++Unindexed searches can cause high CPU and slow down the entire server's performance.\n""", ++ 'fix': """Examine the searches that are unindexed, and either properly index the attributes ++in the filter, increase the nsslapd-idlistscanlimit, or stop using that filter.""" ++} ++ ++DSLOGNOTES0002 = { ++ 'dsle': 'DSLOGNOTES0002', ++ 'severity': 'Medium', ++ 'description': 'Unknown Attribute In Filter', ++ 'items': ['Possible Performance Impact'], ++ 'detail': """Found NUMBER searches in the current access log that are using an ++unknown attribute in the search filter.\n""", ++ 'fix': """Stop using this these unknown attributes in the filter, or add the schema ++to the server and make sure it's properly indexed.""" ++} +-- +2.26.2 + diff --git a/SOURCES/0018-Ticket-50727-change-syntax-validate-by-default-in-1..patch b/SOURCES/0018-Ticket-50727-change-syntax-validate-by-default-in-1..patch deleted file mode 100644 index 1bfae46..0000000 --- a/SOURCES/0018-Ticket-50727-change-syntax-validate-by-default-in-1..patch +++ /dev/null @@ -1,57 +0,0 @@ -From 961d91d16f26f03812c83143cbb7dc3e37677bf6 Mon Sep 17 00:00:00 2001 -From: William Brown -Date: Wed, 18 Dec 2019 13:14:24 +1000 -Subject: [PATCH 1/2] Ticket 50727 - change syntax validate by default in 1.4.2 - -Bug Description: The default syntax validate for 1.4.2 should be changed to -a softer introduction so that admins have time to prepare for the change -of query behaviour in 1.4.3. - -Fix Description: Change default in 1.4.2 to warn-invalid, 1.4.3 will -remain as process-safe. - -https://pagure.io/389-ds-base/issue/50727 - -Author: William Brown - -Review by: tbordaz (Thanks) ---- - ldap/servers/slapd/libglobs.c | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c -index db61ee0b8..b9cdb6b37 100644 ---- a/ldap/servers/slapd/libglobs.c -+++ b/ldap/servers/slapd/libglobs.c -@@ -1783,7 +1783,7 @@ FrontendConfig_init(void) - * scheme set in cn=config - */ - init_enable_upgrade_hash = cfg->enable_upgrade_hash = LDAP_ON; -- init_verify_filter_schema = cfg->verify_filter_schema = SLAPI_WARN; -+ init_verify_filter_schema = cfg->verify_filter_schema = SLAPI_WARN_UNSAFE; - - /* Done, unlock! */ - CFG_UNLOCK_WRITE(cfg); -@@ -7689,7 +7689,7 @@ config_set_onoffwarn(slapdFrontendConfig_t *slapdFrontendConfig, slapi_onwarnoff - return LDAP_OPERATIONS_ERROR; - } - -- slapi_onwarnoff_t p_val = SLAPI_OFF; -+ slapi_special_filter_verify_t p_val = SLAPI_WARN_UNSAFE; - - if (strcasecmp(value, "on") == 0) { - p_val = SLAPI_ON; -@@ -8033,8 +8033,8 @@ config_set_value( - } else if (*((slapi_onwarnoff_t *)value) == SLAPI_WARN) { - slapi_entry_attr_set_charptr(e, cgas->attr_name, "warn"); - } else { -- slapi_entry_attr_set_charptr(e, cgas->attr_name, "off"); -- /* Default to off. */ -+ /* Default to safe warn-proccess-safely */ -+ slapi_entry_attr_set_charptr(e, cgas->attr_name, "warn-invalid"); - } - - break; --- -2.21.1 - diff --git a/SOURCES/0019-Issue-51144-dsctl-fails-with-instance-names-that-con.patch b/SOURCES/0019-Issue-51144-dsctl-fails-with-instance-names-that-con.patch new file mode 100644 index 0000000..d2663da --- /dev/null +++ b/SOURCES/0019-Issue-51144-dsctl-fails-with-instance-names-that-con.patch @@ -0,0 +1,51 @@ +From 2844d4ad90cbbd23ae75309e50ae4d7145586bb7 Mon Sep 17 00:00:00 2001 +From: Mark Reynolds +Date: Wed, 10 Jun 2020 14:07:24 -0400 +Subject: [PATCH] Issue 51144 - dsctl fails with instance names that contain + slapd- + +Bug Description: If an instance name contains 'slapd-' the CLI breaks: + + slapd-test-slapd + +Fix Description: Only strip off "slapd-" from the front of the instance + name. + +relates: https://pagure.io/389-ds-base/issue/51144 + +Reviewed by: firstyear(Thanks!) +--- + src/lib389/lib389/__init__.py | 2 +- + src/lib389/lib389/dseldif.py | 3 ++- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/lib389/lib389/__init__.py b/src/lib389/lib389/__init__.py +index 0ff1ab173..63d44b60a 100644 +--- a/src/lib389/lib389/__init__.py ++++ b/src/lib389/lib389/__init__.py +@@ -710,7 +710,7 @@ class DirSrv(SimpleLDAPObject, object): + # Don't need a default value now since it's set in init. + if serverid is None and hasattr(self, 'serverid'): + serverid = self.serverid +- elif serverid is not None: ++ elif serverid is not None and serverid.startswith('slapd-'): + serverid = serverid.replace('slapd-', '', 1) + + if self.serverid is None: +diff --git a/src/lib389/lib389/dseldif.py b/src/lib389/lib389/dseldif.py +index 96c9af9d1..f2725add9 100644 +--- a/src/lib389/lib389/dseldif.py ++++ b/src/lib389/lib389/dseldif.py +@@ -40,7 +40,8 @@ class DSEldif(DSLint): + if serverid: + # Get the dse.ldif from the instance name + prefix = os.environ.get('PREFIX', ""), +- serverid = serverid.replace("slapd-", "") ++ if serverid.startswith("slapd-"): ++ serverid = serverid.replace("slapd-", "", 1) + self.path = "{}/etc/dirsrv/slapd-{}/dse.ldif".format(prefix[0], serverid) + else: + ds_paths = Paths(self._instance.serverid, self._instance) +-- +2.26.2 + diff --git a/SOURCES/0019-Ticket-50727-correct-mistaken-options-in-filter-vali.patch b/SOURCES/0019-Ticket-50727-correct-mistaken-options-in-filter-vali.patch deleted file mode 100644 index 4e038ba..0000000 --- a/SOURCES/0019-Ticket-50727-correct-mistaken-options-in-filter-vali.patch +++ /dev/null @@ -1,730 +0,0 @@ -From 918df0a60a9cf1e3a836165f1044ea63c88bdd72 Mon Sep 17 00:00:00 2001 -From: William Brown -Date: Fri, 6 Dec 2019 14:04:45 +1000 -Subject: [PATCH] Ticket 50727 - correct mistaken options in filter validation - patch - -Bug Description: Because William of the past missed (forgot) to make -some agreed upon changes, we shipped the feature for filter validation -in a state that was a bit unclear for users. - -Fix Description: Fix the options to now be clearer in what is -expected/demaned from admins. We now have 4 possible states for -the value of the config: - -* reject-invalid (prev on) -* process-safe (prev warn) -* warn-invalid (new!) -* off (prev off) - -These behave as: - -* reject-invalid - reject queries that contain unknown attributes -* process-safe - log a notes=F that an attr is missing, and idl_alloc(0) - the missing attribute for RFC4511 compliance. -* warn-invalid - log a notes=F that an attr is missing, and process - as ALLIDS (the legacy behaviour) -* off - process as ALLIDs (the legacy behaviour) - -The default is "process-safe". - -https://pagure.io/389-ds-base/issue/50727 - -Author: William Brown - -Review by: tbordaz, lkrispen (thanks) ---- - .../suites/filter/schema_validation_test.py | 112 ++++++++++++++++-- - ldap/servers/slapd/back-ldbm/filterindex.c | 28 +++-- - ldap/servers/slapd/libglobs.c | 78 +++++++----- - ldap/servers/slapd/schema.c | 26 ++-- - ldap/servers/slapd/slap.h | 21 ++-- - ldap/servers/slapd/slapi-plugin.h | 1 + - ldap/servers/slapd/slapi-private.h | 3 +- - src/lib389/lib389/extensibleobject.py | 53 +++++++++ - 8 files changed, 258 insertions(+), 64 deletions(-) - create mode 100644 src/lib389/lib389/extensibleobject.py - -diff --git a/dirsrvtests/tests/suites/filter/schema_validation_test.py b/dirsrvtests/tests/suites/filter/schema_validation_test.py -index 4ac9fa8ff..d0d67ca95 100644 ---- a/dirsrvtests/tests/suites/filter/schema_validation_test.py -+++ b/dirsrvtests/tests/suites/filter/schema_validation_test.py -@@ -9,14 +9,29 @@ - - import pytest - import ldap --from lib389.topologies import topology_st -+from lib389.topologies import topology_st as topology_st_pre - from lib389.dirsrv_log import DirsrvAccessLog - from lib389._mapped_object import DSLdapObjects - from lib389._constants import DEFAULT_SUFFIX -+from lib389.extensibleobject import UnsafeExtensibleObjects - --def _check_value(inst_cfg, value): -+def _check_value(inst_cfg, value, exvalue=None): -+ if exvalue is None: -+ exvalue = value - inst_cfg.set('nsslapd-verify-filter-schema', value) -- assert(inst_cfg.get_attr_val_utf8('nsslapd-verify-filter-schema') == value) -+ assert(inst_cfg.get_attr_val_utf8('nsslapd-verify-filter-schema') == exvalue) -+ -+@pytest.fixture(scope="module") -+def topology_st(topology_st_pre): -+ raw_objects = UnsafeExtensibleObjects(topology_st_pre.standalone, basedn=DEFAULT_SUFFIX) -+ # Add an object that won't be able to be queried due to invalid attrs. -+ raw_objects.create(properties = { -+ "cn": "test_obj", -+ "a": "a", -+ "b": "b", -+ "uid": "foo" -+ }) -+ return topology_st_pre - - - @pytest.mark.ds50349 -@@ -51,8 +66,14 @@ def test_filter_validation_config(topology_st): - - initial_value = inst_cfg.get_attr_val_utf8('nsslapd-verify-filter-schema') - -- _check_value(inst_cfg, "on") -- _check_value(inst_cfg, "warn") -+ # Check legacy values that may have been set -+ _check_value(inst_cfg, "on", "reject-invalid") -+ _check_value(inst_cfg, "warn", "process-safe") -+ _check_value(inst_cfg, "off") -+ # Check the more descriptive values -+ _check_value(inst_cfg, "reject-invalid") -+ _check_value(inst_cfg, "process-safe") -+ _check_value(inst_cfg, "warn-invalid") - _check_value(inst_cfg, "off") - - # This should fail -@@ -85,7 +106,7 @@ def test_filter_validation_enabled(topology_st): - inst = topology_st.standalone - - # In case the default has changed, we set the value to warn. -- inst.config.set("nsslapd-verify-filter-schema", "on") -+ inst.config.set("nsslapd-verify-filter-schema", "reject-invalid") - raw_objects = DSLdapObjects(inst, basedn=DEFAULT_SUFFIX) - - # Check a good query has no errors. -@@ -104,9 +125,9 @@ def test_filter_validation_enabled(topology_st): - - - @pytest.mark.ds50349 --def test_filter_validation_warning(topology_st): -+def test_filter_validation_warn_safe(topology_st): - """Test that queries which are invalid, are correctly marked as "notes=F" in -- the access log. -+ the access log, and return no entries or partial sets. - - :id: 8b2b23fe-d878-435c-bc84-8c298be4ca1f - :setup: Standalone instance -@@ -122,7 +143,7 @@ def test_filter_validation_warning(topology_st): - inst = topology_st.standalone - - # In case the default has changed, we set the value to warn. -- inst.config.set("nsslapd-verify-filter-schema", "warn") -+ inst.config.set("nsslapd-verify-filter-schema", "process-safe") - # Set the access log to un-buffered so we get it immediately. - inst.config.set("nsslapd-accesslog-logbuffering", "off") - -@@ -139,20 +160,93 @@ def test_filter_validation_warning(topology_st): - - # Check a good query has no warnings. - r = raw_objects.filter("(objectClass=*)") -+ assert(len(r) > 0) - r_s1 = access_log.match(".*notes=F.*") - # Should be the same number of log lines IE 0. - assert(len(r_init) == len(r_s1)) - - # Check a bad one DOES emit a warning. - r = raw_objects.filter("(a=a)") -+ assert(len(r) == 0) - r_s2 = access_log.match(".*notes=F.*") - # Should be the greate number of log lines IE +1 - assert(len(r_init) + 1 == len(r_s2)) - - # Check a bad complex one does emit a warning. - r = raw_objects.filter("(&(a=a)(b=b)(objectClass=*))") -+ assert(len(r) == 0) - r_s3 = access_log.match(".*notes=F.*") - # Should be the greate number of log lines IE +2 - assert(len(r_init) + 2 == len(r_s3)) - -+ # Check that we can still get things when partial -+ r = raw_objects.filter("(|(a=a)(b=b)(uid=foo))") -+ assert(len(r) == 1) -+ r_s4 = access_log.match(".*notes=F.*") -+ # Should be the greate number of log lines IE +2 -+ assert(len(r_init) + 3 == len(r_s4)) -+ -+ -+@pytest.mark.ds50349 -+def test_filter_validation_warn_unsafe(topology_st): -+ """Test that queries which are invalid, are correctly marked as "notes=F" in -+ the access log, and uses the legacy query behaviour to return unsafe sets. -+ -+ :id: 8b2b23fe-d878-435c-bc84-8c298be4ca1f -+ :setup: Standalone instance -+ :steps: -+ 1. Search a well formed query -+ 2. Search a poorly formed query -+ 3. Search a poorly formed complex (and/or) query -+ :expectedresults: -+ 1. No warnings -+ 2. notes=F is present -+ 3. notes=F is present -+ """ -+ inst = topology_st.standalone -+ -+ # In case the default has changed, we set the value to warn. -+ inst.config.set("nsslapd-verify-filter-schema", "warn-invalid") -+ # Set the access log to un-buffered so we get it immediately. -+ inst.config.set("nsslapd-accesslog-logbuffering", "off") -+ -+ # Setup the query object. -+ # Now we don't care if there are any results, we only care about good/bad queries. -+ # To do this we have to bypass some of the lib389 magic, and just emit raw queries -+ # to check them. Turns out lib389 is well designed and this just works as expected -+ # if you use a single DSLdapObjects and filter. :) -+ raw_objects = DSLdapObjects(inst, basedn=DEFAULT_SUFFIX) -+ -+ # Find any initial notes=F -+ access_log = DirsrvAccessLog(inst) -+ r_init = access_log.match(".*notes=(U,)?F.*") -+ -+ # Check a good query has no warnings. -+ r = raw_objects.filter("(objectClass=*)") -+ assert(len(r) > 0) -+ r_s1 = access_log.match(".*notes=(U,)?F.*") -+ # Should be the same number of log lines IE 0. -+ assert(len(r_init) == len(r_s1)) -+ -+ # Check a bad one DOES emit a warning. -+ r = raw_objects.filter("(a=a)") -+ assert(len(r) == 1) -+ # NOTE: Unlike warn-process-safely, these become UNINDEXED and show in the logs. -+ r_s2 = access_log.match(".*notes=(U,)?F.*") -+ # Should be the greate number of log lines IE +1 -+ assert(len(r_init) + 1 == len(r_s2)) -+ -+ # Check a bad complex one does emit a warning. -+ r = raw_objects.filter("(&(a=a)(b=b)(objectClass=*))") -+ assert(len(r) == 1) -+ r_s3 = access_log.match(".*notes=(U,)?F.*") -+ # Should be the greate number of log lines IE +2 -+ assert(len(r_init) + 2 == len(r_s3)) -+ -+ # Check that we can still get things when partial -+ r = raw_objects.filter("(|(a=a)(b=b)(uid=foo))") -+ assert(len(r) == 1) -+ r_s4 = access_log.match(".*notes=(U,)?F.*") -+ # Should be the greate number of log lines IE +2 -+ assert(len(r_init) + 3 == len(r_s4)) - -diff --git a/ldap/servers/slapd/back-ldbm/filterindex.c b/ldap/servers/slapd/back-ldbm/filterindex.c -index 7e65f73ca..8a79848c3 100644 ---- a/ldap/servers/slapd/back-ldbm/filterindex.c -+++ b/ldap/servers/slapd/back-ldbm/filterindex.c -@@ -223,13 +223,15 @@ ava_candidates( - - switch (ftype) { - case LDAP_FILTER_GE: -- if (f->f_flags & SLAPI_FILTER_INVALID_ATTR) { -+ if (f->f_flags & SLAPI_FILTER_INVALID_ATTR_WARN) { - /* - * REMEMBER: this flag is only set on WARN levels. If the filter verify - * is on strict, we reject in search.c, if we ar off, the flag will NOT - * be set on the filter at all! - */ - slapi_pblock_set_flag_operation_notes(pb, SLAPI_OP_NOTE_FILTER_INVALID); -+ } -+ if (f->f_flags & SLAPI_FILTER_INVALID_ATTR_UNDEFINE) { - idl = idl_alloc(0); - } else { - idl = range_candidates(pb, be, type, bval, NULL, err, &sattr, allidslimit); -@@ -239,13 +241,15 @@ ava_candidates( - goto done; - break; - case LDAP_FILTER_LE: -- if (f->f_flags & SLAPI_FILTER_INVALID_ATTR) { -+ if (f->f_flags & SLAPI_FILTER_INVALID_ATTR_WARN) { - /* - * REMEMBER: this flag is only set on WARN levels. If the filter verify - * is on strict, we reject in search.c, if we ar off, the flag will NOT - * be set on the filter at all! - */ - slapi_pblock_set_flag_operation_notes(pb, SLAPI_OP_NOTE_FILTER_INVALID); -+ } -+ if (f->f_flags & SLAPI_FILTER_INVALID_ATTR_UNDEFINE) { - idl = idl_alloc(0); - } else { - idl = range_candidates(pb, be, type, NULL, bval, err, &sattr, allidslimit); -@@ -293,13 +297,15 @@ ava_candidates( - ptr[1] = NULL; - ivals = ptr; - -- if (f->f_flags & SLAPI_FILTER_INVALID_ATTR) { -+ if (f->f_flags & SLAPI_FILTER_INVALID_ATTR_WARN) { - /* - * REMEMBER: this flag is only set on WARN levels. If the filter verify - * is on strict, we reject in search.c, if we ar off, the flag will NOT - * be set on the filter at all! - */ - slapi_pblock_set_flag_operation_notes(pb, SLAPI_OP_NOTE_FILTER_INVALID); -+ } -+ if (f->f_flags & SLAPI_FILTER_INVALID_ATTR_UNDEFINE) { - idl = idl_alloc(0); - } else { - slapi_attr_assertion2keys_ava_sv(&sattr, &tmp, (Slapi_Value ***)&ivals, LDAP_FILTER_EQUALITY_FAST); -@@ -326,13 +332,15 @@ ava_candidates( - slapi_ch_free((void **)&ivals); - } - } else { -- if (f->f_flags & SLAPI_FILTER_INVALID_ATTR) { -+ if (f->f_flags & SLAPI_FILTER_INVALID_ATTR_WARN) { - /* - * REMEMBER: this flag is only set on WARN levels. If the filter verify - * is on strict, we reject in search.c, if we ar off, the flag will NOT - * be set on the filter at all! - */ - slapi_pblock_set_flag_operation_notes(pb, SLAPI_OP_NOTE_FILTER_INVALID); -+ } -+ if (f->f_flags & SLAPI_FILTER_INVALID_ATTR_UNDEFINE) { - idl = idl_alloc(0); - } else { - slapi_value_init_berval(&sv, bval); -@@ -382,13 +390,15 @@ presence_candidates( - } - slapi_pblock_get(pb, SLAPI_TXN, &txn.back_txn_txn); - -- if (f->f_flags & SLAPI_FILTER_INVALID_ATTR) { -+ if (f->f_flags & SLAPI_FILTER_INVALID_ATTR_WARN) { - /* - * REMEMBER: this flag is only set on WARN levels. If the filter verify - * is on strict, we reject in search.c, if we ar off, the flag will NOT - * be set on the filter at all! - */ - slapi_pblock_set_flag_operation_notes(pb, SLAPI_OP_NOTE_FILTER_INVALID); -+ } -+ if (f->f_flags & SLAPI_FILTER_INVALID_ATTR_UNDEFINE) { - idl = idl_alloc(0); - } else { - idl = index_read_ext_allids(pb, be, type, indextype_PRESENCE, -@@ -485,13 +495,15 @@ extensible_candidates( - slapi_pblock_get(pb, SLAPI_PLUGIN_MR_KEYS, &keys)) { - /* something went wrong. bail. */ - break; -- } else if (f->f_flags & SLAPI_FILTER_INVALID_ATTR) { -+ } else if (f->f_flags & SLAPI_FILTER_INVALID_ATTR_WARN) { - /* - * REMEMBER: this flag is only set on WARN levels. If the filter verify - * is on strict, we reject in search.c, if we ar off, the flag will NOT - * be set on the filter at all! - */ - slapi_pblock_set_flag_operation_notes(pb, SLAPI_OP_NOTE_FILTER_INVALID); -+ } -+ if (f->f_flags & SLAPI_FILTER_INVALID_ATTR_UNDEFINE) { - idl = idl_alloc(0); - } else if (keys == NULL || keys[0] == NULL) { - /* no keys */ -@@ -986,13 +998,15 @@ substring_candidates( - * look up each key in the index, ANDing the resulting - * IDLists together. - */ -- if (f->f_flags & SLAPI_FILTER_INVALID_ATTR) { -+ if (f->f_flags & SLAPI_FILTER_INVALID_ATTR_WARN) { - /* - * REMEMBER: this flag is only set on WARN levels. If the filter verify - * is on strict, we reject in search.c, if we ar off, the flag will NOT - * be set on the filter at all! - */ - slapi_pblock_set_flag_operation_notes(pb, SLAPI_OP_NOTE_FILTER_INVALID); -+ } -+ if (f->f_flags & SLAPI_FILTER_INVALID_ATTR_UNDEFINE) { - idl = idl_alloc(0); - } else { - slapi_pblock_get(pb, SLAPI_TXN, &txn.back_txn_txn); -diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c -index b9cdb6b37..66170ebc6 100644 ---- a/ldap/servers/slapd/libglobs.c -+++ b/ldap/servers/slapd/libglobs.c -@@ -166,7 +166,7 @@ typedef enum { - CONFIG_SPECIAL_VALIDATE_CERT_SWITCH, /* maps strings to an enumeration */ - CONFIG_SPECIAL_UNHASHED_PW_SWITCH, /* unhashed pw: on/off/nolog */ - CONFIG_SPECIAL_TLS_CHECK_CRL, /* maps enum tls_check_crl_t to char * */ -- CONFIG_ON_OFF_WARN, /* maps to a config on/warn/off enum */ -+ CONFIG_SPECIAL_FILTER_VERIFY, /* maps to a config strict/warn-strict/warn/off enum */ - } ConfigVarType; - - static int32_t config_set_onoff(const char *attrname, char *value, int32_t *configvalue, char *errorbuf, int apply); -@@ -256,7 +256,7 @@ slapi_int_t init_malloc_mmap_threshold; - slapi_onoff_t init_extract_pem; - slapi_onoff_t init_ignore_vattrs; - slapi_onoff_t init_enable_upgrade_hash; --slapi_onwarnoff_t init_verify_filter_schema; -+slapi_special_filter_verify_t init_verify_filter_schema; - - static int - isInt(ConfigVarType type) -@@ -1248,7 +1248,7 @@ static struct config_get_and_set - {CONFIG_VERIFY_FILTER_SCHEMA, config_set_verify_filter_schema, - NULL, 0, - (void **)&global_slapdFrontendConfig.verify_filter_schema, -- CONFIG_ON_OFF_WARN, (ConfigGetFunc)config_get_verify_filter_schema, -+ CONFIG_SPECIAL_FILTER_VERIFY, (ConfigGetFunc)config_get_verify_filter_schema, - &init_verify_filter_schema}, - /* End config */ - }; -@@ -7659,18 +7659,21 @@ config_initvalue_to_onoff(struct config_get_and_set *cgas, char *initvalbuf, siz - } - - static char * --config_initvalue_to_onwarnoff(struct config_get_and_set *cgas, char *initvalbuf, size_t initvalbufsize) { -+config_initvalue_to_special_filter_verify(struct config_get_and_set *cgas, char *initvalbuf, size_t initvalbufsize) { - char *retval = NULL; -- if (cgas->config_var_type == CONFIG_ON_OFF_WARN) { -- slapi_onwarnoff_t *value = (slapi_onwarnoff_t *)(intptr_t)cgas->initvalue; -+ if (cgas->config_var_type == CONFIG_SPECIAL_FILTER_VERIFY) { -+ slapi_special_filter_verify_t *value = (slapi_special_filter_verify_t *)(intptr_t)cgas->initvalue; - if (value != NULL) { -- if (*value == SLAPI_ON) { -- PR_snprintf(initvalbuf, initvalbufsize, "%s", "on"); -+ if (*value == SLAPI_STRICT) { -+ PR_snprintf(initvalbuf, initvalbufsize, "%s", "reject-invalid"); - retval = initvalbuf; -- } else if (*value == SLAPI_WARN) { -- PR_snprintf(initvalbuf, initvalbufsize, "%s", "warn"); -+ } else if (*value == SLAPI_WARN_SAFE) { -+ PR_snprintf(initvalbuf, initvalbufsize, "%s", "process-safe"); - retval = initvalbuf; -- } else if (*value == SLAPI_OFF) { -+ } else if (*value == SLAPI_WARN_UNSAFE) { -+ PR_snprintf(initvalbuf, initvalbufsize, "%s", "warn-invalid"); -+ retval = initvalbuf; -+ } else if (*value == SLAPI_OFF_UNSAFE) { - PR_snprintf(initvalbuf, initvalbufsize, "%s", "off"); - retval = initvalbuf; - } -@@ -7680,7 +7683,7 @@ config_initvalue_to_onwarnoff(struct config_get_and_set *cgas, char *initvalbuf, - } - - static int32_t --config_set_onoffwarn(slapdFrontendConfig_t *slapdFrontendConfig, slapi_onwarnoff_t *target, const char *attrname, char *value, char *errorbuf, int apply) { -+config_set_specialfilterverify(slapdFrontendConfig_t *slapdFrontendConfig, slapi_special_filter_verify_t *target, const char *attrname, char *value, char *errorbuf, int apply) { - if (target == NULL) { - return LDAP_OPERATIONS_ERROR; - } -@@ -7691,15 +7694,23 @@ config_set_onoffwarn(slapdFrontendConfig_t *slapdFrontendConfig, slapi_onwarnoff - - slapi_special_filter_verify_t p_val = SLAPI_WARN_UNSAFE; - -+ /* on/warn/off retained for legacy reasons due to wbrown making terrible mistakes :( :( */ - if (strcasecmp(value, "on") == 0) { -- p_val = SLAPI_ON; -+ p_val = SLAPI_STRICT; - } else if (strcasecmp(value, "warn") == 0) { -- p_val = SLAPI_WARN; -+ p_val = SLAPI_WARN_SAFE; -+ /* The new fixed/descriptive names */ -+ } else if (strcasecmp(value, "reject-invalid") == 0) { -+ p_val = SLAPI_STRICT; -+ } else if (strcasecmp(value, "process-safe") == 0) { -+ p_val = SLAPI_WARN_SAFE; -+ } else if (strcasecmp(value, "warn-invalid") == 0) { -+ p_val = SLAPI_WARN_UNSAFE; - } else if (strcasecmp(value, "off") == 0) { -- p_val = SLAPI_OFF; -+ p_val = SLAPI_OFF_UNSAFE; - } else { - slapi_create_errormsg(errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, -- "%s: invalid value \"%s\". Valid values are \"on\", \"warn\" or \"off\".", attrname, value); -+ "%s: invalid value \"%s\". Valid values are \"reject-invalid\", \"process-safe\", \"warn-invalid\" or \"off\". If in doubt, choose \"process-safe\"", attrname, value); - return LDAP_OPERATIONS_ERROR; - } - -@@ -7718,14 +7729,14 @@ config_set_onoffwarn(slapdFrontendConfig_t *slapdFrontendConfig, slapi_onwarnoff - int32_t - config_set_verify_filter_schema(const char *attrname, char *value, char *errorbuf, int apply) { - slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); -- slapi_onwarnoff_t *target = &(slapdFrontendConfig->verify_filter_schema); -- return config_set_onoffwarn(slapdFrontendConfig, target, attrname, value, errorbuf, apply); -+ slapi_special_filter_verify_t *target = &(slapdFrontendConfig->verify_filter_schema); -+ return config_set_specialfilterverify(slapdFrontendConfig, target, attrname, value, errorbuf, apply); - } - - Slapi_Filter_Policy - config_get_verify_filter_schema() - { -- slapi_onwarnoff_t retVal; -+ slapi_special_filter_verify_t retVal; - slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); - CFG_LOCK_READ(slapdFrontendConfig); - retVal = slapdFrontendConfig->verify_filter_schema; -@@ -7733,10 +7744,13 @@ config_get_verify_filter_schema() - - /* Now map this to a policy that the fns understand. */ - switch (retVal) { -- case SLAPI_ON: -+ case SLAPI_STRICT: - return FILTER_POLICY_STRICT; - break; -- case SLAPI_WARN: -+ case SLAPI_WARN_SAFE: -+ return FILTER_POLICY_PROTECT; -+ break; -+ case SLAPI_WARN_UNSAFE: - return FILTER_POLICY_WARNING; - break; - default: -@@ -7794,8 +7808,8 @@ config_set(const char *attr, struct berval **values, char *errorbuf, int apply) - void *initval = cgas->initvalue; - if (cgas->config_var_type == CONFIG_ON_OFF) { - initval = (void *)config_initvalue_to_onoff(cgas, initvalbuf, sizeof(initvalbuf)); -- } else if (cgas->config_var_type == CONFIG_ON_OFF_WARN) { -- initval = (void *)config_initvalue_to_onwarnoff(cgas, initvalbuf, sizeof(initvalbuf)); -+ } else if (cgas->config_var_type == CONFIG_SPECIAL_FILTER_VERIFY) { -+ initval = (void *)config_initvalue_to_special_filter_verify(cgas, initvalbuf, sizeof(initvalbuf)); - } - if (cgas->setfunc) { - retval = (cgas->setfunc)(cgas->attr_name, initval, errorbuf, apply); -@@ -8021,20 +8035,24 @@ config_set_value( - - break; - -- case CONFIG_ON_OFF_WARN: -+ case CONFIG_SPECIAL_FILTER_VERIFY: - /* Is this the right default here? */ - if (!value) { -- slapi_entry_attr_set_charptr(e, cgas->attr_name, "off"); -+ slapi_entry_attr_set_charptr(e, cgas->attr_name, "process-safe"); - break; - } - -- if (*((slapi_onwarnoff_t *)value) == SLAPI_ON) { -- slapi_entry_attr_set_charptr(e, cgas->attr_name, "on"); -- } else if (*((slapi_onwarnoff_t *)value) == SLAPI_WARN) { -- slapi_entry_attr_set_charptr(e, cgas->attr_name, "warn"); -+ if (*((slapi_special_filter_verify_t *)value) == SLAPI_STRICT) { -+ slapi_entry_attr_set_charptr(e, cgas->attr_name, "reject-invalid"); -+ } else if (*((slapi_special_filter_verify_t *)value) == SLAPI_WARN_SAFE) { -+ slapi_entry_attr_set_charptr(e, cgas->attr_name, "process-safe"); -+ } else if (*((slapi_special_filter_verify_t *)value) == SLAPI_WARN_UNSAFE) { -+ slapi_entry_attr_set_charptr(e, cgas->attr_name, "warn-invalid"); -+ } else if (*((slapi_special_filter_verify_t *)value) == SLAPI_OFF_UNSAFE) { -+ slapi_entry_attr_set_charptr(e, cgas->attr_name, "off"); - } else { - /* Default to safe warn-proccess-safely */ -- slapi_entry_attr_set_charptr(e, cgas->attr_name, "warn-invalid"); -+ slapi_entry_attr_set_charptr(e, cgas->attr_name, "process-safe"); - } - - break; -diff --git a/ldap/servers/slapd/schema.c b/ldap/servers/slapd/schema.c -index 6e853fc7c..d7c3c139e 100644 ---- a/ldap/servers/slapd/schema.c -+++ b/ldap/servers/slapd/schema.c -@@ -698,7 +698,7 @@ out: - } - - static Slapi_Filter_Result --slapi_filter_schema_check_inner(Slapi_Filter *f) { -+slapi_filter_schema_check_inner(Slapi_Filter *f, slapi_filter_flags flags) { - /* - * Default response to Ok. If any more severe things happen we - * alter this to reflect it. IE we bubble up more severe errors -@@ -712,26 +712,26 @@ slapi_filter_schema_check_inner(Slapi_Filter *f) { - case LDAP_FILTER_LE: - case LDAP_FILTER_APPROX: - if (!attr_syntax_exist_by_name_nolock(f->f_avtype)) { -- f->f_flags |= SLAPI_FILTER_INVALID_ATTR; -+ f->f_flags |= flags; - r = FILTER_SCHEMA_WARNING; - } - break; - case LDAP_FILTER_PRESENT: - if (!attr_syntax_exist_by_name_nolock(f->f_type)) { -- f->f_flags |= SLAPI_FILTER_INVALID_ATTR; -+ f->f_flags |= flags; - r = FILTER_SCHEMA_WARNING; - } - break; - case LDAP_FILTER_SUBSTRINGS: - if (!attr_syntax_exist_by_name_nolock(f->f_sub_type)) { -- f->f_flags |= SLAPI_FILTER_INVALID_ATTR; -+ f->f_flags |= flags; - r = FILTER_SCHEMA_WARNING; - } - break; - case LDAP_FILTER_EXTENDED: - /* I don't have any examples of this, so I'm not 100% on how to check it */ - if (!attr_syntax_exist_by_name_nolock(f->f_mr_type)) { -- f->f_flags |= SLAPI_FILTER_INVALID_ATTR; -+ f->f_flags |= flags; - r = FILTER_SCHEMA_WARNING; - } - break; -@@ -740,7 +740,7 @@ slapi_filter_schema_check_inner(Slapi_Filter *f) { - case LDAP_FILTER_NOT: - /* Recurse and check all elemments of the filter */ - for (Slapi_Filter *f_child = f->f_list; f_child != NULL; f_child = f_child->f_next) { -- Slapi_Filter_Result ri = slapi_filter_schema_check_inner(f_child); -+ Slapi_Filter_Result ri = slapi_filter_schema_check_inner(f_child, flags); - if (ri > r) { - r = ri; - } -@@ -769,12 +769,24 @@ slapi_filter_schema_check(Slapi_Filter *f, Slapi_Filter_Policy fp) { - return FILTER_SCHEMA_SUCCESS; - } - -+ /* -+ * There are two possible warning types - it's not up to us to warn into -+ * the logs, that's the backends job. So we have to flag a hint into the -+ * filter about what it should do. This is why there are two FILTER_INVALID -+ * types in filter_flags, one for logging it, and one for actually doing -+ * the rejection. -+ */ -+ slapi_filter_flags flags = SLAPI_FILTER_INVALID_ATTR_WARN; -+ if (fp == FILTER_POLICY_PROTECT) { -+ flags |= SLAPI_FILTER_INVALID_ATTR_UNDEFINE; -+ } -+ - /* - * Filters are nested, recursive structures, so we actually have to call an inner - * function until we have a result! - */ - attr_syntax_read_lock(); -- Slapi_Filter_Result r = slapi_filter_schema_check_inner(f); -+ Slapi_Filter_Result r = slapi_filter_schema_check_inner(f, flags); - attr_syntax_unlock_read(); - - /* If any warning occured, ensure we fail it. */ -diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h -index 8a2748519..d73e9aaae 100644 ---- a/ldap/servers/slapd/slap.h -+++ b/ldap/servers/slapd/slap.h -@@ -457,12 +457,12 @@ typedef enum _tls_check_crl_t { - TLS_CHECK_ALL = 2, - } tls_check_crl_t; - --typedef enum _slapi_onwarnoff_t { -- SLAPI_OFF = 0, -- SLAPI_WARN = 1, -- SLAPI_ON = 2, --} slapi_onwarnoff_t; -- -+typedef enum _slapi_special_filter_verify_t { -+ SLAPI_STRICT = 0, -+ SLAPI_WARN_SAFE = 1, -+ SLAPI_WARN_UNSAFE = 2, -+ SLAPI_OFF_UNSAFE = 3, -+} slapi_special_filter_verify_t; - - struct subfilt - { -@@ -2547,11 +2547,12 @@ typedef struct _slapdFrontendConfig - slapi_onoff_t enable_upgrade_hash; /* If on, upgrade hashes for PW at bind */ - /* - * Do we verify the filters we recieve by schema? -- * on - yes, and reject if attribute not found -- * warn - yes, and warn that the attribute is unknown and unindexed -- * off - no, do whatever (old status-quo) -+ * reject-invalid - reject filter if there is anything invalid -+ * process-safe - allow the filter, warn about what's invalid, and then idl_alloc(0) with rfc compliance -+ * warn-invalid - allow the filter, warn about the invalid, and then do a ALLIDS (may lead to full table scan) -+ * off - don't warn, just allow anything. This is the legacy behaviour. - */ -- slapi_onwarnoff_t verify_filter_schema; -+ slapi_special_filter_verify_t verify_filter_schema; - } slapdFrontendConfig_t; - - /* possible values for slapdFrontendConfig_t.schemareplace */ -diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h -index 50b8d12c8..40b5c911a 100644 ---- a/ldap/servers/slapd/slapi-plugin.h -+++ b/ldap/servers/slapd/slapi-plugin.h -@@ -1571,6 +1571,7 @@ int slapi_entry_syntax_check(Slapi_PBlock *pb, Slapi_Entry *e, int override); - typedef enum { - FILTER_POLICY_OFF, - FILTER_POLICY_WARNING, -+ FILTER_POLICY_PROTECT, - FILTER_POLICY_STRICT, - } Slapi_Filter_Policy; - -diff --git a/ldap/servers/slapd/slapi-private.h b/ldap/servers/slapd/slapi-private.h -index 04c045532..1f17eda12 100644 ---- a/ldap/servers/slapd/slapi-private.h -+++ b/ldap/servers/slapd/slapi-private.h -@@ -54,7 +54,8 @@ typedef enum _slapi_filter_flags_t { - SLAPI_FILTER_RUV = 4, - SLAPI_FILTER_NORMALIZED_TYPE = 8, - SLAPI_FILTER_NORMALIZED_VALUE = 16, -- SLAPI_FILTER_INVALID_ATTR = 32, -+ SLAPI_FILTER_INVALID_ATTR_UNDEFINE = 32, -+ SLAPI_FILTER_INVALID_ATTR_WARN = 64, - } slapi_filter_flags; - - #define SLAPI_ENTRY_LDAPSUBENTRY 2 -diff --git a/src/lib389/lib389/extensibleobject.py b/src/lib389/lib389/extensibleobject.py -new file mode 100644 -index 000000000..8fe37f980 ---- /dev/null -+++ b/src/lib389/lib389/extensibleobject.py -@@ -0,0 +1,53 @@ -+# --- BEGIN COPYRIGHT BLOCK --- -+# Copyright (C) 2019, William Brown -+# All rights reserved. -+# -+# License: GPL (version 3 or any later version). -+# See LICENSE for details. -+# --- END COPYRIGHT BLOCK --- -+ -+from lib389._mapped_object import DSLdapObject, DSLdapObjects -+from lib389.utils import ensure_str -+ -+class UnsafeExtensibleObject(DSLdapObject): -+ """A single instance of an extensible object. Extensible object by it's -+ nature is unsafe, eliminating rules around attribute checking. It may -+ cause unsafe or other unknown behaviour if not handled correctly. -+ -+ :param instance: An instance -+ :type instance: lib389.DirSrv -+ :param dn: Entry DN -+ :type dn: str -+ """ -+ -+ def __init__(self, instance, dn=None): -+ super(UnsafeExtensibleObject, self).__init__(instance, dn) -+ self._rdn_attribute = "cn" -+ # Can I generate these from schema? -+ self._must_attributes = [] -+ self._create_objectclasses = [ -+ 'top', -+ 'extensibleObject', -+ ] -+ self._protected = False -+ -+class UnsafeExtensibleObjects(DSLdapObjects): -+ """DSLdapObjects that represents all extensible objects. Extensible Objects -+ are unsafe in their nature, disabling many checks around schema and attribute -+ handling. You should really really REALLY not use this unless you have specific -+ needs for testing. -+ -+ :param instance: An instance -+ :type instance: lib389.DirSrv -+ :param basedn: Base DN for all group entries below -+ :type basedn: str -+ """ -+ -+ def __init__(self, instance, basedn): -+ super(UnsafeExtensibleObjects, self).__init__(instance) -+ self._objectclasses = [ -+ 'extensibleObject', -+ ] -+ self._filterattrs = ["cn"] -+ self._childobject = UnsafeExtensibleObject -+ self._basedn = ensure_str(basedn) --- -2.21.1 - diff --git a/SOURCES/0020-Issue-50599-Fix-memory-leak-when-removing-db-region-.patch b/SOURCES/0020-Issue-50599-Fix-memory-leak-when-removing-db-region-.patch deleted file mode 100644 index 8c5f04a..0000000 --- a/SOURCES/0020-Issue-50599-Fix-memory-leak-when-removing-db-region-.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 0513da63603cfc5730d34cc10aaf3a23beec210c Mon Sep 17 00:00:00 2001 -From: Mark Reynolds -Date: Thu, 16 Jan 2020 15:11:34 -0500 -Subject: [PATCH] Issue 50599 - Fix memory leak when removing db region files - -Description: An unnecessary flag was set in glob() that was resulting - in a memory leak in the DS code. Removing this flag - eliminated the leak. - -relates: https://pagure.io/389-ds-base/issue/50599 - -Reviewed by: ---- - ldap/servers/slapd/back-ldbm/db-bdb/bdb_layer.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -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 2103dac38..5a6a2a2e5 100644 ---- a/ldap/servers/slapd/back-ldbm/db-bdb/bdb_layer.c -+++ b/ldap/servers/slapd/back-ldbm/db-bdb/bdb_layer.c -@@ -1072,7 +1072,7 @@ bdb_start(struct ldbminfo *li, int dbmode) - - /* Better wipe out the region files to help ensure a clean start */ - PR_snprintf(file_pattern, MAXPATHLEN, "%s/%s", region_dir, "__db.*"); -- if (glob(file_pattern, GLOB_DOOFFS, NULL, &globbuf) == 0) { -+ if (glob(file_pattern, 0, NULL, &globbuf) == 0) { - for (size_t i = 0; i < globbuf.gl_pathc; i++) { - remove(globbuf.gl_pathv[i]); - } --- -2.21.1 - diff --git a/SOURCES/0020-Ticket-49859-A-distinguished-value-can-be-missing-in.patch b/SOURCES/0020-Ticket-49859-A-distinguished-value-can-be-missing-in.patch new file mode 100644 index 0000000..8d25933 --- /dev/null +++ b/SOURCES/0020-Ticket-49859-A-distinguished-value-can-be-missing-in.patch @@ -0,0 +1,520 @@ +From 6cd4b1c60dbd3d7b74adb19a2434585d50553f39 Mon Sep 17 00:00:00 2001 +From: Thierry Bordaz +Date: Fri, 5 Jun 2020 12:14:51 +0200 +Subject: [PATCH] Ticket 49859 - A distinguished value can be missing in an + entry + +Bug description: + According to RFC 4511 (see ticket), the values of the RDN attributes + should be present in an entry. + With a set of replicated operations, it is possible that those values + would be missing + +Fix description: + MOD and MODRDN update checks that the RDN values are presents. + If they are missing they are added to the resulting entry. In addition + the set of modifications to add those values are also indexed. + The specific case of single-valued attributes, where the final and unique value + can not be the RDN value, the attribute nsds5ReplConflict is added. + +https://pagure.io/389-ds-base/issue/49859 + +Reviewed by: Mark Reynolds, William Brown + +Platforms tested: F31 +--- + .../replication/conflict_resolve_test.py | 174 +++++++++++++++++- + ldap/servers/slapd/back-ldbm/ldbm_modify.c | 136 ++++++++++++++ + ldap/servers/slapd/back-ldbm/ldbm_modrdn.c | 37 +++- + .../servers/slapd/back-ldbm/proto-back-ldbm.h | 1 + + 4 files changed, 343 insertions(+), 5 deletions(-) + +diff --git a/dirsrvtests/tests/suites/replication/conflict_resolve_test.py b/dirsrvtests/tests/suites/replication/conflict_resolve_test.py +index 99a072935..48d0067db 100644 +--- a/dirsrvtests/tests/suites/replication/conflict_resolve_test.py ++++ b/dirsrvtests/tests/suites/replication/conflict_resolve_test.py +@@ -10,10 +10,11 @@ import time + import logging + import ldap + import pytest ++import re + from itertools import permutations + from lib389._constants import * + from lib389.idm.nscontainer import nsContainers +-from lib389.idm.user import UserAccounts ++from lib389.idm.user import UserAccounts, UserAccount + from lib389.idm.group import Groups + from lib389.idm.organizationalunit import OrganizationalUnits + from lib389.replica import ReplicationManager +@@ -763,6 +764,177 @@ class TestTwoMasters: + user_dns_m2 = [user.dn for user in test_users_m2.list()] + assert set(user_dns_m1) == set(user_dns_m2) + ++ def test_conflict_attribute_multi_valued(self, topology_m2, base_m2): ++ """A RDN attribute being multi-valued, checks that after several operations ++ MODRDN and MOD_REPL its RDN values are the same on both servers ++ ++ :id: 225b3522-8ed7-4256-96f9-5fab9b7044a5 ++ :setup: Two master replication, ++ audit log, error log for replica and access log for internal ++ :steps: ++ 1. Create a test entry uid=user_test_1000,... ++ 2. Pause all replication agreements ++ 3. On M1 rename it into uid=foo1,... ++ 4. On M2 rename it into uid=foo2,... ++ 5. On M1 MOD_REPL uid:foo1 ++ 6. Resume all replication agreements ++ 7. Check that entry on M1 has uid=foo1, foo2 ++ 8. Check that entry on M2 has uid=foo1, foo2 ++ 9. Check that entry on M1 and M2 has the same uid values ++ :expectedresults: ++ 1. It should pass ++ 2. It should pass ++ 3. It should pass ++ 4. It should pass ++ 5. It should pass ++ 6. It should pass ++ 7. It should pass ++ 8. It should pass ++ 9. It should pass ++ """ ++ ++ M1 = topology_m2.ms["master1"] ++ M2 = topology_m2.ms["master2"] ++ ++ # add a test user ++ test_users_m1 = UserAccounts(M1, base_m2.dn, rdn=None) ++ user_1 = test_users_m1.create_test_user(uid=1000) ++ test_users_m2 = UserAccount(M2, user_1.dn) ++ # Waiting fo the user to be replicated ++ for i in range(0,4): ++ time.sleep(1) ++ if test_users_m2.exists(): ++ break ++ assert(test_users_m2.exists()) ++ ++ # Stop replication agreements ++ topology_m2.pause_all_replicas() ++ ++ # On M1 rename test entry in uid=foo1 ++ original_dn = user_1.dn ++ user_1.rename('uid=foo1') ++ time.sleep(1) ++ ++ # On M2 rename test entry in uid=foo2 ++ M2.rename_s(original_dn, 'uid=foo2') ++ time.sleep(2) ++ ++ # on M1 MOD_REPL uid into foo1 ++ user_1.replace('uid', 'foo1') ++ ++ # resume replication agreements ++ topology_m2.resume_all_replicas() ++ time.sleep(5) ++ ++ # check that on M1, the entry 'uid' has two values 'foo1' and 'foo2' ++ final_dn = re.sub('^.*1000,', 'uid=foo2,', original_dn) ++ final_user_m1 = UserAccount(M1, final_dn) ++ for val in final_user_m1.get_attr_vals_utf8('uid'): ++ log.info("Check %s is on M1" % val) ++ assert(val in ['foo1', 'foo2']) ++ ++ # check that on M2, the entry 'uid' has two values 'foo1' and 'foo2' ++ final_user_m2 = UserAccount(M2, final_dn) ++ for val in final_user_m2.get_attr_vals_utf8('uid'): ++ log.info("Check %s is on M1" % val) ++ assert(val in ['foo1', 'foo2']) ++ ++ # check that the entry have the same uid values ++ for val in final_user_m1.get_attr_vals_utf8('uid'): ++ log.info("Check M1.uid %s is also on M2" % val) ++ assert(val in final_user_m2.get_attr_vals_utf8('uid')) ++ ++ for val in final_user_m2.get_attr_vals_utf8('uid'): ++ log.info("Check M2.uid %s is also on M1" % val) ++ assert(val in final_user_m1.get_attr_vals_utf8('uid')) ++ ++ def test_conflict_attribute_single_valued(self, topology_m2, base_m2): ++ """A RDN attribute being signle-valued, checks that after several operations ++ MODRDN and MOD_REPL its RDN values are the same on both servers ++ ++ :id: c38ae613-5d1e-47cf-b051-c7284e64b817 ++ :setup: Two master replication, test container for entries, enable plugin logging, ++ audit log, error log for replica and access log for internal ++ :steps: ++ 1. Create a test entry uid=user_test_1000,... ++ 2. Pause all replication agreements ++ 3. On M1 rename it into employeenumber=foo1,... ++ 4. On M2 rename it into employeenumber=foo2,... ++ 5. On M1 MOD_REPL employeenumber:foo1 ++ 6. Resume all replication agreements ++ 7. Check that entry on M1 has employeenumber=foo1 ++ 8. Check that entry on M2 has employeenumber=foo1 ++ 9. Check that entry on M1 and M2 has the same employeenumber values ++ :expectedresults: ++ 1. It should pass ++ 2. It should pass ++ 3. It should pass ++ 4. It should pass ++ 5. It should pass ++ 6. It should pass ++ 7. It should pass ++ 8. It should pass ++ 9. It should pass ++ """ ++ ++ M1 = topology_m2.ms["master1"] ++ M2 = topology_m2.ms["master2"] ++ ++ # add a test user with a dummy 'uid' extra value because modrdn removes ++ # uid that conflict with 'account' objectclass ++ test_users_m1 = UserAccounts(M1, base_m2.dn, rdn=None) ++ user_1 = test_users_m1.create_test_user(uid=1000) ++ user_1.add('objectclass', 'extensibleobject') ++ user_1.add('uid', 'dummy') ++ test_users_m2 = UserAccount(M2, user_1.dn) ++ ++ # Waiting fo the user to be replicated ++ for i in range(0,4): ++ time.sleep(1) ++ if test_users_m2.exists(): ++ break ++ assert(test_users_m2.exists()) ++ ++ # Stop replication agreements ++ topology_m2.pause_all_replicas() ++ ++ # On M1 rename test entry in employeenumber=foo1 ++ original_dn = user_1.dn ++ user_1.rename('employeenumber=foo1') ++ time.sleep(1) ++ ++ # On M2 rename test entry in employeenumber=foo2 ++ M2.rename_s(original_dn, 'employeenumber=foo2') ++ time.sleep(2) ++ ++ # on M1 MOD_REPL uid into foo1 ++ user_1.replace('employeenumber', 'foo1') ++ ++ # resume replication agreements ++ topology_m2.resume_all_replicas() ++ time.sleep(5) ++ ++ # check that on M1, the entry 'employeenumber' has value 'foo1' ++ final_dn = re.sub('^.*1000,', 'employeenumber=foo2,', original_dn) ++ final_user_m1 = UserAccount(M1, final_dn) ++ for val in final_user_m1.get_attr_vals_utf8('employeenumber'): ++ log.info("Check %s is on M1" % val) ++ assert(val in ['foo1']) ++ ++ # check that on M2, the entry 'employeenumber' has values 'foo1' ++ final_user_m2 = UserAccount(M2, final_dn) ++ for val in final_user_m2.get_attr_vals_utf8('employeenumber'): ++ log.info("Check %s is on M2" % val) ++ assert(val in ['foo1']) ++ ++ # check that the entry have the same uid values ++ for val in final_user_m1.get_attr_vals_utf8('employeenumber'): ++ log.info("Check M1.uid %s is also on M2" % val) ++ assert(val in final_user_m2.get_attr_vals_utf8('employeenumber')) ++ ++ for val in final_user_m2.get_attr_vals_utf8('employeenumber'): ++ log.info("Check M2.uid %s is also on M1" % val) ++ assert(val in final_user_m1.get_attr_vals_utf8('employeenumber')) + + class TestThreeMasters: + def test_nested_entries(self, topology_m3, base_m3): +diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modify.c b/ldap/servers/slapd/back-ldbm/ldbm_modify.c +index e9d7e87e3..a507f3c31 100644 +--- a/ldap/servers/slapd/back-ldbm/ldbm_modify.c ++++ b/ldap/servers/slapd/back-ldbm/ldbm_modify.c +@@ -213,6 +213,112 @@ error: + return retval; + } + ++int32_t ++entry_get_rdn_mods(Slapi_PBlock *pb, Slapi_Entry *entry, CSN *csn, int repl_op, Slapi_Mods **smods_ret) ++{ ++ unsigned long op_type = SLAPI_OPERATION_NONE; ++ char *new_rdn = NULL; ++ char **dns = NULL; ++ char **rdns = NULL; ++ Slapi_Mods *smods = NULL; ++ char *type = NULL; ++ struct berval *bvp[2] = {0}; ++ struct berval bv; ++ Slapi_Attr *attr = NULL; ++ const char *entry_dn = NULL; ++ ++ *smods_ret = NULL; ++ entry_dn = slapi_entry_get_dn_const(entry); ++ /* Do not bother to check that RDN is present, no one rename RUV or change its nsuniqueid */ ++ if (strcasestr(entry_dn, RUV_STORAGE_ENTRY_UNIQUEID)) { ++ return 0; ++ } ++ ++ /* First get the RDNs of the operation */ ++ slapi_pblock_get(pb, SLAPI_OPERATION_TYPE, &op_type); ++ switch (op_type) { ++ case SLAPI_OPERATION_MODIFY: ++ dns = slapi_ldap_explode_dn(entry_dn, 0); ++ if (dns == NULL) { ++ slapi_log_err(SLAPI_LOG_ERR, "entry_get_rdn_mods", ++ "Fails to split DN \"%s\" into components\n", entry_dn); ++ return -1; ++ } ++ rdns = slapi_ldap_explode_rdn(dns[0], 0); ++ slapi_ldap_value_free(dns); ++ ++ break; ++ case SLAPI_OPERATION_MODRDN: ++ slapi_pblock_get(pb, SLAPI_MODRDN_NEWRDN, &new_rdn); ++ rdns = slapi_ldap_explode_rdn(new_rdn, 0); ++ break; ++ default: ++ break; ++ } ++ if (rdns == NULL || rdns[0] == NULL) { ++ slapi_log_err(SLAPI_LOG_ERR, "entry_get_rdn_mods", ++ "Fails to split RDN \"%s\" into components\n", slapi_entry_get_dn_const(entry)); ++ return -1; ++ } ++ ++ /* Update the entry to add RDNs values if they are missing */ ++ smods = slapi_mods_new(); ++ ++ bvp[0] = &bv; ++ bvp[1] = NULL; ++ for (size_t rdns_count = 0; rdns[rdns_count]; rdns_count++) { ++ Slapi_Value *value; ++ attr = NULL; ++ slapi_rdn2typeval(rdns[rdns_count], &type, &bv); ++ ++ /* Check if the RDN value exists */ ++ if ((slapi_entry_attr_find(entry, type, &attr) != 0) || ++ (slapi_attr_value_find(attr, &bv))) { ++ const CSN *csn_rdn_add; ++ const CSN *adcsn = attr_get_deletion_csn(attr); ++ ++ /* It is missing => adds it */ ++ if (slapi_attr_flag_is_set(attr, SLAPI_ATTR_FLAG_SINGLE)) { ++ if (csn_compare(adcsn, csn) >= 0) { ++ /* this is a single valued attribute and the current value ++ * (that is different from RDN value) is more recent than ++ * the RDN value we want to apply. ++ * Keep the current value and add a conflict flag ++ */ ++ ++ type = ATTR_NSDS5_REPLCONFLICT; ++ bv.bv_val = "RDN value may be missing because it is single-valued"; ++ bv.bv_len = strlen(bv.bv_val); ++ slapi_entry_add_string(entry, type, bv.bv_val); ++ slapi_mods_add_modbvps(smods, LDAP_MOD_ADD, type, bvp); ++ continue; ++ } ++ } ++ /* if a RDN value needs to be forced, make sure it csn is ahead */ ++ slapi_mods_add_modbvps(smods, LDAP_MOD_ADD, type, bvp); ++ csn_rdn_add = csn_max(adcsn, csn); ++ ++ if (entry_apply_mods_wsi(entry, smods, csn_rdn_add, repl_op)) { ++ slapi_log_err(SLAPI_LOG_ERR, "entry_get_rdn_mods", ++ "Fails to set \"%s\" in \"%s\"\n", type, slapi_entry_get_dn_const(entry)); ++ slapi_ldap_value_free(rdns); ++ slapi_mods_free(&smods); ++ return -1; ++ } ++ /* Make the RDN value a distinguished value */ ++ attr_value_find_wsi(attr, &bv, &value); ++ value_update_csn(value, CSN_TYPE_VALUE_DISTINGUISHED, csn_rdn_add); ++ } ++ } ++ slapi_ldap_value_free(rdns); ++ if (smods->num_mods == 0) { ++ /* smods_ret already NULL, just free the useless smods */ ++ slapi_mods_free(&smods); ++ } else { ++ *smods_ret = smods; ++ } ++ return 0; ++} + /** + Apply the mods to the ec entry. Check for syntax, schema problems. + Check for abandon. +@@ -269,6 +375,8 @@ modify_apply_check_expand( + goto done; + } + ++ ++ + /* + * If the objectClass attribute type was modified in any way, expand + * the objectClass values to reflect the inheritance hierarchy. +@@ -414,6 +522,7 @@ ldbm_back_modify(Slapi_PBlock *pb) + int result_sent = 0; + int32_t parent_op = 0; + struct timespec parent_time; ++ Slapi_Mods *smods_add_rdn = NULL; + + slapi_pblock_get(pb, SLAPI_BACKEND, &be); + slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &li); +@@ -731,6 +840,15 @@ ldbm_back_modify(Slapi_PBlock *pb) + } + } /* else if new_mod_count == mod_count then betxnpremod plugin did nothing */ + ++ /* time to check if applying a replicated operation removed ++ * the RDN value from the entry. Assuming that only replicated update ++ * can lead to that bad result ++ */ ++ if (entry_get_rdn_mods(pb, ec->ep_entry, opcsn, repl_op, &smods_add_rdn)) { ++ goto error_return; ++ } ++ ++ + /* + * Update the ID to Entry index. + * Note that id2entry_add replaces the entry, so the Entry ID +@@ -764,6 +882,23 @@ ldbm_back_modify(Slapi_PBlock *pb) + MOD_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count); + goto error_return; + } ++ ++ if (smods_add_rdn && slapi_mods_get_num_mods(smods_add_rdn) > 0) { ++ retval = index_add_mods(be, (LDAPMod **) slapi_mods_get_ldapmods_byref(smods_add_rdn), e, ec, &txn); ++ if (DB_LOCK_DEADLOCK == retval) { ++ /* Abort and re-try */ ++ slapi_mods_free(&smods_add_rdn); ++ continue; ++ } ++ if (retval != 0) { ++ slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modify", ++ "index_add_mods (rdn) failed, err=%d %s\n", ++ retval, (msg = dblayer_strerror(retval)) ? msg : ""); ++ MOD_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count); ++ slapi_mods_free(&smods_add_rdn); ++ goto error_return; ++ } ++ } + /* + * Remove the old entry from the Virtual List View indexes. + * Add the new entry to the Virtual List View indexes. +@@ -978,6 +1113,7 @@ error_return: + + common_return: + slapi_mods_done(&smods); ++ slapi_mods_free(&smods_add_rdn); + + if (inst) { + if (ec_locked || cache_is_in_cache(&inst->inst_cache, ec)) { +diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c +index fde83c99f..e97b7a5f6 100644 +--- a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c ++++ b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c +@@ -21,7 +21,7 @@ static void moddn_unlock_and_return_entry(backend *be, struct backentry **target + static int moddn_newrdn_mods(Slapi_PBlock *pb, const char *olddn, struct backentry *ec, Slapi_Mods *smods_wsi, int is_repl_op); + static IDList *moddn_get_children(back_txn *ptxn, Slapi_PBlock *pb, backend *be, struct backentry *parententry, Slapi_DN *parentdn, struct backentry ***child_entries, struct backdn ***child_dns, int is_resurect_operation); + static int moddn_rename_children(back_txn *ptxn, Slapi_PBlock *pb, backend *be, IDList *children, Slapi_DN *dn_parentdn, Slapi_DN *dn_newsuperiordn, struct backentry *child_entries[]); +-static int modrdn_rename_entry_update_indexes(back_txn *ptxn, Slapi_PBlock *pb, struct ldbminfo *li, struct backentry *e, struct backentry **ec, Slapi_Mods *smods1, Slapi_Mods *smods2, Slapi_Mods *smods3); ++static int modrdn_rename_entry_update_indexes(back_txn *ptxn, Slapi_PBlock *pb, struct ldbminfo *li, struct backentry *e, struct backentry **ec, Slapi_Mods *smods1, Slapi_Mods *smods2, Slapi_Mods *smods3, Slapi_Mods *smods4); + static void mods_remove_nsuniqueid(Slapi_Mods *smods); + + #define MOD_SET_ERROR(rc, error, count) \ +@@ -100,6 +100,7 @@ ldbm_back_modrdn(Slapi_PBlock *pb) + Connection *pb_conn = NULL; + int32_t parent_op = 0; + struct timespec parent_time; ++ Slapi_Mods *smods_add_rdn = NULL; + + if (slapi_pblock_get(pb, SLAPI_CONN_ID, &conn_id) < 0) { + conn_id = 0; /* connection is NULL */ +@@ -842,6 +843,15 @@ ldbm_back_modrdn(Slapi_PBlock *pb) + goto error_return; + } + } ++ ++ /* time to check if applying a replicated operation removed ++ * the RDN value from the entry. Assuming that only replicated update ++ * can lead to that bad result ++ */ ++ if (entry_get_rdn_mods(pb, ec->ep_entry, opcsn, is_replicated_operation, &smods_add_rdn)) { ++ goto error_return; ++ } ++ + /* check that the entry still obeys the schema */ + if (slapi_entry_schema_check(pb, ec->ep_entry) != 0) { + ldap_result_code = LDAP_OBJECT_CLASS_VIOLATION; +@@ -1003,7 +1013,7 @@ ldbm_back_modrdn(Slapi_PBlock *pb) + /* + * Update the indexes for the entry. + */ +- retval = modrdn_rename_entry_update_indexes(&txn, pb, li, e, &ec, &smods_generated, &smods_generated_wsi, &smods_operation_wsi); ++ retval = modrdn_rename_entry_update_indexes(&txn, pb, li, e, &ec, &smods_generated, &smods_generated_wsi, &smods_operation_wsi, smods_add_rdn); + if (DB_LOCK_DEADLOCK == retval) { + /* Retry txn */ + continue; +@@ -1497,6 +1507,7 @@ common_return: + slapi_mods_done(&smods_operation_wsi); + slapi_mods_done(&smods_generated); + slapi_mods_done(&smods_generated_wsi); ++ slapi_mods_free(&smods_add_rdn); + slapi_ch_free((void **)&child_entries); + slapi_ch_free((void **)&child_dns); + if (ldap_result_matcheddn && 0 != strcmp(ldap_result_matcheddn, "NULL")) +@@ -1778,7 +1789,7 @@ mods_remove_nsuniqueid(Slapi_Mods *smods) + * mods contains the list of attribute change made. + */ + static int +-modrdn_rename_entry_update_indexes(back_txn *ptxn, Slapi_PBlock *pb, struct ldbminfo *li __attribute__((unused)), struct backentry *e, struct backentry **ec, Slapi_Mods *smods1, Slapi_Mods *smods2, Slapi_Mods *smods3) ++modrdn_rename_entry_update_indexes(back_txn *ptxn, Slapi_PBlock *pb, struct ldbminfo *li __attribute__((unused)), struct backentry *e, struct backentry **ec, Slapi_Mods *smods1, Slapi_Mods *smods2, Slapi_Mods *smods3, Slapi_Mods *smods4) + { + backend *be; + ldbm_instance *inst; +@@ -1874,6 +1885,24 @@ modrdn_rename_entry_update_indexes(back_txn *ptxn, Slapi_PBlock *pb, struct ldbm + goto error_return; + } + } ++ if (smods4 != NULL && slapi_mods_get_num_mods(smods4) > 0) { ++ /* ++ * update the indexes: lastmod, rdn, etc. ++ */ ++ retval = index_add_mods(be, slapi_mods_get_ldapmods_byref(smods4), e, *ec, ptxn); ++ if (DB_LOCK_DEADLOCK == retval) { ++ /* Retry txn */ ++ slapi_log_err(SLAPI_LOG_BACKLDBM, "modrdn_rename_entry_update_indexes", ++ "index_add_mods4 deadlock\n"); ++ goto error_return; ++ } ++ if (retval != 0) { ++ slapi_log_err(SLAPI_LOG_TRACE, "modrdn_rename_entry_update_indexes", ++ "index_add_mods 4 failed, err=%d %s\n", ++ retval, (msg = dblayer_strerror(retval)) ? msg : ""); ++ goto error_return; ++ } ++ } + /* + * Remove the old entry from the Virtual List View indexes. + * Add the new entry to the Virtual List View indexes. +@@ -1991,7 +2020,7 @@ moddn_rename_child_entry( + * Update all the indexes. + */ + retval = modrdn_rename_entry_update_indexes(ptxn, pb, li, e, ec, +- smodsp, NULL, NULL); ++ smodsp, NULL, NULL, NULL); + /* JCMREPL - Should the children get updated modifiersname and lastmodifiedtime? */ + slapi_mods_done(&smods); + } +diff --git a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h +index 4d2524fd9..e2f1100ed 100644 +--- a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h ++++ b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h +@@ -324,6 +324,7 @@ int get_parent_rdn(DB *db, ID parentid, Slapi_RDN *srdn); + /* + * modify.c + */ ++int32_t entry_get_rdn_mods(Slapi_PBlock *pb, Slapi_Entry *entry, CSN *csn, int repl_op, Slapi_Mods **smods_ret); + int modify_update_all(backend *be, Slapi_PBlock *pb, modify_context *mc, back_txn *txn); + void modify_init(modify_context *mc, struct backentry *old_entry); + int modify_apply_mods(modify_context *mc, Slapi_Mods *smods); +-- +2.26.2 + diff --git a/SOURCES/0021-Issue-49256-log-warning-when-thread-number-is-very-d.patch b/SOURCES/0021-Issue-49256-log-warning-when-thread-number-is-very-d.patch new file mode 100644 index 0000000..2e20c8c --- /dev/null +++ b/SOURCES/0021-Issue-49256-log-warning-when-thread-number-is-very-d.patch @@ -0,0 +1,128 @@ +From 2be9d1b4332d3b9b55a2d285e9610813100e235f Mon Sep 17 00:00:00 2001 +From: Mark Reynolds +Date: Mon, 22 Jun 2020 17:49:10 -0400 +Subject: [PATCH] Issue 49256 - log warning when thread number is very + different from autotuned value + +Description: To help prevent customers from setting incorrect values for + the thread number it would be useful to warn them that the + configured value is either way too low or way too high. + +relates: https://pagure.io/389-ds-base/issue/49256 + +Reviewed by: firstyear(Thanks!) +--- + .../tests/suites/config/autotuning_test.py | 28 +++++++++++++++ + ldap/servers/slapd/libglobs.c | 34 ++++++++++++++++++- + ldap/servers/slapd/slap.h | 3 ++ + 3 files changed, 64 insertions(+), 1 deletion(-) + +diff --git a/dirsrvtests/tests/suites/config/autotuning_test.py b/dirsrvtests/tests/suites/config/autotuning_test.py +index d1c751444..540761250 100644 +--- a/dirsrvtests/tests/suites/config/autotuning_test.py ++++ b/dirsrvtests/tests/suites/config/autotuning_test.py +@@ -43,6 +43,34 @@ def test_threads_basic(topo): + assert topo.standalone.config.get_attr_val_int("nsslapd-threadnumber") > 0 + + ++def test_threads_warning(topo): ++ """Check that we log a warning if the thread number is too high or low ++ ++ :id: db92412b-2812-49de-84b0-00f452cd254f ++ :setup: Standalone Instance ++ :steps: ++ 1. Get autotuned thread number ++ 2. Set threads way higher than hw threads, and find a warning in the log ++ 3. Set threads way lower than hw threads, and find a warning in the log ++ :expectedresults: ++ 1. Success ++ 2. Success ++ 3. Success ++ """ ++ topo.standalone.config.set("nsslapd-threadnumber", "-1") ++ autotuned_value = topo.standalone.config.get_attr_val_utf8("nsslapd-threadnumber") ++ ++ topo.standalone.config.set("nsslapd-threadnumber", str(int(autotuned_value) * 4)) ++ time.sleep(.5) ++ assert topo.standalone.ds_error_log.match('.*higher.*hurt server performance.*') ++ ++ if int(autotuned_value) > 1: ++ # If autotuned is 1, there isn't anything to test here ++ topo.standalone.config.set("nsslapd-threadnumber", "1") ++ time.sleep(.5) ++ assert topo.standalone.ds_error_log.match('.*lower.*hurt server performance.*') ++ ++ + @pytest.mark.parametrize("invalid_value", ('-2', '0', 'invalid')) + def test_threads_invalid_value(topo, invalid_value): + """Check nsslapd-threadnumber for an invalid values +diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c +index fbf90d92d..88676a303 100644 +--- a/ldap/servers/slapd/libglobs.c ++++ b/ldap/servers/slapd/libglobs.c +@@ -4374,6 +4374,7 @@ config_set_threadnumber(const char *attrname, char *value, char *errorbuf, int a + { + int retVal = LDAP_SUCCESS; + int32_t threadnum = 0; ++ int32_t hw_threadnum = 0; + char *endp = NULL; + + slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig(); +@@ -4386,8 +4387,39 @@ config_set_threadnumber(const char *attrname, char *value, char *errorbuf, int a + threadnum = strtol(value, &endp, 10); + + /* Means we want to re-run the hardware detection. */ ++ hw_threadnum = util_get_hardware_threads(); + if (threadnum == -1) { +- threadnum = util_get_hardware_threads(); ++ threadnum = hw_threadnum; ++ } else { ++ /* ++ * Log a message if the user defined thread number is very different ++ * from the hardware threads as this is probably not the optimal ++ * value. ++ */ ++ if (threadnum >= hw_threadnum) { ++ if (threadnum > MIN_THREADS && threadnum / hw_threadnum >= 4) { ++ /* We're over the default minimum and way higher than the hw ++ * threads. */ ++ slapi_log_err(SLAPI_LOG_NOTICE, "config_set_threadnumber", ++ "The configured thread number (%d) is significantly " ++ "higher than the number of hardware threads (%d). " ++ "This can potentially hurt server performance. If " ++ "you are unsure how to tune \"nsslapd-threadnumber\" " ++ "then set it to \"-1\" and the server will tune it " ++ "according to the system hardware\n", ++ threadnum, hw_threadnum); ++ } ++ } else if (threadnum < MIN_THREADS) { ++ /* The thread number should never be less than the minimum and ++ * hardware threads. */ ++ slapi_log_err(SLAPI_LOG_WARNING, "config_set_threadnumber", ++ "The configured thread number (%d) is lower than the number " ++ "of hardware threads (%d). This will hurt server performance. " ++ "If you are unsure how to tune \"nsslapd-threadnumber\" then " ++ "set it to \"-1\" and the server will tune it according to the " ++ "system hardware\n", ++ threadnum, hw_threadnum); ++ } + } + + if (*endp != '\0' || errno == ERANGE || threadnum < 1 || threadnum > 65535) { +diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h +index 8e76393c3..894efd29c 100644 +--- a/ldap/servers/slapd/slap.h ++++ b/ldap/servers/slapd/slap.h +@@ -403,6 +403,9 @@ typedef void (*VFPV)(); /* takes undefined arguments */ + #define SLAPD_DEFAULT_PW_MAX_CLASS_CHARS_ATTRIBUTE 0 + #define SLAPD_DEFAULT_PW_MAX_CLASS_CHARS_ATTRIBUTE_STR "0" + ++#define MIN_THREADS 16 ++#define MAX_THREADS 512 ++ + + /* Default password values. */ + +-- +2.26.2 + diff --git a/SOURCES/0021-Issue-50834-Incorrectly-setting-the-NSS-default-SSL-.patch b/SOURCES/0021-Issue-50834-Incorrectly-setting-the-NSS-default-SSL-.patch deleted file mode 100644 index c5a47e9..0000000 --- a/SOURCES/0021-Issue-50834-Incorrectly-setting-the-NSS-default-SSL-.patch +++ /dev/null @@ -1,35 +0,0 @@ -From e169d4690fb37be4fa9be1b2624c72ec90b1b68e Mon Sep 17 00:00:00 2001 -From: Mark Reynolds -Date: Mon, 20 Jan 2020 13:16:36 -0500 -Subject: [PATCH] Issue 50834 - Incorrectly setting the NSS default SSL version - max - -Description: We've been using the wrong function to get the NSS max - version We were calling SSL_VersionRangeGetSupported() - which gets the versions NSS "can" handle, but - SSL_VersionRangeGetDefault() gets the versions that - are actually "enabled". - -relates: https://pagure.io/389-ds-base/issue/50834 - -Reviewed by: mreynolds(one line commit rule) ---- - ldap/servers/slapd/ssl.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ldap/servers/slapd/ssl.c b/ldap/servers/slapd/ssl.c -index 6a07f1ab0..71f91f761 100644 ---- a/ldap/servers/slapd/ssl.c -+++ b/ldap/servers/slapd/ssl.c -@@ -936,7 +936,7 @@ slapd_nss_init(int init_ssl __attribute__((unused)), int config_available __attr - char *certdir; - char emin[VERSION_STR_LENGTH], emax[VERSION_STR_LENGTH]; - /* Get the range of the supported SSL version */ -- SSL_VersionRangeGetSupported(ssl_variant_stream, &enabledNSSVersions); -+ SSL_VersionRangeGetDefault(ssl_variant_stream, &enabledNSSVersions); - - (void)slapi_getSSLVersion_str(enabledNSSVersions.min, emin, sizeof(emin)); - (void)slapi_getSSLVersion_str(enabledNSSVersions.max, emax, sizeof(emax)); --- -2.21.1 - diff --git a/SOURCES/0022-Issue-51188-db2ldif-crashes-when-LDIF-file-can-t-be-.patch b/SOURCES/0022-Issue-51188-db2ldif-crashes-when-LDIF-file-can-t-be-.patch new file mode 100644 index 0000000..94c3f34 --- /dev/null +++ b/SOURCES/0022-Issue-51188-db2ldif-crashes-when-LDIF-file-can-t-be-.patch @@ -0,0 +1,34 @@ +From d24381488a997dda0006b603fb2b452b726757c0 Mon Sep 17 00:00:00 2001 +From: Simon Pichugin +Date: Thu, 25 Jun 2020 10:45:16 +0200 +Subject: [PATCH] Issue 51188 - db2ldif crashes when LDIF file can't be + accessed + +Bug Description: db2ldif crashes when we set '-a LDIF_PATH' to a place that +can't be accessed by the user (dirsrv by default) + +Fix Description: Don't attempt to close DB if we bail after a failed +attempt to open LDIF file. + +https://pagure.io/389-ds-base/issue/51188 + +Reviewed by: mreynolds (Thanks!) +--- + ldap/servers/slapd/back-ldbm/db-bdb/bdb_ldif2db.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/ldap/servers/slapd/back-ldbm/db-bdb/bdb_ldif2db.c b/ldap/servers/slapd/back-ldbm/db-bdb/bdb_ldif2db.c +index 542147c3d..9ffd877cb 100644 +--- a/ldap/servers/slapd/back-ldbm/db-bdb/bdb_ldif2db.c ++++ b/ldap/servers/slapd/back-ldbm/db-bdb/bdb_ldif2db.c +@@ -871,6 +871,7 @@ bdb_db2ldif(Slapi_PBlock *pb) + slapi_log_err(SLAPI_LOG_ERR, "bdb_db2ldif", + "db2ldif: %s: can't open %s: %d (%s) while running as user \"%s\"\n", + inst->inst_name, fname, errno, dblayer_strerror(errno), slapdFrontendConfig->localuserinfo->pw_name); ++ we_start_the_backends = 0; + return_value = -1; + goto bye; + } +-- +2.26.2 + diff --git a/SOURCES/0022-Ticket-50741-cont-bdb_start-Detected-Disorderly-Shut.patch b/SOURCES/0022-Ticket-50741-cont-bdb_start-Detected-Disorderly-Shut.patch deleted file mode 100644 index 455ec9c..0000000 --- a/SOURCES/0022-Ticket-50741-cont-bdb_start-Detected-Disorderly-Shut.patch +++ /dev/null @@ -1,281 +0,0 @@ -From 1d2dca488c7b646dcf5d482414dec2ee032edea6 Mon Sep 17 00:00:00 2001 -From: Ludwig Krispenz -Date: Fri, 6 Dec 2019 13:54:04 +0100 -Subject: [PATCH] Ticket 50741-cont bdb_start - Detected Disorderly Shutdown - -Bug: Offline import does no longer write guardian file, next - normal start will raise a Disorderly Shutdown - -Fix: The bug was introduced with the fix for #50659 when dblayer_close() was - removed from import_moain_offline becasue it was called twice in some - scenarios. But it did miss in ldif2db. Add it there. - Also correct function reference in error messages - -Reviewed by: Thierry, thanks ---- - .../slapd/back-ldbm/db-bdb/bdb_import.c | 60 +++++++++---------- - .../slapd/back-ldbm/db-bdb/bdb_ldif2db.c | 3 + - 2 files changed, 33 insertions(+), 30 deletions(-) - -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 60b6e13eb..15574e60f 100644 ---- a/ldap/servers/slapd/back-ldbm/db-bdb/bdb_import.c -+++ b/ldap/servers/slapd/back-ldbm/db-bdb/bdb_import.c -@@ -2274,7 +2274,7 @@ bdb_import_main(void *arg) - producer, PR_PRIORITY_NORMAL, PR_GLOBAL_BOUND_THREAD, - PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE)) { - PRErrorCode prerr = PR_GetError(); -- slapi_log_err(SLAPI_LOG_ERR, "import_main_offline", -+ slapi_log_err(SLAPI_LOG_ERR, "bdb_import_main", - "Unable to spawn upgrade dn producer thread, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n", - prerr, slapd_pr_strerror(prerr)); - goto error; -@@ -2285,19 +2285,19 @@ bdb_import_main(void *arg) - PR_UNJOINABLE_THREAD, - SLAPD_DEFAULT_THREAD_STACKSIZE)) { - PRErrorCode prerr = PR_GetError(); -- slapi_log_err(SLAPI_LOG_ERR, "import_main_offline", -+ slapi_log_err(SLAPI_LOG_ERR, "bdb_import_main", - "Unable to spawn index producer thread, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n", - prerr, slapd_pr_strerror(prerr)); - goto error; - } - } else { -- import_log_notice(job, SLAPI_LOG_INFO, "import_main_offline", "Beginning import job..."); -+ import_log_notice(job, SLAPI_LOG_INFO, "bdb_import_main", "Beginning import job..."); - if (!CREATE_THREAD(PR_USER_THREAD, (VFP)import_producer, producer, - PR_PRIORITY_NORMAL, PR_GLOBAL_BOUND_THREAD, - PR_UNJOINABLE_THREAD, - SLAPD_DEFAULT_THREAD_STACKSIZE)) { - PRErrorCode prerr = PR_GetError(); -- slapi_log_err(SLAPI_LOG_ERR, "import_main_offline", -+ slapi_log_err(SLAPI_LOG_ERR, "bdb_import_main", - "Unable to spawn import producer thread, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n", - prerr, slapd_pr_strerror(prerr)); - goto error; -@@ -2305,9 +2305,9 @@ bdb_import_main(void *arg) - } - - if (0 == job->job_index_buffer_suggestion) -- import_log_notice(job, SLAPI_LOG_INFO, "import_main_offline", "Index buffering is disabled."); -+ import_log_notice(job, SLAPI_LOG_INFO, "bdb_import_main", "Index buffering is disabled."); - else -- import_log_notice(job, SLAPI_LOG_INFO, "import_main_offline", -+ import_log_notice(job, SLAPI_LOG_INFO, "bdb_import_main", - "Index buffering enabled with bucket size %lu", - (long unsigned int)job->job_index_buffer_suggestion); - -@@ -2343,13 +2343,13 @@ bdb_import_main(void *arg) - if (ret == ERR_IMPORT_ABORTED) { - /* at least one of the threads has aborted -- shut down ALL - * of the threads */ -- import_log_notice(job, SLAPI_LOG_ERR, "import_main_offline", -+ import_log_notice(job, SLAPI_LOG_ERR, "bdb_import_main", - "Aborting all %s threads...", opstr); - /* this abort sets the abort flag on the threads and will block for - * the exit of all threads - */ - import_set_abort_flag_all(job, 1); -- import_log_notice(job, SLAPI_LOG_ERR, "import_main_offline", -+ import_log_notice(job, SLAPI_LOG_ERR, "bdb_import_main", - "%s threads aborted.", opstr); - aborted = 1; - goto error; -@@ -2359,7 +2359,7 @@ bdb_import_main(void *arg) - goto error; - } else if (0 != ret) { - /* Some horrible fate has befallen the import */ -- import_log_notice(job, SLAPI_LOG_ERR, "import_main_offline", -+ import_log_notice(job, SLAPI_LOG_ERR, "bdb_import_main", - "Fatal pass error %d", ret); - goto error; - } -@@ -2405,7 +2405,7 @@ bdb_import_main(void *arg) - job->first_ID = job->ready_ID + 1; - import_free_thread_data(job); - job->worker_list = producer; -- import_log_notice(job, SLAPI_LOG_INFO, "import_main_offline", -+ import_log_notice(job, SLAPI_LOG_INFO, "bdb_import_main", - "Beginning pass number %d", job->total_pass + 1); - } else { - /* Bizarro-slapd */ -@@ -2416,7 +2416,7 @@ bdb_import_main(void *arg) - - /* kill the producer now; we're done */ - if (producer) { -- import_log_notice(job, SLAPI_LOG_INFO, "import_main_offline", "Cleaning up producer thread..."); -+ import_log_notice(job, SLAPI_LOG_INFO, "bdb_import_main", "Cleaning up producer thread..."); - producer->command = STOP; - /* wait for the lead thread to stop */ - while (producer->state != FINISHED) { -@@ -2424,18 +2424,18 @@ bdb_import_main(void *arg) - } - } - -- import_log_notice(job, SLAPI_LOG_INFO, "import_main_offline", "Indexing complete. Post-processing..."); -+ import_log_notice(job, SLAPI_LOG_INFO, "bdb_import_main", "Indexing complete. Post-processing..."); - /* Now do the numsubordinates attribute */ - /* [610066] reindexed db cannot be used in the following backup/restore */ -- import_log_notice(job, SLAPI_LOG_INFO, "import_main_offline", -+ import_log_notice(job, SLAPI_LOG_INFO, "bdb_import_main", - "Generating numsubordinates (this may take several minutes to complete)..."); - if ((!(job->flags & FLAG_REINDEXING) || (job->flags & FLAG_DN2RDN)) && - (ret = bdb_update_subordinatecounts(be, job, NULL)) != 0) { -- import_log_notice(job, SLAPI_LOG_ERR, "import_main_offline", -+ import_log_notice(job, SLAPI_LOG_ERR, "bdb_import_main", - "Failed to update numsubordinates attributes"); - goto error; - } -- import_log_notice(job, SLAPI_LOG_INFO, "import_main_offline", -+ import_log_notice(job, SLAPI_LOG_INFO, "bdb_import_main", - "Generating numSubordinates complete."); - - if (!entryrdn_get_noancestorid()) { -@@ -2446,12 +2446,12 @@ bdb_import_main(void *arg) - ainfo_get(be, "ancestorid", &ai); - dblayer_erase_index_file(be, ai, PR_TRUE, 0); - if ((ret = bdb_ancestorid_create_index(be, job)) != 0) { -- import_log_notice(job, SLAPI_LOG_ERR, "import_main_offline", "Failed to create ancestorid index"); -+ import_log_notice(job, SLAPI_LOG_ERR, "bdb_import_main", "Failed to create ancestorid index"); - goto error; - } - } - -- import_log_notice(job, SLAPI_LOG_INFO, "import_main_offline", "Flushing caches..."); -+ import_log_notice(job, SLAPI_LOG_INFO, "bdb_import_main", "Flushing caches..."); - - /* New way to exit the routine: check the return code. - * If it's non-zero, delete the database files. -@@ -2462,7 +2462,7 @@ bdb_import_main(void *arg) - error: - /* If we fail, the database is now in a mess, so we delete it - except dry run mode */ -- import_log_notice(job, SLAPI_LOG_INFO, "import_main_offline", "Closing files..."); -+ import_log_notice(job, SLAPI_LOG_INFO, "bdb_import_main", "Closing files..."); - cache_clear(&job->inst->inst_cache, CACHE_TYPE_ENTRY); - if (entryrdn_get_switch()) { - cache_clear(&job->inst->inst_dncache, CACHE_TYPE_DN); -@@ -2476,14 +2476,14 @@ error: - /* initialize the entry cache */ - if (!cache_init(&(inst->inst_cache), DEFAULT_CACHE_SIZE, - DEFAULT_CACHE_ENTRIES, CACHE_TYPE_ENTRY)) { -- slapi_log_err(SLAPI_LOG_ERR, "import_main_offline", -+ slapi_log_err(SLAPI_LOG_ERR, "bdb_import_main", - "cache_init failed. Server should be restarted.\n"); - } - - /* initialize the dn cache */ - if (!cache_init(&(inst->inst_dncache), DEFAULT_DNCACHE_SIZE, - DEFAULT_DNCACHE_MAXCOUNT, CACHE_TYPE_DN)) { -- slapi_log_err(SLAPI_LOG_ERR, "import_main_offline", -+ slapi_log_err(SLAPI_LOG_ERR, "bdb_import_main", - "dn cache_init failed. Server should be restarted.\n"); - } - } -@@ -2496,7 +2496,7 @@ error: - } - } else { - if (0 != (ret = dblayer_instance_close(job->inst->inst_be))) { -- import_log_notice(job, SLAPI_LOG_WARNING, "import_main_offline", "Failed to close database"); -+ import_log_notice(job, SLAPI_LOG_WARNING, "bdb_import_main", "Failed to close database"); - } - } - end = slapi_current_utc_time(); -@@ -2508,7 +2508,7 @@ error: - - if (job->not_here_skipped) { - if (job->skipped) { -- import_log_notice(job, SLAPI_LOG_INFO, "import_main_offline", -+ import_log_notice(job, SLAPI_LOG_INFO, "bdb_import_main", - "%s complete. Processed %lu entries " - "(%d bad entries were skipped, " - "%d entries were skipped because they don't " -@@ -2518,7 +2518,7 @@ error: - job->skipped, job->not_here_skipped, - seconds_to_import, entries_per_second); - } else { -- import_log_notice(job, SLAPI_LOG_INFO, "import_main_offline", -+ import_log_notice(job, SLAPI_LOG_INFO, "bdb_import_main", - "%s complete. Processed %lu entries " - "(%d entries were skipped because they don't " - "belong to this database) " -@@ -2529,7 +2529,7 @@ error: - } - } else { - if (job->skipped) { -- import_log_notice(job, SLAPI_LOG_INFO, "import_main_offline", -+ import_log_notice(job, SLAPI_LOG_INFO, "bdb_import_main", - "%s complete. Processed %lu entries " - "(%d were skipped) in %d seconds. " - "(%.2f entries/sec)", -@@ -2537,7 +2537,7 @@ error: - job->skipped, seconds_to_import, - entries_per_second); - } else { -- import_log_notice(job, SLAPI_LOG_INFO, "import_main_offline", -+ import_log_notice(job, SLAPI_LOG_INFO, "bdb_import_main", - "%s complete. Processed %lu entries " - "in %d seconds. (%.2f entries/sec)", - opstr, (long unsigned int)entries_processed, -@@ -2548,7 +2548,7 @@ error: - - if (job->flags & (FLAG_DRYRUN | FLAG_UPGRADEDNFORMAT_V1)) { - if (0 == ret) { -- import_log_notice(job, SLAPI_LOG_INFO, "import_main_offline", "%s complete. %s is up-to-date.", -+ import_log_notice(job, SLAPI_LOG_INFO, "bdb_import_main", "%s complete. %s is up-to-date.", - opstr, job->inst->inst_name); - ret = 0; - if (job->task) { -@@ -2556,7 +2556,7 @@ error: - } - import_all_done(job, ret); - } else if (NEED_DN_NORM_BT == ret) { -- import_log_notice(job, SLAPI_LOG_NOTICE, "import_main_offline", -+ import_log_notice(job, SLAPI_LOG_NOTICE, "bdb_import_main", - "%s complete. %s needs upgradednformat all.", - opstr, job->inst->inst_name); - if (job->task) { -@@ -2565,7 +2565,7 @@ error: - import_all_done(job, ret); - ret = 1; - } else if (NEED_DN_NORM == ret) { -- import_log_notice(job, SLAPI_LOG_NOTICE, "import_main_offline", -+ import_log_notice(job, SLAPI_LOG_NOTICE, "bdb_import_main", - "%s complete. %s needs upgradednformat.", - opstr, job->inst->inst_name); - if (job->task) { -@@ -2574,7 +2574,7 @@ error: - import_all_done(job, ret); - ret = 2; - } else if (NEED_DN_NORM_SP == ret) { -- import_log_notice(job, SLAPI_LOG_NOTICE, "import_main_offline", -+ import_log_notice(job, SLAPI_LOG_NOTICE, "bdb_import_main", - "%s complete. %s needs upgradednformat spaces.", - opstr, job->inst->inst_name); - if (job->task) { -@@ -2589,7 +2589,7 @@ error: - } - } - } else if (0 != ret) { -- import_log_notice(job, SLAPI_LOG_ERR, "import_main_offline", "%s failed.", opstr); -+ import_log_notice(job, SLAPI_LOG_ERR, "bdb_import_main", "%s failed.", opstr); - if (job->task != NULL) { - slapi_task_finish(job->task, ret); - } -diff --git a/ldap/servers/slapd/back-ldbm/db-bdb/bdb_ldif2db.c b/ldap/servers/slapd/back-ldbm/db-bdb/bdb_ldif2db.c -index bb411a539..542147c3d 100644 ---- a/ldap/servers/slapd/back-ldbm/db-bdb/bdb_ldif2db.c -+++ b/ldap/servers/slapd/back-ldbm/db-bdb/bdb_ldif2db.c -@@ -383,6 +383,9 @@ bdb_ldif2db(Slapi_PBlock *pb) - /* always use "new" import code now */ - slapi_pblock_set(pb, SLAPI_BACKEND, inst->inst_be); - ret = bdb_back_ldif2db(pb); -+ if (task_flags & SLAPI_TASK_RUNNING_FROM_COMMANDLINE) { -+ dblayer_close(li, DBLAYER_IMPORT_MODE); -+ } - if (ret == 0) { - if (task_flags & SLAPI_TASK_RUNNING_FROM_COMMANDLINE) { - dblayer_import_file_update(inst); --- -2.21.1 - diff --git a/SOURCES/0023-Issue-49254-Fix-compiler-failures-and-warnings.patch b/SOURCES/0023-Issue-49254-Fix-compiler-failures-and-warnings.patch deleted file mode 100644 index b6a9ffa..0000000 --- a/SOURCES/0023-Issue-49254-Fix-compiler-failures-and-warnings.patch +++ /dev/null @@ -1,240 +0,0 @@ -From 585d536de6927cf47ef817f541db392dfca4526b Mon Sep 17 00:00:00 2001 -From: Mark Reynolds -Date: Wed, 22 Jan 2020 15:10:04 -0500 -Subject: [PATCH] Issue 49254 - Fix compiler failures and warnings - -Description: Fix issues with new gcc compiler flag "-fno-common", - and clean up doxygen warnings around libsds - -relates: https://pagure.io/389-ds-base/issue/49254 - -Reviewed by: mhonek, spichugi, and tbordaz (Thanks!!!) ---- - docs/slapi.doxy.in | 2 - - ldap/servers/plugins/acl/acl.c | 1 + - ldap/servers/plugins/acl/acl.h | 4 +- - ldap/servers/plugins/acl/acl_ext.c | 2 + - ldap/servers/slapd/result.c | 8 ++-- - ldap/servers/slapd/slap.h | 4 +- - ldap/servers/slapd/tools/ldclt/ldapfct.c | 2 +- - src/libsds/include/sds.h | 56 ++++++++++++++---------- - 8 files changed, 47 insertions(+), 32 deletions(-) - -diff --git a/docs/slapi.doxy.in b/docs/slapi.doxy.in -index 2cc2d5f47..b1e4810ab 100644 ---- a/docs/slapi.doxy.in -+++ b/docs/slapi.doxy.in -@@ -760,7 +760,6 @@ WARN_LOGFILE = - - INPUT = src/libsds/include/sds.h \ - docs/job-safety.md \ -- src/nunc-stans/include/nunc-stans.h - # ldap/servers/slapd/slapi-plugin.h \ - - # This tag can be used to specify the character encoding of the source files -@@ -1101,7 +1100,6 @@ HTML_EXTRA_STYLESHEET = docs/custom.css - - # HTML_EXTRA_FILES = docs/nunc-stans-intro.png \ - # docs/nunc-stans-job-states.png --HTML_EXTRA_FILES = docs/nunc-stans-job-states.png - - # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen - # will adjust the colors in the style sheet and background images according to -diff --git a/ldap/servers/plugins/acl/acl.c b/ldap/servers/plugins/acl/acl.c -index 5680de669..41a909a18 100644 ---- a/ldap/servers/plugins/acl/acl.c -+++ b/ldap/servers/plugins/acl/acl.c -@@ -13,6 +13,7 @@ - - #include "acl.h" - -+ - /**************************************************************************** - * - * acl.c -diff --git a/ldap/servers/plugins/acl/acl.h b/ldap/servers/plugins/acl/acl.h -index 5d453d825..becc7f920 100644 ---- a/ldap/servers/plugins/acl/acl.h -+++ b/ldap/servers/plugins/acl/acl.h -@@ -311,8 +311,8 @@ typedef struct aci - #define ATTR_ACLPB_MAX_SELECTED_ACLS "nsslapd-aclpb-max-selected-acls" - #define DEFAULT_ACLPB_MAX_SELECTED_ACLS 200 - --int aclpb_max_selected_acls; /* initialized from plugin config entry */ --int aclpb_max_cache_results; /* initialized from plugin config entry */ -+extern int aclpb_max_selected_acls; /* initialized from plugin config entry */ -+extern int aclpb_max_cache_results; /* initialized from plugin config entry */ - - typedef struct result_cache - { -diff --git a/ldap/servers/plugins/acl/acl_ext.c b/ldap/servers/plugins/acl/acl_ext.c -index 31c61c2f4..797c5d2fd 100644 ---- a/ldap/servers/plugins/acl/acl_ext.c -+++ b/ldap/servers/plugins/acl/acl_ext.c -@@ -23,6 +23,8 @@ static int acl__put_aclpb_back_to_pool(Acl_PBlock *aclpb); - static Acl_PBlock *acl__malloc_aclpb(void); - static void acl__free_aclpb(Acl_PBlock **aclpb_ptr); - -+int aclpb_max_selected_acls = DEFAULT_ACLPB_MAX_SELECTED_ACLS; -+int aclpb_max_cache_results = DEFAULT_ACLPB_MAX_SELECTED_ACLS; - - struct acl_pbqueue - { -diff --git a/ldap/servers/slapd/result.c b/ldap/servers/slapd/result.c -index 89f776716..0b13c30e9 100644 ---- a/ldap/servers/slapd/result.c -+++ b/ldap/servers/slapd/result.c -@@ -1954,9 +1954,11 @@ notes2str(unsigned int notes, char *buf, size_t buflen) - */ - buflen -= len; - p += len; -- /* Put in the end quote, then back track p. */ -- *p++ = '"'; -- *p--; -+ /* -+ * Put in the end quote. If another snp_detail is append a comma -+ * will overwrite the quote. -+ */ -+ *(p + 1) = '"'; - } - } - -diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h -index d73e9aaae..44f6be97a 100644 ---- a/ldap/servers/slapd/slap.h -+++ b/ldap/servers/slapd/slap.h -@@ -935,7 +935,7 @@ enum - }; - - /* DataList definition */ --struct datalist -+typedef struct datalist - { - void **elements; /* array of elements */ - int element_count; /* number of elements in the array */ -@@ -1737,7 +1737,7 @@ typedef struct conn - * * Online tasks interface (to support import, export, etc) - * * After some cleanup, we could consider making these public. - * */ --struct slapi_task -+typedef struct slapi_task - { - struct slapi_task *next; - char *task_dn; -diff --git a/ldap/servers/slapd/tools/ldclt/ldapfct.c b/ldap/servers/slapd/tools/ldclt/ldapfct.c -index ca0912d6c..dbfc553d3 100644 ---- a/ldap/servers/slapd/tools/ldclt/ldapfct.c -+++ b/ldap/servers/slapd/tools/ldclt/ldapfct.c -@@ -698,7 +698,7 @@ connectToLDAP(thread_context *tttctx, const char *bufBindDN, const char *bufPass - } - if (mode & VERY_VERBOSE) - printf("ldclt[%d]: T%03d: Before ldap_simple_bind_s (%s, %s)\n", -- mctx.pid, thrdNum, binddn, -+ mctx.pid, thrdNum, binddn ? binddn : "Anonymous", - passwd ? passwd : "NO PASSWORD PROVIDED"); - ret = ldap_sasl_bind_s(ld, binddn, - LDAP_SASL_SIMPLE, &cred, NULL, NULL, &servercredp); /*JLS 05-01-01*/ -diff --git a/src/libsds/include/sds.h b/src/libsds/include/sds.h -index c649c036d..3f0dd8684 100644 ---- a/src/libsds/include/sds.h -+++ b/src/libsds/include/sds.h -@@ -221,13 +221,13 @@ void sds_free(void *ptr); - * sds_crc32c uses the crc32c algorithm to create a verification checksum of data. - * This checksum is for data verification, not cryptographic purposes. It is used - * largely in debugging to find cases when bytes in structures are updated incorrectly, -- * or to find memory bit flips during operation. If avaliable, this will use the -+ * or to find memory bit flips during operation. If available, this will use the - * intel sse4 crc32c hardware acceleration. - * - * \param crc The running CRC value. Initially should be 0. If in doubt, use 0. - * \param data Pointer to the data to checksum. - * \param length number of bytes to validate. -- * \retval crc The crc of this data. May be re-used in subsequent sds_crc32c calls -+ * \retval rcrc The crc of this data. May be re-used in subsequent sds_crc32c calls - * for certain datatypes. - */ - uint32_t sds_crc32c(uint32_t crc, const unsigned char *data, size_t length); -@@ -1356,48 +1356,60 @@ typedef enum _sds_ht_slot_state { - SDS_HT_BRANCH = 2, - } sds_ht_slot_state; - -+/** -+ * ht values -+ */ - typedef struct _sds_ht_value - { -- uint32_t checksum; -- void *key; -- void *value; -+ uint32_t checksum; /**< the checksum */ -+ void *key; /**< the key */ -+ void *value; /**< the key value */ - // may make this a LL of values later for collisions - } sds_ht_value; - -+/** -+ * ht slot -+ */ - typedef struct _sds_ht_slot - { -- sds_ht_slot_state state; -+ sds_ht_slot_state state; /**< the checksum */ - union - { - sds_ht_value *value; - struct _sds_ht_node *node; -- } slot; -+ } slot; /**< slot union */ - } sds_ht_slot; - -+/** -+ * ht node -+ */ - typedef struct _sds_ht_node - { -- uint32_t checksum; -- uint64_t txn_id; -- uint_fast32_t count; -+ uint32_t checksum; /**< the checksum */ -+ uint64_t txn_id; /**< transaction id */ -+ uint_fast32_t count; /**< the count */ - #ifdef SDS_DEBUG - uint64_t depth; - #endif -- struct _sds_ht_node *parent; -- size_t parent_slot; -- sds_ht_slot slots[HT_SLOTS]; -+ struct _sds_ht_node *parent; /**< the parent */ -+ size_t parent_slot; /**< the parent slot */ -+ sds_ht_slot slots[HT_SLOTS]; /**< the slots */ - } sds_ht_node; - -+/** -+ * ht instance -+ */ - typedef struct _sds_ht_instance - { -- uint32_t checksum; -- char hkey[16]; -- sds_ht_node *root; -- int64_t (*key_cmp_fn)(void *a, void *b); -- uint64_t (*key_size_fn)(void *key); -- void *(*key_dup_fn)(void *key); -- void (*key_free_fn)(void *key); -- void *(*value_dup_fn)(void *value); -- void (*value_free_fn)(void *value); -+ uint32_t checksum; /**< the checksum */ -+ char hkey[16]; /**< the key */ -+ sds_ht_node *root; /**< the root */ -+ int64_t (*key_cmp_fn)(void *a, void *b); /**< the keycompare function */ -+ uint64_t (*key_size_fn)(void *key); /**< the key size function */ -+ void *(*key_dup_fn)(void *key); /**< the key dup function */ -+ void (*key_free_fn)(void *key); /**< the key free function */ -+ void *(*value_dup_fn)(void *value); /**< the value dup function */ -+ void (*value_free_fn)(void *value); /**< the value free function */ - } sds_ht_instance; - - uint64_t sds_uint64_t_size(void *key); --- -2.21.1 - diff --git a/SOURCES/0023-Issue-51086-Fix-instance-name-length-for-interactive.patch b/SOURCES/0023-Issue-51086-Fix-instance-name-length-for-interactive.patch new file mode 100644 index 0000000..90c275e --- /dev/null +++ b/SOURCES/0023-Issue-51086-Fix-instance-name-length-for-interactive.patch @@ -0,0 +1,33 @@ +From 5e0a2d34f1c03a7d6a1c8591896a21e122d90d6b Mon Sep 17 00:00:00 2001 +From: Simon Pichugin +Date: Thu, 23 Jul 2020 23:45:18 +0200 +Subject: [PATCH] Issue 51086 - Fix instance name length for interactive + install + +Description: Instance name lenght is not properly validated +during interactive install. Add a check during a user input. + +https://pagure.io/389-ds-base/issue/51086 + +Reviewed by: mreynolds (Thanks!) +--- + src/lib389/lib389/instance/setup.py | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/lib389/lib389/instance/setup.py b/src/lib389/lib389/instance/setup.py +index f5fc5495d..45c7dfdd4 100644 +--- a/src/lib389/lib389/instance/setup.py ++++ b/src/lib389/lib389/instance/setup.py +@@ -308,6 +308,9 @@ class SetupDs(object): + + val = input('\nEnter the instance name [{}]: '.format(slapd['instance_name'])).rstrip() + if val != "": ++ if len(val) > 80: ++ print("Server identifier should not be longer than 80 symbols") ++ continue + if not all(ord(c) < 128 for c in val): + print("Server identifier can not contain non ascii characters") + continue +-- +2.26.2 + diff --git a/SOURCES/0024-Issue-49990-Need-to-enforce-a-hard-maximum-limit-for.patch b/SOURCES/0024-Issue-49990-Need-to-enforce-a-hard-maximum-limit-for.patch deleted file mode 100644 index 74a41a9..0000000 --- a/SOURCES/0024-Issue-49990-Need-to-enforce-a-hard-maximum-limit-for.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 34c90ca8448890a439aa4282025955b0dfcfb1c3 Mon Sep 17 00:00:00 2001 -From: Mark Reynolds -Date: Thu, 23 Jan 2020 14:38:13 -0500 -Subject: [PATCH 01/12] Issue 49990 - Need to enforce a hard maximum limit for - file descriptors - -Description: on some platforms the maximum FD limit is high it can cause - a OOM at server startup. So we need to add a hard maximum - limit. - -relates: https://pagure.io/389-ds-base/issue/49990 - -Reviewed by: firstyear & tbordaz (Thanks!!) ---- - ldap/servers/slapd/libglobs.c | 10 +++++++--- - ldap/servers/slapd/slap.h | 4 ++-- - 2 files changed, 9 insertions(+), 5 deletions(-) - -diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c -index 66170ebc6..348de43cd 100644 ---- a/ldap/servers/slapd/libglobs.c -+++ b/ldap/servers/slapd/libglobs.c -@@ -1559,7 +1559,9 @@ FrontendConfig_init(void) - #endif - /* Default the maximum fd's to the maximum allowed */ - if (getrlimit(RLIMIT_NOFILE, &rlp) == 0) { -- maxdescriptors = (int64_t)rlp.rlim_max; -+ if ((int64_t)rlp.rlim_max < SLAPD_DEFAULT_MAXDESCRIPTORS) { -+ maxdescriptors = (int64_t)rlp.rlim_max; -+ } - } - - /* Take the lock to make sure we barrier correctly. */ -@@ -4324,7 +4326,7 @@ config_set_maxdescriptors(const char *attrname, char *value, char *errorbuf, int - { - int32_t retVal = LDAP_SUCCESS; - int64_t nValue = 0; -- int64_t maxVal = 524288; -+ int64_t maxVal = SLAPD_DEFAULT_MAXDESCRIPTORS; - struct rlimit rlp; - char *endp = NULL; - -@@ -4335,7 +4337,9 @@ config_set_maxdescriptors(const char *attrname, char *value, char *errorbuf, int - } - - if (0 == getrlimit(RLIMIT_NOFILE, &rlp)) { -- maxVal = (int)rlp.rlim_max; -+ if ((int64_t)rlp.rlim_max < maxVal) { -+ maxVal = (int64_t)rlp.rlim_max; -+ } - } - - errno = 0; -diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h -index 44f6be97a..96ce7d402 100644 ---- a/ldap/servers/slapd/slap.h -+++ b/ldap/servers/slapd/slap.h -@@ -348,8 +348,8 @@ typedef void (*VFPV)(); /* takes undefined arguments */ - - #define SLAPD_DEFAULT_PAGEDSIZELIMIT 0 - #define SLAPD_DEFAULT_PAGEDSIZELIMIT_STR "0" --#define SLAPD_DEFAULT_MAXDESCRIPTORS 8192 --#define SLAPD_DEFAULT_MAXDESCRIPTORS_STR "8192" -+#define SLAPD_DEFAULT_MAXDESCRIPTORS 1048576 -+#define SLAPD_DEFAULT_MAXDESCRIPTORS_STR "1048576" - #define SLAPD_DEFAULT_MAX_FILTER_NEST_LEVEL 40 - #define SLAPD_DEFAULT_MAX_FILTER_NEST_LEVEL_STR "40" - #define SLAPD_DEFAULT_GROUPEVALNESTLEVEL 0 --- -2.21.1 - diff --git a/SOURCES/0024-Issue-51129-SSL-alert-The-value-of-sslVersionMax-TLS.patch b/SOURCES/0024-Issue-51129-SSL-alert-The-value-of-sslVersionMax-TLS.patch new file mode 100644 index 0000000..a4c26cc --- /dev/null +++ b/SOURCES/0024-Issue-51129-SSL-alert-The-value-of-sslVersionMax-TLS.patch @@ -0,0 +1,360 @@ +From 3e11020fa7a79d335a02c001435aabcf59aaa622 Mon Sep 17 00:00:00 2001 +From: Mark Reynolds +Date: Fri, 24 Jul 2020 12:14:44 -0400 +Subject: [PATCH] Issue 51129 - SSL alert: The value of sslVersionMax "TLS1.3" + is higher than the supported version + +Bug Description: If you try and set the sslVersionMax higher than the + default range, but within the supported range, you + would still get an error and the server would reset + the max to "default" max value. + +Fix Description: Keep track of both the supported and default SSL ranges, + and correctly use each range for value validation. If + the value is outside the supported range, then use default + value, etc, but do not check the requested range against + the default range. We only use the default range if + there is no specified min or max in the config, or if + a invalid min or max value is set in the config. + + Also, refactored the range variable names to be more + accurate: + + enabledNSSVersions --> defaultNSSVersions + emin, emax --> dmin, dmax + +relates: https://pagure.io/389-ds-base/issue/51129 + +Reviewed by: firstyear(Thanks!) +--- + ldap/servers/slapd/ssl.c | 155 ++++++++++++++++---------------- + src/lib389/lib389/dirsrv_log.py | 2 +- + 2 files changed, 81 insertions(+), 76 deletions(-) + +diff --git a/ldap/servers/slapd/ssl.c b/ldap/servers/slapd/ssl.c +index 846106b42..7206cafd2 100644 +--- a/ldap/servers/slapd/ssl.c ++++ b/ldap/servers/slapd/ssl.c +@@ -50,11 +50,11 @@ + ******************************************************************************/ + + #define DEFVERSION "TLS1.2" +-#define CURRENT_DEFAULT_SSL_VERSION SSL_LIBRARY_VERSION_TLS_1_2 + + extern char *slapd_SSL3ciphers; + extern symbol_t supported_ciphers[]; +-static SSLVersionRange enabledNSSVersions; ++static SSLVersionRange defaultNSSVersions; ++static SSLVersionRange supportedNSSVersions; + static SSLVersionRange slapdNSSVersions; + + +@@ -1014,15 +1014,24 @@ slapd_nss_init(int init_ssl __attribute__((unused)), int config_available __attr + int create_certdb = 0; + PRUint32 nssFlags = 0; + char *certdir; +- char emin[VERSION_STR_LENGTH], emax[VERSION_STR_LENGTH]; +- /* Get the range of the supported SSL version */ +- SSL_VersionRangeGetDefault(ssl_variant_stream, &enabledNSSVersions); ++ char dmin[VERSION_STR_LENGTH], dmax[VERSION_STR_LENGTH]; ++ char smin[VERSION_STR_LENGTH], smax[VERSION_STR_LENGTH]; + +- (void)slapi_getSSLVersion_str(enabledNSSVersions.min, emin, sizeof(emin)); +- (void)slapi_getSSLVersion_str(enabledNSSVersions.max, emax, sizeof(emax)); ++ /* Get the range of the supported SSL version */ ++ SSL_VersionRangeGetSupported(ssl_variant_stream, &supportedNSSVersions); ++ (void)slapi_getSSLVersion_str(supportedNSSVersions.min, smin, sizeof(smin)); ++ (void)slapi_getSSLVersion_str(supportedNSSVersions.max, smax, sizeof(smax)); ++ ++ /* Get the enabled default range */ ++ SSL_VersionRangeGetDefault(ssl_variant_stream, &defaultNSSVersions); ++ (void)slapi_getSSLVersion_str(defaultNSSVersions.min, dmin, sizeof(dmin)); ++ (void)slapi_getSSLVersion_str(defaultNSSVersions.max, dmax, sizeof(dmax)); + slapi_log_err(SLAPI_LOG_CONFIG, "Security Initialization", + "slapd_nss_init - Supported range by NSS: min: %s, max: %s\n", +- emin, emax); ++ smin, smax); ++ slapi_log_err(SLAPI_LOG_CONFIG, "Security Initialization", ++ "slapd_nss_init - Enabled default range by NSS: min: %s, max: %s\n", ++ dmin, dmax); + + /* set in slapd_bootstrap_config, + thus certdir is available even if config_available is false +@@ -1344,21 +1353,21 @@ static int + set_NSS_version(char *val, PRUint16 *rval, int ismin) + { + char *vp; +- char emin[VERSION_STR_LENGTH], emax[VERSION_STR_LENGTH]; ++ char dmin[VERSION_STR_LENGTH], dmax[VERSION_STR_LENGTH]; + + if (NULL == rval) { + return 1; + } +- (void)slapi_getSSLVersion_str(enabledNSSVersions.min, emin, sizeof(emin)); +- (void)slapi_getSSLVersion_str(enabledNSSVersions.max, emax, sizeof(emax)); ++ (void)slapi_getSSLVersion_str(defaultNSSVersions.min, dmin, sizeof(dmin)); ++ (void)slapi_getSSLVersion_str(defaultNSSVersions.max, dmax, sizeof(dmax)); + + if (!strncasecmp(val, SSLSTR, SSLLEN)) { /* ssl# NOT SUPPORTED */ + if (ismin) { +- slapd_SSL_warn("SSL3 is no longer supported. Using NSS default min value: %s\n", emin); +- (*rval) = enabledNSSVersions.min; ++ slapd_SSL_warn("SSL3 is no longer supported. Using NSS default min value: %s", dmin); ++ (*rval) = defaultNSSVersions.min; + } else { +- slapd_SSL_warn("SSL3 is no longer supported. Using NSS default max value: %s\n", emax); +- (*rval) = enabledNSSVersions.max; ++ slapd_SSL_warn("SSL3 is no longer supported. Using NSS default max value: %s", dmax); ++ (*rval) = defaultNSSVersions.max; + } + } else if (!strncasecmp(val, TLSSTR, TLSLEN)) { /* tls# */ + float tlsv; +@@ -1366,122 +1375,122 @@ set_NSS_version(char *val, PRUint16 *rval, int ismin) + sscanf(vp, "%4f", &tlsv); + if (tlsv < 1.1f) { /* TLS1.0 */ + if (ismin) { +- if (enabledNSSVersions.min > CURRENT_DEFAULT_SSL_VERSION) { ++ if (supportedNSSVersions.min > SSL_LIBRARY_VERSION_TLS_1_0) { + slapd_SSL_warn("The value of sslVersionMin " + "\"%s\" is lower than the supported version; " + "the default value \"%s\" is used.", +- val, emin); +- (*rval) = enabledNSSVersions.min; ++ val, dmin); ++ (*rval) = defaultNSSVersions.min; + } else { + (*rval) = SSL_LIBRARY_VERSION_TLS_1_0; + } + } else { +- if (enabledNSSVersions.max < CURRENT_DEFAULT_SSL_VERSION) { ++ if (supportedNSSVersions.max < SSL_LIBRARY_VERSION_TLS_1_0) { + /* never happens */ + slapd_SSL_warn("The value of sslVersionMax " + "\"%s\" is higher than the supported version; " + "the default value \"%s\" is used.", +- val, emax); +- (*rval) = enabledNSSVersions.max; ++ val, dmax); ++ (*rval) = defaultNSSVersions.max; + } else { + (*rval) = SSL_LIBRARY_VERSION_TLS_1_0; + } + } + } else if (tlsv < 1.2f) { /* TLS1.1 */ + if (ismin) { +- if (enabledNSSVersions.min > SSL_LIBRARY_VERSION_TLS_1_1) { ++ if (supportedNSSVersions.min > SSL_LIBRARY_VERSION_TLS_1_1) { + slapd_SSL_warn("The value of sslVersionMin " + "\"%s\" is lower than the supported version; " + "the default value \"%s\" is used.", +- val, emin); +- (*rval) = enabledNSSVersions.min; ++ val, dmin); ++ (*rval) = defaultNSSVersions.min; + } else { + (*rval) = SSL_LIBRARY_VERSION_TLS_1_1; + } + } else { +- if (enabledNSSVersions.max < SSL_LIBRARY_VERSION_TLS_1_1) { ++ if (supportedNSSVersions.max < SSL_LIBRARY_VERSION_TLS_1_1) { + /* never happens */ + slapd_SSL_warn("The value of sslVersionMax " + "\"%s\" is higher than the supported version; " + "the default value \"%s\" is used.", +- val, emax); +- (*rval) = enabledNSSVersions.max; ++ val, dmax); ++ (*rval) = defaultNSSVersions.max; + } else { + (*rval) = SSL_LIBRARY_VERSION_TLS_1_1; + } + } + } else if (tlsv < 1.3f) { /* TLS1.2 */ + if (ismin) { +- if (enabledNSSVersions.min > SSL_LIBRARY_VERSION_TLS_1_2) { ++ if (supportedNSSVersions.min > SSL_LIBRARY_VERSION_TLS_1_2) { + slapd_SSL_warn("The value of sslVersionMin " + "\"%s\" is lower than the supported version; " + "the default value \"%s\" is used.", +- val, emin); +- (*rval) = enabledNSSVersions.min; ++ val, dmin); ++ (*rval) = defaultNSSVersions.min; + } else { + (*rval) = SSL_LIBRARY_VERSION_TLS_1_2; + } + } else { +- if (enabledNSSVersions.max < SSL_LIBRARY_VERSION_TLS_1_2) { ++ if (supportedNSSVersions.max < SSL_LIBRARY_VERSION_TLS_1_2) { + /* never happens */ + slapd_SSL_warn("The value of sslVersionMax " + "\"%s\" is higher than the supported version; " + "the default value \"%s\" is used.", +- val, emax); +- (*rval) = enabledNSSVersions.max; ++ val, dmax); ++ (*rval) = defaultNSSVersions.max; + } else { + (*rval) = SSL_LIBRARY_VERSION_TLS_1_2; + } + } + } else if (tlsv < 1.4f) { /* TLS1.3 */ +- if (ismin) { +- if (enabledNSSVersions.min > SSL_LIBRARY_VERSION_TLS_1_3) { +- slapd_SSL_warn("The value of sslVersionMin " +- "\"%s\" is lower than the supported version; " +- "the default value \"%s\" is used.", +- val, emin); +- (*rval) = enabledNSSVersions.min; +- } else { +- (*rval) = SSL_LIBRARY_VERSION_TLS_1_3; +- } +- } else { +- if (enabledNSSVersions.max < SSL_LIBRARY_VERSION_TLS_1_3) { +- /* never happens */ +- slapd_SSL_warn("The value of sslVersionMax " +- "\"%s\" is higher than the supported version; " +- "the default value \"%s\" is used.", +- val, emax); +- (*rval) = enabledNSSVersions.max; +- } else { +- (*rval) = SSL_LIBRARY_VERSION_TLS_1_3; +- } +- } ++ if (ismin) { ++ if (supportedNSSVersions.min > SSL_LIBRARY_VERSION_TLS_1_3) { ++ slapd_SSL_warn("The value of sslVersionMin " ++ "\"%s\" is lower than the supported version; " ++ "the default value \"%s\" is used.", ++ val, dmin); ++ (*rval) = defaultNSSVersions.min; ++ } else { ++ (*rval) = SSL_LIBRARY_VERSION_TLS_1_3; ++ } ++ } else { ++ if (supportedNSSVersions.max < SSL_LIBRARY_VERSION_TLS_1_3) { ++ /* never happens */ ++ slapd_SSL_warn("The value of sslVersionMax " ++ "\"%s\" is higher than the supported version; " ++ "the default value \"%s\" is used.", ++ val, dmax); ++ (*rval) = defaultNSSVersions.max; ++ } else { ++ (*rval) = SSL_LIBRARY_VERSION_TLS_1_3; ++ } ++ } + } else { /* Specified TLS is newer than supported */ + if (ismin) { + slapd_SSL_warn("The value of sslVersionMin " + "\"%s\" is out of the range of the supported version; " + "the default value \"%s\" is used.", +- val, emin); +- (*rval) = enabledNSSVersions.min; ++ val, dmin); ++ (*rval) = defaultNSSVersions.min; + } else { + slapd_SSL_warn("The value of sslVersionMax " + "\"%s\" is out of the range of the supported version; " + "the default value \"%s\" is used.", +- val, emax); +- (*rval) = enabledNSSVersions.max; ++ val, dmax); ++ (*rval) = defaultNSSVersions.max; + } + } + } else { + if (ismin) { + slapd_SSL_warn("The value of sslVersionMin " + "\"%s\" is invalid; the default value \"%s\" is used.", +- val, emin); +- (*rval) = enabledNSSVersions.min; ++ val, dmin); ++ (*rval) = defaultNSSVersions.min; + } else { + slapd_SSL_warn("The value of sslVersionMax " + "\"%s\" is invalid; the default value \"%s\" is used.", +- val, emax); +- (*rval) = enabledNSSVersions.max; ++ val, dmax); ++ (*rval) = defaultNSSVersions.max; + } + } + return 0; +@@ -1511,10 +1520,9 @@ slapd_ssl_init2(PRFileDesc **fd, int startTLS) + char *tmpDir; + Slapi_Entry *e = NULL; + PRBool fipsMode = PR_FALSE; +- PRUint16 NSSVersionMin = enabledNSSVersions.min; +- PRUint16 NSSVersionMax = enabledNSSVersions.max; ++ PRUint16 NSSVersionMin = defaultNSSVersions.min; ++ PRUint16 NSSVersionMax = defaultNSSVersions.max; + char mymin[VERSION_STR_LENGTH], mymax[VERSION_STR_LENGTH]; +- char newmax[VERSION_STR_LENGTH]; + int allowweakcipher = CIPHER_SET_DEFAULTWEAKCIPHER; + int_fast16_t renegotiation = (int_fast16_t)SSL_RENEGOTIATE_REQUIRES_XTN; + +@@ -1875,12 +1883,9 @@ slapd_ssl_init2(PRFileDesc **fd, int startTLS) + if (NSSVersionMin > NSSVersionMax) { + (void)slapi_getSSLVersion_str(NSSVersionMin, mymin, sizeof(mymin)); + (void)slapi_getSSLVersion_str(NSSVersionMax, mymax, sizeof(mymax)); +- slapd_SSL_warn("The min value of NSS version range \"%s\" is greater than the max value \"%s\".", ++ slapd_SSL_warn("The min value of NSS version range \"%s\" is greater than the max value \"%s\". Adjusting the max to match the miniumum.", + mymin, mymax); +- (void)slapi_getSSLVersion_str(enabledNSSVersions.max, newmax, sizeof(newmax)); +- slapd_SSL_warn("Reset the max \"%s\" to supported max \"%s\".", +- mymax, newmax); +- NSSVersionMax = enabledNSSVersions.max; ++ NSSVersionMax = NSSVersionMin; + } + } + +@@ -1896,7 +1901,7 @@ slapd_ssl_init2(PRFileDesc **fd, int startTLS) + if (sslStatus != SECSuccess) { + errorCode = PR_GetError(); + slapd_SSL_error("Security Initialization - " +- "slapd_ssl_init2 - Failed to set SSL range: min: %s, max: %s - error %d (%s)\n", ++ "slapd_ssl_init2 - Failed to set SSL range: min: %s, max: %s - error %d (%s)", + mymin, mymax, errorCode, slapd_pr_strerror(errorCode)); + } + /* +@@ -1926,13 +1931,13 @@ slapd_ssl_init2(PRFileDesc **fd, int startTLS) + (void)slapi_getSSLVersion_str(slapdNSSVersions.min, mymin, sizeof(mymin)); + (void)slapi_getSSLVersion_str(slapdNSSVersions.max, mymax, sizeof(mymax)); + slapd_SSL_error("Security Initialization - " +- "slapd_ssl_init2 - Failed to set SSL range: min: %s, max: %s - error %d (%s)\n", ++ "slapd_ssl_init2 - Failed to set SSL range: min: %s, max: %s - error %d (%s)", + mymin, mymax, errorCode, slapd_pr_strerror(errorCode)); + } + } else { + errorCode = PR_GetError(); + slapd_SSL_error("Security Initialization - ", +- "slapd_ssl_init2 - Failed to get SSL range from socket - error %d (%s)\n", ++ "slapd_ssl_init2 - Failed to get SSL range from socket - error %d (%s)", + errorCode, slapd_pr_strerror(errorCode)); + } + +@@ -2265,7 +2270,7 @@ slapd_SSL_client_auth(LDAP *ld) + } + } else { + if (token == NULL) { +- slapd_SSL_warn("slapd_SSL_client_auth - certificate token was not found\n"); ++ slapd_SSL_warn("slapd_SSL_client_auth - certificate token was not found"); + } + rc = -1; + } +diff --git a/src/lib389/lib389/dirsrv_log.py b/src/lib389/lib389/dirsrv_log.py +index 7bed4bb17..ab8872051 100644 +--- a/src/lib389/lib389/dirsrv_log.py ++++ b/src/lib389/lib389/dirsrv_log.py +@@ -207,7 +207,7 @@ class DirsrvAccessLog(DirsrvLog): + return { + 'base': quoted_vals[0], + 'filter': quoted_vals[1], +- 'timestamp': re.findall('\[(.*)\]', lines[0])[0], ++ 'timestamp': re.findall('[(.*)]', lines[0])[0], + 'scope': lines[0].split(' scope=', 1)[1].split(' ',1)[0] + } + +-- +2.26.2 + diff --git a/SOURCES/0025-Issue-50850-Fix-dsctl-healthcheck-for-python36.patch b/SOURCES/0025-Issue-50850-Fix-dsctl-healthcheck-for-python36.patch deleted file mode 100644 index 6dab88e..0000000 --- a/SOURCES/0025-Issue-50850-Fix-dsctl-healthcheck-for-python36.patch +++ /dev/null @@ -1,43 +0,0 @@ -From b941befe083a02ed0e4d5bc6c3c50f1a82f04012 Mon Sep 17 00:00:00 2001 -From: Mark Reynolds -Date: Thu, 23 Jan 2020 12:22:21 -0500 -Subject: [PATCH] Issue 50850 - Fix dsctl healthcheck for python36 - -Description: dsctl health check, specifically the certificate expiring - checks, were using python37 specific functions, but these - do not work on python36. Needed to replace fromisoformat() - with something more portable. - -relates: https://pagure.io/389-ds-base/issue/50850 - -Reviewed by: firstyear(Thanks!) ---- - src/lib389/lib389/nss_ssl.py | 8 +++++--- - 1 file changed, 5 insertions(+), 3 deletions(-) - -diff --git a/src/lib389/lib389/nss_ssl.py b/src/lib389/lib389/nss_ssl.py -index 2a7d1637c..41b19caa4 100644 ---- a/src/lib389/lib389/nss_ssl.py -+++ b/src/lib389/lib389/nss_ssl.py -@@ -79,13 +79,15 @@ class NssSsl(object): - cert_list.append(self.get_cert_details(cert[0])) - - for cert in cert_list: -- if date.fromisoformat(cert[3].split()[0]) - date.today() < timedelta(days=0): -+ cert_date = cert[3].split()[0] -+ diff_date = datetime.strptime(cert_date, '%Y-%m-%d').date() - datetime.today().date() -+ if diff_date < timedelta(days=0): - # Expired - report = copy.deepcopy(DSCERTLE0002) - report['detail'] = report['detail'].replace('CERT', cert[0]) - yield report -- elif date.fromisoformat(cert[3].split()[0]) - date.today() < timedelta(days=30): -- # Expiring -+ elif diff_date < timedelta(days=30): -+ # Expiring within 30 days - report = copy.deepcopy(DSCERTLE0001) - report['detail'] = report['detail'].replace('CERT', cert[0]) - yield report --- -2.21.1 - diff --git a/SOURCES/0025-Issue-50984-Memory-leaks-in-disk-monitoring.patch b/SOURCES/0025-Issue-50984-Memory-leaks-in-disk-monitoring.patch new file mode 100644 index 0000000..5f8d129 --- /dev/null +++ b/SOURCES/0025-Issue-50984-Memory-leaks-in-disk-monitoring.patch @@ -0,0 +1,202 @@ +From 68ca1de0f39c11056a57b03a544520bd6708d855 Mon Sep 17 00:00:00 2001 +From: Simon Pichugin +Date: Thu, 11 Jun 2020 15:39:59 +0200 +Subject: [PATCH] Issue 50984 - Memory leaks in disk monitoring + +Description: Fix the rest of the leaks in disk monitoring +which are present when we shutdown while being below half +of the threshold (at the start-up in main.c). + +Free directories, sockets and ports before going to cleanup. + +https://pagure.io/389-ds-base/issue/50984 + +Reviewed by: mhonek, tbordaz (Thanks!) +--- + ldap/servers/slapd/daemon.c | 75 ++++++++++++++++++++----------------- + ldap/servers/slapd/fe.h | 1 + + ldap/servers/slapd/main.c | 49 +++++++++++++----------- + 3 files changed, 70 insertions(+), 55 deletions(-) + +diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c +index a70f40316..7091b570d 100644 +--- a/ldap/servers/slapd/daemon.c ++++ b/ldap/servers/slapd/daemon.c +@@ -884,6 +884,46 @@ convert_pbe_des_to_aes(void) + charray_free(attrs); + } + ++void ++slapd_sockets_ports_free(daemon_ports_t *ports_info) ++{ ++ /* freeing PRFileDescs */ ++ PRFileDesc **fdesp = NULL; ++ for (fdesp = ports_info->n_socket; fdesp && *fdesp; fdesp++) { ++ PR_Close(*fdesp); ++ } ++ slapi_ch_free((void **)&ports_info->n_socket); ++ ++ for (fdesp = ports_info->s_socket; fdesp && *fdesp; fdesp++) { ++ PR_Close(*fdesp); ++ } ++ slapi_ch_free((void **)&ports_info->s_socket); ++#if defined(ENABLE_LDAPI) ++ for (fdesp = ports_info->i_socket; fdesp && *fdesp; fdesp++) { ++ PR_Close(*fdesp); ++ } ++ slapi_ch_free((void **)&ports_info->i_socket); ++#endif /* ENABLE_LDAPI */ ++ ++ /* freeing NetAddrs */ ++ PRNetAddr **nap; ++ for (nap = ports_info->n_listenaddr; nap && *nap; nap++) { ++ slapi_ch_free((void **)nap); ++ } ++ slapi_ch_free((void **)&ports_info->n_listenaddr); ++ ++ for (nap = ports_info->s_listenaddr; nap && *nap; nap++) { ++ slapi_ch_free((void **)nap); ++ } ++ slapi_ch_free((void **)&ports_info->s_listenaddr); ++#if defined(ENABLE_LDAPI) ++ for (nap = ports_info->i_listenaddr; nap && *nap; nap++) { ++ slapi_ch_free((void **)nap); ++ } ++ slapi_ch_free((void **)&ports_info->i_listenaddr); ++#endif ++} ++ + void + slapd_daemon(daemon_ports_t *ports) + { +@@ -1099,40 +1139,7 @@ slapd_daemon(daemon_ports_t *ports) + /* free the listener indexes */ + slapi_ch_free((void **)&listener_idxs); + +- for (fdesp = n_tcps; fdesp && *fdesp; fdesp++) { +- PR_Close(*fdesp); +- } +- slapi_ch_free((void **)&n_tcps); +- +- for (fdesp = i_unix; fdesp && *fdesp; fdesp++) { +- PR_Close(*fdesp); +- } +- slapi_ch_free((void **)&i_unix); +- +- for (fdesp = s_tcps; fdesp && *fdesp; fdesp++) { +- PR_Close(*fdesp); +- } +- slapi_ch_free((void **)&s_tcps); +- +- /* freeing NetAddrs */ +- { +- PRNetAddr **nap; +- for (nap = ports->n_listenaddr; nap && *nap; nap++) { +- slapi_ch_free((void **)nap); +- } +- slapi_ch_free((void **)&ports->n_listenaddr); +- +- for (nap = ports->s_listenaddr; nap && *nap; nap++) { +- slapi_ch_free((void **)nap); +- } +- slapi_ch_free((void **)&ports->s_listenaddr); +-#if defined(ENABLE_LDAPI) +- for (nap = ports->i_listenaddr; nap && *nap; nap++) { +- slapi_ch_free((void **)nap); +- } +- slapi_ch_free((void **)&ports->i_listenaddr); +-#endif +- } ++ slapd_sockets_ports_free(ports); + + op_thread_cleanup(); + housekeeping_stop(); /* Run this after op_thread_cleanup() logged sth */ +diff --git a/ldap/servers/slapd/fe.h b/ldap/servers/slapd/fe.h +index 2d9a0931b..9cd122881 100644 +--- a/ldap/servers/slapd/fe.h ++++ b/ldap/servers/slapd/fe.h +@@ -120,6 +120,7 @@ int connection_table_iterate_active_connections(Connection_Table *ct, void *arg, + */ + int signal_listner(void); + int daemon_pre_setuid_init(daemon_ports_t *ports); ++void slapd_sockets_ports_free(daemon_ports_t *ports_info); + void slapd_daemon(daemon_ports_t *ports); + void daemon_register_connection(void); + int slapd_listenhost2addr(const char *listenhost, PRNetAddr ***addr); +diff --git a/ldap/servers/slapd/main.c b/ldap/servers/slapd/main.c +index e54b8e1c5..9e5219c4a 100644 +--- a/ldap/servers/slapd/main.c ++++ b/ldap/servers/slapd/main.c +@@ -734,7 +734,6 @@ main(int argc, char **argv) + * etc the backends need to start + */ + +- + /* Important: up 'till here we could be running as root (on unix). + * we believe that we've not created any files before here, otherwise + * they'd be owned by root, which is bad. We're about to change identity +@@ -891,6 +890,34 @@ main(int argc, char **argv) + } + } + ++ if (config_get_disk_monitoring()) { ++ char **dirs = NULL; ++ char *dirstr = NULL; ++ uint64_t disk_space = 0; ++ int64_t threshold = 0; ++ uint64_t halfway = 0; ++ threshold = config_get_disk_threshold(); ++ halfway = threshold / 2; ++ disk_mon_get_dirs(&dirs); ++ dirstr = disk_mon_check_diskspace(dirs, threshold, &disk_space); ++ if (dirstr != NULL && disk_space < halfway) { ++ slapi_log_err(SLAPI_LOG_EMERG, "main", ++ "Disk Monitoring is enabled and disk space on (%s) is too far below the threshold(%" PRIu64 " bytes). Exiting now.\n", ++ dirstr, threshold); ++ slapi_ch_array_free(dirs); ++ /* ++ * We should free the structs we allocated for sockets and addresses ++ * as they would be freed at the slapd_daemon but it was not initiated ++ * at that point of start-up. ++ */ ++ slapd_sockets_ports_free(&ports_info); ++ return_value = 1; ++ goto cleanup; ++ } ++ slapi_ch_array_free(dirs); ++ dirs = NULL; ++ } ++ + /* initialize the normalized DN cache */ + if (ndn_cache_init() != 0) { + slapi_log_err(SLAPI_LOG_EMERG, "main", "Unable to create ndn cache\n"); +@@ -940,26 +967,6 @@ main(int argc, char **argv) + slapi_ch_free((void **)&versionstring); + } + +- if (config_get_disk_monitoring()) { +- char **dirs = NULL; +- char *dirstr = NULL; +- uint64_t disk_space = 0; +- int64_t threshold = 0; +- uint64_t halfway = 0; +- threshold = config_get_disk_threshold(); +- halfway = threshold / 2; +- disk_mon_get_dirs(&dirs); +- dirstr = disk_mon_check_diskspace(dirs, threshold, &disk_space); +- if (dirstr != NULL && disk_space < halfway) { +- slapi_log_err(SLAPI_LOG_EMERG, "main", +- "Disk Monitoring is enabled and disk space on (%s) is too far below the threshold(%" PRIu64 " bytes). Exiting now.\n", +- dirstr, threshold); +- return_value = 1; +- goto cleanup; +- } +- slapi_ch_array_free(dirs); +- dirs = NULL; +- } + /* log the max fd limit as it is typically set in env/systemd */ + slapi_log_err(SLAPI_LOG_INFO, "main", + "Setting the maximum file descriptor limit to: %ld\n", +-- +2.26.2 + diff --git a/SOURCES/0026-Ticket-49624-cont-DB-Deadlock-on-modrdn-appears-to-c.patch b/SOURCES/0026-Ticket-49624-cont-DB-Deadlock-on-modrdn-appears-to-c.patch deleted file mode 100644 index d32c476..0000000 --- a/SOURCES/0026-Ticket-49624-cont-DB-Deadlock-on-modrdn-appears-to-c.patch +++ /dev/null @@ -1,177 +0,0 @@ -From f9c0ae9e0c143359ef12c8f5ae3070e34afd5495 Mon Sep 17 00:00:00 2001 -From: Ludwig Krispenz -Date: Wed, 15 Jan 2020 13:40:36 +0100 -Subject: [PATCH] Ticket 49624 cont - DB Deadlock on modrdn appears to corrupt - database and entry cache - -Bug: If there are deadlocks a transaction will be retried. In the case - of modrdn operation there is an error in handling the newsuperior - dn, which has to be reset when the txn is repeated. - There is also an error in freeing the entry stored in the pblock which can - lead to a double free - There is also a memory leak for ec entries - -Fix: check if the newsuperior in the pblock was changed before the retry and - only then free and reset it. - check and protect pblock entry from double free - remove ec entry from cache - fix the txn_test_thread to run - - There is also a message at shutdown that entries remain in the entry cache - although no leaks are reported and a hash dump didn't show entries. - Change log level to avoid confusion - -Reviewed by: Thierry, William, Viktor - Thanks ---- - ldap/servers/slapd/back-ldbm/cache.c | 2 +- - .../slapd/back-ldbm/db-bdb/bdb_layer.c | 2 +- - ldap/servers/slapd/back-ldbm/ldbm_modrdn.c | 60 +++++++++++++------ - 3 files changed, 45 insertions(+), 19 deletions(-) - -diff --git a/ldap/servers/slapd/back-ldbm/cache.c b/ldap/servers/slapd/back-ldbm/cache.c -index a03cdaa83..89f958a35 100644 ---- a/ldap/servers/slapd/back-ldbm/cache.c -+++ b/ldap/servers/slapd/back-ldbm/cache.c -@@ -723,7 +723,7 @@ entrycache_clear_int(struct cache *cache) - } - cache->c_maxsize = size; - if (cache->c_curentries > 0) { -- slapi_log_err(SLAPI_LOG_WARNING, -+ slapi_log_err(SLAPI_LOG_CACHE, - "entrycache_clear_int", "There are still %" PRIu64 " entries " - "in the entry cache.\n", - cache->c_curentries); -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 5a6a2a2e5..36bf42dab 100644 ---- a/ldap/servers/slapd/back-ldbm/db-bdb/bdb_layer.c -+++ b/ldap/servers/slapd/back-ldbm/db-bdb/bdb_layer.c -@@ -3064,7 +3064,7 @@ txn_test_threadmain(void *param) - - txn_test_init_cfg(&cfg); - -- if(BDB_CONFIG(li)->bdb_enable_transactions) { -+ if(!BDB_CONFIG(li)->bdb_enable_transactions) { - goto end; - } - -diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c -index 433ed88fb..26698012a 100644 ---- a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c -+++ b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c -@@ -67,6 +67,7 @@ ldbm_back_modrdn(Slapi_PBlock *pb) - Slapi_DN *dn_newsuperiordn = NULL; - Slapi_DN dn_parentdn; - Slapi_DN *orig_dn_newsuperiordn = NULL; -+ Slapi_DN *pb_dn_newsuperiordn = NULL; /* used to check what is currently in the pblock */ - Slapi_Entry *target_entry = NULL; - Slapi_Entry *original_targetentry = NULL; - int rc; -@@ -248,30 +249,45 @@ ldbm_back_modrdn(Slapi_PBlock *pb) - slapi_sdn_set_dn_byref(&dn_newrdn, original_newrdn); - original_newrdn = slapi_ch_strdup(original_newrdn); - -- slapi_pblock_get(pb, SLAPI_MODRDN_NEWSUPERIOR_SDN, &dn_newsuperiordn); -- slapi_sdn_free(&dn_newsuperiordn); -- slapi_pblock_set(pb, SLAPI_MODRDN_NEWSUPERIOR_SDN, orig_dn_newsuperiordn); -- dn_newsuperiordn = slapi_sdn_dup(orig_dn_newsuperiordn); -+ /* we need to restart with the original newsuperiordn which could have -+ * been modified. So check what is in the pblock, if it was changed -+ * free it, reset orig dn in th epblock and recreate a working superior -+ */ -+ slapi_pblock_get(pb, SLAPI_MODRDN_NEWSUPERIOR_SDN, &pb_dn_newsuperiordn); -+ if (pb_dn_newsuperiordn != orig_dn_newsuperiordn) { -+ slapi_sdn_free(&pb_dn_newsuperiordn); -+ slapi_pblock_set(pb, SLAPI_MODRDN_NEWSUPERIOR_SDN, orig_dn_newsuperiordn); -+ dn_newsuperiordn = slapi_sdn_dup(orig_dn_newsuperiordn); -+ } - /* must duplicate ec before returning it to cache, - * which could free the entry. */ -- if ((tmpentry = backentry_dup(original_entry ? original_entry : ec)) == NULL) { -+ if (!original_entry) { -+ slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_modrdn", -+ "retrying transaction, but no original entry found\n"); -+ ldap_result_code = LDAP_OPERATIONS_ERROR; -+ goto error_return; -+ } -+ if ((tmpentry = backentry_dup(original_entry)) == NULL) { - ldap_result_code = LDAP_OPERATIONS_ERROR; - goto error_return; - } - slapi_pblock_get(pb, SLAPI_MODRDN_EXISTING_ENTRY, &ent); - if (cache_is_in_cache(&inst->inst_cache, ec)) { - CACHE_REMOVE(&inst->inst_cache, ec); -- if (ent && (ent == ec->ep_entry)) { -- /* -- * On a retry, it's possible that ec is now stored in the -- * pblock as SLAPI_MODRDN_EXISTING_ENTRY. "ec" will be freed -- * by CACHE_RETURN below, so set ent to NULL so don't free -- * it again. -- */ -- ent = NULL; -- } -+ } -+ if (ent && (ent == ec->ep_entry)) { -+ /* -+ * On a retry, it's possible that ec is now stored in the -+ * pblock as SLAPI_MODRDN_EXISTING_ENTRY. "ec" will be freed -+ * by CACHE_RETURN below, so set ent to NULL so don't free -+ * it again. -+ * And it needs to be checked always. -+ */ -+ ent = NULL; - } - CACHE_RETURN(&inst->inst_cache, &ec); -+ -+ /* LK why do we need this ????? */ - if (!cache_is_in_cache(&inst->inst_cache, e)) { - if (CACHE_ADD(&inst->inst_cache, e, NULL) < 0) { - slapi_log_err(SLAPI_LOG_CACHE, -@@ -1087,8 +1103,9 @@ ldbm_back_modrdn(Slapi_PBlock *pb) - if (slapi_sdn_get_dn(dn_newsuperiordn) != NULL) { - retval = ldbm_ancestorid_move_subtree(be, sdn, &dn_newdn, e->ep_id, children, &txn); - if (retval != 0) { -- if (retval == DB_LOCK_DEADLOCK) -+ if (retval == DB_LOCK_DEADLOCK) { - continue; -+ } - if (retval == DB_RUNRECOVERY || LDBM_OS_ERR_IS_DISKFULL(retval)) - disk_full = 1; - MOD_SET_ERROR(ldap_result_code, -@@ -1108,8 +1125,9 @@ ldbm_back_modrdn(Slapi_PBlock *pb) - e->ep_id, &txn, is_tombstone); - slapi_rdn_done(&newsrdn); - if (retval != 0) { -- if (retval == DB_LOCK_DEADLOCK) -+ if (retval == DB_LOCK_DEADLOCK) { - continue; -+ } - if (retval == DB_RUNRECOVERY || LDBM_OS_ERR_IS_DISKFULL(retval)) - disk_full = 1; - MOD_SET_ERROR(ldap_result_code, LDAP_OPERATIONS_ERROR, retry_count); -@@ -1500,7 +1518,12 @@ common_return: - done_with_pblock_entry(pb, SLAPI_MODRDN_NEWPARENT_ENTRY); - done_with_pblock_entry(pb, SLAPI_MODRDN_TARGET_ENTRY); - slapi_ch_free_string(&original_newrdn); -- slapi_sdn_free(&orig_dn_newsuperiordn); -+ slapi_pblock_get(pb, SLAPI_MODRDN_NEWSUPERIOR_SDN, &pb_dn_newsuperiordn); -+ if (pb_dn_newsuperiordn != orig_dn_newsuperiordn) { -+ slapi_sdn_free(&orig_dn_newsuperiordn); -+ } else { -+ slapi_sdn_free(&dn_newsuperiordn); -+ } - backentry_free(&original_entry); - backentry_free(&tmpentry); - slapi_entry_free(original_targetentry); -@@ -1561,6 +1584,9 @@ moddn_unlock_and_return_entry( - /* Something bad happened so we should give back all the entries */ - if (*targetentry != NULL) { - cache_unlock_entry(&inst->inst_cache, *targetentry); -+ if (cache_is_in_cache(&inst->inst_cache, *targetentry)) { -+ CACHE_REMOVE(&inst->inst_cache, *targetentry); -+ } - CACHE_RETURN(&inst->inst_cache, targetentry); - *targetentry = NULL; - } --- -2.21.1 - diff --git a/SOURCES/0027-Issue-50823-dsctl-doesn-t-work-with-slapd-in-the-ins.patch b/SOURCES/0027-Issue-50823-dsctl-doesn-t-work-with-slapd-in-the-ins.patch deleted file mode 100644 index 3585345..0000000 --- a/SOURCES/0027-Issue-50823-dsctl-doesn-t-work-with-slapd-in-the-ins.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 442b49cc1a0d93122fa749363b5930f3acf2eaf0 Mon Sep 17 00:00:00 2001 -From: Matus Honek -Date: Wed, 29 Jan 2020 14:06:04 +0000 -Subject: [PATCH] Issue 50823 - dsctl doesn't work with 'slapd-' in the - instance name - -Bug Description: -DirSrv.list drops all occurrences of 'slapd-' within a serverid -rendering names containing it damaged. - -Fix Description: -Remove only the first occurrence of 'slapd-' in the serverid, which is -the prefix that is expected to be removed. - -Fixes https://pagure.io/389-ds-base/issue/50823 - -Author: Matus Honek - -Review by: Mark, William (thanks!) - -(cherry picked from commit 52930da0bb8abe94a56ff6dca5ea57347d3461a9) ---- - src/lib389/lib389/__init__.py | 2 +- - src/lib389/lib389/instance/setup.py | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/src/lib389/lib389/__init__.py b/src/lib389/lib389/__init__.py -index 0d1ab5747..003b686fa 100644 ---- a/src/lib389/lib389/__init__.py -+++ b/src/lib389/lib389/__init__.py -@@ -711,7 +711,7 @@ class DirSrv(SimpleLDAPObject, object): - if serverid is None and hasattr(self, 'serverid'): - serverid = self.serverid - elif serverid is not None: -- serverid = serverid.replace('slapd-', '') -+ serverid = serverid.replace('slapd-', '', 1) - - if self.serverid is None: - # Need to set the Paths in case it does exist -diff --git a/src/lib389/lib389/instance/setup.py b/src/lib389/lib389/instance/setup.py -index 61ffc32ee..c6bb4fcdc 100644 ---- a/src/lib389/lib389/instance/setup.py -+++ b/src/lib389/lib389/instance/setup.py -@@ -219,7 +219,7 @@ class SetupDs(object): - insts = inst.list(serverid=serverid) - - if len(insts) != 1: -- log.error("No such instance to remove {}".format(serverid)) -+ self.log.error("No such instance to remove {}".format(serverid)) - return - inst.allocate(insts[0]) - remove_ds_instance(inst, force=True) --- -2.21.1 - diff --git a/SOURCES/0028-Ticket-50857-Memory-leak-in-ACI-using-IP-subject.patch b/SOURCES/0028-Ticket-50857-Memory-leak-in-ACI-using-IP-subject.patch deleted file mode 100644 index dd6abd8..0000000 --- a/SOURCES/0028-Ticket-50857-Memory-leak-in-ACI-using-IP-subject.patch +++ /dev/null @@ -1,43 +0,0 @@ -From c804325a9e06b4fabbd456b618db1417a12c135d Mon Sep 17 00:00:00 2001 -From: Thierry Bordaz -Date: Mon, 27 Jan 2020 13:49:37 +0100 -Subject: [PATCH] Ticket 50857 - Memory leak in ACI using IP subject - -Bug Description: - When a ACI is evaluated (LASIpEval) a context (cookie) is allocated. - At the end of the connection, the context is freed - via a callback (LASIpFlush). - The context contains two LASIpTree_t tree (ipv4 and ipv6) - In free callback, only ipv4 tree is freed - -Fix Description: - Free ipv6 tree in LASIpTree - -https://pagure.io/389-ds-base/issue/50857 - -Reviewed by: Mark Reynolds - -Platforms tested: F31 - -Flag Day: no - -Doc impact: no ---- - lib/libaccess/lasip.cpp | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/lib/libaccess/lasip.cpp b/lib/libaccess/lasip.cpp -index 30c546df7..cdb88eec5 100644 ---- a/lib/libaccess/lasip.cpp -+++ b/lib/libaccess/lasip.cpp -@@ -436,6 +436,7 @@ LASIpFlush(void **las_cookie) - return; - - LASIpTreeDealloc(((LASIpContext_t *)*las_cookie)->treetop); -+ LASIpTreeDealloc(((LASIpContext_t *)*las_cookie)->treetop_ipv6); - PERM_FREE(*las_cookie); - *las_cookie = NULL; - return; --- -2.21.1 - diff --git a/SOURCES/0029-Issue-50873-Fix-issues-with-healthcheck-tool.patch b/SOURCES/0029-Issue-50873-Fix-issues-with-healthcheck-tool.patch deleted file mode 100644 index de46a68..0000000 --- a/SOURCES/0029-Issue-50873-Fix-issues-with-healthcheck-tool.patch +++ /dev/null @@ -1,79 +0,0 @@ -From 717ce8b3b50c7a92cc269836a88c3015d1786120 Mon Sep 17 00:00:00 2001 -From: Mark Reynolds -Date: Fri, 31 Jan 2020 16:36:28 -0500 -Subject: [PATCH] Issue 50873 - Fix issues with healthcheck tool - -Description: - -- Wrong error code reported with result for backend check - -- Disk Space Monitor check crashes because it is missing "import copy" - -- On a non-LDAPI instance "dsctl healthcheck" does not prompt for bind dn, only for password. - -relates: https://pagure.io/389-ds-base/issue/50873 - -Reviewed by: firstyear(Thanks!) ---- - src/lib389/lib389/cli_base/__init__.py | 16 ++++++++++------ - src/lib389/lib389/lint.py | 2 +- - src/lib389/lib389/monitor.py | 1 + - 3 files changed, 12 insertions(+), 7 deletions(-) - -diff --git a/src/lib389/lib389/cli_base/__init__.py b/src/lib389/lib389/cli_base/__init__.py -index e2e6c902a..7dd45b373 100644 ---- a/src/lib389/lib389/cli_base/__init__.py -+++ b/src/lib389/lib389/cli_base/__init__.py -@@ -129,14 +129,18 @@ def connect_instance(dsrc_inst, verbose, args): - # No password or we chose to prompt - dsargs[SER_ROOT_PW] = getpass("Enter password for {} on {}: ".format(dsrc_inst['binddn'], dsrc_inst['uri'])) - elif not ds.can_autobind(): -- # No LDAPI, prompt for password -+ # No LDAPI, prompt for password, and bind DN if necessary -+ if dsrc_inst['binddn'] is None: -+ dn = "" -+ while dn == "": -+ dn = input("Enter Bind DN: ") -+ dsrc_inst['binddn'] = dn - dsargs[SER_ROOT_PW] = getpass("Enter password for {} on {}: ".format(dsrc_inst['binddn'], dsrc_inst['uri'])) - -- if 'binddn' in dsrc_inst: -- # Allocate is an awful interface that we should stop using, but for now -- # just directly map the dsrc_inst args in (remember, dsrc_inst DOES -- # overlay cli args into the map ...) -- dsargs[SER_ROOT_DN] = dsrc_inst['binddn'] -+ # Allocate is an awful interface that we should stop using, but for now -+ # just directly map the dsrc_inst args in (remember, dsrc_inst DOES -+ # overlay cli args into the map ...) -+ dsargs[SER_ROOT_DN] = dsrc_inst['binddn'] - - ds = DirSrv(verbose=verbose) - ds.allocate(dsargs) -diff --git a/src/lib389/lib389/lint.py b/src/lib389/lib389/lint.py -index 736dffa14..68b729674 100644 ---- a/src/lib389/lib389/lint.py -+++ b/src/lib389/lib389/lint.py -@@ -47,7 +47,7 @@ DSBLE0002 = { - } - - DSBLE0003 = { -- 'dsle': 'DSBLE0002', -+ 'dsle': 'DSBLE0003', - 'severity': 'LOW', - 'items' : [], - 'detail' : """The backend database has not been initialized yet""", -diff --git a/src/lib389/lib389/monitor.py b/src/lib389/lib389/monitor.py -index 290cad5e2..d6413de98 100644 ---- a/src/lib389/lib389/monitor.py -+++ b/src/lib389/lib389/monitor.py -@@ -6,6 +6,7 @@ - # See LICENSE for details. - # --- END COPYRIGHT BLOCK --- - -+import copy - from lib389._constants import * - from lib389._mapped_object import DSLdapObject - from lib389.utils import (ds_is_older) --- -2.21.1 - diff --git a/SOURCES/0030-Issue-50873-Fix-healthcheck-and-virtual-attr-check.patch b/SOURCES/0030-Issue-50873-Fix-healthcheck-and-virtual-attr-check.patch deleted file mode 100644 index 60d80ae..0000000 --- a/SOURCES/0030-Issue-50873-Fix-healthcheck-and-virtual-attr-check.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 8c7b89bb2a1e25041e339e9e6092f031ac26d585 Mon Sep 17 00:00:00 2001 -From: Mark Reynolds -Date: Wed, 5 Feb 2020 09:48:15 -0500 -Subject: [PATCH] Issue 50873 - Fix healthcheck and virtual attr check - -Description: Used the wrong DN to lookup COS definitions - -relates: https://pagure.io/389-ds-base/issue/50873 - -Reviewed by: mreynolds (one line commit rule) ---- - src/lib389/lib389/backend.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/lib389/lib389/backend.py b/src/lib389/lib389/backend.py -index ac2af021c..86ee33e6e 100644 ---- a/src/lib389/lib389/backend.py -+++ b/src/lib389/lib389/backend.py -@@ -438,7 +438,7 @@ class Backend(DSLdapObject): - - # Check COS next - for cosDefType in [CosIndirectDefinitions, CosPointerDefinitions, CosClassicDefinitions]: -- defs = cosDefType(self._instance, self._dn).list() -+ defs = cosDefType(self._instance, suffix).list() - for cosDef in defs: - attrs = cosDef.get_attr_val_utf8_l("cosAttribute").split() - for attr in attrs: --- -2.21.1 - diff --git a/SOURCES/0031-Issue-50886-Typo-in-the-replication-debug-message.patch b/SOURCES/0031-Issue-50886-Typo-in-the-replication-debug-message.patch deleted file mode 100644 index abff5ad..0000000 --- a/SOURCES/0031-Issue-50886-Typo-in-the-replication-debug-message.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 339a719a4049cd1b9368af1946647227ddf15390 Mon Sep 17 00:00:00 2001 -From: Mark Reynolds -Date: Thu, 6 Feb 2020 14:38:04 -0500 -Subject: [PATCH] Issue 50886 - Typo in the replication debug message - -Description: Fix typo in replication logging message - -relates: https://pagure.io/389-ds-base/issue/50886 - -Reviewed by: mreynolds (one line commit rule) ---- - ldap/servers/plugins/replication/repl5_plugins.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ldap/servers/plugins/replication/repl5_plugins.c b/ldap/servers/plugins/replication/repl5_plugins.c -index e6b2fdb6e..caa99d1c6 100644 ---- a/ldap/servers/plugins/replication/repl5_plugins.c -+++ b/ldap/servers/plugins/replication/repl5_plugins.c -@@ -622,7 +622,7 @@ multimaster_mmr_postop (Slapi_PBlock *pb, int flags) - break; - } - slapi_log_err(SLAPI_LOG_REPL, REPLICATION_SUBSYSTEM, -- "multimaster_mmr_postop - error %d for oparation %d.\n", rc, flags); -+ "multimaster_mmr_postop - error %d for operation %d.\n", rc, flags); - return rc; - } - --- -2.21.1 - diff --git a/SOURCES/0032-Issue-50882-Fix-healthcheck-errors-for-instances-tha.patch b/SOURCES/0032-Issue-50882-Fix-healthcheck-errors-for-instances-tha.patch deleted file mode 100644 index 6fb81c4..0000000 --- a/SOURCES/0032-Issue-50882-Fix-healthcheck-errors-for-instances-tha.patch +++ /dev/null @@ -1,97 +0,0 @@ -From 7130e7595ee5e919558a143e64fb08cab1e3d45d Mon Sep 17 00:00:00 2001 -From: Mark Reynolds -Date: Thu, 6 Feb 2020 15:30:42 -0500 -Subject: [PATCH] Issue 50882 - Fix healthcheck errors for instances that do - not have TLS enabled - -Bug Description: The config and FSChecks fail when TLS is not setup - -Fix Description: Properly check for conditions when TLS is not enabled, - and ignore errors if TLS related files are not present - during the FS permissions check. - -relates: https://pagure.io/389-ds-base/issue/50882 - -Reviewed by: firstyear(thanks!) ---- - src/lib389/lib389/config.py | 2 +- - src/lib389/lib389/dseldif.py | 23 +++++++++++++---------- - src/lib389/lib389/lint.py | 3 +-- - src/lib389/lib389/nss_ssl.py | 3 +++ - 4 files changed, 18 insertions(+), 13 deletions(-) - -diff --git a/src/lib389/lib389/config.py b/src/lib389/lib389/config.py -index f71baf2d8..268b99c90 100644 ---- a/src/lib389/lib389/config.py -+++ b/src/lib389/lib389/config.py -@@ -238,7 +238,7 @@ class Encryption(DSLdapObject): - - def _lint_check_tls_version(self): - tls_min = self.get_attr_val('sslVersionMin') -- if tls_min < ensure_bytes('TLS1.1'): -+ if tls_min is not None and tls_min < ensure_bytes('TLS1.1'): - report = copy.deepcopy(DSELE0001) - report['fix'] = report['fix'].replace('YOUR_INSTANCE', self._instance.serverid) - yield report -diff --git a/src/lib389/lib389/dseldif.py b/src/lib389/lib389/dseldif.py -index fbb50623b..716dd46e9 100644 ---- a/src/lib389/lib389/dseldif.py -+++ b/src/lib389/lib389/dseldif.py -@@ -200,13 +200,16 @@ class FSChecks(object): - """Test file permissions are safe - """ - for ds_file in self.ds_files: -- perms = int(oct(os.stat(ds_file['name'])[ST_MODE])[-3:]) -- if perms not in ds_file['perms']: -- perms = str(ds_file['perms'][0]) -- report = copy.deepcopy(ds_file['report']) -- report['items'].append(ds_file['name']) -- report['detail'] = report['detail'].replace('FILE', ds_file['name']) -- report['detail'] = report['detail'].replace('PERMS', perms) -- report['fix'] = report['fix'].replace('FILE', ds_file['name']) -- report['fix'] = report['fix'].replace('PERMS', perms) -- yield report -+ try: -+ perms = int(oct(os.stat(ds_file['name'])[ST_MODE])[-3:]) -+ if perms not in ds_file['perms']: -+ perms = str(ds_file['perms'][0]) -+ report = copy.deepcopy(ds_file['report']) -+ report['items'].append(ds_file['name']) -+ report['detail'] = report['detail'].replace('FILE', ds_file['name']) -+ report['detail'] = report['detail'].replace('PERMS', perms) -+ report['fix'] = report['fix'].replace('FILE', ds_file['name']) -+ report['fix'] = report['fix'].replace('PERMS', perms) -+ yield report -+ except FileNotFoundError: -+ pass -diff --git a/src/lib389/lib389/lint.py b/src/lib389/lib389/lint.py -index 68b729674..742058fa1 100644 ---- a/src/lib389/lib389/lint.py -+++ b/src/lib389/lib389/lint.py -@@ -224,8 +224,7 @@ DSREPLLE0002 = { - 'dsle': 'DSREPLLE0002', - 'severity': 'LOW', - 'items' : ['Replication', 'Conflict Entries'], -- 'detail': """There were COUNT conflict entries found under the replication suffix "SUFFIX". --Status message: MSG""", -+ 'detail': "There were COUNT conflict entries found under the replication suffix \"SUFFIX\".", - 'fix' : """While conflict entries are expected to occur in an MMR environment, they - should be resolved. In regards to conflict entries there is always the original/counterpart - entry that has a normal DN, and then the conflict version of that entry. Technically both -diff --git a/src/lib389/lib389/nss_ssl.py b/src/lib389/lib389/nss_ssl.py -index 41b19caa4..c64f158d5 100644 ---- a/src/lib389/lib389/nss_ssl.py -+++ b/src/lib389/lib389/nss_ssl.py -@@ -394,6 +394,9 @@ only. - for line in lines: - if line == '': - continue -+ if line == 'Database needs user init': -+ # There are no certs, abort... -+ return [] - cert_values.append(re.match(r'^(.+[^\s])[\s]+([^\s]+)$', line.rstrip()).groups()) - return cert_values - --- -2.21.1 - diff --git a/SOURCES/0033-Ticket-50490-objects-and-memory-leaks.patch b/SOURCES/0033-Ticket-50490-objects-and-memory-leaks.patch deleted file mode 100644 index be3a901..0000000 --- a/SOURCES/0033-Ticket-50490-objects-and-memory-leaks.patch +++ /dev/null @@ -1,45 +0,0 @@ -From ffeb3389c2682b41db28062a48ff555875330098 Mon Sep 17 00:00:00 2001 -From: Ludwig Krispenz -Date: Thu, 1 Aug 2019 10:40:33 +0200 -Subject: [PATCH] Ticket 50490 objects and memory leaks - -Bug: There are severalmemory leaks for replication objects - -Fix: This patch contains a couple of fixes: - - - The balance of acquire and release for a replica object was incorrect, - but the object is allocated at startup or when a replica is added and - destroyed at shutdown. In between we know the replica exists and can be accessed directly - To ensure that no access was made until it is destroyed the shutdown order was - slightly modifed - - - other objects like RUV or AGMT were also not always correctly balanced, this - is corrected - - - in cl5_api where many types of objects are used, the variable names were changed - to bettr indicat to what an object refers - - - some other leaks, eg in repl5_total_init or op_shared_add were fixed - - - unused code has been removed - -Reviewed by: William, Thierry, Mark - thanks ---- - ldap/servers/plugins/replication/repl5_replica_config.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/ldap/servers/plugins/replication/repl5_replica_config.c b/ldap/servers/plugins/replication/repl5_replica_config.c -index 02b36f6ad..238522b54 100644 ---- a/ldap/servers/plugins/replication/repl5_replica_config.c -+++ b/ldap/servers/plugins/replication/repl5_replica_config.c -@@ -769,6 +769,7 @@ replica_config_delete(Slapi_PBlock *pb __attribute__((unused)), - slapi_sdn_get_dn(replica_get_root(r))); - cl5DeleteDBSync(r); - replica_delete_by_name(replica_get_name(r)); -+ mtnode_ext->replica = NULL; - } - - PR_Unlock(s_configLock); --- -2.21.1 - diff --git a/SOURCES/0034-Issue-50780-Fix-UI-issues.patch b/SOURCES/0034-Issue-50780-Fix-UI-issues.patch deleted file mode 100644 index 985e591..0000000 --- a/SOURCES/0034-Issue-50780-Fix-UI-issues.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 82b5436598848d6870174d04f1c3a5cf702c1508 Mon Sep 17 00:00:00 2001 -From: Mark Reynolds -Date: Wed, 11 Dec 2019 15:42:22 -0500 -Subject: [PATCH] Issue 50780 - Fix UI issues - -Description: Fixed issue with replication conflict entry modal, and - problem with the monitor's replication and suffix - state data collision that caused a crash if you first - looked at replication and then the suffix monitor - -relates: https://pagure.io/389-ds-base/issue/50780 - -Reviewed by: spichugi(Thanks!) ---- - src/lib389/lib389/replica.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/lib389/lib389/replica.py b/src/lib389/lib389/replica.py -index 9b84d8f7e..4855f03f0 100644 ---- a/src/lib389/lib389/replica.py -+++ b/src/lib389/lib389/replica.py -@@ -1169,7 +1169,7 @@ class Replica(DSLdapObject): - if len(conflicts) > 0: - report = copy.deepcopy(DSREPLLE0002) - report['detail'] = report['detail'].replace('SUFFIX', suffix) -- report['detail'] = report['detail'].replace('COUNT', len(conflicts)) -+ report['detail'] = report['detail'].replace('COUNT', str(len(conflicts))) - report['fix'] = report['fix'].replace('YOUR_INSTANCE', self._instance.serverid) - yield report - --- -2.24.1 - diff --git a/SOURCES/0035-Issue-51129-SSL-alert-The-value-of-sslVersionMax-TLS.patch b/SOURCES/0035-Issue-51129-SSL-alert-The-value-of-sslVersionMax-TLS.patch deleted file mode 100644 index 93eec89..0000000 --- a/SOURCES/0035-Issue-51129-SSL-alert-The-value-of-sslVersionMax-TLS.patch +++ /dev/null @@ -1,371 +0,0 @@ -From c510a50bbbb05099159817f8d9da0088c5a0a5c0 Mon Sep 17 00:00:00 2001 -From: Mark Reynolds -Date: Fri, 21 Aug 2020 12:44:18 -0400 -Subject: [PATCH] Issue 51129 - SSL alert: The value of sslVersionMax "TLS1.3" - is higher than the supported version - - Bug Description: If you try and set the sslVersionMax higher than the - default range, but within the supported range, you - would still get an error and the server would reset - the max to "default" max value. - - Fix Description: Keep track of both the supported and default SSL ranges, - and correctly use each range for value validation. If - the value is outside the supported range, then use default - value, etc, but do not check the requested range against - the default range. We only use the default range if - there is no specified min or max in the config, or if - a invalid min or max value is set in the config. - - Also, refactored the range variable names to be more - accurate: - - enabledNSSVersions --> defaultNSSVersions - emin, emax --> dmin, dmax - - relates: https://pagure.io/389-ds-base/issue/51129 - - Reviewed by: firstyear(Thanks!) ---- - ldap/servers/slapd/ssl.c | 167 +++++++++++++++++++++------------------ - 1 file changed, 88 insertions(+), 79 deletions(-) - -diff --git a/ldap/servers/slapd/ssl.c b/ldap/servers/slapd/ssl.c -index 71f91f761..1a860b71e 100644 ---- a/ldap/servers/slapd/ssl.c -+++ b/ldap/servers/slapd/ssl.c -@@ -48,12 +48,12 @@ - * sslVersionMax: max ssl version supported by NSS - ******************************************************************************/ - --#define DEFVERSION "TLS1.0" --#define CURRENT_DEFAULT_SSL_VERSION SSL_LIBRARY_VERSION_TLS_1_0 -+#define DEFVERSION "TLS1.2" - - extern char *slapd_SSL3ciphers; - extern symbol_t supported_ciphers[]; --static SSLVersionRange enabledNSSVersions; -+static SSLVersionRange defaultNSSVersions; -+static SSLVersionRange supportedNSSVersions; - static SSLVersionRange slapdNSSVersions; - - -@@ -151,7 +151,7 @@ PRBool enableSSL2 = PR_FALSE; - PRBool enableSSL3 = PR_FALSE; - /* - * nsTLS1: on -- enable TLS1 by default. -- * Corresonding to SSL_LIBRARY_VERSION_TLS_1_0 and greater. -+ * Corresonding to SSL_LIBRARY_VERSION_TLS_1_2 and greater. - */ - PRBool enableTLS1 = PR_TRUE; - -@@ -934,15 +934,24 @@ slapd_nss_init(int init_ssl __attribute__((unused)), int config_available __attr - int create_certdb = 0; - PRUint32 nssFlags = 0; - char *certdir; -- char emin[VERSION_STR_LENGTH], emax[VERSION_STR_LENGTH]; -- /* Get the range of the supported SSL version */ -- SSL_VersionRangeGetDefault(ssl_variant_stream, &enabledNSSVersions); -+ char dmin[VERSION_STR_LENGTH], dmax[VERSION_STR_LENGTH]; -+ char smin[VERSION_STR_LENGTH], smax[VERSION_STR_LENGTH]; - -- (void)slapi_getSSLVersion_str(enabledNSSVersions.min, emin, sizeof(emin)); -- (void)slapi_getSSLVersion_str(enabledNSSVersions.max, emax, sizeof(emax)); -+ /* Get the range of the supported SSL version */ -+ SSL_VersionRangeGetSupported(ssl_variant_stream, &supportedNSSVersions); -+ (void)slapi_getSSLVersion_str(supportedNSSVersions.min, smin, sizeof(smin)); -+ (void)slapi_getSSLVersion_str(supportedNSSVersions.max, smax, sizeof(smax)); -+ -+ /* Get the enabled default range */ -+ SSL_VersionRangeGetDefault(ssl_variant_stream, &defaultNSSVersions); -+ (void)slapi_getSSLVersion_str(defaultNSSVersions.min, dmin, sizeof(dmin)); -+ (void)slapi_getSSLVersion_str(defaultNSSVersions.max, dmax, sizeof(dmax)); - slapi_log_err(SLAPI_LOG_CONFIG, "Security Initialization", - "slapd_nss_init - Supported range by NSS: min: %s, max: %s\n", -- emin, emax); -+ smin, smax); -+ slapi_log_err(SLAPI_LOG_CONFIG, "Security Initialization", -+ "slapd_nss_init - Enabled default range by NSS: min: %s, max: %s\n", -+ dmin, dmax); - - /* set in slapd_bootstrap_config, - thus certdir is available even if config_available is false */ -@@ -1262,21 +1271,21 @@ static int - set_NSS_version(char *val, PRUint16 *rval, int ismin) - { - char *vp; -- char emin[VERSION_STR_LENGTH], emax[VERSION_STR_LENGTH]; -+ char dmin[VERSION_STR_LENGTH], dmax[VERSION_STR_LENGTH]; - - if (NULL == rval) { - return 1; - } -- (void)slapi_getSSLVersion_str(enabledNSSVersions.min, emin, sizeof(emin)); -- (void)slapi_getSSLVersion_str(enabledNSSVersions.max, emax, sizeof(emax)); -+ (void)slapi_getSSLVersion_str(defaultNSSVersions.min, dmin, sizeof(dmin)); -+ (void)slapi_getSSLVersion_str(defaultNSSVersions.max, dmax, sizeof(dmax)); - - if (!strncasecmp(val, SSLSTR, SSLLEN)) { /* ssl# NOT SUPPORTED */ - if (ismin) { -- slapd_SSL_warn("SSL3 is no longer supported. Using NSS default min value: %s\n", emin); -- (*rval) = enabledNSSVersions.min; -+ slapd_SSL_warn("SSL3 is no longer supported. Using NSS default min value: %s", dmin); -+ (*rval) = defaultNSSVersions.min; - } else { -- slapd_SSL_warn("SSL3 is no longer supported. Using NSS default max value: %s\n", emax); -- (*rval) = enabledNSSVersions.max; -+ slapd_SSL_warn("SSL3 is no longer supported. Using NSS default max value: %s", dmax); -+ (*rval) = defaultNSSVersions.max; - } - } else if (!strncasecmp(val, TLSSTR, TLSLEN)) { /* tls# */ - float tlsv; -@@ -1284,122 +1293,122 @@ set_NSS_version(char *val, PRUint16 *rval, int ismin) - sscanf(vp, "%4f", &tlsv); - if (tlsv < 1.1f) { /* TLS1.0 */ - if (ismin) { -- if (enabledNSSVersions.min > CURRENT_DEFAULT_SSL_VERSION) { -+ if (supportedNSSVersions.min > SSL_LIBRARY_VERSION_TLS_1_0) { - slapd_SSL_warn("The value of sslVersionMin " - "\"%s\" is lower than the supported version; " - "the default value \"%s\" is used.", -- val, emin); -- (*rval) = enabledNSSVersions.min; -+ val, dmin); -+ (*rval) = defaultNSSVersions.min; - } else { -- (*rval) = CURRENT_DEFAULT_SSL_VERSION; -+ (*rval) = SSL_LIBRARY_VERSION_TLS_1_0; - } - } else { -- if (enabledNSSVersions.max < CURRENT_DEFAULT_SSL_VERSION) { -+ if (supportedNSSVersions.max < SSL_LIBRARY_VERSION_TLS_1_0) { - /* never happens */ - slapd_SSL_warn("The value of sslVersionMax " - "\"%s\" is higher than the supported version; " - "the default value \"%s\" is used.", -- val, emax); -- (*rval) = enabledNSSVersions.max; -+ val, dmax); -+ (*rval) = defaultNSSVersions.max; - } else { -- (*rval) = CURRENT_DEFAULT_SSL_VERSION; -+ (*rval) = SSL_LIBRARY_VERSION_TLS_1_0; - } - } - } else if (tlsv < 1.2f) { /* TLS1.1 */ - if (ismin) { -- if (enabledNSSVersions.min > SSL_LIBRARY_VERSION_TLS_1_1) { -+ if (supportedNSSVersions.min > SSL_LIBRARY_VERSION_TLS_1_1) { - slapd_SSL_warn("The value of sslVersionMin " - "\"%s\" is lower than the supported version; " - "the default value \"%s\" is used.", -- val, emin); -- (*rval) = enabledNSSVersions.min; -+ val, dmin); -+ (*rval) = defaultNSSVersions.min; - } else { - (*rval) = SSL_LIBRARY_VERSION_TLS_1_1; - } - } else { -- if (enabledNSSVersions.max < SSL_LIBRARY_VERSION_TLS_1_1) { -+ if (supportedNSSVersions.max < SSL_LIBRARY_VERSION_TLS_1_1) { - /* never happens */ - slapd_SSL_warn("The value of sslVersionMax " - "\"%s\" is higher than the supported version; " - "the default value \"%s\" is used.", -- val, emax); -- (*rval) = enabledNSSVersions.max; -+ val, dmax); -+ (*rval) = defaultNSSVersions.max; - } else { - (*rval) = SSL_LIBRARY_VERSION_TLS_1_1; - } - } - } else if (tlsv < 1.3f) { /* TLS1.2 */ - if (ismin) { -- if (enabledNSSVersions.min > SSL_LIBRARY_VERSION_TLS_1_2) { -+ if (supportedNSSVersions.min > SSL_LIBRARY_VERSION_TLS_1_2) { - slapd_SSL_warn("The value of sslVersionMin " - "\"%s\" is lower than the supported version; " - "the default value \"%s\" is used.", -- val, emin); -- (*rval) = enabledNSSVersions.min; -+ val, dmin); -+ (*rval) = defaultNSSVersions.min; - } else { - (*rval) = SSL_LIBRARY_VERSION_TLS_1_2; - } - } else { -- if (enabledNSSVersions.max < SSL_LIBRARY_VERSION_TLS_1_2) { -+ if (supportedNSSVersions.max < SSL_LIBRARY_VERSION_TLS_1_2) { - /* never happens */ - slapd_SSL_warn("The value of sslVersionMax " - "\"%s\" is higher than the supported version; " - "the default value \"%s\" is used.", -- val, emax); -- (*rval) = enabledNSSVersions.max; -+ val, dmax); -+ (*rval) = defaultNSSVersions.max; - } else { - (*rval) = SSL_LIBRARY_VERSION_TLS_1_2; - } - } - } else if (tlsv < 1.4f) { /* TLS1.3 */ -- if (ismin) { -- if (enabledNSSVersions.min > SSL_LIBRARY_VERSION_TLS_1_3) { -- slapd_SSL_warn("The value of sslVersionMin " -- "\"%s\" is lower than the supported version; " -- "the default value \"%s\" is used.", -- val, emin); -- (*rval) = enabledNSSVersions.min; -- } else { -- (*rval) = SSL_LIBRARY_VERSION_TLS_1_3; -- } -- } else { -- if (enabledNSSVersions.max < SSL_LIBRARY_VERSION_TLS_1_3) { -- /* never happens */ -- slapd_SSL_warn("The value of sslVersionMax " -- "\"%s\" is higher than the supported version; " -- "the default value \"%s\" is used.", -- val, emax); -- (*rval) = enabledNSSVersions.max; -- } else { -- (*rval) = SSL_LIBRARY_VERSION_TLS_1_3; -- } -- } -+ if (ismin) { -+ if (supportedNSSVersions.min > SSL_LIBRARY_VERSION_TLS_1_3) { -+ slapd_SSL_warn("The value of sslVersionMin " -+ "\"%s\" is lower than the supported version; " -+ "the default value \"%s\" is used.", -+ val, dmin); -+ (*rval) = defaultNSSVersions.min; -+ } else { -+ (*rval) = SSL_LIBRARY_VERSION_TLS_1_3; -+ } -+ } else { -+ if (supportedNSSVersions.max < SSL_LIBRARY_VERSION_TLS_1_3) { -+ /* never happens */ -+ slapd_SSL_warn("The value of sslVersionMax " -+ "\"%s\" is higher than the supported version; " -+ "the default value \"%s\" is used.", -+ val, dmax); -+ (*rval) = defaultNSSVersions.max; -+ } else { -+ (*rval) = SSL_LIBRARY_VERSION_TLS_1_3; -+ } -+ } - } else { /* Specified TLS is newer than supported */ - if (ismin) { - slapd_SSL_warn("The value of sslVersionMin " - "\"%s\" is out of the range of the supported version; " - "the default value \"%s\" is used.", -- val, emin); -- (*rval) = enabledNSSVersions.min; -+ val, dmin); -+ (*rval) = defaultNSSVersions.min; - } else { - slapd_SSL_warn("The value of sslVersionMax " - "\"%s\" is out of the range of the supported version; " - "the default value \"%s\" is used.", -- val, emax); -- (*rval) = enabledNSSVersions.max; -+ val, dmax); -+ (*rval) = defaultNSSVersions.max; - } - } - } else { - if (ismin) { - slapd_SSL_warn("The value of sslVersionMin " - "\"%s\" is invalid; the default value \"%s\" is used.", -- val, emin); -- (*rval) = enabledNSSVersions.min; -+ val, dmin); -+ (*rval) = defaultNSSVersions.min; - } else { - slapd_SSL_warn("The value of sslVersionMax " - "\"%s\" is invalid; the default value \"%s\" is used.", -- val, emax); -- (*rval) = enabledNSSVersions.max; -+ val, dmax); -+ (*rval) = defaultNSSVersions.max; - } - } - return 0; -@@ -1429,10 +1438,9 @@ slapd_ssl_init2(PRFileDesc **fd, int startTLS) - char *tmpDir; - Slapi_Entry *e = NULL; - PRBool fipsMode = PR_FALSE; -- PRUint16 NSSVersionMin = enabledNSSVersions.min; -- PRUint16 NSSVersionMax = enabledNSSVersions.max; -+ PRUint16 NSSVersionMin = defaultNSSVersions.min; -+ PRUint16 NSSVersionMax = defaultNSSVersions.max; - char mymin[VERSION_STR_LENGTH], mymax[VERSION_STR_LENGTH]; -- char newmax[VERSION_STR_LENGTH]; - int allowweakcipher = CIPHER_SET_DEFAULTWEAKCIPHER; - int_fast16_t renegotiation = (int_fast16_t)SSL_RENEGOTIATE_REQUIRES_XTN; - -@@ -1780,7 +1788,11 @@ slapd_ssl_init2(PRFileDesc **fd, int startTLS) - } - val = slapi_entry_attr_get_ref(e, "sslVersionMin"); - if (val) { -+ /* Use the user defined minimum */ - (void)set_NSS_version((char *)val, &NSSVersionMin, 1); -+ } else { -+ /* Force our default minimum */ -+ (void)set_NSS_version(DEFVERSION, &NSSVersionMin, 1); - } - val = slapi_entry_attr_get_ref(e, "sslVersionMax"); - if (val) { -@@ -1789,12 +1801,9 @@ slapd_ssl_init2(PRFileDesc **fd, int startTLS) - if (NSSVersionMin > NSSVersionMax) { - (void)slapi_getSSLVersion_str(NSSVersionMin, mymin, sizeof(mymin)); - (void)slapi_getSSLVersion_str(NSSVersionMax, mymax, sizeof(mymax)); -- slapd_SSL_warn("The min value of NSS version range \"%s\" is greater than the max value \"%s\".", -+ slapd_SSL_warn("The min value of NSS version range \"%s\" is greater than the max value \"%s\". Adjusting the max to match the miniumum.", - mymin, mymax); -- (void)slapi_getSSLVersion_str(enabledNSSVersions.max, newmax, sizeof(newmax)); -- slapd_SSL_warn("Reset the max \"%s\" to supported max \"%s\".", -- mymax, newmax); -- NSSVersionMax = enabledNSSVersions.max; -+ NSSVersionMax = NSSVersionMin; - } - } - -@@ -1810,7 +1819,7 @@ slapd_ssl_init2(PRFileDesc **fd, int startTLS) - if (sslStatus != SECSuccess) { - errorCode = PR_GetError(); - slapd_SSL_error("Security Initialization - " -- "slapd_ssl_init2 - Failed to set SSL range: min: %s, max: %s - error %d (%s)\n", -+ "slapd_ssl_init2 - Failed to set SSL range: min: %s, max: %s - error %d (%s)", - mymin, mymax, errorCode, slapd_pr_strerror(errorCode)); - } - /* -@@ -1840,13 +1849,13 @@ slapd_ssl_init2(PRFileDesc **fd, int startTLS) - (void)slapi_getSSLVersion_str(slapdNSSVersions.min, mymin, sizeof(mymin)); - (void)slapi_getSSLVersion_str(slapdNSSVersions.max, mymax, sizeof(mymax)); - slapd_SSL_error("Security Initialization - " -- "slapd_ssl_init2 - Failed to set SSL range: min: %s, max: %s - error %d (%s)\n", -+ "slapd_ssl_init2 - Failed to set SSL range: min: %s, max: %s - error %d (%s)", - mymin, mymax, errorCode, slapd_pr_strerror(errorCode)); - } - } else { - errorCode = PR_GetError(); - slapd_SSL_error("Security Initialization - ", -- "slapd_ssl_init2 - Failed to get SSL range from socket - error %d (%s)\n", -+ "slapd_ssl_init2 - Failed to get SSL range from socket - error %d (%s)", - errorCode, slapd_pr_strerror(errorCode)); - } - -@@ -2173,7 +2182,7 @@ slapd_SSL_client_auth(LDAP *ld) - } - } else { - if (token == NULL) { -- slapd_SSL_warn("slapd_SSL_client_auth - certificate token was not found\n"); -+ slapd_SSL_warn("slapd_SSL_client_auth - certificate token was not found"); - } - rc = -1; - } --- -2.26.2 - diff --git a/SOURCES/0036-Issue-49731-undo-db_home_dir-under-dev-shm-dirsrv-fo.patch b/SOURCES/0036-Issue-49731-undo-db_home_dir-under-dev-shm-dirsrv-fo.patch deleted file mode 100644 index 6395c28..0000000 --- a/SOURCES/0036-Issue-49731-undo-db_home_dir-under-dev-shm-dirsrv-fo.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 9ab266c88350c3387a8521897cd599f80b0ec6be Mon Sep 17 00:00:00 2001 -From: Mark Reynolds -Date: Tue, 21 Apr 2020 14:48:11 -0400 -Subject: [PATCH] Issue 49731 - undo db_home_dir under /dev/shm/dirsrv for now - -Bug Description: There are several issues with using /dec/shm/disrv/ - for the db home directory. Cantainers have issues, - and system reboots can cause issues too. - -Fix Description: Using just /dev/shm/slapd-INST solves all the permission - issues, but that requires a new selinux label, so - for now we will just set the db home directory to the - database directory (effectively disabling the change). - -relates: https://pagure.io/389-ds-base/issue/49731 - -Reviewed by: firstyear & tbordaz(Thanks!) ---- - ldap/admin/src/defaults.inf.in | 1 + - ldap/servers/slapd/util.c | 11 +++++++++++ - src/lib389/lib389/instance/setup.py | 5 +++-- - 3 files changed, 15 insertions(+), 2 deletions(-) - -diff --git a/ldap/admin/src/defaults.inf.in b/ldap/admin/src/defaults.inf.in -index f74929581..d60f24cda 100644 ---- a/ldap/admin/src/defaults.inf.in -+++ b/ldap/admin/src/defaults.inf.in -@@ -57,6 +57,7 @@ access_log = @localstatedir@/log/dirsrv/slapd-{instance_name}/access - audit_log = @localstatedir@/log/dirsrv/slapd-{instance_name}/audit - error_log = @localstatedir@/log/dirsrv/slapd-{instance_name}/errors - db_dir = @localstatedir@/lib/dirsrv/slapd-{instance_name}/db -+db_home_dir = @localstatedir@/lib/dirsrv/slapd-{instance_name}/db - backup_dir = @localstatedir@/lib/dirsrv/slapd-{instance_name}/bak - ldif_dir = @localstatedir@/lib/dirsrv/slapd-{instance_name}/ldif - -diff --git a/ldap/servers/slapd/util.c b/ldap/servers/slapd/util.c -index e1219c555..78ee68da9 100644 ---- a/ldap/servers/slapd/util.c -+++ b/ldap/servers/slapd/util.c -@@ -467,6 +467,17 @@ slapi_escape_filter_value(char *filter_str, int len) - } - } - -+/* replace c with c2 in str */ -+void -+replace_char(char *str, char c, char c2) -+{ -+ for (size_t i = 0; (str != NULL) && (str[i] != '\0'); i++) { -+ if (c == str[i]) { -+ str[i] = c2; -+ } -+ } -+} -+ - /* - ** This function takes a quoted attribute value of the form "abc", - ** and strips off the enclosing quotes. It also deals with quoted -diff --git a/src/lib389/lib389/instance/setup.py b/src/lib389/lib389/instance/setup.py -index bb0ff32f5..887eae57c 100644 ---- a/src/lib389/lib389/instance/setup.py -+++ b/src/lib389/lib389/instance/setup.py -@@ -853,8 +853,9 @@ class SetupDs(object): - - # Do selinux fixups - if general['selinux']: -- selinux_paths = ('backup_dir', 'cert_dir', 'config_dir', 'db_dir', 'ldif_dir', -- 'lock_dir', 'log_dir', 'run_dir', 'schema_dir', 'tmp_dir') -+ selinux_paths = ('backup_dir', 'cert_dir', 'config_dir', 'db_dir', -+ 'ldif_dir', 'lock_dir', 'log_dir', -+ 'run_dir', 'schema_dir', 'tmp_dir') - for path in selinux_paths: - selinux_restorecon(slapd[path]) - --- -2.26.2 - diff --git a/SPECS/389-ds-base.spec b/SPECS/389-ds-base.spec index 39a2325..37554a0 100644 --- a/SPECS/389-ds-base.spec +++ b/SPECS/389-ds-base.spec @@ -44,8 +44,8 @@ ExcludeArch: i686 Summary: 389 Directory Server (base) Name: 389-ds-base -Version: 1.4.2.4 -Release: %{?relprefix}10%{?prerel}%{?dist} +Version: 1.4.3.8 +Release: %{?relprefix}5%{?prerel}%{?dist} License: GPLv3+ URL: https://www.port389.org Group: System Environment/Daemons @@ -174,43 +174,31 @@ Source2: %{name}-devel.README %if %{bundle_jemalloc} Source3: https://github.com/jemalloc/%{jemalloc_name}/releases/download/%{jemalloc_ver}/%{jemalloc_name}-%{jemalloc_ver}.tar.bz2 %endif -Patch00: 0000-Issue-50712-Version-comparison-doesn-t-work-correctl.patch -Patch01: 0001-Issue-50499-Fix-npm-audit-issues.patch -Patch02: 0002-Issue-50701-Add-additional-healthchecks-to-dsconf.patch -Patch03: 0003-Issue-50701-Fix-type-in-lint-report.patch -Patch04: 0004-Issue-50816-dsconf-allows-the-root-password-to-be-se.patch -Patch05: 0005-Issue-50812-dscontainer-executable-should-be-placed-.patch -Patch06: 0006-Ticket-50741-bdb_start-Detected-Disorderly-Shutdown-.patch -Patch07: 0007-Ticket-50667-dsctl-l-did-not-respect-PREFIX.patch -Patch08: 0008-Ticket-50709-Several-memory-leaks-reported-by-Valgri.patch -Patch09: 0009-Ticket-50736-RetroCL-trimming-may-crash-at-shutdown-.patch -Patch10: 0010-Issue-50806-Fix-minor-issues-in-lib389-health-checks.patch -Patch11: 0011-Issue-50599-Remove-db-region-files-prior-to-db-recov.patch -Patch12: 0012-Issue-50798-incorrect-bytes-in-format-string-fix-imp.patch -Patch13: 0013-Issue-50824-dsctl-remove-fails-with-name-ensure_str-.patch -Patch14: 0014-Issue-50818-dsconf-pwdpolicy-get-error.patch -Patch15: 0015-Ticket-50709-cont-Several-memory-leaks-reported-by-V.patch -Patch16: 0016-Issue-50829-Disk-monitoring-rotated-log-cleanup-caus.patch -Patch17: 0017-Ticket-50745-ns-slapd-hangs-during-CleanAllRUV-tests.patch -Patch18: 0018-Ticket-50727-change-syntax-validate-by-default-in-1..patch -Patch19: 0019-Ticket-50727-correct-mistaken-options-in-filter-vali.patch -Patch20: 0020-Issue-50599-Fix-memory-leak-when-removing-db-region-.patch -Patch21: 0021-Issue-50834-Incorrectly-setting-the-NSS-default-SSL-.patch -Patch22: 0022-Ticket-50741-cont-bdb_start-Detected-Disorderly-Shut.patch -Patch23: 0023-Issue-49254-Fix-compiler-failures-and-warnings.patch -Patch24: 0024-Issue-49990-Need-to-enforce-a-hard-maximum-limit-for.patch -Patch25: 0025-Issue-50850-Fix-dsctl-healthcheck-for-python36.patch -Patch26: 0026-Ticket-49624-cont-DB-Deadlock-on-modrdn-appears-to-c.patch -Patch27: 0027-Issue-50823-dsctl-doesn-t-work-with-slapd-in-the-ins.patch -Patch28: 0028-Ticket-50857-Memory-leak-in-ACI-using-IP-subject.patch -Patch29: 0029-Issue-50873-Fix-issues-with-healthcheck-tool.patch -Patch30: 0030-Issue-50873-Fix-healthcheck-and-virtual-attr-check.patch -Patch31: 0031-Issue-50886-Typo-in-the-replication-debug-message.patch -Patch32: 0032-Issue-50882-Fix-healthcheck-errors-for-instances-tha.patch -Patch33: 0033-Ticket-50490-objects-and-memory-leaks.patch -Patch34: 0034-Issue-50780-Fix-UI-issues.patch -Patch35: 0035-Issue-51129-SSL-alert-The-value-of-sslVersionMax-TLS.patch -Patch36: 0036-Issue-49731-undo-db_home_dir-under-dev-shm-dirsrv-fo.patch +Patch01: 0001-Issue-51076-prevent-unnecessarily-duplication-of-the.patch +Patch02: 0002-Ticket-51082-abort-when-a-empty-valueset-is-freed.patch +Patch03: 0003-Issue-51091-healthcheck-json-report-fails-when-mappi.patch +Patch04: 0004-Issue-51076-remove-unnecessary-slapi-entry-dups.patch +Patch05: 0005-Issue-51086-Improve-dscreate-instance-name-validatio.patch +Patch06: 0006-Issue-51102-RFE-ds-replcheck-make-online-timeout-con.patch +Patch07: 0007-Issue-51110-Fix-ASAN-ODR-warnings.patch +Patch08: 0008-Issue-51095-abort-operation-if-CSN-can-not-be-genera.patch +Patch09: 0009-Issue-51113-Allow-using-uid-for-replication-manager-.patch +Patch10: 0010-Issue-50931-RFE-AD-filter-rewriter-for-ObjectCategor.patch +Patch11: 0011-Issue-50746-Add-option-to-healthcheck-to-list-all-th.patch +Patch12: 0012-Issue-50984-Memory-leaks-in-disk-monitoring.patch +Patch13: 0013-Issue-50984-Memory-leaks-in-disk-monitoring.patch +Patch14: 0014-Issue-50201-nsIndexIDListScanLimit-accepts-any-value.patch +Patch15: 0015-Issue-51157-Reindex-task-may-create-abandoned-index-.patch +Patch16: 0016-Issue-51165-add-new-access-log-keywords-for-wtime-an.patch +Patch17: 0017-Issue-50912-pwdReset-can-be-modified-by-a-user.patch +Patch18: 0018-Issue-50791-Healthcheck-should-look-for-notes-A-F-in.patch +Patch19: 0019-Issue-51144-dsctl-fails-with-instance-names-that-con.patch +Patch20: 0020-Ticket-49859-A-distinguished-value-can-be-missing-in.patch +Patch21: 0021-Issue-49256-log-warning-when-thread-number-is-very-d.patch +Patch22: 0022-Issue-51188-db2ldif-crashes-when-LDIF-file-can-t-be-.patch +Patch23: 0023-Issue-51086-Fix-instance-name-length-for-interactive.patch +Patch24: 0024-Issue-51129-SSL-alert-The-value-of-sslVersionMax-TLS.patch +Patch25: 0025-Issue-50984-Memory-leaks-in-disk-monitoring.patch %description 389 Directory Server is an LDAPv3 compliant server. The base package includes @@ -370,15 +358,34 @@ CLANG_FLAGS="--enable-clang" %endif %if %{bundle_jemalloc} +# Override page size, bz #1545539 +# 4K +%ifarch %ix86 %arm x86_64 s390x +%define lg_page --with-lg-page=12 +%endif + +# 64K +%ifarch ppc64 ppc64le aarch64 +%define lg_page --with-lg-page=16 +%endif + +# Override huge page size on aarch64 +# 2M instead of 512M +%ifarch aarch64 +%define lg_hugepage --with-lg-hugepage=21 +%endif + # Build jemalloc pushd ../%{jemalloc_name}-%{jemalloc_ver} %configure \ --libdir=%{_libdir}/%{pkgname}/lib \ - --bindir=%{_libdir}/%{pkgname}/bin -make + --bindir=%{_libdir}/%{pkgname}/bin \ + --enable-prof +make %{?_smp_mflags} popd %endif + # Enforce strict linking %define _strict_symbol_defs_build 1 @@ -431,7 +438,7 @@ popd mkdir -p $RPM_BUILD_ROOT/var/log/%{pkgname} mkdir -p $RPM_BUILD_ROOT/var/lib/%{pkgname} -mkdir -p $RPM_BUILD_ROOT/var/lock/%{pkgname} +mkdir -p $RPM_BUILD_ROOT/var/3lock/%{pkgname} # for systemd mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/systemd/system/%{groupname}.wants @@ -665,6 +672,7 @@ exit 0 %{_libdir}/%{pkgname}/libns-dshttpd-*.so %{_libdir}/%{pkgname}/libsds.so.* %{_libdir}/%{pkgname}/libldaputil.so.* +%{_libdir}/%{pkgname}/librewriters.so* %if %{bundle_jemalloc} %{_libdir}/%{pkgname}/lib/libjemalloc.so.2 %endif @@ -808,59 +816,254 @@ exit 0 %doc README.md %changelog -* Mon Aug 24 2020 Mark Reynolds - 1.4.2.4-10 -- Bump version to 1.4.2.4-10 -- Resolves: Bug 1862170 - fix default.ini file - -* Fri Aug 21 2020 Mark Reynolds - 1.4.2.4-9 -- Bump version to 1.4.2.4-9 -- Resolves: Bug 1867097 - Memory leak in ACI using IP subject -- Resolves: Bug 1862170 - python3-lib389 pulls unnecessary bash-completion package -- Resolves: Bug 1867988 - SSL alert: The value of sslVersionMax "TLS1.3" is higher than the supported version - -* Fri Mar 6 2020 Mark Reynolds - 1.4.2.4-8 -- Bump version to 1.4.2.4-8 -- Resolves: Bug 1807971 - dsctl healthcheck fails at checking replica when conflict entries are present - -* Fri Feb 7 2020 Mark Reynolds - 1.4.2.4-7 -- Bump version to 1.4.2.4-7 -- Resolves: Bug 1744662 - DB Deadlock on modrdn appears to corrupt database and entry cache -- Resolves: Bug 1779216 - dsctl doesn't work with 'slapd-' in the instance name -- Resolves: Bug 1790984 - Crash on startup: Bus error in __env_faultmem.isra.1.part.2 -- Resolves: Bug 1793060 - dsctl healthcheck issues error : type object 'datetime.date' has no attribute 'fromisoformat' -- Resolves: Bug 1758494 - LeakSanitizer: detected memory leaks in do_add -- Resolves: Bug 1790975 - Several memory leaks reported by Valgrind for 389-ds 1.3.9.1-10. - -* Mon Jan 20 2020 Mark Reynolds - 1.4.2.4-6 -- Resolves: Bug 1776227 - Error: 'PwPolicyManager' object has no attribute 'get_attr_list' -- Resolves: Bug 1790975 - Several memory leaks reported by Valgrind for 389-ds 1.3.9.1-10(fix regression) -- Resolves: Bug 1758473 - AddressSanitizer: heap-use-after-free in log_get_loglist -- Resolves: Bug 1790259 - Change the default behavior of 'nsslapd-verify-filter-schema' -- Resolves: Bug 1773114 - ns-slapd hangs during CleanAllRUV tests - -* Tue Jan 14 2020 Mark Reynolkds - 1.4.2.4-5 -- Bump version to 1.4.2.4-5 -- Resolves: Bug 1676699 - dsconf allows to set an empty password for Directory Manager -- Resolves: Bug 1714688 - dscontainer executable should be placed under /usr/libexec/dirsrv/ -- Resolves: Bug 1773115 - bdb_start - Detected Disorderly Shutdown last time Directory Server was running -- Resolves: Bug 1790975 - Several memory leaks reported by Valgrind for 389-ds 1.3.9.1-10 -- Resolves: Bug 1790979 - ns-slapd is crashing while restarting ipactl -- Resolves: Bug 1790981 - Entry cache contention during base search -- Resolves: Bug 1790984 - Crash on startup: Bus error in __env_faultmem.isra.1.part.2 - -* Wed Nov 27 2019 Mark Reynolds - 1.4.2.4-4 -- Bump version to 1.4.2.4-4 -- Resolves: Bug 1685160 - [RFE] 389-DS Health Check Tool - -* Fri Nov 15 2019 Mark Reynolds - 1.4.2.4-3 -- Bump version to 1.4.2.4-3 -- Issue 50712 - Version comparison doesn't work correctly on git builds (relates to #1748994) - -* Fri Nov 15 2019 Matus Honek - 1.4.2.4-2 -- Bump version to 1.4.2.4-2 -- Fix missing runtime lib389 dependency (relates to #1748994) - -* Thu Nov 14 2019 Mark Reynolds - 1.4.2.4-1 -- Bump verison to 1.4.2.4-1 -- Resolves: Bug 1748994 - Rebase 389-ds-base to 1.4.2 - +* Wed Aug 5 2020 Mark Reynolds - 1.4.3.8-5 +- Bump version to 1.4.3.8-5 +- Resolves: Bug 1841086 - SSL alert: The value of sslVersionMax "TLS1.3" is higher than the supported version +- Resolves: Bug 1800529 - Memory leaks in disk monitoring +- Resolves: Bug 1748227 - Instance name length is not enforced +- Resolves: Bug 1849418 - python3-lib389 pulls unnecessary bash-completion package + +* Fri Jun 26 2020 Mark Reynolds - 1.4.3.8-4 +- Bump version to 1.4.3.8-4 +- Resolves: Bug 1806978 - ns-slapd crashes during db2ldif +- Resolves: Bug 1450863 - Log warning when tuning of nsslapd-threadnumber above or below the optimal value +- Resolves: Bug 1647017 - A distinguished value of a single valued attribute can be missing in an entry +- Resolves: Bug 1806573 - Dsctl healthcheck doesn't work when using instance name with 'slapd-' +- Resolves: Bug 1807773 - dsctl healthcheck : typo in DSREPLLE0002 Lint error suggested resolution commands +- Resolves: Bug 1843567 - Healthcheck to find notes=F +- Resolves: Bug 1845094 - User/Directory Manager can modify Password Policy attribute "pwdReset" +- Resolves: Bug 1850275 - Add new access log keywords for time spent in work queue and actual operation time +- Resolves: Bug 1442386 - Recreating an index while changing case will create an indexfile with the old name (different case) and after restart the indexfile is abandoned +- Resolves: Bug 1672574 - nsIndexIDListScanLimit accepts any value +- Resolves: Bug 1800529 - Memory leaks in disk monitoring + +* Fri Jun 5 2020 Mark Reynolds - 1.4.3.8-3 +- Bump version to 1.4.3.8-3 +- Resolves: Bug 1835619 - Healthcheck with --json option reports "Object of type 'bytes' is not JSON serializable" when mapping tree is deleted +- Resolves: Bug 1836428 - Directory Server ds-replcheck RFE to add a timeout command-line arg/value to wait longer when connecting to a replica server +- Resolves: Bug 1843090 - abort when a empty valueset is freed +- Resolves: Bug 1843156 - Prevent unnecessarily duplication of the target entry +- Resolves: Bug 1843157 - Check for clock errors and time skew +- Resolves: Bug 1843159 - RFE AD filter rewriter for ObjectCategory +- Resolves: Bug 1843162 - Creating Replication Manager fails if uid=repman is used +- Resolves: Bug 1816851 - Add option to healthcheck to list all the lint reports +- Resolves: Bug 1748227 - Instance name length is not enforced +- Resolves: Bug 1748244 - dscreate doesn't sanitize instance name + +* Mon May 11 2020 Mark Reynolds - 1.4.3.8-2 +- Bump version to 1.4.3.8-2 +- Resolves: Bug 1833350 - Remove cockpit dependancies that are breaking builds + +* Mon May 11 2020 Mark Reynolds - 1.4.3.8-1 +- Bump version to 1.4.3.8-1 +- Resolves: Bug 1833350 - Rebase 389-ds-base for RHEL 8.3 +- Resolves: Bug 1728943 - [RFE] Advance options in RHDS Disk Monitoring Framework +- Resolves: Bug 1775285 - [RFE] Implement the Password Policy attribute "pwdReset" +- Resolves: Bug 1638875 - [RFE] extract key/certs pem file into a private namespace +- Resolves: Bug 1758478 - AddressSanitizer: heap-buffer-overflow in ldap_utf8prev +- Resolves: Bug 1795943 - Port dbmon.sh from legacy tools package +- Resolves: Bug 1798394 - Port dbgen from legacy tools package +- Resolves: Bug 1800529 - Memory leaks in disk monitoring +- Resolves: Bug 1807419 - Unable to create a suffix with countryName either via dscreate or the admin console +- Resolves: Bug 1816848 - Database links: get_monitor() takes 1 positional argument but 2 were given +- Resolves: Bug 1816854 - Setting nsslapd-allowed-sasl-mechanisms truncates the value +- Resolves: Bug 1816857 - Searches on cn=config takes values with spaces and makes multiple attributes out of them +- Resolves: Bug 1816859 - lib389 - Replace exec() with setattr() +- Resolves: Bug 1816862 - Memory leak in indirect COS +- Resolves: Bug 1829071 - Installation of RHDS 11 fails on RHEL8 server with IPv6 disabled +- Resolves: Bug 1833515 - set 'nsslapd-enable-upgrade-hash: off' as this raises warnings in IPA +- Resolves: Bug 1790986 - cenotaph errors on modrdn operations +- Resolves: Bug 1769734 - Heavy StartTLS connection load can randomly fail with err=1 +- Resolves: Bug 1758501 - LeakSanitizer: detected memory leaks in changelog5_init and perfctrs_init + +* Fri May 8 2020 Mark Reynolds - 1.4.3.8-0 +- Bump version to 1.4.3.8-0 +- Issue 51078 - Add nsslapd-enable-upgrade-hash to the schema +- Issue 51054 - Revise ACI target syntax checking +- Issue 51068 - deadlock when updating the schema +- Issue 51060 - unable to set sslVersionMin to TLS1.0 +- Issue 51064 - Unable to install server where IPv6 is disabled +- Issue 51051 - CLI fix consistency issues with confirmations +- Issue 49731 - undo db_home_dir under /dev/shm/dirsrv for now +- Issue 51054 - AddressSanitizer: heap-buffer-overflow in ldap_utf8prev +- Issue 51047 - React deprecating ComponentWillMount +- Issue 50499 - fix npm audit issues +- Issue 50545 - Port dbgen.pl to dsctl + +* Wed Apr 22 2020 Mark Reynolds - 1.4.3.7-1 +- Bump version to 1.4.3.7 +- Issue 51024 - syncrepl_entry callback does not contain attributes added by postoperation plugins +- Issue 51035 - Heavy StartTLS connection load can randomly fail with err=1 +- Issue 49731 - undo db_home_dir under /dev/shm/dirsrv for now +- Issue 51031 - UI - transition between two instances needs improvement + +* Thu Apr 16 2020 Mark Reynolds - 1.4.3.6-1 +- Bump version to 1.4.3.6 +- Issue 50933 - 10rfc2307compat.ldif is not ready to set used by default +- Issue 50931 - RFE AD filter rewriter for ObjectCategory +- Issue 51016 - Fix memory leaks in changelog5_init and perfctrs_init +- Issue 50980 - RFE extend usability for slapi_compute_add_search_rewriter and slapi_compute_add_evaluator +- Issue 51008 - dbhome in containers +- Issue 50875 - Refactor passwordUserAttributes's and passwordBadWords's code +- Issue 51014 - slapi_pal.c possible static buffer overflow +- Issue 50545 - remove dbmon "incr" option from arg parser +- Issue 50545 - Port dbmon.sh to dsconf +- Issue 51005 - AttributeUniqueness plugin's DN parameter should not have a default value +- Issue 49731 - Fix additional issues with setting db home directory by default +- Issue 50337 - Replace exec() with setattr() +- Issue 50905 - intermittent SSL hang with rhds +- Issue 50952 - SSCA lacks basicConstraint:CA +- Issue 50640 - Database links: get_monitor() takes 1 positional argument but 2 were given +- Issue 50869 - Setting nsslapd-allowed-sasl-mechanisms truncates the value + +* Wed Apr 1 2020 Mark Reynolds - 1.4.3.5-1 +- Bump version to 1.4.3.5 +- Issue 50994 - Fix latest UI bugs found by QE +- Issue 50933 - rfc2307compat.ldif +- Issue 50337 - Replace exec() with setattr() +- Issue 50984 - Memory leaks in disk monitoring +- Issue 50984 - Memory leaks in disk monitoring +- Issue 49731 - dscreate fails in silent mode because of db_home_dir +- Issue 50975 - Revise UI branding with new minimized build +- Issue 49437 - Fix memory leak with indirect COS +- Issue 49731 - Do not add db_home_dir to template-dse.ldif +- Issue 49731 - set and use db_home_directory by default +- Issue 50971 - fix BSD_SOURCE +- Issue 50744 - -n option of dbverify does not work +- Issue 50952 - SSCA lacks basicConstraint:CA +- Issue 50976 - Clean up Web UI source directory from unused files +- Issue 50955 - Fix memory leaks in chaining plugin(part 2) +- Issue 50966 - UI - Database indexes not using typeAhead correctly +- Issue 50974 - UI - wrong title in "Delete Suffix" popup +- Issue 50972 - Fix cockpit plugin build +- Issue 49761 - Fix CI test suite issues +- Issue 50971 - Support building on FreeBSD. +- Issue 50960 - [RFE] Advance options in RHDS Disk Monitoring Framework +- Issue 50800 - wildcards in rootdn-allow-ip attribute are not accepted +- Issue 50963 - We should bundle *.min.js files of Console +- Issue 50860 - Port Password Policy test cases from TET to python3 Password grace limit section. +- Issue 50860 - Port Password Policy test cases from TET to python3 series of bugs Port final +- Issue 50954 - buildnum.py - fix date formatting issue + +* Mon Mar 16 2020 Mark Reynolds - 1.4.3.4-1 +- Bump version to 1.4.3.4 +- Issue 50954 - Port buildnum.pl to python(part 2) +- Issue 50955 - Fix memory leaks in chaining plugin +- Issue 50954 - Port buildnum.pl to python +- Issue 50947 - change 00core.ldif objectClasses for openldap migration +- Issue 50755 - setting nsslapd-db-home-directory is overriding db_directory +- Issue 50937 - Update CLI for new backend split configuration +- Issue 50860 - Port Password Policy test cases from TET to python3 pwp.sh +- Issue 50945 - givenname alias of gn from openldap +- Issue 50935 - systemd override in lib389 for dscontainer +- Issue 50499 - Fix npm audit issues +- Issue 49761 - Fix CI test suite issues +- Issue 50618 - clean compiler warning and log level +- Issue 50889 - fix compiler issues +- Issue 50884 - Health check tool DSEldif check fails +- Issue 50926 - Remove dual spinner and other UI fixes +- Issue 50928 - Unable to create a suffix with countryName +- Issue 50758 - Only Recommend bash-completion, not Require +- Issue 50923 - Fix a test regression +- Issue 50904 - Connect All React Components And Refactor the Main Navigation Tab Code +- Issue 50920 - cl-dump exit code is 0 even if command fails with invalid arguments +- Issue 50923 - Add test - dsctl fails to remove instances with dashes in the name +- Issue 50919 - Backend delete fails using dsconf +- Issue 50872 - dsconf can't create GSSAPI replication agreements +- Issue 50912 - RFE - add password policy attribute pwdReset +- Issue 50914 - No error returned when adding an entry matching filters for a non existing automember group +- Issue 50889 - Extract pem files into a private namespace +- Issue 50909 - nsDS5ReplicaId cant be set to the old value it had before +- Issue 50686 - Port fractional replication test cases from TET to python3 final +- Issue 49845 - Remove pkgconfig check for libasan +- Issue:50860 - Port Password Policy test cases from TET to python3 bug624080 +- Issue:50860 - Port Password Policy test cases from TET to python3 series of bugs +- Issue 50786 - connection table freelist +- Issue 50618 - support cgroupv2 +- Issue 50900 - Fix cargo offline build +- Issue 50898 - ldclt core dumped when run with -e genldif option + +* Mon Feb 17 2020 Matus Honek - 1.4.3.3-3 +- Bring back the necessary c_rehash util (#1803370) + +* Fri Feb 14 2020 Mark Reynolds - 1.4.3.3-2 +- Bump version to 1.4.3.3-2 +- Remove unneeded perl dependencies +- Change bash-completion to "Recommends" instead of "Requires" + +* Thu Feb 13 2020 Mark Reynolds - 1.4.3.3-1 +- Bump version to 1.4.3.3 +- Issue 50855 - remove unused file from UI +- Issue 50855 - UI: Port Server Tab to React +- Issue 49845 - README does not contain complete information on building +- Issue 50686 - Port fractional replication test cases from TET to python3 part 1 +- Issue 49623 - cont cenotaph errors on modrdn operations +- Issue 50882 - Fix healthcheck errors for instances that do not have TLS enabled +- Issue 50886 - Typo in the replication debug message +- Issue 50873 - Fix healthcheck and virtual attr check +- Issue 50873 - Fix issues with healthcheck tool +- Issue 50028 - Add a new CI test case +- Issue 49946 - Add a new CI test case +- Issue 50117 - Add a new CI test case +- Issue 50787 - fix implementation of attr unique +- Issue 50859 - support running only with ldaps socket +- Issue 50823 - dsctl doesn't work with 'slapd-' in the instance name +- Issue 49624 - cont - DB Deadlock on modrdn appears to corrupt database and entry cache +- Issue 50867 - Fix minor buildsys issues +- Issue 50737 - Allow building with rust online without vendoring +- Issue 50831 - add cargo.lock to allow offline builds +- Issue 50694 - import PEM certs on startup +- Issue 50857 - Memory leak in ACI using IP subject +- Issue 49761 - Fix CI test suite issues +- Issue 50853 - Fix NULL pointer deref in config setting +- Issue 50850 - Fix dsctl healthcheck for python36 +- Issue 49990 - Need to enforce a hard maximum limit for file descriptors +- Issue 48707 - ldapssotoken for authentication + +* Tue Jan 28 2020 Fedora Release Engineering - 1.4.3.2-1.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild + +* Thu Jan 23 2020 Mark Reynolds - 1.4.3.2-1 +- Bump version to 1.4.3.2 +- Issue 49254 - Fix compiler failures and warnings +- Issue 50741 - cont bdb_start - Detected Disorderly Shutdown +- Issue 50836 - Port Schema UI tab to React +- Issue 50842 - Decrease 389-console Cockpit component size +- Issue 50790 - Add result text when filter is invalid +- Issue 50627 - Add ASAN logs to HTML report +- Issue 50834 - Incorrectly setting the NSS default SSL version max +- Issue 50829 - Disk monitoring rotated log cleanup causes heap-use-after-free +- Issue 50709 - (cont) Several memory leaks reported by Valgrind for 389-ds 1.3.9.1-10 +- Issue 50784 - performance testing scripts +- Issue 50599 - Fix memory leak when removing db region files +- Issue 49395 - Set the default TLS version min to TLS1.2 +- Issue 50818 - dsconf pwdpolicy get error +- Issue 50824 - dsctl remove fails with "name 'ensure_str' is not defined" +- Issue 50599 - Remove db region files prior to db recovery +- Issue 50812 - dscontainer executable should be placed under /usr/libexec/dirsrv/ +- Issue 50816 - dsconf allows the root password to be set to nothing +- Issue 50798 - incorrect bytes in format string(fix import issue) + +* Thu Jan 16 2020 Adam Williamson - 1.4.3.1-3 +- Backport two more import/missing function fixes + +* Wed Jan 15 2020 Adam Williamson - 1.4.3.1-2 +- Backport 828aad0 to fix missing imports from 1.4.3.1 + +* Mon Jan 13 2020 Mark Reynolds - 1.4.3.1-1 +- Bump version to 1.4.3.1 +- Issue 50798 - incorrect bytes in format string +- Issue 50545 - Add the new replication monitor functionality to UI +- Issue 50806 - Fix minor issues in lib389 health checks +- Issue 50690 - Port Password Storage test cases from TET to python3 part 1 +- Issue 49761 - Fix CI test suite issues +- Issue 49761 - Fix CI test suite issues +- Issue 50754 - Add Restore Change Log option to CLI +- Issue 48055 - CI test - automember_plugin(part2) +- Issue 50667 - dsctl -l did not respect PREFIX +- Issue 50780 - More CLI fixes +- Issue 50649 - lib389 without defaults.inf +- Issue 50780 - Fix UI issues +- Issue 50727 - correct mistaken options in filter validation patch +- Issue 50779 - lib389 - conflict compare fails for DN's with spaces +- Set branch version to 1.4.3.0