Ejemplo n.º 1
0
static bool Epimenides(EvalContext *ctx, const char *ns, const char *scope, const char *var, Rval rval, int level)
{
    switch (rval.type)
    {
    case RVAL_TYPE_SCALAR:

        if (StringContainsVar(RvalScalarValue(rval), var))
        {
            Log(LOG_LEVEL_ERR, "Scalar variable '%s' contains itself (non-convergent) '%s'", var, RvalScalarValue(rval));
            return true;
        }

        if (IsCf3VarString(RvalScalarValue(rval)))
        {
            Buffer *exp = BufferNew();
            ExpandScalar(ctx, ns, scope, RvalScalarValue(rval), exp);

            if (strcmp(BufferData(exp), RvalScalarValue(rval)) == 0)
            {
                BufferDestroy(exp);
                return false;
            }

            if (level > 3)
            {
                BufferDestroy(exp);
                return false;
            }

            if (Epimenides(ctx, ns, scope, var, (Rval) { BufferGet(exp), RVAL_TYPE_SCALAR}, level + 1))
            {
                BufferDestroy(exp);
                return true;
            }

            BufferDestroy(exp);
        }

        break;

    case RVAL_TYPE_LIST:
        for (const Rlist *rp = RvalRlistValue(rval); rp != NULL; rp = rp->next)
        {
            if (Epimenides(ctx, ns, scope, var, rp->val, level))
            {
                return true;
            }
        }
        break;

    case RVAL_TYPE_CONTAINER:
    case RVAL_TYPE_FNCALL:
    case RVAL_TYPE_NOPROMISEE:
        return false;
    }

    return false;
}
Ejemplo n.º 2
0
static void ResolvePackageManagerBody(EvalContext *ctx, const Body *pm_body)
{
    PackageModuleBody *new_manager = xcalloc(1, sizeof(PackageModuleBody));
    new_manager->name = SafeStringDuplicate(pm_body->name);

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

        Rval returnval = {0};

        if (IsDefinedClass(ctx, cp->classes))
        {
            returnval = ExpandPrivateRval(ctx, NULL, "body",
                                          cp->rval.item, cp->rval.type);
        }

        if (returnval.item == NULL || returnval.type == RVAL_TYPE_NOPROMISEE)
        {
            Log(LOG_LEVEL_VERBOSE, "have invalid constraint while resolving"
                    "package promise body: %s", cp->lval);

            RvalDestroy(returnval);
            continue;
        }

        if (strcmp(cp->lval, "query_installed_ifelapsed") == 0)
        {
            new_manager->installed_ifelapsed =
                    (int)IntFromString(RvalScalarValue(returnval));
        }
        else if (strcmp(cp->lval, "query_updates_ifelapsed") == 0)
        {
            new_manager->updates_ifelapsed =
                    (int)IntFromString(RvalScalarValue(returnval));
        }
        else if (strcmp(cp->lval, "default_options") == 0)
        {
            new_manager->options = RlistCopy(RvalRlistValue(returnval));
        }
        else
        {
            /* This should be handled by the parser. */
            assert(0);
        }
        RvalDestroy(returnval);
    }
    AddPackageModuleToContext(ctx, new_manager);
}
Ejemplo n.º 3
0
Archivo: expand.c Proyecto: kacf/core
Rval ExpandBundleReference(EvalContext *ctx,
                           const char *ns, const char *scope,
                           Rval rval)
{
    // Allocates new memory for the copy
    switch (rval.type)
    {
    case RVAL_TYPE_SCALAR:
        return (Rval) {
            ExpandScalar(ctx, ns, scope, RvalScalarValue(rval), NULL),
                         RVAL_TYPE_SCALAR
        };

    case RVAL_TYPE_FNCALL:
        return (Rval) {
            ExpandFnCall(ctx, ns, scope, RvalFnCallValue(rval)),
                         RVAL_TYPE_FNCALL
        };

    case RVAL_TYPE_CONTAINER:
    case RVAL_TYPE_LIST:
    case RVAL_TYPE_NOPROMISEE:
        return RvalNew(NULL, RVAL_TYPE_NOPROMISEE);
    }

    assert(false);
    return RvalNew(NULL, RVAL_TYPE_NOPROMISEE);
}
Ejemplo n.º 4
0
Archivo: expand.c Proyecto: tzz/core
Rval ExpandDanglers(EvalContext *ctx, const char *ns, const char *scope, Rval rval, const Promise *pp)
{
    assert(ctx);
    assert(pp);

    switch (rval.type)
    {
    case RVAL_TYPE_SCALAR:
        if (IsCf3VarString(RvalScalarValue(rval)))
        {
            return EvaluateFinalRval(ctx, PromiseGetPolicy(pp), ns, scope, rval, false, pp);
        }
        else
        {
            return RvalCopy(rval);
        }
        break;

    case RVAL_TYPE_LIST:
        {
            Rlist *result_list = RlistCopy(RvalRlistValue(rval));
            RlistFlatten(ctx, &result_list);
            return RvalNew(result_list, RVAL_TYPE_LIST);
        }
        break;

    case RVAL_TYPE_CONTAINER:
    case RVAL_TYPE_FNCALL:
    case RVAL_TYPE_NOPROMISEE:
        return RvalCopy(rval);
    }

    ProgrammingError("Unhandled Rval type");
}
Ejemplo n.º 5
0
void RvalWrite(Writer *writer, Rval rval)
{
    if (rval.item == NULL)
    {
        return;
    }

    switch (rval.type)
    {
    case RVAL_TYPE_SCALAR:
        ScalarWrite(writer, RvalScalarValue(rval));
        break;

    case RVAL_TYPE_LIST:
        RlistWrite(writer, RvalRlistValue(rval));
        break;

    case RVAL_TYPE_FNCALL:
        FnCallPrint(writer, RvalFnCallValue(rval));
        break;

    case RVAL_TYPE_NOPROMISEE:
        WriterWrite(writer, "(no-one)");
        break;

    default:
        ProgrammingError("Unknown rval type %c", rval.type);
    }
}
Ejemplo n.º 6
0
Archivo: rlist.c Proyecto: cduclos/core
void RvalWrite(Writer *writer, Rval rval)
{
    if (rval.item == NULL)
    {
        return;
    }

    switch (rval.type)
    {
    case RVAL_TYPE_SCALAR:
        ScalarWrite(writer, RvalScalarValue(rval));
        break;

    case RVAL_TYPE_LIST:
        RlistWrite(writer, RvalRlistValue(rval));
        break;

    case RVAL_TYPE_FNCALL:
        FnCallWrite(writer, RvalFnCallValue(rval));
        break;

    case RVAL_TYPE_NOPROMISEE:
        WriterWrite(writer, "(no-one)");
        break;

    case RVAL_TYPE_CONTAINER:
        JsonWrite(writer, RvalContainerValue(rval), 0);
        break;
    }
}
Ejemplo n.º 7
0
void RvalDestroy(Rval rval)
{
    if (rval.item == NULL)
    {
        return;
    }

    switch (rval.type)
    {
    case RVAL_TYPE_SCALAR:
        ThreadLock(cft_lock);
        free(RvalScalarValue(rval));
        ThreadUnlock(cft_lock);
        return;

    case RVAL_TYPE_LIST:
        RlistDestroy(RvalRlistValue(rval));
        return;

    case RVAL_TYPE_FNCALL:
        FnCallDestroy(RvalFnCallValue(rval));
        break;

    case RVAL_TYPE_CONTAINER:
        JsonDestroy(RvalContainerValue(rval));
        break;

    case RVAL_TYPE_NOPROMISEE:
        return;
    }
}
Ejemplo n.º 8
0
Archivo: loading.c Proyecto: lra/core
static Policy *LoadPolicyInputFiles(EvalContext *ctx, GenericAgentConfig *config, const Rlist *inputs, StringSet *parsed_files_and_checksums, StringSet *failed_files)
{
    Policy *policy = PolicyNew();

    for (const Rlist *rp = inputs; rp; rp = rp->next)
    {
        if (rp->val.type != RVAL_TYPE_SCALAR)
        {
            Log(LOG_LEVEL_ERR, "Non-file object in inputs list");
            continue;
        }

        const char *unresolved_input = RlistScalarValue(rp);

        if (strcmp(CF_NULL_VALUE, unresolved_input) == 0)
        {
            continue;
        }

        if (IsExpandable(unresolved_input))
        {
            PolicyResolve(ctx, policy, config);
        }

        Rval resolved_input = EvaluateFinalRval(ctx, policy, NULL, "sys", rp->val, true, NULL);

        Policy *aux_policy = NULL;
        switch (resolved_input.type)
        {
        case RVAL_TYPE_SCALAR:
            if (IsCf3VarString(RvalScalarValue(resolved_input)))
            {
                Log(LOG_LEVEL_ERR, "Unresolved variable '%s' in input list, cannot parse", RvalScalarValue(resolved_input));
                break;
            }

            aux_policy = LoadPolicyFile(ctx, config, GenericAgentResolveInputPath(config, RvalScalarValue(resolved_input)), parsed_files_and_checksums, failed_files);
            break;

        case RVAL_TYPE_LIST:
            aux_policy = LoadPolicyInputFiles(ctx, config, RvalRlistValue(resolved_input), parsed_files_and_checksums, failed_files);
            break;

        default:
            ProgrammingError("Unknown type in input list for parsing: %d", resolved_input.type);
            break;
        }

        if (aux_policy)
        {
            policy = PolicyMerge(policy, aux_policy);
        }

        RvalDestroy(resolved_input);
    }

    return policy;
}
Ejemplo n.º 9
0
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);
}
Ejemplo n.º 10
0
static void TestGet(VariableTable *t, const char *ref_str)
{
    VarRef *ref = VarRefParse(ref_str);
    Variable *v = VariableTableGet(t, ref);
    assert_true(v != NULL);
    assert_int_equal(0, VarRefCompare(ref, v->ref));
    assert_string_equal(ref_str, RvalScalarValue(v->rval));
    VarRefDestroy(ref);
}
Ejemplo n.º 11
0
/**
 * Recursively go down the #rval and run PromiseIteratorPrepare() to take note
 * of all iterables and mangle all rvals than need to be mangled before
 * iterating.
 */
