Blame SOURCES/0004-Ticket-4326-entryuuid-fixup-did-not-work-correctly-4.patch

e4a41f
From c167d6127db45d8426437c273060c8c8f7fbcb9b Mon Sep 17 00:00:00 2001
e4a41f
From: Firstyear <william.brown@suse.com>
e4a41f
Date: Wed, 23 Sep 2020 09:19:34 +1000
e4a41f
Subject: [PATCH 04/12] Ticket 4326 - entryuuid fixup did not work correctly
e4a41f
 (#4328)
e4a41f
e4a41f
Bug Description: due to an oversight in how fixup tasks
e4a41f
worked, the entryuuid fixup task did not work correctly and
e4a41f
would not persist over restarts.
e4a41f
e4a41f
Fix Description: Correctly implement entryuuid fixup.
e4a41f
e4a41f
fixes: #4326
e4a41f
e4a41f
Author: William Brown <william@blackhats.net.au>
e4a41f
e4a41f
Review by: mreynolds (thanks!)
e4a41f
---
e4a41f
 .../tests/suites/entryuuid/basic_test.py      |  24 +++-
e4a41f
 src/plugins/entryuuid/src/lib.rs              |  43 ++++++-
e4a41f
 src/slapi_r_plugin/src/constants.rs           |   5 +
e4a41f
 src/slapi_r_plugin/src/entry.rs               |   8 ++
e4a41f
 src/slapi_r_plugin/src/lib.rs                 |   2 +
e4a41f
 src/slapi_r_plugin/src/macros.rs              |   2 +-
e4a41f
 src/slapi_r_plugin/src/modify.rs              | 118 ++++++++++++++++++
e4a41f
 src/slapi_r_plugin/src/pblock.rs              |   7 ++
e4a41f
 src/slapi_r_plugin/src/value.rs               |   4 +
e4a41f
 9 files changed, 206 insertions(+), 7 deletions(-)
e4a41f
 create mode 100644 src/slapi_r_plugin/src/modify.rs
e4a41f
e4a41f
diff --git a/dirsrvtests/tests/suites/entryuuid/basic_test.py b/dirsrvtests/tests/suites/entryuuid/basic_test.py
e4a41f
index beb73701d..4d8a40909 100644
e4a41f
--- a/dirsrvtests/tests/suites/entryuuid/basic_test.py
e4a41f
+++ b/dirsrvtests/tests/suites/entryuuid/basic_test.py
e4a41f
@@ -12,6 +12,7 @@ import time
e4a41f
 import shutil
e4a41f
 from lib389.idm.user import nsUserAccounts, UserAccounts
e4a41f
 from lib389.idm.account import Accounts
e4a41f
+from lib389.idm.domain import Domain
e4a41f
 from lib389.topologies import topology_st as topology
e4a41f
 from lib389.backend import Backends
e4a41f
 from lib389.paths import Paths
e4a41f
@@ -190,6 +191,7 @@ def test_entryuuid_fixup_task(topology):
e4a41f
         3. Enable the entryuuid plugin
e4a41f
         4. Run the fixup
e4a41f
         5. Assert the entryuuid now exists
e4a41f
+        6. Restart and check they persist
e4a41f
 
e4a41f
     :expectedresults:
e4a41f
         1. Success
e4a41f
@@ -197,6 +199,7 @@ def test_entryuuid_fixup_task(topology):
e4a41f
         3. Success
e4a41f
         4. Success
e4a41f
         5. Suddenly EntryUUID!
e4a41f
+        6. Still has EntryUUID!
e4a41f
     """
e4a41f
     # 1. Disable the plugin
e4a41f
     plug = EntryUUIDPlugin(topology.standalone)
e4a41f
@@ -220,7 +223,22 @@ def test_entryuuid_fixup_task(topology):
e4a41f
     assert(task.is_complete() and task.get_exit_code() == 0)
e4a41f
     topology.standalone.config.loglevel(vals=(ErrorLog.DEFAULT,))
e4a41f
 
e4a41f
-    # 5. Assert the uuid.
e4a41f
-    euuid = account.get_attr_val_utf8('entryUUID')
e4a41f
-    assert(euuid is not None)
e4a41f
+    # 5.1 Assert the uuid on the user.
e4a41f
+    euuid_user = account.get_attr_val_utf8('entryUUID')
e4a41f
+    assert(euuid_user is not None)
e4a41f
+
e4a41f
+    # 5.2 Assert it on the domain entry.
e4a41f
+    domain = Domain(topology.standalone, dn=DEFAULT_SUFFIX)
e4a41f
+    euuid_domain = domain.get_attr_val_utf8('entryUUID')
e4a41f
+    assert(euuid_domain is not None)
e4a41f
+
e4a41f
+    # Assert it persists after a restart.
e4a41f
+    topology.standalone.restart()
e4a41f
+    # 6.1 Assert the uuid on the use.
e4a41f
+    euuid_user_2 = account.get_attr_val_utf8('entryUUID')
e4a41f
+    assert(euuid_user_2 == euuid_user)
e4a41f
+
e4a41f
+    # 6.2 Assert it on the domain entry.
e4a41f
+    euuid_domain_2 = domain.get_attr_val_utf8('entryUUID')
e4a41f
+    assert(euuid_domain_2 == euuid_domain)
e4a41f
 
e4a41f
diff --git a/src/plugins/entryuuid/src/lib.rs b/src/plugins/entryuuid/src/lib.rs
e4a41f
index 6b5e8d1bb..92977db05 100644
e4a41f
--- a/src/plugins/entryuuid/src/lib.rs
e4a41f
+++ b/src/plugins/entryuuid/src/lib.rs
e4a41f
@@ -187,9 +187,46 @@ impl SlapiPlugin3 for EntryUuid {
e4a41f
     }
e4a41f
 }
e4a41f
 
e4a41f
-pub fn entryuuid_fixup_mapfn(mut e: EntryRef, _data: &()) -> Result<(), PluginError> {
e4a41f
-    assign_uuid(&mut e);
e4a41f
-    Ok(())
e4a41f
+pub fn entryuuid_fixup_mapfn(e: &EntryRef, _data: &()) -> Result<(), PluginError> {
e4a41f
+    /* Supply a modification to the entry. */
e4a41f
+    let sdn = e.get_sdnref();
e4a41f
+
e4a41f
+    /* Sanity check that entryuuid doesn't already exist */
e4a41f
+    if e.contains_attr("entryUUID") {
e4a41f
+        log_error!(
e4a41f
+            ErrorLevel::Trace,
e4a41f
+            "skipping fixup for -> {}",
e4a41f
+            sdn.to_dn_string()
e4a41f
+        );
e4a41f
+        return Ok(());
e4a41f
+    }
e4a41f
+
e4a41f
+    // Setup the modifications
e4a41f
+    let mut mods = SlapiMods::new();
e4a41f
+
e4a41f
+    let u: Uuid = Uuid::new_v4();
e4a41f
+    let uuid_value = Value::from(&u);
e4a41f
+    let values: ValueArray = std::iter::once(uuid_value).collect();
e4a41f
+    mods.append(ModType::Replace, "entryUUID", values);
e4a41f
+
e4a41f
+    /* */
e4a41f
+    let lmod = Modify::new(&sdn, mods, plugin_id())?;
e4a41f
+
e4a41f
+    match lmod.execute() {
e4a41f
+        Ok(_) => {
e4a41f
+            log_error!(ErrorLevel::Trace, "fixed-up -> {}", sdn.to_dn_string());
e4a41f
+            Ok(())
e4a41f
+        }
e4a41f
+        Err(e) => {
e4a41f
+            log_error!(
e4a41f
+                ErrorLevel::Error,
e4a41f
+                "entryuuid_fixup_mapfn -> fixup failed -> {} {:?}",
e4a41f
+                sdn.to_dn_string(),
e4a41f
+                e
e4a41f
+            );
e4a41f
+            Err(PluginError::GenericFailure)
e4a41f
+        }
e4a41f
+    }
e4a41f
 }
e4a41f
 
e4a41f
 #[cfg(test)]
e4a41f
diff --git a/src/slapi_r_plugin/src/constants.rs b/src/slapi_r_plugin/src/constants.rs
e4a41f
index cf76ccbdb..34845c2f4 100644
e4a41f
--- a/src/slapi_r_plugin/src/constants.rs
e4a41f
+++ b/src/slapi_r_plugin/src/constants.rs
e4a41f
@@ -5,6 +5,11 @@ use std::os::raw::c_char;
e4a41f
 pub const LDAP_SUCCESS: i32 = 0;
e4a41f
 pub const PLUGIN_DEFAULT_PRECEDENCE: i32 = 50;
e4a41f
 
e4a41f
+#[repr(i32)]
e4a41f
+pub enum OpFlags {
e4a41f
+    ByassReferrals = 0x0040_0000,
e4a41f
+}
e4a41f
+
e4a41f
 #[repr(i32)]
e4a41f
 /// The set of possible function handles we can register via the pblock. These
e4a41f
 /// values correspond to slapi-plugin.h.
e4a41f
diff --git a/src/slapi_r_plugin/src/entry.rs b/src/slapi_r_plugin/src/entry.rs
e4a41f
index 034efe692..22ae45189 100644
e4a41f
--- a/src/slapi_r_plugin/src/entry.rs
e4a41f
+++ b/src/slapi_r_plugin/src/entry.rs
e4a41f
@@ -70,6 +70,14 @@ impl EntryRef {
e4a41f
         }
e4a41f
     }
e4a41f
 
e4a41f
+    pub fn contains_attr(&self, name: &str) -> bool {
e4a41f
+        let cname = CString::new(name).expect("invalid attr name");
e4a41f
+        let va = unsafe { slapi_entry_attr_get_valuearray(self.raw_e, cname.as_ptr()) };
e4a41f
+
e4a41f
+        // If it's null, it's not present, so flip the logic.
e4a41f
+        !va.is_null()
e4a41f
+    }
e4a41f
+
e4a41f
     pub fn add_value(&mut self, a: &str, v: &ValueRef) {
e4a41f
         // turn the attr to a c string.
e4a41f
         // TODO FIX
e4a41f
diff --git a/src/slapi_r_plugin/src/lib.rs b/src/slapi_r_plugin/src/lib.rs
e4a41f
index d7fc22e52..076907bae 100644
e4a41f
--- a/src/slapi_r_plugin/src/lib.rs
e4a41f
+++ b/src/slapi_r_plugin/src/lib.rs
e4a41f
@@ -9,6 +9,7 @@ pub mod dn;
e4a41f
 pub mod entry;
e4a41f
 pub mod error;
e4a41f
 pub mod log;
e4a41f
+pub mod modify;
e4a41f
 pub mod pblock;
e4a41f
 pub mod plugin;
e4a41f
 pub mod search;
e4a41f
@@ -24,6 +25,7 @@ pub mod prelude {
e4a41f
     pub use crate::entry::EntryRef;
e4a41f
     pub use crate::error::{DseCallbackStatus, LDAPError, PluginError, RPluginError};
e4a41f
     pub use crate::log::{log_error, ErrorLevel};
e4a41f
+    pub use crate::modify::{ModType, Modify, SlapiMods};
e4a41f
     pub use crate::pblock::{Pblock, PblockRef};
e4a41f
     pub use crate::plugin::{register_plugin_ext, PluginIdRef, SlapiPlugin3};
e4a41f
     pub use crate::search::{Search, SearchScope};
e4a41f
diff --git a/src/slapi_r_plugin/src/macros.rs b/src/slapi_r_plugin/src/macros.rs
e4a41f
index 030449632..bc8dfa60f 100644
e4a41f
--- a/src/slapi_r_plugin/src/macros.rs
e4a41f
+++ b/src/slapi_r_plugin/src/macros.rs
e4a41f
@@ -825,7 +825,7 @@ macro_rules! slapi_r_search_callback_mapfn {
e4a41f
                 let e = EntryRef::new(raw_e);
e4a41f
                 let data_ptr = raw_data as *const _;
e4a41f
                 let data = unsafe { &(*data_ptr) };
e4a41f
-                match $cb_mod_ident(e, data) {
e4a41f
+                match $cb_mod_ident(&e, data) {
e4a41f
                     Ok(_) => LDAPError::Success as i32,
e4a41f
                     Err(e) => e as i32,
e4a41f
                 }
e4a41f
diff --git a/src/slapi_r_plugin/src/modify.rs b/src/slapi_r_plugin/src/modify.rs
e4a41f
new file mode 100644
e4a41f
index 000000000..30864377a
e4a41f
--- /dev/null
e4a41f
+++ b/src/slapi_r_plugin/src/modify.rs
e4a41f
@@ -0,0 +1,118 @@
e4a41f
+use crate::constants::OpFlags;
e4a41f
+use crate::dn::SdnRef;
e4a41f
+use crate::error::{LDAPError, PluginError};
e4a41f
+use crate::pblock::Pblock;
e4a41f
+use crate::plugin::PluginIdRef;
e4a41f
+use crate::value::{slapi_value, ValueArray};
e4a41f
+
e4a41f
+use std::ffi::CString;
e4a41f
+use std::ops::{Deref, DerefMut};
e4a41f
+use std::os::raw::c_char;
e4a41f
+
e4a41f
+extern "C" {
e4a41f
+    fn slapi_modify_internal_set_pb_ext(
e4a41f
+        pb: *const libc::c_void,
e4a41f
+        dn: *const libc::c_void,
e4a41f
+        mods: *const *const libc::c_void,
e4a41f
+        controls: *const *const libc::c_void,
e4a41f
+        uniqueid: *const c_char,
e4a41f
+        plugin_ident: *const libc::c_void,
e4a41f
+        op_flags: i32,
e4a41f
+    );
e4a41f
+    fn slapi_modify_internal_pb(pb: *const libc::c_void);
e4a41f
+    fn slapi_mods_free(smods: *const *const libc::c_void);
e4a41f
+    fn slapi_mods_get_ldapmods_byref(smods: *const libc::c_void) -> *const *const libc::c_void;
e4a41f
+    fn slapi_mods_new() -> *const libc::c_void;
e4a41f
+    fn slapi_mods_add_mod_values(
e4a41f
+        smods: *const libc::c_void,
e4a41f
+        mtype: i32,
e4a41f
+        attrtype: *const c_char,
e4a41f
+        value: *const *const slapi_value,
e4a41f
+    );
e4a41f
+}
e4a41f
+
e4a41f
+#[derive(Debug)]
e4a41f
+#[repr(i32)]
e4a41f
+pub enum ModType {
e4a41f
+    Add = 0,
e4a41f
+    Delete = 1,
e4a41f
+    Replace = 2,
e4a41f
+}
e4a41f
+
e4a41f
+pub struct SlapiMods {
e4a41f
+    inner: *const libc::c_void,
e4a41f
+    vas: Vec<ValueArray>,
e4a41f
+}
e4a41f
+
e4a41f
+impl Drop for SlapiMods {
e4a41f
+    fn drop(&mut self) {
e4a41f
+        unsafe { slapi_mods_free(&self.inner as *const *const libc::c_void) }
e4a41f
+    }
e4a41f
+}
e4a41f
+
e4a41f
+impl SlapiMods {
e4a41f
+    pub fn new() -> Self {
e4a41f
+        SlapiMods {
e4a41f
+            inner: unsafe { slapi_mods_new() },
e4a41f
+            vas: Vec::new(),
e4a41f
+        }
e4a41f
+    }
e4a41f
+
e4a41f
+    pub fn append(&mut self, modtype: ModType, attrtype: &str, values: ValueArray) {
e4a41f
+        // We can get the value array pointer here to push to the inner
e4a41f
+        // because the internal pointers won't change even when we push them
e4a41f
+        // to the list to preserve their lifetime.
e4a41f
+        let vas = values.as_ptr();
e4a41f
+        // We take ownership of this to ensure it lives as least as long as our
e4a41f
+        // slapimods structure.
e4a41f
+        self.vas.push(values);
e4a41f
+        // now we can insert these to the modes.
e4a41f
+        let c_attrtype = CString::new(attrtype).expect("failed to allocate attrtype");
e4a41f
+        unsafe { slapi_mods_add_mod_values(self.inner, modtype as i32, c_attrtype.as_ptr(), vas) };
e4a41f
+    }
e4a41f
+}
e4a41f
+
e4a41f
+pub struct Modify {
e4a41f
+    pb: Pblock,
e4a41f
+    mods: SlapiMods,
e4a41f
+}
e4a41f
+
e4a41f
+pub struct ModifyResult {
e4a41f
+    pb: Pblock,
e4a41f
+}
e4a41f
+
e4a41f
+impl Modify {
e4a41f
+    pub fn new(dn: &SdnRef, mods: SlapiMods, plugin_id: PluginIdRef) -> Result<Self, PluginError> {
e4a41f
+        let pb = Pblock::new();
e4a41f
+        let lmods = unsafe { slapi_mods_get_ldapmods_byref(mods.inner) };
e4a41f
+        // OP_FLAG_ACTION_LOG_ACCESS
e4a41f
+
e4a41f
+        unsafe {
e4a41f
+            slapi_modify_internal_set_pb_ext(
e4a41f
+                pb.deref().as_ptr(),
e4a41f
+                dn.as_ptr(),
e4a41f
+                lmods,
e4a41f
+                std::ptr::null(),
e4a41f
+                std::ptr::null(),
e4a41f
+                plugin_id.raw_pid,
e4a41f
+                OpFlags::ByassReferrals as i32,
e4a41f
+            )
e4a41f
+        };
e4a41f
+
e4a41f
+        Ok(Modify { pb, mods })
e4a41f
+    }
e4a41f
+
e4a41f
+    pub fn execute(self) -> Result<ModifyResult, LDAPError> {
e4a41f
+        let Modify {
e4a41f
+            mut pb,
e4a41f
+            mods: _mods,
e4a41f
+        } = self;
e4a41f
+        unsafe { slapi_modify_internal_pb(pb.deref().as_ptr()) };
e4a41f
+        let result = pb.get_op_result();
e4a41f
+
e4a41f
+        match result {
e4a41f
+            0 => Ok(ModifyResult { pb }),
e4a41f
+            _e => Err(LDAPError::from(result)),
e4a41f
+        }
e4a41f
+    }
e4a41f
+}
e4a41f
diff --git a/src/slapi_r_plugin/src/pblock.rs b/src/slapi_r_plugin/src/pblock.rs
e4a41f
index b69ce1680..0f83914f3 100644
e4a41f
--- a/src/slapi_r_plugin/src/pblock.rs
e4a41f
+++ b/src/slapi_r_plugin/src/pblock.rs
e4a41f
@@ -11,6 +11,7 @@ pub use crate::log::{log_error, ErrorLevel};
e4a41f
 extern "C" {
e4a41f
     fn slapi_pblock_set(pb: *const libc::c_void, arg: i32, value: *const libc::c_void) -> i32;
e4a41f
     fn slapi_pblock_get(pb: *const libc::c_void, arg: i32, value: *const libc::c_void) -> i32;
e4a41f
+    fn slapi_pblock_destroy(pb: *const libc::c_void);
e4a41f
     fn slapi_pblock_new() -> *const libc::c_void;
e4a41f
 }
e4a41f
 
e4a41f
@@ -41,6 +42,12 @@ impl DerefMut for Pblock {
e4a41f
     }
e4a41f
 }
e4a41f
 
e4a41f
+impl Drop for Pblock {
e4a41f
+    fn drop(&mut self) {
e4a41f
+        unsafe { slapi_pblock_destroy(self.value.raw_pb) }
e4a41f
+    }
e4a41f
+}
e4a41f
+
e4a41f
 pub struct PblockRef {
e4a41f
     raw_pb: *const libc::c_void,
e4a41f
 }
e4a41f
diff --git a/src/slapi_r_plugin/src/value.rs b/src/slapi_r_plugin/src/value.rs
e4a41f
index 5a40dd279..46246837a 100644
e4a41f
--- a/src/slapi_r_plugin/src/value.rs
e4a41f
+++ b/src/slapi_r_plugin/src/value.rs
e4a41f
@@ -96,6 +96,10 @@ impl ValueArray {
e4a41f
         let bs = vs.into_boxed_slice();
e4a41f
         Box::leak(bs) as *const _ as *const *const slapi_value
e4a41f
     }
e4a41f
+
e4a41f
+    pub fn as_ptr(&self) -> *const *const slapi_value {
e4a41f
+        self.data.as_ptr() as *const *const slapi_value
e4a41f
+    }
e4a41f
 }
e4a41f
 
e4a41f
 impl FromIterator<Value> for ValueArray {
e4a41f
-- 
e4a41f
2.26.3
e4a41f