Merge in trunk changes for 2.5.0-dev2.

This commit is contained in:
brectanus
2007-06-21 15:46:22 +00:00
parent 2e3a2da9e1
commit 5a94aede33
56 changed files with 4410 additions and 1849 deletions

View File

@@ -29,6 +29,8 @@ APACHECTL = apachectl
INCLUDES = -I /usr/include/libxml2
DEFS = -DWITH_LIBXML2
#DEFS = -DWITH_LIBXML2 -DDEBUG_CONF
#DEFS = -DWITH_LIBXML2 -DCACHE_DEBUG
#LIBS = -Lmy/lib/dir -lmylib
CFLAGS = -O2 -g -Wuninitialized -Wall -Wmissing-prototypes -Wshadow -Wunused-variable -Wunused-value -Wchar-subscripts -Wsign-compare

View File

@@ -24,7 +24,7 @@ OBJS = mod_security2.obj apache2_config.obj apache2_io.obj apache2_util.obj \
re.obj re_operators.obj re_actions.obj re_tfns.obj re_variables.obj \
msc_logging.obj msc_xml.obj msc_multipart.obj modsecurity.obj msc_parsers.obj \
msc_util.obj msc_pcre.obj persist_dbm.obj msc_reqbody.obj pdf_protect.obj \
msc_geo.obj
msc_geo.obj acmp.obj
all: $(DLL)

711
apache2/acmp.c Normal file
View File

@@ -0,0 +1,711 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Breach Security, Inc. at support@breach.com.
*
*/
#include "acmp.h"
#include "utf8tables.h"
#include <apr_tables.h>
#include <stdio.h>
#include <string.h>
/*
*******************************************************************************
*******************************************************************************
* Data structures for acmp parser
*/
/**
* One node in trie
*/
typedef struct acmp_node_t acmp_node_t;
typedef struct acmp_btree_node_t acmp_btree_node_t;
struct acmp_node_t {
acmp_utf8_char_t letter;
int is_last;
acmp_callback_t callback;
void *callback_data;
int depth;
acmp_node_t *child;
acmp_node_t *sibling;
acmp_node_t *fail;
acmp_node_t *parent;
acmp_node_t *o_match;
acmp_btree_node_t *btree;
apr_size_t hit_count;
char *text;
char *pattern;
};
struct acmp_btree_node_t {
acmp_utf8_char_t letter;
acmp_btree_node_t *left;
acmp_btree_node_t *right;
acmp_node_t *node;
};
/**
* Data related to parser, not to individual nodes
*/
struct ACMP {
int is_utf8;
int is_case_sensitive;
apr_pool_t *parent_pool;
apr_pool_t *pool;
int dict_count;
apr_size_t longest_entry;
acmp_node_t *root_node;
const char *data_start;
const char *data_end;
const char *data_pos;
apr_size_t data_len;
apr_size_t *bp_buffer;
apr_size_t bp_buff_len;
acmp_node_t *active_node;
char u8_buff[6];
apr_size_t u8buff_len;
apr_size_t hit_count;
int is_failtree_done;
int is_active;
apr_size_t byte_pos;
apr_size_t char_pos;
};
/*
*******************************************************************************
*******************************************************************************
* Functions for UTF-8 support
*/
/**
* Returns length of utf-8 sequence based on its first byte
*/
static int utf8_seq_len(const char *first_byte) {
return utf8_seq_lengths[(unsigned int)(unsigned char)first_byte[0]];
}
/**
* Returns length of utf8-encoded text
*/
static size_t utf8_strlen(const char *str) {
int len = 0;
const char *c = str;
while (*c != 0) {
c += utf8_seq_len(c);
len++;
}
return len;
}
/**
* Returns ucs code for given utf-8 sequence
*/
static acmp_utf8_char_t utf8_decodechar(const char *str) {
int len = utf8_seq_len(str);
acmp_utf8_char_t ch = 0;
switch (len) {
case 6: ch += (unsigned char)*str++; ch <<= 6;
case 5: ch += (unsigned char)*str++; ch <<= 6;
case 4: ch += (unsigned char)*str++; ch <<= 6;
case 3: ch += (unsigned char)*str++; ch <<= 6;
case 2: ch += (unsigned char)*str++; ch <<= 6;
case 1: ch += (unsigned char)*str++;
}
ch -= utf8_offsets[len - 1];
return ch;
}
/**
* Returns lowercase for given unicode character. Searches through
* utf8_lcase_map table, if it doesn't find the code assumes
* it doesn't have a lowercase variant and returns code itself.
*/
static long utf8_lcase(acmp_utf8_char_t ucs_code) {
long mid, left, right;
left = 1;
right = UTF8_LCASEMAP_LEN * 2 + 1;
while (left <= right) {
mid = (left + right) >> 1;
mid -= (mid % 2); mid++;
if (ucs_code > utf8_lcase_map[mid])
left = mid + 2;
else if (ucs_code < utf8_lcase_map[mid])
right = mid - 2;
else if (ucs_code == utf8_lcase_map[mid])
return utf8_lcase_map[mid - 1];
}
return ucs_code;
}
/*
*******************************************************************************
*******************************************************************************
* Code for local / static utility functions
*/
/**
* Returns length of given string for parser's encoding
*/
static size_t acmp_strlen(ACMP *parser, const char *str) {
return (parser->is_utf8 == 0) ? strlen(str) : utf8_strlen(str);
}
/**
* Turns string to array of ucs values, depending on parser's encoding
* str - string to convert, doesn't have to be NULL-terminated
* ucs_chars - where to write ucs values
* len - length of input string
*/
static void acmp_strtoucs(ACMP *parser, const char *str, acmp_utf8_char_t *ucs_chars, int len) {
int i;
const char *c = str;
if (parser->is_utf8 == 0) {
for (i = 0; i < len; i++) {
*ucs_chars++ = *c++;
}
} else {
for (i = 0; i < len; i++) {
*ucs_chars++ = utf8_decodechar(c);
c += utf8_seq_len(c);
}
}
}
/**
* Returns node with given letter, or null if not found
*/
static acmp_node_t *acmp_child_for_code(acmp_node_t *parent_node, acmp_utf8_char_t ucs_code) {
acmp_node_t *node = parent_node->child;
if (node == NULL) return NULL;
for (;;) {
if (node->letter == ucs_code) return node;
node = node->sibling;
if (node == NULL) return NULL;
}
}
/**
* Adds node to parent node, if it is not already there
*/
static void acmp_add_node_to_parent(acmp_node_t *parent, acmp_node_t *child) {
child->parent = parent;
if (parent->child == NULL) {
parent->child = child;
return;
}
acmp_node_t *node = parent->child;
for (;;) {
if (node == child) return;
if (node->sibling == NULL) {
node->sibling = child;
return;
}
node = node->sibling;
}
}
/**
* Copies values from one node to another, without child/sibling/fail pointers
* and without state variables.
*/
static void acmp_clone_node_no_state(acmp_node_t *from, acmp_node_t *to) {
memcpy(to, from, sizeof(acmp_node_t));
to->child = NULL;
to->sibling = NULL;
to->fail = NULL;
to->hit_count = 0;
}
/**
* Copies sibling nodes and child node for from given "from" node to "to" node.
* Both nodes must already exist.
*/
static void acmp_copy_nodes_recursive(acmp_node_t *from, acmp_node_t *to, apr_pool_t *pool) {
acmp_node_t *old_node = from->child, *new_node, *nn2;
if (old_node == NULL) return;
nn2 = apr_pcalloc(pool, sizeof(acmp_node_t));
acmp_clone_node_no_state(old_node, nn2);
nn2->parent = to;
to->child = nn2;
acmp_copy_nodes_recursive(from->child, to->child, pool);
for (;;) {
old_node = old_node->sibling;
if (old_node == NULL) break;
new_node = apr_pcalloc(pool, sizeof(acmp_node_t));
acmp_clone_node_no_state(old_node, new_node);
new_node->parent = to;
nn2->sibling = new_node;
nn2 = new_node;
acmp_copy_nodes_recursive(old_node, new_node, pool);
}
}
static inline acmp_node_t *acmp_btree_find(acmp_node_t *node, acmp_utf8_char_t letter) {
acmp_btree_node_t *bnode = node->btree;
for (;;) {
if (bnode == NULL) return NULL;
if (bnode->letter == letter) return bnode->node;
if (bnode->letter > letter) {
bnode = bnode->left;
} else {
bnode = bnode->right;
}
}
}
/**
*
*/
static inline acmp_node_t *acmp_goto(acmp_node_t *node, acmp_utf8_char_t letter) {
//return acmp_child_for_code(node, letter);
return acmp_btree_find(node, letter);
}
/**
* Connects each node with its first fail node that is end of a phrase.
*/
static void acmp_connect_other_matches(ACMP *parser, acmp_node_t *node) {
acmp_node_t *child, *om;
for (child = node->child; child != NULL; child = child->sibling) {
if (child->fail == NULL) continue;
for (om = child->fail; om != parser->root_node; om = om->fail) {
if (om->is_last) {
child->o_match = om;
break;
}
}
}
/* Go recursively through children of this node that have a child node */
for(child = node->child; child != NULL; child = child->sibling) {
if (child->child != NULL) acmp_connect_other_matches(parser, child);
}
}
/**
* Adds leaves to binary tree, working from sorted array of keyword tree nodes
*/
static void acmp_add_btree_leaves(acmp_btree_node_t *node, acmp_node_t *nodes[],
int pos, int lb, int rb, apr_pool_t *pool) {
int left = 0, right = 0;
if ((pos - lb) > 1) {
left = lb + (pos - lb) / 2;
node->left = apr_pcalloc(pool, sizeof(acmp_btree_node_t));
node->left->node = nodes[left];
node->left->letter = nodes[left]->letter;
/* printf("%c ->left %c \n", node->node->letter, node->left->node->letter); */
}
if ((rb - pos) > 1) {
right = pos + (rb - pos) / 2;
node->right = apr_pcalloc(pool, sizeof(acmp_btree_node_t));
node->right->node = nodes[right];
node->right->letter = nodes[right]->letter;
/* printf("%c ->right %c \n", node->node->letter, node->right->node->letter); */
}
if (node->right != NULL) {
acmp_add_btree_leaves(node->right, nodes, right, pos, rb, pool);
}
if (node->left != NULL) {
acmp_add_btree_leaves(node->left, nodes, left, lb, pos, pool);
}
}
/**
* Builds balanced binary tree from children nodes of given node.
*/
static void acmp_build_binary_tree(ACMP *parser, acmp_node_t *node) {
apr_size_t count, i, j;
acmp_node_t *child = node->child;
for (count = 0; child != NULL; child = child->sibling) count++;
acmp_node_t *nodes[count];
child = node->child;
for (i = 0; i < count; i++) {
nodes[i] = child;
child = child->sibling;
};
/* We have array with all children of the node and number of those children
*/
for (i = 0; i < count - 1; i++)
for (j = i + 1; j < count; j++) {
if (nodes[i]->letter < nodes[j]->letter) continue;
acmp_node_t *tmp = nodes[i];
nodes[i] = nodes[j];
nodes[j] = tmp;
}
node->btree = apr_pcalloc(parser->pool, sizeof(acmp_btree_node_t));
apr_size_t pos = count / 2;
node->btree->node = nodes[pos];
node->btree->letter = nodes[pos]->letter;
acmp_add_btree_leaves(node->btree, nodes, pos, -1, count, parser->pool);
for (i = 0; i < count; i++) {
if (nodes[i]->child != NULL) acmp_build_binary_tree(parser, nodes[i]);
}
}
/**
* Constructs fail paths on keyword trie
*/
static apr_status_t acmp_connect_fail_branches(ACMP *parser) {
/* Already connected ? */
if (parser->is_failtree_done != 0) return APR_SUCCESS;
acmp_node_t *child, *node, *goto_node;
apr_array_header_t *arr, *arr2, *tmp;
parser->root_node->text = "";
arr = apr_array_make(parser->pool, 32, sizeof(acmp_node_t *));
arr2 = apr_array_make(parser->pool, 32, sizeof(acmp_node_t *));
parser->root_node->fail = parser->root_node;
/* All first-level children will fail back to root node */
for (child = parser->root_node->child; child != NULL; child = child->sibling) {
child->fail = parser->root_node;
*(acmp_node_t **)apr_array_push(arr) = child;
/* printf("fail direction: *%s* => *%s*\n", child->text, child->fail->text); */
}
for (;;) {
while (apr_is_empty_array(arr) == 0) {
node = *(acmp_node_t **)apr_array_pop(arr);
node->fail = parser->root_node;
if (node->parent != parser->root_node) {
goto_node = acmp_child_for_code(node->parent->fail, node->letter);
node->fail = (goto_node != NULL) ? goto_node : parser->root_node;
}
/* printf("fail direction: *%s* => *%s*\n", node->text, node->fail->text); */
child = node->child;
while (child != NULL) {
*(acmp_node_t **)apr_array_push(arr2) = child;
child = child->sibling;
}
}
if (apr_is_empty_array(arr2) != 0) break;
tmp = arr;
arr = arr2;
arr2 = tmp;
}
acmp_connect_other_matches(parser, parser->root_node);
if (parser->root_node->child != NULL) acmp_build_binary_tree(parser, parser->root_node);
parser->is_failtree_done = 1;
return APR_SUCCESS;
}
/**
* Clears hit count of each node, called from acmp_reset()
*/
static void acmp_clear_hit_count_recursive(acmp_node_t *node) {
for (; node != NULL; node = node->sibling) {
node->hit_count = 0;
if (node->child != NULL) acmp_clear_hit_count_recursive(node->child);
}
}
/**
* Called when a match is found
*/
static void acmp_found(ACMP *parser, acmp_node_t *node) {
if (node->callback) {
node->callback(parser, node->callback_data,
parser->bp_buffer[(parser->char_pos - node->depth - 1) % parser->bp_buff_len],
parser->char_pos - node->depth - 1);
}
/* printf("found: %s at position %d\n", node->pattern, parser->char_pos - node->depth - 1); */
node->hit_count++;
parser->hit_count++;
}
/*
*******************************************************************************
*******************************************************************************
* Code for functions from header file
*/
/**
* flags - OR-ed values of ACMP_FLAG constants
* pool - apr_pool to use as parent pool, can be set to NULL
*/
ACMP *acmp_create(int flags, apr_pool_t *pool) {
apr_status_t rc;
apr_pool_t *p;
rc = apr_pool_create(&p, pool);
if (rc != APR_SUCCESS) return NULL;
ACMP *parser = apr_pcalloc(p, sizeof(ACMP));
parser->pool = p;
parser->parent_pool = pool;
parser->is_utf8 = (flags & ACMP_FLAG_UTF8) == 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));
return parser;
}
/**
* Destroys previously created parser
*/
void acmp_destroy(ACMP *parser) {
/*
* All data is kept in parser's pool (including parser struct itself), so
* destroying the pool will destroy everything
*/
apr_pool_destroy(parser->pool);
}
/**
* Creates parser with same options and same patterns
* parser - ACMP parser to duplicate
* pool - parent pool to use, if left as NULL original parser's parent pool is used
*/
ACMP *acmp_duplicate(ACMP *parser, apr_pool_t *pool) {
apr_status_t rc;
apr_pool_t *p;
if (pool == NULL) pool = parser->parent_pool;
rc = apr_pool_create(&p, pool);
if (rc != APR_SUCCESS) return NULL;
ACMP *new_parser = apr_pcalloc(p, sizeof(ACMP));
new_parser->pool = p;
new_parser->parent_pool = pool;
new_parser->is_utf8 = parser->is_utf8;
new_parser->is_case_sensitive = parser->is_case_sensitive;
new_parser->root_node = apr_pcalloc(p, sizeof(acmp_node_t));
new_parser->dict_count = parser->dict_count;
new_parser->longest_entry = parser->longest_entry;
acmp_copy_nodes_recursive(parser->root_node, new_parser->root_node, new_parser->pool);
acmp_prepare(new_parser);
return new_parser;
}
/**
* Creates fail tree and initializes buffer
*/
apr_status_t acmp_prepare(ACMP *parser) {
if (parser->bp_buff_len < parser->longest_entry) {
parser->bp_buff_len = parser->longest_entry * 2;
parser->bp_buffer = apr_pcalloc(parser->pool, sizeof(apr_size_t) * parser->bp_buff_len);
}
apr_status_t st = acmp_connect_fail_branches(parser);
parser->active_node = parser->root_node;
if (st != APR_SUCCESS) return st;
parser->is_active = 1;
return APR_SUCCESS;
}
/**
* Adds pattern to parser
* parser - ACMP parser
* pattern - string with pattern to match
* callback - Optional, pointer to an acmp_callback_t function
* data - pointer to data that will be passed to callback function, only used if callback
* is supplied
* len - Length of pattern in characters, if zero string length is used.
*/
apr_status_t acmp_add_pattern(ACMP *parser, const char *pattern,
acmp_callback_t callback, void *data, apr_size_t len)
{
if (parser->is_active != 0) return APR_EGENERAL;
size_t length = (len == 0) ? acmp_strlen(parser, pattern) : len;
size_t i, j;
acmp_utf8_char_t ucs_chars[length];
acmp_node_t *parent = parser->root_node, *child;
acmp_strtoucs(parser, pattern, ucs_chars, length);
for (i = 0; i < length; i++) {
acmp_utf8_char_t letter = ucs_chars[i];
if (parser->is_case_sensitive == 0) {
letter = utf8_lcase(letter);
}
child = acmp_child_for_code(parent, letter);
if (child == NULL) {
child = apr_pcalloc(parser->pool, sizeof(acmp_node_t));
child->pattern = "";
child->letter = letter;
child->depth = i;
child->text = apr_pcalloc(parser->pool, strlen(pattern) + 2);
for (j = 0; j <= i; j++) child->text[j] = pattern[j];
}
if (i == length - 1) {
if (child->is_last == 0) {
parser->dict_count++;
child->is_last = 1;
child->pattern = apr_pcalloc(parser->pool, strlen(pattern) + 2);
strcpy(child->pattern, pattern);
}
child->callback = callback;
child->callback_data = data;
}
acmp_add_node_to_parent(parent, child);
parent = child;
}
if (length > parser->longest_entry) parser->longest_entry = length;
parser->is_failtree_done = 0;
return APR_SUCCESS;
}
/**
* Called to process incoming data stream
* data - ptr to incoming data
* len - size of data in bytes
*/
apr_status_t acmp_process(ACMP *parser, const char *data, apr_size_t len) {
if (parser->is_failtree_done == 0) acmp_prepare(parser);
acmp_node_t *node = parser->active_node, *go_to;
apr_size_t seq_length;
const char *end = (data + len);
while (data < end) {
parser->bp_buffer[parser->char_pos % parser->bp_buff_len] = parser->byte_pos;
acmp_utf8_char_t letter;
if (parser->is_utf8) {
if (parser->u8buff_len > 0) {
/* Resuming partial utf-8 sequence */
seq_length = utf8_seq_len(parser->u8_buff);
for (;;) {
parser->u8_buff[parser->u8buff_len++] = *data++;
if (parser->u8buff_len == seq_length) {
parser->u8buff_len = 0;
letter = utf8_decodechar(parser->u8_buff);
parser->byte_pos += seq_length;
parser->char_pos++;
break;
}
}
} else {
/* not resuming partial sequence, reading from the stream */
seq_length = utf8_seq_len(data);
if ((data + seq_length) > end) {
while (data < end) parser->u8_buff[parser->u8buff_len++] = *data++;
return APR_SUCCESS;
} else {
letter = utf8_decodechar(data);
data += seq_length;
parser->byte_pos += seq_length;
parser->char_pos++;
}
}
} else {
letter = *data++;
parser->byte_pos++;
parser->char_pos++;
}
if (parser->is_case_sensitive == 0) letter = utf8_lcase(letter);
go_to = NULL;
while (go_to == NULL) {
acmp_node_t *n2 = acmp_goto(node, letter);
go_to = acmp_child_for_code(node, letter);
if (n2 != go_to) {
n2 = acmp_goto(node, letter);
};
if (go_to != NULL) {
if (go_to->is_last) {
acmp_found(parser, go_to);
}
}
if (node == parser->root_node) break;
if (go_to == NULL) node = node->fail;
}
if (go_to != NULL) node = go_to;
/* We need to collect other nodes that are last letters of phrase. These
* will be fail node of current node if it has is_last flag set, and
* fail node of that node, recursively down to root node.
*/
go_to = node;
if (go_to != parser->root_node) {
for (go_to = go_to->o_match; go_to != NULL; go_to = go_to->o_match) {
acmp_found(parser, go_to);
}
}
}
parser->active_node = node;
return parser->hit_count > 0 ? 1 : 0;
}
/**
* Resets the state of parser so you can start using it with new set of data.
*
* No need to clear buffer since it will be re-initialized at first run of
* acmp_process
*/
void acmp_reset(ACMP *parser) {
parser->is_active = 0;
parser->byte_pos = 0;
parser->char_pos = 0;
parser->hit_count = 0;
parser->u8buff_len = 0;
acmp_clear_hit_count_recursive(parser->root_node);
}
/**
* Creates an ACMPT struct that will use parser's tree, without duplicating its data
*/
ACMPT *acmp_duplicate_quick(ACMP *parser, apr_pool_t *pool) {
apr_pool_t *p = (pool != NULL) ? pool : parser->pool;
ACMPT *dup = apr_pcalloc(p, sizeof(ACMPT));
dup->parser = parser;
return dup;
}
/**
* Process the data using ACMPT to keep state, and ACMPT's parser to keep the tree
*/
apr_status_t acmp_process_quick(ACMPT *acmpt, const char **match, const char *data, apr_size_t len) {
if (acmpt->parser->is_failtree_done == 0) {
acmp_prepare(acmpt->parser);
};
ACMP *parser = acmpt->parser;
if (acmpt->ptr == NULL) acmpt->ptr = parser->root_node;
acmp_node_t *node = acmpt->ptr, *go_to;
const char *end = (data + len);
while (data < end) {
acmp_utf8_char_t letter = (unsigned char)*data++;
go_to = NULL;
while (go_to == NULL) {
go_to = acmp_goto(node, letter);
if (go_to != NULL) {
if (go_to->is_last) {
*match = go_to->text;
return 1;
}
}
if (node == parser->root_node) break;
if (go_to == NULL) node = node->fail;
}
if (go_to != NULL) node = go_to;
/* If node has o_match, then we found a pattern */
if (node->o_match != NULL) {
*match = node->text;
return 1;
}
}
acmpt->ptr = node;
return 0;
}

