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; }
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; }
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, ¤t_ok, ¤t_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); }