print "recovering backed-up configuration from '$archive'\n";
($orig_conf, $orig_mp_param) = PVE::LXC::Create::recover_config($storage_cfg, $archive, $vmid);
+ for my $opt (keys %$orig_conf) {
+ # early check before disks are created
+ # the "real" check is in later on when actually merging the configs
+ if ($opt =~ /^net\d+$/ && !defined($param->{$opt})) {
+ PVE::LXC::check_bridge_access($rpcenv, $authuser, $orig_conf->{$opt});
+ }
+ }
+
$was_template = delete $orig_conf->{template};
# When we're root call 'restore_configuration' with restricted=0,
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 " .
- "'Datastore.AllocateSpace' on any used storage.",
+ "'Datastore.AllocateSpace' on any used storage, and 'SDN.Use' on any bridge.",
check =>
[ 'and',
['perm', '/vms/{vmid}', [ 'VM.Clone' ]],
my $net = PVE::LXC::Config->parse_lxc_network($value);
$net->{hwaddr} = PVE::Tools::random_ether_addr($dc->{mac_prefix});
$newconf->{$opt} = PVE::LXC::Config->print_lxc_network($net);
+
+ PVE::LXC::check_bridge_access($rpcenv, $authuser, $newconf->{$opt});
} else {
# copy everything else
$newconf->{$opt} = $value;
use PVE::CGroup;
use PVE::CpuSet;
use PVE::Exception qw(raise_perm_exc);
-use PVE::GuestHelpers qw(safe_string_ne safe_num_ne safe_boolean_ne);
+use PVE::GuestHelpers qw(check_vnet_access safe_string_ne safe_num_ne safe_boolean_ne);
use PVE::INotify;
use PVE::JSONSchema qw(get_standard_option);
use PVE::Network;
} elsif ($opt =~ m/^net\d+$/ || $opt eq 'nameserver' ||
$opt eq 'searchdomain' || $opt eq 'hostname') {
$rpcenv->check_vm_perm($authuser, $vmid, $pool, ['VM.Config.Network']);
+ PVE::LXC::check_bridge_access($rpcenv, $authuser, $newconf->{$opt});
} elsif ($opt eq 'features') {
raise_perm_exc("changing feature flags for privileged container is only allowed for root\@pam")
if !$unprivileged;
return 1;
}
+sub check_bridge_access {
+ my ($rpcenv, $authuser, $raw) = @_;
+
+ return 1 if $authuser eq 'root@pam';
+
+ my $net = PVE::LXC::Config->parse_lxc_network($raw);
+ my $bridge = $net->{bridge};
+ my $tag = $net->{tag};
+ my $trunks = $net->{trunks};
+ check_vnet_access($rpcenv, $authuser, $bridge, $tag, $trunks);
+
+ return 1;
+};
+
sub umount_all {
my ($vmid, $storage_cfg, $conf, $noerr) = @_;
my ($conf, $oldconf, $restricted, $unique) = @_;
my $rpcenv = PVE::RPCEnvironment::get();
+ my $authuser = $rpcenv->get_user();
foreach my $key (keys %$oldconf) {
next if $key eq 'digest' || $key eq 'rootfs' || $key eq 'snapshots' || $key eq 'unprivileged' || $key eq 'parent';
next;
}
+ if ($key =~ /^net\d+$/ && !defined($conf->{$key})) {
+ PVE::LXC::check_bridge_access($rpcenv, $authuser, $oldconf->{$key});
+ }
+
if ($unique && $key =~ /^net\d+$/) {
my $net = PVE::LXC::Config->parse_lxc_network($oldconf->{$key});
my $dc = PVE::Cluster::cfs_read_file('datacenter.cfg');