tape: finish api permission checks

This commit is contained in:
Dietmar Maurer 2021-03-05 11:40:52 +01:00
parent ee33795b72
commit b4975d3102
4 changed files with 151 additions and 4 deletions

View File

@ -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()?;

View File

@ -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(

View File

@ -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(

View File

@ -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