115
apache2/acmp.h Normal file
View File

@@ -0,0 +1,115 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Breach Security, Inc. at support@breach.com.
*
*/
#ifndef ACMP_H_
#define ACMP_H_
#include <apr.h>
#include <apr_pools.h>
#define ACMP_FLAG_BYTE 0
#define ACMP_FLAG_UTF8 0x100
#define ACMP_FLAG_CASE_SENSITIVE 1
#define ACMP_FLAG_CASE_INSENSITIVE 0
/**
* Opaque struct with parser data
*/
typedef struct ACMP ACMP;
/**
* Used to separate state from the trie for acmp_process_quick function
*/
typedef struct {
ACMP *parser;
void *ptr;
} ACMPT;
/**
* Callback function. Arguments are:
* ACMP * - acmp parser that initiated callback
* void * - custom data you supplied when adding callback
* apr_size_t - position in bytes where pattern was found
* apr_size_t - position in chars where pattern was found, for multibyte strings
*/
typedef void (*acmp_callback_t)(ACMP *, void *, apr_size_t, apr_size_t);
/**
* flags - OR-ed values of ACMP_FLAG constants
* pool - apr_pool to use as parent pool, can be set to NULL
*/
ACMP *acmp_create(int flags, apr_pool_t *pool);
/**
* Destroys previously created parser
*/
void acmp_destroy(ACMP *parser);
/**
* Creates parser with same options and same patterns
* parser - ACMP parser to duplicate
* pool - parent pool to use, if left as NULL original parser's parent pool is used
*/
ACMP *acmp_duplicate(ACMP *parser, apr_pool_t *pool);
/**
* Adds pattern to parser. Cannot be done after starting the search.
* parser - ACMP parser
* pattern - string with pattern to match
* callback - Optional, pointer to an acmp_callback_t function
* data - pointer to data that will be passed to callback function, only used if callback
* is supplied
* len - Length of pattern in characters, if zero string length is used.
*/
apr_status_t acmp_add_pattern(ACMP *parser, const char *pattern,
acmp_callback_t callback, void *data, apr_size_t len);
/**
* Called to process incoming data stream. You must call acmp_done after sending
* last data packet
*
* data - ptr to incoming data
* len - size of data in bytes
*/
apr_status_t acmp_process(ACMP *parser, const char *data, apr_size_t len);
/**
* Returns number of matches on all patterns combined
*/
apr_size_t acmp_match_count_total(ACMP *parser);
/**
* Returns number of matches for given pattern
*/
apr_size_t acmp_match_count(ACMP *parser, const char *pattern);
/**
* Resets the state of parser so you can start using it with new set of data,
* or add new patterns.
*/
void acmp_reset(ACMP *parser);
/**
* Creates an ACMPT struct that will use parser's tree, without duplicating its data
*/
ACMPT *acmp_duplicate_quick(ACMP *parser, apr_pool_t *pool);
/**
* Process the data using ACMPT to keep state, and ACMPT's parser to keep the tree
*/
apr_status_t acmp_process_quick(ACMPT *acmpt, const char **match, const char *data, apr_size_t len);
/**
* Prepares parser for searching
*/
apr_status_t acmp_prepare(ACMP *parser);
#endif /*ACMP_H_*/

View File

