diff options
author | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2015-01-18 05:02:47 -0500 |
---|---|---|
committer | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2015-01-22 01:14:53 -0500 |
commit | 50d9e46dbb8400d4570781728c63b151d9ca982b (patch) | |
tree | c628f4011aaa45315d20106f6f78eb74e127b8b9 /src | |
parent | b705ab6a838937f947216af7b2d1fffb00f8b0dc (diff) |
tmpfiles: implement augmenting of existing ACLs
This is much more useful in practice (equivalent to setfacl -m).
Diffstat (limited to 'src')
-rw-r--r-- | src/shared/acl-util.c | 49 | ||||
-rw-r--r-- | src/shared/acl-util.h | 3 | ||||
-rw-r--r-- | src/tmpfiles/tmpfiles.c | 54 |
3 files changed, 79 insertions, 27 deletions
diff --git a/src/shared/acl-util.c b/src/shared/acl-util.c index 22bb8444e5..950f472ddd 100644 --- a/src/shared/acl-util.c +++ b/src/shared/acl-util.c @@ -150,7 +150,7 @@ int search_acl_groups(char*** dst, const char* path, bool* belong) { return 0; } -int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default) { +int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask) { _cleanup_free_ char **a = NULL, **d = NULL; /* strings are not be freed */ _cleanup_strv_free_ char **split; char **entry; @@ -187,9 +187,11 @@ int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default) { if (!a_acl) return -EINVAL; - r = calc_acl_mask_if_needed(&a_acl); - if (r < 0) - return r; + if (want_mask) { + r = calc_acl_mask_if_needed(&a_acl); + if (r < 0) + return r; + } } if (!strv_isempty(d)) { @@ -203,9 +205,11 @@ int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default) { if (!d_acl) return -EINVAL; - r = calc_acl_mask_if_needed(&d_acl); - if (r < 0) - return r; + if (want_mask) { + r = calc_acl_mask_if_needed(&d_acl); + if (r < 0) + return r; + } } *acl_access = a_acl; @@ -213,3 +217,34 @@ int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default) { a_acl = d_acl = NULL; return 0; } + +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; + + 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)) { + + acl_entry_t j; + + if (acl_create_entry(&old, &j) < 0) + return -errno; + + if (acl_copy_entry(j, i) < 0) + return -errno; + } + + r = calc_acl_mask_if_needed(&old); + if (r < 0) + return r; + + *acl = old; + old = NULL; + return 0; +} diff --git a/src/shared/acl-util.h b/src/shared/acl-util.h index 4133214d25..1ad4a2ebc7 100644 --- a/src/shared/acl-util.h +++ b/src/shared/acl-util.h @@ -32,7 +32,8 @@ 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 search_acl_groups(char*** dst, const char* path, bool* belong); -int parse_acl(char *text, acl_t *acl_access, acl_t *acl_default); +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); /* acl_free takes multiple argument types. * Multiple cleanup functions are necessary. */ diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 44a087807e..3c8993e894 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -600,7 +600,9 @@ static int get_acls_from_arg(Item *item) { assert(item); - r = parse_acl(item->argument, &item->acl_access, &item->acl_default); + /* If force (= modify) is set, we will not modify the acl + * afterwards, so the mask can be added now if necessary. */ + r = parse_acl(item->argument, &item->acl_access, &item->acl_default, !item->force); if (r < 0) log_warning_errno(errno, "Failed to parse ACL \"%s\": %m. Ignoring", item->argument); @@ -611,6 +613,32 @@ static int get_acls_from_arg(Item *item) { return 0; } +static int path_set_acl(const char *path, acl_type_t type, acl_t acl, bool modify) { + _cleanup_(acl_freep) acl_t cleanme = NULL; + int r; + + if (modify) { + r = acls_for_file(path, type, acl, &cleanme); + if (r < 0) + return r; + acl = cleanme; + }; + + r = acl_set_file(path, type, acl); + if (r < 0) { + _cleanup_(acl_free_charpp) char *t; + + r = -errno; + t = acl_to_any_text(acl, NULL, ',', TEXT_ABBREVIATE); + log_error_errno(r, + "Setting %s ACL \"%s\" on %s failed: %m", + type == ACL_TYPE_ACCESS ? "access" : "default", + strna(t), path); + } + + return r; +} + static int path_set_acls(Item *item, const char *path) { #ifdef HAVE_ACL int r; @@ -619,27 +647,15 @@ static int path_set_acls(Item *item, const char *path) { assert(path); if (item->acl_access) { - r = acl_set_file(path, ACL_TYPE_ACCESS, item->acl_access); - if (r < 0) { - _cleanup_(acl_free_charpp) char *t; - - t = acl_to_any_text(item->acl_access, NULL, ',', TEXT_ABBREVIATE); - return log_error_errno(errno, - "Setting access ACL \"%s\" on %s failed: %m", - strna(t), path); - } + r = path_set_acl(path, ACL_TYPE_ACCESS, item->acl_access, item->force); + if (r < 0) + return r; } if (item->acl_default) { - r = acl_set_file(path, ACL_TYPE_DEFAULT, item->acl_default); - if (r < 0) { - _cleanup_(acl_free_charpp) char *t; - - t = acl_to_any_text(item->acl_default, NULL, ',', TEXT_ABBREVIATE); - return log_error_errno(errno, - "Setting default ACL \"%s\" on %s failed: %m", - strna(t), path); - } + r = path_set_acl(path, ACL_TYPE_DEFAULT, item->acl_default, item->force); + if (r < 0) + return r; } #endif |