static void test_parse_object_simple(void **state) { const char *data = OBJECT_SIMPLE; JsonElement *obj = JsonParse(&data); assert_string_equal(JsonObjectGetAsString(obj, "second"), "two"); assert_string_equal(JsonObjectGetAsString(obj, "first"), "one"); assert_int_equal(JsonObjectGetAsString(obj, "third"), NULL); JsonElementDestroy(obj); }
static void test_object_get_string(void) { JsonElement *obj = JsonObjectCreate(10); JsonObjectAppendString(obj, "first", "one"); JsonObjectAppendString(obj, "second", "two"); assert_string_equal(JsonObjectGetAsString(obj, "second"), "two"); assert_string_equal(JsonObjectGetAsString(obj, "first"), "one"); JsonDestroy(obj); }
static void test_parse_object_compound(void **state) { const char *data = OBJECT_COMPOUND; JsonElement *obj = JsonParse(&data); assert_string_equal(JsonObjectGetAsString(obj, "first"), "one"); JsonElement *second = JsonObjectGetAsObject(obj, "second"); assert_string_equal(JsonObjectGetAsString(second, "third"), "three"); JsonElement *fourth = JsonObjectGetAsObject(obj, "fourth"); assert_string_equal(JsonObjectGetAsString(fourth, "fifth"), "five"); JsonElementDestroy(obj); }
static void test_parse_array_object(void **state) { const char *data = ARRAY_OBJECT; JsonElement *arr = JsonParse(&data); JsonElement *first = JsonArrayGetAsObject(arr, 0); assert_string_equal(JsonObjectGetAsString(first, "first"), "one"); JsonElementDestroy(arr); }
static void test_parse_array_object(void) { const char *data = ARRAY_OBJECT; JsonElement *arr = NULL; assert_int_equal(JSON_PARSE_OK, JsonParse(&data, &arr)); JsonElement *first = JsonArrayGetAsObject(arr, 0); assert_string_equal(JsonObjectGetAsString(first, "first"), "one"); JsonDestroy(arr); }
static void test_merge_object(void) { JsonElement *a = JsonObjectCreate(2); JsonObjectAppendString(a, "a", "a"); JsonObjectAppendString(a, "b", "b"); JsonElement *b = JsonObjectCreate(2); JsonObjectAppendString(b, "b", "b"); JsonObjectAppendString(b, "c", "c"); JsonElement *c = JsonMerge(a, b); assert_int_equal(2, JsonLength(a)); assert_int_equal(2, JsonLength(b)); assert_int_equal(3, JsonLength(c)); assert_string_equal("a", JsonObjectGetAsString(c, "a")); assert_string_equal("b", JsonObjectGetAsString(c, "b")); assert_string_equal("c", JsonObjectGetAsString(c, "c")); JsonDestroy(a); JsonDestroy(b); JsonDestroy(c); }
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); }
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); }
Rval RvalNewRewriter(const void *item, RvalType type, JsonElement *map) { switch (type) { case RVAL_TYPE_SCALAR: if (NULL != map && JsonLength(map) > 0 && // do we have a rewrite map? (strstr(item, "$(") || strstr(item, "${"))) // are there unresolved variable references? { // TODO: replace with BufferSearchAndReplace when the // string_replace code is merged. // Sorry about the CF_BUFSIZE ugliness. int max_size = 10*CF_BUFSIZE+1; char *buffer_from = xmalloc(max_size); char *buffer_to = xmalloc(max_size); Buffer *format = BufferNew(); strncpy(buffer_from, item, max_size); for (int iteration = 0; iteration < 10; iteration++) { bool replacement_made = false; int var_start = -1; char closing_brace = 0; for (int c = 0; c < buffer_from[c]; c++) { printf("In %s at %i: '%s'\n", __func__, __LINE__, buffer_from); if (buffer_from[c] == '$') { if (buffer_from[c+1] == '(') { closing_brace = ')'; } else if (buffer_from[c+1] == '{') { closing_brace = '}'; } if (closing_brace) { c++; var_start = c-1; } } else if (var_start >= 0 && buffer_from[c] == closing_brace) { char saved = buffer_from[c]; buffer_from[c] = '\0'; const char *repl = JsonObjectGetAsString(map, buffer_from + var_start + 2); buffer_from[c] = saved; if (repl) { // Before the replacement. memcpy(buffer_to, buffer_from, var_start); // The actual replacement. int repl_len = strlen(repl); memcpy(buffer_to + var_start, repl, repl_len); // The text after. strlcpy(buffer_to + var_start + repl_len, buffer_from + c + 1, max_size - var_start - repl_len); // Reset location to immediately after the replacement. c = var_start + repl_len - 1; var_start = -1; strcpy(buffer_from, buffer_to); closing_brace = 0; replacement_made = true; } } } if (!replacement_made) { break; } } char *ret = xstrdup(buffer_to); BufferDestroy(format); free(buffer_to); free(buffer_from); return (Rval) { ret, RVAL_TYPE_SCALAR }; } else { return (Rval) { xstrdup(item), RVAL_TYPE_SCALAR }; } case RVAL_TYPE_FNCALL: return (Rval) { FnCallCopyRewriter(item, map), RVAL_TYPE_FNCALL }; case RVAL_TYPE_LIST: return (Rval) { RlistCopyRewriter(item, map), RVAL_TYPE_LIST }; case RVAL_TYPE_CONTAINER: return (Rval) { JsonCopy(item), RVAL_TYPE_CONTAINER }; case RVAL_TYPE_NOPROMISEE: return ((Rval) {NULL, type}); } assert(false); return ((Rval) { NULL, RVAL_TYPE_NOPROMISEE }); }
Policy *LoadPolicy(EvalContext *ctx, GenericAgentConfig *config) { StringSet *parsed_files_and_checksums = StringSetNew(); StringSet *failed_files = StringSetNew(); Policy *policy = LoadPolicyFile(ctx, config, config->input_file, parsed_files_and_checksums, failed_files); if (StringSetSize(failed_files) > 0) { Log(LOG_LEVEL_ERR, "There are syntax errors in policy files"); exit(EXIT_FAILURE); } StringSetDestroy(parsed_files_and_checksums); StringSetDestroy(failed_files); { Seq *errors = SeqNew(100, PolicyErrorDestroy); if (PolicyCheckPartial(policy, errors)) { if (!config->bundlesequence && (PolicyIsRunnable(policy) || config->check_runnable)) { Log(LOG_LEVEL_VERBOSE, "Running full policy integrity checks"); PolicyCheckRunnable(ctx, policy, errors, config->ignore_missing_bundles); } } if (SeqLength(errors) > 0) { Writer *writer = FileWriter(stderr); for (size_t i = 0; i < errors->length; i++) { PolicyErrorWrite(writer, errors->data[i]); } WriterClose(writer); exit(EXIT_FAILURE); // TODO: do not exit } SeqDestroy(errors); } if (LogGetGlobalLevel() >= LOG_LEVEL_VERBOSE) { ShowContext(ctx); } if (policy) { for (size_t i = 0; i < SeqLength(policy->bundles); i++) { Bundle *bp = SeqAt(policy->bundles, i); EvalContextStackPushBundleFrame(ctx, bp, NULL, false); for (size_t j = 0; j < SeqLength(bp->promise_types); j++) { PromiseType *sp = SeqAt(bp->promise_types, j); EvalContextStackPushPromiseTypeFrame(ctx, sp); for (size_t ppi = 0; ppi < SeqLength(sp->promises); ppi++) { Promise *pp = SeqAt(sp->promises, ppi); ExpandPromise(ctx, pp, CommonEvalPromise, NULL); } EvalContextStackPopFrame(ctx); } EvalContextStackPopFrame(ctx); } PolicyResolve(ctx, policy, config); // TODO: need to move this inside PolicyCheckRunnable eventually. if (!config->bundlesequence && config->check_runnable) { // only verify policy-defined bundlesequence for cf-agent, cf-promises if ((config->agent_type == AGENT_TYPE_AGENT) || (config->agent_type == AGENT_TYPE_COMMON)) { if (!VerifyBundleSequence(ctx, policy, config)) { FatalError(ctx, "Errors in promise bundles: could not verify bundlesequence"); } } } } JsonElement *validated_doc = ReadReleaseIdFileFromInputs(); if (validated_doc) { const char *release_id = JsonObjectGetAsString(validated_doc, "releaseId"); if (release_id) { policy->release_id = xstrdup(release_id); } JsonDestroy(validated_doc); } return policy; }
/* Inserts an Rlist node with value #rval, right after the rlist node #node. */ void RlistInsertAfter(Rlist *node, Rval rval) { assert(node != NULL); Rlist new_node = { .val = rval, .next = node->next }; node->next = xmemdup(&new_node, sizeof(new_node)); } Rval RvalNewRewriter(const void *item, RvalType type, JsonElement *map) { switch (type) { case RVAL_TYPE_SCALAR: if (map != NULL && JsonLength(map) > 0 && // do we have a rewrite map? (strstr(item, "$(") || strstr(item, "${"))) // are there unresolved variable references? { // TODO: replace with BufferSearchAndReplace when the // string_replace code is merged. // Sorry about the CF_BUFSIZE ugliness. int max_size = 10*CF_BUFSIZE+1; char *buffer_from = xmalloc(max_size); char *buffer_to = xmalloc(max_size); Buffer *format = BufferNew(); StringCopy(item, buffer_from, max_size); for (int iteration = 0; iteration < 10; iteration++) { bool replacement_made = false; int var_start = -1; char closing_brace = 0; for (int c = 0; c < buffer_from[c]; c++) { if (buffer_from[c] == '$') { if (buffer_from[c+1] == '(') { closing_brace = ')'; } else if (buffer_from[c+1] == '{') { closing_brace = '}'; } if (closing_brace) { c++; var_start = c-1; } } else if (var_start >= 0 && buffer_from[c] == closing_brace) { char saved = buffer_from[c]; buffer_from[c] = '\0'; const char *repl = JsonObjectGetAsString(map, buffer_from + var_start + 2); buffer_from[c] = saved; if (repl) { // Before the replacement. memcpy(buffer_to, buffer_from, var_start); // The actual replacement. int repl_len = strlen(repl); memcpy(buffer_to + var_start, repl, repl_len); // The text after. strlcpy(buffer_to + var_start + repl_len, buffer_from + c + 1, max_size - var_start - repl_len); // Reset location to immediately after the replacement. c = var_start + repl_len - 1; var_start = -1; StringCopy(buffer_to, buffer_from, max_size); closing_brace = 0; replacement_made = true; } } } if (!replacement_made) { break; } } char *ret = xstrdup(buffer_to); BufferDestroy(format); free(buffer_to); free(buffer_from); return (Rval) { ret, RVAL_TYPE_SCALAR }; } else { return (Rval) { xstrdup(item), RVAL_TYPE_SCALAR }; } case RVAL_TYPE_FNCALL: return (Rval) { FnCallCopyRewriter(item, map), RVAL_TYPE_FNCALL }; case RVAL_TYPE_LIST: return (Rval) { RlistCopyRewriter(item, map), RVAL_TYPE_LIST }; case RVAL_TYPE_CONTAINER: return (Rval) { JsonCopy(item), RVAL_TYPE_CONTAINER }; case RVAL_TYPE_NOPROMISEE: return ((Rval) {NULL, type}); } assert(false); return ((Rval) { NULL, RVAL_TYPE_NOPROMISEE }); } Rval RvalNew(const void *item, RvalType type) { return RvalNewRewriter(item, type, NULL); } Rval RvalCopyRewriter(Rval rval, JsonElement *map) { return RvalNewRewriter(rval.item, rval.type, map); } Rval RvalCopy(Rval rval) { return RvalNew(rval.item, rval.type); } /*******************************************************************/ Rlist *RlistCopyRewriter(const Rlist *rp, JsonElement *map) { Rlist *start = NULL; while (rp != NULL) { RlistAppendRval(&start, RvalCopyRewriter(rp->val, map)); rp = rp->next; } return start; }