From: Fabian Grünbichler Date: Tue, 21 Jan 2020 12:54:11 +0000 (+0100) Subject: roles()/permissions(): also return propagate flag X-Git-Url: https://git.proxmox.com/?p=pve-access-control.git;a=commitdiff_plain;h=7e8bcaa754432f084e53d9daf13c653a8777d88b roles()/permissions(): also return propagate flag this information is already available, but not exposed. we need it for dumping an effective permission tree of a given user/token. Signed-off-by: Fabian Grünbichler --- diff --git a/PVE/AccessControl.pm b/PVE/AccessControl.pm index 71ccf6b..a3990de 100644 --- a/PVE/AccessControl.pm +++ b/PVE/AccessControl.pm @@ -1365,13 +1365,13 @@ sub roles { my $token_info = $cfg->{users}->{$username}->{tokens}->{$token}; return () if !$token_info; - my @user_roles = roles($cfg, $username, $path); + my $user_roles = roles($cfg, $username, $path); # return full user privileges - return @user_roles if !$token_info->{privsep}; + return $user_roles if !$token_info->{privsep}; } - my $perm = {}; + my $roles = {}; foreach my $p (sort keys %{$cfg->{acl}}) { my $final = ($path eq $p); @@ -1389,11 +1389,11 @@ sub roles { if ($final || $propagate) { #print "APPLY ROLE $p $user $role\n"; $new = {} if !$new; - $new->{$role} = 1; + $new->{$role} = $propagate; } } if ($new) { - $perm = $new; # overwrite previous settings + $roles = $new; # overwrite previous settings next; } } @@ -1405,11 +1405,11 @@ sub roles { if ($final || $propagate) { #print "APPLY ROLE $p $user $role\n"; $new = {} if !$new; - $new->{$role} = 1; + $new->{$role} = $propagate; } } if ($new) { - $perm = $new; # overwrite previous settings + $roles = $new; # overwrite previous settings next; # user privs always override group privs } } @@ -1423,27 +1423,25 @@ sub roles { if ($final || $propagate) { #print "APPLY ROLE $p \@$g $role\n"; $new = {} if !$new; - $new->{$role} = 1; + $new->{$role} = $propagate; } } } } if ($new) { - $perm = $new; # overwrite previous settings + $roles = $new; # overwrite previous settings next; } } - return ('NoAccess') if defined ($perm->{NoAccess}); - #return () if defined ($perm->{NoAccess}); + return { 'NoAccess' => $roles->{NoAccess} } if defined ($roles->{NoAccess}); + #return () if defined ($roles->{NoAccess}); - #print "permission $user $path = " . Dumper ($perm); - - my @ra = keys %$perm; + #print "permission $user $path = " . Dumper ($roles); #print "roles $user $path = " . join (',', @ra) . "\n"; - return @ra; + return $roles; } sub remove_vm_access { diff --git a/PVE/RPCEnvironment.pm b/PVE/RPCEnvironment.pm index e37c648..8384376 100644 --- a/PVE/RPCEnvironment.pm +++ b/PVE/RPCEnvironment.pm @@ -38,44 +38,44 @@ my $compile_acl_path = sub { 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}; } } } @@ -83,7 +83,7 @@ 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 { $_ => 1 } grep { $user_privs->{$_} } keys %$privs }; + $privs = { map { $_ => $user_privs->{$_} && $privs->{$_} } keys %$privs }; } $data->{privs}->{$path} = $privs; @@ -96,13 +96,14 @@ 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'}} }; } 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 @@ -133,7 +134,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"); } @@ -150,7 +151,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; } diff --git a/test/perm-test1.pl b/test/perm-test1.pl index 3efc79f..e1bf1c7 100755 --- a/test/perm-test1.pl +++ b/test/perm-test1.pl @@ -14,8 +14,8 @@ $rpcenv->init_request(userconfig => $cfgfn); sub check_roles { my ($user, $path, $expected_result) = @_; - my @ra = PVE::AccessControl::roles($rpcenv->{user_cfg}, $user, $path); - my $res = join(',', sort @ra); + my $roles = PVE::AccessControl::roles($rpcenv->{user_cfg}, $user, $path); + my $res = join(',', sort keys %$roles); die "unexpected result\nneed '${expected_result}'\ngot '$res'\n" if $res ne $expected_result; @@ -38,7 +38,6 @@ sub check_permission { if $res ne $expected_result; print "PERM:$path:$user:$res\n"; - } check_roles('max@pve', '/', ''); diff --git a/test/perm-test2.pl b/test/perm-test2.pl index 745aa09..1317051 100755 --- a/test/perm-test2.pl +++ b/test/perm-test2.pl @@ -14,8 +14,8 @@ $rpcenv->init_request(userconfig => $cfgfn); sub check_roles { my ($user, $path, $expected_result) = @_; - my @ra = PVE::AccessControl::roles($rpcenv->{user_cfg}, $user, $path); - my $res = join(',', sort @ra); + my $roles = PVE::AccessControl::roles($rpcenv->{user_cfg}, $user, $path); + my $res = join(',', sort keys %$roles); die "unexpected result\nneed '${expected_result}'\ngot '$res'\n" if $res ne $expected_result; diff --git a/test/perm-test3.pl b/test/perm-test3.pl index 3426b87..b7b5480 100755 --- a/test/perm-test3.pl +++ b/test/perm-test3.pl @@ -14,8 +14,8 @@ $rpcenv->init_request(userconfig => $cfgfn); sub check_roles { my ($user, $path, $expected_result) = @_; - my @ra = PVE::AccessControl::roles($rpcenv->{user_cfg}, $user, $path); - my $res = join(',', sort @ra); + my $roles = PVE::AccessControl::roles($rpcenv->{user_cfg}, $user, $path); + my $res = join(',', sort keys %$roles); die "unexpected result\nneed '${expected_result}'\ngot '$res'\n" if $res ne $expected_result; diff --git a/test/perm-test4.pl b/test/perm-test4.pl index c71322f..718963e 100755 --- a/test/perm-test4.pl +++ b/test/perm-test4.pl @@ -14,8 +14,8 @@ $rpcenv->init_request(userconfig => $cfgfn); sub check_roles { my ($user, $path, $expected_result) = @_; - my @ra = PVE::AccessControl::roles($rpcenv->{user_cfg}, $user, $path); - my $res = join(',', sort @ra); + my $roles = PVE::AccessControl::roles($rpcenv->{user_cfg}, $user, $path); + my $res = join(',', sort keys %$roles); die "unexpected result\nneed '${expected_result}'\ngot '$res'\n" if $res ne $expected_result; diff --git a/test/perm-test5.pl b/test/perm-test5.pl index 1da9896..ebb40e3 100755 --- a/test/perm-test5.pl +++ b/test/perm-test5.pl @@ -14,8 +14,8 @@ $rpcenv->init_request(userconfig => $cfgfn); sub check_roles { my ($user, $path, $expected_result) = @_; - my @ra = PVE::AccessControl::roles($rpcenv->{user_cfg}, $user, $path); - my $res = join(',', sort @ra); + my $roles = PVE::AccessControl::roles($rpcenv->{user_cfg}, $user, $path); + my $res = join(',', sort keys %$roles); die "unexpected result\nneed '${expected_result}'\ngot '$res'\n" if $res ne $expected_result; diff --git a/test/perm-test6.pl b/test/perm-test6.pl index 71e2a70..87d9bf7 100755 --- a/test/perm-test6.pl +++ b/test/perm-test6.pl @@ -14,8 +14,8 @@ $rpcenv->init_request(userconfig => $cfgfn); sub check_roles { my ($user, $path, $expected_result) = @_; - my @ra = PVE::AccessControl::roles($rpcenv->{user_cfg}, $user, $path); - my $res = join(',', sort @ra); + my $roles = PVE::AccessControl::roles($rpcenv->{user_cfg}, $user, $path); + my $res = join(',', sort keys %$roles); die "unexpected result\nneed '${expected_result}'\ngot '$res'\n" if $res ne $expected_result; diff --git a/test/perm-test7.pl b/test/perm-test7.pl index 2add067..57ece07 100755 --- a/test/perm-test7.pl +++ b/test/perm-test7.pl @@ -14,8 +14,8 @@ $rpcenv->init_request(userconfig => $cfgfn); sub check_roles { my ($user, $path, $expected_result) = @_; - my @ra = PVE::AccessControl::roles($rpcenv->{user_cfg}, $user, $path); - my $res = join(',', sort @ra); + my $roles = PVE::AccessControl::roles($rpcenv->{user_cfg}, $user, $path); + my $res = join(',', sort keys %$roles); die "unexpected result\nneed '${expected_result}'\ngot '$res'\n" if $res ne $expected_result;