X-Git-Url: https://gitweb.michael.orlitzky.com/?a=blobdiff_plain;f=src%2Faclq.c;h=19749cdf671b1de3e6e2aa8eb3180e7614aa4159;hb=2d8496682c9b7283e7c1fb48e48dd19bf091cf5e;hp=9e456e485babbe3e065336c1a75a404adbd7c453;hpb=b09e79496d929d0e310ffeeb9e28c8949a56e10b;p=apply-default-acl.git diff --git a/src/aclq.c b/src/aclq.c index 9e456e4..19749cd 100644 --- a/src/aclq.c +++ b/src/aclq.c @@ -22,7 +22,7 @@ mode_t get_mode(const char* path) { struct stat s; int result = stat(path, &s); - + if (result == 0) { return s.st_mode; } @@ -73,43 +73,15 @@ bool is_directory(const char* path) { } -bool has_default_acl(const char* path) { - /* Return true if the given path has a default ACL, false - otherwise. */ - acl_t defacl = acl_get_file(path, ACL_TYPE_DEFAULT); - - if (defacl == (acl_t)NULL) { - return false; - } +int has_type_tag_acl(const char* path, + acl_type_t type, + acl_tag_t desired_tag) { + /* Returns one if the given path has a default ACL for the supplied + tag, zero if it doesn't, and -1 on error. */ + acl_t defacl = acl_get_file(path, type); - /* Used to store the entry if it exists, even though we don't care - what it is. */ - acl_entry_t dummy; - - int result = acl_get_entry(defacl, ACL_FIRST_ENTRY, &dummy); - - if (result == 1) { - /* There's a first entry in the default ACL. */ - return true; - } - else if (result == 0) { - return false; - } - else { - perror("has_default_acl"); - return false; - } -} - - - -bool has_default_tag_acl(const char* path, acl_tag_t tag_type) { - /* Return true if the given path has a default ACL for the supplied - tag, false otherwise. */ - acl_t defacl = acl_get_file(path, ACL_TYPE_DEFAULT); - if (defacl == (acl_t)NULL) { - return false; + return 0; } acl_entry_t entry; @@ -118,181 +90,323 @@ bool has_default_tag_acl(const char* path, acl_tag_t tag_type) { while (result == 1) { acl_tag_t tag = ACL_UNDEFINED_TAG; int tag_result = acl_get_tag_type(entry, &tag); - + if (tag_result == -1) { - perror("has_default_tag_acl - acl_get_tag_type"); - return false; + perror("has_default_tag_acl (acl_get_tag_type)"); + return -1; } else { - if (tag == tag_type) { - return true; + if (tag == desired_tag) { + return 1; } } - + result = acl_get_entry(defacl, ACL_NEXT_ENTRY, &entry); } - - return false; + + if (result == -1) { + perror("has_default_tag_acl (acl_get_entry)"); + return -1; + } + + return 0; } +int has_default_tag_acl(const char* path, acl_tag_t desired_tag) { + return has_type_tag_acl(path, ACL_TYPE_DEFAULT, desired_tag); +} + +int has_access_tag_acl(const char* path, acl_tag_t desired_tag) { + return has_type_tag_acl(path, ACL_TYPE_ACCESS, desired_tag); +} -bool has_default_user_obj_acl(const char* path) { +int has_default_user_obj_acl(const char* path) { return has_default_tag_acl(path, ACL_USER_OBJ); } -bool has_default_group_obj_acl(const char* path) { +int has_default_group_obj_acl(const char* path) { return has_default_tag_acl(path, ACL_GROUP_OBJ); } -bool has_default_other_acl(const char* path) { +int has_default_other_acl(const char* path) { return has_default_tag_acl(path, ACL_OTHER); } +int has_default_mask_acl(const char* path) { + return has_default_tag_acl(path, ACL_MASK); +} -bool get_default_tag_permset(const char* path, - acl_tag_t tag_type, - acl_permset_t* output_perms) { - /* Returns true if successful or false on error */ - acl_t defacl = acl_get_file(path, ACL_TYPE_DEFAULT); - - if (defacl == (acl_t)NULL) { + +int get_type_tag_entry(const char* path, + acl_type_t type, + acl_tag_t desired_tag, + acl_entry_t* entry) { + /* Returns one if successful, zero when the ACL doesn't exist, and + -1 on unexpected errors. */ + acl_t acl = acl_get_file(path, type); + + if (acl == (acl_t)NULL) { /* Follow the acl_foo convention of -1 == error. */ - errno = EINVAL; - return false; + return 0; } - acl_entry_t entry; - int result = acl_get_entry(defacl, ACL_FIRST_ENTRY, &entry); + int result = acl_get_entry(acl, ACL_FIRST_ENTRY, entry); while (result == 1) { acl_tag_t tag = ACL_UNDEFINED_TAG; - int tag_result = acl_get_tag_type(entry, &tag); - + int tag_result = acl_get_tag_type(*entry, &tag); + if (tag_result == -1) { - perror("get_default_tag_permset"); - return false; + perror("get_type_tag_entry (acl_get_tag_type)"); + return -1; } - else { - if (tag == tag_type) { - /* We found the right tag, now get the permset. */ - int ps_result = acl_get_permset(entry, output_perms); - if (ps_result == 0) { - return true; - } - else { - return false; - } - } + + if (tag == desired_tag) { + /* We found the right tag, so return successfully. */ + return 1; } - - result = acl_get_entry(defacl, ACL_NEXT_ENTRY, &entry); + + result = acl_get_entry(acl, ACL_NEXT_ENTRY, entry); + } + + /* This catches both the initial acl_get_entry and the ones at the + end of the loop. */ + if (result == -1) { + perror("get_type_tag_entry (acl_get_entry)"); + return -1; } - errno = EINVAL; - return false; + return 0; } -bool get_default_user_obj_permset(const char* path, - acl_permset_t* output_perms) { - return get_default_tag_permset(path, ACL_USER_OBJ, output_perms); +int get_default_tag_entry(const char* path, + acl_tag_t desired_tag, + acl_entry_t* entry) { + return get_type_tag_entry(path, ACL_TYPE_DEFAULT, desired_tag, entry); } -bool get_default_group_obj_permset(const char* path, - acl_permset_t* output_perms) { - return get_default_tag_permset(path, ACL_GROUP_OBJ, output_perms); +int get_access_tag_entry(const char* path, + acl_tag_t desired_tag, + acl_entry_t* entry) { + return get_type_tag_entry(path, ACL_TYPE_ACCESS, desired_tag, entry); } -bool get_default_other_permset(const char* path, - acl_permset_t* output_perms) { - return get_default_tag_permset(path, ACL_OTHER, output_perms); + + +int get_type_tag_permset(const char* path, + acl_type_t type, + acl_tag_t desired_tag, + acl_permset_t* output_perms) { + /* Returns one if successful, zero when the ACL doesn't exist, and + -1 on unexpected errors. */ + acl_t defacl = acl_get_file(path, type); + + if (defacl == (acl_t)NULL) { + /* Follow the acl_foo convention of -1 == error. */ + return 0; + } + + acl_entry_t entry; + int result = get_type_tag_entry(path, type, desired_tag, &entry); + + if (result == 1) { + /* We found the right tag, now get the permset. */ + int ps_result = acl_get_permset(entry, output_perms); + if (ps_result == -1) { + perror("get_type_tag_permset (acl_get_permset)"); + return -1; + } + + if (ps_result == 0) { + return 1; + } + else { + return 0; + } + } + else { + return result; + } } +int get_default_tag_permset(const char* path, + acl_tag_t desired_tag, + acl_permset_t* output_perms) { + return get_type_tag_permset(path, + ACL_TYPE_DEFAULT, + desired_tag, + output_perms); +} +int get_access_tag_permset(const char* path, + acl_tag_t desired_tag, + acl_permset_t* output_perms) { + return get_type_tag_permset(path, ACL_TYPE_ACCESS, desired_tag, output_perms); +} -bool has_default_tag_perm(const char* path, +int has_default_tag_perm(const char* path, acl_tag_t tag, acl_perm_t perm) { - /* Check path to see if tag has perm. */ + /* Check path to see if tag has the given perm. Returns one if it + does, zero if it doesn't (or there's no ACL), and -1 on unexpected + errors. */ if (!has_default_tag_acl(path, tag)) { - return false; + return 0; } - + acl_permset_t permset; bool ps_result = get_default_tag_permset(path, tag, &permset); - if (!ps_result) { - return false; + if (ps_result != 1) { + /* Failure or error. */ + return ps_result; } int p_result = acl_get_perm(permset, perm); - if (p_result == 1) { - return true; + if (p_result == -1) { + perror("has_default_tag_perm (acl_get_perm)"); } - else { - return false; + + return p_result; +} + +int remove_access_tag_perm(const char* path, + acl_tag_t desired_tag, + acl_perm_t perm) { + /* Attempt to remove perm from tag. Returns one if successful, zero + if there was nothing to do, and -1 on errors. */ + acl_t acl = acl_get_file(path, ACL_TYPE_ACCESS); + if (acl == (acl_t)NULL) { + /* Error. */ + return -1; } + + acl_permset_t permset; + bool ps_result = get_access_tag_permset(path, desired_tag, &permset); + + if (ps_result != 1) { + /* Failure or error. */ + return ps_result; + } + + int d_result = acl_delete_perm(permset, perm); + if (d_result == -1) { + perror("remove_access_tag_perm (acl_delete_perm)"); + return -1; + } + + /* We've only removed perm from the permset; now we have to replace + the permset. */ + acl_entry_t entry; + int result = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry); + + while (result == 1) { + acl_tag_t tag = ACL_UNDEFINED_TAG; + int tag_result = acl_get_tag_type(entry, &tag); + + if (tag_result == -1) { + perror("remove_access_tag_perm (acl_get_tag_type)"); + return -1; + } + + if (tag == desired_tag) { + /* We found the right tag. Update the permset. */ + int s_result = acl_set_permset(entry, permset); + if (s_result == -1) { + perror("remove_access_tag_perm (acl_set_permset)"); + return -1; + } + + int sf_result = acl_set_file(path, ACL_TYPE_ACCESS, acl); + if (sf_result == -1) { + perror("remove_access_tag_perm (acl_set_file)"); + return -1; + } + + return 1; + } + + result = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry); + } + + /* This catches both the initial acl_get_entry and the ones at the + end of the loop. */ + if (result == -1) { + perror("remove_access_tag_perm (acl_get_entry)"); + return -1; + } + + return 0; +} + +int remove_access_group_obj_execute(const char* path) { + return remove_access_tag_perm(path, ACL_GROUP_OBJ, ACL_EXECUTE); } -bool has_default_user_obj_read(const char* path) { + +int has_default_user_obj_read(const char* path) { return has_default_tag_perm(path, ACL_USER_OBJ, ACL_READ); } -bool has_default_user_obj_write(const char* path) { +int has_default_user_obj_write(const char* path) { return has_default_tag_perm(path, ACL_USER_OBJ, ACL_WRITE); } -bool has_default_user_obj_execute(const char* path) { +int has_default_user_obj_execute(const char* path) { return has_default_tag_perm(path, ACL_USER_OBJ, ACL_EXECUTE); } -bool has_default_group_obj_read(const char* path) { +int has_default_group_obj_read(const char* path) { return has_default_tag_perm(path, ACL_GROUP_OBJ, ACL_READ); } -bool has_default_group_obj_write(const char* path) { +int has_default_group_obj_write(const char* path) { return has_default_tag_perm(path, ACL_GROUP_OBJ, ACL_WRITE); } -bool has_default_group_obj_execute(const char* path) { +int has_default_group_obj_execute(const char* path) { return has_default_tag_perm(path, ACL_GROUP_OBJ, ACL_EXECUTE); } -bool has_default_other_read(const char* path) { +int has_default_other_read(const char* path) { return has_default_tag_perm(path, ACL_OTHER, ACL_READ); } -bool has_default_other_write(const char* path) { +int has_default_other_write(const char* path) { return has_default_tag_perm(path, ACL_OTHER, ACL_WRITE); } -bool has_default_other_execute(const char* path) { +int has_default_other_execute(const char* path) { return has_default_tag_perm(path, ACL_OTHER, ACL_EXECUTE); } -bool has_default_mask_read(const char* path) { +int has_default_mask_read(const char* path) { return has_default_tag_perm(path, ACL_MASK, ACL_READ); } -bool has_default_mask_write(const char* path) { +int has_default_mask_write(const char* path) { return has_default_tag_perm(path, ACL_MASK, ACL_WRITE); } -bool has_default_mask_execute(const char* path) { +int has_default_mask_execute(const char* path) { return has_default_tag_perm(path, ACL_MASK, ACL_EXECUTE); } -bool reapply_default_acl(const char* path) { +int reapply_default_acl(const char* path) { /* If this is a normal file or directory (i.e. that has just been created), we proceed to find its parent directory which will have - a default ACL. */ + a default ACL. + + Returns one for success, zero for failure (i.e. no ACL), and -1 + on unexpected errors. */ if (path == NULL) { - return false; + return 0; } if (!is_regular_file(path) && !is_directory(path)) { - return false; + return 0; } /* dirname mangles its argument */ @@ -303,85 +417,507 @@ bool reapply_default_acl(const char* path) { char* parent = dirname(path_copy); if (!is_directory(parent)) { /* Make sure dirname() did what we think it did. */ - return false; + return 0; } /* This is the original mode of path. We will simply add permissions to it, and then later reapply the result via chmod. */ mode_t path_mode = get_mode(path); - - /* If parent has a default user ACL, apply it to path via chmod. */ - if (has_default_user_obj_read(parent)) { - path_mode |= S_IRUSR; + if (has_default_mask_acl(parent)) { + /* The parent has an extended ACL. Extended ACLs use the mask + entry. */ + + /* For the group bits, we'll use the ACL's mask instead of the group + object bits. If the default ACL had a group entry, it should + already have propagated (but might be masked). */ + if (has_default_mask_read(parent)) { + path_mode |= S_IRGRP; + } + else { + path_mode &= ~S_IRGRP; + } + + if (has_default_mask_write(parent)) { + path_mode |= S_IWGRP; + } + else { + path_mode &= ~S_IWGRP; + } + + if (!mode_has_perm(path_mode, S_IXGRP)) { + /* The group ACL entry should already have been inherited from the + default ACL. If the source was not group executable, we want to + modify the destination so that it is not group executable + either. In the presence of ACLs, the group permissions come not + from the mode bits, but from the group:: ACL entry. So, to do + this, we remove the group::x entry. */ + remove_access_group_obj_execute(path); + } + + /* We need to determine whether or not to mask the execute + bit. This applies not only to the user/group/other entries, but + also to all other named entries. If the original file wasn't + executable, then the result probably should not be. To + determine whether or not "it was executable", we rely on the + user execute bits. Obviously this should be done before we + twiddle that bit. */ + if (has_default_mask_execute(parent)) { + if (mode_has_perm(path_mode, S_IXUSR)) { + /* This just adds the group execute bit, and doesn't actually + grant group execute permissions. */ + path_mode |= S_IXGRP; + } + } + else { + path_mode &= ~S_IXGRP; + } + } - - if (has_default_user_obj_write(parent)) { - path_mode |= S_IWUSR; + else { + /* It's a minimal ACL. We'll repeat for the group bits what we + already did for the owner/other bits. */ + if (has_default_group_obj_acl(parent)) { + if (has_default_group_obj_read(parent)) { + path_mode |= S_IRGRP; + } + else { + path_mode &= ~S_IRGRP; + } + + + if (has_default_group_obj_write(parent)) { + path_mode |= S_IWGRP; + } + else { + path_mode &= ~S_IWGRP; + } + + /* We don't want to set the execute bit on via the ACL unless it + was on originally. */ + if (!has_default_group_obj_execute(parent)) { + path_mode &= ~S_IXGRP; + } + } } - /* However, we don't want to set the execute bit on via the ACL - unless it was on originally. Furthermore, if the ACL denies - execute, we want to honor that. */ + + /* If parent has a default user ACL, apply it. */ if (has_default_user_obj_acl(parent)) { + + if (has_default_user_obj_read(parent)) { + /* Add user read. */ + path_mode |= S_IRUSR; + } + else { + /* Remove user read. */ + path_mode &= ~S_IRUSR; + } + + + if (has_default_user_obj_write(parent)) { + /* Add user write. */ + path_mode |= S_IWUSR; + } + else { + /* Remove user write. */ + path_mode &= ~S_IWUSR; + } + + + /* We don't want to set the execute bit on via the ACL unless it + was on originally. */ if (!has_default_user_obj_execute(parent)) { - /* It has a user ACL, but no user execute is granted. */ + /* Remove user execute. */ path_mode &= ~S_IXUSR; } } /* Do the same thing with the other perms/ACL. */ - if (has_default_other_read(parent)) { - path_mode |= S_IROTH; - } - - if (has_default_other_write(parent)) { - path_mode |= S_IWOTH; - } - if (has_default_other_acl(parent)) { + + if (has_default_other_read(parent)) { + path_mode |= S_IROTH; + } + else { + path_mode &= ~S_IROTH; + } + + + if (has_default_other_write(parent)) { + path_mode |= S_IWOTH; + } + else { + path_mode &= ~S_IWOTH; + } + + + /* We don't want to set the execute bit on via the ACL unless it + was on originally. */ if (!has_default_other_execute(parent)) { - /* It has an other ACL, but no other execute is granted. */ path_mode &= ~S_IXOTH; } } - /* For the group bits, we'll use the ACL's mask instead of the group - object bits. If the default ACL had a group entry, it should - already have propagated (but might be masked). */ - if (has_default_mask_read(parent)) { - path_mode |= S_IRGRP; + int chmod_result = chmod(path, path_mode); + if (chmod_result == 0) { + return 1; } - - if (has_default_mask_write(parent)) { - path_mode |= S_IWGRP; + else { + return 0; } +} + + + + + +int set_acl_entry(acl_t* aclp, + acl_entry_t entry) { + /* Update or create the given entry. */ + + acl_tag_t entry_tag; + int gt_result = acl_get_tag_type(entry, &entry_tag); + if (gt_result == -1) { + perror("set_acl_entry (acl_get_tag_type)"); + return -1; + } + + acl_permset_t entry_permset; + int ps_result = acl_get_permset(entry, &entry_permset); + if (ps_result == -1) { + perror("set_acl_entry (acl_get_permset)"); + return -1; + } + + acl_entry_t existing_entry; + /* Loop through the given ACL looking for matching entries. */ + int result = acl_get_entry(*aclp, ACL_FIRST_ENTRY, &existing_entry); + + while (result == 1) { + acl_tag_t existing_tag = ACL_UNDEFINED_TAG; + int tag_result = acl_get_tag_type(existing_entry, &existing_tag); - /* Honor the mask execute unconditionally. */ - if (has_default_mask_execute(parent)) { - if (mode_has_perm(path_mode, S_IXGRP)) { - path_mode |= S_IXGRP; + if (tag_result == -1) { + perror("set_acl_tag_permset (acl_get_tag_type)"); + return -1; } + + if (existing_tag == entry_tag) { + bool update_it = true; + + if (entry_tag == ACL_USER || entry_tag == ACL_GROUP) { + void* entry_qual = acl_get_qualifier(entry); + if (entry_qual == (void*)NULL) { + perror("set_acl_entry (acl_get_qualifier - entry_qual)"); + return -1; + } + + void* existing_qual = acl_get_qualifier(existing_entry); + if (existing_qual == (void*)NULL) { + perror("set_acl_entry (acl_get_qualifier - existing_qual)"); + return -1; + } + + if (entry_tag == ACL_USER) { + uid_t* u1p = (uid_t *)entry_qual; + uid_t* u2p = (uid_t *)existing_qual; + if (*u1p != *u2p) { + update_it = false; + } + } + else { + gid_t* g1p = (gid_t *)entry_qual; + gid_t* g2p = (gid_t *)existing_qual; + if (*g1p != *g2p) { + update_it = false; + } + } + + acl_free(entry_qual); + acl_free(existing_qual); + } + + if (update_it) { + acl_permset_t existing_permset; + int gep_result = acl_get_permset(existing_entry, &existing_permset); + if (gep_result == -1) { + perror("set_acl_entry (acl_get_permset)"); + return -1; + } + + /* If an existing entry doesn't have its execute bits set, we + don't want to set them from a default ACL. Unless it's the + mask entry! */ + int gp_result = acl_get_perm(existing_permset, ACL_EXECUTE); + if (gp_result == -1) { + perror("set_acl_entry (acl_get_perm)"); + return -1; + } + + if (gp_result == 0 && existing_tag != ACL_MASK) { + /* It doesn't already have execute perms */ + int d_result = acl_delete_perm(entry_permset, ACL_EXECUTE); + if (d_result == -1) { + perror("set_acl_entry (acl_delete_perm)"); + return -1; + } + } + + int s_result = acl_set_permset(existing_entry, entry_permset); + if (s_result == -1) { + perror("set_acl_entry (acl_set_permset)"); + return -1; + } + + return 1; + } + + } + + result = acl_get_entry(*aclp, ACL_NEXT_ENTRY, &existing_entry); } - int result = chmod(path, path_mode); - if (result == 0) { - return true; + /* This catches both the initial acl_get_entry and the ones at the + end of the loop. */ + if (result == -1) { + perror("set_acl_entry (acl_get_entry)"); + return -1; + } + + /* If we've made it this far, we need to add a new entry to the + ACL. */ + acl_entry_t new_entry; + int c_result = acl_create_entry(aclp, &new_entry); + if (c_result == -1) { + perror("set_acl_entry (acl_create_entry)"); + return -1; + } + + int st_result = acl_set_tag_type(new_entry, entry_tag); + if (st_result == -1) { + perror("set_acl_entry (acl_set_tag_type)"); + return -1; + } + + int s_result = acl_set_permset(new_entry, entry_permset); + if (s_result == -1) { + perror("set_acl_entry (acl_set_permset)"); + return -1; + } + + if (entry_tag == ACL_USER || entry_tag == ACL_GROUP) { + /* We need to set the qualifier too. */ + void* entry_qual = acl_get_qualifier(entry); + if (entry_qual == (void*)NULL) { + perror("set_acl_entry (acl_get_qualifier)"); + return -1; + } + + int sq_result = acl_set_qualifier(new_entry, entry_qual); + if (sq_result == -1) { + perror("set_acl_entry (acl_set_qualifier)"); + return -1; + } + } + + return 1; +} + + + +int acl_is_minimal(acl_t* acl) { + /* An ACL is minimal if it has fewer than four entries. */ + acl_entry_t entry; + int entry_count = 0; + int result = acl_get_entry(*acl, ACL_FIRST_ENTRY, &entry); + + while (result == 1) { + entry_count++; + result = acl_get_entry(*acl, ACL_NEXT_ENTRY, &entry); + } + + if (result == -1) { + perror("acl_is_minimal (acl_get_entry)"); + return -1; + } + + if (entry_count > 3) { + return 1; } else { - return false; + return 0; } } +int any_can_execute(const char* path) { + acl_t acl = acl_get_file(path, ACL_TYPE_ACCESS); + + if (acl_is_minimal(&acl)) { + mode_t mode = get_mode(path); + if (mode & (S_IXUSR | S_IXOTH | S_IXGRP)) { + return 1; + } + else { + return 0; + } + } + + if (acl == (acl_t)NULL) { + return 0; + } + + acl_entry_t entry; + int result = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry); + + while (result == 1) { + acl_permset_t permset; + + int ps_result = acl_get_permset(entry, &permset); + if (ps_result == -1) { + perror("any_can_execute (acl_get_permset)"); + return -1; + } + + int gp_result = acl_get_perm(permset, ACL_EXECUTE); + if (gp_result == -1) { + perror("any_can_execute (acl_get_perm)"); + return -1; + } + + if (gp_result == 1) { + return 1; + } + + result = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry); + } + + if (result == -1) { + perror("any_can_execute (acl_get_entry)"); + return -1; + } + + return 0; +} + + +int reapply_default_acl_ng(const char* path) { + /* Really reapply the default ACL by looping through it. Returns one + for success, zero for failure (i.e. no ACL), and -1 on unexpected + errors. */ + if (path == NULL) { + return 0; + } + + if (!is_regular_file(path) && !is_directory(path)) { + return 0; + } + + /* dirname mangles its argument */ + char path_copy[PATH_MAX]; + strncpy(path_copy, path, PATH_MAX-1); + path_copy[PATH_MAX-1] = 0; + + char* parent = dirname(path_copy); + if (!is_directory(parent)) { + /* Make sure dirname() did what we think it did. */ + return 0; + } + + int ace_result = any_can_execute(path); + if (ace_result == -1) { + perror("reapply_default_acl_ng (any_can_execute)"); + return -1; + } + + bool allow_exec = (bool)ace_result; + + acl_t defacl = acl_get_file(parent, ACL_TYPE_DEFAULT); + acl_t acl = acl_get_file(path, ACL_TYPE_ACCESS); + + if (defacl == (acl_t)NULL || acl == (acl_t)NULL) { + return 0; + } + + acl_entry_t entry; + int result = acl_get_entry(defacl, ACL_FIRST_ENTRY, &entry); + + while (result == 1) { + acl_tag_t tag = ACL_UNDEFINED_TAG; + int tag_result = acl_get_tag_type(entry, &tag); + + if (tag_result == -1) { + perror("has_default_tag_acl (acl_get_tag_type)"); + return -1; + } + + + /* We've got an entry/tag from the default ACL. Get its permset. */ + acl_permset_t permset; + int ps_result = acl_get_permset(entry, &permset); + if (ps_result == -1) { + perror("reapply_default_acl_ng (acl_get_permset)"); + return -1; + } + + /* If this is a default mask, fix it up. */ + if (tag == ACL_MASK || + tag == ACL_USER_OBJ || + tag == ACL_GROUP_OBJ || + tag == ACL_OTHER) { + if (!allow_exec) { + /* The mask doesn't affect acl_user_obj, acl_group_obj (in + minimal ACLs) or acl_other entries, so if execute should be + masked, we have to do it manually. */ + int d_result = acl_delete_perm(permset, ACL_EXECUTE); + if (d_result == -1) { + perror("reapply_default_acl_ng (acl_delete_perm)"); + return -1; + } + + int sp_result = acl_set_permset(entry, permset); + if (sp_result == -1) { + perror("reapply_default_acl_ng (acl_set_permset)"); + return -1; + } + } + } + + /* Finally, add the permset to the access ACL. */ + int set_result = set_acl_entry(&acl, entry); + if (set_result == -1) { + perror("reapply_default_acl_ng (set_acl_entry)"); + return -1; + } + + result = acl_get_entry(defacl, ACL_NEXT_ENTRY, &entry); + } + + /* Catches the first acl_get_entry as well as the ones at the end of + the loop. */ + if (result == -1) { + perror("reapply_default_acl_ng (acl_get_entry)"); + return -1; + } + + int sf_result = acl_set_file(path, ACL_TYPE_ACCESS, acl); + if (sf_result == -1) { + perror("reapply_default_acl_ng (acl_set_file)"); + return -1; + } + + return 1; +} + + int main(int argc, char* argv[]) { const char* target = argv[1]; - - bool result = reapply_default_acl(target); + + bool result = reapply_default_acl_ng(target); if (result) { - printf("Success.\n"); return EXIT_SUCCESS; } else {