add description
[pve-access-control.git] / PVE / API2 / ACL.pm
1 package PVE::API2::ACL;
2
3 use strict;
4 use warnings;
5 use PVE::Cluster qw (cfs_read_file cfs_write_file);
6 use PVE::Tools qw(split_list);
7 use PVE::AccessControl;
8 use PVE::Exception qw(raise_param_exc);
9
10 use PVE::SafeSyslog;
11
12 use Data::Dumper; # fixme: remove
13
14 use PVE::RESTHandler;
15
16 use base qw(PVE::RESTHandler);
17
18 __PACKAGE__->register_method ({
19     name => 'read_acl', 
20     path => '', 
21     method => 'GET',
22     description => "Get Access Control List (ACLs).",
23     permissions => { 
24         description => "The returned list is restricted to objects where you have rights to modify permissions.",
25         user => 'all',
26     },
27     parameters => {
28         additionalProperties => 0,
29         properties => {},
30     },
31     returns => {
32         type => 'array',
33         items => {
34             type => "object",
35             additionalProperties => 0,
36             properties => {
37                 path => { type => 'string' },
38                 type => { type => 'string', enum => ['user', 'group'] },
39                 ugid => { type => 'string' },
40                 roleid => { type => 'string' },
41                 propagate => { type => 'boolean' },
42             },
43         },
44     },
45     code => sub {
46         my ($param) = @_;
47     
48         my $rpcenv = PVE::RPCEnvironment::get();
49         my $authuser = $rpcenv->get_user();
50         my $res = [];
51
52         my $usercfg = $rpcenv->{user_cfg};
53         if (!$usercfg || !$usercfg->{acl}) {
54             return {};
55         }
56
57         my $audit = $rpcenv->check($authuser, '/access', ['Sys.Audit'], 1);
58
59         my $acl = $usercfg->{acl};
60         foreach my $path (keys %$acl) {
61             foreach my $type (qw(users groups)) {
62                 my $d = $acl->{$path}->{$type};
63                 next if !$d;
64                 next if !($audit || $rpcenv->check_perm_modify($authuser, $path, 1));
65                 foreach my $id (keys %$d) {
66                     foreach my $role (keys %{$d->{$id}}) {
67                         my $propagate = $d->{$id}->{$role};
68                         push @$res, {
69                             path => $path,
70                             type => $type eq 'groups' ? 'group' : 'user',
71                             ugid => $id,
72                             roleid => $role,
73                             propagate => $propagate,
74                         };
75                     }
76                 }
77             }
78         }
79
80         return $res;
81     }});
82
83 __PACKAGE__->register_method ({
84     name => 'update_acl', 
85     protected => 1,
86     path => '', 
87     method => 'PUT',
88     permissions => { 
89         check => ['perm-modify', '{path}'],
90     },
91     description => "Update Access Control List (add or remove permissions).",
92     parameters => {
93         additionalProperties => 0,
94         properties => {
95             path => {
96                 description => "Access control path",
97                 type => 'string',
98             },
99             users => { 
100                 description => "List of users.",
101                 type => 'string',  format => 'pve-userid-list',  
102                 optional => 1,
103             },
104             groups => { 
105                 description => "List of groups.",
106                 type => 'string', format => 'pve-groupid-list',
107                 optional => 1,  
108             },
109             roles => { 
110                 description => "List of roles.",
111                 type => 'string', format => 'pve-roleid-list',
112             },
113             propagate => { 
114                 description => "Allow to propagate (inherit) permissions.",
115                 type => 'boolean', 
116                 optional => 1,
117             },
118             delete => {
119                 description => "Remove permissions (instead of adding it).",
120                 type => 'boolean', 
121                 optional => 1,
122             },
123         },
124     },
125     returns => { type => 'null' },
126     code => sub {
127         my ($param) = @_;
128
129         if (!($param->{users} || $param->{groups})) {
130             raise_param_exc({ 
131                 users => "either 'users' or 'groups' is required.", 
132                 groups => "either 'users' or 'groups' is required." });
133         }
134
135         my $path = PVE::AccessControl::normalize_path($param->{path});
136         raise_param_exc({ path => "invalid ACL path '$param->{path}'" }) if !$path;
137
138         PVE::AccessControl::lock_user_config(
139             sub {
140                         
141                 my $cfg = cfs_read_file("user.cfg");
142
143                 my $propagate = $param->{propagate} ? 1 : 0;
144
145                 foreach my $role (split_list($param->{roles})) {
146                     die "role '$role' does not exist\n" 
147                         if !$cfg->{roles}->{$role};
148
149                     foreach my $group (split_list($param->{groups})) {
150
151                         die "group '$group' does not exist\n"
152                             if !$cfg->{groups}->{$group};
153
154                         if ($param->{delete}) {
155                             delete($cfg->{acl}->{$path}->{groups}->{$group}->{$role});
156                         } else {
157                             $cfg->{acl}->{$path}->{groups}->{$group}->{$role} = $propagate;
158                         }
159                     }
160
161                     foreach my $userid (split_list($param->{users})) {
162                         my $username = PVE::AccessControl::verify_username($userid);
163
164                         die "user '$username' does not exist\n"
165                             if !$cfg->{users}->{$username};
166
167                         if ($param->{delete}) {
168                             delete($cfg->{acl}->{$path}->{users}->{$username}->{$role});
169                         } else {
170                             $cfg->{acl}->{$path}->{users}->{$username}->{$role} = $propagate;
171                         } 
172                     }
173                 }
174
175                 cfs_write_file("user.cfg", $cfg);
176             }, "ACL update failed");
177
178         return undef;
179     }});
180
181 1;