ui: tape/Restore: let the user choose an owner

so that the tape backup can be restored as any user, given
the current logged in user has the correct permission.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
This commit is contained in:
Dominik Csapak 2021-03-12 11:28:41 +01:00 committed by Dietmar Maurer
parent 5a5ee0326e
commit e36135031d
3 changed files with 38 additions and 1 deletions

View File

@ -40,6 +40,7 @@ use crate::{
cached_user_info::CachedUserInfo, cached_user_info::CachedUserInfo,
acl::{ acl::{
PRIV_DATASTORE_BACKUP, PRIV_DATASTORE_BACKUP,
PRIV_DATASTORE_MODIFY,
PRIV_TAPE_READ, PRIV_TAPE_READ,
}, },
}, },
@ -105,6 +106,10 @@ pub const ROUTER: Router = Router::new()
type: Userid, type: Userid,
optional: true, optional: true,
}, },
owner: {
type: Authid,
optional: true,
},
}, },
}, },
returns: { returns: {
@ -123,6 +128,7 @@ pub fn restore(
drive: String, drive: String,
media_set: String, media_set: String,
notify_user: Option<Userid>, notify_user: Option<Userid>,
owner: Option<Authid>,
rpcenv: &mut dyn RpcEnvironment, rpcenv: &mut dyn RpcEnvironment,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
@ -134,6 +140,18 @@ pub fn restore(
bail!("no permissions on /datastore/{}", store); bail!("no permissions on /datastore/{}", store);
} }
if let Some(ref owner) = owner {
let correct_owner = owner == &auth_id
|| (owner.is_token()
&& !auth_id.is_token()
&& owner.user() == auth_id.user());
// same permission as changing ownership after syncing
if !correct_owner && privs & PRIV_DATASTORE_MODIFY == 0 {
bail!("no permission to restore as '{}'", owner);
}
}
let privs = user_info.lookup_privs(&auth_id, &["tape", "drive", &drive]); let privs = user_info.lookup_privs(&auth_id, &["tape", "drive", &drive]);
if (privs & PRIV_TAPE_READ) == 0 { if (privs & PRIV_TAPE_READ) == 0 {
bail!("no permissions on /tape/drive/{}", drive); bail!("no permissions on /tape/drive/{}", drive);
@ -222,6 +240,7 @@ pub fn restore(
&datastore, &datastore,
&auth_id, &auth_id,
&notify_user, &notify_user,
&owner,
)?; )?;
} }
@ -252,6 +271,7 @@ pub fn request_and_restore_media(
datastore: &DataStore, datastore: &DataStore,
authid: &Authid, authid: &Authid,
notify_user: &Option<Userid>, notify_user: &Option<Userid>,
owner: &Option<Authid>,
) -> Result<(), Error> { ) -> Result<(), Error> {
let media_set_uuid = match media_id.media_set_label { let media_set_uuid = match media_id.media_set_label {
@ -284,7 +304,9 @@ pub fn request_and_restore_media(
} }
} }
restore_media(worker, &mut drive, &info, Some((datastore, authid)), false) let restore_owner = owner.as_ref().unwrap_or(authid);
restore_media(worker, &mut drive, &info, Some((datastore, restore_owner)), false)
} }
/// Restore complete media content and catalog /// Restore complete media content and catalog

View File

@ -27,6 +27,7 @@ use proxmox_backup::{
api2::{ api2::{
self, self,
types::{ types::{
Authid,
DATASTORE_SCHEMA, DATASTORE_SCHEMA,
DRIVE_NAME_SCHEMA, DRIVE_NAME_SCHEMA,
MEDIA_LABEL_SCHEMA, MEDIA_LABEL_SCHEMA,
@ -868,6 +869,10 @@ async fn backup(mut param: Value) -> Result<(), Error> {
type: Userid, type: Userid,
optional: true, optional: true,
}, },
owner: {
type: Authid,
optional: true,
},
"output-format": { "output-format": {
schema: OUTPUT_FORMAT, schema: OUTPUT_FORMAT,
optional: true, optional: true,

View File

@ -51,5 +51,15 @@ Ext.define('PBS.TapeManagement.TapeRestoreWindow', {
skipEmptyText: true, skipEmptyText: true,
renderer: Ext.String.htmlEncode, renderer: Ext.String.htmlEncode,
}, },
{
xtype: 'pbsUserSelector',
name: 'owner',
fieldLabel: gettext('Owner'),
emptyText: gettext('Current User'),
value: null,
allowBlank: true,
skipEmptyText: true,
renderer: Ext.String.htmlEncode,
},
], ],
}); });