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