diff options
-rw-r--r-- | man/tmpfiles.d.xml | 20 | ||||
-rw-r--r-- | src/shared/acl-util.c | 102 | ||||
-rw-r--r-- | src/shared/acl-util.h | 1 | ||||
-rw-r--r-- | src/tmpfiles/tmpfiles.c | 25 |
4 files changed, 112 insertions, 36 deletions
diff --git a/man/tmpfiles.d.xml b/man/tmpfiles.d.xml index 957910dd6d..8815bf9970 100644 --- a/man/tmpfiles.d.xml +++ b/man/tmpfiles.d.xml @@ -306,16 +306,16 @@ <term><varname>a</varname></term> <term><varname>a+</varname></term> <listitem><para>Set POSIX ACLs (access control lists). If - suffixed with <varname>+</varname>, specified mask will be - added to existing - entries. <command>systemd-tmpfiles</command> does not - automatically add the required base entries for user and - group to the specified mask, so they must be specified - explicitly if <varname>+</varname> is not used. The - mask will be added if not specified explicitly. - Lines of this type accept shell-style globs in place - of normal path names. This can be useful for allowing - additional access to certain files. </para></listitem> + suffixed with <varname>+</varname>, specified entries will + be added to the existing set. + <command>systemd-tmpfiles</command> will automatically add + the required base entries for user and group based on the + access mode of the file, unless base entries already exist + or are explictly specified. The mask will be added if not + specified explicitly or already present. Lines of this type + accept shell-style globs in place of normal path names. This + can be useful for allowing additional access to certain + files.</para></listitem> </varlistentry> <varlistentry> diff --git a/src/shared/acl-util.c b/src/shared/acl-util.c index 950f472ddd..a4ff1ab878 100644 --- a/src/shared/acl-util.c +++ b/src/shared/acl-util.c @@ -29,14 +29,14 @@ int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *entry) { acl_entry_t i; - int found; + int r; assert(acl); assert(entry); - for (found = acl_get_entry(acl, ACL_FIRST_ENTRY, &i); - found > 0; - found = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) { + for (r = acl_get_entry(acl, ACL_FIRST_ENTRY, &i); + r > 0; + r = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) { acl_tag_t tag; uid_t *u; @@ -60,8 +60,7 @@ int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *entry) { return 1; } } - - if (found < 0) + if (r < 0) return -errno; return 0; @@ -69,14 +68,13 @@ int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *entry) { int calc_acl_mask_if_needed(acl_t *acl_p) { acl_entry_t i; - int found; + int r; assert(acl_p); - for (found = acl_get_entry(*acl_p, ACL_FIRST_ENTRY, &i); - found > 0; - found = acl_get_entry(*acl_p, ACL_NEXT_ENTRY, &i)) { - + for (r = acl_get_entry(*acl_p, ACL_FIRST_ENTRY, &i); + r > 0; + r = acl_get_entry(*acl_p, ACL_NEXT_ENTRY, &i)) { acl_tag_t tag; if (acl_get_tag_type(i, &tag) < 0) @@ -84,14 +82,80 @@ int calc_acl_mask_if_needed(acl_t *acl_p) { if (tag == ACL_MASK) return 0; + if (IN_SET(tag, ACL_USER, ACL_GROUP)) + goto calc; } - - if (found < 0) + if (r < 0) return -errno; + return 0; +calc: if (acl_calc_mask(acl_p) < 0) return -errno; + return 1; +} + +int add_base_acls_if_needed(acl_t *acl_p, const char *path) { + acl_entry_t i; + int r; + bool have_user_obj = false, have_group_obj = false, have_other = false; + struct stat st; + _cleanup_(acl_freep) acl_t basic = NULL; + + assert(acl_p); + + for (r = acl_get_entry(*acl_p, ACL_FIRST_ENTRY, &i); + r > 0; + r = acl_get_entry(*acl_p, ACL_NEXT_ENTRY, &i)) { + acl_tag_t tag; + + if (acl_get_tag_type(i, &tag) < 0) + return -errno; + + if (tag == ACL_USER_OBJ) + have_user_obj = true; + else if (tag == ACL_GROUP_OBJ) + have_group_obj = true; + else if (tag == ACL_OTHER) + have_other = true; + if (have_user_obj && have_group_obj && have_other) + return 0; + } + if (r < 0) + return -errno; + r = stat(path, &st); + if (r < 0) + return -errno; + + basic = acl_from_mode(st.st_mode); + if (!basic) + return -errno; + + for (r = acl_get_entry(basic, ACL_FIRST_ENTRY, &i); + r > 0; + r = acl_get_entry(basic, ACL_NEXT_ENTRY, &i)) { + acl_tag_t tag; + acl_entry_t dst; + + if (acl_get_tag_type(i, &tag) < 0) + return -errno; + + if ((tag == ACL_USER_OBJ && have_user_obj) || + (tag == ACL_GROUP_OBJ && have_group_obj) || + (tag == ACL_OTHER && have_other)) + continue; + + r = acl_create_entry(acl_p, &dst); + if (r < 0) + return -errno; + + r = acl_copy_entry(dst, i); + if (r < 0) + return -errno; + } + if (r < 0) + return -errno; return 0; } @@ -221,15 +285,15 @@ int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask) int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *acl) { _cleanup_(acl_freep) acl_t old; acl_entry_t i; - int found, r; + int r; old = acl_get_file(path, type); if (!old) return -errno; - for (found = acl_get_entry(new, ACL_FIRST_ENTRY, &i); - found > 0; - found = acl_get_entry(new, ACL_NEXT_ENTRY, &i)) { + for (r = acl_get_entry(new, ACL_FIRST_ENTRY, &i); + r > 0; + r = acl_get_entry(new, ACL_NEXT_ENTRY, &i)) { acl_entry_t j; @@ -239,10 +303,8 @@ int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *acl) { if (acl_copy_entry(j, i) < 0) return -errno; } - - r = calc_acl_mask_if_needed(&old); if (r < 0) - return r; + return -errno; *acl = old; old = NULL; diff --git a/src/shared/acl-util.h b/src/shared/acl-util.h index 1ad4a2ebc7..90e88ffa26 100644 --- a/src/shared/acl-util.h +++ b/src/shared/acl-util.h @@ -31,6 +31,7 @@ int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *entry); int calc_acl_mask_if_needed(acl_t *acl_p); +int add_base_acls_if_needed(acl_t *acl_p, const char *path); int search_acl_groups(char*** dst, const char* path, bool* belong); int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask); int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *acl); diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 3c8993e894..7edeeb7428 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -614,22 +614,35 @@ static int get_acls_from_arg(Item *item) { } static int path_set_acl(const char *path, acl_type_t type, acl_t acl, bool modify) { - _cleanup_(acl_freep) acl_t cleanme = NULL; + _cleanup_(acl_freep) acl_t dup = NULL; int r; if (modify) { - r = acls_for_file(path, type, acl, &cleanme); + r = acls_for_file(path, type, acl, &dup); if (r < 0) return r; - acl = cleanme; - }; - r = acl_set_file(path, type, acl); + r = calc_acl_mask_if_needed(&dup); + if (r < 0) + return r; + } else { + dup = acl_dup(acl); + if (!dup) + return -errno; + + /* the mask was already added earlier if needed */ + } + + r = add_base_acls_if_needed(&dup, path); + if (r < 0) + return r; + + r = acl_set_file(path, type, dup); if (r < 0) { _cleanup_(acl_free_charpp) char *t; r = -errno; - t = acl_to_any_text(acl, NULL, ',', TEXT_ABBREVIATE); + t = acl_to_any_text(dup, NULL, ',', TEXT_ABBREVIATE); log_error_errno(r, "Setting %s ACL \"%s\" on %s failed: %m", type == ACL_TYPE_ACCESS ? "access" : "default", |