Fixed code according to Ivan's review.

This commit is contained in:
brectanus 2008-02-20 00:41:43 +00:00
parent bdc746baff
commit 7a1e2db148
9 changed files with 210 additions and 88 deletions

View File

@ -9,7 +9,17 @@
* *
*/ */
#include "acmp.h" #include "acmp.h"
#ifdef ACMP_USE_UTF8
/* UTF support */
#include "utf8tables.h" #include "utf8tables.h"
#else
/* No UTF support */
#define acmp_utf8_char_t long
#include <apr_lib.h>
#define utf8_lcase(a) apr_tolower(a)
#endif
#include <apr_tables.h> #include <apr_tables.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@ -58,7 +68,9 @@ struct acmp_btree_node_t {
* Data related to parser, not to individual nodes * Data related to parser, not to individual nodes
*/ */
struct ACMP { struct ACMP {
#ifdef ACMP_USE_UTF8
int is_utf8; int is_utf8;
#endif
int is_case_sensitive; int is_case_sensitive;
apr_pool_t *parent_pool; apr_pool_t *parent_pool;
apr_pool_t *pool; apr_pool_t *pool;
@ -92,6 +104,7 @@ struct ACMP {
* Functions for UTF-8 support * Functions for UTF-8 support
*/ */
#ifdef ACMP_USE_UTF8
/** /**
* Returns length of utf-8 sequence based on its first byte * Returns length of utf-8 sequence based on its first byte
*/ */
@ -152,6 +165,7 @@ static long utf8_lcase(acmp_utf8_char_t ucs_code) {
} }
return ucs_code; return ucs_code;
} }
#endif
/* /*
******************************************************************************* *******************************************************************************
@ -163,7 +177,11 @@ static long utf8_lcase(acmp_utf8_char_t ucs_code) {
* Returns length of given string for parser's encoding * Returns length of given string for parser's encoding
*/ */
static size_t acmp_strlen(ACMP *parser, const char *str) { static size_t acmp_strlen(ACMP *parser, const char *str) {
#ifdef ACMP_USE_UTF8
return (parser->is_utf8 == 0) ? strlen(str) : utf8_strlen(str); return (parser->is_utf8 == 0) ? strlen(str) : utf8_strlen(str);
#else
return strlen(str);
#endif
} }
/** /**
@ -176,15 +194,18 @@ static void acmp_strtoucs(ACMP *parser, const char *str, acmp_utf8_char_t *ucs_c
int i; int i;
const char *c = str; const char *c = str;
if (parser->is_utf8 == 0) { #ifdef ACMP_USE_UTF8
for (i = 0; i < len; i++) { if (parser->is_utf8) {
*(ucs_chars++) = *(c++);
}
} else {
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
*(ucs_chars++) = utf8_decodechar(c); *(ucs_chars++) = utf8_decodechar(c);
c += utf8_seq_len(c); c += utf8_seq_len(c);
} }
} else
#endif
{
for (i = 0; i < len; i++) {
*(ucs_chars++) = *(c++);
}
} }
} }
@ -484,7 +505,9 @@ ACMP *acmp_create(int flags, apr_pool_t *pool) {
/* ENH: Check alloc succeded */ /* ENH: Check alloc succeded */
parser->pool = p; parser->pool = p;
parser->parent_pool = pool; parser->parent_pool = pool;
#ifdef ACMP_USE_UTF8
parser->is_utf8 = (flags & ACMP_FLAG_UTF8) == 0 ? 0 : 1; parser->is_utf8 = (flags & ACMP_FLAG_UTF8) == 0 ? 0 : 1;
#endif
parser->is_case_sensitive = (flags & ACMP_FLAG_CASE_SENSITIVE) == 0 ? 0 : 1; parser->is_case_sensitive = (flags & ACMP_FLAG_CASE_SENSITIVE) == 0 ? 0 : 1;
parser->root_node = apr_pcalloc(p, sizeof(acmp_node_t)); parser->root_node = apr_pcalloc(p, sizeof(acmp_node_t));
/* ENH: Check alloc succeded */ /* ENH: Check alloc succeded */
@ -520,7 +543,9 @@ ACMP *acmp_duplicate(ACMP *parser, apr_pool_t *pool) {
/* ENH: Check alloc succeded */ /* ENH: Check alloc succeded */
new_parser->pool = p; new_parser->pool = p;
new_parser->parent_pool = pool; new_parser->parent_pool = pool;
#ifdef ACMP_USE_UTF8
new_parser->is_utf8 = parser->is_utf8; new_parser->is_utf8 = parser->is_utf8;
#endif
new_parser->is_case_sensitive = parser->is_case_sensitive; new_parser->is_case_sensitive = parser->is_case_sensitive;
new_parser->root_node = apr_pcalloc(p, sizeof(acmp_node_t)); new_parser->root_node = apr_pcalloc(p, sizeof(acmp_node_t));
/* ENH: Check alloc succeded */ /* ENH: Check alloc succeded */
@ -618,7 +643,9 @@ apr_status_t acmp_add_pattern(ACMP *parser, const char *pattern,
*/ */
apr_status_t acmp_process(ACMP *parser, const char *data, apr_size_t len) { apr_status_t acmp_process(ACMP *parser, const char *data, apr_size_t len) {
acmp_node_t *node, *go_to; acmp_node_t *node, *go_to;
#ifdef ACMP_USE_UTF8
apr_size_t seq_length; apr_size_t seq_length;
#endif
const char *end; const char *end;
if (parser->is_failtree_done == 0) acmp_prepare(parser); if (parser->is_failtree_done == 0) acmp_prepare(parser);
@ -630,6 +657,7 @@ apr_status_t acmp_process(ACMP *parser, const char *data, apr_size_t len) {
acmp_utf8_char_t letter; acmp_utf8_char_t letter;
parser->bp_buffer[parser->char_pos % parser->bp_buff_len] = parser->byte_pos; parser->bp_buffer[parser->char_pos % parser->bp_buff_len] = parser->byte_pos;
#ifdef ACMP_USE_UTF8
if (parser->is_utf8) { if (parser->is_utf8) {
if (parser->u8buff_len > 0) { if (parser->u8buff_len > 0) {
/* Resuming partial utf-8 sequence */ /* Resuming partial utf-8 sequence */
@ -657,7 +685,9 @@ apr_status_t acmp_process(ACMP *parser, const char *data, apr_size_t len) {
parser->char_pos++; parser->char_pos++;
} }
} }
} else { } else
#endif
{
letter = *data++; letter = *data++;
parser->byte_pos++; parser->byte_pos++;
parser->char_pos++; parser->char_pos++;

View File

@ -15,9 +15,11 @@
#include <apr_pools.h> #include <apr_pools.h>
#define ACMP_FLAG_BYTE 0 #define ACMP_FLAG_BYTE 0
#define ACMP_FLAG_UTF8 0x100
#define ACMP_FLAG_CASE_SENSITIVE 1 #define ACMP_FLAG_CASE_SENSITIVE 1
#define ACMP_FLAG_CASE_INSENSITIVE 0 #define ACMP_FLAG_CASE_INSENSITIVE 0
#ifdef ACMP_USE_UTF8
#define ACMP_FLAG_UTF8 0x100
#endif
/** /**
* Opaque struct with parser data * Opaque struct with parser data

View File

@ -348,7 +348,7 @@ static modsec_rec *create_tx_context(request_rec *r) {
/* Invoke the engine to continue with initialisation */ /* Invoke the engine to continue with initialisation */
if (modsecurity_tx_init(msr) < 0) { if (modsecurity_tx_init(msr) < 0) {
msr_log(msr, 1, "Failed to initialising transaction (txid %s).", msr->txid); msr_log(msr, 1, "Failed to initialise transaction (txid %s).", msr->txid);
return NULL; return NULL;
} }

View File

@ -300,34 +300,35 @@ int geo_lookup(modsec_rec *msr, geo_rec *georec, const char *target, char **erro
georec->dma_code = 0; georec->dma_code = 0;
georec->area_code = 0; georec->area_code = 0;
msr_log(msr, 9, "GEO: Looking up \"%s\".", target); if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "GEO: Looking up \"%s\".", log_escape(msr->mp, target));
}
/* NOTE: This only works with ipv4 */ /* NOTE: This only works with ipv4 */
if ((rc = apr_sockaddr_info_get(&addr, target, APR_INET, 0, 0, msr->mp)) != APR_SUCCESS) { if ((rc = apr_sockaddr_info_get(&addr, target, APR_INET, 0, 0, msr->mp)) != APR_SUCCESS) {
*error_msg = apr_psprintf(msr->mp, "Geo lookup of \"%s\" failed: %s", target, apr_strerror(rc, errstr, 1024)); *error_msg = apr_psprintf(msr->mp, "Geo lookup of \"%s\" failed: %s", log_escape(msr->mp, target), apr_strerror(rc, errstr, 1024));
return 0; return 0;
} }
if ((rc = apr_sockaddr_ip_get(&targetip, addr)) != APR_SUCCESS) { if ((rc = apr_sockaddr_ip_get(&targetip, addr)) != APR_SUCCESS) {
*error_msg = apr_psprintf(msr->mp, "Geo lookup of \"%s\" failed: %s", target, apr_strerror(rc, errstr, 1024)); *error_msg = apr_psprintf(msr->mp, "Geo lookup of \"%s\" failed: %s", log_escape(msr->mp, target), apr_strerror(rc, errstr, 1024));
return 0; return 0;
}; };
/* Why is this in host byte order? */ /* Why is this in host byte order? */
ipnum = ntohl(addr->sa.sin.sin_addr.s_addr); ipnum = ntohl(addr->sa.sin.sin_addr.s_addr);
msr_log(msr, 9, "GEO: Using address \"%s\" (0x%08lx).", targetip, ipnum); if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "GEO: Using address \"%s\" (0x%08lx).", targetip, ipnum);
}
for (level = 31; level >= 0; level--) { for (level = 31; level >= 0; level--) {
/* Read the record */ /* Read the record */
seekto = 2 * reclen * rec_val; seekto = 2 * reclen * rec_val;
apr_file_seek(geo->db, APR_SET, &seekto); apr_file_seek(geo->db, APR_SET, &seekto);
/* TODO: check rc */ /* TODO: check rc */
rc = apr_file_read_full(geo->db, &buf, (2 * reclen), &nbytes); rc = apr_file_read_full(geo->db, &buf, (2 * reclen), &nbytes);
/* NOTE: This is hard-coded for size 3 records */ /* NOTE: This is hard-coded for size 3 records */
/* Left */ /* Left */
if ((ipnum & (1 << level)) == 0) { if ((ipnum & (1 << level)) == 0) {
@ -352,7 +353,7 @@ int geo_lookup(modsec_rec *msr, geo_rec *georec, const char *target, char **erro
country = rec_val; country = rec_val;
country -= geo->ctry_offset; country -= geo->ctry_offset;
if (country <= 0) { if (country <= 0) {
*error_msg = apr_psprintf(msr->mp, "No geo data for \"%s\".", target); *error_msg = apr_psprintf(msr->mp, "No geo data for \"%s\".", log_escape(msr->mp, target));
return 0; return 0;
} }
@ -375,13 +376,17 @@ int geo_lookup(modsec_rec *msr, geo_rec *georec, const char *target, char **erro
country = cbuf[0]; country = cbuf[0];
if (country <= 0) { if (country <= 0) {
*error_msg = apr_psprintf(msr->mp, "No geo data for \"%s\".", target); *error_msg = apr_psprintf(msr->mp, "No geo data for \"%s\".", log_escape(msr->mp, target));
return 0; return 0;
} }
msr_log(msr, 9, "GEO: rec=\"%s\"", log_escape_raw(msr->mp, cbuf, sizeof(cbuf))); if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "GEO: rec=\"%s\"", log_escape_raw(msr->mp, cbuf, sizeof(cbuf)));
}
/* Country */ /* Country */
msr_log(msr, 9, "GEO: country=\"%.*s\"", (1*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))); if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "GEO: country=\"%.*s\"", (1*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf)));
}
georec->country_code = geo_country_code[country]; georec->country_code = geo_country_code[country];
georec->country_code3 = geo_country_code3[country]; georec->country_code3 = geo_country_code3[country];
georec->country_name = geo_country_name[country]; georec->country_name = geo_country_name[country];
@ -391,27 +396,35 @@ int geo_lookup(modsec_rec *msr, geo_rec *georec, const char *target, char **erro
/* Region */ /* Region */
field_len = field_length((const char *)cbuf+rec_offset, remaining); field_len = field_length((const char *)cbuf+rec_offset, remaining);
msr_log(msr, 9, "GEO: region=\"%.*s\"", ((field_len+1)*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4)); if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "GEO: region=\"%.*s\"", ((field_len+1)*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4));
}
georec->region = apr_pstrmemdup(msr->mp, (const char *)cbuf+rec_offset, (remaining)); georec->region = apr_pstrmemdup(msr->mp, (const char *)cbuf+rec_offset, (remaining));
rec_offset += field_len + 1; rec_offset += field_len + 1;
remaining -= field_len + 1; remaining -= field_len + 1;
/* City */ /* City */
field_len = field_length((const char *)cbuf+rec_offset, remaining); field_len = field_length((const char *)cbuf+rec_offset, remaining);
msr_log(msr, 9, "GEO: city=\"%.*s\"", ((field_len+1)*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4)); if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "GEO: city=\"%.*s\"", ((field_len+1)*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4));
}
georec->city = apr_pstrmemdup(msr->mp, (const char *)cbuf+rec_offset, (remaining)); georec->city = apr_pstrmemdup(msr->mp, (const char *)cbuf+rec_offset, (remaining));
rec_offset += field_len + 1; rec_offset += field_len + 1;
remaining -= field_len + 1; remaining -= field_len + 1;
/* Postal Code */ /* Postal Code */
field_len = field_length((const char *)cbuf+rec_offset, remaining); field_len = field_length((const char *)cbuf+rec_offset, remaining);
msr_log(msr, 9, "GEO: postal_code=\"%.*s\"", ((field_len+1)*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4)); if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "GEO: postal_code=\"%.*s\"", ((field_len+1)*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4));
}
georec->postal_code = apr_pstrmemdup(msr->mp, (const char *)cbuf+rec_offset, (remaining)); georec->postal_code = apr_pstrmemdup(msr->mp, (const char *)cbuf+rec_offset, (remaining));
rec_offset += field_len + 1; rec_offset += field_len + 1;
remaining -= field_len + 1; remaining -= field_len + 1;
/* Latitude */ /* Latitude */
msr_log(msr, 9, "GEO: latitude=\"%.*s\"", (3*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4)); if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "GEO: latitude=\"%.*s\"", (3*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4));
}
dtmp = cbuf[rec_offset] + dtmp = cbuf[rec_offset] +
(cbuf[rec_offset+1] << 8) + (cbuf[rec_offset+1] << 8) +
(cbuf[rec_offset+2] << 16); (cbuf[rec_offset+2] << 16);
@ -421,7 +434,9 @@ int geo_lookup(modsec_rec *msr, geo_rec *georec, const char *target, char **erro
/* Longitude */ /* Longitude */
msr_log(msr, 9, "GEO: longitude=\"%.*s\"", (3*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4)); if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "GEO: longitude=\"%.*s\"", (3*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4));
}
dtmp = cbuf[rec_offset] + dtmp = cbuf[rec_offset] +
(cbuf[rec_offset+1] << 8) + (cbuf[rec_offset+1] << 8) +
(cbuf[rec_offset+2] << 16); (cbuf[rec_offset+2] << 16);
@ -430,7 +445,9 @@ int geo_lookup(modsec_rec *msr, geo_rec *georec, const char *target, char **erro
remaining -= 3; remaining -= 3;
/* dma/area codes are in city rev1 and US only */ /* dma/area codes are in city rev1 and US only */
msr_log(msr, 9, "GEO: dma/area=\"%.*s\"", (3*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4)); if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "GEO: dma/area=\"%.*s\"", (3*4), log_escape_raw(msr->mp, cbuf, sizeof(cbuf))+(rec_offset*4));
}
if (geo->dbtype == GEO_CITY_DATABASE_1 if (geo->dbtype == GEO_CITY_DATABASE_1
&& georec->country_code[0] == 'U' && georec->country_code[0] == 'U'
&& georec->country_code[1] == 'S') && georec->country_code[1] == 'S')
@ -447,7 +464,7 @@ int geo_lookup(modsec_rec *msr, geo_rec *georec, const char *target, char **erro
} }
*error_msg = apr_psprintf(msr->mp, "Geo lookup of \"%s\" succeeded.", target); *error_msg = apr_psprintf(msr->mp, "Geo lookup of \"%s\" succeeded.", log_escape(msr->mp, target));
return 1; return 1;
} }

