diff options
author | Mike Yuan <me@yhndnzj.com> | 2022-12-16 17:44:06 +0100 |
---|---|---|
committer | Mike Yuan <me@yhndnzj.com> | 2023-04-27 09:15:09 +0200 |
commit | 26d98cdd78cb5283f5771bd5866997acc494b067 (patch) | |
tree | 6b59215bfcd3ae90e8c54915916eff3c08b80b8d /src/shared/acl-util.c | |
parent | Merge pull request #27413 from yuwata/core-job-cleanups (diff) | |
download | systemd-26d98cdd78cb5283f5771bd5866997acc494b067.tar.xz systemd-26d98cdd78cb5283f5771bd5866997acc494b067.zip |
tmpfiles: add conditionalized execute bit (X) support
According to setfacl(1), "the character X stands for
the execute permission if the file is a directory
or already has execute permission for some user."
After this commit, parse_acl() would return 3 acl
objects. The newly-added acl_exec object contains
entries that are subject to conditionalized execute
bit mangling. In tmpfiles, we would iterate the acl_exec
object, check the permission of the target files,
and remove the execute bit if necessary.
Here's an example entry:
A /tmp/test - - - - u:test:rwX
Closes #25114
Diffstat (limited to 'src/shared/acl-util.c')
-rw-r--r-- | src/shared/acl-util.c | 68 |
1 files changed, 57 insertions, 11 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; |