ModSecurity/apache2/modsecurity.h
Felipe Zimmerle a15f8813e9 Honor the SecRuleEngine while filtering connections
The SecRuleEngine has the capability to Enable, Disable or even to place the
ModSecurity in DetectionOnly mode. The SecReadStateLimit and SecWriteStateLimit
were not honoring such state, due the fact that our configuration belongs to
requests not to connections, the only struct that exists while those filters
are placed. By adding a global variable "conn_limits_filter_state" we are now
able to identify the current state of the ModSecurity, once the configuration
is loaded this variable is set and used by the connections filters.
2014-03-31 16:22:10 -07:00

719 lines
22 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* ModSecurity for Apache 2.x, http://www.modsecurity.org/
* Copyright (c) 2004-2013 Trustwave Holdings, Inc. (http://www.trustwave.com/)
*
* You may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* If any of the files related to licensing are missing or if you have any
* other questions related to licensing please contact Trustwave Holdings, Inc.
* directly using the email address security@modsecurity.org.
*/
#ifndef _MODSECURITY_H_
#define _MODSECURITY_H_
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <libxml/tree.h>
#include <libxml/HTMLparser.h>
typedef struct rule_exception rule_exception;
typedef struct rule_exception hash_method;
typedef struct modsec_rec modsec_rec;
typedef struct directory_config directory_config;
typedef struct error_message_t error_message_t;
typedef struct msc_engine msc_engine;
typedef struct msc_data_chunk msc_data_chunk;
typedef struct msc_arg msc_arg;
typedef struct msc_string msc_string;
typedef struct msc_parm msc_parm;
#include "msc_release.h"
#include "msc_logging.h"
#include "msc_multipart.h"
#include "msc_pcre.h"
#include "msc_util.h"
#include "msc_json.h"
#include "msc_xml.h"
#include "msc_tree.h"
#include "msc_geo.h"
#include "msc_gsb.h"
#include "msc_unicode.h"
#include "re.h"
#include "msc_crypt.h"
#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"
#if defined(WITH_LUA)
#include "msc_lua.h"
#endif
#define PHASE_REQUEST_HEADERS 1
#define PHASE_REQUEST_BODY 2
#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 -1l
#define NOT_SET_P ((void *)-1l)
#define CREATEMODE ( APR_UREAD | APR_UWRITE | APR_GREAD )
#define CREATEMODE_DIR ( APR_UREAD | APR_UWRITE | APR_UEXECUTE | APR_GREAD | APR_GEXECUTE )
#if defined(NETWARE)
#define CREATEMODE_UNISTD ( S_IREAD | S_IWRITE )
#elif defined(WIN32)
#define CREATEMODE_UNISTD ( _S_IREAD | _S_IWRITE )
#else
#define CREATEMODE_UNISTD ( S_IRUSR | S_IWUSR | S_IRGRP )
#endif
#if !defined(O_BINARY)
#define O_BINARY (0)
#endif
#ifndef PIPE_BUF
#define PIPE_BUF (512)
#endif
#define REQUEST_BODY_HARD_LIMIT 1073741824L
#define REQUEST_BODY_DEFAULT_INMEMORY_LIMIT 131072
#define REQUEST_BODY_DEFAULT_LIMIT 134217728
#define REQUEST_BODY_NO_FILES_DEFAULT_LIMIT 1048576
#define RESPONSE_BODY_DEFAULT_LIMIT 524288
#define RESPONSE_BODY_HARD_LIMIT 1073741824L
#define RESPONSE_BODY_LIMIT_ACTION_REJECT 0
#define RESPONSE_BODY_LIMIT_ACTION_PARTIAL 1
#define REQUEST_BODY_FORCEBUF_OFF 0
#define REQUEST_BODY_FORCEBUF_ON 1
#define REQUEST_BODY_LIMIT_ACTION_REJECT 0
#define REQUEST_BODY_LIMIT_ACTION_PARTIAL 1
#define SECACTION_TARGETS "REMOTE_ADDR"
#define SECACTION_ARGS "@unconditionalMatch"
#define SECMARKER_TARGETS "REMOTE_ADDR"
#define SECMARKER_ARGS "@noMatch"
#define SECMARKER_BASE_ACTIONS "t:none,pass,marker:"
#if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE)
#include "unixd.h"
#define __SET_MUTEX_PERMS
#endif
#define COOKIES_V0 0
#define COOKIES_V1 1
#ifdef WIN32
#include <direct.h>
#else
#include <sys/types.h>
#include <unistd.h>
#endif
#define NOTE_MSR "modsecurity-tx-context"
#define FATAL_ERROR "ModSecurity: Fatal error (memory allocation or unexpected internal error)!"
extern DSOLOCAL char *new_server_signature;
extern DSOLOCAL char *chroot_dir;
extern module AP_MODULE_DECLARE_DATA security2_module;
extern DSOLOCAL const command_rec module_directives[];
extern DSOLOCAL unsigned long int msc_pcre_match_limit;
extern DSOLOCAL unsigned long int msc_pcre_match_limit_recursion;
extern DSOLOCAL int status_engine_state;
extern DSOLOCAL int conn_limits_filter_state;
extern DSOLOCAL unsigned long int conn_read_state_limit;
extern DSOLOCAL TreeRoot *conn_read_state_whitelist;
extern DSOLOCAL TreeRoot *conn_read_state_suspicious_list;
extern DSOLOCAL unsigned long int conn_write_state_limit;
extern DSOLOCAL TreeRoot *conn_write_state_whitelist;
extern DSOLOCAL TreeRoot *conn_write_state_suspicious_list;
extern DSOLOCAL unsigned long int unicode_codepage;
extern DSOLOCAL int *unicode_map_table;
#define RESBODY_STATUS_NOT_READ 0 /* we were not configured to read the body */
#define RESBODY_STATUS_ERROR 1 /* error occured while we were reading the body */
#define RESBODY_STATUS_PARTIAL 2 /* partial body content available in the brigade */
#define RESBODY_STATUS_READ_BRIGADE 3 /* body was read but not flattened */
#define RESBODY_STATUS_READ 4 /* body was read and flattened */
#define IF_STATUS_NONE 0
#define IF_STATUS_WANTS_TO_RUN 1
#define IF_STATUS_COMPLETE 2
#define OF_STATUS_NOT_STARTED 0
#define OF_STATUS_IN_PROGRESS 1
#define OF_STATUS_COMPLETE 2
#define MSC_REQBODY_NONE 0
#define MSC_REQBODY_MEMORY 1
#define MSC_REQBODY_DISK 2
#define ACTION_NONE 0
#define ACTION_DENY 1
#define ACTION_REDIRECT 2
#define ACTION_PROXY 3
#define ACTION_DROP 4
#define ACTION_ALLOW 5
#define ACTION_ALLOW_REQUEST 6
#define ACTION_ALLOW_PHASE 7
#define ACTION_PAUSE 8
#define MODSEC_DISABLED 0
#define MODSEC_DETECTION_ONLY 1
#define MODSEC_ENABLED 2
#define STATUS_ENGINE_ENABLED 1
#define STATUS_ENGINE_DISABLED 0
#define HASH_DISABLED 0
#define HASH_ENABLED 1
#define HASH_URL_HREF_HASH_RX 0
#define HASH_URL_HREF_HASH_PM 1
#define HASH_URL_FACTION_HASH_RX 2
#define HASH_URL_FACTION_HASH_PM 3
#define HASH_URL_LOCATION_HASH_RX 4
#define HASH_URL_LOCATION_HASH_PM 5
#define HASH_URL_IFRAMESRC_HASH_RX 6
#define HASH_URL_IFRAMESRC_HASH_PM 7
#define HASH_URL_FRAMESRC_HASH_RX 8
#define HASH_URL_FRAMESRC_HASH_PM 9
#define HASH_KEYONLY 0
#define HASH_SESSIONID 1
#define HASH_REMOTEIP 2
#define MODSEC_CACHE_DISABLED 0
#define MODSEC_CACHE_ENABLED 1
#define MODSEC_OFFLINE 0
#define MODSEC_ONLINE 1
#define REGEX_CAPTURE_BUFLEN 1024
#define KEEP_FILES_OFF 0
#define KEEP_FILES_ON 1
#define KEEP_FILES_RELEVANT_ONLY 2
#define RULE_EXCEPTION_IMPORT_ID 1
#define RULE_EXCEPTION_IMPORT_MSG 2
#define RULE_EXCEPTION_REMOVE_ID 3
#define RULE_EXCEPTION_REMOVE_MSG 4
#define RULE_EXCEPTION_REMOVE_TAG 5
#define NBSP 160
struct rule_exception {
int type;
const char *param;
void *param_data;
};
struct modsec_rec {
apr_pool_t *mp;
msc_engine *modsecurity;
request_rec *r_early;
request_rec *r;
directory_config *dcfg1;
directory_config *dcfg2;
directory_config *usercfg;
directory_config *txcfg;
unsigned int reqbody_should_exist;
unsigned int reqbody_chunked;
unsigned int phase;
unsigned int phase_request_headers_complete;
unsigned int phase_request_body_complete;
apr_bucket_brigade *if_brigade;
unsigned int if_status;
unsigned int if_started_forwarding;
apr_size_t reqbody_length;
apr_bucket_brigade *of_brigade;
unsigned int of_status;
unsigned int of_done_reading;
unsigned int of_skipping;
unsigned int of_partial;
unsigned int of_is_error;
unsigned int resbody_status;
apr_size_t resbody_length;
char *resbody_data;
unsigned int resbody_contains_html;
apr_size_t stream_input_length;
char *stream_input_data;
apr_size_t stream_output_length;
char *stream_output_data;
unsigned int of_stream_changed;
unsigned int if_stream_changed;
apr_array_header_t *error_messages;
apr_array_header_t *alerts;
const char *txid;
const char *sessionid;
const char *userid;
const char *server_software;
const char *local_addr;
unsigned int local_port;
const char *local_user;
/* client */
const char *remote_addr;
unsigned int remote_port;
const char *remote_user;
/* useragent */
const char *useragent_ip;
/* request */
const char *request_line;
const char *request_method;
const char *request_uri;
const char *query_string;
const char *request_protocol;
const char *hostname;
apr_table_t *request_headers;
apr_off_t request_content_length;
const char *request_content_type;
apr_table_t *arguments;
apr_table_t *arguments_to_sanitize;
apr_table_t *request_headers_to_sanitize;
apr_table_t *response_headers_to_sanitize;
apr_table_t *request_cookies;
apr_table_t *pattern_to_sanitize;
unsigned int urlencoded_error;
unsigned int inbound_error;
unsigned int outbound_error;
unsigned int is_relevant;
apr_table_t *tx_vars;
/* ENH: refactor to allow arbitrary var tables */
apr_table_t *geo_vars;
/* response */
unsigned int response_status;
const char *status_line;
const char *response_protocol;
apr_table_t *response_headers;
unsigned int response_headers_sent;
apr_off_t bytes_sent;
/* modsecurity request body processing stuff */
unsigned int msc_reqbody_storage; /* on disk or in memory */
unsigned int msc_reqbody_spilltodisk;
unsigned int msc_reqbody_read;
apr_pool_t *msc_reqbody_mp; /* this is where chunks are allocated from */
apr_array_header_t *msc_reqbody_chunks; /* data chunks when stored in memory */
unsigned int msc_reqbody_length; /* the amount of data received */
int msc_reqbody_chunk_position; /* used when retrieving the body */
unsigned int msc_reqbody_chunk_offset; /* offset of the chunk currently in use */
msc_data_chunk *msc_reqbody_chunk_current; /* current chunk */
char *msc_reqbody_buffer;
const char *msc_reqbody_filename; /* when stored on disk */
int msc_reqbody_fd;
msc_data_chunk *msc_reqbody_disk_chunk;
const char *msc_reqbody_processor;
int msc_reqbody_error;
const char *msc_reqbody_error_msg;
apr_size_t msc_reqbody_no_files_length;
char *msc_full_request_buffer;
int msc_full_request_length;
char *multipart_filename;
char *multipart_name;
multipart_data *mpd; /* MULTIPART processor data structure */
xml_data *xml; /* XML processor data structure */
#ifdef WITH_YAJL
json_data *json; /* JSON processor data structure */
#endif
/* audit logging */
char *new_auditlog_boundary;
char *new_auditlog_filename;
apr_file_t *new_auditlog_fd;
unsigned int new_auditlog_size;
apr_md5_ctx_t new_auditlog_md5ctx;
unsigned int was_intercepted;
unsigned int rule_was_intercepted;
unsigned int intercept_phase;
msre_actionset *intercept_actionset;
const char *intercept_message;
/* performance measurement */
apr_time_t request_time;
apr_time_t time_phase1;
apr_time_t time_phase2;
apr_time_t time_phase3;
apr_time_t time_phase4;
apr_time_t time_phase5;
apr_time_t time_storage_read;
apr_time_t time_storage_write;
apr_time_t time_logging;
apr_time_t time_gc;
apr_table_t *perf_rules;
apr_array_header_t *matched_rules;
msc_string *matched_var;
int highest_severity;
/* upload */
int upload_extract_files;
int upload_remove_files;
int upload_files_count;
/* other */
apr_table_t *collections_original;
apr_table_t *collections;
apr_table_t *collections_dirty;
/* rule processing temp pool */
apr_pool_t *msc_rule_mptmp;
/* content injection */
const char *content_prepend;
apr_off_t content_prepend_len;
const char *content_append;
apr_off_t content_append_len;
/* data cache */
apr_hash_t *tcache;
apr_size_t tcache_items;
/* removed rules */
apr_array_header_t *removed_rules;
apr_array_header_t *removed_rules_tag;
apr_array_header_t *removed_rules_msg;
/* removed targets */
apr_table_t *removed_targets;
/* When "allow" is executed the variable below is
* updated to contain the scope of the allow action. Set
* at 0 by default, it will have ACTION_ALLOW if we are
* to allow phases 1-4 and ACTION_ALLOW_REQUEST if we
* are to allow phases 1-2 only.
*/
unsigned int allow_scope;
/* matched vars */
apr_table_t *matched_vars;
/* Generic request body processor context to be used by custom parsers. */
void *reqbody_processor_ctx;
htmlDocPtr crypto_html_tree;
#if defined(WITH_LUA)
#ifdef CACHE_LUA
lua_State *L;
#endif
#endif
int msc_sdbm_delete_error;
};
struct directory_config {
apr_pool_t *mp;
msre_ruleset *ruleset;
int is_enabled;
int reqbody_access;
int reqintercept_oe;
int reqbody_buffering;
long int reqbody_inmemory_limit;
long int reqbody_limit;
long int reqbody_no_files_limit;
int resbody_access;
long int of_limit;
apr_table_t *of_mime_types;
int of_mime_types_cleared;
int of_limit_action;
int if_limit_action;
const char *debuglog_name;
int debuglog_level;
apr_file_t *debuglog_fd;
int cookie_format;
int argument_separator;
const char *cookiev0_separator;
int rule_inheritance;
apr_array_header_t *rule_exceptions;
/* -- Audit log -- */
/* Max rule time */
int max_rule_time;
/* Whether audit log should be enabled in the context or not */
int auditlog_flag;
/* AUDITLOG_SERIAL (single file) or AUDITLOG_CONCURRENT (multiple files) */
int auditlog_type;
/* Mode for audit log directories and files */
apr_fileperms_t auditlog_dirperms;
apr_fileperms_t auditlog_fileperms;
/* The name of the audit log file (for the old type), or the
* name of the index file (for the new audit log type)
*/
char *auditlog_name;
/* The name of the secondary index file */
char *auditlog2_name;
/* The file descriptors for the files above */
apr_file_t *auditlog_fd;
apr_file_t *auditlog2_fd;
/* For the new-style audit log only, the path where
* audit log entries will be stored
*/
char *auditlog_storage_dir;
/* A list of parts to include in the new-style audit log
* entry. By default, it contains 'ABCFHZ'. Have a look at
* the AUDITLOG_PART_* constants above to decipher the
* meaning.
*/
char *auditlog_parts;
/* A regular expression that determines if a response
* status is treated as relevant.
*/
msc_regex_t *auditlog_relevant_regex;
/* Upload */
const char *tmp_dir;
const char *upload_dir;
int upload_keep_files;
int upload_validates_files;
int upload_filemode; /* int only so NOT_SET works */
int upload_file_limit;
/* Used only in the configuration phase. */
msre_rule *tmp_chain_starter;
msre_actionset *tmp_default_actionset;
apr_table_t *tmp_rule_placeholders;
/* Misc */
const char *data_dir;
const char *webappid;
const char *sensor_id;
const char *httpBlkey;
/* Content injection. */
int content_injection_enabled;
/* Stream Inspection */
int stream_inbody_inspection;
int stream_outbody_inspection;
/* Geo Lookup */
geo_db *geo;
/* Gsb Lookup */
gsb_db *gsb;
/* Unicode map */
unicode_map *u_map;
/* Cache */
int cache_trans;
int cache_trans_incremental;
apr_size_t cache_trans_min;
apr_size_t cache_trans_max;
apr_size_t cache_trans_maxitems;
/* Array to hold signatures of components, which will
* appear in the ModSecurity signature in the audit log.
*/
apr_array_header_t *component_signatures;
/* Request character encoding. */
const char *request_encoding;
int disable_backend_compression;
/* Collection timeout */
int col_timeout;
/* hash of ids */
apr_hash_t *rule_id_htab;
/* Hash */
apr_array_header_t *hash_method;
const char *crypto_key;
int crypto_key_len;
const char *crypto_param_name;
int hash_is_enabled;
int hash_enforcement;
int crypto_key_add;
int crypto_hash_href_rx;
int crypto_hash_faction_rx;
int crypto_hash_location_rx;
int crypto_hash_iframesrc_rx;
int crypto_hash_framesrc_rx;
int crypto_hash_href_pm;
int crypto_hash_faction_pm;
int crypto_hash_location_pm;
int crypto_hash_iframesrc_pm;
int crypto_hash_framesrc_pm;
/* xml */
int xml_external_entity;
};
struct error_message_t {
const char *file;
int line;
int level;
apr_status_t status;
const char *message;
};
struct msc_engine {
apr_pool_t *mp;
apr_global_mutex_t *auditlog_lock;
apr_global_mutex_t *geo_lock;
msre_engine *msre;
unsigned int processing_mode;
};
struct msc_data_chunk {
char *data;
apr_size_t length;
unsigned int is_permanent;
};
struct msc_arg {
const char *name;
unsigned int name_len;
unsigned int name_origin_offset;
unsigned int name_origin_len;
const char *value;
unsigned int value_len;
unsigned int value_origin_offset;
unsigned int value_origin_len;
const char *origin;
};
struct msc_string {
char *name;
unsigned int name_len;
char *value;
unsigned int value_len;
};
struct msc_parm {
char *value;
int pad_1;
int pad_2;
};
/* Engine functions */
msc_engine DSOLOCAL *modsecurity_create(apr_pool_t *mp, int processing_mode);
int DSOLOCAL modsecurity_init(msc_engine *msce, apr_pool_t *mp);
void DSOLOCAL modsecurity_child_init(msc_engine *msce);
void DSOLOCAL modsecurity_shutdown(msc_engine *msce);
apr_status_t DSOLOCAL modsecurity_tx_init(modsec_rec *msr);
apr_status_t DSOLOCAL modsecurity_process_phase(modsec_rec *msr, unsigned int phase);
/* Request body functions */
apr_status_t DSOLOCAL modsecurity_request_body_start(modsec_rec *msr, char **error_msg);
apr_status_t DSOLOCAL modsecurity_request_body_store(modsec_rec *msr,
const char *data, apr_size_t length, char **error_msg);
apr_status_t DSOLOCAL modsecurity_request_body_end(modsec_rec *msr, char **error_msg);
apr_status_t DSOLOCAL modsecurity_request_body_to_stream(modsec_rec *msr, const char *buffer, int buflen, char **error_msg);
apr_status_t DSOLOCAL modsecurity_request_body_retrieve_start(modsec_rec *msr, char **error_msg);
apr_status_t DSOLOCAL modsecurity_request_body_retrieve_end(modsec_rec *msr);
/* Retrieves up to nbytes bytes of the request body. Returns 1 on
* success, 0 when there is no more data, or -1 on error. On return
* nbytes will contain the number of bytes stored in the buffer.
*/
apr_status_t DSOLOCAL modsecurity_request_body_retrieve(modsec_rec *msr, msc_data_chunk **chunk,
long int nbytes, char **error_msg);
void DSOLOCAL msc_add(modsec_rec *msr, int level, msre_actionset *actionset,
const char *action_message, const char *rule_message);
const char DSOLOCAL *msc_alert_message(modsec_rec *msr, msre_actionset *actionset, const char *action_message,
const char *rule_message);
void DSOLOCAL msc_alert(modsec_rec *msr, int level, msre_actionset *actionset, const char *action_message,
const char *rule_message);
apr_status_t DSOLOCAL modsecurity_request_body_clear(modsec_rec *msr, char **error_msg);
#endif