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