static void ShowVariablesFormatted(EvalContext *ctx) { VariableTableIterator *iter = EvalContextVariableTableIteratorNew(ctx, NULL, NULL, NULL); Variable *v = NULL; Seq *seq = SeqNew(2000, free); while ((v = VariableTableIteratorNext(iter))) { char *varname = VarRefToString(v->ref, true); Writer *w = StringWriter(); switch (DataTypeToRvalType(v->type)) { case RVAL_TYPE_CONTAINER: JsonWriteCompact(w, RvalContainerValue(v->rval)); break; default: RvalWrite(w, v->rval); } const char *var_value; if (StringIsPrintable(StringWriterData(w))) { var_value = StringWriterData(w); } else { var_value = "<non-printable>"; } StringSet *tagset = EvalContextVariableTags(ctx, v->ref); Buffer *tagbuf = StringSetToBuffer(tagset, ','); char *line; xasprintf(&line, "%-40s %-60s %-40s", varname, var_value, BufferData(tagbuf)); SeqAppend(seq, line); BufferDestroy(tagbuf); WriterClose(w); free(varname); } SeqSort(seq, (SeqItemComparator)strcmp, NULL); printf("%-40s %-60s %-40s\n", "Variable name", "Variable value", "Meta tags"); for (size_t i = 0; i < SeqLength(seq); i++) { const char *variable = SeqAt(seq, i); printf("%s\n", variable); } SeqDestroy(seq); VariableTableIteratorDestroy(iter); }
void test_file_read_truncate(void) { char expected_output[FILE_SIZE + 1]; bool truncated = false; Writer *w = FileRead(FILE_NAME, FILE_SIZE - 1, &truncated); assert_int_equal(StringWriterLength(w), FILE_SIZE - 1); strlcpy(expected_output, FILE_CONTENTS, FILE_SIZE); assert_string_equal(StringWriterData(w), expected_output); assert_int_equal(truncated, true); WriterClose(w); bool truncated2 = false; Writer *w2 = FileRead(FILE_NAME, 10, &truncated2); assert_int_equal(StringWriterLength(w2), 10); strlcpy(expected_output, FILE_CONTENTS, 11); assert_string_equal(StringWriterData(w2), expected_output); assert_int_equal(truncated2, true); WriterClose(w2); bool truncated3 = false; Writer *w3 = FileRead(FILE_NAME, 1, &truncated3); assert_int_equal(StringWriterLength(w3), 1); strlcpy(expected_output, FILE_CONTENTS, 2); assert_string_equal(StringWriterData(w3), expected_output); assert_int_equal(truncated3, true); WriterClose(w3); }
static const char *ReferenceEnd(const char *str, size_t len) { assert(len > 1); assert(str[0] == '$'); assert(str[1] == '{' || str[1] == '('); #define MAX_VARIABLE_REFERENCE_LEVELS 10 char stack[MAX_VARIABLE_REFERENCE_LEVELS] = { 0, str[1], 0 }; int level = 1; for (size_t i = 2; i < len; i++) { switch (str[i]) { case '{': case '(': if (level < MAX_VARIABLE_REFERENCE_LEVELS - 1) { level++; stack[level] = str[i]; } else { Log(LOG_LEVEL_ERR, "Stack overflow in variable reference parsing. More than %d levels", MAX_VARIABLE_REFERENCE_LEVELS); return NULL; } break; case '}': if (stack[level] != '{') { Writer *w = StringWriter(); WriterWriteLen(w, str, len); Log(LOG_LEVEL_ERR, "Variable reference bracket mismatch '%s'", StringWriterData(w)); WriterClose(w); return NULL; } level--; break; case ')': if (stack[level] != '(') { Writer *w = StringWriter(); WriterWriteLen(w, str, len); Log(LOG_LEVEL_ERR, "Variable reference bracket mismatch '%s'", StringWriterData(w)); WriterClose(w); return NULL; } level--; break; } if (level == 0) { return str + i; } } return NULL; }
bool ExtractScalarReference(Buffer *out, const char *str, size_t len, bool extract_inner) { if (len <= 1) { return false; } const char *dollar_point = memchr(str, '$', len); if (!dollar_point || (dollar_point - str) == len) { return false; } else { const char *close_point = NULL; { size_t remaining = len - (dollar_point - str); if (*(dollar_point + 1) == '{' || *(dollar_point + 1) == '(') { close_point = ReferenceEnd(dollar_point, remaining); } else { return ExtractScalarReference(out, dollar_point + 1, remaining - 1, extract_inner); } } if (!close_point) { Writer *w = StringWriter(); WriterWriteLen(w, str, len); Log(LOG_LEVEL_ERR, "Variable reference close mismatch '%s'", StringWriterData(w)); WriterClose(w); return false; } size_t outer_len = close_point - dollar_point + 1; if (outer_len <= 3) { Writer *w = StringWriter(); WriterWriteLen(w, str, len); Log(LOG_LEVEL_ERR, "Empty variable reference close mismatch '%s'", StringWriterData(w)); WriterClose(w); return false; } if (extract_inner) { BufferAppend(out, dollar_point + 2, outer_len - 3); } else { BufferAppend(out, dollar_point, outer_len); } return true; } }
static bool VerifyBundleSequence(EvalContext *ctx, const Policy *policy, const GenericAgentConfig *config) { Rlist *rp; char *name; Rval retval; int ok = true; FnCall *fp; if (!EvalContextVariableControlCommonGet(ctx, COMMON_CONTROL_BUNDLESEQUENCE, &retval)) { Log(LOG_LEVEL_ERR, " No bundlesequence in the common control body"); return false; } if (retval.type != RVAL_TYPE_LIST) { FatalError(ctx, "Promised bundlesequence was not a list"); } for (rp = (Rlist *) retval.item; rp != NULL; rp = rp->next) { switch (rp->type) { case RVAL_TYPE_SCALAR: name = (char *) rp->item; break; case RVAL_TYPE_FNCALL: fp = (FnCall *) rp->item; name = (char *) fp->name; break; default: name = NULL; ok = false; { Writer *w = StringWriter(); WriterWrite(w, "Illegal item found in bundlesequence '"); RvalWrite(w, (Rval) {rp->item, rp->type}); WriterWrite(w, "'"); Log(LOG_LEVEL_ERR, "%s", StringWriterData(w)); WriterClose(w); } break; } if (strcmp(name, CF_NULL_VALUE) == 0) { continue; } if (!config->ignore_missing_bundles && !PolicyGetBundle(policy, NULL, NULL, name)) { Log(LOG_LEVEL_ERR, "Bundle '%s' listed in the bundlesequence is not a defined bundle", name); ok = false; } } return ok; }
static void test_show_object_compound(void **state) { JsonElement *json = JsonObjectCreate(10); JsonObjectAppendString(json, "first", "one"); { JsonElement *inner = JsonObjectCreate(10); JsonObjectAppendString(inner, "third", "three"); JsonObjectAppendObject(json, "second", inner); } { JsonElement *inner = JsonObjectCreate(10); JsonObjectAppendString(inner, "fifth", "five"); JsonObjectAppendObject(json, "fourth", inner); } Writer *writer = StringWriter(); JsonElementPrint(writer, json, 0); assert_string_equal(OBJECT_COMPOUND, StringWriterData(writer)); JsonElementDestroy(json); }
static void LogPromiseContext(const EvalContext *ctx, const Promise *pp) { Rval retval; char *v; if (EvalContextVariableControlCommonGet(ctx, COMMON_CONTROL_VERSION, &retval)) { v = (char *) retval.item; } else { v = "not specified"; } const char *sp = PromiseGetHandle(pp); if (sp == NULL) { sp = PromiseID(pp); } if (sp == NULL) { sp = "(unknown)"; } Log(LOG_LEVEL_INFO, "Report relates to a promise with handle '%s'", sp); if (PromiseGetBundle(pp)->source_path) { Log(LOG_LEVEL_INFO, "Made in version '%s' of '%s' near line %zu", v, PromiseGetBundle(pp)->source_path, pp->offset.line); } else { Log(LOG_LEVEL_INFO, "Promise is made internally by CFEngine"); } switch (pp->promisee.type) { case RVAL_TYPE_SCALAR: Log(LOG_LEVEL_INFO,"The promise was made to '%s'", (char *) pp->promisee.item); break; case RVAL_TYPE_LIST: { Writer *w = StringWriter(); RlistWrite(w, pp->promisee.item); Log(LOG_LEVEL_INFO, "The promise was made to (stakeholders) '%s'", StringWriterData(w)); WriterClose(w); break; } default: break; } if (pp->comment) { Log(LOG_LEVEL_INFO, "Comment '%s'", pp->comment); } }
static void Nova_DumpSlots(void) { #define MAX_KEY_FILE_SIZE 16384 /* usually around 4000, cannot grow much */ char filename[CF_BUFSIZE]; int i; snprintf(filename, CF_BUFSIZE - 1, "%s%cts_key", GetStateDir(), FILE_SEPARATOR); char file_contents_new[MAX_KEY_FILE_SIZE] = {0}; for (i = 0; i < CF_OBSERVABLES; i++) { char line[CF_MAXVARSIZE]; if (NovaHasSlot(i)) { snprintf(line, sizeof(line), "%d,%s,%s,%s,%.3lf,%.3lf,%d\n", i, NULLStringToEmpty((char*)NovaGetSlotName(i)), NULLStringToEmpty((char*)NovaGetSlotDescription(i)), NULLStringToEmpty((char*)NovaGetSlotUnits(i)), NovaGetSlotExpectedMinimum(i), NovaGetSlotExpectedMaximum(i), NovaIsSlotConsolidable(i) ? 1 : 0); } else { snprintf(line, sizeof(line), "%d,spare,unused\n", i); } strlcat(file_contents_new, line, sizeof(file_contents_new)); } bool contents_changed = true; Writer *w = FileRead(filename, MAX_KEY_FILE_SIZE, NULL); if (w) { if(strcmp(StringWriterData(w), file_contents_new) == 0) { contents_changed = false; } WriterClose(w); } if(contents_changed) { Log(LOG_LEVEL_VERBOSE, "Updating %s with new slot information", filename); if(!FileWriteOver(filename, file_contents_new)) { Log(LOG_LEVEL_ERR, "Nova_DumpSlots: Could not write file '%s'. (FileWriteOver: %s)", filename, GetErrorStr()); } } chmod(filename, 0600); }
void test_file_read_all(void) { bool truncated; Writer *w = FileRead(FILE_NAME, FILE_SIZE, &truncated); assert_int_equal(StringWriterLength(w), FILE_SIZE); assert_string_equal(StringWriterData(w), FILE_CONTENTS); assert_int_equal(truncated, false); WriterClose(w); Writer *w2 = FileRead(FILE_NAME, FILE_SIZE * 10, &truncated); assert_int_equal(StringWriterLength(w2), FILE_SIZE); assert_string_equal(StringWriterData(w2), FILE_CONTENTS); assert_int_equal(truncated, false); WriterClose(w2); Writer *w3 = FileRead(FILE_NAME, FILE_SIZE * 10, NULL); assert_int_equal(StringWriterLength(w3), FILE_SIZE); assert_string_equal(StringWriterData(w3), FILE_CONTENTS); WriterClose(w3); }
static void test_show_array_empty(void **state) { JsonElement *array = JsonArrayCreate(10); Writer *writer = StringWriter(); JsonElementPrint(writer, array, 0); assert_string_equal("[]", StringWriterData(writer)); JsonElementDestroy(array); }
static bool VerifyBundleSequence(EvalContext *ctx, const Policy *policy, const GenericAgentConfig *config) { Rlist *fallback = NULL; const Rlist *bundlesequence = EvalContextVariableControlCommonGet(ctx, COMMON_CONTROL_BUNDLESEQUENCE); if (!bundlesequence) { RlistAppendScalar(&fallback, "main"); bundlesequence = fallback; } const char *name; int ok = true; for (const Rlist *rp = bundlesequence; rp != NULL; rp = rp->next) { switch (rp->val.type) { case RVAL_TYPE_SCALAR: name = RlistScalarValue(rp); break; case RVAL_TYPE_FNCALL: name = RlistFnCallValue(rp)->name; break; default: name = NULL; ok = false; { Writer *w = StringWriter(); WriterWrite(w, "Illegal item found in bundlesequence '"); RvalWrite(w, rp->val); WriterWrite(w, "'"); Log(LOG_LEVEL_ERR, "%s", StringWriterData(w)); WriterClose(w); } continue; } if (strcmp(name, CF_NULL_VALUE) == 0) { continue; } if (!config->ignore_missing_bundles && !PolicyGetBundle(policy, NULL, NULL, name)) { Log(LOG_LEVEL_ERR, "Bundle '%s' listed in the bundlesequence is not a defined bundle", name); ok = false; } } RlistDestroy(fallback); return ok; }
void test_empty_file_buffer(void **p) { global_w = StringWriter(); global_w_closed = false; Writer *w = FileWriter(NULL); assert_int_equal(StringWriterLength(global_w), 0); assert_string_equal(StringWriterData(global_w), ""); WriterClose(w); WriterClose(global_w); assert_int_equal(global_w_closed, true); }
void test_write_file_buffer(void **p) { global_w = StringWriter(); Writer *w = FileWriter(NULL); WriterWrite(w, "123"); assert_int_equal(StringWriterLength(global_w), 3); assert_string_equal(StringWriterData(global_w), "123"); WriterClose(w); WriterClose(global_w); assert_int_equal(global_w_closed, true); }
void test_file_read_empty(void) { int creat_fd = creat(FILE_NAME_EMPTY, 0600); assert_true(creat_fd > -1); int close_res = close(creat_fd); assert_int_equal(close_res, 0); bool truncated = true; Writer *w = FileRead(FILE_NAME_EMPTY, 100, &truncated); assert_int_equal(StringWriterLength(w), 0); assert_string_equal(StringWriterData(w), ""); assert_int_equal(truncated, false); }
static void test_show_object_escaped(void **state) { JsonElement *json = JsonObjectCreate(10); JsonObjectAppendString(json, "escaped", "quote\"stuff \t \n\n"); Writer *writer = StringWriter(); JsonElementPrint(writer, json, 0); assert_string_equal(OBJECT_ESCAPED, StringWriterData(writer)); JsonElementDestroy(json); }
static void test_show_array(void **state) { JsonElement *array = JsonArrayCreate(10); JsonArrayAppendString(array, "one"); JsonArrayAppendString(array, "two"); Writer *writer = StringWriter(); JsonElementPrint(writer, array, 0); assert_string_equal(ARRAY_SIMPLE, StringWriterData(writer)); JsonElementDestroy(array); }
static void test_show_object_simple(void **state) { JsonElement *json = JsonObjectCreate(10); JsonObjectAppendString(json, "first", "one"); JsonObjectAppendString(json, "second", "two"); Writer *writer = StringWriter(); JsonElementPrint(writer, json, 0); assert_string_equal(OBJECT_SIMPLE, StringWriterData(writer)); JsonElementDestroy(json); }
static void test_show_object_numeric(void **state) { JsonElement *json = JsonObjectCreate(10); JsonObjectAppendReal(json, "real", 1234.5678); JsonObjectAppendInteger(json, "int", -1234567890); Writer *writer = StringWriter(); JsonElementPrint(writer, json, 0); assert_string_equal(OBJECT_NUMERIC, StringWriterData(writer)); JsonElementDestroy(json); }
static bool RenderVariableContainer(Buffer *out, const JsonElement *container, bool compact) { Writer *w = StringWriter(); if (compact) { JsonWriteCompact(w, container); } else { JsonWrite(w, container, 0); } BufferAppendString(out, StringWriterData(w)); WriterClose(w); return true; }
static void test_show_array_object(void **state) { JsonElement *array = JsonArrayCreate(10); JsonElement *object = JsonObjectCreate(10); JsonObjectAppendString(object, "first", "one"); JsonArrayAppendObject(array, object); Writer *writer = StringWriter(); JsonElementPrint(writer, array, 0); assert_string_equal(ARRAY_OBJECT, StringWriterData(writer)); JsonElementDestroy(array); }
static void LogPromiseContext(const EvalContext *ctx, const Promise *pp) { Writer *w = StringWriter(); WriterWrite(w, "Additional promise info:"); if (PromiseGetHandle(pp)) { WriterWriteF(w, " handle '%s'", PromiseGetHandle(pp)); } { Rval retval; if (EvalContextVariableControlCommonGet(ctx, COMMON_CONTROL_VERSION, &retval)) { WriterWriteF(w, " version '%s'", RvalScalarValue(retval)); } } if (PromiseGetBundle(pp)->source_path) { WriterWriteF(w, " source path '%s' at line %zu", PromiseGetBundle(pp)->source_path, pp->offset.line); } switch (pp->promisee.type) { case RVAL_TYPE_SCALAR: WriterWriteF(w, " promisee '%s'", RvalScalarValue(pp->promisee)); break; case RVAL_TYPE_LIST: WriterWrite(w, " promisee "); RlistWrite(w, pp->promisee.item); break; default: break; } if (pp->comment) { WriterWriteF(w, " comment '%s'", pp->comment); } Log(LOG_LEVEL_VERBOSE, "%s", StringWriterData(w)); WriterClose(w); }
static void test_parse_object_escaped(void **state) { const char *escaped_string = "\\\"/var/cfenigne/bin/cf-know\\\" "; const char *key = "json_element_key"; Writer *writer = StringWriter(); WriterWriteF(writer, "{ \"%s\" : \"%s\" }", key, escaped_string); const char *json_string = StringWriterData(writer); JsonElement *obj = JsonParse(&json_string); assert_int_not_equal(obj, NULL); assert_string_equal(JsonObjectGetAsString(obj, key), escaped_string); WriterClose(writer); JsonElementDestroy(obj); }
void BannerSubBundle(const Bundle *bp, const Rlist *params) { if (!LEGACY_OUTPUT) { return; } Log(LOG_LEVEL_VERBOSE, " * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *"); Log(LOG_LEVEL_VERBOSE, " BUNDLE %s", bp->name); if (params) { Writer *w = StringWriter(); RlistWrite(w, params); Log(LOG_LEVEL_VERBOSE, "(%s)", StringWriterData(w)); WriterClose(w); } Log(LOG_LEVEL_VERBOSE, " * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *"); }
static void test_show_object_array(void **state) { JsonElement *json = JsonObjectCreate(10); JsonElement *array = JsonArrayCreate(10); JsonArrayAppendString(array, "one"); JsonArrayAppendString(array, "two"); JsonObjectAppendArray(json, "first", array); Writer *writer = StringWriter(); JsonElementPrint(writer, json, 0); assert_string_equal(OBJECT_ARRAY, StringWriterData(writer)); JsonElementDestroy(json); }
static JsonElement *LoadTestFile(const char *filename) { char path[1024]; sprintf(path, "%s/%s", TESTDATADIR, filename); Writer *w = FileRead(path, SIZE_MAX, NULL); if (!w) { return NULL; } JsonElement *json = NULL; const char *data = StringWriterData(w); if (JsonParse(&data, &json) != JSON_PARSE_OK) { WriterClose(w); return NULL; } WriterClose(w); return json; }
static void test_parse_object_escaped(void) { const char *decoded = "\"/var/cfenigne/bin/cf-know\" "; const char *json_string = "{\n \"key\": \"\\\"/var/cfenigne/bin/cf-know\\\" \"\n}"; JsonElement *obj = NULL; const char *data = json_string; assert_int_equal(JSON_PARSE_OK, JsonParse(&data, &obj)); assert_int_not_equal(obj, NULL); assert_string_equal(JsonObjectGetAsString(obj, "key"), decoded); { Writer *w = StringWriter(); JsonWrite(w, obj, 0); assert_string_equal(json_string, StringWriterData(w)); WriterClose(w); } JsonDestroy(obj); }
static void ShowContext(EvalContext *ctx) { { Writer *w = NULL; if (LEGACY_OUTPUT) { w = FileWriter(stdout); WriterWriteF(w, "%s> -> Hard classes = {", VPREFIX); } else { w = StringWriter(); WriterWrite(w, "Discovered hard classes:"); } Seq *hard_contexts = SeqNew(1000, NULL); SetIterator it = EvalContextHeapIteratorHard(ctx); char *context = NULL; while ((context = SetIteratorNext(&it))) { if (!EvalContextHeapContainsNegated(ctx, context)) { SeqAppend(hard_contexts, context); } } SeqSort(hard_contexts, (SeqItemComparator)strcmp, NULL); for (size_t i = 0; i < SeqLength(hard_contexts); i++) { const char *context = SeqAt(hard_contexts, i); WriterWriteF(w, " %s", context); } if (LEGACY_OUTPUT) { WriterWrite(w, "}\n"); FileWriterDetach(w); } else { Log(LOG_LEVEL_VERBOSE, "%s", StringWriterData(w)); WriterClose(w); } SeqDestroy(hard_contexts); } { Writer *w = NULL; if (LEGACY_OUTPUT) { w = FileWriter(stdout); WriterWriteF(w, "%s> -> Additional classes = {", VPREFIX); } else { w = StringWriter(); WriterWrite(w, "Additional classes:"); } Seq *soft_contexts = SeqNew(1000, NULL); SetIterator it = EvalContextHeapIteratorSoft(ctx); char *context = NULL; while ((context = SetIteratorNext(&it))) { if (!EvalContextHeapContainsNegated(ctx, context)) { SeqAppend(soft_contexts, context); } } SeqSort(soft_contexts, (SeqItemComparator)strcmp, NULL); for (size_t i = 0; i < SeqLength(soft_contexts); i++) { const char *context = SeqAt(soft_contexts, i); WriterWriteF(w, " %s", context); } if (LEGACY_OUTPUT) { WriterWrite(w, "}\n"); FileWriterDetach(w); } else { if (SeqLength(soft_contexts) > 0) { Log(LOG_LEVEL_VERBOSE, "%s", StringWriterData(w)); } WriterClose(w); } SeqDestroy(soft_contexts); } { bool have_negated_classes = false; Writer *w = NULL; if (LEGACY_OUTPUT) { w = FileWriter(stdout); WriterWriteF(w, "%s> -> Negated classes = {", VPREFIX); } else { w = StringWriter(); WriterWrite(w, "Negated classes:"); } StringSetIterator it = EvalContextHeapIteratorNegated(ctx); const char *context = NULL; while ((context = StringSetIteratorNext(&it))) { WriterWriteF(w, " %s", context); have_negated_classes = true; } if (LEGACY_OUTPUT) { WriterWrite(w, "}\n"); FileWriterDetach(w); } else { if (have_negated_classes) { Log(LOG_LEVEL_VERBOSE, "%s", StringWriterData(w)); } WriterClose(w); } } }
PromiseResult ScheduleEditOperation(EvalContext *ctx, char *filename, Attributes a, Promise *pp) { void *vp; FnCall *fp; Rlist *args = NULL; char edit_bundle_name[CF_BUFSIZE], lockname[CF_BUFSIZE], qualified_edit[CF_BUFSIZE], *method_deref; CfLock thislock; snprintf(lockname, CF_BUFSIZE - 1, "fileedit-%s", filename); thislock = AcquireLock(ctx, lockname, VUQNAME, CFSTARTTIME, a.transaction, pp, false); if (thislock.lock == NULL) { return PROMISE_RESULT_NOOP; } EditContext *edcontext = NewEditContext(filename, a); PromiseResult result = PROMISE_RESULT_NOOP; if (edcontext == NULL) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "File '%s' was marked for editing but could not be opened", filename); result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL); goto exit; } Policy *policy = PolicyFromPromise(pp); if (a.haveeditline) { if ((vp = ConstraintGetRvalValue(ctx, "edit_line", pp, RVAL_TYPE_FNCALL))) { fp = (FnCall *) vp; strcpy(edit_bundle_name, fp->name); args = fp->args; } else if ((vp = ConstraintGetRvalValue(ctx, "edit_line", pp, RVAL_TYPE_SCALAR))) { strcpy(edit_bundle_name, (char *) vp); args = NULL; } else { goto exit; } if (strncmp(edit_bundle_name,"default:",strlen("default:")) == 0) // CF_NS == ':' { method_deref = strchr(edit_bundle_name, CF_NS) + 1; } else if ((strchr(edit_bundle_name, CF_NS) == NULL) && (strcmp(PromiseGetNamespace(pp), "default") != 0)) { snprintf(qualified_edit, CF_BUFSIZE, "%s%c%s", PromiseGetNamespace(pp), CF_NS, edit_bundle_name); method_deref = qualified_edit; } else { method_deref = edit_bundle_name; } Log(LOG_LEVEL_VERBOSE, "Handling file edits in edit_line bundle '%s'", method_deref); Bundle *bp = NULL; if ((bp = PolicyGetBundle(policy, NULL, "edit_line", method_deref))) { BannerSubBundle(bp, args); EvalContextStackPushBundleFrame(ctx, bp, args, a.edits.inherit); BundleResolve(ctx, bp); ScheduleEditLineOperations(ctx, bp, a, pp, edcontext); EvalContextStackPopFrame(ctx); } else { Log(LOG_LEVEL_ERR, "Did not find method '%s' in bundle '%s' for edit operation", method_deref, edit_bundle_name); } } if (a.haveeditxml) { if ((vp = ConstraintGetRvalValue(ctx, "edit_xml", pp, RVAL_TYPE_FNCALL))) { fp = (FnCall *) vp; strcpy(edit_bundle_name, fp->name); args = fp->args; } else if ((vp = ConstraintGetRvalValue(ctx, "edit_xml", pp, RVAL_TYPE_SCALAR))) { strcpy(edit_bundle_name, (char *) vp); args = NULL; } else { goto exit; } if (strncmp(edit_bundle_name,"default:",strlen("default:")) == 0) // CF_NS == ':' { method_deref = strchr(edit_bundle_name, CF_NS) + 1; } else { method_deref = edit_bundle_name; } Log(LOG_LEVEL_VERBOSE, "Handling file edits in edit_xml bundle '%s'", method_deref); Bundle *bp = NULL; if ((bp = PolicyGetBundle(policy, NULL, "edit_xml", method_deref))) { BannerSubBundle(bp, args); EvalContextStackPushBundleFrame(ctx, bp, args, a.edits.inherit); BundleResolve(ctx, bp); ScheduleEditXmlOperations(ctx, bp, a, pp, edcontext); EvalContextStackPopFrame(ctx); } } if (a.edit_template) { if (!a.template_method || strcmp("cfengine", a.template_method) == 0) { Policy *tmp_policy = PolicyNew(); Bundle *bp = NULL; if ((bp = MakeTemporaryBundleFromTemplate(ctx, tmp_policy, a, pp, &result))) { BannerSubBundle(bp, args); a.haveeditline = true; EvalContextStackPushBundleFrame(ctx, bp, args, a.edits.inherit); BundleResolve(ctx, bp); ScheduleEditLineOperations(ctx, bp, a, pp, edcontext); EvalContextStackPopFrame(ctx); } PolicyDestroy(tmp_policy); } else if (strcmp("mustache", a.template_method) == 0) { if (!FileCanOpen(a.edit_template, "r")) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Template file '%s' could not be opened for reading", a.edit_template); result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL); goto exit; } Writer *ouput_writer = NULL; { FILE *output_file = fopen(pp->promiser, "w"); if (!output_file) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Output file '%s' could not be opened for writing", pp->promiser); result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL); goto exit; } ouput_writer = FileWriter(output_file); } Writer *template_writer = FileRead(a.edit_template, SIZE_MAX, NULL); if (!template_writer) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Could not read template file '%s'", a.edit_template); result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL); WriterClose(ouput_writer); goto exit; } JsonElement *default_template_data = NULL; if (!a.template_data) { a.template_data = default_template_data = DefaultTemplateData(ctx); } if (!MustacheRender(ouput_writer, StringWriterData(template_writer), a.template_data)) { cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Error rendering mustache template '%s'", a.edit_template); result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL); WriterClose(template_writer); WriterClose(ouput_writer); goto exit; } JsonDestroy(default_template_data); WriterClose(template_writer); WriterClose(ouput_writer); } } exit: result = PromiseResultUpdate(result, FinishEditContext(ctx, edcontext, a, pp)); YieldCurrentLock(thislock); return result; }
FnCallResult FnCallEvaluate(EvalContext *ctx, const Policy *policy, FnCall *fp, const Promise *caller) { assert(ctx); assert(policy); assert(fp); fp->caller = caller; if (!EvalContextGetEvalOption(ctx, EVAL_OPTION_EVAL_FUNCTIONS)) { Log(LOG_LEVEL_VERBOSE, "Skipping function '%s', because evaluation was turned off in the evaluator", fp->name); return (FnCallResult) { FNCALL_FAILURE, { FnCallCopy(fp), RVAL_TYPE_FNCALL } }; } const FnCallType *fp_type = FnCallTypeGet(fp->name); if (!fp_type) { if (caller) { Log(LOG_LEVEL_ERR, "No such FnCall '%s' in promise '%s' near line %zd", fp->name, PromiseGetBundle(caller)->source_path, caller->offset.line); } else { Log(LOG_LEVEL_ERR, "No such FnCall '%s', context info unavailable", fp->name); } return (FnCallResult) { FNCALL_FAILURE, { FnCallCopy(fp), RVAL_TYPE_FNCALL } }; } Rlist *expargs = NewExpArgs(ctx, policy, fp, fp_type); Writer *fncall_writer = NULL; const char *fncall_string = ""; if (LogGetGlobalLevel() >= LOG_LEVEL_DEBUG) { fncall_writer = StringWriter(); FnCallWrite(fncall_writer, fp); fncall_string = StringWriterData(fncall_writer); } // Check if arguments are resolved, except for delayed evaluation functions if ( ! (fp_type->options & FNCALL_OPTION_DELAYED_EVALUATION) && RlistIsUnresolved(expargs)) { // Special case: ifelse(isvariable("x"), $(x), "default") // (the first argument will come down expanded as "!any") if (strcmp(fp->name, "ifelse") == 0 && RlistLen(expargs) == 3 && strcmp("!any", RlistScalarValueSafe(expargs)) == 0 && !RlistIsUnresolved(expargs->next->next)) { Log(LOG_LEVEL_DEBUG, "Allowing ifelse() function evaluation even" " though its arguments contain unresolved variables: %s", fncall_string); } else { if (LogGetGlobalLevel() >= LOG_LEVEL_DEBUG) { Log(LOG_LEVEL_DEBUG, "Skipping function evaluation for now," " arguments contain unresolved variables: %s", fncall_string); WriterClose(fncall_writer); } RlistDestroy(expargs); return (FnCallResult) { FNCALL_FAILURE, { FnCallCopy(fp), RVAL_TYPE_FNCALL } }; } } Rval cached_rval; if ((fp_type->options & FNCALL_OPTION_CACHED) && EvalContextFunctionCacheGet(ctx, fp, expargs, &cached_rval)) { if (LogGetGlobalLevel() >= LOG_LEVEL_DEBUG) { Log(LOG_LEVEL_DEBUG, "Using previously cached result for function: %s", fncall_string); WriterClose(fncall_writer); } Writer *w = StringWriter(); FnCallWrite(w, fp); WriterClose(w); RlistDestroy(expargs); return (FnCallResult) { FNCALL_SUCCESS, RvalCopy(cached_rval) }; } if (LogGetGlobalLevel() >= LOG_LEVEL_DEBUG) { Log(LOG_LEVEL_DEBUG, "Evaluating function: %s", fncall_string); WriterClose(fncall_writer); } FnCallResult result = CallFunction(ctx, policy, fp, expargs); if (result.status == FNCALL_FAILURE) { RlistDestroy(expargs); return (FnCallResult) { FNCALL_FAILURE, { FnCallCopy(fp), RVAL_TYPE_FNCALL } }; } if (fp_type->options & FNCALL_OPTION_CACHED) { Writer *w = StringWriter(); FnCallWrite(w, fp); Log(LOG_LEVEL_VERBOSE, "Caching result for function '%s'", StringWriterData(w)); WriterClose(w); EvalContextFunctionCachePut(ctx, fp, expargs, &result.rval); } RlistDestroy(expargs); return result; }
/* * The difference between filename and input_input file is that the latter is the file specified by -f or * equivalently the file containing body common control. This will hopefully be squashed in later refactoring. */ static Policy *Cf3ParseFile(const GenericAgentConfig *config, const char *input_path) { struct stat statbuf; if (stat(input_path, &statbuf) == -1) { if (config->ignore_missing_inputs) { return PolicyNew(); } Log(LOG_LEVEL_ERR, "Can't stat file '%s' for parsing. (stat: %s)", input_path, GetErrorStr()); exit(EXIT_FAILURE); } else if (S_ISDIR(statbuf.st_mode)) { if (config->ignore_missing_inputs) { return PolicyNew(); } Log(LOG_LEVEL_ERR, "Can't parse directory '%s'.", input_path); exit(EXIT_FAILURE); } #ifndef _WIN32 if (config->check_not_writable_by_others && (statbuf.st_mode & (S_IWGRP | S_IWOTH))) { Log(LOG_LEVEL_ERR, "File %s (owner %ju) is writable by others (security exception)", input_path, (uintmax_t)statbuf.st_uid); exit(EXIT_FAILURE); } #endif Log(LOG_LEVEL_VERBOSE, "Parsing file '%s'", input_path); if (!FileCanOpen(input_path, "r")) { Log(LOG_LEVEL_ERR, "Can't open file '%s' for parsing", input_path); exit(EXIT_FAILURE); } Policy *policy = NULL; if (StringEndsWith(input_path, ".json")) { Writer *contents = FileRead(input_path, SIZE_MAX, NULL); if (!contents) { Log(LOG_LEVEL_ERR, "Error reading JSON input file '%s'", input_path); return NULL; } JsonElement *json_policy = NULL; const char *data = StringWriterData(contents); if (JsonParse(&data, &json_policy) != JSON_PARSE_OK) { Log(LOG_LEVEL_ERR, "Error parsing JSON input file '%s'", input_path); WriterClose(contents); return NULL; } policy = PolicyFromJson(json_policy); JsonDestroy(json_policy); WriterClose(contents); } else { if (config->agent_type == AGENT_TYPE_COMMON) { policy = ParserParseFile(config->agent_type, input_path, config->agent_specific.common.parser_warnings, config->agent_specific.common.parser_warnings_error); } else { policy = ParserParseFile(config->agent_type, input_path, 0, 0); } } return policy; }