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