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