From a63008b164a2ff64572d6f1f7cd7f31277e39ed1 Mon Sep 17 00:00:00 2001 From: gregwroblewski Date: Thu, 30 Aug 2012 21:00:49 +0000 Subject: [PATCH] Changes from kyprizel. --- .../modsecurity/ngx_http_modsecurity_module.c | 537 +++++++++--------- 1 file changed, 274 insertions(+), 263 deletions(-) diff --git a/nginx/modsecurity/ngx_http_modsecurity_module.c b/nginx/modsecurity/ngx_http_modsecurity_module.c index ddf4ea7d..7e99ad52 100644 --- a/nginx/modsecurity/ngx_http_modsecurity_module.c +++ b/nginx/modsecurity/ngx_http_modsecurity_module.c @@ -29,47 +29,47 @@ extern ngx_module_t ngx_http_modsecurity_module; -typedef struct -{ - ngx_log_t *log; -} ngx_http_modsecurity_main_conf_t; - -typedef struct -{ - ngx_int_t request_processed; - ngx_int_t request_blocked; - ngx_int_t error; - ngx_flag_t enabled; - ngx_str_t config_path; - directory_config *config; +typedef struct { + ngx_flag_t enabled; + char *config_path; + directory_config *config; } ngx_http_modsecurity_loc_conf_t; +typedef struct { + conn_rec *connection; +} ngx_http_modsecurity_ctx_t; + + /* ** Module's registred function/handlers. */ -static ngx_int_t ngx_http_modsecurity_access_handler(ngx_http_request_t *r); -static ngx_int_t ngx_http_modsecurity_init(ngx_conf_t *cf); -static ngx_int_t ngx_http_modsecurity_init_process(ngx_cycle_t *cycle); -static void ngx_http_modsecurity_exit_process(ngx_cycle_t *cycle); -static void *ngx_http_modsecurity_create_loc_conf(ngx_conf_t *cf); -static char *ngx_http_modsecurity_merge_loc_conf(ngx_conf_t *cf, - void *parent, - void *child); -static ngx_int_t ngx_http_read_request_body(ngx_http_request_t *req, - ngx_http_client_body_handler_pt handler); -void *ngx_http_modsecurity_create_main_conf(ngx_conf_t *cf); +static ngx_int_t ngx_http_modsecurity_handler(ngx_http_request_t *r); +static ngx_int_t ngx_http_modsecurity_init(ngx_conf_t *cf); +static ngx_int_t ngx_http_modsecurity_init_process(ngx_cycle_t *cycle); +static void ngx_http_modsecurity_exit_process(ngx_cycle_t *cycle); +static void *ngx_http_modsecurity_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_modsecurity_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child); +//static ngx_int_t ngx_http_read_request_body(ngx_http_request_t *req, ngx_http_client_body_handler_pt handler); +static char *ngx_http_modsecurity_set_config(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); /* command handled by the module */ static ngx_command_t ngx_http_modsecurity_commands[] = { { ngx_string("ModSecurityConfig"), - NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, +#ifdef zzz_ + ngx_http_modsecurity_set_config, + NGX_HTTP_LOC_CONF_OFFSET, + 0, +#else ngx_conf_set_str_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_modsecurity_loc_conf_t, config_path), +#endif NULL }, { ngx_string("ModSecurityEnabled"), - NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF + |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1, ngx_conf_set_flag_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_modsecurity_loc_conf_t, enabled), @@ -82,165 +82,162 @@ static ngx_command_t ngx_http_modsecurity_commands[] = { */ static ngx_http_module_t ngx_http_modsecurity_module_ctx = { - NULL, /* preconfiguration */ - ngx_http_modsecurity_init, /* postconfiguration */ - ngx_http_modsecurity_create_main_conf, /* create main configuration */ - NULL, /* init main configuration */ - NULL, /* create server configuration */ - NULL, /* merge server configuration */ - ngx_http_modsecurity_create_loc_conf, /* create location configuration */ - ngx_http_modsecurity_merge_loc_conf /* merge location configuration */ + NULL, /* preconfiguration */ + ngx_http_modsecurity_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_modsecurity_create_loc_conf, /* create location configuration */ + ngx_http_modsecurity_merge_loc_conf /* merge location configuration */ }; ngx_module_t ngx_http_modsecurity_module = { - NGX_MODULE_V1, - &ngx_http_modsecurity_module_ctx, /* module context */ - ngx_http_modsecurity_commands, /* module directives */ - NGX_HTTP_MODULE, /* module type */ - NULL, /* init master */ - NULL, /* init module */ - ngx_http_modsecurity_init_process, /* init process */ - NULL, /* init thread */ - NULL, /* exit thread */ - ngx_http_modsecurity_exit_process, /* exit process */ - NULL, /* exit master */ - NGX_MODULE_V1_PADDING + NGX_MODULE_V1, + &ngx_http_modsecurity_module_ctx, /* module context */ + ngx_http_modsecurity_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + ngx_http_modsecurity_init_process, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + ngx_http_modsecurity_exit_process, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING }; -#define DEFAULT_MAX_LOC_T 10 - -void * -ngx_http_modsecurity_create_main_conf(ngx_conf_t *cf) -{ - ngx_http_modsecurity_main_conf_t *mc; - - mc = ngx_pcalloc(cf->pool, sizeof(ngx_http_modsecurity_main_conf_t)); - if (!mc) - return (NGX_CONF_ERROR); - - return (mc); -} - - -/* create log conf struct */ +/* create loc conf struct */ static void * ngx_http_modsecurity_create_loc_conf(ngx_conf_t *cf) { - ngx_http_modsecurity_loc_conf_t *conf; - - conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_modsecurity_loc_conf_t)); - if (conf == NULL) - return NULL; - - conf->enabled = NGX_CONF_UNSET; + ngx_http_modsecurity_loc_conf_t *conf; - return (conf); + conf = (ngx_http_modsecurity_loc_conf_t *) ngx_pcalloc(cf->pool, sizeof(ngx_http_modsecurity_loc_conf_t)); + if (conf == NULL) + return NULL; + + conf->enabled = NGX_CONF_UNSET; + conf->config_path = NULL; + conf->config = NULL; + + return conf; } /* merge loc conf */ static char * ngx_http_modsecurity_merge_loc_conf(ngx_conf_t *cf, void *parent, - void *child) + void *child) { - ngx_http_modsecurity_loc_conf_t *prev = parent; - ngx_http_modsecurity_loc_conf_t *conf = child; + ngx_http_modsecurity_loc_conf_t *prev = parent; + ngx_http_modsecurity_loc_conf_t *conf = child; - if(conf->config_path.len == 0) - conf->config_path = prev->config_path; - - ngx_conf_merge_value(conf->enabled, prev->enabled, 0); + ngx_conf_merge_value(conf->enabled, prev->enabled, 0); - return NGX_CONF_OK; + if (conf->config == NULL) { + conf->config = prev->config; + } + + if (conf->config_path == NULL) { + conf->config_path = prev->config_path; + } + + +// ngx_conf_log_error(NGX_LOG_DEBUG_HTTP, cf, 0, +// "merging loc conf: %s", conf->config_path); + + return NGX_CONF_OK; } -void modsecLog(void *obj, int level, char *str) +void +modsecLog(void *obj, int level, char *str) { - if(obj != NULL) - ngx_log_error(NGX_LOG_INFO, (ngx_log_t *)obj, 0, "%s", str); + if (obj != NULL) + ngx_log_error(NGX_LOG_INFO, (ngx_log_t *)obj, 0, "%s", str); } /* -** This function sets up handlers for ACCESS_PHASE, +** This function sets up handlers for PRE_ACCESS_PHASE, */ static ngx_int_t ngx_http_modsecurity_init(ngx_conf_t *cf) { - ngx_http_handler_pt *h; - ngx_http_core_main_conf_t *cmcf; - ngx_http_modsecurity_main_conf_t *main_cf; -// ngx_http_modsecurity_loc_conf_t **loc_cf; -// unsigned int i; + ngx_http_handler_pt *h; + ngx_http_core_main_conf_t *cmcf; - cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); - main_cf = ngx_http_conf_get_module_main_conf(cf, ngx_http_modsecurity_module); - if (cmcf == NULL || - main_cf == NULL) - return (NGX_ERROR); + cmcf = (ngx_http_core_main_conf_t *) ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); + if (cmcf == NULL) { + return NGX_ERROR; + } - /* Register for access phase */ - //h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers); - h = ngx_array_push(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers); - if (h == NULL) - return (NGX_ERROR); - *h = ngx_http_modsecurity_access_handler; - - return (NGX_OK); + /* Register for pre access phase */ + h = ngx_array_push(&cmcf->phases[NGX_HTTP_PRE_ACCESS_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + *h = ngx_http_modsecurity_handler; + + return NGX_OK; } static ngx_int_t ngx_http_modsecurity_init_process(ngx_cycle_t *cycle) { - cycle->log->log_level = NGX_LOG_INFO; + cycle->log->log_level = NGX_LOG_INFO; - modsecSetLogHook(cycle->log, modsecLog); + modsecSetLogHook(cycle->log, modsecLog); - modsecInit(); + modsecInit(); + modsecStartConfig(); + modsecFinalizeConfig(); + modsecInitProcess(); - modsecStartConfig(); - - modsecFinalizeConfig(); - - modsecInitProcess(); - - return NGX_OK; + return NGX_OK; } static void ngx_http_modsecurity_exit_process(ngx_cycle_t *cycle) { - modsecTerminate(); + // we are exiting process anyway and if the request was not finished properly + // the pool cleanup function for ModSecurity might break the termination process + // + //modsecTerminate(); } -// This is a temporary hack to make PCRE work with ModSecurity -// nginx hijacks pcre_malloc and pcre_free, so we have to re-hijack them -// - +/* This is a temporary hack to make PCRE work with ModSecurity +** nginx hijacks pcre_malloc and pcre_free, so we have to re-hijack them +*/ extern apr_pool_t *pool; -void *modsec_pcre_malloc(size_t size) +void * +modsec_pcre_malloc(size_t size) { - return apr_palloc(pool, size); + return apr_palloc(pool, size); } -void modsec_pcre_free(void *ptr) +void +modsec_pcre_free(void *ptr) { } -char *ConvertNgxStringToUTF8(ngx_str_t str, apr_pool_t *pool) +char * +ConvertNgxStringToUTF8(ngx_str_t str, apr_pool_t *pool) { - char *t = (char *)apr_palloc(pool, str.len + 1); + char *t = (char *) apr_palloc(pool, str.len + 1); - memcpy(t, str.data, str.len); - t[str.len] = 0; - - return t; + ngx_memcpy(t, str.data, str.len); + t[str.len] = 0; + + return t; } /* ** Create payload handler for calling request body function */ - void ngx_http_dummy_payload_handler(ngx_http_request_t *req) { @@ -249,18 +246,18 @@ ngx_http_dummy_payload_handler(ngx_http_request_t *req) /* + * XXX: needs rewrite and testing ** If method is POST or PUT, read request body and put in req->request_body->bufs */ - +#ifdef zz static ngx_int_t ngx_http_read_request_body(ngx_http_request_t *req, ngx_http_client_body_handler_pt handler) { -// If has body request treat it + // If has body request treat it ngx_int_t rc = 0; - if(req->method == NGX_HTTP_POST || req->method==NGX_HTTP_PUT) - { + if (req->method == NGX_HTTP_POST || req->method==NGX_HTTP_PUT) { //calling request body function rc = ngx_http_read_client_request_body(req, ngx_http_dummy_payload_handler); } @@ -273,155 +270,169 @@ ngx_http_read_request_body(ngx_http_request_t *req, return NGX_DONE; } -return NGX_DECLINED; + return NGX_DECLINED; } +#endif /* -** [ENTRY POINT] does : this is the function called by nginx : +** [ENTRY POINT] does : this function called by nginx from the request handler */ -static ngx_int_t ngx_http_modsecurity_access_handler(ngx_http_request_t *req) +static ngx_int_t +ngx_http_modsecurity_handler(ngx_http_request_t *req) { -/* ngx_http_request_ctx_t *ctx; - ngx_int_t rc; - ngx_http_core_loc_conf_t *clcf; - struct tms tmsstart, tmsend; - clock_t start, end; - - ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module); + ngx_http_modsecurity_loc_conf_t *cf; + ngx_http_modsecurity_ctx_t *ctx; + request_rec *r; + ngx_list_part_t *part; + ngx_table_elt_t *h; + ngx_uint_t i; + int status; + conn_rec *connection; + const char *msg; - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - - if (ctx && ctx->over) - return (NGX_DECLINED); - if (ctx && ctx->wait_for_body) { - return (NGX_DONE); - } - // the module is not enabled here - //if (!cf->enabled || cf->force_disabled) - // return (NGX_DECLINED); - // don't process internal requests. - //if (r->internal) { - // return (NGX_DECLINED); - } + /* Process only main request */ + if (req != req->main || req->internal) { + return NGX_DECLINED; + } - //nothing: return (NGX_OK); - //redirect : return (NGX_HTTP_OK); + cf = ngx_http_get_module_loc_conf(req, ngx_http_modsecurity_module); + if (!cf) { + return NGX_ERROR; + } + + if (!cf->enabled) { + return NGX_DECLINED; + } + + /* XXX: temporary hack, nginx uses pcre as well and hijacks these two */ + pcre_malloc = modsec_pcre_malloc; + pcre_free = modsec_pcre_free; + + ctx = ngx_http_get_module_ctx(req, ngx_http_modsecurity_module); + if (ctx == NULL) { + ctx = (ngx_http_modsecurity_ctx_t *) ngx_pcalloc(req->pool, sizeof(ngx_http_modsecurity_ctx_t)); + if (ctx == NULL) { + ngx_log_error(NGX_LOG_INFO, req->connection->log, 0, "ModSecurity: ctx memory allocation error"); + return NGX_ERROR; + } + ngx_http_set_ctx(req, ctx, ngx_http_modsecurity_module); + } + + + if (cf->config == NULL) { + cf->config = modsecGetDefaultConfig(); + + msg = modsecProcessConfig(cf->config, cf->config_path); + if (msg != NULL) { + ngx_log_error(NGX_LOG_INFO, req->connection->log, 0, "ModSecurity: modsecProcessConfig() %s", msg); + return NGX_ERROR; + } + } + + if (req->connection->requests == 0 || ctx->connection == NULL) { + ctx->connection = modsecNewConnection(); + modsecProcessConnection(ctx->connection); + } + + r = modsecNewRequest(ctx->connection, cf->config); + r->request_time = apr_time_now(); + r->method = ConvertNgxStringToUTF8(req->method_name, r->pool); + r->path_info = ConvertNgxStringToUTF8(req->unparsed_uri, r->pool); + r->unparsed_uri = ConvertNgxStringToUTF8(req->unparsed_uri, r->pool); + r->uri = r->unparsed_uri; + r->the_request = ConvertNgxStringToUTF8(req->request_line, r->pool); + r->args = ConvertNgxStringToUTF8(req->args, r->pool); + r->filename = r->path_info; + + r->parsed_uri.scheme = "http"; + r->parsed_uri.path = r->path_info; + r->parsed_uri.is_initialized = 1; + r->parsed_uri.port = 80; + r->parsed_uri.port_str = "80"; + r->parsed_uri.query = r->args; + r->parsed_uri.dns_looked_up = 0; + r->parsed_uri.dns_resolved = 0; + r->parsed_uri.password = NULL; + r->parsed_uri.user = NULL; + r->parsed_uri.fragment = ConvertNgxStringToUTF8(req->exten, r->pool); + + part = &req->headers_in.headers.part; + h = part->elts; + + for (i = 0; ; i++) { + if (i >= part->nelts) { + if (part->next == NULL) + break; + + part = part->next; + h = part->elts; + i = 0; + } + + apr_table_setn(r->headers_in, ConvertNgxStringToUTF8(h[i].key, r->pool), + ConvertNgxStringToUTF8(h[i].value, r->pool)); + } + + apr_table_setn(r->subprocess_env, "UNIQUE_ID", "12345"); + +/* + ngx_log_error(NGX_LOG_INFO, req->connection->log, 0, "ModSecurity: %s", r->uri); */ - ngx_http_modsecurity_loc_conf_t *cf; - conn_rec *c; - request_rec *r; - - cf = ngx_http_get_module_loc_conf(req, ngx_http_modsecurity_module); + /* XXX: need correct request body handler */ +/* + ngx_http_read_request_body(req, ngx_http_dummy_payload_handler); - if (!cf) - return (NGX_ERROR); - - if(!cf->enabled) - return (NGX_DECLINED); - - // temporary hack, nginx uses pcre as well and hijacks these two - // - pcre_malloc = modsec_pcre_malloc; - pcre_free = modsec_pcre_free; - - if(cf->config == NULL) - { - cf->config = modsecGetDefaultConfig(); - - if(cf->config_path.len != 0) - { - char *path = ngx_pcalloc(req->pool, cf->config_path.len+1); - - memcpy(path, cf->config_path.data, cf->config_path.len); - - const char *msg = modsecProcessConfig(cf->config, path); - - if(msg != NULL) - ngx_log_error(NGX_LOG_INFO, req->connection->log, 0, "%s", msg); + if (req->headers_in.content_length) { + ngx_log_error(NGX_LOG_INFO, req->connection->log, 0, "request body: %s", req->request_body->bufs); + } else { + ngx_log_error(NGX_LOG_INFO, req->connection->log, 0, "request body: "); } - } +*/ - //if(r->connection->requests == 0) - //{ - c = modsecNewConnection(); + status = modsecProcessRequest(r); - modsecProcessConnection(c); - //} + modsecFinishRequest(r); - r = modsecNewRequest(c, cf->config); + if (status != DECLINED) { + ngx_log_error(NGX_LOG_INFO, req->connection->log, 0, "ModSecurity: status: %d", status); - r->request_time = apr_time_now(); + /* XXX: not implemented in standalone */ + /* + ngx_http_clear_accept_ranges(req); + ngx_http_clear_last_modified(req); + ngx_http_clear_content_length(req); - r->path_info = ConvertNgxStringToUTF8(req->unparsed_uri, r->pool); - - r->unparsed_uri = ConvertNgxStringToUTF8(req->unparsed_uri, r->pool); - r->uri = r->unparsed_uri; - - r->the_request = ConvertNgxStringToUTF8(req->request_line, r->pool); - - r->args = ConvertNgxStringToUTF8(req->args, r->pool); - - r->filename = r->path_info; - - r->parsed_uri.scheme = "http"; - r->parsed_uri.path = r->path_info; - r->parsed_uri.is_initialized = 1; - r->parsed_uri.port = 80; - r->parsed_uri.port_str = "80"; - r->parsed_uri.query = r->args; - r->parsed_uri.dns_looked_up = 0; - r->parsed_uri.dns_resolved = 0; - r->parsed_uri.password = NULL; - r->parsed_uri.user = NULL; - r->parsed_uri.fragment = ConvertNgxStringToUTF8(req->exten, r->pool); - - ngx_list_part_t *part = &req->headers_in.headers.part; - ngx_table_elt_t *h = part->elts; - u_int i; - - for(i = 0; ; i++) - { - if(i >= part->nelts) - { - if(part->next == NULL) - break; - - part = part->next; - h = part->elts; - i = 0; + return NGX_HTTP_INTERNAL_SERVER_ERROR; + */ + return NGX_DECLINED; } - apr_table_setn(r->headers_in, ConvertNgxStringToUTF8(h[i].key, r->pool), - ConvertNgxStringToUTF8(h[i].value, r->pool)); - } - - apr_table_setn(r->subprocess_env, "UNIQUE_ID", "12345"); - - ngx_log_error(NGX_LOG_INFO, req->connection->log, 0, "%s", r->uri); - - int status = modsecProcessRequest(r); - ngx_log_error(NGX_LOG_INFO, req->connection->log, 0, "status: %d", status); - - ngx_http_read_request_body(req, ngx_http_dummy_payload_handler); - - if(req->headers_in.content_length) - { - ngx_log_error(NGX_LOG_INFO, req->connection->log, 0, "request body: %s", req->request_body->bufs); - } else { - ngx_log_error(NGX_LOG_INFO, req->connection->log, 0, "request body: "); - } - - if(status == DECLINED) - { - // this function would work here, but it is only internal - //ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return (NGX_DECLINED); - - // If DECLINED, finalize connection (sent FIN) and return HTTP 500 - ngx_log_error(NGX_LOG_INFO, req->connection->log, 0, "Invalid Request"); - ngx_http_finalize_request(req, NGX_HTTP_INTERNAL_SERVER_ERROR); - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - return status; + return NGX_DECLINED; +} + +static char * +ngx_http_modsecurity_set_config(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_modsecurity_loc_conf_t *ucf = conf; + ngx_str_t *value; + + value = cf->args->elts; + + if (cf->args->nelts == 0 || value[1].len == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "ModSecurity: config path required"); + return NGX_CONF_ERROR; + } + + /* not sure if we have to copy it in a buffed or use directly */ + /* XXX: need to check if path is absolute or relative and exists */ + ucf->config_path = (char *) ngx_pcalloc(cf->pool, value[1].len + 1); + if (ucf->config_path == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "ModSecurity: config path memory allocation error"); + return NGX_CONF_ERROR; + } + ngx_memcpy(ucf->config_path, value[1].data, value[1].len); + + return NGX_CONF_OK; }