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