X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=PVE%2FRPCEnvironment.pm;h=e66107be7c1567cdc045c303ae0fd89980144a87;hb=f28a69a01832de54b2022577d6cf365bf9324dbd;hp=7e0af7047a6aeb5e7519367538fde44bc0159692;hpb=a31f1d85f9dec83a1fda7e6f6727a1db45fc68c5;p=pve-access-control.git diff --git a/PVE/RPCEnvironment.pm b/PVE/RPCEnvironment.pm index 7e0af70..e66107b 100644 --- a/PVE/RPCEnvironment.pm +++ b/PVE/RPCEnvironment.pm @@ -30,52 +30,62 @@ my $compile_acl_path = sub { $cache->{$user} = {} if !$cache->{$user}; my $data = $cache->{$user}; + my ($username, undef) = PVE::AccessControl::split_tokenid($user, 1); + die "internal error" if $username && $username ne 'root@pam' && !defined($cache->{$username}); + if (!$data->{poolroles}) { $data->{poolroles} = {}; foreach my $pool (keys %{$cfg->{pools}}) { my $d = $cfg->{pools}->{$pool}; - my @ra = PVE::AccessControl::roles($cfg, $user, "/pool/$pool"); # pool roles - next if !scalar(@ra); + my $pool_roles = PVE::AccessControl::roles($cfg, $user, "/pool/$pool"); # pool roles + next if !scalar(keys %$pool_roles); foreach my $vmid (keys %{$d->{vms}}) { - for my $role (@ra) { + for my $role (keys %$pool_roles) { $data->{poolroles}->{"/vms/$vmid"}->{$role} = 1; } } foreach my $storeid (keys %{$d->{storage}}) { - for my $role (@ra) { + for my $role (keys %$pool_roles) { $data->{poolroles}->{"/storage/$storeid"}->{$role} = 1; } } } } - my @ra = PVE::AccessControl::roles($cfg, $user, $path); + my $roles = PVE::AccessControl::roles($cfg, $user, $path); # apply roles inherited from pools # Note: assume we do not want to propagate those privs if ($data->{poolroles}->{$path}) { - if (!($ra[0] && $ra[0] eq 'NoAccess')) { + if (!defined($roles->{NoAccess})) { if ($data->{poolroles}->{$path}->{NoAccess}) { - @ra = ('NoAccess'); + $roles = { 'NoAccess' => 0 }; } else { foreach my $role (keys %{$data->{poolroles}->{$path}}) { - push @ra, $role; + $roles->{$role} = 0 if !defined($roles->{$role}); } } } } - $data->{roles}->{$path} = [ @ra ]; + $data->{roles}->{$path} = $roles; my $privs = {}; - foreach my $role (@ra) { + foreach my $role (keys %$roles) { if (my $privset = $cfg->{roles}->{$role}) { foreach my $p (keys %$privset) { - $privs->{$p} = 1; + $privs->{$p} = $roles->{$role}; } } } + + 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 }; + } + $data->{privs}->{$path} = $privs; return $privs; @@ -86,11 +96,25 @@ sub permissions { if ($user eq 'root@pam') { # root can do anything my $cfg = $self->{user_cfg}; - return $cfg->{roles}->{'Administrator'}; + return { map { $_ => 1 } keys %{$cfg->{roles}->{'Administrator'}} }; } - $user = PVE::AccessControl::verify_username($user, 1); - return {} if !$user; + if (PVE::AccessControl::pve_verify_tokenid($user, 1)) { + my ($username, $token) = PVE::AccessControl::split_tokenid($user); + my $cfg = $self->{user_cfg}; + my $token_info = $cfg->{users}->{$username}->{tokens}->{$token}; + + return {} if !$token_info; + + # ensure cache for user is populated + my $user_perms = $self->permissions($username, $path); + + # return user privs for non-privsep tokens + return $user_perms if !$token_info->{privsep}; + } else { + $user = PVE::AccessControl::verify_username($user, 1); + return {} if !$user; + } my $cache = $self->{aclcache}; $cache->{$user} = {} if !$cache->{$user}; @@ -103,6 +127,47 @@ sub permissions { return &$compile_acl_path($self, $user, $path); } +sub get_effective_permissions { + my ($self, $user) = @_; + + # default / top level paths + my $paths = { + '/' => 1, + '/access' => 1, + '/access/groups' => 1, + '/nodes' => 1, + '/pools' => 1, + '/storage' => 1, + '/vms' => 1, + }; + + my $cfg = $self->{user_cfg}; + + # paths explicitly listed in ACLs + foreach my $acl_path (keys %{$cfg->{acl}}) { + $paths->{$acl_path} = 1; + } + + # paths referenced by pool definitions + foreach my $pool (keys %{$cfg->{pools}}) { + my $d = $cfg->{pools}->{$pool}; + foreach my $vmid (keys %{$d->{vms}}) { + $paths->{"/vms/$vmid"} = 1; + } + foreach my $storeid (keys %{$d->{storage}}) { + $paths->{"/storage/$storeid"} = 1; + } + } + + my $perms = {}; + foreach my $path (keys %$paths) { + my $path_perms = $self->permissions($user, $path); + # filter paths where user has NO permissions + $perms->{$path} = $path_perms if %$path_perms; + } + return $perms; +} + sub check { my ($self, $user, $path, $privs, $noerr) = @_; @@ -110,7 +175,7 @@ sub check { foreach my $priv (@$privs) { PVE::AccessControl::verify_privname($priv); - if (!$perm->{$priv}) { + if (!defined($perm->{$priv})) { return undef if $noerr; raise_perm_exc("$path, $priv"); } @@ -127,7 +192,7 @@ sub check_any { my $found = 0; foreach my $priv (@$privs) { PVE::AccessControl::verify_privname($priv); - if ($perm->{$priv}) { + if (defined($perm->{$priv})) { $found = 1; last; }