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