示例#1
0
PromiseResult ScheduleEditOperation(EvalContext *ctx, char *filename, Attributes a, Promise *pp)
{
    void *vp;
    FnCall *fp;
    Rlist *args = NULL;
    char edit_bundle_name[CF_BUFSIZE], lockname[CF_BUFSIZE], qualified_edit[CF_BUFSIZE], *method_deref;
    CfLock thislock;

    snprintf(lockname, CF_BUFSIZE - 1, "fileedit-%s", filename);
    thislock = AcquireLock(ctx, lockname, VUQNAME, CFSTARTTIME, a.transaction, pp, false);

    if (thislock.lock == NULL)
    {
        return PROMISE_RESULT_NOOP;
    }

    EditContext *edcontext = NewEditContext(filename, a);

    PromiseResult result = PROMISE_RESULT_NOOP;
    if (edcontext == NULL)
    {
        cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "File '%s' was marked for editing but could not be opened", filename);
        result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL);
        goto exit;
    }

    Policy *policy = PolicyFromPromise(pp);

    if (a.haveeditline)
    {
        if ((vp = ConstraintGetRvalValue(ctx, "edit_line", pp, RVAL_TYPE_FNCALL)))
        {
            fp = (FnCall *) vp;
            strcpy(edit_bundle_name, fp->name);
            args = fp->args;
        }
        else if ((vp = ConstraintGetRvalValue(ctx, "edit_line", pp, RVAL_TYPE_SCALAR)))
        {
            strcpy(edit_bundle_name, (char *) vp);
            args = NULL;
        }             
        else
        {
            goto exit;
        }

        if (strncmp(edit_bundle_name,"default:",strlen("default:")) == 0) // CF_NS == ':'
        {
            method_deref = strchr(edit_bundle_name, CF_NS) + 1;
        }
        else if ((strchr(edit_bundle_name, CF_NS) == NULL) && (strcmp(PromiseGetNamespace(pp), "default") != 0))
        {
            snprintf(qualified_edit, CF_BUFSIZE, "%s%c%s", PromiseGetNamespace(pp), CF_NS, edit_bundle_name);
            method_deref = qualified_edit;
        }
        else            
        {
            method_deref = edit_bundle_name;
        }        

        Log(LOG_LEVEL_VERBOSE, "Handling file edits in edit_line bundle '%s'", method_deref);

        Bundle *bp = NULL;
        if ((bp = PolicyGetBundle(policy, NULL, "edit_line", method_deref)))
        {
            BannerSubBundle(bp, args);

            EvalContextStackPushBundleFrame(ctx, bp, args, a.edits.inherit);

            BundleResolve(ctx, bp);

            ScheduleEditLineOperations(ctx, bp, a, pp, edcontext);

            EvalContextStackPopFrame(ctx);
        }
        else
        {
            Log(LOG_LEVEL_ERR, "Did not find method '%s' in bundle '%s' for edit operation", method_deref, edit_bundle_name);
        }
    }


    if (a.haveeditxml)
    {
        if ((vp = ConstraintGetRvalValue(ctx, "edit_xml", pp, RVAL_TYPE_FNCALL)))
        {
            fp = (FnCall *) vp;
            strcpy(edit_bundle_name, fp->name);
            args = fp->args;
        }
        else if ((vp = ConstraintGetRvalValue(ctx, "edit_xml", pp, RVAL_TYPE_SCALAR)))
        {
            strcpy(edit_bundle_name, (char *) vp);
            args = NULL;
        }
        else
        {
            goto exit;
        }

        if (strncmp(edit_bundle_name,"default:",strlen("default:")) == 0) // CF_NS == ':'
        {
            method_deref = strchr(edit_bundle_name, CF_NS) + 1;
        }
        else
        {
            method_deref = edit_bundle_name;
        }
        
        Log(LOG_LEVEL_VERBOSE, "Handling file edits in edit_xml bundle '%s'", method_deref);

        Bundle *bp = NULL;
        if ((bp = PolicyGetBundle(policy, NULL, "edit_xml", method_deref)))
        {
            BannerSubBundle(bp, args);

            EvalContextStackPushBundleFrame(ctx, bp, args, a.edits.inherit);
            BundleResolve(ctx, bp);

            ScheduleEditXmlOperations(ctx, bp, a, pp, edcontext);

            EvalContextStackPopFrame(ctx);
        }
    }

    
    if (a.edit_template)
    {
        if (!a.template_method || strcmp("cfengine", a.template_method) == 0)
        {
            Policy *tmp_policy = PolicyNew();
            Bundle *bp = NULL;
            if ((bp = MakeTemporaryBundleFromTemplate(ctx, tmp_policy, a, pp, &result)))
            {
                BannerSubBundle(bp, args);
                a.haveeditline = true;

                EvalContextStackPushBundleFrame(ctx, bp, args, a.edits.inherit);
                BundleResolve(ctx, bp);

                ScheduleEditLineOperations(ctx, bp, a, pp, edcontext);

                EvalContextStackPopFrame(ctx);
            }

            PolicyDestroy(tmp_policy);
        }
        else if (strcmp("mustache", a.template_method) == 0)
        {
            if (!FileCanOpen(a.edit_template, "r"))
            {
                cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Template file '%s' could not be opened for reading", a.edit_template);
                result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL);
                goto exit;
            }

            Writer *ouput_writer = NULL;
            {
                FILE *output_file = fopen(pp->promiser, "w");
                if (!output_file)
                {
                    cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Output file '%s' could not be opened for writing", pp->promiser);
                    result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL);
                    goto exit;
                }

                ouput_writer = FileWriter(output_file);
            }

            Writer *template_writer = FileRead(a.edit_template, SIZE_MAX, NULL);
            if (!template_writer)
            {
                cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Could not read template file '%s'", a.edit_template);
                result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL);
                WriterClose(ouput_writer);
                goto exit;
            }

            JsonElement *default_template_data = NULL;
            if (!a.template_data)
            {
                a.template_data = default_template_data = DefaultTemplateData(ctx);
            }

            if (!MustacheRender(ouput_writer, StringWriterData(template_writer), a.template_data))
            {
                cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Error rendering mustache template '%s'", a.edit_template);
                result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL);
                WriterClose(template_writer);
                WriterClose(ouput_writer);
                goto exit;
            }

            JsonDestroy(default_template_data);
            WriterClose(template_writer);
            WriterClose(ouput_writer);
        }
    }

