]> git.proxmox.com Git - systemd.git/blame - src/shared/acl-util.c
Imported Upstream version 221
[systemd.git] / src / shared / acl-util.c
CommitLineData
663996b3
MS
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2011,2013 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
663996b3
MS
22#include <errno.h>
23#include <stdbool.h>
24
25#include "acl-util.h"
26#include "util.h"
27#include "strv.h"
28
29int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *entry) {
30 acl_entry_t i;
e735f4d4 31 int r;
663996b3
MS
32
33 assert(acl);
34 assert(entry);
35
e735f4d4
MP
36 for (r = acl_get_entry(acl, ACL_FIRST_ENTRY, &i);
37 r > 0;
38 r = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) {
663996b3
MS
39
40 acl_tag_t tag;
41 uid_t *u;
42 bool b;
43
44 if (acl_get_tag_type(i, &tag) < 0)
45 return -errno;
46
47 if (tag != ACL_USER)
48 continue;
49
50 u = acl_get_qualifier(i);
51 if (!u)
52 return -errno;
53
54 b = *u == uid;
55 acl_free(u);
56
57 if (b) {
58 *entry = i;
59 return 1;
60 }
61 }
e735f4d4 62 if (r < 0)
663996b3
MS
63 return -errno;
64
65 return 0;
66}
67
14228c0d
MB
68int calc_acl_mask_if_needed(acl_t *acl_p) {
69 acl_entry_t i;
e735f4d4 70 int r;
14228c0d
MB
71
72 assert(acl_p);
73
e735f4d4
MP
74 for (r = acl_get_entry(*acl_p, ACL_FIRST_ENTRY, &i);
75 r > 0;
76 r = acl_get_entry(*acl_p, ACL_NEXT_ENTRY, &i)) {
14228c0d
MB
77 acl_tag_t tag;
78
79 if (acl_get_tag_type(i, &tag) < 0)
80 return -errno;
81
82 if (tag == ACL_MASK)
83 return 0;
e3bff60a
MP
84
85 if (IN_SET(tag, ACL_USER, ACL_GROUP)) {
86 if (acl_calc_mask(acl_p) < 0)
87 return -errno;
88
89 return 1;
90 }
14228c0d 91 }
e735f4d4 92 if (r < 0)
14228c0d
MB
93 return -errno;
94
e3bff60a 95 return 0;
e735f4d4
MP
96}
97
98int add_base_acls_if_needed(acl_t *acl_p, const char *path) {
99 acl_entry_t i;
100 int r;
101 bool have_user_obj = false, have_group_obj = false, have_other = false;
102 struct stat st;
103 _cleanup_(acl_freep) acl_t basic = NULL;
104
105 assert(acl_p);
106
107 for (r = acl_get_entry(*acl_p, ACL_FIRST_ENTRY, &i);
108 r > 0;
109 r = acl_get_entry(*acl_p, ACL_NEXT_ENTRY, &i)) {
110 acl_tag_t tag;
111
112 if (acl_get_tag_type(i, &tag) < 0)
113 return -errno;
114
115 if (tag == ACL_USER_OBJ)
116 have_user_obj = true;
117 else if (tag == ACL_GROUP_OBJ)
118 have_group_obj = true;
119 else if (tag == ACL_OTHER)
120 have_other = true;
121 if (have_user_obj && have_group_obj && have_other)
122 return 0;
123 }
124 if (r < 0)
125 return -errno;
14228c0d 126
e735f4d4
MP
127 r = stat(path, &st);
128 if (r < 0)
129 return -errno;
130
131 basic = acl_from_mode(st.st_mode);
132 if (!basic)
133 return -errno;
134
135 for (r = acl_get_entry(basic, ACL_FIRST_ENTRY, &i);
136 r > 0;
137 r = acl_get_entry(basic, ACL_NEXT_ENTRY, &i)) {
138 acl_tag_t tag;
139 acl_entry_t dst;
140
141 if (acl_get_tag_type(i, &tag) < 0)
142 return -errno;
143
144 if ((tag == ACL_USER_OBJ && have_user_obj) ||
145 (tag == ACL_GROUP_OBJ && have_group_obj) ||
146 (tag == ACL_OTHER && have_other))
147 continue;
148
149 r = acl_create_entry(acl_p, &dst);
150 if (r < 0)
151 return -errno;
152
153 r = acl_copy_entry(dst, i);
154 if (r < 0)
155 return -errno;
156 }
157 if (r < 0)
158 return -errno;
14228c0d
MB
159 return 0;
160}
161
e3bff60a
MP
162int acl_search_groups(const char *path, char ***ret_groups) {
163 _cleanup_strv_free_ char **g = NULL;
164 _cleanup_(acl_free) acl_t acl = NULL;
165 bool ret = false;
166 acl_entry_t entry;
167 int r;
663996b3
MS
168
169 assert(path);
663996b3
MS
170
171 acl = acl_get_file(path, ACL_TYPE_DEFAULT);
e3bff60a
MP
172 if (!acl)
173 return -errno;
663996b3 174
e3bff60a
MP
175 r = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
176 for (;;) {
177 _cleanup_(acl_free_gid_tpp) gid_t *gid = NULL;
178 acl_tag_t tag;
179
180 if (r < 0)
181 return -errno;
182 if (r == 0)
183 break;
663996b3 184
e3bff60a
MP
185 if (acl_get_tag_type(entry, &tag) < 0)
186 return -errno;
663996b3 187
e3bff60a
MP
188 if (tag != ACL_GROUP)
189 goto next;
663996b3 190
e3bff60a
MP
191 gid = acl_get_qualifier(entry);
192 if (!gid)
193 return -errno;
194
195 if (in_gid(*gid) > 0) {
196 if (!ret_groups)
197 return true;
198
199 ret = true;
200 }
201
202 if (ret_groups) {
203 char *name;
663996b3
MS
204
205 name = gid_to_name(*gid);
e3bff60a
MP
206 if (!name)
207 return -ENOMEM;
208
209 r = strv_consume(&g, name);
210 if (r < 0)
211 return r;
663996b3
MS
212 }
213
e3bff60a
MP
214 next:
215 r = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
663996b3
MS
216 }
217
e3bff60a
MP
218 if (ret_groups) {
219 *ret_groups = g;
220 g = NULL;
221 }
222
223 return ret;
663996b3 224}
e735f4d4 225
86f210e9 226int parse_acl(const char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask) {
e735f4d4
MP
227 _cleanup_free_ char **a = NULL, **d = NULL; /* strings are not be freed */
228 _cleanup_strv_free_ char **split;
229 char **entry;
230 int r = -EINVAL;
231 _cleanup_(acl_freep) acl_t a_acl = NULL, d_acl = NULL;
232
233 split = strv_split(text, ",");
234 if (!split)
86f210e9 235 return -ENOMEM;
e735f4d4
MP
236
237 STRV_FOREACH(entry, split) {
238 char *p;
239
240 p = startswith(*entry, "default:");
241 if (!p)
242 p = startswith(*entry, "d:");
243
244 if (p)
245 r = strv_push(&d, p);
246 else
247 r = strv_push(&a, *entry);
86f210e9
MP
248 if (r < 0)
249 return r;
e735f4d4 250 }
e735f4d4
MP
251
252 if (!strv_isempty(a)) {
253 _cleanup_free_ char *join;
254
255 join = strv_join(a, ",");
256 if (!join)
257 return -ENOMEM;
258
259 a_acl = acl_from_text(join);
260 if (!a_acl)
86f210e9 261 return -errno;
e735f4d4
MP
262
263 if (want_mask) {
264 r = calc_acl_mask_if_needed(&a_acl);
265 if (r < 0)
266 return r;
267 }
268 }
269
270 if (!strv_isempty(d)) {
271 _cleanup_free_ char *join;
272
273 join = strv_join(d, ",");
274 if (!join)
275 return -ENOMEM;
276
277 d_acl = acl_from_text(join);
278 if (!d_acl)
86f210e9 279 return -errno;
e735f4d4
MP
280
281 if (want_mask) {
282 r = calc_acl_mask_if_needed(&d_acl);
283 if (r < 0)
284 return r;
285 }
286 }
287
288 *acl_access = a_acl;
289 *acl_default = d_acl;
290 a_acl = d_acl = NULL;
86f210e9 291
e735f4d4
MP
292 return 0;
293}
294
e3bff60a
MP
295static int acl_entry_equal(acl_entry_t a, acl_entry_t b) {
296 acl_tag_t tag_a, tag_b;
297
298 if (acl_get_tag_type(a, &tag_a) < 0)
299 return -errno;
300
301 if (acl_get_tag_type(b, &tag_b) < 0)
302 return -errno;
303
304 if (tag_a != tag_b)
305 return false;
306
307 switch (tag_a) {
308 case ACL_USER_OBJ:
309 case ACL_GROUP_OBJ:
310 case ACL_MASK:
311 case ACL_OTHER:
312 /* can have only one of those */
313 return true;
314 case ACL_USER: {
315 _cleanup_(acl_free_uid_tpp) uid_t *uid_a = NULL, *uid_b = NULL;
316
317 uid_a = acl_get_qualifier(a);
318 if (!uid_a)
319 return -errno;
320
321 uid_b = acl_get_qualifier(b);
322 if (!uid_b)
323 return -errno;
324
325 return *uid_a == *uid_b;
326 }
327 case ACL_GROUP: {
328 _cleanup_(acl_free_gid_tpp) gid_t *gid_a = NULL, *gid_b = NULL;
329
330 gid_a = acl_get_qualifier(a);
331 if (!gid_a)
332 return -errno;
333
334 gid_b = acl_get_qualifier(b);
335 if (!gid_b)
336 return -errno;
337
338 return *gid_a == *gid_b;
339 }
340 default:
341 assert_not_reached("Unknown acl tag type");
342 }
343}
344
345static int find_acl_entry(acl_t acl, acl_entry_t entry, acl_entry_t *out) {
346 acl_entry_t i;
347 int r;
348
349 for (r = acl_get_entry(acl, ACL_FIRST_ENTRY, &i);
350 r > 0;
351 r = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) {
352
353 r = acl_entry_equal(i, entry);
354 if (r < 0)
355 return r;
356 if (r > 0) {
357 *out = i;
358 return 1;
359 }
360 }
361 if (r < 0)
362 return -errno;
363 return 0;
364}
365
e735f4d4
MP
366int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *acl) {
367 _cleanup_(acl_freep) acl_t old;
368 acl_entry_t i;
369 int r;
370
371 old = acl_get_file(path, type);
372 if (!old)
373 return -errno;
374
375 for (r = acl_get_entry(new, ACL_FIRST_ENTRY, &i);
376 r > 0;
377 r = acl_get_entry(new, ACL_NEXT_ENTRY, &i)) {
378
379 acl_entry_t j;
380
e3bff60a
MP
381 r = find_acl_entry(old, i, &j);
382 if (r < 0)
383 return r;
384 if (r == 0)
385 if (acl_create_entry(&old, &j) < 0)
386 return -errno;
e735f4d4
MP
387
388 if (acl_copy_entry(j, i) < 0)
389 return -errno;
390 }
391 if (r < 0)
392 return -errno;
393
394 *acl = old;
395 old = NULL;
396 return 0;
397}