priv handling: use DatastoreWithNamespace
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
This commit is contained in:
parent
99e1399729
commit
210ded9803
|
@ -82,14 +82,10 @@ fn get_group_note_path(
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: move somewhere we can reuse it from (namespace has its own copy atm.)
|
// TODO: move somewhere we can reuse it from (namespace has its own copy atm.)
|
||||||
fn get_ns_privs(store: &str, ns: &BackupNamespace, auth_id: &Authid) -> Result<u64, Error> {
|
fn get_ns_privs(store_with_ns: &DatastoreWithNamespace, auth_id: &Authid) -> Result<u64, Error> {
|
||||||
let user_info = CachedUserInfo::new()?;
|
let user_info = CachedUserInfo::new()?;
|
||||||
|
|
||||||
Ok(if ns.is_root() {
|
Ok(user_info.lookup_privs(auth_id, &store_with_ns.acl_path()))
|
||||||
user_info.lookup_privs(auth_id, &["datastore", store])
|
|
||||||
} else {
|
|
||||||
user_info.lookup_privs(auth_id, &["datastore", store, &ns.to_string()])
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// asserts that either either `full_access_privs` or `partial_access_privs` are fulfilled,
|
// asserts that either either `full_access_privs` or `partial_access_privs` are fulfilled,
|
||||||
|
@ -101,7 +97,11 @@ fn check_ns_privs(
|
||||||
full_access_privs: u64,
|
full_access_privs: u64,
|
||||||
partial_access_privs: u64,
|
partial_access_privs: u64,
|
||||||
) -> Result<bool, Error> {
|
) -> Result<bool, Error> {
|
||||||
let privs = get_ns_privs(store, ns, auth_id)?;
|
let store_with_ns = DatastoreWithNamespace {
|
||||||
|
store: store.to_string(),
|
||||||
|
ns: ns.clone(),
|
||||||
|
};
|
||||||
|
let privs = get_ns_privs(&store_with_ns, auth_id)?;
|
||||||
|
|
||||||
if full_access_privs != 0 && (privs & full_access_privs) != 0 {
|
if full_access_privs != 0 && (privs & full_access_privs) != 0 {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
|
@ -1199,7 +1199,11 @@ fn can_access_any_ns(store: Arc<DataStore>, auth_id: &Authid, user_info: &Cached
|
||||||
PRIV_DATASTORE_AUDIT | PRIV_DATASTORE_MODIFY | PRIV_DATASTORE_READ | PRIV_DATASTORE_BACKUP;
|
PRIV_DATASTORE_AUDIT | PRIV_DATASTORE_MODIFY | PRIV_DATASTORE_READ | PRIV_DATASTORE_BACKUP;
|
||||||
let name = store.name();
|
let name = store.name();
|
||||||
iter.any(|ns| -> bool {
|
iter.any(|ns| -> bool {
|
||||||
let user_privs = user_info.lookup_privs(&auth_id, &["datastore", name, &ns.to_string()]);
|
let store_with_ns = DatastoreWithNamespace {
|
||||||
|
store: name.to_string(),
|
||||||
|
ns: ns,
|
||||||
|
};
|
||||||
|
let user_privs = user_info.lookup_privs(&auth_id, &store_with_ns.acl_path());
|
||||||
user_privs & wanted != 0
|
user_privs & wanted != 0
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,21 +6,18 @@ use proxmox_router::{http_bail, ApiMethod, Permission, Router, RpcEnvironment};
|
||||||
use proxmox_schema::*;
|
use proxmox_schema::*;
|
||||||
|
|
||||||
use pbs_api_types::{
|
use pbs_api_types::{
|
||||||
Authid, BackupNamespace, NamespaceListItem, Operation, DATASTORE_SCHEMA, NS_MAX_DEPTH_SCHEMA,
|
Authid, BackupNamespace, DatastoreWithNamespace, NamespaceListItem, Operation,
|
||||||
PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_BACKUP, PRIV_DATASTORE_MODIFY, PROXMOX_SAFE_ID_FORMAT,
|
DATASTORE_SCHEMA, NS_MAX_DEPTH_SCHEMA, PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_BACKUP,
|
||||||
|
PRIV_DATASTORE_MODIFY, PROXMOX_SAFE_ID_FORMAT,
|
||||||
};
|
};
|
||||||
|
|
||||||
use pbs_datastore::DataStore;
|
use pbs_datastore::DataStore;
|
||||||
|
|
||||||
// TODO: move somewhere we can reuse it from (datastore has its own copy atm.)
|
// TODO: move somewhere we can reuse it from (datastore has its own copy atm.)
|
||||||
fn get_ns_privs(store: &str, ns: &BackupNamespace, auth_id: &Authid) -> Result<u64, Error> {
|
fn get_ns_privs(store_with_ns: &DatastoreWithNamespace, auth_id: &Authid) -> Result<u64, Error> {
|
||||||
let user_info = CachedUserInfo::new()?;
|
let user_info = CachedUserInfo::new()?;
|
||||||
|
|
||||||
Ok(if ns.is_root() {
|
Ok(user_info.lookup_privs(auth_id, &store_with_ns.acl_path()))
|
||||||
user_info.lookup_privs(auth_id, &["datastore", store])
|
|
||||||
} else {
|
|
||||||
user_info.lookup_privs(auth_id, &["datastore", store, &ns.to_string()])
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[api(
|
#[api(
|
||||||
|
@ -59,7 +56,12 @@ pub fn create_namespace(
|
||||||
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
||||||
let parent = parent.unwrap_or_default();
|
let parent = parent.unwrap_or_default();
|
||||||
|
|
||||||
if get_ns_privs(&store, &parent, &auth_id)? & PRIV_DATASTORE_MODIFY == 0 {
|
let store_with_parent = DatastoreWithNamespace {
|
||||||
|
store: store.clone(),
|
||||||
|
ns: parent.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if get_ns_privs(&store_with_parent, &auth_id)? & PRIV_DATASTORE_MODIFY == 0 {
|
||||||
proxmox_router::http_bail!(FORBIDDEN, "permission check failed");
|
proxmox_router::http_bail!(FORBIDDEN, "permission check failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +106,12 @@ pub fn list_namespaces(
|
||||||
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
||||||
const PRIVS_OK: u64 = PRIV_DATASTORE_MODIFY | PRIV_DATASTORE_BACKUP | PRIV_DATASTORE_AUDIT;
|
const PRIVS_OK: u64 = PRIV_DATASTORE_MODIFY | PRIV_DATASTORE_BACKUP | PRIV_DATASTORE_AUDIT;
|
||||||
// first do a base check to avoid leaking if a NS exists or not
|
// first do a base check to avoid leaking if a NS exists or not
|
||||||
if get_ns_privs(&store, &parent, &auth_id)? & PRIVS_OK == 0 {
|
let store_with_parent = DatastoreWithNamespace {
|
||||||
|
store: store.clone(),
|
||||||
|
ns: parent.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if get_ns_privs(&store_with_parent, &auth_id)? & PRIVS_OK == 0 {
|
||||||
proxmox_router::http_bail!(FORBIDDEN, "permission check failed");
|
proxmox_router::http_bail!(FORBIDDEN, "permission check failed");
|
||||||
}
|
}
|
||||||
let user_info = CachedUserInfo::new()?;
|
let user_info = CachedUserInfo::new()?;
|
||||||
|
@ -161,7 +168,11 @@ pub fn delete_namespace(
|
||||||
};
|
};
|
||||||
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
||||||
let parent = ns.parent(); // must have MODIFY permission on parent to allow deletion
|
let parent = ns.parent(); // must have MODIFY permission on parent to allow deletion
|
||||||
if get_ns_privs(&store, &parent, &auth_id)? & PRIV_DATASTORE_MODIFY == 0 {
|
let store_with_parent = DatastoreWithNamespace {
|
||||||
|
store: store.clone(),
|
||||||
|
ns: parent.clone(),
|
||||||
|
};
|
||||||
|
if get_ns_privs(&store_with_parent, &auth_id)? & PRIV_DATASTORE_MODIFY == 0 {
|
||||||
http_bail!(FORBIDDEN, "permission check failed");
|
http_bail!(FORBIDDEN, "permission check failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,9 +17,10 @@ use proxmox_schema::*;
|
||||||
use proxmox_sys::sortable;
|
use proxmox_sys::sortable;
|
||||||
|
|
||||||
use pbs_api_types::{
|
use pbs_api_types::{
|
||||||
Authid, BackupNamespace, BackupType, Operation, SnapshotVerifyState, VerifyState,
|
Authid, BackupNamespace, BackupType, DatastoreWithNamespace, Operation, SnapshotVerifyState,
|
||||||
BACKUP_ARCHIVE_NAME_SCHEMA, BACKUP_ID_SCHEMA, BACKUP_NAMESPACE_SCHEMA, BACKUP_TIME_SCHEMA,
|
VerifyState, BACKUP_ARCHIVE_NAME_SCHEMA, BACKUP_ID_SCHEMA, BACKUP_NAMESPACE_SCHEMA,
|
||||||
BACKUP_TYPE_SCHEMA, CHUNK_DIGEST_SCHEMA, DATASTORE_SCHEMA, PRIV_DATASTORE_BACKUP,
|
BACKUP_TIME_SCHEMA, BACKUP_TYPE_SCHEMA, CHUNK_DIGEST_SCHEMA, DATASTORE_SCHEMA,
|
||||||
|
PRIV_DATASTORE_BACKUP,
|
||||||
};
|
};
|
||||||
use pbs_config::CachedUserInfo;
|
use pbs_config::CachedUserInfo;
|
||||||
use pbs_datastore::index::IndexFile;
|
use pbs_datastore::index::IndexFile;
|
||||||
|
@ -81,15 +82,15 @@ fn upgrade_to_backup_protocol(
|
||||||
|
|
||||||
let store = required_string_param(¶m, "store")?.to_owned();
|
let store = required_string_param(¶m, "store")?.to_owned();
|
||||||
let backup_ns = optional_ns_param(¶m)?;
|
let backup_ns = optional_ns_param(¶m)?;
|
||||||
|
let store_with_ns = DatastoreWithNamespace {
|
||||||
|
store: store.clone(),
|
||||||
|
ns: backup_ns.clone(),
|
||||||
|
};
|
||||||
let backup_dir_arg = pbs_api_types::BackupDir::deserialize(¶m)?;
|
let backup_dir_arg = pbs_api_types::BackupDir::deserialize(¶m)?;
|
||||||
|
|
||||||
let user_info = CachedUserInfo::new()?;
|
let user_info = CachedUserInfo::new()?;
|
||||||
|
|
||||||
let privs = if backup_ns.is_root() {
|
let privs = user_info.lookup_privs(&auth_id, &store_with_ns.acl_path());
|
||||||
user_info.lookup_privs(&auth_id, &["datastore", &store])
|
|
||||||
} else {
|
|
||||||
user_info.lookup_privs(&auth_id, &["datastore", &store, &backup_ns.to_string()])
|
|
||||||
};
|
|
||||||
if privs & PRIV_DATASTORE_BACKUP == 0 {
|
if privs & PRIV_DATASTORE_BACKUP == 0 {
|
||||||
proxmox_router::http_bail!(FORBIDDEN, "permission check failed");
|
proxmox_router::http_bail!(FORBIDDEN, "permission check failed");
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,8 @@ use std::sync::Arc;
|
||||||
use anyhow::Error;
|
use anyhow::Error;
|
||||||
|
|
||||||
use pbs_api_types::{
|
use pbs_api_types::{
|
||||||
Authid, BackupNamespace, PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_BACKUP, PRIV_DATASTORE_MODIFY,
|
Authid, BackupNamespace, DatastoreWithNamespace, PRIV_DATASTORE_AUDIT, PRIV_DATASTORE_BACKUP,
|
||||||
PRIV_DATASTORE_READ,
|
PRIV_DATASTORE_MODIFY, PRIV_DATASTORE_READ,
|
||||||
};
|
};
|
||||||
use pbs_config::CachedUserInfo;
|
use pbs_config::CachedUserInfo;
|
||||||
use pbs_datastore::{backup_info::BackupGroup, DataStore, ListGroups, ListNamespacesRecursive};
|
use pbs_datastore::{backup_info::BackupGroup, DataStore, ListGroups, ListNamespacesRecursive};
|
||||||
|
@ -100,14 +100,12 @@ impl<'a> Iterator for ListAccessibleBackupGroups<'a> {
|
||||||
let mut override_owner = false;
|
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 store_with_ns = DatastoreWithNamespace {
|
||||||
info.lookup_privs(&auth_id, &["datastore", self.store.name()])
|
store: self.store.name().to_string(),
|
||||||
} else {
|
ns: ns.clone(),
|
||||||
info.lookup_privs(
|
|
||||||
&auth_id,
|
|
||||||
&["datastore", self.store.name(), &ns.to_string()],
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
let privs = info.lookup_privs(&auth_id, &store_with_ns.acl_path());
|
||||||
|
|
||||||
if privs & NS_PRIVS_OK == 0 {
|
if privs & NS_PRIVS_OK == 0 {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue