#define _GNU_SOURCE /* Definition of AT_* constants */ #include "libacl-helper.h" #include #include #include #include #include enum hakurei_acl_status hakurei_update_acl(int fd, uid_t uid, acl_perm_t perms) { enum hakurei_acl_status ret; bool v; int i; acl_t acl, acl_d = NULL; acl_entry_t entry; acl_tag_t tag_type; void *qualifier_p; acl_permset_t permset; acl_perm_t has_perms; ret = HAKUREI_ACL_GET_FILE; acl = acl_get_file_at(fd, "", AT_EMPTY_PATH, ACL_TYPE_ACCESS); if (acl == NULL) goto out; /* prune entries by uid */ for (i = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry); i == 1; i = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry)) { ret = HAKUREI_ACL_GET_TAG_TYPE; if (acl_get_tag_type(entry, &tag_type) != 0) goto out; if (tag_type != ACL_USER) continue; ret = HAKUREI_ACL_GET_QUALIFIER; qualifier_p = acl_get_qualifier(entry); if (qualifier_p == NULL) goto out; v = *(uid_t *)qualifier_p == uid; acl_free(qualifier_p); if (!v) continue; ret = HAKUREI_ACL_GET_PERMSET; if (acl_get_permset(entry, &permset) != 0) goto out; if (perms == 0) goto delete; /* this is quite ugly, but the standard makes it impossible to * directly obtain these bits */ has_perms = 0; #define COPY_PERM_BIT(perm) \ do { \ ret = HAKUREI_ACL_GET_PERM; \ i = acl_get_perm(permset, perm); \ if (i < 0) \ goto out; \ if (i > 0) \ has_perms |= perm; \ } while (0) COPY_PERM_BIT(ACL_READ); COPY_PERM_BIT(ACL_WRITE); COPY_PERM_BIT(ACL_EXECUTE); if (perms == has_perms) { ret = HAKUREI_ACL_DUP; acl_d = acl_dup(acl); if (acl_d == NULL) goto out; ret = HAKUREI_ACL_CALC_MASK; if (acl_calc_mask(&acl_d) != 0) goto out; ret = HAKUREI_ACL_OK; if (acl_cmp(acl, acl_d) == 0) goto out; } delete: ret = HAKUREI_ACL_DELETE_ENTRY; if (acl_delete_entry(acl, entry) != 0) goto out; } if (perms == 0) goto set; ret = HAKUREI_ACL_CREATE_ENTRY; if (acl_create_entry(&acl, &entry) != 0) goto out; ret = HAKUREI_ACL_GET_PERMSET; if (acl_get_permset(entry, &permset) != 0) goto out; ret = HAKUREI_ACL_ADD_PERM; if (acl_add_perm(permset, perms) != 0) goto out; ret = HAKUREI_ACL_SET_TAG_TYPE; if (acl_set_tag_type(entry, ACL_USER) != 0) goto out; ret = HAKUREI_ACL_SET_QUALIFIER; if (acl_set_qualifier(entry, (void *)&uid) != 0) goto out; set: ret = HAKUREI_ACL_CALC_MASK; if (acl_calc_mask(&acl) != 0) goto out; ret = HAKUREI_ACL_VALID; if (acl_valid(acl) != 0) goto out; ret = HAKUREI_ACL_SET_FILE; if (acl_set_file_at(fd, "", AT_EMPTY_PATH, ACL_TYPE_ACCESS, acl) == 0) ret = HAKUREI_ACL_OK; out: if (acl != NULL) acl_free((void *)acl); if (acl_d != NULL) acl_free((void *)acl_d); return ret; }