diff -Naur a/configure b/configure diff -Naur a/Makefile.in b/Makefile.in --- a/Makefile.in 2008-11-25 22:24:00.000000000 +0200 +++ b/Makefile.in 2013-05-22 14:25:13.000000000 +0300 @@ -4,7 +4,16 @@ PROGRAM_NAME = $(progname) PROGRAM_SOURCES = modules.c -PROGRAM_LDADD = buildmark.o $(HTTPD_LDFLAGS) $(PROGRAM_DEPENDENCIES) $(EXTRA_LIBS) $(AP_LIBS) $(LIBS) + +ifneq (,$(findstring itk,$(CURDIR))) +CONLDD = -llve -lselinux +else +CONLDD = -lselinux +endif +PROGRAM_LDADD = buildmark.o $(HTTPD_LDFLAGS) $(PROGRAM_DEPENDENCIES) $(EXTRA_LIBS) $(AP_LIBS) $(LIBS) $(CONLDD) + + + PROGRAM_PRELINK = $(COMPILE) -c $(top_srcdir)/server/buildmark.c PROGRAM_DEPENDENCIES = \ server/libmain.la \ diff --git a/server/mpm/experimental/itk/itk.c b/server/mpm/experimental/itk/itk.c index d159af5..9917312 100644 --- a/server/mpm/experimental/itk/itk.c +++ b/server/mpm/experimental/itk/itk.c @@ -42,6 +42,11 @@ #include #endif +#include "apr_general.h" +#include "apr_lib.h" +#include "apr_hash.h" +#include "apr_tables.h" + #define CORE_PRIVATE #include "ap_config.h" @@ -61,6 +66,11 @@ #include "ap_mmn.h" #include "apr_poll.h" +#include "mod_core.h" +#include "util_filter.h" +#include "http_protocol.h" +#include "util_script.h" + #ifdef HAVE_BSTRING_H #include /* for IRIX, FD_SET calls bzero() */ #endif @@ -77,6 +87,9 @@ #include #include +#include +#include + /* Limit on the total --- clients will be locked out if more servers than * this are needed. It is intended solely to keep the server from crashing @@ -104,6 +117,13 @@ #define HARD_THREAD_LIMIT 1 #endif +// HTTP error code to return to client if resources limit is reached AND LVEErrorCode directive is not present in module configuration +#define DEFAULT_HTTP_ERROR_CODE 508 + +// HTTP error code should be in these limits +#define MAX_HTTP_SERVER_ERROR_CODE 510 +#define MIN_HTTP_SERVER_ERROR_CODE 500 + /* config globals */ int ap_threads_per_child=0; /* Worker threads per child */ @@ -164,6 +184,9 @@ typedef struct gid_t gid; char *username; int nice_value; + unsigned int http_error_code; + int err_doc_found; + uint32_t retryAfter; } itk_per_dir_conf; typedef struct @@ -1415,12 +1438,31 @@ static int itk_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp) return OK; } +static int lve_itk_enter(uid_t uid){ + uint32_t cookie; + struct liblve *lve; + lve = init_lve_generic(); + if (lve == NULL) { + return 0; + } + if (lve_enter_flags(lve, uid, &cookie, LVE_SILENCE )) { + destroy_lve(lve); + return 0; + } + return 1; +} + +__thread int lve_error_flag = 0; + static int itk_post_perdir_config(request_rec *r) { uid_t wanted_uid; gid_t wanted_gid; const char *wanted_username; int err = 0; + struct passwd *pw = NULL; + char error_str[1024]=""; + itk_server_conf *sconf = (itk_server_conf *) ap_get_module_config(r->server->module_config, &mpm_itk_module); @@ -1465,7 +1507,20 @@ static int itk_post_perdir_config(request_rec *r) } if (!err && wanted_uid != -1 && wanted_gid != -1 && (getuid() != wanted_uid || getgid() != wanted_gid)) { - if (setgid(wanted_gid)) { + pw = getpwuid(wanted_uid); + if(pw){ + if (!lve_itk_enter(wanted_uid)){ + _DBG("lve_enter(%d), %s", wanted_uid, strerror(errno)); + lve_error_flag = 1; + } + } + if (!pw) { + _DBG("getpwuid(%d): %s", wanted_uid, strerror(errno)); + err = 1; + } else if (jail(pw, error_str) < 0) { + _DBG("jail(%d): %s", wanted_uid, error_str); + err = 1; + } else if (setgid(wanted_gid)) { _DBG("setgid(%d): %s", wanted_gid, strerror(errno)); err = 1; } else if (initgroups(wanted_username, wanted_gid)) { @@ -1491,6 +1546,57 @@ static int itk_post_perdir_config(request_rec *r) return OK; } +static int +process_lve_error_itk (request_rec * r, itk_per_dir_conf * cfg) +{ + //Set out header LVE_RETRY_AFTER + if (cfg->retryAfter) + { + apr_table_setn (r->err_headers_out, "Retry-After", + apr_ltoa (r->pool, cfg->retryAfter * 60)); + } + // LVEErrorCode is NOT 508 or "ErrorDocument 508" directive is present in Apache configuration ? + if ((cfg->http_error_code != 508) || (cfg->err_doc_found)) + return cfg->http_error_code; + + int i; + r->status = 508; + r->content_type = "text/html"; + apr_bucket_brigade *bb = apr_brigade_create (r->pool, + r->connection->bucket_alloc); + ap_basic_http_header (r, bb); + + // Send header information only (HEAD request) ? + if (r->header_only) + return DONE; + + ap_rvputs (r, "\n" + DOCTYPE_HTML_2_0 + "\n508 Resource Limit Is Reached(ITK)\n" + "\n" "

