Compare commits
3 Commits
c8-stream-
...
c10-beta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b2fb8c72e | ||
| 2760ce3ca2 | |||
| 89b7694df5 |
@ -1,3 +0,0 @@
|
||||
bd9aab32d9cbf9231058d585479813f3420dc872 SOURCES/389-ds-base-1.4.3.39.tar.bz2
|
||||
1c8f2d0dfbf39fa8cd86363bf3314351ab21f8d4 SOURCES/jemalloc-5.3.0.tar.bz2
|
||||
8d3275209f2f8e1a69053340930ad1fb037d61fb SOURCES/vendor-1.4.3.39-3.tar.gz
|
||||
7
.gitignore
vendored
7
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
SOURCES/389-ds-base-1.4.3.39.tar.bz2
|
||||
SOURCES/jemalloc-5.3.0.tar.bz2
|
||||
SOURCES/vendor-1.4.3.39-3.tar.gz
|
||||
389-ds-base-3.2.0.tar.bz2
|
||||
jemalloc-5.3.0.tar.bz2
|
||||
libdb-5.3.28-59.tar.bz2
|
||||
vendor-3.2.0-4.tar.gz
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
From 2da3ad24ce028c6b68abef0d115dae4215de558d Mon Sep 17 00:00:00 2001
|
||||
From 1c9c535888b9a850095794787d67900b04924a76 Mon Sep 17 00:00:00 2001
|
||||
From: tbordaz <tbordaz@redhat.com>
|
||||
Date: Wed, 7 Jan 2026 11:21:12 +0100
|
||||
Subject: [PATCH] Issue 7096 - During replication online total init the
|
||||
@ -21,15 +21,15 @@ 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 | 29 ++--
|
||||
ldap/servers/slapd/back-ldbm/idl_new.c | 30 ++--
|
||||
.../servers/slapd/back-ldbm/proto-back-ldbm.h | 3 +
|
||||
4 files changed, 189 insertions(+), 18 deletions(-)
|
||||
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 d17ec644b..462d1763c 100644
|
||||
index 1bc36720d..b187c26bc 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/back-ldbm.h
|
||||
+++ b/ldap/servers/slapd/back-ldbm/back-ldbm.h
|
||||
@@ -285,6 +285,18 @@ typedef struct _idlist_set
|
||||
@@ -282,6 +282,18 @@ typedef struct _idlist_set
|
||||
#define INDIRECT_BLOCK(idl) ((idl)->b_nids == INDBLOCK)
|
||||
#define IDL_NIDS(idl) (idl ? (idl)->b_nids : (NIDS)0)
|
||||
|
||||
@ -49,7 +49,7 @@ index d17ec644b..462d1763c 100644
|
||||
|
||||
/* 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 e609d349e..3827e59ea 100644
|
||||
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)
|
||||
@ -223,18 +223,26 @@ index e609d349e..3827e59ea 100644
|
||||
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 916e0781e..212f31b7b 100644
|
||||
index 5fbcaff2e..2d978353f 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/idl_new.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/idl_new.c
|
||||
@@ -378,6 +378,7 @@ idl_new_range_fetch(
|
||||
idl_range_id_pair *leftover = NULL;
|
||||
@@ -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) {
|
||||
return NULL;
|
||||
@@ -528,10 +529,12 @@ idl_new_range_fetch(
|
||||
@@ -578,10 +578,12 @@ idl_new_range_fetch(
|
||||
* found entry is the one from the suffix
|
||||
*/
|
||||
suffix = key;
|
||||
@ -250,7 +258,7 @@ index 916e0781e..212f31b7b 100644
|
||||
} else {
|
||||
/* Otherwise, keep the {key,id} in leftover array */
|
||||
if (!leftover) {
|
||||
@@ -546,13 +549,7 @@ idl_new_range_fetch(
|
||||
@@ -596,13 +598,7 @@ idl_new_range_fetch(
|
||||
leftovercnt++;
|
||||
}
|
||||
} else {
|
||||
@ -265,7 +273,7 @@ index 916e0781e..212f31b7b 100644
|
||||
}
|
||||
|
||||
count++;
|
||||
@@ -655,21 +652,17 @@ error:
|
||||
@@ -695,21 +691,17 @@ error:
|
||||
|
||||
while(remaining > 0) {
|
||||
for (size_t i = 0; i < leftovercnt; i++) {
|
||||
@ -289,13 +297,13 @@ index 916e0781e..212f31b7b 100644
|
||||
slapi_ch_free((void **)&leftover);
|
||||
+ idrange_free(&idrange_list);
|
||||
}
|
||||
return idl;
|
||||
}
|
||||
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 157788fa4..1d93b6402 100644
|
||||
index 91d61098a..30a7aa11f 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
|
||||
+++ b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
|
||||
@@ -229,6 +229,9 @@ ID idl_firstid(IDList *idl);
|
||||
@@ -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);
|
||||
765
0002-Issue-Revise-paged-result-search-locking.patch
Normal file
765
0002-Issue-Revise-paged-result-search-locking.patch
Normal file
@ -0,0 +1,765 @@
|
||||
From 446bc42e7b64a8496c2c3fe486f86bba318bed5e Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
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 6024fcd31..1f47c531c 100644
|
||||
--- a/ldap/servers/slapd/abandon.c
|
||||
+++ b/ldap/servers/slapd/abandon.c
|
||||
@@ -179,7 +179,7 @@ do_abandon(Slapi_PBlock *pb)
|
||||
logpb.tv_sec = -1;
|
||||
logpb.tv_nsec = -1;
|
||||
|
||||
- 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)) {
|
||||
if (log_format != LOG_FORMAT_DEFAULT) {
|
||||
/* JSON logging */
|
||||
logpb.target_op = "Simple Paged Results";
|
||||
diff --git a/ldap/servers/slapd/opshared.c b/ldap/servers/slapd/opshared.c
|
||||
index a5cddfd23..bf800f7dc 100644
|
||||
--- a/ldap/servers/slapd/opshared.c
|
||||
+++ b/ldap/servers/slapd/opshared.c
|
||||
@@ -572,8 +572,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);
|
||||
@@ -619,14 +619,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);
|
||||
}
|
||||
|
||||
@@ -743,17 +736,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;
|
||||
@@ -764,14 +755,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 */
|
||||
@@ -789,22 +779,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;
|
||||
}
|
||||
}
|
||||
@@ -915,7 +905,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);
|
||||
#pragma GCC diagnostic pop
|
||||
}
|
||||
@@ -954,7 +944,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) {
|
||||
@@ -967,23 +957,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);
|
||||
@@ -993,7 +983,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 765c12bf5..455d6d718 100644
|
||||
--- a/ldap/servers/slapd/proto-slap.h
|
||||
+++ b/ldap/servers/slapd/proto-slap.h
|
||||
@@ -1614,20 +1614,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);
|
||||
@@ -1639,15 +1641,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 11c5602e3..d494931c2 100644
|
||||
--- a/ldap/servers/slapd/slap.h
|
||||
+++ b/ldap/servers/slapd/slap.h
|
||||
@@ -89,6 +89,10 @@ static char ptokPBE[34] = "Internal (Software) Token ";
|
||||
#include <stdbool.h>
|
||||
#include <time.h> /* 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 <slapi_pal.h>
|
||||
|
||||
@@ -1669,7 +1673,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
|
||||
|
||||
183
0003-Issue-7108-Fix-shutdown-crash-in-entry-cache-destruc.patch
Normal file
183
0003-Issue-7108-Fix-shutdown-crash-in-entry-cache-destruc.patch
Normal file
@ -0,0 +1,183 @@
|
||||
From 4936f953fa3b0726c2b178f135cd78dcac7463ba Mon Sep 17 00:00:00 2001
|
||||
From: Simon Pichugin <spichugi@redhat.com>
|
||||
Date: Thu, 8 Jan 2026 10:02:39 -0800
|
||||
Subject: [PATCH] Issue 7108 - Fix shutdown crash in entry cache destruction
|
||||
(#7163)
|
||||
|
||||
Description: The entry cache could experience LRU list corruption when
|
||||
using pinned entries, leading to crashes during cache flush operations.
|
||||
|
||||
In entrycache_add_int(), when returning an existing cached entry, the
|
||||
code checked the wrong entry's state before calling lru_delete(). It
|
||||
checked the new entry 'e' but operated on the existing entry 'my_alt',
|
||||
causing lru_delete() to be called on entries not in the LRU list. This
|
||||
is fixed by checking my_alt's refcnt and pinned state instead.
|
||||
|
||||
In flush_hash(), pinned_remove() and lru_delete() were both called on
|
||||
pinned entries. Since pinned entries are in the pinned list, calling
|
||||
lru_delete() afterwards corrupted the list. This is fixed by calling
|
||||
either pinned_remove() or lru_delete() based on the entry's state.
|
||||
|
||||
A NULL check is added in entrycache_flush() and dncache_flush() to
|
||||
gracefully handle corrupted LRU lists and prevent crashes when
|
||||
traversing backwards through the list encounters an unexpected NULL.
|
||||
|
||||
Entry pointers are now always cleared after lru_delete() removal to
|
||||
prevent stale pointer issues in non-debug builds.
|
||||
|
||||
Fixes: https://github.com/389ds/389-ds-base/issues/7108
|
||||
|
||||
Reviewed by: @progier389, @vashirov (Thanks!!)
|
||||
---
|
||||
ldap/servers/slapd/back-ldbm/cache.c | 48 +++++++++++++++++++++++++---
|
||||
1 file changed, 43 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/cache.c b/ldap/servers/slapd/back-ldbm/cache.c
|
||||
index 2e4126134..a87f30687 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/cache.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/cache.c
|
||||
@@ -458,11 +458,13 @@ static void
|
||||
lru_delete(struct cache *cache, void *ptr)
|
||||
{
|
||||
struct backcommon *e;
|
||||
+
|
||||
if (NULL == ptr) {
|
||||
LOG("=> lru_delete\n<= lru_delete (null entry)\n");
|
||||
return;
|
||||
}
|
||||
e = (struct backcommon *)ptr;
|
||||
+
|
||||
#ifdef LDAP_CACHE_DEBUG_LRU
|
||||
pinned_verify(cache, __LINE__);
|
||||
lru_verify(cache, e, 1);
|
||||
@@ -475,8 +477,9 @@ lru_delete(struct cache *cache, void *ptr)
|
||||
e->ep_lrunext->ep_lruprev = e->ep_lruprev;
|
||||
else
|
||||
cache->c_lrutail = e->ep_lruprev;
|
||||
-#ifdef LDAP_CACHE_DEBUG_LRU
|
||||
+ /* Always clear pointers after removal to prevent stale pointer issues */
|
||||
e->ep_lrunext = e->ep_lruprev = NULL;
|
||||
+#ifdef LDAP_CACHE_DEBUG_LRU
|
||||
lru_verify(cache, e, 0);
|
||||
#endif
|
||||
}
|
||||
@@ -633,9 +636,14 @@ flush_hash(struct cache *cache, struct timespec *start_time, int32_t type)
|
||||
if (entry->ep_refcnt == 0) {
|
||||
entry->ep_refcnt++;
|
||||
if (entry->ep_state & ENTRY_STATE_PINNED) {
|
||||
+ /* Entry is in pinned list, not LRU - remove from pinned only.
|
||||
+ * pinned_remove clears lru pointers and won't add to LRU since refcnt > 0.
|
||||
+ */
|
||||
pinned_remove(cache, laste);
|
||||
+ } else {
|
||||
+ /* Entry is in LRU list - remove from LRU */
|
||||
+ lru_delete(cache, laste);
|
||||
}
|
||||
- lru_delete(cache, laste);
|
||||
if (type == ENTRY_CACHE) {
|
||||
entrycache_remove_int(cache, laste);
|
||||
entrycache_return(cache, (struct backentry **)&laste, PR_TRUE);
|
||||
@@ -679,9 +687,14 @@ flush_hash(struct cache *cache, struct timespec *start_time, int32_t type)
|
||||
if (entry->ep_refcnt == 0) {
|
||||
entry->ep_refcnt++;
|
||||
if (entry->ep_state & ENTRY_STATE_PINNED) {
|
||||
+ /* Entry is in pinned list, not LRU - remove from pinned only.
|
||||
+ * pinned_remove clears lru pointers and won't add to LRU since refcnt > 0.
|
||||
+ */
|
||||
pinned_remove(cache, laste);
|
||||
+ } else {
|
||||
+ /* Entry is in LRU list - remove from LRU */
|
||||
+ lru_delete(cache, laste);
|
||||
}
|
||||
- lru_delete(cache, laste);
|
||||
entrycache_remove_int(cache, laste);
|
||||
entrycache_return(cache, (struct backentry **)&laste, PR_TRUE);
|
||||
} else {
|
||||
@@ -772,6 +785,11 @@ entrycache_flush(struct cache *cache)
|
||||
} else {
|
||||
e = BACK_LRU_PREV(e, struct backentry *);
|
||||
}
|
||||
+ if (e == NULL) {
|
||||
+ slapi_log_err(SLAPI_LOG_WARNING, "entrycache_flush",
|
||||
+ "Unexpected NULL entry while flushing cache - LRU list may be corrupted\n");
|
||||
+ break;
|
||||
+ }
|
||||
ASSERT(e->ep_refcnt == 0);
|
||||
e->ep_refcnt++;
|
||||
if (entrycache_remove_int(cache, e) < 0) {
|
||||
@@ -1160,6 +1178,7 @@ pinned_remove(struct cache *cache, void *ptr)
|
||||
{
|
||||
struct backentry *e = (struct backentry *)ptr;
|
||||
ASSERT(e->ep_state & ENTRY_STATE_PINNED);
|
||||
+
|
||||
cache->c_pinned_ctx->npinned--;
|
||||
cache->c_pinned_ctx->size -= e->ep_size;
|
||||
e->ep_state &= ~ENTRY_STATE_PINNED;
|
||||
@@ -1172,13 +1191,23 @@ pinned_remove(struct cache *cache, void *ptr)
|
||||
cache->c_pinned_ctx->head = cache->c_pinned_ctx->tail = NULL;
|
||||
} else {
|
||||
cache->c_pinned_ctx->head = BACK_LRU_NEXT(e, struct backentry *);
|
||||
+ /* Update new head's prev pointer to NULL */
|
||||
+ if (cache->c_pinned_ctx->head) {
|
||||
+ cache->c_pinned_ctx->head->ep_lruprev = NULL;
|
||||
+ }
|
||||
}
|
||||
} else if (cache->c_pinned_ctx->tail == e) {
|
||||
cache->c_pinned_ctx->tail = BACK_LRU_PREV(e, struct backentry *);
|
||||
+ /* Update new tail's next pointer to NULL */
|
||||
+ if (cache->c_pinned_ctx->tail) {
|
||||
+ cache->c_pinned_ctx->tail->ep_lrunext = NULL;
|
||||
+ }
|
||||
} else {
|
||||
+ /* Middle of list: update both neighbors to point to each other */
|
||||
BACK_LRU_PREV(e, struct backentry *)->ep_lrunext = BACK_LRU_NEXT(e, struct backcommon *);
|
||||
BACK_LRU_NEXT(e, struct backentry *)->ep_lruprev = BACK_LRU_PREV(e, struct backcommon *);
|
||||
}
|
||||
+ /* Clear the removed entry's pointers */
|
||||
e->ep_lrunext = e->ep_lruprev = NULL;
|
||||
if (e->ep_refcnt == 0) {
|
||||
lru_add(cache, ptr);
|
||||
@@ -1245,6 +1274,7 @@ pinned_add(struct cache *cache, void *ptr)
|
||||
return false;
|
||||
}
|
||||
/* Now it is time to insert the entry in the pinned list */
|
||||
+
|
||||
cache->c_pinned_ctx->npinned++;
|
||||
cache->c_pinned_ctx->size += e->ep_size;
|
||||
e->ep_state |= ENTRY_STATE_PINNED;
|
||||
@@ -1754,7 +1784,7 @@ entrycache_add_int(struct cache *cache, struct backentry *e, int state, struct b
|
||||
* 3) ep_state: 0 && state: 0
|
||||
* ==> increase the refcnt
|
||||
*/
|
||||
- if (e->ep_refcnt == 0)
|
||||
+ if (e->ep_refcnt == 0 && (e->ep_state & ENTRY_STATE_PINNED) == 0)
|
||||
lru_delete(cache, (void *)e);
|
||||
e->ep_refcnt++;
|
||||
e->ep_state &= ~ENTRY_STATE_UNAVAILABLE;
|
||||
@@ -1781,7 +1811,7 @@ entrycache_add_int(struct cache *cache, struct backentry *e, int state, struct b
|
||||
} else {
|
||||
if (alt) {
|
||||
*alt = my_alt;
|
||||
- if (e->ep_refcnt == 0 && (e->ep_state & ENTRY_STATE_PINNED) == 0)
|
||||
+ if (my_alt->ep_refcnt == 0 && (my_alt->ep_state & ENTRY_STATE_PINNED) == 0)
|
||||
lru_delete(cache, (void *)*alt);
|
||||
(*alt)->ep_refcnt++;
|
||||
LOG("the entry %s already exists. returning existing entry %s (state: 0x%x)\n",
|
||||
@@ -2379,6 +2409,14 @@ dncache_flush(struct cache *cache)
|
||||
} else {
|
||||
dn = BACK_LRU_PREV(dn, struct backdn *);
|
||||
}
|
||||
+ if (dn == NULL) {
|
||||
+ /* Safety check: we should normally exit via the CACHE_LRU_HEAD check.
|
||||
+ * If we get here, c_lruhead may be NULL or the LRU list is corrupted.
|
||||
+ */
|
||||
+ slapi_log_err(SLAPI_LOG_WARNING, "dncache_flush",
|
||||
+ "Unexpected NULL entry while flushing cache - LRU list may be corrupted\n");
|
||||
+ break;
|
||||
+ }
|
||||
ASSERT(dn->ep_refcnt == 0);
|
||||
dn->ep_refcnt++;
|
||||
if (dncache_remove_int(cache, dn) < 0) {
|
||||
--
|
||||
2.52.0
|
||||
|
||||
215
0004-Issue-7172-Index-ordering-mismatch-after-upgrade-717.patch
Normal file
215
0004-Issue-7172-Index-ordering-mismatch-after-upgrade-717.patch
Normal file
@ -0,0 +1,215 @@
|
||||
From 742c12e0247ab64e87da000a4de2f3e5c99044ab Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
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 | 107 +++++++++++++++++++++++-
|
||||
2 files changed, 123 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/instance.c b/ldap/servers/slapd/back-ldbm/instance.c
|
||||
index cb002c379..71bf0f6fa 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/instance.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/instance.c
|
||||
@@ -190,6 +190,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;
|
||||
@@ -248,10 +249,14 @@ ldbm_instance_create_default_indexes(backend *be)
|
||||
ldbm_instance_config_add_index_entry(inst, e, flags);
|
||||
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);
|
||||
@@ -288,10 +293,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);
|
||||
slapi_ch_free_string(&parentid_indexes_limit);
|
||||
diff --git a/ldap/servers/slapd/upgrade.c b/ldap/servers/slapd/upgrade.c
|
||||
index 858392564..b02e37ed6 100644
|
||||
--- a/ldap/servers/slapd/upgrade.c
|
||||
+++ b/ldap/servers/slapd/upgrade.c
|
||||
@@ -330,6 +330,107 @@ upgrade_remove_subtree_rename(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 <instance> backend index set --add-mr integerOrderingMatch --attr %s %s && "
|
||||
+ "dsconf <instance> 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 the base config of the PAM PTA plugin.
|
||||
*
|
||||
@@ -547,7 +648,11 @@ upgrade_server(void)
|
||||
if (upgrade_pam_pta_default_config() != UPGRADE_SUCCESS) {
|
||||
return UPGRADE_FAILURE;
|
||||
}
|
||||
-
|
||||
+
|
||||
+ if (upgrade_check_id_index_matching_rule() != UPGRADE_SUCCESS) {
|
||||
+ return UPGRADE_FAILURE;
|
||||
+ }
|
||||
+
|
||||
return UPGRADE_SUCCESS;
|
||||
}
|
||||
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
From 2d9618da04161d7aecf2a19f5c06cd0b5749921c Mon Sep 17 00:00:00 2001
|
||||
From f5de84e309d5a4435198c9cc9b31b5722979f1ff Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
Date: Mon, 12 Jan 2026 10:58:02 +0100
|
||||
Subject: [PATCH 2/2] Issue 7172 - (2nd) Index ordering mismatch after upgrade
|
||||
Subject: [PATCH] Issue 7172 - (2nd) Index ordering mismatch after upgrade
|
||||
(#7180)
|
||||
|
||||
Commit 742c12e0247ab64e87da000a4de2f3e5c99044ab introduced a regression
|
||||
@ -30,10 +30,10 @@ Reviewed by: @tbordaz (Thanks!)
|
||||
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 04340a992..29643f7e4 100644
|
||||
index 71bf0f6fa..2a6e8cbb8 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)
|
||||
@@ -190,7 +190,7 @@ ldbm_instance_create_default_indexes(backend *be)
|
||||
char *ancestorid_indexes_limit = NULL;
|
||||
char *parentid_indexes_limit = NULL;
|
||||
struct attrinfo *ai = NULL;
|
||||
@ -42,8 +42,8 @@ index 04340a992..29643f7e4 100644
|
||||
struct index_idlistsizeinfo *iter;
|
||||
int cookie;
|
||||
int limit;
|
||||
@@ -257,7 +257,8 @@ ldbm_instance_create_default_indexes(backend *be)
|
||||
}
|
||||
@@ -250,7 +250,8 @@ ldbm_instance_create_default_indexes(backend *be)
|
||||
slapi_entry_free(e);
|
||||
|
||||
ainfo_get(be, (char *)LDBM_PARENTID_STR, &ai);
|
||||
- index_already_configured = ai;
|
||||
@ -52,16 +52,16 @@ index 04340a992..29643f7e4 100644
|
||||
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);
|
||||
@@ -308,7 +309,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);
|
||||
@@ -294,7 +295,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
|
||||
|
||||
924
0006-Issue-6753-Port-ticket-548-test-7101.patch
Normal file
924
0006-Issue-6753-Port-ticket-548-test-7101.patch
Normal file
@ -0,0 +1,924 @@
|
||||
From fb23c9e366f5eafa6bdbb8cd71afd78e3edefde2 Mon Sep 17 00:00:00 2001
|
||||
From: Lenka Doudova <mirielka@users.noreply.github.com>
|
||||
Date: Tue, 13 Jan 2026 10:44:15 +0100
|
||||
Subject: [PATCH] Issue 6753 - Port ticket 548 test (#7101)
|
||||
|
||||
Description:
|
||||
Port ticket 548 test into
|
||||
dirsrvtests/tests/suites/password/pwdPolicy_attribute_test.py
|
||||
|
||||
Relates: #6753
|
||||
|
||||
Author: Lenka Doudova, aadhikar
|
||||
Assisted by: Cursor
|
||||
Reviewer: @droideck(Thanks!)
|
||||
---
|
||||
.../password/pwdPolicy_attribute_test.py | 464 +++++++++++++++++-
|
||||
dirsrvtests/tests/tickets/ticket548_test.py | 408 ---------------
|
||||
2 files changed, 463 insertions(+), 409 deletions(-)
|
||||
delete mode 100644 dirsrvtests/tests/tickets/ticket548_test.py
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/password/pwdPolicy_attribute_test.py b/dirsrvtests/tests/suites/password/pwdPolicy_attribute_test.py
|
||||
index d0c172f94..d021f4720 100644
|
||||
--- a/dirsrvtests/tests/suites/password/pwdPolicy_attribute_test.py
|
||||
+++ b/dirsrvtests/tests/suites/password/pwdPolicy_attribute_test.py
|
||||
@@ -9,12 +9,12 @@
|
||||
import pytest
|
||||
from lib389.tasks import *
|
||||
from lib389.utils import *
|
||||
-import pdb
|
||||
from lib389.topologies import topology_st
|
||||
from lib389.pwpolicy import PwPolicyManager
|
||||
from lib389.idm.user import UserAccount, UserAccounts, TEST_USER_PROPERTIES
|
||||
from lib389.idm.organizationalunit import OrganizationalUnits
|
||||
from lib389._constants import (DEFAULT_SUFFIX, DN_DM, PASSWORD)
|
||||
+from lib389.idm.directorymanager import DirectoryManager
|
||||
|
||||
pytestmark = pytest.mark.tier1
|
||||
|
||||
@@ -361,6 +361,468 @@ def test_pwdpolicysubentry(topology_st, password_policy):
|
||||
assert 'nsPwPolicyEntry_user' not in pwp_subentry
|
||||
|
||||
|
||||
+@pytest.fixture(scope="function")
|
||||
+def shadowUser(request, topology_st):
|
||||
+ """ Create a user with shadowAccount objectclass """
|
||||
+ users = UserAccounts(topology_st.standalone, DEFAULT_SUFFIX)
|
||||
+ shadowUser = users.create(properties={
|
||||
+ 'objectclass': ['top', 'person', 'organizationalPerson',
|
||||
+ 'inetOrgPerson', 'extensibleObject', 'shadowAccount'],
|
||||
+ 'sn': '1',
|
||||
+ 'cn': 'shadowUser',
|
||||
+ 'uid': 'shadowUser',
|
||||
+ 'uidNumber': '1',
|
||||
+ 'gidNumber': '11',
|
||||
+ 'homeDirectory': '/home/shadowUser',
|
||||
+ 'displayName': 'Shadow User',
|
||||
+ 'givenname': 'Shadow',
|
||||
+ 'mail':f'shadowuser@{DEFAULT_SUFFIX}',
|
||||
+ 'userpassword': 'password'
|
||||
+ })
|
||||
+
|
||||
+ def fin():
|
||||
+ if shadowUser.exists():
|
||||
+ shadowUser.delete()
|
||||
+
|
||||
+ request.addfinalizer(fin)
|
||||
+
|
||||
+ return shadowUser
|
||||
+
|
||||
+
|
||||
+def days_to_secs(days):
|
||||
+ """ Convert days to seconds """
|
||||
+ return days * 86400
|
||||
+
|
||||
+
|
||||
+def check_shadow_attr_value(inst, user_dn, attr_type, expected):
|
||||
+ """ Check that shadowAccount attribute has expected value """
|
||||
+ dm = DirectoryManager(inst)
|
||||
+ dm.rebind()
|
||||
+ user = UserAccount(inst, user_dn)
|
||||
+ assert user.present(attr_type), f'Entry {user_dn} does not have {attr_type} attribute'
|
||||
+ actual = int(user.get_attr_val_utf8(attr_type))
|
||||
+ assert actual == expected, f'{attr_type} of entry {user_dn} is {actual}, expected {expected}'
|
||||
+ log.info(f'{attr_type} of entry {user_dn} has expected value {actual}')
|
||||
+
|
||||
+
|
||||
+def setup_pwp(inst, pwp_mgr, policy, dn=None, policy_props=None):
|
||||
+ """ Setup password policy """
|
||||
+
|
||||
+ log.info(f'Setting up {policy} password policy for {dn}')
|
||||
+ dm = DirectoryManager(inst)
|
||||
+ dm.rebind()
|
||||
+
|
||||
+ log.info(f'Configuring {policy} password policy')
|
||||
+
|
||||
+ assert policy == 'global' or dn, 'dn is required for non-global policy'
|
||||
+
|
||||
+ if not policy_props:
|
||||
+ policy_props = {
|
||||
+ 'passwordMinAge': str(days_to_secs(1)),
|
||||
+ 'passwordExp': 'on',
|
||||
+ 'passwordMaxAge': str(days_to_secs(10)),
|
||||
+ 'passwordWarning': str(days_to_secs(3))
|
||||
+ }
|
||||
+
|
||||
+ if policy == 'global':
|
||||
+ pwp_mgr.set_global_policy(policy_props)
|
||||
+ elif policy == 'subtree':
|
||||
+ pwp_mgr.create_subtree_policy(dn, policy_props)
|
||||
+ elif policy == 'user':
|
||||
+ pwp_mgr.create_user_policy(dn, policy_props)
|
||||
+ else:
|
||||
+ raise ValueError(f'Invalid type of password policy: {policy}')
|
||||
+
|
||||
+
|
||||
+def modify_pwp(inst, pwp_mgr, policy, dn=None, policy_props=None):
|
||||
+ """ Modify password policy """
|
||||
+ dm = DirectoryManager(inst)
|
||||
+ dm.rebind()
|
||||
+
|
||||
+ assert policy == 'global' or dn, 'dn is required for non-global policy'
|
||||
+
|
||||
+ if not policy_props:
|
||||
+ policy_props = {
|
||||
+ 'passwordMinAge': str(days_to_secs(3)),
|
||||
+ 'passwordMaxAge': str(days_to_secs(30)),
|
||||
+ 'passwordWarning': str(days_to_secs(9))
|
||||
+ }
|
||||
+
|
||||
+ if policy == 'global':
|
||||
+ pwp_mgr.set_global_policy(properties=policy_props)
|
||||
+ elif policy in ['subtree', 'user']:
|
||||
+ policy_entry = pwp_mgr.get_pwpolicy_entry(dn)
|
||||
+ policy_entry.replace_many(*policy_props.items())
|
||||
+ else:
|
||||
+ raise ValueError(f'Invalid type of password policy: {policy}')
|
||||
+ log.info(f'Modified {policy} policy with {policy_props}.')
|
||||
+
|
||||
+@pytest.mark.skipif(ds_is_older('1.3.6'), reason="Not implemented")
|
||||
+def test_shadowaccount_no_policy(topology_st, shadowUser):
|
||||
+ """Check shadowAccount under no password policy
|
||||
+
|
||||
+ :id: a1b2c3d4-5e6f-7890-abcd-ef1234567890
|
||||
+ :setup: Standalone instance
|
||||
+ :steps:
|
||||
+ 1. Add a user with shadowAccount objectclass
|
||||
+ 2. Bind as the user
|
||||
+ 3. Check shadowLastChange attribute is set correctly
|
||||
+ :expectedresults:
|
||||
+ 1. User is added successfully
|
||||
+ 2. Bind is successful
|
||||
+ 3. shadowLastChange is set correctly (days since epoch)
|
||||
+ """
|
||||
+
|
||||
+ edate = int(time.time() / (60 * 60 * 24))
|
||||
+
|
||||
+ log.info(f"Bind as {shadowUser.dn}")
|
||||
+ shadowUser.rebind('password')
|
||||
+ check_shadow_attr_value(topology_st.standalone, shadowUser.dn,
|
||||
+ 'shadowLastChange', edate)
|
||||
+
|
||||
+
|
||||
+@pytest.mark.skipif(ds_is_older('1.3.6'), reason="Not implemented")
|
||||
+def test_shadowaccount_global_policy(topology_st, shadowUser, request):
|
||||
+ """Check shadowAccount with global password policy
|
||||
+
|
||||
+ :id: b2c3d4e5-6f7a-8901-bcde-f23456789012
|
||||
+ :setup: Standalone instance
|
||||
+ :steps:
|
||||
+ 1. Set global password policy
|
||||
+ 2. Add a second shadowAccount user
|
||||
+ 3. Bind as each user and check shadowAccount attributes
|
||||
+ 4. Modify global password policy
|
||||
+ 5. Change user password (as the user, not DM)
|
||||
+ 6. Re-bind with new password
|
||||
+ 7. Check shadowAccount attributes are updated
|
||||
+ 8. Clean up - delete second user and reset policy
|
||||
+ :expectedresults:
|
||||
+ 1. Global password policy is set successfully
|
||||
+ 2. Second user is added
|
||||
+ 3. shadowAccount attributes match policy values for both users
|
||||
+ 4. Password policy is modified successfully
|
||||
+ 5. Password is changed successfully
|
||||
+ 6. Re-bind with new password is successful
|
||||
+ 7. shadowAccount attributes are updated to match new policy values
|
||||
+ 8. Cleanup is successful
|
||||
+ """
|
||||
+ inst = topology_st.standalone
|
||||
+
|
||||
+ log.info('Create second shadowAccount user')
|
||||
+ users = UserAccounts(inst, DEFAULT_SUFFIX)
|
||||
+ shadowUser2 = users.create(properties={
|
||||
+ 'objectclass': ['top', 'person', 'organizationalPerson',
|
||||
+ 'inetOrgPerson', 'extensibleObject', 'shadowAccount'],
|
||||
+ 'sn': '2',
|
||||
+ 'cn': 'shadowUser2',
|
||||
+ 'uid': 'shadowUser2',
|
||||
+ 'uidNumber': '2',
|
||||
+ 'gidNumber': '22',
|
||||
+ 'homeDirectory': '/home/shadowUser2',
|
||||
+ 'displayName': 'Shadow User 2',
|
||||
+ 'givenname': 'Shadow2',
|
||||
+ 'mail': f'shadowuser2@{DEFAULT_SUFFIX}',
|
||||
+ 'userpassword': 'password'
|
||||
+ })
|
||||
+
|
||||
+ def fin():
|
||||
+ log.info('Clean up - delete second user and reset global policy')
|
||||
+ dm = DirectoryManager(inst)
|
||||
+ dm.rebind()
|
||||
+ try:
|
||||
+ shadowUser2.delete()
|
||||
+ except Exception:
|
||||
+ pass
|
||||
+ inst.config.replace('passwordMinAge', '0')
|
||||
+ inst.config.replace('passwordMaxAge', '8640000')
|
||||
+ inst.config.replace('passwordWarning', '86400')
|
||||
+ inst.config.replace('passwordExp', 'off')
|
||||
+ request.addfinalizer(fin)
|
||||
+
|
||||
+ log.info('Configure global password policy')
|
||||
+ pwp_mgr = PwPolicyManager(inst)
|
||||
+ setup_pwp(inst, pwp_mgr, 'global')
|
||||
+
|
||||
+ edate = int(time.time() / (60 * 60 * 24))
|
||||
+
|
||||
+ log.info('Verify attributes of shadowUser (user 1)')
|
||||
+ shadowUser.rebind('password')
|
||||
+ check_shadow_attr_value(inst, shadowUser.dn,
|
||||
+ 'shadowLastChange', edate)
|
||||
+ check_shadow_attr_value(inst, shadowUser.dn,
|
||||
+ 'shadowMin', 1)
|
||||
+ check_shadow_attr_value(inst, shadowUser.dn,
|
||||
+ 'shadowMax', 10)
|
||||
+ check_shadow_attr_value(inst, shadowUser.dn,
|
||||
+ 'shadowWarning', 3)
|
||||
+
|
||||
+ log.info('Verify attributes of shadowUser2 (user 2)')
|
||||
+ shadowUser2.rebind('password')
|
||||
+ check_shadow_attr_value(inst, shadowUser2.dn,
|
||||
+ 'shadowLastChange', edate)
|
||||
+ check_shadow_attr_value(inst, shadowUser2.dn,
|
||||
+ 'shadowMin', 1)
|
||||
+ check_shadow_attr_value(inst, shadowUser2.dn,
|
||||
+ 'shadowMax', 10)
|
||||
+ check_shadow_attr_value(inst, shadowUser2.dn,
|
||||
+ 'shadowWarning', 3)
|
||||
+
|
||||
+ log.info('Modify global password policy')
|
||||
+ modify_pwp(inst, pwp_mgr, 'global')
|
||||
+
|
||||
+ log.info('Change shadowUser2 password as the user')
|
||||
+ shadowUser2.rebind('password')
|
||||
+ shadowUser2.replace('userpassword', 'password2')
|
||||
+ time.sleep(1)
|
||||
+
|
||||
+ log.info('Re-bind as shadowUser2 with new password')
|
||||
+ shadowUser2.rebind('password2')
|
||||
+
|
||||
+ log.info('Verify modified shadowUser2 attributes')
|
||||
+ check_shadow_attr_value(inst, shadowUser2.dn,
|
||||
+ 'shadowMin', 3)
|
||||
+ check_shadow_attr_value(inst, shadowUser2.dn,
|
||||
+ 'shadowMax', 30)
|
||||
+ check_shadow_attr_value(inst, shadowUser2.dn,
|
||||
+ 'shadowWarning', 9)
|
||||
+
|
||||
+
|
||||
+@pytest.mark.skipif(ds_is_older('1.3.6'), reason="Not implemented")
|
||||
+def test_shadowaccount_subtree_policy(topology_st, request):
|
||||
+ """Check shadowAccount with subtree level password policy
|
||||
+
|
||||
+ :id: c3d4e5f6-7a8b-9012-cdef-345678901234
|
||||
+ :setup: Standalone instance
|
||||
+ :steps:
|
||||
+ 1. Create subtree password policy for DEFAULT_SUFFIX with passwordMustChange on
|
||||
+ 2. Add a new shadowAccount user under the subtree
|
||||
+ 3. Check shadowLastChange is 0 (since passwordMustChange is on)
|
||||
+ 4. Verify search as user fails with UNWILLING_TO_PERFORM
|
||||
+ 5. Change user password (as user)
|
||||
+ 6. Re-bind with new password
|
||||
+ 7. Check shadowAccount attributes are updated with correct values
|
||||
+ 8. Clean up subtree password policy
|
||||
+ :expectedresults:
|
||||
+ 1. Subtree password policy is created successfully
|
||||
+ 2. User is added successfully
|
||||
+ 3. shadowLastChange is 0 until password is changed
|
||||
+ 4. Search fails with UNWILLING_TO_PERFORM as expected
|
||||
+ 5. Password is changed successfully
|
||||
+ 6. Re-bind with new password is successful
|
||||
+ 7. shadowAccount attributes are updated to match policy values
|
||||
+ 8. Subtree password policy is deleted successfully
|
||||
+ """
|
||||
+ inst = topology_st.standalone
|
||||
+ subtree_dn = DEFAULT_SUFFIX
|
||||
+
|
||||
+ log.info('Configure subtree password policy with passwordMustChange on')
|
||||
+ properties = {
|
||||
+ 'passwordMustChange': 'on',
|
||||
+ 'passwordExp': 'on',
|
||||
+ 'passwordMinAge': str(days_to_secs(2)),
|
||||
+ 'passwordMaxAge': str(days_to_secs(20)),
|
||||
+ 'passwordWarning': str(days_to_secs(6)),
|
||||
+ 'passwordChange': 'on',
|
||||
+ 'passwordStorageScheme': 'clear'
|
||||
+ }
|
||||
+
|
||||
+ pwp_mgr = PwPolicyManager(inst)
|
||||
+ setup_pwp(inst, pwp_mgr, 'subtree', dn=subtree_dn, policy_props=properties)
|
||||
+
|
||||
+ def fin():
|
||||
+ log.info('Clean up: delete subtree password policy')
|
||||
+ dm = DirectoryManager(inst)
|
||||
+ dm.rebind()
|
||||
+ try:
|
||||
+ pwp_mgr.delete_local_policy(subtree_dn)
|
||||
+ except Exception:
|
||||
+ pass
|
||||
+ try:
|
||||
+ subtree_user.delete()
|
||||
+ except Exception:
|
||||
+ pass
|
||||
+ request.addfinalizer(fin)
|
||||
+
|
||||
+ log.info('Add a new shadowAccount user under the subtree')
|
||||
+ users = UserAccounts(inst, DEFAULT_SUFFIX)
|
||||
+ subtree_user = users.create(properties={
|
||||
+ 'objectclass': ['top', 'person', 'organizationalPerson',
|
||||
+ 'inetOrgPerson', 'extensibleObject', 'shadowAccount'],
|
||||
+ 'sn': '3',
|
||||
+ 'cn': 'subtreeUser',
|
||||
+ 'uid': 'subtreeUser',
|
||||
+ 'uidNumber': '3',
|
||||
+ 'gidNumber': '33',
|
||||
+ 'homeDirectory': '/home/subtreeUser',
|
||||
+ 'displayName': 'Subtree User',
|
||||
+ 'givenname': 'Subtree',
|
||||
+ 'mail': f'subtreeuser@{DEFAULT_SUFFIX}',
|
||||
+ 'userpassword': 'password'
|
||||
+ })
|
||||
+
|
||||
+ dm = DirectoryManager(inst)
|
||||
+ dm.rebind()
|
||||
+
|
||||
+ log.info('Verify shadowLastChange is 0 since passwordMustChange is on')
|
||||
+ check_shadow_attr_value(inst, subtree_user.dn,
|
||||
+ 'shadowLastChange', 0)
|
||||
+ check_shadow_attr_value(inst, subtree_user.dn,
|
||||
+ 'shadowMin', 2)
|
||||
+ check_shadow_attr_value(inst, subtree_user.dn,
|
||||
+ 'shadowMax', 20)
|
||||
+ check_shadow_attr_value(inst, subtree_user.dn,
|
||||
+ 'shadowWarning', 6)
|
||||
+
|
||||
+ log.info(f'Bind as {subtree_user.dn} and verify search fails with UNWILLING_TO_PERFORM')
|
||||
+ subtree_user.rebind('password')
|
||||
+ with pytest.raises(ldap.UNWILLING_TO_PERFORM):
|
||||
+ subtree_user.exists()
|
||||
+
|
||||
+ log.info('Modify subtree password policy')
|
||||
+ dm.rebind()
|
||||
+ modify_properties = {
|
||||
+ 'passwordMinAge': str(days_to_secs(4)),
|
||||
+ 'passwordMaxAge': str(days_to_secs(40)),
|
||||
+ 'passwordWarning': str(days_to_secs(12))
|
||||
+ }
|
||||
+ modify_pwp(inst, pwp_mgr, 'subtree', dn=subtree_dn, policy_props=modify_properties)
|
||||
+
|
||||
+ log.info(f'Change {subtree_user.dn} password as the user')
|
||||
+ subtree_user.rebind('password')
|
||||
+ subtree_user.replace('userpassword', 'password0')
|
||||
+ time.sleep(1)
|
||||
+
|
||||
+ log.info(f'Re-bind as {subtree_user.dn} with new password')
|
||||
+ subtree_user.rebind('password0')
|
||||
+
|
||||
+ edate = int(time.time() / (60 * 60 * 24))
|
||||
+
|
||||
+ log.info('Verify shadowLastChange is now set to today after password change')
|
||||
+ check_shadow_attr_value(inst, subtree_user.dn,
|
||||
+ 'shadowLastChange', edate)
|
||||
+ check_shadow_attr_value(inst, subtree_user.dn,
|
||||
+ 'shadowMin', 4)
|
||||
+ check_shadow_attr_value(inst, subtree_user.dn,
|
||||
+ 'shadowMax', 40)
|
||||
+ check_shadow_attr_value(inst, subtree_user.dn,
|
||||
+ 'shadowWarning', 12)
|
||||
+
|
||||
+
|
||||
+@pytest.mark.skipif(ds_is_older('1.3.6'), reason="Not implemented")
|
||||
+def test_shadowaccount_user_policy(topology_st, request):
|
||||
+ """Check shadowAccount with user level password policy
|
||||
+
|
||||
+ :id: d4e5f6a7-8b9c-0123-def0-456789012345
|
||||
+ :setup: Standalone instance
|
||||
+ :steps:
|
||||
+ 1. Create a new shadowAccount user
|
||||
+ 2. Create user password policy
|
||||
+ 3. Verify shadowAccount attributes match policy values
|
||||
+ 4. Modify user password policy
|
||||
+ 5. Change user password
|
||||
+ 6. Re-bind with new password
|
||||
+ 7. Check shadowAccount attributes are updated
|
||||
+ 8. Clean up user password policy
|
||||
+ :expectedresults:
|
||||
+ 1. User is created successfully
|
||||
+ 2. User password policy is created successfully
|
||||
+ 3. shadowAccount attributes match policy values
|
||||
+ 4. Password policy is modified successfully
|
||||
+ 5. Password is changed successfully
|
||||
+ 6. Re-bind with new password is successful
|
||||
+ 7. shadowAccount attributes are updated to match new policy values
|
||||
+ 8. User password policy is deleted successfully
|
||||
+ """
|
||||
+ inst = topology_st.standalone
|
||||
+
|
||||
+ log.info('Create a new shadowAccount user for user policy test')
|
||||
+ users = UserAccounts(inst, DEFAULT_SUFFIX)
|
||||
+ user_policy_user = users.create(properties={
|
||||
+ 'objectclass': ['top', 'person', 'organizationalPerson',
|
||||
+ 'inetOrgPerson', 'extensibleObject', 'shadowAccount'],
|
||||
+ 'sn': '4',
|
||||
+ 'cn': 'userPolicyUser',
|
||||
+ 'uid': 'userPolicyUser',
|
||||
+ 'uidNumber': '4',
|
||||
+ 'gidNumber': '44',
|
||||
+ 'homeDirectory': '/home/userPolicyUser',
|
||||
+ 'displayName': 'User Policy User',
|
||||
+ 'givenname': 'UserPolicy',
|
||||
+ 'mail': f'userpolicyuser@{DEFAULT_SUFFIX}',
|
||||
+ 'userpassword': 'password'
|
||||
+ })
|
||||
+
|
||||
+ pwp_mgr = PwPolicyManager(inst)
|
||||
+
|
||||
+ def fin():
|
||||
+ log.info('Clean up: delete user password policy and user')
|
||||
+ dm = DirectoryManager(inst)
|
||||
+ dm.rebind()
|
||||
+ try:
|
||||
+ pwp_mgr.delete_local_policy(user_policy_user.dn)
|
||||
+ except Exception:
|
||||
+ pass
|
||||
+ try:
|
||||
+ user_policy_user.delete()
|
||||
+ except Exception:
|
||||
+ pass
|
||||
+ request.addfinalizer(fin)
|
||||
+
|
||||
+ log.info('Configure user password policy')
|
||||
+ properties = {
|
||||
+ 'passwordExp': 'on',
|
||||
+ 'passwordMinAge': str(days_to_secs(2)),
|
||||
+ 'passwordMaxAge': str(days_to_secs(20)),
|
||||
+ 'passwordWarning': str(days_to_secs(6)),
|
||||
+ 'passwordChange': 'on',
|
||||
+ 'passwordStorageScheme': 'clear'
|
||||
+ }
|
||||
+ setup_pwp(inst, pwp_mgr, 'user', dn=user_policy_user.dn, policy_props=properties)
|
||||
+
|
||||
+ edate = int(time.time() / (60 * 60 * 24))
|
||||
+
|
||||
+ dm = DirectoryManager(inst)
|
||||
+ dm.rebind()
|
||||
+
|
||||
+ log.info('Verify shadowAccount attributes match user policy')
|
||||
+ check_shadow_attr_value(inst, user_policy_user.dn,
|
||||
+ 'shadowLastChange', edate)
|
||||
+ check_shadow_attr_value(inst, user_policy_user.dn,
|
||||
+ 'shadowMin', 2)
|
||||
+ check_shadow_attr_value(inst, user_policy_user.dn,
|
||||
+ 'shadowMax', 20)
|
||||
+ check_shadow_attr_value(inst, user_policy_user.dn,
|
||||
+ 'shadowWarning', 6)
|
||||
+
|
||||
+ log.info('Modify user password policy')
|
||||
+ modify_properties = {
|
||||
+ 'passwordMinAge': str(days_to_secs(4)),
|
||||
+ 'passwordMaxAge': str(days_to_secs(40)),
|
||||
+ 'passwordWarning': str(days_to_secs(12))
|
||||
+ }
|
||||
+ modify_pwp(inst, pwp_mgr, 'user', dn=user_policy_user.dn, policy_props=modify_properties)
|
||||
+
|
||||
+ log.info(f'Change {user_policy_user.dn} password as the user')
|
||||
+ user_policy_user.rebind('password')
|
||||
+ user_policy_user.replace('userpassword', 'password0')
|
||||
+ time.sleep(1)
|
||||
+
|
||||
+ log.info(f'Re-bind as {user_policy_user.dn} with new password')
|
||||
+ user_policy_user.rebind('password0')
|
||||
+
|
||||
+ edate = int(time.time() / (60 * 60 * 24))
|
||||
+
|
||||
+ log.info('Verify shadowAccount attributes are updated after password change')
|
||||
+ check_shadow_attr_value(inst, user_policy_user.dn,
|
||||
+ 'shadowLastChange', edate)
|
||||
+ check_shadow_attr_value(inst, user_policy_user.dn,
|
||||
+ 'shadowMin', 4)
|
||||
+ check_shadow_attr_value(inst, user_policy_user.dn,
|
||||
+ 'shadowMax', 40)
|
||||
+ check_shadow_attr_value(inst, user_policy_user.dn,
|
||||
+ 'shadowWarning', 12)
|
||||
+
|
||||
+
|
||||
if __name__ == '__main__':
|
||||
# Run isolated
|
||||
# -s for DEBUG mode
|
||||
diff --git a/dirsrvtests/tests/tickets/ticket548_test.py b/dirsrvtests/tests/tickets/ticket548_test.py
|
||||
deleted file mode 100644
|
||||
index cac3cc5f8..000000000
|
||||
--- a/dirsrvtests/tests/tickets/ticket548_test.py
|
||||
+++ /dev/null
|
||||
@@ -1,408 +0,0 @@
|
||||
-# --- BEGIN COPYRIGHT BLOCK ---
|
||||
-# Copyright (C) 2016 Red Hat, Inc.
|
||||
-# All rights reserved.
|
||||
-#
|
||||
-# License: GPL (version 3 or any later version).
|
||||
-# See LICENSE for details.
|
||||
-# --- END COPYRIGHT BLOCK ---
|
||||
-#
|
||||
-import pytest
|
||||
-from lib389.tasks import *
|
||||
-from lib389.utils import *
|
||||
-from lib389.topologies import topology_st
|
||||
-
|
||||
-from lib389._constants import DEFAULT_SUFFIX, DN_CONFIG, DN_DM, PASSWORD, DEFAULT_SUFFIX_ESCAPED
|
||||
-
|
||||
-# Skip on older versions
|
||||
-pytestmark = [pytest.mark.tier2,
|
||||
- pytest.mark.skipif(ds_is_older('1.3.6'), reason="Not implemented")]
|
||||
-
|
||||
-log = logging.getLogger(__name__)
|
||||
-
|
||||
-# Assuming DEFAULT_SUFFIX is "dc=example,dc=com", otherwise it does not work... :(
|
||||
-SUBTREE_CONTAINER = 'cn=nsPwPolicyContainer,' + DEFAULT_SUFFIX
|
||||
-SUBTREE_PWPDN = 'cn=nsPwPolicyEntry,' + DEFAULT_SUFFIX
|
||||
-SUBTREE_PWP = 'cn=cn\3DnsPwPolicyEntry\2C' + DEFAULT_SUFFIX_ESCAPED + ',' + SUBTREE_CONTAINER
|
||||
-SUBTREE_COS_TMPLDN = 'cn=nsPwTemplateEntry,' + DEFAULT_SUFFIX
|
||||
-SUBTREE_COS_TMPL = 'cn=cn\3DnsPwTemplateEntry\2C' + DEFAULT_SUFFIX_ESCAPED + ',' + SUBTREE_CONTAINER
|
||||
-SUBTREE_COS_DEF = 'cn=nsPwPolicy_CoS,' + DEFAULT_SUFFIX
|
||||
-
|
||||
-USER1_DN = 'uid=user1,' + DEFAULT_SUFFIX
|
||||
-USER2_DN = 'uid=user2,' + DEFAULT_SUFFIX
|
||||
-USER3_DN = 'uid=user3,' + DEFAULT_SUFFIX
|
||||
-USER_PW = 'password'
|
||||
-
|
||||
-
|
||||
-def days_to_secs(days):
|
||||
- # Value of 60 * 60 * 24
|
||||
- return days * 86400
|
||||
-
|
||||
-
|
||||
-# Values are in days
|
||||
-def set_global_pwpolicy(topology_st, min_=1, max_=10, warn=3):
|
||||
- log.info(" +++++ Enable global password policy +++++\n")
|
||||
- # Enable password policy
|
||||
- try:
|
||||
- topology_st.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'nsslapd-pwpolicy-local', b'on')])
|
||||
- except ldap.LDAPError as e:
|
||||
- log.error('Failed to set pwpolicy-local: error ' + e.message['desc'])
|
||||
- assert False
|
||||
-
|
||||
- # Convert our values to seconds
|
||||
- min_secs = days_to_secs(min_)
|
||||
- max_secs = days_to_secs(max_)
|
||||
- warn_secs = days_to_secs(warn)
|
||||
-
|
||||
- log.info(" Set global password Min Age -- %s day\n" % min_)
|
||||
- try:
|
||||
- topology_st.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'passwordMinAge', ('%s' % min_secs).encode())])
|
||||
- except ldap.LDAPError as e:
|
||||
- log.error('Failed to set passwordMinAge: error ' + e.message['desc'])
|
||||
- assert False
|
||||
-
|
||||
- log.info(" Set global password Expiration -- on\n")
|
||||
- try:
|
||||
- topology_st.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'passwordExp', b'on')])
|
||||
- except ldap.LDAPError as e:
|
||||
- log.error('Failed to set passwordExp: error ' + e.message['desc'])
|
||||
- assert False
|
||||
-
|
||||
- log.info(" Set global password Max Age -- %s days\n" % max_)
|
||||
- try:
|
||||
- topology_st.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'passwordMaxAge', ('%s' % max_secs).encode())])
|
||||
- except ldap.LDAPError as e:
|
||||
- log.error('Failed to set passwordMaxAge: error ' + e.message['desc'])
|
||||
- assert False
|
||||
-
|
||||
- log.info(" Set global password Warning -- %s days\n" % warn)
|
||||
- try:
|
||||
- topology_st.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'passwordWarning', ('%s' % warn_secs).encode())])
|
||||
- except ldap.LDAPError as e:
|
||||
- log.error('Failed to set passwordWarning: error ' + e.message['desc'])
|
||||
- assert False
|
||||
-
|
||||
-
|
||||
-def set_subtree_pwpolicy(topology_st, min_=2, max_=20, warn=6):
|
||||
- log.info(" +++++ Enable subtree level password policy +++++\n")
|
||||
-
|
||||
- # Convert our values to seconds
|
||||
- min_secs = days_to_secs(min_)
|
||||
- max_secs = days_to_secs(max_)
|
||||
- warn_secs = days_to_secs(warn)
|
||||
-
|
||||
- log.info(" Add the container")
|
||||
- try:
|
||||
- topology_st.standalone.add_s(Entry((SUBTREE_CONTAINER, {'objectclass': 'top nsContainer'.split(),
|
||||
- 'cn': 'nsPwPolicyContainer'})))
|
||||
- except ldap.ALREADY_EXISTS:
|
||||
- pass
|
||||
- except ldap.LDAPError as e:
|
||||
- log.error('Failed to add subtree container: error ' + e.message['desc'])
|
||||
- # assert False
|
||||
-
|
||||
- try:
|
||||
- # Purge the old policy
|
||||
- topology_st.standalone.delete_s(SUBTREE_PWP)
|
||||
- except:
|
||||
- pass
|
||||
-
|
||||
- log.info(
|
||||
- " Add the password policy subentry {passwordMustChange: on, passwordMinAge: %s, passwordMaxAge: %s, passwordWarning: %s}" % (
|
||||
- min_, max_, warn))
|
||||
- try:
|
||||
- topology_st.standalone.add_s(Entry((SUBTREE_PWP, {'objectclass': 'top ldapsubentry passwordpolicy'.split(),
|
||||
- 'cn': SUBTREE_PWPDN,
|
||||
- 'passwordMustChange': 'on',
|
||||
- 'passwordExp': 'on',
|
||||
- 'passwordMinAge': '%s' % min_secs,
|
||||
- 'passwordMaxAge': '%s' % max_secs,
|
||||
- 'passwordWarning': '%s' % warn_secs,
|
||||
- 'passwordChange': 'on',
|
||||
- 'passwordStorageScheme': 'clear'})))
|
||||
- except ldap.LDAPError as e:
|
||||
- log.error('Failed to add passwordpolicy: error ' + e.message['desc'])
|
||||
- assert False
|
||||
-
|
||||
- log.info(" Add the COS template")
|
||||
- try:
|
||||
- topology_st.standalone.add_s(
|
||||
- Entry((SUBTREE_COS_TMPL, {'objectclass': 'top ldapsubentry costemplate extensibleObject'.split(),
|
||||
- 'cn': SUBTREE_PWPDN,
|
||||
- 'cosPriority': '1',
|
||||
- 'cn': SUBTREE_COS_TMPLDN,
|
||||
- 'pwdpolicysubentry': SUBTREE_PWP})))
|
||||
- except ldap.ALREADY_EXISTS:
|
||||
- pass
|
||||
- except ldap.LDAPError as e:
|
||||
- log.error('Failed to add COS template: error ' + e.message['desc'])
|
||||
- # assert False
|
||||
-
|
||||
- log.info(" Add the COS definition")
|
||||
- try:
|
||||
- topology_st.standalone.add_s(
|
||||
- Entry((SUBTREE_COS_DEF, {'objectclass': 'top ldapsubentry cosSuperDefinition cosPointerDefinition'.split(),
|
||||
- 'cn': SUBTREE_PWPDN,
|
||||
- 'costemplatedn': SUBTREE_COS_TMPL,
|
||||
- 'cosAttribute': 'pwdpolicysubentry default operational-default'})))
|
||||
- except ldap.ALREADY_EXISTS:
|
||||
- pass
|
||||
- except ldap.LDAPError as e:
|
||||
- log.error('Failed to add COS def: error ' + e.message['desc'])
|
||||
- # assert False
|
||||
-
|
||||
- time.sleep(1)
|
||||
-
|
||||
-
|
||||
-def update_passwd(topology_st, user, passwd, newpasswd):
|
||||
- log.info(" Bind as {%s,%s}" % (user, passwd))
|
||||
- topology_st.standalone.simple_bind_s(user, passwd)
|
||||
- try:
|
||||
- topology_st.standalone.modify_s(user, [(ldap.MOD_REPLACE, 'userpassword', newpasswd.encode())])
|
||||
- except ldap.LDAPError as e:
|
||||
- log.fatal('test_ticket548: Failed to update the password ' + cpw + ' of user ' + user + ': error ' + e.message[
|
||||
- 'desc'])
|
||||
- assert False
|
||||
-
|
||||
- time.sleep(1)
|
||||
-
|
||||
-
|
||||
-def check_shadow_attr_value(entry, attr_type, expected, dn):
|
||||
- if entry.hasAttr(attr_type):
|
||||
- actual = entry.getValue(attr_type)
|
||||
- if int(actual) == expected:
|
||||
- log.info('%s of entry %s has expected value %s' % (attr_type, dn, actual))
|
||||
- assert True
|
||||
- else:
|
||||
- log.fatal('%s %s of entry %s does not have expected value %s' % (attr_type, actual, dn, expected))
|
||||
- assert False
|
||||
- else:
|
||||
- log.fatal('entry %s does not have %s attr' % (dn, attr_type))
|
||||
- assert False
|
||||
-
|
||||
-
|
||||
-def test_ticket548_test_with_no_policy(topology_st):
|
||||
- """
|
||||
- Check shadowAccount under no password policy
|
||||
- """
|
||||
- log.info("Case 1. No password policy")
|
||||
-
|
||||
- log.info("Bind as %s" % DN_DM)
|
||||
- topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
|
||||
-
|
||||
- log.info('Add an entry' + USER1_DN)
|
||||
- try:
|
||||
- topology_st.standalone.add_s(
|
||||
- Entry((USER1_DN, {'objectclass': "top person organizationalPerson inetOrgPerson shadowAccount".split(),
|
||||
- 'sn': '1',
|
||||
- 'cn': 'user 1',
|
||||
- 'uid': 'user1',
|
||||
- 'givenname': 'user',
|
||||
- 'mail': 'user1@' + DEFAULT_SUFFIX,
|
||||
- 'userpassword': USER_PW})))
|
||||
- except ldap.LDAPError as e:
|
||||
- log.fatal('test_ticket548: Failed to add user' + USER1_DN + ': error ' + e.message['desc'])
|
||||
- assert False
|
||||
-
|
||||
- edate = int(time.time() / (60 * 60 * 24))
|
||||
- log.info('Search entry %s' % USER1_DN)
|
||||
-
|
||||
- log.info("Bind as %s" % USER1_DN)
|
||||
- topology_st.standalone.simple_bind_s(USER1_DN, USER_PW)
|
||||
- entry = topology_st.standalone.getEntry(USER1_DN, ldap.SCOPE_BASE, "(objectclass=*)", ['shadowLastChange'])
|
||||
- check_shadow_attr_value(entry, 'shadowLastChange', edate, USER1_DN)
|
||||
-
|
||||
- log.info("Check shadowAccount with no policy was successfully verified.")
|
||||
-
|
||||
-
|
||||
-def test_ticket548_test_global_policy(topology_st):
|
||||
- """
|
||||
- Check shadowAccount with global password policy
|
||||
- """
|
||||
-
|
||||
- log.info("Case 2. Check shadowAccount with global password policy")
|
||||
-
|
||||
- log.info("Bind as %s" % DN_DM)
|
||||
- topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
|
||||
-
|
||||
- set_global_pwpolicy(topology_st)
|
||||
-
|
||||
- log.info('Add an entry' + USER2_DN)
|
||||
- try:
|
||||
- topology_st.standalone.add_s(
|
||||
- Entry((USER2_DN, {'objectclass': "top person organizationalPerson inetOrgPerson shadowAccount".split(),
|
||||
- 'sn': '2',
|
||||
- 'cn': 'user 2',
|
||||
- 'uid': 'user2',
|
||||
- 'givenname': 'user',
|
||||
- 'mail': 'user2@' + DEFAULT_SUFFIX,
|
||||
- 'userpassword': USER_PW})))
|
||||
- except ldap.LDAPError as e:
|
||||
- log.fatal('test_ticket548: Failed to add user' + USER2_DN + ': error ' + e.message['desc'])
|
||||
- assert False
|
||||
-
|
||||
- edate = int(time.time() / (60 * 60 * 24))
|
||||
-
|
||||
- log.info("Bind as %s" % USER1_DN)
|
||||
- topology_st.standalone.simple_bind_s(USER1_DN, USER_PW)
|
||||
-
|
||||
- log.info('Search entry %s' % USER1_DN)
|
||||
- entry = topology_st.standalone.getEntry(USER1_DN, ldap.SCOPE_BASE, "(objectclass=*)")
|
||||
- check_shadow_attr_value(entry, 'shadowLastChange', edate, USER1_DN)
|
||||
-
|
||||
- # passwordMinAge -- 1 day
|
||||
- check_shadow_attr_value(entry, 'shadowMin', 1, USER1_DN)
|
||||
-
|
||||
- # passwordMaxAge -- 10 days
|
||||
- check_shadow_attr_value(entry, 'shadowMax', 10, USER1_DN)
|
||||
-
|
||||
- # passwordWarning -- 3 days
|
||||
- check_shadow_attr_value(entry, 'shadowWarning', 3, USER1_DN)
|
||||
-
|
||||
- log.info("Bind as %s" % USER2_DN)
|
||||
- topology_st.standalone.simple_bind_s(USER2_DN, USER_PW)
|
||||
-
|
||||
- log.info('Search entry %s' % USER2_DN)
|
||||
- entry = topology_st.standalone.getEntry(USER2_DN, ldap.SCOPE_BASE, "(objectclass=*)")
|
||||
- check_shadow_attr_value(entry, 'shadowLastChange', edate, USER2_DN)
|
||||
-
|
||||
- # passwordMinAge -- 1 day
|
||||
- check_shadow_attr_value(entry, 'shadowMin', 1, USER2_DN)
|
||||
-
|
||||
- # passwordMaxAge -- 10 days
|
||||
- check_shadow_attr_value(entry, 'shadowMax', 10, USER2_DN)
|
||||
-
|
||||
- # passwordWarning -- 3 days
|
||||
- check_shadow_attr_value(entry, 'shadowWarning', 3, USER2_DN)
|
||||
-
|
||||
- # Bind as DM again, change policy
|
||||
- log.info("Bind as %s" % DN_DM)
|
||||
- topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
|
||||
- set_global_pwpolicy(topology_st, 3, 30, 9)
|
||||
-
|
||||
- # change the user password, then check again.
|
||||
- log.info("Bind as %s" % USER2_DN)
|
||||
- topology_st.standalone.simple_bind_s(USER2_DN, USER_PW)
|
||||
-
|
||||
- newpasswd = USER_PW + '2'
|
||||
- update_passwd(topology_st, USER2_DN, USER_PW, newpasswd)
|
||||
-
|
||||
- log.info("Re-bind as %s with new password" % USER2_DN)
|
||||
- topology_st.standalone.simple_bind_s(USER2_DN, newpasswd)
|
||||
-
|
||||
- ## This tests if we update the shadow values on password change.
|
||||
- log.info('Search entry %s' % USER2_DN)
|
||||
- entry = topology_st.standalone.getEntry(USER2_DN, ldap.SCOPE_BASE, "(objectclass=*)")
|
||||
-
|
||||
- # passwordMinAge -- 1 day
|
||||
- check_shadow_attr_value(entry, 'shadowMin', 3, USER2_DN)
|
||||
-
|
||||
- # passwordMaxAge -- 10 days
|
||||
- check_shadow_attr_value(entry, 'shadowMax', 30, USER2_DN)
|
||||
-
|
||||
- # passwordWarning -- 3 days
|
||||
- check_shadow_attr_value(entry, 'shadowWarning', 9, USER2_DN)
|
||||
-
|
||||
- log.info("Check shadowAccount with global policy was successfully verified.")
|
||||
-
|
||||
-
|
||||
-def test_ticket548_test_subtree_policy(topology_st):
|
||||
- """
|
||||
- Check shadowAccount with subtree level password policy
|
||||
- """
|
||||
-
|
||||
- log.info("Case 3. Check shadowAccount with subtree level password policy")
|
||||
-
|
||||
- log.info("Bind as %s" % DN_DM)
|
||||
- topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
|
||||
- # Check the global policy values
|
||||
-
|
||||
- set_subtree_pwpolicy(topology_st, 2, 20, 6)
|
||||
-
|
||||
- log.info('Add an entry' + USER3_DN)
|
||||
- try:
|
||||
- topology_st.standalone.add_s(
|
||||
- Entry((USER3_DN, {'objectclass': "top person organizationalPerson inetOrgPerson shadowAccount".split(),
|
||||
- 'sn': '3',
|
||||
- 'cn': 'user 3',
|
||||
- 'uid': 'user3',
|
||||
- 'givenname': 'user',
|
||||
- 'mail': 'user3@' + DEFAULT_SUFFIX,
|
||||
- 'userpassword': USER_PW})))
|
||||
- except ldap.LDAPError as e:
|
||||
- log.fatal('test_ticket548: Failed to add user' + USER3_DN + ': error ' + e.message['desc'])
|
||||
- assert False
|
||||
-
|
||||
- log.info('Search entry %s' % USER3_DN)
|
||||
- entry0 = topology_st.standalone.getEntry(USER3_DN, ldap.SCOPE_BASE, "(objectclass=*)")
|
||||
-
|
||||
- log.info('Expecting shadowLastChange 0 since passwordMustChange is on')
|
||||
- check_shadow_attr_value(entry0, 'shadowLastChange', 0, USER3_DN)
|
||||
-
|
||||
- # passwordMinAge -- 2 day
|
||||
- check_shadow_attr_value(entry0, 'shadowMin', 2, USER3_DN)
|
||||
-
|
||||
- # passwordMaxAge -- 20 days
|
||||
- check_shadow_attr_value(entry0, 'shadowMax', 20, USER3_DN)
|
||||
-
|
||||
- # passwordWarning -- 6 days
|
||||
- check_shadow_attr_value(entry0, 'shadowWarning', 6, USER3_DN)
|
||||
-
|
||||
- log.info("Bind as %s" % USER3_DN)
|
||||
- topology_st.standalone.simple_bind_s(USER3_DN, USER_PW)
|
||||
-
|
||||
- log.info('Search entry %s' % USER3_DN)
|
||||
- try:
|
||||
- entry1 = topology_st.standalone.getEntry(USER3_DN, ldap.SCOPE_BASE, "(objectclass=*)")
|
||||
- except ldap.UNWILLING_TO_PERFORM:
|
||||
- log.info('test_ticket548: Search by' + USER3_DN + ' failed by UNWILLING_TO_PERFORM as expected')
|
||||
- except ldap.LDAPError as e:
|
||||
- log.fatal('test_ticket548: Failed to serch user' + USER3_DN + ' by self: error ' + e.message['desc'])
|
||||
- assert False
|
||||
-
|
||||
- log.info("Bind as %s and updating the password with a new one" % USER3_DN)
|
||||
- topology_st.standalone.simple_bind_s(USER3_DN, USER_PW)
|
||||
-
|
||||
- # Bind as DM again, change policy
|
||||
- log.info("Bind as %s" % DN_DM)
|
||||
- topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
|
||||
-
|
||||
- set_subtree_pwpolicy(topology_st, 4, 40, 12)
|
||||
-
|
||||
- newpasswd = USER_PW + '0'
|
||||
- update_passwd(topology_st, USER3_DN, USER_PW, newpasswd)
|
||||
-
|
||||
- log.info("Re-bind as %s with new password" % USER3_DN)
|
||||
- topology_st.standalone.simple_bind_s(USER3_DN, newpasswd)
|
||||
-
|
||||
- try:
|
||||
- entry2 = topology_st.standalone.getEntry(USER3_DN, ldap.SCOPE_BASE, "(objectclass=*)")
|
||||
- except ldap.LDAPError as e:
|
||||
- log.fatal('test_ticket548: Failed to serch user' + USER3_DN + ' by self: error ' + e.message['desc'])
|
||||
- assert False
|
||||
-
|
||||
- edate = int(time.time() / (60 * 60 * 24))
|
||||
-
|
||||
- log.info('Expecting shadowLastChange %d once userPassword is updated', edate)
|
||||
- check_shadow_attr_value(entry2, 'shadowLastChange', edate, USER3_DN)
|
||||
-
|
||||
- log.info('Search entry %s' % USER3_DN)
|
||||
- entry = topology_st.standalone.getEntry(USER3_DN, ldap.SCOPE_BASE, "(objectclass=*)")
|
||||
- check_shadow_attr_value(entry, 'shadowLastChange', edate, USER3_DN)
|
||||
-
|
||||
- # passwordMinAge -- 1 day
|
||||
- check_shadow_attr_value(entry, 'shadowMin', 4, USER3_DN)
|
||||
-
|
||||
- # passwordMaxAge -- 10 days
|
||||
- check_shadow_attr_value(entry, 'shadowMax', 40, USER3_DN)
|
||||
-
|
||||
- # passwordWarning -- 3 days
|
||||
- check_shadow_attr_value(entry, 'shadowWarning', 12, USER3_DN)
|
||||
-
|
||||
- log.info("Check shadowAccount with subtree level policy was successfully verified.")
|
||||
-
|
||||
-
|
||||
-if __name__ == '__main__':
|
||||
- # Run isolated
|
||||
- # -s for DEBUG mode
|
||||
- CURRENT_FILE = os.path.realpath(__file__)
|
||||
- pytest.main("-s %s" % CURRENT_FILE)
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@ -0,0 +1,82 @@
|
||||
From 7c8a16c6bed524fb54d18a5b7e93d4bd5bb19d49 Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
Date: Wed, 14 Jan 2026 17:55:29 +0100
|
||||
Subject: [PATCH] Issue 7152 - ns-slapd fails to shutdown when deferred
|
||||
memberof update is in progress (#7187)
|
||||
|
||||
Bug Description:
|
||||
When a deferred memberof update is in progress during shutdown, the
|
||||
backend operations (add, modify, delete, modrdn) wait in a polling loop
|
||||
for the deferred task to complete. However, if the deferred thread exits
|
||||
before clearing the SLAPI_DEFERRED_MEMBEROF flag, the loop becomes
|
||||
infinite, causing the server to hang during shutdown.
|
||||
|
||||
Fix Description:
|
||||
Add additional check to the polling loops so they exit immediately when
|
||||
the server is shutting down.
|
||||
|
||||
Fixes: https://github.com/389ds/389-ds-base/issues/7152
|
||||
|
||||
Reviewed by: @tbordaz (Thanks!)
|
||||
---
|
||||
ldap/servers/slapd/back-ldbm/ldbm_add.c | 2 +-
|
||||
ldap/servers/slapd/back-ldbm/ldbm_delete.c | 2 +-
|
||||
ldap/servers/slapd/back-ldbm/ldbm_modify.c | 2 +-
|
||||
ldap/servers/slapd/back-ldbm/ldbm_modrdn.c | 2 +-
|
||||
4 files changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_add.c b/ldap/servers/slapd/back-ldbm/ldbm_add.c
|
||||
index db6024636..90d5abc3d 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/ldbm_add.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/ldbm_add.c
|
||||
@@ -1452,7 +1452,7 @@ common_return:
|
||||
slapi_pblock_get(pb, SLAPI_DEFERRED_MEMBEROF, &deferred);
|
||||
if (deferred) {
|
||||
PRIntervalTime delay = PR_MillisecondsToInterval(100);
|
||||
- while (deferred) {
|
||||
+ while (deferred && !g_get_shutdown()) {
|
||||
DS_Sleep(delay);
|
||||
slapi_pblock_get(pb, SLAPI_DEFERRED_MEMBEROF, &deferred);
|
||||
}
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_delete.c b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
|
||||
index 498342f2d..cbfb5bca9 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/ldbm_delete.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
|
||||
@@ -1536,7 +1536,7 @@ diskfull_return:
|
||||
slapi_pblock_get(pb, SLAPI_DEFERRED_MEMBEROF, &deferred);
|
||||
if (deferred) {
|
||||
PRIntervalTime delay = PR_MillisecondsToInterval(100);
|
||||
- while (deferred) {
|
||||
+ while (deferred && !g_get_shutdown()) {
|
||||
DS_Sleep(delay);
|
||||
slapi_pblock_get(pb, SLAPI_DEFERRED_MEMBEROF, &deferred);
|
||||
}
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modify.c b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
|
||||
index ea49a4c56..c57ba43ae 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/ldbm_modify.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
|
||||
@@ -1179,7 +1179,7 @@ common_return:
|
||||
slapi_pblock_get(pb, SLAPI_DEFERRED_MEMBEROF, &deferred);
|
||||
if (deferred) {
|
||||
PRIntervalTime delay = PR_MillisecondsToInterval(100);
|
||||
- while (deferred) {
|
||||
+ while (deferred && !g_get_shutdown()) {
|
||||
DS_Sleep(delay);
|
||||
slapi_pblock_get(pb, SLAPI_DEFERRED_MEMBEROF, &deferred);
|
||||
}
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
|
||||
index 018ad9e49..759edb80d 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
|
||||
@@ -1469,7 +1469,7 @@ common_return:
|
||||
slapi_pblock_get(pb, SLAPI_DEFERRED_MEMBEROF, &deferred);
|
||||
if (deferred) {
|
||||
PRIntervalTime delay = PR_MillisecondsToInterval(100);
|
||||
- while (deferred) {
|
||||
+ while (deferred && !g_get_shutdown()) {
|
||||
DS_Sleep(delay);
|
||||
slapi_pblock_get(pb, SLAPI_DEFERRED_MEMBEROF, &deferred);
|
||||
}
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@ -0,0 +1,61 @@
|
||||
From a84a6a7d8323316bfa4055729a3604a0fcfebaf9 Mon Sep 17 00:00:00 2001
|
||||
From: Akshay Adhikari <aadhikar@redhat.com>
|
||||
Date: Fri, 16 Jan 2026 19:35:42 +0530
|
||||
Subject: [PATCH] Issue 7169 - Fix automember_plugin CI test failures (#7181)
|
||||
|
||||
Description: Issue 7053 removed member cleanup from MemberOf plugin,
|
||||
transferring it to Referential Integrity plugin. Enable this plugin
|
||||
in automember tests and clean up groups before rebuild task tests.
|
||||
|
||||
Fixes: #7169
|
||||
|
||||
Reviewed by: @progier389
|
||||
---
|
||||
.../tests/suites/automember_plugin/basic_test.py | 16 ++++++++++++++--
|
||||
1 file changed, 14 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/automember_plugin/basic_test.py b/dirsrvtests/tests/suites/automember_plugin/basic_test.py
|
||||
index 6f2cf3326..f3629c811 100644
|
||||
--- a/dirsrvtests/tests/suites/automember_plugin/basic_test.py
|
||||
+++ b/dirsrvtests/tests/suites/automember_plugin/basic_test.py
|
||||
@@ -19,7 +19,8 @@ from lib389.idm.organizationalunit import OrganizationalUnits
|
||||
from lib389.idm.domain import Domain
|
||||
from lib389.idm.posixgroup import PosixGroups
|
||||
from lib389.plugins import AutoMembershipPlugin, AutoMembershipDefinitions, \
|
||||
- MemberOfPlugin, AutoMembershipRegexRules, AutoMembershipDefinition, RetroChangelogPlugin
|
||||
+ MemberOfPlugin, AutoMembershipRegexRules, AutoMembershipDefinition, RetroChangelogPlugin, \
|
||||
+ ReferentialIntegrityPlugin
|
||||
from lib389.backend import Backends
|
||||
from lib389.config import Config
|
||||
from lib389._constants import DEFAULT_SUFFIX
|
||||
@@ -196,6 +197,7 @@ def _create_all_entries(topo):
|
||||
auto = AutoMembershipPlugin(topo.ms["supplier1"])
|
||||
auto.add("nsslapd-pluginConfigArea", "cn=autoMembersPlugin,{}".format(BASE_REPL))
|
||||
MemberOfPlugin(topo.ms["supplier1"]).enable()
|
||||
+ ReferentialIntegrityPlugin(topo.ms["supplier1"]).enable()
|
||||
automembers_definitions = AutoMembershipDefinitions(topo.ms["supplier1"])
|
||||
automembers_definitions.create(properties={
|
||||
'cn': 'userGroups',
|
||||
@@ -950,8 +952,18 @@ def _startuptask(topo):
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def _fixture_for_build_task(request, topo):
|
||||
+ supplier = topo.ms['supplier1']
|
||||
+ managers_grp = "cn=Managers,ou=userGroups,{}".format(BASE_SUFF)
|
||||
+ contract_grp = "cn=Contractors,ou=userGroups,{}".format(BASE_SUFF)
|
||||
+
|
||||
+ for grp in (managers_grp, contract_grp):
|
||||
+ group = Group(supplier, grp)
|
||||
+ try:
|
||||
+ group.remove_all('member')
|
||||
+ except ldap.NO_SUCH_ATTRIBUTE:
|
||||
+ pass
|
||||
+
|
||||
def finof():
|
||||
- supplier = topo.ms['supplier1']
|
||||
auto_mem_scope = "ou=TaskEmployees,{}".format(BASE_SUFF)
|
||||
for user in nsAdminGroups(supplier, auto_mem_scope, rdn=None).list():
|
||||
user.delete()
|
||||
--
|
||||
2.52.0
|
||||
|
||||
115
0009-Issue-6758-Use-OUIA-selectors-for-WebUI-plugin-tests.patch
Normal file
115
0009-Issue-6758-Use-OUIA-selectors-for-WebUI-plugin-tests.patch
Normal file
@ -0,0 +1,115 @@
|
||||
From 5b32479abcd68f8b37d2fb207c502113a5b4b16c Mon Sep 17 00:00:00 2001
|
||||
From: Akshay Adhikari <aadhikar@redhat.com>
|
||||
Date: Mon, 19 Jan 2026 19:45:29 +0530
|
||||
Subject: [PATCH] Issue 6758 - Use OUIA selectors for WebUI plugin tests
|
||||
(#7182)
|
||||
|
||||
Description:
|
||||
Add ouiaId to plugin NavItems and update tests to use OUIA selectors
|
||||
instead of text matching.
|
||||
|
||||
Relates: #6758
|
||||
|
||||
Reviewed by: @droideck
|
||||
---
|
||||
.../suites/webui/plugins/plugins_test.py | 28 +++++++++----------
|
||||
src/cockpit/389-console/src/plugins.jsx | 2 +-
|
||||
2 files changed, 15 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/webui/plugins/plugins_test.py b/dirsrvtests/tests/suites/webui/plugins/plugins_test.py
|
||||
index e4bd7f039..a849bfb91 100644
|
||||
--- a/dirsrvtests/tests/suites/webui/plugins/plugins_test.py
|
||||
+++ b/dirsrvtests/tests/suites/webui/plugins/plugins_test.py
|
||||
@@ -168,8 +168,8 @@ def test_linked_attributes_plugin_visibility(topology_st, page, browser_name):
|
||||
|
||||
log.info('Click on Plugins tab, click on Linked Attributes plugin and check if element is loaded.')
|
||||
frame.get_by_role('tab', name='Plugins', exact=True).click()
|
||||
- frame.get_by_text('Linked Attributes').wait_for()
|
||||
- frame.get_by_text('Linked Attributes').click()
|
||||
+ frame.locator('[data-ouia-component-id="linkedAttributes"]').wait_for()
|
||||
+ frame.locator('[data-ouia-component-id="linkedAttributes"]').click()
|
||||
frame.get_by_role('button', name='Add Config').wait_for()
|
||||
assert frame.get_by_role('button', name='Add Config').is_visible()
|
||||
|
||||
@@ -254,8 +254,8 @@ def test_ldap_pass_through_auth_plugin_visibility(topology_st, page, browser_nam
|
||||
|
||||
log.info('Click on Plugins tab, click on LDAP Pass Through Auth plugin and check if element is loaded.')
|
||||
frame.get_by_role('tab', name='Plugins', exact=True).click()
|
||||
- frame.get_by_text('LDAP Pass Through Auth').wait_for()
|
||||
- frame.get_by_text('LDAP Pass Through Auth').click()
|
||||
+ frame.locator('[data-ouia-component-id="passthroughAuthentication"]').wait_for()
|
||||
+ frame.locator('[data-ouia-component-id="passthroughAuthentication"]').click()
|
||||
frame.get_by_role('button', name='Add URL').wait_for()
|
||||
assert frame.get_by_role('button', name='Add URL').is_visible()
|
||||
|
||||
@@ -280,8 +280,8 @@ def test_pam_pass_through_auth_plugin_visibility(topology_st, page, browser_name
|
||||
|
||||
log.info('Click on Plugins tab, click on PAM Pass Through Auth plugin and check if element is loaded.')
|
||||
frame.get_by_role('tab', name='Plugins', exact=True).click()
|
||||
- frame.get_by_text('PAM Pass Through Auth').wait_for()
|
||||
- frame.get_by_text('PAM Pass Through Auth').click()
|
||||
+ frame.locator('[data-ouia-component-id="pamPassthroughAuthentication"]').wait_for()
|
||||
+ frame.locator('[data-ouia-component-id="pamPassthroughAuthentication"]').click()
|
||||
frame.get_by_role('button', name='Add Config').wait_for()
|
||||
assert frame.get_by_role('button', name='Add Config').is_visible()
|
||||
|
||||
@@ -306,8 +306,8 @@ def test_posix_winsync_plugin_visibility(topology_st, page, browser_name):
|
||||
|
||||
log.info('Click on Plugins tab, click on Posix Winsync plugin and check if element is loaded.')
|
||||
frame.get_by_role('tab', name='Plugins', exact=True).click()
|
||||
- frame.get_by_text('Posix Winsync').wait_for()
|
||||
- frame.get_by_text('Posix Winsync').click()
|
||||
+ frame.locator('[data-ouia-component-id="winsync"]').wait_for()
|
||||
+ frame.locator('[data-ouia-component-id="winsync"]').click()
|
||||
frame.locator('#posixWinsyncCreateMemberOfTask').wait_for()
|
||||
assert frame.locator('#posixWinsyncCreateMemberOfTask').is_visible()
|
||||
|
||||
@@ -332,8 +332,8 @@ def test_referential_integrity_plugin_visibility(topology_st, page, browser_name
|
||||
|
||||
log.info('Click on Plugins tab, click on Referential Integrity plugin and check if element is loaded.')
|
||||
frame.get_by_role('tab', name='Plugins', exact=True).click()
|
||||
- frame.get_by_text('Referential Integrity').wait_for()
|
||||
- frame.get_by_text('Referential Integrity').click()
|
||||
+ frame.locator('[data-ouia-component-id="referentialIntegrity"]').wait_for()
|
||||
+ frame.locator('[data-ouia-component-id="referentialIntegrity"]').click()
|
||||
frame.locator('#entryScope').wait_for()
|
||||
assert frame.locator('#entryScope').is_visible()
|
||||
|
||||
@@ -358,8 +358,8 @@ def test_retro_changelog_plugin_visibility(topology_st, page, browser_name):
|
||||
|
||||
log.info('Click on Plugins tab, click on Retro Changelog plugin and check if element is loaded.')
|
||||
frame.get_by_role('tab', name='Plugins', exact=True).click()
|
||||
- frame.get_by_text('Retro Changelog').wait_for()
|
||||
- frame.get_by_text('Retro Changelog').click()
|
||||
+ frame.locator('[data-ouia-component-id="retroChangelog"]').wait_for()
|
||||
+ frame.locator('[data-ouia-component-id="retroChangelog"]').click()
|
||||
frame.locator('#isReplicated').wait_for()
|
||||
assert frame.locator('#isReplicated').is_visible()
|
||||
|
||||
@@ -384,8 +384,8 @@ def test_rootdn_access_control_plugin_visibility(topology_st, page, browser_name
|
||||
|
||||
log.info('Click on Plugins tab, click on RootDN Access Control plugin and check if element is loaded.')
|
||||
frame.get_by_role('tab', name='Plugins', exact=True).click()
|
||||
- frame.get_by_text('RootDN Access Control').wait_for()
|
||||
- frame.get_by_text('RootDN Access Control').click()
|
||||
+ frame.locator('[data-ouia-component-id="rootDnaAccessControl"]').wait_for()
|
||||
+ frame.locator('[data-ouia-component-id="rootDnaAccessControl"]').click()
|
||||
frame.locator('#allowMon').wait_for()
|
||||
assert frame.locator('#allowMon').is_visible()
|
||||
|
||||
diff --git a/src/cockpit/389-console/src/plugins.jsx b/src/cockpit/389-console/src/plugins.jsx
|
||||
index 4124a77ef..e24255c76 100644
|
||||
--- a/src/cockpit/389-console/src/plugins.jsx
|
||||
+++ b/src/cockpit/389-console/src/plugins.jsx
|
||||
@@ -680,7 +680,7 @@ export class Plugins extends React.Component {
|
||||
<Nav key={this.state.pluginTableKey} theme="light" onSelect={(event, item) => this.handleSelect(event, item)}>
|
||||
<NavList>
|
||||
{Object.entries(selectPlugins).map(([id, item]) => (
|
||||
- <NavItem key={item.name} itemId={item.name} isActive={this.state.activePlugin === item.name}>
|
||||
+ <NavItem key={item.name} itemId={item.name} ouiaId={id} isActive={this.state.activePlugin === item.name}>
|
||||
{item.icon}
|
||||
</NavItem>
|
||||
))}
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
From 9bd93dc618c261d52222e713c56500abbce4113e Mon Sep 17 00:00:00 2001
|
||||
From: progier389 <progier@redhat.com>
|
||||
Date: Mon, 19 Jan 2026 17:24:40 +0100
|
||||
Subject: [PATCH] Issue 7196 - DynamicCertificates returns empty DER (#7197)
|
||||
|
||||
Fixing a mistake done while fixing memory leaks.
|
||||
Value was freed before being added in the entry rather than after ...
|
||||
|
||||
Issue: #7196
|
||||
|
||||
Reviewed by: @jchapma (thanks!)
|
||||
---
|
||||
ldap/servers/slapd/dyncerts.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/ldap/servers/slapd/dyncerts.c b/ldap/servers/slapd/dyncerts.c
|
||||
index 50b92aa5f..efeaa6eb6 100644
|
||||
--- a/ldap/servers/slapd/dyncerts.c
|
||||
+++ b/ldap/servers/slapd/dyncerts.c
|
||||
@@ -786,8 +786,8 @@ dyncerts_cert2entry(CERTCertificate *cert)
|
||||
COND_STR(e, DYCATTR_TYPE, "OBJECT SIGNING CA", cert->nsCertType & NS_CERT_TYPE_OBJECT_SIGNING_CA);
|
||||
slapi_entry_add_string(e, DYCATTR_TOKEN, PK11_GetTokenName(cert->slot));
|
||||
secitemv(&cert->derCert, &tmpv);
|
||||
- value_done(&tmpv);
|
||||
slapi_entry_add_value(e, DYCATTR_CERTDER, &tmpv);
|
||||
+ value_done(&tmpv);
|
||||
tmpstr = secitem2hex(&cert->serialNumber);
|
||||
slapi_entry_add_string(e, DYCATTR_SN, tmpstr);
|
||||
slapi_ch_free_string(&tmpstr);
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
From 05ce84ae76e0e71381bcc7b8491a74e7edcd888f Mon Sep 17 00:00:00 2001
|
||||
From c6f458b421598b18a545582441472b910b5ba56e Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
Date: Tue, 20 Jan 2026 09:52:47 +0100
|
||||
Subject: [PATCH 2/2] Issue 7189 - DSBLE0007 generates incorrect remediation
|
||||
Subject: [PATCH] Issue 7189 - DSBLE0007 generates incorrect remediation
|
||||
commands for scan limits
|
||||
|
||||
Bug Description:
|
||||
@ -32,10 +32,10 @@ Reviewed by: @progier389, @droideck (Thanks!)
|
||||
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 1700ba207..f25de4214 100644
|
||||
index a977b71d1..486fad44b 100644
|
||||
--- a/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py
|
||||
+++ b/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py
|
||||
@@ -406,6 +406,132 @@ def test_retrocl_plugin_missing_matching_rule(topology_st, retrocl_plugin_enable
|
||||
@@ -408,6 +408,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)
|
||||
|
||||
|
||||
@ -169,10 +169,10 @@ index 1700ba207..f25de4214 100644
|
||||
"""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 14b64d1d3..3cea0df36 100644
|
||||
index fba95987b..db464b43a 100644
|
||||
--- a/src/lib389/lib389/backend.py
|
||||
+++ b/src/lib389/lib389/backend.py
|
||||
@@ -602,7 +602,7 @@ class Backend(DSLdapObject):
|
||||
@@ -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'):
|
||||
@ -181,7 +181,7 @@ index 14b64d1d3..3cea0df36 100644
|
||||
remediation_commands.append(cmd)
|
||||
reindex_attrs.add(attr_name) # New index needs reindexing
|
||||
else:
|
||||
@@ -624,28 +624,31 @@ class Backend(DSLdapObject):
|
||||
@@ -700,28 +700,31 @@ class Backend(DSLdapObject):
|
||||
remediation_commands.append(cmd)
|
||||
reindex_attrs.add(attr_name)
|
||||
|
||||
504
0012-Issue-7170-Support-of-PQC-keys-7188.patch
Normal file
504
0012-Issue-7170-Support-of-PQC-keys-7188.patch
Normal file
@ -0,0 +1,504 @@
|
||||
From 6ce33b1bedd2cd13d7e6544692354715f6e613b8 Mon Sep 17 00:00:00 2001
|
||||
From: progier389 <progier@redhat.com>
|
||||
Date: Tue, 20 Jan 2026 19:41:05 +0100
|
||||
Subject: [PATCH] Issue 7170 - Support of PQC keys (#7188)
|
||||
|
||||
Support of Post Quantum Cryptography Keys in certificates:
|
||||
Added support of a new key type: ML_DSA
|
||||
Enable the following policies (that are not enabled by defaut): ML-DSA-44, ML-DSA-65- ML-DSA-87
|
||||
Replaced deprecated function SSL_ConfigSecureServer by SSL_ConfigServerCert
|
||||
Added test case for ML-DSA certificate. That test case rely of openssl command because python cryptography module does not yet support ML-DSA keys
|
||||
|
||||
Issue: #7170
|
||||
|
||||
Reviewed by: @tbordaz, @droideck and @vashirov (Thanks!)
|
||||
---
|
||||
dirsrvtests/tests/suites/tls/mldsa_test.py | 322 +++++++++++++++++++++
|
||||
ldap/servers/slapd/ssl.c | 95 +++++-
|
||||
2 files changed, 407 insertions(+), 10 deletions(-)
|
||||
create mode 100644 dirsrvtests/tests/suites/tls/mldsa_test.py
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/tls/mldsa_test.py b/dirsrvtests/tests/suites/tls/mldsa_test.py
|
||||
new file mode 100644
|
||||
index 000000000..2c815088b
|
||||
--- /dev/null
|
||||
+++ b/dirsrvtests/tests/suites/tls/mldsa_test.py
|
||||
@@ -0,0 +1,322 @@
|
||||
+# --- 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 logging
|
||||
+import pytest
|
||||
+import os
|
||||
+import sys
|
||||
+import itertools
|
||||
+import rpm
|
||||
+import socket
|
||||
+import subprocess
|
||||
+from lib389.utils import ds_is_older
|
||||
+from lib389._constants import DN_DM, PW_DM, DEFAULT_SUFFIX
|
||||
+from lib389.config import Encryption, CertmapLegacy
|
||||
+from lib389.idm.user import UserAccount
|
||||
+from lib389.topologies import topology_st as topo
|
||||
+from tempfile import TemporaryDirectory
|
||||
+
|
||||
+pytestmark = pytest.mark.tier1
|
||||
+
|
||||
+DEBUGGING = os.getenv("DEBUGGING", default=False)
|
||||
+if DEBUGGING:
|
||||
+ logging.getLogger(__name__).setLevel(logging.DEBUG)
|
||||
+else:
|
||||
+ logging.getLogger(__name__).setLevel(logging.INFO)
|
||||
+log = logging.getLogger(__name__)
|
||||
+
|
||||
+
|
||||
+def rpm_is_older(pkg, version):
|
||||
+ ts = rpm.TransactionSet()
|
||||
+ mi = ts.dbMatch('name', pkg)
|
||||
+ for h in mi:
|
||||
+ print(f"{pkg} {h['version']} {version}")
|
||||
+ for n1,n2 in itertools.zip_longest(h['version'].split('.'), version.split('.'), fillvalue=""):
|
||||
+ try:
|
||||
+ if int(n1) < int(n2):
|
||||
+ return True
|
||||
+ except ValueError:
|
||||
+ if n1 < n2:
|
||||
+ return True
|
||||
+ return False
|
||||
+
|
||||
+
|
||||
+script_content="""
|
||||
+#!/bin/bash
|
||||
+set -e # Exit if a command fails
|
||||
+set -x # Log the commands
|
||||
+
|
||||
+cd {dir}
|
||||
+inst={instname}
|
||||
+url={url}
|
||||
+rootdn="{rootdn}"
|
||||
+rootpw="{rootpw}"
|
||||
+
|
||||
+################################
|
||||
+###### GENERATE CA CERT ########
|
||||
+################################
|
||||
+
|
||||
+echo "
|
||||
+[ req ]
|
||||
+distinguished_name = req_distinguished_name
|
||||
+policy = policy_match
|
||||
+x509_extensions = v3_ca
|
||||
+
|
||||
+# For the CA policy
|
||||
+[ policy_match ]
|
||||
+countryName = optional
|
||||
+stateOrProvinceName = optional
|
||||
+organizationName = optional
|
||||
+organizationalUnitName = optional
|
||||
+commonName = supplied
|
||||
+emailAddress = optional
|
||||
+
|
||||
+[ req_distinguished_name ]
|
||||
+countryName = Country Name (2 letter code)
|
||||
+countryName_default = FR
|
||||
+countryName_min = 2
|
||||
+countryName_max = 2
|
||||
+
|
||||
+stateOrProvinceName = State or Province Name (full name)
|
||||
+stateOrProvinceName_default = test
|
||||
+
|
||||
+localityName = Locality Name (eg, city)
|
||||
+
|
||||
+0.organizationName = Organization Name (eg, company)
|
||||
+0.organizationName_default = test-ML-DSA-CA
|
||||
+
|
||||
+organizationalUnitName = Organizational Unit Name (eg, section)
|
||||
+#organizationalUnitName_default =
|
||||
+
|
||||
+commonName = Common Name (e.g. server FQDN or YOUR name)
|
||||
+commonName_max = 64
|
||||
+
|
||||
+
|
||||
+[ v3_ca ]
|
||||
+subjectKeyIdentifier = hash
|
||||
+authorityKeyIdentifier = keyid:always,issuer
|
||||
+basicConstraints = critical,CA:true
|
||||
+#nsComment = "OpenSSL Generated Certificate"
|
||||
+keyUsage=critical, keyCertSign
|
||||
+" >ca.conf
|
||||
+
|
||||
+
|
||||
+openssl genpkey -algorithm ML-DSA-87 -out ca.key
|
||||
+openssl req -x509 -new -sha256 -key ca.key -nodes -days 3650 -config ca.conf -subj "/CN=`hostname`/O=test-ML-DSA-CA/C=FR" -out ca.pem -keyout ca.key
|
||||
+openssl x509 -outform der -in ca.pem -out ca.crt
|
||||
+
|
||||
+openssl x509 -text -in ca.pem
|
||||
+
|
||||
+####################################
|
||||
+###### GENERATE SERVER CERT ########
|
||||
+####################################
|
||||
+
|
||||
+echo "
|
||||
+[ req ]
|
||||
+distinguished_name = req_distinguished_name
|
||||
+policy = policy_match
|
||||
+x509_extensions = v3_cert
|
||||
+
|
||||
+# For the cert policy
|
||||
+[ policy_match ]
|
||||
+countryName = optional
|
||||
+stateOrProvinceName = optional
|
||||
+organizationName = optional
|
||||
+organizationalUnitName = optional
|
||||
+commonName = supplied
|
||||
+emailAddress = optional
|
||||
+
|
||||
+[ req_distinguished_name ]
|
||||
+countryName = Country Name (2 letter code)
|
||||
+countryName_default = FR
|
||||
+countryName_min = 2
|
||||
+countryName_max = 2
|
||||
+
|
||||
+stateOrProvinceName = State or Province Name (full name)
|
||||
+
|
||||
+localityName = Locality Name (eg, city)
|
||||
+
|
||||
+0.organizationName = Organization Name (eg, company)
|
||||
+0.organizationName_default = test-ML-DSA
|
||||
+
|
||||
+organizationalUnitName = Organizational Unit Name (eg, section)
|
||||
+#organizationalUnitName_default =
|
||||
+
|
||||
+commonName = Common Name (e.g. server FQDN or YOUR name)
|
||||
+commonName_max = 64
|
||||
+
|
||||
+
|
||||
+[ v3_cert ]
|
||||
+basicConstraints = critical,CA:false
|
||||
+subjectAltName=DNS:`hostname`
|
||||
+keyUsage=digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
|
||||
+#nsComment = "OpenSSL Generated Certificate"
|
||||
+extendedKeyUsage=clientAuth, serverAuth
|
||||
+nsCertType=client, server
|
||||
+" >cert.conf
|
||||
+
|
||||
+openssl genpkey -algorithm ML-DSA-65 -out cert.key
|
||||
+openssl req -new -sha256 -key cert.key -nodes -config cert.conf -subj "/CN=`hostname`/O=test-ML-DSA/C=FR" -out cert.csr
|
||||
+openssl x509 -req -sha256 -days 3650 -extensions v3_cert -extfile cert.conf -in cert.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out cert.pem
|
||||
+openssl pkcs12 -export -inkey cert.key -in cert.pem -name mldsacert -out cert.p12 -passout pass:secret12
|
||||
+
|
||||
+openssl x509 -text -in cert.pem
|
||||
+
|
||||
+
|
||||
+
|
||||
+####################################
|
||||
+###### GENERATE CLIENT CERT ########
|
||||
+####################################
|
||||
+
|
||||
+echo "
|
||||
+[ req ]
|
||||
+distinguished_name = req_distinguished_name
|
||||
+policy = policy_match
|
||||
+x509_extensions = v3_cert
|
||||
+
|
||||
+# For the cert policy
|
||||
+[ policy_match ]
|
||||
+countryName = optional
|
||||
+stateOrProvinceName = optional
|
||||
+organizationName = optional
|
||||
+organizationalUnitName = optional
|
||||
+commonName = supplied
|
||||
+emailAddress = optional
|
||||
+
|
||||
+[ req_distinguished_name ]
|
||||
+countryName = Country Name (2 letter code)
|
||||
+countryName_default = FR
|
||||
+countryName_min = 2
|
||||
+countryName_max = 2
|
||||
+
|
||||
+stateOrProvinceName = State or Province Name (full name)
|
||||
+
|
||||
+localityName = Locality Name (eg, city)
|
||||
+
|
||||
+0.organizationName = Organization Name (eg, company)
|
||||
+0.organizationName_default = test-ML-DSA
|
||||
+
|
||||
+organizationalUnitName = Organizational Unit Name (eg, section)
|
||||
+#organizationalUnitName_default =
|
||||
+
|
||||
+commonName = Common Name (e.g. server FQDN or YOUR name)
|
||||
+commonName_max = 64
|
||||
+
|
||||
+
|
||||
+[ v3_cert ]
|
||||
+basicConstraints = critical,CA:false
|
||||
+subjectAltName=DNS:`hostname`
|
||||
+keyUsage=digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
|
||||
+#nsComment = "OpenSSL Generated Certificate"
|
||||
+extendedKeyUsage=clientAuth
|
||||
+nsCertType=client, server
|
||||
+" >client.conf
|
||||
+
|
||||
+openssl genpkey -algorithm ML-DSA-65 -out client.key
|
||||
+openssl req -new -sha256 -key client.key -nodes -config client.conf -subj "/CN=`hostname`/O=client-test-ML-DSA/C=FR" -out client.csr
|
||||
+openssl x509 -req -sha256 -days 3650 -extensions v3_cert -extfile client.conf -in client.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out client.pem
|
||||
+openssl pkcs12 -export -inkey client.key -in client.pem -name mldsacert2 -out client.p12 -passout pass:secret12
|
||||
+
|
||||
+openssl x509 -text -in client.pem
|
||||
+
|
||||
+
|
||||
+#############################
|
||||
+###### INSTALL CERTS ########
|
||||
+#############################
|
||||
+
|
||||
+certdbdir=$PREFIX/etc/dirsrv/slapd-$inst
|
||||
+rm -f $certdbdir/cert9.db $certdbdir/key4.db
|
||||
+certutil -N -d $certdbdir -f $certdbdir/pwdfile.txt
|
||||
+
|
||||
+certutil -A -n Self-Signed-CA -t CT,, -f $certdbdir/pwdfile.txt -d $certdbdir -a -i ca.pem
|
||||
+certutil -A -n Client-Cert -t u,, -f $certdbdir/pwdfile.txt -d $certdbdir -a -i client.pem
|
||||
+
|
||||
+dsctl $inst tls import-server-key-cert cert.pem cert.key
|
||||
+
|
||||
+dsctl $inst restart
|
||||
+
|
||||
+
|
||||
+#########################
|
||||
+###### TEST CERT ########
|
||||
+#########################
|
||||
+export LDAPTLS_CACERT=$PWD/ca.pem
|
||||
+export LDAPTLS_CERT=$PWD/client.pem
|
||||
+export LDAPTLS_KEY=$PWD/client.key
|
||||
+
|
||||
+ldapsearch -x -H $url -D "$rootdn" -w "$rootpw" -b "" -s base
|
||||
+ldapsearch -Y external -H $url -b "" -s base
|
||||
+"""
|
||||
+
|
||||
+@pytest.mark.skipif(rpm_is_older("openssl", "3.5"), reason="OpenSSL too old to support PQC")
|
||||
+@pytest.mark.skipif(rpm_is_older("nss", "3.119.1"), reason="NSS too old to support PQC")
|
||||
+def test_mldsa(topo):
|
||||
+ """Test using ML-DSA Certificate - (PQC)
|
||||
+
|
||||
+ :id: 87fb19ef-672d-4fa7-934d-dfb4397f2312
|
||||
+ :setup: Standalone Instance
|
||||
+ :steps:
|
||||
+ 1. Configure the certmap
|
||||
+ 2. Create user mapped with theclient certificate
|
||||
+ 3. Generate the test script
|
||||
+ 4. Run the test script
|
||||
+ 5. Check that ldapsearch returned the namingcontext
|
||||
+ :expectedresults:
|
||||
+ 1. No error
|
||||
+ 2. No error
|
||||
+ 3. No error
|
||||
+ 4. No error and exit code should be 0
|
||||
+ 5. namingcontext should be in the script output
|
||||
+ """
|
||||
+
|
||||
+ inst = topo.standalone
|
||||
+ inst.enable_tls()
|
||||
+
|
||||
+ cm = CertmapLegacy(inst)
|
||||
+ certmaps = cm.list()
|
||||
+ certmaps['default'].update({'DNComps': None, 'CmapLdapAttr': 'description'})
|
||||
+ cm.set(certmaps)
|
||||
+
|
||||
+ cert_dn = f'C=FR,O=client-test-ML-DSA,CN={socket.gethostname()}'
|
||||
+ dn = f'uid=test_user,ou=people,{DEFAULT_SUFFIX}'
|
||||
+ UserAccount(inst, dn=dn).create( properties= {
|
||||
+ 'uid': 'test_user',
|
||||
+ 'cn': 'Test user',
|
||||
+ 'sn': 'Test user',
|
||||
+ 'uidNumber': '99998',
|
||||
+ 'gidNumber': '99998',
|
||||
+ 'homeDirectory': '/var/empty',
|
||||
+ 'loginShell': '/bin/false',
|
||||
+ 'description': cert_dn })
|
||||
+
|
||||
+ tmpdir_kwargs = {}
|
||||
+ if sys.version_info >= (3, 12):
|
||||
+ tmpdir_kwargs['delete'] = not DEBUGGING
|
||||
+ with TemporaryDirectory(**tmpdir_kwargs) as dir:
|
||||
+ scriptname = f"{dir}/doit"
|
||||
+ d = {
|
||||
+ 'dir': dir,
|
||||
+ 'instname': inst.serverid,
|
||||
+ 'url': f"ldaps://localhost:{inst.sslport}",
|
||||
+ 'rootdn': DN_DM,
|
||||
+ 'rootpw': PW_DM,
|
||||
+ }
|
||||
+ with open(scriptname, 'w') as f:
|
||||
+ f.write(script_content.format(**d))
|
||||
+ res = subprocess.run(('/bin/bash', scriptname), stdout=subprocess.PIPE, stderr=subprocess.STDOUT, encoding='utf-8')
|
||||
+ assert res
|
||||
+ log.info(res.stdout)
|
||||
+ res.check_returncode()
|
||||
+ # If ldapsearch is successful then defaultnamingcontext should be in res.stdout
|
||||
+ assert "defaultnamingcontext" in res.stdout
|
||||
+
|
||||
+
|
||||
+if __name__ == '__main__':
|
||||
+ # Run isolated
|
||||
+ # -s for DEBUG mode
|
||||
+ CURRENT_FILE = os.path.realpath(__file__)
|
||||
+ pytest.main(["-s", CURRENT_FILE])
|
||||
diff --git a/ldap/servers/slapd/ssl.c b/ldap/servers/slapd/ssl.c
|
||||
index a9c17ef42..053db5424 100644
|
||||
--- a/ldap/servers/slapd/ssl.c
|
||||
+++ b/ldap/servers/slapd/ssl.c
|
||||
@@ -169,6 +169,20 @@ PRBool enableTLS1 = PR_TRUE;
|
||||
/* CA cert pem file */
|
||||
static char *CACertPemFile = NULL;
|
||||
|
||||
+static const struct {
|
||||
+ KeyType kt;
|
||||
+ const char *shortname;
|
||||
+ const char *fullname;
|
||||
+} supported_key_types[] = {
|
||||
+ { rsaKey, "RSA", "Rivest–Shamir–Adleman" },
|
||||
+ { ecKey, "EC", "Elliptic Curve" },
|
||||
+#ifdef MAX_ML_DSA_PRIVATE_KEY_LEN
|
||||
+ { mldsaKey, "ML-DSA", "Module-Lattice-Based Digital Signature Algorithm (post-quantum)" },
|
||||
+#endif
|
||||
+ { 0 }
|
||||
+};
|
||||
+
|
||||
+
|
||||
/* helper functions for openldap update. */
|
||||
static int slapd_extract_cert(Slapi_Entry *entry, int isCA);
|
||||
static int slapd_extract_key(Slapi_Entry *entry, char *token, PK11SlotInfo *slot);
|
||||
@@ -718,9 +732,31 @@ SSLPLCY_Install(void)
|
||||
{
|
||||
|
||||
SECStatus s = 0;
|
||||
+#ifdef MAX_ML_DSA_PRIVATE_KEY_LEN
|
||||
+ int flags = NSS_USE_ALG_IN_SIGNATURE | NSS_USE_ALG_IN_SSL;
|
||||
+ static const SECOidTag oids[] = {
|
||||
+ SEC_OID_ML_DSA_44,
|
||||
+ SEC_OID_ML_DSA_65,
|
||||
+ SEC_OID_ML_DSA_87,
|
||||
+ };
|
||||
+#endif
|
||||
|
||||
s = NSS_SetDomesticPolicy();
|
||||
|
||||
+#ifdef MAX_ML_DSA_PRIVATE_KEY_LEN
|
||||
+ /* Should rely on the crypto module policy in FIPS mode */
|
||||
+ if (!slapd_pk11_isFIPS()) {
|
||||
+ /* Set explicitly PQC algorithm policy if it is not set by default */
|
||||
+ for (size_t i=0; s == SECSuccess && i < PR_ARRAY_SIZE(oids); i++) {
|
||||
+ int oflags = 0;
|
||||
+ (void) NSS_GetAlgorithmPolicy(oids[i], &oflags);
|
||||
+ if ((oflags & flags) != flags) {
|
||||
+ s = NSS_SetAlgorithmPolicy(oids[i], flags, 0);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
return s ? PR_FAILURE : PR_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1640,7 +1676,7 @@ slapd_ssl_init2(PRFileDesc **fd, int startTLS)
|
||||
/*
|
||||
* Now, get the complete list of cipher families. Each family
|
||||
* has a token name and personality name which we'll use to find
|
||||
- * appropriate keys and certs, and call SSL_ConfigSecureServer
|
||||
+ * appropriate keys and certs, and call SSL_ConfigServerCert
|
||||
* with.
|
||||
*/
|
||||
|
||||
@@ -1759,8 +1795,6 @@ slapd_ssl_init2(PRFileDesc **fd, int startTLS)
|
||||
}
|
||||
|
||||
if (SECSuccess == rv) {
|
||||
- SSLKEAType certKEA;
|
||||
-
|
||||
/* If we want weak dh params, flag it on the socket now! */
|
||||
rv = SSL_OptionSet(*fd, SSL_ENABLE_SERVER_DHE, PR_TRUE);
|
||||
if (rv != SECSuccess) {
|
||||
@@ -1774,11 +1808,10 @@ slapd_ssl_init2(PRFileDesc **fd, int startTLS)
|
||||
}
|
||||
}
|
||||
|
||||
- certKEA = NSS_FindCertKEAType(cert);
|
||||
- rv = SSL_ConfigSecureServer(*fd, cert, key, certKEA);
|
||||
+ rv = SSL_ConfigServerCert(*fd, cert, key, NULL, 0);
|
||||
if (SECSuccess != rv) {
|
||||
errorCode = PR_GetError();
|
||||
- slapd_SSL_warn("ConfigSecureServer: "
|
||||
+ slapd_SSL_warn("SSL_ConfigServerCert: "
|
||||
"Server key/certificate is "
|
||||
"bad for cert %s of family %s (" SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
|
||||
cert_name, *family, errorCode,
|
||||
@@ -2663,6 +2696,38 @@ bail:
|
||||
return rv;
|
||||
}
|
||||
|
||||
+/* Helper for get_supported_key_type */
|
||||
+static char *
|
||||
+buf_add_str(char *buf, char *bufend, const char *str)
|
||||
+{
|
||||
+ /* bufend is sizeof(buf)-4 (to avoid overflow with ...) */
|
||||
+ char *ret = buf+strlen(str);
|
||||
+ if (ret > bufend) {
|
||||
+ ret = bufend;
|
||||
+ strcpy(buf, "...");
|
||||
+ } else {
|
||||
+ strcpy(buf, str);
|
||||
+ }
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+get_supported_key_type_names(char *buf, size_t bufsize)
|
||||
+{
|
||||
+ char *bufend = buf + bufsize - 4;
|
||||
+ for (size_t i=0; supported_key_types[i].kt; i++) {
|
||||
+ if (i>0) {
|
||||
+ if (supported_key_types[i+1].kt == 0) {
|
||||
+ /* Last supported key type */
|
||||
+ buf = buf_add_str(buf, bufend, " or ");
|
||||
+ } else {
|
||||
+ buf = buf_add_str(buf, bufend, ", ");
|
||||
+ }
|
||||
+ }
|
||||
+ buf = buf_add_str(buf, bufend, supported_key_types[i].shortname);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Borrowed from keyutil.c (crypto-util)
|
||||
*
|
||||
@@ -2723,10 +2788,20 @@ extractKeysAndSubject(
|
||||
}
|
||||
|
||||
keytype = (*privkey)->keyType;
|
||||
- if (keytype != rsaKey && keytype != ecKey) {
|
||||
- slapi_log_err(SLAPI_LOG_ERR, "extractKeysAndSubject",
|
||||
- "Unexpected key algorythm in certificate: %s. Only rsa and ec keys are supported.\n", nickname);
|
||||
- goto bail;
|
||||
+ for (size_t i=0; ;i++) {
|
||||
+ KeyType kt = supported_key_types[i].kt;
|
||||
+ if (kt == keytype && keytype != 0) {
|
||||
+ /* Stop looping if the key type is supported */
|
||||
+ break;
|
||||
+ }
|
||||
+ if (kt == 0) {
|
||||
+ /* No supported key type have been found. */
|
||||
+ char sktnames[100] = "";
|
||||
+ get_supported_key_type_names(sktnames, sizeof sktnames);
|
||||
+ slapi_log_err(SLAPI_LOG_ERR, "extractKeysAndSubject",
|
||||
+ "Unexpected key algorithm in certificate: %s. Only %s are supported.\n", nickname, sktnames);
|
||||
+ goto bail;
|
||||
+ }
|
||||
}
|
||||
|
||||
*subject = CERT_AsciiToName(cert->subjectName);
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@ -0,0 +1,56 @@
|
||||
From 4068f68bea77f466f9b3d87c766ea14d2f175b17 Mon Sep 17 00:00:00 2001
|
||||
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
|
||||
Date: Wed, 21 Jan 2026 19:58:46 -0800
|
||||
Subject: [PATCH] Bump lodash from 4.17.21 to 4.17.23 in
|
||||
/src/cockpit/389-console (#7203)
|
||||
|
||||
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.21 to 4.17.23.
|
||||
- [Release notes](https://github.com/lodash/lodash/releases)
|
||||
- [Commits](https://github.com/lodash/lodash/compare/4.17.21...4.17.23)
|
||||
|
||||
---
|
||||
updated-dependencies:
|
||||
- dependency-name: lodash
|
||||
dependency-version: 4.17.23
|
||||
dependency-type: indirect
|
||||
...
|
||||
|
||||
Signed-off-by: dependabot[bot] <support@github.com>
|
||||
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
|
||||
---
|
||||
src/cockpit/389-console/package-lock.json | 12 ++++++------
|
||||
1 file changed, 6 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/src/cockpit/389-console/package-lock.json b/src/cockpit/389-console/package-lock.json
|
||||
index 0aa5bbbb9..23faef62f 100644
|
||||
--- a/src/cockpit/389-console/package-lock.json
|
||||
+++ b/src/cockpit/389-console/package-lock.json
|
||||
@@ -4833,9 +4833,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
- "version": "4.17.21",
|
||||
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
+ "version": "4.17.23",
|
||||
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz",
|
||||
+ "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w=="
|
||||
},
|
||||
"node_modules/lodash.merge": {
|
||||
"version": "4.6.2",
|
||||
@@ -11087,9 +11087,9 @@
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
- "version": "4.17.21",
|
||||
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
+ "version": "4.17.23",
|
||||
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz",
|
||||
+ "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w=="
|
||||
},
|
||||
"lodash.merge": {
|
||||
"version": "4.6.2",
|
||||
--
|
||||
2.52.0
|
||||
|
||||
517
0014-Issue-7198-Web-console-doesn-t-show-sub-suffix-when-.patch
Normal file
517
0014-Issue-7198-Web-console-doesn-t-show-sub-suffix-when-.patch
Normal file
@ -0,0 +1,517 @@
|
||||
From 3ff253af76df07fe0519481795b7ed155fefaa9e Mon Sep 17 00:00:00 2001
|
||||
From: Simon Pichugin <spichugi@redhat.com>
|
||||
Date: Fri, 23 Jan 2026 17:35:45 -0800
|
||||
Subject: [PATCH] Issue 7198 - Web console doesn't show sub-suffix when
|
||||
parent-suffix points to an entry (#7202)
|
||||
|
||||
Description: The web console doesn't show sub-suffixes when the
|
||||
nsslapd-parent-suffix attribute points to an entry rather than a backend
|
||||
suffix.
|
||||
For example, creating a sub-suffix ou=foo,ou=people,dc=example,dc=com
|
||||
with parent-suffix ou=people,dc=example,dc=com (where ou=people is just an
|
||||
entry, not a suffix) would not appear in the web console tree.
|
||||
|
||||
Fix: In backend_build_tree() and get_sub_suffixes(), the code only matched
|
||||
when nsslapd-parent-suffix exactly equaled an existing backend suffix.
|
||||
Now it also checks if the parent-suffix is an entry under the current
|
||||
suffix (ends with ,suffix) and is not itself a backend suffix. This
|
||||
correctly attaches sub-suffixes to their containing suffix when the
|
||||
parent-suffix points to an intermediate entry.
|
||||
|
||||
Fixes: https://github.com/389ds/389-ds-base/issues/7198
|
||||
|
||||
Reviewed by: @progier389 (Thanks!)
|
||||
---
|
||||
.../suites/lib389/subsuffix_tree_test.py | 313 ++++++++++++++++++
|
||||
src/lib389/lib389/backend.py | 47 ++-
|
||||
src/lib389/lib389/cli_conf/backend.py | 34 +-
|
||||
3 files changed, 370 insertions(+), 24 deletions(-)
|
||||
create mode 100644 dirsrvtests/tests/suites/lib389/subsuffix_tree_test.py
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/lib389/subsuffix_tree_test.py b/dirsrvtests/tests/suites/lib389/subsuffix_tree_test.py
|
||||
new file mode 100644
|
||||
index 000000000..fa10ba530
|
||||
--- /dev/null
|
||||
+++ b/dirsrvtests/tests/suites/lib389/subsuffix_tree_test.py
|
||||
@@ -0,0 +1,313 @@
|
||||
+# --- 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 logging
|
||||
+import os
|
||||
+import pytest
|
||||
+from lib389.topologies import topology_st as topo
|
||||
+from lib389.backend import Backends
|
||||
+from lib389.idm.organizationalunit import OrganizationalUnits
|
||||
+from lib389._constants import DEFAULT_SUFFIX
|
||||
+
|
||||
+pytestmark = pytest.mark.tier1
|
||||
+
|
||||
+logging.getLogger(__name__).setLevel(logging.INFO)
|
||||
+log = logging.getLogger(__name__)
|
||||
+
|
||||
+
|
||||
+@pytest.fixture(scope="function")
|
||||
+def setup_subsuffix_with_entry_parent(topo, request):
|
||||
+ """Setup a sub-suffix whose parent-suffix points to an entry, not a suffix."""
|
||||
+ inst = topo.standalone
|
||||
+
|
||||
+ # Create ou=people entry under the root suffix
|
||||
+ log.info("Creating ou=people,dc=example,dc=com entry")
|
||||
+ ous = OrganizationalUnits(inst, DEFAULT_SUFFIX)
|
||||
+ ou_people = ous.get('people')
|
||||
+
|
||||
+ # Create sub-suffix with parent-suffix pointing to the entry
|
||||
+ log.info("Creating sub-suffix ou=foo,ou=people,dc=example,dc=com")
|
||||
+ backends = Backends(inst)
|
||||
+ subsuffix_dn = 'ou=foo,ou=people,dc=example,dc=com'
|
||||
+ parent_suffix_dn = 'ou=people,dc=example,dc=com'
|
||||
+
|
||||
+ foo_backend = backends.create(properties={
|
||||
+ 'cn': 'foo',
|
||||
+ 'nsslapd-suffix': subsuffix_dn,
|
||||
+ 'parent': parent_suffix_dn,
|
||||
+ })
|
||||
+
|
||||
+ # Create the suffix entry
|
||||
+ foo_ous = OrganizationalUnits(inst, parent_suffix_dn)
|
||||
+ foo_ou = foo_ous.create(properties={'ou': 'foo'})
|
||||
+
|
||||
+ def cleanup():
|
||||
+ log.info("Cleaning up test backends and entries")
|
||||
+ try:
|
||||
+ foo_ou.delete()
|
||||
+ except Exception as e:
|
||||
+ log.warning(f"Failed to delete foo_ou: {e}")
|
||||
+ try:
|
||||
+ foo_backend.delete()
|
||||
+ except Exception as e:
|
||||
+ log.warning(f"Failed to delete foo_backend: {e}")
|
||||
+
|
||||
+ request.addfinalizer(cleanup)
|
||||
+
|
||||
+ return {
|
||||
+ 'instance': inst,
|
||||
+ 'backends': backends,
|
||||
+ 'foo_backend': foo_backend,
|
||||
+ 'ou_people': ou_people,
|
||||
+ 'subsuffix_dn': subsuffix_dn,
|
||||
+ 'parent_suffix_dn': parent_suffix_dn,
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+def test_subsuffix_with_entry_parent_in_tree(topo, setup_subsuffix_with_entry_parent):
|
||||
+ """Test that a sub-suffix with parent pointing to an entry is visible in the tree.
|
||||
+
|
||||
+ :id: 256f36f5-76ad-4043-ad8d-1f9e2afc4e1d
|
||||
+ :setup: Standalone instance with sub-suffix whose parent is an entry
|
||||
+ :steps:
|
||||
+ 1. Verify the sub-suffix backend exists
|
||||
+ 2. Get sub-suffixes of the root backend
|
||||
+ 3. Verify the sub-suffix appears in the list
|
||||
+ :expectedresults:
|
||||
+ 1. Backend should exist
|
||||
+ 2. Sub-suffixes should be retrievable
|
||||
+ 3. Sub-suffix should be visible (this is where the bug manifested)
|
||||
+ """
|
||||
+ backends = setup_subsuffix_with_entry_parent['backends']
|
||||
+ foo_backend = setup_subsuffix_with_entry_parent['foo_backend']
|
||||
+ subsuffix_dn = setup_subsuffix_with_entry_parent['subsuffix_dn']
|
||||
+
|
||||
+ # Step 1: Verify the sub-suffix backend exists
|
||||
+ assert foo_backend.exists(), "The foo backend should exist"
|
||||
+
|
||||
+ # Step 2: Get sub-suffixes of the root backend
|
||||
+ root_backend = backends.get(DEFAULT_SUFFIX)
|
||||
+ sub_suffixes = root_backend.get_sub_suffixes()
|
||||
+ log.info(f"Sub-suffixes found: {[s.get_attr_val_utf8('nsslapd-suffix') for s in sub_suffixes]}")
|
||||
+
|
||||
+ # Step 3: Verify sub-suffix is in the list
|
||||
+ sub_suffix_found = any(
|
||||
+ s.get_attr_val_utf8_l('nsslapd-suffix') == subsuffix_dn.lower()
|
||||
+ for s in sub_suffixes
|
||||
+ )
|
||||
+
|
||||
+ assert sub_suffix_found, (
|
||||
+ f"Sub-suffix {subsuffix_dn} should be visible in get_sub_suffixes(). "
|
||||
+ "The parent-suffix points to an entry, not a backend suffix."
|
||||
+ )
|
||||
+
|
||||
+
|
||||
+def test_subsuffix_in_backend_list(topo, setup_subsuffix_with_entry_parent):
|
||||
+ """Test that the sub-suffix appears in the backend list.
|
||||
+
|
||||
+ :id: 0ccc49af-91bb-4e8f-b0e1-1bd0b75c041b
|
||||
+ :setup: Standalone instance with sub-suffix configuration
|
||||
+ :steps:
|
||||
+ 1. Get all backends
|
||||
+ 2. Verify both root suffix and sub-suffix are present
|
||||
+ :expectedresults:
|
||||
+ 1. Should retrieve all backends
|
||||
+ 2. Both suffixes should be listed
|
||||
+ """
|
||||
+ backends = setup_subsuffix_with_entry_parent['backends']
|
||||
+ subsuffix_dn = setup_subsuffix_with_entry_parent['subsuffix_dn']
|
||||
+
|
||||
+ be_list = backends.list()
|
||||
+ suffixes = [be.get_attr_val_utf8_l('nsslapd-suffix') for be in be_list]
|
||||
+
|
||||
+ assert DEFAULT_SUFFIX.lower() in suffixes, \
|
||||
+ f"Root suffix {DEFAULT_SUFFIX} should be in the list"
|
||||
+ assert subsuffix_dn.lower() in suffixes, \
|
||||
+ f"Sub-suffix {subsuffix_dn} should be in the list"
|
||||
+
|
||||
+
|
||||
+def test_subsuffix_dn_boundary_matching():
|
||||
+ """Test that suffix matching respects DN component boundaries.
|
||||
+
|
||||
+ :id: 0b856e26-c394-4c36-b9ba-d7894aa2ed11
|
||||
+ :setup: None (unit test)
|
||||
+ :steps:
|
||||
+ 1. Test exact suffix match
|
||||
+ 2. Test proper DN ancestor match (ends with ,suffix)
|
||||
+ 3. Test that partial string matches are rejected
|
||||
+ :expectedresults:
|
||||
+ 1. Exact match should return True
|
||||
+ 2. Proper ancestor should return True
|
||||
+ 3. Partial string match should return False
|
||||
+ """
|
||||
+ from lib389.backend import is_subsuffix_of
|
||||
+
|
||||
+ all_suffixes = {'dc=com', 'dc=example,dc=com', 'ou=dept,dc=example,dc=com'}
|
||||
+
|
||||
+ # Test 1: Exact match
|
||||
+ assert is_subsuffix_of('dc=example,dc=com', 'dc=example,dc=com', all_suffixes), \
|
||||
+ "Exact match should return True"
|
||||
+
|
||||
+ # Test 2: Parent is an entry under the suffix (not itself a suffix)
|
||||
+ assert is_subsuffix_of('ou=people,dc=example,dc=com', 'dc=example,dc=com', all_suffixes), \
|
||||
+ "Parent entry under suffix should return True"
|
||||
+
|
||||
+ # Test 3: Parent IS a suffix - should return False (handled separately)
|
||||
+ assert not is_subsuffix_of('ou=dept,dc=example,dc=com', 'dc=example,dc=com', all_suffixes), \
|
||||
+ "Parent that is itself a suffix should return False"
|
||||
+
|
||||
+ # Test 4: Edge case - wrong DN boundary (string ends with suffix but wrong boundary)
|
||||
+ edge_suffixes = {'dc=com', 'st,dc=com'}
|
||||
+ assert is_subsuffix_of('dc=test,dc=com', 'dc=com', edge_suffixes), \
|
||||
+ "dc=test,dc=com should match dc=com"
|
||||
+ assert not is_subsuffix_of('dc=test,dc=com', 'st,dc=com', edge_suffixes), \
|
||||
+ "dc=test,dc=com should NOT match st,dc=com (wrong DN boundary)"
|
||||
+
|
||||
+ # Test 5: None input
|
||||
+ assert not is_subsuffix_of(None, 'dc=com', all_suffixes), \
|
||||
+ "None parent should return False"
|
||||
+
|
||||
+ # Test 6: Closest ancestor - should only match the nearest suffix
|
||||
+ # Hierarchy: dc=com -> dc=example,dc=com -> ou=branch,dc=example,dc=com (suffix)
|
||||
+ # -> ou=dept,ou=branch,dc=example,dc=com (entry) -> subsuffix
|
||||
+ # The subsuffix should only appear under ou=branch, not under dc=example,dc=com
|
||||
+ nested_suffixes = {'dc=com', 'dc=example,dc=com', 'ou=branch,dc=example,dc=com'}
|
||||
+ entry_parent = 'ou=dept,ou=branch,dc=example,dc=com'
|
||||
+ # Should match ou=branch (closest)
|
||||
+ assert is_subsuffix_of(entry_parent, 'ou=branch,dc=example,dc=com', nested_suffixes), \
|
||||
+ "Should match closest ancestor suffix (ou=branch)"
|
||||
+ # Should NOT match dc=example,dc=com (not closest)
|
||||
+ assert not is_subsuffix_of(entry_parent, 'dc=example,dc=com', nested_suffixes), \
|
||||
+ "Should NOT match distant ancestor (dc=example) - ou=branch is closer"
|
||||
+ # Should NOT match dc=com (not closest)
|
||||
+ assert not is_subsuffix_of(entry_parent, 'dc=com', nested_suffixes), \
|
||||
+ "Should NOT match distant ancestor (dc=com) - ou=branch is closer"
|
||||
+
|
||||
+ log.info("All DN boundary edge cases passed")
|
||||
+
|
||||
+
|
||||
+def test_deep_suffix_hierarchy(topo, request):
|
||||
+ """Test complex hierarchy: suffix -> suffix -> entry -> suffix -> suffix.
|
||||
+
|
||||
+ :id: fd06491a-defa-4780-8472-78c077febdfb
|
||||
+ :setup: Standalone instance
|
||||
+ :steps:
|
||||
+ 1. Create sub-suffix ou=branch (parent=dc=example,dc=com - a suffix)
|
||||
+ 2. Create entry ou=dept,ou=branch (not a suffix)
|
||||
+ 3. Create sub-suffix ou=team,ou=dept,ou=branch (parent=ou=dept - an entry)
|
||||
+ 4. Create sub-suffix ou=sub,ou=team,ou=dept,ou=branch (parent=ou=team - a suffix)
|
||||
+ 5. Verify all sub-suffixes are correctly placed in the tree
|
||||
+ :expectedresults:
|
||||
+ 1. Sub-suffix created successfully
|
||||
+ 2. Entry created successfully
|
||||
+ 3. Sub-suffix with entry parent created successfully
|
||||
+ 4. Sub-suffix with suffix parent created successfully
|
||||
+ 5. Tree hierarchy is correct
|
||||
+ """
|
||||
+ inst = topo.standalone
|
||||
+ backends = Backends(inst)
|
||||
+
|
||||
+ # Define the hierarchy
|
||||
+ branch_suffix = f'ou=branch,{DEFAULT_SUFFIX}'
|
||||
+ dept_entry = f'ou=dept,{branch_suffix}' # This is an ENTRY, not a suffix
|
||||
+ team_suffix = f'ou=team,{dept_entry}'
|
||||
+ sub_suffix = f'ou=sub,{team_suffix}'
|
||||
+
|
||||
+ created_backends = []
|
||||
+ created_entries = []
|
||||
+
|
||||
+ def cleanup():
|
||||
+ log.info("Cleaning up deep hierarchy test")
|
||||
+ for entry in reversed(created_entries):
|
||||
+ try:
|
||||
+ entry.delete()
|
||||
+ except Exception as e:
|
||||
+ log.warning(f"Failed to delete entry: {e}")
|
||||
+ for be in reversed(created_backends):
|
||||
+ try:
|
||||
+ be.delete()
|
||||
+ except Exception as e:
|
||||
+ log.warning(f"Failed to delete backend: {e}")
|
||||
+
|
||||
+ request.addfinalizer(cleanup)
|
||||
+
|
||||
+ # Step 1: Create ou=branch sub-suffix (parent is root suffix)
|
||||
+ log.info(f"Creating sub-suffix {branch_suffix}")
|
||||
+ branch_be = backends.create(properties={
|
||||
+ 'cn': 'branch',
|
||||
+ 'nsslapd-suffix': branch_suffix,
|
||||
+ 'parent': DEFAULT_SUFFIX,
|
||||
+ })
|
||||
+ created_backends.append(branch_be)
|
||||
+ branch_ous = OrganizationalUnits(inst, DEFAULT_SUFFIX)
|
||||
+ branch_ou = branch_ous.create(properties={'ou': 'branch'})
|
||||
+ created_entries.append(branch_ou)
|
||||
+
|
||||
+ # Step 2: Create ou=dept entry under branch (NOT a suffix)
|
||||
+ log.info(f"Creating entry {dept_entry}")
|
||||
+ dept_ous = OrganizationalUnits(inst, branch_suffix)
|
||||
+ dept_ou = dept_ous.create(properties={'ou': 'dept'})
|
||||
+ created_entries.append(dept_ou)
|
||||
+
|
||||
+ # Step 3: Create ou=team sub-suffix (parent is dept ENTRY, not a suffix)
|
||||
+ log.info(f"Creating sub-suffix {team_suffix} with entry parent {dept_entry}")
|
||||
+ team_be = backends.create(properties={
|
||||
+ 'cn': 'team',
|
||||
+ 'nsslapd-suffix': team_suffix,
|
||||
+ 'parent': dept_entry, # Parent is an ENTRY!
|
||||
+ })
|
||||
+ created_backends.append(team_be)
|
||||
+ team_ous = OrganizationalUnits(inst, dept_entry)
|
||||
+ team_ou = team_ous.create(properties={'ou': 'team'})
|
||||
+ created_entries.append(team_ou)
|
||||
+
|
||||
+ # Step 4: Create ou=sub sub-suffix (parent is team suffix)
|
||||
+ log.info(f"Creating sub-suffix {sub_suffix} with suffix parent {team_suffix}")
|
||||
+ sub_be = backends.create(properties={
|
||||
+ 'cn': 'sub',
|
||||
+ 'nsslapd-suffix': sub_suffix,
|
||||
+ 'parent': team_suffix, # Parent is a SUFFIX
|
||||
+ })
|
||||
+ created_backends.append(sub_be)
|
||||
+ sub_ous = OrganizationalUnits(inst, team_suffix)
|
||||
+ sub_ou = sub_ous.create(properties={'ou': 'sub'})
|
||||
+ created_entries.append(sub_ou)
|
||||
+
|
||||
+ # Step 5: Verify the tree hierarchy
|
||||
+ log.info("Verifying tree hierarchy...")
|
||||
+
|
||||
+ # Root should have branch as sub-suffix
|
||||
+ root_be = backends.get(DEFAULT_SUFFIX)
|
||||
+ root_subs = root_be.get_sub_suffixes()
|
||||
+ root_sub_suffixes = [s.get_attr_val_utf8_l('nsslapd-suffix') for s in root_subs]
|
||||
+ log.info(f"Root sub-suffixes: {root_sub_suffixes}")
|
||||
+ assert branch_suffix.lower() in root_sub_suffixes, \
|
||||
+ f"branch should be under root suffix"
|
||||
+
|
||||
+ # Branch should have team as sub-suffix (even though team's parent is an entry)
|
||||
+ branch_be_obj = backends.get(branch_suffix)
|
||||
+ branch_subs = branch_be_obj.get_sub_suffixes()
|
||||
+ branch_sub_suffixes = [s.get_attr_val_utf8_l('nsslapd-suffix') for s in branch_subs]
|
||||
+ log.info(f"Branch sub-suffixes: {branch_sub_suffixes}")
|
||||
+ assert team_suffix.lower() in branch_sub_suffixes, \
|
||||
+ f"team should be under branch suffix (parent is entry under branch)"
|
||||
+
|
||||
+ # Team should have sub as sub-suffix
|
||||
+ team_be_obj = backends.get(team_suffix)
|
||||
+ team_subs = team_be_obj.get_sub_suffixes()
|
||||
+ team_sub_suffixes = [s.get_attr_val_utf8_l('nsslapd-suffix') for s in team_subs]
|
||||
+ log.info(f"Team sub-suffixes: {team_sub_suffixes}")
|
||||
+ assert sub_suffix.lower() in team_sub_suffixes, \
|
||||
+ f"sub should be under team suffix"
|
||||
+
|
||||
+ log.info("Deep hierarchy test passed!")
|
||||
+
|
||||
+
|
||||
+if __name__ == '__main__':
|
||||
+ CURRENT_FILE = os.path.realpath(__file__)
|
||||
+ pytest.main(["-s", CURRENT_FILE])
|
||||
diff --git a/src/lib389/lib389/backend.py b/src/lib389/lib389/backend.py
|
||||
index db464b43a..274d45abe 100644
|
||||
--- a/src/lib389/lib389/backend.py
|
||||
+++ b/src/lib389/lib389/backend.py
|
||||
@@ -38,6 +38,36 @@ from lib389.lint import DSBLE0001, DSBLE0002, DSBLE0003, DSBLE0004, DSBLE0005, D
|
||||
from lib389.plugins import USNPlugin
|
||||
|
||||
|
||||
+def is_subsuffix_of(sub_parent, be_suffix, all_suffixes):
|
||||
+ """Check if sub_parent indicates this is a sub-suffix of be_suffix.
|
||||
+
|
||||
+ Returns True only if be_suffix is the CLOSEST ancestor suffix of sub_parent.
|
||||
+ This prevents a sub-suffix from appearing under multiple ancestors.
|
||||
+
|
||||
+ :param sub_parent: The nsslapd-parent-suffix value (lowercase)
|
||||
+ :param be_suffix: The suffix to check against (lowercase)
|
||||
+ :param all_suffixes: Set of all backend suffixes (lowercase)
|
||||
+ :returns: True if be_suffix is the closest ancestor suffix
|
||||
+ """
|
||||
+ if not sub_parent:
|
||||
+ return False
|
||||
+ if sub_parent == be_suffix:
|
||||
+ return True
|
||||
+ if sub_parent in all_suffixes:
|
||||
+ # sub_parent is itself a suffix, will be handled separately
|
||||
+ return False
|
||||
+ if not sub_parent.endswith(',' + be_suffix):
|
||||
+ return False
|
||||
+ # Find the closest (longest) matching suffix for this parent
|
||||
+ best_match = None
|
||||
+ for sfx in all_suffixes:
|
||||
+ if sub_parent == sfx or sub_parent.endswith(',' + sfx):
|
||||
+ if best_match is None or len(sfx) > len(best_match):
|
||||
+ best_match = sfx
|
||||
+ # Only return True if be_suffix is the closest match
|
||||
+ return best_match == be_suffix
|
||||
+
|
||||
+
|
||||
class BackendLegacy(object):
|
||||
proxied_methods = 'search_s getEntry'.split()
|
||||
|
||||
@@ -1104,22 +1134,27 @@ class Backend(DSLdapObject):
|
||||
vlv.create(rdn="cn=" + vlvname, properties=props, basedn=basedn)
|
||||
|
||||
def get_sub_suffixes(self):
|
||||
- """Return a list of Backend's
|
||||
- returns: a List of subsuffix entries
|
||||
+ """Return a list of Backend's that are sub-suffixes of this backend.
|
||||
+ :returns: A list of Backend instances that are sub-suffixes
|
||||
"""
|
||||
subsuffixes = []
|
||||
top_be_suffix = self.get_attr_val_utf8_l('nsslapd-suffix')
|
||||
+ if not top_be_suffix:
|
||||
+ return subsuffixes
|
||||
+
|
||||
mts = self._mts.list()
|
||||
+ be_insts = Backends(self._instance).list()
|
||||
+ all_suffixes = {be.get_attr_val_utf8_l('nsslapd-suffix') for be in be_insts}
|
||||
+
|
||||
for mt in mts:
|
||||
parent_suffix = mt.get_attr_val_utf8_l('nsslapd-parent-suffix')
|
||||
if parent_suffix is None:
|
||||
continue
|
||||
- if parent_suffix == top_be_suffix:
|
||||
+
|
||||
+ if is_subsuffix_of(parent_suffix, top_be_suffix, all_suffixes):
|
||||
child_suffix = mt.get_attr_val_utf8_l('cn')
|
||||
- be_insts = Backends(self._instance).list()
|
||||
for be in be_insts:
|
||||
- be_suffix = be.get_attr_val_utf8_l('nsslapd-suffix')
|
||||
- if child_suffix == be_suffix:
|
||||
+ if child_suffix == be.get_attr_val_utf8_l('nsslapd-suffix'):
|
||||
subsuffixes.append(be)
|
||||
break
|
||||
return subsuffixes
|
||||
diff --git a/src/lib389/lib389/cli_conf/backend.py b/src/lib389/lib389/cli_conf/backend.py
|
||||
index d0ec4bd9e..9772e39d4 100644
|
||||
--- a/src/lib389/lib389/cli_conf/backend.py
|
||||
+++ b/src/lib389/lib389/cli_conf/backend.py
|
||||
@@ -7,7 +7,7 @@
|
||||
# See LICENSE for details.
|
||||
# --- END COPYRIGHT BLOCK ---
|
||||
|
||||
-from lib389.backend import Backend, Backends, DatabaseConfig, BackendSuffixView
|
||||
+from lib389.backend import Backend, Backends, DatabaseConfig, BackendSuffixView, is_subsuffix_of
|
||||
from lib389.configurations.sample import (
|
||||
create_base_domain,
|
||||
create_base_org,
|
||||
@@ -338,6 +338,7 @@ def is_db_replicated(inst, suffix):
|
||||
def backend_get_subsuffixes(inst, basedn, log, args):
|
||||
subsuffixes = []
|
||||
be_insts = MANY(inst).list()
|
||||
+ all_suffixes = {be.get_attr_val_utf8_l('nsslapd-suffix') for be in be_insts}
|
||||
for be in be_insts:
|
||||
be_suffix = be.get_attr_val_utf8_l('nsslapd-suffix')
|
||||
if be_suffix == args.be_name.lower():
|
||||
@@ -347,7 +348,7 @@ def backend_get_subsuffixes(inst, basedn, log, args):
|
||||
db_type = "suffix"
|
||||
sub = mt.get_attr_val_utf8_l('nsslapd-parent-suffix')
|
||||
sub_be = mt.get_attr_val_utf8_l('nsslapd-backend')
|
||||
- if sub == be_suffix:
|
||||
+ if is_subsuffix_of(sub, be_suffix, all_suffixes):
|
||||
# We have a subsuffix (maybe a db link?)
|
||||
if is_db_link(inst, sub_be):
|
||||
db_type = "link"
|
||||
@@ -399,38 +400,34 @@ def build_node(suffix, be_name, subsuf=False, link=False, replicated=False):
|
||||
}
|
||||
|
||||
|
||||
-def backend_build_tree(inst, be_insts, nodes):
|
||||
- """Recursively build the tree
|
||||
- """
|
||||
- if len(nodes) == 0:
|
||||
- # Done
|
||||
+def backend_build_tree(inst, be_insts, nodes, all_suffixes):
|
||||
+ """Recursively build the tree."""
|
||||
+ if not nodes:
|
||||
return
|
||||
|
||||
for node in nodes:
|
||||
- node_suffix = node['id']
|
||||
+ node_suffix = node['id'].lower()
|
||||
# Get sub suffixes and chaining of node
|
||||
for be in be_insts:
|
||||
be_suffix = be.get_attr_val_utf8_l('nsslapd-suffix')
|
||||
- if be_suffix == node_suffix.lower():
|
||||
+ if be_suffix == node_suffix:
|
||||
# We have our parent, now find the children
|
||||
mts = be._mts.list()
|
||||
-
|
||||
for mt in mts:
|
||||
sub_parent = mt.get_attr_val_utf8_l('nsslapd-parent-suffix')
|
||||
sub_be = mt.get_attr_val_utf8_l('nsslapd-backend')
|
||||
sub_suffix = mt.get_attr_val_utf8_l('cn')
|
||||
- if sub_parent == be_suffix:
|
||||
+ if is_subsuffix_of(sub_parent, be_suffix, all_suffixes):
|
||||
# We have a subsuffix (maybe a db link?)
|
||||
link = is_db_link(inst, sub_be)
|
||||
replicated = is_db_replicated(inst, sub_suffix)
|
||||
node['children'].append(build_node(sub_suffix,
|
||||
- sub_be,
|
||||
- subsuf=True,
|
||||
- link=link,
|
||||
- replicated=replicated))
|
||||
-
|
||||
+ sub_be,
|
||||
+ subsuf=True,
|
||||
+ link=link,
|
||||
+ replicated=replicated))
|
||||
# Recurse over the new subsuffixes
|
||||
- backend_build_tree(inst, be_insts, node['children'])
|
||||
+ backend_build_tree(inst, be_insts, node['children'], all_suffixes)
|
||||
break
|
||||
|
||||
|
||||
@@ -471,7 +468,8 @@ def backend_get_tree(inst, basedn, log, args):
|
||||
else:
|
||||
# Build the tree
|
||||
be_insts = Backends(inst).list()
|
||||
- backend_build_tree(inst, be_insts, nodes)
|
||||
+ all_suffixes = {be.get_attr_val_utf8_l('nsslapd-suffix') for be in be_insts}
|
||||
+ backend_build_tree(inst, be_insts, nodes, all_suffixes)
|
||||
|
||||
# Done
|
||||
if args.json:
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@ -0,0 +1,38 @@
|
||||
From aa24c00d9ed1ea9730c0e8c5dccc1bbb5b61e312 Mon Sep 17 00:00:00 2001
|
||||
From: Lenka Doudova <lryznaro@redhat.com>
|
||||
Date: Mon, 26 Jan 2026 16:21:23 +0100
|
||||
Subject: [PATCH] Issue 7014 - memberOf - ignored deferred updates with LMDB
|
||||
|
||||
Description:
|
||||
Fix typo in pytest marker reason.
|
||||
|
||||
Relates: #7014
|
||||
|
||||
Author: Lenka Doudova
|
||||
Reviewed by: ???
|
||||
---
|
||||
.../suites/memberof_plugin/memberof_deferred_lmdb_test.py | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/memberof_plugin/memberof_deferred_lmdb_test.py b/dirsrvtests/tests/suites/memberof_plugin/memberof_deferred_lmdb_test.py
|
||||
index 0d9f793c1..12fcfa3ec 100644
|
||||
--- a/dirsrvtests/tests/suites/memberof_plugin/memberof_deferred_lmdb_test.py
|
||||
+++ b/dirsrvtests/tests/suites/memberof_plugin/memberof_deferred_lmdb_test.py
|
||||
@@ -1,4 +1,5 @@
|
||||
# --- BEGIN COPYRIGHT BLOCK ---
|
||||
+
|
||||
# Copyright (C) 2025 Red Hat, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
@@ -28,7 +29,7 @@ else:
|
||||
logging.getLogger(__name__).setLevel(logging.INFO)
|
||||
|
||||
|
||||
-@pytest.mark.skipif(get_default_db_lib() != "mdb", reason="Not supported over mdb")
|
||||
+@pytest.mark.skipif(get_default_db_lib() != "mdb", reason="Not supported over bdb")
|
||||
def test_memberof_deferred_update_lmdb_rejection(topo):
|
||||
"""Test that memberOf plugin rejects deferred update configuration with LMDB backend
|
||||
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@ -0,0 +1,48 @@
|
||||
From 4a73a31e6c91e507e5aa2cba1e5bd55d1d07894d Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
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
|
||||
|
||||
174
0017-Issue-6947-Revise-time-skew-check-in-healthcheck-too.patch
Normal file
174
0017-Issue-6947-Revise-time-skew-check-in-healthcheck-too.patch
Normal file
@ -0,0 +1,174 @@
|
||||
From bc28406778534a77064a26b4f0467dffecde33ea Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
Date: Tue, 27 Jan 2026 09:40:12 +0100
|
||||
Subject: [PATCH] Issue 6947 - Revise time skew check in healthcheck tool - add
|
||||
tests (#7208)
|
||||
|
||||
Description:
|
||||
Add tests for DSSKEWLE0003 and DSSKEWLE0004 checks.
|
||||
|
||||
Relates: https://github.com/389ds/389-ds-base/issues/6947
|
||||
|
||||
Reviewed by: @droideck (Thanks!)
|
||||
---
|
||||
.../suites/healthcheck/health_skew_test.py | 148 ++++++++++++++++++
|
||||
1 file changed, 148 insertions(+)
|
||||
create mode 100644 dirsrvtests/tests/suites/healthcheck/health_skew_test.py
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/healthcheck/health_skew_test.py b/dirsrvtests/tests/suites/healthcheck/health_skew_test.py
|
||||
new file mode 100644
|
||||
index 000000000..9ee070364
|
||||
--- /dev/null
|
||||
+++ b/dirsrvtests/tests/suites/healthcheck/health_skew_test.py
|
||||
@@ -0,0 +1,148 @@
|
||||
+# --- 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 logging
|
||||
+import os
|
||||
+import pytest
|
||||
+import subprocess
|
||||
+from lib389._constants import DEFAULT_SUFFIX
|
||||
+from lib389.dseldif import DSEldif
|
||||
+from lib389.replica import ReplicationManager
|
||||
+from lib389.topologies import topology_m2
|
||||
+
|
||||
+pytestmark = pytest.mark.tier1
|
||||
+
|
||||
+CMD_OUTPUT = 'No issues found.'
|
||||
+JSON_OUTPUT = '[]'
|
||||
+
|
||||
+log = logging.getLogger(__name__)
|
||||
+
|
||||
+
|
||||
+def run_healthcheck_and_check_result(instance, searched_code, json=False, isnot=False):
|
||||
+ """Run healthcheck and verify the expected code is in the output"""
|
||||
+ cmd = ['dsctl']
|
||||
+ if json:
|
||||
+ cmd.append('--json')
|
||||
+ if searched_code == CMD_OUTPUT:
|
||||
+ searched_code = JSON_OUTPUT
|
||||
+ cmd.append(instance.serverid)
|
||||
+ cmd.extend(['healthcheck', '--check', 'dseldif:nsstate'])
|
||||
+
|
||||
+ result = subprocess.run(cmd, capture_output=True, universal_newlines=True)
|
||||
+ log.info(f'Running: {cmd}')
|
||||
+ log.info(f'Stdout: {result.stdout}')
|
||||
+ log.info(f'Stderr: {result.stderr}')
|
||||
+ log.info(f'Return code: {result.returncode}')
|
||||
+ stdout = result.stdout
|
||||
+
|
||||
+ # stdout should not be empty
|
||||
+ assert stdout is not None
|
||||
+ assert len(stdout) > 0
|
||||
+
|
||||
+ if isnot:
|
||||
+ assert searched_code not in stdout, \
|
||||
+ f'{searched_code} should NOT be in healthcheck output but was found'
|
||||
+ log.info(f'Verified {searched_code} is NOT in healthcheck output')
|
||||
+ else:
|
||||
+ assert searched_code in stdout, \
|
||||
+ f'{searched_code} should be in healthcheck output but was not found'
|
||||
+ log.info(f'Verified {searched_code} is in healthcheck output')
|
||||
+
|
||||
+
|
||||
+def test_healthcheck_time_skew_extensive(topology_m2):
|
||||
+ """Check if HealthCheck returns DSSKEWLE0003 and DSSKEWLE0004 codes for extensive time skew
|
||||
+
|
||||
+ :id: 7591cd2b-8d66-4d33-9f8d-babff0571086
|
||||
+ :setup: Two suppliers replication topology
|
||||
+ :steps:
|
||||
+ 1. Create a replicated topology
|
||||
+ 2. Stop supplier1
|
||||
+ 3. Increase time skew on supplier1 to over 24 hours
|
||||
+ 4. Start supplier1
|
||||
+ 5. Use HealthCheck and verify DSSKEWLE0003 is reported
|
||||
+ 6. Set nsslapd-ignore-time-skew to on
|
||||
+ 7. Use HealthCheck and verify DSSKEWLE0003 is NOT reported
|
||||
+ 8. Stop supplier1
|
||||
+ 9. Increase time skew on supplier1 to over 365 days
|
||||
+ 10. Start supplier1
|
||||
+ 11. Use HealthCheck and verify only DSSKEWLE0004 is reported
|
||||
+ :expectedresults:
|
||||
+ 1. Success
|
||||
+ 2. Success
|
||||
+ 3. Success
|
||||
+ 4. Success
|
||||
+ 5. Healthcheck reports DSSKEWLE0003 code
|
||||
+ 6. Success
|
||||
+ 7. Healthcheck does not report DSSKEWLE0003 code
|
||||
+ 8. Success
|
||||
+ 9. Success
|
||||
+ 10. Success
|
||||
+ 11. Healthcheck reports DSSKEWLE0004 code and not DSSKEWLE0003
|
||||
+ """
|
||||
+
|
||||
+ M1 = topology_m2.ms['supplier1']
|
||||
+ M2 = topology_m2.ms['supplier2']
|
||||
+
|
||||
+ # Ensure replication is working first
|
||||
+ repl = ReplicationManager(DEFAULT_SUFFIX)
|
||||
+ repl.wait_for_replication(M1, M2)
|
||||
+
|
||||
+ # Step 2-4: Stop supplier1, increase time skew to over 24 hours, start supplier1
|
||||
+ log.info('Stop supplier1 to modify dse.ldif')
|
||||
+ M1.stop()
|
||||
+
|
||||
+ # Set time skew to over 24 hours (86400 seconds)
|
||||
+ # Add a margin to be safely over the threshold
|
||||
+ time_skew_24h = 86400 + 3600 # 25 hours
|
||||
+ log.info(f'Increase time skew on supplier1 by {time_skew_24h} seconds')
|
||||
+ DSEldif(M1)._increaseTimeSkew(DEFAULT_SUFFIX, time_skew_24h)
|
||||
+
|
||||
+ log.info('Start supplier1')
|
||||
+ M1.start()
|
||||
+
|
||||
+ # Step 5: Verify DSSKEWLE0003 is reported
|
||||
+ log.info('Run healthcheck and verify DSSKEWLE0003 is reported')
|
||||
+ run_healthcheck_and_check_result(M1, 'DSSKEWLE0003', json=False)
|
||||
+ run_healthcheck_and_check_result(M1, 'DSSKEWLE0003', json=True)
|
||||
+
|
||||
+ # Step 6: Set nsslapd-ignore-time-skew to on
|
||||
+ log.info('Set nsslapd-ignore-time-skew to on')
|
||||
+ M1.config.set('nsslapd-ignore-time-skew', 'on')
|
||||
+
|
||||
+ # Step 7: Verify DSSKEWLE0003 is NOT reported when ignoring time skew
|
||||
+ log.info('Run healthcheck and verify DSSKEWLE0003 is NOT reported')
|
||||
+ run_healthcheck_and_check_result(M1, 'DSSKEWLE0003', json=False, isnot=True)
|
||||
+ run_healthcheck_and_check_result(M1, 'DSSKEWLE0003', json=True, isnot=True)
|
||||
+
|
||||
+ # Step 8-10: Stop supplier1, increase time skew to over 365 days, start supplier1
|
||||
+ log.info('Stop supplier1 to modify dse.ldif')
|
||||
+ M1.stop()
|
||||
+
|
||||
+ # Increase time skew to over 365 days (31536000 seconds)
|
||||
+ # We need to add enough to go from current ~25 hours to over 365 days
|
||||
+ time_skew_year = (86400 * 365) + 86400 # 366 days total additional
|
||||
+ log.info(f'Increase time skew on supplier1 by {time_skew_year} seconds')
|
||||
+ DSEldif(M1)._increaseTimeSkew(DEFAULT_SUFFIX, time_skew_year)
|
||||
+
|
||||
+ log.info('Start supplier1')
|
||||
+ M1.start()
|
||||
+
|
||||
+ # Step 11: Verify only DSSKEWLE0004 is reported (not DSSKEWLE0003)
|
||||
+ log.info('Run healthcheck and verify only DSSKEWLE0004 is reported')
|
||||
+ run_healthcheck_and_check_result(M1, 'DSSKEWLE0004', json=False)
|
||||
+ run_healthcheck_and_check_result(M1, 'DSSKEWLE0004', json=True)
|
||||
+ run_healthcheck_and_check_result(M1, 'DSSKEWLE0003', json=False, isnot=True)
|
||||
+ run_healthcheck_and_check_result(M1, 'DSSKEWLE0003', json=True, isnot=True)
|
||||
+
|
||||
+
|
||||
+if __name__ == '__main__':
|
||||
+ # Run isolated
|
||||
+ # -s for DEBUG mode
|
||||
+ CURRENT_FILE = os.path.realpath(__file__)
|
||||
+ pytest.main("-s %s" % CURRENT_FILE)
|
||||
--
|
||||
2.52.0
|
||||
|
||||
215
0018-Issue-7201-Syscall-overhead-in-LMDB-import-writer-th.patch
Normal file
215
0018-Issue-7201-Syscall-overhead-in-LMDB-import-writer-th.patch
Normal file
@ -0,0 +1,215 @@
|
||||
From a53c0e4dea5c35fef196500b2a36c92bc8f07a51 Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
Date: Tue, 27 Jan 2026 09:49:16 +0100
|
||||
Subject: [PATCH] Issue 7201 - Syscall overhead in LMDB import writer thread
|
||||
(#7204)
|
||||
|
||||
Bug Description:
|
||||
ldif2db import is slower with LMDB than with BDB (~3500 vs ~4500
|
||||
entries/s) due to 2 issues:
|
||||
1. The MDB_STAT_STEP macro calls `clock_gettime()` to collect
|
||||
performance statistics. This was called on every single operation inside
|
||||
the writer loop, resulting in ~3 syscalls per write or ~6000 syscalls
|
||||
per transaction (with 2000 as the default batch size).
|
||||
|
||||
2. In `dbmdb_import_workerq_push()`, after copying work to a worker
|
||||
slot, the condition variable was never signaled. This caused workers to
|
||||
spend up to 100ms in `safe_cond_wait()` before checking for new work,
|
||||
severely limiting import throughput.
|
||||
|
||||
Fix Description:
|
||||
1. Add a new config parameter `nsslapd-mdb-import-stats` (default: off)
|
||||
to control whether performance statistics collection is enabled.
|
||||
2. Add `pthread_cond_broadcast()` immediately after copying data to wake
|
||||
the workers.
|
||||
|
||||
After applying these fixes ldif2db import rate is about ~10000 entries/s.
|
||||
|
||||
Fixes: https://github.com/389ds/389-ds-base/issues/7201
|
||||
|
||||
Reviewed by: @progier389 (Thanks!)
|
||||
---
|
||||
.../slapd/back-ldbm/db-mdb/mdb_config.c | 23 +++++++++++
|
||||
.../back-ldbm/db-mdb/mdb_import_threads.c | 40 ++++++++++---------
|
||||
.../slapd/back-ldbm/db-mdb/mdb_layer.h | 2 +
|
||||
3 files changed, 46 insertions(+), 19 deletions(-)
|
||||
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/db-mdb/mdb_config.c b/ldap/servers/slapd/back-ldbm/db-mdb/mdb_config.c
|
||||
index 96295ed5b..ade42b1d7 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/db-mdb/mdb_config.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/db-mdb/mdb_config.c
|
||||
@@ -477,6 +477,28 @@ dbmdb_ctx_t_db_durable_transactions_set(void *arg, void *value, char *errorbuf _
|
||||
return retval;
|
||||
}
|
||||
|
||||
+static void *
|
||||
+dbmdb_ctx_t_db_import_stats_get(void *arg)
|
||||
+{
|
||||
+ struct ldbminfo *li = (struct ldbminfo *)arg;
|
||||
+
|
||||
+ return (void *)((uintptr_t)(MDB_CONFIG(li)->dsecfg.import_stats));
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+dbmdb_ctx_t_db_import_stats_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);
|
||||
+
|
||||
+ if (apply) {
|
||||
+ MDB_CONFIG(li)->dsecfg.import_stats = val;
|
||||
+ }
|
||||
+
|
||||
+ return retval;
|
||||
+}
|
||||
+
|
||||
static int
|
||||
dbmdb_ctx_t_set_bypass_filter_test(void *arg,
|
||||
void *value,
|
||||
@@ -589,6 +611,7 @@ static config_info dbmdb_ctx_t_param[] = {
|
||||
{CONFIG_MDB_MAX_DBS, CONFIG_TYPE_INT, "512", &dbmdb_ctx_t_db_max_dbs_get, &dbmdb_ctx_t_db_max_dbs_set, CONFIG_FLAG_ALWAYS_SHOW | CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
|
||||
{CONFIG_MAXPASSBEFOREMERGE, CONFIG_TYPE_INT, "100", &dbmdb_ctx_t_maxpassbeforemerge_get, &dbmdb_ctx_t_maxpassbeforemerge_set, 0},
|
||||
{CONFIG_DB_DURABLE_TRANSACTIONS, CONFIG_TYPE_ONOFF, "on", &dbmdb_ctx_t_db_durable_transactions_get, &dbmdb_ctx_t_db_durable_transactions_set, CONFIG_FLAG_ALWAYS_SHOW},
|
||||
+ {CONFIG_MDB_IMPORT_STATS, CONFIG_TYPE_ONOFF, "off", &dbmdb_ctx_t_db_import_stats_get, &dbmdb_ctx_t_db_import_stats_set, CONFIG_FLAG_ALWAYS_SHOW | CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
|
||||
{CONFIG_BYPASS_FILTER_TEST, CONFIG_TYPE_STRING, "on", &dbmdb_ctx_t_get_bypass_filter_test, &dbmdb_ctx_t_set_bypass_filter_test, CONFIG_FLAG_ALWAYS_SHOW | CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
|
||||
{CONFIG_SERIAL_LOCK, CONFIG_TYPE_ONOFF, "on", &dbmdb_ctx_t_serial_lock_get, &dbmdb_ctx_t_serial_lock_set, CONFIG_FLAG_ALWAYS_SHOW | CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
|
||||
{CONFIG_CACHE_AUTOSIZE, CONFIG_TYPE_INT, "25", &mdb_config_cache_autosize_get, &mdb_config_cache_autosize_set, CONFIG_FLAG_ALWAYS_SHOW | CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
|
||||
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 2270abd69..65b29343e 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
|
||||
@@ -59,9 +59,9 @@
|
||||
|
||||
|
||||
/* import thread usage statistics */
|
||||
-#define MDB_STAT_INIT(stats) { mdb_stat_collect(&stats, MDB_STAT_RUN, 1); }
|
||||
-#define MDB_STAT_END(stats) { mdb_stat_collect(&stats, MDB_STAT_RUN, 0); }
|
||||
-#define MDB_STAT_STEP(stats, step) { mdb_stat_collect(&stats, (step), 0); }
|
||||
+#define MDB_STAT_INIT(stats, enabled) { if (enabled) mdb_stat_collect(&stats, MDB_STAT_RUN, 1); }
|
||||
+#define MDB_STAT_END(stats, enabled) { if (enabled) mdb_stat_collect(&stats, MDB_STAT_RUN, 0); }
|
||||
+#define MDB_STAT_STEP(stats, step, enabled) { if (enabled) mdb_stat_collect(&stats, (step), 0); }
|
||||
|
||||
typedef enum {
|
||||
MDB_STAT_RUN,
|
||||
@@ -424,6 +424,7 @@ dbmdb_import_workerq_push(ImportQueue_t *q, WorkerQueueData_t *data)
|
||||
return -1;
|
||||
}
|
||||
dbmdb_dup_worker_slot(q, data, slot);
|
||||
+ pthread_cond_broadcast(&q->cv);
|
||||
pthread_mutex_unlock(&q->mutex);
|
||||
return 0;
|
||||
}
|
||||
@@ -3914,14 +3915,15 @@ dbmdb_import_writer(void*param)
|
||||
int count = 0;
|
||||
int rc = 0;
|
||||
mdb_stat_info_t stats = {0};
|
||||
+ int stats_enabled = ctx->ctx->dsecfg.import_stats;
|
||||
|
||||
- MDB_STAT_INIT(stats);
|
||||
+ MDB_STAT_INIT(stats, stats_enabled);
|
||||
while (!rc && !info_is_finished(info)) {
|
||||
- MDB_STAT_STEP(stats, MDB_STAT_PAUSE);
|
||||
+ MDB_STAT_STEP(stats, MDB_STAT_PAUSE, stats_enabled);
|
||||
wait_for_starting(info);
|
||||
- MDB_STAT_STEP(stats, MDB_STAT_READ);
|
||||
+ MDB_STAT_STEP(stats, MDB_STAT_READ, stats_enabled);
|
||||
slot = dbmdb_import_q_getall(&ctx->writerq);
|
||||
- MDB_STAT_STEP(stats, MDB_STAT_RUN);
|
||||
+ MDB_STAT_STEP(stats, MDB_STAT_RUN, stats_enabled);
|
||||
if (info_is_finished(info)) {
|
||||
dbmdb_import_q_flush(&ctx->writerq);
|
||||
break;
|
||||
@@ -3932,14 +3934,14 @@ dbmdb_import_writer(void*param)
|
||||
|
||||
for (; slot; slot = nextslot) {
|
||||
if (!txn) {
|
||||
- MDB_STAT_STEP(stats, MDB_STAT_TXNSTART);
|
||||
+ MDB_STAT_STEP(stats, MDB_STAT_TXNSTART, stats_enabled);
|
||||
rc = TXN_BEGIN(ctx->ctx->env, NULL, 0, &txn);
|
||||
}
|
||||
if (!rc) {
|
||||
- MDB_STAT_STEP(stats, MDB_STAT_WRITE);
|
||||
+ MDB_STAT_STEP(stats, MDB_STAT_WRITE, stats_enabled);
|
||||
rc = MDB_PUT(txn, slot->dbi->dbi, &slot->key, &slot->data, 0);
|
||||
}
|
||||
- MDB_STAT_STEP(stats, MDB_STAT_RUN);
|
||||
+ MDB_STAT_STEP(stats, MDB_STAT_RUN, stats_enabled);
|
||||
nextslot = slot->next;
|
||||
slapi_ch_free((void**)&slot);
|
||||
}
|
||||
@@ -3947,9 +3949,9 @@ dbmdb_import_writer(void*param)
|
||||
break;
|
||||
}
|
||||
if (count++ >= WRITER_MAX_OPS_IN_TXN) {
|
||||
- MDB_STAT_STEP(stats, MDB_STAT_TXNSTOP);
|
||||
+ MDB_STAT_STEP(stats, MDB_STAT_TXNSTOP, stats_enabled);
|
||||
rc = TXN_COMMIT(txn);
|
||||
- MDB_STAT_STEP(stats, MDB_STAT_RUN);
|
||||
+ MDB_STAT_STEP(stats, MDB_STAT_RUN, stats_enabled);
|
||||
if (rc) {
|
||||
break;
|
||||
}
|
||||
@@ -3958,32 +3960,32 @@ dbmdb_import_writer(void*param)
|
||||
}
|
||||
}
|
||||
if (txn && !rc) {
|
||||
- MDB_STAT_STEP(stats, MDB_STAT_TXNSTOP);
|
||||
+ MDB_STAT_STEP(stats, MDB_STAT_TXNSTOP, stats_enabled);
|
||||
rc = TXN_COMMIT(txn);
|
||||
- MDB_STAT_STEP(stats, MDB_STAT_RUN);
|
||||
+ MDB_STAT_STEP(stats, MDB_STAT_RUN, stats_enabled);
|
||||
if (!rc) {
|
||||
txn = NULL;
|
||||
}
|
||||
}
|
||||
if (txn) {
|
||||
- MDB_STAT_STEP(stats, MDB_STAT_TXNSTOP);
|
||||
+ MDB_STAT_STEP(stats, MDB_STAT_TXNSTOP, stats_enabled);
|
||||
TXN_ABORT(txn);
|
||||
- MDB_STAT_STEP(stats, MDB_STAT_RUN);
|
||||
+ MDB_STAT_STEP(stats, MDB_STAT_RUN, stats_enabled);
|
||||
txn = NULL;
|
||||
}
|
||||
- MDB_STAT_STEP(stats, MDB_STAT_WRITE);
|
||||
+ MDB_STAT_STEP(stats, MDB_STAT_WRITE, stats_enabled);
|
||||
if (!rc) {
|
||||
/* Ensure that all data are written on disk */
|
||||
rc = mdb_env_sync(ctx->ctx->env, 1);
|
||||
}
|
||||
- MDB_STAT_END(stats);
|
||||
+ MDB_STAT_END(stats, stats_enabled);
|
||||
|
||||
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));
|
||||
thread_abort(info);
|
||||
- } else {
|
||||
+ } else if (stats_enabled) {
|
||||
char buf[200];
|
||||
char *summary = mdb_stat_summarize(&stats, buf, sizeof buf);
|
||||
if (summary) {
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/db-mdb/mdb_layer.h b/ldap/servers/slapd/back-ldbm/db-mdb/mdb_layer.h
|
||||
index 647d00db9..cf6d00dd4 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/db-mdb/mdb_layer.h
|
||||
+++ b/ldap/servers/slapd/back-ldbm/db-mdb/mdb_layer.h
|
||||
@@ -41,6 +41,7 @@
|
||||
#define CONFIG_MDB_MAX_SIZE "nsslapd-mdb-max-size"
|
||||
#define CONFIG_MDB_MAX_READERS "nsslapd-mdb-max-readers"
|
||||
#define CONFIG_MDB_MAX_DBS "nsslapd-mdb-max-dbs"
|
||||
+#define CONFIG_MDB_IMPORT_STATS "nsslapd-mdb-import-stats"
|
||||
|
||||
#define DBMDB_DB_MINSIZE ( 4LL * MEGABYTE )
|
||||
#define DBMDB_DISK_RESERVE(disksize) ((disksize)*2ULL/1000ULL)
|
||||
@@ -76,6 +77,7 @@ typedef struct
|
||||
int max_readers;
|
||||
int max_dbs;
|
||||
uint64_t max_size;
|
||||
+ int import_stats;
|
||||
} dbmdb_cfg_t;
|
||||
|
||||
/* config parameters limits */
|
||||
--
|
||||
2.52.0
|
||||
|
||||
135
0019-Issue-7096-2nd-During-replication-online-total-init-.patch
Normal file
135
0019-Issue-7096-2nd-During-replication-online-total-init-.patch
Normal file
@ -0,0 +1,135 @@
|
||||
From 40484cb0b5034bc3c1e23b2ae1f2d39eedce07e9 Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
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
|
||||
|
||||
149
0020-Issue-7206-Should-log-whether-TLS-key-is-PQC-or-not-.patch
Normal file
149
0020-Issue-7206-Should-log-whether-TLS-key-is-PQC-or-not-.patch
Normal file
@ -0,0 +1,149 @@
|
||||
From 8c6d1cfca22f87b20b79a419ceabdb182846ff4a Mon Sep 17 00:00:00 2001
|
||||
From: progier389 <progier@redhat.com>
|
||||
Date: Tue, 27 Jan 2026 15:39:39 +0100
|
||||
Subject: [PATCH] Issue 7206 - Should log whether TLS key is PQC or not (#7207)
|
||||
|
||||
Append [PQC] to the cipher name when logging SSL/TLS if the Key Exchange is one of the KEM group
|
||||
If connection debug level is enabled, logs in error log the keaType and keaGroup (as integer)
|
||||
|
||||
Issue: #7206
|
||||
|
||||
Reviewed by: @tbordaz, @droideck (Thanks!)
|
||||
|
||||
* Issue 7206 - Should log whether TLS key is PQC or not
|
||||
|
||||
* Fix Sourcery A/I comments
|
||||
|
||||
* Check PQC in test case
|
||||
|
||||
* Update ldap/servers/slapd/auth.c
|
||||
|
||||
Co-authored-by: Simon Pichugin <spichugi@redhat.com>
|
||||
|
||||
---------
|
||||
|
||||
Co-authored-by: Simon Pichugin <spichugi@redhat.com>
|
||||
---
|
||||
dirsrvtests/tests/suites/tls/mldsa_test.py | 7 ++++
|
||||
ldap/servers/slapd/auth.c | 45 +++++++++++++++++++++-
|
||||
ldap/servers/slapd/ssl.c | 2 +-
|
||||
3 files changed, 52 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/tls/mldsa_test.py b/dirsrvtests/tests/suites/tls/mldsa_test.py
|
||||
index 2c815088b..d6cbaf662 100644
|
||||
--- a/dirsrvtests/tests/suites/tls/mldsa_test.py
|
||||
+++ b/dirsrvtests/tests/suites/tls/mldsa_test.py
|
||||
@@ -274,6 +274,7 @@ def test_mldsa(topo):
|
||||
"""
|
||||
|
||||
inst = topo.standalone
|
||||
+ inst.config.set('nsslapd-errorlog-level', str(16384 + 8))
|
||||
inst.enable_tls()
|
||||
|
||||
cm = CertmapLegacy(inst)
|
||||
@@ -293,6 +294,9 @@ def test_mldsa(topo):
|
||||
'loginShell': '/bin/false',
|
||||
'description': cert_dn })
|
||||
|
||||
+ inst.config.set("nsslapd-accesslog-logbuffering", "off")
|
||||
+ inst.config.set("nsslapd-errorlog-logbuffering", "off")
|
||||
+
|
||||
tmpdir_kwargs = {}
|
||||
if sys.version_info >= (3, 12):
|
||||
tmpdir_kwargs['delete'] = not DEBUGGING
|
||||
@@ -313,6 +317,9 @@ def test_mldsa(topo):
|
||||
res.check_returncode()
|
||||
# If ldapsearch is successful then defaultnamingcontext should be in res.stdout
|
||||
assert "defaultnamingcontext" in res.stdout
|
||||
+ assert inst.ds_access_log.match('.*RESULT.*dn="uid=test_user,ou=people,dc=example,dc=com".*')
|
||||
+ assert inst.ds_access_log.match('.*TLS.*[PQC].*')
|
||||
+ assert inst.ds_error_log.match('.*check_pqc.*')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
diff --git a/ldap/servers/slapd/auth.c b/ldap/servers/slapd/auth.c
|
||||
index 48e4b7129..9e83408d4 100644
|
||||
--- a/ldap/servers/slapd/auth.c
|
||||
+++ b/ldap/servers/slapd/auth.c
|
||||
@@ -395,6 +395,43 @@ handle_bad_certificate(void *clientData, PRFileDesc *prfd)
|
||||
}
|
||||
|
||||
|
||||
+/*
|
||||
+ * Determine if the connection key exchange is Post Quantum Cryptography aware.
|
||||
+ * This function may need to evolve with NSS as more PQC methods get supported.
|
||||
+ */
|
||||
+static bool
|
||||
+check_pqc(uint64_t connid, SSLChannelInfo *sci)
|
||||
+{
|
||||
+ /*
|
||||
+ * FYI: To interpret the values:
|
||||
+ * KeaType and KeaGroup values are defined in
|
||||
+ * https://github.com/nss-dev/nss/blob/master/lib/ssl/sslt.h
|
||||
+ * Respectively in SSLKEAType and SSLNamedGroup enums
|
||||
+ */
|
||||
+ slapi_log_err(SLAPI_LOG_CONNS, "check_pqc", "conn=%" PRIu64 " TLS keaType=%d keaGroup=%d\n",
|
||||
+ connid, sci->keaType, sci->keaGroup);
|
||||
+#ifdef MAX_ML_DSA_PRIVATE_KEY_LEN
|
||||
+ /* NSS supports PQC (because of the ifdef). Now lets check if the connection uses it */
|
||||
+ /* Check that PQC KeaType is hybrid */
|
||||
+ switch (sci->keaType) {
|
||||
+ case ssl_kea_ecdh_hybrid:
|
||||
+ case ssl_kea_ecdh_hybrid_psk:
|
||||
+ break;
|
||||
+ default:
|
||||
+ return false;
|
||||
+ }
|
||||
+ /* Check that PQC keaGroup is KEM */
|
||||
+ switch (sci->keaGroup) {
|
||||
+ case ssl_grp_kem_secp256r1mlkem768:
|
||||
+ case ssl_grp_kem_secp384r1mlkem1024:
|
||||
+ case ssl_grp_kem_mlkem768x25519:
|
||||
+ case ssl_grp_kem_xyber768d00:
|
||||
+ return true;
|
||||
+ }
|
||||
+#endif
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Get an identity from the client's certificate (if any was sent).
|
||||
*
|
||||
@@ -417,6 +454,7 @@ handle_handshake_done(PRFileDesc *prfd, void *clientData)
|
||||
SSLCipherSuiteInfo cipherInfo;
|
||||
char *subject = NULL;
|
||||
char sslversion[64];
|
||||
+ bool pqc = false;
|
||||
int err = 0;
|
||||
|
||||
if ((slapd_ssl_getChannelInfo(prfd, &channelInfo, sizeof(channelInfo))) != SECSuccess) {
|
||||
@@ -454,7 +492,12 @@ handle_handshake_done(PRFileDesc *prfd, void *clientData)
|
||||
}
|
||||
|
||||
keySize = cipherInfo.effectiveKeyBits;
|
||||
- cipher = slapi_ch_strdup(cipherInfo.symCipherName);
|
||||
+ pqc = check_pqc(conn->c_connid, &channelInfo);
|
||||
+ if (pqc) {
|
||||
+ cipher = slapi_ch_smprintf("%s[PQC]", cipherInfo.symCipherName);
|
||||
+ } else {
|
||||
+ cipher = slapi_ch_strdup(cipherInfo.symCipherName);
|
||||
+ }
|
||||
|
||||
/* If inside an Start TLS operation, perform the privacy level discovery
|
||||
* and if the security degree achieved after the handshake is not reckoned
|
||||
diff --git a/ldap/servers/slapd/ssl.c b/ldap/servers/slapd/ssl.c
|
||||
index 053db5424..7d5db2cdd 100644
|
||||
--- a/ldap/servers/slapd/ssl.c
|
||||
+++ b/ldap/servers/slapd/ssl.c
|
||||
@@ -748,7 +748,7 @@ SSLPLCY_Install(void)
|
||||
if (!slapd_pk11_isFIPS()) {
|
||||
/* Set explicitly PQC algorithm policy if it is not set by default */
|
||||
for (size_t i=0; s == SECSuccess && i < PR_ARRAY_SIZE(oids); i++) {
|
||||
- int oflags = 0;
|
||||
+ PRUint32 oflags = 0;
|
||||
(void) NSS_GetAlgorithmPolicy(oids[i], &oflags);
|
||||
if ((oflags & flags) != flags) {
|
||||
s = NSS_SetAlgorithmPolicy(oids[i], flags, 0);
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@ -0,0 +1,53 @@
|
||||
From 27d3ea211847fa7ae674c5e4dcf485706e4ac591 Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
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 ea744ac1e..80c07382a 100644
|
||||
--- a/ldap/servers/slapd/log.c
|
||||
+++ b/ldap/servers/slapd/log.c
|
||||
@@ -206,8 +206,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;
|
||||
}
|
||||
|
||||
@@ -217,17 +217,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
|
||||
|
||||
195
0022-Issue-7213-MDB_BAD_VALSIZE-error-while-handling-VLV-.patch
Normal file
195
0022-Issue-7213-MDB_BAD_VALSIZE-error-while-handling-VLV-.patch
Normal file
@ -0,0 +1,195 @@
|
||||
From 5ebce22d4214bec5ed94ad84c4448164be99389a Mon Sep 17 00:00:00 2001
|
||||
From: progier389 <progier@redhat.com>
|
||||
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
|
||||
---
|
||||
.../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 f7847ac74..7cdf16a84 100644
|
||||
--- a/dirsrvtests/tests/suites/vlv/regression_test.py
|
||||
+++ b/dirsrvtests/tests/suites/vlv/regression_test.py
|
||||
@@ -1175,6 +1175,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 d320ecbeb..cd797621d 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/db-mdb/mdb_layer.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/db-mdb/mdb_layer.c
|
||||
@@ -2134,10 +2134,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 8f9263f25..f2f882b5a 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
|
||||
|
||||
285
0023-Issue-6753-Port-ticket-47781-test-7210.patch
Normal file
285
0023-Issue-6753-Port-ticket-47781-test-7210.patch
Normal file
@ -0,0 +1,285 @@
|
||||
From 56f1881b5fb0198af4810eeca9e98736c297a2a5 Mon Sep 17 00:00:00 2001
|
||||
From: Lenka Doudova <mirielka@users.noreply.github.com>
|
||||
Date: Tue, 3 Feb 2026 10:28:02 +0100
|
||||
Subject: [PATCH] Issue 6753 - Port ticket 47781 test (#7210)
|
||||
|
||||
Description:
|
||||
Port ticket 47781 test into dirsrvtests/tests/suites/replication/replication_deadlock_test.py
|
||||
|
||||
Relates: #6753
|
||||
Author: Lenka Doudova
|
||||
Assisted by: Cursor
|
||||
Reviewer: Mark Reynolds
|
||||
---
|
||||
.../replication/replication_deadlock_test.py | 129 +++++++++++++++++-
|
||||
dirsrvtests/tests/tickets/ticket47781_test.py | 104 --------------
|
||||
2 files changed, 128 insertions(+), 105 deletions(-)
|
||||
delete mode 100644 dirsrvtests/tests/tickets/ticket47781_test.py
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/replication/replication_deadlock_test.py b/dirsrvtests/tests/suites/replication/replication_deadlock_test.py
|
||||
index 8ddbb43bd..9c122add3 100644
|
||||
--- a/dirsrvtests/tests/suites/replication/replication_deadlock_test.py
|
||||
+++ b/dirsrvtests/tests/suites/replication/replication_deadlock_test.py
|
||||
@@ -15,14 +15,20 @@ with replication data when replication agreements are present.
|
||||
import logging
|
||||
import os
|
||||
import pytest
|
||||
+import ldap
|
||||
|
||||
+from lib389._mapped_object import DSLdapObjects
|
||||
from lib389.topologies import topology_m2 as topo
|
||||
+from lib389.topologies import topology_st
|
||||
from lib389.replica import Replicas, ReplicationManager
|
||||
from lib389.agreement import Agreements
|
||||
from lib389.tasks import ImportTask, ExportTask
|
||||
from lib389.idm.user import UserAccounts
|
||||
from lib389.tombstone import Tombstones
|
||||
-from lib389._constants import DEFAULT_SUFFIX
|
||||
+from lib389.backend import Backends
|
||||
+from lib389._constants import (DEFAULT_SUFFIX, DEFAULT_BENAME, defaultProperties,
|
||||
+ REPLICATION_BIND_DN, REPLICATION_BIND_PW,
|
||||
+ REPLICATION_BIND_METHOD, REPLICATION_TRANSPORT)
|
||||
|
||||
pytestmark = pytest.mark.tier2
|
||||
|
||||
@@ -200,6 +206,127 @@ def test_replication_deadlock_tombstone_search(topo):
|
||||
os.remove(export_ldif)
|
||||
|
||||
|
||||
+def test_replication_deadlock_tombstone_invalid_agreement(topology_st):
|
||||
+ """Test deadlock scenario after importing LDIF with replication data and invalid agreement
|
||||
+
|
||||
+ This test verifies that a deadlock does not occur while searching for tombstones after
|
||||
+ setting up an invalid replication agreement (pointing to a non-existent server)
|
||||
+
|
||||
+ :id: a1b2c3d4-e5f6-4781-9abc-def012345678
|
||||
+ :setup: Standalone instance with replication enabled
|
||||
+ :steps:
|
||||
+ 1. Create a supplier with an invalid replication agreement (port 5555, non-existent server)
|
||||
+ 2. Add two test user entries
|
||||
+ 3. Export LDIF with replication data
|
||||
+ 4. Restart the server
|
||||
+ 5. Import the LDIF back
|
||||
+ 6. Search for tombstone entries with timeout (should not hang/deadlock)
|
||||
+ 7. Cleanup: restore original timeout settings, delete invalid agreement, test entries, and export file
|
||||
+ :expectedresults:
|
||||
+ 1. Invalid replication agreement is created successfully
|
||||
+ 2. Test entries are created successfully
|
||||
+ 3. LDIF export completes successfully
|
||||
+ 4. Server restarts successfully
|
||||
+ 5. LDIF import completes successfully
|
||||
+ 6. Tombstone search completes without deadlock (returns at least one entry; no hang/timeout)
|
||||
+ 7. Cleanup completes successfully
|
||||
+ """
|
||||
+
|
||||
+ standalone = topology_st.standalone
|
||||
+ export_ldif = os.path.join(standalone.get_ldif_dir(), 'export.ldif')
|
||||
+
|
||||
+ # Step 1: Create supplier with invalid replication agreement
|
||||
+ log.info('Creating supplier with invalid replication agreement (port 5555 - non-existent server)')
|
||||
+ repl = ReplicationManager(DEFAULT_SUFFIX)
|
||||
+ repl.create_first_supplier(standalone)
|
||||
+
|
||||
+ replicas = Replicas(standalone)
|
||||
+ replica = replicas.get(DEFAULT_SUFFIX)
|
||||
+ agreements = Agreements(standalone, basedn=replica.dn)
|
||||
+
|
||||
+ # Create agreement with invalid port (non-existent server)
|
||||
+ invalid_agreement = agreements.create(properties={
|
||||
+ 'cn': r'meTo_$host:$port',
|
||||
+ 'nsDS5ReplicaRoot': DEFAULT_SUFFIX,
|
||||
+ 'nsDS5ReplicaHost': standalone.host,
|
||||
+ 'nsDS5ReplicaPort': '5555', # Invalid port - server does not exist
|
||||
+ 'nsDS5ReplicaBindDN': defaultProperties[REPLICATION_BIND_DN],
|
||||
+ 'nsDS5ReplicaBindMethod': defaultProperties[REPLICATION_BIND_METHOD],
|
||||
+ 'nsDS5ReplicaTransportInfo': defaultProperties[REPLICATION_TRANSPORT],
|
||||
+ 'nsDS5ReplicaCredentials': defaultProperties[REPLICATION_BIND_PW]
|
||||
+ })
|
||||
+
|
||||
+ # Step 2: Add two test entries
|
||||
+ log.info('Adding two test entries')
|
||||
+ users = UserAccounts(standalone, DEFAULT_SUFFIX)
|
||||
+
|
||||
+ entry1 = users.create(properties={
|
||||
+ 'uid': 'entry1',
|
||||
+ 'cn': 'entry1',
|
||||
+ 'sn': 'user',
|
||||
+ 'userpassword': 'password',
|
||||
+ 'uidNumber': '1001',
|
||||
+ 'gidNumber': '2001',
|
||||
+ 'homeDirectory': '/home/entry1'
|
||||
+ })
|
||||
+
|
||||
+ entry2 = users.create(properties={
|
||||
+ 'uid': 'entry2',
|
||||
+ 'cn': 'entry2',
|
||||
+ 'sn': 'user',
|
||||
+ 'userpassword': 'password',
|
||||
+ 'uidNumber': '1002',
|
||||
+ 'gidNumber': '2002',
|
||||
+ 'homeDirectory': '/home/entry2'
|
||||
+ })
|
||||
+
|
||||
+ # Step 3: Export LDIF with replication data
|
||||
+ log.info('Exporting LDIF with replication data')
|
||||
+ backends = Backends(standalone)
|
||||
+ export_task = backends.export_ldif(be_names=DEFAULT_BENAME, ldif=export_ldif, replication=True)
|
||||
+ export_task.wait()
|
||||
+
|
||||
+ # Step 4: Restart the server
|
||||
+ log.info('Restarting server')
|
||||
+ standalone.restart()
|
||||
+
|
||||
+ # Step 5: Import the LDIF
|
||||
+ log.info('Importing replication LDIF file')
|
||||
+ import_task = ImportTask(standalone)
|
||||
+ import_task.import_suffix_from_ldif(ldiffile=export_ldif, suffix=DEFAULT_SUFFIX)
|
||||
+ import_task.wait()
|
||||
+
|
||||
+ # Step 6: Search for tombstones with timeout - should not hang/deadlock
|
||||
+ log.info('Searching for tombstone entries (should find entries and not hang)')
|
||||
+ # Save original timeout settings so we can restore them in cleanup
|
||||
+ orig_network_timeout = standalone.get_option(ldap.OPT_NETWORK_TIMEOUT)
|
||||
+ orig_timeout = standalone.get_option(ldap.OPT_TIMEOUT)
|
||||
+ # Set explicit timeouts to detect deadlocks
|
||||
+ standalone.set_option(ldap.OPT_NETWORK_TIMEOUT, 5)
|
||||
+ standalone.set_option(ldap.OPT_TIMEOUT, 5)
|
||||
+
|
||||
+ # Verify at least one tombstone exists and the search does not hang/timeout
|
||||
+ try:
|
||||
+ results = DSLdapObjects(standalone, DEFAULT_SUFFIX).filter('(objectclass=nsTombstone)')
|
||||
+ log.info(f'Found {len(results)} tombstone entries')
|
||||
+ assert len(results) > 0, "Tombstone search should return at least one entry"
|
||||
+ except Exception as e:
|
||||
+ log.error(f"Tombstone search failed with error: {e}")
|
||||
+ pytest.fail(f"Tombstone search failed: {e}")
|
||||
+ finally:
|
||||
+ # Restore original timeout settings
|
||||
+ standalone.set_option(ldap.OPT_NETWORK_TIMEOUT, orig_network_timeout)
|
||||
+ standalone.set_option(ldap.OPT_TIMEOUT, orig_timeout)
|
||||
+ # Cleanup test entries and export file
|
||||
+ log.info('Cleaning up test entries')
|
||||
+ invalid_agreement.delete()
|
||||
+ entry1.delete()
|
||||
+ entry2.delete()
|
||||
+ if os.path.exists(export_ldif):
|
||||
+ os.remove(export_ldif)
|
||||
+
|
||||
+ log.info('Test completed successfully - no deadlock detected')
|
||||
+
|
||||
if __name__ == '__main__':
|
||||
CURRENT_FILE = os.path.realpath(__file__)
|
||||
pytest.main(["-s", CURRENT_FILE])
|
||||
diff --git a/dirsrvtests/tests/tickets/ticket47781_test.py b/dirsrvtests/tests/tickets/ticket47781_test.py
|
||||
deleted file mode 100644
|
||||
index ffb9a5e1a..000000000
|
||||
--- a/dirsrvtests/tests/tickets/ticket47781_test.py
|
||||
+++ /dev/null
|
||||
@@ -1,104 +0,0 @@
|
||||
-# --- BEGIN COPYRIGHT BLOCK ---
|
||||
-# Copyright (C) 2016 Red Hat, Inc.
|
||||
-# All rights reserved.
|
||||
-#
|
||||
-# License: GPL (version 3 or any later version).
|
||||
-# See LICENSE for details.
|
||||
-# --- END COPYRIGHT BLOCK ---
|
||||
-#
|
||||
-import logging
|
||||
-
|
||||
-import pytest
|
||||
-from lib389.tasks import *
|
||||
-from lib389.topologies import topology_st
|
||||
-from lib389.replica import ReplicationManager
|
||||
-
|
||||
-from lib389._constants import (defaultProperties, DEFAULT_SUFFIX, ReplicaRole,
|
||||
- REPLICAID_SUPPLIER_1, REPLICATION_BIND_DN, REPLICATION_BIND_PW,
|
||||
- REPLICATION_BIND_METHOD, REPLICATION_TRANSPORT, RA_NAME,
|
||||
- RA_BINDDN, RA_BINDPW, RA_METHOD, RA_TRANSPORT_PROT)
|
||||
-
|
||||
-pytestmark = pytest.mark.tier2
|
||||
-
|
||||
-log = logging.getLogger(__name__)
|
||||
-
|
||||
-
|
||||
-def test_ticket47781(topology_st):
|
||||
- """
|
||||
- Testing for a deadlock after doing an online import of an LDIF with
|
||||
- replication data. The replication agreement should be invalid.
|
||||
- """
|
||||
-
|
||||
- log.info('Testing Ticket 47781 - Testing for deadlock after importing LDIF with replication data')
|
||||
-
|
||||
- supplier = topology_st.standalone
|
||||
- repl = ReplicationManager(DEFAULT_SUFFIX)
|
||||
- repl.create_first_supplier(supplier)
|
||||
-
|
||||
- properties = {RA_NAME: r'meTo_$host:$port',
|
||||
- RA_BINDDN: defaultProperties[REPLICATION_BIND_DN],
|
||||
- RA_BINDPW: defaultProperties[REPLICATION_BIND_PW],
|
||||
- RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD],
|
||||
- RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
|
||||
- # The agreement should point to a server that does NOT exist (invalid port)
|
||||
- repl_agreement = supplier.agreement.create(suffix=DEFAULT_SUFFIX,
|
||||
- host=supplier.host,
|
||||
- port=5555,
|
||||
- properties=properties)
|
||||
-
|
||||
- #
|
||||
- # add two entries
|
||||
- #
|
||||
- log.info('Adding two entries...')
|
||||
-
|
||||
- supplier.add_s(Entry(('cn=entry1,dc=example,dc=com', {
|
||||
- 'objectclass': 'top person'.split(),
|
||||
- 'sn': 'user',
|
||||
- 'cn': 'entry1'})))
|
||||
-
|
||||
- supplier.add_s(Entry(('cn=entry2,dc=example,dc=com', {
|
||||
- 'objectclass': 'top person'.split(),
|
||||
- 'sn': 'user',
|
||||
- 'cn': 'entry2'})))
|
||||
-
|
||||
- #
|
||||
- # export the replication ldif
|
||||
- #
|
||||
- log.info('Exporting replication ldif...')
|
||||
- args = {EXPORT_REPL_INFO: True}
|
||||
- exportTask = Tasks(supplier)
|
||||
- exportTask.exportLDIF(DEFAULT_SUFFIX, None, "/tmp/export.ldif", args)
|
||||
-
|
||||
- #
|
||||
- # Restart the server
|
||||
- #
|
||||
- log.info('Restarting server...')
|
||||
- supplier.stop()
|
||||
- supplier.start()
|
||||
-
|
||||
- #
|
||||
- # Import the ldif
|
||||
- #
|
||||
- log.info('Import replication LDIF file...')
|
||||
- importTask = Tasks(supplier)
|
||||
- args = {TASK_WAIT: True}
|
||||
- importTask.importLDIF(DEFAULT_SUFFIX, None, "/tmp/export.ldif", args)
|
||||
- os.remove("/tmp/export.ldif")
|
||||
-
|
||||
- #
|
||||
- # Search for tombstones - we should not hang/timeout
|
||||
- #
|
||||
- log.info('Search for tombstone entries(should find one and not hang)...')
|
||||
- supplier.set_option(ldap.OPT_NETWORK_TIMEOUT, 5)
|
||||
- supplier.set_option(ldap.OPT_TIMEOUT, 5)
|
||||
- entries = supplier.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, 'objectclass=nsTombstone')
|
||||
- if not entries:
|
||||
- log.fatal('Search failed to find any entries.')
|
||||
- assert PR_False
|
||||
-
|
||||
-
|
||||
-if __name__ == '__main__':
|
||||
- # Run isolated
|
||||
- # -s for DEBUG mode
|
||||
- CURRENT_FILE = os.path.realpath(__file__)
|
||||
- pytest.main("-s %s" % CURRENT_FILE)
|
||||
--
|
||||
2.52.0
|
||||
|
||||
1645
0024-Issue-7194-Repl-Log-Analysis-Add-CSN-propagation-det.patch
Normal file
1645
0024-Issue-7194-Repl-Log-Analysis-Add-CSN-propagation-det.patch
Normal file
File diff suppressed because it is too large
Load Diff
265
0025-Issue-6753-Port-ticket-48896-test.patch
Normal file
265
0025-Issue-6753-Port-ticket-48896-test.patch
Normal file
@ -0,0 +1,265 @@
|
||||
From 603f4deb1e87c819c1830f58c7be4281d981fbbd Mon Sep 17 00:00:00 2001
|
||||
From: Lenka Doudova <lryznaro@redhat.com>
|
||||
Date: Mon, 2 Feb 2026 16:46:52 +0100
|
||||
Subject: [PATCH] Issue 6753 - Port ticket 48896 test
|
||||
|
||||
Description:
|
||||
Port ticket 48896 test into dirsrvtests/tests/suites/password/pwdPolicy_token_test.py
|
||||
|
||||
Relates: #6753
|
||||
Author: Lenka Doudova
|
||||
Assisted by: Cursor
|
||||
Reviewer: Mark Reynolds
|
||||
---
|
||||
.../suites/password/pwdPolicy_token_test.py | 68 ++++++---
|
||||
dirsrvtests/tests/tickets/ticket48896_test.py | 139 ------------------
|
||||
2 files changed, 44 insertions(+), 163 deletions(-)
|
||||
delete mode 100644 dirsrvtests/tests/tickets/ticket48896_test.py
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/password/pwdPolicy_token_test.py b/dirsrvtests/tests/suites/password/pwdPolicy_token_test.py
|
||||
index ae4eb300f..a3caaa230 100644
|
||||
--- a/dirsrvtests/tests/suites/password/pwdPolicy_token_test.py
|
||||
+++ b/dirsrvtests/tests/suites/password/pwdPolicy_token_test.py
|
||||
@@ -15,6 +15,7 @@ from lib389._constants import *
|
||||
from lib389.idm.user import UserAccounts
|
||||
from lib389.idm.organizationalunit import OrganizationalUnits
|
||||
from lib389.topologies import topology_st as topo
|
||||
+from lib389.idm.directorymanager import DirectoryManager
|
||||
|
||||
pytestmark = pytest.mark.tier1
|
||||
|
||||
@@ -25,14 +26,13 @@ else:
|
||||
logging.getLogger(__name__).setLevel(logging.INFO)
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
-USER_DN = 'uid=Test_user1,ou=People,dc=example,dc=com'
|
||||
USER_ACI = '(targetattr="userpassword")(version 3.0; acl "pwp test"; allow (all) userdn="ldap:///self";)'
|
||||
-TOKEN = 'test_user1'
|
||||
+TOKEN = 'test_user123'
|
||||
|
||||
user_properties = {
|
||||
- 'uid': 'Test_user1',
|
||||
- 'cn': 'test_user1',
|
||||
- 'sn': 'test_user1',
|
||||
+ 'uid': 'Test_user123',
|
||||
+ 'cn': 'test_user123',
|
||||
+ 'sn': 'test_user123',
|
||||
'uidNumber': '1001',
|
||||
'gidNumber': '2001',
|
||||
'userpassword': PASSWORD,
|
||||
@@ -59,28 +59,48 @@ def test_token_lengths(topo):
|
||||
:id: dae9d916-2a03-4707-b454-9e901d295b13
|
||||
:setup: Standalone instance
|
||||
:steps:
|
||||
- 1. Test token length rejects password of the same length as rdn value
|
||||
+ 1. Create user, setup global password policy
|
||||
+ 2. Bind as user, change password to 'Abcd012+'
|
||||
+ 3. Bind as user with 'Abcd012+', attempt changes to 'user', 'us123', 'Tuse!1234', 'Tuse!0987', 'Tabc!1234'
|
||||
+ 4. For each passwordMinTokenLength 4, 6, 10: change settings, rebind as user, attempt password with token of that length from TOKEN
|
||||
+ 5. Cleanup - delete user
|
||||
:expectedresults:
|
||||
- 1. Passwords are rejected
|
||||
+ 1. User created, password policy enabled and set
|
||||
+ 2. Success
|
||||
+ 3. All attempts fail with CONSTRAINT_VIOLATION
|
||||
+ 4. All attempts fail with CONSTRAINT_VIOLATION
|
||||
+ 5. User successfully deleted
|
||||
"""
|
||||
user = pwd_setup(topo)
|
||||
- for length in ['4', '6', '10']:
|
||||
- topo.standalone.simple_bind_s(DN_DM, PASSWORD)
|
||||
- topo.standalone.config.set('passwordMinTokenLength', length)
|
||||
- topo.standalone.simple_bind_s(USER_DN, PASSWORD)
|
||||
- time.sleep(1)
|
||||
-
|
||||
- try:
|
||||
- passwd = TOKEN[:int(length)]
|
||||
- log.info("Testing password len {} token ({})".format(length, passwd))
|
||||
- user.replace('userpassword', passwd)
|
||||
- log.fatal('Password incorrectly allowed!')
|
||||
- assert False
|
||||
- except ldap.CONSTRAINT_VIOLATION as e:
|
||||
- log.info('Password correctly rejected: ' + str(e))
|
||||
- except ldap.LDAPError as e:
|
||||
- log.fatal('Unexpected failure ' + str(e))
|
||||
- assert False
|
||||
+ dm = DirectoryManager(topo.standalone)
|
||||
+
|
||||
+ try:
|
||||
+ # Verify that the user can change their password
|
||||
+ user.rebind(PASSWORD)
|
||||
+ user.replace('userpassword', 'Abcd012+')
|
||||
+
|
||||
+ # Verify that the default password policy is enforced
|
||||
+ user.rebind('Abcd012+')
|
||||
+ for new_password in ['user', 'us123', 'Tuse!1234', 'Tuse!0987', 'Tabc!1234']:
|
||||
+ log.info(f"Testing password {new_password}")
|
||||
+ with pytest.raises(ldap.CONSTRAINT_VIOLATION):
|
||||
+ user.replace('userpassword', new_password)
|
||||
+
|
||||
+ # Verify that the password policy is enforced for different token lengths
|
||||
+ for length in ['4', '6', '10']:
|
||||
+ dm.rebind(PASSWORD)
|
||||
+ topo.standalone.config.set('passwordMinTokenLength', length)
|
||||
+ user.rebind('Abcd012+')
|
||||
+ time.sleep(1)
|
||||
+
|
||||
+ with pytest.raises(ldap.CONSTRAINT_VIOLATION):
|
||||
+ passwd = TOKEN[:int(length)]
|
||||
+ log.info("Testing password len {} token ({})".format(length, passwd))
|
||||
+ user.replace('userpassword', passwd)
|
||||
+
|
||||
+ finally:
|
||||
+ # Cleanup
|
||||
+ user.delete()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
diff --git a/dirsrvtests/tests/tickets/ticket48896_test.py b/dirsrvtests/tests/tickets/ticket48896_test.py
|
||||
deleted file mode 100644
|
||||
index a1897589e..000000000
|
||||
--- a/dirsrvtests/tests/tickets/ticket48896_test.py
|
||||
+++ /dev/null
|
||||
@@ -1,139 +0,0 @@
|
||||
-# --- BEGIN COPYRIGHT BLOCK ---
|
||||
-# Copyright (C) 2016 Red Hat, Inc.
|
||||
-# All rights reserved.
|
||||
-#
|
||||
-# License: GPL (version 3 or any later version).
|
||||
-# See LICENSE for details.
|
||||
-# --- END COPYRIGHT BLOCK ---
|
||||
-#
|
||||
-import pytest
|
||||
-from lib389.tasks import *
|
||||
-from lib389.utils import *
|
||||
-from lib389.topologies import topology_st
|
||||
-
|
||||
-from lib389._constants import DEFAULT_SUFFIX, DN_DM, PASSWORD
|
||||
-
|
||||
-# Skip on older versions
|
||||
-pytestmark = [pytest.mark.tier2,
|
||||
- pytest.mark.skipif(ds_is_older('1.3.6'), reason="Not implemented")]
|
||||
-
|
||||
-logging.getLogger(__name__).setLevel(logging.DEBUG)
|
||||
-log = logging.getLogger(__name__)
|
||||
-
|
||||
-CONFIG_DN = 'cn=config'
|
||||
-UID = 'buser123'
|
||||
-TESTDN = 'uid=%s,' % UID + DEFAULT_SUFFIX
|
||||
-
|
||||
-
|
||||
-def check_attr_val(topology_st, dn, attr, expected):
|
||||
- try:
|
||||
- centry = topology_st.standalone.search_s(dn, ldap.SCOPE_BASE, 'cn=*')
|
||||
- if centry:
|
||||
- val = centry[0].getValue(attr)
|
||||
- if val == expected:
|
||||
- log.info('Default value of %s is %s' % (attr, expected))
|
||||
- else:
|
||||
- log.info('Default value of %s is not %s, but %s' % (attr, expected, val))
|
||||
- assert False
|
||||
- else:
|
||||
- log.fatal('Failed to get %s' % dn)
|
||||
- assert False
|
||||
- except ldap.LDAPError as e:
|
||||
- log.fatal('Failed to search ' + dn + ': ' + e.message['desc'])
|
||||
- assert False
|
||||
-
|
||||
-
|
||||
-def replace_pw(server, curpw, newpw, expstr, rc):
|
||||
- log.info('Binding as {%s, %s}' % (TESTDN, curpw))
|
||||
- server.simple_bind_s(TESTDN, curpw)
|
||||
-
|
||||
- hit = 0
|
||||
- log.info('Replacing password: %s -> %s, which should %s' % (curpw, newpw, expstr))
|
||||
- try:
|
||||
- server.modify_s(TESTDN, [(ldap.MOD_REPLACE, 'userPassword', ensure_bytes(newpw))])
|
||||
- except Exception as e:
|
||||
- log.info("Exception (expected): %s" % type(e).__name__)
|
||||
- hit = 1
|
||||
- assert isinstance(e, rc)
|
||||
-
|
||||
- if (0 != rc) and (0 == hit):
|
||||
- log.info('Expected to fail with %s, but passed' % rc.__name__)
|
||||
- assert False
|
||||
-
|
||||
- log.info('PASSED')
|
||||
-
|
||||
-
|
||||
-def test_ticket48896(topology_st):
|
||||
- """
|
||||
- """
|
||||
- log.info('Testing Ticket 48896 - Default Setting for passwordMinTokenLength does not work')
|
||||
-
|
||||
- log.info("Setting global password policy with password syntax.")
|
||||
- topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
|
||||
- topology_st.standalone.modify_s(CONFIG_DN, [(ldap.MOD_REPLACE, 'passwordCheckSyntax', b'on'),
|
||||
- (ldap.MOD_REPLACE, 'nsslapd-pwpolicy-local', b'on')])
|
||||
-
|
||||
- config = topology_st.standalone.search_s(CONFIG_DN, ldap.SCOPE_BASE, 'cn=*')
|
||||
- mintokenlen = config[0].getValue('passwordMinTokenLength')
|
||||
- history = config[0].getValue('passwordInHistory')
|
||||
-
|
||||
- log.info('Default passwordMinTokenLength == %s' % mintokenlen)
|
||||
- log.info('Default passwordInHistory == %s' % history)
|
||||
-
|
||||
- log.info('Adding a user.')
|
||||
- curpw = 'password'
|
||||
- topology_st.standalone.add_s(Entry((TESTDN,
|
||||
- {'objectclass': "top person organizationalPerson inetOrgPerson".split(),
|
||||
- 'cn': 'test user',
|
||||
- 'sn': 'user',
|
||||
- 'userPassword': curpw})))
|
||||
-
|
||||
- newpw = 'Abcd012+'
|
||||
- exp = 'be ok'
|
||||
- rc = 0
|
||||
- replace_pw(topology_st.standalone, curpw, newpw, exp, rc)
|
||||
-
|
||||
- curpw = 'Abcd012+'
|
||||
- newpw = 'user'
|
||||
- exp = 'fail'
|
||||
- rc = ldap.CONSTRAINT_VIOLATION
|
||||
- replace_pw(topology_st.standalone, curpw, newpw, exp, rc)
|
||||
-
|
||||
- curpw = 'Abcd012+'
|
||||
- newpw = UID
|
||||
- exp = 'fail'
|
||||
- rc = ldap.CONSTRAINT_VIOLATION
|
||||
- replace_pw(topology_st.standalone, curpw, newpw, exp, rc)
|
||||
-
|
||||
- curpw = 'Abcd012+'
|
||||
- newpw = 'Tuse!1234'
|
||||
- exp = 'fail'
|
||||
- rc = ldap.CONSTRAINT_VIOLATION
|
||||
- replace_pw(topology_st.standalone, curpw, newpw, exp, rc)
|
||||
-
|
||||
- curpw = 'Abcd012+'
|
||||
- newpw = 'Tuse!0987'
|
||||
- exp = 'fail'
|
||||
- rc = ldap.CONSTRAINT_VIOLATION
|
||||
- replace_pw(topology_st.standalone, curpw, newpw, exp, rc)
|
||||
-
|
||||
- curpw = 'Abcd012+'
|
||||
- newpw = 'Tabc!1234'
|
||||
- exp = 'fail'
|
||||
- rc = ldap.CONSTRAINT_VIOLATION
|
||||
- replace_pw(topology_st.standalone, curpw, newpw, exp, rc)
|
||||
-
|
||||
- curpw = 'Abcd012+'
|
||||
- newpw = 'Direc+ory389'
|
||||
- exp = 'be ok'
|
||||
- rc = 0
|
||||
- replace_pw(topology_st.standalone, curpw, newpw, exp, rc)
|
||||
-
|
||||
- log.info('SUCCESS')
|
||||
-
|
||||
-
|
||||
-if __name__ == '__main__':
|
||||
- # Run isolated
|
||||
- # -s for DEBUG mode
|
||||
- CURRENT_FILE = os.path.realpath(__file__)
|
||||
- pytest.main("-s %s" % CURRENT_FILE)
|
||||
--
|
||||
2.52.0
|
||||
|
||||
30
0026-Issue-6810-Fix-PAM-PTA-test-7219.patch
Normal file
30
0026-Issue-6810-Fix-PAM-PTA-test-7219.patch
Normal file
@ -0,0 +1,30 @@
|
||||
From ff44acffcc67c985148c4df280685a674fec010a Mon Sep 17 00:00:00 2001
|
||||
From: Akshay Adhikari <aadhikar@redhat.com>
|
||||
Date: Thu, 5 Feb 2026 15:19:58 +0530
|
||||
Subject: [PATCH] Issue 6810 - Fix PAM PTA test (#7219)
|
||||
|
||||
Description: Fix the PAM PTA test by add missing yield in fixture.
|
||||
|
||||
Relates: #6810
|
||||
|
||||
Reviewed by: @jchapma
|
||||
---
|
||||
dirsrvtests/tests/suites/plugins/pam_pta_test.py | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/plugins/pam_pta_test.py b/dirsrvtests/tests/suites/plugins/pam_pta_test.py
|
||||
index 484c1bc80..e55a7f7ee 100644
|
||||
--- a/dirsrvtests/tests/suites/plugins/pam_pta_test.py
|
||||
+++ b/dirsrvtests/tests/suites/plugins/pam_pta_test.py
|
||||
@@ -104,6 +104,8 @@ def pam_service_ldapserver(migrated_child_config):
|
||||
f.write(line + "\n")
|
||||
os.chmod(pam_file, 0o644)
|
||||
|
||||
+ yield
|
||||
+
|
||||
except Exception as e:
|
||||
if os.path.exists(backup_file):
|
||||
# Restore backup on error
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@ -0,0 +1,57 @@
|
||||
From 2a0ed9c267fc56a14e84ad53ffaeb0b822594367 Mon Sep 17 00:00:00 2001
|
||||
From: Akshay Adhikari <aadhikar@redhat.com>
|
||||
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 759edb80d..e859789b3 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
|
||||
@@ -102,6 +102,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;
|
||||
|
||||
@@ -1181,6 +1182,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) {
|
||||
@@ -1363,12 +1366,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
|
||||
|
||||
1492
0028-Issue-6951-Dynamic-Certificate-refresh-phase-4-Updat.patch
Normal file
1492
0028-Issue-6951-Dynamic-Certificate-refresh-phase-4-Updat.patch
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,93 @@
|
||||
From d5a83e8f2ccd0c9d11792f026947c4785996b4a6 Mon Sep 17 00:00:00 2001
|
||||
From: James Chapman <jachapma@redhat.com>
|
||||
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 c843a4b24..a49e378c3 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 = 25 if is_fips() else 20 # Reserve descriptor constant (higher in FIPS mode)
|
||||
- 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
|
||||
|
||||
@ -0,0 +1,94 @@
|
||||
From 9bfbec8c4aad1c698fd80b3086e11f06fd9df26d Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
Date: Mon, 9 Feb 2026 13:15:44 +0100
|
||||
Subject: [PATCH] Issue 7178 - Bundled jemalloc fails to build with GCC 15
|
||||
(#7216)
|
||||
|
||||
Description:
|
||||
Update spec file to fix build failures on Fedora Rawhide
|
||||
|
||||
Fixes: https://github.com/389ds/389-ds-base/issues/7178
|
||||
|
||||
Reviewed by: @progier389, @droideck (Thanks!)
|
||||
---
|
||||
rpm.mk | 1 +
|
||||
rpm/389-ds-base.spec.in | 10 +++++-----
|
||||
rpm/jemalloc-5.3.0_throw_bad_alloc.patch | 12 ++++++++++++
|
||||
3 files changed, 18 insertions(+), 5 deletions(-)
|
||||
create mode 100644 rpm/jemalloc-5.3.0_throw_bad_alloc.patch
|
||||
|
||||
diff --git a/rpm.mk b/rpm.mk
|
||||
index f91011814..372cee5a6 100644
|
||||
--- a/rpm.mk
|
||||
+++ b/rpm.mk
|
||||
@@ -143,6 +143,7 @@ srpmdistdir:
|
||||
rpmbuildprep:
|
||||
cp dist/sources/$(TARBALL) $(RPMBUILD)/SOURCES/
|
||||
cp rpm/$(PACKAGE)-* $(RPMBUILD)/SOURCES/
|
||||
+ cp rpm/jemalloc-5.3.0_throw_bad_alloc.patch $(RPMBUILD)/SOURCES/
|
||||
if [ $(BUNDLE_JEMALLOC) -eq 1 ]; then \
|
||||
cp dist/sources/$(JEMALLOC_TARBALL) $(RPMBUILD)/SOURCES/ ; \
|
||||
fi
|
||||
diff --git a/rpm/389-ds-base.spec.in b/rpm/389-ds-base.spec.in
|
||||
index 51bfd7e77..dc8c75dac 100644
|
||||
--- a/rpm/389-ds-base.spec.in
|
||||
+++ b/rpm/389-ds-base.spec.in
|
||||
@@ -152,8 +152,8 @@ BuildRequires: python%{python3_pkgversion}-devel
|
||||
# For cockpit
|
||||
%if %{with cockpit}
|
||||
BuildRequires: rsync
|
||||
-BuildRequires: npm
|
||||
-BuildRequires: nodejs
|
||||
+BuildRequires: /usr/bin/npm
|
||||
+BuildRequires: /usr/bin/node
|
||||
%endif
|
||||
|
||||
# END BUILD REQUIRES
|
||||
@@ -188,9 +188,7 @@ Requires: %{name}-robdb-libs = %{version}-%{release}
|
||||
Requires: libdb
|
||||
%endif
|
||||
%endif
|
||||
-Requires: lmdb
|
||||
-# This picks up libperl.so as a Requires, so we add this versioned one
|
||||
-Requires: perl(:MODULE_COMPAT_%(eval "`%{__perl} -V:version`"; echo $version))
|
||||
+Requires: lmdb-libs
|
||||
# Needed by logconv.pl
|
||||
%if %{without libbdb_ro}
|
||||
%if %{without bundle_libdb}
|
||||
@@ -217,6 +215,7 @@ Source0: %{name}-%{version}.tar.bz2
|
||||
Source2: %{name}-devel.README
|
||||
%if %{with bundle_jemalloc}
|
||||
Source3: https://github.com/jemalloc/%{jemalloc_name}/releases/download/%{jemalloc_ver}/%{jemalloc_name}-%{jemalloc_ver}.tar.bz2
|
||||
+Source5: jemalloc-5.3.0_throw_bad_alloc.patch
|
||||
%endif
|
||||
%if %{with bundle_libdb}
|
||||
Source4: https://fedorapeople.org/groups/389ds/libdb-5.3.28-59.tar.bz2
|
||||
@@ -434,6 +433,7 @@ COCKPIT_FLAGS="--disable-cockpit"
|
||||
|
||||
# Build jemalloc
|
||||
pushd ../%{jemalloc_name}-%{jemalloc_ver}
|
||||
+patch -p1 -F3 < %{SOURCE5}
|
||||
%configure \
|
||||
--libdir=%{_libdir}/%{pkgname}/lib \
|
||||
--bindir=%{_libdir}/%{pkgname}/bin \
|
||||
diff --git a/rpm/jemalloc-5.3.0_throw_bad_alloc.patch b/rpm/jemalloc-5.3.0_throw_bad_alloc.patch
|
||||
new file mode 100644
|
||||
index 000000000..685e6968c
|
||||
--- /dev/null
|
||||
+++ b/rpm/jemalloc-5.3.0_throw_bad_alloc.patch
|
||||
@@ -0,0 +1,12 @@
|
||||
+diff --git a/src/jemalloc_cpp.cpp b/src/jemalloc_cpp.cpp
|
||||
+index fffd6aee..5a682991 100644
|
||||
+--- a/src/jemalloc_cpp.cpp
|
||||
++++ b/src/jemalloc_cpp.cpp
|
||||
+@@ -93,7 +93,7 @@ handleOOM(std::size_t size, bool nothrow) {
|
||||
+ }
|
||||
+
|
||||
+ if (ptr == nullptr && !nothrow)
|
||||
+- std::__throw_bad_alloc();
|
||||
++ throw std::bad_alloc();
|
||||
+ return ptr;
|
||||
+ }
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@ -0,0 +1,71 @@
|
||||
From fb4254a97fe0da25064d2f6296705c9e1810ffda Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
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=<optimized out>, conn=<optimized out>)
|
||||
at ldap/servers/slapd/connection.c:672
|
||||
#15 connection_threadmain (arg=<optimized out>) 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=<optimized out>) 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
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
From 850cb2ae142b1dc31081387e8e997699668e70f4 Mon Sep 17 00:00:00 2001
|
||||
From 3938942a5418add83616b1413f3070d394c30a7f Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
Date: Thu, 5 Feb 2026 12:17:06 +0100
|
||||
Subject: [PATCH] Issue 7223 - Revert index scan limits for system indexes
|
||||
@ -9,28 +9,28 @@ c6f458b42 Issue 7189 - DSBLE0007 generates incorrect remediation commands for sc
|
||||
|
||||
Relates: https://github.com/389ds/389-ds-base/issues/7223
|
||||
|
||||
Reviewed by: @progier389, @tbordaz (Thanks!)
|
||||
Reviewed by: @progier389, @tbordaz, @droideck (Thanks!)
|
||||
---
|
||||
.../tests/suites/config/config_test.py | 27 +---
|
||||
.../healthcheck/health_system_indexes_test.py | 135 +-----------------
|
||||
.../healthcheck/health_system_indexes_test.py | 136 +-----------------
|
||||
.../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 | 108 ++------------
|
||||
ldap/servers/slapd/back-ldbm/instance.c | 104 +++-----------
|
||||
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, 39 insertions(+), 368 deletions(-)
|
||||
11 files changed, 40 insertions(+), 364 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/config/config_test.py b/dirsrvtests/tests/suites/config/config_test.py
|
||||
index 430176602..bbe13d248 100644
|
||||
index cbb8875fa..2c7d949d0 100644
|
||||
--- a/dirsrvtests/tests/suites/config/config_test.py
|
||||
+++ b/dirsrvtests/tests/suites/config/config_test.py
|
||||
@@ -514,19 +514,17 @@ def test_ndn_cache_enabled(topo):
|
||||
topo.standalone.config.set('nsslapd-ndn-cache-max-size', 'invalid_value')
|
||||
@@ -706,19 +706,17 @@ def test_ndn_cache_size_enforcement(topo, request):
|
||||
|
||||
request.addfinalizer(fin)
|
||||
|
||||
-def test_require_index(topo, request):
|
||||
+def test_require_index(topo):
|
||||
@ -50,7 +50,7 @@ index 430176602..bbe13d248 100644
|
||||
"""
|
||||
|
||||
# Set the config
|
||||
@@ -537,10 +535,6 @@ def test_require_index(topo, request):
|
||||
@@ -729,10 +727,6 @@ def test_require_index(topo, request):
|
||||
|
||||
db_cfg = DatabaseConfig(topo.standalone)
|
||||
db_cfg.set([('nsslapd-idlistscanlimit', '100')])
|
||||
@ -61,7 +61,7 @@ index 430176602..bbe13d248 100644
|
||||
|
||||
users = UserAccounts(topo.standalone, DEFAULT_SUFFIX)
|
||||
for i in range(101):
|
||||
@@ -551,15 +545,10 @@ def test_require_index(topo, request):
|
||||
@@ -743,15 +737,10 @@ def test_require_index(topo, request):
|
||||
with pytest.raises(ldap.UNWILLING_TO_PERFORM):
|
||||
raw_objects.filter("(description=test*)")
|
||||
|
||||
@ -78,7 +78,7 @@ index 430176602..bbe13d248 100644
|
||||
"""Ensure internal operations require indexed attributes
|
||||
|
||||
:id: 22b94f30-59e3-4f27-89a1-c4f4be036f7f
|
||||
@@ -591,10 +580,6 @@ def test_require_internal_index(topo, request):
|
||||
@@ -782,10 +771,6 @@ def test_require_internal_index(topo, request):
|
||||
# Create a bunch of users
|
||||
db_cfg = DatabaseConfig(topo.standalone)
|
||||
db_cfg.set([('nsslapd-idlistscanlimit', '100')])
|
||||
@ -89,7 +89,7 @@ index 430176602..bbe13d248 100644
|
||||
users = UserAccounts(topo.standalone, DEFAULT_SUFFIX)
|
||||
for i in range(102, 202):
|
||||
users.create_test_user(uid=i)
|
||||
@@ -619,12 +604,6 @@ def test_require_internal_index(topo, request):
|
||||
@@ -810,12 +795,6 @@ def test_require_internal_index(topo, request):
|
||||
with pytest.raises(ldap.UNWILLING_TO_PERFORM):
|
||||
user.delete()
|
||||
|
||||
@ -100,23 +100,24 @@ index 430176602..bbe13d248 100644
|
||||
-
|
||||
-
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Run isolated
|
||||
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 f25de4214..842f7e8dd 100644
|
||||
index 486fad44b..140845a33 100644
|
||||
--- a/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py
|
||||
+++ b/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py
|
||||
@@ -172,8 +172,7 @@ def test_missing_parentid(topology_st, log_buffering_enabled):
|
||||
@@ -172,9 +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"],
|
||||
- idlistscanlimit=['limit=5000 type=eq flags=AND'])
|
||||
- standalone.restart()
|
||||
+ 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)
|
||||
@@ -261,8 +260,7 @@ def test_usn_plugin_missing_entryusn(topology_st, usn_plugin_enabled, log_buffer
|
||||
@@ -263,8 +261,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")
|
||||
@ -126,7 +127,7 @@ index f25de4214..842f7e8dd 100644
|
||||
|
||||
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)
|
||||
@@ -406,132 +404,6 @@ def test_retrocl_plugin_missing_matching_rule(topology_st, retrocl_plugin_enable
|
||||
@@ -408,132 +405,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)
|
||||
|
||||
|
||||
@ -259,7 +260,7 @@ index f25de4214..842f7e8dd 100644
|
||||
def test_multiple_missing_indexes(topology_st, log_buffering_enabled):
|
||||
"""Check if healthcheck returns DSBLE0007 code when multiple system indexes are missing
|
||||
|
||||
@@ -572,8 +444,7 @@ def test_multiple_missing_indexes(topology_st, log_buffering_enabled):
|
||||
@@ -574,8 +445,7 @@ def test_multiple_missing_indexes(topology_st, log_buffering_enabled):
|
||||
|
||||
log.info("Re-add the missing system indexes")
|
||||
backend = Backends(standalone).get("userRoot")
|
||||
@ -267,13 +268,13 @@ index f25de4214..842f7e8dd 100644
|
||||
- idlistscanlimit=['limit=5000 type=eq flags=AND'])
|
||||
+ 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)
|
||||
diff --git a/dirsrvtests/tests/suites/paged_results/paged_results_test.py b/dirsrvtests/tests/suites/paged_results/paged_results_test.py
|
||||
index 8835be8fa..1ed11c891 100644
|
||||
index 61d6702da..1bb94b53a 100644
|
||||
--- a/dirsrvtests/tests/suites/paged_results/paged_results_test.py
|
||||
+++ b/dirsrvtests/tests/suites/paged_results/paged_results_test.py
|
||||
@@ -317,19 +317,19 @@ def test_search_success(topology_st, create_user, page_size, users_num):
|
||||
@@ -306,19 +306,19 @@ def test_search_success(topology_st, create_user, page_size, users_num):
|
||||
del_users(users_list)
|
||||
|
||||
|
||||
@ -300,7 +301,7 @@ index 8835be8fa..1ed11c891 100644
|
||||
"""Verify that search with a simple paged results control
|
||||
throws expected exceptoins when corresponding limits are
|
||||
exceeded.
|
||||
@@ -351,15 +351,6 @@ def test_search_limits_fail(topology_st, create_user, page_size, users_num,
|
||||
@@ -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)
|
||||
@ -316,7 +317,7 @@ index 8835be8fa..1ed11c891 100644
|
||||
conf_param_dict = {attr_name: attr_value}
|
||||
search_flt = r'(uid=test*)'
|
||||
searchreq_attrlist = ['dn', 'sn']
|
||||
@@ -412,8 +403,6 @@ def test_search_limits_fail(topology_st, create_user, page_size, users_num,
|
||||
@@ -402,8 +393,6 @@ def test_search_limits_fail(topology_st, create_user, page_size, users_num,
|
||||
else:
|
||||
break
|
||||
finally:
|
||||
@ -326,10 +327,10 @@ index 8835be8fa..1ed11c891 100644
|
||||
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 cde30cedd..d17ec644b 100644
|
||||
index b187c26bc..e23e7ff43 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/back-ldbm.h
|
||||
+++ b/ldap/servers/slapd/back-ldbm/back-ldbm.h
|
||||
@@ -554,7 +554,6 @@ struct ldbminfo
|
||||
@@ -583,7 +583,6 @@ struct ldbminfo
|
||||
int li_mode;
|
||||
int li_lookthroughlimit;
|
||||
int li_allidsthreshold;
|
||||
@ -338,10 +339,10 @@ index cde30cedd..d17ec644b 100644
|
||||
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 63f0196c1..30fa09ebb 100644
|
||||
index 0ab82948c..a5004be19 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/index.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/index.c
|
||||
@@ -999,8 +999,6 @@ index_read_ext_allids(
|
||||
@@ -997,8 +997,6 @@ index_read_ext_allids(
|
||||
}
|
||||
if (pb) {
|
||||
slapi_pblock_get(pb, SLAPI_SEARCH_IS_AND, &is_and);
|
||||
@ -351,7 +352,7 @@ index 63f0196c1..30fa09ebb 100644
|
||||
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 29643f7e4..6098e04fc 100644
|
||||
index 2a6e8cbb8..2b71cd4f7 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/instance.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/instance.c
|
||||
@@ -16,7 +16,7 @@
|
||||
@ -363,7 +364,7 @@ index 29643f7e4..6098e04fc 100644
|
||||
|
||||
|
||||
/* Creates and initializes a new ldbm_instance structure.
|
||||
@@ -127,7 +127,7 @@ done:
|
||||
@@ -126,7 +126,7 @@ done:
|
||||
* Take a bunch of strings, and create a index config entry
|
||||
*/
|
||||
Slapi_Entry *
|
||||
@ -372,7 +373,7 @@ index 29643f7e4..6098e04fc 100644
|
||||
{
|
||||
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
|
||||
@@ -167,11 +167,6 @@ ldbm_instance_init_config_entry(char *cn_val, char *val1, char *val2, char *val3
|
||||
slapi_entry_add_values(e, "nsMatchingRule", vals);
|
||||
}
|
||||
|
||||
@ -384,7 +385,7 @@ index 29643f7e4..6098e04fc 100644
|
||||
return e;
|
||||
}
|
||||
|
||||
@@ -185,60 +180,8 @@ ldbm_instance_create_default_indexes(backend *be)
|
||||
@@ -184,60 +179,8 @@ ldbm_instance_create_default_indexes(backend *be)
|
||||
{
|
||||
Slapi_Entry *e;
|
||||
ldbm_instance *inst = (ldbm_instance *)be->be_instance_info;
|
||||
@ -445,20 +446,14 @@ index 29643f7e4..6098e04fc 100644
|
||||
|
||||
/*
|
||||
* Always index (entrydn or entryrdn), parentid, objectclass,
|
||||
@@ -247,59 +190,47 @@ ldbm_instance_create_default_indexes(backend *be)
|
||||
@@ -245,48 +188,42 @@ ldbm_instance_create_default_indexes(backend *be)
|
||||
* since they are used by some searches, replication and the
|
||||
* 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);
|
||||
}
|
||||
- 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);
|
||||
|
||||
- ainfo_get(be, (char *)LDBM_PARENTID_STR, &ai);
|
||||
- /* Check if the attrinfo is actually for parentid, not a fallback to .default */
|
||||
@ -469,28 +464,24 @@ index 29643f7e4..6098e04fc 100644
|
||||
- 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);
|
||||
+ 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);
|
||||
+ 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("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(LDBM_NUMSUBORDINATES_STR, "pres", 0, 0, 0, 0, 0);
|
||||
- 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);
|
||||
|
||||
-#if 0 /* don't need copiedfrom */
|
||||
- e = ldbm_instance_init_config_entry("copiedfrom","pres",0 ,0);
|
||||
- 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);
|
||||
-#endif
|
||||
|
||||
- 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);
|
||||
@ -515,35 +506,33 @@ index 29643f7e4..6098e04fc 100644
|
||||
attr_index_config(be, "ldbm index init", 0, e, 1, 0, NULL);
|
||||
slapi_entry_free(e);
|
||||
|
||||
@@ -308,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);
|
||||
}
|
||||
|
||||
@@ -294,18 +231,9 @@ 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);
|
||||
- }
|
||||
-
|
||||
- slapi_ch_free_string(&ancestorid_indexes_limit);
|
||||
- slapi_ch_free_string(&parentid_indexes_limit);
|
||||
-
|
||||
+ 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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_config.c b/ldap/servers/slapd/back-ldbm/ldbm_config.c
|
||||
index f8d8f7474..b7bceabf2 100644
|
||||
index c24e3d766..6a2ce4c27 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/ldbm_config.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/ldbm_config.c
|
||||
@@ -366,35 +366,6 @@ ldbm_config_allidsthreshold_set(void *arg, void *value, char *errorbuf __attribu
|
||||
@@ -385,35 +385,6 @@ ldbm_config_allidsthreshold_set(void *arg, void *value, char *errorbuf __attribu
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -579,7 +568,7 @@ index f8d8f7474..b7bceabf2 100644
|
||||
static void *
|
||||
ldbm_config_pagedallidsthreshold_get(void *arg)
|
||||
{
|
||||
@@ -974,7 +945,6 @@ static config_info ldbm_config[] = {
|
||||
@@ -1094,7 +1065,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},
|
||||
@ -588,7 +577,7 @@ index f8d8f7474..b7bceabf2 100644
|
||||
{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 004e5ea7e..48446193e 100644
|
||||
index 29a3426ab..e69bfeedf 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
|
||||
@ -619,10 +608,10 @@ index bae2a64b9..38e7368e1 100644
|
||||
if (eBuf) {
|
||||
PR_smprintf_free(eBuf);
|
||||
diff --git a/src/lib389/lib389/backend.py b/src/lib389/lib389/backend.py
|
||||
index 3cea0df36..4babf6850 100644
|
||||
index 274d45abe..f3dbe7c92 100644
|
||||
--- a/src/lib389/lib389/backend.py
|
||||
+++ b/src/lib389/lib389/backend.py
|
||||
@@ -539,10 +539,11 @@ class Backend(DSLdapObject):
|
||||
@@ -645,10 +645,11 @@ class Backend(DSLdapObject):
|
||||
indexes = self.get_indexes()
|
||||
|
||||
# Default system indexes taken from ldap/servers/slapd/back-ldbm/instance.c
|
||||
@ -637,7 +626,7 @@ index 3cea0df36..4babf6850 100644
|
||||
'objectClass': {'types': ['eq'], 'matching_rule': None},
|
||||
'aci': {'types': ['pres'], 'matching_rule': None},
|
||||
'nscpEntryDN': {'types': ['eq'], 'matching_rule': None},
|
||||
@@ -599,17 +600,14 @@ class Backend(DSLdapObject):
|
||||
@@ -705,17 +706,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}"
|
||||
@ -656,7 +645,7 @@ index 3cea0df36..4babf6850 100644
|
||||
|
||||
# Normalize to lowercase for comparison
|
||||
actual_types = [t.lower() for t in actual_types]
|
||||
@@ -624,31 +622,16 @@ class Backend(DSLdapObject):
|
||||
@@ -730,31 +728,16 @@ class Backend(DSLdapObject):
|
||||
remediation_commands.append(cmd)
|
||||
reindex_attrs.add(attr_name)
|
||||
|
||||
@ -693,7 +682,7 @@ index 3cea0df36..4babf6850 100644
|
||||
|
||||
except Exception as e:
|
||||
self._log.debug(f"_lint_system_indexes - Error checking index {attr_name}: {e}")
|
||||
@@ -879,13 +862,12 @@ class Backend(DSLdapObject):
|
||||
@@ -993,13 +976,12 @@ class Backend(DSLdapObject):
|
||||
return
|
||||
raise ValueError("Can not delete index because it does not exist")
|
||||
|
||||
@ -708,7 +697,7 @@ index 3cea0df36..4babf6850 100644
|
||||
:param reindex - If set to True then index the attribute after creating it.
|
||||
"""
|
||||
|
||||
@@ -915,15 +897,6 @@ class Backend(DSLdapObject):
|
||||
@@ -1029,15 +1011,6 @@ class Backend(DSLdapObject):
|
||||
# Only add if there are actually rules present in the list.
|
||||
if len(mrs) > 0:
|
||||
props['nsMatchingRule'] = mrs
|
||||
@ -724,7 +713,7 @@ index 3cea0df36..4babf6850 100644
|
||||
new_index.create(properties=props, basedn="cn=index," + self._dn)
|
||||
|
||||
if reindex:
|
||||
@@ -1230,7 +1203,6 @@ class DatabaseConfig(DSLdapObject):
|
||||
@@ -1349,7 +1322,6 @@ class DatabaseConfig(DSLdapObject):
|
||||
'nsslapd-lookthroughlimit',
|
||||
'nsslapd-mode',
|
||||
'nsslapd-idlistscanlimit',
|
||||
@ -733,7 +722,7 @@ index 3cea0df36..4babf6850 100644
|
||||
'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 d57cb9433..4dc67d563 100644
|
||||
index 9772e39d4..68efa795c 100644
|
||||
--- a/src/lib389/lib389/cli_conf/backend.py
|
||||
+++ b/src/lib389/lib389/cli_conf/backend.py
|
||||
@@ -39,7 +39,6 @@ arg_to_attr = {
|
||||
@ -744,7 +733,7 @@ index d57cb9433..4dc67d563 100644
|
||||
'directory': 'nsslapd-directory',
|
||||
'dbcachesize': 'nsslapd-dbcachesize',
|
||||
'logdirectory': 'nsslapd-db-logdirectory',
|
||||
@@ -588,21 +587,6 @@ def backend_set_index(inst, basedn, log, args):
|
||||
@@ -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')
|
||||
|
||||
@ -766,7 +755,7 @@ index d57cb9433..4dc67d563 100644
|
||||
if args.reindex:
|
||||
be.reindex(attrs=[args.attr])
|
||||
log.info("Index successfully updated")
|
||||
@@ -924,9 +908,6 @@ def create_parser(subparsers):
|
||||
@@ -963,9 +947,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')
|
||||
@ -776,7 +765,7 @@ index d57cb9433..4dc67d563 100644
|
||||
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')
|
||||
|
||||
@@ -1053,7 +1034,6 @@ def create_parser(subparsers):
|
||||
@@ -1092,7 +1073,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')
|
||||
@ -1,4 +1,4 @@
|
||||
From c6e2911dca08aac40e98999b48019eac72cc74a6 Mon Sep 17 00:00:00 2001
|
||||
From 4c44e4c522afc0f5401754f29a47645889e21aca Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
Date: Thu, 5 Feb 2026 12:17:06 +0100
|
||||
Subject: [PATCH] Issue 7223 - Add upgrade function to remove
|
||||
@ -15,17 +15,17 @@ automatically on server startup and removes the attribute if found.
|
||||
|
||||
Relates: https://github.com/389ds/389-ds-base/issues/7223
|
||||
|
||||
Reviewed by: @progier389, @tbordaz (Thanks!)
|
||||
Reviewed by: @progier389, @tbordaz, @droideck (Thanks!)
|
||||
---
|
||||
.../healthcheck/health_system_indexes_test.py | 52 +++++
|
||||
ldap/servers/slapd/upgrade.c | 210 ++++++++++++++++++
|
||||
2 files changed, 262 insertions(+)
|
||||
.../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 842f7e8dd..72a04fdab 100644
|
||||
index 140845a33..aea88e0e2 100644
|
||||
--- a/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py
|
||||
+++ b/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py
|
||||
@@ -451,6 +451,58 @@ def test_multiple_missing_indexes(topology_st, log_buffering_enabled):
|
||||
@@ -453,6 +453,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)
|
||||
|
||||
|
||||
@ -85,12 +85,12 @@ index 842f7e8dd..72a04fdab 100644
|
||||
# Run isolated
|
||||
# -s for DEBUG mode
|
||||
diff --git a/ldap/servers/slapd/upgrade.c b/ldap/servers/slapd/upgrade.c
|
||||
index 2f124afaf..074c15e3c 100644
|
||||
index b02e37ed6..dcd16940b 100644
|
||||
--- a/ldap/servers/slapd/upgrade.c
|
||||
+++ b/ldap/servers/slapd/upgrade.c
|
||||
@@ -22,8 +22,218 @@
|
||||
* or altered.
|
||||
*/
|
||||
@@ -330,6 +330,107 @@ upgrade_remove_subtree_rename(void)
|
||||
return UPGRADE_SUCCESS;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Remove nsIndexIDListScanLimit from parentid index configuration.
|
||||
@ -193,120 +193,20 @@ index 2f124afaf..074c15e3c 100644
|
||||
+ return uresult;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Check if parentid 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 <instance> backend index set --add-mr integerOrderingMatch --attr %s %s && "
|
||||
+ "dsconf <instance> 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)
|
||||
{
|
||||
/*
|
||||
* Check if parentid/ancestorid indexes are missing the integerOrderingMatch
|
||||
* matching rule.
|
||||
@@ -649,6 +750,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;
|
||||
+ }
|
||||
+
|
||||
return UPGRADE_SUCCESS;
|
||||
}
|
||||
if (upgrade_check_id_index_matching_rule() != UPGRADE_SUCCESS) {
|
||||
return UPGRADE_FAILURE;
|
||||
}
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
From 1669e65b36d543fb69ef5503e5072ea37e9a0e19 Mon Sep 17 00:00:00 2001
|
||||
From 41670301ccad5558296a3380a4974f7c0d4baede Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
Date: Mon, 9 Feb 2026 14:12:18 +0100
|
||||
Date: Thu, 5 Feb 2026 12:17:06 +0100
|
||||
Subject: [PATCH] Issue 7223 - Add upgrade function to remove ancestorid index
|
||||
config entry
|
||||
|
||||
@ -13,7 +13,7 @@ Also remove ancestorid index configuration from template-dse.ldif.
|
||||
|
||||
Relates: https://github.com/389ds/389-ds-base/issues/7223
|
||||
|
||||
Reviewed by: @progier389, @tbordaz (Thanks!)
|
||||
Reviewed by: @progier389, @tbordaz, @droideck (Thanks!)
|
||||
---
|
||||
.../healthcheck/health_system_indexes_test.py | 85 +++++++++++
|
||||
ldap/ldif/template-dse.ldif.in | 8 --
|
||||
@ -21,10 +21,10 @@ Reviewed by: @progier389, @tbordaz (Thanks!)
|
||||
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 72a04fdab..db5d13bf8 100644
|
||||
index aea88e0e2..eb727b902 100644
|
||||
--- a/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py
|
||||
+++ b/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py
|
||||
@@ -502,6 +502,91 @@ def test_upgrade_removes_parentid_scanlimit(topology_st):
|
||||
@@ -504,6 +504,91 @@ def test_upgrade_removes_parentid_scanlimit(topology_st):
|
||||
|
||||
log.info("Upgrade successfully removed nsIndexIDListScanLimit from parentid index")
|
||||
|
||||
@ -117,10 +117,10 @@ index 72a04fdab..db5d13bf8 100644
|
||||
if __name__ == "__main__":
|
||||
# Run isolated
|
||||
diff --git a/ldap/ldif/template-dse.ldif.in b/ldap/ldif/template-dse.ldif.in
|
||||
index c2754adf8..2ddaf5fb3 100644
|
||||
index bb8c71cd9..b6ab6f6c6 100644
|
||||
--- a/ldap/ldif/template-dse.ldif.in
|
||||
+++ b/ldap/ldif/template-dse.ldif.in
|
||||
@@ -973,14 +973,6 @@ cn: aci
|
||||
@@ -998,14 +998,6 @@ cn: aci
|
||||
nssystemindex: true
|
||||
nsindextype: pres
|
||||
|
||||
@ -136,10 +136,10 @@ index c2754adf8..2ddaf5fb3 100644
|
||||
objectclass: top
|
||||
objectclass: nsIndex
|
||||
diff --git a/ldap/servers/slapd/upgrade.c b/ldap/servers/slapd/upgrade.c
|
||||
index 074c15e3c..aa51e72d2 100644
|
||||
index dcd16940b..6b1b012da 100644
|
||||
--- a/ldap/servers/slapd/upgrade.c
|
||||
+++ b/ldap/servers/slapd/upgrade.c
|
||||
@@ -123,6 +123,126 @@ upgrade_remove_index_scanlimit(void)
|
||||
@@ -431,6 +431,126 @@ upgrade_remove_index_scanlimit(void)
|
||||
return uresult;
|
||||
}
|
||||
|
||||
@ -264,9 +264,9 @@ index 074c15e3c..aa51e72d2 100644
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Check if parentid indexes are missing the integerOrderingMatch
|
||||
* Check if parentid/ancestorid indexes are missing the integerOrderingMatch
|
||||
* matching rule.
|
||||
@@ -137,7 +257,7 @@ upgrade_check_id_index_matching_rule(void)
|
||||
@@ -445,7 +565,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)";
|
||||
@ -275,7 +275,7 @@ index 074c15e3c..aa51e72d2 100644
|
||||
upgrade_status uresult = UPGRADE_SUCCESS;
|
||||
|
||||
/* Search for all backend instances */
|
||||
@@ -151,8 +271,9 @@ upgrade_check_id_index_matching_rule(void)
|
||||
@@ -459,8 +579,9 @@ upgrade_check_id_index_matching_rule(void)
|
||||
|
||||
if (backends) {
|
||||
for (size_t be_idx = 0; backends[be_idx] != NULL; be_idx++) {
|
||||
@ -286,7 +286,7 @@ index 074c15e3c..aa51e72d2 100644
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -161,8 +282,8 @@ upgrade_check_id_index_matching_rule(void)
|
||||
@@ -469,8 +590,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;
|
||||
@ -297,7 +297,7 @@ index 074c15e3c..aa51e72d2 100644
|
||||
char *idx_filter = "(objectclass=nsIndex)";
|
||||
PRBool has_matching_rule = PR_FALSE;
|
||||
|
||||
@@ -231,6 +352,10 @@ upgrade_server(void)
|
||||
@@ -754,6 +875,10 @@ upgrade_server(void)
|
||||
return UPGRADE_FAILURE;
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
From f6dd2d6dc94290c85d221951b34792443bb08d80 Mon Sep 17 00:00:00 2001
|
||||
From a260b50aa0c8e6c5b8b3fd0b164e9bbc4a15983f Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
Date: Thu, 5 Feb 2026 12:17:06 +0100
|
||||
Subject: [PATCH] Issue 7223 - Detect and log index ordering mismatch during
|
||||
@ -10,16 +10,16 @@ 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 (Thanks!)
|
||||
Reviewed by: @progier389, @tbordaz, @droideck (Thanks!)
|
||||
---
|
||||
ldap/servers/slapd/back-ldbm/instance.c | 269 ++++++++++++++++++++++++
|
||||
1 file changed, 269 insertions(+)
|
||||
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 6098e04fc..388dd6efb 100644
|
||||
index 2b71cd4f7..17bfc09a0 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/instance.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/instance.c
|
||||
@@ -248,6 +248,273 @@ ldbm_instance_create_default_indexes(backend *be)
|
||||
@@ -239,6 +239,266 @@ ldbm_instance_create_default_indexes(backend *be)
|
||||
}
|
||||
|
||||
|
||||
@ -107,10 +107,10 @@ index 6098e04fc..388dd6efb 100644
|
||||
+{
|
||||
+ ldbm_instance *inst = (ldbm_instance *)be->be_instance_info;
|
||||
+ struct attrinfo *ai = NULL;
|
||||
+ DB *db = NULL;
|
||||
+ DBC *dbc = NULL;
|
||||
+ DBT key;
|
||||
+ DBT data;
|
||||
+ 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 */
|
||||
@ -147,7 +147,7 @@ index 6098e04fc..388dd6efb 100644
|
||||
+ }
|
||||
+
|
||||
+ /* Create a cursor to read keys */
|
||||
+ ret = db->cursor(db, NULL, &dbc, 0);
|
||||
+ 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",
|
||||
@ -156,10 +156,8 @@ index 6098e04fc..388dd6efb 100644
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ memset(&key, 0, sizeof(key));
|
||||
+ memset(&data, 0, sizeof(data));
|
||||
+ key.flags = DB_DBT_MALLOC;
|
||||
+ data.flags = DB_DBT_MALLOC;
|
||||
+ dblayer_value_init(be, &key);
|
||||
+ dblayer_value_init(be, &data);
|
||||
+
|
||||
+ /*
|
||||
+ * Read up to 100 unique keys and check their ordering.
|
||||
@ -173,12 +171,7 @@ index 6098e04fc..388dd6efb 100644
|
||||
+ while (key_count < 100) {
|
||||
+ ID current_id;
|
||||
+
|
||||
+ slapi_ch_free(&(key.data));
|
||||
+ slapi_ch_free(&(data.data));
|
||||
+ key.size = 0;
|
||||
+ data.size = 0;
|
||||
+
|
||||
+ ret = dbc->c_get(dbc, &key, &data, first_key ? DB_FIRST : DB_NEXT_NODUP);
|
||||
+ 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 */
|
||||
@ -229,9 +222,9 @@ index 6098e04fc..388dd6efb 100644
|
||||
+ }
|
||||
+
|
||||
+ /* Close the cursor and free values */
|
||||
+ slapi_ch_free(&(key.data));
|
||||
+ slapi_ch_free(&(data.data));
|
||||
+ dbc->c_close(dbc);
|
||||
+ 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);
|
||||
@ -293,7 +286,7 @@ index 6098e04fc..388dd6efb 100644
|
||||
/* Starts a backend instance */
|
||||
int
|
||||
ldbm_instance_start(backend *be)
|
||||
@@ -316,6 +583,8 @@ ldbm_instance_startall(struct ldbminfo *li)
|
||||
@@ -308,6 +568,8 @@ ldbm_instance_startall(struct ldbminfo *li)
|
||||
ldbm_instance_register_modify_callback(inst);
|
||||
vlv_init(inst);
|
||||
slapi_mtn_be_started(inst->inst_be);
|
||||
@ -1,4 +1,4 @@
|
||||
From 99470a4befbea7eda777b9096337e29113e1ddda Mon Sep 17 00:00:00 2001
|
||||
From 9e5f22c94b822fcd3decb8f98ce2eb383cc16a7c Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
Date: Thu, 5 Feb 2026 12:17:06 +0100
|
||||
Subject: [PATCH] Issue 7223 - Add dsctl index-check command for offline index
|
||||
@ -15,19 +15,19 @@ upgrade.
|
||||
|
||||
Relates: https://github.com/389ds/389-ds-base/issues/7223
|
||||
|
||||
Reviewed by: @progier389, @tbordaz (Thanks!)
|
||||
Reviewed by: @progier389, @tbordaz, @droideck (Thanks!)
|
||||
---
|
||||
.../healthcheck/health_system_indexes_test.py | 593 ++++++++++++++++++
|
||||
rpm/389-ds-base.spec.in | 40 +-
|
||||
rpm/389-ds-base.spec.in | 51 +-
|
||||
src/lib389/lib389/cli_ctl/dbtasks.py | 402 ++++++++++++
|
||||
src/lib389/lib389/dseldif.py | 56 +-
|
||||
4 files changed, 1085 insertions(+), 6 deletions(-)
|
||||
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 db5d13bf8..ce86239e5 100644
|
||||
index eb727b902..dd42cd197 100644
|
||||
--- a/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py
|
||||
+++ b/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py
|
||||
@@ -588,6 +588,599 @@ def test_upgrade_removes_ancestorid_index_config(topology_st):
|
||||
@@ -590,6 +590,599 @@ def test_upgrade_removes_ancestorid_index_config(topology_st):
|
||||
log.info(f"Idempotency verified - ancestorid still absent after second restart (got exception: {e})")
|
||||
|
||||
|
||||
@ -628,47 +628,70 @@ index db5d13bf8..ce86239e5 100644
|
||||
# Run isolated
|
||||
# -s for DEBUG mode
|
||||
diff --git a/rpm/389-ds-base.spec.in b/rpm/389-ds-base.spec.in
|
||||
index b8c14cd14..16b8d14c5 100644
|
||||
index dc8c75dac..0e0e28285 100644
|
||||
--- a/rpm/389-ds-base.spec.in
|
||||
+++ b/rpm/389-ds-base.spec.in
|
||||
@@ -507,7 +507,45 @@ if ! getent passwd $USERNAME >/dev/null ; then
|
||||
@@ -628,42 +628,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}"
|
||||
instbase="%{_sysconfdir}/%{pkgname}"
|
||||
+instances=""
|
||||
+ninst=0
|
||||
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
|
||||
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"
|
||||
instances="$instances $inst"
|
||||
+ /bin/systemctl stop "$inst" >> "$output" 2>&1 || :
|
||||
+ else
|
||||
else
|
||||
- echo instance $inst is not running >> $output 2>&1 || :
|
||||
+ echo "instance $inst is not running" >> "$output" 2>&1 || :
|
||||
+ fi
|
||||
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
|
||||
done
|
||||
+
|
||||
+if [ $ninst -eq 0 ] ; then
|
||||
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
|
||||
+
|
||||
fi
|
||||
|
||||
+# Restart previously running instances
|
||||
+for inst in $instances ; do
|
||||
+ echo "starting instance $inst" >> "$output" 2>&1 || :
|
||||
@ -1109,19 +1132,14 @@ index 856639672..16da966d1 100644
|
||||
+ 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 3104a7b6f..49efc5dcb 100644
|
||||
index d12c6424c..7834d9468 100644
|
||||
--- a/src/lib389/lib389/dseldif.py
|
||||
+++ b/src/lib389/lib389/dseldif.py
|
||||
@@ -118,11 +118,19 @@ class DSEldif(DSLint):
|
||||
with open(self.path, "w") as file_dse:
|
||||
file_dse.write("".join(self._contents))
|
||||
@@ -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 globalSubstitute(self, strfrom, strto):
|
||||
+ for i in range(0, len(self._contents)-1):
|
||||
+ self._contents[i] = self._contents[i].replace(strfrom, strto)
|
||||
+ self._update()
|
||||
+
|
||||
+ def _find_attr(self, entry_dn, attr, lower=False):
|
||||
"""Find all attribute values and indexes under a given entry
|
||||
|
||||
@ -1133,7 +1151,7 @@ index 3104a7b6f..49efc5dcb 100644
|
||||
"""
|
||||
|
||||
entry_dn_i = self._contents.index("dn: {}\n".format(entry_dn.lower()))
|
||||
@@ -139,7 +147,11 @@ class DSEldif(DSLint):
|
||||
@@ -146,7 +149,11 @@ class DSEldif(DSLint):
|
||||
|
||||
# Find the attribute
|
||||
for line in entry_slice:
|
||||
@ -1146,7 +1164,7 @@ index 3104a7b6f..49efc5dcb 100644
|
||||
attr_value = line.split(" ", 1)[1][:-1]
|
||||
attr_data.update({entry_slice.index(line): attr_value})
|
||||
|
||||
@@ -148,7 +160,7 @@ class DSEldif(DSLint):
|
||||
@@ -155,7 +162,7 @@ class DSEldif(DSLint):
|
||||
|
||||
return entry_dn_i, attr_data
|
||||
|
||||
@ -1155,7 +1173,7 @@ index 3104a7b6f..49efc5dcb 100644
|
||||
"""Return attribute values under a given entry
|
||||
|
||||
:param entry_dn: a DN of entry we want to get attribute from
|
||||
@@ -156,11 +168,13 @@ class DSEldif(DSLint):
|
||||
@@ -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
|
||||
@ -1171,7 +1189,7 @@ index 3104a7b6f..49efc5dcb 100644
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
@@ -183,6 +197,38 @@ class DSEldif(DSLint):
|
||||
@@ -190,6 +199,38 @@ class DSEldif(DSLint):
|
||||
|
||||
return indexes
|
||||
|
||||
62
0037-Issue-7230-Regression-in-healtcheck-NssCheck-7235.patch
Normal file
62
0037-Issue-7230-Regression-in-healtcheck-NssCheck-7235.patch
Normal file
@ -0,0 +1,62 @@
|
||||
From 3ebb30a65e2b40610301e5feedda0408ac9f3631 Mon Sep 17 00:00:00 2001
|
||||
From: James Chapman <jachapma@redhat.com>
|
||||
Date: Tue, 10 Feb 2026 10:35:48 +0000
|
||||
Subject: [PATCH] Issue 7230 - Regression in healtcheck NssCheck (#7235)
|
||||
|
||||
Description:
|
||||
Dynamic Certificate lib389 updadates modified get_cert_details() to
|
||||
return a dict instead of tuple format. _lint_certificate_expiration() and
|
||||
tls.list_cas() still assumes tuple style access.
|
||||
|
||||
Fix:
|
||||
Update method to use dict key.
|
||||
|
||||
Fixes: https://github.com/389ds/389-ds-base/issues/7230
|
||||
|
||||
Co-authored-by: @flo-renaud
|
||||
|
||||
Reviewed by: @droideck (Thank you)
|
||||
---
|
||||
src/lib389/lib389/cli_ctl/tls.py | 4 ++--
|
||||
src/lib389/lib389/nss_ssl.py | 4 ++--
|
||||
2 files changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/src/lib389/lib389/cli_ctl/tls.py b/src/lib389/lib389/cli_ctl/tls.py
|
||||
index 8834f5758..91f1f3a59 100644
|
||||
--- a/src/lib389/lib389/cli_ctl/tls.py
|
||||
+++ b/src/lib389/lib389/cli_ctl/tls.py
|
||||
@@ -25,9 +25,9 @@ def list_client_cas(inst, log, args):
|
||||
|
||||
def list_cas(inst, log, args):
|
||||
tls = NssSsl(dirsrv=inst)
|
||||
- # This turns an array of [('CA', 'C,,')]
|
||||
+ # Returns a list of cert dicts, eg {'cn': 'nickname', etc}
|
||||
for c in tls.list_ca_certs():
|
||||
- log.info(c[0])
|
||||
+ log.info(c['cn'])
|
||||
|
||||
|
||||
def show_cert(inst, log, args):
|
||||
diff --git a/src/lib389/lib389/nss_ssl.py b/src/lib389/lib389/nss_ssl.py
|
||||
index 764434166..fae65d19c 100644
|
||||
--- a/src/lib389/lib389/nss_ssl.py
|
||||
+++ b/src/lib389/lib389/nss_ssl.py
|
||||
@@ -91,13 +91,13 @@ class NssSsl(DSLint):
|
||||
if diff_date < timedelta(days=0):
|
||||
# Expired
|
||||
report = copy.deepcopy(DSCERTLE0002)
|
||||
- report['detail'] = report['detail'].replace('CERT', cert[0])
|
||||
+ report['detail'] = report['detail'].replace('CERT', cert['cn'])
|
||||
report['check'] = f'tls:certificate_expiration'
|
||||
yield report
|
||||
elif diff_date < timedelta(days=30):
|
||||
# Expiring within 30 days
|
||||
report = copy.deepcopy(DSCERTLE0001)
|
||||
- report['detail'] = report['detail'].replace('CERT', cert[0])
|
||||
+ report['detail'] = report['detail'].replace('CERT', cert['cn'])
|
||||
report['check'] = f'tls:certificate_expiration'
|
||||
yield report
|
||||
|
||||
--
|
||||
2.52.0
|
||||
|
||||
1225
0038-Issue-3555-UI-Fix-audit-issue-with-npm-isaacs-brace-.patch
Normal file
1225
0038-Issue-3555-UI-Fix-audit-issue-with-npm-isaacs-brace-.patch
Normal file
File diff suppressed because it is too large
Load Diff
97
0039-Issue-7221-CI-tests-fix-some-flaky-tests.patch
Normal file
97
0039-Issue-7221-CI-tests-fix-some-flaky-tests.patch
Normal file
@ -0,0 +1,97 @@
|
||||
From ae4a39474df08d56064453f0fb6c2272e6c3dc8b Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
Date: Fri, 6 Feb 2026 15:13:30 -0500
|
||||
Subject: [PATCH] Issue 7221 - CI tests - fix some flaky tests
|
||||
|
||||
Description:
|
||||
|
||||
Try to harden some of the flaky tests with sleeps and more relaxed contraints
|
||||
|
||||
Relates: https://github.com/389ds/389-ds-base/issues/7221
|
||||
|
||||
Reviewed by: spichugi(Thanks!)
|
||||
---
|
||||
dirsrvtests/tests/suites/acl/acivattr_test.py | 7 +++++--
|
||||
dirsrvtests/tests/suites/import/regression_test.py | 2 +-
|
||||
.../suites/replication/wait_for_async_feature_test.py | 2 +-
|
||||
dirsrvtests/tests/suites/retrocl/basic_test.py | 2 +-
|
||||
4 files changed, 8 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/acl/acivattr_test.py b/dirsrvtests/tests/suites/acl/acivattr_test.py
|
||||
index d55eea023..efe2d5ef1 100644
|
||||
--- a/dirsrvtests/tests/suites/acl/acivattr_test.py
|
||||
+++ b/dirsrvtests/tests/suites/acl/acivattr_test.py
|
||||
@@ -1,12 +1,12 @@
|
||||
# --- BEGIN COPYRIGHT BLOCK ---
|
||||
-# Copyright (C) 2019 Red Hat, Inc.
|
||||
+# 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 pytest, os, ldap
|
||||
+import pytest, os, ldap, time
|
||||
from lib389._constants import DEFAULT_SUFFIX, PW_DM
|
||||
from lib389.idm.user import UserAccount
|
||||
from lib389.idm.organization import Organization
|
||||
@@ -190,6 +190,8 @@ def test_positive(topo, _add_user, aci_of_user, user, entry, aci):
|
||||
"""
|
||||
# set aci
|
||||
Domain(topo.standalone, DNBASE).set("aci", aci)
|
||||
+ time.sleep(.5)
|
||||
+
|
||||
# create connection
|
||||
conn = UserAccount(topo.standalone, user).bind(PW_DM)
|
||||
# according to the aci , user will be able to change description
|
||||
@@ -242,6 +244,7 @@ def test_negative(topo, _add_user, aci_of_user, user, entry, aci):
|
||||
"""
|
||||
# set aci
|
||||
Domain(topo.standalone, DNBASE).set("aci", aci)
|
||||
+ time.sleep(.5)
|
||||
# create connection
|
||||
conn = UserAccount(topo.standalone, user).bind(PW_DM)
|
||||
# according to the aci , user will not be able to change description
|
||||
diff --git a/dirsrvtests/tests/suites/import/regression_test.py b/dirsrvtests/tests/suites/import/regression_test.py
|
||||
index 0e3ba1930..25a7f359d 100644
|
||||
--- a/dirsrvtests/tests/suites/import/regression_test.py
|
||||
+++ b/dirsrvtests/tests/suites/import/regression_test.py
|
||||
@@ -687,7 +687,7 @@ def test_ldif2db_after_backend_create(topo, verify):
|
||||
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) < 15
|
||||
+ assert abs(import_time_1 - import_time_2) < 20
|
||||
|
||||
|
||||
def test_ldif_missing_suffix_entry(topo, request, verify):
|
||||
diff --git a/dirsrvtests/tests/suites/replication/wait_for_async_feature_test.py b/dirsrvtests/tests/suites/replication/wait_for_async_feature_test.py
|
||||
index c5ab585e4..84ce1ca2b 100644
|
||||
--- a/dirsrvtests/tests/suites/replication/wait_for_async_feature_test.py
|
||||
+++ b/dirsrvtests/tests/suites/replication/wait_for_async_feature_test.py
|
||||
@@ -26,7 +26,7 @@ log = logging.getLogger(__name__)
|
||||
installation1_prefix = None
|
||||
|
||||
# Expected minimum and maximum number of async result in usual cases
|
||||
-USUAL_MIN_AP = 3
|
||||
+USUAL_MIN_AP = 2
|
||||
USUAL_MAX_AP = 11
|
||||
|
||||
@pytest.fixture(params=[(None, (USUAL_MIN_AP, USUAL_MAX_AP)),
|
||||
diff --git a/dirsrvtests/tests/suites/retrocl/basic_test.py b/dirsrvtests/tests/suites/retrocl/basic_test.py
|
||||
index b53a60851..2fce72049 100644
|
||||
--- a/dirsrvtests/tests/suites/retrocl/basic_test.py
|
||||
+++ b/dirsrvtests/tests/suites/retrocl/basic_test.py
|
||||
@@ -492,7 +492,7 @@ def test_retrocl_trimming_entries(topology_st):
|
||||
if inst.searchErrorsLog("trim_changelog: removed "):
|
||||
log.info(f'Trimming detected after {attempt * 6} seconds')
|
||||
break
|
||||
-
|
||||
+
|
||||
log.info('Verify trimming occurred by checking error log')
|
||||
assert inst.searchErrorsLog("trim_changelog: removed ")
|
||||
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@ -0,0 +1,56 @@
|
||||
From 58f5d129496cc8b4271daf5d0cd3ab31e8b926a8 Mon Sep 17 00:00:00 2001
|
||||
From: Akshay Adhikari <aadhikar@redhat.com>
|
||||
Date: Thu, 12 Feb 2026 12:47:23 +0530
|
||||
Subject: [PATCH] Issue 7233 - test_produce_division_by_zero fails with
|
||||
IsADirectoryError in conftest.py (#7234)
|
||||
|
||||
Description: glob('/*/*') matches directories causing open() to fail.
|
||||
|
||||
Fixes: #7233
|
||||
|
||||
Reviewed by: @droideck (Thanks!)
|
||||
---
|
||||
dirsrvtests/conftest.py | 2 ++
|
||||
.../suites/disk_monitoring/disk_monitoring_divide_test.py | 7 ++++---
|
||||
2 files changed, 6 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/conftest.py b/dirsrvtests/conftest.py
|
||||
index 0db6045f4..19b34c4a4 100644
|
||||
--- a/dirsrvtests/conftest.py
|
||||
+++ b/dirsrvtests/conftest.py
|
||||
@@ -126,6 +126,8 @@ def pytest_runtest_makereport(item, call):
|
||||
text = asan_report.read()
|
||||
extra.append(pytest_html.extras.text(text, name=os.path.basename(f)))
|
||||
for f in glob.glob(f'{p.log_dir.split("/slapd",1)[0]}/*/*'):
|
||||
+ if not os.path.isfile(f):
|
||||
+ continue
|
||||
if f.endswith('gz'):
|
||||
with gzip.open(f, 'rb') as dirsrv_log:
|
||||
text = dirsrv_log.read()
|
||||
diff --git a/dirsrvtests/tests/suites/disk_monitoring/disk_monitoring_divide_test.py b/dirsrvtests/tests/suites/disk_monitoring/disk_monitoring_divide_test.py
|
||||
index 9d952f93a..3e52e7c6b 100644
|
||||
--- a/dirsrvtests/tests/suites/disk_monitoring/disk_monitoring_divide_test.py
|
||||
+++ b/dirsrvtests/tests/suites/disk_monitoring/disk_monitoring_divide_test.py
|
||||
@@ -31,15 +31,16 @@ def create_dummy_mount(topology_st, request):
|
||||
log.info('Create dummy mount')
|
||||
for cmd in cmds:
|
||||
log.info('Command used : %s' % cmd)
|
||||
- subprocess.Popen(cmd, shell=True)
|
||||
+ subprocess.run(cmd, shell=True)
|
||||
|
||||
def fin():
|
||||
cmds = ['umount /var/log/dirsrv/slapd-{}/tmp'.format(topology_st.standalone.serverid),
|
||||
+ 'rmdir /var/log/dirsrv/slapd-{}/tmp'.format(topology_st.standalone.serverid),
|
||||
'setenforce 1']
|
||||
|
||||
for cmd in cmds:
|
||||
- log.info('Command used : %s' % cmds)
|
||||
- subprocess.Popen(cmd, shell=True)
|
||||
+ log.info('Command used : %s' % cmd)
|
||||
+ subprocess.run(cmd, shell=True)
|
||||
|
||||
request.addfinalizer(fin)
|
||||
|
||||
--
|
||||
2.52.0
|
||||
|
||||
226
0041-Issue-7241-Drop-dateutil-7242.patch
Normal file
226
0041-Issue-7241-Drop-dateutil-7242.patch
Normal file
@ -0,0 +1,226 @@
|
||||
From bbda49b86f3841ac5100894da426edc541b6226c Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
Date: Thu, 12 Feb 2026 09:15:18 +0100
|
||||
Subject: [PATCH] Issue 7241 - Drop dateutil (#7242)
|
||||
|
||||
Bug Description:
|
||||
python-dateutil is unmaintained upstream and is marked for deprecation.
|
||||
|
||||
Fix Description:
|
||||
* Replace `dateutil.tz.tzoffset` with `datetime.timezone(datetime.timedelta())`.
|
||||
* Replace `dateutil.parser.parse` with standard `datetime` calls.
|
||||
* Import `datetime` as `dt` to avoid confusion between module and class.
|
||||
* Fix month lookup bug ('Oct': 9 / 'Sep': 10).
|
||||
|
||||
Fixes: https://github.com/389ds/389-ds-base/issues/7241
|
||||
|
||||
Reviewed by: jchapma, droideck (Thanks!)
|
||||
---
|
||||
.../suites/password/pwdPolicy_warning_test.py | 5 +-
|
||||
src/lib389/lib389/dirsrv_log.py | 48 ++++++++++++-------
|
||||
src/lib389/lib389/tests/dirsrv_log_test.py | 13 +++--
|
||||
src/lib389/pyproject.toml | 2 -
|
||||
src/lib389/requirements.txt | 1 -
|
||||
5 files changed, 38 insertions(+), 31 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/password/pwdPolicy_warning_test.py b/dirsrvtests/tests/suites/password/pwdPolicy_warning_test.py
|
||||
index 154ec01f1..2341da6eb 100644
|
||||
--- a/dirsrvtests/tests/suites/password/pwdPolicy_warning_test.py
|
||||
+++ b/dirsrvtests/tests/suites/password/pwdPolicy_warning_test.py
|
||||
@@ -15,9 +15,8 @@ from lib389.topologies import topology_st
|
||||
from lib389.idm.user import UserAccounts
|
||||
from lib389.idm.organizationalunit import OrganizationalUnits
|
||||
from lib389._constants import (DEFAULT_SUFFIX, DN_CONFIG, PASSWORD, DN_DM)
|
||||
-from dateutil.parser import parse as dt_parse
|
||||
from lib389.config import Config
|
||||
-import datetime
|
||||
+import datetime as dt
|
||||
|
||||
pytestmark = pytest.mark.tier1
|
||||
|
||||
@@ -351,7 +350,7 @@ def test_with_different_password_states(topology_st, global_policy, add_user):
|
||||
old_ts = user.get_attr_val_utf8('passwordExpirationTime')
|
||||
log.info("Old passwordExpirationTime: {}".format(old_ts))
|
||||
|
||||
- new_ts = (dt_parse(old_ts) - datetime.timedelta(31)).strftime('%Y%m%d%H%M%SZ')
|
||||
+ new_ts = (dt.datetime.strptime(old_ts, '%Y%m%d%H%M%SZ') - dt.timedelta(31)).strftime('%Y%m%d%H%M%SZ')
|
||||
log.info("New passwordExpirationTime: {}".format(new_ts))
|
||||
user.replace('passwordExpirationTime', new_ts)
|
||||
|
||||
diff --git a/src/lib389/lib389/dirsrv_log.py b/src/lib389/lib389/dirsrv_log.py
|
||||
index e40105ad3..3d923a8bf 100644
|
||||
--- a/src/lib389/lib389/dirsrv_log.py
|
||||
+++ b/src/lib389/lib389/dirsrv_log.py
|
||||
@@ -10,11 +10,11 @@
|
||||
"""
|
||||
|
||||
import copy
|
||||
+import datetime as dt
|
||||
import json
|
||||
import glob
|
||||
import re
|
||||
import gzip
|
||||
-from dateutil.parser import parse as dt_parse
|
||||
from lib389.utils import ensure_bytes
|
||||
from lib389._mapped_object_lint import DSLint
|
||||
from lib389.lint import (
|
||||
@@ -34,8 +34,8 @@ MONTH_LOOKUP = {
|
||||
'Jun': 6,
|
||||
'Jul': 7,
|
||||
'Aug': 8,
|
||||
- 'Oct': 9,
|
||||
- 'Sep': 10,
|
||||
+ 'Sep': 9,
|
||||
+ 'Oct': 10,
|
||||
'Nov': 11,
|
||||
'Dec': 12,
|
||||
}
|
||||
@@ -50,9 +50,9 @@ class DirsrvLog(DSLint):
|
||||
"""
|
||||
self.dirsrv = dirsrv
|
||||
self.log = self.dirsrv.log
|
||||
- self.prog_timestamp = re.compile(r'\[(?P<day>\d*)\/(?P<month>\w*)\/(?P<year>\d*):(?P<hour>\d*):(?P<minute>\d*):(?P<second>\d*)(.(?P<nanosecond>\d*))+\s(?P<tz>[\+\-]\d*)') # noqa
|
||||
+ self.prog_timestamp = re.compile(r'\[(?P<day>\d*)\/(?P<month>\w*)\/(?P<year>\d*):(?P<hour>\d*):(?P<minute>\d*):(?P<second>\d*)(.(?P<nanosecond>\d*))+\s(?P<tz>[\+\-]\d{4})') # noqa
|
||||
# JSON timestamp uses strftime %FT%T --> 2025-02-12T17:00:47.663123181 -0500
|
||||
- self.prog_json_timestamp = re.compile(r'(?P<year>\d*)-(?P<month>\w*)-(?P<day>\d*)T(?P<hour>\d*):(?P<minute>\d*):(?P<second>\d*)(.(?P<nanosecond>\d*))+\s(?P<tz>[\+\-]\d*)') # noqa
|
||||
+ self.prog_json_timestamp = re.compile(r'(?P<year>\d*)-(?P<month>\w*)-(?P<day>\d*)T(?P<hour>\d*):(?P<minute>\d*):(?P<second>\d*)(.(?P<nanosecond>\d*))+\s(?P<tz>[\+\-]\d{4})') # noqa
|
||||
self.prog_datetime = re.compile(r'^(?P<timestamp>\[.*\])')
|
||||
self.jsonFormat = False
|
||||
|
||||
@@ -157,20 +157,32 @@ class DirsrvLog(DSLint):
|
||||
else:
|
||||
timedata = self.prog_timestamp.match(ts).groupdict()
|
||||
|
||||
- # Now, have to convert month to an int.
|
||||
- dt_str = '{YEAR}-{MONTH}-{DAY} {HOUR}-{MINUTE}-{SECOND} {TZ}'.format(
|
||||
- YEAR=timedata['year'],
|
||||
- MONTH=timedata['month'],
|
||||
- DAY=timedata['day'],
|
||||
- HOUR=timedata['hour'],
|
||||
- MINUTE=timedata['minute'],
|
||||
- SECOND=timedata['second'],
|
||||
- TZ=timedata['tz'],
|
||||
- )
|
||||
- dt = dt_parse(dt_str)
|
||||
+ # Convert month to an int.
|
||||
+ month = timedata['month']
|
||||
+ if not month.isdigit():
|
||||
+ month = MONTH_LOOKUP[month]
|
||||
+ else:
|
||||
+ month = int(month)
|
||||
+
|
||||
+ # Parse timezone offset string (e.g. "+1000" or "-0500") into a timezone
|
||||
+ tz_str = timedata['tz']
|
||||
+ tz_sign = 1 if tz_str[0] == '+' else -1
|
||||
+ tz_hours = int(tz_str[1:3])
|
||||
+ tz_minutes = int(tz_str[3:5])
|
||||
+ tz = dt.timezone(dt.timedelta(hours=tz_sign * tz_hours, minutes=tz_sign * tz_minutes))
|
||||
+
|
||||
+ parsed_dt = dt.datetime(
|
||||
+ int(timedata['year']),
|
||||
+ month,
|
||||
+ int(timedata['day']),
|
||||
+ int(timedata['hour']),
|
||||
+ int(timedata['minute']),
|
||||
+ int(timedata['second']),
|
||||
+ tzinfo=tz
|
||||
+ )
|
||||
if timedata['nanosecond']:
|
||||
- dt = dt.replace(microsecond=int(int(timedata['nanosecond']) / 1000))
|
||||
- return dt
|
||||
+ parsed_dt = parsed_dt.replace(microsecond=int(timedata['nanosecond']) // 1000)
|
||||
+ return parsed_dt
|
||||
|
||||
def get_time_in_secs(self, log_line):
|
||||
"""Take the timestamp (not the date) from a DS access log and convert
|
||||
diff --git a/src/lib389/lib389/tests/dirsrv_log_test.py b/src/lib389/lib389/tests/dirsrv_log_test.py
|
||||
index 920e67a01..d0259ced9 100644
|
||||
--- a/src/lib389/lib389/tests/dirsrv_log_test.py
|
||||
+++ b/src/lib389/lib389/tests/dirsrv_log_test.py
|
||||
@@ -12,8 +12,7 @@ from lib389 import DirSrv, Entry
|
||||
import pytest
|
||||
import time
|
||||
import shutil
|
||||
-import datetime
|
||||
-from dateutil.tz import tzoffset
|
||||
+import datetime as dt
|
||||
|
||||
INSTANCE_PORT = 54321
|
||||
INSTANCE_SERVERID = 'standalone'
|
||||
@@ -74,7 +73,7 @@ def test_access_log(topology):
|
||||
topology.standalone.ds_access_log.parse_line('[27/Apr/2016:12:49:49.726093186 +1000] conn=1 fd=64 slot=64 connection from ::1 to ::1') ==
|
||||
{
|
||||
'slot': '64', 'remote': '::1', 'action': 'CONNECT', 'timestamp': '[27/Apr/2016:12:49:49.726093186 +1000]', 'fd': '64', 'conn': '1', 'local': '::1',
|
||||
- 'datetime': datetime.datetime(2016, 4, 27, 12, 0, 0, 726093, tzinfo=tzoffset(None, 36000))
|
||||
+ 'datetime': dt.datetime(2016, 4, 27, 12, 49, 49, 726093, tzinfo=dt.timezone(dt.timedelta(seconds=36000)))
|
||||
}
|
||||
)
|
||||
assert(
|
||||
@@ -82,21 +81,21 @@ def test_access_log(topology):
|
||||
{
|
||||
'rem': 'base="cn=config" scope=0 filter="(objectClass=*)" attrs="nsslapd-instancedir nsslapd-errorlog nsslapd-accesslog nsslapd-auditlog nsslapd-certdir nsslapd-schemadir nsslapd-bakdir nsslapd-ldifdir"', # noqa
|
||||
'action': 'SRCH', 'timestamp': '[27/Apr/2016:12:49:49.727235997 +1000]', 'conn': '1', 'op': '2',
|
||||
- 'datetime': datetime.datetime(2016, 4, 27, 12, 0, 0, 727235, tzinfo=tzoffset(None, 36000))
|
||||
+ 'datetime': dt.datetime(2016, 4, 27, 12, 49, 49, 727235, tzinfo=dt.timezone(dt.timedelta(seconds=36000)))
|
||||
}
|
||||
)
|
||||
assert(
|
||||
topology.standalone.ds_access_log.parse_line('[27/Apr/2016:12:49:49.736297002 +1000] conn=1 op=4 fd=64 closed - U1') ==
|
||||
{
|
||||
'status': 'U1', 'fd': '64', 'action': 'DISCONNECT', 'timestamp': '[27/Apr/2016:12:49:49.736297002 +1000]', 'conn': '1', 'op': '4',
|
||||
- 'datetime': datetime.datetime(2016, 4, 27, 12, 0, 0, 736297, tzinfo=tzoffset(None, 36000))
|
||||
+ 'datetime': dt.datetime(2016, 4, 27, 12, 49, 49, 736297, tzinfo=dt.timezone(dt.timedelta(seconds=36000)))
|
||||
}
|
||||
)
|
||||
assert(
|
||||
topology.standalone.ds_access_log.parse_line('[27/Apr/2016:12:49:49.736297002 -1000] conn=1 op=4 fd=64 closed - U1') ==
|
||||
{
|
||||
'status': 'U1', 'fd': '64', 'action': 'DISCONNECT', 'timestamp': '[27/Apr/2016:12:49:49.736297002 -1000]', 'conn': '1', 'op': '4',
|
||||
- 'datetime': datetime.datetime(2016, 4, 27, 12, 0, 0, 736297, tzinfo=tzoffset(None, -36000))
|
||||
+ 'datetime': dt.datetime(2016, 4, 27, 12, 49, 49, 736297, tzinfo=dt.timezone(dt.timedelta(seconds=-36000)))
|
||||
}
|
||||
)
|
||||
|
||||
@@ -113,7 +112,7 @@ def test_error_log(topology):
|
||||
topology.standalone.ds_error_log.parse_line('[27/Apr/2016:13:46:35.775670167 +1000] slapd started. Listening on All Interfaces port 54321 for LDAP requests') == # noqa
|
||||
{
|
||||
'timestamp': '[27/Apr/2016:13:46:35.775670167 +1000]', 'message': 'slapd started. Listening on All Interfaces port 54321 for LDAP requests',
|
||||
- 'datetime': datetime.datetime(2016, 4, 27, 13, 0, 0, 775670, tzinfo=tzoffset(None, 36000))
|
||||
+ 'datetime': dt.datetime(2016, 4, 27, 13, 46, 35, 775670, tzinfo=dt.timezone(dt.timedelta(seconds=36000)))
|
||||
}
|
||||
)
|
||||
|
||||
diff --git a/src/lib389/pyproject.toml b/src/lib389/pyproject.toml
|
||||
index 63c7c9710..e067d1590 100644
|
||||
--- a/src/lib389/pyproject.toml
|
||||
+++ b/src/lib389/pyproject.toml
|
||||
@@ -5,7 +5,6 @@ requires = [
|
||||
"argparse-manpage[setuptools]",
|
||||
"pyasn1",
|
||||
"pyasn1-modules",
|
||||
- "python-dateutil",
|
||||
"argcomplete",
|
||||
"python-ldap",
|
||||
"distro",
|
||||
@@ -43,7 +42,6 @@ classifiers = [
|
||||
dependencies = [
|
||||
"pyasn1",
|
||||
"pyasn1-modules",
|
||||
- "python-dateutil",
|
||||
"argcomplete",
|
||||
"python-ldap",
|
||||
"distro",
|
||||
diff --git a/src/lib389/requirements.txt b/src/lib389/requirements.txt
|
||||
index 5e1b3dad7..94b10e3c2 100644
|
||||
--- a/src/lib389/requirements.txt
|
||||
+++ b/src/lib389/requirements.txt
|
||||
@@ -1,6 +1,5 @@
|
||||
pyasn1
|
||||
pyasn1-modules
|
||||
-python-dateutil
|
||||
argcomplete
|
||||
argparse-manpage
|
||||
python-ldap
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@ -0,0 +1,94 @@
|
||||
From d19c50372d5c5d901f05ce6e7dd03313f41fc197 Mon Sep 17 00:00:00 2001
|
||||
From: James Chapman <jachapma@redhat.com>
|
||||
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 | 14 +++++++++++---
|
||||
1 file changed, 11 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/syncrepl_plugin/basic_test.py b/dirsrvtests/tests/suites/syncrepl_plugin/basic_test.py
|
||||
index 85b4ac078..d0e7e8a32 100644
|
||||
--- a/dirsrvtests/tests/suites/syncrepl_plugin/basic_test.py
|
||||
+++ b/dirsrvtests/tests/suites/syncrepl_plugin/basic_test.py
|
||||
@@ -21,7 +21,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,10 +214,13 @@ class Sync_persist(threading.Thread, ReconnectLDAPObject, SyncreplConsumer):
|
||||
|
||||
def run(self):
|
||||
"""Start a sync repl client"""
|
||||
- ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, os.path.join(self.inst.get_config_dir(), "ca.crt"))
|
||||
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",
|
||||
@@ -257,6 +260,7 @@ def test_sync_repl_mep(topology, request):
|
||||
5. Success
|
||||
"""
|
||||
inst = topology[0]
|
||||
+ inst.enable_tls()
|
||||
|
||||
# Enable/configure retroCL
|
||||
plugin = RetroChangelogPlugin(inst)
|
||||
@@ -342,6 +346,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)
|
||||
@@ -408,6 +413,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()
|
||||
@@ -551,6 +558,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()
|
||||
@@ -609,7 +617,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
|
||||
|
||||
@ -0,0 +1,33 @@
|
||||
From 1df3852cf0e073cfe006d661aecdd909862fc79a Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
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
|
||||
|
||||
201
0044-Issue-CLI-dsctl-db2index-needs-some-hardening-with-M.patch
Normal file
201
0044-Issue-CLI-dsctl-db2index-needs-some-hardening-with-M.patch
Normal file
@ -0,0 +1,201 @@
|
||||
From 63bf648f699b8fcd8f319254b0348d969ceea7a0 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
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 c7275e4cb..ad6d05a1e 100644
|
||||
--- a/dirsrvtests/tests/suites/import/import_test.py
|
||||
+++ b/dirsrvtests/tests/suites/import/import_test.py
|
||||
@@ -514,7 +514,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 d57a91929..01b3ea23c 100644
|
||||
--- a/src/lib389/lib389/__init__.py
|
||||
+++ b/src/lib389/lib389/__init__.py
|
||||
@@ -2953,7 +2953,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
|
||||
@@ -2966,34 +2966,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
|
||||
|
||||
@ -0,0 +1,74 @@
|
||||
From d52901f69e9b7952b33b219ec197308a1a20bda9 Mon Sep 17 00:00:00 2001
|
||||
From: progier389 <progier@redhat.com>
|
||||
Date: Fri, 13 Feb 2026 15:13:05 +0100
|
||||
Subject: [PATCH] Issue 7252 - PQC - Need to iterate on SECOidTag instead of
|
||||
using OID (#7254)
|
||||
|
||||
* Issue 7252 - PQC - Need to iterate on SECOidTag instead of using OID
|
||||
|
||||
Need to dynamically iterate on SECOidTag instead of using SEC_OID_ML_DSA_* OIDs to avoid issue with upcoming nss versions and fix a RHEL build break with nss 3.112
|
||||
|
||||
Issue: #7252
|
||||
|
||||
Reviewed by: @mreynolds389, @droideck, @vashirov
|
||||
|
||||
|
||||
* Update ldap/servers/slapd/ssl.c
|
||||
|
||||
Co-authored-by: Simon Pichugin <spichugi@redhat.com>
|
||||
|
||||
---------
|
||||
|
||||
Co-authored-by: Simon Pichugin <spichugi@redhat.com>
|
||||
---
|
||||
ldap/servers/slapd/ssl.c | 24 +++++++++---------------
|
||||
1 file changed, 9 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/ldap/servers/slapd/ssl.c b/ldap/servers/slapd/ssl.c
|
||||
index 7d5db2cdd..d05c64fb1 100644
|
||||
--- a/ldap/servers/slapd/ssl.c
|
||||
+++ b/ldap/servers/slapd/ssl.c
|
||||
@@ -732,31 +732,25 @@ SSLPLCY_Install(void)
|
||||
{
|
||||
|
||||
SECStatus s = 0;
|
||||
-#ifdef MAX_ML_DSA_PRIVATE_KEY_LEN
|
||||
int flags = NSS_USE_ALG_IN_SIGNATURE | NSS_USE_ALG_IN_SSL;
|
||||
- static const SECOidTag oids[] = {
|
||||
- SEC_OID_ML_DSA_44,
|
||||
- SEC_OID_ML_DSA_65,
|
||||
- SEC_OID_ML_DSA_87,
|
||||
- };
|
||||
-#endif
|
||||
+ SECOidData *oid = NULL;
|
||||
|
||||
s = NSS_SetDomesticPolicy();
|
||||
|
||||
-#ifdef MAX_ML_DSA_PRIVATE_KEY_LEN
|
||||
/* Should rely on the crypto module policy in FIPS mode */
|
||||
if (!slapd_pk11_isFIPS()) {
|
||||
/* Set explicitly PQC algorithm policy if it is not set by default */
|
||||
- for (size_t i=0; s == SECSuccess && i < PR_ARRAY_SIZE(oids); i++) {
|
||||
- PRUint32 oflags = 0;
|
||||
- (void) NSS_GetAlgorithmPolicy(oids[i], &oflags);
|
||||
- if ((oflags & flags) != flags) {
|
||||
- s = NSS_SetAlgorithmPolicy(oids[i], flags, 0);
|
||||
+ for (SECOidTag tag = 1; s == SECSuccess && (oid = SECOID_FindOIDByTag(tag)) != NULL; tag++) {
|
||||
+ if (oid->mechanism != CKM_INVALID_MECHANISM &&
|
||||
+ PL_strncasecmp(oid->desc, "ML-DSA-", 7) == 0) {
|
||||
+ PRUint32 oflags = 0;
|
||||
+ (void) NSS_GetAlgorithmPolicy(tag, &oflags);
|
||||
+ if ((oflags & flags) != flags) {
|
||||
+ s = NSS_SetAlgorithmPolicy(tag, flags, 0);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
}
|
||||
-#endif
|
||||
-
|
||||
return s ? PR_FAILURE : PR_SUCCESS;
|
||||
}
|
||||
|
||||
--
|
||||
2.52.0
|
||||
|
||||
3031
0046-Issue-6951-Dynamic-Certificas-Refresh-CI-tests-7238.patch
Normal file
3031
0046-Issue-6951-Dynamic-Certificas-Refresh-CI-tests-7238.patch
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,41 @@
|
||||
From 48ad61231203d9ccb96d0fe542aae93dbb74a9bf Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
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
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
From c7ef5b3073bbd94a5d2b544556368c830c165e0d Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
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 7cdf16a84..89a747199 100644
|
||||
--- a/dirsrvtests/tests/suites/vlv/regression_test.py
|
||||
+++ b/dirsrvtests/tests/suites/vlv/regression_test.py
|
||||
@@ -1175,6 +1175,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
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
From 384dbcaba418afe9e4de798d16a68d0468632a57 Mon Sep 17 00:00:00 2001
|
||||
From 7e575cc8cc6f1bf558f50ca0fc55145e469d60d2 Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
Date: Fri, 13 Feb 2026 13:08:40 +0100
|
||||
Subject: [PATCH] Issue 7223 - Use lexicographical order for ancestorid
|
||||
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
|
||||
@ -11,24 +11,24 @@ ldif2db import).
|
||||
|
||||
Relates: https://github.com/389ds/389-ds-base/issues/7223
|
||||
|
||||
Reviewed by: @progier389, @tbordaz (Thanks!)
|
||||
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 388dd6efb..f5342b99a 100644
|
||||
index 17bfc09a0..1569eb7ff 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);
|
||||
}
|
||||
@@ -231,7 +231,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
|
||||
|
||||
38
0050-Issue-3134-Fix-build-break-7260.patch
Normal file
38
0050-Issue-3134-Fix-build-break-7260.patch
Normal file
@ -0,0 +1,38 @@
|
||||
From 245bc3b53f385e12e4dc9d2cb765a55e10e0fdc5 Mon Sep 17 00:00:00 2001
|
||||
From: progier389 <progier@redhat.com>
|
||||
Date: Fri, 13 Feb 2026 17:51:12 +0100
|
||||
Subject: [PATCH] Issue 3134 - Fix build break (#7260)
|
||||
|
||||
Fix build break of PR #7238 related to import rpm
|
||||
|
||||
Issue: #3134
|
||||
|
||||
Reviewed by: @vashirov (Thanks!)
|
||||
---
|
||||
src/lib389/lib389/utils.py | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/lib389/lib389/utils.py b/src/lib389/lib389/utils.py
|
||||
index 07cb34d93..4df36cf1f 100644
|
||||
--- a/src/lib389/lib389/utils.py
|
||||
+++ b/src/lib389/lib389/utils.py
|
||||
@@ -28,7 +28,6 @@ from datetime import (datetime, timedelta)
|
||||
import sys
|
||||
import filecmp
|
||||
import pwd
|
||||
-import rpm
|
||||
import shlex
|
||||
import operator
|
||||
import subprocess
|
||||
@@ -2135,6 +2134,8 @@ def get_timeout_scale():
|
||||
|
||||
def rpm_is_older(pkg, version):
|
||||
"""Check if an RPM package version is older than specified version"""
|
||||
+ # rpm module is not installed in build environment so let import it only when used.
|
||||
+ import rpm
|
||||
ts = rpm.TransactionSet()
|
||||
mi = ts.dbMatch('name', pkg)
|
||||
for h in mi:
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@ -0,0 +1,87 @@
|
||||
From ac3d9253e0a7a4b5f0108506bcf25255b302fd16 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
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 | 7 ++++---
|
||||
ldap/servers/slapd/modify.c | 2 +-
|
||||
ldap/servers/slapd/pw.c | 13 ++++++++++++-
|
||||
3 files changed, 17 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/password/pwp_history_test.py b/dirsrvtests/tests/suites/password/pwp_history_test.py
|
||||
index cf68d743c..78b448a87 100644
|
||||
--- a/dirsrvtests/tests/suites/password/pwp_history_test.py
|
||||
+++ b/dirsrvtests/tests/suites/password/pwp_history_test.py
|
||||
@@ -189,9 +189,9 @@ def test_history_is_not_overwritten(topology_st, user):
|
||||
|
||||
|
||||
@pytest.mark.parametrize('policy',
|
||||
- [(pytest.param('global', marks=pytest.mark.xfail(reason="DS7052"))),
|
||||
- (pytest.param('subtree', marks=pytest.mark.xfail(reason="DS7066, DS7052"))),
|
||||
- (pytest.param('user', marks=pytest.mark.xfail(reason="DS7066, DS7052")))])
|
||||
+ [(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
|
||||
|
||||
@@ -282,6 +282,7 @@ def test_basic(topology_st, user, policy):
|
||||
# Password history [password3, password4], current password is "password1"
|
||||
|
||||
# Reset password by Directory Manager(admin reset)
|
||||
+ dm = DirectoryManager(topology_st.standalone)
|
||||
dm.rebind()
|
||||
time.sleep(.5)
|
||||
change_password(user, 'password-reset', success=True)
|
||||
diff --git a/ldap/servers/slapd/modify.c b/ldap/servers/slapd/modify.c
|
||||
index 9e5bce80b..0ecce9bc8 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 055ec0d74..c53ecf23d 100644
|
||||
--- a/ldap/servers/slapd/pw.c
|
||||
+++ b/ldap/servers/slapd/pw.c
|
||||
@@ -1535,7 +1535,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
|
||||
|
||||
1379
0052-Issue-7243-UI-add-support-for-hot-certificates.patch
Normal file
1379
0052-Issue-7243-UI-add-support-for-hot-certificates.patch
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,32 @@
|
||||
From b216b86c5607dc0421eb609c46f3004844fb37c0 Mon Sep 17 00:00:00 2001
|
||||
From: Akshay Adhikari <aadhikar@redhat.com>
|
||||
Date: Tue, 17 Feb 2026 17:40:44 +0530
|
||||
Subject: [PATCH] Issue 6758 - Fix Enable Replication dropdown not opening
|
||||
(#7262)
|
||||
|
||||
Description: Removed hardcoded isOpen={false} and empty onToggle handler that
|
||||
prevented dropdown from opening. Let component manage its own state.
|
||||
|
||||
Relates: #6758
|
||||
|
||||
Reviewed by: @vashirov
|
||||
---
|
||||
src/cockpit/389-console/src/lib/replication/replModals.jsx | 2 --
|
||||
1 file changed, 2 deletions(-)
|
||||
|
||||
diff --git a/src/cockpit/389-console/src/lib/replication/replModals.jsx b/src/cockpit/389-console/src/lib/replication/replModals.jsx
|
||||
index ba4859617..83a8b75a5 100644
|
||||
--- a/src/cockpit/389-console/src/lib/replication/replModals.jsx
|
||||
+++ b/src/cockpit/389-console/src/lib/replication/replModals.jsx
|
||||
@@ -1757,8 +1757,6 @@ export class EnableReplModal extends React.Component {
|
||||
handleChange(syntheticEvent);
|
||||
}}
|
||||
options={[_("Supplier"), _("Hub"), _("Consumer")]}
|
||||
- isOpen={false}
|
||||
- onToggle={() => {}}
|
||||
placeholder={_("Select role...")}
|
||||
ariaLabel="Replication role selection"
|
||||
isMulti={false}
|
||||
--
|
||||
2.52.0
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
From 67c3183380888f4af093b546e717f3e7451a41d6 Mon Sep 17 00:00:00 2001
|
||||
From 6ce19a9a3e36213a5604144aa5eb3cba666e5ed4 Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
Date: Wed, 18 Feb 2026 09:26:57 +0100
|
||||
Subject: [PATCH] Issue 7223 - Remove integerOrderingMatch requirement for
|
||||
@ -19,14 +19,14 @@ 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 | 106 ------------------
|
||||
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(+), 223 deletions(-)
|
||||
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 ce86239e5..088b48587 100644
|
||||
index dd42cd197..8dc82c779 100644
|
||||
--- a/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py
|
||||
+++ b/dirsrvtests/tests/suites/healthcheck/health_system_indexes_test.py
|
||||
@@ -179,7 +179,8 @@ def test_missing_parentid(topology_st, log_buffering_enabled):
|
||||
@ -61,7 +61,7 @@ index ce86239e5..088b48587 100644
|
||||
PARENTID_DN = "cn=parentid,cn=index,cn=userroot,cn=ldbm database,cn=plugins,cn=config"
|
||||
|
||||
standalone = topology_st.standalone
|
||||
@@ -210,16 +206,13 @@ def test_missing_matching_rule(topology_st, log_buffering_enabled):
|
||||
@@ -210,17 +206,14 @@ def test_missing_matching_rule(topology_st, log_buffering_enabled):
|
||||
parentid_index = Index(standalone, PARENTID_DN)
|
||||
parentid_index.remove("nsMatchingRule", "integerOrderingMatch")
|
||||
|
||||
@ -73,6 +73,7 @@ index ce86239e5..088b48587 100644
|
||||
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)
|
||||
@ -80,7 +81,7 @@ index ce86239e5..088b48587 100644
|
||||
|
||||
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
|
||||
@@ -908,7 +901,9 @@ def test_index_check_fixes_ancestorid_config(topology_st):
|
||||
@@ -910,7 +903,9 @@ def test_index_check_fixes_ancestorid_config(topology_st):
|
||||
|
||||
|
||||
def test_index_check_fixes_missing_matching_rule(topology_st):
|
||||
@ -91,7 +92,7 @@ index ce86239e5..088b48587 100644
|
||||
|
||||
:id: 6c1d4e9f-0a3b-4d5c-1e7f-8a9b0c2d3e4f
|
||||
:setup: Standalone instance
|
||||
@@ -916,18 +911,14 @@ def test_index_check_fixes_missing_matching_rule(topology_st):
|
||||
@@ -918,18 +913,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
|
||||
@ -114,7 +115,7 @@ index ce86239e5..088b48587 100644
|
||||
"""
|
||||
from lib389.cli_ctl.dbtasks import dbtasks_index_check
|
||||
from lib389.dseldif import DSEldif
|
||||
@@ -961,34 +952,20 @@ def test_index_check_fixes_missing_matching_rule(topology_st):
|
||||
@@ -963,34 +954,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")
|
||||
|
||||
@ -156,7 +157,7 @@ index ce86239e5..088b48587 100644
|
||||
|
||||
log.info("Start the server")
|
||||
standalone.start()
|
||||
@@ -1078,7 +1055,7 @@ def test_index_check_fixes_multiple_issues(topology_st):
|
||||
@@ -1080,7 +1057,7 @@ def test_index_check_fixes_multiple_issues(topology_st):
|
||||
:steps:
|
||||
1. Create DS instance
|
||||
2. Stop the server
|
||||
@ -165,7 +166,7 @@ index ce86239e5..088b48587 100644
|
||||
4. Run dsctl index-check (should detect all issues)
|
||||
5. Run dsctl index-check --fix
|
||||
6. Verify all issues were fixed
|
||||
@@ -1120,14 +1097,6 @@ def test_index_check_fixes_multiple_issues(topology_st):
|
||||
@@ -1122,14 +1099,6 @@ def test_index_check_fixes_multiple_issues(topology_st):
|
||||
]
|
||||
dse_ldif.add_entry(ancestorid_entry)
|
||||
|
||||
@ -180,7 +181,7 @@ index ce86239e5..088b48587 100644
|
||||
log.info("Run index-check without --fix (should detect all issues)")
|
||||
args = FakeArgs()
|
||||
args.backend = "userRoot"
|
||||
@@ -1158,16 +1127,6 @@ def test_index_check_fixes_multiple_issues(topology_st):
|
||||
@@ -1160,16 +1129,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}"
|
||||
|
||||
@ -198,15 +199,15 @@ index ce86239e5..088b48587 100644
|
||||
|
||||
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 aa51e72d2..4eb09ca38 100644
|
||||
index 6b1b012da..9557e9066 100644
|
||||
--- a/ldap/servers/slapd/upgrade.c
|
||||
+++ b/ldap/servers/slapd/upgrade.c
|
||||
@@ -243,108 +243,6 @@ upgrade_remove_ancestorid_index_config(void)
|
||||
@@ -551,107 +551,6 @@ upgrade_remove_ancestorid_index_config(void)
|
||||
return uresult;
|
||||
}
|
||||
|
||||
-/*
|
||||
- * Check if parentid indexes are missing the integerOrderingMatch
|
||||
- * Check if parentid/ancestorid indexes are missing the integerOrderingMatch
|
||||
- * matching rule.
|
||||
- *
|
||||
- * This function logs a warning if we detect this condition, advising
|
||||
@ -306,11 +307,10 @@ index aa51e72d2..4eb09ca38 100644
|
||||
-
|
||||
- return uresult;
|
||||
-}
|
||||
-
|
||||
upgrade_status
|
||||
upgrade_server(void)
|
||||
{
|
||||
@@ -356,9 +254,5 @@ upgrade_server(void)
|
||||
|
||||
/*
|
||||
* Upgrade the base config of the PAM PTA plugin.
|
||||
@@ -879,10 +778,6 @@ upgrade_server(void)
|
||||
return UPGRADE_FAILURE;
|
||||
}
|
||||
|
||||
@ -320,11 +320,12 @@ index aa51e72d2..4eb09ca38 100644
|
||||
-
|
||||
return UPGRADE_SUCCESS;
|
||||
}
|
||||
|
||||
diff --git a/rpm/389-ds-base.spec.in b/rpm/389-ds-base.spec.in
|
||||
index 16b8d14c5..59e3a748f 100644
|
||||
index 0e0e28285..370e3abd4 100644
|
||||
--- a/rpm/389-ds-base.spec.in
|
||||
+++ b/rpm/389-ds-base.spec.in
|
||||
@@ -529,9 +529,6 @@ for dir in "$instbase"/slapd-* ; do
|
||||
@@ -650,9 +650,6 @@ for dir in "$instbase"/slapd-* ; do
|
||||
else
|
||||
echo "instance $inst is not running" >> "$output" 2>&1 || :
|
||||
fi
|
||||
@ -335,10 +336,10 @@ index 16b8d14c5..59e3a748f 100644
|
||||
done
|
||||
|
||||
diff --git a/src/lib389/lib389/backend.py b/src/lib389/lib389/backend.py
|
||||
index 4babf6850..376596cd6 100644
|
||||
index f3dbe7c92..6c8cbc018 100644
|
||||
--- a/src/lib389/lib389/backend.py
|
||||
+++ b/src/lib389/lib389/backend.py
|
||||
@@ -541,9 +541,10 @@ class Backend(DSLdapObject):
|
||||
@@ -647,9 +647,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.
|
||||
@ -352,7 +353,7 @@ index 4babf6850..376596cd6 100644
|
||||
'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 16da966d1..ea8a00cc3 100644
|
||||
index cd96cdaf7..b02de203f 100644
|
||||
--- a/src/lib389/lib389/cli_ctl/dbtasks.py
|
||||
+++ b/src/lib389/lib389/cli_ctl/dbtasks.py
|
||||
@@ -10,6 +10,7 @@
|
||||
@ -363,7 +364,7 @@ index 16da966d1..ea8a00cc3 100644
|
||||
import subprocess
|
||||
from enum import Enum
|
||||
from lib389._constants import TaskWarning
|
||||
@@ -271,45 +272,53 @@ def _check_disk_ordering(db_dir, backend, index_name, dbscan_path, is_mdb, log):
|
||||
@@ -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
|
||||
|
||||
@ -430,7 +431,7 @@ index 16da966d1..ea8a00cc3 100644
|
||||
except OSError as e:
|
||||
log.warning(" Error running dbscan: %s", e)
|
||||
return IndexOrdering.UNKNOWN
|
||||
@@ -383,8 +392,7 @@ def dbtasks_index_check(inst, log, args):
|
||||
@@ -375,8 +384,7 @@ def dbtasks_index_check(inst, log, args):
|
||||
|
||||
# Track all issues found
|
||||
all_ok = True
|
||||
@ -440,7 +441,7 @@ index 16da966d1..ea8a00cc3 100644
|
||||
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
|
||||
@@ -417,13 +425,6 @@ def dbtasks_index_check(inst, log, args):
|
||||
@@ -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)
|
||||
@ -454,7 +455,7 @@ index 16da966d1..ea8a00cc3 100644
|
||||
continue
|
||||
|
||||
config_has_int_order = _has_integer_ordering_match(dse_ldif, backend, index_name)
|
||||
@@ -431,18 +432,15 @@ def dbtasks_index_check(inst, log, args):
|
||||
@@ -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)
|
||||
|
||||
@ -480,7 +481,7 @@ index 16da966d1..ea8a00cc3 100644
|
||||
all_ok = False
|
||||
|
||||
# Handle issues
|
||||
@@ -488,26 +486,27 @@ def dbtasks_index_check(inst, log, args):
|
||||
@@ -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
|
||||
|
||||
@ -525,7 +526,7 @@ index 16da966d1..ea8a00cc3 100644
|
||||
|
||||
log.info("All issues fixed")
|
||||
return True
|
||||
@@ -572,5 +571,5 @@ def create_parser(subcommands):
|
||||
@@ -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,
|
||||
227
0055-Issue-7236-Fix-GSSAPI-tests-7237.patch
Normal file
227
0055-Issue-7236-Fix-GSSAPI-tests-7237.patch
Normal file
@ -0,0 +1,227 @@
|
||||
From 26feecae026581e39a43f001faff59e81a92c03d Mon Sep 17 00:00:00 2001
|
||||
From: Lenka Doudova <mirielka@users.noreply.github.com>
|
||||
Date: Wed, 18 Feb 2026 14:33:49 +0100
|
||||
Subject: [PATCH] Issue 7236 - Fix GSSAPI tests (#7237)
|
||||
|
||||
* Issue 7236 - Fix GSSAPI tests
|
||||
|
||||
Description:
|
||||
Fix for failing GSSAPI tests
|
||||
Add GSSAPI_ACK variable to pytest workflow for proper execution in
|
||||
Github CI
|
||||
|
||||
Relates: #7236
|
||||
Author: Lenka Doudova
|
||||
Reviewer: Barbora Simonova, Viktor Ashirov
|
||||
---
|
||||
.github/workflows/lmdbpytest.yml | 2 +-
|
||||
.github/workflows/pytest.yml | 2 +-
|
||||
.../tests/suites/gssapi/simple_gssapi_test.py | 2 +
|
||||
.../suites/gssapi_repl/gssapi_repl_test.py | 43 +++++---------
|
||||
src/lib389/lib389/topologies.py | 57 +++++++++++++++++++
|
||||
5 files changed, 76 insertions(+), 30 deletions(-)
|
||||
|
||||
diff --git a/.github/workflows/lmdbpytest.yml b/.github/workflows/lmdbpytest.yml
|
||||
index 2d0a122bf..376090bf6 100644
|
||||
--- a/.github/workflows/lmdbpytest.yml
|
||||
+++ b/.github/workflows/lmdbpytest.yml
|
||||
@@ -120,7 +120,7 @@ jobs:
|
||||
sudo docker exec $CID sh -c "systemctl enable --now cockpit.socket"
|
||||
sudo docker exec $CID sh -c "mkdir -p /workspace/assets/cores && chmod 777 /workspace{,/assets{,/cores}}"
|
||||
sudo docker exec $CID sh -c "echo '/workspace/assets/cores/core.%e.%P' > /proc/sys/kernel/core_pattern"
|
||||
- sudo docker exec -e WEBUI=1 -e NSSLAPD_DB_LIB=mdb -e DEBUG=pw:api -e PASSWD="${PASSWD}" $CID py.test --suppress-no-test-exit-code -m "not flaky" --junit-xml=pytest.xml --html=pytest.html --browser=firefox --browser=chromium -v dirsrvtests/tests/suites/${{ matrix.suite }}
|
||||
+ sudo docker exec -e WEBUI=1 -e NSSLAPD_DB_LIB=mdb -e DEBUG=pw:api -e PASSWD="${PASSWD}" -e GSSAPI_ACK=1 $CID py.test --suppress-no-test-exit-code -m "not flaky" --junit-xml=pytest.xml --html=pytest.html --browser=firefox --browser=chromium -v dirsrvtests/tests/suites/${{ matrix.suite }}
|
||||
|
||||
- name: Make the results file readable by all
|
||||
if: always()
|
||||
diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml
|
||||
index 8a543be85..a51553656 100644
|
||||
--- a/.github/workflows/pytest.yml
|
||||
+++ b/.github/workflows/pytest.yml
|
||||
@@ -125,7 +125,7 @@ jobs:
|
||||
echo "Tests skipped because read-only Berkeley Database is installed." > pytest.html
|
||||
echo "<?xml version="1.0" encoding="utf-8"?>'Tests skipped because read-only Berkeley Database is installed.'" > pytest.xml
|
||||
else
|
||||
- sudo docker exec -e WEBUI=1 -e NSSLAPD_DB_LIB=bdb -e DEBUG=pw:api -e PASSWD="${PASSWD}" $CID py.test --suppress-no-test-exit-code -m "not flaky" --junit-xml=pytest.xml --html=pytest.html --browser=firefox --browser=chromium -v dirsrvtests/tests/suites/${{ matrix.suite }}
|
||||
+ sudo docker exec -e WEBUI=1 -e NSSLAPD_DB_LIB=bdb -e DEBUG=pw:api -e PASSWD="${PASSWD}" -e GSSAPI_ACK=1 $CID py.test --suppress-no-test-exit-code -m "not flaky" --junit-xml=pytest.xml --html=pytest.html --browser=firefox --browser=chromium -v dirsrvtests/tests/suites/${{ matrix.suite }}
|
||||
fi
|
||||
|
||||
- name: Make the results file readable by all
|
||||
diff --git a/dirsrvtests/tests/suites/gssapi/simple_gssapi_test.py b/dirsrvtests/tests/suites/gssapi/simple_gssapi_test.py
|
||||
index be6f68a9a..e48de3491 100644
|
||||
--- a/dirsrvtests/tests/suites/gssapi/simple_gssapi_test.py
|
||||
+++ b/dirsrvtests/tests/suites/gssapi/simple_gssapi_test.py
|
||||
@@ -34,6 +34,8 @@ def testuser(topology_st_gssapi):
|
||||
})
|
||||
# Give them a krb princ
|
||||
user.create_keytab()
|
||||
+ # Make krb5 config readable by everyone for the tests to work
|
||||
+ os.chmod(user._instance.realm.krb5confrealm, 0o644)
|
||||
return user
|
||||
|
||||
@gssapi_ack
|
||||
diff --git a/dirsrvtests/tests/suites/gssapi_repl/gssapi_repl_test.py b/dirsrvtests/tests/suites/gssapi_repl/gssapi_repl_test.py
|
||||
index 402684aab..fa7fc9c24 100644
|
||||
--- a/dirsrvtests/tests/suites/gssapi_repl/gssapi_repl_test.py
|
||||
+++ b/dirsrvtests/tests/suites/gssapi_repl/gssapi_repl_test.py
|
||||
@@ -10,7 +10,7 @@ import pytest
|
||||
from lib389.tasks import *
|
||||
from lib389.utils import *
|
||||
from lib389.agreement import *
|
||||
-from lib389.topologies import topology_m2
|
||||
+from lib389.topologies import topology_m2_gssapi, gssapi_ack
|
||||
|
||||
pytestmark = pytest.mark.tier2
|
||||
|
||||
@@ -69,25 +69,8 @@ def _allow_machine_account(inst, name):
|
||||
(ldap.MOD_REPLACE, 'nsDS5ReplicaBindDN', f"uid={name},ou=Machines,{DEFAULT_SUFFIX}".encode('utf-8'))
|
||||
])
|
||||
|
||||
-def _verify_etc_hosts():
|
||||
- #Check if /etc/hosts is compatible with the test
|
||||
- NEEDED_HOSTS = ( ('ldapkdc.example.com', '127.0.0.1'),
|
||||
- ('ldapkdc1.example.com', '127.0.1.1'),
|
||||
- ('ldapkdc2.example.com', '127.0.2.1'))
|
||||
- found_hosts = {}
|
||||
- with open('/etc/hosts','r') as f:
|
||||
- for l in f:
|
||||
- s = l.split()
|
||||
- if len(s) < 2:
|
||||
- continue
|
||||
- for nh in NEEDED_HOSTS:
|
||||
- if (s[0] == nh[1] and s[1] == nh[0]):
|
||||
- found_hosts[s[1]] = True
|
||||
- return len(found_hosts) == len(NEEDED_HOSTS)
|
||||
-
|
||||
-@pytest.mark.skipif(not _verify_etc_hosts(), reason="/etc/hosts does not contains the needed hosts.")
|
||||
-@pytest.mark.skipif(True, reason="Test disabled because it requires specific kerberos requirement (server principal, keytab, etc ...")
|
||||
-def test_gssapi_repl(topology_m2):
|
||||
+@gssapi_ack
|
||||
+def test_gssapi_repl(topology_m2_gssapi):
|
||||
"""Test gssapi authenticated replication agreement of two suppliers using KDC
|
||||
|
||||
:id: 552850aa-afc3-473e-9c39-aae802b46f11
|
||||
@@ -112,8 +95,8 @@ def test_gssapi_repl(topology_m2):
|
||||
6. Test User should be created on M1 and M2 both
|
||||
7. Test User should be created on M1 and M2 both
|
||||
"""
|
||||
- supplier1 = topology_m2.ms["supplier1"]
|
||||
- supplier2 = topology_m2.ms["supplier2"]
|
||||
+ supplier1 = topology_m2_gssapi.ms["supplier1"]
|
||||
+ supplier2 = topology_m2_gssapi.ms["supplier2"]
|
||||
|
||||
# Create the locations on each supplier for the other to bind to.
|
||||
_create_machine_ou(supplier1)
|
||||
@@ -134,10 +117,9 @@ def test_gssapi_repl(topology_m2):
|
||||
# Creating agreement from supplier 1 to supplier 2
|
||||
|
||||
# Set the replica bind method to sasl gssapi
|
||||
- properties = {RA_NAME: r'meTo_$host:$port',
|
||||
+ properties = {RA_NAME: 'meTo_' + supplier2.host + ':' + str(supplier2.port),
|
||||
RA_METHOD: 'SASL/GSSAPI',
|
||||
RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
|
||||
- supplier1.agreement.delete(suffix=SUFFIX, consumer_host=supplier2.host, consumer_port=supplier2.port)
|
||||
m1_m2_agmt = supplier1.agreement.create(suffix=SUFFIX, host=supplier2.host, port=supplier2.port, properties=properties)
|
||||
if not m1_m2_agmt:
|
||||
log.fatal("Fail to create a supplier -> supplier replica agreement")
|
||||
@@ -147,10 +129,9 @@ def test_gssapi_repl(topology_m2):
|
||||
# Creating agreement from supplier 2 to supplier 1
|
||||
|
||||
# Set the replica bind method to sasl gssapi
|
||||
- properties = {RA_NAME: r'meTo_$host:$port',
|
||||
+ properties = {RA_NAME: 'meTo_' + supplier1.host + ':' + str(supplier1.port),
|
||||
RA_METHOD: 'SASL/GSSAPI',
|
||||
RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
|
||||
- supplier2.agreement.delete(suffix=SUFFIX, consumer_host=supplier1.host, consumer_port=supplier1.port)
|
||||
m2_m1_agmt = supplier2.agreement.create(suffix=SUFFIX, host=supplier1.host, port=supplier1.port, properties=properties)
|
||||
if not m2_m1_agmt:
|
||||
log.fatal("Fail to create a supplier -> supplier replica agreement")
|
||||
@@ -169,9 +150,15 @@ def test_gssapi_repl(topology_m2):
|
||||
|
||||
# Check replication is working...
|
||||
if supplier1.testReplication(DEFAULT_SUFFIX, supplier2):
|
||||
- log.info('Replication is working.')
|
||||
+ log.info('Replication is working: supplier1 -> supplier2')
|
||||
else:
|
||||
- log.fatal('Replication is not working.')
|
||||
+ log.fatal('Replication is not working: supplier1 -> supplier2')
|
||||
+ assert False
|
||||
+
|
||||
+ if supplier2.testReplication(DEFAULT_SUFFIX, supplier1):
|
||||
+ log.info('Replication is working: supplier2 -> supplier1')
|
||||
+ else:
|
||||
+ log.fatal('Replication is not working: supplier2 -> supplier1')
|
||||
assert False
|
||||
|
||||
# Add a user to supplier 1
|
||||
diff --git a/src/lib389/lib389/topologies.py b/src/lib389/lib389/topologies.py
|
||||
index 33341f669..84e620cb3 100644
|
||||
--- a/src/lib389/lib389/topologies.py
|
||||
+++ b/src/lib389/lib389/topologies.py
|
||||
@@ -499,6 +499,63 @@ def topology_m2(request):
|
||||
topology.logcap = LogCapture()
|
||||
return topology
|
||||
|
||||
+@pytest.fixture(scope="module")
|
||||
+def topology_m2_gssapi(request):
|
||||
+ """Create Replication Deployment with two suppliers with GSSAPI enabled.
|
||||
+
|
||||
+ Similar to topology_st_gssapi but for two suppliers. Configures Kerberos
|
||||
+ realm, principals and keytabs for ldap/ldapkdc1.<domain> and ldap/ldapkdc2.<domain>,
|
||||
+ SASL mappings, and disables SSL port on both instances so GSSAPI can be used.
|
||||
+ """
|
||||
+ hostname = socket.gethostname().split('.', 1)
|
||||
+ assert len(hostname) == 2
|
||||
+ domain = hostname[1]
|
||||
+ REALM = domain.upper()
|
||||
+ host_supplier_1 = 'ldapkdc1.' + domain
|
||||
+ host_supplier_2 = 'ldapkdc2.' + domain
|
||||
+
|
||||
+ topology = create_topology({ReplicaRole.SUPPLIER: 2}, request=request,
|
||||
+ cleanup_cb=lambda x: krb.destroy_realm())
|
||||
+
|
||||
+ supplier1 = topology.ms["supplier1"]
|
||||
+ supplier2 = topology.ms["supplier2"]
|
||||
+ supplier1.host = host_supplier_1
|
||||
+ supplier2.host = host_supplier_2
|
||||
+
|
||||
+ krb = MitKrb5(realm=REALM, debug=DEBUGGING)
|
||||
+ if krb.check_realm():
|
||||
+ krb.destroy_realm()
|
||||
+ krb.create_realm()
|
||||
+
|
||||
+ krb.create_principal(principal=f'ldap/{host_supplier_1}')
|
||||
+ krb.create_principal(principal=f'ldap/{host_supplier_2}')
|
||||
+ krb.create_keytab(principal=f'ldap/{host_supplier_1}', keytab='/etc/krb5.keytab')
|
||||
+ krb.create_keytab(principal=f'ldap/{host_supplier_2}', keytab='/etc/krb5.keytab')
|
||||
+
|
||||
+ os.chown('/etc/krb5.keytab', supplier1.get_user_uid(), supplier1.get_group_gid())
|
||||
+
|
||||
+ for inst, host in [(supplier1, host_supplier_1), (supplier2, host_supplier_2)]:
|
||||
+ saslmappings = SaslMappings(inst)
|
||||
+ for m in saslmappings.list():
|
||||
+ m.delete()
|
||||
+ saslmappings.create(properties={
|
||||
+ 'cn': 'suffix map',
|
||||
+ 'nsSaslMapRegexString': '\\(.*\\)',
|
||||
+ 'nsSaslMapBaseDNTemplate': inst.creation_suffix,
|
||||
+ 'nsSaslMapFilterTemplate': '(uid=\\1)'
|
||||
+ })
|
||||
+ inst.realm = krb
|
||||
+ inst.config.set('nsslapd-localhost', host)
|
||||
+ inst.sslport = None
|
||||
+
|
||||
+ supplier1.restart()
|
||||
+ supplier2.restart()
|
||||
+ supplier1.clearTmpDir(__file__)
|
||||
+ supplier2.clearTmpDir(__file__)
|
||||
+
|
||||
+ topology.logcap = LogCapture()
|
||||
+ return topology
|
||||
+
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def topology_m3(request):
|
||||
--
|
||||
2.52.0
|
||||
|
||||
260
0056-Issue-6753-Port-ticket-49039-test.patch
Normal file
260
0056-Issue-6753-Port-ticket-49039-test.patch
Normal file
@ -0,0 +1,260 @@
|
||||
From a4ae29afc6547e8231b933cfa1b95d7f7b37a25c Mon Sep 17 00:00:00 2001
|
||||
From: Lenka Doudova <lryznaro@redhat.com>
|
||||
Date: Tue, 10 Feb 2026 05:45:32 +0100
|
||||
Subject: [PATCH] Issue 6753 - Port ticket 49039 test
|
||||
|
||||
Description:
|
||||
Port ticket 49039 test into
|
||||
dirsrvtests/tests/suites/password/pwp_test.py
|
||||
|
||||
Relates: #6753
|
||||
Author: Lenka Doudova
|
||||
Assisted by: Cursor
|
||||
Reviewer: Barbora Simonova, Viktor Ashirov
|
||||
---
|
||||
dirsrvtests/tests/suites/password/pwp_test.py | 83 +++++++++++-
|
||||
dirsrvtests/tests/tickets/ticket49039_test.py | 127 ------------------
|
||||
2 files changed, 82 insertions(+), 128 deletions(-)
|
||||
delete mode 100644 dirsrvtests/tests/tickets/ticket49039_test.py
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/password/pwp_test.py b/dirsrvtests/tests/suites/password/pwp_test.py
|
||||
index 663d9bea9..6dae08cb2 100644
|
||||
--- a/dirsrvtests/tests/suites/password/pwp_test.py
|
||||
+++ b/dirsrvtests/tests/suites/password/pwp_test.py
|
||||
@@ -9,11 +9,14 @@
|
||||
"""
|
||||
|
||||
import os
|
||||
+import subprocess
|
||||
import pytest
|
||||
from lib389.topologies import topology_st as topo
|
||||
from lib389.idm.user import UserAccounts, UserAccount
|
||||
-from lib389._constants import DEFAULT_SUFFIX
|
||||
+from lib389.idm.directorymanager import DirectoryManager
|
||||
+from lib389._constants import DEFAULT_SUFFIX, PASSWORD
|
||||
from lib389.config import Config
|
||||
+from lib389.pwpolicy import PwPolicyManager
|
||||
from lib389.idm.group import Group
|
||||
from lib389.utils import ds_is_older
|
||||
import ldap
|
||||
@@ -512,6 +515,84 @@ def test_passwordlockout(topo, _fix_password):
|
||||
_change_password_with_own(topo, user.dn, 'dby3rs2', 'secreter')
|
||||
|
||||
|
||||
+def test_password_must_change_ignores_min_age(topo):
|
||||
+ """Test that passwordMinAge does not block password update when the password was reset.
|
||||
+
|
||||
+ :id: a1b2c3d4-e5f6-4903-9abc-def012345678
|
||||
+ :setup: Standalone instance
|
||||
+ :steps:
|
||||
+ 1. Enable TLS (for ldappasswd StartTLS)
|
||||
+ 2. Set global policy via PwPolicyManager: passwordMustChange, passwordExp,
|
||||
+ passwordMaxAge, passwordMinAge (high), passwordChange
|
||||
+ 3. Bind as Directory Manager
|
||||
+ 4. Create user
|
||||
+ 5. Reset user password as Directory Manager
|
||||
+ 6. User binds and changes own password (must succeed; min age must not block)
|
||||
+ 7. Rebind as Directory Manager, reset user password again
|
||||
+ 8. Run ldappasswd as user (StartTLS) to change password to password2
|
||||
+ 9. Bind as user with password2 to verify
|
||||
+ 10. Cleanup: delete user
|
||||
+ :expectedresults:
|
||||
+ 1. TLS enabled
|
||||
+ 2. Policy set successfully
|
||||
+ 3. Bind succeeds
|
||||
+ 4. User created
|
||||
+ 5. Reset succeeds
|
||||
+ 6. User password change succeeds (min age does not block after reset)
|
||||
+ 7. Reset succeeds
|
||||
+ 8. ldappasswd succeeds
|
||||
+ 9. Bind succeeds
|
||||
+ 10. User deleted
|
||||
+ """
|
||||
+
|
||||
+ topo.standalone.enable_tls()
|
||||
+
|
||||
+ policy = PwPolicyManager(topo.standalone)
|
||||
+ policy.set_global_policy(properties={'nsslapd-pwpolicy-local': 'on',
|
||||
+ 'passwordMustChange': 'on',
|
||||
+ 'passwordExp': 'on',
|
||||
+ 'passwordMaxAge': '86400000',
|
||||
+ 'passwordMinAge': '8640000',
|
||||
+ 'passwordChange': 'on'})
|
||||
+ dm = DirectoryManager(topo.standalone)
|
||||
+ dm.bind()
|
||||
+
|
||||
+ user = _create_user(topo, 'user', 'Test User', '1002', PASSWORD)
|
||||
+ try:
|
||||
+ # Reset password as Directory Manager
|
||||
+ user.replace('userpassword', PASSWORD)
|
||||
+ time.sleep(1)
|
||||
+
|
||||
+ # Reset password as user (must succeed; min age must not block after reset)
|
||||
+ user.rebind(PASSWORD)
|
||||
+ user.replace('userpassword', PASSWORD)
|
||||
+ time.sleep(1)
|
||||
+
|
||||
+ # Reset again as Directory Manager
|
||||
+ dm.rebind(PASSWORD)
|
||||
+ user.replace('userpassword', PASSWORD)
|
||||
+ time.sleep(1)
|
||||
+
|
||||
+ # Change password through ldappasswd as user to ensure functionality
|
||||
+ env = os.environ.copy()
|
||||
+ env['LDAPTLS_CACERTDIR'] = topo.standalone.get_cert_dir()
|
||||
+ cmd = [
|
||||
+ 'ldappasswd',
|
||||
+ '-ZZ','-H', f"ldap://{topo.standalone.host}:{topo.standalone.port}",
|
||||
+ '-D', user.dn, '-w', PASSWORD,
|
||||
+ '-a', PASSWORD, '-s', 'password2',
|
||||
+ user.dn,
|
||||
+ ]
|
||||
+ result = subprocess.run(cmd, env=env, capture_output=True, text=True)
|
||||
+ assert result.returncode == 0, f'ldappasswd failed: {result.stderr}'
|
||||
+
|
||||
+ # Bind as user with new password
|
||||
+ user.bind('password2')
|
||||
+ finally:
|
||||
+ dm.rebind(PASSWORD)
|
||||
+ user.delete()
|
||||
+
|
||||
+
|
||||
if __name__ == "__main__":
|
||||
CURRENT_FILE = os.path.realpath(__file__)
|
||||
pytest.main("-s -v %s" % CURRENT_FILE)
|
||||
diff --git a/dirsrvtests/tests/tickets/ticket49039_test.py b/dirsrvtests/tests/tickets/ticket49039_test.py
|
||||
deleted file mode 100644
|
||||
index 0313f69a3..000000000
|
||||
--- a/dirsrvtests/tests/tickets/ticket49039_test.py
|
||||
+++ /dev/null
|
||||
@@ -1,127 +0,0 @@
|
||||
-# --- BEGIN COPYRIGHT BLOCK ---
|
||||
-# Copyright (C) 2022 Red Hat, Inc.
|
||||
-# All rights reserved.
|
||||
-#
|
||||
-# License: GPL (version 3 or any later version).
|
||||
-# See LICENSE for details.
|
||||
-# --- END COPYRIGHT BLOCK ---
|
||||
-#
|
||||
-import time
|
||||
-import ldap
|
||||
-import logging
|
||||
-import pytest
|
||||
-import os
|
||||
-from lib389 import Entry
|
||||
-from lib389._constants import *
|
||||
-from lib389.properties import *
|
||||
-from lib389.tasks import *
|
||||
-from lib389.utils import *
|
||||
-from lib389.topologies import topology_st as topo
|
||||
-from lib389.pwpolicy import PwPolicyManager
|
||||
-
|
||||
-
|
||||
-pytestmark = pytest.mark.tier2
|
||||
-
|
||||
-DEBUGGING = os.getenv("DEBUGGING", default=False)
|
||||
-if DEBUGGING:
|
||||
- logging.getLogger(__name__).setLevel(logging.DEBUG)
|
||||
-else:
|
||||
- logging.getLogger(__name__).setLevel(logging.INFO)
|
||||
-log = logging.getLogger(__name__)
|
||||
-
|
||||
-USER_DN = 'uid=user,dc=example,dc=com'
|
||||
-
|
||||
-
|
||||
-def test_ticket49039(topo):
|
||||
- """Test "password must change" verses "password min age". Min age should not
|
||||
- block password update if the password was reset.
|
||||
- """
|
||||
-
|
||||
- # Setup SSL (for ldappasswd test)
|
||||
- topo.standalone.enable_tls()
|
||||
-
|
||||
- # Configure password policy
|
||||
- try:
|
||||
- policy = PwPolicyManager(topo.standalone)
|
||||
- policy.set_global_policy(properties={'nsslapd-pwpolicy-local': 'on',
|
||||
- 'passwordMustChange': 'on',
|
||||
- 'passwordExp': 'on',
|
||||
- 'passwordMaxAge': '86400000',
|
||||
- 'passwordMinAge': '8640000',
|
||||
- 'passwordChange': 'on'})
|
||||
- except ldap.LDAPError as e:
|
||||
- log.fatal('Failed to set password policy: ' + str(e))
|
||||
-
|
||||
- # Add user, bind, and set password
|
||||
- try:
|
||||
- topo.standalone.add_s(Entry((USER_DN, {
|
||||
- 'objectclass': 'top extensibleObject'.split(),
|
||||
- 'uid': 'user1',
|
||||
- 'userpassword': PASSWORD
|
||||
- })))
|
||||
- except ldap.LDAPError as e:
|
||||
- log.fatal('Failed to add user: error ' + e.args[0]['desc'])
|
||||
- assert False
|
||||
-
|
||||
- # Reset password as RootDN
|
||||
- try:
|
||||
- topo.standalone.modify_s(USER_DN, [(ldap.MOD_REPLACE, 'userpassword', ensure_bytes(PASSWORD))])
|
||||
- except ldap.LDAPError as e:
|
||||
- log.fatal('Failed to bind: error ' + e.args[0]['desc'])
|
||||
- assert False
|
||||
-
|
||||
- time.sleep(1)
|
||||
-
|
||||
- # Reset password as user
|
||||
- try:
|
||||
- topo.standalone.simple_bind_s(USER_DN, PASSWORD)
|
||||
- except ldap.LDAPError as e:
|
||||
- log.fatal('Failed to bind: error ' + e.args[0]['desc'])
|
||||
- assert False
|
||||
-
|
||||
- try:
|
||||
- topo.standalone.modify_s(USER_DN, [(ldap.MOD_REPLACE, 'userpassword', ensure_bytes(PASSWORD))])
|
||||
- except ldap.LDAPError as e:
|
||||
- log.fatal('Failed to change password: error ' + e.args[0]['desc'])
|
||||
- assert False
|
||||
-
|
||||
- ###################################
|
||||
- # Make sure ldappasswd also works
|
||||
- ###################################
|
||||
-
|
||||
- # Reset password as RootDN
|
||||
- try:
|
||||
- topo.standalone.simple_bind_s(DN_DM, PASSWORD)
|
||||
- except ldap.LDAPError as e:
|
||||
- log.fatal('Failed to bind as rootdn: error ' + e.args[0]['desc'])
|
||||
- assert False
|
||||
-
|
||||
- try:
|
||||
- topo.standalone.modify_s(USER_DN, [(ldap.MOD_REPLACE, 'userpassword', ensure_bytes(PASSWORD))])
|
||||
- except ldap.LDAPError as e:
|
||||
- log.fatal('Failed to bind: error ' + e.args[0]['desc'])
|
||||
- assert False
|
||||
-
|
||||
- time.sleep(1)
|
||||
-
|
||||
- # Run ldappasswd as the User.
|
||||
- os.environ["LDAPTLS_CACERTDIR"] = topo.standalone.get_cert_dir()
|
||||
- cmd = ('ldappasswd' + ' -h ' + topo.standalone.host + ' -Z -p 38901 -D ' + USER_DN +
|
||||
- ' -w password -a password -s password2 ' + USER_DN)
|
||||
- os.system(cmd)
|
||||
- time.sleep(1)
|
||||
-
|
||||
- try:
|
||||
- topo.standalone.simple_bind_s(USER_DN, "password2")
|
||||
- except ldap.LDAPError as e:
|
||||
- log.fatal('Failed to bind: error ' + e.args[0]['desc'])
|
||||
- assert False
|
||||
-
|
||||
- log.info('Test Passed')
|
||||
-
|
||||
-
|
||||
-if __name__ == '__main__':
|
||||
- # Run isolated
|
||||
- # -s for DEBUG mode
|
||||
- CURRENT_FILE = os.path.realpath(__file__)
|
||||
- pytest.main("-s %s" % CURRENT_FILE)
|
||||
--
|
||||
2.52.0
|
||||
|
||||
952
0057-Issue-5853-Update-concread-to-0.5.10.patch
Normal file
952
0057-Issue-5853-Update-concread-to-0.5.10.patch
Normal file
@ -0,0 +1,952 @@
|
||||
From 0e2d9c4288873446dcb3d8bff61c558ff2b6681a Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
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
|
||||
|
||||
@ -0,0 +1,86 @@
|
||||
From 8b4dbf35ace326e5b836982d428e7029313a2247 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
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
|
||||
|
||||
@ -0,0 +1,40 @@
|
||||
From ffe1909e69ab2aecef396f31cf95cdcecd992782 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
Date: Mon, 23 Feb 2026 12:10:32 -0500
|
||||
Subject: [PATCH] Issue 7273 - In a chaining environment binding as remote user
|
||||
causes an invalid error in the logs
|
||||
|
||||
Description:
|
||||
|
||||
In a database link/chaining environment you can bind as a remote user, and
|
||||
this triggers an error when trying to "upgrade_on_bind" as the user does not
|
||||
locally have a userpassword since it's remote. There is no strong case to
|
||||
log an error in this situation.
|
||||
|
||||
relates: http://github.com/389ds/389-ds-base/issues/7273
|
||||
|
||||
Reviewed by: vashirov(Thanks!)
|
||||
---
|
||||
ldap/servers/slapd/pw.c | 6 ++----
|
||||
1 file changed, 2 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/ldap/servers/slapd/pw.c b/ldap/servers/slapd/pw.c
|
||||
index c53ecf23d..88e32537d 100644
|
||||
--- a/ldap/servers/slapd/pw.c
|
||||
+++ b/ldap/servers/slapd/pw.c
|
||||
@@ -3564,10 +3564,8 @@ int32_t update_pw_encoding(Slapi_PBlock *orig_pb, Slapi_Entry *e, Slapi_DN *sdn,
|
||||
* Does the entry have a pw?
|
||||
*/
|
||||
if (e == NULL || slapi_entry_attr_find(e, SLAPI_USERPWD_ATTR, &pw) != 0 || pw == NULL) {
|
||||
- slapi_log_err(SLAPI_LOG_WARNING,
|
||||
- "update_pw_encoding", "Could not read password attribute on '%s'\n",
|
||||
- dn);
|
||||
- res = -1;
|
||||
+ /* The entry does not have a userpassword attribute so there is nothing to do.
|
||||
+ * This typically happens when chaining is involved. */
|
||||
goto free_and_return;
|
||||
}
|
||||
|
||||
--
|
||||
2.53.0
|
||||
|
||||
@ -0,0 +1,46 @@
|
||||
From 3a233116a564fc339aee1021913c995504951d86 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Pichugin <spichugi@redhat.com>
|
||||
Date: Tue, 24 Feb 2026 09:28:24 -0800
|
||||
Subject: [PATCH] Issue 7279 - UI - Fix typo in export certificate dialog
|
||||
(#7280)
|
||||
|
||||
Description: Fix typo "cetificate" -> "certificate" in the
|
||||
export certificate dialog message.
|
||||
|
||||
Fixes: https://github.com/389ds/389-ds-base/issues/7279
|
||||
|
||||
Reviewed by: @vashirov (Thanks!)
|
||||
---
|
||||
src/cockpit/389-console/po/ja.po | 2 +-
|
||||
src/cockpit/389-console/src/lib/security/securityModals.jsx | 2 +-
|
||||
2 files changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/cockpit/389-console/po/ja.po b/src/cockpit/389-console/po/ja.po
|
||||
index 27d21bf7a..12c10ded4 100644
|
||||
--- a/src/cockpit/389-console/po/ja.po
|
||||
+++ b/src/cockpit/389-console/po/ja.po
|
||||
@@ -11560,7 +11560,7 @@ msgstr "証明書のエクスポート:"
|
||||
#: src/lib/security/securityModals.jsx:58
|
||||
msgid ""
|
||||
"Enter the full path and file name, if the path portion is omitted the "
|
||||
-"cetificate is written to the server's certificate directory "
|
||||
+"certificate is written to the server's certificate directory "
|
||||
msgstr ""
|
||||
"ファイル名を含むフルパスを入力してください。パス部分を省略した場合、証明書は"
|
||||
"サーバの証明書ディレクトリに書き込まれます。"
|
||||
diff --git a/src/cockpit/389-console/src/lib/security/securityModals.jsx b/src/cockpit/389-console/src/lib/security/securityModals.jsx
|
||||
index 4d6631fd2..f32d47596 100644
|
||||
--- a/src/cockpit/389-console/src/lib/security/securityModals.jsx
|
||||
+++ b/src/cockpit/389-console/src/lib/security/securityModals.jsx
|
||||
@@ -55,7 +55,7 @@ export class ExportCertModal extends React.Component {
|
||||
}
|
||||
|
||||
const title = <>{_("Export Certificate:")} <i>{nickName}</i></>;
|
||||
- const desc = <>{_("Enter the full path and file name, if the path portion is omitted the cetificate is written to the server's certificate directory ")}<i>{certDir}</i></>;
|
||||
+ const desc = <>{_("Enter the full path and file name, if the path portion is omitted the certificate is written to the server's certificate directory ")}<i>{certDir}</i></>;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
--
|
||||
2.53.0
|
||||
|
||||
1178
0061-Issue-7275-UI-Improve-password-policy-field-validati.patch
Normal file
1178
0061-Issue-7275-UI-Improve-password-policy-field-validati.patch
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,34 @@
|
||||
From f4d8df66187c0d1db6c9f5c9aa55946a8564de4b Mon Sep 17 00:00:00 2001
|
||||
From: Sam Morris <sam@robots.org.uk>
|
||||
Date: Wed, 25 Feb 2026 12:30:01 +0000
|
||||
Subject: [PATCH] Issue 7246 - correct formatting of 'Gen as CSN' in dsctl
|
||||
get-nsstate output (#7247)
|
||||
|
||||
Description: CSNs are formatted as hexadecimal, but the replica id and
|
||||
sequence number are displayed in decomal.
|
||||
|
||||
Fix: use correct format specifiers for hexadecimal output.
|
||||
|
||||
Fixes: https://github.com/389ds/389-ds-base/issues/7246
|
||||
|
||||
Signed-off-by: Sam Morris <sam@robots.org.uk>
|
||||
---
|
||||
src/lib389/lib389/dseldif.py | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/lib389/lib389/dseldif.py b/src/lib389/lib389/dseldif.py
|
||||
index 7834d9468..eac17aa4c 100644
|
||||
--- a/src/lib389/lib389/dseldif.py
|
||||
+++ b/src/lib389/lib389/dseldif.py
|
||||
@@ -407,7 +407,7 @@ class DSEldif(DSLint):
|
||||
'endian': endian,
|
||||
'rid': str(rid),
|
||||
'gen_time': str(sampled_time),
|
||||
- 'gencsn': "%08x%04d%04d0000" % (sampled_time, seq_num, rid),
|
||||
+ 'gencsn': "%08x%04x%04x0000" % (sampled_time, seq_num, rid),
|
||||
'gen_time_str': time.ctime(sampled_time),
|
||||
'local_offset': str(local_offset),
|
||||
'local_offset_str': print_nice_time(local_offset),
|
||||
--
|
||||
2.53.0
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
From 582c4916a80660e3ea876ae4b6355a81c29a791d Mon Sep 17 00:00:00 2001
|
||||
From 2e424110def2e3998f6045e136fb0d43f47b7f5a Mon Sep 17 00:00:00 2001
|
||||
From: tbordaz <tbordaz@redhat.com>
|
||||
Date: Wed, 25 Feb 2026 14:06:42 +0100
|
||||
Subject: [PATCH] Security fix for CVE-2025-14905
|
||||
@ -17,7 +17,7 @@ References:
|
||||
1 file changed, 38 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/ldap/servers/slapd/schema.c b/ldap/servers/slapd/schema.c
|
||||
index 16f1861cf..ff92d2b33 100644
|
||||
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)
|
||||
@ -89,5 +89,5 @@ index 16f1861cf..ff92d2b33 100644
|
||||
/*
|
||||
* Overall strategy is to maintain a pointer to the next location in
|
||||
--
|
||||
2.52.0
|
||||
2.53.0
|
||||
|
||||
654
0064-Issue-7267-MDB_BAD_VALSIZE-error-when-updating-index.patch
Normal file
654
0064-Issue-7267-MDB_BAD_VALSIZE-error-when-updating-index.patch
Normal file
@ -0,0 +1,654 @@
|
||||
From c7e1eb08eb36fd9a16c745935f56fa4a4b2a99df Mon Sep 17 00:00:00 2001
|
||||
From: progier389 <progier@redhat.com>
|
||||
Date: Wed, 25 Feb 2026 18:00:24 +0100
|
||||
Subject: [PATCH] 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 <vashirov@redhat.com>
|
||||
|
||||
---------
|
||||
|
||||
Co-authored-by: Viktor Ashirov <vashirov@redhat.com>
|
||||
---
|
||||
.../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 | 43 +++++
|
||||
ldap/servers/slapd/slapi-private.h | 2 +
|
||||
10 files changed, 224 insertions(+), 144 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/indexes/regression_test.py b/dirsrvtests/tests/suites/indexes/regression_test.py
|
||||
index 8176d6db0..a4218a2b5 100644
|
||||
--- a/dirsrvtests/tests/suites/indexes/regression_test.py
|
||||
+++ b/dirsrvtests/tests/suites/indexes/regression_test.py
|
||||
@@ -1022,6 +1022,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 <config.h>
|
||||
#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 e23e7ff43..92aa1ddbb 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 a6cb10aec..489433801 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 65b29343e..b969790da 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
|
||||
@@ -1123,6 +1123,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:
|
||||
@@ -1758,6 +1774,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:
|
||||
@@ -3936,10 +3953,24 @@ dbmdb_import_writer(void*param)
|
||||
if (!txn) {
|
||||
MDB_STAT_STEP(stats, MDB_STAT_TXNSTART, stats_enabled);
|
||||
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, stats_enabled);
|
||||
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, stats_enabled);
|
||||
nextslot = slot->next;
|
||||
@@ -3953,6 +3984,9 @@ dbmdb_import_writer(void*param)
|
||||
rc = TXN_COMMIT(txn);
|
||||
MDB_STAT_STEP(stats, MDB_STAT_RUN, stats_enabled);
|
||||
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;
|
||||
@@ -3965,6 +3999,10 @@ dbmdb_import_writer(void*param)
|
||||
MDB_STAT_STEP(stats, MDB_STAT_RUN, stats_enabled);
|
||||
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) {
|
||||
@@ -3977,13 +4015,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, stats_enabled);
|
||||
|
||||
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 if (stats_enabled) {
|
||||
char buf[200];
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/index.c b/ldap/servers/slapd/back-ldbm/index.c
|
||||
index a5004be19..c108bce3c 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/index.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/index.c
|
||||
@@ -881,6 +881,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
|
||||
@@ -917,7 +978,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;
|
||||
|
||||
@@ -1028,36 +1088,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);
|
||||
@@ -1824,6 +1855,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,
|
||||
@@ -1842,15 +1874,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",
|
||||
@@ -1889,66 +1916,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];
|
||||
|
||||
@@ -1981,10 +1956,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 124810426..6655633fc 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/ldbm_attrcrypt.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/ldbm_attrcrypt.c
|
||||
@@ -1079,15 +1079,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];
|
||||
@@ -1101,16 +1101,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 30a7aa11f..c882dac7b 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
|
||||
+++ b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
|
||||
@@ -622,7 +622,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 80c07382a..93101494b 100644
|
||||
--- a/ldap/servers/slapd/log.c
|
||||
+++ b/ldap/servers/slapd/log.c
|
||||
@@ -93,6 +93,10 @@ static int slapi_log_map[] = {
|
||||
#define FLUSH PR_TRUE
|
||||
#define NO_FLUSH PR_FALSE
|
||||
|
||||
+#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
|
||||
*************************************************************************/
|
||||
@@ -3133,6 +3137,45 @@ 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 72f4cd6f0..2da37ff6e 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);
|
||||
+
|
||||
|
||||
/*
|
||||
* accesslog.c
|
||||
--
|
||||
2.53.0
|
||||
|
||||
291
0065-Issue-7271-implement-a-pre-close-plugin-function.patch
Normal file
291
0065-Issue-7271-implement-a-pre-close-plugin-function.patch
Normal file
@ -0,0 +1,291 @@
|
||||
From 6fc10eae5b44989c703b67bdca157202d35d8a92 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
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 | 8 +++--
|
||||
ldap/servers/slapd/pblock.c | 36 +++++++++++++------
|
||||
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, 74 insertions(+), 22 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 19c6d7e48..7a2ca2ae2 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).
|
||||
@@ -1416,6 +1416,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",
|
||||
@@ -3178,7 +3182,7 @@ void
|
||||
wait4certs_refresh(daemon_ports_t *ports)
|
||||
{
|
||||
/*
|
||||
- * Block listening and accept threads until
|
||||
+ * Block listening and accept threads until
|
||||
* certificates refresh is complete
|
||||
* Note:
|
||||
* Listening threads have a NULL ports
|
||||
diff --git a/ldap/servers/slapd/pblock.c b/ldap/servers/slapd/pblock.c
|
||||
index 24cb9b15e..3405e6da6 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 <config.h>
|
||||
@@ -1008,6 +1008,13 @@ slapi_pblock_get_plugin_close_fn(Slapi_PBlock *pblock, void *value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int32_t
|
||||
+slapi_pblock_get_plugin_pre_close_fn(Slapi_PBlock *pblock, void *value)
|
||||
+{
|
||||
+ (*(IFP *)value) = pblock->pb_plugin->plg_pre_close;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int32_t
|
||||
slapi_pblock_get_plugin_cleanup_fn(Slapi_PBlock *pblock, void *value)
|
||||
{
|
||||
@@ -4100,6 +4107,13 @@ slapi_pblock_set_plugin_close_fn(Slapi_PBlock *pblock, void *value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int32_t
|
||||
+slapi_pblock_set_plugin_pre_close_fn(Slapi_PBlock *pblock, void *value)
|
||||
+{
|
||||
+ pblock->pb_plugin->plg_pre_close = (IFP)value;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int32_t
|
||||
slapi_pblock_set_plugin_cleanup_fn(Slapi_PBlock *pblock, void *value)
|
||||
{
|
||||
@@ -6948,7 +6962,7 @@ static int32_t (*get_cbtable[])(Slapi_PBlock *, void *) = {
|
||||
slapi_pblock_get_plugin_db_abandon_fn,
|
||||
slapi_pblock_get_plugin_db_config_fn,
|
||||
slapi_pblock_get_plugin_close_fn,
|
||||
- NULL, /* slot 211 available */
|
||||
+ slapi_pblock_get_plugin_pre_close_fn,
|
||||
slapi_pblock_get_plugin_start_fn,
|
||||
slapi_pblock_get_plugin_db_seq_fn,
|
||||
slapi_pblock_get_plugin_db_entry_fn,
|
||||
@@ -8923,7 +8937,7 @@ static int32_t (*set_cbtable[])(Slapi_PBlock *, void *) = {
|
||||
slapi_pblock_set_plugin_db_abandon_fn,
|
||||
slapi_pblock_set_plugin_db_config_fn,
|
||||
slapi_pblock_set_plugin_close_fn,
|
||||
- NULL, /* slot 211 available */
|
||||
+ slapi_pblock_set_plugin_pre_close_fn,
|
||||
slapi_pblock_set_plugin_start_fn,
|
||||
slapi_pblock_set_plugin_db_seq_fn,
|
||||
slapi_pblock_set_plugin_db_entry_fn,
|
||||
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 455d6d718..ce7e4f047 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).
|
||||
@@ -997,6 +997,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 d494931c2..3e50f77b2 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:
|
||||
@@ -1046,6 +1046,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 85bbf8fa1..70677123d 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.
|
||||
*
|
||||
@@ -7085,6 +7085,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
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
From 5cc3edb9732784e8a3edb033962b6312f2bb7b55 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
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
|
||||
|
||||
4
389-ds-base-devel.README
Normal file
4
389-ds-base-devel.README
Normal file
@ -0,0 +1,4 @@
|
||||
For detailed information on developing plugins for 389 Directory Server visit
|
||||
|
||||
https://www.port389.org/docs/389ds/design/plugins.html
|
||||
https://github.com/389ds/389-ds-base/blob/main/src/slapi_r_plugin/README.md
|
||||
1233
389-ds-base.spec
Normal file
1233
389-ds-base.spec
Normal file
File diff suppressed because it is too large
Load Diff
3
389-ds-base.sysusers
Normal file
3
389-ds-base.sysusers
Normal file
@ -0,0 +1,3 @@
|
||||
#Type Name ID GECOS Home directory Shell
|
||||
g dirsrv 389
|
||||
u dirsrv 389:389 "user for 389-ds-base" /usr/share/dirsrv/ /sbin/nologin
|
||||
@ -3,39 +3,10 @@
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.24.2"
|
||||
name = "allocator-api2"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler2"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.7.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9"
|
||||
dependencies = [
|
||||
"getrandom 0.2.16",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
@ -50,24 +21,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.4.0"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||
|
||||
[[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",
|
||||
]
|
||||
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
@ -83,9 +39,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.9.1"
|
||||
version = "2.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
|
||||
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
@ -95,11 +51,13 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "cbindgen"
|
||||
version = "0.9.1"
|
||||
version = "0.26.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9daec6140ab4dcd38c3dd57e580b59a621172a526ac79f1527af760a55afeafd"
|
||||
checksum = "da6bc11b07529f16944307272d5bd9b22530bc7d05751717c9d416586cedab49"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"heck",
|
||||
"indexmap",
|
||||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -112,10 +70,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.25"
|
||||
version = "1.2.51"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0fc897dc1e865cc67c0e05a836d9d3f1df3cbe442aa4a9473b18e12624a4951"
|
||||
checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203"
|
||||
dependencies = [
|
||||
"find-msvc-tools",
|
||||
"jobserver",
|
||||
"libc",
|
||||
"shlex",
|
||||
@ -123,72 +82,49 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.34.0"
|
||||
version = "3.2.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
|
||||
checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"atty",
|
||||
"bitflags 1.3.2",
|
||||
"clap_lex",
|
||||
"indexmap",
|
||||
"strsim",
|
||||
"termcolor",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
"vec_map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
|
||||
dependencies = [
|
||||
"os_str_bytes",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "concread"
|
||||
version = "0.2.21"
|
||||
version = "0.5.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcc9816f5ac93ebd51c37f7f9a6bf2b40dfcd42978ad2aea5d542016e9244cf6"
|
||||
checksum = "6588e9e68e11207fb9a5aabd88765187969e6bcba98763c40bcad87b2a73e9f5"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"crossbeam",
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
"lru",
|
||||
"parking_lot",
|
||||
"rand",
|
||||
"smallvec",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"crossbeam-deque",
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-queue",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
|
||||
dependencies = [
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
"foldhash",
|
||||
"lru",
|
||||
"smallvec",
|
||||
"sptr",
|
||||
"tokio",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -238,10 +174,16 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.12"
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys",
|
||||
@ -266,6 +208,18 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "find-msvc-tools"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff"
|
||||
|
||||
[[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"
|
||||
@ -289,36 +243,44 @@ checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi 0.11.0+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"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"allocator-api2",
|
||||
"equivalent",
|
||||
"foldhash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
@ -329,35 +291,36 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.13"
|
||||
name = "indexmap"
|
||||
version = "1.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
|
||||
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"autocfg",
|
||||
"hashbrown 0.12.3",
|
||||
]
|
||||
|
||||
[[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 = "libc"
|
||||
version = "0.2.172"
|
||||
version = "0.2.179"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
||||
checksum = "c5a2d376baa530d1238d133232d15e239abad80d05838b4b59354e5268af431f"
|
||||
|
||||
[[package]]
|
||||
name = "librnsslapd"
|
||||
@ -380,58 +343,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"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"scopeguard",
|
||||
]
|
||||
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.7.8"
|
||||
version = "0.16.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e999beba7b6e8345721bd280141ed958096a2e4abdf74f67ff4ce49b4b54e47a"
|
||||
checksum = "a1dc47f592c06f33f8e3aea9591776ec7c9f9e4124778ff8a3c3b87159f7e593"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
"hashbrown 0.16.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
version = "2.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.36.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
@ -441,11 +376,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.10.0",
|
||||
"cfg-if",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
@ -462,14 +397,14 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[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",
|
||||
@ -478,29 +413,10 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.11.2"
|
||||
name = "os_str_bytes"
|
||||
version = "6.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
|
||||
dependencies = [
|
||||
"instant",
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"instant",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"winapi",
|
||||
]
|
||||
checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1"
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
@ -533,15 +449,6 @@ version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
|
||||
dependencies = [
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.20+deprecated"
|
||||
@ -550,9 +457,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.95"
|
||||
version = "1.0.105"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
|
||||
checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@ -572,123 +479,73 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.40"
|
||||
version = "1.0.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
|
||||
checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "r-efi"
|
||||
version = "5.2.0"
|
||||
version = "5.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom 0.2.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rsds"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
||||
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||
|
||||
[[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.10.0",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[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.101",
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[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]]
|
||||
@ -715,15 +572,21 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.15.0"
|
||||
version = "1.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
|
||||
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
||||
|
||||
[[package]]
|
||||
name = "sptr"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b9b39299b249ad65f3b7e96443bad61c02ca5cd3589f46cb6d610a0fd6c0d6a"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
@ -738,9 +601,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.101"
|
||||
version = "2.0.114"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
|
||||
checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@ -749,46 +612,39 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.20.0"
|
||||
version = "3.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1"
|
||||
checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"getrandom 0.3.3",
|
||||
"getrandom 0.3.4",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
name = "termcolor"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.16.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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",
|
||||
"tokio-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -801,16 +657,41 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.18"
|
||||
name = "tracing"
|
||||
version = "0.1.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||
checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
|
||||
dependencies = [
|
||||
"pin-project-lite",
|
||||
"tracing-attributes",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.14"
|
||||
name = "tracing-attributes"
|
||||
version = "0.1.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
|
||||
checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
@ -827,31 +708,19 @@ version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
version = "0.11.1+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.14.2+wasi-0.2.4"
|
||||
name = "wasip2"
|
||||
version = "1.0.1+wasi-0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
|
||||
checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7"
|
||||
dependencies = [
|
||||
"wit-bindgen-rt",
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -870,130 +739,64 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
name = "wit-bindgen"
|
||||
version = "0.46.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
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",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
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"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rt"
|
||||
version = "0.39.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.8.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.8.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.101",
|
||||
]
|
||||
checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59"
|
||||
|
||||
[[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.101",
|
||||
"syn 2.0.114",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zmij"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fc5a66a20078bf1251bde995aa2fdcc4b800c70b5d92dd2c62abc5c60f679f8"
|
||||
@ -1,119 +0,0 @@
|
||||
From dddb14210b402f317e566b6387c76a8e659bf7fa Mon Sep 17 00:00:00 2001
|
||||
From: progier389 <progier@redhat.com>
|
||||
Date: Tue, 14 Feb 2023 13:34:10 +0100
|
||||
Subject: [PATCH 1/2] issue 5647 - covscan: memory leak in audit log when
|
||||
adding entries (#5650)
|
||||
|
||||
covscan reported an issue about "vals" variable in auditlog.c:231 and indeed a charray_free is missing.
|
||||
Issue: 5647
|
||||
Reviewed by: @mreynolds389, @droideck
|
||||
---
|
||||
ldap/servers/slapd/auditlog.c | 71 +++++++++++++++++++----------------
|
||||
1 file changed, 38 insertions(+), 33 deletions(-)
|
||||
|
||||
diff --git a/ldap/servers/slapd/auditlog.c b/ldap/servers/slapd/auditlog.c
|
||||
index 68cbc674d..3128e0497 100644
|
||||
--- a/ldap/servers/slapd/auditlog.c
|
||||
+++ b/ldap/servers/slapd/auditlog.c
|
||||
@@ -177,6 +177,40 @@ write_auditfail_log_entry(Slapi_PBlock *pb)
|
||||
slapi_ch_free_string(&audit_config);
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Write the attribute values to the audit log as "comments"
|
||||
+ *
|
||||
+ * Slapi_Attr *entry - the attribute begin logged.
|
||||
+ * char *attrname - the attribute name.
|
||||
+ * lenstr *l - the audit log buffer
|
||||
+ *
|
||||
+ * Resulting output in the log:
|
||||
+ *
|
||||
+ * #ATTR: VALUE
|
||||
+ * #ATTR: VALUE
|
||||
+ */
|
||||
+static void
|
||||
+log_entry_attr(Slapi_Attr *entry_attr, char *attrname, lenstr *l)
|
||||
+{
|
||||
+ Slapi_Value **vals = attr_get_present_values(entry_attr);
|
||||
+ for(size_t i = 0; vals && vals[i]; i++) {
|
||||
+ char log_val[256] = "";
|
||||
+ const struct berval *bv = slapi_value_get_berval(vals[i]);
|
||||
+ if (bv->bv_len >= 256) {
|
||||
+ strncpy(log_val, bv->bv_val, 252);
|
||||
+ strcpy(log_val+252, "...");
|
||||
+ } else {
|
||||
+ strncpy(log_val, bv->bv_val, bv->bv_len);
|
||||
+ log_val[bv->bv_len] = 0;
|
||||
+ }
|
||||
+ addlenstr(l, "#");
|
||||
+ addlenstr(l, attrname);
|
||||
+ addlenstr(l, ": ");
|
||||
+ addlenstr(l, log_val);
|
||||
+ addlenstr(l, "\n");
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Write "requested" attributes from the entry to the audit log as "comments"
|
||||
*
|
||||
@@ -212,21 +246,9 @@ add_entry_attrs(Slapi_Entry *entry, lenstr *l)
|
||||
for (req_attr = ldap_utf8strtok_r(display_attrs, ", ", &last); req_attr;
|
||||
req_attr = ldap_utf8strtok_r(NULL, ", ", &last))
|
||||
{
|
||||
- char **vals = slapi_entry_attr_get_charray(entry, req_attr);
|
||||
- for(size_t i = 0; vals && vals[i]; i++) {
|
||||
- char log_val[256] = {0};
|
||||
-
|
||||
- if (strlen(vals[i]) > 256) {
|
||||
- strncpy(log_val, vals[i], 252);
|
||||
- strcat(log_val, "...");
|
||||
- } else {
|
||||
- strcpy(log_val, vals[i]);
|
||||
- }
|
||||
- addlenstr(l, "#");
|
||||
- addlenstr(l, req_attr);
|
||||
- addlenstr(l, ": ");
|
||||
- addlenstr(l, log_val);
|
||||
- addlenstr(l, "\n");
|
||||
+ slapi_entry_attr_find(entry, req_attr, &entry_attr);
|
||||
+ if (entry_attr) {
|
||||
+ log_entry_attr(entry_attr, req_attr, l);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -234,7 +256,6 @@ add_entry_attrs(Slapi_Entry *entry, lenstr *l)
|
||||
for (; entry_attr; entry_attr = entry_attr->a_next) {
|
||||
Slapi_Value **vals = attr_get_present_values(entry_attr);
|
||||
char *attr = NULL;
|
||||
- const char *val = NULL;
|
||||
|
||||
slapi_attr_get_type(entry_attr, &attr);
|
||||
if (strcmp(attr, PSEUDO_ATTR_UNHASHEDUSERPASSWORD) == 0) {
|
||||
@@ -251,23 +272,7 @@ add_entry_attrs(Slapi_Entry *entry, lenstr *l)
|
||||
addlenstr(l, ": ****************************\n");
|
||||
continue;
|
||||
}
|
||||
-
|
||||
- for(size_t i = 0; vals && vals[i]; i++) {
|
||||
- char log_val[256] = {0};
|
||||
-
|
||||
- val = slapi_value_get_string(vals[i]);
|
||||
- if (strlen(val) > 256) {
|
||||
- strncpy(log_val, val, 252);
|
||||
- strcat(log_val, "...");
|
||||
- } else {
|
||||
- strcpy(log_val, val);
|
||||
- }
|
||||
- addlenstr(l, "#");
|
||||
- addlenstr(l, attr);
|
||||
- addlenstr(l, ": ");
|
||||
- addlenstr(l, log_val);
|
||||
- addlenstr(l, "\n");
|
||||
- }
|
||||
+ log_entry_attr(entry_attr, attr, l);
|
||||
}
|
||||
}
|
||||
slapi_ch_free_string(&display_attrs);
|
||||
--
|
||||
2.43.0
|
||||
|
||||
@ -1,27 +0,0 @@
|
||||
From be7c2b82958e91ce08775bf6b5da3c311d3b00e5 Mon Sep 17 00:00:00 2001
|
||||
From: progier389 <progier@redhat.com>
|
||||
Date: Mon, 20 Feb 2023 16:14:05 +0100
|
||||
Subject: [PATCH 2/2] Issue 5647 - Fix unused variable warning from previous
|
||||
commit (#5670)
|
||||
|
||||
* issue 5647 - memory leak in audit log when adding entries
|
||||
* Issue 5647 - Fix unused variable warning from previous commit
|
||||
---
|
||||
ldap/servers/slapd/auditlog.c | 1 -
|
||||
1 file changed, 1 deletion(-)
|
||||
|
||||
diff --git a/ldap/servers/slapd/auditlog.c b/ldap/servers/slapd/auditlog.c
|
||||
index 3128e0497..0597ecc6f 100644
|
||||
--- a/ldap/servers/slapd/auditlog.c
|
||||
+++ b/ldap/servers/slapd/auditlog.c
|
||||
@@ -254,7 +254,6 @@ add_entry_attrs(Slapi_Entry *entry, lenstr *l)
|
||||
} else {
|
||||
/* Return all attributes */
|
||||
for (; entry_attr; entry_attr = entry_attr->a_next) {
|
||||
- Slapi_Value **vals = attr_get_present_values(entry_attr);
|
||||
char *attr = NULL;
|
||||
|
||||
slapi_attr_get_type(entry_attr, &attr);
|
||||
--
|
||||
2.43.0
|
||||
|
||||
@ -1,147 +0,0 @@
|
||||
From 692c4cec6cc5c0086cf58f83bcfa690c766c9887 Mon Sep 17 00:00:00 2001
|
||||
From: Thierry Bordaz <tbordaz@redhat.com>
|
||||
Date: Fri, 2 Feb 2024 14:14:28 +0100
|
||||
Subject: [PATCH] Issue 5407 - sync_repl crashes if enabled while dynamic
|
||||
plugin is enabled (#5411)
|
||||
|
||||
Bug description:
|
||||
When dynamic plugin is enabled, if a MOD enables sync_repl plugin
|
||||
then sync_repl init function registers the postop callback
|
||||
that will be called for the MOD itself while the preop
|
||||
has not been called.
|
||||
postop expects preop to be called and so primary operation
|
||||
to be set. When it is not set it crashes
|
||||
|
||||
Fix description:
|
||||
If the primary operation is not set, just return
|
||||
|
||||
relates: #5407
|
||||
---
|
||||
.../suites/syncrepl_plugin/basic_test.py | 68 +++++++++++++++++++
|
||||
ldap/servers/plugins/sync/sync_persist.c | 23 ++++++-
|
||||
2 files changed, 90 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/syncrepl_plugin/basic_test.py b/dirsrvtests/tests/suites/syncrepl_plugin/basic_test.py
|
||||
index eb3770b78..cdf35eeaa 100644
|
||||
--- a/dirsrvtests/tests/suites/syncrepl_plugin/basic_test.py
|
||||
+++ b/dirsrvtests/tests/suites/syncrepl_plugin/basic_test.py
|
||||
@@ -592,6 +592,74 @@ def test_sync_repl_cenotaph(topo_m2, request):
|
||||
|
||||
request.addfinalizer(fin)
|
||||
|
||||
+def test_sync_repl_dynamic_plugin(topology, request):
|
||||
+ """Test sync_repl with dynamic plugin
|
||||
+
|
||||
+ :id: d4f84913-c18a-459f-8525-110f610ca9e6
|
||||
+ :setup: install a standalone instance
|
||||
+ :steps:
|
||||
+ 1. reset instance to standard (no retroCL, no sync_repl, no dynamic plugin)
|
||||
+ 2. Enable dynamic plugin
|
||||
+ 3. Enable retroCL/content_sync
|
||||
+ 4. Establish a sync_repl req
|
||||
+ :expectedresults:
|
||||
+ 1. Should succeeds
|
||||
+ 2. Should succeeds
|
||||
+ 3. Should succeeds
|
||||
+ 4. Should succeeds
|
||||
+ """
|
||||
+
|
||||
+ # Reset the instance in a default config
|
||||
+ # Disable content sync plugin
|
||||
+ topology.standalone.plugins.disable(name=PLUGIN_REPL_SYNC)
|
||||
+
|
||||
+ # Disable retro changelog
|
||||
+ topology.standalone.plugins.disable(name=PLUGIN_RETRO_CHANGELOG)
|
||||
+
|
||||
+ # Disable dynamic plugins
|
||||
+ topology.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'nsslapd-dynamic-plugins', b'off')])
|
||||
+ topology.standalone.restart()
|
||||
+
|
||||
+ # Now start the test
|
||||
+ # Enable dynamic plugins
|
||||
+ try:
|
||||
+ topology.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'nsslapd-dynamic-plugins', b'on')])
|
||||
+ except ldap.LDAPError as e:
|
||||
+ log.error('Failed to enable dynamic plugin! {}'.format(e.args[0]['desc']))
|
||||
+ assert False
|
||||
+
|
||||
+ # Enable retro changelog
|
||||
+ topology.standalone.plugins.enable(name=PLUGIN_RETRO_CHANGELOG)
|
||||
+
|
||||
+ # Enbale content sync plugin
|
||||
+ topology.standalone.plugins.enable(name=PLUGIN_REPL_SYNC)
|
||||
+
|
||||
+ # create a sync repl client and wait 5 seconds to be sure it is running
|
||||
+ sync_repl = Sync_persist(topology.standalone)
|
||||
+ sync_repl.start()
|
||||
+ time.sleep(5)
|
||||
+
|
||||
+ # create users
|
||||
+ users = UserAccounts(topology.standalone, DEFAULT_SUFFIX)
|
||||
+ users_set = []
|
||||
+ for i in range(10001, 10004):
|
||||
+ users_set.append(users.create_test_user(uid=i))
|
||||
+
|
||||
+ time.sleep(10)
|
||||
+ # delete users, that automember/memberof will generate nested updates
|
||||
+ for user in users_set:
|
||||
+ user.delete()
|
||||
+ # stop the server to get the sync_repl result set (exit from while loop).
|
||||
+ # Only way I found to acheive that.
|
||||
+ # and wait a bit to let sync_repl thread time to set its result before fetching it.
|
||||
+ topology.standalone.stop()
|
||||
+ sync_repl.get_result()
|
||||
+ sync_repl.join()
|
||||
+ log.info('test_sync_repl_dynamic_plugin: PASS\n')
|
||||
+
|
||||
+ # Success
|
||||
+ log.info('Test complete')
|
||||
+
|
||||
def test_sync_repl_invalid_cookie(topology, request):
|
||||
"""Test sync_repl with invalid cookie
|
||||
|
||||
diff --git a/ldap/servers/plugins/sync/sync_persist.c b/ldap/servers/plugins/sync/sync_persist.c
|
||||
index d2210b64c..283607361 100644
|
||||
--- a/ldap/servers/plugins/sync/sync_persist.c
|
||||
+++ b/ldap/servers/plugins/sync/sync_persist.c
|
||||
@@ -156,6 +156,17 @@ ignore_op_pl(Slapi_PBlock *pb)
|
||||
* This is the same for ident
|
||||
*/
|
||||
prim_op = get_thread_primary_op();
|
||||
+ if (prim_op == NULL) {
|
||||
+ /* This can happen if the PRE_OP (sync_update_persist_betxn_pre_op) was not called.
|
||||
+ * The only known case it happens is with dynamic plugin enabled and an
|
||||
+ * update that enable the sync_repl plugin. In such case sync_repl registers
|
||||
+ * the postop (sync_update_persist_op) that is called while the preop was not called
|
||||
+ */
|
||||
+ slapi_log_err(SLAPI_LOG_PLUGIN, SYNC_PLUGIN_SUBSYSTEM,
|
||||
+ "ignore_op_pl - Operation without primary op set (0x%lx)\n",
|
||||
+ (ulong) op);
|
||||
+ return;
|
||||
+ }
|
||||
ident = sync_persist_get_operation_extension(pb);
|
||||
|
||||
if (ident) {
|
||||
@@ -232,8 +243,18 @@ sync_update_persist_op(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eprev, ber
|
||||
|
||||
|
||||
prim_op = get_thread_primary_op();
|
||||
+ if (prim_op == NULL) {
|
||||
+ /* This can happen if the PRE_OP (sync_update_persist_betxn_pre_op) was not called.
|
||||
+ * The only known case it happens is with dynamic plugin enabled and an
|
||||
+ * update that enable the sync_repl plugin. In such case sync_repl registers
|
||||
+ * the postop (sync_update_persist_op) that is called while the preop was not called
|
||||
+ */
|
||||
+ slapi_log_err(SLAPI_LOG_PLUGIN, SYNC_PLUGIN_SUBSYSTEM,
|
||||
+ "sync_update_persist_op - Operation without primary op set (0x%lx)\n",
|
||||
+ (ulong) pb_op);
|
||||
+ return;
|
||||
+ }
|
||||
ident = sync_persist_get_operation_extension(pb);
|
||||
- PR_ASSERT(prim_op);
|
||||
|
||||
if ((ident == NULL) && operation_is_flag_set(pb_op, OP_FLAG_NOOP)) {
|
||||
/* This happens for URP (add cenotaph, fixup rename, tombstone resurrect)
|
||||
--
|
||||
2.43.0
|
||||
|
||||
@ -1,840 +0,0 @@
|
||||
From 8dc61a176323f0d41df730abd715ccff3034c2be Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
Date: Sun, 27 Nov 2022 09:37:19 -0500
|
||||
Subject: [PATCH] Issue 5547 - automember plugin improvements
|
||||
|
||||
Description:
|
||||
|
||||
Rebuild task has the following improvements:
|
||||
|
||||
- Only one task allowed at a time
|
||||
- Do not cleanup previous members by default. Add new CLI option to intentionally
|
||||
cleanup memberships before rebuilding from scratch.
|
||||
- Add better task logging to show fixup progress
|
||||
|
||||
To prevent automember from being called in a nested be_txn loop thread storage is
|
||||
used to check and skip these loops.
|
||||
|
||||
relates: https://github.com/389ds/389-ds-base/issues/5547
|
||||
|
||||
Reviewed by: spichugi(Thanks!)
|
||||
---
|
||||
.../automember_plugin/automember_mod_test.py | 43 +++-
|
||||
ldap/servers/plugins/automember/automember.c | 232 ++++++++++++++----
|
||||
ldap/servers/slapd/back-ldbm/ldbm_add.c | 11 +-
|
||||
ldap/servers/slapd/back-ldbm/ldbm_delete.c | 10 +-
|
||||
ldap/servers/slapd/back-ldbm/ldbm_modify.c | 11 +-
|
||||
.../lib389/cli_conf/plugins/automember.py | 10 +-
|
||||
src/lib389/lib389/plugins.py | 7 +-
|
||||
src/lib389/lib389/tasks.py | 9 +-
|
||||
8 files changed, 250 insertions(+), 83 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/automember_plugin/automember_mod_test.py b/dirsrvtests/tests/suites/automember_plugin/automember_mod_test.py
|
||||
index 8d25384bf..7a0ed3275 100644
|
||||
--- a/dirsrvtests/tests/suites/automember_plugin/automember_mod_test.py
|
||||
+++ b/dirsrvtests/tests/suites/automember_plugin/automember_mod_test.py
|
||||
@@ -5,12 +5,13 @@
|
||||
# License: GPL (version 3 or any later version).
|
||||
# See LICENSE for details.
|
||||
# --- END COPYRIGHT BLOCK ---
|
||||
-#
|
||||
+import ldap
|
||||
import logging
|
||||
import pytest
|
||||
import os
|
||||
+import time
|
||||
from lib389.utils import ds_is_older
|
||||
-from lib389._constants import *
|
||||
+from lib389._constants import DEFAULT_SUFFIX
|
||||
from lib389.plugins import AutoMembershipPlugin, AutoMembershipDefinitions
|
||||
from lib389.idm.user import UserAccounts
|
||||
from lib389.idm.group import Groups
|
||||
@@ -41,6 +42,11 @@ def automember_fixture(topo, request):
|
||||
user_accts = UserAccounts(topo.standalone, DEFAULT_SUFFIX)
|
||||
user = user_accts.create_test_user()
|
||||
|
||||
+ # Create extra users
|
||||
+ users = UserAccounts(topo.standalone, DEFAULT_SUFFIX)
|
||||
+ for i in range(0, 100):
|
||||
+ users.create_test_user(uid=i)
|
||||
+
|
||||
# Create automember definitions and regex rules
|
||||
automember_prop = {
|
||||
'cn': 'testgroup_definition',
|
||||
@@ -59,7 +65,7 @@ def automember_fixture(topo, request):
|
||||
automemberplugin.enable()
|
||||
topo.standalone.restart()
|
||||
|
||||
- return (user, groups)
|
||||
+ return user, groups
|
||||
|
||||
|
||||
def test_mods(automember_fixture, topo):
|
||||
@@ -72,19 +78,21 @@ def test_mods(automember_fixture, topo):
|
||||
2. Update user that should add it to group[1]
|
||||
3. Update user that should add it to group[2]
|
||||
4. Update user that should add it to group[0]
|
||||
- 5. Test rebuild task correctly moves user to group[1]
|
||||
+ 5. Test rebuild task adds user to group[1]
|
||||
+ 6. Test rebuild task cleanups groups and only adds it to group[1]
|
||||
:expectedresults:
|
||||
1. Success
|
||||
2. Success
|
||||
3. Success
|
||||
4. Success
|
||||
5. Success
|
||||
+ 6. Success
|
||||
"""
|
||||
(user, groups) = automember_fixture
|
||||
|
||||
# Update user which should go into group[0]
|
||||
user.replace('cn', 'whatever')
|
||||
- groups[0].is_member(user.dn)
|
||||
+ assert groups[0].is_member(user.dn)
|
||||
if groups[1].is_member(user.dn):
|
||||
assert False
|
||||
if groups[2].is_member(user.dn):
|
||||
@@ -92,7 +100,7 @@ def test_mods(automember_fixture, topo):
|
||||
|
||||
# Update user0 which should go into group[1]
|
||||
user.replace('cn', 'mark')
|
||||
- groups[1].is_member(user.dn)
|
||||
+ assert groups[1].is_member(user.dn)
|
||||
if groups[0].is_member(user.dn):
|
||||
assert False
|
||||
if groups[2].is_member(user.dn):
|
||||
@@ -100,7 +108,7 @@ def test_mods(automember_fixture, topo):
|
||||
|
||||
# Update user which should go into group[2]
|
||||
user.replace('cn', 'simon')
|
||||
- groups[2].is_member(user.dn)
|
||||
+ assert groups[2].is_member(user.dn)
|
||||
if groups[0].is_member(user.dn):
|
||||
assert False
|
||||
if groups[1].is_member(user.dn):
|
||||
@@ -108,7 +116,7 @@ def test_mods(automember_fixture, topo):
|
||||
|
||||
# Update user which should go back into group[0] (full circle)
|
||||
user.replace('cn', 'whatever')
|
||||
- groups[0].is_member(user.dn)
|
||||
+ assert groups[0].is_member(user.dn)
|
||||
if groups[1].is_member(user.dn):
|
||||
assert False
|
||||
if groups[2].is_member(user.dn):
|
||||
@@ -128,12 +136,24 @@ def test_mods(automember_fixture, topo):
|
||||
automemberplugin.enable()
|
||||
topo.standalone.restart()
|
||||
|
||||
- # Run rebuild task
|
||||
+ # Run rebuild task (no cleanup)
|
||||
task = automemberplugin.fixup(DEFAULT_SUFFIX, "objectclass=posixaccount")
|
||||
+ with pytest.raises(ldap.UNWILLING_TO_PERFORM):
|
||||
+ # test only one fixup task is allowed at a time
|
||||
+ automemberplugin.fixup(DEFAULT_SUFFIX, "objectclass=top")
|
||||
task.wait()
|
||||
|
||||
- # Test membership
|
||||
- groups[1].is_member(user.dn)
|
||||
+ # Test membership (user should still be in groups[0])
|
||||
+ assert groups[1].is_member(user.dn)
|
||||
+ if not groups[0].is_member(user.dn):
|
||||
+ assert False
|
||||
+
|
||||
+ # Run rebuild task with cleanup
|
||||
+ task = automemberplugin.fixup(DEFAULT_SUFFIX, "objectclass=posixaccount", cleanup=True)
|
||||
+ task.wait()
|
||||
+
|
||||
+ # Test membership (user should only be in groups[1])
|
||||
+ assert groups[1].is_member(user.dn)
|
||||
if groups[0].is_member(user.dn):
|
||||
assert False
|
||||
if groups[2].is_member(user.dn):
|
||||
@@ -148,4 +168,3 @@ if __name__ == '__main__':
|
||||
# -s for DEBUG mode
|
||||
CURRENT_FILE = os.path.realpath(__file__)
|
||||
pytest.main(["-s", CURRENT_FILE])
|
||||
-
|
||||
diff --git a/ldap/servers/plugins/automember/automember.c b/ldap/servers/plugins/automember/automember.c
|
||||
index 3494d0343..419adb052 100644
|
||||
--- a/ldap/servers/plugins/automember/automember.c
|
||||
+++ b/ldap/servers/plugins/automember/automember.c
|
||||
@@ -1,5 +1,5 @@
|
||||
/** BEGIN COPYRIGHT BLOCK
|
||||
- * Copyright (C) 2011 Red Hat, Inc.
|
||||
+ * Copyright (C) 2022 Red Hat, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* License: GPL (version 3 or any later version).
|
||||
@@ -14,7 +14,7 @@
|
||||
* Auto Membership Plug-in
|
||||
*/
|
||||
#include "automember.h"
|
||||
-
|
||||
+#include <pthread.h>
|
||||
|
||||
/*
|
||||
* Plug-in globals
|
||||
@@ -22,7 +22,9 @@
|
||||
static PRCList *g_automember_config = NULL;
|
||||
static Slapi_RWLock *g_automember_config_lock = NULL;
|
||||
static uint64_t abort_rebuild_task = 0;
|
||||
-
|
||||
+static pthread_key_t td_automem_block_nested;
|
||||
+static PRBool fixup_running = PR_FALSE;
|
||||
+static PRLock *fixup_lock = NULL;
|
||||
static void *_PluginID = NULL;
|
||||
static Slapi_DN *_PluginDN = NULL;
|
||||
static Slapi_DN *_ConfigAreaDN = NULL;
|
||||
@@ -93,9 +95,43 @@ static void automember_task_export_destructor(Slapi_Task *task);
|
||||
static void automember_task_map_destructor(Slapi_Task *task);
|
||||
|
||||
#define DEFAULT_FILE_MODE PR_IRUSR | PR_IWUSR
|
||||
+#define FIXUP_PROGRESS_LIMIT 1000
|
||||
static uint64_t plugin_do_modify = 0;
|
||||
static uint64_t plugin_is_betxn = 0;
|
||||
|
||||
+/* automember_plugin fixup task and add operations should block other be_txn
|
||||
+ * plugins from calling automember_post_op_mod() */
|
||||
+static int32_t
|
||||
+slapi_td_block_nested_post_op(void)
|
||||
+{
|
||||
+ int32_t val = 12345;
|
||||
+
|
||||
+ if (pthread_setspecific(td_automem_block_nested, (void *)&val) != 0) {
|
||||
+ return PR_FAILURE;
|
||||
+ }
|
||||
+ return PR_SUCCESS;
|
||||
+}
|
||||
+
|
||||
+static int32_t
|
||||
+slapi_td_unblock_nested_post_op(void)
|
||||
+{
|
||||
+ if (pthread_setspecific(td_automem_block_nested, NULL) != 0) {
|
||||
+ return PR_FAILURE;
|
||||
+ }
|
||||
+ return PR_SUCCESS;
|
||||
+}
|
||||
+
|
||||
+static int32_t
|
||||
+slapi_td_is_post_op_nested(void)
|
||||
+{
|
||||
+ int32_t *value = pthread_getspecific(td_automem_block_nested);
|
||||
+
|
||||
+ if (value == NULL) {
|
||||
+ return 0;
|
||||
+ }
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Config cache locking functions
|
||||
*/
|
||||
@@ -317,6 +353,14 @@ automember_start(Slapi_PBlock *pb)
|
||||
return -1;
|
||||
}
|
||||
|
||||
+ if (fixup_lock == NULL) {
|
||||
+ if ((fixup_lock = PR_NewLock()) == NULL) {
|
||||
+ slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
+ "automember_start - Failed to create fixup lock.\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
/*
|
||||
* Get the plug-in target dn from the system
|
||||
* and store it for future use. */
|
||||
@@ -360,6 +404,11 @@ automember_start(Slapi_PBlock *pb)
|
||||
}
|
||||
}
|
||||
|
||||
+ if (pthread_key_create(&td_automem_block_nested, NULL) != 0) {
|
||||
+ slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
+ "automember_start - pthread_key_create failed\n");
|
||||
+ }
|
||||
+
|
||||
slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
"automember_start - ready for service\n");
|
||||
slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
@@ -394,6 +443,8 @@ automember_close(Slapi_PBlock *pb __attribute__((unused)))
|
||||
slapi_sdn_free(&_ConfigAreaDN);
|
||||
slapi_destroy_rwlock(g_automember_config_lock);
|
||||
g_automember_config_lock = NULL;
|
||||
+ PR_DestroyLock(fixup_lock);
|
||||
+ fixup_lock = NULL;
|
||||
|
||||
slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
"<-- automember_close\n");
|
||||
@@ -1619,7 +1670,6 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
-
|
||||
/*
|
||||
* automember_update_member_value()
|
||||
*
|
||||
@@ -1634,7 +1684,7 @@ automember_update_member_value(Slapi_Entry *member_e, const char *group_dn, char
|
||||
LDAPMod *mods[2];
|
||||
char *vals[2];
|
||||
char *member_value = NULL;
|
||||
- int rc = 0;
|
||||
+ int rc = LDAP_SUCCESS;
|
||||
Slapi_DN *group_sdn;
|
||||
|
||||
/* First thing check that the group still exists */
|
||||
@@ -1653,7 +1703,7 @@ automember_update_member_value(Slapi_Entry *member_e, const char *group_dn, char
|
||||
"automember_update_member_value - group (default or target) can not be retrieved (%s) err=%d\n",
|
||||
group_dn, rc);
|
||||
}
|
||||
- return rc;
|
||||
+ goto out;
|
||||
}
|
||||
|
||||
/* If grouping_value is dn, we need to fetch the dn instead. */
|
||||
@@ -1879,6 +1929,13 @@ automember_mod_post_op(Slapi_PBlock *pb)
|
||||
PRCList *list = NULL;
|
||||
int rc = SLAPI_PLUGIN_SUCCESS;
|
||||
|
||||
+ if (slapi_td_is_post_op_nested()) {
|
||||
+ /* don't process op twice in the same thread */
|
||||
+ return rc;
|
||||
+ } else {
|
||||
+ slapi_td_block_nested_post_op();
|
||||
+ }
|
||||
+
|
||||
slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
"--> automember_mod_post_op\n");
|
||||
|
||||
@@ -2005,6 +2062,7 @@ automember_mod_post_op(Slapi_PBlock *pb)
|
||||
}
|
||||
}
|
||||
}
|
||||
+ slapi_td_unblock_nested_post_op();
|
||||
|
||||
slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
"<-- automember_mod_post_op (%d)\n", rc);
|
||||
@@ -2024,6 +2082,13 @@ automember_add_post_op(Slapi_PBlock *pb)
|
||||
slapi_log_err(SLAPI_LOG_TRACE, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
"--> automember_add_post_op\n");
|
||||
|
||||
+ if (slapi_td_is_post_op_nested()) {
|
||||
+ /* don't process op twice in the same thread */
|
||||
+ return rc;
|
||||
+ } else {
|
||||
+ slapi_td_block_nested_post_op();
|
||||
+ }
|
||||
+
|
||||
/* Reload config if a config entry was added. */
|
||||
if ((sdn = automember_get_sdn(pb))) {
|
||||
if (automember_dn_is_config(sdn)) {
|
||||
@@ -2039,7 +2104,7 @@ automember_add_post_op(Slapi_PBlock *pb)
|
||||
|
||||
/* If replication, just bail. */
|
||||
if (automember_isrepl(pb)) {
|
||||
- return SLAPI_PLUGIN_SUCCESS;
|
||||
+ goto bail;
|
||||
}
|
||||
|
||||
/* Get the newly added entry. */
|
||||
@@ -2052,7 +2117,7 @@ automember_add_post_op(Slapi_PBlock *pb)
|
||||
tombstone);
|
||||
slapi_value_free(&tombstone);
|
||||
if (is_tombstone) {
|
||||
- return SLAPI_PLUGIN_SUCCESS;
|
||||
+ goto bail;
|
||||
}
|
||||
|
||||
/* Check if a config entry applies
|
||||
@@ -2063,21 +2128,19 @@ automember_add_post_op(Slapi_PBlock *pb)
|
||||
list = PR_LIST_HEAD(g_automember_config);
|
||||
while (list != g_automember_config) {
|
||||
config = (struct configEntry *)list;
|
||||
-
|
||||
/* Does the entry meet scope and filter requirements? */
|
||||
if (slapi_dn_issuffix(slapi_sdn_get_dn(sdn), config->scope) &&
|
||||
- (slapi_filter_test_simple(e, config->filter) == 0)) {
|
||||
+ (slapi_filter_test_simple(e, config->filter) == 0))
|
||||
+ {
|
||||
/* Find out what membership changes are needed and make them. */
|
||||
if (automember_update_membership(config, e, NULL) == SLAPI_PLUGIN_FAILURE) {
|
||||
rc = SLAPI_PLUGIN_FAILURE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
-
|
||||
list = PR_NEXT_LINK(list);
|
||||
}
|
||||
}
|
||||
-
|
||||
automember_config_unlock();
|
||||
} else {
|
||||
slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
@@ -2098,6 +2161,7 @@ bail:
|
||||
slapi_pblock_set(pb, SLAPI_RESULT_CODE, &result);
|
||||
slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, &errtxt);
|
||||
}
|
||||
+ slapi_td_unblock_nested_post_op();
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -2138,6 +2202,7 @@ typedef struct _task_data
|
||||
Slapi_DN *base_dn;
|
||||
char *bind_dn;
|
||||
int scope;
|
||||
+ PRBool cleanup;
|
||||
} task_data;
|
||||
|
||||
static void
|
||||
@@ -2270,6 +2335,7 @@ automember_task_abort_thread(void *arg)
|
||||
* basedn: dc=example,dc=com
|
||||
* filter: (uid=*)
|
||||
* scope: sub
|
||||
+ * cleanup: yes/on (default is off)
|
||||
*
|
||||
* basedn and filter are required. If scope is omitted, the default is sub
|
||||
*/
|
||||
@@ -2284,9 +2350,22 @@ automember_task_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter __attr
|
||||
const char *base_dn;
|
||||
const char *filter;
|
||||
const char *scope;
|
||||
+ const char *cleanup_str;
|
||||
+ PRBool cleanup = PR_FALSE;
|
||||
|
||||
*returncode = LDAP_SUCCESS;
|
||||
|
||||
+ PR_Lock(fixup_lock);
|
||||
+ if (fixup_running) {
|
||||
+ PR_Unlock(fixup_lock);
|
||||
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
|
||||
+ slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
+ "automember_task_add - there is already a fixup task running\n");
|
||||
+ rv = SLAPI_DSE_CALLBACK_ERROR;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ PR_Unlock(fixup_lock);
|
||||
+
|
||||
/*
|
||||
* Grab the task params
|
||||
*/
|
||||
@@ -2300,6 +2379,12 @@ automember_task_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter __attr
|
||||
rv = SLAPI_DSE_CALLBACK_ERROR;
|
||||
goto out;
|
||||
}
|
||||
+ if ((cleanup_str = slapi_entry_attr_get_ref(e, "cleanup"))) {
|
||||
+ if (strcasecmp(cleanup_str, "yes") == 0 || strcasecmp(cleanup_str, "on")) {
|
||||
+ cleanup = PR_TRUE;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
scope = slapi_fetch_attr(e, "scope", "sub");
|
||||
/*
|
||||
* setup our task data
|
||||
@@ -2315,6 +2400,7 @@ automember_task_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter __attr
|
||||
mytaskdata->bind_dn = slapi_ch_strdup(bind_dn);
|
||||
mytaskdata->base_dn = slapi_sdn_new_dn_byval(base_dn);
|
||||
mytaskdata->filter_str = slapi_ch_strdup(filter);
|
||||
+ mytaskdata->cleanup = cleanup;
|
||||
|
||||
if (scope) {
|
||||
if (strcasecmp(scope, "sub") == 0) {
|
||||
@@ -2334,6 +2420,9 @@ automember_task_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter __attr
|
||||
task = slapi_plugin_new_task(slapi_entry_get_ndn(e), arg);
|
||||
slapi_task_set_destructor_fn(task, automember_task_destructor);
|
||||
slapi_task_set_data(task, mytaskdata);
|
||||
+ PR_Lock(fixup_lock);
|
||||
+ fixup_running = PR_TRUE;
|
||||
+ PR_Unlock(fixup_lock);
|
||||
/*
|
||||
* Start the task as a separate thread
|
||||
*/
|
||||
@@ -2345,6 +2434,9 @@ automember_task_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter __attr
|
||||
"automember_task_add - Unable to create task thread!\n");
|
||||
*returncode = LDAP_OPERATIONS_ERROR;
|
||||
slapi_task_finish(task, *returncode);
|
||||
+ PR_Lock(fixup_lock);
|
||||
+ fixup_running = PR_FALSE;
|
||||
+ PR_Unlock(fixup_lock);
|
||||
rv = SLAPI_DSE_CALLBACK_ERROR;
|
||||
} else {
|
||||
rv = SLAPI_DSE_CALLBACK_OK;
|
||||
@@ -2372,6 +2464,9 @@ automember_rebuild_task_thread(void *arg)
|
||||
PRCList *list = NULL;
|
||||
PRCList *include_list = NULL;
|
||||
int result = 0;
|
||||
+ int64_t fixup_progress_count = 0;
|
||||
+ int64_t fixup_progress_elapsed = 0;
|
||||
+ int64_t fixup_start_time = 0;
|
||||
size_t i = 0;
|
||||
|
||||
/* Reset abort flag */
|
||||
@@ -2380,6 +2475,7 @@ automember_rebuild_task_thread(void *arg)
|
||||
if (!task) {
|
||||
return; /* no task */
|
||||
}
|
||||
+
|
||||
slapi_task_inc_refcount(task);
|
||||
slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
"automember_rebuild_task_thread - Refcount incremented.\n");
|
||||
@@ -2393,9 +2489,11 @@ automember_rebuild_task_thread(void *arg)
|
||||
slapi_task_log_status(task, "Automember rebuild task starting (base dn: (%s) filter (%s)...",
|
||||
slapi_sdn_get_dn(td->base_dn), td->filter_str);
|
||||
/*
|
||||
- * Set the bind dn in the local thread data
|
||||
+ * Set the bind dn in the local thread data, and block post op mods
|
||||
*/
|
||||
slapi_td_set_dn(slapi_ch_strdup(td->bind_dn));
|
||||
+ slapi_td_block_nested_post_op();
|
||||
+ fixup_start_time = slapi_current_rel_time_t();
|
||||
/*
|
||||
* Take the config lock now and search the database
|
||||
*/
|
||||
@@ -2426,6 +2524,21 @@ automember_rebuild_task_thread(void *arg)
|
||||
* Loop over the entries
|
||||
*/
|
||||
for (i = 0; entries && (entries[i] != NULL); i++) {
|
||||
+ fixup_progress_count++;
|
||||
+ if (fixup_progress_count % FIXUP_PROGRESS_LIMIT == 0 ) {
|
||||
+ slapi_task_log_notice(task,
|
||||
+ "Processed %ld entries in %ld seconds (+%ld seconds)",
|
||||
+ fixup_progress_count,
|
||||
+ slapi_current_rel_time_t() - fixup_start_time,
|
||||
+ slapi_current_rel_time_t() - fixup_progress_elapsed);
|
||||
+ slapi_task_log_status(task,
|
||||
+ "Processed %ld entries in %ld seconds (+%ld seconds)",
|
||||
+ fixup_progress_count,
|
||||
+ slapi_current_rel_time_t() - fixup_start_time,
|
||||
+ slapi_current_rel_time_t() - fixup_progress_elapsed);
|
||||
+ slapi_task_inc_progress(task);
|
||||
+ fixup_progress_elapsed = slapi_current_rel_time_t();
|
||||
+ }
|
||||
if (slapi_atomic_load_64(&abort_rebuild_task, __ATOMIC_ACQUIRE) == 1) {
|
||||
/* The task was aborted */
|
||||
slapi_task_log_notice(task, "Automember rebuild task was intentionally aborted");
|
||||
@@ -2443,48 +2556,66 @@ automember_rebuild_task_thread(void *arg)
|
||||
if (slapi_dn_issuffix(slapi_entry_get_dn(entries[i]), config->scope) &&
|
||||
(slapi_filter_test_simple(entries[i], config->filter) == 0))
|
||||
{
|
||||
- /* First clear out all the defaults groups */
|
||||
- for (size_t ii = 0; config->default_groups && config->default_groups[ii]; ii++) {
|
||||
- if ((result = automember_update_member_value(entries[i], config->default_groups[ii],
|
||||
- config->grouping_attr, config->grouping_value, NULL, DEL_MEMBER)))
|
||||
- {
|
||||
- slapi_task_log_notice(task, "Automember rebuild membership task unable to delete "
|
||||
- "member from default group (%s) error (%d)",
|
||||
- config->default_groups[ii], result);
|
||||
- slapi_task_log_status(task, "Automember rebuild membership task unable to delete "
|
||||
- "member from default group (%s) error (%d)",
|
||||
- config->default_groups[ii], result);
|
||||
- slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
- "automember_rebuild_task_thread - Unable to unable to delete from (%s) error (%d)\n",
|
||||
- config->default_groups[ii], result);
|
||||
- goto out;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- /* Then clear out the non-default group */
|
||||
- if (config->inclusive_rules && !PR_CLIST_IS_EMPTY((PRCList *)config->inclusive_rules)) {
|
||||
- include_list = PR_LIST_HEAD((PRCList *)config->inclusive_rules);
|
||||
- while (include_list != (PRCList *)config->inclusive_rules) {
|
||||
- struct automemberRegexRule *curr_rule = (struct automemberRegexRule *)include_list;
|
||||
- if ((result = automember_update_member_value(entries[i], slapi_sdn_get_dn(curr_rule->target_group_dn),
|
||||
- config->grouping_attr, config->grouping_value, NULL, DEL_MEMBER)))
|
||||
+ if (td->cleanup) {
|
||||
+
|
||||
+ slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
+ "automember_rebuild_task_thread - Cleaning up groups (config %s)\n",
|
||||
+ config->dn);
|
||||
+ /* First clear out all the defaults groups */
|
||||
+ for (size_t ii = 0; config->default_groups && config->default_groups[ii]; ii++) {
|
||||
+ if ((result = automember_update_member_value(entries[i],
|
||||
+ config->default_groups[ii],
|
||||
+ config->grouping_attr,
|
||||
+ config->grouping_value,
|
||||
+ NULL, DEL_MEMBER)))
|
||||
{
|
||||
slapi_task_log_notice(task, "Automember rebuild membership task unable to delete "
|
||||
- "member from group (%s) error (%d)",
|
||||
- slapi_sdn_get_dn(curr_rule->target_group_dn), result);
|
||||
+ "member from default group (%s) error (%d)",
|
||||
+ config->default_groups[ii], result);
|
||||
slapi_task_log_status(task, "Automember rebuild membership task unable to delete "
|
||||
- "member from group (%s) error (%d)",
|
||||
- slapi_sdn_get_dn(curr_rule->target_group_dn), result);
|
||||
+ "member from default group (%s) error (%d)",
|
||||
+ config->default_groups[ii], result);
|
||||
slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
"automember_rebuild_task_thread - Unable to unable to delete from (%s) error (%d)\n",
|
||||
- slapi_sdn_get_dn(curr_rule->target_group_dn), result);
|
||||
+ config->default_groups[ii], result);
|
||||
goto out;
|
||||
}
|
||||
- include_list = PR_NEXT_LINK(include_list);
|
||||
}
|
||||
+
|
||||
+ /* Then clear out the non-default group */
|
||||
+ if (config->inclusive_rules && !PR_CLIST_IS_EMPTY((PRCList *)config->inclusive_rules)) {
|
||||
+ include_list = PR_LIST_HEAD((PRCList *)config->inclusive_rules);
|
||||
+ while (include_list != (PRCList *)config->inclusive_rules) {
|
||||
+ struct automemberRegexRule *curr_rule = (struct automemberRegexRule *)include_list;
|
||||
+ if ((result = automember_update_member_value(entries[i],
|
||||
+ slapi_sdn_get_dn(curr_rule->target_group_dn),
|
||||
+ config->grouping_attr,
|
||||
+ config->grouping_value,
|
||||
+ NULL, DEL_MEMBER)))
|
||||
+ {
|
||||
+ slapi_task_log_notice(task, "Automember rebuild membership task unable to delete "
|
||||
+ "member from group (%s) error (%d)",
|
||||
+ slapi_sdn_get_dn(curr_rule->target_group_dn), result);
|
||||
+ slapi_task_log_status(task, "Automember rebuild membership task unable to delete "
|
||||
+ "member from group (%s) error (%d)",
|
||||
+ slapi_sdn_get_dn(curr_rule->target_group_dn), result);
|
||||
+ slapi_log_err(SLAPI_LOG_ERR, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
+ "automember_rebuild_task_thread - Unable to unable to delete from (%s) error (%d)\n",
|
||||
+ slapi_sdn_get_dn(curr_rule->target_group_dn), result);
|
||||
+ goto out;
|
||||
+ }
|
||||
+ include_list = PR_NEXT_LINK(include_list);
|
||||
+ }
|
||||
+ }
|
||||
+ slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
+ "automember_rebuild_task_thread - Finished cleaning up groups (config %s)\n",
|
||||
+ config->dn);
|
||||
}
|
||||
|
||||
/* Update the memberships for this entries */
|
||||
+ slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
+ "automember_rebuild_task_thread - Updating membership (config %s)\n",
|
||||
+ config->dn);
|
||||
if (slapi_is_shutting_down() ||
|
||||
automember_update_membership(config, entries[i], NULL) == SLAPI_PLUGIN_FAILURE)
|
||||
{
|
||||
@@ -2508,15 +2639,22 @@ out:
|
||||
slapi_task_log_notice(task, "Automember rebuild task aborted. Error (%d)", result);
|
||||
slapi_task_log_status(task, "Automember rebuild task aborted. Error (%d)", result);
|
||||
} else {
|
||||
- slapi_task_log_notice(task, "Automember rebuild task finished. Processed (%d) entries.", (int32_t)i);
|
||||
- slapi_task_log_status(task, "Automember rebuild task finished. Processed (%d) entries.", (int32_t)i);
|
||||
+ slapi_task_log_notice(task, "Automember rebuild task finished. Processed (%ld) entries in %ld seconds",
|
||||
+ (int64_t)i, slapi_current_rel_time_t() - fixup_start_time);
|
||||
+ slapi_task_log_status(task, "Automember rebuild task finished. Processed (%ld) entries in %ld seconds",
|
||||
+ (int64_t)i, slapi_current_rel_time_t() - fixup_start_time);
|
||||
}
|
||||
slapi_task_inc_progress(task);
|
||||
slapi_task_finish(task, result);
|
||||
slapi_task_dec_refcount(task);
|
||||
slapi_atomic_store_64(&abort_rebuild_task, 0, __ATOMIC_RELEASE);
|
||||
+ slapi_td_unblock_nested_post_op();
|
||||
+ PR_Lock(fixup_lock);
|
||||
+ fixup_running = PR_FALSE;
|
||||
+ PR_Unlock(fixup_lock);
|
||||
+
|
||||
slapi_log_err(SLAPI_LOG_PLUGIN, AUTOMEMBER_PLUGIN_SUBSYSTEM,
|
||||
- "automember_rebuild_task_thread - Refcount decremented.\n");
|
||||
+ "automember_rebuild_task_thread - task finished, refcount decremented.\n");
|
||||
}
|
||||
|
||||
/*
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_add.c b/ldap/servers/slapd/back-ldbm/ldbm_add.c
|
||||
index ba2d73a84..ce4c314a1 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/ldbm_add.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/ldbm_add.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) 2022 Red Hat, Inc.
|
||||
* Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -1264,10 +1264,6 @@ ldbm_back_add(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);
|
||||
- }
|
||||
if (addingentry_id_assigned) {
|
||||
next_id_return(be, addingentry->ep_id);
|
||||
}
|
||||
@@ -1376,6 +1372,11 @@ diskfull_return:
|
||||
if (!not_an_error) {
|
||||
rc = SLAPI_FAIL_GENERAL;
|
||||
}
|
||||
+
|
||||
+ /* Revert the caches if this is the parent operation */
|
||||
+ if (parent_op && betxn_callback_fails) {
|
||||
+ revert_cache(inst, &parent_time);
|
||||
+ }
|
||||
}
|
||||
|
||||
common_return:
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_delete.c b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
|
||||
index de23190c3..27f0ac58a 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/ldbm_delete.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
|
||||
@@ -1407,11 +1407,6 @@ commit_return:
|
||||
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);
|
||||
- }
|
||||
-
|
||||
if (tombstone) {
|
||||
if (cache_is_in_cache(&inst->inst_cache, tombstone)) {
|
||||
tomb_ep_id = tombstone->ep_id; /* Otherwise, tombstone might have been freed. */
|
||||
@@ -1496,6 +1491,11 @@ error_return:
|
||||
conn_id, op_id, parent_modify_c.old_entry, parent_modify_c.new_entry, myrc);
|
||||
}
|
||||
|
||||
+ /* Revert the caches if this is the parent operation */
|
||||
+ if (parent_op && betxn_callback_fails) {
|
||||
+ revert_cache(inst, &parent_time);
|
||||
+ }
|
||||
+
|
||||
common_return:
|
||||
if (orig_entry) {
|
||||
/* NOTE: #define SLAPI_DELETE_BEPREOP_ENTRY SLAPI_ENTRY_PRE_OP */
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modify.c b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
|
||||
index 537369055..64b293001 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/ldbm_modify.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modify.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) 2022 Red Hat, Inc.
|
||||
* Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -1043,11 +1043,6 @@ ldbm_back_modify(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);
|
||||
- }
|
||||
-
|
||||
if (postentry != NULL) {
|
||||
slapi_entry_free(postentry);
|
||||
postentry = NULL;
|
||||
@@ -1103,6 +1098,10 @@ error_return:
|
||||
if (!not_an_error) {
|
||||
rc = SLAPI_FAIL_GENERAL;
|
||||
}
|
||||
+ /* Revert the caches if this is the parent operation */
|
||||
+ if (parent_op && betxn_callback_fails) {
|
||||
+ revert_cache(inst, &parent_time);
|
||||
+ }
|
||||
}
|
||||
|
||||
/* if ec is in cache, remove it, then add back e if we still have it */
|
||||
diff --git a/src/lib389/lib389/cli_conf/plugins/automember.py b/src/lib389/lib389/cli_conf/plugins/automember.py
|
||||
index 15b00c633..568586ad8 100644
|
||||
--- a/src/lib389/lib389/cli_conf/plugins/automember.py
|
||||
+++ b/src/lib389/lib389/cli_conf/plugins/automember.py
|
||||
@@ -155,7 +155,7 @@ def fixup(inst, basedn, log, args):
|
||||
log.info('Attempting to add task entry... This will fail if Automembership plug-in is not enabled.')
|
||||
if not plugin.status():
|
||||
log.error("'%s' is disabled. Rebuild membership task can't be executed" % plugin.rdn)
|
||||
- fixup_task = plugin.fixup(args.DN, args.filter)
|
||||
+ fixup_task = plugin.fixup(args.DN, args.filter, args.cleanup)
|
||||
if args.wait:
|
||||
log.info(f'Waiting for fixup task "{fixup_task.dn}" to complete. You can safely exit by pressing Control C ...')
|
||||
fixup_task.wait(timeout=args.timeout)
|
||||
@@ -225,8 +225,8 @@ def create_parser(subparsers):
|
||||
subcommands = automember.add_subparsers(help='action')
|
||||
add_generic_plugin_parsers(subcommands, AutoMembershipPlugin)
|
||||
|
||||
- list = subcommands.add_parser('list', help='List Automembership definitions or regex rules.')
|
||||
- subcommands_list = list.add_subparsers(help='action')
|
||||
+ automember_list = subcommands.add_parser('list', help='List Automembership definitions or regex rules.')
|
||||
+ subcommands_list = automember_list.add_subparsers(help='action')
|
||||
list_definitions = subcommands_list.add_parser('definitions', help='Lists Automembership definitions.')
|
||||
list_definitions.set_defaults(func=definition_list)
|
||||
list_regexes = subcommands_list.add_parser('regexes', help='List Automembership regex rules.')
|
||||
@@ -269,6 +269,8 @@ def create_parser(subparsers):
|
||||
fixup_task.add_argument('-f', '--filter', required=True, help='Sets the LDAP filter for entries to fix up')
|
||||
fixup_task.add_argument('-s', '--scope', required=True, choices=['sub', 'base', 'one'], type=str.lower,
|
||||
help='Sets the LDAP search scope for entries to fix up')
|
||||
+ fixup_task.add_argument('--cleanup', action='store_true',
|
||||
+ help="Clean up previous group memberships before rebuilding")
|
||||
fixup_task.add_argument('--wait', action='store_true',
|
||||
help="Wait for the task to finish, this could take a long time")
|
||||
fixup_task.add_argument('--timeout', default=0, type=int,
|
||||
@@ -279,7 +281,7 @@ def create_parser(subparsers):
|
||||
fixup_status.add_argument('--dn', help="The task entry's DN")
|
||||
fixup_status.add_argument('--show-log', action='store_true', help="Display the task log")
|
||||
fixup_status.add_argument('--watch', action='store_true',
|
||||
- help="Watch the task's status and wait for it to finish")
|
||||
+ help="Watch the task's status and wait for it to finish")
|
||||
|
||||
abort_fixup = subcommands.add_parser('abort-fixup', help='Abort the rebuild membership task.')
|
||||
abort_fixup.set_defaults(func=abort)
|
||||
diff --git a/src/lib389/lib389/plugins.py b/src/lib389/lib389/plugins.py
|
||||
index 52691a44c..a1ad0a45b 100644
|
||||
--- a/src/lib389/lib389/plugins.py
|
||||
+++ b/src/lib389/lib389/plugins.py
|
||||
@@ -1141,13 +1141,15 @@ class AutoMembershipPlugin(Plugin):
|
||||
def __init__(self, instance, dn="cn=Auto Membership Plugin,cn=plugins,cn=config"):
|
||||
super(AutoMembershipPlugin, self).__init__(instance, dn)
|
||||
|
||||
- def fixup(self, basedn, _filter=None):
|
||||
+ def fixup(self, basedn, _filter=None, cleanup=False):
|
||||
"""Create an automember rebuild membership task
|
||||
|
||||
:param basedn: Basedn to fix up
|
||||
:type basedn: str
|
||||
:param _filter: a filter for entries to fix up
|
||||
:type _filter: str
|
||||
+ :param cleanup: cleanup old group memberships
|
||||
+ :type cleanup: boolean
|
||||
|
||||
:returns: an instance of Task(DSLdapObject)
|
||||
"""
|
||||
@@ -1156,6 +1158,9 @@ class AutoMembershipPlugin(Plugin):
|
||||
task_properties = {'basedn': basedn}
|
||||
if _filter is not None:
|
||||
task_properties['filter'] = _filter
|
||||
+ if cleanup:
|
||||
+ task_properties['cleanup'] = "yes"
|
||||
+
|
||||
task.create(properties=task_properties)
|
||||
|
||||
return task
|
||||
diff --git a/src/lib389/lib389/tasks.py b/src/lib389/lib389/tasks.py
|
||||
index 1a16bbb83..193805780 100644
|
||||
--- a/src/lib389/lib389/tasks.py
|
||||
+++ b/src/lib389/lib389/tasks.py
|
||||
@@ -1006,12 +1006,13 @@ class Tasks(object):
|
||||
return exitCode
|
||||
|
||||
def automemberRebuild(self, suffix=DEFAULT_SUFFIX, scope='sub',
|
||||
- filterstr='objectclass=top', args=None):
|
||||
+ filterstr='objectclass=top', cleanup=False, args=None):
|
||||
'''
|
||||
- @param suffix - The suffix the task should examine - defualt is
|
||||
+ @param suffix - The suffix the task should examine - default is
|
||||
"dc=example,dc=com"
|
||||
@param scope - The scope of the search to find entries
|
||||
- @param fitlerstr - THe search filter to find entries
|
||||
+ @param fitlerstr - The search filter to find entries
|
||||
+ @param cleanup - reset/clear the old group mmeberships prior to rebuilding
|
||||
@param args - is a dictionary that contains modifier of the task
|
||||
wait: True/[False] - If True, waits for the completion of
|
||||
the task before to return
|
||||
@@ -1027,6 +1028,8 @@ class Tasks(object):
|
||||
entry.setValues('basedn', suffix)
|
||||
entry.setValues('filter', filterstr)
|
||||
entry.setValues('scope', scope)
|
||||
+ if cleanup:
|
||||
+ entry.setValues('cleanup', 'yes')
|
||||
|
||||
# start the task and possibly wait for task completion
|
||||
try:
|
||||
--
|
||||
2.43.0
|
||||
|
||||
@ -1,83 +0,0 @@
|
||||
From 9319d5b022918f14cacb00e3faef85a6ab730a26 Mon Sep 17 00:00:00 2001
|
||||
From: Simon Pichugin <spichugi@redhat.com>
|
||||
Date: Tue, 27 Feb 2024 16:30:47 -0800
|
||||
Subject: [PATCH] Issue 3527 - Support HAProxy and Instance on the same machine
|
||||
configuration (#6107)
|
||||
|
||||
Description: Improve how we handle HAProxy connections to work better when
|
||||
the DS and HAProxy are on the same machine.
|
||||
Ensure the client and header destination IPs are checked against the trusted IP list.
|
||||
|
||||
Additionally, this change will also allow configuration having
|
||||
HAProxy is listening on a different subnet than the one used to forward the request.
|
||||
|
||||
Related: https://github.com/389ds/389-ds-base/issues/3527
|
||||
|
||||
Reviewed by: @progier389, @jchapma (Thanks!)
|
||||
---
|
||||
ldap/servers/slapd/connection.c | 35 +++++++++++++++++++++++++--------
|
||||
1 file changed, 27 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/ldap/servers/slapd/connection.c b/ldap/servers/slapd/connection.c
|
||||
index d28a39bf7..10a8cc577 100644
|
||||
--- a/ldap/servers/slapd/connection.c
|
||||
+++ b/ldap/servers/slapd/connection.c
|
||||
@@ -1187,6 +1187,8 @@ connection_read_operation(Connection *conn, Operation *op, ber_tag_t *tag, int *
|
||||
char str_ip[INET6_ADDRSTRLEN + 1] = {0};
|
||||
char str_haproxy_ip[INET6_ADDRSTRLEN + 1] = {0};
|
||||
char str_haproxy_destip[INET6_ADDRSTRLEN + 1] = {0};
|
||||
+ int trusted_matches_ip_found = 0;
|
||||
+ int trusted_matches_destip_found = 0;
|
||||
struct berval **bvals = NULL;
|
||||
int proxy_connection = 0;
|
||||
|
||||
@@ -1245,21 +1247,38 @@ connection_read_operation(Connection *conn, Operation *op, ber_tag_t *tag, int *
|
||||
normalize_IPv4(conn->cin_addr, buf_ip, sizeof(buf_ip), str_ip, sizeof(str_ip));
|
||||
normalize_IPv4(&pr_netaddr_dest, buf_haproxy_destip, sizeof(buf_haproxy_destip),
|
||||
str_haproxy_destip, sizeof(str_haproxy_destip));
|
||||
+ size_t ip_len = strlen(buf_ip);
|
||||
+ size_t destip_len = strlen(buf_haproxy_destip);
|
||||
|
||||
/* Now, reset RC and set it to 0 only if a match is found */
|
||||
haproxy_rc = -1;
|
||||
|
||||
- /* Allow only:
|
||||
- * Trusted IP == Original Client IP == HAProxy Header Destination IP */
|
||||
+ /*
|
||||
+ * We need to allow a configuration where DS instance and HAProxy are on the same machine.
|
||||
+ * In this case, we need to check if
|
||||
+ * the HAProxy client IP (which will be a loopback address) matches one of the the trusted IP addresses,
|
||||
+ * while still checking that
|
||||
+ * the HAProxy header destination IP address matches one of the trusted IP addresses.
|
||||
+ * Additionally, this change will also allow configuration having
|
||||
+ * HAProxy listening on a different subnet than one used to forward the request.
|
||||
+ */
|
||||
for (size_t i = 0; bvals[i] != NULL; ++i) {
|
||||
- if ((strlen(bvals[i]->bv_val) == strlen(buf_ip)) &&
|
||||
- (strlen(bvals[i]->bv_val) == strlen(buf_haproxy_destip)) &&
|
||||
- (strncasecmp(bvals[i]->bv_val, buf_ip, strlen(buf_ip)) == 0) &&
|
||||
- (strncasecmp(bvals[i]->bv_val, buf_haproxy_destip, strlen(buf_haproxy_destip)) == 0)) {
|
||||
- haproxy_rc = 0;
|
||||
- break;
|
||||
+ size_t bval_len = strlen(bvals[i]->bv_val);
|
||||
+
|
||||
+ /* Check if the Client IP (HAProxy's machine IP) address matches the trusted IP address */
|
||||
+ if (!trusted_matches_ip_found) {
|
||||
+ trusted_matches_ip_found = (bval_len == ip_len) && (strncasecmp(bvals[i]->bv_val, buf_ip, ip_len) == 0);
|
||||
+ }
|
||||
+ /* Check if the HAProxy header destination IP address matches the trusted IP address */
|
||||
+ if (!trusted_matches_destip_found) {
|
||||
+ trusted_matches_destip_found = (bval_len == destip_len) && (strncasecmp(bvals[i]->bv_val, buf_haproxy_destip, destip_len) == 0);
|
||||
}
|
||||
}
|
||||
+
|
||||
+ if (trusted_matches_ip_found && trusted_matches_destip_found) {
|
||||
+ haproxy_rc = 0;
|
||||
+ }
|
||||
+
|
||||
if (haproxy_rc == -1) {
|
||||
slapi_log_err(SLAPI_LOG_CONNS, "connection_read_operation", "HAProxy header received from unknown source.\n");
|
||||
disconnect_server_nomutex(conn, conn->c_connid, -1, SLAPD_DISCONNECT_PROXY_UNKNOWN, EPROTO);
|
||||
--
|
||||
2.45.0
|
||||
|
||||
@ -1,108 +0,0 @@
|
||||
From 016a2b6bd3e27cbff36609824a75b020dfd24823 Mon Sep 17 00:00:00 2001
|
||||
From: James Chapman <jachapma@redhat.com>
|
||||
Date: Wed, 1 May 2024 15:01:33 +0100
|
||||
Subject: [PATCH] CVE-2024-2199
|
||||
|
||||
---
|
||||
.../tests/suites/password/password_test.py | 56 +++++++++++++++++++
|
||||
ldap/servers/slapd/modify.c | 8 ++-
|
||||
2 files changed, 62 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/password/password_test.py b/dirsrvtests/tests/suites/password/password_test.py
|
||||
index 38079476a..b3ff08904 100644
|
||||
--- a/dirsrvtests/tests/suites/password/password_test.py
|
||||
+++ b/dirsrvtests/tests/suites/password/password_test.py
|
||||
@@ -65,6 +65,62 @@ def test_password_delete_specific_password(topology_st):
|
||||
log.info('test_password_delete_specific_password: PASSED')
|
||||
|
||||
|
||||
+def test_password_modify_non_utf8(topology_st):
|
||||
+ """Attempt a modify of the userPassword attribute with
|
||||
+ an invalid non utf8 value
|
||||
+
|
||||
+ :id: a31af9d5-d665-42b9-8d6e-fea3d0837d36
|
||||
+ :setup: Standalone instance
|
||||
+ :steps:
|
||||
+ 1. Add a user if it doesnt exist and set its password
|
||||
+ 2. Verify password with a bind
|
||||
+ 3. Modify userPassword attr with invalid value
|
||||
+ 4. Attempt a bind with invalid password value
|
||||
+ 5. Verify original password with a bind
|
||||
+ :expectedresults:
|
||||
+ 1. The user with userPassword should be added successfully
|
||||
+ 2. Operation should be successful
|
||||
+ 3. Server returns ldap.UNWILLING_TO_PERFORM
|
||||
+ 4. Server returns ldap.INVALID_CREDENTIALS
|
||||
+ 5. Operation should be successful
|
||||
+ """
|
||||
+
|
||||
+ log.info('Running test_password_modify_non_utf8...')
|
||||
+
|
||||
+ # Create user and set password
|
||||
+ standalone = topology_st.standalone
|
||||
+ users = UserAccounts(standalone, DEFAULT_SUFFIX)
|
||||
+ if not users.exists(TEST_USER_PROPERTIES['uid'][0]):
|
||||
+ user = users.create(properties=TEST_USER_PROPERTIES)
|
||||
+ else:
|
||||
+ user = users.get(TEST_USER_PROPERTIES['uid'][0])
|
||||
+ user.set('userpassword', PASSWORD)
|
||||
+
|
||||
+ # Verify password
|
||||
+ try:
|
||||
+ user.bind(PASSWORD)
|
||||
+ except ldap.LDAPError as e:
|
||||
+ log.fatal('Failed to bind as {}, error: '.format(user.dn) + e.args[0]['desc'])
|
||||
+ assert False
|
||||
+
|
||||
+ # Modify userPassword with an invalid value
|
||||
+ password = b'tes\x82t-password' # A non UTF-8 encoded password
|
||||
+ with pytest.raises(ldap.UNWILLING_TO_PERFORM):
|
||||
+ user.replace('userpassword', password)
|
||||
+
|
||||
+ # Verify a bind fails with invalid pasword
|
||||
+ with pytest.raises(ldap.INVALID_CREDENTIALS):
|
||||
+ user.bind(password)
|
||||
+
|
||||
+ # Verify we can still bind with original password
|
||||
+ try:
|
||||
+ user.bind(PASSWORD)
|
||||
+ except ldap.LDAPError as e:
|
||||
+ log.fatal('Failed to bind as {}, error: '.format(user.dn) + e.args[0]['desc'])
|
||||
+ assert False
|
||||
+
|
||||
+ log.info('test_password_modify_non_utf8: PASSED')
|
||||
+
|
||||
if __name__ == '__main__':
|
||||
# Run isolated
|
||||
# -s for DEBUG mode
|
||||
diff --git a/ldap/servers/slapd/modify.c b/ldap/servers/slapd/modify.c
|
||||
index 5ca78539c..669bb104c 100644
|
||||
--- a/ldap/servers/slapd/modify.c
|
||||
+++ b/ldap/servers/slapd/modify.c
|
||||
@@ -765,8 +765,10 @@ op_shared_modify(Slapi_PBlock *pb, int pw_change, char *old_pw)
|
||||
* flagged - leave mod attributes alone */
|
||||
if (!repl_op && !skip_modified_attrs && lastmod) {
|
||||
modify_update_last_modified_attr(pb, &smods);
|
||||
+ slapi_pblock_set(pb, SLAPI_MODIFY_MODS, slapi_mods_get_ldapmods_byref(&smods));
|
||||
}
|
||||
|
||||
+
|
||||
if (0 == slapi_mods_get_num_mods(&smods)) {
|
||||
/* nothing to do - no mods - this is not an error - just
|
||||
send back LDAP_SUCCESS */
|
||||
@@ -933,8 +935,10 @@ op_shared_modify(Slapi_PBlock *pb, int pw_change, char *old_pw)
|
||||
|
||||
/* encode password */
|
||||
if (pw_encodevals_ext(pb, sdn, va)) {
|
||||
- slapi_log_err(SLAPI_LOG_CRIT, "op_shared_modify", "Unable to hash userPassword attribute for %s.\n", slapi_entry_get_dn_const(e));
|
||||
- send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL, "Unable to store attribute \"userPassword\" correctly\n", 0, NULL);
|
||||
+ slapi_log_err(SLAPI_LOG_CRIT, "op_shared_modify", "Unable to hash userPassword attribute for %s, "
|
||||
+ "check value is utf8 string.\n", slapi_entry_get_dn_const(e));
|
||||
+ send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL, "Unable to hash \"userPassword\" attribute, "
|
||||
+ "check value is utf8 string.\n", 0, NULL);
|
||||
valuearray_free(&va);
|
||||
goto free_and_return;
|
||||
}
|
||||
--
|
||||
2.45.0
|
||||
|
||||
@ -1,213 +0,0 @@
|
||||
From d5bbe52fbe84a7d3b5938bf82d5c4af15061a8e2 Mon Sep 17 00:00:00 2001
|
||||
From: Pierre Rogier <progier@redhat.com>
|
||||
Date: Wed, 17 Apr 2024 18:18:04 +0200
|
||||
Subject: [PATCH] CVE-2024-3657
|
||||
|
||||
---
|
||||
.../tests/suites/filter/large_filter_test.py | 34 +++++-
|
||||
ldap/servers/slapd/back-ldbm/index.c | 111 ++++++++++--------
|
||||
2 files changed, 92 insertions(+), 53 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/filter/large_filter_test.py b/dirsrvtests/tests/suites/filter/large_filter_test.py
|
||||
index ecc7bf979..40526bb16 100644
|
||||
--- a/dirsrvtests/tests/suites/filter/large_filter_test.py
|
||||
+++ b/dirsrvtests/tests/suites/filter/large_filter_test.py
|
||||
@@ -13,19 +13,29 @@ verify and testing Filter from a search
|
||||
|
||||
import os
|
||||
import pytest
|
||||
+import ldap
|
||||
|
||||
-from lib389._constants import PW_DM
|
||||
+from lib389._constants import PW_DM, DEFAULT_SUFFIX, ErrorLog
|
||||
from lib389.topologies import topology_st as topo
|
||||
from lib389.idm.user import UserAccounts, UserAccount
|
||||
from lib389.idm.account import Accounts
|
||||
from lib389.backend import Backends
|
||||
from lib389.idm.domain import Domain
|
||||
+from lib389.utils import get_ldapurl_from_serverid
|
||||
|
||||
SUFFIX = 'dc=anuj,dc=com'
|
||||
|
||||
pytestmark = pytest.mark.tier1
|
||||
|
||||
|
||||
+def open_new_ldapi_conn(dsinstance):
|
||||
+ ldapurl, certdir = get_ldapurl_from_serverid(dsinstance)
|
||||
+ assert 'ldapi://' in ldapurl
|
||||
+ conn = ldap.initialize(ldapurl)
|
||||
+ conn.sasl_interactive_bind_s("", ldap.sasl.external())
|
||||
+ return conn
|
||||
+
|
||||
+
|
||||
@pytest.fixture(scope="module")
|
||||
def _create_entries(request, topo):
|
||||
"""
|
||||
@@ -160,6 +170,28 @@ def test_large_filter(topo, _create_entries, real_value):
|
||||
assert len(Accounts(conn, SUFFIX).filter(real_value)) == 3
|
||||
|
||||
|
||||
+def test_long_filter_value(topo):
|
||||
+ """Exercise large eq filter with dn syntax attributes
|
||||
+
|
||||
+ :id: b069ef72-fcc3-11ee-981c-482ae39447e5
|
||||
+ :setup: Standalone
|
||||
+ :steps:
|
||||
+ 1. Try to pass filter rules as per the condition.
|
||||
+ :expectedresults:
|
||||
+ 1. Pass
|
||||
+ """
|
||||
+ inst = topo.standalone
|
||||
+ conn = open_new_ldapi_conn(inst.serverid)
|
||||
+ inst.config.loglevel(vals=(ErrorLog.DEFAULT,ErrorLog.TRACE,ErrorLog.SEARCH_FILTER))
|
||||
+ filter_value = "a\x1Edmin" * 1025
|
||||
+ conn.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, f'(cn={filter_value})')
|
||||
+ filter_value = "aAdmin" * 1025
|
||||
+ conn.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, f'(cn={filter_value})')
|
||||
+ filter_value = "*"
|
||||
+ conn.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, f'(cn={filter_value})')
|
||||
+ inst.config.loglevel(vals=(ErrorLog.DEFAULT,))
|
||||
+
|
||||
+
|
||||
if __name__ == '__main__':
|
||||
CURRENT_FILE = os.path.realpath(__file__)
|
||||
pytest.main("-s -v %s" % CURRENT_FILE)
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/index.c b/ldap/servers/slapd/back-ldbm/index.c
|
||||
index 410db23d1..30fa09ebb 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/index.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/index.c
|
||||
@@ -71,6 +71,32 @@ typedef struct _index_buffer_handle index_buffer_handle;
|
||||
#define INDEX_BUFFER_FLAG_SERIALIZE 1
|
||||
#define INDEX_BUFFER_FLAG_STATS 2
|
||||
|
||||
+/*
|
||||
+ * space needed to encode a byte:
|
||||
+ * 0x00-0x31 and 0x7f-0xff requires 3 bytes: \xx
|
||||
+ * 0x22 and 0x5C requires 2 bytes: \" and \\
|
||||
+ * other requires 1 byte: c
|
||||
+ */
|
||||
+static char encode_size[] = {
|
||||
+ /* 0x00 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
+ /* 0x10 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
+ /* 0x20 */ 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
+ /* 0x30 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
+ /* 0x40 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
+ /* 0x50 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1,
|
||||
+ /* 0x60 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
+ /* 0x70 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3,
|
||||
+ /* 0x80 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
+ /* 0x90 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
+ /* 0xA0 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
+ /* 0xB0 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
+ /* 0xC0 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
+ /* 0xD0 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
+ /* 0xE0 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
+ /* 0xF0 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
+};
|
||||
+
|
||||
+
|
||||
/* Index buffering functions */
|
||||
|
||||
static int
|
||||
@@ -799,65 +825,46 @@ index_add_mods(
|
||||
|
||||
/*
|
||||
* Convert a 'struct berval' into a displayable ASCII string
|
||||
+ * returns the printable string
|
||||
*/
|
||||
-
|
||||
-#define SPECIAL(c) (c < 32 || c > 126 || c == '\\' || c == '"')
|
||||
-
|
||||
const char *
|
||||
encode(const struct berval *data, char buf[BUFSIZ])
|
||||
{
|
||||
- char *s;
|
||||
- char *last;
|
||||
- if (data == NULL || data->bv_len == 0)
|
||||
- return "";
|
||||
- last = data->bv_val + data->bv_len - 1;
|
||||
- for (s = data->bv_val; s < last; ++s) {
|
||||
- if (SPECIAL(*s)) {
|
||||
- char *first = data->bv_val;
|
||||
- char *bufNext = buf;
|
||||
- size_t bufSpace = BUFSIZ - 4;
|
||||
- while (1) {
|
||||
- /* printf ("%lu bytes ASCII\n", (unsigned long)(s - first)); */
|
||||
- if (bufSpace < (size_t)(s - first))
|
||||
- s = first + bufSpace - 1;
|
||||
- if (s != first) {
|
||||
- memcpy(bufNext, first, s - first);
|
||||
- bufNext += (s - first);
|
||||
- bufSpace -= (s - first);
|
||||
- }
|
||||
- do {
|
||||
- if (bufSpace) {
|
||||
- *bufNext++ = '\\';
|
||||
- --bufSpace;
|
||||
- }
|
||||
- if (bufSpace < 2) {
|
||||
- memcpy(bufNext, "..", 2);
|
||||
- bufNext += 2;
|
||||
- goto bail;
|
||||
- }
|
||||
- if (*s == '\\' || *s == '"') {
|
||||
- *bufNext++ = *s;
|
||||
- --bufSpace;
|
||||
- } else {
|
||||
- sprintf(bufNext, "%02x", (unsigned)*(unsigned char *)s);
|
||||
- bufNext += 2;
|
||||
- bufSpace -= 2;
|
||||
- }
|
||||
- } while (++s <= last && SPECIAL(*s));
|
||||
- if (s > last)
|
||||
- break;
|
||||
- first = s;
|
||||
- while (!SPECIAL(*s) && s <= last)
|
||||
- ++s;
|
||||
- }
|
||||
- bail:
|
||||
- *bufNext = '\0';
|
||||
- /* printf ("%lu chars in buffer\n", (unsigned long)(bufNext - buf)); */
|
||||
+ if (!data || !data->bv_val) {
|
||||
+ strcpy(buf, "<NULL>");
|
||||
+ return buf;
|
||||
+ }
|
||||
+ char *endbuff = &buf[BUFSIZ-4]; /* Reserve space to append "...\0" */
|
||||
+ char *ptout = buf;
|
||||
+ unsigned char *ptin = (unsigned char*) data->bv_val;
|
||||
+ unsigned char *endptin = ptin+data->bv_len;
|
||||
+
|
||||
+ while (ptin < endptin) {
|
||||
+ if (ptout >= endbuff) {
|
||||
+ /*
|
||||
+ * BUFSIZ(8K) > SLAPI_LOG_BUFSIZ(2K) so the error log message will be
|
||||
+ * truncated anyway. So there is no real interrest to test if the original
|
||||
+ * data contains no special characters and return it as is.
|
||||
+ */
|
||||
+ strcpy(endbuff, "...");
|
||||
return buf;
|
||||
}
|
||||
+ switch (encode_size[*ptin]) {
|
||||
+ case 1:
|
||||
+ *ptout++ = *ptin++;
|
||||
+ break;
|
||||
+ case 2:
|
||||
+ *ptout++ = '\\';
|
||||
+ *ptout++ = *ptin++;
|
||||
+ break;
|
||||
+ case 3:
|
||||
+ sprintf(ptout, "\\%02x", *ptin++);
|
||||
+ ptout += 3;
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
- /* printf ("%lu bytes, all ASCII\n", (unsigned long)(s - data->bv_val)); */
|
||||
- return data->bv_val;
|
||||
+ *ptout = 0;
|
||||
+ return buf;
|
||||
}
|
||||
|
||||
static const char *
|
||||
--
|
||||
2.45.0
|
||||
|
||||
@ -1,143 +0,0 @@
|
||||
From 6e5f03d5872129963106024f53765234a282406c Mon Sep 17 00:00:00 2001
|
||||
From: James Chapman <jachapma@redhat.com>
|
||||
Date: Fri, 16 Feb 2024 11:13:16 +0000
|
||||
Subject: [PATCH] Issue 6096 - Improve connection timeout error logging (#6097)
|
||||
|
||||
Bug description: When a paged result search is run with a time limit,
|
||||
if the time limit is exceed the server closes the connection with
|
||||
closed IO timeout (nsslapd-ioblocktimeout) - T2. This error message
|
||||
is incorrect as the reason the connection has been closed was because
|
||||
the specified time limit on a paged result search has been exceeded.
|
||||
|
||||
Fix description: Correct error message
|
||||
|
||||
Relates: https://github.com/389ds/389-ds-base/issues/6096
|
||||
|
||||
Reviewed by: @tbordaz (Thank you)
|
||||
---
|
||||
ldap/admin/src/logconv.pl | 24 ++++++++++++++++++-
|
||||
ldap/servers/slapd/daemon.c | 4 ++--
|
||||
ldap/servers/slapd/disconnect_error_strings.h | 1 +
|
||||
ldap/servers/slapd/disconnect_errors.h | 2 +-
|
||||
4 files changed, 27 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/ldap/admin/src/logconv.pl b/ldap/admin/src/logconv.pl
|
||||
index 7698c383a..2a933c4a3 100755
|
||||
--- a/ldap/admin/src/logconv.pl
|
||||
+++ b/ldap/admin/src/logconv.pl
|
||||
@@ -267,7 +267,7 @@ my $optimeAvg = 0;
|
||||
my %cipher = ();
|
||||
my @removefiles = ();
|
||||
|
||||
-my @conncodes = qw(A1 B1 B4 T1 T2 B2 B3 R1 P1 P2 U1);
|
||||
+my @conncodes = qw(A1 B1 B4 T1 T2 T3 B2 B3 R1 P1 P2 U1);
|
||||
my %conn = ();
|
||||
map {$conn{$_} = $_} @conncodes;
|
||||
|
||||
@@ -355,6 +355,7 @@ $connmsg{"B1"} = "Bad Ber Tag Encountered";
|
||||
$connmsg{"B4"} = "Server failed to flush data (response) back to Client";
|
||||
$connmsg{"T1"} = "Idle Timeout Exceeded";
|
||||
$connmsg{"T2"} = "IO Block Timeout Exceeded or NTSSL Timeout";
|
||||
+$connmsg{"T3"} = "Paged Search Time Limit Exceeded";
|
||||
$connmsg{"B2"} = "Ber Too Big";
|
||||
$connmsg{"B3"} = "Ber Peek";
|
||||
$connmsg{"R1"} = "Revents";
|
||||
@@ -1723,6 +1724,10 @@ if ($usage =~ /j/i || $verb eq "yes"){
|
||||
print "\n $recCount. You have some coonections that are being closed by the ioblocktimeout setting. You may want to increase the ioblocktimeout.\n";
|
||||
$recCount++;
|
||||
}
|
||||
+ if (defined($conncount->{"T3"}) and $conncount->{"T3"} > 0){
|
||||
+ print "\n $recCount. You have some connections that are being closed because a paged result search limit has been exceeded. You may want to increase the search time limit.\n";
|
||||
+ $recCount++;
|
||||
+ }
|
||||
# compare binds to unbinds, if the difference is more than 30% of the binds, then report a issue
|
||||
if (($bindCount - $unbindCount) > ($bindCount*.3)){
|
||||
print "\n $recCount. You have a significant difference between binds and unbinds. You may want to investigate this difference.\n";
|
||||
@@ -2366,6 +2371,7 @@ sub parseLineNormal
|
||||
$brokenPipeCount++;
|
||||
if (m/- T1/){ $hashes->{rc}->{"T1"}++; }
|
||||
elsif (m/- T2/){ $hashes->{rc}->{"T2"}++; }
|
||||
+ elsif (m/- T3/){ $hashes->{rc}->{"T3"}++; }
|
||||
elsif (m/- A1/){ $hashes->{rc}->{"A1"}++; }
|
||||
elsif (m/- B1/){ $hashes->{rc}->{"B1"}++; }
|
||||
elsif (m/- B4/){ $hashes->{rc}->{"B4"}++; }
|
||||
@@ -2381,6 +2387,7 @@ sub parseLineNormal
|
||||
$connResetByPeerCount++;
|
||||
if (m/- T1/){ $hashes->{src}->{"T1"}++; }
|
||||
elsif (m/- T2/){ $hashes->{src}->{"T2"}++; }
|
||||
+ elsif (m/- T3/){ $hashes->{src}->{"T3"}++; }
|
||||
elsif (m/- A1/){ $hashes->{src}->{"A1"}++; }
|
||||
elsif (m/- B1/){ $hashes->{src}->{"B1"}++; }
|
||||
elsif (m/- B4/){ $hashes->{src}->{"B4"}++; }
|
||||
@@ -2396,6 +2403,7 @@ sub parseLineNormal
|
||||
$resourceUnavailCount++;
|
||||
if (m/- T1/){ $hashes->{rsrc}->{"T1"}++; }
|
||||
elsif (m/- T2/){ $hashes->{rsrc}->{"T2"}++; }
|
||||
+ elsif (m/- T3/){ $hashes->{rsrc}->{"T3"}++; }
|
||||
elsif (m/- A1/){ $hashes->{rsrc}->{"A1"}++; }
|
||||
elsif (m/- B1/){ $hashes->{rsrc}->{"B1"}++; }
|
||||
elsif (m/- B4/){ $hashes->{rsrc}->{"B4"}++; }
|
||||
@@ -2494,6 +2502,20 @@ sub parseLineNormal
|
||||
}
|
||||
}
|
||||
}
|
||||
+ if (m/- T3/){
|
||||
+ if ($_ =~ /conn= *([0-9A-Z]+)/i) {
|
||||
+ $exc = "no";
|
||||
+ $ip = getIPfromConn($1, $serverRestartCount);
|
||||
+ for (my $xxx = 0; $xxx < $#excludeIP; $xxx++){
|
||||
+ if ($ip eq $excludeIP[$xxx]){$exc = "yes";}
|
||||
+ }
|
||||
+ if ($exc ne "yes"){
|
||||
+ $hashes->{T3}->{$ip}++;
|
||||
+ $hashes->{conncount}->{"T3"}++;
|
||||
+ $connCodeCount++;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
if (m/- B2/){
|
||||
if ($_ =~ /conn= *([0-9A-Z]+)/i) {
|
||||
$exc = "no";
|
||||
diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
|
||||
index 5a48aa66f..bb80dae36 100644
|
||||
--- a/ldap/servers/slapd/daemon.c
|
||||
+++ b/ldap/servers/slapd/daemon.c
|
||||
@@ -1599,9 +1599,9 @@ setup_pr_read_pds(Connection_Table *ct)
|
||||
int add_fd = 1;
|
||||
/* check timeout for PAGED RESULTS */
|
||||
if (pagedresults_is_timedout_nolock(c)) {
|
||||
- /* Exceeded the timelimit; disconnect the client */
|
||||
+ /* Exceeded the paged search timelimit; disconnect the client */
|
||||
disconnect_server_nomutex(c, c->c_connid, -1,
|
||||
- SLAPD_DISCONNECT_IO_TIMEOUT,
|
||||
+ SLAPD_DISCONNECT_PAGED_SEARCH_LIMIT,
|
||||
0);
|
||||
connection_table_move_connection_out_of_active_list(ct,
|
||||
c);
|
||||
diff --git a/ldap/servers/slapd/disconnect_error_strings.h b/ldap/servers/slapd/disconnect_error_strings.h
|
||||
index f7a31d728..c2d9e283b 100644
|
||||
--- a/ldap/servers/slapd/disconnect_error_strings.h
|
||||
+++ b/ldap/servers/slapd/disconnect_error_strings.h
|
||||
@@ -27,6 +27,7 @@ ER2(SLAPD_DISCONNECT_BER_FLUSH, "B4")
|
||||
ER2(SLAPD_DISCONNECT_IDLE_TIMEOUT, "T1")
|
||||
ER2(SLAPD_DISCONNECT_REVENTS, "R1")
|
||||
ER2(SLAPD_DISCONNECT_IO_TIMEOUT, "T2")
|
||||
+ER2(SLAPD_DISCONNECT_PAGED_SEARCH_LIMIT, "T3")
|
||||
ER2(SLAPD_DISCONNECT_PLUGIN, "P1")
|
||||
ER2(SLAPD_DISCONNECT_UNBIND, "U1")
|
||||
ER2(SLAPD_DISCONNECT_POLL, "P2")
|
||||
diff --git a/ldap/servers/slapd/disconnect_errors.h b/ldap/servers/slapd/disconnect_errors.h
|
||||
index a0484f1c2..e118f674c 100644
|
||||
--- a/ldap/servers/slapd/disconnect_errors.h
|
||||
+++ b/ldap/servers/slapd/disconnect_errors.h
|
||||
@@ -35,6 +35,6 @@
|
||||
#define SLAPD_DISCONNECT_SASL_FAIL SLAPD_DISCONNECT_ERROR_BASE + 12
|
||||
#define SLAPD_DISCONNECT_PROXY_INVALID_HEADER SLAPD_DISCONNECT_ERROR_BASE + 13
|
||||
#define SLAPD_DISCONNECT_PROXY_UNKNOWN SLAPD_DISCONNECT_ERROR_BASE + 14
|
||||
-
|
||||
+#define SLAPD_DISCONNECT_PAGED_SEARCH_LIMIT SLAPD_DISCONNECT_ERROR_BASE + 15
|
||||
|
||||
#endif /* __DISCONNECT_ERRORS_H_ */
|
||||
--
|
||||
2.45.0
|
||||
|
||||
@ -1,44 +0,0 @@
|
||||
From a112394af3a20787755029804684d57a9c3ffa9a Mon Sep 17 00:00:00 2001
|
||||
From: James Chapman <jachapma@redhat.com>
|
||||
Date: Wed, 21 Feb 2024 12:43:03 +0000
|
||||
Subject: [PATCH] Issue 6103 - New connection timeout error breaks errormap
|
||||
(#6104)
|
||||
|
||||
Bug description: A recent addition to the connection disconnect error
|
||||
messaging, conflicts with how errormap.c maps error codes/strings.
|
||||
|
||||
Fix description: errormap expects error codes/strings to be in ascending
|
||||
order. Moved the new error code to the bottom of the list.
|
||||
|
||||
Relates: https://github.com/389ds/389-ds-base/issues/6103
|
||||
|
||||
Reviewed by: @droideck. @progier389 (Thank you)
|
||||
---
|
||||
ldap/servers/slapd/disconnect_error_strings.h | 5 +++--
|
||||
1 file changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/ldap/servers/slapd/disconnect_error_strings.h b/ldap/servers/slapd/disconnect_error_strings.h
|
||||
index c2d9e283b..f603a08ce 100644
|
||||
--- a/ldap/servers/slapd/disconnect_error_strings.h
|
||||
+++ b/ldap/servers/slapd/disconnect_error_strings.h
|
||||
@@ -14,7 +14,8 @@
|
||||
/* disconnect_error_strings.h
|
||||
*
|
||||
* Strings describing the errors used in logging the reason a connection
|
||||
- * was closed.
|
||||
+ * was closed. Ensure definitions are in the same order as the error codes
|
||||
+ * defined in disconnect_errors.h
|
||||
*/
|
||||
#ifndef __DISCONNECT_ERROR_STRINGS_H_
|
||||
#define __DISCONNECT_ERROR_STRINGS_H_
|
||||
@@ -35,6 +36,6 @@ ER2(SLAPD_DISCONNECT_NTSSL_TIMEOUT, "T2")
|
||||
ER2(SLAPD_DISCONNECT_SASL_FAIL, "S1")
|
||||
ER2(SLAPD_DISCONNECT_PROXY_INVALID_HEADER, "P3")
|
||||
ER2(SLAPD_DISCONNECT_PROXY_UNKNOWN, "P4")
|
||||
-
|
||||
+ER2(SLAPD_DISCONNECT_PAGED_SEARCH_LIMIT, "T3")
|
||||
|
||||
#endif /* __DISCONNECT_ERROR_STRINGS_H_ */
|
||||
--
|
||||
2.45.0
|
||||
|
||||
@ -1,30 +0,0 @@
|
||||
From edd9abc8901604dde1d739d87ca2906734d53dd3 Mon Sep 17 00:00:00 2001
|
||||
From: Viktor Ashirov <vashirov@redhat.com>
|
||||
Date: Thu, 13 Jun 2024 13:35:09 +0200
|
||||
Subject: [PATCH] Issue 6103 - New connection timeout error breaks errormap
|
||||
|
||||
Description:
|
||||
Remove duplicate SLAPD_DISCONNECT_PAGED_SEARCH_LIMIT error code.
|
||||
|
||||
Fixes: https://github.com/389ds/389-ds-base/issues/6103
|
||||
|
||||
Reviewed by: @tbordaz (Thanks!)
|
||||
---
|
||||
ldap/servers/slapd/disconnect_error_strings.h | 1 -
|
||||
1 file changed, 1 deletion(-)
|
||||
|
||||
diff --git a/ldap/servers/slapd/disconnect_error_strings.h b/ldap/servers/slapd/disconnect_error_strings.h
|
||||
index f603a08ce..d49cc79a2 100644
|
||||
--- a/ldap/servers/slapd/disconnect_error_strings.h
|
||||
+++ b/ldap/servers/slapd/disconnect_error_strings.h
|
||||
@@ -28,7 +28,6 @@ ER2(SLAPD_DISCONNECT_BER_FLUSH, "B4")
|
||||
ER2(SLAPD_DISCONNECT_IDLE_TIMEOUT, "T1")
|
||||
ER2(SLAPD_DISCONNECT_REVENTS, "R1")
|
||||
ER2(SLAPD_DISCONNECT_IO_TIMEOUT, "T2")
|
||||
-ER2(SLAPD_DISCONNECT_PAGED_SEARCH_LIMIT, "T3")
|
||||
ER2(SLAPD_DISCONNECT_PLUGIN, "P1")
|
||||
ER2(SLAPD_DISCONNECT_UNBIND, "U1")
|
||||
ER2(SLAPD_DISCONNECT_POLL, "P2")
|
||||
--
|
||||
2.45.0
|
||||
|
||||
@ -1,220 +0,0 @@
|
||||
From 8cf981c00ae18d3efaeb10819282cd991621e9a2 Mon Sep 17 00:00:00 2001
|
||||
From: tbordaz <tbordaz@redhat.com>
|
||||
Date: Wed, 22 May 2024 11:29:05 +0200
|
||||
Subject: [PATCH] Issue 6172 - RFE: improve the performance of evaluation of
|
||||
filter component when tested against a large valueset (like group members)
|
||||
(#6173)
|
||||
|
||||
Bug description:
|
||||
Before returning an entry (to a SRCH) the server checks that the entry matches the SRCH filter.
|
||||
If a filter component (equality) is testing the value (ava) against a
|
||||
large valueset (like uniquemember values), it takes a long time because
|
||||
of the large number of values and required normalization of the values.
|
||||
This can be improved taking benefit of sorted valueset. Those sorted
|
||||
valueset were created to improve updates of large valueset (groups) but
|
||||
at that time not implemented in SRCH path.
|
||||
|
||||
Fix description:
|
||||
In case of LDAP_FILTER_EQUALITY component, the server can get
|
||||
benefit of the sorted valuearray.
|
||||
To limit the risk of regression, we use the sorted valuearray
|
||||
only for the DN syntax attribute. Indeed the sorted valuearray was
|
||||
designed for those type of attribute.
|
||||
With those two limitations, there is no need of a toggle and
|
||||
the call to plugin_call_syntax_filter_ava can be replaced by
|
||||
a call to slapi_valueset_find.
|
||||
In both cases, sorted valueset and plugin_call_syntax_filter_ava, ava and
|
||||
values are normalized.
|
||||
In sorted valueset, the values have been normalized to insert the index
|
||||
in the sorted array and then comparison is done on normalized values.
|
||||
In plugin_call_syntax_filter_ava, all values in valuearray (of valueset) are normalized
|
||||
before comparison.
|
||||
|
||||
relates: #6172
|
||||
|
||||
Reviewed by: Pierre Rogier, Simon Pichugin (Big Thanks !!!)
|
||||
---
|
||||
.../tests/suites/filter/filter_test.py | 125 ++++++++++++++++++
|
||||
ldap/servers/slapd/filterentry.c | 22 ++-
|
||||
2 files changed, 146 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/filter/filter_test.py b/dirsrvtests/tests/suites/filter/filter_test.py
|
||||
index d6bfa5a3b..4baaf04a7 100644
|
||||
--- a/dirsrvtests/tests/suites/filter/filter_test.py
|
||||
+++ b/dirsrvtests/tests/suites/filter/filter_test.py
|
||||
@@ -9,7 +9,11 @@
|
||||
import logging
|
||||
|
||||
import pytest
|
||||
+import time
|
||||
+from lib389.dirsrv_log import DirsrvAccessLog
|
||||
from lib389.tasks import *
|
||||
+from lib389.backend import Backends, Backend
|
||||
+from lib389.dbgen import dbgen_users, dbgen_groups
|
||||
from lib389.topologies import topology_st
|
||||
from lib389._constants import PASSWORD, DEFAULT_SUFFIX, DN_DM, SUFFIX
|
||||
from lib389.utils import *
|
||||
@@ -304,6 +308,127 @@ def test_extended_search(topology_st):
|
||||
ents = topology_st.standalone.search_s(SUFFIX, ldap.SCOPE_SUBTREE, myfilter)
|
||||
assert len(ents) == 1
|
||||
|
||||
+def test_match_large_valueset(topology_st):
|
||||
+ """Test that when returning a big number of entries
|
||||
+ and that we need to match the filter from a large valueset
|
||||
+ we get benefit to use the sorted valueset
|
||||
+
|
||||
+ :id: 7db5aa88-50e0-4c31-85dd-1d2072cb674c
|
||||
+
|
||||
+ :setup: Standalone instance
|
||||
+
|
||||
+ :steps:
|
||||
+ 1. Create a users and groups backends and tune them
|
||||
+ 2. Generate a test ldif (2k users and 1K groups with all users)
|
||||
+ 3. Import test ldif file using Offline import (ldif2db).
|
||||
+ 4. Prim the 'groups' entrycache with a "fast" search
|
||||
+ 5. Search the 'groups' with a difficult matching value
|
||||
+ 6. check that etime from step 5 is less than a second
|
||||
+
|
||||
+ :expectedresults:
|
||||
+ 1. Create a users and groups backends should PASS
|
||||
+ 2. Generate LDIF should PASS.
|
||||
+ 3. Offline import should PASS.
|
||||
+ 4. Priming should PASS.
|
||||
+ 5. Performance search should PASS.
|
||||
+ 6. Etime of performance search should PASS.
|
||||
+ """
|
||||
+
|
||||
+ log.info('Running test_match_large_valueset...')
|
||||
+ #
|
||||
+ # Test online/offline LDIF imports
|
||||
+ #
|
||||
+ inst = topology_st.standalone
|
||||
+ inst.start()
|
||||
+ backends = Backends(inst)
|
||||
+ users_suffix = "ou=users,%s" % DEFAULT_SUFFIX
|
||||
+ users_backend = 'users'
|
||||
+ users_ldif = 'users_import.ldif'
|
||||
+ groups_suffix = "ou=groups,%s" % DEFAULT_SUFFIX
|
||||
+ groups_backend = 'groups'
|
||||
+ groups_ldif = 'groups_import.ldif'
|
||||
+ groups_entrycache = '200000000'
|
||||
+ users_number = 2000
|
||||
+ groups_number = 1000
|
||||
+
|
||||
+
|
||||
+ # For priming the cache we just want to be fast
|
||||
+ # taking the first value in the valueset is good
|
||||
+ # whether the valueset is sorted or not
|
||||
+ priming_user_rdn = "user0001"
|
||||
+
|
||||
+ # For performance testing, this is important to use
|
||||
+ # user1000 rather then user0001
|
||||
+ # Because user0001 is the first value in the valueset
|
||||
+ # whether we use the sorted valuearray or non sorted
|
||||
+ # valuearray the performance will be similar.
|
||||
+ # With middle value user1000, the performance boost of
|
||||
+ # the sorted valuearray will make the difference.
|
||||
+ perf_user_rdn = "user1000"
|
||||
+
|
||||
+ # Step 1. Prepare the backends and tune the groups entrycache
|
||||
+ try:
|
||||
+ be_users = backends.create(properties={'parent': DEFAULT_SUFFIX, 'nsslapd-suffix': users_suffix, 'name': users_backend})
|
||||
+ be_groups = backends.create(properties={'parent': DEFAULT_SUFFIX, 'nsslapd-suffix': groups_suffix, 'name': groups_backend})
|
||||
+
|
||||
+ # set the entry cache to 200Mb as the 1K groups of 2K users require at least 170Mb
|
||||
+ be_groups.replace('nsslapd-cachememsize', groups_entrycache)
|
||||
+ except:
|
||||
+ raise
|
||||
+
|
||||
+ # Step 2. Generate a test ldif (10k users entries)
|
||||
+ log.info("Generating users LDIF...")
|
||||
+ ldif_dir = inst.get_ldif_dir()
|
||||
+ users_import_ldif = "%s/%s" % (ldif_dir, users_ldif)
|
||||
+ groups_import_ldif = "%s/%s" % (ldif_dir, groups_ldif)
|
||||
+ dbgen_users(inst, users_number, users_import_ldif, suffix=users_suffix, generic=True, parent=users_suffix)
|
||||
+
|
||||
+ # Generate a test ldif (800 groups with 10k members) that fit in 700Mb entry cache
|
||||
+ props = {
|
||||
+ "name": "group",
|
||||
+ "suffix": groups_suffix,
|
||||
+ "parent": groups_suffix,
|
||||
+ "number": groups_number,
|
||||
+ "numMembers": users_number,
|
||||
+ "createMembers": False,
|
||||
+ "memberParent": users_suffix,
|
||||
+ "membershipAttr": "uniquemember",
|
||||
+ }
|
||||
+ dbgen_groups(inst, groups_import_ldif, props)
|
||||
+
|
||||
+ # Step 3. Do the both offline imports
|
||||
+ inst.stop()
|
||||
+ if not inst.ldif2db(users_backend, None, None, None, users_import_ldif):
|
||||
+ log.fatal('test_basic_import_export: Offline users import failed')
|
||||
+ assert False
|
||||
+ if not inst.ldif2db(groups_backend, None, None, None, groups_import_ldif):
|
||||
+ log.fatal('test_basic_import_export: Offline groups import failed')
|
||||
+ assert False
|
||||
+ inst.start()
|
||||
+
|
||||
+ # Step 4. first prime the cache
|
||||
+ # Just request the 'DN'. We are interested by the time of matching not by the time of transfert
|
||||
+ entries = topology_st.standalone.search_s(groups_suffix, ldap.SCOPE_SUBTREE, "(&(objectclass=groupOfUniqueNames)(uniquemember=uid=%s,%s))" % (priming_user_rdn, users_suffix), ['dn'])
|
||||
+ assert len(entries) == groups_number
|
||||
+
|
||||
+ # Step 5. Now do the real performance checking it should take less than a second
|
||||
+ # Just request the 'DN'. We are interested by the time of matching not by the time of transfert
|
||||
+ search_start = time.time()
|
||||
+ entries = topology_st.standalone.search_s(groups_suffix, ldap.SCOPE_SUBTREE, "(&(objectclass=groupOfUniqueNames)(uniquemember=uid=%s,%s))" % (perf_user_rdn, users_suffix), ['dn'])
|
||||
+ duration = time.time() - search_start
|
||||
+ log.info("Duration of the search was %f", duration)
|
||||
+
|
||||
+ # Step 6. Gather the etime from the access log
|
||||
+ inst.stop()
|
||||
+ access_log = DirsrvAccessLog(inst)
|
||||
+ search_result = access_log.match(".*RESULT err=0 tag=101 nentries=%s.*" % groups_number)
|
||||
+ log.info("Found patterns are %s", search_result[0])
|
||||
+ log.info("Found patterns are %s", search_result[1])
|
||||
+ etime = float(search_result[1].split('etime=')[1])
|
||||
+ log.info("Duration of the search from access log was %f", etime)
|
||||
+ assert len(entries) == groups_number
|
||||
+ assert (etime < 1)
|
||||
+
|
||||
if __name__ == '__main__':
|
||||
# Run isolated
|
||||
# -s for DEBUG mode
|
||||
diff --git a/ldap/servers/slapd/filterentry.c b/ldap/servers/slapd/filterentry.c
|
||||
index fd8fdda9f..cae5c7edc 100644
|
||||
--- a/ldap/servers/slapd/filterentry.c
|
||||
+++ b/ldap/servers/slapd/filterentry.c
|
||||
@@ -296,7 +296,27 @@ test_ava_filter(
|
||||
rc = -1;
|
||||
for (; a != NULL; a = a->a_next) {
|
||||
if (slapi_attr_type_cmp(ava->ava_type, a->a_type, SLAPI_TYPE_CMP_SUBTYPE) == 0) {
|
||||
- rc = plugin_call_syntax_filter_ava(a, ftype, ava);
|
||||
+ if ((ftype == LDAP_FILTER_EQUALITY) &&
|
||||
+ (slapi_attr_is_dn_syntax_type(a->a_type))) {
|
||||
+ /* This path is for a performance improvement */
|
||||
+
|
||||
+ /* In case of equality filter we can get benefit of the
|
||||
+ * sorted valuearray (from valueset).
|
||||
+ * This improvement is limited to DN syntax attributes for
|
||||
+ * which the sorted valueset was designed.
|
||||
+ */
|
||||
+ Slapi_Value *sval = NULL;
|
||||
+ sval = slapi_value_new_berval(&ava->ava_value);
|
||||
+ if (slapi_valueset_find((const Slapi_Attr *)a, &a->a_present_values, sval)) {
|
||||
+ rc = 0;
|
||||
+ }
|
||||
+ slapi_value_free(&sval);
|
||||
+ } else {
|
||||
+ /* When sorted valuearray optimization cannot be used
|
||||
+ * lets filter the value according to its syntax
|
||||
+ */
|
||||
+ rc = plugin_call_syntax_filter_ava(a, ftype, ava);
|
||||
+ }
|
||||
if (rc == 0) {
|
||||
break;
|
||||
}
|
||||
--
|
||||
2.46.0
|
||||
|
||||
@ -1,163 +0,0 @@
|
||||
From 57051154bafaf50b83fc27dadbd89a49fd1c8c36 Mon Sep 17 00:00:00 2001
|
||||
From: Pierre Rogier <progier@redhat.com>
|
||||
Date: Fri, 14 Jun 2024 13:27:10 +0200
|
||||
Subject: [PATCH] Security fix for CVE-2024-5953
|
||||
|
||||
Description:
|
||||
A denial of service vulnerability was found in the 389 Directory Server.
|
||||
This issue may allow an authenticated user to cause a server denial
|
||||
of service while attempting to log in with a user with a malformed hash
|
||||
in their password.
|
||||
|
||||
Fix Description:
|
||||
To prevent buffer overflow when a bind request is processed, the bind fails
|
||||
if the hash size is not coherent without even attempting to process further
|
||||
the hashed password.
|
||||
|
||||
References:
|
||||
- https://nvd.nist.gov/vuln/detail/CVE-2024-5953
|
||||
- https://access.redhat.com/security/cve/CVE-2024-5953
|
||||
- https://bugzilla.redhat.com/show_bug.cgi?id=2292104
|
||||
---
|
||||
.../tests/suites/password/regression_test.py | 54 ++++++++++++++++++-
|
||||
ldap/servers/plugins/pwdstorage/md5_pwd.c | 9 +++-
|
||||
ldap/servers/plugins/pwdstorage/pbkdf2_pwd.c | 6 +++
|
||||
3 files changed, 66 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/password/regression_test.py b/dirsrvtests/tests/suites/password/regression_test.py
|
||||
index 8f1facb6d..1fa581643 100644
|
||||
--- a/dirsrvtests/tests/suites/password/regression_test.py
|
||||
+++ b/dirsrvtests/tests/suites/password/regression_test.py
|
||||
@@ -7,12 +7,14 @@
|
||||
#
|
||||
import pytest
|
||||
import time
|
||||
+import glob
|
||||
+import base64
|
||||
from lib389._constants import PASSWORD, DN_DM, DEFAULT_SUFFIX
|
||||
from lib389._constants import SUFFIX, PASSWORD, DN_DM, DN_CONFIG, PLUGIN_RETRO_CHANGELOG, DEFAULT_SUFFIX, DEFAULT_CHANGELOG_DB
|
||||
from lib389 import Entry
|
||||
from lib389.topologies import topology_m1 as topo_supplier
|
||||
-from lib389.idm.user import UserAccounts
|
||||
-from lib389.utils import ldap, os, logging, ensure_bytes, ds_is_newer
|
||||
+from lib389.idm.user import UserAccounts, UserAccount
|
||||
+from lib389.utils import ldap, os, logging, ensure_bytes, ds_is_newer, ds_supports_new_changelog
|
||||
from lib389.topologies import topology_st as topo
|
||||
from lib389.idm.organizationalunit import OrganizationalUnits
|
||||
|
||||
@@ -39,6 +41,13 @@ TEST_PASSWORDS += ['CNpwtest1ZZZZ', 'ZZZZZCNpwtest1',
|
||||
TEST_PASSWORDS2 = (
|
||||
'CN12pwtest31', 'SN3pwtest231', 'UID1pwtest123', 'MAIL2pwtest12@redhat.com', '2GN1pwtest123', 'People123')
|
||||
|
||||
+SUPPORTED_SCHEMES = (
|
||||
+ "{SHA}", "{SSHA}", "{SHA256}", "{SSHA256}",
|
||||
+ "{SHA384}", "{SSHA384}", "{SHA512}", "{SSHA512}",
|
||||
+ "{crypt}", "{NS-MTA-MD5}", "{clear}", "{MD5}",
|
||||
+ "{SMD5}", "{PBKDF2_SHA256}", "{PBKDF2_SHA512}",
|
||||
+ "{GOST_YESCRYPT}", "{PBKDF2-SHA256}", "{PBKDF2-SHA512}" )
|
||||
+
|
||||
def _check_unhashed_userpw(inst, user_dn, is_present=False):
|
||||
"""Check if unhashed#user#password attribute is present or not in the changelog"""
|
||||
unhashed_pwd_attribute = 'unhashed#user#password'
|
||||
@@ -319,6 +328,47 @@ def test_unhashed_pw_switch(topo_supplier):
|
||||
# Add debugging steps(if any)...
|
||||
pass
|
||||
|
||||
+@pytest.mark.parametrize("scheme", SUPPORTED_SCHEMES )
|
||||
+def test_long_hashed_password(topo, create_user, scheme):
|
||||
+ """Check that hashed password with very long value does not cause trouble
|
||||
+
|
||||
+ :id: 252a1f76-114b-11ef-8a7a-482ae39447e5
|
||||
+ :setup: standalone Instance
|
||||
+ :parametrized: yes
|
||||
+ :steps:
|
||||
+ 1. Add a test user user
|
||||
+ 2. Set a long password with requested scheme
|
||||
+ 3. Bind on that user using a wrong password
|
||||
+ 4. Check that instance is still alive
|
||||
+ 5. Remove the added user
|
||||
+ :expectedresults:
|
||||
+ 1. Success
|
||||
+ 2. Success
|
||||
+ 3. Should get ldap.INVALID_CREDENTIALS exception
|
||||
+ 4. Success
|
||||
+ 5. Success
|
||||
+ """
|
||||
+ inst = topo.standalone
|
||||
+ inst.simple_bind_s(DN_DM, PASSWORD)
|
||||
+ users = UserAccounts(inst, DEFAULT_SUFFIX)
|
||||
+ # Make sure that server is started as this test may crash it
|
||||
+ inst.start()
|
||||
+ # Adding Test user (It may already exists if previous test failed)
|
||||
+ user2 = UserAccount(inst, dn='uid=test_user_1002,ou=People,dc=example,dc=com')
|
||||
+ if not user2.exists():
|
||||
+ user2 = users.create_test_user(uid=1002, gid=2002)
|
||||
+ # Setting hashed password
|
||||
+ passwd = 'A'*4000
|
||||
+ hashed_passwd = scheme.encode('utf-8') + base64.b64encode(passwd.encode('utf-8'))
|
||||
+ user2.replace('userpassword', hashed_passwd)
|
||||
+ # Bind on that user using a wrong password
|
||||
+ with pytest.raises(ldap.INVALID_CREDENTIALS):
|
||||
+ conn = user2.bind(PASSWORD)
|
||||
+ # Check that instance is still alive
|
||||
+ assert inst.status()
|
||||
+ # Remove the added user
|
||||
+ user2.delete()
|
||||
+
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Run isolated
|
||||
diff --git a/ldap/servers/plugins/pwdstorage/md5_pwd.c b/ldap/servers/plugins/pwdstorage/md5_pwd.c
|
||||
index 1e2cf58e7..b9a48d5ca 100644
|
||||
--- a/ldap/servers/plugins/pwdstorage/md5_pwd.c
|
||||
+++ b/ldap/servers/plugins/pwdstorage/md5_pwd.c
|
||||
@@ -37,6 +37,7 @@ md5_pw_cmp(const char *userpwd, const char *dbpwd)
|
||||
unsigned char hash_out[MD5_HASH_LEN];
|
||||
unsigned char b2a_out[MD5_HASH_LEN * 2]; /* conservative */
|
||||
SECItem binary_item;
|
||||
+ size_t dbpwd_len = strlen(dbpwd);
|
||||
|
||||
ctx = PK11_CreateDigestContext(SEC_OID_MD5);
|
||||
if (ctx == NULL) {
|
||||
@@ -45,6 +46,12 @@ md5_pw_cmp(const char *userpwd, const char *dbpwd)
|
||||
goto loser;
|
||||
}
|
||||
|
||||
+ if (dbpwd_len >= sizeof b2a_out) {
|
||||
+ slapi_log_err(SLAPI_LOG_PLUGIN, MD5_SUBSYSTEM_NAME,
|
||||
+ "The hashed password stored in the user entry is longer than any valid md5 hash");
|
||||
+ goto loser;
|
||||
+ }
|
||||
+
|
||||
/* create the hash */
|
||||
PK11_DigestBegin(ctx);
|
||||
PK11_DigestOp(ctx, (const unsigned char *)userpwd, strlen(userpwd));
|
||||
@@ -57,7 +64,7 @@ md5_pw_cmp(const char *userpwd, const char *dbpwd)
|
||||
bver = NSSBase64_EncodeItem(NULL, (char *)b2a_out, sizeof b2a_out, &binary_item);
|
||||
/* bver points to b2a_out upon success */
|
||||
if (bver) {
|
||||
- rc = slapi_ct_memcmp(bver, dbpwd, strlen(dbpwd));
|
||||
+ rc = slapi_ct_memcmp(bver, dbpwd, dbpwd_len);
|
||||
} else {
|
||||
slapi_log_err(SLAPI_LOG_PLUGIN, MD5_SUBSYSTEM_NAME,
|
||||
"Could not base64 encode hashed value for password compare");
|
||||
diff --git a/ldap/servers/plugins/pwdstorage/pbkdf2_pwd.c b/ldap/servers/plugins/pwdstorage/pbkdf2_pwd.c
|
||||
index dcac4fcdd..82b8c9501 100644
|
||||
--- a/ldap/servers/plugins/pwdstorage/pbkdf2_pwd.c
|
||||
+++ b/ldap/servers/plugins/pwdstorage/pbkdf2_pwd.c
|
||||
@@ -255,6 +255,12 @@ pbkdf2_sha256_pw_cmp(const char *userpwd, const char *dbpwd)
|
||||
passItem.data = (unsigned char *)userpwd;
|
||||
passItem.len = strlen(userpwd);
|
||||
|
||||
+ if (pwdstorage_base64_decode_len(dbpwd, dbpwd_len) > sizeof dbhash) {
|
||||
+ /* Hashed value is too long and cannot match any value generated by pbkdf2_sha256_hash */
|
||||
+ slapi_log_err(SLAPI_LOG_ERR, (char *)schemeName, "Unable to base64 decode dbpwd value. (hashed value is too long)\n");
|
||||
+ return result;
|
||||
+ }
|
||||
+
|
||||
/* Decode the DBpwd to bytes from b64 */
|
||||
if (PL_Base64Decode(dbpwd, dbpwd_len, dbhash) == NULL) {
|
||||
slapi_log_err(SLAPI_LOG_ERR, (char *)schemeName, "Unable to base64 decode dbpwd value\n");
|
||||
--
|
||||
2.46.0
|
||||
|
||||
@ -1,178 +0,0 @@
|
||||
From e8a5b1deef1b455aafecb71efc029d2407b1b06f Mon Sep 17 00:00:00 2001
|
||||
From: Simon Pichugin <spichugi@redhat.com>
|
||||
Date: Tue, 16 Jul 2024 08:32:21 -0700
|
||||
Subject: [PATCH] Issue 4778 - Add COMPACT_CL5 task to dsconf replication
|
||||
(#6260)
|
||||
|
||||
Description: In 1.4.3, the changelog is not part of a backend.
|
||||
It can be compacted with nsds5task: CAMPACT_CL5 as part of the replication entry.
|
||||
Add the task as a compact-changelog command under the dsconf replication tool.
|
||||
Add tests for the feature and fix old tests.
|
||||
|
||||
Related: https://github.com/389ds/389-ds-base/issues/4778
|
||||
|
||||
Reviewed by: @progier389 (Thanks!)
|
||||
---
|
||||
.../tests/suites/config/compact_test.py | 36 ++++++++++++++---
|
||||
src/lib389/lib389/cli_conf/replication.py | 10 +++++
|
||||
src/lib389/lib389/replica.py | 40 +++++++++++++++++++
|
||||
3 files changed, 81 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/config/compact_test.py b/dirsrvtests/tests/suites/config/compact_test.py
|
||||
index 317258d0e..31d98d10c 100644
|
||||
--- a/dirsrvtests/tests/suites/config/compact_test.py
|
||||
+++ b/dirsrvtests/tests/suites/config/compact_test.py
|
||||
@@ -13,14 +13,14 @@ import time
|
||||
import datetime
|
||||
from lib389.tasks import DBCompactTask
|
||||
from lib389.backend import DatabaseConfig
|
||||
-from lib389.replica import Changelog5
|
||||
+from lib389.replica import Changelog5, Replicas
|
||||
from lib389.topologies import topology_m1 as topo
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def test_compact_db_task(topo):
|
||||
- """Specify a test case purpose or name here
|
||||
+ """Test compaction of database
|
||||
|
||||
:id: 1b3222ef-a336-4259-be21-6a52f76e1859
|
||||
:setup: Standalone Instance
|
||||
@@ -48,7 +48,7 @@ def test_compact_db_task(topo):
|
||||
|
||||
|
||||
def test_compaction_interval_and_time(topo):
|
||||
- """Specify a test case purpose or name here
|
||||
+ """Test compaction interval and time for database and changelog
|
||||
|
||||
:id: f361bee9-d7e7-4569-9255-d7b60dd9d92e
|
||||
:setup: Supplier Instance
|
||||
@@ -95,10 +95,36 @@ def test_compaction_interval_and_time(topo):
|
||||
|
||||
# Check compaction occurred as expected
|
||||
time.sleep(45)
|
||||
- assert not inst.searchErrorsLog("Compacting databases")
|
||||
+ assert not inst.searchErrorsLog("compacting replication changelogs")
|
||||
|
||||
time.sleep(90)
|
||||
- assert inst.searchErrorsLog("Compacting databases")
|
||||
+ assert inst.searchErrorsLog("compacting replication changelogs")
|
||||
+ inst.deleteErrorLogs(restart=False)
|
||||
+
|
||||
+
|
||||
+def test_compact_cl5_task(topo):
|
||||
+ """Test compaction of changelog5 database
|
||||
+
|
||||
+ :id: aadfa9f7-73c0-463a-912c-0a29aa1f8167
|
||||
+ :setup: Standalone Instance
|
||||
+ :steps:
|
||||
+ 1. Run compaction task
|
||||
+ 2. Check errors log to show task was run
|
||||
+ :expectedresults:
|
||||
+ 1. Success
|
||||
+ 2. Success
|
||||
+ """
|
||||
+ inst = topo.ms["supplier1"]
|
||||
+
|
||||
+ replicas = Replicas(inst)
|
||||
+ replicas.compact_changelog(log=log)
|
||||
+
|
||||
+ # Check compaction occurred as expected. But instead of time.sleep(5) check 1 sec in loop
|
||||
+ for _ in range(5):
|
||||
+ time.sleep(1)
|
||||
+ if inst.searchErrorsLog("compacting replication changelogs"):
|
||||
+ break
|
||||
+ assert inst.searchErrorsLog("compacting replication changelogs")
|
||||
inst.deleteErrorLogs(restart=False)
|
||||
|
||||
|
||||
diff --git a/src/lib389/lib389/cli_conf/replication.py b/src/lib389/lib389/cli_conf/replication.py
|
||||
index 352c0ee5b..ccc394255 100644
|
||||
--- a/src/lib389/lib389/cli_conf/replication.py
|
||||
+++ b/src/lib389/lib389/cli_conf/replication.py
|
||||
@@ -1199,6 +1199,11 @@ def restore_cl_dir(inst, basedn, log, args):
|
||||
replicas.restore_changelog(replica_roots=args.REPLICA_ROOTS, log=log)
|
||||
|
||||
|
||||
+def compact_cl5(inst, basedn, log, args):
|
||||
+ replicas = Replicas(inst)
|
||||
+ replicas.compact_changelog(replica_roots=args.REPLICA_ROOTS, log=log)
|
||||
+
|
||||
+
|
||||
def create_parser(subparsers):
|
||||
|
||||
############################################
|
||||
@@ -1326,6 +1331,11 @@ def create_parser(subparsers):
|
||||
help="Specify one replica root whose changelog you want to restore. "
|
||||
"The replica root will be consumed from the LDIF file name if the option is omitted.")
|
||||
|
||||
+ compact_cl = repl_subcommands.add_parser('compact-changelog', help='Compact the changelog database')
|
||||
+ compact_cl.set_defaults(func=compact_cl5)
|
||||
+ compact_cl.add_argument('REPLICA_ROOTS', nargs="+",
|
||||
+ help="Specify replica roots whose changelog you want to compact.")
|
||||
+
|
||||
restore_changelogdir = restore_subcommands.add_parser('from-changelogdir', help='Restore LDIF files from changelogdir.')
|
||||
restore_changelogdir.set_defaults(func=restore_cl_dir)
|
||||
restore_changelogdir.add_argument('REPLICA_ROOTS', nargs="+",
|
||||
diff --git a/src/lib389/lib389/replica.py b/src/lib389/lib389/replica.py
|
||||
index 94e1fdad5..1f321972d 100644
|
||||
--- a/src/lib389/lib389/replica.py
|
||||
+++ b/src/lib389/lib389/replica.py
|
||||
@@ -1648,6 +1648,11 @@ class Replica(DSLdapObject):
|
||||
"""
|
||||
self.replace('nsds5task', 'ldif2cl')
|
||||
|
||||
+ def begin_task_compact_cl5(self):
|
||||
+ """Begin COMPACT_CL5 task
|
||||
+ """
|
||||
+ self.replace('nsds5task', 'COMPACT_CL5')
|
||||
+
|
||||
def get_suffix(self):
|
||||
"""Return the suffix
|
||||
"""
|
||||
@@ -1829,6 +1834,41 @@ class Replicas(DSLdapObjects):
|
||||
log.error(f"Changelog LDIF for '{repl_root}' was not found")
|
||||
continue
|
||||
|
||||
+ def compact_changelog(self, replica_roots=[], log=None):
|
||||
+ """Compact Directory Server replication changelog
|
||||
+
|
||||
+ :param replica_roots: Replica suffixes that need to be processed (and optional LDIF file path)
|
||||
+ :type replica_roots: list of str
|
||||
+ :param log: The logger object
|
||||
+ :type log: logger
|
||||
+ """
|
||||
+
|
||||
+ if log is None:
|
||||
+ log = self._log
|
||||
+
|
||||
+ # Check if the changelog entry exists
|
||||
+ try:
|
||||
+ cl = Changelog5(self._instance)
|
||||
+ cl.get_attr_val_utf8_l("nsslapd-changelogdir")
|
||||
+ except ldap.NO_SUCH_OBJECT:
|
||||
+ raise ValueError("Changelog entry was not found. Probably, the replication is not enabled on this instance")
|
||||
+
|
||||
+ # Get all the replicas on the server if --replica-roots option is not specified
|
||||
+ repl_roots = []
|
||||
+ if not replica_roots:
|
||||
+ for replica in self.list():
|
||||
+ repl_roots.append(replica.get_attr_val_utf8("nsDS5ReplicaRoot"))
|
||||
+ else:
|
||||
+ for repl_root in replica_roots:
|
||||
+ repl_roots.append(repl_root)
|
||||
+
|
||||
+ # Dump the changelog for the replica
|
||||
+
|
||||
+ # Dump the changelog for the replica
|
||||
+ for repl_root in repl_roots:
|
||||
+ replica = self.get(repl_root)
|
||||
+ replica.begin_task_compact_cl5()
|
||||
+
|
||||
|
||||
class BootstrapReplicationManager(DSLdapObject):
|
||||
"""A Replication Manager credential for bootstrapping the repl process.
|
||||
--
|
||||
2.47.0
|
||||
|
||||
@ -1,55 +0,0 @@
|
||||
From d1cd9a5675e2953b7c8034ebb87a434cdd3ce0c3 Mon Sep 17 00:00:00 2001
|
||||
From: tbordaz <tbordaz@redhat.com>
|
||||
Date: Mon, 2 Dec 2024 17:18:32 +0100
|
||||
Subject: [PATCH] Issue 6417 - If an entry RDN is identical to the suffix, then
|
||||
Entryrdn gets broken during a reindex (#6418)
|
||||
|
||||
Bug description:
|
||||
During a reindex, the entryrdn index is built at the end from
|
||||
each entry in the suffix.
|
||||
If one entry has a RDN that is identical to the suffix DN,
|
||||
then entryrdn_lookup_dn may erroneously return the suffix DN
|
||||
as the DN of the entry.
|
||||
|
||||
Fix description:
|
||||
When the lookup entry has no parent (because index is under
|
||||
work) the loop lookup the entry using the RDN.
|
||||
If this RDN matches the suffix DN, then it exits from the loop
|
||||
with the suffix DN.
|
||||
Before exiting it checks that the original lookup entryID
|
||||
is equal to suffix entryID. If it does not match
|
||||
the function fails and then the DN from the entry will be
|
||||
built from id2enty
|
||||
|
||||
fixes: #6417
|
||||
|
||||
Reviewed by: Pierre Rogier, Simon Pichugin (Thanks !!!)
|
||||
---
|
||||
ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c | 11 ++++++++++-
|
||||
1 file changed, 10 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
|
||||
index 5797dd779..83b041192 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
|
||||
@@ -1224,7 +1224,16 @@ entryrdn_lookup_dn(backend *be,
|
||||
}
|
||||
goto bail;
|
||||
}
|
||||
- maybesuffix = 1;
|
||||
+ if (workid == 1) {
|
||||
+ /* The loop (workid) iterates from the starting 'id'
|
||||
+ * up to the suffix ID (i.e. '1').
|
||||
+ * A corner case (#6417) is if an entry, on the path
|
||||
+ * 'id' -> suffix, has the same RDN than the suffix.
|
||||
+ * In order to erroneously believe the loop hits the suffix
|
||||
+ * we need to check that 'workid' is '1' (suffix)
|
||||
+ */
|
||||
+ maybesuffix = 1;
|
||||
+ }
|
||||
} else {
|
||||
_entryrdn_cursor_print_error("entryrdn_lookup_dn",
|
||||
key.data, data.size, data.ulen, rc);
|
||||
--
|
||||
2.48.0
|
||||
|
||||
@ -1,267 +0,0 @@
|
||||
From 9b2fc77a36156ea987dcea6e2043f8e4c4a6b259 Mon Sep 17 00:00:00 2001
|
||||
From: progier389 <progier@redhat.com>
|
||||
Date: Tue, 18 Jun 2024 14:21:07 +0200
|
||||
Subject: [PATCH] Issue 6224 - d2entry - Could not open id2entry err 0 - at
|
||||
startup when having sub-suffixes (#6225)
|
||||
|
||||
Problem:: d2entry - Could not open id2entry err 0 is logged at startup when having sub-suffixes
|
||||
Reason: The slapi_exist_referral internal search access a backend that is not yet started.
|
||||
Solution: Limit the internal search to a single backend
|
||||
|
||||
Issue: #6224
|
||||
|
||||
Reviewed by: @droideck Thanks!
|
||||
|
||||
(cherry picked from commit 796f703021e961fdd8cbc53b4ad4e20258af0e96)
|
||||
---
|
||||
.../tests/suites/ds_logs/ds_logs_test.py | 1 +
|
||||
.../suites/mapping_tree/regression_test.py | 161 +++++++++++++++++-
|
||||
ldap/servers/slapd/backend.c | 7 +-
|
||||
3 files changed, 159 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/ds_logs/ds_logs_test.py b/dirsrvtests/tests/suites/ds_logs/ds_logs_test.py
|
||||
index 812936c62..84a9c6ec8 100644
|
||||
--- a/dirsrvtests/tests/suites/ds_logs/ds_logs_test.py
|
||||
+++ b/dirsrvtests/tests/suites/ds_logs/ds_logs_test.py
|
||||
@@ -1222,6 +1222,7 @@ def test_referral_check(topology_st, request):
|
||||
|
||||
request.addfinalizer(fin)
|
||||
|
||||
+<<<<<<< HEAD
|
||||
def test_referral_subsuffix(topology_st, request):
|
||||
"""Test the results of an inverted parent suffix definition in the configuration.
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/mapping_tree/regression_test.py b/dirsrvtests/tests/suites/mapping_tree/regression_test.py
|
||||
index 99d4a1d5f..689ff9f59 100644
|
||||
--- a/dirsrvtests/tests/suites/mapping_tree/regression_test.py
|
||||
+++ b/dirsrvtests/tests/suites/mapping_tree/regression_test.py
|
||||
@@ -11,10 +11,14 @@ import ldap
|
||||
import logging
|
||||
import os
|
||||
import pytest
|
||||
+import time
|
||||
from lib389.backend import Backends, Backend
|
||||
+from lib389._constants import HOST_STANDALONE, PORT_STANDALONE, DN_DM, PW_DM
|
||||
from lib389.dbgen import dbgen_users
|
||||
from lib389.mappingTree import MappingTrees
|
||||
from lib389.topologies import topology_st
|
||||
+from lib389.referral import Referrals, Referral
|
||||
+
|
||||
|
||||
try:
|
||||
from lib389.backend import BackendSuffixView
|
||||
@@ -31,14 +35,26 @@ else:
|
||||
logging.getLogger(__name__).setLevel(logging.INFO)
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
+PARENT_SUFFIX = "dc=parent"
|
||||
+CHILD1_SUFFIX = f"dc=child1,{PARENT_SUFFIX}"
|
||||
+CHILD2_SUFFIX = f"dc=child2,{PARENT_SUFFIX}"
|
||||
+
|
||||
+PARENT_REFERRAL_DN = f"cn=ref,ou=People,{PARENT_SUFFIX}"
|
||||
+CHILD1_REFERRAL_DN = f"cn=ref,ou=people,{CHILD1_SUFFIX}"
|
||||
+CHILD2_REFERRAL_DN = f"cn=ref,ou=people,{CHILD2_SUFFIX}"
|
||||
+
|
||||
+REFERRAL_CHECK_PEDIOD = 7
|
||||
+
|
||||
+
|
||||
+
|
||||
BESTRUCT = [
|
||||
- { "bename" : "parent", "suffix": "dc=parent" },
|
||||
- { "bename" : "child1", "suffix": "dc=child1,dc=parent" },
|
||||
- { "bename" : "child2", "suffix": "dc=child2,dc=parent" },
|
||||
+ { "bename" : "parent", "suffix": PARENT_SUFFIX },
|
||||
+ { "bename" : "child1", "suffix": CHILD1_SUFFIX },
|
||||
+ { "bename" : "child2", "suffix": CHILD2_SUFFIX },
|
||||
]
|
||||
|
||||
|
||||
-@pytest.fixture(scope="function")
|
||||
+@pytest.fixture(scope="module")
|
||||
def topo(topology_st, request):
|
||||
bes = []
|
||||
|
||||
@@ -50,6 +66,9 @@ def topo(topology_st, request):
|
||||
request.addfinalizer(fin)
|
||||
|
||||
inst = topology_st.standalone
|
||||
+ # Reduce nsslapd-referral-check-period to accelerate test
|
||||
+ topology_st.standalone.config.set("nsslapd-referral-check-period", str(REFERRAL_CHECK_PEDIOD))
|
||||
+
|
||||
ldif_files = {}
|
||||
for d in BESTRUCT:
|
||||
bename = d['bename']
|
||||
@@ -76,14 +95,13 @@ def topo(topology_st, request):
|
||||
inst.start()
|
||||
return topology_st
|
||||
|
||||
-# Parameters for test_change_repl_passwd
|
||||
-EXPECTED_ENTRIES = (("dc=parent", 39), ("dc=child1,dc=parent", 13), ("dc=child2,dc=parent", 13))
|
||||
+# Parameters for test_sub_suffixes
|
||||
@pytest.mark.parametrize(
|
||||
"orphan_param",
|
||||
[
|
||||
- pytest.param( ( True, { "dc=parent": 2, "dc=child1,dc=parent":1, "dc=child2,dc=parent":1}), id="orphan-is-true" ),
|
||||
- pytest.param( ( False, { "dc=parent": 3, "dc=child1,dc=parent":1, "dc=child2,dc=parent":1}), id="orphan-is-false" ),
|
||||
- pytest.param( ( None, { "dc=parent": 3, "dc=child1,dc=parent":1, "dc=child2,dc=parent":1}), id="no-orphan" ),
|
||||
+ pytest.param( ( True, { PARENT_SUFFIX: 2, CHILD1_SUFFIX:1, CHILD2_SUFFIX:1}), id="orphan-is-true" ),
|
||||
+ pytest.param( ( False, { PARENT_SUFFIX: 3, CHILD1_SUFFIX:1, CHILD2_SUFFIX:1}), id="orphan-is-false" ),
|
||||
+ pytest.param( ( None, { PARENT_SUFFIX: 3, CHILD1_SUFFIX:1, CHILD2_SUFFIX:1}), id="no-orphan" ),
|
||||
],
|
||||
)
|
||||
|
||||
@@ -128,3 +146,128 @@ def test_sub_suffixes(topo, orphan_param):
|
||||
log.info('Test PASSED')
|
||||
|
||||
|
||||
+def test_one_level_search_on_sub_suffixes(topo):
|
||||
+ """ Perform one level scoped search accross suffix and sub-suffix
|
||||
+
|
||||
+ :id: 92f3139e-280e-11ef-a989-482ae39447e5
|
||||
+ :feature: mapping-tree
|
||||
+ :setup: Standalone instance with 3 additional backends:
|
||||
+ dc=parent, dc=child1,dc=parent, dc=childr21,dc=parent
|
||||
+ :steps:
|
||||
+ 1. Perform a ONE LEVEL search on dc=parent
|
||||
+ 2. Check that all expected entries have been returned
|
||||
+ 3. Check that only the expected entries have been returned
|
||||
+ :expectedresults:
|
||||
+ 1. Success
|
||||
+ 2. each expected dn should be in the result set
|
||||
+ 3. Number of returned entries should be the same as the number of expected entries
|
||||
+ """
|
||||
+ expected_dns = ( 'dc=child1,dc=parent',
|
||||
+ 'dc=child2,dc=parent',
|
||||
+ 'ou=accounting,dc=parent',
|
||||
+ 'ou=product development,dc=parent',
|
||||
+ 'ou=product testing,dc=parent',
|
||||
+ 'ou=human resources,dc=parent',
|
||||
+ 'ou=payroll,dc=parent',
|
||||
+ 'ou=people,dc=parent',
|
||||
+ 'ou=groups,dc=parent', )
|
||||
+ entries = topo.standalone.search_s("dc=parent", ldap.SCOPE_ONELEVEL, "(objectClass=*)",
|
||||
+ attrlist=("dc","ou"), escapehatch='i am sure')
|
||||
+ log.info(f'one level search on dc=parent returned the following entries: {entries}')
|
||||
+ dns = [ entry.dn for entry in entries ]
|
||||
+ for dn in expected_dns:
|
||||
+ assert dn in dns
|
||||
+ assert len(entries) == len(expected_dns)
|
||||
+
|
||||
+
|
||||
+def test_sub_suffixes_errlog(topo):
|
||||
+ """ check the entries found on suffix/sub-suffix
|
||||
+ used int
|
||||
+
|
||||
+ :id: 1db9d52e-28de-11ef-b286-482ae39447e5
|
||||
+ :feature: mapping-tree
|
||||
+ :setup: Standalone instance with 3 additional backends:
|
||||
+ dc=parent, dc=child1,dc=parent, dc=childr21,dc=parent
|
||||
+ :steps:
|
||||
+ 1. Check that id2entry error message is not in the error log.
|
||||
+ :expectedresults:
|
||||
+ 1. Success
|
||||
+ """
|
||||
+ inst = topo.standalone
|
||||
+ assert not inst.searchErrorsLog('id2entry - Could not open id2entry err 0')
|
||||
+
|
||||
+
|
||||
+# Parameters for test_referral_subsuffix:
|
||||
+# a tuple pair containing:
|
||||
+# - list of referral dn that must be created
|
||||
+# - dict of searches basedn: expected_number_of_referrals
|
||||
+@pytest.mark.parametrize(
|
||||
+ "parameters",
|
||||
+ [
|
||||
+ pytest.param( ((PARENT_REFERRAL_DN, CHILD1_REFERRAL_DN), {PARENT_SUFFIX: 2, CHILD1_SUFFIX:1, CHILD2_SUFFIX:0}), id="Both"),
|
||||
+ pytest.param( ((PARENT_REFERRAL_DN,), {PARENT_SUFFIX: 1, CHILD1_SUFFIX:0, CHILD2_SUFFIX:0}) , id="Parent"),
|
||||
+ pytest.param( ((CHILD1_REFERRAL_DN,), {PARENT_SUFFIX: 1, CHILD1_SUFFIX:1, CHILD2_SUFFIX:0}) , id="Child"),
|
||||
+ pytest.param( ((), {PARENT_SUFFIX: 0, CHILD1_SUFFIX:0, CHILD2_SUFFIX:0}), id="None"),
|
||||
+ ])
|
||||
+
|
||||
+def test_referral_subsuffix(topo, request, parameters):
|
||||
+ """Test the results of an inverted parent suffix definition in the configuration.
|
||||
+
|
||||
+ For more details see:
|
||||
+ https://www.port389.org/docs/389ds/design/mapping_tree_assembly.html
|
||||
+
|
||||
+ :id: 4e111a22-2a5d-11ef-a890-482ae39447e5
|
||||
+ :feature: referrals
|
||||
+ :setup: Standalone instance with 3 additional backends:
|
||||
+ dc=parent, dc=child1,dc=parent, dc=childr21,dc=parent
|
||||
+
|
||||
+ :setup: Standalone instance
|
||||
+ :parametrized: yes
|
||||
+ :steps:
|
||||
+ refs,searches = referrals
|
||||
+
|
||||
+ 1. Create the referrals according to the current parameter
|
||||
+ 2. Wait enough time so they get detected
|
||||
+ 3. For each search base dn, in the current parameter, perform the two following steps
|
||||
+ 4. In 3. loop: Perform a search with provided base dn
|
||||
+ 5. In 3. loop: Check that the number of returned referrals is the expected one.
|
||||
+
|
||||
+ :expectedresults:
|
||||
+ all steps succeeds
|
||||
+ """
|
||||
+ inst = topo.standalone
|
||||
+
|
||||
+ def fin():
|
||||
+ log.info('Deleting all referrals')
|
||||
+ for ref in Referrals(inst, PARENT_SUFFIX).list():
|
||||
+ ref.delete()
|
||||
+
|
||||
+ # Set cleanup callback
|
||||
+ if DEBUGGING:
|
||||
+ request.addfinalizer(fin)
|
||||
+
|
||||
+ # Remove all referrals
|
||||
+ fin()
|
||||
+ # Add requested referrals
|
||||
+ for dn in parameters[0]:
|
||||
+ refs = Referral(inst, dn=dn)
|
||||
+ refs.create(basedn=dn, properties={ 'cn': 'ref', 'ref': f'ldap://remote/{dn}'})
|
||||
+ # Wait that the internal search detects the referrals
|
||||
+ time.sleep(REFERRAL_CHECK_PEDIOD + 1)
|
||||
+ # Open a test connection
|
||||
+ ldc = ldap.initialize(f"ldap://{HOST_STANDALONE}:{PORT_STANDALONE}")
|
||||
+ ldc.set_option(ldap.OPT_REFERRALS,0)
|
||||
+ ldc.simple_bind_s(DN_DM,PW_DM)
|
||||
+
|
||||
+ # For each search base dn:
|
||||
+ for basedn,nbref in parameters[1].items():
|
||||
+ log.info(f"Referrals are: {parameters[0]}")
|
||||
+ # Perform a search with provided base dn
|
||||
+ result = ldc.search_s(basedn, ldap.SCOPE_SUBTREE, filterstr="(ou=People)")
|
||||
+ found_dns = [ dn for dn,entry in result if dn is not None ]
|
||||
+ found_refs = [ entry for dn,entry in result if dn is None ]
|
||||
+ log.info(f"Search on {basedn} returned {found_dns} and {found_refs}")
|
||||
+ # Check that the number of returned referrals is the expected one.
|
||||
+ log.info(f"Search returned {len(found_refs)} referrals. {nbref} are expected.")
|
||||
+ assert len(found_refs) == nbref
|
||||
+ ldc.unbind()
|
||||
diff --git a/ldap/servers/slapd/backend.c b/ldap/servers/slapd/backend.c
|
||||
index 498f683b1..f86b0b9b6 100644
|
||||
--- a/ldap/servers/slapd/backend.c
|
||||
+++ b/ldap/servers/slapd/backend.c
|
||||
@@ -230,12 +230,17 @@ slapi_exist_referral(Slapi_Backend *be)
|
||||
|
||||
/* search for ("smart") referral entries */
|
||||
search_pb = slapi_pblock_new();
|
||||
- server_ctrls = (LDAPControl **) slapi_ch_calloc(2, sizeof (LDAPControl *));
|
||||
+ server_ctrls = (LDAPControl **) slapi_ch_calloc(3, sizeof (LDAPControl *));
|
||||
server_ctrls[0] = (LDAPControl *) slapi_ch_malloc(sizeof (LDAPControl));
|
||||
server_ctrls[0]->ldctl_oid = slapi_ch_strdup(LDAP_CONTROL_MANAGEDSAIT);
|
||||
server_ctrls[0]->ldctl_value.bv_val = NULL;
|
||||
server_ctrls[0]->ldctl_value.bv_len = 0;
|
||||
server_ctrls[0]->ldctl_iscritical = '\0';
|
||||
+ server_ctrls[1] = (LDAPControl *) slapi_ch_malloc(sizeof (LDAPControl));
|
||||
+ server_ctrls[1]->ldctl_oid = slapi_ch_strdup(MTN_CONTROL_USE_ONE_BACKEND_EXT_OID);
|
||||
+ server_ctrls[1]->ldctl_value.bv_val = NULL;
|
||||
+ server_ctrls[1]->ldctl_value.bv_len = 0;
|
||||
+ server_ctrls[1]->ldctl_iscritical = '\0';
|
||||
slapi_search_internal_set_pb(search_pb, suffix, LDAP_SCOPE_SUBTREE,
|
||||
filter, NULL, 0, server_ctrls, NULL,
|
||||
(void *) plugin_get_default_component_id(), 0);
|
||||
--
|
||||
2.48.0
|
||||
|
||||
@ -1,32 +0,0 @@
|
||||
From ab06b3cebbe0287ef557c0307ca2ee86fe8cb761 Mon Sep 17 00:00:00 2001
|
||||
From: progier389 <progier@redhat.com>
|
||||
Date: Thu, 21 Nov 2024 16:26:02 +0100
|
||||
Subject: [PATCH] Issue 6224 - Fix merge issue in 389-ds-base-2.1 for
|
||||
ds_log_test.py (#6414)
|
||||
|
||||
Fix a merge issue during cherry-pick over 389-ds-base-2.1 and 389-ds-base-1.4.3 branches
|
||||
|
||||
Issue: #6224
|
||||
|
||||
Reviewed by: @mreynolds389
|
||||
|
||||
(cherry picked from commit 2b541c64b8317209e4dafa4f82918d714039907c)
|
||||
---
|
||||
dirsrvtests/tests/suites/ds_logs/ds_logs_test.py | 1 -
|
||||
1 file changed, 1 deletion(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/ds_logs/ds_logs_test.py b/dirsrvtests/tests/suites/ds_logs/ds_logs_test.py
|
||||
index 84a9c6ec8..812936c62 100644
|
||||
--- a/dirsrvtests/tests/suites/ds_logs/ds_logs_test.py
|
||||
+++ b/dirsrvtests/tests/suites/ds_logs/ds_logs_test.py
|
||||
@@ -1222,7 +1222,6 @@ def test_referral_check(topology_st, request):
|
||||
|
||||
request.addfinalizer(fin)
|
||||
|
||||
-<<<<<<< HEAD
|
||||
def test_referral_subsuffix(topology_st, request):
|
||||
"""Test the results of an inverted parent suffix definition in the configuration.
|
||||
|
||||
--
|
||||
2.48.0
|
||||
|
||||
@ -1,214 +0,0 @@
|
||||
From 3fe2cf7cdedcdf5cafb59867e52a1fbe4a643571 Mon Sep 17 00:00:00 2001
|
||||
From: Masahiro Matsuya <mmatsuya@redhat.com>
|
||||
Date: Fri, 20 Dec 2024 22:37:15 +0900
|
||||
Subject: [PATCH] Issue 6224 - Remove test_referral_subsuffix from
|
||||
ds_logs_test.py (#6456)
|
||||
|
||||
Bug Description:
|
||||
|
||||
test_referral_subsuffix test was removed from main branch and some other
|
||||
ones for higher versions. But, it was not removed from 389-ds-base-1.4.3
|
||||
and 389-ds-base-2.1. The test doesn't work anymore with the fix for
|
||||
Issue 6224, because the added new control limited one backend for internal
|
||||
search. The test should be removed.
|
||||
|
||||
Fix Description:
|
||||
|
||||
remove the test from ds_logs_test.py
|
||||
|
||||
relates: https://github.com/389ds/389-ds-base/issues/6224
|
||||
---
|
||||
.../tests/suites/ds_logs/ds_logs_test.py | 177 ------------------
|
||||
1 file changed, 177 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/ds_logs/ds_logs_test.py b/dirsrvtests/tests/suites/ds_logs/ds_logs_test.py
|
||||
index 812936c62..84d721756 100644
|
||||
--- a/dirsrvtests/tests/suites/ds_logs/ds_logs_test.py
|
||||
+++ b/dirsrvtests/tests/suites/ds_logs/ds_logs_test.py
|
||||
@@ -1222,183 +1222,6 @@ def test_referral_check(topology_st, request):
|
||||
|
||||
request.addfinalizer(fin)
|
||||
|
||||
-def test_referral_subsuffix(topology_st, request):
|
||||
- """Test the results of an inverted parent suffix definition in the configuration.
|
||||
-
|
||||
- For more details see:
|
||||
- https://www.port389.org/docs/389ds/design/mapping_tree_assembly.html
|
||||
-
|
||||
- :id: 4faf210a-4fde-4e4f-8834-865bdc8f4d37
|
||||
- :setup: Standalone instance
|
||||
- :steps:
|
||||
- 1. First create two Backends, without mapping trees.
|
||||
- 2. create the mapping trees for these backends
|
||||
- 3. reduce nsslapd-referral-check-period to accelerate test
|
||||
- 4. Remove error log file
|
||||
- 5. Create a referral entry on parent suffix
|
||||
- 6. Check that the server detected the referral
|
||||
- 7. Delete the referral entry
|
||||
- 8. Check that the server detected the deletion of the referral
|
||||
- 9. Remove error log file
|
||||
- 10. Create a referral entry on child suffix
|
||||
- 11. Check that the server detected the referral on both parent and child suffixes
|
||||
- 12. Delete the referral entry
|
||||
- 13. Check that the server detected the deletion of the referral on both parent and child suffixes
|
||||
- 14. Remove error log file
|
||||
- 15. Create a referral entry on parent suffix
|
||||
- 16. Check that the server detected the referral on both parent and child suffixes
|
||||
- 17. Delete the child referral entry
|
||||
- 18. Check that the server detected the deletion of the referral on child suffix but not on parent suffix
|
||||
- 19. Delete the parent referral entry
|
||||
- 20. Check that the server detected the deletion of the referral parent suffix
|
||||
-
|
||||
- :expectedresults:
|
||||
- all steps succeeds
|
||||
- """
|
||||
- inst = topology_st.standalone
|
||||
- # Step 1 First create two Backends, without mapping trees.
|
||||
- PARENT_SUFFIX='dc=parent,dc=com'
|
||||
- CHILD_SUFFIX='dc=child,%s' % PARENT_SUFFIX
|
||||
- be1 = create_backend(inst, 'Parent', PARENT_SUFFIX)
|
||||
- be2 = create_backend(inst, 'Child', CHILD_SUFFIX)
|
||||
- # Step 2 create the mapping trees for these backends
|
||||
- mts = MappingTrees(inst)
|
||||
- mt1 = mts.create(properties={
|
||||
- 'cn': PARENT_SUFFIX,
|
||||
- 'nsslapd-state': 'backend',
|
||||
- 'nsslapd-backend': 'Parent',
|
||||
- })
|
||||
- mt2 = mts.create(properties={
|
||||
- 'cn': CHILD_SUFFIX,
|
||||
- 'nsslapd-state': 'backend',
|
||||
- 'nsslapd-backend': 'Child',
|
||||
- 'nsslapd-parent-suffix': PARENT_SUFFIX,
|
||||
- })
|
||||
-
|
||||
- dc_ex = Domain(inst, dn=PARENT_SUFFIX)
|
||||
- assert dc_ex.exists()
|
||||
-
|
||||
- dc_st = Domain(inst, dn=CHILD_SUFFIX)
|
||||
- assert dc_st.exists()
|
||||
-
|
||||
- # Step 3 reduce nsslapd-referral-check-period to accelerate test
|
||||
- # requires a restart done on step 4
|
||||
- REFERRAL_CHECK=7
|
||||
- topology_st.standalone.config.set("nsslapd-referral-check-period", str(REFERRAL_CHECK))
|
||||
-
|
||||
- # Check that if we create a referral at parent level
|
||||
- # - referral is detected at parent backend
|
||||
- # - referral is not detected at child backend
|
||||
-
|
||||
- # Step 3 Remove error log file
|
||||
- topology_st.standalone.stop()
|
||||
- lpath = topology_st.standalone.ds_error_log._get_log_path()
|
||||
- os.unlink(lpath)
|
||||
- topology_st.standalone.start()
|
||||
-
|
||||
- # Step 4 Create a referral entry on parent suffix
|
||||
- rs_parent = Referrals(topology_st.standalone, PARENT_SUFFIX)
|
||||
-
|
||||
- referral_entry_parent = rs_parent.create(properties={
|
||||
- 'cn': 'testref',
|
||||
- 'ref': 'ldap://localhost:38901/ou=People,dc=example,dc=com'
|
||||
- })
|
||||
-
|
||||
- # Step 5 Check that the server detected the referral
|
||||
- time.sleep(REFERRAL_CHECK + 1)
|
||||
- assert topology_st.standalone.ds_error_log.match('.*slapd_daemon - New referral entries are detected under %s.*' % PARENT_SUFFIX)
|
||||
- assert not topology_st.standalone.ds_error_log.match('.*slapd_daemon - New referral entries are detected under %s.*' % CHILD_SUFFIX)
|
||||
- assert not topology_st.standalone.ds_error_log.match('.*slapd_daemon - No more referral entry under %s' % PARENT_SUFFIX)
|
||||
-
|
||||
- # Step 6 Delete the referral entry
|
||||
- referral_entry_parent.delete()
|
||||
-
|
||||
- # Step 7 Check that the server detected the deletion of the referral
|
||||
- time.sleep(REFERRAL_CHECK + 1)
|
||||
- assert topology_st.standalone.ds_error_log.match('.*slapd_daemon - No more referral entry under %s' % PARENT_SUFFIX)
|
||||
-
|
||||
- # Check that if we create a referral at child level
|
||||
- # - referral is detected at parent backend
|
||||
- # - referral is detected at child backend
|
||||
-
|
||||
- # Step 8 Remove error log file
|
||||
- topology_st.standalone.stop()
|
||||
- lpath = topology_st.standalone.ds_error_log._get_log_path()
|
||||
- os.unlink(lpath)
|
||||
- topology_st.standalone.start()
|
||||
-
|
||||
- # Step 9 Create a referral entry on child suffix
|
||||
- rs_child = Referrals(topology_st.standalone, CHILD_SUFFIX)
|
||||
- referral_entry_child = rs_child.create(properties={
|
||||
- 'cn': 'testref',
|
||||
- 'ref': 'ldap://localhost:38901/ou=People,dc=example,dc=com'
|
||||
- })
|
||||
-
|
||||
- # Step 10 Check that the server detected the referral on both parent and child suffixes
|
||||
- time.sleep(REFERRAL_CHECK + 1)
|
||||
- assert topology_st.standalone.ds_error_log.match('.*slapd_daemon - New referral entries are detected under %s.*' % PARENT_SUFFIX)
|
||||
- assert topology_st.standalone.ds_error_log.match('.*slapd_daemon - New referral entries are detected under %s.*' % CHILD_SUFFIX)
|
||||
- assert not topology_st.standalone.ds_error_log.match('.*slapd_daemon - No more referral entry under %s' % CHILD_SUFFIX)
|
||||
-
|
||||
- # Step 11 Delete the referral entry
|
||||
- referral_entry_child.delete()
|
||||
-
|
||||
- # Step 12 Check that the server detected the deletion of the referral on both parent and child suffixes
|
||||
- time.sleep(REFERRAL_CHECK + 1)
|
||||
- assert topology_st.standalone.ds_error_log.match('.*slapd_daemon - No more referral entry under %s' % PARENT_SUFFIX)
|
||||
- assert topology_st.standalone.ds_error_log.match('.*slapd_daemon - No more referral entry under %s' % CHILD_SUFFIX)
|
||||
-
|
||||
- # Check that if we create a referral at child level and parent level
|
||||
- # - referral is detected at parent backend
|
||||
- # - referral is detected at child backend
|
||||
-
|
||||
- # Step 13 Remove error log file
|
||||
- topology_st.standalone.stop()
|
||||
- lpath = topology_st.standalone.ds_error_log._get_log_path()
|
||||
- os.unlink(lpath)
|
||||
- topology_st.standalone.start()
|
||||
-
|
||||
- # Step 14 Create a referral entry on parent suffix
|
||||
- # Create a referral entry on child suffix
|
||||
- referral_entry_parent = rs_parent.create(properties={
|
||||
- 'cn': 'testref',
|
||||
- 'ref': 'ldap://localhost:38901/ou=People,dc=example,dc=com'
|
||||
- })
|
||||
- referral_entry_child = rs_child.create(properties={
|
||||
- 'cn': 'testref',
|
||||
- 'ref': 'ldap://localhost:38901/ou=People,dc=example,dc=com'
|
||||
- })
|
||||
-
|
||||
- # Step 15 Check that the server detected the referral on both parent and child suffixes
|
||||
- time.sleep(REFERRAL_CHECK + 1)
|
||||
- assert topology_st.standalone.ds_error_log.match('.*slapd_daemon - New referral entries are detected under %s.*' % PARENT_SUFFIX)
|
||||
- assert topology_st.standalone.ds_error_log.match('.*slapd_daemon - New referral entries are detected under %s.*' % CHILD_SUFFIX)
|
||||
- assert not topology_st.standalone.ds_error_log.match('.*slapd_daemon - No more referral entry under %s' % CHILD_SUFFIX)
|
||||
-
|
||||
- # Step 16 Delete the child referral entry
|
||||
- referral_entry_child.delete()
|
||||
-
|
||||
- # Step 17 Check that the server detected the deletion of the referral on child suffix but not on parent suffix
|
||||
- time.sleep(REFERRAL_CHECK + 1)
|
||||
- assert topology_st.standalone.ds_error_log.match('.*slapd_daemon - No more referral entry under %s' % CHILD_SUFFIX)
|
||||
- assert not topology_st.standalone.ds_error_log.match('.*slapd_daemon - No more referral entry under %s' % PARENT_SUFFIX)
|
||||
-
|
||||
- # Step 18 Delete the parent referral entry
|
||||
- referral_entry_parent.delete()
|
||||
-
|
||||
- # Step 19 Check that the server detected the deletion of the referral parent suffix
|
||||
- time.sleep(REFERRAL_CHECK + 1)
|
||||
- assert topology_st.standalone.ds_error_log.match('.*slapd_daemon - No more referral entry under %s' % PARENT_SUFFIX)
|
||||
-
|
||||
- def fin():
|
||||
- log.info('Deleting referral')
|
||||
- try:
|
||||
- referral_entry_parent.delete()
|
||||
- referral.entry_child.delete()
|
||||
- except:
|
||||
- pass
|
||||
-
|
||||
- request.addfinalizer(fin)
|
||||
|
||||
def test_missing_backend_suffix(topology_st, request):
|
||||
"""Test that the server does not crash if a backend has no suffix
|
||||
--
|
||||
2.48.0
|
||||
|
||||
@ -1,90 +0,0 @@
|
||||
From 4121ffe7a44fbacf513758661e71e483eb11ee3c Mon Sep 17 00:00:00 2001
|
||||
From: tbordaz <tbordaz@redhat.com>
|
||||
Date: Mon, 6 Jan 2025 14:00:39 +0100
|
||||
Subject: [PATCH] Issue 6417 - (2nd) If an entry RDN is identical to the
|
||||
suffix, then Entryrdn gets broken during a reindex (#6460)
|
||||
|
||||
Bug description:
|
||||
The primary fix has a flaw as it assumes that the
|
||||
suffix ID is '1'.
|
||||
If the RUV entry is the first entry of the database
|
||||
the server loops indefinitely
|
||||
|
||||
Fix description:
|
||||
Read the suffix ID from the entryrdn index
|
||||
|
||||
fixes: #6417
|
||||
|
||||
Reviewed by: Pierre Rogier (also reviewed the first fix)
|
||||
---
|
||||
.../suites/replication/regression_m2_test.py | 9 +++++++++
|
||||
ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c | 19 ++++++++++++++++++-
|
||||
2 files changed, 27 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/replication/regression_m2_test.py b/dirsrvtests/tests/suites/replication/regression_m2_test.py
|
||||
index abac46ada..72d4b9f89 100644
|
||||
--- a/dirsrvtests/tests/suites/replication/regression_m2_test.py
|
||||
+++ b/dirsrvtests/tests/suites/replication/regression_m2_test.py
|
||||
@@ -1010,6 +1010,15 @@ def test_online_reinit_may_hang(topo_with_sigkill):
|
||||
"""
|
||||
M1 = topo_with_sigkill.ms["supplier1"]
|
||||
M2 = topo_with_sigkill.ms["supplier2"]
|
||||
+
|
||||
+ # The RFE 5367 (when enabled) retrieves the DN
|
||||
+ # from the dncache. This hides an issue
|
||||
+ # with primary fix for 6417.
|
||||
+ # We need to disable the RFE to verify that the primary
|
||||
+ # fix is properly fixed.
|
||||
+ if ds_is_newer('2.3.1'):
|
||||
+ M1.config.replace('nsslapd-return-original-entrydn', 'off')
|
||||
+
|
||||
M1.stop()
|
||||
ldif_file = '%s/supplier1.ldif' % M1.get_ldif_dir()
|
||||
M1.db2ldif(bename=DEFAULT_BENAME, suffixes=[DEFAULT_SUFFIX],
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
|
||||
index 83b041192..1bbb6252a 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
|
||||
@@ -1115,6 +1115,7 @@ entryrdn_lookup_dn(backend *be,
|
||||
rdn_elem *elem = NULL;
|
||||
int maybesuffix = 0;
|
||||
int db_retry = 0;
|
||||
+ ID suffix_id = 1;
|
||||
|
||||
slapi_log_err(SLAPI_LOG_TRACE, "entryrdn_lookup_dn",
|
||||
"--> entryrdn_lookup_dn\n");
|
||||
@@ -1175,6 +1176,22 @@ entryrdn_lookup_dn(backend *be,
|
||||
/* Setting the bulk fetch buffer */
|
||||
data.flags = DB_DBT_MALLOC;
|
||||
|
||||
+ /* Just in case the suffix ID is not '1' retrieve it from the database */
|
||||
+ keybuf = slapi_ch_strdup(slapi_sdn_get_ndn(be->be_suffix));
|
||||
+ dblayer_value_set(be, &key, keybuf, strlen(keybuf) + 1);
|
||||
+ rc = dblayer_cursor_op(&ctx.cursor, DBI_OP_MOVE_TO_KEY, &key, &data);
|
||||
+ if (rc) {
|
||||
+ slapi_log_err(SLAPI_LOG_WARNING, "entryrdn_lookup_dn",
|
||||
+ "Fails to retrieve the ID of suffix %s - keep the default value '%d'\n",
|
||||
+ slapi_sdn_get_ndn(be->be_suffix),
|
||||
+ suffix_id);
|
||||
+ } else {
|
||||
+ elem = (rdn_elem *)data.data;
|
||||
+ suffix_id = id_stored_to_internal(elem->rdn_elem_id);
|
||||
+ }
|
||||
+ dblayer_value_free(be, &data);
|
||||
+ dblayer_value_free(be, &key);
|
||||
+
|
||||
do {
|
||||
/* Setting up a key for the node to get its parent */
|
||||
slapi_ch_free_string(&keybuf);
|
||||
@@ -1224,7 +1241,7 @@ entryrdn_lookup_dn(backend *be,
|
||||
}
|
||||
goto bail;
|
||||
}
|
||||
- if (workid == 1) {
|
||||
+ if (workid == suffix_id) {
|
||||
/* The loop (workid) iterates from the starting 'id'
|
||||
* up to the suffix ID (i.e. '1').
|
||||
* A corner case (#6417) is if an entry, on the path
|
||||
--
|
||||
2.48.0
|
||||
|
||||
@ -1,40 +0,0 @@
|
||||
From 1ffcc9aa9a397180fe35283ee61b164471d073fb Mon Sep 17 00:00:00 2001
|
||||
From: Thierry Bordaz <tbordaz@redhat.com>
|
||||
Date: Tue, 7 Jan 2025 10:01:51 +0100
|
||||
Subject: [PATCH] Issue 6417 - (2nd) fix typo
|
||||
|
||||
---
|
||||
ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c | 10 ++++++----
|
||||
1 file changed, 6 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
|
||||
index 1bbb6252a..e2b8273a2 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
|
||||
@@ -1178,8 +1178,10 @@ entryrdn_lookup_dn(backend *be,
|
||||
|
||||
/* Just in case the suffix ID is not '1' retrieve it from the database */
|
||||
keybuf = slapi_ch_strdup(slapi_sdn_get_ndn(be->be_suffix));
|
||||
- dblayer_value_set(be, &key, keybuf, strlen(keybuf) + 1);
|
||||
- rc = dblayer_cursor_op(&ctx.cursor, DBI_OP_MOVE_TO_KEY, &key, &data);
|
||||
+ key.data = keybuf;
|
||||
+ key.size = key.ulen = strlen(keybuf) + 1;
|
||||
+ key.flags = DB_DBT_USERMEM;
|
||||
+ rc = cursor->c_get(cursor, &key, &data, DB_SET);
|
||||
if (rc) {
|
||||
slapi_log_err(SLAPI_LOG_WARNING, "entryrdn_lookup_dn",
|
||||
"Fails to retrieve the ID of suffix %s - keep the default value '%d'\n",
|
||||
@@ -1189,8 +1191,8 @@ entryrdn_lookup_dn(backend *be,
|
||||
elem = (rdn_elem *)data.data;
|
||||
suffix_id = id_stored_to_internal(elem->rdn_elem_id);
|
||||
}
|
||||
- dblayer_value_free(be, &data);
|
||||
- dblayer_value_free(be, &key);
|
||||
+ slapi_ch_free(&data.data);
|
||||
+ slapi_ch_free_string(&keybuf);
|
||||
|
||||
do {
|
||||
/* Setting up a key for the node to get its parent */
|
||||
--
|
||||
2.48.0
|
||||
|
||||
@ -1,75 +0,0 @@
|
||||
From 9e1284122a929fe14633a2aa6e2de4d72891f98f Mon Sep 17 00:00:00 2001
|
||||
From: Thierry Bordaz <tbordaz@redhat.com>
|
||||
Date: Mon, 13 Jan 2025 17:41:18 +0100
|
||||
Subject: [PATCH] Issue 6417 - (3rd) If an entry RDN is identical to the
|
||||
suffix, then Entryrdn gets broken during a reindex (#6480)
|
||||
|
||||
Bug description:
|
||||
The previous fix had a flaw.
|
||||
In case entryrdn_lookup_dn is called with an undefined suffix
|
||||
the lookup of the suffix trigger a crash.
|
||||
For example it can occur during internal search of an
|
||||
unexisting map (view plugin).
|
||||
The issue exists in all releases but is hidden since 2.3.
|
||||
|
||||
Fix description:
|
||||
testing the suffix is defined
|
||||
|
||||
fixes: #6417
|
||||
|
||||
Reviewed by: Pierre Rogier (THnaks !)
|
||||
---
|
||||
ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c | 36 +++++++++++---------
|
||||
1 file changed, 20 insertions(+), 16 deletions(-)
|
||||
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
|
||||
index e2b8273a2..01c77156f 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/ldbm_entryrdn.c
|
||||
@@ -1176,23 +1176,27 @@ entryrdn_lookup_dn(backend *be,
|
||||
/* Setting the bulk fetch buffer */
|
||||
data.flags = DB_DBT_MALLOC;
|
||||
|
||||
- /* Just in case the suffix ID is not '1' retrieve it from the database */
|
||||
- keybuf = slapi_ch_strdup(slapi_sdn_get_ndn(be->be_suffix));
|
||||
- key.data = keybuf;
|
||||
- key.size = key.ulen = strlen(keybuf) + 1;
|
||||
- key.flags = DB_DBT_USERMEM;
|
||||
- rc = cursor->c_get(cursor, &key, &data, DB_SET);
|
||||
- if (rc) {
|
||||
- slapi_log_err(SLAPI_LOG_WARNING, "entryrdn_lookup_dn",
|
||||
- "Fails to retrieve the ID of suffix %s - keep the default value '%d'\n",
|
||||
- slapi_sdn_get_ndn(be->be_suffix),
|
||||
- suffix_id);
|
||||
- } else {
|
||||
- elem = (rdn_elem *)data.data;
|
||||
- suffix_id = id_stored_to_internal(elem->rdn_elem_id);
|
||||
+ /* Just in case the suffix ID is not '1' retrieve it from the database
|
||||
+ * if the suffix is not defined suffix_id remains '1'
|
||||
+ */
|
||||
+ if (be->be_suffix) {
|
||||
+ keybuf = slapi_ch_strdup(slapi_sdn_get_ndn(be->be_suffix));
|
||||
+ key.data = keybuf;
|
||||
+ key.size = key.ulen = strlen(keybuf) + 1;
|
||||
+ key.flags = DB_DBT_USERMEM;
|
||||
+ rc = cursor->c_get(cursor, &key, &data, DB_SET);
|
||||
+ if (rc) {
|
||||
+ slapi_log_err(SLAPI_LOG_WARNING, "entryrdn_lookup_dn",
|
||||
+ "Fails to retrieve the ID of suffix %s - keep the default value '%d'\n",
|
||||
+ slapi_sdn_get_ndn(be->be_suffix),
|
||||
+ suffix_id);
|
||||
+ } else {
|
||||
+ elem = (rdn_elem *) data.data;
|
||||
+ suffix_id = id_stored_to_internal(elem->rdn_elem_id);
|
||||
+ }
|
||||
+ slapi_ch_free(&data.data);
|
||||
+ slapi_ch_free_string(&keybuf);
|
||||
}
|
||||
- slapi_ch_free(&data.data);
|
||||
- slapi_ch_free_string(&keybuf);
|
||||
|
||||
do {
|
||||
/* Setting up a key for the node to get its parent */
|
||||
--
|
||||
2.48.0
|
||||
|
||||
@ -1,297 +0,0 @@
|
||||
From d2f9dd82e3610ee9b73feea981c680c03bb21394 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
Date: Thu, 16 Jan 2025 08:42:53 -0500
|
||||
Subject: [PATCH] Issue 6509 - Race condition with Paged Result searches
|
||||
|
||||
Description:
|
||||
|
||||
There is a race condition with Paged Result searches when a new operation comes
|
||||
in while a paged search is finishing. This triggers an invalid time out error
|
||||
and closes the connection with a T3 code.
|
||||
|
||||
The problem is that we do not use the "PagedResult lock" when checking the
|
||||
connection's paged result data for a timeout event. This causes the paged
|
||||
result timeout value to change unexpectedly and trigger a false timeout when a
|
||||
new operation arrives.
|
||||
|
||||
Now we check the timeout without hte conn lock, if its expired it could
|
||||
be a race condition and false positive. Try the lock again and test the
|
||||
timeout. This also prevents blocking non-paged result searches from
|
||||
getting held up by the lock when it's not necessary.
|
||||
|
||||
This also fixes some memory leaks that occur when an error happens.
|
||||
|
||||
Relates: https://github.com/389ds/389-ds-base/issues/6509
|
||||
|
||||
Reviewed by: tbordaz & proger (Thanks!!)
|
||||
---
|
||||
ldap/servers/slapd/daemon.c | 61 ++++++++++++++++++-------------
|
||||
ldap/servers/slapd/opshared.c | 58 ++++++++++++++---------------
|
||||
ldap/servers/slapd/pagedresults.c | 9 +++++
|
||||
ldap/servers/slapd/slap.h | 2 +-
|
||||
4 files changed, 75 insertions(+), 55 deletions(-)
|
||||
|
||||
diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
|
||||
index bb80dae36..13dfe250d 100644
|
||||
--- a/ldap/servers/slapd/daemon.c
|
||||
+++ b/ldap/servers/slapd/daemon.c
|
||||
@@ -1578,7 +1578,29 @@ setup_pr_read_pds(Connection_Table *ct)
|
||||
if (c->c_state == CONN_STATE_FREE) {
|
||||
connection_table_move_connection_out_of_active_list(ct, c);
|
||||
} else {
|
||||
- /* we try to acquire the connection mutex, if it is already
|
||||
+ /* Check for a timeout for PAGED RESULTS */
|
||||
+ if (pagedresults_is_timedout_nolock(c)) {
|
||||
+ /*
|
||||
+ * There could be a race condition so lets try again with the
|
||||
+ * right lock
|
||||
+ */
|
||||
+ pthread_mutex_t *pr_mutex = pageresult_lock_get_addr(c);
|
||||
+ if (pthread_mutex_trylock(pr_mutex) == EBUSY) {
|
||||
+ c = next;
|
||||
+ continue;
|
||||
+ }
|
||||
+ if (pagedresults_is_timedout_nolock(c)) {
|
||||
+ pthread_mutex_unlock(pr_mutex);
|
||||
+ disconnect_server(c, c->c_connid, -1,
|
||||
+ SLAPD_DISCONNECT_PAGED_SEARCH_LIMIT,
|
||||
+ 0);
|
||||
+ } else {
|
||||
+ pthread_mutex_unlock(pr_mutex);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * we try to acquire the connection mutex, if it is already
|
||||
* acquired by another thread, don't wait
|
||||
*/
|
||||
if (pthread_mutex_trylock(&(c->c_mutex)) == EBUSY) {
|
||||
@@ -1586,35 +1608,24 @@ setup_pr_read_pds(Connection_Table *ct)
|
||||
continue;
|
||||
}
|
||||
if (c->c_flags & CONN_FLAG_CLOSING) {
|
||||
- /* A worker thread has marked that this connection
|
||||
- * should be closed by calling disconnect_server.
|
||||
- * move this connection out of the active list
|
||||
- * the last thread to use the connection will close it
|
||||
+ /*
|
||||
+ * A worker thread, or paged result timeout, has marked that
|
||||
+ * this connection should be closed by calling
|
||||
+ * disconnect_server(). Move this connection out of the active
|
||||
+ * list then the last thread to use the connection will close
|
||||
+ * it.
|
||||
*/
|
||||
connection_table_move_connection_out_of_active_list(ct, c);
|
||||
} else if (c->c_sd == SLAPD_INVALID_SOCKET) {
|
||||
connection_table_move_connection_out_of_active_list(ct, c);
|
||||
} else if (c->c_prfd != NULL) {
|
||||
if ((!c->c_gettingber) && (c->c_threadnumber < c->c_max_threads_per_conn)) {
|
||||
- int add_fd = 1;
|
||||
- /* check timeout for PAGED RESULTS */
|
||||
- if (pagedresults_is_timedout_nolock(c)) {
|
||||
- /* Exceeded the paged search timelimit; disconnect the client */
|
||||
- disconnect_server_nomutex(c, c->c_connid, -1,
|
||||
- SLAPD_DISCONNECT_PAGED_SEARCH_LIMIT,
|
||||
- 0);
|
||||
- connection_table_move_connection_out_of_active_list(ct,
|
||||
- c);
|
||||
- add_fd = 0; /* do not poll on this fd */
|
||||
- }
|
||||
- if (add_fd) {
|
||||
- ct->fd[count].fd = c->c_prfd;
|
||||
- ct->fd[count].in_flags = SLAPD_POLL_FLAGS;
|
||||
- /* slot i of the connection table is mapped to slot
|
||||
- * count of the fds array */
|
||||
- c->c_fdi = count;
|
||||
- count++;
|
||||
- }
|
||||
+ ct->fd[listnum][count].fd = c->c_prfd;
|
||||
+ ct->fd[listnum][count].in_flags = SLAPD_POLL_FLAGS;
|
||||
+ /* slot i of the connection table is mapped to slot
|
||||
+ * count of the fds array */
|
||||
+ c->c_fdi = count;
|
||||
+ count++;
|
||||
} else {
|
||||
if (c->c_threadnumber >= c->c_max_threads_per_conn) {
|
||||
c->c_maxthreadsblocked++;
|
||||
@@ -1675,7 +1686,7 @@ handle_pr_read_ready(Connection_Table *ct, PRIntn num_poll __attribute__((unused
|
||||
continue;
|
||||
}
|
||||
|
||||
- /* Try to get connection mutex, if not available just skip the connection and
|
||||
+ /* Try to get connection mutex, if not available just skip the connection and
|
||||
* process other connections events. May generates cpu load for listening thread
|
||||
* if connection mutex is held for a long time
|
||||
*/
|
||||
diff --git a/ldap/servers/slapd/opshared.c b/ldap/servers/slapd/opshared.c
|
||||
index 7ab4117cd..a29eed052 100644
|
||||
--- a/ldap/servers/slapd/opshared.c
|
||||
+++ b/ldap/servers/slapd/opshared.c
|
||||
@@ -250,7 +250,7 @@ op_shared_search(Slapi_PBlock *pb, int send_result)
|
||||
char *errtext = NULL;
|
||||
int nentries, pnentries;
|
||||
int flag_search_base_found = 0;
|
||||
- int flag_no_such_object = 0;
|
||||
+ bool flag_no_such_object = false;
|
||||
int flag_referral = 0;
|
||||
int flag_psearch = 0;
|
||||
int err_code = LDAP_SUCCESS;
|
||||
@@ -315,7 +315,7 @@ op_shared_search(Slapi_PBlock *pb, int send_result)
|
||||
rc = -1;
|
||||
goto free_and_return_nolock;
|
||||
}
|
||||
-
|
||||
+
|
||||
/* Set the time we actually started the operation */
|
||||
slapi_operation_set_time_started(operation);
|
||||
|
||||
@@ -798,11 +798,11 @@ op_shared_search(Slapi_PBlock *pb, int send_result)
|
||||
}
|
||||
|
||||
/* subtree searches :
|
||||
- * if the search was started above the backend suffix
|
||||
- * - temporarily set the SLAPI_SEARCH_TARGET_SDN to the
|
||||
- * base of the node so that we don't get a NO SUCH OBJECT error
|
||||
- * - do not change the scope
|
||||
- */
|
||||
+ * if the search was started above the backend suffix
|
||||
+ * - temporarily set the SLAPI_SEARCH_TARGET_SDN to the
|
||||
+ * base of the node so that we don't get a NO SUCH OBJECT error
|
||||
+ * - do not change the scope
|
||||
+ */
|
||||
if (scope == LDAP_SCOPE_SUBTREE) {
|
||||
if (slapi_sdn_issuffix(be_suffix, basesdn)) {
|
||||
if (free_sdn) {
|
||||
@@ -825,53 +825,53 @@ op_shared_search(Slapi_PBlock *pb, int send_result)
|
||||
switch (rc) {
|
||||
case 1:
|
||||
/* if the backend returned LDAP_NO_SUCH_OBJECT for a SEARCH request,
|
||||
- * it will not have sent back a result - otherwise, it will have
|
||||
- * sent a result */
|
||||
+ * it will not have sent back a result - otherwise, it will have
|
||||
+ * sent a result */
|
||||
rc = SLAPI_FAIL_GENERAL;
|
||||
slapi_pblock_get(pb, SLAPI_RESULT_CODE, &err);
|
||||
if (err == LDAP_NO_SUCH_OBJECT) {
|
||||
/* may be the object exist somewhere else
|
||||
- * wait the end of the loop to send back this error
|
||||
- */
|
||||
- flag_no_such_object = 1;
|
||||
+ * wait the end of the loop to send back this error
|
||||
+ */
|
||||
+ flag_no_such_object = true;
|
||||
} else {
|
||||
/* err something other than LDAP_NO_SUCH_OBJECT, so the backend will
|
||||
- * have sent the result -
|
||||
- * Set a flag here so we don't return another result. */
|
||||
+ * have sent the result -
|
||||
+ * Set a flag here so we don't return another result. */
|
||||
sent_result = 1;
|
||||
}
|
||||
- /* fall through */
|
||||
+ /* fall through */
|
||||
|
||||
case -1: /* an error occurred */
|
||||
+ slapi_pblock_get(pb, SLAPI_RESULT_CODE, &err);
|
||||
/* PAGED RESULTS */
|
||||
if (op_is_pagedresults(operation)) {
|
||||
/* cleanup the slot */
|
||||
pthread_mutex_lock(pagedresults_mutex);
|
||||
+ if (err != LDAP_NO_SUCH_OBJECT && !flag_no_such_object) {
|
||||
+ /* Free the results if not "no_such_object" */
|
||||
+ void *sr = NULL;
|
||||
+ slapi_pblock_get(pb, SLAPI_SEARCH_RESULT_SET, &sr);
|
||||
+ be->be_search_results_release(&sr);
|
||||
+ }
|
||||
pagedresults_set_search_result(pb_conn, operation, NULL, 1, pr_idx);
|
||||
rc = pagedresults_set_current_be(pb_conn, NULL, pr_idx, 1);
|
||||
pthread_mutex_unlock(pagedresults_mutex);
|
||||
}
|
||||
- if (1 == flag_no_such_object) {
|
||||
- break;
|
||||
- }
|
||||
- slapi_pblock_get(pb, SLAPI_RESULT_CODE, &err);
|
||||
- if (err == LDAP_NO_SUCH_OBJECT) {
|
||||
- /* may be the object exist somewhere else
|
||||
- * wait the end of the loop to send back this error
|
||||
- */
|
||||
- flag_no_such_object = 1;
|
||||
+
|
||||
+ if (err == LDAP_NO_SUCH_OBJECT || flag_no_such_object) {
|
||||
+ /* Maybe the object exists somewhere else, wait to the end
|
||||
+ * of the loop to send back this error */
|
||||
+ flag_no_such_object = true;
|
||||
break;
|
||||
} else {
|
||||
- /* for error other than LDAP_NO_SUCH_OBJECT
|
||||
- * the error has already been sent
|
||||
- * stop the search here
|
||||
- */
|
||||
+ /* For error other than LDAP_NO_SUCH_OBJECT the error has
|
||||
+ * already been sent stop the search here */
|
||||
cache_return_target_entry(pb, be, operation);
|
||||
goto free_and_return;
|
||||
}
|
||||
|
||||
/* when rc == SLAPI_FAIL_DISKFULL this case is executed */
|
||||
-
|
||||
case SLAPI_FAIL_DISKFULL:
|
||||
operation_out_of_disk_space();
|
||||
cache_return_target_entry(pb, be, operation);
|
||||
diff --git a/ldap/servers/slapd/pagedresults.c b/ldap/servers/slapd/pagedresults.c
|
||||
index db87e486e..4aa1fa3e5 100644
|
||||
--- a/ldap/servers/slapd/pagedresults.c
|
||||
+++ b/ldap/servers/slapd/pagedresults.c
|
||||
@@ -121,12 +121,15 @@ pagedresults_parse_control_value(Slapi_PBlock *pb,
|
||||
if (ber_scanf(ber, "{io}", pagesize, &cookie) == LBER_ERROR) {
|
||||
slapi_log_err(SLAPI_LOG_ERR, "pagedresults_parse_control_value",
|
||||
"<= corrupted control value\n");
|
||||
+ ber_free(ber, 1);
|
||||
return LDAP_PROTOCOL_ERROR;
|
||||
}
|
||||
if (!maxreqs) {
|
||||
slapi_log_err(SLAPI_LOG_ERR, "pagedresults_parse_control_value",
|
||||
"Simple paged results requests per conn exceeded the limit: %d\n",
|
||||
maxreqs);
|
||||
+ ber_free(ber, 1);
|
||||
+ slapi_ch_free_string(&cookie.bv_val);
|
||||
return LDAP_UNWILLING_TO_PERFORM;
|
||||
}
|
||||
|
||||
@@ -376,6 +379,10 @@ pagedresults_free_one_msgid(Connection *conn, ber_int_t msgid, pthread_mutex_t *
|
||||
}
|
||||
prp->pr_flags |= CONN_FLAG_PAGEDRESULTS_ABANDONED;
|
||||
prp->pr_flags &= ~CONN_FLAG_PAGEDRESULTS_PROCESSING;
|
||||
+ if (conn->c_pagedresults.prl_count > 0) {
|
||||
+ _pr_cleanup_one_slot(prp);
|
||||
+ conn->c_pagedresults.prl_count--;
|
||||
+ }
|
||||
rc = 0;
|
||||
break;
|
||||
}
|
||||
@@ -940,7 +947,9 @@ pagedresults_is_timedout_nolock(Connection *conn)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
+
|
||||
slapi_log_err(SLAPI_LOG_TRACE, "<-- pagedresults_is_timedout", "<= false 2\n");
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h
|
||||
index 072f6f962..469874fd1 100644
|
||||
--- a/ldap/servers/slapd/slap.h
|
||||
+++ b/ldap/servers/slapd/slap.h
|
||||
@@ -74,7 +74,7 @@ static char ptokPBE[34] = "Internal (Software) Token ";
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
-
|
||||
+#include <stdbool.h>
|
||||
#include <time.h> /* For timespec definitions */
|
||||
|
||||
/* Provides our int types and platform specific requirements. */
|
||||
--
|
||||
2.48.0
|
||||
|
||||
@ -1,29 +0,0 @@
|
||||
From 27cd055197bc3cae458a1f86621aa5410c66dd2c Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
Date: Mon, 20 Jan 2025 15:51:24 -0500
|
||||
Subject: [PATCH] Issue 6509 - Fix cherry pick issue (race condition in Paged
|
||||
results)
|
||||
|
||||
Relates: https://github.com/389ds/389-ds-base/issues/6509
|
||||
---
|
||||
ldap/servers/slapd/daemon.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
|
||||
index 13dfe250d..57e07e5f5 100644
|
||||
--- a/ldap/servers/slapd/daemon.c
|
||||
+++ b/ldap/servers/slapd/daemon.c
|
||||
@@ -1620,8 +1620,8 @@ setup_pr_read_pds(Connection_Table *ct)
|
||||
connection_table_move_connection_out_of_active_list(ct, c);
|
||||
} else if (c->c_prfd != NULL) {
|
||||
if ((!c->c_gettingber) && (c->c_threadnumber < c->c_max_threads_per_conn)) {
|
||||
- ct->fd[listnum][count].fd = c->c_prfd;
|
||||
- ct->fd[listnum][count].in_flags = SLAPD_POLL_FLAGS;
|
||||
+ ct->fd[count].fd = c->c_prfd;
|
||||
+ ct->fd[count].in_flags = SLAPD_POLL_FLAGS;
|
||||
/* slot i of the connection table is mapped to slot
|
||||
* count of the fds array */
|
||||
c->c_fdi = count;
|
||||
--
|
||||
2.48.0
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,236 +0,0 @@
|
||||
From 1845aed98becaba6b975342229cb5e0de79d208d Mon Sep 17 00:00:00 2001
|
||||
From: James Chapman <jachapma@redhat.com>
|
||||
Date: Wed, 29 Jan 2025 17:41:55 +0000
|
||||
Subject: [PATCH] Issue 6436 - MOD on a large group slow if substring index is
|
||||
present (#6437)
|
||||
|
||||
Bug Description: If the substring index is configured for the group
|
||||
membership attribute ( member or uniqueMember ), the removal of a
|
||||
member from a large static group is pretty slow.
|
||||
|
||||
Fix Description: A solution to this issue would be to introduce
|
||||
a new index to track a membership atttribute index. In the interm,
|
||||
we add a check to healthcheck to inform the user of the implications
|
||||
of this configuration.
|
||||
|
||||
Fixes: https://github.com/389ds/389-ds-base/issues/6436
|
||||
|
||||
Reviewed by: @Firstyear, @tbordaz, @droideck (Thanks)
|
||||
---
|
||||
.../suites/healthcheck/health_config_test.py | 89 ++++++++++++++++++-
|
||||
src/lib389/lib389/lint.py | 15 ++++
|
||||
src/lib389/lib389/plugins.py | 37 +++++++-
|
||||
3 files changed, 137 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/healthcheck/health_config_test.py b/dirsrvtests/tests/suites/healthcheck/health_config_test.py
|
||||
index 6d3d08bfa..747699486 100644
|
||||
--- a/dirsrvtests/tests/suites/healthcheck/health_config_test.py
|
||||
+++ b/dirsrvtests/tests/suites/healthcheck/health_config_test.py
|
||||
@@ -212,6 +212,7 @@ def test_healthcheck_RI_plugin_missing_indexes(topology_st):
|
||||
MEMBER_DN = 'cn=member,cn=index,cn=userroot,cn=ldbm database,cn=plugins,cn=config'
|
||||
|
||||
standalone = topology_st.standalone
|
||||
+ standalone.config.set("nsslapd-accesslog-logbuffering", "on")
|
||||
|
||||
log.info('Enable RI plugin')
|
||||
plugin = ReferentialIntegrityPlugin(standalone)
|
||||
@@ -233,7 +234,7 @@ def test_healthcheck_RI_plugin_missing_indexes(topology_st):
|
||||
|
||||
|
||||
def test_healthcheck_MO_plugin_missing_indexes(topology_st):
|
||||
- """Check if HealthCheck returns DSMOLE0002 code
|
||||
+ """Check if HealthCheck returns DSMOLE0001 code
|
||||
|
||||
:id: 236b0ec2-13da-48fb-b65a-db7406d56d5d
|
||||
:setup: Standalone instance
|
||||
@@ -248,8 +249,8 @@ def test_healthcheck_MO_plugin_missing_indexes(topology_st):
|
||||
:expectedresults:
|
||||
1. Success
|
||||
2. Success
|
||||
- 3. Healthcheck reports DSMOLE0002 code and related details
|
||||
- 4. Healthcheck reports DSMOLE0002 code and related details
|
||||
+ 3. Healthcheck reports DSMOLE0001 code and related details
|
||||
+ 4. Healthcheck reports DSMOLE0001 code and related details
|
||||
5. Success
|
||||
6. Healthcheck reports no issue found
|
||||
7. Healthcheck reports no issue found
|
||||
@@ -259,6 +260,7 @@ def test_healthcheck_MO_plugin_missing_indexes(topology_st):
|
||||
MO_GROUP_ATTR = 'creatorsname'
|
||||
|
||||
standalone = topology_st.standalone
|
||||
+ standalone.config.set("nsslapd-accesslog-logbuffering", "on")
|
||||
|
||||
log.info('Enable MO plugin')
|
||||
plugin = MemberOfPlugin(standalone)
|
||||
@@ -279,6 +281,87 @@ def test_healthcheck_MO_plugin_missing_indexes(topology_st):
|
||||
run_healthcheck_and_flush_log(topology_st, standalone, json=True, searched_code=JSON_OUTPUT)
|
||||
|
||||
|
||||
+def test_healthcheck_MO_plugin_substring_index(topology_st):
|
||||
+ """Check if HealthCheck returns DSMOLE0002 code when the
|
||||
+ member, uniquemember attribute contains a substring index type
|
||||
+
|
||||
+ :id: 10954811-24ac-4886-8183-e30892f8e02d
|
||||
+ :setup: Standalone instance
|
||||
+ :steps:
|
||||
+ 1. Create DS instance
|
||||
+ 2. Configure the instance with MO Plugin
|
||||
+ 3. Change index type to substring for member attribute
|
||||
+ 4. Use HealthCheck without --json option
|
||||
+ 5. Use HealthCheck with --json option
|
||||
+ 6. Change index type back to equality for member attribute
|
||||
+ 7. Use HealthCheck without --json option
|
||||
+ 8. Use HealthCheck with --json option
|
||||
+ 9. Change index type to substring for uniquemember attribute
|
||||
+ 10. Use HealthCheck without --json option
|
||||
+ 11. Use HealthCheck with --json option
|
||||
+ 12. Change index type back to equality for uniquemember attribute
|
||||
+ 13. Use HealthCheck without --json option
|
||||
+ 14. Use HealthCheck with --json option
|
||||
+
|
||||
+ :expectedresults:
|
||||
+ 1. Success
|
||||
+ 2. Success
|
||||
+ 3. Success
|
||||
+ 4. Healthcheck reports DSMOLE0002 code and related details
|
||||
+ 5. Healthcheck reports DSMOLE0002 code and related details
|
||||
+ 6. Success
|
||||
+ 7. Healthcheck reports no issue found
|
||||
+ 8. Healthcheck reports no issue found
|
||||
+ 9. Success
|
||||
+ 10. Healthcheck reports DSMOLE0002 code and related details
|
||||
+ 11. Healthcheck reports DSMOLE0002 code and related details
|
||||
+ 12. Success
|
||||
+ 13. Healthcheck reports no issue found
|
||||
+ 14. Healthcheck reports no issue found
|
||||
+ """
|
||||
+
|
||||
+ RET_CODE = 'DSMOLE0002'
|
||||
+ MEMBER_DN = 'cn=member,cn=index,cn=userroot,cn=ldbm database,cn=plugins,cn=config'
|
||||
+ UNIQUE_MEMBER_DN = 'cn=uniquemember,cn=index,cn=userroot,cn=ldbm database,cn=plugins,cn=config'
|
||||
+
|
||||
+ standalone = topology_st.standalone
|
||||
+ standalone.config.set("nsslapd-accesslog-logbuffering", "on")
|
||||
+
|
||||
+ log.info('Enable MO plugin')
|
||||
+ plugin = MemberOfPlugin(standalone)
|
||||
+ plugin.disable()
|
||||
+ plugin.enable()
|
||||
+
|
||||
+ log.info('Change the index type of the member attribute index to substring')
|
||||
+ index = Index(topology_st.standalone, MEMBER_DN)
|
||||
+ index.replace('nsIndexType', 'sub')
|
||||
+
|
||||
+ 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)
|
||||
+
|
||||
+ log.info('Set the index type of the member attribute index back to eq')
|
||||
+ index.replace('nsIndexType', 'eq')
|
||||
+
|
||||
+ 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('Change the index type of the uniquemember attribute index to substring')
|
||||
+ index = Index(topology_st.standalone, UNIQUE_MEMBER_DN)
|
||||
+ index.replace('nsIndexType', 'sub')
|
||||
+
|
||||
+ 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)
|
||||
+
|
||||
+ log.info('Set the index type of the uniquemember attribute index back to eq')
|
||||
+ index.replace('nsIndexType', 'eq')
|
||||
+
|
||||
+ 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)
|
||||
+
|
||||
+ # Restart the instance after changing the plugin to avoid breaking the other tests
|
||||
+ standalone.restart()
|
||||
+
|
||||
+
|
||||
@pytest.mark.ds50873
|
||||
@pytest.mark.bz1685160
|
||||
@pytest.mark.xfail(ds_is_older("1.4.1"), reason="Not implemented")
|
||||
diff --git a/src/lib389/lib389/lint.py b/src/lib389/lib389/lint.py
|
||||
index 4d9cbb666..3d3c79ea3 100644
|
||||
--- a/src/lib389/lib389/lint.py
|
||||
+++ b/src/lib389/lib389/lint.py
|
||||
@@ -231,6 +231,21 @@ database after adding the missing index type. Here is an example using dsconf:
|
||||
"""
|
||||
}
|
||||
|
||||
+DSMOLE0002 = {
|
||||
+ 'dsle': 'DSMOLE0002',
|
||||
+ 'severity': 'LOW',
|
||||
+ 'description': 'Removal of a member can be slow ',
|
||||
+ 'items': ['cn=memberof plugin,cn=plugins,cn=config', ],
|
||||
+ 'detail': """If the substring index is configured for a membership attribute. The removal of a member
|
||||
+from the large group can be slow.
|
||||
+
|
||||
+""",
|
||||
+ 'fix': """If not required, you can remove the substring index type using dsconf:
|
||||
+
|
||||
+ # dsconf slapd-YOUR_INSTANCE backend index set --attr=ATTR BACKEND --del-type=sub
|
||||
+"""
|
||||
+}
|
||||
+
|
||||
# Disk Space check. Note - PARTITION is replaced by the calling function
|
||||
DSDSLE0001 = {
|
||||
'dsle': 'DSDSLE0001',
|
||||
diff --git a/src/lib389/lib389/plugins.py b/src/lib389/lib389/plugins.py
|
||||
index 6bf1843ad..185398e5b 100644
|
||||
--- a/src/lib389/lib389/plugins.py
|
||||
+++ b/src/lib389/lib389/plugins.py
|
||||
@@ -12,7 +12,7 @@ import copy
|
||||
import os.path
|
||||
from lib389 import tasks
|
||||
from lib389._mapped_object import DSLdapObjects, DSLdapObject
|
||||
-from lib389.lint import DSRILE0001, DSRILE0002, DSMOLE0001
|
||||
+from lib389.lint import DSRILE0001, DSRILE0002, DSMOLE0001, DSMOLE0002
|
||||
from lib389.utils import ensure_str, ensure_list_bytes
|
||||
from lib389.schema import Schema
|
||||
from lib389._constants import (
|
||||
@@ -827,6 +827,41 @@ class MemberOfPlugin(Plugin):
|
||||
report['check'] = f'memberof:attr_indexes'
|
||||
yield report
|
||||
|
||||
+ def _lint_member_substring_index(self):
|
||||
+ if self.status():
|
||||
+ from lib389.backend import Backends
|
||||
+ backends = Backends(self._instance).list()
|
||||
+ membership_attrs = ['member', 'uniquemember']
|
||||
+ container = self.get_attr_val_utf8_l("nsslapd-plugincontainerscope")
|
||||
+ 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
|
||||
+ continue
|
||||
+ indexes = backend.get_indexes()
|
||||
+ for attr in membership_attrs:
|
||||
+ report = copy.deepcopy(DSMOLE0002)
|
||||
+ try:
|
||||
+ index = indexes.get(attr)
|
||||
+ types = index.get_attr_vals_utf8_l("nsIndexType")
|
||||
+ if "sub" in types:
|
||||
+ report['detail'] = report['detail'].replace('ATTR', attr)
|
||||
+ report['detail'] = report['detail'].replace('BACKEND', suffix)
|
||||
+ report['fix'] = report['fix'].replace('ATTR', attr)
|
||||
+ report['fix'] = report['fix'].replace('BACKEND', suffix)
|
||||
+ report['fix'] = report['fix'].replace('YOUR_INSTANCE', self._instance.serverid)
|
||||
+ report['items'].append(suffix)
|
||||
+ report['items'].append(attr)
|
||||
+ report['check'] = f'attr:substring_index'
|
||||
+ yield report
|
||||
+ except KeyError:
|
||||
+ continue
|
||||
+
|
||||
def get_attr(self):
|
||||
"""Get memberofattr attribute"""
|
||||
|
||||
--
|
||||
2.48.1
|
||||
|
||||
@ -1,651 +0,0 @@
|
||||
From dba27e56161943fbcf54ecbc28337e2c81b07979 Mon Sep 17 00:00:00 2001
|
||||
From: progier389 <progier@redhat.com>
|
||||
Date: Mon, 13 Jan 2025 18:03:07 +0100
|
||||
Subject: [PATCH] Issue 6494 - Various errors when using extended matching rule
|
||||
on vlv sort filter (#6495)
|
||||
|
||||
* Issue 6494 - Various errors when using extended matching rule on vlv sort filter
|
||||
|
||||
Various issues when configuring and using extended matching rule within a vlv sort filter:
|
||||
|
||||
Race condition about the keys storage while indexing leading to various heap and data corruption. (lmdb only)
|
||||
Crash while indexing if vlv are misconfigured because NULL key is not checked.
|
||||
Read after block because of data type mismatch between SlapiValue and berval
|
||||
Memory leaks
|
||||
Solution:
|
||||
|
||||
Serialize the vlv index key generation if vlv filter has an extended matching rule.
|
||||
Check null keys
|
||||
Always provides SlapiValue even ifg we want to get keys as bervals
|
||||
Free properly the resources
|
||||
Issue: #6494
|
||||
|
||||
Reviewed by: @mreynolds389 (Thanks!)
|
||||
|
||||
(cherry picked from commit 4bd27ecc4e1d21c8af5ab8cad795d70477179a98)
|
||||
(cherry picked from commit 223a20250cbf29a546dcb398cfc76024d2f91347)
|
||||
(cherry picked from commit 280043740a525eaf0438129fd8b99ca251c62366)
|
||||
---
|
||||
.../tests/suites/indexes/regression_test.py | 29 +++
|
||||
.../tests/suites/vlv/regression_test.py | 183 ++++++++++++++++++
|
||||
ldap/servers/slapd/back-ldbm/cleanup.c | 8 +
|
||||
ldap/servers/slapd/back-ldbm/dblayer.c | 22 ++-
|
||||
ldap/servers/slapd/back-ldbm/ldbm_attr.c | 2 +-
|
||||
ldap/servers/slapd/back-ldbm/matchrule.c | 8 +-
|
||||
.../servers/slapd/back-ldbm/proto-back-ldbm.h | 3 +-
|
||||
ldap/servers/slapd/back-ldbm/sort.c | 37 ++--
|
||||
ldap/servers/slapd/back-ldbm/vlv.c | 26 +--
|
||||
ldap/servers/slapd/back-ldbm/vlv_srch.c | 4 +-
|
||||
ldap/servers/slapd/generation.c | 5 +
|
||||
ldap/servers/slapd/plugin_mr.c | 12 +-
|
||||
src/lib389/lib389/backend.py | 10 +
|
||||
13 files changed, 292 insertions(+), 57 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/indexes/regression_test.py b/dirsrvtests/tests/suites/indexes/regression_test.py
|
||||
index fc6db727f..2196fb2ed 100644
|
||||
--- a/dirsrvtests/tests/suites/indexes/regression_test.py
|
||||
+++ b/dirsrvtests/tests/suites/indexes/regression_test.py
|
||||
@@ -227,6 +227,35 @@ def test_reject_virtual_attr_for_indexing(topo):
|
||||
break
|
||||
|
||||
|
||||
+def test_reindex_extended_matching_rule(topo, add_backend_and_ldif_50K_users):
|
||||
+ """Check that index with extended matching rule are reindexed properly.
|
||||
+
|
||||
+ :id: 8a3198e8-cc5a-11ef-a3e7-482ae39447e5
|
||||
+ :setup: Standalone instance + a second backend with 50K users
|
||||
+ :steps:
|
||||
+ 1. Configure uid with 2.5.13.2 matching rule
|
||||
+ 1. Configure cn with 2.5.13.2 matching rule
|
||||
+ 2. Reindex
|
||||
+ :expectedresults:
|
||||
+ 1. Success
|
||||
+ 2. Success
|
||||
+ """
|
||||
+
|
||||
+ inst = topo.standalone
|
||||
+ tasks = Tasks(inst)
|
||||
+ be2 = Backends(topo.standalone).get_backend(SUFFIX2)
|
||||
+ index = be2.get_index('uid')
|
||||
+ index.replace('nsMatchingRule', '2.5.13.2')
|
||||
+ index = be2.get_index('cn')
|
||||
+ index.replace('nsMatchingRule', '2.5.13.2')
|
||||
+
|
||||
+ assert tasks.reindex(
|
||||
+ suffix=SUFFIX2,
|
||||
+ args={TASK_WAIT: True}
|
||||
+ ) == 0
|
||||
+
|
||||
+
|
||||
+
|
||||
if __name__ == "__main__":
|
||||
# Run isolated
|
||||
# -s for DEBUG mode
|
||||
diff --git a/dirsrvtests/tests/suites/vlv/regression_test.py b/dirsrvtests/tests/suites/vlv/regression_test.py
|
||||
index 3b66de8b5..6ab709bd3 100644
|
||||
--- a/dirsrvtests/tests/suites/vlv/regression_test.py
|
||||
+++ b/dirsrvtests/tests/suites/vlv/regression_test.py
|
||||
@@ -22,6 +22,146 @@ logging.getLogger(__name__).setLevel(logging.DEBUG)
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
+class BackendHandler:
|
||||
+ def __init__(self, inst, bedict, scope=ldap.SCOPE_ONELEVEL):
|
||||
+ self.inst = inst
|
||||
+ self.bedict = bedict
|
||||
+ self.bes = Backends(inst)
|
||||
+ self.scope = scope
|
||||
+ self.data = {}
|
||||
+
|
||||
+ def find_backend(self, bename):
|
||||
+ for be in self.bes.list():
|
||||
+ if be.get_attr_val_utf8_l('cn') == bename:
|
||||
+ return be
|
||||
+ return None
|
||||
+
|
||||
+ def cleanup(self):
|
||||
+ benames = list(self.bedict.keys())
|
||||
+ benames.reverse()
|
||||
+ for bename in benames:
|
||||
+ be = self.find_backend(bename)
|
||||
+ if be:
|
||||
+ be.delete()
|
||||
+
|
||||
+ def setup(self):
|
||||
+ # Create backends, add vlv index and populate the backends.
|
||||
+ for bename,suffix in self.bedict.items():
|
||||
+ be = self.bes.create(properties={
|
||||
+ 'cn': bename,
|
||||
+ 'nsslapd-suffix': suffix,
|
||||
+ })
|
||||
+ # Add suffix entry
|
||||
+ Organization(self.inst, dn=suffix).create(properties={ 'o': bename, })
|
||||
+ # Configure vlv
|
||||
+ vlv_search, vlv_index = create_vlv_search_and_index(
|
||||
+ self.inst, basedn=suffix,
|
||||
+ bename=bename, scope=self.scope,
|
||||
+ prefix=f'vlv_1lvl_{bename}')
|
||||
+ # Reindex
|
||||
+ reindex_task = Tasks(self.inst)
|
||||
+ assert reindex_task.reindex(
|
||||
+ suffix=suffix,
|
||||
+ attrname=vlv_index.rdn,
|
||||
+ args={TASK_WAIT: True},
|
||||
+ vlv=True
|
||||
+ ) == 0
|
||||
+ # Add ou=People entry
|
||||
+ OrganizationalUnits(self.inst, suffix).create(properties={'ou': 'People'})
|
||||
+ # Add another ou that will be deleted before the export
|
||||
+ # so that import will change the vlv search basedn entryid
|
||||
+ ou2 = OrganizationalUnits(self.inst, suffix).create(properties={'ou': 'dummy ou'})
|
||||
+ # Add a demo user so that vlv_check is happy
|
||||
+ dn = f'uid=demo_user,ou=people,{suffix}'
|
||||
+ UserAccount(self.inst, dn=dn).create( properties= {
|
||||
+ 'uid': 'demo_user',
|
||||
+ 'cn': 'Demo user',
|
||||
+ 'sn': 'Demo user',
|
||||
+ 'uidNumber': '99998',
|
||||
+ 'gidNumber': '99998',
|
||||
+ 'homeDirectory': '/var/empty',
|
||||
+ 'loginShell': '/bin/false',
|
||||
+ 'userpassword': DEMO_PW })
|
||||
+ # Add regular user
|
||||
+ add_users(self.inst, 10, suffix=suffix)
|
||||
+ # Removing ou2
|
||||
+ ou2.delete()
|
||||
+ # And export
|
||||
+ tasks = Tasks(self.inst)
|
||||
+ ldif = f'{self.inst.get_ldif_dir()}/db-{bename}.ldif'
|
||||
+ assert tasks.exportLDIF(suffix=suffix,
|
||||
+ output_file=ldif,
|
||||
+ args={TASK_WAIT: True}) == 0
|
||||
+ # Add the various parameters in topology_st.belist
|
||||
+ self.data[bename] = { 'be': be,
|
||||
+ 'suffix': suffix,
|
||||
+ 'ldif': ldif,
|
||||
+ 'vlv_search' : vlv_search,
|
||||
+ 'vlv_index' : vlv_index,
|
||||
+ 'dn' : dn}
|
||||
+
|
||||
+
|
||||
+def create_vlv_search_and_index(inst, basedn=DEFAULT_SUFFIX, bename='userRoot',
|
||||
+ scope=ldap.SCOPE_SUBTREE, prefix="vlv", vlvsort="cn"):
|
||||
+ vlv_searches = VLVSearch(inst)
|
||||
+ vlv_search_properties = {
|
||||
+ "objectclass": ["top", "vlvSearch"],
|
||||
+ "cn": f"{prefix}Srch",
|
||||
+ "vlvbase": basedn,
|
||||
+ "vlvfilter": "(uid=*)",
|
||||
+ "vlvscope": str(scope),
|
||||
+ }
|
||||
+ vlv_searches.create(
|
||||
+ basedn=f"cn={bename},cn=ldbm database,cn=plugins,cn=config",
|
||||
+ properties=vlv_search_properties
|
||||
+ )
|
||||
+
|
||||
+ vlv_index = VLVIndex(inst)
|
||||
+ vlv_index_properties = {
|
||||
+ "objectclass": ["top", "vlvIndex"],
|
||||
+ "cn": f"{prefix}Idx",
|
||||
+ "vlvsort": vlvsort,
|
||||
+ }
|
||||
+ vlv_index.create(
|
||||
+ basedn=f"cn={prefix}Srch,cn={bename},cn=ldbm database,cn=plugins,cn=config",
|
||||
+ properties=vlv_index_properties
|
||||
+ )
|
||||
+ return vlv_searches, vlv_index
|
||||
+
|
||||
+
|
||||
+@pytest.fixture
|
||||
+def vlv_setup_with_uid_mr(topology_st, request):
|
||||
+ inst = topology_st.standalone
|
||||
+ bename = 'be1'
|
||||
+ besuffix = f'o={bename}'
|
||||
+ beh = BackendHandler(inst, { bename: besuffix })
|
||||
+
|
||||
+ def fin():
|
||||
+ # Cleanup function
|
||||
+ if not DEBUGGING and inst.exists() and inst.status():
|
||||
+ beh.cleanup()
|
||||
+
|
||||
+ request.addfinalizer(fin)
|
||||
+
|
||||
+ # Make sure that our backend are not already present.
|
||||
+ beh.cleanup()
|
||||
+
|
||||
+ # Then add the new backend
|
||||
+ beh.setup()
|
||||
+
|
||||
+ index = Index(inst, f'cn=uid,cn=index,cn={bename},cn=ldbm database,cn=plugins,cn=config')
|
||||
+ index.add('nsMatchingRule', '2.5.13.2')
|
||||
+ reindex_task = Tasks(inst)
|
||||
+ assert reindex_task.reindex(
|
||||
+ suffix=besuffix,
|
||||
+ attrname='uid',
|
||||
+ args={TASK_WAIT: True}
|
||||
+ ) == 0
|
||||
+
|
||||
+ topology_st.beh = beh
|
||||
+ return topology_st
|
||||
+
|
||||
+
|
||||
@pytest.mark.DS47966
|
||||
def test_bulk_import_when_the_backend_with_vlv_was_recreated(topology_m2):
|
||||
"""
|
||||
@@ -105,6 +245,49 @@ def test_bulk_import_when_the_backend_with_vlv_was_recreated(topology_m2):
|
||||
entries = M2.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, "(objectclass=*)")
|
||||
|
||||
|
||||
+def test_vlv_with_mr(vlv_setup_with_uid_mr):
|
||||
+ """
|
||||
+ Testing vlv having specific matching rule
|
||||
+
|
||||
+ :id: 5e04afe2-beec-11ef-aa84-482ae39447e5
|
||||
+ :setup: Standalone with uid have a matching rule index
|
||||
+ :steps:
|
||||
+ 1. Append vlvIndex entries then vlvSearch entry in the dse.ldif
|
||||
+ 2. Restart the server
|
||||
+ :expectedresults:
|
||||
+ 1. Should Success.
|
||||
+ 2. Should Success.
|
||||
+ """
|
||||
+ inst = vlv_setup_with_uid_mr.standalone
|
||||
+ beh = vlv_setup_with_uid_mr.beh
|
||||
+ bename, besuffix = next(iter(beh.bedict.items()))
|
||||
+ vlv_searches, vlv_index = create_vlv_search_and_index(
|
||||
+ inst, basedn=besuffix, bename=bename,
|
||||
+ vlvsort="uid:2.5.13.2")
|
||||
+ # Reindex the vlv
|
||||
+ reindex_task = Tasks(inst)
|
||||
+ assert reindex_task.reindex(
|
||||
+ suffix=besuffix,
|
||||
+ attrname=vlv_index.rdn,
|
||||
+ args={TASK_WAIT: True},
|
||||
+ vlv=True
|
||||
+ ) == 0
|
||||
+
|
||||
+ inst.restart()
|
||||
+ users = UserAccounts(inst, besuffix)
|
||||
+ user_properties = {
|
||||
+ 'uid': f'a new testuser',
|
||||
+ 'cn': f'a new testuser',
|
||||
+ 'sn': 'user',
|
||||
+ 'uidNumber': '0',
|
||||
+ 'gidNumber': '0',
|
||||
+ 'homeDirectory': 'foo'
|
||||
+ }
|
||||
+ user = users.create(properties=user_properties)
|
||||
+ user.delete()
|
||||
+ assert inst.status()
|
||||
+
|
||||
+
|
||||
if __name__ == "__main__":
|
||||
# Run isolated
|
||||
# -s for DEBUG mode
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/cleanup.c b/ldap/servers/slapd/back-ldbm/cleanup.c
|
||||
index 6b2e9faef..939d8bc4f 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/cleanup.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/cleanup.c
|
||||
@@ -15,12 +15,14 @@
|
||||
|
||||
#include "back-ldbm.h"
|
||||
#include "dblayer.h"
|
||||
+#include "vlv_srch.h"
|
||||
|
||||
int
|
||||
ldbm_back_cleanup(Slapi_PBlock *pb)
|
||||
{
|
||||
struct ldbminfo *li;
|
||||
Slapi_Backend *be;
|
||||
+ struct vlvSearch *nextp;
|
||||
|
||||
slapi_log_err(SLAPI_LOG_TRACE, "ldbm_back_cleanup", "ldbm backend cleaning up\n");
|
||||
slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &li);
|
||||
@@ -45,6 +47,12 @@ ldbm_back_cleanup(Slapi_PBlock *pb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+ /* Release the vlv list */
|
||||
+ for (struct vlvSearch *p=be->vlvSearchList; p; p=nextp) {
|
||||
+ nextp = p->vlv_next;
|
||||
+ vlvSearch_delete(&p);
|
||||
+ }
|
||||
+
|
||||
/*
|
||||
* We check if li is NULL. Because of an issue in how we create backends
|
||||
* we share the li and plugin info between many unique backends. This causes
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/dblayer.c b/ldap/servers/slapd/back-ldbm/dblayer.c
|
||||
index 05cc5b891..6b8ce0016 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/dblayer.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/dblayer.c
|
||||
@@ -494,8 +494,12 @@ int
|
||||
dblayer_close(struct ldbminfo *li, int dbmode)
|
||||
{
|
||||
dblayer_private *priv = (dblayer_private *)li->li_dblayer_private;
|
||||
-
|
||||
- return priv->dblayer_close_fn(li, dbmode);
|
||||
+ int rc = priv->dblayer_close_fn(li, dbmode);
|
||||
+ if (rc == 0) {
|
||||
+ /* Clean thread specific data */
|
||||
+ dblayer_destroy_txn_stack();
|
||||
+ }
|
||||
+ return rc;
|
||||
}
|
||||
|
||||
/* Routines for opening and closing random files in the DB_ENV.
|
||||
@@ -621,6 +625,9 @@ dblayer_erase_index_file(backend *be, struct attrinfo *a, PRBool use_lock, int n
|
||||
return 0;
|
||||
}
|
||||
struct ldbminfo *li = (struct ldbminfo *)be->be_database->plg_private;
|
||||
+ if (NULL == li) {
|
||||
+ return 0;
|
||||
+ }
|
||||
dblayer_private *priv = (dblayer_private *)li->li_dblayer_private;
|
||||
|
||||
return priv->dblayer_rm_db_file_fn(be, a, use_lock, no_force_chkpt);
|
||||
@@ -1382,3 +1389,14 @@ dblayer_pop_pvt_txn(void)
|
||||
}
|
||||
return;
|
||||
}
|
||||
+
|
||||
+void
|
||||
+dblayer_destroy_txn_stack(void)
|
||||
+{
|
||||
+ /*
|
||||
+ * Cleanup for the main thread to avoid false/positive leaks from libasan
|
||||
+ * Note: data is freed because PR_SetThreadPrivate calls the
|
||||
+ * dblayer_cleanup_txn_stack callback
|
||||
+ */
|
||||
+ PR_SetThreadPrivate(thread_private_txn_stack, NULL);
|
||||
+}
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_attr.c b/ldap/servers/slapd/back-ldbm/ldbm_attr.c
|
||||
index 708756d3e..70700ca1d 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/ldbm_attr.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/ldbm_attr.c
|
||||
@@ -54,7 +54,7 @@ attrinfo_delete(struct attrinfo **pp)
|
||||
idl_release_private(*pp);
|
||||
(*pp)->ai_key_cmp_fn = NULL;
|
||||
slapi_ch_free((void **)&((*pp)->ai_type));
|
||||
- slapi_ch_free((void **)(*pp)->ai_index_rules);
|
||||
+ charray_free((*pp)->ai_index_rules);
|
||||
slapi_ch_free((void **)&((*pp)->ai_attrcrypt));
|
||||
attr_done(&((*pp)->ai_sattr));
|
||||
attrinfo_delete_idlistinfo(&(*pp)->ai_idlistinfo);
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/matchrule.c b/ldap/servers/slapd/back-ldbm/matchrule.c
|
||||
index 5d516b9f8..5365e8acf 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/matchrule.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/matchrule.c
|
||||
@@ -107,7 +107,7 @@ destroy_matchrule_indexer(Slapi_PBlock *pb)
|
||||
* is destroyed
|
||||
*/
|
||||
int
|
||||
-matchrule_values_to_keys(Slapi_PBlock *pb, struct berval **input_values, struct berval ***output_values)
|
||||
+matchrule_values_to_keys(Slapi_PBlock *pb, Slapi_Value **input_values, struct berval ***output_values)
|
||||
{
|
||||
IFP mrINDEX = NULL;
|
||||
|
||||
@@ -135,10 +135,8 @@ matchrule_values_to_keys_sv(Slapi_PBlock *pb, Slapi_Value **input_values, Slapi_
|
||||
slapi_pblock_get(pb, SLAPI_PLUGIN_MR_INDEX_SV_FN, &mrINDEX);
|
||||
if (NULL == mrINDEX) { /* old school - does not have SV function */
|
||||
int rc;
|
||||
- struct berval **bvi = NULL, **bvo = NULL;
|
||||
- valuearray_get_bervalarray(input_values, &bvi);
|
||||
- rc = matchrule_values_to_keys(pb, bvi, &bvo);
|
||||
- ber_bvecfree(bvi);
|
||||
+ struct berval **bvo = NULL;
|
||||
+ rc = matchrule_values_to_keys(pb, input_values, &bvo);
|
||||
/* note - the indexer owns bvo and will free it when destroyed */
|
||||
valuearray_init_bervalarray(bvo, output_values);
|
||||
/* store output values in SV form - caller expects SLAPI_PLUGIN_MR_KEYS is Slapi_Value** */
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
|
||||
index d93ff9239..157788fa4 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
|
||||
+++ b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
|
||||
@@ -84,6 +84,7 @@ int dblayer_release_index_file(backend *be, struct attrinfo *a, DB *pDB);
|
||||
int dblayer_erase_index_file(backend *be, struct attrinfo *a, PRBool use_lock, int no_force_chkpt);
|
||||
int dblayer_get_id2entry(backend *be, DB **ppDB);
|
||||
int dblayer_release_id2entry(backend *be, DB *pDB);
|
||||
+void dblayer_destroy_txn_stack(void);
|
||||
int dblayer_txn_init(struct ldbminfo *li, back_txn *txn);
|
||||
int dblayer_txn_begin(backend *be, back_txnid parent_txn, back_txn *txn);
|
||||
int dblayer_txn_begin_ext(struct ldbminfo *li, back_txnid parent_txn, back_txn *txn, PRBool use_lock);
|
||||
@@ -560,7 +561,7 @@ int compute_allids_limit(Slapi_PBlock *pb, struct ldbminfo *li);
|
||||
*/
|
||||
int create_matchrule_indexer(Slapi_PBlock **pb, char *matchrule, char *type);
|
||||
int destroy_matchrule_indexer(Slapi_PBlock *pb);
|
||||
-int matchrule_values_to_keys(Slapi_PBlock *pb, struct berval **input_values, struct berval ***output_values);
|
||||
+int matchrule_values_to_keys(Slapi_PBlock *pb, Slapi_Value **input_values, struct berval ***output_values);
|
||||
int matchrule_values_to_keys_sv(Slapi_PBlock *pb, Slapi_Value **input_values, Slapi_Value ***output_values);
|
||||
|
||||
/*
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/sort.c b/ldap/servers/slapd/back-ldbm/sort.c
|
||||
index 70ac60803..196af753f 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/sort.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/sort.c
|
||||
@@ -536,30 +536,18 @@ compare_entries_sv(ID *id_a, ID *id_b, sort_spec *s, baggage_carrier *bc, int *e
|
||||
valuearray_get_bervalarray(valueset_get_valuearray(&attr_b->a_present_values), &value_b);
|
||||
} else {
|
||||
/* Match rule case */
|
||||
- struct berval **actual_value_a = NULL;
|
||||
- struct berval **actual_value_b = NULL;
|
||||
- struct berval **temp_value = NULL;
|
||||
-
|
||||
- valuearray_get_bervalarray(valueset_get_valuearray(&attr_a->a_present_values), &actual_value_a);
|
||||
- valuearray_get_bervalarray(valueset_get_valuearray(&attr_b->a_present_values), &actual_value_b);
|
||||
- matchrule_values_to_keys(this_one->mr_pb, actual_value_a, &temp_value);
|
||||
- /* Now copy it, so the second call doesn't crap on it */
|
||||
- value_a = slapi_ch_bvecdup(temp_value); /* Really, we'd prefer to not call the chXXX variant...*/
|
||||
- matchrule_values_to_keys(this_one->mr_pb, actual_value_b, &value_b);
|
||||
-
|
||||
- if ((actual_value_a && !value_a) ||
|
||||
- (actual_value_b && !value_b)) {
|
||||
- ber_bvecfree(actual_value_a);
|
||||
- ber_bvecfree(actual_value_b);
|
||||
- CACHE_RETURN(&inst->inst_cache, &a);
|
||||
- CACHE_RETURN(&inst->inst_cache, &b);
|
||||
- *error = 1;
|
||||
- return 0;
|
||||
+ Slapi_Value **va_a = valueset_get_valuearray(&attr_a->a_present_values);
|
||||
+ Slapi_Value **va_b = valueset_get_valuearray(&attr_b->a_present_values);
|
||||
+
|
||||
+ matchrule_values_to_keys(this_one->mr_pb, va_a, &value_a);
|
||||
+ /* Plugin owns the memory ==> duplicate the key before next call garble it */
|
||||
+ value_a = slapi_ch_bvecdup(value_a);
|
||||
+ matchrule_values_to_keys(this_one->mr_pb, va_b, &value_b);
|
||||
+
|
||||
+ if ((va_a && !value_a) || (va_b && !value_b)) {
|
||||
+ result = 0;
|
||||
+ goto bail;
|
||||
}
|
||||
- if (actual_value_a)
|
||||
- ber_bvecfree(actual_value_a);
|
||||
- if (actual_value_b)
|
||||
- ber_bvecfree(actual_value_b);
|
||||
}
|
||||
/* Compare them */
|
||||
if (!order) {
|
||||
@@ -582,9 +570,10 @@ compare_entries_sv(ID *id_a, ID *id_b, sort_spec *s, baggage_carrier *bc, int *e
|
||||
}
|
||||
/* If so, proceed to the next attribute for comparison */
|
||||
}
|
||||
+ *error = 0;
|
||||
+bail:
|
||||
CACHE_RETURN(&inst->inst_cache, &a);
|
||||
CACHE_RETURN(&inst->inst_cache, &b);
|
||||
- *error = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/vlv.c b/ldap/servers/slapd/back-ldbm/vlv.c
|
||||
index 121fb3667..70e0bac85 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/vlv.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/vlv.c
|
||||
@@ -605,7 +605,7 @@ vlv_getindices(IFP callback_fn, void *param, backend *be)
|
||||
* generate the same composite key, so we append the EntryID
|
||||
* to ensure the uniqueness of the key.
|
||||
*
|
||||
- * Always creates a key. Never returns NULL.
|
||||
+ * May return NULL in case of errors (typically in some configuration error cases)
|
||||
*/
|
||||
static struct vlv_key *
|
||||
vlv_create_key(struct vlvIndex *p, struct backentry *e)
|
||||
@@ -659,10 +659,8 @@ vlv_create_key(struct vlvIndex *p, struct backentry *e)
|
||||
/* Matching rule. Do the magic mangling. Plugin owns the memory. */
|
||||
if (p->vlv_mrpb[sortattr] != NULL) {
|
||||
/* xxxPINAKI */
|
||||
- struct berval **bval = NULL;
|
||||
Slapi_Value **va = valueset_get_valuearray(&attr->a_present_values);
|
||||
- valuearray_get_bervalarray(va, &bval);
|
||||
- matchrule_values_to_keys(p->vlv_mrpb[sortattr], bval, &value);
|
||||
+ matchrule_values_to_keys(p->vlv_mrpb[sortattr], va, &value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -779,6 +777,13 @@ do_vlv_update_index(back_txn *txn, struct ldbminfo *li __attribute__((unused)),
|
||||
}
|
||||
|
||||
key = vlv_create_key(pIndex, entry);
|
||||
+ if (key == NULL) {
|
||||
+ slapi_log_err(SLAPI_LOG_ERR, "vlv_create_key", "Unable to generate vlv %s index key."
|
||||
+ " There may be a configuration issue.\n", pIndex->vlv_name);
|
||||
+ dblayer_release_index_file(be, pIndex->vlv_attrinfo, db);
|
||||
+ return rc;
|
||||
+ }
|
||||
+
|
||||
if (NULL != txn) {
|
||||
db_txn = txn->back_txn_txn;
|
||||
} else {
|
||||
@@ -949,11 +954,11 @@ vlv_create_matching_rule_value(Slapi_PBlock *pb, struct berval *original_value)
|
||||
struct berval **value = NULL;
|
||||
if (pb != NULL) {
|
||||
struct berval **outvalue = NULL;
|
||||
- struct berval *invalue[2];
|
||||
- invalue[0] = original_value; /* jcm: cast away const */
|
||||
- invalue[1] = NULL;
|
||||
+ Slapi_Value v_in = {0};
|
||||
+ Slapi_Value *va_in[2] = { &v_in, NULL };
|
||||
+ slapi_value_init_berval(&v_in, original_value);
|
||||
/* The plugin owns the memory it returns in outvalue */
|
||||
- matchrule_values_to_keys(pb, invalue, &outvalue);
|
||||
+ matchrule_values_to_keys(pb, va_in, &outvalue);
|
||||
if (outvalue != NULL) {
|
||||
value = slapi_ch_bvecdup(outvalue);
|
||||
}
|
||||
@@ -1610,11 +1615,8 @@ retry:
|
||||
PRBool needFree = PR_FALSE;
|
||||
|
||||
if (sort_control->mr_pb != NULL) {
|
||||
- struct berval **tmp_entry_value = NULL;
|
||||
-
|
||||
- valuearray_get_bervalarray(csn_value, &tmp_entry_value);
|
||||
/* Matching rule. Do the magic mangling. Plugin owns the memory. */
|
||||
- matchrule_values_to_keys(sort_control->mr_pb, /* xxxPINAKI needs modification attr->a_vals */ tmp_entry_value, &entry_value);
|
||||
+ matchrule_values_to_keys(sort_control->mr_pb, csn_value, &entry_value);
|
||||
} else {
|
||||
valuearray_get_bervalarray(csn_value, &entry_value);
|
||||
needFree = PR_TRUE; /* entry_value is a copy */
|
||||
diff --git a/ldap/servers/slapd/back-ldbm/vlv_srch.c b/ldap/servers/slapd/back-ldbm/vlv_srch.c
|
||||
index fe1208d59..11d1c715b 100644
|
||||
--- a/ldap/servers/slapd/back-ldbm/vlv_srch.c
|
||||
+++ b/ldap/servers/slapd/back-ldbm/vlv_srch.c
|
||||
@@ -203,6 +203,9 @@ vlvSearch_delete(struct vlvSearch **ppvs)
|
||||
{
|
||||
if (ppvs != NULL && *ppvs != NULL) {
|
||||
struct vlvIndex *pi, *ni;
|
||||
+ if ((*ppvs)->vlv_e) {
|
||||
+ slapi_entry_free((struct slapi_entry *)((*ppvs)->vlv_e));
|
||||
+ }
|
||||
slapi_sdn_free(&((*ppvs)->vlv_dn));
|
||||
slapi_ch_free((void **)&((*ppvs)->vlv_name));
|
||||
slapi_sdn_free(&((*ppvs)->vlv_base));
|
||||
@@ -217,7 +220,6 @@ vlvSearch_delete(struct vlvSearch **ppvs)
|
||||
pi = ni;
|
||||
}
|
||||
slapi_ch_free((void **)ppvs);
|
||||
- *ppvs = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/ldap/servers/slapd/generation.c b/ldap/servers/slapd/generation.c
|
||||
index c4f20f793..89f097322 100644
|
||||
--- a/ldap/servers/slapd/generation.c
|
||||
+++ b/ldap/servers/slapd/generation.c
|
||||
@@ -93,9 +93,13 @@ get_server_dataversion()
|
||||
lenstr *l = NULL;
|
||||
Slapi_Backend *be;
|
||||
char *cookie;
|
||||
+ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
+ /* Serialize to avoid race condition */
|
||||
+ pthread_mutex_lock(&mutex);
|
||||
/* we already cached the copy - just return it */
|
||||
if (server_dataversion_id != NULL) {
|
||||
+ pthread_mutex_unlock(&mutex);
|
||||
return server_dataversion_id;
|
||||
}
|
||||
|
||||
@@ -130,5 +134,6 @@ get_server_dataversion()
|
||||
server_dataversion_id = slapi_ch_strdup(l->ls_buf);
|
||||
}
|
||||
lenstr_free(&l);
|
||||
+ pthread_mutex_unlock(&mutex);
|
||||
return server_dataversion_id;
|
||||
}
|
||||
diff --git a/ldap/servers/slapd/plugin_mr.c b/ldap/servers/slapd/plugin_mr.c
|
||||
index 13f76fe52..6cf88b7de 100644
|
||||
--- a/ldap/servers/slapd/plugin_mr.c
|
||||
+++ b/ldap/servers/slapd/plugin_mr.c
|
||||
@@ -391,28 +391,18 @@ mr_wrap_mr_index_sv_fn(Slapi_PBlock *pb)
|
||||
return rc;
|
||||
}
|
||||
|
||||
-/* this function takes SLAPI_PLUGIN_MR_VALUES as struct berval ** and
|
||||
+/* this function takes SLAPI_PLUGIN_MR_VALUES as Slapi_Value ** and
|
||||
returns SLAPI_PLUGIN_MR_KEYS as struct berval **
|
||||
*/
|
||||
static int
|
||||
mr_wrap_mr_index_fn(Slapi_PBlock *pb)
|
||||
{
|
||||
int rc = -1;
|
||||
- struct berval **in_vals = NULL;
|
||||
struct berval **out_vals = NULL;
|
||||
struct mr_private *mrpriv = NULL;
|
||||
- Slapi_Value **in_vals_sv = NULL;
|
||||
Slapi_Value **out_vals_sv = NULL;
|
||||
|
||||
- slapi_pblock_get(pb, SLAPI_PLUGIN_MR_VALUES, &in_vals); /* get bervals */
|
||||
- /* convert bervals to sv ary */
|
||||
- valuearray_init_bervalarray(in_vals, &in_vals_sv);
|
||||
- slapi_pblock_set(pb, SLAPI_PLUGIN_MR_VALUES, in_vals_sv); /* use sv */
|
||||
rc = mr_wrap_mr_index_sv_fn(pb);
|
||||
- /* clean up in_vals_sv */
|
||||
- valuearray_free(&in_vals_sv);
|
||||
- /* restore old in_vals */
|
||||
- slapi_pblock_set(pb, SLAPI_PLUGIN_MR_VALUES, in_vals);
|
||||
/* get result sv keys */
|
||||
slapi_pblock_get(pb, SLAPI_PLUGIN_MR_KEYS, &out_vals_sv);
|
||||
/* convert to bvec */
|
||||
diff --git a/src/lib389/lib389/backend.py b/src/lib389/lib389/backend.py
|
||||
index 9acced205..cee073ea7 100644
|
||||
--- a/src/lib389/lib389/backend.py
|
||||
+++ b/src/lib389/lib389/backend.py
|
||||
@@ -1029,6 +1029,16 @@ class Backends(DSLdapObjects):
|
||||
for be in sorted(self.list(), key=lambda be: len(be.get_suffix()), reverse=True):
|
||||
be.delete()
|
||||
|
||||
+ def get_backend(self, suffix):
|
||||
+ """
|
||||
+ Return the backend associated with the provided suffix.
|
||||
+ """
|
||||
+ suffix_l = suffix.lower()
|
||||
+ for be in self.list():
|
||||
+ if be.get_attr_val_utf8_l('nsslapd-suffix') == suffix_l:
|
||||
+ return be
|
||||
+ return None
|
||||
+
|
||||
|
||||
class DatabaseConfig(DSLdapObject):
|
||||
"""Backend Database configuration
|
||||
--
|
||||
2.48.1
|
||||
|
||||
@ -1,230 +0,0 @@
|
||||
From bd2829d04491556c35a0b36b591c09a69baf6546 Mon Sep 17 00:00:00 2001
|
||||
From: progier389 <progier@redhat.com>
|
||||
Date: Mon, 11 Dec 2023 11:58:40 +0100
|
||||
Subject: [PATCH] Issue 6004 - idletimeout may be ignored (#6005)
|
||||
|
||||
* Issue 6004 - idletimeout may be ignored
|
||||
|
||||
Problem: idletimeout is still not handled when binding as non root (unless there are some activity
|
||||
on another connection)
|
||||
Fix:
|
||||
Add a slapi_eq_repeat_rel handler that walks all active connection every seconds and check if the timeout is expired.
|
||||
Note about CI test:
|
||||
Notice that idletimeout is never enforced for connections bound as root (i.e cn=directory manager).
|
||||
|
||||
Issue #6004
|
||||
|
||||
Reviewed by: @droideck, @tbordaz (Thanks!)
|
||||
|
||||
(cherry picked from commit 86b5969acbe124eec8c89bcf1ab2156b2b140c17)
|
||||
(cherry picked from commit bdb0a72b4953678e5418406b3c202dfa2c7469a2)
|
||||
(cherry picked from commit 61cebc191cd4090072dda691b9956dbde4cf7c48)
|
||||
---
|
||||
.../tests/suites/config/regression_test.py | 82 ++++++++++++++++++-
|
||||
ldap/servers/slapd/daemon.c | 52 +++++++++++-
|
||||
2 files changed, 128 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/dirsrvtests/tests/suites/config/regression_test.py b/dirsrvtests/tests/suites/config/regression_test.py
|
||||
index 0000dd82d..8dbba8cd2 100644
|
||||
--- a/dirsrvtests/tests/suites/config/regression_test.py
|
||||
+++ b/dirsrvtests/tests/suites/config/regression_test.py
|
||||
@@ -6,20 +6,49 @@
|
||||
# See LICENSE for details.
|
||||
# --- END COPYRIGHT BLOCK ---
|
||||
#
|
||||
+import os
|
||||
import logging
|
||||
import pytest
|
||||
+import time
|
||||
from lib389.utils import *
|
||||
from lib389.dseldif import DSEldif
|
||||
-from lib389.config import LDBMConfig
|
||||
+from lib389.config import BDB_LDBMConfig, LDBMConfig, Config
|
||||
from lib389.backend import Backends
|
||||
from lib389.topologies import topology_st as topo
|
||||
+from lib389.idm.user import UserAccounts, TEST_USER_PROPERTIES
|
||||
+from lib389._constants import DEFAULT_SUFFIX, PASSWORD, DN_DM
|
||||
|
||||
pytestmark = pytest.mark.tier0
|
||||
|
||||
logging.getLogger(__name__).setLevel(logging.INFO)
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
+DEBUGGING = os.getenv("DEBUGGING", default=False)
|
||||
CUSTOM_MEM = '9100100100'
|
||||
+IDLETIMEOUT = 5
|
||||
+DN_TEST_USER = f'uid={TEST_USER_PROPERTIES["uid"]},ou=People,{DEFAULT_SUFFIX}'
|
||||
+
|
||||
+
|
||||
+@pytest.fixture(scope="module")
|
||||
+def idletimeout_topo(topo, request):
|
||||
+ """Create an instance with a test user and set idletimeout"""
|
||||
+ inst = topo.standalone
|
||||
+ config = Config(inst)
|
||||
+
|
||||
+ users = UserAccounts(inst, DEFAULT_SUFFIX)
|
||||
+ user = users.create(properties={
|
||||
+ **TEST_USER_PROPERTIES,
|
||||
+ 'userpassword' : PASSWORD,
|
||||
+ })
|
||||
+ config.replace('nsslapd-idletimeout', str(IDLETIMEOUT))
|
||||
+
|
||||
+ def fin():
|
||||
+ if not DEBUGGING:
|
||||
+ config.reset('nsslapd-idletimeout')
|
||||
+ user.delete()
|
||||
+
|
||||
+ request.addfinalizer(fin)
|
||||
+ return topo
|
||||
|
||||
|
||||
# Function to return value of available memory in kb
|
||||
@@ -79,7 +108,7 @@ def test_maxbersize_repl(topo):
|
||||
nsslapd-errorlog-logmaxdiskspace are set in certain order
|
||||
|
||||
:id: 743e912c-2be4-4f5f-9c2a-93dcb18f51a0
|
||||
- :setup: MMR with two suppliers
|
||||
+ :setup: Standalone Instance
|
||||
:steps:
|
||||
1. Stop the instance
|
||||
2. Set nsslapd-errorlog-maxlogsize before/after
|
||||
@@ -112,3 +141,52 @@ def test_maxbersize_repl(topo):
|
||||
log.info("Assert no init_dse_file errors in the error log")
|
||||
assert not inst.ds_error_log.match('.*ERR - init_dse_file.*')
|
||||
|
||||
+
|
||||
+def test_bdb_config(topo):
|
||||
+ """Check that bdb config entry exists
|
||||
+
|
||||
+ :id: edbc6f54-7c98-11ee-b1c0-482ae39447e5
|
||||
+ :setup: standalone
|
||||
+ :steps:
|
||||
+ 1. Check that bdb config instance exists.
|
||||
+ :expectedresults:
|
||||
+ 1. Success
|
||||
+ """
|
||||
+
|
||||
+ inst = topo.standalone
|
||||
+ assert BDB_LDBMConfig(inst).exists()
|
||||
+
|
||||
+
|
||||
+@pytest.mark.parametrize("dn,expected_result", [(DN_TEST_USER, True), (DN_DM, False)])
|
||||
+def test_idletimeout(idletimeout_topo, dn, expected_result):
|
||||
+ """Check that bdb config entry exists
|
||||
+
|
||||
+ :id: b20f2826-942a-11ee-827b-482ae39447e5
|
||||
+ :parametrized: yes
|
||||
+ :setup: Standalone Instance with test user and idletimeout
|
||||
+ :steps:
|
||||
+ 1. Open new ldap connection
|
||||
+ 2. Bind with the provided dn
|
||||
+ 3. Wait longer than idletimeout
|
||||
+ 4. Try to bind again the provided dn and check if
|
||||
+ connection is closed or not.
|
||||
+ 5. Check if result is the expected one.
|
||||
+ :expectedresults:
|
||||
+ 1. Success
|
||||
+ 2. Success
|
||||
+ 3. Success
|
||||
+ 4. Success
|
||||
+ 5. Success
|
||||
+ """
|
||||
+
|
||||
+ inst = idletimeout_topo.standalone
|
||||
+
|
||||
+ l = ldap.initialize(f'ldap://localhost:{inst.port}')
|
||||
+ l.bind_s(dn, PASSWORD)
|
||||
+ time.sleep(IDLETIMEOUT+1)
|
||||
+ try:
|
||||
+ l.bind_s(dn, PASSWORD)
|
||||
+ result = False
|
||||
+ except ldap.SERVER_DOWN:
|
||||
+ result = True
|
||||
+ assert expected_result == result
|
||||
diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
|
||||
index 57e07e5f5..6df109760 100644
|
||||
--- a/ldap/servers/slapd/daemon.c
|
||||
+++ b/ldap/servers/slapd/daemon.c
|
||||
@@ -68,6 +68,8 @@
|
||||
#define SLAPD_ACCEPT_WAKEUP_TIMER 250
|
||||
#endif
|
||||
|
||||
+#define MILLISECONDS_PER_SECOND 1000
|
||||
+
|
||||
int slapd_wakeup_timer = SLAPD_WAKEUP_TIMER; /* time in ms to wakeup */
|
||||
int slapd_accept_wakeup_timer = SLAPD_ACCEPT_WAKEUP_TIMER; /* time in ms to wakeup */
|
||||
#ifdef notdef /* GGOODREPL */
|
||||
@@ -1045,6 +1047,48 @@ slapd_sockets_ports_free(daemon_ports_t *ports_info)
|
||||
#endif
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Tells if idle timeout has expired
|
||||
+ */
|
||||
+static inline int __attribute__((always_inline))
|
||||
+has_idletimeout_expired(Connection *c, time_t curtime)
|
||||
+{
|
||||
+ return (c->c_state != CONN_STATE_FREE && !c->c_gettingber &&
|
||||
+ c->c_idletimeout > 0 && NULL == c->c_ops &&
|
||||
+ curtime - c->c_idlesince >= c->c_idletimeout);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * slapi_eq_repeat_rel callback that checks that idletimeout has not expired.
|
||||
+ */
|
||||
+void
|
||||
+check_idletimeout(time_t when __attribute__((unused)), void *arg __attribute__((unused)) )
|
||||
+{
|
||||
+ Connection_Table *ct = the_connection_table;
|
||||
+ time_t curtime = slapi_current_rel_time_t();
|
||||
+ /* Walk all active connections of all connection listeners */
|
||||
+ for (int list_num = 0; list_num < ct->list_num; list_num++) {
|
||||
+ for (Connection *c = connection_table_get_first_active_connection(ct, list_num);
|
||||
+ c != NULL; c = connection_table_get_next_active_connection(ct, c)) {
|
||||
+ if (!has_idletimeout_expired(c, curtime)) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ /* Looks like idletimeout has expired, lets acquire the lock
|
||||
+ * and double check.
|
||||
+ */
|
||||
+ if (pthread_mutex_trylock(&(c->c_mutex)) == EBUSY) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ if (has_idletimeout_expired(c, curtime)) {
|
||||
+ /* idle timeout has expired */
|
||||
+ disconnect_server_nomutex(c, c->c_connid, -1,
|
||||
+ SLAPD_DISCONNECT_IDLE_TIMEOUT, ETIMEDOUT);
|
||||
+ }
|
||||
+ pthread_mutex_unlock(&(c->c_mutex));
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void
|
||||
slapd_daemon(daemon_ports_t *ports)
|
||||
{
|
||||
@@ -1258,7 +1302,9 @@ slapd_daemon(daemon_ports_t *ports)
|
||||
"MAINPID=%lu",
|
||||
(unsigned long)getpid());
|
||||
#endif
|
||||
-
|
||||
+ slapi_eq_repeat_rel(check_idletimeout, NULL,
|
||||
+ slapi_current_rel_time_t(),
|
||||
+ MILLISECONDS_PER_SECOND);
|
||||
/* The meat of the operation is in a loop on a call to select */
|
||||
while (!g_get_shutdown()) {
|
||||
int select_return = 0;
|
||||
@@ -1734,9 +1780,7 @@ handle_pr_read_ready(Connection_Table *ct, PRIntn num_poll __attribute__((unused
|
||||
disconnect_server_nomutex(c, c->c_connid, -1,
|
||||
SLAPD_DISCONNECT_POLL, EPIPE);
|
||||
}
|
||||
- } else if (c->c_idletimeout > 0 &&
|
||||
- (curtime - c->c_idlesince) >= c->c_idletimeout &&
|
||||
- NULL == c->c_ops) {
|
||||
+ } else if (has_idletimeout_expired(c, curtime)) {
|
||||
/* idle timeout */
|
||||
disconnect_server_nomutex(c, c->c_connid, -1,
|
||||
SLAPD_DISCONNECT_IDLE_TIMEOUT, ETIMEDOUT);
|
||||
--
|
||||
2.48.1
|
||||
|
||||
@ -1,69 +0,0 @@
|
||||
From e9fe6e074130406328b8e932a5c2efa814d190a0 Mon Sep 17 00:00:00 2001
|
||||
From: tbordaz <tbordaz@redhat.com>
|
||||
Date: Wed, 5 Feb 2025 09:41:30 +0100
|
||||
Subject: [PATCH] Issue 6004 - (2nd) idletimeout may be ignored (#6569)
|
||||
|
||||
Problem:
|
||||
multiple listener threads was implemented in 2.x and after
|
||||
This is missing in 1.4.3 so the cherry pick should be adapted
|
||||
Fix:
|
||||
skip the loop with listeners
|
||||
|
||||
Issue #6004
|
||||
|
||||
Reviewed by: Jamie Chapman (Thanks !)
|
||||
---
|
||||
ldap/servers/slapd/daemon.c | 36 +++++++++++++++++-------------------
|
||||
1 file changed, 17 insertions(+), 19 deletions(-)
|
||||
|
||||
diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
|
||||
index 6df109760..bef75e4a3 100644
|
||||
--- a/ldap/servers/slapd/daemon.c
|
||||
+++ b/ldap/servers/slapd/daemon.c
|
||||
@@ -1066,26 +1066,24 @@ check_idletimeout(time_t when __attribute__((unused)), void *arg __attribute__((
|
||||
{
|
||||
Connection_Table *ct = the_connection_table;
|
||||
time_t curtime = slapi_current_rel_time_t();
|
||||
- /* Walk all active connections of all connection listeners */
|
||||
- for (int list_num = 0; list_num < ct->list_num; list_num++) {
|
||||
- for (Connection *c = connection_table_get_first_active_connection(ct, list_num);
|
||||
- c != NULL; c = connection_table_get_next_active_connection(ct, c)) {
|
||||
- if (!has_idletimeout_expired(c, curtime)) {
|
||||
- continue;
|
||||
- }
|
||||
- /* Looks like idletimeout has expired, lets acquire the lock
|
||||
- * and double check.
|
||||
- */
|
||||
- if (pthread_mutex_trylock(&(c->c_mutex)) == EBUSY) {
|
||||
- continue;
|
||||
- }
|
||||
- if (has_idletimeout_expired(c, curtime)) {
|
||||
- /* idle timeout has expired */
|
||||
- disconnect_server_nomutex(c, c->c_connid, -1,
|
||||
- SLAPD_DISCONNECT_IDLE_TIMEOUT, ETIMEDOUT);
|
||||
- }
|
||||
- pthread_mutex_unlock(&(c->c_mutex));
|
||||
+ /* Walk all active connections */
|
||||
+ for (Connection *c = connection_table_get_first_active_connection(ct);
|
||||
+ c != NULL; c = connection_table_get_next_active_connection(ct, c)) {
|
||||
+ if (!has_idletimeout_expired(c, curtime)) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ /* Looks like idletimeout has expired, lets acquire the lock
|
||||
+ * and double check.
|
||||
+ */
|
||||
+ if (pthread_mutex_trylock(&(c->c_mutex)) == EBUSY) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ if (has_idletimeout_expired(c, curtime)) {
|
||||
+ /* idle timeout has expired */
|
||||
+ disconnect_server_nomutex(c, c->c_connid, -1,
|
||||
+ SLAPD_DISCONNECT_IDLE_TIMEOUT, ETIMEDOUT);
|
||||
}
|
||||
+ pthread_mutex_unlock(&(c->c_mutex));
|
||||
}
|
||||
}
|
||||
|
||||
--
|
||||
2.48.1
|
||||
|
||||
@ -1,52 +0,0 @@
|
||||
From b2edc371c5ca4fd24ef469c64829c48824098e7f Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
Date: Wed, 8 Jan 2025 12:57:52 -0500
|
||||
Subject: [PATCH] Issue 6485 - Fix double free in USN cleanup task
|
||||
|
||||
Description:
|
||||
|
||||
ASAN report shows double free of bind dn in the USN cleanup task data. The bind
|
||||
dn was passed as a reference so it should never have to be freed by the cleanup
|
||||
task.
|
||||
|
||||
Relates: https://github.com/389ds/389-ds-base/issues/6485
|
||||
|
||||
Reviewed by: tbordaz(Thanks!)
|
||||
---
|
||||
ldap/servers/plugins/usn/usn_cleanup.c | 6 ++----
|
||||
1 file changed, 2 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/ldap/servers/plugins/usn/usn_cleanup.c b/ldap/servers/plugins/usn/usn_cleanup.c
|
||||
index bdb55e6b1..7eaf0f88f 100644
|
||||
--- a/ldap/servers/plugins/usn/usn_cleanup.c
|
||||
+++ b/ldap/servers/plugins/usn/usn_cleanup.c
|
||||
@@ -240,7 +240,7 @@ usn_cleanup_add(Slapi_PBlock *pb,
|
||||
char *suffix = NULL;
|
||||
char *backend = NULL;
|
||||
char *maxusn = NULL;
|
||||
- char *bind_dn;
|
||||
+ char *bind_dn = NULL;
|
||||
struct usn_cleanup_data *cleanup_data = NULL;
|
||||
int rv = SLAPI_DSE_CALLBACK_OK;
|
||||
Slapi_Task *task = NULL;
|
||||
@@ -323,8 +323,7 @@ usn_cleanup_add(Slapi_PBlock *pb,
|
||||
suffix = NULL; /* don't free in this function */
|
||||
cleanup_data->maxusn_to_delete = maxusn;
|
||||
maxusn = NULL; /* don't free in this function */
|
||||
- cleanup_data->bind_dn = bind_dn;
|
||||
- bind_dn = NULL; /* don't free in this function */
|
||||
+ cleanup_data->bind_dn = slapi_ch_strdup(bind_dn);
|
||||
slapi_task_set_data(task, cleanup_data);
|
||||
|
||||
/* start the USN tombstone cleanup task as a separate thread */
|
||||
@@ -363,7 +362,6 @@ usn_cleanup_task_destructor(Slapi_Task *task)
|
||||
slapi_ch_free_string(&mydata->suffix);
|
||||
slapi_ch_free_string(&mydata->maxusn_to_delete);
|
||||
slapi_ch_free_string(&mydata->bind_dn);
|
||||
- /* Need to cast to avoid a compiler warning */
|
||||
slapi_ch_free((void **)&mydata);
|
||||
}
|
||||
}
|
||||
--
|
||||
2.48.1
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user