api: check bridge access for create, update, clone & restore

Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
Reviewed-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
This commit is contained in:
Alexandre Derumier 2023-06-07 14:03:49 +02:00 committed by Thomas Lamprecht
parent 3dd16f4a6c
commit 9cfd06d944

View File

@ -23,7 +23,7 @@ use PVE::Storage;
use PVE::JSONSchema qw(get_standard_option); use PVE::JSONSchema qw(get_standard_option);
use PVE::RESTHandler; use PVE::RESTHandler;
use PVE::ReplicationConfig; use PVE::ReplicationConfig;
use PVE::GuestHelpers qw(assert_tag_permissions); use PVE::GuestHelpers qw(assert_tag_permissions check_vnet_access);
use PVE::QemuConfig; use PVE::QemuConfig;
use PVE::QemuServer; use PVE::QemuServer;
use PVE::QemuServer::Cloudinit; use PVE::QemuServer::Cloudinit;
@ -601,6 +601,22 @@ my $check_vm_create_usb_perm = sub {
return 1; return 1;
}; };
my $check_bridge_access = sub {
my ($rpcenv, $authuser, $param) = @_;
return 1 if $authuser eq 'root@pam';
foreach my $opt (keys %{$param}) {
next if $opt !~ m/^net\d+$/;
my $net = PVE::QemuServer::parse_net($param->{$opt});
my $bridge = $net->{bridge};
my $tag = $net->{tag};
my $trunks = $net->{trunks};
check_vnet_access($rpcenv, $authuser, $bridge, $tag, $trunks);
}
return 1;
};
my $check_vm_modify_config_perm = sub { my $check_vm_modify_config_perm = sub {
my ($rpcenv, $authuser, $vmid, $pool, $key_list) = @_; my ($rpcenv, $authuser, $vmid, $pool, $key_list) = @_;
@ -728,7 +744,8 @@ __PACKAGE__->register_method({
permissions => { permissions => {
description => "You need 'VM.Allocate' permissions on /vms/{vmid} or on the VM pool /pool/{pool}. " . description => "You need 'VM.Allocate' permissions on /vms/{vmid} or on the VM pool /pool/{pool}. " .
"For restore (option 'archive'), it is enough if the user has 'VM.Backup' permission and the VM already exists. " . "For restore (option 'archive'), it is enough if the user has 'VM.Backup' permission and the VM already exists. " .
"If you create disks you need 'Datastore.AllocateSpace' on any used storage.", "If you create disks you need 'Datastore.AllocateSpace' on any used storage." .
"If you use a bridge/vlan, you need 'SDN.Use' on any used bridge/vlan.",
user => 'all', # check inside user => 'all', # check inside
}, },
protected => 1, protected => 1,
@ -865,6 +882,10 @@ __PACKAGE__->register_method({
'backup', 'backup',
); );
my $vzdump_conf = PVE::Storage::extract_vzdump_config($storecfg, $archive);
my $backup_conf = PVE::QemuServer::parse_vm_config("restore/qemu-server/$vmid.conf", $vzdump_conf, 1);
&$check_bridge_access($rpcenv, $authuser, $backup_conf);
$archive = $parse_restore_archive->($storecfg, $archive); $archive = $parse_restore_archive->($storecfg, $archive);
} }
} }
@ -878,7 +899,7 @@ __PACKAGE__->register_method({
&$check_vm_create_serial_perm($rpcenv, $authuser, $vmid, $pool, $param); &$check_vm_create_serial_perm($rpcenv, $authuser, $vmid, $pool, $param);
&$check_vm_create_usb_perm($rpcenv, $authuser, $vmid, $pool, $param); &$check_vm_create_usb_perm($rpcenv, $authuser, $vmid, $pool, $param);
&$check_bridge_access($rpcenv, $authuser, $param);
&$check_cpu_model_access($rpcenv, $authuser, $param); &$check_cpu_model_access($rpcenv, $authuser, $param);
$check_drive_param->($param, $storecfg); $check_drive_param->($param, $storecfg);
@ -1598,6 +1619,8 @@ my $update_vm_api = sub {
&$check_storage_access($rpcenv, $authuser, $storecfg, $vmid, $param); &$check_storage_access($rpcenv, $authuser, $storecfg, $vmid, $param);
&$check_bridge_access($rpcenv, $authuser, $param);
my $updatefn = sub { my $updatefn = sub {
my $conf = PVE::QemuConfig->load_config($vmid); my $conf = PVE::QemuConfig->load_config($vmid);
@ -3375,7 +3398,7 @@ __PACKAGE__->register_method({
permissions => { permissions => {
description => "You need 'VM.Clone' permissions on /vms/{vmid}, and 'VM.Allocate' permissions " . description => "You need 'VM.Clone' permissions on /vms/{vmid}, and 'VM.Allocate' permissions " .
"on /vms/{newid} (or on the VM pool /pool/{pool}). You also need " . "on /vms/{newid} (or on the VM pool /pool/{pool}). You also need " .
"'Datastore.AllocateSpace' on any used storage.", "'Datastore.AllocateSpace' on any used storage and 'SDN.Use' on any used bridge/vnet",
check => check =>
[ 'and', [ 'and',
['perm', '/vms/{vmid}', [ 'VM.Clone' ]], ['perm', '/vms/{vmid}', [ 'VM.Clone' ]],
@ -3509,6 +3532,8 @@ __PACKAGE__->register_method({
my $sharedvm = &$check_storage_access_clone($rpcenv, $authuser, $storecfg, $oldconf, $storage); my $sharedvm = &$check_storage_access_clone($rpcenv, $authuser, $storecfg, $oldconf, $storage);
&$check_bridge_access($rpcenv, $authuser, $oldconf);
die "can't clone VM to node '$target' (VM uses local storage)\n" die "can't clone VM to node '$target' (VM uses local storage)\n"
if $target && !$sharedvm; if $target && !$sharedvm;