Exemple #1
0
static const char *am_set_opt(cmd_parms *c, void *cfg, const char *arg) {
    amagent_config_t *conf = (amagent_config_t *)
            ap_get_module_config(c->server->module_config, &amagent_module);
    if (conf) {
        const char *name = c->cmd->name;
        if (name) {
            if (strcmp(name, "AmAgentConf") == 0) {
                am_config_t *ac = NULL;
                conf->config = apr_psprintf(c->pool, "%s", arg);
                conf->config_id = am_instance_id(conf->config);
                /* read and parse agent bootstrap configuration */
                ac = am_get_config_file(conf->config_id, conf->config);
                if (ac != NULL) {
                    conf->debug_file = ac->debug_file != NULL ? apr_pstrdup(c->pool, ac->debug_file) : NULL;
                    conf->audit_file = ac->audit_file != NULL ? apr_pstrdup(c->pool, ac->audit_file) : NULL;
                    conf->debug_level = ac->debug_level;
                    conf->audit_level = ac->audit_level;
                    conf->error = AM_SUCCESS;
                    am_config_free(&ac);
                } else {
                    conf->error = AM_FILE_ERROR;
                }
            } else if (strcmp(name, "AmAgent") == 0) {
                if (!strcasecmp(arg, "on")) {
                    conf->enabled = 1;
                } else {
                    conf->enabled = 0;
                }
            }
        }
    }
    return NULL;
}
Exemple #2
0
am_config_t *am_parse_config_xml(unsigned long instance_id, const char *xml, size_t xml_sz, char log_enable) {
    const char *thisfunc = "am_parse_config_xml():";
    am_config_t *r = NULL;
    char *begin, *stream = NULL;
    size_t data_sz;
    pcre *x = NULL;
    const char *error = NULL;
    int erroroffset;

    am_xml_parser_ctx_t xctx = {.depth = 0, .setting_value = 0,
        .conf = NULL, .rgx = NULL, .parser = NULL, .log_enable = log_enable};

    if (xml == NULL || xml_sz == 0) {
        am_log_error(instance_id, "%s memory allocation error", thisfunc);
        return NULL;
    }

    /*match [key]=value returned within <value>[key]=value_of_a_key</value> element*/
    x = pcre_compile("(?<=\\[)(.+?)(?=\\])\\]\\s*\\=\\s*(.+)", 0, &error, &erroroffset, NULL);
    if (x == NULL) {
        am_log_error(instance_id, "%s pcre error %s", thisfunc, error == NULL ? "" : error);
    }

    r = calloc(1, sizeof (am_config_t));
    if (r == NULL) {
        am_log_error(instance_id, "%s memory allocation error", thisfunc);
        pcre_free(x);
        return NULL;
    }
    r->instance_id = instance_id;

    begin = strstr(xml, "![CDATA[");
    if (begin != NULL) {
        char *end = strstr(begin + 8, "]]>");
        if (end != NULL) {
            stream = begin + 8;
            data_sz = end - (begin + 8);
        }
    } else {
        /*no CDATA*/
        stream = (char *) xml;
        data_sz = xml_sz;
    }

    if (stream != NULL && data_sz > 0) {
        XML_Parser parser = XML_ParserCreate("UTF-8");
        xctx.parser = &parser;
        xctx.conf = r;
        xctx.rgx = x;
        XML_SetUserData(parser, &xctx);
        XML_SetElementHandler(parser, start_element, end_element);
        XML_SetCharacterDataHandler(parser, character_data);
        XML_SetEntityDeclHandler(parser, entity_declaration);
        if (XML_Parse(parser, stream, (int) data_sz, XML_TRUE) == XML_STATUS_ERROR) {
            const char *message = XML_ErrorString(XML_GetErrorCode(parser));
            int line = XML_GetCurrentLineNumber(parser);
            int col = XML_GetCurrentColumnNumber(parser);
            am_log_error(instance_id, "%s xml parser error (%d:%d) %s", thisfunc,
                    line, col, message);
            am_config_free(&r);
            r = NULL;
        } else {
            r->ts = time(NULL);
        }
        XML_ParserFree(parser);
    }

    pcre_free(x);
    return r;
}
Exemple #3
0
static int amagent_auth_handler(request_rec *r) {
    const char *thisfunc = "amagent_auth_handler():";
    int rv;
    am_request_t d;
    am_config_t *boot = NULL;

    amagent_config_t *c = ap_get_module_config(r->server->module_config, &amagent_module);

    if (c == NULL || !c->enabled || c->error != AM_SUCCESS) {
        /* amagent module is not enabled for this 
         * server/virtualhost - we are not handling this request
         **/
        return DECLINED;
    }

    if (c->error != AM_SUCCESS) {
        LOG_R(APLOG_ERR, r, "%s is not configured to handle the request "
                "to %s (unable to load bootstrap configuration from %s, error: %s)",
                DESCRIPTION, r->uri, c->config, am_strerror(c->error));
        return HTTP_FORBIDDEN;
    }

    LOG_R(APLOG_DEBUG, r, "amagent_auth_handler(): [%s] [%ld]", c->config, c->config_id);

    /* register and update instance logger configuration (for already registered
     * instances - update logging level only 
     */
    am_log_register_instance(c->config_id, c->debug_file, c->debug_level,
            c->audit_file, c->audit_level);

    am_log_debug(c->config_id, "%s begin", thisfunc);

    /* fetch agent configuration instance (from cache if available) */
    rv = am_get_agent_config(c->config_id, c->config, &boot);
    if (boot == NULL || rv != AM_SUCCESS) {
        LOG_R(APLOG_ERR, r, "%s is not configured to handle the request "
                "to %s (unable to get agent configuration instance, configuration: %s, error: %s)",
                DESCRIPTION, r->uri, c->config, am_strerror(rv));
        am_log_error(c->config_id, "amagent_auth_handler(): failed to get agent configuration instance, error: %s",
                am_strerror(rv));
        return HTTP_FORBIDDEN;
    }

    /* set up request processor data structure */
    memset(&d, 0, sizeof (am_request_t));
    d.conf = boot;
    d.status = AM_ERROR;
    d.instance_id = c->config_id;
    d.ctx = r;
    d.method = get_method_num(r, c->config_id);
    d.content_type = apr_table_get(r->headers_in, "Content-Type");
    d.cookies = apr_table_get(r->headers_in, "Cookie");

    if (ISVALID(d.conf->client_ip_header)) {
        d.client_ip = (char *) apr_table_get(r->headers_in, d.conf->client_ip_header);
    }
    if (!ISVALID(d.client_ip)) {
#ifdef APACHE24
        d.client_ip = (char *) r->connection->client_ip;
#else
        d.client_ip = (char *) r->connection->remote_ip;
#endif
    }

    if (ISVALID(d.conf->client_hostname_header)) {
        d.client_host = (char *) apr_table_get(r->headers_in, d.conf->client_hostname_header);
    }

    d.am_get_request_url_f = get_request_url;
    d.am_get_post_data_f = get_request_body;
    d.am_set_post_data_f = set_request_body;
    d.am_set_user_f = set_user;
    d.am_set_header_in_request_f = set_header_in_request;
    d.am_add_header_in_response_f = add_header_in_response;
    d.am_set_cookie_f = set_cookie;
    d.am_set_custom_response_f = set_custom_response;
    d.am_set_method_f = set_method;

    am_process_request(&d);

    rv = am_status_value(d.status);

    am_log_debug(c->config_id, "amagent_auth_handler(): exit status: %s (%d)",
            am_strerror(d.status), d.status);

    am_config_free(&d.conf);
    am_request_free(&d);

    LOG_R(APLOG_DEBUG, r, "amagent_auth_handler(): return status: %d", rv);
    return rv;
}
void url_validator_worker(void *arg) {
    static const char *thisfunc = "url_validator_worker():";
    struct url_validator_worker_data *w = (struct url_validator_worker_data *) arg;
    am_net_options_t *net_options;
    int i, validate_status;
    am_config_t *conf = NULL;
    time_t current_ts;
    struct url_valid_table *e, *t;
    int current_index, current_ok, current_fail, default_ok, next_ok;
    char **url_list;
    int url_list_sz = 0;
    int ping_diff;

    set_valid_url_instance_running(w->instance_id, AM_TRUE);

    conf = am_get_config_file(w->instance_id, w->config_path);
    if (conf == NULL) {
        AM_LOG_WARNING(w->instance_id, "%s failed to get agent configuration (%s)",
                thisfunc, LOGEMPTY(w->config_path));
        set_valid_url_instance_running(w->instance_id, AM_FALSE);
        AM_FREE(w->config_path, w);
        return;
    }

    ping_diff = MAX(MIN_URL_VALIDATOR_TICK, conf->valid_ping);
    current_ts = time(NULL);
    /* this index corresponds to the naming.url multi-value index */
    current_index = w->url_index;

    if (conf->valid_level > 1 || conf->naming_url_sz < 2 || conf->naming_url_sz != conf->valid_default_url_sz ||
            (current_ts - w->last) < ping_diff) {
        /* a) validation is disabled; b) there is nothing to validate;
         * c) naming.url list and default.url list sizes do not match or
         * d) its not time yet to do any validation
         */
        am_config_free(&conf);
        set_valid_url_instance_running(w->instance_id, AM_FALSE);
        AM_FREE(w->config_path, w);
        return;
    }

    if (current_index < 0 || current_index >= conf->naming_url_sz) {
        AM_LOG_WARNING(w->instance_id,
                "%s invalid current index value, defaulting to %s", thisfunc, conf->naming_url[0]);
        set_valid_url_index(w->instance_id, 0);
        am_config_free(&conf);
        set_valid_url_instance_running(w->instance_id, AM_FALSE);
        AM_FREE(w->config_path, w);
        return;
    }

#define URL_LIST_FREE(l, s) do { \
        int k; \
        if (l == NULL) break; \
        for (k = 0; k < s; k++) { \
            am_free(l[k]); \
        }\
        free(l); \
    } while (0)

    net_options = calloc(1, sizeof (am_net_options_t));
    if (net_options == NULL) {
        AM_LOG_ERROR(w->instance_id, "%s memory allocation error", thisfunc);
        am_config_free(&conf);
        set_valid_url_instance_running(w->instance_id, AM_FALSE);
        AM_FREE(w->config_path, w);
        return;
    }

    url_list = (char **) calloc(1, conf->naming_url_sz * sizeof (char *));
    if (url_list == NULL) {
        AM_LOG_ERROR(w->instance_id, "%s memory allocation error", thisfunc);
        am_config_free(&conf);
        set_valid_url_instance_running(w->instance_id, AM_FALSE);
        AM_FREE(net_options, w->config_path, w);
        return;
    }
    url_list_sz = conf->naming_url_sz;

    for (i = 0; i < url_list_sz; i++) {
        /* default.url.set contains fail-over order;
         * will keep internal value list index-ordered 
         **/
        int j = conf->valid_default_url[i];
        url_list[i] = strdup(conf->naming_url[j]);
        if (url_list[i] == NULL) {
            URL_LIST_FREE(url_list, url_list_sz);
            am_config_free(&conf);
            set_valid_url_instance_running(w->instance_id, AM_FALSE);
            AM_FREE(net_options, w->config_path, w);
            return;
        }
    }

    am_net_options_create(conf, net_options, NULL);
    net_options->keepalive = AM_FALSE;
    net_options->local = net_options->cert_trust = AM_TRUE;
    net_options->net_timeout = 2; /* fixed for url validator; in sec */

    /* do the actual url validation */

    for (i = 0; i < url_list_sz; i++) {
        const char *url = url_list[i];
        int ok = 0, fail = 0, httpcode = 0;

        get_validation_table_entry(w->instance_id, i, &ok, &fail, NULL);

        AM_LOG_DEBUG(w->instance_id, "%s validating %s", thisfunc, url);

        if (conf->valid_level == 1) {
            /* simple HEAD request */
            validate_status = am_url_validate(w->instance_id, url, net_options, &httpcode);
        } else {
            /* full scale agent login-logout request */
            char *agent_token = NULL;
            validate_status = am_agent_login(w->instance_id, url, conf->user, conf->pass, conf->realm,
                    net_options, &agent_token, NULL, NULL, NULL);
            if (agent_token != NULL) {
                am_agent_logout(0, url, agent_token, net_options);
                free(agent_token);
                httpcode = 200;
            }
        }

        if (validate_status == AM_SUCCESS && httpcode != 0) {
            if (ok++ > conf->valid_ping_ok) {
                ok = conf->valid_ping_ok;
            }
            fail = 0;
        } else {
            if (fail++ > conf->valid_ping_miss) {
                fail = conf->valid_ping_miss;
            }
            ok = 0;
        }

        set_validation_table_entry(w->instance_id, i, ok, fail);
    }

    /* map stored index value to our ordered list index */
    for (i = 0; i < conf->valid_default_url_sz; i++) {
        if (current_index == conf->valid_default_url[i]) {
            current_index = i;
            break;
        }
    }

    default_ok = current_ok = current_fail = 0;
    /* fetch validation table entry for the current_index 
     * (which now corresponds to the default.url.set value/index) */
    get_validation_table_entry(w->instance_id, current_index, &current_ok, &current_fail, &default_ok);

    /* do the fail-over logic */
    do {
        if (current_ok > 0) {
            if (current_index > 0 && default_ok >= conf->valid_ping_ok) {
                set_valid_url_index(w->instance_id, conf->valid_default_url[0]);
                AM_LOG_INFO(w->instance_id, "%s fail-back to %s", thisfunc, url_list[0]);
            } else {
                set_valid_url_index(w->instance_id, conf->valid_default_url[current_index]);
                AM_LOG_INFO(w->instance_id, "%s continue with %s", thisfunc, url_list[current_index]);
            }
            break;
        }

        /* current index is not valid; check ping.miss.count */
        if (current_ok == 0 && current_fail <= conf->valid_ping_miss) {
            set_valid_url_index(w->instance_id, conf->valid_default_url[current_index]);
            AM_LOG_INFO(w->instance_id, "%s still staying with %s", thisfunc, url_list[current_index]);
            break;
        }

        /* find next valid index value to fail-over to */
        next_ok = 0;
        AM_MUTEX_LOCK(&table_mutex);

        AM_LIST_FOR_EACH(table, e, t) {
            if (e->instance_id == w->instance_id && e->index == 0) {
                default_ok = e->ok;
            }
            if (e->instance_id == w->instance_id && e->ok > 0) {
                next_ok = e->ok;
                i = e->index;
                break;
            }
        }

        AM_MUTEX_UNLOCK(&table_mutex);

        if (next_ok == 0) {
            AM_LOG_WARNING(w->instance_id,
                    "%s none of the values are valid, defaulting to %s", thisfunc, url_list[0]);
            set_valid_url_index(w->instance_id, conf->valid_default_url[0]);
            break;
        }

        if (current_index > 0 && default_ok >= conf->valid_ping_ok) {
            AM_LOG_INFO(w->instance_id, "%s fail-back to %s", thisfunc, url_list[0]);
            set_valid_url_index(w->instance_id, conf->valid_default_url[0]);
            break;
        }

        AM_LOG_INFO(w->instance_id, "%s fail-over to %s", thisfunc, url_list[i]);
        set_valid_url_index(w->instance_id, conf->valid_default_url[i]);

    } while (0);

    am_net_options_delete(net_options);
    free(net_options);
    am_config_free(&conf);
    set_valid_url_instance_running(w->instance_id, AM_FALSE);
    AM_FREE(w->config_path, w);
    URL_LIST_FREE(url_list, url_list_sz);
}