From 56883e0b8096b29cc545702f063f28619b593fe0 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Sat, 19 Jan 2013 19:33:25 -0500 Subject: [PATCH] Document more functions with Doxygen. Replace magic exit codes with defined constants. Replace a few failure codes with errors. --- src/apply-default-acl.c | 347 +++++++++++++++++++++++++--------------- 1 file changed, 222 insertions(+), 125 deletions(-) diff --git a/src/apply-default-acl.c b/src/apply-default-acl.c index f6aa5be..9c48b97 100644 --- a/src/apply-default-acl.c +++ b/src/apply-default-acl.c @@ -7,6 +7,7 @@ /* On Linux, ftw.h needs this special voodoo to work. */ #define _XOPEN_SOURCE 500 +#define _GNU_SOURCE #include #include /* nftw() et al. */ @@ -25,11 +26,18 @@ #include #include +/* Most of the libacl functions return 1 for success, 0 for failure, + and -1 on error */ +#define ACL_ERROR -1 +#define ACL_FAILURE 0 +#define ACL_SUCCESS 1 + /* Command-line options */ static bool no_exec_mask = false; + /** * @brief Get the mode bits from the given path. * @@ -58,6 +66,7 @@ mode_t get_mode(const char* path) { } + /** * @brief Determine whether or not the given path is a regular file. * @@ -82,6 +91,7 @@ bool is_regular_file(const char* path) { } + /** * @brief Determine whether or not the given path is a directory. * @@ -107,37 +117,58 @@ bool is_directory(const char* path) { +/** + * @brief Update (or create) an entry in an @b minimal ACL. + * + * This function will not work if @c aclp contains extended + * entries. This is fine for our purposes, since we call @c wipe_acls + * on each path before applying the default to it. + * + * The assumption that there are no extended entries makes things much + * simpler. For example, we only have to update the ACL_USER_OBJ, + * ACL_GROUP_OBJ, and ACL_OTHER entries -- all others can simply be + * created anew. This means we don't have to fool around comparing + * named-user/group entries. + * + * @param aclp + * A pointer to the acl_t structure whose entry we want to modify. + * + * @param entry + * The new entry. If @c entry contains a user/group/other entry, we + * update the existing one. Otherwise we create a new entry. + * + * @return If there is an unexpected library error, ACL_ERROR is + * returned. Otherwise, ACL_SUCCESS. + * + */ int acl_set_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) { + if (gt_result == ACL_ERROR) { perror("acl_set_entry (acl_get_tag_type)"); - return -1; + return ACL_ERROR; } acl_permset_t entry_permset; int ps_result = acl_get_permset(entry, &entry_permset); - if (ps_result == -1) { + if (ps_result == ACL_ERROR) { perror("acl_set_entry (acl_get_permset)"); - return -1; + return ACL_ERROR; } 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) { + while (result == ACL_SUCCESS) { acl_tag_t existing_tag = ACL_UNDEFINED_TAG; int tag_result = acl_get_tag_type(existing_entry, &existing_tag); - if (tag_result == -1) { + if (tag_result == ACL_ERROR) { perror("set_acl_tag_permset (acl_get_tag_type)"); - return -1; + return ACL_ERROR; } if (existing_tag == entry_tag) { @@ -145,21 +176,23 @@ int acl_set_entry(acl_t* aclp, entry_tag == ACL_GROUP_OBJ || entry_tag == ACL_OTHER) { /* Only update for these three since all other tags will have - been wiped. */ + been wiped. These three are guaranteed to exist, so if we + match one of them, we're allowed to return ACL_SUCCESS + below and bypass the rest of the function. */ acl_permset_t existing_permset; int gep_result = acl_get_permset(existing_entry, &existing_permset); - if (gep_result == -1) { + if (gep_result == ACL_ERROR) { perror("acl_set_entry (acl_get_permset)"); - return -1; + return ACL_ERROR; } int s_result = acl_set_permset(existing_entry, entry_permset); - if (s_result == -1) { + if (s_result == ACL_ERROR) { perror("acl_set_entry (acl_set_permset)"); - return -1; + return ACL_ERROR; } - return 1; + return ACL_SUCCESS; } } @@ -169,9 +202,9 @@ int acl_set_entry(acl_t* aclp, /* This catches both the initial acl_get_entry and the ones at the end of the loop. */ - if (result == -1) { + if (result == ACL_ERROR) { perror("acl_set_entry (acl_get_entry)"); - return -1; + return ACL_ERROR; } /* If we've made it this far, we need to add a new entry to the @@ -180,21 +213,21 @@ int acl_set_entry(acl_t* aclp, /* We allocate memory here that we should release! */ int c_result = acl_create_entry(aclp, &new_entry); - if (c_result == -1) { + if (c_result == ACL_ERROR) { perror("acl_set_entry (acl_create_entry)"); - return -1; + return ACL_ERROR; } int st_result = acl_set_tag_type(new_entry, entry_tag); - if (st_result == -1) { + if (st_result == ACL_ERROR) { perror("acl_set_entry (acl_set_tag_type)"); - return -1; + return ACL_ERROR; } int s_result = acl_set_permset(new_entry, entry_permset); - if (s_result == -1) { + if (s_result == ACL_ERROR) { perror("acl_set_entry (acl_set_permset)"); - return -1; + return ACL_ERROR; } if (entry_tag == ACL_USER || entry_tag == ACL_GROUP) { @@ -202,87 +235,118 @@ int acl_set_entry(acl_t* aclp, void* entry_qual = acl_get_qualifier(entry); if (entry_qual == (void*)NULL) { perror("acl_set_entry (acl_get_qualifier)"); - return -1; + return ACL_ERROR; } int sq_result = acl_set_qualifier(new_entry, entry_qual); - if (sq_result == -1) { + if (sq_result == ACL_ERROR) { perror("acl_set_entry (acl_set_qualifier)"); - return -1; + return ACL_ERROR; } } - return 1; + return ACL_SUCCESS; } +/** + * @brief Determine the number of entries in the given ACL. + * + * @param acl + * A pointer to an acl_t structure. + * + * @return Either the non-negative number of entries in @c acl, or + * ACL_ERROR on error. + */ int acl_entry_count(acl_t* acl) { - /* - * Return the number of entries in acl, or -1 on error. - */ + acl_entry_t entry; int entry_count = 0; int result = acl_get_entry(*acl, ACL_FIRST_ENTRY, &entry); - while (result == 1) { + while (result == ACL_SUCCESS) { entry_count++; result = acl_get_entry(*acl, ACL_NEXT_ENTRY, &entry); } - if (result == -1) { - perror("acl_is_minimal (acl_get_entry)"); - return -1; + if (result == ACL_ERROR) { + perror("acl_entry_count (acl_get_entry)"); + return ACL_ERROR; } return entry_count; } + +/** + * @brief Determine whether or not the given ACL is minimal. + * + * An ACL is minimal if it has fewer than four entries. + * + * @param acl + * A pointer to an acl_t structure. + * + * @return + * - ACL_SUCCESS - @c acl is minimal + * - ACL_FAILURE - @c acl is not minimal + * - ACL_ERROR - Unexpected library error + */ int acl_is_minimal(acl_t* acl) { - /* An ACL is minimal if it has fewer than four entries. Return 0 for - * false, 1 for true, and -1 on error. - */ int ec = acl_entry_count(acl); - if (ec == -1) { + + if (ec == ACL_ERROR) { perror("acl_is_minimal (acl_entry_count)"); - return -1; + return ACL_ERROR; } if (ec < 4) { - return 1; + return ACL_SUCCESS; } else { - return 0; + return ACL_FAILURE; } } + +/** + * @brief Determine whether the given path has an ACL whose mask + * denies execute. + * + * @param path + * The path to check. + * + * @return + * - ACL_SUCCESS - @c path has a mask which denies execute. + * - ACL_FAILURE - The ACL for @c path does not deny execute, + * or @c path has no extended ACL at all. + * - ACL_ERROR - Unexpected library error. + */ int acl_execute_masked(const char* path) { - /* Returns 1 i the given path has an ACL mask which denies - execute. Returns 0 if it does not (or if it has no ACL/mask at - all), and -1 on error. */ acl_t acl = acl_get_file(path, ACL_TYPE_ACCESS); if (acl == (acl_t)NULL) { - return 0; + perror("acl_execute_masked (acl_get_file)"); + return ACL_ERROR; } /* Our return value. */ - int result = 0; + int result = ACL_FAILURE; acl_entry_t entry; int ge_result = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry); - while (ge_result == 1) { + while (ge_result == ACL_SUCCESS) { acl_tag_t tag = ACL_UNDEFINED_TAG; int tag_result = acl_get_tag_type(entry, &tag); - if (tag_result == -1) { + if (tag_result == ACL_ERROR) { perror("acl_execute_masked (acl_get_tag_type)"); - result = -1; + result = ACL_ERROR; goto cleanup; } @@ -292,22 +356,22 @@ int acl_execute_masked(const char* path) { acl_permset_t permset; int ps_result = acl_get_permset(entry, &permset); - if (ps_result == -1) { + if (ps_result == ACL_ERROR) { perror("acl_execute_masked (acl_get_permset)"); - result = -1; + result = ACL_ERROR; goto cleanup; } int gp_result = acl_get_perm(permset, ACL_EXECUTE); - if (gp_result == -1) { + if (gp_result == ACL_ERROR) { perror("acl_execute_masked (acl_get_perm)"); - result = -1; + result = ACL_ERROR; goto cleanup; } - if (gp_result == 0) { + if (gp_result == ACL_FAILURE) { /* No execute bit set in the mask; execute not allowed. */ - return 1; + return ACL_SUCCESS; } } @@ -320,39 +384,52 @@ int acl_execute_masked(const char* path) { } +/** + * @brief Determine whether @c path is executable (by anyone) or a + * directory. + * + * This is used as part of the heuristic to determine whether or not + * we should mask the execute bit when inheriting an ACL. If @c path + * is a directory, the answer is a clear-cut yes. This behavior is + * modeled after the capital 'X' perms of setfacl. + * + * If @c path is a file, we check the @a effective permissions, + * contrary to what setfacl does. + * + * @param path + * The path to check. + * + * @return + * - ACL_SUCCESS - @c path is a directory, or someone has effective + execute permissions. + * - ACL_FAILURE - @c path is a regular file and nobody can execute it. + * - ACL_ERROR - Unexpected library error. + */ int any_can_execute_or_dir(const char* path) { - /* If the given path is a directory, returns 1. Otherwise, returns 1 - * if any ACL entry has EFFECTIVE execute access, 0 if none do, and - * -1 on error. - * - * This is meant to somewhat mimic setfacl's handling of the capital - * 'X' perm, which allows execute access if the target is a - * directory or someone can already execute it. We differ in that we - * check the effective execute rather than just the execute bits. - */ if (is_directory(path)) { /* That was easy... */ - return 1; + return ACL_SUCCESS; } acl_t acl = acl_get_file(path, ACL_TYPE_ACCESS); if (acl == (acl_t)NULL) { - return 0; + perror("any_can_execute_or_dir (acl_get_file)"); + return ACL_ERROR; } /* Our return value. */ - int result = 0; + int result = ACL_FAILURE; if (acl_is_minimal(&acl)) { mode_t mode = get_mode(path); if (mode & (S_IXUSR | S_IXOTH | S_IXGRP)) { - result = 1; + result = ACL_SUCCESS; goto cleanup; } else { - result = 0; + result = ACL_FAILURE; goto cleanup; } } @@ -360,27 +437,27 @@ int any_can_execute_or_dir(const char* path) { acl_entry_t entry; int ge_result = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry); - while (ge_result == 1) { + while (ge_result == ACL_SUCCESS) { acl_permset_t permset; int ps_result = acl_get_permset(entry, &permset); - if (ps_result == -1) { + if (ps_result == ACL_ERROR) { perror("any_can_execute_or_dir (acl_get_permset)"); - result = -1; + result = ACL_ERROR; goto cleanup; } int gp_result = acl_get_perm(permset, ACL_EXECUTE); - if (gp_result == -1) { + if (gp_result == ACL_ERROR) { perror("any_can_execute_or_dir (acl_get_perm)"); - result = -1; + result = ACL_ERROR; goto cleanup; } - if (gp_result == 1) { + if (gp_result == ACL_SUCCESS) { /* Only return one if this execute bit is not masked. */ - if (acl_execute_masked(path) != 1) { - result = 1; + if (acl_execute_masked(path) != ACL_SUCCESS) { + result = ACL_SUCCESS; goto cleanup; } } @@ -388,9 +465,9 @@ int any_can_execute_or_dir(const char* path) { ge_result = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry); } - if (ge_result == -1) { + if (ge_result == ACL_ERROR) { perror("any_can_execute_or_dir (acl_get_entry)"); - result = -1; + result = ACL_ERROR; goto cleanup; } @@ -400,6 +477,25 @@ int any_can_execute_or_dir(const char* path) { } + +/** + * @brief Inherit the default ACL from @c parent to @c path. + * + * The @c parent parameter does not necessarily need to be the parent + * of @c path, although that will usually be the case. This overwrites + * any existing default ACL on @c path. + * + * @param parent + * The parent directory whose ACL we want to inherit. + * + * @param path + * The target directory whose ACL we wish to overwrite (or create). + * + * @return + * - ACL_SUCCESS - The default ACL was inherited successfully. + * - ACL_FAILURE - Either @c parent or @c path is not a directory. + * - ACL_ERROR - Unexpected library error. + */ int inherit_default_acl(const char* path, const char* parent) { /* Inherit the default ACL from parent to path. This overwrites any * existing default ACL. Returns 1 for success, 0 for failure, and @@ -407,20 +503,21 @@ int inherit_default_acl(const char* path, const char* parent) { */ /* Our return value. */ - int result = 1; + int result = ACL_SUCCESS; if (path == NULL) { errno = ENOENT; - return -1; + return ACL_ERROR; } if (!is_directory(path) || !is_directory(parent)) { - return 0; + return ACL_FAILURE; } acl_t parent_acl = acl_get_file(parent, ACL_TYPE_DEFAULT); if (parent_acl == (acl_t)NULL) { - return 0; + perror("inherit_default_acl (acl_get_file)"); + return ACL_ERROR; } acl_t path_acl = acl_dup(parent_acl); @@ -428,13 +525,13 @@ int inherit_default_acl(const char* path, const char* parent) { if (path_acl == (acl_t)NULL) { perror("inherit_default_acl (acl_dup)"); acl_free(parent_acl); - return -1; + return ACL_ERROR; } int sf_result = acl_set_file(path, ACL_TYPE_DEFAULT, path_acl); if (sf_result == -1) { perror("inherit_default_acl (acl_set_file)"); - result = -1; + result = ACL_ERROR; goto cleanup; } @@ -450,27 +547,27 @@ int wipe_acls(const char* path) { if (path == NULL) { errno = ENOENT; - return -1; + return ACL_ERROR; } /* Finally, remove individual named/mask entries. */ acl_t acl = acl_get_file(path, ACL_TYPE_ACCESS); if (acl == (acl_t)NULL) { perror("wipe_acls (acl_get_file)"); - return -1; + return ACL_ERROR; } /* Our return value. */ - int result = 1; + int result = ACL_SUCCESS; acl_entry_t entry; int ge_result = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry); - while (ge_result == 1) { + while (ge_result == ACL_SUCCESS) { int d_result = acl_delete_entry(acl, entry); - if (d_result == -1) { + if (d_result == ACL_ERROR) { perror("wipe_acls (acl_delete_entry)"); - result = -1; + result = ACL_ERROR; goto cleanup; } @@ -479,16 +576,16 @@ int wipe_acls(const char* path) { /* Catches the first acl_get_entry as well as the ones at the end of the loop. */ - if (ge_result == -1) { + if (ge_result == ACL_ERROR) { perror("wipe_acls (acl_get_entry)"); - result = -1; + result = ACL_ERROR; goto cleanup; } int sf_result = acl_set_file(path, ACL_TYPE_ACCESS, acl); - if (sf_result == -1) { + if (sf_result == ACL_ERROR) { perror("wipe_acls (acl_set_file)"); - result = -1; + result = ACL_ERROR; goto cleanup; } @@ -505,11 +602,11 @@ int apply_default_acl(const char* path) { */ if (path == NULL) { - return 0; + return ACL_FAILURE; } if (!is_regular_file(path) && !is_directory(path)) { - return 0; + return ACL_FAILURE; } /* dirname mangles its argument */ @@ -520,7 +617,7 @@ int apply_default_acl(const char* path) { char* parent = dirname(path_copy); if (!is_directory(parent)) { /* Make sure dirname() did what we think it did. */ - return 0; + return ACL_FAILURE; } /* Default to not masking the exec bit; i.e. applying the default @@ -531,9 +628,9 @@ int apply_default_acl(const char* path) { if (!no_exec_mask) { int ace_result = any_can_execute_or_dir(path); - if (ace_result == -1) { + if (ace_result == ACL_ERROR) { perror("apply_default_acl (any_can_execute_or_dir)"); - return -1; + return ACL_ERROR; } allow_exec = (bool)ace_result; } @@ -542,16 +639,16 @@ int apply_default_acl(const char* path) { if (defacl == (acl_t)NULL) { perror("apply_default_acl (acl_get_file)"); - return -1; + return ACL_ERROR; } /* Our return value. */ - int result = 1; + int result = ACL_SUCCESS; int wipe_result = wipe_acls(path); - if (wipe_result == -1) { + if (wipe_result == ACL_ERROR) { perror("apply_default_acl (wipe_acls)"); - result = -1; + result = ACL_ERROR; goto cleanup; } @@ -560,27 +657,27 @@ int apply_default_acl(const char* path) { acl_t acl = acl_get_file(path, ACL_TYPE_ACCESS); if (acl == (acl_t)NULL) { perror("apply_default_acl (acl_get_file)"); - return -1; + return ACL_ERROR; } /* If it's a directory, inherit the parent's default. */ int inherit_result = inherit_default_acl(path, parent); - if (inherit_result == -1) { + if (inherit_result == ACL_ERROR) { perror("apply_default_acl (inherit_acls)"); - result = -1; + result = ACL_ERROR; goto cleanup; } acl_entry_t entry; int ge_result = acl_get_entry(defacl, ACL_FIRST_ENTRY, &entry); - while (ge_result == 1) { + while (ge_result == ACL_SUCCESS) { acl_tag_t tag = ACL_UNDEFINED_TAG; int tag_result = acl_get_tag_type(entry, &tag); - if (tag_result == -1) { + if (tag_result == ACL_ERROR) { perror("apply_default_acl (acl_get_tag_type)"); - result = -1; + result = ACL_ERROR; goto cleanup; } @@ -588,9 +685,9 @@ int apply_default_acl(const char* path) { /* 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) { + if (ps_result == ACL_ERROR) { perror("apply_default_acl (acl_get_permset)"); - result = -1; + result = ACL_ERROR; goto cleanup; } @@ -605,16 +702,16 @@ int apply_default_acl(const char* path) { 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) { + if (d_result == ACL_ERROR) { perror("apply_default_acl (acl_delete_perm)"); - result = -1; + result = ACL_ERROR; goto cleanup; } int sp_result = acl_set_permset(entry, permset); - if (sp_result == -1) { + if (sp_result == ACL_ERROR) { perror("apply_default_acl (acl_set_permset)"); - result = -1; + result = ACL_ERROR; goto cleanup; } } @@ -622,9 +719,9 @@ int apply_default_acl(const char* path) { /* Finally, add the permset to the access ACL. */ int set_result = acl_set_entry(&acl, entry); - if (set_result == -1) { + if (set_result == ACL_ERROR) { perror("apply_default_acl (acl_set_entry)"); - result = -1; + result = ACL_ERROR; goto cleanup; } @@ -633,16 +730,16 @@ int apply_default_acl(const char* path) { /* Catches the first acl_get_entry as well as the ones at the end of the loop. */ - if (ge_result == -1) { + if (ge_result == ACL_ERROR) { perror("apply_default_acl (acl_get_entry)"); - result = -1; + result = ACL_ERROR; goto cleanup; } int sf_result = acl_set_file(path, ACL_TYPE_ACCESS, acl); - if (sf_result == -1) { + if (sf_result == ACL_ERROR) { perror("apply_default_acl (acl_set_file)"); - result = -1; + result = ACL_ERROR; goto cleanup; } @@ -679,10 +776,10 @@ int apply_default_acl_nftw(const char *target, */ bool reapp_result = apply_default_acl(target); if (reapp_result) { - return 0; + return FTW_CONTINUE; } else { - return 1; + return FTW_STOP; } } -- 2.44.2