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 <t.lamprecht@proxmox.com>
This commit is contained in:
Thomas Lamprecht 2022-05-19 12:27:55 +02:00
parent 49bea6b5d9
commit 71cad8cac0
1 changed files with 34 additions and 4 deletions

View File

@ -18,7 +18,12 @@ pub struct ListAccessibleBackupGroups<'a> {
store: &'a Arc<DataStore>, store: &'a Arc<DataStore>,
auth_id: Option<&'a Authid>, auth_id: Option<&'a Authid>,
user_info: Arc<CachedUserInfo>, user_info: Arc<CachedUserInfo>,
state: Option<ListGroups>, /// 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, ns_iter: ListNamespacesRecursive,
} }
@ -30,11 +35,25 @@ impl<'a> ListAccessibleBackupGroups<'a> {
ns: BackupNamespace, ns: BackupNamespace,
max_depth: usize, max_depth: usize,
auth_id: Option<&'a Authid>, auth_id: Option<&'a Authid>,
) -> Result<Self, Error> {
// 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<DataStore>,
ns: BackupNamespace,
max_depth: usize,
override_owner_priv: Option<u64>,
owner_and_priv: Option<u64>,
auth_id: Option<&'a Authid>,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
let ns_iter = ListNamespacesRecursive::new_max_depth(Arc::clone(store), ns, max_depth)?; let ns_iter = ListNamespacesRecursive::new_max_depth(Arc::clone(store), ns, max_depth)?;
Ok(ListAccessibleBackupGroups { Ok(ListAccessibleBackupGroups {
auth_id, auth_id,
ns_iter, ns_iter,
override_owner_priv: override_owner_priv.unwrap_or(0),
owner_and_priv: owner_and_priv.unwrap_or(0),
state: None, state: None,
store: store, store: store,
user_info: CachedUserInfo::new()?, user_info: CachedUserInfo::new()?,
@ -50,9 +69,12 @@ impl<'a> Iterator for ListAccessibleBackupGroups<'a> {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
loop { loop {
if let Some(ref mut state) = self.state { if let Some((ref mut state, override_owner)) = self.state {
match state.next() { match state.next() {
Some(Ok(group)) => { Some(Ok(group)) => {
if override_owner {
return Some(Ok(group));
}
if let Some(auth_id) = &self.auth_id { if let Some(auth_id) = &self.auth_id {
match self.store.owns_backup( match self.store.owns_backup(
&group.backup_ns(), &group.backup_ns(),
@ -75,6 +97,7 @@ impl<'a> Iterator for ListAccessibleBackupGroups<'a> {
} else { } else {
match self.ns_iter.next() { match self.ns_iter.next() {
Some(Ok(ns)) => { Some(Ok(ns)) => {
let mut override_owner = false;
if let Some(auth_id) = &self.auth_id { if let Some(auth_id) = &self.auth_id {
let info = &self.user_info; let info = &self.user_info;
let privs = if ns.is_root() { let privs = if ns.is_root() {
@ -85,12 +108,19 @@ impl<'a> Iterator for ListAccessibleBackupGroups<'a> {
&["datastore", self.store.name(), &ns.to_string()], &["datastore", self.store.name(), &ns.to_string()],
) )
}; };
if privs & PRIVS_OK == 0 { if privs & NS_PRIVS_OK == 0 {
continue; 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) { 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)), Err(err) => return Some(Err(err)),
}; };
} }