import 389-ds-base-1.4.3.23-14.module+el8.5.0+14377+c731dc97
This commit is contained in:
parent
7900475d31
commit
21cd549720
@ -0,0 +1,105 @@
|
|||||||
|
From 1cdb49e70e35ad69e76be10f93233cdf504375df Mon Sep 17 00:00:00 2001
|
||||||
|
From: Mark Reynolds <mreynolds@redhat.com>
|
||||||
|
Date: Thu, 16 Dec 2021 16:13:08 -0500
|
||||||
|
Subject: [PATCH 1/4] CVE-2021-4091 (BZ#2030367) double-free of the virtual
|
||||||
|
attribute context in persistent search
|
||||||
|
|
||||||
|
description:
|
||||||
|
A search is processed by a worker using a private pblock.
|
||||||
|
If the search is persistent, the worker spawn a thread
|
||||||
|
and kind of duplicate its private pblock so that the spawn
|
||||||
|
thread continue to process the persistent search.
|
||||||
|
Then worker ends the initial search, reinit (free) its private pblock,
|
||||||
|
and returns monitoring the wait_queue.
|
||||||
|
When the persistent search completes, it frees the duplicated
|
||||||
|
pblock.
|
||||||
|
The problem is that private pblock and duplicated pblock
|
||||||
|
are referring to a same structure (pb_vattr_context).
|
||||||
|
That lead to a double free
|
||||||
|
|
||||||
|
Fix:
|
||||||
|
When cloning the pblock (slapi_pblock_clone) make sure
|
||||||
|
to transfert the references inside the original (private)
|
||||||
|
pblock to the target (cloned) one
|
||||||
|
That includes pb_vattr_context pointer.
|
||||||
|
|
||||||
|
Reviewed by: Mark Reynolds, James Chapman, Pierre Rogier (Thanks !)
|
||||||
|
---
|
||||||
|
ldap/servers/slapd/connection.c | 8 +++++---
|
||||||
|
ldap/servers/slapd/pblock.c | 14 ++++++++++++--
|
||||||
|
2 files changed, 17 insertions(+), 5 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/ldap/servers/slapd/connection.c b/ldap/servers/slapd/connection.c
|
||||||
|
index e0c1a52d2..fc7ed9c4a 100644
|
||||||
|
--- a/ldap/servers/slapd/connection.c
|
||||||
|
+++ b/ldap/servers/slapd/connection.c
|
||||||
|
@@ -1823,9 +1823,11 @@ connection_threadmain()
|
||||||
|
pthread_mutex_unlock(&(conn->c_mutex));
|
||||||
|
}
|
||||||
|
/* ps_add makes a shallow copy of the pb - so we
|
||||||
|
- * can't free it or init it here - just set operation to NULL.
|
||||||
|
- * ps_send_results will call connection_remove_operation_ext to free it
|
||||||
|
- */
|
||||||
|
+ * can't free it or init it here - just set operation to NULL.
|
||||||
|
+ * ps_send_results will call connection_remove_operation_ext to free it
|
||||||
|
+ * The connection_thread private pblock ('pb') has be cloned and should only
|
||||||
|
+ * be reinit (slapi_pblock_init)
|
||||||
|
+ */
|
||||||
|
slapi_pblock_set(pb, SLAPI_OPERATION, NULL);
|
||||||
|
slapi_pblock_init(pb);
|
||||||
|
} else {
|
||||||
|
diff --git a/ldap/servers/slapd/pblock.c b/ldap/servers/slapd/pblock.c
|
||||||
|
index a64986aeb..c78d1250f 100644
|
||||||
|
--- a/ldap/servers/slapd/pblock.c
|
||||||
|
+++ b/ldap/servers/slapd/pblock.c
|
||||||
|
@@ -292,6 +292,12 @@ _pblock_assert_pb_deprecated(Slapi_PBlock *pblock)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+/* It clones the pblock
|
||||||
|
+ * the content of the source pblock is transfered
|
||||||
|
+ * to the target pblock (returned)
|
||||||
|
+ * The source pblock should not be used for any operation
|
||||||
|
+ * it needs to be reinit (slapi_pblock_init)
|
||||||
|
+ */
|
||||||
|
Slapi_PBlock *
|
||||||
|
slapi_pblock_clone(Slapi_PBlock *pb)
|
||||||
|
{
|
||||||
|
@@ -312,28 +318,32 @@ slapi_pblock_clone(Slapi_PBlock *pb)
|
||||||
|
if (pb->pb_task != NULL) {
|
||||||
|
_pblock_assert_pb_task(new_pb);
|
||||||
|
*(new_pb->pb_task) = *(pb->pb_task);
|
||||||
|
+ memset(pb->pb_task, 0, sizeof(slapi_pblock_task));
|
||||||
|
}
|
||||||
|
if (pb->pb_mr != NULL) {
|
||||||
|
_pblock_assert_pb_mr(new_pb);
|
||||||
|
*(new_pb->pb_mr) = *(pb->pb_mr);
|
||||||
|
+ memset(pb->pb_mr, 0, sizeof(slapi_pblock_matching_rule));
|
||||||
|
}
|
||||||
|
if (pb->pb_misc != NULL) {
|
||||||
|
_pblock_assert_pb_misc(new_pb);
|
||||||
|
*(new_pb->pb_misc) = *(pb->pb_misc);
|
||||||
|
+ memset(pb->pb_misc, 0, sizeof(slapi_pblock_misc));
|
||||||
|
}
|
||||||
|
if (pb->pb_intop != NULL) {
|
||||||
|
_pblock_assert_pb_intop(new_pb);
|
||||||
|
*(new_pb->pb_intop) = *(pb->pb_intop);
|
||||||
|
- /* set pwdpolicy to NULL so this clone allocates its own policy */
|
||||||
|
- new_pb->pb_intop->pwdpolicy = NULL;
|
||||||
|
+ memset(pb->pb_intop, 0, sizeof(slapi_pblock_intop));
|
||||||
|
}
|
||||||
|
if (pb->pb_intplugin != NULL) {
|
||||||
|
_pblock_assert_pb_intplugin(new_pb);
|
||||||
|
*(new_pb->pb_intplugin) = *(pb->pb_intplugin);
|
||||||
|
+ memset(pb->pb_intplugin, 0,sizeof(slapi_pblock_intplugin));
|
||||||
|
}
|
||||||
|
if (pb->pb_deprecated != NULL) {
|
||||||
|
_pblock_assert_pb_deprecated(new_pb);
|
||||||
|
*(new_pb->pb_deprecated) = *(pb->pb_deprecated);
|
||||||
|
+ memset(pb->pb_deprecated, 0, sizeof(slapi_pblock_deprecated));
|
||||||
|
}
|
||||||
|
#ifdef PBLOCK_ANALYTICS
|
||||||
|
new_pb->analytics = NULL;
|
||||||
|
--
|
||||||
|
2.31.1
|
||||||
|
|
228
SOURCES/0035-Issue-4775-Add-entryuuid-CLI-and-Fixup-4776.patch
Normal file
228
SOURCES/0035-Issue-4775-Add-entryuuid-CLI-and-Fixup-4776.patch
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
From cf620c104ac50af48e48e8c0040820b6c073f7d7 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Firstyear <william@blackhats.net.au>
|
||||||
|
Date: Thu, 19 Aug 2021 10:46:00 +1000
|
||||||
|
Subject: [PATCH 2/4] Issue 4775 - Add entryuuid CLI and Fixup (#4776)
|
||||||
|
|
||||||
|
Bug Description: EntryUUID when added was missing it's CLI
|
||||||
|
and helpers for fixups.
|
||||||
|
|
||||||
|
Fix Description: Add the CLI elements.
|
||||||
|
|
||||||
|
fixes: https://github.com/389ds/389-ds-base/issues/4775
|
||||||
|
|
||||||
|
Author: William Brown <william@blackhats.net.au>
|
||||||
|
|
||||||
|
Review by: @mreynolds389 (thanks!)
|
||||||
|
---
|
||||||
|
src/lib389/lib389/cli_conf/plugin.py | 2 +
|
||||||
|
.../lib389/cli_conf/plugins/entryuuid.py | 39 +++++++++++++++++++
|
||||||
|
src/plugins/entryuuid/src/lib.rs | 34 +++++++++-------
|
||||||
|
3 files changed, 60 insertions(+), 15 deletions(-)
|
||||||
|
create mode 100644 src/lib389/lib389/cli_conf/plugins/entryuuid.py
|
||||||
|
|
||||||
|
diff --git a/src/lib389/lib389/cli_conf/plugin.py b/src/lib389/lib389/cli_conf/plugin.py
|
||||||
|
index b50837cb8..1bd0c70db 100644
|
||||||
|
--- a/src/lib389/lib389/cli_conf/plugin.py
|
||||||
|
+++ b/src/lib389/lib389/cli_conf/plugin.py
|
||||||
|
@@ -27,6 +27,7 @@ from lib389.cli_conf.plugins import passthroughauth as cli_passthroughauth
|
||||||
|
from lib389.cli_conf.plugins import retrochangelog as cli_retrochangelog
|
||||||
|
from lib389.cli_conf.plugins import automember as cli_automember
|
||||||
|
from lib389.cli_conf.plugins import posix_winsync as cli_posix_winsync
|
||||||
|
+from lib389.cli_conf.plugins import entryuuid as cli_entryuuid
|
||||||
|
|
||||||
|
SINGULAR = Plugin
|
||||||
|
MANY = Plugins
|
||||||
|
@@ -113,6 +114,7 @@ def create_parser(subparsers):
|
||||||
|
cli_passthroughauth.create_parser(subcommands)
|
||||||
|
cli_retrochangelog.create_parser(subcommands)
|
||||||
|
cli_posix_winsync.create_parser(subcommands)
|
||||||
|
+ cli_entryuuid.create_parser(subcommands)
|
||||||
|
|
||||||
|
list_parser = subcommands.add_parser('list', help="List current configured (enabled and disabled) plugins")
|
||||||
|
list_parser.set_defaults(func=plugin_list)
|
||||||
|
diff --git a/src/lib389/lib389/cli_conf/plugins/entryuuid.py b/src/lib389/lib389/cli_conf/plugins/entryuuid.py
|
||||||
|
new file mode 100644
|
||||||
|
index 000000000..6c86bff4b
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/src/lib389/lib389/cli_conf/plugins/entryuuid.py
|
||||||
|
@@ -0,0 +1,39 @@
|
||||||
|
+# --- 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
|
||||||
|
+from lib389.plugins import EntryUUIDPlugin
|
||||||
|
+from lib389.cli_conf import add_generic_plugin_parsers, generic_object_edit, generic_object_add
|
||||||
|
+
|
||||||
|
+def do_fixup(inst, basedn, log, args):
|
||||||
|
+ plugin = EntryUUIDPlugin(inst)
|
||||||
|
+ log.info('Attempting to add task entry...')
|
||||||
|
+ if not plugin.status():
|
||||||
|
+ log.error("'%s' is disabled. Fix up task can't be executed" % plugin.rdn)
|
||||||
|
+ return
|
||||||
|
+ fixup_task = plugin.fixup(args.DN, args.filter)
|
||||||
|
+ fixup_task.wait()
|
||||||
|
+ exitcode = fixup_task.get_exit_code()
|
||||||
|
+ if exitcode != 0:
|
||||||
|
+ log.error('EntryUUID fixup task has failed. Please, check the error log for more - %s' % exitcode)
|
||||||
|
+ else:
|
||||||
|
+ log.info('Successfully added task entry')
|
||||||
|
+
|
||||||
|
+def create_parser(subparsers):
|
||||||
|
+ referint = subparsers.add_parser('entryuuid', help='Manage and configure EntryUUID plugin')
|
||||||
|
+ subcommands = referint.add_subparsers(help='action')
|
||||||
|
+
|
||||||
|
+ add_generic_plugin_parsers(subcommands, EntryUUIDPlugin)
|
||||||
|
+
|
||||||
|
+ fixup = subcommands.add_parser('fixup', help='Run the fix-up task for EntryUUID plugin')
|
||||||
|
+ fixup.set_defaults(func=do_fixup)
|
||||||
|
+ fixup.add_argument('DN', help="Base DN that contains entries to fix up")
|
||||||
|
+ fixup.add_argument('-f', '--filter',
|
||||||
|
+ help='Filter for entries to fix up.\n If omitted, all entries under base DN'
|
||||||
|
+ 'will have their EntryUUID attribute regenerated if not present.')
|
||||||
|
+
|
||||||
|
diff --git a/src/plugins/entryuuid/src/lib.rs b/src/plugins/entryuuid/src/lib.rs
|
||||||
|
index 0197c5e83..29a9f1258 100644
|
||||||
|
--- a/src/plugins/entryuuid/src/lib.rs
|
||||||
|
+++ b/src/plugins/entryuuid/src/lib.rs
|
||||||
|
@@ -33,7 +33,7 @@ fn assign_uuid(e: &mut EntryRef) {
|
||||||
|
// 🚧 safety barrier 🚧
|
||||||
|
if e.contains_attr("entryUUID") {
|
||||||
|
log_error!(
|
||||||
|
- ErrorLevel::Trace,
|
||||||
|
+ ErrorLevel::Plugin,
|
||||||
|
"assign_uuid -> entryUUID exists, skipping dn {}",
|
||||||
|
sdn.to_dn_string()
|
||||||
|
);
|
||||||
|
@@ -47,7 +47,7 @@ fn assign_uuid(e: &mut EntryRef) {
|
||||||
|
if sdn.is_below_suffix(&*config_sdn) || sdn.is_below_suffix(&*schema_sdn) {
|
||||||
|
// We don't need to assign to these suffixes.
|
||||||
|
log_error!(
|
||||||
|
- ErrorLevel::Trace,
|
||||||
|
+ ErrorLevel::Plugin,
|
||||||
|
"assign_uuid -> not assigning to {:?} as part of system suffix",
|
||||||
|
sdn.to_dn_string()
|
||||||
|
);
|
||||||
|
@@ -57,7 +57,7 @@ fn assign_uuid(e: &mut EntryRef) {
|
||||||
|
// Generate a new Uuid.
|
||||||
|
let u: Uuid = Uuid::new_v4();
|
||||||
|
log_error!(
|
||||||
|
- ErrorLevel::Trace,
|
||||||
|
+ ErrorLevel::Plugin,
|
||||||
|
"assign_uuid -> assigning {:?} to dn {}",
|
||||||
|
u,
|
||||||
|
sdn.to_dn_string()
|
||||||
|
@@ -78,13 +78,13 @@ impl SlapiPlugin3 for EntryUuid {
|
||||||
|
fn betxn_pre_add(pb: &mut PblockRef) -> Result<(), PluginError> {
|
||||||
|
if pb.get_is_replicated_operation() {
|
||||||
|
log_error!(
|
||||||
|
- ErrorLevel::Trace,
|
||||||
|
+ ErrorLevel::Plugin,
|
||||||
|
"betxn_pre_add -> replicated operation, will not change"
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
- log_error!(ErrorLevel::Trace, "betxn_pre_add -> start");
|
||||||
|
+ log_error!(ErrorLevel::Plugin, "betxn_pre_add -> start");
|
||||||
|
|
||||||
|
let mut e = pb.get_op_add_entryref().map_err(|_| PluginError::Pblock)?;
|
||||||
|
assign_uuid(&mut e);
|
||||||
|
@@ -105,7 +105,7 @@ impl SlapiPlugin3 for EntryUuid {
|
||||||
|
.first()
|
||||||
|
.ok_or_else(|| {
|
||||||
|
log_error!(
|
||||||
|
- ErrorLevel::Trace,
|
||||||
|
+ ErrorLevel::Plugin,
|
||||||
|
"task_validate basedn error -> empty value array?"
|
||||||
|
);
|
||||||
|
LDAPError::Operation
|
||||||
|
@@ -113,7 +113,7 @@ impl SlapiPlugin3 for EntryUuid {
|
||||||
|
.as_ref()
|
||||||
|
.try_into()
|
||||||
|
.map_err(|e| {
|
||||||
|
- log_error!(ErrorLevel::Trace, "task_validate basedn error -> {:?}", e);
|
||||||
|
+ log_error!(ErrorLevel::Plugin, "task_validate basedn error -> {:?}", e);
|
||||||
|
LDAPError::Operation
|
||||||
|
})?,
|
||||||
|
None => return Err(LDAPError::ObjectClassViolation),
|
||||||
|
@@ -124,7 +124,7 @@ impl SlapiPlugin3 for EntryUuid {
|
||||||
|
.first()
|
||||||
|
.ok_or_else(|| {
|
||||||
|
log_error!(
|
||||||
|
- ErrorLevel::Trace,
|
||||||
|
+ ErrorLevel::Plugin,
|
||||||
|
"task_validate filter error -> empty value array?"
|
||||||
|
);
|
||||||
|
LDAPError::Operation
|
||||||
|
@@ -132,7 +132,7 @@ impl SlapiPlugin3 for EntryUuid {
|
||||||
|
.as_ref()
|
||||||
|
.try_into()
|
||||||
|
.map_err(|e| {
|
||||||
|
- log_error!(ErrorLevel::Trace, "task_validate filter error -> {:?}", e);
|
||||||
|
+ log_error!(ErrorLevel::Plugin, "task_validate filter error -> {:?}", e);
|
||||||
|
LDAPError::Operation
|
||||||
|
})?,
|
||||||
|
None => {
|
||||||
|
@@ -144,7 +144,11 @@ impl SlapiPlugin3 for EntryUuid {
|
||||||
|
// Error if the first filter is empty?
|
||||||
|
|
||||||
|
// Now, to make things faster, we wrap the filter in a exclude term.
|
||||||
|
- let raw_filter = format!("(&{}(!(entryuuid=*)))", raw_filter);
|
||||||
|
+ let raw_filter = if !raw_filter.starts_with('(') && !raw_filter.ends_with('(') {
|
||||||
|
+ format!("(&({})(!(entryuuid=*)))", raw_filter)
|
||||||
|
+ } else {
|
||||||
|
+ format!("(&{}(!(entryuuid=*)))", raw_filter)
|
||||||
|
+ };
|
||||||
|
|
||||||
|
Ok(FixupData { basedn, raw_filter })
|
||||||
|
}
|
||||||
|
@@ -155,7 +159,7 @@ impl SlapiPlugin3 for EntryUuid {
|
||||||
|
|
||||||
|
fn task_handler(_task: &Task, data: Self::TaskData) -> Result<Self::TaskData, PluginError> {
|
||||||
|
log_error!(
|
||||||
|
- ErrorLevel::Trace,
|
||||||
|
+ ErrorLevel::Plugin,
|
||||||
|
"task_handler -> start thread with -> {:?}",
|
||||||
|
data
|
||||||
|
);
|
||||||
|
@@ -195,12 +199,12 @@ impl SlapiPlugin3 for EntryUuid {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start(_pb: &mut PblockRef) -> Result<(), PluginError> {
|
||||||
|
- log_error!(ErrorLevel::Trace, "plugin start");
|
||||||
|
+ log_error!(ErrorLevel::Plugin, "plugin start");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn close(_pb: &mut PblockRef) -> Result<(), PluginError> {
|
||||||
|
- log_error!(ErrorLevel::Trace, "plugin close");
|
||||||
|
+ log_error!(ErrorLevel::Plugin, "plugin close");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -212,7 +216,7 @@ pub fn entryuuid_fixup_mapfn(e: &EntryRef, _data: &()) -> Result<(), PluginError
|
||||||
|
/* Sanity check that entryuuid doesn't already exist */
|
||||||
|
if e.contains_attr("entryUUID") {
|
||||||
|
log_error!(
|
||||||
|
- ErrorLevel::Trace,
|
||||||
|
+ ErrorLevel::Plugin,
|
||||||
|
"skipping fixup for -> {}",
|
||||||
|
sdn.to_dn_string()
|
||||||
|
);
|
||||||
|
@@ -232,7 +236,7 @@ pub fn entryuuid_fixup_mapfn(e: &EntryRef, _data: &()) -> Result<(), PluginError
|
||||||
|
|
||||||
|
match lmod.execute() {
|
||||||
|
Ok(_) => {
|
||||||
|
- log_error!(ErrorLevel::Trace, "fixed-up -> {}", sdn.to_dn_string());
|
||||||
|
+ log_error!(ErrorLevel::Plugin, "fixed-up -> {}", sdn.to_dn_string());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
--
|
||||||
|
2.31.1
|
||||||
|
|
@ -0,0 +1,443 @@
|
|||||||
|
From 0ed5299841733f9e18c5fe8c6a3f9d3fbd49c75a Mon Sep 17 00:00:00 2001
|
||||||
|
From: Firstyear <william@blackhats.net.au>
|
||||||
|
Date: Fri, 20 Aug 2021 09:18:50 +1000
|
||||||
|
Subject: [PATCH 3/4] Issue 4877 - RFE - EntryUUID to validate UUIDs on fixup
|
||||||
|
(#4878)
|
||||||
|
|
||||||
|
Bug Description: Due to changing the syntax of EntryUUID's
|
||||||
|
to string, we may have invalid EntryUUID's imported into
|
||||||
|
the database.
|
||||||
|
|
||||||
|
Fix Description: To resolve this during a fixup we validate
|
||||||
|
that Uuid's have a valid syntax. If they do not, we regenerate
|
||||||
|
them.
|
||||||
|
|
||||||
|
fixes: https://github.com/389ds/389-ds-base/issues/4877
|
||||||
|
|
||||||
|
Author: William Brown <william@blackhats.net.au>
|
||||||
|
|
||||||
|
Review by: @mreynolds389
|
||||||
|
---
|
||||||
|
.../entryuuid/localhost-userRoot-invalid.ldif | 233 ++++++++++++++++++
|
||||||
|
.../tests/suites/entryuuid/basic_test.py | 58 ++++-
|
||||||
|
src/plugins/entryuuid/src/lib.rs | 28 ++-
|
||||||
|
src/slapi_r_plugin/src/pblock.rs | 4 +-
|
||||||
|
src/slapi_r_plugin/src/value.rs | 10 +-
|
||||||
|
5 files changed, 322 insertions(+), 11 deletions(-)
|
||||||
|
create mode 100644 dirsrvtests/tests/data/entryuuid/localhost-userRoot-invalid.ldif
|
||||||
|
|
||||||
|
diff --git a/dirsrvtests/tests/data/entryuuid/localhost-userRoot-invalid.ldif b/dirsrvtests/tests/data/entryuuid/localhost-userRoot-invalid.ldif
|
||||||
|
new file mode 100644
|
||||||
|
index 000000000..9703babed
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/dirsrvtests/tests/data/entryuuid/localhost-userRoot-invalid.ldif
|
||||||
|
@@ -0,0 +1,233 @@
|
||||||
|
+version: 1
|
||||||
|
+
|
||||||
|
+# entry-id: 1
|
||||||
|
+dn: dc=example,dc=com
|
||||||
|
+objectClass: top
|
||||||
|
+objectClass: domain
|
||||||
|
+dc: example
|
||||||
|
+description: dc=example,dc=com
|
||||||
|
+creatorsName: cn=Directory Manager
|
||||||
|
+modifiersName: cn=Directory Manager
|
||||||
|
+createTimestamp: 20200325015542Z
|
||||||
|
+modifyTimestamp: 20200325015542Z
|
||||||
|
+nsUniqueId: a2b33229-6e3b11ea-8de0c78c-83e27eda
|
||||||
|
+aci: (targetattr="dc || description || objectClass")(targetfilter="(objectClas
|
||||||
|
+ s=domain)")(version 3.0; acl "Enable anyone domain read"; allow (read, search
|
||||||
|
+ , compare)(userdn="ldap:///anyone");)
|
||||||
|
+aci: (targetattr="ou || objectClass")(targetfilter="(objectClass=organizationa
|
||||||
|
+ lUnit)")(version 3.0; acl "Enable anyone ou read"; allow (read, search, compa
|
||||||
|
+ re)(userdn="ldap:///anyone");)
|
||||||
|
+
|
||||||
|
+# entry-id: 2
|
||||||
|
+dn: cn=389_ds_system,dc=example,dc=com
|
||||||
|
+objectClass: top
|
||||||
|
+objectClass: nscontainer
|
||||||
|
+objectClass: ldapsubentry
|
||||||
|
+cn: 389_ds_system
|
||||||
|
+creatorsName: cn=Directory Manager
|
||||||
|
+modifiersName: cn=Directory Manager
|
||||||
|
+createTimestamp: 20200325015542Z
|
||||||
|
+modifyTimestamp: 20200325015542Z
|
||||||
|
+nsUniqueId: a2b3322a-6e3b11ea-8de0c78c-83e27eda
|
||||||
|
+
|
||||||
|
+# entry-id: 3
|
||||||
|
+dn: ou=groups,dc=example,dc=com
|
||||||
|
+objectClass: top
|
||||||
|
+objectClass: organizationalunit
|
||||||
|
+ou: groups
|
||||||
|
+aci: (targetattr="cn || member || gidNumber || nsUniqueId || description || ob
|
||||||
|
+ jectClass")(targetfilter="(objectClass=groupOfNames)")(version 3.0; acl "Enab
|
||||||
|
+ le anyone group read"; allow (read, search, compare)(userdn="ldap:///anyone")
|
||||||
|
+ ;)
|
||||||
|
+aci: (targetattr="member")(targetfilter="(objectClass=groupOfNames)")(version
|
||||||
|
+ 3.0; acl "Enable group_modify to alter members"; allow (write)(groupdn="ldap:
|
||||||
|
+ ///cn=group_modify,ou=permissions,dc=example,dc=com");)
|
||||||
|
+aci: (targetattr="cn || member || gidNumber || description || objectClass")(ta
|
||||||
|
+ rgetfilter="(objectClass=groupOfNames)")(version 3.0; acl "Enable group_admin
|
||||||
|
+ to manage groups"; allow (write, add, delete)(groupdn="ldap:///cn=group_admi
|
||||||
|
+ n,ou=permissions,dc=example,dc=com");)
|
||||||
|
+creatorsName: cn=Directory Manager
|
||||||
|
+modifiersName: cn=Directory Manager
|
||||||
|
+createTimestamp: 20200325015543Z
|
||||||
|
+modifyTimestamp: 20200325015543Z
|
||||||
|
+nsUniqueId: a2b3322b-6e3b11ea-8de0c78c-83e27eda
|
||||||
|
+
|
||||||
|
+# entry-id: 4
|
||||||
|
+dn: ou=people,dc=example,dc=com
|
||||||
|
+objectClass: top
|
||||||
|
+objectClass: organizationalunit
|
||||||
|
+ou: people
|
||||||
|
+aci: (targetattr="objectClass || description || nsUniqueId || uid || displayNa
|
||||||
|
+ me || loginShell || uidNumber || gidNumber || gecos || homeDirectory || cn ||
|
||||||
|
+ memberOf || mail || nsSshPublicKey || nsAccountLock || userCertificate")(tar
|
||||||
|
+ getfilter="(objectClass=posixaccount)")(version 3.0; acl "Enable anyone user
|
||||||
|
+ read"; allow (read, search, compare)(userdn="ldap:///anyone");)
|
||||||
|
+aci: (targetattr="displayName || legalName || userPassword || nsSshPublicKey")
|
||||||
|
+ (version 3.0; acl "Enable self partial modify"; allow (write)(userdn="ldap://
|
||||||
|
+ /self");)
|
||||||
|
+aci: (targetattr="legalName || telephoneNumber || mobile || sn")(targetfilter=
|
||||||
|
+ "(|(objectClass=nsPerson)(objectClass=inetOrgPerson))")(version 3.0; acl "Ena
|
||||||
|
+ ble self legalname read"; allow (read, search, compare)(userdn="ldap:///self"
|
||||||
|
+ );)
|
||||||
|
+aci: (targetattr="legalName || telephoneNumber")(targetfilter="(objectClass=ns
|
||||||
|
+ Person)")(version 3.0; acl "Enable user legalname read"; allow (read, search,
|
||||||
|
+ compare)(groupdn="ldap:///cn=user_private_read,ou=permissions,dc=example,dc=
|
||||||
|
+ com");)
|
||||||
|
+aci: (targetattr="uid || description || displayName || loginShell || uidNumber
|
||||||
|
+ || gidNumber || gecos || homeDirectory || cn || memberOf || mail || legalNam
|
||||||
|
+ e || telephoneNumber || mobile")(targetfilter="(&(objectClass=nsPerson)(objec
|
||||||
|
+ tClass=nsAccount))")(version 3.0; acl "Enable user admin create"; allow (writ
|
||||||
|
+ e, add, delete, read)(groupdn="ldap:///cn=user_admin,ou=permissions,dc=exampl
|
||||||
|
+ e,dc=com");)
|
||||||
|
+aci: (targetattr="uid || description || displayName || loginShell || uidNumber
|
||||||
|
+ || gidNumber || gecos || homeDirectory || cn || memberOf || mail || legalNam
|
||||||
|
+ e || telephoneNumber || mobile")(targetfilter="(&(objectClass=nsPerson)(objec
|
||||||
|
+ tClass=nsAccount))")(version 3.0; acl "Enable user modify to change users"; a
|
||||||
|
+ llow (write, read)(groupdn="ldap:///cn=user_modify,ou=permissions,dc=example,
|
||||||
|
+ dc=com");)
|
||||||
|
+aci: (targetattr="userPassword || nsAccountLock || userCertificate || nsSshPub
|
||||||
|
+ licKey")(targetfilter="(objectClass=nsAccount)")(version 3.0; acl "Enable use
|
||||||
|
+ r password reset"; allow (write, read)(groupdn="ldap:///cn=user_passwd_reset,
|
||||||
|
+ ou=permissions,dc=example,dc=com");)
|
||||||
|
+creatorsName: cn=Directory Manager
|
||||||
|
+modifiersName: cn=Directory Manager
|
||||||
|
+createTimestamp: 20200325015543Z
|
||||||
|
+modifyTimestamp: 20200325015543Z
|
||||||
|
+nsUniqueId: a2b3322c-6e3b11ea-8de0c78c-83e27eda
|
||||||
|
+
|
||||||
|
+# entry-id: 5
|
||||||
|
+dn: ou=permissions,dc=example,dc=com
|
||||||
|
+objectClass: top
|
||||||
|
+objectClass: organizationalunit
|
||||||
|
+ou: permissions
|
||||||
|
+creatorsName: cn=Directory Manager
|
||||||
|
+modifiersName: cn=Directory Manager
|
||||||
|
+createTimestamp: 20200325015543Z
|
||||||
|
+modifyTimestamp: 20200325015543Z
|
||||||
|
+nsUniqueId: a2b3322d-6e3b11ea-8de0c78c-83e27eda
|
||||||
|
+
|
||||||
|
+# entry-id: 6
|
||||||
|
+dn: ou=services,dc=example,dc=com
|
||||||
|
+objectClass: top
|
||||||
|
+objectClass: organizationalunit
|
||||||
|
+ou: services
|
||||||
|
+aci: (targetattr="objectClass || description || nsUniqueId || cn || memberOf |
|
||||||
|
+ | nsAccountLock ")(targetfilter="(objectClass=netscapeServer)")(version 3.0;
|
||||||
|
+ acl "Enable anyone service account read"; allow (read, search, compare)(userd
|
||||||
|
+ n="ldap:///anyone");)
|
||||||
|
+creatorsName: cn=Directory Manager
|
||||||
|
+modifiersName: cn=Directory Manager
|
||||||
|
+createTimestamp: 20200325015544Z
|
||||||
|
+modifyTimestamp: 20200325015544Z
|
||||||
|
+nsUniqueId: a2b3322e-6e3b11ea-8de0c78c-83e27eda
|
||||||
|
+
|
||||||
|
+# entry-id: 7
|
||||||
|
+dn: uid=demo_user,ou=people,dc=example,dc=com
|
||||||
|
+objectClass: top
|
||||||
|
+objectClass: nsPerson
|
||||||
|
+objectClass: nsAccount
|
||||||
|
+objectClass: nsOrgPerson
|
||||||
|
+objectClass: posixAccount
|
||||||
|
+uid: demo_user
|
||||||
|
+cn: Demo User
|
||||||
|
+displayName: Demo User
|
||||||
|
+legalName: Demo User Name
|
||||||
|
+uidNumber: 99998
|
||||||
|
+gidNumber: 99998
|
||||||
|
+homeDirectory: /var/empty
|
||||||
|
+loginShell: /bin/false
|
||||||
|
+nsAccountLock: true
|
||||||
|
+creatorsName: cn=Directory Manager
|
||||||
|
+modifiersName: cn=Directory Manager
|
||||||
|
+createTimestamp: 20200325015544Z
|
||||||
|
+modifyTimestamp: 20200325061615Z
|
||||||
|
+nsUniqueId: a2b3322f-6e3b11ea-8de0c78c-83e27eda
|
||||||
|
+entryUUID: INVALID_UUID
|
||||||
|
+
|
||||||
|
+# entry-id: 8
|
||||||
|
+dn: cn=demo_group,ou=groups,dc=example,dc=com
|
||||||
|
+objectClass: top
|
||||||
|
+objectClass: groupOfNames
|
||||||
|
+objectClass: posixGroup
|
||||||
|
+objectClass: nsMemberOf
|
||||||
|
+cn: demo_group
|
||||||
|
+gidNumber: 99999
|
||||||
|
+creatorsName: cn=Directory Manager
|
||||||
|
+modifiersName: cn=Directory Manager
|
||||||
|
+createTimestamp: 20200325015544Z
|
||||||
|
+modifyTimestamp: 20200325015544Z
|
||||||
|
+nsUniqueId: a2b33230-6e3b11ea-8de0c78c-83e27eda
|
||||||
|
+entryUUID: f6df8fe9-6b30-46aa-aa13-f0bf755371e8
|
||||||
|
+
|
||||||
|
+# entry-id: 9
|
||||||
|
+dn: cn=group_admin,ou=permissions,dc=example,dc=com
|
||||||
|
+objectClass: top
|
||||||
|
+objectClass: groupOfNames
|
||||||
|
+objectClass: nsMemberOf
|
||||||
|
+cn: group_admin
|
||||||
|
+creatorsName: cn=Directory Manager
|
||||||
|
+modifiersName: cn=Directory Manager
|
||||||
|
+createTimestamp: 20200325015545Z
|
||||||
|
+modifyTimestamp: 20200325015545Z
|
||||||
|
+nsUniqueId: a2b33231-6e3b11ea-8de0c78c-83e27eda
|
||||||
|
+
|
||||||
|
+# entry-id: 10
|
||||||
|
+dn: cn=group_modify,ou=permissions,dc=example,dc=com
|
||||||
|
+objectClass: top
|
||||||
|
+objectClass: groupOfNames
|
||||||
|
+objectClass: nsMemberOf
|
||||||
|
+cn: group_modify
|
||||||
|
+creatorsName: cn=Directory Manager
|
||||||
|
+modifiersName: cn=Directory Manager
|
||||||
|
+createTimestamp: 20200325015545Z
|
||||||
|
+modifyTimestamp: 20200325015545Z
|
||||||
|
+nsUniqueId: a2b33232-6e3b11ea-8de0c78c-83e27eda
|
||||||
|
+
|
||||||
|
+# entry-id: 11
|
||||||
|
+dn: cn=user_admin,ou=permissions,dc=example,dc=com
|
||||||
|
+objectClass: top
|
||||||
|
+objectClass: groupOfNames
|
||||||
|
+objectClass: nsMemberOf
|
||||||
|
+cn: user_admin
|
||||||
|
+creatorsName: cn=Directory Manager
|
||||||
|
+modifiersName: cn=Directory Manager
|
||||||
|
+createTimestamp: 20200325015545Z
|
||||||
|
+modifyTimestamp: 20200325015545Z
|
||||||
|
+nsUniqueId: a2b33233-6e3b11ea-8de0c78c-83e27eda
|
||||||
|
+
|
||||||
|
+# entry-id: 12
|
||||||
|
+dn: cn=user_modify,ou=permissions,dc=example,dc=com
|
||||||
|
+objectClass: top
|
||||||
|
+objectClass: groupOfNames
|
||||||
|
+objectClass: nsMemberOf
|
||||||
|
+cn: user_modify
|
||||||
|
+creatorsName: cn=Directory Manager
|
||||||
|
+modifiersName: cn=Directory Manager
|
||||||
|
+createTimestamp: 20200325015546Z
|
||||||
|
+modifyTimestamp: 20200325015546Z
|
||||||
|
+nsUniqueId: a2b33234-6e3b11ea-8de0c78c-83e27eda
|
||||||
|
+
|
||||||
|
+# entry-id: 13
|
||||||
|
+dn: cn=user_passwd_reset,ou=permissions,dc=example,dc=com
|
||||||
|
+objectClass: top
|
||||||
|
+objectClass: groupOfNames
|
||||||
|
+objectClass: nsMemberOf
|
||||||
|
+cn: user_passwd_reset
|
||||||
|
+creatorsName: cn=Directory Manager
|
||||||
|
+modifiersName: cn=Directory Manager
|
||||||
|
+createTimestamp: 20200325015546Z
|
||||||
|
+modifyTimestamp: 20200325015546Z
|
||||||
|
+nsUniqueId: a2b33235-6e3b11ea-8de0c78c-83e27eda
|
||||||
|
+
|
||||||
|
+# entry-id: 14
|
||||||
|
+dn: cn=user_private_read,ou=permissions,dc=example,dc=com
|
||||||
|
+objectClass: top
|
||||||
|
+objectClass: groupOfNames
|
||||||
|
+objectClass: nsMemberOf
|
||||||
|
+cn: user_private_read
|
||||||
|
+creatorsName: cn=Directory Manager
|
||||||
|
+modifiersName: cn=Directory Manager
|
||||||
|
+createTimestamp: 20200325015547Z
|
||||||
|
+modifyTimestamp: 20200325015547Z
|
||||||
|
+nsUniqueId: a2b33236-6e3b11ea-8de0c78c-83e27eda
|
||||||
|
+
|
||||||
|
diff --git a/dirsrvtests/tests/suites/entryuuid/basic_test.py b/dirsrvtests/tests/suites/entryuuid/basic_test.py
|
||||||
|
index 4d8a40909..41ffbfe10 100644
|
||||||
|
--- a/dirsrvtests/tests/suites/entryuuid/basic_test.py
|
||||||
|
+++ b/dirsrvtests/tests/suites/entryuuid/basic_test.py
|
||||||
|
@@ -10,6 +10,7 @@ import ldap
|
||||||
|
import pytest
|
||||||
|
import time
|
||||||
|
import shutil
|
||||||
|
+import uuid
|
||||||
|
from lib389.idm.user import nsUserAccounts, UserAccounts
|
||||||
|
from lib389.idm.account import Accounts
|
||||||
|
from lib389.idm.domain import Domain
|
||||||
|
@@ -217,7 +218,7 @@ def test_entryuuid_fixup_task(topology):
|
||||||
|
|
||||||
|
# 4. run the fix up
|
||||||
|
# For now set the log level to high!
|
||||||
|
- topology.standalone.config.loglevel(vals=(ErrorLog.DEFAULT,ErrorLog.TRACE))
|
||||||
|
+ topology.standalone.config.loglevel(vals=(ErrorLog.DEFAULT,ErrorLog.PLUGIN))
|
||||||
|
task = plug.fixup(DEFAULT_SUFFIX)
|
||||||
|
task.wait()
|
||||||
|
assert(task.is_complete() and task.get_exit_code() == 0)
|
||||||
|
@@ -242,3 +243,58 @@ def test_entryuuid_fixup_task(topology):
|
||||||
|
euuid_domain_2 = domain.get_attr_val_utf8('entryUUID')
|
||||||
|
assert(euuid_domain_2 == euuid_domain)
|
||||||
|
|
||||||
|
+@pytest.mark.skipif(not default_paths.rust_enabled or ds_is_older('1.4.2.0'), reason="Entryuuid is not available in older versions")
|
||||||
|
+def test_entryuuid_import_and_fixup_of_invalid_values(topology):
|
||||||
|
+ """ Test that when we import a database with an invalid entryuuid
|
||||||
|
+ that it is accepted *and* that subsequently we can fix the invalid
|
||||||
|
+ entryuuid during a fixup.
|
||||||
|
+
|
||||||
|
+ :id: ec8ef3a7-3cd2-4cbd-b6f1-2449fa17be75
|
||||||
|
+
|
||||||
|
+ :setup: Standalone instance
|
||||||
|
+
|
||||||
|
+ :steps:
|
||||||
|
+ 1. Import the db from the ldif
|
||||||
|
+ 2. Check the entryuuid is invalid
|
||||||
|
+ 3. Run the fixup
|
||||||
|
+ 4. Check the entryuuid is now valid (regenerated)
|
||||||
|
+
|
||||||
|
+ :expectedresults:
|
||||||
|
+ 1. Success
|
||||||
|
+ 2. The entryuuid is invalid
|
||||||
|
+ 3. Success
|
||||||
|
+ 4. The entryuuid is valid
|
||||||
|
+ """
|
||||||
|
+
|
||||||
|
+ # 1. Import the db
|
||||||
|
+ ldif_dir = topology.standalone.get_ldif_dir()
|
||||||
|
+ target_ldif = os.path.join(ldif_dir, 'localhost-userRoot-invalid.ldif')
|
||||||
|
+ import_ldif = os.path.join(DATADIR1, 'localhost-userRoot-invalid.ldif')
|
||||||
|
+ shutil.copyfile(import_ldif, target_ldif)
|
||||||
|
+ os.chmod(target_ldif, 0o777)
|
||||||
|
+
|
||||||
|
+ be = Backends(topology.standalone).get('userRoot')
|
||||||
|
+ task = be.import_ldif([target_ldif])
|
||||||
|
+ task.wait()
|
||||||
|
+ assert(task.is_complete() and task.get_exit_code() == 0)
|
||||||
|
+
|
||||||
|
+ # 2. Check the entryuuid is invalid
|
||||||
|
+ account = nsUserAccounts(topology.standalone, DEFAULT_SUFFIX).get("demo_user")
|
||||||
|
+ euuid = account.get_attr_val_utf8('entryUUID')
|
||||||
|
+ assert(euuid == "INVALID_UUID")
|
||||||
|
+
|
||||||
|
+ # 3. Run the fixup
|
||||||
|
+ topology.standalone.config.loglevel(vals=(ErrorLog.DEFAULT,ErrorLog.PLUGIN))
|
||||||
|
+ plug = EntryUUIDPlugin(topology.standalone)
|
||||||
|
+ task = plug.fixup(DEFAULT_SUFFIX)
|
||||||
|
+ task.wait()
|
||||||
|
+ assert(task.is_complete() and task.get_exit_code() == 0)
|
||||||
|
+ topology.standalone.config.loglevel(vals=(ErrorLog.DEFAULT,))
|
||||||
|
+
|
||||||
|
+ # 4. Check the entryuuid is valid
|
||||||
|
+ euuid = account.get_attr_val_utf8('entryUUID')
|
||||||
|
+ print(f"❄️ account entryUUID -> {euuid}");
|
||||||
|
+ assert(euuid != "INVALID_UUID")
|
||||||
|
+ # Raises an error if invalid
|
||||||
|
+ uuid.UUID(euuid)
|
||||||
|
+
|
||||||
|
diff --git a/src/plugins/entryuuid/src/lib.rs b/src/plugins/entryuuid/src/lib.rs
|
||||||
|
index 29a9f1258..ad3faef4b 100644
|
||||||
|
--- a/src/plugins/entryuuid/src/lib.rs
|
||||||
|
+++ b/src/plugins/entryuuid/src/lib.rs
|
||||||
|
@@ -144,11 +144,17 @@ impl SlapiPlugin3 for EntryUuid {
|
||||||
|
// Error if the first filter is empty?
|
||||||
|
|
||||||
|
// Now, to make things faster, we wrap the filter in a exclude term.
|
||||||
|
+
|
||||||
|
+ // 2021 - #4877 because we allow entryuuid to be strings, on import these may
|
||||||
|
+ // be invalid. As a result, we DO need to allow the fixup to check the entryuuid
|
||||||
|
+ // value is correct, so we can not exclude these during the search.
|
||||||
|
+ /*
|
||||||
|
let raw_filter = if !raw_filter.starts_with('(') && !raw_filter.ends_with('(') {
|
||||||
|
format!("(&({})(!(entryuuid=*)))", raw_filter)
|
||||||
|
} else {
|
||||||
|
format!("(&{}(!(entryuuid=*)))", raw_filter)
|
||||||
|
};
|
||||||
|
+ */
|
||||||
|
|
||||||
|
Ok(FixupData { basedn, raw_filter })
|
||||||
|
}
|
||||||
|
@@ -213,14 +219,20 @@ pub fn entryuuid_fixup_mapfn(e: &EntryRef, _data: &()) -> Result<(), PluginError
|
||||||
|
/* Supply a modification to the entry. */
|
||||||
|
let sdn = e.get_sdnref();
|
||||||
|
|
||||||
|
- /* Sanity check that entryuuid doesn't already exist */
|
||||||
|
- if e.contains_attr("entryUUID") {
|
||||||
|
- log_error!(
|
||||||
|
- ErrorLevel::Plugin,
|
||||||
|
- "skipping fixup for -> {}",
|
||||||
|
- sdn.to_dn_string()
|
||||||
|
- );
|
||||||
|
- return Ok(());
|
||||||
|
+ /* Check that entryuuid doesn't already exist, and is valid */
|
||||||
|
+ if let Some(valueset) = e.get_attr("entryUUID") {
|
||||||
|
+ if valueset.iter().all(|v| {
|
||||||
|
+ let u: Result<Uuid, _> = (&v).try_into();
|
||||||
|
+ u.is_ok()
|
||||||
|
+ }) {
|
||||||
|
+ // All values were valid uuid, move on!
|
||||||
|
+ log_error!(
|
||||||
|
+ ErrorLevel::Plugin,
|
||||||
|
+ "skipping fixup for -> {}",
|
||||||
|
+ sdn.to_dn_string()
|
||||||
|
+ );
|
||||||
|
+ return Ok(());
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup the modifications
|
||||||
|
diff --git a/src/slapi_r_plugin/src/pblock.rs b/src/slapi_r_plugin/src/pblock.rs
|
||||||
|
index 718ff2ca7..ac1b3c33b 100644
|
||||||
|
--- a/src/slapi_r_plugin/src/pblock.rs
|
||||||
|
+++ b/src/slapi_r_plugin/src/pblock.rs
|
||||||
|
@@ -281,7 +281,9 @@ impl PblockRef {
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_is_replicated_operation(&mut self) -> bool {
|
||||||
|
- let i = self.get_value_i32(PblockType::IsReplicationOperation).unwrap_or(0);
|
||||||
|
+ let i = self
|
||||||
|
+ .get_value_i32(PblockType::IsReplicationOperation)
|
||||||
|
+ .unwrap_or(0);
|
||||||
|
// Because rust returns the result of the last evaluation, we can
|
||||||
|
// just return if not equal 0.
|
||||||
|
i != 0
|
||||||
|
diff --git a/src/slapi_r_plugin/src/value.rs b/src/slapi_r_plugin/src/value.rs
|
||||||
|
index 46246837a..cd565295c 100644
|
||||||
|
--- a/src/slapi_r_plugin/src/value.rs
|
||||||
|
+++ b/src/slapi_r_plugin/src/value.rs
|
||||||
|
@@ -1,6 +1,6 @@
|
||||||
|
use crate::ber::{ol_berval, BerValRef};
|
||||||
|
use crate::dn::Sdn;
|
||||||
|
-use std::convert::{From, TryFrom};
|
||||||
|
+use std::convert::{From, TryFrom, TryInto};
|
||||||
|
use std::ffi::CString;
|
||||||
|
use std::iter::once;
|
||||||
|
use std::iter::FromIterator;
|
||||||
|
@@ -213,6 +213,14 @@ impl TryFrom<&ValueRef> for String {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+impl TryFrom<&ValueRef> for Uuid {
|
||||||
|
+ type Error = ();
|
||||||
|
+
|
||||||
|
+ fn try_from(value: &ValueRef) -> Result<Self, Self::Error> {
|
||||||
|
+ (&value.bvr).try_into().map_err(|_| ())
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
impl TryFrom<&ValueRef> for Sdn {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
--
|
||||||
|
2.31.1
|
||||||
|
|
@ -0,0 +1,143 @@
|
|||||||
|
From 0bdb7445af5be162e18c26f7fc2b75536c467748 Mon Sep 17 00:00:00 2001
|
||||||
|
From: James Chapman <jachapma@redhat.com>
|
||||||
|
Date: Fri, 19 Feb 2021 16:32:22 +0000
|
||||||
|
Subject: [PATCH 4/4] Issue 4595 - Paged search lookthroughlimit bug (#4602)
|
||||||
|
|
||||||
|
Bug Description: During a paged search with lookthroughlimit enabled,
|
||||||
|
lookthroughcount is used to keep track of how many entries are
|
||||||
|
examined. A paged search reads ahead one entry to catch the end of the
|
||||||
|
search so it doesn't show the prompt when there are no more entries.
|
||||||
|
lookthroughcount doesn't take read ahead into account when tracking
|
||||||
|
how many entries have been examined.
|
||||||
|
|
||||||
|
Fix Description: Keep lookthroughcount in sync with read ahead by
|
||||||
|
by decrementing it during read ahead roll back.
|
||||||
|
|
||||||
|
Fixes: https://github.com/389ds/389-ds-base/issues/4595
|
||||||
|
|
||||||
|
Relates: https://github.com/389ds/389-ds-base/issues/4513
|
||||||
|
|
||||||
|
Reviewed by: droideck, mreynolds389, Firstyear, progier389 (Many thanks)
|
||||||
|
---
|
||||||
|
dirsrvtests/tests/suites/basic/basic_test.py | 85 ++++++++++++++++++++
|
||||||
|
ldap/servers/slapd/back-ldbm/ldbm_search.c | 1 +
|
||||||
|
2 files changed, 86 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/dirsrvtests/tests/suites/basic/basic_test.py b/dirsrvtests/tests/suites/basic/basic_test.py
|
||||||
|
index 332f5bb8d..e1a31175a 100644
|
||||||
|
--- a/dirsrvtests/tests/suites/basic/basic_test.py
|
||||||
|
+++ b/dirsrvtests/tests/suites/basic/basic_test.py
|
||||||
|
@@ -95,6 +95,24 @@ def rootdse_attr(topology_st, request):
|
||||||
|
return rootdse_attr_name
|
||||||
|
|
||||||
|
|
||||||
|
+def change_conf_attr(topology_st, suffix, attr_name, attr_value):
|
||||||
|
+ """Change configuration attribute in the given suffix.
|
||||||
|
+
|
||||||
|
+ Returns previous attribute value.
|
||||||
|
+ """
|
||||||
|
+
|
||||||
|
+ entry = DSLdapObject(topology_st.standalone, suffix)
|
||||||
|
+
|
||||||
|
+ attr_value_bck = entry.get_attr_val_bytes(attr_name)
|
||||||
|
+ log.info('Set %s to %s. Previous value - %s. Modified suffix - %s.' % (
|
||||||
|
+ attr_name, attr_value, attr_value_bck, suffix))
|
||||||
|
+ if attr_value is None:
|
||||||
|
+ entry.remove_all(attr_name)
|
||||||
|
+ else:
|
||||||
|
+ entry.replace(attr_name, attr_value)
|
||||||
|
+ return attr_value_bck
|
||||||
|
+
|
||||||
|
+
|
||||||
|
def test_basic_ops(topology_st, import_example_ldif):
|
||||||
|
"""Tests adds, mods, modrdns, and deletes operations
|
||||||
|
|
||||||
|
@@ -607,6 +625,73 @@ def test_basic_searches(topology_st, import_example_ldif):
|
||||||
|
log.info('test_basic_searches: PASSED')
|
||||||
|
|
||||||
|
|
||||||
|
+@pytest.mark.parametrize('limit,resp',
|
||||||
|
+ ((('200'), 'PASS'),
|
||||||
|
+ (('50'), ldap.ADMINLIMIT_EXCEEDED)))
|
||||||
|
+def test_basic_search_lookthroughlimit(topology_st, limit, resp, import_example_ldif):
|
||||||
|
+ """
|
||||||
|
+ Tests normal search with lookthroughlimit set high and low.
|
||||||
|
+
|
||||||
|
+ :id: b5119970-6c9f-41b7-9649-de9233226fec
|
||||||
|
+
|
||||||
|
+ :setup: Standalone instance, add example.ldif to the database, search filter (uid=*).
|
||||||
|
+
|
||||||
|
+ :steps:
|
||||||
|
+ 1. Import ldif user file.
|
||||||
|
+ 2. Change lookthroughlimit to 200.
|
||||||
|
+ 3. Bind to server as low priv user
|
||||||
|
+ 4. Run search 1 with "high" lookthroughlimit.
|
||||||
|
+ 5. Change lookthroughlimit to 50.
|
||||||
|
+ 6. Run search 2 with "low" lookthroughlimit.
|
||||||
|
+ 8. Delete user from DB.
|
||||||
|
+ 9. Reset lookthroughlimit to original.
|
||||||
|
+
|
||||||
|
+ :expectedresults:
|
||||||
|
+ 1. First search should complete with no error.
|
||||||
|
+ 2. Second search should return ldap.ADMINLIMIT_EXCEEDED error.
|
||||||
|
+ """
|
||||||
|
+
|
||||||
|
+ log.info('Running test_basic_search_lookthroughlimit...')
|
||||||
|
+
|
||||||
|
+ search_filter = "(uid=*)"
|
||||||
|
+
|
||||||
|
+ ltl_orig = change_conf_attr(topology_st, 'cn=config,cn=ldbm database,cn=plugins,cn=config', 'nsslapd-lookthroughlimit', limit)
|
||||||
|
+
|
||||||
|
+ try:
|
||||||
|
+ users = UserAccounts(topology_st.standalone, DEFAULT_SUFFIX, rdn=None)
|
||||||
|
+ user = users.create_test_user()
|
||||||
|
+ user.replace('userPassword', PASSWORD)
|
||||||
|
+ except ldap.LDAPError as e:
|
||||||
|
+ log.fatal('Failed to create test user: error ' + e.args[0]['desc'])
|
||||||
|
+ assert False
|
||||||
|
+
|
||||||
|
+ try:
|
||||||
|
+ conn = UserAccount(topology_st.standalone, user.dn).bind(PASSWORD)
|
||||||
|
+ except ldap.LDAPError as e:
|
||||||
|
+ log.fatal('Failed to bind test user: error ' + e.args[0]['desc'])
|
||||||
|
+ assert False
|
||||||
|
+
|
||||||
|
+ try:
|
||||||
|
+ if resp == ldap.ADMINLIMIT_EXCEEDED:
|
||||||
|
+ with pytest.raises(ldap.ADMINLIMIT_EXCEEDED):
|
||||||
|
+ searchid = conn.search(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, search_filter)
|
||||||
|
+ rtype, rdata = conn.result(searchid)
|
||||||
|
+ else:
|
||||||
|
+ searchid = conn.search(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, search_filter)
|
||||||
|
+ rtype, rdata = conn.result(searchid)
|
||||||
|
+ assert(len(rdata) == 151) #151 entries in the imported ldif file using "(uid=*)"
|
||||||
|
+ except ldap.LDAPError as e:
|
||||||
|
+ log.fatal('Failed to perform search: error ' + e.args[0]['desc'])
|
||||||
|
+ assert False
|
||||||
|
+
|
||||||
|
+ finally:
|
||||||
|
+ #Cleanup
|
||||||
|
+ change_conf_attr(topology_st, 'cn=config,cn=ldbm database,cn=plugins,cn=config', 'nsslapd-lookthroughlimit', ltl_orig)
|
||||||
|
+ user.delete()
|
||||||
|
+
|
||||||
|
+ log.info('test_basic_search_lookthroughlimit: PASSED')
|
||||||
|
+
|
||||||
|
+
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def add_test_entry(topology_st, request):
|
||||||
|
# Add test entry
|
||||||
|
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_search.c b/ldap/servers/slapd/back-ldbm/ldbm_search.c
|
||||||
|
index 6e22debde..d0f52b6f7 100644
|
||||||
|
--- a/ldap/servers/slapd/back-ldbm/ldbm_search.c
|
||||||
|
+++ b/ldap/servers/slapd/back-ldbm/ldbm_search.c
|
||||||
|
@@ -1885,6 +1885,7 @@ ldbm_back_prev_search_results(Slapi_PBlock *pb)
|
||||||
|
sr->sr_entry = NULL;
|
||||||
|
}
|
||||||
|
idl_iterator_decrement(&(sr->sr_current));
|
||||||
|
+ --sr->sr_lookthroughcount;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
--
|
||||||
|
2.31.1
|
||||||
|
|
@ -48,7 +48,7 @@ ExcludeArch: i686
|
|||||||
Summary: 389 Directory Server (base)
|
Summary: 389 Directory Server (base)
|
||||||
Name: 389-ds-base
|
Name: 389-ds-base
|
||||||
Version: 1.4.3.23
|
Version: 1.4.3.23
|
||||||
Release: %{?relprefix}12%{?prerel}%{?dist}
|
Release: %{?relprefix}14%{?prerel}%{?dist}
|
||||||
License: GPLv3+
|
License: GPLv3+
|
||||||
URL: https://www.port389.org
|
URL: https://www.port389.org
|
||||||
Group: System Environment/Daemons
|
Group: System Environment/Daemons
|
||||||
@ -270,6 +270,10 @@ Patch30: 0030-Issue-4884-server-crashes-when-dnaInterval-attribute.patc
|
|||||||
Patch31: 0031-Issue-4925-Performance-ACI-targetfilter-evaluation-r.patch
|
Patch31: 0031-Issue-4925-Performance-ACI-targetfilter-evaluation-r.patch
|
||||||
Patch32: 0032-Issue-4972-gecos-with-IA5-introduces-a-compatibility.patch
|
Patch32: 0032-Issue-4972-gecos-with-IA5-introduces-a-compatibility.patch
|
||||||
Patch33: 0033-Issue-4910-db-reindex-corrupts-RUV-tombstone-nsuique.patch
|
Patch33: 0033-Issue-4910-db-reindex-corrupts-RUV-tombstone-nsuique.patch
|
||||||
|
Patch34: 0034-CVE-2021-4091-BZ-2030367-double-free-of-the-virtual-.patch
|
||||||
|
Patch35: 0035-Issue-4775-Add-entryuuid-CLI-and-Fixup-4776.patch
|
||||||
|
Patch36: 0036-Issue-4877-RFE-EntryUUID-to-validate-UUIDs-on-fixup-.patch
|
||||||
|
Patch37: 0037-Issue-4595-Paged-search-lookthroughlimit-bug-4602.patch
|
||||||
|
|
||||||
%description
|
%description
|
||||||
389 Directory Server is an LDAPv3 compliant server. The base package includes
|
389 Directory Server is an LDAPv3 compliant server. The base package includes
|
||||||
@ -888,6 +892,18 @@ exit 0
|
|||||||
%doc README.md
|
%doc README.md
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Wed Mar 2 2022 Thierry Bordaz <tbordaz@redhat.com> - 1.4.3.23-14
|
||||||
|
- Bump version to 1.4.3.23-14
|
||||||
|
- Resolves: Bug 2059893 - Paged search lookthroughlimit counter doesnt take read ahead into account
|
||||||
|
- Resolves: Bug 2060106 - Based on 1944494 (RFC 4530 entryUUID attribute) - plugin entryuuid failing
|
||||||
|
- Resolves: Bug 2060110 - double-free of the virtual attribute context in persistent search
|
||||||
|
|
||||||
|
* Mon Feb 21 2022 Thierry Bordaz <tbordaz@redhat.com> - 1.4.3.23-13
|
||||||
|
- Bump version to 1.4.3.23-13
|
||||||
|
- Resolves: Bug 2056488 - Paged search lookthroughlimit counter doesnt take read ahead into account
|
||||||
|
- Resolves: Bug 2047166 - Based on 1944494 (RFC 4530 entryUUID attribute) - plugin entryuuid failing
|
||||||
|
- Resolves: Bug 2056481 - double-free of the virtual attribute context in persistent search
|
||||||
|
|
||||||
* Thu Nov 18 2021 Mark Reynolds <mreynolds@redhat.com> - 1.4.3.23-12
|
* Thu Nov 18 2021 Mark Reynolds <mreynolds@redhat.com> - 1.4.3.23-12
|
||||||
- Bump version to 1.4.3.23-12
|
- Bump version to 1.4.3.23-12
|
||||||
- Resolves: Bug 2024697 - DB corruption "_entryrdn_insert_key - Same DN (dn: nsuniqueid=ffffffff-ffffffff-ffffffff-ffffffff,<SUFFIX>) is already in the entryrdn file"
|
- Resolves: Bug 2024697 - DB corruption "_entryrdn_insert_key - Same DN (dn: nsuniqueid=ffffffff-ffffffff-ffffffff-ffffffff,<SUFFIX>) is already in the entryrdn file"
|
||||||
|
Loading…
Reference in New Issue
Block a user