diff options
Diffstat (limited to 'modules')
61 files changed, 1386 insertions, 1317 deletions
diff --git a/modules/aaa/mod_auth_basic.c b/modules/aaa/mod_auth_basic.c index 8c1367b3..75044d48 100644 --- a/modules/aaa/mod_auth_basic.c +++ b/modules/aaa/mod_auth_basic.c @@ -27,6 +27,7 @@ #include "http_log.h" #include "http_protocol.h" #include "http_request.h" +#include "util_md5.h" #include "ap_provider.h" #include "ap_expr.h" @@ -38,7 +39,9 @@ typedef struct { int authoritative; ap_expr_info_t *fakeuser; ap_expr_info_t *fakepass; + const char *use_digest_algorithm; int fake_set:1; + int use_digest_algorithm_set:1; int authoritative_set:1; } auth_basic_config_rec; @@ -70,6 +73,12 @@ static void *merge_auth_basic_dir_config(apr_pool_t *p, void *basev, void *overr overrides->fake_set ? overrides->fakepass : base->fakepass; newconf->fake_set = overrides->fake_set || base->fake_set; + newconf->use_digest_algorithm = + overrides->use_digest_algorithm_set ? overrides->use_digest_algorithm + : base->use_digest_algorithm; + newconf->use_digest_algorithm_set = + overrides->use_digest_algorithm_set || base->use_digest_algorithm_set; + newconf->providers = overrides->providers ? overrides->providers : base->providers; return newconf; @@ -175,6 +184,23 @@ static const char *add_basic_fake(cmd_parms * cmd, void *config, return NULL; } +static const char *set_use_digest_algorithm(cmd_parms *cmd, void *config, + const char *alg) +{ + auth_basic_config_rec *conf = (auth_basic_config_rec *)config; + + if (strcasecmp(alg, "Off") && strcasecmp(alg, "MD5")) { + return apr_pstrcat(cmd->pool, + "Invalid algorithm in " + "AuthBasicUseDigestAlgorithm: ", alg, NULL); + } + + conf->use_digest_algorithm = apr_pstrdup(cmd->pool, alg); + conf->use_digest_algorithm_set = 1; + + return NULL; +} + static const command_rec auth_basic_cmds[] = { AP_INIT_ITERATE("AuthBasicProvider", add_authn_provider, NULL, OR_AUTHCFG, @@ -186,6 +212,10 @@ static const command_rec auth_basic_cmds[] = "Fake basic authentication using the given expressions for " "username and password, 'off' to disable. Password defaults " "to 'password' if missing."), + AP_INIT_TAKE1("AuthBasicUseDigestAlgorithm", set_use_digest_algorithm, + NULL, OR_AUTHCFG, + "Set to 'MD5' to use the auth provider's authentication " + "check for digest auth, using a hash of 'user:realm:pass'"), {NULL} }; @@ -271,6 +301,8 @@ static int authenticate_basic_user(request_rec *r) auth_basic_config_rec *conf = ap_get_module_config(r->per_dir_config, &auth_basic_module); const char *sent_user, *sent_pw, *current_auth; + const char *realm = NULL; + const char *digest = NULL; int res; authn_status auth_result; authn_provider_list *current_provider; @@ -295,6 +327,15 @@ static int authenticate_basic_user(request_rec *r) return res; } + if (conf->use_digest_algorithm + && !strcasecmp(conf->use_digest_algorithm, "MD5")) { + realm = ap_auth_name(r); + digest = ap_md5(r->pool, + (unsigned char *)apr_pstrcat(r->pool, sent_user, ":", + realm, ":", + sent_pw, NULL)); + } + current_provider = conf->providers; do { const authn_provider *provider; @@ -320,8 +361,27 @@ static int authenticate_basic_user(request_rec *r) apr_table_setn(r->notes, AUTHN_PROVIDER_NAME_NOTE, current_provider->provider_name); } + if (digest) { + char *password; - auth_result = provider->check_password(r, sent_user, sent_pw); + if (!provider->get_realm_hash) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02493) + "Authn provider does not support " + "AuthBasicUseDigestAlgorithm"); + auth_result = AUTH_GENERAL_ERROR; + break; + } + /* We expect the password to be hash of user:realm:password */ + auth_result = provider->get_realm_hash(r, sent_user, realm, + &password); + if (auth_result == AUTH_USER_FOUND) { + auth_result = strcmp(digest, password) ? AUTH_DENIED + : AUTH_GRANTED; + } + } + else { + auth_result = provider->check_password(r, sent_user, sent_pw); + } apr_table_unset(r->notes, AUTHN_PROVIDER_NAME_NOTE); diff --git a/modules/aaa/mod_auth_digest.c b/modules/aaa/mod_auth_digest.c index 987e5b5b..dcf1e15b 100644 --- a/modules/aaa/mod_auth_digest.c +++ b/modules/aaa/mod_auth_digest.c @@ -1811,7 +1811,15 @@ static int authenticate_digest_user(request_rec *r) return HTTP_UNAUTHORIZED; } - if (strcmp(resp->realm, conf->realm)) { + if (!conf->realm) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02533) + "realm mismatch - got `%s' but no realm specified", + resp->realm); + note_digest_auth_failure(r, conf, resp, 0); + return HTTP_UNAUTHORIZED; + } + + if (!resp->realm || strcmp(resp->realm, conf->realm)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01788) "realm mismatch - got `%s' but expected `%s'", resp->realm, conf->realm); diff --git a/modules/aaa/mod_authn_socache.c b/modules/aaa/mod_authn_socache.c index cccd076b..f36d49c8 100644 --- a/modules/aaa/mod_authn_socache.c +++ b/modules/aaa/mod_authn_socache.c @@ -40,7 +40,7 @@ typedef struct authn_cache_dircfg { const char *context; } authn_cache_dircfg; -/* FIXME: figure out usage of socache create vs init +/* FIXME: * I think the cache and mutex should be global */ static apr_global_mutex_t *authn_cache_mutex = NULL; @@ -86,7 +86,6 @@ static int authn_cache_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptmp, server_rec *s) { apr_status_t rv; - const char *errmsg; static struct ap_socache_hints authn_cache_hints = {64, 32, 60000000}; if (!configured) { @@ -109,12 +108,6 @@ static int authn_cache_post_config(apr_pool_t *pconf, apr_pool_t *plog, } apr_pool_cleanup_register(pconf, NULL, remove_lock, apr_pool_cleanup_null); - errmsg = socache_provider->create(&socache_instance, NULL, ptmp, pconf); - if (errmsg) { - ap_log_perror(APLOG_MARK, APLOG_CRIT, rv, plog, APLOGNO(01676) "%s", errmsg); - return 500; /* An HTTP status would be a misnomer! */ - } - rv = socache_provider->init(socache_instance, authn_cache_id, &authn_cache_hints, s, pconf); if (rv != APR_SUCCESS) { @@ -144,9 +137,22 @@ static const char *authn_cache_socache(cmd_parms *cmd, void *CFG, const char *arg) { const char *errmsg = ap_check_cmd_context(cmd, GLOBAL_ONLY); + const char *sep, *name; + if (errmsg) return errmsg; - socache_provider = ap_lookup_provider(AP_SOCACHE_PROVIDER_GROUP, arg, + + /* Argument is of form 'name:args' or just 'name'. */ + sep = ap_strchr_c(arg, ':'); + if (sep) { + name = apr_pstrmemdup(cmd->pool, arg, sep - arg); + sep++; + } + else { + name = arg; + } + + socache_provider = ap_lookup_provider(AP_SOCACHE_PROVIDER_GROUP, name, AP_SOCACHE_PROVIDER_VERSION); if (socache_provider == NULL) { errmsg = apr_psprintf(cmd->pool, @@ -154,6 +160,14 @@ static const char *authn_cache_socache(cmd_parms *cmd, void *CFG, "to load the appropriate socache module " "(mod_socache_%s?)", arg, arg); } + else { + errmsg = socache_provider->create(&socache_instance, sep, + cmd->temp_pool, cmd->pool); + } + + if (errmsg) { + errmsg = apr_psprintf(cmd->pool, "AuthnCacheSOCache: %s", errmsg); + } return errmsg; } diff --git a/modules/aaa/mod_authnz_ldap.c b/modules/aaa/mod_authnz_ldap.c index 2c25dbc7..d46eeb44 100644 --- a/modules/aaa/mod_authnz_ldap.c +++ b/modules/aaa/mod_authnz_ldap.c @@ -894,7 +894,7 @@ static authz_status ldapgroup_check_authorization(request_rec *r, ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01719) "auth_ldap authorize: require group \"%s\": " "didn't match with attr %s [%s][%d - %s]", - t, ldc->reason, ent[i].name, result, + t, ent[i].name, ldc->reason, result, ldap_err2string(result)); } } diff --git a/modules/aaa/mod_authz_groupfile.c b/modules/aaa/mod_authz_groupfile.c index 934a7d2f..c7fd13b6 100644 --- a/modules/aaa/mod_authz_groupfile.c +++ b/modules/aaa/mod_authz_groupfile.c @@ -249,7 +249,7 @@ static authz_status filegroup_check_authorization(request_rec *r, return AUTHZ_DENIED; } - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01671) + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01671) "Authorization of user %s to access %s failed, reason: " "user is not part of the 'require'ed file group.", r->user, r->uri); diff --git a/modules/aaa/mod_authz_user.c b/modules/aaa/mod_authz_user.c index 7c9462c8..e4af7946 100644 --- a/modules/aaa/mod_authz_user.c +++ b/modules/aaa/mod_authz_user.c @@ -62,7 +62,7 @@ static authz_status user_check_authorization(request_rec *r, } } - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01663) + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01663) "access to %s failed, reason: user '%s' does not meet " "'require'ments for user to be allowed access", r->uri, r->user); diff --git a/modules/cache/cache_storage.c b/modules/cache/cache_storage.c index af60a39b..782dc712 100644 --- a/modules/cache/cache_storage.c +++ b/modules/cache/cache_storage.c @@ -713,7 +713,9 @@ int cache_invalidate(cache_request_rec *cache, request_rec *r) || APR_SUCCESS != cache_canonicalise_key(r, r->pool, location, &location_uri, &location_key) - || strcmp(r->parsed_uri.hostname, location_uri.hostname)) { + || !(r->parsed_uri.hostname && location_uri.hostname + && !strcmp(r->parsed_uri.hostname, + location_uri.hostname))) { location_key = NULL; } } @@ -726,8 +728,9 @@ int cache_invalidate(cache_request_rec *cache, request_rec *r) || APR_SUCCESS != cache_canonicalise_key(r, r->pool, content_location, &content_location_uri, &content_location_key) - || strcmp(r->parsed_uri.hostname, - content_location_uri.hostname)) { + || !(r->parsed_uri.hostname && content_location_uri.hostname + && !strcmp(r->parsed_uri.hostname, + content_location_uri.hostname))) { content_location_key = NULL; } } diff --git a/modules/cache/mod_cache.c b/modules/cache/mod_cache.c index 06bdf460..6e644e67 100644 --- a/modules/cache/mod_cache.c +++ b/modules/cache/mod_cache.c @@ -1104,7 +1104,7 @@ static apr_status_t cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in) reason = "updated entity is older than cached entity"; /* while this response is not cacheable, the previous response still is */ - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00770) + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02474) "cache: Removing CACHE_REMOVE_URL filter."); ap_remove_output_filter(cache->remove_url_filter); } @@ -1171,8 +1171,10 @@ static apr_status_t cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in) */ if (reason && r->status == HTTP_NOT_MODIFIED && cache->stale_handle) { - ap_log_rerror( - APLOG_MARK, APLOG_INFO, 0, r, APLOGNO() "cache: %s responded with an uncacheable 304, retrying the request. Reason: %s", r->unparsed_uri, reason); + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02473) + "cache: %s responded with an uncacheable 304, " + "retrying the request. Reason: %s", + r->unparsed_uri, reason); /* we've got a cache conditional miss! tell anyone who cares */ cache_run_cache_status(cache->handle, r, r->headers_out, AP_CACHE_MISS, diff --git a/modules/cache/mod_cache_socache.c b/modules/cache/mod_cache_socache.c index 913de2ee..220f9c8b 100644 --- a/modules/cache/mod_cache_socache.c +++ b/modules/cache/mod_cache_socache.c @@ -168,8 +168,8 @@ static apr_status_t store_array(apr_array_header_t *arr, unsigned char *buffer, elts = (const char **) arr->elts; for (i = 0; i < arr->nelts; i++) { - len = strlen(elts[i]); - if (len + 3 >= buffer_len - *slider) { + apr_size_t e_len = strlen(elts[i]); + if (e_len + 3 >= buffer_len - *slider) { return APR_EOF; } len = apr_snprintf(buffer ? (char *) buffer + *slider : NULL, diff --git a/modules/cache/mod_socache_memcache.c b/modules/cache/mod_socache_memcache.c index beeeec2c..8cabd8a5 100644 --- a/modules/cache/mod_socache_memcache.c +++ b/modules/cache/mod_socache_memcache.c @@ -85,7 +85,7 @@ static apr_status_t socache_mc_init(ap_socache_instance_t *ctx, { apr_status_t rv; int thread_limit = 0; - int nservers = 0; + apr_uint16_t nservers = 0; char *cache_config; char *split; char *tok; diff --git a/modules/cache/mod_socache_shmcb.c b/modules/cache/mod_socache_shmcb.c index 4d4246b3..f6bf1dab 100644 --- a/modules/cache/mod_socache_shmcb.c +++ b/modules/cache/mod_socache_shmcb.c @@ -316,11 +316,9 @@ static const char *socache_shmcb_create(ap_socache_instance_t **context, } if (ctx->shm_size >= SHMCB_MAX_SIZE) { - return apr_psprintf(tmp, - "Invalid argument: size has " - "to be < %d bytes on this platform", - SHMCB_MAX_SIZE); - + return apr_psprintf(tmp, "Invalid argument: size has " + "to be < %" APR_SIZE_T_FMT " bytes on this platform", + SHMCB_MAX_SIZE); } } else if (cp2 >= path && *cp2 == ')') { diff --git a/modules/dav/fs/repos.c b/modules/dav/fs/repos.c index 6c4c44b1..ae6f5c0e 100644 --- a/modules/dav/fs/repos.c +++ b/modules/dav/fs/repos.c @@ -717,13 +717,13 @@ static dav_error * dav_fs_get_resource( resource->pool = r->pool; /* make sure the URI does not have a trailing "/" */ - len = strlen(r->uri); - if (len > 1 && r->uri[len - 1] == '/') { - s = apr_pstrmemdup(r->pool, r->uri, len-1); + len = strlen(r->unparsed_uri); + if (len > 1 && r->unparsed_uri[len - 1] == '/') { + s = apr_pstrmemdup(r->pool, r->unparsed_uri, len-1); resource->uri = s; } else { - resource->uri = r->uri; + resource->uri = r->unparsed_uri; } if (r->finfo.filetype != APR_NOFILE) { @@ -1482,6 +1482,18 @@ static dav_error * dav_fs_remove_resource(dav_resource *resource, return dav_fs_deleteset(info->pool, resource); } +/* Take an unescaped path component and escape it and append it onto a + * dav_buffer for a URI */ +static apr_size_t dav_fs_append_uri(apr_pool_t *p, dav_buffer *pbuf, + const char *path, apr_size_t pad) +{ + const char *epath = ap_escape_uri(p, path); + apr_size_t epath_len = strlen(epath); + + dav_buffer_place_mem(p, pbuf, epath, epath_len + 1, pad); + return epath_len; +} + /* ### move this to dav_util? */ /* Walk recursively down through directories, * * including lock-null resources as we go. */ @@ -1537,6 +1549,7 @@ static dav_error * dav_fs_walker(dav_fs_walker_context *fsctx, int depth) } while ((apr_dir_read(&dirent, APR_FINFO_DIRENT, dirp)) == APR_SUCCESS) { apr_size_t len; + apr_size_t escaped_len; len = strlen(dirent.name); @@ -1579,7 +1592,7 @@ static dav_error * dav_fs_walker(dav_fs_walker_context *fsctx, int depth) /* copy the file to the URI, too. NOTE: we will pad an extra byte for the trailing slash later. */ - dav_buffer_place_mem(pool, &fsctx->uri_buf, dirent.name, len + 1, 1); + escaped_len = dav_fs_append_uri(pool, &fsctx->uri_buf, dirent.name, 1); /* if there is a secondary path, then do that, too */ if (fsctx->path2.buf != NULL) { @@ -1612,7 +1625,7 @@ static dav_error * dav_fs_walker(dav_fs_walker_context *fsctx, int depth) fsctx->path2.cur_len += len; /* adjust URI length to incorporate subdir and a slash */ - fsctx->uri_buf.cur_len += len + 1; + fsctx->uri_buf.cur_len += escaped_len + 1; fsctx->uri_buf.buf[fsctx->uri_buf.cur_len - 1] = '/'; fsctx->uri_buf.buf[fsctx->uri_buf.cur_len] = '\0'; @@ -1678,8 +1691,8 @@ static dav_error * dav_fs_walker(dav_fs_walker_context *fsctx, int depth) */ dav_buffer_place_mem(pool, &fsctx->path1, fsctx->locknull_buf.buf + offset, len + 1, 0); - dav_buffer_place_mem(pool, &fsctx->uri_buf, - fsctx->locknull_buf.buf + offset, len + 1, 0); + dav_fs_append_uri(pool, &fsctx->uri_buf, + fsctx->locknull_buf.buf + offset, 0); if (fsctx->path2.buf != NULL) { dav_buffer_place_mem(pool, &fsctx->path2, fsctx->locknull_buf.buf + offset, diff --git a/modules/dav/main/mod_dav.c b/modules/dav/main/mod_dav.c index 9135cd96..f3c2958b 100644 --- a/modules/dav/main/mod_dav.c +++ b/modules/dav/main/mod_dav.c @@ -396,11 +396,9 @@ static int dav_error_response_tag(request_rec *r, */ static const char *dav_xml_escape_uri(apr_pool_t *p, const char *uri) { - const char *e_uri = ap_escape_uri(p, uri); - /* check the easy case... */ - if (ap_strchr_c(e_uri, '&') == NULL) - return e_uri; + if (ap_strchr_c(uri, '&') == NULL) + return uri; /* there was a '&', so more work is needed... sigh. */ @@ -408,7 +406,7 @@ static const char *dav_xml_escape_uri(apr_pool_t *p, const char *uri) * Note: this is a teeny bit of overkill since we know there are no * '<' or '>' characters, but who cares. */ - return apr_xml_quote_string(p, e_uri, 0); + return apr_xml_quote_string(p, uri, 0); } @@ -604,7 +602,8 @@ static int dav_handle_err(request_rec *r, dav_error *err, return DONE; } -/* handy function for return values of methods that (may) create things */ +/* handy function for return values of methods that (may) create things. + * locn if provided is assumed to be escaped. */ static int dav_created(request_rec *r, const char *locn, const char *what, int replaced) { @@ -612,8 +611,6 @@ static int dav_created(request_rec *r, const char *locn, const char *what, if (locn == NULL) { locn = r->unparsed_uri; - } else { - locn = ap_escape_uri(r->pool, locn); } /* did the target resource already exist? */ @@ -2756,7 +2753,7 @@ static int dav_method_copymove(request_rec *r, int is_move) * The multistatus responses will contain the information about any * resource that fails the validation. * - * We check the parent resource, too, since this is a MOVE. Moving the + * We check the parent resource, too, if this is a MOVE. Moving the * resource effectively removes it from the parent collection, so we * must ensure that we have met the appropriate conditions. * @@ -2765,7 +2762,9 @@ static int dav_method_copymove(request_rec *r, int is_move) */ if ((err = dav_validate_request(r, resource, depth, NULL, &multi_response, - DAV_VALIDATE_PARENT + (is_move ? DAV_VALIDATE_PARENT + : DAV_VALIDATE_RESOURCE + | DAV_VALIDATE_NO_MODIFY) | DAV_VALIDATE_USE_424, NULL)) != NULL) { err = dav_push_error(r->pool, err->status, 0, @@ -3002,7 +3001,7 @@ static int dav_method_copymove(request_rec *r, int is_move) } /* return an appropriate response (HTTP_CREATED or HTTP_NO_CONTENT) */ - return dav_created(r, lookup.rnew->uri, "Destination", + return dav_created(r, lookup.rnew->unparsed_uri, "Destination", resnew_state == DAV_RESOURCE_EXISTS); } @@ -4608,7 +4607,7 @@ static int dav_method_bind(request_rec *r) /* return an appropriate response (HTTP_CREATED) */ /* ### spec doesn't say what happens when destination was replaced */ - return dav_created(r, lookup.rnew->uri, "Binding", 0); + return dav_created(r, lookup.rnew->unparsed_uri, "Binding", 0); } diff --git a/modules/dav/main/mod_dav.h b/modules/dav/main/mod_dav.h index 7b91b63c..62c21f05 100644 --- a/modules/dav/main/mod_dav.h +++ b/modules/dav/main/mod_dav.h @@ -386,7 +386,7 @@ typedef struct dav_resource { * REGULAR and WORKSPACE resources, * and is always 1 for WORKING */ - const char *uri; /* the URI for this resource */ + const char *uri; /* the escaped URI for this resource */ dav_resource_private *info; /* the provider's private info */ @@ -1297,6 +1297,9 @@ DAV_DECLARE(dav_error *) dav_validate_request(request_rec *r, the 424 DAV:response */ #define DAV_VALIDATE_USE_424 0x0080 /* return 424 status, not 207 */ #define DAV_VALIDATE_IS_PARENT 0x0100 /* for internal use */ +#define DAV_VALIDATE_NO_MODIFY 0x0200 /* resource is not being modified + so allow even if lock token + is not provided */ /* Lock-null related public lock functions */ DAV_DECLARE(int) dav_get_resource_state(request_rec *r, diff --git a/modules/dav/main/util.c b/modules/dav/main/util.c index ab42af02..1f393401 100644 --- a/modules/dav/main/util.c +++ b/modules/dav/main/util.c @@ -954,13 +954,16 @@ static dav_error * dav_validate_resource_state(apr_pool_t *p, /* ** For methods other than LOCK: ** - ** If we have no locks, then <seen_locktoken> can be set to true -- + ** If we have no locks or if the resource is not being modified + ** (per RFC 4918 the lock token is not required on resources + ** we are not changing), then <seen_locktoken> can be set to true -- ** pretending that we've already met the requirement of seeing one ** of the resource's locks in the If: header. ** ** Otherwise, it must be cleared and we'll look for one. */ - seen_locktoken = (lock_list == NULL); + seen_locktoken = (lock_list == NULL + || flags & DAV_VALIDATE_NO_MODIFY); } /* diff --git a/modules/filters/mod_charset_lite.c b/modules/filters/mod_charset_lite.c index 2d3d1439..934f0477 100644 --- a/modules/filters/mod_charset_lite.c +++ b/modules/filters/mod_charset_lite.c @@ -474,7 +474,7 @@ static void log_xlate_error(ap_filter_t *f, apr_status_t rv) charset_filter_ctx_t *ctx = f->ctx; const char *msg; char msgbuf[100]; - int len; + apr_size_t len; switch(ctx->ees) { case EES_LIMIT: diff --git a/modules/filters/mod_data.c b/modules/filters/mod_data.c index 83284dd2..d083d322 100644 --- a/modules/filters/mod_data.c +++ b/modules/filters/mod_data.c @@ -109,7 +109,8 @@ static apr_status_t data_out_filter(ap_filter_t *f, apr_bucket_brigade *bb) apr_brigade_length(ctx->bb, 1, &len); clen = apr_atoi64(content_length); if (clen >= 0 && clen < APR_INT32_MAX) { - ap_set_content_length(r, len + apr_base64_encode_len(clen) - 1); + ap_set_content_length(r, len + + apr_base64_encode_len((int)clen) - 1); } else { apr_table_unset(r->headers_out, "Content-Length"); diff --git a/modules/filters/mod_deflate.c b/modules/filters/mod_deflate.c index 79f6f8d1..5ae06085 100644 --- a/modules/filters/mod_deflate.c +++ b/modules/filters/mod_deflate.c @@ -1013,8 +1013,8 @@ static apr_status_t deflate_in_filter(ap_filter_t *f, if (APR_BUCKET_IS_EOS(bkt)) { if (!ctx->done) { inflateEnd(&ctx->stream); - ap_log_rerror( - APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02481) "Encountered premature end-of-stream while inflating"); + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02481) + "Encountered premature end-of-stream while inflating"); return APR_EGENERAL; } @@ -1053,8 +1053,8 @@ static apr_status_t deflate_in_filter(ap_filter_t *f, /* sanity check - data after completed compressed body and before eos? */ if (ctx->done) { - ap_log_rerror( - APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02482) "Encountered extra data after compressed data"); + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02482) + "Encountered extra data after compressed data"); return APR_EGENERAL; } @@ -1096,6 +1096,7 @@ static apr_status_t deflate_in_filter(ap_filter_t *f, } if (zRC == Z_STREAM_END) { apr_bucket *tmp_heap; + apr_size_t avail; ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01393) "Zlib: Inflated %ld to %ld : URL %s", @@ -1110,8 +1111,10 @@ static apr_status_t deflate_in_filter(ap_filter_t *f, APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, tmp_heap); ctx->stream.avail_out = c->bufferSize; + avail = ctx->stream.avail_in; + /* Is the remaining 8 bytes already in the avail stream? */ - if (ctx->stream.avail_in >= 8) { + if (avail >= 8) { unsigned long compCRC, compLen; compCRC = getLong(ctx->stream.next_in); if (ctx->crc != compCRC) { @@ -1143,6 +1146,13 @@ static apr_status_t deflate_in_filter(ap_filter_t *f, inflateEnd(&ctx->stream); ctx->done = 1; + + /* Did we have trailing data behind the closing 8 bytes? */ + if (avail > 8) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02485) + "Encountered extra data after compressed data"); + return APR_EGENERAL; + } } } diff --git a/modules/filters/mod_filter.c b/modules/filters/mod_filter.c index 2d8e8b65..8fb872cd 100644 --- a/modules/filters/mod_filter.c +++ b/modules/filters/mod_filter.c @@ -368,6 +368,9 @@ static const char *filter_protocol(cmd_parms *cmd, void *CFG, const char *fname, if (!strcasecmp(arg, "change=yes")) { flags |= AP_FILTER_PROTO_CHANGE | AP_FILTER_PROTO_CHANGE_LENGTH; } + if (!strcasecmp(arg, "change=no")) { + flags &= ~(AP_FILTER_PROTO_CHANGE | AP_FILTER_PROTO_CHANGE_LENGTH); + } else if (!strcasecmp(arg, "change=1:1")) { flags |= AP_FILTER_PROTO_CHANGE; } diff --git a/modules/filters/mod_proxy_html.dsp b/modules/filters/mod_proxy_html.dsp index be883edd..1d5d54e7 100644 --- a/modules/filters/mod_proxy_html.dsp +++ b/modules/filters/mod_proxy_html.dsp @@ -79,7 +79,7 @@ PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).ma # ADD BASE MTL /nologo /D "_DEBUG" /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /i /d "_DEBUG" "../../include" /i "../../srclib/apr/include" /I "../../srclib/apr-util/include" /i "../../srclib/libxml2/include" /d BIN_NAME="mod_proxy_html.so" /d LONG_NAME="proxy_html_module for Apache" +# ADD RSC /l 0x409 /d "_DEBUG" /i "../../include" /i "../../srclib/apr/include" /I "../../srclib/apr-util/include" /i "../../srclib/libxml2/include" /d BIN_NAME="mod_proxy_html.so" /d LONG_NAME="proxy_html_module for Apache" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo diff --git a/modules/filters/mod_xml2enc.dsp b/modules/filters/mod_xml2enc.dsp index d5e357a4..69e2904a 100644 --- a/modules/filters/mod_xml2enc.dsp +++ b/modules/filters/mod_xml2enc.dsp @@ -79,7 +79,7 @@ PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).ma # ADD BASE MTL /nologo /D "_DEBUG" /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /i /d "_DEBUG" "../../include" /i "../../srclib/apr/include" /i "../../srclib/apr-util/include" /i "../../srclib/libxml2/include" /d BIN_NAME="mod_xml2enc.so" /d LONG_NAME="xml2enc_module for Apache" +# ADD RSC /l 0x409 /d "_DEBUG" /i "../../include" /i "../../srclib/apr/include" /i "../../srclib/apr-util/include" /i "../../srclib/libxml2/include" /d BIN_NAME="mod_xml2enc.so" /d LONG_NAME="xml2enc_module for Apache" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo diff --git a/modules/generators/mod_info.c b/modules/generators/mod_info.c index 2f2db9fa..e5e63de1 100644 --- a/modules/generators/mod_info.c +++ b/modules/generators/mod_info.c @@ -113,7 +113,7 @@ static void put_int_flush_right(request_rec * r, int i, int field) if (r) ap_rputc('0' + i % 10, r); else - apr_file_putc('0' + i % 10, out); + apr_file_putc((char)('0' + i % 10), out); } else { if (r) diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c index 24a939a4..c7274194 100644 --- a/modules/http/http_filters.c +++ b/modules/http/http_filters.c @@ -825,7 +825,7 @@ static apr_status_t send_all_header_fields(header_struct *h, * handler. * Zap r->status_line if bad. */ -static void validate_status_line(request_rec *r) +static apr_status_t validate_status_line(request_rec *r) { char *end; @@ -836,15 +836,19 @@ static void validate_status_line(request_rec *r) || (end - 3) != r->status_line || (len >= 4 && ! apr_isspace(r->status_line[3]))) { r->status_line = NULL; + return APR_EGENERAL; } /* Since we passed the above check, we know that length three * is equivalent to only a 3 digit numeric http status. * RFC2616 mandates a trailing space, let's add it. */ - else if (len == 3) { + if (len == 3) { r->status_line = apr_pstrcat(r->pool, r->status_line, " ", NULL); + return APR_EGENERAL; } + return APR_SUCCESS; } + return APR_EGENERAL; } /* @@ -856,15 +860,25 @@ static void validate_status_line(request_rec *r) static void basic_http_header_check(request_rec *r, const char **protocol) { + apr_status_t rv; + if (r->assbackwards) { /* no such thing as a response protocol */ return; } - validate_status_line(r); + rv = validate_status_line(r); if (!r->status_line) { r->status_line = ap_get_status_line(r->status); + } else if (rv != APR_SUCCESS) { + /* Status line is OK but our own reason phrase + * would be preferred if defined + */ + const char *tmp = ap_get_status_line(r->status); + if (!strncmp(tmp, r->status_line, 3)) { + r->status_line = tmp; + } } /* Note that we must downgrade before checking for force responses. */ diff --git a/modules/ldap/util_ldap.c b/modules/ldap/util_ldap.c index 7c6a5e30..bf37567a 100644 --- a/modules/ldap/util_ldap.c +++ b/modules/ldap/util_ldap.c @@ -60,6 +60,7 @@ #endif #define AP_LDAP_HOPLIMIT_UNSET -1 +#define AP_LDAP_CHASEREFERRALS_SDKDEFAULT -1 #define AP_LDAP_CHASEREFERRALS_OFF 0 #define AP_LDAP_CHASEREFERRALS_ON 1 @@ -364,7 +365,7 @@ static int uldap_connection_init(request_rec *r, ldap_option = ldc->deref; ldap_set_option(ldc->ldap, LDAP_OPT_DEREF, &ldap_option); - if (ldc->ChaseReferrals == AP_LDAP_CHASEREFERRALS_ON) { + if (ldc->ChaseReferrals != AP_LDAP_CHASEREFERRALS_SDKDEFAULT) { /* Set options for rebind and referrals. */ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, APLOGNO(01278) "LDAP: Setting referrals to %s.", @@ -384,7 +385,9 @@ static int uldap_connection_init(request_rec *r, uldap_connection_unbind(ldc); return(result->rc); } + } + if (ldc->ChaseReferrals == AP_LDAP_CHASEREFERRALS_ON) { if ((ldc->ReferralHopLimit != AP_LDAP_HOPLIMIT_UNSET) && ldc->ChaseReferrals == AP_LDAP_CHASEREFERRALS_ON) { /* Referral hop limit - only if referrals are enabled and a hop limit is explicitly requested */ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, APLOGNO(01280) @@ -941,6 +944,7 @@ start_over: "failed with server down"; uldap_connection_unbind(ldc); failures++; + ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, r, "%s (attempt %d)", ldc->reason, failures); goto start_over; } if (result == LDAP_TIMEOUT && failures == 0) { @@ -952,6 +956,7 @@ start_over: "failed with timeout"; uldap_connection_unbind(ldc); failures++; + ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, r, "%s (attempt %d)", ldc->reason, failures); goto start_over; } if (result != LDAP_SUCCESS) { @@ -1096,6 +1101,7 @@ start_over: ldc->reason = "ldap_compare_s() failed with server down"; uldap_connection_unbind(ldc); failures++; + ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, r, "%s (attempt %d)", ldc->reason, failures); goto start_over; } if (result == LDAP_TIMEOUT && failures == 0) { @@ -1106,6 +1112,7 @@ start_over: ldc->reason = "ldap_compare_s() failed with timeout"; uldap_connection_unbind(ldc); failures++; + ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, r, "%s (attempt %d)", ldc->reason, failures); goto start_over; } @@ -1206,13 +1213,14 @@ start_over: /* try to do the search */ result = ldap_search_ext_s(ldc->ldap, (char *)dn, LDAP_SCOPE_BASE, - (char *)"cn=*", subgroupAttrs, 0, + NULL, subgroupAttrs, 0, NULL, NULL, NULL, APR_LDAP_SIZELIMIT, &sga_res); if (AP_LDAP_IS_SERVER_DOWN(result)) { ldc->reason = "ldap_search_ext_s() for subgroups failed with server" " down"; uldap_connection_unbind(ldc); failures++; + ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, r, "%s (attempt %d)", ldc->reason, failures); goto start_over; } if (result == LDAP_TIMEOUT && failures == 0) { @@ -1223,6 +1231,7 @@ start_over: ldc->reason = "ldap_search_ext_s() for subgroups failed with timeout"; uldap_connection_unbind(ldc); failures++; + ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, r, "%s (attempt %d)", ldc->reason, failures); goto start_over; } @@ -1691,9 +1700,19 @@ start_over: ldc->reason = "ldap_search_ext_s() for user failed with server down"; uldap_connection_unbind(ldc); failures++; + ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, r, "%s (attempt %d)", ldc->reason, failures); + goto start_over; + } + + if (result == LDAP_TIMEOUT) { + ldc->reason = "ldap_search_ext_s() for user failed with timeout"; + uldap_connection_unbind(ldc); + failures++; + ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, r, "%s (attempt %d)", ldc->reason, failures); goto start_over; } + /* if there is an error (including LDAP_NO_SUCH_OBJECT) return now */ if (result != LDAP_SUCCESS) { ldc->reason = "ldap_search_ext_s() for user failed"; @@ -1754,6 +1773,7 @@ start_over: ldap_msgfree(res); uldap_connection_unbind(ldc); failures++; + ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, r, "%s (attempt %d)", ldc->reason, failures); goto start_over; } @@ -1949,6 +1969,7 @@ start_over: ldc->reason = "ldap_search_ext_s() for user failed with server down"; uldap_connection_unbind(ldc); failures++; + ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, r, "%s (attempt %d)", ldc->reason, failures); goto start_over; } @@ -2536,15 +2557,25 @@ static const char *util_ldap_set_connection_timeout(cmd_parms *cmd, static const char *util_ldap_set_chase_referrals(cmd_parms *cmd, void *config, - int mode) + const char *arg) { util_ldap_config_t *dc = config; ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01311) - "LDAP: Setting referral chasing %s", - (mode == AP_LDAP_CHASEREFERRALS_ON) ? "ON" : "OFF"); + "LDAP: Setting referral chasing %s", arg); - dc->ChaseReferrals = mode; + if (0 == strcasecmp(arg, "on")) { + dc->ChaseReferrals = AP_LDAP_CHASEREFERRALS_ON; + } + else if (0 == strcasecmp(arg, "off")) { + dc->ChaseReferrals = AP_LDAP_CHASEREFERRALS_OFF; + } + else if (0 == strcasecmp(arg, "default")) { + dc->ChaseReferrals = AP_LDAP_CHASEREFERRALS_SDKDEFAULT; + } + else { + return "LDAPReferrals must be 'on', 'off', or 'default'"; + } return(NULL); } @@ -3076,9 +3107,9 @@ static const command_rec util_ldap_cmds[] = { "Specify the LDAP socket connection timeout in seconds " "(default: 10)"), - AP_INIT_FLAG("LDAPReferrals", util_ldap_set_chase_referrals, + AP_INIT_TAKE1("LDAPReferrals", util_ldap_set_chase_referrals, NULL, OR_AUTHCFG, - "Choose whether referrals are chased ['ON'|'OFF']. Default 'ON'"), + "Choose whether referrals are chased ['ON'|'OFF'|'DEFAULT']. Default 'ON'"), AP_INIT_TAKE1("LDAPReferralHopLimit", util_ldap_set_referral_hop_limit, NULL, OR_AUTHCFG, diff --git a/modules/ldap/util_ldap_cache.c b/modules/ldap/util_ldap_cache.c index 87642e11..b1346f05 100644 --- a/modules/ldap/util_ldap_cache.c +++ b/modules/ldap/util_ldap_cache.c @@ -52,7 +52,7 @@ void *util_ldap_url_node_copy(util_ald_cache_t *cache, void *c) if (node) { if (!(node->url = util_ald_strdup(cache, n->url))) { - util_ald_free(cache, node->url); + util_ald_free(cache, node); return NULL; } node->search_cache = n->search_cache; diff --git a/modules/loggers/mod_log_config.c b/modules/loggers/mod_log_config.c index e1a82041..f17e1641 100644 --- a/modules/loggers/mod_log_config.c +++ b/modules/loggers/mod_log_config.c @@ -194,8 +194,8 @@ static void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s, static void *ap_buffered_log_writer_init(apr_pool_t *p, server_rec *s, const char* name); -static ap_log_writer_init* ap_log_set_writer_init(ap_log_writer_init *handle); -static ap_log_writer* ap_log_set_writer(ap_log_writer *handle); +static ap_log_writer_init *ap_log_set_writer_init(ap_log_writer_init *handle); +static ap_log_writer *ap_log_set_writer(ap_log_writer *handle); static ap_log_writer *log_writer = ap_default_log_writer; static ap_log_writer_init *log_writer_init = ap_default_log_writer_init; static int buffered_logs = 0; /* default unbuffered */ @@ -1507,7 +1507,7 @@ static void ap_register_log_handler(apr_pool_t *p, char *tag, apr_hash_set(log_hash, tag, 1, (const void *)log_struct); } -static ap_log_writer_init* ap_log_set_writer_init(ap_log_writer_init *handle) +static ap_log_writer_init *ap_log_set_writer_init(ap_log_writer_init *handle) { ap_log_writer_init *old = log_writer_init; log_writer_init = handle; @@ -1536,6 +1536,10 @@ static apr_status_t ap_default_log_writer( request_rec *r, int i; apr_status_t rv; + /* + * We do this memcpy dance because write() is atomic for len < PIPE_BUF, + * while writev() need not be. + */ str = apr_palloc(r->pool, len + 1); for (i = 0, s = str; i < nelts; ++i) { @@ -1616,6 +1620,10 @@ static apr_status_t ap_buffered_log_writer(request_rec *r, if (len >= LOG_BUFSIZE) { apr_size_t w; + /* + * We do this memcpy dance because write() is atomic for + * len < PIPE_BUF, while writev() need not be. + */ str = apr_palloc(r->pool, len + 1); for (i = 0, s = str; i < nelts; ++i) { memcpy(s, strs[i], strl[i]); diff --git a/modules/loggers/mod_logio.c b/modules/loggers/mod_logio.c index f58c2922..ad387a9b 100644 --- a/modules/loggers/mod_logio.c +++ b/modules/loggers/mod_logio.c @@ -15,15 +15,7 @@ */ /* - * Written by Bojan Smojver <bojan rexursive.com>: - * - * The argument to LogFormat and CustomLog is a string, which can include - * literal characters copied into the log files, and '%' directives as - * follows: - * - * %...I: bytes received, including request and headers, cannot be zero - * %...O: bytes sent, including headers, cannot be zero - * + * Written by Bojan Smojver <bojan rexursive.com>. */ #include "apr_strings.h" @@ -108,6 +100,14 @@ static const char *log_bytes_out(request_rec *r, char *a) return apr_off_t_toa(r->pool, cf->bytes_out); } +static const char *log_bytes_combined(request_rec *r, char *a) +{ + logio_config_t *cf = ap_get_module_config(r->connection->conn_config, + &logio_module); + + return apr_off_t_toa(r->pool, cf->bytes_out + cf->bytes_in); +} + /* * Reset counters after logging... */ @@ -170,6 +170,7 @@ static int logio_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp) if (log_pfn_register) { log_pfn_register(p, "I", log_bytes_in, 0); log_pfn_register(p, "O", log_bytes_out, 0); + log_pfn_register(p, "S", log_bytes_combined, 0); } return OK; diff --git a/modules/lua/lua_passwd.h b/modules/lua/lua_passwd.h index 797556bf..8606cc1d 100644 --- a/modules/lua/lua_passwd.h +++ b/modules/lua/lua_passwd.h @@ -70,7 +70,6 @@ struct passwd_ctx { const char *errstr; char *out; apr_size_t out_len; -// const char *passwd; char *passwd; int alg; int cost; diff --git a/modules/lua/lua_request.c b/modules/lua/lua_request.c index c2cfb535..8dce13cc 100644 --- a/modules/lua/lua_request.c +++ b/modules/lua/lua_request.c @@ -26,8 +26,9 @@ #include "apr_date.h" #include "apr_pools.h" #include "apr_thread_mutex.h" - -#include <lua.h> +#include "apr_tables.h" +#include "util_cookies.h" +#include "apr_want.h" extern apr_thread_mutex_t* lua_ivm_mutex; @@ -839,6 +840,7 @@ static int lua_apr_sha1(lua_State *L) apr_sha1_init(&sha1); apr_sha1_update(&sha1, buffer, len); apr_sha1_final(digest, &sha1); + ap_bin2hex(digest, sizeof(digest), result); lua_pushstring(L, result); return 1; @@ -884,7 +886,7 @@ static int lua_apr_touch(lua_State *L) r = ap_lua_check_request_rec(L, 1); luaL_checktype(L, 2, LUA_TSTRING); path = lua_tostring(L, 2); - mtime = luaL_optnumber(L, 3, apr_time_now()); + mtime = (apr_time_t)luaL_optnumber(L, 3, (lua_Number)apr_time_now()); status = apr_file_mtime_set(path, mtime, r->pool); lua_pushboolean(L, (status == 0)); return 1; @@ -1887,6 +1889,414 @@ static int lua_ivm_set(lua_State *L) return 0; } +static int lua_get_cookie(lua_State *L) +{ + const char *key, *cookie; + request_rec *r = ap_lua_check_request_rec(L, 1); + key = luaL_checkstring(L, 2); + cookie = NULL; + ap_cookie_read(r, key, &cookie, 0); + if (cookie != NULL) { + lua_pushstring(L, cookie); + return 1; + } + return 0; +} + +static int lua_set_cookie(lua_State *L) +{ + const char *key, *value, *out, *strexpires; + int secure, expires; + char cdate[APR_RFC822_DATE_LEN+1]; + apr_status_t rv; + request_rec *r = ap_lua_check_request_rec(L, 1); + key = luaL_checkstring(L, 2); + value = luaL_checkstring(L, 3); + secure = 0; + if (lua_isboolean(L, 4)) { + secure = lua_toboolean(L, 4); + } + expires = luaL_optinteger(L, 5, 0); + strexpires = ""; + if (expires > 0) { + rv = apr_rfc822_date(cdate, apr_time_from_sec(expires)); + if (rv == APR_SUCCESS) { + strexpires = apr_psprintf(r->pool, "Expires=%s", cdate); + } + } + out = apr_psprintf(r->pool, "%s=%s; %s %s", key, value, secure ? "Secure;" : "", expires ? strexpires : ""); + apr_table_set(r->headers_out, "Set-Cookie", out); + return 0; +} + +static apr_uint64_t ap_ntoh64(const apr_uint64_t *input) +{ + apr_uint64_t rval; + unsigned char *data = (unsigned char *)&rval; + if (APR_IS_BIGENDIAN) { + return *input; + } + + data[0] = *input >> 56; + data[1] = *input >> 48; + data[2] = *input >> 40; + data[3] = *input >> 32; + data[4] = *input >> 24; + data[5] = *input >> 16; + data[6] = *input >> 8; + data[7] = *input >> 0; + + return rval; +} + +static int lua_websocket_greet(lua_State *L) +{ + const char *key = NULL; + unsigned char digest[APR_SHA1_DIGESTSIZE]; + apr_sha1_ctx_t sha1; + char *encoded; + int encoded_len; + request_rec *r = ap_lua_check_request_rec(L, 1); + key = apr_table_get(r->headers_in, "Sec-WebSocket-Key"); + if (key != NULL) { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + "Websocket: Got websocket key: %s", key); + key = apr_pstrcat(r->pool, key, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", + NULL); + apr_sha1_init(&sha1); + apr_sha1_update(&sha1, key, strlen(key)); + apr_sha1_final(digest, &sha1); + encoded_len = apr_base64_encode_len(APR_SHA1_DIGESTSIZE); + if (encoded_len) { + encoded = apr_palloc(r->pool, encoded_len); + encoded_len = apr_base64_encode(encoded, (char*) digest, APR_SHA1_DIGESTSIZE); + r->status = 101; + apr_table_set(r->headers_out, "Upgrade", "websocket"); + apr_table_set(r->headers_out, "Connection", "Upgrade"); + apr_table_set(r->headers_out, "Sec-WebSocket-Accept", encoded); + + /* Trick httpd into NOT using the chunked filter, IMPORTANT!!!111*/ + apr_table_set(r->headers_out, "Transfer-Encoding", "chunked"); + + r->clength = 0; + r->bytes_sent = 0; + r->read_chunked = 0; + ap_rflush(r); + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + "Websocket: Upgraded from HTTP to Websocket"); + lua_pushboolean(L, 1); + return 1; + } + } + ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, + "Websocket: Upgrade from HTTP to Websocket failed"); + return 0; +} + +static apr_status_t lua_websocket_readbytes(conn_rec* c, char* buffer, + apr_off_t len) +{ + apr_bucket_brigade *brigade = apr_brigade_create(c->pool, c->bucket_alloc); + apr_status_t rv; + rv = ap_get_brigade(c->input_filters, brigade, AP_MODE_READBYTES, + APR_BLOCK_READ, len); + if (rv == APR_SUCCESS) { + if (!APR_BRIGADE_EMPTY(brigade)) { + apr_bucket* bucket = APR_BRIGADE_FIRST(brigade); + const char* data = NULL; + apr_size_t data_length = 0; + rv = apr_bucket_read(bucket, &data, &data_length, APR_BLOCK_READ); + if (rv == APR_SUCCESS) { + memcpy(buffer, data, len); + } + apr_bucket_delete(bucket); + } + } + apr_brigade_cleanup(brigade); + return rv; +} + +static int lua_websocket_read(lua_State *L) +{ + apr_socket_t *sock; + apr_status_t rv; + int n = 0; + apr_size_t len = 1; + apr_size_t plen = 0; + unsigned short payload_short = 0; + apr_uint64_t payload_long = 0; + unsigned char *mask_bytes; + char byte; + int plaintext; + + + request_rec *r = (request_rec *) lua_unboxpointer(L, 1); + plaintext = ap_lua_ssl_is_https(r->connection) ? 0 : 1; + + + mask_bytes = apr_pcalloc(r->pool, 4); + sock = ap_get_conn_socket(r->connection); + + /* Get opcode and FIN bit */ + if (plaintext) { + rv = apr_socket_recv(sock, &byte, &len); + } + else { + rv = lua_websocket_readbytes(r->connection, &byte, 1); + } + if (rv == APR_SUCCESS) { + unsigned char fin, opcode, mask, payload; + fin = byte >> 7; + opcode = (byte << 4) >> 4; + + /* Get the payload length and mask bit */ + if (plaintext) { + rv = apr_socket_recv(sock, &byte, &len); + } + else { + rv = lua_websocket_readbytes(r->connection, &byte, 1); + } + if (rv == APR_SUCCESS) { + mask = byte >> 7; + payload = byte - 128; + plen = payload; + + /* Extended payload? */ + if (payload == 126) { + len = 2; + if (plaintext) { + rv = apr_socket_recv(sock, (char*) &payload_short, &len); + } + else { + rv = lua_websocket_readbytes(r->connection, + (char*) &payload_short, 2); + } + payload_short = ntohs(payload_short); + + if (rv == APR_SUCCESS) { + plen = payload_short; + } + else { + return 0; + } + } + /* Super duper extended payload? */ + if (payload == 127) { + len = 8; + if (plaintext) { + rv = apr_socket_recv(sock, (char*) &payload_long, &len); + } + else { + rv = lua_websocket_readbytes(r->connection, + (char*) &payload_long, 8); + } + if (rv == APR_SUCCESS) { + plen = ap_ntoh64(&payload_long); + } + else { + return 0; + } + } + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + "Websocket: Reading %lu (%s) bytes, masking is %s. %s", + plen, + (payload >= 126) ? "extra payload" : "no extra payload", + mask ? "on" : "off", + fin ? "This is a final frame" : "more to follow"); + if (mask) { + len = 4; + if (plaintext) { + rv = apr_socket_recv(sock, (char*) mask_bytes, &len); + } + else { + rv = lua_websocket_readbytes(r->connection, + (char*) mask_bytes, 4); + } + if (rv != APR_SUCCESS) { + return 0; + } + } + if (plen < (HUGE_STRING_LEN*1024) && plen > 0) { + apr_size_t remaining = plen; + apr_size_t received; + apr_off_t at = 0; + char *buffer = apr_palloc(r->pool, plen+1); + buffer[plen] = 0; + + if (plaintext) { + while (remaining > 0) { + received = remaining; + rv = apr_socket_recv(sock, buffer+at, &received); + if (received > 0 ) { + remaining -= received; + at += received; + } + } + ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, + "Websocket: Frame contained %lu bytes, pushed to Lua stack", + at); + } + else { + rv = lua_websocket_readbytes(r->connection, buffer, + remaining); + ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, + "Websocket: SSL Frame contained %lu bytes, "\ + "pushed to Lua stack", + remaining); + } + if (mask) { + for (n = 0; n < plen; n++) { + buffer[n] ^= mask_bytes[n%4]; + } + } + + lua_pushlstring(L, buffer, (size_t) plen); /* push to stack */ + lua_pushboolean(L, fin); /* push FIN bit to stack as boolean */ + return 2; + } + + + /* Decide if we need to react to the opcode or not */ + if (opcode == 0x09) { /* ping */ + char frame[2]; + plen = 2; + frame[0] = 0x8A; + frame[1] = 0; + apr_socket_send(sock, frame, &plen); /* Pong! */ + lua_websocket_read(L); /* read the next frame instead */ + } + } + } + return 0; +} + + +static int lua_websocket_write(lua_State *L) +{ + const char *string; + apr_status_t rv; + size_t len; + int raw = 0; + char prelude; + request_rec *r = (request_rec *) lua_unboxpointer(L, 1); + + if (lua_isboolean(L, 3)) { + raw = lua_toboolean(L, 3); + } + string = lua_tolstring(L, 2, &len); + + if (raw != 1) { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + "Websocket: Writing framed message to client"); + + prelude = 0x81; /* text frame, FIN */ + ap_rputc(prelude, r); + if (len < 126) { + ap_rputc(len, r); + } + else if (len < 65535) { + apr_uint16_t slen = len; + ap_rputc(126, r); + slen = htons(slen); + ap_rwrite((char*) &slen, 2, r); + } + else { + apr_uint64_t llen = len; + ap_rputc(127, r); + llen = ap_ntoh64(&llen); /* ntoh doubles as hton */ + ap_rwrite((char*) &llen, 8, r); + } + } + else { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + "Websocket: Writing raw message to client"); + } + ap_rwrite(string, len, r); + rv = ap_rflush(r); + if (rv == APR_SUCCESS) { + lua_pushboolean(L, 1); + } + else { + lua_pushboolean(L, 0); + } + return 1; +} + + +static int lua_websocket_close(lua_State *L) +{ + apr_socket_t *sock; + char prelude[2]; + request_rec *r = (request_rec *) lua_unboxpointer(L, 1); + + sock = ap_get_conn_socket(r->connection); + + /* Send a header that says: socket is closing. */ + prelude[0] = 0x88; /* closing socket opcode */ + prelude[1] = 0; /* zero length frame */ + ap_rwrite(prelude, 2, r); + + /* Close up tell the MPM and filters to back off */ + apr_socket_close(sock); + r->output_filters = NULL; + r->connection->keepalive = AP_CONN_CLOSE; + ap_destroy_sub_req(r); + return DONE; +} + + +static int lua_websocket_ping(lua_State *L) +{ + apr_socket_t *sock; + apr_size_t plen; + char prelude[2]; + apr_status_t rv; + request_rec *r = ap_lua_check_request_rec(L, 1); + sock = ap_get_conn_socket(r->connection); + + /* Send a header that says: PING. */ + prelude[0] = 0x89; /* ping opcode */ + prelude[1] = 0; + plen = 2; + apr_socket_send(sock, prelude, &plen); + + + /* Get opcode and FIN bit from pong */ + plen = 2; + rv = apr_socket_recv(sock, prelude, &plen); + if (rv == APR_SUCCESS) { + unsigned char opcode = prelude[0]; + unsigned char len = prelude[1]; + unsigned char mask = len >> 7; + if (mask) len -= 128; + plen = len; + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + "Websocket: Got PONG opcode: %x", opcode); + if (opcode == 0x8A) { + lua_pushboolean(L, 1); + } + else { + lua_pushboolean(L, 0); + } + if (plen > 0) { + ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, + "Websocket: Reading %lu bytes of PONG", plen); + return 1; + } + if (mask) { + plen = 2; + apr_socket_recv(sock, prelude, &plen); + plen = 2; + apr_socket_recv(sock, prelude, &plen); + } + } + else { + lua_pushboolean(L, 0); + } + return 1; +} + + #define APLUA_REQ_TRACE(lev) static int req_trace##lev(lua_State *L) \ { \ return req_log_at(L, APLOG_TRACE##lev); \ @@ -1994,6 +2404,7 @@ static const char* lua_ap_get_server_name(request_rec* r) + static const struct luaL_Reg server_methods[] = { {NULL, NULL} }; @@ -2236,7 +2647,22 @@ void ap_lua_load_request_lmodule(lua_State *L, apr_pool_t *p) makefun(&lua_ivm_get, APL_REQ_FUNTYPE_LUACFUN, p)); apr_hash_set(dispatch, "ivm_set", APR_HASH_KEY_STRING, makefun(&lua_ivm_set, APL_REQ_FUNTYPE_LUACFUN, p)); - + apr_hash_set(dispatch, "getcookie", APR_HASH_KEY_STRING, + makefun(&lua_get_cookie, APL_REQ_FUNTYPE_LUACFUN, p)); + apr_hash_set(dispatch, "setcookie", APR_HASH_KEY_STRING, + makefun(&lua_set_cookie, APL_REQ_FUNTYPE_LUACFUN, p)); + apr_hash_set(dispatch, "wsupgrade", APR_HASH_KEY_STRING, + makefun(&lua_websocket_greet, APL_REQ_FUNTYPE_LUACFUN, p)); + apr_hash_set(dispatch, "wsread", APR_HASH_KEY_STRING, + makefun(&lua_websocket_read, APL_REQ_FUNTYPE_LUACFUN, p)); + apr_hash_set(dispatch, "wswrite", APR_HASH_KEY_STRING, + makefun(&lua_websocket_write, APL_REQ_FUNTYPE_LUACFUN, p)); + apr_hash_set(dispatch, "wsclose", APR_HASH_KEY_STRING, + makefun(&lua_websocket_close, APL_REQ_FUNTYPE_LUACFUN, p)); + apr_hash_set(dispatch, "wsping", APR_HASH_KEY_STRING, + makefun(&lua_websocket_ping, APL_REQ_FUNTYPE_LUACFUN, p)); + + lua_pushlightuserdata(L, dispatch); lua_setfield(L, LUA_REGISTRYINDEX, "Apache2.Request.dispatch"); diff --git a/modules/lua/mod_lua.c b/modules/lua/mod_lua.c index 7c35011e..6e3390fb 100644 --- a/modules/lua/mod_lua.c +++ b/modules/lua/mod_lua.c @@ -318,7 +318,10 @@ static apr_status_t lua_setup_filter_ctx(ap_filter_t* f, request_rec* r, lua_fil ctx = apr_pcalloc(r->pool, sizeof(lua_filter_ctx)); ctx->broken = 0; *c = ctx; - /* Find the filter that was called */ + /* Find the filter that was called. + * XXX: If we were wired with mod_filter, the filter (mod_filters name) + * and the provider (our underlying filters name) need to have matched. + */ for (n = 0; n < cfg->mapped_filters->nelts; n++) { ap_lua_filter_handler_spec *hook_spec = ((ap_lua_filter_handler_spec **) cfg->mapped_filters->elts)[n]; @@ -374,6 +377,12 @@ static apr_status_t lua_setup_filter_ctx(ap_filter_t* f, request_rec* r, lua_fil */ rc = lua_resume(L, 1); if (rc == LUA_YIELD) { + if (f->frec->providers == NULL) { + /* Not wired by mod_filter */ + apr_table_unset(r->headers_out, "Content-Length"); + apr_table_unset(r->headers_out, "Content-MD5"); + apr_table_unset(r->headers_out, "ETAG"); + } return OK; } else { @@ -407,8 +416,25 @@ static apr_status_t lua_output_filter_handle(ap_filter_t *f, apr_bucket_brigade ap_remove_output_filter(f); return ap_pass_brigade(f->next,pbbIn); } - f->ctx = ctx; - ctx->tmpBucket = apr_brigade_create(r->pool, c->bucket_alloc); + else { + /* We've got a willing lua filter, setup and check for a prefix */ + size_t olen; + apr_bucket *pbktOut; + const char* output = lua_tolstring(ctx->L, 1, &olen); + + f->ctx = ctx; + ctx->tmpBucket = apr_brigade_create(r->pool, c->bucket_alloc); + + if (olen > 0) { + pbktOut = apr_bucket_heap_create(output, olen, NULL, c->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(ctx->tmpBucket, pbktOut); + rv = ap_pass_brigade(f->next, ctx->tmpBucket); + apr_brigade_cleanup(ctx->tmpBucket); + if (rv != APR_SUCCESS) { + return rv; + } + } + } } ctx = (lua_filter_ctx*) f->ctx; L = ctx->L; @@ -433,13 +459,15 @@ static apr_status_t lua_output_filter_handle(ap_filter_t *f, apr_bucket_brigade if (lua_resume(L, 0) == LUA_YIELD) { size_t olen; const char* output = lua_tolstring(L, 1, &olen); - pbktOut = apr_bucket_heap_create(output, olen, NULL, - c->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(ctx->tmpBucket, pbktOut); - rv = ap_pass_brigade(f->next, ctx->tmpBucket); - apr_brigade_cleanup(ctx->tmpBucket); - if (rv != APR_SUCCESS) { - return rv; + if (olen > 0) { + pbktOut = apr_bucket_heap_create(output, olen, NULL, + c->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(ctx->tmpBucket, pbktOut); + rv = ap_pass_brigade(f->next, ctx->tmpBucket); + apr_brigade_cleanup(ctx->tmpBucket); + if (rv != APR_SUCCESS) { + return rv; + } } } else { @@ -461,9 +489,11 @@ static apr_status_t lua_output_filter_handle(ap_filter_t *f, apr_bucket_brigade apr_bucket *pbktOut; size_t olen; const char* output = lua_tolstring(L, 1, &olen); - pbktOut = apr_bucket_heap_create(output, olen, NULL, - c->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(ctx->tmpBucket, pbktOut); + if (olen > 0) { + pbktOut = apr_bucket_heap_create(output, olen, NULL, + c->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(ctx->tmpBucket, pbktOut); + } } pbktEOS = apr_bucket_eos_create(c->bucket_alloc); APR_BRIGADE_INSERT_TAIL(ctx->tmpBucket, pbktEOS); @@ -661,6 +691,13 @@ static int lua_request_rec_hook_harness(request_rec *r, const char *name, int ap rc = DECLINED; if (lua_isnumber(L, -1)) { rc = lua_tointeger(L, -1); + ap_log_rerror(APLOG_MARK, APLOG_TRACE4, 0, r, "Lua hook %s:%s for phase %s returned %d", + hook_spec->file_name, hook_spec->function_name, name, rc); + } + else { + ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, "Lua hook %s:%s for phase %s did not return a numeric value", + hook_spec->file_name, hook_spec->function_name, name); + return HTTP_INTERNAL_SERVER_ERROR; } if (rc != DECLINED) { ap_lua_release_state(L, spec, r); @@ -1076,7 +1113,8 @@ static const char *register_filter_function_hook(const char *filter, /* TODO: Make it work on other types than just AP_FTYPE_RESOURCE? */ if (direction == AP_LUA_FILTER_OUTPUT) { spec->direction = AP_LUA_FILTER_OUTPUT; - ap_register_output_filter(filter, lua_output_filter_handle, NULL, AP_FTYPE_RESOURCE); + ap_register_output_filter_protocol(filter, lua_output_filter_handle, NULL, AP_FTYPE_RESOURCE, + AP_FILTER_PROTO_CHANGE|AP_FILTER_PROTO_CHANGE_LENGTH); } else { spec->direction = AP_LUA_FILTER_INPUT; @@ -1155,6 +1193,11 @@ static void lua_insert_filter_harness(request_rec *r) /* ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, "LuaHookInsertFilter not yet implemented"); */ } +static int lua_log_transaction_harness(request_rec *r) +{ + return lua_request_rec_hook_harness(r, "log_transaction", APR_HOOK_FIRST); +} + static int lua_quick_harness(request_rec *r, int lookup) { if (lookup) { @@ -1219,6 +1262,15 @@ static const char *register_map_to_storage_hook(cmd_parms *cmd, void *_cfg, return register_named_file_function_hook("map_to_storage", cmd, _cfg, file, function, APR_HOOK_MIDDLE); } + +static const char *register_log_transaction_hook(cmd_parms *cmd, void *_cfg, + const char *file, + const char *function) +{ + return register_named_file_function_hook("log_transaction", cmd, _cfg, + file, function, APR_HOOK_FIRST); +} + static const char *register_map_to_storage_block(cmd_parms *cmd, void *_cfg, const char *line) { @@ -1226,6 +1278,7 @@ static const char *register_map_to_storage_block(cmd_parms *cmd, void *_cfg, line); } + static const char *register_check_user_id_hook(cmd_parms *cmd, void *_cfg, const char *file, const char *function, @@ -1783,6 +1836,10 @@ command_rec lua_commands[] = { AP_INIT_TAKE2("LuaHookInsertFilter", register_insert_filter_hook, NULL, OR_ALL, "Provide a hook for the insert_filter phase of request processing"), + + AP_INIT_TAKE2("LuaHookLog", register_log_transaction_hook, NULL, + OR_ALL, + "Provide a hook for the logging phase of request processing"), AP_INIT_TAKE123("LuaScope", register_lua_scope, NULL, OR_ALL, "One of once, request, conn, server -- default is once"), @@ -1983,6 +2040,10 @@ static void lua_register_hooks(apr_pool_t *p) /* ivm mutex */ apr_thread_mutex_create(&lua_ivm_mutex, APR_THREAD_MUTEX_DEFAULT, p); + + /* Logging catcher */ + ap_hook_log_transaction(lua_log_transaction_harness,NULL,NULL, + APR_HOOK_FIRST); } AP_DECLARE_MODULE(lua) = { diff --git a/modules/lua/mod_lua.dsp b/modules/lua/mod_lua.dsp index 770c13a1..ef3294ed 100644 --- a/modules/lua/mod_lua.dsp +++ b/modules/lua/mod_lua.dsp @@ -52,8 +52,8 @@ BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe -# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /out:".\Release\mod_lua.so" /base:@..\..\os\win32\BaseAddr.ref,mod_lua.so -# ADD LINK32 kernel32.lib lua51.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Release\mod_lua.so" /base:@..\..\os\win32\BaseAddr.ref,mod_lua.so /opt:ref /libpath:"../../srclib/lua/src" +# ADD BASE LINK32 kernel32.lib ws2_32.lib /nologo /subsystem:windows /dll /out:".\Release\mod_lua.so" /base:@..\..\os\win32\BaseAddr.ref,mod_lua.so +# ADD LINK32 kernel32.lib ws2_32.lib lua51.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Release\mod_lua.so" /base:@..\..\os\win32\BaseAddr.ref,mod_lua.so /opt:ref /libpath:"../../srclib/lua/src" # Begin Special Build Tool TargetPath=.\Release\mod_lua.so SOURCE="$(InputPath)" @@ -84,8 +84,8 @@ BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe -# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_lua.so" /base:@..\..\os\win32\BaseAddr.ref,mod_lua.so -# ADD LINK32 kernel32.lib lua51.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_lua.so" /base:@..\..\os\win32\BaseAddr.ref,mod_lua.so /libpath:"../../srclib/lua/src" +# ADD BASE LINK32 kernel32.lib ws2_32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_lua.so" /base:@..\..\os\win32\BaseAddr.ref,mod_lua.so +# ADD LINK32 kernel32.lib ws2_32.lib lua51.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_lua.so" /base:@..\..\os\win32\BaseAddr.ref,mod_lua.so /libpath:"../../srclib/lua/src" # Begin Special Build Tool TargetPath=.\Debug\mod_lua.so SOURCE="$(InputPath)" diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c index a7ac2134..0ac4dc9d 100644 --- a/modules/mappers/mod_rewrite.c +++ b/modules/mappers/mod_rewrite.c @@ -585,6 +585,18 @@ static unsigned is_absolute_uri(char *uri, int *supportsqs) return 7; } break; + + case 'w': + case 'W': + if (!strncasecmp(uri, "s://", 4)) { /* ws:// */ + *sqs = 1; + return 5; + } + else if (!strncasecmp(uri, "ss://", 5)) { /* wss:// */ + *sqs = 1; + return 6; + } + break; } return 0; diff --git a/modules/metadata/mod_headers.c b/modules/metadata/mod_headers.c index 9ce2fdec..d4e694bf 100644 --- a/modules/metadata/mod_headers.c +++ b/modules/metadata/mod_headers.c @@ -96,7 +96,9 @@ typedef enum { hdr_unset = 'u', /* unset header */ hdr_echo = 'e', /* echo headers from request to response */ hdr_edit = 'r', /* change value by regexp, match once */ - hdr_edit_r = 'R' /* change value by regexp, everymatch */ + hdr_edit_r = 'R', /* change value by regexp, everymatch */ + hdr_setifempty = 'i', /* set value if header not already present*/ + hdr_note = 'n' /* set value of header in a note */ } hdr_actions; /* @@ -141,7 +143,7 @@ typedef struct { /* edit_do is used for Header edit to iterate through the request headers */ typedef struct { - apr_pool_t *p; + request_rec *r; header_entry *hdr; apr_table_t *t; } edit_do; @@ -390,12 +392,13 @@ static char *parse_format_string(apr_pool_t *p, header_entry *hdr, const char *s char *res; /* No string to parse with unset and echo commands */ - if (hdr->action == hdr_unset || - hdr->action == hdr_edit || - hdr->action == hdr_edit_r || - hdr->action == hdr_echo) { + if (hdr->action == hdr_unset || hdr->action == hdr_echo) { return NULL; } + /* Tags are in the replacement value for edit */ + else if (hdr->action == hdr_edit || hdr->action == hdr_edit_r ) { + s = hdr->subs; + } hdr->ta = apr_array_make(p, 10, sizeof(format_tag)); @@ -431,6 +434,8 @@ static APR_INLINE const char *header_inout_cmd(cmd_parms *cmd, if (!strcasecmp(action, "set")) new->action = hdr_set; + else if (!strcasecmp(action, "setifempty")) + new->action = hdr_setifempty; else if (!strcasecmp(action, "add")) new->action = hdr_add; else if (!strcasecmp(action, "append")) @@ -445,9 +450,11 @@ static APR_INLINE const char *header_inout_cmd(cmd_parms *cmd, new->action = hdr_edit; else if (!strcasecmp(action, "edit*")) new->action = hdr_edit_r; + else if (!strcasecmp(action, "note")) + new->action = hdr_note; else - return "first argument must be 'add', 'set', 'append', 'merge', " - "'unset', 'echo', 'edit', or 'edit*'."; + return "first argument must be 'add', 'set', 'setifempty', 'append', 'merge', " + "'unset', 'echo', 'note', 'edit', or 'edit*'."; if (new->action == hdr_edit || new->action == hdr_edit_r) { if (subs == NULL) { @@ -596,7 +603,7 @@ static char* process_tags(header_entry *hdr, request_rec *r) return str ? str : ""; } static const char *process_regexp(header_entry *hdr, const char *value, - apr_pool_t *pool) + request_rec *r) { ap_regmatch_t pmatch[AP_MAX_REG_MATCH]; const char *subs; @@ -607,7 +614,10 @@ static const char *process_regexp(header_entry *hdr, const char *value, /* no match, nothing to do */ return value; } - subs = ap_pregsub(pool, hdr->subs, value, AP_MAX_REG_MATCH, pmatch); + /* Process tags in the input string rather than the resulting + * substitution to avoid surprises + */ + subs = ap_pregsub(r->pool, process_tags(hdr, r), value, AP_MAX_REG_MATCH, pmatch); if (subs == NULL) return NULL; diffsz = strlen(subs) - (pmatch[0].rm_eo - pmatch[0].rm_so); @@ -615,12 +625,12 @@ static const char *process_regexp(header_entry *hdr, const char *value, remainder = value + pmatch[0].rm_eo; } else { /* recurse to edit multiple matches if applicable */ - remainder = process_regexp(hdr, value + pmatch[0].rm_eo, pool); + remainder = process_regexp(hdr, value + pmatch[0].rm_eo, r); if (remainder == NULL) return NULL; diffsz += strlen(remainder) - strlen(value + pmatch[0].rm_eo); } - ret = apr_palloc(pool, strlen(value) + 1 + diffsz); + ret = apr_palloc(r->pool, strlen(value) + 1 + diffsz); memcpy(ret, value, pmatch[0].rm_so); strcpy(ret + pmatch[0].rm_so, subs); strcat(ret, remainder); @@ -642,7 +652,7 @@ static int echo_header(echo_do *v, const char *key, const char *val) static int edit_header(void *v, const char *key, const char *val) { edit_do *ed = (edit_do *)v; - const char *repl = process_regexp(ed->hdr, val, ed->p); + const char *repl = process_regexp(ed->hdr, val, ed->r); if (repl == NULL) return 0; @@ -755,6 +765,14 @@ static int do_headers_fixup(request_rec *r, apr_table_t *headers, } apr_table_setn(headers, hdr->header, process_tags(hdr, r)); break; + case hdr_setifempty: + if (NULL == apr_table_get(headers, hdr->header)) { + 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: apr_table_unset(headers, hdr->header); break; @@ -767,7 +785,7 @@ static int do_headers_fixup(request_rec *r, apr_table_t *headers, case hdr_edit: case hdr_edit_r: if (!strcasecmp(hdr->header, "Content-Type") && r->content_type) { - const char *repl = process_regexp(hdr, r->content_type, r->pool); + const char *repl = process_regexp(hdr, r->content_type, r); if (repl == NULL) return 0; ap_set_content_type(r, repl); @@ -775,7 +793,7 @@ static int do_headers_fixup(request_rec *r, apr_table_t *headers, if (apr_table_get(headers, hdr->header)) { edit_do ed; - ed.p = r->pool; + ed.r = r; ed.hdr = hdr; ed.t = apr_table_make(r->pool, 5); if (!apr_table_do(edit_header, (void *) &ed, headers, @@ -785,6 +803,10 @@ static int do_headers_fixup(request_rec *r, apr_table_t *headers, apr_table_do(add_them_all, (void *) headers, ed.t, NULL); } break; + case hdr_note: + apr_table_setn(r->notes, process_tags(hdr, r), apr_table_get(headers, hdr->header)); + break; + } } return 1; diff --git a/modules/metadata/mod_mime_magic.c b/modules/metadata/mod_mime_magic.c index 03226aca..693ceca8 100644 --- a/modules/metadata/mod_mime_magic.c +++ b/modules/metadata/mod_mime_magic.c @@ -1973,7 +1973,7 @@ static int ascmagic(request_rec *r, unsigned char *buf, apr_size_t nbytes) { int has_escapes = 0; unsigned char *s; - char nbuf[HOWMANY + 1]; /* one extra for terminating '\0' */ + char nbuf[SMALL_HOWMANY + 1]; /* one extra for terminating '\0' */ char *token; const struct names *p; int small_nbytes; diff --git a/modules/proxy/ajp.h b/modules/proxy/ajp.h index c65ebe53..814ab0a2 100644 --- a/modules/proxy/ajp.h +++ b/modules/proxy/ajp.h @@ -382,7 +382,7 @@ apr_status_t ajp_msg_dump(apr_pool_t *pool, ajp_msg_t *msg, char *err, /** * Log an AJP message * - * @param request The current request + * @param r The current request * @param msg AJP Message to dump * @param err error string to display * @return APR_SUCCESS or error diff --git a/modules/proxy/fcgi_protocol.h b/modules/proxy/fcgi_protocol.h index a3cbcfca..e69de29b 100644 --- a/modules/proxy/fcgi_protocol.h +++ b/modules/proxy/fcgi_protocol.h @@ -1,108 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @file fcgi_protocol.h - * @brief FastCGI protocol defines - * - * @defgroup FCGI_defines FastCGI protocol definition - * @ingroup APACHE_INTERNAL - * @{ - */ - -#ifndef FCGI_PROTOCOL_H -#define FCGI_PROTOCOL_H - - -#define FCGI_VERSION 1 - -#define FCGI_BEGIN_REQUEST 1 -#define FCGI_ABORT_REQUEST 2 -#define FCGI_END_REQUEST 3 -#define FCGI_PARAMS 4 -#define FCGI_STDIN 5 -#define FCGI_STDOUT 6 -#define FCGI_STDERR 7 -#define FCGI_DATA 8 -#define FCGI_GET_VALUES 9 -#define FCGI_GET_VALUES_RESULT 10 -#define FCGI_UNKNOWN_TYPE 11 -#define FCGI_MAXTYPE (FCGI_UNKNOWN_TYPE) - -typedef struct { - unsigned char version; - unsigned char type; - unsigned char requestIdB1; - unsigned char requestIdB0; - unsigned char contentLengthB1; - unsigned char contentLengthB0; - unsigned char paddingLength; - unsigned char reserved; -} fcgi_header; - -#define FCGI_HDR_VERSION_OFFSET 0 -#define FCGI_HDR_TYPE_OFFSET 1 -#define FCGI_HDR_REQUEST_ID_B1_OFFSET 2 -#define FCGI_HDR_REQUEST_ID_B0_OFFSET 3 -#define FCGI_HDR_CONTENT_LEN_B1_OFFSET 4 -#define FCGI_HDR_CONTENT_LEN_B0_OFFSET 5 -#define FCGI_HDR_PADDING_LEN_OFFSET 6 -#define FCGI_HDR_RESERVED_OFFSET 7 - -#define FCGI_BRB_ROLEB1_OFFSET 0 -#define FCGI_BRB_ROLEB0_OFFSET 1 -#define FCGI_BRB_FLAGS_OFFSET 2 -#define FCGI_BRB_RESERVED0_OFFSET 3 -#define FCGI_BRB_RESERVED1_OFFSET 4 -#define FCGI_BRB_RESERVED2_OFFSET 5 -#define FCGI_BRB_RESERVED3_OFFSET 6 -#define FCGI_BRB_RESERVED4_OFFSET 7 - -/* - * Number of bytes in a fcgi_header. Future versions of the protocol - * will not reduce this number. - */ -#define FCGI_HEADER_LEN 8 - -/* - * Mask for flags component of FCGI_BeginRequestBody - */ -#define FCGI_KEEP_CONN 1 - -/* - * Values for role component of FCGI_BeginRequestBody - */ -#define FCGI_RESPONDER 1 -#define FCGI_AUTHORIZER 2 -#define FCGI_FILTER 3 - -typedef struct { - unsigned char roleB1; - unsigned char roleB0; - unsigned char flags; - unsigned char reserved[5]; -} fcgi_begin_request_body; - -/* - * Maximum size of the allowed environment. - */ -#define FCGI_MAX_ENV_SIZE 65535 - -/* #define FCGI_DUMP_ENV_VARS */ - - -#endif /* FCGI_PROTOCOL_H */ -/** @} */ diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c index 0ee2ff35..88ddb899 100644 --- a/modules/proxy/mod_proxy.c +++ b/modules/proxy/mod_proxy.c @@ -177,15 +177,17 @@ static const char *set_worker_param(apr_pool_t *p, else if (!strcasecmp(key, "route")) { /* Worker route. */ - if (strlen(val) >= PROXY_WORKER_MAX_ROUTE_SIZE) - return "Route length must be < 64 characters"; + if (strlen(val) >= sizeof(worker->s->route)) + return apr_psprintf(p, "Route length must be < %d characters", + (int)sizeof(worker->s->route)); PROXY_STRNCPY(worker->s->route, val); } else if (!strcasecmp(key, "redirect")) { /* Worker redirection route. */ - if (strlen(val) >= PROXY_WORKER_MAX_ROUTE_SIZE) - return "Redirect length must be < 64 characters"; + if (strlen(val) >= sizeof(worker->s->redirect)) + return apr_psprintf(p, "Redirect length must be < %d characters", + (int)sizeof(worker->s->redirect)); PROXY_STRNCPY(worker->s->redirect, val); } else if (!strcasecmp(key, "status")) { @@ -256,8 +258,9 @@ static const char *set_worker_param(apr_pool_t *p, worker->s->conn_timeout_set = 1; } else if (!strcasecmp(key, "flusher")) { - if (strlen(val) >= PROXY_WORKER_MAX_SCHEME_SIZE) - return "flusher name length must be < 16 characters"; + if (strlen(val) >= sizeof(worker->s->flusher)) + apr_psprintf(p, "flusher name length must be < %d characters", + (int)sizeof(worker->s->flusher)); PROXY_STRNCPY(worker->s->flusher, val); } else { @@ -280,8 +283,9 @@ static const char *set_balancer_param(proxy_server_conf *conf, * Set to something like JSESSIONID or * PHPSESSIONID, etc.., */ - if (strlen(val) > (PROXY_BALANCER_MAX_STICKY_SIZE-1)) - return "stickysession length must be < 64 characters"; + if (strlen(val) >= sizeof(balancer->s->sticky_path)) + apr_psprintf(p, "stickysession length must be < %d characters", + (int)sizeof(balancer->s->sticky_path)); PROXY_STRNCPY(balancer->s->sticky_path, val); PROXY_STRNCPY(balancer->s->sticky, val); @@ -1700,19 +1704,19 @@ static const char * New->name = apr_pstrdup(parms->pool, arg); New->hostaddr = NULL; - if (ap_proxy_is_ipaddr(New, parms->pool)) { + if (ap_proxy_is_ipaddr(New, parms->pool)) { #if DEBUGGING - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "Parsed addr %s", inet_ntoa(New->addr)); - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "Parsed mask %s", inet_ntoa(New->mask)); + ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, + "Parsed addr %s", inet_ntoa(New->addr)); + ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, + "Parsed mask %s", inet_ntoa(New->mask)); #endif - } - else if (ap_proxy_is_domainname(New, parms->pool)) { - ap_str_tolower(New->name); + } + else if (ap_proxy_is_domainname(New, parms->pool)) { + ap_str_tolower(New->name); #if DEBUGGING - ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, - "Parsed domain %s", New->name); + ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, + "Parsed domain %s", New->name); #endif } else if (ap_proxy_is_hostname(New, parms->pool)) { @@ -2435,7 +2439,7 @@ static int proxy_status_hook(request_rec *r, int flags) proxy_balancer *balancer = NULL; proxy_worker **worker = NULL; - if (flags & AP_STATUS_SHORT || conf->balancers->nelts == 0 || + if ((flags & AP_STATUS_SHORT) || conf->balancers->nelts == 0 || conf->proxy_status == status_off) return OK; diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h index 81fd14c1..aef8b209 100644 --- a/modules/proxy/mod_proxy.h +++ b/modules/proxy/mod_proxy.h @@ -723,11 +723,11 @@ PROXY_DECLARE(proxy_worker_shared *) ap_proxy_find_workershm(ap_slotmem_provider /** * Find the shm of the balancer as needed - * @param storage slotmem provider - * @param slot slotmem instance - * @param worker worker to find - * @param index pointer to index within slotmem of balancer - * @return pointer to shm of balancer, or NULL + * @param storage slotmem provider + * @param slot slotmem instance + * @param balancer balancer of shm to find + * @param index pointer to index within slotmem of balancer + * @return pointer to shm of balancer, or NULL */ PROXY_DECLARE(proxy_balancer_shared *) ap_proxy_find_balancershm(ap_slotmem_provider_t *storage, ap_slotmem_instance_t *slot, @@ -922,7 +922,7 @@ PROXY_DECLARE(int) ap_proxy_trans_match(request_rec *r, /** * Create a HTTP request header brigade, old_cl_val and old_te_val as required. - * @parama p pool + * @param p pool * @param header_brigade header brigade to use/fill * @param r request * @param p_conn proxy connection rec diff --git a/modules/proxy/mod_proxy_balancer.c b/modules/proxy/mod_proxy_balancer.c index 0f45be7a..5fd9e151 100644 --- a/modules/proxy/mod_proxy_balancer.c +++ b/modules/proxy/mod_proxy_balancer.c @@ -1463,7 +1463,14 @@ static int balancer_handler(request_rec *r) ap_rvputs(r, "<dl><dt>Server Version: ", ap_get_server_description(), "</dt>\n", NULL); ap_rvputs(r, "<dt>Server Built: ", - ap_get_server_built(), "\n</dt></dl>\n", NULL); + ap_get_server_built(), "</dt>\n", NULL); + ap_rvputs(r, "<dt>Balancer changes will ", conf->bal_persist ? "" : "NOT ", + "be persisted on restart.</dt>", NULL); + ap_rvputs(r, "<dt>Balancers are ", conf->inherit ? "" : "NOT ", + "inherited from main server.</dt>", NULL); + ap_rvputs(r, "<dt>ProxyPass settings are ", conf->ppinherit ? "" : "NOT ", + "inherited from main server.</dt>", NULL); + ap_rputs("</dl>\n", r); balancer = (proxy_balancer *)conf->balancers->elts; for (i = 0; i < conf->balancers->nelts; i++) { diff --git a/modules/proxy/mod_proxy_connect.c b/modules/proxy/mod_proxy_connect.c index b38edc91..9a1bfefb 100644 --- a/modules/proxy/mod_proxy_connect.c +++ b/modules/proxy/mod_proxy_connect.c @@ -220,7 +220,7 @@ static int proxy_connect_handler(request_rec *r, proxy_worker *worker, apr_uri_t uri; const char *connectname; - int connectport = 0; + apr_port_t connectport = 0; /* is this for us? */ if (r->method_number != M_CONNECT) { diff --git a/modules/proxy/mod_proxy_fcgi.c b/modules/proxy/mod_proxy_fcgi.c index 0f844163..ee702900 100644 --- a/modules/proxy/mod_proxy_fcgi.c +++ b/modules/proxy/mod_proxy_fcgi.c @@ -15,59 +15,12 @@ */ #include "mod_proxy.h" -#include "fcgi_protocol.h" +#include "util_fcgi.h" #include "util_script.h" module AP_MODULE_DECLARE_DATA proxy_fcgi_module; /* - * The below 3 functions serve to map the FCGI structs - * back and forth between an 8 byte array. We do this to avoid - * any potential padding issues when we send or read these - * structures. - * - * NOTE: These have specific internal knowledge of the - * layout of the fcgi_header and fcgi_begin_request_body - * structs! - */ -static void fcgi_header_to_array(fcgi_header *h, unsigned char a[]) -{ - a[FCGI_HDR_VERSION_OFFSET] = h->version; - a[FCGI_HDR_TYPE_OFFSET] = h->type; - a[FCGI_HDR_REQUEST_ID_B1_OFFSET] = h->requestIdB1; - a[FCGI_HDR_REQUEST_ID_B0_OFFSET] = h->requestIdB0; - a[FCGI_HDR_CONTENT_LEN_B1_OFFSET] = h->contentLengthB1; - a[FCGI_HDR_CONTENT_LEN_B0_OFFSET] = h->contentLengthB0; - a[FCGI_HDR_PADDING_LEN_OFFSET] = h->paddingLength; - a[FCGI_HDR_RESERVED_OFFSET] = h->reserved; -} - -static void fcgi_header_from_array(fcgi_header *h, unsigned char a[]) -{ - h->version = a[FCGI_HDR_VERSION_OFFSET]; - h->type = a[FCGI_HDR_TYPE_OFFSET]; - h->requestIdB1 = a[FCGI_HDR_REQUEST_ID_B1_OFFSET]; - h->requestIdB0 = a[FCGI_HDR_REQUEST_ID_B0_OFFSET]; - h->contentLengthB1 = a[FCGI_HDR_CONTENT_LEN_B1_OFFSET]; - h->contentLengthB0 = a[FCGI_HDR_CONTENT_LEN_B0_OFFSET]; - h->paddingLength = a[FCGI_HDR_PADDING_LEN_OFFSET]; - h->reserved = a[FCGI_HDR_RESERVED_OFFSET]; -} - -static void fcgi_begin_request_body_to_array(fcgi_begin_request_body *h, - unsigned char a[]) -{ - a[FCGI_BRB_ROLEB1_OFFSET] = h->roleB1; - a[FCGI_BRB_ROLEB0_OFFSET] = h->roleB0; - a[FCGI_BRB_FLAGS_OFFSET] = h->flags; - a[FCGI_BRB_RESERVED0_OFFSET] = h->reserved[0]; - a[FCGI_BRB_RESERVED1_OFFSET] = h->reserved[1]; - a[FCGI_BRB_RESERVED2_OFFSET] = h->reserved[2]; - a[FCGI_BRB_RESERVED3_OFFSET] = h->reserved[3]; - a[FCGI_BRB_RESERVED4_OFFSET] = h->reserved[4]; -} - -/* * Canonicalise http-like URLs. * scheme is the scheme for the URL * url is the URL starting with the first '/' @@ -129,33 +82,6 @@ static int proxy_fcgi_canon(request_rec *r, char *url) return OK; } -/* - * Fill in a fastcgi request header with the following type, request id, - * content length, and padding length. - * - * The header array must be at least FCGI_HEADER_LEN bytes long. - */ -static void fill_in_header(fcgi_header *header, - unsigned char type, - apr_uint16_t request_id, - apr_uint16_t content_len, - unsigned char padding_len) -{ - header->version = FCGI_VERSION; - - header->type = type; - - header->requestIdB1 = ((request_id >> 8) & 0xff); - header->requestIdB0 = ((request_id) & 0xff); - - header->contentLengthB1 = ((content_len >> 8) & 0xff); - header->contentLengthB0 = ((content_len) & 0xff); - - header->paddingLength = padding_len; - - header->reserved = 0; -} - /* Wrapper for apr_socket_sendv that handles updating the worker stats. */ static apr_status_t send_data(proxy_conn_rec *conn, struct iovec *vec, @@ -234,28 +160,43 @@ static apr_status_t get_data(proxy_conn_rec *conn, return rv; } -static apr_status_t send_begin_request(proxy_conn_rec *conn, int request_id) +static apr_status_t get_data_full(proxy_conn_rec *conn, + char *buffer, + apr_size_t buflen) +{ + apr_size_t readlen; + apr_size_t cumulative_len = 0; + apr_status_t rv; + + do { + readlen = buflen - cumulative_len; + rv = get_data(conn, buffer + cumulative_len, &readlen); + if (rv != APR_SUCCESS) { + return rv; + } + cumulative_len += readlen; + } while (cumulative_len < buflen); + + return APR_SUCCESS; +} + +static apr_status_t send_begin_request(proxy_conn_rec *conn, + apr_uint16_t request_id) { struct iovec vec[2]; - fcgi_header header; - unsigned char farray[FCGI_HEADER_LEN]; - fcgi_begin_request_body brb; - unsigned char abrb[FCGI_HEADER_LEN]; + ap_fcgi_header header; + unsigned char farray[AP_FCGI_HEADER_LEN]; + ap_fcgi_begin_request_body brb; + unsigned char abrb[AP_FCGI_HEADER_LEN]; apr_size_t len; - fill_in_header(&header, FCGI_BEGIN_REQUEST, request_id, sizeof(abrb), 0); + ap_fcgi_fill_in_header(&header, AP_FCGI_BEGIN_REQUEST, request_id, + sizeof(abrb), 0); - brb.roleB1 = ((FCGI_RESPONDER >> 8) & 0xff); - brb.roleB0 = ((FCGI_RESPONDER) & 0xff); - brb.flags = FCGI_KEEP_CONN; - brb.reserved[0] = 0; - brb.reserved[1] = 0; - brb.reserved[2] = 0; - brb.reserved[3] = 0; - brb.reserved[4] = 0; + ap_fcgi_fill_in_request_body(&brb, AP_FCGI_RESPONDER, AP_FCGI_KEEP_CONN); - fcgi_header_to_array(&header, farray); - fcgi_begin_request_body_to_array(&brb, abrb); + ap_fcgi_header_to_array(&header, farray); + ap_fcgi_begin_request_body_to_array(&brb, abrb); vec[0].iov_base = (void *)farray; vec[0].iov_len = sizeof(farray); @@ -266,26 +207,24 @@ static apr_status_t send_begin_request(proxy_conn_rec *conn, int request_id) } static apr_status_t send_environment(proxy_conn_rec *conn, request_rec *r, - int request_id) + apr_pool_t *temp_pool, + apr_uint16_t request_id) { const apr_array_header_t *envarr; const apr_table_entry_t *elts; struct iovec vec[2]; - fcgi_header header; - unsigned char farray[FCGI_HEADER_LEN]; - apr_size_t bodylen, envlen; - char *body, *itr; + ap_fcgi_header header; + unsigned char farray[AP_FCGI_HEADER_LEN]; + char *body; apr_status_t rv; - apr_size_t len; - int i, numenv; + apr_size_t avail_len, len, required_len; + int next_elem, starting_elem; ap_add_common_vars(r); ap_add_cgi_vars(r); /* XXX are there any FastCGI specific env vars we need to send? */ - bodylen = envlen = 0; - /* XXX mod_cgi/mod_cgid use ap_create_environment here, which fills in * the TZ value specially. We could use that, but it would mean * parsing the key/value pairs back OUT of the allocated env array, @@ -293,118 +232,75 @@ static apr_status_t send_environment(proxy_conn_rec *conn, request_rec *r, * place, which would suck. */ envarr = apr_table_elts(r->subprocess_env); - elts = (const apr_table_entry_t *) envarr->elts; - for (i = 0; i < envarr->nelts; ++i) { - apr_size_t keylen, vallen; - - if (! elts[i].key) { - continue; - } - - keylen = strlen(elts[i].key); - - if (keylen >> 7 == 0) { - envlen += 1; - } - else { - envlen += 4; - } - - envlen += keylen; - - vallen = strlen(elts[i].val); - #ifdef FCGI_DUMP_ENV_VARS - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01062) - "sending env var '%s' value '%s'", - elts[i].key, elts[i].val); -#endif - - if (vallen >> 7 == 0) { - envlen += 1; + { + int i; + + for (i = 0; i < envarr->nelts; ++i) { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01062) + "sending env var '%s' value '%s'", + elts[i].key, elts[i].val); } - else { - envlen += 4; - } - - envlen += vallen; + } +#endif - /* The cast of bodylen is safe since FCGI_MAX_ENV_SIZE is for sure an int */ - if (envlen > FCGI_MAX_ENV_SIZE) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01063) - "truncating environment to %d bytes and %d elements", - (int)bodylen, i); + /* Send envvars over in as many FastCGI records as it takes, */ + next_elem = 0; /* starting with the first one */ + + avail_len = 16 * 1024; /* our limit per record, which could have been up + * to AP_FCGI_MAX_CONTENT_LEN + */ + + while (next_elem < envarr->nelts) { + starting_elem = next_elem; + required_len = ap_fcgi_encoded_env_len(r->subprocess_env, + avail_len, + &next_elem); + + if (!required_len) { + if (next_elem < envarr->nelts) { + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, + APLOGNO(02536) "couldn't encode envvar '%s' in %" + APR_SIZE_T_FMT " bytes", + elts[next_elem].key, avail_len); + /* skip this envvar and continue */ + ++next_elem; + continue; + } + /* only an unused element at the end of the array */ break; } - bodylen = envlen; - } + body = apr_palloc(temp_pool, required_len); + rv = ap_fcgi_encode_env(r, r->subprocess_env, body, required_len, + &starting_elem); + /* we pre-compute, so we can't run out of space */ + ap_assert(rv == APR_SUCCESS); + /* compute and encode must be in sync */ + ap_assert(starting_elem == next_elem); - numenv = i; + ap_fcgi_fill_in_header(&header, AP_FCGI_PARAMS, request_id, + (apr_uint16_t)required_len, 0); + ap_fcgi_header_to_array(&header, farray); - body = apr_pcalloc(r->pool, bodylen); + vec[0].iov_base = (void *)farray; + vec[0].iov_len = sizeof(farray); + vec[1].iov_base = body; + vec[1].iov_len = required_len; - itr = body; + rv = send_data(conn, vec, 2, &len, 1); + apr_pool_clear(temp_pool); - for (i = 0; i < numenv; ++i) { - apr_size_t keylen, vallen; - - if (! elts[i].key) { - continue; - } - - keylen = strlen(elts[i].key); - - if (keylen >> 7 == 0) { - itr[0] = keylen & 0xff; - itr += 1; + if (rv) { + return rv; } - else { - itr[0] = ((keylen >> 24) & 0xff) | 0x80; - itr[1] = ((keylen >> 16) & 0xff); - itr[2] = ((keylen >> 8) & 0xff); - itr[3] = ((keylen) & 0xff); - itr += 4; - } - - vallen = strlen(elts[i].val); - - if (vallen >> 7 == 0) { - itr[0] = vallen & 0xff; - itr += 1; - } - else { - itr[0] = ((vallen >> 24) & 0xff) | 0x80; - itr[1] = ((vallen >> 16) & 0xff); - itr[2] = ((vallen >> 8) & 0xff); - itr[3] = ((vallen) & 0xff); - itr += 4; - } - - memcpy(itr, elts[i].key, keylen); - itr += keylen; - - memcpy(itr, elts[i].val, vallen); - itr += vallen; } - fill_in_header(&header, FCGI_PARAMS, request_id, bodylen, 0); - fcgi_header_to_array(&header, farray); - - vec[0].iov_base = (void *)farray; - vec[0].iov_len = sizeof(farray); - vec[1].iov_base = body; - vec[1].iov_len = bodylen; - - rv = send_data(conn, vec, 2, &len, 1); - if (rv) { - return rv; - } - - fill_in_header(&header, FCGI_PARAMS, request_id, 0, 0); - fcgi_header_to_array(&header, farray); + /* Envvars sent, so say we're done */ + ap_fcgi_fill_in_header(&header, AP_FCGI_PARAMS, request_id, 0, 0); + ap_fcgi_header_to_array(&header, farray); vec[0].iov_base = (void *)farray; vec[0].iov_len = sizeof(farray); @@ -481,69 +377,9 @@ static int handle_headers(request_rec *r, return 0; } -static void dump_header_to_log(request_rec *r, unsigned char fheader[], - apr_size_t length) -{ -#ifdef FCGI_DUMP_HEADERS - apr_size_t posn = 0; - char asc_line[20]; - char hex_line[60]; - int i = 0; - - memset(asc_line, 0, sizeof(asc_line)); - memset(hex_line, 0, sizeof(hex_line)); - - while (posn < length) { - unsigned char c = fheader[posn]; - - if (i >= 20) { - i = 0; - - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01064) - "HEADER: %s %s", asc_line, hex_line); - - memset(asc_line, 0, sizeof(asc_line)); - memset(hex_line, 0, sizeof(hex_line)); - } - - if (isprint(c)) { - asc_line[i] = c; - } - else { - asc_line[i] = '.'; - } - - if ((c >> 4) >= 10) { - hex_line[i * 3] = 'a' + ((c >> 4) - 10); - } - else { - hex_line[i * 3] = '0' + (c >> 4); - } - - if ((c & 0x0F) >= 10) { - hex_line[i * 3 + 1] = 'a' + ((c & 0x0F) - 10); - } - else { - hex_line[i * 3 + 1] = '0' + (c & 0xF); - } - - hex_line[i * 3 + 2] = ' '; - - i++; - posn++; - } - - if (i != 1) { - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01065) "HEADER: %s %s", - asc_line, hex_line); - } - - ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01066) "HEADER: -EOH-"); -#endif -} - static apr_status_t dispatch(proxy_conn_rec *conn, proxy_dir_conf *conf, - request_rec *r, int request_id) + request_rec *r, apr_pool_t *setaside_pool, + apr_uint16_t request_id) { apr_bucket_brigade *ib, *ob; int seen_end_of_headers = 0, done = 0; @@ -551,14 +387,11 @@ static apr_status_t dispatch(proxy_conn_rec *conn, proxy_dir_conf *conf, int script_error_status = HTTP_OK; conn_rec *c = r->connection; struct iovec vec[2]; - fcgi_header header; - unsigned char farray[FCGI_HEADER_LEN]; + ap_fcgi_header header; + unsigned char farray[AP_FCGI_HEADER_LEN]; apr_pollfd_t pfd; int header_state = HDR_STATE_READING_HEADERS; - apr_pool_t *setaside_pool; - - apr_pool_create(&setaside_pool, r->pool); - + pfd.desc_type = APR_POLL_SOCKET; pfd.desc.s = conn->sock; pfd.p = r->pool; @@ -568,15 +401,13 @@ static apr_status_t dispatch(proxy_conn_rec *conn, proxy_dir_conf *conf, ob = apr_brigade_create(r->pool, c->bucket_alloc); while (! done) { - apr_interval_time_t timeout = conn->worker->s->timeout; + apr_interval_time_t timeout; apr_size_t len; int n; /* We need SOME kind of timeout here, or virtually anything will * cause timeout errors. */ - if (! conn->worker->s->timeout_set) { - timeout = apr_time_from_sec(30); - } + apr_socket_timeout_get(conn->sock, &timeout); rv = apr_poll(&pfd, 1, &n, timeout); if (rv != APR_SUCCESS) { @@ -613,9 +444,9 @@ static apr_status_t dispatch(proxy_conn_rec *conn, proxy_dir_conf *conf, break; } - fill_in_header(&header, FCGI_STDIN, request_id, - (apr_uint16_t) writebuflen, 0); - fcgi_header_to_array(&header, farray); + ap_fcgi_fill_in_header(&header, AP_FCGI_STDIN, request_id, + (apr_uint16_t) writebuflen, 0); + ap_fcgi_header_to_array(&header, farray); vec[nvec].iov_base = (void *)farray; vec[nvec].iov_len = sizeof(farray); @@ -634,9 +465,10 @@ static apr_status_t dispatch(proxy_conn_rec *conn, proxy_dir_conf *conf, if (last_stdin) { pfd.reqevents = APR_POLLIN; /* Done with input data */ - if (writebuflen) { /* empty FCGI_STDIN not already sent? */ - fill_in_header(&header, FCGI_STDIN, request_id, 0, 0); - fcgi_header_to_array(&header, farray); + if (writebuflen) { /* empty AP_FCGI_STDIN not already sent? */ + ap_fcgi_fill_in_header(&header, AP_FCGI_STDIN, request_id, + 0, 0); + ap_fcgi_header_to_array(&header, farray); vec[0].iov_base = (void *)farray; vec[0].iov_len = sizeof(farray); @@ -652,47 +484,37 @@ static apr_status_t dispatch(proxy_conn_rec *conn, proxy_dir_conf *conf, * the headers, even if we fill the entire length in the recv. */ char readbuf[AP_IOBUFSIZE + 1]; apr_size_t readbuflen; - apr_size_t clen; - int rid, type; + apr_uint16_t clen, rid; apr_bucket *b; - char plen; + unsigned char plen; + unsigned char type, version; memset(readbuf, 0, sizeof(readbuf)); memset(farray, 0, sizeof(farray)); /* First, we grab the header... */ - readbuflen = FCGI_HEADER_LEN; - - rv = get_data(conn, (char *) farray, &readbuflen); + rv = get_data_full(conn, (char *) farray, AP_FCGI_HEADER_LEN); if (rv != APR_SUCCESS) { - break; - } - - dump_header_to_log(r, farray, readbuflen); - - if (readbuflen != FCGI_HEADER_LEN) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01067) - "Failed to read entire header " - "got %" APR_SIZE_T_FMT " wanted %d", - readbuflen, FCGI_HEADER_LEN); - rv = APR_EINVAL; + "Failed to read FastCGI header"); break; } - fcgi_header_from_array(&header, farray); +#ifdef FCGI_DUMP_HEADERS + ap_log_rdata(APLOG_MARK, APLOG_DEBUG, r, "FastCGI header", + farray, AP_FCGI_HEADER_LEN, 0); +#endif + + ap_fcgi_header_fields_from_array(&version, &type, &rid, + &clen, &plen, farray); - if (header.version != FCGI_VERSION) { + if (version != AP_FCGI_VERSION_1) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01068) "Got bogus version %d", (int) header.version); rv = APR_EINVAL; break; } - type = header.type; - - rid = header.requestIdB1 << 8; - rid |= header.requestIdB0; - if (rid != request_id) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01069) "Got bogus rid %d, expected %d", @@ -701,11 +523,6 @@ static apr_status_t dispatch(proxy_conn_rec *conn, proxy_dir_conf *conf, break; } - clen = header.contentLengthB1 << 8; - clen |= header.contentLengthB0; - - plen = header.paddingLength; - recv_again: if (clen > sizeof(readbuf) - 1) { readbuflen = sizeof(readbuf) - 1; @@ -725,7 +542,7 @@ recv_again: } switch (type) { - case FCGI_STDOUT: + case AP_FCGI_STDOUT: if (clen != 0) { b = apr_bucket_transient_create(readbuf, readbuflen, @@ -825,7 +642,7 @@ recv_again: } break; - case FCGI_STDERR: + case AP_FCGI_STDERR: /* TODO: Should probably clean up this logging a bit... */ if (clen) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01071) @@ -838,7 +655,7 @@ recv_again: } break; - case FCGI_END_REQUEST: + case AP_FCGI_END_REQUEST: done = 1; break; @@ -849,10 +666,10 @@ recv_again: } if (plen) { - readbuflen = plen; - - rv = get_data(conn, readbuf, &readbuflen); + rv = get_data_full(conn, readbuf, plen); if (rv != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, + APLOGNO(02537) "Error occurred reading padding"); break; } } @@ -884,10 +701,11 @@ static int fcgi_do_request(apr_pool_t *p, request_rec *r, * multiple requests to the same FastCGI connection, but * we don't support that, and always use a value of '1' to * keep things simple. */ - int request_id = 1; + apr_uint16_t request_id = 1; apr_status_t rv; + apr_pool_t *temp_pool; - /* Step 1: Send FCGI_BEGIN_REQUEST */ + /* Step 1: Send AP_FCGI_BEGIN_REQUEST */ rv = send_begin_request(conn, request_id); if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01073) @@ -896,8 +714,10 @@ static int fcgi_do_request(apr_pool_t *p, request_rec *r, return HTTP_SERVICE_UNAVAILABLE; } + apr_pool_create(&temp_pool, r->pool); + /* Step 2: Send Environment via FCGI_PARAMS */ - rv = send_environment(conn, r, request_id); + rv = send_environment(conn, r, temp_pool, request_id); if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01074) "Failed writing Environment to %s:", server_portstr); @@ -906,7 +726,7 @@ static int fcgi_do_request(apr_pool_t *p, request_rec *r, } /* Step 3: Read records from the back end server and handle them. */ - rv = dispatch(conn, conf, r, request_id); + rv = dispatch(conn, conf, r, temp_pool, request_id); if (rv != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01075) "Error dispatching request to %s:", server_portstr); diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c index cffad2e7..714014de 100644 --- a/modules/proxy/mod_proxy_http.c +++ b/modules/proxy/mod_proxy_http.c @@ -1873,7 +1873,7 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker, return DECLINED; if ((u - url) > 14) return HTTP_BAD_REQUEST; - scheme = apr_pstrndup(p, url, u - url); + scheme = apr_pstrmemdup(p, url, u - url); /* scheme is lowercase */ ap_str_tolower(scheme); /* is it for us? */ diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c index 67dc9394..d3dd0686 100644 --- a/modules/proxy/proxy_util.c +++ b/modules/proxy/proxy_util.c @@ -309,7 +309,7 @@ PROXY_DECLARE(char *) url = ""; } else { - *(url++) = '\0'; /* skip seperating '/' */ + *(url++) = '\0'; /* skip separating '/' */ } /* find _last_ '@' since it might occur in user/password part */ @@ -386,7 +386,7 @@ PROXY_DECLARE(int) ap_proxyerror(request_rec *r, int statuscode, const char *mes static const char * proxy_get_host_of_request(request_rec *r) { - char *url, *user = NULL, *password = NULL, *err, *host; + char *url, *user = NULL, *password = NULL, *err, *host = NULL; apr_port_t port; if (r->hostname != NULL) { @@ -1080,7 +1080,6 @@ PROXY_DECLARE(proxy_balancer *) ap_proxy_get_balancer(apr_pool_t *p, int i; proxy_hashes hash; - ap_str_tolower(uri); c = strchr(uri, ':'); if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0') { return NULL; @@ -1089,6 +1088,7 @@ PROXY_DECLARE(proxy_balancer *) ap_proxy_get_balancer(apr_pool_t *p, if ((c = strchr(c + 3, '/'))) { *c = '\0'; } + ap_str_tolower(uri); hash.def = ap_proxy_hashfunc(uri, PROXY_HASHFUNC_DEFAULT); hash.fnv = ap_proxy_hashfunc(uri, PROXY_HASHFUNC_FNV); balancer = (proxy_balancer *)conf->balancers->elts; @@ -2132,34 +2132,46 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, conn->port = uri->port; } socket_cleanup(conn); - err = apr_sockaddr_info_get(&(conn->addr), - conn->hostname, APR_UNSPEC, - conn->port, 0, - conn->pool); - } - else if (!worker->cp->addr) { - if ((err = PROXY_THREAD_LOCK(worker)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, err, r, APLOGNO(00945) "lock"); - return HTTP_INTERNAL_SERVER_ERROR; + if (!worker->s->is_address_reusable || worker->s->disablereuse) { + /* + * Only do a lookup if we should not reuse the backend address. + * Otherwise we will look it up once for the worker. + */ + err = apr_sockaddr_info_get(&(conn->addr), + conn->hostname, APR_UNSPEC, + conn->port, 0, + conn->pool); } - + } + if (worker->s->is_address_reusable && !worker->s->disablereuse) { /* - * Worker can have the single constant backend adress. - * The single DNS lookup is used once per worker. - * If dynamic change is needed then set the addr to NULL - * inside dynamic config to force the lookup. + * Looking up the backend address for the worker only makes sense if + * we can reuse the address. */ - err = apr_sockaddr_info_get(&(worker->cp->addr), - conn->hostname, APR_UNSPEC, - conn->port, 0, - worker->cp->pool); - conn->addr = worker->cp->addr; - if ((uerr = PROXY_THREAD_UNLOCK(worker)) != APR_SUCCESS) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, uerr, r, APLOGNO(00946) "unlock"); + if (!worker->cp->addr) { + if ((err = PROXY_THREAD_LOCK(worker)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, err, r, APLOGNO(00945) "lock"); + return HTTP_INTERNAL_SERVER_ERROR; + } + + /* + * Worker can have the single constant backend adress. + * The single DNS lookup is used once per worker. + * If dynamic change is needed then set the addr to NULL + * inside dynamic config to force the lookup. + */ + err = apr_sockaddr_info_get(&(worker->cp->addr), + conn->hostname, APR_UNSPEC, + conn->port, 0, + worker->cp->pool); + conn->addr = worker->cp->addr; + if ((uerr = PROXY_THREAD_UNLOCK(worker)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, uerr, r, APLOGNO(00946) "unlock"); + } + } + else { + conn->addr = worker->cp->addr; } - } - else { - conn->addr = worker->cp->addr; } /* Close a possible existing socket if we are told to do so */ if (conn->close) { diff --git a/modules/session/mod_session.c b/modules/session/mod_session.c index 7213eb3c..89c80747 100644 --- a/modules/session/mod_session.c +++ b/modules/session/mod_session.c @@ -144,9 +144,11 @@ static apr_status_t ap_session_load(request_rec * r, session_rec ** z) } } - /* make sure the expiry is set, if present */ - if (!zz->expiry && dconf->maxage) { - zz->expiry = now + dconf->maxage * APR_USEC_PER_SEC; + /* make sure the expiry and maxage are set, if present */ + if (dconf->maxage) { + if (!zz->expiry) { + zz->expiry = now + dconf->maxage * APR_USEC_PER_SEC; + } zz->maxage = dconf->maxage; } @@ -194,6 +196,11 @@ static apr_status_t ap_session_save(request_rec * r, session_rec * z) z->maxage = dconf->maxage; } + /* reset the expiry before saving if present */ + if (z->dirty && z->maxage) { + z->expiry = now + z->maxage * APR_USEC_PER_SEC; + } + /* encode the session */ rv = ap_run_session_encode(r, z); if (OK != rv) { @@ -443,6 +450,8 @@ static apr_status_t session_output_filter(ap_filter_t * f, override = apr_table_get(r->headers_out, conf->header); } if (override) { + apr_table_unset(r->err_headers_out, conf->header); + apr_table_unset(r->headers_out, conf->header); z->encoded = override; z->dirty = 1; session_identity_decode(r, z); diff --git a/modules/session/mod_session_crypto.c b/modules/session/mod_session_crypto.c index 03dbba61..984a0487 100644 --- a/modules/session/mod_session_crypto.c +++ b/modules/session/mod_session_crypto.c @@ -534,11 +534,41 @@ static const char *set_crypto_driver(cmd_parms * cmd, void *config, const char * static const char *set_crypto_passphrase(cmd_parms * cmd, void *config, const char *arg) { + int arglen = strlen(arg); + char **argv; + char *result; const char **passphrase; session_crypto_dir_conf *dconf = (session_crypto_dir_conf *) config; passphrase = apr_array_push(dconf->passphrases); - *passphrase = arg; + + if ((arglen > 5) && strncmp(arg, "exec:", 5) == 0) { + if (apr_tokenize_to_argv(arg+5, &argv, cmd->temp_pool) != APR_SUCCESS) { + return apr_pstrcat(cmd->pool, + "Unable to parse exec arguments from ", + arg+5, NULL); + } + argv[0] = ap_server_root_relative(cmd->temp_pool, argv[0]); + + if (!argv[0]) { + return apr_pstrcat(cmd->pool, + "Invalid SessionCryptoPassphrase exec location:", + arg+5, NULL); + } + result = ap_get_exec_line(cmd->pool, + (const char*)argv[0], (const char * const *)argv); + + if(!result) { + return apr_pstrcat(cmd->pool, + "Unable to get bind password from exec of ", + arg+5, NULL); + } + *passphrase = result; + } + else { + *passphrase = arg; + } + dconf->passphrases_set = 1; return NULL; diff --git a/modules/slotmem/mod_slotmem_shm.c b/modules/slotmem/mod_slotmem_shm.c index aac96e23..1f7e557c 100644 --- a/modules/slotmem/mod_slotmem_shm.c +++ b/modules/slotmem/mod_slotmem_shm.c @@ -178,6 +178,7 @@ static void store_slotmem(ap_slotmem_instance_t *slotmem) apr_status_t rv; apr_size_t nbytes; const char *storename; + unsigned char digest[APR_MD5_DIGESTSIZE]; storename = slotmem_filename(slotmem->gpool, slotmem->name, 1); @@ -200,20 +201,27 @@ static void store_slotmem(ap_slotmem_instance_t *slotmem) } nbytes = (slotmem->desc.size * slotmem->desc.num) + (slotmem->desc.num * sizeof(char)) + AP_UNSIGNEDINT_OFFSET; - /* XXX: Error handling */ - apr_file_write_full(fp, slotmem->persist, nbytes, NULL); + apr_md5(digest, slotmem->persist, nbytes); + rv = apr_file_write_full(fp, slotmem->persist, nbytes, NULL); + if (rv == APR_SUCCESS) { + rv = apr_file_write_full(fp, digest, APR_MD5_DIGESTSIZE, NULL); + } apr_file_close(fp); + if (rv != APR_SUCCESS) { + apr_file_remove(storename, slotmem->gpool); + } } } -/* should be apr_status_t really */ -static void restore_slotmem(void *ptr, const char *name, apr_size_t size, - apr_pool_t *pool) +static apr_status_t restore_slotmem(void *ptr, const char *name, apr_size_t size, + apr_pool_t *pool) { const char *storename; apr_file_t *fp; apr_size_t nbytes = size; - apr_status_t rv; + apr_status_t rv = APR_SUCCESS; + unsigned char digest[APR_MD5_DIGESTSIZE]; + unsigned char digest2[APR_MD5_DIGESTSIZE]; storename = slotmem_filename(pool, name, 1); @@ -224,20 +232,42 @@ static void restore_slotmem(void *ptr, const char *name, apr_size_t size, rv = apr_file_open(&fp, storename, APR_READ | APR_WRITE, APR_OS_DEFAULT, pool); if (rv == APR_SUCCESS) { - apr_finfo_t fi; - if (apr_file_info_get(&fi, APR_FINFO_SIZE, fp) == APR_SUCCESS) { - if (fi.size == nbytes) { - apr_file_read(fp, ptr, &nbytes); + rv = apr_file_read(fp, ptr, &nbytes); + if ((rv == APR_SUCCESS || rv == APR_EOF) && nbytes == size) { + rv = APR_SUCCESS; /* for successful return @ EOF */ + /* + * if at EOF, don't bother checking md5 + * - backwards compatibility + * */ + if (apr_file_eof(fp) != APR_EOF) { + apr_size_t ds = APR_MD5_DIGESTSIZE; + rv = apr_file_read(fp, digest, &ds); + if ((rv == APR_SUCCESS || rv == APR_EOF) && + ds == APR_MD5_DIGESTSIZE) { + rv = APR_SUCCESS; + apr_md5(digest2, ptr, nbytes); + if (memcmp(digest, digest2, APR_MD5_DIGESTSIZE)) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, + APLOGNO(02551) "bad md5 match"); + rv = APR_EGENERAL; + } + } } else { - apr_file_close(fp); - apr_file_remove(storename, pool); - return; + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, + APLOGNO(02552) "at EOF... bypassing md5 match check (old persist file?)"); } } + else if (nbytes != size) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, + APLOGNO(02553) "Expected %" APR_SIZE_T_FMT ": Read %" APR_SIZE_T_FMT, + size, nbytes); + rv = APR_EGENERAL; + } apr_file_close(fp); } } + return rv; } static apr_status_t cleanup_slotmem(void *param) @@ -251,7 +281,12 @@ static apr_status_t cleanup_slotmem(void *param) store_slotmem(next); } if (next->fbased) { + const char *name; apr_shm_remove(next->name, next->gpool); + name = slotmem_filename(next->gpool, next->name, 0); + if (name) { + apr_file_remove(name, next->gpool); + } } apr_shm_destroy((apr_shm_t *)next->shm); next = next->next; @@ -390,8 +425,16 @@ static apr_status_t slotmem_create(ap_slotmem_instance_t **new, * sense if the restore fails? Any? */ if (type & AP_SLOTMEM_TYPE_PERSIST) { - restore_slotmem(ptr, fname, dsize, pool); - restored = 1; + rv = restore_slotmem(ptr, fname, dsize, pool); + if (rv == APR_SUCCESS) { + restored = 1; + } + else { + /* just in case, re-zero */ + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, + APLOGNO(02554) "could not restore %s", fname); + memset(ptr, 0, dsize); + } } } diff --git a/modules/ssl/config.m4 b/modules/ssl/config.m4 index 1b589d81..45eeb43d 100644 --- a/modules/ssl/config.m4 +++ b/modules/ssl/config.m4 @@ -20,7 +20,6 @@ dnl # list of module object files ssl_objs="dnl mod_ssl.lo dnl ssl_engine_config.lo dnl -ssl_engine_dh.lo dnl ssl_engine_init.lo dnl ssl_engine_io.lo dnl ssl_engine_kernel.lo dnl diff --git a/modules/ssl/mod_ssl.c b/modules/ssl/mod_ssl.c index a43f656e..f0499405 100644 --- a/modules/ssl/mod_ssl.c +++ b/modules/ssl/mod_ssl.c @@ -139,7 +139,7 @@ static const command_rec ssl_config_cmds[] = { SSL_CMD_SRV(HonorCipherOrder, FLAG, "Use the server's cipher ordering preference") SSL_CMD_SRV(Compression, FLAG, - "Enable SSL level compression" + "Enable SSL level compression " "(`on', `off')") SSL_CMD_SRV(InsecureRenegotiation, FLAG, "Enable support for insecure renegotiation") @@ -148,7 +148,7 @@ static const command_rec ssl_config_cmds[] = { SSL_CMD_SRV(StrictSNIVHostCheck, FLAG, "Strict SNI virtual host checking") -#ifndef OPENSSL_NO_SRP +#ifdef HAVE_SRP SSL_CMD_SRV(SRPVerifierFile, TAKE1, "SRP verifier file " "('/path/to/file' - created by srptool)") @@ -471,15 +471,6 @@ int ssl_init_ssl_connection(conn_rec *c, request_rec *r) sslconn->ssl = ssl; - /* - * Configure callbacks for SSL connection - */ - SSL_set_tmp_rsa_callback(ssl, ssl_callback_TmpRSA); - SSL_set_tmp_dh_callback(ssl, ssl_callback_TmpDH); -#ifndef OPENSSL_NO_EC - SSL_set_tmp_ecdh_callback(ssl, ssl_callback_TmpECDH); -#endif - SSL_set_verify_result(ssl, X509_V_OK); ssl_io_filter_init(c, r, ssl); diff --git a/modules/ssl/mod_ssl.dsp b/modules/ssl/mod_ssl.dsp index fc86a7b6..58b55456 100644 --- a/modules/ssl/mod_ssl.dsp +++ b/modules/ssl/mod_ssl.dsp @@ -112,10 +112,6 @@ SOURCE=.\ssl_engine_config.c # End Source File # Begin Source File -SOURCE=.\ssl_engine_dh.c -# End Source File -# Begin Source File - SOURCE=.\ssl_engine_init.c # End Source File # Begin Source File diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c index 1ab5bf37..f519151e 100644 --- a/modules/ssl/ssl_engine_config.c +++ b/modules/ssl/ssl_engine_config.c @@ -75,8 +75,6 @@ SSLModConfigRec *ssl_config_global_create(server_rec *s) mc->stapling_mutex = NULL; #endif - memset(mc->pTmpKeys, 0, sizeof(mc->pTmpKeys)); - apr_pool_userdata_set(mc, SSL_MOD_CONFIG_KEY, apr_pool_cleanup_null, pool); @@ -150,7 +148,7 @@ static void modssl_ctx_init(modssl_ctx_t *mctx) mctx->stapling_force_url = NULL; #endif -#ifndef OPENSSL_NO_SRP +#ifdef HAVE_SRP mctx->srp_vfile = NULL; mctx->srp_unknown_user_seed = NULL; mctx->srp_vbase = NULL; @@ -208,7 +206,7 @@ static SSLSrvConfigRec *ssl_config_server_new(apr_pool_t *p) sc->proxy_ssl_check_peer_expire = SSL_ENABLED_UNSET; sc->proxy_ssl_check_peer_cn = SSL_ENABLED_UNSET; sc->proxy_ssl_check_peer_name = SSL_ENABLED_UNSET; -#ifndef OPENSSL_NO_TLSEXT +#ifdef HAVE_TLSEXT sc->strict_sni_vhost_check = SSL_ENABLED_UNSET; #endif #ifdef HAVE_FIPS @@ -282,7 +280,7 @@ static void modssl_ctx_cfg_merge(modssl_ctx_t *base, cfgMerge(stapling_force_url, NULL); #endif -#ifndef OPENSSL_NO_SRP +#ifdef HAVE_SRP cfgMergeString(srp_vfile); cfgMergeString(srp_unknown_user_seed); #endif @@ -338,7 +336,7 @@ void *ssl_config_server_merge(apr_pool_t *p, void *basev, void *addv) cfgMerge(proxy_ssl_check_peer_expire, SSL_ENABLED_UNSET); cfgMerge(proxy_ssl_check_peer_cn, SSL_ENABLED_UNSET); cfgMerge(proxy_ssl_check_peer_name, SSL_ENABLED_UNSET); -#ifndef OPENSSL_NO_TLSEXT +#ifdef HAVE_TLSEXT cfgMerge(strict_sni_vhost_check, SSL_ENABLED_UNSET); #endif #ifdef HAVE_FIPS @@ -601,7 +599,7 @@ const char *ssl_cmd_SSLEngine(cmd_parms *cmd, void *dcfg, const char *arg) if (!strcasecmp(arg, "On")) { sc->enabled = SSL_ENABLED_TRUE; - return NULL; + return NULL; } else if (!strcasecmp(arg, "Off")) { sc->enabled = SSL_ENABLED_FALSE; @@ -645,6 +643,9 @@ const char *ssl_cmd_SSLCipherSuite(cmd_parms *cmd, SSLSrvConfigRec *sc = mySrvConfig(cmd->server); SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; + /* always disable null and export ciphers */ + arg = apr_pstrcat(cmd->pool, "!aNULL:!eNULL:!EXP:", arg, NULL); + if (cmd->path) { dc->szCipherSuite = arg; } @@ -1384,6 +1385,9 @@ const char *ssl_cmd_SSLProxyCipherSuite(cmd_parms *cmd, { SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + /* always disable null and export ciphers */ + arg = apr_pstrcat(cmd->pool, "!aNULL:!eNULL:!EXP:", arg, NULL); + sc->proxy->auth.cipher_suite = arg; return NULL; @@ -1645,7 +1649,7 @@ const char *ssl_cmd_SSLProxyCheckPeerName(cmd_parms *cmd, void *dcfg, int flag) const char *ssl_cmd_SSLStrictSNIVHostCheck(cmd_parms *cmd, void *dcfg, int flag) { -#ifndef OPENSSL_NO_TLSEXT +#ifdef HAVE_TLSEXT SSLSrvConfigRec *sc = mySrvConfig(cmd->server); sc->strict_sni_vhost_check = flag ? SSL_ENABLED_TRUE : SSL_ENABLED_FALSE; @@ -1804,7 +1808,7 @@ const char *ssl_cmd_SSLStaplingForceURL(cmd_parms *cmd, void *dcfg, #endif /* HAVE_OCSP_STAPLING */ -#ifndef OPENSSL_NO_SRP +#ifdef HAVE_SRP const char *ssl_cmd_SSLSRPVerifierFile(cmd_parms *cmd, void *dcfg, const char *arg) @@ -1828,7 +1832,7 @@ const char *ssl_cmd_SSLSRPUnknownUserSeed(cmd_parms *cmd, void *dcfg, return NULL; } -#endif /* OPENSSL_NO_SRP */ +#endif /* HAVE_SRP */ void ssl_hook_ConfigTest(apr_pool_t *pconf, server_rec *s) { diff --git a/modules/ssl/ssl_engine_dh.c b/modules/ssl/ssl_engine_dh.c deleted file mode 100644 index 0cc74555..00000000 --- a/modules/ssl/ssl_engine_dh.c +++ /dev/null @@ -1,244 +0,0 @@ -#if 0 -=pod -#endif - -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* _ _ - * _ __ ___ ___ __| | ___ ___| | mod_ssl - * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL - * | | | | | | (_) | (_| | \__ \__ \ | - * |_| |_| |_|\___/ \__,_|___|___/___/_| - * |_____| - * ssl_engine_dh.c - * Diffie-Hellman Built-in Temporary Parameters - */ - -#include "ssl_private.h" - -/* ----BEGIN GENERATED SECTION-------- */ - -/* -** Diffie-Hellman-Parameters: (512 bit) -** prime: -** 00:9f:db:8b:8a:00:45:44:f0:04:5f:17:37:d0:ba: -** 2e:0b:27:4c:df:1a:9f:58:82:18:fb:43:53:16:a1: -** 6e:37:41:71:fd:19:d8:d8:f3:7c:39:bf:86:3f:d6: -** 0e:3e:30:06:80:a3:03:0c:6e:4c:37:57:d0:8f:70: -** e6:aa:87:10:33 -** generator: 2 (0x2) -** Diffie-Hellman-Parameters: (1024 bit) -** prime: -** 00:d6:7d:e4:40:cb:bb:dc:19:36:d6:93:d3:4a:fd: -** 0a:d5:0c:84:d2:39:a4:5f:52:0b:b8:81:74:cb:98: -** bc:e9:51:84:9f:91:2e:63:9c:72:fb:13:b4:b4:d7: -** 17:7e:16:d5:5a:c1:79:ba:42:0b:2a:29:fe:32:4a: -** 46:7a:63:5e:81:ff:59:01:37:7b:ed:dc:fd:33:16: -** 8a:46:1a:ad:3b:72:da:e8:86:00:78:04:5b:07:a7: -** db:ca:78:74:08:7d:15:10:ea:9f:cc:9d:dd:33:05: -** 07:dd:62:db:88:ae:aa:74:7d:e0:f4:d6:e2:bd:68: -** b0:e7:39:3e:0f:24:21:8e:b3 -** generator: 2 (0x2) -*/ - -static unsigned char dh512_p[] = { - 0x9F, 0xDB, 0x8B, 0x8A, 0x00, 0x45, 0x44, 0xF0, 0x04, 0x5F, 0x17, 0x37, - 0xD0, 0xBA, 0x2E, 0x0B, 0x27, 0x4C, 0xDF, 0x1A, 0x9F, 0x58, 0x82, 0x18, - 0xFB, 0x43, 0x53, 0x16, 0xA1, 0x6E, 0x37, 0x41, 0x71, 0xFD, 0x19, 0xD8, - 0xD8, 0xF3, 0x7C, 0x39, 0xBF, 0x86, 0x3F, 0xD6, 0x0E, 0x3E, 0x30, 0x06, - 0x80, 0xA3, 0x03, 0x0C, 0x6E, 0x4C, 0x37, 0x57, 0xD0, 0x8F, 0x70, 0xE6, - 0xAA, 0x87, 0x10, 0x33, -}; -static unsigned char dh512_g[] = { - 0x02, -}; - -static DH *get_dh512(void) -{ - DH *dh; - - if (!(dh = DH_new())) { - return NULL; - } - - dh->p = BN_bin2bn(dh512_p, sizeof(dh512_p), NULL); - dh->g = BN_bin2bn(dh512_g, sizeof(dh512_g), NULL); - if (!(dh->p && dh->g)) { - DH_free(dh); - return NULL; - } - - return dh; -} - -static unsigned char dh1024_p[] = { - 0xD6, 0x7D, 0xE4, 0x40, 0xCB, 0xBB, 0xDC, 0x19, 0x36, 0xD6, 0x93, 0xD3, - 0x4A, 0xFD, 0x0A, 0xD5, 0x0C, 0x84, 0xD2, 0x39, 0xA4, 0x5F, 0x52, 0x0B, - 0xB8, 0x81, 0x74, 0xCB, 0x98, 0xBC, 0xE9, 0x51, 0x84, 0x9F, 0x91, 0x2E, - 0x63, 0x9C, 0x72, 0xFB, 0x13, 0xB4, 0xB4, 0xD7, 0x17, 0x7E, 0x16, 0xD5, - 0x5A, 0xC1, 0x79, 0xBA, 0x42, 0x0B, 0x2A, 0x29, 0xFE, 0x32, 0x4A, 0x46, - 0x7A, 0x63, 0x5E, 0x81, 0xFF, 0x59, 0x01, 0x37, 0x7B, 0xED, 0xDC, 0xFD, - 0x33, 0x16, 0x8A, 0x46, 0x1A, 0xAD, 0x3B, 0x72, 0xDA, 0xE8, 0x86, 0x00, - 0x78, 0x04, 0x5B, 0x07, 0xA7, 0xDB, 0xCA, 0x78, 0x74, 0x08, 0x7D, 0x15, - 0x10, 0xEA, 0x9F, 0xCC, 0x9D, 0xDD, 0x33, 0x05, 0x07, 0xDD, 0x62, 0xDB, - 0x88, 0xAE, 0xAA, 0x74, 0x7D, 0xE0, 0xF4, 0xD6, 0xE2, 0xBD, 0x68, 0xB0, - 0xE7, 0x39, 0x3E, 0x0F, 0x24, 0x21, 0x8E, 0xB3, -}; -static unsigned char dh1024_g[] = { - 0x02, -}; - -static DH *get_dh1024(void) -{ - DH *dh; - - if (!(dh = DH_new())) { - return NULL; - } - - dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL); - dh->g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL); - if (!(dh->p && dh->g)) { - DH_free(dh); - return NULL; - } - - return dh; -} - -/* ----END GENERATED SECTION---------- */ - -DH *ssl_dh_GetTmpParam(int nKeyLen) -{ - DH *dh; - - if (nKeyLen == 512) - dh = get_dh512(); - else if (nKeyLen == 1024) - dh = get_dh1024(); - else - dh = get_dh1024(); - return dh; -} - -DH *ssl_dh_GetParamFromFile(char *file) -{ - DH *dh = NULL; - BIO *bio; - - if ((bio = BIO_new_file(file, "r")) == NULL) - return NULL; - dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); - BIO_free(bio); - return (dh); -} - -/* -=cut -## -## Embedded Perl script for generating the temporary DH parameters -## - -require 5.003; -use strict; - -# configuration -my $file = $0; -my $begin = '----BEGIN GENERATED SECTION--------'; -my $end = '----END GENERATED SECTION----------'; - -# read ourself and keep a backup -open(FP, "<$file") || die; -my $source = ''; -$source .= $_ while (<FP>); -close(FP); -open(FP, ">$file.bak") || die; -print FP $source; -close(FP); - -# generate the DH parameters -print "1. Generate 512 and 1024 bit Diffie-Hellman parameters (p, g)\n"; -my $rand = ''; -foreach $file (qw(/var/log/messages /var/adm/messages - /kernel /vmunix /vmlinuz /etc/hosts /etc/resolv.conf)) { - if (-f $file) { - $rand = $file if ($rand eq ''); - $rand .= ":$file" if ($rand ne ''); - } -} -$rand = "-rand $rand" if ($rand ne ''); -system("openssl gendh $rand -out dh512.pem 512"); -system("openssl gendh $rand -out dh1024.pem 1024"); - -# generate DH param info -my $dhinfo = ''; -open(FP, "openssl dh -noout -text -in dh512.pem |") || die; -$dhinfo .= $_ while (<FP>); -close(FP); -open(FP, "openssl dh -noout -text -in dh1024.pem |") || die; -$dhinfo .= $_ while (<FP>); -close(FP); -$dhinfo =~ s|^|** |mg; -$dhinfo = "\n\/\*\n$dhinfo\*\/\n\n"; - -my $indent_args = "-i4 -npsl -di0 -br -nce -d0 -cli0 -npcs -nfc1"; - -# generate C source from DH params -my $dhsource = ''; -open(FP, "openssl dh -noout -C -in dh512.pem | indent $indent_args | expand |") || die; -$dhsource .= $_ while (<FP>); -close(FP); -open(FP, "openssl dh -noout -C -in dh1024.pem | indent $indent_args | expand |") || die; -$dhsource .= $_ while (<FP>); -close(FP); -$dhsource =~ s|(DH\s+\*get_dh)(\d+)[^}]*\n}|static $1$2(void) -{ - DH *dh; - - if (!(dh = DH_new())) { - return NULL; - } - - dh->p = BN_bin2bn(dh$2_p, sizeof(dh$2_p), NULL); - dh->g = BN_bin2bn(dh$2_g, sizeof(dh$2_g), NULL); - if (!(dh->p && dh->g)) { - DH_free(dh); - return NULL; - } - - return dh; -} -|sg; - -# generate output -my $o = $dhinfo . $dhsource; - -# insert the generated code at the target location -$source =~ s|(\/\* $begin.+?\n).*\n(.*?\/\* $end)|$1$o$2|s; - -# and update the source on disk -print "Updating file `$file'\n"; -open(FP, ">$file") || die; -print FP $source; -close(FP); - -# cleanup -unlink("dh512.pem"); -unlink("dh1024.pem"); - -=pod -*/ diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c index 9f8dcc8f..f6e010de 100644 --- a/modules/ssl/ssl_engine_init.c +++ b/modules/ssl/ssl_engine_init.c @@ -35,7 +35,7 @@ ** _________________________________________________________________ */ -#ifndef OPENSSL_NO_EC +#ifdef HAVE_ECC #define KEYTYPES "RSA, DSA or ECC" #else #define KEYTYPES "RSA or DSA" @@ -56,180 +56,6 @@ static void ssl_add_version_components(apr_pool_t *p, modver, AP_SERVER_BASEVERSION, incver); } - -/* - * Handle the Temporary RSA Keys and DH Params - */ - -#define MODSSL_TMP_KEY_FREE(mc, type, idx) \ - if (mc->pTmpKeys[idx]) { \ - type##_free((type *)mc->pTmpKeys[idx]); \ - mc->pTmpKeys[idx] = NULL; \ - } - -#define MODSSL_TMP_KEYS_FREE(mc, type) \ - MODSSL_TMP_KEY_FREE(mc, type, SSL_TMP_KEY_##type##_512); \ - MODSSL_TMP_KEY_FREE(mc, type, SSL_TMP_KEY_##type##_1024) - -static void ssl_tmp_keys_free(server_rec *s) -{ - SSLModConfigRec *mc = myModConfig(s); - - MODSSL_TMP_KEYS_FREE(mc, RSA); - MODSSL_TMP_KEYS_FREE(mc, DH); -#ifndef OPENSSL_NO_EC - MODSSL_TMP_KEY_FREE(mc, EC_KEY, SSL_TMP_KEY_EC_256); -#endif -} - -static int ssl_tmp_key_init_rsa(server_rec *s, - int bits, int idx) -{ - SSLModConfigRec *mc = myModConfig(s); - -#ifdef HAVE_FIPS - - if (FIPS_mode() && bits < 1024) { - mc->pTmpKeys[idx] = NULL; - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01877) - "Init: Skipping generating temporary " - "%d bit RSA private key in FIPS mode", bits); - return OK; - } - -#endif -#ifdef HAVE_GENERATE_EX - { - RSA *tkey; - BIGNUM *bn_f4; - if (!(tkey = RSA_new()) - || !(bn_f4 = BN_new()) - || !BN_set_word(bn_f4, RSA_F4) - || !RSA_generate_key_ex(tkey, bits, bn_f4, NULL)) - { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01878) - "Init: Failed to generate temporary " - "%d bit RSA private key", bits); - ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s); - return !OK; - } - BN_free(bn_f4); - mc->pTmpKeys[idx] = tkey; - } -#else - if (!(mc->pTmpKeys[idx] = - RSA_generate_key(bits, RSA_F4, NULL, NULL))) - { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01879) - "Init: Failed to generate temporary " - "%d bit RSA private key", bits); - ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s); - return !OK; - } -#endif - - return OK; -} - -static int ssl_tmp_key_init_dh(server_rec *s, - int bits, int idx) -{ - SSLModConfigRec *mc = myModConfig(s); - -#ifdef HAVE_FIPS - - if (FIPS_mode() && bits < 1024) { - mc->pTmpKeys[idx] = NULL; - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01880) - "Init: Skipping generating temporary " - "%d bit DH parameters in FIPS mode", bits); - return OK; - } - -#endif - - if (!(mc->pTmpKeys[idx] = - ssl_dh_GetTmpParam(bits))) - { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01881) - "Init: Failed to generate temporary " - "%d bit DH parameters", bits); - return !OK; - } - - return OK; -} - -#ifndef OPENSSL_NO_EC -static int ssl_tmp_key_init_ec(server_rec *s, - int bits, int idx) -{ - SSLModConfigRec *mc = myModConfig(s); - EC_KEY *ecdh = NULL; - - /* XXX: Are there any FIPS constraints we should enforce? */ - - if (bits != 256) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02298) - "Init: Failed to generate temporary " - "%d bit EC parameters, only 256 bits supported", bits); - return !OK; - } - - if ((ecdh = EC_KEY_new()) == NULL || - EC_KEY_set_group(ecdh, EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)) != 1) - { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02299) - "Init: Failed to generate temporary " - "%d bit EC parameters", bits); - return !OK; - } - - mc->pTmpKeys[idx] = ecdh; - return OK; -} - -#define MODSSL_TMP_KEY_INIT_EC(s, bits) \ - ssl_tmp_key_init_ec(s, bits, SSL_TMP_KEY_EC_##bits) - -#endif - -#define MODSSL_TMP_KEY_INIT_RSA(s, bits) \ - ssl_tmp_key_init_rsa(s, bits, SSL_TMP_KEY_RSA_##bits) - -#define MODSSL_TMP_KEY_INIT_DH(s, bits) \ - ssl_tmp_key_init_dh(s, bits, SSL_TMP_KEY_DH_##bits) - -static int ssl_tmp_keys_init(server_rec *s) -{ - ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s, - "Init: Generating temporary RSA private keys (512/1024 bits)"); - - if (MODSSL_TMP_KEY_INIT_RSA(s, 512) || - MODSSL_TMP_KEY_INIT_RSA(s, 1024)) { - return !OK; - } - - ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s, - "Init: Generating temporary DH parameters (512/1024 bits)"); - - if (MODSSL_TMP_KEY_INIT_DH(s, 512) || - MODSSL_TMP_KEY_INIT_DH(s, 1024)) { - return !OK; - } - -#ifndef OPENSSL_NO_EC - ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s, - "Init: Generating temporary EC parameters (256 bits)"); - - if (MODSSL_TMP_KEY_INIT_EC(s, 256)) { - return !OK; - } -#endif - - return OK; -} - /* * Per-module initialization */ @@ -294,7 +120,7 @@ int ssl_init_Module(apr_pool_t *p, apr_pool_t *plog, sc->enabled = SSL_ENABLED_TRUE; } - /* If sc->enabled is UNSET, then SSL is optional on this vhost */ + /* If sc->enabled is UNSET, then SSL is optional on this vhost */ /* Fix up stuff that may not have been set */ if (sc->enabled == SSL_ENABLED_UNSET) { sc->enabled = SSL_ENABLED_FALSE; @@ -367,10 +193,6 @@ int ssl_init_Module(apr_pool_t *p, apr_pool_t *plog, */ ssl_pphrase_Handle(base_server, ptemp); - if (ssl_tmp_keys_init(base_server)) { - return !OK; - } - /* * initialize the mutex handling */ @@ -481,7 +303,7 @@ static void ssl_init_server_check(server_rec *s, */ if (mctx->pks->certs[SSL_AIDX_RSA] || mctx->pks->certs[SSL_AIDX_DSA] -#ifndef OPENSSL_NO_EC +#ifdef HAVE_ECC || mctx->pks->certs[SSL_AIDX_ECC] #endif ) @@ -493,7 +315,7 @@ static void ssl_init_server_check(server_rec *s, } } -#ifndef OPENSSL_NO_TLSEXT +#ifdef HAVE_TLSEXT static void ssl_init_ctx_tls_extensions(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, @@ -527,7 +349,7 @@ static void ssl_init_ctx_tls_extensions(server_rec *s, } #endif -#ifndef OPENSSL_NO_SRP +#ifdef HAVE_SRP /* * TLS-SRP support */ @@ -660,7 +482,7 @@ static void ssl_init_ctx_protocol(server_rec *s, #ifdef SSL_OP_NO_COMPRESSION /* OpenSSL >= 1.0 only */ SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION); -#elif OPENSSL_VERSION_NUMBER >= 0x00908000L +#else sk_SSL_COMP_zero(SSL_COMP_get_compression_methods()); #endif } @@ -678,6 +500,9 @@ static void ssl_init_ctx_protocol(server_rec *s, * Configure additional context ingredients */ SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE); +#ifdef HAVE_ECC + SSL_CTX_set_options(ctx, SSL_OP_SINGLE_ECDH_USE); +#endif #ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION /* @@ -718,11 +543,7 @@ static void ssl_init_ctx_callbacks(server_rec *s, { SSL_CTX *ctx = mctx->ssl_ctx; - SSL_CTX_set_tmp_rsa_callback(ctx, ssl_callback_TmpRSA); SSL_CTX_set_tmp_dh_callback(ctx, ssl_callback_TmpDH); -#ifndef OPENSSL_NO_EC - SSL_CTX_set_tmp_ecdh_callback(ctx,ssl_callback_TmpECDH); -#endif SSL_CTX_set_info_callback(ctx, ssl_callback_Info); } @@ -818,14 +639,16 @@ static void ssl_init_ctx_cipher_suite(server_rec *s, modssl_ctx_t *mctx) { SSL_CTX *ctx = mctx->ssl_ctx; - const char *suite = mctx->auth.cipher_suite; + const char *suite; /* - * Configure SSL Cipher Suite + * Configure SSL Cipher Suite. Always disable NULL and export ciphers, + * see also ssl_engine_config.c:ssl_cmd_SSLCipherSuite(). + * OpenSSL's SSL_DEFAULT_CIPHER_LIST already includes !aNULL:!eNULL, + * so only prepend !EXP in this case. */ - if (!suite) { - return; - } + suite = mctx->auth.cipher_suite ? mctx->auth.cipher_suite : + apr_pstrcat(ptemp, "!EXP:", SSL_DEFAULT_CIPHER_LIST, NULL); ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s, "Configuring permitted SSL ciphers [%s]", @@ -988,7 +811,7 @@ 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 +#ifdef HAVE_TLSEXT ssl_init_ctx_tls_extensions(s, p, ptemp, mctx); #endif } @@ -1001,7 +824,7 @@ static int ssl_server_import_cert(server_rec *s, { SSLModConfigRec *mc = myModConfig(s); ssl_asn1_t *asn1; - MODSSL_D2I_X509_CONST unsigned char *ptr; + const unsigned char *ptr; const char *type = ssl_asn1_keystr(idx); X509 *cert; @@ -1048,12 +871,12 @@ static int ssl_server_import_key(server_rec *s, { SSLModConfigRec *mc = myModConfig(s); ssl_asn1_t *asn1; - MODSSL_D2I_PrivateKey_CONST unsigned char *ptr; + const unsigned char *ptr; const char *type = ssl_asn1_keystr(idx); int pkey_type; EVP_PKEY *pkey; -#ifndef OPENSSL_NO_EC +#ifdef HAVE_ECC if (idx == SSL_AIDX_ECC) pkey_type = EVP_PKEY_EC; else @@ -1157,30 +980,34 @@ static void ssl_init_server_certs(server_rec *s, modssl_ctx_t *mctx) { const char *rsa_id, *dsa_id; -#ifndef OPENSSL_NO_EC +#ifdef HAVE_ECC const char *ecc_id; + EC_GROUP *ecparams; + int nid; + EC_KEY *eckey; #endif const char *vhost_id = mctx->sc->vhost_id; int i; int have_rsa, have_dsa; -#ifndef OPENSSL_NO_EC + DH *dhparams; +#ifdef HAVE_ECC int have_ecc; #endif rsa_id = ssl_asn1_table_keyfmt(ptemp, vhost_id, SSL_AIDX_RSA); dsa_id = ssl_asn1_table_keyfmt(ptemp, vhost_id, SSL_AIDX_DSA); -#ifndef OPENSSL_NO_EC +#ifdef HAVE_ECC ecc_id = ssl_asn1_table_keyfmt(ptemp, vhost_id, SSL_AIDX_ECC); #endif have_rsa = ssl_server_import_cert(s, mctx, rsa_id, SSL_AIDX_RSA); have_dsa = ssl_server_import_cert(s, mctx, dsa_id, SSL_AIDX_DSA); -#ifndef OPENSSL_NO_EC +#ifdef HAVE_ECC have_ecc = ssl_server_import_cert(s, mctx, ecc_id, SSL_AIDX_ECC); #endif if (!(have_rsa || have_dsa -#ifndef OPENSSL_NO_EC +#ifdef HAVE_ECC || have_ecc #endif )) { @@ -1196,12 +1023,12 @@ static void ssl_init_server_certs(server_rec *s, have_rsa = ssl_server_import_key(s, mctx, rsa_id, SSL_AIDX_RSA); have_dsa = ssl_server_import_key(s, mctx, dsa_id, SSL_AIDX_DSA); -#ifndef OPENSSL_NO_EC +#ifdef HAVE_ECC have_ecc = ssl_server_import_key(s, mctx, ecc_id, SSL_AIDX_ECC); #endif if (!(have_rsa || have_dsa -#ifndef OPENSSL_NO_EC +#ifdef HAVE_ECC || have_ecc #endif )) { @@ -1209,6 +1036,40 @@ static void ssl_init_server_certs(server_rec *s, "Oops, no " KEYTYPES " server private key found?!"); ssl_die(s); } + + /* + * Try to read DH parameters from the (first) SSLCertificateFile + */ + if ((mctx->pks->cert_files[0] != NULL) && + (dhparams = ssl_dh_GetParamFromFile(mctx->pks->cert_files[0]))) { + SSL_CTX_set_tmp_dh(mctx->ssl_ctx, dhparams); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02540) + "Custom DH parameters (%d bits) for %s loaded from %s", + BN_num_bits(dhparams->p), vhost_id, + mctx->pks->cert_files[0]); + } + +#ifdef HAVE_ECC + /* + * Similarly, try to read the ECDH curve name from SSLCertificateFile... + */ + if ((mctx->pks->cert_files[0] != NULL) && + (ecparams = ssl_ec_GetParamFromFile(mctx->pks->cert_files[0])) && + (nid = EC_GROUP_get_curve_name(ecparams)) && + (eckey = EC_KEY_new_by_curve_name(nid))) { + SSL_CTX_set_tmp_ecdh(mctx->ssl_ctx, eckey); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02541) + "ECDH curve %s for %s specified in %s", + OBJ_nid2sn(nid), vhost_id, mctx->pks->cert_files[0]); + } + /* + * ...otherwise, configure NIST P-256 (required to enable ECDHE) + */ + else { + SSL_CTX_set_tmp_ecdh(mctx->ssl_ctx, + EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); + } +#endif } #ifdef HAVE_TLS_SESSION_TICKETS @@ -1516,7 +1377,7 @@ 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))) { -#ifdef OPENSSL_NO_TLSEXT +#ifndef HAVE_TLSEXT int level = APLOG_WARNING; const char *problem = "conflict"; #else @@ -1540,7 +1401,7 @@ void ssl_init_CheckServers(server_rec *base_server, apr_pool_t *p) } if (conflict) { -#ifdef OPENSSL_NO_TLSEXT +#ifndef HAVE_TLSEXT ap_log_error(APLOG_MARK, APLOG_WARNING, 0, base_server, APLOGNO(01917) "Init: You should not use name-based " "virtual hosts in conjunction with SSL!!"); @@ -1689,7 +1550,7 @@ static void ssl_init_ctx_cleanup(modssl_ctx_t *mctx) { MODSSL_CFG_ITEM_FREE(SSL_CTX_free, mctx->ssl_ctx); -#ifndef OPENSSL_NO_SRP +#ifdef HAVE_SRP if (mctx->srp_vbase != NULL) { SRP_VBASE_free(mctx->srp_vbase); mctx->srp_vbase = NULL; @@ -1745,11 +1606,6 @@ apr_status_t ssl_init_ModuleKill(void *data) ssl_scache_kill(base_server); /* - * Destroy the temporary keys and params - */ - ssl_tmp_keys_free(base_server); - - /* * Free the non-pool allocated structures * in the per-server configurations */ diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c index d135bd38..7f60cc27 100644 --- a/modules/ssl/ssl_engine_io.c +++ b/modules/ssl/ssl_engine_io.c @@ -775,6 +775,18 @@ static apr_status_t ssl_filter_write(ap_filter_t *f, */ outctx->rc = APR_EAGAIN; } + else if (ssl_err == SSL_ERROR_WANT_READ) { + /* + * If OpenSSL wants to read during write, and we were + * nonblocking, set the sense explicitly to read and + * report as an EAGAIN. + * + * (This is usually the case when the client forces an SSL + * renegotiation which is handled implicitly by OpenSSL.) + */ + outctx->c->cs->sense = CONN_SENSE_WANT_READ; + outctx->rc = APR_EAGAIN; + } else if (ssl_err == SSL_ERROR_SYSCALL) { ap_log_cerror(APLOG_MARK, APLOG_INFO, outctx->rc, c, APLOGNO(01993) "SSL output filter write failed."); @@ -1048,7 +1060,7 @@ static apr_status_t ssl_io_filter_handshake(ssl_filter_ctx_t *filter_ctx) server = sslconn->server; if (sslconn->is_proxy) { -#ifndef OPENSSL_NO_TLSEXT +#ifdef HAVE_TLSEXT apr_ipsubnet_t *ip; #endif const char *hostname_note = apr_table_get(c->notes, @@ -1056,7 +1068,7 @@ static apr_status_t ssl_io_filter_handshake(ssl_filter_ctx_t *filter_ctx) BOOL proxy_ssl_check_peer_ok = TRUE; sc = mySrvConfig(server); -#ifndef OPENSSL_NO_TLSEXT +#ifdef HAVE_TLSEXT /* * Enable SNI for backend requests. Make sure we don't do it for * pure SSLv3 connections, and also prevent IP addresses @@ -1902,8 +1914,10 @@ void ssl_io_filter_init(conn_rec *c, request_rec *r, SSL *ssl) filter_ctx->pbioWrite = BIO_new(&bio_filter_out_method); filter_ctx->pbioWrite->ptr = (void *)bio_filter_out_ctx_new(filter_ctx, c); - /* We insert a clogging input filter. Let the core know. */ - c->clogging_input_filters = 1; + /* write is non blocking for the benefit of async mpm */ + if (c->cs) { + BIO_set_nbio(filter_ctx->pbioWrite, 1); + } ssl_io_input_add_filter(filter_ctx, c, r, ssl); diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c index a088df16..6d93ac99 100644 --- a/modules/ssl/ssl_engine_kernel.c +++ b/modules/ssl/ssl_engine_kernel.c @@ -32,7 +32,7 @@ #include "util_md5.h" static void ssl_configure_env(request_rec *r, SSLConnRec *sslconn); -#ifndef OPENSSL_NO_TLSEXT +#ifdef HAVE_TLSEXT static int ssl_find_vhost(void *servername, conn_rec *c, server_rec *s); #endif @@ -119,7 +119,7 @@ int ssl_hook_ReadReq(request_rec *r) SSLSrvConfigRec *sc = mySrvConfig(r->server); SSLConnRec *sslconn; const char *upgrade; -#ifndef OPENSSL_NO_TLSEXT +#ifdef HAVE_TLSEXT const char *servername; #endif SSL *ssl; @@ -162,7 +162,7 @@ int ssl_hook_ReadReq(request_rec *r) if (!ssl) { return DECLINED; } -#ifndef OPENSSL_NO_TLSEXT +#ifdef HAVE_TLSEXT if ((servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name))) { char *host, *scope_id; apr_port_t port; @@ -329,7 +329,7 @@ int ssl_hook_Access(request_rec *r) return DECLINED; } -#ifndef OPENSSL_NO_SRP +#ifdef HAVE_SRP /* * Support for per-directory reconfigured SSL connection parameters * @@ -1101,7 +1101,7 @@ static const char *ssl_hook_Fixup_vars[] = { "SSL_SERVER_A_SIG", "SSL_SESSION_ID", "SSL_SESSION_RESUMED", -#ifndef OPENSSL_NO_SRP +#ifdef HAVE_SRP "SSL_SRP_USER", "SSL_SRP_USERINFO", #endif @@ -1115,7 +1115,7 @@ 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 +#ifdef HAVE_TLSEXT const char *servername; #endif STACK_OF(X509) *peer_certs; @@ -1144,7 +1144,7 @@ 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 +#ifdef HAVE_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); @@ -1287,117 +1287,70 @@ const authz_provider ssl_authz_provider_verify_client = */ /* - * Handle out temporary RSA private keys on demand - * - * The background of this as the TLSv1 standard explains it: - * - * | D.1. Temporary RSA keys - * | - * | US Export restrictions limit RSA keys used for encryption to 512 - * | bits, but do not place any limit on lengths of RSA keys used for - * | signing operations. Certificates often need to be larger than 512 - * | bits, since 512-bit RSA keys are not secure enough for high-value - * | transactions or for applications requiring long-term security. Some - * | certificates are also designated signing-only, in which case they - * | cannot be used for key exchange. - * | - * | When the public key in the certificate cannot be used for encryption, - * | the server signs a temporary RSA key, which is then exchanged. In - * | exportable applications, the temporary RSA key should be the maximum - * | allowable length (i.e., 512 bits). Because 512-bit RSA keys are - * | relatively insecure, they should be changed often. For typical - * | electronic commerce applications, it is suggested that keys be - * | changed daily or every 500 transactions, and more often if possible. - * | Note that while it is acceptable to use the same temporary key for - * | multiple transactions, it must be signed each time it is used. - * | - * | RSA key generation is a time-consuming process. In many cases, a - * | low-priority process can be assigned the task of key generation. - * | Whenever a new key is completed, the existing temporary key can be - * | replaced with the new one. - * - * XXX: base on comment above, if thread support is enabled, - * we should spawn a low-priority thread to generate new keys - * on the fly. - * - * So we generated 512 and 1024 bit temporary keys on startup - * which we now just hand out on demand.... + * Grab well-defined DH parameters from OpenSSL, see <openssl/bn.h> + * (get_rfc*) for all available primes. */ - -RSA *ssl_callback_TmpRSA(SSL *ssl, int export, int keylen) -{ - conn_rec *c = (conn_rec *)SSL_get_app_data(ssl); - SSLModConfigRec *mc = myModConfigFromConn(c); - int idx; - - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, - "handing out temporary %d bit RSA key", keylen); - - /* doesn't matter if export flag is on, - * we won't be asked for keylen > 512 in that case. - * if we are asked for a keylen > 1024, it is too expensive - * to generate on the fly. - * XXX: any reason not to generate 2048 bit keys at startup? - */ - - switch (keylen) { - case 512: - idx = SSL_TMP_KEY_RSA_512; - break; - - case 1024: - default: - idx = SSL_TMP_KEY_RSA_1024; - } - - return (RSA *)mc->pTmpKeys[idx]; +#define make_get_dh(rfc,size,gen) \ +static DH *get_dh##size(void) \ +{ \ + DH *dh; \ + if (!(dh = DH_new())) { \ + return NULL; \ + } \ + dh->p = get_##rfc##_prime_##size(NULL); \ + BN_dec2bn(&dh->g, #gen); \ + if (!dh->p || !dh->g) { \ + DH_free(dh); \ + return NULL; \ + } \ + return dh; \ } /* - * Hand out the already generated DH parameters... + * Prepare DH parameters from 1024 to 4096 bits, in 1024-bit increments + */ +make_get_dh(rfc2409, 1024, 2) +make_get_dh(rfc3526, 2048, 2) +make_get_dh(rfc3526, 3072, 2) +make_get_dh(rfc3526, 4096, 2) + +/* + * Hand out standard DH parameters, based on the authentication strength */ DH *ssl_callback_TmpDH(SSL *ssl, int export, int keylen) { conn_rec *c = (conn_rec *)SSL_get_app_data(ssl); - SSLModConfigRec *mc = myModConfigFromConn(c); - int idx; - - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, - "handing out temporary %d bit DH key", keylen); - - switch (keylen) { - case 512: - idx = SSL_TMP_KEY_DH_512; - break; + EVP_PKEY *pkey = SSL_get_privatekey(ssl); + int type = pkey ? EVP_PKEY_type(pkey->type) : EVP_PKEY_NONE; - case 1024: - default: - idx = SSL_TMP_KEY_DH_1024; + /* + * OpenSSL will call us with either keylen == 512 or keylen == 1024 + * (see the definition of SSL_EXPORT_PKEYLENGTH in ssl_locl.h). + * Adjust the DH parameter length according to the size of the + * RSA/DSA private key used for the current connection, and always + * use at least 1024-bit parameters. + * Note: This may cause interoperability issues with implementations + * which limit their DH support to 1024 bit - e.g. Java 7 and earlier. + * In this case, SSLCertificateFile can be used to specify fixed + * 1024-bit DH parameters (with the effect that OpenSSL skips this + * callback). + */ + if ((type == EVP_PKEY_RSA) || (type == EVP_PKEY_DSA)) { + keylen = EVP_PKEY_bits(pkey); } - return (DH *)mc->pTmpKeys[idx]; -} - -#ifndef OPENSSL_NO_EC -EC_KEY *ssl_callback_TmpECDH(SSL *ssl, int export, int keylen) -{ - conn_rec *c = (conn_rec *)SSL_get_app_data(ssl); - SSLModConfigRec *mc = myModConfigFromConn(c); - int idx; - - /* XXX Uses 256-bit key for now. TODO: support other sizes. */ ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, - "handing out temporary 256 bit ECC key"); - - switch (keylen) { - case 256: - default: - idx = SSL_TMP_KEY_EC_256; - } - - return (EC_KEY *)mc->pTmpKeys[idx]; + "handing out built-in DH parameters for %d-bit authenticated connection", keylen); + + if (keylen >= 4096) + return get_dh4096(); + else if (keylen >= 3072) + return get_dh3072(); + else if (keylen >= 2048) + return get_dh2048(); + else + return get_dh1024(); } -#endif /* * This OpenSSL callback function is called when OpenSSL @@ -1687,7 +1640,7 @@ static void ssl_session_log(server_rec *s, if (timeout) { apr_snprintf(timeout_str, sizeof(timeout_str), - "timeout=%lds ", (timeout - time(NULL))); + "timeout=%lds ", timeout); } ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, s, @@ -1938,7 +1891,7 @@ void ssl_callback_Info(const SSL *ssl, int where, int rc) } } -#ifndef OPENSSL_NO_TLSEXT +#ifdef HAVE_TLSEXT /* * This callback function is executed when OpenSSL encounters an extended * client hello with a server name indication extension ("SNI", cf. RFC 4366). @@ -2089,7 +2042,7 @@ static int ssl_find_vhost(void *servername, conn_rec *c, server_rec *s) return 0; } -#endif /* OPENSSL_NO_TLSEXT */ +#endif /* HAVE_TLSEXT */ #ifdef HAVE_TLS_SESSION_TICKETS /* @@ -2161,7 +2114,7 @@ int ssl_callback_SessionTicket(SSL *ssl, } #endif /* HAVE_TLS_SESSION_TICKETS */ -#ifndef OPENSSL_NO_SRP +#ifdef HAVE_SRP int ssl_callback_SRPServerParams(SSL *ssl, int *ad, void *arg) { @@ -2185,4 +2138,4 @@ int ssl_callback_SRPServerParams(SSL *ssl, int *ad, void *arg) return SSL_ERROR_NONE; } -#endif /* OPENSSL_NO_SRP */ +#endif /* HAVE_SRP */ diff --git a/modules/ssl/ssl_engine_pphrase.c b/modules/ssl/ssl_engine_pphrase.c index 23ccaf4a..ca8e130f 100644 --- a/modules/ssl/ssl_engine_pphrase.c +++ b/modules/ssl/ssl_engine_pphrase.c @@ -708,7 +708,7 @@ int ssl_pphrase_Handle_CB(char *buf, int bufsize, int verify, void *srv) ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01966) "Init: Failed to create pass phrase pipe '%s'", sc->server->pphrase_dialog_path); - PEMerr(PEM_F_DEF_CALLBACK,PEM_R_PROBLEMS_GETTING_PASSWORD); + PEMerr(PEM_F_PEM_DEF_CALLBACK,PEM_R_PROBLEMS_GETTING_PASSWORD); memset(buf, 0, (unsigned int)bufsize); return (-1); } @@ -718,7 +718,7 @@ int ssl_pphrase_Handle_CB(char *buf, int bufsize, int verify, void *srv) } else { /* sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN */ #ifdef WIN32 - PEMerr(PEM_F_DEF_CALLBACK,PEM_R_PROBLEMS_GETTING_PASSWORD); + PEMerr(PEM_F_PEM_DEF_CALLBACK,PEM_R_PROBLEMS_GETTING_PASSWORD); memset(buf, 0, (unsigned int)bufsize); return (-1); #else @@ -769,7 +769,7 @@ int ssl_pphrase_Handle_CB(char *buf, int bufsize, int verify, void *srv) i = EVP_read_pw_string(buf, bufsize, "", FALSE); } if (i != 0) { - PEMerr(PEM_F_DEF_CALLBACK,PEM_R_PROBLEMS_GETTING_PASSWORD); + PEMerr(PEM_F_PEM_DEF_CALLBACK,PEM_R_PROBLEMS_GETTING_PASSWORD); memset(buf, 0, (unsigned int)bufsize); return (-1); } diff --git a/modules/ssl/ssl_engine_vars.c b/modules/ssl/ssl_engine_vars.c index 536e6b1f..922bf7c1 100644 --- a/modules/ssl/ssl_engine_vars.c +++ b/modules/ssl/ssl_engine_vars.c @@ -382,7 +382,7 @@ static char *ssl_var_lookup_ssl(apr_pool_t *p, conn_rec *c, request_rec *r, else if (ssl != NULL && strcEQ(var, "COMPRESS_METHOD")) { result = ssl_var_lookup_ssl_compress_meth(ssl); } -#ifndef OPENSSL_NO_TLSEXT +#ifdef HAVE_TLSEXT else if (ssl != NULL && strcEQ(var, "TLS_SNI")) { result = apr_pstrdup(p, SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name)); @@ -395,7 +395,7 @@ static char *ssl_var_lookup_ssl(apr_pool_t *p, conn_rec *c, request_rec *r, #endif result = apr_pstrdup(p, flag ? "true" : "false"); } -#ifndef OPENSSL_NO_SRP +#ifdef HAVE_SRP else if (ssl != NULL && strcEQ(var, "SRP_USER")) { if ((result = SSL_get_srp_username(ssl)) != NULL) { result = apr_pstrdup(p, result); @@ -879,7 +879,7 @@ void modssl_var_extract_dns(apr_table_t *t, SSL *ssl, apr_pool_t *p) * success and writes the string to the given bio. */ static int dump_extn_value(BIO *bio, ASN1_OCTET_STRING *str) { - MODSSL_D2I_ASN1_type_bytes_CONST unsigned char *pp = str->data; + const unsigned char *pp = str->data; ASN1_STRING *ret = ASN1_STRING_new(); int rv = 0; @@ -975,7 +975,7 @@ apr_array_header_t *ssl_ext_list(apr_pool_t *p, conn_rec *c, int peer, static char *ssl_var_lookup_ssl_compress_meth(SSL *ssl) { char *result = "NULL"; -#if (OPENSSL_VERSION_NUMBER >= 0x00908000) && !defined(OPENSSL_NO_COMP) +#ifndef OPENSSL_NO_COMP SSL_SESSION *pSession = SSL_get_session(ssl); if (pSession) { diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h index 080ecef3..4ea924f3 100644 --- a/modules/ssl/ssl_private.h +++ b/modules/ssl/ssl_private.h @@ -105,65 +105,55 @@ #include <openssl/engine.h> #endif -#if (OPENSSL_VERSION_NUMBER < 0x0090700f) -#error mod_ssl requires OpenSSL 0.9.7 or later -#endif - -/* ...shifting sands of OpenSSL... */ -#if (OPENSSL_VERSION_NUMBER >= 0x0090707f) -#define MODSSL_D2I_SSL_SESSION_CONST const -#else -#define MODSSL_D2I_SSL_SESSION_CONST -#endif - -#if (OPENSSL_VERSION_NUMBER >= 0x00908000) -#define HAVE_GENERATE_EX -#define MODSSL_D2I_ASN1_type_bytes_CONST const -#define MODSSL_D2I_PrivateKey_CONST const -#define MODSSL_D2I_X509_CONST const -#else -#define MODSSL_D2I_ASN1_type_bytes_CONST -#define MODSSL_D2I_PrivateKey_CONST -#define MODSSL_D2I_X509_CONST -#endif - -#if OPENSSL_VERSION_NUMBER >= 0x00908080 && !defined(OPENSSL_NO_OCSP) \ - && !defined(OPENSSL_NO_TLSEXT) -#define HAVE_OCSP_STAPLING -#if (OPENSSL_VERSION_NUMBER < 0x10000000) -#define sk_OPENSSL_STRING_pop sk_pop -#endif -#endif - -#if (OPENSSL_VERSION_NUMBER >= 0x009080a0) && defined(OPENSSL_FIPS) -#define HAVE_FIPS +#if (OPENSSL_VERSION_NUMBER < 0x0090801f) +#error mod_ssl requires OpenSSL 0.9.8a or later #endif +/** + * ...shifting sands of OpenSSL... + * Note: when adding support for new OpenSSL features, avoid explicit + * version number checks whenever possible, and use "feature-based" + * detection instead (check for definitions of constants or functions) + */ #if (OPENSSL_VERSION_NUMBER >= 0x10000000) #define MODSSL_SSL_CIPHER_CONST const #define MODSSL_SSL_METHOD_CONST const #else #define MODSSL_SSL_CIPHER_CONST #define MODSSL_SSL_METHOD_CONST -/* ECC support came along in OpenSSL 1.0.0 */ -#define OPENSSL_NO_EC #endif -#ifndef PEM_F_DEF_CALLBACK -#ifdef PEM_F_PEM_DEF_CALLBACK -/** In OpenSSL 0.9.8 PEM_F_DEF_CALLBACK was renamed */ -#define PEM_F_DEF_CALLBACK PEM_F_PEM_DEF_CALLBACK +#if defined(OPENSSL_FIPS) +#define HAVE_FIPS #endif + +#if defined(SSL_OP_NO_TLSv1_2) +#define HAVE_TLSV1_X #endif -#ifndef OPENSSL_NO_TLSEXT -#ifndef SSL_CTRL_SET_TLSEXT_HOSTNAME -#define OPENSSL_NO_TLSEXT +/** + * The following features all depend on TLS extension support. + * Within this block, check again for features (not version numbers). + */ +#if !defined(OPENSSL_NO_TLSEXT) && defined(SSL_set_tlsext_host_name) + +#define HAVE_TLSEXT + +/* ECC: make sure we have at least 1.0.0 */ +#if !defined(OPENSSL_NO_EC) && defined(TLSEXT_ECPOINTFORMAT_uncompressed) +#define HAVE_ECC +#endif + +/* OCSP stapling */ +#if !defined(OPENSSL_NO_OCSP) && defined(SSL_CTX_set_tlsext_status_cb) +#define HAVE_OCSP_STAPLING +#ifndef sk_OPENSSL_STRING_pop +#define sk_OPENSSL_STRING_pop sk_pop #endif #endif -#ifndef OPENSSL_NO_TLSEXT -#ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB +/* TLS session tickets */ +#if defined(SSL_CTX_set_tlsext_ticket_key_cb) #define HAVE_TLS_SESSION_TICKETS #define TLSEXT_TICKET_KEY_LEN 48 #ifndef tlsext_tick_md @@ -174,26 +164,15 @@ #endif #endif #endif -#endif -#ifdef SSL_OP_NO_TLSv1_2 -#define HAVE_TLSV1_X -#endif - -#if !defined(OPENSSL_NO_COMP) && !defined(SSL_OP_NO_COMPRESSION) \ - && OPENSSL_VERSION_NUMBER < 0x00908000L -#define OPENSSL_NO_COMP -#endif - -/* SRP support came in OpenSSL 1.0.1 */ -#ifndef OPENSSL_NO_SRP -#ifdef SSL_CTRL_SET_TLS_EXT_SRP_USERNAME_CB +/* Secure Remote Password */ +#if !defined(OPENSSL_NO_SRP) && defined(SSL_CTRL_SET_TLS_EXT_SRP_USERNAME_CB) +#define HAVE_SRP #include <openssl/srp.h> -#else -#define OPENSSL_NO_SRP -#endif #endif +#endif /* !defined(OPENSSL_NO_TLSEXT) && defined(SSL_set_tlsext_host_name) */ + /* mod_ssl headers */ #include "ssl_util_ssl.h" @@ -287,7 +266,7 @@ typedef int ssl_algo_t; #define SSL_ALGO_UNKNOWN (0) #define SSL_ALGO_RSA (1<<0) #define SSL_ALGO_DSA (1<<1) -#ifndef OPENSSL_NO_EC +#ifdef HAVE_ECC #define SSL_ALGO_ECC (1<<2) #define SSL_ALGO_ALL (SSL_ALGO_RSA|SSL_ALGO_DSA|SSL_ALGO_ECC) #else @@ -296,29 +275,13 @@ typedef int ssl_algo_t; #define SSL_AIDX_RSA (0) #define SSL_AIDX_DSA (1) -#ifndef OPENSSL_NO_EC +#ifdef HAVE_ECC #define SSL_AIDX_ECC (2) #define SSL_AIDX_MAX (3) #else #define SSL_AIDX_MAX (2) #endif - -/** - * Define IDs for the temporary RSA keys and DH params - */ - -#define SSL_TMP_KEY_RSA_512 (0) -#define SSL_TMP_KEY_RSA_1024 (1) -#define SSL_TMP_KEY_DH_512 (2) -#define SSL_TMP_KEY_DH_1024 (3) -#ifndef OPENSSL_NO_EC -#define SSL_TMP_KEY_EC_256 (4) -#define SSL_TMP_KEY_MAX (5) -#else -#define SSL_TMP_KEY_MAX (4) -#endif - /** * Define the SSL options */ @@ -534,7 +497,6 @@ typedef struct { apr_global_mutex_t *pMutex; apr_array_header_t *aRandSeed; apr_hash_t *tVHostKeys; - void *pTmpKeys[SSL_TMP_KEY_MAX]; /* Two hash tables of pointers to ssl_asn1_t structures. The * structures are used to store certificates and private keys @@ -656,7 +618,7 @@ typedef struct { const char *stapling_force_url; #endif -#ifndef OPENSSL_NO_SRP +#ifdef HAVE_SRP char *srp_vfile; char *srp_unknown_user_seed; SRP_VBASE *srp_vbase; @@ -688,7 +650,7 @@ struct SSLSrvConfigRec { ssl_enabled_t proxy_ssl_check_peer_expire; ssl_enabled_t proxy_ssl_check_peer_cn; ssl_enabled_t proxy_ssl_check_peer_name; -#ifndef OPENSSL_NO_TLSEXT +#ifdef HAVE_TLSEXT ssl_enabled_t strict_sni_vhost_check; #endif #ifdef HAVE_FIPS @@ -792,7 +754,7 @@ const char *ssl_cmd_SSLOCSPResponseMaxAge(cmd_parms *cmd, void *dcfg, const char const char *ssl_cmd_SSLOCSPResponderTimeout(cmd_parms *cmd, void *dcfg, const char *arg); const char *ssl_cmd_SSLOCSPEnable(cmd_parms *cmd, void *dcfg, int flag); -#ifndef OPENSSL_NO_SRP +#ifdef HAVE_SRP const char *ssl_cmd_SSLSRPVerifierFile(cmd_parms *cmd, void *dcfg, const char *arg); const char *ssl_cmd_SSLSRPUnknownUserSeed(cmd_parms *cmd, void *dcfg, const char *arg); #endif @@ -823,11 +785,7 @@ extern const authz_provider ssl_authz_provider_require_ssl; extern const authz_provider ssl_authz_provider_verify_client; /** OpenSSL callbacks */ -RSA *ssl_callback_TmpRSA(SSL *, int, int); DH *ssl_callback_TmpDH(SSL *, int, int); -#ifndef OPENSSL_NO_EC -EC_KEY *ssl_callback_TmpECDH(SSL *, int, int); -#endif int ssl_callback_SSLVerify(int, X509_STORE_CTX *); int ssl_callback_SSLVerify_CRL(int, X509_STORE_CTX *, conn_rec *); int ssl_callback_proxy_cert(SSL *ssl, X509 **x509, EVP_PKEY **pkey); @@ -835,7 +793,7 @@ 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_Info(const SSL *, int, int); -#ifndef OPENSSL_NO_TLSEXT +#ifdef HAVE_TLSEXT int ssl_callback_ServerNameIndication(SSL *, int *, modssl_ctx_t *); #endif #ifdef HAVE_TLS_SESSION_TICKETS @@ -873,7 +831,7 @@ void modssl_init_stapling(server_rec *, apr_pool_t *, apr_pool_t *, mods void ssl_stapling_ex_init(void); int ssl_stapling_init_cert(server_rec *s, modssl_ctx_t *mctx, X509 *x); #endif -#ifndef OPENSSL_NO_SRP +#ifdef HAVE_SRP int ssl_callback_SRPServerParams(SSL *, int *, void *); #endif @@ -906,8 +864,10 @@ int ssl_init_ssl_connection(conn_rec *c, request_rec *r); void ssl_pphrase_Handle(server_rec *, apr_pool_t *); /** Diffie-Hellman Parameter Support */ -DH *ssl_dh_GetTmpParam(int); -DH *ssl_dh_GetParamFromFile(char *); +DH *ssl_dh_GetParamFromFile(const char *); +#ifdef HAVE_ECC +EC_GROUP *ssl_ec_GetParamFromFile(const char *); +#endif unsigned char *ssl_asn1_table_set(apr_hash_t *table, const char *key, diff --git a/modules/ssl/ssl_scache.c b/modules/ssl/ssl_scache.c index d32f8e1d..bfed6e7c 100644 --- a/modules/ssl/ssl_scache.c +++ b/modules/ssl/ssl_scache.c @@ -148,7 +148,7 @@ SSL_SESSION *ssl_scache_retrieve(server_rec *s, UCHAR *id, int idlen, SSLModConfigRec *mc = myModConfig(s); unsigned char dest[SSL_SESSION_MAX_DER]; unsigned int destlen = SSL_SESSION_MAX_DER; - MODSSL_D2I_SSL_SESSION_CONST unsigned char *ptr; + const unsigned char *ptr; apr_status_t rv; if (mc->sesscache->flags & AP_SOCACHE_FLAG_NOTMPSAFE) { diff --git a/modules/ssl/ssl_util.c b/modules/ssl/ssl_util.c index 475fe4d2..d2122784 100644 --- a/modules/ssl/ssl_util.c +++ b/modules/ssl/ssl_util.c @@ -151,7 +151,7 @@ ssl_algo_t ssl_util_algotypeof(X509 *pCert, EVP_PKEY *pKey) case EVP_PKEY_DSA: t = SSL_ALGO_DSA; break; -#ifndef OPENSSL_NO_EC +#ifdef HAVE_ECC case EVP_PKEY_EC: t = SSL_ALGO_ECC; break; @@ -177,7 +177,7 @@ char *ssl_util_algotypestr(ssl_algo_t t) case SSL_ALGO_DSA: cp = "DSA"; break; -#ifndef OPENSSL_NO_EC +#ifdef HAVE_ECC case SSL_ALGO_ECC: cp = "ECC"; break; @@ -253,7 +253,7 @@ void ssl_asn1_table_unset(apr_hash_t *table, apr_hash_set(table, key, klen, NULL); } -#ifndef OPENSSL_NO_EC +#ifdef HAVE_ECC static const char *ssl_asn1_key_types[] = {"RSA", "DSA", "ECC"}; #else static const char *ssl_asn1_key_types[] = {"RSA", "DSA"}; diff --git a/modules/ssl/ssl_util_ssl.c b/modules/ssl/ssl_util_ssl.c index a8c36adb..9f4cfa2c 100644 --- a/modules/ssl/ssl_util_ssl.c +++ b/modules/ssl/ssl_util_ssl.c @@ -483,6 +483,38 @@ BOOL SSL_X509_INFO_load_path(apr_pool_t *ptemp, /* _________________________________________________________________ ** +** Custom (EC)DH parameter support +** _________________________________________________________________ +*/ + +DH *ssl_dh_GetParamFromFile(const char *file) +{ + DH *dh = NULL; + BIO *bio; + + if ((bio = BIO_new_file(file, "r")) == NULL) + return NULL; + dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); + BIO_free(bio); + return (dh); +} + +#ifdef HAVE_ECC +EC_GROUP *ssl_ec_GetParamFromFile(const char *file) +{ + EC_GROUP *group = NULL; + BIO *bio; + + if ((bio = BIO_new_file(file, "r")) == NULL) + return NULL; + group = PEM_read_bio_ECPKParameters(bio, NULL, NULL, NULL); + BIO_free(bio); + return (group); +} +#endif + +/* _________________________________________________________________ +** ** Extra Server Certificate Chain Support ** _________________________________________________________________ */ diff --git a/modules/test/mod_optional_hook_export.h b/modules/test/mod_optional_hook_export.h index 7af68620..223f5914 100644 --- a/modules/test/mod_optional_hook_export.h +++ b/modules/test/mod_optional_hook_export.h @@ -15,7 +15,7 @@ */ #ifndef MOD_OPTIONAL_HOOK_EXPORT_H -#define MOD_OPTOPNAL_HOOK_EXPORT_H +#define MOD_OPTIONAL_HOOK_EXPORT_H #include "ap_config.h" |
