summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorStefan Fritsch <sf@sfritsch.de>2011-12-27 19:42:33 +0100
committerStefan Fritsch <sf@sfritsch.de>2011-12-27 19:42:33 +0100
commitad14e19ad0400e289b06fb7728aea815e6ed49be (patch)
treebd29489cafb04b303940169ae7b00c1171a5a34c /modules
parent02a0e3b89d2ea1b984365e692c910668d75c6dcd (diff)
downloadapache2-ad14e19ad0400e289b06fb7728aea815e6ed49be.tar.gz
Upstream tarball 2.2.12upstream/2.2.12
Diffstat (limited to 'modules')
-rw-r--r--modules/aaa/mod_authnz_ldap.c38
-rw-r--r--modules/cache/mod_cache.c26
-rw-r--r--modules/cache/mod_disk_cache.c23
-rw-r--r--modules/cache/mod_mem_cache.c11
-rw-r--r--modules/filters/mod_deflate.c20
-rw-r--r--modules/filters/mod_ext_filter.c60
-rw-r--r--modules/filters/mod_include.c62
-rw-r--r--modules/filters/mod_substitute.c4
-rw-r--r--modules/generators/mod_cgid.c59
-rw-r--r--modules/generators/mod_info.c14
-rw-r--r--modules/http/http_filters.c5
-rw-r--r--modules/http/http_protocol.c4
-rw-r--r--modules/ldap/util_ldap.c11
-rw-r--r--modules/mappers/mod_alias.c53
-rw-r--r--modules/mappers/mod_negotiation.c4
-rw-r--r--modules/mappers/mod_rewrite.c138
-rw-r--r--modules/mappers/mod_so.c2
-rw-r--r--modules/metadata/config.m42
-rw-r--r--modules/metadata/mod_headers.c3
-rw-r--r--modules/metadata/mod_mime_magic.c22
-rw-r--r--modules/proxy/ajp_header.c20
-rw-r--r--modules/proxy/ajp_header.h8
-rw-r--r--modules/proxy/mod_proxy.c5
-rw-r--r--modules/proxy/mod_proxy_ajp.c48
-rw-r--r--modules/proxy/mod_proxy_balancer.c16
-rw-r--r--modules/proxy/mod_proxy_http.c53
-rw-r--r--modules/proxy/proxy_util.c72
-rw-r--r--modules/ssl/mod_ssl.c52
-rw-r--r--modules/ssl/ssl_engine_config.c60
-rw-r--r--modules/ssl/ssl_engine_init.c48
-rw-r--r--modules/ssl/ssl_engine_io.c83
-rw-r--r--modules/ssl/ssl_engine_kernel.c466
-rw-r--r--modules/ssl/ssl_engine_vars.c8
-rw-r--r--modules/ssl/ssl_private.h25
-rw-r--r--modules/ssl/ssl_toolkit_compat.h6
35 files changed, 1133 insertions, 398 deletions
diff --git a/modules/aaa/mod_authnz_ldap.c b/modules/aaa/mod_authnz_ldap.c
index 5d767f65..db13f1fd 100644
--- a/modules/aaa/mod_authnz_ldap.c
+++ b/modules/aaa/mod_authnz_ldap.c
@@ -872,31 +872,12 @@ static const char *mod_auth_ldap_parse_url(cmd_parms *cmd,
authn_ldap_config_t *sec = config;
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
- cmd->server, "[%" APR_PID_T_FMT "] auth_ldap url parse: `%s'", getpid(), url);
-
rc = apr_ldap_url_parse(cmd->pool, url, &(urld), &(result));
if (rc != APR_SUCCESS) {
return result->reason;
}
sec->url = apr_pstrdup(cmd->pool, url);
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
- cmd->server, "[%" APR_PID_T_FMT "] auth_ldap url parse: Host: %s", getpid(), urld->lud_host);
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
- cmd->server, "[%" APR_PID_T_FMT "] auth_ldap url parse: Port: %d", getpid(), urld->lud_port);
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
- cmd->server, "[%" APR_PID_T_FMT "] auth_ldap url parse: DN: %s", getpid(), urld->lud_dn);
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
- cmd->server, "[%" APR_PID_T_FMT "] auth_ldap url parse: attrib: %s", getpid(), urld->lud_attrs? urld->lud_attrs[0] : "(null)");
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
- cmd->server, "[%" APR_PID_T_FMT "] auth_ldap url parse: scope: %s", getpid(),
- (urld->lud_scope == LDAP_SCOPE_SUBTREE? "subtree" :
- urld->lud_scope == LDAP_SCOPE_BASE? "base" :
- urld->lud_scope == LDAP_SCOPE_ONELEVEL? "onelevel" : "unknown"));
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
- cmd->server, "[%" APR_PID_T_FMT "] auth_ldap url parse: filter: %s", getpid(), urld->lud_filter);
-
/* Set all the values, or at least some sane defaults */
if (sec->host) {
char *p = apr_palloc(cmd->pool, strlen(sec->host) + strlen(urld->lud_host) + 2);
@@ -968,18 +949,29 @@ static const char *mod_auth_ldap_parse_url(cmd_parms *cmd,
{
sec->secure = APR_LDAP_SSL;
sec->port = urld->lud_port? urld->lud_port : LDAPS_PORT;
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server,
- "LDAP: auth_ldap using SSL connections");
}
else
{
sec->port = urld->lud_port? urld->lud_port : LDAP_PORT;
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server,
- "LDAP: auth_ldap not using SSL connections");
}
sec->have_ldap_url = 1;
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
+ cmd->server, "[%" APR_PID_T_FMT "] auth_ldap url parse: `%s', Host: %s, Port: %d, DN: %s, attrib: %s, scope: %s, filter: %s, connection mode: %s",
+ getpid(),
+ url,
+ urld->lud_host,
+ urld->lud_port,
+ urld->lud_dn,
+ urld->lud_attrs? urld->lud_attrs[0] : "(null)",
+ (urld->lud_scope == LDAP_SCOPE_SUBTREE? "subtree" :
+ urld->lud_scope == LDAP_SCOPE_BASE? "base" :
+ urld->lud_scope == LDAP_SCOPE_ONELEVEL? "onelevel" : "unknown"),
+ urld->lud_filter,
+ sec->secure == APR_LDAP_SSL ? "using SSL": "not using SSL"
+ );
+
return NULL;
}
diff --git a/modules/cache/mod_cache.c b/modules/cache/mod_cache.c
index 27df70d4..a35b2abc 100644
--- a/modules/cache/mod_cache.c
+++ b/modules/cache/mod_cache.c
@@ -440,7 +440,28 @@ static int cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in)
* We include 304 Not Modified here too as this is the origin server
* telling us to serve the cached copy.
*/
- reason = apr_psprintf(p, "Response status %d", r->status);
+ if (exps != NULL || cc_out != NULL) {
+ /* We are also allowed to cache any response given that it has a
+ * valid Expires or Cache Control header. If we find a either of
+ * those here, we pass request through the rest of the tests. From
+ * the RFC:
+ *
+ * A response received with any other status code (e.g. status
+ * codes 302 and 307) MUST NOT be returned in a reply to a
+ * subsequent request unless there are cache-control directives or
+ * another header(s) that explicitly allow it. For example, these
+ * include the following: an Expires header (section 14.21); a
+ * "max-age", "s-maxage", "must-revalidate", "proxy-revalidate",
+ * "public" or "private" cache-control directive (section 14.9).
+ */
+ }
+ else {
+ reason = apr_psprintf(p, "Response status %d", r->status);
+ }
+ }
+
+ if (reason) {
+ /* noop */
}
else if (exps != NULL && exp == APR_DATE_BAD) {
/* if a broken Expires header is present, don't cache it */
@@ -519,6 +540,9 @@ static int cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in)
"*", NULL)) {
reason = "Vary header contains '*'";
}
+ else if (apr_table_get(r->subprocess_env, "no-cache") != NULL) {
+ reason = "environment variable 'no-cache' is set";
+ }
else if (r->no_cache) {
/* or we've been asked not to cache it above */
reason = "r->no_cache present";
diff --git a/modules/cache/mod_disk_cache.c b/modules/cache/mod_disk_cache.c
index 4148b373..70a804b8 100644
--- a/modules/cache/mod_disk_cache.c
+++ b/modules/cache/mod_disk_cache.c
@@ -357,6 +357,10 @@ static int open_entity(cache_handle_t *h, request_rec *r, const char *key)
static int error_logged = 0;
disk_cache_conf *conf = ap_get_module_config(r->server->module_config,
&disk_cache_module);
+#ifdef APR_SENDFILE_ENABLED
+ core_dir_config *coreconf = ap_get_module_config(r->per_dir_config,
+ &core_module);
+#endif
apr_finfo_t finfo;
cache_object_t *obj;
cache_info *info;
@@ -452,7 +456,12 @@ static int open_entity(cache_handle_t *h, request_rec *r, const char *key)
/* Open the data file */
flags = APR_READ|APR_BINARY;
#ifdef APR_SENDFILE_ENABLED
- flags |= APR_SENDFILE_ENABLED;
+ /* When we are in the quick handler we don't have the per-directory
+ * configuration, so this check only takes the globel setting of
+ * the EnableSendFile directive into account.
+ */
+ flags |= ((coreconf->enable_sendfile == ENABLE_SENDFILE_OFF)
+ ? 0 : APR_SENDFILE_ENABLED);
#endif
rc = apr_file_open(&dobj->fd, dobj->datafile, flags, 0, r->pool);
if (rc != APR_SUCCESS) {
@@ -907,7 +916,9 @@ static apr_status_t store_headers(cache_handle_t *h, request_rec *r, cache_info
if (r->headers_out) {
apr_table_t *headers_out;
- headers_out = ap_cache_cacheable_hdrs_out(r->pool, r->headers_out,
+ headers_out = apr_table_overlay(r->pool, r->headers_out,
+ r->err_headers_out);
+ headers_out = ap_cache_cacheable_hdrs_out(r->pool, headers_out,
r->server);
if (!apr_table_get(headers_out, "Content-Type")
@@ -916,8 +927,12 @@ static apr_status_t store_headers(cache_handle_t *h, request_rec *r, cache_info
ap_make_content_type(r, r->content_type));
}
- headers_out = apr_table_overlay(r->pool, headers_out,
- r->err_headers_out);
+ if (!apr_table_get(headers_out, "Content-Encoding")
+ && r->content_encoding) {
+ apr_table_setn(headers_out, "Content-Encoding",
+ r->content_encoding);
+ }
+
rv = store_table(dobj->hfd, headers_out);
if (rv != APR_SUCCESS) {
return rv;
diff --git a/modules/cache/mod_mem_cache.c b/modules/cache/mod_mem_cache.c
index 65f35327..7bdaeac9 100644
--- a/modules/cache/mod_mem_cache.c
+++ b/modules/cache/mod_mem_cache.c
@@ -604,7 +604,9 @@ static apr_status_t store_headers(cache_handle_t *h, request_rec *r, cache_info
mobj->req_hdrs = deep_table_copy(mobj->pool, r->headers_in);
/* Precompute how much storage we need to hold the headers */
- headers_out = ap_cache_cacheable_hdrs_out(r->pool, r->headers_out,
+ headers_out = apr_table_overlay(r->pool, r->headers_out,
+ r->err_headers_out);
+ headers_out = ap_cache_cacheable_hdrs_out(r->pool, headers_out,
r->server);
/* If not set in headers_out, set Content-Type */
@@ -614,7 +616,12 @@ static apr_status_t store_headers(cache_handle_t *h, request_rec *r, cache_info
ap_make_content_type(r, r->content_type));
}
- headers_out = apr_table_overlay(r->pool, headers_out, r->err_headers_out);
+ if (!apr_table_get(headers_out, "Content-Encoding")
+ && r->content_encoding) {
+ apr_table_setn(headers_out, "Content-Encoding",
+ r->content_encoding);
+ }
+
mobj->header_out = deep_table_copy(mobj->pool, headers_out);
/* Init the info struct */
diff --git a/modules/filters/mod_deflate.c b/modules/filters/mod_deflate.c
index de1a57d7..07ca194f 100644
--- a/modules/filters/mod_deflate.c
+++ b/modules/filters/mod_deflate.c
@@ -372,23 +372,7 @@ static apr_status_t deflate_ctx_cleanup(void *data)
ctx->libz_end_func(&ctx->stream);
return APR_SUCCESS;
}
-/* PR 39727: we're screwing up our clients if we leave a strong ETag
- * header while transforming content. Henrik Nordstrom suggests
- * appending ";gzip".
- *
- * Pending a more thorough review of our Etag handling, let's just
- * implement his suggestion. It fixes the bug, or at least turns it
- * from a showstopper to an inefficiency. And it breaks nothing that
- * wasn't already broken.
- */
-static void deflate_check_etag(request_rec *r, const char *transform)
-{
- const char *etag = apr_table_get(r->headers_out, "ETag");
- if (etag && (((etag[0] != 'W') && (etag[0] !='w')) || (etag[1] != '/'))) {
- apr_table_set(r->headers_out, "ETag",
- apr_pstrcat(r->pool, etag, "-", transform, NULL));
- }
-}
+
static apr_status_t deflate_out_filter(ap_filter_t *f,
apr_bucket_brigade *bb)
{
@@ -586,7 +570,6 @@ static apr_status_t deflate_out_filter(ap_filter_t *f,
}
apr_table_unset(r->headers_out, "Content-Length");
apr_table_unset(r->headers_out, "Content-MD5");
- deflate_check_etag(r, "gzip");
/* initialize deflate output buffer */
ctx->stream.next_out = ctx->buffer;
@@ -1079,7 +1062,6 @@ static apr_status_t inflate_out_filter(ap_filter_t *f,
/* these are unlikely to be set anyway, but ... */
apr_table_unset(r->headers_out, "Content-Length");
apr_table_unset(r->headers_out, "Content-MD5");
- deflate_check_etag(r, "gunzip");
/* initialize inflate output buffer */
ctx->stream.next_out = ctx->buffer;
diff --git a/modules/filters/mod_ext_filter.c b/modules/filters/mod_ext_filter.c
index 78c9f90d..fe922716 100644
--- a/modules/filters/mod_ext_filter.c
+++ b/modules/filters/mod_ext_filter.c
@@ -58,6 +58,7 @@ typedef struct ef_filter_t {
typedef struct ef_dir_t {
int debug;
int log_stderr;
+ int onfail;
} ef_dir_t;
typedef struct ef_ctx_t {
@@ -81,7 +82,6 @@ static apr_status_t ef_input_filter(ap_filter_t *, apr_bucket_brigade *,
apr_off_t);
#define DBGLVL_SHOWOPTIONS 1
-#define DBGLVL_ERRORCHECK 2
#define DBGLVL_GORY 9
#define ERRFN_USERDATA_KEY "EXTFILTCHILDERRFN"
@@ -92,6 +92,7 @@ static void *create_ef_dir_conf(apr_pool_t *p, char *dummy)
dc->debug = -1;
dc->log_stderr = -1;
+ dc->onfail = -1;
return dc;
}
@@ -125,6 +126,13 @@ static void *merge_ef_dir_conf(apr_pool_t *p, void *basev, void *overridesv)
a->log_stderr = base->log_stderr;
}
+ if (over->onfail != -1) { /* if admin coded something... */
+ a->onfail = over->onfail;
+ }
+ else {
+ a->onfail = base->onfail;
+ }
+
return a;
}
@@ -142,6 +150,12 @@ static const char *add_options(cmd_parms *cmd, void *in_dc,
else if (!strcasecmp(arg, "NoLogStderr")) {
dc->log_stderr = 0;
}
+ else if (!strcasecmp(arg, "Onfail=remove")) {
+ dc->onfail = 1;
+ }
+ else if (!strcasecmp(arg, "Onfail=abort")) {
+ dc->onfail = 0;
+ }
else {
return apr_pstrcat(cmd->temp_pool,
"Invalid ExtFilterOptions option: ",
@@ -449,9 +463,9 @@ static apr_status_t init_ext_filter_process(ap_filter_t *f)
ap_assert(rc == APR_SUCCESS);
apr_pool_userdata_set(f->r, ERRFN_USERDATA_KEY, apr_pool_cleanup_null, ctx->p);
- if (dc->debug >= DBGLVL_ERRORCHECK) {
- rc = apr_procattr_error_check_set(ctx->procattr, 1);
- ap_assert(rc == APR_SUCCESS);
+ rc = apr_procattr_error_check_set(ctx->procattr, 1);
+ if (rc != APR_SUCCESS) {
+ return rc;
}
/* add standard CGI variables as well as DOCUMENT_URI, DOCUMENT_PATH_INFO,
@@ -855,7 +869,29 @@ static apr_status_t ef_output_filter(ap_filter_t *f, apr_bucket_brigade *bb)
if (!ctx) {
if ((rv = init_filter_instance(f)) != APR_SUCCESS) {
- return rv;
+ ctx = f->ctx;
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
+ "can't initialise output filter %s: %s",
+ f->frec->name,
+ (ctx->dc->onfail == 1) ? "removing" : "aborting");
+ ap_remove_output_filter(f);
+ if (ctx->dc->onfail == 1) {
+ return ap_pass_brigade(f->next, bb);
+ }
+ else {
+ apr_bucket *e;
+ f->r->status_line = "500 Internal Server Error";
+
+ apr_brigade_cleanup(bb);
+ e = ap_bucket_error_create(HTTP_INTERNAL_SERVER_ERROR,
+ NULL, r->pool,
+ f->c->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(bb, e);
+ e = apr_bucket_eos_create(f->c->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(bb, e);
+ ap_pass_brigade(f->next, bb);
+ return AP_FILTER_ERROR;
+ }
}
ctx = f->ctx;
}
@@ -886,7 +922,19 @@ static int ef_input_filter(ap_filter_t *f, apr_bucket_brigade *bb,
if (!ctx) {
if ((rv = init_filter_instance(f)) != APR_SUCCESS) {
- return rv;
+ ctx = f->ctx;
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, f->r,
+ "can't initialise input filter %s: %s",
+ f->frec->name,
+ (ctx->dc->onfail == 1) ? "removing" : "aborting");
+ ap_remove_input_filter(f);
+ if (ctx->dc->onfail == 1) {
+ return ap_get_brigade(f->next, bb, mode, block, readbytes);
+ }
+ else {
+ f->r->status = HTTP_INTERNAL_SERVER_ERROR;
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
}
ctx = f->ctx;
}
diff --git a/modules/filters/mod_include.c b/modules/filters/mod_include.c
index 1c683880..6ec0fa89 100644
--- a/modules/filters/mod_include.c
+++ b/modules/filters/mod_include.c
@@ -158,6 +158,7 @@ typedef struct {
const char *rexp;
apr_size_t nsub;
ap_regmatch_t match[AP_MAX_REG_MATCH];
+ int have_match;
} backref_t;
typedef struct {
@@ -580,7 +581,7 @@ static void decodehtml(char *s)
*p = '\0';
}
-static void add_include_vars(request_rec *r, const char *timefmt)
+static void add_include_vars(request_rec *r)
{
apr_table_t *e = r->subprocess_env;
char *t;
@@ -608,26 +609,17 @@ static void add_include_vars(request_rec *r, const char *timefmt)
}
}
-static const char *add_include_vars_lazy(request_rec *r, const char *var)
+static const char *add_include_vars_lazy(request_rec *r, const char *var, const char *timefmt)
{
char *val;
if (!strcasecmp(var, "DATE_LOCAL")) {
- include_dir_config *conf =
- (include_dir_config *)ap_get_module_config(r->per_dir_config,
- &include_module);
- val = ap_ht_time(r->pool, r->request_time, conf->default_time_fmt, 0);
+ val = ap_ht_time(r->pool, r->request_time, timefmt, 0);
}
else if (!strcasecmp(var, "DATE_GMT")) {
- include_dir_config *conf =
- (include_dir_config *)ap_get_module_config(r->per_dir_config,
- &include_module);
- val = ap_ht_time(r->pool, r->request_time, conf->default_time_fmt, 1);
+ val = ap_ht_time(r->pool, r->request_time, timefmt, 1);
}
else if (!strcasecmp(var, "LAST_MODIFIED")) {
- include_dir_config *conf =
- (include_dir_config *)ap_get_module_config(r->per_dir_config,
- &include_module);
- val = ap_ht_time(r->pool, r->finfo.mtime, conf->default_time_fmt, 0);
+ val = ap_ht_time(r->pool, r->finfo.mtime, timefmt, 0);
}
else if (!strcasecmp(var, "USER_NAME")) {
if (apr_uid_name_get(&val, r->finfo.user, r->pool) != APR_SUCCESS) {
@@ -657,25 +649,26 @@ static const char *get_include_var(const char *var, include_ctx_t *ctx)
* The choice of returning NULL strings on not-found,
* v.s. empty strings on an empty match is deliberate.
*/
- if (!re) {
+ if (!re || !re->have_match) {
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
"regex capture $%" APR_SIZE_T_FMT " refers to no regex in %s",
idx, r->filename);
return NULL;
}
+ else if (re->nsub < idx || idx >= AP_MAX_REG_MATCH) {
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
+ "regex capture $%" APR_SIZE_T_FMT
+ " is out of range (last regex was: '%s') in %s",
+ idx, re->rexp, r->filename);
+ return NULL;
+ }
+ else if (re->match[idx].rm_so < 0 || re->match[idx].rm_eo < 0) {
+ /* I don't think this can happen if have_match is true.
+ * But let's not risk a regression by dropping this
+ */
+ return NULL;
+ }
else {
- if (re->nsub < idx || idx >= AP_MAX_REG_MATCH) {
- ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
- "regex capture $%" APR_SIZE_T_FMT
- " is out of range (last regex was: '%s') in %s",
- idx, re->rexp, r->filename);
- return NULL;
- }
-
- if (re->match[idx].rm_so < 0 || re->match[idx].rm_eo < 0) {
- return NULL;
- }
-
val = apr_pstrmemdup(ctx->dpool, re->source + re->match[idx].rm_so,
re->match[idx].rm_eo - re->match[idx].rm_so);
}
@@ -684,7 +677,7 @@ static const char *get_include_var(const char *var, include_ctx_t *ctx)
val = apr_table_get(r->subprocess_env, var);
if (val == LAZY_VALUE) {
- val = add_include_vars_lazy(r, var);
+ val = add_include_vars_lazy(r, var, ctx->time_str);
}
}
@@ -923,7 +916,6 @@ static APR_INLINE int re_check(include_ctx_t *ctx, const char *string,
{
ap_regex_t *compiled;
backref_t *re = ctx->intern->re;
- int rc;
compiled = ap_pregcomp(ctx->dpool, rexp, AP_REG_EXTENDED);
if (!compiled) {
@@ -939,10 +931,11 @@ static APR_INLINE int re_check(include_ctx_t *ctx, const char *string,
re->source = apr_pstrdup(ctx->pool, string);
re->rexp = apr_pstrdup(ctx->pool, rexp);
re->nsub = compiled->re_nsub;
- rc = !ap_regexec(compiled, string, AP_MAX_REG_MATCH, re->match, 0);
+ re->have_match = !ap_regexec(compiled, string, AP_MAX_REG_MATCH,
+ re->match, 0);
ap_pregfree(ctx->dpool, compiled);
- return rc;
+ return re->have_match;
}
static int get_ptoken(include_ctx_t *ctx, const char **parse, token_t *token, token_t *previous)
@@ -1812,7 +1805,8 @@ static apr_status_t handle_echo(include_ctx_t *ctx, ap_filter_t *f,
echo_text = ap_escape_uri(ctx->dpool, val);
break;
case E_ENTITY:
- echo_text = ap_escape_html(ctx->dpool, val);
+ /* PR#25202: escape anything non-ascii here */
+ echo_text = ap_escape_html2(ctx->dpool, val, 1);
break;
}
@@ -2423,7 +2417,7 @@ static apr_status_t handle_printenv(include_ctx_t *ctx, ap_filter_t *f,
/* get value */
val_text = elts[i].val;
if (val_text == LAZY_VALUE) {
- val_text = add_include_vars_lazy(r, elts[i].key);
+ val_text = add_include_vars_lazy(r, elts[i].key, ctx->time_str);
}
val_text = ap_escape_html(ctx->dpool, elts[i].val);
v_len = strlen(val_text);
@@ -3608,7 +3602,7 @@ static apr_status_t includes_filter(ap_filter_t *f, apr_bucket_brigade *b)
* environment */
ap_add_common_vars(r);
ap_add_cgi_vars(r);
- add_include_vars(r, conf->default_time_fmt);
+ add_include_vars(r);
}
/* Always unset the content-length. There is no way to know if
* the content will be modified at some point by send_parsed_content.
diff --git a/modules/filters/mod_substitute.c b/modules/filters/mod_substitute.c
index a50248f3..07030403 100644
--- a/modules/filters/mod_substitute.c
+++ b/modules/filters/mod_substitute.c
@@ -199,7 +199,6 @@ static void do_pattmatch(ap_filter_t *f, apr_bucket *inb,
tmp_b = apr_bucket_transient_create(s1, strlen(s1),
f->r->connection->bucket_alloc);
APR_BUCKET_INSERT_BEFORE(b, tmp_b);
- tmp_b = APR_BUCKET_NEXT(b);
apr_bucket_delete(b);
b = tmp_b;
}
@@ -249,7 +248,6 @@ static void do_pattmatch(ap_filter_t *f, apr_bucket *inb,
tmp_b = apr_bucket_transient_create(s1, strlen(s1),
f->r->connection->bucket_alloc);
APR_BUCKET_INSERT_BEFORE(b, tmp_b);
- tmp_b = APR_BUCKET_NEXT(b);
apr_bucket_delete(b);
b = tmp_b;
}
@@ -375,7 +373,7 @@ static apr_status_t substitute_filter(ap_filter_t *f, apr_bucket_brigade *bb)
*/
rv = apr_bucket_read(b, &buff, &bytes, APR_BLOCK_READ);
if (rv != APR_SUCCESS || bytes == 0) {
- APR_BUCKET_REMOVE(b);
+ apr_bucket_delete(b);
}
else {
int num = 0;
diff --git a/modules/generators/mod_cgid.c b/modules/generators/mod_cgid.c
index 5ee3df07..99ae84b5 100644
--- a/modules/generators/mod_cgid.c
+++ b/modules/generators/mod_cgid.c
@@ -344,6 +344,33 @@ static apr_status_t sock_write(int fd, const void *buf, size_t buf_size)
return APR_SUCCESS;
}
+static apr_status_t sock_writev(int fd, request_rec *r, int count, ...)
+{
+ va_list ap;
+ int rc;
+ struct iovec *vec;
+ int i;
+ int total_bytes = 0;
+
+ vec = (struct iovec *)apr_palloc(r->pool, count * sizeof(struct iovec));
+ va_start(ap, count);
+ for (i = 0; i < count; i++) {
+ vec[i].iov_base = va_arg(ap, caddr_t);
+ vec[i].iov_len = va_arg(ap, apr_size_t);
+ total_bytes += vec[i].iov_len;
+ }
+ va_end(ap);
+
+ do {
+ rc = writev(fd, vec, count);
+ } while (rc < 0 && errno == EINTR);
+ if (rc < 0) {
+ return errno;
+ }
+
+ return APR_SUCCESS;
+}
+
static apr_status_t get_req(int fd, request_rec *r, char **argv0, char ***env,
cgid_req_t *req)
{
@@ -472,31 +499,31 @@ static apr_status_t send_req(int fd, request_rec *r, char *argv0, char **env,
req.loglevel = r->server->loglevel;
/* Write the request header */
- if ((stat = sock_write(fd, &req, sizeof(req))) != APR_SUCCESS) {
- return stat;
+ if (req.args_len) {
+ stat = sock_writev(fd, r, 5,
+ &req, sizeof(req),
+ r->filename, req.filename_len,
+ argv0, req.argv0_len,
+ r->uri, req.uri_len,
+ r->args, req.args_len);
+ } else {
+ stat = sock_writev(fd, r, 4,
+ &req, sizeof(req),
+ r->filename, req.filename_len,
+ argv0, req.argv0_len,
+ r->uri, req.uri_len);
}
- /* Write filename, argv0, uri, and args */
- if ((stat = sock_write(fd, r->filename, req.filename_len)) != APR_SUCCESS ||
- (stat = sock_write(fd, argv0, req.argv0_len)) != APR_SUCCESS ||
- (stat = sock_write(fd, r->uri, req.uri_len)) != APR_SUCCESS) {
+ if (stat != APR_SUCCESS) {
return stat;
}
- if (req.args_len) {
- if ((stat = sock_write(fd, r->args, req.args_len)) != APR_SUCCESS) {
- return stat;
- }
- }
/* write the environment variables */
for (i = 0; i < req.env_count; i++) {
apr_size_t curlen = strlen(env[i]);
- if ((stat = sock_write(fd, &curlen, sizeof(curlen))) != APR_SUCCESS) {
- return stat;
- }
-
- if ((stat = sock_write(fd, env[i], curlen)) != APR_SUCCESS) {
+ if ((stat = sock_writev(fd, r, 2, &curlen, sizeof(curlen),
+ env[i], curlen)) != APR_SUCCESS) {
return stat;
}
}
diff --git a/modules/generators/mod_info.c b/modules/generators/mod_info.c
index 9d8495ca..297953fd 100644
--- a/modules/generators/mod_info.c
+++ b/modules/generators/mod_info.c
@@ -44,6 +44,8 @@
#include "apr.h"
#include "apr_strings.h"
#include "apr_lib.h"
+#include "apr_version.h"
+#include "apu_version.h"
#define APR_WANT_STRFUNC
#include "apr_want.h"
@@ -352,6 +354,18 @@ static int show_server_settings(request_rec * r)
"<font size=\"+1\"><tt>%s</tt></font></dt>\n",
ap_get_server_built());
ap_rprintf(r,
+ "<dt><strong>Server loaded APR Version:</strong> "
+ "<tt>%s</tt></dt>\n", apr_version_string());
+ ap_rprintf(r,
+ "<dt><strong>Compiled with APR Version:</strong> "
+ "<tt>%s</tt></dt>\n", APR_VERSION_STRING);
+ ap_rprintf(r,
+ "<dt><strong>Server loaded APU Version:</strong> "
+ "<tt>%s</tt></dt>\n", apu_version_string());
+ ap_rprintf(r,
+ "<dt><strong>Compiled with APU Version:</strong> "
+ "<tt>%s</tt></dt>\n", APU_VERSION_STRING);
+ ap_rprintf(r,
"<dt><strong>Module Magic Number:</strong> "
"<tt>%d:%d</tt></dt>\n", MODULE_MAGIC_NUMBER_MAJOR,
MODULE_MAGIC_NUMBER_MINOR);
diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c
index 89263d4d..f7f86df4 100644
--- a/modules/http/http_filters.c
+++ b/modules/http/http_filters.c
@@ -329,11 +329,14 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b,
ctx->eos_sent = 1;
} else {
char *tmp;
+ int len;
tmp = apr_pstrcat(f->r->pool, AP_SERVER_PROTOCOL, " ",
ap_get_status_line(100), CRLF CRLF, NULL);
+ len = strlen(tmp);
+ ap_xlate_proto_to_ascii(tmp, len);
apr_brigade_cleanup(bb);
- e = apr_bucket_pool_create(tmp, strlen(tmp), f->r->pool,
+ e = apr_bucket_pool_create(tmp, len, f->r->pool,
f->c->bucket_alloc);
APR_BRIGADE_INSERT_HEAD(bb, e);
e = apr_bucket_flush_create(f->c->bucket_alloc);
diff --git a/modules/http/http_protocol.c b/modules/http/http_protocol.c
index 10e6514b..046e98bc 100644
--- a/modules/http/http_protocol.c
+++ b/modules/http/http_protocol.c
@@ -1044,8 +1044,8 @@ static const char *get_canned_error_string(int status,
"request due to maintenance downtime or capacity\n"
"problems. Please try again later.</p>\n");
case HTTP_GATEWAY_TIME_OUT:
- return("<p>The proxy server did not receive a timely response\n"
- "from the upstream server.</p>\n");
+ return("<p>The gateway did not receive a timely response\n"
+ "from the upstream server or application.</p>\n");
case HTTP_NOT_EXTENDED:
return("<p>A mandatory extension policy in the request is not\n"
"accepted by the server for this resource.</p>\n");
diff --git a/modules/ldap/util_ldap.c b/modules/ldap/util_ldap.c
index 5ea50d0a..c9cc6e98 100644
--- a/modules/ldap/util_ldap.c
+++ b/modules/ldap/util_ldap.c
@@ -232,7 +232,16 @@ static int uldap_connection_init(request_rec *r,
&(result));
- if (result != NULL && result->rc) {
+ if (NULL == result) {
+ /* something really bad happened */
+ ldc->bound = 0;
+ if (NULL == ldc->reason) {
+ ldc->reason = "LDAP: ldap initialization failed";
+ }
+ return(APR_EGENERAL);
+ }
+
+ if (result->rc) {
ldc->reason = result->reason;
}
diff --git a/modules/mappers/mod_alias.c b/modules/mappers/mod_alias.c
index bde1703d..6a6856c5 100644
--- a/modules/mappers/mod_alias.c
+++ b/modules/mappers/mod_alias.c
@@ -176,21 +176,41 @@ static const char *add_redirect_internal(cmd_parms *cmd,
alias_server_conf *serverconf = ap_get_module_config(s->module_config,
&alias_module);
int status = (int) (long) cmd->info;
+ int grokarg1 = 1;
ap_regex_t *r = NULL;
const char *f = arg2;
const char *url = arg3;
- if (!strcasecmp(arg1, "gone"))
- status = HTTP_GONE;
- else if (!strcasecmp(arg1, "permanent"))
+ /*
+ * Logic flow:
+ * Go ahead and try to grok the 1st arg, in case it is a
+ * Redirect status. Now if we have 3 args, we expect that
+ * we were able to understand that 1st argument (it's something
+ * we expected, so if not, then we bail
+ */
+ if (!strcasecmp(arg1, "permanent"))
status = HTTP_MOVED_PERMANENTLY;
else if (!strcasecmp(arg1, "temp"))
status = HTTP_MOVED_TEMPORARILY;
else if (!strcasecmp(arg1, "seeother"))
status = HTTP_SEE_OTHER;
+ else if (!strcasecmp(arg1, "gone"))
+ status = HTTP_GONE;
else if (apr_isdigit(*arg1))
status = atoi(arg1);
- else {
+ else
+ grokarg1 = 0;
+
+ if (arg3 && !grokarg1)
+ return "Redirect: invalid first argument (of three)";
+
+ /*
+ * if we don't have the 3rd arg and we didn't understand the 1st
+ * one, then assume URL-path URL. This also handles case, eg, GONE
+ * we even though we don't have a 3rd arg, we did understand the 1st
+ * one, so we don't want to re-arrange
+ */
+ if (!arg3 && !grokarg1) {
f = arg1;
url = arg2;
}
@@ -405,8 +425,29 @@ static int translate_alias_redir(request_rec *r)
if ((ret = try_alias_list(r, serverconf->redirects, 1, &status)) != NULL) {
if (ap_is_HTTP_REDIRECT(status)) {
- /* include QUERY_STRING if any */
- if (r->args) {
+ char *orig_target = ret;
+ if (ret[0] == '/') {
+
+ ret = ap_construct_url(r->pool, ret, r);
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
+ "incomplete redirection target of '%s' for "
+ "URI '%s' modified to '%s'",
+ orig_target, r->uri, ret);
+ }
+ if (!ap_is_url(ret)) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "cannot redirect '%s' to '%s'; "
+ "target is not a valid absoluteURI or abs_path",
+ r->uri, ret);
+ /* restore the config value, so as not to get a
+ * "regression" on existing "working" configs.
+ */
+ ret = orig_target;
+ }
+ /* append requested query only, if the config didn't
+ * supply its own.
+ */
+ if (r->args && !ap_strchr(ret, '?')) {
ret = apr_pstrcat(r->pool, ret, "?", r->args, NULL);
}
apr_table_setn(r->headers_out, "Location", ret);
diff --git a/modules/mappers/mod_negotiation.c b/modules/mappers/mod_negotiation.c
index c9fff1e5..a9c6bc9e 100644
--- a/modules/mappers/mod_negotiation.c
+++ b/modules/mappers/mod_negotiation.c
@@ -2530,7 +2530,7 @@ static void set_neg_headers(request_rec *r, negotiation_state *neg,
/* Generate the string components for this Alternates entry */
*((const char **) apr_array_push(arr)) = "{\"";
- *((const char **) apr_array_push(arr)) = variant->file_name;
+ *((const char **) apr_array_push(arr)) = ap_escape_path_segment(r->pool, variant->file_name);
*((const char **) apr_array_push(arr)) = "\" ";
qstr = (char *) apr_palloc(r->pool, 6);
@@ -2804,7 +2804,7 @@ static int setup_choice_response(request_rec *r, negotiation_state *neg,
}
apr_table_setn(r->err_headers_out, "Content-Location",
- apr_pstrdup(r->pool, variant->file_name));
+ ap_escape_path_segment(r->pool, variant->file_name));
set_neg_headers(r, neg, alg_choice); /* add Alternates and Vary */
diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c
index 863d69e1..b9c8a51f 100644
--- a/modules/mappers/mod_rewrite.c
+++ b/modules/mappers/mod_rewrite.c
@@ -147,6 +147,7 @@
#define RULEFLAG_NOSUB 1<<12
#define RULEFLAG_STATUS 1<<13
#define RULEFLAG_ESCAPEBACKREF 1<<14
+#define RULEFLAG_DISCARDPATHINFO 1<<15
/* return code of the rewrite rule
* the result may be escaped - or not
@@ -373,13 +374,10 @@ static int rewrite_rand_init_done = 0;
static const char *lockname;
static apr_global_mutex_t *rewrite_mapr_lock_acquire = NULL;
-#ifndef REWRITELOG_DISABLED
-static apr_global_mutex_t *rewrite_log_lock = NULL;
-#endif
-
/* Optional functions imported from mod_ssl when loaded: */
static APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *rewrite_ssl_lookup = NULL;
static APR_OPTIONAL_FN_TYPE(ssl_is_https) *rewrite_is_https = NULL;
+static char *escape_uri(apr_pool_t *p, const char *path);
/*
* +-------------------------------------------------------+
@@ -472,7 +470,6 @@ static void do_rewritelog(request_rec *r, int level, char *perdir,
const char *rhost, *rname;
apr_size_t nbytes;
int redir;
- apr_status_t rv;
request_rec *req;
va_list ap;
@@ -512,23 +509,9 @@ static void do_rewritelog(request_rec *r, int level, char *perdir,
perdir ? "] ": "",
text);
- rv = apr_global_mutex_lock(rewrite_log_lock);
- if (rv != APR_SUCCESS) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
- "apr_global_mutex_lock(rewrite_log_lock) failed");
- /* XXX: Maybe this should be fatal? */
- }
-
nbytes = strlen(logline);
apr_file_write(conf->rewritelogfp, logline, &nbytes);
- rv = apr_global_mutex_unlock(rewrite_log_lock);
- if (rv != APR_SUCCESS) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
- "apr_global_mutex_unlock(rewrite_log_lock) failed");
- /* XXX: Maybe this should be fatal? */
- }
-
return;
}
#endif /* !REWRITELOG_DISABLED */
@@ -628,6 +611,46 @@ static unsigned is_absolute_uri(char *uri)
return 0;
}
+static const char c2x_table[] = "0123456789abcdef";
+
+static APR_INLINE unsigned char *c2x(unsigned what, unsigned char prefix,
+ unsigned char *where)
+{
+#if APR_CHARSET_EBCDIC
+ what = apr_xlate_conv_byte(ap_hdrs_to_ascii, (unsigned char)what);
+#endif /*APR_CHARSET_EBCDIC*/
+ *where++ = prefix;
+ *where++ = c2x_table[what >> 4];
+ *where++ = c2x_table[what & 0xf];
+ return where;
+}
+
+/*
+ * Escapes a uri in a similar way as php's urlencode does.
+ * Based on ap_os_escape_path in server/util.c
+ */
+static char *escape_uri(apr_pool_t *p, const char *path) {
+ char *copy = apr_palloc(p, 3 * strlen(path) + 3);
+ const unsigned char *s = (const unsigned char *)path;
+ unsigned char *d = (unsigned char *)copy;
+ unsigned c;
+
+ while ((c = *s)) {
+ if (apr_isalnum(c) || c == '_') {
+ *d++ = c;
+ }
+ else if (c == ' ') {
+ *d++ = '+';
+ }
+ else {
+ d = c2x(c, '%', d);
+ }
+ ++s;
+ }
+ *d = '\0';
+ return copy;
+}
+
/*
* escape absolute uri, which may or may not be path oriented.
* So let's handle them differently.
@@ -2240,15 +2263,16 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry)
if (entry && (entry->flags & RULEFLAG_ESCAPEBACKREF)) {
/* escape the backreference */
char *tmp2, *tmp;
- tmp = apr_pstrndup(pool, bri->source + bri->regmatch[n].rm_so, span);
- tmp2 = ap_escape_path_segment(pool, tmp);
+ tmp = apr_palloc(pool, span + 1);
+ strncpy(tmp, bri->source + bri->regmatch[n].rm_so, span);
+ tmp[span] = '\0';
+ tmp2 = escape_uri(pool, tmp);
rewritelog((ctx->r, 5, ctx->perdir, "escaping backreference '%s' to '%s'",
tmp, tmp2));
current->len = span = strlen(tmp2);
current->string = tmp2;
- }
- else {
+ } else {
current->len = span;
current->string = bri->source + bri->regmatch[n].rm_so;
}
@@ -3021,7 +3045,7 @@ static const char *cmd_parseflagfield(apr_pool_t *p, void *cfg, char *key,
endp = key + strlen(key) - 1;
if (*key != '[' || *endp != ']') {
- return "RewriteCond: bad flag delimiters";
+ return "bad flag delimiters";
}
*endp = ','; /* for simpler parsing */
@@ -3084,7 +3108,7 @@ static const char *cmd_rewritecond_setflag(apr_pool_t *p, void *_cfg,
cfg->flags |= CONDFLAG_NOVARY;
}
else {
- return apr_pstrcat(p, "RewriteCond: unknown flag '", key, "'", NULL);
+ return apr_pstrcat(p, "unknown flag '", key, "'", NULL);
}
return NULL;
}
@@ -3133,7 +3157,7 @@ static const char *cmd_rewritecond(cmd_parms *cmd, void *in_dconf,
if (a3 != NULL) {
if ((err = cmd_parseflagfield(cmd->pool, newcond, a3,
cmd_rewritecond_setflag)) != NULL) {
- return err;
+ return apr_pstrcat(cmd->pool, "RewriteCond: ", err, NULL);
}
}
@@ -3239,7 +3263,12 @@ static const char *cmd_rewriterule_setflag(apr_pool_t *p, void *_cfg,
++error;
}
break;
-
+ case 'd':
+ case 'D':
+ if (!*key || !strcasecmp(key, "PI") || !strcasecmp(key,"iscardpath")) {
+ cfg->flags |= (RULEFLAG_DISCARDPATHINFO);
+ }
+ break;
case 'e':
case 'E':
if (!*key || !strcasecmp(key, "nv")) { /* env */
@@ -3295,7 +3324,6 @@ static const char *cmd_rewriterule_setflag(apr_pool_t *p, void *_cfg,
++error;
}
break;
-
case 'l':
case 'L':
if (!*key || !strcasecmp(key, "ast")) { /* last */
@@ -3376,7 +3404,7 @@ static const char *cmd_rewriterule_setflag(apr_pool_t *p, void *_cfg,
ap_index_of_response(HTTP_INTERNAL_SERVER_ERROR);
if (ap_index_of_response(status) == idx) {
- return apr_psprintf(p, "RewriteRule: invalid HTTP "
+ return apr_psprintf(p, "invalid HTTP "
"response code '%s' for "
"flag 'R'",
val);
@@ -3419,7 +3447,7 @@ static const char *cmd_rewriterule_setflag(apr_pool_t *p, void *_cfg,
}
if (error) {
- return apr_pstrcat(p, "RewriteRule: unknown flag '", --key, "'", NULL);
+ return apr_pstrcat(p, "unknown flag '", --key, "'", NULL);
}
return NULL;
@@ -3465,7 +3493,7 @@ static const char *cmd_rewriterule(cmd_parms *cmd, void *in_dconf,
if (a3 != NULL) {
if ((err = cmd_parseflagfield(cmd->pool, newrule, a3,
cmd_rewriterule_setflag)) != NULL) {
- return err;
+ return apr_pstrcat(cmd->pool, "RewriteRule: ", err, NULL);
}
}
@@ -3847,6 +3875,11 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx)
/* Now adjust API's knowledge about r->filename and r->args */
r->filename = newuri;
+
+ if (ctx->perdir && (p->flags & RULEFLAG_DISCARDPATHINFO)) {
+ r->path_info = NULL;
+ }
+
splitout_queryargs(r, p->flags & RULEFLAG_QSAPPEND);
/* Add the previously stripped per-directory location prefix, unless
@@ -3869,7 +3902,20 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx)
* ourself).
*/
if (p->flags & RULEFLAG_PROXY) {
- /* PR#39746: Escaping things here gets repeated in mod_proxy */
+ /* For rules evaluated in server context, the mod_proxy fixup
+ * hook can be relied upon to escape the URI as and when
+ * necessary, since it occurs later. If in directory context,
+ * the ordering of the fixup hooks is forced such that
+ * mod_proxy comes first, so the URI must be escaped here
+ * instead. See PR 39746, 46428, and other headaches. */
+ if (ctx->perdir && (p->flags & RULEFLAG_NOESCAPE) == 0) {
+ char *old_filename = r->filename;
+
+ r->filename = ap_escape_uri(r->pool, r->filename);
+ rewritelog((r, 2, ctx->perdir, "escaped URI in per-dir context "
+ "for proxy, %s -> %s", old_filename, r->filename));
+ }
+
fully_qualify_uri(r);
rewritelog((r, 2, ctx->perdir, "forcing proxy-throughput with %s",
@@ -4099,26 +4145,6 @@ static int post_config(apr_pool_t *p,
/* check if proxy module is available */
proxy_available = (ap_find_linked_module("mod_proxy.c") != NULL);
-#ifndef REWRITELOG_DISABLED
- /* create the rewriting lockfiles in the parent */
- if ((rv = apr_global_mutex_create(&rewrite_log_lock, NULL,
- APR_LOCK_DEFAULT, p)) != APR_SUCCESS) {
- ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
- "mod_rewrite: could not create rewrite_log_lock");
- return HTTP_INTERNAL_SERVER_ERROR;
- }
-
-#ifdef AP_NEED_SET_MUTEX_PERMS
- rv = unixd_set_global_mutex_perms(rewrite_log_lock);
- if (rv != APR_SUCCESS) {
- ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
- "mod_rewrite: Could not set permissions on "
- "rewrite_log_lock; check User and Group directives");
- return HTTP_INTERNAL_SERVER_ERROR;
- }
-#endif /* perms */
-#endif /* rewritelog */
-
rv = rewritelock_create(s, p);
if (rv != APR_SUCCESS) {
return HTTP_INTERNAL_SERVER_ERROR;
@@ -4165,14 +4191,6 @@ static void init_child(apr_pool_t *p, server_rec *s)
}
}
-#ifndef REWRITELOG_DISABLED
- rv = apr_global_mutex_child_init(&rewrite_log_lock, NULL, p);
- if (rv != APR_SUCCESS) {
- ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
- "mod_rewrite: could not init rewrite log lock in child");
- }
-#endif
-
/* create the lookup cache */
if (!init_cache(p)) {
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s,
diff --git a/modules/mappers/mod_so.c b/modules/mappers/mod_so.c
index 44bed43b..2d4a54c2 100644
--- a/modules/mappers/mod_so.c
+++ b/modules/mappers/mod_so.c
@@ -363,7 +363,7 @@ static void dump_loaded_modules(apr_pool_t *p, server_rec *s)
return;
}
- apr_file_open_stderr(&out, p);
+ apr_file_open_stdout(&out, p);
apr_file_printf(out, "Loaded Modules:\n");
diff --git a/modules/metadata/config.m4 b/modules/metadata/config.m4
index c970a717..6eb0e4e9 100644
--- a/modules/metadata/config.m4
+++ b/modules/metadata/config.m4
@@ -18,6 +18,6 @@ APACHE_MODULE(usertrack, user-session tracking, , , , [
APACHE_MODULE(unique_id, per-request unique ids)
APACHE_MODULE(setenvif, basing ENV vars on headers, , , yes)
-APACHE_MODULE(version, determining httpd version in config files)
+APACHE_MODULE(version, determining httpd version in config files, , , yes)
APACHE_MODPATH_FINISH
diff --git a/modules/metadata/mod_headers.c b/modules/metadata/mod_headers.c
index 8e748fa9..b65fbfd0 100644
--- a/modules/metadata/mod_headers.c
+++ b/modules/metadata/mod_headers.c
@@ -680,6 +680,9 @@ static void do_headers_fixup(request_rec *r, apr_table_t *headers,
}
break;
case hdr_set:
+ if (!strcasecmp(hdr->header, "Content-Type")) {
+ ap_set_content_type(r, process_tags(hdr, r));
+ }
apr_table_setn(headers, hdr->header, process_tags(hdr, r));
break;
case hdr_unset:
diff --git a/modules/metadata/mod_mime_magic.c b/modules/metadata/mod_mime_magic.c
index cd627911..867a4964 100644
--- a/modules/metadata/mod_mime_magic.c
+++ b/modules/metadata/mod_mime_magic.c
@@ -2099,13 +2099,15 @@ static int zmagic(request_rec *r, unsigned char *buf, apr_size_t nbytes)
if (i == ncompr)
return 0;
- if ((newsize = uncompress(r, i, &newbuf, nbytes)) > 0) {
+ if ((newsize = uncompress(r, i, &newbuf, HOWMANY)) > 0) {
+ /* set encoding type in the request record */
+ r->content_encoding = compr[i].encoding;
+
+ newbuf[newsize-1] = '\0'; /* null-terminate uncompressed data */
+ /* Try to detect the content type of the uncompressed data */
if (tryit(r, newbuf, newsize, 0) != OK) {
return 0;
}
-
- /* set encoding type in the request record */
- r->content_encoding = compr[i].encoding;
}
return 1;
}
@@ -2121,7 +2123,6 @@ static int create_uncompress_child(struct uncompress_parms *parm, apr_pool_t *cn
{
int rc = 1;
const char *new_argv[4];
- const char *const *env;
request_rec *r = parm->r;
apr_pool_t *child_context = cntxt;
apr_procattr_t *procattr;
@@ -2133,13 +2134,12 @@ static int create_uncompress_child(struct uncompress_parms *parm, apr_pool_t *cn
* Should we create the err pipe, read it, and copy to the log?
*/
- env = (const char *const *)ap_create_environment(child_context, r->subprocess_env);
-
if ((apr_procattr_create(&procattr, child_context) != APR_SUCCESS) ||
(apr_procattr_io_set(procattr, APR_FULL_BLOCK,
APR_FULL_BLOCK, APR_NO_PIPE) != APR_SUCCESS) ||
- (apr_procattr_dir_set(procattr, r->filename) != APR_SUCCESS) ||
- (apr_procattr_cmdtype_set(procattr, APR_PROGRAM) != APR_SUCCESS)) {
+ (apr_procattr_dir_set(procattr,
+ ap_make_dirstr_parent(r->pool, r->filename)) != APR_SUCCESS) ||
+ (apr_procattr_cmdtype_set(procattr, APR_PROGRAM_PATH) != APR_SUCCESS)) {
/* Something bad happened, tell the world. */
ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_ENOPROC, r,
"couldn't setup child process: %s", r->filename);
@@ -2152,7 +2152,7 @@ static int create_uncompress_child(struct uncompress_parms *parm, apr_pool_t *cn
procnew = apr_pcalloc(child_context, sizeof(*procnew));
rc = apr_proc_create(procnew, compr[parm->method].argv[0],
- new_argv, env, procattr, child_context);
+ new_argv, NULL, procattr, child_context);
if (rc != APR_SUCCESS) {
/* Bad things happened. Everyone should have cleaned up. */
@@ -2473,5 +2473,3 @@ module AP_MODULE_DECLARE_DATA mime_magic_module =
mime_magic_cmds, /* command apr_table_t */
register_hooks /* register hooks */
};
-
-
diff --git a/modules/proxy/ajp_header.c b/modules/proxy/ajp_header.c
index 9130de9a..90a5a074 100644
--- a/modules/proxy/ajp_header.c
+++ b/modules/proxy/ajp_header.c
@@ -403,6 +403,26 @@ static apr_status_t ajp_marshal_into_msgb(ajp_msg_t *msg,
}
}
}
+ /* Forward the remote port information, which was forgotten
+ * from the builtin data of the AJP 13 protocol.
+ * Since the servlet spec allows to retrieve it via getRemotePort(),
+ * we provide the port to the Tomcat connector as a request
+ * attribute. Modern Tomcat versions know how to retrieve
+ * the remote port from this attribute.
+ */
+ {
+ const char *key = SC_A_REQ_REMOTE_PORT;
+ char *val = apr_itoa(r->pool, r->connection->remote_addr->port);
+ if (ajp_msg_append_uint8(msg, SC_A_REQ_ATTRIBUTE) ||
+ ajp_msg_append_string(msg, key) ||
+ ajp_msg_append_string(msg, val)) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+ "ajp_marshal_into_msgb: "
+ "Error appending attribute %s=%s",
+ key, val);
+ return AJP_EOVERFLOW;
+ }
+ }
/* Use the environment vars prefixed with AJP_
* and pass it to the header striping that prefix.
*/
diff --git a/modules/proxy/ajp_header.h b/modules/proxy/ajp_header.h
index bb6adae3..35379fee 100644
--- a/modules/proxy/ajp_header.h
+++ b/modules/proxy/ajp_header.h
@@ -44,6 +44,14 @@
#define SC_A_ARE_DONE (unsigned char)0xFF
/*
+ * AJP private request attributes
+ *
+ * The following request attribute is recognized by Tomcat
+ * to contain the forwarded remote port.
+ */
+#define SC_A_REQ_REMOTE_PORT ("AJP_REMOTE_PORT")
+
+/*
* Request methods, coded as numbers instead of strings.
* The list of methods was taken from Section 5.1.1 of RFC 2616,
* RFC 2518, the ACL IETF draft, and the DeltaV IESG Proposed Standard.
diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c
index 45365364..70dddbb5 100644
--- a/modules/proxy/mod_proxy.c
+++ b/modules/proxy/mod_proxy.c
@@ -1002,8 +1002,10 @@ static int proxy_handler(request_rec *r)
* We can not failover to another worker.
* Mark the worker as unusable if member of load balancer
*/
- if (balancer)
+ if (balancer) {
worker->s->status |= PROXY_WORKER_IN_ERROR;
+ worker->s->error_time = apr_time_now();
+ }
break;
}
else if (access_status == HTTP_SERVICE_UNAVAILABLE) {
@@ -1013,6 +1015,7 @@ static int proxy_handler(request_rec *r)
*/
if (balancer) {
worker->s->status |= PROXY_WORKER_IN_ERROR;
+ worker->s->error_time = apr_time_now();
}
}
else {
diff --git a/modules/proxy/mod_proxy_ajp.c b/modules/proxy/mod_proxy_ajp.c
index c3b80e3d..66693aa9 100644
--- a/modules/proxy/mod_proxy_ajp.c
+++ b/modules/proxy/mod_proxy_ajp.c
@@ -180,6 +180,7 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
int backend_failed = 0;
apr_off_t bb_len;
int data_sent = 0;
+ int request_ended = 0;
int headers_sent = 0;
int rv = 0;
apr_int32_t conn_poll_fd;
@@ -307,21 +308,17 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
"proxy: read zero bytes, expecting"
" %" APR_OFF_T_FMT " bytes",
content_length);
- status = ajp_send_data_msg(conn->sock, msg, 0);
- if (status != APR_SUCCESS) {
- /* We had a failure: Close connection to backend */
- conn->close++;
- ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
- "proxy: send failed to %pI (%s)",
- conn->worker->cp->addr,
- conn->worker->hostname);
- return HTTP_INTERNAL_SERVER_ERROR;
- }
- else {
- /* Client send zero bytes with C-L > 0
- */
- return HTTP_BAD_REQUEST;
- }
+ /*
+ * We can only get here if the client closed the connection
+ * to us without sending the body.
+ * Now the connection is in the wrong state on the backend.
+ * Sending an empty data msg doesn't help either as it does
+ * not move this connection to the correct state on the backend
+ * for later resusage by the next request again.
+ * Close it to clean things up.
+ */
+ conn->close++;
+ return HTTP_BAD_REQUEST;
}
}
@@ -419,6 +416,15 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
}
break;
case CMD_AJP13_SEND_HEADERS:
+ if (headers_sent) {
+ /* Do not send anything to the client.
+ * Backend already send us the headers.
+ */
+ backend_failed = 1;
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: Backend sent headers twice.");
+ break;
+ }
/* AJP13_SEND_HEADERS: process them */
status = ajp_parse_header(r, conf, conn->data);
if (status != APR_SUCCESS) {
@@ -484,6 +490,7 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
}
/* XXX: what about flush here? See mod_jk */
data_sent = 1;
+ request_ended = 1;
break;
default:
backend_failed = 1;
@@ -540,6 +547,17 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
rv = DONE;
}
}
+ else if (!request_ended) {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ "proxy: Processing of request didn't terminate cleanly");
+ /* We had a failure: Close connection to backend */
+ conn->close++;
+ backend_failed = 1;
+ /* Return DONE to avoid error messages being added to the stream */
+ if (data_sent) {
+ rv = DONE;
+ }
+ }
else {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
"proxy: got response from %pI (%s)",
diff --git a/modules/proxy/mod_proxy_balancer.c b/modules/proxy/mod_proxy_balancer.c
index c0dc2af9..e5a010db 100644
--- a/modules/proxy/mod_proxy_balancer.c
+++ b/modules/proxy/mod_proxy_balancer.c
@@ -406,7 +406,15 @@ static void force_recovery(proxy_balancer *balancer, server_rec *s)
for (i = 0; i < balancer->workers->nelts; i++, worker++) {
if (!(worker->s->status & PROXY_WORKER_IN_ERROR)) {
ok = 1;
- break;
+ break;
+ }
+ else {
+ /* Try if we can recover */
+ ap_proxy_retry_worker("BALANCER", worker, s);
+ if (!(worker->s->status & PROXY_WORKER_IN_ERROR)) {
+ ok = 1;
+ break;
+ }
}
}
if (!ok) {
@@ -1006,7 +1014,7 @@ static proxy_worker *find_best_byrequests(proxy_balancer *balancer,
if (worker->s->lbset > max_lbset)
max_lbset = worker->s->lbset;
}
- if (worker->s->lbset > cur_lbset)
+ if (worker->s->lbset != cur_lbset)
continue;
if ( (checking_standby ? !PROXY_WORKER_IS_STANDBY(worker) : PROXY_WORKER_IS_STANDBY(worker)) )
continue;
@@ -1088,7 +1096,7 @@ static proxy_worker *find_best_bytraffic(proxy_balancer *balancer,
if (worker->s->lbset > max_lbset)
max_lbset = worker->s->lbset;
}
- if (worker->s->lbset > cur_lbset)
+ if (worker->s->lbset != cur_lbset)
continue;
if ( (checking_standby ? !PROXY_WORKER_IS_STANDBY(worker) : PROXY_WORKER_IS_STANDBY(worker)) )
continue;
@@ -1158,7 +1166,7 @@ static proxy_worker *find_best_bybusyness(proxy_balancer *balancer,
max_lbset = worker->s->lbset;
}
- if (worker->s->lbset > cur_lbset)
+ if (worker->s->lbset != cur_lbset)
continue;
if ( (checking_standby ? !PROXY_WORKER_IS_STANDBY(worker) : PROXY_WORKER_IS_STANDBY(worker)) )
diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c
index b60db985..34015263 100644
--- a/modules/proxy/mod_proxy_http.c
+++ b/modules/proxy/mod_proxy_http.c
@@ -422,10 +422,16 @@ static int stream_reqbody_cl(apr_pool_t *p,
apr_off_t bytes_streamed = 0;
if (old_cl_val) {
+ char *endstr;
+
add_cl(p, bucket_alloc, header_brigade, old_cl_val);
- if (APR_SUCCESS != (status = apr_strtoff(&cl_val, old_cl_val, NULL,
- 0))) {
- return HTTP_INTERNAL_SERVER_ERROR;
+ status = apr_strtoff(&cl_val, old_cl_val, &endstr, 10);
+
+ if (status || *endstr || endstr == old_cl_val || cl_val < 0) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r,
+ "proxy: could not parse request Content-Length (%s)",
+ old_cl_val);
+ return HTTP_BAD_REQUEST;
}
}
terminate_headers(bucket_alloc, header_brigade);
@@ -453,8 +459,13 @@ static int stream_reqbody_cl(apr_pool_t *p,
*
* Prevents HTTP Response Splitting.
*/
- if (bytes_streamed > cl_val)
- continue;
+ if (bytes_streamed > cl_val) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "proxy: read more bytes of request body than expected "
+ "(got %" APR_OFF_T_FMT ", expected %" APR_OFF_T_FMT ")",
+ bytes_streamed, cl_val);
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
if (header_brigade) {
/* we never sent the header brigade, so go ahead and
@@ -720,11 +731,20 @@ int ap_proxy_http_request(apr_pool_t *p, request_rec *r,
e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(header_brigade, e);
if (conf->preserve_host == 0) {
- if (uri->port_str && uri->port != DEFAULT_HTTP_PORT) {
- buf = apr_pstrcat(p, "Host: ", uri->hostname, ":", uri->port_str,
- CRLF, NULL);
+ if (ap_strchr_c(uri->hostname, ':')) { /* if literal IPv6 address */
+ if (uri->port_str && uri->port != DEFAULT_HTTP_PORT) {
+ buf = apr_pstrcat(p, "Host: [", uri->hostname, "]:",
+ uri->port_str, CRLF, NULL);
+ } else {
+ buf = apr_pstrcat(p, "Host: [", uri->hostname, "]", CRLF, NULL);
+ }
} else {
- buf = apr_pstrcat(p, "Host: ", uri->hostname, CRLF, NULL);
+ if (uri->port_str && uri->port != DEFAULT_HTTP_PORT) {
+ buf = apr_pstrcat(p, "Host: ", uri->hostname, ":",
+ uri->port_str, CRLF, NULL);
+ } else {
+ buf = apr_pstrcat(p, "Host: ", uri->hostname, CRLF, NULL);
+ }
}
}
else {
@@ -933,7 +953,7 @@ int ap_proxy_http_request(apr_pool_t *p, request_rec *r,
* encoding has been done by the extensions' handler, and
* do not modify add_te_chunked's logic
*/
- if (old_te_val && strcmp(old_te_val, "chunked") != 0) {
+ if (old_te_val && strcasecmp(old_te_val, "chunked") != 0) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
"proxy: %s Transfer-Encoding is not supported",
old_te_val);
@@ -1622,7 +1642,7 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r,
*/
const char *policy = apr_table_get(r->subprocess_env,
"proxy-interim-response");
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL,
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
"proxy: HTTP: received interim %d response",
r->status);
if (!policy || !strcasecmp(policy, "RFC")) {
@@ -1632,7 +1652,7 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r,
* policies and maybe also add option to bail out with 502
*/
else if (strcasecmp(policy, "Suppress")) {
- ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL,
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
"undefined proxy interim response policy");
}
}
@@ -1966,6 +1986,15 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker,
if ((status = ap_proxy_connection_create(proxy_function, backend,
c, r->server)) != OK)
goto cleanup;
+ /*
+ * On SSL connections set a note on the connection what CN is
+ * requested, such that mod_ssl can check if it is requested to do
+ * so.
+ */
+ if (is_ssl) {
+ apr_table_set(backend->connection->notes, "proxy-request-hostname",
+ uri->hostname);
+ }
}
/* Step Four: Send the Request */
diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c
index 24f5aa22..b835832d 100644
--- a/modules/proxy/proxy_util.c
+++ b/modules/proxy/proxy_util.c
@@ -1049,6 +1049,7 @@ PROXY_DECLARE(const char *) ap_proxy_location_reverse_map(request_rec *r,
/*
* XXX FIXME: Make sure this handled the ambiguous case of the :<PORT>
* after the hostname
+ * XXX FIXME: Ensure the /uri component is a case sensitive match
*/
if (r->proxyreq != PROXYREQ_REVERSE) {
return url;
@@ -1066,10 +1067,7 @@ PROXY_DECLARE(const char *) ap_proxy_location_reverse_map(request_rec *r,
proxy_server_conf *sconf = (proxy_server_conf *)
ap_get_module_config(r->server->module_config, &proxy_module);
proxy_balancer *balancer;
- const char *real;
- real = ent[i].real;
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
- "ppr: real: %s", real);
+ const char *real = ent[i].real;
/*
* First check if mapping against a balancer and see
* if we have such a entity. If so, then we need to
@@ -1077,42 +1075,49 @@ PROXY_DECLARE(const char *) ap_proxy_location_reverse_map(request_rec *r,
* or may not be the right one... basically, we need
* to find which member actually handled this request.
*/
- if ((strncasecmp(real, "balancer:", 9) == 0) &&
+ if ((strncasecmp(real, "balancer://", 11) == 0) &&
(balancer = ap_proxy_get_balancer(r->pool, sconf, real))) {
- int n;
- proxy_worker *worker;
- worker = (proxy_worker *)balancer->workers->elts;
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
- "ppr: checking balancer: %s",
- balancer->name);
+ int n, l3 = 0;
+ proxy_worker *worker = (proxy_worker *)balancer->workers->elts;
+ const char *urlpart = ap_strchr_c(real + 11, '/');
+ if (urlpart) {
+ if (!urlpart[1])
+ urlpart = NULL;
+ else
+ l3 = strlen(urlpart);
+ }
+ /* The balancer comparison is a bit trickier. Given the context
+ * BalancerMember balancer://alias http://example.com/foo
+ * ProxyPassReverse /bash balancer://alias/bar
+ * translate url http://example.com/foo/bar/that to /bash/that
+ */
for (n = 0; n < balancer->workers->nelts; n++) {
- if (worker->port) {
- u = apr_psprintf(r->pool, "%s://%s:%d/", worker->scheme,
- worker->hostname, worker->port);
+ l2 = strlen(worker->name);
+ if (urlpart) {
+ /* urlpart (l3) assuredly starts with its own '/' */
+ if (worker->name[l2 - 1] == '/')
+ --l2;
+ if (l1 >= l2 + l3
+ && strncasecmp(worker->name, url, l2) == 0
+ && strncmp(urlpart, url + l2, l3) == 0) {
+ u = apr_pstrcat(r->pool, ent[i].fake, &url[l2 + l3],
+ NULL);
+ return ap_construct_url(r->pool, u, r);
+ }
}
- else {
- u = apr_psprintf(r->pool, "%s://%s/", worker->scheme,
- worker->hostname);
- }
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
- "ppr: matching member (%s) and URL (%s)",
- u, url);
-
- l2 = strlen(u);
- if (l1 >= l2 && strncasecmp(u, url, l2) == 0) {
+ else if (l1 >= l2 && strncasecmp(worker->name, url, l2) == 0) {
u = apr_pstrcat(r->pool, ent[i].fake, &url[l2], NULL);
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
- "ppr: matched member (%s)", u);
return ap_construct_url(r->pool, u, r);
}
worker++;
}
}
-
- l2 = strlen(real);
- if (l1 >= l2 && strncasecmp(real, url, l2) == 0) {
- u = apr_pstrcat(r->pool, ent[i].fake, &url[l2], NULL);
- return ap_construct_url(r->pool, u, r);
+ else {
+ l2 = strlen(real);
+ if (l1 >= l2 && strncasecmp(real, url, l2) == 0) {
+ u = apr_pstrcat(r->pool, ent[i].fake, &url[l2], NULL);
+ return ap_construct_url(r->pool, u, r);
+ }
}
}
@@ -1909,8 +1914,11 @@ PROXY_DECLARE(apr_status_t) ap_proxy_initialize_worker(proxy_worker *worker, ser
else
#endif
{
+ void *conn;
+
+ rv = connection_constructor(&conn, worker, worker->cp->pool);
+ worker->cp->conn = conn;
- rv = connection_constructor((void **)&(worker->cp->conn), worker, worker->cp->pool);
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
"proxy: initialized single connection worker %d in child %" APR_PID_T_FMT " for (%s)",
worker->id, getpid(), worker->hostname);
diff --git a/modules/ssl/mod_ssl.c b/modules/ssl/mod_ssl.c
index ff690167..c8600e9d 100644
--- a/modules/ssl/mod_ssl.c
+++ b/modules/ssl/mod_ssl.c
@@ -145,6 +145,8 @@ static const command_rec ssl_config_cmds[] = {
"Use the server's cipher ordering preference")
SSL_CMD_ALL(UserName, TAKE1,
"Set user name to SSL variable value")
+ SSL_CMD_SRV(StrictSNIVHostCheck, FLAG,
+ "Strict SNI virtual host checking")
/*
* Proxy configuration for remote SSL connections
@@ -182,6 +184,10 @@ static const command_rec ssl_config_cmds[] = {
SSL_CMD_SRV(ProxyMachineCertificatePath, TAKE1,
"SSL Proxy: directory containing client certificates "
"(`/path/to/dir' - contains PEM encoded certificates)")
+ SSL_CMD_SRV(ProxyCheckPeerExpire, FLAG,
+ "SSL Proxy: check the peers certificate expiration date")
+ SSL_CMD_SRV(ProxyCheckPeerCN, FLAG,
+ "SSL Proxy: check the peers certificate CN")
/*
* Per-directory context configuration directives
@@ -195,6 +201,10 @@ static const command_rec ssl_config_cmds[] = {
SSL_CMD_DIR(Require, AUTHCFG, RAW_ARGS,
"Require a boolean expression to evaluate to true for granting access"
"(arbitrary complex boolean expression - see manual)")
+ SSL_CMD_DIR(RenegBufferSize, AUTHCFG, TAKE1,
+ "Configure the amount of memory that will be used for buffering the "
+ "request body if a per-location SSL renegotiation is required due to "
+ "changed access control requirements")
/* Deprecated directives. */
AP_INIT_RAW_ARGS("SSLLog", ap_set_deprecated, NULL, OR_ALL,
@@ -295,6 +305,8 @@ static SSLConnRec *ssl_init_connection_ctx(conn_rec *c)
sslconn = apr_pcalloc(c->pool, sizeof(*sslconn));
+ sslconn->server = c->base_server;
+
myConnConfigSet(c, sslconn);
return sslconn;
@@ -302,9 +314,10 @@ static SSLConnRec *ssl_init_connection_ctx(conn_rec *c)
int ssl_proxy_enable(conn_rec *c)
{
- SSLSrvConfigRec *sc = mySrvConfig(c->base_server);
+ SSLSrvConfigRec *sc;
SSLConnRec *sslconn = ssl_init_connection_ctx(c);
+ sc = mySrvConfig(sslconn->server);
if (!sc->proxy_enabled) {
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c,
@@ -322,10 +335,16 @@ int ssl_proxy_enable(conn_rec *c)
int ssl_engine_disable(conn_rec *c)
{
- SSLSrvConfigRec *sc = mySrvConfig(c->base_server);
+ SSLSrvConfigRec *sc;
- SSLConnRec *sslconn;
+ SSLConnRec *sslconn = myConnConfig(c);
+ if (sslconn) {
+ sc = mySrvConfig(sslconn->server);
+ }
+ else {
+ sc = mySrvConfig(c->base_server);
+ }
if (sc->enabled == SSL_ENABLED_FALSE) {
return 0;
}
@@ -339,20 +358,23 @@ int ssl_engine_disable(conn_rec *c)
int ssl_init_ssl_connection(conn_rec *c)
{
- SSLSrvConfigRec *sc = mySrvConfig(c->base_server);
+ SSLSrvConfigRec *sc;
SSL *ssl;
SSLConnRec *sslconn = myConnConfig(c);
char *vhost_md5;
modssl_ctx_t *mctx;
-
- /*
- * Seed the Pseudo Random Number Generator (PRNG)
- */
- ssl_rand_seed(c->base_server, c->pool, SSL_RSCTX_CONNECT, "");
+ server_rec *server;
if (!sslconn) {
sslconn = ssl_init_connection_ctx(c);
}
+ server = sslconn->server;
+ sc = mySrvConfig(server);
+
+ /*
+ * Seed the Pseudo Random Number Generator (PRNG)
+ */
+ ssl_rand_seed(server, c->pool, SSL_RSCTX_CONNECT, "");
mctx = sslconn->is_proxy ? sc->proxy : sc->server;
@@ -365,7 +387,7 @@ int ssl_init_ssl_connection(conn_rec *c)
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c,
"Unable to create a new SSL connection from the SSL "
"context");
- ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, c->base_server);
+ ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, server);
c->aborted = 1;
@@ -380,7 +402,7 @@ int ssl_init_ssl_connection(conn_rec *c)
{
ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c,
"Unable to set session id context to `%s'", vhost_md5);
- ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, c->base_server);
+ ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, server);
c->aborted = 1;
@@ -429,9 +451,15 @@ static apr_port_t ssl_hook_default_port(const request_rec *r)
static int ssl_hook_pre_connection(conn_rec *c, void *csd)
{
- SSLSrvConfigRec *sc = mySrvConfig(c->base_server);
+ SSLSrvConfigRec *sc;
SSLConnRec *sslconn = myConnConfig(c);
+ if (sslconn) {
+ sc = mySrvConfig(sslconn->server);
+ }
+ else {
+ sc = mySrvConfig(c->base_server);
+ }
/*
* Immediately stop processing if SSL is disabled for this connection
*/
diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c
index df6674dd..bda6fe56 100644
--- a/modules/ssl/ssl_engine_config.c
+++ b/modules/ssl/ssl_engine_config.c
@@ -169,6 +169,11 @@ static SSLSrvConfigRec *ssl_config_server_new(apr_pool_t *p)
sc->vhost_id_len = 0; /* set during module init */
sc->session_cache_timeout = UNSET;
sc->cipher_server_pref = UNSET;
+ sc->proxy_ssl_check_peer_expire = SSL_ENABLED_UNSET;
+ sc->proxy_ssl_check_peer_cn = SSL_ENABLED_UNSET;
+#ifndef OPENSSL_NO_TLSEXT
+ sc->strict_sni_vhost_check = SSL_ENABLED_UNSET;
+#endif
modssl_ctx_init_proxy(sc, p);
@@ -257,6 +262,11 @@ void *ssl_config_server_merge(apr_pool_t *p, void *basev, void *addv)
cfgMergeBool(proxy_enabled);
cfgMergeInt(session_cache_timeout);
cfgMergeBool(cipher_server_pref);
+ cfgMerge(proxy_ssl_check_peer_expire, SSL_ENABLED_UNSET);
+ cfgMerge(proxy_ssl_check_peer_cn, SSL_ENABLED_UNSET);
+#ifndef OPENSSL_NO_TLSEXT
+ cfgMerge(strict_sni_vhost_check, SSL_ENABLED_UNSET);
+#endif
modssl_ctx_cfg_merge_proxy(base->proxy, add->proxy, mrg->proxy);
@@ -286,6 +296,8 @@ void *ssl_config_perdir_create(apr_pool_t *p, char *dir)
dc->szCACertificateFile = NULL;
dc->szUserName = NULL;
+ dc->nRenegBufferSize = UNSET;
+
return dc;
}
@@ -323,6 +335,8 @@ void *ssl_config_perdir_merge(apr_pool_t *p, void *basev, void *addv)
cfgMergeString(szCACertificateFile);
cfgMergeString(szUserName);
+ cfgMergeInt(nRenegBufferSize);
+
return mrg;
}
@@ -1185,6 +1199,19 @@ const char *ssl_cmd_SSLRequire(cmd_parms *cmd,
return NULL;
}
+const char *ssl_cmd_SSLRenegBufferSize(cmd_parms *cmd, void *dcfg, const char *arg)
+{
+ SSLDirConfigRec *dc = dcfg;
+
+ dc->nRenegBufferSize = atoi(arg);
+ if (dc->nRenegBufferSize < 0) {
+ return apr_pstrcat(cmd->pool, "Invalid size for SSLRenegBufferSize: ",
+ arg, NULL);
+ }
+
+ return NULL;
+}
+
static const char *ssl_cmd_protocol_parse(cmd_parms *parms,
const char *arg,
ssl_proto_t *options)
@@ -1411,6 +1438,39 @@ const char *ssl_cmd_SSLUserName(cmd_parms *cmd, void *dcfg,
return NULL;
}
+const char *ssl_cmd_SSLProxyCheckPeerExpire(cmd_parms *cmd, void *dcfg, int flag)
+{
+ SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+
+ sc->proxy_ssl_check_peer_expire = flag ? SSL_ENABLED_TRUE : SSL_ENABLED_FALSE;
+
+ return NULL;
+}
+
+const char *ssl_cmd_SSLProxyCheckPeerCN(cmd_parms *cmd, void *dcfg, int flag)
+{
+ SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+
+ sc->proxy_ssl_check_peer_cn = flag ? SSL_ENABLED_TRUE : SSL_ENABLED_FALSE;
+
+ return NULL;
+}
+
+const char *ssl_cmd_SSLStrictSNIVHostCheck(cmd_parms *cmd, void *dcfg, int flag)
+{
+#ifndef OPENSSL_NO_TLSEXT
+ SSLSrvConfigRec *sc = mySrvConfig(cmd->server);
+
+ sc->strict_sni_vhost_check = flag ? SSL_ENABLED_TRUE : SSL_ENABLED_FALSE;
+
+ return NULL;
+#else
+ return "SSLStrictSNIVHostCheck failed; OpenSSL is not built with support "
+ "for TLS extensions and SNI indication. Refer to the "
+ "documentation, and build a compatible version of OpenSSL.";
+#endif
+}
+
void ssl_hook_ConfigTest(apr_pool_t *pconf, server_rec *s)
{
if (!ap_exists_config_define("DUMP_CERTS")) {
diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c
index 8e3cef8f..4c11208a 100644
--- a/modules/ssl/ssl_engine_init.c
+++ b/modules/ssl/ssl_engine_init.c
@@ -358,6 +358,33 @@ static void ssl_init_server_check(server_rec *s,
}
}
+#ifndef OPENSSL_NO_TLSEXT
+static void ssl_init_ctx_tls_extensions(server_rec *s,
+ apr_pool_t *p,
+ apr_pool_t *ptemp,
+ modssl_ctx_t *mctx)
+{
+ /*
+ * Configure TLS extensions support
+ */
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
+ "Configuring TLS extension handling");
+
+ /*
+ * Server name indication (SNI)
+ */
+ if (!SSL_CTX_set_tlsext_servername_callback(mctx->ssl_ctx,
+ ssl_callback_ServerNameIndication) ||
+ !SSL_CTX_set_tlsext_servername_arg(mctx->ssl_ctx, mctx)) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
+ "Unable to initialize TLS servername extension "
+ "callback (incompatible OpenSSL version?)");
+ ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, s);
+ ssl_die();
+ }
+}
+#endif
+
static void ssl_init_ctx_protocol(server_rec *s,
apr_pool_t *p,
apr_pool_t *ptemp,
@@ -690,6 +717,9 @@ static void ssl_init_ctx(server_rec *s,
if (mctx->pks) {
/* XXX: proxy support? */
ssl_init_ctx_cert_chain(s, p, ptemp, mctx);
+#ifndef OPENSSL_NO_TLSEXT
+ ssl_init_ctx_tls_extensions(s, p, ptemp, mctx);
+#endif
}
}
@@ -1039,9 +1069,19 @@ void ssl_init_CheckServers(server_rec *base_server, apr_pool_t *p)
klen = strlen(key);
if ((ps = (server_rec *)apr_hash_get(table, key, klen))) {
- ap_log_error(APLOG_MARK, APLOG_WARNING, 0,
+ ap_log_error(APLOG_MARK,
+#ifdef OPENSSL_NO_TLSEXT
+ APLOG_WARNING,
+#else
+ APLOG_DEBUG,
+#endif
+ 0,
base_server,
+#ifdef OPENSSL_NO_TLSEXT
"Init: SSL server IP/port conflict: "
+#else
+ "Init: SSL server IP/port overlap: "
+#endif
"%s (%s:%d) vs. %s (%s:%d)",
ssl_util_vhostid(p, s),
(s->defn_name ? s->defn_name : "unknown"),
@@ -1058,8 +1098,14 @@ void ssl_init_CheckServers(server_rec *base_server, apr_pool_t *p)
if (conflict) {
ap_log_error(APLOG_MARK, APLOG_WARNING, 0, base_server,
+#ifdef OPENSSL_NO_TLSEXT
"Init: You should not use name-based "
"virtual hosts in conjunction with SSL!!");
+#else
+ "Init: Name-based SSL virtual hosts only "
+ "work for clients with TLS server name indication "
+ "support (RFC 4366)");
+#endif
}
}
diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c
index 1264c289..6e58c6b3 100644
--- a/modules/ssl/ssl_engine_io.c
+++ b/modules/ssl/ssl_engine_io.c
@@ -28,6 +28,7 @@
core keeps dumping.''
-- Unknown */
#include "ssl_private.h"
+#include "apr_date.h"
/* _________________________________________________________________
**
@@ -695,7 +696,7 @@ static apr_status_t ssl_io_input_read(bio_filter_in_ctx_t *inctx,
*/
ap_log_cerror(APLOG_MARK, APLOG_INFO, inctx->rc, c,
"SSL library error %d reading data", ssl_err);
- ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, c->base_server);
+ ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, mySrvFromConn(c));
}
if (inctx->rc == APR_SUCCESS) {
@@ -799,7 +800,7 @@ static apr_status_t ssl_filter_write(ap_filter_t *f,
*/
ap_log_cerror(APLOG_MARK, APLOG_INFO, outctx->rc, c,
"SSL library error %d writing data", ssl_err);
- ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, c->base_server);
+ ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, mySrvFromConn(c));
}
if (outctx->rc == APR_SUCCESS) {
outctx->rc = APR_EGENERAL;
@@ -861,7 +862,7 @@ static apr_status_t ssl_io_filter_error(ap_filter_t *f,
ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, f->c,
"SSL handshake failed: HTTP spoken on HTTPS port; "
"trying to send HTML error page");
- ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, f->c->base_server);
+ ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, sslconn->server);
sslconn->non_ssl_request = 1;
ssl_io_filter_disable(sslconn, f);
@@ -971,11 +972,11 @@ static apr_status_t ssl_filter_io_shutdown(ssl_filter_ctx_t *filter_ctx,
SSL_smart_shutdown(ssl);
/* and finally log the fact that we've closed the connection */
- if (c->base_server->loglevel >= APLOG_INFO) {
+ if (mySrvFromConn(c)->loglevel >= APLOG_INFO) {
ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c,
"Connection closed to child %ld with %s shutdown "
"(server %s)",
- c->id, type, ssl_util_vhostid(c->pool, c->base_server));
+ c->id, type, ssl_util_vhostid(c->pool, mySrvFromConn(c)));
}
/* deallocate the SSL connection */
@@ -1021,26 +1022,68 @@ static int ssl_io_filter_connect(ssl_filter_ctx_t *filter_ctx)
{
conn_rec *c = (conn_rec *)SSL_get_app_data(filter_ctx->pssl);
SSLConnRec *sslconn = myConnConfig(c);
- SSLSrvConfigRec *sc = mySrvConfig(c->base_server);
+ SSLSrvConfigRec *sc;
X509 *cert;
int n;
int ssl_err;
long verify_result;
+ server_rec *server;
if (SSL_is_init_finished(filter_ctx->pssl)) {
return APR_SUCCESS;
}
+ server = sslconn->server;
if (sslconn->is_proxy) {
+ const char *hostname_note;
+
+ sc = mySrvConfig(server);
if ((n = SSL_connect(filter_ctx->pssl)) <= 0) {
ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c,
"SSL Proxy connect failed");
- ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, c->base_server);
+ ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, server);
/* ensure that the SSL structures etc are freed, etc: */
ssl_filter_io_shutdown(filter_ctx, c, 1);
return HTTP_BAD_GATEWAY;
}
+ if (sc->proxy_ssl_check_peer_expire == SSL_ENABLED_TRUE) {
+ cert = SSL_get_peer_certificate(filter_ctx->pssl);
+ if (!cert
+ || (X509_cmp_current_time(
+ X509_get_notBefore(cert)) >= 0)
+ || (X509_cmp_current_time(
+ X509_get_notAfter(cert)) <= 0)) {
+ ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c,
+ "SSL Proxy: Peer certificate is expired");
+ if (cert) {
+ X509_free(cert);
+ }
+ /* ensure that the SSL structures etc are freed, etc: */
+ ssl_filter_io_shutdown(filter_ctx, c, 1);
+ return HTTP_BAD_GATEWAY;
+ }
+ X509_free(cert);
+ }
+ if ((sc->proxy_ssl_check_peer_cn == SSL_ENABLED_TRUE)
+ && ((hostname_note =
+ apr_table_get(c->notes, "proxy-request-hostname")) != NULL)) {
+ const char *hostname;
+
+ hostname = ssl_var_lookup(NULL, server, c, NULL,
+ "SSL_CLIENT_S_DN_CN");
+ apr_table_unset(c->notes, "proxy-request-hostname");
+ if (strcasecmp(hostname, hostname_note)) {
+ ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c,
+ "SSL Proxy: Peer certificate CN mismatch:"
+ " Certificate CN: %s Requested hostname: %s",
+ hostname, hostname_note);
+ /* ensure that the SSL structures etc are freed, etc: */
+ ssl_filter_io_shutdown(filter_ctx, c, 1);
+ return HTTP_BAD_GATEWAY;
+ }
+ }
+
return APR_SUCCESS;
}
@@ -1092,8 +1135,8 @@ static int ssl_io_filter_connect(ssl_filter_ctx_t *filter_ctx)
ap_log_cerror(APLOG_MARK, APLOG_INFO, rc, c,
"SSL library error %d in handshake "
"(server %s)", ssl_err,
- ssl_util_vhostid(c->pool, c->base_server));
- ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, c->base_server);
+ ssl_util_vhostid(c->pool, server));
+ ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, server);
}
if (inctx->rc == APR_SUCCESS) {
@@ -1102,6 +1145,7 @@ static int ssl_io_filter_connect(ssl_filter_ctx_t *filter_ctx)
return ssl_filter_io_shutdown(filter_ctx, c, 1);
}
+ sc = mySrvConfig(sslconn->server);
/*
* Check for failed client authentication
@@ -1127,7 +1171,7 @@ static int ssl_io_filter_connect(ssl_filter_ctx_t *filter_ctx)
"accepting certificate based on "
"\"SSLVerifyClient optional_no_ca\" "
"configuration");
- ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, c->base_server);
+ ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, server);
}
else {
const char *error = sslconn->verify_error ?
@@ -1137,7 +1181,7 @@ static int ssl_io_filter_connect(ssl_filter_ctx_t *filter_ctx)
ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c,
"SSL client authentication failed: %s",
error ? error : "unknown");
- ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, c->base_server);
+ ssl_log_ssl_error(APLOG_MARK, APLOG_INFO, server);
return ssl_filter_io_shutdown(filter_ctx, c, 1);
}
@@ -1447,17 +1491,12 @@ static apr_status_t ssl_io_filter_output(ap_filter_t *f,
return status;
}
-/* 128K maximum buffer size by default. */
-#ifndef SSL_MAX_IO_BUFFER
-#define SSL_MAX_IO_BUFFER (128 * 1024)
-#endif
-
struct modssl_buffer_ctx {
apr_bucket_brigade *bb;
apr_pool_t *pool;
};
-int ssl_io_buffer_fill(request_rec *r)
+int ssl_io_buffer_fill(request_rec *r, apr_size_t maxlen)
{
conn_rec *c = r->connection;
struct modssl_buffer_ctx *ctx;
@@ -1475,7 +1514,8 @@ int ssl_io_buffer_fill(request_rec *r)
/* ... and a temporary brigade. */
tempb = apr_brigade_create(r->pool, c->bucket_alloc);
- ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, "filling buffer");
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, "filling buffer, max size "
+ "%" APR_SIZE_T_FMT " bytes", maxlen);
do {
apr_status_t rv;
@@ -1531,9 +1571,10 @@ int ssl_io_buffer_fill(request_rec *r)
total, eos);
/* Fail if this exceeds the maximum buffer size. */
- if (total > SSL_MAX_IO_BUFFER) {
+ if (total > maxlen) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "request body exceeds maximum size for SSL buffer");
+ "request body exceeds maximum size (%" APR_SIZE_T_FMT
+ ") for SSL buffer", maxlen);
return HTTP_REQUEST_ENTITY_TOO_LARGE;
}
@@ -1809,7 +1850,7 @@ long ssl_io_data_cb(BIO *bio, int cmd,
return rc;
if ((c = (conn_rec *)SSL_get_app_data(ssl)) == NULL)
return rc;
- s = c->base_server;
+ s = mySrvFromConn(c);
if ( cmd == (BIO_CB_WRITE|BIO_CB_RETURN)
|| cmd == (BIO_CB_READ |BIO_CB_RETURN) ) {
diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c
index 0a8e1933..17bf9353 100644
--- a/modules/ssl/ssl_engine_kernel.c
+++ b/modules/ssl/ssl_engine_kernel.c
@@ -31,6 +31,9 @@
#include "ssl_private.h"
static void ssl_configure_env(request_rec *r, SSLConnRec *sslconn);
+#ifndef OPENSSL_NO_TLSEXT
+static int ssl_find_vhost(void *servername, conn_rec *c, server_rec *s);
+#endif
/*
* Post Read Request Handler
@@ -38,6 +41,9 @@ static void ssl_configure_env(request_rec *r, SSLConnRec *sslconn);
int ssl_hook_ReadReq(request_rec *r)
{
SSLConnRec *sslconn = myConnConfig(r->connection);
+#ifndef OPENSSL_NO_TLSEXT
+ const char *servername;
+#endif
SSL *ssl;
if (!sslconn) {
@@ -87,6 +93,51 @@ int ssl_hook_ReadReq(request_rec *r)
if (!ssl) {
return DECLINED;
}
+#ifndef OPENSSL_NO_TLSEXT
+ if ((servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name))) {
+ char *host, *scope_id;
+ apr_port_t port;
+ apr_status_t rv;
+
+ /*
+ * The SNI extension supplied a hostname. So don't accept requests
+ * with either no hostname or a different hostname.
+ */
+ if (!r->hostname) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+ "Hostname %s provided via SNI, but no hostname"
+ " provided in HTTP request", servername);
+ return HTTP_BAD_REQUEST;
+ }
+ rv = apr_parse_addr_port(&host, &scope_id, &port, r->hostname, r->pool);
+ if (rv != APR_SUCCESS || scope_id) {
+ return HTTP_BAD_REQUEST;
+ }
+ if (strcmp(host, servername)) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+ "Hostname %s provided via SNI and hostname %s provided"
+ " via HTTP are different", servername, host);
+ return HTTP_BAD_REQUEST;
+ }
+ }
+ else if ((((mySrvConfig(r->server))->strict_sni_vhost_check
+ == SSL_ENABLED_TRUE)
+ || (mySrvConfig(sslconn->server))->strict_sni_vhost_check
+ == SSL_ENABLED_TRUE)
+ && r->connection->vhost_lookup_data) {
+ /*
+ * We are using a name based configuration here, but no hostname was
+ * provided via SNI. Don't allow that if are requested to do strict
+ * checking. Check wether this strict checking was setup either in the
+ * server config we used for handshaking or in our current server.
+ * This should avoid insecure configuration by accident.
+ */
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
+ "No hostname was provided via SNI for a name based"
+ " virtual host");
+ return HTTP_FORBIDDEN;
+ }
+#endif
SSL_set_app_data2(ssl, r);
/*
@@ -155,10 +206,11 @@ static void ssl_configure_env(request_rec *r, SSLConnRec *sslconn)
*/
int ssl_hook_Access(request_rec *r)
{
- SSLDirConfigRec *dc = myDirConfig(r);
- SSLSrvConfigRec *sc = mySrvConfig(r->server);
- SSLConnRec *sslconn = myConnConfig(r->connection);
- SSL *ssl = sslconn ? sslconn->ssl : NULL;
+ SSLDirConfigRec *dc = myDirConfig(r);
+ SSLSrvConfigRec *sc = mySrvConfig(r->server);
+ SSLConnRec *sslconn = myConnConfig(r->connection);
+ SSL *ssl = sslconn ? sslconn->ssl : NULL;
+ server_rec *handshakeserver = sslconn ? sslconn->server : NULL;
SSL_CTX *ctx = NULL;
apr_array_header_t *requires;
ssl_require_t *ssl_requires;
@@ -252,7 +304,7 @@ int ssl_hook_Access(request_rec *r)
* has to enable this via ``SSLOptions +OptRenegotiate''. So we do no
* implicit optimizations.
*/
- if (dc->szCipherSuite) {
+ if (dc->szCipherSuite || (r->server != handshakeserver)) {
/* remember old state */
if (dc->nOptions & SSL_OPT_OPTRENEGOTIATE) {
@@ -267,11 +319,13 @@ int ssl_hook_Access(request_rec *r)
}
/* configure new state */
- if (!modssl_set_cipher_list(ssl, dc->szCipherSuite)) {
- ap_log_error(APLOG_MARK, APLOG_WARNING, 0,
- r->server,
- "Unable to reconfigure (per-directory) "
- "permitted SSL ciphers");
+ if ((dc->szCipherSuite || sc->server->auth.cipher_suite) &&
+ !modssl_set_cipher_list(ssl, dc->szCipherSuite ?
+ dc->szCipherSuite :
+ sc->server->auth.cipher_suite)) {
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r,
+ "Unable to reconfigure (per-directory) "
+ "permitted SSL ciphers");
ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, r->server);
if (cipher_list_old) {
@@ -334,9 +388,14 @@ int ssl_hook_Access(request_rec *r)
sk_SSL_CIPHER_free(cipher_list_old);
}
- /* tracing */
if (renegotiate) {
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE
+ if (sc->cipher_server_pref == TRUE) {
+ SSL_set_options(ssl, SSL_OP_CIPHER_SERVER_PREFERENCE);
+ }
+#endif
+ /* tracing */
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
"Reconfigured cipher suite will force renegotiation");
}
}
@@ -348,24 +407,22 @@ int ssl_hook_Access(request_rec *r)
* function and not by OpenSSL internally (and our function is aware of
* both the per-server and per-directory contexts). So we cannot ask
* OpenSSL about the currently verify depth. Instead we remember it in our
- * ap_ctx attached to the SSL* of OpenSSL. We've to force the
+ * SSLConnRec attached to the SSL* of OpenSSL. We've to force the
* renegotiation if the reconfigured/new verify depth is less than the
* currently active/remembered verify depth (because this means more
* restriction on the certificate chain).
*/
- if (dc->nVerifyDepth != UNSET) {
- /* XXX: doesnt look like sslconn->verify_depth is actually used */
- if (!(n = sslconn->verify_depth)) {
- sslconn->verify_depth = n = sc->server->auth.verify_depth;
- }
-
- /* determine whether a renegotiation has to be forced */
- if (dc->nVerifyDepth < n) {
- renegotiate = TRUE;
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
- "Reduced client verification depth will force "
- "renegotiation");
- }
+ n = sslconn->verify_depth ?
+ sslconn->verify_depth :
+ (mySrvConfig(handshakeserver))->server->auth.verify_depth;
+ /* determine the new depth */
+ sslconn->verify_depth = (dc->nVerifyDepth != UNSET) ?
+ dc->nVerifyDepth : sc->server->auth.verify_depth;
+ if (sslconn->verify_depth < n) {
+ renegotiate = TRUE;
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+ "Reduced client verification depth will force "
+ "renegotiation");
}
/*
@@ -382,18 +439,22 @@ int ssl_hook_Access(request_rec *r)
* verification but at least skip the I/O-intensive renegotation
* handshake.
*/
- if (dc->nVerifyClient != SSL_CVERIFY_UNSET) {
+ if ((dc->nVerifyClient != SSL_CVERIFY_UNSET) ||
+ (sc->server->auth.verify_mode != SSL_CVERIFY_UNSET)) {
/* remember old state */
verify_old = SSL_get_verify_mode(ssl);
/* configure new state */
verify = SSL_VERIFY_NONE;
- if (dc->nVerifyClient == SSL_CVERIFY_REQUIRE) {
+ if ((dc->nVerifyClient == SSL_CVERIFY_REQUIRE) ||
+ (sc->server->auth.verify_mode == SSL_CVERIFY_REQUIRE)) {
verify |= SSL_VERIFY_PEER_STRICT;
}
if ((dc->nVerifyClient == SSL_CVERIFY_OPTIONAL) ||
- (dc->nVerifyClient == SSL_CVERIFY_OPTIONAL_NO_CA))
+ (dc->nVerifyClient == SSL_CVERIFY_OPTIONAL_NO_CA) ||
+ (sc->server->auth.verify_mode == SSL_CVERIFY_OPTIONAL) ||
+ (sc->server->auth.verify_mode == SSL_CVERIFY_OPTIONAL_NO_CA))
{
verify |= SSL_VERIFY_PEER;
}
@@ -423,13 +484,51 @@ int ssl_hook_Access(request_rec *r)
X509_free(peercert);
}
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0,
- r->server,
- "Changed client verification type will force "
- "%srenegotiation",
- renegotiate_quick ? "quick " : "");
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+ "Changed client verification type will force "
+ "%srenegotiation",
+ renegotiate_quick ? "quick " : "");
}
}
+ /* If we're handling a request for a vhost other than the default one,
+ * then we need to make sure that client authentication is properly
+ * enforced. For clients supplying an SNI extension, the peer
+ * certificate verification has happened in the handshake already
+ * (and r->server == handshakeserver). For non-SNI requests,
+ * an additional check is needed here. If client authentication
+ * is configured as mandatory, then we can only proceed if the
+ * CA list doesn't have to be changed (OpenSSL doesn't provide
+ * an option to change the list for an existing session).
+ */
+ if ((r->server != handshakeserver)
+ && renegotiate
+ && ((verify & SSL_VERIFY_PEER) ||
+ (verify & SSL_VERIFY_FAIL_IF_NO_PEER_CERT))) {
+ SSLSrvConfigRec *hssc = mySrvConfig(handshakeserver);
+
+#define MODSSL_CFG_CA_NE(f, sc1, sc2) \
+ (sc1->server->auth.f && \
+ (!sc2->server->auth.f || \
+ strNE(sc1->server->auth.f, sc2->server->auth.f)))
+
+ if (MODSSL_CFG_CA_NE(ca_cert_file, sc, hssc) ||
+ MODSSL_CFG_CA_NE(ca_cert_path, sc, hssc)) {
+ if (verify & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) {
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
+ "Non-default virtual host with SSLVerify set to "
+ "'require' and VirtualHost-specific CA certificate "
+ "list is only available to clients with TLS server "
+ "name indication (SNI) support");
+ modssl_set_verify(ssl, verify_old, NULL);
+ return HTTP_FORBIDDEN;
+ } else
+ /* let it pass, possibly with an "incorrect" peer cert,
+ * so make sure the SSL_CLIENT_VERIFY environment variable
+ * will indicate partial success only, later on.
+ */
+ sslconn->verify_info = "GENEROUS";
+ }
+ }
}
/*
@@ -461,9 +560,9 @@ int ssl_hook_Access(request_rec *r)
cert_store = X509_STORE_new();
if (!X509_STORE_load_locations(cert_store, ca_file, ca_path)) {
- ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
- "Unable to reconfigure verify locations "
- "for client authentication");
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "Unable to reconfigure verify locations "
+ "for client authentication");
ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, r->server);
X509_STORE_free(cert_store);
@@ -487,9 +586,9 @@ int ssl_hook_Access(request_rec *r)
SSL_set_client_CA_list(ssl, ca_list);
renegotiate = TRUE;
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
- "Changed client verification locations will force "
- "renegotiation");
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+ "Changed client verification locations will force "
+ "renegotiation");
}
#endif /* HAVE_SSL_SET_CERT_STORE */
@@ -512,9 +611,18 @@ int ssl_hook_Access(request_rec *r)
&& strcmp(apr_table_get(r->headers_in, "content-length"), "0")))
&& !r->expecting_100) {
int rv;
+ apr_size_t rsize;
- /* Fill the I/O buffer with the request body if possible. */
- rv = ssl_io_buffer_fill(r);
+ rsize = dc->nRenegBufferSize == UNSET ? DEFAULT_RENEG_BUFFER_SIZE :
+ dc->nRenegBufferSize;
+ if (rsize > 0) {
+ /* Fill the I/O buffer with the request body if possible. */
+ rv = ssl_io_buffer_fill(r, rsize);
+ }
+ else {
+ /* If the reneg buffer size is set to zero, just fail. */
+ rv = HTTP_REQUEST_ENTITY_TOO_LARGE;
+ }
if (rv) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
@@ -539,14 +647,14 @@ int ssl_hook_Access(request_rec *r)
* here because it resets too much of the connection. So we set the
* state explicitly and continue the handshake manually.
*/
- ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server,
- "Requesting connection re-negotiation");
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
+ "Requesting connection re-negotiation");
if (renegotiate_quick) {
STACK_OF(X509) *cert_stack;
/* perform just a manual re-verification of the peer */
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
"Performing quick renegotiation: "
"just re-verifying the peer");
@@ -565,8 +673,8 @@ int ssl_hook_Access(request_rec *r)
}
if (!cert_stack || (sk_X509_num(cert_stack) == 0)) {
- ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
- "Cannot find peer certificate chain");
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "Cannot find peer certificate chain");
return HTTP_FORBIDDEN;
}
@@ -574,8 +682,8 @@ int ssl_hook_Access(request_rec *r)
if (!(cert_store ||
(cert_store = SSL_CTX_get_cert_store(ctx))))
{
- ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
- "Cannot find certificate storage");
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "Cannot find certificate storage");
return HTTP_FORBIDDEN;
}
@@ -596,8 +704,8 @@ int ssl_hook_Access(request_rec *r)
(char *)ssl);
if (!modssl_X509_verify_cert(&cert_store_ctx)) {
- ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
- "Re-negotiation verification step failed");
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "Re-negotiation verification step failed");
ssl_log_ssl_error(APLOG_MARK, APLOG_ERR, r->server);
}
@@ -613,9 +721,9 @@ int ssl_hook_Access(request_rec *r)
request_rec *id = r->main ? r->main : r;
/* do a full renegotiation */
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
- "Performing full renegotiation: "
- "complete handshake protocol");
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+ "Performing full renegotiation: "
+ "complete handshake protocol");
SSL_set_session_id_context(ssl,
(unsigned char *)&id,
@@ -625,15 +733,15 @@ int ssl_hook_Access(request_rec *r)
SSL_do_handshake(ssl);
if (SSL_get_state(ssl) != SSL_ST_OK) {
- ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
- "Re-negotiation request failed");
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "Re-negotiation request failed");
r->connection->aborted = 1;
return HTTP_FORBIDDEN;
}
- ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server,
- "Awaiting re-negotiation handshake");
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
+ "Awaiting re-negotiation handshake");
/* XXX: Should replace SSL_set_state with SSL_renegotiate(ssl);
* However, this causes failures in perl-framework currently,
@@ -643,9 +751,9 @@ int ssl_hook_Access(request_rec *r)
SSL_do_handshake(ssl);
if (SSL_get_state(ssl) != SSL_ST_OK) {
- ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
- "Re-negotiation handshake failed: "
- "Not accepted by client!?");
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "Re-negotiation handshake failed: "
+ "Not accepted by client!?");
r->connection->aborted = 1;
return HTTP_FORBIDDEN;
@@ -666,22 +774,24 @@ int ssl_hook_Access(request_rec *r)
/*
* Finally check for acceptable renegotiation results
*/
- if (dc->nVerifyClient != SSL_CVERIFY_NONE) {
- BOOL do_verify = (dc->nVerifyClient == SSL_CVERIFY_REQUIRE);
+ if ((dc->nVerifyClient != SSL_CVERIFY_NONE) ||
+ (sc->server->auth.verify_mode != SSL_CVERIFY_NONE)) {
+ BOOL do_verify = ((dc->nVerifyClient == SSL_CVERIFY_REQUIRE) ||
+ (sc->server->auth.verify_mode == SSL_CVERIFY_REQUIRE));
if (do_verify && (SSL_get_verify_result(ssl) != X509_V_OK)) {
- ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
- "Re-negotiation handshake failed: "
- "Client verification failed");
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "Re-negotiation handshake failed: "
+ "Client verification failed");
return HTTP_FORBIDDEN;
}
if (do_verify) {
if ((peercert = SSL_get_peer_certificate(ssl)) == NULL) {
- ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
- "Re-negotiation handshake failed: "
- "Client certificate missing");
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "Re-negotiation handshake failed: "
+ "Client certificate missing");
return HTTP_FORBIDDEN;
}
@@ -747,13 +857,13 @@ int ssl_hook_Access(request_rec *r)
}
if (ok != 1) {
- ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server,
- "Access to %s denied for %s "
- "(requirement expression not fulfilled)",
- r->filename, r->connection->remote_ip);
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
+ "Access to %s denied for %s "
+ "(requirement expression not fulfilled)",
+ r->filename, r->connection->remote_ip);
- ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server,
- "Failed expression: %s", req->cpExpr);
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
+ "Failed expression: %s", req->cpExpr);
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"access to %s failed, reason: %s",
@@ -878,9 +988,9 @@ int ssl_hook_UserCheck(request_rec *r)
NULL);
apr_table_set(r->headers_in, "Authorization", auth_line);
- ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server,
- "Faking HTTP Basic Auth header: \"Authorization: %s\"",
- auth_line);
+ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r,
+ "Faking HTTP Basic Auth header: \"Authorization: %s\"",
+ auth_line);
return DECLINED;
}
@@ -997,6 +1107,9 @@ int ssl_hook_Fixup(request_rec *r)
SSLDirConfigRec *dc = myDirConfig(r);
apr_table_t *env = r->subprocess_env;
char *var, *val = "";
+#ifndef OPENSSL_NO_TLSEXT
+ const char *servername;
+#endif
STACK_OF(X509) *peer_certs;
SSL *ssl;
int i;
@@ -1018,6 +1131,13 @@ int ssl_hook_Fixup(request_rec *r)
/* the always present HTTPS (=HTTP over SSL) flag! */
apr_table_setn(env, "HTTPS", "on");
+#ifndef OPENSSL_NO_TLSEXT
+ /* add content of SNI TLS extension (if supplied with ClientHello) */
+ if ((servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name))) {
+ apr_table_set(env, "SSL_TLS_SNI", servername);
+ }
+#endif
+
/* standard SSL environment variables */
if (dc->nOptions & SSL_OPT_STDENVVARS) {
for (i = 0; ssl_hook_Fixup_vars[i]; i++) {
@@ -1105,7 +1225,7 @@ int ssl_hook_Fixup(request_rec *r)
RSA *ssl_callback_TmpRSA(SSL *ssl, int export, int keylen)
{
conn_rec *c = (conn_rec *)SSL_get_app_data(ssl);
- SSLModConfigRec *mc = myModConfig(c->base_server);
+ SSLModConfigRec *mc = myModConfigFromConn(c);
int idx;
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
@@ -1137,7 +1257,7 @@ RSA *ssl_callback_TmpRSA(SSL *ssl, int export, int keylen)
DH *ssl_callback_TmpDH(SSL *ssl, int export, int keylen)
{
conn_rec *c = (conn_rec *)SSL_get_app_data(ssl);
- SSLModConfigRec *mc = myModConfig(c->base_server);
+ SSLModConfigRec *mc = myModConfigFromConn(c);
int idx;
ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
@@ -1166,8 +1286,8 @@ int ssl_callback_SSLVerify(int ok, X509_STORE_CTX *ctx)
SSL *ssl = X509_STORE_CTX_get_ex_data(ctx,
SSL_get_ex_data_X509_STORE_CTX_idx());
conn_rec *conn = (conn_rec *)SSL_get_app_data(ssl);
- server_rec *s = conn->base_server;
request_rec *r = (request_rec *)SSL_get_app_data2(ssl);
+ server_rec *s = r ? r->server : mySrvFromConn(conn);
SSLSrvConfigRec *sc = mySrvConfig(s);
SSLDirConfigRec *dc = r ? myDirConfig(r) : NULL;
@@ -1187,12 +1307,12 @@ int ssl_callback_SSLVerify(int ok, X509_STORE_CTX *ctx)
char *sname = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
char *iname = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0);
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
- "Certificate Verification: "
- "depth: %d, subject: %s, issuer: %s",
- errdepth,
- sname ? sname : "-unknown-",
- iname ? iname : "-unknown-");
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, conn,
+ "Certificate Verification: "
+ "depth: %d, subject: %s, issuer: %s",
+ errdepth,
+ sname ? sname : "-unknown-",
+ iname ? iname : "-unknown-");
if (sname) {
modssl_free(sname);
@@ -1225,10 +1345,10 @@ int ssl_callback_SSLVerify(int ok, X509_STORE_CTX *ctx)
if (ssl_verify_error_is_optional(errnum) &&
(verify == SSL_CVERIFY_OPTIONAL_NO_CA))
{
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s,
- "Certificate Verification: Verifiable Issuer is "
- "configured as optional, therefore we're accepting "
- "the certificate");
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, conn,
+ "Certificate Verification: Verifiable Issuer is "
+ "configured as optional, therefore we're accepting "
+ "the certificate");
sslconn->verify_info = "GENEROUS";
ok = TRUE;
@@ -1247,9 +1367,9 @@ int ssl_callback_SSLVerify(int ok, X509_STORE_CTX *ctx)
* If we already know it's not ok, log the real reason
*/
if (!ok) {
- ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
- "Certificate Verification: Error (%d): %s",
- errnum, X509_verify_cert_error_string(errnum));
+ ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, conn,
+ "Certificate Verification: Error (%d): %s",
+ errnum, X509_verify_cert_error_string(errnum));
if (sslconn->client_cert) {
X509_free(sslconn->client_cert);
@@ -1270,11 +1390,11 @@ int ssl_callback_SSLVerify(int ok, X509_STORE_CTX *ctx)
}
if (errdepth > depth) {
- ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
- "Certificate Verification: Certificate Chain too long "
- "(chain has %d certificates, but maximum allowed are "
- "only %d)",
- errdepth, depth);
+ ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, conn,
+ "Certificate Verification: Certificate Chain too long "
+ "(chain has %d certificates, but maximum allowed are "
+ "only %d)",
+ errdepth, depth);
errnum = X509_V_ERR_CERT_CHAIN_TOO_LONG;
sslconn->verify_error = X509_verify_cert_error_string(errnum);
@@ -1290,7 +1410,10 @@ int ssl_callback_SSLVerify(int ok, X509_STORE_CTX *ctx)
int ssl_callback_SSLVerify_CRL(int ok, X509_STORE_CTX *ctx, conn_rec *c)
{
- server_rec *s = c->base_server;
+ SSL *ssl = X509_STORE_CTX_get_ex_data(ctx,
+ SSL_get_ex_data_X509_STORE_CTX_idx());
+ request_rec *r = (request_rec *)SSL_get_app_data2(ssl);
+ server_rec *s = r ? r->server : mySrvFromConn(c);
SSLSrvConfigRec *sc = mySrvConfig(s);
SSLConnRec *sslconn = myConnConfig(c);
modssl_ctx_t *mctx = myCtxConfig(sslconn, sc);
@@ -1515,7 +1638,7 @@ static void modssl_proxy_info_log(server_rec *s,
int ssl_callback_proxy_cert(SSL *ssl, MODSSL_CLIENT_CERT_CB_ARG_TYPE **x509, EVP_PKEY **pkey)
{
conn_rec *c = (conn_rec *)SSL_get_app_data(ssl);
- server_rec *s = c->base_server;
+ server_rec *s = mySrvFromConn(c);
SSLSrvConfigRec *sc = mySrvConfig(s);
X509_NAME *ca_name, *issuer;
X509_INFO *info;
@@ -1613,7 +1736,7 @@ int ssl_callback_NewSessionCacheEntry(SSL *ssl, SSL_SESSION *session)
{
/* Get Apache context back through OpenSSL context */
conn_rec *conn = (conn_rec *)SSL_get_app_data(ssl);
- server_rec *s = conn->base_server;
+ server_rec *s = mySrvFromConn(conn);
SSLSrvConfigRec *sc = mySrvConfig(s);
long timeout = sc->session_cache_timeout;
BOOL rc;
@@ -1661,7 +1784,7 @@ SSL_SESSION *ssl_callback_GetSessionCacheEntry(SSL *ssl,
{
/* Get Apache context back through OpenSSL context */
conn_rec *conn = (conn_rec *)SSL_get_app_data(ssl);
- server_rec *s = conn->base_server;
+ server_rec *s = mySrvFromConn(conn);
SSL_SESSION *session;
/*
@@ -1739,7 +1862,7 @@ void ssl_callback_LogTracingState(MODSSL_INFO_CB_ARG_TYPE ssl, int where, int rc
return;
}
- s = c->base_server;
+ s = mySrvFromConn(c);
if (!(sc = mySrvConfig(s))) {
return;
}
@@ -1810,3 +1933,138 @@ void ssl_callback_LogTracingState(MODSSL_INFO_CB_ARG_TYPE ssl, int where, int rc
}
}
+#ifndef OPENSSL_NO_TLSEXT
+/*
+ * This callback function is executed when OpenSSL encounters an extended
+ * client hello with a server name indication extension ("SNI", cf. RFC 4366).
+ */
+int ssl_callback_ServerNameIndication(SSL *ssl, int *al, modssl_ctx_t *mctx)
+{
+ const char *servername =
+ SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
+
+ if (servername) {
+ conn_rec *c = (conn_rec *)SSL_get_app_data(ssl);
+ if (c) {
+ if (ap_vhost_iterate_given_conn(c, ssl_find_vhost,
+ (void *)servername)) {
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
+ "SSL virtual host for servername %s found",
+ servername);
+ return SSL_TLSEXT_ERR_OK;
+ }
+ else {
+ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c,
+ "No matching SSL virtual host for servername "
+ "%s found (using default/first virtual host)",
+ servername);
+ return SSL_TLSEXT_ERR_ALERT_WARNING;
+ }
+ }
+ }
+
+ return SSL_TLSEXT_ERR_NOACK;
+}
+
+/*
+ * Find a (name-based) SSL virtual host where either the ServerName
+ * or one of the ServerAliases matches the supplied name (to be used
+ * with ap_vhost_iterate_given_conn())
+ */
+static int ssl_find_vhost(void *servername, conn_rec *c, server_rec *s)
+{
+ SSLSrvConfigRec *sc;
+ SSL *ssl;
+ BOOL found = FALSE;
+ apr_array_header_t *names;
+ int i;
+ SSLConnRec *sslcon;
+
+ /* check ServerName */
+ if (!strcasecmp(servername, s->server_hostname)) {
+ found = TRUE;
+ }
+
+ /*
+ * if not matched yet, check ServerAlias entries
+ * (adapted from vhost.c:matches_aliases())
+ */
+ if (!found) {
+ names = s->names;
+ if (names) {
+ char **name = (char **)names->elts;
+ for (i = 0; i < names->nelts; ++i) {
+ if (!name[i])
+ continue;
+ if (!strcasecmp(servername, name[i])) {
+ found = TRUE;
+ break;
+ }
+ }
+ }
+ }
+
+ /* if still no match, check ServerAlias entries with wildcards */
+ if (!found) {
+ names = s->wild_names;
+ if (names) {
+ char **name = (char **)names->elts;
+ for (i = 0; i < names->nelts; ++i) {
+ if (!name[i])
+ continue;
+ if (!ap_strcasecmp_match(servername, name[i])) {
+ found = TRUE;
+ break;
+ }
+ }
+ }
+ }
+
+ /* set SSL_CTX (if matched) */
+ sslcon = myConnConfig(c);
+ if (found && (ssl = sslcon->ssl) &&
+ (sc = mySrvConfig(s))) {
+ SSL_set_SSL_CTX(ssl, sc->server->ssl_ctx);
+ /*
+ * SSL_set_SSL_CTX() only deals with the server cert,
+ * so we need to duplicate a few additional settings
+ * from the ctx by hand
+ */
+ SSL_set_options(ssl, SSL_CTX_get_options(ssl->ctx));
+ if ((SSL_get_verify_mode(ssl) == SSL_VERIFY_NONE) ||
+ (SSL_num_renegotiations(ssl) == 0)) {
+ /*
+ * Only initialize the verification settings from the ctx
+ * if they are not yet set, or if we're called when a new
+ * SSL connection is set up (num_renegotiations == 0).
+ * Otherwise, we would possibly reset a per-directory
+ * configuration which was put into effect by ssl_hook_Access.
+ */
+ SSL_set_verify(ssl, SSL_CTX_get_verify_mode(ssl->ctx),
+ SSL_CTX_get_verify_callback(ssl->ctx));
+ }
+
+ /*
+ * Save the found server into our SSLConnRec for later
+ * retrieval
+ */
+ sslcon->server = s;
+
+ /*
+ * There is one special filter callback, which is set
+ * very early depending on the base_server's log level.
+ * If this is not the first vhost we're now selecting
+ * (and the first vhost doesn't use APLOG_DEBUG), then
+ * we need to set that callback here.
+ */
+ if (s->loglevel >= APLOG_DEBUG) {
+ BIO_set_callback(SSL_get_rbio(ssl), ssl_io_data_cb);
+ BIO_set_callback_arg(SSL_get_rbio(ssl), (void *)ssl);
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+#endif
diff --git a/modules/ssl/ssl_engine_vars.c b/modules/ssl/ssl_engine_vars.c
index 97d8d9a7..4bbe375b 100644
--- a/modules/ssl/ssl_engine_vars.c
+++ b/modules/ssl/ssl_engine_vars.c
@@ -320,6 +320,12 @@ static char *ssl_var_lookup_ssl(apr_pool_t *p, conn_rec *c, char *var)
else if (ssl != NULL && strcEQ(var, "COMPRESS_METHOD")) {
result = ssl_var_lookup_ssl_compress_meth(ssl);
}
+#ifndef OPENSSL_NO_TLSEXT
+ else if (ssl != NULL && strcEQ(var, "TLS_SNI")) {
+ result = apr_pstrdup(p, SSL_get_servername(ssl,
+ TLSEXT_NAMETYPE_host_name));
+ }
+#endif
return result;
}
@@ -589,7 +595,7 @@ static char *ssl_var_lookup_ssl_cert_verify(apr_pool_t *p, conn_rec *c)
vrc = SSL_get_verify_result(ssl);
xs = SSL_get_peer_certificate(ssl);
- if (vrc == X509_V_OK && verr == NULL && vinfo == NULL && xs == NULL)
+ if (vrc == X509_V_OK && verr == NULL && xs == NULL)
/* no client verification done at all */
result = "NONE";
else if (vrc == X509_V_OK && verr == NULL && vinfo == NULL && xs != NULL)
diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h
index 64ad36be..818ed983 100644
--- a/modules/ssl/ssl_private.h
+++ b/modules/ssl/ssl_private.h
@@ -35,6 +35,7 @@
#include "http_connection.h"
#include "http_request.h"
#include "http_protocol.h"
+#include "http_vhost.h"
#include "util_script.h"
#include "util_filter.h"
#include "util_ebcdic.h"
@@ -129,6 +130,9 @@ ap_set_module_config(c->conn_config, &ssl_module, val)
#define mySrvConfig(srv) (SSLSrvConfigRec *)ap_get_module_config(srv->module_config, &ssl_module)
#define myDirConfig(req) (SSLDirConfigRec *)ap_get_module_config(req->per_dir_config, &ssl_module)
#define myModConfig(srv) (mySrvConfig((srv)))->mc
+#define mySrvFromConn(c) (myConnConfig(c))->server
+#define mySrvConfigFromConn(c) mySrvConfig(mySrvFromConn(c))
+#define myModConfigFromConn(c) myModConfig(mySrvFromConn(c))
#define myCtxVarSet(mc,num,val) mc->rCtx.pV##num = val
#define myCtxVarGet(mc,num,type) (type)(mc->rCtx.pV##num)
@@ -140,6 +144,11 @@ ap_set_module_config(c->conn_config, &ssl_module, val)
#define SSL_SESSION_CACHE_TIMEOUT 300
#endif
+/* Default setting for per-dir reneg buffer. */
+#ifndef DEFAULT_RENEG_BUFFER_SIZE
+#define DEFAULT_RENEG_BUFFER_SIZE (128 * 1024)
+#endif
+
/**
* Support for MM library
*/
@@ -347,6 +356,7 @@ typedef struct {
int is_proxy;
int disabled;
int non_ssl_request;
+ server_rec *server;
} SSLConnRec;
typedef struct {
@@ -449,6 +459,11 @@ struct SSLSrvConfigRec {
BOOL cipher_server_pref;
modssl_ctx_t *server;
modssl_ctx_t *proxy;
+ ssl_enabled_t proxy_ssl_check_peer_expire;
+ ssl_enabled_t proxy_ssl_check_peer_cn;
+#ifndef OPENSSL_NO_TLSEXT
+ ssl_enabled_t strict_sni_vhost_check;
+#endif
};
/**
@@ -468,6 +483,7 @@ typedef struct {
const char *szCACertificatePath;
const char *szCACertificateFile;
const char *szUserName;
+ apr_size_t nRenegBufferSize;
} SSLDirConfigRec;
/**
@@ -513,6 +529,8 @@ const char *ssl_cmd_SSLOptions(cmd_parms *, void *, const char *);
const char *ssl_cmd_SSLRequireSSL(cmd_parms *, void *);
const char *ssl_cmd_SSLRequire(cmd_parms *, void *, const char *);
const char *ssl_cmd_SSLUserName(cmd_parms *, void *, const char *);
+const char *ssl_cmd_SSLRenegBufferSize(cmd_parms *cmd, void *dcfg, const char *arg);
+const char *ssl_cmd_SSLStrictSNIVHostCheck(cmd_parms *cmd, void *dcfg, int flag);
const char *ssl_cmd_SSLProxyEngine(cmd_parms *cmd, void *dcfg, int flag);
const char *ssl_cmd_SSLProxyProtocol(cmd_parms *, void *, const char *);
@@ -525,6 +543,8 @@ const char *ssl_cmd_SSLProxyCARevocationPath(cmd_parms *, void *, const char *)
const char *ssl_cmd_SSLProxyCARevocationFile(cmd_parms *, void *, const char *);
const char *ssl_cmd_SSLProxyMachineCertificatePath(cmd_parms *, void *, const char *);
const char *ssl_cmd_SSLProxyMachineCertificateFile(cmd_parms *, void *, const char *);
+const char *ssl_cmd_SSLProxyCheckPeerExpire(cmd_parms *cmd, void *dcfg, int flag);
+const char *ssl_cmd_SSLProxyCheckPeerCN(cmd_parms *cmd, void *dcfg, int flag);
/** module initialization */
int ssl_init_Module(apr_pool_t *, apr_pool_t *, apr_pool_t *, server_rec *);
@@ -555,6 +575,9 @@ int ssl_callback_NewSessionCacheEntry(SSL *, SSL_SESSION *);
SSL_SESSION *ssl_callback_GetSessionCacheEntry(SSL *, unsigned char *, int, int *);
void ssl_callback_DelSessionCacheEntry(SSL_CTX *, SSL_SESSION *);
void ssl_callback_LogTracingState(MODSSL_INFO_CB_ARG_TYPE, int, int);
+#ifndef OPENSSL_NO_TLSEXT
+int ssl_callback_ServerNameIndication(SSL *, int *, modssl_ctx_t *);
+#endif
/** Session Cache Support */
void ssl_scache_init(server_rec *, apr_pool_t *);
@@ -597,7 +620,7 @@ long ssl_io_data_cb(BIO *, int, MODSSL_BIO_CB_ARG_TYPE *, int, long, lon
/* ssl_io_buffer_fill fills the setaside buffering of the HTTP request
* to allow an SSL renegotiation to take place. */
-int ssl_io_buffer_fill(request_rec *r);
+int ssl_io_buffer_fill(request_rec *r, apr_size_t maxlen);
/* PRNG */
int ssl_rand_seed(server_rec *, apr_pool_t *, ssl_rsctx_t, char *);
diff --git a/modules/ssl/ssl_toolkit_compat.h b/modules/ssl/ssl_toolkit_compat.h
index 430127c1..06a22669 100644
--- a/modules/ssl/ssl_toolkit_compat.h
+++ b/modules/ssl/ssl_toolkit_compat.h
@@ -264,6 +264,12 @@ typedef void (*modssl_popfree_fn)(char *data);
#define SSL_SESS_CACHE_NO_INTERNAL SSL_SESS_CACHE_NO_INTERNAL_LOOKUP
#endif
+#ifndef OPENSSL_NO_TLSEXT
+#ifndef SSL_CTRL_SET_TLSEXT_HOSTNAME
+#define OPENSSL_NO_TLSEXT
+#endif
+#endif
+
#endif /* SSL_TOOLKIT_COMPAT_H */
/** @} */