exit:
    result = PromiseResultUpdate(result, FinishEditContext(ctx, edcontext, a, pp));
    YieldCurrentLock(thislock);
    return result;
}
示例#2
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));
}
示例#3
0
文件: verify_files.c 项目: lra/core
static PromiseResult RenderTemplateMustache(EvalContext *ctx, const Promise *pp, Attributes a,
                                            EditContext *edcontext)
{
    PromiseResult result = PROMISE_RESULT_NOOP;

    if (!FileCanOpen(a.edit_template, "r"))
    {
        cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Template file '%s' could not be opened for reading", a.edit_template);
        return PromiseResultUpdate(result, PROMISE_RESULT_FAIL);
    }

    unsigned char existing_output_digest[EVP_MAX_MD_SIZE + 1] = { 0 };
    if (access(pp->promiser, R_OK) == 0)
    {
        HashFile(pp->promiser, existing_output_digest, CF_DEFAULT_DIGEST);
    }

    int template_fd = safe_open(a.edit_template, O_RDONLY | O_TEXT);
    Writer *template_writer = NULL;
    if (template_fd >= 0)
    {
        template_writer = FileReadFromFd(template_fd, SIZE_MAX, NULL);
        close(template_fd);
    }
    if (!template_writer)
    {
        cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Could not read template file '%s'", a.edit_template);
        return PromiseResultUpdate(result, PROMISE_RESULT_FAIL);
    }

    JsonElement *default_template_data = NULL;
    if (!a.template_data)
    {
        a.template_data = default_template_data = DefaultTemplateData(ctx);
    }

    Buffer *output_buffer = BufferNew();
    if (MustacheRender(output_buffer, StringWriterData(template_writer), a.template_data))
    {
        unsigned char rendered_output_digest[EVP_MAX_MD_SIZE + 1] = { 0 };
        HashString(BufferData(output_buffer), BufferSize(output_buffer), rendered_output_digest, CF_DEFAULT_DIGEST);
        if (!HashesMatch(existing_output_digest, rendered_output_digest, CF_DEFAULT_DIGEST))
        {
            if (SaveAsFile(SaveBufferCallback, output_buffer, edcontext->filename, a, edcontext->new_line_mode))
            {
                cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_CHANGE, pp, a, "Updated rendering of '%s' from template mustache template '%s'",
                     pp->promiser, a.edit_template);
                result = PromiseResultUpdate(result, PROMISE_RESULT_CHANGE);
            }
            else
            {
                cfPS(ctx, LOG_LEVEL_INFO, PROMISE_RESULT_FAIL, pp, a, "Updated rendering of '%s' from template mustache template '%s'",
                     pp->promiser, a.edit_template);
                result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL);
            }
        }

        JsonDestroy(default_template_data);
        WriterClose(template_writer);
        BufferDestroy(output_buffer);

        return result;
    }
    else
    {
        cfPS(ctx, LOG_LEVEL_ERR, PROMISE_RESULT_FAIL, pp, a, "Error rendering mustache template '%s'", a.edit_template);
        result = PromiseResultUpdate(result, PROMISE_RESULT_FAIL);
        JsonDestroy(default_template_data);
        WriterClose(template_writer);
        BufferDestroy(output_buffer);
        return PromiseResultUpdate(result, PROMISE_RESULT_FAIL);
    }
}
示例#4
0
/*
 * The difference between filename and input_input file is that the latter is the file specified by -f or
 * equivalently the file containing body common control. This will hopefully be squashed in later refactoring.
 */
