diff --git a/.389-ds-base.metadata b/.389-ds-base.metadata
index 46fc901..9ce4a90 100644
--- a/.389-ds-base.metadata
+++ b/.389-ds-base.metadata
@@ -1,2 +1,3 @@
 c69c175a2f27053dffbfefac9c84ff16c7ff4cbf SOURCES/389-ds-base-1.4.3.23.tar.bz2
 9e06b5cc57fd185379d007696da153893cf73e30 SOURCES/jemalloc-5.2.1.tar.bz2
+22b1ef11852864027e184bb4bee56286b855b703 SOURCES/vendor-1.4.3.23-2.tar.gz
diff --git a/.gitignore b/.gitignore
index 6114f52..3e96486 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
 SOURCES/389-ds-base-1.4.3.23.tar.bz2
 SOURCES/jemalloc-5.2.1.tar.bz2
+SOURCES/vendor-1.4.3.23-2.tar.gz
diff --git a/SOURCES/0013-Issue-4797-ACL-IP-ADDRESS-evaluation-may-corrupt-c_i.patch b/SOURCES/0013-Issue-4797-ACL-IP-ADDRESS-evaluation-may-corrupt-c_i.patch
new file mode 100644
index 0000000..db28cfa
--- /dev/null
+++ b/SOURCES/0013-Issue-4797-ACL-IP-ADDRESS-evaluation-may-corrupt-c_i.patch
@@ -0,0 +1,52 @@
+From bc41bbb89405b2059b80e344b2d4c59ae39aabe6 Mon Sep 17 00:00:00 2001
+From: tbordaz <tbordaz@redhat.com>
+Date: Thu, 10 Jun 2021 15:03:27 +0200
+Subject: [PATCH 1/3] Issue 4797 - ACL IP ADDRESS evaluation may corrupt
+ c_isreplication_session connection flags (#4799)
+
+Bug description:
+	The fix for ticket #3764 was broken with a missing break in a
+	switch. The consequence is that while setting the client IP
+	address in the pblock (SLAPI_CONN_CLIENTNETADDR_ACLIP), the
+	connection is erroneously set as replication connection.
+        This can lead to crash or failure of testcase
+        test_access_from_certain_network_only_ip.
+        This bug was quite hidden until the fix for #4764 is
+        showing it more frequently
+
+Fix description:
+	Add the missing break
+
+relates: https://github.com/389ds/389-ds-base/issues/4797
+
+Reviewed by: Mark Reynolds
+
+Platforms tested: F33
+---
+ ldap/servers/slapd/pblock.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/ldap/servers/slapd/pblock.c b/ldap/servers/slapd/pblock.c
+index fcac53839..a64986aeb 100644
+--- a/ldap/servers/slapd/pblock.c
++++ b/ldap/servers/slapd/pblock.c
+@@ -2595,7 +2595,7 @@ slapi_pblock_set(Slapi_PBlock *pblock, int arg, void *value)
+         pblock->pb_conn->c_authtype = slapi_ch_strdup((char *)value);
+         pthread_mutex_unlock(&(pblock->pb_conn->c_mutex));
+         break;
+-	case SLAPI_CONN_CLIENTNETADDR_ACLIP:
++    case SLAPI_CONN_CLIENTNETADDR_ACLIP:
+         if (pblock->pb_conn == NULL) {
+             break;
+         }
+@@ -2603,6 +2603,7 @@ slapi_pblock_set(Slapi_PBlock *pblock, int arg, void *value)
+         slapi_ch_free((void **)&pblock->pb_conn->cin_addr_aclip);
+         pblock->pb_conn->cin_addr_aclip = (PRNetAddr *)value;
+         pthread_mutex_unlock(&(pblock->pb_conn->c_mutex));
++        break;
+     case SLAPI_CONN_IS_REPLICATION_SESSION:
+         if (pblock->pb_conn == NULL) {
+             slapi_log_err(SLAPI_LOG_ERR,
+-- 
+2.31.1
+
diff --git a/SOURCES/0014-Issue-4396-Minor-memory-leak-in-backend-4558-4572.patch b/SOURCES/0014-Issue-4396-Minor-memory-leak-in-backend-4558-4572.patch
new file mode 100644
index 0000000..eb16fcb
--- /dev/null
+++ b/SOURCES/0014-Issue-4396-Minor-memory-leak-in-backend-4558-4572.patch
@@ -0,0 +1,79 @@
+From b3170e39519530c39d59202413b20e6bd466224d Mon Sep 17 00:00:00 2001
+From: James Chapman <jachapma@redhat.com>
+Date: Wed, 27 Jan 2021 09:56:38 +0000
+Subject: [PATCH 2/3] Issue 4396 - Minor memory leak in backend (#4558) (#4572)
+
+Bug Description: As multiple suffixes per backend were no longer used, this
+functionality has been replaced with a single suffix per backend. Legacy
+code remains that adds multiple suffixes to the dse internal backend,
+resulting in memory allocations that are lost.
+
+Also a minor typo is corrected in backend.c
+
+Fix Description: Calls to be_addsuffix on the DSE backend are removed
+as they are never used.
+
+Fixes: https://github.com/389ds/389-ds-base/issues/4396
+
+Reviewed by: mreynolds389, Firstyear, droideck (Thank you)
+---
+ ldap/servers/slapd/backend.c |  2 +-
+ ldap/servers/slapd/fedse.c   | 12 +++---------
+ 2 files changed, 4 insertions(+), 10 deletions(-)
+
+diff --git a/ldap/servers/slapd/backend.c b/ldap/servers/slapd/backend.c
+index bc52b4643..5707504a9 100644
+--- a/ldap/servers/slapd/backend.c
++++ b/ldap/servers/slapd/backend.c
+@@ -42,7 +42,7 @@ be_init(Slapi_Backend *be, const char *type, const char *name, int isprivate, in
+     }
+     be->be_monitordn = slapi_create_dn_string("cn=monitor,cn=%s,cn=%s,cn=plugins,cn=config",
+                                               name, type);
+-    if (NULL == be->be_configdn) {
++    if (NULL == be->be_monitordn) {
+         slapi_log_err(SLAPI_LOG_ERR,
+                       "be_init", "Failed create instance monitor dn for "
+                                  "plugin %s, instance %s\n",
+diff --git a/ldap/servers/slapd/fedse.c b/ldap/servers/slapd/fedse.c
+index 0d645f909..7b820b540 100644
+--- a/ldap/servers/slapd/fedse.c
++++ b/ldap/servers/slapd/fedse.c
+@@ -2827,7 +2827,7 @@ search_snmp(Slapi_PBlock *pb __attribute__((unused)),
+ }
+ 
+ /*
+- * Called from config.c to install the internal backends
++ * Called from main.c to install the internal backends
+  */
+ int
+ setup_internal_backends(char *configdir)
+@@ -2846,7 +2846,6 @@ setup_internal_backends(char *configdir)
+         Slapi_DN counters;
+         Slapi_DN snmp;
+         Slapi_DN root;
+-        Slapi_Backend *be;
+         Slapi_DN encryption;
+         Slapi_DN saslmapping;
+         Slapi_DN plugins;
+@@ -2895,16 +2894,11 @@ setup_internal_backends(char *configdir)
+         dse_register_callback(pfedse, SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, &saslmapping, LDAP_SCOPE_SUBTREE, "(objectclass=nsSaslMapping)", sasl_map_config_add, NULL, NULL);
+         dse_register_callback(pfedse, SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, &plugins, LDAP_SCOPE_SUBTREE, "(objectclass=nsSlapdPlugin)", check_plugin_path, NULL, NULL);
+ 
+-        be = be_new_internal(pfedse, "DSE", DSE_BACKEND, &fedse_plugin);
+-        be_addsuffix(be, &root);
+-        be_addsuffix(be, &monitor);
+-        be_addsuffix(be, &config);
++        be_new_internal(pfedse, "DSE", DSE_BACKEND, &fedse_plugin);
+ 
+         /*
+-         * Now that the be's are in place, we can
+-         * setup the mapping tree.
++         * Now that the be's are in place, we can setup the mapping tree.
+          */
+-
+         if (mapping_tree_init()) {
+             slapi_log_err(SLAPI_LOG_EMERG, "setup_internal_backends", "Failed to init mapping tree\n");
+             exit(1);
+-- 
+2.31.1
+
diff --git a/SOURCES/0015-Issue-4700-Regression-in-winsync-replication-agreeme.patch b/SOURCES/0015-Issue-4700-Regression-in-winsync-replication-agreeme.patch
new file mode 100644
index 0000000..9e5231d
--- /dev/null
+++ b/SOURCES/0015-Issue-4700-Regression-in-winsync-replication-agreeme.patch
@@ -0,0 +1,66 @@
+From 8d06fdf44b0d337f1e321e61ee1b22972ddea917 Mon Sep 17 00:00:00 2001
+From: tbordaz <tbordaz@redhat.com>
+Date: Fri, 2 Apr 2021 14:05:41 +0200
+Subject: [PATCH 3/3] Issue 4700 - Regression in winsync replication agreement
+ (#4712)
+
+Bug description:
+	#4396 fixes a memory leak but did not set 'cn=config' as
+	DSE backend.
+	It had no signicant impact unless with sidgen IPA plugin
+
+Fix description:
+	revert the portion of the #4364 patch that set be_suffix
+	in be_addsuffix, free the suffix before setting it
+
+relates: https://github.com/389ds/389-ds-base/issues/4700
+
+Reviewed by: Pierre Rogier (thanks !)
+
+Platforms tested: F33
+---
+ ldap/servers/slapd/backend.c | 3 ++-
+ ldap/servers/slapd/fedse.c   | 6 +++++-
+ 2 files changed, 7 insertions(+), 2 deletions(-)
+
+diff --git a/ldap/servers/slapd/backend.c b/ldap/servers/slapd/backend.c
+index 5707504a9..5db706841 100644
+--- a/ldap/servers/slapd/backend.c
++++ b/ldap/servers/slapd/backend.c
+@@ -173,7 +173,8 @@ void
+ be_addsuffix(Slapi_Backend *be, const Slapi_DN *suffix)
+ {
+     if (be->be_state != BE_STATE_DELETED) {
+-        be->be_suffix = slapi_sdn_dup(suffix);;
++        slapi_sdn_free(&be->be_suffix);
++        be->be_suffix = slapi_sdn_dup(suffix);
+     }
+ }
+ 
+diff --git a/ldap/servers/slapd/fedse.c b/ldap/servers/slapd/fedse.c
+index 7b820b540..44159c991 100644
+--- a/ldap/servers/slapd/fedse.c
++++ b/ldap/servers/slapd/fedse.c
+@@ -2846,6 +2846,7 @@ setup_internal_backends(char *configdir)
+         Slapi_DN counters;
+         Slapi_DN snmp;
+         Slapi_DN root;
++        Slapi_Backend *be;
+         Slapi_DN encryption;
+         Slapi_DN saslmapping;
+         Slapi_DN plugins;
+@@ -2894,7 +2895,10 @@ setup_internal_backends(char *configdir)
+         dse_register_callback(pfedse, SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, &saslmapping, LDAP_SCOPE_SUBTREE, "(objectclass=nsSaslMapping)", sasl_map_config_add, NULL, NULL);
+         dse_register_callback(pfedse, SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, &plugins, LDAP_SCOPE_SUBTREE, "(objectclass=nsSlapdPlugin)", check_plugin_path, NULL, NULL);
+ 
+-        be_new_internal(pfedse, "DSE", DSE_BACKEND, &fedse_plugin);
++        be = be_new_internal(pfedse, "DSE", DSE_BACKEND, &fedse_plugin);
++        be_addsuffix(be, &root);
++        be_addsuffix(be, &monitor);
++        be_addsuffix(be, &config);
+ 
+         /*
+          * Now that the be's are in place, we can setup the mapping tree.
+-- 
+2.31.1
+
diff --git a/SOURCES/0016-Issue-4725-Fix-compiler-warnings.patch b/SOURCES/0016-Issue-4725-Fix-compiler-warnings.patch
new file mode 100644
index 0000000..2371384
--- /dev/null
+++ b/SOURCES/0016-Issue-4725-Fix-compiler-warnings.patch
@@ -0,0 +1,88 @@
+From 7345c51c68dfd90a704ccbb0e5b1e736af80f146 Mon Sep 17 00:00:00 2001
+From: Thierry Bordaz <tbordaz@redhat.com>
+Date: Mon, 17 May 2021 16:10:22 +0200
+Subject: [PATCH] Issue 4725 - Fix compiler warnings
+
+---
+ ldap/servers/slapd/proto-slap.h | 2 +-
+ ldap/servers/slapd/pw.c         | 9 ++++-----
+ ldap/servers/slapd/pw_retry.c   | 2 --
+ 3 files changed, 5 insertions(+), 8 deletions(-)
+
+diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
+index 6ff178127..2768d5a1d 100644
+--- a/ldap/servers/slapd/proto-slap.h
++++ b/ldap/servers/slapd/proto-slap.h
+@@ -1012,7 +1012,7 @@ int add_shadow_ext_password_attrs(Slapi_PBlock *pb, Slapi_Entry **e);
+  * pw_retry.c
+  */
+ int update_pw_retry(Slapi_PBlock *pb);
+-int update_trp_pw_usecount(Slapi_PBlock *pb, Slapi_Entry *e, int32_t use_count);
++int update_tpr_pw_usecount(Slapi_PBlock *pb, Slapi_Entry *e, int32_t use_count);
+ void pw_apply_mods(const Slapi_DN *sdn, Slapi_Mods *mods);
+ void pw_set_componentID(struct slapi_componentid *cid);
+ struct slapi_componentid *pw_get_componentID(void);
+diff --git a/ldap/servers/slapd/pw.c b/ldap/servers/slapd/pw.c
+index d98422513..2a167c8f1 100644
+--- a/ldap/servers/slapd/pw.c
++++ b/ldap/servers/slapd/pw.c
+@@ -2622,7 +2622,6 @@ int
+ slapi_check_tpr_limits(Slapi_PBlock *pb, Slapi_Entry *bind_target_entry, int send_result) {
+     passwdPolicy *pwpolicy = NULL;
+     char *dn = NULL;
+-    int tpr_maxuse;
+     char *value;
+     time_t cur_time;
+     char *cur_time_str = NULL;
+@@ -2638,7 +2637,7 @@ slapi_check_tpr_limits(Slapi_PBlock *pb, Slapi_Entry *bind_target_entry, int sen
+         return 0;
+     }
+ 
+-    if (slapi_entry_attr_hasvalue(bind_target_entry, "pwdTPRReset", "TRUE") == NULL) {
++    if (!slapi_entry_attr_hasvalue(bind_target_entry, "pwdTPRReset", "TRUE")) {
+         /* the password was not reset by an admin while a TRP pwp was set, just returned */
+         return 0;
+     }
+@@ -2646,7 +2645,7 @@ slapi_check_tpr_limits(Slapi_PBlock *pb, Slapi_Entry *bind_target_entry, int sen
+     /* Check entry TPR max use */
+     if (pwpolicy->pw_tpr_maxuse >= 0) {
+         uint use_count;
+-        value = slapi_entry_attr_get_ref(bind_target_entry, "pwdTPRUseCount");
++        value = (char *) slapi_entry_attr_get_ref(bind_target_entry, "pwdTPRUseCount");
+         if (value) {
+             /* max Use is enforced */
+             use_count = strtoull(value, 0, 0);
+@@ -2681,7 +2680,7 @@ slapi_check_tpr_limits(Slapi_PBlock *pb, Slapi_Entry *bind_target_entry, int sen
+ 
+     /* Check entry TPR expiration at a specific time */
+     if (pwpolicy->pw_tpr_delay_expire_at >= 0) {
+-        value = slapi_entry_attr_get_ref(bind_target_entry, "pwdTPRExpireAt");
++        value = (char *) slapi_entry_attr_get_ref(bind_target_entry, "pwdTPRExpireAt");
+         if (value) {
+             /* max Use is enforced */
+             if (difftime(parse_genTime(cur_time_str), parse_genTime(value)) >= 0) {
+@@ -2709,7 +2708,7 @@ slapi_check_tpr_limits(Slapi_PBlock *pb, Slapi_Entry *bind_target_entry, int sen
+ 
+     /* Check entry TPR valid after a specific time */
+     if (pwpolicy->pw_tpr_delay_valid_from >= 0) {
+-        value = slapi_entry_attr_get_ref(bind_target_entry, "pwdTPRValidFrom");
++        value = (char *) slapi_entry_attr_get_ref(bind_target_entry, "pwdTPRValidFrom");
+         if (value) {
+             /* validity after a specific time is enforced */
+             if (difftime(parse_genTime(value), parse_genTime(cur_time_str)) >= 0) {
+diff --git a/ldap/servers/slapd/pw_retry.c b/ldap/servers/slapd/pw_retry.c
+index 5d13eb636..af54aa19d 100644
+--- a/ldap/servers/slapd/pw_retry.c
++++ b/ldap/servers/slapd/pw_retry.c
+@@ -163,8 +163,6 @@ set_retry_cnt_and_time(Slapi_PBlock *pb, int count, time_t cur_time)
+ int
+ set_tpr_usecount_mods(Slapi_PBlock *pb, Slapi_Mods *smods, int count)
+ {
+-    char *timestr;
+-    time_t unlock_time;
+     char retry_cnt[16] = {0}; /* 1-65535 */
+     const char *dn = NULL;
+     Slapi_DN *sdn = NULL;
+-- 
+2.31.1
+
diff --git a/SOURCES/0017-Issue-4814-_cl5_get_tod_expiration-may-crash-at-star.patch b/SOURCES/0017-Issue-4814-_cl5_get_tod_expiration-may-crash-at-star.patch
new file mode 100644
index 0000000..6785c04
--- /dev/null
+++ b/SOURCES/0017-Issue-4814-_cl5_get_tod_expiration-may-crash-at-star.patch
@@ -0,0 +1,202 @@
+From 59266365eda8130abf6901263efae4c87586376a Mon Sep 17 00:00:00 2001
+From: Thierry Bordaz <tbordaz@redhat.com>
+Date: Mon, 28 Jun 2021 16:40:15 +0200
+Subject: [PATCH] Issue 4814 - _cl5_get_tod_expiration may crash at startup
+
+Bug description:
+	This bug exist only in 1.4.3 branch
+	In 1.4.3, CL open as a separated database so
+        compaction mechanism is started along a CL
+        mechanism (CL trimming).
+        The problem is that the configuration of the CL
+        compaction is done after the compaction mechanism
+        (is started). Depending on thread scheduling it
+        crashes
+
+Fix description:
+        Make sure configuration of compaction thread is
+        taken into account (cl5ConfigSetCompaction) before
+	the compaction thread starts (cl5open)
+
+relates: https://github.com/389ds/389-ds-base/issues/4814
+
+Reviewed by: Mark Reynolds, Simon Pichugin (thanks !)
+
+Platforms tested: 8.5
+---
+ ldap/servers/plugins/replication/cl5_api.c    | 24 ++++++++++++-------
+ ldap/servers/plugins/replication/cl5_api.h    | 10 +++++++-
+ ldap/servers/plugins/replication/cl5_config.c |  8 +++++--
+ ldap/servers/plugins/replication/cl5_init.c   |  4 +++-
+ ldap/servers/plugins/replication/cl5_test.c   |  2 +-
+ .../servers/plugins/replication/repl_shared.h |  2 +-
+ 6 files changed, 35 insertions(+), 15 deletions(-)
+
+diff --git a/ldap/servers/plugins/replication/cl5_api.c b/ldap/servers/plugins/replication/cl5_api.c
+index 4c5077b48..954b6b9e3 100644
+--- a/ldap/servers/plugins/replication/cl5_api.c
++++ b/ldap/servers/plugins/replication/cl5_api.c
+@@ -1016,6 +1016,20 @@ cl5GetState()
+     return s_cl5Desc.dbState;
+ }
+ 
++void
++cl5ConfigSetCompaction(int compactInterval, char *compactTime)
++{
++
++    if (compactInterval != CL5_NUM_IGNORE) {
++        s_cl5Desc.dbTrim.compactInterval = compactInterval;
++    }
++
++    if (strcmp(compactTime, CL5_STR_IGNORE) != 0) {
++        s_cl5Desc.dbTrim.compactTime = slapi_ch_strdup(compactTime);
++    }
++
++}
++
+ /* Name:        cl5ConfigTrimming
+    Description:    sets changelog trimming parameters; changelog must be open.
+    Parameters:  maxEntries - maximum number of entries in the chnagelog (in all files);
+@@ -1026,7 +1040,7 @@ cl5GetState()
+                 CL5_BAD_STATE if changelog is not open
+  */
+ int
+-cl5ConfigTrimming(int maxEntries, const char *maxAge, int compactInterval, char *compactTime, int trimInterval)
++cl5ConfigTrimming(int maxEntries, const char *maxAge, int trimInterval)
+ {
+     if (s_cl5Desc.dbState == CL5_STATE_NONE) {
+         slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name_cl,
+@@ -1058,14 +1072,6 @@ cl5ConfigTrimming(int maxEntries, const char *maxAge, int compactInterval, char
+         s_cl5Desc.dbTrim.maxEntries = maxEntries;
+     }
+ 
+-    if (compactInterval != CL5_NUM_IGNORE) {
+-        s_cl5Desc.dbTrim.compactInterval = compactInterval;
+-    }
+-
+-    if (strcmp(compactTime, CL5_STR_IGNORE) != 0) {
+-        s_cl5Desc.dbTrim.compactTime = slapi_ch_strdup(compactTime);
+-    }
+-
+     if (trimInterval != CL5_NUM_IGNORE) {
+         s_cl5Desc.dbTrim.trimInterval = trimInterval;
+     }
+diff --git a/ldap/servers/plugins/replication/cl5_api.h b/ldap/servers/plugins/replication/cl5_api.h
+index 11db771f2..6aa48aec4 100644
+--- a/ldap/servers/plugins/replication/cl5_api.h
++++ b/ldap/servers/plugins/replication/cl5_api.h
+@@ -227,6 +227,14 @@ int cl5ImportLDIF(const char *clDir, const char *ldifFile, Replica **replicas);
+ 
+ int cl5GetState(void);
+ 
++/* Name:        cl5ConfigSetCompaction
++ * Description: sets the database compaction parameters
++ * Parameters:  compactInterval - Interval for compaction default is 30days
++ *              compactTime - Compact time default is 23:59
++ * Return:      void
++ */
++void cl5ConfigSetCompaction(int compactInterval, char *compactTime);
++
+ /* Name:        cl5ConfigTrimming
+    Description:    sets changelog trimming parameters
+    Parameters:  maxEntries - maximum number of entries in the log;
+@@ -236,7 +244,7 @@ int cl5GetState(void);
+    Return:        CL5_SUCCESS if successful;
+                 CL5_BAD_STATE if changelog has not been open
+  */
+-int cl5ConfigTrimming(int maxEntries, const char *maxAge, int compactInterval, char *compactTime, int trimInterval);
++int cl5ConfigTrimming(int maxEntries, const char *maxAge, int trimInterval);
+ 
+ void cl5DestroyIterator(void *iterator);
+ 
+diff --git a/ldap/servers/plugins/replication/cl5_config.c b/ldap/servers/plugins/replication/cl5_config.c
+index b32686788..a43534c9b 100644
+--- a/ldap/servers/plugins/replication/cl5_config.c
++++ b/ldap/servers/plugins/replication/cl5_config.c
+@@ -197,6 +197,8 @@ changelog5_config_add(Slapi_PBlock *pb __attribute__((unused)),
+ 
+         goto done;
+     }
++    /* Set compaction parameters */
++    cl5ConfigSetCompaction(config.compactInterval, config.compactTime);
+ 
+     /* start the changelog */
+     rc = cl5Open(config.dir, &config.dbconfig);
+@@ -212,7 +214,7 @@ changelog5_config_add(Slapi_PBlock *pb __attribute__((unused)),
+     }
+ 
+     /* set trimming parameters */
+-    rc = cl5ConfigTrimming(config.maxEntries, config.maxAge, config.compactInterval, config.compactTime, config.trimInterval);
++    rc = cl5ConfigTrimming(config.maxEntries, config.maxAge, config.trimInterval);
+     if (rc != CL5_SUCCESS) {
+         *returncode = 1;
+         if (returntext) {
+@@ -548,6 +550,8 @@ changelog5_config_modify(Slapi_PBlock *pb,
+                 slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name_cl,
+                               "changelog5_config_modify - Deleted the changelog at %s\n", currentDir);
+             }
++            /* Set compaction parameters */
++            cl5ConfigSetCompaction(config.compactInterval, config.compactTime);
+ 
+             rc = cl5Open(config.dir, &config.dbconfig);
+             if (rc != CL5_SUCCESS) {
+@@ -575,7 +579,7 @@ changelog5_config_modify(Slapi_PBlock *pb,
+     if (config.maxEntries != CL5_NUM_IGNORE ||
+         config.trimInterval != CL5_NUM_IGNORE ||
+         strcmp(config.maxAge, CL5_STR_IGNORE) != 0) {
+-        rc = cl5ConfigTrimming(config.maxEntries, config.maxAge, config.compactInterval, config.compactTime, config.trimInterval);
++        rc = cl5ConfigTrimming(config.maxEntries, config.maxAge, config.trimInterval);
+         if (rc != CL5_SUCCESS) {
+             *returncode = 1;
+             if (returntext) {
+diff --git a/ldap/servers/plugins/replication/cl5_init.c b/ldap/servers/plugins/replication/cl5_init.c
+index 251859714..567e0274c 100644
+--- a/ldap/servers/plugins/replication/cl5_init.c
++++ b/ldap/servers/plugins/replication/cl5_init.c
+@@ -45,6 +45,8 @@ changelog5_init()
+         rc = 0; /* OK */
+         goto done;
+     }
++    /* Set compaction parameters */
++    cl5ConfigSetCompaction(config.compactInterval, config.compactTime);
+ 
+     /* start changelog */
+     rc = cl5Open(config.dir, &config.dbconfig);
+@@ -57,7 +59,7 @@ changelog5_init()
+     }
+ 
+     /* set trimming parameters */
+-    rc = cl5ConfigTrimming(config.maxEntries, config.maxAge, config.compactInterval, config.compactTime, config.trimInterval);
++    rc = cl5ConfigTrimming(config.maxEntries, config.maxAge, config.trimInterval);
+     if (rc != CL5_SUCCESS) {
+         slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name_cl,
+                       "changelog5_init: failed to configure changelog trimming\n");
+diff --git a/ldap/servers/plugins/replication/cl5_test.c b/ldap/servers/plugins/replication/cl5_test.c
+index d6656653c..efb8c543a 100644
+--- a/ldap/servers/plugins/replication/cl5_test.c
++++ b/ldap/servers/plugins/replication/cl5_test.c
+@@ -281,7 +281,7 @@ testTrimming()
+         rc = populateChangelog(300, NULL);
+ 
+         if (rc == 0)
+-            rc = cl5ConfigTrimming(300, "1d", CHANGELOGDB_COMPACT_INTERVAL, CHANGELOGDB_TRIM_INTERVAL);
++            rc = cl5ConfigTrimming(300, "1d", CHANGELOGDB_TRIM_INTERVAL);
+ 
+         interval = PR_SecondsToInterval(300); /* 5 min is default trimming interval */
+         slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name_cl,
+diff --git a/ldap/servers/plugins/replication/repl_shared.h b/ldap/servers/plugins/replication/repl_shared.h
+index 6708e12f7..b59b2bd27 100644
+--- a/ldap/servers/plugins/replication/repl_shared.h
++++ b/ldap/servers/plugins/replication/repl_shared.h
+@@ -26,7 +26,7 @@
+ 
+ #define CHANGELOGDB_TRIM_INTERVAL 300        /* 5 minutes */
+ #define CHANGELOGDB_COMPACT_INTERVAL 2592000 /* 30 days */
+-#define CHANGELOGDB_COMPACT_TIME "23:55" /* 30 days */
++#define CHANGELOGDB_COMPACT_TIME "23:59"     /* around midnight */
+ 
+ #define CONFIG_CHANGELOG_DIR_ATTRIBUTE "nsslapd-changelogdir"
+ #define CONFIG_CHANGELOG_MAXENTRIES_ATTRIBUTE "nsslapd-changelogmaxentries"
+-- 
+2.31.1
+
diff --git a/SOURCES/0018-Issue-4789-Temporary-password-rules-are-not-enforce-.patch b/SOURCES/0018-Issue-4789-Temporary-password-rules-are-not-enforce-.patch
new file mode 100644
index 0000000..5ab86af
--- /dev/null
+++ b/SOURCES/0018-Issue-4789-Temporary-password-rules-are-not-enforce-.patch
@@ -0,0 +1,51 @@
+From e7fdfe527a5f72674fe4b577a0555cabf8ec73a5 Mon Sep 17 00:00:00 2001
+From: tbordaz <tbordaz@redhat.com>
+Date: Mon, 7 Jun 2021 11:23:35 +0200
+Subject: [PATCH] Issue 4789 - Temporary password rules are not enforce with
+ local password policy (#4790)
+
+Bug description:
+	When allocating a password policy structure (new_passwdPolicy)
+        it is initialized with the local policy definition or
+	the global one. If it exists a local policy entry, the TPR
+        attributes (passwordTPRMaxUse, passwordTPRDelayValidFrom and
+        passwordTPRDelayExpireAt) are not taken into account.
+
+Fix description:
+	Take into account TPR attributes to initialize the policy
+
+relates: https://github.com/389ds/389-ds-base/issues/4789
+
+Reviewed by: Simon Pichugin, William Brown
+
+Platforms tested: F34
+---
+ ldap/servers/slapd/pw.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/ldap/servers/slapd/pw.c b/ldap/servers/slapd/pw.c
+index 2a167c8f1..7680df41d 100644
+--- a/ldap/servers/slapd/pw.c
++++ b/ldap/servers/slapd/pw.c
+@@ -2356,6 +2356,18 @@ new_passwdPolicy(Slapi_PBlock *pb, const char *dn)
+                     if ((sval = attr_get_present_values(attr))) {
+                         pwdpolicy->pw_dict_path = (char *)slapi_value_get_string(*sval);
+                     }
++                } else if (!strcasecmp(attr_name, CONFIG_PW_TPR_MAXUSE)) {
++                    if ((sval = attr_get_present_values(attr))) {
++                        pwdpolicy->pw_tpr_maxuse = slapi_value_get_int(*sval);
++                    }
++                } else if (!strcasecmp(attr_name, CONFIG_PW_TPR_DELAY_EXPIRE_AT)) {
++                    if ((sval = attr_get_present_values(attr))) {
++                        pwdpolicy->pw_tpr_delay_expire_at = slapi_value_get_int(*sval);
++                    }
++                } else if (!strcasecmp(attr_name, CONFIG_PW_TPR_DELAY_VALID_FROM)) {
++                    if ((sval = attr_get_present_values(attr))) {
++                        pwdpolicy->pw_tpr_delay_valid_from = slapi_value_get_int(*sval);
++                    }
+                 }
+             } /* end of for() loop */
+             if (pw_entry) {
+-- 
+2.31.1
+
diff --git a/SOURCES/0019-Issue-4788-CLI-should-support-Temporary-Password-Rul.patch b/SOURCES/0019-Issue-4788-CLI-should-support-Temporary-Password-Rul.patch
new file mode 100644
index 0000000..f9e4266
--- /dev/null
+++ b/SOURCES/0019-Issue-4788-CLI-should-support-Temporary-Password-Rul.patch
@@ -0,0 +1,350 @@
+From 6a741b3ef50babf2ac2479437a38829204ffd438 Mon Sep 17 00:00:00 2001
+From: tbordaz <tbordaz@redhat.com>
+Date: Thu, 17 Jun 2021 16:22:09 +0200
+Subject: [PATCH] Issue 4788 - CLI should support Temporary Password Rules
+ attributes (#4793)
+
+Bug description:
+    Since #4725, password policy support temporary password rules.
+    CLI (dsconf) does not support this RFE and only direct ldap
+    operation can configure global/local password policy
+
+Fix description:
+    Update dsconf to support this new RFE.
+    To run successfully the testcase it relies on #4788
+
+relates: #4788
+
+Reviewed by: Simon Pichugin (thanks !!)
+
+Platforms tested: F34
+---
+ .../password/pwdPolicy_attribute_test.py      | 172 ++++++++++++++++--
+ src/lib389/lib389/cli_conf/pwpolicy.py        |   5 +-
+ src/lib389/lib389/pwpolicy.py                 |   5 +-
+ 3 files changed, 165 insertions(+), 17 deletions(-)
+
+diff --git a/dirsrvtests/tests/suites/password/pwdPolicy_attribute_test.py b/dirsrvtests/tests/suites/password/pwdPolicy_attribute_test.py
+index aee3a91ad..085d0a373 100644
+--- a/dirsrvtests/tests/suites/password/pwdPolicy_attribute_test.py
++++ b/dirsrvtests/tests/suites/password/pwdPolicy_attribute_test.py
+@@ -34,7 +34,7 @@ log = logging.getLogger(__name__)
+ 
+ 
+ @pytest.fixture(scope="module")
+-def create_user(topology_st, request):
++def test_user(topology_st, request):
+     """User for binding operation"""
+     topology_st.standalone.config.set('nsslapd-auditlog-logging-enabled', 'on')
+     log.info('Adding test user {}')
+@@ -56,10 +56,11 @@ def create_user(topology_st, request):
+         topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
+ 
+     request.addfinalizer(fin)
++    return user
+ 
+ 
+ @pytest.fixture(scope="module")
+-def password_policy(topology_st, create_user):
++def password_policy(topology_st, test_user):
+     """Set up password policy for subtree and user"""
+ 
+     pwp = PwPolicyManager(topology_st.standalone)
+@@ -71,7 +72,7 @@ def password_policy(topology_st, create_user):
+     pwp.create_user_policy(TEST_USER_DN, policy_props)
+ 
+ @pytest.mark.skipif(ds_is_older('1.4.3.3'), reason="Not implemented")
+-def test_pwd_reset(topology_st, create_user):
++def test_pwd_reset(topology_st, test_user):
+     """Test new password policy attribute "pwdReset"
+ 
+     :id: 03db357b-4800-411e-a36e-28a534293004
+@@ -124,7 +125,7 @@ def test_pwd_reset(topology_st, create_user):
+                          [('on', 'off', ldap.UNWILLING_TO_PERFORM),
+                           ('off', 'off', ldap.UNWILLING_TO_PERFORM),
+                           ('off', 'on', False), ('on', 'on', False)])
+-def test_change_pwd(topology_st, create_user, password_policy,
++def test_change_pwd(topology_st, test_user, password_policy,
+                     subtree_pwchange, user_pwchange, exception):
+     """Verify that 'passwordChange' attr works as expected
+     User should have a priority over a subtree.
+@@ -184,7 +185,7 @@ def test_change_pwd(topology_st, create_user, password_policy,
+         user.reset_password(TEST_USER_PWD)
+ 
+ 
+-def test_pwd_min_age(topology_st, create_user, password_policy):
++def test_pwd_min_age(topology_st, test_user, password_policy):
+     """If we set passwordMinAge to some value, for example to 10, then it
+     should not allow the user to change the password within 10 seconds after
+     his previous change.
+@@ -257,7 +258,7 @@ def test_pwd_min_age(topology_st, create_user, password_policy):
+         topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
+         user.reset_password(TEST_USER_PWD)
+ 
+-def test_global_tpr_maxuse_1(topology_st, create_user, request):
++def test_global_tpr_maxuse_1(topology_st, test_user, request):
+     """Test global TPR policy : passwordTPRMaxUse
+     Test that after passwordTPRMaxUse failures to bind
+     additional bind with valid password are failing with CONSTRAINT_VIOLATION
+@@ -374,7 +375,7 @@ def test_global_tpr_maxuse_1(topology_st, create_user, request):
+ 
+     request.addfinalizer(fin)
+ 
+-def test_global_tpr_maxuse_2(topology_st, create_user, request):
++def test_global_tpr_maxuse_2(topology_st, test_user, request):
+     """Test global TPR policy : passwordTPRMaxUse
+     Test that after less than passwordTPRMaxUse failures to bind
+     additional bind with valid password are successfull
+@@ -474,7 +475,7 @@ def test_global_tpr_maxuse_2(topology_st, create_user, request):
+ 
+     request.addfinalizer(fin)
+ 
+-def test_global_tpr_maxuse_3(topology_st, create_user, request):
++def test_global_tpr_maxuse_3(topology_st, test_user, request):
+     """Test global TPR policy : passwordTPRMaxUse
+     Test that after less than passwordTPRMaxUse failures to bind
+     A bind with valid password is successfull but passwordMustChange
+@@ -587,7 +588,7 @@ def test_global_tpr_maxuse_3(topology_st, create_user, request):
+ 
+     request.addfinalizer(fin)
+ 
+-def test_global_tpr_maxuse_4(topology_st, create_user, request):
++def test_global_tpr_maxuse_4(topology_st, test_user, request):
+     """Test global TPR policy : passwordTPRMaxUse
+     Test that a TPR attribute passwordTPRMaxUse
+     can be updated by DM but not the by user itself
+@@ -701,7 +702,148 @@ def test_global_tpr_maxuse_4(topology_st, create_user, request):
+ 
+     request.addfinalizer(fin)
+ 
+-def test_global_tpr_delayValidFrom_1(topology_st, create_user, request):
++def test_local_tpr_maxuse_5(topology_st, test_user, request):
++    """Test TPR local policy overpass global one: passwordTPRMaxUse
++    Test that after passwordTPRMaxUse failures to bind
++    additional bind with valid password are failing with CONSTRAINT_VIOLATION
++
++    :id: c3919707-d804-445a-8754-8385b1072c42
++    :customerscenario: False
++    :setup: Standalone instance
++    :steps:
++        1. Global password policy Enable passwordMustChange
++        2. Global password policy Set passwordTPRMaxUse=5
++        3. Global password policy Set passwordMaxFailure to a higher value to not disturb the test
++        4. Local password policy Enable passwordMustChange
++        5. Local password policy Set passwordTPRMaxUse=10 (higher than global)
++        6. Bind with a wrong password 10 times and check INVALID_CREDENTIALS
++        7. Check that passwordTPRUseCount got to the limit (5)
++        8. Bind with a wrong password (CONSTRAINT_VIOLATION)
++           and check passwordTPRUseCount overpass the limit by 1 (11)
++        9. Bind with a valid password 10 times and check CONSTRAINT_VIOLATION
++           and check passwordTPRUseCount increases
++        10. Reset password policy configuration and remove local password from user
++    :expected results:
++        1. Success
++        2. Success
++        3. Success
++        4. Success
++        5. Success
++        6. Success
++        7. Success
++        8. Success
++        9. Success
++        10. Success
++    """
++
++    global_tpr_maxuse = 5
++    # Set global password policy config, passwordMaxFailure being higher than
++    # passwordTPRMaxUse so that TPR is enforced first
++    topology_st.standalone.config.replace('passwordMustChange', 'on')
++    topology_st.standalone.config.replace('passwordMaxFailure', str(global_tpr_maxuse + 20))
++    topology_st.standalone.config.replace('passwordTPRMaxUse', str(global_tpr_maxuse))
++    time.sleep(.5)
++
++    local_tpr_maxuse = global_tpr_maxuse + 5
++    # Reset user's password with a local password policy
++    # that has passwordTPRMaxUse higher than global
++    #our_user = UserAccount(topology_st.standalone, TEST_USER_DN)
++    subprocess.call(['%s/dsconf' % topology_st.standalone.get_sbin_dir(),
++                     'slapd-standalone1',
++                     'localpwp',
++                     'adduser',
++                     test_user.dn])
++    subprocess.call(['%s/dsconf' % topology_st.standalone.get_sbin_dir(),
++                     'slapd-standalone1',
++                     'localpwp',
++                     'set',
++                     '--pwptprmaxuse',
++                     str(local_tpr_maxuse),
++                     '--pwdmustchange',
++                     'on',
++                     test_user.dn])
++    test_user.replace('userpassword', PASSWORD)
++    time.sleep(.5)
++
++    # look up to passwordTPRMaxUse with failing
++    # bind to check that the limits of TPR are enforced
++    for i in range(local_tpr_maxuse):
++        # Bind as user with a wrong password
++        with pytest.raises(ldap.INVALID_CREDENTIALS):
++            test_user.rebind('wrong password')
++        time.sleep(.5)
++
++        # Check that pwdReset is TRUE
++        topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
++        #assert test_user.get_attr_val_utf8('pwdReset') == 'TRUE'
++
++        # Check that pwdTPRReset is TRUE
++        assert test_user.get_attr_val_utf8('pwdTPRReset') == 'TRUE'
++        assert test_user.get_attr_val_utf8('pwdTPRUseCount') == str(i+1)
++        log.info("%dth failing bind (INVALID_CREDENTIALS) => pwdTPRUseCount = %d" % (i+1, i+1))
++
++
++    # Now the #failures reached passwordTPRMaxUse
++    # Check that pwdReset is TRUE
++    topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
++
++    # Check that pwdTPRReset is TRUE
++    assert test_user.get_attr_val_utf8('pwdTPRReset') == 'TRUE'
++    assert test_user.get_attr_val_utf8('pwdTPRUseCount') == str(local_tpr_maxuse)
++    log.info("last failing bind (INVALID_CREDENTIALS) => pwdTPRUseCount = %d" % (local_tpr_maxuse))
++
++    # Bind as user with wrong password --> ldap.CONSTRAINT_VIOLATION
++    with pytest.raises(ldap.CONSTRAINT_VIOLATION):
++        test_user.rebind("wrong password")
++    time.sleep(.5)
++
++    # Check that pwdReset is TRUE
++    topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
++
++    # Check that pwdTPRReset is TRUE
++    assert test_user.get_attr_val_utf8('pwdTPRReset') == 'TRUE'
++    assert test_user.get_attr_val_utf8('pwdTPRUseCount') == str(local_tpr_maxuse + 1)
++    log.info("failing bind (CONSTRAINT_VIOLATION) => pwdTPRUseCount = %d" % (local_tpr_maxuse + i))
++
++    # Now check that all next attempts with correct password are all in LDAP_CONSTRAINT_VIOLATION
++    # and passwordTPRRetryCount remains unchanged
++    # account is now similar to locked
++    for i in range(10):
++        # Bind as user with valid password
++        with pytest.raises(ldap.CONSTRAINT_VIOLATION):
++            test_user.rebind(PASSWORD)
++        time.sleep(.5)
++
++        # Check that pwdReset is TRUE
++        topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
++
++        # Check that pwdTPRReset is TRUE
++        # pwdTPRUseCount keeps increasing
++        assert test_user.get_attr_val_utf8('pwdTPRReset') == 'TRUE'
++        assert test_user.get_attr_val_utf8('pwdTPRUseCount') == str(local_tpr_maxuse + i + 2)
++        log.info("Rejected bind (CONSTRAINT_VIOLATION) => pwdTPRUseCount = %d" % (local_tpr_maxuse + i + 2))
++
++
++    def fin():
++        topology_st.standalone.restart()
++        # Reset password policy config
++        topology_st.standalone.simple_bind_s(DN_DM, PASSWORD)
++        topology_st.standalone.config.replace('passwordMustChange', 'off')
++
++        # Remove local password policy from that entry
++        subprocess.call(['%s/dsconf' % topology_st.standalone.get_sbin_dir(),
++                        'slapd-standalone1',
++                        'localpwp',
++                        'remove',
++                        test_user.dn])
++
++        # Reset user's password
++        test_user.replace('userpassword', TEST_USER_PWD)
++
++
++    request.addfinalizer(fin)
++
++def test_global_tpr_delayValidFrom_1(topology_st, test_user, request):
+     """Test global TPR policy : passwordTPRDelayValidFrom
+     Test that a TPR password is not valid before reset time +
+     passwordTPRDelayValidFrom
+@@ -766,7 +908,7 @@ def test_global_tpr_delayValidFrom_1(topology_st, create_user, request):
+ 
+     request.addfinalizer(fin)
+ 
+-def test_global_tpr_delayValidFrom_2(topology_st, create_user, request):
++def test_global_tpr_delayValidFrom_2(topology_st, test_user, request):
+     """Test global TPR policy : passwordTPRDelayValidFrom
+     Test that a TPR password is valid after reset time +
+     passwordTPRDelayValidFrom
+@@ -838,7 +980,7 @@ def test_global_tpr_delayValidFrom_2(topology_st, create_user, request):
+ 
+     request.addfinalizer(fin)
+ 
+-def test_global_tpr_delayValidFrom_3(topology_st, create_user, request):
++def test_global_tpr_delayValidFrom_3(topology_st, test_user, request):
+     """Test global TPR policy : passwordTPRDelayValidFrom
+     Test that a TPR attribute passwordTPRDelayValidFrom
+     can be updated by DM but not the by user itself
+@@ -940,7 +1082,7 @@ def test_global_tpr_delayValidFrom_3(topology_st, create_user, request):
+ 
+     request.addfinalizer(fin)
+ 
+-def test_global_tpr_delayExpireAt_1(topology_st, create_user, request):
++def test_global_tpr_delayExpireAt_1(topology_st, test_user, request):
+     """Test global TPR policy : passwordTPRDelayExpireAt
+     Test that a TPR password is not valid after reset time +
+     passwordTPRDelayExpireAt
+@@ -1010,7 +1152,7 @@ def test_global_tpr_delayExpireAt_1(topology_st, create_user, request):
+ 
+     request.addfinalizer(fin)
+ 
+-def test_global_tpr_delayExpireAt_2(topology_st, create_user, request):
++def test_global_tpr_delayExpireAt_2(topology_st, test_user, request):
+     """Test global TPR policy : passwordTPRDelayExpireAt
+     Test that a TPR password is valid before reset time +
+     passwordTPRDelayExpireAt
+@@ -1082,7 +1224,7 @@ def test_global_tpr_delayExpireAt_2(topology_st, create_user, request):
+ 
+     request.addfinalizer(fin)
+ 
+-def test_global_tpr_delayExpireAt_3(topology_st, create_user, request):
++def test_global_tpr_delayExpireAt_3(topology_st, test_user, request):
+     """Test global TPR policy : passwordTPRDelayExpireAt
+     Test that a TPR attribute passwordTPRDelayExpireAt
+     can be updated by DM but not the by user itself
+diff --git a/src/lib389/lib389/cli_conf/pwpolicy.py b/src/lib389/lib389/cli_conf/pwpolicy.py
+index 2838afcb8..26af6e7ec 100644
+--- a/src/lib389/lib389/cli_conf/pwpolicy.py
++++ b/src/lib389/lib389/cli_conf/pwpolicy.py
+@@ -255,6 +255,9 @@ def create_parser(subparsers):
+     set_parser.add_argument('--pwpinheritglobal', help="Set to \"on\" to allow local policies to inherit the global policy")
+     set_parser.add_argument('--pwddictcheck', help="Set to \"on\" to enforce CrackLib dictionary checking")
+     set_parser.add_argument('--pwddictpath', help="Filesystem path to specific/custom CrackLib dictionary files")
++    set_parser.add_argument('--pwptprmaxuse', help="Number of times a reset password can be used for authentication")
++    set_parser.add_argument('--pwptprdelayexpireat', help="Number of seconds after which a reset password expires")
++    set_parser.add_argument('--pwptprdelayvalidfrom', help="Number of seconds to wait before using a reset password to authenticated")
+     # delete local password policy
+     del_parser = local_subcommands.add_parser('remove', help='Remove a local password policy')
+     del_parser.set_defaults(func=del_local_policy)
+@@ -291,4 +294,4 @@ def create_parser(subparsers):
+     #############################################
+     set_parser.add_argument('DN', nargs=1, help='Set the local policy for this entry DN')
+     add_subtree_parser.add_argument('DN', nargs=1, help='Add/replace the subtree policy for this entry DN')
+-    add_user_parser.add_argument('DN', nargs=1, help='Add/replace the local password policy for this entry DN')
+\ No newline at end of file
++    add_user_parser.add_argument('DN', nargs=1, help='Add/replace the local password policy for this entry DN')
+diff --git a/src/lib389/lib389/pwpolicy.py b/src/lib389/lib389/pwpolicy.py
+index 8653cb195..d2427933b 100644
+--- a/src/lib389/lib389/pwpolicy.py
++++ b/src/lib389/lib389/pwpolicy.py
+@@ -65,7 +65,10 @@ class PwPolicyManager(object):
+             'pwddictcheck': 'passworddictcheck',
+             'pwddictpath': 'passworddictpath',
+             'pwdallowhash': 'nsslapd-allow-hashed-passwords',
+-            'pwpinheritglobal': 'nsslapd-pwpolicy-inherit-global'
++            'pwpinheritglobal': 'nsslapd-pwpolicy-inherit-global',
++            'pwptprmaxuse': 'passwordTPRMaxUse',
++            'pwptprdelayexpireat': 'passwordTPRDelayExpireAt',
++            'pwptprdelayvalidfrom': 'passwordTPRDelayValidFrom'
+         }
+ 
+     def is_subtree_policy(self, dn):
+-- 
+2.31.1
+
diff --git a/SOURCES/0020-Issue-4447-Crash-when-the-Referential-Integrity-log-.patch b/SOURCES/0020-Issue-4447-Crash-when-the-Referential-Integrity-log-.patch
new file mode 100644
index 0000000..193d44b
--- /dev/null
+++ b/SOURCES/0020-Issue-4447-Crash-when-the-Referential-Integrity-log-.patch
@@ -0,0 +1,179 @@
+From 7b7217538908ae58df864ef5cd82e1d3303c189f Mon Sep 17 00:00:00 2001
+From: Mark Reynolds <mreynolds@redhat.com>
+Date: Mon, 7 Jun 2021 12:58:42 -0400
+Subject: [PATCH] Issue 4447 - Crash when the Referential Integrity log is
+ manually edited
+
+Bug Description:  If the referint log is manually edited with a string
+                  that is not a DN the server will crash when processing
+                  the log.
+
+Fix Description:  Check for NULL pointers when strtoking the file line.
+
+relates: https://github.com/389ds/389-ds-base/issues/4447
+
+Reviewed by: firstyear(Thanks!)
+---
+ .../tests/suites/plugins/referint_test.py     | 72 +++++++++++++++----
+ ldap/servers/plugins/referint/referint.c      |  7 ++
+ src/lib389/lib389/plugins.py                  | 15 ++++
+ 3 files changed, 80 insertions(+), 14 deletions(-)
+
+diff --git a/dirsrvtests/tests/suites/plugins/referint_test.py b/dirsrvtests/tests/suites/plugins/referint_test.py
+index 02b985767..fda602545 100644
+--- a/dirsrvtests/tests/suites/plugins/referint_test.py
++++ b/dirsrvtests/tests/suites/plugins/referint_test.py
+@@ -1,5 +1,5 @@
+ # --- BEGIN COPYRIGHT BLOCK ---
+-# Copyright (C) 2016 Red Hat, Inc.
++# Copyright (C) 2021 Red Hat, Inc.
+ # All rights reserved.
+ #
+ # License: GPL (version 3 or any later version).
+@@ -12,13 +12,11 @@ Created on Dec 12, 2019
+ @author: tbordaz
+ '''
+ import logging
+-import subprocess
+ import pytest
+ from lib389 import Entry
+-from lib389.utils import *
+-from lib389.plugins import *
+-from lib389._constants import *
+-from lib389.idm.user import UserAccounts, UserAccount
++from lib389.plugins import ReferentialIntegrityPlugin
++from lib389._constants import DEFAULT_SUFFIX
++from lib389.idm.user import UserAccounts
+ from lib389.idm.group import Groups
+ from lib389.topologies import topology_st as topo
+ 
+@@ -29,21 +27,27 @@ log = logging.getLogger(__name__)
+ ESCAPED_RDN_BASE = "foo\\,oo"
+ def _user_get_dn(no):
+     uid = '%s%d' % (ESCAPED_RDN_BASE, no)
+-    dn = 'uid=%s,%s' % (uid, SUFFIX)
++    dn = 'uid=%s,%s' % (uid, DEFAULT_SUFFIX)
+     return (uid, dn)
+ 
+ def add_escaped_user(server, no):
+     (uid, dn) = _user_get_dn(no)
+     log.fatal('Adding user (%s): ' % dn)
+-    server.add_s(Entry((dn, {'objectclass': ['top', 'person', 'organizationalPerson', 'inetOrgPerson'],
+-                             'uid': [uid],
+-                             'sn' : [uid],
+-                             'cn' : [uid]})))
++    users = UserAccounts(server, DEFAULT_SUFFIX, None)
++    user_properties = {
++        'objectclass': ['top', 'person', 'organizationalPerson', 'inetOrgPerson', 'posixAccount'],
++        'uid': uid,
++        'cn' : uid,
++        'sn' : uid,
++        'uidNumber' : '1000',
++        'gidNumber' : '2000',
++        'homeDirectory' : '/home/testuser',
++    }
++    users.create(properties=user_properties)
+     return dn
+ 
+-@pytest.mark.ds50020
+ def test_referential_false_failure(topo):
+-    """On MODRDN referential integrity can erronously fail
++    """On MODRDN referential integrity can erroneously fail
+ 
+     :id: f77aeb80-c4c4-471b-8c1b-4733b714778b
+     :setup: Standalone Instance
+@@ -100,6 +104,46 @@ def test_referential_false_failure(topo):
+     inst.restart()
+ 
+     # Here if the bug is fixed, referential is able to update the member value
+-    inst.rename_s(user1.dn, 'uid=new_test_user_1001', newsuperior=SUFFIX, delold=0)
++    user1.rename('uid=new_test_user_1001', newsuperior=DEFAULT_SUFFIX, deloldrdn=False)
+ 
+ 
++def test_invalid_referint_log(topo):
++    """If there is an invalid log line in the referint log, make sure the server
++    does not crash at startup
++
++    :id: 34807b5a-ab17-4281-ae48-4e3513e19145
++    :setup: Standalone Instance
++    :steps:
++        1. Set the referint log delay
++        2. Create invalid log
++        3. Start the server (no crash)
++    :expectedresults:
++        1. Success
++        2. Success
++        3. Success
++    """
++
++    inst = topo.standalone
++
++    # Set delay - required for log parsing at server startup
++    plugin = ReferentialIntegrityPlugin(inst)
++    plugin.enable()
++    plugin.set_update_delay('2')
++    logfile = plugin.get_log_file()
++    inst.restart()
++
++    # Create invalid log
++    inst.stop()
++    with open(logfile, 'w') as log_fh:
++        log_fh.write("CRASH\n")
++
++    # Start the instance
++    inst.start()
++    assert inst.status()
++
++
++if __name__ == '__main__':
++    # Run isolated
++    # -s for DEBUG mode
++    CURRENT_FILE = os.path.realpath(__file__)
++    pytest.main("-s %s" % CURRENT_FILE)
+diff --git a/ldap/servers/plugins/referint/referint.c b/ldap/servers/plugins/referint/referint.c
+index fd5356d72..28240c1f6 100644
+--- a/ldap/servers/plugins/referint/referint.c
++++ b/ldap/servers/plugins/referint/referint.c
+@@ -1447,6 +1447,13 @@ referint_thread_func(void *arg __attribute__((unused)))
+             sdn = slapi_sdn_new_normdn_byref(ptoken);
+             ptoken = ldap_utf8strtok_r(NULL, delimiter, &iter);
+ 
++            if (ptoken == NULL) {
++                /* Invalid line in referint log, skip it */
++                slapi_log_err(SLAPI_LOG_ERR, REFERINT_PLUGIN_SUBSYSTEM,
++                        "Skipping invalid referint log line: (%s)\n", thisline);
++                slapi_sdn_free(&sdn);
++                continue;
++            }
+             if (!strcasecmp(ptoken, "NULL")) {
+                 tmprdn = NULL;
+             } else {
+diff --git a/src/lib389/lib389/plugins.py b/src/lib389/lib389/plugins.py
+index 2d88e60bd..b07e80022 100644
+--- a/src/lib389/lib389/plugins.py
++++ b/src/lib389/lib389/plugins.py
+@@ -518,6 +518,21 @@ class ReferentialIntegrityPlugin(Plugin):
+ 
+         self.set('referint-update-delay', str(value))
+ 
++    def get_log_file(self):
++        """Get referint log file"""
++
++        return self.get_attr_val_utf8('referint-logfile')
++
++    def get_log_file_formatted(self):
++        """Get referint log file"""
++
++        return self.display_attr('referint-logfile')
++
++    def set_log_file(self, value):
++        """Set referint log file"""
++
++        self.set('referint-logfile', value)
++
+     def get_membership_attr(self, formatted=False):
+         """Get referint-membership-attr attribute"""
+ 
+-- 
+2.31.1
+
diff --git a/SOURCES/0021-Issue-4791-Missing-dependency-for-RetroCL-RFE.patch b/SOURCES/0021-Issue-4791-Missing-dependency-for-RetroCL-RFE.patch
new file mode 100644
index 0000000..4810288
--- /dev/null
+++ b/SOURCES/0021-Issue-4791-Missing-dependency-for-RetroCL-RFE.patch
@@ -0,0 +1,114 @@
+From 964a153b420b26140e0bbddfbebb4a51aaa0e4ea Mon Sep 17 00:00:00 2001
+From: James Chapman <jachapma@redhat.com>
+Date: Thu, 3 Jun 2021 15:16:22 +0000
+Subject: [PATCH 1/7] Issue 4791 - Missing dependency for RetroCL RFE
+
+Description: The RetroCL exclude attribute RFE is dependent on functionality of the
+	     EntryUUID bug fix, that didn't make into the latest build. This breaks the
+             RetroCL exclude attr feature so we need to provide a workaround.
+
+Fixes: https://github.com/389ds/389-ds-base/issues/4791
+
+Relates: https://github.com/389ds/389-ds-base/pull/4723
+
+Relates: https://github.com/389ds/389-ds-base/issues/4224
+
+Reviewed by: tbordaz, droideck (Thank you)
+---
+ .../tests/suites/retrocl/basic_test.py        |  6 ++--
+ .../lib389/cli_conf/plugins/retrochangelog.py | 35 +++++++++++++++++--
+ 2 files changed, 36 insertions(+), 5 deletions(-)
+
+diff --git a/dirsrvtests/tests/suites/retrocl/basic_test.py b/dirsrvtests/tests/suites/retrocl/basic_test.py
+index 112c73cb9..f3bc50f29 100644
+--- a/dirsrvtests/tests/suites/retrocl/basic_test.py
++++ b/dirsrvtests/tests/suites/retrocl/basic_test.py
+@@ -17,7 +17,7 @@ from lib389.utils import *
+ from lib389.tasks import *
+ from lib389.cli_base import FakeArgs, connect_instance, disconnect_instance
+ from lib389.cli_base.dsrc import dsrc_arg_concat
+-from lib389.cli_conf.plugins.retrochangelog import retrochangelog_add
++from lib389.cli_conf.plugins.retrochangelog import retrochangelog_add_attr
+ from lib389.idm.user import UserAccount, UserAccounts, nsUserAccounts
+ 
+ pytestmark = pytest.mark.tier1
+@@ -122,7 +122,7 @@ def test_retrocl_exclude_attr_add(topology_st):
+     args.bindpw = None
+     args.prompt = False
+     args.exclude_attrs = ATTR_HOMEPHONE
+-    args.func = retrochangelog_add
++    args.func = retrochangelog_add_attr
+     dsrc_inst = dsrc_arg_concat(args, None)
+     inst = connect_instance(dsrc_inst, False, args)
+     result = args.func(inst, None, log, args)
+@@ -255,7 +255,7 @@ def test_retrocl_exclude_attr_mod(topology_st):
+     args.bindpw = None
+     args.prompt = False
+     args.exclude_attrs = ATTR_CARLICENSE
+-    args.func = retrochangelog_add
++    args.func = retrochangelog_add_attr
+     dsrc_inst = dsrc_arg_concat(args, None)
+     inst = connect_instance(dsrc_inst, False, args)
+     result = args.func(inst, None, log, args)
+diff --git a/src/lib389/lib389/cli_conf/plugins/retrochangelog.py b/src/lib389/lib389/cli_conf/plugins/retrochangelog.py
+index 9940c6532..160fbb82d 100644
+--- a/src/lib389/lib389/cli_conf/plugins/retrochangelog.py
++++ b/src/lib389/lib389/cli_conf/plugins/retrochangelog.py
+@@ -6,8 +6,13 @@
+ # See LICENSE for details.
+ # --- END COPYRIGHT BLOCK ---
+ 
++# JC Work around for missing dependency on https://github.com/389ds/389-ds-base/pull/4344
++import ldap
++
+ from lib389.plugins import RetroChangelogPlugin
+-from lib389.cli_conf import add_generic_plugin_parsers, generic_object_edit
++# JC Work around for missing dependency https://github.com/389ds/389-ds-base/pull/4344
++# from lib389.cli_conf import add_generic_plugin_parsers, generic_object_edit, generic_object_add_attr
++from lib389.cli_conf import add_generic_plugin_parsers, generic_object_edit, _args_to_attrs
+ 
+ arg_to_attr = {
+     'is_replicated': 'isReplicated',
+@@ -18,12 +23,38 @@ arg_to_attr = {
+     'exclude_attrs': 'nsslapd-exclude-attrs'
+ }
+ 
+-
+ def retrochangelog_edit(inst, basedn, log, args):
+     log = log.getChild('retrochangelog_edit')
+     plugin = RetroChangelogPlugin(inst)
+     generic_object_edit(plugin, log, args, arg_to_attr)
+ 
++# JC Work around for missing dependency https://github.com/389ds/389-ds-base/pull/4344
++def retrochangelog_add_attr(inst, basedn, log, args):
++    log = log.getChild('retrochangelog_add_attr')
++    plugin = RetroChangelogPlugin(inst)
++    generic_object_add_attr(plugin, log, args, arg_to_attr)
++
++# JC Work around for missing dependency https://github.com/389ds/389-ds-base/pull/4344
++def generic_object_add_attr(dsldap_object, log, args, arg_to_attr):
++    """Add an attribute to the entry. This differs to 'edit' as edit uses replace,
++    and this allows multivalues to be added.
++
++    dsldap_object should be a single instance of DSLdapObject with a set dn
++    """
++    log = log.getChild('generic_object_add_attr')
++    # Gather the attributes
++    attrs = _args_to_attrs(args, arg_to_attr)
++
++    modlist = []
++    for attr, value in attrs.items():
++        if not isinstance(value, list):
++            value = [value]
++        modlist.append((ldap.MOD_ADD, attr, value))
++    if len(modlist) > 0:
++        dsldap_object.apply_mods(modlist)
++        log.info("Successfully changed the %s", dsldap_object.dn)
++    else:
++        raise ValueError("There is nothing to set in the %s plugin entry" % dsldap_object.dn)
+ 
+ def _add_parser_args(parser):
+     parser.add_argument('--is-replicated', choices=['TRUE', 'FALSE'], type=str.upper,
+-- 
+2.31.1
+
diff --git a/SOURCES/0022-Issue-4656-remove-problematic-language-from-ds-replc.patch b/SOURCES/0022-Issue-4656-remove-problematic-language-from-ds-replc.patch
new file mode 100644
index 0000000..82d6945
--- /dev/null
+++ b/SOURCES/0022-Issue-4656-remove-problematic-language-from-ds-replc.patch
@@ -0,0 +1,642 @@
+From d2ac7e98d53cfe6c74c99ddf3504b1072418f05a Mon Sep 17 00:00:00 2001
+From: Mark Reynolds <mreynolds@redhat.com>
+Date: Thu, 11 Mar 2021 10:12:46 -0500
+Subject: [PATCH] Issue 4656 - remove problematic language from ds-replcheck
+
+Description: remove master from ds-replcheck and replace it with supplier
+
+relates: https://github.com/389ds/389-ds-base/issues/4656
+
+Reviewed by: mreynolds
+
+e with '#' will be ignored, and an empty message aborts the commit.
+---
+ ldap/admin/src/scripts/ds-replcheck | 202 ++++++++++++++--------------
+ 1 file changed, 101 insertions(+), 101 deletions(-)
+
+diff --git a/ldap/admin/src/scripts/ds-replcheck b/ldap/admin/src/scripts/ds-replcheck
+index 169496e8f..f411f357a 100755
+--- a/ldap/admin/src/scripts/ds-replcheck
++++ b/ldap/admin/src/scripts/ds-replcheck
+@@ -1,7 +1,7 @@
+ #!/usr/bin/python3
+ 
+ # --- BEGIN COPYRIGHT BLOCK ---
+-# Copyright (C) 2020 Red Hat, Inc.
++# Copyright (C) 2021 Red Hat, Inc.
+ # All rights reserved.
+ #
+ # License: GPL (version 3 or any later version).
+@@ -63,7 +63,7 @@ def remove_entry(rentries, dn):
+ def get_ruv_time(ruv, rid):
+     """Take a RUV element (nsds50ruv attribute) and extract the timestamp from maxcsn
+     :param ruv - A lsit of RUV elements
+-    :param rid - The rid of the master to extractthe maxcsn time from
++    :param rid - The rid of the supplier to extract the maxcsn time from
+     :return: The time in seconds of the maxcsn, or 0 if there is no maxcsn, or -1 if
+              the rid was not found
+     """
+@@ -213,22 +213,22 @@ def get_ruv_state(opts):
+     :param opts - all the script options
+     :return - A text description of the replicaton state
+     """
+-    mtime = get_ruv_time(opts['master_ruv'], opts['rid'])
++    mtime = get_ruv_time(opts['supplier_ruv'], opts['rid'])
+     rtime = get_ruv_time(opts['replica_ruv'], opts['rid'])
+     if mtime == -1:
+-        repl_state = "Replication State: Replica ID ({}) not found in Master's RUV".format(opts['rid'])
++        repl_state = "Replication State: Replica ID ({}) not found in Supplier's RUV".format(opts['rid'])
+     elif rtime == -1:
+         repl_state = "Replication State: Replica ID ({}) not found in Replica's RUV (not initialized?)".format(opts['rid'])
+     elif mtime == 0:
+-        repl_state = "Replication State: Master has not seen any updates"
++        repl_state = "Replication State: Supplier has not seen any updates"
+     elif rtime == 0:
+-        repl_state = "Replication State: Replica has not seen any changes from the Master"
++        repl_state = "Replication State: Replica has not seen any changes from the Supplier"
+     elif mtime > rtime:
+-        repl_state = "Replication State: Replica is behind Master by: {} seconds".format(mtime - rtime)
++        repl_state = "Replication State: Replica is behind Supplier by: {} seconds".format(mtime - rtime)
+     elif mtime < rtime:
+-        repl_state = "Replication State: Replica is ahead of Master by: {} seconds".format(rtime - mtime)
++        repl_state = "Replication State: Replica is ahead of Supplier by: {} seconds".format(rtime - mtime)
+     else:
+-        repl_state = "Replication State: Master and Replica are in perfect synchronization"
++        repl_state = "Replication State: Supplier and Replica are in perfect synchronization"
+ 
+     return repl_state
+ 
+@@ -238,11 +238,11 @@ def get_ruv_report(opts):
+     :param opts - all the script options
+     :return - A text blob to display in the report
+     """
+-    opts['master_ruv'].sort()
++    opts['supplier_ruv'].sort()
+     opts['replica_ruv'].sort()
+ 
+-    report = "Master RUV:\n"
+-    for element in opts['master_ruv']:
++    report = "Supplier RUV:\n"
++    for element in opts['supplier_ruv']:
+         report += "  %s\n" % (element)
+     report += "\nReplica RUV:\n"
+     for element in opts['replica_ruv']:
+@@ -521,7 +521,7 @@ def get_ldif_ruv(LDIF, opts):
+ 
+ def cmp_entry(mentry, rentry, opts):
+     """Compare the two entries, and return a "diff map"
+-    :param mentry - A Master entry
++    :param mentry - A Supplier entry
+     :param rentry - A Replica entry
+     :param opts - A Dict of the scripts options
+     :return - A Dict of the differences in the entry, or None
+@@ -536,7 +536,7 @@ def cmp_entry(mentry, rentry, opts):
+     mlist = list(mentry.data.keys())
+ 
+     #
+-    # Check master
++    # Check Supplier
+     #
+     for mattr in mlist:
+         if mattr in opts['ignore']:
+@@ -555,7 +555,7 @@ def cmp_entry(mentry, rentry, opts):
+                             if not found:
+                                 diff['missing'].append("")
+                             found = True
+-                            diff['missing'].append(" - Master's State Info: %s" % (val))
++                            diff['missing'].append(" - Supplier's State Info: %s" % (val))
+                             diff['missing'].append(" - Date: %s\n" % (time.ctime(extract_time(val))))
+                 else:
+                     # No state info, just move on
+@@ -566,18 +566,18 @@ def cmp_entry(mentry, rentry, opts):
+             if report_conflict(rentry, mattr, opts) and report_conflict(mentry, mattr, opts):
+                 diff['diff'].append(" - Attribute '%s' is different:" % mattr)
+                 if 'nscpentrywsi' in mentry.data:
+-                    # Process Master
++                    # Process Supplier
+                     found = False
+                     for val in mentry.data['nscpentrywsi']:
+                         if val.lower().startswith(mattr + ';'):
+                             if not found:
+-                                diff['diff'].append("      Master:")
++                                diff['diff'].append("      Supplier:")
+                             diff['diff'].append("        - Value:      %s" % (val.split(':')[1].lstrip()))
+                             diff['diff'].append("        - State Info: %s" % (val))
+                             diff['diff'].append("        - Date:       %s\n" % (time.ctime(extract_time(val))))
+                             found = True
+                     if not found:
+-                        diff['diff'].append("      Master: ")
++                        diff['diff'].append("      Supplier: ")
+                         for val in mentry.data[mattr]:
+                             # This is an "origin" value which means it's never been
+                             # updated since replication was set up.  So its the
+@@ -605,7 +605,7 @@ def cmp_entry(mentry, rentry, opts):
+                         diff['diff'].append("")
+                 else:
+                     # no state info, report what we got
+-                    diff['diff'].append("      Master: ")
++                    diff['diff'].append("      Supplier: ")
+                     for val in mentry.data[mattr]:
+                         diff['diff'].append("        - %s: %s" % (mattr, val))
+                     diff['diff'].append("      Replica: ")
+@@ -622,9 +622,9 @@ def cmp_entry(mentry, rentry, opts):
+             continue
+ 
+         if rattr not in mlist:
+-            # Master is missing the attribute
++            # Supplier is missing the attribute
+             if report_conflict(rentry, rattr, opts):
+-                diff['missing'].append(" - Master missing attribute: \"%s\"" % (rattr))
++                diff['missing'].append(" - Supplier missing attribute: \"%s\"" % (rattr))
+                 diff_count += 1
+                 if 'nscpentrywsi' in rentry.data:
+                     found = False
+@@ -663,7 +663,7 @@ def do_offline_report(opts, output_file=None):
+     try:
+         MLDIF = open(opts['mldif'], "r")
+     except Exception as e:
+-        print('Failed to open Master LDIF: ' + str(e))
++        print('Failed to open Supplier LDIF: ' + str(e))
+         return
+ 
+     try:
+@@ -676,10 +676,10 @@ def do_offline_report(opts, output_file=None):
+     # Verify LDIF Files
+     try:
+         if opts['verbose']:
+-            print("Validating Master ldif file ({})...".format(opts['mldif']))
++            print("Validating Supplier ldif file ({})...".format(opts['mldif']))
+         LDIFRecordList(MLDIF).parse()
+     except ValueError:
+-        print('Master LDIF file in invalid, aborting...')
++        print('Supplier LDIF file in invalid, aborting...')
+         MLDIF.close()
+         RLDIF.close()
+         return
+@@ -696,34 +696,34 @@ def do_offline_report(opts, output_file=None):
+     # Get all the dn's, and entry counts
+     if opts['verbose']:
+         print ("Gathering all the DN's...")
+-    master_dns = get_dns(MLDIF, opts['mldif'], opts)
++    supplier_dns = get_dns(MLDIF, opts['mldif'], opts)
+     replica_dns = get_dns(RLDIF, opts['rldif'], opts)
+-    if master_dns is None or replica_dns is None:
++    if supplier_dns is None or replica_dns is None:
+         print("Aborting scan...")
+         MLDIF.close()
+         RLDIF.close()
+         sys.exit(1)
+-    m_count = len(master_dns)
++    m_count = len(supplier_dns)
+     r_count = len(replica_dns)
+ 
+     # Get DB RUV
+     if opts['verbose']:
+         print ("Gathering the database RUV's...")
+-    opts['master_ruv'] = get_ldif_ruv(MLDIF, opts)
++    opts['supplier_ruv'] = get_ldif_ruv(MLDIF, opts)
+     opts['replica_ruv'] = get_ldif_ruv(RLDIF, opts)
+ 
+-    """ Compare the master entries with the replica's.  Take our list of dn's from
+-    the master ldif and get that entry( dn) from the master and replica ldif.  In
++    """ Compare the Supplier entries with the replica's.  Take our list of dn's from
++    the Supplier ldif and get that entry( dn) from the Supplier and replica ldif.  In
+     this phase we keep keep track of conflict/tombstone counts, and we check for
+     missing entries and entry differences.   We only need to do the entry diff
+     checking in this phase - we do not need to do it when process the replica dn's
+     because if the entry exists in both LDIF's then we already checked or diffs
+-    while processing the master dn's.
++    while processing the Supplier dn's.
+     """
+     if opts['verbose']:
+-        print ("Comparing Master to Replica...")
++        print ("Comparing Supplier to Replica...")
+     missing = False
+-    for dn in master_dns:
++    for dn in supplier_dns:
+         mresult = ldif_search(MLDIF, dn)
+         if mresult['entry'] is None and mresult['conflict'] is None and not mresult['tombstone']:
+             # Try from the beginning
+@@ -736,7 +736,7 @@ def do_offline_report(opts, output_file=None):
+                 rresult['conflict'] is not None or rresult['tombstone']):
+                 """ We can safely remove this DN from the replica dn list as it
+                 does not need to be checked again.  This also speeds things up
+-                when doing the replica vs master phase.
++                when doing the replica vs Supplier phase.
+                 """
+                 replica_dns.remove(dn)
+ 
+@@ -766,7 +766,7 @@ def do_offline_report(opts, output_file=None):
+                         missing_report += ('  Entries missing on Replica:\n')
+                         missing = True
+                     if mresult['entry'] and 'createtimestamp' in mresult['entry'].data:
+-                        missing_report += ('   - %s  (Created on Master at: %s)\n' %
++                        missing_report += ('   - %s  (Created on Supplier at: %s)\n' %
+                                            (dn, convert_timestamp(mresult['entry'].data['createtimestamp'][0])))
+                     else:
+                         missing_report += ('  - %s\n' % dn)
+@@ -791,7 +791,7 @@ def do_offline_report(opts, output_file=None):
+     remaining conflict & tombstone entries as well.
+     """
+     if opts['verbose']:
+-        print ("Comparing Replica to Master...")
++        print ("Comparing Replica to Supplier...")
+     MLDIF.seek(0)
+     RLDIF.seek(0)
+     missing = False
+@@ -811,7 +811,7 @@ def do_offline_report(opts, output_file=None):
+             if mresult['entry'] is None and mresult['glue'] is None:
+                 MLDIF.seek(rresult['idx'])  # Set the LDIF cursor/index to the last good line
+                 if not missing:
+-                    missing_report += ('  Entries missing on Master:\n')
++                    missing_report += ('  Entries missing on Supplier:\n')
+                     missing = True
+                 if rresult['entry'] and 'createtimestamp' in rresult['entry'].data:
+                     missing_report += ('   - %s  (Created on Replica at: %s)\n' %
+@@ -837,12 +837,12 @@ def do_offline_report(opts, output_file=None):
+     final_report += get_ruv_report(opts)
+     final_report += ('Entry Counts\n')
+     final_report += ('=====================================================\n\n')
+-    final_report += ('Master:  %d\n' % (m_count))
++    final_report += ('Supplier:  %d\n' % (m_count))
+     final_report += ('Replica: %d\n\n' % (r_count))
+ 
+     final_report += ('\nTombstones\n')
+     final_report += ('=====================================================\n\n')
+-    final_report += ('Master:  %d\n' % (mtombstones))
++    final_report += ('Supplier:  %d\n' % (mtombstones))
+     final_report += ('Replica: %d\n' % (rtombstones))
+ 
+     final_report += get_conflict_report(mconflicts, rconflicts, opts['conflicts'])
+@@ -859,9 +859,9 @@ def do_offline_report(opts, output_file=None):
+     final_report += ('\nResult\n')
+     final_report += ('=====================================================\n\n')
+     if missing_report == "" and len(diff_report) == 0:
+-        final_report += ('No replication differences between Master and Replica\n')
++        final_report += ('No replication differences between Supplier and Replica\n')
+     else:
+-        final_report += ('There are replication differences between Master and Replica\n')
++        final_report += ('There are replication differences between Supplier and Replica\n')
+ 
+     if output_file:
+         output_file.write(final_report)
+@@ -871,8 +871,8 @@ def do_offline_report(opts, output_file=None):
+ 
+ def check_for_diffs(mentries, mglue, rentries, rglue, report, opts):
+     """Online mode only - Check for diffs, return the updated report
+-    :param mentries - Master entries
+-    :param mglue - Master glue entries
++    :param mentries - Supplier entries
++    :param mglue - Supplier glue entries
+     :param rentries - Replica entries
+     :param rglue - Replica glue entries
+     :param report - A Dict of the entire report
+@@ -947,8 +947,8 @@ def validate_suffix(ldapnode, suffix, hostname):
+     # Check suffix is replicated
+     try:
+         replica_filter = "(&(objectclass=nsds5replica)(nsDS5ReplicaRoot=%s))" % suffix
+-        master_replica = ldapnode.search_s("cn=config",ldap.SCOPE_SUBTREE,replica_filter)
+-        if (len(master_replica) != 1):
++        supplier_replica = ldapnode.search_s("cn=config",ldap.SCOPE_SUBTREE,replica_filter)
++        if (len(supplier_replica) != 1):
+             print("Error: Failed to validate suffix in {}. {} is not replicated.".format(hostname, suffix))
+             return False
+     except ldap.LDAPError as e:
+@@ -969,7 +969,7 @@ def connect_to_replicas(opts):
+         muri = "%s://%s" % (opts['mprotocol'], opts['mhost'].replace("/", "%2f"))
+     else:
+         muri = "%s://%s:%s/" % (opts['mprotocol'], opts['mhost'], opts['mport'])
+-    master = SimpleLDAPObject(muri)
++    supplier = SimpleLDAPObject(muri)
+ 
+     if opts['rprotocol'].lower() == 'ldapi':
+         ruri = "%s://%s" % (opts['rprotocol'], opts['rhost'].replace("/", "%2f"))
+@@ -978,23 +978,23 @@ def connect_to_replicas(opts):
+     replica = SimpleLDAPObject(ruri)
+ 
+     # Set timeouts
+-    master.set_option(ldap.OPT_NETWORK_TIMEOUT, opts['timeout'])
+-    master.set_option(ldap.OPT_TIMEOUT, opts['timeout'])
++    supplier.set_option(ldap.OPT_NETWORK_TIMEOUT, opts['timeout'])
++    supplier.set_option(ldap.OPT_TIMEOUT, opts['timeout'])
+     replica.set_option(ldap.OPT_NETWORK_TIMEOUT, opts['timeout'])
+     replica.set_option(ldap.OPT_TIMEOUT, opts['timeout'])
+ 
+     # Setup Secure Connection
+     if opts['certdir'] is not None:
+-        # Setup Master
++        # Setup Supplier
+         if opts['mprotocol'] != LDAPI:
+-            master.set_option(ldap.OPT_X_TLS_CACERTDIR, opts['certdir'])
+-            master.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_HARD)
++            supplier.set_option(ldap.OPT_X_TLS_CACERTDIR, opts['certdir'])
++            supplier.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_HARD)
+             if opts['mprotocol'] == LDAP:
+                 # Do StartTLS
+                 try:
+-                    master.start_tls_s()
++                    supplier.start_tls_s()
+                 except ldap.LDAPError as e:
+-                    print('TLS negotiation failed on Master: {}'.format(str(e)))
++                    print('TLS negotiation failed on Supplier: {}'.format(str(e)))
+                     exit(1)
+ 
+         # Setup Replica
+@@ -1006,17 +1006,17 @@ def connect_to_replicas(opts):
+                 try:
+                     replica.start_tls_s()
+                 except ldap.LDAPError as e:
+-                    print('TLS negotiation failed on Master: {}'.format(str(e)))
++                    print('TLS negotiation failed on Supplier: {}'.format(str(e)))
+                     exit(1)
+ 
+-    # Open connection to master
++    # Open connection to Supplier
+     try:
+-        master.simple_bind_s(opts['binddn'], opts['bindpw'])
++        supplier.simple_bind_s(opts['binddn'], opts['bindpw'])
+     except ldap.SERVER_DOWN as e:
+         print(f"Cannot connect to {muri} ({str(e)})")
+         sys.exit(1)
+     except ldap.LDAPError as e:
+-        print("Error: Failed to authenticate to Master: ({}).  "
++        print("Error: Failed to authenticate to Supplier: ({}).  "
+               "Please check your credentials and LDAP urls are correct.".format(str(e)))
+         sys.exit(1)
+ 
+@@ -1034,7 +1034,7 @@ def connect_to_replicas(opts):
+     # Validate suffix
+     if opts['verbose']:
+         print ("Validating suffix ...")
+-    if not validate_suffix(master, opts['suffix'], opts['mhost']):
++    if not validate_suffix(supplier, opts['suffix'], opts['mhost']):
+       sys.exit(1)
+ 
+     if not validate_suffix(replica,opts['suffix'], opts['rhost']):
+@@ -1042,16 +1042,16 @@ def connect_to_replicas(opts):
+ 
+     # Get the RUVs
+     if opts['verbose']:
+-        print ("Gathering Master's RUV...")
++        print ("Gathering Supplier's RUV...")
+     try:
+-        master_ruv = master.search_s(opts['suffix'], ldap.SCOPE_SUBTREE, RUV_FILTER, ['nsds50ruv'])
+-        if len(master_ruv) > 0:
+-            opts['master_ruv'] = ensure_list_str(master_ruv[0][1]['nsds50ruv'])
++        supplier_ruv = supplier.search_s(opts['suffix'], ldap.SCOPE_SUBTREE, RUV_FILTER, ['nsds50ruv'])
++        if len(supplier_ruv) > 0:
++            opts['supplier_ruv'] = ensure_list_str(supplier_ruv[0][1]['nsds50ruv'])
+         else:
+-            print("Error: Master does not have an RUV entry")
++            print("Error: Supplier does not have an RUV entry")
+             sys.exit(1)
+     except ldap.LDAPError as e:
+-        print("Error: Failed to get Master RUV entry: {}".format(str(e)))
++        print("Error: Failed to get Supplier RUV entry: {}".format(str(e)))
+         sys.exit(1)
+ 
+     if opts['verbose']:
+@@ -1067,12 +1067,12 @@ def connect_to_replicas(opts):
+         print("Error: Failed to get Replica RUV entry: {}".format(str(e)))
+         sys.exit(1)
+ 
+-    # Get the master RID
++    # Get the Supplier RID
+     if opts['verbose']:
+-        print("Getting Master's replica ID")
++        print("Getting Supplier's replica ID")
+     try:
+         search_filter = "(&(objectclass=nsds5Replica)(nsDS5ReplicaRoot={})(nsDS5ReplicaId=*))".format(opts['suffix'])
+-        replica_entry = master.search_s("cn=config", ldap.SCOPE_SUBTREE, search_filter)
++        replica_entry = supplier.search_s("cn=config", ldap.SCOPE_SUBTREE, search_filter)
+         if len(replica_entry) > 0:
+             opts['rid'] = ensure_int(replica_entry[0][1]['nsDS5ReplicaId'][0])
+         else:
+@@ -1081,7 +1081,7 @@ def connect_to_replicas(opts):
+         print("Error: Failed to get Replica entry: {}".format(str(e)))
+         sys.exit(1)
+ 
+-    return (master, replica, opts)
++    return (supplier, replica, opts)
+ 
+ 
+ def print_online_report(report, opts, output_file):
+@@ -1104,11 +1104,11 @@ def print_online_report(report, opts, output_file):
+     final_report += get_ruv_report(opts)
+     final_report += ('Entry Counts\n')
+     final_report += ('=====================================================\n\n')
+-    final_report += ('Master:  %d\n' % (report['m_count']))
++    final_report += ('Supplier:  %d\n' % (report['m_count']))
+     final_report += ('Replica: %d\n\n' % (report['r_count']))
+     final_report += ('\nTombstones\n')
+     final_report += ('=====================================================\n\n')
+-    final_report += ('Master:  %d\n' % (report['mtombstones']))
++    final_report += ('Supplier:  %d\n' % (report['mtombstones']))
+     final_report += ('Replica: %d\n' % (report['rtombstones']))
+     final_report += report['conflict']
+     missing = False
+@@ -1121,7 +1121,7 @@ def print_online_report(report, opts, output_file):
+             final_report += ('  Entries missing on Replica:\n')
+             for entry in report['r_missing']:
+                 if 'createtimestamp' in entry.data:
+-                    final_report += ('   - %s  (Created on Master at: %s)\n' %
++                    final_report += ('   - %s  (Created on Supplier at: %s)\n' %
+                                      (entry.dn, convert_timestamp(entry.data['createtimestamp'][0])))
+                 else:
+                     final_report += ('   - %s\n' % (entry.dn))
+@@ -1129,7 +1129,7 @@ def print_online_report(report, opts, output_file):
+         if m_missing > 0:
+             if r_missing > 0:
+                 final_report += ('\n')
+-            final_report += ('  Entries missing on Master:\n')
++            final_report += ('  Entries missing on Supplier:\n')
+             for entry in report['m_missing']:
+                 if 'createtimestamp' in entry.data:
+                     final_report += ('   - %s  (Created on Replica at: %s)\n' %
+@@ -1146,9 +1146,9 @@ def print_online_report(report, opts, output_file):
+     final_report += ('\nResult\n')
+     final_report += ('=====================================================\n\n')
+     if not missing and len(report['diff']) == 0:
+-        final_report += ('No replication differences between Master and Replica\n')
++        final_report += ('No replication differences between Supplier and Replica\n')
+     else:
+-        final_report += ('There are replication differences between Master and Replica\n')
++        final_report += ('There are replication differences between Supplier and Replica\n')
+ 
+     if output_file:
+         output_file.write(final_report)
+@@ -1170,7 +1170,7 @@ def remove_state_info(entry):
+ 
+ def get_conflict_report(mentries, rentries, verbose):
+     """Gather the conflict entry dn's for each replica
+-    :param mentries - Master entries
++    :param mentries - Supplier entries
+     :param rentries - Replica entries
+     :param verbose - verbose logging
+     :return - A text blob to dispaly in the report
+@@ -1197,7 +1197,7 @@ def get_conflict_report(mentries, rentries, verbose):
+         report = "\n\nConflict Entries\n"
+         report += "=====================================================\n\n"
+         if len(m_conflicts) > 0:
+-            report += ('Master Conflict Entries:  %d\n' % (len(m_conflicts)))
++            report += ('Supplier Conflict Entries:  %d\n' % (len(m_conflicts)))
+             if verbose:
+                 for entry in m_conflicts:
+                     report += ('\n - %s\n' % (entry['dn']))
+@@ -1239,8 +1239,8 @@ def do_online_report(opts, output_file=None):
+     rconflicts = []
+     mconflicts = []
+ 
+-    # Fire off paged searches on Master and Replica
+-    master, replica, opts = connect_to_replicas(opts)
++    # Fire off paged searches on Supplier and Replica
++    supplier, replica, opts = connect_to_replicas(opts)
+ 
+     if opts['verbose']:
+         print('Start searching and comparing...')
+@@ -1248,12 +1248,12 @@ def do_online_report(opts, output_file=None):
+     controls = [paged_ctrl]
+     req_pr_ctrl = controls[0]
+     try:
+-        master_msgid = master.search_ext(opts['suffix'], ldap.SCOPE_SUBTREE,
+-                                         "(|(objectclass=*)(objectclass=ldapsubentry)(objectclass=nstombstone))",
+-                                         ['*', 'createtimestamp', 'nscpentrywsi', 'nsds5replconflict'],
+-                                         serverctrls=controls)
++        supplier_msgid = supplier.search_ext(opts['suffix'], ldap.SCOPE_SUBTREE,
++                                             "(|(objectclass=*)(objectclass=ldapsubentry)(objectclass=nstombstone))",
++                                             ['*', 'createtimestamp', 'nscpentrywsi', 'nsds5replconflict'],
++                                             serverctrls=controls)
+     except ldap.LDAPError as e:
+-        print("Error: Failed to get Master entries: %s", str(e))
++        print("Error: Failed to get Supplier entries: %s", str(e))
+         sys.exit(1)
+     try:
+         replica_msgid = replica.search_ext(opts['suffix'], ldap.SCOPE_SUBTREE,
+@@ -1268,11 +1268,11 @@ def do_online_report(opts, output_file=None):
+     while not m_done or not r_done:
+         try:
+             if not m_done:
+-                m_rtype, m_rdata, m_rmsgid, m_rctrls = master.result3(master_msgid)
++                m_rtype, m_rdata, m_rmsgid, m_rctrls = supplier.result3(supplier_msgid)
+             elif not r_done:
+                 m_rdata = []
+         except ldap.LDAPError as e:
+-            print("Error: Problem getting the results from the master: %s", str(e))
++            print("Error: Problem getting the results from the Supplier: %s", str(e))
+             sys.exit(1)
+         try:
+             if not r_done:
+@@ -1299,7 +1299,7 @@ def do_online_report(opts, output_file=None):
+                                  report, opts)
+ 
+         if not m_done:
+-            # Master
++            # Supplier
+             m_pctrls = [
+                 c
+                 for c in m_rctrls
+@@ -1310,11 +1310,11 @@ def do_online_report(opts, output_file=None):
+                     try:
+                         # Copy cookie from response control to request control
+                         req_pr_ctrl.cookie = m_pctrls[0].cookie
+-                        master_msgid = master.search_ext(opts['suffix'], ldap.SCOPE_SUBTREE,
++                        supplier_msgid = supplier.search_ext(opts['suffix'], ldap.SCOPE_SUBTREE,
+                             "(|(objectclass=*)(objectclass=ldapsubentry))",
+                             ['*', 'createtimestamp', 'nscpentrywsi', 'conflictcsn', 'nsds5replconflict'], serverctrls=controls)
+                     except ldap.LDAPError as e:
+-                        print("Error: Problem searching the master: %s", str(e))
++                        print("Error: Problem searching the Supplier: %s", str(e))
+                         sys.exit(1)
+                 else:
+                     m_done = True  # No more pages available
+@@ -1354,7 +1354,7 @@ def do_online_report(opts, output_file=None):
+     print_online_report(report, opts, output_file)
+ 
+     # unbind
+-    master.unbind_s()
++    supplier.unbind_s()
+     replica.unbind_s()
+ 
+ 
+@@ -1367,18 +1367,18 @@ def init_online_params(args):
+ 
+     # Make sure the URLs are different
+     if args.murl == args.rurl:
+-        print("Master and Replica LDAP URLs are the same, they must be different")
++        print("Supplier and Replica LDAP URLs are the same, they must be different")
+         sys.exit(1)
+ 
+-    # Parse Master url
++    # Parse Supplier url
+     if not ldapurl.isLDAPUrl(args.murl):
+-        print("Master LDAP URL is invalid")
++        print("Supplier LDAP URL is invalid")
+         sys.exit(1)
+     murl = ldapurl.LDAPUrl(args.murl)
+     if murl.urlscheme in VALID_PROTOCOLS:
+         opts['mprotocol'] = murl.urlscheme
+     else:
+-        print('Unsupported ldap url protocol (%s) for Master, please use "ldaps" or "ldap"' %
++        print('Unsupported ldap url protocol (%s) for Supplier, please use "ldaps" or "ldap"' %
+               murl.urlscheme)
+         sys.exit(1)
+ 
+@@ -1520,7 +1520,7 @@ def offline_report(args):
+             print ("LDIF file ({}) is empty".format(ldif_dir))
+             sys.exit(1)
+     if opts['mldif'] == opts['rldif']:
+-        print("The Master and Replica LDIF files must be different")
++        print("The Supplier and Replica LDIF files must be different")
+         sys.exit(1)
+ 
+     OUTPUT_FILE = None
+@@ -1547,7 +1547,7 @@ def get_state(args):
+     """Just do the RUV comparision
+     """
+     opts = init_online_params(args)
+-    master, replica, opts = connect_to_replicas(opts)
++    supplier, replica, opts = connect_to_replicas(opts)
+     print(get_ruv_state(opts))
+ 
+ 
+@@ -1569,10 +1569,10 @@ def main():
+     # Get state
+     state_parser = subparsers.add_parser('state', help="Get the current replicaton state between two replicas")
+     state_parser.set_defaults(func=get_state)
+-    state_parser.add_argument('-m', '--master-url', help='The LDAP URL for the Master server',
+-                               dest='murl', default=None, required=True)
++    state_parser.add_argument('-m', '--supplier-url', help='The LDAP URL for the Supplier server',
++                              dest='murl', default=None, required=True)
+     state_parser.add_argument('-r', '--replica-url', help='The LDAP URL for the Replica server',
+-                               dest='rurl', required=True, default=None)
++                              dest='rurl', required=True, default=None)
+     state_parser.add_argument('-b', '--suffix', help='Replicated suffix', dest='suffix', required=True)
+     state_parser.add_argument('-D', '--bind-dn', help='The Bind DN', required=True, dest='binddn', default=None)
+     state_parser.add_argument('-w', '--bind-pw', help='The Bind password', dest='bindpw', default=None)
+@@ -1586,7 +1586,7 @@ def main():
+     # Online mode
+     online_parser = subparsers.add_parser('online', help="Compare two online replicas for differences")
+     online_parser.set_defaults(func=online_report)
+-    online_parser.add_argument('-m', '--master-url', help='The LDAP URL for the Master server (REQUIRED)',
++    online_parser.add_argument('-m', '--supplier-url', help='The LDAP URL for the Supplier server (REQUIRED)',
+                                dest='murl', default=None, required=True)
+     online_parser.add_argument('-r', '--replica-url', help='The LDAP URL for the Replica server (REQUIRED)',
+                                dest='rurl', required=True, default=None)
+@@ -1612,12 +1612,12 @@ def main():
+     # Offline LDIF mode
+     offline_parser = subparsers.add_parser('offline', help="Compare two replication LDIF files for differences (LDIF file generated by 'db2ldif -r')")
+     offline_parser.set_defaults(func=offline_report)
+-    offline_parser.add_argument('-m', '--master-ldif', help='Master LDIF file',
++    offline_parser.add_argument('-m', '--supplier-ldif', help='Supplier LDIF file',
+                                 dest='mldif', default=None, required=True)
+     offline_parser.add_argument('-r', '--replica-ldif', help='Replica LDIF file',
+                                 dest='rldif', default=None, required=True)
+     offline_parser.add_argument('--rid', dest='rid', default=None, required=True,
+-                                help='The Replica Identifer (rid) for the "Master" server')
++                                help='The Replica Identifier (rid) for the "Supplier" server')
+     offline_parser.add_argument('-b', '--suffix', help='Replicated suffix', dest='suffix', required=True)
+     offline_parser.add_argument('-c', '--conflicts', help='Display verbose conflict information', action='store_true',
+                                 dest='conflicts', default=False)
+-- 
+2.31.1
+
diff --git a/SOURCES/0023-Issue-4443-Internal-unindexed-searches-in-syncrepl-r.patch b/SOURCES/0023-Issue-4443-Internal-unindexed-searches-in-syncrepl-r.patch
new file mode 100644
index 0000000..3fd6f16
--- /dev/null
+++ b/SOURCES/0023-Issue-4443-Internal-unindexed-searches-in-syncrepl-r.patch
@@ -0,0 +1,373 @@
+From 55a47c1bfe1ce1c27e470384c4f1d50895db25f7 Mon Sep 17 00:00:00 2001
+From: Mark Reynolds <mreynolds@redhat.com>
+Date: Tue, 13 Jul 2021 14:18:03 -0400
+Subject: [PATCH] Issue 4443 - Internal unindexed searches in syncrepl/retro
+ changelog
+
+Bug Description:
+
+When a non-system index is added to a backend it is
+disabled until the database is initialized or reindexed.
+So in the case of the retro changelog the changenumber index
+is alway disabled by default since it is never initialized.
+This leads to unexpected unindexed searches of the retro
+changelog.
+
+Fix Description:
+
+If an index has "nsSystemIndex" set to "true" then enable it
+immediately.
+
+relates:  https://github.com/389ds/389-ds-base/issues/4443
+
+Reviewed by: spichugi & tbordaz(Thanks!!)
+---
+ .../tests/suites/retrocl/basic_test.py        | 53 ++++++++-------
+ .../suites/retrocl/retrocl_indexing_test.py   | 68 +++++++++++++++++++
+ ldap/servers/plugins/retrocl/retrocl_create.c |  2 +-
+ .../slapd/back-ldbm/ldbm_index_config.c       | 25 +++++--
+ src/lib389/lib389/_mapped_object.py           | 13 ++++
+ 5 files changed, 130 insertions(+), 31 deletions(-)
+ create mode 100644 dirsrvtests/tests/suites/retrocl/retrocl_indexing_test.py
+
+diff --git a/dirsrvtests/tests/suites/retrocl/basic_test.py b/dirsrvtests/tests/suites/retrocl/basic_test.py
+index f3bc50f29..84d513829 100644
+--- a/dirsrvtests/tests/suites/retrocl/basic_test.py
++++ b/dirsrvtests/tests/suites/retrocl/basic_test.py
+@@ -8,7 +8,6 @@
+ 
+ import logging
+ import ldap
+-import time
+ import pytest
+ from lib389.topologies import topology_st
+ from lib389.plugins import RetroChangelogPlugin
+@@ -18,7 +17,8 @@ from lib389.tasks import *
+ from lib389.cli_base import FakeArgs, connect_instance, disconnect_instance
+ from lib389.cli_base.dsrc import dsrc_arg_concat
+ from lib389.cli_conf.plugins.retrochangelog import retrochangelog_add_attr
+-from lib389.idm.user import UserAccount, UserAccounts, nsUserAccounts
++from lib389.idm.user import UserAccount, UserAccounts
++from lib389._mapped_object import DSLdapObjects
+ 
+ pytestmark = pytest.mark.tier1
+ 
+@@ -82,7 +82,7 @@ def test_retrocl_exclude_attr_add(topology_st):
+ 
+     log.info('Adding user1')
+     try:
+-        user1 = users.create(properties={
++        users.create(properties={
+             'sn': '1',
+             'cn': 'user 1',
+             'uid': 'user1',
+@@ -97,17 +97,18 @@ def test_retrocl_exclude_attr_add(topology_st):
+     except ldap.ALREADY_EXISTS:
+         pass
+     except ldap.LDAPError as e:
+-        log.error("Failed to add user1")
++        log.error("Failed to add user1: " + str(e))
+ 
+     log.info('Verify homePhone and carLicense attrs are in the changelog changestring')
+     try:
+-        cllist = st.search_s(RETROCL_SUFFIX, ldap.SCOPE_SUBTREE, '(targetDn=%s)' % USER1_DN)
++        retro_changelog_suffix = DSLdapObjects(st, basedn=RETROCL_SUFFIX)
++        cllist = retro_changelog_suffix.filter(f'(targetDn={USER1_DN})')
+     except ldap.LDAPError as e:
+-        log.fatal("Changelog search failed, error: " +str(e))
++        log.fatal("Changelog search failed, error: " + str(e))
+         assert False
+     assert len(cllist) > 0
+-    if  cllist[0].hasAttr('changes'):
+-        clstr = (cllist[0].getValue('changes')).decode()
++    if  cllist[0].present('changes'):
++        clstr = str(cllist[0].get_attr_vals_utf8('changes'))
+         assert ATTR_HOMEPHONE in clstr
+         assert ATTR_CARLICENSE in clstr
+ 
+@@ -134,7 +135,7 @@ def test_retrocl_exclude_attr_add(topology_st):
+ 
+     log.info('Adding user2')
+     try:
+-        user2 = users.create(properties={
++        users.create(properties={
+             'sn': '2',
+             'cn': 'user 2',
+             'uid': 'user2',
+@@ -149,18 +150,18 @@ def test_retrocl_exclude_attr_add(topology_st):
+     except ldap.ALREADY_EXISTS:
+         pass
+     except ldap.LDAPError as e:
+-        log.error("Failed to add user2")
++        log.error("Failed to add user2: " + str(e))
+ 
+     log.info('Verify homePhone attr is not in the changelog changestring')
+     try:
+-        cllist = st.search_s(RETROCL_SUFFIX, ldap.SCOPE_SUBTREE, '(targetDn=%s)' % USER2_DN)
++        cllist = retro_changelog_suffix.filter(f'(targetDn={USER2_DN})')
+         assert len(cllist) > 0
+-        if  cllist[0].hasAttr('changes'):
+-            clstr = (cllist[0].getValue('changes')).decode()
++        if  cllist[0].present('changes'):
++            clstr = str(cllist[0].get_attr_vals_utf8('changes'))
+             assert ATTR_HOMEPHONE not in clstr
+             assert ATTR_CARLICENSE in clstr
+     except ldap.LDAPError as e:
+-        log.fatal("Changelog search failed, error: " +str(e))
++        log.fatal("Changelog search failed, error: " + str(e))
+         assert False
+ 
+ def test_retrocl_exclude_attr_mod(topology_st):
+@@ -228,19 +229,20 @@ def test_retrocl_exclude_attr_mod(topology_st):
+             'homeDirectory': '/home/user1',
+             'userpassword': USER_PW})
+     except ldap.ALREADY_EXISTS:
+-        pass
++        user1 = UserAccount(st, dn=USER1_DN)
+     except ldap.LDAPError as e:
+-        log.error("Failed to add user1")
++        log.error("Failed to add user1: " + str(e))
+ 
+     log.info('Verify homePhone and carLicense attrs are in the changelog changestring')
+     try:
+-        cllist = st.search_s(RETROCL_SUFFIX, ldap.SCOPE_SUBTREE, '(targetDn=%s)' % USER1_DN)
++        retro_changelog_suffix = DSLdapObjects(st, basedn=RETROCL_SUFFIX)
++        cllist = retro_changelog_suffix.filter(f'(targetDn={USER1_DN})')
+     except ldap.LDAPError as e:
+-        log.fatal("Changelog search failed, error: " +str(e))
++        log.fatal("Changelog search failed, error: " + str(e))
+         assert False
+     assert len(cllist) > 0
+-    if  cllist[0].hasAttr('changes'):
+-        clstr = (cllist[0].getValue('changes')).decode()
++    if  cllist[0].present('changes'):
++        clstr = str(cllist[0].get_attr_vals_utf8('changes'))
+         assert ATTR_HOMEPHONE in clstr
+         assert ATTR_CARLICENSE in clstr
+ 
+@@ -267,24 +269,25 @@ def test_retrocl_exclude_attr_mod(topology_st):
+ 
+     log.info('Modify user1 carLicense attribute')
+     try:
+-        st.modify_s(USER1_DN, [(ldap.MOD_REPLACE, ATTR_CARLICENSE, b"123WX321")])
++        user1.replace(ATTR_CARLICENSE, "123WX321")
+     except ldap.LDAPError as e:
+         log.fatal('test_retrocl_exclude_attr_mod: Failed to update user1 attribute: error ' + e.message['desc'])
+         assert False
+ 
+     log.info('Verify carLicense attr is not in the changelog changestring')
+     try:
+-        cllist = st.search_s(RETROCL_SUFFIX, ldap.SCOPE_SUBTREE, '(targetDn=%s)' % USER1_DN)
++        cllist = retro_changelog_suffix.filter(f'(targetDn={USER1_DN})')
+         assert len(cllist) > 0
+         # There will be 2 entries in the changelog for this user, we are only
+         #interested in the second one, the modify operation.
+-        if  cllist[1].hasAttr('changes'):
+-            clstr = (cllist[1].getValue('changes')).decode()
++        if  cllist[1].present('changes'):
++            clstr = str(cllist[1].get_attr_vals_utf8('changes'))
+             assert ATTR_CARLICENSE not in clstr
+     except ldap.LDAPError as e:
+-        log.fatal("Changelog search failed, error: " +str(e))
++        log.fatal("Changelog search failed, error: " + str(e))
+         assert False
+ 
++
+ if __name__ == '__main__':
+     # Run isolated
+     # -s for DEBUG mode
+diff --git a/dirsrvtests/tests/suites/retrocl/retrocl_indexing_test.py b/dirsrvtests/tests/suites/retrocl/retrocl_indexing_test.py
+new file mode 100644
+index 000000000..b1dfe962c
+--- /dev/null
++++ b/dirsrvtests/tests/suites/retrocl/retrocl_indexing_test.py
+@@ -0,0 +1,68 @@
++import logging
++import pytest
++import os
++from lib389._constants import RETROCL_SUFFIX, DEFAULT_SUFFIX
++from lib389.topologies import topology_st as topo
++from lib389.plugins import RetroChangelogPlugin
++from lib389.idm.user import UserAccounts
++from lib389._mapped_object import DSLdapObjects
++log = logging.getLogger(__name__)
++
++
++def test_indexing_is_online(topo):
++    """Test that the changenmumber index is online right after enabling the plugin
++
++    :id: 16f4c001-9e0c-4448-a2b3-08ac1e85d40f
++    :setup: Standalone Instance
++    :steps:
++        1. Enable retro cl
++        2. Perform some updates
++        3. Search for "(changenumber>=-1)", and it is not partially unindexed
++        4. Search for "(&(changenumber>=-1)(targetuniqueid=*))", and it is not partially unindexed
++    :expectedresults:
++        1. Success
++        2. Success
++        3. Success
++        4. Success
++    """
++
++    # Enable plugin
++    topo.standalone.config.set('nsslapd-accesslog-logbuffering',  'off')
++    plugin = RetroChangelogPlugin(topo.standalone)
++    plugin.enable()
++    topo.standalone.restart()
++
++    # Do a bunch of updates
++    users = UserAccounts(topo.standalone, DEFAULT_SUFFIX)
++    user_entry = users.create(properties={
++        'sn': '1',
++        'cn': 'user 1',
++        'uid': 'user1',
++        'uidNumber': '11',
++        'gidNumber': '111',
++        'givenname': 'user1',
++        'homePhone': '0861234567',
++        'carLicense': '131D16674',
++        'mail': 'user1@whereever.com',
++        'homeDirectory': '/home'
++    })
++    for count in range(0, 10):
++        user_entry.replace('mail', f'test{count}@test.com')
++
++    # Search the retro cl, and check for error messages
++    filter_simple = '(changenumber>=-1)'
++    filter_compound = '(&(changenumber>=-1)(targetuniqueid=*))'
++    retro_changelog_suffix = DSLdapObjects(topo.standalone, basedn=RETROCL_SUFFIX)
++    retro_changelog_suffix.filter(filter_simple)
++    assert not topo.standalone.searchAccessLog('Partially Unindexed Filter')
++
++    # Search the retro cl again with compound filter
++    retro_changelog_suffix.filter(filter_compound)
++    assert not topo.standalone.searchAccessLog('Partially Unindexed Filter')
++
++
++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/plugins/retrocl/retrocl_create.c b/ldap/servers/plugins/retrocl/retrocl_create.c
+index 571e6899f..5bfde7831 100644
+--- a/ldap/servers/plugins/retrocl/retrocl_create.c
++++ b/ldap/servers/plugins/retrocl/retrocl_create.c
+@@ -133,7 +133,7 @@ retrocl_create_be(const char *bedir)
+     val.bv_len = strlen(val.bv_val);
+     slapi_entry_add_values(e, "cn", vals);
+ 
+-    val.bv_val = "false";
++    val.bv_val = "true"; /* enables the index */
+     val.bv_len = strlen(val.bv_val);
+     slapi_entry_add_values(e, "nssystemindex", vals);
+ 
+diff --git a/ldap/servers/slapd/back-ldbm/ldbm_index_config.c b/ldap/servers/slapd/back-ldbm/ldbm_index_config.c
+index 9722d0ce7..38e7368e1 100644
+--- a/ldap/servers/slapd/back-ldbm/ldbm_index_config.c
++++ b/ldap/servers/slapd/back-ldbm/ldbm_index_config.c
+@@ -25,7 +25,7 @@ int ldbm_instance_index_config_delete_callback(Slapi_PBlock *pb, Slapi_Entry *en
+ #define INDEXTYPE_NONE 1
+ 
+ static int
+-ldbm_index_parse_entry(ldbm_instance *inst, Slapi_Entry *e, const char *trace_string, char **index_name, char *err_buf)
++ldbm_index_parse_entry(ldbm_instance *inst, Slapi_Entry *e, const char *trace_string, char **index_name, PRBool *is_system_index, char *err_buf)
+ {
+     Slapi_Attr *attr;
+     const struct berval *attrValue;
+@@ -78,6 +78,15 @@ ldbm_index_parse_entry(ldbm_instance *inst, Slapi_Entry *e, const char *trace_st
+         }
+     }
+ 
++    *is_system_index = PR_FALSE;
++    if (0 == slapi_entry_attr_find(e, "nsSystemIndex", &attr)) {
++        slapi_attr_first_value(attr, &sval);
++        attrValue = slapi_value_get_berval(sval);
++        if (strcasecmp(attrValue->bv_val, "true") == 0) {
++            *is_system_index = PR_TRUE;
++        }
++    }
++
+     /* ok the entry is good to process, pass it to attr_index_config */
+     if (attr_index_config(inst->inst_be, (char *)trace_string, 0, e, 0, 0, err_buf)) {
+         slapi_ch_free_string(index_name);
+@@ -101,9 +110,10 @@ ldbm_index_init_entry_callback(Slapi_PBlock *pb __attribute__((unused)),
+                                void *arg)
+ {
+     ldbm_instance *inst = (ldbm_instance *)arg;
++    PRBool is_system_index = PR_FALSE;
+ 
+     returntext[0] = '\0';
+-    *returncode = ldbm_index_parse_entry(inst, e, "from ldbm instance init", NULL, NULL);
++    *returncode = ldbm_index_parse_entry(inst, e, "from ldbm instance init", NULL, &is_system_index /* not used */, NULL);
+     if (*returncode == LDAP_SUCCESS) {
+         return SLAPI_DSE_CALLBACK_OK;
+     } else {
+@@ -126,17 +136,21 @@ ldbm_instance_index_config_add_callback(Slapi_PBlock *pb __attribute__((unused))
+ {
+     ldbm_instance *inst = (ldbm_instance *)arg;
+     char *index_name = NULL;
++    PRBool is_system_index = PR_FALSE;
+ 
+     returntext[0] = '\0';
+-    *returncode = ldbm_index_parse_entry(inst, e, "from DSE add", &index_name, returntext);
++    *returncode = ldbm_index_parse_entry(inst, e, "from DSE add", &index_name, &is_system_index, returntext);
+     if (*returncode == LDAP_SUCCESS) {
+         struct attrinfo *ai = NULL;
+         /* if the index is a "system" index, we assume it's being added by
+          * by the server, and it's okay for the index to go online immediately.
+          * if not, we set the index "offline" so it won't actually be used
+          * until someone runs db2index on it.
++         * If caller wants to add an index that they want to be online
++         * immediately they can also set "nsSystemIndex" to "true" in the
++         * index config entry (e.g. is_system_index).
+          */
+-        if (!ldbm_attribute_always_indexed(index_name)) {
++        if (!is_system_index && !ldbm_attribute_always_indexed(index_name)) {
+             ainfo_get(inst->inst_be, index_name, &ai);
+             PR_ASSERT(ai != NULL);
+             ai->ai_indexmask |= INDEX_OFFLINE;
+@@ -386,13 +400,14 @@ ldbm_instance_index_config_enable_index(ldbm_instance *inst, Slapi_Entry *e)
+     char *index_name = NULL;
+     int rc = LDAP_SUCCESS;
+     struct attrinfo *ai = NULL;
++    PRBool is_system_index = PR_FALSE;
+ 
+     index_name = slapi_entry_attr_get_charptr(e, "cn");
+     if (index_name) {
+         ainfo_get(inst->inst_be, index_name, &ai);
+     }
+     if (!ai) {
+-        rc = ldbm_index_parse_entry(inst, e, "from DSE add", &index_name, NULL);
++        rc = ldbm_index_parse_entry(inst, e, "from DSE add", &index_name, &is_system_index /* not used */, NULL);
+     }
+     if (rc == LDAP_SUCCESS) {
+         /* Assume the caller knows if it is OK to go online immediately */
+diff --git a/src/lib389/lib389/_mapped_object.py b/src/lib389/lib389/_mapped_object.py
+index b6d778b01..fe610d175 100644
+--- a/src/lib389/lib389/_mapped_object.py
++++ b/src/lib389/lib389/_mapped_object.py
+@@ -148,6 +148,19 @@ class DSLdapObject(DSLogging, DSLint):
+ 
+         return True
+ 
++    def search(self, scope="subtree", filter='objectclass=*'):
++        search_scope = ldap.SCOPE_SUBTREE
++        if scope == 'base':
++            search_scope = ldap.SCOPE_BASE
++        elif scope == 'one':
++            search_scope = ldap.SCOPE_ONE
++        elif scope == 'subtree':
++            search_scope = ldap.SCOPE_SUBTREE
++        return self._instance.search_ext_s(self._dn, search_scope, filter,
++                                           serverctrls=self._server_controls,
++                                           clientctrls=self._client_controls,
++                                           escapehatch='i am sure')
++
+     def display(self, attrlist=['*']):
+         """Get an entry but represent it as a string LDIF
+ 
+-- 
+2.31.1
+
diff --git a/SOURCES/0024-Issue-4817-BUG-locked-crypt-accounts-on-import-may-a.patch b/SOURCES/0024-Issue-4817-BUG-locked-crypt-accounts-on-import-may-a.patch
new file mode 100644
index 0000000..32c0eb1
--- /dev/null
+++ b/SOURCES/0024-Issue-4817-BUG-locked-crypt-accounts-on-import-may-a.patch
@@ -0,0 +1,121 @@
+From 2f0218f91d35c83a2aaecb71849a54b2481390ab Mon Sep 17 00:00:00 2001
+From: Firstyear <william@blackhats.net.au>
+Date: Fri, 9 Jul 2021 11:53:35 +1000
+Subject: [PATCH] Issue 4817 - BUG - locked crypt accounts on import may allow
+ all passwords (#4819)
+
+Bug Description: Due to mishanding of short dbpwd hashes, the
+crypt_r algorithm was misused and was only comparing salts
+in some cases, rather than checking the actual content
+of the password.
+
+Fix Description: Stricter checks on dbpwd lengths to ensure
+that content passed to crypt_r has at least 2 salt bytes and
+1 hash byte, as well as stricter checks on ct_memcmp to ensure
+that compared values are the same length, rather than potentially
+allowing overruns/short comparisons.
+
+fixes: https://github.com/389ds/389-ds-base/issues/4817
+
+Author: William Brown <william@blackhats.net.au>
+
+Review by: @mreynolds389
+---
+ .../password/pwd_crypt_asterisk_test.py       | 50 +++++++++++++++++++
+ ldap/servers/plugins/pwdstorage/crypt_pwd.c   | 20 +++++---
+ 2 files changed, 64 insertions(+), 6 deletions(-)
+ create mode 100644 dirsrvtests/tests/suites/password/pwd_crypt_asterisk_test.py
+
+diff --git a/dirsrvtests/tests/suites/password/pwd_crypt_asterisk_test.py b/dirsrvtests/tests/suites/password/pwd_crypt_asterisk_test.py
+new file mode 100644
+index 000000000..d76614db1
+--- /dev/null
++++ b/dirsrvtests/tests/suites/password/pwd_crypt_asterisk_test.py
+@@ -0,0 +1,50 @@
++# --- BEGIN COPYRIGHT BLOCK ---
++# Copyright (C) 2021 William Brown <william@blackhats.net.au>
++# All rights reserved.
++#
++# License: GPL (version 3 or any later version).
++# See LICENSE for details.
++# --- END COPYRIGHT BLOCK ---
++#
++import ldap
++import pytest
++from lib389.topologies import topology_st
++from lib389.idm.user import UserAccounts
++from lib389._constants import (DEFAULT_SUFFIX, PASSWORD)
++
++pytestmark = pytest.mark.tier1
++
++def test_password_crypt_asterisk_is_rejected(topology_st):
++    """It was reported that {CRYPT}* was allowing all passwords to be
++    valid in the bind process. This checks that we should be rejecting
++    these as they should represent locked accounts. Similar, {CRYPT}!
++
++    :id: 0b8f1a6a-f3eb-4443-985e-da14d0939dc3
++    :setup: Single instance
++    :steps: 1. Set a password hash in with CRYPT and the content *
++            2. Test a bind
++            3. Set a password hash in with CRYPT and the content !
++            4. Test a bind
++    :expectedresults:
++            1. Successfully set the values
++            2. The bind fails
++            3. Successfully set the values
++            4. The bind fails
++    """
++    topology_st.standalone.config.set('nsslapd-allow-hashed-passwords', 'on')
++    topology_st.standalone.config.set('nsslapd-enable-upgrade-hash', 'off')
++
++    users = UserAccounts(topology_st.standalone, DEFAULT_SUFFIX)
++    user = users.create_test_user()
++
++    user.set('userPassword', "{CRYPT}*")
++
++    # Attempt to bind with incorrect password.
++    with pytest.raises(ldap.INVALID_CREDENTIALS):
++        badconn = user.bind('badpassword')
++
++    user.set('userPassword', "{CRYPT}!")
++    # Attempt to bind with incorrect password.
++    with pytest.raises(ldap.INVALID_CREDENTIALS):
++        badconn = user.bind('badpassword')
++
+diff --git a/ldap/servers/plugins/pwdstorage/crypt_pwd.c b/ldap/servers/plugins/pwdstorage/crypt_pwd.c
+index 9031b2199..1b37d41ed 100644
+--- a/ldap/servers/plugins/pwdstorage/crypt_pwd.c
++++ b/ldap/servers/plugins/pwdstorage/crypt_pwd.c
+@@ -48,15 +48,23 @@ static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */
+ int
+ crypt_pw_cmp(const char *userpwd, const char *dbpwd)
+ {
+-    int rc;
+-    char *cp;
++    int rc = -1;
++    char *cp = NULL;
++    size_t dbpwd_len = strlen(dbpwd);
+     struct crypt_data data;
+     data.initialized = 0;
+ 
+-    /* we use salt (first 2 chars) of encoded password in call to crypt_r() */
+-    cp = crypt_r(userpwd, dbpwd, &data);
+-    if (cp) {
+-        rc = slapi_ct_memcmp(dbpwd, cp, strlen(dbpwd));
++    /*
++     * there MUST be at least 2 chars of salt and some pw bytes, else this is INVALID and will
++     * allow any password to bind as we then only compare SALTS.
++     */
++    if (dbpwd_len >= 3) {
++        /* we use salt (first 2 chars) of encoded password in call to crypt_r() */
++        cp = crypt_r(userpwd, dbpwd, &data);
++    }
++    /* If these are not the same length, we can not proceed safely with memcmp. */
++    if (cp && dbpwd_len == strlen(cp)) {
++        rc = slapi_ct_memcmp(dbpwd, cp, dbpwd_len);
+     } else {
+         rc = -1;
+     }
+-- 
+2.31.1
+
diff --git a/SOURCES/0025-Issue-4837-persistent-search-returns-entries-even-wh.patch b/SOURCES/0025-Issue-4837-persistent-search-returns-entries-even-wh.patch
new file mode 100644
index 0000000..66643a1
--- /dev/null
+++ b/SOURCES/0025-Issue-4837-persistent-search-returns-entries-even-wh.patch
@@ -0,0 +1,39 @@
+From 31d53e7da585723e66b838dcf34b77ea7c9968c6 Mon Sep 17 00:00:00 2001
+From: tbordaz <tbordaz@redhat.com>
+Date: Wed, 21 Jul 2021 09:16:30 +0200
+Subject: [PATCH] Issue 4837 - persistent search returns entries even when an
+ error is returned by content-sync-plugin (#4838)
+
+Bug description:
+	When a ldap client sends a sync request control, the server response may contain a sync state control.
+        If the server fails to create the control the search should fail.
+
+Fix description:
+	In case the server fails to create the response control
+        logs the failure of the pre_search
+
+relates: https://github.com/389ds/389-ds-base/issues/4837
+
+Reviewed by: Simon Pichugin
+
+Platforms tested: RH8.4
+---
+ ldap/servers/plugins/sync/sync_refresh.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/ldap/servers/plugins/sync/sync_refresh.c b/ldap/servers/plugins/sync/sync_refresh.c
+index 646ff760b..4cbb6a949 100644
+--- a/ldap/servers/plugins/sync/sync_refresh.c
++++ b/ldap/servers/plugins/sync/sync_refresh.c
+@@ -213,7 +213,7 @@ sync_srch_refresh_pre_entry(Slapi_PBlock *pb)
+         Slapi_Entry *e;
+         slapi_pblock_get(pb, SLAPI_SEARCH_RESULT_ENTRY, &e);
+         LDAPControl **ctrl = (LDAPControl **)slapi_ch_calloc(2, sizeof(LDAPControl *));
+-        sync_create_state_control(e, &ctrl[0], LDAP_SYNC_ADD, NULL);
++        rc = sync_create_state_control(e, &ctrl[0], LDAP_SYNC_ADD, NULL);
+         slapi_pblock_set(pb, SLAPI_SEARCH_CTRLS, ctrl);
+     }
+     return (rc);
+-- 
+2.31.1
+
diff --git a/SOURCES/0026-Hardcode-gost-crypt-passsword-storage-scheme.patch b/SOURCES/0026-Hardcode-gost-crypt-passsword-storage-scheme.patch
new file mode 100644
index 0000000..aa701a0
--- /dev/null
+++ b/SOURCES/0026-Hardcode-gost-crypt-passsword-storage-scheme.patch
@@ -0,0 +1,49 @@
+From 616dc9964a4675dea2ab2c2efb9bd31c3903e29d Mon Sep 17 00:00:00 2001
+From: Mark Reynolds <mreynolds@redhat.com>
+Date: Mon, 26 Jul 2021 15:22:08 -0400
+Subject: [PATCH] Hardcode gost crypt passsword storage scheme
+
+---
+ .../plugins/pwdstorage/gost_yescrypt.c        | 22 -------------------
+ 1 file changed, 22 deletions(-)
+
+diff --git a/ldap/servers/plugins/pwdstorage/gost_yescrypt.c b/ldap/servers/plugins/pwdstorage/gost_yescrypt.c
+index 67b39395e..7b0d1653c 100644
+--- a/ldap/servers/plugins/pwdstorage/gost_yescrypt.c
++++ b/ldap/servers/plugins/pwdstorage/gost_yescrypt.c
+@@ -11,7 +11,6 @@
+ 
+ #include <crypt.h>
+ 
+-#ifdef XCRYPT_VERSION_STR
+ #include <errno.h>
+ int
+ gost_yescrypt_pw_cmp(const char *userpwd, const char *dbpwd)
+@@ -64,24 +63,3 @@ gost_yescrypt_pw_enc(const char *pwd)
+     return enc;
+ }
+ 
+-#else
+-
+-/*
+- * We do not have xcrypt, so always fail all checks.
+- */
+-int
+-gost_yescrypt_pw_cmp(const char *userpwd __attribute__((unused)), const char *dbpwd __attribute__((unused)))
+-{
+-    slapi_log_err(SLAPI_LOG_ERR, GOST_YESCRYPT_SCHEME_NAME,
+-                  "Unable to use gost_yescrypt_pw_cmp, xcrypt is not available.\n");
+-    return 1;
+-}
+-
+-char *
+-gost_yescrypt_pw_enc(const char *pwd __attribute__((unused)))
+-{
+-    slapi_log_err(SLAPI_LOG_ERR, GOST_YESCRYPT_SCHEME_NAME,
+-                  "Unable to use gost_yescrypt_pw_enc, xcrypt is not available.\n");
+-    return NULL;
+-}
+-#endif
+-- 
+2.31.1
+
diff --git a/SOURCES/Cargo.lock b/SOURCES/Cargo.lock
new file mode 100644
index 0000000..1127ca0
--- /dev/null
+++ b/SOURCES/Cargo.lock
@@ -0,0 +1,565 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "ansi_term"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
+
+[[package]]
+name = "base64"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
+
+[[package]]
+name = "bitflags"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
+
+[[package]]
+name = "byteorder"
+version = "1.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
+
+[[package]]
+name = "cbindgen"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9daec6140ab4dcd38c3dd57e580b59a621172a526ac79f1527af760a55afeafd"
+dependencies = [
+ "clap",
+ "log",
+ "proc-macro2",
+ "quote",
+ "serde",
+ "serde_json",
+ "syn",
+ "tempfile",
+ "toml",
+]
+
+[[package]]
+name = "cc"
+version = "1.0.68"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787"
+dependencies = [
+ "jobserver",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "clap"
+version = "2.33.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
+dependencies = [
+ "ansi_term",
+ "atty",
+ "bitflags",
+ "strsim",
+ "textwrap",
+ "unicode-width",
+ "vec_map",
+]
+
+[[package]]
+name = "entryuuid"
+version = "0.1.0"
+dependencies = [
+ "cc",
+ "libc",
+ "paste",
+ "slapi_r_plugin",
+ "uuid",
+]
+
+[[package]]
+name = "entryuuid_syntax"
+version = "0.1.0"
+dependencies = [
+ "cc",
+ "libc",
+ "paste",
+ "slapi_r_plugin",
+ "uuid",
+]
+
+[[package]]
+name = "fernet"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93804560e638370a8be6d59ce71ed803e55e230abdbf42598e666b41adda9b1f"
+dependencies = [
+ "base64",
+ "byteorder",
+ "getrandom",
+ "openssl",
+ "zeroize",
+]
+
+[[package]]
+name = "foreign-types"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
+dependencies = [
+ "foreign-types-shared",
+]
+
+[[package]]
+name = "foreign-types-shared"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
+
+[[package]]
+name = "getrandom"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "itoa"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
+
+[[package]]
+name = "jobserver"
+version = "0.1.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "972f5ae5d1cb9c6ae417789196c803205313edde988685da5e3aae0827b9e7fd"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "libc"
+version = "0.2.95"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36"
+
+[[package]]
+name = "librnsslapd"
+version = "0.1.0"
+dependencies = [
+ "cbindgen",
+ "libc",
+ "slapd",
+]
+
+[[package]]
+name = "librslapd"
+version = "0.1.0"
+dependencies = [
+ "cbindgen",
+ "libc",
+ "slapd",
+]
+
+[[package]]
+name = "log"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3"
+
+[[package]]
+name = "openssl"
+version = "0.10.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d7830286ad6a3973c0f1d9b73738f69c76b739301d0229c4b96501695cbe4c8"
+dependencies = [
+ "bitflags",
+ "cfg-if",
+ "foreign-types",
+ "libc",
+ "once_cell",
+ "openssl-sys",
+]
+
+[[package]]
+name = "openssl-sys"
+version = "0.9.63"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6b0d6fb7d80f877617dfcb014e605e2b5ab2fb0afdf27935219bb6bd984cb98"
+dependencies = [
+ "autocfg",
+ "cc",
+ "libc",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
+name = "paste"
+version = "0.1.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "45ca20c77d80be666aef2b45486da86238fabe33e38306bd3118fe4af33fa880"
+dependencies = [
+ "paste-impl",
+ "proc-macro-hack",
+]
+
+[[package]]
+name = "paste-impl"
+version = "0.1.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d95a7db200b97ef370c8e6de0088252f7e0dfff7d047a28528e47456c0fc98b6"
+dependencies = [
+ "proc-macro-hack",
+]
+
+[[package]]
+name = "pkg-config"
+version = "0.3.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
+
+[[package]]
+name = "proc-macro-hack"
+version = "0.5.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rand"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e"
+dependencies = [
+ "libc",
+ "rand_chacha",
+ "rand_core",
+ "rand_hc",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "rand_hc"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73"
+dependencies = [
+ "rand_core",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "remove_dir_all"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "rsds"
+version = "0.1.0"
+
+[[package]]
+name = "ryu"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
+
+[[package]]
+name = "serde"
+version = "1.0.126"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.126"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.64"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
+dependencies = [
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "slapd"
+version = "0.1.0"
+dependencies = [
+ "fernet",
+]
+
+[[package]]
+name = "slapi_r_plugin"
+version = "0.1.0"
+dependencies = [
+ "lazy_static",
+ "libc",
+ "paste",
+ "uuid",
+]
+
+[[package]]
+name = "strsim"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
+
+[[package]]
+name = "syn"
+version = "1.0.72"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "synstructure"
+version = "0.12.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "unicode-xid",
+]
+
+[[package]]
+name = "tempfile"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "rand",
+ "redox_syscall",
+ "remove_dir_all",
+ "winapi",
+]
+
+[[package]]
+name = "textwrap"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
+dependencies = [
+ "unicode-width",
+]
+
+[[package]]
+name = "toml"
+version = "0.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "unicode-width"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
+
+[[package]]
+name = "uuid"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "vcpkg"
+version = "0.2.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "025ce40a007e1907e58d5bc1a594def78e5573bb0b1160bc389634e8f12e4faa"
+
+[[package]]
+name = "vec_map"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
+
+[[package]]
+name = "wasi"
+version = "0.10.2+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[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 = "zeroize"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd"
+dependencies = [
+ "zeroize_derive",
+]
+
+[[package]]
+name = "zeroize_derive"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2c1e130bebaeab2f23886bf9acbaca14b092408c452543c857f66399cd6dab1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "synstructure",
+]
diff --git a/SPECS/389-ds-base.spec b/SPECS/389-ds-base.spec
index 4f85296..129ac96 100644
--- a/SPECS/389-ds-base.spec
+++ b/SPECS/389-ds-base.spec
@@ -16,7 +16,7 @@ ExcludeArch: i686
 %global use_Socket6 0
 
 %global use_asan 0
-%global use_rust 0
+%global use_rust 1
 %global use_legacy 1
 %global bundle_jemalloc 1
 %if %{use_asan}
@@ -42,10 +42,13 @@ ExcludeArch: i686
 # set PIE flag
 %global _hardened_build 1
 
+# Filter argparse-manpage from autogenerated package Requires
+%global __requires_exclude ^python.*argparse-manpage
+
 Summary:          389 Directory Server (base)
 Name:             389-ds-base
 Version:          1.4.3.23
-Release:          %{?relprefix}2%{?prerel}%{?dist}
+Release:          %{?relprefix}7%{?prerel}%{?dist}
 License:          GPLv3+
 URL:              https://www.port389.org
 Group:            System Environment/Daemons
@@ -246,6 +249,21 @@ Patch09:          0009-Issue-4623-RFE-Monitor-the-current-DB-locks-4762.patch
 Patch10:          0010-Issue-4764-replicated-operation-sometime-checks-ACI-.patch
 Patch11:          0011-Issue-4778-RFE-Allow-setting-TOD-for-db-compaction-a.patch
 Patch12:          0012-Issue-4778-RFE-Add-changelog-compaction-task-in-1.4..patch
+Patch13:          0013-Issue-4797-ACL-IP-ADDRESS-evaluation-may-corrupt-c_i.patch
+Patch14:          0014-Issue-4396-Minor-memory-leak-in-backend-4558-4572.patch
+Patch15:          0015-Issue-4700-Regression-in-winsync-replication-agreeme.patch
+Patch16:          0016-Issue-4725-Fix-compiler-warnings.patch
+Patch17:          0017-Issue-4814-_cl5_get_tod_expiration-may-crash-at-star.patch
+Patch18:          0018-Issue-4789-Temporary-password-rules-are-not-enforce-.patch
+Patch19:          0019-Issue-4788-CLI-should-support-Temporary-Password-Rul.patch
+Patch20:          0020-Issue-4447-Crash-when-the-Referential-Integrity-log-.patch
+Patch21:          0021-Issue-4791-Missing-dependency-for-RetroCL-RFE.patch
+Patch22:          0022-Issue-4656-remove-problematic-language-from-ds-replc.patch
+Patch23:          0023-Issue-4443-Internal-unindexed-searches-in-syncrepl-r.patch
+Patch24:          0024-Issue-4817-BUG-locked-crypt-accounts-on-import-may-a.patch
+Patch25:          0025-Issue-4837-persistent-search-returns-entries-even-wh.patch
+Patch26:          0026-Hardcode-gost-crypt-passsword-storage-scheme.patch
+
 
 %description
 389 Directory Server is an LDAPv3 compliant server.  The base package includes
@@ -864,6 +882,33 @@ exit 0
 %doc README.md
 
 %changelog
+* Mon Jul 26 2021 Mark Reynolds <mreynolds@redhat.com> - 1.4.3.23-7
+- Bump version to 1.4.3.23-7
+- Resolves: Bug 1983921 - persistent search returns entries even when an error is returned by content-sync-plugin
+
+* Fri Jul 16 2021 Mark Reynolds <mreynolds@redhat.com> - 1.4.3.23-6
+- Bump version to 1.4.3.23-6
+- Resolves: Bug 1982787 - CRYPT password hash with asterisk allows any bind attempt to succeed
+
+* Thu Jul 15 2021 Mark Reynolds <mreynolds@redhat.com> - 1.4.3.23-5
+- Bump version to 1.4.3.23-5
+- Resolves: Bug 1951020 - Internal unindexed searches in syncrepl
+- Resolves: Bug 1978279 - ds-replcheck state output message has 'Master' instead of 'Supplier'
+
+* Tue Jun 29 2021 Mark Reynolds <mreynolds@redhat.com> - 1.4.3.23-4
+- Bump version to 1.4.3.23-4
+- Resolves: Bug 1976906 - Instance crash at restart after changelog configuration
+- Resolves: Bug 1480323 - ns-slapd crash at startup - Segmentation fault in strcmpi_fast() when the Referential Integrity log is manually edited
+- Resolves: Bug 1967596 - Temporary password - add CLI and fix compiler errors
+
+* Thu Jun 17 2021 Mark Reynolds <mreynolds@redhat.com> - 1.4.3.23-3
+- Bump version to 1.4.3.23-3
+- Resolves: Bug 1944494 - support for RFC 4530 entryUUID attribute
+- Resolves: Bug 1967839 - ACIs are being evaluated against the Replication Manager account in a replication context
+- Resolves: Bug 1970259 - A connection can be erroneously flagged as replication conn during evaluation of an aci with ip bind rule
+- Resolves: Bug 1972590 - Large updates can reset the CLcache to the beginning of the changelog
+- Resolves: Bug 1903221 - Memory leak in 389ds backend (Minor)
+
 * Sun May 30 2021 Mark Reynolds <mreynolds@redhat.com> - 1.4.3.23-2
 - Bump version to 1.4.3.23-2
 - Resolves: Bug 1812286 - RFE - Monitor the current DB locks ( nsslapd-db-current-locks )