static int amagent_init(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) { /* main process init */ int status; apr_status_t rv = APR_SUCCESS; void *data; #define AMAGENT_INIT_ONCE "AMAGENT_INIT_ONCE" apr_pool_userdata_get(&data, AMAGENT_INIT_ONCE, s->process->pool); if (!data) { /* module has already been initialized */ apr_pool_userdata_set((const void *) 1, AMAGENT_INIT_ONCE, apr_pool_cleanup_null, s->process->pool); return rv; } apr_pool_cleanup_register(pconf, s, amagent_cleanup, apr_pool_cleanup_null); ap_add_version_component(pconf, MODINFO); LOG_S(APLOG_DEBUG, s, "amagent_init() %d", getpid()); #ifndef _WIN32 status = am_init(); if (status != AM_SUCCESS) { rv = APR_EINIT; LOG_S(APLOG_ERR, s, "amagent_init() status: %s", am_strerror(status)); } #endif return rv; }
static am_status_t set_custom_response(am_request_t *rq, const char *text, const char *cont_type) { request_rec *r = (request_rec *) (rq != NULL ? rq->ctx : NULL); if (r == NULL || !ISVALID(text)) return AM_EINVAL; if (rq->status == AM_INTERNAL_REDIRECT) { ap_internal_redirect(text, r); rq->status = AM_DONE; } else if (rq->status == AM_REDIRECT) { apr_table_add(r->headers_out, "Location", text); ap_custom_response(r, HTTP_MOVED_TEMPORARILY, text); } else { if (rq->status == AM_PDP_DONE) { request_rec *sr = ap_sub_req_method_uri(am_method_num_to_str(rq->method), rq->post_data_url, r, NULL); sr->headers_in = r->headers_in; sr->notes = r->notes; am_log_debug(rq->instance_id, "set_custom_response(): issuing sub-request %s to %s", sr->method, rq->post_data_url); ap_run_sub_req(sr); ap_destroy_sub_req(sr); rq->status = AM_DONE; } else { size_t tl = strlen(text); if (ISVALID(cont_type)) { ap_set_content_type(r, cont_type); } ap_set_content_length(r, tl); ap_rwrite(text, (int) tl, r); ap_custom_response(r, am_status_value(rq->status == AM_SUCCESS || rq->status == AM_DONE ? AM_SUCCESS : rq->status), text); ap_rflush(r); } } am_log_info(rq->instance_id, "set_custom_response(): status: %s", am_strerror(rq->status)); return AM_SUCCESS; }
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; }
static int send_policychange_request(am_net_t *conn, char **token, const char *notifyurl) { static const char *thisfunc = "send_policychange_request():"; size_t post_sz, post_data_sz; char *post = NULL, *post_data = NULL; int status = AM_ERROR; struct request_data *req_data; if (conn == NULL || conn->data == NULL || token == NULL || !ISVALID(*token)) return AM_EINVAL; req_data = (struct request_data *) conn->data; post_data_sz = am_asprintf(&post_data, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" "<RequestSet vers=\"1.0\" svcid=\"Policy\" reqid=\"1\">" "<Request><![CDATA[" "<PolicyService version=\"1.0\">" "<PolicyRequest requestId=\"1\" appSSOToken=\"%s\">" "<RemovePolicyListener notificationURL=\"%s\" serviceName=\"iPlanetAMWebAgentService\"/>" "</PolicyRequest>" "</PolicyService>]]>" "</Request>" "<Request><![CDATA[" "<PolicyService version=\"1.0\">" "<PolicyRequest requestId=\"2\" appSSOToken=\"%s\">" "<AddPolicyListener notificationURL=\"%s\" serviceName=\"iPlanetAMWebAgentService\"/>" "</PolicyRequest>" "</PolicyService>]]>" "</Request>" "</RequestSet>", *token, NOTNULL(notifyurl), *token, NOTNULL(notifyurl)); if (post_data == NULL) return AM_ENOMEM; post_sz = am_asprintf(&post, "POST %s/policyservice HTTP/1.1\r\n" "Host: %s:%d\r\n" "User-Agent: "MODINFO"\r\n" "Accept: text/xml\r\n" "Connection: Close\r\n" "Content-Type: text/xml; charset=UTF-8\r\n" "%s" "Content-Length: %d\r\n\r\n" "%s", conn->uv.path, conn->uv.host, conn->uv.port, NOTNULL(conn->req_headers), post_data_sz, post_data); if (post == NULL) { free(post_data); return AM_ENOMEM; } #ifdef DEBUG AM_LOG_DEBUG(conn->instance_id, "%s sending %d bytes:\n%s", thisfunc, post_sz, post); #else AM_LOG_DEBUG(conn->instance_id, "%s sending %d bytes", thisfunc, post_sz); #endif if (conn->log != NULL) { #ifdef DEBUG conn->log("%s sending %d bytes:\n%s", thisfunc, post_sz, post); #else conn->log("%s sending %d bytes", thisfunc, post_sz); #endif } status = am_net_write(conn, post, post_sz); free(post_data); free(post); if (status == AM_SUCCESS) { wait_for_event(req_data->event, 0); } AM_LOG_DEBUG(conn->instance_id, "%s authenticate response status code: %d\n%s", thisfunc, conn->http_status, LOGEMPTY(req_data->data)); if (conn->log != NULL) { conn->log("%s authenticate response status code: %d\n%s", thisfunc, conn->http_status, LOGEMPTY(req_data->data)); } AM_LOG_DEBUG(conn->instance_id, "%s status: %s", thisfunc, am_strerror(status)); am_free(req_data->data); req_data->data = NULL; return status; }
static int send_authcontext_request(am_net_t *conn, const char *realm, char **token) { static const char *thisfunc = "send_authcontext_request():"; size_t post_sz, post_data_sz; char *post = NULL, *post_data = NULL; int status = AM_ERROR; struct request_data *req_data; if (conn == NULL || conn->data == NULL || token == NULL || !ISVALID(realm)) return AM_EINVAL; req_data = (struct request_data *) conn->data; post_data_sz = am_asprintf(&post_data, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" "<RequestSet vers=\"1.0\" svcid=\"auth\" reqid=\"0\">" "<Request><![CDATA[" "<?xml version=\"1.0\" encoding=\"UTF-8\"?><AuthContext version=\"1.0\">" "<Request authIdentifier=\"0\">" "<NewAuthContext orgName=\"%s\"/></Request></AuthContext>]]>" "</Request></RequestSet>", realm); if (post_data == NULL) return AM_ENOMEM; post_sz = am_asprintf(&post, "POST %s/authservice HTTP/1.1\r\n" "Host: %s:%d\r\n" "User-Agent: "MODINFO"\r\n" "Accept: text/xml\r\n" "Connection: Keep-Alive\r\n" "Content-Type: text/xml; charset=UTF-8\r\n" "Content-Length: %d\r\n\r\n" "%s", conn->uv.path, conn->uv.host, conn->uv.port, post_data_sz, post_data); if (post == NULL) { free(post_data); return AM_ENOMEM; } #ifdef DEBUG AM_LOG_DEBUG(conn->instance_id, "%s sending %d bytes:\n%s", thisfunc, post_sz, post); #else AM_LOG_DEBUG(conn->instance_id, "%s sending %d bytes", thisfunc, post_sz); #endif if (conn->log != NULL) { #ifdef DEBUG conn->log("%s sending %d bytes:\n%s", thisfunc, post_sz, post); #else conn->log("%s sending %d bytes", thisfunc, post_sz); #endif } status = am_net_write(conn, post, post_sz); free(post_data); free(post); if (status == AM_SUCCESS) { wait_for_event(req_data->event, 0); } AM_LOG_DEBUG(conn->instance_id, "%s response status code: %d\n%s", thisfunc, conn->http_status, LOGEMPTY(req_data->data)); if (conn->log != NULL) { conn->log("%s response status code: %d\n%s", thisfunc, conn->http_status, LOGEMPTY(req_data->data)); } if (status == AM_SUCCESS && conn->http_status == 200 && ISVALID(req_data->data)) { char *begin = strstr(req_data->data, "Response authIdentifier=\""); if (begin != NULL) { char *end = strstr(begin + 25, "\""); if (end != NULL) { *token = strndup(begin + 25, end - begin - 25); } } if (ISINVALID(*token)) { status = AM_NOT_FOUND; } if (status == AM_SUCCESS && ISVALID(conn->req_headers)) { am_request_t req_temp; int decode_status; memset(&req_temp, 0, sizeof(am_request_t)); req_temp.token = strdup(*token); decode_status = am_session_decode(&req_temp); if (decode_status == AM_SUCCESS && req_temp.session_info.error == AM_SUCCESS) { if (ISVALID(req_temp.session_info.si)) { am_asprintf(&conn->req_headers, "%s%s\r\n", conn->req_headers, req_temp.session_info.si); } else { am_free(conn->req_headers); conn->req_headers = NULL; } AM_LOG_DEBUG(conn->instance_id, "%s app token SI: %s, S1: %s", thisfunc, LOGEMPTY(req_temp.session_info.si), LOGEMPTY(req_temp.session_info.s1)); } am_request_free(&req_temp); } } AM_LOG_DEBUG(conn->instance_id, "%s status: %s", thisfunc, am_strerror(status)); am_free(req_data->data); req_data->data = NULL; return status; }
static int send_session_request(am_net_t *conn, char **token, const char *notifyurl, struct am_namevalue **session_list) { static const char *thisfunc = "send_session_request():"; size_t post_sz, post_data_sz, token_sz; char *post = NULL, *post_data = NULL, *token_in = NULL, *token_b64; int status = AM_ERROR; struct request_data *req_data; if (conn == NULL || conn->data == NULL || token == NULL || !ISVALID(*token)) return AM_EINVAL; token_sz = am_asprintf(&token_in, "token:%s", *token); token_b64 = base64_encode(token_in, &token_sz); req_data = (struct request_data *) conn->data; post_data_sz = am_asprintf(&post_data, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" "<RequestSet vers=\"1.0\" svcid=\"Session\" reqid=\"0\">" "<Request><![CDATA[" "<SessionRequest vers=\"1.0\" reqid=\"1\" requester=\"%s\">" "<GetSession reset=\"true\">" "<SessionID>%s</SessionID>" "</GetSession>" "</SessionRequest>]]>" "</Request>" "<Request><![CDATA[" "<SessionRequest vers=\"1.0\" reqid=\"2\" requester=\"%s\">" "<AddSessionListener>" "<URL>%s</URL>" "<SessionID>%s</SessionID>" "</AddSessionListener>" "</SessionRequest>]]>" "</Request>" "</RequestSet>", NOTNULL(token_b64), *token, NOTNULL(token_b64), notifyurl, *token); if (post_data == NULL) { AM_FREE(token_b64, token_in); return AM_ENOMEM; } post_sz = am_asprintf(&post, "POST %s/sessionservice HTTP/1.1\r\n" "Host: %s:%d\r\n" "User-Agent: "MODINFO"\r\n" "Accept: text/xml\r\n" "Connection: Keep-Alive\r\n" "Content-Type: text/xml; charset=UTF-8\r\n" "%s" "Content-Length: %d\r\n\r\n" "%s", conn->uv.path, conn->uv.host, conn->uv.port, NOTNULL(conn->req_headers), post_data_sz, post_data); if (post == NULL) { AM_FREE(post_data, token_b64, token_in); return AM_ENOMEM; } #ifdef DEBUG AM_LOG_DEBUG(conn->instance_id, "%s sending %d bytes:\n%s", thisfunc, post_sz, post); #else AM_LOG_DEBUG(conn->instance_id, "%s sending %d bytes", thisfunc, post_sz); #endif if (conn->log != NULL) { #ifdef DEBUG conn->log("%s sending %d bytes:\n%s", thisfunc, post_sz, post); #else conn->log("%s sending %d bytes", thisfunc, post_sz); #endif } status = am_net_write(conn, post, post_sz); AM_FREE(post, post_data, token_b64, token_in); if (status == AM_SUCCESS) { wait_for_event(req_data->event, 0); } AM_LOG_DEBUG(conn->instance_id, "%s response status code: %d\n%s", thisfunc, conn->http_status, LOGEMPTY(req_data->data)); if (conn->log != NULL) { conn->log("%s response status code: %d\n%s", thisfunc, conn->http_status, LOGEMPTY(req_data->data)); } if (status == AM_SUCCESS && conn->http_status == 200 && ISVALID(req_data->data)) { if (session_list != NULL) { *session_list = am_parse_session_xml(conn->instance_id, req_data->data, req_data->data_size); } } AM_LOG_DEBUG(conn->instance_id, "%s status: %s", thisfunc, am_strerror(status)); am_free(req_data->data); req_data->data = NULL; return status; }
static int send_attribute_request(am_net_t *conn, char **token, char **pxml, size_t *pxsz, const char *user, const char *realm) { static const char *thisfunc = "send_attribute_request():"; size_t post_sz; char *post = NULL; int status = AM_ERROR; struct request_data *req_data; char *token_enc; char *realm_enc = url_encode(realm); char *user_enc = url_encode(user); if (conn == NULL || conn->data == NULL || token == NULL || !ISVALID(*token) || !ISVALID(realm) || !ISVALID(user)) return AM_EINVAL; token_enc = url_encode(*token); req_data = (struct request_data *) conn->data; post_sz = am_asprintf(&post, "GET %s/identity/xml/read?" "name=%s&attributes_names=realm&attributes_values_realm=%s&attributes_names=objecttype" "&attributes_values_objecttype=Agent&admin=%s HTTP/1.1\r\n" "Host: %s:%d\r\n" "User-Agent: "MODINFO"\r\n" "Accept: text/xml\r\n" "%s" "Connection: Keep-Alive\r\n\r\n", conn->uv.path, user_enc, realm_enc, token_enc, conn->uv.host, conn->uv.port, NOTNULL(conn->req_headers)); if (post == NULL) { AM_FREE(realm_enc, user_enc, token_enc); return AM_ENOMEM; } #ifdef DEBUG AM_LOG_DEBUG(conn->instance_id, "%s sending %d bytes:\n%s", thisfunc, post_sz, post); #else AM_LOG_DEBUG(conn->instance_id, "%s sending %d bytes", thisfunc, post_sz); #endif if (conn->log != NULL) { #ifdef DEBUG conn->log("%s sending %d bytes:\n%s", thisfunc, post_sz, post); #else conn->log("%s sending %d bytes", thisfunc, post_sz); #endif } status = am_net_write(conn, post, post_sz); free(post); if (status == AM_SUCCESS) { wait_for_event(req_data->event, 0); } AM_LOG_DEBUG(conn->instance_id, "%s response status code: %d\n%s", thisfunc, conn->http_status, LOGEMPTY(req_data->data)); if (conn->log != NULL) { conn->log("%s response status code: %d\n%s", thisfunc, conn->http_status, LOGEMPTY(req_data->data)); } if (status == AM_SUCCESS && conn->http_status == 200 && ISVALID(req_data->data)) { if (stristr(req_data->data, "exception") != NULL) { status = AM_ERROR; } else { if (pxml != NULL) { *pxml = malloc(req_data->data_size + 1); if (*pxml != NULL) { memcpy(*pxml, req_data->data, req_data->data_size); (*pxml)[req_data->data_size] = 0; } else { status = AM_ENOMEM; } } if (pxsz != NULL) *pxsz = req_data->data_size; } } AM_LOG_DEBUG(conn->instance_id, "%s status: %s", thisfunc, am_strerror(status)); AM_FREE(req_data->data, realm_enc, user_enc, token_enc); req_data->data = NULL; return status; }
static int send_login_request(am_net_t *conn, char **token, const char *user, const char *password) { static const char *thisfunc = "send_login_request():"; size_t post_sz, post_data_sz, xml_esc_sz; char *post = NULL, *post_data = NULL; int status = AM_ERROR; struct request_data *req_data; char *user_xml_esc = NULL, *pass_xml_esc = NULL; if (conn == NULL || conn->data == NULL || token == NULL || !ISVALID(*token) || !ISVALID(user)) return AM_EINVAL; /* do xml-escape */ xml_esc_sz = strlen(user); user_xml_esc = malloc(xml_esc_sz * 6 + 1); /* worst case */ if (user_xml_esc != NULL) { memcpy(user_xml_esc, user, xml_esc_sz); xml_entity_escape(user_xml_esc, xml_esc_sz); } else { return AM_ENOMEM; } if (ISVALID(password)) { xml_esc_sz = strlen(password); pass_xml_esc = malloc(xml_esc_sz * 6 + 1); /* worst case */ if (pass_xml_esc != NULL) { memcpy(pass_xml_esc, password, xml_esc_sz); xml_entity_escape(pass_xml_esc, xml_esc_sz); } else { free(user_xml_esc); return AM_ENOMEM; } } req_data = (struct request_data *) conn->data; post_data_sz = am_asprintf(&post_data, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" "<RequestSet vers=\"1.0\" svcid=\"auth\" reqid=\"0\">" "<Request><![CDATA[" "<?xml version=\"1.0\" encoding=\"UTF-8\"?><AuthContext version=\"1.0\">" "<Request authIdentifier=\"%s\"><Login>" "<IndexTypeNamePair indexType=\"moduleInstance\"><IndexName>Application</IndexName>" "</IndexTypeNamePair></Login></Request></AuthContext>]]>" "</Request>" "<Request><![CDATA[" "<?xml version=\"1.0\" encoding=\"UTF-8\"?><AuthContext version=\"1.0\">" "<Request authIdentifier=\"%s\"><SubmitRequirements>" "<Callbacks length=\"2\"><NameCallback><Prompt>Enter application name.</Prompt>" "<Value>%s</Value>" "</NameCallback><PasswordCallback echoPassword=\"true\"><Prompt>Enter secret string.</Prompt>" "<Value>%s</Value>" "</PasswordCallback></Callbacks>" "</SubmitRequirements></Request></AuthContext>]]>" "</Request>" "</RequestSet>", *token, *token, user_xml_esc, NOTNULL(pass_xml_esc)); AM_FREE(user_xml_esc, pass_xml_esc); if (post_data == NULL) { return AM_ENOMEM; } post_sz = am_asprintf(&post, "POST %s/authservice HTTP/1.1\r\n" "Host: %s:%d\r\n" "User-Agent: "MODINFO"\r\n" "Accept: text/xml\r\n" "Connection: Keep-Alive\r\n" "Content-Type: text/xml; charset=UTF-8\r\n" "%s" "Content-Length: %d\r\n\r\n" "%s", conn->uv.path, conn->uv.host, conn->uv.port, NOTNULL(conn->req_headers), post_data_sz, post_data); if (post == NULL) { free(post_data); return AM_ENOMEM; } #ifdef DEBUG AM_LOG_DEBUG(conn->instance_id, "%s sending %d bytes:\n%s", thisfunc, post_sz, post); #else AM_LOG_DEBUG(conn->instance_id, "%s sending %d bytes", thisfunc, post_sz); #endif if (conn->log != NULL) { #ifdef DEBUG conn->log("%s sending %d bytes:\n%s", thisfunc, post_sz, post); #else conn->log("%s sending %d bytes", thisfunc, post_sz); #endif } status = am_net_write(conn, post, post_sz); free(post_data); free(post); free(*token); /* delete pre-login/authcontext token */ *token = NULL; if (status == AM_SUCCESS) { wait_for_event(req_data->event, 0); } AM_LOG_DEBUG(conn->instance_id, "%s authenticate response status code: %d\n%s", thisfunc, conn->http_status, LOGEMPTY(req_data->data)); if (conn->log != NULL) { conn->log("%s authenticate response status code: %d\n%s", thisfunc, conn->http_status, LOGEMPTY(req_data->data)); } status = AM_ERROR; if (ISVALID(req_data->data)) { char *begin = strstr(req_data->data, "LoginStatus status=\"success\" ssoToken=\""); if (begin != NULL) { char *end = strstr(begin + 39, "\""); if (end != NULL) { *token = strndup(begin + 39, end - begin - 39); if (ISVALID(*token)) status = AM_SUCCESS; } } } AM_LOG_DEBUG(conn->instance_id, "%s status: %s", thisfunc, am_strerror(status)); am_free(req_data->data); req_data->data = NULL; return status; }
static void *net_async_connect(void *arg) { am_net_t *n = (am_net_t *) arg; static const char *thisfunc = "net_async_connect():"; struct in6_addr serveraddr; struct addrinfo *rp, hints; int err = 0, on = 1; char port[7]; am_timer_t tmr; memset(&hints, 0, sizeof (struct addrinfo)); hints.ai_flags = AI_NUMERICSERV; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; err = INETPTON(AF_INET, n->uv.host, &serveraddr); if (err == 1) { hints.ai_family = AF_INET; hints.ai_flags |= AI_NUMERICHOST; } else { err = INETPTON(AF_INET6, n->uv.host, &serveraddr); if (err == 1) { hints.ai_family = AF_INET6; hints.ai_flags |= AI_NUMERICHOST; } } snprintf(port, sizeof (port), "%d", n->uv.port); am_timer_start(&tmr); if ((err = getaddrinfo(n->uv.host, port, &hints, &n->ra)) != 0) { n->error = AM_EHOSTUNREACH; am_timer_stop(&tmr); am_timer_report(n->instance_id, &tmr, "getaddrinfo"); set_event(n->ce); return NULL; } am_timer_stop(&tmr); am_timer_report(n->instance_id, &tmr, "getaddrinfo"); n->error = 0; for (rp = n->ra; rp != NULL; rp = rp->ai_next) { if (rp->ai_family != AF_INET && rp->ai_family != AF_INET6 && rp->ai_socktype != SOCK_STREAM && rp->ai_protocol != IPPROTO_TCP) continue; if ((n->sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) == INVALID_SOCKET) { AM_LOG_ERROR(n->instance_id, "%s: cannot create socket while connecting to %s:%d", thisfunc, n->uv.host, n->uv.port); net_log_error(n->instance_id, net_error()); continue; } if (setsockopt(n->sock, IPPROTO_TCP, TCP_NODELAY, (void *) &on, sizeof (on)) < 0) { net_log_error(n->instance_id, net_error()); } if (setsockopt(n->sock, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof (on)) < 0) { net_log_error(n->instance_id, net_error()); } #ifdef SO_NOSIGPIPE if (setsockopt(n->sock, SOL_SOCKET, SO_NOSIGPIPE, (void *) &on, sizeof (on)) < 0) { net_log_error(n->instance_id, net_error()); } #endif if (set_nonblocking(n, 1) != 0) { n->error = AM_EPERM; continue; } err = connect(n->sock, rp->ai_addr, (SOCKLEN_T) rp->ai_addrlen); if (err == 0) { AM_LOG_DEBUG(n->instance_id, "%s: connected to %s:%d (%s)", thisfunc, n->uv.host, n->uv.port, rp->ai_family == AF_INET ? "IPv4" : "IPv6"); n->error = 0; if (n->uv.ssl) { net_connect_ssl(n); if (n->ssl.error != AM_SUCCESS) { AM_LOG_ERROR(n->instance_id, "%s: SSL/TLS connection to %s:%d (%s) failed (%s)", thisfunc, n->uv.host, n->uv.port, rp->ai_family == AF_INET ? "IPv4" : "IPv6", am_strerror(n->ssl.error)); net_close_socket(n->sock); n->sock = INVALID_SOCKET; n->error = n->ssl.error; break; } } net_async_poll(n); break; } if (err == INVALID_SOCKET && net_in_progress(net_error())) { #ifdef _WIN32 WSAPOLLFD fds[1]; #else struct pollfd fds[1]; #endif memset(fds, 0, sizeof (fds)); fds[0].fd = n->sock; fds[0].events = connect_ev; fds[0].revents = 0; err = sockpoll(fds, 1, n->timeout > 0 ? n->timeout * 1000 : -1); if (err > 0 && fds[0].revents & connected_ev) { int pe = 0; SOCKLEN_T pe_sz = sizeof (pe); err = getsockopt(n->sock, SOL_SOCKET, SO_ERROR, (char *) &pe, &pe_sz); if (err == 0 && pe == 0) { AM_LOG_DEBUG(n->instance_id, "%s: connected to %s:%d (%s)", thisfunc, n->uv.host, n->uv.port, rp->ai_family == AF_INET ? "IPv4" : "IPv6"); n->error = 0; if (n->uv.ssl) { net_connect_ssl(n); if (n->ssl.error != AM_SUCCESS) { AM_LOG_ERROR(n->instance_id, "%s: SSL/TLS connection to %s:%d (%s) failed (%s)", thisfunc, n->uv.host, n->uv.port, rp->ai_family == AF_INET ? "IPv4" : "IPv6", am_strerror(n->ssl.error)); net_close_socket(n->sock); n->sock = INVALID_SOCKET; n->error = n->ssl.error; break; } } net_async_poll(n); break; } net_log_error(n->instance_id, pe); n->error = AM_ECONNREFUSED; } else if (err == 0) { AM_LOG_WARNING(n->instance_id, "%s: timeout connecting to %s:%d (%s)", thisfunc, n->uv.host, n->uv.port, rp->ai_family == AF_INET ? "IPv4" : "IPv6"); n->error = AM_ETIMEDOUT; } else { int pe = 0; SOCKLEN_T pe_sz = sizeof (pe); err = getsockopt(n->sock, SOL_SOCKET, SO_ERROR, (char *) &pe, &pe_sz); n->error = AM_ETIMEDOUT; break; } } net_close_socket(n->sock); n->sock = INVALID_SOCKET; } if (n->error != 0) { set_event(n->ce); } return NULL; }
am_config_t *am_parse_config_xml(unsigned long instance_id, const char *xml, size_t xml_sz, char log_enable) { static 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 = {.setting_value = 0, .conf = NULL, .rgx = NULL, .parser = NULL, .log_enable = log_enable, .data_sz = 0, .data = NULL, .status = AM_SUCCESS}; 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)); XML_Size line = XML_GetCurrentLineNumber(parser); XML_Size col = XML_GetCurrentColumnNumber(parser); AM_LOG_ERROR(instance_id, "%s xml parser error (%lu:%lu) %s", thisfunc, (unsigned long) line, (unsigned long) col, message); am_config_free(&r); r = NULL; } else { r->ts = time(NULL); } XML_ParserFree(parser); } if (xctx.status != AM_SUCCESS) { AM_LOG_ERROR(instance_id, "%s %s", thisfunc, am_strerror(xctx.status)); } pcre_free(x); decrypt_agent_passwords(r); update_agent_configuration_ttl(r); return r; }