]> git.proxmox.com Git - pve-access-control.git/blobdiff - PVE/API2/AccessControl.pm
correctly compute GUI capabilities (consider pools)
[pve-access-control.git] / PVE / API2 / AccessControl.pm
index 913bdd81a8fea82fd6ed71735ba696be80734b08..1679ed45eb4c0d6ff81682eb967fbce3c5521cfd 100644 (file)
@@ -15,7 +15,6 @@ use PVE::API2::User;
 use PVE::API2::Group;
 use PVE::API2::Role;
 use PVE::API2::ACL;
-use PVE::API2::Pool;
 
 use base qw(PVE::RESTHandler);
 
@@ -44,16 +43,14 @@ __PACKAGE__->register_method ({
     path => 'domains',
 });
 
-__PACKAGE__->register_method ({
-    subclass => "PVE::API2::Pool",  
-    path => 'pools',
-});
-
 __PACKAGE__->register_method ({
     name => 'index', 
     path => '', 
     method => 'GET',
     description => "Directory index.",
+    permissions => { 
+       user => 'all',
+    },
     parameters => {
        additionalProperties => 0,
        properties => {},
@@ -134,6 +131,81 @@ my $create_ticket = sub {
     };
 };
 
+my $compute_api_permission = sub {
+    my ($rpcenv, $authuser) = @_;
+
+    my $usercfg = $rpcenv->{user_cfg};
+
+    my $nodelist = PVE::Cluster::get_nodelist();
+    my $vmlist = PVE::Cluster::get_vmlist() || {};
+    my $idlist = $vmlist->{ids} || {};
+
+    my $cfg = PVE::Storage::config();
+    my @sids =  PVE::Storage::storage_ids ($cfg);
+
+    my $res = {
+       vms => {},
+       storage => {},
+       access => {},
+       nodes => {},
+       dc => {},
+    };
+
+    my $extract_vm_caps = sub {
+       my ($path) = @_;
+       
+       my $perm = $rpcenv->permissions($authuser, $path);
+       foreach my $priv (keys %$perm) {
+           next if !($priv eq 'Permissions.Modify' || $priv =~ m/^VM\./);
+           $res->{vms}->{$priv} = 1;   
+       }
+    };
+
+    foreach my $pool (keys %{$usercfg->{pools}}) {
+       &$extract_vm_caps("/pool/$pool");
+    }
+
+    foreach my $vmid (keys %$idlist, '__phantom__') {
+       &$extract_vm_caps("/vms/$vmid");
+    }
+
+    foreach my $storeid (@sids, '__phantom__') {
+       my $perm = $rpcenv->permissions($authuser, "/storage/$storeid");
+       foreach my $priv (keys %$perm) {
+           next if !($priv eq 'Permissions.Modify' || $priv =~ m/^Datastore\./);
+           $res->{storage}->{$priv} = 1;
+       }
+    }
+
+    foreach my $path (('/access/groups')) {
+       my $perm = $rpcenv->permissions($authuser, $path);
+       foreach my $priv (keys %$perm) {
+           next if $priv !~ m/^(User|Group)\./;
+           $res->{access}->{$priv} = 1;
+       }
+    }
+
+    foreach my $group (keys %{$usercfg->{users}->{$authuser}->{groups}}, '__phantom__') {
+       my $perm = $rpcenv->permissions($authuser, "/access/groups/$group");
+       if ($perm->{'User.Modify'}) {
+           $res->{access}->{'User.Modify'} = 1;
+       }
+    }
+
+    foreach my $node (@$nodelist) {
+       my $perm = $rpcenv->permissions($authuser, "/nodes/$node");
+       foreach my $priv (keys %$perm) {
+           next if $priv !~ m/^Sys\./;
+           $res->{nodes}->{$priv} = 1;
+       }
+    }
+
+    my $perm = $rpcenv->permissions($authuser, "/");
+    $res->{dc}->{'Sys.Audit'} = 1 if $perm->{'Sys.Audit'};
+
+    return $res;
+};
+
 __PACKAGE__->register_method ({
     name => 'create_ticket', 
     path => 'ticket', 
@@ -210,6 +282,8 @@ __PACKAGE__->register_method ({
            die $err;
        }
 
+       $res->{cap} = &$compute_api_permission($rpcenv, $username);
+
        PVE::Cluster::log_msg('info', 'root@pam', "successful auth for user '$username'");
 
        return $res;
@@ -220,10 +294,13 @@ __PACKAGE__->register_method ({
     path => 'password', 
     method => 'PUT',
     permissions => { 
-       description => "Each user is allowed to change his own password. A user can change the password of another user if he has modify permission on /access/groups/<group> on a group where user <userid> is member of.",
+       description => "Each user is allowed to change his own password. A user can change the password of another user if he has 'Realm.AllocateUser' (on the realm of user <userid>) and 'User.Modify' permission on /access/groups/<group> on a group where user <userid> is member of.",
        check => [ 'or', 
                   ['userid-param', 'self'],
-                  ['userid-group', ['User.Modify']],
+                  [ 'and',
+                    [ 'userid-param', 'Realm.AllocateUser'],
+                    [ 'userid-group', ['User.Modify']]
+                  ]
            ],
     },
     protected => 1, # else we can't access shadow files
@@ -260,6 +337,8 @@ __PACKAGE__->register_method ({
            } else {
                # only root may change root password
                raise_perm_exc() if $userid eq 'root@pam';
+               # do not allow to change system user passwords
+               raise_perm_exc() if $realm eq 'pam';
            }
        }