along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
#include <errno.h>
#include <stdbool.h>
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;
return 1;
}
}
-
- if (found < 0)
+ if (r < 0)
return -errno;
return 0;
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)
if (tag == ACL_MASK)
return 0;
+
+ if (IN_SET(tag, ACL_USER, ACL_GROUP)) {
+ if (acl_calc_mask(acl_p) < 0)
+ return -errno;
+
+ return 1;
+ }
+ }
+ if (r < 0)
+ return -errno;
+
+ return 0;
+}
+
+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;
- if (found < 0)
+ r = stat(path, &st);
+ if (r < 0)
return -errno;
- if (acl_calc_mask(acl_p) < 0)
+ 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;
}
-int search_acl_groups(char*** dst, const char* path, bool* belong) {
- acl_t acl;
+int acl_search_groups(const char *path, char ***ret_groups) {
+ _cleanup_strv_free_ char **g = NULL;
+ _cleanup_(acl_free) acl_t acl = NULL;
+ bool ret = false;
+ acl_entry_t entry;
+ int r;
assert(path);
- assert(belong);
acl = acl_get_file(path, ACL_TYPE_DEFAULT);
- if (acl) {
- acl_entry_t entry;
- int r;
-
- r = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
- while (r > 0) {
- acl_tag_t tag;
- gid_t *gid;
- char *name;
+ if (!acl)
+ return -errno;
- r = acl_get_tag_type(entry, &tag);
- if (r < 0)
- break;
+ r = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry);
+ for (;;) {
+ _cleanup_(acl_free_gid_tpp) gid_t *gid = NULL;
+ acl_tag_t tag;
+
+ if (r < 0)
+ return -errno;
+ if (r == 0)
+ break;
+
+ if (acl_get_tag_type(entry, &tag) < 0)
+ return -errno;
+
+ if (tag != ACL_GROUP)
+ goto next;
- if (tag != ACL_GROUP)
- goto next;
+ gid = acl_get_qualifier(entry);
+ if (!gid)
+ return -errno;
+
+ if (in_gid(*gid) > 0) {
+ if (!ret_groups)
+ return true;
- gid = acl_get_qualifier(entry);
- if (!gid)
- break;
+ ret = true;
+ }
- if (in_gid(*gid) > 0) {
- *belong = true;
- break;
- }
+ if (ret_groups) {
+ char *name;
name = gid_to_name(*gid);
- if (!name) {
- acl_free(acl);
- return log_oom();
- }
-
- r = strv_consume(dst, name);
- if (r < 0) {
- acl_free(acl);
- return log_oom();
- }
-
- next:
- r = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
+ if (!name)
+ return -ENOMEM;
+
+ r = strv_consume(&g, name);
+ if (r < 0)
+ return r;
}
- acl_free(acl);
+ next:
+ r = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry);
}
- return 0;
+ if (ret_groups) {
+ *ret_groups = g;
+ g = NULL;
+ }
+
+ return ret;
}
-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;
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)) {
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;
a_acl = d_acl = NULL;
return 0;
}
+
+static int acl_entry_equal(acl_entry_t a, acl_entry_t b) {
+ acl_tag_t tag_a, tag_b;
+
+ if (acl_get_tag_type(a, &tag_a) < 0)
+ return -errno;
+
+ if (acl_get_tag_type(b, &tag_b) < 0)
+ return -errno;
+
+ if (tag_a != tag_b)
+ return false;
+
+ switch (tag_a) {
+ case ACL_USER_OBJ:
+ case ACL_GROUP_OBJ:
+ case ACL_MASK:
+ case ACL_OTHER:
+ /* can have only one of those */
+ return true;
+ case ACL_USER: {
+ _cleanup_(acl_free_uid_tpp) uid_t *uid_a = NULL, *uid_b = NULL;
+
+ uid_a = acl_get_qualifier(a);
+ if (!uid_a)
+ return -errno;
+
+ uid_b = acl_get_qualifier(b);
+ if (!uid_b)
+ return -errno;
+
+ return *uid_a == *uid_b;
+ }
+ case ACL_GROUP: {
+ _cleanup_(acl_free_gid_tpp) gid_t *gid_a = NULL, *gid_b = NULL;
+
+ gid_a = acl_get_qualifier(a);
+ if (!gid_a)
+ return -errno;
+
+ gid_b = acl_get_qualifier(b);
+ if (!gid_b)
+ return -errno;
+
+ return *gid_a == *gid_b;
+ }
+ default:
+ assert_not_reached("Unknown acl tag type");
+ }
+}
+
+static int find_acl_entry(acl_t acl, acl_entry_t entry, acl_entry_t *out) {
+ acl_entry_t i;
+ int r;
+
+ for (r = acl_get_entry(acl, ACL_FIRST_ENTRY, &i);
+ r > 0;
+ r = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) {
+
+ r = acl_entry_equal(i, entry);
+ if (r < 0)
+ return r;
+ if (r > 0) {
+ *out = i;
+ return 1;
+ }
+ }
+ if (r < 0)
+ return -errno;
+ 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 r;
+
+ old = acl_get_file(path, type);
+ if (!old)
+ return -errno;
+
+ 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;
+
+ r = find_acl_entry(old, i, &j);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ if (acl_create_entry(&old, &j) < 0)
+ return -errno;
+
+ if (acl_copy_entry(j, i) < 0)
+ return -errno;
+ }
+ if (r < 0)
+ return -errno;
+
+ *acl = old;
+ old = NULL;
+ return 0;
+}