From ed98564350b82d31d857880277fe63df0851fc15 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Mar 16 2021 10:29:57 +0000 Subject: import 389-ds-base-1.3.10.2-10.el7_9 --- diff --git a/SOURCES/0016-Issue-4521-DS-crash-in-deref-plugin-if-dereferenced-.patch b/SOURCES/0016-Issue-4521-DS-crash-in-deref-plugin-if-dereferenced-.patch new file mode 100644 index 0000000..64608a7 --- /dev/null +++ b/SOURCES/0016-Issue-4521-DS-crash-in-deref-plugin-if-dereferenced-.patch @@ -0,0 +1,55 @@ +From ffeb863e47ab35cbb2e5666847561451d0394ed9 Mon Sep 17 00:00:00 2001 +From: tbordaz +Date: Mon, 11 Jan 2021 17:33:06 +0100 +Subject: [PATCH] Issue 4521 - DS crash in deref plugin if dereferenced entry + exists but is not returned by internal search (#4525) + +Bug description: + For each returned entry, deref plugin dereferences some attribute values that refer to entries. + To do this it does an internal search (scope base) with each attribute values. + Deref plugin assumes that if internal search succeeds, a single entry is returned. + It exists cases (not identified) where internal search succeeds but returns no entry. + In such case (search succeeds but no entry returned) the server crash. + Note: wonder if DB deadlock could lead to such situation. + +Fix description: + Make a hardening fix that logs warning in such case + +relates: https://github.com/389ds/389-ds-base/issues/4521 + +Reviewed by: Mark Reynolds (thanks) + +Platforms tested: F31 +--- + ldap/servers/plugins/deref/deref.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/ldap/servers/plugins/deref/deref.c b/ldap/servers/plugins/deref/deref.c +index ec1884ba3..fc1c10f71 100644 +--- a/ldap/servers/plugins/deref/deref.c ++++ b/ldap/servers/plugins/deref/deref.c +@@ -592,6 +592,21 @@ deref_do_deref_attr(Slapi_PBlock *pb, BerElement *ctrlber, const char *derefdn, + slapi_log_err(SLAPI_LOG_PLUGIN, DEREF_PLUGIN_SUBSYSTEM, + "deref_do_deref_attr - More than one entry matching DN [%s]\n", + derefdn); ++ } else if (entries[0] == NULL) { ++ int32_t op_id; ++ uint64_t conn_id; ++ ++ slapi_pblock_get(pb, SLAPI_OPERATION_ID, &op_id); ++ slapi_pblock_get(pb, SLAPI_CONN_ID, &conn_id); ++ /* Weird case not clearly understood: ++ * the entry 'derefdn' exists (else we would have NOT_SUCH_ENTRY in 'rc') ++ * but it is not returned by the internal search. Note that internal search ++ * returns tombstone or subentry. ++ * Just to prevent a crash, catch this error condition and log a warning ++ */ ++ slapi_log_err(SLAPI_LOG_WARNING, DEREF_PLUGIN_SUBSYSTEM, ++ "deref_do_deref_attr - conn=%" PRIu64 " op=%d - failed to retrieve the entry [%s], although the entry exists\n", ++ conn_id, op_id, derefdn); + } else { + int ii; + int needattrvals = 1; /* need attrvals sequence? */ +-- +2.26.2 + diff --git a/SOURCES/0017-Issue-4492-Changelog-cache-can-upload-updates-from-a.patch b/SOURCES/0017-Issue-4492-Changelog-cache-can-upload-updates-from-a.patch new file mode 100644 index 0000000..2462641 --- /dev/null +++ b/SOURCES/0017-Issue-4492-Changelog-cache-can-upload-updates-from-a.patch @@ -0,0 +1,206 @@ +From f22fe3da910889ab2530d84b647b5b36b6e7e95f Mon Sep 17 00:00:00 2001 +From: tbordaz +Date: Mon, 14 Dec 2020 10:02:24 +0100 +Subject: [PATCH] Issue 4492 - Changelog cache can upload updates from a wrong + starting point (CSN) (#4493) + +Bug description: + When a replication session starts, a starting point is computed + according to supplier/consumer RUVs. + from the starting point the updates are bulk loaded from the CL. + When a bulk set have been fully evaluated the server needs to bulk load another set. + It iterates until there is no more updates to send. + The bug is that during bulk load, it recomputes the CL cursor position + and this computation can be wrong. For example if a new update on + a rarely updated replica (or not known replica) the new position will + be set before the inital starting point + +Fix description: + Fixing the invalid computation is a bit risky (complex code resulting from + years of corner cases handling) and a fix could fail to address others flavor + with the same symptom + The fix is only (sorry for that) safety checking fix that would end a replication session + if the computed cursor position goes before the initial starting point. + In case of large jump behind (24h) the starting point, a warning is logged. + +relates: https://github.com/389ds/389-ds-base/issues/4492 + +Reviewed by: Mark Reynolds, William Brown + +Platforms tested: F31 +--- + ldap/servers/plugins/replication/cl5_api.c | 6 +- + .../servers/plugins/replication/cl5_clcache.c | 60 ++++++++++++++++++- + .../servers/plugins/replication/cl5_clcache.h | 4 +- + 3 files changed, 63 insertions(+), 7 deletions(-) + +diff --git a/ldap/servers/plugins/replication/cl5_api.c b/ldap/servers/plugins/replication/cl5_api.c +index 65801bc01..1d6e20b07 100644 +--- a/ldap/servers/plugins/replication/cl5_api.c ++++ b/ldap/servers/plugins/replication/cl5_api.c +@@ -143,6 +143,7 @@ struct cl5replayiterator + ReplicaId consumerRID; /* consumer's RID */ + const RUV *consumerRuv; /* consumer's update vector */ + Object *supplierRuvObj; /* supplier's update vector object */ ++ char starting_csn[CSN_STRSIZE]; + }; + + typedef struct cl5iterator +@@ -1542,7 +1543,7 @@ cl5GetNextOperationToReplay(CL5ReplayIterator *iterator, CL5Entry *entry) + return CL5_BAD_DATA; + } + +- rc = clcache_get_next_change(iterator->clcache, (void **)&key, &keylen, (void **)&data, &datalen, &csn); ++ rc = clcache_get_next_change(iterator->clcache, (void **)&key, &keylen, (void **)&data, &datalen, &csn, iterator->starting_csn); + + if (rc == DB_NOTFOUND) { + /* +@@ -5256,7 +5257,7 @@ _cl5PositionCursorForReplay(ReplicaId consumerRID, const RUV *consumerRuv, Objec + if (rc != 0) + goto done; + +- rc = clcache_load_buffer(clcache, &startCSN, continue_on_missing); ++ rc = clcache_load_buffer(clcache, &startCSN, continue_on_missing, NULL /* retrieving startCSN, no limit enforced on this call */); + + if (rc == 0) { + haveChanges = PR_TRUE; +@@ -5320,6 +5321,7 @@ _cl5PositionCursorForReplay(ReplicaId consumerRID, const RUV *consumerRuv, Objec + (*iterator)->consumerRID = consumerRID; + (*iterator)->consumerRuv = consumerRuv; + (*iterator)->supplierRuvObj = supplierRuvObj; ++ csn_as_string(startCSN, PR_FALSE, (*iterator)->starting_csn); + } else if (rc == CL5_SUCCESS) { + /* we have no changes to send */ + rc = CL5_NOTFOUND; +diff --git a/ldap/servers/plugins/replication/cl5_clcache.c b/ldap/servers/plugins/replication/cl5_clcache.c +index a8477a83a..43b7c77d8 100644 +--- a/ldap/servers/plugins/replication/cl5_clcache.c ++++ b/ldap/servers/plugins/replication/cl5_clcache.c +@@ -15,6 +15,8 @@ + #include "db.h" /* Berkeley DB */ + #include "cl5.h" /* changelog5Config */ + #include "cl5_clcache.h" ++#include "slap.h" ++#include "proto-slap.h" + + /* newer bdb uses DB_BUFFER_SMALL instead of ENOMEM as the + error return if the given buffer in which to load a +@@ -323,14 +325,21 @@ clcache_return_buffer(CLC_Buffer **buf) + * anchorcsn - passed in for the first load of a replication session; + * flag - DB_SET to load in the key CSN record. + * DB_NEXT to load in the records greater than key CSN. ++ * initial_starting_csn ++ * This is the starting_csn computed at the beginning of ++ * the replication session. It never change during a session ++ * (aka iterator creation). ++ * This is used for safety checking that the next CSN use ++ * for bulk load is not before the initial csn + * return - DB error code instead of cl5 one because of the + * historic reason. + */ + int +-clcache_load_buffer(CLC_Buffer *buf, CSN **anchorCSN, int *continue_on_miss) ++clcache_load_buffer(CLC_Buffer *buf, CSN **anchorCSN, int *continue_on_miss, char *initial_starting_csn) + { + int rc = 0; + int flag = DB_NEXT; ++ CSN limit_csn = {0}; + + if (anchorCSN) + *anchorCSN = NULL; +@@ -343,6 +352,30 @@ clcache_load_buffer(CLC_Buffer *buf, CSN **anchorCSN, int *continue_on_miss) + rc = clcache_adjust_anchorcsn(buf, &flag); + } + ++ /* safety checking, we do not want to (re)start replication before ++ * the inital computed starting point ++ */ ++ if (initial_starting_csn) { ++ csn_init_by_string(&limit_csn, initial_starting_csn); ++ if (csn_compare(&limit_csn, buf->buf_current_csn) > 0) { ++ char curr[CSN_STRSIZE]; ++ int loglevel = SLAPI_LOG_REPL; ++ ++ if (csn_time_difference(&limit_csn, buf->buf_current_csn) > (24 * 60 * 60)) { ++ /* This is a big jump (more than a day) behind the ++ * initial starting csn. Log a warning before ending ++ * the session ++ */ ++ loglevel = SLAPI_LOG_WARNING; ++ } ++ csn_as_string(buf->buf_current_csn, 0, curr); ++ slapi_log_err(loglevel, buf->buf_agmt_name, ++ "clcache_load_buffer - bulk load cursor (%s) is lower than starting csn %s. Ending session.\n", curr, initial_starting_csn); ++ /* it just end the session with UPDATE_NO_MORE_UPDATES */ ++ rc = CLC_STATE_DONE; ++ } ++ } ++ + if (rc == 0) { + + buf->buf_state = CLC_STATE_READY; +@@ -365,6 +398,27 @@ clcache_load_buffer(CLC_Buffer *buf, CSN **anchorCSN, int *continue_on_miss) + } + /* the use of alternative start csns can be limited, record its usage */ + (*continue_on_miss)--; ++ ++ if (initial_starting_csn) { ++ if (csn_compare(&limit_csn, buf->buf_current_csn) > 0) { ++ char curr[CSN_STRSIZE]; ++ int loglevel = SLAPI_LOG_REPL; ++ ++ if (csn_time_difference(&limit_csn, buf->buf_current_csn) > (24 * 60 * 60)) { ++ /* This is a big jump (more than a day) behind the ++ * initial starting csn. Log a warning before ending ++ * the session ++ */ ++ loglevel = SLAPI_LOG_WARNING; ++ } ++ csn_as_string(buf->buf_current_csn, 0, curr); ++ slapi_log_err(loglevel, buf->buf_agmt_name, ++ "clcache_load_buffer - (DB_SET_RANGE) bulk load cursor (%s) is lower than starting csn %s. Ending session.\n", curr, initial_starting_csn); ++ rc = DB_NOTFOUND; ++ ++ return rc; ++ } ++ } + } + /* Reset some flag variables */ + if (rc == 0) { +@@ -492,7 +546,7 @@ retry: + * *data: output - data of the next change, or NULL if no more change + */ + int +-clcache_get_next_change(CLC_Buffer *buf, void **key, size_t *keylen, void **data, size_t *datalen, CSN **csn) ++clcache_get_next_change(CLC_Buffer *buf, void **key, size_t *keylen, void **data, size_t *datalen, CSN **csn, char *initial_starting_csn) + { + int skip = 1; + int rc = 0; +@@ -510,7 +564,7 @@ clcache_get_next_change(CLC_Buffer *buf, void **key, size_t *keylen, void **data + * We're done with the current buffer. Now load the next chunk. + */ + if (NULL == *key && CLC_STATE_READY == buf->buf_state) { +- rc = clcache_load_buffer(buf, NULL, NULL); ++ rc = clcache_load_buffer(buf, NULL, NULL, initial_starting_csn); + if (0 == rc && buf->buf_record_ptr) { + DB_MULTIPLE_KEY_NEXT(buf->buf_record_ptr, &buf->buf_data, + *key, *keylen, *data, *datalen); +diff --git a/ldap/servers/plugins/replication/cl5_clcache.h b/ldap/servers/plugins/replication/cl5_clcache.h +index 73eb41590..16d53d563 100644 +--- a/ldap/servers/plugins/replication/cl5_clcache.h ++++ b/ldap/servers/plugins/replication/cl5_clcache.h +@@ -23,9 +23,9 @@ typedef struct clc_buffer CLC_Buffer; + int clcache_init(DB_ENV **dbenv); + void clcache_set_config(void); + int clcache_get_buffer(CLC_Buffer **buf, DB *db, ReplicaId consumer_rid, const RUV *consumer_ruv, const RUV *local_ruv); +-int clcache_load_buffer(CLC_Buffer *buf, CSN **anchorCSN, int *continue_on_miss); ++int clcache_load_buffer(CLC_Buffer *buf, CSN **anchorCSN, int *continue_on_miss, char *initial_starting_csn); + void clcache_return_buffer(CLC_Buffer **buf); +-int clcache_get_next_change(CLC_Buffer *buf, void **key, size_t *keylen, void **data, size_t *datalen, CSN **csn); ++int clcache_get_next_change(CLC_Buffer *buf, void **key, size_t *keylen, void **data, size_t *datalen, CSN **csn, char *initial_starting_csn); + void clcache_destroy(void); + + #endif +-- +2.26.2 + diff --git a/SOURCES/0018-Issue-5442-Search-results-are-different-between-RHDS.patch b/SOURCES/0018-Issue-5442-Search-results-are-different-between-RHDS.patch new file mode 100644 index 0000000..c67df62 --- /dev/null +++ b/SOURCES/0018-Issue-5442-Search-results-are-different-between-RHDS.patch @@ -0,0 +1,639 @@ +From 21bfb590a53c078d3dfeb982497f049d4627c71d Mon Sep 17 00:00:00 2001 +From: Mark Reynolds +Date: Wed, 20 Jan 2021 16:42:15 -0500 +Subject: [PATCH] Issue 5442 - Search results are different between RHDS10 and + RHDS11 + +Bug Description: In 1.4.x we introduced a change that was overly strict about + how a search on a non-existent subtree returned its error code. + It was changed from returning an error 32 to an error 0 with + zero entries returned. + +Fix Description: When finding the entry and processing acl's make sure to + gather the aci's that match the resource even if the resource + does not exist. This requires some extra checks when processing + the target attribute. + +relates: https://github.com/389ds/389-ds-base/issues/4542 + +Reviewed by: firstyear, elkris, and tbordaz (Thanks!) + +Apply Thierry's changes + +round 2 + +Apply more suggestions from Thierry +--- + ldap/servers/plugins/acl/acl.c | 296 ++++++++++------------- + ldap/servers/slapd/back-ldbm/findentry.c | 6 +- + src/lib389/lib389/_mapped_object.py | 1 + + 3 files changed, 134 insertions(+), 169 deletions(-) + +diff --git a/ldap/servers/plugins/acl/acl.c b/ldap/servers/plugins/acl/acl.c +index 6d105f4fa..ecd23aa88 100644 +--- a/ldap/servers/plugins/acl/acl.c ++++ b/ldap/servers/plugins/acl/acl.c +@@ -2109,10 +2109,11 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a + aci_right = aci->aci_access; + res_right = aclpb->aclpb_access; + if (!(aci_right & res_right)) { +- /* If we are looking for read/search and the acl has read/search +- ** then go further because if targets match we may keep that +- ** acl in the entry cache list. +- */ ++ /* ++ * If we are looking for read/search and the acl has read/search ++ * then go further because if targets match we may keep that ++ * acl in the entry cache list. ++ */ + if (!((res_right & (SLAPI_ACL_SEARCH | SLAPI_ACL_READ)) && + (aci_right & (SLAPI_ACL_SEARCH | SLAPI_ACL_READ)))) { + matches = ACL_FALSE; +@@ -2120,30 +2121,29 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a + } + } + +- +- /* first Let's see if the entry is under the subtree where the +- ** ACL resides. We can't let somebody affect a target beyond the +- ** scope of where the ACL resides +- ** Example: ACL is located in "ou=engineering, o=ace industry, c=us +- ** but if the target is "o=ace industry, c=us", then we are in trouble. +- ** +- ** If the aci is in the rootdse and the entry is not, then we do not +- ** match--ie. acis in the rootdse do NOT apply below...for the moment. +- ** +- */ ++ /* ++ * First Let's see if the entry is under the subtree where the ++ * ACL resides. We can't let somebody affect a target beyond the ++ * scope of where the ACL resides ++ * Example: ACL is located in "ou=engineering, o=ace industry, c=us ++ * but if the target is "o=ace industry, c=us", then we are in trouble. ++ * ++ * If the aci is in the rootdse and the entry is not, then we do not ++ * match--ie. acis in the rootdse do NOT apply below...for the moment. ++ */ + res_ndn = slapi_sdn_get_ndn(aclpb->aclpb_curr_entry_sdn); + aci_ndn = slapi_sdn_get_ndn(aci->aci_sdn); +- if (!slapi_sdn_issuffix(aclpb->aclpb_curr_entry_sdn, aci->aci_sdn) || (!slapi_is_rootdse(res_ndn) && slapi_is_rootdse(aci_ndn))) { +- +- /* cant' poke around */ ++ if (!slapi_sdn_issuffix(aclpb->aclpb_curr_entry_sdn, aci->aci_sdn) || ++ (!slapi_is_rootdse(res_ndn) && slapi_is_rootdse(aci_ndn))) ++ { ++ /* can't poke around */ + matches = ACL_FALSE; + goto acl__resource_match_aci_EXIT; + } + + /* +- ** We have a single ACI which we need to find if it applies to +- ** the resource or not. +- */ ++ * We have a single ACI which we need to find if it applies to the resource or not. ++ */ + if ((aci->aci_type & ACI_TARGET_DN) && (aclpb->aclpb_curr_entry_sdn)) { + char *avaType; + struct berval *avaValue; +@@ -2171,25 +2171,23 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a + char *avaType; + struct berval *avaValue; + char logbuf[1024]; +- +- /* We are evaluating the moddn permission. +- * The aci contains target_to and target_from +- * +- * target_to filter must be checked against the resource ndn that was stored in +- * aclpb->aclpb_curr_entry_sdn +- * +- * target_from filter must be check against the entry ndn that is in aclpb->aclpb_moddn_source_sdn +- * (sdn was stored in the pblock) +- */ ++ /* ++ * We are evaluating the moddn permission. ++ * The aci contains target_to and target_from ++ * ++ * target_to filter must be checked against the resource ndn that was stored in ++ * aclpb->aclpb_curr_entry_sdn ++ * ++ * target_from filter must be check against the entry ndn that is in aclpb->aclpb_moddn_source_sdn ++ * (sdn was stored in the pblock) ++ */ + if (aci->target_to) { + f = aci->target_to; + dn_matched = ACL_TRUE; + + /* Now check if the filter is a simple or substring filter */ + if (aci->aci_type & ACI_TARGET_MODDN_TO_PATTERN) { +- /* This is a filter with substring +- * e.g. ldap:///uid=*,cn=accounts,dc=example,dc=com +- */ ++ /* This is a filter with substring e.g. ldap:///uid=*,cn=accounts,dc=example,dc=com */ + slapi_log_err(SLAPI_LOG_ACL, plugin_name, "acl__resource_match_aci - moddn target_to substring: %s\n", + slapi_filter_to_string(f, logbuf, sizeof(logbuf))); + if ((rv = acl_match_substring(f, (char *)res_ndn, 0 /* match suffix */)) != ACL_TRUE) { +@@ -2202,9 +2200,7 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a + } + } + } else { +- /* This is a filter without substring +- * e.g. ldap:///cn=accounts,dc=example,dc=com +- */ ++ /* This is a filter without substring e.g. ldap:///cn=accounts,dc=example,dc=com */ + slapi_log_err(SLAPI_LOG_ACL, plugin_name, "acl__resource_match_aci - moddn target_to: %s\n", + slapi_filter_to_string(f, logbuf, sizeof(logbuf))); + slapi_filter_get_ava(f, &avaType, &avaValue); +@@ -2228,8 +2224,8 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a + /* Now check if the filter is a simple or substring filter */ + if (aci->aci_type & ACI_TARGET_MODDN_FROM_PATTERN) { + /* This is a filter with substring +- * e.g. ldap:///uid=*,cn=accounts,dc=example,dc=com +- */ ++ * e.g. ldap:///uid=*,cn=accounts,dc=example,dc=com ++ */ + slapi_log_err(SLAPI_LOG_ACL, plugin_name, "acl__resource_match_aci - moddn target_from substring: %s\n", + slapi_filter_to_string(f, logbuf, sizeof(logbuf))); + if ((rv = acl_match_substring(f, (char *)slapi_sdn_get_dn(aclpb->aclpb_moddn_source_sdn), 0 /* match suffix */)) != ACL_TRUE) { +@@ -2241,11 +2237,8 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a + goto acl__resource_match_aci_EXIT; + } + } +- + } else { +- /* This is a filter without substring +- * e.g. ldap:///cn=accounts,dc=example,dc=com +- */ ++ /* This is a filter without substring e.g. ldap:///cn=accounts,dc=example,dc=com */ + slapi_log_err(SLAPI_LOG_ACL, plugin_name, "acl__resource_match_aci - moddn target_from: %s\n", + slapi_filter_to_string(f, logbuf, sizeof(logbuf))); + if (!slapi_dn_issuffix(slapi_sdn_get_dn(aclpb->aclpb_moddn_source_sdn), avaValue->bv_val)) { +@@ -2267,10 +2260,8 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a + } + + if (aci->aci_type & ACI_TARGET_PATTERN) { +- + f = aci->target; + dn_matched = ACL_TRUE; +- + if ((rv = acl_match_substring(f, (char *)res_ndn, 0 /* match suffux */)) != ACL_TRUE) { + dn_matched = ACL_FALSE; + if (rv == ACL_ERR) { +@@ -2294,7 +2285,7 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a + + /* + * Is it a (target="ldap://cn=*,($dn),o=sun.com") kind of thing. +- */ ++ */ + if (aci->aci_type & ACI_TARGET_MACRO_DN) { + /* + * See if the ($dn) component matches the string and +@@ -2304,8 +2295,7 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a + * entry is the same one don't recalculate it-- + * this flag only works for search right now, could + * also optimise for mods by making it work for mods. +- */ +- ++ */ + if ((aclpb->aclpb_res_type & ACLPB_NEW_ENTRY) == 0) { + /* + * Here same entry so just look up the matched value, +@@ -2354,8 +2344,7 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a + * If there is already an entry for this aci in this + * aclpb then remove it--it's an old value for a + * different entry. +- */ +- ++ */ + acl_ht_add_and_freeOld(aclpb->aclpb_macro_ht, + (PLHashNumber)aci->aci_index, + matched_val); +@@ -2379,30 +2368,27 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a + } + + /* +- ** Here, if there's a targetfilter field, see if it matches. +- ** +- ** The commented out code below was an erroneous attempt to skip +- ** this test. It is wrong because: 1. you need to store +- ** whether the last test matched or not (you cannot just assume it did) +- ** and 2. It may not be the same aci, so the previous matched +- ** value is a function of the aci. +- ** May be interesting to build such a cache...but no evidence for +- ** for that right now. See Bug 383424. +- ** +- ** +- ** && ((aclpb->aclpb_state & ACLPB_SEARCH_BASED_ON_LIST) || +- ** (aclpb->aclpb_res_type & ACLPB_NEW_ENTRY)) +- */ ++ * Here, if there's a targetfilter field, see if it matches. ++ * ++ * The commented out code below was an erroneous attempt to skip ++ * this test. It is wrong because: 1. you need to store ++ * whether the last test matched or not (you cannot just assume it did) ++ * and 2. It may not be the same aci, so the previous matched ++ * value is a function of the aci. ++ * May be interesting to build such a cache...but no evidence for ++ * for that right now. See Bug 383424. ++ * ++ * ++ * && ((aclpb->aclpb_state & ACLPB_SEARCH_BASED_ON_LIST) || ++ * (aclpb->aclpb_res_type & ACLPB_NEW_ENTRY)) ++ */ + if (aci->aci_type & ACI_TARGET_FILTER) { + int filter_matched = ACL_TRUE; +- + /* + * Check for macros. + * For targetfilter we need to fake the lasinfo structure--it's + * created "naturally" for subjects but not targets. +- */ +- +- ++ */ + if (aci->aci_type & ACI_TARGET_FILTER_MACRO_DN) { + + lasInfo *lasinfo = NULL; +@@ -2417,11 +2403,9 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a + ACL_EVAL_TARGET_FILTER); + slapi_ch_free((void **)&lasinfo); + } else { +- +- + if (slapi_vattr_filter_test(NULL, aclpb->aclpb_curr_entry, + aci->targetFilter, +- 0 /*don't do acess chk*/) != 0) { ++ 0 /*don't do access check*/) != 0) { + filter_matched = ACL_FALSE; + } + } +@@ -2448,7 +2432,7 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a + * Check to see if we need to evaluate any targetattrfilters. + * They look as follows: + * (targetattrfilters="add=sn:(sn=rob) && gn:(gn!=byrne), +- * del=sn:(sn=rob) && gn:(gn=byrne)") ++ * del=sn:(sn=rob) && gn:(gn=byrne)") + * + * For ADD/DELETE: + * If theres's a targetattrfilter then each add/del filter +@@ -2456,29 +2440,25 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a + * by each value of the attribute in the entry. + * + * For MODIFY: +- * If there's a targetattrfilter then the add/del filter ++ * If there's a targetattrfilter then the add/del filter + * must be satisfied by the attribute to be added/deleted. + * (MODIFY acl is evaluated one value at a time). + * + * +- */ +- ++ */ + if (((aclpb->aclpb_access & SLAPI_ACL_ADD) && + (aci->aci_type & ACI_TARGET_ATTR_ADD_FILTERS)) || + ((aclpb->aclpb_access & SLAPI_ACL_DELETE) && +- (aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS))) { +- ++ (aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS))) ++ { + Targetattrfilter **attrFilterArray = NULL; +- + Targetattrfilter *attrFilter = NULL; +- + Slapi_Attr *attr_ptr = NULL; + Slapi_Value *sval; + const struct berval *attrVal; + int k; + int done; + +- + if ((aclpb->aclpb_access & SLAPI_ACL_ADD) && + (aci->aci_type & ACI_TARGET_ATTR_ADD_FILTERS)) { + +@@ -2495,28 +2475,20 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a + + while (attrFilterArray && attrFilterArray[num_attrs] && attr_matched) { + attrFilter = attrFilterArray[num_attrs]; +- + /* +- * If this filter applies to an attribute in the entry, +- * apply it to the entry. +- * Otherwise just ignore it. +- * +- */ +- +- if (slapi_entry_attr_find(aclpb->aclpb_curr_entry, +- attrFilter->attr_str, +- &attr_ptr) == 0) { +- ++ * If this filter applies to an attribute in the entry, ++ * apply it to the entry. ++ * Otherwise just ignore it. ++ * ++ */ ++ if (slapi_entry_attr_find(aclpb->aclpb_curr_entry, attrFilter->attr_str, &attr_ptr) == 0) { + /* +- * This is an applicable filter. +- * The filter is to be appplied to the entry being added +- * or deleted. +- * The filter needs to be satisfied by _each_ occurence +- * of the attribute in the entry--otherwise you +- * could satisfy the filter and then put loads of other +- * values in on the back of it. +- */ +- ++ * This is an applicable filter. ++ * The filter is to be applied to the entry being added or deleted. ++ * The filter needs to be satisfied by _each_ occurrence of the ++ * attribute in the entry--otherwise you could satisfy the filter ++ * and then put loads of other values in on the back of it. ++ */ + sval = NULL; + attrVal = NULL; + k = slapi_attr_first_value(attr_ptr, &sval); +@@ -2526,12 +2498,11 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a + + if (acl__make_filter_test_entry(&aclpb->aclpb_filter_test_entry, + attrFilter->attr_str, +- (struct berval *)attrVal) == LDAP_SUCCESS) { +- ++ (struct berval *)attrVal) == LDAP_SUCCESS) ++ { + attr_matched = acl__test_filter(aclpb->aclpb_filter_test_entry, + attrFilter->filter, +- 1 /* Do filter sense evaluation below */ +- ); ++ 1 /* Do filter sense evaluation below */); + done = !attr_matched; + slapi_entry_free(aclpb->aclpb_filter_test_entry); + } +@@ -2540,19 +2511,19 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a + } /* while */ + + /* +- * Here, we applied an applicable filter to the entry. +- * So if attr_matched is ACL_TRUE then every value +- * of the attribute in the entry satisfied the filter. +- * Otherwise, attr_matched is ACL_FALSE and not every +- * value satisfied the filter, so we will teminate the +- * scan of the filter list. +- */ ++ * Here, we applied an applicable filter to the entry. ++ * So if attr_matched is ACL_TRUE then every value ++ * of the attribute in the entry satisfied the filter. ++ * Otherwise, attr_matched is ACL_FALSE and not every ++ * value satisfied the filter, so we will terminate the ++ * scan of the filter list. ++ */ + } + + num_attrs++; + } /* while */ + +-/* ++ /* + * Here, we've applied all the applicable filters to the entry. + * Each one must have been satisfied by all the values of the attribute. + * The result of this is stored in attr_matched. +@@ -2583,7 +2554,8 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a + } else if (((aclpb->aclpb_access & ACLPB_SLAPI_ACL_WRITE_ADD) && + (aci->aci_type & ACI_TARGET_ATTR_ADD_FILTERS)) || + ((aclpb->aclpb_access & ACLPB_SLAPI_ACL_WRITE_DEL) && +- (aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS))) { ++ (aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS))) ++ { + /* + * Here, it's a modify add/del and we have attr filters. + * So, we need to scan the add/del filter list to find the filter +@@ -2633,11 +2605,10 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a + */ + + if (found) { +- + if (acl__make_filter_test_entry(&aclpb->aclpb_filter_test_entry, + aclpb->aclpb_curr_attrEval->attrEval_name, +- aclpb->aclpb_curr_attrVal) == LDAP_SUCCESS) { +- ++ aclpb->aclpb_curr_attrVal) == LDAP_SUCCESS) ++ { + attr_matched = acl__test_filter(aclpb->aclpb_filter_test_entry, + attrFilter->filter, + 1 /* Do filter sense evaluation below */ +@@ -2655,20 +2626,21 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a + * Here this attribute appeared and was matched in a + * targetattrfilters list, so record this fact so we do + * not have to scan the targetattr list for the attribute. +- */ ++ */ + + attr_matched_in_targetattrfilters = 1; + } + } /* targetvaluefilters */ + + +- /* There are 3 cases by which acis are selected. +- ** 1) By scanning the whole list and picking based on the resource. +- ** 2) By picking a subset of the list which will be used for the whole +- ** acl evaluation. +- ** 3) A finer granularity, i.e, a selected list of acls which will be +- ** used for only that entry's evaluation. +- */ ++ /* ++ * There are 3 cases by which acis are selected. ++ * 1) By scanning the whole list and picking based on the resource. ++ * 2) By picking a subset of the list which will be used for the whole ++ * acl evaluation. ++ * 3) A finer granularity, i.e, a selected list of acls which will be ++ * used for only that entry's evaluation. ++ */ + if (!(skip_attrEval) && (aclpb->aclpb_state & ACLPB_SEARCH_BASED_ON_ENTRY_LIST) && + (res_right & SLAPI_ACL_SEARCH) && + ((aci->aci_access & SLAPI_ACL_READ) || (aci->aci_access & SLAPI_ACL_SEARCH))) { +@@ -2684,7 +2656,6 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a + } + } + +- + /* If we are suppose to skip attr eval, then let's skip it */ + if ((aclpb->aclpb_access & SLAPI_ACL_SEARCH) && (!skip_attrEval) && + (aclpb->aclpb_res_type & ACLPB_NEW_ENTRY)) { +@@ -2701,9 +2672,10 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a + goto acl__resource_match_aci_EXIT; + } + +- /* We need to check again because we don't want to select this handle +- ** if the right doesn't match for now. +- */ ++ /* ++ * We need to check again because we don't want to select this handle ++ * if the right doesn't match for now. ++ */ + if (!(aci_right & res_right)) { + matches = ACL_FALSE; + goto acl__resource_match_aci_EXIT; +@@ -2722,20 +2694,16 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a + * rbyrneXXX if we had a proper permission for modrdn eg SLAPI_ACL_MODRDN + * then we would not need this crappy way of telling it was a MODRDN + * request ie. SLAPI_ACL_WRITE && !(c_attrEval). +- */ +- ++ */ + c_attrEval = aclpb->aclpb_curr_attrEval; + + /* + * If we've already matched on targattrfilter then do not + * bother to look at the attrlist. +- */ +- ++ */ + if (!attr_matched_in_targetattrfilters) { +- + /* match target attr */ +- if ((c_attrEval) && +- (aci->aci_type & ACI_TARGET_ATTR)) { ++ if ((c_attrEval) && (aci->aci_type & ACI_TARGET_ATTR)) { + /* there is a target ATTR */ + Targetattr **attrArray = aci->targetAttr; + Targetattr *attr = NULL; +@@ -2777,46 +2745,43 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a + matches = (attr_matched ? ACL_TRUE : ACL_FALSE); + } + +- + aclpb->aclpb_state &= ~ACLPB_ATTR_STAR_MATCHED; + /* figure out how it matched, i.e star matched */ +- if (matches && star_matched && num_attrs == 1 && +- !(aclpb->aclpb_state & ACLPB_FOUND_ATTR_RULE)) ++ if (matches && star_matched && num_attrs == 1 && !(aclpb->aclpb_state & ACLPB_FOUND_ATTR_RULE)) { + aclpb->aclpb_state |= ACLPB_ATTR_STAR_MATCHED; +- else { ++ } else { + /* we are here means that there is a specific +- ** attr in the rule for this resource. +- ** We need to avoid this case +- ** Rule 1: (targetattr = "uid") +- ** Rule 2: (targetattr = "*") +- ** we cannot use STAR optimization +- */ ++ * attr in the rule for this resource. ++ * We need to avoid this case ++ * Rule 1: (targetattr = "uid") ++ * Rule 2: (targetattr = "*") ++ * we cannot use STAR optimization ++ */ + aclpb->aclpb_state |= ACLPB_FOUND_ATTR_RULE; + aclpb->aclpb_state &= ~ACLPB_ATTR_STAR_MATCHED; + } +- } else if ((c_attrEval) || +- (aci->aci_type & ACI_TARGET_ATTR)) { ++ } else if ((c_attrEval) || (aci->aci_type & ACI_TARGET_ATTR)) { + if ((aci_right & ACL_RIGHTS_TARGETATTR_NOT_NEEDED) && + (aclpb->aclpb_access & ACL_RIGHTS_TARGETATTR_NOT_NEEDED)) { + /* +- ** Targetattr rule doesn't make any sense +- ** in this case. So select this rule +- ** default: matches = ACL_TRUE; +- */ ++ * Targetattr rule doesn't make any sense ++ * in this case. So select this rule ++ * default: matches = ACL_TRUE; ++ */ + ; +- } else if (aci_right & SLAPI_ACL_WRITE && ++ } else if ((aci_right & SLAPI_ACL_WRITE) && + (aci->aci_type & ACI_TARGET_ATTR) && + !(c_attrEval) && + (aci->aci_type & ACI_HAS_ALLOW_RULE)) { + /* We need to handle modrdn operation. Modrdn doesn't +- ** change any attrs but changes the RDN and so (attr=NULL). +- ** Here we found an acl which has a targetattr but +- ** the resource doesn't need one. In that case, we should +- ** consider this acl. +- ** the opposite is true if it is a deny rule, only a deny without +- ** any targetattr should deny modrdn +- ** default: matches = ACL_TRUE; +- */ ++ * change any attrs but changes the RDN and so (attr=NULL). ++ * Here we found an acl which has a targetattr but ++ * the resource doesn't need one. In that case, we should ++ * consider this acl. ++ * the opposite is true if it is a deny rule, only a deny without ++ * any targetattr should deny modrdn ++ * default: matches = ACL_TRUE; ++ */ + ; + } else { + matches = ACL_FALSE; +@@ -2825,16 +2790,16 @@ acl__resource_match_aci(Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a + } /* !attr_matched_in_targetattrfilters */ + + /* +- ** Here we are testing if we find a entry test rule (which should +- ** be rare). In that case, just remember it. An entry test rule +- ** doesn't have "(targetattr)". +- */ ++ * Here we are testing if we find a entry test rule (which should ++ * be rare). In that case, just remember it. An entry test rule ++ * doesn't have "(targetattr)". ++ */ + if ((aclpb->aclpb_state & ACLPB_EVALUATING_FIRST_ATTR) && + (!(aci->aci_type & ACI_TARGET_ATTR))) { + aclpb->aclpb_state |= ACLPB_FOUND_A_ENTRY_TEST_RULE; + } + +-/* ++ /* + * Generic exit point for this routine: + * matches is ACL_TRUE if the aci matches the target of the resource, + * ACL_FALSE othrewise. +@@ -2857,6 +2822,7 @@ acl__resource_match_aci_EXIT: + + return (matches); + } ++ + /* Macro to determine if the cached result is valid or not. */ + #define ACL_CACHED_RESULT_VALID(result) \ + (((result & ACLPB_CACHE_READ_RES_ALLOW) && \ +diff --git a/ldap/servers/slapd/back-ldbm/findentry.c b/ldap/servers/slapd/back-ldbm/findentry.c +index 6e53a0aea..bff751c88 100644 +--- a/ldap/servers/slapd/back-ldbm/findentry.c ++++ b/ldap/servers/slapd/back-ldbm/findentry.c +@@ -93,7 +93,6 @@ find_entry_internal_dn( + size_t tries = 0; + int isroot = 0; + int op_type; +- char *errbuf = NULL; + + /* get the managedsait ldap message control */ + slapi_pblock_get(pb, SLAPI_MANAGEDSAIT, &managedsait); +@@ -207,8 +206,8 @@ find_entry_internal_dn( + break; + } + if (acl_type > 0) { +- err = plugin_call_acl_plugin(pb, me->ep_entry, NULL, NULL, acl_type, +- ACLPLUGIN_ACCESS_DEFAULT, &errbuf); ++ char *dummy_attr = "1.1"; ++ err = slapi_access_allowed(pb, me->ep_entry, dummy_attr, NULL, acl_type); + } + if (((acl_type > 0) && err) || (op_type == SLAPI_OPERATION_BIND)) { + /* +@@ -237,7 +236,6 @@ find_entry_internal_dn( + CACHE_RETURN(&inst->inst_cache, &me); + } + +- slapi_ch_free_string(&errbuf); + slapi_log_err(SLAPI_LOG_TRACE, "find_entry_internal_dn", "<= Not found (%s)\n", + slapi_sdn_get_dn(sdn)); + return (NULL); +diff --git a/src/lib389/lib389/_mapped_object.py b/src/lib389/lib389/_mapped_object.py +index f73cb25f3..ada3f4976 100644 +--- a/src/lib389/lib389/_mapped_object.py ++++ b/src/lib389/lib389/_mapped_object.py +@@ -838,3 +838,4 @@ class DSLdapObjects(DSLogging): + (rdn, properties) = self._validate(rdn, properties) + # Now actually commit the creation req + return co.create(rdn, properties, self._basedn) ++ +-- +2.26.2 + diff --git a/SOURCES/0019-Issue-4644-Large-updates-can-reset-the-CLcache-to-th.patch b/SOURCES/0019-Issue-4644-Large-updates-can-reset-the-CLcache-to-th.patch new file mode 100644 index 0000000..0ad2d5d --- /dev/null +++ b/SOURCES/0019-Issue-4644-Large-updates-can-reset-the-CLcache-to-th.patch @@ -0,0 +1,146 @@ +From 905d243347e13a342ce39491927f158b5337fd43 Mon Sep 17 00:00:00 2001 +From: tbordaz +Date: Tue, 23 Feb 2021 13:42:31 +0100 +Subject: [PATCH] Issue 4644 - Large updates can reset the CLcache to the + beginning of the changelog (#4647) + +Bug description: + The replication agreements are using bulk load to load updates. + For bulk load it uses a cursor with DB_MULTIPLE_KEY and DB_NEXT. + Before using the cursor, it must be initialized with DB_SET. + + If during the cursor/DB_SET the CSN refers to an update that is larger than + the size of the provided buffer, then the cursor remains not initialized and + c_get returns DB_BUFFER_SMALL. + + The consequence is that the next c_get(DB_MULTIPLE_KEY and DB_NEXT) will return the + first record in the changelog DB. This break CLcache. + +Fix description: + The fix is to harden cursor initialization so that if DB_SET fails + because of DB_BUFFER_SMALL. It reallocates buf_data and retries a DB_SET. + If DB_SET can not be initialized it logs a warning. + + The patch also changes the behaviour of the fix #4492. + #4492 detected a massive (1day) jump prior the starting csn and ended the + replication session. If the jump was systematic, for example + if the CLcache got broken because of a too large updates, then + replication was systematically stopped. + This patch suppress the systematically stop, letting RA doing a big jump. + From #4492 only remains the warning. + +relates: https://github.com/389ds/389-ds-base/issues/4644 + +Reviewed by: Pierre Rogier (Thanks !!!!) + +Platforms tested: F31 +--- + .../servers/plugins/replication/cl5_clcache.c | 68 +++++++++++++++---- + 1 file changed, 53 insertions(+), 15 deletions(-) + +diff --git a/ldap/servers/plugins/replication/cl5_clcache.c b/ldap/servers/plugins/replication/cl5_clcache.c +index 43b7c77d8..0b1f48f0c 100644 +--- a/ldap/servers/plugins/replication/cl5_clcache.c ++++ b/ldap/servers/plugins/replication/cl5_clcache.c +@@ -370,9 +370,7 @@ clcache_load_buffer(CLC_Buffer *buf, CSN **anchorCSN, int *continue_on_miss, cha + } + csn_as_string(buf->buf_current_csn, 0, curr); + slapi_log_err(loglevel, buf->buf_agmt_name, +- "clcache_load_buffer - bulk load cursor (%s) is lower than starting csn %s. Ending session.\n", curr, initial_starting_csn); +- /* it just end the session with UPDATE_NO_MORE_UPDATES */ +- rc = CLC_STATE_DONE; ++ "clcache_load_buffer - bulk load cursor (%s) is lower than starting csn %s.\n", curr, initial_starting_csn); + } + } + +@@ -413,10 +411,7 @@ clcache_load_buffer(CLC_Buffer *buf, CSN **anchorCSN, int *continue_on_miss, cha + } + csn_as_string(buf->buf_current_csn, 0, curr); + slapi_log_err(loglevel, buf->buf_agmt_name, +- "clcache_load_buffer - (DB_SET_RANGE) bulk load cursor (%s) is lower than starting csn %s. Ending session.\n", curr, initial_starting_csn); +- rc = DB_NOTFOUND; +- +- return rc; ++ "clcache_load_buffer - (DB_SET_RANGE) bulk load cursor (%s) is lower than starting csn %s.\n", curr, initial_starting_csn); + } + } + } +@@ -444,6 +439,42 @@ clcache_load_buffer(CLC_Buffer *buf, CSN **anchorCSN, int *continue_on_miss, cha + return rc; + } + ++/* Set a cursor to a specific key (buf->buf_key) ++ * In case buf_data is too small to receive the value, DB_SET fails ++ * (DB_BUFFER_SMALL). This let the cursor uninitialized that is ++ * problematic because further cursor DB_NEXT will reset the cursor ++ * to the beginning of the CL. ++ * If buf_data is too small, this function reallocates enough space ++ * ++ * It returns the return code of cursor->c_get ++ */ ++static int ++clcache_cursor_set(DBC *cursor, CLC_Buffer *buf) ++{ ++ int rc; ++ uint32_t ulen; ++ uint32_t dlen; ++ uint32_t size; ++ ++ rc = cursor->c_get(cursor, &buf->buf_key, &buf->buf_data, DB_SET); ++ if (rc == DB_BUFFER_SMALL) { ++ uint32_t ulen; ++ ++ /* Fortunately, buf->buf_data.size has been set by ++ * c_get() to the actual data size needed. So we can ++ * reallocate the data buffer and try to set again. ++ */ ++ ulen = buf->buf_data.ulen; ++ buf->buf_data.ulen = (buf->buf_data.size / DEFAULT_CLC_BUFFER_PAGE_SIZE + 1) * DEFAULT_CLC_BUFFER_PAGE_SIZE; ++ buf->buf_data.data = slapi_ch_realloc(buf->buf_data.data, buf->buf_data.ulen); ++ slapi_log_err(SLAPI_LOG_REPL, buf->buf_agmt_name, ++ "clcache_cursor_set - buf data len reallocated %d -> %d bytes (DB_BUFFER_SMALL)\n", ++ ulen, buf->buf_data.ulen); ++ rc = cursor->c_get(cursor, &buf->buf_key, &buf->buf_data, DB_SET); ++ } ++ return rc; ++} ++ + static int + clcache_load_buffer_bulk(CLC_Buffer *buf, int flag) + { +@@ -478,17 +509,24 @@ retry: + + if (use_flag == DB_NEXT) { + /* For bulk read, position the cursor before read the next block */ +- rc = cursor->c_get(cursor, +- &buf->buf_key, +- &buf->buf_data, +- DB_SET); ++ rc = clcache_cursor_set(cursor, buf); + } + +- /* +- * Continue if the error is no-mem since we don't need to +- * load in the key record anyway with DB_SET. +- */ + if (0 == rc || DB_BUFFER_SMALL == rc) { ++ /* ++ * It should not have failed with DB_BUFFER_SMALL as we tried ++ * to adjust buf_data in clcache_cursor_set. ++ * But if it failed with DB_BUFFER_SMALL, there is a risk in clcache_cursor_get ++ * that the cursor will be reset to the beginning of the changelog. ++ * Returning an error at this point will stop replication that is ++ * a risk. So just accept the risk of a reset to the beginning of the CL ++ * and log an alarming message. ++ */ ++ if (rc == DB_BUFFER_SMALL) { ++ slapi_log_err(SLAPI_LOG_WARNING, buf->buf_agmt_name, ++ "clcache_load_buffer_bulk - Fail to position on csn=%s from the changelog (too large update ?). Risk of full CL evaluation.\n", ++ (char *)buf->buf_key.data); ++ } + rc = clcache_cursor_get(cursor, buf, use_flag); + } + } +-- +2.26.2 + diff --git a/SPECS/389-ds-base.spec b/SPECS/389-ds-base.spec index 17de959..70fb029 100644 --- a/SPECS/389-ds-base.spec +++ b/SPECS/389-ds-base.spec @@ -39,7 +39,7 @@ Summary: 389 Directory Server (%{variant}) Name: 389-ds-base Version: 1.3.10.2 -Release: %{?relprefix}9%{?prerel}%{?dist} +Release: %{?relprefix}10%{?prerel}%{?dist} License: GPLv3+ URL: https://www.port389.org/ Group: System Environment/Daemons @@ -161,6 +161,11 @@ Patch12: 0012-Issue-51166-Log-an-error-when-a-search-is-fully-unin.patc Patch13: 0013-Issue-4297-2nd-fix-for-on-ADD-replication-URP-issue-.patch Patch14: 0014-0002-Issue-4383-Do-not-normalize-escaped-spaces-in-a-DN.patch Patch15: 0015-Issue-4219-fix-crash-around-logging-internal-unindex.patch +Patch16: 0016-Issue-4521-DS-crash-in-deref-plugin-if-dereferenced-.patch +Patch17: 0017-Issue-4492-Changelog-cache-can-upload-updates-from-a.patch +Patch18: 0018-Issue-5442-Search-results-are-different-between-RHDS.patch +Patch19: 0019-Issue-4644-Large-updates-can-reset-the-CLcache-to-th.patch + %description 389 Directory Server is an LDAPv3 compliant server. The base package includes @@ -514,8 +519,14 @@ fi %{_sysconfdir}/%{pkgname}/dirsrvtests %changelog +* Thu Feb 25 2021 Mark Reynolds - 1.3.10.2-10 +- Bump version to 1.3.10.2-10 +- Resolves: Bug 1909342 - DS crash in deref plugin while dereferencing an entry that exists but that is not returned by internal search +- Resolves: Bug 1921856 - “write” permission of ACI changes ns-slapd’s behavior on search operation +- Resolves: Bug 1881968 - Replication Lag under high load + * Thu Jan 7 2021 Mark Reynolds - 1.3.10.2-9 -- Bump version to 1.3.10.2-8 +- Bump version to 1.3.10.2-9 - Resolves: Bug 1905450 - Internal unindexed search crashes the server * Thu Dec 3 2020 Mark Reynolds - 1.3.10.2-8