View File

@ -1325,7 +1325,6 @@ char *msre_format_metadata(modsec_rec *msr, msre_actionset *actionset) {
log_escape_ex(msr->mp, var->value, var->value_len)); log_escape_ex(msr->mp, var->value, var->value_len));
} }
if (actionset->logdata != NULL) { if (actionset->logdata != NULL) {
//TODO: restrict to 512 bytes
/* Expand variables in the message string. */ /* Expand variables in the message string. */
msc_string *var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string)); msc_string *var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
var->value = (char *)actionset->logdata; var->value = (char *)actionset->logdata;
@ -1334,6 +1333,18 @@ char *msre_format_metadata(modsec_rec *msr, msre_actionset *actionset) {
logdata = apr_psprintf(msr->mp, " [data \"%s\"]", logdata = apr_psprintf(msr->mp, " [data \"%s\"]",
log_escape_hex(msr->mp, (unsigned char *)var->value, var->value_len)); log_escape_hex(msr->mp, (unsigned char *)var->value, var->value_len));
/* If it is > 512 bytes, then truncate at 512 with ellipsis.
* NOTE: 512 actual data + 9 bytes of label = 521
*/
if (strlen(logdata) > 521) {
logdata[517] = '.';
logdata[518] = '.';
logdata[519] = '.';
logdata[520] = '"';
logdata[521] = ']';
logdata[522] = '\0';
}
} }
if ((actionset->severity >= 0)&&(actionset->severity <= 7)) { if ((actionset->severity >= 0)&&(actionset->severity <= 7)) {
severity = apr_psprintf(msr->mp, " [severity \"%s\"]", severity = apr_psprintf(msr->mp, " [severity \"%s\"]",
@ -1835,18 +1846,24 @@ static apr_status_t msre_rule_process_normal(msre_rule *rule, modsec_rec *msr) {
/* check the cache options */ /* check the cache options */
if (var->value_len < msr->txcfg->cache_trans_min) { if (var->value_len < msr->txcfg->cache_trans_min) {
msr_log(msr, 9, "CACHE: Disabled - %s value length=%u, smaller than minlen=%" APR_SIZE_T_FMT, var->name, var->value_len, msr->txcfg->cache_trans_min); if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "CACHE: Disabled - %s value length=%u, smaller than minlen=%" APR_SIZE_T_FMT, var->name, var->value_len, msr->txcfg->cache_trans_min);
}
usecache = 0; usecache = 0;
} }
if ((msr->txcfg->cache_trans_max != 0) && (var->value_len > msr->txcfg->cache_trans_max)) { if ((msr->txcfg->cache_trans_max != 0) && (var->value_len > msr->txcfg->cache_trans_max)) {
msr_log(msr, 9, "CACHE: Disabled - %s value length=%u, larger than maxlen=%" APR_SIZE_T_FMT, var->name, var->value_len, msr->txcfg->cache_trans_max); if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "CACHE: Disabled - %s value length=%u, larger than maxlen=%" APR_SIZE_T_FMT, var->name, var->value_len, msr->txcfg->cache_trans_max);
}
usecache = 0; usecache = 0;
} }
/* if cache is still enabled, check the VAR for cacheablity */ /* if cache is still enabled, check the VAR for cacheablity */
if (usecache) { if (usecache) {
if (var->metadata->is_cacheable == VAR_CACHE) { if (var->metadata->is_cacheable == VAR_CACHE) {
msr_log(msr, 9, "CACHE: Enabled"); if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "CACHE: Enabled");
}
/* Fetch cache table for this target */ /* Fetch cache table for this target */
carr = (apr_table_t **)apr_hash_get(msr->tcache, var->name, APR_HASH_KEY_STRING); carr = (apr_table_t **)apr_hash_get(msr->tcache, var->name, APR_HASH_KEY_STRING);
@ -1868,7 +1885,9 @@ static apr_status_t msre_rule_process_normal(msre_rule *rule, modsec_rec *msr) {
} }
else { else {
usecache = 0; usecache = 0;
msr_log(msr, 9, "CACHE: %s transformations are not cacheable", var->name); if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "CACHE: %s transformations are not cacheable", var->name);
}
} }
} }
} }
@ -1945,7 +1964,9 @@ static apr_status_t msre_rule_process_normal(msre_rule *rule, modsec_rec *msr) {
var->value_len = crec->val_len; var->value_len = crec->val_len;
} }
msr_log(msr, 9, "T (%d) %s: \"%s\" [cached hits=%d]", crec->changed, crec->path, log_escape_nq_ex(mptmp, var->value, var->value_len), crec->hits); if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "T (%d) %s: \"%s\" [cached hits=%d]", crec->changed, crec->path, log_escape_nq_ex(mptmp, var->value, var->value_len), crec->hits);
}
#if !defined(PERFORMANCE_MEASUREMENT) #if !defined(PERFORMANCE_MEASUREMENT)
if (msr->txcfg->debuglog_level >= 4) if (msr->txcfg->debuglog_level >= 4)
@ -2079,7 +2100,9 @@ static apr_status_t msre_rule_process_normal(msre_rule *rule, modsec_rec *msr) {
var->value_len = crec->val_len; var->value_len = crec->val_len;
} }
msr_log(msr, 9, "T (%d) %s: \"%s\" [cached hits=%d]", crec->changed, metadata->name, log_escape_nq_ex(mptmp, var->value, var->value_len), crec->hits); if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "T (%d) %s: \"%s\" [cached hits=%d]", crec->changed, metadata->name, log_escape_nq_ex(mptmp, var->value, var->value_len), crec->hits);
}
continue; continue;
} }
} }
@ -2183,10 +2206,14 @@ static apr_status_t msre_rule_process_normal(msre_rule *rule, modsec_rec *msr) {
cn++; cn++;
rec = (msre_cache_rec *)ctelts[ri].val; rec = (msre_cache_rec *)ctelts[ri].val;
if (rec->changed) { if (rec->changed) {
msr_log(msr, 9, "CACHE: %5d) phase=%d hits=%d %x;%s=\"%s\"", cn, msr->phase, rec->hits, rec->num, rec->path, log_escape_nq_ex(mptmp, rec->val, rec->val_len)); if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "CACHE: %5d) phase=%d hits=%d %x;%s=\"%s\"", cn, msr->phase, rec->hits, rec->num, rec->path, log_escape_nq_ex(mptmp, rec->val, rec->val_len));
}
} }
else { else {
msr_log(msr, 9, "CACHE: %5d) phase=%d hits=%d %x;%s=<no change>", cn, msr->phase, rec->hits, rec->num, rec->path); if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "CACHE: %5d) phase=%d hits=%d %x;%s=<no change>", cn, msr->phase, rec->hits, rec->num, rec->path);
}
} }
} }
} }