static Policy *Cf3ParseFile(const GenericAgentConfig *config, const char *input_path)
{
    struct stat statbuf;

    if (stat(input_path, &statbuf) == -1)
    {
        if (config->ignore_missing_inputs)
        {
            return PolicyNew();
        }

        Log(LOG_LEVEL_ERR, "Can't stat file '%s' for parsing. (stat: %s)", input_path, GetErrorStr());
        exit(1);
    }

#ifndef _WIN32
    if (config->check_not_writable_by_others && (statbuf.st_mode & (S_IWGRP | S_IWOTH)))
    {
        Log(LOG_LEVEL_ERR, "File %s (owner %ju) is writable by others (security exception)", input_path, (uintmax_t)statbuf.st_uid);
        exit(1);
    }
#endif

    Log(LOG_LEVEL_VERBOSE, "Parsing file '%s'", input_path);

    if (!FileCanOpen(input_path, "r"))
    {
        Log(LOG_LEVEL_ERR, "Can't open file '%s' for parsing", input_path);
        exit(1);
    }

    Policy *policy = NULL;
    if (StringEndsWith(input_path, ".json"))
    {
        char *contents = NULL;
        if (FileReadMax(&contents, input_path, SIZE_MAX) == -1)
        {
            Log(LOG_LEVEL_ERR, "Error reading JSON input file '%s'", input_path);
            return NULL;
        }
        JsonElement *json_policy = NULL;
        const char *data = contents; // TODO: need to fix JSON parser signature, just silly
        if (JsonParse(&data, &json_policy) != JSON_PARSE_OK)
        {
            Log(LOG_LEVEL_ERR, "Error parsing JSON input file '%s'", input_path);
            free(contents);
            return NULL;
        }

        policy = PolicyFromJson(json_policy);

        JsonDestroy(json_policy);
        free(contents);
    }
    else
    {
        if (config->agent_type == AGENT_TYPE_COMMON)
        {
            policy = ParserParseFile(input_path, config->agent_specific.common.parser_warnings, config->agent_specific.common.parser_warnings_error);
        }
        else
        {
            policy = ParserParseFile(input_path, 0, 0);
        }
    }

    return policy;
}
示例#5
0
文件: loading.c 项目: atsaloli/core
/*
 * The difference between filename and input_input file is that the latter is the file specified by -f or
 * equivalently the file containing body common control. This will hopefully be squashed in later refactoring.
 */
Policy *Cf3ParseFile(const GenericAgentConfig *config, const char *input_path)
{
    struct stat statbuf;

    if (stat(input_path, &statbuf) == -1)
    {
        if (config->ignore_missing_inputs)
        {
            return PolicyNew();
        }

        Log(LOG_LEVEL_ERR, "Can't stat file '%s' for parsing. (stat: %s)", input_path, GetErrorStr());
        exit(EXIT_FAILURE);
    }
    else if (S_ISDIR(statbuf.st_mode))
    {
        if (config->ignore_missing_inputs)
        {
            return PolicyNew();
        }

        Log(LOG_LEVEL_ERR, "Can't parse directory '%s'.", input_path);
        exit(EXIT_FAILURE);
    }

#ifndef _WIN32
    if (config->check_not_writable_by_others && (statbuf.st_mode & (S_IWGRP | S_IWOTH)))
    {
        Log(LOG_LEVEL_ERR, "File %s (owner %ju) is writable by others (security exception)", input_path, (uintmax_t)statbuf.st_uid);
        exit(EXIT_FAILURE);
    }
#endif

    Log(LOG_LEVEL_VERBOSE, "BEGIN parsing file: %s", input_path);

    if (!FileCanOpen(input_path, "r"))
    {
        Log(LOG_LEVEL_ERR, "Can't open file '%s' for parsing", input_path);
        exit(EXIT_FAILURE);
    }

    Policy *policy = NULL;
    if (StringEndsWith(input_path, ".json"))
    {
        Writer *contents = FileRead(input_path, SIZE_MAX, NULL);
        if (!contents)
        {
            Log(LOG_LEVEL_ERR, "Error reading JSON input file '%s'", input_path);
            return NULL;
        }
        JsonElement *json_policy = NULL;
        const char *data = StringWriterData(contents);
        if (JsonParse(&data, &json_policy) != JSON_PARSE_OK)
        {
            Log(LOG_LEVEL_ERR, "Error parsing JSON input file '%s'", input_path);
            WriterClose(contents);
            return NULL;
        }

        policy = PolicyFromJson(json_policy);

        JsonDestroy(json_policy);
        WriterClose(contents);
    }
    else
    {
        if (config->agent_type == AGENT_TYPE_COMMON)
        {
            policy = ParserParseFile(config->agent_type, input_path, config->agent_specific.common.parser_warnings, config->agent_specific.common.parser_warnings_error);
        }
        else
        {
            policy = ParserParseFile(config->agent_type, input_path, 0, 0);
        }
    }

    Log(LOG_LEVEL_VERBOSE, "END   parsing file: %s", input_path);
    return policy;
}