static int CheckPosixLinuxACEs(EvalContext *ctx, Rlist *aces, AclMethod method, const char *file_path, acl_type_t acl_type, Attributes a, const Promise *pp, PromiseResult *result) { acl_t acl_existing; acl_t acl_new; acl_t acl_tmp; acl_entry_t ace_parsed; acl_entry_t ace_current; acl_permset_t perms; char *cf_ace; int retv; int has_mask; Rlist *rp; char *acl_type_str; acl_new = NULL; acl_existing = NULL; acl_tmp = NULL; has_mask = false; acl_type_str = acl_type == ACL_TYPE_ACCESS ? "Access" : "Default"; // read existing acl if ((acl_existing = acl_get_file(file_path, acl_type)) == NULL) { Log(LOG_LEVEL_VERBOSE, "No ACL for '%s' could be read. (acl_get_file: %s)", file_path, GetErrorStr()); return false; } // allocate memory for temp ace (it needs to reside in a temp acl) if ((acl_tmp = acl_init(1)) == NULL) { Log(LOG_LEVEL_ERR, "New ACL could not be allocated (acl_init: %s)", GetErrorStr()); acl_free((void *) acl_existing); return false; } if (acl_create_entry(&acl_tmp, &ace_parsed) != 0) { Log(LOG_LEVEL_ERR, "New ACL could not be allocated (acl_create_entry: %s)", GetErrorStr()); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); return false; } // copy existing aces if we are appending if (method == ACL_METHOD_APPEND) { if ((acl_new = acl_dup(acl_existing)) == NULL) { Log(LOG_LEVEL_ERR, "Error copying existing ACL (acl_dup: %s)", GetErrorStr()); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); return false; } } else // overwrite existing acl { if ((acl_new = acl_init(5)) == NULL) // TODO: Always OK with 5 here ? { Log(LOG_LEVEL_ERR, "New ACL could not be allocated (acl_init: %s)", GetErrorStr()); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); return false; } } for (rp = aces; rp != NULL; rp = rp->next) { cf_ace = RlistScalarValue(rp); if (!ParseEntityPosixLinux(&cf_ace, ace_parsed, &has_mask)) { Log(LOG_LEVEL_ERR, "Error parsing entity in 'cf_ace'."); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); acl_free((void *) acl_new); return false; } // check if an ACE with this entity-type and id already exist in the Posix Linux ACL ace_current = FindACE(acl_new, ace_parsed); // create new entry in ACL if it did not exist if (ace_current == NULL) { if (acl_create_entry(&acl_new, &ace_current) != 0) { Log(LOG_LEVEL_ERR, "Failed to allocate ace (acl_create_entry: %s)", GetErrorStr()); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); acl_free((void *) acl_new); return false; } // copy parsed entity-type and id if (acl_copy_entry(ace_current, ace_parsed) != 0) { Log(LOG_LEVEL_ERR, "Error copying Linux entry in 'cf_ace' (acl_copy_entry: %s)", GetErrorStr()); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); acl_free((void *) acl_new); return false; } // clear ace_current's permissions to avoid ace_parsed from last // loop iteration to be taken into account when applying mode below if ((acl_get_permset(ace_current, &perms) != 0)) { Log(LOG_LEVEL_ERR, "Error obtaining permset for 'ace_current' (acl_get_permset: %s)", GetErrorStr()); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); acl_free((void *) acl_new); return false; } if (acl_clear_perms(perms) != 0) { Log(LOG_LEVEL_ERR, "Error clearing permset for 'ace_current'. (acl_clear_perms: %s)", GetErrorStr()); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); acl_free((void *) acl_new); return false; } } // mode string should be prefixed with an entry seperator if (*cf_ace != ':') { Log(LOG_LEVEL_ERR, "No separator before mode-string in 'cf_ace'"); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); acl_free((void *) acl_new); return false; } cf_ace += 1; if (acl_get_permset(ace_current, &perms) != 0) { Log(LOG_LEVEL_ERR, "Error obtaining permset for 'cf_ace'"); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); acl_free((void *) acl_new); return false; } if (!ParseModePosixLinux(cf_ace, perms)) { Log(LOG_LEVEL_ERR, "Error parsing mode-string in 'cf_ace'"); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); acl_free((void *) acl_new); return false; } // only allow permissions exist on posix acls, so we do // not check what follows next } // if no mask exists, calculate one (or both?): run acl_calc_mask and add one if (!has_mask) { if (acl_calc_mask(&acl_new) != 0) { Log(LOG_LEVEL_ERR, "Error calculating new acl mask"); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); acl_free((void *) acl_new); return false; } } if ((retv = ACLEquals(acl_existing, acl_new)) == -1) { Log(LOG_LEVEL_ERR, "Error while comparing existing and new ACL, unable to repair."); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); acl_free((void *) acl_new); return false; } if (retv == 1) // existing and new acl differ, update existing { switch (a.transaction.action) { case cfa_warn: cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_WARN, pp, a, "%s ACL on file '%s' needs to be updated", acl_type_str, file_path); *result = PromiseResultUpdate(*result, PROMISE_RESULT_WARN); break; case cfa_fix: if (!DONTDO) { if ((retv = acl_set_file(file_path, acl_type, acl_new)) != 0) { Log(LOG_LEVEL_ERR, "Error setting new %s ACL on file '%s' (acl_set_file: %s), are required ACEs present ?", acl_type_str, file_path, GetErrorStr()); acl_free((void *) acl_existing); acl_free((void *) acl_tmp); acl_free((void *) acl_new); return false; } } cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_CHANGE, pp, a, "%s ACL on '%s' successfully changed.", acl_type_str, file_path); *result = PromiseResultUpdate(*result, PROMISE_RESULT_CHANGE); break; default: ProgrammingError("CFEngine: internal error: illegal file action"); } } else { cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_NOOP, pp, a, "'%s' ACL on '%s' needs no modification.", acl_type_str, file_path); } acl_free((void *) acl_existing); acl_free((void *) acl_new); acl_free((void *) acl_tmp); return true; }
static int CheckDefaultEqualsAccessACL(EvalContext *ctx, const char *file_path, Attributes a, const Promise *pp, PromiseResult *result) { acl_t acl_access; acl_t acl_default; int equals; int retval = false; acl_access = NULL; acl_default = NULL; if ((acl_access = acl_get_file(file_path, ACL_TYPE_ACCESS)) == NULL) { Log(LOG_LEVEL_ERR, "Could not find an ACL for '%s'. (acl_get_file: %s)", file_path, GetErrorStr()); return false; } acl_default = acl_get_file(file_path, ACL_TYPE_DEFAULT); if (acl_default == NULL) { Log(LOG_LEVEL_ERR, "Could not find default ACL for '%s'. (acl_get_file: %s)", file_path, GetErrorStr()); acl_free(acl_access); return false; } equals = ACLEquals(acl_access, acl_default); switch (equals) { case 0: // they equal, as desired cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_NOOP, pp, a, "Default ACL on '%s' needs no modification.", file_path); retval = true; break; case 1: // set access ACL as default ACL switch (a.transaction.action) { case cfa_warn: cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_WARN, pp, a, "Default ACL on '%s' needs to be copied from access ACL.", file_path); *result = PromiseResultUpdate(*result, PROMISE_RESULT_WARN); break; case cfa_fix: if (!DONTDO) { if ((acl_set_file(file_path, ACL_TYPE_DEFAULT, acl_access)) != 0) { Log(LOG_LEVEL_ERR, "Could not set default ACL to access"); acl_free(acl_access); acl_free(acl_default); return false; } } cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_CHANGE, pp, a, "Default ACL on '%s' successfully copied from access ACL.", file_path); *result = PromiseResultUpdate(*result, PROMISE_RESULT_CHANGE); retval = true; break; default: ProgrammingError("CFEngine: internal error: illegal file action"); retval = false; } break; default: retval = false; Log(LOG_LEVEL_ERR, "Unable to compare access and default ACEs"); } acl_free(acl_access); acl_free(acl_default); return retval; }
static int CheckDefaultEqualsAccessACL(char *file_path, Attributes a, Promise *pp) { acl_t acl_access; acl_t acl_default; int equals; int result = false; acl_access = NULL; acl_default = NULL; if ((acl_access = acl_get_file(file_path, ACL_TYPE_ACCESS)) == NULL) { CfOut(OUTPUT_LEVEL_ERROR, "acl_get_file", "Could not find an ACL for %s", file_path); return false; } acl_default = acl_get_file(file_path, ACL_TYPE_DEFAULT); if (acl_default == NULL) { CfOut(OUTPUT_LEVEL_ERROR, "acl_get_file", "Could not find default ACL for %s", file_path); acl_free(acl_access); return false; } equals = ACLEquals(acl_access, acl_default); switch (equals) { case 0: // they equal, as desired cfPS(OUTPUT_LEVEL_INFORM, CF_NOP, "", pp, a, "-> Default ACL on \"%s\" needs no modification.", file_path); result = true; break; case 1: // set access ACL as default ACL switch (a.transaction.action) { case cfa_warn: cfPS(OUTPUT_LEVEL_ERROR, CF_WARN, "", pp, a, " !! Default ACL on \"%s\" needs to be copied from access ACL.", file_path); break; case cfa_fix: if (!DONTDO) { if ((acl_set_file(file_path, ACL_TYPE_DEFAULT, acl_access)) != 0) { CfOut(OUTPUT_LEVEL_ERROR, "", "!! Could not set default ACL to access"); acl_free(acl_access); acl_free(acl_default); return false; } } cfPS(OUTPUT_LEVEL_INFORM, CF_CHG, "", pp, a, "-> Default ACL on \"%s\" successfully copied from access ACL.", file_path); result = true; break; default: ProgrammingError("Cfengine: internal error: illegal file action\n"); result = false; } break; default: result = false; CfOut(OUTPUT_LEVEL_ERROR, "", "!! Unable to compare access and default ACEs"); } acl_free(acl_access); acl_free(acl_default); return result; }