View File

@ -69,7 +69,7 @@ msre_var *generate_single_var(modsec_rec *msr, msre_var *var, apr_array_header_t
return rvar; return rvar;
} }
/* Copy the value so that we can transform it in piece. */ /* Copy the value so that we can transform it in place. */
rvar->value = apr_pstrndup(mptmp, rvar->value, rvar->value_len); rvar->value = apr_pstrndup(mptmp, rvar->value, rvar->value_len);
/* Transform rvar in a loop. */ /* Transform rvar in a loop. */
@ -127,7 +127,7 @@ apr_table_t *generate_multi_var(modsec_rec *msr, msre_var *var, apr_array_header
for (j = 0; j < tarr->nelts; j++) { for (j = 0; j < tarr->nelts; j++) {
rvar = (msre_var *)telts[j].val; rvar = (msre_var *)telts[j].val;
/* Copy the value so that we can transform it in piece. */ /* Copy the value so that we can transform it in place. */
rvar->value = apr_pstrndup(mptmp, rvar->value, rvar->value_len); rvar->value = apr_pstrndup(mptmp, rvar->value, rvar->value_len);
/* Transform rvar in a loop. */ /* Transform rvar in a loop. */
@ -230,11 +230,13 @@ int expand_macros(modsec_rec *msr, msc_string *var, msre_rule *rule, apr_pool_t
part->value_len = var_generated->value_len; part->value_len = var_generated->value_len;
part->value = (char *)var_generated->value; part->value = (char *)var_generated->value;
*(msc_string **)apr_array_push(arr) = part; *(msc_string **)apr_array_push(arr) = part;
msr_log(msr, 9, "Resolved macro %%{%s%s%s} to \"%s\"", if (msr->txcfg->debuglog_level >= 9) {
var_name, msr_log(msr, 9, "Resolved macro %%{%s%s%s} to \"%s\"",
(var_value ? "." : ""), var_name,
(var_value ? var_value : ""), (var_value ? "." : ""),
log_escape_ex(mptmp, part->value, part->value_len)); (var_value ? var_value : ""),
log_escape_ex(mptmp, part->value, part->value_len));
}
} }
} else { } else {
msr_log(msr, 4, "Failed to resolve macro %%{%s%s%s}: %s", msr_log(msr, 4, "Failed to resolve macro %%{%s%s%s}: %s",
@ -1348,8 +1350,10 @@ static apr_status_t msre_action_deprecatevar_execute(modsec_rec *msr, apr_pool_t
/* Find the current value. */ /* Find the current value. */
var = (msc_string *)apr_table_get(target_col, var_name); var = (msc_string *)apr_table_get(target_col, var_name);
if (var == NULL) { if (var == NULL) {
msr_log(msr, 9, "Asked to deprecate variable \"%s.%s\", but it does not exist.", if (msr->txcfg->debuglog_level >= 9) {
log_escape(msr->mp, col_name), log_escape(msr->mp, var_name)); msr_log(msr, 9, "Asked to deprecate variable \"%s.%s\", but it does not exist.",
log_escape(msr->mp, col_name), log_escape(msr->mp, var_name));
}
return 0; return 0;
} }
current_value = atoi(var->value); current_value = atoi(var->value);
@ -1393,10 +1397,12 @@ static apr_status_t msre_action_deprecatevar_execute(modsec_rec *msr, apr_pool_t
apr_table_set(msr->collections_dirty, col_name, "1"); apr_table_set(msr->collections_dirty, col_name, "1");
} else { } else {
msr_log(msr, 9, "Not deprecating variable \"%s.%s\" because the new value (%ld) is " if (msr->txcfg->debuglog_level >= 9) {
"the same as the old one (%ld) (%" APR_TIME_T_FMT " seconds since last update).", msr_log(msr, 9, "Not deprecating variable \"%s.%s\" because the new value (%ld) is "
log_escape(msr->mp, col_name), log_escape(msr->mp, var_name), current_value, "the same as the old one (%ld) (%" APR_TIME_T_FMT " seconds since last update).",
new_value, (apr_time_t)(current_time - last_update_time)); log_escape(msr->mp, col_name), log_escape(msr->mp, var_name), current_value,
new_value, (apr_time_t)(current_time - last_update_time));
}
} }
return 1; return 1;

View File

@ -166,11 +166,6 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c
} }
} }
/*
if ( ((rc == PCRE_ERROR_NOMATCH)&&(rule->op_negated == 1))
|| ((rc != PCRE_ERROR_NOMATCH)&&(rule->op_negated == 0)) )
{
*/
if (rc != PCRE_ERROR_NOMATCH) { /* Match. */ if (rc != PCRE_ERROR_NOMATCH) { /* Match. */
/* We no longer escape the pattern here as it is done when logging */ /* We no longer escape the pattern here as it is done when logging */
char *pattern = apr_pstrdup(msr->mp, regex->pattern); char *pattern = apr_pstrdup(msr->mp, regex->pattern);
@ -207,15 +202,14 @@ static int msre_op_pm_param_init(msre_rule *rule, char **error_msg) {
if (p == NULL) return 0; if (p == NULL) return 0;
phrase = apr_pstrdup(rule->ruleset->mp, rule->op_param); phrase = apr_pstrdup(rule->ruleset->mp, rule->op_param);
next = rule->op_param + strlen(rule->op_param);
/* Loop through phrases */ /* Loop through phrases */
/* ENH: Need to allow quoted phrases w/space */ /* ENH: Need to allow quoted phrases w/space */
for (;;) { for (;;) {
while((isspace(*phrase) != 0) && (*phrase != '\0')) phrase++; while((apr_isspace(*phrase) != 0) && (*phrase != '\0')) phrase++;
if (*phrase == '\0') break; if (*phrase == '\0') break;
next = phrase; next = phrase;
while((isspace(*next) == 0) && (*next != 0)) next++; while((apr_isspace(*next) == 0) && (*next != 0)) next++;
acmp_add_pattern(p, phrase, NULL, NULL, next - phrase); acmp_add_pattern(p, phrase, NULL, NULL, next - phrase);
phrase = next; phrase = next;
} }
@ -238,7 +232,7 @@ static int msre_op_pmFromFile_param_init(msre_rule *rule, char **error_msg) {
ACMP *p; ACMP *p;
if ((rule->op_param == NULL)||(strlen(rule->op_param) == 0)) { if ((rule->op_param == NULL)||(strlen(rule->op_param) == 0)) {
*error_msg = apr_psprintf(rule->ruleset->mp, "Missing parameter for operator 'pm'."); *error_msg = apr_psprintf(rule->ruleset->mp, "Missing parameter for operator 'pmFromFile'.");
return 0; /* ERROR */ return 0; /* ERROR */
} }
@ -246,7 +240,6 @@ static int msre_op_pmFromFile_param_init(msre_rule *rule, char **error_msg) {
if (p == NULL) return 0; if (p == NULL) return 0;
fn = apr_pstrdup(rule->ruleset->mp, rule->op_param); fn = apr_pstrdup(rule->ruleset->mp, rule->op_param);
next = fn + strlen(rule->op_param);
/* Get the path of the rule filename to use as a base */ /* Get the path of the rule filename to use as a base */
rulefile_path = apr_pstrndup(rule->ruleset->mp, rule->filename, strlen(rule->filename) - strlen(apr_filepath_name_get(rule->filename))); rulefile_path = apr_pstrndup(rule->ruleset->mp, rule->filename, strlen(rule->filename) - strlen(apr_filepath_name_get(rule->filename)));
@ -263,11 +256,11 @@ static int msre_op_pmFromFile_param_init(msre_rule *rule, char **error_msg) {
int line = 0; int line = 0;
/* Trim whitespace */ /* Trim whitespace */
while((isspace(*fn) != 0) && (*fn != '\0')) fn++; while((apr_isspace(*fn) != 0) && (*fn != '\0')) fn++;
if (*fn == '\0') break; if (*fn == '\0') break;
next = fn; next = fn;
while((isspace(*next) == 0) && (*next != '\0')) next++; while((apr_isspace(*next) == 0) && (*next != '\0')) next++;
while((isspace(*next) != 0) && (*next != '\0')) *(next++) = '\0'; while((apr_isspace(*next) != 0) && (*next != '\0')) *(next++) = '\0';
/* Add path of the rule filename for a relative phrase filename */ /* Add path of the rule filename for a relative phrase filename */
filepath = fn; filepath = fn;
@ -433,7 +426,6 @@ static int msre_op_within_execute(modsec_rec *msr, msre_rule *rule, msre_var *va
/* scan for first character, then compare from there until we /* scan for first character, then compare from there until we
* have a match or there is no room left in the target * have a match or there is no room left in the target
*/ */
msr_log(msr, 9, "match[%u]='%s' target[%u]='%s'", match_length, match, target_length, target);
i_max = match_length - target_length; i_max = match_length - target_length;
for (i = 0; i <= i_max; i++) { for (i = 0; i <= i_max; i++) {
if (match[i] == target[0]) { if (match[i] == target[0]) {
@ -507,8 +499,12 @@ static int msre_op_contains_execute(modsec_rec *msr, msre_rule *rule, msre_var *
*/ */
i_max = target_length - match_length; i_max = target_length - match_length;
for (i = 0; i <= i_max; i++) { for (i = 0; i <= i_max; i++) {
/* First character matched - avoid func call */
if (target[i] == match[0]) { if (target[i] == match[0]) {
if (memcmp((match + 1), (target + i + 1), (match_length - 1)) == 0) { /* See if remaining matches */
if ( (match_length == 1)
|| (memcmp((match + 1), (target + i + 1), (match_length - 1)) == 0))
{
/* Match. */ /* Match. */
*error_msg = apr_psprintf(msr->mp, "String match \"%s\" at %s.", *error_msg = apr_psprintf(msr->mp, "String match \"%s\" at %s.",
log_escape_ex(msr->mp, match, match_length), log_escape_ex(msr->mp, match, match_length),
@ -531,6 +527,7 @@ static int msre_op_containsWord_execute(modsec_rec *msr, msre_rule *rule, msre_v
unsigned int match_length; unsigned int match_length;
unsigned int target_length = 0; unsigned int target_length = 0;
unsigned int i, i_max; unsigned int i, i_max;
int rc = 0;
str->value = (char *)rule->op_param; str->value = (char *)rule->op_param;
str->value_len = strlen(str->value); str->value_len = strlen(str->value);
@ -580,42 +577,36 @@ static int msre_op_containsWord_execute(modsec_rec *msr, msre_rule *rule, msre_v
for (i = 0; i <= i_max; i++) { for (i = 0; i <= i_max; i++) {
/* Previous char must have been a start or non-word */ /* Previous char must have been a start or non-word */
if ((i > 0) && (isalnum(target[i-1])||(target[i-1] == '_'))) if ((i > 0) && (apr_isalnum(target[i-1])||(target[i-1] == '_')))
continue; continue;
/* First character matched - avoid func call */
/* First character matched */
if (target[i] == match[0]) { if (target[i] == match[0]) {
/* See if remaining matches */
/* Maybe a match. */ if ( (match_length == 1)
*error_msg = apr_psprintf(msr->mp, "String match \"%s\" at %s.", || (memcmp((match + 1), (target + i + 1), (match_length - 1)) == 0))
log_escape_ex(msr->mp, match, match_length), {
var->name);
/* only one character */
if (match_length == 1) return 1;
/* remaining matched */
if (memcmp((match + 1), (target + i + 1), (match_length - 1)) == 0) {
/* check boundaries */ /* check boundaries */
if (i == i_max) { if (i == i_max) {
/* exact/end word match */ /* exact/end word match */
return 1; rc = 1;
} }
else if (!(isalnum(target[i+match_length])||(target[i+match_length] == '_'))) { else if (!(apr_isalnum(target[i + match_length])||(target[i + match_length] == '_'))) {
/* start/mid word match */ /* start/mid word match */
return 1; rc = 1;
} }
/* No word match */
*error_msg = NULL;
return 0;
} }
} }
} }
if (rc == 1) {
/* Maybe a match. */
*error_msg = apr_psprintf(msr->mp, "String match \"%s\" at %s.",
log_escape_ex(msr->mp, match, match_length),
var->name);
return 1;
}
/* No match. */ /* No match. */
*error_msg = NULL; *error_msg = NULL;
return 0; return 0;
@ -987,7 +978,7 @@ static int luhn_verify(const char *ccnumber, int len) {
* for both odd and even CC numbers to avoid 2 passes. * for both odd and even CC numbers to avoid 2 passes.
*/ */
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
if (isdigit(ccnumber[i])) { if (apr_isdigit(ccnumber[i])) {
sum[0] += (!odd ? wtable[ccnumber[i] - '0'] : (ccnumber[i] - '0')); sum[0] += (!odd ? wtable[ccnumber[i] - '0'] : (ccnumber[i] - '0'));
sum[1] += (odd ? wtable[ccnumber[i] - '0'] : (ccnumber[i] - '0')); sum[1] += (odd ? wtable[ccnumber[i] - '0'] : (ccnumber[i] - '0'));
odd = 1 - odd; /* alternate weights */ odd = 1 - odd; /* alternate weights */
@ -1160,7 +1151,7 @@ static int msre_op_geoLookup_execute(modsec_rec *msr, msre_rule *rule, msre_var
*error_msg = NULL; *error_msg = NULL;
if (geo == NULL) { if (geo == NULL) {
msr_log(msr, 1, "Geo lookup for \"%s\" attempted without a database. Set SecGeoLookupDB.", log_escape_nq(msr->mp, geo_host)); msr_log(msr, 1, "Geo lookup for \"%s\" attempted without a database. Set SecGeoLookupDB.", log_escape(msr->mp, geo_host));
return 0; return 0;
} }

View File

@ -50,3 +50,24 @@
input => "abcdefghi", input => "abcdefghi",
ret => 0, ret => 0,
}, },
{
type => "op",
name => "contains",
param => "x",
input => "x",
ret => 1,
},
{
type => "op",
name => "contains",
param => "y",
input => "xyz",
ret => 1,
},
{
type => "op",
name => "contains",
param => "hiding",
input => "hidinX<-not quite, but is later on->hiding",
ret => 1,
},

View File

@ -78,3 +78,31 @@
input => "abc\0def ghi", input => "abc\0def ghi",
ret => 1, ret => 1,
}, },
{
type => "op",
name => "containsWord",
param => "x",
input => "x",
ret => 1,
},
{
type => "op",
name => "containsWord",
param => "x",
input => " x ",
ret => 1,
},
{
type => "op",
name => "containsWord",
param => "y",
input => "xyz",
ret => 0,
},
{
type => "op",
name => "containsWord",
param => "hiding",
input => "hidingX<-not on word boundary, but is later on->hiding",
ret => 1,
},