/* * ModSecurity for Apache 2.x, http://www.modsecurity.org/ * Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/) * * You may not use this file except in compliance with * the License.  You may obtain a copy of the License at * *     http://www.apache.org/licenses/LICENSE-2.0 * * If any of the files related to licensing are missing or if you have any * other questions related to licensing please contact Trustwave Holdings, Inc. * directly using the email address security@modsecurity.org. */ #include "msc_crypt.h" #include "msc_util.h" #include "apr_sha1.h" #include "apr_uri.h" #include "apr_base64.h" #include "acmp.h" #include "libxml/HTMLtree.h" #include "libxml/uri.h" #include /** * \brief Normalize path in URI * * \param msr ModSecurity transaction resource * \param input The URI to be normalized * * \retval input normalized input * \retval NULL on fail */ char *normalize_path(modsec_rec *msr, char *input) { xmlURI *uri = NULL; char *parsed_content = NULL; char *content = NULL; if(msr == NULL) return NULL; if(input == NULL) return NULL; uri = xmlParseURI(input); if(uri != NULL && uri->path) { if(uri->scheme) { content = apr_psprintf(msr->mp, "%s://", uri->scheme); parsed_content = apr_pstrcat(msr->mp, content, NULL); } if(uri->server) { content = apr_psprintf(msr->mp, "%s", uri->server); if(parsed_content) parsed_content = apr_pstrcat(msr->mp, parsed_content, content, NULL); else parsed_content = apr_pstrcat(msr->mp, content, NULL); } if(uri->port) { content = apr_psprintf(msr->mp, ":%d", uri->port); if(parsed_content) parsed_content = apr_pstrcat(msr->mp, parsed_content, content, NULL); else parsed_content = apr_pstrcat(msr->mp, content, NULL); } if(uri->path) { char *Uri = NULL; int bytes = 0; /*int i;*/ char *abs_link = NULL; char *filename = NULL; char *abs_path = NULL; char *abs_uri = NULL; if (uri->path[0] != '/') { /* uri->path is relative. make it absolute */ filename = file_basename(msr->mp, msr->r->parsed_uri.path); if(filename == NULL || (strlen(msr->r->parsed_uri.path) - strlen(filename) < 0)) return NULL; abs_path = apr_pstrndup(msr->mp, msr->r->parsed_uri.path, strlen(msr->r->parsed_uri.path) - strlen(filename)); abs_uri = apr_pstrcat(msr->mp, abs_path, uri->path, NULL); abs_link = apr_pstrdup(msr->mp, abs_uri); } else { abs_link = apr_pstrdup(msr->mp, uri->path); } xmlNormalizeURIPath(abs_link); Uri = apr_pstrdup(msr->mp, abs_link); /* for(i = 0; i < (int)strlen(Uri); i++) { if(Uri[i] != '.' && Uri[i] != '/') { if (i - 1 < 0) i = 0; else i--; if(Uri[i] == '/') --bytes; break; } else { bytes++; } } if(bytes >= (int)strlen(uri->path)) return NULL; */ content = apr_psprintf(msr->mp, "%s", Uri); if(parsed_content) parsed_content = apr_pstrcat(msr->mp, parsed_content, content, NULL); else parsed_content = apr_pstrcat(msr->mp, content, NULL); } if(uri->query_raw) { content = apr_psprintf(msr->mp, "?%s", uri->query_raw); if(parsed_content) parsed_content = apr_pstrcat(msr->mp, parsed_content, content, NULL); else parsed_content = apr_pstrcat(msr->mp, content, NULL); } if(uri->fragment) { content = apr_psprintf(msr->mp, "#%s", uri->fragment); if(parsed_content) parsed_content = apr_pstrcat(msr->mp, parsed_content, content, NULL); else parsed_content = apr_pstrcat(msr->mp, content, NULL); } xmlFreeURI(uri); return apr_pstrdup(msr->mp, parsed_content); } if(uri != NULL) xmlFreeURI(uri); return apr_pstrdup(msr->mp, input); } /** * \brief Create a random password * * \param mp ModSecurity transaction memory pool * * \retval key random key */ char *getkey(apr_pool_t *mp) { unsigned char digest[APR_SHA1_DIGESTSIZE]; char *sig, *key, *value; apr_sha1_ctx_t ctx; char salt[64]; apr_generate_random_bytes(salt, sizeof(salt)); key = apr_psprintf(mp,"%.*s",(int)sizeof(salt),salt); apr_sha1_init (&ctx); apr_sha1_update (&ctx, (const char*)key, strlen(key)); apr_sha1_update (&ctx, "\0", 1); apr_generate_random_bytes(salt, sizeof(salt)); value = apr_psprintf(mp,"%.*s",(int)sizeof(salt),salt); apr_sha1_update (&ctx, value, strlen (value)); apr_sha1_final (digest, &ctx); sig = apr_pcalloc (mp, apr_base64_encode_len (sizeof (digest))); apr_base64_encode (sig, (const char*)digest, sizeof (digest)); return sig; } /** * \brief Generate the MAC for a given message * * \param msr ModSecurity transaction resource * \param key The key used within HMAC * \param key_len Key length * \param msg The message to generate the MAC * \param msglen The message length * * \retval hex_digest The MAC */ char *hmac(modsec_rec *msr, const char *key, int key_len, unsigned char *msg, int msglen) { apr_sha1_ctx_t ctx; unsigned char digest[APR_SHA1_DIGESTSIZE]; unsigned char hmac_ipad[HMAC_PAD_SIZE], hmac_opad[HMAC_PAD_SIZE]; unsigned char nkey[APR_SHA1_DIGESTSIZE]; unsigned char *hmac_key = (unsigned char *) key; char hex_digest[APR_SHA1_DIGESTSIZE * 2 + 1], *hmac_digest; const char hex[] = "0123456789abcdef"; int i; if (key_len > HMAC_PAD_SIZE-1) { hmac_key = nkey; key_len = APR_SHA1_DIGESTSIZE; } memset ((void *) hmac_ipad, 0, sizeof (hmac_ipad)); memset ((void *) hmac_opad, 0, sizeof (hmac_opad)); memmove (hmac_ipad, hmac_key, key_len); memmove (hmac_opad, hmac_key, key_len); for (i = 0; i < HMAC_PAD_SIZE-1; i++) { hmac_ipad[i] ^= 0x36; hmac_opad[i] ^= 0x5c; } apr_sha1_init (&ctx); apr_sha1_update_binary (&ctx, hmac_ipad, HMAC_PAD_SIZE-1); apr_sha1_update_binary (&ctx, (const unsigned char *) msg, msglen); apr_sha1_final (digest, &ctx); apr_sha1_init (&ctx); apr_sha1_update_binary (&ctx, hmac_opad, HMAC_PAD_SIZE-1); apr_sha1_update_binary (&ctx, digest, sizeof (digest)); apr_sha1_final (digest, &ctx); hmac_digest = hex_digest; for (i = 0; i < sizeof (digest); i++) { *hmac_digest++ = hex[digest[i] >> 4]; *hmac_digest++ = hex[digest[i] & 0xF]; } *hmac_digest = '\0'; return apr_pstrdup (msr->mp, hex_digest); } /** * \brief Init html response body parser * * \param msr ModSecurity transaction resource * * \retval 1 on success * \retval -1 on fail */ int init_response_body_html_parser(modsec_rec *msr) { char *charset = NULL; char *final_charset = NULL; char sep; if(msr == NULL) return -1; if(msr->r == NULL) return -1; if(msr->r->content_type == NULL) return -1; if(msr->crypto_html_tree != NULL){ xmlFreeDoc(msr->crypto_html_tree); msr->crypto_html_tree = NULL; } if((strncmp("text/html",msr->r->content_type, 9) != 0)){ if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "init_response_body_html_parser: skipping html_tree generation for Content[%s].", msr->r->content_type); if(msr->crypto_html_tree != NULL){ xmlFreeDoc(msr->crypto_html_tree); msr->crypto_html_tree = NULL; } return -1; } if (msr->resbody_length == 0) { if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "init_response_body_html_parser: skipping html_tree generation for zero length respomse body."); msr->crypto_html_tree = NULL; return 0; } if((msr->r->content_encoding == NULL)||(apr_strnatcasecmp(msr->r->content_encoding,"(null)")==0)){ charset=m_strcasestr(msr->r->content_type,"charset="); if(charset == NULL){ if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "init_response_body_html_parser: assuming ISO-8859-1."); msr->crypto_html_tree = htmlReadMemory(msr->resbody_data, msr->resbody_length, NULL, "ISO-8859-1", HTML_PARSE_RECOVER | HTML_PARSE_NOBLANKS | HTML_PARSE_NOERROR | HTML_PARSE_NOWARNING); htmlSetMetaEncoding ((htmlDocPtr) msr->crypto_html_tree, (const xmlChar *) "ISO-8859-1"); } else{ charset+=8; final_charset=strchr(charset,' '); if(final_charset == NULL) final_charset = strchr(charset,';'); if(final_charset != NULL) { sep = *final_charset; *final_charset = '\0'; } if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "init_response_body_html_parser: Charset[%s]",charset); msr->crypto_html_tree = htmlReadMemory(msr->resbody_data, msr->resbody_length, NULL, charset, HTML_PARSE_RECOVER| HTML_PARSE_NOBLANKS | HTML_PARSE_NOERROR | HTML_PARSE_NOWARNING); htmlSetMetaEncoding ((htmlDocPtr) msr->crypto_html_tree, (const xmlChar *)charset); if(final_charset != NULL) *final_charset=sep; } } else{ if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4,"init_response_body_html_parser: Enconding[%s].",msr->r->content_encoding); msr->crypto_html_tree = htmlReadMemory(msr->resbody_data, msr->resbody_length, NULL, msr->r->content_encoding, HTML_PARSE_RECOVER | HTML_PARSE_NOBLANKS | HTML_PARSE_NOERROR | HTML_PARSE_NOWARNING); htmlSetMetaEncoding ((htmlDocPtr) msr->crypto_html_tree, (const xmlChar *)msr->r->content_encoding); } if(msr->crypto_html_tree == NULL){ if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "init_response_body_html_parser: Failed to parse response body."); return -1; } else { if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "init_response_body_html_parser: Successfully html parser generated."); return 1; } return 1; } /** * \brief Execute all hash methods * * \param msr ModSecurity transaction resource * \param link The html attr value to be checked * \param type The hash method type * * \retval 1 Match * \retval 0 No Match * \retval -1 on fail */ int do_hash_method(modsec_rec *msr, char *link, int type) { hash_method **em = NULL; int i = 0; char *error_msg = NULL; char *my_error_msg = NULL; int ovector[33]; int rc; if(msr == NULL) return -1; em = (hash_method **)msr->txcfg->hash_method->elts; if(msr->txcfg->hash_method->nelts == 0) return 1; for (i = 0; i < msr->txcfg->hash_method->nelts; i++) { if(em[i] != NULL && em[i]->param_data != NULL){ switch(type) { case HASH_URL_HREF_HASH_PM: if(em[i]->type == HASH_URL_HREF_HASH_PM) { const char *match = NULL; apr_status_t rc = 0; ACMPT pt; pt.parser = (ACMP *)em[i]->param_data; pt.ptr = NULL; rc = acmp_process_quick(&pt, &match, link, strlen(link)); if (rc) { return 1; } else { return 0; } } break; case HASH_URL_HREF_HASH_RX: if(em[i]->type == HASH_URL_HREF_HASH_RX) { rc = msc_regexec_capture(em[i]->param_data, link, strlen(link), ovector, 30, &my_error_msg); if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) { msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); if (s == NULL) return -1; s->name = apr_pstrdup(msr->mp, "MSC_PCRE_LIMITS_EXCEEDED"); if (s->name == NULL) return -1; s->name_len = strlen(s->name); s->value = apr_pstrdup(msr->mp, "1"); if (s->value == NULL) return -1; s->value_len = 1; apr_table_setn(msr->tx_vars, s->name, (void *)s); error_msg = apr_psprintf(msr->mp, "Execution error - " "PCRE limits exceeded for Hash regex [%s] (%d): %s", em[i]->param,rc, my_error_msg); if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "%s.", error_msg); return 0; /* No match. */ } else if (rc < -1) { error_msg = apr_psprintf(msr->mp, "Regex execution failed (%d): %s", rc, my_error_msg); if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "%s.", error_msg); return -1; } if (rc != PCRE_ERROR_NOMATCH) { /* Match. */ return 1; } } break; case HASH_URL_FACTION_HASH_PM: if(em[i]->type == HASH_URL_FACTION_HASH_PM) { const char *match = NULL; apr_status_t rc = 0; ACMPT pt; pt.parser = (ACMP *)em[i]->param_data; pt.ptr = NULL; rc = acmp_process_quick(&pt, &match, link, strlen(link)); if (rc) { return 1; } else { return 0; } } break; case HASH_URL_FACTION_HASH_RX: if(em[i]->type == HASH_URL_FACTION_HASH_RX) { rc = msc_regexec_capture(em[i]->param_data, link, strlen(link), ovector, 30, &my_error_msg); if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) { msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); if (s == NULL) return -1; s->name = apr_pstrdup(msr->mp, "MSC_PCRE_LIMITS_EXCEEDED"); if (s->name == NULL) return -1; s->name_len = strlen(s->name); s->value = apr_pstrdup(msr->mp, "1"); if (s->value == NULL) return -1; s->value_len = 1; apr_table_setn(msr->tx_vars, s->name, (void *)s); error_msg = apr_psprintf(msr->mp, "Execution error - " "PCRE limits exceeded for Hash regex [%s] (%d): %s", em[i]->param,rc, my_error_msg); if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "%s.", error_msg); return 0; /* No match. */ } else if (rc < -1) { error_msg = apr_psprintf(msr->mp, "Regex execution failed (%d): %s", rc, my_error_msg); if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "%s.", error_msg); return -1; } if (rc != PCRE_ERROR_NOMATCH) { /* Match. */ return 1; } } break; case HASH_URL_LOCATION_HASH_PM: if(em[i]->type == HASH_URL_LOCATION_HASH_PM) { const char *match = NULL; apr_status_t rc = 0; ACMPT pt; pt.parser = (ACMP *)em[i]->param_data; pt.ptr = NULL; rc = acmp_process_quick(&pt, &match, link, strlen(link)); if (rc) { return 1; } else { return 0; } } break; case HASH_URL_LOCATION_HASH_RX: if(em[i]->type == HASH_URL_LOCATION_HASH_RX) { rc = msc_regexec_capture(em[i]->param_data, link, strlen(link), ovector, 30, &my_error_msg); if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) { msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); if (s == NULL) return -1; s->name = apr_pstrdup(msr->mp, "MSC_PCRE_LIMITS_EXCEEDED"); if (s->name == NULL) return -1; s->name_len = strlen(s->name); s->value = apr_pstrdup(msr->mp, "1"); if (s->value == NULL) return -1; s->value_len = 1; apr_table_setn(msr->tx_vars, s->name, (void *)s); error_msg = apr_psprintf(msr->mp, "Execution error - " "PCRE limits exceeded for Hash regex [%s] (%d): %s", em[i]->param,rc, my_error_msg); if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "%s.", error_msg); return 0; /* No match. */ } else if (rc < -1) { error_msg = apr_psprintf(msr->mp, "Regex execution failed (%d): %s", rc, my_error_msg); if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "%s.", error_msg); return -1; } if (rc != PCRE_ERROR_NOMATCH) { /* Match. */ return 1; } } break; case HASH_URL_IFRAMESRC_HASH_PM: if(em[i]->type == HASH_URL_IFRAMESRC_HASH_PM) { const char *match = NULL; apr_status_t rc = 0; ACMPT pt; pt.parser = (ACMP *)em[i]->param_data; pt.ptr = NULL; rc = acmp_process_quick(&pt, &match, link, strlen(link)); if (rc) { return 1; } else { return 0; } } break; case HASH_URL_IFRAMESRC_HASH_RX: if(em[i]->type == HASH_URL_IFRAMESRC_HASH_RX) { rc = msc_regexec_capture(em[i]->param_data, link, strlen(link), ovector, 30, &my_error_msg); if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) { msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); if (s == NULL) return -1; s->name = apr_pstrdup(msr->mp, "MSC_PCRE_LIMITS_EXCEEDED"); if (s->name == NULL) return -1; s->name_len = strlen(s->name); s->value = apr_pstrdup(msr->mp, "1"); if (s->value == NULL) return -1; s->value_len = 1; apr_table_setn(msr->tx_vars, s->name, (void *)s); error_msg = apr_psprintf(msr->mp, "Execution error - " "PCRE limits exceeded for Hash regex [%s] (%d): %s", em[i]->param,rc, my_error_msg); if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "%s.", error_msg); return 0; /* No match. */ } else if (rc < -1) { error_msg = apr_psprintf(msr->mp, "Regex execution failed (%d): %s", rc, my_error_msg); if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "%s.", error_msg); return -1; } if (rc != PCRE_ERROR_NOMATCH) { /* Match. */ return 1; } } break; case HASH_URL_FRAMESRC_HASH_PM: if(em[i]->type == HASH_URL_FRAMESRC_HASH_PM) { const char *match = NULL; apr_status_t rc = 0; ACMPT pt; pt.parser = (ACMP *)em[i]->param_data; pt.ptr = NULL; rc = acmp_process_quick(&pt, &match, link, strlen(link)); if (rc) { return 1; } else { return 0; } } break; case HASH_URL_FRAMESRC_HASH_RX: if(em[i]->type == HASH_URL_FRAMESRC_HASH_RX) { rc = msc_regexec_capture(em[i]->param_data, link, strlen(link), ovector, 30, &my_error_msg); if ((rc == PCRE_ERROR_MATCHLIMIT) || (rc == PCRE_ERROR_RECURSIONLIMIT)) { msc_string *s = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); if (s == NULL) return -1; s->name = apr_pstrdup(msr->mp, "MSC_PCRE_LIMITS_EXCEEDED"); if (s->name == NULL) return -1; s->name_len = strlen(s->name); s->value = apr_pstrdup(msr->mp, "1"); if (s->value == NULL) return -1; s->value_len = 1; apr_table_setn(msr->tx_vars, s->name, (void *)s); error_msg = apr_psprintf(msr->mp, "Execution error - " "PCRE limits exceeded for Hash regex [%s] (%d): %s", em[i]->param,rc, my_error_msg); if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "%s.", error_msg); return 0; /* No match. */ } else if (rc < -1) { error_msg = apr_psprintf(msr->mp, "Regex execution failed (%d): %s", rc, my_error_msg); if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "%s.", error_msg); return -1; } if (rc != PCRE_ERROR_NOMATCH) { /* Match. */ return 1; } } break; } } } return 0; } /** * \brief Hash the html elements * * \param msr ModSecurity transaction resource * * \retval 1 On success * \retval 0 No element was changed * \retval -1 On fail */ int hash_response_body_links(modsec_rec *msr) { int lsize = 0, fsize = 0, lcount = 0, fcount = 0, i; int isize = 0, icount = 0, frsize = 0, frcount = 0; int bytes = 0; xmlXPathContextPtr xpathCtx = NULL; xmlXPathObjectPtr xpathObj = NULL; xmlChar *content_option = NULL; char *mac_link = NULL; int rc, elts = 0; if(msr == NULL) return -1; if (msr->crypto_html_tree == NULL) { if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "hash_response_body_links: Cannot parse NULL html tree"); return -1; } if(msr->txcfg->crypto_hash_href_rx == 0 && msr->txcfg->crypto_hash_href_pm == 0 && msr->txcfg->crypto_hash_faction_rx == 0 && msr->txcfg->crypto_hash_faction_pm == 0 && msr->txcfg->crypto_hash_iframesrc_rx == 0 && msr->txcfg->crypto_hash_iframesrc_pm == 0 && msr->txcfg->crypto_hash_framesrc_rx == 0 && msr->txcfg->crypto_hash_framesrc_pm == 0) return -1; xpathCtx = xmlXPathNewContext(msr->crypto_html_tree); if(xpathCtx == NULL) { if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "hash_response_body_links: Unable to create Xpath context."); goto ctx_error; } lcount=fcount=0; if(msr->txcfg->crypto_hash_href_rx == 1 || msr->txcfg->crypto_hash_href_pm == 1) { xpathObj = xmlXPathEvalExpression((xmlChar*)"//*[@href]", xpathCtx); if(xpathObj == NULL) { if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "hash_response_body_links: Unable to evaluate xpath expression."); goto obj_error; } lsize = (xpathObj->nodesetval) ? xpathObj->nodesetval->nodeNr : 0; for(i = lsize - 1; i >=0; i--) { register xmlNodePtr cur; cur = xpathObj->nodesetval->nodeTab[i]; if(cur != NULL){ xmlChar *href = xmlGetProp(cur, (const xmlChar *) "href"); char *content_href = normalize_path(msr, (char *)href); if(content_href != NULL && strstr(content_href,msr->txcfg->crypto_param_name) == NULL) { if(msr->txcfg->crypto_hash_href_rx == 1) { rc = do_hash_method(msr, (char *)content_href, HASH_URL_HREF_HASH_RX); if(rc > 0) { mac_link = NULL; mac_link = do_hash_link(msr, (char *)content_href, FULL_LINK); if(mac_link != NULL) { xmlSetProp(cur, (const xmlChar *) "href", (const xmlChar *) mac_link); lcount++; bytes += strlen(mac_link); msr->of_stream_changed = 1; } mac_link = NULL; if(href != NULL) xmlFree(href); continue; } } if(msr->txcfg->crypto_hash_href_pm == 1) { rc = do_hash_method(msr, (char *)content_href, HASH_URL_HREF_HASH_PM); if(rc > 0) { mac_link = NULL; mac_link = do_hash_link(msr, (char *)content_href, FULL_LINK); if(mac_link != NULL) { xmlSetProp(cur, (const xmlChar *) "href", (const xmlChar *) mac_link); lcount++; bytes += strlen(mac_link); msr->of_stream_changed = 1; } mac_link = NULL; if(href != NULL) xmlFree(href); continue; } } } if(href != NULL) { xmlFree(href); href = NULL; } } } if(xpathObj != NULL) xmlXPathFreeObject(xpathObj); } if(msr->txcfg->crypto_hash_faction_rx == 1 || msr->txcfg->crypto_hash_faction_pm == 1) { xpathObj = xmlXPathEvalExpression((xmlChar*)"//form", xpathCtx); if(xpathObj == NULL) { if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "hash_response_body_links: Unable to evaluate xpath expression."); goto obj_error; } fsize = (xpathObj->nodesetval) ? xpathObj->nodesetval->nodeNr : 0; for(i = fsize - 1; i >=0; i--) { register xmlNodePtr cur; cur = xpathObj->nodesetval->nodeTab[i]; if((cur != NULL)){ xmlChar *action = NULL; char *content_action = NULL; if(content_option) xmlFree(content_option); action = xmlGetProp(cur, (const xmlChar *) "action"); content_action = normalize_path(msr, (char *)action); content_option = xmlGetProp(cur, (const xmlChar *) "option"); if(content_action != NULL && content_option == NULL && strstr(content_action,msr->txcfg->crypto_param_name) == NULL) { if(msr->txcfg->crypto_hash_faction_rx == 1) { rc = do_hash_method(msr, (char *)content_action, HASH_URL_FACTION_HASH_RX); if(rc > 0) { mac_link = NULL; mac_link = do_hash_link(msr, (char *)content_action, FULL_LINK); if(mac_link != NULL) { xmlSetProp(cur, (const xmlChar *) "action", (const xmlChar *) mac_link); fcount++; bytes += strlen(mac_link); msr->of_stream_changed = 1; } mac_link = NULL; if(action != NULL) xmlFree(action); continue; } } if(msr->txcfg->crypto_hash_faction_pm == 1) { rc = do_hash_method(msr, (char *)content_action, HASH_URL_FACTION_HASH_PM); if(rc > 0) { mac_link = NULL; mac_link = do_hash_link(msr, (char *)content_action, FULL_LINK); if(mac_link != NULL) { xmlSetProp(cur, (const xmlChar *) "action", (const xmlChar *) mac_link); fcount++; bytes += strlen(mac_link); msr->of_stream_changed = 1; } mac_link = NULL; if(action != NULL) xmlFree(action); continue; } } } if(action != NULL) { xmlFree(action); action = NULL; } if(content_option) { xmlFree(content_option); content_option = NULL; } } } if(xpathObj != NULL) xmlXPathFreeObject(xpathObj); } if(msr->txcfg->crypto_hash_iframesrc_rx == 1 || msr->txcfg->crypto_hash_iframesrc_pm == 1) { xpathObj = xmlXPathEvalExpression((xmlChar*)"//iframe", xpathCtx); if(xpathObj == NULL) { if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "hash_response_body_links: Unable to evaluate xpath expression."); goto obj_error; } isize = (xpathObj->nodesetval) ? xpathObj->nodesetval->nodeNr : 0; for(i = isize - 1; i >=0; i--) { register xmlNodePtr cur; cur = xpathObj->nodesetval->nodeTab[i]; if((cur != NULL)){ xmlChar *src = xmlGetProp(cur, (const xmlChar *) "src"); char *content_src = normalize_path(msr, (char *)src); if(content_src != NULL && strstr(content_src,msr->txcfg->crypto_param_name) == NULL) { if(msr->txcfg->crypto_hash_iframesrc_rx == 1) { rc = do_hash_method(msr, (char *)content_src, HASH_URL_IFRAMESRC_HASH_RX); if(rc > 0) { mac_link = NULL; mac_link = do_hash_link(msr, (char *)content_src, FULL_LINK); if(mac_link != NULL) { xmlSetProp(cur, (const xmlChar *) "src", (const xmlChar *) mac_link); icount++; bytes += strlen(mac_link); msr->of_stream_changed = 1; } mac_link = NULL; if(src != NULL) xmlFree(src); continue; } } if(msr->txcfg->crypto_hash_iframesrc_pm == 1) { rc = do_hash_method(msr, (char *)content_src, HASH_URL_IFRAMESRC_HASH_PM); if(rc > 0) { mac_link = NULL; mac_link = do_hash_link(msr, (char *)content_src, FULL_LINK); if(mac_link != NULL) { xmlSetProp(cur, (const xmlChar *) "src", (const xmlChar *) mac_link); icount++; bytes += strlen(mac_link); msr->of_stream_changed = 1; } mac_link = NULL; if(src != NULL) xmlFree(src); continue; } } } if(src != NULL) { xmlFree(src); src = NULL; } } } if(xpathObj != NULL) xmlXPathFreeObject(xpathObj); } if(msr->txcfg->crypto_hash_framesrc_rx == 1 || msr->txcfg->crypto_hash_framesrc_pm == 1) { xpathObj = xmlXPathEvalExpression((xmlChar*)"//frame", xpathCtx); if(xpathObj == NULL) { if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "hash_response_body_links: Unable to evaluate xpath expression."); goto obj_error; } frsize = (xpathObj->nodesetval) ? xpathObj->nodesetval->nodeNr : 0; for(i = frsize - 1; i >=0; i--) { register xmlNodePtr cur; cur = xpathObj->nodesetval->nodeTab[i]; if((cur != NULL)){ xmlChar *src = xmlGetProp(cur, (const xmlChar *) "src"); char *content_src = normalize_path(msr, (char *)src); if(content_src != NULL && strstr(content_src,msr->txcfg->crypto_param_name) == NULL) { if(msr->txcfg->crypto_hash_framesrc_rx == 1) { rc = do_hash_method(msr, (char *)content_src, HASH_URL_FRAMESRC_HASH_RX); if(rc > 0) { mac_link = NULL; mac_link = do_hash_link(msr, (char *)content_src, FULL_LINK); if(mac_link != NULL) { xmlSetProp(cur, (const xmlChar *) "src", (const xmlChar *) mac_link); frcount++; bytes += strlen(mac_link); msr->of_stream_changed = 1; } mac_link = NULL; if(src != NULL) xmlFree(src); continue; } } if(msr->txcfg->crypto_hash_framesrc_pm == 1) { rc = do_hash_method(msr, (char *)content_src, HASH_URL_FRAMESRC_HASH_PM); if(rc > 0) { mac_link = NULL; mac_link = do_hash_link(msr, (char *)content_src, FULL_LINK); if(mac_link != NULL) { xmlSetProp(cur, (const xmlChar *) "src", (const xmlChar *) mac_link); frcount++; bytes += strlen(mac_link); msr->of_stream_changed = 1; } mac_link = NULL; if(src != NULL) xmlFree(src); continue; } } } if(src != NULL) { xmlFree(src); src = NULL; } } } if(xpathObj != NULL) xmlXPathFreeObject(xpathObj); } if(xpathCtx != NULL) xmlXPathFreeContext(xpathCtx); if (msr->txcfg->debuglog_level >= 4) { msr_log(msr, 4, "hash_response_body_links: Processed [%d] iframe src, [%d] hashed.",isize, icount); msr_log(msr, 4, "hash_response_body_links: Processed [%d] frame src, [%d] hashed.",frsize, frcount); msr_log(msr, 4, "hash_response_body_links: Processed [%d] form actions, [%d] hashed.",fsize, fcount); msr_log(msr, 4, "hash_response_body_links: Processed [%d] links, [%d] hashed.",lsize, lcount); } if(msr->of_stream_changed == 0) { if(msr->crypto_html_tree != NULL) { xmlFreeDoc(msr->crypto_html_tree); msr->crypto_html_tree = NULL; } return 0; } elts = (icount+frcount+fcount+lcount); if((elts >= INT32_MAX) || (elts < 0)) return 0; return bytes; obj_error: if(xpathCtx != NULL) xmlXPathFreeContext(xpathCtx); ctx_error: return -1; } /** * \brief Inject the new response body * * \param msr ModSecurity transaction resource * \param elts Number of hashed elements * * \retval 1 On success * \retval -1 On fail */ int inject_hashed_response_body(modsec_rec *msr, int elts) { xmlOutputBufferPtr output_buf = NULL; xmlCharEncodingHandlerPtr handler = NULL; char *p = NULL; const char *ctype = NULL; const char *encoding = NULL; char *new_ct = NULL, *content_value = NULL; if(msr == NULL) return -1; if(msr->r == NULL) return -1; if (msr->crypto_html_tree == NULL) { if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "inject_hashed_response_body: Cannot parse NULL html tree"); return -1; } if(msr->r->content_type != NULL) ctype = msr->r->content_type; encoding = (const char *) htmlGetMetaEncoding(msr->crypto_html_tree); if (ctype && encoding == NULL) { if (ctype && (p = m_strcasestr(ctype, "charset=") , p != NULL)) { p += 8 ; if (encoding = apr_pstrndup(msr->mp, p, strcspn(p, " ;") ), encoding) { xmlCharEncoding enc; enc = xmlParseCharEncoding(encoding); handler = xmlFindCharEncodingHandler(encoding); } } } else { if(encoding != NULL) { xmlCharEncoding enc; enc = xmlParseCharEncoding(encoding); handler = xmlFindCharEncodingHandler(encoding); } } if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "inject_hashed_response_body: Detected encoding type [%s].", encoding); if (handler == NULL) handler = xmlFindCharEncodingHandler("UTF-8"); if (handler == NULL) handler = xmlFindCharEncodingHandler("ISO-8859-1"); if (handler == NULL) handler = xmlFindCharEncodingHandler("HTML"); if (handler == NULL) handler = xmlFindCharEncodingHandler("ascii"); if(handler == NULL) { xmlFreeDoc(msr->crypto_html_tree); return -1; } apr_table_unset(msr->r->headers_out,"Content-Type"); new_ct = (char*)apr_psprintf(msr->mp, "text/html;%s",handler->name); apr_table_set(msr->r->err_headers_out,"Content-Type",new_ct); if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "inject_hashed_response_body: Using content-type [%s].", handler->name); output_buf = xmlAllocOutputBuffer(handler); if (output_buf == NULL) { if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "inject_hashed_response_body: Unable to allocate memory buffer."); xmlFreeDoc(msr->crypto_html_tree); return -1; } htmlDocContentDumpFormatOutput(output_buf, msr->crypto_html_tree, NULL, 0); // Not necessary in 2.9.4+ //xmlOutputBufferFlush(output_buf); #ifdef LIBXML2_NEW_BUFFER if (output_buf->conv == NULL || (output_buf->conv && xmlOutputBufferGetSize(output_buf) == 0)) { if(output_buf->buffer == NULL || xmlOutputBufferGetSize(output_buf) == 0) { xmlOutputBufferClose(output_buf); xmlFreeDoc(msr->crypto_html_tree); msr->of_stream_changed = 0; msr_log(msr, 4, "inject_hashed_response_body: NEW_BUFFER Output buffer is null."); return -1; } if(msr->stream_output_data != NULL) { free(msr->stream_output_data); msr->stream_output_data = NULL; } msr->stream_output_length = xmlOutputBufferGetSize(output_buf); msr->stream_output_data = (char *)malloc(msr->stream_output_length+1); if (msr->stream_output_data == NULL) { xmlOutputBufferClose(output_buf); xmlFreeDoc(msr->crypto_html_tree); msr_log(msr, 4, "inject_hashed_response_body: NEW BUFFER Stream Output is null."); return -1; } memset(msr->stream_output_data, 0x0, msr->stream_output_length+1); memcpy(msr->stream_output_data, xmlOutputBufferGetContent(output_buf), msr->stream_output_length); if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "inject_hashed_response_body: Copying XML tree from CONTENT to stream buffer [%zu] bytes.", xmlOutputBufferGetSize(output_buf)); } else { if(output_buf->conv == NULL || xmlOutputBufferGetSize(output_buf) == 0) { xmlOutputBufferClose(output_buf); xmlFreeDoc(msr->crypto_html_tree); msr->of_stream_changed = 0; msr_log(msr, 4, "inject_hashed_response_body: Conv is null."); return -1; } if(msr->stream_output_data != NULL) { free(msr->stream_output_data); msr->stream_output_data = NULL; } msr->stream_output_length = xmlOutputBufferGetSize(output_buf); msr->stream_output_data = (char *)malloc(msr->stream_output_length+1); if (msr->stream_output_data == NULL) { msr_log(msr, 4, "inject_hashed_response_body: Stream Output data is NULL."); xmlOutputBufferClose(output_buf); xmlFreeDoc(msr->crypto_html_tree); return -1; } memset(msr->stream_output_data, 0x0, msr->stream_output_length+1); memcpy(msr->stream_output_data, xmlOutputBufferGetContent(output_buf), msr->stream_output_length); if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "inject_hashed_response_body: Copying XML tree from CONV to stream buffer [%zu] bytes.", xmlOutputBufferGetSize(output_buf)); } #else if (output_buf->conv == NULL || (output_buf->conv && output_buf->conv->use == 0)) { if(output_buf->buffer == NULL || output_buf->buffer->use == 0) { xmlOutputBufferClose(output_buf); xmlFreeDoc(msr->crypto_html_tree); msr_log(msr, 4, "inject_hashed_response_body: Output buffer is null."); msr->of_stream_changed = 0; return -1; } if(msr->stream_output_data != NULL) { free(msr->stream_output_data); msr->stream_output_data = NULL; } msr->stream_output_length = output_buf->buffer->use; msr->stream_output_data = (char *)malloc(msr->stream_output_length+1); if (msr->stream_output_data == NULL) { xmlOutputBufferClose(output_buf); xmlFreeDoc(msr->crypto_html_tree); msr_log(msr, 4, "inject_hashed_response_body: Stream Output is null."); return -1; } memset(msr->stream_output_data, 0x0, msr->stream_output_length+1); memcpy(msr->stream_output_data, (char *)xmlBufferContent(output_buf->buffer), msr->stream_output_length); //memcpy(msr->stream_output_data, output_buf->buffer->content, msr->stream_output_length); if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "inject_hashed_response_body: Copying XML tree from CONTENT to stream buffer [%d] bytes.", msr->stream_output_length); } else { if(output_buf->conv == NULL || output_buf->conv->use == 0) { xmlOutputBufferClose(output_buf); xmlFreeDoc(msr->crypto_html_tree); msr->of_stream_changed = 0; msr_log(msr, 4, "inject_hashed_response_body: Stream Output is null."); return -1; } if(msr->stream_output_data != NULL) { free(msr->stream_output_data); msr->stream_output_data = NULL; } msr->stream_output_length = output_buf->conv->use; msr->stream_output_data = (char *)malloc(msr->stream_output_length+1); if (msr->stream_output_data == NULL) { xmlOutputBufferClose(output_buf); xmlFreeDoc(msr->crypto_html_tree); msr_log(msr, 4, "inject_hashed_response_body: Stream Output Data is null."); return -1; } memset(msr->stream_output_data, 0x0, msr->stream_output_length+1); memcpy(msr->stream_output_data, (char *)xmlBufferContent(output_buf->conv), msr->stream_output_length); //memcpy(msr->stream_output_data, output_buf->conv->content, msr->stream_output_length); if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "inject_hashed_response_body: Copying XML tree from CONV to stream buffer [%d] bytes.", msr->stream_output_length); } #endif xmlOutputBufferClose(output_buf); content_value = (char*)apr_psprintf(msr->mp, "%"APR_SIZE_T_FMT, msr->stream_output_length); apr_table_unset(msr->r->headers_out,"Content-Length"); if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "inject_hashed_response_body: Setting new content value %s", content_value); apr_table_set(msr->r->headers_out, "Content-Length", content_value); xmlFreeDoc(msr->crypto_html_tree); if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "inject_hashed_response_body: Stream buffer [%"APR_SIZE_T_FMT"]. Done",msr->stream_output_length); return 1; } /** * \brief Parse and MAC html elements * * \param msr ModSecurity transaction resource * \param link The html attr value to be checked * \param type The hash method type * * \retval mac_link MACed link * \retval NULL on fail */ char *do_hash_link(modsec_rec *msr, char *link, int type) { char *mac_link = NULL; char *path_chunk = NULL; char *hash_value = NULL; char *qm = NULL; if(msr == NULL) return NULL; if(strlen(link) > 7 && strncmp("http:",(char*)link,5)==0){ path_chunk = strchr(link+7,'/'); if(path_chunk != NULL) { if (msr->txcfg->debuglog_level >= 4) { msr_log(msr, 4, "Signing data [%s]", path_chunk+1); } if(msr->txcfg->crypto_key_add == HASH_KEYONLY) hash_value = hmac(msr, msr->txcfg->crypto_key, msr->txcfg->crypto_key_len, (unsigned char *) path_chunk+1, strlen((char*)path_chunk)-1); if(msr->txcfg->crypto_key_add == HASH_SESSIONID) { if(msr->sessionid == NULL || strlen(msr->sessionid) == 0) { #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->r->connection->client_ip); #else const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->r->connection->remote_ip); #endif if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "Session id is empty. Using REMOTE_IP"); msr->txcfg->crypto_key_len = strlen(new_pwd); hash_value = hmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) path_chunk+1, strlen((char*)path_chunk)-1); } else { const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->sessionid); if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "Using session id [%s]", msr->sessionid); msr->txcfg->crypto_key_len = strlen(new_pwd); hash_value = hmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) path_chunk+1, strlen((char*)path_chunk)-1); } } if(msr->txcfg->crypto_key_add == HASH_REMOTEIP) { #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->r->connection->client_ip); #else const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->r->connection->remote_ip); #endif msr->txcfg->crypto_key_len = strlen(new_pwd); hash_value = hmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) path_chunk+1, strlen((char*)path_chunk)-1); } } else { return NULL; } } else if(strlen(link) > 8 && strncmp("https",(char*)link,5)==0){ path_chunk = strchr(link+8,'/'); if(path_chunk != NULL) { if (msr->txcfg->debuglog_level >= 4) { msr_log(msr, 4, "Signing data [%s]", path_chunk+1); } if(msr->txcfg->crypto_key_add == HASH_KEYONLY) hash_value = hmac(msr, msr->txcfg->crypto_key, msr->txcfg->crypto_key_len, (unsigned char *) path_chunk+1, strlen((char*)path_chunk)-1); if(msr->txcfg->crypto_key_add == HASH_SESSIONID) { if(msr->sessionid == NULL || strlen(msr->sessionid) == 0) { #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->r->connection->client_ip); #else const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->r->connection->remote_ip); #endif if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "Session id is empty. Using REMOTE_IP"); msr->txcfg->crypto_key_len = strlen(new_pwd); hash_value = hmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) path_chunk+1, strlen((char*)path_chunk)-1); } else { const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->sessionid); if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "Using session id [%s]", msr->sessionid); msr->txcfg->crypto_key_len = strlen(new_pwd); hash_value = hmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) path_chunk+1, strlen((char*)path_chunk)-1); } } if(msr->txcfg->crypto_key_add == HASH_REMOTEIP) { #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->r->connection->client_ip); #else const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->r->connection->remote_ip); #endif msr->txcfg->crypto_key_len = strlen(new_pwd); hash_value = hmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) path_chunk+1, strlen((char*)path_chunk)-1); } } else { return NULL; } } else if(*link=='/'){ if (msr->txcfg->debuglog_level >= 4) { msr_log(msr, 4, "Signing data [%s]", link+1); } if(msr->txcfg->crypto_key_add == HASH_KEYONLY) hash_value = hmac(msr, msr->txcfg->crypto_key, msr->txcfg->crypto_key_len, (unsigned char *) link+1, strlen((char*)link)-1); if(msr->txcfg->crypto_key_add == HASH_SESSIONID) { if(msr->sessionid == NULL || strlen(msr->sessionid) == 0) { #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->r->connection->client_ip); #else const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->r->connection->remote_ip); #endif if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "Session id is empty. Using REMOTE_IP"); msr->txcfg->crypto_key_len = strlen(new_pwd); hash_value = hmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) link+1, strlen((char*)link)-1); } else { const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->sessionid); if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "Using session id [%s]", msr->sessionid); msr->txcfg->crypto_key_len = strlen(new_pwd); hash_value = hmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) link+1, strlen((char*)link)-1); } } if(msr->txcfg->crypto_key_add == HASH_REMOTEIP) { #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->r->connection->client_ip); #else const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->r->connection->remote_ip); #endif msr->txcfg->crypto_key_len = strlen(new_pwd); hash_value = hmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) link+1, strlen((char*)link)-1); } } else { char *relative_link = NULL; char *filename = NULL; char *relative_path = NULL; char *relative_uri = NULL; filename = file_basename(msr->mp, msr->r->parsed_uri.path); if(filename == NULL || (strlen(msr->r->parsed_uri.path) - strlen(filename) < 0)) return NULL; relative_path = apr_pstrndup(msr->mp, msr->r->parsed_uri.path, strlen(msr->r->parsed_uri.path) - strlen(filename)); relative_uri = apr_pstrcat(msr->mp, relative_path, link, NULL); relative_link = relative_uri+1; if (msr->txcfg->debuglog_level >= 4) { msr_log(msr, 4, "Signing data [%s] size %zu", relative_link, strlen(relative_link)); } if(msr->txcfg->crypto_key_add == HASH_KEYONLY) hash_value = hmac(msr, msr->txcfg->crypto_key, msr->txcfg->crypto_key_len, (unsigned char *) relative_link, strlen((char*)relative_link)); if(msr->txcfg->crypto_key_add == HASH_SESSIONID) { if(msr->sessionid == NULL || strlen(msr->sessionid) == 0) { #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->r->connection->client_ip); #else const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->r->connection->remote_ip); #endif if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "Session id is empty. Using REMOTE_IP"); msr->txcfg->crypto_key_len = strlen(new_pwd); hash_value = hmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) relative_link, strlen((char*)relative_link)); } else { const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->sessionid); if (msr->txcfg->debuglog_level >= 4) msr_log(msr, 4, "Using session id [%s]", msr->sessionid); msr->txcfg->crypto_key_len = strlen(new_pwd); hash_value = hmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) relative_link, strlen((char*)relative_link)); } } if(msr->txcfg->crypto_key_add == HASH_REMOTEIP) { #if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER > 2 const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->r->connection->client_ip); #else const char *new_pwd = apr_psprintf(msr->mp,"%s%s", msr->txcfg->crypto_key, msr->r->connection->remote_ip); #endif msr->txcfg->crypto_key_len = strlen(new_pwd); hash_value = hmac(msr, new_pwd, msr->txcfg->crypto_key_len, (unsigned char *) relative_link, strlen((char*)relative_link)); } link = relative_uri; } if(hash_value == NULL) return NULL; if(type == HASH_ONLY) return hash_value; qm = strchr((char*)link,'?'); if(qm == NULL){ mac_link= (char*)apr_psprintf(msr->mp, "%s?%s=%s", link, msr->txcfg->crypto_param_name, (char *)hash_value); } else{ mac_link= (char*)apr_psprintf(msr->mp, "%s&%s=%s", link, msr->txcfg->crypto_param_name, (char*)hash_value); } return mac_link; } /** * \brief Modify Location in case of status 302 and 301 * * \param msr ModSecurity transaction resource * * \retval 1 On Success * \retval 0 on fail */ int modify_response_header(modsec_rec *msr) { char *mac_link = NULL; const char *location = NULL; int rc = 0; if(msr == NULL) return 0; if (msr->txcfg->debuglog_level >= 9) msr_log(msr, 4, "HTTP status (%d)", msr->response_status); if(msr->response_status != HTTP_MOVED_TEMPORARILY && msr->response_status != HTTP_MOVED_PERMANENTLY) { if (msr->txcfg->debuglog_level >= 9) msr_log(msr, 4, "Skipping status other than 302 an 301"); return 0; } location = apr_table_get(msr->r->headers_out, "Location"); if(location == NULL || strlen(location) == 0) return 0; if (msr->txcfg->debuglog_level >= 9) msr_log(msr, 4, "Processing reponse header location [%s]", location); if(msr->txcfg->crypto_hash_location_rx == 1) { rc = do_hash_method(msr, (char *)location, HASH_URL_LOCATION_HASH_RX); if(rc > 0) { mac_link = NULL; mac_link = do_hash_link(msr, (char *)location, FULL_LINK); } else { return 0; } } else if(msr->txcfg->crypto_hash_location_pm == 1) { rc = do_hash_method(msr, (char *)location, HASH_URL_LOCATION_HASH_PM); if(rc > 0) { mac_link = NULL; mac_link = do_hash_link(msr, (char *)location, FULL_LINK); } else { return 0; } } if(mac_link == NULL) return 0; if (msr->txcfg->debuglog_level >= 9) msr_log(msr, 4, "Setting new reponse header location [%s]", mac_link); if(rc > 0) { apr_table_unset(msr->r->headers_out,"Location"); apr_table_set(msr->r->headers_out, "Location",(char*)apr_psprintf(msr->mp,"%s", mac_link)); } return 1; }