]>
Commit | Line | Data |
---|---|---|
2c3a6c0a DM |
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).", | |
96919234 | 23 | permissions => { |
fc21a5c2 | 24 | description => "The returned list is restricted to objects where you have rights to modify permissions.", |
e3a3a0d7 | 25 | user => 'all', |
96919234 | 26 | }, |
2c3a6c0a DM |
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 | ||
e3a3a0d7 DM |
48 | my $rpcenv = PVE::RPCEnvironment::get(); |
49 | my $authuser = $rpcenv->get_user(); | |
2c3a6c0a DM |
50 | my $res = []; |
51 | ||
e3a3a0d7 | 52 | my $usercfg = $rpcenv->{user_cfg}; |
2c3a6c0a | 53 | if (!$usercfg || !$usercfg->{acl}) { |
4384e19e | 54 | return $res; |
2c3a6c0a DM |
55 | } |
56 | ||
e3a3a0d7 DM |
57 | my $audit = $rpcenv->check($authuser, '/access', ['Sys.Audit'], 1); |
58 | ||
2c3a6c0a DM |
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; | |
e3a3a0d7 | 64 | next if !($audit || $rpcenv->check_perm_modify($authuser, $path, 1)); |
2c3a6c0a DM |
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', | |
96919234 | 88 | permissions => { |
e3a3a0d7 | 89 | check => ['perm-modify', '{path}'], |
96919234 | 90 | }, |
2c3a6c0a DM |
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, | |
e2993b66 | 117 | default => 1, |
2c3a6c0a DM |
118 | }, |
119 | delete => { | |
120 | description => "Remove permissions (instead of adding it).", | |
121 | type => 'boolean', | |
122 | optional => 1, | |
123 | }, | |
124 | }, | |
125 | }, | |
126 | returns => { type => 'null' }, | |
127 | code => sub { | |
128 | my ($param) = @_; | |
129 | ||
130 | if (!($param->{users} || $param->{groups})) { | |
131 | raise_param_exc({ | |
132 | users => "either 'users' or 'groups' is required.", | |
133 | groups => "either 'users' or 'groups' is required." }); | |
134 | } | |
135 | ||
136 | my $path = PVE::AccessControl::normalize_path($param->{path}); | |
137 | raise_param_exc({ path => "invalid ACL path '$param->{path}'" }) if !$path; | |
138 | ||
139 | PVE::AccessControl::lock_user_config( | |
140 | sub { | |
141 | ||
142 | my $cfg = cfs_read_file("user.cfg"); | |
143 | ||
e2993b66 DM |
144 | my $propagate = 1; |
145 | ||
146 | if (defined($param->{propagate})) { | |
147 | $propagate = $param->{propagate} ? 1 : 0; | |
148 | } | |
2c3a6c0a DM |
149 | |
150 | foreach my $role (split_list($param->{roles})) { | |
151 | die "role '$role' does not exist\n" | |
152 | if !$cfg->{roles}->{$role}; | |
153 | ||
154 | foreach my $group (split_list($param->{groups})) { | |
155 | ||
156 | die "group '$group' does not exist\n" | |
157 | if !$cfg->{groups}->{$group}; | |
158 | ||
159 | if ($param->{delete}) { | |
160 | delete($cfg->{acl}->{$path}->{groups}->{$group}->{$role}); | |
161 | } else { | |
162 | $cfg->{acl}->{$path}->{groups}->{$group}->{$role} = $propagate; | |
163 | } | |
164 | } | |
165 | ||
166 | foreach my $userid (split_list($param->{users})) { | |
167 | my $username = PVE::AccessControl::verify_username($userid); | |
168 | ||
169 | die "user '$username' does not exist\n" | |
170 | if !$cfg->{users}->{$username}; | |
171 | ||
172 | if ($param->{delete}) { | |
173 | delete($cfg->{acl}->{$path}->{users}->{$username}->{$role}); | |
174 | } else { | |
175 | $cfg->{acl}->{$path}->{users}->{$username}->{$role} = $propagate; | |
176 | } | |
177 | } | |
178 | } | |
179 | ||
180 | cfs_write_file("user.cfg", $cfg); | |
181 | }, "ACL update failed"); | |
182 | ||
183 | return undef; | |
184 | }}); | |
185 | ||
186 | 1; |