static void MapIteratorsFromRval(EvalContext *ctx,
                                 PromiseIterator *iterctx,
                                 Rval rval)
{
    switch (rval.type)
    {

    case RVAL_TYPE_SCALAR:
        PromiseIteratorPrepare(iterctx, ctx, RvalScalarValue(rval));
        break;

    case RVAL_TYPE_LIST:
        for (const Rlist *rp = RvalRlistValue(rval);
             rp != NULL; rp = rp->next)
        {
            MapIteratorsFromRval(ctx, iterctx, rp->val);
        }
        break;

    case RVAL_TYPE_FNCALL:
    {
        char *fn_name = RvalFnCallValue(rval)->name;

        /* Check function name. */
        PromiseIteratorPrepare(iterctx, ctx, fn_name);

        /* Check each of the function arguments. */
        /* EXCEPT on functions that use special variables: the mangled
         * variables would never be resolved if they contain inner special
         * variables (for example "$(bundle.A[$(this.k)])" and the returned
         * slist would contained mangled vars like "bundle#A[1]" which would
         * never resolve in future iterations. By skipping the iteration
         * engine for now, the function returns an slist with unmangled
         * entries, and the iteration engine works correctly on the next
         * pass! */
        if (strcmp(fn_name, "maplist") != 0 &&
            strcmp(fn_name, "mapdata") != 0 &&
            strcmp(fn_name, "maparray")!= 0)
        {
            for (Rlist *rp = RvalFnCallValue(rval)->args;
                 rp != NULL;  rp = rp->next)
            {
                MapIteratorsFromRval(ctx, iterctx, rp->val);
            }
        }
        break;
    }

    case RVAL_TYPE_CONTAINER:
    case RVAL_TYPE_NOPROMISEE:
        break;
    }
}
Ejemplo n.º 12
0
Promise *ExpandDeRefPromise(EvalContext *ctx, const Promise *pp)
{
    Promise *pcopy;
    Rval returnval, final;

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

    returnval = ExpandPrivateRval(ctx, NULL, "this", pp->promiser, RVAL_TYPE_SCALAR);
    pcopy->promiser = RvalScalarValue(returnval);

    if (pp->promisee.item)
    {
        pcopy->promisee = EvaluateFinalRval(ctx, NULL, "this", 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, NULL, "this", cp->rval);
        }
        else
        {
Ejemplo n.º 13
0
unsigned RvalHash(Rval rval, unsigned seed, unsigned max)
{
    switch (rval.type)
    {
    case RVAL_TYPE_SCALAR:
        return StringHash(RvalScalarValue(rval), seed, max);
    case RVAL_TYPE_FNCALL:
        return FnCallHash(RvalFnCallValue(rval), seed, max);
    case RVAL_TYPE_LIST:
        return RlistHash(RvalRlistValue(rval), seed, max);
    case RVAL_TYPE_NOPROMISEE:
        return (seed + 1) % max;
    default:
        ProgrammingError("Unhandled case in switch: %d", rval.type);
    }
}
Ejemplo n.º 14
0
JsonElement *RvalToJson(Rval rval)
{
    assert(rval.item);

    switch (rval.type)
    {
    case RVAL_TYPE_SCALAR:
        return JsonStringCreate(RvalScalarValue(rval));
    case RVAL_TYPE_LIST:
        return RlistToJson(RvalRlistValue(rval));
    case RVAL_TYPE_FNCALL:
        return FnCallToJson(RvalFnCallValue(rval));
    default:
        assert(false && "Invalid rval type");
        return JsonStringCreate("");
    }
}
Ejemplo n.º 15
0
unsigned RvalHash(Rval rval, unsigned seed)
{
    switch (rval.type)
    {
    case RVAL_TYPE_SCALAR:
        return StringHash(RvalScalarValue(rval), seed);
    case RVAL_TYPE_FNCALL:
        return FnCallHash(RvalFnCallValue(rval), seed);
    case RVAL_TYPE_LIST:
        return RlistHash(RvalRlistValue(rval), seed);
    case RVAL_TYPE_NOPROMISEE:
        /* TODO modulus operation is biasing results. */
        return (seed + 1);
    default:
        ProgrammingError("Unhandled case in switch: %d", rval.type);
    }
}
Ejemplo n.º 16
0
static void test_replace(void)
{
    VariableTable *t = ReferenceTable();

    VarRef *ref = VarRefParse("scope1.lval1");
    TestGet(t, "scope1.lval1");

    Rval rval = (Rval) { "foo", RVAL_TYPE_SCALAR };
    assert_true(VariableTablePut(t, ref, &rval, CF_DATA_TYPE_STRING, NULL, NULL));

    Variable *v = VariableTableGet(t, ref);
    assert_true(v != NULL);
    assert_string_equal("foo", RvalScalarValue(v->rval));

    VarRefDestroy(ref);

    VariableTableDestroy(t);
}
Ejemplo n.º 17
0
void MapIteratorsFromRval(EvalContext *ctx, const Bundle *bundle, Rval rval,
                          Rlist **scalars, Rlist **lists, Rlist **containers)
{
    assert(rval.item);
    if (rval.item == NULL)
    {
        return;
    }

    switch (rval.type)
    {
    case RVAL_TYPE_SCALAR:
        {
            char *val = RvalScalarValue(rval);
            size_t val_len = strlen(val);
            ExpandAndMapIteratorsFromScalar(ctx, bundle, val, val_len, 0, scalars, lists, containers, NULL);
        }
        break;

    case RVAL_TYPE_LIST:
        for (const Rlist *rp = RvalRlistValue(rval); rp; rp = rp->next)
        {
            MapIteratorsFromRval(ctx, bundle, rp->val, scalars, lists, containers);
        }
        break;

    case RVAL_TYPE_FNCALL:
        ExpandAndMapIteratorsFromScalar(ctx, bundle, RvalFnCallValue(rval)->name,
                                        strlen(RvalFnCallValue(rval)->name), 0, scalars, lists, containers, NULL);
        for (const Rlist *rp = RvalFnCallValue(rval)->args; rp; rp = rp->next)
        {
            Log(LOG_LEVEL_DEBUG, "Looking at arg for function-like object '%s'", RvalFnCallValue(rval)->name);
            MapIteratorsFromRval(ctx, bundle, rp->val, scalars, lists, containers);
        }
        break;

    case RVAL_TYPE_CONTAINER:
    case RVAL_TYPE_NOPROMISEE:
        Log(LOG_LEVEL_DEBUG, "Unknown Rval type for scope '%s'", bundle->name);
        break;
    }
}
Ejemplo n.º 18
0
JsonElement *RvalToJson(Rval rval)
{
    assert(rval.item);

    switch (rval.type)
    {
    case RVAL_TYPE_SCALAR:
        return JsonStringCreate(RvalScalarValue(rval));
    case RVAL_TYPE_LIST:
        return RlistToJson(RvalRlistValue(rval));
    case RVAL_TYPE_FNCALL:
        return FnCallToJson(RvalFnCallValue(rval));
    case RVAL_TYPE_CONTAINER:
        return JsonCopy(RvalContainerValue(rval));
    case RVAL_TYPE_NOPROMISEE:
        assert(false);
        return JsonObjectCreate(1);
    }

    assert(false);
    return NULL;
}
Ejemplo n.º 19
0
void ScopeAugment(EvalContext *ctx, const Bundle *bp, const Promise *pp, const Rlist *arguments)
{
    if (RlistLen(bp->args) != RlistLen(arguments))
    {
        Log(LOG_LEVEL_ERR, "While constructing scope '%s'", bp->name);
        fprintf(stderr, "Formal = ");
        RlistShow(stderr, bp->args);
        fprintf(stderr, ", Actual = ");
        RlistShow(stderr, arguments);
        fprintf(stderr, "\n");
        FatalError(ctx, "Augment scope, formal and actual parameter mismatch is fatal");
    }

    const Bundle *pbp = NULL;
    if (pp != NULL)
    {
        pbp = PromiseGetBundle(pp);
    }

    for (const Rlist *rpl = bp->args, *rpr = arguments; rpl != NULL; rpl = rpl->next, rpr = rpr->next)
    {
        const char *lval = RlistScalarValue(rpl);

        Log(LOG_LEVEL_VERBOSE, "Augment scope '%s' with variable '%s' (type: %c)", bp->name, lval, rpr->val.type);

        // CheckBundleParameters() already checked that there is no namespace collision
        // By this stage all functions should have been expanded, so we only have scalars left

        if (rpr->val.type == RVAL_TYPE_SCALAR && IsNakedVar(RlistScalarValue(rpr), '@'))
        {

            char naked[CF_BUFSIZE];
            
            GetNaked(naked, RlistScalarValue(rpr));

            DataType value_type = CF_DATA_TYPE_NONE;
            const void *value = NULL;
            if (pbp != NULL)
            {
                VarRef *ref = VarRefParseFromBundle(naked, pbp);
                value = EvalContextVariableGet(ctx, ref, &value_type);
                VarRefDestroy(ref);
            }
            else
            {
                VarRef *ref = VarRefParseFromBundle(naked, bp);
                value = EvalContextVariableGet(ctx, ref, &value_type);
                VarRefDestroy(ref);
            }

            switch (value_type)
            {
            case CF_DATA_TYPE_STRING_LIST:
            case CF_DATA_TYPE_INT_LIST:
            case CF_DATA_TYPE_REAL_LIST:
                {
                    VarRef *ref = VarRefParseFromBundle(lval, bp);
                    EvalContextVariablePut(ctx, ref, value, CF_DATA_TYPE_STRING_LIST, "source=promise");
                    VarRefDestroy(ref);
                }
                break;
            case CF_DATA_TYPE_CONTAINER:
                {
                    VarRef *ref = VarRefParseFromBundle(lval, bp);
                    EvalContextVariablePut(ctx, ref, value, CF_DATA_TYPE_CONTAINER, "source=promise");
                    VarRefDestroy(ref);
                }
                break;
            default:
                {
                    Log(LOG_LEVEL_ERR, "List or container parameter '%s' not found while constructing scope '%s' - use @(scope.variable) in calling reference", naked, bp->name);
                    VarRef *ref = VarRefParseFromBundle(lval, bp);
                    EvalContextVariablePut(ctx, ref, RlistScalarValue(rpr), CF_DATA_TYPE_STRING, "source=promise");
                    VarRefDestroy(ref);
                }
                break;
            }
        }
        else
        {
            switch(rpr->val.type)
            {
            case RVAL_TYPE_SCALAR:
                {
                    VarRef *ref = VarRefParseFromBundle(lval, bp);
                    EvalContextVariablePut(ctx, ref, RvalScalarValue(rpr->val), CF_DATA_TYPE_STRING, "source=promise");
                    VarRefDestroy(ref);
                }
                break;

            case RVAL_TYPE_FNCALL:
                {
                    FnCall *subfp = RlistFnCallValue(rpr);
                    Rval rval = FnCallEvaluate(ctx, PromiseGetPolicy(pp), subfp, pp).rval;
                    if (rval.type == RVAL_TYPE_SCALAR)
                    {
                        VarRef *ref = VarRefParseFromBundle(lval, bp);
                        EvalContextVariablePut(ctx, ref, RvalScalarValue(rval), CF_DATA_TYPE_STRING, "source=promise");
                        VarRefDestroy(ref);
                    }
                    else
                    {
                        Log(LOG_LEVEL_ERR, "Only functions returning scalars can be used as arguments");
                    }
                    RvalDestroy(rval);
                }
                break;
            default:
                ProgrammingError("An argument neither a scalar nor a list seemed to appear. Impossible");
            }
        }
    }

/* Check that there are no danglers left to evaluate in the hash table itself */

    return;
}
Ejemplo n.º 20
0
static bool VerifyIfUserNeedsModifs (const char *puser, const User *u, const struct passwd *passwd_info,
                             uint32_t *changemap)
{
    assert(u != NULL);
    if (u->description != NULL && strcmp (u->description, passwd_info->pw_gecos))
    {
        CFUSR_SETBIT (*changemap, i_comment);
    }
    if (u->uid != NULL && (atoi (u->uid) != passwd_info->pw_uid))
    {
        CFUSR_SETBIT (*changemap, i_uid);
    }
    if (u->home_dir != NULL && strcmp (u->home_dir, passwd_info->pw_dir))
    {
        CFUSR_SETBIT (*changemap, i_home);
    }
    if (u->shell != NULL && strcmp (u->shell, passwd_info->pw_shell))
    {
        CFUSR_SETBIT (*changemap, i_shell);
    }
    bool account_is_locked = IsAccountLocked(puser, passwd_info);
    if ((!account_is_locked && u->policy == USER_STATE_LOCKED)
        || (account_is_locked && u->policy != USER_STATE_LOCKED))
    {
        CFUSR_SETBIT(*changemap, i_locked);
    }
    // Don't bother with passwords if the account is going to be locked anyway.
    if (u->password != NULL && strcmp (u->password, "")
        && u->policy != USER_STATE_LOCKED)
    {
        if (!IsPasswordCorrect(puser, u->password, u->password_format, passwd_info))
        {
            CFUSR_SETBIT (*changemap, i_password);
        }
    }

    if (SafeStringLength(u->group_primary))
    {
        bool group_could_be_gid = (strlen(u->group_primary) == strspn(u->group_primary, "0123456789"));
        int gid;

        // We try name first, even if it looks like a gid. Only fall back to gid.
        struct group *group_info;
        errno = 0;
        group_info = GetGrEntry(u->group_primary, &EqualGroupName);
        if (!group_info && errno != 0)
        {
            Log(LOG_LEVEL_ERR, "Could not obtain information about group '%s': %s", u->group_primary, GetErrorStr());
            gid = -1;
        }
        else if (!group_info)
        {
            if (group_could_be_gid)
            {
                gid = atoi(u->group_primary);
            }
            else
            {
                Log(LOG_LEVEL_ERR, "No such group '%s'.", u->group_primary);
                gid = -1;
            }
        }
        else
        {
            gid = group_info->gr_gid;
        }

        if (gid != passwd_info->pw_gid)
        {
            CFUSR_SETBIT (*changemap, i_group);
        }
    }

    if (u->groups_secondary_given)
    {
        StringSet *wanted_groups = StringSetNew();
        for (Rlist *ptr = u->groups_secondary; ptr; ptr = ptr->next)
        {
            StringSetAdd(wanted_groups, xstrdup(RvalScalarValue(ptr->val)));
        }
        TransformGidsToGroups(&wanted_groups);
        StringSet *current_groups = StringSetNew();
        if (!GroupGetUserMembership (puser, current_groups))
        {
            CFUSR_SETBIT (*changemap, i_groups);
        }
        else if (!StringSetIsEqual (current_groups, wanted_groups))
        {
            CFUSR_SETBIT (*changemap, i_groups);
        }
        StringSetDestroy(current_groups);
        StringSetDestroy(wanted_groups);
    }

    ////////////////////////////////////////////
    if (*changemap == 0)
    {
        return false;
    }
    else
    {
        return true;
    }
}
Ejemplo n.º 21
0
Archivo: expand.c Proyecto: tzz/core
static void ResolveControlBody(EvalContext *ctx, GenericAgentConfig *config, const Body *control_body)
{
    const ConstraintSyntax *body_syntax = NULL;
    Rval returnval;

    assert(strcmp(control_body->name, "control") == 0);

    for (int i = 0; CONTROL_BODIES[i].constraints != NULL; i++)
    {
        body_syntax = CONTROL_BODIES[i].constraints;

        if (strcmp(control_body->type, CONTROL_BODIES[i].body_type) == 0)
        {
            break;
        }
    }

    if (body_syntax == NULL)
    {
        FatalError(ctx, "Unknown agent");
    }

    char scope[CF_BUFSIZE];
    snprintf(scope, CF_BUFSIZE, "%s_%s", control_body->name, control_body->type);
    Log(LOG_LEVEL_DEBUG, "Initiate control variable convergence for scope '%s'", scope);

    EvalContextStackPushBodyFrame(ctx, NULL, control_body, NULL);

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

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

        if (strcmp(cp->lval, CFG_CONTROLBODY[COMMON_CONTROL_BUNDLESEQUENCE].lval) == 0)
        {
            returnval = ExpandPrivateRval(ctx, NULL, scope, cp->rval.item, cp->rval.type);
        }
        else
        {
            returnval = EvaluateFinalRval(ctx, control_body->parent_policy, NULL, scope, cp->rval, true, NULL);
        }

        VarRef *ref = VarRefParseFromScope(cp->lval, scope);
        EvalContextVariableRemove(ctx, ref);

        if (!EvalContextVariablePut(ctx, ref, returnval.item, ConstraintSyntaxGetDataType(body_syntax, cp->lval), "source=promise"))
        {
            Log(LOG_LEVEL_ERR, "Rule from %s at/before line %zu", control_body->source_path, cp->offset.line);
        }

        VarRefDestroy(ref);

        if (strcmp(cp->lval, CFG_CONTROLBODY[COMMON_CONTROL_OUTPUT_PREFIX].lval) == 0)
        {
            strncpy(VPREFIX, returnval.item, CF_MAXVARSIZE);
        }

        if (strcmp(cp->lval, CFG_CONTROLBODY[COMMON_CONTROL_DOMAIN].lval) == 0)
        {
            strcpy(VDOMAIN, cp->rval.item);
            Log(LOG_LEVEL_VERBOSE, "SET domain = %s", VDOMAIN);
            EvalContextVariableRemoveSpecial(ctx, SPECIAL_SCOPE_SYS, "domain");
            EvalContextVariableRemoveSpecial(ctx, SPECIAL_SCOPE_SYS, "fqhost");
            snprintf(VFQNAME, CF_MAXVARSIZE, "%s.%s", VUQNAME, VDOMAIN);
            EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "fqhost", VFQNAME, DATA_TYPE_STRING, "inventory,source=agent,group=Host name");
            EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "domain", VDOMAIN, DATA_TYPE_STRING, "source=agent");
            EvalContextClassPutHard(ctx, VDOMAIN, "source=agent");
        }

        if (strcmp(cp->lval, CFG_CONTROLBODY[COMMON_CONTROL_IGNORE_MISSING_INPUTS].lval) == 0)
        {
            Log(LOG_LEVEL_VERBOSE, "SET ignore_missing_inputs %s", RvalScalarValue(cp->rval));
            config->ignore_missing_inputs = BooleanFromString(cp->rval.item);
        }

        if (strcmp(cp->lval, CFG_CONTROLBODY[COMMON_CONTROL_IGNORE_MISSING_BUNDLES].lval) == 0)
        {
            Log(LOG_LEVEL_VERBOSE, "SET ignore_missing_bundles %s", RvalScalarValue(cp->rval));
            config->ignore_missing_bundles = BooleanFromString(cp->rval.item);
        }

        if (strcmp(cp->lval, CFG_CONTROLBODY[COMMON_CONTROL_CACHE_SYSTEM_FUNCTIONS].lval) == 0)
        {
            Log(LOG_LEVEL_VERBOSE, "SET cache_system_functions %s", RvalScalarValue(cp->rval));
            bool cache_system_functions = BooleanFromString(RvalScalarValue(cp->rval));
            EvalContextSetEvalOption(ctx, EVAL_OPTION_CACHE_SYSTEM_FUNCTIONS,
                                     cache_system_functions);
        }

        if (strcmp(cp->lval, CFG_CONTROLBODY[COMMON_CONTROL_GOALPATTERNS].lval) == 0)
        {
            /* Ignored */
            continue;
        }

        RvalDestroy(returnval);
    }

    EvalContextStackPopFrame(ctx);
}
Ejemplo n.º 22
0
static bool DoCreateUser(const char *puser, const User *u, enum cfopaction action,
                         EvalContext *ctx, const Attributes *a, const Promise *pp)
{
    assert(u != NULL);
    char cmd[CF_BUFSIZE];
    char sec_group_args[CF_BUFSIZE];
    if (puser == NULL || !strcmp (puser, ""))
    {
        return false;
    }
    strcpy (cmd, USERADD);

    if (u->uid != NULL && strcmp (u->uid, ""))
    {
        StringAppend(cmd, " -u \"", sizeof(cmd));
        StringAppend(cmd, u->uid, sizeof(cmd));
        StringAppend(cmd, "\"", sizeof(cmd));
    }

    if (u->description != NULL)
    {
        StringAppend(cmd, " -c \"", sizeof(cmd));
        StringAppend(cmd, u->description, sizeof(cmd));
        StringAppend(cmd, "\"", sizeof(cmd));
    }

    if (u->group_primary != NULL && strcmp (u->group_primary, ""))
    {
        // TODO: Should check that group exists
        StringAppend(cmd, " -g \"", sizeof(cmd));
        StringAppend(cmd, u->group_primary, sizeof(cmd));
        StringAppend(cmd, "\"", sizeof(cmd));
    }

    if (u->groups_secondary_given)
    {
        // TODO: Should check that groups exist
        strlcpy(sec_group_args, " -G \"", sizeof(sec_group_args));
        char sep[2] = { '\0', '\0' };
        for (Rlist *i = u->groups_secondary; i; i = i->next)
        {
            StringAppend(sec_group_args, sep, sizeof(sec_group_args));
            StringAppend(sec_group_args, RvalScalarValue(i->val), sizeof(sec_group_args));
            sep[0] = ',';
        }
        StringAppend(sec_group_args, "\"", sizeof(sec_group_args));
        StringAppend(cmd, sec_group_args, sizeof(cmd));
    }

    if (u->home_dir != NULL && strcmp (u->home_dir, ""))
    {
        StringAppend(cmd, " -d \"", sizeof(cmd));
        StringAppend(cmd, u->home_dir, sizeof(cmd));
        StringAppend(cmd, "\"", sizeof(cmd));
    }
    if (u->shell != NULL && strcmp (u->shell, ""))
    {
        StringAppend(cmd, " -s \"", sizeof(cmd));
        StringAppend(cmd, u->shell, sizeof(cmd));
        StringAppend(cmd, "\"", sizeof(cmd));
    }

#ifndef __hpux
    // HP-UX has two variants of useradd, the normal one which does
    // not support -M and one variant to modify default values which
    // does take -M and yes or no
    // Since both are output with -h SupportOption incorrectly reports
    // -M as supported
    if (SupportsOption(USERADD, "-M"))
    {
        // Prevents creation of home_dir.
        // We want home_bundle to do that.
        StringAppend(cmd, " -M", sizeof(cmd));
    }
#endif
    StringAppend(cmd, " ", sizeof(cmd));
    StringAppend(cmd, puser, sizeof(cmd));

    if (action == cfa_warn || DONTDO)
    {
        Log(LOG_LEVEL_WARNING, "Need to create user '%s'.", puser);
        return false;
    }
    else
    {
        if (!ExecuteUserCommand(puser, cmd, sizeof(cmd), "creating", "Creating"))
        {
            return false;
        }

        if (u->groups_secondary_given)
        {
            // Work around issue on AIX. Always set secondary groups a second time, because AIX
            // likes to assign the primary group as the secondary group as well, even if we didn't
            // ask for it.
            strlcpy(cmd, USERMOD, sizeof(cmd));
            StringAppend(cmd, sec_group_args, sizeof(cmd));
            StringAppend(cmd, " ", sizeof(cmd));
            StringAppend(cmd, puser, sizeof(cmd));
            if (!ExecuteUserCommand(puser, cmd, sizeof(cmd), "modifying", "Modifying"))
            {
                return false;
            }
        }

        // Initially, "useradd" may set the password to '!', which confuses our detection for
        // locked accounts. So reset it to 'x' hash instead, which will never match anything.
        if (!ChangePassword(puser, "x", PASSWORD_FORMAT_HASH))
        {
            return false;
        }

        if (u->policy == USER_STATE_LOCKED)
        {
            if (!SetAccountLocked(puser, "x", true))
            {
                return false;
            }
        }

        if (a->havebundle)
        {
            const Constraint *method_attrib = PromiseGetConstraint(pp, "home_bundle");
            if (method_attrib == NULL)
            {
                Log(LOG_LEVEL_ERR, "Cannot create user (home_bundle not found)");
                return false;
            }
            VerifyMethod(ctx, method_attrib->rval, a, pp);
        }

        if (u->policy != USER_STATE_LOCKED && u->password != NULL && strcmp (u->password, ""))
        {
            if (!ChangePassword(puser, u->password, u->password_format))
            {
                return false;
            }
        }
    }

    return true;
}
Ejemplo n.º 23
0
static bool DoModifyUser (const char *puser, const User *u, const struct passwd *passwd_info, uint32_t changemap, enum cfopaction action)
{
    assert(u != NULL);
    char cmd[CF_BUFSIZE];

    strcpy (cmd, USERMOD);

    if (CFUSR_CHECKBIT (changemap, i_uid) != 0)
    {
        StringAppend(cmd, " -u \"", sizeof(cmd));
        StringAppend(cmd, u->uid, sizeof(cmd));
        StringAppend(cmd, "\"", sizeof(cmd));
    }

    if (CFUSR_CHECKBIT (changemap, i_comment) != 0)
    {
        StringAppend(cmd, " -c \"", sizeof(cmd));
        StringAppend(cmd, u->description, sizeof(cmd));
        StringAppend(cmd, "\"", sizeof(cmd));
    }

    if (CFUSR_CHECKBIT (changemap, i_group) != 0)
    {
        StringAppend(cmd, " -g \"", sizeof(cmd));
        StringAppend(cmd, u->group_primary, sizeof(cmd));
        StringAppend(cmd, "\"", sizeof(cmd));
    }

#ifndef __hpux
    // HP-UX does not support -G with empty argument
    if (CFUSR_CHECKBIT (changemap, i_groups) != 0)
    {
        /* Work around bug on SUSE. If secondary groups contain a group that is
           the same group as the primary group, the secondary group is not set.
           This happens even if the primary group is changed in the same call.
           Therefore, set an empty group list first, and then set it to the real
           list later.
        */
        StringAppend(cmd, " -G \"\"", sizeof(cmd));
    }
#endif

    if (CFUSR_CHECKBIT (changemap, i_home) != 0)
    {
        StringAppend(cmd, " -d \"", sizeof(cmd));
        StringAppend(cmd, u->home_dir, sizeof(cmd));
        StringAppend(cmd, "\"", sizeof(cmd));
    }

    if (CFUSR_CHECKBIT (changemap, i_shell) != 0)
    {
        StringAppend(cmd, " -s \"", sizeof(cmd));
        StringAppend(cmd, u->shell, sizeof(cmd));
        StringAppend(cmd, "\"", sizeof(cmd));
    }

    StringAppend(cmd, " ", sizeof(cmd));
    StringAppend(cmd, puser, sizeof(cmd));

    if (CFUSR_CHECKBIT (changemap, i_password) != 0)
    {
        if (action == cfa_warn || DONTDO)
        {
            Log(LOG_LEVEL_WARNING, "Need to change password for user '%s'.", puser);
            return false;
        }
        else
        {
            if (!ChangePassword(puser, u->password, u->password_format))
            {
                return false;
            }
        }
    }

    if (CFUSR_CHECKBIT (changemap, i_locked) != 0)
    {
        if (action == cfa_warn || DONTDO)
        {
            Log(LOG_LEVEL_WARNING, "Need to %s account for user '%s'.",
                (u->policy == USER_STATE_LOCKED) ? "lock" : "unlock", puser);
            return false;
        }
        else
        {
            const char *hash;
            if (CFUSR_CHECKBIT(changemap, i_password) == 0)
            {
                if (!GetPasswordHash(puser, passwd_info, &hash))
                {
                    return false;
                }
            }
            else
            {
                // Don't unlock the hash if we already set the password. Our
                // cached value in passwd_info->pw_passwd will be wrong, and the
                // account will already have been unlocked anyway.
                hash = NULL;
            }
            if (!SetAccountLocked(puser, hash, (u->policy == USER_STATE_LOCKED)))
            {
                return false;
            }
        }
    }

    // If password and locking were the only things changed, don't run the command.
    CFUSR_CLEARBIT(changemap, i_password);
    CFUSR_CLEARBIT(changemap, i_locked);
    if (action == cfa_warn || DONTDO)
    {
        Log(LOG_LEVEL_WARNING, "Need to update user attributes (command '%s').", cmd);
        return false;
    }
    else if (changemap != 0)
    {
#ifdef __hpux
        // This is to overcome the Suse hack above which does not work on HP-UX and thus we
        // risk getting an empty command if change of secondary groups is the only change
        // Only run for other changes than i_groups, otherwise the command will be empty
        uint32_t changemap_without_groups = changemap;
        CFUSR_CLEARBIT(changemap_without_groups, i_groups);
        if(changemap_without_groups != 0)
#endif
        {
            if (!ExecuteUserCommand(puser, cmd, sizeof(cmd), "modifying", "Modifying"))
            {
                return false;
            }
        }
        if (CFUSR_CHECKBIT (changemap, i_groups) != 0)
        {
            // Set real group list (see -G comment earlier).
            strcpy(cmd, USERMOD);
            StringAppend(cmd, " -G \"", sizeof(cmd));
            char sep[2] = { '\0', '\0' };
            for (Rlist *i = u->groups_secondary; i; i = i->next)
            {
                StringAppend(cmd, sep, sizeof(cmd));
                StringAppend(cmd, RvalScalarValue(i->val), sizeof(cmd));
                sep[0] = ',';
            }
            StringAppend(cmd, "\" ", sizeof(cmd));
            StringAppend(cmd, puser, sizeof(cmd));
            if (!ExecuteUserCommand(puser, cmd, sizeof(cmd), "modifying", "Modifying"))
            {
                return false;
            }
        }
    }
    return true;
}
Ejemplo n.º 24
0
static void test_rval_to_scalar(void)
{
    Rval rval = { "abc", RVAL_TYPE_SCALAR };
    assert_string_equal("abc", RvalScalarValue(rval));
}
Ejemplo n.º 25
0
static void test_rval_to_scalar2(void)
{
    Rval rval = { NULL, RVAL_TYPE_FNCALL };
    expect_assert_failure(RvalScalarValue(rval));
}
Ejemplo n.º 26
0
PromiseResult VerifyVarPromise(EvalContext *ctx, const Promise *pp, bool allow_duplicates)
{
    ConvergeVariableOptions opts = CollectConvergeVariableOptions(ctx, pp, allow_duplicates);
    if (!opts.should_converge)
    {
        return PROMISE_RESULT_NOOP;
    }

    Attributes a = { {0} };
    // More consideration needs to be given to using these
    //a.transaction = GetTransactionConstraints(pp);
    a.classes = GetClassDefinitionConstraints(ctx, pp);

    VarRef *ref = VarRefParseFromBundle(pp->promiser, PromiseGetBundle(pp));
    if (strcmp("meta", pp->parent_promise_type->name) == 0)
    {
        VarRefSetMeta(ref, true);
    }

    DataType existing_value_type = CF_DATA_TYPE_NONE;
    const void *const existing_value =
        IsExpandable(pp->promiser) ? NULL : EvalContextVariableGet(ctx, ref, &existing_value_type);

    PromiseResult result = PROMISE_RESULT_NOOP;
    Rval rval = opts.cp_save->rval;

    if (rval.item != NULL)
    {
        DataType data_type = DataTypeFromString(opts.cp_save->lval);

        if (opts.cp_save->rval.type == RVAL_TYPE_FNCALL)
        {
            FnCall *fp = RvalFnCallValue(rval);
            const FnCallType *fn = FnCallTypeGet(fp->name);
            if (!fn)
            {
                assert(false && "Canary: should have been caught before this point");
                FatalError(ctx, "While setting variable '%s' in bundle '%s', unknown function '%s'",
                           pp->promiser, PromiseGetBundle(pp)->name, fp->name);
            }

            if (fn->dtype != DataTypeFromString(opts.cp_save->lval))
            {
                FatalError(ctx, "While setting variable '%s' in bundle '%s', variable declared type '%s' but function '%s' returns type '%s'",
                           pp->promiser, PromiseGetBundle(pp)->name, opts.cp_save->lval,
                           fp->name, DataTypeToString(fn->dtype));
            }

            if (existing_value_type != CF_DATA_TYPE_NONE)
            {
                // Already did this
                VarRefDestroy(ref);
                return PROMISE_RESULT_NOOP;
            }

            FnCallResult res = FnCallEvaluate(ctx, PromiseGetPolicy(pp), fp, pp);

            if (res.status == FNCALL_FAILURE)
            {
                /* We do not assign variables to failed fn calls */
                RvalDestroy(res.rval);
                VarRefDestroy(ref);
                return PROMISE_RESULT_NOOP;
            }
            else
            {
                rval = res.rval;
            }
        }
        else
        {
            Buffer *conv = BufferNew();
            bool malformed = false, misprint = false;

            if (strcmp(opts.cp_save->lval, "int") == 0)
            {
                long int asint = IntFromString(opts.cp_save->rval.item);
                if (asint == CF_NOINT)
                {
                    malformed = true;
                }
                else if (0 > BufferPrintf(conv, "%ld", asint))
                {
                    misprint = true;
                }
                else
                {
                    rval = RvalNew(BufferData(conv), opts.cp_save->rval.type);
                }
            }
            else if (strcmp(opts.cp_save->lval, "real") == 0)
            {
                double real_value;
                if (!DoubleFromString(opts.cp_save->rval.item, &real_value))
                {
                    malformed = true;
                }
                else if (0 > BufferPrintf(conv, "%lf", real_value))
                {
                    misprint = true;
                }
                else
                {
                    rval = RvalNew(BufferData(conv), opts.cp_save->rval.type);
                }
            }
            else
            {
                rval = RvalCopy(opts.cp_save->rval);
            }
            BufferDestroy(conv);

            if (malformed)
            {
                /* Arises when opts->cp_save->rval.item isn't yet expanded. */
                /* Has already been logged by *FromString */
                VarRefDestroy(ref);
                return PromiseResultUpdate(result, PROMISE_RESULT_FAIL);
            }
            else if (misprint)
            {
                /* Even though no problems with memory allocation can
                 * get here, there might be other problems. */
                UnexpectedError("Problems writing to buffer");
                VarRefDestroy(ref);
                return PROMISE_RESULT_NOOP;
            }
            else if (rval.type == RVAL_TYPE_LIST)
            {
                Rlist *rval_list = RvalRlistValue(rval);
                RlistFlatten(ctx, &rval_list);
                rval.item = rval_list;
            }
        }

        if (Epimenides(ctx, PromiseGetBundle(pp)->ns, PromiseGetBundle(pp)->name, pp->promiser, rval, 0))
        {
            Log(LOG_LEVEL_ERR, "Variable '%s' contains itself indirectly - an unkeepable promise", pp->promiser);
            exit(EXIT_FAILURE);
        }
        else
        {
            /* See if the variable needs recursively expanding again */

            Rval returnval = EvaluateFinalRval(ctx, PromiseGetPolicy(pp), ref->ns, ref->scope, rval, true, pp);

            RvalDestroy(rval);

            // freed before function exit
            rval = returnval;
        }

        if (existing_value_type != CF_DATA_TYPE_NONE)
        {
            if (!opts.ok_redefine)    /* only on second iteration, else we ignore broken promises */
            {
                if (THIS_AGENT_TYPE == AGENT_TYPE_COMMON &&
                     !CompareRval(existing_value, DataTypeToRvalType(existing_value_type),
                                  rval.item, rval.type))
                {
                    switch (rval.type)
                    {
                    case RVAL_TYPE_SCALAR:
                        Log(LOG_LEVEL_VERBOSE, "Redefinition of a constant scalar '%s', was '%s' now '%s'",
                            pp->promiser, (const char *)existing_value, RvalScalarValue(rval));
                        PromiseRef(LOG_LEVEL_VERBOSE, pp);
                        break;

                    case RVAL_TYPE_LIST:
                        {
                            Log(LOG_LEVEL_VERBOSE, "Redefinition of a constant list '%s'", pp->promiser);
                            Writer *w = StringWriter();
                            RlistWrite(w, existing_value);
                            char *oldstr = StringWriterClose(w);
                            Log(LOG_LEVEL_VERBOSE, "Old value '%s'", oldstr);
                            free(oldstr);

                            w = StringWriter();
                            RlistWrite(w, rval.item);
                            char *newstr = StringWriterClose(w);
                            Log(LOG_LEVEL_VERBOSE, " New value '%s'", newstr);
                            free(newstr);
                            PromiseRef(LOG_LEVEL_VERBOSE, pp);
                        }
                        break;

                    case RVAL_TYPE_CONTAINER:
                    case RVAL_TYPE_FNCALL:
                    case RVAL_TYPE_NOPROMISEE:
                        break;
                    }
                }

                RvalDestroy(rval);
                VarRefDestroy(ref);
                return result;
            }
        }

        if (IsCf3VarString(pp->promiser))
        {
            // Unexpanded variables, we don't do anything with
            RvalDestroy(rval);
            VarRefDestroy(ref);
            return result;
        }

        if (!IsValidVariableName(pp->promiser))
        {
            Log(LOG_LEVEL_ERR, "Variable identifier contains illegal characters");
            PromiseRef(LOG_LEVEL_ERR, pp);
            RvalDestroy(rval);
            VarRefDestroy(ref);
            return result;
        }

        if (rval.type == RVAL_TYPE_LIST)
        {
            if (opts.drop_undefined)
            {
                for (Rlist *rp = RvalRlistValue(rval); rp; rp = rp->next)
                {
                    if (IsNakedVar(RlistScalarValue(rp), '@'))
                    {
                        free(rp->val.item);
                        rp->val.item = xstrdup(CF_NULL_VALUE);
                    }
                }
            }

            for (const Rlist *rp = RvalRlistValue(rval); rp; rp = rp->next)
            {
                switch (rp->val.type)
                {
                case RVAL_TYPE_SCALAR:
                    break;

                default:
                    // Cannot assign variable because value is a list containing a non-scalar item
                    VarRefDestroy(ref);
                    RvalDestroy(rval);
                    return result;
                }
            }
        }

        if (ref->num_indices > 0)
        {
            if (data_type == CF_DATA_TYPE_CONTAINER)
            {
                char *lval_str = VarRefToString(ref, true);
                Log(LOG_LEVEL_ERR, "Cannot assign a container to an indexed variable name '%s'. Should be assigned to '%s' instead",
                    lval_str, ref->lval);
                free(lval_str);
                VarRefDestroy(ref);
                RvalDestroy(rval);
                return result;
            }
            else
            {
                DataType existing_type = CF_DATA_TYPE_NONE;
                VarRef *base_ref = VarRefCopyIndexless(ref);
                if (EvalContextVariableGet(ctx, ref, &existing_type) && existing_type == CF_DATA_TYPE_CONTAINER)
                {
                    char *lval_str = VarRefToString(ref, true);
                    char *base_ref_str = VarRefToString(base_ref, true);
                    Log(LOG_LEVEL_ERR, "Cannot assign value to indexed variable name '%s', because a container is already assigned to the base name '%s'",
                        lval_str, base_ref_str);
                    free(lval_str);
                    free(base_ref_str);
                    VarRefDestroy(base_ref);
                    VarRefDestroy(ref);
                    RvalDestroy(rval);
                    return result;
                }
                VarRefDestroy(base_ref);
            }
        }


        DataType required_datatype = DataTypeFromString(opts.cp_save->lval);
        if (rval.type != DataTypeToRvalType(required_datatype))
        {
            char *ref_str = VarRefToString(ref, true);
            char *value_str = RvalToString(rval);
            Log(LOG_LEVEL_ERR, "Variable '%s' expected a variable of type '%s', but was given incompatible value '%s'",
                ref_str, DataTypeToString(required_datatype), value_str);
            PromiseRef(LOG_LEVEL_ERR, pp);
            free(ref_str);
            free(value_str);
            VarRefDestroy(ref);
            RvalDestroy(rval);
            return PromiseResultUpdate(result, PROMISE_RESULT_FAIL);
        }

        if (!EvalContextVariablePut(ctx, ref, rval.item, required_datatype, "source=promise"))
        {
            Log(LOG_LEVEL_VERBOSE,
                "Unable to converge %s.%s value (possibly empty or infinite regression)",
                ref->scope, pp->promiser);
            PromiseRef(LOG_LEVEL_VERBOSE, pp);
            result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL);
        }
        else
        {
            Rlist *promise_meta = PromiseGetConstraintAsList(ctx, "meta", pp);
            if (promise_meta)
            {
                StringSet *class_meta = EvalContextVariableTags(ctx, ref);
                Buffer *print;
                for (const Rlist *rp = promise_meta; rp; rp = rp->next)
                {
                    StringSetAdd(class_meta, xstrdup(RlistScalarValue(rp)));
                    print = StringSetToBuffer(class_meta, ',');
                    Log(LOG_LEVEL_DEBUG,
                        "Added tag %s to class %s, tags now [%s]",
                        RlistScalarValue(rp), pp->promiser, BufferData(print));
                    BufferDestroy(print);
                }
            }
        }
    }
    else
    {
        Log(LOG_LEVEL_ERR, "Variable %s has no promised value", pp->promiser);
        Log(LOG_LEVEL_ERR, "Rule from %s at/before line %llu",
            PromiseGetBundle(pp)->source_path,
            (unsigned long long)opts.cp_save->offset.line);
        result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL);
    }

    /*
     * FIXME: Variable promise are exempt from normal evaluation logic still, so
     * they are not pushed to evaluation stack before being evaluated. Due to
     * this reason, we cannot call cfPS here to set classes, as it will error
     * out with ProgrammingError.
     *
     * In order to support 'classes' body for variables as well, we call
     * ClassAuditLog explicitly.
     */
    ClassAuditLog(ctx, pp, a, result);

    VarRefDestroy(ref);
    RvalDestroy(rval);

    return result;
}
Ejemplo n.º 27
0
SyntaxTypeMatch CheckConstraintTypeMatch(const char *lval, Rval rval, DataType dt, const char *range, int level)
{
 Rlist *rp;
 Item *checklist;

/* Get type of lval */

 switch (rval.type)
    {
    case RVAL_TYPE_SCALAR:
        switch (dt)
           {
           case CF_DATA_TYPE_STRING_LIST:
           case CF_DATA_TYPE_INT_LIST:
           case CF_DATA_TYPE_REAL_LIST:
           case CF_DATA_TYPE_CONTEXT_LIST:
           case CF_DATA_TYPE_OPTION_LIST:
               if (level == 0)
                  {
                  return SYNTAX_TYPE_MATCH_ERROR_GOT_SCALAR;
                  }
               break;
           default:
               /* Only lists are incompatible with scalars */
               break;
           }
        break;

    case RVAL_TYPE_LIST:

        switch (dt)
           {
           case CF_DATA_TYPE_STRING_LIST:
           case CF_DATA_TYPE_INT_LIST:
           case CF_DATA_TYPE_REAL_LIST:
           case CF_DATA_TYPE_CONTEXT_LIST:
           case CF_DATA_TYPE_OPTION_LIST:
               break;
           default:
               return SYNTAX_TYPE_MATCH_ERROR_GOT_LIST;
           }

        for (rp = (Rlist *) rval.item; rp != NULL; rp = rp->next)
           {
           SyntaxTypeMatch err = CheckConstraintTypeMatch(lval, rp->val, dt, range, 1);
           switch (err)
              {
              case SYNTAX_TYPE_MATCH_OK:
              case SYNTAX_TYPE_MATCH_ERROR_UNEXPANDED:
                  break;

              default:
                  return err;
              }
           }

        return SYNTAX_TYPE_MATCH_OK;

    case RVAL_TYPE_FNCALL:

        /* Fn-like objects are assumed to be parameterized bundles in these... */

        checklist = SplitString("bundlesequence,edit_line,edit_xml,usebundle,service_bundle,home_bundle", ',');

        if (!IsItemIn(checklist, lval))
           {
           SyntaxTypeMatch err = CheckFnCallType(RvalFnCallValue(rval)->name, dt);
           DeleteItemList(checklist);
           return err;
           }

        DeleteItemList(checklist);
        return SYNTAX_TYPE_MATCH_OK;

    case RVAL_TYPE_CONTAINER:
        break;

    case RVAL_TYPE_NOPROMISEE:
        return SYNTAX_TYPE_MATCH_ERROR_GOT_NULL;
    }

/* If we get here, we have a literal scalar type */

 switch (dt)
    {
    case CF_DATA_TYPE_STRING:
    case CF_DATA_TYPE_STRING_LIST:
        return CheckParseString(lval, (const char *) rval.item, range);

    case CF_DATA_TYPE_INT:
    case CF_DATA_TYPE_INT_LIST:
        return CheckParseInt(lval, (const char *) rval.item, range);

    case CF_DATA_TYPE_REAL:
    case CF_DATA_TYPE_REAL_LIST:
        return CheckParseReal(lval, (const char *) rval.item, range);

    case CF_DATA_TYPE_BODY:
    case CF_DATA_TYPE_BUNDLE:
    case CF_DATA_TYPE_CONTAINER:
        break;

    case CF_DATA_TYPE_OPTION:
    case CF_DATA_TYPE_OPTION_LIST:
        return CheckParseOpts(RvalScalarValue(rval), range);

    case CF_DATA_TYPE_CONTEXT:
    case CF_DATA_TYPE_CONTEXT_LIST:
        return CheckParseContext((const char *) rval.item, range);

    case CF_DATA_TYPE_INT_RANGE:
        return CheckParseIntRange(lval, (const char *) rval.item, range);

    case CF_DATA_TYPE_REAL_RANGE:
        return CheckParseRealRange(lval, (char *) rval.item, range);

    default:
        ProgrammingError("Unknown (unhandled) datatype for lval = %s (CheckConstraintTypeMatch)", lval);
        break;
    }

 return SYNTAX_TYPE_MATCH_OK;
}
Ejemplo n.º 28
0
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;
}
Ejemplo n.º 29
0
void ScopeMapBodyArgs(EvalContext *ctx, const Body *body, const Rlist *args)
{
    const Rlist *arg = NULL;
    const Rlist *param = NULL;

    for (arg = args, param = body->args; arg != NULL && param != NULL; arg = arg->next, param = param->next)
    {
        DataType arg_type = CF_DATA_TYPE_NONE;
        switch (arg->val.type)
        {
        case RVAL_TYPE_SCALAR:
            arg_type = StringDataType(ctx, RlistScalarValue(arg));
            break;

        case RVAL_TYPE_FNCALL:
            {
                const FnCallType *fn = FnCallTypeGet(RlistFnCallValue(arg)->name);
                if (!fn)
                {
                    FatalError(ctx, "Argument '%s' given to body '%s' is not a valid function",
                               RlistFnCallValue(arg)->name, body->name);
                }
                arg_type = fn->dtype;
            }
            break;

        default:
            FatalError(ctx, "Cannot derive data type from Rval type %c", arg->val.type);
        }

        switch (arg->val.type)
        {
        case RVAL_TYPE_SCALAR:
            {
                const char *lval = RlistScalarValue(param);
                VarRef *ref = VarRefParseFromNamespaceAndScope(lval, NULL, "body", CF_NS, '.');
                EvalContextVariablePut(ctx, ref, RvalScalarValue(arg->val), arg_type, "source=body");
                VarRefDestroy(ref);
            }
            break;

        case RVAL_TYPE_LIST:
            {
                const char *lval = RlistScalarValue(param);
                VarRef *ref = VarRefParseFromNamespaceAndScope(lval, NULL, "body", CF_NS, '.');
                EvalContextVariablePut(ctx, ref, RvalRlistValue(arg->val), arg_type, "source=body");
                VarRefDestroy(ref);
            }
            break;

        case RVAL_TYPE_FNCALL:
            {
                FnCall *fp = RlistFnCallValue(arg);
                arg_type = CF_DATA_TYPE_NONE;
                {
                    const FnCallType *fncall_type = FnCallTypeGet(fp->name);
                    if (fncall_type)
                    {
                        arg_type = fncall_type->dtype;
                    }
                }

                FnCallResult res = FnCallEvaluate(ctx, body->parent_policy, fp, NULL);

                if (res.status == FNCALL_FAILURE && THIS_AGENT_TYPE != AGENT_TYPE_COMMON)
                {
                    Log(LOG_LEVEL_VERBOSE, "Embedded function argument does not resolve to a name - probably too many evaluation levels for '%s'",
                        fp->name);
                }
                else
                {
                    const char *lval = RlistScalarValue(param);
                    void *rval = res.rval.item;

                    VarRef *ref = VarRefParseFromNamespaceAndScope(lval, NULL, "body", CF_NS, '.');
                    EvalContextVariablePut(ctx, ref, rval, arg_type, "source=body");
                    VarRefDestroy(ref);
                }

                RvalDestroy(res.rval);
            }

            break;

        default:
            /* Nothing else should happen */
            ProgrammingError("Software error: something not a scalar/function in argument literal");
        }
    }
}
Ejemplo n.º 30
0
void KeepPromises(Policy *policy, ExecConfig *config)
{
    bool schedule_is_specified = false;

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

            if (IsExcluded(cp->classes, NULL))
            {
                continue;
            }

            Rval retval;
            if (GetVariable("control_executor", cp->lval, &retval) == DATA_TYPE_NONE)
            {
                CfOut(OUTPUT_LEVEL_ERROR, "", "Unknown lval %s in exec control body", cp->lval);
                continue;
            }

            if (strcmp(cp->lval, CFEX_CONTROLBODY[cfex_mailfrom].lval) == 0)
            {
                free(config->mail_from_address);
                config->mail_from_address = SafeStringDuplicate(retval.item);
                CfDebug("mailfrom = %s\n", config->mail_from_address);
            }

            if (strcmp(cp->lval, CFEX_CONTROLBODY[cfex_mailto].lval) == 0)
            {
                free(config->mail_to_address);
                config->mail_to_address = SafeStringDuplicate(retval.item);
                CfDebug("mailto = %s\n", config->mail_to_address);
            }

            if (strcmp(cp->lval, CFEX_CONTROLBODY[cfex_smtpserver].lval) == 0)
            {
                free(config->mail_server);
                config->mail_server = SafeStringDuplicate(retval.item);
                CfDebug("smtpserver = %s\n", config->mail_server);
            }

            if (strcmp(cp->lval, CFEX_CONTROLBODY[cfex_execcommand].lval) == 0)
            {
                free(config->exec_command);
                config->exec_command = SafeStringDuplicate(retval.item);
                CfDebug("exec_command = %s\n", config->exec_command);
            }

            if (strcmp(cp->lval, CFEX_CONTROLBODY[cfex_agent_expireafter].lval) == 0)
            {
                config->agent_expireafter = IntFromString(retval.item);
                CfDebug("agent_expireafter = %d\n", config->agent_expireafter);
            }

            if (strcmp(cp->lval, CFEX_CONTROLBODY[cfex_executorfacility].lval) == 0)
            {
                SetFacility(retval.item);
                continue;
            }

            if (strcmp(cp->lval, CFEX_CONTROLBODY[cfex_mailmaxlines].lval) == 0)
            {
                config->mail_max_lines = IntFromString(retval.item);
                CfDebug("maxlines = %d\n", config->mail_max_lines);
            }

            if (strcmp(cp->lval, CFEX_CONTROLBODY[cfex_splaytime].lval) == 0)
            {
                int time = IntFromString(RvalScalarValue(retval));

                SPLAYTIME = (int) (time * SECONDS_PER_MINUTE * GetSplay());
            }

            if (strcmp(cp->lval, CFEX_CONTROLBODY[cfex_schedule].lval) == 0)
            {
                CfDebug("Loading user-defined schedule...\n");
                DeleteItemList(SCHEDULE);
                SCHEDULE = NULL;
                schedule_is_specified = true;

                for (const Rlist *rp = retval.item; rp; rp = rp->next)
                {
                    if (!IsItemIn(SCHEDULE, rp->item))
                    {
                        AppendItem(&SCHEDULE, rp->item, NULL);
                    }
                }
            }
        }
    }

    if (!schedule_is_specified)
    {
        LoadDefaultSchedule();
    }
}