Resource Limit Is Reached

\n", NULL); + for (i = 0; i < 1000; i++) + ap_rvputs (r, " \n", NULL); + ap_rputs + ("The website is temporarily unable to service your request as it exceeded resource limit.\n" + "Please try again later.\n", r); + ap_rputs (ap_psignature ("
\n", r), r); + ap_rputs ("\n", r); + ap_finalize_request_protocol (r); + ap_rflush (r); + return DONE; +} + +static int +enter_jail_handler (request_rec * r){ + itk_per_dir_conf *dconf = + (itk_per_dir_conf *) ap_get_module_config(r->per_dir_config, &mpm_itk_module); + if(lve_error_flag){ + lve_error_flag = 0; + return process_lve_error_itk (r, dconf); + } + return DECLINED; +} + static void itk_hooks(apr_pool_t *p) { /* The itk open_logs phase must run before the core's, or stderr @@ -1511,8 +1617,11 @@ static void itk_hooks(apr_pool_t *p) /* set the uid as fast as possible, but not before merging per-dit config */ ap_hook_header_parser(itk_post_perdir_config, NULL, NULL, APR_HOOK_REALLY_FIRST); + + ap_hook_handler (enter_jail_handler, NULL, NULL, APR_HOOK_REALLY_FIRST); } + static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy, const char *arg) { const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); @@ -1661,6 +1770,49 @@ static const char *set_nice_value (cmd_parms *cmd, void *ptr, const char *arg) return NULL; } +static unsigned int +get_valid_http_error_code_itk (unsigned int code) +{ + if ((code < MIN_HTTP_SERVER_ERROR_CODE) + || (code > MAX_HTTP_SERVER_ERROR_CODE)) + return DEFAULT_HTTP_ERROR_CODE; + else + return code; +} + +static const char * +set_lve_error_code_itk (cmd_parms * cmd, void *mcfg, const char *lve_error_code) +{ + itk_per_dir_conf *cfg = (itk_per_dir_conf *) mcfg; + if (lve_error_code) + { + cfg->http_error_code = get_valid_http_error_code_itk ((unsigned int)apr_atoi64 (lve_error_code)); + } + return NULL; +} + +static const char * +error_doc_func_itk (cmd_parms * cmd, void *mcfg, const char *par1, const char *par2) +{ + itk_per_dir_conf *cfg = (itk_per_dir_conf *) mcfg; + if (par1) + if (strstr (par1, "508")) + cfg->err_doc_found = 1; + + return NULL; +} + +static const char * +set_lve_retryafter_itk (cmd_parms * cmd, void *mcfg, const char *minutes) +{ + itk_per_dir_conf *cfg = (itk_per_dir_conf *) mcfg; + if (minutes) + { + cfg->retryAfter = (uint32_t) apr_atoi64 (minutes); + } + return NULL; +} + static const command_rec itk_cmds[] = { UNIX_DAEMON_COMMANDS, LISTEN_COMMANDS, @@ -1681,6 +1833,12 @@ AP_INIT_TAKE1("MaxClientsVHost", set_max_clients_vhost, NULL, RSRC_CONF, AP_INIT_TAKE1("NiceValue", set_nice_value, NULL, RSRC_CONF|ACCESS_CONF, "Set nice value for the given vhost, from -20 (highest priority) to 19 (lowest priority)."), AP_GRACEFUL_SHUTDOWN_TIMEOUT_COMMAND, +AP_INIT_TAKE1 ("LVEErrorCodeITK", set_lve_error_code_itk, NULL, RSRC_CONF, + "Integer HTTP error code to return to client if resources limit is reached"), +AP_INIT_TAKE2 ("ErrorDocument", error_doc_func_itk, NULL, OR_FILEINFO, + "ErrorDocument Apache configuration directive"), +AP_INIT_TAKE1 ("LVERetryAfterITK", set_lve_retryafter_itk, NULL, RSRC_CONF, + "Set minutes of LVE_RETRY_AFTER header, which comes with 508 error. O - disabled"), { NULL } }; @@ -1691,6 +1849,9 @@ static void *itk_create_dir_config(apr_pool_t *p, char *dummy) apr_pcalloc(p, sizeof(itk_per_dir_conf)); c->uid = c->gid = -1; c->nice_value = UNSET_NICE_VALUE; + c->http_error_code = DEFAULT_HTTP_ERROR_CODE; + c->err_doc_found = 0; + c->retryAfter = 240; return c; } @@ -1716,6 +1877,11 @@ static void *itk_merge_dir_config(apr_pool_t *p, void *parent_ptr, void *child_p } else { c->nice_value = parent->nice_value; } + c->http_error_code = + (child->http_error_code != DEFAULT_HTTP_ERROR_CODE) ? child->http_error_code : parent->http_error_code; + c->retryAfter = (child->retryAfter) ? child->retryAfter : parent->retryAfter; + c->err_doc_found = + (child->err_doc_found) ? child->err_doc_found : parent->err_doc_found; return c; }