diff options
Diffstat (limited to 'src/shared')
-rw-r--r-- | src/shared/acl-util.c | 68 | ||||
-rw-r--r-- | src/shared/acl-util.h | 7 |
2 files changed, 63 insertions, 12 deletions
diff --git a/src/shared/acl-util.c b/src/shared/acl-util.c index b734ee1e0c..5c0c4e21aa 100644 --- a/src/shared/acl-util.c +++ b/src/shared/acl-util.c @@ -209,14 +209,20 @@ int acl_search_groups(const char *path, char ***ret_groups) { return ret; } -int parse_acl(const char *text, acl_t *ret_acl_access, acl_t *ret_acl_default, bool want_mask) { - _cleanup_free_ char **a = NULL, **d = NULL; /* strings are not freed */ - _cleanup_strv_free_ char **split = NULL; - int r = -EINVAL; - _cleanup_(acl_freep) acl_t a_acl = NULL, d_acl = NULL; +int parse_acl( + const char *text, + acl_t *ret_acl_access, + acl_t *ret_acl_access_exec, /* extra rules to apply to inodes subject to uppercase X handling */ + acl_t *ret_acl_default, + bool want_mask) { + + _cleanup_strv_free_ char **a = NULL, **e = NULL, **d = NULL, **split = NULL; + _cleanup_(acl_freep) acl_t a_acl = NULL, e_acl = NULL, d_acl = NULL; + int r; assert(text); assert(ret_acl_access); + assert(ret_acl_access_exec); assert(ret_acl_default); split = strv_split(text, ","); @@ -224,13 +230,38 @@ int parse_acl(const char *text, acl_t *ret_acl_access, acl_t *ret_acl_default, b return -ENOMEM; STRV_FOREACH(entry, split) { - char *p; + _cleanup_strv_free_ char **entry_split = NULL; + _cleanup_free_ char *entry_join = NULL; + int n; + + n = strv_split_full(&entry_split, *entry, ":", EXTRACT_DONT_COALESCE_SEPARATORS|EXTRACT_RETAIN_ESCAPE); + if (n < 0) + return n; + + if (n < 3 || n > 4) + return -EINVAL; + + string_replace_char(entry_split[n-1], 'X', 'x'); + + if (n == 4) { + if (!STR_IN_SET(entry_split[0], "default", "d")) + return -EINVAL; - p = STARTSWITH_SET(*entry, "default:", "d:"); - if (p) - r = strv_push(&d, p); - else - r = strv_push(&a, *entry); + entry_join = strv_join(entry_split + 1, ":"); + if (!entry_join) + return -ENOMEM; + + r = strv_consume(&d, TAKE_PTR(entry_join)); + } else { /* n == 3 */ + entry_join = strv_join(entry_split, ":"); + if (!entry_join) + return -ENOMEM; + + if (!streq(*entry, entry_join)) + r = strv_consume(&e, TAKE_PTR(entry_join)); + else + r = strv_consume(&a, TAKE_PTR(entry_join)); + } if (r < 0) return r; } @@ -253,6 +284,20 @@ int parse_acl(const char *text, acl_t *ret_acl_access, acl_t *ret_acl_default, b } } + if (!strv_isempty(e)) { + _cleanup_free_ char *join = NULL; + + join = strv_join(e, ","); + if (!join) + return -ENOMEM; + + e_acl = acl_from_text(join); + if (!e_acl) + return -errno; + + /* The mask must be calculated after deciding whether the execute bit should be set. */ + } + if (!strv_isempty(d)) { _cleanup_free_ char *join = NULL; @@ -272,6 +317,7 @@ int parse_acl(const char *text, acl_t *ret_acl_access, acl_t *ret_acl_default, b } *ret_acl_access = TAKE_PTR(a_acl); + *ret_acl_access_exec = TAKE_PTR(e_acl); *ret_acl_default = TAKE_PTR(d_acl); return 0; diff --git a/src/shared/acl-util.h b/src/shared/acl-util.h index d3a341fbe6..978389ed1d 100644 --- a/src/shared/acl-util.h +++ b/src/shared/acl-util.h @@ -15,7 +15,12 @@ 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 acl_search_groups(const char* path, char ***ret_groups); -int parse_acl(const char *text, acl_t *ret_acl_access, acl_t *ret_acl_default, bool want_mask); +int parse_acl( + const char *text, + acl_t *ret_acl_access, + acl_t *ret_acl_access_exec, + acl_t *ret_acl_default, + bool want_mask); int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *ret); int fd_add_uid_acl_permission(int fd, uid_t uid, unsigned mask); |