@@ -1,13 +1,11 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2006 Thinking Stone (http://www.thinkingstone.com)
*
* $Id$
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Thinking Stone at contact@thinkingstone.com.
* write to Breach Security, Inc. at support@breach.com.
*
*/
#ifndef _APACHE2_H_

View File

@@ -1,20 +1,18 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2006 Thinking Stone (http://www.thinkingstone.com)
*
* $Id: apache2_config.c,v 1.8 2006/12/28 10:39:13 ivanr Exp $
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Thinking Stone at contact@thinkingstone.com.
* write to Breach Security, Inc. at support@breach.com.
*
*/
#include <limits.h>
#include "modsecurity.h"
#include "msc_logging.h"
#include "pdf_protect.h"
#include "http_log.h"
/* #define DEBUG_CONF 1 */
@@ -90,6 +88,7 @@ void *create_directory_config(apr_pool_t *mp, char *path) {
dcfg->pdfp_timeout = NOT_SET;
dcfg->pdfp_token_name = NOT_SET_P;
dcfg->pdfp_only_get = NOT_SET;
dcfg->pdfp_method = NOT_SET;
/* Geo Lookups */
dcfg->geo = NOT_SET_P;
@@ -384,6 +383,8 @@ void *merge_directory_configs(apr_pool_t *mp, void *_parent, void *_child) {
? parent->pdfp_token_name : child->pdfp_token_name);
merged->pdfp_only_get = (child->pdfp_only_get == NOT_SET
? parent->pdfp_only_get : child->pdfp_only_get);
merged->pdfp_method = (child->pdfp_method == NOT_SET
? parent->pdfp_method : child->pdfp_method);
/* Geo Lookup */
merged->geo = (child->geo == NOT_SET_P
@@ -456,7 +457,8 @@ void init_directory_config(directory_config *dcfg) {
if (dcfg->pdfp_secret == NOT_SET_P) dcfg->pdfp_secret = NULL;
if (dcfg->pdfp_timeout == NOT_SET) dcfg->pdfp_timeout = 10;
if (dcfg->pdfp_token_name == NOT_SET_P) dcfg->pdfp_token_name = "PDFPTOKEN";
if (dcfg->pdfp_only_get == NOT_SET) dcfg->pdfp_only_get = 0;
if (dcfg->pdfp_only_get == NOT_SET) dcfg->pdfp_only_get = 1;
if (dcfg->pdfp_method == NOT_SET) dcfg->pdfp_method = PDF_PROTECT_METHOD_TOKEN_REDIRECTION;
/* Geo Lookup */
if (dcfg->geo == NOT_SET_P) dcfg->geo = NULL;
@@ -1195,6 +1197,25 @@ static const char *cmd_pdf_protect_intercept_get_only(cmd_parms *cmd, void *_dcf
return NULL;
}
static const char *cmd_pdf_protect_method(cmd_parms *cmd, void *_dcfg,
const char *p1)
{
directory_config *dcfg = (directory_config *)_dcfg;
if (dcfg == NULL) return NULL;
if (strcasecmp(p1, "TokenRedirection") == 0) {
dcfg->pdfp_method = PDF_PROTECT_METHOD_TOKEN_REDIRECTION;
} else
if (strcasecmp(p1, "ForcedDownload") == 0) {
dcfg->pdfp_method = PDF_PROTECT_METHOD_FORCED_DOWNLOAD;
} else {
return (const char *)apr_psprintf(cmd->pool,
"ModSecurity: Unrecognised parameter value for SecPdfProtectMethod: %s", p1);
}
return NULL;
}
/* -- Geo Lookup configuration -- */
static const char *cmd_geo_lookups_db(cmd_parms *cmd, void *_dcfg,
@@ -1547,7 +1568,15 @@ const command_rec module_directives[] = {
cmd_pdf_protect_intercept_get_only,
NULL,
RSRC_CONF,
"whether or not to intercept only GET requess."
"whether or not to intercept only GET and HEAD requess. Defaults to true."
),
AP_INIT_TAKE1 (
"SecPdfProtectMethod",
cmd_pdf_protect_method,
NULL,
RSRC_CONF,
"protection method to use. Can be 'TokenRedirection' (default) or 'ForcedDownload'"
),
AP_INIT_TAKE1 (

View File

@@ -1,13 +1,11 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2006 Thinking Stone (http://www.thinkingstone.com)
*
* $Id: apache2_io.c,v 1.6 2007/01/23 16:08:15 ivanr Exp $
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Thinking Stone at contact@thinkingstone.com.
* write to Breach Security, Inc. at support@breach.com.
*
*/
#include "modsecurity.h"

View File

@@ -1,13 +1,11 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2006 Thinking Stone (http://www.thinkingstone.com)
*
* $Id: apache2_util.c,v 1.1.1.1 2006/10/14 09:30:43 ivanr Exp $
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Thinking Stone at contact@thinkingstone.com.
* write to Breach Security, Inc. at support@breach.com.
*
*/
#include "modsecurity.h"
@@ -255,6 +253,7 @@ void msr_log(modsec_rec *msr, int level, const char *text, ...) {
va_end(ap);
}
/**
* Converts an Apache error log message into one line of text.
*/

View File

@@ -1,13 +1,11 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2006 Thinking Stone (http://www.thinkingstone.com)
*
* $Id: mod_security2.c,v 1.11 2006/12/15 15:06:04 ivanr Exp $
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Thinking Stone at contact@thinkingstone.com.
* write to Breach Security, Inc. at support@breach.com.
*
*/
#include <limits.h>
@@ -55,14 +53,30 @@ int perform_interception(modsec_rec *msr) {
msre_actionset *actionset = NULL;
const char *message = NULL;
const char *phase_text = "";
const char *intreq_text = "";
int is_initial_req = ap_is_initial_req(msr->r);
int status = DECLINED;
int log_level = 1;
/* Check for an initial request */
if (is_initial_req != 1) {
if (msr->r->main != NULL) {
intreq_text = "Sub-Request: ";
}
else if (msr->r->prev != NULL) {
intreq_text = "Internal Redirect: ";
}
else {
intreq_text = "Internal Request: ";
}
}
/* Sanity checks first. */
if (msr->was_intercepted == 0) {
msr_log(msr, 1, "Internal Error: Asked to intercept request but was_intercepted is zero");
msr->was_intercepted = 0;
return DECLINED;
}
@@ -78,12 +92,13 @@ int perform_interception(modsec_rec *msr) {
phase_text = apr_psprintf(msr->mp, " (phase %i)", msr->phase);
/* By default we log at level 1 but we switch to 4
* if a nolog action was used to hide the message.
* if a nolog action was used or this is not the initial request
* to hide the message.
*/
log_level = (actionset->log != 1) ? 4 : 1;
log_level = ((actionset->log != 1) || (is_initial_req != 1)) ? 4 : 1;
/* Pause the request first (if configured to do so). */
if (actionset->intercept_pause) {
/* Pause the request first (if configured and the initial request). */
if (actionset->intercept_pause && (is_initial_req == 1)) {
msr_log(msr, (log_level > 3 ? log_level : log_level + 1), "Pausing transaction for "
"%i msec.", actionset->intercept_pause);
/* apr_sleep accepts microseconds */
@@ -95,14 +110,14 @@ int perform_interception(modsec_rec *msr) {
case ACTION_DENY :
if (actionset->intercept_status != 0) {
status = actionset->intercept_status;
message = apr_psprintf(msr->mp, "Access denied with code %i%s.", status,
phase_text);
message = apr_psprintf(msr->mp, "%sAccess denied with code %i%s.",
intreq_text, status, phase_text);
} else {
log_level = 1;
status = HTTP_INTERNAL_SERVER_ERROR;
message = apr_psprintf(msr->mp, "Access denied with code 500%s "
"(Internal Error: Invalid status code requested %i).", phase_text,
actionset->intercept_status);
message = apr_psprintf(msr->mp, "%sAccess denied with code 500%s "
"(Internal Error: Invalid status code requested %i).",
intreq_text, phase_text, actionset->intercept_status);
}
break;
@@ -111,23 +126,25 @@ int perform_interception(modsec_rec *msr) {
if (ap_find_linked_module("mod_proxy.c") == NULL) {
log_level = 1;
status = HTTP_INTERNAL_SERVER_ERROR;
message = apr_psprintf(msr->mp, "Access denied with code 500%s "
message = apr_psprintf(msr->mp, "%sAccess denied with code 500%s "
"(Configuration Error: Proxy action to %s requested but mod_proxy not found).",
phase_text, log_escape_nq(msr->mp, actionset->intercept_uri));
intreq_text, phase_text,
log_escape_nq(msr->mp, actionset->intercept_uri));
} else {
msr->r->filename = apr_psprintf(msr->mp, "proxy:%s", actionset->intercept_uri);
msr->r->proxyreq = PROXYREQ_REVERSE;
msr->r->handler = "proxy-server";
status = OK;
message = apr_psprintf(msr->mp, "Access denied using proxy to %s%s.",
phase_text, log_escape_nq(msr->mp, actionset->intercept_uri));
message = apr_psprintf(msr->mp, "%sAccess denied using proxy to%s %s.",
intreq_text, phase_text,
log_escape_nq(msr->mp, actionset->intercept_uri));
}
} else {
log_level = 1;
status = HTTP_INTERNAL_SERVER_ERROR;
message = apr_psprintf(msr->mp, "Access denied with code 500%s "
message = apr_psprintf(msr->mp, "%sAccess denied with code 500%s "
"(Configuration Error: Proxy action requested but it does not work in output phases).",
phase_text);
intreq_text, phase_text);
}
break;
@@ -144,29 +161,30 @@ int perform_interception(modsec_rec *msr) {
if (csd) {
if (apr_socket_close(csd) == APR_SUCCESS) {
status = HTTP_FORBIDDEN;
message = apr_psprintf(msr->mp, "Access denied with connection close%s.",
phase_text);
message = apr_psprintf(msr->mp, "%sAccess denied with connection close%s.",
intreq_text, phase_text);
} else {
log_level = 1;
status = HTTP_INTERNAL_SERVER_ERROR;
message = apr_psprintf(msr->mp, "Access denied with code 500%s "
message = apr_psprintf(msr->mp, "%sAccess denied with code 500%s "
"(Error: Connection drop requested but failed to close the "
" socket).", phase_text);
" socket).",
intreq_text, phase_text);
}
} else {
log_level = 1;
status = HTTP_INTERNAL_SERVER_ERROR;
message = apr_psprintf(msr->mp, "Access denied with code 500%s "
message = apr_psprintf(msr->mp, "%sAccess denied with code 500%s "
"(Error: Connection drop requested but socket not found.",
phase_text);
intreq_text, phase_text);
}
}
#else
log_level = 1;
status = HTTP_INTERNAL_SERVER_ERROR;
message = apr_psprintf(msr->mp, "Access denied with code 500%s "
message = apr_psprintf(msr->mp, "%sAccess denied with code 500%s "
"(Error: Connection drop not implemented on this platform).",
phase_text);
intreq_text, phase_text);
#endif
break;
@@ -179,23 +197,25 @@ int perform_interception(modsec_rec *msr) {
} else {
status = HTTP_MOVED_TEMPORARILY;
}
message = apr_psprintf(msr->mp, "Access denied with redirection to %s using "
"status %i%s.", log_escape_nq(msr->mp, actionset->intercept_uri), status,
message = apr_psprintf(msr->mp, "%sAccess denied with redirection to %s using "
"status %i%s.",
intreq_text,
log_escape_nq(msr->mp, actionset->intercept_uri), status,
phase_text);
break;
case ACTION_ALLOW :
status = DECLINED;
message = apr_psprintf(msr->mp, "Access allowed%s.", phase_text);
message = apr_psprintf(msr->mp, "%sAccess allowed%s.", intreq_text, phase_text);
msr->was_intercepted = 0;
break;
default :
log_level = 1;
status = HTTP_INTERNAL_SERVER_ERROR;
message = apr_psprintf(msr->mp, "Access denied with code 500%s "
message = apr_psprintf(msr->mp, "%sAccess denied with code 500%s "
"(Internal Error: invalid interception action %i).",
phase_text, actionset->intercept_action);
intreq_text, phase_text, actionset->intercept_action);
break;
}
@@ -333,6 +353,8 @@ static modsec_rec *create_tx_context(request_rec *r) {
msr_log(msr, 4, "Transaction context created (dcfg %x).", msr->dcfg1);
}
msr->msc_rule_mptmp = NULL;
return msr;
}
@@ -562,6 +584,10 @@ static int hook_request_late(request_rec *r) {
/* Has this phase been completed already? */
if (msr->phase_request_body_complete) {
if (msr->was_intercepted) {
msr_log(msr, 4, "Phase REQUEST_BODY request already intercepted. Intercepting additional request.");
return perform_interception(msr);
}
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Phase REQUEST_BODY already complete, skipping.");
}

View File

@@ -1,13 +1,11 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2006 Thinking Stone (http://www.thinkingstone.com)
*
* $Id: modsecurity.c,v 1.7 2006/12/28 10:39:13 ivanr Exp $
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Thinking Stone at contact@thinkingstone.com.
* write to Breach Security, Inc. at support@breach.com.
*
*/
#include <stdlib.h>
@@ -297,6 +295,9 @@ apr_status_t modsecurity_tx_init(modsec_rec *msr) {
msr->collections_dirty = apr_table_make(msr->mp, 8);
if (msr->collections_dirty == NULL) return -1;
msr->tcache = apr_hash_make(msr->mp);
if (msr->tcache == NULL) return -1;
return 1;
}

View File

@@ -1,13 +1,11 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2006 Thinking Stone (http://www.thinkingstone.com)
*
* $Id: modsecurity.h,v 1.27 2007/02/05 12:44:40 ivanr Exp $
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Thinking Stone at contact@thinkingstone.com.
* write to Breach Security, Inc. at support@breach.com.
*
*/
#ifndef _MODSECURITY_H_
@@ -26,7 +24,7 @@ typedef struct msc_data_chunk msc_data_chunk;
typedef struct msc_arg msc_arg;
typedef struct msc_string msc_string;
#if !(defined(WIN32) || defined(NETWARE))
#if !(defined(WIN32) || defined(NETWARE) || defined(SOLARIS2))
#define DSOLOCAL __attribute__((visibility("hidden")))
#else
#define DSOLOCAL
@@ -45,13 +43,14 @@ typedef struct msc_string msc_string;
#include "ap_config.h"
#include "apr_md5.h"
#include "apr_strings.h"
#include "apr_hash.h"
#include "httpd.h"
#include "http_config.h"
#include "http_log.h"
#include "http_protocol.h"
#define MODULE_NAME "ModSecurity"
#define MODULE_RELEASE "2.2.0-dev1"
#define MODULE_RELEASE "2.5.0-dev2"
#define MODULE_NAME_FULL (MODULE_NAME " v" MODULE_RELEASE " (Apache 2.x)")
#define PHASE_REQUEST_HEADERS 1
@@ -59,6 +58,8 @@ typedef struct msc_string msc_string;
#define PHASE_RESPONSE_HEADERS 3
#define PHASE_RESPONSE_BODY 4
#define PHASE_LOGGING 5
#define PHASE_FIRST PHASE_REQUEST_HEADERS
#define PHASE_LAST PHASE_LOGGING
#define NOT_SET -1
#define NOT_SET_P (void *)-1
@@ -319,6 +320,9 @@ struct modsec_rec {
apr_off_t content_prepend_len;
const char *content_append;
apr_off_t content_append_len;
/* data cache */
apr_hash_t *tcache;
};
struct directory_config {
@@ -406,6 +410,7 @@ struct directory_config {
int pdfp_timeout;
const char *pdfp_token_name;
int pdfp_only_get;
int pdfp_method;
/* Geo Lookup */
geo_db *geo;

View File

@@ -2,11 +2,11 @@
MOD_SECURITY2 = mod_security2 apache2_config apache2_io apache2_util \
re re_operators re_actions re_tfns re_variables \
msc_logging msc_xml msc_multipart modsecurity msc_parsers msc_util msc_pcre \
persist_dbm msc_reqbody pdf_protect msc_geo
persist_dbm msc_reqbody pdf_protect msc_geo acmp
H = re.h modsecurity.h msc_logging.h msc_multipart.h msc_parsers.h \
msc_pcre.h msc_util.h msc_xml.h persist_dbm.h apache2.h pdf_protect.h \
msc_geo.h
msc_geo.h acmp.h utf8tables.h
${MOD_SECURITY2:=.slo}: ${H}
${MOD_SECURITY2:=.lo}: ${H}

View File

@@ -1,11 +1,11 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2006 Thinking Stone (http://www.thinkingstone.com)
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Thinking Stone at contact@thinkingstone.com.
* write to Breach Security, Inc. at support@breach.com.
*
*/
#include "msc_geo.h"
@@ -228,6 +228,23 @@ static int db_open(directory_config *dcfg, char **error_msg)
return 1;
}
static int field_length(const char *field, int maxlen)
{
int i;
if (field == NULL) {
return 0;
}
for (i = 0; i < maxlen; i++) {
if (field[i] == '\0') {
break;
}
}
return i;
}
/**
* Initialise Geo data structure
*/
@@ -375,21 +392,21 @@ int geo_lookup(modsec_rec *msr, geo_rec *georec, const char *target, char **erro
remaining -= rec_offset;
/* Region */
field_len = strnlen((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));
georec->region = apr_pstrmemdup(msr->mp, (const char *)cbuf+rec_offset, (remaining));
rec_offset += field_len + 1;
remaining -= field_len + 1;
/* City */
field_len = strnlen((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));
georec->city = apr_pstrmemdup(msr->mp, (const char *)cbuf+rec_offset, (remaining));
rec_offset += field_len + 1;
remaining -= field_len + 1;
/* Postal Code */
field_len = strnlen((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));
georec->postal_code = apr_pstrmemdup(msr->mp, (const char *)cbuf+rec_offset, (remaining));
rec_offset += field_len + 1;

View File

@@ -1,11 +1,11 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2006 Thinking Stone (http://www.thinkingstone.com)
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Thinking Stone at contact@thinkingstone.com.
* write to Breach Security, Inc. at support@breach.com.
*
*/
#ifndef _MSC_GEO_H_

View File

@@ -1,13 +1,11 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2006 Thinking Stone (http://www.thinkingstone.com)
*
* $Id: msc_logging.c,v 1.1.1.1 2006/10/14 09:30:43 ivanr Exp $
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Thinking Stone at contact@thinkingstone.com.
* write to Breach Security, Inc. at support@breach.com.
*
*/
#include "msc_logging.h"

View File

@@ -1,13 +1,11 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2006 Thinking Stone (http://www.thinkingstone.com)
*
* $Id: msc_logging.h,v 1.1.1.1 2006/10/14 09:30:43 ivanr Exp $
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Thinking Stone at contact@thinkingstone.com.
* write to Breach Security, Inc. at support@breach.com.
*
*/
#ifndef _MSC_LOGGING_H_

View File

@@ -1,13 +1,11 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2006 Thinking Stone (http://www.thinkingstone.com)
*
* $Id: msc_multipart.c,v 1.2 2006/10/16 04:41:51 ivanr Exp $
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Thinking Stone at contact@thinkingstone.com.
* write to Breach Security, Inc. at support@breach.com.
*
*/
#include <ctype.h>

View File

@@ -1,13 +1,11 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2006 Thinking Stone (http://www.thinkingstone.com)
*
* $Id: msc_multipart.h,v 1.1.1.1 2006/10/14 09:30:43 ivanr Exp $
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Thinking Stone at contact@thinkingstone.com.
* write to Breach Security, Inc. at support@breach.com.
*
*/
#ifndef _MSC_MULTIPART_H_

View File

@@ -1,13 +1,11 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2006 Thinking Stone (http://www.thinkingstone.com)
*
* $Id: msc_parsers.c,v 1.1.1.1 2006/10/14 09:30:43 ivanr Exp $
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Thinking Stone at contact@thinkingstone.com.
* write to Breach Security, Inc. at support@breach.com.
*
*/
#include "msc_parsers.h"

View File

@@ -1,13 +1,11 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2006 Thinking Stone (http://www.thinkingstone.com)
*
* $Id: msc_parsers.h,v 1.1.1.1 2006/10/14 09:30:43 ivanr Exp $
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Thinking Stone at contact@thinkingstone.com.
* write to Breach Security, Inc. at support@breach.com.
*
*/
#ifndef _MSC_PARSERS_H_

View File

@@ -1,13 +1,11 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2006 Thinking Stone (http://www.thinkingstone.com)
*
* $Id: msc_pcre.c,v 1.2 2006/12/28 10:39:13 ivanr Exp $
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Thinking Stone at contact@thinkingstone.com.
* write to Breach Security, Inc. at support@breach.com.
*
*/
#include "msc_pcre.h"

View File

@@ -1,13 +1,11 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2006 Thinking Stone (http://www.thinkingstone.com)
*
* $Id: msc_pcre.h,v 1.3 2006/12/28 10:39:13 ivanr Exp $
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Thinking Stone at contact@thinkingstone.com.
* write to Breach Security, Inc. at support@breach.com.
*
*/
#ifndef _MSC_PCRE_H_

View File

@@ -1,13 +1,11 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2006 Thinking Stone (http://www.thinkingstone.com)
*
* $Id: msc_reqbody.c,v 1.2 2006/12/04 21:54:10 ivanr Exp $
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Thinking Stone at contact@thinkingstone.com.
* write to Breach Security, Inc. at support@breach.com.
*
*/
#include "modsecurity.h"

View File

@@ -1,13 +1,11 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2006 Thinking Stone (http://www.thinkingstone.com)
*
* $Id: msc_util.c,v 1.1.1.1 2006/10/14 09:30:43 ivanr Exp $
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Thinking Stone at contact@thinkingstone.com.
* write to Breach Security, Inc. at support@breach.com.
*
*/
#include "msc_util.h"
@@ -561,8 +559,18 @@ int urldecode_uni_nonstrict_inplace_ex(unsigned char *input, long int input_len)
if ( (VALID_HEX(input[i + 2]))&&(VALID_HEX(input[i + 3]))
&&(VALID_HEX(input[i + 4]))&&(VALID_HEX(input[i + 5])) )
{
/* We make use of the lower byte here, ignoring the higher byte. */
*d++ = x2c(&input[i + 4]);
/* We first make use of the lower byte here, ignoring the higher byte. */
*d = x2c(&input[i + 4]);
/* Full width ASCII (ff01 - ff5e) needs 0x20 added */
if ( (*d > 0x00) && (*d < 0x5f)
&& ((input[i + 2] == 'f') || (input[i + 2] == 'F'))
&& ((input[i + 3] == 'f') || (input[i + 3] == 'F')))
{
*d += 0x20;
}
d++;
count++;
i += 6;
} else {

View File

@@ -1,13 +1,11 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2006 Thinking Stone (http://www.thinkingstone.com)
*
* $Id: msc_util.h,v 1.1.1.1 2006/10/14 09:30:43 ivanr Exp $
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Thinking Stone at contact@thinkingstone.com.
* write to Breach Security, Inc. at support@breach.com.
*
*/
#ifndef _UTIL_H_

View File

@@ -1,13 +1,11 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2006 Thinking Stone (http://www.thinkingstone.com)
*
* $Id: msc_xml.c,v 1.2 2006/12/04 20:04:09 ivanr Exp $
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Thinking Stone at contact@thinkingstone.com.
* write to Breach Security, Inc. at support@breach.com.
*
*/
#ifdef WITH_LIBXML2

View File

@@ -1,13 +1,11 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2006 Thinking Stone (http://www.thinkingstone.com)
*
* $Id: msc_xml.h,v 1.1.1.1 2006/10/14 09:30:43 ivanr Exp $
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Thinking Stone at contact@thinkingstone.com.
* write to Breach Security, Inc. at support@breach.com.
*
*/
#ifndef _MSC_XML_H_

View File

@@ -1,17 +1,14 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2006 Thinking Stone (http://www.thinkingstone.com)
*
* $Id$
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Thinking Stone at contact@thinkingstone.com.
* write to Breach Security, Inc. at support@breach.com.
*
*/
#include "modsecurity.h"
// #include "apache2.h"
#include "pdf_protect.h"
#include <ctype.h>
@@ -225,17 +222,21 @@ apr_status_t pdfp_output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
if (msr == NULL) {
ap_log_error(APLOG_MARK, APLOG_ERR | APLOG_NOERRNO, 0, f->r->server,
"ModSecurity: Internal Error: msr is null in PDF output filter.");
"ModSecurity: Internal Error: Unable to retrieve context in PDF output filter.");
ap_remove_output_filter(f);
return send_error_bucket(f, HTTP_INTERNAL_SERVER_ERROR);
}
if (msr->txcfg->pdfp_enabled == 1) {
// TODO Should we look at err_headers_out too?
const char *h_content_type = apr_table_get(f->r->headers_out, "Content-Type");
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "PdfProtect: r->content_type=%s, header C-T=%s",
f->r->content_type, h_content_type);
log_escape_nq(msr->mp, f->r->content_type),
log_escape_nq(msr->mp, h_content_type));
}
/* Have we been asked to tweak the headers? */
@@ -255,6 +256,10 @@ apr_status_t pdfp_output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
}
/* Proceed to detect dynamically-generated PDF files. */
// TODO application/x-pdf, application/vnd.fdf, application/vnd.adobe.xfdf,
// application/vnd.adobe.xdp+xml, application/vnd.adobe.xfd+xml, application/vnd.pdf
// application/acrobat, text/pdf, text/x-pdf ???
if (((f->r->content_type != NULL)&&(strcasecmp(f->r->content_type, "application/pdf") == 0))
|| ((h_content_type != NULL)&&(strcasecmp(h_content_type, "application/pdf") == 0)))
{
@@ -263,16 +268,35 @@ apr_status_t pdfp_output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "PdfProtect: Detected a dynamically-generated PDF in %s",
r->uri);
log_escape_nq(msr->mp, r->uri));
}
/* If we are configured with ForcedDownload protection method then we
* can do our thing here and finish early.
*/
if (msr->txcfg->pdfp_method == PDF_PROTECT_METHOD_FORCED_DOWNLOAD) {
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "PdfProtect: Forcing download of a dynamically "
"generated PDF file.");
}
apr_table_set(f->r->headers_out, "Content-Disposition", DISPOSITION_VALUE);
f->r->content_type = ATTACHMENT_MIME_TYPE;
ap_remove_output_filter(f);
return ap_pass_brigade(f->next, bb_in);
}
/* If we are here that means TokenRedirection is the desired protection method. */
/* Is this a non-GET request? */
if ((f->r->method_number != M_GET)&&
((msr->txcfg->pdfp_only_get == 1)||(msr->txcfg->pdfp_only_get == -1))
) {
/* This is a non-GET request and we have been configured
* not to intercept it. We are not going to do that but
* we are going to tweak the headers to force download.
* not to intercept it. So we are going to tweak the headers
* to force download.
*/
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "PdfProtect: Forcing download of a dynamically "
@@ -283,6 +307,7 @@ apr_status_t pdfp_output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
f->r->content_type = ATTACHMENT_MIME_TYPE;
ap_remove_output_filter(f);
return ap_pass_brigade(f->next, bb_in);
}
@@ -298,10 +323,11 @@ apr_status_t pdfp_output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in) {
/* Redirect user to the new URI. */
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "PdfProtect: PDF request without a token - "
"redirecting to %s.", new_uri);
"redirecting to %s.", log_escape_nq(msr->mp, new_uri));
}
apr_table_set(r->headers_out, "Location", new_uri);
return send_error_bucket(f, REDIRECT_STATUS);
}
} else { /* Token found. */
@@ -353,6 +379,16 @@ int pdfp_check(modsec_rec *msr) {
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "PdfProtect: Not enabled here.");
}
return 0;
}
if (msr->txcfg->pdfp_method != PDF_PROTECT_METHOD_TOKEN_REDIRECTION) {
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "PdfProtect: Configured with ForcedDownload as protection method, "
"skipping detection on the inbound.");
}
return 0;
}
@@ -365,17 +401,18 @@ int pdfp_check(modsec_rec *msr) {
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "PdfProtect: Unable to inspect URI because it is NULL.");
}
/* TODO Should we return -1 instead? */
return 0;
return -1; /* Error. */
}
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "PdfProtect: URI=%s, filename=%s, QUERY_STRING=%s.",
msr->r->uri, msr->r->filename, msr->r->args);
log_escape_nq(msr->mp, msr->r->uri), log_escape_nq(msr->mp, msr->r->filename),
log_escape_nq(msr->mp, msr->r->args));
}
uri = apr_pstrdup(msr->mp, msr->r->uri);
if (uri == NULL) return -1;
if (uri == NULL) return -1; /* Error. */
ap_str_tolower(uri);
/* Attempt to figure out if this is a request for a PDF file. We are
@@ -389,17 +426,19 @@ int pdfp_check(modsec_rec *msr) {
msr_log(msr, 4, "PdfProtect: No indication in the URI this is a "
"request for a PDF file.");
}
return 0;
}
/* Ignore request methods other than GET if
/* Ignore request methods other than GET and HEAD if
* configured to do so.
*/
if ((msr->r->method_number != M_GET)&&(cfg->pdfp_only_get != 0)) {
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "PdfProtect: Configured not to intercept non-GET requests "
"(method=%s/%i).", msr->r->method, msr->r->method_number);
msr_log(msr, 4, "PdfProtect: Not intercepting a GET/HEAD request "
"(method=%s/%i).", log_escape_nq(msr->mp, msr->r->method), msr->r->method_number);
}
return 0;
}
@@ -421,7 +460,7 @@ int pdfp_check(modsec_rec *msr) {
/* Redirect user to the new URI. */
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "PdfProtect: PDF request without a token - redirecting to %s.",
new_uri);
log_escape_nq(msr->mp, new_uri));
}
apr_table_set(msr->r->headers_out, "Location", new_uri);
@@ -437,6 +476,7 @@ int pdfp_check(modsec_rec *msr) {
msr_log(msr, 9, "PdfProtect: PDF request with a valid token - "
"serving PDF file normally.");
}
return 0;
} else { /* Not valid. */
/* The token is not valid. We will tweak the response

View File

@@ -1,19 +1,20 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2007 Thinking Stone (http://www.thinkingstone.com)
*
* $Id$
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Thinking Stone at contact@thinkingstone.com.
* write to Breach Security, Inc. at support@breach.com.
*
*/
#ifndef _PDF_PROTECT_H_
#define _PDF_PROTECT_H_
#define PDF_PROTECT_METHOD_TOKEN_REDIRECTION 1
#define PDF_PROTECT_METHOD_FORCED_DOWNLOAD 2
apr_status_t DSOLOCAL pdfp_output_filter(ap_filter_t *f, apr_bucket_brigade *bb_in);
int DSOLOCAL pdfp_check(modsec_rec *msr);

View File

@@ -1,13 +1,11 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2006 Thinking Stone (http://www.thinkingstone.com)
*
* $Id: persist_dbm.c,v 1.3 2006/12/21 19:57:41 ivanr Exp $
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Thinking Stone at contact@thinkingstone.com.
* write to Breach Security, Inc. at support@breach.com.
*
*/
#include "persist_dbm.h"

View File

@@ -1,13 +1,11 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2006 Thinking Stone (http://www.thinkingstone.com)
*
* $Id: persist_dbm.h,v 1.1.1.1 2006/10/14 09:30:43 ivanr Exp $
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Thinking Stone at contact@thinkingstone.com.
* write to Breach Security, Inc. at support@breach.com.
*
*/
#ifndef _PERSIST_DBM_H_

View File

@@ -1,13 +1,11 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2006 Thinking Stone (http://www.thinkingstone.com)
*
* $Id: re.c,v 1.15 2006/12/29 10:44:25 ivanr Exp $
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Thinking Stone at contact@thinkingstone.com.
* write to Breach Security, Inc. at support@breach.com.
*
*/
#include <ctype.h>
@@ -294,7 +292,7 @@ int msre_parse_generic(apr_pool_t *mp, const char *text, apr_table_t *vartable,
/* we are at the beginning of the name */
name = p;
while((*p != '\0')&&(*p != '|')&&(*p != ':')&&(*p != ',')&&(!isspace(*p))) p++; // ENH replace with isvarnamechar()
while((*p != '\0')&&(*p != '|')&&(*p != ':')&&(*p != ',')&&(!isspace(*p))) p++; /* ENH replace with isvarnamechar() */
/* get the name */
name = apr_pstrmemdup(mp, name, p - name);
@@ -421,6 +419,7 @@ msre_actionset *msre_actionset_create(msre_engine *engine, const char *text,
actionset->msg = NOT_SET_P;
actionset->phase = NOT_SET;
actionset->severity = -1;
actionset->rule = NOT_SET_P;
/* Flow */
actionset->is_chained = NOT_SET;
@@ -495,6 +494,7 @@ msre_actionset *msre_actionset_merge(msre_engine *engine, msre_actionset *parent
if (child->msg != NOT_SET_P) merged->msg = child->msg;
if (child->severity != NOT_SET) merged->severity = child->severity;
if (child->phase != NOT_SET) merged->phase = child->phase;
if (child->rule != NOT_SET_P) merged->rule = child->rule;
/* Flow */
merged->is_chained = child->is_chained;
@@ -550,6 +550,7 @@ static void msre_actionset_set_defaults(msre_actionset *actionset) {
if (actionset->msg == NOT_SET_P) actionset->msg = NULL;
if (actionset->phase == NOT_SET) actionset->phase = 2;
if (actionset->severity == -1); /* leave at -1 */
if (actionset->rule == NOT_SET_P) actionset->rule = NULL;
/* Flow */
if (actionset->is_chained == NOT_SET) actionset->is_chained = 0;
@@ -844,6 +845,8 @@ int msre_ruleset_rule_add(msre_ruleset *ruleset, msre_rule *rule, int phase) {
*/
msre_actionset_set_defaults(rule->actionset);
rule->actionset->rule = rule;
*(const msre_rule **)apr_array_push(arr) = rule;
return 1;
@@ -972,14 +975,23 @@ char *msre_format_metadata(modsec_rec *msr, msre_actionset *actionset) {
char *msg = "";
char *severity = "";
char *tags = "";
char *fn = "";
int k;
if (actionset == NULL) return "";
if (actionset->id != NULL) id = apr_psprintf(msr->mp, " [id \"%s\"]",
log_escape(msr->mp, actionset->id));
if (actionset->rev != NULL) rev = apr_psprintf(msr->mp, " [rev \"%s\"]",
log_escape(msr->mp, actionset->rev));
if ((actionset->rule != NULL) && (actionset->rule->filename != NULL)) {
fn = apr_psprintf(msr->mp, " [file \"%s\"] [line \"%d\"]",
actionset->rule->filename, actionset->rule->line_num);
}
if (actionset->id != NULL) {
id = apr_psprintf(msr->mp, " [id \"%s\"]",
log_escape(msr->mp, actionset->id));
}
if (actionset->rev != NULL) {
rev = apr_psprintf(msr->mp, " [rev \"%s\"]",
log_escape(msr->mp, actionset->rev));
}
if (actionset->msg != NULL) {
/* Expand variables in the message string. */
msc_string *var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
@@ -988,11 +1000,11 @@ char *msre_format_metadata(modsec_rec *msr, msre_actionset *actionset) {
expand_macros(msr, var, NULL, msr->mp);
msg = apr_psprintf(msr->mp, " [msg \"%s\"]",
log_escape_ex(msr->mp, var->value, var->value_len));
log_escape_ex(msr->mp, var->value, var->value_len));
}
if ((actionset->severity >= 0)&&(actionset->severity <= 7)) {
severity = apr_psprintf(msr->mp, " [severity \"%s\"]",
msre_format_severity(actionset->severity));
msre_format_severity(actionset->severity));
}
/* Extract rule tags from the action list. */
@@ -1007,7 +1019,7 @@ char *msre_format_metadata(modsec_rec *msr, msre_actionset *actionset) {
}
}
return apr_pstrcat(msr->mp, id, rev, msg, severity, tags, NULL);
return apr_pstrcat(msr->mp, fn, id, rev, msg, severity, tags, NULL);
}
/**
@@ -1175,7 +1187,7 @@ static void msre_perform_disruptive_actions(modsec_rec *msr, msre_rule *rule,
static int execute_operator(msre_var *var, msre_rule *rule, modsec_rec *msr,
msre_actionset *acting_actionset, apr_pool_t *mptmp)
{
apr_time_t time_before_regex;
apr_time_t time_before_regex = 0;
char *my_error_msg = NULL;
const char *full_varname = NULL;
int rc;
@@ -1210,7 +1222,9 @@ static int execute_operator(msre_var *var, msre_rule *rule, modsec_rec *msr,
var->value_len));
}
time_before_regex = apr_time_now(); /* IMP1 time_before_regex? */
if (msr->txcfg->debuglog_level >= 4) {
time_before_regex = apr_time_now(); /* IMP1 time_before_regex? */
}
rc = rule->op_metadata->execute(msr, rule, var, &my_error_msg);
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Operator completed in %" APR_TIME_T_FMT " usec.",
@@ -1280,9 +1294,6 @@ apr_status_t msre_rule_process(msre_rule *rule, modsec_rec *msr) {
/* Use a fresh memory sub-pool for processing each rule */
if (msr->msc_rule_mptmp == NULL) {
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "Creating new rule processing memory pool");
}
if (apr_pool_create(&msr->msc_rule_mptmp, msr->mp) != APR_SUCCESS) {
return -1;
}
@@ -1351,11 +1362,27 @@ apr_status_t msre_rule_process(msre_rule *rule, modsec_rec *msr) {
{
const apr_array_header_t *tarr;
const apr_table_entry_t *telts;
msre_cache_rec **carr = NULL;
msre_cache_rec *crec = NULL;
char *tfnsvar = NULL;
char *tfnskey = NULL;
int tfnscount = 0;
int usecache = 0;
apr_table_t *normtab;
int k;
msre_action *action;
msre_tfn_metadata *metadata;
/* Is this var cacheable? */
if (var->metadata->is_cacheable == VAR_CACHE) {
usecache = 1;
tfnsvar = apr_psprintf(msr->mp, "%lx;%s", (unsigned long)var, var->name);
tfnskey = tfnsvar;
}
else {
msr_log(msr, 9, "CACHE: %s transformations are not cacheable", var->name);
}
normtab = apr_table_make(mptmp, 10);
if (normtab == NULL) return -1;
tarr = apr_table_elts(rule->actionset->actions);
@@ -1367,6 +1394,8 @@ apr_status_t msre_rule_process(msre_rule *rule, modsec_rec *msr) {
if (strcmp(telts[k].key, "t") == 0) {
if (strcmp(action->param, "none") == 0) {
apr_table_clear(normtab);
tfnskey = tfnsvar;
tfnscount = 0;
continue;
}
@@ -1374,12 +1403,55 @@ apr_status_t msre_rule_process(msre_rule *rule, modsec_rec *msr) {
apr_table_unset(normtab, action->param);
} else {
apr_table_addn(normtab, action->param, (void *)action);
tfnskey = apr_psprintf(msr->mp, "%s,%s", tfnskey, action->param);
tfnscount++;
}
}
}
/* Perform transformations. */
/* Try to fetch the full multi-transformation from cache */
if (usecache && tfnscount > 1 && !multi_match) {
crec = NULL;
msr_log(msr, 9, "CACHE: Fetching %s (multi)", tfnskey);
carr = (msre_cache_rec **)apr_hash_get(msr->tcache, tfnskey, APR_HASH_KEY_STRING);
if (carr != NULL) {
crec = carr[msr->phase];
}
/* Cache Miss - Reset the key to perform transformations */
if (crec == NULL) {
tfnskey = tfnsvar;
}
/* Cache Hit - Use cache value and execute immediatly */
else {
crec->hits++;
if (crec->changed) {
var->value = apr_pmemdup(msr->mp, crec->val, crec->val_len);
var->value_len = crec->val_len;
}
msr_log(msr, 9, "T (%i) %s: \"%s\" [cached hits=%d]", crec->changed, (tfnskey + strlen(tfnsvar) + 1), log_escape_nq_ex(mptmp, var->value, var->value_len), crec->hits);
rc = execute_operator(var, rule, msr, acting_actionset, mptmp);
if (rc < 0) {
return -1;
}
if (rc == RULE_MATCH) {
/* Return straight away if the transaction
* was intercepted - no need to process the remaining
* targets.
*/
if (msr->was_intercepted) {
return RULE_MATCH;
}
}
continue; /* next target */
}
}
tarr = apr_table_elts(normtab);
/* Make a copy of the variable value so that
@@ -1392,6 +1464,7 @@ apr_status_t msre_rule_process(msre_rule *rule, modsec_rec *msr) {
/* Execute transformations in a loop. */
tfnskey = tfnsvar;
changed = 1;
telts = (const apr_table_entry_t*)tarr->elts;
for (k = 0; k < tarr->nelts; k++) {
@@ -1429,6 +1502,31 @@ apr_status_t msre_rule_process(msre_rule *rule, modsec_rec *msr) {
action = (msre_action *)telts[k].val;
metadata = (msre_tfn_metadata *)action->param_data;
/* Try to use the cache */
if (usecache) {
/* Generate the cache key */
tfnskey = apr_psprintf(msr->mp, "%s,%s", tfnskey, action->param);
/* Try to fetch this transformation from cache */
msr_log(msr, 9, "CACHE: Fetching %s", tfnskey);
crec = NULL;
carr = (msre_cache_rec **)apr_hash_get(msr->tcache, tfnskey, APR_HASH_KEY_STRING);
if (carr != NULL) {
crec = carr[msr->phase];
}
if (crec != NULL) {
crec->hits++;
if ((changed = crec->changed) == 1) {
var->value = apr_pmemdup(msr->mp, crec->val, crec->val_len);
var->value_len = crec->val_len;
}
msr_log(msr, 9, "T (%i) %s: \"%s\" [cached hits=%i]", crec->changed, metadata->name, log_escape_nq_ex(mptmp, var->value, var->value_len), crec->hits);
continue;
}
}
rc = metadata->execute(mptmp, (unsigned char *)var->value, var->value_len,
&rval, &rval_length);
if (rc < 0) {
@@ -1440,6 +1538,26 @@ apr_status_t msre_rule_process(msre_rule *rule, modsec_rec *msr) {
var->value = rval;
var->value_len = rval_length;
/* Cache the transformation */
if (usecache) {
/* ENH1: Add flag to vars to tell which ones can change across phases store the rest in a global cache */
if (carr == NULL) {
carr = (msre_cache_rec **)apr_pcalloc(msr->mp, (sizeof(msre_cache_rec *) * (PHASE_LAST + 1)));
if (carr == NULL) return -1;
memset(carr, 0, (sizeof(msre_cache_rec *) * (PHASE_LAST + 1)));
apr_hash_set(msr->tcache, tfnskey, APR_HASH_KEY_STRING, carr);
}
crec = carr[msr->phase] = (msre_cache_rec *)apr_pcalloc(msr->mp, sizeof(msre_cache_rec));
if (crec == NULL) return -1;
crec->hits = 0;
crec->changed = changed;
crec->key = tfnskey;
crec->val = changed ? apr_pmemdup(msr->mp, rval, rval_length) : NULL;
crec->val_len = changed ? rval_length : -1;
msr_log(msr, 9, "CACHE: Caching %s=\"%.*s\"", tfnskey, crec->val_len, crec->val);
}
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "T (%i) %s: \"%s\"", rc, metadata->name,
log_escape_nq_ex(mptmp, var->value, var->value_len));
@@ -1475,6 +1593,33 @@ apr_status_t msre_rule_process(msre_rule *rule, modsec_rec *msr) {
}
msr_log(msr, 9, "CACHE: size=%u", apr_hash_count(msr->tcache));
#ifdef CACHE_DEBUG
if (msr->txcfg->debuglog_level >= 9) {
apr_hash_index_t *hi;
void *dummy;
msre_cache_rec **rec;
int hn = 0;
int ri;
for (hi = apr_hash_first(msr->mp, msr->tcache); hi; hi = apr_hash_next(hi)) {
hn++;
apr_hash_this(hi, NULL, NULL, &dummy);
rec = (msre_cache_rec **)dummy;
if (rec == NULL) continue;
for (ri = PHASE_FIRST; ri <= PHASE_LAST; ri++) {
if (rec[ri] == NULL) continue;
if (rec[ri]->changed) {
msr_log(msr, 9, "CACHE: %5d) phase=%d hits=%d %s=\"%s\"", hn, msr->phase, rec[ri]->hits, rec[ri]->key, log_escape_nq_ex(mptmp, rec[ri]->val, rec[ri]->val_len));
}
else {
msr_log(msr, 9, "CACHE: %5d) phase=%d hits=%d %s=<no change>", hn, msr->phase, rec[ri]->hits, rec[ri]->key);
}
}
}
}
#endif
return (match_count ? RULE_MATCH : RULE_NO_MATCH);
}

View File

@@ -1,13 +1,11 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2006 Thinking Stone (http://www.thinkingstone.com)
*
* $Id: re.h,v 1.7 2006/12/29 10:31:38 ivanr Exp $
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Thinking Stone at contact@thinkingstone.com.
* write to Breach Security, Inc. at support@breach.com.
*
*/
#ifndef _MSC_RE_H_
@@ -28,6 +26,7 @@ typedef struct msre_tfn_metadata msre_tfn_metadata;
typedef struct msre_actionset msre_actionset;
typedef struct msre_action_metadata msre_action_metadata;
typedef struct msre_action msre_action;
typedef struct msre_cache_rec msre_cache_rec;
#include "apr_general.h"
#include "apr_tables.h"
@@ -226,6 +225,7 @@ struct msre_actionset {
const char *msg;
int severity;
int phase;
msre_rule *rule;
/* Flow */
int is_chained;
@@ -303,4 +303,15 @@ apr_status_t DSOLOCAL msre_parse_vars(msre_ruleset *ruleset, const char *text,
char DSOLOCAL *msre_format_metadata(modsec_rec *msr, msre_actionset *actionset);
/* -- Data Cache -- */
struct msre_cache_rec {
int hits;
int changed;
const char *key;
const char *val;
apr_size_t val_len;
};
#endif

View File

@@ -1,13 +1,11 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2006 Thinking Stone (http://www.thinkingstone.com)
*
* $Id: re_actions.c,v 1.9 2007/02/02 18:16:41 ivanr Exp $
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Thinking Stone at contact@thinkingstone.com.
* write to Breach Security, Inc. at support@breach.com.
*
*/
#include "re.h"

View File

@@ -1,19 +1,19 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2006 Thinking Stone (http://www.thinkingstone.com)
*
* $Id: re_operators.c,v 1.7 2007/01/23 16:08:15 ivanr Exp $
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Thinking Stone at contact@thinkingstone.com.
* write to Breach Security, Inc. at support@breach.com.
*
*/
#include "re.h"
#include "msc_pcre.h"
#include "msc_geo.h"
#include "apr_lib.h"
#include "apr_strmatch.h"
#include "acmp.h"
/**
*
@@ -109,15 +109,12 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c
/* Are we supposed to capture subexpressions? */
capture = apr_table_get(rule->actionset->actions, "capture") ? 1 : 0;
/* Warn when the regex captures but "capture" is not set */
if (msr->txcfg->debuglog_level >= 3) {
/* Show when the regex captures but "capture" is not set */
if (msr->txcfg->debuglog_level >= 6) {
int capcount = 0;
rc = msc_fullinfo(regex, PCRE_INFO_CAPTURECOUNT, &capcount);
if ((capture == 0) && (capcount > 0)) {
msr_log(msr, 4, "Ignoring regex captures since \"capture\" action is not enabled.");
}
if ((capture == 1) && (capcount == 0)) {
msr_log(msr, 3, "Notice. The \"capture\" action is enabled, but the regex does not have explicit captures.");
msr_log(msr, 6, "Ignoring regex captures since \"capture\" action is not enabled.");
}
}
@@ -182,23 +179,247 @@ static int msre_op_rx_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, c
return 0;
}
/* contains */
/* pm */
static int msre_op_contains_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) {
const char *match = (const char *)rule->op_param;
static int msre_op_pm_param_init(msre_rule *rule, char **error_msg) {
if ((rule->op_param == NULL)||(strlen(rule->op_param) == 0)) {
*error_msg = apr_psprintf(rule->ruleset->mp, "Missing parameter for operator 'pm'.");
return 0; /* ERROR */
}
ACMP *p = acmp_create(0, rule->ruleset->mp);
if (p == NULL) return 0;
const char *phrase = apr_pstrdup(rule->ruleset->mp, rule->op_param);
const char *next = rule->op_param + strlen(rule->op_param);
/* Loop through phrases */
/* ENH: Need to allow quoted phrases w/space */
for (;;) {
while((isspace(*phrase) != 0) && (*phrase != '\0')) phrase++;
if (*phrase == '\0') break;
next = phrase;
while((isspace(*next) == 0) && (*next != 0)) next++;
acmp_add_pattern(p, phrase, NULL, NULL, next - phrase);
phrase = next;
}
acmp_prepare(p);
rule->op_param_data = p;
return 1;
}
/* pmFromFile */
static int msre_op_pmFromFile_param_init(msre_rule *rule, char **error_msg) {
char errstr[1024];
char buf[HUGE_STRING_LEN + 1];
char *fn;
char *next;
char *ptr;
const char *rulefile_path;
apr_status_t rc;
apr_file_t *fd;
if ((rule->op_param == NULL)||(strlen(rule->op_param) == 0)) {
*error_msg = apr_psprintf(rule->ruleset->mp, "Missing parameter for operator 'pm'.");
return 0; /* ERROR */
}
ACMP *p = acmp_create(0, rule->ruleset->mp);
if (p == NULL) return 0;
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 */
rulefile_path = apr_pstrndup(rule->ruleset->mp, rule->filename, strlen(rule->filename) - strlen(apr_filepath_name_get(rule->filename)));
#ifdef DEBUG_CONF
fprintf(stderr, "Rulefile path: \"%s\"\n", rulefile_path);
#endif
/* Loop through filenames */
/* ENH: Need to allow quoted filenames w/space */
for (;;) {
const char *rootpath = NULL;
const char *filepath = NULL;
int line = 0;
/* Trim whitespace */
while((isspace(*fn) != 0) && (*fn != '\0')) fn++;
if (*fn == '\0') break;
next = fn;
while((isspace(*next) == 0) && (*next != '\0')) next++;
while((isspace(*next) != 0) && (*next != '\0')) *next++ = '\0';
/* Add path of the rule filename for a relative phrase filename */
filepath = fn;
if (apr_filepath_root(&rootpath, &filepath, APR_FILEPATH_TRUENAME, rule->ruleset->mp) != APR_SUCCESS) {
/* We are not an absolute path. It could mean an error, but
* let that pass through to the open call for a better error */
apr_filepath_merge(&fn, rulefile_path, fn, APR_FILEPATH_TRUENAME, rule->ruleset->mp);
}
/* Open file and read */
rc = apr_file_open(&fd, fn, APR_READ | APR_FILE_NOCLEANUP, 0, rule->ruleset->mp);
if (rc != APR_SUCCESS) {
*error_msg = apr_psprintf(rule->ruleset->mp, "Could not open phrase file \"%s\": %s", fn, apr_strerror(rc, errstr, 1024));
return 0;
}
#ifdef DEBUG_CONF
fprintf(stderr, "Loading phrase file: \"%s\"\n", fn);
#endif
/* Read one pattern per line skipping empty/commented */
for(;;) {
line++;
rc = apr_file_gets(buf, HUGE_STRING_LEN, fd);
if (rc == APR_EOF) break;
if (rc != APR_SUCCESS) {
*error_msg = apr_psprintf(rule->ruleset->mp, "Could read \"%s\" line %d: %s", fn, line, apr_strerror(rc, errstr, 1024));
return 0;
}
/* Remove newline */
ptr = buf;
while(*ptr != '\0') ptr++;
if ((ptr > buf) && (*(ptr - 1) == '\n')) *(ptr - 1) = '\0';
/* Ignore empty lines and comments */
ptr = buf;
while((*ptr != '\0') && apr_isspace(*ptr)) ptr++;
if ((*ptr == '\0') || (*ptr == '#')) continue;
#ifdef DEBUG_CONF
fprintf(stderr, "Adding phrase file pattern: \"%s\"\n", buf);
#endif
acmp_add_pattern(p, buf, NULL, NULL, strlen(buf));
}
fn = next;
}
if (fd != NULL) apr_file_close(fd);
acmp_prepare(p);
rule->op_param_data = p;
return 1;
}
static int msre_op_pm_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) {
const char *match = NULL;
apr_status_t rc = 0;
/* Nothing to read */
if ((var->value == NULL) || (var->value_len == 0)) return 0;
ACMPT pt = {(ACMP *)rule->op_param_data, NULL};
rc = acmp_process_quick(&pt, &match, var->value, var->value_len);
if (rc) {
char *match_escaped = log_escape(msr->mp, match ? match : "<Unknown Match>");
/* This message will be logged. */
if (strlen(match_escaped) > 252) {
*error_msg = apr_psprintf(msr->mp, "Matched phrase \"%.252s ...\" at %s.",
match_escaped, var->name);
} else {
*error_msg = apr_psprintf(msr->mp, "Matched phrase \"%s\" at %s.",
match_escaped, var->name);
}
return 1;
}
return rc;
}
/* within */
static int msre_op_within_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) {
msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
const char *match = NULL;
const char *target;
unsigned int match_length;
unsigned int target_length;
unsigned int target_length = 0;
unsigned int i, i_max;
str->value = (char *)rule->op_param;
str->value_len = strlen(str->value);
if (error_msg == NULL) return -1;
*error_msg = NULL;
if (match == NULL) {
if (str->value == NULL) {
*error_msg = "Internal Error: match string is null.";
return -1;
}
expand_macros(msr, str, rule, msr->mp);
match = (const char *)str->value;
match_length = str->value_len;
/* If the given target is null we give up without a match */
if (var->value == NULL) {
/* No match. */
return 0;
}
target = var->value;
target_length = var->value_len;
/* These are impossible to match */
if ((match_length == 0) || (target_length > match_length)) {
/* No match. */
return 0;
}
/* scan for first character, then compare from there until we
* have a match or there is no room left in the target
*/
msr_log(msr, 9, "match[%d]='%s' target[%d]='%s'", match_length, match, target_length, target);
i_max = match_length - target_length;
for (i = 0; i <= i_max; i++) {
if (match[i] == target[0]) {
if (strncmp(target, (match + i), target_length) == 0) {
/* match. */
*error_msg = apr_psprintf(msr->mp, "String match %s=\"%s\" within \"%s\".",
var->name,
log_escape_ex(msr->mp, target, target_length),
log_escape_ex(msr->mp, match, match_length));
return 1;
}
}
}
/* No match. */
return 0;
}
/* contains */
static int msre_op_contains_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) {
msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
const char *match = NULL;
const char *target;
unsigned int match_length;
unsigned int target_length = 0;
unsigned int i, i_max;
str->value = (char *)rule->op_param;
str->value_len = strlen(str->value);
if (error_msg == NULL) return -1;
*error_msg = NULL;
if (str->value == NULL) {
*error_msg = "Internal Error: match string is null.";
return -1;
}
expand_macros(msr, str, rule, msr->mp);
match = (const char *)str->value;
match_length = str->value_len;
/* If the given target is null run against an empty
* string. This is a behaviour consistent with previous
* releases.
@@ -211,8 +432,6 @@ static int msre_op_contains_execute(modsec_rec *msr, msre_rule *rule, msre_var *
target_length = var->value_len;
}
match_length = strlen(match);
/* These are impossible to match */
if ((match_length == 0) || (match_length > target_length)) {
/* No match. */
@@ -294,22 +513,31 @@ static int msre_op_streq_execute(modsec_rec *msr, msre_rule *rule, msre_var *var
return 0;
}
/* startsWith */
/* beginsWith */
static int msre_op_startsWith_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) {
const char *match = (const char *)rule->op_param;
static int msre_op_beginsWith_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) {
msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
const char *match = NULL;
const char *target;
unsigned int match_length;
unsigned int target_length;
str->value = (char *)rule->op_param;
str->value_len = strlen(str->value);
if (error_msg == NULL) return -1;
*error_msg = NULL;
if (match == NULL) {
if (str->value == NULL) {
*error_msg = "Internal Error: match string is null.";
return -1;
}
expand_macros(msr, str, rule, msr->mp);
match = (const char *)str->value;
match_length = str->value_len;
/* If the given target is null run against an empty
* string. This is a behaviour consistent with previous
* releases.
@@ -322,8 +550,6 @@ static int msre_op_startsWith_execute(modsec_rec *msr, msre_rule *rule, msre_var
target_length = var->value_len;
}
match_length = strlen(match);
/* These are impossible to match */
if ((match_length == 0) || (match_length > target_length)) {
/* No match. */
@@ -345,19 +571,28 @@ static int msre_op_startsWith_execute(modsec_rec *msr, msre_rule *rule, msre_var
/* endsWith */
static int msre_op_endsWith_execute(modsec_rec *msr, msre_rule *rule, msre_var *var, char **error_msg) {
const char *match = (const char *)rule->op_param;
msc_string *str = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
const char *match = NULL;
const char *target;
unsigned int match_length;
unsigned int target_length;
str->value = (char *)rule->op_param;
str->value_len = strlen(str->value);
if (error_msg == NULL) return -1;
*error_msg = NULL;
if (match == NULL) {
if (str->value == NULL) {
*error_msg = "Internal Error: match string is null.";
return -1;
}
expand_macros(msr, str, rule, msr->mp);
match = (const char *)str->value;
match_length = str->value_len;
/* If the given target is null run against an empty
* string. This is a behaviour consistent with previous
* releases.
@@ -370,8 +605,6 @@ static int msre_op_endsWith_execute(modsec_rec *msr, msre_rule *rule, msre_var *
target_length = var->value_len;
}
match_length = strlen(match);
/* These are impossible to match */
if ((match_length == 0) || (match_length > target_length)) {
/* No match. */
@@ -1197,6 +1430,27 @@ void msre_engine_register_default_operators(msre_engine *engine) {
msre_op_rx_execute
);
/* pm */
msre_engine_op_register(engine,
"pm",
msre_op_pm_param_init,
msre_op_pm_execute
);
/* pmFromFile */
msre_engine_op_register(engine,
"pmFromFile",
msre_op_pmFromFile_param_init,
msre_op_pm_execute
);
/* within */
msre_engine_op_register(engine,
"within",
NULL, /* ENH init function to flag var substitution */
msre_op_within_execute
);
/* contains */
msre_engine_op_register(engine,
"contains",
@@ -1211,11 +1465,11 @@ void msre_engine_register_default_operators(msre_engine *engine) {
msre_op_streq_execute
);
/* startsWith */
/* beginsWith */
msre_engine_op_register(engine,
"startsWith",
"beginsWith",
NULL, /* ENH init function to flag var substitution */
msre_op_startsWith_execute
msre_op_beginsWith_execute
);
/* endsWith */

View File

@@ -1,13 +1,11 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2006 Thinking Stone (http://www.thinkingstone.com)
*
* $Id: re_tfns.c,v 1.3 2006/12/04 12:00:24 ivanr Exp $
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Thinking Stone at contact@thinkingstone.com.
* write to Breach Security, Inc. at support@breach.com.
*
*/
#include <ctype.h>

View File

@@ -1,13 +1,11 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2006 Thinking Stone (http://www.thinkingstone.com)
*
* $Id: re_variables.c,v 1.7 2007/01/23 16:08:15 ivanr Exp $
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Thinking Stone at contact@thinkingstone.com.
* write to Breach Security, Inc. at support@breach.com.
*
*/
#include "http_core.h"
@@ -1670,14 +1668,6 @@ static int var_response_status_generate(modsec_rec *msr, msre_var *var, msre_rul
return var_simple_generate(var, vartab, mptmp, value);
}
/* RESPONSE_CONTENT_ENCODING */
static int var_response_content_encoding(modsec_rec *msr, msre_var *var, msre_rule *rule,
apr_table_t *vartab, apr_pool_t *mptmp)
{
return var_simple_generate(var, vartab, mptmp, msr->r->content_encoding);
}
/* RESPONSE_CONTENT_TYPE */
static int var_response_content_type(modsec_rec *msr, msre_var *var, msre_rule *rule,
@@ -2470,17 +2460,6 @@ void msre_engine_register_default_variables(msre_engine *engine) {
PHASE_RESPONSE_HEADERS
);
/* RESPONSE_CONTENT_ENCODING */
msre_engine_variable_register(engine,
"RESPONSE_CONTENT_ENCODING",
VAR_SIMPLE,
0, 0,
NULL,
var_response_content_encoding,
VAR_CACHE,
PHASE_RESPONSE_HEADERS
);
/* RESPONSE_CONTENT_TYPE */
msre_engine_variable_register(engine,
"RESPONSE_CONTENT_TYPE",

810
apache2/utf8tables.h Normal file
View File

@@ -0,0 +1,810 @@
/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2007 Breach Security, Inc. (http://www.breach.com/)
*
* You should have received a copy of the licence along with this
* program (stored in the file "LICENSE"). If the file is missing,
* or if you have any other questions related to the licence, please
* write to Breach Security, Inc. at support@breach.com.
*
*/
#ifndef UTF8TABLES_H_
#define UTF8TABLES_H_
/**
* This include file is used by acmp.c only, it's not included anywhere else
*/
typedef long acmp_utf8_char_t;
static const char utf8_seq_lengths[256] = {
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,
3,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3,
4,4,4,4,4,4,4,4, 5,5,5,5,6,6,6,6,
};
static const acmp_utf8_char_t utf8_offsets[6] = {
0x00000000UL, 0x00003080UL, 0x000E2080UL,
0x03C82080UL, 0xFA082080UL, 0x82082080UL
};
/**
* How many element pairs are there in utf8_lcase_map
*/
#define UTF8_LCASEMAP_LEN 759
/**
* Table mapping is from PHP's mbstring extension, maps uppercase
*/
static const acmp_utf8_char_t utf8_lcase_map[UTF8_LCASEMAP_LEN * 2] = {
0x00000061, 0x00000041,
0x00000062, 0x00000042,
0x00000063, 0x00000043,
0x00000064, 0x00000044,
0x00000065, 0x00000045,
0x00000066, 0x00000046,
0x00000067, 0x00000047,
0x00000068, 0x00000048,
0x00000069, 0x00000049,
0x0000006a, 0x0000004a,
0x0000006b, 0x0000004b,
0x0000006c, 0x0000004c,
0x0000006d, 0x0000004d,
0x0000006e, 0x0000004e,
0x0000006f, 0x0000004f,
0x00000070, 0x00000050,
0x00000071, 0x00000051,
0x00000072, 0x00000052,
0x00000073, 0x00000053,
0x00000074, 0x00000054,
0x00000075, 0x00000055,
0x00000076, 0x00000056,
0x00000077, 0x00000057,
0x00000078, 0x00000058,
0x00000079, 0x00000059,
0x0000007a, 0x0000005a,
0x000000b5, 0x0000039c,
0x000000e0, 0x000000c0,
0x000000e1, 0x000000c1,
0x000000e2, 0x000000c2,
0x000000e3, 0x000000c3,
0x000000e4, 0x000000c4,
0x000000e5, 0x000000c5,
0x000000e6, 0x000000c6,
0x000000e7, 0x000000c7,
0x000000e8, 0x000000c8,
0x000000e9, 0x000000c9,
0x000000ea, 0x000000ca,
0x000000eb, 0x000000cb,
0x000000ec, 0x000000cc,
0x000000ed, 0x000000cd,
0x000000ee, 0x000000ce,
0x000000ef, 0x000000cf,
0x000000f0, 0x000000d0,
0x000000f1, 0x000000d1,
0x000000f2, 0x000000d2,
0x000000f3, 0x000000d3,
0x000000f4, 0x000000d4,
0x000000f5, 0x000000d5,
0x000000f6, 0x000000d6,
0x000000f8, 0x000000d8,
0x000000f9, 0x000000d9,
0x000000fa, 0x000000da,
0x000000fb, 0x000000db,
0x000000fc, 0x000000dc,
0x000000fd, 0x000000dd,
0x000000fe, 0x000000de,
0x000000ff, 0x00000178,
0x00000101, 0x00000100,
0x00000103, 0x00000102,
0x00000105, 0x00000104,
0x00000107, 0x00000106,
0x00000109, 0x00000108,
0x0000010b, 0x0000010a,
0x0000010d, 0x0000010c,
0x0000010f, 0x0000010e,
0x00000111, 0x00000110,
0x00000113, 0x00000112,
0x00000115, 0x00000114,
0x00000117, 0x00000116,
0x00000119, 0x00000118,
0x0000011b, 0x0000011a,
0x0000011d, 0x0000011c,
0x0000011f, 0x0000011e,
0x00000121, 0x00000120,
0x00000123, 0x00000122,
0x00000125, 0x00000124,
0x00000127, 0x00000126,
0x00000129, 0x00000128,
0x0000012b, 0x0000012a,
0x0000012d, 0x0000012c,
0x0000012f, 0x0000012e,
0x00000131, 0x00000049,
0x00000133, 0x00000132,
0x00000135, 0x00000134,
0x00000137, 0x00000136,
0x0000013a, 0x00000139,
0x0000013c, 0x0000013b,
0x0000013e, 0x0000013d,
0x00000140, 0x0000013f,
0x00000142, 0x00000141,
0x00000144, 0x00000143,
0x00000146, 0x00000145,
0x00000148, 0x00000147,
0x0000014b, 0x0000014a,
0x0000014d, 0x0000014c,
0x0000014f, 0x0000014e,
0x00000151, 0x00000150,
0x00000153, 0x00000152,
0x00000155, 0x00000154,
0x00000157, 0x00000156,
0x00000159, 0x00000158,
0x0000015b, 0x0000015a,
0x0000015d, 0x0000015c,
0x0000015f, 0x0000015e,
0x00000161, 0x00000160,
0x00000163, 0x00000162,
0x00000165, 0x00000164,
0x00000167, 0x00000166,
0x00000169, 0x00000168,
0x0000016b, 0x0000016a,
0x0000016d, 0x0000016c,
0x0000016f, 0x0000016e,
0x00000171, 0x00000170,
0x00000173, 0x00000172,
0x00000175, 0x00000174,
0x00000177, 0x00000176,
0x0000017a, 0x00000179,
0x0000017c, 0x0000017b,
0x0000017e, 0x0000017d,
0x0000017f, 0x00000053,
0x00000183, 0x00000182,
0x00000185, 0x00000184,
0x00000188, 0x00000187,
0x0000018c, 0x0000018b,
0x00000192, 0x00000191,
0x00000195, 0x000001f6,
0x00000199, 0x00000198,
0x0000019e, 0x00000220,
0x000001a1, 0x000001a0,
0x000001a3, 0x000001a2,
0x000001a5, 0x000001a4,
0x000001a8, 0x000001a7,
0x000001ad, 0x000001ac,
0x000001b0, 0x000001af,
0x000001b4, 0x000001b3,
0x000001b6, 0x000001b5,
0x000001b9, 0x000001b8,
0x000001bd, 0x000001bc,
0x000001bf, 0x000001f7,
0x000001c6, 0x000001c4,
0x000001c9, 0x000001c7,
0x000001cc, 0x000001ca,
0x000001ce, 0x000001cd,
0x000001d0, 0x000001cf,
0x000001d2, 0x000001d1,
0x000001d4, 0x000001d3,
0x000001d6, 0x000001d5,
0x000001d8, 0x000001d7,
0x000001da, 0x000001d9,
0x000001dc, 0x000001db,
0x000001dd, 0x0000018e,
0x000001df, 0x000001de,
0x000001e1, 0x000001e0,
0x000001e3, 0x000001e2,
0x000001e5, 0x000001e4,
0x000001e7, 0x000001e6,
0x000001e9, 0x000001e8,
0x000001eb, 0x000001ea,
0x000001ed, 0x000001ec,
0x000001ef, 0x000001ee,
0x000001f3, 0x000001f1,
0x000001f5, 0x000001f4,
0x000001f9, 0x000001f8,
0x000001fb, 0x000001fa,
0x000001fd, 0x000001fc,
0x000001ff, 0x000001fe,
0x00000201, 0x00000200,
0x00000203, 0x00000202,
0x00000205, 0x00000204,
0x00000207, 0x00000206,
0x00000209, 0x00000208,
0x0000020b, 0x0000020a,
0x0000020d, 0x0000020c,
0x0000020f, 0x0000020e,
0x00000211, 0x00000210,
0x00000213, 0x00000212,
0x00000215, 0x00000214,
0x00000217, 0x00000216,
0x00000219, 0x00000218,
0x0000021b, 0x0000021a,
0x0000021d, 0x0000021c,
0x0000021f, 0x0000021e,
0x00000223, 0x00000222,
0x00000225, 0x00000224,
0x00000227, 0x00000226,
0x00000229, 0x00000228,
0x0000022b, 0x0000022a,
0x0000022d, 0x0000022c,
0x0000022f, 0x0000022e,
0x00000231, 0x00000230,
0x00000233, 0x00000232,
0x00000253, 0x00000181,
0x00000254, 0x00000186,
0x00000256, 0x00000189,
0x00000257, 0x0000018a,
0x00000259, 0x0000018f,
0x0000025b, 0x00000190,
0x00000260, 0x00000193,
0x00000263, 0x00000194,
0x00000268, 0x00000197,
0x00000269, 0x00000196,
0x0000026f, 0x0000019c,
0x00000272, 0x0000019d,
0x00000275, 0x0000019f,
0x00000280, 0x000001a6,
0x00000283, 0x000001a9,
0x00000288, 0x000001ae,
0x0000028a, 0x000001b1,
0x0000028b, 0x000001b2,
0x00000292, 0x000001b7,
0x00000345, 0x00000399,
0x000003ac, 0x00000386,
0x000003ad, 0x00000388,
0x000003ae, 0x00000389,
0x000003af, 0x0000038a,
0x000003b1, 0x00000391,
0x000003b2, 0x00000392,
0x000003b3, 0x00000393,
0x000003b4, 0x00000394,
0x000003b5, 0x00000395,
0x000003b6, 0x00000396,
0x000003b7, 0x00000397,
0x000003b8, 0x00000398,
0x000003b9, 0x00000399,
0x000003ba, 0x0000039a,
0x000003bb, 0x0000039b,
0x000003bc, 0x0000039c,
0x000003bd, 0x0000039d,
0x000003be, 0x0000039e,
0x000003bf, 0x0000039f,
0x000003c0, 0x000003a0,
0x000003c1, 0x000003a1,
0x000003c2, 0x000003a3,
0x000003c3, 0x000003a3,
0x000003c4, 0x000003a4,
0x000003c5, 0x000003a5,
0x000003c6, 0x000003a6,
0x000003c7, 0x000003a7,
0x000003c8, 0x000003a8,
0x000003c9, 0x000003a9,
0x000003ca, 0x000003aa,
0x000003cb, 0x000003ab,
0x000003cc, 0x0000038c,
0x000003cd, 0x0000038e,
0x000003ce, 0x0000038f,
0x000003d0, 0x00000392,
0x000003d1, 0x00000398,
0x000003d5, 0x000003a6,
0x000003d6, 0x000003a0,
0x000003d9, 0x000003d8,
0x000003db, 0x000003da,
0x000003dd, 0x000003dc,
0x000003df, 0x000003de,
0x000003e1, 0x000003e0,
0x000003e3, 0x000003e2,
0x000003e5, 0x000003e4,
0x000003e7, 0x000003e6,
0x000003e9, 0x000003e8,
0x000003eb, 0x000003ea,
0x000003ed, 0x000003ec,
0x000003ef, 0x000003ee,
0x000003f0, 0x0000039a,
0x000003f1, 0x000003a1,
0x000003f2, 0x000003a3,
0x000003f5, 0x00000395,
0x00000430, 0x00000410,
0x00000431, 0x00000411,
0x00000432, 0x00000412,
0x00000433, 0x00000413,
0x00000434, 0x00000414,
0x00000435, 0x00000415,
0x00000436, 0x00000416,
0x00000437, 0x00000417,
0x00000438, 0x00000418,
0x00000439, 0x00000419,
0x0000043a, 0x0000041a,
0x0000043b, 0x0000041b,
0x0000043c, 0x0000041c,
0x0000043d, 0x0000041d,
0x0000043e, 0x0000041e,
0x0000043f, 0x0000041f,
0x00000440, 0x00000420,
0x00000441, 0x00000421,
0x00000442, 0x00000422,
0x00000443, 0x00000423,
0x00000444, 0x00000424,
0x00000445, 0x00000425,
0x00000446, 0x00000426,
0x00000447, 0x00000427,
0x00000448, 0x00000428,
0x00000449, 0x00000429,
0x0000044a, 0x0000042a,
0x0000044b, 0x0000042b,
0x0000044c, 0x0000042c,
0x0000044d, 0x0000042d,
0x0000044e, 0x0000042e,
0x0000044f, 0x0000042f,
0x00000450, 0x00000400,
0x00000451, 0x00000401,
0x00000452, 0x00000402,
0x00000453, 0x00000403,
0x00000454, 0x00000404,
0x00000455, 0x00000405,
0x00000456, 0x00000406,
0x00000457, 0x00000407,
0x00000458, 0x00000408,
0x00000459, 0x00000409,
0x0000045a, 0x0000040a,
0x0000045b, 0x0000040b,
0x0000045c, 0x0000040c,
0x0000045d, 0x0000040d,
0x0000045e, 0x0000040e,
0x0000045f, 0x0000040f,
0x00000461, 0x00000460,
0x00000463, 0x00000462,
0x00000465, 0x00000464,
0x00000467, 0x00000466,
0x00000469, 0x00000468,
0x0000046b, 0x0000046a,
0x0000046d, 0x0000046c,
0x0000046f, 0x0000046e,
0x00000471, 0x00000470,
0x00000473, 0x00000472,
0x00000475, 0x00000474,
0x00000477, 0x00000476,
0x00000479, 0x00000478,
0x0000047b, 0x0000047a,
0x0000047d, 0x0000047c,
0x0000047f, 0x0000047e,
0x00000481, 0x00000480,
0x0000048b, 0x0000048a,
0x0000048d, 0x0000048c,
0x0000048f, 0x0000048e,
0x00000491, 0x00000490,
0x00000493, 0x00000492,
0x00000495, 0x00000494,
0x00000497, 0x00000496,
0x00000499, 0x00000498,
0x0000049b, 0x0000049a,
0x0000049d, 0x0000049c,
0x0000049f, 0x0000049e,
0x000004a1, 0x000004a0,
0x000004a3, 0x000004a2,
0x000004a5, 0x000004a4,
0x000004a7, 0x000004a6,
0x000004a9, 0x000004a8,
0x000004ab, 0x000004aa,
0x000004ad, 0x000004ac,
0x000004af, 0x000004ae,
0x000004b1, 0x000004b0,
0x000004b3, 0x000004b2,
0x000004b5, 0x000004b4,
0x000004b7, 0x000004b6,
0x000004b9, 0x000004b8,
0x000004bb, 0x000004ba,
0x000004bd, 0x000004bc,
0x000004bf, 0x000004be,
0x000004c2, 0x000004c1,
0x000004c4, 0x000004c3,
0x000004c6, 0x000004c5,
0x000004c8, 0x000004c7,
0x000004ca, 0x000004c9,
0x000004cc, 0x000004cb,
0x000004ce, 0x000004cd,
0x000004d1, 0x000004d0,
0x000004d3, 0x000004d2,
0x000004d5, 0x000004d4,
0x000004d7, 0x000004d6,
0x000004d9, 0x000004d8,
0x000004db, 0x000004da,
0x000004dd, 0x000004dc,
0x000004df, 0x000004de,
0x000004e1, 0x000004e0,
0x000004e3, 0x000004e2,
0x000004e5, 0x000004e4,
0x000004e7, 0x000004e6,
0x000004e9, 0x000004e8,
0x000004eb, 0x000004ea,
0x000004ed, 0x000004ec,
0x000004ef, 0x000004ee,
0x000004f1, 0x000004f0,
0x000004f3, 0x000004f2,
0x000004f5, 0x000004f4,
0x000004f9, 0x000004f8,
0x00000501, 0x00000500,
0x00000503, 0x00000502,
0x00000505, 0x00000504,
0x00000507, 0x00000506,
0x00000509, 0x00000508,
0x0000050b, 0x0000050a,
0x0000050d, 0x0000050c,
0x0000050f, 0x0000050e,
0x00000561, 0x00000531,
0x00000562, 0x00000532,
0x00000563, 0x00000533,
0x00000564, 0x00000534,
0x00000565, 0x00000535,
0x00000566, 0x00000536,
0x00000567, 0x00000537,
0x00000568, 0x00000538,
0x00000569, 0x00000539,
0x0000056a, 0x0000053a,
0x0000056b, 0x0000053b,
0x0000056c, 0x0000053c,
0x0000056d, 0x0000053d,
0x0000056e, 0x0000053e,
0x0000056f, 0x0000053f,
0x00000570, 0x00000540,
0x00000571, 0x00000541,
0x00000572, 0x00000542,
0x00000573, 0x00000543,
0x00000574, 0x00000544,
0x00000575, 0x00000545,
0x00000576, 0x00000546,
0x00000577, 0x00000547,
0x00000578, 0x00000548,
0x00000579, 0x00000549,
0x0000057a, 0x0000054a,
0x0000057b, 0x0000054b,
0x0000057c, 0x0000054c,
0x0000057d, 0x0000054d,
0x0000057e, 0x0000054e,
0x0000057f, 0x0000054f,
0x00000580, 0x00000550,
0x00000581, 0x00000551,
0x00000582, 0x00000552,
0x00000583, 0x00000553,
0x00000584, 0x00000554,
0x00000585, 0x00000555,
0x00000586, 0x00000556,
0x00001e01, 0x00001e00,
0x00001e03, 0x00001e02,
0x00001e05, 0x00001e04,
0x00001e07, 0x00001e06,
0x00001e09, 0x00001e08,
0x00001e0b, 0x00001e0a,
0x00001e0d, 0x00001e0c,
0x00001e0f, 0x00001e0e,
0x00001e11, 0x00001e10,
0x00001e13, 0x00001e12,
0x00001e15, 0x00001e14,
0x00001e17, 0x00001e16,
0x00001e19, 0x00001e18,
0x00001e1b, 0x00001e1a,
0x00001e1d, 0x00001e1c,
0x00001e1f, 0x00001e1e,
0x00001e21, 0x00001e20,
0x00001e23, 0x00001e22,
0x00001e25, 0x00001e24,
0x00001e27, 0x00001e26,
0x00001e29, 0x00001e28,
0x00001e2b, 0x00001e2a,
0x00001e2d, 0x00001e2c,
0x00001e2f, 0x00001e2e,
0x00001e31, 0x00001e30,
0x00001e33, 0x00001e32,
0x00001e35, 0x00001e34,
0x00001e37, 0x00001e36,
0x00001e39, 0x00001e38,
0x00001e3b, 0x00001e3a,
0x00001e3d, 0x00001e3c,
0x00001e3f, 0x00001e3e,
0x00001e41, 0x00001e40,
0x00001e43, 0x00001e42,
0x00001e45, 0x00001e44,
0x00001e47, 0x00001e46,
0x00001e49, 0x00001e48,
0x00001e4b, 0x00001e4a,
0x00001e4d, 0x00001e4c,
0x00001e4f, 0x00001e4e,
0x00001e51, 0x00001e50,
0x00001e53, 0x00001e52,
0x00001e55, 0x00001e54,
0x00001e57, 0x00001e56,
0x00001e59, 0x00001e58,
0x00001e5b, 0x00001e5a,
0x00001e5d, 0x00001e5c,
0x00001e5f, 0x00001e5e,
0x00001e61, 0x00001e60,
0x00001e63, 0x00001e62,
0x00001e65, 0x00001e64,
0x00001e67, 0x00001e66,
0x00001e69, 0x00001e68,
0x00001e6b, 0x00001e6a,
0x00001e6d, 0x00001e6c,
0x00001e6f, 0x00001e6e,
0x00001e71, 0x00001e70,
0x00001e73, 0x00001e72,
0x00001e75, 0x00001e74,
0x00001e77, 0x00001e76,
0x00001e79, 0x00001e78,
0x00001e7b, 0x00001e7a,
0x00001e7d, 0x00001e7c,
0x00001e7f, 0x00001e7e,
0x00001e81, 0x00001e80,
0x00001e83, 0x00001e82,
0x00001e85, 0x00001e84,
0x00001e87, 0x00001e86,
0x00001e89, 0x00001e88,
0x00001e8b, 0x00001e8a,
0x00001e8d, 0x00001e8c,
0x00001e8f, 0x00001e8e,
0x00001e91, 0x00001e90,
0x00001e93, 0x00001e92,
0x00001e95, 0x00001e94,
0x00001e9b, 0x00001e60,
0x00001ea1, 0x00001ea0,
0x00001ea3, 0x00001ea2,
0x00001ea5, 0x00001ea4,
0x00001ea7, 0x00001ea6,
0x00001ea9, 0x00001ea8,
0x00001eab, 0x00001eaa,
0x00001ead, 0x00001eac,
0x00001eaf, 0x00001eae,
0x00001eb1, 0x00001eb0,
0x00001eb3, 0x00001eb2,
0x00001eb5, 0x00001eb4,
0x00001eb7, 0x00001eb6,
0x00001eb9, 0x00001eb8,
0x00001ebb, 0x00001eba,
0x00001ebd, 0x00001ebc,
0x00001ebf, 0x00001ebe,
0x00001ec1, 0x00001ec0,
0x00001ec3, 0x00001ec2,
0x00001ec5, 0x00001ec4,
0x00001ec7, 0x00001ec6,
0x00001ec9, 0x00001ec8,
0x00001ecb, 0x00001eca,
0x00001ecd, 0x00001ecc,
0x00001ecf, 0x00001ece,
0x00001ed1, 0x00001ed0,
0x00001ed3, 0x00001ed2,
0x00001ed5, 0x00001ed4,
0x00001ed7, 0x00001ed6,
0x00001ed9, 0x00001ed8,
0x00001edb, 0x00001eda,
0x00001edd, 0x00001edc,
0x00001edf, 0x00001ede,
0x00001ee1, 0x00001ee0,
0x00001ee3, 0x00001ee2,
0x00001ee5, 0x00001ee4,
0x00001ee7, 0x00001ee6,
0x00001ee9, 0x00001ee8,
0x00001eeb, 0x00001eea,
0x00001eed, 0x00001eec,
0x00001eef, 0x00001eee,
0x00001ef1, 0x00001ef0,
0x00001ef3, 0x00001ef2,
0x00001ef5, 0x00001ef4,
0x00001ef7, 0x00001ef6,
0x00001ef9, 0x00001ef8,
0x00001f00, 0x00001f08,
0x00001f01, 0x00001f09,
0x00001f02, 0x00001f0a,
0x00001f03, 0x00001f0b,
0x00001f04, 0x00001f0c,
0x00001f05, 0x00001f0d,
0x00001f06, 0x00001f0e,
0x00001f07, 0x00001f0f,
0x00001f10, 0x00001f18,
0x00001f11, 0x00001f19,
0x00001f12, 0x00001f1a,
0x00001f13, 0x00001f1b,
0x00001f14, 0x00001f1c,
0x00001f15, 0x00001f1d,
0x00001f20, 0x00001f28,
0x00001f21, 0x00001f29,
0x00001f22, 0x00001f2a,
0x00001f23, 0x00001f2b,
0x00001f24, 0x00001f2c,
0x00001f25, 0x00001f2d,
0x00001f26, 0x00001f2e,
0x00001f27, 0x00001f2f,
0x00001f30, 0x00001f38,
0x00001f31, 0x00001f39,
0x00001f32, 0x00001f3a,
0x00001f33, 0x00001f3b,
0x00001f34, 0x00001f3c,
0x00001f35, 0x00001f3d,
0x00001f36, 0x00001f3e,
0x00001f37, 0x00001f3f,
0x00001f40, 0x00001f48,
0x00001f41, 0x00001f49,
0x00001f42, 0x00001f4a,
0x00001f43, 0x00001f4b,
0x00001f44, 0x00001f4c,
0x00001f45, 0x00001f4d,
0x00001f51, 0x00001f59,
0x00001f53, 0x00001f5b,
0x00001f55, 0x00001f5d,
0x00001f57, 0x00001f5f,
0x00001f60, 0x00001f68,
0x00001f61, 0x00001f69,
0x00001f62, 0x00001f6a,
0x00001f63, 0x00001f6b,
0x00001f64, 0x00001f6c,
0x00001f65, 0x00001f6d,
0x00001f66, 0x00001f6e,
0x00001f67, 0x00001f6f,
0x00001f70, 0x00001fba,
0x00001f71, 0x00001fbb,
0x00001f72, 0x00001fc8,
0x00001f73, 0x00001fc9,
0x00001f74, 0x00001fca,
0x00001f75, 0x00001fcb,
0x00001f76, 0x00001fda,
0x00001f77, 0x00001fdb,
0x00001f78, 0x00001ff8,
0x00001f79, 0x00001ff9,
0x00001f7a, 0x00001fea,
0x00001f7b, 0x00001feb,
0x00001f7c, 0x00001ffa,
0x00001f7d, 0x00001ffb,
0x00001f80, 0x00001f88,
0x00001f81, 0x00001f89,
0x00001f82, 0x00001f8a,
0x00001f83, 0x00001f8b,
0x00001f84, 0x00001f8c,
0x00001f85, 0x00001f8d,
0x00001f86, 0x00001f8e,
0x00001f87, 0x00001f8f,
0x00001f90, 0x00001f98,
0x00001f91, 0x00001f99,
0x00001f92, 0x00001f9a,
0x00001f93, 0x00001f9b,
0x00001f94, 0x00001f9c,
0x00001f95, 0x00001f9d,
0x00001f96, 0x00001f9e,
0x00001f97, 0x00001f9f,
0x00001fa0, 0x00001fa8,
0x00001fa1, 0x00001fa9,
0x00001fa2, 0x00001faa,
0x00001fa3, 0x00001fab,
0x00001fa4, 0x00001fac,
0x00001fa5, 0x00001fad,
0x00001fa6, 0x00001fae,
0x00001fa7, 0x00001faf,
0x00001fb0, 0x00001fb8,
0x00001fb1, 0x00001fb9,
0x00001fb3, 0x00001fbc,
0x00001fbe, 0x00000399,
0x00001fc3, 0x00001fcc,
0x00001fd0, 0x00001fd8,
0x00001fd1, 0x00001fd9,
0x00001fe0, 0x00001fe8,
0x00001fe1, 0x00001fe9,
0x00001fe5, 0x00001fec,
0x00001ff3, 0x00001ffc,
0x00002170, 0x00002160,
0x00002171, 0x00002161,
0x00002172, 0x00002162,
0x00002173, 0x00002163,
0x00002174, 0x00002164,
0x00002175, 0x00002165,
0x00002176, 0x00002166,
0x00002177, 0x00002167,
0x00002178, 0x00002168,
0x00002179, 0x00002169,
0x0000217a, 0x0000216a,
0x0000217b, 0x0000216b,
0x0000217c, 0x0000216c,
0x0000217d, 0x0000216d,
0x0000217e, 0x0000216e,
0x0000217f, 0x0000216f,
0x000024d0, 0x000024b6,
0x000024d1, 0x000024b7,
0x000024d2, 0x000024b8,
0x000024d3, 0x000024b9,
0x000024d4, 0x000024ba,
0x000024d5, 0x000024bb,
0x000024d6, 0x000024bc,
0x000024d7, 0x000024bd,
0x000024d8, 0x000024be,
0x000024d9, 0x000024bf,
0x000024da, 0x000024c0,
0x000024db, 0x000024c1,
0x000024dc, 0x000024c2,
0x000024dd, 0x000024c3,
0x000024de, 0x000024c4,
0x000024df, 0x000024c5,
0x000024e0, 0x000024c6,
0x000024e1, 0x000024c7,
0x000024e2, 0x000024c8,
0x000024e3, 0x000024c9,
0x000024e4, 0x000024ca,
0x000024e5, 0x000024cb,
0x000024e6, 0x000024cc,
0x000024e7, 0x000024cd,
0x000024e8, 0x000024ce,
0x000024e9, 0x000024cf,
0x0000ff41, 0x0000ff21,
0x0000ff42, 0x0000ff22,
0x0000ff43, 0x0000ff23,
0x0000ff44, 0x0000ff24,
0x0000ff45, 0x0000ff25,
0x0000ff46, 0x0000ff26,
0x0000ff47, 0x0000ff27,
0x0000ff48, 0x0000ff28,
0x0000ff49, 0x0000ff29,
0x0000ff4a, 0x0000ff2a,
0x0000ff4b, 0x0000ff2b,
0x0000ff4c, 0x0000ff2c,
0x0000ff4d, 0x0000ff2d,
0x0000ff4e, 0x0000ff2e,
0x0000ff4f, 0x0000ff2f,
0x0000ff50, 0x0000ff30,
0x0000ff51, 0x0000ff31,
0x0000ff52, 0x0000ff32,
0x0000ff53, 0x0000ff33,
0x0000ff54, 0x0000ff34,
0x0000ff55, 0x0000ff35,
0x0000ff56, 0x0000ff36,
0x0000ff57, 0x0000ff37,
0x0000ff58, 0x0000ff38,
0x0000ff59, 0x0000ff39,
0x0000ff5a, 0x0000ff3a,
0x00010428, 0x00010400,
0x00010429, 0x00010401,
0x0001042a, 0x00010402,
0x0001042b, 0x00010403,
0x0001042c, 0x00010404,
0x0001042d, 0x00010405,
0x0001042e, 0x00010406,
0x0001042f, 0x00010407,
0x00010430, 0x00010408,
0x00010431, 0x00010409,
0x00010432, 0x0001040a,
0x00010433, 0x0001040b,
0x00010434, 0x0001040c,
0x00010435, 0x0001040d,
0x00010436, 0x0001040e,
0x00010437, 0x0001040f,
0x00010438, 0x00010410,
0x00010439, 0x00010411,
0x0001043a, 0x00010412,
0x0001043b, 0x00010413,
0x0001043c, 0x00010414,
0x0001043d, 0x00010415,
0x0001043e, 0x00010416,
0x0001043f, 0x00010417,
0x00010440, 0x00010418,
0x00010441, 0x00010419,
0x00010442, 0x0001041a,
0x00010443, 0x0001041b,
0x00010444, 0x0001041c,
0x00010445, 0x0001041d,
0x00010446, 0x0001041e,
0x00010447, 0x0001041f,
0x00010448, 0x00010420,
0x00010449, 0x00010421,
0x0001044a, 0x00010422,
0x0001044b, 0x00010423,
0x0001044c, 0x00010424,
0x0001044d, 0x00010425,
};
#endif /*UTF8TABLES_H_*/