1
0
mirror of https://github.com/systemd/systemd.git synced 2024-12-25 01:34:28 +03:00

shared/acl-util: add mask only when needed, always add base ACLs

For ACLs to be valid, a set of entries for user, group, and other
must be always present. Always add those entries.

While at it, only add the mask ACL if it is actually required, i.e.
when at least on ACL for non-owner group or user exists.
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2015-01-18 18:22:27 -05:00
parent a48a62a1af
commit dd4105b0a9
4 changed files with 112 additions and 36 deletions

View File

@ -306,16 +306,16 @@
<term><varname>a</varname></term> <term><varname>a</varname></term>
<term><varname>a+</varname></term> <term><varname>a+</varname></term>
<listitem><para>Set POSIX ACLs (access control lists). If <listitem><para>Set POSIX ACLs (access control lists). If
suffixed with <varname>+</varname>, specified mask will be suffixed with <varname>+</varname>, specified entries will
added to existing be added to the existing set.
entries. <command>systemd-tmpfiles</command> does not <command>systemd-tmpfiles</command> will automatically add
automatically add the required base entries for user and the required base entries for user and group based on the
group to the specified mask, so they must be specified access mode of the file, unless base entries already exist
explicitly if <varname>+</varname> is not used. The or are explictly specified. The mask will be added if not
mask will be added if not specified explicitly. specified explicitly or already present. Lines of this type
Lines of this type accept shell-style globs in place accept shell-style globs in place of normal path names. This
of normal path names. This can be useful for allowing can be useful for allowing additional access to certain
additional access to certain files. </para></listitem> files.</para></listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>

View File

@ -29,14 +29,14 @@
int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *entry) { int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *entry) {
acl_entry_t i; acl_entry_t i;
int found; int r;
assert(acl); assert(acl);
assert(entry); assert(entry);
for (found = acl_get_entry(acl, ACL_FIRST_ENTRY, &i); for (r = acl_get_entry(acl, ACL_FIRST_ENTRY, &i);
found > 0; r > 0;
found = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) { r = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) {
acl_tag_t tag; acl_tag_t tag;
uid_t *u; uid_t *u;
@ -60,8 +60,7 @@ int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *entry) {
return 1; return 1;
} }
} }
if (r < 0)
if (found < 0)
return -errno; return -errno;
return 0; 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) { int calc_acl_mask_if_needed(acl_t *acl_p) {
acl_entry_t i; acl_entry_t i;
int found; int r;
assert(acl_p); assert(acl_p);
for (found = acl_get_entry(*acl_p, ACL_FIRST_ENTRY, &i); for (r = acl_get_entry(*acl_p, ACL_FIRST_ENTRY, &i);
found > 0; r > 0;
found = acl_get_entry(*acl_p, ACL_NEXT_ENTRY, &i)) { r = acl_get_entry(*acl_p, ACL_NEXT_ENTRY, &i)) {
acl_tag_t tag; acl_tag_t tag;
if (acl_get_tag_type(i, &tag) < 0) 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) if (tag == ACL_MASK)
return 0; return 0;
if (IN_SET(tag, ACL_USER, ACL_GROUP))
goto calc;
} }
if (r < 0)
if (found < 0)
return -errno; return -errno;
return 0;
calc:
if (acl_calc_mask(acl_p) < 0) if (acl_calc_mask(acl_p) < 0)
return -errno; 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; 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) { int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *acl) {
_cleanup_(acl_freep) acl_t old; _cleanup_(acl_freep) acl_t old;
acl_entry_t i; acl_entry_t i;
int found, r; int r;
old = acl_get_file(path, type); old = acl_get_file(path, type);
if (!old) if (!old)
return -errno; return -errno;
for (found = acl_get_entry(new, ACL_FIRST_ENTRY, &i); for (r = acl_get_entry(new, ACL_FIRST_ENTRY, &i);
found > 0; r > 0;
found = acl_get_entry(new, ACL_NEXT_ENTRY, &i)) { r = acl_get_entry(new, ACL_NEXT_ENTRY, &i)) {
acl_entry_t j; 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) if (acl_copy_entry(j, i) < 0)
return -errno; return -errno;
} }
r = calc_acl_mask_if_needed(&old);
if (r < 0) if (r < 0)
return r; return -errno;
*acl = old; *acl = old;
old = NULL; old = NULL;

View File

@ -31,6 +31,7 @@
int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *entry); 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 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 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 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); int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *acl);

View File

@ -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) { 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; int r;
if (modify) { if (modify) {
r = acls_for_file(path, type, acl, &cleanme); r = acls_for_file(path, type, acl, &dup);
if (r < 0) if (r < 0)
return r; 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) { if (r < 0) {
_cleanup_(acl_free_charpp) char *t; _cleanup_(acl_free_charpp) char *t;
r = -errno; r = -errno;
t = acl_to_any_text(acl, NULL, ',', TEXT_ABBREVIATE); t = acl_to_any_text(dup, NULL, ',', TEXT_ABBREVIATE);
log_error_errno(r, log_error_errno(r,
"Setting %s ACL \"%s\" on %s failed: %m", "Setting %s ACL \"%s\" on %s failed: %m",
type == ACL_TYPE_ACCESS ? "access" : "default", type == ACL_TYPE_ACCESS ? "access" : "default",