/** * Ensure that at warning log level we do NOT log something via AM_LOG_DEBUG. */ void test_log_debug_not_at_warning_level(void** state) { int result; const char* message = "Message written at DEBUG level."; logging_setup(AM_LOG_LEVEL_WARNING); AM_LOG_DEBUG(getpid(), message); sleep(5); result = validate_contains(log_file_name, message); logging_teardown(); assert_int_equal(result, 0); }
/** * Ensure that an impractically high log level we DO actually log text via AM_LOG_DEBUG. */ void test_log_debug_at_debug_level(void** state) { int result; const char* message = "Message written at DEBUG level."; srand(time(NULL)); logging_setup(AM_LOG_LEVEL_AUDIT_DENY); AM_LOG_DEBUG(getpid(), message); sleep(5); result = validate_contains(log_file_name, message); logging_teardown(); assert_int_equal(result, 1); }
/** * This is the simplest of tests to check we can log things without crashing. * * In fact, because of the way logging works (differently) in test mode than it does in "agent mode" * all we're really doing here is to test that logging in test mode isn't broken. This may or may not * bear any relation to whether logging works for the rest of the time. */ void test_logging_in_unit_test_mode(void** state) { static const char* text1 = "Now is the winter of our discontent,"; static const char* text2 = "Made glorious summer by this son of York"; AM_LOG_INFO(0, "instance id is zero and no args"); AM_LOG_INFO(0, "instance id is zero and incorrect args", text1); AM_LOG_INFO(0, "instance id is zero and more incorrect args", text1, text2); /* we're testing this will not crash */ AM_LOG_INFO(0, NULL, text1, text2); /* this will not appear, since the instance is greater than zero, but it should not crash either */ AM_LOG_ERROR(10, "%s %s", text1, text2); AM_LOG_INFO(0, "%s %s", text1, text2); AM_LOG_WARNING(0, "%s %s", text1, text2); AM_LOG_ERROR(0, "%s %s", text1, text2); AM_LOG_DEBUG(0, "%s %s", text1, text2); AM_LOG_AUDIT(0, "%s %s", text1, text2); AM_LOG_ALWAYS(0, "%s %s", text1, text2); AM_LOG_ALWAYS(0, "Now %s the %s of our %s, %s summ%s of York", "is", "winter", "discontent", "Made glorious", "er by this son"); /* attempt to overflow the buffer, although this will be ultimately unsuccessful because the * logging works differently in unit test mode than it does in "real life" mode. */ AM_LOG_ALWAYS(0, "\n" "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\n" "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\n" "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\n" "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\n" "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\n" "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\n" "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\n" "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\n" "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\n" "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890\n" "ABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJ"); }
static void parse_config_value(unsigned long instance_id, const char *line, const char *prm, int type, int *itm_sz, void *itm, const char *sep) { if (itm == NULL || compare_property(line, prm) != AM_SUCCESS) { return; } switch (type) { case CONF_STRING: { char **value = (char **) itm; *value = (char *) parse_value(line, prm, type, NULL); if (strstr(prm, "password") != NULL) { AM_LOG_DEBUG(instance_id, "am_get_config_file() %s is set to '%s'", prm, *value == NULL ? "NULL" : "********"); break; } AM_LOG_DEBUG(instance_id, "am_get_config_file() %s is set to '%s'", prm, *value == NULL ? "NULL" : *value); } break; case CONF_NUMBER: case CONF_DEBUG_LEVEL: case CONF_ATTR_MODE: case CONF_AUDIT_LEVEL: { int *value = (int *) itm; int *value_tmp = (int *) parse_value(line, prm, type, NULL); if (value_tmp != NULL) { *value = *value_tmp; free(value_tmp); } AM_LOG_DEBUG(instance_id, "am_get_config_file() %s is set to '%d'", prm, *value); } break; case CONF_STRING_LIST: { char ***value = (char ***) itm; struct val_string_list *value_tmp = (struct val_string_list *) parse_value(line, prm, type, sep); if (value_tmp != NULL) { *value = value_tmp->list; *itm_sz = value_tmp->size; free(value_tmp); } AM_LOG_DEBUG(instance_id, "am_get_config_file() %s is set to %d value(s)", prm, *itm_sz); } break; case CONF_NUMBER_LIST: { int **value = (int **) itm; struct val_number_list *value_tmp = (struct val_number_list *) parse_value(line, prm, type, sep); if (value_tmp != NULL) { *value = value_tmp->list; *itm_sz = value_tmp->size; free(value_tmp); } AM_LOG_DEBUG(instance_id, "am_get_config_file() %s is set to %d value(s)", prm, *itm_sz); } break; case CONF_STRING_MAP: { int old_sz = *itm_sz; am_config_map_t **value = (am_config_map_t **) itm; char *value_tmp = (char *) parse_value(line, prm, CONF_STRING, NULL); if (value_tmp == NULL) { break; } *value = (am_config_map_t *) realloc(*value, sizeof (am_config_map_t) *(++(*itm_sz))); if (*value == NULL) { if (--(*itm_sz) < 0) { *itm_sz = 0; } free(value_tmp); break; } (&(*value)[old_sz])->name = value_tmp; (&(*value)[old_sz])->value = value_tmp + strlen(value_tmp) + 1; AM_LOG_DEBUG(instance_id, "am_get_config_file() %s is set to %d value(s)", prm, *itm_sz); } break; default: AM_LOG_WARNING(instance_id, "am_get_config_file() unknown type value %d setting %s", type, prm); break; } }
int am_agent_policy_request(unsigned long instance_id, const char *openam, const char *token, const char *user_token, const char *req_url, const char *notif_url, const char *scope, const char *cip, const char *pattr, const char *server_id, struct am_ssl_options *info, struct am_namevalue **session_list, struct am_policy_result **policy_list) { static const char *thisfunc = "am_agent_policy_request():"; char *post = NULL, *post_data = NULL; am_net_t n; size_t post_sz; int status = AM_ERROR; int session_status = AM_SUCCESS; struct request_data req_data; if (!ISVALID(token) || !ISVALID(user_token) || !ISVALID(notif_url) || !ISVALID(scope) || !ISVALID(req_url) || !ISVALID(openam) || !ISVALID(cip)) { return AM_EINVAL; } memset(&req_data, 0, sizeof(struct request_data)); memset(&n, 0, sizeof(am_net_t)); n.instance_id = instance_id; n.timeout = AM_NET_CONNECT_TIMEOUT; n.url = openam; if (info != NULL) { memcpy(&n.ssl.info, info, sizeof(struct am_ssl_options)); } if (ISVALID(server_id)) { am_asprintf(&n.req_headers, "Cookie: amlbcookie=%s\r\n", server_id); } req_data.event = create_event(); if (req_data.event == NULL) { return AM_ENOMEM; } n.data = &req_data; n.on_connected = on_connected_cb; n.on_close = on_close_cb; n.on_data = on_agent_request_data_cb; n.on_complete = on_complete_cb; if (am_net_connect(&n) == 0) { char *token_in = NULL; size_t token_sz = am_asprintf(&token_in, "token:%s", token); char *token_b64 = base64_encode(token_in, &token_sz); size_t 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\">" /* reset the idle timeout */ "<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), user_token, NOTNULL(token_b64), notif_url, user_token); AM_FREE(token_in, token_b64); if (post_data != NULL) { 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", n.uv.path, n.uv.host, n.uv.port, NOTNULL(n.req_headers), post_data_sz, post_data); if (post != NULL) { AM_LOG_DEBUG(instance_id, "%s sending request:\n%s", thisfunc, post); status = am_net_write(&n, post, post_sz); free(post); post = NULL; } free(post_data); post_data = NULL; } if (status == AM_SUCCESS) { wait_for_event(req_data.event, 0); } AM_LOG_DEBUG(instance_id, "%s response status code: %d", thisfunc, n.http_status); if (status == AM_SUCCESS && n.http_status == 200 && ISVALID(req_data.data)) { size_t req_url_sz = strlen(req_url); char *req_url_escaped = malloc(req_url_sz * 6 + 1); /* worst case */ if (req_url_escaped != NULL) { memcpy(req_url_escaped, req_url, req_url_sz); xml_entity_escape(req_url_escaped, req_url_sz); } AM_LOG_DEBUG(instance_id, "%s response:\n%s", thisfunc, req_data.data); if (strstr(req_data.data, "<Exception>") != NULL && strstr(req_data.data, "Invalid session ID") != NULL) { session_status = AM_INVALID_SESSION; } if (strstr(req_data.data, "<Exception>") != NULL && strstr(req_data.data, "Application token passed in") != NULL) { session_status = AM_INVALID_AGENT_SESSION; } if (session_status == AM_SUCCESS && session_list != NULL) { *session_list = am_parse_session_xml(instance_id, req_data.data, req_data.data_size); } req_data.data_size = 0; free(req_data.data); req_data.data = NULL; /* TODO: * <AttributeValuePair><Attribute name=\"requestDnsName\"/><Value>%s</Value></AttributeValuePair> */ post_data_sz = am_asprintf(&post_data, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" "<RequestSet vers=\"1.0\" svcid=\"Policy\" reqid=\"3\">" "<Request><![CDATA[<PolicyService version=\"1.0\">" "<PolicyRequest requestId=\"4\" appSSOToken=\"%s\">" "<GetResourceResults userSSOToken=\"%s\" serviceName=\"iPlanetAMWebAgentService\" resourceName=\"%s\" resourceScope=\"%s\">" "<EnvParameters><AttributeValuePair><Attribute name=\"requestIp\"/><Value>%s</Value></AttributeValuePair></EnvParameters>" "<GetResponseDecisions>" "%s" "</GetResponseDecisions>" "</GetResourceResults>" "</PolicyRequest>" "</PolicyService>]]>" "</Request>" "</RequestSet>", token, user_token, NOTNULL(req_url_escaped), scope, cip, NOTNULL(pattr)); am_free(req_url_escaped); 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" "Content-Type: text/xml; charset=UTF-8\r\n" "Content-Length: %d\r\n" "%s" "Connection: close\r\n\r\n" "%s", n.uv.path, n.uv.host, n.uv.port, post_data_sz, NOTNULL(n.req_headers), post_data); if (post != NULL) { AM_LOG_DEBUG(instance_id, "%s sending request:\n%s", thisfunc, post); status = am_net_write(&n, post, post_sz); free(post); } } else { status = n.error != AM_SUCCESS ? n.error : AM_ERROR; } } if (status == AM_SUCCESS) { wait_for_event(req_data.event, 0); } else { AM_LOG_DEBUG(instance_id, "%s disconnecting", thisfunc); am_net_diconnect(&n); } AM_LOG_DEBUG(instance_id, "%s response status code: %d", thisfunc, n.http_status); if (status == AM_SUCCESS && n.http_status == 200 && ISVALID(req_data.data)) { AM_LOG_DEBUG(instance_id, "%s response:\n%s", thisfunc, req_data.data); if (strstr(req_data.data, "<Exception>") != NULL) { if (strstr(req_data.data, "SSO token is invalid") != NULL) { session_status = AM_INVALID_SESSION; } else if (strstr(req_data.data, "Application sso token is invalid") != NULL) { session_status = AM_INVALID_AGENT_SESSION; } } if (session_status == AM_SUCCESS && policy_list != NULL) { *policy_list = am_parse_policy_xml(instance_id, req_data.data, req_data.data_size, am_scope_to_num(scope)); } } am_net_close(&n); close_event(req_data.event); am_free(req_data.data); return session_status != AM_SUCCESS ? session_status : 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; }
int am_agent_logout(unsigned long instance_id, const char *openam, const char *token, const char *server_id, struct am_ssl_options *info, void(*log)(const char *, ...)) { static const char *thisfunc = "am_agent_logout():"; am_net_t conn; int status = AM_ERROR; size_t post_sz, post_data_sz; char *post = NULL, *post_data = NULL; struct request_data req_data; if (!ISVALID(token) || !ISVALID(openam)) return AM_EINVAL; memset(&req_data, 0, sizeof(struct request_data)); memset(&conn, 0, sizeof(am_net_t)); conn.log = log; conn.instance_id = instance_id; conn.timeout = AM_NET_CONNECT_TIMEOUT; conn.url = openam; if (info != NULL) { memcpy(&conn.ssl.info, info, sizeof(struct am_ssl_options)); } if (ISVALID(server_id)) { am_asprintf(&conn.req_headers, "Cookie: amlbcookie=%s\r\n", server_id); } req_data.event = create_event(); if (req_data.event == NULL) return AM_ENOMEM; conn.data = &req_data; conn.on_connected = on_connected_cb; conn.on_close = on_close_cb; conn.on_data = on_agent_request_data_cb; conn.on_complete = on_complete_cb; if (am_net_connect(&conn) == 0) { 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\">" "<Logout/></Request></AuthContext>]]>" "</Request></RequestSet>", token); if (post_data != NULL) { 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: 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) { AM_LOG_DEBUG(instance_id, "%s sending request:\n%s", thisfunc, post); if (log != NULL) { log("%s sending request:\n%s", thisfunc, post); } status = am_net_write(&conn, post, post_sz); free(post); } free(post_data); } } if (status == AM_SUCCESS) { wait_for_event(req_data.event, 0); } else { AM_LOG_DEBUG(instance_id, "%s disconnecting", thisfunc); if (log != NULL) { log("%s disconnecting", thisfunc); } am_net_diconnect(&conn); } AM_LOG_DEBUG(instance_id, "%s response status code: %d", thisfunc, conn.http_status); if (log != NULL) { log("%s response status code: %d", thisfunc, conn.http_status); } am_net_close(&conn); close_event(req_data.event); am_free(req_data.data); return status; }
int am_agent_login(unsigned long instance_id, const char *openam, const char *notifyurl, const char *user, const char *pass, const char *realm, int is_local, int lb_enable, struct am_ssl_options *info, char **agent_token, char **pxml, size_t *pxsz, struct am_namevalue **session_list, void(*log)(const char *, ...)) { static const char *thisfunc = "am_agent_login():"; am_net_t conn; int status = AM_ERROR; struct request_data req_data; if (!ISVALID(realm) || !ISVALID(user) || !ISVALID(pass) || !ISVALID(openam)) { return AM_EINVAL; } memset(&req_data, 0, sizeof(struct request_data)); memset(&conn, 0, sizeof(am_net_t)); conn.log = log; conn.instance_id = instance_id; conn.timeout = AM_NET_CONNECT_TIMEOUT; conn.url = openam; if (info != NULL) { memcpy(&conn.ssl.info, info, sizeof(struct am_ssl_options)); } if (lb_enable) { conn.req_headers = strdup("Cookie: amlbcookie="); } req_data.event = create_event(); if (req_data.event == NULL) return AM_ENOMEM; conn.data = &req_data; conn.on_connected = on_connected_cb; conn.on_close = on_close_cb; conn.on_data = on_agent_request_data_cb; conn.on_complete = on_complete_cb; if (am_net_connect(&conn) == 0) { do { /* authenticate with agent profile/password and module Application (PLL endpoint) */ status = send_authcontext_request(&conn, realm, agent_token); if (status != AM_SUCCESS) break; status = send_login_request(&conn, agent_token, user, pass); if (status != AM_SUCCESS) break; if (!is_local) { /* send agent attribute request (/identity/xml/read REST endpoint); * no interest in a remote profile in case of a local-only configuration */ status = send_attribute_request(&conn, agent_token, pxml, pxsz, user, realm); if (status != AM_SUCCESS) break; } /* send session request (PLL endpoint) */ status = send_session_request(&conn, agent_token, notifyurl, session_list); if (status != AM_SUCCESS) break; /* subscribe to a policy change notification (PLL endpoint) */ status = send_policychange_request(&conn, agent_token, notifyurl); } while (0); if (status != AM_SUCCESS) { AM_LOG_DEBUG(instance_id, "%s disconnecting", thisfunc); if (log != NULL) { log("%s disconnecting", thisfunc); } am_net_diconnect(&conn); } } am_net_close(&conn); close_event(req_data.event); am_free(req_data.data); return status; }
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_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; }
/** * Validate the specified URL by using HTTP HEAD request. */ int am_url_validate(unsigned long instance_id, const char* url, struct am_ssl_options* info, int* httpcode, void(*log)(const char *, ...)) { static const char* thisfunc = "am_url_validate():"; char* get = NULL; am_net_t conn; size_t get_sz; int status = AM_ERROR; struct request_data request_data; AM_LOG_DEBUG(instance_id, "%s%s", thisfunc, LOGEMPTY(url)); if (!ISVALID(url)) { return AM_EINVAL; } memset(&request_data, 0, sizeof(struct request_data)); memset(&conn, 0, sizeof(am_net_t)); conn.log = log; conn.instance_id = instance_id; conn.timeout = AM_NET_CONNECT_TIMEOUT; conn.url = url; if (info != NULL) { memcpy(&conn.ssl.info, info, sizeof(struct am_ssl_options)); } request_data.event = create_event(); if (request_data.event == NULL) { return AM_ENOMEM; } conn.data = &request_data; conn.on_connected = on_connected_cb; conn.on_close = on_close_cb; conn.on_data = on_agent_request_data_cb; conn.on_complete = on_complete_cb; if (am_net_connect(&conn) == 0) { AM_LOG_DEBUG(instance_id, "am_net_connect(%s) returns zero", url); if (log != NULL) { log("am_net_connect(%s) returns zero", url); } get_sz = am_asprintf(&get, "HEAD %s HTTP/1.1\r\n" "Host: %s:%d\r\n" "User-Agent: "MODINFO"\r\n" "Accept: text/plain\r\n" "Connection: close\r\n\r\n", conn.uv.path, conn.uv.host, conn.uv.port); if (get != NULL) { AM_LOG_DEBUG(instance_id, "%s sending request:\n%s", thisfunc, get); if (log != NULL) { log("%s sending request:\n%s", thisfunc, get); } status = am_net_write(&conn, get, get_sz); free(get); } } else { AM_LOG_DEBUG(instance_id, "am_net_connect(%s) returns NON zero", url); if (log != NULL) { log("am_net_connect(%s) returns NON zero", url); } } AM_LOG_DEBUG(instance_id, "status is set to %d", status); if (log != NULL) { log("status is set to %d", status); } if (status == AM_SUCCESS) { wait_for_event(request_data.event, 0); } else { AM_LOG_DEBUG(instance_id, "%s disconnecting", thisfunc); if (log != NULL) { log("%s disconnecting", thisfunc); } am_net_diconnect(&conn); } AM_LOG_DEBUG(instance_id, "%s response status code: %d", thisfunc, conn.http_status); if (log != NULL) { log("%s response status code: %d", thisfunc, conn.http_status); } if (httpcode) { *httpcode = conn.http_status; } am_net_close(&conn); close_event(request_data.event); am_free(request_data.data); 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; }
static void parse_config_value(am_xml_parser_ctx_t *x, const char *prm, int type, int *itm_sz, void *itm, const char *val, int len) { if (itm == NULL || val == NULL || len <= 0 || strcmp(x->current_name, prm) != 0) { return; } switch (type) { case CONF_STRING: { char **value = (char **) itm; *value = strndup(val, len); if (x->log_enable) { if (strstr(prm, "password") != NULL) { AM_LOG_DEBUG(x->conf->instance_id, "am_parse_config_xml() %s is set to '********'", prm); break; } AM_LOG_DEBUG(x->conf->instance_id, "am_parse_config_xml() %s is set to '%s'", prm, LOGEMPTY(*value)); } } break; case CONF_NUMBER: { int *value = (int *) itm; if (strncasecmp(val, "on", len) == 0 || strncasecmp(val, "true", len) == 0 || strncasecmp(val, "local", len) == 0) { *value = 1; } else if (strncasecmp(val, "off", len) == 0 || strncasecmp(val, "false", len) == 0 || strncasecmp(val, "centralized", len) == 0) { *value = 0; } else { char *t = strndup(val, len); if (t != NULL) { *value = strtol(t, NULL, AM_BASE_TEN); free(t); } } if (x->log_enable) { AM_LOG_DEBUG(x->conf->instance_id, "am_parse_config_xml() %s is set to '%d'", prm, *value); } } break; case CONF_DEBUG_LEVEL: { int *value = (int *) itm; *value = AM_LOG_LEVEL_NONE; if (strncasecmp(val, "all", 3) == 0) { *value = AM_LOG_LEVEL_DEBUG; } else if (strncasecmp(val, "error", len) == 0) { *value = AM_LOG_LEVEL_ERROR; } else if (strncasecmp(val, "info", len) == 0) { *value = AM_LOG_LEVEL_INFO; } else if (strncasecmp(val, "message", len) == 0) { *value = AM_LOG_LEVEL_WARNING; } else if (strncasecmp(val, "warning", len) == 0) { *value = AM_LOG_LEVEL_WARNING; } if (x->log_enable) { AM_LOG_DEBUG(x->conf->instance_id, "am_parse_config_xml() %s is set to '%d'", prm, *value); } } break; case CONF_ATTR_MODE: { int *value = (int *) itm; *value = AM_SET_ATTRS_NONE; if (strncasecmp(val, "HTTP_HEADER", len) == 0) { *value = AM_SET_ATTRS_AS_HEADER; } else if (strncasecmp(val, "HTTP_COOKIE", len) == 0) { *value = AM_SET_ATTRS_AS_COOKIE; } if (x->log_enable) { AM_LOG_DEBUG(x->conf->instance_id, "am_parse_config_xml() %s is set to '%d'", prm, *value); } } break; case CONF_AUDIT_LEVEL: { int *value = (int *) itm; *value = 0; if (strncasecmp(val, "LOG_ALLOW", len) == 0) { *value |= AM_LOG_LEVEL_AUDIT_ALLOW; } else if (strncasecmp(val, "LOG_BOTH", len) == 0) { *value |= AM_LOG_LEVEL_AUDIT_ALLOW; *value |= AM_LOG_LEVEL_AUDIT_DENY; } else if (strncasecmp(val, "LOG_DENY", len) == 0) { *value |= AM_LOG_LEVEL_AUDIT_DENY; } else if (strncasecmp(val, "ALL", len) == 0) { *value |= AM_LOG_LEVEL_AUDIT; *value |= AM_LOG_LEVEL_AUDIT_REMOTE; } else if (strncasecmp(val, "LOCAL", len) == 0) { *value |= AM_LOG_LEVEL_AUDIT; } else if (strncasecmp(val, "REMOTE", len) == 0) { *value |= AM_LOG_LEVEL_AUDIT_REMOTE; } if (x->log_enable) { AM_LOG_DEBUG(x->conf->instance_id, "am_parse_config_xml() %s is set to '%d'", prm, *value); } } break; case CONF_STRING_LIST: { int old_sz = *itm_sz; char ***value = (char ***) itm; char **value_tmp; char *v = strndup(val, len); if (v == NULL) break; value_tmp = (char **) realloc(*value, sizeof (char *) *(++(*itm_sz))); if (value_tmp == NULL) {//TODO: realloc failure? (*itm_sz)--; if (*itm_sz < 0) *itm_sz = 0; free(v); break; } *value = value_tmp; (*value)[old_sz] = v; if (x->log_enable) { AM_LOG_DEBUG(x->conf->instance_id, "am_parse_config_xml() %s is set to %d value(s)", prm, *itm_sz); } } break; case CONF_NUMBER_LIST: { int old_sz = *itm_sz; int **value = (int **) itm; int *value_tmp; char *v = strndup(val, len); if (v == NULL) break; value_tmp = (int *) realloc(*value, sizeof (int) *(++(*itm_sz))); if (value_tmp == NULL) { (*itm_sz)--; if (*itm_sz < 0) *itm_sz = 0; free(v); break; } *value = value_tmp; (*value)[old_sz] = strtol(v, NULL, AM_BASE_TEN); free(v); if (x->log_enable) { AM_LOG_DEBUG(x->conf->instance_id, "am_parse_config_xml() %s is set to %d value(s)", prm, *itm_sz); } } break; case CONF_STRING_MAP: { int old_sz = *itm_sz; am_config_map_t **value = (am_config_map_t **) itm; am_config_map_t *value_tmp; size_t slen = (size_t) len; char *v, *mv; if (val[0] != '[') break; v = strndup(val, len); if (v == NULL) break; mv = match_group(x->rgx, 2 /* groups in [key]=value */, v, &slen); free(v); if (mv == NULL) break; value_tmp = (am_config_map_t *) realloc(*value, sizeof (am_config_map_t) *(++(*itm_sz))); if (value_tmp == NULL) { (*itm_sz)--; if (*itm_sz < 0) *itm_sz = 0; free(mv); break; } *value = value_tmp; (&(*value)[old_sz])->name = mv; (&(*value)[old_sz])->value = mv + strlen(mv) + 1; if (x->log_enable) { AM_LOG_DEBUG(x->conf->instance_id, "am_parse_config_xml() %s is set to %d value(s)", prm, *itm_sz); } } break; default: AM_LOG_WARNING(x->conf->instance_id, "am_parse_config_xml() unknown type value %d setting %s", type, prm); break; } }
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); }