]> git.proxmox.com Git - pve-access-control.git/blobdiff - PVE/RPCEnvironment.pm
new test option 'require_param' - code cleanup
[pve-access-control.git] / PVE / RPCEnvironment.pm
index 15f7badd5c831f97b6c3336d95916e8b7e03b2a6..06360f23ddc01fe01496a67e6eac0a52df06e671 100644 (file)
@@ -106,9 +106,9 @@ my $compile_acl_path = sub {
     if (!$data->{poolroles}) {
        $data->{poolroles} = {}; 
  
-       foreach my $poolpath (keys %{$cfg->{pools}}) {
-           my $d = $cfg->{pools}->{$poolpath};
-           my @ra = PVE::AccessControl::roles($cfg, $user, "/pool$poolpath"); # pool roles
+       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);
            foreach my $vmid (keys %{$d->{vms}}) {
                for my $role (@ra) {
@@ -129,8 +129,12 @@ my $compile_acl_path = sub {
     # Note: assume we do not want to propagate those privs
     if ($data->{poolroles}->{$path}) {
        if (!($ra[0] && $ra[0] eq 'NoAccess')) {
-           foreach my $role (keys %{$data->{poolroles}->{$path}}) {
-               push @ra, $role;
+           if ($data->{poolroles}->{$path}->{NoAccess}) {
+               @ra = ('NoAccess');
+           } else {
+               foreach my $role (keys %{$data->{poolroles}->{$path}}) {
+                   push @ra, $role;
+               }
            }
        }
     }
@@ -215,7 +219,7 @@ sub check_any {
     my ($self, $user, $path, $privs, $noerr) = @_;
 
     my $perm = $self->permissions($user, $path);
-    syslog("info", "check_any $user $path " . join(" ", keys %$perm));
+
     my $found = 0;
     foreach my $priv (@$privs) {
        PVE::AccessControl::verify_privname($priv);
@@ -232,6 +236,15 @@ sub check_any {
     raise_perm_exc("$path, " . join("|", @$privs)); 
 };
 
+sub check_full {
+    my ($self, $username, $path, $privs, $any, $noerr) = @_;
+    if ($any) {
+       return $self->check_any($username, $path, $privs, $noerr);
+    } else {
+       return $self->check($username, $path, $privs, $noerr);
+    }
+}
+
 sub check_user_enabled {
     my ($self, $user, $noerr) = @_;
     
@@ -264,14 +277,8 @@ sub filter_groups {
     my $groups = {};
     foreach my $group (keys %{$cfg->{groups}}) {
        my $path = "/access/groups/$group";
-       if ($any) {
-           if ($self->check_any($user, $path, $privs, 1)) {
-               $groups->{$group} = $cfg->{groups}->{$group};
-           }
-       } else {
-           if ($self->check($user, $path, $privs, 1)) {
-               $groups->{$group} = $cfg->{groups}->{$group};
-           }
+       if ($self->check_full($user, $path, $privs, $any, 1)) {
+           $groups->{$group} = $cfg->{groups}->{$group};
        }
     }
 
@@ -295,6 +302,23 @@ sub group_member_join {
     return $users;
 }
 
+sub check_perm_modify {
+    my ($self, $username, $path, $noerr) = @_;
+
+    return $self->check($username, '/access', [ 'Permissions.Modify' ], $noerr) if !$path;
+
+    my $testperms = [ 'Permissions.Modify' ];
+    if ($path =~ m|^/storage/.+$|) {
+       push @$testperms, 'Datastore.Allocate';
+    } elsif ($path =~ m|^/vms/.+$|) {
+       push @$testperms, 'VM.Allocate';
+    } elsif ($path =~ m|^/pool/.+$|) {
+       push @$testperms, 'Pool.Allocate';
+    }
+
+    return $self->check_any($username, $path, $testperms, $noerr);
+}
+
 sub exec_api2_perm_check {
     my ($self, $check, $username, $param, $noerr) = @_;
 
@@ -319,21 +343,23 @@ sub exec_api2_perm_check {
        my ($t, $tmplpath, $privs, %options) = @$check;
        my $any = $options{any};
        die "missing parameters" if !($tmplpath && $privs);
-       my $path = PVE::Tools::template_replace($tmplpath, $param);
-       if ($any) {
-           return $self->check_any($username, $path, $privs, $noerr);
-       } else {
-           return $self->check($username, $path, $privs, $noerr);
+       my $require_param = $options{require_param};
+       if ($require_param && !defined($param->{$require_param})) {
+           return 0 if $noerr;
+           raise_perm_exc();
        }
+       my $path = PVE::Tools::template_replace($tmplpath, $param);
+       $path = PVE::AccessControl::normalize_path($path);
+       return $self->check_full($username, $path, $privs, $any, $noerr);
     } elsif ($test eq 'userid-group') {
        my $userid = $param->{userid};
        my ($t, $privs, %options) = @$check;
-       return if !$options{groups_param} && !$self->check_user_exist($userid, $noerr);
-       if (!$self->check_any($username, "/access", $privs, 1)) {
+       return if !$options{groups_param} && !$self->check_user_exist($userid, $noerr);
+       if (!$self->check_any($username, "/access/groups", $privs, 1)) {
            my $groups = $self->filter_groups($username, $privs, 1);
            if ($options{groups_param}) {
                my @group_param = PVE::Tools::split_list($param->{groups});
-               raise_perm_exc("/access, " . join("|", @$privs)) if !scalar(@group_param);
+               raise_perm_exc("/access/groups, " . join("|", @$privs)) if !scalar(@group_param);
                foreach my $pg (@group_param) {
                    raise_perm_exc("/access/groups/$pg, " . join("|", @$privs))
                        if !$groups->{$pg};
@@ -348,7 +374,7 @@ sub exec_api2_perm_check {
        }
        return 1;
     } elsif ($test eq 'userid-param') {
-       my $userid = $param->{userid};
+       my ($userid, undef, $realm) = verify_username($param->{userid});
        return if !$self->check_user_exist($userid, $noerr);
        my ($t, $subtest) = @$check;
        die "missing parameters" if !$subtest;
@@ -356,10 +382,18 @@ sub exec_api2_perm_check {
            return 1 if $username eq 'userid';
            return 0 if $noerr;
            raise_perm_exc();
+       } elsif ($subtest eq 'Realm.AllocateUser') {
+           my $path =  "/access/realm/$realm";
+           return $self->check($username, $path, ['Realm.AllocateUser'], $noerr);
        } else {
            die "unknown userid-param test";
        }
-    } else {
+     } elsif ($test eq 'perm-modify') {
+       my ($t, $tmplpath) = @$check;
+       my $path = PVE::Tools::template_replace($tmplpath, $param);
+       $path = PVE::AccessControl::normalize_path($path);
+       return $self->check_perm_modify($username, $path, $noerr);
+   } else {
        die "unknown permission test";
     }
 };