diff --git a/meson.build b/meson.build index 15e1d3821e..afd2342488 100644 --- a/meson.build +++ b/meson.build @@ -1183,6 +1183,7 @@ conf.set10('ENABLE_POLKIT', install_polkit) libacl = dependency('libacl', required : get_option('acl')) conf.set10('HAVE_ACL', libacl.found()) +libacl_cflags = libacl.partial_dependency(includes: true, compile_args: true) libaudit = dependency('audit', required : get_option('audit')) diff --git a/src/shared/acl-util.c b/src/shared/acl-util.c index 0a5c8c9f92..554d473821 100644 --- a/src/shared/acl-util.c +++ b/src/shared/acl-util.c @@ -7,11 +7,74 @@ #include "errno-util.h" #include "extract-word.h" #include "fd-util.h" +#include "log.h" #include "string-util.h" #include "strv.h" #include "user-util.h" #if HAVE_ACL +static void *libacl_dl = NULL; + +DLSYM_PROTOTYPE(acl_add_perm); +DLSYM_PROTOTYPE(acl_calc_mask); +DLSYM_PROTOTYPE(acl_copy_entry); +DLSYM_PROTOTYPE(acl_create_entry); +DLSYM_PROTOTYPE(acl_delete_entry); +DLSYM_PROTOTYPE(acl_delete_perm); +DLSYM_PROTOTYPE(acl_dup); +DLSYM_PROTOTYPE(acl_entries); +DLSYM_PROTOTYPE(acl_free); +DLSYM_PROTOTYPE(acl_from_mode); +DLSYM_PROTOTYPE(acl_from_text); +DLSYM_PROTOTYPE(acl_get_entry); +DLSYM_PROTOTYPE(acl_get_fd); +DLSYM_PROTOTYPE(acl_get_file); +DLSYM_PROTOTYPE(acl_get_perm); +DLSYM_PROTOTYPE(acl_get_permset); +DLSYM_PROTOTYPE(acl_get_qualifier); +DLSYM_PROTOTYPE(acl_get_tag_type); +DLSYM_PROTOTYPE(acl_init); +DLSYM_PROTOTYPE(acl_set_fd); +DLSYM_PROTOTYPE(acl_set_file); +DLSYM_PROTOTYPE(acl_set_qualifier); +DLSYM_PROTOTYPE(acl_set_tag_type); +DLSYM_PROTOTYPE(acl_to_any_text); + +int dlopen_libacl(void) { + ELF_NOTE_DLOPEN("acl", + "Support for file Access Control Lists (ACLs)", + ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED, + "libacl.so.1"); + + return dlopen_many_sym_or_warn( + &libacl_dl, + "libacl.so.1", + LOG_DEBUG, + DLSYM_ARG(acl_add_perm), + DLSYM_ARG(acl_calc_mask), + DLSYM_ARG(acl_copy_entry), + DLSYM_ARG(acl_create_entry), + DLSYM_ARG(acl_delete_entry), + DLSYM_ARG(acl_delete_perm), + DLSYM_ARG(acl_dup), + DLSYM_ARG(acl_entries), + DLSYM_ARG(acl_free), + DLSYM_ARG(acl_from_mode), + DLSYM_ARG(acl_from_text), + DLSYM_ARG(acl_get_entry), + DLSYM_ARG(acl_get_fd), + DLSYM_ARG(acl_get_file), + DLSYM_ARG(acl_get_perm), + DLSYM_ARG(acl_get_permset), + DLSYM_ARG(acl_get_qualifier), + DLSYM_ARG(acl_get_tag_type), + DLSYM_ARG(acl_init), + DLSYM_ARG(acl_set_fd), + DLSYM_ARG(acl_set_file), + DLSYM_ARG(acl_set_qualifier), + DLSYM_ARG(acl_set_tag_type), + DLSYM_ARG(acl_to_any_text)); +} int devnode_acl(int fd, uid_t uid) { bool changed = false, found = false; @@ -19,43 +82,47 @@ int devnode_acl(int fd, uid_t uid) { assert(fd >= 0); + r = dlopen_libacl(); + if (r < 0) + return r; + _cleanup_(acl_freep) acl_t acl = NULL; - acl = acl_get_file(FORMAT_PROC_FD_PATH(fd), ACL_TYPE_ACCESS); + acl = sym_acl_get_file(FORMAT_PROC_FD_PATH(fd), ACL_TYPE_ACCESS); if (!acl) return -errno; acl_entry_t entry; - for (r = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry); + for (r = sym_acl_get_entry(acl, ACL_FIRST_ENTRY, &entry); r > 0; - r = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry)) { + r = sym_acl_get_entry(acl, ACL_NEXT_ENTRY, &entry)) { acl_tag_t tag; - if (acl_get_tag_type(entry, &tag) < 0) + if (sym_acl_get_tag_type(entry, &tag) < 0) return -errno; if (tag != ACL_USER) continue; if (uid > 0) { - uid_t *u = acl_get_qualifier(entry); + uid_t *u = sym_acl_get_qualifier(entry); if (!u) return -errno; if (*u == uid) { acl_permset_t permset; - if (acl_get_permset(entry, &permset) < 0) + if (sym_acl_get_permset(entry, &permset) < 0) return -errno; - int rd = acl_get_perm(permset, ACL_READ); + int rd = sym_acl_get_perm(permset, ACL_READ); if (rd < 0) return -errno; - int wt = acl_get_perm(permset, ACL_WRITE); + int wt = sym_acl_get_perm(permset, ACL_WRITE); if (wt < 0) return -errno; if (!rd || !wt) { - if (acl_add_perm(permset, ACL_READ|ACL_WRITE) < 0) + if (sym_acl_add_perm(permset, ACL_READ|ACL_WRITE) < 0) return -errno; changed = true; @@ -66,7 +133,7 @@ int devnode_acl(int fd, uid_t uid) { } } - if (acl_delete_entry(acl, entry) < 0) + if (sym_acl_delete_entry(acl, entry) < 0) return -errno; changed = true; @@ -75,20 +142,20 @@ int devnode_acl(int fd, uid_t uid) { return -errno; if (!found && uid > 0) { - if (acl_create_entry(&acl, &entry) < 0) + if (sym_acl_create_entry(&acl, &entry) < 0) return -errno; - if (acl_set_tag_type(entry, ACL_USER) < 0) + if (sym_acl_set_tag_type(entry, ACL_USER) < 0) return -errno; - if (acl_set_qualifier(entry, &uid) < 0) + if (sym_acl_set_qualifier(entry, &uid) < 0) return -errno; acl_permset_t permset; - if (acl_get_permset(entry, &permset) < 0) + if (sym_acl_get_permset(entry, &permset) < 0) return -errno; - if (acl_add_perm(permset, ACL_READ|ACL_WRITE) < 0) + if (sym_acl_add_perm(permset, ACL_READ|ACL_WRITE) < 0) return -errno; changed = true; @@ -97,10 +164,10 @@ int devnode_acl(int fd, uid_t uid) { if (!changed) return 0; - if (acl_calc_mask(&acl) < 0) + if (sym_acl_calc_mask(&acl) < 0) return -errno; - if (acl_set_file(FORMAT_PROC_FD_PATH(fd), ACL_TYPE_ACCESS, acl) < 0) + if (sym_acl_set_file(FORMAT_PROC_FD_PATH(fd), ACL_TYPE_ACCESS, acl) < 0) return -errno; return 0; @@ -114,27 +181,25 @@ static int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *ret_entry) { assert(uid_is_valid(uid)); assert(ret_entry); - for (r = acl_get_entry(acl, ACL_FIRST_ENTRY, &i); + for (r = sym_acl_get_entry(acl, ACL_FIRST_ENTRY, &i); r > 0; - r = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) { + r = sym_acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) { acl_tag_t tag; - uid_t *u; bool b; - if (acl_get_tag_type(i, &tag) < 0) + if (sym_acl_get_tag_type(i, &tag) < 0) return -errno; if (tag != ACL_USER) continue; - u = acl_get_qualifier(i); + _cleanup_(acl_free_uid_tpp) uid_t *u = NULL; + u = sym_acl_get_qualifier(i); if (!u) return -errno; b = *u == uid; - acl_free(u); - if (b) { *ret_entry = i; return 1; @@ -154,12 +219,12 @@ int calc_acl_mask_if_needed(acl_t *acl_p) { assert(acl_p); - for (r = acl_get_entry(*acl_p, ACL_FIRST_ENTRY, &i); + for (r = sym_acl_get_entry(*acl_p, ACL_FIRST_ENTRY, &i); r > 0; - r = acl_get_entry(*acl_p, ACL_NEXT_ENTRY, &i)) { + r = sym_acl_get_entry(*acl_p, ACL_NEXT_ENTRY, &i)) { acl_tag_t tag; - if (acl_get_tag_type(i, &tag) < 0) + if (sym_acl_get_tag_type(i, &tag) < 0) return -errno; if (tag == ACL_MASK) @@ -171,7 +236,7 @@ int calc_acl_mask_if_needed(acl_t *acl_p) { if (r < 0) return -errno; - if (need && acl_calc_mask(acl_p) < 0) + if (need && sym_acl_calc_mask(acl_p) < 0) return -errno; return need; @@ -187,12 +252,12 @@ int add_base_acls_if_needed(acl_t *acl_p, const char *path) { assert(acl_p); assert(path); - for (r = acl_get_entry(*acl_p, ACL_FIRST_ENTRY, &i); + for (r = sym_acl_get_entry(*acl_p, ACL_FIRST_ENTRY, &i); r > 0; - r = acl_get_entry(*acl_p, ACL_NEXT_ENTRY, &i)) { + r = sym_acl_get_entry(*acl_p, ACL_NEXT_ENTRY, &i)) { acl_tag_t tag; - if (acl_get_tag_type(i, &tag) < 0) + if (sym_acl_get_tag_type(i, &tag) < 0) return -errno; if (tag == ACL_USER_OBJ) @@ -207,21 +272,20 @@ int add_base_acls_if_needed(acl_t *acl_p, const char *path) { if (r < 0) return -errno; - r = stat(path, &st); - if (r < 0) + if (stat(path, &st) < 0) return -errno; - basic = acl_from_mode(st.st_mode); + basic = sym_acl_from_mode(st.st_mode); if (!basic) return -errno; - for (r = acl_get_entry(basic, ACL_FIRST_ENTRY, &i); + for (r = sym_acl_get_entry(basic, ACL_FIRST_ENTRY, &i); r > 0; - r = acl_get_entry(basic, ACL_NEXT_ENTRY, &i)) { + r = sym_acl_get_entry(basic, ACL_NEXT_ENTRY, &i)) { acl_tag_t tag; acl_entry_t dst; - if (acl_get_tag_type(i, &tag) < 0) + if (sym_acl_get_tag_type(i, &tag) < 0) return -errno; if ((tag == ACL_USER_OBJ && have_user_obj) || @@ -229,11 +293,11 @@ int add_base_acls_if_needed(acl_t *acl_p, const char *path) { (tag == ACL_OTHER && have_other)) continue; - r = acl_create_entry(acl_p, &dst); + r = sym_acl_create_entry(acl_p, &dst); if (r < 0) return -errno; - r = acl_copy_entry(dst, i); + r = sym_acl_copy_entry(dst, i); if (r < 0) return -errno; } @@ -251,11 +315,15 @@ int acl_search_groups(const char *path, char ***ret_groups) { assert(path); - acl = acl_get_file(path, ACL_TYPE_DEFAULT); + r = dlopen_libacl(); + if (r < 0) + return r; + + acl = sym_acl_get_file(path, ACL_TYPE_DEFAULT); if (!acl) return -errno; - r = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry); + r = sym_acl_get_entry(acl, ACL_FIRST_ENTRY, &entry); for (;;) { _cleanup_(acl_free_gid_tpp) gid_t *gid = NULL; acl_tag_t tag; @@ -265,13 +333,13 @@ int acl_search_groups(const char *path, char ***ret_groups) { if (r == 0) break; - if (acl_get_tag_type(entry, &tag) < 0) + if (sym_acl_get_tag_type(entry, &tag) < 0) return -errno; if (tag != ACL_GROUP) goto next; - gid = acl_get_qualifier(entry); + gid = sym_acl_get_qualifier(entry); if (!gid) return -errno; @@ -295,7 +363,7 @@ int acl_search_groups(const char *path, char ***ret_groups) { } next: - r = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry); + r = sym_acl_get_entry(acl, ACL_NEXT_ENTRY, &entry); } if (ret_groups) @@ -324,6 +392,10 @@ int parse_acl( if (!split) return -ENOMEM; + r = dlopen_libacl(); + if (r < 0) + return r; + STRV_FOREACH(entry, split) { _cleanup_strv_free_ char **entry_split = NULL; _cleanup_free_ char *entry_join = NULL; @@ -368,7 +440,7 @@ int parse_acl( if (!join) return -ENOMEM; - a_acl = acl_from_text(join); + a_acl = sym_acl_from_text(join); if (!a_acl) return -errno; @@ -386,7 +458,7 @@ int parse_acl( if (!join) return -ENOMEM; - e_acl = acl_from_text(join); + e_acl = sym_acl_from_text(join); if (!e_acl) return -errno; @@ -400,7 +472,7 @@ int parse_acl( if (!join) return -ENOMEM; - d_acl = acl_from_text(join); + d_acl = sym_acl_from_text(join); if (!d_acl) return -errno; @@ -421,10 +493,10 @@ int parse_acl( static int acl_entry_equal(acl_entry_t a, acl_entry_t b) { acl_tag_t tag_a, tag_b; - if (acl_get_tag_type(a, &tag_a) < 0) + if (sym_acl_get_tag_type(a, &tag_a) < 0) return -errno; - if (acl_get_tag_type(b, &tag_b) < 0) + if (sym_acl_get_tag_type(b, &tag_b) < 0) return -errno; if (tag_a != tag_b) @@ -440,11 +512,11 @@ static int acl_entry_equal(acl_entry_t a, acl_entry_t b) { case ACL_USER: { _cleanup_(acl_free_uid_tpp) uid_t *uid_a = NULL, *uid_b = NULL; - uid_a = acl_get_qualifier(a); + uid_a = sym_acl_get_qualifier(a); if (!uid_a) return -errno; - uid_b = acl_get_qualifier(b); + uid_b = sym_acl_get_qualifier(b); if (!uid_b) return -errno; @@ -453,11 +525,11 @@ static int acl_entry_equal(acl_entry_t a, acl_entry_t b) { case ACL_GROUP: { _cleanup_(acl_free_gid_tpp) gid_t *gid_a = NULL, *gid_b = NULL; - gid_a = acl_get_qualifier(a); + gid_a = sym_acl_get_qualifier(a); if (!gid_a) return -errno; - gid_b = acl_get_qualifier(b); + gid_b = sym_acl_get_qualifier(b); if (!gid_b) return -errno; @@ -472,9 +544,9 @@ static int find_acl_entry(acl_t acl, acl_entry_t entry, acl_entry_t *ret) { acl_entry_t i; int r; - for (r = acl_get_entry(acl, ACL_FIRST_ENTRY, &i); + for (r = sym_acl_get_entry(acl, ACL_FIRST_ENTRY, &i); r > 0; - r = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) { + r = sym_acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) { r = acl_entry_equal(i, entry); if (r < 0) @@ -498,24 +570,28 @@ int acls_for_file(const char *path, acl_type_t type, acl_t acl, acl_t *ret) { assert(path); - applied = acl_get_file(path, type); + r = dlopen_libacl(); + if (r < 0) + return r; + + applied = sym_acl_get_file(path, type); if (!applied) return -errno; - for (r = acl_get_entry(acl, ACL_FIRST_ENTRY, &i); + for (r = sym_acl_get_entry(acl, ACL_FIRST_ENTRY, &i); r > 0; - r = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) { + r = sym_acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) { acl_entry_t j; r = find_acl_entry(applied, i, &j); if (r == -ENOENT) { - if (acl_create_entry(&applied, &j) < 0) + if (sym_acl_create_entry(&applied, &j) < 0) return -errno; } else if (r < 0) return r; - if (acl_copy_entry(j, i) < 0) + if (sym_acl_copy_entry(j, i) < 0) return -errno; } if (r < 0) @@ -553,33 +629,37 @@ int fd_add_uid_acl_permission( assert(fd >= 0); assert(uid_is_valid(uid)); - acl = acl_get_fd(fd); + r = dlopen_libacl(); + if (r < 0) + return r; + + acl = sym_acl_get_fd(fd); if (!acl) return -errno; r = acl_find_uid(acl, uid, &entry); if (r <= 0) { - if (acl_create_entry(&acl, &entry) < 0 || - acl_set_tag_type(entry, ACL_USER) < 0 || - acl_set_qualifier(entry, &uid) < 0) + if (sym_acl_create_entry(&acl, &entry) < 0 || + sym_acl_set_tag_type(entry, ACL_USER) < 0 || + sym_acl_set_qualifier(entry, &uid) < 0) return -errno; } - if (acl_get_permset(entry, &permset) < 0) + if (sym_acl_get_permset(entry, &permset) < 0) return -errno; - if ((mask & ACL_READ) && acl_add_perm(permset, ACL_READ) < 0) + if ((mask & ACL_READ) && sym_acl_add_perm(permset, ACL_READ) < 0) return -errno; - if ((mask & ACL_WRITE) && acl_add_perm(permset, ACL_WRITE) < 0) + if ((mask & ACL_WRITE) && sym_acl_add_perm(permset, ACL_WRITE) < 0) return -errno; - if ((mask & ACL_EXECUTE) && acl_add_perm(permset, ACL_EXECUTE) < 0) + if ((mask & ACL_EXECUTE) && sym_acl_add_perm(permset, ACL_EXECUTE) < 0) return -errno; r = calc_acl_mask_if_needed(&acl); if (r < 0) return r; - if (acl_set_fd(fd, acl) < 0) + if (sym_acl_set_fd(fd, acl) < 0) return -errno; return 0; @@ -596,7 +676,11 @@ int fd_acl_make_read_only(int fd) { /* Safely drops all W bits from all relevant ACL entries of the file, without changing entries which * are masked by the ACL mask */ - acl = acl_get_fd(fd); + r = dlopen_libacl(); + if (r < 0) + return r; + + acl = sym_acl_get_fd(fd); if (!acl) { if (!ERRNO_IS_NOT_SUPPORTED(errno)) @@ -606,29 +690,29 @@ int fd_acl_make_read_only(int fd) { return fd_acl_make_read_only_fallback(fd); } - for (r = acl_get_entry(acl, ACL_FIRST_ENTRY, &i); + for (r = sym_acl_get_entry(acl, ACL_FIRST_ENTRY, &i); r > 0; - r = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) { + r = sym_acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) { acl_permset_t permset; acl_tag_t tag; int b; - if (acl_get_tag_type(i, &tag) < 0) + if (sym_acl_get_tag_type(i, &tag) < 0) return -errno; /* These three control the x bits overall (as ACL_MASK affects all remaining tags) */ if (!IN_SET(tag, ACL_USER_OBJ, ACL_MASK, ACL_OTHER)) continue; - if (acl_get_permset(i, &permset) < 0) + if (sym_acl_get_permset(i, &permset) < 0) return -errno; - b = acl_get_perm(permset, ACL_WRITE); + b = sym_acl_get_perm(permset, ACL_WRITE); if (b < 0) return -errno; if (b) { - if (acl_delete_perm(permset, ACL_WRITE) < 0) + if (sym_acl_delete_perm(permset, ACL_WRITE) < 0) return -errno; changed = true; @@ -640,7 +724,7 @@ int fd_acl_make_read_only(int fd) { if (!changed) return 0; - if (acl_set_fd(fd, acl) < 0) { + if (sym_acl_set_fd(fd, acl) < 0) { if (!ERRNO_IS_NOT_SUPPORTED(errno)) return -errno; @@ -658,7 +742,11 @@ int fd_acl_make_writable(int fd) { /* Safely adds the writable bit to the owner's ACL entry of this inode. (And only the owner's! – This * not the obvious inverse of fd_acl_make_read_only() hence!) */ - acl = acl_get_fd(fd); + r = dlopen_libacl(); + if (r < 0) + return r; + + acl = sym_acl_get_fd(fd); if (!acl) { if (!ERRNO_IS_NOT_SUPPORTED(errno)) return -errno; @@ -667,30 +755,30 @@ int fd_acl_make_writable(int fd) { return fd_acl_make_writable_fallback(fd); } - for (r = acl_get_entry(acl, ACL_FIRST_ENTRY, &i); + for (r = sym_acl_get_entry(acl, ACL_FIRST_ENTRY, &i); r > 0; - r = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) { + r = sym_acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) { acl_permset_t permset; acl_tag_t tag; int b; - if (acl_get_tag_type(i, &tag) < 0) + if (sym_acl_get_tag_type(i, &tag) < 0) return -errno; if (tag != ACL_USER_OBJ) continue; - if (acl_get_permset(i, &permset) < 0) + if (sym_acl_get_permset(i, &permset) < 0) return -errno; - b = acl_get_perm(permset, ACL_WRITE); + b = sym_acl_get_perm(permset, ACL_WRITE); if (b < 0) return -errno; if (b) return 0; /* Already set? Then there's nothing to do. */ - if (acl_add_perm(permset, ACL_WRITE) < 0) + if (sym_acl_add_perm(permset, ACL_WRITE) < 0) return -errno; break; @@ -698,7 +786,7 @@ int fd_acl_make_writable(int fd) { if (r < 0) return -errno; - if (acl_set_fd(fd, acl) < 0) { + if (sym_acl_set_fd(fd, acl) < 0) { if (!ERRNO_IS_NOT_SUPPORTED(errno)) return -errno; diff --git a/src/shared/acl-util.h b/src/shared/acl-util.h index 3e23fe3938..54eba92f38 100644 --- a/src/shared/acl-util.h +++ b/src/shared/acl-util.h @@ -10,6 +10,35 @@ int fd_acl_make_writable_fallback(int fd); #include /* IWYU pragma: export */ #include /* IWYU pragma: export */ +#include "dlfcn-util.h" + +extern DLSYM_PROTOTYPE(acl_add_perm); +extern DLSYM_PROTOTYPE(acl_calc_mask); +extern DLSYM_PROTOTYPE(acl_copy_entry); +extern DLSYM_PROTOTYPE(acl_create_entry); +extern DLSYM_PROTOTYPE(acl_delete_entry); +extern DLSYM_PROTOTYPE(acl_delete_perm); +extern DLSYM_PROTOTYPE(acl_dup); +extern DLSYM_PROTOTYPE(acl_entries); +extern DLSYM_PROTOTYPE(acl_free); +extern DLSYM_PROTOTYPE(acl_from_mode); +extern DLSYM_PROTOTYPE(acl_from_text); +extern DLSYM_PROTOTYPE(acl_get_entry); +extern DLSYM_PROTOTYPE(acl_get_fd); +extern DLSYM_PROTOTYPE(acl_get_file); +extern DLSYM_PROTOTYPE(acl_get_perm); +extern DLSYM_PROTOTYPE(acl_get_permset); +extern DLSYM_PROTOTYPE(acl_get_qualifier); +extern DLSYM_PROTOTYPE(acl_get_tag_type); +extern DLSYM_PROTOTYPE(acl_init); +extern DLSYM_PROTOTYPE(acl_set_fd); +extern DLSYM_PROTOTYPE(acl_set_file); +extern DLSYM_PROTOTYPE(acl_set_qualifier); +extern DLSYM_PROTOTYPE(acl_set_tag_type); +extern DLSYM_PROTOTYPE(acl_to_any_text); + +int dlopen_libacl(void); + int devnode_acl(int fd, uid_t uid); int calc_acl_mask_if_needed(acl_t *acl_p); @@ -27,21 +56,22 @@ int fd_add_uid_acl_permission(int fd, uid_t uid, unsigned mask); int fd_acl_make_read_only(int fd); int fd_acl_make_writable(int fd); -/* acl_free takes multiple argument types. - * Multiple cleanup functions are necessary. */ -DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(acl_t, acl_free, NULL); -#define acl_free_charp acl_free -DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(char*, acl_free_charp, NULL); -#define acl_free_uid_tp acl_free -DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(uid_t*, acl_free_uid_tp, NULL); -#define acl_free_gid_tp acl_free -DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(gid_t*, acl_free_gid_tp, NULL); +/* acl_free() takes multiple argument types. Multiple cleanup functions are necessary. */ +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(acl_t, sym_acl_free, acl_freep, NULL); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(char*, sym_acl_free, acl_free_charpp, NULL); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(uid_t*, sym_acl_free, acl_free_uid_tpp, NULL); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(gid_t*, sym_acl_free, acl_free_gid_tpp, NULL); #else + #define ACL_READ 0x04 #define ACL_WRITE 0x02 #define ACL_EXECUTE 0x01 +static inline int dlopen_libacl(void) { + return -EOPNOTSUPP; +} + static inline int devnode_acl(int fd, uid_t uid) { return -EOPNOTSUPP; } @@ -57,7 +87,6 @@ static inline int fd_acl_make_read_only(int fd) { static inline int fd_acl_make_writable(int fd) { return fd_acl_make_writable_fallback(fd); } - #endif int inode_type_can_acl(mode_t mode); diff --git a/src/shared/meson.build b/src/shared/meson.build index 4b84dd9cea..a734c86891 100644 --- a/src/shared/meson.build +++ b/src/shared/meson.build @@ -312,7 +312,7 @@ man_page_depends += ethtool_link_mode_xml libshared_name = 'systemd-shared-@0@'.format(shared_lib_tag) libshared_deps = [threads, - libacl, + libacl_cflags, libaudit_cflags, libblkid, libcap, diff --git a/src/shared/shift-uid.c b/src/shared/shift-uid.c index 2f34908fff..f0353f2391 100644 --- a/src/shared/shift-uid.c +++ b/src/shared/shift-uid.c @@ -7,6 +7,7 @@ #include "acl-util.h" #include "alloc-util.h" #include "dirent-util.h" +#include "errno-util.h" #include "fd-util.h" #include "fileio.h" #include "fs-util.h" @@ -36,11 +37,11 @@ static int get_acl(int fd, const char *name, acl_type_t type, acl_t *ret) { if (child_fd < 0) return -errno; - acl = acl_get_file(FORMAT_PROC_FD_PATH(child_fd), type); + acl = sym_acl_get_file(FORMAT_PROC_FD_PATH(child_fd), type); } else if (type == ACL_TYPE_ACCESS) - acl = acl_get_fd(fd); + acl = sym_acl_get_fd(fd); else - acl = acl_get_file(FORMAT_PROC_FD_PATH(fd), type); + acl = sym_acl_get_file(FORMAT_PROC_FD_PATH(fd), type); if (!acl) return -errno; @@ -61,11 +62,11 @@ static int set_acl(int fd, const char *name, acl_type_t type, acl_t acl) { if (child_fd < 0) return -errno; - r = acl_set_file(FORMAT_PROC_FD_PATH(child_fd), type, acl); + r = sym_acl_set_file(FORMAT_PROC_FD_PATH(child_fd), type, acl); } else if (type == ACL_TYPE_ACCESS) - r = acl_set_fd(fd, acl); + r = sym_acl_set_fd(fd, acl); else - r = acl_set_file(FORMAT_PROC_FD_PATH(fd), type, acl); + r = sym_acl_set_file(FORMAT_PROC_FD_PATH(fd), type, acl); if (r < 0) return -errno; @@ -80,7 +81,7 @@ static int shift_acl(acl_t acl, uid_t shift, acl_t *ret) { assert(acl); assert(ret); - r = acl_get_entry(acl, ACL_FIRST_ENTRY, &i); + r = sym_acl_get_entry(acl, ACL_FIRST_ENTRY, &i); if (r < 0) return -errno; while (r > 0) { @@ -88,7 +89,7 @@ static int shift_acl(acl_t acl, uid_t shift, acl_t *ret) { bool modify = false; acl_tag_t tag; - if (acl_get_tag_type(i, &tag) < 0) + if (sym_acl_get_tag_type(i, &tag) < 0) return -errno; if (IN_SET(tag, ACL_USER, ACL_GROUP)) { @@ -97,7 +98,7 @@ static int shift_acl(acl_t acl, uid_t shift, acl_t *ret) { * this is actually OK */ assert_cc(sizeof(uid_t) == sizeof(gid_t)); - old_uid = acl_get_qualifier(i); + old_uid = sym_acl_get_qualifier(i); if (!old_uid) return -errno; @@ -112,16 +113,16 @@ static int shift_acl(acl_t acl, uid_t shift, acl_t *ret) { /* There's no copy of the ACL yet? if so, let's create one, and start the loop from the * beginning, so that we copy all entries, starting from the first, this time. */ - n = acl_entries(acl); + n = sym_acl_entries(acl); if (n < 0) return -errno; - copy = acl_init(n); + copy = sym_acl_init(n); if (!copy) return -errno; /* Seek back to the beginning */ - r = acl_get_entry(acl, ACL_FIRST_ENTRY, &i); + r = sym_acl_get_entry(acl, ACL_FIRST_ENTRY, &i); if (r < 0) return -errno; continue; @@ -131,18 +132,18 @@ static int shift_acl(acl_t acl, uid_t shift, acl_t *ret) { if (copy) { acl_entry_t new_entry; - if (acl_create_entry(©, &new_entry) < 0) + if (sym_acl_create_entry(©, &new_entry) < 0) return -errno; - if (acl_copy_entry(new_entry, i) < 0) + if (sym_acl_copy_entry(new_entry, i) < 0) return -errno; if (modify) - if (acl_set_qualifier(new_entry, &new_uid) < 0) + if (sym_acl_set_qualifier(new_entry, &new_uid) < 0) return -errno; } - r = acl_get_entry(acl, ACL_NEXT_ENTRY, &i); + r = sym_acl_get_entry(acl, ACL_NEXT_ENTRY, &i); if (r < 0) return -errno; } @@ -164,6 +165,12 @@ static int patch_acls(int fd, const char *name, const struct stat *st, uid_t shi if (!inode_type_can_acl(st->st_mode)) return 0; + r = dlopen_libacl(); + if (ERRNO_IS_NEG_NOT_SUPPORTED(r)) + return 0; + if (r < 0) + return r; + r = get_acl(fd, name, ACL_TYPE_ACCESS, &acl); if (r == -EOPNOTSUPP) return 0; @@ -182,10 +189,10 @@ static int patch_acls(int fd, const char *name, const struct stat *st, uid_t shi } if (S_ISDIR(st->st_mode)) { - acl_free(acl); + sym_acl_free(acl); if (shifted) - acl_free(shifted); + sym_acl_free(shifted); acl = shifted = NULL; diff --git a/src/test/test-dlopen-so.c b/src/test/test-dlopen-so.c index ada19fdc66..817ddde202 100644 --- a/src/test/test-dlopen-so.c +++ b/src/test/test-dlopen-so.c @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include "acl-util.h" #include "apparmor-util.h" #include "bpf-dlopen.h" #include "compress.h" @@ -52,6 +53,7 @@ static int run(int argc, char **argv) { ASSERT_DLOPEN(dlopen_libapparmor, HAVE_APPARMOR); ASSERT_DLOPEN(dlopen_libaudit, HAVE_AUDIT); ASSERT_DLOPEN(dlopen_libpam, HAVE_PAM); + ASSERT_DLOPEN(dlopen_libacl, HAVE_ACL); return 0; } diff --git a/src/tmpfiles/meson.build b/src/tmpfiles/meson.build index a973d16f5c..2e26d7b0dc 100644 --- a/src/tmpfiles/meson.build +++ b/src/tmpfiles/meson.build @@ -17,7 +17,7 @@ executables += [ 'public' : true, 'sources' : systemd_tmpfiles_sources + systemd_tmpfiles_extract_sources, 'extract' : systemd_tmpfiles_extract_sources, - 'dependencies' : libacl, + 'dependencies' : libacl_cflags, }, executable_template + { 'name' : 'systemd-tmpfiles.standalone', @@ -30,7 +30,7 @@ executables += [ libshared_static, libsystemd_static, ], - 'dependencies' : libacl, + 'dependencies' : libacl_cflags, }, test_template + { 'sources' : files('test-offline-passwd.c'), diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 42d67deebf..981c6a5198 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -1271,22 +1271,26 @@ static int parse_acl_cond_exec( assert(cond_exec); assert(ret); + r = dlopen_libacl(); + if (r < 0) + return r; + if (!S_ISDIR(st->st_mode)) { _cleanup_(acl_freep) acl_t old = NULL; - old = acl_get_file(path, ACL_TYPE_ACCESS); + old = sym_acl_get_file(path, ACL_TYPE_ACCESS); if (!old) return -errno; has_exec = false; - for (r = acl_get_entry(old, ACL_FIRST_ENTRY, &entry); + for (r = sym_acl_get_entry(old, ACL_FIRST_ENTRY, &entry); r > 0; - r = acl_get_entry(old, ACL_NEXT_ENTRY, &entry)) { + r = sym_acl_get_entry(old, ACL_NEXT_ENTRY, &entry)) { acl_tag_t tag; - if (acl_get_tag_type(entry, &tag) < 0) + if (sym_acl_get_tag_type(entry, &tag) < 0) return -errno; if (tag == ACL_MASK) @@ -1296,10 +1300,10 @@ static int parse_acl_cond_exec( if (!append && IN_SET(tag, ACL_USER, ACL_GROUP)) continue; - if (acl_get_permset(entry, &permset) < 0) + if (sym_acl_get_permset(entry, &permset) < 0) return -errno; - r = acl_get_perm(permset, ACL_EXECUTE); + r = sym_acl_get_perm(permset, ACL_EXECUTE); if (r < 0) return -errno; if (r > 0) { @@ -1312,14 +1316,14 @@ static int parse_acl_cond_exec( /* Check if we're about to set the execute bit in acl_access */ if (!has_exec && access) { - for (r = acl_get_entry(access, ACL_FIRST_ENTRY, &entry); + for (r = sym_acl_get_entry(access, ACL_FIRST_ENTRY, &entry); r > 0; - r = acl_get_entry(access, ACL_NEXT_ENTRY, &entry)) { + r = sym_acl_get_entry(access, ACL_NEXT_ENTRY, &entry)) { - if (acl_get_permset(entry, &permset) < 0) + if (sym_acl_get_permset(entry, &permset) < 0) return -errno; - r = acl_get_perm(permset, ACL_EXECUTE); + r = sym_acl_get_perm(permset, ACL_EXECUTE); if (r < 0) return -errno; if (r > 0) { @@ -1333,28 +1337,28 @@ static int parse_acl_cond_exec( } else has_exec = true; - _cleanup_(acl_freep) acl_t parsed = access ? acl_dup(access) : acl_init(0); + _cleanup_(acl_freep) acl_t parsed = access ? sym_acl_dup(access) : sym_acl_init(0); if (!parsed) return -errno; - for (r = acl_get_entry(cond_exec, ACL_FIRST_ENTRY, &entry); + for (r = sym_acl_get_entry(cond_exec, ACL_FIRST_ENTRY, &entry); r > 0; - r = acl_get_entry(cond_exec, ACL_NEXT_ENTRY, &entry)) { + r = sym_acl_get_entry(cond_exec, ACL_NEXT_ENTRY, &entry)) { acl_entry_t parsed_entry; - if (acl_create_entry(&parsed, &parsed_entry) < 0) + if (sym_acl_create_entry(&parsed, &parsed_entry) < 0) return -errno; - if (acl_copy_entry(parsed_entry, entry) < 0) + if (sym_acl_copy_entry(parsed_entry, entry) < 0) return -errno; /* We substituted 'X' with 'x' in parse_acl(), so drop execute bit here if not applicable. */ if (!has_exec) { - if (acl_get_permset(parsed_entry, &permset) < 0) + if (sym_acl_get_permset(parsed_entry, &permset) < 0) return -errno; - if (acl_delete_perm(permset, ACL_EXECUTE) < 0) + if (sym_acl_delete_perm(permset, ACL_EXECUTE) < 0) return -errno; } } @@ -1386,6 +1390,10 @@ static int path_set_acl( assert(c); + r = dlopen_libacl(); + if (r < 0) + return r; + /* Returns 0 for success, positive error if already warned, negative error otherwise. */ if (modify) { @@ -1397,7 +1405,7 @@ static int path_set_acl( if (r < 0) return r; } else { - dup = acl_dup(acl); + dup = sym_acl_dup(acl); if (!dup) return -errno; @@ -1408,14 +1416,14 @@ static int path_set_acl( if (r < 0) return r; - t = acl_to_any_text(dup, NULL, ',', TEXT_ABBREVIATE); + t = sym_acl_to_any_text(dup, NULL, ',', TEXT_ABBREVIATE); log_action("Would set", "Setting", "%s %s ACL %s on %s", type == ACL_TYPE_ACCESS ? "access" : "default", strna(t), pretty); if (!arg_dry_run && - acl_set_file(path, type, dup) < 0) { + sym_acl_set_file(path, type, dup) < 0) { if (ERRNO_IS_NOT_SUPPORTED(errno)) /* No error if filesystem doesn't support ACLs. Return negative. */ return -errno; @@ -3295,13 +3303,13 @@ static void item_free_contents(Item *i) { #if HAVE_ACL if (i->acl_access) - acl_free(i->acl_access); + sym_acl_free(i->acl_access); if (i->acl_access_exec) - acl_free(i->acl_access_exec); + sym_acl_free(i->acl_access_exec); if (i->acl_default) - acl_free(i->acl_default); + sym_acl_free(i->acl_default); #endif } diff --git a/src/udev/meson.build b/src/udev/meson.build index 908bec8b1d..b13b5d8979 100644 --- a/src/udev/meson.build +++ b/src/udev/meson.build @@ -114,7 +114,7 @@ endif ############################################################ udev_dependencies = [ - libacl, + libacl_cflags, libblkid, libkmod, threads, @@ -131,7 +131,7 @@ udev_plugin_template = executable_template + { udev_common_template = { 'objects' : ['udevadm'], 'dependencies' : [ - libacl, + libacl_cflags, libblkid, threads, ],