File: | build-scan/../src/shared/acl-util.c |
Warning: | line 369, column 21 1st function call argument is an uninitialized value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* SPDX-License-Identifier: LGPL-2.1+ */ | |||
2 | ||||
3 | #include <errno(*__errno_location ()).h> | |||
4 | #include <stdbool.h> | |||
5 | ||||
6 | #include "acl-util.h" | |||
7 | #include "alloc-util.h" | |||
8 | #include "string-util.h" | |||
9 | #include "strv.h" | |||
10 | #include "user-util.h" | |||
11 | #include "util.h" | |||
12 | ||||
13 | int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *entry) { | |||
14 | acl_entry_t i; | |||
15 | int r; | |||
16 | ||||
17 | assert(acl)do { if ((__builtin_expect(!!(!(acl)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("acl"), "../src/shared/acl-util.c", 17, __PRETTY_FUNCTION__ ); } while (0); | |||
18 | assert(entry)do { if ((__builtin_expect(!!(!(entry)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("entry"), "../src/shared/acl-util.c", 18 , __PRETTY_FUNCTION__); } while (0); | |||
19 | ||||
20 | for (r = acl_get_entry(acl, ACL_FIRST_ENTRY0, &i); | |||
21 | r > 0; | |||
22 | r = acl_get_entry(acl, ACL_NEXT_ENTRY1, &i)) { | |||
23 | ||||
24 | acl_tag_t tag; | |||
25 | uid_t *u; | |||
26 | bool_Bool b; | |||
27 | ||||
28 | if (acl_get_tag_type(i, &tag) < 0) | |||
29 | return -errno(*__errno_location ()); | |||
30 | ||||
31 | if (tag != ACL_USER(0x02)) | |||
32 | continue; | |||
33 | ||||
34 | u = acl_get_qualifier(i); | |||
35 | if (!u) | |||
36 | return -errno(*__errno_location ()); | |||
37 | ||||
38 | b = *u == uid; | |||
39 | acl_free(u); | |||
40 | ||||
41 | if (b) { | |||
42 | *entry = i; | |||
43 | return 1; | |||
44 | } | |||
45 | } | |||
46 | if (r < 0) | |||
47 | return -errno(*__errno_location ()); | |||
48 | ||||
49 | return 0; | |||
50 | } | |||
51 | ||||
52 | int calc_acl_mask_if_needed(acl_t *acl_p) { | |||
53 | acl_entry_t i; | |||
54 | int r; | |||
55 | bool_Bool need = false0; | |||
56 | ||||
57 | assert(acl_p)do { if ((__builtin_expect(!!(!(acl_p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("acl_p"), "../src/shared/acl-util.c", 57 , __PRETTY_FUNCTION__); } while (0); | |||
58 | ||||
59 | for (r = acl_get_entry(*acl_p, ACL_FIRST_ENTRY0, &i); | |||
60 | r > 0; | |||
61 | r = acl_get_entry(*acl_p, ACL_NEXT_ENTRY1, &i)) { | |||
62 | acl_tag_t tag; | |||
63 | ||||
64 | if (acl_get_tag_type(i, &tag) < 0) | |||
65 | return -errno(*__errno_location ()); | |||
66 | ||||
67 | if (tag == ACL_MASK(0x10)) | |||
68 | return 0; | |||
69 | ||||
70 | if (IN_SET(tag, ACL_USER, ACL_GROUP)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended [20 - sizeof((int[]){(0x02), (0x08)})/sizeof(int)]; switch(tag ) { case (0x02): case (0x08): _found = 1; break; default: break ; } _found; })) | |||
71 | need = true1; | |||
72 | } | |||
73 | if (r < 0) | |||
74 | return -errno(*__errno_location ()); | |||
75 | ||||
76 | if (need && acl_calc_mask(acl_p) < 0) | |||
77 | return -errno(*__errno_location ()); | |||
78 | ||||
79 | return need; | |||
80 | } | |||
81 | ||||
82 | int add_base_acls_if_needed(acl_t *acl_p, const char *path) { | |||
83 | acl_entry_t i; | |||
84 | int r; | |||
85 | bool_Bool have_user_obj = false0, have_group_obj = false0, have_other = false0; | |||
86 | struct stat st; | |||
87 | _cleanup_(acl_freep)__attribute__((cleanup(acl_freep))) acl_t basic = NULL((void*)0); | |||
88 | ||||
89 | assert(acl_p)do { if ((__builtin_expect(!!(!(acl_p)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("acl_p"), "../src/shared/acl-util.c", 89 , __PRETTY_FUNCTION__); } while (0); | |||
90 | ||||
91 | for (r = acl_get_entry(*acl_p, ACL_FIRST_ENTRY0, &i); | |||
92 | r > 0; | |||
93 | r = acl_get_entry(*acl_p, ACL_NEXT_ENTRY1, &i)) { | |||
94 | acl_tag_t tag; | |||
95 | ||||
96 | if (acl_get_tag_type(i, &tag) < 0) | |||
97 | return -errno(*__errno_location ()); | |||
98 | ||||
99 | if (tag == ACL_USER_OBJ(0x01)) | |||
100 | have_user_obj = true1; | |||
101 | else if (tag == ACL_GROUP_OBJ(0x04)) | |||
102 | have_group_obj = true1; | |||
103 | else if (tag == ACL_OTHER(0x20)) | |||
104 | have_other = true1; | |||
105 | if (have_user_obj && have_group_obj && have_other) | |||
106 | return 0; | |||
107 | } | |||
108 | if (r < 0) | |||
109 | return -errno(*__errno_location ()); | |||
110 | ||||
111 | r = stat(path, &st); | |||
112 | if (r < 0) | |||
113 | return -errno(*__errno_location ()); | |||
114 | ||||
115 | basic = acl_from_mode(st.st_mode); | |||
116 | if (!basic) | |||
117 | return -errno(*__errno_location ()); | |||
118 | ||||
119 | for (r = acl_get_entry(basic, ACL_FIRST_ENTRY0, &i); | |||
120 | r > 0; | |||
121 | r = acl_get_entry(basic, ACL_NEXT_ENTRY1, &i)) { | |||
122 | acl_tag_t tag; | |||
123 | acl_entry_t dst; | |||
124 | ||||
125 | if (acl_get_tag_type(i, &tag) < 0) | |||
126 | return -errno(*__errno_location ()); | |||
127 | ||||
128 | if ((tag == ACL_USER_OBJ(0x01) && have_user_obj) || | |||
129 | (tag == ACL_GROUP_OBJ(0x04) && have_group_obj) || | |||
130 | (tag == ACL_OTHER(0x20) && have_other)) | |||
131 | continue; | |||
132 | ||||
133 | r = acl_create_entry(acl_p, &dst); | |||
134 | if (r < 0) | |||
135 | return -errno(*__errno_location ()); | |||
136 | ||||
137 | r = acl_copy_entry(dst, i); | |||
138 | if (r < 0) | |||
139 | return -errno(*__errno_location ()); | |||
140 | } | |||
141 | if (r < 0) | |||
142 | return -errno(*__errno_location ()); | |||
143 | return 0; | |||
144 | } | |||
145 | ||||
146 | int acl_search_groups(const char *path, char ***ret_groups) { | |||
147 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **g = NULL((void*)0); | |||
148 | _cleanup_(acl_freep)__attribute__((cleanup(acl_freep))) acl_t acl = NULL((void*)0); | |||
149 | bool_Bool ret = false0; | |||
150 | acl_entry_t entry; | |||
151 | int r; | |||
152 | ||||
153 | assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("path"), "../src/shared/acl-util.c", 153 , __PRETTY_FUNCTION__); } while (0); | |||
154 | ||||
155 | acl = acl_get_file(path, ACL_TYPE_DEFAULT(0x4000)); | |||
156 | if (!acl) | |||
157 | return -errno(*__errno_location ()); | |||
158 | ||||
159 | r = acl_get_entry(acl, ACL_FIRST_ENTRY0, &entry); | |||
160 | for (;;) { | |||
161 | _cleanup_(acl_free_gid_tpp)__attribute__((cleanup(acl_free_gid_tpp))) gid_t *gid = NULL((void*)0); | |||
162 | acl_tag_t tag; | |||
163 | ||||
164 | if (r < 0) | |||
165 | return -errno(*__errno_location ()); | |||
166 | if (r == 0) | |||
167 | break; | |||
168 | ||||
169 | if (acl_get_tag_type(entry, &tag) < 0) | |||
170 | return -errno(*__errno_location ()); | |||
171 | ||||
172 | if (tag != ACL_GROUP(0x08)) | |||
173 | goto next; | |||
174 | ||||
175 | gid = acl_get_qualifier(entry); | |||
176 | if (!gid) | |||
177 | return -errno(*__errno_location ()); | |||
178 | ||||
179 | if (in_gid(*gid) > 0) { | |||
180 | if (!ret_groups) | |||
181 | return true1; | |||
182 | ||||
183 | ret = true1; | |||
184 | } | |||
185 | ||||
186 | if (ret_groups) { | |||
187 | char *name; | |||
188 | ||||
189 | name = gid_to_name(*gid); | |||
190 | if (!name) | |||
191 | return -ENOMEM12; | |||
192 | ||||
193 | r = strv_consume(&g, name); | |||
194 | if (r < 0) | |||
195 | return r; | |||
196 | } | |||
197 | ||||
198 | next: | |||
199 | r = acl_get_entry(acl, ACL_NEXT_ENTRY1, &entry); | |||
200 | } | |||
201 | ||||
202 | if (ret_groups) | |||
203 | *ret_groups = TAKE_PTR(g)({ typeof(g) _ptr_ = (g); (g) = ((void*)0); _ptr_; }); | |||
204 | ||||
205 | return ret; | |||
206 | } | |||
207 | ||||
208 | int parse_acl(const char *text, acl_t *acl_access, acl_t *acl_default, bool_Bool want_mask) { | |||
209 | _cleanup_free___attribute__((cleanup(freep))) char **a = NULL((void*)0), **d = NULL((void*)0); /* strings are not freed */ | |||
210 | _cleanup_strv_free___attribute__((cleanup(strv_freep))) char **split; | |||
211 | char **entry; | |||
212 | int r = -EINVAL22; | |||
213 | _cleanup_(acl_freep)__attribute__((cleanup(acl_freep))) acl_t a_acl = NULL((void*)0), d_acl = NULL((void*)0); | |||
214 | ||||
215 | split = strv_split(text, ","); | |||
216 | if (!split) | |||
217 | return -ENOMEM12; | |||
218 | ||||
219 | STRV_FOREACH(entry, split)for ((entry) = (split); (entry) && *(entry); (entry)++ ) { | |||
220 | char *p; | |||
221 | ||||
222 | p = startswith(*entry, "default:"); | |||
223 | if (!p) | |||
224 | p = startswith(*entry, "d:"); | |||
225 | ||||
226 | if (p) | |||
227 | r = strv_push(&d, p); | |||
228 | else | |||
229 | r = strv_push(&a, *entry); | |||
230 | if (r < 0) | |||
231 | return r; | |||
232 | } | |||
233 | ||||
234 | if (!strv_isempty(a)) { | |||
235 | _cleanup_free___attribute__((cleanup(freep))) char *join; | |||
236 | ||||
237 | join = strv_join(a, ","); | |||
238 | if (!join) | |||
239 | return -ENOMEM12; | |||
240 | ||||
241 | a_acl = acl_from_text(join); | |||
242 | if (!a_acl) | |||
243 | return -errno(*__errno_location ()); | |||
244 | ||||
245 | if (want_mask) { | |||
246 | r = calc_acl_mask_if_needed(&a_acl); | |||
247 | if (r < 0) | |||
248 | return r; | |||
249 | } | |||
250 | } | |||
251 | ||||
252 | if (!strv_isempty(d)) { | |||
253 | _cleanup_free___attribute__((cleanup(freep))) char *join; | |||
254 | ||||
255 | join = strv_join(d, ","); | |||
256 | if (!join) | |||
257 | return -ENOMEM12; | |||
258 | ||||
259 | d_acl = acl_from_text(join); | |||
260 | if (!d_acl) | |||
261 | return -errno(*__errno_location ()); | |||
262 | ||||
263 | if (want_mask) { | |||
264 | r = calc_acl_mask_if_needed(&d_acl); | |||
265 | if (r < 0) | |||
266 | return r; | |||
267 | } | |||
268 | } | |||
269 | ||||
270 | *acl_access = TAKE_PTR(a_acl)({ typeof(a_acl) _ptr_ = (a_acl); (a_acl) = ((void*)0); _ptr_ ; }); | |||
271 | *acl_default = TAKE_PTR(d_acl)({ typeof(d_acl) _ptr_ = (d_acl); (d_acl) = ((void*)0); _ptr_ ; }); | |||
272 | ||||
273 | return 0; | |||
274 | } | |||
275 | ||||
276 | static int acl_entry_equal(acl_entry_t a, acl_entry_t b) { | |||
277 | acl_tag_t tag_a, tag_b; | |||
278 | ||||
279 | if (acl_get_tag_type(a, &tag_a) < 0) | |||
280 | return -errno(*__errno_location ()); | |||
281 | ||||
282 | if (acl_get_tag_type(b, &tag_b) < 0) | |||
283 | return -errno(*__errno_location ()); | |||
284 | ||||
285 | if (tag_a != tag_b) | |||
286 | return false0; | |||
287 | ||||
288 | switch (tag_a) { | |||
289 | case ACL_USER_OBJ(0x01): | |||
290 | case ACL_GROUP_OBJ(0x04): | |||
291 | case ACL_MASK(0x10): | |||
292 | case ACL_OTHER(0x20): | |||
293 | /* can have only one of those */ | |||
294 | return true1; | |||
295 | case ACL_USER(0x02): { | |||
296 | _cleanup_(acl_free_uid_tpp)__attribute__((cleanup(acl_free_uid_tpp))) uid_t *uid_a = NULL((void*)0), *uid_b = NULL((void*)0); | |||
297 | ||||
298 | uid_a = acl_get_qualifier(a); | |||
299 | if (!uid_a) | |||
300 | return -errno(*__errno_location ()); | |||
301 | ||||
302 | uid_b = acl_get_qualifier(b); | |||
303 | if (!uid_b) | |||
304 | return -errno(*__errno_location ()); | |||
305 | ||||
306 | return *uid_a == *uid_b; | |||
307 | } | |||
308 | case ACL_GROUP(0x08): { | |||
309 | _cleanup_(acl_free_gid_tpp)__attribute__((cleanup(acl_free_gid_tpp))) gid_t *gid_a = NULL((void*)0), *gid_b = NULL((void*)0); | |||
310 | ||||
311 | gid_a = acl_get_qualifier(a); | |||
312 | if (!gid_a) | |||
313 | return -errno(*__errno_location ()); | |||
314 | ||||
315 | gid_b = acl_get_qualifier(b); | |||
316 | if (!gid_b) | |||
317 | return -errno(*__errno_location ()); | |||
318 | ||||
319 | return *gid_a == *gid_b; | |||
320 | } | |||
321 | default: | |||
322 | assert_not_reached("Unknown acl tag type")do { log_assert_failed_unreachable_realm(LOG_REALM_SYSTEMD, ( "Unknown acl tag type"), "../src/shared/acl-util.c", 322, __PRETTY_FUNCTION__ ); } while (0); | |||
323 | } | |||
324 | } | |||
325 | ||||
326 | static int find_acl_entry(acl_t acl, acl_entry_t entry, acl_entry_t *out) { | |||
327 | acl_entry_t i; | |||
328 | int r; | |||
329 | ||||
330 | for (r = acl_get_entry(acl, ACL_FIRST_ENTRY0, &i); | |||
331 | r > 0; | |||
332 | r = acl_get_entry(acl, ACL_NEXT_ENTRY1, &i)) { | |||
333 | ||||
334 | r = acl_entry_equal(i, entry); | |||
335 | if (r < 0) | |||
336 | return r; | |||
337 | if (r > 0) { | |||
338 | *out = i; | |||
339 | return 1; | |||
340 | } | |||
341 | } | |||
342 | if (r < 0) | |||
343 | return -errno(*__errno_location ()); | |||
344 | return 0; | |||
345 | } | |||
346 | ||||
347 | int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *acl) { | |||
348 | _cleanup_(acl_freep)__attribute__((cleanup(acl_freep))) acl_t old; | |||
349 | acl_entry_t i; | |||
350 | int r; | |||
351 | ||||
352 | old = acl_get_file(path, type); | |||
353 | if (!old) | |||
| ||||
354 | return -errno(*__errno_location ()); | |||
355 | ||||
356 | for (r = acl_get_entry(new, ACL_FIRST_ENTRY0, &i); | |||
357 | r > 0; | |||
358 | r = acl_get_entry(new, ACL_NEXT_ENTRY1, &i)) { | |||
359 | ||||
360 | acl_entry_t j; | |||
361 | ||||
362 | r = find_acl_entry(old, i, &j); | |||
363 | if (r < 0) | |||
364 | return r; | |||
365 | if (r == 0) | |||
366 | if (acl_create_entry(&old, &j) < 0) | |||
367 | return -errno(*__errno_location ()); | |||
368 | ||||
369 | if (acl_copy_entry(j, i) < 0) | |||
| ||||
370 | return -errno(*__errno_location ()); | |||
371 | } | |||
372 | if (r < 0) | |||
373 | return -errno(*__errno_location ()); | |||
374 | ||||
375 | *acl = TAKE_PTR(old)({ typeof(old) _ptr_ = (old); (old) = ((void*)0); _ptr_; }); | |||
376 | ||||
377 | return 0; | |||
378 | } | |||
379 | ||||
380 | int add_acls_for_user(int fd, uid_t uid) { | |||
381 | _cleanup_(acl_freep)__attribute__((cleanup(acl_freep))) acl_t acl = NULL((void*)0); | |||
382 | acl_entry_t entry; | |||
383 | acl_permset_t permset; | |||
384 | int r; | |||
385 | ||||
386 | acl = acl_get_fd(fd); | |||
387 | if (!acl) | |||
388 | return -errno(*__errno_location ()); | |||
389 | ||||
390 | r = acl_find_uid(acl, uid, &entry); | |||
391 | if (r <= 0) { | |||
392 | if (acl_create_entry(&acl, &entry) < 0 || | |||
393 | acl_set_tag_type(entry, ACL_USER(0x02)) < 0 || | |||
394 | acl_set_qualifier(entry, &uid) < 0) | |||
395 | return -errno(*__errno_location ()); | |||
396 | } | |||
397 | ||||
398 | /* We do not recalculate the mask unconditionally here, | |||
399 | * so that the fchmod() mask above stays intact. */ | |||
400 | if (acl_get_permset(entry, &permset) < 0 || | |||
401 | acl_add_perm(permset, ACL_READ(0x04)) < 0) | |||
402 | return -errno(*__errno_location ()); | |||
403 | ||||
404 | r = calc_acl_mask_if_needed(&acl); | |||
405 | if (r < 0) | |||
406 | return r; | |||
407 | ||||
408 | return acl_set_fd(fd, acl); | |||
409 | } |