tape: finish api permission checks
This commit is contained in:
parent
ee33795b72
commit
b4975d3102
@ -20,7 +20,9 @@ use crate::{
|
||||
self,
|
||||
cached_user_info::CachedUserInfo,
|
||||
acl::{
|
||||
PRIV_DATASTORE_READ,
|
||||
PRIV_TAPE_AUDIT,
|
||||
PRIV_TAPE_WRITE,
|
||||
},
|
||||
tape_job::{
|
||||
TapeBackupJobConfig,
|
||||
@ -71,6 +73,33 @@ pub const ROUTER: Router = Router::new()
|
||||
.post(&API_METHOD_BACKUP)
|
||||
.match_all("id", &TAPE_BACKUP_JOB_ROUTER);
|
||||
|
||||
fn check_backup_permission(
|
||||
auth_id: &Authid,
|
||||
store: &str,
|
||||
pool: &str,
|
||||
drive: &str,
|
||||
) -> Result<(), Error> {
|
||||
|
||||
let user_info = CachedUserInfo::new()?;
|
||||
|
||||
let privs = user_info.lookup_privs(auth_id, &["datastore", store]);
|
||||
if (privs & PRIV_DATASTORE_READ) == 0 {
|
||||
bail!("no permissions on /datastore/{}", store);
|
||||
}
|
||||
|
||||
let privs = user_info.lookup_privs(auth_id, &["tape", "drive", drive]);
|
||||
if (privs & PRIV_TAPE_WRITE) == 0 {
|
||||
bail!("no permissions on /tape/drive/{}", drive);
|
||||
}
|
||||
|
||||
let privs = user_info.lookup_privs(auth_id, &["tape", "pool", pool]);
|
||||
if (privs & PRIV_TAPE_WRITE) == 0 {
|
||||
bail!("no permissions on /tape/pool/{}", pool);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[api(
|
||||
returns: {
|
||||
description: "List configured thape backup jobs and their status",
|
||||
@ -202,6 +231,12 @@ pub fn do_tape_backup_job(
|
||||
},
|
||||
},
|
||||
},
|
||||
access: {
|
||||
// Note: parameters are from job config, so we need to test inside function body
|
||||
description: "The user needs Tape.Write privilege on /tape/pool/{pool} \
|
||||
and /tape/drive/{drive}, Datastore.Read privilege on /datastore/{store}.",
|
||||
permission: &Permission::Anybody,
|
||||
},
|
||||
)]
|
||||
/// Runs a tape backup job manually.
|
||||
pub fn run_tape_backup_job(
|
||||
@ -213,6 +248,13 @@ pub fn run_tape_backup_job(
|
||||
let (config, _digest) = config::tape_job::config()?;
|
||||
let backup_job: TapeBackupJobConfig = config.lookup("backup", &id)?;
|
||||
|
||||
check_backup_permission(
|
||||
&auth_id,
|
||||
&backup_job.setup.store,
|
||||
&backup_job.setup.pool,
|
||||
&backup_job.setup.drive,
|
||||
)?;
|
||||
|
||||
let job = Job::new("tape-backup-job", &id)?;
|
||||
|
||||
let upid_str = do_tape_backup_job(job, backup_job.setup, &auth_id, None)?;
|
||||
@ -232,6 +274,12 @@ pub fn run_tape_backup_job(
|
||||
returns: {
|
||||
schema: UPID_SCHEMA,
|
||||
},
|
||||
access: {
|
||||
// Note: parameters are no uri parameter, so we need to test inside function body
|
||||
description: "The user needs Tape.Write privilege on /tape/pool/{pool} \
|
||||
and /tape/drive/{drive}, Datastore.Read privilege on /datastore/{store}.",
|
||||
permission: &Permission::Anybody,
|
||||
},
|
||||
)]
|
||||
/// Backup datastore to tape media pool
|
||||
pub fn backup(
|
||||
@ -241,6 +289,13 @@ pub fn backup(
|
||||
|
||||
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
||||
|
||||
check_backup_permission(
|
||||
&auth_id,
|
||||
&setup.store,
|
||||
&setup.pool,
|
||||
&setup.drive,
|
||||
)?;
|
||||
|
||||
let datastore = DataStore::lookup_datastore(&setup.store)?;
|
||||
|
||||
let (config, _digest) = config::media_pool::config()?;
|
||||
|
@ -13,6 +13,7 @@ use crate::{
|
||||
cached_user_info::CachedUserInfo,
|
||||
acl::{
|
||||
PRIV_TAPE_AUDIT,
|
||||
PRIV_TAPE_READ,
|
||||
},
|
||||
},
|
||||
api2::types::{
|
||||
@ -60,6 +61,9 @@ use crate::{
|
||||
type: MtxStatusEntry,
|
||||
},
|
||||
},
|
||||
access: {
|
||||
permission: &Permission::Privilege(&["tape", "device", "{name}"], PRIV_TAPE_AUDIT, false),
|
||||
},
|
||||
)]
|
||||
/// Get tape changer status
|
||||
pub async fn get_status(
|
||||
@ -156,6 +160,9 @@ pub async fn get_status(
|
||||
},
|
||||
},
|
||||
},
|
||||
access: {
|
||||
permission: &Permission::Privilege(&["tape", "device", "{name}"], PRIV_TAPE_READ, false),
|
||||
},
|
||||
)]
|
||||
/// Transfers media from one slot to another
|
||||
pub async fn transfer(
|
||||
|
@ -29,6 +29,8 @@ use crate::{
|
||||
cached_user_info::CachedUserInfo,
|
||||
acl::{
|
||||
PRIV_TAPE_AUDIT,
|
||||
PRIV_TAPE_READ,
|
||||
PRIV_TAPE_WRITE,
|
||||
},
|
||||
},
|
||||
api2::{
|
||||
@ -143,6 +145,9 @@ where
|
||||
returns: {
|
||||
schema: UPID_SCHEMA,
|
||||
},
|
||||
access: {
|
||||
permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_READ, false),
|
||||
},
|
||||
)]
|
||||
/// Load media with specified label
|
||||
///
|
||||
@ -182,6 +187,9 @@ pub fn load_media(
|
||||
},
|
||||
},
|
||||
},
|
||||
access: {
|
||||
permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_READ, false),
|
||||
},
|
||||
)]
|
||||
/// Load media from the specified slot
|
||||
///
|
||||
@ -215,6 +223,9 @@ pub async fn load_slot(drive: String, source_slot: u64) -> Result<(), Error> {
|
||||
type: u64,
|
||||
minimum: 1,
|
||||
},
|
||||
access: {
|
||||
permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_READ, false),
|
||||
},
|
||||
)]
|
||||
/// Export media with specified label
|
||||
pub async fn export_media(drive: String, label_text: String) -> Result<u64, Error> {
|
||||
@ -252,6 +263,9 @@ pub async fn export_media(drive: String, label_text: String) -> Result<u64, Erro
|
||||
returns: {
|
||||
schema: UPID_SCHEMA,
|
||||
},
|
||||
access: {
|
||||
permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_READ, false),
|
||||
},
|
||||
)]
|
||||
/// Unload media via changer
|
||||
pub fn unload(
|
||||
@ -297,6 +311,9 @@ pub fn unload(
|
||||
returns: {
|
||||
schema: UPID_SCHEMA,
|
||||
},
|
||||
access: {
|
||||
permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_WRITE, false),
|
||||
},
|
||||
)]
|
||||
/// Erase media. Check for label-text if given (cancels if wrong media).
|
||||
pub fn erase_media(
|
||||
@ -381,6 +398,9 @@ pub fn erase_media(
|
||||
returns: {
|
||||
schema: UPID_SCHEMA,
|
||||
},
|
||||
access: {
|
||||
permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_READ, false),
|
||||
},
|
||||
)]
|
||||
/// Rewind tape
|
||||
pub fn rewind(
|
||||
@ -413,6 +433,9 @@ pub fn rewind(
|
||||
returns: {
|
||||
schema: UPID_SCHEMA,
|
||||
},
|
||||
access: {
|
||||
permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_READ, false),
|
||||
},
|
||||
)]
|
||||
/// Eject/Unload drive media
|
||||
pub fn eject_media(
|
||||
@ -456,6 +479,9 @@ pub fn eject_media(
|
||||
returns: {
|
||||
schema: UPID_SCHEMA,
|
||||
},
|
||||
access: {
|
||||
permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_WRITE, false),
|
||||
},
|
||||
)]
|
||||
/// Label media
|
||||
///
|
||||
@ -588,6 +614,9 @@ fn write_media_label(
|
||||
},
|
||||
},
|
||||
},
|
||||
access: {
|
||||
permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_READ, false),
|
||||
},
|
||||
)]
|
||||
/// Try to restore a tape encryption key
|
||||
pub async fn restore_key(
|
||||
@ -631,6 +660,9 @@ pub async fn restore_key(
|
||||
returns: {
|
||||
type: MediaIdFlat,
|
||||
},
|
||||
access: {
|
||||
permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_READ, false),
|
||||
},
|
||||
)]
|
||||
/// Read media label (optionally inventorize media)
|
||||
pub async fn read_label(
|
||||
@ -706,6 +738,9 @@ pub async fn read_label(
|
||||
returns: {
|
||||
schema: UPID_SCHEMA,
|
||||
},
|
||||
access: {
|
||||
permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_READ, false),
|
||||
},
|
||||
)]
|
||||
/// Clean drive
|
||||
pub fn clean_drive(
|
||||
@ -748,6 +783,9 @@ pub fn clean_drive(
|
||||
type: LabelUuidMap,
|
||||
},
|
||||
},
|
||||
access: {
|
||||
permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_READ, false),
|
||||
},
|
||||
)]
|
||||
/// List known media labels (Changer Inventory)
|
||||
///
|
||||
@ -817,6 +855,9 @@ pub async fn inventory(
|
||||
returns: {
|
||||
schema: UPID_SCHEMA,
|
||||
},
|
||||
access: {
|
||||
permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_READ, false),
|
||||
},
|
||||
)]
|
||||
/// Update inventory
|
||||
///
|
||||
@ -911,6 +952,9 @@ pub fn update_inventory(
|
||||
returns: {
|
||||
schema: UPID_SCHEMA,
|
||||
},
|
||||
access: {
|
||||
permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_WRITE, false),
|
||||
},
|
||||
)]
|
||||
/// Label media with barcodes from changer device
|
||||
pub fn barcode_label_media(
|
||||
@ -1020,6 +1064,9 @@ fn barcode_label_media_worker(
|
||||
type: MamAttribute,
|
||||
},
|
||||
},
|
||||
access: {
|
||||
permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_AUDIT, false),
|
||||
},
|
||||
)]
|
||||
/// Read Cartridge Memory (Medium auxiliary memory attributes)
|
||||
pub async fn cartridge_memory(drive: String) -> Result<Vec<MamAttribute>, Error> {
|
||||
@ -1047,6 +1094,9 @@ pub async fn cartridge_memory(drive: String) -> Result<Vec<MamAttribute>, Error>
|
||||
returns: {
|
||||
type: Lp17VolumeStatistics,
|
||||
},
|
||||
access: {
|
||||
permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_AUDIT, false),
|
||||
},
|
||||
)]
|
||||
/// Read Volume Statistics (SCSI log page 17h)
|
||||
pub async fn volume_statistics(drive: String) -> Result<Lp17VolumeStatistics, Error> {
|
||||
@ -1074,6 +1124,9 @@ pub async fn volume_statistics(drive: String) -> Result<Lp17VolumeStatistics, Er
|
||||
returns: {
|
||||
type: LinuxDriveAndMediaStatus,
|
||||
},
|
||||
access: {
|
||||
permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_AUDIT, false),
|
||||
},
|
||||
)]
|
||||
/// Get drive/media status
|
||||
pub async fn status(drive: String) -> Result<LinuxDriveAndMediaStatus, Error> {
|
||||
@ -1115,6 +1168,9 @@ pub async fn status(drive: String) -> Result<LinuxDriveAndMediaStatus, Error> {
|
||||
returns: {
|
||||
schema: UPID_SCHEMA,
|
||||
},
|
||||
access: {
|
||||
permission: &Permission::Privilege(&["tape", "device", "{drive}"], PRIV_TAPE_READ, false),
|
||||
},
|
||||
)]
|
||||
/// Scan media and record content
|
||||
pub fn catalog_media(
|
||||
|
@ -11,6 +11,7 @@ use proxmox::{
|
||||
RpcEnvironment,
|
||||
RpcEnvironmentType,
|
||||
Router,
|
||||
Permission,
|
||||
section_config::SectionConfigData,
|
||||
},
|
||||
tools::{
|
||||
@ -33,7 +34,14 @@ use crate::{
|
||||
UPID_SCHEMA,
|
||||
Authid,
|
||||
},
|
||||
config,
|
||||
config::{
|
||||
self,
|
||||
cached_user_info::CachedUserInfo,
|
||||
acl::{
|
||||
PRIV_DATASTORE_BACKUP,
|
||||
PRIV_TAPE_READ,
|
||||
},
|
||||
},
|
||||
backup::{
|
||||
archive_type,
|
||||
MANIFEST_BLOB_NAME,
|
||||
@ -76,7 +84,6 @@ use crate::{
|
||||
pub const ROUTER: Router = Router::new()
|
||||
.post(&API_METHOD_RESTORE);
|
||||
|
||||
|
||||
#[api(
|
||||
input: {
|
||||
properties: {
|
||||
@ -95,6 +102,12 @@ pub const ROUTER: Router = Router::new()
|
||||
returns: {
|
||||
schema: UPID_SCHEMA,
|
||||
},
|
||||
access: {
|
||||
// Note: parameters are no uri parameter, so we need to test inside function body
|
||||
description: "The user needs Tape.Read privilege on /tape/pool/{pool} \
|
||||
and /tape/drive/{drive}, Datastore.Backup privilege on /datastore/{store}.",
|
||||
permission: &Permission::Anybody,
|
||||
},
|
||||
)]
|
||||
/// Restore data from media-set
|
||||
pub fn restore(
|
||||
@ -104,9 +117,18 @@ pub fn restore(
|
||||
rpcenv: &mut dyn RpcEnvironment,
|
||||
) -> Result<Value, Error> {
|
||||
|
||||
let datastore = DataStore::lookup_datastore(&store)?;
|
||||
|
||||
let auth_id: Authid = rpcenv.get_auth_id().unwrap().parse()?;
|
||||
let user_info = CachedUserInfo::new()?;
|
||||
|
||||
let privs = user_info.lookup_privs(&auth_id, &["datastore", &store]);
|
||||
if (privs & PRIV_DATASTORE_BACKUP) == 0 {
|
||||
bail!("no permissions on /datastore/{}", store);
|
||||
}
|
||||
|
||||
let privs = user_info.lookup_privs(&auth_id, &["tape", "drive", &drive]);
|
||||
if (privs & PRIV_TAPE_READ) == 0 {
|
||||
bail!("no permissions on /tape/drive/{}", drive);
|
||||
}
|
||||
|
||||
let status_path = Path::new(TAPE_STATUS_DIR);
|
||||
let inventory = Inventory::load(status_path)?;
|
||||
@ -115,6 +137,13 @@ pub fn restore(
|
||||
|
||||
let pool = inventory.lookup_media_set_pool(&media_set_uuid)?;
|
||||
|
||||
let privs = user_info.lookup_privs(&auth_id, &["tape", "pool", &pool]);
|
||||
if (privs & PRIV_TAPE_READ) == 0 {
|
||||
bail!("no permissions on /tape/pool/{}", pool);
|
||||
}
|
||||
|
||||
let datastore = DataStore::lookup_datastore(&store)?;
|
||||
|
||||
let (drive_config, _digest) = config::drive::config()?;
|
||||
|
||||
// early check/lock before starting worker
|
||||
|
Loading…
Reference in New Issue
Block a user