コード例 #1
0
ファイル: loading.c プロジェクト: ddurieux/core
// TODO: should be replaced by something not complected with loading
static void ShowContext(EvalContext *ctx)
{
    Seq *hard_contexts = SeqNew(1000, NULL);
    Seq *soft_contexts = SeqNew(1000, NULL);

    {
        ClassTableIterator *iter = EvalContextClassTableIteratorNewGlobal(ctx, NULL, true, true);
        Class *cls = NULL;
        while ((cls = ClassTableIteratorNext(iter)))
        {
            if (cls->is_soft)
            {
                SeqAppend(soft_contexts, cls->name);
            }
            else
            {
                SeqAppend(hard_contexts, cls->name);
            }
        }

        ClassTableIteratorDestroy(iter);
    }

    SeqSort(soft_contexts, (SeqItemComparator)strcmp, NULL);
    SeqSort(hard_contexts, (SeqItemComparator)strcmp, NULL);

    Log(LOG_LEVEL_VERBOSE, "----------------------------------------------------------------");

    {
        Log(LOG_LEVEL_VERBOSE, "BEGIN Discovered hard classes:");

        for (size_t i = 0; i < SeqLength(hard_contexts); i++)
        {
            const char *context = SeqAt(hard_contexts, i);
            Log(LOG_LEVEL_VERBOSE, "C: discovered hard class %s", context);
        }

        Log(LOG_LEVEL_VERBOSE, "END Discovered hard classes");
    }

    Log(LOG_LEVEL_VERBOSE, "----------------------------------------------------------------");

    if (SeqLength(soft_contexts))
    {
        Log(LOG_LEVEL_VERBOSE, "BEGIN initial soft classes:");

        for (size_t i = 0; i < SeqLength(soft_contexts); i++)
        {
            const char *context = SeqAt(soft_contexts, i);
            Log(LOG_LEVEL_VERBOSE, "C: added soft class %s", context);
        }

        Log(LOG_LEVEL_VERBOSE, "END initial soft classes");
    }

    SeqDestroy(hard_contexts);
    SeqDestroy(soft_contexts);
}
コード例 #2
0
ファイル: iteration.c プロジェクト: Kegeruneku/core
PromiseIterator *PromiseIteratorNew(EvalContext *ctx, const Promise *pp, const Rlist *lists, const Rlist *containers)
{
    PromiseIterator *iter = xmalloc(sizeof(PromiseIterator));

    iter->vars = SeqNew(RlistLen(lists), DeleteAssoc);
    iter->var_states = SeqNew(RlistLen(lists), NULL);
    iter->has_null_list = false;

    for (const Rlist *rp = lists; rp != NULL; rp = rp->next)
    {
        VarRef *ref = VarRefParseFromBundle(RlistScalarValue(rp), PromiseGetBundle(pp));

        DataType dtype = CF_DATA_TYPE_NONE;
        const void *value = EvalContextVariableGet(ctx, ref, &dtype);
        if (!value)
        {
            Log(LOG_LEVEL_ERR, "Couldn't locate variable '%s' apparently in '%s'", RlistScalarValue(rp), PromiseGetBundle(pp)->name);
            VarRefDestroy(ref);
            continue;
        }

        VarRefDestroy(ref);

        CfAssoc *new_var = NewAssoc(RlistScalarValue(rp), (Rval) { (void *)value, DataTypeToRvalType(dtype) }, dtype);
        iter->has_null_list |= !AppendIterationVariable(iter, new_var);
    }

    for (const Rlist *rp = containers; rp; rp = rp->next)
    {
        VarRef *ref = VarRefParseFromBundle(RlistScalarValue(rp), PromiseGetBundle(pp));

        DataType dtype = CF_DATA_TYPE_NONE;
        const JsonElement *value = EvalContextVariableGet(ctx, ref, &dtype);
        if (!value)
        {
            Log(LOG_LEVEL_ERR, "Couldn't locate variable '%s' apparently in '%s'", RlistScalarValue(rp), PromiseGetBundle(pp)->name);
            VarRefDestroy(ref);
            continue;
        }

        VarRefDestroy(ref);

        assert(dtype == CF_DATA_TYPE_CONTAINER);

        /* Mimics NewAssoc() but bypassing extra copying of ->rval: */
        CfAssoc *new_var = xmalloc(sizeof(CfAssoc));
        new_var->lval = xstrdup(RlistScalarValue(rp));
        new_var->rval = (Rval) { ContainerToRlist(value), RVAL_TYPE_LIST };
        new_var->dtype = CF_DATA_TYPE_STRING_LIST;

        iter->has_null_list |= !AppendIterationVariable(iter, new_var);
    }

    // We now have a control list of list-variables, with internal state in state_ptr
    return iter;
}
コード例 #3
0
ファイル: exec-config.c プロジェクト: atsaloli/core
static void SeqMailFilterFill(const Seq *input,
                              Seq **output, Seq **output_regex,
                              const char *filter_type)
{
    int len = SeqLength(input);

    *output = SeqNew(len, &free);
    *output_regex = SeqNew(len, &RegexFree);

    for (int i = 0; i < len; i++)
    {
        MailFilterFill(SeqAt(input, i), output, output_regex, filter_type);
    }
}
コード例 #4
0
static void test_failsafe(void)
{
    char *tmp = tempnam(NULL, "cfengine_test");
    WriteBuiltinFailsafePolicyToPath(tmp);

    Policy *failsafe = ParserParseFile(tmp, PARSER_WARNING_ALL, PARSER_WARNING_ALL);

    unlink(tmp);
    free(tmp);

    assert_true(failsafe);

    Seq *errs = SeqNew(10, PolicyErrorDestroy);
    PolicyCheckPartial(failsafe, errs);

    DumpErrors(errs);
    assert_int_equal(0, SeqLength(errs));

    {
        EvalContext *ctx = EvalContextNew();

        PolicyCheckRunnable(ctx, failsafe, errs, false);

        DumpErrors(errs);
        assert_int_equal(0, SeqLength(errs));

        EvalContextDestroy(ctx);
    }

    assert_int_equal(0, (SeqLength(errs)));

    SeqDestroy(errs);
    PolicyDestroy(failsafe);
}
コード例 #5
0
ファイル: cf-promises.c プロジェクト: cstroe/core
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);
}
コード例 #6
0
ファイル: cf-promises.c プロジェクト: tzz/core
static void ShowContextsFormatted(EvalContext *ctx)
{
    ClassTableIterator *iter = EvalContextClassTableIteratorNewGlobal(ctx, NULL, true, true);
    Class *cls = NULL;

    Seq *seq = SeqNew(1000, free);

    while ((cls = ClassTableIteratorNext(iter)))
    {
        char *class_name = ClassRefToString(cls->ns, cls->name);
        StringSet *tagset = EvalContextClassTags(ctx, cls->ns, cls->name);
        Buffer *tagbuf = StringSetToBuffer(tagset, ',');

        char *line;
        xasprintf(&line, "%-60s %-40s", class_name, BufferData(tagbuf));
        SeqAppend(seq, line);

        BufferDestroy(tagbuf);
        free(class_name);
    }

    SeqSort(seq, (SeqItemComparator)strcmp, NULL);

    printf("%-60s %-40s\n", "Class name", "Meta tags");

    for (size_t i = 0; i < SeqLength(seq); i++)
    {
        const char *context = SeqAt(seq, i);
        printf("%s\n", context);
    }

    SeqDestroy(seq);

    ClassTableIteratorDestroy(iter);
}
コード例 #7
0
ファイル: sequence_test.c プロジェクト: nperron/core
static void test_sort(void)
{
    Seq *seq = SeqNew(5, NULL);

    size_t one = 1;
    size_t two = 2;
    size_t three = 3;
    size_t four = 4;
    size_t five = 5;

    SeqAppend(seq, &three);
    SeqAppend(seq, &two);
    SeqAppend(seq, &five);
    SeqAppend(seq, &one);
    SeqAppend(seq, &four);

    SeqSort(seq, CompareNumbers, NULL);

    assert_int_equal(seq->data[0], &one);
    assert_int_equal(seq->data[1], &two);
    assert_int_equal(seq->data[2], &three);
    assert_int_equal(seq->data[3], &four);
    assert_int_equal(seq->data[4], &five);

    SeqDestroy(seq);
}
コード例 #8
0
ファイル: exec-config.c プロジェクト: atsaloli/core
static void RlistMailFilterFill(const Rlist *input,
                                Seq **output, Seq **output_regex,
                                const char *filter_type)
{
    int len = RlistLen(input);

    *output = SeqNew(len, &free);
    *output_regex = SeqNew(len, &RegexFree);

    const Rlist *ptr = input;
    for (int i = 0; i < len; i++)
    {
        const char *str = ptr->val.item;
        MailFilterFill(str, output, output_regex, filter_type);

        ptr = ptr->next;
    }
}
コード例 #9
0
ファイル: generic_agent.c プロジェクト: nperron/core
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;
}
コード例 #10
0
ファイル: verify_storage.c プロジェクト: cduclos/core
Seq *GetGlobalMountedFSList(void)
{
    static Seq *mounted_fs_list = NULL;
    if (!mounted_fs_list)
    {
        mounted_fs_list = SeqNew(100, free);
    }

    return mounted_fs_list;
}
コード例 #11
0
ファイル: promises.c プロジェクト: ouafae31/core
Promise *ExpandDeRefPromise(EvalContext *ctx, const char *scopeid, const Promise *pp)
{
    Promise *pcopy;
    Rval returnval, final;

    CfDebug("ExpandDerefPromise()\n");

    pcopy = xcalloc(1, sizeof(Promise));

    returnval = ExpandPrivateRval(ctx, "this", (Rval) {pp->promiser, RVAL_TYPE_SCALAR });
    pcopy->promiser = (char *) returnval.item;

    if (pp->promisee.item)
    {
        pcopy->promisee = EvaluateFinalRval(ctx, scopeid, pp->promisee, true, pp);
    }
    else
    {
        pcopy->promisee = (Rval) {NULL, RVAL_TYPE_NOPROMISEE };
    }

    if (pp->classes)
    {
        pcopy->classes = xstrdup(pp->classes);
    }
    else
    {
        pcopy->classes = xstrdup("any");
    }

    if (pcopy->promiser == NULL)
    {
        ProgrammingError("ExpandPromise returned NULL");
    }

    pcopy->parent_promise_type = pp->parent_promise_type;
    pcopy->offset.line = pp->offset.line;
    pcopy->comment = pp->comment ? xstrdup(pp->comment) : NULL;
    pcopy->conlist = SeqNew(10, ConstraintDestroy);
    pcopy->org_pp = pp->org_pp;

/* No further type checking should be necessary here, already done by CheckConstraintTypeMatch */

    for (size_t i = 0; i < SeqLength(pp->conlist); i++)
    {
        Constraint *cp = SeqAt(pp->conlist, i);

        Rval returnval;

        if (ExpectedDataType(cp->lval) == DATA_TYPE_BUNDLE)
        {
            final = ExpandBundleReference(ctx, scopeid, cp->rval);
        }
        else
        {
コード例 #12
0
Seq *SeqParseCsvString(const char *string)
{
    Seq *newlist = SeqNew(16, free);

    if (LaunchCsvAutomata(string, &newlist) != CSV_ERR_OK)
    {
        return NULL;
    }

    return newlist;
}
コード例 #13
0
static Seq *LoadAndCheck(const char *filename)
{
    Policy *p = LoadPolicy(filename);

    Seq *errs = SeqNew(10, PolicyErrorDestroy);
    PolicyCheckPartial(p, errs);

    DumpErrors(errs);

    return errs;
}
コード例 #14
0
ファイル: sequence_test.c プロジェクト: nperron/core
static Seq *SequenceCreateRange(size_t initialCapacity, size_t start, size_t end)
{
    Seq *seq = SeqNew(initialCapacity, free);

    for (size_t i = start; i <= end; i++)
    {
        size_t *item = xmalloc(sizeof(size_t));

        *item = i;
        SeqAppend(seq, item);
    }

    return seq;
}
コード例 #15
0
ファイル: expand.c プロジェクト: kkaempf/core
static void RemoveRemotelyInjectedVars(const EvalContext *ctx, const Bundle *bundle)
{
    const Seq *remote_var_promises = EvalContextGetRemoteVarPromises(ctx, bundle->name);
    if ((remote_var_promises == NULL) || SeqLength(remote_var_promises) == 0)
    {
        /* nothing to do here */
        return;
    }

    size_t promises_length = SeqLength(remote_var_promises);
    Seq *remove_vars = SeqNew(promises_length, NULL);

    /* remove variables that have been attempted to be inserted into this
     * bundle */
    /* TODO: this is expensive and should be removed! */
    for (size_t i = 0; i < promises_length; i++)
    {
        const Promise *pp = (Promise *) SeqAt(remote_var_promises, i);

        VariableTableIterator *iter = EvalContextVariableTableIteratorNew(ctx, NULL, bundle->name, NULL);
        const Variable *var = VariableTableIteratorNext(iter);
        while (var != NULL)
        {
            /* variables are stored together with their original promises (org_pp) */
            if (var->promise && var->promise->org_pp == pp)
            {
                Log(LOG_LEVEL_ERR, "Ignoring remotely-injected variable '%s'",
                    var->ref->lval);
                /* avoid modifications of the variable table being iterated
                 * over and avoid trying to remove the same variable twice */
                SeqAppendOnce(remove_vars, (void *) var, PointerCmp);
            }
            var = VariableTableIteratorNext(iter);
        }
        VariableTableIteratorDestroy(iter);
    }

    /* iteration over the variable table done, time to remove the variables */
    size_t remove_vars_length = SeqLength(remove_vars);
    for (size_t i = 0; i < remove_vars_length; i++)
    {
        Variable *var = (Variable *) SeqAt(remove_vars, i);
        if (var->ref != NULL)
        {
            EvalContextVariableRemove(ctx, var->ref);
        }
    }
    SeqDestroy(remove_vars);
}
コード例 #16
0
ファイル: env_context.c プロジェクト: shaunamarie/core
EvalContext *EvalContextNew(void)
{
    EvalContext *ctx = xmalloc(sizeof(EvalContext));

    ctx->heap_soft = StringSetNew();
    ctx->heap_hard = StringSetNew();
    ctx->heap_negated = StringSetNew();
    ctx->heap_abort = NULL;
    ctx->heap_abort_current_bundle = NULL;

    ctx->stack = SeqNew(10, StackFrameDestroy);

    ctx->dependency_handles = StringSetNew();

    return ctx;
}
コード例 #17
0
ファイル: mock_package_manager.c プロジェクト: atsaloli/core
static Seq *FindPackages(const char *database_filename, PackagePattern *pattern)
{
    Seq *db = ReadPackageEntries(database_filename);
    Seq *matching = SeqNew(1000, NULL);

    for (size_t i = 0; i < SeqLength(db); i++)
    {
        Package *package = SeqAt(db, i);

        if (MatchPackage(pattern, package))
        {
            SeqAppend(matching, package);
        }
    }

    return matching;
}
コード例 #18
0
ファイル: sequence_test.c プロジェクト: nperron/core
static void test_append(void)
{
    Seq *seq = SeqNew(2, free);

    for (size_t i = 0; i < 1000; i++)
    {
        SeqAppend(seq, xstrdup("snookie"));
    }

    assert_int_equal(seq->length, 1000);

    for (size_t i = 0; i < 1000; i++)
    {
        assert_string_equal(seq->data[i], "snookie");
    }

    SeqDestroy(seq);
}
コード例 #19
0
ファイル: sequence_test.c プロジェクト: nperron/core
static void test_len(void)
{
    Seq *seq = SeqNew(5, NULL);

    size_t one = 1;
    size_t two = 2;
    size_t three = 3;
    size_t four = 4;
    size_t five = 5;

    SeqAppend(seq, &three);
    SeqAppend(seq, &two);
    SeqAppend(seq, &five);
    SeqAppend(seq, &one);
    SeqAppend(seq, &four);

    assert_int_equal(SeqLength(seq),5);

    SeqDestroy(seq);
}
コード例 #20
0
static Seq *LoadAndCheckString(const char *policy_code)
{
    const char *tmp = tempnam(NULL, "cfengine_test");

    {
        FILE *out = fopen(tmp, "w");
        Writer *w = FileWriter(out);
        WriterWrite(w, policy_code);

        WriterClose(w);
    }

    Policy *p = ParserParseFile(tmp, PARSER_WARNING_ALL, PARSER_WARNING_ALL);
    assert_true(p);

    Seq *errs = SeqNew(10, PolicyErrorDestroy);
    PolicyCheckPartial(p, errs);

    unlink(tmp);
    return errs;
}
コード例 #21
0
ファイル: mock_package_manager.c プロジェクト: atsaloli/core
static Seq *ReadPackageEntries(const char *database_filename)
{
    FILE *packages_file = fopen(database_filename, "r");
    Seq *packages = SeqNew(1000, NULL);

    if (packages_file != NULL)
    {
        char serialized_package[MAX_PACKAGE_ENTRY_LENGTH];

        while (fscanf(packages_file, "%s\n", serialized_package) != EOF)
        {
            Package *package = DeserializePackage(serialized_package);

            SeqAppend(packages, package);
        }

        fclose(packages_file);
    }

    return packages;
}
コード例 #22
0
ファイル: mustache.c プロジェクト: amousset/core
bool MustacheRender(Buffer *out, const char *input, const JsonElement *hash)
{
    char delim_start[MUSTACHE_MAX_DELIM_SIZE] = "{{";
    size_t delim_start_len = strlen(delim_start);

    char delim_end[MUSTACHE_MAX_DELIM_SIZE] = "}}";
    size_t delim_end_len = strlen(delim_end);

    Seq *hash_stack = SeqNew(10, NULL);
    SeqAppend(hash_stack, (JsonElement*)hash);

    bool success = Render(out, input, input,
                         hash_stack,
                         delim_start, &delim_start_len,
                         delim_end, &delim_end_len,
                         false, NULL, NULL);

    SeqDestroy(hash_stack);

    return success;
}
コード例 #23
0
ファイル: promises.c プロジェクト: embedian/core
Promise *DeRefCopyPromise(EvalContext *ctx, const Promise *pp)
{
    Promise *pcopy;
    Rval returnval;

    pcopy = xcalloc(1, sizeof(Promise));

    if (pp->promiser)
    {
        pcopy->promiser = xstrdup(pp->promiser);
    }

    if (pp->promisee.item)
    {
        pcopy->promisee = RvalCopy(pp->promisee);
        if (pcopy->promisee.type == RVAL_TYPE_LIST)
        {
            Rlist *rval_list = RvalRlistValue(pcopy->promisee);
            RlistFlatten(ctx, &rval_list);
            pcopy->promisee.item = rval_list;
        }
    }

    if (pp->classes)
    {
        pcopy->classes = xstrdup(pp->classes);
    }

/* FIXME: may it happen? */
    if ((pp->promisee.item != NULL && pcopy->promisee.item == NULL))
    {
        ProgrammingError("Unable to copy promise");
    }

    pcopy->parent_promise_type = pp->parent_promise_type;
    pcopy->offset.line = pp->offset.line;
    pcopy->comment = pp->comment ? xstrdup(pp->comment) : NULL;
    pcopy->has_subbundles = pp->has_subbundles;
    pcopy->conlist = SeqNew(10, ConstraintDestroy);
    pcopy->org_pp = pp->org_pp;
    pcopy->offset = pp->offset;

/* No further type checking should be necessary here, already done by CheckConstraintTypeMatch */

    for (size_t i = 0; i < SeqLength(pp->conlist); i++)
    {
        Constraint *cp = SeqAt(pp->conlist, i);

        Body *bp = NULL;
        FnCall *fp = NULL;

        /* A body template reference could look like a scalar or fn to the parser w/w () */
        const Policy *policy = PolicyFromPromise(pp);
        Seq *bodies = policy ? policy->bodies : NULL;

        char body_ns[CF_MAXVARSIZE] = "";
        char body_name[CF_MAXVARSIZE] = "";

        switch (cp->rval.type)
        {
        case RVAL_TYPE_SCALAR:
            if (cp->references_body)
            {
                SplitScopeName(RvalScalarValue(cp->rval), body_ns, body_name);
                if (EmptyString(body_ns))
                {
                    strncpy(body_ns, PromiseGetNamespace(pp), CF_MAXVARSIZE);
                }
                bp = IsBody(bodies, body_ns, body_name);
            }
            fp = NULL;
            break;
        case RVAL_TYPE_FNCALL:
            fp = RvalFnCallValue(cp->rval);
            SplitScopeName(fp->name, body_ns, body_name);
            if (EmptyString(body_ns))
            {
                strncpy(body_ns, PromiseGetNamespace(pp), CF_MAXVARSIZE);
            }
            bp = IsBody(bodies, body_ns, body_name);
            break;
        default:
            bp = NULL;
            fp = NULL;
            break;
        }

        /* First case is: we have a body template to expand lval = body(args), .. */

        if (bp)
        {
            EvalContextStackPushBodyFrame(ctx, pcopy, bp, fp ? fp->args : NULL);

            if (strcmp(bp->type, cp->lval) != 0)
            {
                Log(LOG_LEVEL_ERR,
                    "Body type mismatch for body reference '%s' in promise at line %zu of file '%s', '%s' does not equal '%s'",
                      body_name, pp->offset.line, PromiseGetBundle(pp)->source_path, bp->type, cp->lval);
            }

            /* Keep the referent body type as a boolean for convenience when checking later */

            if (IsDefinedClass(ctx, cp->classes, PromiseGetNamespace(pcopy)))
            {
                Constraint *cp_copy = PromiseAppendConstraint(pcopy, cp->lval, (Rval) {xstrdup("true"), RVAL_TYPE_SCALAR }, false);
                cp_copy->offset = cp->offset;
            }

            if (bp->args != NULL)
            {
                /* There are arguments to insert */

                if (fp == NULL || fp->args == NULL)
                {
                    Log(LOG_LEVEL_ERR, "Argument mismatch for body reference '%s' in promise at line %zu of file '%s'",
                          body_name, pp->offset.line, PromiseGetBundle(pp)->source_path);
                }

                for (size_t k = 0; k < SeqLength(bp->conlist); k++)
                {
                    Constraint *scp = SeqAt(bp->conlist, k);

                    returnval = ExpandPrivateRval(ctx, NULL, "body", scp->rval.item, scp->rval.type);
                    if (IsDefinedClass(ctx, scp->classes, PromiseGetNamespace(pcopy)))
                    {
                        Constraint *scp_copy = PromiseAppendConstraint(pcopy, scp->lval, returnval, false);
                        scp_copy->offset = scp->offset;
                    }
                }
            }
            else
            {
                /* No arguments to deal with or body undeclared */

                if (fp != NULL)
                {
                    Log(LOG_LEVEL_ERR,
                          "An apparent body \"%s()\" was undeclared or could have incorrect args, but used in a promise near line %zu of %s (possible unquoted literal value)",
                          body_name, pp->offset.line, PromiseGetBundle(pp)->source_path);
                }
                else
                {
                    for (size_t k = 0; k < SeqLength(bp->conlist); k++)
                    {
                        Constraint *scp = SeqAt(bp->conlist, k);

                        Rval newrv = RvalCopy(scp->rval);
                        if (newrv.type == RVAL_TYPE_LIST)
                        {
                            Rlist *new_list = RvalRlistValue(newrv);
                            RlistFlatten(ctx, &new_list);
                            newrv.item = new_list;
                        }

                        if (IsDefinedClass(ctx, scp->classes, PromiseGetNamespace(pcopy)))
                        {
                            Constraint *scp_copy = PromiseAppendConstraint(pcopy, scp->lval, newrv, false);
                            scp_copy->offset = scp->offset;
                        }
                    }
                }
            }

            EvalContextStackPopFrame(ctx);
        }
        else
        {
            const Policy *policy = PolicyFromPromise(pp);

            if (cp->references_body && !IsBundle(policy->bundles, EmptyString(body_ns) ? NULL : body_ns, body_name))
            {
                Log(LOG_LEVEL_ERR,
                      "Apparent body \"%s()\" was undeclared, but used in a promise near line %zu of %s (possible unquoted literal value)",
                      body_name, pp->offset.line, PromiseGetBundle(pp)->source_path);
            }

            Rval newrv = RvalCopy(cp->rval);
            if (newrv.type == RVAL_TYPE_LIST)
            {
                Rlist *new_list = RvalRlistValue(newrv);
                RlistFlatten(ctx, &new_list);
                newrv.item = new_list;
            }

            if (IsDefinedClass(ctx, cp->classes, PromiseGetNamespace(pcopy)))
            {
                Constraint *cp_copy = PromiseAppendConstraint(pcopy, cp->lval, newrv, false);
                cp_copy->offset = cp->offset;
            }
        }
    }

    return pcopy;
}
コード例 #24
0
ファイル: cf-execd.c プロジェクト: FancsalMelinda/core
static void Apoptosis()
{
    Promise pp = { 0 };
    Rlist *signals = NULL, *owners = NULL;
    char mypid[32];
    static char promiser_buf[CF_SMALLBUF];

#if defined(_WIN32)
    return;
#endif

    CfOut(OUTPUT_LEVEL_VERBOSE, "", " !! Programmed pruning of the scheduler cluster");

#ifdef __MINGW32__
    snprintf(promiser_buf, sizeof(promiser_buf), "cf-execd");     // using '\' causes regexp problems
#else
    snprintf(promiser_buf, sizeof(promiser_buf), "%s/bin/cf-execd", CFWORKDIR);
#endif

    pp.promiser = promiser_buf;
    pp.promisee = (Rval) {"cfengine", RVAL_TYPE_SCALAR};
    pp.classes = "any";
    pp.offset.line = 0;
    pp.audit = NULL;
    pp.conlist = SeqNew(100, ConstraintDestroy);

    pp.bundletype = "agent";
    pp.bundle = "exec_apoptosis";
    pp.ref = "Programmed death";
    pp.agentsubtype = "processes";
    pp.done = false;
    pp.cache = NULL;
    pp.inode_cache = NULL;
    pp.this_server = NULL;
    pp.donep = &(pp.done);
    pp.conn = NULL;

    GetCurrentUserName(mypid, 31);

    RlistPrepend(&signals, "term", RVAL_TYPE_SCALAR);
    RlistPrepend(&owners, mypid, RVAL_TYPE_SCALAR);

    PromiseAppendConstraint(&pp, "signals", (Rval) {signals, RVAL_TYPE_LIST }, "any", false);
    PromiseAppendConstraint(&pp, "process_select", (Rval) {xstrdup("true"), RVAL_TYPE_SCALAR}, "any", false);
    PromiseAppendConstraint(&pp, "process_owner", (Rval) {owners, RVAL_TYPE_LIST }, "any", false);
    PromiseAppendConstraint(&pp, "ifelapsed", (Rval) {xstrdup("0"), RVAL_TYPE_SCALAR}, "any", false);
    PromiseAppendConstraint(&pp, "process_count", (Rval) {xstrdup("true"), RVAL_TYPE_SCALAR}, "any", false);
    PromiseAppendConstraint(&pp, "match_range", (Rval) {xstrdup("0,2"), RVAL_TYPE_SCALAR}, "any", false);
    PromiseAppendConstraint(&pp, "process_result", (Rval) {xstrdup("process_owner.process_count"), RVAL_TYPE_SCALAR}, "any", false);

    CfOut(OUTPUT_LEVEL_VERBOSE, "", " -> Looking for cf-execd processes owned by %s", mypid);

    if (LoadProcessTable(&PROCESSTABLE))
    {
        VerifyProcessesPromise(&pp);
    }

    DeleteItemList(PROCESSTABLE);

    SeqDestroy(pp.conlist);

    CfOut(OUTPUT_LEVEL_VERBOSE, "", " !! Pruning complete");
}
コード例 #25
0
ファイル: cf-testd.c プロジェクト: kkaempf/core
static void *CFTestD_ServeReport(void *config_arg)
{
    CFTestD_Config *config = (CFTestD_Config *) config_arg;

    /* Set prefix for all Log()ging: */
    LoggingPrivContext *prior = LoggingPrivGetContext();
    LoggingPrivContext log_ctx = {
        .log_hook = LogAddPrefix,
        .param = config->address
    };
    LoggingPrivSetContext(&log_ctx);

    char *priv_key_path = NULL;
    char *pub_key_path = NULL;
    if (config->key_file != NULL)
    {
        priv_key_path = config->key_file;
        pub_key_path = xstrdup(priv_key_path);
        StringReplace(pub_key_path, strlen(pub_key_path) + 1,
                      "priv", "pub");
    }

    LoadSecretKeys(priv_key_path, pub_key_path, &(config->priv_key), &(config->pub_key));
    free(pub_key_path);

    char *report_file = config->report_file;

    if (report_file != NULL)
    {
        Log(LOG_LEVEL_NOTICE, "Got file argument: '%s'", report_file);
        if (!FileCanOpen(report_file, "r"))
        {
            Log(LOG_LEVEL_ERR,
                "Can't open file '%s' for reading",
                report_file);
            exit(EXIT_FAILURE);
        }

        Writer *contents = FileRead(report_file, SIZE_MAX, NULL);
        if (!contents)
        {
            Log(LOG_LEVEL_ERR, "Error reading report file '%s'", report_file);
            exit(EXIT_FAILURE);
        }

        size_t report_data_len = StringWriterLength(contents);
        config->report_data = StringWriterClose(contents);

        Seq *report = SeqNew(64, NULL);
        size_t report_len = 0;

        StringRef ts_ref = StringGetToken(config->report_data, report_data_len, 0, "\n");
        char *ts = (char *) ts_ref.data;
        *(ts + ts_ref.len) = '\0';
        SeqAppend(report, ts);

        /* start right after the newline after the timestamp header */
        char *position = ts + ts_ref.len + 1;
        char *report_line;
        size_t report_line_len;
        while (CFTestD_GetReportLine(position, &report_line, &report_line_len))
        {
            *(report_line + report_line_len) = '\0';
            SeqAppend(report, report_line);
            report_len += report_line_len;
            position = report_line + report_line_len + 1; /* there's an extra newline after each report_line */
        }

        config->report = report;
        config->report_len = report_len;

        Log(LOG_LEVEL_NOTICE,
            "Read %d bytes for report contents",
            config->report_len);

        if (config->report_len <= 0)
        {
            Log(LOG_LEVEL_ERR, "Report file contained no bytes");
            exit(EXIT_FAILURE);
        }
    }

    Log(LOG_LEVEL_INFO, "Starting server at %s...", config->address);
    fflush(stdout); // for debugging startup

    config->ret = CFTestD_StartServer(config);

    free(config->report_data);

    /* we don't really need to do this here because the process is about the
     * terminate, but it's a good way the cleanup actually works and doesn't
     * cause a segfault or something */
    ServerTLSDeInitialize(&(config->priv_key), &(config->pub_key), &(config->ssl_ctx));

    LoggingPrivSetContext(prior);

    return NULL;
}

static void HandleSignal(int signum)
{
    switch (signum)
    {
    case SIGTERM:
    case SIGINT:
        // flush all logging before process ends.
        fflush(stdout);
        fprintf(stderr, "Terminating...\n");
        TERMINATE = true;
        break;
    default:
        break;
    }
}

/**
 * @param ip_str string representation of an IPv4 address (the usual one, with
 *               4 octets separated by dots)
 * @return a new string representing the incremented IP address (HAS TO BE FREED)
 */
static char *IncrementIPaddress(const char *ip_str)
{
    uint32_t ip = (uint32_t) inet_addr(ip_str);
    if (ip == INADDR_NONE)
    {
        Log(LOG_LEVEL_ERR, "Failed to parse address: '%s'", ip_str);
        return NULL;
    }

    int step = 1;
    char *last_dot = strrchr(ip_str, '.');
    assert(last_dot != NULL);   /* the doc comment says there must be dots! */
    if (StringSafeEqual(last_dot + 1, "255"))
    {
        /* avoid the network address (ending with 0) */
        step = 2;
    }
    else if (StringSafeEqual(last_dot + 1, "254"))
    {
        /* avoid the broadcast address and the network address */
        step = 3;
    }

    uint32_t ip_num = ntohl(ip);
    ip_num += step;
    ip = htonl(ip_num);

    struct in_addr ip_struct;
    ip_struct.s_addr = ip;

    return xstrdup(inet_ntoa(ip_struct));
}
コード例 #26
0
ファイル: regex.c プロジェクト: cstroe/core
// If return_names is not set, only the captured data is returned (so
// for N captures you can expect N elements in the Sequence).
Seq *StringMatchCapturesWithPrecompiledRegex(const pcre *pattern, const char *str, const bool return_names)
{
    int captures;
    int res = pcre_fullinfo(pattern, NULL, PCRE_INFO_CAPTURECOUNT, &captures);
    if (res != 0)
    {
        return NULL;
    }

    // Get the table of named captures.
    unsigned char *name_table = NULL; // Doesn't have to be freed as per docs.
    int namecount = 0;
    int name_entry_size = 0;
    unsigned char *tabptr;

    pcre_fullinfo(pattern, NULL, PCRE_INFO_NAMECOUNT, &namecount);

    const bool have_named_captures = (namecount > 0 && return_names);

    if (have_named_captures)
    {
        pcre_fullinfo(pattern, NULL, PCRE_INFO_NAMETABLE, &name_table);
        pcre_fullinfo(pattern, NULL, PCRE_INFO_NAMEENTRYSIZE, &name_entry_size);
    }

    int *ovector = xmalloc(sizeof(int) * (captures + 1) * 3);

    int result = pcre_exec(pattern, NULL, str, strlen(str),
                           0, 0, ovector, (captures + 1) * 3);

    if (result <= 0)
    {
        free(ovector);
        return NULL;
    }

    Seq *ret = SeqNew(captures + 1, BufferDestroy);
    for (int i = 0; i <= captures; ++i)
    {
        Buffer *capture = NULL;

        if (have_named_captures)
        {
            // The overhead of doing a nested name scan is negligible.
            tabptr = name_table;
            for (int namepos = 0; namepos < namecount; namepos++)
            {
                int n = (tabptr[0] << 8) | tabptr[1];
                if (n == i) // We found the position
                {
                    capture = BufferNewFrom(tabptr + 2, name_entry_size - 3);
                    break;
                }
                tabptr += name_entry_size;
            }
        }

        if (return_names)
        {
            if (NULL == capture)
            {
                capture = BufferNew();
                BufferAppendF(capture, "%zd", i);
            }

            SeqAppend(ret, capture);
        }

        Buffer *data = BufferNewFrom(str + ovector[2*i],
                                     ovector[2*i + 1] - ovector[2 * i]);
        Log(LOG_LEVEL_DEBUG, "StringMatchCaptures: return_names = %d, have_named_captures = %d, offset %d, name '%s', data '%s'", return_names, have_named_captures, i, capture == NULL ? "no_name" : BufferData(capture), BufferData(data));
        SeqAppend(ret, data);
    }

    free(ovector);
    return ret;
}
コード例 #27
0
ファイル: syntax.c プロジェクト: markburgess/Cellibrium
static JsonElement *BundleTypesToJson(void)
{
 JsonElement *bundle_types = JsonObjectCreate(50);

 Seq *common_promise_types = SeqNew(50, free);

 for (int module_index = 0; module_index < CF3_MODULES; module_index++)
    {
    for (int promise_type_index = 0; CF_ALL_PROMISE_TYPES[module_index][promise_type_index].promise_type; promise_type_index++)
       {
       const PromiseTypeSyntax *promise_type_syntax = &CF_ALL_PROMISE_TYPES[module_index][promise_type_index];

       // skip global constraints
       if (strcmp("*", promise_type_syntax->promise_type) == 0)
          {
          continue;
          }

       // collect common promise types to be appended at the end
       if (strcmp("*", promise_type_syntax->bundle_type) == 0)
          {
          SeqAppend(common_promise_types, xstrdup(promise_type_syntax->promise_type));
          continue;
          }

       if (promise_type_syntax->status == SYNTAX_STATUS_REMOVED)
          {
          continue;
          }

       JsonElement *bundle_type = JsonObjectGet(bundle_types, promise_type_syntax->bundle_type);
       if (!bundle_type)
          {
          bundle_type = JsonBundleTypeNew();
          JsonObjectAppendObject(bundle_types, promise_type_syntax->bundle_type, bundle_type);
          }
       assert(bundle_type);

       JsonElement *promise_types = JsonObjectGet(bundle_type, "promiseTypes");
       assert(promise_types);

       JsonArrayAppendString(promise_types, promise_type_syntax->promise_type);
       }
    }

 // Append the common bundle, which has only common promise types, but is not declared in syntax
 {
 JsonElement *bundle_type = JsonBundleTypeNew();
 JsonObjectAppendObject(bundle_types, "common", bundle_type);
 }

 JsonIterator it = JsonIteratorInit(bundle_types);
 const char *bundle_type = NULL;
 while ((bundle_type = JsonIteratorNextKey(&it)))
    {
    JsonElement *promise_types = JsonObjectGetAsArray(JsonObjectGetAsObject(bundle_types, bundle_type), "promiseTypes");
    for (int i = 0; i < SeqLength(common_promise_types); i++)
       {
       const char *common_promise_type = SeqAt(common_promise_types, i);
       JsonArrayAppendString(promise_types, common_promise_type);
       }
    }

 SeqDestroy(common_promise_types);
 return bundle_types;
}
コード例 #28
0
ファイル: lastseen.c プロジェクト: AsherBond/core
bool ScanLastSeenQuality(LastSeenQualityCallback callback, void *ctx)
{
    StringMap *lastseen_db = LoadDatabaseToStringMap(dbid_lastseen);
    if (!lastseen_db)
    {
        return false;
    }
    MapIterator it = MapIteratorInit(lastseen_db->impl);
    MapKeyValue *item;

    Seq *hostkeys = SeqNew(100, free);
    while ((item = MapIteratorNext(&it)) != NULL)
    {
        char *key = item->key;
        /* Only look for "keyhost" entries */
        if (key[0] != 'k')
        {
            continue;
        }

        SeqAppend(hostkeys, xstrdup(key + 1));
    }
    for (int i = 0; i < SeqLength(hostkeys); ++i)
    {
        const char *hostkey = SeqAt(hostkeys, i);

        char keyhost_key[CF_BUFSIZE];
        snprintf(keyhost_key, CF_BUFSIZE, "k%s", hostkey);
        char *address = NULL;
        address = (char*)StringMapGet(lastseen_db, keyhost_key);
        if (!address)
        {
            Log(LOG_LEVEL_ERR, "Failed to read address for key '%s'.", hostkey);
            continue;
        }

        char incoming_key[CF_BUFSIZE];
        snprintf(incoming_key, CF_BUFSIZE, "qi%s", hostkey);
        KeyHostSeen *incoming = NULL;
        incoming = (KeyHostSeen*)StringMapGet(lastseen_db, incoming_key);
        if (incoming)
        {
            if (!(*callback)(hostkey, address, true, incoming, ctx))
            {
                break;
            }
        }

        char outgoing_key[CF_BUFSIZE];
        snprintf(outgoing_key, CF_BUFSIZE, "qo%s", hostkey);
        KeyHostSeen *outgoing = NULL;
        outgoing = (KeyHostSeen*)StringMapGet(lastseen_db, outgoing_key);
        if (outgoing)
        {
            if (!(*callback)(hostkey, address, false, outgoing, ctx))
            {
                break;
            }
        }
    }

    StringMapDestroy(lastseen_db);
    SeqDestroy(hostkeys);

    return true;
}
コード例 #29
0
ファイル: generic_agent.c プロジェクト: nperron/core
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);
        }
    }
}
コード例 #30
0
ファイル: exec-config.c プロジェクト: atsaloli/core
ExecConfig *ExecConfigNew(bool scheduled_run, const EvalContext *ctx, const Policy *policy)
{
    ExecConfig *exec_config = xcalloc(1, sizeof(ExecConfig));

    exec_config->scheduled_run = scheduled_run;
    exec_config->exec_command = xstrdup("");
    exec_config->agent_expireafter = 2 * 60;                   /* two hours */

    exec_config->mail_server = xstrdup("");
    exec_config->mail_from_address = xstrdup("");
    exec_config->mail_to_address = xstrdup("");
    exec_config->mail_subject = xstrdup("");
    exec_config->mail_max_lines = 30;
    exec_config->mailfilter_include = SeqNew(0, &free);
    exec_config->mailfilter_include_regex = SeqNew(0, &RegexFree);
    exec_config->mailfilter_exclude = SeqNew(0, &free);
    exec_config->mailfilter_exclude_regex = SeqNew(0, &RegexFree);

    exec_config->fq_name = xstrdup(VFQNAME);
    exec_config->ip_address = xstrdup(VIPADDRESS);
    exec_config->ip_addresses = GetIpAddresses(ctx);

    Seq *constraints = ControlBodyConstraints(policy, AGENT_TYPE_EXECUTOR);
    if (constraints)
    {
        for (size_t i = 0; i < SeqLength(constraints); i++)
        {
            Constraint *cp = SeqAt(constraints, i);

            if (!IsDefinedClass(ctx, cp->classes))
            {
                continue;
            }

            VarRef *ref = VarRefParseFromScope(cp->lval, "control_executor");
            DataType t;
            const void *value = EvalContextVariableGet(ctx, ref, &t);
            VarRefDestroy(ref);

            if (t == CF_DATA_TYPE_NONE)
            {
                ProgrammingError("Unknown attribute '%s' in control body,"
                                 " should have already been stopped by the parser",
                                 cp->lval);
            }

            if (strcmp(cp->lval, CFEX_CONTROLBODY[EXEC_CONTROL_MAILFROM].lval) == 0)
            {
                free(exec_config->mail_from_address);
                exec_config->mail_from_address = xstrdup(value);
                Log(LOG_LEVEL_DEBUG, "mailfrom '%s'", exec_config->mail_from_address);
            }
            else if (strcmp(cp->lval, CFEX_CONTROLBODY[EXEC_CONTROL_MAILTO].lval) == 0)
            {
                free(exec_config->mail_to_address);
                exec_config->mail_to_address = xstrdup(value);
                Log(LOG_LEVEL_DEBUG, "mailto '%s'", exec_config->mail_to_address);
            }
            else if (strcmp(cp->lval, CFEX_CONTROLBODY[EXEC_CONTROL_MAILSUBJECT].lval) == 0)
            {
                free(exec_config->mail_subject);
                exec_config->mail_subject = xstrdup(value);
                Log(LOG_LEVEL_DEBUG, "mailsubject '%s'", exec_config->mail_subject);
            }
            else if (strcmp(cp->lval, CFEX_CONTROLBODY[EXEC_CONTROL_SMTPSERVER].lval) == 0)
            {
                free(exec_config->mail_server);
                exec_config->mail_server = xstrdup(value);
                Log(LOG_LEVEL_DEBUG, "smtpserver '%s'", exec_config->mail_server);
            }
            else if (strcmp(cp->lval, CFEX_CONTROLBODY[EXEC_CONTROL_EXECCOMMAND].lval) == 0)
            {
                free(exec_config->exec_command);
                exec_config->exec_command = xstrdup(value);
                Log(LOG_LEVEL_DEBUG, "exec_command '%s'", exec_config->exec_command);
            }
            else if (strcmp(cp->lval, CFEX_CONTROLBODY[EXEC_CONTROL_AGENT_EXPIREAFTER].lval) == 0)
            {
                exec_config->agent_expireafter = IntFromString(value);
                Log(LOG_LEVEL_DEBUG, "agent_expireafter %d", exec_config->agent_expireafter);
            }
            else if (strcmp(cp->lval, CFEX_CONTROLBODY[EXEC_CONTROL_MAILMAXLINES].lval) == 0)
            {
                exec_config->mail_max_lines = IntFromString(value);
                Log(LOG_LEVEL_DEBUG, "maxlines %d", exec_config->mail_max_lines);
            }
            else if (strcmp(cp->lval, CFEX_CONTROLBODY[EXEC_CONTROL_MAILFILTER_INCLUDE].lval) == 0)
            {
                SeqDestroy(exec_config->mailfilter_include);
                SeqDestroy(exec_config->mailfilter_include_regex);
                RlistMailFilterFill(value, &exec_config->mailfilter_include,
                                    &exec_config->mailfilter_include_regex, "include");
            }
            else if (strcmp(cp->lval, CFEX_CONTROLBODY[EXEC_CONTROL_MAILFILTER_EXCLUDE].lval) == 0)
            {
                SeqDestroy(exec_config->mailfilter_exclude);
                SeqDestroy(exec_config->mailfilter_exclude_regex);
                RlistMailFilterFill(value, &exec_config->mailfilter_exclude,
                                    &exec_config->mailfilter_exclude_regex, "exclude");
            }
        }
    }

    return exec_config;
}