Buffer *StringSetToBuffer(StringSet *set, const char delimiter) { Buffer *buf = BufferNew(); StringSetIterator it = StringSetIteratorInit(set); const char *element = NULL; int pos = 0; int size = StringSetSize(set); char minibuf[2]; minibuf[0] = delimiter; minibuf[1] = '\0'; while ((element = StringSetIteratorNext(&it))) { BufferAppend(buf, element, strlen(element)); if (pos < size-1) { BufferAppend(buf, minibuf, sizeof(char)); } pos++; } return buf; }
Policy *GenericAgentLoadPolicy(EvalContext *ctx, GenericAgentConfig *config) { config->policy_last_read_attempt = time(NULL); StringSet *parsed_files = StringSetNew(); StringSet *failed_files = StringSetNew(); Policy *policy = LoadPolicyFile(ctx, config, config->input_file, parsed_files, failed_files); if (StringSetSize(failed_files) > 0) { Log(LOG_LEVEL_ERR, "There are syntax errors in policy files"); exit(EXIT_FAILURE); } StringSetDestroy(parsed_files); 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) { VerifyPromises(ctx, policy, config); } return policy; }
static void execd_config_full_cb(const EvalContext *ctx, const Policy *policy) { ExecdConfig *config = ExecdConfigNew(ctx, policy); assert_int_equal(2, StringSetSize(config->schedule)); assert_int_equal(true, StringSetContains(config->schedule, "Min00_05")); assert_int_equal(true, StringSetContains(config->schedule, "Min05_10")); /* Splay calculation uses FQNAME and getuid(), so can't predict actual splay value */ assert_int_equal(true, config->splay_time>=0 && config->splay_time<60); assert_string_equal("LOG_LOCAL6", config->log_facility); ExecdConfigDestroy(config); }
JsonElement *StringSetToJson(const StringSet *set) { JsonElement *arr = JsonArrayCreate(StringSetSize(set)); StringSetIterator it = StringSetIteratorInit((StringSet *)set); const char *el = NULL; while ((el = StringSetIteratorNext(&it))) { JsonArrayAppendString(arr, el); } return arr; }
static void TestCheckConfigIsDefault(ExecConfig *c) { assert_int_equal(10800, c->agent_expireafter); assert_string_equal("", c->exec_command); assert_string_equal("LOG_USER",c->log_facility); assert_string_equal("",c->mail_from_address); assert_int_equal(30, c->mail_max_lines); assert_string_equal("", c->mail_server); assert_string_equal("",c->mail_to_address); assert_string_equal("",c->mail_subject); assert_int_equal(0, c->splay_time); assert_int_equal(12, StringSetSize(c->schedule)); }
static void execd_config_empty_cb(const EvalContext *ctx, const Policy *policy) { ExecdConfig *config = ExecdConfigNew(ctx, policy); assert_int_equal(12, StringSetSize(config->schedule)); assert_int_equal(true, StringSetContains(config->schedule, "Min00")); assert_int_equal(true, StringSetContains(config->schedule, "Min05")); assert_int_equal(true, StringSetContains(config->schedule, "Min10")); assert_int_equal(true, StringSetContains(config->schedule, "Min15")); assert_int_equal(true, StringSetContains(config->schedule, "Min20")); assert_int_equal(true, StringSetContains(config->schedule, "Min25")); assert_int_equal(true, StringSetContains(config->schedule, "Min30")); assert_int_equal(true, StringSetContains(config->schedule, "Min35")); assert_int_equal(true, StringSetContains(config->schedule, "Min40")); assert_int_equal(true, StringSetContains(config->schedule, "Min45")); assert_int_equal(true, StringSetContains(config->schedule, "Min50")); assert_int_equal(true, StringSetContains(config->schedule, "Min55")); assert_int_equal(0, config->splay_time); assert_string_equal("LOG_USER", config->log_facility); ExecdConfigDestroy(config); }
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; }
static int SelectProcess(EvalContext *ctx, char *procentry, char **names, int *start, int *end, ProcessSelect a) { int result = true, i; char *column[CF_PROCCOLS]; Rlist *rp; StringSet *process_select_attributes = StringSetNew(); if (!SplitProcLine(procentry, names, start, end, column)) { return false; } for (i = 0; names[i] != NULL; i++) { Log(LOG_LEVEL_DEBUG, "In SelectProcess, COL[%s] = '%s'", names[i], column[i]); } for (rp = a.owner; rp != NULL; rp = rp->next) { if (SelectProcRegexMatch(ctx, "USER", "UID", RlistScalarValue(rp), names, column)) { StringSetAdd(process_select_attributes, xstrdup("process_owner")); break; } } if (SelectProcRangeMatch("PID", "PID", a.min_pid, a.max_pid, names, column)) { StringSetAdd(process_select_attributes, xstrdup("pid")); } if (SelectProcRangeMatch("PPID", "PPID", a.min_ppid, a.max_ppid, names, column)) { StringSetAdd(process_select_attributes, xstrdup("ppid")); } if (SelectProcRangeMatch("PGID", "PGID", a.min_pgid, a.max_pgid, names, column)) { StringSetAdd(process_select_attributes, xstrdup("pgid")); } if (SelectProcRangeMatch("VSZ", "SZ", a.min_vsize, a.max_vsize, names, column)) { StringSetAdd(process_select_attributes, xstrdup("vsize")); } if (SelectProcRangeMatch("RSS", "RSS", a.min_rsize, a.max_rsize, names, column)) { StringSetAdd(process_select_attributes, xstrdup("rsize")); } if (SelectProcTimeCounterRangeMatch("TIME", "TIME", a.min_ttime, a.max_ttime, names, column)) { StringSetAdd(process_select_attributes, xstrdup("ttime")); } if (SelectProcTimeAbsRangeMatch ("STIME", "START", a.min_stime, a.max_stime, names, column)) { StringSetAdd(process_select_attributes, xstrdup("stime")); } if (SelectProcRangeMatch("NI", "PRI", a.min_pri, a.max_pri, names, column)) { StringSetAdd(process_select_attributes, xstrdup("priority")); } if (SelectProcRangeMatch("NLWP", "NLWP", a.min_thread, a.max_thread, names, column)) { StringSetAdd(process_select_attributes, xstrdup("threads")); } if (SelectProcRegexMatch(ctx, "S", "STAT", a.status, names, column)) { StringSetAdd(process_select_attributes, xstrdup("status")); } if (SelectProcRegexMatch(ctx, "CMD", "COMMAND", a.command, names, column)) { StringSetAdd(process_select_attributes, xstrdup("command")); } if (SelectProcRegexMatch(ctx, "TTY", "TTY", a.tty, names, column)) { StringSetAdd(process_select_attributes, xstrdup("tty")); } if (!a.process_result) { if (StringSetSize(process_select_attributes) == 0) { result = EvalProcessResult("", process_select_attributes); } else { Writer *w = StringWriter(); StringSetIterator iter = StringSetIteratorInit(process_select_attributes); char *attr = StringSetIteratorNext(&iter); WriterWrite(w, attr); while ((attr = StringSetIteratorNext(&iter))) { WriterWriteChar(w, '.'); WriterWrite(w, attr); } result = EvalProcessResult(StringWriterData(w), process_select_attributes); WriterClose(w); } } else { result = EvalProcessResult(a.process_result, process_select_attributes); } StringSetDestroy(process_select_attributes); for (i = 0; column[i] != NULL; i++) { free(column[i]); } return result; }
static bool SelectProcess(const char *procentry, time_t pstime, char **names, int *start, int *end, const char *process_regex, ProcessSelect a, bool attrselect) { bool result = true; char *column[CF_PROCCOLS]; Rlist *rp; assert(process_regex); StringSet *process_select_attributes = StringSetNew(); memset(column, 0, sizeof(column)); if (!SplitProcLine(procentry, pstime, names, start, end, PS_COLUMN_ALGORITHM[VPSHARDCLASS], column)) { result = false; goto cleanup; } ApplyPlatformExtraTable(names, column); for (int i = 0; names[i] != NULL; i++) { Log(LOG_LEVEL_DEBUG, "In SelectProcess, COL[%s] = '%s'", names[i], column[i]); } if (!SelectProcRegexMatch("CMD", "COMMAND", process_regex, false, names, column)) { result = false; goto cleanup; } if (!attrselect) { // If we are not considering attributes, then the matching is done. goto cleanup; } for (rp = a.owner; rp != NULL; rp = rp->next) { if (SelectProcRegexMatch("USER", "UID", RlistScalarValue(rp), true, names, column)) { StringSetAdd(process_select_attributes, xstrdup("process_owner")); break; } } if (SelectProcRangeMatch("PID", "PID", a.min_pid, a.max_pid, names, column)) { StringSetAdd(process_select_attributes, xstrdup("pid")); } if (SelectProcRangeMatch("PPID", "PPID", a.min_ppid, a.max_ppid, names, column)) { StringSetAdd(process_select_attributes, xstrdup("ppid")); } if (SelectProcRangeMatch("PGID", "PGID", a.min_pgid, a.max_pgid, names, column)) { StringSetAdd(process_select_attributes, xstrdup("pgid")); } if (SelectProcRangeMatch("VSZ", "SZ", a.min_vsize, a.max_vsize, names, column)) { StringSetAdd(process_select_attributes, xstrdup("vsize")); } if (SelectProcRangeMatch("RSS", "RSS", a.min_rsize, a.max_rsize, names, column)) { StringSetAdd(process_select_attributes, xstrdup("rsize")); } if (SelectProcTimeCounterRangeMatch("TIME", "TIME", a.min_ttime, a.max_ttime, names, column)) { StringSetAdd(process_select_attributes, xstrdup("ttime")); } if (SelectProcTimeAbsRangeMatch ("STIME", "START", a.min_stime, a.max_stime, names, column)) { StringSetAdd(process_select_attributes, xstrdup("stime")); } if (SelectProcRangeMatch("NI", "PRI", a.min_pri, a.max_pri, names, column)) { StringSetAdd(process_select_attributes, xstrdup("priority")); } if (SelectProcRangeMatch("NLWP", "NLWP", a.min_thread, a.max_thread, names, column)) { StringSetAdd(process_select_attributes, xstrdup("threads")); } if (SelectProcRegexMatch("S", "STAT", a.status, true, names, column)) { StringSetAdd(process_select_attributes, xstrdup("status")); } if (SelectProcRegexMatch("CMD", "COMMAND", a.command, true, names, column)) { StringSetAdd(process_select_attributes, xstrdup("command")); } if (SelectProcRegexMatch("TTY", "TTY", a.tty, true, names, column)) { StringSetAdd(process_select_attributes, xstrdup("tty")); } if (!a.process_result) { if (StringSetSize(process_select_attributes) == 0) { result = EvalProcessResult("", process_select_attributes); } else { Writer *w = StringWriter(); StringSetIterator iter = StringSetIteratorInit(process_select_attributes); char *attr = StringSetIteratorNext(&iter); WriterWrite(w, attr); while ((attr = StringSetIteratorNext(&iter))) { WriterWriteChar(w, '.'); WriterWrite(w, attr); } result = EvalProcessResult(StringWriterData(w), process_select_attributes); WriterClose(w); } } else { result = EvalProcessResult(a.process_result, process_select_attributes); } cleanup: StringSetDestroy(process_select_attributes); for (int i = 0; column[i] != NULL; i++) { free(column[i]); } return result; }
static void test_load(void) { GenericAgentConfig *agent_config = GenericAgentConfigNewDefault(AGENT_TYPE_EXECUTOR); ExecConfig *c = ExecConfigNewDefault(true, "host", "ip"); assert_true(c->scheduled_run); assert_string_equal("host", c->fq_name); assert_string_equal("ip", c->ip_address); TestCheckConfigIsDefault(c); EvalContext *ctx = EvalContextNew(); { VarRef *lval = VarRefParse("g.host"); EvalContextVariablePut(ctx, lval, "snookie", DATA_TYPE_STRING, NULL); VarRefDestroy(lval); } // provide a full body executor control and check that all options are collected { Policy *p = LoadPolicy("body_executor_control_full.cf"); PolicyResolve(ctx, p, agent_config); ExecConfigUpdate(ctx, p, c); assert_true(c->scheduled_run); assert_string_equal("host", c->fq_name); assert_string_equal("ip", c->ip_address); assert_int_equal(120, c->agent_expireafter); assert_string_equal("/bin/echo", c->exec_command); assert_string_equal("LOG_LOCAL6",c->log_facility); assert_string_equal("*****@*****.**",c->mail_from_address); assert_int_equal(50, c->mail_max_lines); assert_string_equal("localhost", c->mail_server); assert_string_equal("*****@*****.**",c->mail_to_address); assert_string_equal("Test [localhost/127.0.0.1]",c->mail_subject); // splay time hard to test (pseudo random) assert_int_equal(2, StringSetSize(c->schedule)); assert_true(StringSetContains(c->schedule, "Min00_05")); assert_true(StringSetContains(c->schedule, "Min05_10")); PolicyDestroy(p); } // provide a small policy and check that missing settings are being reverted to default { { Policy *p = LoadPolicy("body_executor_control_agent_expireafter_only.cf"); PolicyResolve(ctx, p, agent_config); ExecConfigUpdate(ctx, p, c); assert_true(c->scheduled_run); assert_string_equal("host", c->fq_name); assert_string_equal("ip", c->ip_address); assert_int_equal(121, c->agent_expireafter); // rest should be default assert_string_equal("", c->exec_command); assert_string_equal("LOG_USER",c->log_facility); assert_string_equal("",c->mail_from_address); assert_int_equal(30, c->mail_max_lines); assert_string_equal("", c->mail_server); assert_string_equal("",c->mail_to_address); assert_string_equal("",c->mail_subject); assert_int_equal(0, c->splay_time); assert_int_equal(12, StringSetSize(c->schedule)); PolicyDestroy(p); } } EvalContextDestroy(ctx); GenericAgentConfigDestroy(agent_config); }
static void test_class_persistence(void) { EvalContext *ctx = EvalContextNew(); // simulate old version { CF_DB *dbp; PersistentClassInfo i; assert_true(OpenDB(&dbp, dbid_state)); i.expires = UINT_MAX; i.policy = CONTEXT_STATE_POLICY_RESET; WriteDB(dbp, "old", &i, sizeof(PersistentClassInfo)); CloseDB(dbp); } // e.g. by monitoring EvalContextHeapPersistentSave(ctx, "class1", 3, CONTEXT_STATE_POLICY_PRESERVE, "a,b"); // e.g. by a class promise in a bundle with a namespace { Policy *p = PolicyNew(); Bundle *bp = PolicyAppendBundle(p, "ns1", "bundle1", "agent", NULL, NULL); EvalContextStackPushBundleFrame(ctx, bp, NULL, false); EvalContextHeapPersistentSave(ctx, "class2", 5, CONTEXT_STATE_POLICY_PRESERVE, "x"); EvalContextStackPopFrame(ctx); PolicyDestroy(p); } EvalContextHeapPersistentLoadAll(ctx); { const Class *cls = EvalContextClassGet(ctx, "default", "old"); assert_true(cls != NULL); assert_string_equal("old", cls->name); assert_true(cls->tags != NULL); assert_int_equal(1, StringSetSize(cls->tags)); assert_true(StringSetContains(cls->tags, "source=persistent")); } { const Class *cls = EvalContextClassGet(ctx, "default", "class1"); assert_true(cls != NULL); assert_string_equal("class1", cls->name); assert_true(cls->tags != NULL); assert_int_equal(3, StringSetSize(cls->tags)); assert_true(StringSetContains(cls->tags, "source=persistent")); assert_true(StringSetContains(cls->tags, "a")); assert_true(StringSetContains(cls->tags, "b")); } { const Class *cls = EvalContextClassGet(ctx, "ns1", "class2"); assert_true(cls != NULL); assert_string_equal("ns1", cls->ns); assert_string_equal("class2", cls->name); assert_true(cls->tags != NULL); assert_int_equal(2, StringSetSize(cls->tags)); assert_true(StringSetContains(cls->tags, "source=persistent")); assert_true(StringSetContains(cls->tags, "x")); } EvalContextDestroy(ctx); }