]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/acl-util.c
2 This file is part of systemd.
4 Copyright 2011,2013 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include "alloc-util.h"
25 #include "string-util.h"
27 #include "user-util.h"
30 int acl_find_uid(acl_t acl
, uid_t uid
, acl_entry_t
*entry
) {
37 for (r
= acl_get_entry(acl
, ACL_FIRST_ENTRY
, &i
);
39 r
= acl_get_entry(acl
, ACL_NEXT_ENTRY
, &i
)) {
45 if (acl_get_tag_type(i
, &tag
) < 0)
51 u
= acl_get_qualifier(i
);
69 int calc_acl_mask_if_needed(acl_t
*acl_p
) {
76 for (r
= acl_get_entry(*acl_p
, ACL_FIRST_ENTRY
, &i
);
78 r
= acl_get_entry(*acl_p
, ACL_NEXT_ENTRY
, &i
)) {
81 if (acl_get_tag_type(i
, &tag
) < 0)
87 if (IN_SET(tag
, ACL_USER
, ACL_GROUP
))
93 if (need
&& acl_calc_mask(acl_p
) < 0)
99 int add_base_acls_if_needed(acl_t
*acl_p
, const char *path
) {
102 bool have_user_obj
= false, have_group_obj
= false, have_other
= false;
104 _cleanup_(acl_freep
) acl_t basic
= NULL
;
108 for (r
= acl_get_entry(*acl_p
, ACL_FIRST_ENTRY
, &i
);
110 r
= acl_get_entry(*acl_p
, ACL_NEXT_ENTRY
, &i
)) {
113 if (acl_get_tag_type(i
, &tag
) < 0)
116 if (tag
== ACL_USER_OBJ
)
117 have_user_obj
= true;
118 else if (tag
== ACL_GROUP_OBJ
)
119 have_group_obj
= true;
120 else if (tag
== ACL_OTHER
)
122 if (have_user_obj
&& have_group_obj
&& have_other
)
132 basic
= acl_from_mode(st
.st_mode
);
136 for (r
= acl_get_entry(basic
, ACL_FIRST_ENTRY
, &i
);
138 r
= acl_get_entry(basic
, ACL_NEXT_ENTRY
, &i
)) {
142 if (acl_get_tag_type(i
, &tag
) < 0)
145 if ((tag
== ACL_USER_OBJ
&& have_user_obj
) ||
146 (tag
== ACL_GROUP_OBJ
&& have_group_obj
) ||
147 (tag
== ACL_OTHER
&& have_other
))
150 r
= acl_create_entry(acl_p
, &dst
);
154 r
= acl_copy_entry(dst
, i
);
163 int acl_search_groups(const char *path
, char ***ret_groups
) {
164 _cleanup_strv_free_
char **g
= NULL
;
165 _cleanup_(acl_freep
) acl_t acl
= NULL
;
172 acl
= acl_get_file(path
, ACL_TYPE_DEFAULT
);
176 r
= acl_get_entry(acl
, ACL_FIRST_ENTRY
, &entry
);
178 _cleanup_(acl_free_gid_tpp
) gid_t
*gid
= NULL
;
186 if (acl_get_tag_type(entry
, &tag
) < 0)
189 if (tag
!= ACL_GROUP
)
192 gid
= acl_get_qualifier(entry
);
196 if (in_gid(*gid
) > 0) {
206 name
= gid_to_name(*gid
);
210 r
= strv_consume(&g
, name
);
216 r
= acl_get_entry(acl
, ACL_NEXT_ENTRY
, &entry
);
227 int parse_acl(const char *text
, acl_t
*acl_access
, acl_t
*acl_default
, bool want_mask
) {
228 _cleanup_free_
char **a
= NULL
, **d
= NULL
; /* strings are not be freed */
229 _cleanup_strv_free_
char **split
;
232 _cleanup_(acl_freep
) acl_t a_acl
= NULL
, d_acl
= NULL
;
234 split
= strv_split(text
, ",");
238 STRV_FOREACH(entry
, split
) {
241 p
= startswith(*entry
, "default:");
243 p
= startswith(*entry
, "d:");
246 r
= strv_push(&d
, p
);
248 r
= strv_push(&a
, *entry
);
253 if (!strv_isempty(a
)) {
254 _cleanup_free_
char *join
;
256 join
= strv_join(a
, ",");
260 a_acl
= acl_from_text(join
);
265 r
= calc_acl_mask_if_needed(&a_acl
);
271 if (!strv_isempty(d
)) {
272 _cleanup_free_
char *join
;
274 join
= strv_join(d
, ",");
278 d_acl
= acl_from_text(join
);
283 r
= calc_acl_mask_if_needed(&d_acl
);
290 *acl_default
= d_acl
;
291 a_acl
= d_acl
= NULL
;
296 static int acl_entry_equal(acl_entry_t a
, acl_entry_t b
) {
297 acl_tag_t tag_a
, tag_b
;
299 if (acl_get_tag_type(a
, &tag_a
) < 0)
302 if (acl_get_tag_type(b
, &tag_b
) < 0)
313 /* can have only one of those */
316 _cleanup_(acl_free_uid_tpp
) uid_t
*uid_a
= NULL
, *uid_b
= NULL
;
318 uid_a
= acl_get_qualifier(a
);
322 uid_b
= acl_get_qualifier(b
);
326 return *uid_a
== *uid_b
;
329 _cleanup_(acl_free_gid_tpp
) gid_t
*gid_a
= NULL
, *gid_b
= NULL
;
331 gid_a
= acl_get_qualifier(a
);
335 gid_b
= acl_get_qualifier(b
);
339 return *gid_a
== *gid_b
;
342 assert_not_reached("Unknown acl tag type");
346 static int find_acl_entry(acl_t acl
, acl_entry_t entry
, acl_entry_t
*out
) {
350 for (r
= acl_get_entry(acl
, ACL_FIRST_ENTRY
, &i
);
352 r
= acl_get_entry(acl
, ACL_NEXT_ENTRY
, &i
)) {
354 r
= acl_entry_equal(i
, entry
);
367 int acls_for_file(const char *path
, acl_type_t type
, acl_t
new, acl_t
*acl
) {
368 _cleanup_(acl_freep
) acl_t old
;
372 old
= acl_get_file(path
, type
);
376 for (r
= acl_get_entry(new, ACL_FIRST_ENTRY
, &i
);
378 r
= acl_get_entry(new, ACL_NEXT_ENTRY
, &i
)) {
382 r
= find_acl_entry(old
, i
, &j
);
386 if (acl_create_entry(&old
, &j
) < 0)
389 if (acl_copy_entry(j
, i
) < 0)
400 int add_acls_for_user(int fd
, uid_t uid
) {
401 _cleanup_(acl_freep
) acl_t acl
= NULL
;
403 acl_permset_t permset
;
406 acl
= acl_get_fd(fd
);
410 r
= acl_find_uid(acl
, uid
, &entry
);
412 if (acl_create_entry(&acl
, &entry
) < 0 ||
413 acl_set_tag_type(entry
, ACL_USER
) < 0 ||
414 acl_set_qualifier(entry
, &uid
) < 0)
418 /* We do not recalculate the mask unconditionally here,
419 * so that the fchmod() mask above stays intact. */
420 if (acl_get_permset(entry
, &permset
) < 0 ||
421 acl_add_perm(permset
, ACL_READ
) < 0)
424 r
= calc_acl_mask_if_needed(&acl
);
428 return acl_set_fd(fd
, acl
);