From 97a849f60570c2174bf0397311498f29d5b9155a Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sun, 12 Aug 2012 12:35:56 -0400 Subject: [PATCH] Implement the reapply_default_acl function. --- src/aclq.c | 293 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 227 insertions(+), 66 deletions(-) diff --git a/src/aclq.c b/src/aclq.c index 4f9ad72..6ea2e1d 100644 --- a/src/aclq.c +++ b/src/aclq.c @@ -1,14 +1,77 @@ #include +#include /* dirname() */ #include /* PATH_MAX */ #include #include #include +#include +#include +#include /* ACLs */ #include #include +mode_t get_mode(const char* path) { + if (path == NULL) { + errno = ENOENT; + return -1; + } + + struct stat s; + int result = stat(path, &s); + + if (result == 0) { + return s.st_mode; + } + else { + /* errno will be set already by stat() */ + return result; + } +} + +bool mode_has_perm(mode_t mode, int perm) { + if (mode & perm) { + return true; + } + else { + return false; + } +} + + +bool is_regular_file(const char* path) { + if (path == NULL) { + return false; + } + + struct stat s; + int result = stat(path, &s); + if (result == 0) { + return S_ISREG(s.st_mode); + } + else { + return false; + } +} + +bool is_directory(const char* path) { + if (path == NULL) { + return false; + } + + struct stat s; + int result = stat(path, &s); + if (result == 0) { + return S_ISDIR(s.st_mode); + } + else { + return false; + } +} + + bool has_default_acl(const char* path) { /* Return true if the given path has a default ACL, false otherwise. */ @@ -80,22 +143,21 @@ bool has_default_group_obj_acl(const char* path) { return has_default_tag_acl(path, ACL_GROUP_OBJ); } -bool has_default_other_obj_acl(const char* path) { +bool has_default_other_acl(const char* path) { return has_default_tag_acl(path, ACL_OTHER); } -int get_default_tag_permset(const char* path, +bool get_default_tag_permset(const char* path, acl_tag_t tag_type, acl_permset_t* output_perms) { - /* Returns 0 if successful or -1 on error in accordance with - acl_get_permset. */ + /* Returns true if successful or false on error */ 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 -1; + return false; } acl_entry_t entry; @@ -107,12 +169,18 @@ int get_default_tag_permset(const char* path, if (tag_result == -1) { perror("get_default_tag_permset"); - return -1; + return false; } else { if (tag == tag_type) { /* We found the right tag, now get the permset. */ - return acl_get_permset(entry, output_perms); + int ps_result = acl_get_permset(entry, output_perms); + if (ps_result == 0) { + return true; + } + else { + return false; + } } } @@ -120,32 +188,39 @@ int get_default_tag_permset(const char* path, } errno = EINVAL; - return -1; + return false; } -int get_default_user_obj_permset(const char* path, +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_group_obj_permset(const char* path, +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_default_other_obj_permset(const char* path, +bool get_default_other_permset(const char* path, acl_permset_t* output_perms) { return get_default_tag_permset(path, ACL_OTHER, output_perms); } -bool has_default_tag_perm(const char* path, acl_perm_t, perm) { +bool has_default_tag_perm(const char* path, + acl_tag_t tag, + acl_perm_t perm) { + /* Check path to see if tag has perm. */ + + if (!has_default_tag_acl(path, tag)) { + return false; + } + acl_permset_t permset; - int ps_result = get_default_tag_permset(path, tag, &permset); + bool ps_result = get_default_tag_permset(path, tag, &permset); - if (ps_result == -1) { - perror("has_default_tag_perm - get_default_tag_permset"); + if (!ps_result) { return false; } @@ -153,76 +228,162 @@ bool has_default_tag_perm(const char* path, acl_perm_t, perm) { if (p_result == 1) { return true; } - else if (p_result == 0) { - return false; - } else { - /* p_result == -1 */ - perror("has_default_tag_perm - get_default_tag_permset"); return false; } } bool has_default_user_obj_read(const char* path) { - return has_default_tag_perm(ACL_USER_OBJ, ACL_READ); + return has_default_tag_perm(path, ACL_USER_OBJ, ACL_READ); } bool has_default_user_obj_write(const char* path) { - return has_default_tag_perm(ACL_USER_OBJ, ACL_WRITE); + return has_default_tag_perm(path, ACL_USER_OBJ, ACL_WRITE); } bool has_default_user_obj_execute(const char* path) { - return has_default_tag_perm(ACL_USER_OBJ, ACL_EXECUTE); + return has_default_tag_perm(path, ACL_USER_OBJ, ACL_EXECUTE); +} + +bool 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) { + return has_default_tag_perm(path, ACL_GROUP_OBJ, ACL_WRITE); +} + +bool 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) { + return has_default_tag_perm(path, ACL_OTHER, ACL_READ); +} + +bool 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) { + return has_default_tag_perm(path, ACL_OTHER, ACL_EXECUTE); +} + +bool 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) { + return has_default_tag_perm(path, ACL_MASK, ACL_WRITE); +} + +bool has_default_mask_execute(const char* path) { + return has_default_tag_perm(path, ACL_MASK, ACL_EXECUTE); } + +bool 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. */ + if (path == NULL) { + return false; + } + + if (!is_regular_file(path) && !is_directory(path)) { + return false; + } + + /* dirname mangles its argument */ + char path_copy[PATH_MAX]; + strncpy(path_copy, path, PATH_MAX-1); + path_copy[PATH_MAX] = 0; + + char* parent = dirname(path_copy); + if (!is_directory(parent)) { + /* Make sure dirname() did what we think it did. */ + return false; + } + + /* 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; + } + + /* 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 (has_default_user_obj_acl(parent)) { + if (!has_default_user_obj_execute(parent)) { + /* It has a user ACL, but no user execute is granted. */ + 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_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; + } + + if (has_default_mask_write(parent)) { + path_mode |= S_IWGRP; + } + + /* Honor the mask execute unconditionally. */ + if (has_default_mask_execute(parent)) { + if (mode_has_perm(path_mode, S_IXGRP)) { + path_mode |= S_IXGRP; + } + } + + int result = chmod(path, path_mode); + if (result == 0) { + return true; + } + else { + return false; + } +} + + int main(int argc, char* argv[]) { const char* target = argv[1]; - printf("Target: %s\n", target); - if (has_default_acl(target)) { - printf("Target has a default ACL.\n"); - } - else { - printf("Target does not have a default ACL.\n"); - } - - if (has_default_user_obj_acl(target)) { - printf("Target has a default owner ACL.\n"); - acl_permset_t owner_perms; - get_default_user_obj_permset(target, &owner_perms); - if (acl_get_perm(owner_perms, ACL_READ) == 1) { - printf("User: read\n"); - } - if (acl_get_perm(owner_perms, ACL_WRITE) == 1) { - printf("User: write\n"); - } - if (acl_get_perm(owner_perms, ACL_EXECUTE) == 1) { - printf("User: execute\n"); - } - } - else { - printf("Target does not have a default owner ACL.\n"); - } - - if (has_default_group_obj_acl(target)) { - printf("Target has a default group ACL.\n"); - } - else { - printf("Target does not have a default group ACL.\n"); - } + bool result = reapply_default_acl(target); - if (has_default_other_obj_acl(target)) { - printf("Target has a default other ACL.\n"); + if (result) { + printf("Success.\n"); + return EXIT_SUCCESS; } else { - printf("Target does not have a default other ACL.\n"); + return EXIT_FAILURE; } - /* - acl_permset_t group_perms; - get_default_group_obj_permset(); - - acl_permset_t other_perms; - get_default_other_obj_permset(); - */ - return EXIT_SUCCESS; } -- 2.44.2