]>
Commit | Line | Data |
---|---|---|
2c3a6c0a DM |
1 | package PVE::API2::User; |
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::JSONSchema qw(get_standard_option); | |
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 | my $extract_user_data = sub { | |
19 | my ($data, $full) = @_; | |
20 | ||
21 | my $res = {}; | |
22 | ||
23 | foreach my $prop (qw(enable expire firstname lastname email comment)) { | |
24 | $res->{$prop} = $data->{$prop} if defined($data->{$prop}); | |
25 | } | |
26 | ||
27 | return $res if !$full; | |
28 | ||
29 | $res->{groups} = $data->{groups} ? [ keys %{$data->{groups}} ] : []; | |
30 | ||
31 | return $res; | |
32 | }; | |
33 | ||
34 | __PACKAGE__->register_method ({ | |
35 | name => 'index', | |
36 | path => '', | |
37 | method => 'GET', | |
38 | description => "User index.", | |
930dcfc8 | 39 | permissions => { user => 'all' }, |
2c3a6c0a DM |
40 | parameters => { |
41 | additionalProperties => 0, | |
cb6f2f93 DM |
42 | properties => { |
43 | enabled => { | |
44 | type => 'boolean', | |
45 | description => "Optional filter for enable property.", | |
46 | optional => 1, | |
47 | } | |
48 | }, | |
2c3a6c0a DM |
49 | }, |
50 | returns => { | |
51 | type => 'array', | |
52 | items => { | |
53 | type => "object", | |
54 | properties => { | |
55 | userid => { type => 'string' }, | |
56 | }, | |
57 | }, | |
58 | links => [ { rel => 'child', href => "{userid}" } ], | |
59 | }, | |
60 | code => sub { | |
61 | my ($param) = @_; | |
62 | ||
930dcfc8 DM |
63 | my $rpcenv = PVE::RPCEnvironment::get(); |
64 | my $authuser = $rpcenv->get_user(); | |
65 | ||
2c3a6c0a DM |
66 | my $res = []; |
67 | ||
68 | my $usercfg = cfs_read_file("user.cfg"); | |
69 | ||
70 | foreach my $user (keys %{$usercfg->{users}}) { | |
930dcfc8 DM |
71 | # root sees all entries, a user only sees its own entry |
72 | next if $authuser ne 'root@pam' && $user ne $authuser; | |
73 | ||
2c3a6c0a | 74 | my $entry = &$extract_user_data($usercfg->{users}->{$user}); |
cb6f2f93 DM |
75 | |
76 | if (defined($param->{enabled})) { | |
77 | next if $entry->{enable} && !$param->{enabled}; | |
78 | next if !$entry->{enable} && $param->{enabled}; | |
79 | } | |
80 | ||
2c3a6c0a DM |
81 | $entry->{userid} = $user; |
82 | push @$res, $entry; | |
83 | } | |
84 | ||
85 | return $res; | |
86 | }}); | |
87 | ||
88 | __PACKAGE__->register_method ({ | |
89 | name => 'create_user', | |
90 | protected => 1, | |
91 | path => '', | |
92 | method => 'POST', | |
93 | description => "Create new user.", | |
94 | parameters => { | |
95 | additionalProperties => 0, | |
96 | properties => { | |
97 | userid => get_standard_option('userid'), | |
fdb30a4c | 98 | password => { type => 'string', optional => 1, minLength => 5, maxLength => 64 }, |
2c3a6c0a DM |
99 | groups => { type => 'string', optional => 1, format => 'pve-groupid-list'}, |
100 | firstname => { type => 'string', optional => 1 }, | |
101 | lastname => { type => 'string', optional => 1 }, | |
102 | email => { type => 'string', optional => 1, format => 'email-opt' }, | |
103 | comment => { type => 'string', optional => 1 }, | |
104 | expire => { | |
105 | description => "Account expiration date (seconds since epoch). '0' means no expiration date.", | |
106 | type => 'integer', | |
107 | minimum => 0, | |
108 | optional => 1, | |
109 | }, | |
110 | enable => { | |
111 | description => "Enable the account (default). You can set this to '0' to disable the accout", | |
112 | type => 'boolean', | |
113 | optional => 1, | |
114 | default => 1, | |
115 | }, | |
116 | }, | |
117 | }, | |
118 | returns => { type => 'null' }, | |
119 | code => sub { | |
120 | my ($param) = @_; | |
121 | ||
122 | PVE::AccessControl::lock_user_config( | |
123 | sub { | |
124 | ||
125 | my ($username, $ruid, $realm) = PVE::AccessControl::verify_username($param->{userid}); | |
126 | ||
127 | my $usercfg = cfs_read_file("user.cfg"); | |
128 | ||
129 | die "user '$username' already exists\n" | |
130 | if $usercfg->{users}->{$username}; | |
131 | ||
132 | PVE::AccessControl::domain_set_password($realm, $ruid, $param->{password}) | |
fdb30a4c | 133 | if defined($param->{password}); |
2c3a6c0a DM |
134 | |
135 | my $enable = defined($param->{enable}) ? $param->{enable} : 1; | |
136 | $usercfg->{users}->{$username} = { enable => $enable }; | |
137 | $usercfg->{users}->{$username}->{expire} = $param->{expire} if $param->{expire}; | |
138 | ||
139 | if ($param->{groups}) { | |
140 | foreach my $group (split_list($param->{groups})) { | |
141 | if ($usercfg->{groups}->{$group}) { | |
142 | PVE::AccessControl::add_user_group($username, $usercfg, $group); | |
143 | } else { | |
144 | die "no such group '$group'\n"; | |
145 | } | |
146 | } | |
147 | } | |
148 | ||
149 | $usercfg->{users}->{$username}->{firstname} = $param->{firstname} if $param->{firstname}; | |
150 | $usercfg->{users}->{$username}->{lastname} = $param->{lastname} if $param->{lastname}; | |
151 | $usercfg->{users}->{$username}->{email} = $param->{email} if $param->{email}; | |
152 | $usercfg->{users}->{$username}->{comment} = $param->{comment} if $param->{comment}; | |
153 | ||
154 | cfs_write_file("user.cfg", $usercfg); | |
155 | }, "create user failed"); | |
156 | ||
157 | return undef; | |
158 | }}); | |
159 | ||
160 | __PACKAGE__->register_method ({ | |
161 | name => 'read_user', | |
162 | path => '{userid}', | |
163 | method => 'GET', | |
164 | description => "Get user configuration.", | |
165 | parameters => { | |
166 | additionalProperties => 0, | |
167 | properties => { | |
168 | userid => get_standard_option('userid'), | |
169 | }, | |
170 | }, | |
171 | returns => { | |
172 | additionalProperties => 0, | |
173 | properties => { | |
174 | enable => { type => 'boolean' }, | |
175 | expire => { type => 'integer', optional => 1 }, | |
176 | firstname => { type => 'string', optional => 1 }, | |
177 | lastname => { type => 'string', optional => 1 }, | |
178 | email => { type => 'string', optional => 1 }, | |
179 | comment => { type => 'string', optional => 1 }, | |
180 | groups => { type => 'array' }, | |
181 | } | |
182 | }, | |
183 | code => sub { | |
184 | my ($param) = @_; | |
185 | ||
186 | my ($username, undef, $domain) = | |
187 | PVE::AccessControl::verify_username($param->{userid}); | |
188 | ||
189 | my $usercfg = cfs_read_file("user.cfg"); | |
190 | ||
191 | my $data = $usercfg->{users}->{$username}; | |
192 | ||
193 | die "user '$username' does not exist\n" if !$data; | |
194 | ||
195 | return &$extract_user_data($data, 1); | |
196 | }}); | |
197 | ||
198 | __PACKAGE__->register_method ({ | |
199 | name => 'update_user', | |
200 | protected => 1, | |
201 | path => '{userid}', | |
202 | method => 'PUT', | |
203 | description => "Update user configuration.", | |
204 | parameters => { | |
205 | additionalProperties => 0, | |
206 | properties => { | |
207 | userid => get_standard_option('userid'), | |
fdb30a4c | 208 | password => { type => 'string', optional => 1, minLength => 5, maxLength => 64 }, |
2c3a6c0a DM |
209 | groups => { type => 'string', optional => 1, format => 'pve-groupid-list' }, |
210 | append => { | |
211 | type => 'boolean', | |
212 | optional => 1, | |
213 | requires => 'groups', | |
214 | }, | |
215 | enable => { | |
216 | description => "Enable/disable the account.", | |
217 | type => 'boolean', | |
218 | optional => 1, | |
219 | }, | |
220 | firstname => { type => 'string', optional => 1 }, | |
221 | lastname => { type => 'string', optional => 1 }, | |
222 | email => { type => 'string', optional => 1, format => 'email-opt' }, | |
223 | comment => { type => 'string', optional => 1 }, | |
224 | expire => { | |
225 | description => "Account expiration date (seconds since epoch). '0' means no expiration date.", | |
226 | type => 'integer', | |
227 | minimum => 0, | |
228 | optional => 1 | |
229 | }, | |
230 | }, | |
231 | }, | |
232 | returns => { type => 'null' }, | |
233 | code => sub { | |
234 | my ($param) = @_; | |
235 | ||
236 | PVE::AccessControl::lock_user_config( | |
237 | sub { | |
238 | ||
239 | my ($username, $ruid, $realm) = | |
240 | PVE::AccessControl::verify_username($param->{userid}); | |
241 | ||
242 | my $usercfg = cfs_read_file("user.cfg"); | |
243 | ||
244 | die "user '$username' does not exist\n" | |
245 | if !$usercfg->{users}->{$username}; | |
246 | ||
247 | PVE::AccessControl::domain_set_password($realm, $ruid, $param->{password}) | |
fdb30a4c | 248 | if defined($param->{password}); |
2c3a6c0a DM |
249 | |
250 | $usercfg->{users}->{$username}->{enable} = $param->{enable} if defined($param->{enable}); | |
251 | ||
252 | $usercfg->{users}->{$username}->{expire} = $param->{expire} if defined($param->{expire}); | |
253 | ||
254 | PVE::AccessControl::delete_user_group($username, $usercfg) | |
e6521738 | 255 | if (!$param->{append} && defined($param->{groups})); |
2c3a6c0a DM |
256 | |
257 | if ($param->{groups}) { | |
258 | foreach my $group (split_list($param->{groups})) { | |
259 | if ($usercfg->{groups}->{$group}) { | |
260 | PVE::AccessControl::add_user_group($username, $usercfg, $group); | |
261 | } else { | |
262 | die "no such group '$group'\n"; | |
263 | } | |
264 | } | |
265 | } | |
266 | ||
267 | $usercfg->{users}->{$username}->{firstname} = $param->{firstname} if defined($param->{firstname}); | |
268 | $usercfg->{users}->{$username}->{lastname} = $param->{lastname} if defined($param->{lastname}); | |
269 | $usercfg->{users}->{$username}->{email} = $param->{email} if defined($param->{email}); | |
270 | $usercfg->{users}->{$username}->{comment} = $param->{comment} if defined($param->{comment}); | |
271 | ||
272 | cfs_write_file("user.cfg", $usercfg); | |
273 | }, "update user failed"); | |
274 | ||
275 | return undef; | |
276 | }}); | |
277 | ||
278 | __PACKAGE__->register_method ({ | |
279 | name => 'delete_user', | |
280 | protected => 1, | |
281 | path => '{userid}', | |
282 | method => 'DELETE', | |
283 | description => "Delete user.", | |
284 | parameters => { | |
285 | additionalProperties => 0, | |
286 | properties => { | |
287 | userid => get_standard_option('userid'), | |
288 | } | |
289 | }, | |
290 | returns => { type => 'null' }, | |
291 | code => sub { | |
292 | my ($param) = @_; | |
293 | ||
294 | PVE::AccessControl::lock_user_config( | |
295 | sub { | |
296 | ||
297 | my ($username, $ruid, $realm) = | |
298 | PVE::AccessControl::verify_username($param->{userid}); | |
299 | ||
300 | my $usercfg = cfs_read_file("user.cfg"); | |
301 | ||
302 | die "user '$username' does not exist\n" | |
303 | if !$usercfg->{users}->{$username}; | |
304 | ||
305 | delete ($usercfg->{users}->{$username}); | |
306 | ||
307 | PVE::AccessControl::delete_shadow_password($ruid) if $realm eq 'pve'; | |
308 | PVE::AccessControl::delete_user_group($username, $usercfg); | |
309 | PVE::AccessControl::delete_user_acl($username, $usercfg); | |
310 | ||
311 | cfs_write_file("user.cfg", $usercfg); | |
312 | }, "delete user failed"); | |
313 | ||
314 | return undef; | |
315 | }}); | |
316 | ||
317 | 1; |