diff options
| author | Stefan Fritsch <sf@sfritsch.de> | 2011-12-27 19:42:33 +0100 |
|---|---|---|
| committer | Stefan Fritsch <sf@sfritsch.de> | 2011-12-27 19:42:33 +0100 |
| commit | ad14e19ad0400e289b06fb7728aea815e6ed49be (patch) | |
| tree | bd29489cafb04b303940169ae7b00c1171a5a34c /modules | |
| parent | 02a0e3b89d2ea1b984365e692c910668d75c6dcd (diff) | |
| download | apache2-ad14e19ad0400e289b06fb7728aea815e6ed49be.tar.gz | |
Upstream tarball 2.2.12upstream/2.2.12
Diffstat (limited to 'modules')
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 */ /** @} */ |
