]> git.proxmox.com Git - pve-access-control.git/blobdiff - PVE/API2/AccessControl.pm
d/control: bump debhelper compat to >= 12
[pve-access-control.git] / PVE / API2 / AccessControl.pm
index 273178d98754ac206b89f42fbee079d49c124571..a77694b7561d64f080db9c4c26e22d6ffd7b0f1d 100644 (file)
@@ -32,36 +32,36 @@ eval {
 use base qw(PVE::RESTHandler);
 
 __PACKAGE__->register_method ({
-    subclass => "PVE::API2::User",  
+    subclass => "PVE::API2::User",
     path => 'users',
 });
 
 __PACKAGE__->register_method ({
-    subclass => "PVE::API2::Group",  
+    subclass => "PVE::API2::Group",
     path => 'groups',
 });
 
 __PACKAGE__->register_method ({
-    subclass => "PVE::API2::Role",  
+    subclass => "PVE::API2::Role",
     path => 'roles',
 });
 
 __PACKAGE__->register_method ({
-    subclass => "PVE::API2::ACL",  
+    subclass => "PVE::API2::ACL",
     path => 'acl',
 });
 
 __PACKAGE__->register_method ({
-    subclass => "PVE::API2::Domains",  
+    subclass => "PVE::API2::Domains",
     path => 'domains',
 });
 
 __PACKAGE__->register_method ({
-    name => 'index', 
-    path => '', 
+    name => 'index',
+    path => '',
     method => 'GET',
     description => "Directory index.",
-    permissions => { 
+    permissions => {
        user => 'all',
     },
     parameters => {
@@ -80,7 +80,7 @@ __PACKAGE__->register_method ({
     },
     code => sub {
        my ($param) = @_;
-    
+
        my $res = [];
 
        my $ma = __PACKAGE__->method_attributes();
@@ -176,11 +176,12 @@ my $compute_api_permission = sub {
        access => qr/(User|Group)\.|Permissions\.Modify/,
        storage => qr/Datastore\.|Permissions\.Modify/,
        nodes => qr/Sys\.|Permissions\.Modify/,
-       dc => qr/Sys\.Audit/,
+       sdn => qr/SDN\.|Permissions\.Modify/,
+       dc => qr/Sys\.Audit|SDN\./,
     };
     map { $res->{$_} = {} } keys %$priv_re_map;
 
-    my $required_paths = ['/', '/nodes', '/access/groups', '/vms', '/storage'];
+    my $required_paths = ['/', '/nodes', '/access/groups', '/vms', '/storage', '/sdn'];
 
     my $checked_paths = {};
     foreach my $path (@$required_paths, keys %{$usercfg->{acl}}) {
@@ -214,8 +215,8 @@ my $compute_api_permission = sub {
 };
 
 __PACKAGE__->register_method ({
-    name => 'get_ticket', 
-    path => 'ticket', 
+    name => 'get_ticket',
+    path => 'ticket',
     method => 'GET',
     permissions => { user => 'world' },
     description => "Dummy. Useful for formatters which want to provide a login page.",
@@ -224,16 +225,17 @@ __PACKAGE__->register_method ({
     },
     returns => { type => "null" },
     code => sub { return undef; }});
-  
+
 __PACKAGE__->register_method ({
-    name => 'create_ticket', 
-    path => 'ticket', 
+    name => 'create_ticket',
+    path => 'ticket',
     method => 'POST',
-    permissions => { 
+    permissions => {
        description => "You need to pass valid credientials.",
-       user => 'world' 
+       user => 'world'
     },
     protected => 1, # else we can't access shadow files
+    allowtoken => 0, # we don't want tokens to create tickets
     description => "Create or verify authentication ticket.",
     parameters => {
        additionalProperties => 0,
@@ -249,7 +251,7 @@ __PACKAGE__->register_method ({
                optional => 1,
                completion => \&PVE::AccessControl::complete_realm,
            }),
-           password => { 
+           password => {
                description => "The secret password. This can also be a valid ticket.",
                type => 'string',
            },
@@ -265,7 +267,7 @@ __PACKAGE__->register_method ({
                optional => 1,
                maxLength => 64,
            },
-           privs => { 
+           privs => {
                description => "Verify ticket, and check if user have access 'privs' on 'path'",
                type => 'string' , format => 'pve-priv-list',
                requires => 'path',
@@ -286,10 +288,11 @@ __PACKAGE__->register_method ({
     },
     code => sub {
        my ($param) = @_;
-    
+
        my $username = $param->{username};
        $username .= "\@$param->{realm}" if $param->{realm};
 
+       $username = PVE::AccessControl::lookup_username($username);
        my $rpcenv = PVE::RPCEnvironment::get();
 
        my $res;
@@ -326,11 +329,11 @@ __PACKAGE__->register_method ({
 
 __PACKAGE__->register_method ({
     name => 'change_password',
-    path => 'password', 
+    path => 'password',
     method => 'PUT',
-    permissions => { 
+    permissions => {
        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', 
+       check => [ 'or',
                   ['userid-param', 'self'],
                   [ 'and',
                     [ 'userid-param', 'Realm.AllocateUser'],
@@ -339,15 +342,16 @@ __PACKAGE__->register_method ({
            ],
     },
     protected => 1, # else we can't access shadow files
+    allowtoken => 0, # we don't want tokens to change the regular user password
     description => "Change user password.",
     parameters => {
        additionalProperties => 0,
        properties => {
            userid => get_standard_option('userid-completed'),
-           password => { 
+           password => {
                description => "The new password.",
                type => 'string',
-               minLength => 5, 
+               minLength => 5,
                maxLength => 64,
            },
        }
@@ -470,6 +474,7 @@ __PACKAGE__->register_method ({
            ],
     },
     protected => 1, # else we can't access shadow files
+    allowtoken => 0, # we don't want tokens to change the regular user's TFA settings
     description => "Change user u2f authentication.",
     parameters => {
        additionalProperties => 0,
@@ -594,6 +599,7 @@ __PACKAGE__->register_method({
     method => 'POST',
     permissions => { user => 'all' },
     protected => 1, # else we can't access shadow files
+    allowtoken => 0, # we don't want tokens to access TFA information
     description => 'Finish a u2f challenge.',
     parameters => {
        additionalProperties => 0,
@@ -657,4 +663,60 @@ __PACKAGE__->register_method({
        }
     }});
 
+__PACKAGE__->register_method({
+    name => 'permissions',
+    path => 'permissions',
+    method => 'GET',
+    description => 'Retrieve effective permissions of given user/token.',
+    permissions => {
+       description => "Each user/token is allowed to dump their own permissions. A user can dump the permissions of another user if they have 'Sys.Audit' permission on /access.",
+       user => 'all',
+    },
+    parameters => {
+       additionalProperties => 0,
+       properties => {
+           userid => {
+               type => 'string',
+               description => "User ID or full API token ID",
+               pattern => $PVE::AccessControl::userid_or_token_regex,
+               optional => 1,
+           },
+           path => get_standard_option('acl-path', {
+               description => "Only dump this specific path, not the whole tree.",
+               optional => 1,
+           }),
+       },
+    },
+    returns => {
+       type => 'object',
+       description => 'Map of "path" => (Map of "privilege" => "propagate boolean").',
+    },
+    code => sub {
+       my ($param) = @_;
+
+       my $rpcenv = PVE::RPCEnvironment::get();
+
+       my $userid = $param->{userid};
+       if (defined($userid)) {
+           $rpcenv->check($rpcenv->get_user(), '/access', ['Sys.Audit']);
+       } else {
+           $userid = $rpcenv->get_user();
+       }
+
+       my $res;
+
+       if (my $path = $param->{path}) {
+           my $perms = $rpcenv->permissions($userid, $path);
+           if ($perms) {
+               $res = { $path => $perms };
+           } else {
+               $res = {};
+           }
+       } else {
+           $res = $rpcenv->get_effective_permissions($userid);
+       }
+
+       return $res;
+    }});
+
 1;