X-Git-Url: https://git.proxmox.com/?p=pve-access-control.git;a=blobdiff_plain;f=src%2FPVE%2FRPCEnvironment.pm;h=b1348fab8f38141606cbce5a61d2d6a4ded3253d;hp=e66107be7c1567cdc045c303ae0fd89980144a87;hb=9aa49a8de1a5b014609e9bf72399ed8b9e9c4e39;hpb=197d1016fd2f75aa4654d2fd77b4142fc450e2ba diff --git a/src/PVE/RPCEnvironment.pm b/src/PVE/RPCEnvironment.pm index e66107b..b1348fa 100644 --- a/src/PVE/RPCEnvironment.pm +++ b/src/PVE/RPCEnvironment.pm @@ -3,15 +3,14 @@ package PVE::RPCEnvironment; use strict; use warnings; -use PVE::RESTEnvironment; - +use PVE::AccessControl; +use PVE::Cluster; use PVE::Exception qw(raise raise_perm_exc); -use PVE::SafeSyslog; -use PVE::Tools; use PVE::INotify; -use PVE::Cluster; use PVE::ProcFSTools; -use PVE::AccessControl; +use PVE::RESTEnvironment; +use PVE::SafeSyslog; +use PVE::Tools; use base qw(PVE::RESTEnvironment); @@ -83,7 +82,13 @@ my $compile_acl_path = sub { if ($username && $username ne 'root@pam') { # intersect user and token permissions my $user_privs = $cache->{$username}->{privs}->{$path}; - $privs = { map { $_ => $user_privs->{$_} && $privs->{$_} } keys %$privs }; + my $filtered_privs = [ grep { $user_privs->{$_} } keys %$privs ]; + $privs = { map { $_ => $user_privs->{$_} && $privs->{$_} } @$filtered_privs }; + } + + foreach my $priv (keys %$privs) { + # safeguard, this should never happen anyway + delete $privs->{$priv} if !defined($privs->{$priv}); } $data->{privs}->{$path} = $privs; @@ -127,6 +132,59 @@ sub permissions { return &$compile_acl_path($self, $user, $path); } +sub compute_api_permission { + my ($self, $authuser) = @_; + + my $usercfg = $self->{user_cfg}; + + my $res = {}; + my $priv_re_map = { + vms => qr/VM\.|Permissions\.Modify/, + access => qr/(User|Group)\.|Permissions\.Modify/, + storage => qr/Datastore\.|Permissions\.Modify/, + nodes => qr/Sys\.|Permissions\.Modify/, + sdn => qr/SDN\.|Permissions\.Modify/, + dc => qr/Sys\.Audit|SDN\./, + }; + map { $res->{$_} = {} } keys %$priv_re_map; + + my $required_paths = ['/', '/nodes', '/access/groups', '/vms', '/storage', '/sdn']; + + my $checked_paths = {}; + foreach my $path (@$required_paths, keys %{$usercfg->{acl}}) { + next if $checked_paths->{$path}; + $checked_paths->{$path} = 1; + + my $path_perm = $self->permissions($authuser, $path); + + my $toplevel = ($path =~ /^\/(\w+)/) ? $1 : 'dc'; + if ($toplevel eq 'pool') { + foreach my $priv (keys %$path_perm) { + next if !defined($path_perm->{$priv}); + + if ($priv =~ m/^VM\./) { + $res->{vms}->{$priv} = 1; + } elsif ($priv =~ m/^Datastore\./) { + $res->{storage}->{$priv} = 1; + } elsif ($priv eq 'Permissions.Modify') { + $res->{storage}->{$priv} = 1; + $res->{vms}->{$priv} = 1; + } + } + } else { + my $priv_regex = $priv_re_map->{$toplevel} // next; + foreach my $priv (keys %$path_perm) { + next if !defined($path_perm->{$priv}); + + next if $priv !~ m/^($priv_regex)/; + $res->{$toplevel}->{$priv} = 1; + } + } + } + + return $res; +} + sub get_effective_permissions { my ($self, $user) = @_; @@ -137,6 +195,7 @@ sub get_effective_permissions { '/access/groups' => 1, '/nodes' => 1, '/pools' => 1, + '/sdn' => 1, '/storage' => 1, '/vms' => 1, }; @@ -162,6 +221,9 @@ sub get_effective_permissions { my $perms = {}; foreach my $path (keys %$paths) { my $path_perms = $self->permissions($user, $path); + foreach my $priv (keys %$path_perms) { + delete $path_perms->{$priv} if !defined($path_perms->{$priv}); + } # filter paths where user has NO permissions $perms->{$path} = $path_perms if %$path_perms; }