api: list datastore: avoid iterating over NS for priv check, use AclTree

Make the assumption that if a user has any privilege that would make
an NS and (parts) of its content visible they also should be able to
know about the datastore and very basic errors on lookup (path
existence and maintenance mode) even if that NS doesn't even exists
(yet), as they could, e.g., make or view a backup and find out
anyway.

This avoids iterating over parts of the whole datastore folder tree
on disk, doing a priv check on each, swapping IO to virtual in memory
checks on info we got available already anyway, is always a good idea
after all

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
This commit is contained in:
Thomas Lamprecht 2022-06-04 14:57:30 +02:00
parent 2c69b69108
commit 8c9c6c0755
1 changed files with 5 additions and 6 deletions

View File

@ -64,7 +64,7 @@ use crate::api2::backup::optional_ns_param;
use crate::api2::node::rrd::create_value_from_rrd; use crate::api2::node::rrd::create_value_from_rrd;
use crate::backup::{ use crate::backup::{
can_access_any_namespace, check_ns_privs_full, verify_all_backups, verify_backup_dir, can_access_any_namespace, check_ns_privs_full, verify_all_backups, verify_backup_dir,
verify_backup_group, verify_filter, ListAccessibleBackupGroups, verify_backup_group, verify_filter, ListAccessibleBackupGroups, NS_PRIVS_OK,
}; };
use crate::server::jobstate::Job; use crate::server::jobstate::Job;
@ -1188,16 +1188,15 @@ pub fn get_datastore_list(
let mut list = Vec::new(); let mut list = Vec::new();
for (store, (_, data)) in &config.sections { for (store, (_, data)) in &config.sections {
let user_privs = user_info.lookup_privs(&auth_id, &["datastore", store]); let acl_path = &["datastore", store];
let user_privs = user_info.lookup_privs(&auth_id, acl_path);
let allowed = (user_privs & (PRIV_DATASTORE_AUDIT | PRIV_DATASTORE_BACKUP)) != 0; let allowed = (user_privs & (PRIV_DATASTORE_AUDIT | PRIV_DATASTORE_BACKUP)) != 0;
let mut allow_id = false; let mut allow_id = false;
if !allowed { if !allowed {
if let Ok(datastore) = DataStore::lookup_datastore(store, Some(Operation::Read)) { if let Ok(any_privs) = user_info.any_privs_below(&auth_id, acl_path, NS_PRIVS_OK) {
allow_id = can_access_any_namespace(datastore, &auth_id, &user_info); allow_id = any_privs;
} }
// FIXME: check for any ACL on the datastore below in the error case, otherwise offline
// datastore will disappear for users that can only access a specific namespace
} }
if allowed || allow_id { if allowed || allow_id {