From c824da947d55fab59946eb7d37fa21878ecb7359 Mon Sep 17 00:00:00 2001 From: Viktor Ashirov Date: Fri, 5 Jun 2026 11:24:42 +0200 Subject: [PATCH] Bump version to 2.9.0 - Resolves: RHEL-165978 - Replication halt caused by an incorrect setting of "nsslapd-changelogmaxage" - Resolves: RHEL-166003 - Crash in replica_config_add when manually configuring a replica with an incorrect nsds5ReplicaRoot. - Resolves: RHEL-166004 - Possible memory leak when using the Retro Changelog plugin. - Resolves: RHEL-168908 - ns-slapd fails to shutdown when deferred memberof update is in progress - Resolves: RHEL-168964 - Web console doesn't show the sub suffix of ou=foo,ou=people,dc=example,dc=com. [rhel-9] - Resolves: RHEL-168972 - Replica installation is failing with message MDB_BAD_VALSIZE: Unsupported size of key/DB name/data, or wrong DUPFIXED [rhel-9] - Resolves: RHEL-169530 - Rebase 389-ds-base to 2.9.x - Resolves: RHEL-170270 - DS 12 does not handle escape char in bind user [rhel-9] - Resolves: RHEL-170275 - dnaSharedConfig: "dnaPortNum: 0" [rhel-9] - Resolves: RHEL-170280 - Memory leaks in syncrepl plugin during persistent search operations [rhel-9] - Resolves: RHEL-170287 - access log - suspicious wtime optime negative and large values in internal op [rhel-9] - Resolves: RHEL-170477 - An online reinitialization with LMDB is terminating the receiving server [rhel-9] - Resolves: RHEL-170480 - dsctl healthcheck DSMOLE0001 inaccurate recommendations when there is more than 1 LDAP backend [rhel-9] - Resolves: RHEL-170651 - passwordbadwords attribute of the local password policy is not functioning [rhel-9] - Resolves: RHEL-170732 - Memory leaks in IPA context on server restart [rhel-9] - Resolves: RHEL-174525 - [RFE] Add OS-level thread names to all server threads [rhel-9] - Resolves: RHEL-180717 - Online export is failing when using the option "-s" [rhel-9] --- ...etroCL-plugin-generates-invalid-LDIF.patch | 80 - ...-plugin-null-pointer-dereference-if-.patch | 45 + ...x-audit-issue-with-npm-brace-expansi.patch | 37 + ...g-replication-online-total-init-the-.patch | 318 -- ...ssSanitizer-leaks-found-by-acl-test-.patch | 687 ++++ ...e-Revise-paged-result-search-locking.patch | 765 ---- ...-ordering-mismatch-after-upgrade-717.patch | 213 -- ...anitizer-memory-leaks-in-CoS-cache-e.patch | 54 + ...ndex-ordering-mismatch-after-upgrade.patch | 67 - ...ex-adds-tombstones-to-ancestorid-cau.patch | 169 + ...0007-generates-incorrect-remediation.patch | 235 -- ...-healthcheck-DSMOLE0001-inaccurate-r.patch | 199 + ...rse.HelpFormatter-_format_actions_us.patch | 48 - ...AD_VALSIZE-error-when-updating-index.patch | 651 ++++ ...ix-test389-imports-on-older-branches.patch | 39 + ...89-ds-base-OpenScanHub-Leaks-Detecte.patch | 53 - ...AD_VALSIZE-error-while-handling-VLV-.patch | 197 - ...e-6542-RPM-build-errors-on-Fedora-42.patch | 43 - ...e-6476-Fix-build-failure-with-GCC-15.patch | 3318 ----------------- ...t-index-scan-limits-for-system-index.patch | 785 ---- ...pgrade-function-to-remove-nsIndexIDL.patch | 212 -- ...pgrade-function-to-remove-ancestorid.patch | 313 -- ...t-and-log-index-ordering-mismatch-du.patch | 300 -- ...sctl-index-check-command-for-offline.patch | 1233 ------ ...uring-replication-online-total-init-.patch | 135 - ...-6784-6214-Fix-CI-test-failures-7077.patch | 877 ----- ...evert_cache-never-called-in-modrdn-7.patch | 57 - ...47-Fix-health_system_indexes_test.py.patch | 24 - ...eakSanitizer-various-leaks-during-re.patch | 71 - ...essed-access-log-rotations-skipped-a.patch | 551 --- ...st-Simplify-test_reserve_descriptor_.patch | 93 - ...repl-tests-fail-in-FIPS-mode-due-to-.patch | 92 - ...ttribute-uniqueness-fix-usage-for-ex.patch | 33 - ...db2index-needs-some-hardening-with-M.patch | 201 - ...rgparse.HelpFormatter-_format_action.patch | 41 - ...DB_BAD_VALSIZE-error-while-handling-.patch | 32 - ...exicographical-order-for-ancestorid-.patch | 34 - ...allow-password-history-to-be-set-to-.patch | 89 - ...3-UI-fix-certificate-table-and-modal.patch | 260 -- ...e-integerOrderingMatch-requirement-f.patch | 538 --- ...e-memberof_del_dn_from_groups-from-M.patch | 202 - ...Issue-5853-Update-concread-to-0.5.10.patch | 952 ----- ...ns-that-create-threads-need-to-updat.patch | 86 - 0036-Security-fix-for-CVE-2025-14905.patch | 93 - ...mplement-a-pre-close-plugin-function.patch | 262 -- ...ew-plugin-pre-close-function-check-t.patch | 34 - 389-ds-base.spec | 155 +- main.fmf | 2 +- sources | 6 +- 49 files changed, 1965 insertions(+), 13016 deletions(-) delete mode 100644 0001-Issue-7049-RetroCL-plugin-generates-invalid-LDIF.patch create mode 100644 0001-Issue-7554-deref-plugin-null-pointer-dereference-if-.patch create mode 100644 0002-Issue-3555-UI-Fix-audit-issue-with-npm-brace-expansi.patch delete mode 100644 0002-Issue-7096-During-replication-online-total-init-the-.patch create mode 100644 0003-Issue-6922-AddressSanitizer-leaks-found-by-acl-test-.patch delete mode 100644 0003-Issue-Revise-paged-result-search-locking.patch delete mode 100644 0004-Issue-7172-Index-ordering-mismatch-after-upgrade-717.patch create mode 100644 0004-Issue-7437-LeakSanitizer-memory-leaks-in-CoS-cache-e.patch delete mode 100644 0005-Issue-7172-2nd-Index-ordering-mismatch-after-upgrade.patch create mode 100644 0005-Issue-7372-Reindex-adds-tombstones-to-ancestorid-cau.patch delete mode 100644 0006-Issue-7189-DSBLE0007-generates-incorrect-remediation.patch create mode 100644 0006-Issue-7327-dsctl-healthcheck-DSMOLE0001-inaccurate-r.patch delete mode 100644 0007-Issue-7184-argparse.HelpFormatter-_format_actions_us.patch create mode 100644 0007-Issue-7267-MDB_BAD_VALSIZE-error-when-updating-index.patch create mode 100644 0008-Fix-test389-imports-on-older-branches.patch delete mode 100644 0008-Issue-7027-2nd-389-ds-base-OpenScanHub-Leaks-Detecte.patch delete mode 100644 0009-Issue-7213-MDB_BAD_VALSIZE-error-while-handling-VLV-.patch delete mode 100644 0010-Issue-6542-RPM-build-errors-on-Fedora-42.patch delete mode 100644 0011-Issue-6476-Fix-build-failure-with-GCC-15.patch delete mode 100644 0012-Issue-7223-Revert-index-scan-limits-for-system-index.patch delete mode 100644 0013-Issue-7223-Add-upgrade-function-to-remove-nsIndexIDL.patch delete mode 100644 0014-Issue-7223-Add-upgrade-function-to-remove-ancestorid.patch delete mode 100644 0015-Issue-7223-Detect-and-log-index-ordering-mismatch-du.patch delete mode 100644 0016-Issue-7223-Add-dsctl-index-check-command-for-offline.patch delete mode 100644 0017-Issue-7096-2nd-During-replication-online-total-init-.patch delete mode 100644 0018-Issue-7076-6992-6784-6214-Fix-CI-test-failures-7077.patch delete mode 100644 0019-Issue-7076-Fix-revert_cache-never-called-in-modrdn-7.patch delete mode 100644 0020-Issue-6947-Fix-health_system_indexes_test.py.patch delete mode 100644 0021-Issue-7121-2nd-LeakSanitizer-various-leaks-during-re.patch delete mode 100644 0022-Issue-7150-Compressed-access-log-rotations-skipped-a.patch delete mode 100644 0023-Issue-7224-CI-Test-Simplify-test_reserve_descriptor_.patch delete mode 100644 0024-Issue-7231-Sync-repl-tests-fail-in-FIPS-mode-due-to-.patch delete mode 100644 0025-Issue-7248-CLI-attribute-uniqueness-fix-usage-for-ex.patch delete mode 100644 0026-Issue-CLI-dsctl-db2index-needs-some-hardening-with-M.patch delete mode 100644 0027-Issue-7184-2nd-argparse.HelpFormatter-_format_action.patch delete mode 100644 0028-Issue-7213-2nd-MDB_BAD_VALSIZE-error-while-handling-.patch delete mode 100644 0029-Issue-7223-Use-lexicographical-order-for-ancestorid-.patch delete mode 100644 0030-Issue-7066-7052-allow-password-history-to-be-set-to-.patch delete mode 100644 0031-Issue-7243-UI-fix-certificate-table-and-modal.patch delete mode 100644 0032-Issue-7223-Remove-integerOrderingMatch-requirement-f.patch delete mode 100644 0033-Issue-7053-Remove-memberof_del_dn_from_groups-from-M.patch delete mode 100644 0034-Issue-5853-Update-concread-to-0.5.10.patch delete mode 100644 0035-Issue-7271-plugins-that-create-threads-need-to-updat.patch delete mode 100644 0036-Security-fix-for-CVE-2025-14905.patch delete mode 100644 0037-Issue-7271-implement-a-pre-close-plugin-function.patch delete mode 100644 0038-Issue-7271-Add-new-plugin-pre-close-function-check-t.patch diff --git a/0001-Issue-7049-RetroCL-plugin-generates-invalid-LDIF.patch b/0001-Issue-7049-RetroCL-plugin-generates-invalid-LDIF.patch deleted file mode 100644 index f4ae039..0000000 --- a/0001-Issue-7049-RetroCL-plugin-generates-invalid-LDIF.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 94a52cd03a6fcccf78a4d7e5c4adc65fb777fcfb Mon Sep 17 00:00:00 2001 -From: Viktor Ashirov -Date: Mon, 10 Nov 2025 13:20:28 +0100 -Subject: [PATCH] Issue 7049 - RetroCL plugin generates invalid LDIF - -Bug Description: -When a replicated modification marked with LDAP_MOD_IGNORE is logged, -`changes` attribute contains invalid LDIF: - -``` -replace: modifiersName -modifiersName: cn=MemberOf Plugin,cn=plugins,cn=config -- -modifyTimestamp: 20250903092211Z -- -``` -Line `replace: modifyTimestamp` is missing. - -A similar issue is present in audit log: -``` -time: 20251031064114 -dn: ou=tuser,dc=example,dc=com -result: 0 -changetype: modify -add: objectClass -objectClass: nsMemberOf -- -replace: modifiersName -modifiersName: cn=MemberOf Plugin,cn=plugins,cn=config -- -- -``` -Dash separator is logged, while the operation is not. -This issue is not present wheh JSON format is used. - -Fix Description: -* retrocl_po.c: add a default case to skip the entire modification if it - has LDAP_MOD_IGNORE flag. -* auditlog.c: write the dash separator only if operation type is not - LDAP_MOD_IGNORE - -Fixes: https://github.com/389ds/389-ds-base/issues/7049 - -Reviewed by: @progier389 (Thanks!) ---- - ldap/servers/plugins/retrocl/retrocl_po.c | 3 +++ - ldap/servers/slapd/auditlog.c | 2 +- - 2 files changed, 4 insertions(+), 1 deletion(-) - -diff --git a/ldap/servers/plugins/retrocl/retrocl_po.c b/ldap/servers/plugins/retrocl/retrocl_po.c -index e447ccdfb..277711dd3 100644 ---- a/ldap/servers/plugins/retrocl/retrocl_po.c -+++ b/ldap/servers/plugins/retrocl/retrocl_po.c -@@ -99,6 +99,9 @@ make_changes_string(LDAPMod **ldm, const char **includeattrs) - addlenstr(l, ldm[i]->mod_type); - addlenstr(l, "\n"); - break; -+ default: -+ /* LDAP_MOD_IGNORE or unknown - skip this mod entirely */ -+ continue; - } - for (j = 0; ldm[i]->mod_bvalues != NULL && - ldm[i]->mod_bvalues[j] != NULL; -diff --git a/ldap/servers/slapd/auditlog.c b/ldap/servers/slapd/auditlog.c -index 32fcea38a..e2db40722 100644 ---- a/ldap/servers/slapd/auditlog.c -+++ b/ldap/servers/slapd/auditlog.c -@@ -853,8 +853,8 @@ write_audit_file( - slapi_ch_free((void **)&buf); - } - } -+ addlenstr(l, "-\n"); - } -- addlenstr(l, "-\n"); - } - break; - --- -2.52.0 - diff --git a/0001-Issue-7554-deref-plugin-null-pointer-dereference-if-.patch b/0001-Issue-7554-deref-plugin-null-pointer-dereference-if-.patch new file mode 100644 index 0000000..e7900bb --- /dev/null +++ b/0001-Issue-7554-deref-plugin-null-pointer-dereference-if-.patch @@ -0,0 +1,45 @@ +From 71cda087462c7cef744555676603c7c5fde3ca55 Mon Sep 17 00:00:00 2001 +From: Mark Reynolds +Date: Wed, 3 Jun 2026 17:52:09 -0400 +Subject: [PATCH 1/8] Issue 7554 - deref plugin null pointer dereference if + ber_init fails + +Description: + +**CWE**: CWE-476 (NULL Pointer Dereference) + +A flaw in the 389 Directory Server's dereference control plugin allows an +unauthenticated attacker to crash the LDAP server when the system is under +memory pressure(OOM). The deref plugin, enabled by default, fails to check for +a memory allocation failure before using the result, causing the server +process to terminate. + +CI test 'test_deref_and_access_control' already covers this fix. + +relates: https://github.com/389ds/389-ds-base/issues/7554 + +Reviewed by: tbordaz & progier(Thanks!!) +--- + ldap/servers/plugins/deref/deref.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/ldap/servers/plugins/deref/deref.c b/ldap/servers/plugins/deref/deref.c +index fc1c10f71..fc157f6d6 100644 +--- a/ldap/servers/plugins/deref/deref.c ++++ b/ldap/servers/plugins/deref/deref.c +@@ -357,6 +357,12 @@ deref_parse_ctrl_value(DerefSpecList *speclist, const struct berval *ctrlbv, int + } + + ber = ber_init((struct berval *)ctrlbv); ++ if (!ber) { ++ *ldapcode = LDAP_UNWILLING_TO_PERFORM; ++ *ldaperrtext = "Deref control parsing failed to initialize BER element"; ++ return; ++ } ++ + for (tag = ber_first_element(ber, &len, &last); + (tag != LBER_ERROR) && (tag != LBER_END_OF_SEQORSET); + tag = ber_next_element(ber, &len, last)) { +-- +2.54.0 + diff --git a/0002-Issue-3555-UI-Fix-audit-issue-with-npm-brace-expansi.patch b/0002-Issue-3555-UI-Fix-audit-issue-with-npm-brace-expansi.patch new file mode 100644 index 0000000..42d5476 --- /dev/null +++ b/0002-Issue-3555-UI-Fix-audit-issue-with-npm-brace-expansi.patch @@ -0,0 +1,37 @@ +From d42d7eefa937d4f12e21929210786274f9c8e849 Mon Sep 17 00:00:00 2001 +From: Simon Pichugin +Date: Thu, 4 Jun 2026 19:21:30 -0700 +Subject: [PATCH 2/8] Issue 3555 - UI - Fix audit issue with npm - + brace-expansion (#7556) + +Description: Run npm audit fix to address the vulnerability +in brace-expansion. + +Relates: https://github.com/389ds/389-ds-base/issues/3555 +Relates: https://github.com/389ds/389-ds-base/issues/7527 + +Reviewed by: jchapma (Thanks!) +--- + src/cockpit/389-console/package-lock.json | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/cockpit/389-console/package-lock.json b/src/cockpit/389-console/package-lock.json +index 6c8ccdbd8..1efed1c1d 100644 +--- a/src/cockpit/389-console/package-lock.json ++++ b/src/cockpit/389-console/package-lock.json +@@ -2377,9 +2377,9 @@ + } + }, + "node_modules/brace-expansion": { +- "version": "5.0.5", +- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", +- "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", ++ "version": "5.0.6", ++ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", ++ "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { +-- +2.54.0 + diff --git a/0002-Issue-7096-During-replication-online-total-init-the-.patch b/0002-Issue-7096-During-replication-online-total-init-the-.patch deleted file mode 100644 index 4d86c59..0000000 --- a/0002-Issue-7096-During-replication-online-total-init-the-.patch +++ /dev/null @@ -1,318 +0,0 @@ -From 67118939bd2b51e53f7284c2058a43744d1dba76 Mon Sep 17 00:00:00 2001 -From: tbordaz -Date: Wed, 7 Jan 2026 11:21:12 +0100 -Subject: [PATCH] Issue 7096 - During replication online total init the - function idl_id_is_in_idlist is not scaling with large database (#7145) - -Bug description: - During a online total initialization, the supplier sorts - the candidate list of entries so that the parents are sent before - children entries. - With large DB the ID array used for the sorting is not - scaling. It takes so long to build the candidate list that - the connection gets closed - -Fix description: - Instead of using an ID array, uses a list of ID ranges - -fixes: #7096 - -Reviewed by: Mark Reynolds, Pierre Rogier (Thanks !!) ---- - ldap/servers/slapd/back-ldbm/back-ldbm.h | 12 ++ - ldap/servers/slapd/back-ldbm/idl_common.c | 163 ++++++++++++++++++ - ldap/servers/slapd/back-ldbm/idl_new.c | 30 ++-- - .../servers/slapd/back-ldbm/proto-back-ldbm.h | 3 + - 4 files changed, 189 insertions(+), 19 deletions(-) - -diff --git a/ldap/servers/slapd/back-ldbm/back-ldbm.h b/ldap/servers/slapd/back-ldbm/back-ldbm.h -index 36aa432e0..5e4988782 100644 ---- a/ldap/servers/slapd/back-ldbm/back-ldbm.h -+++ b/ldap/servers/slapd/back-ldbm/back-ldbm.h -@@ -281,6 +281,18 @@ typedef struct _idlist_set - #define INDIRECT_BLOCK(idl) ((idl)->b_nids == INDBLOCK) - #define IDL_NIDS(idl) (idl ? (idl)->b_nids : (NIDS)0) - -+/* -+ * used by the supplier during online total init -+ * it stores the ranges of ID that are already present -+ * in the candidate list ('parentid>=1') -+ */ -+typedef struct IdRange { -+ ID first; -+ ID last; -+ struct IdRange *next; -+} IdRange_t; -+ -+ - typedef size_t idl_iterator; - - /* small hashtable implementation used in the entry cache -- the table -diff --git a/ldap/servers/slapd/back-ldbm/idl_common.c b/ldap/servers/slapd/back-ldbm/idl_common.c -index fcb0ece4b..fdc9b4e67 100644 ---- a/ldap/servers/slapd/back-ldbm/idl_common.c -+++ b/ldap/servers/slapd/back-ldbm/idl_common.c -@@ -172,6 +172,169 @@ idl_min(IDList *a, IDList *b) - return (a->b_nids > b->b_nids ? b : a); - } - -+/* -+ * This is a faster version of idl_id_is_in_idlist. -+ * idl_id_is_in_idlist uses an array of ID so lookup is expensive -+ * idl_id_is_in_idlist_ranges uses a list of ranges of ID lookup is faster -+ * returns -+ * 1: 'id' is present in idrange_list -+ * 0: 'id' is not present in idrange_list -+ */ -+int -+idl_id_is_in_idlist_ranges(IDList *idl, IdRange_t *idrange_list, ID id) -+{ -+ IdRange_t *range = idrange_list; -+ int found = 0; -+ -+ if (NULL == idl || NOID == id) { -+ return 0; /* not in the list */ -+ } -+ if (ALLIDS(idl)) { -+ return 1; /* in the list */ -+ } -+ -+ for(;range; range = range->next) { -+ if (id > range->last) { -+ /* check if it belongs to the next range */ -+ continue; -+ } -+ if (id >= range->first) { -+ /* It belongs to that range [first..last ] */ -+ found = 1; -+ break; -+ } else { -+ /* this range is after id */ -+ break; -+ } -+ } -+ return found; -+} -+ -+/* This function is used during the online total initialisation -+ * (see next function) -+ * It frees all ranges of ID in the list -+ */ -+void idrange_free(IdRange_t **head) -+{ -+ IdRange_t *curr, *sav; -+ -+ if ((head == NULL) || (*head == NULL)) { -+ return; -+ } -+ curr = *head; -+ sav = NULL; -+ for (; curr;) { -+ sav = curr; -+ curr = curr->next; -+ slapi_ch_free((void *) &sav); -+ } -+ if (sav) { -+ slapi_ch_free((void *) &sav); -+ } -+ *head = NULL; -+} -+ -+/* This function is used during the online total initialisation -+ * Because a MODRDN can move entries under a parent that -+ * has a higher ID we need to sort the IDList so that parents -+ * are sent, to the consumer, before the children are sent. -+ * The sorting with a simple IDlist does not scale instead -+ * a list of IDs ranges is much faster. -+ * In that list we only ADD/lookup ID. -+ */ -+IdRange_t *idrange_add_id(IdRange_t **head, ID id) -+{ -+ if (head == NULL) { -+ slapi_log_err(SLAPI_LOG_ERR, "idrange_add_id", -+ "Can not add ID %d in non defined list\n", id); -+ return NULL; -+ } -+ -+ if (*head == NULL) { -+ /* This is the first range */ -+ IdRange_t *new_range = (IdRange_t *)slapi_ch_malloc(sizeof(IdRange_t)); -+ new_range->first = id; -+ new_range->last = id; -+ new_range->next = NULL; -+ *head = new_range; -+ return *head; -+ } -+ -+ IdRange_t *curr = *head, *prev = NULL; -+ -+ /* First, find if id already falls within any existing range, or it is adjacent to any */ -+ while (curr) { -+ if (id >= curr->first && id <= curr->last) { -+ /* inside a range, nothing to do */ -+ return curr; -+ } -+ -+ if (id == curr->last + 1) { -+ /* Extend this range upwards */ -+ curr->last = id; -+ -+ /* Check for possible merge with next range */ -+ IdRange_t *next = curr->next; -+ if (next && curr->last + 1 >= next->first) { -+ slapi_log_err(SLAPI_LOG_REPL, "idrange_add_id", -+ "(id=%d) merge current with next range [%d..%d]\n", id, curr->first, curr->last); -+ curr->last = (next->last > curr->last) ? next->last : curr->last; -+ curr->next = next->next; -+ slapi_ch_free((void*) &next); -+ } else { -+ slapi_log_err(SLAPI_LOG_REPL, "idrange_add_id", -+ "(id=%d) extend forward current range [%d..%d]\n", id, curr->first, curr->last); -+ } -+ return curr; -+ } -+ -+ if (id + 1 == curr->first) { -+ /* Extend this range downwards */ -+ curr->first = id; -+ -+ /* Check for possible merge with previous range */ -+ if (prev && prev->last + 1 >= curr->first) { -+ prev->last = curr->last; -+ prev->next = curr->next; -+ slapi_ch_free((void *) &curr); -+ slapi_log_err(SLAPI_LOG_REPL, "idrange_add_id", -+ "(id=%d) merge current with previous range [%d..%d]\n", id, prev->first, prev->last); -+ return prev; -+ } else { -+ slapi_log_err(SLAPI_LOG_REPL, "idrange_add_id", -+ "(id=%d) extend backward current range [%d..%d]\n", id, curr->first, curr->last); -+ return curr; -+ } -+ } -+ -+ /* If id is before the current range, break so we can insert before */ -+ if (id < curr->first) { -+ break; -+ } -+ -+ prev = curr; -+ curr = curr->next; -+ } -+ /* Need to insert a new standalone IdRange */ -+ IdRange_t *new_range = (IdRange_t *)slapi_ch_malloc(sizeof(IdRange_t)); -+ new_range->first = id; -+ new_range->last = id; -+ new_range->next = curr; -+ -+ if (prev) { -+ slapi_log_err(SLAPI_LOG_REPL, "idrange_add_id", -+ "(id=%d) add new range [%d..%d]\n", id, new_range->first, new_range->last); -+ prev->next = new_range; -+ } else { -+ /* Insert at head */ -+ slapi_log_err(SLAPI_LOG_REPL, "idrange_add_id", -+ "(id=%d) head range [%d..%d]\n", id, new_range->first, new_range->last); -+ *head = new_range; -+ } -+ return *head; -+} -+ -+ - int - idl_id_is_in_idlist(IDList *idl, ID id) - { -diff --git a/ldap/servers/slapd/back-ldbm/idl_new.c b/ldap/servers/slapd/back-ldbm/idl_new.c -index 5fbcaff2e..2d978353f 100644 ---- a/ldap/servers/slapd/back-ldbm/idl_new.c -+++ b/ldap/servers/slapd/back-ldbm/idl_new.c -@@ -417,7 +417,6 @@ idl_new_range_fetch( - { - int ret = 0; - int ret2 = 0; -- int idl_rc = 0; - dbi_cursor_t cursor = {0}; - IDList *idl = NULL; - dbi_val_t cur_key = {0}; -@@ -436,6 +435,7 @@ idl_new_range_fetch( - size_t leftoverlen = 32; - size_t leftovercnt = 0; - char *index_id = get_index_name(be, db, ai); -+ IdRange_t *idrange_list = NULL; - - - if (NULL == flag_err) { -@@ -578,10 +578,12 @@ idl_new_range_fetch( - * found entry is the one from the suffix - */ - suffix = key; -- idl_rc = idl_append_extend(&idl, id); -- } else if ((key == suffix) || idl_id_is_in_idlist(idl, key)) { -+ idl_append_extend(&idl, id); -+ idrange_add_id(&idrange_list, id); -+ } else if ((key == suffix) || idl_id_is_in_idlist_ranges(idl, idrange_list, key)) { - /* the parent is the suffix or already in idl. */ -- idl_rc = idl_append_extend(&idl, id); -+ idl_append_extend(&idl, id); -+ idrange_add_id(&idrange_list, id); - } else { - /* Otherwise, keep the {key,id} in leftover array */ - if (!leftover) { -@@ -596,13 +598,7 @@ idl_new_range_fetch( - leftovercnt++; - } - } else { -- idl_rc = idl_append_extend(&idl, id); -- } -- if (idl_rc) { -- slapi_log_err(SLAPI_LOG_ERR, "idl_new_range_fetch", -- "Unable to extend id list (err=%d)\n", idl_rc); -- idl_free(&idl); -- goto error; -+ idl_append_extend(&idl, id); - } - - count++; -@@ -695,21 +691,17 @@ error: - - while(remaining > 0) { - for (size_t i = 0; i < leftovercnt; i++) { -- if (leftover[i].key > 0 && idl_id_is_in_idlist(idl, leftover[i].key) != 0) { -+ if (leftover[i].key > 0 && idl_id_is_in_idlist_ranges(idl, idrange_list, leftover[i].key) != 0) { - /* if the leftover key has its parent in the idl */ -- idl_rc = idl_append_extend(&idl, leftover[i].id); -- if (idl_rc) { -- slapi_log_err(SLAPI_LOG_ERR, "idl_new_range_fetch", -- "Unable to extend id list (err=%d)\n", idl_rc); -- idl_free(&idl); -- return NULL; -- } -+ idl_append_extend(&idl, leftover[i].id); -+ idrange_add_id(&idrange_list, leftover[i].id); - leftover[i].key = 0; - remaining--; - } - } - } - slapi_ch_free((void **)&leftover); -+ idrange_free(&idrange_list); - } - slapi_log_err(SLAPI_LOG_FILTER, "idl_new_range_fetch", - "Found %d candidates; error code is: %d\n", -diff --git a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h -index 9a7ffee37..f16c37d73 100644 ---- a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h -+++ b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h -@@ -217,6 +217,9 @@ ID idl_firstid(IDList *idl); - ID idl_nextid(IDList *idl, ID id); - int idl_init_private(backend *be, struct attrinfo *a); - int idl_release_private(struct attrinfo *a); -+IdRange_t *idrange_add_id(IdRange_t **head, ID id); -+void idrange_free(IdRange_t **head); -+int idl_id_is_in_idlist_ranges(IDList *idl, IdRange_t *idrange_list, ID id); - int idl_id_is_in_idlist(IDList *idl, ID id); - - idl_iterator idl_iterator_init(const IDList *idl); --- -2.52.0 - diff --git a/0003-Issue-6922-AddressSanitizer-leaks-found-by-acl-test-.patch b/0003-Issue-6922-AddressSanitizer-leaks-found-by-acl-test-.patch new file mode 100644 index 0000000..24397d2 --- /dev/null +++ b/0003-Issue-6922-AddressSanitizer-leaks-found-by-acl-test-.patch @@ -0,0 +1,687 @@ +From 46808f90d9026454b77a65bbab7fccdde75253a4 Mon Sep 17 00:00:00 2001 +From: Viktor Ashirov +Date: Fri, 11 Jul 2025 11:43:28 +0200 +Subject: [PATCH 3/8] Issue 6922 - AddressSanitizer: leaks found by acl test + suite + +Description: +Fix multiple memory leaks in ACL plugin: + +* aclgroup.c: Fix memory leak in `aclgroup_free()` by properly cleaning + up all user groups before destroying the rwlock and freeing the main + structure +* aclscan.l & acltext.y: use `PERM_FREE` macro instead of `free()` +* Add cleanups in aclparse.c, aclinit.c, acllist.c, acllas.c + +Fixes: https://github.com/389ds/389-ds-base/issues/6922 + +Reviewed by: @progier389 (Thanks!) +--- + ldap/servers/plugins/acl/aclgroup.c | 16 ++++- + ldap/servers/plugins/acl/aclinit.c | 4 ++ + ldap/servers/plugins/acl/acllas.c | 7 ++ + ldap/servers/plugins/acl/acllist.c | 2 + + ldap/servers/plugins/acl/aclparse.c | 7 ++ + lib/libaccess/aclscan.l | 104 ++++++++++++++++++++++++++-- + lib/libaccess/acltext.y | 54 +++++++-------- + 7 files changed, 160 insertions(+), 34 deletions(-) + +diff --git a/ldap/servers/plugins/acl/aclgroup.c b/ldap/servers/plugins/acl/aclgroup.c +index a5b0426f9..43faeae58 100644 +--- a/ldap/servers/plugins/acl/aclgroup.c ++++ b/ldap/servers/plugins/acl/aclgroup.c +@@ -50,8 +50,20 @@ aclgroup_init() + void + aclgroup_free() + { +- slapi_destroy_rwlock(aclUserGroups->aclg_rwlock); +- slapi_ch_free((void **)&aclUserGroups); ++ aclUserGroup *u_group, *next_group; ++ ++ if (aclUserGroups) { ++ /* Clean up all user groups */ ++ u_group = aclUserGroups->aclg_first; ++ while (u_group) { ++ next_group = u_group->aclug_next; ++ __aclg__delete_userGroup(u_group); ++ u_group = next_group; ++ } ++ ++ slapi_destroy_rwlock(aclUserGroups->aclg_rwlock); ++ slapi_ch_free((void **)&aclUserGroups); ++ } + } + + /* +diff --git a/ldap/servers/plugins/acl/aclinit.c b/ldap/servers/plugins/acl/aclinit.c +index e2d5eba95..925fbbe53 100644 +--- a/ldap/servers/plugins/acl/aclinit.c ++++ b/ldap/servers/plugins/acl/aclinit.c +@@ -409,6 +409,7 @@ __aclinit__RegisterAttributes(void) + rv = ACL_MethodRegister(&errp, DS_METHOD, &methodinfo); + if (rv < 0) { + acl_print_acllib_err(&errp, NULL); ++ nserrDispose(&errp); + slapi_log_err(SLAPI_LOG_ERR, plugin_name, + "__aclinit__RegisterAttributes - Unable to Register the methods\n"); + return ACL_ERR; +@@ -416,6 +417,7 @@ __aclinit__RegisterAttributes(void) + rv = ACL_MethodSetDefault(&errp, methodinfo); + if (rv < 0) { + acl_print_acllib_err(&errp, NULL); ++ nserrDispose(&errp); + slapi_log_err(SLAPI_LOG_ERR, plugin_name, + "__aclinit__RegisterAttributes - Unable to Set the default method\n"); + return ACL_ERR; +@@ -424,6 +426,7 @@ __aclinit__RegisterAttributes(void) + methodinfo, ACL_DBTYPE_ANY, ACL_AT_FRONT, NULL); + if (rv < 0) { + acl_print_acllib_err(&errp, NULL); ++ nserrDispose(&errp); + slapi_log_err(SLAPI_LOG_ERR, plugin_name, + "__aclinit__RegisterAttributes - Unable to Register Attr ip\n"); + return ACL_ERR; +@@ -432,6 +435,7 @@ __aclinit__RegisterAttributes(void) + methodinfo, ACL_DBTYPE_ANY, ACL_AT_FRONT, NULL); + if (rv < 0) { + acl_print_acllib_err(&errp, NULL); ++ nserrDispose(&errp); + slapi_log_err(SLAPI_LOG_ERR, plugin_name, + "__aclinit__RegisterAttributes - Unable to Register Attr dns\n"); + return ACL_ERR; +diff --git a/ldap/servers/plugins/acl/acllas.c b/ldap/servers/plugins/acl/acllas.c +index 792216cca..282359ae1 100644 +--- a/ldap/servers/plugins/acl/acllas.c ++++ b/ldap/servers/plugins/acl/acllas.c +@@ -258,6 +258,7 @@ DS_LASIpGetter(NSErr_t *errp, PList_t subject, PList_t resource, PList_t auth_in + rv = ACL_GetAttribute(errp, DS_PROP_ACLPB, (void **)&aclpb, subject, resource, auth_info, global_auth); + if (rv != LAS_EVAL_TRUE || (NULL == aclpb)) { + acl_print_acllib_err(errp, NULL); ++ nserrDispose(errp); + slapi_log_err(SLAPI_LOG_ACL, plugin_name, + "DS_LASIpGetter: Unable to get the ACLPB(%d)\n", rv); + return LAS_EVAL_FAIL; +@@ -334,6 +335,7 @@ DS_LASDnsGetter(NSErr_t *errp, PList_t subject, PList_t resource, PList_t auth_i + subject, resource, auth_info, global_auth); + if (rv != LAS_EVAL_TRUE || (NULL == aclpb)) { + acl_print_acllib_err(errp, NULL); ++ nserrDispose(errp); + slapi_log_err(SLAPI_LOG_ACL, plugin_name, + "DS_LASDnsGetter - Unable to get the ACLPB(%d)\n", rv); + return LAS_EVAL_FAIL; +@@ -3743,6 +3745,7 @@ __acllas_setup(NSErr_t *errp, char *attr_name, CmpOp_t comparator, int allow_ran + + if (rc != LAS_EVAL_TRUE) { + acl_print_acllib_err(errp, NULL); ++ nserrDispose(errp); + slapi_log_err(SLAPI_LOG_ACL, plugin_name, + "__acllas_setup - %s:Unable to get the clientdn attribute(%d)\n", lasName, rc); + return LAS_EVAL_FAIL; +@@ -3762,6 +3765,7 @@ __acllas_setup(NSErr_t *errp, char *attr_name, CmpOp_t comparator, int allow_ran + if ((rc = PListFindValue(subject, DS_ATTR_ENTRY, + (void **)&linfo->resourceEntry, NULL)) < 0) { + acl_print_acllib_err(errp, NULL); ++ nserrDispose(errp); + slapi_log_err(SLAPI_LOG_ACL, plugin_name, + "__acllas_setup - %s:Unable to get the Slapi_Entry attr(%d)\n", lasName, rc); + return LAS_EVAL_FAIL; +@@ -3772,6 +3776,7 @@ __acllas_setup(NSErr_t *errp, char *attr_name, CmpOp_t comparator, int allow_ran + subject, resource, auth_info, global_auth); + if (rc != LAS_EVAL_TRUE) { + acl_print_acllib_err(errp, NULL); ++ nserrDispose(errp); + slapi_log_err(SLAPI_LOG_ACL, plugin_name, + "__acllas_setup - %s:Unable to get the ACLPB(%d)\n", lasName, rc); + return LAS_EVAL_FAIL; +@@ -3795,6 +3800,7 @@ __acllas_setup(NSErr_t *errp, char *attr_name, CmpOp_t comparator, int allow_ran + if ((rc = PListFindValue(subject, DS_ATTR_AUTHTYPE, + (void **)&linfo->authType, NULL)) < 0) { + acl_print_acllib_err(errp, NULL); ++ nserrDispose(errp); + slapi_log_err(SLAPI_LOG_ACL, plugin_name, + "__acllas_setup - %s:Unable to get the auth type(%d)\n", lasName, rc); + return LAS_EVAL_FAIL; +@@ -3804,6 +3810,7 @@ __acllas_setup(NSErr_t *errp, char *attr_name, CmpOp_t comparator, int allow_ran + if ((rc = PListFindValue(subject, DS_ATTR_SSF, + (void **)&linfo->ssf, NULL)) < 0) { + acl_print_acllib_err(errp, NULL); ++ nserrDispose(errp); + slapi_log_err(SLAPI_LOG_ACL, plugin_name, + "__acllas_setup - %s:Unable to get the ssf(%d)\n", lasName, rc); + } +diff --git a/ldap/servers/plugins/acl/acllist.c b/ldap/servers/plugins/acl/acllist.c +index bf1168691..6d80a5835 100644 +--- a/ldap/servers/plugins/acl/acllist.c ++++ b/ldap/servers/plugins/acl/acllist.c +@@ -526,6 +526,8 @@ acllist_free_aci(aci_t *item) + + slapi_sdn_free(&item->aci_sdn); + slapi_filter_free(item->target, 1); ++ slapi_filter_free(item->target_to, 1); ++ slapi_filter_free(item->target_from, 1); + + /* slapi_filter_free(item->targetAttr, 1); */ + attrArray = item->targetAttr; +diff --git a/ldap/servers/plugins/acl/aclparse.c b/ldap/servers/plugins/acl/aclparse.c +index 261cb69ec..882f4ef28 100644 +--- a/ldap/servers/plugins/acl/aclparse.c ++++ b/ldap/servers/plugins/acl/aclparse.c +@@ -423,6 +423,9 @@ __aclp__parse_aci(char *str, aci_t *aci_item, char **errbuf) + } + f = slapi_str2filter(tstr); + slapi_ch_free_string(&tstr); ++ if (rv > 0) { ++ slapi_ch_free_string(&tmpstr); ++ } + } else if (strncmp(str, aci_targetdn, targetdnlen) == 0) { + char *tstr = NULL; + size_t LDAP_URL_prefix_len = 0; +@@ -706,6 +709,7 @@ __aclp__sanity_check_acltxt(aci_t *aci_item, char *str) + /* check for acl syntax error */ + if ((handle = (ACLListHandle_t *)ACL_ParseString(&errp, newstr)) == NULL) { + acl_print_acllib_err(&errp, str); ++ nserrDispose(&errp); + slapi_ch_free_string(&newstr); + return ACL_SYNTAX_ERR; + } else { +@@ -1144,13 +1148,16 @@ normalize_nextACERule: + if (nextACE && *nextACE != '\0') + aclutil_str_append(&ret_str, nextACE); + slapi_ch_free_string(&s_aclstr); ++ slapi_ch_free_string(&s_acestr); + return (ret_str); + } + acestr = nextACE; ++ slapi_ch_free_string(&s_acestr); + goto normalize_nextACERule; + } + + slapi_ch_free_string(&s_aclstr); ++ slapi_ch_free_string(&s_acestr); + return (ret_str); + + error: +diff --git a/lib/libaccess/aclscan.l b/lib/libaccess/aclscan.l +index 7067096c0..9c836decc 100644 +--- a/lib/libaccess/aclscan.l ++++ b/lib/libaccess/aclscan.l +@@ -64,11 +64,18 @@ variable [\*a-zA-Z0-9\.\-\_][\*a-zA-Z0-9\.\-\_]* + + <> { + yylval.string = NULL; +- last_string = yylval.string; ++ if (last_string) { ++ PERM_FREE(last_string); ++ last_string = NULL; ++ } + return(0); + } + + {qstring} { ++ if (last_string) { ++ PERM_FREE(last_string); ++ last_string = NULL; ++ } + yylval.string = PERM_STRDUP( yytext+1 ); + last_string = yylval.string; + if ( yylval.string[yyleng-2] != '"' ) +@@ -81,96 +88,144 @@ variable [\*a-zA-Z0-9\.\-\_][\*a-zA-Z0-9\.\-\_]* + + + absolute { ++ if (last_string) { ++ PERM_FREE(last_string); ++ } + last_string = NULL; + acl_tokenpos += yyleng; + return ACL_ABSOLUTE_TOK; + } + + acl { ++ if (last_string) { ++ PERM_FREE(last_string); ++ } + last_string = NULL; + acl_tokenpos += yyleng; + return ACL_ACL_TOK; + } + + allow { ++ if (last_string) { ++ PERM_FREE(last_string); ++ } + last_string = NULL; + acl_tokenpos += yyleng; + return ACL_ALLOW_TOK; + } + + always { ++ if (last_string) { ++ PERM_FREE(last_string); ++ } + last_string = NULL; + acl_tokenpos += yyleng; + return ACL_ALWAYS_TOK; + } + + at { ++ if (last_string) { ++ PERM_FREE(last_string); ++ } + last_string = NULL; + acl_tokenpos += yyleng; + return ACL_AT_TOK; + } + + authenticate { ++ if (last_string) { ++ PERM_FREE(last_string); ++ } + last_string = NULL; + acl_tokenpos += yyleng; + return ACL_AUTHENTICATE_TOK; + } + + content { ++ if (last_string) { ++ PERM_FREE(last_string); ++ } + last_string = NULL; + acl_tokenpos += yyleng; + return ACL_CONTENT_TOK; + } + + default { ++ if (last_string) { ++ PERM_FREE(last_string); ++ } + last_string = NULL; + acl_tokenpos += yyleng; + return ACL_DEFAULT_TOK; + } + + deny { ++ if (last_string) { ++ PERM_FREE(last_string); ++ } + last_string = NULL; + acl_tokenpos += yyleng; + return ACL_DENY_TOK; + } + + in { ++ if (last_string) { ++ PERM_FREE(last_string); ++ } + last_string = NULL; + acl_tokenpos += yyleng; + return ACL_IN_TOK; + } + + inherit { ++ if (last_string) { ++ PERM_FREE(last_string); ++ } + last_string = NULL; + acl_tokenpos += yyleng; + return ACL_INHERIT_TOK; + } + + terminal { ++ if (last_string) { ++ PERM_FREE(last_string); ++ } + last_string = NULL; + acl_tokenpos += yyleng; + return ACL_TERMINAL_TOK; + } + + version { ++ if (last_string) { ++ PERM_FREE(last_string); ++ } + last_string = NULL; + acl_tokenpos += yyleng; + return ACL_VERSION_TOK; + } + + with { ++ if (last_string) { ++ PERM_FREE(last_string); ++ } + last_string = NULL; + acl_tokenpos += yyleng; + return ACL_WITH_TOK; + } + + not { ++ if (last_string) { ++ PERM_FREE(last_string); ++ } + last_string = NULL; + acl_tokenpos += yyleng; + return ACL_NOT_TOK; + } + + and { ++ if (last_string) { ++ PERM_FREE(last_string); ++ } + last_string = NULL; + yylval.ival = ACL_EXPR_OP_AND; + acl_tokenpos += yyleng; +@@ -178,6 +233,9 @@ and { + } + + or { ++ if (last_string) { ++ PERM_FREE(last_string); ++ } + last_string = NULL; + yylval.ival = ACL_EXPR_OP_OR; + acl_tokenpos += yyleng; +@@ -185,6 +243,9 @@ or { + } + + "=" { ++ if (last_string) { ++ PERM_FREE(last_string); ++ } + last_string = NULL; + yylval.ival = CMP_OP_EQ; + acl_tokenpos += yyleng; +@@ -192,6 +253,9 @@ or { + } + + ">=" { ++ if (last_string) { ++ PERM_FREE(last_string); ++ } + last_string = NULL; + yylval.ival = CMP_OP_GE; + acl_tokenpos += yyleng; +@@ -199,6 +263,9 @@ or { + } + + ">" { ++ if (last_string) { ++ PERM_FREE(last_string); ++ } + last_string = NULL; + yylval.ival = CMP_OP_GT; + acl_tokenpos += yyleng; +@@ -206,6 +273,9 @@ or { + } + + "<" { ++ if (last_string) { ++ PERM_FREE(last_string); ++ } + last_string = NULL; + yylval.ival = CMP_OP_LT; + acl_tokenpos += yyleng; +@@ -213,6 +283,9 @@ or { + } + + "<=" { ++ if (last_string) { ++ PERM_FREE(last_string); ++ } + last_string = NULL; + yylval.ival = CMP_OP_LE; + acl_tokenpos += yyleng; +@@ -220,6 +293,9 @@ or { + } + + "!=" { ++ if (last_string) { ++ PERM_FREE(last_string); ++ } + last_string = NULL; + yylval.ival = CMP_OP_NE; + acl_tokenpos += yyleng; +@@ -227,6 +303,9 @@ or { + } + + [(){},;] { ++ if (last_string) { ++ PERM_FREE(last_string); ++ } + last_string = NULL; + acl_tokenpos += yyleng; + return yytext[0]; +@@ -234,6 +313,10 @@ or { + + {variable} { + acl_tokenpos += yyleng; ++ if (last_string) { ++ PERM_FREE(last_string); ++ last_string = NULL; ++ } + yylval.string = PERM_STRDUP( yytext ); + last_string = yylval.string; + return ACL_VARIABLE_TOK; +@@ -272,8 +355,10 @@ char errorStr[256]; + #if defined(UTEST) || defined(ACL_COMPILER) + printf("ACL file: %s\n", acl_filename); + printf("Syntax error at line: %d, token: %s\n", acl_lineno, yytext); +- if ( last_string ) +- free(last_string); ++ if ( last_string ) { ++ PERM_FREE(last_string); ++ last_string = NULL; ++ } + #else + sprintf(errorStr, "%d", acl_lineno); + if (yytext) { +@@ -283,8 +368,10 @@ char errorStr[256]; + nserrGenerate(acl_errp, ACLERRPARSE, ACLERR1780, ACL_Program, + 2, acl_filename, errorStr); + } +- if ( last_string ) +- free(last_string); ++ if ( last_string ) { ++ PERM_FREE(last_string); ++ last_string = NULL; ++ } + #endif + + } +@@ -294,6 +381,7 @@ acl_InitScanner(NSErr_t *errp, char *filename, char *buffer) + { + acl_errp = errp; + acl_lineno = 1; ++ last_string = NULL; + acl_use_buffer = (filename == NULL) ? 1 : 0 ; + if ( filename != NULL ) { + PL_strncpyz(acl_filename, filename, sizeof(acl_filename)); +@@ -342,6 +430,12 @@ acl_EndScanner() + #endif + yyin = NULL ; + } ++ ++ if ( last_string ) { ++ PERM_FREE(last_string); ++ last_string = NULL; ++ } ++ + return(0); + } + +diff --git a/lib/libaccess/acltext.y b/lib/libaccess/acltext.y +index 16eea355b..ed2c6109b 100644 +--- a/lib/libaccess/acltext.y ++++ b/lib/libaccess/acltext.y +@@ -80,7 +80,7 @@ acl_free_args(char **args_list) + + for (ii = 0; ii < MAX_LIST_SIZE; ii++) { + if ( args_list[ii] ) +- free(args_list[ii]); ++ PERM_FREE(args_list[ii]); + else + break; + } +@@ -240,7 +240,7 @@ acl_set_ip_dns(ACLExprHandle_t *expr, char **ip_dns) + start: | start_acl_v2 + | ACL_VERSION_TOK ACL_VARIABLE_TOK + { +- free($2); ++ PERM_FREE($2); + } + ';' start_acl_v3 + ; +@@ -267,7 +267,7 @@ acl_v2: ACL_ACL_TOK acl_name_v2 + acl_name_v2: ACL_VARIABLE_TOK + { + curr_acl = ACL_AclNew(NULL, $1); +- free($1); ++ PERM_FREE($1); + if ( ACL_ListAppend(NULL, curr_acl_list, curr_acl, 0) < 0 ) { + yyerror("Couldn't add ACL to list."); + return(-1); +@@ -289,7 +289,7 @@ acl_name_v2: ACL_VARIABLE_TOK + | ACL_QSTRING_TOK + { + curr_acl = ACL_AclNew(NULL, $1); +- free($1); ++ PERM_FREE($1); + if ( ACL_ListAppend(NULL, curr_acl_list, curr_acl, 0) < 0 ) { + yyerror("Couldn't add ACL to list."); + return(-1); +@@ -503,8 +503,8 @@ ip_spec_v2: ACL_VARIABLE_TOK ACL_VARIABLE_TOK + char tmp_str[255]; + + util_sprintf(tmp_str, "%s+%s", $1, $2); +- free($1); +- free($2); ++ PERM_FREE($1); ++ PERM_FREE($2); + acl_add_arg(curr_ip_dns_list, PERM_STRDUP(tmp_str)); + } + ; +@@ -538,26 +538,26 @@ method_v2: ACL_VARIABLE_TOK ACL_VARIABLE_TOK ';' + { + acl_string_lower($1); + if (strcmp($1, "database") == 0) { +- free($1); +- free($2); ++ PERM_FREE($1); ++ PERM_FREE($2); + } else { + if ( PListInitProp(curr_auth_info, + ACL_Attr2Index($1), $1, $2, NULL) < 0 ) { + } +- free($1); ++ PERM_FREE($1); + } + } + | ACL_VARIABLE_TOK ACL_QSTRING_TOK ';' + { + acl_string_lower($1); + if (strcmp($1, "database") == 0) { +- free($1); +- free($2); ++ PERM_FREE($1); ++ PERM_FREE($2); + } else { + if ( PListInitProp(curr_auth_info, + ACL_Attr2Index($1), $1, $2, NULL) < 0 ) { + } +- free($1); ++ PERM_FREE($1); + } + } + ; +@@ -586,7 +586,7 @@ acl: named_acl ';' body_list + named_acl: ACL_ACL_TOK ACL_VARIABLE_TOK + { + curr_acl = ACL_AclNew(NULL, $2); +- free($2); ++ PERM_FREE($2); + if ( ACL_ListAppend(NULL, curr_acl_list, curr_acl, 0) < 0 ) { + yyerror("Couldn't add ACL to list."); + return(-1); +@@ -595,7 +595,7 @@ named_acl: ACL_ACL_TOK ACL_VARIABLE_TOK + | ACL_ACL_TOK ACL_QSTRING_TOK + { + curr_acl = ACL_AclNew(NULL, $2); +- free($2); ++ PERM_FREE($2); + if ( ACL_ListAppend(NULL, curr_acl_list, curr_acl, 0) < 0 ) { + yyerror("Couldn't add ACL to list."); + return(-1); +@@ -654,8 +654,8 @@ deny_common: ACL_VARIABLE_TOK ACL_EQ_TOK ACL_QSTRING_TOK + yyerror("ACL_ExprSetDenyWith() failed"); + return(-1); + } +- free($1); +- free($3); ++ PERM_FREE($1); ++ PERM_FREE($3); + } + ; + +@@ -692,7 +692,7 @@ attribute: ACL_VARIABLE_TOK + yyerror("ACL_ExprAddArg() failed"); + return(-1); + } +- free($1); ++ PERM_FREE($1); + } + ; + +@@ -706,7 +706,7 @@ parameter: ACL_VARIABLE_TOK ACL_EQ_TOK ACL_QSTRING_TOK + if ( PListInitProp(curr_auth_info, + ACL_Attr2Index($1), $1, $3, NULL) < 0 ) { + } +- free($1); ++ PERM_FREE($1); + } + | ACL_VARIABLE_TOK ACL_EQ_TOK ACL_VARIABLE_TOK + { +@@ -714,7 +714,7 @@ parameter: ACL_VARIABLE_TOK ACL_EQ_TOK ACL_QSTRING_TOK + if ( PListInitProp(curr_auth_info, + ACL_Attr2Index($1), $1, $3, NULL) < 0 ) { + } +- free($1); ++ PERM_FREE($1); + } + ; + +@@ -896,12 +896,12 @@ base_expr: ACL_VARIABLE_TOK relop ACL_QSTRING_TOK + if ( ACL_ExprTerm(NULL, curr_expr, + $1, (CmpOp_t) $2, $3) < 0 ) { + yyerror("ACL_ExprTerm() failed"); +- free($1); +- free($3); ++ PERM_FREE($1); ++ PERM_FREE($3); + return(-1); + } +- free($1); +- free($3); ++ PERM_FREE($1); ++ PERM_FREE($3); + } + | ACL_VARIABLE_TOK relop ACL_VARIABLE_TOK + { +@@ -909,12 +909,12 @@ base_expr: ACL_VARIABLE_TOK relop ACL_QSTRING_TOK + if ( ACL_ExprTerm(NULL, curr_expr, + $1, (CmpOp_t) $2, $3) < 0 ) { + yyerror("ACL_ExprTerm() failed"); +- free($1); +- free($3); ++ PERM_FREE($1); ++ PERM_FREE($3); + return(-1); + } +- free($1); +- free($3); ++ PERM_FREE($1); ++ PERM_FREE($3); + } + ; + +-- +2.54.0 + diff --git a/0003-Issue-Revise-paged-result-search-locking.patch b/0003-Issue-Revise-paged-result-search-locking.patch deleted file mode 100644 index 3e0fcc8..0000000 --- a/0003-Issue-Revise-paged-result-search-locking.patch +++ /dev/null @@ -1,765 +0,0 @@ -From a0af5ab79ddad7944687e31f16bb2a667c800958 Mon Sep 17 00:00:00 2001 -From: Mark Reynolds -Date: Wed, 7 Jan 2026 16:55:27 -0500 -Subject: [PATCH] Issue - Revise paged result search locking - -Description: - -Move to a single lock approach verses having two locks. This will impact -concurrency when multiple async paged result searches are done on the same -connection, but it simplifies the code and avoids race conditions and -deadlocks. - -Relates: https://github.com/389ds/389-ds-base/issues/7118 - -Reviewed by: progier & tbordaz (Thanks!!) ---- - ldap/servers/slapd/abandon.c | 2 +- - ldap/servers/slapd/opshared.c | 60 ++++---- - ldap/servers/slapd/pagedresults.c | 228 +++++++++++++++++++----------- - ldap/servers/slapd/proto-slap.h | 26 ++-- - ldap/servers/slapd/slap.h | 5 +- - 5 files changed, 187 insertions(+), 134 deletions(-) - -diff --git a/ldap/servers/slapd/abandon.c b/ldap/servers/slapd/abandon.c -index 2dd1ee320..d7c1f8868 100644 ---- a/ldap/servers/slapd/abandon.c -+++ b/ldap/servers/slapd/abandon.c -@@ -141,7 +141,7 @@ do_abandon(Slapi_PBlock *pb) - } - - pthread_mutex_unlock(&(pb_conn->c_mutex)); -- if (0 == pagedresults_free_one_msgid(pb_conn, id, pageresult_lock_get_addr(pb_conn))) { -+ if (0 == pagedresults_free_one_msgid(pb_conn, id, PR_NOT_LOCKED)) { - slapi_log_access(LDAP_DEBUG_STATS, "conn=%" PRIu64 - " op=%d ABANDON targetop=Simple Paged Results msgid=%d\n", - pb_conn->c_connid, pb_op->o_opid, id); -diff --git a/ldap/servers/slapd/opshared.c b/ldap/servers/slapd/opshared.c -index 03ed60981..bb474ef3d 100644 ---- a/ldap/servers/slapd/opshared.c -+++ b/ldap/servers/slapd/opshared.c -@@ -545,8 +545,8 @@ op_shared_search(Slapi_PBlock *pb, int send_result) - be = be_list[index]; - } - } -- pr_search_result = pagedresults_get_search_result(pb_conn, operation, 0 /*not locked*/, pr_idx); -- estimate = pagedresults_get_search_result_set_size_estimate(pb_conn, operation, pr_idx); -+ pr_search_result = pagedresults_get_search_result(pb_conn, operation, PR_NOT_LOCKED, pr_idx); -+ estimate = pagedresults_get_search_result_set_size_estimate(pb_conn, operation, PR_NOT_LOCKED, pr_idx); - /* Set operation note flags as required. */ - if (pagedresults_get_unindexed(pb_conn, operation, pr_idx)) { - slapi_pblock_set_flag_operation_notes(pb, SLAPI_OP_NOTE_UNINDEXED); -@@ -592,14 +592,7 @@ op_shared_search(Slapi_PBlock *pb, int send_result) - int32_t tlimit; - slapi_pblock_get(pb, SLAPI_SEARCH_TIMELIMIT, &tlimit); - pagedresults_set_timelimit(pb_conn, operation, (time_t)tlimit, pr_idx); -- /* When using this mutex in conjunction with the main paged -- * result lock, you must do so in this order: -- * -- * --> pagedresults_lock() -- * --> pagedresults_mutex -- * <-- pagedresults_mutex -- * <-- pagedresults_unlock() -- */ -+ /* IMPORTANT: Never acquire pagedresults_mutex when holding c_mutex. */ - pagedresults_mutex = pageresult_lock_get_addr(pb_conn); - } - -@@ -716,17 +709,15 @@ op_shared_search(Slapi_PBlock *pb, int send_result) - if (op_is_pagedresults(operation) && pr_search_result) { - void *sr = NULL; - /* PAGED RESULTS and already have the search results from the prev op */ -- pagedresults_lock(pb_conn, pr_idx); - /* - * In async paged result case, the search result might be released - * by other theads. We need to double check it in the locked region. - */ - pthread_mutex_lock(pagedresults_mutex); -- pr_search_result = pagedresults_get_search_result(pb_conn, operation, 1 /*locked*/, pr_idx); -+ pr_search_result = pagedresults_get_search_result(pb_conn, operation, PR_LOCKED, pr_idx); - if (pr_search_result) { -- if (pagedresults_is_abandoned_or_notavailable(pb_conn, 1 /*locked*/, pr_idx)) { -+ if (pagedresults_is_abandoned_or_notavailable(pb_conn, PR_LOCKED, pr_idx)) { - pthread_mutex_unlock(pagedresults_mutex); -- pagedresults_unlock(pb_conn, pr_idx); - /* Previous operation was abandoned and the simplepaged object is not in use. */ - send_ldap_result(pb, 0, NULL, "Simple Paged Results Search abandoned", 0, NULL); - rc = LDAP_SUCCESS; -@@ -737,14 +728,13 @@ op_shared_search(Slapi_PBlock *pb, int send_result) - - /* search result could be reset in the backend/dse */ - slapi_pblock_get(pb, SLAPI_SEARCH_RESULT_SET, &sr); -- pagedresults_set_search_result(pb_conn, operation, sr, 1 /*locked*/, pr_idx); -+ pagedresults_set_search_result(pb_conn, operation, sr, PR_LOCKED, pr_idx); - } - } else { - pr_stat = PAGEDRESULTS_SEARCH_END; - rc = LDAP_SUCCESS; - } - pthread_mutex_unlock(pagedresults_mutex); -- pagedresults_unlock(pb_conn, pr_idx); - - if ((PAGEDRESULTS_SEARCH_END == pr_stat) || (0 == pnentries)) { - /* no more entries to send in the backend */ -@@ -762,22 +752,22 @@ op_shared_search(Slapi_PBlock *pb, int send_result) - } - pagedresults_set_response_control(pb, 0, estimate, - curr_search_count, pr_idx); -- if (pagedresults_get_with_sort(pb_conn, operation, pr_idx)) { -+ if (pagedresults_get_with_sort(pb_conn, operation, PR_NOT_LOCKED, pr_idx)) { - sort_make_sort_response_control(pb, CONN_GET_SORT_RESULT_CODE, NULL); - } - pagedresults_set_search_result_set_size_estimate(pb_conn, - operation, -- estimate, pr_idx); -+ estimate, PR_NOT_LOCKED, pr_idx); - if (PAGEDRESULTS_SEARCH_END == pr_stat) { -- pagedresults_lock(pb_conn, pr_idx); -+ pthread_mutex_lock(pagedresults_mutex); - slapi_pblock_set(pb, SLAPI_SEARCH_RESULT_SET, NULL); -- if (!pagedresults_is_abandoned_or_notavailable(pb_conn, 0 /*not locked*/, pr_idx)) { -- pagedresults_free_one(pb_conn, operation, pr_idx); -+ if (!pagedresults_is_abandoned_or_notavailable(pb_conn, PR_LOCKED, pr_idx)) { -+ pagedresults_free_one(pb_conn, operation, PR_LOCKED, pr_idx); - } -- pagedresults_unlock(pb_conn, pr_idx); -+ pthread_mutex_unlock(pagedresults_mutex); - if (next_be) { - /* no more entries, but at least another backend */ -- if (pagedresults_set_current_be(pb_conn, next_be, pr_idx, 0) < 0) { -+ if (pagedresults_set_current_be(pb_conn, next_be, pr_idx, PR_NOT_LOCKED) < 0) { - goto free_and_return; - } - } -@@ -884,7 +874,7 @@ op_shared_search(Slapi_PBlock *pb, int send_result) - } - } - pagedresults_set_search_result(pb_conn, operation, NULL, 1, pr_idx); -- rc = pagedresults_set_current_be(pb_conn, NULL, pr_idx, 1); -+ rc = pagedresults_set_current_be(pb_conn, NULL, pr_idx, PR_LOCKED); - pthread_mutex_unlock(pagedresults_mutex); - } - -@@ -922,7 +912,7 @@ op_shared_search(Slapi_PBlock *pb, int send_result) - pthread_mutex_lock(pagedresults_mutex); - pagedresults_set_search_result(pb_conn, operation, NULL, 1, pr_idx); - be->be_search_results_release(&sr); -- rc = pagedresults_set_current_be(pb_conn, next_be, pr_idx, 1); -+ rc = pagedresults_set_current_be(pb_conn, next_be, pr_idx, PR_LOCKED); - pthread_mutex_unlock(pagedresults_mutex); - pr_stat = PAGEDRESULTS_SEARCH_END; /* make sure stat is SEARCH_END */ - if (NULL == next_be) { -@@ -935,23 +925,23 @@ op_shared_search(Slapi_PBlock *pb, int send_result) - } else { - curr_search_count = pnentries; - slapi_pblock_get(pb, SLAPI_SEARCH_RESULT_SET_SIZE_ESTIMATE, &estimate); -- pagedresults_lock(pb_conn, pr_idx); -- if ((pagedresults_set_current_be(pb_conn, be, pr_idx, 0) < 0) || -- (pagedresults_set_search_result(pb_conn, operation, sr, 0, pr_idx) < 0) || -- (pagedresults_set_search_result_count(pb_conn, operation, curr_search_count, pr_idx) < 0) || -- (pagedresults_set_search_result_set_size_estimate(pb_conn, operation, estimate, pr_idx) < 0) || -- (pagedresults_set_with_sort(pb_conn, operation, with_sort, pr_idx) < 0)) { -- pagedresults_unlock(pb_conn, pr_idx); -+ pthread_mutex_lock(pagedresults_mutex); -+ if ((pagedresults_set_current_be(pb_conn, be, pr_idx, PR_LOCKED) < 0) || -+ (pagedresults_set_search_result(pb_conn, operation, sr, PR_LOCKED, pr_idx) < 0) || -+ (pagedresults_set_search_result_count(pb_conn, operation, curr_search_count, PR_LOCKED, pr_idx) < 0) || -+ (pagedresults_set_search_result_set_size_estimate(pb_conn, operation, estimate, PR_LOCKED, pr_idx) < 0) || -+ (pagedresults_set_with_sort(pb_conn, operation, with_sort, PR_LOCKED, pr_idx) < 0)) { -+ pthread_mutex_unlock(pagedresults_mutex); - cache_return_target_entry(pb, be, operation); - goto free_and_return; - } -- pagedresults_unlock(pb_conn, pr_idx); -+ pthread_mutex_unlock(pagedresults_mutex); - } - slapi_pblock_set(pb, SLAPI_SEARCH_RESULT_SET, NULL); - next_be = NULL; /* to break the loop */ - if (operation->o_status & SLAPI_OP_STATUS_ABANDONED) { - /* It turned out this search was abandoned. */ -- pagedresults_free_one_msgid(pb_conn, operation->o_msgid, pagedresults_mutex); -+ pagedresults_free_one_msgid(pb_conn, operation->o_msgid, PR_NOT_LOCKED); - /* paged-results-request was abandoned; making an empty cookie. */ - pagedresults_set_response_control(pb, 0, estimate, -1, pr_idx); - send_ldap_result(pb, 0, NULL, "Simple Paged Results Search abandoned", 0, NULL); -@@ -961,7 +951,7 @@ op_shared_search(Slapi_PBlock *pb, int send_result) - } - pagedresults_set_response_control(pb, 0, estimate, curr_search_count, pr_idx); - if (curr_search_count == -1) { -- pagedresults_free_one(pb_conn, operation, pr_idx); -+ pagedresults_free_one(pb_conn, operation, PR_NOT_LOCKED, pr_idx); - } - } - -diff --git a/ldap/servers/slapd/pagedresults.c b/ldap/servers/slapd/pagedresults.c -index 941ab97e3..0d6c4a1aa 100644 ---- a/ldap/servers/slapd/pagedresults.c -+++ b/ldap/servers/slapd/pagedresults.c -@@ -34,9 +34,9 @@ pageresult_lock_cleanup() - slapi_ch_free((void**)&lock_hash); - } - --/* Beware to the lock order with c_mutex: -- * c_mutex is sometime locked while holding pageresult_lock -- * ==> Do not lock pageresult_lock when holing c_mutex -+/* Lock ordering constraint with c_mutex: -+ * c_mutex is sometimes locked while holding pageresult_lock. -+ * Therefore: DO NOT acquire pageresult_lock when holding c_mutex. - */ - pthread_mutex_t * - pageresult_lock_get_addr(Connection *conn) -@@ -44,7 +44,11 @@ pageresult_lock_get_addr(Connection *conn) - return &lock_hash[(((size_t)conn)/sizeof (Connection))%LOCK_HASH_SIZE]; - } - --/* helper function to clean up one prp slot */ -+/* helper function to clean up one prp slot -+ * -+ * NOTE: This function must be called while holding the pageresult_lock -+ * (via pageresult_lock_get_addr(conn)) to ensure thread-safe cleanup. -+ */ - static void - _pr_cleanup_one_slot(PagedResults *prp) - { -@@ -56,7 +60,7 @@ _pr_cleanup_one_slot(PagedResults *prp) - prp->pr_current_be->be_search_results_release(&(prp->pr_search_result_set)); - } - -- /* clean up the slot except the mutex */ -+ /* clean up the slot */ - prp->pr_current_be = NULL; - prp->pr_search_result_set = NULL; - prp->pr_search_result_count = 0; -@@ -136,6 +140,8 @@ pagedresults_parse_control_value(Slapi_PBlock *pb, - return LDAP_UNWILLING_TO_PERFORM; - } - -+ /* Acquire hash-based lock for paged results list access -+ * IMPORTANT: Never acquire this lock when holding c_mutex */ - pthread_mutex_lock(pageresult_lock_get_addr(conn)); - /* the ber encoding is no longer needed */ - ber_free(ber, 1); -@@ -184,10 +190,6 @@ pagedresults_parse_control_value(Slapi_PBlock *pb, - goto bail; - } - -- if ((*index > -1) && (*index < conn->c_pagedresults.prl_maxlen) && -- !conn->c_pagedresults.prl_list[*index].pr_mutex) { -- conn->c_pagedresults.prl_list[*index].pr_mutex = PR_NewLock(); -- } - conn->c_pagedresults.prl_count++; - } else { - /* Repeated paged results request. -@@ -327,8 +329,14 @@ bailout: - "<= idx=%d\n", index); - } - -+/* -+ * Free one paged result entry by index. -+ * -+ * Locking: If locked=0, acquires pageresult_lock. If locked=1, assumes -+ * caller already holds pageresult_lock. Never call when holding c_mutex. -+ */ - int --pagedresults_free_one(Connection *conn, Operation *op, int index) -+pagedresults_free_one(Connection *conn, Operation *op, bool locked, int index) - { - int rc = -1; - -@@ -338,7 +346,9 @@ pagedresults_free_one(Connection *conn, Operation *op, int index) - slapi_log_err(SLAPI_LOG_TRACE, "pagedresults_free_one", - "=> idx=%d\n", index); - if (conn && (index > -1)) { -- pthread_mutex_lock(pageresult_lock_get_addr(conn)); -+ if (!locked) { -+ pthread_mutex_lock(pageresult_lock_get_addr(conn)); -+ } - if (conn->c_pagedresults.prl_count <= 0) { - slapi_log_err(SLAPI_LOG_TRACE, "pagedresults_free_one", - "conn=%" PRIu64 " paged requests list count is %d\n", -@@ -349,7 +359,9 @@ pagedresults_free_one(Connection *conn, Operation *op, int index) - conn->c_pagedresults.prl_count--; - rc = 0; - } -- pthread_mutex_unlock(pageresult_lock_get_addr(conn)); -+ if (!locked) { -+ pthread_mutex_unlock(pageresult_lock_get_addr(conn)); -+ } - } - - slapi_log_err(SLAPI_LOG_TRACE, "pagedresults_free_one", "<= %d\n", rc); -@@ -357,21 +369,28 @@ pagedresults_free_one(Connection *conn, Operation *op, int index) - } - - /* -- * Used for abandoning - pageresult_lock_get_addr(conn) is already locked in do_abandone. -+ * Free one paged result entry by message ID. -+ * -+ * Locking: If locked=0, acquires pageresult_lock. If locked=1, assumes -+ * caller already holds pageresult_lock. Never call when holding c_mutex. - */ - int --pagedresults_free_one_msgid(Connection *conn, ber_int_t msgid, pthread_mutex_t *mutex) -+pagedresults_free_one_msgid(Connection *conn, ber_int_t msgid, bool locked) - { - int rc = -1; - int i; -+ pthread_mutex_t *lock = NULL; - - if (conn && (msgid > -1)) { - if (conn->c_pagedresults.prl_maxlen <= 0) { - ; /* Not a paged result. */ - } else { - slapi_log_err(SLAPI_LOG_TRACE, -- "pagedresults_free_one_msgid_nolock", "=> msgid=%d\n", msgid); -- pthread_mutex_lock(mutex); -+ "pagedresults_free_one_msgid", "=> msgid=%d\n", msgid); -+ lock = pageresult_lock_get_addr(conn); -+ if (!locked) { -+ pthread_mutex_lock(lock); -+ } - for (i = 0; i < conn->c_pagedresults.prl_maxlen; i++) { - if (conn->c_pagedresults.prl_list[i].pr_msgid == msgid) { - PagedResults *prp = conn->c_pagedresults.prl_list + i; -@@ -390,9 +409,11 @@ pagedresults_free_one_msgid(Connection *conn, ber_int_t msgid, pthread_mutex_t * - break; - } - } -- pthread_mutex_unlock(mutex); -+ if (!locked) { -+ pthread_mutex_unlock(lock); -+ } - slapi_log_err(SLAPI_LOG_TRACE, -- "pagedresults_free_one_msgid_nolock", "<= %d\n", rc); -+ "pagedresults_free_one_msgid", "<= %d\n", rc); - } - } - -@@ -418,29 +439,43 @@ pagedresults_get_current_be(Connection *conn, int index) - return be; - } - -+/* -+ * Set current backend for a paged result entry. -+ * -+ * Locking: If locked=false, acquires pageresult_lock. If locked=true, assumes -+ * caller already holds pageresult_lock. Never call when holding c_mutex. -+ */ - int --pagedresults_set_current_be(Connection *conn, Slapi_Backend *be, int index, int nolock) -+pagedresults_set_current_be(Connection *conn, Slapi_Backend *be, int index, bool locked) - { - int rc = -1; - slapi_log_err(SLAPI_LOG_TRACE, - "pagedresults_set_current_be", "=> idx=%d\n", index); - if (conn && (index > -1)) { -- if (!nolock) -+ if (!locked) { - pthread_mutex_lock(pageresult_lock_get_addr(conn)); -+ } - if (index < conn->c_pagedresults.prl_maxlen) { - conn->c_pagedresults.prl_list[index].pr_current_be = be; - } - rc = 0; -- if (!nolock) -+ if (!locked) { - pthread_mutex_unlock(pageresult_lock_get_addr(conn)); -+ } - } - slapi_log_err(SLAPI_LOG_TRACE, - "pagedresults_set_current_be", "<= %d\n", rc); - return rc; - } - -+/* -+ * Get search result set for a paged result entry. -+ * -+ * Locking: If locked=0, acquires pageresult_lock. If locked=1, assumes -+ * caller already holds pageresult_lock. Never call when holding c_mutex. -+ */ - void * --pagedresults_get_search_result(Connection *conn, Operation *op, int locked, int index) -+pagedresults_get_search_result(Connection *conn, Operation *op, bool locked, int index) - { - void *sr = NULL; - if (!op_is_pagedresults(op)) { -@@ -465,8 +500,14 @@ pagedresults_get_search_result(Connection *conn, Operation *op, int locked, int - return sr; - } - -+/* -+ * Set search result set for a paged result entry. -+ * -+ * Locking: If locked=0, acquires pageresult_lock. If locked=1, assumes -+ * caller already holds pageresult_lock. Never call when holding c_mutex. -+ */ - int --pagedresults_set_search_result(Connection *conn, Operation *op, void *sr, int locked, int index) -+pagedresults_set_search_result(Connection *conn, Operation *op, void *sr, bool locked, int index) - { - int rc = -1; - if (!op_is_pagedresults(op)) { -@@ -494,8 +535,14 @@ pagedresults_set_search_result(Connection *conn, Operation *op, void *sr, int lo - return rc; - } - -+/* -+ * Get search result count for a paged result entry. -+ * -+ * Locking: If locked=0, acquires pageresult_lock. If locked=1, assumes -+ * caller already holds pageresult_lock. Never call when holding c_mutex. -+ */ - int --pagedresults_get_search_result_count(Connection *conn, Operation *op, int index) -+pagedresults_get_search_result_count(Connection *conn, Operation *op, bool locked, int index) - { - int count = 0; - if (!op_is_pagedresults(op)) { -@@ -504,19 +551,29 @@ pagedresults_get_search_result_count(Connection *conn, Operation *op, int index) - slapi_log_err(SLAPI_LOG_TRACE, - "pagedresults_get_search_result_count", "=> idx=%d\n", index); - if (conn && (index > -1)) { -- pthread_mutex_lock(pageresult_lock_get_addr(conn)); -+ if (!locked) { -+ pthread_mutex_lock(pageresult_lock_get_addr(conn)); -+ } - if (index < conn->c_pagedresults.prl_maxlen) { - count = conn->c_pagedresults.prl_list[index].pr_search_result_count; - } -- pthread_mutex_unlock(pageresult_lock_get_addr(conn)); -+ if (!locked) { -+ pthread_mutex_unlock(pageresult_lock_get_addr(conn)); -+ } - } - slapi_log_err(SLAPI_LOG_TRACE, - "pagedresults_get_search_result_count", "<= %d\n", count); - return count; - } - -+/* -+ * Set search result count for a paged result entry. -+ * -+ * Locking: If locked=0, acquires pageresult_lock. If locked=1, assumes -+ * caller already holds pageresult_lock. Never call when holding c_mutex. -+ */ - int --pagedresults_set_search_result_count(Connection *conn, Operation *op, int count, int index) -+pagedresults_set_search_result_count(Connection *conn, Operation *op, int count, bool locked, int index) - { - int rc = -1; - if (!op_is_pagedresults(op)) { -@@ -525,11 +582,15 @@ pagedresults_set_search_result_count(Connection *conn, Operation *op, int count, - slapi_log_err(SLAPI_LOG_TRACE, - "pagedresults_set_search_result_count", "=> idx=%d\n", index); - if (conn && (index > -1)) { -- pthread_mutex_lock(pageresult_lock_get_addr(conn)); -+ if (!locked) { -+ pthread_mutex_lock(pageresult_lock_get_addr(conn)); -+ } - if (index < conn->c_pagedresults.prl_maxlen) { - conn->c_pagedresults.prl_list[index].pr_search_result_count = count; - } -- pthread_mutex_unlock(pageresult_lock_get_addr(conn)); -+ if (!locked) { -+ pthread_mutex_unlock(pageresult_lock_get_addr(conn)); -+ } - rc = 0; - } - slapi_log_err(SLAPI_LOG_TRACE, -@@ -537,9 +598,16 @@ pagedresults_set_search_result_count(Connection *conn, Operation *op, int count, - return rc; - } - -+/* -+ * Get search result set size estimate for a paged result entry. -+ * -+ * Locking: If locked=0, acquires pageresult_lock. If locked=1, assumes -+ * caller already holds pageresult_lock. Never call when holding c_mutex. -+ */ - int - pagedresults_get_search_result_set_size_estimate(Connection *conn, - Operation *op, -+ bool locked, - int index) - { - int count = 0; -@@ -550,11 +618,15 @@ pagedresults_get_search_result_set_size_estimate(Connection *conn, - "pagedresults_get_search_result_set_size_estimate", - "=> idx=%d\n", index); - if (conn && (index > -1)) { -- pthread_mutex_lock(pageresult_lock_get_addr(conn)); -+ if (!locked) { -+ pthread_mutex_lock(pageresult_lock_get_addr(conn)); -+ } - if (index < conn->c_pagedresults.prl_maxlen) { - count = conn->c_pagedresults.prl_list[index].pr_search_result_set_size_estimate; - } -- pthread_mutex_unlock(pageresult_lock_get_addr(conn)); -+ if (!locked) { -+ pthread_mutex_unlock(pageresult_lock_get_addr(conn)); -+ } - } - slapi_log_err(SLAPI_LOG_TRACE, - "pagedresults_get_search_result_set_size_estimate", "<= %d\n", -@@ -562,10 +634,17 @@ pagedresults_get_search_result_set_size_estimate(Connection *conn, - return count; - } - -+/* -+ * Set search result set size estimate for a paged result entry. -+ * -+ * Locking: If locked=0, acquires pageresult_lock. If locked=1, assumes -+ * caller already holds pageresult_lock. Never call when holding c_mutex. -+ */ - int - pagedresults_set_search_result_set_size_estimate(Connection *conn, - Operation *op, - int count, -+ bool locked, - int index) - { - int rc = -1; -@@ -576,11 +655,15 @@ pagedresults_set_search_result_set_size_estimate(Connection *conn, - "pagedresults_set_search_result_set_size_estimate", - "=> idx=%d\n", index); - if (conn && (index > -1)) { -- pthread_mutex_lock(pageresult_lock_get_addr(conn)); -+ if (!locked) { -+ pthread_mutex_lock(pageresult_lock_get_addr(conn)); -+ } - if (index < conn->c_pagedresults.prl_maxlen) { - conn->c_pagedresults.prl_list[index].pr_search_result_set_size_estimate = count; - } -- pthread_mutex_unlock(pageresult_lock_get_addr(conn)); -+ if (!locked) { -+ pthread_mutex_unlock(pageresult_lock_get_addr(conn)); -+ } - rc = 0; - } - slapi_log_err(SLAPI_LOG_TRACE, -@@ -589,8 +672,14 @@ pagedresults_set_search_result_set_size_estimate(Connection *conn, - return rc; - } - -+/* -+ * Get with_sort flag for a paged result entry. -+ * -+ * Locking: If locked=0, acquires pageresult_lock. If locked=1, assumes -+ * caller already holds pageresult_lock. Never call when holding c_mutex. -+ */ - int --pagedresults_get_with_sort(Connection *conn, Operation *op, int index) -+pagedresults_get_with_sort(Connection *conn, Operation *op, bool locked, int index) - { - int flags = 0; - if (!op_is_pagedresults(op)) { -@@ -599,19 +688,29 @@ pagedresults_get_with_sort(Connection *conn, Operation *op, int index) - slapi_log_err(SLAPI_LOG_TRACE, - "pagedresults_get_with_sort", "=> idx=%d\n", index); - if (conn && (index > -1)) { -- pthread_mutex_lock(pageresult_lock_get_addr(conn)); -+ if (!locked) { -+ pthread_mutex_lock(pageresult_lock_get_addr(conn)); -+ } - if (index < conn->c_pagedresults.prl_maxlen) { - flags = conn->c_pagedresults.prl_list[index].pr_flags & CONN_FLAG_PAGEDRESULTS_WITH_SORT; - } -- pthread_mutex_unlock(pageresult_lock_get_addr(conn)); -+ if (!locked) { -+ pthread_mutex_unlock(pageresult_lock_get_addr(conn)); -+ } - } - slapi_log_err(SLAPI_LOG_TRACE, - "pagedresults_get_with_sort", "<= %d\n", flags); - return flags; - } - -+/* -+ * Set with_sort flag for a paged result entry. -+ * -+ * Locking: If locked=0, acquires pageresult_lock. If locked=1, assumes -+ * caller already holds pageresult_lock. Never call when holding c_mutex. -+ */ - int --pagedresults_set_with_sort(Connection *conn, Operation *op, int flags, int index) -+pagedresults_set_with_sort(Connection *conn, Operation *op, int flags, bool locked, int index) - { - int rc = -1; - if (!op_is_pagedresults(op)) { -@@ -620,14 +719,18 @@ pagedresults_set_with_sort(Connection *conn, Operation *op, int flags, int index - slapi_log_err(SLAPI_LOG_TRACE, - "pagedresults_set_with_sort", "=> idx=%d\n", index); - if (conn && (index > -1)) { -- pthread_mutex_lock(pageresult_lock_get_addr(conn)); -+ if (!locked) { -+ pthread_mutex_lock(pageresult_lock_get_addr(conn)); -+ } - if (index < conn->c_pagedresults.prl_maxlen) { - if (flags & OP_FLAG_SERVER_SIDE_SORTING) { - conn->c_pagedresults.prl_list[index].pr_flags |= - CONN_FLAG_PAGEDRESULTS_WITH_SORT; - } - } -- pthread_mutex_unlock(pageresult_lock_get_addr(conn)); -+ if (!locked) { -+ pthread_mutex_unlock(pageresult_lock_get_addr(conn)); -+ } - rc = 0; - } - slapi_log_err(SLAPI_LOG_TRACE, "pagedresults_set_with_sort", "<= %d\n", rc); -@@ -802,10 +905,6 @@ pagedresults_cleanup(Connection *conn, int needlock) - rc = 1; - } - prp->pr_current_be = NULL; -- if (prp->pr_mutex) { -- PR_DestroyLock(prp->pr_mutex); -- prp->pr_mutex = NULL; -- } - memset(prp, '\0', sizeof(PagedResults)); - } - conn->c_pagedresults.prl_count = 0; -@@ -840,10 +939,6 @@ pagedresults_cleanup_all(Connection *conn, int needlock) - i < conn->c_pagedresults.prl_maxlen; - i++) { - prp = conn->c_pagedresults.prl_list + i; -- if (prp->pr_mutex) { -- PR_DestroyLock(prp->pr_mutex); -- prp->pr_mutex = NULL; -- } - if (prp->pr_current_be && prp->pr_search_result_set && - prp->pr_current_be->be_search_results_release) { - prp->pr_current_be->be_search_results_release(&(prp->pr_search_result_set)); -@@ -1010,43 +1105,8 @@ op_set_pagedresults(Operation *op) - op->o_flags |= OP_FLAG_PAGED_RESULTS; - } - --/* -- * pagedresults_lock/unlock -- introduced to protect search results for the -- * asynchronous searches. Do not call these functions while the PR conn lock -- * is held (e.g. pageresult_lock_get_addr(conn)) -- */ --void --pagedresults_lock(Connection *conn, int index) --{ -- PagedResults *prp; -- if (!conn || (index < 0) || (index >= conn->c_pagedresults.prl_maxlen)) { -- return; -- } -- pthread_mutex_lock(pageresult_lock_get_addr(conn)); -- prp = conn->c_pagedresults.prl_list + index; -- if (prp->pr_mutex) { -- PR_Lock(prp->pr_mutex); -- } -- pthread_mutex_unlock(pageresult_lock_get_addr(conn)); --} -- --void --pagedresults_unlock(Connection *conn, int index) --{ -- PagedResults *prp; -- if (!conn || (index < 0) || (index >= conn->c_pagedresults.prl_maxlen)) { -- return; -- } -- pthread_mutex_lock(pageresult_lock_get_addr(conn)); -- prp = conn->c_pagedresults.prl_list + index; -- if (prp->pr_mutex) { -- PR_Unlock(prp->pr_mutex); -- } -- pthread_mutex_unlock(pageresult_lock_get_addr(conn)); --} -- - int --pagedresults_is_abandoned_or_notavailable(Connection *conn, int locked, int index) -+pagedresults_is_abandoned_or_notavailable(Connection *conn, bool locked, int index) - { - PagedResults *prp; - int32_t result; -@@ -1066,7 +1126,7 @@ pagedresults_is_abandoned_or_notavailable(Connection *conn, int locked, int inde - } - - int --pagedresults_set_search_result_pb(Slapi_PBlock *pb, void *sr, int locked) -+pagedresults_set_search_result_pb(Slapi_PBlock *pb, void *sr, bool locked) - { - int rc = -1; - Connection *conn = NULL; -diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h -index 37c643ea9..742e3ee14 100644 ---- a/ldap/servers/slapd/proto-slap.h -+++ b/ldap/servers/slapd/proto-slap.h -@@ -1597,20 +1597,22 @@ pthread_mutex_t *pageresult_lock_get_addr(Connection *conn); - int pagedresults_parse_control_value(Slapi_PBlock *pb, struct berval *psbvp, ber_int_t *pagesize, int *index, Slapi_Backend *be); - void pagedresults_set_response_control(Slapi_PBlock *pb, int iscritical, ber_int_t estimate, int curr_search_count, int index); - Slapi_Backend *pagedresults_get_current_be(Connection *conn, int index); --int pagedresults_set_current_be(Connection *conn, Slapi_Backend *be, int index, int nolock); --void *pagedresults_get_search_result(Connection *conn, Operation *op, int locked, int index); --int pagedresults_set_search_result(Connection *conn, Operation *op, void *sr, int locked, int index); --int pagedresults_get_search_result_count(Connection *conn, Operation *op, int index); --int pagedresults_set_search_result_count(Connection *conn, Operation *op, int cnt, int index); -+int pagedresults_set_current_be(Connection *conn, Slapi_Backend *be, int index, bool locked); -+void *pagedresults_get_search_result(Connection *conn, Operation *op, bool locked, int index); -+int pagedresults_set_search_result(Connection *conn, Operation *op, void *sr, bool locked, int index); -+int pagedresults_get_search_result_count(Connection *conn, Operation *op, bool locked, int index); -+int pagedresults_set_search_result_count(Connection *conn, Operation *op, int cnt, bool locked, int index); - int pagedresults_get_search_result_set_size_estimate(Connection *conn, - Operation *op, -+ bool locked, - int index); - int pagedresults_set_search_result_set_size_estimate(Connection *conn, - Operation *op, - int cnt, -+ bool locked, - int index); --int pagedresults_get_with_sort(Connection *conn, Operation *op, int index); --int pagedresults_set_with_sort(Connection *conn, Operation *op, int flags, int index); -+int pagedresults_get_with_sort(Connection *conn, Operation *op, bool locked, int index); -+int pagedresults_set_with_sort(Connection *conn, Operation *op, int flags, bool locked, int index); - int pagedresults_get_unindexed(Connection *conn, Operation *op, int index); - int pagedresults_set_unindexed(Connection *conn, Operation *op, int index); - int pagedresults_get_sort_result_code(Connection *conn, Operation *op, int index); -@@ -1622,15 +1624,13 @@ int pagedresults_cleanup(Connection *conn, int needlock); - int pagedresults_is_timedout_nolock(Connection *conn); - int pagedresults_reset_timedout_nolock(Connection *conn); - int pagedresults_in_use_nolock(Connection *conn); --int pagedresults_free_one(Connection *conn, Operation *op, int index); --int pagedresults_free_one_msgid(Connection *conn, ber_int_t msgid, pthread_mutex_t *mutex); -+int pagedresults_free_one(Connection *conn, Operation *op, bool locked, int index); -+int pagedresults_free_one_msgid(Connection *conn, ber_int_t msgid, bool locked); - int op_is_pagedresults(Operation *op); - int pagedresults_cleanup_all(Connection *conn, int needlock); - void op_set_pagedresults(Operation *op); --void pagedresults_lock(Connection *conn, int index); --void pagedresults_unlock(Connection *conn, int index); --int pagedresults_is_abandoned_or_notavailable(Connection *conn, int locked, int index); --int pagedresults_set_search_result_pb(Slapi_PBlock *pb, void *sr, int locked); -+int pagedresults_is_abandoned_or_notavailable(Connection *conn, bool locked, int index); -+int pagedresults_set_search_result_pb(Slapi_PBlock *pb, void *sr, bool locked); - - /* - * sort.c -diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h -index 9aaa4fb80..f2395cfa2 100644 ---- a/ldap/servers/slapd/slap.h -+++ b/ldap/servers/slapd/slap.h -@@ -80,6 +80,10 @@ static char ptokPBE[34] = "Internal (Software) Token "; - #include - #include /* For timespec definitions */ - -+/* Macros for paged results lock parameter */ -+#define PR_LOCKED true -+#define PR_NOT_LOCKED false -+ - /* Provides our int types and platform specific requirements. */ - #include - -@@ -1656,7 +1660,6 @@ typedef struct _paged_results - struct timespec pr_timelimit_hr; /* expiry time of this request rel to clock monotonic */ - int pr_flags; - ber_int_t pr_msgid; /* msgid of the request; to abandon */ -- PRLock *pr_mutex; /* protect each conn structure */ - } PagedResults; - - /* array of simple paged structure stashed in connection */ --- -2.52.0 - diff --git a/0004-Issue-7172-Index-ordering-mismatch-after-upgrade-717.patch b/0004-Issue-7172-Index-ordering-mismatch-after-upgrade-717.patch deleted file mode 100644 index 824c475..0000000 --- a/0004-Issue-7172-Index-ordering-mismatch-after-upgrade-717.patch +++ /dev/null @@ -1,213 +0,0 @@ -From 5b6211de252f801ffc088703acc242e47f6273ab Mon Sep 17 00:00:00 2001 -From: Viktor Ashirov -Date: Fri, 9 Jan 2026 11:39:50 +0100 -Subject: [PATCH] Issue 7172 - Index ordering mismatch after upgrade (#7173) - -Bug Description: -Commit daf731f55071d45eaf403a52b63d35f4e699ff28 introduced a regression. -After upgrading to a version that adds `integerOrderingMatch` matching -rule to `parentid` and `ancestorid` indexes, searches may return empty -or incorrect results. - -This happens because the existing index data was created with -lexicographic ordering, but the new compare function expects integer -ordering. Index lookups fail because the compare function doesn't match -the data ordering. -The root cause is that `ldbm_instance_create_default_indexes()` calls -`attr_index_config()` unconditionally for `parentid` and `ancestorid` -indexes, which triggers `ainfo_dup()` to overwrite `ai_key_cmp_fn` on -existing indexes. This breaks indexes that were created without the -`integerOrderingMatch` matching rule. - -Fix Description: -* Call `attr_index_config()` for `parentid` and `ancestorid` indexes -only if index config doesn't exist. - -* Add `upgrade_check_id_index_matching_rule()` that logs an error on -server startup if `parentid` or `ancestorid` indexes are missing the -integerOrderingMatch matching rule, advising administrators to reindex. - -Fixes: https://github.com/389ds/389-ds-base/issues/7172 - -Reviewed by: @tbordaz, @progier389, @droideck (Thanks!) ---- - ldap/servers/slapd/back-ldbm/instance.c | 25 ++++-- - ldap/servers/slapd/upgrade.c | 105 ++++++++++++++++++++++++ - 2 files changed, 122 insertions(+), 8 deletions(-) - -diff --git a/ldap/servers/slapd/back-ldbm/instance.c b/ldap/servers/slapd/back-ldbm/instance.c -index 24c00200b..30db99c81 100644 ---- a/ldap/servers/slapd/back-ldbm/instance.c -+++ b/ldap/servers/slapd/back-ldbm/instance.c -@@ -191,6 +191,7 @@ ldbm_instance_create_default_indexes(backend *be) - char *ancestorid_indexes_limit = NULL; - char *parentid_indexes_limit = NULL; - struct attrinfo *ai = NULL; -+ struct attrinfo *index_already_configured = NULL; - struct index_idlistsizeinfo *iter; - int cookie; - int limit; -@@ -255,10 +256,14 @@ ldbm_instance_create_default_indexes(backend *be) - slapi_entry_free(e); - } - -- e = ldbm_instance_init_config_entry(LDBM_PARENTID_STR, "eq", 0, 0, 0, "integerOrderingMatch", parentid_indexes_limit); -- ldbm_instance_config_add_index_entry(inst, e, flags); -- attr_index_config(be, "ldbm index init", 0, e, 1, 0, NULL); -- slapi_entry_free(e); -+ ainfo_get(be, (char *)LDBM_PARENTID_STR, &ai); -+ index_already_configured = ai; -+ if (!index_already_configured) { -+ e = ldbm_instance_init_config_entry(LDBM_PARENTID_STR, "eq", 0, 0, 0, "integerOrderingMatch", parentid_indexes_limit); -+ ldbm_instance_config_add_index_entry(inst, e, flags); -+ attr_index_config(be, "ldbm index init", 0, e, 1, 0, NULL); -+ slapi_entry_free(e); -+ } - - e = ldbm_instance_init_config_entry("objectclass", "eq", 0, 0, 0, 0, 0); - ldbm_instance_config_add_index_entry(inst, e, flags); -@@ -296,10 +301,14 @@ ldbm_instance_create_default_indexes(backend *be) - * ancestorid is special, there is actually no such attr type - * but we still want to use the attr index file APIs. - */ -- e = ldbm_instance_init_config_entry(LDBM_ANCESTORID_STR, "eq", 0, 0, 0, "integerOrderingMatch", ancestorid_indexes_limit); -- ldbm_instance_config_add_index_entry(inst, e, flags); -- attr_index_config(be, "ldbm index init", 0, e, 1, 0, NULL); -- slapi_entry_free(e); -+ ainfo_get(be, (char *)LDBM_ANCESTORID_STR, &ai); -+ index_already_configured = ai; -+ if (!index_already_configured) { -+ e = ldbm_instance_init_config_entry(LDBM_ANCESTORID_STR, "eq", 0, 0, 0, "integerOrderingMatch", ancestorid_indexes_limit); -+ ldbm_instance_config_add_index_entry(inst, e, flags); -+ attr_index_config(be, "ldbm index init", 0, e, 1, 0, NULL); -+ slapi_entry_free(e); -+ } - } - - slapi_ch_free_string(&ancestorid_indexes_limit); -diff --git a/ldap/servers/slapd/upgrade.c b/ldap/servers/slapd/upgrade.c -index 0d1e2abf4..43906c1af 100644 ---- a/ldap/servers/slapd/upgrade.c -+++ b/ldap/servers/slapd/upgrade.c -@@ -279,6 +279,107 @@ upgrade_205_fixup_repl_dep(void) - return UPGRADE_SUCCESS; - } - -+/* -+ * Check if parentid/ancestorid indexes are missing the integerOrderingMatch -+ * matching rule. -+ * -+ * This function logs a warning if we detect this condition, advising -+ * the administrator to reindex the affected attributes. -+ */ -+static upgrade_status -+upgrade_check_id_index_matching_rule(void) -+{ -+ struct slapi_pblock *pb = slapi_pblock_new(); -+ Slapi_Entry **backends = NULL; -+ const char *be_base_dn = "cn=ldbm database,cn=plugins,cn=config"; -+ const char *be_filter = "(objectclass=nsBackendInstance)"; -+ const char *attrs_to_check[] = {"parentid", "ancestorid", NULL}; -+ upgrade_status uresult = UPGRADE_SUCCESS; -+ -+ /* Search for all backend instances */ -+ slapi_search_internal_set_pb( -+ pb, be_base_dn, -+ LDAP_SCOPE_ONELEVEL, -+ be_filter, NULL, 0, NULL, NULL, -+ plugin_get_default_component_id(), 0); -+ slapi_search_internal_pb(pb); -+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &backends); -+ -+ if (backends) { -+ for (size_t be_idx = 0; backends[be_idx] != NULL; be_idx++) { -+ const char *be_name = slapi_entry_attr_get_ref(backends[be_idx], "cn"); -+ if (!be_name) { -+ continue; -+ } -+ -+ /* Check each attribute that should have integerOrderingMatch */ -+ for (size_t attr_idx = 0; attrs_to_check[attr_idx] != NULL; attr_idx++) { -+ const char *attr_name = attrs_to_check[attr_idx]; -+ struct slapi_pblock *idx_pb = slapi_pblock_new(); -+ Slapi_Entry **idx_entries = NULL; -+ char *idx_dn = slapi_create_dn_string("cn=%s,cn=index,cn=%s,%s", -+ attr_name, be_name, be_base_dn); -+ char *idx_filter = "(objectclass=nsIndex)"; -+ PRBool has_matching_rule = PR_FALSE; -+ -+ if (!idx_dn) { -+ slapi_pblock_destroy(idx_pb); -+ continue; -+ } -+ -+ slapi_search_internal_set_pb( -+ idx_pb, idx_dn, -+ LDAP_SCOPE_BASE, -+ idx_filter, NULL, 0, NULL, NULL, -+ plugin_get_default_component_id(), 0); -+ slapi_search_internal_pb(idx_pb); -+ slapi_pblock_get(idx_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &idx_entries); -+ -+ if (idx_entries && idx_entries[0]) { -+ /* Index exists, check if it has integerOrderingMatch */ -+ Slapi_Attr *mr_attr = NULL; -+ if (slapi_entry_attr_find(idx_entries[0], "nsMatchingRule", &mr_attr) == 0) { -+ Slapi_Value *sval = NULL; -+ int idx; -+ for (idx = slapi_attr_first_value(mr_attr, &sval); -+ idx != -1; -+ idx = slapi_attr_next_value(mr_attr, idx, &sval)) { -+ const struct berval *bval = slapi_value_get_berval(sval); -+ if (bval && bval->bv_val && -+ strcasecmp(bval->bv_val, "integerOrderingMatch") == 0) { -+ has_matching_rule = PR_TRUE; -+ break; -+ } -+ } -+ } -+ -+ if (!has_matching_rule) { -+ /* Index exists but doesn't have integerOrderingMatch, log a warning */ -+ slapi_log_err(SLAPI_LOG_ERR, "upgrade_check_id_index_matching_rule", -+ "Index '%s' in backend '%s' is missing 'nsMatchingRule: integerOrderingMatch'. " -+ "Incorrectly configured system indexes can lead to poor search performance, replication issues, and other operational problems. " -+ "To fix this, add the matching rule and reindex: " -+ "dsconf backend index set --add-mr integerOrderingMatch --attr %s %s && " -+ "dsconf backend index reindex --attr %s %s. " -+ "WARNING: Reindexing can be resource-intensive and may impact server performance on a live system. " -+ "Consider scheduling reindexing during maintenance windows or periods of low activity.\n", -+ attr_name, be_name, attr_name, be_name, attr_name, be_name); -+ } -+ } -+ -+ slapi_ch_free_string(&idx_dn); -+ slapi_free_search_results_internal(idx_pb); -+ slapi_pblock_destroy(idx_pb); -+ } -+ } -+ } -+ -+ slapi_free_search_results_internal(pb); -+ slapi_pblock_destroy(pb); -+ -+ return uresult; -+} -+ - upgrade_status - upgrade_server(void) - { -@@ -306,6 +407,10 @@ upgrade_server(void) - return UPGRADE_FAILURE; - } - -+ if (upgrade_check_id_index_matching_rule() != UPGRADE_SUCCESS) { -+ return UPGRADE_FAILURE; -+ } -+ - return UPGRADE_SUCCESS; - } - --- -2.52.0 - diff --git a/0004-Issue-7437-LeakSanitizer-memory-leaks-in-CoS-cache-e.patch b/0004-Issue-7437-LeakSanitizer-memory-leaks-in-CoS-cache-e.patch new file mode 100644 index 0000000..b62bc45 --- /dev/null +++ b/0004-Issue-7437-LeakSanitizer-memory-leaks-in-CoS-cache-e.patch @@ -0,0 +1,54 @@ +From 56dde3de7c90d9d81f4588a5afda2cfa05bdb20f Mon Sep 17 00:00:00 2001 +From: Viktor Ashirov +Date: Fri, 24 Apr 2026 11:19:04 +0200 +Subject: [PATCH 4/8] Issue 7437 - LeakSanitizer: memory leaks in CoS cache + error paths (#7438) + +Description: +Fix memory leaks in CoS plugin when a CoS definition fails validation +or is incomplete. + +Fixes: https://github.com/389ds/389-ds-base/issues/7437 + +Reviewed by: @mreynolds389 (Thanks!) +--- + ldap/servers/plugins/cos/cos_cache.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/ldap/servers/plugins/cos/cos_cache.c b/ldap/servers/plugins/cos/cos_cache.c +index d8ebbbe3d..7074cb60a 100644 +--- a/ldap/servers/plugins/cos/cos_cache.c ++++ b/ldap/servers/plugins/cos/cos_cache.c +@@ -1007,6 +1007,14 @@ cos_dn_defs_cb(Slapi_Entry *e, void *callback_data) + cos_cache_del_attrval_list(&pCosSpecifier); + if (pCosAttribute) + cos_cache_del_attrval_list(&pCosAttribute); ++ if (pCosOverrides) ++ cos_cache_del_attrval_list(&pCosOverrides); ++ if (pCosOperational) ++ cos_cache_del_attrval_list(&pCosOperational); ++ if (pCosMerge) ++ cos_cache_del_attrval_list(&pCosMerge); ++ if (pCosOpDefault) ++ cos_cache_del_attrval_list(&pCosOpDefault); + if (pDn) + cos_cache_del_attrval_list(&pDn); + } +@@ -1430,6 +1438,14 @@ out: + cos_cache_del_attrval_list(spec); + if (pAttrs) + cos_cache_del_attrval_list(pAttrs); ++ if (pOverrides) ++ cos_cache_del_attrval_list(pOverrides); ++ if (pOperational) ++ cos_cache_del_attrval_list(pOperational); ++ if (pCosMerge) ++ cos_cache_del_attrval_list(pCosMerge); ++ if (pCosOpDefault) ++ cos_cache_del_attrval_list(pCosOpDefault); + } + + slapi_log_err(SLAPI_LOG_TRACE, COS_PLUGIN_SUBSYSTEM, "<-- cos_cache_add_defn\n"); +-- +2.54.0 + diff --git a/0005-Issue-7172-2nd-Index-ordering-mismatch-after-upgrade.patch b/0005-Issue-7172-2nd-Index-ordering-mismatch-after-upgrade.patch deleted file mode 100644 index cec44d4..0000000 --- a/0005-Issue-7172-2nd-Index-ordering-mismatch-after-upgrade.patch +++ /dev/null @@ -1,67 +0,0 @@ -From cae81cde000df9a28733c673ee7c9b8292d69ef3 Mon Sep 17 00:00:00 2001 -From: Viktor Ashirov -Date: Mon, 12 Jan 2026 10:58:02 +0100 -Subject: [PATCH] Issue 7172 - (2nd) Index ordering mismatch after upgrade - (#7180) - -Commit 742c12e0247ab64e87da000a4de2f3e5c99044ab introduced a regression -where the check to skip creating parentid/ancestorid indexes if they -already exist was incorrect. -The `ainfo_get()` function falls back to returning -LDBM_PSEUDO_ATTR_DEFAULT attrinfo when the requested attribute is not -found. -Since LDBM_PSEUDO_ATTR_DEFAULT is created before the ancestorid check, -`ainfo_get()` returns LDBM_PSEUDO_ATTR_DEFAULT instead of NULL, causing -the ancestorid index creation to be skipped entirely. - -When operations later try to use the ancestorid index, they fall back to -LDBM_PSEUDO_ATTR_DEFAULT, and attempting to open the .default dbi -mid-transaction fails with MDB_NOTFOUND (-30798). - -Fix Description: -Instead of just checking if `ainfo_get()` returns non-NULL, verify that -the returned attrinfo is actually for the requested attribute. - -Fixes: https://github.com/389ds/389-ds-base/issues/7172 - -Reviewed by: @tbordaz (Thanks!) ---- - ldap/servers/slapd/back-ldbm/instance.c | 8 +++++--- - 1 file changed, 5 insertions(+), 3 deletions(-) - -diff --git a/ldap/servers/slapd/back-ldbm/instance.c b/ldap/servers/slapd/back-ldbm/instance.c -index 30db99c81..23bd70243 100644 ---- a/ldap/servers/slapd/back-ldbm/instance.c -+++ b/ldap/servers/slapd/back-ldbm/instance.c -@@ -191,7 +191,7 @@ ldbm_instance_create_default_indexes(backend *be) - char *ancestorid_indexes_limit = NULL; - char *parentid_indexes_limit = NULL; - struct attrinfo *ai = NULL; -- struct attrinfo *index_already_configured = NULL; -+ int index_already_configured = 0; - struct index_idlistsizeinfo *iter; - int cookie; - int limit; -@@ -257,7 +257,8 @@ ldbm_instance_create_default_indexes(backend *be) - } - - ainfo_get(be, (char *)LDBM_PARENTID_STR, &ai); -- index_already_configured = ai; -+ /* Check if the attrinfo is actually for parentid, not a fallback to .default */ -+ index_already_configured = (ai != NULL && strcmp(ai->ai_type, LDBM_PARENTID_STR) == 0); - if (!index_already_configured) { - e = ldbm_instance_init_config_entry(LDBM_PARENTID_STR, "eq", 0, 0, 0, "integerOrderingMatch", parentid_indexes_limit); - ldbm_instance_config_add_index_entry(inst, e, flags); -@@ -302,7 +303,8 @@ ldbm_instance_create_default_indexes(backend *be) - * but we still want to use the attr index file APIs. - */ - ainfo_get(be, (char *)LDBM_ANCESTORID_STR, &ai); -- index_already_configured = ai; -+ /* Check if the attrinfo is actually for ancestorid, not a fallback to .default */ -+ index_already_configured = (ai != NULL && strcmp(ai->ai_type, LDBM_ANCESTORID_STR) == 0); - if (!index_already_configured) { - e = ldbm_instance_init_config_entry(LDBM_ANCESTORID_STR, "eq", 0, 0, 0, "integerOrderingMatch", ancestorid_indexes_limit); - ldbm_instance_config_add_index_entry(inst, e, flags); --- -2.52.0 - diff --git a/0005-Issue-7372-Reindex-adds-tombstones-to-ancestorid-cau.patch b/0005-Issue-7372-Reindex-adds-tombstones-to-ancestorid-cau.patch new file mode 100644 index 0000000..a177457 --- /dev/null +++ b/0005-Issue-7372-Reindex-adds-tombstones-to-ancestorid-cau.patch @@ -0,0 +1,169 @@ +From f34eff84824f64470a8c181a0f7a8492695eaab3 Mon Sep 17 00:00:00 2001 +From: Viktor Ashirov +Date: Tue, 5 May 2026 11:13:47 +0200 +Subject: [PATCH 5/8] Issue 7372 - Reindex adds tombstones to ancestorid + causing export failures (#7373) + +Bug Description: +During import/reindex, tombstone entries are added to the ancestorid +index. When those tombstones are later purged, the purge thread skips +updates to ancestorid index. This leaves stale entry IDs in the +ancestorid index referencing entries in id2entry that are no longer +there. + +Fix Description: +Skip tombstone entries when building the ancestorid index during +import/reindex. + +Fixes: https://github.com/389ds/389-ds-base/issues/7372 + +Reviewed by: @progier389, @tbordaz, @droideck (Thanks!) +--- + .../export/export_reindex_tombstone_test.py | 107 ++++++++++++++++++ + .../slapd/back-ldbm/db-bdb/bdb_ldif2db.c | 2 +- + .../back-ldbm/db-mdb/mdb_import_threads.c | 2 +- + 3 files changed, 109 insertions(+), 2 deletions(-) + create mode 100644 dirsrvtests/tests/suites/export/export_reindex_tombstone_test.py + +diff --git a/dirsrvtests/tests/suites/export/export_reindex_tombstone_test.py b/dirsrvtests/tests/suites/export/export_reindex_tombstone_test.py +new file mode 100644 +index 000000000..3cb6e6178 +--- /dev/null ++++ b/dirsrvtests/tests/suites/export/export_reindex_tombstone_test.py +@@ -0,0 +1,107 @@ ++# --- BEGIN COPYRIGHT BLOCK --- ++# Copyright (C) 2026 Red Hat, Inc. ++# All rights reserved. ++# ++# License: GPL (version 3 or any later version). ++# See LICENSE for details. ++# --- END COPYRIGHT BLOCK --- ++ ++import os ++import time ++import pytest ++import ldap ++from lib389.idm.user import UserAccounts ++from lib389.idm.domain import Domain ++from lib389.tombstone import Tombstones ++from lib389.topologies import topology_m2 as topo_m2 ++from lib389._constants import DEFAULT_SUFFIX, DEFAULT_BENAME, ErrorLog ++from lib389.utils import * ++from lib389.backend import Backends ++from lib389.replica import Replicas, ReplicationManager ++ ++pytestmark = pytest.mark.tier1 ++ ++ ++def test_export_after_reindex_and_tombstone_purge(topo_m2): ++ """Test that export with -s works after reindex and tombstone purge. ++ ++ :id: 8c5cb603-1f43-46ad-9935-5f518d6d7fe0 ++ :setup: Two supplier replication topology ++ :steps: ++ 1. Add entries under ou=people on S1, wait for replication to S2 ++ 2. Delete the entries on S1, wait for replication ++ 3. Perform additional modifications to advance the RUV ++ 4. Reindex S1 ++ 5. Configure aggressive tombstone purging and wait for tombstones to be purged on S1 ++ 6. Export ou=people,dc=example,dc=com with -s ++ :expectedresults: ++ 1. Success ++ 2. Success ++ 3. Success ++ 4. Success ++ 5. Success ++ 6. Export completes successfully ++ """ ++ S1 = topo_m2.ms["supplier1"] ++ S2 = topo_m2.ms["supplier2"] ++ PEOPLE = f"ou=people,{DEFAULT_SUFFIX}" ++ ++ users = UserAccounts(S1, DEFAULT_SUFFIX, rdn="ou=people") ++ test_users = [] ++ for i in range(5): ++ user = users.create_test_user(uid=1234 + i) ++ test_users.append(user) ++ log.info("Added 5 test entries under ou=people") ++ ++ repl = ReplicationManager(DEFAULT_SUFFIX) ++ repl.wait_for_replication(S1, S2) ++ ++ for user in test_users: ++ user.delete() ++ log.info("Deleted 5 test entries") ++ ++ repl.wait_for_replication(S1, S2) ++ ++ domain = Domain(S1, DEFAULT_SUFFIX) ++ for i in range(10): ++ domain.replace("description", f"advancing RUV {i}") ++ repl.wait_for_replication(S1, S2) ++ ++ domain2 = Domain(S2, DEFAULT_SUFFIX) ++ for i in range(10): ++ domain2.replace("description", f"advancing RUV from S2 {i}") ++ repl.wait_for_replication(S2, S1) ++ log.info("RUV advanced on both suppliers") ++ ++ S1.stop() ++ S1.db2index(DEFAULT_BENAME) ++ log.info("Reindex completed on S1") ++ S1.start() ++ ++ replica = Replicas(S1).get(DEFAULT_SUFFIX) ++ replica.replace("nsDS5ReplicaPurgeDelay", "1") ++ replica.replace("nsDS5ReplicaTombstonePurgeInterval", "1") ++ ++ S1.config.loglevel((ErrorLog.REPLICA,), "error") ++ ++ log.info("Waiting for tombstone purge on S1...") ++ tombstones = Tombstones(S1, PEOPLE) ++ for attempt in range(60): ++ time.sleep(2) ++ ts_list = tombstones.list() ++ if len(ts_list) == 0: ++ log.info(f"All tombstones purged after {(attempt + 1) * 2}s") ++ break ++ log.info(f"Attempt {attempt + 1}: {len(ts_list)} tombstones remaining") ++ else: ++ pytest.fail("Tombstones not purged after 120s") ++ ++ S1.deleteErrorLogs() ++ ++ backends = Backends(S1) ++ task = backends.export_ldif(be_names=[DEFAULT_BENAME], include_suffixes=[PEOPLE]) ++ task.wait() ++ assert task.is_complete() ++ assert task.get_exit_code() == 0 ++ ++ log.info("Export after reindex + tombstone purge succeeded") +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 f5127cc66..5138646f6 100644 +--- a/ldap/servers/slapd/back-ldbm/db-bdb/bdb_ldif2db.c ++++ b/ldap/servers/slapd/back-ldbm/db-bdb/bdb_ldif2db.c +@@ -2053,7 +2053,7 @@ bdb_db2index(Slapi_PBlock *pb) + /* + * Update the ancestorid and entryrdn index + */ +- if (!entryrdn_get_noancestorid() && (index_ext & DB2INDEX_ANCESTORID)) { ++ if (!entryrdn_get_noancestorid() && (index_ext & DB2INDEX_ANCESTORID) && !istombstone) { + rc = ldbm_ancestorid_index_entry(be, ep, BE_INDEX_ADD, NULL); + if (rc != 0) { + slapi_log_err(SLAPI_LOG_ERR, +diff --git a/ldap/servers/slapd/back-ldbm/db-mdb/mdb_import_threads.c b/ldap/servers/slapd/back-ldbm/db-mdb/mdb_import_threads.c +index d37f223fd..35965df85 100644 +--- a/ldap/servers/slapd/back-ldbm/db-mdb/mdb_import_threads.c ++++ b/ldap/servers/slapd/back-ldbm/db-mdb/mdb_import_threads.c +@@ -3087,7 +3087,7 @@ process_entryrdn(backentry *ep, WorkerQueueData_t *wqelmnt) + add_update_entry_operational_attributes(ep, 0); + } + +- if (ctx->ancestorid && wqelmnt->entry_info) { ++ if (ctx->ancestorid && wqelmnt->entry_info && wqelmnt->dnrc != DNRC_TOMBSTONE) { + /* Update ancestorids */ + wqd.dbi = ctx->ancestorid->dbi; + for (n=0; nentry_info[INFO_IDX_NB_ANCESTORS]; n++) { +-- +2.54.0 + diff --git a/0006-Issue-7189-DSBLE0007-generates-incorrect-remediation.patch b/0006-Issue-7189-DSBLE0007-generates-incorrect-remediation.patch deleted file mode 100644 index 010e099..0000000 --- a/0006-Issue-7189-DSBLE0007-generates-incorrect-remediation.patch +++ /dev/null @@ -1,235 +0,0 @@ -From c5aab4f8ba822572daa9ef69a0109577bf2147e1 Mon Sep 17 00:00:00 2001 -From: Viktor Ashirov -Date: Tue, 20 Jan 2026 09:52:47 +0100 -Subject: [PATCH] Issue 7189 - DSBLE0007 generates incorrect remediation - commands for scan limits - -Bug Description: - -The generated dsconf commands for fixing missing system indexes had two issues: - -1. The --add-scanlimit value was not quoted, causing the shell to interpret - "limit=5000 type=eq flags=AND" as multiple arguments instead of a single - value, resulting in "unrecognized arguments: type=eq flags=AND" error. - -2. When both matching rule and scanlimit were missing, two separate commands - were generated where the second would fail because the matching rule was - already added by the first command. - -Fix Description: - -1. Quote the scanlimit value in all remediation commands - -2. Combine matching rule and scanlimit fixes into a single command when - both are missing for the same index instead of expected_scanlimit) - -Fixes: https://github.com/389ds/389-ds-base/issues/7189 - -Reviewed by: @progier389, @droideck (Thanks!) ---- - .../healthcheck/health_system_indexes_test.py | 126 ++++++++++++++++++ - src/lib389/lib389/backend.py | 39 +++--- - 2 files changed, 147 insertions(+), 18 deletions(-) - -diff --git a/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py b/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py -index 6293340ca..5eadf6283 100644 ---- a/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py -+++ b/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py -@@ -405,6 +405,132 @@ def test_retrocl_plugin_missing_matching_rule(topology_st, retrocl_plugin_enable - run_healthcheck_and_flush_log(topology_st, standalone, json=True, searched_code=JSON_OUTPUT) - - -+def test_missing_scanlimit(topology_st, log_buffering_enabled): -+ """Check if healthcheck returns DSBLE0007 code when parentId index is missing scanlimit -+ -+ :id: 40e1bf6a-2397-459b-bdf3-f787ca118b86 -+ :setup: Standalone instance -+ :steps: -+ 1. Create DS instance -+ 2. Remove nsIndexIDListScanLimit from parentId index -+ 3. Use healthcheck without --json option -+ 4. Use healthcheck with --json option -+ 5. Verify the remediation command has properly quoted scanlimit -+ 6. Re-add the scanlimit -+ 7. Use healthcheck without --json option -+ 8. Use healthcheck with --json option -+ :expectedresults: -+ 1. Success -+ 2. Success -+ 3. healthcheck reports DSBLE0007 code and related details -+ 4. healthcheck reports DSBLE0007 code and related details -+ 5. The scanlimit value is quoted in the remediation command -+ 6. Success -+ 7. healthcheck reports no issues found -+ 8. healthcheck reports no issues found -+ """ -+ -+ RET_CODE = "DSBLE0007" -+ PARENTID_DN = "cn=parentid,cn=index,cn=userroot,cn=ldbm database,cn=plugins,cn=config" -+ SCANLIMIT_VALUE = "limit=5000 type=eq flags=AND" -+ -+ standalone = topology_st.standalone -+ -+ log.info("Remove nsIndexIDListScanLimit from parentId index") -+ parentid_index = Index(standalone, PARENTID_DN) -+ parentid_index.remove("nsIndexIDListScanLimit", SCANLIMIT_VALUE) -+ -+ run_healthcheck_and_flush_log(topology_st, standalone, json=False, searched_code=RET_CODE) -+ -+ # Verify the remediation command has properly quoted scanlimit -+ args = FakeArgs() -+ args.instance = standalone.serverid -+ args.verbose = standalone.verbose -+ args.list_errors = False -+ args.list_checks = False -+ args.exclude_check = [] -+ args.check = ["backends"] -+ args.dry_run = False -+ args.json = False -+ health_check_run(standalone, topology_st.logcap.log, args) -+ # Check that the scanlimit is quoted in the output -+ assert topology_st.logcap.contains('--add-scanlimit "limit=5000 type=eq flags=AND"') -+ log.info("Verified scanlimit is properly quoted in remediation command") -+ topology_st.logcap.flush() -+ -+ run_healthcheck_and_flush_log(topology_st, standalone, json=True, searched_code=RET_CODE) -+ -+ log.info("Re-add the nsIndexIDListScanLimit") -+ parentid_index = Index(standalone, PARENTID_DN) -+ parentid_index.add("nsIndexIDListScanLimit", SCANLIMIT_VALUE) -+ -+ run_healthcheck_and_flush_log(topology_st, standalone, json=False, searched_code=CMD_OUTPUT) -+ run_healthcheck_and_flush_log(topology_st, standalone, json=True, searched_code=JSON_OUTPUT) -+ -+ -+def test_missing_matching_rule_and_scanlimit(topology_st, log_buffering_enabled): -+ """Check if healthcheck generates a single combined command when both matching rule and scanlimit are missing -+ -+ :id: af8214ad-5e4c-422a-8f74-3e99227551df -+ :setup: Standalone instance -+ :steps: -+ 1. Create DS instance -+ 2. Remove both integerOrderingMatch and nsIndexIDListScanLimit from parentId index -+ 3. Use healthcheck and verify a single combined command is generated -+ 4. Re-add the matching rule and scanlimit -+ 5. Use healthcheck without --json option -+ 6. Use healthcheck with --json option -+ :expectedresults: -+ 1. Success -+ 2. Success -+ 3. healthcheck reports DSBLE0007 and generates a single command with both --add-mr and --add-scanlimit -+ 4. Success -+ 5. healthcheck reports no issues found -+ 6. healthcheck reports no issues found -+ """ -+ -+ RET_CODE = "DSBLE0007" -+ PARENTID_DN = "cn=parentid,cn=index,cn=userroot,cn=ldbm database,cn=plugins,cn=config" -+ SCANLIMIT_VALUE = "limit=5000 type=eq flags=AND" -+ -+ standalone = topology_st.standalone -+ -+ log.info("Remove both integerOrderingMatch and nsIndexIDListScanLimit from parentId index") -+ parentid_index = Index(standalone, PARENTID_DN) -+ parentid_index.remove("nsMatchingRule", "integerOrderingMatch") -+ parentid_index.remove("nsIndexIDListScanLimit", SCANLIMIT_VALUE) -+ -+ # Run healthcheck and verify combined command -+ args = FakeArgs() -+ args.instance = standalone.serverid -+ args.verbose = standalone.verbose -+ args.list_errors = False -+ args.list_checks = False -+ args.exclude_check = [] -+ args.check = ["backends"] -+ args.dry_run = False -+ args.json = False -+ health_check_run(standalone, topology_st.logcap.log, args) -+ -+ # Verify DSBLE0007 is reported -+ assert topology_st.logcap.contains(RET_CODE) -+ log.info("healthcheck returned code: %s" % RET_CODE) -+ -+ # Verify a single combined command is generated with both --add-mr and --add-scanlimit -+ assert topology_st.logcap.contains('--add-mr integerOrderingMatch --add-scanlimit "limit=5000 type=eq flags=AND"') -+ log.info("Verified combined command with both --add-mr and --add-scanlimit") -+ -+ topology_st.logcap.flush() -+ -+ log.info("Re-add the integerOrderingMatch matching rule and scanlimit") -+ parentid_index = Index(standalone, PARENTID_DN) -+ parentid_index.add("nsMatchingRule", "integerOrderingMatch") -+ parentid_index.add("nsIndexIDListScanLimit", SCANLIMIT_VALUE) -+ -+ run_healthcheck_and_flush_log(topology_st, standalone, json=False, searched_code=CMD_OUTPUT) -+ run_healthcheck_and_flush_log(topology_st, standalone, json=True, searched_code=JSON_OUTPUT) -+ -+ - def test_multiple_missing_indexes(topology_st, log_buffering_enabled): - """Check if healthcheck returns DSBLE0007 code when multiple system indexes are missing - -diff --git a/src/lib389/lib389/backend.py b/src/lib389/lib389/backend.py -index 024de2adb..d3c9ccf35 100644 ---- a/src/lib389/lib389/backend.py -+++ b/src/lib389/lib389/backend.py -@@ -678,7 +678,7 @@ class Backend(DSLdapObject): - if expected_config.get('matching_rule'): - cmd += f" --matching-rule {expected_config['matching_rule']}" - if expected_config.get('scanlimit'): -- cmd += f" --add-scanlimit {expected_config['scanlimit']}" -+ cmd += f" --add-scanlimit \"{expected_config['scanlimit']}\"" - remediation_commands.append(cmd) - reindex_attrs.add(attr_name) # New index needs reindexing - else: -@@ -700,28 +700,31 @@ class Backend(DSLdapObject): - remediation_commands.append(cmd) - reindex_attrs.add(attr_name) - -- # Check matching rules -+ # Check matching rules and scanlimit together to generate a single combined command - expected_mr = expected_config.get('matching_rule') -+ expected_scanlimit = expected_config.get('scanlimit') -+ -+ missing_mr = False - if expected_mr: - actual_mrs_lower = [mr.lower() for mr in actual_mrs] - if expected_mr.lower() not in actual_mrs_lower: - discrepancies.append(f"Index {attr_name} missing matching rule: {expected_mr}") -- # Add the missing matching rule -- cmd = f"dsconf YOUR_INSTANCE backend index set {bename} --attr {attr_name} --add-mr {expected_mr}" -- remediation_commands.append(cmd) -- reindex_attrs.add(attr_name) -- -- # Check fine grain definitions for parentid ONLY -- expected_scanlimit = expected_config.get('scanlimit') -- if (attr_name.lower() == "parentid") and expected_scanlimit and (len(actual_scanlimit) == 0): -- discrepancies.append(f"Index {attr_name} missing fine grain definition of IDs limit: {expected_mr}") -- # Add the missing scanlimit -- if expected_mr: -- cmd = f"dsconf YOUR_INSTANCE backend index set {bename} --attr {attr_name} --add-mr {expected_mr} --add-scanlimit {expected_scanlimit}" -- else: -- cmd = f"dsconf YOUR_INSTANCE backend index set {bename} --attr {attr_name} --add-scanlimit {expected_scanlimit}" -- remediation_commands.append(cmd) -- reindex_attrs.add(attr_name) -+ missing_mr = True -+ -+ missing_scanlimit = False -+ if expected_scanlimit and (len(actual_scanlimit) == 0): -+ discrepancies.append(f"Index {attr_name} missing fine grain definition of IDs limit: {expected_scanlimit}") -+ missing_scanlimit = True -+ -+ # Generate a single combined command for all missing items -+ if missing_mr or missing_scanlimit: -+ cmd = f"dsconf YOUR_INSTANCE backend index set {bename} --attr {attr_name}" -+ if missing_mr: -+ cmd += f" --add-mr {expected_mr}" -+ if missing_scanlimit: -+ cmd += f" --add-scanlimit \"{expected_scanlimit}\"" -+ remediation_commands.append(cmd) -+ reindex_attrs.add(attr_name) - - except Exception as e: - self._log.debug(f"_lint_system_indexes - Error checking index {attr_name}: {e}") --- -2.52.0 - diff --git a/0006-Issue-7327-dsctl-healthcheck-DSMOLE0001-inaccurate-r.patch b/0006-Issue-7327-dsctl-healthcheck-DSMOLE0001-inaccurate-r.patch new file mode 100644 index 0000000..828c0eb --- /dev/null +++ b/0006-Issue-7327-dsctl-healthcheck-DSMOLE0001-inaccurate-r.patch @@ -0,0 +1,199 @@ +From af0216be875e3580f5c916c7ca9ab63db4df32f7 Mon Sep 17 00:00:00 2001 +From: James Chapman +Date: Wed, 8 Apr 2026 23:56:15 +0100 +Subject: [PATCH 6/8] Issue 7327 - dsctl healthcheck DSMOLE0001 inaccurate + recommendations with multiple backends (#7328) + +Description: +The dsctl healthcheck tool generates incorrect recommendations for the MO plugin when +multiple backends are present. This commonly occurs in IPA environments where both +userroot and ipaca backends exist. Healthcheck incorrectly suggests indexing attributes +for backends that are not within the MemberOf plugin scope. + +Fix: +Determine the MO plugin scope while iterating over backends and only generate +recommendations for backends that fall within that scope. + +Removed references to nsslapd-plugincontainerscope as we dont use it. + +Fixes: +https://github.com/389ds/389-ds-base/issues/7327 + +Reviewed by: @droideck (Thank you) +--- + .../memberof_include_scopes_test.py | 86 +++++++++++++++++++ + src/lib389/lib389/plugins.py | 30 ++++--- + 2 files changed, 106 insertions(+), 10 deletions(-) + +diff --git a/dirsrvtests/tests/suites/memberof_plugin/memberof_include_scopes_test.py b/dirsrvtests/tests/suites/memberof_plugin/memberof_include_scopes_test.py +index 347eb880f..8cdf94f3c 100644 +--- a/dirsrvtests/tests/suites/memberof_plugin/memberof_include_scopes_test.py ++++ b/dirsrvtests/tests/suites/memberof_plugin/memberof_include_scopes_test.py +@@ -10,6 +10,7 @@ import pytest + import os + import ldap + import time ++from lib389.backend import Backends + from lib389.utils import ensure_str + from lib389.topologies import topology_st as topo + from lib389._constants import * +@@ -17,6 +18,8 @@ from lib389.plugins import MemberOfPlugin, ReferentialIntegrityPlugin + from lib389.idm.user import UserAccount, UserAccounts + from lib389.idm.group import Group, Groups + from lib389.idm.nscontainer import nsContainers ++from lib389.idm.domain import Domain ++from lib389.idm.organizationalunit import OrganizationalUnit + + SUBTREE_1 = 'cn=sub1,%s' % SUFFIX + SUBTREE_2 = 'cn=sub2,%s' % SUFFIX +@@ -131,6 +134,89 @@ def test_multiple_scopes(topo): + assert not group.present("member", INCLUDED_USER) + assert not group.present("member", EXCLUDED_USER) + ++def test_memberof_scope_multiple_backends(topology_st): ++ """Test memberOf plugin correctly handles multiple backends with different scopes ++ ++ :id: 96419128-70a4-4a81-943e-8d1e9c92f241 ++ :setup: Instance with multiple backends ++ :steps: ++ 1. Create out of scope backend ++ 2. Create domain and OU's for out of scope backend ++ 3. Create groups and users in both backends ++ 4. Enable MO plugin and set scope to backend 1 ++ 5. Add users to groups in both backends ++ 6. Verify in scope user has memberOf attr value of in scope group dn ++ 7. Verify out scope user has an empty memberOf attr value ++ :expectedresults: ++ 1. Success ++ 2. Success ++ 3. Success ++ 4. Success ++ 5. Success, trigger MO update ++ 6. Success ++ 7. Success ++ """ ++ inst = topology_st.standalone ++ outscope_suffix = 'dc=other,dc=org' ++ ++ # Create a backend 2 ++ backends = Backends(inst) ++ outscope_be = backends.create(properties={ ++ 'cn': 'testBackend', ++ 'nsslapd-suffix': outscope_suffix ++ }) ++ ++ # Create domain entry for backend 2 ++ domain = Domain(inst, outscope_suffix) ++ domain.create(properties={ ++ 'dc': 'other' ++ }) ++ ++ # Create OUs for backend 2 ++ people_ou = OrganizationalUnit(inst, f'ou=People,{outscope_suffix}') ++ people_ou.create(properties={'ou': 'People'}) ++ groups_ou = OrganizationalUnit(inst, f'ou=Groups,{outscope_suffix}') ++ groups_ou.create(properties={'ou': 'Groups'}) ++ ++ # Create test groups and users ++ inscope_users = UserAccounts(inst, 'dc=example,dc=com') ++ inscope_groups = Groups(inst, 'dc=example,dc=com') ++ inscope_user = inscope_users.create_test_user(uid=1000) ++ inscope_group = inscope_groups.create(properties={'cn': 'testgroup1'}) # NO MEMBERS initially ++ ++ outscope_users = UserAccounts(inst, outscope_suffix) ++ outscope_groups = Groups(inst, outscope_suffix) ++ outscope_user = outscope_users.create_test_user(uid=2000) ++ outscope_group = outscope_groups.create(properties={'cn': 'testgroup2'}) # NO MEMBERS initially ++ ++ # Configure memberof plugin with backend 1 scope ++ memberof = MemberOfPlugin(inst) ++ memberof.enable() ++ memberof.replace('memberOfEntryScope', 'dc=example,dc=com') ++ inst.restart() ++ ++ # Trigger memberof processing ++ inscope_group.add('member', inscope_user.dn) ++ outscope_group.add('member', outscope_user.dn) ++ ++ # Sleep for a bit ++ time.sleep(2) ++ ++ # In scope user should have memberOf attribute ++ inscope_user_entry = inscope_user.get_attrs_vals_utf8(['memberOf']) ++ assert inscope_user_entry['memberOf'] == [inscope_group.dn] ++ ++ # Out of scope user should not have memberOf attribute ++ outscope_user_entry = outscope_user.get_attrs_vals_utf8(['memberOf']) ++ assert outscope_user_entry['memberOf'] == [] ++ ++ # Cleanup ++ inscope_group.delete() ++ inscope_user.delete() ++ outscope_group.delete() ++ outscope_user.delete() ++ outscope_be.delete() ++ + if __name__ == '__main__': + # Run isolated + # -s for DEBUG mode +diff --git a/src/lib389/lib389/plugins.py b/src/lib389/lib389/plugins.py +index 483d86659..0c0148119 100644 +--- a/src/lib389/lib389/plugins.py ++++ b/src/lib389/lib389/plugins.py +@@ -794,16 +794,21 @@ class MemberOfPlugin(Plugin): + from lib389.backend import Backends + backends = Backends(self._instance).list() + attrs = self.get_attr_vals_utf8_l("memberofgroupattr") +- container = self.get_attr_val_utf8_l("nsslapd-plugincontainerscope") ++ scopes = self.get_attr_vals_utf8_l("memberofentryscope") + for backend in backends: + suffix = backend.get_attr_val_utf8_l('nsslapd-suffix') + 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 ++ if scopes: ++ # Is this backend suffix in scope ++ in_scope = False ++ for scope in scopes: ++ if scope.endswith(suffix) or suffix.endswith(scope): ++ in_scope = True ++ break ++ ++ if not in_scope: + continue + indexes = backend.get_indexes() + for attr in attrs: +@@ -842,16 +847,21 @@ class MemberOfPlugin(Plugin): + from lib389.backend import Backends + backends = Backends(self._instance).list() + membership_attrs = ['member', 'uniquemember'] +- container = self.get_attr_val_utf8_l("nsslapd-plugincontainerscope") ++ scopes = self.get_attr_vals_utf8_l("memberofentryscope") + for backend in backends: + suffix = backend.get_attr_val_utf8_l('nsslapd-suffix') + 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 ++ if scopes: ++ # Is this backend suffix in scope ++ in_scope = False ++ for scope in scopes: ++ if scope.endswith(suffix) or suffix.endswith(scope): ++ in_scope = True ++ break ++ ++ if not in_scope: + continue + indexes = backend.get_indexes() + for attr in membership_attrs: +-- +2.54.0 + diff --git a/0007-Issue-7184-argparse.HelpFormatter-_format_actions_us.patch b/0007-Issue-7184-argparse.HelpFormatter-_format_actions_us.patch deleted file mode 100644 index 8b06dee..0000000 --- a/0007-Issue-7184-argparse.HelpFormatter-_format_actions_us.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 327ebf93decaa19bd3919afaeba0dc122eef1990 Mon Sep 17 00:00:00 2001 -From: Mark Reynolds -Date: Mon, 12 Jan 2026 13:53:05 -0500 -Subject: [PATCH] Issue 7184 - argparse.HelpFormatter _format_actions_usage() - is deprecated - -Description: - -_format_actions_usage() was removed in python 3.15. Instead we can use -_get_actions_usage_parts() but it also behaves differently between -python 3.14 and 3.15 so we need special handling. - -Relates: https://github.com/389ds/389-ds-base/issues/7184 - -Reviewed by: spichugi(Thanks!) ---- - src/lib389/lib389/cli_base/__init__.py | 15 ++++++++++++++- - 1 file changed, 14 insertions(+), 1 deletion(-) - -diff --git a/src/lib389/lib389/cli_base/__init__.py b/src/lib389/lib389/cli_base/__init__.py -index 06b8f9964..f1055aadc 100644 ---- a/src/lib389/lib389/cli_base/__init__.py -+++ b/src/lib389/lib389/cli_base/__init__.py -@@ -413,7 +413,20 @@ class CustomHelpFormatter(argparse.HelpFormatter): - - def _format_usage(self, usage, actions, groups, prefix): - usage = super(CustomHelpFormatter, self)._format_usage(usage, actions, groups, prefix) -- formatted_options = self._format_actions_usage(parent_arguments, []) -+ -+ if sys.version_info < (3, 13): -+ # Use _format_actions_usage() for Python 3.12 and earlier -+ formatted_options = self._format_actions_usage(parent_arguments, []) -+ else: -+ # Use _get_actions_usage_parts() for Python 3.13 and later -+ action_parts = self._get_actions_usage_parts(parent_arguments, []) -+ if sys.version_info >= (3, 15): -+ # Python 3.15 returns a tuple (list of actions, count of actions) -+ formatted_options = ' '.join(action_parts[0]) -+ else: -+ # Python 3.13 and 3.14 return a list of actions -+ formatted_options = ' '.join(action_parts) -+ - # If formatted_options already in usage - remove them - if formatted_options in usage: - usage = usage.replace(f' {formatted_options}', '') --- -2.52.0 - diff --git a/0007-Issue-7267-MDB_BAD_VALSIZE-error-when-updating-index.patch b/0007-Issue-7267-MDB_BAD_VALSIZE-error-when-updating-index.patch new file mode 100644 index 0000000..034bc4d --- /dev/null +++ b/0007-Issue-7267-MDB_BAD_VALSIZE-error-when-updating-index.patch @@ -0,0 +1,651 @@ +From 50ee439bb1d2e2344ea8cef076d54585204d9fbb Mon Sep 17 00:00:00 2001 +From: progier389 +Date: Wed, 25 Feb 2026 18:00:24 +0100 +Subject: [PATCH 7/8] Issue 7267 - MDB_BAD_VALSIZE error when updating index + (#7268) + +* Issue 7267 - MDB_BAD_VALSIZE error when updating index +* Improve import log when writer fails +* Fix Sourcery AI comments +* Fix INDEX_KEY_LENGTH typo + +Problem with the key prefix handling when key is too long and must be hashed. +The issue is that the # that is prepended is not reset when iterating over the valueset values (Ending up with very long prefix) + +Also refactored the code to avoid duplicate the code that prepare the key from the attribute value (used when updating the index or retrieving a value from an index) + +Issue: #7267 + +Reviewed by: @tbordaz , @vashirov (Thanks!) + +Co-authored-by: Viktor Ashirov + +--------- + +Co-authored-by: Viktor Ashirov +--- + .../tests/suites/indexes/regression_test.py | 58 +++++++ + ldap/servers/slapd/back-ldbm/attrcrypt.h | 2 +- + ldap/servers/slapd/back-ldbm/back-ldbm.h | 2 + + .../slapd/back-ldbm/db-bdb/bdb_import.c | 39 +---- + .../back-ldbm/db-mdb/mdb_import_threads.c | 46 ++++- + ldap/servers/slapd/back-ldbm/index.c | 161 +++++++----------- + ldap/servers/slapd/back-ldbm/ldbm_attrcrypt.c | 13 +- + .../servers/slapd/back-ldbm/proto-back-ldbm.h | 2 +- + ldap/servers/slapd/log.c | 40 +++++ + ldap/servers/slapd/slapi-private.h | 2 + + 10 files changed, 221 insertions(+), 144 deletions(-) + +diff --git a/dirsrvtests/tests/suites/indexes/regression_test.py b/dirsrvtests/tests/suites/indexes/regression_test.py +index e2c2f5c35..53d340cdd 100644 +--- a/dirsrvtests/tests/suites/indexes/regression_test.py ++++ b/dirsrvtests/tests/suites/indexes/regression_test.py +@@ -699,6 +699,64 @@ def test_idl_range_limit(topo, add_some_entries): + assert len(entries) == 3 + + ++def test_large_multivalued_sn_attribute(topo): ++ """Test adding a user entry with 512 values for sn attribute, each 512 bytes ++ ++ :id: 8f2a9b3c-e8d7-11ef-9a5f-482ae39447e5 ++ :setup: Standalone Instance ++ :steps: ++ 1. Create a user with 512 sn values, each 512 bytes long ++ 2. Verify the user was created successfully ++ 3. Search for the user and verify all sn values are present ++ 4. Clean up the user entry ++ :expectedresults: ++ 1. User is created successfully ++ 2. User entry exists ++ 3. All 512 sn values are present and have correct length ++ 4. User is deleted successfully ++ """ ++ ++ inst = topo.standalone ++ users = UserAccounts(inst, DEFAULT_SUFFIX) ++ ++ log.info("Creating user with 512 sn values, each 512 bytes") ++ ++ # Generate 512 unique sn values, each 512 bytes long ++ # Use a pattern that makes each value unique but predictable ++ sn_values = [] ++ for i in range(512): ++ # Create a 512-byte value with unique identifier at the start ++ value = f'sn_value_{i:04d}_' + 'x' * (512 - len(f'sn_value_{i:04d}_')) ++ sn_values.append(value) ++ ++ # Create the user with first sn value ++ user_name = 'test_user_large_sn' ++ user = users.create(properties={ ++ 'uid': user_name, ++ 'cn': user_name, ++ 'sn': sn_values, ++ 'uidNumber': '99999', ++ 'gidNumber': '99999', ++ 'homeDirectory': f'/home/{user_name}' ++ }) ++ ++ # Verify the entry was created and has all sn values ++ log.info("Verifying all sn values are present") ++ sn_attr_values = user.get_attr_vals_utf8('sn') ++ ++ assert len(sn_attr_values) == 512, f"Expected 512 sn values, got {len(sn_attr_values)}" ++ ++ # Verify each value has the correct length ++ for idx, value in enumerate(sn_attr_values): ++ assert len(value) == 512, f"sn value {idx} has length {len(value)}, expected 512" ++ ++ log.info("Successfully created and verified user with 512 sn values of 512 bytes each") ++ ++ # Clean up ++ user.delete() ++ log.info("User entry deleted successfully") ++ ++ + if __name__ == "__main__": + # Run isolated + # -s for DEBUG mode +diff --git a/ldap/servers/slapd/back-ldbm/attrcrypt.h b/ldap/servers/slapd/back-ldbm/attrcrypt.h +index d653ba951..dcbea80fe 100644 +--- a/ldap/servers/slapd/back-ldbm/attrcrypt.h ++++ b/ldap/servers/slapd/back-ldbm/attrcrypt.h +@@ -10,7 +10,7 @@ + #include + #endif + +-/* Private tructures and #defines used in the attribute encryption code. */ ++/* Private structures and #defines used in the attribute encryption code. */ + + #ifndef _ATTRCRYPT_H_ + #define _ATTRCRYPT_H_ +diff --git a/ldap/servers/slapd/back-ldbm/back-ldbm.h b/ldap/servers/slapd/back-ldbm/back-ldbm.h +index 70f532538..f77924f1a 100644 +--- a/ldap/servers/slapd/back-ldbm/back-ldbm.h ++++ b/ldap/servers/slapd/back-ldbm/back-ldbm.h +@@ -104,6 +104,8 @@ typedef unsigned short u_int16_t; + */ + #define BE_CHANGELOG_FILE "replication_changelog" + ++#define INDEX_KEY_LENGTH(lenval,lenprefix) (lenval+lenprefix+2) ++ + #define BDB_IMPL "bdb" + #define BDB_BACKEND "libback-ldbm" /* This backend plugin */ + #define BDB_NEWIDL "newidl" /* new idl format */ +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 59a472f58..bdc4ee4f6 100644 +--- a/ldap/servers/slapd/back-ldbm/db-bdb/bdb_import.c ++++ b/ldap/servers/slapd/back-ldbm/db-bdb/bdb_import.c +@@ -75,9 +75,9 @@ static IDList *bdb_idl_union_allids(backend *be, struct attrinfo *ai, IDList *a, + #define DEBUG_SUBCOUNT_MSG(msg, ...) { debug_subcount(__FUNCTION__, __LINE__, (msg), __VA_ARGS__); } + #define DUMP_SUBCOUNT_KEY(msg, key, ret) { debug_subcount(__FUNCTION__, __LINE__, "ret=%d size=%u ulen=%u doff=%u dlen=%u", \ + ret, (key).size, (key).ulen, (key).doff, (key).dlen); \ +- if (ret == 0) hexadump(msg, (key).data, 0, (key).size); \ ++ if (ret == 0) slapi_log_hexadump(SLAPI_LOG_INFO, msg, (key).data, (key).size); \ + else if (ret == DB_BUFFER_SMALL) \ +- hexadump(msg, (key).data, 0, (key).ulen); } ++ slapi_log_hexadump(SLAPI_LOG_INFO, msg, (key).data, (key).ulen); } + + static void + debug_subcount(const char *funcname, int line, char *msg, ...) +@@ -90,41 +90,6 @@ debug_subcount(const char *funcname, int line, char *msg, ...) + slapi_log_err(SLAPI_LOG_INFO, (char*)funcname, "DEBUG SUBCOUNT [%d] %s\n", line, buff); + } + +-/* +- * Dump a memory buffer in hexa and ascii in error log +- * +- * addr - The memory buffer address. +- * len - The memory buffer lenght. +- */ +-static void +-hexadump(char *msg, const void *addr, size_t offset, size_t len) +-{ +-#define HEXADUMP_TAB 4 +-/* 4 characters per bytes: 2 hexa digits, 1 space and the ascii */ +-#define HEXADUMP_BUF_SIZE (4*16+HEXADUMP_TAB) +- char hexdigit[] = "0123456789ABCDEF"; +- +- const unsigned char *pt = addr; +- char buff[HEXADUMP_BUF_SIZE+1]; +- memset (buff, ' ', HEXADUMP_BUF_SIZE); +- buff[HEXADUMP_BUF_SIZE] = '\0'; +- while (len > 0) { +- int dpl; +- for (dpl = 0; dpl < 16 && len>0; dpl++, len--) { +- buff[3*dpl] = hexdigit[((*pt) >> 4) & 0xf]; +- buff[3*dpl+1] = hexdigit[(*pt) & 0xf]; +- buff[3*16+HEXADUMP_TAB+dpl] = (*pt>=0x20 && *pt<0x7f) ? *pt : '.'; +- pt++; +- } +- for (;dpl < 16; dpl++) { +- buff[3*dpl] = ' '; +- buff[3*dpl+1] = ' '; +- buff[3*16+HEXADUMP_TAB+dpl] = ' '; +- } +- slapi_log_err(SLAPI_LOG_INFO, msg, "[0x%08lx] %s\n", offset, buff); +- offset += 16; +- } +-} + #else + #define DEBUG_SUBCOUNT_MSG(msg, ...) + #define DUMP_SUBCOUNT_KEY(msg, key, ret) +diff --git a/ldap/servers/slapd/back-ldbm/db-mdb/mdb_import_threads.c b/ldap/servers/slapd/back-ldbm/db-mdb/mdb_import_threads.c +index 35965df85..c49412a70 100644 +--- a/ldap/servers/slapd/back-ldbm/db-mdb/mdb_import_threads.c ++++ b/ldap/servers/slapd/back-ldbm/db-mdb/mdb_import_threads.c +@@ -1122,6 +1122,21 @@ dbmdb_import_entry_info_by_backentry(mdb_privdb_t *db, BulkQueueData_t *bqdata, + return dnrc; + } + ++/* Log wqelmt details */ ++void ++log_wqelmt(int loglvl, char *fname, WorkerQueueData_t *wqelmt) ++{ ++ if (wqelmt->dn) { ++ slapi_log_err(loglvl, fname, "log_wqelmt: dn=%s\n", wqelmt->dn); ++ } ++ if (wqelmt->filename && wqelmt->lineno) { ++ slapi_log_err(loglvl, fname, "log_wqelmt: ldif=%s[%d]\n", wqelmt->filename, wqelmt->lineno); ++ } ++ if (wqelmt->data) { ++ size_t len = wqelmt->datalen ? wqelmt->datalen : strlen(wqelmt->data); ++ slapi_log_hexadump(loglvl, "log_wqelmt:data", wqelmt->data, len); ++ } ++} + + /* producer thread for ldif import case: + * read through the given file list, parsing entries (str2entry), assigning +@@ -1255,6 +1270,7 @@ dbmdb_import_producer(void *param) + import_log_notice(job, SLAPI_LOG_ERR, "dbmdb_import_producer", + "ns_slapd software error: unexpected dbmdb_import_entry_info return code: %d.", + wqelmt.dnrc); ++ log_wqelmt(SLAPI_LOG_ERR, "dbmdb_import_producer", &wqelmt); + abort(); + case DNRC_OK: + case DNRC_SUFFIX: +@@ -1761,6 +1777,7 @@ dbmdb_index_producer(void *param) + import_log_notice(job, SLAPI_LOG_ERR, "dbmdb_index_producer", + "ns_slapd software error: unexpected dbmdb_import_entry_info return code: %d.", + tmpslot.dnrc); ++ log_wqelmt(SLAPI_LOG_ERR, "dbmdb_index_producer", &tmpslot); + abort(); + case DNRC_OK: + case DNRC_SUFFIX: +@@ -3951,10 +3968,24 @@ dbmdb_import_writer(void*param) + if (!txn) { + MDB_STAT_STEP(stats, MDB_STAT_TXNSTART); + rc = TXN_BEGIN(ctx->ctx->env, NULL, 0, &txn); ++ if (rc) { ++ slapi_log_err(SLAPI_LOG_ERR, "dbmdb_import_writer", ++ "Failed to begin a txn. Error is 0x%x: %s.\n", ++ rc, mdb_strerror(rc)); ++ } + } + if (!rc) { + MDB_STAT_STEP(stats, MDB_STAT_WRITE); + rc = MDB_PUT(txn, slot->dbi->dbi, &slot->key, &slot->data, 0); ++ if (rc) { ++ slapi_log_err(SLAPI_LOG_ERR, "dbmdb_import_writer", ++ "Failed to write record in dbi %s. Error is 0x%x: %s.\n", ++ slot->dbi->dbname, rc, mdb_strerror(rc)); ++ slapi_log_hexadump(SLAPI_LOG_ERR, "dbmdb_import_writer:key", ++ slot->key.mv_data, slot->key.mv_size); ++ slapi_log_hexadump(SLAPI_LOG_ERR, "dbmdb_import_writer:data", ++ slot->data.mv_data, slot->data.mv_size); ++ } + } + MDB_STAT_STEP(stats, MDB_STAT_RUN); + nextslot = slot->next; +@@ -3968,6 +3999,9 @@ dbmdb_import_writer(void*param) + rc = TXN_COMMIT(txn); + MDB_STAT_STEP(stats, MDB_STAT_RUN); + if (rc) { ++ slapi_log_err(SLAPI_LOG_ERR, "dbmdb_import_writer", ++ "Failed to commit the txn. Error is 0x%x: %s.\n", ++ rc, mdb_strerror(rc)); + break; + } + count = 0; +@@ -3980,6 +4014,10 @@ dbmdb_import_writer(void*param) + MDB_STAT_STEP(stats, MDB_STAT_RUN); + if (!rc) { + txn = NULL; ++ } else { ++ slapi_log_err(SLAPI_LOG_ERR, "dbmdb_import_writer", ++ "Failed to commit the txn. Error is 0x%x: %s.\n", ++ rc, mdb_strerror(rc)); + } + } + if (txn) { +@@ -3992,13 +4030,17 @@ dbmdb_import_writer(void*param) + if (!rc) { + /* Ensure that all data are written on disk */ + rc = mdb_env_sync(ctx->ctx->env, 1); ++ if (rc) { ++ slapi_log_err(SLAPI_LOG_ERR, "dbmdb_import_writer", ++ "mdb_env_sync failed. Error is 0x%x: %s.\n", ++ rc, mdb_strerror(rc)); ++ } + } + MDB_STAT_END(stats); + + if (rc) { + slapi_log_err(SLAPI_LOG_ERR, "dbmdb_import_writer", +- "Failed to write in the database. Error is 0x%x: %s.\n", +- rc, mdb_strerror(rc)); ++ "Aborting import after failure.\n"); + thread_abort(info); + } else { + char buf[200]; +diff --git a/ldap/servers/slapd/back-ldbm/index.c b/ldap/servers/slapd/back-ldbm/index.c +index ca3a866bb..3bdf8926b 100644 +--- a/ldap/servers/slapd/back-ldbm/index.c ++++ b/ldap/servers/slapd/back-ldbm/index.c +@@ -891,6 +891,67 @@ index_read( + return index_read_ext(be, (char *)type, indextype, val, txn, err, NULL); + } + ++/* Prepare an index key (hashed if too long, encrypted if needed from attribute value */ ++int ++prepare_key(backend *be, struct attrinfo *a, char **buf, size_t *buflen, ++ int flags, const char *prefix, const struct berval *bvp, dbi_val_t *key) ++{ ++ /* Key format is [Hash?] [prefix] [val] [\0] */ ++ struct ldbminfo *li = (struct ldbminfo *)be->be_database->plg_private; ++ size_t plen = strlen(prefix); ++ struct berval *hashed_bvp = NULL; ++ struct berval *encrypted_bvp = NULL; ++ int rc = 0; ++ ++ /* Hash large index key if necessary */ ++ if (INDEX_KEY_LENGTH(bvp->bv_len,plen) >= li->li_max_key_len) { ++ rc = attrcrypt_hash_large_index_key(be, prefix, a, bvp, &hashed_bvp); ++ if (rc) { ++ slapi_log_err(SLAPI_LOG_ERR, "index_read_ext_allids", ++ "Failed to hash large index key for %s\n", a->ai_type); ++ return rc; ++ } else { ++ bvp = hashed_bvp; ++ } ++ } ++ ++ /* Encrypt the index key if necessary */ ++ if (rc == 0 && a->ai_attrcrypt && (0 == (flags & BE_INDEX_DONT_ENCRYPT))) { ++ rc = attrcrypt_encrypt_index_key(be, a, bvp, &encrypted_bvp); ++ if (rc) { ++ slapi_log_err(SLAPI_LOG_ERR, "addordel_values_sv", ++ "Failed to encrypt index key for %s\n", a->ai_type); ++ } else { ++ bvp = encrypted_bvp; ++ } ++ } ++ if (hashed_bvp) { ++ prefix = slapi_ch_smprintf("%c%s",HASH_PREFIX, prefix); ++ plen++; ++ } ++ if (buf && buflen) { ++ if (plen+bvp->bv_len+1 > *buflen) { ++ *buflen = plen+bvp->bv_len+1; ++ *buf = slapi_ch_realloc(*buf, *buflen); ++ } ++ dblayer_value_concat(be, key, *buf, *buflen, prefix, plen, bvp->bv_val, bvp->bv_len, "", 1); ++ } else { ++ dblayer_value_concat(be, key, NULL, 0, prefix, plen, bvp->bv_val, bvp->bv_len, "", 1); ++ } ++ ++ if (hashed_bvp) { ++ ber_bvfree(hashed_bvp); ++ hashed_bvp = NULL; ++ slapi_ch_free_string((char**)&prefix); ++ } ++ if (encrypted_bvp) { ++ ber_bvfree(encrypted_bvp); ++ encrypted_bvp = NULL; ++ } ++ return rc; ++} ++ ++ + /* + * Extended version of index_read. + * The unindexed flag can be used to distinguish between a +@@ -927,7 +988,6 @@ index_read_ext_allids( + struct berval *hashed_val = NULL; + int is_and = 0; + unsigned int ai_flags = 0; +- struct ldbminfo *li = (struct ldbminfo *)be->be_database->plg_private; + + *err = 0; + +@@ -1038,36 +1098,7 @@ index_read_ext_allids( + } + + if (val != NULL) { +- size_t vlen; +- int ret = 0; +- +- /* If necessary, hash this index key */ +- if (val->bv_len >= li->li_max_key_len) { +- ret = attrcrypt_hash_large_index_key(be, &prefix, ai, val, &hashed_val); +- if (ret) { +- slapi_log_err(SLAPI_LOG_ERR, "index_read_ext_allids", +- "Failed to hash large index key for %s\n", basetype); +- *err = DBI_RC_OTHER; +- index_free_prefix(prefix); +- slapi_ch_free_string(&basetmp); +- return (NULL); +- } +- if (hashed_val) { +- val = hashed_val; +- } +- } +- /* If necessary, encrypt this index key */ +- ret = attrcrypt_encrypt_index_key(be, ai, val, &encrypted_val); +- if (ret) { +- slapi_log_err(SLAPI_LOG_ERR, "index_read_ext_allids", +- "Failed to encrypt index key for %s\n", basetype); +- } +- if (encrypted_val) { +- val = encrypted_val; +- } +- vlen = val->bv_len; +- dblayer_value_concat(be, &key, buf, sizeof(buf), +- prefix, strlen(prefix), val->bv_val, vlen, "", 1); ++ (void) prepare_key(be, ai, NULL, 0, 0, prefix, val, &key); + } else { + dblayer_value_concat(be, &key, buf, sizeof(buf), prefix, strlen(prefix), + "", 1, NULL, 0); +@@ -1867,6 +1898,7 @@ index_range_read( + return index_range_read_ext(pb, be, type, indextype, operator, val, nextval, range, txn, err, 0); + } + ++ + static int + addordel_values_sv( + backend *be, +@@ -1885,15 +1917,10 @@ addordel_values_sv( + int i = 0; + dbi_val_t key = {0}; + dbi_txn_t *db_txn = NULL; +- size_t plen, vlen, len; + char *tmpbuf = NULL; + size_t tmpbuflen = 0; +- char *realbuf; + char *prefix = NULL; + const struct berval *bvp; +- struct berval *hashed_bvp = NULL; +- struct berval *encrypted_bvp = NULL; +- struct ldbminfo *li = (struct ldbminfo *)be->be_database->plg_private; + char *index_id = get_index_name(be, db, a); + + slapi_log_err(SLAPI_LOG_TRACE, "addordel_values_sv", "%s_values\n", +@@ -1932,66 +1959,14 @@ addordel_values_sv( + return (rc); + } + +- plen = strlen(prefix); + for (i = 0; vals[i] != NULL; i++) { + bvp = slapi_value_get_berval(vals[i]); + +- /* Hash large index key if necessary */ +- if (bvp->bv_len >= li->li_max_key_len) { +- rc = attrcrypt_hash_large_index_key(be, &prefix, a, bvp, &hashed_bvp); +- if (rc) { +- slapi_log_err(SLAPI_LOG_ERR, "index_read_ext_allids", +- "Failed to hash large index key for %s\n", a->ai_type); +- break; +- } else { +- bvp = hashed_bvp; +- plen = strlen(prefix); +- } +- } +- /* Encrypt the index key if necessary */ +- { +- if (a->ai_attrcrypt && (0 == (flags & BE_INDEX_DONT_ENCRYPT))) { +- rc = attrcrypt_encrypt_index_key(be, a, bvp, &encrypted_bvp); +- if (rc) { +- slapi_log_err(SLAPI_LOG_ERR, "addordel_values_sv", +- "Failed to encrypt index key for %s\n", a->ai_type); +- } else { +- bvp = encrypted_bvp; +- } +- } ++ rc = prepare_key(be, a, &tmpbuf, &tmpbuflen, flags, prefix, bvp, &key); ++ if (rc) { ++ break; + } + +- vlen = bvp->bv_len; +- len = plen + vlen; +- +- if (len < tmpbuflen) { +- realbuf = tmpbuf; +- } else { +- tmpbuf = slapi_ch_realloc(tmpbuf, len + 1); +- tmpbuflen = len + 1; +- realbuf = tmpbuf; +- } +- +- assert(realbuf); /* For coverity */ +- memcpy(realbuf, prefix, plen); +- memcpy(realbuf + plen, bvp->bv_val, vlen); +- realbuf[len] = '\0'; +- /* Free the encrypted berval if necessary */ +- if (hashed_bvp) { +- ber_bvfree(hashed_bvp); +- hashed_bvp = NULL; +- } +- if (encrypted_bvp) { +- ber_bvfree(encrypted_bvp); +- encrypted_bvp = NULL; +- } +- /* should be okay to use USERMEM here because we know what +- * the key is and it should never return a different value +- * than the one we pass in. +- */ +- dblayer_value_set_buffer(be, &key, realbuf, plen + vlen + 1); +- key.ulen = tmpbuflen; +- + if (slapi_is_loglevel_set(LDAP_DEBUG_TRACE)) { + char encbuf[BUFSIZ]; + +@@ -2024,10 +1999,6 @@ addordel_values_sv( + ldbm_nasty(NASTY_MSG("addordel_values_sv"), index_id, 1130, rc); + break; + } +- if (NULL != key.dptr && realbuf != key.dptr) { /* realloc'ed */ +- tmpbuf = key.dptr; +- tmpbuflen = key.size; +- } + } + index_free_prefix(prefix); + if (tmpbuf != NULL) { +diff --git a/ldap/servers/slapd/back-ldbm/ldbm_attrcrypt.c b/ldap/servers/slapd/back-ldbm/ldbm_attrcrypt.c +index 3b86a5dd7..14b3b9ce2 100644 +--- a/ldap/servers/slapd/back-ldbm/ldbm_attrcrypt.c ++++ b/ldap/servers/slapd/back-ldbm/ldbm_attrcrypt.c +@@ -1065,15 +1065,15 @@ attrcrypt_decrypt_index_key(backend *be, + * : NULL - no hash or failure + */ + int +-attrcrypt_hash_large_index_key(backend *be, char **prefix, struct attrinfo *ai, const struct berval *in, struct berval **out) ++attrcrypt_hash_large_index_key(backend *be, const char *prefix, struct attrinfo *ai, const struct berval *in, struct berval **out) + { + int ret = 0; + struct berval *out_berval = NULL; + struct ldbminfo *li = (struct ldbminfo *)be->be_database->plg_private; +- char *new_prefix; ++ size_t final_key_len = INDEX_KEY_LENGTH(in->bv_len, strlen(prefix)); + + /* If the index key is too long (i.e mdb case) we must hash it */ +- if (in->bv_len >= li->li_max_key_len) { ++ if (final_key_len >= li->li_max_key_len) { + PK11Context *c = PK11_CreateDigestContext(SEC_OID_MD5); + if (c != NULL) { + unsigned char hash[32]; +@@ -1087,16 +1087,13 @@ attrcrypt_hash_large_index_key(backend *be, char **prefix, struct attrinfo *ai, + return ENOMEM; + } + slapi_log_err(SLAPI_LOG_TRACE, "attrcrypt_hash_large_index_key", +- "Key lenght (%lu) >= max key lenght (%lu) so key must be hashed\n", in->bv_len, li->li_max_key_len); ++ "Key lenght (%lu) >= max key lenght (%lu) so key must be hashed\n", final_key_len, li->li_max_key_len); + slapi_be_set_flag(be, SLAPI_BE_FLAG_DONT_BYPASS_FILTERTEST); + PK11_DigestBegin(c); + /* Compute hash for the key without the prefix */ + PK11_DigestOp(c, (unsigned char *)in->bv_val, in->bv_len); + PK11_DigestFinal(c, hash, &hashLen, sizeof hash); +- /* Add HASH_PREFIX before the prefix */ +- new_prefix = slapi_ch_smprintf("%c%s", HASH_PREFIX, *prefix); +- index_free_prefix(*prefix); +- *prefix = new_prefix; ++ + /* Build the key: hash value in hexa */ + hkey = slapi_ch_malloc(1+2*sizeof hash); + out_berval->bv_val = hkey; +diff --git a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h +index 8754a4847..1884da603 100644 +--- a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h ++++ b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h +@@ -620,7 +620,7 @@ int attrcrypt_encrypt_entry_inplace(backend *be, const struct backentry *inout); + int attrcrypt_encrypt_entry(backend *be, const struct backentry *in, struct backentry **out); + int attrcrypt_encrypt_index_key(backend *be, struct attrinfo *ai, const struct berval *in, struct berval **out); + int attrcrypt_decrypt_index_key(backend *be, struct attrinfo *ai, const struct berval *in, struct berval **out); +-int attrcrypt_hash_large_index_key(backend *be, char **prefix, struct attrinfo *ai, const struct berval *in, struct berval **out); ++int attrcrypt_hash_large_index_key(backend *be, const char *prefix, struct attrinfo *ai, const struct berval *in, struct berval **out); + int attrcrypt_init(ldbm_instance *li); + int attrcrypt_cleanup_private(ldbm_instance *li); + +diff --git a/ldap/servers/slapd/log.c b/ldap/servers/slapd/log.c +index ca8d481e5..17c7bbb7d 100644 +--- a/ldap/servers/slapd/log.c ++++ b/ldap/servers/slapd/log.c +@@ -92,6 +92,10 @@ static int slapi_log_map[] = { + #define SLAPI_LOG_MAX SLAPI_LOG_DEBUG /* from slapi-plugin.h */ + #define LOG_CHUNK 16384 /* zlib compression */ + ++#define HEXADUMP_TAB 4 ++/* 4 characters per bytes: 2 hexa digits, 1 space and the ascii */ ++#define HEXADUMP_BUF_SIZE (4*16+HEXADUMP_TAB) ++ + /************************************************************************** + * PROTOTYPES + *************************************************************************/ +@@ -3065,6 +3069,42 @@ slapi_log_backtrace(int loglevel) + } + } + ++/* ++ * Dump a memory buffer in hexa and ascii in error log ++ * ++ * addr - The memory buffer address. ++ * len - The memory buffer lenght. ++ */ ++void ++slapi_log_hexadump(int loglevel, char *fname, const void *addr, size_t len) ++{ ++ char hexdigit[] = "0123456789ABCDEF"; ++ const unsigned char *pt = addr; ++ char buff[HEXADUMP_BUF_SIZE+1]; ++ size_t offset = 0; ++ ++ if (!slapi_is_loglevel_set(loglevel)) { ++ return; ++ } ++ memset (buff, ' ', HEXADUMP_BUF_SIZE); ++ buff[HEXADUMP_BUF_SIZE] = '\0'; ++ while (len > 0) { ++ int dpl; ++ for (dpl = 0; dpl < 16 && len>0; dpl++, len--) { ++ buff[3*dpl] = hexdigit[((*pt) >> 4) & 0xf]; ++ buff[3*dpl+1] = hexdigit[(*pt) & 0xf]; ++ buff[3*16+HEXADUMP_TAB+dpl] = (*pt>=0x20 && *pt<0x7f) ? *pt : '.'; ++ pt++; ++ } ++ for (;dpl < 16; dpl++) { ++ buff[3*dpl] = ' '; ++ buff[3*dpl+1] = ' '; ++ buff[3*16+HEXADUMP_TAB+dpl] = ' '; ++ } ++ slapi_log_err(loglevel, fname, "[0x%08lx] %s\n", offset, buff); ++ offset += 16; ++ } ++} + + /****************************************************************************** + * write in the access log +diff --git a/ldap/servers/slapd/slapi-private.h b/ldap/servers/slapd/slapi-private.h +index a55ea3ee1..97eed5a9b 100644 +--- a/ldap/servers/slapd/slapi-private.h ++++ b/ldap/servers/slapd/slapi-private.h +@@ -1527,6 +1527,8 @@ void slapi_pblock_set_task_warning(Slapi_PBlock *pb, task_warning warning); + int slapi_exists_or_add_internal(Slapi_DN *dn, const char *filter, const char *entry, const char *modifier_name); + + void slapi_log_backtrace(int loglevel); ++void slapi_log_hexadump(int loglevel, char *fname, const void *addr, size_t len); ++ + + #ifdef __cplusplus + } +-- +2.54.0 + diff --git a/0008-Fix-test389-imports-on-older-branches.patch b/0008-Fix-test389-imports-on-older-branches.patch new file mode 100644 index 0000000..5230767 --- /dev/null +++ b/0008-Fix-test389-imports-on-older-branches.patch @@ -0,0 +1,39 @@ +From 853d11cd6abc69a8e93172771b19b52950293e6f Mon Sep 17 00:00:00 2001 +From: Viktor Ashirov +Date: Fri, 5 Jun 2026 11:17:35 +0200 +Subject: [PATCH 8/8] Fix test389 imports on older branches + +--- + dirsrvtests/tests/suites/basic/modrdn_bulk_children_test.py | 2 +- + dirsrvtests/tests/suites/features/ldap_controls_test.py | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/dirsrvtests/tests/suites/basic/modrdn_bulk_children_test.py b/dirsrvtests/tests/suites/basic/modrdn_bulk_children_test.py +index 77f839c40..adbe2861a 100644 +--- a/dirsrvtests/tests/suites/basic/modrdn_bulk_children_test.py ++++ b/dirsrvtests/tests/suites/basic/modrdn_bulk_children_test.py +@@ -13,7 +13,7 @@ import pytest + from lib389._constants import DEFAULT_SUFFIX + from lib389.idm.organizationalunit import OrganizationalUnit, OrganizationalUnits + from lib389.idm.user import UserAccount, UserAccounts +-from test389.topologies import topology_st as topo ++from lib389.topologies import topology_st as topo + + pytestmark = pytest.mark.tier1 + +diff --git a/dirsrvtests/tests/suites/features/ldap_controls_test.py b/dirsrvtests/tests/suites/features/ldap_controls_test.py +index 59a58b21d..7d8b21c8f 100644 +--- a/dirsrvtests/tests/suites/features/ldap_controls_test.py ++++ b/dirsrvtests/tests/suites/features/ldap_controls_test.py +@@ -12,7 +12,7 @@ import ldap + from ldap.controls import RequestControl + from ldap.controls.readentry import PostReadControl + from lib389.idm.user import UserAccounts, UserAccount +-from test389.topologies import topology_st ++from lib389.topologies import topology_st + from lib389._constants import DEFAULT_SUFFIX, DN_DM, PASSWORD + + pytestmark = pytest.mark.tier1 +-- +2.54.0 + diff --git a/0008-Issue-7027-2nd-389-ds-base-OpenScanHub-Leaks-Detecte.patch b/0008-Issue-7027-2nd-389-ds-base-OpenScanHub-Leaks-Detecte.patch deleted file mode 100644 index ec16ee6..0000000 --- a/0008-Issue-7027-2nd-389-ds-base-OpenScanHub-Leaks-Detecte.patch +++ /dev/null @@ -1,53 +0,0 @@ -From dbabbe6a3c42b979d14960b355925c9748371cad Mon Sep 17 00:00:00 2001 -From: Viktor Ashirov -Date: Fri, 30 Jan 2026 12:00:13 +0100 -Subject: [PATCH] Issue 7027 - (2nd) 389-ds-base OpenScanHub Leaks Detected - (#7211) - -Fix Description: -Update coverity annotations. - -Relates: https://github.com/389ds/389-ds-base/issues/7027 - -Reviewed by: @aadhikar (Thanks!) ---- - ldap/servers/slapd/log.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/ldap/servers/slapd/log.c b/ldap/servers/slapd/log.c -index 668a02454..6f57a3d9c 100644 ---- a/ldap/servers/slapd/log.c -+++ b/ldap/servers/slapd/log.c -@@ -203,8 +203,8 @@ compress_log_file(char *log_name, int32_t mode) - - if ((source = fopen(log_name, "r")) == NULL) { - /* Failed to open log file */ -- /* coverity[leaked_storage] gzclose does close FD */ - gzclose(outfile); -+ /* coverity[leaked_handle] gzclose does close FD */ - return -1; - } - -@@ -214,17 +214,17 @@ compress_log_file(char *log_name, int32_t mode) - if (bytes_written == 0) - { - fclose(source); -- /* coverity[leaked_storage] gzclose does close FD */ - gzclose(outfile); -+ /* coverity[leaked_handle] gzclose does close FD */ - return -1; - } - bytes_read = fread(buf, 1, LOG_CHUNK, source); - } -- /* coverity[leaked_storage] gzclose does close FD */ - gzclose(outfile); - fclose(source); - PR_Delete(log_name); /* remove the old uncompressed log */ - -+ /* coverity[leaked_handle] gzclose does close FD */ - return 0; - } - --- -2.52.0 - diff --git a/0009-Issue-7213-MDB_BAD_VALSIZE-error-while-handling-VLV-.patch b/0009-Issue-7213-MDB_BAD_VALSIZE-error-while-handling-VLV-.patch deleted file mode 100644 index 229a8d4..0000000 --- a/0009-Issue-7213-MDB_BAD_VALSIZE-error-while-handling-VLV-.patch +++ /dev/null @@ -1,197 +0,0 @@ -From 39d47ca91e866d30b35dca41d477ad4ee07f8a14 Mon Sep 17 00:00:00 2001 -From: progier389 -Date: Mon, 2 Feb 2026 15:39:18 +0100 -Subject: [PATCH] Issue 7213 - MDB_BAD_VALSIZE error while handling VLV (#7214) - -* Issue 7213 - MDB_BAD_VALSIZE error while handling VLV -Avoid failing lmdb operation when handling VLV index by truncating the key so that key+data is small enough. - -Issue: #7213 - -Reviewed by: @mreynolds389 , @vashirov (Thanks!) - -Assisted by: Claude A/I - -(cherry picked from commit 5ebce22d4214bec5ed94ad84c4448164be99389a) ---- - .../tests/suites/vlv/regression_test.py | 110 ++++++++++++++++++ - .../slapd/back-ldbm/db-mdb/mdb_layer.c | 5 + - ldap/servers/slapd/back-ldbm/vlv.c | 7 +- - 3 files changed, 121 insertions(+), 1 deletion(-) - -diff --git a/dirsrvtests/tests/suites/vlv/regression_test.py b/dirsrvtests/tests/suites/vlv/regression_test.py -index c8db94b19..1cc03c303 100644 ---- a/dirsrvtests/tests/suites/vlv/regression_test.py -+++ b/dirsrvtests/tests/suites/vlv/regression_test.py -@@ -1178,6 +1178,116 @@ def test_vlv_with_mr(vlv_setup_with_uid_mr): - - - -+def test_vlv_long_attribute_value(topology_st, request): -+ """ -+ Test VLV with an entry containing a very long attribute value (2K). -+ -+ :id: 99126fa4-003e-11f1-b7d6-c85309d5c3e3 -+ :setup: Standalone instance. -+ :steps: -+ 1. Cleanup leftover from previous tests -+ 2. Create VLV search and index on cn attribute -+ 3. Reindex VLV -+ 4. Add an entry with a cn attribute having 2K character value -+ 5. Verify the entry was added successfully -+ 6. Perform a VLV search to ensure it still works -+ 7. Add another entry with a cn attribute having 2K character value -+ 8. Verify the entry was added successfully -+ 9. Perform a VLV search to ensure it still works -+ :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. -+ """ -+ inst = topology_st.standalone -+ reindex_task = Tasks(inst) -+ -+ users_to_delete = [] -+ -+ def fin(): -+ cleanup(inst) -+ # Clean the added users -+ for user in users_to_delete: -+ user.delete() -+ -+ if not DEBUGGING: -+ request.addfinalizer(fin) -+ -+ # Clean previous tests leftover -+ fin() -+ -+ # Create VLV search and index -+ vlv_search, vlv_index = create_vlv_search_and_index(inst) -+ assert reindex_task.reindex( -+ suffix=DEFAULT_SUFFIX, -+ attrname=vlv_index.rdn, -+ args={TASK_WAIT: True}, -+ vlv=True -+ ) == 0 -+ -+ # Add a few regular users first -+ add_users(inst, 10) -+ -+ # Create a very long cn value (2K characters) -+ long_cn_value = 'a' * 2048 + '1' -+ -+ # Add an entry with the long cn attribute -+ users = UserAccounts(inst, DEFAULT_SUFFIX) -+ user_properties = { -+ 'uid': 'longcnuser1', -+ 'cn': long_cn_value, -+ 'sn': 'user1', -+ 'uidNumber': '99999', -+ 'gidNumber': '99999', -+ 'homeDirectory': '/home/longcnuser1' -+ } -+ user = users.create(properties=user_properties) -+ users_to_delete.append(user); -+ -+ # Verify the entry was created and has the long cn value -+ entry = user.get_attr_vals_utf8('cn') -+ assert entry[0] == long_cn_value -+ log.info(f'Successfully created user with cn length: {len(entry[0])}') -+ -+ # Perform VLV search to ensure VLV still works with long attribute values -+ conn = open_new_ldapi_conn(inst.serverid) -+ count = len(conn.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, "(uid=*)")) -+ assert count > 0 -+ log.info(f'VLV search successful with {count} entries including entry with 2K cn value') -+ -+ # Add another entry with the long cn attribute -+ long_cn_value = 'a' * 2048 + '2' -+ -+ user_properties = { -+ 'uid': 'longcnuser2', -+ 'cn': long_cn_value, -+ 'sn': 'user2', -+ 'uidNumber': '99998', -+ 'gidNumber': '99998', -+ 'homeDirectory': '/home/longcnuser2' -+ } -+ user = users.create(properties=user_properties) -+ users_to_delete.append(user); -+ -+ # Verify the entry was created and has the long cn value -+ entry = user.get_attr_vals_utf8('cn') -+ assert entry[0] == long_cn_value -+ log.info(f'Successfully created user with cn length: {len(entry[0])}') -+ -+ # Perform VLV search to ensure VLV still works with long attribute values -+ conn = open_new_ldapi_conn(inst.serverid) -+ count = len(conn.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, "(uid=*)")) -+ assert count > 1 -+ log.info(f'VLV search successful with {count} entries including entry with 2K cn value') -+ -+ -+ - if __name__ == "__main__": - # Run isolated - # -s for DEBUG mode -diff --git a/ldap/servers/slapd/back-ldbm/db-mdb/mdb_layer.c b/ldap/servers/slapd/back-ldbm/db-mdb/mdb_layer.c -index c6e9f8b01..ffbd6609f 100644 ---- a/ldap/servers/slapd/back-ldbm/db-mdb/mdb_layer.c -+++ b/ldap/servers/slapd/back-ldbm/db-mdb/mdb_layer.c -@@ -2138,10 +2138,15 @@ void *dbmdb_recno_cache_build(void *arg) - recno = 1; - } - while (rc == 0) { -+ struct ldbminfo *li = (struct ldbminfo *)rcctx->cursor->be->be_database->plg_private; - slapi_log_err(SLAPI_LOG_DEBUG, "dbmdb_recno_cache_build", "recno=%d\n", recno); - if (recno % RECNO_CACHE_INTERVAL == 1) { - /* Prepare the cache data */ - len = sizeof(*rce) + data.mv_size + key.mv_size; -+ if (len > li->li_max_key_len) { -+ key.mv_size = li->li_max_key_len - data.mv_size - sizeof(*rce); -+ len = li->li_max_key_len; -+ } - rce = (dbmdb_recno_cache_elmt_t*)slapi_ch_malloc(len); - rce->len = len; - rce->recno = recno; -diff --git a/ldap/servers/slapd/back-ldbm/vlv.c b/ldap/servers/slapd/back-ldbm/vlv.c -index 18431799c..a1cd226f4 100644 ---- a/ldap/servers/slapd/back-ldbm/vlv.c -+++ b/ldap/servers/slapd/back-ldbm/vlv.c -@@ -866,6 +866,7 @@ do_vlv_update_index(back_txn *txn, struct ldbminfo *li, Slapi_PBlock *pb, struct - struct vlv_key *key = NULL; - dbi_val_t data = {0}; - dblayer_private *priv = NULL; -+ size_t key_size_limit = li->li_max_key_len - sizeof(entry->ep_id); - - slapi_pblock_get(pb, SLAPI_BACKEND, &be); - priv = (dblayer_private *)li->li_dblayer_private; -@@ -886,6 +887,10 @@ do_vlv_update_index(back_txn *txn, struct ldbminfo *li, Slapi_PBlock *pb, struct - return rc; - } - -+ /* Truncate the key if it is too long */ -+ if (key->key.size > key_size_limit) { -+ key->key.size = key_size_limit; -+ } - if (NULL != txn) { - db_txn = txn->back_txn_txn; - } else { -@@ -930,7 +935,7 @@ do_vlv_update_index(back_txn *txn, struct ldbminfo *li, Slapi_PBlock *pb, struct - if (txn && txn->back_special_handling_fn) { - rc = txn->back_special_handling_fn(be, BTXNACT_VLV_DEL, db, &key->key, &data, txn); - } else { -- rc = dblayer_db_op(be, db, db_txn, DBI_OP_DEL, &key->key, NULL); -+ rc = dblayer_db_op(be, db, db_txn, DBI_OP_DEL, &key->key, &data); - } - if (rc == 0) { - if (txn && txn->back_special_handling_fn) { --- -2.52.0 - diff --git a/0010-Issue-6542-RPM-build-errors-on-Fedora-42.patch b/0010-Issue-6542-RPM-build-errors-on-Fedora-42.patch deleted file mode 100644 index 8581df5..0000000 --- a/0010-Issue-6542-RPM-build-errors-on-Fedora-42.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 70d323d4d9ca4d1d682ab4a273178946922c6929 Mon Sep 17 00:00:00 2001 -From: Viktor Ashirov -Date: Fri, 24 Jan 2025 11:10:45 +0100 -Subject: [PATCH] Issue 6542 - RPM build errors on Fedora 42 - -Bug Description: -Fedora 42 has unified `/bin` and `/sbin`: https://fedoraproject.org/wiki/Changes/Unify_bin_and_sbin -https://docs.fedoraproject.org/en-US/packaging-guidelines/#_merged_file_system_layout - -This change causes RPM build to fail with: -``` -RPM build errors: - File not found: /builddir/build/BUILD/389-ds-base-3.1.2-build/BUILDROOT/usr/bin/openldap_to_ds -``` - -Fix Description: -Patch `setup.py.in` based on Fedora or RHEL version that support unified -`/bin` and `/sbin`. - -Fixes: https://github.com/389ds/389-ds-base/issues/6542 - -Reviewed by: @mreynolds389, @droideck (Thanks!) ---- - rpm/389-ds-base.spec.in | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/rpm/389-ds-base.spec.in b/rpm/389-ds-base.spec.in -index 258d94698..44a158ce5 100644 ---- a/rpm/389-ds-base.spec.in -+++ b/rpm/389-ds-base.spec.in -@@ -522,6 +522,9 @@ autoreconf -fiv - - %if 0%{?rhel} > 7 || 0%{?fedora} - # lib389 -+%if 0%{?fedora} >= 42 || 0%{?rhel} >= 11 -+ sed -i "/prefix/s@sbin@bin@g" src/lib389/setup.py.in -+%endif - make src/lib389/setup.py - pushd ./src/lib389 - %py3_build --- -2.52.0 - diff --git a/0011-Issue-6476-Fix-build-failure-with-GCC-15.patch b/0011-Issue-6476-Fix-build-failure-with-GCC-15.patch deleted file mode 100644 index e8b17e2..0000000 --- a/0011-Issue-6476-Fix-build-failure-with-GCC-15.patch +++ /dev/null @@ -1,3318 +0,0 @@ -From 9043425312dcf1ff7bf9a211a3d5a387d346a9fa Mon Sep 17 00:00:00 2001 -From: Mark Reynolds -Date: Tue, 28 Jan 2025 15:49:46 -0500 -Subject: [PATCH] Issue 6476 - Fix build failure with GCC 15 - -Description: - -Most of the failures are our use of function pointer with a generic -typedef with unknown parameters (e.g. IFP) - -There are other IFP we use, but they are not triggering build failures -yet. - -Relates: https://github.com/389ds/389-ds-base/issues/6476 - -Reviewed by: tbordaz & spichugi (Thanks!!) ---- - .../suites/replication/acceptance_test.py | 4 +- - .../suites/replication/changelog_test.py | 11 +- - ldap/include/avl.h | 15 +- - ldap/libraries/libavl/avl.c | 44 ++-- - ldap/servers/plugins/acl/acllist.c | 23 +- - ldap/servers/plugins/collation/orfilter.c | 218 ++++++++--------- - ldap/servers/plugins/pwdstorage/md5c.c | 87 +++---- - ldap/servers/plugins/roles/roles_cache.c | 37 +-- - ldap/servers/plugins/syntaxes/bin.c | 3 +- - ldap/servers/plugins/syntaxes/syntax.h | 21 +- - ldap/servers/plugins/syntaxes/syntax_common.c | 2 +- - ldap/servers/slapd/attrsyntax.c | 23 +- - .../slapd/back-ldbm/db-bdb/bdb_import.c | 8 +- - .../slapd/back-ldbm/db-mdb/mdb_import.c | 21 +- - .../back-ldbm/db-mdb/mdb_import_threads.c | 14 +- - .../slapd/back-ldbm/db-mdb/mdb_instance.c | 6 +- - ldap/servers/slapd/back-ldbm/filterindex.c | 2 +- - ldap/servers/slapd/back-ldbm/ldbm_attr.c | 28 ++- - ldap/servers/slapd/back-ldbm/matchrule.c | 6 +- - ldap/servers/slapd/back-ldbm/misc.c | 2 +- - .../servers/slapd/back-ldbm/proto-back-ldbm.h | 2 +- - ldap/servers/slapd/back-ldbm/vlv.c | 4 +- - ldap/servers/slapd/backend.c | 55 ++--- - ldap/servers/slapd/dse.c | 16 +- - ldap/servers/slapd/entry.c | 4 +- - ldap/servers/slapd/filtercmp.c | 4 +- - ldap/servers/slapd/getfilelist.c | 8 +- - ldap/servers/slapd/pblock.c | 219 +++++++++--------- - ldap/servers/slapd/pblock_v3.h | 2 +- - ldap/servers/slapd/plugin.c | 10 +- - ldap/servers/slapd/plugin_mmr.c | 20 +- - ldap/servers/slapd/plugin_mr.c | 13 +- - ldap/servers/slapd/plugin_syntax.c | 16 +- - ldap/servers/slapd/pw.c | 4 +- - ldap/servers/slapd/slap.h | 157 ++++++------- - ldap/servers/slapd/slapi-private.h | 2 +- - ldap/servers/slapd/task.c | 2 +- - 37 files changed, 558 insertions(+), 555 deletions(-) - -diff --git a/dirsrvtests/tests/suites/replication/acceptance_test.py b/dirsrvtests/tests/suites/replication/acceptance_test.py -index 547aee995..af3d4eaae 100644 ---- a/dirsrvtests/tests/suites/replication/acceptance_test.py -+++ b/dirsrvtests/tests/suites/replication/acceptance_test.py -@@ -597,7 +597,7 @@ def test_double_delete(topo_m4, create_entry): - time.sleep(5) - else: - time.sleep(1) -- -+ - log.info('Make searches to check if server is alive') - entries = get_repl_entries(topo_m4, TEST_ENTRY_NAME, ["uid"]) - assert not entries, "Entry deletion {} wasn't replicated successfully".format(TEST_ENTRY_DN) -@@ -688,7 +688,7 @@ def test_invalid_agmt(topo_m4): - assert False - - --def test_warining_for_invalid_replica(topo_m4): -+def test_warning_for_invalid_replica(topo_m4): - """Testing logs to indicate the inconsistency when configuration is performed. - - :id: dd689d03-69b8-4bf9-a06e-2acd19d5e2c8 -diff --git a/dirsrvtests/tests/suites/replication/changelog_test.py b/dirsrvtests/tests/suites/replication/changelog_test.py -index b12521789..b74650a69 100644 ---- a/dirsrvtests/tests/suites/replication/changelog_test.py -+++ b/dirsrvtests/tests/suites/replication/changelog_test.py -@@ -14,6 +14,7 @@ import pytest - import time - import subprocess - import glob -+import re - from lib389.properties import TASK_WAIT - from lib389.replica import Replicas - from lib389.idm.user import UserAccounts -@@ -46,10 +47,11 @@ else: - logging.getLogger(__name__).setLevel(logging.INFO) - log = logging.getLogger(__name__) - -+ - def _check_repl_changelog_backup(instance, backup_dir): - # Note: there is no way to check dbi on lmdb backup - # That said dbscan may perhaps do it ... -- if instance.get_db_lib() is 'bdb': -+ if instance.get_db_lib() == 'bdb': - if ds_supports_new_changelog(): - backup_checkdir = os.path.join(backup_dir, DEFAULT_BENAME, BDB_CL_FILENAME) - else: -@@ -60,6 +62,7 @@ def _check_repl_changelog_backup(instance, backup_dir): - log.fatal('test_changelog5: backup directory does not exist : {}*'.format(backup_checkdir)) - assert False - -+ - def _perform_ldap_operations(topo): - """Add a test user, modify description, modrdn user and delete it""" - -@@ -760,7 +763,7 @@ def test_changelog_pagesize(topo): - 3. Should not have any 4K page size in db_stat output - """ - -- s1=topo.ms["supplier1"] -+ s1 = topo.ms["supplier1"] - fs_pagesize = os.statvfs(s1.ds_paths.db_home_dir).f_bsize - if fs_pagesize != 4096: - pytest.skip("This test requires that database filesystem prefered block size is 4K.") -@@ -770,8 +773,8 @@ def test_changelog_pagesize(topo): - log.debug(f"DEBUG: Running {cmd}") - output = subprocess.check_output(cmd, universal_newlines=True, stderr=subprocess.STDOUT) - except subprocess.CalledProcessError as e: -- self.log.error(f'Failed to gather db statistics {cmd}: "{e.output.decode()}') -- self.log.error(e) -+ log.error(f'Failed to gather db statistics {cmd}: "{e.output.decode()}') -+ log.error(e) - raise e - assert not re.match("^4096 *Page size", output, flags=re.MULTILINE) - -diff --git a/ldap/include/avl.h b/ldap/include/avl.h -index cafe810ac..57086de23 100644 ---- a/ldap/include/avl.h -+++ b/ldap/include/avl.h -@@ -64,14 +64,15 @@ typedef int (*IFP)(); /* takes undefined arguments */ - /* avl routines */ - #define avl_getone(x) (x == 0 ? 0 : (x)->avl_data) - #define avl_onenode(x) (x == 0 || ((x)->avl_left == 0 && (x)->avl_right == 0)) --extern int avl_insert(Avlnode **root, void *data, IFP fcmp, IFP fdup); --extern caddr_t avl_delete(Avlnode **root, void *data, IFP fcmp); --extern caddr_t avl_find(Avlnode *root, void *data, IFP fcmp); -+ -+extern int avl_insert(Avlnode **root, caddr_t data, int32_t(*fcmp)(caddr_t, caddr_t), int32_t(*fdup)(caddr_t, caddr_t)); -+extern caddr_t avl_delete(Avlnode **root, caddr_t data, int32_t(*fcmp)(caddr_t, caddr_t)); -+extern caddr_t avl_find(Avlnode *root, caddr_t data, int32_t(*fcmp)(caddr_t, caddr_t)); - extern caddr_t avl_getfirst(Avlnode *root); - extern caddr_t avl_getnext(void); --extern int avl_dup_error(void); --extern int avl_apply(Avlnode *root, IFP fn, void *arg, int stopflag, int type); --extern int avl_free(Avlnode *root, IFP dfree); -+extern int avl_dup_error(caddr_t a, caddr_t b); -+extern int avl_apply(Avlnode *root, int32_t(*fn)(caddr_t, caddr_t), void *arg, int stopflag, int type); -+extern int avl_free(Avlnode *root, int32_t(*dfree)(caddr_t)); - - /* apply traversal types */ - #define AVL_PREORDER 1 -@@ -80,6 +81,6 @@ extern int avl_free(Avlnode *root, IFP dfree); - /* what apply returns if it ran out of nodes */ - #define AVL_NOMORE -6 - --caddr_t avl_find_lin(Avlnode *root, caddr_t data, IFP fcmp); -+caddr_t avl_find_lin(Avlnode *root, caddr_t data, int32_t(*fcmp)(caddr_t, caddr_t)); - - #endif /* _AVL */ -diff --git a/ldap/libraries/libavl/avl.c b/ldap/libraries/libavl/avl.c -index 517e08098..84a50308a 100644 ---- a/ldap/libraries/libavl/avl.c -+++ b/ldap/libraries/libavl/avl.c -@@ -69,8 +69,8 @@ ravl_insert( - Avlnode **iroot, - caddr_t data, - int *taller, -- IFP fcmp, /* comparison function */ -- IFP fdup, /* function to call for duplicates */ -+ int32_t (*fcmp)(caddr_t, caddr_t), /* comparison function */ -+ int32_t (*fdup)(caddr_t, caddr_t), /* function to call for duplicates */ - int depth) - { - int rc, cmp, tallersub; -@@ -226,13 +226,13 @@ ravl_insert( - int - avl_insert( - Avlnode **root, -- void *data, -- IFP fcmp, -- IFP fdup) -+ caddr_t data, -+ int32_t (*fcmp)(caddr_t, caddr_t), -+ int32_t (*fdup)(caddr_t, caddr_t)) - { - int taller; - -- return ravl_insert(root, (caddr_t)data, &taller, fcmp, fdup, 0); -+ return ravl_insert(root, data, &taller, fcmp, fdup, 0); - } - - /* -@@ -374,7 +374,7 @@ static caddr_t - ravl_delete( - Avlnode **root, - caddr_t data, -- IFP fcmp, -+ int32_t (*fcmp)(caddr_t, caddr_t), - int *shorter) - { - int shortersubtree = 0; -@@ -464,15 +464,15 @@ ravl_delete( - */ - - caddr_t --avl_delete(Avlnode **root, void *data, IFP fcmp) -+avl_delete(Avlnode **root, caddr_t data, int32_t(*fcmp)(caddr_t, caddr_t)) - { - int shorter; - -- return ravl_delete(root, (caddr_t)data, fcmp, &shorter); -+ return ravl_delete(root, data, fcmp, &shorter); - } - - static int --avl_inapply(Avlnode *root, IFP fn, caddr_t arg, int stopflag) -+avl_inapply(Avlnode *root, int32_t(*fn)(caddr_t, caddr_t), caddr_t arg, int stopflag) - { - if (root == 0) - return (AVL_NOMORE); -@@ -491,7 +491,7 @@ avl_inapply(Avlnode *root, IFP fn, caddr_t arg, int stopflag) - } - - static int --avl_postapply(Avlnode *root, IFP fn, caddr_t arg, int stopflag) -+avl_postapply(Avlnode *root, int32_t(*fn)(caddr_t, caddr_t), caddr_t arg, int stopflag) - { - if (root == 0) - return (AVL_NOMORE); -@@ -508,7 +508,7 @@ avl_postapply(Avlnode *root, IFP fn, caddr_t arg, int stopflag) - } - - static int --avl_preapply(Avlnode *root, IFP fn, caddr_t arg, int stopflag) -+avl_preapply(Avlnode *root, int32_t(*fn)(caddr_t, caddr_t), caddr_t arg, int stopflag) - { - if (root == 0) - return (AVL_NOMORE); -@@ -537,7 +537,7 @@ avl_preapply(Avlnode *root, IFP fn, caddr_t arg, int stopflag) - int - avl_apply( - Avlnode *root, -- IFP fn, -+ int32_t (*fn)(caddr_t, caddr_t), - void *arg, - int stopflag, - int type) -@@ -572,9 +572,9 @@ int - avl_prefixapply( - Avlnode *root, - caddr_t data, -- IFP fmatch, -+ int32_t (*fmatch)(caddr_t, caddr_t), - caddr_t marg, -- IFP fcmp, -+ int32_t (*fcmp)(caddr_t, caddr_t, caddr_t), - caddr_t carg, - int stopflag) - { -@@ -619,7 +619,7 @@ avl_prefixapply( - */ - - int --avl_free(Avlnode *root, IFP dfree) -+avl_free(Avlnode *root, int32_t (*dfree)(caddr_t)) - { - int nleft, nright; - -@@ -649,11 +649,11 @@ avl_free(Avlnode *root, IFP dfree) - */ - - caddr_t --avl_find(Avlnode *root, void *data, IFP fcmp) -+avl_find(Avlnode *root, caddr_t data, int32_t (*fcmp)(caddr_t, caddr_t)) - { - int cmp; - -- while (root != 0 && (cmp = (*fcmp)((caddr_t)data, root->avl_data)) != 0) { -+ while (root != 0 && (cmp = (*fcmp)(data, root->avl_data)) != 0) { - if (cmp < 0) - root = root->avl_left; - else -@@ -671,7 +671,7 @@ avl_find(Avlnode *root, void *data, IFP fcmp) - */ - - caddr_t --avl_find_lin(Avlnode *root, caddr_t data, IFP fcmp) -+avl_find_lin(Avlnode *root, caddr_t data, int32_t (*fcmp)(caddr_t, caddr_t)) - { - caddr_t res; - -@@ -699,7 +699,7 @@ static int avl_nextlist = 0; - - /* ARGSUSED */ - static int --avl_buildlist(caddr_t data, int arg __attribute__((unused))) -+avl_buildlist(caddr_t data, caddr_t arg __attribute__((unused))) - { - static int slots = 0; - -@@ -766,8 +766,10 @@ avl_getnext(void) - return (avl_list[avl_nextlist++]); - } - -+/* This is always called from avl_insert, where the dup function expects two -+ * caddr_t paramters */ - int --avl_dup_error(void) -+avl_dup_error(caddr_t a __attribute__((unused)), caddr_t b __attribute__((unused))) - { - return (-1); - } -diff --git a/ldap/servers/plugins/acl/acllist.c b/ldap/servers/plugins/acl/acllist.c -index e80c567c3..bf1168691 100644 ---- a/ldap/servers/plugins/acl/acllist.c -+++ b/ldap/servers/plugins/acl/acllist.c -@@ -233,14 +233,14 @@ __acllist_add_aci(aci_t *aci) - slapi_sdn_set_ndn_byval(aciListHead->acic_sdn, slapi_sdn_get_ndn(aci->aci_sdn)); - - /* insert the aci */ -- switch (avl_insert(&acllistRoot, aciListHead, __acllist_aciContainer_node_cmp, -+ switch (avl_insert(&acllistRoot, (caddr_t)aciListHead, __acllist_aciContainer_node_cmp, - __acllist_aciContainer_node_dup)) { - - case 1: /* duplicate ACL on the same entry */ - - /* Find the node that contains the acl. */ -- if (NULL == (head = (AciContainer *)avl_find(acllistRoot, aciListHead, -- (IFP)__acllist_aciContainer_node_cmp))) { -+ if (NULL == (head = (AciContainer *)avl_find(acllistRoot, (caddr_t)aciListHead, -+ __acllist_aciContainer_node_cmp))) { - slapi_log_err(SLAPI_PLUGIN_ACL, plugin_name, - "__acllist_add_aci - Can't insert the acl in the tree\n"); - rv = 1; -@@ -356,8 +356,8 @@ acllist_remove_aci_needsLock(const Slapi_DN *sdn, const struct berval *attr) - slapi_sdn_set_ndn_byval(aciListHead->acic_sdn, slapi_sdn_get_ndn(sdn)); - - /* now find it */ -- if (NULL == (root = (AciContainer *)avl_find(acllistRoot, aciListHead, -- (IFP)__acllist_aciContainer_node_cmp))) { -+ if (NULL == (root = (AciContainer *)avl_find(acllistRoot, (caddr_t)aciListHead, -+ __acllist_aciContainer_node_cmp))) { - /* In that case we don't have any acl for this entry. cool !!! */ - - acllist_free_aciContainer(&aciListHead); -@@ -389,7 +389,7 @@ acllist_remove_aci_needsLock(const Slapi_DN *sdn, const struct berval *attr) - slapi_log_err(SLAPI_LOG_ACL, plugin_name, - "acllist_remove_aci_needsLock - Removing container[%d]=%s\n", root->acic_index, - slapi_sdn_get_ndn(root->acic_sdn)); -- dContainer = (AciContainer *)avl_delete(&acllistRoot, aciListHead, -+ dContainer = (AciContainer *)avl_delete(&acllistRoot, (caddr_t)aciListHead, - __acllist_aciContainer_node_cmp); - acllist_free_aciContainer(&dContainer); - -@@ -472,8 +472,9 @@ acllist_done_aciContainer(AciContainer *head) - } - - static int --free_aci_avl_container(AciContainer *data) -+free_aci_avl_container(caddr_t d) - { -+ AciContainer *data = (AciContainer *)d; - aci_t *head, *next = NULL; - - head = data->acic_list; -@@ -658,7 +659,7 @@ acllist_init_scan(Slapi_PBlock *pb, int scope __attribute__((unused)), const cha - - root = (AciContainer *)avl_find(acllistRoot, - (caddr_t)aclpb->aclpb_aclContainer, -- (IFP)__acllist_aciContainer_node_cmp); -+ __acllist_aciContainer_node_cmp); - if (index >= aclpb_max_selected_acls - 2) { - aclpb->aclpb_handles_index[0] = -1; - slapi_ch_free_string(&basedn); -@@ -750,7 +751,7 @@ acllist_aciscan_update_scan(Acl_PBlock *aclpb, char *edn) - - root = (AciContainer *)avl_find(acllistRoot, - (caddr_t)aclpb->aclpb_aclContainer, -- (IFP)__acllist_aciContainer_node_cmp); -+ __acllist_aciContainer_node_cmp); - - slapi_log_err(SLAPI_LOG_ACL, plugin_name, - "acllist_aciscan_update_scan - Searching AVL tree for update:%s: container:%d\n", -@@ -910,8 +911,8 @@ acllist_moddn_aci_needsLock(Slapi_DN *oldsdn, char *newdn) - slapi_sdn_free(&aciListHead->acic_sdn); - aciListHead->acic_sdn = oldsdn; - -- if (NULL == (head = (AciContainer *)avl_find(acllistRoot, aciListHead, -- (IFP)__acllist_aciContainer_node_cmp))) { -+ if (NULL == (head = (AciContainer *)avl_find(acllistRoot, (caddr_t)aciListHead, -+ __acllist_aciContainer_node_cmp))) { - - slapi_log_err(SLAPI_PLUGIN_ACL, plugin_name, - "acllist_moddn_aci_needsLock - Can't find the acl in the tree for moddn operation:olddn%s\n", -diff --git a/ldap/servers/plugins/collation/orfilter.c b/ldap/servers/plugins/collation/orfilter.c -index 1ed17c097..22fa7607d 100644 ---- a/ldap/servers/plugins/collation/orfilter.c -+++ b/ldap/servers/plugins/collation/orfilter.c -@@ -54,7 +54,7 @@ typedef struct or_filter_t - static or_filter_t * - or_filter_get(Slapi_PBlock *pb) - { -- auto void *obj = NULL; -+ void *obj = NULL; - if (!slapi_pblock_get(pb, SLAPI_PLUGIN_OBJECT, &obj)) { - return (or_filter_t *)obj; - } -@@ -64,7 +64,7 @@ or_filter_get(Slapi_PBlock *pb) - static int - or_filter_destroy(Slapi_PBlock *pb) - { -- auto or_filter_t * or = or_filter_get(pb); -+ or_filter_t * or = or_filter_get(pb); - slapi_log_err(SLAPI_LOG_FILTER, COLLATE_PLUGIN_SUBSYSTEM, - "or_filter_destroy - (%p)\n", (void *) or); - if (or != NULL) { -@@ -105,10 +105,10 @@ ss_match(struct berval *value, - * -1 nothing in value will match; give up - */ - { -- auto struct berval *vals[2]; -- auto struct berval val; -- auto struct berval key; -- auto size_t attempts = MAX_CHAR_COMBINING; -+ struct berval *vals[2]; -+ struct berval val; -+ struct berval key; -+ size_t attempts = MAX_CHAR_COMBINING; - - vals[0] = &val; - vals[1] = NULL; -@@ -117,9 +117,9 @@ ss_match(struct berval *value, - key.bv_val = key0->bv_val; - key.bv_len = key0->bv_len - 1; - while (1) { -- auto struct berval **vkeys = ix->ix_index(ix, vals, NULL); -+ struct berval **vkeys = ix->ix_index(ix, vals, NULL); - if (vkeys && vkeys[0]) { -- auto const struct berval *vkey = vkeys[0]; -+ const struct berval *vkey = vkeys[0]; - if (vkey->bv_len > key.bv_len) { - if (--attempts <= 0) { - break; /* No match at this starting point */ -@@ -138,7 +138,7 @@ ss_match(struct berval *value, - val.bv_len += LDAP_UTF8LEN(val.bv_val + val.bv_len); - } - if (value->bv_len > 0) { -- auto size_t one = LDAP_UTF8LEN(value->bv_val); -+ size_t one = LDAP_UTF8LEN(value->bv_val); - value->bv_len -= one; - value->bv_val += one; - return 1; -@@ -153,12 +153,12 @@ ss_filter_match(or_filter_t * or, struct berval **vals) - * >0 an LDAP error code - */ - { -- auto int rc = -1; /* no match */ -- auto indexer_t *ix = or->or_indexer; -+ int rc = -1; /* no match */ -+ indexer_t *ix = or->or_indexer; - if (vals != NULL) - for (; *vals; ++vals) { -- auto struct berval v; -- auto struct berval **k = or->or_match_keys; -+ struct berval v; -+ struct berval **k = or->or_match_keys; - if (k == NULL || *k == NULL) { - rc = 0; /* present */ - break; -@@ -180,12 +180,12 @@ ss_filter_match(or_filter_t * or, struct berval **vals) - break; - } - } else { /* final */ -- auto size_t attempts = MAX_CHAR_COMBINING; -- auto char *limit = v.bv_val; -- auto char *end; -- auto struct berval **vkeys; -- auto struct berval *final_vals[2]; -- auto struct berval key; -+ size_t attempts = MAX_CHAR_COMBINING; -+ char *limit = v.bv_val; -+ char *end; -+ struct berval **vkeys; -+ struct berval *final_vals[2]; -+ struct berval key; - - rc = -1; - final_vals[0] = &v; -@@ -211,7 +211,7 @@ ss_filter_match(or_filter_t * or, struct berval **vals) - v.bv_len = end - v.bv_val + 1; - vkeys = ix->ix_index(ix, final_vals, NULL); - if (vkeys && vkeys[0]) { -- auto const struct berval *vkey = vkeys[0]; -+ const struct berval *vkey = vkeys[0]; - if (vkey->bv_len > key.bv_len) { - if (--attempts <= 0) { - break; -@@ -239,11 +239,11 @@ ss_filter_match(or_filter_t * or, struct berval **vals) - static int - op_filter_match(or_filter_t * or, struct berval **vals) - { -- auto indexer_t *ix = or->or_indexer; -- auto struct berval **v = ix->ix_index(ix, vals, NULL); -+ indexer_t *ix = or->or_indexer; -+ struct berval **v = ix->ix_index(ix, vals, NULL); - if (v != NULL) - for (; *v; ++v) { -- auto struct berval **k = or->or_match_keys; -+ struct berval **k = or->or_match_keys; - if (k != NULL) - for (; *k; ++k) { - switch (or->or_op) { -@@ -282,11 +282,11 @@ or_filter_match(void *obj, Slapi_Entry *entry, Slapi_Attr *attr) - * >0 an LDAP error code - */ - { -- auto int rc = -1; /* no match */ -- auto or_filter_t * or = (or_filter_t *)obj; -+ int rc = -1; /* no match */ -+ or_filter_t * or = (or_filter_t *)obj; - for (; attr != NULL; slapi_entry_next_attr(entry, attr, &attr)) { -- auto char *type = NULL; -- auto struct berval **vals = NULL; -+ char *type = NULL; -+ struct berval **vals = NULL; - - /* - * XXXmcs 1-March-2001: This code would perform better if it did not make -@@ -352,7 +352,7 @@ static struct berval * - slapi_ch_bvdup0(struct berval *val) - /* Return a copy of val, with a 0 byte following the end. */ - { -- auto struct berval *result = (struct berval *) -+ struct berval *result = (struct berval *) - slapi_ch_malloc(sizeof(struct berval)); - slapi_ber_bvcpy(result, val); - return result; -@@ -372,12 +372,12 @@ static struct berval ** - ss_filter_values(struct berval *pattern, int *query_op) - /* Split the pattern into its substrings and return them. */ - { -- auto struct berval **result; -- auto struct berval val; -- auto size_t n; -- auto char *s; -- auto char *p; -- auto char *plimit = pattern->bv_val + pattern->bv_len; -+ struct berval **result; -+ struct berval val; -+ size_t n; -+ char *s; -+ char *p; -+ char *plimit = pattern->bv_val + pattern->bv_len; - - /* Compute the length of the result array, and - the maximum bv_len of any of its elements. */ -@@ -389,7 +389,7 @@ ss_filter_values(struct berval *pattern, int *query_op) - case WILDCARD: - ++n; - { -- auto const size_t len = (p - s); -+ const size_t len = (p - s); - if (val.bv_len < len) - val.bv_len = len; - } -@@ -402,8 +402,8 @@ ss_filter_values(struct berval *pattern, int *query_op) - } - } - if (n == 2) { /* no wildcards in pattern */ -- auto struct berval **pvec = (struct berval **)slapi_ch_malloc(sizeof(struct berval *) * 2); -- auto struct berval *pv = slapi_ch_bvdup(pattern); -+ struct berval **pvec = (struct berval **)slapi_ch_malloc(sizeof(struct berval *) * 2); -+ struct berval *pv = slapi_ch_bvdup(pattern); - pvec[0] = pv; - pvec[1] = NULL; - ss_unescape(pv); -@@ -413,7 +413,7 @@ ss_filter_values(struct berval *pattern, int *query_op) - return NULL; /* presence */ - } - { -- auto const size_t len = (p - s); -+ const size_t len = (p - s); - if (val.bv_len < len) - val.bv_len = len; - } -@@ -449,7 +449,7 @@ ss_filter_key(indexer_t *ix, struct berval *val) - struct berval *key = (struct berval *)slapi_ch_calloc(1, sizeof(struct berval)); - if (val->bv_len > 0) { - struct berval **keys = NULL; -- auto struct berval *vals[2]; -+ struct berval *vals[2]; - vals[0] = val; - vals[1] = NULL; - keys = ix->ix_index(ix, vals, NULL); -@@ -477,10 +477,10 @@ ss_filter_keys(indexer_t *ix, struct berval **values) - an empty key definitely implies an absent value. - */ - { -- auto struct berval **keys = NULL; -+ struct berval **keys = NULL; - if (values != NULL) { -- auto size_t n; /* how many substring values */ -- auto struct berval **val; -+ size_t n; /* how many substring values */ -+ struct berval **val; - for (n = 0, val = values; *val != NULL; ++n, ++val) - ; - keys = (struct berval **)slapi_ch_malloc((n + 1) * sizeof(struct berval *)); -@@ -497,25 +497,25 @@ static int or_filter_index(Slapi_PBlock *pb); - static int - or_filter_create(Slapi_PBlock *pb) - { -- auto int rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION; /* failed to initialize */ -- auto char *mrOID = NULL; -- auto char *mrTYPE = NULL; -- auto struct berval *mrVALUE = NULL; -- auto or_filter_t * or = NULL; -+ int rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION; /* failed to initialize */ -+ char *mrOID = NULL; -+ char *mrTYPE = NULL; -+ struct berval *mrVALUE = NULL; -+ or_filter_t * or = NULL; - - if (!slapi_pblock_get(pb, SLAPI_PLUGIN_MR_OID, &mrOID) && mrOID != NULL && - !slapi_pblock_get(pb, SLAPI_PLUGIN_MR_TYPE, &mrTYPE) && mrTYPE != NULL && - !slapi_pblock_get(pb, SLAPI_PLUGIN_MR_VALUE, &mrVALUE) && mrVALUE != NULL) { -- auto size_t len = mrVALUE->bv_len; -- auto indexer_t *ix = NULL; -- auto int op = SLAPI_OP_EQUAL; -- auto struct berval bv; -- auto int reusable = MRF_ANY_TYPE; -+ size_t len = mrVALUE->bv_len; -+ indexer_t *ix = NULL; -+ int op = SLAPI_OP_EQUAL; -+ struct berval bv; -+ int reusable = MRF_ANY_TYPE; - - slapi_log_err(SLAPI_LOG_FILTER, COLLATE_PLUGIN_SUBSYSTEM, - "or_filter_create - (oid %s; type %s)\n", mrOID, mrTYPE); - if (len > 1 && (ix = indexer_create(mrOID)) != NULL) { -- auto char *val = mrVALUE->bv_val; -+ char *val = mrVALUE->bv_val; - switch (val[0]) { - case '=': - break; -@@ -537,7 +537,7 @@ or_filter_create(Slapi_PBlock *pb) - bv.bv_val = (len > 0) ? val : NULL; - } else { /* mrOID does not identify an ordering rule. */ - /* Is it an ordering rule OID with a relational operator suffix? */ -- auto size_t oidlen = strlen(mrOID); -+ size_t oidlen = strlen(mrOID); - if (oidlen > 2 && mrOID[oidlen - 2] == '.') { - op = atoi(mrOID + oidlen - 1); - switch (op) { -@@ -547,7 +547,7 @@ or_filter_create(Slapi_PBlock *pb) - case SLAPI_OP_GREATER_OR_EQUAL: - case SLAPI_OP_GREATER: - case SLAPI_OP_SUBSTRING: { -- auto char *or_oid = slapi_ch_strdup(mrOID); -+ char *or_oid = slapi_ch_strdup(mrOID); - or_oid[oidlen - 2] = '\0'; - ix = indexer_create(or_oid); - if (ix != NULL) { -@@ -575,7 +575,7 @@ or_filter_create(Slapi_PBlock *pb) - or->or_values[1] = NULL; - } - { -- auto struct berval **val = or->or_values; -+ struct berval **val = or->or_values; - if (val) - for (; *val; ++val) { - slapi_log_err(SLAPI_LOG_FILTER, COLLATE_PLUGIN_SUBSYSTEM, -@@ -607,7 +607,7 @@ or_filter_create(Slapi_PBlock *pb) - static indexer_t * - op_indexer_get(Slapi_PBlock *pb) - { -- auto void *obj = NULL; -+ void *obj = NULL; - if (!slapi_pblock_get(pb, SLAPI_PLUGIN_OBJECT, &obj)) { - return (indexer_t *)obj; - } -@@ -617,7 +617,7 @@ op_indexer_get(Slapi_PBlock *pb) - static int - op_indexer_destroy(Slapi_PBlock *pb) - { -- auto indexer_t *ix = op_indexer_get(pb); -+ indexer_t *ix = op_indexer_get(pb); - slapi_log_err(SLAPI_LOG_FILTER, COLLATE_PLUGIN_SUBSYSTEM, - "op_indexer_destroy - (%p)\n", (void *)ix); - if (ix != NULL) { -@@ -632,8 +632,8 @@ static int - op_index_entry(Slapi_PBlock *pb) - /* Compute collation keys (when writing an entry). */ - { -- auto indexer_t *ix = op_indexer_get(pb); -- auto int rc; -+ indexer_t *ix = op_indexer_get(pb); -+ int rc; - struct berval **values; - if (ix != NULL && ix->ix_index != NULL && - !slapi_pblock_get(pb, SLAPI_PLUGIN_MR_VALUES, &values) && -@@ -651,10 +651,10 @@ static int - op_index_search(Slapi_PBlock *pb) - /* Compute collation keys (when searching for entries). */ - { -- auto or_filter_t * or = or_filter_get(pb); -- auto int rc = LDAP_OPERATIONS_ERROR; -+ or_filter_t * or = or_filter_get(pb); -+ int rc = LDAP_OPERATIONS_ERROR; - if (or != NULL) { -- auto indexer_t *ix = or->or_indexer; -+ indexer_t *ix = or->or_indexer; - struct berval **values; - if (or->or_index_keys == NULL && ix != NULL && ix->ix_index != NULL && !slapi_pblock_get(pb, SLAPI_PLUGIN_MR_VALUES, &values)) { - or->or_index_keys = slapi_ch_bvecdup(ix->ix_index(ix, values, NULL)); -@@ -688,7 +688,7 @@ ss_indexer_free(ss_indexer_t *ss) - static ss_indexer_t * - ss_indexer_get(Slapi_PBlock *pb) - { -- auto void *obj = NULL; -+ void *obj = NULL; - if (!slapi_pblock_get(pb, SLAPI_PLUGIN_OBJECT, &obj)) { - return (ss_indexer_t *)obj; - } -@@ -698,7 +698,7 @@ ss_indexer_get(Slapi_PBlock *pb) - static void - ss_indexer_destroy(Slapi_PBlock *pb) - { -- auto ss_indexer_t *ss = ss_indexer_get(pb); -+ ss_indexer_t *ss = ss_indexer_get(pb); - slapi_log_err(SLAPI_LOG_FILTER, COLLATE_PLUGIN_SUBSYSTEM, - "ss_indexer_destroy - (%p)\n", (void *)ss); - if (ss) { -@@ -722,9 +722,9 @@ static int - long_enough(struct berval *bval, size_t enough) - { - if (bval) { -- auto size_t len = 0; -- auto char *next = bval->bv_val; -- auto char *last = next + bval->bv_len; -+ size_t len = 0; -+ char *next = bval->bv_val; -+ char *last = next + bval->bv_len; - while (next < last) { - LDAP_UTF8INC(next); - if (++len >= enough) { -@@ -742,23 +742,23 @@ static int - ss_index_entry(Slapi_PBlock *pb) - /* Compute substring index keys (when writing an entry). */ - { -- auto int rc = LDAP_OPERATIONS_ERROR; -- auto size_t substringsLen = 0; -+ int rc = LDAP_OPERATIONS_ERROR; -+ size_t substringsLen = 0; - struct berval **values; -- auto ss_indexer_t *ss = ss_indexer_get(pb); -- auto indexer_t *ix = ss ? ss->ss_indexer : NULL; -+ ss_indexer_t *ss = ss_indexer_get(pb); -+ indexer_t *ix = ss ? ss->ss_indexer : NULL; - if (ix != NULL && ix->ix_index != NULL && - !slapi_pblock_get(pb, SLAPI_PLUGIN_MR_VALUES, &values)) { -- auto struct berval *substrings = NULL; -- auto struct berval **prefixes = NULL; -- auto struct berval **value; -+ struct berval *substrings = NULL; -+ struct berval **prefixes = NULL; -+ struct berval **value; - for (value = values; *value != NULL; ++value) { -- auto struct berval substring; -+ struct berval substring; - substring.bv_val = (*value)->bv_val; - substring.bv_len = (*value)->bv_len; - if (long_enough(&substring, SS_INDEX_LENGTH - 1)) { -- auto struct berval *prefix = &ss_index_initial; -- auto size_t offset; -+ struct berval *prefix = &ss_index_initial; -+ size_t offset; - for (offset = 0; 1; ++offset) { - ++substringsLen; - substrings = (struct berval *) -@@ -782,9 +782,9 @@ ss_index_entry(Slapi_PBlock *pb) - } - } - if (substrings != NULL) { -- auto struct berval **vector = (struct berval **) -+ struct berval **vector = (struct berval **) - slapi_ch_malloc((substringsLen + 1) * sizeof(struct berval *)); -- auto size_t i; -+ size_t i; - for (i = 0; i < substringsLen; ++i) - vector[i] = &(substrings[i]); - vector[substringsLen] = NULL; -@@ -804,21 +804,21 @@ static int - ss_index_search(Slapi_PBlock *pb) - /* Compute substring search keys (when searching for entries). */ - { -- auto int rc = LDAP_OPERATIONS_ERROR; -- auto or_filter_t * or = or_filter_get(pb); -+ int rc = LDAP_OPERATIONS_ERROR; -+ or_filter_t * or = or_filter_get(pb); - if (or) { - if (or->or_index_keys == NULL /* not yet computed */ && - or->or_values && or->or_indexer && or->or_indexer->ix_index) { -- auto size_t substringsLen = 0; -- auto struct berval *substrings = NULL; -- auto struct berval **prefixes = NULL; -- auto struct berval **value; -+ size_t substringsLen = 0; -+ struct berval *substrings = NULL; -+ struct berval **prefixes = NULL; -+ struct berval **value; - for (value = or->or_values; *value != NULL; ++value) { -- auto size_t offset; -- auto struct berval substring; -+ size_t offset; -+ struct berval substring; - substring.bv_val = (*value)->bv_val; - for (offset = 0; 1; ++offset, LDAP_UTF8INC(substring.bv_val)) { -- auto struct berval *prefix = NULL; -+ struct berval *prefix = NULL; - substring.bv_len = (*value)->bv_len - (substring.bv_val - (*value)->bv_val); - if (offset == 0 && value == or->or_values) { - if (long_enough(&substring, SS_INDEX_LENGTH - 1)) { -@@ -845,10 +845,10 @@ ss_index_search(Slapi_PBlock *pb) - } - } - if (substrings != NULL) { -- auto indexer_t *ix = or->or_indexer; -- auto struct berval **vector = (struct berval **) -+ indexer_t *ix = or->or_indexer; -+ struct berval **vector = (struct berval **) - slapi_ch_malloc((substringsLen + 1) * sizeof(struct berval *)); -- auto size_t i; -+ size_t i; - for (i = 0; i < substringsLen; ++i) - vector[i] = &(substrings[i]); - vector[substringsLen] = NULL; -@@ -872,10 +872,10 @@ static int - ss_indexable(struct berval **values) - /* at least one of the values is long enough to index */ - { -- auto struct berval **val = values; -+ struct berval **val = values; - if (val) - for (; *val; ++val) { -- auto struct berval value; -+ struct berval value; - value.bv_val = (*val)->bv_val; - value.bv_len = (*val)->bv_len; - if (val == values) { /* initial */ -@@ -899,12 +899,12 @@ static int - or_filter_index(Slapi_PBlock *pb) - /* Return an indexer and values that accelerate the given filter. */ - { -- auto or_filter_t * or = or_filter_get(pb); -- auto int rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION; -- auto IFP mrINDEX_FN = NULL; -- auto struct berval **mrVALUES = NULL; -- auto char *mrOID = NULL; -- auto int mrQUERY_OPERATOR; -+ or_filter_t * or = or_filter_get(pb); -+ int rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION; -+ int32_t (*mrINDEX_FN)(Slapi_PBlock *) = NULL; -+ struct berval **mrVALUES = NULL; -+ char *mrOID = NULL; -+ int mrQUERY_OPERATOR; - if (or && or->or_indexer && or->or_indexer->ix_index) { - switch (or->or_op) { - case SLAPI_OP_LESS: -@@ -920,7 +920,7 @@ or_filter_index(Slapi_PBlock *pb) - case SLAPI_OP_SUBSTRING: - if (ss_indexable(or->or_values)) { - if (or->or_oid == NULL) { -- auto const size_t len = strlen(or->or_indexer->ix_oid); -+ const size_t len = strlen(or->or_indexer->ix_oid); - or->or_oid = slapi_ch_malloc(len + 3); - memcpy(or->or_oid, or->or_indexer->ix_oid, len); - sprintf(or->or_oid + len, ".%1i", SLAPI_OP_SUBSTRING); -@@ -952,15 +952,15 @@ or_filter_index(Slapi_PBlock *pb) - static int - or_indexer_create(Slapi_PBlock *pb) - { -- auto int rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION; /* failed to initialize */ -- auto char *mrOID = NULL; -- auto void *mrOBJECT = NULL; -+ int rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION; /* failed to initialize */ -+ char *mrOID = NULL; -+ void *mrOBJECT = NULL; - if (slapi_pblock_get(pb, SLAPI_PLUGIN_MR_OID, &mrOID) || mrOID == NULL) { - slapi_log_err(SLAPI_LOG_FILTER, COLLATE_PLUGIN_SUBSYSTEM, - "or_indexer_create - No OID parameter\n"); - } else { -- auto indexer_t *ix = indexer_create(mrOID); -- auto char *mrTYPE = NULL; -+ indexer_t *ix = indexer_create(mrOID); -+ char *mrTYPE = NULL; - slapi_pblock_get(pb, SLAPI_PLUGIN_MR_TYPE, &mrTYPE); - slapi_log_err(SLAPI_LOG_FILTER, "or_indexer_create", "(oid %s; type %s)\n", - mrOID, mrTYPE ? mrTYPE : ""); -@@ -977,14 +977,14 @@ or_indexer_create(Slapi_PBlock *pb) - } - } else { /* mrOID does not identify an ordering rule. */ - /* Is it an ordering rule OID with the substring suffix? */ -- auto size_t oidlen = strlen(mrOID); -+ size_t oidlen = strlen(mrOID); - if (oidlen > 2 && mrOID[oidlen - 2] == '.' && - atoi(mrOID + oidlen - 1) == SLAPI_OP_SUBSTRING) { -- auto char *or_oid = slapi_ch_strdup(mrOID); -+ char *or_oid = slapi_ch_strdup(mrOID); - or_oid[oidlen - 2] = '\0'; - ix = indexer_create(or_oid); - if (ix != NULL) { -- auto ss_indexer_t *ss = (ss_indexer_t *)slapi_ch_malloc(sizeof(ss_indexer_t)); -+ ss_indexer_t *ss = (ss_indexer_t *)slapi_ch_malloc(sizeof(ss_indexer_t)); - ss->ss_indexer = ix; - oidlen = strlen(ix->ix_oid); - ss->ss_oid = slapi_ch_malloc(oidlen + 3); -diff --git a/ldap/servers/plugins/pwdstorage/md5c.c b/ldap/servers/plugins/pwdstorage/md5c.c -index e7085a68d..8075dcb80 100644 ---- a/ldap/servers/plugins/pwdstorage/md5c.c -+++ b/ldap/servers/plugins/pwdstorage/md5c.c -@@ -1,6 +1,6 @@ - /** BEGIN COPYRIGHT BLOCK - * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. -- * Copyright (C) 2005 Red Hat, Inc. -+ * Copyright (C) 2005-2025 Red Hat, Inc. - * All rights reserved. - * - * License: GPL (version 3 or any later version). -@@ -69,20 +69,17 @@ static unsigned char PADDING[64] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - --/* F, G, H and I are basic MD5 functions. -- */ -+/* F, G, H and I are basic MD5 functions. */ - #define F(x, y, z) (((x) & (y)) | ((~(x)) & (z))) - #define G(x, y, z) (((x) & (z)) | ((y) & (~(z)))) - #define H(x, y, z) ((x) ^ (y) ^ (z)) - #define I(x, y, z) ((y) ^ ((x) | (~(z)))) - --/* ROTATE_LEFT rotates x left n bits. -- */ -+/* ROTATE_LEFT rotates x left n bits. */ - #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) - - /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. --Rotation is separate from addition to prevent recomputation. -- */ -+ * Rotation is separate from addition to prevent recomputation. */ - #define FF(a, b, c, d, x, s, ac) \ - { \ - (a) += F((b), (c), (d)) + (x) + (UINT4)(ac); \ -@@ -108,14 +105,11 @@ Rotation is separate from addition to prevent recomputation. - (a) += (b); \ - } - --/* MD5 initialization. Begins an MD5 operation, writing a new context. -- */ --void mta_MD5Init(context) -- mta_MD5_CTX *context; /* context */ -+/* MD5 initialization. Begins an MD5 operation, writing a new context. */ -+void mta_MD5Init(mta_MD5_CTX *context) - { - context->count[0] = context->count[1] = 0; -- /* Load magic initialization constants. --*/ -+ /* Load magic initialization constants */ - context->state[0] = 0x67452301; - context->state[1] = 0xefcdab89; - context->state[2] = 0x98badcfe; -@@ -123,13 +117,9 @@ void mta_MD5Init(context) - } - - /* MD5 block update operation. Continues an MD5 message-digest -- operation, processing another message block, and updating the -- context. -- */ --void mta_MD5Update(context, input, inputLen) -- mta_MD5_CTX *context; /* context */ --const unsigned char *input; /* input block */ --unsigned int inputLen; /* length of input block */ -+ * operation, processing another message block, and updating the -+ * context. */ -+void mta_MD5Update(mta_MD5_CTX *context, const unsigned char *input, unsigned int inputLen) - { - unsigned int i, index, partLen; - -@@ -143,8 +133,7 @@ unsigned int inputLen; /* length of input block */ - - partLen = 64 - index; - -- /* Transform as many times as possible. --*/ -+ /* Transform as many times as possible. */ - if (inputLen >= partLen) { - MD5_memcpy((POINTER)&context->buffer[index], (POINTER)input, partLen); - MD5Transform(context->state, context->buffer); -@@ -162,10 +151,8 @@ unsigned int inputLen; /* length of input block */ - } - - /* MD5 finalization. Ends an MD5 message-digest operation, writing the -- the message digest and zeroizing the context. -- */ --void mta_MD5Final(digest, context) unsigned char digest[16]; /* message digest */ --mta_MD5_CTX *context; /* context */ -+ * the message digest and zeroizing the context. */ -+void mta_MD5Final(unsigned char digest[16], mta_MD5_CTX *context) - { - unsigned char bits[8]; - unsigned int index, padLen; -@@ -173,8 +160,7 @@ mta_MD5_CTX *context; /* context */ - /* Save number of bits */ - Encode(bits, context->count, 8); - -- /* Pad out to 56 mod 64. --*/ -+ /* Pad out to 56 mod 64.*/ - index = (unsigned int)((context->count[0] >> 3) & 0x3f); - padLen = (index < 56) ? (56 - index) : (120 - index); - mta_MD5Update(context, PADDING, padLen); -@@ -185,16 +171,12 @@ mta_MD5_CTX *context; /* context */ - /* Store state in digest */ - Encode(digest, context->state, 16); - -- /* Zeroize sensitive information. --*/ -+ /* Zeroize sensitive information.*/ - MD5_memset((POINTER)context, 0, sizeof(*context)); - } - --/* MD5 basic transformation. Transforms state based on block. -- */ --static void MD5Transform(state, block) -- UINT4 state[4]; --const unsigned char block[64]; -+/* MD5 basic transformation. Transforms state based on block. */ -+static void MD5Transform(UINT4 state[4], const unsigned char block[64]) - { - UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; - -@@ -277,17 +259,13 @@ const unsigned char block[64]; - state[2] += c; - state[3] += d; - -- /* Zeroize sensitive information. --*/ -+ /* Zeroize sensitive information. */ - MD5_memset((POINTER)x, 0, sizeof(x)); - } - - /* Encodes input (UINT4) into output (unsigned char). Assumes len is -- a multiple of 4. -- */ --static void Encode(output, input, len) unsigned char *output; --const UINT4 *input; --unsigned int len; -+ * a multiple of 4. */ -+static void Encode(unsigned char *output, const UINT4 *input, unsigned int len) - { - unsigned int i, j; - -@@ -300,12 +278,8 @@ unsigned int len; - } - - /* Decodes input (unsigned char) into output (UINT4). Assumes len is -- a multiple of 4. -- */ --static void Decode(output, input, len) -- UINT4 *output; --const unsigned char *input; --unsigned int len; -+ * a multiple of 4. */ -+static void Decode(UINT4 *output, const unsigned char *input, unsigned int len) - { - unsigned int i, j; - -@@ -314,13 +288,8 @@ unsigned int len; - (((UINT4)input[j + 2]) << 16) | (((UINT4)input[j + 3]) << 24); - } - --/* Note: Replace "for loop" with standard memcpy if possible. -- */ -- --static void MD5_memcpy(output, input, len) -- POINTER output; --const POINTER input; --unsigned int len; -+/* Note: Replace "for loop" with standard memcpy if possible. */ -+static void MD5_memcpy(POINTER output, const POINTER input, unsigned int len) - { - unsigned int i; - -@@ -328,12 +297,8 @@ unsigned int len; - output[i] = input[i]; - } - --/* Note: Replace "for loop" with standard memset if possible. -- */ --static void MD5_memset(output, value, len) -- POINTER output; --int value; --unsigned int len; -+/* Note: Replace "for loop" with standard memset if possible. */ -+static void MD5_memset(POINTER output, int value, unsigned int len) - { - unsigned int i; - -diff --git a/ldap/servers/plugins/roles/roles_cache.c b/ldap/servers/plugins/roles/roles_cache.c -index 60f5a919a..9fadcdfc4 100644 ---- a/ldap/servers/plugins/roles/roles_cache.c -+++ b/ldap/servers/plugins/roles/roles_cache.c -@@ -156,8 +156,8 @@ static int roles_is_inscope(Slapi_Entry *entry_to_check, role_object *this_role) - static void berval_set_string(struct berval *bv, const char *string); - static void roles_cache_role_def_delete(roles_cache_def *role_def); - static void roles_cache_role_def_free(roles_cache_def *role_def); --static void roles_cache_role_object_free(role_object *this_role); --static int roles_cache_role_object_nested_free(role_object_nested *this_role); -+static int roles_cache_role_object_free(caddr_t this_role); -+static int roles_cache_role_object_nested_free(caddr_t this_role); - static int roles_cache_dump(caddr_t data, caddr_t arg); - static int roles_cache_add_entry_cb(Slapi_Entry *e, void *callback_data); - static void roles_cache_result_cb(int rc, void *callback_data); -@@ -578,11 +578,11 @@ roles_cache_update(roles_cache_def *suffix_to_update) - if ((operation == SLAPI_OPERATION_MODIFY) || - (operation == SLAPI_OPERATION_DELETE)) { - -- to_delete = (role_object *)avl_delete(&(suffix_to_update->avl_tree), dn, roles_cache_find_node); -- roles_cache_role_object_free(to_delete); -+ to_delete = (role_object *)avl_delete(&(suffix_to_update->avl_tree), (caddr_t)dn, roles_cache_find_node); -+ roles_cache_role_object_free((caddr_t)to_delete); - to_delete = NULL; - if (slapi_is_loglevel_set(SLAPI_LOG_PLUGIN)) { -- avl_apply(suffix_to_update->avl_tree, (IFP)roles_cache_dump, &rc, -1, AVL_INORDER); -+ avl_apply(suffix_to_update->avl_tree, roles_cache_dump, &rc, -1, AVL_INORDER); - } - } - if ((operation == SLAPI_OPERATION_MODIFY) || -@@ -1513,7 +1513,7 @@ roles_cache_listroles_ext(vattr_context *c, Slapi_Entry *entry, int return_value - /* XXX really need a mutex for this read operation ? */ - slapi_rwlock_rdlock(roles_cache->cache_lock); - -- avl_apply(roles_cache->avl_tree, (IFP)roles_cache_build_nsrole, &arg, -1, AVL_INORDER); -+ avl_apply(roles_cache->avl_tree, roles_cache_build_nsrole, &arg, -1, AVL_INORDER); - - slapi_rwlock_unlock(roles_cache->cache_lock); - -@@ -1630,7 +1630,7 @@ roles_check(Slapi_Entry *entry_to_check, Slapi_DN *role_dn, int *present) - } - slapi_rwlock_unlock(global_lock); - -- this_role = (role_object *)avl_find(roles_cache->avl_tree, role_dn, (IFP)roles_cache_find_node); -+ this_role = (role_object *)avl_find(roles_cache->avl_tree, (caddr_t)role_dn, roles_cache_find_node); - - /* MAB: For some reason the assumption made by this function (the role exists and is in scope) - * does not seem to be true... this_role might be NULL after the avl_find call (is the avl_tree -@@ -1768,7 +1768,7 @@ roles_is_entry_member_of_object_ext(vattr_context *c, caddr_t data, caddr_t argu - case ROLE_TYPE_NESTED: { - /* Go through the tree of the nested DNs */ - get_nsrole->hint++; -- avl_apply(this_role->avl_tree, (IFP)roles_check_nested, get_nsrole, 0, AVL_INORDER); -+ avl_apply(this_role->avl_tree, roles_check_nested, get_nsrole, 0, AVL_INORDER); - get_nsrole->hint--; - - /* kexcoff?? */ -@@ -1904,12 +1904,12 @@ roles_check_nested(caddr_t data, caddr_t arg) - } - - if (slapi_is_loglevel_set(SLAPI_LOG_PLUGIN)) { -- avl_apply(roles_cache->avl_tree, (IFP)roles_cache_dump, &rc, -1, AVL_INORDER); -+ avl_apply(roles_cache->avl_tree, roles_cache_dump, &rc, -1, AVL_INORDER); - } - - this_role = (role_object *)avl_find(roles_cache->avl_tree, -- current_nested_role->dn, -- (IFP)roles_cache_find_node); -+ (caddr_t)current_nested_role->dn, -+ roles_cache_find_node); - - if (this_role == NULL) { - /* the nested role doesn't exist */ -@@ -2029,7 +2029,7 @@ roles_cache_role_def_free(roles_cache_def *role_def) - - slapi_lock_mutex(role_def->stop_lock); - -- avl_free(role_def->avl_tree, (IFP)roles_cache_role_object_free); -+ avl_free(role_def->avl_tree, roles_cache_role_object_free); - slapi_sdn_free(&(role_def->suffix_dn)); - slapi_destroy_rwlock(role_def->cache_lock); - role_def->cache_lock = NULL; -@@ -2060,14 +2060,16 @@ roles_cache_role_def_free(roles_cache_def *role_def) - /* roles_cache_role_object_free - ---------------------------- - */ --static void --roles_cache_role_object_free(role_object *this_role) -+static int -+roles_cache_role_object_free(caddr_t tr) - { -+ role_object *this_role = (role_object *)tr; -+ - slapi_log_err(SLAPI_LOG_PLUGIN, - ROLES_PLUGIN_SUBSYSTEM, "--> roles_cache_role_object_free\n"); - - if (this_role == NULL) { -- return; -+ return 0; - } - - switch (this_role->type) { -@@ -2097,14 +2099,17 @@ roles_cache_role_object_free(role_object *this_role) - - slapi_log_err(SLAPI_LOG_PLUGIN, - ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_role_object_free\n"); -+ return 0; - } - - /* roles_cache_role_object_nested_free - ------------------------------------ - */ - static int --roles_cache_role_object_nested_free(role_object_nested *this_role) -+roles_cache_role_object_nested_free(caddr_t tr) - { -+ role_object_nested *this_role = (role_object_nested *)tr; -+ - slapi_log_err(SLAPI_LOG_PLUGIN, - ROLES_PLUGIN_SUBSYSTEM, "--> roles_cache_role_object_nested_free\n"); - -diff --git a/ldap/servers/plugins/syntaxes/bin.c b/ldap/servers/plugins/syntaxes/bin.c -index ab67cecf9..f793f3539 100644 ---- a/ldap/servers/plugins/syntaxes/bin.c -+++ b/ldap/servers/plugins/syntaxes/bin.c -@@ -139,7 +139,8 @@ static struct mr_plugin_def mr_plugin_table[] = { - NULL, - bin_compare, - NULL /* mr_normalize */ -- }}; -+ } -+}; - /* - certificateExactMatch - certificateListExactMatch -diff --git a/ldap/servers/plugins/syntaxes/syntax.h b/ldap/servers/plugins/syntaxes/syntax.h -index c743532c1..7e53c3586 100644 ---- a/ldap/servers/plugins/syntaxes/syntax.h -+++ b/ldap/servers/plugins/syntaxes/syntax.h -@@ -104,21 +104,22 @@ struct mr_plugin_def - Slapi_PluginDesc mr_plg_desc; /* for SLAPI_PLUGIN_DESCRIPTION */ - const char **mr_names; /* list of oid and names, NULL terminated SLAPI_PLUGIN_MR_NAMES */ - /* these are optional for new style mr plugins */ -- IFP mr_filter_create; /* old style factory function SLAPI_PLUGIN_MR_FILTER_CREATE_FN */ -- IFP mr_indexer_create; /* old style factory function SLAPI_PLUGIN_MR_INDEXER_CREATE_FN */ -+ int32_t (*mr_filter_create)(Slapi_PBlock *); /* old style factory function SLAPI_PLUGIN_MR_FILTER_CREATE_FN */ -+ int32_t (*mr_indexer_create)(Slapi_PBlock *); /* old style factory function SLAPI_PLUGIN_MR_INDEXER_CREATE_FN */ - /* new style syntax plugin functions */ - /* not all functions will apply to all matching rule types */ - /* e.g. a SUBSTR rule will not have a filter_ava func */ -- IFP mr_filter_ava; /* SLAPI_PLUGIN_MR_FILTER_AVA */ -- IFP mr_filter_sub; /* SLAPI_PLUGIN_MR_FILTER_SUB */ -- IFP mr_values2keys; /* SLAPI_PLUGIN_MR_VALUES2KEYS */ -- IFP mr_assertion2keys_ava; /* SLAPI_PLUGIN_MR_ASSERTION2KEYS_AVA */ -- IFP mr_assertion2keys_sub; /* SLAPI_PLUGIN_MR_ASSERTION2KEYS_SUB */ -- IFP mr_compare; /* SLAPI_PLUGIN_MR_COMPARE - only for ORDERING */ -- VFPV mr_normalize; -+ int32_t (*mr_filter_ava)(Slapi_PBlock *, struct berval *, Slapi_Value **, int32_t, Slapi_Value **); /* SLAPI_PLUGIN_MR_FILTER_AVA */ -+ int32_t (*mr_filter_sub)(Slapi_PBlock *, char *, char **, char *, Slapi_Value **); /* SLAPI_PLUGIN_MR_FILTER_SUB */ -+ int32_t (*mr_values2keys)(Slapi_PBlock *, Slapi_Value **, Slapi_Value ***, int32_t); /* SLAPI_PLUGIN_MR_VALUES2KEYS */ -+ int32_t (*mr_assertion2keys_ava)(Slapi_PBlock *, Slapi_Value *, Slapi_Value ***, int32_t); -+ int32_t (*mr_assertion2keys_sub)(Slapi_PBlock *, char *, char **, char *, Slapi_Value ***); /* SLAPI_PLUGIN_MR_ASSERTION2KEYS_SUB */ -+ int32_t (*mr_compare)(struct berval *, struct berval *); /* SLAPI_PLUGIN_MR_COMPARE - only for ORDERING */ -+ void (*mr_normalize)(Slapi_PBlock *, char *, int32_t, char **); - }; - --int syntax_register_matching_rule_plugins(struct mr_plugin_def mr_plugin_table[], size_t mr_plugin_table_size, IFP matching_rule_plugin_init); -+int syntax_register_matching_rule_plugins(struct mr_plugin_def mr_plugin_table[], size_t mr_plugin_table_size, -+ int32_t (*matching_rule_plugin_init)(Slapi_PBlock *)); - int syntax_matching_rule_plugin_init(Slapi_PBlock *pb, struct mr_plugin_def mr_plugin_table[], size_t mr_plugin_table_size); - - #endif -diff --git a/ldap/servers/plugins/syntaxes/syntax_common.c b/ldap/servers/plugins/syntaxes/syntax_common.c -index 821d4d557..7407f0b9c 100644 ---- a/ldap/servers/plugins/syntaxes/syntax_common.c -+++ b/ldap/servers/plugins/syntaxes/syntax_common.c -@@ -16,7 +16,7 @@ int - syntax_register_matching_rule_plugins( - struct mr_plugin_def mr_plugin_table[], - size_t mr_plugin_table_size, -- IFP matching_rule_plugin_init) -+ int32_t (*matching_rule_plugin_init)(Slapi_PBlock *)) - { - int rc = -1; - size_t ii; -diff --git a/ldap/servers/slapd/attrsyntax.c b/ldap/servers/slapd/attrsyntax.c -index 6bbcb05ac..e03ea6478 100644 ---- a/ldap/servers/slapd/attrsyntax.c -+++ b/ldap/servers/slapd/attrsyntax.c -@@ -608,10 +608,11 @@ attr_syntax_exists(const char *attr_name) - - static void default_dirstring_normalize_int(char *s, int trim_spaces); - --static int --default_dirstring_filter_ava(struct berval *bvfilter __attribute__((unused)), -- Slapi_Value **bvals __attribute__((unused)), -- int ftype __attribute__((unused)), -+static int32_t -+default_dirstring_filter_ava(Slapi_PBlock *pb __attribute__((unused)), -+ const struct berval *bv __attribute__((unused)), -+ Slapi_Value **vals __attribute__((unused)), -+ int32_t ftype __attribute__((unused)), - Slapi_Value **retVal __attribute__((unused))) - { - return (0); -@@ -621,7 +622,7 @@ static int - default_dirstring_values2keys(Slapi_PBlock *pb __attribute__((unused)), - Slapi_Value **bvals, - Slapi_Value ***ivals, -- int ftype) -+ int32_t ftype) - { - int numbvals = 0; - Slapi_Value **nbvals, **nbvlp; -@@ -664,11 +665,11 @@ default_dirstring_values2keys(Slapi_PBlock *pb __attribute__((unused)), - return (0); - } - --static int -+static int32_t - default_dirstring_assertion2keys_ava(Slapi_PBlock *pb __attribute__((unused)), - Slapi_Value *val __attribute__((unused)), - Slapi_Value ***ivals __attribute__((unused)), -- int ftype __attribute__((unused))) -+ int32_t ftype __attribute__((unused))) - { - return (0); - } -@@ -759,11 +760,11 @@ attr_syntax_default_plugin(const char *nameoroid) - pi->plg_syntax_oid = slapi_ch_strdup(nameoroid); - - -- pi->plg_syntax_filter_ava = (IFP)default_dirstring_filter_ava; -- pi->plg_syntax_values2keys = (IFP)default_dirstring_values2keys; -- pi->plg_syntax_assertion2keys_ava = (IFP)default_dirstring_assertion2keys_ava; -+ pi->plg_syntax_filter_ava = default_dirstring_filter_ava; -+ pi->plg_syntax_values2keys = default_dirstring_values2keys; -+ pi->plg_syntax_assertion2keys_ava = default_dirstring_assertion2keys_ava; - pi->plg_syntax_compare = (IFP)default_dirstring_cmp; -- pi->plg_syntax_normalize = (VFPV)default_dirstring_normalize; -+ pi->plg_syntax_normalize = default_dirstring_normalize; - - return (pi); - } -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 2bb6b0267..23dd7983f 100644 ---- a/ldap/servers/slapd/back-ldbm/db-bdb/bdb_import.c -+++ b/ldap/servers/slapd/back-ldbm/db-bdb/bdb_import.c -@@ -1298,8 +1298,10 @@ bdb_update_subordinatecounts(backend *be, ImportJob *job, DB_TXN *txn) - - /* Function used to gather a list of indexed attrs */ - static int --bdb_import_attr_callback(void *node, void *param) -+bdb_import_attr_callback(caddr_t n, caddr_t p) - { -+ void *node = (void *)n; -+ void *param = (void *)p; - ImportJob *job = (ImportJob *)param; - struct attrinfo *a = (struct attrinfo *)node; - -@@ -2215,9 +2217,9 @@ bdb_public_bdb_import_main(void *arg) - /* Here, we get an AVL tree which contains nodes for all attributes - * in the schema. Given this tree, we need to identify those nodes - * which are marked for indexing. */ -- avl_apply(job->inst->inst_attrs, (IFP)bdb_import_attr_callback, -+ avl_apply(job->inst->inst_attrs, bdb_import_attr_callback, - (caddr_t)job, -1, AVL_INORDER); -- vlv_getindices((IFP)bdb_import_attr_callback, (void *)job, be); -+ vlv_getindices(bdb_import_attr_callback, (void *)job, be); - } - - /* Determine how much index buffering space to allocate to each index */ -diff --git a/ldap/servers/slapd/back-ldbm/db-mdb/mdb_import.c b/ldap/servers/slapd/back-ldbm/db-mdb/mdb_import.c -index d0efc1bca..f945f5a59 100644 ---- a/ldap/servers/slapd/back-ldbm/db-mdb/mdb_import.c -+++ b/ldap/servers/slapd/back-ldbm/db-mdb/mdb_import.c -@@ -347,9 +347,11 @@ dbmdb_update_subordinatecounts(backend *be, ImportJob *job, dbi_txn_t *txn) - } - - /* Function used to gather a list of indexed attrs */ --static int --dbmdb_import_attr_callback(void *node, void *param) -+static int32_t -+dbmdb_import_attr_callback(caddr_t n, caddr_t p) - { -+ void *node = (void *)n; -+ void *param = (void *)p; - ImportJob *job = (ImportJob *)param; - struct attrinfo *a = (struct attrinfo *)node; - -@@ -788,11 +790,11 @@ dbmdb_import_all_done(ImportJob *job, int ret) - /* Bring backend online again: - * In lmdb case, the import framework is also used for reindexing - * while in bdb case reindexing uses its own code. -- * So dbmdb_import_all_done is called either after -+ * So dbmdb_import_all_done is called either after - * dbmdb_ldif2db or after dbmdb_db2index while - * bdb_import_all_done is only called after bdb_ldif2db. - * -- * dbmdb_db2index uses instance_set_busy_and_readonly -+ * dbmdb_db2index uses instance_set_busy_and_readonly - * while dbmdb_ldif2db uses slapi_mtn_be_disable - * and these functions have to be reverted accordingly. - */ -@@ -821,9 +823,12 @@ dbmdb_import_all_done(ImportJob *job, int ret) - - /* vlv_getindices callback that truncate vlv index (in reindex case) */ - static int --truncate_index_dbi(struct attrinfo *ai, ImportCtx_t *ctx) -+truncate_index_dbi(caddr_t a, caddr_t c) - { -+ struct attrinfo *ai = (struct attrinfo *)a; -+ ImportCtx_t *ctx = (ImportCtx_t *)c; - int rc = 0; -+ - if (is_reindexed_attr(ai->ai_type, ctx, ctx->indexVlvs)) { - backend *be = ctx->job->inst->inst_be; - dbmdb_dbi_t *dbi = NULL; -@@ -878,9 +883,9 @@ dbmdb_public_dbmdb_import_main(void *arg) - /* Here, we get an AVL tree which contains nodes for all attributes - * in the schema. Given this tree, we need to identify those nodes - * which are marked for indexing. */ -- avl_apply(job->inst->inst_attrs, (IFP)dbmdb_import_attr_callback, -+ avl_apply(job->inst->inst_attrs, dbmdb_import_attr_callback, - (caddr_t)job, -1, AVL_INORDER); -- vlv_getindices((IFP)dbmdb_import_attr_callback, (void *)job, be); -+ vlv_getindices(dbmdb_import_attr_callback, (void *)job, be); - } - - /* insure all dbi get open */ -@@ -901,7 +906,7 @@ dbmdb_public_dbmdb_import_main(void *arg) - pthread_mutex_unlock(&job->wire_lock); - break; - case IM_INDEX: -- vlv_getindices((IFP)truncate_index_dbi, ctx, job->inst->inst_be); -+ vlv_getindices(truncate_index_dbi, ctx, job->inst->inst_be); - default: - break; - } -diff --git a/ldap/servers/slapd/back-ldbm/db-mdb/mdb_import_threads.c b/ldap/servers/slapd/back-ldbm/db-mdb/mdb_import_threads.c -index 6978bf5e3..545099b5f 100644 ---- a/ldap/servers/slapd/back-ldbm/db-mdb/mdb_import_threads.c -+++ b/ldap/servers/slapd/back-ldbm/db-mdb/mdb_import_threads.c -@@ -2895,7 +2895,7 @@ look4indexinfo(ImportCtx_t *ctx, const char *attrname) - { - MdbIndexInfo_t searched_mii = {0}; - searched_mii.name = (char*) attrname; -- return (MdbIndexInfo_t *)avl_find(ctx->indexes, &searched_mii, cmp_mii); -+ return (MdbIndexInfo_t *)avl_find(ctx->indexes, (caddr_t)&searched_mii, cmp_mii); - } - - /* Prepare key and data for updating parentid or ancestorid indexes */ -@@ -3460,7 +3460,7 @@ dbmdb_add_import_index(ImportCtx_t *ctx, const char *name, IndexInfo *ii) - - DBG_LOG(DBGMDB_LEVEL_OTHER,"Calling dbmdb_open_dbi_from_filename for %s flags = 0x%x", mii->name, dbi_flags); - dbmdb_open_dbi_from_filename(&mii->dbi, job->inst->inst_be, mii->name, mii->ai, dbi_flags); -- avl_insert(&ctx->indexes, mii, cmp_mii, NULL); -+ avl_insert(&ctx->indexes, (caddr_t)mii, cmp_mii, NULL); - } - - /* -@@ -3486,7 +3486,7 @@ dbmdb_open_redirect_db(ImportCtx_t *ctx) - mii->ai = ai; - mii->flags = MII_SKIP | MII_NOATTR; - dbmdb_open_dbi_from_filename(&mii->dbi, be, mii->name, mii->ai, dbi_flags); -- avl_insert(&ctx->indexes, mii, cmp_mii, NULL); -+ avl_insert(&ctx->indexes, (caddr_t)mii, cmp_mii, NULL); - ctx->redirect = mii; - } - -@@ -3532,11 +3532,13 @@ dbmdb_build_import_index_list(ImportCtx_t *ctx) - - } - --void --free_ii(MdbIndexInfo_t *ii) -+static int32_t -+free_ii(caddr_t i) - { -+ MdbIndexInfo_t *ii = (MdbIndexInfo_t *)i; - slapi_ch_free_string(&ii->name); - slapi_ch_free((void**)&ii); -+ return 0; - } - - /* -@@ -4338,7 +4340,7 @@ dbmdb_free_import_ctx(ImportJob *job) - dbmdb_import_q_destroy(&ctx->bulkq); - slapi_ch_free((void**)&ctx->id2entry->name); - slapi_ch_free((void**)&ctx->id2entry); -- avl_free(ctx->indexes, (IFP) free_ii); -+ avl_free(ctx->indexes, free_ii); - ctx->indexes = NULL; - charray_free(ctx->indexAttrs); - charray_free(ctx->indexVlvs); -diff --git a/ldap/servers/slapd/back-ldbm/db-mdb/mdb_instance.c b/ldap/servers/slapd/back-ldbm/db-mdb/mdb_instance.c -index 682fd70e2..145811237 100644 ---- a/ldap/servers/slapd/back-ldbm/db-mdb/mdb_instance.c -+++ b/ldap/servers/slapd/back-ldbm/db-mdb/mdb_instance.c -@@ -336,8 +336,10 @@ int add_dbi(dbi_open_ctx_t *octx, backend *be, const char *fname, int flags) - - /* avlapply callback to open/create the dbi needed to handle an index */ - static int --add_index_dbi(struct attrinfo *ai, dbi_open_ctx_t *octx) -+add_index_dbi(caddr_t attr, caddr_t otx) - { -+ struct attrinfo *ai = (struct attrinfo *)attr; -+ dbi_open_ctx_t *octx = (dbi_open_ctx_t *)otx; - int flags = octx->ctx->readonly ? MDB_RDONLY: MDB_CREATE; - char *rcdbname = NULL; - -@@ -473,7 +475,7 @@ dbmdb_open_all_files(dbmdb_ctx_t *ctx, backend *be) - } - if (be->vlvSearchList_lock) { - /* vlv search list is initialized so we can use it */ -- vlv_getindices((IFP)add_index_dbi, &octx, be); -+ vlv_getindices(add_index_dbi, &octx, be); - } else if (vlv_list) { - char *rcdbname = NULL; - for (size_t i=0; rc == 0 && vlv_list[i]; i++) { -diff --git a/ldap/servers/slapd/back-ldbm/filterindex.c b/ldap/servers/slapd/back-ldbm/filterindex.c -index 8bb22570b..c01a58ccd 100644 ---- a/ldap/servers/slapd/back-ldbm/filterindex.c -+++ b/ldap/servers/slapd/back-ldbm/filterindex.c -@@ -462,7 +462,7 @@ extensible_candidates( - case SLAPI_OP_EQUAL: - case SLAPI_OP_GREATER_OR_EQUAL: - case SLAPI_OP_GREATER: { -- IFP mrINDEX = NULL; -+ int32_t (*mrINDEX)(Slapi_PBlock *) = NULL; - void *mrOBJECT = NULL; - struct berval **mrVALUES = NULL; - char *mrOID = NULL; -diff --git a/ldap/servers/slapd/back-ldbm/ldbm_attr.c b/ldap/servers/slapd/back-ldbm/ldbm_attr.c -index 30bfd1349..7fe6f1405 100644 ---- a/ldap/servers/slapd/back-ldbm/ldbm_attr.c -+++ b/ldap/servers/slapd/back-ldbm/ldbm_attr.c -@@ -68,7 +68,7 @@ attrinfo_delete(struct attrinfo **pp) - } - - static int --attrinfo_internal_delete(caddr_t data, caddr_t arg __attribute__((unused))) -+attrinfo_internal_delete(caddr_t data) - { - struct attrinfo *n = (struct attrinfo *)data; - attrinfo_delete(&n); -@@ -85,16 +85,19 @@ attrinfo_deletetree(ldbm_instance *inst) - static int - ainfo_type_cmp( - char *type, -- struct attrinfo *a) -+ caddr_t val) - { -+ struct attrinfo *a = (struct attrinfo *)val; - return (strcasecmp(type, a->ai_type)); - } - - static int - ainfo_cmp( -- struct attrinfo *a, -- struct attrinfo *b) -+ caddr_t val1, -+ caddr_t val2) - { -+ struct attrinfo *a = (struct attrinfo *)val1; -+ struct attrinfo *b = (struct attrinfo *)val2; - return (strcasecmp(a->ai_type, b->ai_type)); - } - -@@ -102,7 +105,7 @@ 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); -+ avl_delete(&inst->inst_attrs, (caddr_t)ai, ainfo_cmp); - } - - /* -@@ -117,9 +120,12 @@ attrinfo_delete_from_tree(backend *be, struct attrinfo *ai) - - static int - ainfo_dup( -- struct attrinfo *a, -- struct attrinfo *b) -+ caddr_t val1, -+ caddr_t val2) - { -+ struct attrinfo *a = (struct attrinfo *)val1; -+ struct attrinfo *b = (struct attrinfo *)val2; -+ - /* merge duplicate indexing information */ - if (b->ai_indexmask == 0 || b->ai_indexmask == INDEX_OFFLINE) { - a->ai_indexmask = INDEX_OFFLINE; /* turns off all indexes */ -@@ -203,7 +209,7 @@ attr_index_parse_idlistsize_values(Slapi_Attr *attr, struct index_idlistsizeinfo - char *lasts = NULL; - char *val; - int syntaxcheck = config_get_syntaxcheck(); -- IFP syntax_validate_fn = syntaxcheck ? attr->a_plugin->plg_syntax_validate : NULL; -+ int32_t (*syntax_validate_fn)(struct berval *) = syntaxcheck ? attr->a_plugin->plg_syntax_validate : NULL; - char staticfiltstrbuf[1024]; /* for small filter strings */ - char *filtstrbuf = staticfiltstrbuf; /* default if not malloc'd */ - size_t filtstrbuflen = sizeof(staticfiltstrbuf); /* default if not malloc'd */ -@@ -880,7 +886,7 @@ attr_index_config( - * It would improve speed to save the indexer, for future use. - * But, for simplicity, we destroy it now: - */ -- IFP mrDESTROY = NULL; -+ int32_t (*mrDESTROY)(Slapi_PBlock *) = NULL; - if (!slapi_pblock_get(pb, SLAPI_PLUGIN_DESTROY_FN, &mrDESTROY) && - mrDESTROY != NULL) { - mrDESTROY(pb); -@@ -941,7 +947,7 @@ attr_index_config( - } - } - -- if (avl_insert(&inst->inst_attrs, a, ainfo_cmp, ainfo_dup) != 0) { -+ if (avl_insert(&inst->inst_attrs, (caddr_t)a, ainfo_cmp, ainfo_dup) != 0) { - /* duplicate - existing version updated */ - attrinfo_delete(&a); - } -@@ -964,7 +970,7 @@ attr_create_empty(backend *be, char *type, struct attrinfo **ai) - struct attrinfo *a = attrinfo_new(); - slapi_attr_init(&a->ai_sattr, type); - a->ai_type = slapi_ch_strdup(type); -- if (avl_insert(&inst->inst_attrs, a, ainfo_cmp, ainfo_dup) != 0) { -+ if (avl_insert(&inst->inst_attrs, (caddr_t)a, ainfo_cmp, ainfo_dup) != 0) { - /* duplicate - existing version updated */ - attrinfo_delete(&a); - ainfo_get(be, type, &a); -diff --git a/ldap/servers/slapd/back-ldbm/matchrule.c b/ldap/servers/slapd/back-ldbm/matchrule.c -index 5365e8acf..85ff87b95 100644 ---- a/ldap/servers/slapd/back-ldbm/matchrule.c -+++ b/ldap/servers/slapd/back-ldbm/matchrule.c -@@ -79,7 +79,7 @@ int - destroy_matchrule_indexer(Slapi_PBlock *pb) - { - Slapi_Value **keys = NULL; -- IFP mrDESTROY = NULL; -+ int32_t (*mrDESTROY)(Slapi_PBlock *) = NULL; - if (!slapi_pblock_get(pb, SLAPI_PLUGIN_DESTROY_FN, &mrDESTROY)) { - if (mrDESTROY != NULL) { - mrDESTROY(pb); -@@ -109,7 +109,7 @@ destroy_matchrule_indexer(Slapi_PBlock *pb) - int - matchrule_values_to_keys(Slapi_PBlock *pb, Slapi_Value **input_values, struct berval ***output_values) - { -- IFP mrINDEX = NULL; -+ int32_t (*mrINDEX)(Slapi_PBlock *) = NULL; - - slapi_pblock_get(pb, SLAPI_PLUGIN_MR_INDEX_FN, &mrINDEX); - slapi_pblock_set(pb, SLAPI_PLUGIN_MR_VALUES, input_values); -@@ -130,7 +130,7 @@ matchrule_values_to_keys(Slapi_PBlock *pb, Slapi_Value **input_values, struct be - int - matchrule_values_to_keys_sv(Slapi_PBlock *pb, Slapi_Value **input_values, Slapi_Value ***output_values) - { -- IFP mrINDEX = NULL; -+ int32_t (*mrINDEX)(Slapi_PBlock *) = NULL; - - slapi_pblock_get(pb, SLAPI_PLUGIN_MR_INDEX_SV_FN, &mrINDEX); - if (NULL == mrINDEX) { /* old school - does not have SV function */ -diff --git a/ldap/servers/slapd/back-ldbm/misc.c b/ldap/servers/slapd/back-ldbm/misc.c -index 309cc8a94..4ced0f1da 100644 ---- a/ldap/servers/slapd/back-ldbm/misc.c -+++ b/ldap/servers/slapd/back-ldbm/misc.c -@@ -329,7 +329,7 @@ ldbm_txn_ruv_modify_context(Slapi_PBlock *pb, modify_context *mc) - Slapi_Mods *smods = NULL; - struct backentry *bentry; - entry_address bentry_addr; -- IFP fn = NULL; -+ int32_t (*fn)(Slapi_PBlock *, char **, Slapi_Mods **) = NULL; - int rc = 0; - back_txn txn = {NULL}; - -diff --git a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h -index f16c37d73..29d196f39 100644 ---- a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h -+++ b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h -@@ -499,7 +499,7 @@ int vlv_trim_candidates_txn(backend *be, const IDList *candidates, const sort_sp - int vlv_trim_candidates(backend *be, const IDList *candidates, const sort_spec *sort_control, const struct vlv_request *vlv_request_control, IDList **filteredCandidates, struct vlv_response *pResponse); - int vlv_parse_request_control(backend *be, struct berval *vlv_spec_ber, struct vlv_request *vlvp); - int vlv_make_response_control(Slapi_PBlock *pb, const struct vlv_response *vlvp); --void vlv_getindices(IFP callback_fn, void *param, backend *be); -+void vlv_getindices(int32_t (*callback_fn)(caddr_t, caddr_t), void *param, backend *be); - void vlv_print_access_log(Slapi_PBlock *pb, struct vlv_request *vlvi, struct vlv_response *vlvo); - void vlv_grok_new_import_entry(const struct backentry *e, backend *be, int *seen_them_all); - IDList *vlv_find_index_by_filter(struct backend *be, const char *base, Slapi_Filter *f); -diff --git a/ldap/servers/slapd/back-ldbm/vlv.c b/ldap/servers/slapd/back-ldbm/vlv.c -index a1cd226f4..b5dd1ea55 100644 ---- a/ldap/servers/slapd/back-ldbm/vlv.c -+++ b/ldap/servers/slapd/back-ldbm/vlv.c -@@ -673,7 +673,7 @@ vlv_getindexnames(backend *be) - /* Return the list of VLV indices to the import code. Added read lock */ - - void --vlv_getindices(IFP callback_fn, void *param, backend *be) -+vlv_getindices(int32_t (*callback_fn)(caddr_t, caddr_t), void *param, backend *be) - { - /* Traverse the list, calling the import code's callback function */ - struct vlvSearch *ps = NULL; -@@ -683,7 +683,7 @@ vlv_getindices(IFP callback_fn, void *param, backend *be) - for (; ps != NULL; ps = ps->vlv_next) { - struct vlvIndex *pi = ps->vlv_index; - for (; pi != NULL; pi = pi->vlv_next) { -- callback_fn(pi->vlv_attrinfo, param); -+ callback_fn((caddr_t)(pi->vlv_attrinfo), (caddr_t)param); - } - } - slapi_rwlock_unlock(be->vlvSearchList_lock); -diff --git a/ldap/servers/slapd/backend.c b/ldap/servers/slapd/backend.c -index 0a2555a9b..cf3c2ebbc 100644 ---- a/ldap/servers/slapd/backend.c -+++ b/ldap/servers/slapd/backend.c -@@ -502,6 +502,7 @@ slapi_be_getentrypoint(Slapi_Backend *be, int entrypoint, void **ret_fnptr, Slap - return 0; - } - -+ - int - slapi_be_setentrypoint(Slapi_Backend *be, int entrypoint, void *ret_fnptr, Slapi_PBlock *pb) - { -@@ -517,61 +518,61 @@ slapi_be_setentrypoint(Slapi_Backend *be, int entrypoint, void *ret_fnptr, Slapi - - switch (entrypoint) { - case SLAPI_PLUGIN_DB_BIND_FN: -- be->be_bind = (IFP)ret_fnptr; -+ be->be_bind = ret_fnptr; - break; - case SLAPI_PLUGIN_DB_UNBIND_FN: -- be->be_unbind = (IFP)ret_fnptr; -+ be->be_unbind = ret_fnptr; - break; - case SLAPI_PLUGIN_DB_SEARCH_FN: -- be->be_search = (IFP)ret_fnptr; -+ be->be_search = ret_fnptr; - break; - case SLAPI_PLUGIN_DB_COMPARE_FN: -- be->be_compare = (IFP)ret_fnptr; -+ be->be_compare = ret_fnptr; - break; - case SLAPI_PLUGIN_DB_MODIFY_FN: -- be->be_modify = (IFP)ret_fnptr; -+ be->be_modify = ret_fnptr; - break; - case SLAPI_PLUGIN_DB_MODRDN_FN: -- be->be_modrdn = (IFP)ret_fnptr; -+ be->be_modrdn = ret_fnptr; - break; - case SLAPI_PLUGIN_DB_ADD_FN: -- be->be_add = (IFP)ret_fnptr; -+ be->be_add = ret_fnptr; - break; - case SLAPI_PLUGIN_DB_DELETE_FN: -- be->be_delete = (IFP)ret_fnptr; -+ be->be_delete = ret_fnptr; - break; - case SLAPI_PLUGIN_DB_ABANDON_FN: -- be->be_abandon = (IFP)ret_fnptr; -+ be->be_abandon = ret_fnptr; - break; - case SLAPI_PLUGIN_DB_CONFIG_FN: -- be->be_config = (IFP)ret_fnptr; -+ be->be_config = ret_fnptr; - break; - case SLAPI_PLUGIN_CLOSE_FN: -- be->be_close = (IFP)ret_fnptr; -+ be->be_close = ret_fnptr; - break; - case SLAPI_PLUGIN_START_FN: -- be->be_start = (IFP)ret_fnptr; -+ be->be_start = ret_fnptr; - break; - case SLAPI_PLUGIN_DB_RESULT_FN: -- be->be_result = (IFP)ret_fnptr; -+ be->be_result = ret_fnptr; - break; - case SLAPI_PLUGIN_DB_LDIF2DB_FN: -- be->be_ldif2db = (IFP)ret_fnptr; -+ be->be_ldif2db = ret_fnptr; - break; - case SLAPI_PLUGIN_DB_DB2LDIF_FN: -- be->be_db2ldif = (IFP)ret_fnptr; -+ be->be_db2ldif = ret_fnptr; - break; - case SLAPI_PLUGIN_DB_ARCHIVE2DB_FN: -- be->be_archive2db = (IFP)ret_fnptr; -+ be->be_archive2db = ret_fnptr; - break; - case SLAPI_PLUGIN_DB_DB2ARCHIVE_FN: -- be->be_db2archive = (IFP)ret_fnptr; -+ be->be_db2archive = ret_fnptr; - break; - case SLAPI_PLUGIN_DB_NEXT_SEARCH_ENTRY_FN: -- be->be_next_search_entry = (IFP)ret_fnptr; -+ be->be_next_search_entry = ret_fnptr; - break; - case SLAPI_PLUGIN_DB_NEXT_SEARCH_ENTRY_EXT_FN: -- be->be_next_search_entry_ext = (IFP)ret_fnptr; -+ be->be_next_search_entry_ext = ret_fnptr; - break; - case SLAPI_PLUGIN_DB_SEARCH_RESULTS_RELEASE_FN: - be->be_search_results_release = (VFPP)ret_fnptr; -@@ -580,19 +581,19 @@ slapi_be_setentrypoint(Slapi_Backend *be, int entrypoint, void *ret_fnptr, Slapi - be->be_prev_search_results = (VFP)ret_fnptr; - break; - case SLAPI_PLUGIN_DB_TEST_FN: -- be->be_dbtest = (IFP)ret_fnptr; -+ be->be_dbtest = ret_fnptr; - break; - case SLAPI_PLUGIN_DB_RMDB_FN: -- be->be_rmdb = (IFP)ret_fnptr; -+ be->be_rmdb = ret_fnptr; - break; - case SLAPI_PLUGIN_DB_SEQ_FN: -- be->be_seq = (IFP)ret_fnptr; -+ be->be_seq = ret_fnptr; - break; - case SLAPI_PLUGIN_DB_DB2INDEX_FN: -- be->be_db2index = (IFP)ret_fnptr; -+ be->be_db2index = ret_fnptr; - break; - case SLAPI_PLUGIN_CLEANUP_FN: -- be->be_cleanup = (IFP)ret_fnptr; -+ be->be_cleanup = ret_fnptr; - break; - default: - slapi_log_err(SLAPI_LOG_ERR, "slapi_be_setentrypoint", -@@ -682,7 +683,7 @@ slapi_back_ctrl_info(Slapi_Backend *be, int cmd, void *info) - int - slapi_back_transaction_begin(Slapi_PBlock *pb) - { -- IFP txn_begin; -+ int32_t (*txn_begin)(Slapi_PBlock *); - if (slapi_pblock_get(pb, SLAPI_PLUGIN_DB_BEGIN_FN, (void *)&txn_begin) || - !txn_begin) { - return SLAPI_BACK_TRANSACTION_NOT_SUPPORTED; -@@ -695,7 +696,7 @@ slapi_back_transaction_begin(Slapi_PBlock *pb) - int - slapi_back_transaction_commit(Slapi_PBlock *pb) - { -- IFP txn_commit; -+ int32_t (*txn_commit)(Slapi_PBlock *); - if (slapi_pblock_get(pb, SLAPI_PLUGIN_DB_COMMIT_FN, (void *)&txn_commit) || - !txn_commit) { - return SLAPI_BACK_TRANSACTION_NOT_SUPPORTED; -@@ -708,7 +709,7 @@ slapi_back_transaction_commit(Slapi_PBlock *pb) - int - slapi_back_transaction_abort(Slapi_PBlock *pb) - { -- IFP txn_abort; -+ int32_t (*txn_abort)(Slapi_PBlock *); - if (slapi_pblock_get(pb, SLAPI_PLUGIN_DB_ABORT_FN, (void *)&txn_abort) || - !txn_abort) { - return SLAPI_BACK_TRANSACTION_NOT_SUPPORTED; -diff --git a/ldap/servers/slapd/dse.c b/ldap/servers/slapd/dse.c -index a0db367b2..bec3e32f4 100644 ---- a/ldap/servers/slapd/dse.c -+++ b/ldap/servers/slapd/dse.c -@@ -120,7 +120,7 @@ typedef struct dse_search_set - - static int dse_permission_to_write(struct dse *pdse, int loglevel); - static int dse_write_file_nolock(struct dse *pdse); --static int dse_apply_nolock(struct dse *pdse, IFP fp, caddr_t arg); -+static int dse_apply_nolock(struct dse *pdse, int32_t (*fp)(caddr_t, caddr_t), caddr_t arg); - static int dse_replace_entry(struct dse *pdse, Slapi_Entry *e, int write_file, int use_lock); - static dse_search_set *dse_search_set_new(void); - static void dse_search_set_delete(dse_search_set *ss); -@@ -257,7 +257,7 @@ dse_find_node(struct dse *pdse, const Slapi_DN *dn) - slapi_entry_set_sdn(fe, dn); - searchNode.entry = fe; - -- n = (struct dse_node *)avl_find(pdse->dse_tree, &searchNode, entry_dn_cmp); -+ n = (struct dse_node *)avl_find(pdse->dse_tree, (caddr_t)&searchNode, entry_dn_cmp); - - slapi_entry_free(fe); - } -@@ -491,7 +491,7 @@ dse_new_with_filelist(char *filename, char *tmpfilename, char *backfilename, cha - } - - static int --dse_internal_delete_entry(caddr_t data, caddr_t arg __attribute__((unused))) -+dse_internal_delete_entry(caddr_t data) - { - struct dse_node *n = (struct dse_node *)data; - dse_node_delete(&n); -@@ -1290,9 +1290,9 @@ dse_add_entry_pb(struct dse *pdse, Slapi_Entry *e, Slapi_PBlock *pb) - /* keep write lock during both tree update and file write operations */ - dse_lock_write(pdse, DSE_USE_LOCK); - if (merge) { -- rc = avl_insert(&(pdse->dse_tree), n, entry_dn_cmp, dupentry_merge); -+ rc = avl_insert(&(pdse->dse_tree), (caddr_t)n, entry_dn_cmp, dupentry_merge); - } else { -- rc = avl_insert(&(pdse->dse_tree), n, entry_dn_cmp, dupentry_disallow); -+ rc = avl_insert(&(pdse->dse_tree), (caddr_t)n, entry_dn_cmp, dupentry_disallow); - } - if (-1 != rc) { - /* update num sub of parent with no lock; we already hold the write lock */ -@@ -1479,7 +1479,7 @@ dse_replace_entry(struct dse *pdse, Slapi_Entry *e, int write_file, int use_lock - if (NULL != e) { - struct dse_node *n = dse_node_new(e); - dse_lock_write(pdse, use_lock); -- rc = avl_insert(&(pdse->dse_tree), n, entry_dn_cmp, dupentry_replace); -+ rc = avl_insert(&(pdse->dse_tree), (caddr_t)n, entry_dn_cmp, dupentry_replace); - if (write_file) - dse_write_file_nolock(pdse); - /* If the entry was replaced i.e. not added as a new entry, we need to -@@ -1554,7 +1554,7 @@ dse_read_next_entry(char *buf, char **lastp) - * searching, a read lock, for modifying in place, a write lock - */ - static int --dse_apply_nolock(struct dse *pdse, IFP fp, caddr_t arg) -+dse_apply_nolock(struct dse *pdse, int32_t (*fp)(caddr_t, caddr_t), caddr_t arg) - { - avl_apply(pdse->dse_tree, fp, arg, STOP_TRAVERSAL, AVL_INORDER); - return 1; -@@ -1576,7 +1576,7 @@ dse_delete_entry(struct dse *pdse, Slapi_PBlock *pb, const Slapi_Entry *e) - - /* keep write lock for both tree deleting and file writing */ - dse_lock_write(pdse, DSE_USE_LOCK); -- if ((deleted_node = (struct dse_node *)avl_delete(&pdse->dse_tree, n, entry_dn_cmp))) { -+ if ((deleted_node = (struct dse_node *)avl_delete(&pdse->dse_tree, (caddr_t)n, entry_dn_cmp))) { - dse_node_delete(&deleted_node); - } - dse_node_delete(&n); -diff --git a/ldap/servers/slapd/entry.c b/ldap/servers/slapd/entry.c -index 235410e45..6040eb419 100644 ---- a/ldap/servers/slapd/entry.c -+++ b/ldap/servers/slapd/entry.c -@@ -709,7 +709,7 @@ entry_attrs_add(entry_attrs *ea, const char *atname, int atarrayindex) - ead->ead_attrarrayindex = atarrayindex; - ead->ead_attrtypename = atname; /* a reference, not a strdup! */ - -- avl_insert(&(ea->ea_attrlist), ead, attr_type_node_cmp, avl_dup_error); -+ avl_insert(&(ea->ea_attrlist), (caddr_t)ead, attr_type_node_cmp, avl_dup_error); - } - - /* -@@ -723,7 +723,7 @@ entry_attrs_find(entry_attrs *ea, char *type) - entry_attr_data *foundead; - - tmpead.ead_attrtypename = type; -- foundead = (entry_attr_data *)avl_find(ea->ea_attrlist, &tmpead, -+ foundead = (entry_attr_data *)avl_find(ea->ea_attrlist, (caddr_t)&tmpead, - attr_type_node_cmp); - return (NULL != foundead) ? foundead->ead_attrarrayindex : -1; - } -diff --git a/ldap/servers/slapd/filtercmp.c b/ldap/servers/slapd/filtercmp.c -index 3e17796e9..0d8764b5a 100644 ---- a/ldap/servers/slapd/filtercmp.c -+++ b/ldap/servers/slapd/filtercmp.c -@@ -86,7 +86,7 @@ get_mr_normval(char *oid, char *type, struct berval **inval, struct berval ***ou - { - Slapi_PBlock *pb = slapi_pblock_new(); - unsigned int sort_indicator = SLAPI_PLUGIN_MR_USAGE_SORT; -- IFP mrIndex = NULL; -+ int32_t (*mrIndex)(Slapi_PBlock *) = NULL; - - if (!pb) { - return NULL; -@@ -118,7 +118,7 @@ get_mr_normval(char *oid, char *type, struct berval **inval, struct berval ***ou - static void - done_mr_normval(Slapi_PBlock *pb) - { -- IFP mrDestroy = NULL; -+ int32_t (*mrDestroy)(Slapi_PBlock *) = NULL; - - if (slapi_pblock_get(pb, SLAPI_PLUGIN_DESTROY_FN, &mrDestroy) == 0) { - if (mrDestroy) -diff --git a/ldap/servers/slapd/getfilelist.c b/ldap/servers/slapd/getfilelist.c -index dd5deb282..2fd164baf 100644 ---- a/ldap/servers/slapd/getfilelist.c -+++ b/ldap/servers/slapd/getfilelist.c -@@ -46,9 +46,11 @@ struct path_wrapper - int order; - }; - --static int --path_wrapper_cmp(struct path_wrapper *p1, struct path_wrapper *p2) -+static int32_t -+path_wrapper_cmp(caddr_t pwc1, caddr_t pwc2) - { -+ struct path_wrapper *p1 = (struct path_wrapper *)pwc1; -+ struct path_wrapper *p2 = (struct path_wrapper *)pwc2; - if (p1->order < p2->order) { - /* p1 is "earlier" so put it first */ - return -1; -@@ -217,7 +219,7 @@ get_filelist( - pw_ptr->path = slapi_ch_smprintf("%s/%s", dirname, dirent->name); - pw_ptr->filename = slapi_ch_strdup(dirent->name); - pw_ptr->order = i; -- avl_insert(&filetree, pw_ptr, path_wrapper_cmp, 0); -+ avl_insert(&filetree, (caddr_t)pw_ptr, path_wrapper_cmp, 0); - num++; - } - } -diff --git a/ldap/servers/slapd/pblock.c b/ldap/servers/slapd/pblock.c -index 3801326c4..76e26cb86 100644 ---- a/ldap/servers/slapd/pblock.c -+++ b/ldap/servers/slapd/pblock.c -@@ -1,6 +1,6 @@ - /** BEGIN COPYRIGHT BLOCK - * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. -- * Copyright (C) 2005 Red Hat, Inc. -+ * Copyright (C) 2005-2025 Red Hat, Inc. - * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. - * All rights reserved. - * -@@ -783,25 +783,25 @@ slapi_pblock_get(Slapi_PBlock *pblock, int arg, void *value) - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- (*(IFP *)value) = pblock->pb_plugin->plg_bind; -+ (*(int32_t (**)(Slapi_PBlock *))value) = pblock->pb_plugin->plg_bind; - break; - case SLAPI_PLUGIN_DB_UNBIND_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- (*(IFP *)value) = pblock->pb_plugin->plg_unbind; -+ (*(int32_t (**)(Slapi_PBlock *))value) = pblock->pb_plugin->plg_unbind; - break; - case SLAPI_PLUGIN_DB_SEARCH_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- (*(IFP *)value) = pblock->pb_plugin->plg_search; -+ (*(int32_t (**)(Slapi_PBlock *))value) = pblock->pb_plugin->plg_search; - break; - case SLAPI_PLUGIN_DB_NEXT_SEARCH_ENTRY_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- (*(IFP *)value) = pblock->pb_plugin->plg_next_search_entry; -+ (*(int32_t (**)(Slapi_PBlock *))value) = pblock->pb_plugin->plg_next_search_entry; - break; - case SLAPI_PLUGIN_DB_NEXT_SEARCH_ENTRY_EXT_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { -@@ -825,37 +825,37 @@ slapi_pblock_get(Slapi_PBlock *pblock, int arg, void *value) - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- (*(IFP *)value) = pblock->pb_plugin->plg_compare; -+ (*(int32_t (**)(Slapi_PBlock *))value) = pblock->pb_plugin->plg_compare; - break; - case SLAPI_PLUGIN_DB_MODIFY_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- (*(IFP *)value) = pblock->pb_plugin->plg_modify; -+ (*(int32_t (**)(Slapi_PBlock *))value) = pblock->pb_plugin->plg_modify; - break; - case SLAPI_PLUGIN_DB_MODRDN_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- (*(IFP *)value) = pblock->pb_plugin->plg_modrdn; -+ (*(int32_t (**)(Slapi_PBlock *))value) = pblock->pb_plugin->plg_modrdn; - break; - case SLAPI_PLUGIN_DB_ADD_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- (*(IFP *)value) = pblock->pb_plugin->plg_add; -+ (*(int32_t (**)(Slapi_PBlock *))value) = pblock->pb_plugin->plg_add; - break; - case SLAPI_PLUGIN_DB_DELETE_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- (*(IFP *)value) = pblock->pb_plugin->plg_delete; -+ (*(int32_t (**)(Slapi_PBlock *))value) = pblock->pb_plugin->plg_delete; - break; - case SLAPI_PLUGIN_DB_ABANDON_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- (*(IFP *)value) = pblock->pb_plugin->plg_abandon; -+ (*(int32_t (**)(Slapi_PBlock *))value) = pblock->pb_plugin->plg_abandon; - break; - case SLAPI_PLUGIN_DB_CONFIG_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { -@@ -867,7 +867,7 @@ slapi_pblock_get(Slapi_PBlock *pblock, int arg, void *value) - (*(IFP *)value) = pblock->pb_plugin->plg_close; - break; - case SLAPI_PLUGIN_CLEANUP_FN: -- (*(IFP *)value) = pblock->pb_plugin->plg_cleanup; -+ (*(int32_t (**)(Slapi_PBlock *))value) = pblock->pb_plugin->plg_cleanup; - break; - case SLAPI_PLUGIN_START_FN: - (*(IFP *)value) = pblock->pb_plugin->plg_start; -@@ -876,22 +876,22 @@ slapi_pblock_get(Slapi_PBlock *pblock, int arg, void *value) - (*(IFP *)value) = pblock->pb_plugin->plg_poststart; - break; - case SLAPI_PLUGIN_DB_WIRE_IMPORT_FN: -- (*(IFP *)value) = pblock->pb_plugin->plg_wire_import; -+ (*(int32_t (**)(Slapi_PBlock *))value) = pblock->pb_plugin->plg_wire_import; - break; - case SLAPI_PLUGIN_DB_GET_INFO_FN: -- (*(IFP *)value) = pblock->pb_plugin->plg_get_info; -+ (*(int32_t (**)(struct backend *, int32_t, void **))value) = pblock->pb_plugin->plg_get_info; - break; - case SLAPI_PLUGIN_DB_SET_INFO_FN: -- (*(IFP *)value) = pblock->pb_plugin->plg_set_info; -+ (*(int32_t (**)(struct backend *, int32_t, void **))value) = pblock->pb_plugin->plg_set_info; - break; - case SLAPI_PLUGIN_DB_CTRL_INFO_FN: -- (*(IFP *)value) = pblock->pb_plugin->plg_ctrl_info; -+ (*(int32_t (**)(struct backend *, int32_t, void **))value) = pblock->pb_plugin->plg_ctrl_info; - break; - case SLAPI_PLUGIN_DB_SEQ_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- (*(IFP *)value) = pblock->pb_plugin->plg_seq; -+ (*(int32_t (**)(Slapi_PBlock *))value) = pblock->pb_plugin->plg_seq; - break; - case SLAPI_PLUGIN_DB_ENTRY_FN: - (*(IFP *)value) = SLAPI_PBLOCK_GET_PLUGIN_RELATED_POINTER(pblock, -@@ -915,55 +915,55 @@ slapi_pblock_get(Slapi_PBlock *pblock, int arg, void *value) - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- (*(IFP *)value) = pblock->pb_plugin->plg_ldif2db; -+ (*(int32_t (**)(Slapi_PBlock *))value) = pblock->pb_plugin->plg_ldif2db; - break; - case SLAPI_PLUGIN_DB_DB2LDIF_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- (*(IFP *)value) = pblock->pb_plugin->plg_db2ldif; -+ (*(int32_t (**)(Slapi_PBlock *))value) = pblock->pb_plugin->plg_db2ldif; - break; - case SLAPI_PLUGIN_DB_COMPACT_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- (*(IFP *)value) = pblock->pb_plugin->plg_dbcompact; -+ (*(int32_t (**)(struct backend *, bool))value) = pblock->pb_plugin->plg_dbcompact; - break; - case SLAPI_PLUGIN_DB_DB2INDEX_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- (*(IFP *)value) = pblock->pb_plugin->plg_db2index; -+ (*(int32_t (**)(Slapi_PBlock *))value) = pblock->pb_plugin->plg_db2index; - break; - case SLAPI_PLUGIN_DB_ARCHIVE2DB_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- (*(IFP *)value) = pblock->pb_plugin->plg_archive2db; -+ (*(int32_t (**)(Slapi_PBlock *))value) = pblock->pb_plugin->plg_archive2db; - break; - case SLAPI_PLUGIN_DB_DB2ARCHIVE_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- (*(IFP *)value) = pblock->pb_plugin->plg_db2archive; -+ (*(int32_t (**)(Slapi_PBlock *))value) = pblock->pb_plugin->plg_db2archive; - break; - case SLAPI_PLUGIN_DB_UPGRADEDB_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- (*(IFP *)value) = pblock->pb_plugin->plg_upgradedb; -+ (*(int32_t (**)(Slapi_PBlock *))value) = pblock->pb_plugin->plg_upgradedb; - break; - case SLAPI_PLUGIN_DB_UPGRADEDNFORMAT_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- (*(IFP *)value) = pblock->pb_plugin->plg_upgradednformat; -+ (*(int32_t (**)(Slapi_PBlock *))value) = pblock->pb_plugin->plg_upgradednformat; - break; - case SLAPI_PLUGIN_DB_DBVERIFY_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- (*(IFP *)value) = pblock->pb_plugin->plg_dbverify; -+ (*(int32_t (**)(Slapi_PBlock *))value) = pblock->pb_plugin->plg_dbverify; - break; - case SLAPI_PLUGIN_DB_BEGIN_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { -@@ -1007,7 +1007,7 @@ slapi_pblock_get(Slapi_PBlock *pblock, int arg, void *value) - pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BETXNEXTENDEDOP) { - return (-1); - } -- (*(IFP *)value) = pblock->pb_plugin->plg_exhandler; -+ (*(int32_t (**)(Slapi_PBlock *))value) = pblock->pb_plugin->plg_exhandler; - break; - case SLAPI_PLUGIN_EXT_OP_OIDLIST: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_EXTENDEDOP && -@@ -1028,7 +1028,7 @@ slapi_pblock_get(Slapi_PBlock *pblock, int arg, void *value) - pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BETXNEXTENDEDOP) { - return (-1); - } -- (*(IFP *)value) = pblock->pb_plugin->plg_be_exhandler; -+ (*(int32_t (**)(Slapi_PBlock *, Slapi_Backend **))value) = pblock->pb_plugin->plg_be_exhandler; - break; - - /* preoperation plugin functions */ -@@ -1474,31 +1474,32 @@ slapi_pblock_get(Slapi_PBlock *pblock, int arg, void *value) - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX) { - return (-1); - } -- (*(IFP *)value) = pblock->pb_plugin->plg_syntax_filter_ava; -+ (*(int32_t (**)(Slapi_PBlock *, const struct berval *, Slapi_Value **, -+ int32_t, Slapi_Value **))value) = pblock->pb_plugin->plg_syntax_filter_ava; - break; - case SLAPI_PLUGIN_SYNTAX_FILTER_SUB: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX) { - return (-1); - } -- (*(IFP *)value) = pblock->pb_plugin->plg_syntax_filter_sub; -+ (*(int32_t (**)(Slapi_PBlock*, char *, char **, char *, Slapi_Value**))value) = pblock->pb_plugin->plg_syntax_filter_sub; - break; - case SLAPI_PLUGIN_SYNTAX_VALUES2KEYS: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX) { - return (-1); - } -- (*(IFP *)value) = pblock->pb_plugin->plg_syntax_values2keys; -+ (*(int32_t (**)(Slapi_PBlock *, Slapi_Value **, Slapi_Value ***, int32_t))value) = pblock->pb_plugin->plg_syntax_values2keys; - break; - case SLAPI_PLUGIN_SYNTAX_ASSERTION2KEYS_AVA: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX) { - return (-1); - } -- (*(IFP *)value) = pblock->pb_plugin->plg_syntax_assertion2keys_ava; -+ (*(int32_t (**)(Slapi_PBlock *, Slapi_Value *, Slapi_Value ***, int32_t))value) = pblock->pb_plugin->plg_syntax_assertion2keys_ava; - break; - case SLAPI_PLUGIN_SYNTAX_ASSERTION2KEYS_SUB: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX) { - return (-1); - } -- (*(IFP *)value) = pblock->pb_plugin->plg_syntax_assertion2keys_sub; -+ (*(int32_t (**)(Slapi_PBlock *, char *, char **, char *, Slapi_Value ***))value) = pblock->pb_plugin->plg_syntax_assertion2keys_sub; - break; - case SLAPI_PLUGIN_SYNTAX_NAMES: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX) { -@@ -1535,13 +1536,13 @@ slapi_pblock_get(Slapi_PBlock *pblock, int arg, void *value) - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX) { - return (-1); - } -- (*(IFP *)value) = pblock->pb_plugin->plg_syntax_validate; -+ (*(int32_t (**)(struct berval *))value) = pblock->pb_plugin->plg_syntax_validate; - break; - case SLAPI_PLUGIN_SYNTAX_NORMALIZE: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX) { - return (-1); - } -- (*(VFPV *)value) = pblock->pb_plugin->plg_syntax_normalize; -+ (*(void (**)(Slapi_PBlock *, char *, int32_t, char **))value) = pblock->pb_plugin->plg_syntax_normalize; - break; - - /* controls we know about */ -@@ -1799,11 +1800,12 @@ slapi_pblock_get(Slapi_PBlock *pblock, int arg, void *value) - /* matching rule plugin functions */ - case SLAPI_PLUGIN_MR_FILTER_CREATE_FN: - SLAPI_PLUGIN_TYPE_CHECK(pblock, SLAPI_PLUGIN_MATCHINGRULE); -- (*(IFP *)value) = pblock->pb_plugin->plg_mr_filter_create; -+ -+ (*(int32_t (**)(Slapi_PBlock *))value) = pblock->pb_plugin->plg_mr_filter_create; - break; - case SLAPI_PLUGIN_MR_INDEXER_CREATE_FN: - SLAPI_PLUGIN_TYPE_CHECK(pblock, SLAPI_PLUGIN_MATCHINGRULE); -- (*(IFP *)value) = pblock->pb_plugin->plg_mr_indexer_create; -+ (*(int32_t (**)(Slapi_PBlock *))value) = pblock->pb_plugin->plg_mr_indexer_create; - break; - case SLAPI_PLUGIN_MR_FILTER_MATCH_FN: - if (pblock->pb_mr != NULL) { -@@ -1904,31 +1906,31 @@ slapi_pblock_get(Slapi_PBlock *pblock, int arg, void *value) - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_MATCHINGRULE) { - return (-1); - } -- (*(IFP *)value) = pblock->pb_plugin->plg_mr_filter_ava; -+ (*(int32_t (**)(Slapi_PBlock *, const struct berval *, Slapi_Value **, int32_t, Slapi_Value **))value) = pblock->pb_plugin->plg_mr_filter_ava; - break; - case SLAPI_PLUGIN_MR_FILTER_SUB: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_MATCHINGRULE) { - return (-1); - } -- (*(IFP *)value) = pblock->pb_plugin->plg_mr_filter_sub; -+ (*(int32_t (**)(Slapi_PBlock *, char *, char **, char*, Slapi_Value **))value) = pblock->pb_plugin->plg_mr_filter_sub; - break; - case SLAPI_PLUGIN_MR_VALUES2KEYS: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_MATCHINGRULE) { - return (-1); - } -- (*(IFP *)value) = pblock->pb_plugin->plg_mr_values2keys; -+ (*(int32_t (**)(Slapi_PBlock *, Slapi_Value **, Slapi_Value ***, int32_t))value) = pblock->pb_plugin->plg_mr_values2keys; - break; - case SLAPI_PLUGIN_MR_ASSERTION2KEYS_AVA: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_MATCHINGRULE) { - return (-1); - } -- (*(IFP *)value) = pblock->pb_plugin->plg_mr_assertion2keys_ava; -+ (*(int32_t (**)(Slapi_PBlock *, Slapi_Value *, Slapi_Value ***, int32_t))value) = pblock->pb_plugin->plg_mr_assertion2keys_ava; - break; - case SLAPI_PLUGIN_MR_ASSERTION2KEYS_SUB: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_MATCHINGRULE) { - return (-1); - } -- (*(IFP *)value) = pblock->pb_plugin->plg_mr_assertion2keys_sub; -+ (*(int32_t (**)(Slapi_PBlock *, char *, char **, char *, Slapi_Value ***))value) = pblock->pb_plugin->plg_mr_assertion2keys_sub; - break; - case SLAPI_PLUGIN_MR_FLAGS: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_MATCHINGRULE) { -@@ -1946,13 +1948,13 @@ slapi_pblock_get(Slapi_PBlock *pblock, int arg, void *value) - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_MATCHINGRULE) { - return (-1); - } -- (*(IFP *)value) = pblock->pb_plugin->plg_mr_compare; -+ (*(int32_t (**)(struct berval *, struct berval *))value) = pblock->pb_plugin->plg_mr_compare; - break; - case SLAPI_PLUGIN_MR_NORMALIZE: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_MATCHINGRULE) { - return (-1); - } -- (*(VFPV *)value) = pblock->pb_plugin->plg_mr_normalize; -+ (*(void (**)(Slapi_PBlock *, char *, int32_t, char **))value) = pblock->pb_plugin->plg_mr_normalize; - break; - - /* seq arguments */ -@@ -2145,9 +2147,9 @@ slapi_pblock_get(Slapi_PBlock *pblock, int arg, void *value) - break; - case SLAPI_TXN_RUV_MODS_FN: - if (pblock->pb_intop != NULL) { -- (*(IFP *)value) = pblock->pb_intop->pb_txn_ruv_mods_fn; -+ (*(int32_t(**)(Slapi_PBlock *, char **, Slapi_Mods **))value) = pblock->pb_intop->pb_txn_ruv_mods_fn; - } else { -- (*(IFP *)value) = NULL; -+ (*(int32_t(**)(Slapi_PBlock *, char **, Slapi_Mods **))value) = NULL; - } - break; - -@@ -2221,24 +2223,25 @@ slapi_pblock_get(Slapi_PBlock *pblock, int arg, void *value) - (*(IFP *)value) = pblock->pb_plugin->plg_acl_init; - break; - case SLAPI_PLUGIN_ACL_SYNTAX_CHECK: -- (*(IFP *)value) = pblock->pb_plugin->plg_acl_syntax_check; -+ (*(int32_t (**)(Slapi_PBlock *, Slapi_Entry *, char **))value) = pblock->pb_plugin->plg_acl_syntax_check; - break; - case SLAPI_PLUGIN_ACL_ALLOW_ACCESS: -- (*(IFP *)value) = pblock->pb_plugin->plg_acl_access_allowed; -+ (*(int32_t (**)(Slapi_PBlock *, Slapi_Entry *, char **, struct berval *, -+ int32_t, int32_t, char **))value) = pblock->pb_plugin->plg_acl_access_allowed; - break; - case SLAPI_PLUGIN_ACL_MODS_ALLOWED: -- (*(IFP *)value) = pblock->pb_plugin->plg_acl_mods_allowed; -+ (*(int32_t (**)(Slapi_PBlock *, Slapi_Entry *, LDAPMod **, void *))value) = pblock->pb_plugin->plg_acl_mods_allowed; - break; - case SLAPI_PLUGIN_ACL_MODS_UPDATE: -- (*(IFP *)value) = pblock->pb_plugin->plg_acl_mods_update; -+ (*(int32_t (**)(Slapi_PBlock *, int32_t, Slapi_DN *, void *))value) = pblock->pb_plugin->plg_acl_mods_update; - break; - /* MMR Plugin */ - case SLAPI_PLUGIN_MMR_BETXN_PREOP: -- (*(IFP *)value) = pblock->pb_plugin->plg_mmr_betxn_preop; -- break; -+ (*(int32_t (**)(Slapi_PBlock *, int32_t))value) = pblock->pb_plugin->plg_mmr_betxn_preop; -+ break; - case SLAPI_PLUGIN_MMR_BETXN_POSTOP: -- (*(IFP *)value) = pblock->pb_plugin->plg_mmr_betxn_postop; -- break; -+ (*(int32_t (**)(Slapi_PBlock *, int32_t))value) = pblock->pb_plugin->plg_mmr_betxn_postop; -+ break; - - case SLAPI_REQUESTOR_DN: - /* NOTE: It's not a copy of the DN */ -@@ -2362,11 +2365,11 @@ slapi_pblock_get(Slapi_PBlock *pblock, int arg, void *value) - - /* entry fetch/store plugin */ - case SLAPI_PLUGIN_ENTRY_FETCH_FUNC: -- (*(IFP *)value) = pblock->pb_plugin->plg_entryfetchfunc; -+ (*(int32_t (**)(char **, uint32_t *))value) = pblock->pb_plugin->plg_entryfetchfunc; - break; - - case SLAPI_PLUGIN_ENTRY_STORE_FUNC: -- (*(IFP *)value) = pblock->pb_plugin->plg_entrystorefunc; -+ (*(int32_t (**)(char **, uint32_t *))value) = pblock->pb_plugin->plg_entrystorefunc; - break; - - case SLAPI_PLUGIN_ENABLED: -@@ -2723,25 +2726,25 @@ slapi_pblock_set(Slapi_PBlock *pblock, int arg, void *value) - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- pblock->pb_plugin->plg_bind = (IFP)value; -+ pblock->pb_plugin->plg_bind = value; - break; - case SLAPI_PLUGIN_DB_UNBIND_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- pblock->pb_plugin->plg_unbind = (IFP)value; -+ pblock->pb_plugin->plg_unbind = value; - break; - case SLAPI_PLUGIN_DB_SEARCH_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- pblock->pb_plugin->plg_search = (IFP)value; -+ pblock->pb_plugin->plg_search = value; - break; - case SLAPI_PLUGIN_DB_NEXT_SEARCH_ENTRY_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- pblock->pb_plugin->plg_next_search_entry = (IFP)value; -+ pblock->pb_plugin->plg_next_search_entry = value; - break; - case SLAPI_PLUGIN_DB_NEXT_SEARCH_ENTRY_EXT_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { -@@ -2765,37 +2768,37 @@ slapi_pblock_set(Slapi_PBlock *pblock, int arg, void *value) - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- pblock->pb_plugin->plg_compare = (IFP)value; -+ pblock->pb_plugin->plg_compare = value; - break; - case SLAPI_PLUGIN_DB_MODIFY_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- pblock->pb_plugin->plg_modify = (IFP)value; -+ pblock->pb_plugin->plg_modify = value; - break; - case SLAPI_PLUGIN_DB_MODRDN_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- pblock->pb_plugin->plg_modrdn = (IFP)value; -+ pblock->pb_plugin->plg_modrdn = value; - break; - case SLAPI_PLUGIN_DB_ADD_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- pblock->pb_plugin->plg_add = (IFP)value; -+ pblock->pb_plugin->plg_add = value; - break; - case SLAPI_PLUGIN_DB_DELETE_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- pblock->pb_plugin->plg_delete = (IFP)value; -+ pblock->pb_plugin->plg_delete = value; - break; - case SLAPI_PLUGIN_DB_ABANDON_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- pblock->pb_plugin->plg_abandon = (IFP)value; -+ pblock->pb_plugin->plg_abandon = value; - break; - case SLAPI_PLUGIN_DB_CONFIG_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { -@@ -2807,7 +2810,7 @@ slapi_pblock_set(Slapi_PBlock *pblock, int arg, void *value) - pblock->pb_plugin->plg_close = (IFP)value; - break; - case SLAPI_PLUGIN_CLEANUP_FN: -- pblock->pb_plugin->plg_cleanup = (IFP)value; -+ pblock->pb_plugin->plg_cleanup = value; - break; - case SLAPI_PLUGIN_START_FN: - pblock->pb_plugin->plg_start = (IFP)value; -@@ -2816,22 +2819,22 @@ slapi_pblock_set(Slapi_PBlock *pblock, int arg, void *value) - pblock->pb_plugin->plg_poststart = (IFP)value; - break; - case SLAPI_PLUGIN_DB_WIRE_IMPORT_FN: -- pblock->pb_plugin->plg_wire_import = (IFP)value; -+ pblock->pb_plugin->plg_wire_import = value; - break; - case SLAPI_PLUGIN_DB_GET_INFO_FN: -- pblock->pb_plugin->plg_get_info = (IFP)value; -+ pblock->pb_plugin->plg_get_info = value; - break; - case SLAPI_PLUGIN_DB_SET_INFO_FN: -- pblock->pb_plugin->plg_set_info = (IFP)value; -+ pblock->pb_plugin->plg_set_info = value; - break; - case SLAPI_PLUGIN_DB_CTRL_INFO_FN: -- pblock->pb_plugin->plg_ctrl_info = (IFP)value; -+ pblock->pb_plugin->plg_ctrl_info = value; - break; - case SLAPI_PLUGIN_DB_SEQ_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- pblock->pb_plugin->plg_seq = (IFP)value; -+ pblock->pb_plugin->plg_seq = value; - break; - case SLAPI_PLUGIN_DB_ENTRY_FN: - pblock->pb_plugin->plg_entry = (IFP)value; -@@ -2852,49 +2855,49 @@ slapi_pblock_set(Slapi_PBlock *pblock, int arg, void *value) - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- pblock->pb_plugin->plg_ldif2db = (IFP)value; -+ pblock->pb_plugin->plg_ldif2db = value; - break; - case SLAPI_PLUGIN_DB_DB2LDIF_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- pblock->pb_plugin->plg_db2ldif = (IFP)value; -+ pblock->pb_plugin->plg_db2ldif = value; - break; - case SLAPI_PLUGIN_DB_DB2INDEX_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- pblock->pb_plugin->plg_db2index = (IFP)value; -+ pblock->pb_plugin->plg_db2index = value; - break; - case SLAPI_PLUGIN_DB_ARCHIVE2DB_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- pblock->pb_plugin->plg_archive2db = (IFP)value; -+ pblock->pb_plugin->plg_archive2db = value; - break; - case SLAPI_PLUGIN_DB_DB2ARCHIVE_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- pblock->pb_plugin->plg_db2archive = (IFP)value; -+ pblock->pb_plugin->plg_db2archive = value; - break; - case SLAPI_PLUGIN_DB_UPGRADEDB_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- pblock->pb_plugin->plg_upgradedb = (IFP)value; -+ pblock->pb_plugin->plg_upgradedb = value; - break; - case SLAPI_PLUGIN_DB_UPGRADEDNFORMAT_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- pblock->pb_plugin->plg_upgradednformat = (IFP)value; -+ pblock->pb_plugin->plg_upgradednformat = value; - break; - case SLAPI_PLUGIN_DB_DBVERIFY_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- pblock->pb_plugin->plg_dbverify = (IFP)value; -+ pblock->pb_plugin->plg_dbverify = value; - break; - case SLAPI_PLUGIN_DB_BEGIN_FN: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { -@@ -2934,7 +2937,7 @@ slapi_pblock_set(Slapi_PBlock *pblock, int arg, void *value) - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE) { - return (-1); - } -- pblock->pb_plugin->plg_dbcompact = (IFP)value; -+ pblock->pb_plugin->plg_dbcompact = value; - break; - - /* extendedop plugin functions */ -@@ -2943,7 +2946,7 @@ slapi_pblock_set(Slapi_PBlock *pblock, int arg, void *value) - pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BETXNEXTENDEDOP) { - return (-1); - } -- pblock->pb_plugin->plg_exhandler = (IFP)value; -+ pblock->pb_plugin->plg_exhandler = value; - break; - case SLAPI_PLUGIN_EXT_OP_OIDLIST: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_EXTENDEDOP && -@@ -2965,7 +2968,7 @@ slapi_pblock_set(Slapi_PBlock *pblock, int arg, void *value) - pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BETXNEXTENDEDOP) { - return (-1); - } -- pblock->pb_plugin->plg_be_exhandler = (IFP)value; -+ pblock->pb_plugin->plg_be_exhandler = value; - break; - - /* preoperation plugin functions */ -@@ -3331,31 +3334,31 @@ slapi_pblock_set(Slapi_PBlock *pblock, int arg, void *value) - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX) { - return (-1); - } -- pblock->pb_plugin->plg_syntax_filter_ava = (IFP)value; -+ pblock->pb_plugin->plg_syntax_filter_ava = value; - break; - case SLAPI_PLUGIN_SYNTAX_FILTER_SUB: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX) { - return (-1); - } -- pblock->pb_plugin->plg_syntax_filter_sub = (IFP)value; -+ pblock->pb_plugin->plg_syntax_filter_sub = value; - break; - case SLAPI_PLUGIN_SYNTAX_VALUES2KEYS: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX) { - return (-1); - } -- pblock->pb_plugin->plg_syntax_values2keys = (IFP)value; -+ pblock->pb_plugin->plg_syntax_values2keys = value; - break; - case SLAPI_PLUGIN_SYNTAX_ASSERTION2KEYS_AVA: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX) { - return (-1); - } -- pblock->pb_plugin->plg_syntax_assertion2keys_ava = (IFP)value; -+ pblock->pb_plugin->plg_syntax_assertion2keys_ava = value; - break; - case SLAPI_PLUGIN_SYNTAX_ASSERTION2KEYS_SUB: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX) { - return (-1); - } -- pblock->pb_plugin->plg_syntax_assertion2keys_sub = (IFP)value; -+ pblock->pb_plugin->plg_syntax_assertion2keys_sub = value; - break; - case SLAPI_PLUGIN_SYNTAX_NAMES: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX) { -@@ -3391,13 +3394,13 @@ slapi_pblock_set(Slapi_PBlock *pblock, int arg, void *value) - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX) { - return (-1); - } -- pblock->pb_plugin->plg_syntax_validate = (IFP)value; -+ pblock->pb_plugin->plg_syntax_validate = value; - break; - case SLAPI_PLUGIN_SYNTAX_NORMALIZE: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX) { - return (-1); - } -- pblock->pb_plugin->plg_syntax_normalize = (VFPV)value; -+ pblock->pb_plugin->plg_syntax_normalize = value; - break; - case SLAPI_ENTRY_PRE_OP: - _pblock_assert_pb_intop(pblock); -@@ -3723,11 +3726,11 @@ slapi_pblock_set(Slapi_PBlock *pblock, int arg, void *value) - /* matching rule plugin functions */ - case SLAPI_PLUGIN_MR_FILTER_CREATE_FN: - SLAPI_PLUGIN_TYPE_CHECK(pblock, SLAPI_PLUGIN_MATCHINGRULE); -- pblock->pb_plugin->plg_mr_filter_create = (IFP)value; -+ pblock->pb_plugin->plg_mr_filter_create = value; - break; - case SLAPI_PLUGIN_MR_INDEXER_CREATE_FN: - SLAPI_PLUGIN_TYPE_CHECK(pblock, SLAPI_PLUGIN_MATCHINGRULE); -- pblock->pb_plugin->plg_mr_indexer_create = (IFP)value; -+ pblock->pb_plugin->plg_mr_indexer_create = value; - break; - case SLAPI_PLUGIN_MR_FILTER_MATCH_FN: - _pblock_assert_pb_mr(pblock); -@@ -3789,31 +3792,31 @@ slapi_pblock_set(Slapi_PBlock *pblock, int arg, void *value) - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_MATCHINGRULE) { - return (-1); - } -- pblock->pb_plugin->plg_mr_filter_ava = (IFP)value; -+ pblock->pb_plugin->plg_mr_filter_ava = value; - break; - case SLAPI_PLUGIN_MR_FILTER_SUB: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_MATCHINGRULE) { - return (-1); - } -- pblock->pb_plugin->plg_mr_filter_sub = (IFP)value; -+ pblock->pb_plugin->plg_mr_filter_sub = value; - break; - case SLAPI_PLUGIN_MR_VALUES2KEYS: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_MATCHINGRULE) { - return (-1); - } -- pblock->pb_plugin->plg_mr_values2keys = (IFP)value; -+ pblock->pb_plugin->plg_mr_values2keys = value; - break; - case SLAPI_PLUGIN_MR_ASSERTION2KEYS_AVA: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_MATCHINGRULE) { - return (-1); - } -- pblock->pb_plugin->plg_mr_assertion2keys_ava = (IFP)value; -+ pblock->pb_plugin->plg_mr_assertion2keys_ava = value; - break; - case SLAPI_PLUGIN_MR_ASSERTION2KEYS_SUB: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_MATCHINGRULE) { - return (-1); - } -- pblock->pb_plugin->plg_mr_assertion2keys_sub = (IFP)value; -+ pblock->pb_plugin->plg_mr_assertion2keys_sub = value; - break; - case SLAPI_PLUGIN_MR_FLAGS: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_MATCHINGRULE) { -@@ -3832,13 +3835,13 @@ slapi_pblock_set(Slapi_PBlock *pblock, int arg, void *value) - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_MATCHINGRULE) { - return (-1); - } -- pblock->pb_plugin->plg_mr_compare = (IFP)value; -+ pblock->pb_plugin->plg_mr_compare = value; - break; - case SLAPI_PLUGIN_MR_NORMALIZE: - if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_MATCHINGRULE) { - return (-1); - } -- pblock->pb_plugin->plg_mr_normalize = (VFPV)value; -+ pblock->pb_plugin->plg_mr_normalize = value; - break; - - /* seq arguments */ -@@ -3957,7 +3960,7 @@ slapi_pblock_set(Slapi_PBlock *pblock, int arg, void *value) - break; - case SLAPI_TXN_RUV_MODS_FN: - _pblock_assert_pb_intop(pblock); -- pblock->pb_intop->pb_txn_ruv_mods_fn = (IFP)value; -+ pblock->pb_intop->pb_txn_ruv_mods_fn = value; - break; - - /* Search results set */ -@@ -4027,23 +4030,23 @@ slapi_pblock_set(Slapi_PBlock *pblock, int arg, void *value) - break; - - case SLAPI_PLUGIN_ACL_SYNTAX_CHECK: -- pblock->pb_plugin->plg_acl_syntax_check = (IFP)value; -+ pblock->pb_plugin->plg_acl_syntax_check = value; - break; - case SLAPI_PLUGIN_ACL_ALLOW_ACCESS: -- pblock->pb_plugin->plg_acl_access_allowed = (IFP)value; -+ pblock->pb_plugin->plg_acl_access_allowed = value; - break; - case SLAPI_PLUGIN_ACL_MODS_ALLOWED: -- pblock->pb_plugin->plg_acl_mods_allowed = (IFP)value; -+ pblock->pb_plugin->plg_acl_mods_allowed = value; - break; - case SLAPI_PLUGIN_ACL_MODS_UPDATE: -- pblock->pb_plugin->plg_acl_mods_update = (IFP)value; -+ pblock->pb_plugin->plg_acl_mods_update = value; - break; - /* MMR Plugin */ - case SLAPI_PLUGIN_MMR_BETXN_PREOP: -- pblock->pb_plugin->plg_mmr_betxn_preop = (IFP) value; -+ pblock->pb_plugin->plg_mmr_betxn_preop = value; - break; - case SLAPI_PLUGIN_MMR_BETXN_POSTOP: -- pblock->pb_plugin->plg_mmr_betxn_postop = (IFP) value; -+ pblock->pb_plugin->plg_mmr_betxn_postop = value; - break; - - case SLAPI_CLIENT_DNS: -@@ -4106,11 +4109,11 @@ slapi_pblock_set(Slapi_PBlock *pblock, int arg, void *value) - - /* entry fetch store */ - case SLAPI_PLUGIN_ENTRY_FETCH_FUNC: -- pblock->pb_plugin->plg_entryfetchfunc = (IFP)value; -+ pblock->pb_plugin->plg_entryfetchfunc = value; - break; - - case SLAPI_PLUGIN_ENTRY_STORE_FUNC: -- pblock->pb_plugin->plg_entrystorefunc = (IFP)value; -+ pblock->pb_plugin->plg_entrystorefunc = value; - break; - - case SLAPI_PLUGIN_ENABLED: -diff --git a/ldap/servers/slapd/pblock_v3.h b/ldap/servers/slapd/pblock_v3.h -index ef15ee457..82dcb8ebf 100644 ---- a/ldap/servers/slapd/pblock_v3.h -+++ b/ldap/servers/slapd/pblock_v3.h -@@ -117,7 +117,7 @@ typedef struct _slapi_pblock_intop - void *op_stack_elem; - - void *pb_txn; /* transaction ID */ -- IFP pb_txn_ruv_mods_fn; /* Function to fetch RUV mods for txn */ -+ int32_t (*pb_txn_ruv_mods_fn)(Slapi_PBlock *, char **, Slapi_Mods **); /* Function to fetch RUV mods for txn */ - passwdPolicy *pwdpolicy; - LDAPControl **pb_ctrls_arg; /* allows to pass controls as arguments before - operation object is created */ -diff --git a/ldap/servers/slapd/plugin.c b/ldap/servers/slapd/plugin.c -index 1528d5593..52d25e19e 100644 ---- a/ldap/servers/slapd/plugin.c -+++ b/ldap/servers/slapd/plugin.c -@@ -663,7 +663,7 @@ slapi_send_ldap_intermediate(Slapi_PBlock *pb, LDAPControl **ectrls, char *respo - int - slapi_send_ldap_search_entry(Slapi_PBlock *pb, Slapi_Entry *e, LDAPControl **ectrls, char **attrs, int attrsonly) - { -- IFP fn = NULL; -+ int32_t (*fn)(Slapi_PBlock *, Slapi_Entry *, LDAPControl **, char **, int32_t) = NULL; - slapi_pblock_get(pb, SLAPI_PLUGIN_DB_ENTRY_FN, (void *)&fn); - if (NULL == fn) { - return -1; -@@ -698,7 +698,7 @@ slapi_send_ldap_result_from_pb(Slapi_PBlock *pb) - int err; - char *matched; - char *text; -- IFP fn = NULL; -+ int32_t (*fn)(Slapi_PBlock*, int32_t, char*, char*, int32_t, struct berval **) = NULL; - - slapi_pblock_get(pb, SLAPI_RESULT_CODE, &err); - slapi_pblock_get(pb, SLAPI_RESULT_TEXT, &text); -@@ -713,7 +713,7 @@ slapi_send_ldap_result_from_pb(Slapi_PBlock *pb) - void - slapi_send_ldap_result(Slapi_PBlock *pb, int err, char *matched, char *text, int nentries, struct berval **urls) - { -- IFP fn = NULL; -+ int32_t (*fn)(Slapi_PBlock*, int32_t, char*, char*, int32_t, struct berval **) = NULL; - Slapi_Operation *operation; - long op_type; - -@@ -751,7 +751,7 @@ slapi_send_ldap_result(Slapi_PBlock *pb, int err, char *matched, char *text, int - int - slapi_send_ldap_referral(Slapi_PBlock *pb, Slapi_Entry *e, struct berval **refs, struct berval ***urls) - { -- IFP fn = NULL; -+ int32_t (*fn)(Slapi_PBlock*, Slapi_Entry*, struct berval **, struct berval ***) = NULL; - slapi_pblock_get(pb, SLAPI_PLUGIN_DB_REFERRAL_FN, (void *)&fn); - if (NULL == fn) { - return -1; -@@ -1964,7 +1964,7 @@ plugin_call_func(struct slapdplugin *list, int operation, Slapi_PBlock *pb, int - int count = 0; - - for (; list != NULL; list = list->plg_next) { -- IFP func = NULL; -+ int32_t (*func)(Slapi_PBlock *) = NULL; - - slapi_pblock_set(pb, SLAPI_PLUGIN, list); - set_db_default_result_handlers(pb); /* JCM: What's this do? Is it needed here? */ -diff --git a/ldap/servers/slapd/plugin_mmr.c b/ldap/servers/slapd/plugin_mmr.c -index f58120543..845e8f0ad 100644 ---- a/ldap/servers/slapd/plugin_mmr.c -+++ b/ldap/servers/slapd/plugin_mmr.c -@@ -1,10 +1,10 @@ - /** BEGIN COPYRIGHT BLOCK - * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. -- * Copyright (C) 2005 Red Hat, Inc. -+ * Copyright (C) 2005-2025 Red Hat, Inc. - * All rights reserved. - * - * License: GPL (version 3 or any later version). -- * See LICENSE for details. -+ * See LICENSE for details. - * END COPYRIGHT BLOCK **/ - - #ifdef HAVE_CONFIG_H -@@ -19,11 +19,11 @@ - #include "slap.h" - - int --plugin_call_mmr_plugin_preop ( Slapi_PBlock *pb, Slapi_Entry *e, int flags) -+plugin_call_mmr_plugin_preop(Slapi_PBlock *pb, Slapi_Entry *e, int flags) - { -- struct slapdplugin *p; -- int rc = LDAP_INSUFFICIENT_ACCESS; -- Operation *operation; -+ struct slapdplugin *p; -+ int rc = LDAP_INSUFFICIENT_ACCESS; -+ Operation *operation; - - slapi_pblock_get (pb, SLAPI_OPERATION, &operation); - -@@ -45,11 +45,11 @@ plugin_call_mmr_plugin_preop ( Slapi_PBlock *pb, Slapi_Entry *e, int flags) - } - - int --plugin_call_mmr_plugin_postop ( Slapi_PBlock *pb, Slapi_Entry *e, int flags) -+plugin_call_mmr_plugin_postop(Slapi_PBlock *pb, Slapi_Entry *e, int flags) - { -- struct slapdplugin *p; -- int rc = LDAP_INSUFFICIENT_ACCESS; -- Operation *operation; -+ struct slapdplugin *p; -+ int rc = LDAP_INSUFFICIENT_ACCESS; -+ Operation *operation; - - slapi_pblock_get (pb, SLAPI_OPERATION, &operation); - -diff --git a/ldap/servers/slapd/plugin_mr.c b/ldap/servers/slapd/plugin_mr.c -index 67051a5ff..757355dbc 100644 ---- a/ldap/servers/slapd/plugin_mr.c -+++ b/ldap/servers/slapd/plugin_mr.c -@@ -1,6 +1,6 @@ - /** BEGIN COPYRIGHT BLOCK - * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. -- * Copyright (C) 2005 Red Hat, Inc. -+ * Copyright (C) 2005-2025 Red Hat, Inc. - * All rights reserved. - * - * License: GPL (version 3 or any later version). -@@ -35,7 +35,7 @@ struct mr_private - const struct berval *value; /* orig value from filter */ - int ftype; /* filter type */ - int op; /* query op type */ -- IFP match_fn; /* match func to use */ -+ int32_t (*match_fn)(Slapi_PBlock *, const struct berval *, Slapi_Value **, int32_t, Slapi_Value **); /* match func to use */ - /* note - substring matching rules not currently supported */ - char *initial; /* these are for substring matches */ - char *any[2]; /* at most one value for extensible filter */ -@@ -225,7 +225,7 @@ int /* an LDAP error code, hopefully LDAP_SUCCESS */ - int rc; - char *oid; - if (!(rc = slapi_pblock_get(opb, SLAPI_PLUGIN_MR_OID, &oid))) { -- IFP createFn = NULL; -+ int32_t (*createFn)(Slapi_PBlock *) = NULL; - struct slapdplugin *mrp = plugin_mr_find_registered(oid); - if (mrp != NULL) { - /* Great the matching OID -> MR plugin was already found, just reuse it */ -@@ -251,7 +251,6 @@ int /* an LDAP error code, hopefully LDAP_SUCCESS */ - rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION; - - for (mrp = get_plugin_list(PLUGIN_LIST_MATCHINGRULE); mrp != NULL; mrp = mrp->plg_next) { -- - Slapi_PBlock *pb = slapi_pblock_new(); - mr_indexer_init_pb(opb, pb); - slapi_pblock_set(pb, SLAPI_PLUGIN, mrp); -@@ -263,8 +262,8 @@ int /* an LDAP error code, hopefully LDAP_SUCCESS */ - } - - if (createFn && !createFn(pb)) { -- IFP indexFn = NULL; -- IFP indexSvFn = NULL; -+ int32_t (*indexFn)(void) = NULL; -+ int32_t (*indexSvFn)(void) = NULL; - /* These however, are in the pblock direct, so we need to copy them. */ - slapi_pblock_get(pb, SLAPI_PLUGIN_MR_INDEX_FN, &indexFn); - slapi_pblock_get(pb, SLAPI_PLUGIN_MR_INDEX_SV_FN, &indexSvFn); -@@ -624,7 +623,7 @@ static int - attempt_mr_filter_create(mr_filter_t *f, struct slapdplugin *mrp, Slapi_PBlock *pb) - { - int rc; -- IFP mrf_create = NULL; -+ int32_t (*mrf_create)(Slapi_PBlock *) = NULL; - f->mrf_match = NULL; - slapi_pblock_init(pb); - if (!(rc = slapi_pblock_set(pb, SLAPI_PLUGIN, mrp)) && -diff --git a/ldap/servers/slapd/plugin_syntax.c b/ldap/servers/slapd/plugin_syntax.c -index f8a133f96..68f7bcb4b 100644 ---- a/ldap/servers/slapd/plugin_syntax.c -+++ b/ldap/servers/slapd/plugin_syntax.c -@@ -1,6 +1,6 @@ - /** BEGIN COPYRIGHT BLOCK - * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. -- * Copyright (C) 2005 Red Hat, Inc. -+ * Copyright (C) 2005-2025 Red Hat, Inc. - * All rights reserved. - * - * License: GPL (version 3 or any later version). -@@ -95,7 +95,7 @@ plugin_call_syntax_filter_ava_sv( - int useDeletedValues) - { - int rc; -- IFP ava_fn = NULL; -+ int32_t (*ava_fn)(Slapi_PBlock *, const struct berval *, Slapi_Value **, int32_t, Slapi_Value **) = NULL; - - slapi_log_err(SLAPI_LOG_FILTER, - "plugin_call_syntax_filter_ava_sv", "=> %s=%s\n", ava->ava_type, -@@ -207,7 +207,7 @@ plugin_call_syntax_filter_sub_sv( - struct subfilt *fsub) - { - int rc; -- IFP sub_fn = NULL; -+ int32_t (*sub_fn)(Slapi_PBlock *, char *, char **, char*, Slapi_Value **) = NULL; - int filter_normalized = 0; - - slapi_log_err(SLAPI_LOG_FILTER, -@@ -396,7 +396,7 @@ slapi_entry_syntax_check( - /* iterate through each value to check if it's valid */ - while (val != NULL) { - bval = slapi_value_get_berval(val); -- if ((a->a_plugin->plg_syntax_validate(bval)) != 0) { -+ if ((a->a_plugin->plg_syntax_validate((struct berval *)bval)) != 0) { - if (syntaxlogging) { - slapi_log_err(SLAPI_LOG_ERR, "slapi_entry_syntax_check", - "\"%s\": (%s) value #%d invalid per syntax\n", -@@ -586,7 +586,7 @@ slapi_attr_values2keys_sv_pb( - { - int rc; - struct slapdplugin *pi = NULL; -- IFP v2k_fn = NULL; -+ int32_t (*v2k_fn)(Slapi_PBlock*, Slapi_Value**, Slapi_Value***, int32_t) = NULL; - - if ((sattr->a_plugin == NULL)) { - /* could be lazy plugin initialization, get it now */ -@@ -748,7 +748,7 @@ slapi_attr_assertion2keys_ava_sv( - { - int rc; - struct slapdplugin *pi = NULL; -- IFP a2k_fn = NULL; -+ int32_t (*a2k_fn)(Slapi_PBlock *, Slapi_Value *, Slapi_Value ***, int32_t) = NULL; - - slapi_log_err(SLAPI_LOG_FILTER, - "slapi_attr_assertion2keys_ava_sv", "=>\n"); -@@ -880,7 +880,7 @@ slapi_attr_assertion2keys_sub_sv_pb( - Slapi_PBlock *work_pb = NULL; - struct slapdplugin *pi = NULL; - struct slapdplugin *origpi = NULL; -- IFP a2k_fn = NULL; -+ int32_t (*a2k_fn)(Slapi_PBlock *, char *, char **, char *, Slapi_Value ***) = NULL; - - slapi_log_err(SLAPI_LOG_FILTER, - "slapi_attr_assertion2keys_sub_sv_pb", "=>\n"); -@@ -951,7 +951,7 @@ slapi_attr_value_normalize_ext( - unsigned long filter_type) - { - Slapi_Attr myattr = {0}; -- VFPV norm_fn = NULL; -+ void (*norm_fn)(Slapi_PBlock *, char *, int32_t, char **) = NULL; - - if (!sattr) { - sattr = slapi_attr_init(&myattr, type); -diff --git a/ldap/servers/slapd/pw.c b/ldap/servers/slapd/pw.c -index 65e491590..cda1c404f 100644 ---- a/ldap/servers/slapd/pw.c -+++ b/ldap/servers/slapd/pw.c -@@ -3243,7 +3243,7 @@ slapi_pw_set_entry_ext(Slapi_Entry *entry, Slapi_Value **vals, int flags) - } - - int --pw_copy_entry_ext(Slapi_Entry *src_e, Slapi_Entry *dest_e) -+pw_copy_entry_ext(const Slapi_Entry *src_e, Slapi_Entry *dest_e) - { - struct slapi_pw_entry_ext *src_extp = NULL; - struct slapi_pw_entry_ext *dest_extp = NULL; -@@ -3254,7 +3254,7 @@ pw_copy_entry_ext(Slapi_Entry *src_e, Slapi_Entry *dest_e) - - src_extp = (struct slapi_pw_entry_ext *)slapi_get_object_extension( - pw_entry_objtype, -- src_e, -+ (void *)src_e, - pw_entry_handle); - if (NULL == src_extp) { - return LDAP_NO_SUCH_ATTRIBUTE; -diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h -index f2395cfa2..fee5a6ab5 100644 ---- a/ldap/servers/slapd/slap.h -+++ b/ldap/servers/slapd/slap.h -@@ -1,7 +1,7 @@ - /** BEGIN COPYRIGHT BLOCK - * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. -- * Copyright (C) 2009 Red Hat, Inc. - * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. -+ * Copyright (C) 2009-2025 Red Hat, Inc. - * All rights reserved. - * - * Contributors: -@@ -870,10 +870,10 @@ struct slapi_entry - struct attrs_in_extension - { - char *ext_type; -- IFP ext_get; -- IFP ext_set; -- IFP ext_copy; -- IFP ext_get_size; -+ int32_t (*ext_get)(Slapi_Entry *, Slapi_Value ***); -+ int32_t (*ext_set)(Slapi_Entry *, Slapi_Value **, int32_t); -+ int32_t (*ext_copy)(const Slapi_Entry *, Slapi_Entry *); -+ int32_t (*ext_get_size)(Slapi_Entry *, size_t *); - }; - - extern struct attrs_in_extension attrs_in_extension[]; -@@ -1045,7 +1045,7 @@ struct slapdplugin - int plg_precedence; /* for plugin execution ordering */ - struct slapdplugin *plg_group; /* pointer to the group to which this plugin belongs */ - struct pluginconfig plg_conf; /* plugin configuration parameters */ -- IFP plg_cleanup; /* cleanup function */ -+ int32_t (*plg_cleanup)(Slapi_PBlock *); /* cleanup function */ - IFP plg_start; /* start function */ - IFP plg_poststart; /* poststart function */ - int plg_closed; /* mark plugin as closed */ -@@ -1055,47 +1055,47 @@ struct slapdplugin - Slapi_Counter *plg_op_counter; /* operation counter, used for shutdown */ - - /* NOTE: These LDIF2DB and DB2LDIF fn pointers are internal only for now. -- I don't believe you can get these functions from a plug-in and -- then call them without knowing what IFP or VFP0 are. (These aren't -- declared in slapi-plugin.h.) More importantly, it's a pretty ugly -- way to get to these functions. (Do we want people to get locked into -- this?) -- -- The correct way to do this would be to expose these functions as -- front-end API functions. We can fix this for the next release. -- (No one has the time right now.) -- */ -+ * I don't believe you can get these functions from a plug-in and -+ * then call them without knowing what IFP or VFP0 are. (These aren't -+ * declared in slapi-plugin.h.) More importantly, it's a pretty ugly -+ * way to get to these functions. (Do we want people to get locked into -+ * this?) -+ * -+ * The correct way to do this would be to expose these functions as -+ * front-end API functions. We can fix this for the next release. -+ * (No one has the time right now.) -+ */ - union - { /* backend database plugin structure */ - struct plg_un_database_backend - { -- IFP plg_un_db_bind; /* bind */ -- IFP plg_un_db_unbind; /* unbind */ -- IFP plg_un_db_search; /* search */ -- IFP plg_un_db_next_search_entry; /* iterate */ -+ int32_t (*plg_un_db_bind)(Slapi_PBlock *); /* bind */ -+ int32_t (*plg_un_db_unbind)(Slapi_PBlock *); /* undbind */ -+ int32_t (*plg_un_db_search)(Slapi_PBlock *); /* search */ -+ int32_t (*plg_un_db_next_search_entry)(Slapi_PBlock *); /* iterate */ - IFP plg_un_db_next_search_entry_ext; -- VFPP plg_un_db_search_results_release; /* PAGED RESULTS */ -- VFP plg_un_db_prev_search_results; /* PAGED RESULTS */ -- IFP plg_un_db_entry_release; -- IFP plg_un_db_compare; /* compare */ -- IFP plg_un_db_modify; /* modify */ -- IFP plg_un_db_modrdn; /* modrdn */ -- IFP plg_un_db_add; /* add */ -- IFP plg_un_db_delete; /* delete */ -- IFP plg_un_db_abandon; /* abandon */ -- IFP plg_un_db_config; /* config */ -- IFP plg_un_db_seq; /* sequence */ -- IFP plg_un_db_entry; /* entry send */ -- IFP plg_un_db_referral; /* referral send */ -- IFP plg_un_db_result; /* result send */ -- IFP plg_un_db_ldif2db; /* ldif 2 database */ -- IFP plg_un_db_db2ldif; /* database 2 ldif */ -- IFP plg_un_db_db2index; /* database 2 index */ -- IFP plg_un_db_dbcompact; /* compact database */ -- IFP plg_un_db_archive2db; /* ldif 2 database */ -- IFP plg_un_db_db2archive; /* database 2 ldif */ -- IFP plg_un_db_upgradedb; /* convert old idl to new */ -- IFP plg_un_db_upgradednformat; /* convert old dn format to new */ -+ VFPP plg_un_db_search_results_release; /* Paged results */ -+ VFP plg_un_db_prev_search_results; /* Paged results */ -+ int32_t (*plg_un_db_entry_release)(Slapi_PBlock *, void *); /* Releas entry from cache */ -+ int32_t (*plg_un_db_compare)(Slapi_PBlock *); /* compare */ -+ int32_t (*plg_un_db_modify)(Slapi_PBlock *); /* modify */ -+ int32_t (*plg_un_db_modrdn)(Slapi_PBlock *); /* modrdn */ -+ int32_t (*plg_un_db_add)(Slapi_PBlock *); /* add */ -+ int32_t (*plg_un_db_delete)(Slapi_PBlock *); /* delete */ -+ int32_t (*plg_un_db_abandon)(Slapi_PBlock *); /* abandon */ -+ IFP plg_un_db_config; /* config */ -+ int32_t (*plg_un_db_seq)(Slapi_PBlock *); /* sequence */ -+ IFP plg_un_db_entry; /* entry send */ -+ IFP plg_un_db_referral; /* referral send */ -+ IFP plg_un_db_result; -+ int32_t (*plg_un_db_ldif2db)(Slapi_PBlock *); /* ldif 2 database */ -+ int32_t (*plg_un_db_db2ldif)(Slapi_PBlock *); /* database 2 ldif */ -+ int32_t (*plg_un_db_db2index)(Slapi_PBlock *); /* database 2 index */ -+ int32_t (*plg_un_db_dbcompact)(Slapi_Backend *, bool); /* compact database */ -+ int32_t (*plg_un_db_archive2db)(Slapi_PBlock *); /* ldif 2 database */ -+ int32_t (*plg_un_db_db2archive)(Slapi_PBlock *); /* database 2 ldif */ -+ int32_t (*plg_un_db_upgradedb)(Slapi_PBlock *); /* convert old idl to new */ -+ int32_t (*plg_un_db_upgradednformat)(Slapi_PBlock *); /* convert old dn format to new */ - IFP plg_un_db_begin; /* dbase txn begin */ - IFP plg_un_db_commit; /* dbase txn commit */ - IFP plg_un_db_abort; /* dbase txn abort */ -@@ -1105,12 +1105,12 @@ struct slapdplugin - IFP plg_un_db_register_dn_callback; /* Register a function to call when a operation is applied to a given DN */ - IFP plg_un_db_register_oc_callback; /* Register a function to call when a operation is applied to a given ObjectClass */ - IFP plg_un_db_init_instance; /* initializes new db instance */ -- IFP plg_un_db_wire_import; /* fast replica update */ -- IFP plg_un_db_verify; /* verify db files */ -- IFP plg_un_db_add_schema; /* add schema */ -- IFP plg_un_db_get_info; /* get info */ -- IFP plg_un_db_set_info; /* set info */ -- IFP plg_un_db_ctrl_info; /* ctrl info */ -+ int32_t (*plg_un_db_wire_import)(Slapi_PBlock *); /* fast replica update */ -+ int32_t (*plg_un_db_verify)(Slapi_PBlock *); /* verify db files */ -+ IFP plg_un_db_add_schema; /* add schema */ -+ int32_t (*plg_un_db_get_info)(Slapi_Backend *, int32_t, void **); /* get info */ -+ int32_t (*plg_un_db_set_info)(Slapi_Backend *, int32_t, void **); /* set info */ -+ int32_t (*plg_un_db_ctrl_info)(Slapi_Backend *, int32_t, void **); /* ctrl info */ - } plg_un_db; - #define plg_bind plg_un.plg_un_db.plg_un_db_bind - #define plg_unbind plg_un.plg_un_db.plg_un_db_unbind -@@ -1155,10 +1155,10 @@ struct slapdplugin - { - char **plg_un_pe_exoids; /* exop oids */ - char **plg_un_pe_exnames; /* exop names (may be NULL) */ -- IFP plg_un_pe_exhandler; /* handler */ -+ int32_t (*plg_un_pe_exhandler)(Slapi_PBlock *); /* handler */ - IFP plg_un_pe_pre_exhandler; /* pre extop */ - IFP plg_un_pe_post_exhandler; /* post extop */ -- IFP plg_un_pe_be_exhandler; /* handler to retrieve the be name for the operation */ -+ int32_t (*plg_un_pe_be_exhandler)(Slapi_PBlock *, Slapi_Backend **); /* handler to retrieve the be name for the operation */ - } plg_un_pe; - #define plg_exoids plg_un.plg_un_pe.plg_un_pe_exoids - #define plg_exnames plg_un.plg_un_pe.plg_un_pe_exnames -@@ -1294,20 +1294,20 @@ struct slapdplugin - /* matching rule plugin structure */ - struct plg_un_matching_rule - { -- IFP plg_un_mr_filter_create; /* factory function */ -- IFP plg_un_mr_indexer_create; /* factory function */ -+ int32_t (*plg_un_mr_filter_create)(Slapi_PBlock *); /* factory function */ -+ int32_t (*plg_un_mr_indexer_create)(Slapi_PBlock *); /* factory function */ - /* new style syntax plugin functions */ - /* not all functions will apply to all matching rule types */ - /* e.g. a SUBSTR rule will not have a filter_ava func */ -- IFP plg_un_mr_filter_ava; -- IFP plg_un_mr_filter_sub; -- IFP plg_un_mr_values2keys; -- IFP plg_un_mr_assertion2keys_ava; -- IFP plg_un_mr_assertion2keys_sub; -+ int32_t (*plg_un_mr_filter_ava)(Slapi_PBlock *, const struct berval *, Slapi_Value **, int32_t, Slapi_Value **); -+ int32_t (*plg_un_mr_filter_sub)(Slapi_PBlock *, char *, char **, char*, Slapi_Value **); -+ int32_t (*plg_un_mr_values2keys)(Slapi_PBlock *, Slapi_Value **, Slapi_Value ***, int32_t); -+ int32_t (*plg_un_mr_assertion2keys_ava)(Slapi_PBlock *, Slapi_Value *, Slapi_Value ***, int32_t); -+ int32_t (*plg_un_mr_assertion2keys_sub)(Slapi_PBlock *, char *, char **, char *, Slapi_Value ***); - int plg_un_mr_flags; - char **plg_un_mr_names; -- IFP plg_un_mr_compare; /* only for ORDERING */ -- VFPV plg_un_mr_normalize; -+ int32_t (*plg_un_mr_compare)(struct berval *, struct berval *); /* only for ORDERING */ -+ void (*plg_un_mr_normalize)(Slapi_PBlock *, char *, int32_t, char **); - } plg_un_mr; - #define plg_mr_filter_create plg_un.plg_un_mr.plg_un_mr_filter_create - #define plg_mr_indexer_create plg_un.plg_un_mr.plg_un_mr_indexer_create -@@ -1324,25 +1324,25 @@ struct slapdplugin - /* syntax plugin structure */ - struct plg_un_syntax_struct - { -- IFP plg_un_syntax_filter_ava; -+ int32_t (*plg_un_syntax_filter_ava)(Slapi_PBlock *, const struct berval *, Slapi_Value **, int32_t, Slapi_Value **); - IFP plg_un_syntax_filter_ava_sv; -- IFP plg_un_syntax_filter_sub; -+ int32_t (*plg_un_syntax_filter_sub)(Slapi_PBlock*, char *, char **, char *, Slapi_Value**); - IFP plg_un_syntax_filter_sub_sv; -- IFP plg_un_syntax_values2keys; -+ int32_t (*plg_un_syntax_values2keys)(Slapi_PBlock*, Slapi_Value**, Slapi_Value***, int32_t); - IFP plg_un_syntax_values2keys_sv; -- IFP plg_un_syntax_assertion2keys_ava; -- IFP plg_un_syntax_assertion2keys_sub; -+ int32_t (*plg_un_syntax_assertion2keys_ava)(Slapi_PBlock*, Slapi_Value*, Slapi_Value***, int32_t); -+ int32_t (*plg_un_syntax_assertion2keys_sub)(Slapi_PBlock*, char*, char**, char*, Slapi_Value***); - int plg_un_syntax_flags; - /* -- from slapi-plugin.h --#define SLAPI_PLUGIN_SYNTAX_FLAG_ORKEYS 1 --#define SLAPI_PLUGIN_SYNTAX_FLAG_ORDERING 2 --*/ -+ * from slapi-plugin.h -+#define SLAPI_PLUGIN_SYNTAX_FLAG_ORKEYS 1 -+#define SLAPI_PLUGIN_SYNTAX_FLAG_ORDERING 2 -+ */ - char **plg_un_syntax_names; - char *plg_un_syntax_oid; - IFP plg_un_syntax_compare; -- IFP plg_un_syntax_validate; -- VFPV plg_un_syntax_normalize; -+ int32_t (*plg_un_syntax_validate)(struct berval *); -+ void (*plg_un_syntax_normalize)(Slapi_PBlock *, char *, int32_t, char **); - } plg_un_syntax; - #define plg_syntax_filter_ava plg_un.plg_un_syntax.plg_un_syntax_filter_ava - #define plg_syntax_filter_sub plg_un.plg_un_syntax.plg_un_syntax_filter_sub -@@ -1359,10 +1359,11 @@ struct slapdplugin - struct plg_un_acl_struct - { - IFP plg_un_acl_init; -- IFP plg_un_acl_syntax_check; -- IFP plg_un_acl_access_allowed; -- IFP plg_un_acl_mods_allowed; -- IFP plg_un_acl_mods_update; -+ int32_t (*plg_un_acl_syntax_check)(Slapi_PBlock *, Slapi_Entry *, char **); -+ int32_t (*plg_un_acl_access_allowed)(Slapi_PBlock *, Slapi_Entry*, char **, struct berval *, int32_t, int32_t, char **); -+ int32_t (*plg_un_acl_mods_allowed)(Slapi_PBlock *, Slapi_Entry *, LDAPMod **, void *); -+ int32_t (*plg_un_acl_mods_update)(Slapi_PBlock *, int32_t, Slapi_DN *, void *); -+ - } plg_un_acl; - #define plg_acl_init plg_un.plg_un_acl.plg_un_acl_init - #define plg_acl_syntax_check plg_un.plg_un_acl.plg_un_acl_syntax_check -@@ -1372,8 +1373,8 @@ struct slapdplugin - - struct plg_un_mmr_struct - { -- IFP plg_un_mmr_betxn_preop; -- IFP plg_un_mmr_betxn_postop; -+ int32_t (*plg_un_mmr_betxn_preop)(Slapi_PBlock *, int32_t); -+ int32_t (*plg_un_mmr_betxn_postop)(Slapi_PBlock *, int32_t); - } plg_un_mmr; - #define plg_mmr_betxn_preop plg_un.plg_un_mmr.plg_un_mmr_betxn_preop - #define plg_mmr_betxn_postop plg_un.plg_un_mmr.plg_un_mmr_betxn_postop -@@ -1394,8 +1395,8 @@ struct slapdplugin - /* entry fetch/store */ - struct plg_un_entry_fetch_store_struct - { -- IFP plg_un_entry_fetch_func; -- IFP plg_un_entry_store_func; -+ int32_t (*plg_un_entry_fetch_func)(char **, uint32_t *); -+ int32_t (*plg_un_entry_store_func)(char **, uint32_t *); - } plg_un_entry_fetch_store; - #define plg_entryfetchfunc plg_un.plg_un_entry_fetch_store.plg_un_entry_fetch_func - #define plg_entrystorefunc plg_un.plg_un_entry_fetch_store.plg_un_entry_store_func -diff --git a/ldap/servers/slapd/slapi-private.h b/ldap/servers/slapd/slapi-private.h -index ec4b540c3..533c4e428 100644 ---- a/ldap/servers/slapd/slapi-private.h -+++ b/ldap/servers/slapd/slapi-private.h -@@ -1409,7 +1409,7 @@ int slapi_add_internal_attr_syntax(const char *name, const char *oid, const char - - /* pw.c */ - void pw_exp_init(void); --int pw_copy_entry_ext(Slapi_Entry *src_e, Slapi_Entry *dest_e); -+int pw_copy_entry_ext(const Slapi_Entry *src_e, Slapi_Entry *dest_e); - int pw_get_ext_size(Slapi_Entry *e, size_t *size); - - /* op_shared.c */ -diff --git a/ldap/servers/slapd/task.c b/ldap/servers/slapd/task.c -index c14af83e0..d2a9a1b48 100644 ---- a/ldap/servers/slapd/task.c -+++ b/ldap/servers/slapd/task.c -@@ -2036,7 +2036,7 @@ task_upgradedb_add(Slapi_PBlock *pb __attribute__((unused)), - int32_t task_flags = SLAPI_TASK_RUNNING_AS_TASK; - slapi_pblock_set(mypb, SLAPI_TASK_FLAGS, &task_flags); - -- rv = (be->be_database->plg_upgradedb)(&mypb); -+ rv = (be->be_database->plg_upgradedb)(mypb); - if (rv == 0) { - slapi_entry_attr_set_charptr(e, TASK_LOG_NAME, ""); - slapi_entry_attr_set_charptr(e, TASK_STATUS_NAME, ""); --- -2.52.0 - diff --git a/0012-Issue-7223-Revert-index-scan-limits-for-system-index.patch b/0012-Issue-7223-Revert-index-scan-limits-for-system-index.patch deleted file mode 100644 index c3fde35..0000000 --- a/0012-Issue-7223-Revert-index-scan-limits-for-system-index.patch +++ /dev/null @@ -1,785 +0,0 @@ -From 7a45b50bf3d9cfc8f7e805379fcb39d5669d6c8b Mon Sep 17 00:00:00 2001 -From: Viktor Ashirov -Date: Thu, 5 Feb 2026 12:17:06 +0100 -Subject: [PATCH] Issue 7223 - Revert index scan limits for system indexes - -This reverts changes introduced by the following commits: -c6f458b42 Issue 7189 - DSBLE0007 generates incorrect remediation commands for scan limits -8b6b3a9f9 Issue 6966 - On large DB, unlimited IDL scan limit reduce the SRCH performance - -Relates: https://github.com/389ds/389-ds-base/issues/7223 - -Reviewed by: @progier389, @tbordaz, @droideck (Thanks!) ---- - .../tests/suites/config/config_test.py | 27 +--- - .../healthcheck/health_system_indexes_test.py | 135 +----------------- - .../paged_results/paged_results_test.py | 25 +--- - ldap/servers/slapd/back-ldbm/back-ldbm.h | 1 - - ldap/servers/slapd/back-ldbm/index.c | 2 - - ldap/servers/slapd/back-ldbm/instance.c | 106 +++----------- - ldap/servers/slapd/back-ldbm/ldbm_config.c | 30 ---- - ldap/servers/slapd/back-ldbm/ldbm_config.h | 1 - - .../slapd/back-ldbm/ldbm_index_config.c | 8 -- - src/lib389/lib389/backend.py | 50 ++----- - src/lib389/lib389/cli_conf/backend.py | 20 --- - 11 files changed, 41 insertions(+), 364 deletions(-) - -diff --git a/dirsrvtests/tests/suites/config/config_test.py b/dirsrvtests/tests/suites/config/config_test.py -index b9ba684d9..6f11e7fc8 100644 ---- a/dirsrvtests/tests/suites/config/config_test.py -+++ b/dirsrvtests/tests/suites/config/config_test.py -@@ -715,19 +715,17 @@ def test_ndn_cache_size_enforcement(topo, request): - - request.addfinalizer(fin) - --def test_require_index(topo, request): -+def test_require_index(topo): - """Validate that unindexed searches are rejected - - :id: fb6e31f2-acc2-4e75-a195-5c356faeb803 - :setup: Standalone instance - :steps: - 1. Set "nsslapd-require-index" to "on" -- 2. ancestorid/idlscanlimit to 100 -- 3. Test an unindexed search is rejected -+ 2. Test an unindexed search is rejected - :expectedresults: - 1. Success - 2. Success -- 3. Success - """ - - # Set the config -@@ -738,10 +736,6 @@ def test_require_index(topo, request): - - db_cfg = DatabaseConfig(topo.standalone) - db_cfg.set([('nsslapd-idlistscanlimit', '100')]) -- backend = Backends(topo.standalone).get_backend(DEFAULT_SUFFIX) -- ancestorid_index = backend.get_index('ancestorid') -- ancestorid_index.replace("nsIndexIDListScanLimit", ensure_bytes("limit=100 type=eq flags=AND")) -- topo.standalone.restart() - - users = UserAccounts(topo.standalone, DEFAULT_SUFFIX) - for i in range(101): -@@ -752,15 +746,10 @@ def test_require_index(topo, request): - with pytest.raises(ldap.UNWILLING_TO_PERFORM): - raw_objects.filter("(description=test*)") - -- def fin(): -- ancestorid_index.replace("nsIndexIDListScanLimit", ensure_bytes("limit=5000 type=eq flags=AND")) -- -- request.addfinalizer(fin) -- - - - @pytest.mark.skipif(ds_is_older('1.4.2'), reason="The config setting only exists in 1.4.2 and higher") --def test_require_internal_index(topo, request): -+def test_require_internal_index(topo): - """Ensure internal operations require indexed attributes - - :id: 22b94f30-59e3-4f27-89a1-c4f4be036f7f -@@ -791,10 +780,6 @@ def test_require_internal_index(topo, request): - # Create a bunch of users - db_cfg = DatabaseConfig(topo.standalone) - db_cfg.set([('nsslapd-idlistscanlimit', '100')]) -- backend = Backends(topo.standalone).get_backend(DEFAULT_SUFFIX) -- ancestorid_index = backend.get_index('ancestorid') -- ancestorid_index.replace("nsIndexIDListScanLimit", ensure_bytes("limit=100 type=eq flags=AND")) -- topo.standalone.restart() - users = UserAccounts(topo.standalone, DEFAULT_SUFFIX) - for i in range(102, 202): - users.create_test_user(uid=i) -@@ -819,12 +804,6 @@ def test_require_internal_index(topo, request): - with pytest.raises(ldap.UNWILLING_TO_PERFORM): - user.delete() - -- def fin(): -- ancestorid_index.replace("nsIndexIDListScanLimit", ensure_bytes("limit=5000 type=eq flags=AND")) -- -- request.addfinalizer(fin) -- -- - - def get_pstack(pid): - """Get a pstack of the pid.""" -diff --git a/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py b/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py -index 5eadf6283..61972d60c 100644 ---- a/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py -+++ b/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py -@@ -171,8 +171,7 @@ def test_missing_parentid(topology_st, log_buffering_enabled): - - log.info("Re-add the parentId index") - backend = Backends(standalone).get("userRoot") -- backend.add_index("parentid", ["eq"], matching_rules=["integerOrderingMatch"], -- idlistscanlimit=['limit=5000 type=eq flags=AND']) -+ backend.add_index("parentid", ["eq"], matching_rules=["integerOrderingMatch"]) - - run_healthcheck_and_flush_log(topology_st, standalone, json=False, searched_code=CMD_OUTPUT) - run_healthcheck_and_flush_log(topology_st, standalone, json=True, searched_code=JSON_OUTPUT) -@@ -260,8 +259,7 @@ def test_usn_plugin_missing_entryusn(topology_st, usn_plugin_enabled, log_buffer - - log.info("Re-add the entryusn index") - backend = Backends(standalone).get("userRoot") -- backend.add_index("entryusn", ["eq"], matching_rules=["integerOrderingMatch"], -- idlistscanlimit=['limit=5000 type=eq flags=AND']) -+ backend.add_index("entryusn", ["eq"], matching_rules=["integerOrderingMatch"]) - - run_healthcheck_and_flush_log(topology_st, standalone, json=False, searched_code=CMD_OUTPUT) - run_healthcheck_and_flush_log(topology_st, standalone, json=True, searched_code=JSON_OUTPUT) -@@ -405,132 +403,6 @@ def test_retrocl_plugin_missing_matching_rule(topology_st, retrocl_plugin_enable - run_healthcheck_and_flush_log(topology_st, standalone, json=True, searched_code=JSON_OUTPUT) - - --def test_missing_scanlimit(topology_st, log_buffering_enabled): -- """Check if healthcheck returns DSBLE0007 code when parentId index is missing scanlimit -- -- :id: 40e1bf6a-2397-459b-bdf3-f787ca118b86 -- :setup: Standalone instance -- :steps: -- 1. Create DS instance -- 2. Remove nsIndexIDListScanLimit from parentId index -- 3. Use healthcheck without --json option -- 4. Use healthcheck with --json option -- 5. Verify the remediation command has properly quoted scanlimit -- 6. Re-add the scanlimit -- 7. Use healthcheck without --json option -- 8. Use healthcheck with --json option -- :expectedresults: -- 1. Success -- 2. Success -- 3. healthcheck reports DSBLE0007 code and related details -- 4. healthcheck reports DSBLE0007 code and related details -- 5. The scanlimit value is quoted in the remediation command -- 6. Success -- 7. healthcheck reports no issues found -- 8. healthcheck reports no issues found -- """ -- -- RET_CODE = "DSBLE0007" -- PARENTID_DN = "cn=parentid,cn=index,cn=userroot,cn=ldbm database,cn=plugins,cn=config" -- SCANLIMIT_VALUE = "limit=5000 type=eq flags=AND" -- -- standalone = topology_st.standalone -- -- log.info("Remove nsIndexIDListScanLimit from parentId index") -- parentid_index = Index(standalone, PARENTID_DN) -- parentid_index.remove("nsIndexIDListScanLimit", SCANLIMIT_VALUE) -- -- run_healthcheck_and_flush_log(topology_st, standalone, json=False, searched_code=RET_CODE) -- -- # Verify the remediation command has properly quoted scanlimit -- args = FakeArgs() -- args.instance = standalone.serverid -- args.verbose = standalone.verbose -- args.list_errors = False -- args.list_checks = False -- args.exclude_check = [] -- args.check = ["backends"] -- args.dry_run = False -- args.json = False -- health_check_run(standalone, topology_st.logcap.log, args) -- # Check that the scanlimit is quoted in the output -- assert topology_st.logcap.contains('--add-scanlimit "limit=5000 type=eq flags=AND"') -- log.info("Verified scanlimit is properly quoted in remediation command") -- topology_st.logcap.flush() -- -- run_healthcheck_and_flush_log(topology_st, standalone, json=True, searched_code=RET_CODE) -- -- log.info("Re-add the nsIndexIDListScanLimit") -- parentid_index = Index(standalone, PARENTID_DN) -- parentid_index.add("nsIndexIDListScanLimit", SCANLIMIT_VALUE) -- -- run_healthcheck_and_flush_log(topology_st, standalone, json=False, searched_code=CMD_OUTPUT) -- run_healthcheck_and_flush_log(topology_st, standalone, json=True, searched_code=JSON_OUTPUT) -- -- --def test_missing_matching_rule_and_scanlimit(topology_st, log_buffering_enabled): -- """Check if healthcheck generates a single combined command when both matching rule and scanlimit are missing -- -- :id: af8214ad-5e4c-422a-8f74-3e99227551df -- :setup: Standalone instance -- :steps: -- 1. Create DS instance -- 2. Remove both integerOrderingMatch and nsIndexIDListScanLimit from parentId index -- 3. Use healthcheck and verify a single combined command is generated -- 4. Re-add the matching rule and scanlimit -- 5. Use healthcheck without --json option -- 6. Use healthcheck with --json option -- :expectedresults: -- 1. Success -- 2. Success -- 3. healthcheck reports DSBLE0007 and generates a single command with both --add-mr and --add-scanlimit -- 4. Success -- 5. healthcheck reports no issues found -- 6. healthcheck reports no issues found -- """ -- -- RET_CODE = "DSBLE0007" -- PARENTID_DN = "cn=parentid,cn=index,cn=userroot,cn=ldbm database,cn=plugins,cn=config" -- SCANLIMIT_VALUE = "limit=5000 type=eq flags=AND" -- -- standalone = topology_st.standalone -- -- log.info("Remove both integerOrderingMatch and nsIndexIDListScanLimit from parentId index") -- parentid_index = Index(standalone, PARENTID_DN) -- parentid_index.remove("nsMatchingRule", "integerOrderingMatch") -- parentid_index.remove("nsIndexIDListScanLimit", SCANLIMIT_VALUE) -- -- # Run healthcheck and verify combined command -- args = FakeArgs() -- args.instance = standalone.serverid -- args.verbose = standalone.verbose -- args.list_errors = False -- args.list_checks = False -- args.exclude_check = [] -- args.check = ["backends"] -- args.dry_run = False -- args.json = False -- health_check_run(standalone, topology_st.logcap.log, args) -- -- # Verify DSBLE0007 is reported -- assert topology_st.logcap.contains(RET_CODE) -- log.info("healthcheck returned code: %s" % RET_CODE) -- -- # Verify a single combined command is generated with both --add-mr and --add-scanlimit -- assert topology_st.logcap.contains('--add-mr integerOrderingMatch --add-scanlimit "limit=5000 type=eq flags=AND"') -- log.info("Verified combined command with both --add-mr and --add-scanlimit") -- -- topology_st.logcap.flush() -- -- log.info("Re-add the integerOrderingMatch matching rule and scanlimit") -- parentid_index = Index(standalone, PARENTID_DN) -- parentid_index.add("nsMatchingRule", "integerOrderingMatch") -- parentid_index.add("nsIndexIDListScanLimit", SCANLIMIT_VALUE) -- -- run_healthcheck_and_flush_log(topology_st, standalone, json=False, searched_code=CMD_OUTPUT) -- run_healthcheck_and_flush_log(topology_st, standalone, json=True, searched_code=JSON_OUTPUT) -- -- - def test_multiple_missing_indexes(topology_st, log_buffering_enabled): - """Check if healthcheck returns DSBLE0007 code when multiple system indexes are missing - -@@ -571,8 +443,7 @@ def test_multiple_missing_indexes(topology_st, log_buffering_enabled): - - log.info("Re-add the missing system indexes") - backend = Backends(standalone).get("userRoot") -- backend.add_index("parentid", ["eq"], matching_rules=["integerOrderingMatch"], -- idlistscanlimit=['limit=5000 type=eq flags=AND']) -+ backend.add_index("parentid", ["eq"], matching_rules=["integerOrderingMatch"]) - backend.add_index("nsuniqueid", ["eq"]) - - run_healthcheck_and_flush_log(topology_st, standalone, json=False, searched_code=CMD_OUTPUT) -diff --git a/dirsrvtests/tests/suites/paged_results/paged_results_test.py b/dirsrvtests/tests/suites/paged_results/paged_results_test.py -index 61d6702da..1bb94b53a 100644 ---- a/dirsrvtests/tests/suites/paged_results/paged_results_test.py -+++ b/dirsrvtests/tests/suites/paged_results/paged_results_test.py -@@ -306,19 +306,19 @@ def test_search_success(topology_st, create_user, page_size, users_num): - del_users(users_list) - - --@pytest.mark.parametrize("page_size,users_num,suffix,attr_name,attr_value,expected_err, restart", [ -+@pytest.mark.parametrize("page_size,users_num,suffix,attr_name,attr_value,expected_err", [ - (50, 200, 'cn=config,%s' % DN_LDBM, 'nsslapd-idlistscanlimit', '100', -- ldap.UNWILLING_TO_PERFORM, True), -+ ldap.UNWILLING_TO_PERFORM), - (5, 15, DN_CONFIG, 'nsslapd-timelimit', '20', -- ldap.UNAVAILABLE_CRITICAL_EXTENSION, False), -+ ldap.UNAVAILABLE_CRITICAL_EXTENSION), - (21, 50, DN_CONFIG, 'nsslapd-sizelimit', '20', -- ldap.SIZELIMIT_EXCEEDED, False), -+ ldap.SIZELIMIT_EXCEEDED), - (21, 50, DN_CONFIG, 'nsslapd-pagedsizelimit', '5', -- ldap.SIZELIMIT_EXCEEDED, False), -+ ldap.SIZELIMIT_EXCEEDED), - (5, 50, 'cn=config,%s' % DN_LDBM, 'nsslapd-lookthroughlimit', '20', -- ldap.ADMINLIMIT_EXCEEDED, False)]) -+ ldap.ADMINLIMIT_EXCEEDED)]) - def test_search_limits_fail(topology_st, create_user, page_size, users_num, -- suffix, attr_name, attr_value, expected_err, restart): -+ suffix, attr_name, attr_value, expected_err): - """Verify that search with a simple paged results control - throws expected exceptoins when corresponding limits are - exceeded. -@@ -341,15 +341,6 @@ def test_search_limits_fail(topology_st, create_user, page_size, users_num, - - users_list = add_users(topology_st, users_num, DEFAULT_SUFFIX) - attr_value_bck = change_conf_attr(topology_st, suffix, attr_name, attr_value) -- ancestorid_index = None -- if attr_name == 'nsslapd-idlistscanlimit': -- backend = Backends(topology_st.standalone).get_backend(DEFAULT_SUFFIX) -- ancestorid_index = backend.get_index('ancestorid') -- ancestorid_index.replace("nsIndexIDListScanLimit", ensure_bytes("limit=100 type=eq flags=AND")) -- -- if (restart): -- log.info('Instance restarted') -- topology_st.standalone.restart() - conf_param_dict = {attr_name: attr_value} - search_flt = r'(uid=test*)' - searchreq_attrlist = ['dn', 'sn'] -@@ -402,8 +393,6 @@ def test_search_limits_fail(topology_st, create_user, page_size, users_num, - else: - break - finally: -- if ancestorid_index: -- ancestorid_index.replace("nsIndexIDListScanLimit", ensure_bytes("limit=5000 type=eq flags=AND")) - del_users(users_list) - change_conf_attr(topology_st, suffix, attr_name, attr_value_bck) - -diff --git a/ldap/servers/slapd/back-ldbm/back-ldbm.h b/ldap/servers/slapd/back-ldbm/back-ldbm.h -index 5e4988782..a4993208c 100644 ---- a/ldap/servers/slapd/back-ldbm/back-ldbm.h -+++ b/ldap/servers/slapd/back-ldbm/back-ldbm.h -@@ -561,7 +561,6 @@ struct ldbminfo - int li_mode; - int li_lookthroughlimit; - int li_allidsthreshold; -- int li_system_allidsthreshold; - char *li_directory; - int li_reslimit_lookthrough_handle; - uint64_t li_dbcachesize; -diff --git a/ldap/servers/slapd/back-ldbm/index.c b/ldap/servers/slapd/back-ldbm/index.c -index e06a8ee5f..90129b682 100644 ---- a/ldap/servers/slapd/back-ldbm/index.c -+++ b/ldap/servers/slapd/back-ldbm/index.c -@@ -1007,8 +1007,6 @@ index_read_ext_allids( - } - if (pb) { - slapi_pblock_get(pb, SLAPI_SEARCH_IS_AND, &is_and); -- } else if (strcasecmp(type, LDBM_ANCESTORID_STR) == 0) { -- is_and = 1; - } - ai_flags = is_and ? INDEX_ALLIDS_FLAG_AND : 0; - /* the caller can pass in a value of 0 - just ignore those - but if the index -diff --git a/ldap/servers/slapd/back-ldbm/instance.c b/ldap/servers/slapd/back-ldbm/instance.c -index 23bd70243..f9a546661 100644 ---- a/ldap/servers/slapd/back-ldbm/instance.c -+++ b/ldap/servers/slapd/back-ldbm/instance.c -@@ -16,7 +16,7 @@ - - /* Forward declarations */ - static void ldbm_instance_destructor(void **arg); --Slapi_Entry *ldbm_instance_init_config_entry(char *cn_val, char *v1, char *v2, char *v3, char *v4, char *mr, char *scanlimit); -+Slapi_Entry *ldbm_instance_init_config_entry(char *cn_val, char *v1, char *v2, char *v3, char *v4, char *mr); - - - /* Creates and initializes a new ldbm_instance structure. -@@ -127,7 +127,7 @@ done: - * Take a bunch of strings, and create a index config entry - */ - Slapi_Entry * --ldbm_instance_init_config_entry(char *cn_val, char *val1, char *val2, char *val3, char *val4, char *mr, char *scanlimit) -+ldbm_instance_init_config_entry(char *cn_val, char *val1, char *val2, char *val3, char *val4, char *mr) - { - Slapi_Entry *e = slapi_entry_alloc(); - struct berval *vals[2]; -@@ -168,11 +168,6 @@ ldbm_instance_init_config_entry(char *cn_val, char *val1, char *val2, char *val3 - slapi_entry_add_values(e, "nsMatchingRule", vals); - } - -- if (scanlimit) { -- val.bv_val = scanlimit; -- val.bv_len = strlen(scanlimit); -- slapi_entry_add_values(e, "nsIndexIDListScanLimit", vals); -- } - return e; - } - -@@ -185,60 +180,8 @@ ldbm_instance_create_default_indexes(backend *be) - { - Slapi_Entry *e; - ldbm_instance *inst = (ldbm_instance *)be->be_instance_info; -- struct ldbminfo *li = (struct ldbminfo *)be->be_database->plg_private; - /* write the dse file only on the final index */ - int flags = LDBM_INSTANCE_CONFIG_DONT_WRITE; -- char *ancestorid_indexes_limit = NULL; -- char *parentid_indexes_limit = NULL; -- struct attrinfo *ai = NULL; -- int index_already_configured = 0; -- struct index_idlistsizeinfo *iter; -- int cookie; -- int limit; -- -- ainfo_get(be, (char *)LDBM_ANCESTORID_STR, &ai); -- if (ai && ai->ai_idlistinfo) { -- iter = (struct index_idlistsizeinfo *)dl_get_first(ai->ai_idlistinfo, &cookie); -- if (iter) { -- limit = iter->ai_idlistsizelimit; -- slapi_log_err(SLAPI_LOG_BACKLDBM, "ldbm_instance_create_default_indexes", -- "set ancestorid limit to %d from attribute index\n", -- limit); -- } else { -- limit = li->li_system_allidsthreshold; -- slapi_log_err(SLAPI_LOG_BACKLDBM, "ldbm_instance_create_default_indexes", -- "set ancestorid limit to %d from default (fail to read limit)\n", -- limit); -- } -- ancestorid_indexes_limit = slapi_ch_smprintf("limit=%d type=eq flags=AND", limit); -- } else { -- ancestorid_indexes_limit = slapi_ch_smprintf("limit=%d type=eq flags=AND", li->li_system_allidsthreshold); -- slapi_log_err(SLAPI_LOG_BACKLDBM, "ldbm_instance_create_default_indexes", -- "set ancestorid limit to %d from default (no attribute or limit)\n", -- li->li_system_allidsthreshold); -- } -- -- ainfo_get(be, (char *)LDBM_PARENTID_STR, &ai); -- if (ai && ai->ai_idlistinfo) { -- iter = (struct index_idlistsizeinfo *)dl_get_first(ai->ai_idlistinfo, &cookie); -- if (iter) { -- limit = iter->ai_idlistsizelimit; -- slapi_log_err(SLAPI_LOG_BACKLDBM, "ldbm_instance_create_default_indexes", -- "set parentid limit to %d from attribute index\n", -- limit); -- } else { -- limit = li->li_system_allidsthreshold; -- slapi_log_err(SLAPI_LOG_BACKLDBM, "ldbm_instance_create_default_indexes", -- "set parentid limit to %d from default (fail to read limit)\n", -- limit); -- } -- parentid_indexes_limit = slapi_ch_smprintf("limit=%d type=eq flags=AND", limit); -- } else { -- parentid_indexes_limit = slapi_ch_smprintf("limit=%d type=eq flags=AND", li->li_system_allidsthreshold); -- slapi_log_err(SLAPI_LOG_BACKLDBM, "ldbm_instance_create_default_indexes", -- "set parentid limit to %d from default (no attribute or limit)\n", -- li->li_system_allidsthreshold); -- } - - /* - * Always index (entrydn or entryrdn), parentid, objectclass, -@@ -247,53 +190,47 @@ ldbm_instance_create_default_indexes(backend *be) - * ACL routines. - */ - if (entryrdn_get_switch()) { /* subtree-rename: on */ -- e = ldbm_instance_init_config_entry(LDBM_ENTRYRDN_STR, "subtree", 0, 0, 0, 0, 0); -+ e = ldbm_instance_init_config_entry(LDBM_ENTRYRDN_STR, "subtree", 0, 0, 0, 0); - ldbm_instance_config_add_index_entry(inst, e, flags); - slapi_entry_free(e); - } else { -- e = ldbm_instance_init_config_entry(LDBM_ENTRYDN_STR, "eq", 0, 0, 0, 0, 0); -+ e = ldbm_instance_init_config_entry(LDBM_ENTRYDN_STR, "eq", 0, 0, 0, 0); - ldbm_instance_config_add_index_entry(inst, e, flags); - slapi_entry_free(e); - } - -- ainfo_get(be, (char *)LDBM_PARENTID_STR, &ai); -- /* Check if the attrinfo is actually for parentid, not a fallback to .default */ -- index_already_configured = (ai != NULL && strcmp(ai->ai_type, LDBM_PARENTID_STR) == 0); -- if (!index_already_configured) { -- e = ldbm_instance_init_config_entry(LDBM_PARENTID_STR, "eq", 0, 0, 0, "integerOrderingMatch", parentid_indexes_limit); -- ldbm_instance_config_add_index_entry(inst, e, flags); -- attr_index_config(be, "ldbm index init", 0, e, 1, 0, NULL); -- slapi_entry_free(e); -- } -+ e = ldbm_instance_init_config_entry(LDBM_PARENTID_STR, "eq", 0, 0, 0, "integerOrderingMatch"); -+ ldbm_instance_config_add_index_entry(inst, e, flags); -+ slapi_entry_free(e); - -- e = ldbm_instance_init_config_entry("objectclass", "eq", 0, 0, 0, 0, 0); -+ e = ldbm_instance_init_config_entry("objectclass", "eq", 0, 0, 0, 0); - ldbm_instance_config_add_index_entry(inst, e, flags); - slapi_entry_free(e); - -- e = ldbm_instance_init_config_entry("aci", "pres", 0, 0, 0, 0, 0); -+ e = ldbm_instance_init_config_entry("aci", "pres", 0, 0, 0, 0); - ldbm_instance_config_add_index_entry(inst, e, flags); - slapi_entry_free(e); - -- e = ldbm_instance_init_config_entry(LDBM_NUMSUBORDINATES_STR, "pres", 0, 0, 0, 0, 0); -+ e = ldbm_instance_init_config_entry(LDBM_NUMSUBORDINATES_STR, "pres", 0, 0, 0, 0); - ldbm_instance_config_add_index_entry(inst, e, flags); - slapi_entry_free(e); - -- e = ldbm_instance_init_config_entry(SLAPI_ATTR_UNIQUEID, "eq", 0, 0, 0, 0, 0); -+ e = ldbm_instance_init_config_entry(SLAPI_ATTR_UNIQUEID, "eq", 0, 0, 0, 0); - ldbm_instance_config_add_index_entry(inst, e, flags); - slapi_entry_free(e); - - /* For MMR, we need this attribute (to replace use of dncomp in delete). */ -- e = ldbm_instance_init_config_entry(ATTR_NSDS5_REPLCONFLICT, "eq", "pres", 0, 0, 0, 0); -+ e = ldbm_instance_init_config_entry(ATTR_NSDS5_REPLCONFLICT, "eq", "pres", 0, 0, 0); - ldbm_instance_config_add_index_entry(inst, e, flags); - slapi_entry_free(e); - - /* write the dse file only on the final index */ -- e = ldbm_instance_init_config_entry(SLAPI_ATTR_NSCP_ENTRYDN, "eq", 0, 0, 0, 0, 0); -+ e = ldbm_instance_init_config_entry(SLAPI_ATTR_NSCP_ENTRYDN, "eq", 0, 0, 0, 0); - ldbm_instance_config_add_index_entry(inst, e, flags); - slapi_entry_free(e); - - /* ldbm_instance_config_add_index_entry(inst, 2, argv); */ -- e = ldbm_instance_init_config_entry(LDBM_PSEUDO_ATTR_DEFAULT, "none", 0, 0, 0, 0, 0); -+ e = ldbm_instance_init_config_entry(LDBM_PSEUDO_ATTR_DEFAULT, "none", 0, 0, 0, 0); - attr_index_config(be, "ldbm index init", 0, e, 1, 0, NULL); - slapi_entry_free(e); - -@@ -302,20 +239,11 @@ ldbm_instance_create_default_indexes(backend *be) - * ancestorid is special, there is actually no such attr type - * but we still want to use the attr index file APIs. - */ -- ainfo_get(be, (char *)LDBM_ANCESTORID_STR, &ai); -- /* Check if the attrinfo is actually for ancestorid, not a fallback to .default */ -- index_already_configured = (ai != NULL && strcmp(ai->ai_type, LDBM_ANCESTORID_STR) == 0); -- if (!index_already_configured) { -- e = ldbm_instance_init_config_entry(LDBM_ANCESTORID_STR, "eq", 0, 0, 0, "integerOrderingMatch", ancestorid_indexes_limit); -- ldbm_instance_config_add_index_entry(inst, e, flags); -- attr_index_config(be, "ldbm index init", 0, e, 1, 0, NULL); -- slapi_entry_free(e); -- } -+ e = ldbm_instance_init_config_entry(LDBM_ANCESTORID_STR, "eq", 0, 0, 0, "integerOrderingMatch"); -+ attr_index_config(be, "ldbm index init", 0, e, 1, 0, NULL); -+ slapi_entry_free(e); - } - -- slapi_ch_free_string(&ancestorid_indexes_limit); -- slapi_ch_free_string(&parentid_indexes_limit); -- - return 0; - } - -diff --git a/ldap/servers/slapd/back-ldbm/ldbm_config.c b/ldap/servers/slapd/back-ldbm/ldbm_config.c -index d8ffc4479..5cce0dbd3 100644 ---- a/ldap/servers/slapd/back-ldbm/ldbm_config.c -+++ b/ldap/servers/slapd/back-ldbm/ldbm_config.c -@@ -386,35 +386,6 @@ ldbm_config_allidsthreshold_set(void *arg, void *value, char *errorbuf __attribu - return retval; - } - --static void * --ldbm_config_system_allidsthreshold_get(void *arg) --{ -- struct ldbminfo *li = (struct ldbminfo *)arg; -- -- return (void *)((uintptr_t)(li->li_system_allidsthreshold)); --} -- --static int --ldbm_config_system_allidsthreshold_set(void *arg, void *value, char *errorbuf __attribute__((unused)), int phase __attribute__((unused)), int apply) --{ -- struct ldbminfo *li = (struct ldbminfo *)arg; -- int retval = LDAP_SUCCESS; -- int val = (int)((uintptr_t)value); -- -- /* Do whatever we can to make sure the data is ok. */ -- -- /* Catch attempts to configure a stupidly low ancestorid allidsthreshold */ -- if ((val > -1) && (val < 5000)) { -- val = 5000; -- } -- -- if (apply) { -- li->li_system_allidsthreshold = val; -- } -- -- return retval; --} -- - static void * - ldbm_config_pagedallidsthreshold_get(void *arg) - { -@@ -1133,7 +1104,6 @@ static config_info ldbm_config[] = { - {CONFIG_LOOKTHROUGHLIMIT, CONFIG_TYPE_INT, "5000", &ldbm_config_lookthroughlimit_get, &ldbm_config_lookthroughlimit_set, CONFIG_FLAG_ALWAYS_SHOW | CONFIG_FLAG_ALLOW_RUNNING_CHANGE}, - {CONFIG_MODE, CONFIG_TYPE_INT_OCTAL, "0600", &ldbm_config_mode_get, &ldbm_config_mode_set, CONFIG_FLAG_ALWAYS_SHOW | CONFIG_FLAG_ALLOW_RUNNING_CHANGE}, - {CONFIG_IDLISTSCANLIMIT, CONFIG_TYPE_INT, "2147483646", &ldbm_config_allidsthreshold_get, &ldbm_config_allidsthreshold_set, CONFIG_FLAG_ALWAYS_SHOW | CONFIG_FLAG_ALLOW_RUNNING_CHANGE}, -- {CONFIG_SYSTEMIDLISTSCANLIMIT, CONFIG_TYPE_INT, "5000", &ldbm_config_system_allidsthreshold_get, &ldbm_config_system_allidsthreshold_set, CONFIG_FLAG_ALWAYS_SHOW | CONFIG_FLAG_ALLOW_RUNNING_CHANGE}, - {CONFIG_DIRECTORY, CONFIG_TYPE_STRING, "", &ldbm_config_directory_get, &ldbm_config_directory_set, CONFIG_FLAG_ALWAYS_SHOW | CONFIG_FLAG_ALLOW_RUNNING_CHANGE | CONFIG_FLAG_SKIP_DEFAULT_SETTING}, - {CONFIG_MAXPASSBEFOREMERGE, CONFIG_TYPE_INT, "100", &ldbm_config_maxpassbeforemerge_get, &ldbm_config_maxpassbeforemerge_set, 0}, - -diff --git a/ldap/servers/slapd/back-ldbm/ldbm_config.h b/ldap/servers/slapd/back-ldbm/ldbm_config.h -index 30e3477ed..e1f05d7a2 100644 ---- a/ldap/servers/slapd/back-ldbm/ldbm_config.h -+++ b/ldap/servers/slapd/back-ldbm/ldbm_config.h -@@ -60,7 +60,6 @@ struct config_info - #define CONFIG_RANGELOOKTHROUGHLIMIT "nsslapd-rangelookthroughlimit" - #define CONFIG_PAGEDLOOKTHROUGHLIMIT "nsslapd-pagedlookthroughlimit" - #define CONFIG_IDLISTSCANLIMIT "nsslapd-idlistscanlimit" --#define CONFIG_SYSTEMIDLISTSCANLIMIT "nsslapd-systemidlistscanlimit" - #define CONFIG_PAGEDIDLISTSCANLIMIT "nsslapd-pagedidlistscanlimit" - #define CONFIG_DIRECTORY "nsslapd-directory" - #define CONFIG_MODE "nsslapd-mode" -diff --git a/ldap/servers/slapd/back-ldbm/ldbm_index_config.c b/ldap/servers/slapd/back-ldbm/ldbm_index_config.c -index bae2a64b9..38e7368e1 100644 ---- a/ldap/servers/slapd/back-ldbm/ldbm_index_config.c -+++ b/ldap/servers/slapd/back-ldbm/ldbm_index_config.c -@@ -384,14 +384,6 @@ ldbm_instance_config_add_index_entry( - } - } - -- /* get nsIndexIDListScanLimit and its values, and add them */ -- if (0 == slapi_entry_attr_find(e, "nsIndexIDListScanLimit", &attr)) { -- for (j = slapi_attr_first_value(attr, &sval); j != -1; j = slapi_attr_next_value(attr, j, &sval)) { -- attrValue = slapi_value_get_berval(sval); -- eBuf = PR_sprintf_append(eBuf, "nsIndexIDListScanLimit: %s\n", attrValue->bv_val); -- } -- } -- - ldbm_config_add_dse_entry(li, eBuf, flags); - if (eBuf) { - PR_smprintf_free(eBuf); -diff --git a/src/lib389/lib389/backend.py b/src/lib389/lib389/backend.py -index d3c9ccf35..1d9be4683 100644 ---- a/src/lib389/lib389/backend.py -+++ b/src/lib389/lib389/backend.py -@@ -615,10 +615,11 @@ class Backend(DSLdapObject): - indexes = self.get_indexes() - - # Default system indexes taken from ldap/servers/slapd/back-ldbm/instance.c -+ # Note: entryrdn and ancestorid are internal system indexes that are not -+ # exposed in cn=config - they are managed internally by the server. -+ # Only parentid has a DSE config entry (for the integerOrderingMatch rule). - expected_system_indexes = { -- 'entryrdn': {'types': ['subtree'], 'matching_rule': None}, -- 'parentid': {'types': ['eq'], 'matching_rule': 'integerOrderingMatch', 'scanlimit': 'limit=5000 type=eq flags=AND'}, -- 'ancestorid': {'types': ['eq'], 'matching_rule': 'integerOrderingMatch', 'scanlimit': 'limit=5000 type=eq flags=AND'}, -+ 'parentid': {'types': ['eq'], 'matching_rule': 'integerOrderingMatch'}, - 'objectClass': {'types': ['eq'], 'matching_rule': None}, - 'aci': {'types': ['pres'], 'matching_rule': None}, - 'nscpEntryDN': {'types': ['eq'], 'matching_rule': None}, -@@ -675,17 +676,14 @@ class Backend(DSLdapObject): - # Generate remediation command - index_types = ' '.join([f"--index-type {t}" for t in expected_config['types']]) - cmd = f"dsconf YOUR_INSTANCE backend index add {bename} --attr {attr_name} {index_types}" -- if expected_config.get('matching_rule'): -+ if expected_config['matching_rule']: - cmd += f" --matching-rule {expected_config['matching_rule']}" -- if expected_config.get('scanlimit'): -- cmd += f" --add-scanlimit \"{expected_config['scanlimit']}\"" - remediation_commands.append(cmd) - reindex_attrs.add(attr_name) # New index needs reindexing - else: - # Index exists, check configuration - actual_types = index.get_attr_vals_utf8('nsIndexType') or [] - actual_mrs = index.get_attr_vals_utf8('nsMatchingRule') or [] -- actual_scanlimit = index.get_attr_vals_utf8('nsIndexIDListScanLimit') or [] - - # Normalize to lowercase for comparison - actual_types = [t.lower() for t in actual_types] -@@ -700,31 +698,16 @@ class Backend(DSLdapObject): - remediation_commands.append(cmd) - reindex_attrs.add(attr_name) - -- # Check matching rules and scanlimit together to generate a single combined command -+ # Check matching rules - expected_mr = expected_config.get('matching_rule') -- expected_scanlimit = expected_config.get('scanlimit') -- -- missing_mr = False - if expected_mr: - actual_mrs_lower = [mr.lower() for mr in actual_mrs] - if expected_mr.lower() not in actual_mrs_lower: - discrepancies.append(f"Index {attr_name} missing matching rule: {expected_mr}") -- missing_mr = True -- -- missing_scanlimit = False -- if expected_scanlimit and (len(actual_scanlimit) == 0): -- discrepancies.append(f"Index {attr_name} missing fine grain definition of IDs limit: {expected_scanlimit}") -- missing_scanlimit = True -- -- # Generate a single combined command for all missing items -- if missing_mr or missing_scanlimit: -- cmd = f"dsconf YOUR_INSTANCE backend index set {bename} --attr {attr_name}" -- if missing_mr: -- cmd += f" --add-mr {expected_mr}" -- if missing_scanlimit: -- cmd += f" --add-scanlimit \"{expected_scanlimit}\"" -- remediation_commands.append(cmd) -- reindex_attrs.add(attr_name) -+ # Add the missing matching rule -+ cmd = f"dsconf YOUR_INSTANCE backend index set {bename} --attr {attr_name} --add-mr {expected_mr}" -+ remediation_commands.append(cmd) -+ reindex_attrs.add(attr_name) - - except Exception as e: - self._log.debug(f"_lint_system_indexes - Error checking index {attr_name}: {e}") -@@ -963,13 +946,12 @@ class Backend(DSLdapObject): - return - raise ValueError("Can not delete index because it does not exist") - -- def add_index(self, attr_name, types, matching_rules=None, idlistscanlimit=None, reindex=False): -+ def add_index(self, attr_name, types, matching_rules=None, reindex=False): - """ Add an index. - - :param attr_name - name of the attribute to index - :param types - a List of index types(eq, pres, sub, approx) - :param matching_rules - a List of matching rules for the index -- :param idlistscanlimit - a List of fine grain definitions for scanning limit - :param reindex - If set to True then index the attribute after creating it. - """ - -@@ -999,15 +981,6 @@ class Backend(DSLdapObject): - # Only add if there are actually rules present in the list. - if len(mrs) > 0: - props['nsMatchingRule'] = mrs -- -- if idlistscanlimit is not None: -- scanlimits = [] -- for scanlimit in idlistscanlimit: -- scanlimits.append(scanlimit) -- # Only add if there are actually limits in the list. -- if len(scanlimits) > 0: -- props['nsIndexIDListScanLimit'] = scanlimits -- - new_index.create(properties=props, basedn="cn=index," + self._dn) - - if reindex: -@@ -1314,7 +1287,6 @@ class DatabaseConfig(DSLdapObject): - 'nsslapd-lookthroughlimit', - 'nsslapd-mode', - 'nsslapd-idlistscanlimit', -- 'nsslapd-systemidlistscanlimit', - 'nsslapd-directory', - 'nsslapd-import-cachesize', - 'nsslapd-idl-switch', -diff --git a/src/lib389/lib389/cli_conf/backend.py b/src/lib389/lib389/cli_conf/backend.py -index dcf57d006..80008d22d 100644 ---- a/src/lib389/lib389/cli_conf/backend.py -+++ b/src/lib389/lib389/cli_conf/backend.py -@@ -39,7 +39,6 @@ arg_to_attr = { - 'mode': 'nsslapd-mode', - 'state': 'nsslapd-state', - 'idlistscanlimit': 'nsslapd-idlistscanlimit', -- 'systemidlistscanlimit': 'nsslapd-systemidlistscanlimit', - 'directory': 'nsslapd-directory', - 'dbcachesize': 'nsslapd-dbcachesize', - 'logdirectory': 'nsslapd-db-logdirectory', -@@ -626,21 +625,6 @@ def backend_set_index(inst, basedn, log, args): - except ldap.NO_SUCH_ATTRIBUTE: - raise ValueError('Can not delete matching rule type because it does not exist') - -- if args.replace_scanlimit is not None: -- for replace_scanlimit in args.replace_scanlimit: -- index.replace('nsIndexIDListScanLimit', replace_scanlimit) -- -- if args.add_scanlimit is not None: -- for add_scanlimit in args.add_scanlimit: -- index.add('nsIndexIDListScanLimit', add_scanlimit) -- -- if args.del_scanlimit is not None: -- for del_scanlimit in args.del_scanlimit: -- try: -- index.remove('nsIndexIDListScanLimit', del_scanlimit) -- except ldap.NO_SUCH_ATTRIBUTE: -- raise ValueError('Can not delete a fine grain limit definition because it does not exist') -- - if args.reindex: - be.reindex(attrs=[args.attr]) - log.info("Index successfully updated") -@@ -962,9 +946,6 @@ def create_parser(subparsers): - edit_index_parser.add_argument('--del-type', action='append', help='Removes an index type from the index: (eq, sub, pres, or approx)') - edit_index_parser.add_argument('--add-mr', action='append', help='Adds a matching-rule to the index') - edit_index_parser.add_argument('--del-mr', action='append', help='Removes a matching-rule from the index') -- edit_index_parser.add_argument('--add-scanlimit', action='append', help='Adds a fine grain limit definiton to the index') -- edit_index_parser.add_argument('--replace-scanlimit', action='append', help='Replaces a fine grain limit definiton to the index') -- edit_index_parser.add_argument('--del-scanlimit', action='append', help='Removes a fine grain limit definiton to the index') - edit_index_parser.add_argument('--reindex', action='store_true', help='Re-indexes the database after editing the index') - edit_index_parser.add_argument('be_name', help='The backend name or suffix') - -@@ -1091,7 +1072,6 @@ def create_parser(subparsers): - 'will check when examining candidate entries in response to a search request') - set_db_config_parser.add_argument('--mode', help='Specifies the permissions used for newly created index files') - set_db_config_parser.add_argument('--idlistscanlimit', help='Specifies the number of entry IDs that are searched during a search operation') -- set_db_config_parser.add_argument('--systemidlistscanlimit', help='Specifies the number of entry IDs that are fetch from ancestorid/parentid indexes') - set_db_config_parser.add_argument('--directory', help='Specifies absolute path to database instance') - set_db_config_parser.add_argument('--dbcachesize', help='Specifies the database index cache size in bytes') - set_db_config_parser.add_argument('--logdirectory', help='Specifies the path to the directory that contains the database transaction logs') --- -2.52.0 - diff --git a/0013-Issue-7223-Add-upgrade-function-to-remove-nsIndexIDL.patch b/0013-Issue-7223-Add-upgrade-function-to-remove-nsIndexIDL.patch deleted file mode 100644 index b55d17b..0000000 --- a/0013-Issue-7223-Add-upgrade-function-to-remove-nsIndexIDL.patch +++ /dev/null @@ -1,212 +0,0 @@ -From a58212943da2604091e7d5a20829ab54970d41c9 Mon Sep 17 00:00:00 2001 -From: Viktor Ashirov -Date: Thu, 5 Feb 2026 12:17:06 +0100 -Subject: [PATCH] Issue 7223 - Add upgrade function to remove - nsIndexIDListScanLimit from parentid - -Description: -Add `upgrade_remove_index_scanlimit()` function that removes the -nsIndexIDListScanLimit attribute from parentid index configuration -if present. - -This attribute was incorrectly added by a previous version and can -cause issues with index configuration. The upgrade function runs -automatically on server startup and removes the attribute if found. - -Relates: https://github.com/389ds/389-ds-base/issues/7223 - -Reviewed by: @progier389, @tbordaz, @droideck (Thanks!) ---- - .../healthcheck/health_system_indexes_test.py | 52 +++++++++ - ldap/servers/slapd/upgrade.c | 105 ++++++++++++++++++ - 2 files changed, 157 insertions(+) - -diff --git a/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py b/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py -index 61972d60c..b0d7a99ec 100644 ---- a/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py -+++ b/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py -@@ -450,6 +450,58 @@ def test_multiple_missing_indexes(topology_st, log_buffering_enabled): - run_healthcheck_and_flush_log(topology_st, standalone, json=True, searched_code=JSON_OUTPUT) - - -+def test_upgrade_removes_parentid_scanlimit(topology_st): -+ """Check if upgrade function removes nsIndexIDListScanLimit from parentid index -+ -+ :id: 2808886e-c1c1-441d-b3a3-299c4ef1ab4a -+ :setup: Standalone instance -+ :steps: -+ 1. Create DS instance -+ 2. Stop the server -+ 3. Use DSEldif to add nsIndexIDListScanLimit to parentid index -+ 4. Start the server (triggers upgrade) -+ 5. Verify nsIndexIDListScanLimit is removed from parentid index -+ :expectedresults: -+ 1. Success -+ 2. Success -+ 3. Success -+ 4. Success -+ 5. nsIndexIDListScanLimit is no longer present -+ """ -+ from lib389.dseldif import DSEldif -+ -+ standalone = topology_st.standalone -+ PARENTID_DN = "cn=parentid,cn=index,cn=userroot,cn=ldbm database,cn=plugins,cn=config" -+ SCANLIMIT_VALUE = "limit=5000 type=eq flags=AND" -+ -+ log.info("Stop the server") -+ standalone.stop() -+ -+ log.info("Add nsIndexIDListScanLimit to parentid index using DSEldif") -+ dse_ldif = DSEldif(standalone) -+ dse_ldif.add(PARENTID_DN, "nsIndexIDListScanLimit", SCANLIMIT_VALUE) -+ -+ # Verify it was added -+ scanlimit = dse_ldif.get(PARENTID_DN, "nsIndexIDListScanLimit") -+ assert scanlimit is not None, "Failed to add nsIndexIDListScanLimit" -+ log.info(f"Added nsIndexIDListScanLimit: {scanlimit}") -+ -+ log.info("Start the server (triggers upgrade)") -+ standalone.start() -+ -+ log.info("Verify nsIndexIDListScanLimit was removed by upgrade") -+ # Check via LDAP - the upgrade should have removed it -+ parentid_index = Index(standalone, PARENTID_DN) -+ scanlimit_after = parentid_index.get_attr_vals_utf8("nsIndexIDListScanLimit") -+ log.info(f"nsIndexIDListScanLimit after upgrade: {scanlimit_after}") -+ -+ # The upgrade function should have removed nsIndexIDListScanLimit -+ assert not scanlimit_after, \ -+ f"nsIndexIDListScanLimit should have been removed but found: {scanlimit_after}" -+ -+ log.info("Upgrade successfully removed nsIndexIDListScanLimit from parentid index") -+ -+ - if __name__ == "__main__": - # Run isolated - # -s for DEBUG mode -diff --git a/ldap/servers/slapd/upgrade.c b/ldap/servers/slapd/upgrade.c -index 43906c1af..adfec63de 100644 ---- a/ldap/servers/slapd/upgrade.c -+++ b/ldap/servers/slapd/upgrade.c -@@ -279,6 +279,107 @@ upgrade_205_fixup_repl_dep(void) - return UPGRADE_SUCCESS; - } - -+/* -+ * Remove nsIndexIDListScanLimit from parentid index configuration. -+ * -+ * This attribute was incorrectly added by a previous version and can -+ * cause issues with index configuration. Remove it if present. -+ */ -+static upgrade_status -+upgrade_remove_index_scanlimit(void) -+{ -+ struct slapi_pblock *pb = slapi_pblock_new(); -+ Slapi_Entry **backends = NULL; -+ const char *be_base_dn = "cn=ldbm database,cn=plugins,cn=config"; -+ const char *be_filter = "(objectclass=nsBackendInstance)"; -+ const char *attrs_to_check[] = {"parentid", NULL}; -+ upgrade_status uresult = UPGRADE_SUCCESS; -+ -+ /* Search for all backend instances */ -+ slapi_search_internal_set_pb( -+ pb, be_base_dn, -+ LDAP_SCOPE_ONELEVEL, -+ be_filter, NULL, 0, NULL, NULL, -+ plugin_get_default_component_id(), 0); -+ slapi_search_internal_pb(pb); -+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &backends); -+ -+ if (backends) { -+ for (size_t be_idx = 0; backends[be_idx] != NULL; be_idx++) { -+ const char *be_dn = slapi_entry_get_dn_const(backends[be_idx]); -+ const char *be_name = slapi_entry_attr_get_ref(backends[be_idx], "cn"); -+ if (!be_dn || !be_name) { -+ continue; -+ } -+ -+ for (size_t attr_idx = 0; attrs_to_check[attr_idx] != NULL; attr_idx++) { -+ const char *attr_name = attrs_to_check[attr_idx]; -+ struct slapi_pblock *idx_pb = slapi_pblock_new(); -+ Slapi_Entry **idx_entries = NULL; -+ char *idx_dn = slapi_create_dn_string("cn=%s,cn=index,%s", -+ attr_name, be_dn); -+ char *idx_filter = "(objectclass=nsIndex)"; -+ -+ if (!idx_dn) { -+ slapi_pblock_destroy(idx_pb); -+ continue; -+ } -+ -+ slapi_search_internal_set_pb( -+ idx_pb, idx_dn, -+ LDAP_SCOPE_BASE, -+ idx_filter, NULL, 0, NULL, NULL, -+ plugin_get_default_component_id(), 0); -+ slapi_search_internal_pb(idx_pb); -+ slapi_pblock_get(idx_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &idx_entries); -+ -+ if (idx_entries && idx_entries[0]) { -+ /* Check if nsIndexIDListScanLimit is present */ -+ if (slapi_entry_attr_get_ref(idx_entries[0], "nsIndexIDListScanLimit") != NULL) { -+ /* Remove nsIndexIDListScanLimit */ -+ Slapi_PBlock *mod_pb = slapi_pblock_new(); -+ Slapi_Mods smods; -+ int rc; -+ -+ slapi_mods_init(&smods, 1); -+ slapi_mods_add(&smods, LDAP_MOD_DELETE, "nsIndexIDListScanLimit", 0, NULL); -+ -+ slapi_modify_internal_set_pb( -+ mod_pb, idx_dn, -+ slapi_mods_get_ldapmods_byref(&smods), -+ NULL, NULL, -+ plugin_get_default_component_id(), 0); -+ slapi_modify_internal_pb(mod_pb); -+ slapi_pblock_get(mod_pb, SLAPI_PLUGIN_INTOP_RESULT, &rc); -+ -+ if (rc == LDAP_SUCCESS) { -+ slapi_log_err(SLAPI_LOG_NOTICE, "upgrade_remove_index_scanlimit", -+ "Removed 'nsIndexIDListScanLimit' from index '%s' in backend '%s'\n", -+ attr_name, be_name); -+ } else if (rc != LDAP_NO_SUCH_ATTRIBUTE) { -+ slapi_log_err(SLAPI_LOG_ERR, "upgrade_remove_index_scanlimit", -+ "Failed to remove 'nsIndexIDListScanLimit' from index '%s' in backend '%s': error %d\n", -+ attr_name, be_name, rc); -+ } -+ -+ slapi_mods_done(&smods); -+ slapi_pblock_destroy(mod_pb); -+ } -+ } -+ -+ slapi_ch_free_string(&idx_dn); -+ slapi_free_search_results_internal(idx_pb); -+ slapi_pblock_destroy(idx_pb); -+ } -+ } -+ } -+ -+ slapi_free_search_results_internal(pb); -+ slapi_pblock_destroy(pb); -+ -+ return uresult; -+} -+ - /* - * Check if parentid/ancestorid indexes are missing the integerOrderingMatch - * matching rule. -@@ -407,6 +508,10 @@ upgrade_server(void) - return UPGRADE_FAILURE; - } - -+ if (upgrade_remove_index_scanlimit() != UPGRADE_SUCCESS) { -+ return UPGRADE_FAILURE; -+ } -+ - if (upgrade_check_id_index_matching_rule() != UPGRADE_SUCCESS) { - return UPGRADE_FAILURE; - } --- -2.52.0 - diff --git a/0014-Issue-7223-Add-upgrade-function-to-remove-ancestorid.patch b/0014-Issue-7223-Add-upgrade-function-to-remove-ancestorid.patch deleted file mode 100644 index 494a3e1..0000000 --- a/0014-Issue-7223-Add-upgrade-function-to-remove-ancestorid.patch +++ /dev/null @@ -1,313 +0,0 @@ -From 9a9446b9bafe25eacf97039e66d6ef19d366315c Mon Sep 17 00:00:00 2001 -From: Viktor Ashirov -Date: Thu, 5 Feb 2026 12:17:06 +0100 -Subject: [PATCH] Issue 7223 - Add upgrade function to remove ancestorid index - config entry - -Description: -Add `upgrade_remove_ancestorid_index_config()` function that removes: -* ancestorid from `cn=default indexes` -* ancestorid index config entries from each backend's `cn=index` - -Also remove ancestorid index configuration from template-dse.ldif. - -Relates: https://github.com/389ds/389-ds-base/issues/7223 - -Reviewed by: @progier389, @tbordaz, @droideck (Thanks!) ---- - .../healthcheck/health_system_indexes_test.py | 85 +++++++++++ - ldap/ldif/template-dse.ldif.in | 8 -- - ldap/servers/slapd/upgrade.c | 133 +++++++++++++++++- - 3 files changed, 214 insertions(+), 12 deletions(-) - -diff --git a/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py b/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py -index b0d7a99ec..4b0c58835 100644 ---- a/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py -+++ b/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py -@@ -501,6 +501,91 @@ def test_upgrade_removes_parentid_scanlimit(topology_st): - - log.info("Upgrade successfully removed nsIndexIDListScanLimit from parentid index") - -+ # Verify idempotency - restart again and ensure no errors -+ log.info("Restart server again to verify idempotency (no errors on second run)") -+ standalone.restart() -+ # Verify the attribute is still absent -+ scanlimit_after_second = parentid_index.get_attr_vals_utf8("nsIndexIDListScanLimit") -+ assert not scanlimit_after_second, \ -+ f"nsIndexIDListScanLimit should still be absent after second restart but found: {scanlimit_after_second}" -+ log.info("Idempotency verified - no issues on second restart") -+ -+ -+def test_upgrade_removes_ancestorid_index_config(topology_st): -+ """Check if upgrade function removes ancestorid index config entry -+ -+ :id: 3f3d6e9b-75ac-4f0d-b2ce-7204e6eacd0a -+ :setup: Standalone instance -+ :steps: -+ 1. Create DS instance -+ 2. Stop the server -+ 3. Use DSEldif to add an ancestorid index config entry -+ 4. Start the server (triggers upgrade) -+ 5. Verify ancestorid index config entry is removed -+ :expectedresults: -+ 1. Success -+ 2. Success -+ 3. Success -+ 4. Success -+ 5. ancestorid index config entry is no longer present -+ """ -+ from lib389.dseldif import DSEldif -+ -+ standalone = topology_st.standalone -+ ANCESTORID_DN = "cn=ancestorid,cn=index,cn=userroot,cn=ldbm database,cn=plugins,cn=config" -+ -+ log.info("Stop the server") -+ standalone.stop() -+ -+ log.info("Add ancestorid index config entry using DSEldif") -+ dse_ldif = DSEldif(standalone) -+ -+ # Create a fake ancestorid index entry -+ ancestorid_entry = [ -+ "dn: {}\n".format(ANCESTORID_DN), -+ "objectClass: top\n", -+ "objectClass: nsIndex\n", -+ "cn: ancestorid\n", -+ "nsSystemIndex: true\n", -+ "nsIndexType: eq\n", -+ "nsMatchingRule: integerOrderingMatch\n", -+ "\n" -+ ] -+ dse_ldif.add_entry(ancestorid_entry) -+ -+ # Verify it was added by re-reading dse.ldif -+ dse_ldif2 = DSEldif(standalone) -+ cn_value = dse_ldif2.get(ANCESTORID_DN, "cn") -+ assert cn_value is not None, "Failed to add ancestorid index config entry" -+ log.info(f"Added ancestorid index entry with cn: {cn_value}") -+ -+ log.info("Start the server (triggers upgrade)") -+ standalone.start() -+ -+ log.info("Verify ancestorid index config entry was removed by upgrade") -+ # Check via LDAP - the upgrade should have removed the entry -+ try: -+ ancestorid_index = Index(standalone, ANCESTORID_DN) -+ # If we can get the entry, it wasn't removed - this is a failure -+ cn_after = ancestorid_index.get_attr_vals_utf8("cn") -+ assert False, f"ancestorid index config entry should have been removed but still exists: {cn_after}" -+ except Exception as e: -+ # Entry should not exist - this is expected -+ log.info(f"ancestorid index config entry correctly removed (got exception: {e})") -+ -+ log.info("Upgrade successfully removed ancestorid index config entry") -+ -+ # Verify idempotency - restart again and ensure no errors -+ log.info("Restart server again to verify idempotency (no errors on second run)") -+ standalone.restart() -+ # Verify the entry is still absent -+ try: -+ ancestorid_index = Index(standalone, ANCESTORID_DN) -+ cn_after_second = ancestorid_index.get_attr_vals_utf8("cn") -+ assert False, f"ancestorid index config entry should still be absent after second restart but found: {cn_after_second}" -+ except Exception as e: -+ log.info(f"Idempotency verified - ancestorid still absent after second restart (got exception: {e})") -+ - - if __name__ == "__main__": - # Run isolated -diff --git a/ldap/ldif/template-dse.ldif.in b/ldap/ldif/template-dse.ldif.in -index 6f97d492b..70e7a85ac 100644 ---- a/ldap/ldif/template-dse.ldif.in -+++ b/ldap/ldif/template-dse.ldif.in -@@ -990,14 +990,6 @@ cn: aci - nssystemindex: true - nsindextype: pres - --dn: cn=ancestorid,cn=default indexes, cn=config,cn=ldbm database,cn=plugins,cn=config --objectclass: top --objectclass: nsIndex --cn: ancestorid --nssystemindex: true --nsindextype: eq --nsmatchingrule: integerOrderingMatch -- - dn: cn=cn,cn=default indexes, cn=config,cn=ldbm database,cn=plugins,cn=config - objectclass: top - objectclass: nsIndex -diff --git a/ldap/servers/slapd/upgrade.c b/ldap/servers/slapd/upgrade.c -index adfec63de..d9156cae9 100644 ---- a/ldap/servers/slapd/upgrade.c -+++ b/ldap/servers/slapd/upgrade.c -@@ -380,6 +380,126 @@ upgrade_remove_index_scanlimit(void) - return uresult; - } - -+/* -+ * Remove ancestorid index configuration entry if present. -+ * -+ * The ancestorid index is special - it has no corresponding attribute type -+ * and should not have a DSE config entry. If an entry exists, remove it. -+ * -+ * This function removes: -+ * 1. The ancestorid entry from cn=default indexes (to prevent re-creation on startup) -+ * 2. The ancestorid entry from each backend's cn=index (if it exists) -+ */ -+static upgrade_status -+upgrade_remove_ancestorid_index_config(void) -+{ -+ struct slapi_pblock *pb = slapi_pblock_new(); -+ Slapi_Entry **backends = NULL; -+ const char *be_base_dn = "cn=ldbm database,cn=plugins,cn=config"; -+ const char *be_filter = "(objectclass=nsBackendInstance)"; -+ upgrade_status uresult = UPGRADE_SUCCESS; -+ int rc; -+ -+ /* -+ * First, remove ancestorid from cn=default indexes to prevent -+ * ldbm_instance_create_default_user_indexes() from re-creating it. -+ */ -+ { -+ Slapi_PBlock *def_pb = slapi_pblock_new(); -+ char *def_idx_dn = slapi_create_dn_string( -+ "cn=ancestorid,cn=default indexes,cn=config,%s", be_base_dn); -+ -+ if (def_idx_dn) { -+ slapi_delete_internal_set_pb( -+ def_pb, def_idx_dn, NULL, NULL, -+ plugin_get_default_component_id(), 0); -+ slapi_delete_internal_pb(def_pb); -+ slapi_pblock_get(def_pb, SLAPI_PLUGIN_INTOP_RESULT, &rc); -+ -+ if (rc == LDAP_SUCCESS) { -+ slapi_log_err(SLAPI_LOG_NOTICE, "upgrade_remove_ancestorid_index_config", -+ "Removed 'ancestorid' from default indexes.\n"); -+ } else if (rc != LDAP_NO_SUCH_OBJECT) { -+ slapi_log_err(SLAPI_LOG_ERR, "upgrade_remove_ancestorid_index_config", -+ "Failed to remove 'ancestorid' from default indexes: error %d\n", rc); -+ } -+ -+ slapi_ch_free_string(&def_idx_dn); -+ } -+ slapi_pblock_destroy(def_pb); -+ } -+ -+ /* Search for all backend instances */ -+ slapi_search_internal_set_pb( -+ pb, be_base_dn, -+ LDAP_SCOPE_ONELEVEL, -+ be_filter, NULL, 0, NULL, NULL, -+ plugin_get_default_component_id(), 0); -+ slapi_search_internal_pb(pb); -+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &backends); -+ -+ if (backends) { -+ for (size_t be_idx = 0; backends[be_idx] != NULL; be_idx++) { -+ const char *be_dn = slapi_entry_get_dn_const(backends[be_idx]); -+ const char *be_name = slapi_entry_attr_get_ref(backends[be_idx], "cn"); -+ if (!be_dn || !be_name) { -+ continue; -+ } -+ -+ struct slapi_pblock *idx_pb = slapi_pblock_new(); -+ Slapi_Entry **idx_entries = NULL; -+ char *idx_dn = slapi_create_dn_string("cn=ancestorid,cn=index,%s", -+ be_dn); -+ char *idx_filter = "(objectclass=nsIndex)"; -+ -+ if (!idx_dn) { -+ slapi_pblock_destroy(idx_pb); -+ continue; -+ } -+ -+ slapi_search_internal_set_pb( -+ idx_pb, idx_dn, -+ LDAP_SCOPE_BASE, -+ idx_filter, NULL, 0, NULL, NULL, -+ plugin_get_default_component_id(), 0); -+ slapi_search_internal_pb(idx_pb); -+ slapi_pblock_get(idx_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &idx_entries); -+ -+ if (idx_entries && idx_entries[0]) { -+ /* ancestorid index entry exists - delete it */ -+ Slapi_PBlock *del_pb = slapi_pblock_new(); -+ -+ slapi_delete_internal_set_pb( -+ del_pb, idx_dn, NULL, NULL, -+ plugin_get_default_component_id(), 0); -+ slapi_delete_internal_pb(del_pb); -+ slapi_pblock_get(del_pb, SLAPI_PLUGIN_INTOP_RESULT, &rc); -+ -+ if (rc == LDAP_SUCCESS) { -+ slapi_log_err(SLAPI_LOG_NOTICE, "upgrade_remove_ancestorid_index_config", -+ "Removed 'ancestorid' index config entry in backend '%s'.\n", -+ be_name); -+ } else if (rc != LDAP_NO_SUCH_OBJECT) { -+ slapi_log_err(SLAPI_LOG_ERR, "upgrade_remove_ancestorid_index_config", -+ "Failed to remove 'ancestorid' index config entry in backend '%s': error %d\n", -+ be_name, rc); -+ } -+ -+ slapi_pblock_destroy(del_pb); -+ } -+ -+ slapi_ch_free_string(&idx_dn); -+ slapi_free_search_results_internal(idx_pb); -+ slapi_pblock_destroy(idx_pb); -+ } -+ } -+ -+ slapi_free_search_results_internal(pb); -+ slapi_pblock_destroy(pb); -+ -+ return uresult; -+} -+ - /* - * Check if parentid/ancestorid indexes are missing the integerOrderingMatch - * matching rule. -@@ -394,7 +514,7 @@ upgrade_check_id_index_matching_rule(void) - Slapi_Entry **backends = NULL; - const char *be_base_dn = "cn=ldbm database,cn=plugins,cn=config"; - const char *be_filter = "(objectclass=nsBackendInstance)"; -- const char *attrs_to_check[] = {"parentid", "ancestorid", NULL}; -+ const char *attrs_to_check[] = {"parentid", NULL}; - upgrade_status uresult = UPGRADE_SUCCESS; - - /* Search for all backend instances */ -@@ -408,8 +528,9 @@ upgrade_check_id_index_matching_rule(void) - - if (backends) { - for (size_t be_idx = 0; backends[be_idx] != NULL; be_idx++) { -+ const char *be_dn = slapi_entry_get_dn_const(backends[be_idx]); - const char *be_name = slapi_entry_attr_get_ref(backends[be_idx], "cn"); -- if (!be_name) { -+ if (!be_dn || !be_name) { - continue; - } - -@@ -418,8 +539,8 @@ upgrade_check_id_index_matching_rule(void) - const char *attr_name = attrs_to_check[attr_idx]; - struct slapi_pblock *idx_pb = slapi_pblock_new(); - Slapi_Entry **idx_entries = NULL; -- char *idx_dn = slapi_create_dn_string("cn=%s,cn=index,cn=%s,%s", -- attr_name, be_name, be_base_dn); -+ char *idx_dn = slapi_create_dn_string("cn=%s,cn=index,%s", -+ attr_name, be_dn); - char *idx_filter = "(objectclass=nsIndex)"; - PRBool has_matching_rule = PR_FALSE; - -@@ -512,6 +633,10 @@ upgrade_server(void) - return UPGRADE_FAILURE; - } - -+ if (upgrade_remove_ancestorid_index_config() != UPGRADE_SUCCESS) { -+ return UPGRADE_FAILURE; -+ } -+ - if (upgrade_check_id_index_matching_rule() != UPGRADE_SUCCESS) { - return UPGRADE_FAILURE; - } --- -2.52.0 - diff --git a/0015-Issue-7223-Detect-and-log-index-ordering-mismatch-du.patch b/0015-Issue-7223-Detect-and-log-index-ordering-mismatch-du.patch deleted file mode 100644 index 0960428..0000000 --- a/0015-Issue-7223-Detect-and-log-index-ordering-mismatch-du.patch +++ /dev/null @@ -1,300 +0,0 @@ -From b5bee921b7f4cfbf7a2edbe55d4291f487f4a140 Mon Sep 17 00:00:00 2001 -From: Viktor Ashirov -Date: Thu, 5 Feb 2026 12:17:06 +0100 -Subject: [PATCH] Issue 7223 - Detect and log index ordering mismatch during - backend startup - -Description: -Add `ldbm_instance_check_index_config()` function that checks on-disk -index data and logs a message in case of a mismatch with DSE config entry. - -Relates: https://github.com/389ds/389-ds-base/issues/7223 - -Reviewed by: @progier389, @tbordaz, @droideck (Thanks!) ---- - ldap/servers/slapd/back-ldbm/instance.c | 262 ++++++++++++++++++++++++ - 1 file changed, 262 insertions(+) - -diff --git a/ldap/servers/slapd/back-ldbm/instance.c b/ldap/servers/slapd/back-ldbm/instance.c -index f9a546661..3fcdb5554 100644 ---- a/ldap/servers/slapd/back-ldbm/instance.c -+++ b/ldap/servers/slapd/back-ldbm/instance.c -@@ -248,6 +248,266 @@ ldbm_instance_create_default_indexes(backend *be) - } - - -+/* -+ * Check if an index has integerOrderingMatch configured in DSE. -+ * -+ * This function performs an internal LDAP search to check if the index -+ * configuration entry has nsMatchingRule: integerOrderingMatch. -+ * -+ * Parameters: -+ * inst_name - backend instance name (e.g., "userRoot") -+ * index_name - name of the index to check (e.g., "parentid", "ancestorid") -+ * -+ * Returns: -+ * PR_TRUE if integerOrderingMatch is configured -+ * PR_FALSE if not configured or index entry doesn't exist -+ */ -+static PRBool -+ldbm_instance_index_has_int_order_in_dse(const char *inst_name, const char *index_name) -+{ -+ Slapi_PBlock *pb = NULL; -+ Slapi_Entry **entries = NULL; -+ char *idx_dn = NULL; -+ PRBool has_int_order = PR_FALSE; -+ -+ idx_dn = slapi_create_dn_string("cn=%s,cn=index,cn=%s,cn=ldbm database,cn=plugins,cn=config", -+ index_name, inst_name); -+ if (idx_dn == NULL) { -+ return PR_FALSE; -+ } -+ -+ pb = slapi_pblock_new(); -+ slapi_search_internal_set_pb(pb, idx_dn, LDAP_SCOPE_BASE, -+ "(objectclass=nsIndex)", NULL, 0, NULL, NULL, -+ plugin_get_default_component_id(), 0); -+ slapi_search_internal_pb(pb); -+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries); -+ -+ if (entries && entries[0]) { -+ Slapi_Attr *mr_attr = NULL; -+ if (slapi_entry_attr_find(entries[0], "nsMatchingRule", &mr_attr) == 0) { -+ Slapi_Value *sval = NULL; -+ int idx; -+ for (idx = slapi_attr_first_value(mr_attr, &sval); -+ idx != -1; -+ idx = slapi_attr_next_value(mr_attr, idx, &sval)) { -+ const struct berval *bval = slapi_value_get_berval(sval); -+ if (bval && bval->bv_val && -+ strcasecmp(bval->bv_val, "integerOrderingMatch") == 0) { -+ has_int_order = PR_TRUE; -+ break; -+ } -+ } -+ } -+ } -+ -+ slapi_ch_free_string(&idx_dn); -+ slapi_free_search_results_internal(pb); -+ slapi_pblock_destroy(pb); -+ -+ return has_int_order; -+} -+ -+/* -+ * Check a system index for ordering mismatch between config and on-disk data. -+ * -+ * This function compares what's configured in DSE (nsMatchingRule) with -+ * what's actually on disk. A mismatch can occur in two scenarios: -+ * 1. Ordering rule is configured but disk has lexicographic order -+ * (rule was added after index was created) -+ * 2. No ordering rule configured but disk has integer order -+ * (rule was removed after index was created with it) -+ * -+ * This function reads the first keys from the specified index and checks -+ * if they are stored in lexicographic order (string: "1" < "10" < "2") or -+ * integer order (numeric: "1" < "2" < "10"). -+ * -+ * Parameters: -+ * be - backend -+ * index_name - name of the index to check (e.g., "parentid", "ancestorid") -+ * -+ */ -+static void -+ldbm_instance_check_index_config(backend *be, const char *index_name) -+{ -+ ldbm_instance *inst = (ldbm_instance *)be->be_instance_info; -+ struct attrinfo *ai = NULL; -+ dbi_db_t *db = NULL; -+ dbi_cursor_t dbc = {0}; -+ dbi_val_t key = {0}; -+ dbi_val_t data = {0}; -+ int ret = 0; -+ PRBool config_has_int_order = PR_FALSE; -+ PRBool disk_has_int_order = PR_TRUE; /* Assume integer order until proven otherwise */ -+ ID prev_id = 0; -+ int key_count = 0; -+ PRBool first_key = PR_TRUE; -+ PRBool found_ordering_evidence = PR_FALSE; -+ -+ slapi_log_err(SLAPI_LOG_DEBUG, "ldbm_instance_check_index_config", -+ "Backend '%s': checking %s index ordering...\n", -+ inst->inst_name, index_name); -+ -+ /* Check if integerOrderingMatch is configured in DSE */ -+ config_has_int_order = ldbm_instance_index_has_int_order_in_dse(inst->inst_name, index_name); -+ -+ /* Get attrinfo for the index */ -+ ainfo_get(be, (char *)index_name, &ai); -+ if (ai == NULL || strcmp(ai->ai_type, index_name) != 0) { -+ /* No index config found */ -+ slapi_log_err(SLAPI_LOG_DEBUG, "ldbm_instance_check_index_config", -+ "Backend '%s': no %s attrinfo found, skipping check\n", -+ inst->inst_name, index_name); -+ return; -+ } -+ -+ /* Open the index file */ -+ ret = dblayer_get_index_file(be, ai, &db, 0); -+ if (ret != 0 || db == NULL) { -+ /* Index file doesn't exist or can't be opened - this is fine for new instances */ -+ slapi_log_err(SLAPI_LOG_DEBUG, "ldbm_instance_check_index_config", -+ "Backend '%s': could not open %s index file (ret=%d), skipping order check\n", -+ inst->inst_name, index_name, ret); -+ return; -+ } -+ -+ /* Create a cursor to read keys */ -+ ret = dblayer_new_cursor(be, db, NULL, &dbc); -+ if (ret != 0) { -+ slapi_log_err(SLAPI_LOG_ERR, "ldbm_instance_check_index_config", -+ "Backend '%s': could not create cursor on %s index (ret=%d)\n", -+ inst->inst_name, index_name, ret); -+ dblayer_release_index_file(be, ai, db); -+ return; -+ } -+ -+ dblayer_value_init(be, &key); -+ dblayer_value_init(be, &data); -+ -+ /* -+ * Read up to 100 unique keys and check their ordering. -+ * With lexicographic ordering: "1" < "10" < "100" < "2" < "20" < "3" -+ * With integer ordering: "1" < "2" < "3" < "10" < "20" < "100" -+ * -+ * If we find a case where prev_id > current_id (numerically), but the -+ * keys are still in order (lexicographically), then the index uses -+ * lexicographic ordering. -+ */ -+ while (key_count < 100) { -+ ID current_id; -+ -+ ret = dblayer_cursor_op(&dbc, first_key ? DBI_OP_MOVE_TO_FIRST : DBI_OP_NEXT_KEY, &key, &data); -+ first_key = PR_FALSE; /* Always advance cursor on next iteration */ -+ if (ret != 0) { -+ break; /* No more keys or error */ -+ } -+ -+ /* Skip non-equality keys */ -+ if (key.size < 2 || *(char *)key.data != EQ_PREFIX) { -+ continue; -+ } -+ -+ /* Parse the ID from the key (format: "=") */ -+ current_id = (ID)strtoul((char *)key.data + 1, NULL, 10); -+ if (current_id == 0) { -+ continue; /* Invalid ID, skip */ -+ } -+ -+ key_count++; -+ -+ if (prev_id != 0) { -+ /* -+ * Check ordering: if prev_id > current_id numerically, -+ * but we got this key after prev in DB order, then -+ * the index is using lexicographic ordering. -+ * -+ * Example: if we see "10" followed by "2", that's lexicographic -+ * because "10" < "2" as strings, but 10 > 2 as integers. -+ */ -+ if (prev_id > current_id) { -+ /* Found evidence of lexicographic ordering */ -+ disk_has_int_order = PR_FALSE; -+ found_ordering_evidence = PR_TRUE; -+ break; -+ } else if (prev_id < current_id) { -+ /* -+ * This is consistent with integer ordering, but we need -+ * to find a case that proves lexicographic ordering. -+ * For example, seeing "1" followed by "2" is ambiguous, -+ * but seeing "1" followed by "10" (not "2") proves lexicographic. -+ * -+ * A definitive test: if we see an ID followed by a smaller -+ * ID, that's lexicographic. If all IDs are strictly increasing, -+ * it could be either (or the index only has sequential IDs). -+ */ -+ found_ordering_evidence = PR_TRUE; -+ } -+ } -+ prev_id = current_id; -+ } -+ -+ /* Close the cursor and free values */ -+ dblayer_cursor_op(&dbc, DBI_OP_CLOSE, NULL, NULL); -+ dblayer_value_free(be, &key); -+ dblayer_value_free(be, &data); -+ -+ /* Release the index file */ -+ dblayer_release_index_file(be, ai, db); -+ -+ /* -+ * Report findings and check for config/disk mismatch. -+ * Log an error if there's a discrepancy between what's configured -+ * in DSE and what's actually on disk. -+ */ -+ if (!found_ordering_evidence) { -+ slapi_log_err(SLAPI_LOG_DEBUG, "ldbm_instance_check_index_config", -+ "Backend '%s': %s index ordering check - " -+ "could not determine on-disk ordering (index may be empty or have sequential IDs only). " -+ "Config has integerOrderingMatch: %s\n", -+ inst->inst_name, index_name, config_has_int_order ? "yes" : "no"); -+ } else if (config_has_int_order && !disk_has_int_order) { -+ /* Config expects integer ordering, but disk has lexicographic - MISMATCH */ -+ slapi_log_err(SLAPI_LOG_ERR, "ldbm_instance_check_index_config", -+ "Backend '%s': MISMATCH - %s index has integerOrderingMatch configured, " -+ "but on-disk data uses lexicographic ordering. " -+ "This will cause searches to return incorrect or incomplete results. " -+ "Please reindex the %s attribute: " -+ "dsconf backend index reindex --attr %s %s\n", -+ inst->inst_name, index_name, index_name, index_name, inst->inst_name); -+ } else if (!config_has_int_order && disk_has_int_order) { -+ /* Config expects lexicographic ordering, but disk has integer - MISMATCH */ -+ slapi_log_err(SLAPI_LOG_ERR, "ldbm_instance_check_index_config", -+ "Backend '%s': MISMATCH - %s index does not have integerOrderingMatch configured, " -+ "but on-disk data uses integer ordering. " -+ "This will cause searches to return incorrect or incomplete results. " -+ "Please reindex the %s attribute: " -+ "dsconf backend index reindex --attr %s %s\n", -+ inst->inst_name, index_name, index_name, index_name, inst->inst_name); -+ } else { -+ /* Config and disk ordering match - no action needed */ -+ slapi_log_err(SLAPI_LOG_DEBUG, "ldbm_instance_check_index_config", -+ "Backend '%s': %s index ordering check passed - " -+ "config has integerOrderingMatch: %s, on-disk data matches.\n", -+ inst->inst_name, index_name, config_has_int_order ? "yes" : "no"); -+ } -+} -+ -+/* -+ * Check system indexes for ordering mismatches. -+ * If a mismatch is detected, log an error advising the administrator -+ * to reindex the affected attribute. -+ * -+ * Note: We only check parentid here. The ancestorid index is a special -+ * system index that has no DSE config entry - its ordering is hardcoded -+ * in ldbm_instance_init_config_entry() and cannot be changed by users. -+ */ -+static void -+ldbm_instance_check_indexes(backend *be) -+{ -+ /* Check parentid index */ -+ ldbm_instance_check_index_config(be, LDBM_PARENTID_STR); -+} -+ - /* Starts a backend instance */ - int - ldbm_instance_start(backend *be) -@@ -319,6 +579,8 @@ ldbm_instance_startall(struct ldbminfo *li) - ldbm_instance_register_modify_callback(inst); - vlv_init(inst); - slapi_mtn_be_started(inst->inst_be); -+ /* Check index configuration for potential issues */ -+ ldbm_instance_check_indexes(inst->inst_be); - } - if (slapi_exist_referral(inst->inst_be)) { - slapi_be_set_flag(inst->inst_be, SLAPI_BE_FLAG_CONTAINS_REFERRAL); --- -2.52.0 - diff --git a/0016-Issue-7223-Add-dsctl-index-check-command-for-offline.patch b/0016-Issue-7223-Add-dsctl-index-check-command-for-offline.patch deleted file mode 100644 index c3af0f1..0000000 --- a/0016-Issue-7223-Add-dsctl-index-check-command-for-offline.patch +++ /dev/null @@ -1,1233 +0,0 @@ -From 04eca1fe36480561bc2f59440d971e000133d213 Mon Sep 17 00:00:00 2001 -From: Viktor Ashirov -Date: Thu, 5 Feb 2026 12:17:06 +0100 -Subject: [PATCH] Issue 7223 - Add dsctl index-check command for offline index - repair - -Description: -Add `dsctl index-check [backend] [--fix]` command for offline -detection and repair of index ordering mismatches. This is needed after -upgrade from versions that didn't use integerOrderingMatch for -parentid/ancestorid system indexes. - -It's automatically executed as part of RPM %post scriptlet during -upgrade. - -Relates: https://github.com/389ds/389-ds-base/issues/7223 - -Reviewed by: @progier389, @tbordaz, @droideck (Thanks!) ---- - .../healthcheck/health_system_indexes_test.py | 593 ++++++++++++++++++ - rpm/389-ds-base.spec.in | 51 +- - src/lib389/lib389/cli_ctl/dbtasks.py | 402 ++++++++++++ - src/lib389/lib389/dseldif.py | 51 +- - 4 files changed, 1068 insertions(+), 29 deletions(-) - -diff --git a/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py b/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py -index 4b0c58835..571465562 100644 ---- a/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py -+++ b/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py -@@ -587,6 +587,599 @@ def test_upgrade_removes_ancestorid_index_config(topology_st): - log.info(f"Idempotency verified - ancestorid still absent after second restart (got exception: {e})") - - -+def test_index_check_basic(topology_st): -+ """Check if dsctl index-check works correctly -+ -+ :id: 8a4e5c2d-1f3b-4a7c-9e8d-2b6f0c4a5d3e -+ :setup: Standalone instance -+ :steps: -+ 1. Create DS instance -+ 2. Run dsctl index-check while server is running (should fail) -+ 3. Stop the server -+ 4. Run dsctl index-check (should pass) -+ 5. Start the server -+ :expectedresults: -+ 1. Success -+ 2. index-check returns False and logs error -+ 3. Success -+ 4. index-check returns True (no mismatches) -+ 5. Success -+ """ -+ from lib389.cli_ctl.dbtasks import dbtasks_index_check -+ -+ standalone = topology_st.standalone -+ -+ log.info("Run index-check while server is running") -+ args = FakeArgs() -+ args.backend = None -+ args.fix = False -+ -+ # Server should be running, index-check should fail -+ assert standalone.status() -+ result = dbtasks_index_check(standalone, topology_st.logcap.log, args) -+ assert result is False -+ assert topology_st.logcap.contains("index-check requires the instance to be stopped") -+ topology_st.logcap.flush() -+ -+ log.info("Stop the server") -+ standalone.stop() -+ -+ log.info("Run index-check with server stopped") -+ result = dbtasks_index_check(standalone, topology_st.logcap.log, args) -+ assert result is True -+ assert topology_st.logcap.contains("All checks passed") -+ topology_st.logcap.flush() -+ -+ log.info("Start the server") -+ standalone.start() -+ -+ -+def test_index_check_specific_backend(topology_st): -+ """Check if dsctl index-check works with a specific backend -+ -+ :id: 407d8fcc-62e0-43dd-90fa-70e7090a5cfd -+ :setup: Standalone instance -+ :steps: -+ 1. Create DS instance -+ 2. Stop the server -+ 3. Run dsctl index-check with specific backend (userRoot) -+ 4. Run dsctl index-check with non-existent backend -+ 5. Start the server -+ :expectedresults: -+ 1. Success -+ 2. Success -+ 3. index-check returns True for userRoot -+ 4. index-check returns False for non-existent backend -+ 5. Success -+ """ -+ from lib389.cli_ctl.dbtasks import dbtasks_index_check -+ -+ standalone = topology_st.standalone -+ -+ log.info("Stop the server") -+ standalone.stop() -+ -+ log.info("Run index-check for userRoot backend") -+ args = FakeArgs() -+ args.backend = "userRoot" -+ args.fix = False -+ -+ result = dbtasks_index_check(standalone, topology_st.logcap.log, args) -+ assert result is True -+ # Check for backend name in any case -+ assert topology_st.logcap.contains("Checking backend:") -+ topology_st.logcap.flush() -+ -+ log.info("Run index-check for non-existent backend") -+ args.backend = "nonExistentBackend" -+ result = dbtasks_index_check(standalone, topology_st.logcap.log, args) -+ assert result is False -+ assert topology_st.logcap.contains("not found") -+ topology_st.logcap.flush() -+ -+ log.info("Start the server") -+ standalone.start() -+ -+ -+def test_index_check_mismatch_detection(topology_st): -+ """Check if dsctl index-check detects ordering mismatch -+ -+ :id: 50d14520-b0bf-4243-9fe6-b097928d4351 -+ :setup: Standalone instance -+ :steps: -+ 1. Create DS instance -+ 2. Stop the server -+ 3. Run dsctl index-check (without --fix) -+ 4. Verify output format -+ 5. Start the server -+ :expectedresults: -+ 1. Success -+ 2. Success -+ 3. index-check returns True (no mismatch on fresh instance) -+ 4. Log contains expected format -+ 5. Success -+ """ -+ from lib389.cli_ctl.dbtasks import dbtasks_index_check -+ -+ standalone = topology_st.standalone -+ -+ log.info("Stop the server") -+ standalone.stop() -+ -+ log.info("Run index-check to verify detection logic") -+ args = FakeArgs() -+ args.backend = "userRoot" -+ args.fix = False -+ -+ # On a fresh instance, there should be no mismatch -+ result = dbtasks_index_check(standalone, topology_st.logcap.log, args) -+ # Fresh instance should have matching config and disk ordering -+ assert result is True -+ # Check that the backend was checked (may skip indexes if ordering can't be determined) -+ assert topology_st.logcap.contains("Checking backend:") -+ topology_st.logcap.flush() -+ -+ log.info("Start the server") -+ standalone.start() -+ -+ -+def test_index_check_with_fix(topology_st): -+ """Check if dsctl index-check --fix triggers reindexing -+ -+ :id: 38ae36e4-c861-4771-ae7d-354370376a2f -+ :setup: Standalone instance -+ :steps: -+ 1. Create DS instance -+ 2. Stop the server -+ 3. Run dsctl index-check --fix (should pass since no mismatch) -+ 4. Verify output indicates check passed -+ 5. Start the server -+ :expectedresults: -+ 1. Success -+ 2. Success -+ 3. index-check returns True -+ 4. Log contains "All checks passed" -+ 5. Success -+ """ -+ from lib389.cli_ctl.dbtasks import dbtasks_index_check -+ -+ standalone = topology_st.standalone -+ -+ log.info("Stop the server") -+ standalone.stop() -+ -+ log.info("Run index-check with --fix option") -+ args = FakeArgs() -+ args.backend = None -+ args.fix = True -+ -+ result = dbtasks_index_check(standalone, topology_st.logcap.log, args) -+ # On a fresh instance, there should be no mismatch, so no reindexing needed -+ assert result is True -+ assert topology_st.logcap.contains("All checks passed") -+ topology_st.logcap.flush() -+ -+ log.info("Start the server") -+ standalone.start() -+ -+ -+def test_index_check_fixes_scanlimit(topology_st): -+ """Check if dsctl index-check --fix removes nsIndexIDListScanLimit -+ -+ :id: 4a9b2c7d-8e1f-4b3a-9c5d-6e7f8a0b1c2d -+ :setup: Standalone instance -+ :steps: -+ 1. Create DS instance -+ 2. Stop the server -+ 3. Add nsIndexIDListScanLimit to parentid index using DSEldif -+ 4. Run dsctl index-check (should detect issue) -+ 5. Run dsctl index-check --fix -+ 6. Verify nsIndexIDListScanLimit was removed -+ 7. Start the server -+ :expectedresults: -+ 1. Success -+ 2. Success -+ 3. Success -+ 4. index-check returns False and detects scanlimit -+ 5. index-check returns True after fix -+ 6. nsIndexIDListScanLimit no longer present -+ 7. Success -+ """ -+ from lib389.cli_ctl.dbtasks import dbtasks_index_check -+ from lib389.dseldif import DSEldif -+ -+ standalone = topology_st.standalone -+ -+ log.info("Stop the server") -+ standalone.stop() -+ -+ log.info("Add nsIndexIDListScanLimit to parentid index using DSEldif") -+ dse_ldif = DSEldif(standalone) -+ parentid_dn = "cn=parentid,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config" -+ dse_ldif.add(parentid_dn, "nsIndexIDListScanLimit", "4000") -+ -+ # Verify it was added -+ scanlimit = dse_ldif.get(parentid_dn, "nsIndexIDListScanLimit", single=True) -+ assert scanlimit == "4000", f"Failed to add nsIndexIDListScanLimit, got: {scanlimit}" -+ log.info("Added nsIndexIDListScanLimit to parentid index") -+ -+ log.info("Run index-check without --fix (should detect issue)") -+ args = FakeArgs() -+ args.backend = "userRoot" -+ args.fix = False -+ -+ result = dbtasks_index_check(standalone, topology_st.logcap.log, args) -+ assert result is False, "index-check should detect scanlimit issue" -+ assert topology_st.logcap.contains("nsIndexIDListScanLimit") -+ topology_st.logcap.flush() -+ -+ log.info("Run index-check with --fix") -+ args.fix = True -+ result = dbtasks_index_check(standalone, topology_st.logcap.log, args) -+ assert result is True, "index-check --fix should succeed" -+ assert topology_st.logcap.contains("Removed nsIndexIDListScanLimit") -+ topology_st.logcap.flush() -+ -+ log.info("Verify nsIndexIDListScanLimit was removed") -+ dse_ldif = DSEldif(standalone) # Reload to get fresh data -+ scanlimit = dse_ldif.get(parentid_dn, "nsIndexIDListScanLimit", single=True) -+ assert scanlimit is None, f"nsIndexIDListScanLimit should be removed, but got: {scanlimit}" -+ log.info("nsIndexIDListScanLimit successfully removed") -+ -+ log.info("Start the server") -+ standalone.start() -+ -+ -+def test_index_check_fixes_ancestorid_config(topology_st): -+ """Check if dsctl index-check --fix removes ancestorid config entries -+ -+ :id: 5b0c3d8e-9f2a-4c4b-0d6e-7f8a9b1c2d3e -+ :setup: Standalone instance -+ :steps: -+ 1. Create DS instance -+ 2. Stop the server -+ 3. Add ancestorid index config entry using DSEldif -+ 4. Run dsctl index-check (should detect issue) -+ 5. Run dsctl index-check --fix -+ 6. Verify ancestorid config entry was removed -+ 7. Start the server -+ :expectedresults: -+ 1. Success -+ 2. Success -+ 3. Success -+ 4. index-check returns False and detects ancestorid config -+ 5. index-check returns True after fix -+ 6. ancestorid config entry no longer present -+ 7. Success -+ """ -+ from lib389.cli_ctl.dbtasks import dbtasks_index_check -+ from lib389.dseldif import DSEldif -+ -+ standalone = topology_st.standalone -+ -+ log.info("Stop the server") -+ standalone.stop() -+ -+ log.info("Add ancestorid index config entry using DSEldif") -+ dse_ldif = DSEldif(standalone) -+ ancestorid_entry = [ -+ "dn: cn=ancestorid,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config\n", -+ "objectClass: top\n", -+ "objectClass: nsIndex\n", -+ "cn: ancestorid\n", -+ "nsSystemIndex: true\n", -+ "nsIndexType: eq\n", -+ ] -+ dse_ldif.add_entry(ancestorid_entry) -+ -+ # Verify it was added -+ ancestorid_dn = "cn=ancestorid,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config" -+ dse_ldif = DSEldif(standalone) # Reload -+ cn_value = dse_ldif.get(ancestorid_dn, "cn", single=True) -+ assert cn_value is not None, "Failed to add ancestorid index config entry" -+ log.info(f"Added ancestorid index entry with cn: {cn_value}") -+ -+ log.info("Run index-check without --fix (should detect issue)") -+ args = FakeArgs() -+ args.backend = "userRoot" -+ args.fix = False -+ -+ result = dbtasks_index_check(standalone, topology_st.logcap.log, args) -+ assert result is False, "index-check should detect ancestorid config issue" -+ assert topology_st.logcap.contains("ancestorid") and topology_st.logcap.contains("config entry exists") -+ topology_st.logcap.flush() -+ -+ log.info("Run index-check with --fix") -+ args.fix = True -+ result = dbtasks_index_check(standalone, topology_st.logcap.log, args) -+ assert result is True, "index-check --fix should succeed" -+ assert topology_st.logcap.contains("Removed ancestorid config entry") -+ topology_st.logcap.flush() -+ -+ log.info("Verify ancestorid config entry was removed") -+ dse_ldif = DSEldif(standalone) # Reload to get fresh data -+ cn_value = dse_ldif.get(ancestorid_dn, "cn", single=True) -+ assert cn_value is None, f"ancestorid config entry should be removed, but got: {cn_value}" -+ log.info("ancestorid config entry successfully removed") -+ -+ log.info("Start the server") -+ standalone.start() -+ -+ -+def test_index_check_fixes_missing_matching_rule(topology_st): -+ """Check if dsctl index-check --fix adds missing integerOrderingMatch -+ -+ :id: 6c1d4e9f-0a3b-4d5c-1e7f-8a9b0c2d3e4f -+ :setup: Standalone instance -+ :steps: -+ 1. Create DS instance -+ 2. Stop the server -+ 3. Remove integerOrderingMatch from parentid index using DSEldif -+ 4. Run dsctl index-check (should detect issue) -+ 5. Run dsctl index-check --fix -+ 6. Verify integerOrderingMatch was added back -+ 7. Start the server -+ :expectedresults: -+ 1. Success -+ 2. Success -+ 3. Success -+ 4. index-check returns False and detects missing matching rule -+ 5. index-check returns True after fix -+ 6. integerOrderingMatch is present -+ 7. Success -+ """ -+ from lib389.cli_ctl.dbtasks import dbtasks_index_check -+ from lib389.dseldif import DSEldif -+ -+ standalone = topology_st.standalone -+ -+ log.info("Stop the server") -+ standalone.stop() -+ -+ log.info("Remove integerOrderingMatch from parentid index using DSEldif") -+ dse_ldif = DSEldif(standalone) -+ parentid_dn = "cn=parentid,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config" -+ -+ # Check current matching rules -+ matching_rules = dse_ldif.get(parentid_dn, "nsMatchingRule") -+ log.info(f"Current matching rules: {matching_rules}") -+ -+ # Remove integerOrderingMatch if present -+ if matching_rules: -+ for mr in matching_rules: -+ if "integerorderingmatch" in mr.lower(): -+ dse_ldif.delete(parentid_dn, "nsMatchingRule", mr) -+ log.info(f"Removed matching rule: {mr}") -+ -+ # Verify it was removed -+ dse_ldif = DSEldif(standalone) # Reload -+ matching_rules = dse_ldif.get(parentid_dn, "nsMatchingRule") -+ if matching_rules: -+ for mr in matching_rules: -+ assert "integerorderingmatch" not in mr.lower(), \ -+ f"integerOrderingMatch should be removed, but found: {mr}" -+ log.info("integerOrderingMatch removed from parentid index") -+ -+ log.info("Run index-check without --fix (should detect issue)") -+ args = FakeArgs() -+ args.backend = "userRoot" -+ args.fix = False -+ -+ result = dbtasks_index_check(standalone, topology_st.logcap.log, args) -+ assert result is False, "index-check should detect missing matching rule" -+ assert topology_st.logcap.contains("missing integerOrderingMatch") -+ topology_st.logcap.flush() -+ -+ log.info("Run index-check with --fix") -+ args.fix = True -+ result = dbtasks_index_check(standalone, topology_st.logcap.log, args) -+ assert result is True, "index-check --fix should succeed" -+ assert topology_st.logcap.contains("integerOrderingMatch") -+ topology_st.logcap.flush() -+ -+ log.info("Verify integerOrderingMatch was added back") -+ dse_ldif = DSEldif(standalone) # Reload to get fresh data -+ matching_rules = dse_ldif.get(parentid_dn, "nsMatchingRule") -+ assert matching_rules is not None, "nsMatchingRule should be present" -+ found_int_order = False -+ for mr in matching_rules: -+ if "integerorderingmatch" in mr.lower(): -+ found_int_order = True -+ break -+ assert found_int_order, f"integerOrderingMatch should be present, got: {matching_rules}" -+ log.info("integerOrderingMatch successfully added back") -+ -+ log.info("Start the server") -+ standalone.start() -+ -+ -+def test_index_check_fixes_default_ancestorid(topology_st): -+ """Check if dsctl index-check --fix removes ancestorid from default indexes -+ -+ :id: 7d2e5f0a-1b4c-4e6d-2f8a-9b0c1d3e4f5a -+ :setup: Standalone instance -+ :steps: -+ 1. Create DS instance -+ 2. Stop the server -+ 3. Add ancestorid to cn=default indexes using DSEldif -+ 4. Run dsctl index-check (should detect issue) -+ 5. Run dsctl index-check --fix -+ 6. Verify ancestorid was removed from default indexes -+ 7. Start the server -+ :expectedresults: -+ 1. Success -+ 2. Success -+ 3. Success -+ 4. index-check returns False and detects ancestorid in default indexes -+ 5. index-check returns True after fix -+ 6. ancestorid no longer in default indexes -+ 7. Success -+ """ -+ from lib389.cli_ctl.dbtasks import dbtasks_index_check -+ from lib389.dseldif import DSEldif -+ -+ standalone = topology_st.standalone -+ -+ log.info("Stop the server") -+ standalone.stop() -+ -+ log.info("Add ancestorid to cn=default indexes using DSEldif") -+ dse_ldif = DSEldif(standalone) -+ ancestorid_default_entry = [ -+ "dn: cn=ancestorid,cn=default indexes,cn=config,cn=ldbm database,cn=plugins,cn=config\n", -+ "objectClass: top\n", -+ "objectClass: nsIndex\n", -+ "cn: ancestorid\n", -+ "nsSystemIndex: true\n", -+ "nsIndexType: eq\n", -+ ] -+ dse_ldif.add_entry(ancestorid_default_entry) -+ -+ # Verify it was added -+ ancestorid_default_dn = "cn=ancestorid,cn=default indexes,cn=config,cn=ldbm database,cn=plugins,cn=config" -+ dse_ldif = DSEldif(standalone) # Reload -+ cn_value = dse_ldif.get(ancestorid_default_dn, "cn", single=True) -+ assert cn_value is not None, "Failed to add ancestorid to default indexes" -+ log.info(f"Added ancestorid to default indexes with cn: {cn_value}") -+ -+ log.info("Run index-check without --fix (should detect issue)") -+ args = FakeArgs() -+ args.backend = None # Check all backends including default indexes -+ args.fix = False -+ -+ result = dbtasks_index_check(standalone, topology_st.logcap.log, args) -+ assert result is False, "index-check should detect ancestorid in default indexes" -+ assert topology_st.logcap.contains("ancestorid found in cn=default indexes") -+ topology_st.logcap.flush() -+ -+ log.info("Run index-check with --fix") -+ args.fix = True -+ result = dbtasks_index_check(standalone, topology_st.logcap.log, args) -+ assert result is True, "index-check --fix should succeed" -+ assert topology_st.logcap.contains("Removed ancestorid from default indexes") -+ topology_st.logcap.flush() -+ -+ log.info("Verify ancestorid was removed from default indexes") -+ dse_ldif = DSEldif(standalone) # Reload to get fresh data -+ cn_value = dse_ldif.get(ancestorid_default_dn, "cn", single=True) -+ assert cn_value is None, f"ancestorid should be removed from default indexes, but got: {cn_value}" -+ log.info("ancestorid successfully removed from default indexes") -+ -+ log.info("Start the server") -+ standalone.start() -+ -+ -+def test_index_check_fixes_multiple_issues(topology_st): -+ """Check if dsctl index-check --fix handles multiple issues at once -+ -+ :id: 8e3f6a1b-2c5d-4f7e-3a9b-0c1d2e4f5a6b -+ :setup: Standalone instance -+ :steps: -+ 1. Create DS instance -+ 2. Stop the server -+ 3. Add multiple issues: scanlimit, ancestorid config, missing matching rule -+ 4. Run dsctl index-check (should detect all issues) -+ 5. Run dsctl index-check --fix -+ 6. Verify all issues were fixed -+ 7. Run dsctl index-check again (should pass) -+ 8. Start the server -+ :expectedresults: -+ 1. Success -+ 2. Success -+ 3. Success -+ 4. index-check returns False and detects all issues -+ 5. index-check returns True after fix -+ 6. All issues resolved -+ 7. index-check returns True (no issues) -+ 8. Success -+ """ -+ from lib389.cli_ctl.dbtasks import dbtasks_index_check -+ from lib389.dseldif import DSEldif -+ -+ standalone = topology_st.standalone -+ -+ log.info("Stop the server") -+ standalone.stop() -+ -+ dse_ldif = DSEldif(standalone) -+ parentid_dn = "cn=parentid,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config" -+ ancestorid_dn = "cn=ancestorid,cn=index,cn=userRoot,cn=ldbm database,cn=plugins,cn=config" -+ -+ log.info("Add issue 1: nsIndexIDListScanLimit to parentid") -+ dse_ldif.add(parentid_dn, "nsIndexIDListScanLimit", "4000") -+ -+ log.info("Add issue 2: ancestorid index config entry") -+ ancestorid_entry = [ -+ f"dn: {ancestorid_dn}\n", -+ "objectClass: top\n", -+ "objectClass: nsIndex\n", -+ "cn: ancestorid\n", -+ "nsSystemIndex: true\n", -+ "nsIndexType: eq\n", -+ ] -+ dse_ldif.add_entry(ancestorid_entry) -+ -+ log.info("Add issue 3: Remove integerOrderingMatch from parentid") -+ dse_ldif = DSEldif(standalone) # Reload -+ matching_rules = dse_ldif.get(parentid_dn, "nsMatchingRule") -+ if matching_rules: -+ for mr in matching_rules: -+ if "integerorderingmatch" in mr.lower(): -+ dse_ldif.delete(parentid_dn, "nsMatchingRule", mr) -+ -+ log.info("Run index-check without --fix (should detect all issues)") -+ args = FakeArgs() -+ args.backend = "userRoot" -+ args.fix = False -+ -+ result = dbtasks_index_check(standalone, topology_st.logcap.log, args) -+ assert result is False, "index-check should detect multiple issues" -+ # Check that multiple issues were detected -+ assert topology_st.logcap.contains("nsIndexIDListScanLimit") -+ assert topology_st.logcap.contains("ancestorid") -+ topology_st.logcap.flush() -+ -+ log.info("Run index-check with --fix") -+ args.fix = True -+ result = dbtasks_index_check(standalone, topology_st.logcap.log, args) -+ assert result is True, "index-check --fix should succeed" -+ assert topology_st.logcap.contains("All issues fixed") -+ topology_st.logcap.flush() -+ -+ log.info("Verify all issues were fixed") -+ dse_ldif = DSEldif(standalone) # Reload -+ -+ # Check scanlimit removed -+ scanlimit = dse_ldif.get(parentid_dn, "nsIndexIDListScanLimit", single=True) -+ assert scanlimit is None, f"nsIndexIDListScanLimit should be removed, got: {scanlimit}" -+ -+ # Check ancestorid config removed -+ cn_value = dse_ldif.get(ancestorid_dn, "cn", single=True) -+ assert cn_value is None, f"ancestorid config should be removed, got: {cn_value}" -+ -+ # Check matching rule added back -+ matching_rules = dse_ldif.get(parentid_dn, "nsMatchingRule") -+ found_int_order = False -+ if matching_rules: -+ for mr in matching_rules: -+ if "integerorderingmatch" in mr.lower(): -+ found_int_order = True -+ break -+ assert found_int_order, f"integerOrderingMatch should be present, got: {matching_rules}" -+ -+ log.info("All issues verified as fixed") -+ -+ log.info("Run index-check again to confirm all clear") -+ args.fix = False -+ result = dbtasks_index_check(standalone, topology_st.logcap.log, args) -+ assert result is True, "index-check should pass after fix" -+ assert topology_st.logcap.contains("All checks passed") -+ topology_st.logcap.flush() -+ -+ log.info("Start the server") -+ standalone.start() -+ -+ - if __name__ == "__main__": - # Run isolated - # -s for DEBUG mode -diff --git a/rpm/389-ds-base.spec.in b/rpm/389-ds-base.spec.in -index 44a158ce5..0175dfa7c 100644 ---- a/rpm/389-ds-base.spec.in -+++ b/rpm/389-ds-base.spec.in -@@ -645,42 +645,45 @@ if ! getent passwd $USERNAME >/dev/null ; then - fi - - # Reload our sysctl before we restart (if we can) --sysctl --system &> $output; true -+sysctl --system &> "$output"; true - --# Gather the running instances so we can restart them -+# Gather running instances, stop them, run index-check, then restart - instbase="%{_sysconfdir}/%{pkgname}" -+instances="" - ninst=0 --for dir in $instbase/slapd-* ; do -- echo dir = $dir >> $output 2>&1 || : -+ -+for dir in "$instbase"/slapd-* ; do -+ echo "dir = $dir" >> "$output" 2>&1 || : - if [ ! -d "$dir" ] ; then continue ; fi - case "$dir" in *.removed) continue ;; esac -- basename=`basename $dir` -- inst="%{pkgname}@`echo $basename | sed -e 's/slapd-//g'`" -- echo found instance $inst - getting status >> $output 2>&1 || : -- if /bin/systemctl -q is-active $inst ; then -- echo instance $inst is running >> $output 2>&1 || : -+ basename=$(basename "$dir") -+ inst="%{pkgname}@${basename#slapd-}" -+ inst_name="${basename#slapd-}" -+ echo "found instance $inst - getting status" >> "$output" 2>&1 || : -+ if /bin/systemctl -q is-active "$inst" ; then -+ echo "instance $inst is running - stopping for upgrade" >> "$output" 2>&1 || : - instances="$instances $inst" -+ /bin/systemctl stop "$inst" >> "$output" 2>&1 || : - else -- echo instance $inst is not running >> $output 2>&1 || : -+ echo "instance $inst is not running" >> "$output" 2>&1 || : - fi -- ninst=`expr $ninst + 1` -+ # Run index-check on all instances (running or not) -+ # This fixes index ordering mismatches from older versions -+ dsctl "$inst_name" index-check --fix >> "$output2" 2>&1 || : -+ ninst=$((ninst + 1)) - done -+ - if [ $ninst -eq 0 ] ; then -- echo no instances to upgrade >> $output 2>&1 || : -- exit 0 # have no instances to upgrade - just skip the rest --else -- # restart running instances -- echo shutting down all instances . . . >> $output 2>&1 || : -- for inst in $instances ; do -- echo stopping instance $inst >> $output 2>&1 || : -- /bin/systemctl stop $inst >> $output 2>&1 || : -- done -- for inst in $instances ; do -- echo starting instance $inst >> $output 2>&1 || : -- /bin/systemctl start $inst >> $output 2>&1 || : -- done -+ echo "no instances to upgrade" >> "$output" 2>&1 || : -+ exit 0 - fi - -+# Restart previously running instances -+for inst in $instances ; do -+ echo "starting instance $inst" >> "$output" 2>&1 || : -+ /bin/systemctl start "$inst" >> "$output" 2>&1 || : -+done -+ - - %preun - if [ $1 -eq 0 ]; then # Final removal -diff --git a/src/lib389/lib389/cli_ctl/dbtasks.py b/src/lib389/lib389/cli_ctl/dbtasks.py -index 856639672..16da966d1 100644 ---- a/src/lib389/lib389/cli_ctl/dbtasks.py -+++ b/src/lib389/lib389/cli_ctl/dbtasks.py -@@ -7,12 +7,24 @@ - # See LICENSE for details. - # --- END COPYRIGHT BLOCK --- - -+import glob - import os -+import re -+import subprocess -+from enum import Enum - from lib389._constants import TaskWarning - from lib389.cli_base import CustomHelpFormatter -+from lib389.dseldif import DSEldif - from pathlib import Path - - -+class IndexOrdering(Enum): -+ """Represents the ordering type of an index.""" -+ INTEGER = "integer" -+ LEXICOGRAPHIC = "lexicographic" -+ UNKNOWN = "unknown" -+ -+ - def dbtasks_db2index(inst, log, args): - rtn = False - if not args.backend: -@@ -126,6 +138,387 @@ def dbtasks_verify(inst, log, args): - log.info("dbverify successful") - - -+def _get_db_dir(dse_ldif): -+ """Get the database directory. -+ -+ Args: -+ dse_ldif: DSEldif instance. -+ -+ Returns: -+ Path to the database directory, or None if not found. -+ """ -+ try: -+ db_dir = dse_ldif.get( -+ "cn=config,cn=ldbm database,cn=plugins,cn=config", -+ "nsslapd-directory", -+ single=True, -+ ) -+ return db_dir -+ except (ValueError, TypeError): -+ pass -+ return None -+ -+ -+ -+def _has_integer_ordering_match(dse_ldif, backend, index_name): -+ """Check if an index has integerOrderingMatch configured in DSE. -+ -+ Args: -+ dse_ldif: DSEldif instance. -+ backend: Backend name. -+ index_name: Name of the index to check. -+ -+ Returns: -+ True if integerOrderingMatch is configured, False otherwise. -+ """ -+ index_dn = "cn={},cn=index,cn={},cn=ldbm database,cn=plugins,cn=config".format( -+ index_name, backend -+ ) -+ matching_rules = dse_ldif.get(index_dn, "nsMatchingRule", lower=True) -+ if matching_rules: -+ return any(mr.lower() == "integerorderingmatch" for mr in matching_rules) -+ return False -+ -+ -+def _has_index_scan_limit(dse_ldif, backend, index_name): -+ """Check if an index has nsIndexIDListScanLimit configured. -+ -+ Args: -+ dse_ldif: DSEldif instance. -+ backend: Backend name. -+ index_name: Name of the index to check. -+ -+ Returns: -+ True if nsIndexIDListScanLimit is configured, False otherwise. -+ """ -+ index_dn = "cn={},cn=index,cn={},cn=ldbm database,cn=plugins,cn=config".format( -+ index_name, backend -+ ) -+ scan_limit = dse_ldif.get(index_dn, "nsIndexIDListScanLimit") -+ return scan_limit is not None -+ -+ -+def _index_config_exists(dse_ldif, backend, index_name): -+ """Check if an index configuration entry exists in DSE. -+ -+ Args: -+ dse_ldif: DSEldif instance. -+ backend: Backend name. -+ index_name: Name of the index to check. -+ -+ Returns: -+ True if the index config entry exists, False otherwise. -+ """ -+ index_dn = "cn={},cn=index,cn={},cn=ldbm database,cn=plugins,cn=config".format( -+ index_name, backend -+ ) -+ try: -+ cn = dse_ldif.get(index_dn, "cn") -+ return cn is not None -+ except (ValueError, KeyError): -+ return False -+ -+ -+def _default_index_exists(dse_ldif, index_name): -+ """Check if an index exists in cn=default indexes. -+ -+ Args: -+ dse_ldif: DSEldif instance. -+ index_name: Name of the index to check. -+ -+ Returns: -+ True if the index exists in default indexes, False otherwise. -+ """ -+ index_dn = "cn={},cn=default indexes,cn=config,cn=ldbm database,cn=plugins,cn=config".format( -+ index_name -+ ) -+ try: -+ cn = dse_ldif.get(index_dn, "cn") -+ return cn is not None -+ except (ValueError, KeyError): -+ return False -+ -+ -+def _check_disk_ordering(db_dir, backend, index_name, dbscan_path, is_mdb, log): -+ """Check if index on disk uses lexicographic or integer ordering. -+ -+ Args: -+ db_dir: Path to the database directory. -+ backend: Backend name. -+ index_name: Name of the index to check. -+ dbscan_path: Path to the dbscan binary. -+ is_mdb: True if using MDB backend. -+ log: Logger instance. -+ -+ Returns: -+ IndexOrdering: The detected ordering type. -+ """ -+ if is_mdb: -+ # MDB uses pseudo-paths: db_dir/backend/index.db -+ # dbscan accesses indexes via paths like: /var/lib/dirsrv/slapd-xxx/db/userroot/parentid.db -+ index_file = os.path.join(db_dir, backend, "{}.db".format(index_name)) -+ else: -+ # BDB has separate directories per backend with actual index files -+ backend_dir = os.path.join(db_dir, backend) -+ if not os.path.exists(backend_dir): -+ return IndexOrdering.UNKNOWN -+ index_file = None -+ pattern = os.path.join(backend_dir, "{}.db*".format(index_name)) -+ for f in glob.glob(pattern): -+ if os.path.isfile(f): -+ index_file = f -+ break -+ if not index_file: -+ return IndexOrdering.UNKNOWN -+ -+ try: -+ result = subprocess.run( -+ [dbscan_path, "-f", index_file], -+ stdout=subprocess.PIPE, -+ stderr=subprocess.PIPE, -+ universal_newlines=True, -+ timeout=60, -+ ) -+ -+ if result.returncode != 0: -+ log.warning(" dbscan returned non-zero exit code for %s", index_file) -+ return IndexOrdering.UNKNOWN -+ -+ # Parse keys from dbscan output -+ keys = [] -+ for line in result.stdout.split("\n"): -+ line = line.strip() -+ if line.startswith("="): -+ match = re.match(r"^=(\d+)", line) -+ if match: -+ keys.append(int(match.group(1))) -+ -+ if len(keys) < 2: -+ return IndexOrdering.UNKNOWN -+ -+ # Check if keys are in integer order by looking for decreasing numeric values -+ # (which would indicate lexicographic ordering, e.g., "3" < "30" < "4") -+ prev_id = keys[0] -+ for i in range(1, min(len(keys), 100)): -+ current_id = keys[i] -+ if prev_id > current_id: -+ return IndexOrdering.LEXICOGRAPHIC -+ prev_id = current_id -+ -+ return IndexOrdering.INTEGER -+ -+ except subprocess.TimeoutExpired: -+ log.warning(" dbscan timed out for %s", index_file) -+ return IndexOrdering.UNKNOWN -+ except OSError as e: -+ log.warning(" Error running dbscan: %s", e) -+ return IndexOrdering.UNKNOWN -+ -+ -+def dbtasks_index_check(inst, log, args): -+ """Check and optionally fix index ordering mismatches. -+ -+ This function detects mismatches between the configured ordering -+ (integerOrderingMatch in DSE) and the actual on-disk ordering of -+ parentid and ancestorid indexes. -+ -+ Args: -+ inst: DirSrv instance. -+ log: Logger instance. -+ args: Parsed command line arguments. -+ -+ Returns: -+ True if all checks passed, False if mismatches were detected. -+ """ -+ # Server must be stopped -+ if inst.status(): -+ log.error("index-check requires the instance to be stopped") -+ return False -+ -+ # Check for dbscan binary -+ dbscan_path = os.path.join(inst.ds_paths.bin_dir, "dbscan") -+ if not os.path.exists(dbscan_path): -+ log.error("dbscan utility not found at %s", dbscan_path) -+ return False -+ -+ # Load DSE -+ try: -+ dse_ldif = DSEldif(inst) -+ except Exception as e: -+ log.error("Failed to read dse.ldif: %s", e) -+ return False -+ -+ # Get backends to check -+ all_backends = dse_ldif.get_backends() -+ if not all_backends: -+ log.info("No backends found") -+ return True -+ -+ # Filter to specific backend if requested -+ if args.backend: -+ # Case-insensitive backend lookup -+ backend_lower = args.backend.lower() -+ matching_backend = None -+ for be in all_backends: -+ if be.lower() == backend_lower: -+ matching_backend = be -+ break -+ if matching_backend is None: -+ log.error("Backend '%s' not found. Available backends: %s", -+ args.backend, ", ".join(all_backends)) -+ return False -+ backends_to_check = [matching_backend] -+ else: -+ backends_to_check = all_backends -+ -+ # Get database directory and check database type -+ db_dir = _get_db_dir(dse_ldif) -+ if not db_dir or not os.path.exists(db_dir): -+ log.error("Database directory not found") -+ return False -+ -+ db_lib = inst.get_db_lib() -+ is_mdb = (db_lib == "mdb") -+ log.info("Database type: %s", db_lib.upper()) -+ -+ # Track all issues found -+ all_ok = True -+ mismatches = [] # (backend, index_name) tuples needing reindex -+ missing_matching_rules = [] # (backend, index_name) tuples missing integerOrderingMatch -+ scan_limits_to_remove = [] # (backend, index_name) tuples with nsIndexIDListScanLimit -+ ancestorid_configs_to_remove = [] # backend names with ancestorid config entries -+ remove_ancestorid_from_defaults = False # Flag to remove from cn=default indexes -+ -+ # Check if ancestorid exists in cn=default indexes (should be removed) -+ if _default_index_exists(dse_ldif, "ancestorid"): -+ log.warning("ancestorid found in cn=default indexes - should be removed") -+ remove_ancestorid_from_defaults = True -+ all_ok = False -+ -+ for backend in backends_to_check: -+ log.info("Checking backend: %s", backend) -+ -+ # Check for ancestorid config entry (should not exist) -+ if _index_config_exists(dse_ldif, backend, "ancestorid"): -+ log.warning(" ancestorid - config entry exists (should be removed)") -+ ancestorid_configs_to_remove.append(backend) -+ all_ok = False -+ -+ # Check parentid and ancestorid indexes -+ for index_name in ["parentid", "ancestorid"]: -+ # Check for scan limits (should be removed) -+ if _has_index_scan_limit(dse_ldif, backend, index_name): -+ log.warning(" %s - has nsIndexIDListScanLimit (should be removed)", index_name) -+ scan_limits_to_remove.append((backend, index_name)) -+ all_ok = False -+ -+ # Check disk ordering -+ disk_ordering = _check_disk_ordering(db_dir, backend, index_name, dbscan_path, is_mdb, log) -+ -+ if disk_ordering == IndexOrdering.UNKNOWN: -+ log.info(" %s - could not determine disk ordering, skipping", index_name) -+ # For parentid, still check if matching rule is missing -+ if index_name == "parentid": -+ config_has_int_order = _has_integer_ordering_match(dse_ldif, backend, index_name) -+ if not config_has_int_order: -+ log.warning(" %s - missing integerOrderingMatch in config", index_name) -+ missing_matching_rules.append((backend, index_name)) -+ all_ok = False -+ continue -+ -+ config_has_int_order = _has_integer_ordering_match(dse_ldif, backend, index_name) -+ config_desc = "integer" if config_has_int_order else "lexicographic" -+ log.info(" %s - config: %s, disk: %s", -+ index_name, config_desc, disk_ordering.value) -+ -+ # For parentid, the desired state is always integer ordering -+ if index_name == "parentid": -+ if not config_has_int_order: -+ log.warning(" %s - missing integerOrderingMatch in config", index_name) -+ if (backend, index_name) not in missing_matching_rules: -+ missing_matching_rules.append((backend, index_name)) -+ all_ok = False -+ -+ if disk_ordering == IndexOrdering.LEXICOGRAPHIC: -+ log.warning(" %s - disk ordering is lexicographic, needs reindex", index_name) -+ if (backend, index_name) not in mismatches: -+ mismatches.append((backend, index_name)) -+ all_ok = False -+ -+ # Handle issues -+ if not all_ok: -+ if args.fix: -+ log.info("Fixing issues...") -+ -+ # Remove ancestorid from cn=default indexes -+ if remove_ancestorid_from_defaults: -+ default_idx_dn = "cn=ancestorid,cn=default indexes,cn=config,cn=ldbm database,cn=plugins,cn=config" -+ log.info(" Removing ancestorid from default indexes...") -+ try: -+ dse_ldif.delete_dn(default_idx_dn) -+ log.info(" Removed ancestorid from default indexes") -+ except Exception as e: -+ log.error(" Failed to remove ancestorid from default indexes: %s", e) -+ return False -+ -+ # Remove scan limits (only for indexes that won't be deleted) -+ for backend, index_name in scan_limits_to_remove: -+ # Skip ancestorid if we're going to delete the whole entry anyway -+ if index_name == "ancestorid" and backend in ancestorid_configs_to_remove: -+ continue -+ index_dn = "cn={},cn=index,cn={},cn=ldbm database,cn=plugins,cn=config".format( -+ index_name, backend -+ ) -+ log.info(" Removing nsIndexIDListScanLimit from %s in backend %s...", index_name, backend) -+ try: -+ dse_ldif.delete(index_dn, "nsIndexIDListScanLimit") -+ log.info(" Removed nsIndexIDListScanLimit from %s", index_name) -+ except Exception as e: -+ log.error(" Failed to remove nsIndexIDListScanLimit from %s: %s", index_name, e) -+ return False -+ -+ # Remove ancestorid config entries from backends -+ for backend in ancestorid_configs_to_remove: -+ index_dn = "cn=ancestorid,cn=index,cn={},cn=ldbm database,cn=plugins,cn=config".format(backend) -+ log.info(" Removing ancestorid config entry from backend %s...", backend) -+ try: -+ dse_ldif.delete_dn(index_dn) -+ log.info(" Removed ancestorid config entry from backend %s", backend) -+ except Exception as e: -+ log.error(" Failed to remove ancestorid config from backend %s: %s", backend, e) -+ return False -+ -+ # Add missing matching rules to dse.ldif -+ for backend, index_name in missing_matching_rules: -+ index_dn = "cn={},cn=index,cn={},cn=ldbm database,cn=plugins,cn=config".format( -+ index_name, backend -+ ) -+ log.info(" Adding integerOrderingMatch to %s in backend %s...", index_name, backend) -+ try: -+ dse_ldif.add(index_dn, "nsMatchingRule", "integerOrderingMatch") -+ log.info(" Updated dse.ldif with integerOrderingMatch for %s", index_name) -+ except Exception as e: -+ log.error(" Failed to update dse.ldif for %s: %s", index_name, e) -+ return False -+ -+ # Reindex indexes with disk ordering issues -+ for backend, index_name in mismatches: -+ log.info(" Reindexing %s in backend %s...", index_name, backend) -+ if not inst.db2index(bename=backend, attrs=[index_name]): -+ log.error(" Failed to reindex %s", index_name) -+ return False -+ log.info(" Reindex of %s completed successfully", index_name) -+ -+ log.info("All issues fixed") -+ return True -+ else: -+ log.info("Issues detected. Run with --fix to repair.") -+ return False -+ else: -+ log.info("All checks passed - no issues found") -+ return True -+ -+ - def create_parser(subcommands): - db2index_parser = subcommands.add_parser('db2index', help="Initialise a reindex of the server database. The server must be stopped for this to proceed.", formatter_class=CustomHelpFormatter) - # db2index_parser.add_argument('suffix', help="The suffix to reindex. IE dc=example,dc=com.") -@@ -172,3 +565,12 @@ def create_parser(subcommands): - ldifs_parser = subcommands.add_parser('ldifs', help="List all the LDIF files located in the server's LDIF directory", formatter_class=CustomHelpFormatter) - ldifs_parser.add_argument('--delete', nargs=1, help="Delete LDIF file") - ldifs_parser.set_defaults(func=dbtasks_ldifs) -+ -+ index_check_parser = subcommands.add_parser('index-check', -+ help="Check for index ordering mismatches (parentid/ancestorid). The server must be stopped.", -+ formatter_class=CustomHelpFormatter) -+ index_check_parser.add_argument('backend', nargs='?', default=None, -+ help="Backend to check. If not specified, all backends are checked.") -+ index_check_parser.add_argument('--fix', action='store_true', default=False, -+ help="Fix mismatches by reindexing affected indexes") -+ index_check_parser.set_defaults(func=dbtasks_index_check) -diff --git a/src/lib389/lib389/dseldif.py b/src/lib389/lib389/dseldif.py -index d12c6424c..7834d9468 100644 ---- a/src/lib389/lib389/dseldif.py -+++ b/src/lib389/lib389/dseldif.py -@@ -125,11 +125,14 @@ class DSEldif(DSLint): - self._contents[i] = self._contents[i].replace(strfrom, strto) - self._update() - -- def _find_attr(self, entry_dn, attr): -+ def _find_attr(self, entry_dn, attr, lower=False): - """Find all attribute values and indexes under a given entry - - Returns entry dn index and attribute data dict: - relative attribute indexes and the attribute value -+ -+ :param lower: Use case-insensitive matching for attribute name -+ :type lower: boolean - """ - - entry_dn_i = self._contents.index("dn: {}\n".format(entry_dn.lower())) -@@ -146,7 +149,11 @@ class DSEldif(DSLint): - - # Find the attribute - for line in entry_slice: -- if line.startswith("{}:".format(attr)): -+ if lower: -+ match = line.lower().startswith("{}:".format(attr.lower())) -+ else: -+ match = line.startswith("{}:".format(attr)) -+ if match: - attr_value = line.split(" ", 1)[1][:-1] - attr_data.update({entry_slice.index(line): attr_value}) - -@@ -155,7 +162,7 @@ class DSEldif(DSLint): - - return entry_dn_i, attr_data - -- def get(self, entry_dn, attr, single=False): -+ def get(self, entry_dn, attr, single=False, lower=False): - """Return attribute values under a given entry - - :param entry_dn: a DN of entry we want to get attribute from -@@ -163,11 +170,13 @@ class DSEldif(DSLint): - :param attr: an attribute name - :type attr: str - :param single: Return a single value instead of a list -- :type sigle: boolean -+ :type single: boolean -+ :param lower: Use case-insensitive matching for attribute name -+ :type lower: boolean - """ - - try: -- _, attr_data = self._find_attr(entry_dn, attr) -+ _, attr_data = self._find_attr(entry_dn, attr, lower=lower) - except ValueError: - return None - -@@ -190,6 +199,38 @@ class DSEldif(DSLint): - - return indexes - -+ def get_backends(self): -+ """Return a list of backend names from DSE. -+ -+ Returns backend names preserving their original case, as the -+ database directory names on disk use the original case. -+ -+ Note: DSEldif lowercases DN lines, so we read the 'cn' attribute -+ from each entry to get the original case. -+ -+ :returns: List of backend names -+ """ -+ backends = [] -+ excluded = ("config", "monitor", "index", "encrypted attributes") -+ -+ for entry in self._contents: -+ if (entry.startswith("dn: cn=") and -+ ",cn=ldbm database,cn=plugins,cn=config" in entry): -+ parts = entry.split(",") -+ if len(parts) > 1: -+ cn_lower = parts[0].replace("dn: cn=", "") -+ if cn_lower not in excluded: -+ dn = entry.strip()[4:].strip() -+ try: -+ suffix = self.get(dn, "nsslapd-suffix") -+ if suffix: -+ cn_values = self.get(dn, "cn") -+ if cn_values: -+ backends.append(cn_values[0]) -+ except (ValueError, IndexError): -+ pass -+ -+ return list(set(backends)) - - def add_entry(self, entry): - """Add a new entry --- -2.52.0 - diff --git a/0017-Issue-7096-2nd-During-replication-online-total-init-.patch b/0017-Issue-7096-2nd-During-replication-online-total-init-.patch deleted file mode 100644 index 724a0b7..0000000 --- a/0017-Issue-7096-2nd-During-replication-online-total-init-.patch +++ /dev/null @@ -1,135 +0,0 @@ -From c1f0756b453b7ea219add236f60a72b3fc660af0 Mon Sep 17 00:00:00 2001 -From: Viktor Ashirov -Date: Tue, 27 Jan 2026 14:26:29 +0100 -Subject: [PATCH] Issue 7096 - (2nd) During replication online total init the - function idl_id_is_in_idlist is not scaling with large database (#7205) - -Bug Description: -The fix for #7096 optimized the BDB backend's `idl_new_range_fetch()` -function to use ID ranges instead of checking the full ID list during -online total initialization. However, the LMDB backend's -`idl_lmdb_range_fetch()` function and its callback -`idl_range_add_id_cb()` were not updated and still use the non-scaling -`idl_id_is_in_idlist()` function. - -Fix Description: -Apply the same optimization to the LMDB backend. - -Fixes: https://github.com/389ds/389-ds-base/issues/7096 - -Reviewed by: @tbordaz, @droideck (Thanks!) ---- - ldap/servers/slapd/back-ldbm/idl_new.c | 39 ++++++++++---------------- - 1 file changed, 15 insertions(+), 24 deletions(-) - -diff --git a/ldap/servers/slapd/back-ldbm/idl_new.c b/ldap/servers/slapd/back-ldbm/idl_new.c -index 2d978353f..613d53815 100644 ---- a/ldap/servers/slapd/back-ldbm/idl_new.c -+++ b/ldap/servers/slapd/back-ldbm/idl_new.c -@@ -66,6 +66,7 @@ typedef struct { - size_t leftoverlen; - size_t leftovercnt; - IDList *idl; -+ IdRange_t *idrange_list; - int flag_err; - ID lastid; - ID suffix; -@@ -700,9 +701,9 @@ error: - } - } - } -- slapi_ch_free((void **)&leftover); -- idrange_free(&idrange_list); - } -+ slapi_ch_free((void **)&leftover); -+ idrange_free(&idrange_list); - slapi_log_err(SLAPI_LOG_FILTER, "idl_new_range_fetch", - "Found %d candidates; error code is: %d\n", - idl ? idl->b_nids : 0, *flag_err); -@@ -716,7 +717,6 @@ static int - idl_range_add_id_cb(dbi_val_t *key, dbi_val_t *data, void *ctx) - { - idl_range_ctx_t *rctx = ctx; -- int idl_rc = 0; - ID id = 0; - - if (key->data == NULL) { -@@ -779,10 +779,12 @@ idl_range_add_id_cb(dbi_val_t *key, dbi_val_t *data, void *ctx) - * found entry is the one from the suffix - */ - rctx->suffix = keyval; -- idl_rc = idl_append_extend(&rctx->idl, id); -- } else if ((keyval == rctx->suffix) || idl_id_is_in_idlist(rctx->idl, keyval)) { -+ idl_append_extend(&rctx->idl, id); -+ idrange_add_id(&rctx->idrange_list, id); -+ } else if ((keyval == rctx->suffix) || idl_id_is_in_idlist_ranges(rctx->idl, rctx->idrange_list, keyval)) { - /* the parent is the suffix or already in idl. */ -- idl_rc = idl_append_extend(&rctx->idl, id); -+ idl_append_extend(&rctx->idl, id); -+ idrange_add_id(&rctx->idrange_list, id); - } else { - /* Otherwise, keep the {keyval,id} in leftover array */ - if (!rctx->leftover) { -@@ -797,14 +799,7 @@ idl_range_add_id_cb(dbi_val_t *key, dbi_val_t *data, void *ctx) - rctx->leftovercnt++; - } - } else { -- idl_rc = idl_append_extend(&rctx->idl, id); -- } -- if (idl_rc) { -- slapi_log_err(SLAPI_LOG_ERR, "idl_lmdb_range_fetch", -- "Unable to extend id list (err=%d)\n", idl_rc); -- idl_free(&rctx->idl); -- rctx->flag_err = LDAP_UNWILLING_TO_PERFORM; -- return DBI_RC_NOTFOUND; -+ idl_append_extend(&rctx->idl, id); - } - #if defined(DB_ALLIDS_ON_READ) - /* enforce the allids read limit */ -@@ -841,7 +836,6 @@ idl_lmdb_range_fetch( - { - int ret = 0; - int ret2 = 0; -- int idl_rc = 0; - dbi_cursor_t cursor = {0}; - back_txn s_txn; - struct ldbminfo *li = (struct ldbminfo *)be->be_database->plg_private; -@@ -891,6 +885,7 @@ idl_lmdb_range_fetch( - idl_range_ctx.lastid = 0; - idl_range_ctx.count = 0; - idl_range_ctx.index_id = index_id; -+ idl_range_ctx.idrange_list = NULL; - if (operator & SLAPI_OP_RANGE_NO_IDL_SORT) { - struct _back_info_index_key bck_info; - /* We are doing a bulk import -@@ -966,22 +961,18 @@ error: - while(remaining > 0) { - for (size_t i = 0; i < idl_range_ctx.leftovercnt; i++) { - if (idl_range_ctx.leftover[i].key > 0 && -- idl_id_is_in_idlist(idl_range_ctx.idl, idl_range_ctx.leftover[i].key) != 0) { -+ idl_id_is_in_idlist_ranges(idl_range_ctx.idl, idl_range_ctx.idrange_list, idl_range_ctx.leftover[i].key) != 0) { - /* if the leftover key has its parent in the idl */ -- idl_rc = idl_append_extend(&idl_range_ctx.idl, idl_range_ctx.leftover[i].id); -- if (idl_rc) { -- slapi_log_err(SLAPI_LOG_ERR, "idl_lmdb_range_fetch", -- "Unable to extend id list (err=%d)\n", idl_rc); -- idl_free(&idl_range_ctx.idl); -- break; -- } -+ idl_append_extend(&idl_range_ctx.idl, idl_range_ctx.leftover[i].id); -+ idrange_add_id(&idl_range_ctx.idrange_list, idl_range_ctx.leftover[i].id); - idl_range_ctx.leftover[i].key = 0; - remaining--; - } - } - } -- slapi_ch_free((void **)&idl_range_ctx.leftover); - } -+ slapi_ch_free((void **)&idl_range_ctx.leftover); -+ idrange_free(&idl_range_ctx.idrange_list); - *flag_err = idl_range_ctx.flag_err; - slapi_log_err(SLAPI_LOG_FILTER, "idl_lmdb_range_fetch", - "Found %d candidates; error code is: %d\n", --- -2.52.0 - diff --git a/0018-Issue-7076-6992-6784-6214-Fix-CI-test-failures-7077.patch b/0018-Issue-7076-6992-6784-6214-Fix-CI-test-failures-7077.patch deleted file mode 100644 index dfd9482..0000000 --- a/0018-Issue-7076-6992-6784-6214-Fix-CI-test-failures-7077.patch +++ /dev/null @@ -1,877 +0,0 @@ -From 35237d57daf6fdf20a42c3cef27130ba70f0cdc2 Mon Sep 17 00:00:00 2001 -From: Akshay Adhikari -Date: Tue, 18 Nov 2025 21:57:10 +0530 -Subject: [PATCH] Issue 7076, 6992, 6784, 6214 - Fix CI test failures (#7077) - -- Fixed import test bugs in regression_test.py (cleanup handler, LDIF permissions) - - https://github.com/389ds/389-ds-base/issues/6992 -- Fixed ModRDN cache corruption on failed operations (parent update check, cache cleanup) -- Fixed attribute uniqueness test fixture cleanup in attruniq_test.py -- mproved test stability by fixing race conditions in replication, healthcheck, - web UI, memberOf, and basic tests. -- Fixed entrycache_eviction_test.py to track incremental log counts instead of cumulative - - https://github.com/389ds/389-ds-base/issues/6784 - -Fixes: https://github.com/389ds/389-ds-base/issues/7076 -Relates: https://github.com/389ds/389-ds-base/issues/6992 -Relates: https://github.com/389ds/389-ds-base/issues/6784 -Fixes: https://github.com/389ds/389-ds-base/issues/6214 - -Reviewed by: @vashirov, @progier389 (Thanks!) ---- - dirsrvtests/tests/suites/basic/basic_test.py | 4 +- - .../healthcheck/health_system_indexes_test.py | 3 + - .../tests/suites/import/regression_test.py | 388 +++++++++++++++++- - .../suites/memberof_plugin/fixup_test.py | 8 +- - .../tests/suites/plugins/attruniq_test.py | 84 ++-- - .../suites/replication/regression_m2_test.py | 4 + - .../replication/repl_log_monitoring_test.py | 8 +- - .../suites/webui/database/database_test.py | 1 + - ldap/servers/slapd/back-ldbm/ldbm_modrdn.c | 44 +- - 9 files changed, 481 insertions(+), 63 deletions(-) - -diff --git a/dirsrvtests/tests/suites/basic/basic_test.py b/dirsrvtests/tests/suites/basic/basic_test.py -index be825efe9..e9b611439 100644 ---- a/dirsrvtests/tests/suites/basic/basic_test.py -+++ b/dirsrvtests/tests/suites/basic/basic_test.py -@@ -593,7 +593,7 @@ def test_basic_import_export(topology_st, import_example_ldif): - # - # Test online/offline LDIF imports - # -- topology_st.standalone.start() -+ topology_st.standalone.restart() - # topology_st.standalone.config.set('nsslapd-errorlog-level', '1') - - # Generate a test ldif (50k entries) -@@ -691,6 +691,8 @@ def test_basic_backup(topology_st, import_example_ldif): - - log.info('Running test_basic_backup...') - -+ topology_st.standalone.restart() -+ - backup_dir = topology_st.standalone.get_bak_dir() + '/backup_test_online' - log.info(f'Backup directory is {backup_dir}') - -diff --git a/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py b/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py -index 571465562..4cd4d0c70 100644 ---- a/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py -+++ b/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py -@@ -172,6 +172,7 @@ def test_missing_parentid(topology_st, log_buffering_enabled): - log.info("Re-add the parentId index") - backend = Backends(standalone).get("userRoot") - backend.add_index("parentid", ["eq"], matching_rules=["integerOrderingMatch"]) -+ standalone.restart() - - run_healthcheck_and_flush_log(topology_st, standalone, json=False, searched_code=CMD_OUTPUT) - run_healthcheck_and_flush_log(topology_st, standalone, json=True, searched_code=JSON_OUTPUT) -@@ -215,6 +216,7 @@ def test_missing_matching_rule(topology_st, log_buffering_enabled): - log.info("Re-add the integerOrderingMatch matching rule") - parentid_index = Index(standalone, PARENTID_DN) - parentid_index.add("nsMatchingRule", "integerOrderingMatch") -+ standalone.restart() - - run_healthcheck_and_flush_log(topology_st, standalone, json=False, searched_code=CMD_OUTPUT) - run_healthcheck_and_flush_log(topology_st, standalone, json=True, searched_code=JSON_OUTPUT) -@@ -445,6 +447,7 @@ def test_multiple_missing_indexes(topology_st, log_buffering_enabled): - backend = Backends(standalone).get("userRoot") - backend.add_index("parentid", ["eq"], matching_rules=["integerOrderingMatch"]) - backend.add_index("nsuniqueid", ["eq"]) -+ standalone.restart() - - run_healthcheck_and_flush_log(topology_st, standalone, json=False, searched_code=CMD_OUTPUT) - run_healthcheck_and_flush_log(topology_st, standalone, json=True, searched_code=JSON_OUTPUT) -diff --git a/dirsrvtests/tests/suites/import/regression_test.py b/dirsrvtests/tests/suites/import/regression_test.py -index 18611de35..bdbb516e8 100644 ---- a/dirsrvtests/tests/suites/import/regression_test.py -+++ b/dirsrvtests/tests/suites/import/regression_test.py -@@ -5,6 +5,7 @@ - # See LICENSE for details. - # --- END COPYRIGHT BLOCK --- - # -+from abc import ABC, abstractmethod - from decimal import * - import ldap - import logging -@@ -16,9 +17,9 @@ from lib389.backend import Backends - from lib389.properties import TASK_WAIT - from lib389.topologies import topology_st as topo - from lib389.dbgen import dbgen_users --from lib389._constants import DEFAULT_SUFFIX -+from lib389._constants import DEFAULT_SUFFIX, DEFAULT_BENAME - from lib389.tasks import * --from lib389.idm.user import UserAccounts -+from lib389.idm.user import UserAccounts, UserAccount - from lib389.idm.directorymanager import DirectoryManager - from lib389.dbgen import * - from lib389.utils import * -@@ -92,7 +93,203 @@ class AddDelUsers(threading.Thread): - return self._ran - - --def test_replay_import_operation(topo): -+def get_backend_by_name(inst, bename): -+ bes = Backends(inst) -+ bename = bename.lower() -+ be = [ be for be in bes if be.get_attr_val_utf8_l('cn') == bename ] -+ return be[0] if len(be) == 1 else None -+ -+ -+class LogHandler(): -+ def __init__(self, logfd, patterns): -+ self.logfd = logfd -+ self.patterns = [ p.lower() for p in patterns ] -+ self.pos = logfd.tell() -+ self.last_result = None -+ -+ def zero(self): -+ return [0 for _ in range(len(self.patterns))] -+ -+ def countCaptures(self): -+ res = self.zero() -+ self.logfd.seek(self.pos) -+ for line in iter(self.logfd.readline, ''): -+ # Ignore autotune messages that may confuse the counts -+ if 'bdb_start_autotune' in line: -+ continue -+ # Ignore LMDB size warnings that may confuse the counts -+ if 'dbmdb_ctx_t_db_max_size_set' in line: -+ continue -+ log.info(f'ERROR LOG line is {line.strip()}') -+ for idx,pattern in enumerate(self.patterns): -+ if pattern in line.lower(): -+ res[idx] += 1 -+ self.pos = self.logfd.tell() -+ self.last_result = res -+ log.info(f'ERROR LOG counts are: {res}') -+ return res -+ -+ def seek2end(self): -+ self.pos = os.fstat(self.logfd.fileno()).st_size -+ -+ def check(self, idx, val): -+ count = self.last_result[idx] -+ assert count == val , f"Should have {val} '{self.patterns[idx]}' messages but got: {count} - idx = {idx}" -+ -+ -+class IEHandler(ABC): -+ def __init__(self, inst, errlog, ldifname, bename=DEFAULT_BENAME, suffix=None): -+ self.inst = inst -+ self.errlog = errlog -+ self.ldifname = ldifname -+ self.bename = bename -+ self.suffix = suffix -+ self.ldif = ldifname if ldifname.startswith('/') else f'{inst.get_ldif_dir()}/{ldifname}.ldif' -+ -+ @abstractmethod -+ def get_name(self): -+ pass -+ -+ @abstractmethod -+ def _run_task_b(self): -+ pass -+ -+ @abstractmethod -+ def _run_task_s(self): -+ pass -+ -+ @abstractmethod -+ def _run_offline(self): -+ pass -+ -+ @abstractmethod -+ def _set_log_pattern(self, success): -+ pass -+ -+ def run(self, extra_checks, success=True): -+ if self.errlog: -+ self._set_log_pattern(success) -+ self.errlog.seek2end() -+ -+ if self.inst.status(): -+ if self.bename: -+ log.info(f"Performing online {self.get_name()} of backend {self.bename} into LDIF file {self.ldif}") -+ r = self._run_task_b() -+ else: -+ log.info(f"Performing online {self.get_name()} of suffix {self.suffix} into LDIF file {self.ldif}") -+ r = self._run_task_s() -+ r.wait() -+ time.sleep(1) -+ else: -+ if self.bename: -+ log.info(f"Performing offline {self.get_name()} of backend {self.bename} into LDIF file {self.ldif}") -+ else: -+ log.info(f"Performing offline {self.get_name()} of suffix {self.suffix} into LDIF file {self.ldif}") -+ self._run_offline() -+ if self.errlog: -+ expected_counts = ['*' for _ in range(len(self.errlog.patterns))] -+ for (idx, val) in extra_checks: -+ expected_counts[idx] = val -+ res = self.errlog.countCaptures() -+ log.info(f'Expected errorlog counts are: {expected_counts}') -+ if success is True or success is False: -+ log.info(f'Number of {self.errlog.patterns[0]} in errorlog is: {res[0]}') -+ assert res[0] >= 1 -+ for (idx, val) in extra_checks: -+ self.errlog.check(idx, val) -+ -+ def check_db(self): -+ assert self.inst.dbscan(bename=self.bename, index='id2entry') -+ -+ -+class Importer(IEHandler): -+ def get_name(self): -+ return "import" -+ -+ def _set_log_pattern(self, success): -+ if success is True: -+ self.errlog.patterns[0] = 'import complete' -+ elif success is False: -+ self.errlog.patterns[0] = 'import failed' -+ -+ def _run_task_b(self): -+ bes = Backends(self.inst) -+ r = bes.import_ldif(self.bename, [self.ldif,], include_suffixes=self.suffix) -+ return r -+ -+ def _run_task_s(self): -+ r = ImportTask(self.inst) -+ r.import_suffix_from_ldif(self.ldif, self.suffix) -+ return r -+ -+ def _run_offline(self): -+ log.info(f'self.inst.ldif2db({self.bename}, {self.suffix}, ...)') -+ if self.suffix is None: -+ self.inst.ldif2db(self.bename, self.suffix, None, False, self.ldif) -+ else: -+ self.inst.ldif2db(self.bename, [self.suffix, ], None, False, self.ldif) -+ -+ -+class Exporter(IEHandler): -+ def get_name(self): -+ return "export" -+ -+ def _set_log_pattern(self, success): -+ if success is True: -+ self.errlog.patterns[0] = 'export finished' -+ elif success is False: -+ self.errlog.patterns[0] = 'export failed' -+ -+ def _run_task_b(self): -+ bes = Backends(self.inst) -+ r = bes.export_ldif(self.bename, self.ldif, include_suffixes=self.suffix) -+ return r -+ -+ def _run_task_s(self): -+ r = ExportTask(self.inst) -+ r.export_suffix_to_ldif(self.ldif, self.suffix) -+ return r -+ -+ def _run_offline(self): -+ self.inst.db2ldif(self.bename, self.suffix, None, False, False, self.ldif) -+ -+ -+def preserve_func(topo, request, restart): -+ # Ensure that topology get preserved helper -+ inst = topo.standalone -+ -+ def fin(): -+ if restart: -+ inst.restart() -+ Importer(inst, None, "save").run(()) -+ -+ r = Exporter(inst, None, "save") -+ if not os.path.isfile(r.ldif): -+ r.run(()) -+ request.addfinalizer(fin) -+ -+ -+@pytest.fixture(scope="function") -+def preserve(topo, request): -+ # Ensure that topology get preserved (no restart) -+ preserve_func(topo, request, False) -+ -+ -+@pytest.fixture(scope="function") -+def preserve_r(topo, request): -+ # Ensure that topology get preserved (with restart) -+ preserve_func(topo, request, True) -+ -+ -+@pytest.fixture(scope="function") -+def verify(topo): -+ # Check that backend is not broken -+ inst = topo.standalone -+ dn=f'uid=demo_user,ou=people,{DEFAULT_SUFFIX}' -+ assert UserAccount(inst,dn).exists() -+ -+ -+def test_replay_import_operation(topo, preserve_r, verify): - """ Check after certain failed import operation, is it - possible to replay an import operation - -@@ -487,7 +684,190 @@ def test_ldif2db_after_backend_create(topo): - import_time_2 = create_backend_and_import(instance, ldif_file_2, 'o=test_2', 'test_2') - - log.info('Import times should be approximately the same') -- assert abs(import_time_1 - import_time_2) < 5 -+ assert abs(import_time_1 - import_time_2) < 15 -+ -+ -+def test_ldif_missing_suffix_entry(topo, request, verify): -+ """Test that ldif2db/import aborts if suffix entry is not in the ldif -+ -+ :id: 731bd0d6-8cc8-11f0-8ef2-c85309d5c3e3 -+ :setup: Standalone Instance -+ :steps: -+ 1. Prepare final cleanup -+ 2. Add a few users -+ 3. Export ou=people subtree -+ 4. Online import using backend name ou=people subtree -+ 5. Online import using suffix name ou=people subtree -+ 6. Stop the instance -+ 7. Offline import using backend name ou=people subtree -+ 8. Offline import using suffix name ou=people subtree -+ 9. Generate ldif with a far away suffix -+ 10. Offline import using backend name and "far" ldif -+ 11. Offline import using suffix name and "far" ldif -+ 12. Start the instance -+ 13. Online import using backend name and "far" ldif -+ 14. Online import using suffix name and "far" ldif -+ :expectedresults: -+ 1. Operation successful -+ 2. Operation successful -+ 3. Operation successful -+ 4. Import should success, skip all entries, db should exists -+ 5. Import should success, skip all entries, db should exists -+ 6. Operation successful -+ 7. Import should success, skip all entries, db should exists -+ 8. Import should success, skip all entries, db should exists -+ 9. Operation successful -+ 10. Import should success, skip all entries, db should exists -+ 11. Import should success, 10 entries skipped, db should exists -+ 12. Operation successful -+ 13. Import should success, skip all entries, db should exists -+ 14. Import should success, 10 entries skipped, db should exists -+ """ -+ -+ inst = topo.standalone -+ inst.config.set('nsslapd-errorlog-level', '266354688') -+ no_suffix_on = ( -+ (1, 0), # no errors are expected. -+ (2, 1), # 1 warning is expected. -+ (3, 0), # no 'no parent' warning is expected. -+ (4, 1), # 1 'all entries were skipped' warning -+ (5, 0), # no 'returning task warning' info message -+ ) -+ no_suffix_off = ( -+ (1, 0), # no errors are expected. -+ (2, 1), # 1 warning is expected. -+ (3, 0), # no 'no parent' warning is expected. -+ (4, 1), # 1 'all entries were skipped' warning -+ (5, 1), # 1 'returning task warning' info message -+ ) -+ -+ far_suffix_on = ( -+ (1, 0), # no errors are expected. -+ (2, 1), # 1 warning (consolidated, pre-check aborts after 4 entries) -+ (3, 0), # 0 'no parent' warnings (pre-check aborts before processing) -+ (4, 1), # 1 'all entries were skipped' warning (from pre-check) -+ (5, 0), # 0 'returning task warning' info message (online import) -+ ) -+ # Backend-specific behavior for orphan detection when suffix parameter is provided -+ nbw = 0 if get_default_db_lib() == "bdb" else 10 -+ far_suffix_with_suffix_on = ( -+ (1, 0), # no errors are expected. -+ (2, nbw), # 0 (BDB early filtering) or 10 (LMDB orphan detection) warnings -+ (3, nbw), # 0 (BDB early filtering) or 10 (LMDB orphan detection) 'no parent' warnings -+ (4, 0), # 0 'all entries were skipped' warning (no pre-check abort) -+ (5, 0), # 0 'returning task warning' info message (online import) -+ ) -+ far_suffix_off = ( -+ (1, 0), # no errors are expected. -+ (2, 1), # 1 warning (consolidated, pre-check detects missing suffix) -+ (3, 0), # 0 'no parent' warnings (pre-check aborts before processing) -+ (4, 1), # 1 'all entries were skipped' warning (from pre-check) -+ (5, 1), # 1 'returning task warning' info message (offline import) -+ ) -+ far_suffix_with_suffix_off = ( -+ (1, 0), # no errors are expected. -+ (2, nbw), # 0 (BDB early filtering) or 10 (LMDB orphan detection) warnings -+ (3, nbw), # 0 (BDB early filtering) or 10 (LMDB orphan detection) 'no parent' warnings -+ (4, 0), # 0 'all entries were skipped' warning (no pre-check abort) -+ (5, 0), # 0 'returning task warning' (rc=0, successful import of suffix) -+ ) -+ -+ with open(inst.ds_paths.error_log, 'at+') as fd: -+ patterns = ( -+ "Reserved for IEHandler", -+ " ERR ", -+ " WARN ", -+ "has no parent", -+ "all entries were skipped", -+ "returning task warning", -+ ) -+ errlog = LogHandler(fd, patterns) -+ no_errors = ((1, 0), (2, 0)) # no errors nor warnings are expected. -+ -+ -+ # 1. Prepare final cleanup -+ Exporter(inst, errlog, "full").run(no_errors) -+ -+ def fin(): -+ inst.start() -+ with open(inst.ds_paths.error_log, 'at+') as cleanup_fd: -+ cleanup_errlog = LogHandler(cleanup_fd, patterns) -+ Importer(inst, cleanup_errlog, "full").run(no_errors) -+ -+ if not DEBUGGING: -+ request.addfinalizer(fin) -+ -+ # 2. Add a few users -+ user = UserAccounts(inst, DEFAULT_SUFFIX) -+ users = [ user.create_test_user(uid=i) for i in range(10) ] -+ -+ # 3. Export ou=people subtree -+ e = Exporter(inst, errlog, "people", suffix=f'ou=people,{DEFAULT_SUFFIX}') -+ e.run(no_errors) # no errors nor warnings are expected. -+ -+ # 4. Online import using backend name ou=people subtree -+ e = Importer(inst, errlog, "people") -+ e.run(no_suffix_on) -+ e.check_db() -+ -+ # 5. Online import using suffix name ou=people subtree -+ e = Importer(inst, errlog, "people", suffix=DEFAULT_SUFFIX) -+ e.run(no_suffix_on) -+ e.check_db() -+ -+ # 6. Stop the instance -+ inst.stop() -+ -+ # 7. Offline import using backend name ou=people subtree -+ e = Importer(inst, errlog, "people") -+ e.run(no_suffix_off) -+ e.check_db() -+ -+ # 8. Offline import using suffix name ou=people subtree -+ e = Importer(inst, errlog, "people", suffix=DEFAULT_SUFFIX) -+ e.run(no_suffix_off) -+ e.check_db() -+ -+ # 9. Generate ldif with a far away suffix -+ e = Importer(inst, errlog, "full") -+ people_ldif = e.ldif -+ e = Importer(inst, errlog, "far") -+ with open(e.ldif, "wt") as fout: -+ with open(people_ldif, "rt") as fin: -+ # Copy version -+ line = fin.readline() -+ fout.write(line) -+ line = fin.readline() -+ fout.write(line) -+ # Generate fake entries -+ for idx in range(10): -+ fout.write(f"dn: uid=id{idx},dc=foo\nobjectclasses: extensibleObject\n\n") -+ for line in iter(fin.readline, ''): -+ fout.write(line) -+ -+ os.chmod(e.ldif, 0o644) -+ -+ # 10. Offline import using backend name ou=people subtree -+ e.run(far_suffix_off) -+ e.check_db() -+ -+ # 11. Offline import using suffix name ou=people subtree -+ e = Importer(inst, errlog, "far", suffix=DEFAULT_SUFFIX) -+ e.run(far_suffix_with_suffix_off) -+ e.check_db() -+ -+ # 12. Start the instance -+ inst.start() -+ -+ # 13. Online import using backend name ou=people subtree -+ e = Importer(inst, errlog, "far") -+ e.run(far_suffix_on) -+ e.check_db() -+ -+ # 14. Online import using suffix name ou=people subtree -+ e = Importer(inst, errlog, "far", suffix=DEFAULT_SUFFIX) -+ e.run(far_suffix_with_suffix_on) -+ e.check_db() - - - if __name__ == '__main__': -diff --git a/dirsrvtests/tests/suites/memberof_plugin/fixup_test.py b/dirsrvtests/tests/suites/memberof_plugin/fixup_test.py -index 5aac40d2b..44804bd1c 100644 ---- a/dirsrvtests/tests/suites/memberof_plugin/fixup_test.py -+++ b/dirsrvtests/tests/suites/memberof_plugin/fixup_test.py -@@ -44,7 +44,10 @@ def test_fixup_task_limit(topo): - group = groups.create(properties={'cn': 'test'}) - - users = UserAccounts(topo.standalone, DEFAULT_SUFFIX) -- for idx in range(400): -+ # Turn on access log buffering to speed up user creation -+ buffering = topo.standalone.config.get_attr_val_utf8('nsslapd-accesslog-logbuffering') -+ topo.standalone.config.set('nsslapd-accesslog-logbuffering', 'on') -+ for idx in range(6000): - user = users.create(properties={ - 'uid': 'testuser%s' % idx, - 'cn' : 'testuser%s' % idx, -@@ -55,6 +58,9 @@ def test_fixup_task_limit(topo): - }) - group.add('member', user.dn) - -+ # Restore access log buffering -+ topo.standalone.config.set('nsslapd-accesslog-logbuffering', buffering) -+ - # Configure memberOf plugin - memberof = MemberOfPlugin(topo.standalone) - memberof.enable() -diff --git a/dirsrvtests/tests/suites/plugins/attruniq_test.py b/dirsrvtests/tests/suites/plugins/attruniq_test.py -index 6eaee08a4..a2be413c8 100644 ---- a/dirsrvtests/tests/suites/plugins/attruniq_test.py -+++ b/dirsrvtests/tests/suites/plugins/attruniq_test.py -@@ -84,14 +84,23 @@ def containers(topology_st, request): - def attruniq(topology_st, request): - log.info('Setup attribute uniqueness plugin') - attruniq = AttributeUniquenessPlugin(topology_st.standalone, dn="cn=attruniq,cn=plugins,cn=config") -- attruniq.create(properties={'cn': 'attruniq'}) -- attruniq.add_unique_attribute('cn') -+ -+ if attruniq.exists(): -+ attruniq.delete() -+ topology_st.standalone.restart() -+ -+ attruniq.create(properties={ -+ 'cn': 'attruniq', -+ 'uniqueness-attribute-name': 'cn', -+ 'uniqueness-subtrees': 'cn=config', -+ 'nsslapd-pluginEnabled': 'on' -+ }) - topology_st.standalone.restart() - - def fin(): - if attruniq.exists(): -- attruniq.disable() - attruniq.delete() -+ topology_st.standalone.restart() - - request.addfinalizer(fin) - -@@ -250,8 +259,8 @@ def test_modrdn_attr_uniqueness(topology_st, attruniq): - group1 = groups.create(properties={'cn': 'group1'}) - group2 = groups.create(properties={'cn': 'group2'}) - -- attruniq.add_unique_attribute('mail') -- attruniq.add_unique_subtree(group2.dn) -+ attruniq.replace('uniqueness-attribute-name', 'mail') -+ attruniq.replace('uniqueness-subtrees', group2.dn) - attruniq.enable_all_subtrees() - log.debug(f'Enable PLUGIN_ATTR_UNIQUENESS plugin as "ON"') - attruniq.enable() -@@ -274,9 +283,6 @@ def test_modrdn_attr_uniqueness(topology_st, attruniq): - assert 'attribute value already exist' in str(excinfo.value) - log.debug(excinfo.value) - -- log.debug('Move user2 to group1') -- user2.rename(f'uid={user2.rdn}', group1.dn) -- - user1.delete() - user2.delete() - -@@ -302,17 +308,11 @@ def test_multiple_attr_uniqueness(topology_st, attruniq): - 6. Should raise CONSTRAINT_VIOLATION - """ - -- try: -- attruniq.add_unique_attribute('mail') -- attruniq.add_unique_attribute('mailAlternateAddress') -- attruniq.add_unique_subtree(DEFAULT_SUFFIX) -- attruniq.enable_all_subtrees() -- log.debug(f'Enable PLUGIN_ATTR_UNIQUENESS plugin as "ON"') -- attruniq.enable() -- except ldap.LDAPError as e: -- log.fatal('test_multiple_attribute_uniqueness: Failed to configure plugin for "mail": error {}'.format(e.args[0]['desc'])) -- assert False -- -+ attruniq.replace('uniqueness-attribute-name', ['mail', 'mailAlternateAddress']) -+ attruniq.replace('uniqueness-subtrees', DEFAULT_SUFFIX) -+ attruniq.enable_all_subtrees() -+ log.debug(f'Enable PLUGIN_ATTR_UNIQUENESS plugin as "ON"') -+ attruniq.enable() - topology_st.standalone.restart() - - users = UserAccounts(topology_st.standalone, DEFAULT_SUFFIX) -@@ -383,8 +383,9 @@ def test_exclude_subtrees(topology_st, attruniq): - 16. Success - 17. Success - """ -- attruniq.add_unique_attribute('telephonenumber') -- attruniq.add_unique_subtree(DEFAULT_SUFFIX) -+ # Replace dummy config with actual test config -+ attruniq.replace('uniqueness-attribute-name', 'telephonenumber') -+ attruniq.replace('uniqueness-subtrees', DEFAULT_SUFFIX) - attruniq.enable_all_subtrees() - attruniq.enable() - topology_st.standalone.restart() -@@ -517,10 +518,18 @@ def test_matchingrule_attr(topology_st): - """ - - inst = topology_st.standalone -- - attruniq = AttributeUniquenessPlugin(inst, - dn="cn=attribute uniqueness,cn=plugins,cn=config") -- attruniq.add_unique_attribute('cn:CaseExactMatch:') -+ -+ if attruniq.exists(): -+ attruniq.delete() -+ inst.restart() -+ -+ attruniq.create(properties={ -+ 'cn': 'attribute uniqueness', -+ 'uniqueness-attribute-name': 'cn:CaseExactMatch:', -+ 'uniqueness-subtrees': DEFAULT_SUFFIX -+ }) - attruniq.enable_all_subtrees() - attruniq.enable() - inst.restart() -@@ -595,7 +604,7 @@ def test_one_container_add(topology_st, attruniq, containers, active_user_1): - active_2.delete() - - log.info('Setup attribute uniqueness plugin for "cn" attribute') -- attruniq.add_unique_subtree(ACTIVE_DN) -+ attruniq.replace('uniqueness-subtrees', ACTIVE_DN) - attruniq.enable() - topology_st.standalone.restart() - -@@ -628,7 +637,7 @@ def test_one_container_mod(topology_st, attruniq, containers, - """ - - log.info('Setup attribute uniqueness plugin for "cn" attribute') -- attruniq.add_unique_subtree(ACTIVE_DN) -+ attruniq.replace('uniqueness-subtrees', ACTIVE_DN) - attruniq.enable() - topology_st.standalone.restart() - -@@ -656,7 +665,7 @@ def test_one_container_modrdn(topology_st, attruniq, containers, - """ - - log.info('Setup attribute uniqueness plugin for "cn" attribute') -- attruniq.add_unique_subtree(ACTIVE_DN) -+ attruniq.replace('uniqueness-subtrees', ACTIVE_DN) - attruniq.enable() - topology_st.standalone.restart() - -@@ -690,8 +699,7 @@ def test_multiple_containers_add(topology_st, attruniq, containers, - """ - - log.info('Setup attribute uniqueness plugin for "cn" attribute') -- attruniq.add_unique_subtree(ACTIVE_DN) -- attruniq.add_unique_subtree(STAGE_DN) -+ attruniq.replace('uniqueness-subtrees', [ACTIVE_DN, STAGE_DN]) - attruniq.enable() - topology_st.standalone.restart() - -@@ -789,8 +797,7 @@ def test_multiple_containers_mod(topology_st, attruniq, containers, - """ - - log.info('Setup attribute uniqueness plugin for "cn" attribute') -- attruniq.add_unique_subtree(ACTIVE_DN) -- attruniq.add_unique_subtree(STAGE_DN) -+ attruniq.replace('uniqueness-subtrees', [ACTIVE_DN, STAGE_DN]) - attruniq.enable() - topology_st.standalone.restart() - -@@ -874,8 +881,8 @@ def test_multiple_containers_modrdn(topology_st, attruniq, containers, - """ - - log.info('Setup attribute uniqueness plugin for "cn" attribute') -- attruniq.add_unique_subtree(ACTIVE_DN) -- attruniq.add_unique_subtree(STAGE_DN) -+ # Replace dummy subtree with actual test subtrees -+ attruniq.replace('uniqueness-subtrees', [ACTIVE_DN, STAGE_DN]) - attruniq.enable() - topology_st.standalone.restart() - -@@ -993,7 +1000,10 @@ def test_invalid_config_missing_attr_name(topology_st): - _config_file(topology_st, action='save') - - attruniq = AttributeUniquenessPlugin(topology_st.standalone, dn="cn=attruniq,cn=plugins,cn=config") -- attruniq.create(properties={'cn': 'attruniq'}) -+ attruniq.create(properties={ -+ 'cn': 'attruniq', -+ 'uniqueness-subtrees': DEFAULT_SUFFIX -+ }) - attruniq.enable() - - topology_st.standalone.errorlog_file = open(topology_st.standalone.errlog, "r") -@@ -1040,9 +1050,11 @@ def test_invalid_config_invalid_subtree(topology_st): - _config_file(topology_st, action='save') - - attruniq = AttributeUniquenessPlugin(topology_st.standalone, dn="cn=attruniq,cn=plugins,cn=config") -- attruniq.create(properties={'cn': 'attruniq'}) -- attruniq.add_unique_attribute('cn') -- attruniq.add_unique_subtree('invalid_subtree') -+ attruniq.create(properties={ -+ 'cn': 'attruniq', -+ 'uniqueness-attribute-name': 'cn', -+ 'uniqueness-subtrees': 'invalid_subtree' -+ }) - attruniq.enable() - - topology_st.standalone.errorlog_file = open(topology_st.standalone.errlog, "r") -diff --git a/dirsrvtests/tests/suites/replication/regression_m2_test.py b/dirsrvtests/tests/suites/replication/regression_m2_test.py -index ba1ffcc9c..db5140b0b 100644 ---- a/dirsrvtests/tests/suites/replication/regression_m2_test.py -+++ b/dirsrvtests/tests/suites/replication/regression_m2_test.py -@@ -1221,6 +1221,10 @@ def test_rid_starting_with_0(topo_m2, request): - for replica,rid in zip(replicas, ['010', '020']): - replica.replace('nsDS5ReplicaId', rid) - -+ # Restart required - replica IDs are loaded at startup and cached in memory -+ S1.restart() -+ S2.restart() -+ - # Restore replica id in finalizer - def fin(): - for replica,rid in zip(replicas, ['1', '2']): -diff --git a/dirsrvtests/tests/suites/replication/repl_log_monitoring_test.py b/dirsrvtests/tests/suites/replication/repl_log_monitoring_test.py -index 665fcb96f..b2b2d25a2 100644 ---- a/dirsrvtests/tests/suites/replication/repl_log_monitoring_test.py -+++ b/dirsrvtests/tests/suites/replication/repl_log_monitoring_test.py -@@ -369,11 +369,13 @@ def test_replication_log_monitoring_multi_suffix(topo_m4): - repl.ensure_agreement(s1, s2) - repl.ensure_agreement(s2, s1) - -- # Allow initial topology to settle before capturing metrics -+ # Wait for all the setup replication to settle, then clear the logs - for suffix in all_suffixes: - repl = ReplicationManager(suffix) -- repl.test_replication_topology(topo_m4) -- -+ for s1 in suppliers: -+ for s2 in suppliers: -+ if s1 != s2: -+ repl.wait_for_replication(s1, s2) - for supplier in suppliers: - supplier.deleteAccessLogs(restart=True) - -diff --git a/dirsrvtests/tests/suites/webui/database/database_test.py b/dirsrvtests/tests/suites/webui/database/database_test.py -index ef105d262..05ddb6b00 100644 ---- a/dirsrvtests/tests/suites/webui/database/database_test.py -+++ b/dirsrvtests/tests/suites/webui/database/database_test.py -@@ -138,6 +138,7 @@ def test_chaining_configuration_availability(topology_st, page, browser_name): - log.info('Click on Chaining Configuration and check if element is loaded.') - frame.get_by_role('tab', name='Database', exact=True).click() - frame.locator('#chaining-config').click() -+ frame.locator('#chaining-page').wait_for() - frame.locator('#defSizeLimit').wait_for() - assert frame.locator('#defSizeLimit').is_visible() - -diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c -index e3b7e5783..b1a29ff7f 100644 ---- a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c -+++ b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c -@@ -1080,7 +1080,9 @@ ldbm_back_modrdn(Slapi_PBlock *pb) - } - } - } -- if (slapi_sdn_get_dn(dn_newsuperiordn) != NULL) { -+ /* Only update parent if we're actually moving to a NEW parent (not the same parent) */ -+ if (slapi_sdn_get_dn(dn_newsuperiordn) != NULL && -+ slapi_sdn_compare(dn_newsuperiordn, &dn_parentdn) != 0) { - /* Push out the db modifications from the parent entry */ - retval = modify_update_all(be, pb, &parent_modify_context, &txn); - if (DBI_RC_RETRY == retval) { -@@ -1335,11 +1337,6 @@ ldbm_back_modrdn(Slapi_PBlock *pb) - goto common_return; - - error_return: -- /* Revert the caches if this is the parent operation */ -- if (parent_op && betxn_callback_fails) { -- revert_cache(inst, &parent_time); -- } -- - /* result already sent above - just free stuff */ - if (postentry) { - slapi_entry_free(postentry); -@@ -1417,13 +1414,6 @@ error_return: - slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, ldap_result_code ? &ldap_result_code : &retval); - } - slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message); -- -- /* As it is a BETXN plugin failure then -- * revert the caches if this is the parent operation -- */ -- if (parent_op) { -- revert_cache(inst, &parent_time); -- } - } - retval = plugin_call_mmr_plugin_postop(pb, NULL,SLAPI_PLUGIN_BE_TXN_POST_MODRDN_FN); - -@@ -1437,6 +1427,15 @@ error_return: - } - } - -+ /* Revert the caches if this is the parent operation and cache modifications were made. -+ * Cache modifications (via modify_switch_entries) only happen after BETXN PRE plugins succeed, -+ * so we should only revert if we got past that point (i.e., BETXN POST plugin failures). -+ * For BETXN PRE failures, no cache modifications were made to parent/newparent entries. -+ */ -+ if (parent_op && betxn_callback_fails && postentry) { -+ revert_cache(inst, &parent_time); -+ } -+ - common_return: - - /* result code could be used in the bepost plugin functions. */ -@@ -1482,12 +1481,22 @@ common_return: - "operation failed, the target entry is cleared from dncache (%s)\n", slapi_entry_get_dn(ec->ep_entry)); - CACHE_REMOVE(&inst->inst_dncache, bdn); - CACHE_RETURN(&inst->inst_dncache, &bdn); -+ -+ /* Also remove ec from entry cache and free it since the operation failed */ -+ if (inst && cache_is_in_cache(&inst->inst_cache, ec)) { -+ CACHE_REMOVE(&inst->inst_cache, ec); -+ CACHE_RETURN(&inst->inst_cache, &ec); -+ } else { -+ /* ec was not in cache, just free it */ -+ backentry_free(&ec); -+ } -+ ec = NULL; - } - - if (ec && inst) { - CACHE_RETURN(&inst->inst_cache, &ec); -+ ec = NULL; - } -- ec = NULL; - } - - if (inst) { -@@ -1817,6 +1826,8 @@ moddn_get_newdn(Slapi_PBlock *pb, Slapi_DN *dn_olddn, Slapi_DN *dn_newrdn, Slapi - - /* - * Return the entries to the cache. -+ * For the original entry 'e', we should NOT remove it from cache on failure, -+ * as it's still a valid entry in the directory. - */ - static void - moddn_unlock_and_return_entry( -@@ -1825,12 +1836,9 @@ moddn_unlock_and_return_entry( - { - ldbm_instance *inst = (ldbm_instance *)be->be_instance_info; - -- /* Something bad happened so we should give back all the entries */ -+ /* Unlock and return the entry to the cache */ - 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.52.0 - diff --git a/0019-Issue-7076-Fix-revert_cache-never-called-in-modrdn-7.patch b/0019-Issue-7076-Fix-revert_cache-never-called-in-modrdn-7.patch deleted file mode 100644 index 9036d72..0000000 --- a/0019-Issue-7076-Fix-revert_cache-never-called-in-modrdn-7.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 04a0f5560ea741972b9c264af23b377893ab7133 Mon Sep 17 00:00:00 2001 -From: Akshay Adhikari -Date: Thu, 5 Feb 2026 15:41:09 +0530 -Subject: [PATCH] Issue 7076 - Fix revert_cache() never called in modrdn - (#7220) - -Description: The postentry check in PR #7077 was broken - postentry is always NULL -at that point, fixed by removing the check. - -Relates: #7076 - -Reviewed by: @vashirov, @mreynolds389, @droideck (Thanks!) ---- - ldap/servers/slapd/back-ldbm/ldbm_modrdn.c | 12 +++++++----- - 1 file changed, 7 insertions(+), 5 deletions(-) - -diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c -index b1a29ff7f..36377fc01 100644 ---- a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c -+++ b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c -@@ -103,6 +103,7 @@ ldbm_back_modrdn(Slapi_PBlock *pb) - Connection *pb_conn = NULL; - int32_t parent_op = 0; - int32_t betxn_callback_fails = 0; /* if a BETXN fails we need to revert entry cache */ -+ int32_t cache_mod_phase = 0; /* set when we reach the cache modification phase */ - struct timespec parent_time; - Slapi_Mods *smods_add_rdn = NULL; - -@@ -1229,6 +1230,8 @@ ldbm_back_modrdn(Slapi_PBlock *pb) - goto error_return; - } - -+ /* We're now past the BETXN PRE phase and entering the cache modification phase */ -+ cache_mod_phase = 1; - postentry = slapi_entry_dup(ec->ep_entry); - - if (parententry != NULL) { -@@ -1427,12 +1430,11 @@ error_return: - } - } - -- /* Revert the caches if this is the parent operation and cache modifications were made. -- * Cache modifications (via modify_switch_entries) only happen after BETXN PRE plugins succeed, -- * so we should only revert if we got past that point (i.e., BETXN POST plugin failures). -- * For BETXN PRE failures, no cache modifications were made to parent/newparent entries. -+ /* Revert the caches if this is the parent operation AND we reached the -+ * cache modification phase. If BETXN PRE fails, cache_mod_phase is 0 -+ * and we don't need to revert since no cache modifications were made. - */ -- if (parent_op && betxn_callback_fails && postentry) { -+ if (parent_op && betxn_callback_fails && cache_mod_phase) { - revert_cache(inst, &parent_time); - } - --- -2.52.0 - diff --git a/0020-Issue-6947-Fix-health_system_indexes_test.py.patch b/0020-Issue-6947-Fix-health_system_indexes_test.py.patch deleted file mode 100644 index 6d15057..0000000 --- a/0020-Issue-6947-Fix-health_system_indexes_test.py.patch +++ /dev/null @@ -1,24 +0,0 @@ -From fb8acf6141b069e250be3821c1e70ee7ed448720 Mon Sep 17 00:00:00 2001 -From: Viktor Ashirov -Date: Wed, 11 Feb 2026 19:53:44 +0100 -Subject: [PATCH] Issue 6947 - Fix health_system_indexes_test.py - ---- - .../tests/suites/healthcheck/health_system_indexes_test.py | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py b/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py -index 4cd4d0c70..3b3651b38 100644 ---- a/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py -+++ b/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py -@@ -99,6 +99,7 @@ def run_healthcheck_and_flush_log(topology, instance, searched_code, json, searc - "memberof", - ] - args.dry_run = False -+ args.exclude_check = [] - - # If we are using BDB as a backend, we will get error DSBLE0006 on new versions - if ( --- -2.52.0 - diff --git a/0021-Issue-7121-2nd-LeakSanitizer-various-leaks-during-re.patch b/0021-Issue-7121-2nd-LeakSanitizer-various-leaks-during-re.patch deleted file mode 100644 index 777be86..0000000 --- a/0021-Issue-7121-2nd-LeakSanitizer-various-leaks-during-re.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 8761b28fd2f2cf3d2e2119bdf1b348bc7d2d1834 Mon Sep 17 00:00:00 2001 -From: Viktor Ashirov -Date: Mon, 9 Feb 2026 13:18:09 +0100 -Subject: [PATCH] Issue 7121 - (2nd) LeakSanitizer: various leaks during - replication (#7212) - -Bug Description: -With the previous fix 75e0e487545893a7b0d83f94f9264c10f8bb0353 applied, -server can crash in ber_bvcpy. - -``` -Program terminated with signal SIGSEGV, Segmentation fault. -#0 ber_bvcpy (bvs=0x7f1d00000000, bvd=0x7f1da2cd73c0) at ldap/servers/slapd/value.c:47 -47 len = bvs->bv_len; -[Current thread is 1 (Thread 0x7f1db47fe640 (LWP 36576))] -(gdb) bt -#0 ber_bvcpy (bvs=0x7f1d00000000, bvd=0x7f1da2cd73c0) at ldap/servers/slapd/value.c:47 -#1 ber_bvcpy (bvs=0x7f1d00000000, bvd=0x7f1da2cd73c0) at ldap/servers/slapd/value.c:40 -#2 slapi_value_set_berval (bval=0x7f1d00000000, value=0x7f1da2cd73c0) at ldap/servers/slapd/value.c:322 -#3 slapi_value_set_berval (value=value@entry=0x7f1da2cd73c0, bval=bval@entry=0x7f1d00000000) at ldap/servers/slapd/value.c:317 -#4 0x00007f1e48b7d787 in value_init (v=v@entry=0x7f1da2cd73c0, bval=bval@entry=0x7f1d00000000, t=t@entry=0 '\000', csn=csn@entry=0x0) - at ldap/servers/slapd/value.c:179 -#5 0x00007f1e48b7d884 in value_new (bval=bval@entry=0x7f1d00000000, t=t@entry=0 '\000', csn=csn@entry=0x0) at ldap/servers/slapd/value.c:158 -#6 0x00007f1e48b7ddb7 in slapi_value_dup (v=0x7f1d00000000) at ldap/servers/slapd/value.c:147 -#7 0x00007f1e48b7e262 in valueset_set_valueset (vs2=0x7f1d502b5218, vs1=0x7f1da2c5b358) at ldap/servers/slapd/valueset.c:1244 -#8 valueset_set_valueset (vs1=0x7f1da2c5b358, vs2=0x7f1d502b5218) at ldap/servers/slapd/valueset.c:1220 -#9 0x00007f1e48add4af in slapi_attr_dup (attr=0x7f1d502b51e0) at ldap/servers/slapd/attr.c:396 -#10 0x00007f1e48af0f60 in slapi_entry_dup (e=0x7f1da2c19000) at ldap/servers/slapd/entry.c:2036 -#11 0x00007f1e442c734e in ldbm_back_modify (pb=0x7f1da2c00000) at ldap/servers/slapd/back-ldbm/ldbm_modify.c:741 -#12 0x00007f1e48b30076 in op_shared_modify (pb=pb@entry=0x7f1da2c00000, pw_change=pw_change@entry=0, old_pw=0x0) - at ldap/servers/slapd/modify.c:1079 -#13 0x00007f1e48b30ced in do_modify (pb=pb@entry=0x7f1da2c00000) at ldap/servers/slapd/modify.c:377 -#14 0x000055e990e2fd1c in connection_dispatch_operation (pb=0x7f1da2c00000, op=, conn=) - at ldap/servers/slapd/connection.c:672 -#15 connection_threadmain (arg=) at ldap/servers/slapd/connection.c:1955 -#16 0x00007f1e48839bd4 in _pt_root (arg=0x7f1e439d9500) at pthreads/../../../../nspr/pr/src/pthreads/ptthread.c:191 -#17 0x00007f1e4868a19a in start_thread (arg=) at pthread_create.c:443 -#18 0x00007f1e4870f100 in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81 -``` - -The fix changed from always setting `v_csnset = NULL` to only freeing it -inside the if-block. - -Fix Description: -Keep `csnset_free()` outside the if-block to handle all values, not just -those matching the condtion. - -Related: https://github.com/389ds/389-ds-base/issues/7121 - -Reviewed by: @progier389, @droideck (Thanks!) ---- - ldap/servers/slapd/entrywsi.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ldap/servers/slapd/entrywsi.c b/ldap/servers/slapd/entrywsi.c -index e1bdc1bab..0d044092d 100644 ---- a/ldap/servers/slapd/entrywsi.c -+++ b/ldap/servers/slapd/entrywsi.c -@@ -1185,8 +1185,8 @@ resolve_attribute_state_deleted_to_present(Slapi_Entry *e, Slapi_Attr *a, Slapi_ - if ((csn_compare(vucsn, deletedcsn) >= 0) || - value_distinguished_at_csn(e, a, valuestoupdate[i], deletedcsn)) { - entry_deleted_value_to_present_value(a, valuestoupdate[i]); -- csnset_free(&valuestoupdate[i]->v_csnset); - } -+ csnset_free(&valuestoupdate[i]->v_csnset); - } - } - } --- -2.52.0 - diff --git a/0022-Issue-7150-Compressed-access-log-rotations-skipped-a.patch b/0022-Issue-7150-Compressed-access-log-rotations-skipped-a.patch deleted file mode 100644 index 5f7b711..0000000 --- a/0022-Issue-7150-Compressed-access-log-rotations-skipped-a.patch +++ /dev/null @@ -1,551 +0,0 @@ -From 86b15d688949197a9efe3d5fc7a7eadcdd46e115 Mon Sep 17 00:00:00 2001 -From: Simon Pichugin -Date: Tue, 16 Dec 2025 15:48:35 -0800 -Subject: [PATCH] Issue 7150 - Compressed access log rotations skipped, - accesslog-list out of sync (#7151) - -Description: Accept `.gz`-suffixed rotated log filenames when -rebuilding rotation info and checking previous logs, preventing -compressed rotations from being dropped from the internal list. - -Add regression tests to stress log rotation with compression, -verify `nsslapd-accesslog-list` stays in sync, and guard against -crashes when flushing buffered logs during rotation. -Minor doc fix in test. - -Fixes: https://github.com/389ds/389-ds-base/issues/7150 - -Reviewed by: @progier389 (Thanks!) ---- - .../suites/logging/log_flush_rotation_test.py | 341 +++++++++++++++++- - ldap/servers/slapd/log.c | 99 +++-- - 2 files changed, 402 insertions(+), 38 deletions(-) - -diff --git a/dirsrvtests/tests/suites/logging/log_flush_rotation_test.py b/dirsrvtests/tests/suites/logging/log_flush_rotation_test.py -index b33a622e1..864ba9c5d 100644 ---- a/dirsrvtests/tests/suites/logging/log_flush_rotation_test.py -+++ b/dirsrvtests/tests/suites/logging/log_flush_rotation_test.py -@@ -6,6 +6,7 @@ - # See LICENSE for details. - # --- END COPYRIGHT BLOCK --- - # -+import glob - import os - import logging - import time -@@ -13,14 +14,351 @@ import pytest - from lib389._constants import DEFAULT_SUFFIX, PW_DM - from lib389.tasks import ImportTask - from lib389.idm.user import UserAccounts -+from lib389.idm.domain import Domain -+from lib389.idm.directorymanager import DirectoryManager - from lib389.topologies import topology_st as topo - - - log = logging.getLogger(__name__) - - -+def remove_rotated_access_logs(inst): -+ """ -+ Remove all rotated access log files to start fresh for each test. -+ This prevents log files from previous tests affecting current test results. -+ """ -+ log_dir = inst.get_log_dir() -+ patterns = [ -+ f'{log_dir}/access.2*', # Uncompressed rotated logs -+ f'{log_dir}/access.*.gz', # Compressed rotated logs -+ ] -+ for pattern in patterns: -+ for log_file in glob.glob(pattern): -+ try: -+ os.remove(log_file) -+ log.info(f"Removed old log file: {log_file}") -+ except OSError as e: -+ log.warning(f"Could not remove {log_file}: {e}") -+ -+ -+def reset_access_log_config(inst): -+ """ -+ Reset access log configuration to default values. -+ """ -+ inst.config.set('nsslapd-accesslog-compress', 'off') -+ inst.config.set('nsslapd-accesslog-maxlogsize', '100') -+ inst.config.set('nsslapd-accesslog-maxlogsperdir', '10') -+ inst.config.set('nsslapd-accesslog-logrotationsync-enabled', 'off') -+ inst.config.set('nsslapd-accesslog-logbuffering', 'on') -+ inst.config.set('nsslapd-accesslog-logexpirationtime', '-1') -+ inst.config.set('nsslapd-accesslog-logminfreediskspace', '5') -+ -+ -+def generate_heavy_load(inst, suffix, iterations=50): -+ """ -+ Generate heavy LDAP load to fill access log quickly. -+ Performs multiple operations: searches, modifies, binds to populate logs. -+ """ -+ for i in range(iterations): -+ suffix.replace('description', f'iteration_{i}') -+ suffix.get_attr_val('description') -+ -+ -+def count_access_logs(log_dir, compressed_only=False): -+ """ -+ Count access log files in the log directory. -+ Returns count of rotated access logs (not including the active 'access' file). -+ """ -+ if compressed_only: -+ pattern = f'{log_dir}/access.*.gz' -+ else: -+ pattern = f'{log_dir}/access.2*' -+ log_files = glob.glob(pattern) -+ return len(log_files) -+ -+ -+def test_log_pileup_with_compression(topo): -+ """Test that log rotation properly deletes old logs when compression is enabled. -+ -+ :id: fa1bfce8-b6d3-4520-a0a8-bead14fa5838 -+ :setup: Standalone Instance -+ :steps: -+ 1. Clean up existing rotated logs and reset configuration -+ 2. Enable access log compression -+ 3. Set strict log limits (small maxlogsperdir) -+ 4. Disable log expiration to test count-based deletion -+ 5. Generate heavy load to create many log rotations -+ 6. Verify log count does not exceed maxlogsperdir limit -+ :expectedresults: -+ 1. Success -+ 2. Success -+ 3. Success -+ 4. Success -+ 5. Success -+ 6. Log count should be at or below maxlogsperdir + small buffer -+ """ -+ -+ inst = topo.standalone -+ suffix = Domain(inst, DEFAULT_SUFFIX) -+ log_dir = inst.get_log_dir() -+ -+ # Clean up before test -+ remove_rotated_access_logs(inst) -+ reset_access_log_config(inst) -+ inst.restart() -+ -+ max_logs = 5 -+ inst.config.set('nsslapd-accesslog-compress', 'on') -+ inst.config.set('nsslapd-accesslog-maxlogsperdir', str(max_logs)) -+ inst.config.set('nsslapd-accesslog-maxlogsize', '1') # 1MB to trigger rotation -+ inst.config.set('nsslapd-accesslog-logrotationsync-enabled', 'off') -+ inst.config.set('nsslapd-accesslog-logbuffering', 'off') -+ -+ inst.config.set('nsslapd-accesslog-logexpirationtime', '-1') -+ -+ inst.config.set('nsslapd-accesslog-logminfreediskspace', '5') -+ -+ inst.restart() -+ time.sleep(2) -+ -+ target_logs = max_logs * 3 -+ for i in range(target_logs): -+ log.info(f"Generating load for log rotation {i+1}/{target_logs}") -+ generate_heavy_load(inst, suffix, iterations=150) -+ time.sleep(1) # Wait for rotation -+ -+ time.sleep(3) -+ -+ logs_on_disk = count_access_logs(log_dir) -+ log.info(f"Configured maxlogsperdir: {max_logs}") -+ log.info(f"Actual rotated logs on disk: {logs_on_disk}") -+ -+ all_access_logs = glob.glob(f'{log_dir}/access*') -+ log.info(f"All access log files: {all_access_logs}") -+ -+ max_allowed = max_logs + 2 -+ assert logs_on_disk <= max_allowed, ( -+ f"Log rotation failed to delete old files! " -+ f"Expected at most {max_allowed} rotated logs (maxlogsperdir={max_logs} + 2 buffer), " -+ f"but found {logs_on_disk}. The server has lost track of the file list." -+ ) -+ -+ -+@pytest.mark.parametrize("compress_enabled", ["on", "off"]) -+def test_accesslog_list_mismatch(topo, compress_enabled): -+ """Test that nsslapd-accesslog-list stays synchronized with actual log files. -+ -+ :id: 0a8a46a6-cae7-43bd-8b64-5e3481480cd3 -+ :parametrized: yes -+ :setup: Standalone Instance -+ :steps: -+ 1. Clean up existing rotated logs and reset configuration -+ 2. Configure log rotation with compression enabled/disabled -+ 3. Generate activity to trigger multiple rotations -+ 4. Get the nsslapd-accesslog-list attribute -+ 5. Compare with actual files on disk -+ 6. Verify they match (accounting for .gz extension when enabled) -+ :expectedresults: -+ 1. Success -+ 2. Success -+ 3. Success -+ 4. Success -+ 5. Success -+ 6. The list attribute should match actual files on disk -+ """ -+ -+ inst = topo.standalone -+ suffix = Domain(inst, DEFAULT_SUFFIX) -+ log_dir = inst.get_log_dir() -+ compression_on = compress_enabled == "on" -+ -+ # Clean up before test -+ remove_rotated_access_logs(inst) -+ reset_access_log_config(inst) -+ inst.restart() -+ -+ inst.config.set('nsslapd-accesslog-compress', compress_enabled) -+ inst.config.set('nsslapd-accesslog-maxlogsize', '1') -+ inst.config.set('nsslapd-accesslog-maxlogsperdir', '10') -+ inst.config.set('nsslapd-accesslog-logrotationsync-enabled', 'off') -+ inst.config.set('nsslapd-accesslog-logbuffering', 'off') -+ inst.config.set('nsslapd-accesslog-logexpirationtime', '-1') -+ -+ inst.restart() -+ time.sleep(2) -+ -+ for i in range(15): -+ suffix_note = "(no compression)" if not compression_on else "" -+ log.info(f"Generating load for rotation {i+1}/15 {suffix_note}") -+ generate_heavy_load(inst, suffix, iterations=150) -+ time.sleep(1) -+ -+ time.sleep(3) -+ -+ accesslog_list = inst.config.get_attr_vals_utf8('nsslapd-accesslog-list') -+ log.info(f"nsslapd-accesslog-list entries (compress={compress_enabled}): {len(accesslog_list)}") -+ log.info(f"nsslapd-accesslog-list (compress={compress_enabled}): {accesslog_list}") -+ -+ disk_files = glob.glob(f'{log_dir}/access.2*') -+ log.info(f"Actual files on disk (compress={compress_enabled}): {len(disk_files)}") -+ log.info(f"Disk files (compress={compress_enabled}): {disk_files}") -+ -+ disk_files_for_compare = set() -+ for fpath in disk_files: -+ if compression_on and fpath.endswith('.gz'): -+ disk_files_for_compare.add(fpath[:-3]) -+ else: -+ disk_files_for_compare.add(fpath) -+ -+ list_files_set = set(accesslog_list) -+ missing_from_disk = list_files_set - disk_files_for_compare -+ extra_on_disk = disk_files_for_compare - list_files_set -+ -+ if missing_from_disk: -+ log.error( -+ f"[compress={compress_enabled}] Files in list but NOT on disk: {missing_from_disk}" -+ ) -+ if extra_on_disk: -+ log.warning( -+ f"[compress={compress_enabled}] Files on disk but NOT in list: {extra_on_disk}" -+ ) -+ -+ assert not missing_from_disk, ( -+ f"nsslapd-accesslog-list mismatch (compress={compress_enabled})! " -+ f"Files listed but missing from disk: {missing_from_disk}. " -+ f"This indicates the server's internal list is out of sync with actual files." -+ ) -+ -+ if len(extra_on_disk) > 2: -+ log.warning( -+ f"Potential log tracking issue (compress={compress_enabled}): " -+ f"{len(extra_on_disk)} files on disk are not tracked in the accesslog-list: " -+ f"{extra_on_disk}" -+ ) -+ -+ -+def test_accesslog_list_mixed_compression(topo): -+ """Test that nsslapd-accesslog-list correctly tracks both compressed and uncompressed logs. -+ -+ :id: 11b088cd-23be-407d-ad16-4ce2e12da09e -+ :setup: Standalone Instance -+ :steps: -+ 1. Clean up existing rotated logs and reset configuration -+ 2. Create rotated logs with compression OFF -+ 3. Enable compression and create more rotated logs -+ 4. Get the nsslapd-accesslog-list attribute -+ 5. Compare with actual files on disk -+ 6. Verify all files are correctly tracked (uncompressed and compressed) -+ :expectedresults: -+ 1. Success -+ 2. Success - uncompressed rotated logs created -+ 3. Success - compressed rotated logs created -+ 4. Success -+ 5. Success -+ 6. The list should contain base filenames (without .gz) that -+ correspond to files on disk (either as-is or with .gz suffix) -+ """ -+ -+ inst = topo.standalone -+ suffix = Domain(inst, DEFAULT_SUFFIX) -+ log_dir = inst.get_log_dir() -+ -+ # Clean up before test -+ remove_rotated_access_logs(inst) -+ reset_access_log_config(inst) -+ inst.restart() -+ -+ inst.config.set('nsslapd-accesslog-compress', 'off') -+ inst.config.set('nsslapd-accesslog-maxlogsize', '1') -+ inst.config.set('nsslapd-accesslog-maxlogsperdir', '20') -+ inst.config.set('nsslapd-accesslog-logrotationsync-enabled', 'off') -+ inst.config.set('nsslapd-accesslog-logbuffering', 'off') -+ inst.config.set('nsslapd-accesslog-logexpirationtime', '-1') -+ -+ inst.restart() -+ time.sleep(2) -+ -+ for i in range(15): -+ log.info(f"Generating load for uncompressed rotation {i+1}/15") -+ generate_heavy_load(inst, suffix, iterations=150) -+ time.sleep(1) -+ -+ time.sleep(2) -+ -+ # Check what we have so far -+ uncompressed_files = glob.glob(f'{log_dir}/access.2*') -+ log.info(f"Files on disk after uncompressed phase: {uncompressed_files}") -+ -+ inst.config.set('nsslapd-accesslog-compress', 'on') -+ inst.restart() -+ time.sleep(2) -+ -+ for i in range(15): -+ log.info(f"Generating load for compressed rotation {i+1}/15") -+ generate_heavy_load(inst, suffix, iterations=150) -+ time.sleep(1) -+ -+ time.sleep(3) -+ -+ accesslog_list = inst.config.get_attr_vals_utf8('nsslapd-accesslog-list') -+ -+ disk_files = glob.glob(f'{log_dir}/access.2*') -+ -+ log.info(f"nsslapd-accesslog-list entries: {len(accesslog_list)}") -+ log.info(f"nsslapd-accesslog-list: {sorted(accesslog_list)}") -+ log.info(f"Actual files on disk: {len(disk_files)}") -+ log.info(f"Disk files: {sorted(disk_files)}") -+ -+ compressed_on_disk = [f for f in disk_files if f.endswith('.gz')] -+ uncompressed_on_disk = [f for f in disk_files if not f.endswith('.gz')] -+ log.info(f"Compressed files on disk: {compressed_on_disk}") -+ log.info(f"Uncompressed files on disk: {uncompressed_on_disk}") -+ -+ list_files_set = set(accesslog_list) -+ -+ disk_files_base = set() -+ for fpath in disk_files: -+ if fpath.endswith('.gz'): -+ disk_files_base.add(fpath[:-3]) # Strip .gz -+ else: -+ disk_files_base.add(fpath) -+ -+ missing_from_disk = list_files_set - disk_files_base -+ -+ extra_on_disk = disk_files_base - list_files_set -+ -+ if missing_from_disk: -+ log.error(f"Files in list but NOT on disk: {missing_from_disk}") -+ if extra_on_disk: -+ log.warning(f"Files on disk but NOT in list: {extra_on_disk}") -+ -+ assert not missing_from_disk, ( -+ f"nsslapd-accesslog-list contains stale entries! " -+ f"Files in list but not on disk (as base or .gz): {missing_from_disk}" -+ ) -+ -+ for list_file in accesslog_list: -+ exists_uncompressed = os.path.exists(list_file) -+ exists_compressed = os.path.exists(list_file + '.gz') -+ assert exists_uncompressed or exists_compressed, ( -+ f"File in accesslog-list does not exist on disk: {list_file} " -+ f"(checked both {list_file} and {list_file}.gz)" -+ ) -+ if exists_compressed and not exists_uncompressed: -+ log.info(f" {list_file} -> exists as .gz (compressed)") -+ elif exists_uncompressed: -+ log.info(f" {list_file} -> exists (uncompressed)") -+ -+ if len(extra_on_disk) > 1: -+ log.warning( -+ f"Some files on disk are not tracked in accesslog-list: {extra_on_disk}" -+ ) -+ -+ log.info("Mixed compression test completed successfully") -+ -+ - def test_log_flush_and_rotation_crash(topo): -- """Make sure server does not crash whening flushing a buffer and rotating -+ """Make sure server does not crash when flushing a buffer and rotating - the log at the same time - - :id: d4b0af2f-48b2-45f5-ae8b-f06f692c3133 -@@ -36,6 +374,7 @@ def test_log_flush_and_rotation_crash(topo): - 3. Success - 4. Success - """ -+ # NOTE: This test is placed last as it may affect the suffix state. - - inst = topo.standalone - -diff --git a/ldap/servers/slapd/log.c b/ldap/servers/slapd/log.c -index 6f57a3d9c..ca8d481e5 100644 ---- a/ldap/servers/slapd/log.c -+++ b/ldap/servers/slapd/log.c -@@ -135,6 +135,7 @@ static void vslapd_log_emergency_error(LOGFD fp, const char *msg, int locked); - static int get_syslog_loglevel(int loglevel); - static void log_external_libs_debug_openldap_print(char *buffer); - static int log__fix_rotationinfof(char *pathname); -+static int log__validate_rotated_logname(const char *timestamp_str, PRBool *is_compressed); - - static int - get_syslog_loglevel(int loglevel) -@@ -410,7 +411,7 @@ g_log_init() - loginfo.log_security_fdes = NULL; - loginfo.log_security_file = NULL; - loginfo.log_securityinfo_file = NULL; -- loginfo.log_numof_access_logs = 1; -+ loginfo.log_numof_security_logs = 1; - loginfo.log_security_logchain = NULL; - loginfo.log_security_buffer = log_create_buffer(LOG_BUFFER_MAXSIZE); - loginfo.log_security_compress = cfg->securitylog_compress; -@@ -3311,7 +3312,7 @@ log__open_accesslogfile(int logfile_state, int locked) - } - } else if (loginfo.log_access_compress) { - if (compress_log_file(newfile, loginfo.log_access_mode) != 0) { -- slapi_log_err(SLAPI_LOG_ERR, "log__open_auditfaillogfile", -+ slapi_log_err(SLAPI_LOG_ERR, "log__open_accesslogfile", - "failed to compress rotated access log (%s)\n", - newfile); - } else { -@@ -4710,6 +4711,50 @@ log__delete_rotated_logs() - loginfo.log_error_logchain = NULL; - } - -+/* -+ * log__validate_rotated_logname -+ * -+ * Validates that a log filename timestamp suffix matches the expected format: -+ * YYYYMMDD-HHMMSS (15 chars) or YYYYMMDD-HHMMSS.gz (18 chars) for compressed files. -+ * Uses regex pattern: ^[0-9]{8}-[0-9]{6}(\.gz)?$ -+ * -+ * \param timestamp_str The timestamp portion of the log filename (after the first '.') -+ * \param is_compressed Output parameter set to PR_TRUE if the file has .gz suffix -+ * \return 1 if valid, 0 if invalid -+ */ -+static int -+log__validate_rotated_logname(const char *timestamp_str, PRBool *is_compressed) -+{ -+ Slapi_Regex *re = NULL; -+ char *re_error = NULL; -+ int rc = 0; -+ -+ /* Match YYYYMMDD-HHMMSS with optional .gz suffix */ -+ static const char *pattern = "^[0-9]{8}-[0-9]{6}(\\.gz)?$"; -+ -+ *is_compressed = PR_FALSE; -+ -+ re = slapi_re_comp(pattern, &re_error); -+ if (re == NULL) { -+ slapi_log_err(SLAPI_LOG_ERR, "log__validate_rotated_logname", -+ "Failed to compile regex: %s\n", re_error ? re_error : "unknown error"); -+ slapi_ch_free_string(&re_error); -+ return 0; -+ } -+ -+ rc = slapi_re_exec_nt(re, timestamp_str); -+ if (rc == 1) { -+ /* Check if compressed by looking for .gz suffix */ -+ size_t len = strlen(timestamp_str); -+ if (len >= 3 && strcmp(timestamp_str + len - 3, ".gz") == 0) { -+ *is_compressed = PR_TRUE; -+ } -+ } -+ -+ slapi_re_free(re); -+ return rc == 1 ? 1 : 0; -+} -+ - #define ERRORSLOG 1 - #define ACCESSLOG 2 - #define AUDITLOG 3 -@@ -4792,31 +4837,19 @@ log__fix_rotationinfof(char *pathname) - } - } else if (0 == strncmp(log_type, dirent->name, strlen(log_type)) && - (p = strchr(dirent->name, '.')) != NULL && -- NULL != strchr(p, '-')) /* e.g., errors.20051123-165135 */ -+ NULL != strchr(p, '-')) /* e.g., errors.20051123-165135 or errors.20051123-165135.gz */ - { - struct logfileinfo *logp; -- char *q; -- int ignoreit = 0; -- -- for (q = ++p; q && *q; q++) { -- if (*q != '-' && -- *q != '.' && /* .gz */ -- *q != 'g' && -- *q != 'z' && -- !isdigit(*q)) -- { -- ignoreit = 1; -- } -- } -- if (ignoreit || (q - p != 15)) { -+ PRBool is_compressed = PR_FALSE; -+ -+ /* Skip the '.' to get the timestamp portion */ -+ p++; -+ if (!log__validate_rotated_logname(p, &is_compressed)) { - continue; - } - logp = (struct logfileinfo *)slapi_ch_malloc(sizeof(struct logfileinfo)); - logp->l_ctime = log_reverse_convert_time(p); -- logp->l_compressed = PR_FALSE; -- if (strcmp(p + strlen(p) - 3, ".gz") == 0) { -- logp->l_compressed = PR_TRUE; -- } -+ logp->l_compressed = is_compressed; - PR_snprintf(rotated_log, rotated_log_len, "%s/%s", - logsdir, dirent->name); - -@@ -4982,23 +5015,15 @@ log__check_prevlogs(FILE *fp, char *pathname) - for (dirent = PR_ReadDir(dirptr, dirflags); dirent; - dirent = PR_ReadDir(dirptr, dirflags)) { - if (0 == strncmp(log_type, dirent->name, strlen(log_type)) && -- (p = strrchr(dirent->name, '.')) != NULL && -- NULL != strchr(p, '-')) { /* e.g., errors.20051123-165135 */ -- char *q; -- int ignoreit = 0; -- -- for (q = ++p; q && *q; q++) { -- if (*q != '-' && -- *q != '.' && /* .gz */ -- *q != 'g' && -- *q != 'z' && -- !isdigit(*q)) -- { -- ignoreit = 1; -- } -- } -- if (ignoreit || (q - p != 15)) -+ (p = strchr(dirent->name, '.')) != NULL && -+ NULL != strchr(p, '-')) { /* e.g., errors.20051123-165135 or errors.20051123-165135.gz */ -+ PRBool is_compressed = PR_FALSE; -+ -+ /* Skip the '.' to get the timestamp portion */ -+ p++; -+ if (!log__validate_rotated_logname(p, &is_compressed)) { - continue; -+ } - - fseek(fp, 0, SEEK_SET); - buf[BUFSIZ - 1] = '\0'; --- -2.52.0 - diff --git a/0023-Issue-7224-CI-Test-Simplify-test_reserve_descriptor_.patch b/0023-Issue-7224-CI-Test-Simplify-test_reserve_descriptor_.patch deleted file mode 100644 index d3cd410..0000000 --- a/0023-Issue-7224-CI-Test-Simplify-test_reserve_descriptor_.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 524cae18721234e1bc8d958c89684008d62e6b30 Mon Sep 17 00:00:00 2001 -From: James Chapman -Date: Thu, 5 Feb 2026 15:33:08 +0000 -Subject: [PATCH] Issue 7224 - CI Test - Simplify - test_reserve_descriptor_validation (#7225) - -Description: -Previously, the test_reserve_descriptor_validation CItest calculated -the expected number of file descriptors based on backends, indexes, -SSL/FIPS mode, and compared it to the value returned by the server. -This approach is fragile, especially in FIPS mode. - -Fix: -The test has been updated to simply verify that the server corrects -the configured nsslapd-reservedescriptors value if it is set too low, -instead of calculating the expected total. - -Fixes: https://github.com/389ds/389-ds-base/issues/7224 - -Reviewed by: @bsimonova (Thank you) ---- - .../suites/resource_limits/fdlimits_test.py | 36 +++++++------------ - 1 file changed, 13 insertions(+), 23 deletions(-) - -diff --git a/dirsrvtests/tests/suites/resource_limits/fdlimits_test.py b/dirsrvtests/tests/suites/resource_limits/fdlimits_test.py -index edcae28a5..9d8fdec52 100644 ---- a/dirsrvtests/tests/suites/resource_limits/fdlimits_test.py -+++ b/dirsrvtests/tests/suites/resource_limits/fdlimits_test.py -@@ -27,7 +27,7 @@ RESRV_FD_ATTR = "nsslapd-reservedescriptors" - GLOBAL_LIMIT = resource.getrlimit(resource.RLIMIT_NOFILE)[1] - SYSTEMD_LIMIT = ensure_str(check_output("systemctl show -p LimitNOFILE dirsrv@standalone1".split(" ")).strip()).split('=')[1] - CUSTOM_VAL = str(int(SYSTEMD_LIMIT) - 10) --RESRV_DESC_VAL = str(10) -+RESRV_DESC_VAL_LOW = 10 - TOO_HIGH_VAL = str(GLOBAL_LIMIT * 2) - TOO_HIGH_VAL2 = str(int(SYSTEMD_LIMIT) * 2) - TOO_LOW_VAL = "0" -@@ -86,40 +86,30 @@ def test_reserve_descriptor_validation(topology_st): - :id: 9bacdbcc-7754-4955-8a56-1d8c82bce274 - :setup: Standalone Instance - :steps: -- 1. Set attr nsslapd-reservedescriptors to a low value of RESRV_DESC_VAL (10) -+ 1. Set attr nsslapd-reservedescriptors to a low value (10) - 2. Verify low value has been set - 3. Restart instance (On restart the reservedescriptor attr will be validated) -- 4. Check updated value for nsslapd-reservedescriptors attr -+ 4. Verify corrected value for nsslapd-reservedescriptors > low value - :expectedresults: - 1. Success -- 2. A value of RESRV_DESC_VAL (10) is returned -+ 2. A value of RESRV_DESC_VAL_LOW (10) is returned - 3. Success -- 4. A value of STANDALONE_INST_RESRV_DESCS (55) is returned -+ 4. Corrected value for nsslapd-reservedescriptors > low value - """ - -- # Set nsslapd-reservedescriptors to a low value (RESRV_DESC_VAL:10) -- topology_st.standalone.config.set(RESRV_FD_ATTR, RESRV_DESC_VAL) -- resrv_fd = topology_st.standalone.config.get_attr_val_utf8(RESRV_FD_ATTR) -- assert resrv_fd == RESRV_DESC_VAL -+ # Set nsslapd-reservedescriptors to a low value (10) -+ topology_st.standalone.config.set(RESRV_FD_ATTR, str(RESRV_DESC_VAL_LOW)) -+ resrv_fd = int(topology_st.standalone.config.get_attr_val_utf8(RESRV_FD_ATTR)) -+ assert resrv_fd == RESRV_DESC_VAL_LOW - - # An instance restart triggers a validation of the configured nsslapd-reservedescriptors attribute - topology_st.standalone.restart() - -- """ -- A standalone instance contains a single backend with default indexes -- so we only check these. TODO add tests for repl, chaining, PTA, SSL -- """ -- STANDALONE_INST_RESRV_DESCS = 20 # 20 = Reserve descriptor constant -- backends = Backends(topology_st.standalone) -- STANDALONE_INST_RESRV_DESCS += (len(backends.list()) * 4) # 4 = Backend descriptor constant -- for be in backends.list() : -- STANDALONE_INST_RESRV_DESCS += len(be.get_indexes().list()) -- -- # Varify reservedescriptors has been updated -- resrv_fd = topology_st.standalone.config.get_attr_val_utf8(RESRV_FD_ATTR) -- assert resrv_fd == str(STANDALONE_INST_RESRV_DESCS) -+ # Get the corrected value -+ corrected_fd = int(topology_st.standalone.config.get_attr_val_utf8(RESRV_FD_ATTR)) -+ assert corrected_fd > RESRV_DESC_VAL_LOW - -- log.info("test_reserve_descriptor_validation PASSED") -+ log.info(f"test_reserve_descriptor_validation PASSED (corrected from {RESRV_DESC_VAL_LOW} to {corrected_fd})") - - @pytest.mark.skipif(ds_is_older("1.4.1.2"), reason="Not implemented") - def test_reserve_descriptors_high(topology_st): --- -2.52.0 - diff --git a/0024-Issue-7231-Sync-repl-tests-fail-in-FIPS-mode-due-to-.patch b/0024-Issue-7231-Sync-repl-tests-fail-in-FIPS-mode-due-to-.patch deleted file mode 100644 index 3f6ae94..0000000 --- a/0024-Issue-7231-Sync-repl-tests-fail-in-FIPS-mode-due-to-.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 91e03f431d8ee0b1d316ebd7add232bf49360db2 Mon Sep 17 00:00:00 2001 -From: James Chapman -Date: Thu, 12 Feb 2026 10:42:09 +0000 -Subject: [PATCH] Issue 7231 - Sync repl tests fail in FIPS mode due to non - FIPS compliant crypto (#7232) - -Description: -Several sync_repl tests fail when running on a FIPS enabled system. The failures -are caused by the sync repl client (Sync_persist), using TLS options and ciphers -that are not FIPS compatible. - -Fix: -Update the sync repl client to use FIPS approved TLS version. - -Fixes: https://github.com/389ds/389-ds-base/issues/7231 - -Reviewed by: @progier389, @droideck (Thank you) ---- - .../tests/suites/syncrepl_plugin/basic_test.py | 15 +++++++++++++-- - 1 file changed, 13 insertions(+), 2 deletions(-) - -diff --git a/dirsrvtests/tests/suites/syncrepl_plugin/basic_test.py b/dirsrvtests/tests/suites/syncrepl_plugin/basic_test.py -index c22331eb5..1e9a530bb 100644 ---- a/dirsrvtests/tests/suites/syncrepl_plugin/basic_test.py -+++ b/dirsrvtests/tests/suites/syncrepl_plugin/basic_test.py -@@ -20,7 +20,7 @@ from lib389.idm.group import Groups - from lib389.topologies import topology_st as topology - from lib389.topologies import topology_m2 as topo_m2 - from lib389.paths import Paths --from lib389.utils import ds_is_older -+from lib389.utils import ds_is_older, is_fips - from lib389.plugins import RetroChangelogPlugin, ContentSyncPlugin, AutoMembershipPlugin, MemberOfPlugin, MemberOfSharedConfig, AutoMembershipDefinitions, MEPTemplates, MEPConfigs, ManagedEntriesPlugin, MEPTemplate - from lib389._constants import * - -@@ -214,6 +214,12 @@ class Sync_persist(threading.Thread, ReconnectLDAPObject, SyncreplConsumer): - def run(self): - """Start a sync repl client""" - ldap_connection = TestSyncer(self.inst.toLDAPURL()) -+ ldap_connection.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_DEMAND) -+ ldap_connection.set_option(ldap.OPT_X_TLS_CACERTFILE, os.path.join(self.inst.get_config_dir(), "ca.crt")) -+ if is_fips(): -+ ldap_connection.set_option(ldap.OPT_X_TLS_PROTOCOL_MIN, ldap.OPT_X_TLS_PROTOCOL_TLS1_2) -+ ldap_connection.set_option(ldap.OPT_X_TLS_NEWCTX, 0) -+ - ldap_connection.simple_bind_s('cn=directory manager', 'password') - ldap_search = ldap_connection.syncrepl_search( - "dc=example,dc=com", -@@ -253,6 +259,7 @@ def test_sync_repl_mep(topology, request): - 5. Success - """ - inst = topology[0] -+ inst.enable_tls() - - # Enable/configure retroCL - plugin = RetroChangelogPlugin(inst) -@@ -338,6 +345,7 @@ def test_sync_repl_cookie(topology, init_sync_repl_plugins, request): - 5.: succeeds - """ - inst = topology[0] -+ inst.enable_tls() - - # create a sync repl client and wait 5 seconds to be sure it is running - sync_repl = Sync_persist(inst) -@@ -404,6 +412,8 @@ def test_sync_repl_cookie_add_del(topology, init_sync_repl_plugins, request): - 6.: succeeds - """ - inst = topology[0] -+ inst.enable_tls() -+ - # create a sync repl client and wait 5 seconds to be sure it is running - sync_repl = Sync_persist(inst) - sync_repl.start() -@@ -547,6 +557,7 @@ def test_sync_repl_cenotaph(topo_m2, request): - 5. Should succeeds - """ - m1 = topo_m2.ms["supplier1"] -+ m1.enable_tls() - # Enable/configure retroCL - plugin = RetroChangelogPlugin(m1) - plugin.disable() -@@ -605,7 +616,7 @@ def test_sync_repl_dynamic_plugin(topology, request): - 3. Should succeeds - 4. Should succeeds - """ -- -+ topology.standalone.enable_tls() - # Reset the instance in a default config - # Disable content sync plugin - topology.standalone.plugins.disable(name=PLUGIN_REPL_SYNC) --- -2.52.0 - diff --git a/0025-Issue-7248-CLI-attribute-uniqueness-fix-usage-for-ex.patch b/0025-Issue-7248-CLI-attribute-uniqueness-fix-usage-for-ex.patch deleted file mode 100644 index 35619dd..0000000 --- a/0025-Issue-7248-CLI-attribute-uniqueness-fix-usage-for-ex.patch +++ /dev/null @@ -1,33 +0,0 @@ -From bd57467f6efd8e398eb2e608331711bdd571d3ac Mon Sep 17 00:00:00 2001 -From: Mark Reynolds -Date: Thu, 12 Feb 2026 09:58:54 -0500 -Subject: [PATCH] Issue 7248 - CLI - attribute uniqueness - fix usage for - exclude subtree option - -Description: - -Fix typo in usage message for the exclude subtree option - -relates: https://github.com/389ds/389-ds-base/issues/7248 - -Reviewed by: progier (Thanks!) ---- - src/lib389/lib389/cli_conf/plugins/attruniq.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/lib389/lib389/cli_conf/plugins/attruniq.py b/src/lib389/lib389/cli_conf/plugins/attruniq.py -index bc925eb1c..26ca5d819 100644 ---- a/src/lib389/lib389/cli_conf/plugins/attruniq.py -+++ b/src/lib389/lib389/cli_conf/plugins/attruniq.py -@@ -127,7 +127,7 @@ def _add_parser_args(parser): - help='Sets the DN under which the plug-in checks for uniqueness of ' - 'the attributes value. This attribute is multi-valued (uniqueness-subtrees)') - parser.add_argument('--exclude-subtree', nargs='+', -- help='Sets subtrees that should not excludedfrom attribute uniqueness. ' -+ help='Sets subtrees that should be excluded from attribute uniqueness checks. ' - 'This attribute is multi-valued (uniqueness-exclude-subtrees)') - parser.add_argument('--across-all-subtrees', choices=['on', 'off'], type=str.lower, - help='If enabled (on), the plug-in checks that the attribute is unique across all subtrees ' --- -2.52.0 - diff --git a/0026-Issue-CLI-dsctl-db2index-needs-some-hardening-with-M.patch b/0026-Issue-CLI-dsctl-db2index-needs-some-hardening-with-M.patch deleted file mode 100644 index 9e5ff53..0000000 --- a/0026-Issue-CLI-dsctl-db2index-needs-some-hardening-with-M.patch +++ /dev/null @@ -1,201 +0,0 @@ -From 180329d9ca672306f8e90d599890be3a6a8aa95c Mon Sep 17 00:00:00 2001 -From: Mark Reynolds -Date: Thu, 12 Feb 2026 11:13:45 -0500 -Subject: [PATCH] Issue - CLI - dsctl db2index needs some hardening with MBD - -Description: - -The usage for dsctl db2index was confusing. The way the attr options and -backend name were displayed it looks like the backend name could come after -the attributes, but instead the backend name was treated as an attribute. - -Instead make the backend name required, and change the attribute naming to -require individual options instead of a list of values. - -Relates: https://github.com/389ds/389-ds-base/issues/7250 - -Reviewed by: progier(Thanks!) ---- - .../tests/suites/import/import_test.py | 2 +- - src/lib389/lib389/__init__.py | 40 ++++++------------- - src/lib389/lib389/cli_ctl/dbtasks.py | 37 +++++++---------- - 3 files changed, 27 insertions(+), 52 deletions(-) - -diff --git a/dirsrvtests/tests/suites/import/import_test.py b/dirsrvtests/tests/suites/import/import_test.py -index 18caec633..058a4b3c7 100644 ---- a/dirsrvtests/tests/suites/import/import_test.py -+++ b/dirsrvtests/tests/suites/import/import_test.py -@@ -512,7 +512,7 @@ def test_entry_with_escaped_characters_fails_to_import_and_index(topo, _import_c - count += 1 - # Now re-index the database - topo.standalone.stop() -- topo.standalone.db2index() -+ topo.standalone.db2index(bename="userroot") - topo.standalone.start() - # Should not return error. - assert not topo.standalone.searchErrorsLog('error') -diff --git a/src/lib389/lib389/__init__.py b/src/lib389/lib389/__init__.py -index 39a2852e5..ec47987be 100644 ---- a/src/lib389/lib389/__init__.py -+++ b/src/lib389/lib389/__init__.py -@@ -2985,7 +2985,7 @@ class DirSrv(SimpleLDAPObject, object): - - return True - -- def db2index(self, bename=None, suffixes=None, attrs=None, vlvTag=None): -+ def db2index(self, bename, suffixes=None, attrs=None, vlvTag=None): - """ - @param bename - The backend name to reindex - @param suffixes - List/tuple of suffixes to reindex, currently unused -@@ -2998,34 +2998,18 @@ class DirSrv(SimpleLDAPObject, object): - if self.status(): - self.log.error("db2index: Can not operate while directory server is running") - return False -- cmd = [prog, ] -- # No backend specified, do an upgrade on all backends -- # Backend and no attrs specified, reindex with all backend indexes -- # Backend and attr/s specified, reindex backend with attr/s -- if bename: -- cmd.append('db2index') -- cmd.append('-n') -- cmd.append(bename) -- if attrs: -- for attr in attrs: -- cmd.append('-t') -- cmd.append(attr) -- else: -- dse_ldif = DSEldif(self) -- indexes = dse_ldif.get_indexes(bename) -- if indexes: -- for idx in indexes: -- cmd.append('-t') -- cmd.append(idx) -+ cmd = [prog, 'db2index', '-n', bename, '-D', self.get_config_dir()] -+ if attrs: -+ for attr in attrs: -+ cmd.append('-t') -+ cmd.append(attr) - else: -- cmd.append('upgradedb') -- cmd.append('-a') -- now = datetime.now().isoformat() -- cmd.append(os.path.join(self.get_bak_dir(), 'reindex_%s' % now)) -- cmd.append('-f') -- -- cmd.append('-D') -- cmd.append(self.get_config_dir()) -+ dse_ldif = DSEldif(self) -+ indexes = dse_ldif.get_indexes(bename) -+ if indexes: -+ for idx in indexes: -+ cmd.append('-t') -+ cmd.append(idx) - - try: - result = subprocess.check_output(cmd, encoding='utf-8') -diff --git a/src/lib389/lib389/cli_ctl/dbtasks.py b/src/lib389/lib389/cli_ctl/dbtasks.py -index 16da966d1..cd96cdaf7 100644 ---- a/src/lib389/lib389/cli_ctl/dbtasks.py -+++ b/src/lib389/lib389/cli_ctl/dbtasks.py -@@ -26,32 +26,18 @@ class IndexOrdering(Enum): - - - def dbtasks_db2index(inst, log, args): -- rtn = False -- if not args.backend: -- if not inst.db2index(): -- rtn = False -- else: -- rtn = True -- elif args.backend and not args.attr: -- if not inst.db2index(bename=args.backend): -- rtn = False -- else: -- rtn = True -+ inst.log = log -+ if not inst.db2index(bename=args.backend, attrs=args.attr): -+ log.fatal("db2index failed") -+ return False - else: -- if not inst.db2index(bename=args.backend, attrs=args.attr): -- rtn = False -- else: -- rtn = True -- if rtn: - log.info("db2index successful") -- return rtn -- else: -- log.fatal("db2index failed") -- return rtn -+ return True - - - def dbtasks_db2bak(inst, log, args): - # Needs an output name? -+ inst.log = log - if not inst.db2bak(args.archive): - log.fatal("db2bak failed") - return False -@@ -61,6 +47,7 @@ def dbtasks_db2bak(inst, log, args): - - def dbtasks_bak2db(inst, log, args): - # Needs the archive to restore. -+ inst.log = log - if not inst.bak2db(args.archive): - log.fatal("bak2db failed") - return False -@@ -70,6 +57,7 @@ def dbtasks_bak2db(inst, log, args): - - def dbtasks_db2ldif(inst, log, args): - # If export filename is provided, check if file path exists -+ inst.log = log - if args.ldif: - path = Path(args.ldif) - parent = path.parent.absolute() -@@ -88,6 +76,7 @@ def dbtasks_db2ldif(inst, log, args): - - def dbtasks_ldif2db(inst, log, args): - # Check if ldif file exists -+ inst.log = log - if not os.path.exists(args.ldif): - raise ValueError("The LDIF file does not exist: " + args.ldif) - -@@ -103,6 +92,7 @@ def dbtasks_ldif2db(inst, log, args): - - - def dbtasks_backups(inst, log, args): -+ inst.log = log - if args.delete: - # Delete backup - inst.del_backup(args.delete[0]) -@@ -117,6 +107,7 @@ def dbtasks_backups(inst, log, args): - - - def dbtasks_ldifs(inst, log, args): -+ inst.log = log - if args.delete: - # Delete LDIF file - inst.del_ldif(args.delete[0]) -@@ -131,6 +122,7 @@ def dbtasks_ldifs(inst, log, args): - - - def dbtasks_verify(inst, log, args): -+ inst.log = log - if not inst.dbverify(bename=args.backend): - log.fatal("dbverify failed") - return False -@@ -521,9 +513,8 @@ def dbtasks_index_check(inst, log, args): - - def create_parser(subcommands): - db2index_parser = subcommands.add_parser('db2index', help="Initialise a reindex of the server database. The server must be stopped for this to proceed.", formatter_class=CustomHelpFormatter) -- # db2index_parser.add_argument('suffix', help="The suffix to reindex. IE dc=example,dc=com.") -- db2index_parser.add_argument('backend', nargs="?", help="The backend to reindex. IE userRoot", default=False) -- db2index_parser.add_argument('--attr', nargs="*", help="The attribute's to reindex. IE --attr aci cn givenname", default=False) -+ db2index_parser.add_argument('backend', help="The backend to reindex. IE userRoot") -+ db2index_parser.add_argument('--attr', action='append', help="An attribute to reindex. IE: --attr member --attr cn ...") - db2index_parser.set_defaults(func=dbtasks_db2index) - - db2bak_parser = subcommands.add_parser('db2bak', help="Initialise a BDB backup of the database. The server must be stopped for this to proceed.", formatter_class=CustomHelpFormatter) --- -2.52.0 - diff --git a/0027-Issue-7184-2nd-argparse.HelpFormatter-_format_action.patch b/0027-Issue-7184-2nd-argparse.HelpFormatter-_format_action.patch deleted file mode 100644 index 0886182..0000000 --- a/0027-Issue-7184-2nd-argparse.HelpFormatter-_format_action.patch +++ /dev/null @@ -1,41 +0,0 @@ -From c831a7af2afb7cfd2eb958476a7a8d421ac5d339 Mon Sep 17 00:00:00 2001 -From: Viktor Ashirov -Date: Fri, 13 Feb 2026 15:38:52 +0100 -Subject: [PATCH] Issue 7184 - (2nd) argparse.HelpFormatter - _format_actions_usage() is deprecated (#7257) - -Description: -`_format_actions_usage()` was also removed in Python 3.14.3. -Replace version check with `isinstance()` to handle the return type of -`_get_actions_usage_parts()` more robustly across Python versions. - -Relates: https://github.com/389ds/389-ds-base/issues/7184 -Fixes: https://github.com/389ds/389-ds-base/issues/7253 - -Reviewed by: @progier389 (Thanks!) ---- - src/lib389/lib389/cli_base/__init__.py | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/src/lib389/lib389/cli_base/__init__.py b/src/lib389/lib389/cli_base/__init__.py -index f1055aadc..3af8a46e6 100644 ---- a/src/lib389/lib389/cli_base/__init__.py -+++ b/src/lib389/lib389/cli_base/__init__.py -@@ -420,11 +420,11 @@ class CustomHelpFormatter(argparse.HelpFormatter): - else: - # Use _get_actions_usage_parts() for Python 3.13 and later - action_parts = self._get_actions_usage_parts(parent_arguments, []) -- if sys.version_info >= (3, 15): -- # Python 3.15 returns a tuple (list of actions, count of actions) -+ if isinstance(action_parts, tuple): -+ # Python 3.14.3+ and 3.15+ return a tuple (list of actions, count of actions) - formatted_options = ' '.join(action_parts[0]) - else: -- # Python 3.13 and 3.14 return a list of actions -+ # Earlier versions return a list of actions - formatted_options = ' '.join(action_parts) - - # If formatted_options already in usage - remove them --- -2.52.0 - diff --git a/0028-Issue-7213-2nd-MDB_BAD_VALSIZE-error-while-handling-.patch b/0028-Issue-7213-2nd-MDB_BAD_VALSIZE-error-while-handling-.patch deleted file mode 100644 index d016d69..0000000 --- a/0028-Issue-7213-2nd-MDB_BAD_VALSIZE-error-while-handling-.patch +++ /dev/null @@ -1,32 +0,0 @@ -From a7f8eb79dde03ac771de2335a2acb4aed48483a2 Mon Sep 17 00:00:00 2001 -From: Viktor Ashirov -Date: Fri, 13 Feb 2026 16:27:25 +0100 -Subject: [PATCH] Issue 7213 - (2nd) MDB_BAD_VALSIZE error while handling VLV - (#7258) - -Decription: -Disable test_vlv_long_attribute_value on BDB as it hangs sometimes in -CI, blocking other pipelines. - -Relates: https://github.com/389ds/389-ds-base/issues/7213 - -Reviewed by: @progier389 (Thanks!) ---- - dirsrvtests/tests/suites/vlv/regression_test.py | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/dirsrvtests/tests/suites/vlv/regression_test.py b/dirsrvtests/tests/suites/vlv/regression_test.py -index 1cc03c303..94001af62 100644 ---- a/dirsrvtests/tests/suites/vlv/regression_test.py -+++ b/dirsrvtests/tests/suites/vlv/regression_test.py -@@ -1178,6 +1178,7 @@ def test_vlv_with_mr(vlv_setup_with_uid_mr): - - - -+@pytest.mark.skipif(get_default_db_lib() == "bdb", reason="Hangs on BDB") - def test_vlv_long_attribute_value(topology_st, request): - """ - Test VLV with an entry containing a very long attribute value (2K). --- -2.52.0 - diff --git a/0029-Issue-7223-Use-lexicographical-order-for-ancestorid-.patch b/0029-Issue-7223-Use-lexicographical-order-for-ancestorid-.patch deleted file mode 100644 index d57c972..0000000 --- a/0029-Issue-7223-Use-lexicographical-order-for-ancestorid-.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 75b1213dfb94495160a735c2688cee03d6be5a9a Mon Sep 17 00:00:00 2001 -From: Viktor Ashirov -Date: Fri, 13 Feb 2026 16:58:24 +0100 -Subject: [PATCH] Issue 7223 - Use lexicographical order for ancestorid (#7256) - -Description: -`ldbm_instance_create_default_indexes()` configured ancestorid with -integerOrderingMatch in the in-memory attrinfo, but ancestorid on disk -might be using lexicographic ordering (data before the upgrade or after -ldif2db import). - -Relates: https://github.com/389ds/389-ds-base/issues/7223 - -Reviewed by: @tbordaz (Thanks!) ---- - ldap/servers/slapd/back-ldbm/instance.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ldap/servers/slapd/back-ldbm/instance.c b/ldap/servers/slapd/back-ldbm/instance.c -index 3fcdb5554..563cf96db 100644 ---- a/ldap/servers/slapd/back-ldbm/instance.c -+++ b/ldap/servers/slapd/back-ldbm/instance.c -@@ -239,7 +239,7 @@ ldbm_instance_create_default_indexes(backend *be) - * ancestorid is special, there is actually no such attr type - * but we still want to use the attr index file APIs. - */ -- e = ldbm_instance_init_config_entry(LDBM_ANCESTORID_STR, "eq", 0, 0, 0, "integerOrderingMatch"); -+ e = ldbm_instance_init_config_entry(LDBM_ANCESTORID_STR, "eq", 0, 0, 0, 0); - attr_index_config(be, "ldbm index init", 0, e, 1, 0, NULL); - slapi_entry_free(e); - } --- -2.52.0 - diff --git a/0030-Issue-7066-7052-allow-password-history-to-be-set-to-.patch b/0030-Issue-7066-7052-allow-password-history-to-be-set-to-.patch deleted file mode 100644 index ccab1a6..0000000 --- a/0030-Issue-7066-7052-allow-password-history-to-be-set-to-.patch +++ /dev/null @@ -1,89 +0,0 @@ -From 7809104b9edb2d05ceee7ca819152f365cc1beb0 Mon Sep 17 00:00:00 2001 -From: Mark Reynolds -Date: Wed, 11 Feb 2026 15:51:47 -0500 -Subject: [PATCH] Issue 7066/7052 - allow password history to be set to zero - and remove history - -Description: - -For local password policies the server was incorrectly rejecting updates that -set the value to zero. When password history is set to zero the old passwords -in the entry history are not cleaned as expected. - -relates: https://github.com/389ds/389-ds-base/issues/7052 -relates: https://github.com/389ds/389-ds-base/issues/7066 - -Reviewed by: progier(Thanks!) ---- - .../tests/suites/password/pwp_history_test.py | 9 ++++++--- - ldap/servers/slapd/modify.c | 2 +- - ldap/servers/slapd/pw.c | 13 ++++++++++++- - 3 files changed, 19 insertions(+), 5 deletions(-) - -diff --git a/dirsrvtests/tests/suites/password/pwp_history_test.py b/dirsrvtests/tests/suites/password/pwp_history_test.py -index 8a15a1986..387824bc5 100644 ---- a/dirsrvtests/tests/suites/password/pwp_history_test.py -+++ b/dirsrvtests/tests/suites/password/pwp_history_test.py -@@ -108,8 +108,12 @@ def test_history_is_not_overwritten(topology_st, user): - user.set('userpassword', USER_PWD) - - --def test_basic(topology_st, user): -- """Test basic password policy history feature functionality -+@pytest.mark.parametrize('policy', -+ [(pytest.param('global')), -+ (pytest.param('subtree')), -+ (pytest.param('user'))]) -+def test_basic(topology_st, user, policy): -+ """Test basic password policy history feature functionality with dynamic count reduction - - :id: 83d74f7d-3036-4944-8839-1b40bbf265ff - :setup: Standalone instance, a test user -@@ -238,7 +242,6 @@ def test_basic(topology_st, user): - - # - # Reset password by Directory Manager(admin reset) -- # - dm = DirectoryManager(topology_st.standalone) - dm.rebind() - time.sleep(.5) -diff --git a/ldap/servers/slapd/modify.c b/ldap/servers/slapd/modify.c -index b0066faf8..d76427886 100644 ---- a/ldap/servers/slapd/modify.c -+++ b/ldap/servers/slapd/modify.c -@@ -87,7 +87,7 @@ static struct attr_value_check - {CONFIG_PW_WARNING_ATTRIBUTE, check_pw_duration_value, 0, -1}, - {CONFIG_PW_MINLENGTH_ATTRIBUTE, attr_check_minmax, 2, 512}, - {CONFIG_PW_MAXFAILURE_ATTRIBUTE, attr_check_minmax, 1, 32767}, -- {CONFIG_PW_INHISTORY_ATTRIBUTE, attr_check_minmax, 1, 24}, -+ {CONFIG_PW_INHISTORY_ATTRIBUTE, attr_check_minmax, 0, 24}, - {CONFIG_PW_LOCKDURATION_ATTRIBUTE, check_pw_duration_value, -1, -1}, - {CONFIG_PW_RESETFAILURECOUNT_ATTRIBUTE, check_pw_resetfailurecount_value, -1, -1}, - {CONFIG_PW_GRACELIMIT_ATTRIBUTE, attr_check_minmax, 0, -1}, -diff --git a/ldap/servers/slapd/pw.c b/ldap/servers/slapd/pw.c -index cda1c404f..12cf759ce 100644 ---- a/ldap/servers/slapd/pw.c -+++ b/ldap/servers/slapd/pw.c -@@ -1532,7 +1532,18 @@ update_pw_history(Slapi_PBlock *pb, const Slapi_DN *sdn, char *old_pw) - pwpolicy = new_passwdPolicy(pb, dn); - - if (pwpolicy->pw_inhistory == 0){ -- /* We are only enforcing the current password, just return */ -+ /* We are only enforcing the current password, just return but first -+ * cleanup any old passwords in the history */ -+ attribute.mod_type = "passwordHistory"; -+ attribute.mod_op = LDAP_MOD_REPLACE; -+ attribute.mod_values = NULL; -+ list_of_mods[0] = &attribute; -+ list_of_mods[1] = NULL; -+ mod_pb = slapi_pblock_new(); -+ slapi_modify_internal_set_pb_ext(mod_pb, sdn, list_of_mods, NULL, NULL, pw_get_componentID(), 0); -+ slapi_modify_internal_pb(mod_pb); -+ slapi_pblock_destroy(mod_pb); -+ - return res; - } - --- -2.52.0 - diff --git a/0031-Issue-7243-UI-fix-certificate-table-and-modal.patch b/0031-Issue-7243-UI-fix-certificate-table-and-modal.patch deleted file mode 100644 index 8420bcd..0000000 --- a/0031-Issue-7243-UI-fix-certificate-table-and-modal.patch +++ /dev/null @@ -1,260 +0,0 @@ -From 4209ff65310c54b6ab55594984201b1214fb75b2 Mon Sep 17 00:00:00 2001 -From: Mark Reynolds -Date: Mon, 16 Feb 2026 16:52:52 -0500 -Subject: [PATCH] Issue 7243 - UI - fix certificate table and modal - -Description: - -The certificate table was not handling sorting and pagination correctly, and -the add cert modal was not correctly selecting certs on disk - -This was fixed upstream for the hot cetificate features, but only backporting -the table/modal changes to older branches - -relates: https://github.com/389ds/389-ds-base/issues/7243 - -Reviewed by: spichugi(Thanks!) ---- - .../src/lib/security/securityModals.jsx | 4 +- - .../src/lib/security/securityTables.jsx | 85 ++++++------------- - 2 files changed, 29 insertions(+), 60 deletions(-) - -diff --git a/src/cockpit/389-console/src/lib/security/securityModals.jsx b/src/cockpit/389-console/src/lib/security/securityModals.jsx -index a42aa50d6..c4af753c0 100644 ---- a/src/cockpit/389-console/src/lib/security/securityModals.jsx -+++ b/src/cockpit/389-console/src/lib/security/securityModals.jsx -@@ -298,7 +298,9 @@ export class SecurityAddCertModal extends React.Component { - { -+ handleCertSelect(str); -+ }} - aria-label="FormSelect Input" - className="ds-cert-select" - validated={selectValidated} -diff --git a/src/cockpit/389-console/src/lib/security/securityTables.jsx b/src/cockpit/389-console/src/lib/security/securityTables.jsx -index fce4cb04e..a6c64e6c1 100644 ---- a/src/cockpit/389-console/src/lib/security/securityTables.jsx -+++ b/src/cockpit/389-console/src/lib/security/securityTables.jsx -@@ -4,7 +4,6 @@ import { - Grid, - GridItem, - Pagination, -- PaginationVariant, - SearchInput, - Tooltip, - } from '@patternfly/react-core'; -@@ -94,10 +93,10 @@ class KeyTable extends React.Component { - ]; - - handleSort(_event, index, direction) { -- const sortedRows = [...this.state.rows].sort((a, b) => -+ const sortedRows = [...this.state.rows].sort((a, b) => - (a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0) - ); -- -+ - this.setState({ - sortBy: { - index, -@@ -127,7 +126,7 @@ class KeyTable extends React.Component { - > - {_("What is an orphan key?")} - -- - - {columns.map((column, idx) => ( --
-- - -@@ -224,7 +223,7 @@ class CSRTable extends React.Component { - } - - handleSort(_event, index, direction) { -- const sortedRows = [...this.state.rows].sort((a, b) => -+ const sortedRows = [...this.state.rows].sort((a, b) => - (a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0) - ); - this.setState({ -@@ -316,7 +315,7 @@ class CSRTable extends React.Component { - onClear={(evt) => this.handleSearchChange(evt, '')} - /> - } -- - - {columns.map((column, idx) => ( --
-- - -@@ -418,41 +417,11 @@ class CertTable extends React.Component { - } - - handleSort(_event, columnIndex, direction) { -- const sorted_rows = []; -- const rows = []; -- let count = 0; -- -- // Convert the rows pairings into a sortable array -- for (let idx = 0; idx < this.state.rows.length; idx += 2) { -- sorted_rows.push({ -- expandedRow: this.state.rows[idx + 1], -- 1: this.state.rows[idx].cells[0].content, -- 2: this.state.rows[idx].cells[1].content, -- 3: this.state.rows[idx].cells[2].content, -- issuer: this.state.rows[idx].issuer, -- flags: this.state.rows[idx].flags -- }); -- } -+ const rows = [...this.state.rows]; - -- sorted_rows.sort((a, b) => (a[columnIndex + 1] > b[columnIndex + 1]) ? 1 : -1); -+ rows.sort((a, b) => (a.cells[columnIndex].content > b.cells[columnIndex].content) ? 1 : -1); - if (direction !== SortByDirection.asc) { -- sorted_rows.reverse(); -- } -- -- for (const srow of sorted_rows) { -- rows.push({ -- isOpen: false, -- cells: [ -- { content: srow[1] }, -- { content: srow[2] }, -- { content: srow[3] } -- ], -- issuer: srow.issuer, -- flags: srow.flags, -- }); -- srow.expandedRow.parent = count; -- rows.push(srow.expandedRow); -- count += 2; -+ rows.reverse(); - } - - this.setState({ -@@ -534,18 +503,16 @@ class CertTable extends React.Component { - rows.push( - { - isOpen: false, -- cells: [cert.attrs.nickname, cert.attrs.subject, cert.attrs.expires], -+ cells: [ -+ { content: cert.attrs.nickname }, -+ { content: cert.attrs.subject }, -+ { content: cert.attrs.expires } -+ ], - issuer: cert.attrs.issuer, - flags: cert.attrs.flags, -- -- }, -- { -- parent: count, -- fullWidth: true, -- cells: [{ title: this.getExpandedRow(cert.attrs.issuer, cert.attrs.flags) }] -- }, -+ } - ); -- count += 2; -+ count += 1; - } - - this.setState({ -@@ -587,7 +554,7 @@ class CertTable extends React.Component { - onChange={this.handleSearchChange} - onClear={(evt) => this.handleSearchChange(evt, '')} - />} -- -@@ -626,7 +593,7 @@ class CertTable extends React.Component { - - ))} - -@@ -646,7 +613,7 @@ class CertTable extends React.Component { -
-- -
- {hasRows && - this.handleSearchChange(evt, '')} - /> -- - - - {this.state.columns.map((column, idx) => ( --
-- - --- -2.52.0 - diff --git a/0032-Issue-7223-Remove-integerOrderingMatch-requirement-f.patch b/0032-Issue-7223-Remove-integerOrderingMatch-requirement-f.patch deleted file mode 100644 index 39bc237..0000000 --- a/0032-Issue-7223-Remove-integerOrderingMatch-requirement-f.patch +++ /dev/null @@ -1,538 +0,0 @@ -From 09b6f770f15ee8d333377b7902e18b78f4f7008c Mon Sep 17 00:00:00 2001 -From: Viktor Ashirov -Date: Wed, 18 Feb 2026 09:26:57 +0100 -Subject: [PATCH] Issue 7223 - Remove integerOrderingMatch requirement for - parentid (#7264) - -Description: -integerOrderingMatch was introduced as a requirement for parentid and -ancestorid indexes for performance reasons. But after #7096 the order -for parentid doesn't make a lot of difference. - -Fix Description: -* Remove integerOrderingMatch requirement for parentid. -* Read only first 100 keys from dbscan in index ordering check -* Do not run dsctl index-check during RPM upgrade - -Relates: https://github.com/389ds/389-ds-base/pull/7223 - -Reviewed by: @progier389, @tbordaz (Thanks!) ---- - .../healthcheck/health_system_indexes_test.py | 83 ++++---------- - ldap/servers/slapd/upgrade.c | 105 ------------------ - rpm/389-ds-base.spec.in | 3 - - src/lib389/lib389/backend.py | 5 +- - src/lib389/lib389/cli_ctl/dbtasks.py | 99 ++++++++--------- - 5 files changed, 73 insertions(+), 222 deletions(-) - -diff --git a/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py b/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py -index 3b3651b38..71a9f590a 100644 ---- a/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py -+++ b/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py -@@ -180,7 +180,8 @@ def test_missing_parentid(topology_st, log_buffering_enabled): - - - def test_missing_matching_rule(topology_st, log_buffering_enabled): -- """Check if healthcheck returns DSBLE0007 code when parentId index is missing integerOrderingMatch -+ """Check that healthcheck does NOT report DSBLE0007 when parentId index is missing integerOrderingMatch. -+ Both lexicographic and integer orderings are valid for parentid. - - :id: 7ffa71db-8995-430a-bed8-59bce944221c - :setup: Standalone instance -@@ -190,19 +191,14 @@ def test_missing_matching_rule(topology_st, log_buffering_enabled): - 3. Use healthcheck without --json option - 4. Use healthcheck with --json option - 5. Re-add the matching rule -- 6. Use healthcheck without --json option -- 7. Use healthcheck with --json option - :expectedresults: - 1. Success - 2. Success -- 3. healthcheck reports DSBLE0007 code and related details -- 4. healthcheck reports DSBLE0007 code and related details -+ 3. healthcheck reports no issues found -+ 4. healthcheck reports no issues found - 5. Success -- 6. healthcheck reports no issues found -- 7. healthcheck reports no issues found - """ - -- RET_CODE = "DSBLE0007" - PARENTID_DN = "cn=parentid,cn=index,cn=userroot,cn=ldbm database,cn=plugins,cn=config" - - standalone = topology_st.standalone -@@ -211,17 +207,14 @@ def test_missing_matching_rule(topology_st, log_buffering_enabled): - parentid_index = Index(standalone, PARENTID_DN) - parentid_index.remove("nsMatchingRule", "integerOrderingMatch") - -- run_healthcheck_and_flush_log(topology_st, standalone, json=False, searched_code=RET_CODE) -- run_healthcheck_and_flush_log(topology_st, standalone, json=True, searched_code=RET_CODE) -+ run_healthcheck_and_flush_log(topology_st, standalone, json=False, searched_code=CMD_OUTPUT) -+ run_healthcheck_and_flush_log(topology_st, standalone, json=True, searched_code=JSON_OUTPUT) - - log.info("Re-add the integerOrderingMatch matching rule") - parentid_index = Index(standalone, PARENTID_DN) - parentid_index.add("nsMatchingRule", "integerOrderingMatch") - standalone.restart() - -- run_healthcheck_and_flush_log(topology_st, standalone, json=False, searched_code=CMD_OUTPUT) -- run_healthcheck_and_flush_log(topology_st, standalone, json=True, searched_code=JSON_OUTPUT) -- - - def test_usn_plugin_missing_entryusn(topology_st, usn_plugin_enabled, log_buffering_enabled): - """Check if healthcheck returns DSBLE0007 code when USN plugin is enabled but entryusn index is missing -@@ -911,7 +904,9 @@ def test_index_check_fixes_ancestorid_config(topology_st): - - - def test_index_check_fixes_missing_matching_rule(topology_st): -- """Check if dsctl index-check --fix adds missing integerOrderingMatch -+ """Check that removing integerOrderingMatch from parentid config is not -+ flagged as an issue when disk ordering cannot be determined. -+ Both lexicographic and integer orderings are valid for parentid. - - :id: 6c1d4e9f-0a3b-4d5c-1e7f-8a9b0c2d3e4f - :setup: Standalone instance -@@ -919,18 +914,14 @@ def test_index_check_fixes_missing_matching_rule(topology_st): - 1. Create DS instance - 2. Stop the server - 3. Remove integerOrderingMatch from parentid index using DSEldif -- 4. Run dsctl index-check (should detect issue) -- 5. Run dsctl index-check --fix -- 6. Verify integerOrderingMatch was added back -- 7. Start the server -+ 4. Run dsctl index-check (should NOT detect issue since disk ordering is unknown) -+ 5. Start the server - :expectedresults: - 1. Success - 2. Success - 3. Success -- 4. index-check returns False and detects missing matching rule -- 5. index-check returns True after fix -- 6. integerOrderingMatch is present -- 7. Success -+ 4. index-check returns True (no issues, disk ordering unknown) -+ 5. Success - """ - from lib389.cli_ctl.dbtasks import dbtasks_index_check - from lib389.dseldif import DSEldif -@@ -964,34 +955,20 @@ def test_index_check_fixes_missing_matching_rule(topology_st): - f"integerOrderingMatch should be removed, but found: {mr}" - log.info("integerOrderingMatch removed from parentid index") - -- log.info("Run index-check without --fix (should detect issue)") -+ log.info("Run index-check (should NOT detect issue - disk ordering unknown)") - args = FakeArgs() - args.backend = "userRoot" - args.fix = False - - result = dbtasks_index_check(standalone, topology_st.logcap.log, args) -- assert result is False, "index-check should detect missing matching rule" -- assert topology_st.logcap.contains("missing integerOrderingMatch") -+ assert result is True, \ -+ "index-check should not flag missing integerOrderingMatch when disk ordering is unknown" -+ assert topology_st.logcap.contains("could not determine disk ordering") - topology_st.logcap.flush() - -- log.info("Run index-check with --fix") -- args.fix = True -- result = dbtasks_index_check(standalone, topology_st.logcap.log, args) -- assert result is True, "index-check --fix should succeed" -- assert topology_st.logcap.contains("integerOrderingMatch") -- topology_st.logcap.flush() -- -- log.info("Verify integerOrderingMatch was added back") -- dse_ldif = DSEldif(standalone) # Reload to get fresh data -- matching_rules = dse_ldif.get(parentid_dn, "nsMatchingRule") -- assert matching_rules is not None, "nsMatchingRule should be present" -- found_int_order = False -- for mr in matching_rules: -- if "integerorderingmatch" in mr.lower(): -- found_int_order = True -- break -- assert found_int_order, f"integerOrderingMatch should be present, got: {matching_rules}" -- log.info("integerOrderingMatch successfully added back") -+ log.info("Restore integerOrderingMatch and start the server") -+ dse_ldif = DSEldif(standalone) -+ dse_ldif.add(parentid_dn, "nsMatchingRule", "integerOrderingMatch") - - log.info("Start the server") - standalone.start() -@@ -1081,7 +1058,7 @@ def test_index_check_fixes_multiple_issues(topology_st): - :steps: - 1. Create DS instance - 2. Stop the server -- 3. Add multiple issues: scanlimit, ancestorid config, missing matching rule -+ 3. Add multiple issues: scanlimit and ancestorid config - 4. Run dsctl index-check (should detect all issues) - 5. Run dsctl index-check --fix - 6. Verify all issues were fixed -@@ -1123,14 +1100,6 @@ def test_index_check_fixes_multiple_issues(topology_st): - ] - dse_ldif.add_entry(ancestorid_entry) - -- log.info("Add issue 3: Remove integerOrderingMatch from parentid") -- dse_ldif = DSEldif(standalone) # Reload -- matching_rules = dse_ldif.get(parentid_dn, "nsMatchingRule") -- if matching_rules: -- for mr in matching_rules: -- if "integerorderingmatch" in mr.lower(): -- dse_ldif.delete(parentid_dn, "nsMatchingRule", mr) -- - log.info("Run index-check without --fix (should detect all issues)") - args = FakeArgs() - args.backend = "userRoot" -@@ -1161,16 +1130,6 @@ def test_index_check_fixes_multiple_issues(topology_st): - cn_value = dse_ldif.get(ancestorid_dn, "cn", single=True) - assert cn_value is None, f"ancestorid config should be removed, got: {cn_value}" - -- # Check matching rule added back -- matching_rules = dse_ldif.get(parentid_dn, "nsMatchingRule") -- found_int_order = False -- if matching_rules: -- for mr in matching_rules: -- if "integerorderingmatch" in mr.lower(): -- found_int_order = True -- break -- assert found_int_order, f"integerOrderingMatch should be present, got: {matching_rules}" -- - log.info("All issues verified as fixed") - - log.info("Run index-check again to confirm all clear") -diff --git a/ldap/servers/slapd/upgrade.c b/ldap/servers/slapd/upgrade.c -index d9156cae9..537c38feb 100644 ---- a/ldap/servers/slapd/upgrade.c -+++ b/ldap/servers/slapd/upgrade.c -@@ -500,107 +500,6 @@ upgrade_remove_ancestorid_index_config(void) - return uresult; - } - --/* -- * Check if parentid/ancestorid indexes are missing the integerOrderingMatch -- * matching rule. -- * -- * This function logs a warning if we detect this condition, advising -- * the administrator to reindex the affected attributes. -- */ --static upgrade_status --upgrade_check_id_index_matching_rule(void) --{ -- struct slapi_pblock *pb = slapi_pblock_new(); -- Slapi_Entry **backends = NULL; -- const char *be_base_dn = "cn=ldbm database,cn=plugins,cn=config"; -- const char *be_filter = "(objectclass=nsBackendInstance)"; -- const char *attrs_to_check[] = {"parentid", NULL}; -- upgrade_status uresult = UPGRADE_SUCCESS; -- -- /* Search for all backend instances */ -- slapi_search_internal_set_pb( -- pb, be_base_dn, -- LDAP_SCOPE_ONELEVEL, -- be_filter, NULL, 0, NULL, NULL, -- plugin_get_default_component_id(), 0); -- slapi_search_internal_pb(pb); -- slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &backends); -- -- if (backends) { -- for (size_t be_idx = 0; backends[be_idx] != NULL; be_idx++) { -- const char *be_dn = slapi_entry_get_dn_const(backends[be_idx]); -- const char *be_name = slapi_entry_attr_get_ref(backends[be_idx], "cn"); -- if (!be_dn || !be_name) { -- continue; -- } -- -- /* Check each attribute that should have integerOrderingMatch */ -- for (size_t attr_idx = 0; attrs_to_check[attr_idx] != NULL; attr_idx++) { -- const char *attr_name = attrs_to_check[attr_idx]; -- struct slapi_pblock *idx_pb = slapi_pblock_new(); -- Slapi_Entry **idx_entries = NULL; -- char *idx_dn = slapi_create_dn_string("cn=%s,cn=index,%s", -- attr_name, be_dn); -- char *idx_filter = "(objectclass=nsIndex)"; -- PRBool has_matching_rule = PR_FALSE; -- -- if (!idx_dn) { -- slapi_pblock_destroy(idx_pb); -- continue; -- } -- -- slapi_search_internal_set_pb( -- idx_pb, idx_dn, -- LDAP_SCOPE_BASE, -- idx_filter, NULL, 0, NULL, NULL, -- plugin_get_default_component_id(), 0); -- slapi_search_internal_pb(idx_pb); -- slapi_pblock_get(idx_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &idx_entries); -- -- if (idx_entries && idx_entries[0]) { -- /* Index exists, check if it has integerOrderingMatch */ -- Slapi_Attr *mr_attr = NULL; -- if (slapi_entry_attr_find(idx_entries[0], "nsMatchingRule", &mr_attr) == 0) { -- Slapi_Value *sval = NULL; -- int idx; -- for (idx = slapi_attr_first_value(mr_attr, &sval); -- idx != -1; -- idx = slapi_attr_next_value(mr_attr, idx, &sval)) { -- const struct berval *bval = slapi_value_get_berval(sval); -- if (bval && bval->bv_val && -- strcasecmp(bval->bv_val, "integerOrderingMatch") == 0) { -- has_matching_rule = PR_TRUE; -- break; -- } -- } -- } -- -- if (!has_matching_rule) { -- /* Index exists but doesn't have integerOrderingMatch, log a warning */ -- slapi_log_err(SLAPI_LOG_ERR, "upgrade_check_id_index_matching_rule", -- "Index '%s' in backend '%s' is missing 'nsMatchingRule: integerOrderingMatch'. " -- "Incorrectly configured system indexes can lead to poor search performance, replication issues, and other operational problems. " -- "To fix this, add the matching rule and reindex: " -- "dsconf backend index set --add-mr integerOrderingMatch --attr %s %s && " -- "dsconf backend index reindex --attr %s %s. " -- "WARNING: Reindexing can be resource-intensive and may impact server performance on a live system. " -- "Consider scheduling reindexing during maintenance windows or periods of low activity.\n", -- attr_name, be_name, attr_name, be_name, attr_name, be_name); -- } -- } -- -- slapi_ch_free_string(&idx_dn); -- slapi_free_search_results_internal(idx_pb); -- slapi_pblock_destroy(idx_pb); -- } -- } -- } -- -- slapi_free_search_results_internal(pb); -- slapi_pblock_destroy(pb); -- -- return uresult; --} - - upgrade_status - upgrade_server(void) -@@ -637,10 +536,6 @@ upgrade_server(void) - return UPGRADE_FAILURE; - } - -- if (upgrade_check_id_index_matching_rule() != UPGRADE_SUCCESS) { -- return UPGRADE_FAILURE; -- } -- - return UPGRADE_SUCCESS; - } - -diff --git a/rpm/389-ds-base.spec.in b/rpm/389-ds-base.spec.in -index 0175dfa7c..f78258f6a 100644 ---- a/rpm/389-ds-base.spec.in -+++ b/rpm/389-ds-base.spec.in -@@ -667,9 +667,6 @@ for dir in "$instbase"/slapd-* ; do - else - echo "instance $inst is not running" >> "$output" 2>&1 || : - fi -- # Run index-check on all instances (running or not) -- # This fixes index ordering mismatches from older versions -- dsctl "$inst_name" index-check --fix >> "$output2" 2>&1 || : - ninst=$((ninst + 1)) - done - -diff --git a/src/lib389/lib389/backend.py b/src/lib389/lib389/backend.py -index 1d9be4683..29a1796ac 100644 ---- a/src/lib389/lib389/backend.py -+++ b/src/lib389/lib389/backend.py -@@ -617,9 +617,10 @@ class Backend(DSLdapObject): - # Default system indexes taken from ldap/servers/slapd/back-ldbm/instance.c - # Note: entryrdn and ancestorid are internal system indexes that are not - # exposed in cn=config - they are managed internally by the server. -- # Only parentid has a DSE config entry (for the integerOrderingMatch rule). -+ # parentid works correctly with both lexicographic and integer ordering, -+ # so integerOrderingMatch is not required. - expected_system_indexes = { -- 'parentid': {'types': ['eq'], 'matching_rule': 'integerOrderingMatch'}, -+ 'parentid': {'types': ['eq'], 'matching_rule': None}, - 'objectClass': {'types': ['eq'], 'matching_rule': None}, - 'aci': {'types': ['pres'], 'matching_rule': None}, - 'nscpEntryDN': {'types': ['eq'], 'matching_rule': None}, -diff --git a/src/lib389/lib389/cli_ctl/dbtasks.py b/src/lib389/lib389/cli_ctl/dbtasks.py -index cd96cdaf7..b02de203f 100644 ---- a/src/lib389/lib389/cli_ctl/dbtasks.py -+++ b/src/lib389/lib389/cli_ctl/dbtasks.py -@@ -10,6 +10,7 @@ - import glob - import os - import re -+import signal - import subprocess - from enum import Enum - from lib389._constants import TaskWarning -@@ -263,45 +264,53 @@ def _check_disk_ordering(db_dir, backend, index_name, dbscan_path, is_mdb, log): - if not index_file: - return IndexOrdering.UNKNOWN - -+ # Only read the first 100 lines from dbscan to avoid scanning the -+ # entire index (which can take hours on large databases). - try: -- result = subprocess.run( -+ proc = subprocess.Popen( - [dbscan_path, "-f", index_file], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - universal_newlines=True, -- timeout=60, - ) - -- if result.returncode != 0: -- log.warning(" dbscan returned non-zero exit code for %s", index_file) -- return IndexOrdering.UNKNOWN -- -- # Parse keys from dbscan output - keys = [] -- for line in result.stdout.split("\n"): -+ line_count = 0 -+ assert proc.stdout is not None -+ for line in proc.stdout: -+ line_count += 1 -+ if line_count > 100: -+ break - line = line.strip() - if line.startswith("="): - match = re.match(r"^=(\d+)", line) - if match: - keys.append(int(match.group(1))) - -+ proc.terminate() -+ try: -+ proc.wait(timeout=5) -+ except subprocess.TimeoutExpired: -+ proc.kill() -+ proc.wait() -+ -+ if proc.returncode not in (0, -signal.SIGTERM): -+ log.warning(" dbscan returned non-zero exit code for %s", index_file) -+ return IndexOrdering.UNKNOWN -+ - if len(keys) < 2: - return IndexOrdering.UNKNOWN - - # Check if keys are in integer order by looking for decreasing numeric values - # (which would indicate lexicographic ordering, e.g., "3" < "30" < "4") - prev_id = keys[0] -- for i in range(1, min(len(keys), 100)): -- current_id = keys[i] -+ for current_id in keys[1:]: - if prev_id > current_id: - return IndexOrdering.LEXICOGRAPHIC - prev_id = current_id - - return IndexOrdering.INTEGER - -- except subprocess.TimeoutExpired: -- log.warning(" dbscan timed out for %s", index_file) -- return IndexOrdering.UNKNOWN - except OSError as e: - log.warning(" Error running dbscan: %s", e) - return IndexOrdering.UNKNOWN -@@ -375,8 +384,7 @@ def dbtasks_index_check(inst, log, args): - - # Track all issues found - all_ok = True -- mismatches = [] # (backend, index_name) tuples needing reindex -- missing_matching_rules = [] # (backend, index_name) tuples missing integerOrderingMatch -+ config_fixes = [] # (backend, index_name, action) tuples: action is "add_mr" or "remove_mr" - scan_limits_to_remove = [] # (backend, index_name) tuples with nsIndexIDListScanLimit - ancestorid_configs_to_remove = [] # backend names with ancestorid config entries - remove_ancestorid_from_defaults = False # Flag to remove from cn=default indexes -@@ -409,13 +417,6 @@ def dbtasks_index_check(inst, log, args): - - if disk_ordering == IndexOrdering.UNKNOWN: - log.info(" %s - could not determine disk ordering, skipping", index_name) -- # For parentid, still check if matching rule is missing -- if index_name == "parentid": -- config_has_int_order = _has_integer_ordering_match(dse_ldif, backend, index_name) -- if not config_has_int_order: -- log.warning(" %s - missing integerOrderingMatch in config", index_name) -- missing_matching_rules.append((backend, index_name)) -- all_ok = False - continue - - config_has_int_order = _has_integer_ordering_match(dse_ldif, backend, index_name) -@@ -423,18 +424,15 @@ def dbtasks_index_check(inst, log, args): - log.info(" %s - config: %s, disk: %s", - index_name, config_desc, disk_ordering.value) - -- # For parentid, the desired state is always integer ordering -+ # Both orderings are valid for parentid, but config must match disk. - if index_name == "parentid": -- if not config_has_int_order: -- log.warning(" %s - missing integerOrderingMatch in config", index_name) -- if (backend, index_name) not in missing_matching_rules: -- missing_matching_rules.append((backend, index_name)) -+ if config_has_int_order and disk_ordering == IndexOrdering.LEXICOGRAPHIC: -+ log.warning(" %s - MISMATCH: config has integerOrderingMatch but disk is lexicographic", index_name) -+ config_fixes.append((backend, index_name, "remove_mr")) - all_ok = False -- -- if disk_ordering == IndexOrdering.LEXICOGRAPHIC: -- log.warning(" %s - disk ordering is lexicographic, needs reindex", index_name) -- if (backend, index_name) not in mismatches: -- mismatches.append((backend, index_name)) -+ elif not config_has_int_order and disk_ordering == IndexOrdering.INTEGER: -+ log.warning(" %s - MISMATCH: config is lexicographic but disk has integer ordering", index_name) -+ config_fixes.append((backend, index_name, "add_mr")) - all_ok = False - - # Handle issues -@@ -480,26 +478,27 @@ def dbtasks_index_check(inst, log, args): - log.error(" Failed to remove ancestorid config from backend %s: %s", backend, e) - return False - -- # Add missing matching rules to dse.ldif -- for backend, index_name in missing_matching_rules: -+ # Fix config-vs-disk ordering mismatches by adjusting config to match disk -+ for backend, index_name, action in config_fixes: - index_dn = "cn={},cn=index,cn={},cn=ldbm database,cn=plugins,cn=config".format( - index_name, backend - ) -- log.info(" Adding integerOrderingMatch to %s in backend %s...", index_name, backend) -- try: -- dse_ldif.add(index_dn, "nsMatchingRule", "integerOrderingMatch") -- log.info(" Updated dse.ldif with integerOrderingMatch for %s", index_name) -- except Exception as e: -- log.error(" Failed to update dse.ldif for %s: %s", index_name, e) -- return False -- -- # Reindex indexes with disk ordering issues -- for backend, index_name in mismatches: -- log.info(" Reindexing %s in backend %s...", index_name, backend) -- if not inst.db2index(bename=backend, attrs=[index_name]): -- log.error(" Failed to reindex %s", index_name) -- return False -- log.info(" Reindex of %s completed successfully", index_name) -+ if action == "add_mr": -+ log.info(" Adding integerOrderingMatch to %s in backend %s...", index_name, backend) -+ try: -+ dse_ldif.add(index_dn, "nsMatchingRule", "integerOrderingMatch") -+ log.info(" Updated dse.ldif with integerOrderingMatch for %s", index_name) -+ except Exception as e: -+ log.error(" Failed to update dse.ldif for %s: %s", index_name, e) -+ return False -+ elif action == "remove_mr": -+ log.info(" Removing integerOrderingMatch from %s in backend %s...", index_name, backend) -+ try: -+ dse_ldif.delete(index_dn, "nsMatchingRule", "integerOrderingMatch") -+ log.info(" Removed integerOrderingMatch from %s", index_name) -+ except Exception as e: -+ log.error(" Failed to remove integerOrderingMatch from %s: %s", index_name, e) -+ return False - - log.info("All issues fixed") - return True -@@ -563,5 +562,5 @@ def create_parser(subcommands): - index_check_parser.add_argument('backend', nargs='?', default=None, - help="Backend to check. If not specified, all backends are checked.") - index_check_parser.add_argument('--fix', action='store_true', default=False, -- help="Fix mismatches by reindexing affected indexes") -+ help="Fix mismatches by adjusting config to match on-disk data") - index_check_parser.set_defaults(func=dbtasks_index_check) --- -2.52.0 - diff --git a/0033-Issue-7053-Remove-memberof_del_dn_from_groups-from-M.patch b/0033-Issue-7053-Remove-memberof_del_dn_from_groups-from-M.patch deleted file mode 100644 index adbc1fb..0000000 --- a/0033-Issue-7053-Remove-memberof_del_dn_from_groups-from-M.patch +++ /dev/null @@ -1,202 +0,0 @@ -From 31bef3852f7064c73f66974d7c41262d2a724eab Mon Sep 17 00:00:00 2001 -From: Alex Kulberg -Date: Tue, 9 Dec 2025 17:11:56 +0300 -Subject: [PATCH] Issue 7053 - Remove memberof_del_dn_from_groups from MemberOf - plugin (#7064) - -Bug Description: - -The member plugin creates redundant changes to the member attribute -in groups when deleting a user, although the referential integrity -of the member attribute should be controlled by the Referential Integrity plugin. -Furthermore, memberof doesn't take replication of operations into account -and performs the change on every server instance in the topology. - -Fix Description: - -Remove the `memberof_del_dn_from_groups` function from the MemberOf plugin, -completely transferring responsibility for deleting users from groups -to the Referential Integrity plugin. - -Relates: https://github.com/389ds/389-ds-base/issues/7053 - -Reviewed by: @tbordaz ---- - .../memberof_include_scopes_test.py | 13 ++- - ldap/servers/plugins/memberof/memberof.c | 79 ------------------- - 2 files changed, 9 insertions(+), 83 deletions(-) - -diff --git a/dirsrvtests/tests/suites/memberof_plugin/memberof_include_scopes_test.py b/dirsrvtests/tests/suites/memberof_plugin/memberof_include_scopes_test.py -index e1d3b0a96..347eb880f 100644 ---- a/dirsrvtests/tests/suites/memberof_plugin/memberof_include_scopes_test.py -+++ b/dirsrvtests/tests/suites/memberof_plugin/memberof_include_scopes_test.py -@@ -13,7 +13,7 @@ import time - from lib389.utils import ensure_str - from lib389.topologies import topology_st as topo - from lib389._constants import * --from lib389.plugins import MemberOfPlugin -+from lib389.plugins import MemberOfPlugin, ReferentialIntegrityPlugin - from lib389.idm.user import UserAccount, UserAccounts - from lib389.idm.group import Group, Groups - from lib389.idm.nscontainer import nsContainers -@@ -77,6 +77,13 @@ def test_multiple_scopes(topo): - - inst = topo.standalone - -+ EXCLUDED_SUBTREE = 'cn=exclude,%s' % SUFFIX -+ # enable Referential Integrity plugin -+ # to correctly process the 'member' attribute -+ refint = ReferentialIntegrityPlugin(inst) -+ refint.add_excludescope(EXCLUDED_SUBTREE) -+ refint.enable() -+ - # configure plugin - memberof = MemberOfPlugin(inst) - memberof.enable() -@@ -106,7 +113,6 @@ def test_multiple_scopes(topo): - check_membership(inst, f'uid=test_m3,{SUBTREE_3}', f'cn=g3,{SUBTREE_3}', False) - - # Set exclude scope -- EXCLUDED_SUBTREE = 'cn=exclude,%s' % SUFFIX - EXCLUDED_USER = f"uid=test_m1,{EXCLUDED_SUBTREE}" - INCLUDED_USER = f"uid=test_m1,{SUBTREE_1}" - GROUP_DN = f'cn=g1,{SUBTREE_1}' -@@ -122,9 +128,8 @@ def test_multiple_scopes(topo): - # Check memberOf and group are cleaned up - check_membership(inst, EXCLUDED_USER, GROUP_DN, False) - group = Group(topo.standalone, dn=GROUP_DN) -- assert not group.present("member", EXCLUDED_USER) - assert not group.present("member", INCLUDED_USER) -- -+ assert not group.present("member", EXCLUDED_USER) - - if __name__ == '__main__': - # Run isolated -diff --git a/ldap/servers/plugins/memberof/memberof.c b/ldap/servers/plugins/memberof/memberof.c -index c4b5afee7..5de2e9e72 100644 ---- a/ldap/servers/plugins/memberof/memberof.c -+++ b/ldap/servers/plugins/memberof/memberof.c -@@ -151,7 +151,6 @@ static void memberof_set_plugin_id(void *plugin_id); - static int memberof_compare(MemberOfConfig *config, const void *a, const void *b); - static int memberof_qsort_compare(const void *a, const void *b); - static void memberof_load_array(Slapi_Value **array, Slapi_Attr *attr); --static int memberof_del_dn_from_groups(Slapi_PBlock *pb, MemberOfConfig *config, Slapi_Entry *e, Slapi_DN *sdn); - static int memberof_call_foreach_dn(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_DN *sdn, MemberOfConfig *config, char **types, plugin_search_entry_callback callback, void *callback_data, int *cached, PRBool use_grp_cache); - static int memberof_is_direct_member(MemberOfConfig *config, Slapi_Value *groupdn, Slapi_Value *memberdn); - static int memberof_is_grouping_attr(char *type, MemberOfConfig *config); -@@ -540,21 +539,6 @@ deferred_modrdn_func(MemberofDeferredModrdnTask *task) - * attributes to refer to the new name. */ - if (ret == LDAP_SUCCESS && pre_sdn && post_sdn) { - if (!memberof_entry_in_scope(&configCopy, &post_entry_info)) { -- /* -- * After modrdn the group contains both the pre and post DN's as -- * members, so we need to cleanup both in this case. -- */ -- if ((ret = memberof_del_dn_from_groups(pb, &configCopy, pre_e, pre_sdn))) { -- slapi_log_err(SLAPI_LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM, -- "deferred_modrdn_func - Delete dn failed for preop entry(%s), error (%d)\n", -- slapi_sdn_get_dn(pre_sdn), ret); -- } -- if ((ret = memberof_del_dn_from_groups(pb, &configCopy, post_e, post_sdn))) { -- slapi_log_err(SLAPI_LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM, -- "deferred_modrdn_func - Delete dn failed for postop entry(%s), error (%d)\n", -- slapi_sdn_get_dn(post_sdn), ret); -- } -- - if (ret == LDAP_SUCCESS && pre_e && configCopy.group_filter && - 0 == slapi_filter_test_simple(pre_e, configCopy.group_filter)) - { -@@ -638,16 +622,6 @@ deferred_del_func(MemberofDeferredDelTask *task) - free_configCopy = PR_TRUE; - memberof_unlock_config(); - -- /* remove this DN from the -- * membership lists of groups -- */ -- if ((ret = memberof_del_dn_from_groups(pb, &configCopy, e, sdn))) { -- slapi_log_err(SLAPI_LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM, -- "deferred_del_func - Error deleting dn (%s) from group. Error (%d)\n", -- slapi_sdn_get_dn(sdn), ret); -- goto bail; -- } -- - /* is the entry of interest as a group? */ - if (e && configCopy.group_filter && 0 == slapi_filter_test_simple(e, configCopy.group_filter)) { - Slapi_Attr *attr = 0; -@@ -1456,16 +1430,6 @@ memberof_postop_del(Slapi_PBlock *pb) - memberof_copy_config(&configCopy, memberof_get_config()); - memberof_unlock_config(); - -- /* remove this DN from the -- * membership lists of groups -- */ -- if ((ret = memberof_del_dn_from_groups(pb, &configCopy, e, sdn))) { -- slapi_log_err(SLAPI_LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM, -- "memberof_postop_del - Error deleting dn (%s) from group. Error (%d)\n", -- slapi_sdn_get_dn(sdn), ret); -- goto bail; -- } -- - /* is the entry of interest as a group? */ - if (e && configCopy.group_filter && 0 == slapi_filter_test_simple(e, configCopy.group_filter)) { - Slapi_Attr *attr = 0; -@@ -1496,34 +1460,6 @@ done: - } - - --/* Deletes a member dn from all groups that refer to it. */ --static int --memberof_del_dn_from_groups(Slapi_PBlock *pb, MemberOfConfig *config, Slapi_Entry *e, Slapi_DN *sdn) --{ -- char *groupattrs[2] = {0, 0}; -- int rc = LDAP_SUCCESS; -- int cached = 0; -- -- /* Loop through each grouping attribute to find groups that have -- * dn as a member. For any matches, delete the dn value from the -- * same grouping attribute. */ -- for (size_t i = 0; config->groupattrs && config->groupattrs[i] && rc == LDAP_SUCCESS; i++) { -- memberof_del_dn_data data = {(char *)slapi_sdn_get_dn(sdn), -- config->groupattrs[i], config}; -- -- groupattrs[0] = config->groupattrs[i]; -- -- slapi_log_err(SLAPI_LOG_PLUGIN, MEMBEROF_PLUGIN_SUBSYSTEM, -- "memberof_del_dn_from_groups: Ancestors of %s attr: %s\n", -- slapi_sdn_get_dn(sdn), -- groupattrs[0]); -- rc = memberof_call_foreach_dn(pb, e, sdn, config, groupattrs, -- memberof_del_dn_type_callback, &data, &cached, PR_FALSE); -- } -- -- return rc; --} -- - int - memberof_del_dn_type_callback(Slapi_Entry *e, void *callback_data) - { -@@ -1904,21 +1840,6 @@ memberof_postop_modrdn(Slapi_PBlock *pb) - * attributes to refer to the new name. */ - if (ret == LDAP_SUCCESS && pre_sdn && post_sdn) { - if (!memberof_entry_in_scope(&configCopy, &post_entry_info)) { -- /* -- * After modrdn the group contains both the pre and post DN's as -- * members, so we need to cleanup both in this case. -- */ -- if ((ret = memberof_del_dn_from_groups(pb, &configCopy, pre_e, pre_sdn))) { -- slapi_log_err(SLAPI_LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM, -- "memberof_postop_modrdn - Delete dn failed for preop entry(%s), error (%d)\n", -- slapi_sdn_get_dn(pre_sdn), ret); -- } -- if ((ret = memberof_del_dn_from_groups(pb, &configCopy, post_e, post_sdn))) { -- slapi_log_err(SLAPI_LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM, -- "memberof_postop_modrdn - Delete dn failed for postop entry(%s), error (%d)\n", -- slapi_sdn_get_dn(post_sdn), ret); -- } -- - if (ret == LDAP_SUCCESS && pre_e && configCopy.group_filter && - 0 == slapi_filter_test_simple(pre_e, configCopy.group_filter)) { - /* is the entry of interest as a group? */ --- -2.52.0 - diff --git a/0034-Issue-5853-Update-concread-to-0.5.10.patch b/0034-Issue-5853-Update-concread-to-0.5.10.patch deleted file mode 100644 index 038ba0f..0000000 --- a/0034-Issue-5853-Update-concread-to-0.5.10.patch +++ /dev/null @@ -1,952 +0,0 @@ -From 0c5f7b9909ababc53e73e9469da6e30b81637cd0 Mon Sep 17 00:00:00 2001 -From: Viktor Ashirov -Date: Mon, 23 Feb 2026 09:49:52 +0100 -Subject: [PATCH] Issue 5853 - Update concread to 0.5.10 - -Description: -Update concread to 0.5.10 and update Cargo.lock - -Relates: https://github.com/389ds/389-ds-base/issues/5853 - -Reviewed by: @droideck (Thanks!) ---- - src/Cargo.lock | 515 +++++++++++++++++++++++---------------- - src/librslapd/Cargo.toml | 2 +- - 2 files changed, 312 insertions(+), 205 deletions(-) - -diff --git a/src/Cargo.lock b/src/Cargo.lock -index 87aeee852..425371478 100644 ---- a/src/Cargo.lock -+++ b/src/Cargo.lock -@@ -2,27 +2,18 @@ - # It is not intended for manual editing. - version = 3 - --[[package]] --name = "addr2line" --version = "0.24.2" --source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" --dependencies = [ -- "gimli", --] -- --[[package]] --name = "adler2" --version = "2.0.1" --source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" -- - [[package]] - name = "allocator-api2" - version = "0.2.21" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" - -+[[package]] -+name = "anyhow" -+version = "1.0.102" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" -+ - [[package]] - name = "atty" - version = "0.2.14" -@@ -40,21 +31,6 @@ version = "1.5.0" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" - --[[package]] --name = "backtrace" --version = "0.3.75" --source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" --dependencies = [ -- "addr2line", -- "cfg-if", -- "libc", -- "miniz_oxide", -- "object", -- "rustc-demangle", -- "windows-targets", --] -- - [[package]] - name = "base64" - version = "0.13.1" -@@ -69,9 +45,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - - [[package]] - name = "bitflags" --version = "2.9.1" -+version = "2.11.0" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" -+checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" - - [[package]] - name = "byteorder" -@@ -86,8 +62,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "da6bc11b07529f16944307272d5bd9b22530bc7d05751717c9d416586cedab49" - dependencies = [ - "clap", -- "heck", -- "indexmap", -+ "heck 0.4.1", -+ "indexmap 1.9.3", - "log", - "proc-macro2", - "quote", -@@ -100,10 +76,11 @@ dependencies = [ - - [[package]] - name = "cc" --version = "1.2.27" -+version = "1.2.56" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" -+checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" - dependencies = [ -+ "find-msvc-tools", - "jobserver", - "libc", - "shlex", -@@ -111,9 +88,9 @@ dependencies = [ - - [[package]] - name = "cfg-if" --version = "1.0.1" -+version = "1.0.4" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" -+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - - [[package]] - name = "clap" -@@ -124,7 +101,7 @@ dependencies = [ - "atty", - "bitflags 1.3.2", - "clap_lex", -- "indexmap", -+ "indexmap 1.9.3", - "strsim", - "termcolor", - "textwrap", -@@ -141,14 +118,14 @@ dependencies = [ - - [[package]] - name = "concread" --version = "0.5.6" -+version = "0.5.10" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "7b639eeaa550eba0c8be45b292d5e272e6d29bfdffb4df6925d651ed9ed10fd6" -+checksum = "6588e9e68e11207fb9a5aabd88765187969e6bcba98763c40bcad87b2a73e9f5" - dependencies = [ - "crossbeam-epoch", - "crossbeam-queue", - "crossbeam-utils", -- "foldhash", -+ "foldhash 0.2.0", - "lru", - "smallvec", - "sptr", -@@ -210,9 +187,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - - [[package]] - name = "errno" --version = "0.3.12" -+version = "0.3.14" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" -+checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" - dependencies = [ - "libc", - "windows-sys", -@@ -232,17 +209,29 @@ checksum = "93804560e638370a8be6d59ce71ed803e55e230abdbf42598e666b41adda9b1f" - dependencies = [ - "base64", - "byteorder", -- "getrandom 0.2.16", -+ "getrandom 0.2.17", - "openssl", - "zeroize", - ] - -+[[package]] -+name = "find-msvc-tools" -+version = "0.1.9" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" -+ - [[package]] - name = "foldhash" - version = "0.1.5" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - -+[[package]] -+name = "foldhash" -+version = "0.2.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" -+ - [[package]] - name = "foreign-types" - version = "0.3.2" -@@ -260,32 +249,39 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - - [[package]] - name = "getrandom" --version = "0.2.16" -+version = "0.2.17" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" -+checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" - dependencies = [ - "cfg-if", - "libc", -- "wasi 0.11.1+wasi-snapshot-preview1", -+ "wasi", - ] - - [[package]] - name = "getrandom" --version = "0.3.3" -+version = "0.3.4" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" -+checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" - dependencies = [ - "cfg-if", - "libc", - "r-efi", -- "wasi 0.14.2+wasi-0.2.4", -+ "wasip2", - ] - - [[package]] --name = "gimli" --version = "0.31.1" -+name = "getrandom" -+version = "0.4.1" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" -+checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" -+dependencies = [ -+ "cfg-if", -+ "libc", -+ "r-efi", -+ "wasip2", -+ "wasip3", -+] - - [[package]] - name = "hashbrown" -@@ -295,13 +291,22 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - - [[package]] - name = "hashbrown" --version = "0.15.4" -+version = "0.15.5" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" -+checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" -+dependencies = [ -+ "foldhash 0.1.5", -+] -+ -+[[package]] -+name = "hashbrown" -+version = "0.16.1" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" - dependencies = [ - "allocator-api2", - "equivalent", -- "foldhash", -+ "foldhash 0.2.0", - ] - - [[package]] -@@ -310,6 +315,12 @@ version = "0.4.1" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -+[[package]] -+name = "heck" -+version = "0.5.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -+ - [[package]] - name = "hermit-abi" - version = "0.1.19" -@@ -319,6 +330,12 @@ dependencies = [ - "libc", - ] - -+[[package]] -+name = "id-arena" -+version = "2.3.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" -+ - [[package]] - name = "indexmap" - version = "1.9.3" -@@ -329,27 +346,45 @@ dependencies = [ - "hashbrown 0.12.3", - ] - -+[[package]] -+name = "indexmap" -+version = "2.13.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" -+dependencies = [ -+ "equivalent", -+ "hashbrown 0.16.1", -+ "serde", -+ "serde_core", -+] -+ - [[package]] - name = "itoa" --version = "1.0.15" -+version = "1.0.17" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" -+checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" - - [[package]] - name = "jobserver" --version = "0.1.33" -+version = "0.1.34" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" -+checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" - dependencies = [ -- "getrandom 0.3.3", -+ "getrandom 0.3.4", - "libc", - ] - -+[[package]] -+name = "leb128fmt" -+version = "0.1.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" -+ - [[package]] - name = "libc" --version = "0.2.174" -+version = "0.2.182" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" -+checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" - - [[package]] - name = "librnsslapd" -@@ -372,48 +407,30 @@ dependencies = [ - - [[package]] - name = "linux-raw-sys" --version = "0.9.4" -+version = "0.11.0" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" -+checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" - - [[package]] - name = "log" --version = "0.4.27" -+version = "0.4.29" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" -+checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" - - [[package]] - name = "lru" --version = "0.13.0" -+version = "0.16.3" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "227748d55f2f0ab4735d87fd623798cb6b664512fe979705f829c9f81c934465" -+checksum = "a1dc47f592c06f33f8e3aea9591776ec7c9f9e4124778ff8a3c3b87159f7e593" - dependencies = [ -- "hashbrown 0.15.4", -+ "hashbrown 0.16.1", - ] - - [[package]] - name = "memchr" --version = "2.7.5" --source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" -- --[[package]] --name = "miniz_oxide" --version = "0.8.9" --source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" --dependencies = [ -- "adler2", --] -- --[[package]] --name = "object" --version = "0.36.7" -+version = "2.8.0" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" --dependencies = [ -- "memchr", --] -+checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" - - [[package]] - name = "once_cell" -@@ -423,11 +440,11 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - - [[package]] - name = "openssl" --version = "0.10.73" -+version = "0.10.75" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" -+checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" - dependencies = [ -- "bitflags 2.9.1", -+ "bitflags 2.11.0", - "cfg-if", - "foreign-types", - "libc", -@@ -444,14 +461,14 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" - dependencies = [ - "proc-macro2", - "quote", -- "syn 2.0.103", -+ "syn 2.0.117", - ] - - [[package]] - name = "openssl-sys" --version = "0.9.109" -+version = "0.9.111" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" -+checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" - dependencies = [ - "cc", - "libc", -@@ -496,6 +513,16 @@ version = "0.3.32" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" - -+[[package]] -+name = "prettyplease" -+version = "0.2.37" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -+dependencies = [ -+ "proc-macro2", -+ "syn 2.0.117", -+] -+ - [[package]] - name = "proc-macro-hack" - version = "0.5.20+deprecated" -@@ -504,9 +531,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - - [[package]] - name = "proc-macro2" --version = "1.0.95" -+version = "1.0.106" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" -+checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" - dependencies = [ - "unicode-ident", - ] -@@ -526,9 +553,9 @@ dependencies = [ - - [[package]] - name = "quote" --version = "1.0.40" -+version = "1.0.44" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" -+checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" - dependencies = [ - "proc-macro2", - ] -@@ -539,19 +566,13 @@ version = "5.3.0" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" - --[[package]] --name = "rustc-demangle" --version = "0.1.25" --source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" -- - [[package]] - name = "rustix" --version = "1.0.7" -+version = "1.1.3" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" -+checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" - dependencies = [ -- "bitflags 2.9.1", -+ "bitflags 2.11.0", - "errno", - "libc", - "linux-raw-sys", -@@ -559,41 +580,52 @@ dependencies = [ - ] - - [[package]] --name = "ryu" --version = "1.0.20" -+name = "semver" -+version = "1.0.27" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" -+checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" - - [[package]] - name = "serde" --version = "1.0.219" -+version = "1.0.228" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" -+checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -+dependencies = [ -+ "serde_core", -+ "serde_derive", -+] -+ -+[[package]] -+name = "serde_core" -+version = "1.0.228" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" - dependencies = [ - "serde_derive", - ] - - [[package]] - name = "serde_derive" --version = "1.0.219" -+version = "1.0.228" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" -+checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" - dependencies = [ - "proc-macro2", - "quote", -- "syn 2.0.103", -+ "syn 2.0.117", - ] - - [[package]] - name = "serde_json" --version = "1.0.140" -+version = "1.0.149" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" -+checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" - dependencies = [ - "itoa", - "memchr", -- "ryu", - "serde", -+ "serde_core", -+ "zmij", - ] - - [[package]] -@@ -649,9 +681,9 @@ dependencies = [ - - [[package]] - name = "syn" --version = "2.0.103" -+version = "2.0.117" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8" -+checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" - dependencies = [ - "proc-macro2", - "quote", -@@ -660,12 +692,12 @@ dependencies = [ - - [[package]] - name = "tempfile" --version = "3.20.0" -+version = "3.25.0" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" -+checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1" - dependencies = [ - "fastrand", -- "getrandom 0.3.3", -+ "getrandom 0.4.1", - "once_cell", - "rustix", - "windows-sys", -@@ -688,11 +720,10 @@ checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" - - [[package]] - name = "tokio" --version = "1.45.1" -+version = "1.49.0" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" -+checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" - dependencies = [ -- "backtrace", - "pin-project-lite", - ] - -@@ -707,9 +738,9 @@ dependencies = [ - - [[package]] - name = "tracing" --version = "0.1.41" -+version = "0.1.44" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" -+checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" - dependencies = [ - "pin-project-lite", - "tracing-attributes", -@@ -718,29 +749,35 @@ dependencies = [ - - [[package]] - name = "tracing-attributes" --version = "0.1.30" -+version = "0.1.31" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" -+checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" - dependencies = [ - "proc-macro2", - "quote", -- "syn 2.0.103", -+ "syn 2.0.117", - ] - - [[package]] - name = "tracing-core" --version = "0.1.34" -+version = "0.1.36" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" -+checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" - dependencies = [ - "once_cell", - ] - - [[package]] - name = "unicode-ident" --version = "1.0.18" -+version = "1.0.24" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" -+checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" -+ -+[[package]] -+name = "unicode-xid" -+version = "0.2.6" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - - [[package]] - name = "uuid" -@@ -748,7 +785,7 @@ version = "0.8.2" - source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" - dependencies = [ -- "getrandom 0.2.16", -+ "getrandom 0.2.17", - ] - - [[package]] -@@ -764,12 +801,55 @@ source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" - - [[package]] --name = "wasi" --version = "0.14.2+wasi-0.2.4" -+name = "wasip2" -+version = "1.0.2+wasi-0.2.9" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" -+dependencies = [ -+ "wit-bindgen", -+] -+ -+[[package]] -+name = "wasip3" -+version = "0.4.0+wasi-0.3.0-rc-2026-01-06" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" -+dependencies = [ -+ "wit-bindgen", -+] -+ -+[[package]] -+name = "wasm-encoder" -+version = "0.244.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" -+dependencies = [ -+ "leb128fmt", -+ "wasmparser", -+] -+ -+[[package]] -+name = "wasm-metadata" -+version = "0.244.0" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" -+dependencies = [ -+ "anyhow", -+ "indexmap 2.13.0", -+ "wasm-encoder", -+ "wasmparser", -+] -+ -+[[package]] -+name = "wasmparser" -+version = "0.244.0" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" -+checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" - dependencies = [ -- "wit-bindgen-rt", -+ "bitflags 2.11.0", -+ "hashbrown 0.15.5", -+ "indexmap 2.13.0", -+ "semver", - ] - - [[package]] -@@ -790,9 +870,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - - [[package]] - name = "winapi-util" --version = "0.1.9" -+version = "0.1.11" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" -+checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" - dependencies = [ - "windows-sys", - ] -@@ -804,103 +884,130 @@ source = "registry+https://github.com/rust-lang/crates.io-index" - checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - - [[package]] --name = "windows-sys" --version = "0.59.0" -+name = "windows-link" -+version = "0.2.1" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" --dependencies = [ -- "windows-targets", --] -+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" - - [[package]] --name = "windows-targets" --version = "0.52.6" -+name = "windows-sys" -+version = "0.61.2" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" - dependencies = [ -- "windows_aarch64_gnullvm", -- "windows_aarch64_msvc", -- "windows_i686_gnu", -- "windows_i686_gnullvm", -- "windows_i686_msvc", -- "windows_x86_64_gnu", -- "windows_x86_64_gnullvm", -- "windows_x86_64_msvc", -+ "windows-link", - ] - - [[package]] --name = "windows_aarch64_gnullvm" --version = "0.52.6" -+name = "wit-bindgen" -+version = "0.51.0" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -- --[[package]] --name = "windows_aarch64_msvc" --version = "0.52.6" --source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -- --[[package]] --name = "windows_i686_gnu" --version = "0.52.6" --source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" -- --[[package]] --name = "windows_i686_gnullvm" --version = "0.52.6" --source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -+checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" -+dependencies = [ -+ "wit-bindgen-rust-macro", -+] - - [[package]] --name = "windows_i686_msvc" --version = "0.52.6" -+name = "wit-bindgen-core" -+version = "0.51.0" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -+checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" -+dependencies = [ -+ "anyhow", -+ "heck 0.5.0", -+ "wit-parser", -+] - - [[package]] --name = "windows_x86_64_gnu" --version = "0.52.6" -+name = "wit-bindgen-rust" -+version = "0.51.0" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -+checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" -+dependencies = [ -+ "anyhow", -+ "heck 0.5.0", -+ "indexmap 2.13.0", -+ "prettyplease", -+ "syn 2.0.117", -+ "wasm-metadata", -+ "wit-bindgen-core", -+ "wit-component", -+] - - [[package]] --name = "windows_x86_64_gnullvm" --version = "0.52.6" -+name = "wit-bindgen-rust-macro" -+version = "0.51.0" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -+checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" -+dependencies = [ -+ "anyhow", -+ "prettyplease", -+ "proc-macro2", -+ "quote", -+ "syn 2.0.117", -+ "wit-bindgen-core", -+ "wit-bindgen-rust", -+] - - [[package]] --name = "windows_x86_64_msvc" --version = "0.52.6" -+name = "wit-component" -+version = "0.244.0" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -+checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" -+dependencies = [ -+ "anyhow", -+ "bitflags 2.11.0", -+ "indexmap 2.13.0", -+ "log", -+ "serde", -+ "serde_derive", -+ "serde_json", -+ "wasm-encoder", -+ "wasm-metadata", -+ "wasmparser", -+ "wit-parser", -+] - - [[package]] --name = "wit-bindgen-rt" --version = "0.39.0" -+name = "wit-parser" -+version = "0.244.0" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -+checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" - dependencies = [ -- "bitflags 2.9.1", -+ "anyhow", -+ "id-arena", -+ "indexmap 2.13.0", -+ "log", -+ "semver", -+ "serde", -+ "serde_derive", -+ "serde_json", -+ "unicode-xid", -+ "wasmparser", - ] - - [[package]] - name = "zeroize" --version = "1.8.1" -+version = "1.8.2" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" -+checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" - dependencies = [ - "zeroize_derive", - ] - - [[package]] - name = "zeroize_derive" --version = "1.4.2" -+version = "1.4.3" - source = "registry+https://github.com/rust-lang/crates.io-index" --checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" -+checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" - dependencies = [ - "proc-macro2", - "quote", -- "syn 2.0.103", -+ "syn 2.0.117", - ] -+ -+[[package]] -+name = "zmij" -+version = "1.0.21" -+source = "registry+https://github.com/rust-lang/crates.io-index" -+checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" -diff --git a/src/librslapd/Cargo.toml b/src/librslapd/Cargo.toml -index f38f93f4c..61100f381 100644 ---- a/src/librslapd/Cargo.toml -+++ b/src/librslapd/Cargo.toml -@@ -16,7 +16,7 @@ crate-type = ["staticlib", "lib"] - [dependencies] - slapd = { path = "../slapd" } - libc = "0.2" --concread = "0.5.6" -+concread = "0.5.10" - - [build-dependencies] - cbindgen = "0.26" --- -2.53.0 - diff --git a/0035-Issue-7271-plugins-that-create-threads-need-to-updat.patch b/0035-Issue-7271-plugins-that-create-threads-need-to-updat.patch deleted file mode 100644 index 0bbd969..0000000 --- a/0035-Issue-7271-plugins-that-create-threads-need-to-updat.patch +++ /dev/null @@ -1,86 +0,0 @@ -From a3fd3897ede4166625194d48b010b6dbdcdf9f70 Mon Sep 17 00:00:00 2001 -From: Mark Reynolds -Date: Mon, 23 Feb 2026 12:37:26 -0500 -Subject: [PATCH] Issue 7271 - plugins that create threads need to update - active thread count - -Description: - -Plugins that create threads need to up to the global active thread count. -Otherwise when the server is being stopped the plugin's close function gets -called while these threads are still running and still using the plugin -configuration. This can lead to crashes. - -relates: https://github.com/389ds/389-ds-base/issues/7271 - -Reviewed by: progier & tbordaz (Thanks!!) ---- - ldap/servers/plugins/replication/repl5_protocol.c | 5 +++++ - ldap/servers/plugins/retrocl/retrocl_trim.c | 7 ++++++- - 2 files changed, 11 insertions(+), 1 deletion(-) - -diff --git a/ldap/servers/plugins/replication/repl5_protocol.c b/ldap/servers/plugins/replication/repl5_protocol.c -index 5d4a0e455..bc9580319 100644 ---- a/ldap/servers/plugins/replication/repl5_protocol.c -+++ b/ldap/servers/plugins/replication/repl5_protocol.c -@@ -23,6 +23,7 @@ - - #include "repl5.h" - #include "repl5_prot_private.h" -+#include "slap.h" - - #define PROTOCOL_5_INCREMENTAL 1 - #define PROTOCOL_5_TOTAL 2 -@@ -237,6 +238,8 @@ prot_thread_main(void *arg) - return; - } - -+ g_incr_active_threadcnt(); -+ - set_thread_private_agmtname(agmt_get_long_name(agmt)); - - done = 0; -@@ -301,6 +304,8 @@ prot_thread_main(void *arg) - done = 1; - } - } -+ -+ g_decr_active_threadcnt(); - } - - /* -diff --git a/ldap/servers/plugins/retrocl/retrocl_trim.c b/ldap/servers/plugins/retrocl/retrocl_trim.c -index 8fcd3d32b..8fdc75c62 100644 ---- a/ldap/servers/plugins/retrocl/retrocl_trim.c -+++ b/ldap/servers/plugins/retrocl/retrocl_trim.c -@@ -243,6 +243,8 @@ trim_changelog(void) - - now_interval = slapi_current_rel_time_t(); /* monotonic time for interval */ - -+ g_incr_active_threadcnt(); -+ - PR_Lock(ts.ts_s_trim_mutex); - max_age = ts.ts_c_max_age; - trim_interval = ts.ts_c_trim_interval; -@@ -257,7 +259,7 @@ trim_changelog(void) - */ - done = 0; - now_maxage = slapi_current_utc_time(); /* real time for trim candidates */ -- while (!done && retrocl_trimming == 1) { -+ while (!done && retrocl_trimming == 1 && !slapi_is_shutting_down()) { - int did_delete; - - did_delete = 0; -@@ -309,6 +311,9 @@ trim_changelog(void) - "trim_changelog: removed %d change records\n", - num_deleted); - } -+ -+ g_decr_active_threadcnt(); -+ - return rc; - } - --- -2.53.0 - diff --git a/0036-Security-fix-for-CVE-2025-14905.patch b/0036-Security-fix-for-CVE-2025-14905.patch deleted file mode 100644 index d889f57..0000000 --- a/0036-Security-fix-for-CVE-2025-14905.patch +++ /dev/null @@ -1,93 +0,0 @@ -From f4817944e43e080b1ab15c3fa13359252429e500 Mon Sep 17 00:00:00 2001 -From: tbordaz -Date: Wed, 25 Feb 2026 14:06:42 +0100 -Subject: [PATCH] Security fix for CVE-2025-14905 - -Description: - A vulnerability was found in the 389 Directory Server. - The 389 Directory Server present a risk of heap buffer overflow that - can be exploited to excute a Denial of Service and potential Remote - Code Execution - -References: - - https://access.redhat.com/security/cve/CVE-2025-14905 - - https://bugzilla.redhat.com/show_bug.cgi?id=2423624 ---- - ldap/servers/slapd/schema.c | 47 ++++++++++++++++++++++++++++++------- - 1 file changed, 38 insertions(+), 9 deletions(-) - -diff --git a/ldap/servers/slapd/schema.c b/ldap/servers/slapd/schema.c -index 9ef4ee4bf..7712a720d 100644 ---- a/ldap/servers/slapd/schema.c -+++ b/ldap/servers/slapd/schema.c -@@ -1410,6 +1410,7 @@ schema_attr_enum_callback(struct asyntaxinfo *asip, void *arg) - const char *attr_desc, *syntaxoid; - char *outp, syntaxlengthbuf[128]; - int i; -+ int nb_aliases = 0; - - vals[0] = &val; - -@@ -1435,6 +1436,7 @@ schema_attr_enum_callback(struct asyntaxinfo *asip, void *arg) - if (asip->asi_aliases != NULL) { - for (i = 0; asip->asi_aliases[i] != NULL; ++i) { - aliaslen += strlen(asip->asi_aliases[i]); -+ nb_aliases++; - } - } - -@@ -1452,15 +1454,42 @@ schema_attr_enum_callback(struct asyntaxinfo *asip, void *arg) - * XXX: 256 is a magic number... it must be big enough to account for - * all of the fixed sized items we output. - */ -- sizedbuffer_allocate(aew->psbAttrTypes, 256 + strlen(asip->asi_oid) + -- strlen(asip->asi_name) + -- aliaslen + strlen_null_ok(attr_desc) + -- strlen(syntaxoid) + -- strlen_null_ok(asip->asi_superior) + -- strlen_null_ok(asip->asi_mr_equality) + -- strlen_null_ok(asip->asi_mr_ordering) + -- strlen_null_ok(asip->asi_mr_substring) + -- strcat_extensions(NULL, asip->asi_extensions)); -+ { -+ int asi_oid_strlen = strlen(asip->asi_oid) + 8; /* "( %s NAME " */ -+ int asi_name_strlen = strlen(asip->asi_name) + 6; /* "( '%s' ...)" */ -+ int asi_aliases_strlen = aliaslen + nb_aliases * 3; /* "'%s' " */ -+ int asi_desc_strlen = strlen_null_ok(attr_desc) + 7; /* "DESC '%s'" */ -+ int asi_syntaxoid_strlen = strlen("SYNTAX ") + strlen(syntaxoid) + strlen(syntaxlengthbuf); -+ int asi_superior_strlen = strlen("SUP ") + strlen_null_ok(asip->asi_superior); -+ int asi_mr_equality_strlen = strlen("EQUALITY ") + strlen_null_ok(asip->asi_mr_equality); -+ int asi_mr_ordering_strlen = strlen("ORDERING ") + strlen_null_ok(asip->asi_mr_ordering); -+ int asi_mr_substring_strlen = strlen("SUBSTR ") + strlen_null_ok(asip->asi_mr_substring); -+ int asi_flags_strlen = strlen("SINGLE-VALUE ") + -+ strlen(schema_obsolete_with_spaces) + -+ strlen(schema_collective_with_spaces) + -+ strlen(schema_nousermod_with_spaces) + -+ strlen("USAGE distributedOperation ") + -+ strlen("USAGE dSAOperation ") + -+ strlen("USAGE directoryOperation "); -+ int asi_extension_strlen = strcat_extensions(NULL, asip->asi_extensions); -+ -+ if (aew->enquote_sup_oc) { -+ /* it enquote the syntax oid */ -+ asi_syntaxoid_strlen += 2; -+ } -+ -+ sizedbuffer_allocate(aew->psbAttrTypes, 256 + asi_oid_strlen + -+ asi_name_strlen + -+ asi_aliases_strlen + -+ asi_desc_strlen + -+ asi_syntaxoid_strlen + -+ asi_superior_strlen + -+ asi_mr_equality_strlen + -+ asi_mr_ordering_strlen + -+ asi_mr_substring_strlen + -+ asi_extension_strlen + -+ asi_flags_strlen); -+ } - - /* - * Overall strategy is to maintain a pointer to the next location in --- -2.53.0 - diff --git a/0037-Issue-7271-implement-a-pre-close-plugin-function.patch b/0037-Issue-7271-implement-a-pre-close-plugin-function.patch deleted file mode 100644 index cda832c..0000000 --- a/0037-Issue-7271-implement-a-pre-close-plugin-function.patch +++ /dev/null @@ -1,262 +0,0 @@ -From c6bb96c95dcbff0052fc2decab7020b0f833f313 Mon Sep 17 00:00:00 2001 -From: Mark Reynolds -Date: Mon, 2 Mar 2026 14:31:29 -0500 -Subject: [PATCH] Issue 7271 - implement a pre-close plugin function - -Description: - -replication protocol could benefit from being notifioed the shutdown process -has started before calling the "close" plugin function. This would allow the -replication protocol to wake up and adjust its active thread count to prevent -a hang during shutdown. - -relates: https://github.com/389ds/389-ds-base/issues/7271 - -Reviewed by: progier, spichugi, and vashirov(Thanks!!!) ---- - ldap/servers/plugins/replication/repl5_init.c | 19 ++++++++---- - ldap/servers/slapd/daemon.c | 6 +++- - ldap/servers/slapd/pblock.c | 30 +++++++++++++------ - ldap/servers/slapd/plugin.c | 24 ++++++++++++++- - ldap/servers/slapd/proto-slap.h | 3 +- - ldap/servers/slapd/slap.h | 3 +- - ldap/servers/slapd/slapi-plugin.h | 3 +- - 7 files changed, 69 insertions(+), 19 deletions(-) - -diff --git a/ldap/servers/plugins/replication/repl5_init.c b/ldap/servers/plugins/replication/repl5_init.c -index 5047fb8dc..395744db8 100644 ---- a/ldap/servers/plugins/replication/repl5_init.c -+++ b/ldap/servers/plugins/replication/repl5_init.c -@@ -1,6 +1,6 @@ - /** BEGIN COPYRIGHT BLOCK - * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. -- * Copyright (C) 2005 Red Hat, Inc. -+ * Copyright (C) 2026 Red Hat, Inc. - * All rights reserved. - * - * License: GPL (version 3 or any later version). -@@ -122,6 +122,8 @@ static PRUintn thread_private_agmtname; /* thread private index for logging*/ - static PRUintn thread_private_cache; - static PRUintn thread_primary_csn; - -+static int multisupplier_pre_stop(Slapi_PBlock *pb __attribute__((unused))); -+ - char * - get_thread_private_agmtname() - { -@@ -836,10 +838,6 @@ multisupplier_stop(Slapi_PBlock *pb __attribute__((unused))) - int rc = 0; /* OK */ - - if (!multisupplier_stopped_flag) { -- if (!is_ldif_dump) { -- /* Shut down replication agreements */ -- agmtlist_shutdown(); -- } - /* if we are cleaning a ruv, stop */ - stop_ruv_cleaning(); - /* unregister backend state change notification */ -@@ -853,6 +851,16 @@ multisupplier_stop(Slapi_PBlock *pb __attribute__((unused))) - return rc; - } - -+static int -+multisupplier_pre_stop(Slapi_PBlock *pb __attribute__((unused))) -+{ -+ if (!multisupplier_stopped_flag) { -+ /* Shut down replication agreements which will stop all the -+ * replication protocol threads */ -+ agmtlist_shutdown(); -+ } -+ return 0; -+} - - PRBool - multisupplier_started() -@@ -900,6 +908,7 @@ replication_multisupplier_plugin_init(Slapi_PBlock *pb) - rc = slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&multisupplierdesc); - rc = slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN, (void *)multisupplier_start); - rc = slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN, (void *)multisupplier_stop); -+ rc = slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_CLOSE_FN, (void *)multisupplier_pre_stop); - - /* Register the plugin interfaces we implement */ - /* preop acquires csn generator handle */ -diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c -index d6911f03c..7fc1a16f1 100644 ---- a/ldap/servers/slapd/daemon.c -+++ b/ldap/servers/slapd/daemon.c -@@ -1,6 +1,6 @@ - /** BEGIN COPYRIGHT BLOCK - * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. -- * Copyright (C) 2021 Red Hat, Inc. -+ * Copyright (C) 2026 Red Hat, Inc. - * All rights reserved. - * - * License: GPL (version 3 or any later version). -@@ -1216,6 +1216,10 @@ slapd_daemon(daemon_ports_t *ports) - task_cancel_all(); - } - -+ /* Call plugin pre close functions */ -+ plugin_pre_closeall(); -+ -+ /* Now wait for active threads to terminate */ - threads = g_get_active_threadcnt(); - if (threads > 0) { - slapi_log_err(SLAPI_LOG_INFO, "slapd_daemon", -diff --git a/ldap/servers/slapd/pblock.c b/ldap/servers/slapd/pblock.c -index 76e26cb86..90114dee1 100644 ---- a/ldap/servers/slapd/pblock.c -+++ b/ldap/servers/slapd/pblock.c -@@ -1,12 +1,12 @@ --/** BEGIN COPYRIGHT BLOCK -- * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. -- * Copyright (C) 2005-2025 Red Hat, Inc. -- * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. -- * All rights reserved. -- * -- * License: GPL (version 3 or any later version). -- * See LICENSE for details. -- * END COPYRIGHT BLOCK **/ -+ /** BEGIN COPYRIGHT BLOCK -+ * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. -+ * Copyright (C) 2026 Red Hat, Inc. -+ * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. -+ * All rights reserved. -+ * -+ * License: GPL (version 3 or any later version). -+ * See LICENSE for details. -+ * END COPYRIGHT BLOCK **/ - - #ifdef HAVE_CONFIG_H - #include -@@ -2524,6 +2524,14 @@ slapi_pblock_get(Slapi_PBlock *pblock, int arg, void *value) - } - break; - -+ case SLAPI_PLUGIN_PRE_CLOSE_FN: -+ if (pblock->pb_plugin != NULL) { -+ (*(IFP *)value) = pblock->pb_plugin->plg_pre_close; -+ } else { -+ (*(IFP *)value) = NULL; -+ } -+ break; -+ - default: - slapi_log_err(SLAPI_LOG_ERR, "slapi_pblock_get", "Unknown parameter block argument %d\n", arg); - PR_ASSERT(0); -@@ -4209,6 +4217,10 @@ slapi_pblock_set(Slapi_PBlock *pblock, int arg, void *value) - pblock->pb_misc->pb_aci_target_check = *((int *)value); - break; - -+ case SLAPI_PLUGIN_PRE_CLOSE_FN: -+ pblock->pb_plugin->plg_pre_close = (IFP)value; -+ break; -+ - default: - slapi_log_err(SLAPI_LOG_ERR, "slapi_pblock_set", - "Unknown parameter block argument %d\n", arg); -diff --git a/ldap/servers/slapd/plugin.c b/ldap/servers/slapd/plugin.c -index 52d25e19e..95b8de894 100644 ---- a/ldap/servers/slapd/plugin.c -+++ b/ldap/servers/slapd/plugin.c -@@ -1,6 +1,6 @@ - /** BEGIN COPYRIGHT BLOCK - * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. -- * Copyright (C) 2021 Red Hat, Inc. -+ * Copyright (C) 2026 Red Hat, Inc. - * All rights reserved. - * - * License: GPL (version 3 or any later version). -@@ -1847,6 +1847,28 @@ plugin_dependency_closeall(void) - } - } - -+/* Call the pre close functions of all the plugins */ -+void -+plugin_pre_closeall(void) -+{ -+ Slapi_PBlock *pb = NULL; -+ int plugins_pre_closed = 0; -+ int index = 0; -+ -+ while (plugins_pre_closed < global_plugins_started) { -+ if (global_plugin_shutdown_order[index].name) { -+ if (!global_plugin_shutdown_order[index].removed) { -+ pb = slapi_pblock_new(); -+ plugin_call_one(global_plugin_shutdown_order[index].plugin, -+ SLAPI_PLUGIN_PRE_CLOSE_FN, pb); -+ slapi_pblock_destroy(pb); -+ } -+ plugins_pre_closed++; -+ } -+ index++; -+ } -+} -+ - void - plugin_freeall(void) - { -diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h -index 742e3ee14..fd5bc6e71 100644 ---- a/ldap/servers/slapd/proto-slap.h -+++ b/ldap/servers/slapd/proto-slap.h -@@ -1,6 +1,6 @@ - /** BEGIN COPYRIGHT BLOCK - * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. -- * Copyright (C) 2021-2025 Red Hat, Inc. -+ * Copyright (C) 2026 Red Hat, Inc. - * All rights reserved. - * - * License: GPL (version 3 or any later version). -@@ -982,6 +982,7 @@ int plugin_call_exop_plugins(Slapi_PBlock *pb, struct slapdplugin *p); - Slapi_Backend *plugin_extended_op_getbackend(Slapi_PBlock *pb, struct slapdplugin *p); - const char *plugin_extended_op_oid2string(const char *oid); - void plugin_closeall(int close_backends, int close_globals); -+void plugin_pre_closeall(void); - void plugin_dependency_freeall(void); - void plugin_startall(int argc, char **argv, char **plugin_list); - void plugin_get_plugin_dependencies(char *plugin_name, char ***names); -diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h -index fee5a6ab5..64f9f465b 100644 ---- a/ldap/servers/slapd/slap.h -+++ b/ldap/servers/slapd/slap.h -@@ -1,7 +1,7 @@ - /** BEGIN COPYRIGHT BLOCK - * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. - * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. -- * Copyright (C) 2009-2025 Red Hat, Inc. -+ * Copyright (C) 2026 Red Hat, Inc. - * All rights reserved. - * - * Contributors: -@@ -1035,6 +1035,7 @@ struct slapdplugin - char *plg_libpath; /* library path for dll/so */ - char *plg_initfunc; /* init symbol */ - IFP plg_close; /* close function */ -+ IFP plg_pre_close; /* pre close function */ - Slapi_PluginDesc plg_desc; /* vendor's info */ - char *plg_name; /* used for plugin rdn in cn=config */ - struct slapdplugin *plg_next; /* for plugin lists */ -diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h -index 5d9ef289d..4661d2cf0 100644 ---- a/ldap/servers/slapd/slapi-plugin.h -+++ b/ldap/servers/slapd/slapi-plugin.h -@@ -1,6 +1,6 @@ - /* BEGIN COPYRIGHT BLOCK - * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. -- * Copyright (C) 2021 Red Hat, Inc. -+ * Copyright (C) 2026 Red Hat, Inc. - * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. - * All rights reserved. - * -@@ -7082,6 +7082,7 @@ typedef struct slapi_plugindesc - - /* miscellaneous plugin functions */ - #define SLAPI_PLUGIN_CLOSE_FN 210 -+#define SLAPI_PLUGIN_PRE_CLOSE_FN 211 - #define SLAPI_PLUGIN_START_FN 212 - #define SLAPI_PLUGIN_CLEANUP_FN 232 - #define SLAPI_PLUGIN_POSTSTART_FN 233 --- -2.53.0 - diff --git a/0038-Issue-7271-Add-new-plugin-pre-close-function-check-t.patch b/0038-Issue-7271-Add-new-plugin-pre-close-function-check-t.patch deleted file mode 100644 index e3f43c0..0000000 --- a/0038-Issue-7271-Add-new-plugin-pre-close-function-check-t.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 21b9e00264437dff3b6b81355cd159485bfdaf37 Mon Sep 17 00:00:00 2001 -From: Mark Reynolds -Date: Wed, 4 Mar 2026 14:47:01 -0500 -Subject: [PATCH] Issue 7271 - Add new plugin pre-close function check to - plugin_invoke_plugin_pb - -Description: - -In plugin_invoke_plugin_pb we were not checking for the new pre-close function -which led to an error in the logs: pb_op is NULL. In a debug build this leads -to an assertion error at shutdown. - -relates: https://github.com/389ds/389-ds-base/issues/7271 - -Reviewed by: vashirov(Thanks!) ---- - ldap/servers/slapd/plugin.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/ldap/servers/slapd/plugin.c b/ldap/servers/slapd/plugin.c -index 95b8de894..c1b0571eb 100644 ---- a/ldap/servers/slapd/plugin.c -+++ b/ldap/servers/slapd/plugin.c -@@ -3647,6 +3647,7 @@ plugin_invoke_plugin_pb(struct slapdplugin *plugin, int operation, Slapi_PBlock - if (operation == SLAPI_PLUGIN_START_FN || - operation == SLAPI_PLUGIN_POSTSTART_FN || - operation == SLAPI_PLUGIN_CLOSE_FN || -+ operation == SLAPI_PLUGIN_PRE_CLOSE_FN || - operation == SLAPI_PLUGIN_CLEANUP_FN || - operation == SLAPI_PLUGIN_BE_PRE_CLOSE_FN || - operation == SLAPI_PLUGIN_BE_POST_OPEN_FN || --- -2.53.0 - diff --git a/389-ds-base.spec b/389-ds-base.spec index fead9da..972ee8d 100644 --- a/389-ds-base.spec +++ b/389-ds-base.spec @@ -46,8 +46,8 @@ ExcludeArch: i686 Summary: 389 Directory Server (base) Name: 389-ds-base -Version: 2.8.0 -Release: 6%{?dist} +Version: 2.9.0 +Release: 1%{?dist} License: GPL-3.0-or-later WITH GPL-3.0-389-ds-base-exception AND (Apache-2.0 OR Apache-2.0 WITH LLVM-exception OR MIT) AND (Apache-2.0 OR LGPL-2.1-or-later OR MIT) AND (Apache-2.0 OR MIT) AND (MIT OR Apache-2.0) AND Unicode-3.0 AND (MIT OR Unlicense) AND Apache-2.0 AND MIT AND MPL-2.0 AND Zlib URL: https://www.port389.org Conflicts: selinux-policy-base < 3.9.8 @@ -59,13 +59,14 @@ Provides: ldif2ldbm >= 0 ##### Bundled cargo crates list - START ##### Provides: bundled(crate(allocator-api2)) = 0.2.21 +Provides: bundled(crate(anyhow)) = 1.0.102 Provides: bundled(crate(atty)) = 0.2.14 -Provides: bundled(crate(autocfg)) = 1.5.0 +Provides: bundled(crate(autocfg)) = 1.5.1 Provides: bundled(crate(base64)) = 0.13.1 -Provides: bundled(crate(bitflags)) = 2.10.0 +Provides: bundled(crate(bitflags)) = 2.12.1 Provides: bundled(crate(byteorder)) = 1.5.0 Provides: bundled(crate(cbindgen)) = 0.26.0 -Provides: bundled(crate(cc)) = 1.2.52 +Provides: bundled(crate(cc)) = 1.2.63 Provides: bundled(crate(cfg-if)) = 1.0.4 Provides: bundled(crate(clap)) = 3.2.25 Provides: bundled(crate(clap_lex)) = 0.2.4 @@ -75,70 +76,84 @@ Provides: bundled(crate(crossbeam-queue)) = 0.3.12 Provides: bundled(crate(crossbeam-utils)) = 0.8.21 Provides: bundled(crate(equivalent)) = 1.0.2 Provides: bundled(crate(errno)) = 0.3.14 -Provides: bundled(crate(fastrand)) = 2.3.0 +Provides: bundled(crate(fastrand)) = 2.4.1 Provides: bundled(crate(fernet)) = 0.1.4 -Provides: bundled(crate(find-msvc-tools)) = 0.1.7 +Provides: bundled(crate(find-msvc-tools)) = 0.1.9 Provides: bundled(crate(foldhash)) = 0.2.0 Provides: bundled(crate(foreign-types)) = 0.3.2 Provides: bundled(crate(foreign-types-shared)) = 0.1.1 -Provides: bundled(crate(getrandom)) = 0.3.4 -Provides: bundled(crate(hashbrown)) = 0.16.1 -Provides: bundled(crate(heck)) = 0.4.1 +Provides: bundled(crate(getrandom)) = 0.4.2 +Provides: bundled(crate(hashbrown)) = 0.17.1 +Provides: bundled(crate(heck)) = 0.5.0 Provides: bundled(crate(hermit-abi)) = 0.1.19 -Provides: bundled(crate(indexmap)) = 1.9.3 -Provides: bundled(crate(itoa)) = 1.0.17 +Provides: bundled(crate(id-arena)) = 2.3.0 +Provides: bundled(crate(indexmap)) = 2.14.0 +Provides: bundled(crate(itoa)) = 1.0.18 Provides: bundled(crate(jobserver)) = 0.1.34 -Provides: bundled(crate(libc)) = 0.2.180 -Provides: bundled(crate(linux-raw-sys)) = 0.11.0 -Provides: bundled(crate(log)) = 0.4.29 -Provides: bundled(crate(lru)) = 0.16.3 -Provides: bundled(crate(memchr)) = 2.7.6 -Provides: bundled(crate(once_cell)) = 1.21.3 -Provides: bundled(crate(openssl)) = 0.10.75 +Provides: bundled(crate(leb128fmt)) = 0.1.0 +Provides: bundled(crate(libc)) = 0.2.186 +Provides: bundled(crate(linux-raw-sys)) = 0.12.1 +Provides: bundled(crate(log)) = 0.4.32 +Provides: bundled(crate(lru)) = 0.16.4 +Provides: bundled(crate(memchr)) = 2.8.1 +Provides: bundled(crate(once_cell)) = 1.21.4 +Provides: bundled(crate(openssl)) = 0.10.80 Provides: bundled(crate(openssl-macros)) = 0.1.1 -Provides: bundled(crate(openssl-sys)) = 0.9.111 +Provides: bundled(crate(openssl-sys)) = 0.9.116 Provides: bundled(crate(os_str_bytes)) = 6.6.1 Provides: bundled(crate(paste)) = 0.1.18 Provides: bundled(crate(paste-impl)) = 0.1.18 -Provides: bundled(crate(pin-project-lite)) = 0.2.16 -Provides: bundled(crate(pkg-config)) = 0.3.32 +Provides: bundled(crate(pin-project-lite)) = 0.2.17 +Provides: bundled(crate(pkg-config)) = 0.3.33 +Provides: bundled(crate(prettyplease)) = 0.2.37 Provides: bundled(crate(proc-macro-hack)) = 0.5.20+deprecated -Provides: bundled(crate(proc-macro2)) = 1.0.105 -Provides: bundled(crate(quote)) = 1.0.43 -Provides: bundled(crate(r-efi)) = 5.3.0 -Provides: bundled(crate(rustix)) = 1.1.3 +Provides: bundled(crate(proc-macro2)) = 1.0.106 +Provides: bundled(crate(quote)) = 1.0.45 +Provides: bundled(crate(r-efi)) = 6.0.0 +Provides: bundled(crate(rustix)) = 1.1.4 +Provides: bundled(crate(semver)) = 1.0.28 Provides: bundled(crate(serde)) = 1.0.228 Provides: bundled(crate(serde_core)) = 1.0.228 Provides: bundled(crate(serde_derive)) = 1.0.228 -Provides: bundled(crate(serde_json)) = 1.0.149 -Provides: bundled(crate(shlex)) = 1.3.0 +Provides: bundled(crate(serde_json)) = 1.0.150 +Provides: bundled(crate(shlex)) = 2.0.1 Provides: bundled(crate(smallvec)) = 1.15.1 Provides: bundled(crate(sptr)) = 0.3.2 Provides: bundled(crate(strsim)) = 0.10.0 -Provides: bundled(crate(syn)) = 2.0.114 -Provides: bundled(crate(tempfile)) = 3.24.0 +Provides: bundled(crate(syn)) = 2.0.117 +Provides: bundled(crate(tempfile)) = 3.27.0 Provides: bundled(crate(termcolor)) = 1.4.1 Provides: bundled(crate(textwrap)) = 0.16.2 -Provides: bundled(crate(tokio)) = 1.49.0 +Provides: bundled(crate(tokio)) = 1.52.3 Provides: bundled(crate(toml)) = 0.5.11 Provides: bundled(crate(tracing)) = 0.1.44 Provides: bundled(crate(tracing-attributes)) = 0.1.31 Provides: bundled(crate(tracing-core)) = 0.1.36 -Provides: bundled(crate(unicode-ident)) = 1.0.22 +Provides: bundled(crate(unicode-ident)) = 1.0.24 +Provides: bundled(crate(unicode-xid)) = 0.2.6 Provides: bundled(crate(uuid)) = 0.8.2 Provides: bundled(crate(vcpkg)) = 0.2.15 Provides: bundled(crate(wasi)) = 0.11.1+wasi_snapshot_preview1 -Provides: bundled(crate(wasip2)) = 1.0.1+wasi_0.2.4 +Provides: bundled(crate(wasip2)) = 1.0.3+wasi_0.2.9 +Provides: bundled(crate(wasip3)) = 0.4.0+wasi_0.3.0_rc_2026_01_06 +Provides: bundled(crate(wasm-encoder)) = 0.244.0 +Provides: bundled(crate(wasm-metadata)) = 0.244.0 +Provides: bundled(crate(wasmparser)) = 0.244.0 Provides: bundled(crate(winapi)) = 0.3.9 Provides: bundled(crate(winapi-i686-pc-windows-gnu)) = 0.4.0 Provides: bundled(crate(winapi-util)) = 0.1.11 Provides: bundled(crate(winapi-x86_64-pc-windows-gnu)) = 0.4.0 Provides: bundled(crate(windows-link)) = 0.2.1 Provides: bundled(crate(windows-sys)) = 0.61.2 -Provides: bundled(crate(wit-bindgen)) = 0.46.0 +Provides: bundled(crate(wit-bindgen)) = 0.57.1 +Provides: bundled(crate(wit-bindgen-core)) = 0.51.0 +Provides: bundled(crate(wit-bindgen-rust)) = 0.51.0 +Provides: bundled(crate(wit-bindgen-rust-macro)) = 0.51.0 +Provides: bundled(crate(wit-component)) = 0.244.0 +Provides: bundled(crate(wit-parser)) = 0.244.0 Provides: bundled(crate(zeroize)) = 1.8.2 Provides: bundled(crate(zeroize_derive)) = 1.4.3 -Provides: bundled(crate(zmij)) = 1.0.12 +Provides: bundled(crate(zmij)) = 1.0.21 ##### Bundled cargo crates list - END ##### BuildRequires: nspr-devel >= 4.32 @@ -268,47 +283,17 @@ Source3: https://github.com/jemalloc/%{jemalloc_name}/releases/download %endif Source4: 389-ds-base.sysusers -Source5: vendor-%{version}-5.tar.gz -Source6: Cargo-%{version}-5.lock +Source5: vendor-%{version}-1.tar.gz +Source6: Cargo-%{version}-1.lock -Patch: 0001-Issue-7049-RetroCL-plugin-generates-invalid-LDIF.patch -Patch: 0002-Issue-7096-During-replication-online-total-init-the-.patch -Patch: 0003-Issue-Revise-paged-result-search-locking.patch -Patch: 0004-Issue-7172-Index-ordering-mismatch-after-upgrade-717.patch -Patch: 0005-Issue-7172-2nd-Index-ordering-mismatch-after-upgrade.patch -Patch: 0006-Issue-7189-DSBLE0007-generates-incorrect-remediation.patch -Patch: 0007-Issue-7184-argparse.HelpFormatter-_format_actions_us.patch -Patch: 0008-Issue-7027-2nd-389-ds-base-OpenScanHub-Leaks-Detecte.patch -Patch: 0009-Issue-7213-MDB_BAD_VALSIZE-error-while-handling-VLV-.patch -Patch: 0010-Issue-6542-RPM-build-errors-on-Fedora-42.patch -Patch: 0011-Issue-6476-Fix-build-failure-with-GCC-15.patch -Patch: 0012-Issue-7223-Revert-index-scan-limits-for-system-index.patch -Patch: 0013-Issue-7223-Add-upgrade-function-to-remove-nsIndexIDL.patch -Patch: 0014-Issue-7223-Add-upgrade-function-to-remove-ancestorid.patch -Patch: 0015-Issue-7223-Detect-and-log-index-ordering-mismatch-du.patch -Patch: 0016-Issue-7223-Add-dsctl-index-check-command-for-offline.patch -Patch: 0017-Issue-7096-2nd-During-replication-online-total-init-.patch -Patch: 0018-Issue-7076-6992-6784-6214-Fix-CI-test-failures-7077.patch -Patch: 0019-Issue-7076-Fix-revert_cache-never-called-in-modrdn-7.patch -Patch: 0020-Issue-6947-Fix-health_system_indexes_test.py.patch -Patch: 0021-Issue-7121-2nd-LeakSanitizer-various-leaks-during-re.patch -Patch: 0022-Issue-7150-Compressed-access-log-rotations-skipped-a.patch -Patch: 0023-Issue-7224-CI-Test-Simplify-test_reserve_descriptor_.patch -Patch: 0024-Issue-7231-Sync-repl-tests-fail-in-FIPS-mode-due-to-.patch -Patch: 0025-Issue-7248-CLI-attribute-uniqueness-fix-usage-for-ex.patch -Patch: 0026-Issue-CLI-dsctl-db2index-needs-some-hardening-with-M.patch -Patch: 0027-Issue-7184-2nd-argparse.HelpFormatter-_format_action.patch -Patch: 0028-Issue-7213-2nd-MDB_BAD_VALSIZE-error-while-handling-.patch -Patch: 0029-Issue-7223-Use-lexicographical-order-for-ancestorid-.patch -Patch: 0030-Issue-7066-7052-allow-password-history-to-be-set-to-.patch -Patch: 0031-Issue-7243-UI-fix-certificate-table-and-modal.patch -Patch: 0032-Issue-7223-Remove-integerOrderingMatch-requirement-f.patch -Patch: 0033-Issue-7053-Remove-memberof_del_dn_from_groups-from-M.patch -Patch: 0034-Issue-5853-Update-concread-to-0.5.10.patch -Patch: 0035-Issue-7271-plugins-that-create-threads-need-to-updat.patch -Patch: 0036-Security-fix-for-CVE-2025-14905.patch -Patch: 0037-Issue-7271-implement-a-pre-close-plugin-function.patch -Patch: 0038-Issue-7271-Add-new-plugin-pre-close-function-check-t.patch +Patch: 0001-Issue-7554-deref-plugin-null-pointer-dereference-if-.patch +Patch: 0002-Issue-3555-UI-Fix-audit-issue-with-npm-brace-expansi.patch +Patch: 0003-Issue-6922-AddressSanitizer-leaks-found-by-acl-test-.patch +Patch: 0004-Issue-7437-LeakSanitizer-memory-leaks-in-CoS-cache-e.patch +Patch: 0005-Issue-7372-Reindex-adds-tombstones-to-ancestorid-cau.patch +Patch: 0006-Issue-7327-dsctl-healthcheck-DSMOLE0001-inaccurate-r.patch +Patch: 0007-Issue-7267-MDB_BAD_VALSIZE-error-when-updating-index.patch +Patch: 0008-Fix-test389-imports-on-older-branches.patch %description 389 Directory Server is an LDAPv3 compliant server. The base package includes @@ -758,6 +743,26 @@ exit 0 %endif %changelog +* Fri Jun 05 2026 Viktor Ashirov - 2.9.0-1 +- Bump version to 2.9.0 +- Resolves: RHEL-165978 - Replication halt caused by an incorrect setting of "nsslapd-changelogmaxage" +- Resolves: RHEL-166003 - Crash in replica_config_add when manually configuring a replica with an incorrect nsds5ReplicaRoot. +- Resolves: RHEL-166004 - Possible memory leak when using the Retro Changelog plugin. +- Resolves: RHEL-168908 - ns-slapd fails to shutdown when deferred memberof update is in progress +- Resolves: RHEL-168964 - Web console doesn't show the sub suffix of ou=foo,ou=people,dc=example,dc=com. [rhel-9] +- Resolves: RHEL-168972 - Replica installation is failing with message MDB_BAD_VALSIZE: Unsupported size of key/DB name/data, or wrong DUPFIXED [rhel-9] +- Resolves: RHEL-169530 - Rebase 389-ds-base to 2.9.x +- Resolves: RHEL-170270 - DS 12 does not handle escape char in bind user [rhel-9] +- Resolves: RHEL-170275 - dnaSharedConfig: "dnaPortNum: 0" [rhel-9] +- Resolves: RHEL-170280 - Memory leaks in syncrepl plugin during persistent search operations [rhel-9] +- Resolves: RHEL-170287 - access log - suspicious wtime optime negative and large values in internal op [rhel-9] +- Resolves: RHEL-170477 - An online reinitialization with LMDB is terminating the receiving server [rhel-9] +- Resolves: RHEL-170480 - dsctl healthcheck DSMOLE0001 inaccurate recommendations when there is more than 1 LDAP backend [rhel-9] +- Resolves: RHEL-170651 - passwordbadwords attribute of the local password policy is not functioning [rhel-9] +- Resolves: RHEL-170732 - Memory leaks in IPA context on server restart [rhel-9] +- Resolves: RHEL-174525 - [RFE] Add OS-level thread names to all server threads [rhel-9] +- Resolves: RHEL-180717 - Online export is failing when using the option "-s" [rhel-9] + * Thu Mar 05 2026 Viktor Ashirov - 2.8.0-6 - Resolves: RHEL-152335 - Crash in trim_changelog() during the Retro Changelog trimming. [rhel-9.8] diff --git a/main.fmf b/main.fmf index 0470ee9..663be96 100644 --- a/main.fmf +++ b/main.fmf @@ -10,7 +10,7 @@ package: [389-ds-base, git, pytest] - name: clone repo how: shell - script: git clone -b 389-ds-base-2.8 https://github.com/389ds/389-ds-base /root/ds + script: git clone -b 389-ds-base-2.9 https://github.com/389ds/389-ds-base /root/ds /test: /upstream_basic: test: pytest -v /root/ds/dirsrvtests/tests/suites/basic/basic_test.py diff --git a/sources b/sources index 8827d3f..afc92d3 100644 --- a/sources +++ b/sources @@ -1,4 +1,4 @@ SHA512 (jemalloc-5.3.0.tar.bz2) = 22907bb052096e2caffb6e4e23548aecc5cc9283dce476896a2b1127eee64170e3562fa2e7db9571298814a7a2c7df6e8d1fbe152bd3f3b0c1abec22a2de34b1 -SHA512 (389-ds-base-2.8.0.tar.bz2) = 82a1d71618dafa2aaba9e0c54d049dfda0a404fc836887e6283a22eded00a564d66c2988f19c549041db85511a3baa4792d68e89b2de8a5b3647c703c65b75cd -SHA512 (Cargo-2.8.0-5.lock) = efd2512a494c2d8764553b99f911065f41545d55183385889a1e60a5ba65b6514347eef50cea2cc4126abae81e35b2c683b6d99bbe111cef603bc3f04f62c7e9 -SHA512 (vendor-2.8.0-5.tar.gz) = 587b478cf1ae57d808495317660ac31a0dcd5ef9df7f7ff6b7ce80e1690de3866fa3d40fa0d67a95413bd88b323e87cea3236454fba02cf1cef673a49092e0f2 +SHA512 (389-ds-base-2.9.0.tar.bz2) = 7bbc25185a4df5624a4ec8c3c79c78eecdce03e21548bc7f906263aae5815b3fd464d05d38a2540f378a1085c8b740660b908a82757f4e839928932dcf7da8d0 +SHA512 (vendor-2.9.0-1.tar.gz) = 7cddffb4a974201e96baa635fe1c07725f7ee036ac00852fcb7c318a9037d8d87683cc7d8ea4cfe1aa5d3b1af484e56fd946ed2ec2c99cc1d5730835dd304641 +SHA512 (Cargo-2.9.0-1.lock) = 967eedd442bd30ba39fc759f32d435c2956487d7d20dd8b922c0c5a4e1c4fe98b649471b3243065ffdf8d810acb8d2b69731d71fe26f2001b787a8b7dbea89a0