From f6383fa078b90292b5bf372d0baba4b434959b4e Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Tue, 14 Aug 2012 15:16:44 -0400 Subject: [PATCH] Change all return types to int. Add the has_minimal_default_acl() function. Make group bits correct in the presence of minimal ACLs. Begin fixing group execute with extended ACLs. --- src/aclq.c | 268 +++++++++++++++++++++++++++++------------------------ 1 file changed, 148 insertions(+), 120 deletions(-) diff --git a/src/aclq.c b/src/aclq.c index 9e456e4..5cdcea9 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,13 @@ 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. */ +int has_default_tag_acl(const char* path, acl_tag_t tag_type) { + /* 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, ACL_TYPE_DEFAULT); - - if (defacl == (acl_t)NULL) { - return false; - } - - /* 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,47 +88,71 @@ 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; + 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_minimal_default_acl(const char* path) { + /* An ACL is minimal if and only if it has no mask. Return 1 if it's + minimal, zero if it isn't, and -1 on errors. */ + int has_dm = has_default_tag_acl(path, ACL_MASK); + + if (has_dm == 0) { + return 1; + } + else if (has_dm == 1) { + return 0; + } + else { + perror("has_minimal_default_acl"); + return -1; + } } -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); } -bool get_default_tag_permset(const char* path, +int 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 */ + /* Returns one if successful, zero when the ACL doesn't exist, and + -1 on unexpected errors. */ acl_t defacl = acl_get_file(path, ACL_TYPE_DEFAULT); - + if (defacl == (acl_t)NULL) { /* Follow the acl_foo convention of -1 == error. */ errno = EINVAL; - return false; + return 0; } acl_entry_t entry; @@ -167,132 +161,131 @@ bool get_default_tag_permset(const char* path, while (result == 1) { acl_tag_t tag = ACL_UNDEFINED_TAG; int tag_result = acl_get_tag_type(entry, &tag); - + if (tag_result == -1) { - perror("get_default_tag_permset"); - return false; + perror("get_default_tag_permset (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 == -1) { + perror("get_default_tag_permset (acl_get_permset)"); + } + if (ps_result == 0) { - return true; + return 1; } else { - return false; + return 0; } } } - + result = acl_get_entry(defacl, ACL_NEXT_ENTRY, &entry); } - errno = EINVAL; - return false; -} - -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); -} - -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); -} + /* This catches both the initial acl_get_entry and the ones at the + end of the loop. */ + if (result == -1) { + perror("get_default_tag_permset (acl_get_entry)"); + return -1; + } -bool get_default_other_permset(const char* path, - acl_permset_t* output_perms) { - return get_default_tag_permset(path, ACL_OTHER, output_perms); + return 0; } - -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; - } - else { - return false; + if (p_result == -1) { + perror("has_default_tag_perm (acl_get_perm)"); } + + return p_result; } -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,19 +296,19 @@ 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_user_obj_write(parent)) { path_mode |= S_IWUSR; } @@ -335,7 +328,7 @@ bool reapply_default_acl(const char* path) { if (has_default_other_read(parent)) { path_mode |= S_IROTH; } - + if (has_default_other_write(parent)) { path_mode |= S_IWOTH; } @@ -347,37 +340,72 @@ bool reapply_default_acl(const char* path) { } } - /* 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; - } - - if (has_default_mask_write(parent)) { - path_mode |= S_IWGRP; + if (has_minimal_default_acl(parent)) { + /* With a minimal ACL, we'll repeat for the group bits what we + already did for the owner/other bits. */ + if (has_default_group_obj_read(parent)) { + path_mode |= S_IRGRP; + } + + if (has_default_group_obj_write(parent)) { + path_mode |= S_IWGRP; + } + + if (has_default_group_obj_acl(parent)) { + if (!has_default_group_obj_execute(parent)) { + /* It has a group ACL, but no group execute is granted. */ + path_mode &= ~S_IXGRP; + } + } } + else { + /* 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; + } - /* Honor the mask execute unconditionally. */ - if (has_default_mask_execute(parent)) { - if (mode_has_perm(path_mode, S_IXGRP)) { + if (has_default_mask_write(parent)) { + path_mode |= S_IWGRP; + } + + /* Honor the mask execute unconditionally. */ + if (has_default_mask_execute(parent)) { + /* This just adds the group execute bit, and doesn't actually + grant group execute permissions. */ path_mode |= S_IXGRP; } + + 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. */ + if (has_default_group_obj_execute(path)) { + /* remove_default_group_obj_execute(path);*/ + } + } } - int result = chmod(path, path_mode); - if (result == 0) { - return true; + int chmod_result = chmod(path, path_mode); + if (chmod_result == 0) { + return 1; } else { - return false; + return 0; } } int main(int argc, char* argv[]) { const char* target = argv[1]; - + bool result = reapply_default_acl(target); if (result) { -- 2.44.2