import 389-ds-base-1.4.3.23-7.module+el8.5.0+11979+655d714b
This commit is contained in:
parent
3e0d9e8a55
commit
9ad1a01ffd
@ -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
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
88
SOURCES/0016-Issue-4725-Fix-compiler-warnings.patch
Normal file
88
SOURCES/0016-Issue-4725-Fix-compiler-warnings.patch
Normal file
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
114
SOURCES/0021-Issue-4791-Missing-dependency-for-RetroCL-RFE.patch
Normal file
114
SOURCES/0021-Issue-4791-Missing-dependency-for-RetroCL-RFE.patch
Normal file
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
565
SOURCES/Cargo.lock
generated
Normal file
565
SOURCES/Cargo.lock
generated
Normal file
@ -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",
|
||||
]
|
@ -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 )
|
||||
|
Loading…
Reference in New Issue
Block a user