From 71cad8cac090751392e4ba4770665606f6925036 Mon Sep 17 00:00:00 2001 From: Thomas Lamprecht Date: Thu, 19 May 2022 12:27:55 +0200 Subject: [PATCH] accessible group iter: add owner override and owner + extra priv handling The "owner override" privs will skip the owner check completely if the authid has a permission for any of the bitwise OR'd privs requested on the namespace level. The "owner and privs" are for the case where being the owner is not enough, e.g., pruning, if set they need to match all, not just any, on the namespace, otherwise we don't even look at the groups from the current NS level. Signed-off-by: Thomas Lamprecht --- src/backup/hierarchy.rs | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/src/backup/hierarchy.rs b/src/backup/hierarchy.rs index 9d6580f1..6728cf3d 100644 --- a/src/backup/hierarchy.rs +++ b/src/backup/hierarchy.rs @@ -18,7 +18,12 @@ pub struct ListAccessibleBackupGroups<'a> { store: &'a Arc, auth_id: Option<&'a Authid>, user_info: Arc, - state: Option, + /// The priv on NS level that allows auth_id trump the owner check + override_owner_priv: u64, + /// The priv that auth_id is required to have on NS level additionally to being owner + owner_and_priv: u64, + /// Contains the intertnal state, group iter and a bool flag for override_owner_priv + state: Option<(ListGroups, bool)>, ns_iter: ListNamespacesRecursive, } @@ -30,11 +35,25 @@ impl<'a> ListAccessibleBackupGroups<'a> { ns: BackupNamespace, max_depth: usize, auth_id: Option<&'a Authid>, + ) -> Result { + // only owned groups by default and no extra priv required + Self::new_with_privs(store, ns, max_depth, None, None, auth_id) + } + + pub fn new_with_privs( + store: &'a Arc, + ns: BackupNamespace, + max_depth: usize, + override_owner_priv: Option, + owner_and_priv: Option, + auth_id: Option<&'a Authid>, ) -> Result { let ns_iter = ListNamespacesRecursive::new_max_depth(Arc::clone(store), ns, max_depth)?; Ok(ListAccessibleBackupGroups { auth_id, ns_iter, + override_owner_priv: override_owner_priv.unwrap_or(0), + owner_and_priv: owner_and_priv.unwrap_or(0), state: None, store: store, user_info: CachedUserInfo::new()?, @@ -50,9 +69,12 @@ impl<'a> Iterator for ListAccessibleBackupGroups<'a> { fn next(&mut self) -> Option { loop { - if let Some(ref mut state) = self.state { + if let Some((ref mut state, override_owner)) = self.state { match state.next() { Some(Ok(group)) => { + if override_owner { + return Some(Ok(group)); + } if let Some(auth_id) = &self.auth_id { match self.store.owns_backup( &group.backup_ns(), @@ -75,6 +97,7 @@ impl<'a> Iterator for ListAccessibleBackupGroups<'a> { } else { match self.ns_iter.next() { Some(Ok(ns)) => { + let mut override_owner = false; if let Some(auth_id) = &self.auth_id { let info = &self.user_info; let privs = if ns.is_root() { @@ -85,12 +108,19 @@ impl<'a> Iterator for ListAccessibleBackupGroups<'a> { &["datastore", self.store.name(), &ns.to_string()], ) }; - if privs & PRIVS_OK == 0 { + if privs & NS_PRIVS_OK == 0 { continue; } + + // check first if *any* override owner priv is available up front + if privs & self.override_owner_priv != 0 { + override_owner = true; + } else if privs & self.owner_and_priv != self.owner_and_priv { + continue; // no owner override and no extra privs -> nothing visible + } } self.state = match ListGroups::new(Arc::clone(&self.store), ns) { - Ok(iter) => Some(iter), + Ok(iter) => Some((iter, override_owner)), Err(err) => return Some(Err(err)), }; }