From e249e1729b11dfb8bfa27c22eff2ef1c030f1c0ad192f5e64ed048b720e65f90 Mon Sep 17 00:00:00 2001 From: Roman Drahtmueller Date: Wed, 1 Aug 2012 01:54:19 +0000 Subject: [PATCH] Accepting request 129508 from home:elvigia:branches:Apache - Upgrade to apache 2.4.2 ** ATTENTION, before installing this update YOU MUST READ http://httpd.apache.org/docs/2.4/upgrading.html CAREFULLY otherwise your server will most likely fail to start due to backward incompatible changes. * You can read the huge complete list of changes at http://httpd.apache.org/docs/2.4/new_features_2_4.html OBS-URL: https://build.opensuse.org/request/show/129508 OBS-URL: https://build.opensuse.org/package/show/Apache/apache2?expand=0&rev=370 --- apache-20-22-upgrade | 8 +- apache2-default-server.conf | 2 +- apache2-httpd.conf | 2 +- apache2-mod_ssl_npn.patch | 1398 ++++++++++- apache2.4-mpm-itk-2.4.2-01.patch | 2159 +++++++++++++++++ apache2.changes | 12 + apache2.spec | 62 +- httpd-2.0.54-envvars.dif | 16 +- httpd-2.1.9-apachectl.dif | 22 +- httpd-2.2.22.tar.bz2 | 3 - httpd-2.2.22.tar.bz2.asc | Bin 678 -> 0 bytes ...-2.2.x-CVE-2011-3368-server_protocl_c.diff | 68 - httpd-2.2.x-bnc690734.patch | 21 +- httpd-2.4.2.tar.xz | 3 + httpd-keepalivetimeout-millisecs.patch | 20 - httpd-mod_deflate_head.patch | 23 - ssl-mode-release-buffers.patch | 13 - 17 files changed, 3513 insertions(+), 319 deletions(-) create mode 100644 apache2.4-mpm-itk-2.4.2-01.patch delete mode 100644 httpd-2.2.22.tar.bz2 delete mode 100644 httpd-2.2.22.tar.bz2.asc delete mode 100644 httpd-2.2.x-CVE-2011-3368-server_protocl_c.diff create mode 100644 httpd-2.4.2.tar.xz delete mode 100644 httpd-keepalivetimeout-millisecs.patch delete mode 100644 httpd-mod_deflate_head.patch delete mode 100644 ssl-mode-release-buffers.patch diff --git a/apache-20-22-upgrade b/apache-20-22-upgrade index 6eeaaf2..561c697 100644 --- a/apache-20-22-upgrade +++ b/apache-20-22-upgrade @@ -13,7 +13,6 @@ if a2enmod -q auth; then a2enmod authz_groupfile a2enmod authz_default a2enmod authz_user - cat <<-EOF @@ -61,4 +60,11 @@ if a2enmod -q auth_ldap; then a2enmod mod_authnz_ldap fi +for module in mod_authn_default mod_authz_default mod_mem_cache; do + if a2enmod -q "$module"; then + echo "!!ATTENTION! $module was removed from apache version 2.4 or later, CHECK YOUR CONFIGURATION!!!" + a2dismod "$module" + fi +done + echo 'Done.' diff --git a/apache2-default-server.conf b/apache2-default-server.conf index fc45e52..eb12cad 100644 --- a/apache2-default-server.conf +++ b/apache2-default-server.conf @@ -102,5 +102,5 @@ ScriptAlias /cgi-bin/ "/srv/www/cgi-bin/" Include /etc/apache2/conf.d/*.conf # The manual... if it is installed ('?' means it won't complain) -Include /etc/apache2/conf.d/apache2-manual?conf +IncludeOptional /etc/apache2/conf.d/apache2-manual?conf diff --git a/apache2-httpd.conf b/apache2-httpd.conf index 696da7a..fe1f272 100644 --- a/apache2-httpd.conf +++ b/apache2-httpd.conf @@ -202,7 +202,7 @@ Include /etc/apache2/sysconfig.d/include.conf # You may use the command line option '-S' to verify your virtual host # configuration. # -Include /etc/apache2/vhosts.d/*.conf +IncludeOptional /etc/apache2/vhosts.d/*.conf # Note: instead of adding your own configuration here, consider diff --git a/apache2-mod_ssl_npn.patch b/apache2-mod_ssl_npn.patch index 246cd74..4162345 100644 --- a/apache2-mod_ssl_npn.patch +++ b/apache2-mod_ssl_npn.patch @@ -1,51 +1,658 @@ -# This patch adds hooks for Next Protocol Negotiation (NPN) into mod_ssl. This -# change is under review to be included in Apache trunk: -# https://issues.apache.org/bugzilla/show_bug.cgi?id=52210 -# But until it becomes part of an Apache 2.2 release, we need to apply the patch -# ourselves. -Index: modules/ssl/ssl_private.h -=================================================================== ---- modules/ssl/ssl_private.h (revision 1202283) -+++ modules/ssl/ssl_private.h (working copy) -@@ -603,6 +603,7 @@ - #ifndef OPENSSL_NO_TLSEXT - int ssl_callback_ServerNameIndication(SSL *, int *, modssl_ctx_t *); - #endif -+int ssl_callback_AdvertiseNextProtos(SSL *ssl, const unsigned char **data, unsigned int *len, void *arg); +diff --git a/modules/ssl/mod_ssl.c b/modules/ssl/mod_ssl.c +index fe7aeae..0ca336f 100644 +--- a/modules/ssl/mod_ssl.c ++++ b/modules/ssl/mod_ssl.c +@@ -94,6 +94,15 @@ static const command_rec ssl_config_cmds[] = { + SSL_CMD_SRV(PKCS7CertificateFile, TAKE1, + "PKCS#7 file containing server certificate and chain" + " certificates ('/path/to/file' - PEM encoded)") ++ SSL_CMD_ALL(RSAAuthzFile, TAKE1, ++ "RFC 5878 Authz Extension file for RSA certificate " ++ "(`/path/to/file')") ++ SSL_CMD_ALL(DSAAuthzFile, TAKE1, ++ "RFC 5878 Authz Extension file for DSA certificate " ++ "(`/path/to/file')") ++ SSL_CMD_ALL(ECAuthzFile, TAKE1, ++ "RFC 5878 Authz Extension file for EC certificate " ++ "(`/path/to/file')") + #ifdef HAVE_TLS_SESSION_TICKETS + SSL_CMD_SRV(SessionTicketKeyFile, TAKE1, + "TLS session ticket encryption/decryption key file (RFC 5077) " +@@ -138,6 +147,9 @@ static const command_rec ssl_config_cmds[] = { + "('[+-][" SSL_PROTOCOLS "] ...' - see manual)") + SSL_CMD_SRV(HonorCipherOrder, FLAG, + "Use the server's cipher ordering preference") ++ SSL_CMD_SRV(Compression, FLAG, ++ "Enable SSL level compression" ++ "(`on', `off')") + SSL_CMD_SRV(InsecureRenegotiation, FLAG, + "Enable support for insecure renegotiation") + SSL_CMD_ALL(UserName, TAKE1, +@@ -145,6 +157,15 @@ static const command_rec ssl_config_cmds[] = { + SSL_CMD_SRV(StrictSNIVHostCheck, FLAG, + "Strict SNI virtual host checking") - /** Session Cache Support */ - void ssl_scache_init(server_rec *, apr_pool_t *); -@@ -714,4 +715,3 @@ ++#ifndef OPENSSL_NO_SRP ++ SSL_CMD_SRV(SRPVerifierFile, TAKE1, ++ "SRP verifier file " ++ "('/path/to/file' - created by srptool)") ++ SSL_CMD_SRV(SRPUnknownUserSeed, TAKE1, ++ "SRP seed for unknown users (to avoid leaking a user's existence) " ++ "('some secret text')") ++#endif ++ + /* + * Proxy configuration for remote SSL connections + */ +@@ -260,6 +281,18 @@ static const command_rec ssl_config_cmds[] = { + AP_END_CMD + }; - #endif /* SSL_PRIVATE_H */ ++/* Implement 'modssl_run_npn_advertise_protos_hook'. */ ++APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL( ++ modssl, AP, int, npn_advertise_protos_hook, ++ (conn_rec *connection, apr_array_header_t *protos), ++ (connection, protos), OK, DECLINED); ++ ++/* Implement 'modssl_run_npn_proto_negotiated_hook'. */ ++APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL( ++ modssl, AP, int, npn_proto_negotiated_hook, ++ (conn_rec *connection, const char *proto_name, apr_size_t proto_name_len), ++ (connection, proto_name, proto_name_len), OK, DECLINED); ++ + /* + * the various processing hooks + */ +diff --git a/modules/ssl/mod_ssl.h b/modules/ssl/mod_ssl.h +index 48984e2..0280a68 100644 +--- a/modules/ssl/mod_ssl.h ++++ b/modules/ssl/mod_ssl.h +@@ -63,5 +63,26 @@ APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *)); + + APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *)); + ++/** The npn_advertise_protos optional hook allows other modules to add entries ++ * to the list of protocol names advertised by the server during the Next ++ * Protocol Negotiation (NPN) portion of the SSL handshake. The hook callee is ++ * given the connection and an APR array; it should push one or more char*'s ++ * pointing to null-terminated strings (such as "http/1.1" or "spdy/2") onto ++ * the array and return OK, or do nothing and return DECLINED. */ ++APR_DECLARE_EXTERNAL_HOOK(modssl, AP, int, npn_advertise_protos_hook, ++ (conn_rec *connection, apr_array_header_t *protos)); ++ ++/** The npn_proto_negotiated optional hook allows other modules to discover the ++ * name of the protocol that was chosen during the Next Protocol Negotiation ++ * (NPN) portion of the SSL handshake. Note that this may be the empty string ++ * (in which case modules should probably assume HTTP), or it may be a protocol ++ * that was never even advertised by the server. The hook callee is given the ++ * connection, a non-null-terminated string containing the protocol name, and ++ * the length of the string; it should do something appropriate (i.e. insert or ++ * remove filters) and return OK, or do nothing and return DECLINED. */ ++APR_DECLARE_EXTERNAL_HOOK(modssl, AP, int, npn_proto_negotiated_hook, ++ (conn_rec *connection, const char *proto_name, ++ apr_size_t proto_name_len)); ++ + #endif /* __MOD_SSL_H__ */ /** @} */ -- -Index: modules/ssl/ssl_engine_init.c -=================================================================== ---- modules/ssl/ssl_engine_init.c (revision 1202283) -+++ modules/ssl/ssl_engine_init.c (working copy) -@@ -559,6 +559,11 @@ - SSL_CTX_set_tmp_dh_callback(ctx, ssl_callback_TmpDH); +diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c +index 6aab764..39f20f9 100644 +--- a/modules/ssl/ssl_engine_config.c ++++ b/modules/ssl/ssl_engine_config.c +@@ -125,6 +125,10 @@ static void modssl_ctx_init(modssl_ctx_t *mctx) + mctx->crl_file = NULL; + mctx->crl_check_mode = SSL_CRLCHECK_UNSET; + ++ mctx->rsa_authz_file = NULL; ++ mctx->dsa_authz_file = NULL; ++ mctx->ec_authz_file = NULL; ++ + mctx->auth.ca_cert_path = NULL; + mctx->auth.ca_cert_file = NULL; + mctx->auth.cipher_suite = NULL; +@@ -149,6 +153,12 @@ static void modssl_ctx_init(modssl_ctx_t *mctx) + mctx->stapling_responder_timeout = UNSET; + mctx->stapling_force_url = NULL; + #endif ++ ++#ifndef OPENSSL_NO_SRP ++ mctx->srp_vfile = NULL; ++ mctx->srp_unknown_user_seed = NULL; ++ mctx->srp_vbase = NULL; ++#endif + } + + static void modssl_ctx_init_proxy(SSLSrvConfigRec *sc, +@@ -207,6 +217,9 @@ static SSLSrvConfigRec *ssl_config_server_new(apr_pool_t *p) + #ifdef HAVE_FIPS + sc->fips = UNSET; + #endif ++#ifndef OPENSSL_NO_COMP ++ sc->compression = UNSET; ++#endif + + modssl_ctx_init_proxy(sc, p); + +@@ -248,6 +261,10 @@ static void modssl_ctx_cfg_merge(modssl_ctx_t *base, + cfgMerge(crl_file, NULL); + cfgMerge(crl_check_mode, SSL_CRLCHECK_UNSET); + ++ cfgMergeString(rsa_authz_file); ++ cfgMergeString(dsa_authz_file); ++ cfgMergeString(ec_authz_file); ++ + cfgMergeString(auth.ca_cert_path); + cfgMergeString(auth.ca_cert_file); + cfgMergeString(auth.cipher_suite); +@@ -271,6 +288,11 @@ static void modssl_ctx_cfg_merge(modssl_ctx_t *base, + cfgMergeInt(stapling_responder_timeout); + cfgMerge(stapling_force_url, NULL); + #endif ++ ++#ifndef OPENSSL_NO_SRP ++ cfgMergeString(srp_vfile); ++ cfgMergeString(srp_unknown_user_seed); ++#endif + } + + static void modssl_ctx_cfg_merge_proxy(modssl_ctx_t *base, +@@ -328,6 +350,9 @@ void *ssl_config_server_merge(apr_pool_t *p, void *basev, void *addv) + #ifdef HAVE_FIPS + cfgMergeBool(fips); + #endif ++#ifndef OPENSSL_NO_COMP ++ cfgMergeBool(compression); ++#endif + + modssl_ctx_cfg_merge_proxy(base->proxy, add->proxy, mrg->proxy); + +@@ -663,6 +688,23 @@ static const char *ssl_cmd_check_file(cmd_parms *parms, + + } + ++const char *ssl_cmd_SSLCompression(cmd_parms *cmd, void *dcfg, int flag) ++{ ++#if !defined(OPENSSL_NO_COMP) ++ SSLSrvConfigRec *sc = mySrvConfig(cmd->server); ++#ifndef SSL_OP_NO_COMPRESSION ++ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); ++ if (err) ++ return "This version of openssl does not support configuring " ++ "compression within sections."; ++#endif ++ sc->compression = flag ? TRUE : FALSE; ++ return NULL; ++#else ++ return "Setting Compression mode unsupported; not implemented by the SSL library"; ++#endif ++} ++ + const char *ssl_cmd_SSLHonorCipherOrder(cmd_parms *cmd, void *dcfg, int flag) + { + #ifdef SSL_OP_CIPHER_SERVER_PREFERENCE +@@ -806,6 +848,54 @@ const char *ssl_cmd_SSLPKCS7CertificateFile(cmd_parms *cmd, + return NULL; + } + ++const char *ssl_cmd_SSLRSAAuthzFile(cmd_parms *cmd, ++ void *dcfg, ++ const char *arg) ++{ ++ SSLSrvConfigRec *sc = mySrvConfig(cmd->server); ++ const char *err; ++ ++ if ((err = ssl_cmd_check_file(cmd, &arg))) { ++ return err; ++ } ++ ++ sc->server->rsa_authz_file = arg; ++ ++ return NULL; ++} ++ ++const char *ssl_cmd_SSLDSAAuthzFile(cmd_parms *cmd, ++ void *dcfg, ++ const char *arg) ++{ ++ SSLSrvConfigRec *sc = mySrvConfig(cmd->server); ++ const char *err; ++ ++ if ((err = ssl_cmd_check_file(cmd, &arg))) { ++ return err; ++ } ++ ++ sc->server->dsa_authz_file = arg; ++ ++ return NULL; ++} ++ ++const char *ssl_cmd_SSLECAuthzFile(cmd_parms *cmd, ++ void *dcfg, ++ const char *arg) ++{ ++ SSLSrvConfigRec *sc = mySrvConfig(cmd->server); ++ const char *err; ++ ++ if ((err = ssl_cmd_check_file(cmd, &arg))) { ++ return err; ++ } ++ ++ sc->server->ec_authz_file = arg; ++ ++ return NULL; ++} ++ + #ifdef HAVE_TLS_SESSION_TICKETS + const char *ssl_cmd_SSLSessionTicketKeyFile(cmd_parms *cmd, + void *dcfg, +@@ -1759,6 +1849,32 @@ const char *ssl_cmd_SSLStaplingForceURL(cmd_parms *cmd, void *dcfg, + + #endif /* HAVE_OCSP_STAPLING */ + ++#ifndef OPENSSL_NO_SRP ++ ++const char *ssl_cmd_SSLSRPVerifierFile(cmd_parms *cmd, void *dcfg, ++ const char *arg) ++{ ++ SSLSrvConfigRec *sc = mySrvConfig(cmd->server); ++ const char *err; ++ ++ if ((err = ssl_cmd_check_file(cmd, &arg))) ++ return err; ++ /* SRP_VBASE_init takes char*, not const char* */ ++ sc->server->srp_vfile = apr_pstrdup(cmd->pool, arg); ++ return NULL; ++} ++ ++const char *ssl_cmd_SSLSRPUnknownUserSeed(cmd_parms *cmd, void *dcfg, ++ const char *arg) ++{ ++ SSLSrvConfigRec *sc = mySrvConfig(cmd->server); ++ /* SRP_VBASE_new takes char*, not const char* */ ++ sc->server->srp_unknown_user_seed = apr_pstrdup(cmd->pool, arg); ++ return NULL; ++} ++ ++#endif /* OPENSSL_NO_SRP */ ++ + void ssl_hook_ConfigTest(apr_pool_t *pconf, server_rec *s) + { + apr_file_t *out = NULL; +diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c +index 5d81647..8cdc29a 100644 +--- a/modules/ssl/ssl_engine_init.c ++++ b/modules/ssl/ssl_engine_init.c +@@ -349,7 +349,7 @@ int ssl_init_Module(apr_pool_t *p, apr_pool_t *plog, + else { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01885) "FIPS mode failed"); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); +- ssl_die(); ++ ssl_die(s); + } + } + } +@@ -438,7 +438,7 @@ void ssl_init_Engine(server_rec *s, apr_pool_t *p) + "Init: Failed to load Crypto Device API `%s'", + mc->szCryptoDevice); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); +- ssl_die(); ++ ssl_die(s); + } + + if (strEQ(mc->szCryptoDevice, "chil")) { +@@ -450,7 +450,7 @@ void ssl_init_Engine(server_rec *s, apr_pool_t *p) + "Init: Failed to enable Crypto Device API `%s'", + mc->szCryptoDevice); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); +- ssl_die(); ++ ssl_die(s); + } + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(01890) + "Init: loaded Crypto Device API `%s'", +@@ -473,7 +473,7 @@ static void ssl_init_server_check(server_rec *s, + if (!mctx->pks->cert_files[0] && !mctx->pkcs7) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01891) + "No SSL Certificate set [hint: SSLCertificateFile]"); +- ssl_die(); ++ ssl_die(s); + } + + /* +@@ -489,7 +489,7 @@ static void ssl_init_server_check(server_rec *s, + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01892) + "Illegal attempt to re-initialise SSL for server " + "(SSLEngine On should go in the VirtualHost, not in global scope.)"); +- ssl_die(); ++ ssl_die(s); + } + } + +@@ -515,7 +515,7 @@ static void ssl_init_ctx_tls_extensions(server_rec *s, + "Unable to initialize TLS servername extension " + "callback (incompatible OpenSSL version?)"); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); +- ssl_die(); ++ ssl_die(s); + } + + #ifdef HAVE_OCSP_STAPLING +@@ -526,6 +526,38 @@ static void ssl_init_ctx_tls_extensions(server_rec *s, + modssl_init_stapling(s, p, ptemp, mctx); + } + #endif ++ ++#ifndef OPENSSL_NO_SRP ++ /* ++ * TLS-SRP support ++ */ ++ if (mctx->srp_vfile != NULL) { ++ int err; ++ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02308) ++ "Using SRP verifier file [%s]", mctx->srp_vfile); ++ ++ if (!(mctx->srp_vbase = SRP_VBASE_new(mctx->srp_unknown_user_seed))) { ++ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02309) ++ "Unable to initialize SRP verifier structure " ++ "[%s seed]", ++ mctx->srp_unknown_user_seed ? "with" : "without"); ++ ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); ++ ssl_die(s); ++ } ++ ++ err = SRP_VBASE_init(mctx->srp_vbase, mctx->srp_vfile); ++ if (err != SRP_NO_ERROR) { ++ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02310) ++ "Unable to load SRP verifier file [error %d]", err); ++ ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); ++ ssl_die(s); ++ } ++ ++ SSL_CTX_set_srp_username_callback(mctx->ssl_ctx, ++ ssl_callback_SRPServerParams); ++ SSL_CTX_set_srp_cb_arg(mctx->ssl_ctx, mctx); ++ } ++#endif + } + #endif + +@@ -546,7 +578,7 @@ static void ssl_init_ctx_protocol(server_rec *s, + if (protocol == SSL_PROTOCOL_NONE) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02231) + "No SSL protocols available [hint: SSLProtocol]"); +- ssl_die(); ++ ssl_die(s); + } + + cp = apr_pstrcat(p, +@@ -622,6 +654,18 @@ static void ssl_init_ctx_protocol(server_rec *s, + } + #endif + ++ ++#ifndef OPENSSL_NO_COMP ++ if (sc->compression == FALSE) { ++#ifdef SSL_OP_NO_COMPRESSION ++ /* OpenSSL >= 1.0 only */ ++ SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION); ++#elif OPENSSL_VERSION_NUMBER >= 0x00908000L ++ sk_SSL_COMP_zero(SSL_COMP_get_compression_methods()); ++#endif ++ } ++#endif ++ + #ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION + if (sc->insecure_reneg == TRUE) { + SSL_CTX_set_options(ctx, SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION); +@@ -681,6 +725,11 @@ static void ssl_init_ctx_callbacks(server_rec *s, + #endif SSL_CTX_set_info_callback(ctx, ssl_callback_Info); + -+#if OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) ++#ifdef HAVE_TLS_NPN + SSL_CTX_set_next_protos_advertised_cb( + ctx, ssl_callback_AdvertiseNextProtos, NULL); +#endif } static void ssl_init_ctx_verify(server_rec *s, -@@ -1352,4 +1357,3 @@ +@@ -731,7 +780,7 @@ static void ssl_init_ctx_verify(server_rec *s, + "Unable to configure verify locations " + "for client authentication"); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); +- ssl_die(); ++ ssl_die(s); + } - return APR_SUCCESS; + if (mctx->pks && (mctx->pks->ca_name_file || mctx->pks->ca_name_path)) { +@@ -746,7 +795,7 @@ static void ssl_init_ctx_verify(server_rec *s, + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01896) + "Unable to determine list of acceptable " + "CA certificates for client authentication"); +- ssl_die(); ++ ssl_die(s); + } + + SSL_CTX_set_client_CA_list(ctx, ca_list); +@@ -791,7 +840,7 @@ static void ssl_init_ctx_cipher_suite(server_rec *s, + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01898) + "Unable to configure permitted SSL ciphers"); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); +- ssl_die(); ++ ssl_die(s); + } } -- -Index: modules/ssl/ssl_engine_io.c -=================================================================== ---- modules/ssl/ssl_engine_io.c (revision 1202283) -+++ modules/ssl/ssl_engine_io.c (working copy) -@@ -338,6 +338,7 @@ + +@@ -815,7 +864,7 @@ static void ssl_init_ctx_crl(server_rec *s, + "Host %s: CRL checking has been enabled, but " + "neither %sCARevocationFile nor %sCARevocationPath " + "is configured", mctx->sc->vhost_id, cfgp, cfgp); +- ssl_die(); ++ ssl_die(s); + } + return; + } +@@ -829,7 +878,7 @@ static void ssl_init_ctx_crl(server_rec *s, + "Host %s: unable to configure X.509 CRL storage " + "for certificate revocation", mctx->sc->vhost_id); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); +- ssl_die(); ++ ssl_die(s); + } + + switch (mctx->crl_check_mode) { +@@ -915,7 +964,7 @@ static void ssl_init_ctx_cert_chain(server_rec *s, + if (n < 0) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01903) + "Failed to configure CA certificate chain!"); +- ssl_die(); ++ ssl_die(s); + } + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01904) +@@ -953,7 +1002,8 @@ static void ssl_init_ctx(server_rec *s, + static int ssl_server_import_cert(server_rec *s, + modssl_ctx_t *mctx, + const char *id, +- int idx) ++ int idx, ++ const char *authz_file) + { + SSLModConfigRec *mc = myModConfig(s); + ssl_asn1_t *asn1; +@@ -973,14 +1023,14 @@ static int ssl_server_import_cert(server_rec *s, + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02233) + "Unable to import %s server certificate", type); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); +- ssl_die(); ++ ssl_die(s); + } + + if (SSL_CTX_use_certificate(mctx->ssl_ctx, cert) <= 0) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02234) + "Unable to configure %s server certificate", type); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); +- ssl_die(); ++ ssl_die(s); + } + + #ifdef HAVE_OCSP_STAPLING +@@ -992,6 +1042,24 @@ static int ssl_server_import_cert(server_rec *s, + } + #endif + ++ if (authz_file) { ++#if !defined(OPENSSL_NO_TLSEXT) && OPENSSL_VERSION_NUMBER >= 0x10002000L ++ if (!SSL_CTX_use_authz_file(mctx->ssl_ctx, authz_file)) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, ++ "Unable to initialize TLS authz extension"); ++ ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s); ++ ssl_die(s); ++ } ++ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, "Set %s authz_file to %s", ++ type, authz_file); ++#else ++ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, ++ "Unable to initialize TLS authz extension: " ++ "OpenSSL version too low"); ++ ssl_die(s); ++#endif ++ } ++ + mctx->pks->certs[idx] = cert; + + return TRUE; +@@ -1029,14 +1097,14 @@ static int ssl_server_import_key(server_rec *s, + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02237) + "Unable to import %s server private key", type); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); +- ssl_die(); ++ ssl_die(s); + } + + if (SSL_CTX_use_PrivateKey(mctx->ssl_ctx, pkey) <= 0) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02238) + "Unable to configure %s server private key", type); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); +- ssl_die(); ++ ssl_die(s); + } + + /* +@@ -1174,10 +1242,13 @@ static void ssl_init_server_certs(server_rec *s, + 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); ++ have_rsa = ssl_server_import_cert(s, mctx, rsa_id, SSL_AIDX_RSA, ++ mctx->rsa_authz_file); ++ have_dsa = ssl_server_import_cert(s, mctx, dsa_id, SSL_AIDX_DSA, ++ mctx->dsa_authz_file); + #ifndef OPENSSL_NO_EC +- have_ecc = ssl_server_import_cert(s, mctx, ecc_id, SSL_AIDX_ECC); ++ have_ecc = ssl_server_import_cert(s, mctx, ecc_id, SSL_AIDX_ECC, ++ mctx->ec_authz_file); + #endif + + if (!(have_rsa || have_dsa +@@ -1188,7 +1259,7 @@ static void ssl_init_server_certs(server_rec *s, + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01910) + "Oops, no " KEYTYPES " server certificate found " + "for '%s:%d'?!", s->server_hostname, s->port); +- ssl_die(); ++ ssl_die(s); + } + + for (i = 0; i < SSL_AIDX_MAX; i++) { +@@ -1208,7 +1279,7 @@ static void ssl_init_server_certs(server_rec *s, + )) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01911) + "Oops, no " KEYTYPES " server private key found?!"); +- ssl_die(); ++ ssl_die(s); + } + } + +@@ -1238,7 +1309,7 @@ static void ssl_init_ticket_key(server_rec *s, + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02286) + "Failed to open ticket key file %s: (%d) %pm", + path, rv, &rv); +- ssl_die(); ++ ssl_die(s); + } + + rv = apr_file_read_full(fp, &buf[0], TLSEXT_TICKET_KEY_LEN, &len); +@@ -1247,7 +1318,7 @@ static void ssl_init_ticket_key(server_rec *s, + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02287) + "Failed to read %d bytes from %s: (%d) %pm", + TLSEXT_TICKET_KEY_LEN, path, rv, &rv); +- ssl_die(); ++ ssl_die(s); + } + + memcpy(ticket_key->key_name, buf, 16); +@@ -1260,7 +1331,7 @@ static void ssl_init_ticket_key(server_rec *s, + "Unable to initialize TLS session ticket key callback " + "(incompatible OpenSSL version?)"); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); +- ssl_die(); ++ ssl_die(s); + } + + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(02288) +@@ -1315,7 +1386,7 @@ static void ssl_init_proxy_certs(server_rec *s, + ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, APLOGNO(02252) + "incomplete client cert configured for SSL proxy " + "(missing or encrypted private key?)"); +- ssl_die(); ++ ssl_die(s); + return; + } + } +@@ -1338,7 +1409,7 @@ static void ssl_init_proxy_certs(server_rec *s, + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02208) + "SSL proxy client cert initialization failed"); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); +- ssl_die(); ++ ssl_die(s); + } + + X509_STORE_load_locations(store, pkp->ca_cert_file, NULL); +@@ -1628,7 +1699,7 @@ STACK_OF(X509_NAME) *ssl_init_FindCAList(server_rec *s, + ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(02211) + "Failed to open Certificate Path `%s'", + ca_path); +- ssl_die(); ++ ssl_die(s); + } + + while ((apr_dir_read(&direntry, finfo_flags, dir)) == APR_SUCCESS) { +@@ -1675,6 +1746,13 @@ void ssl_init_Child(apr_pool_t *p, server_rec *s) + static void ssl_init_ctx_cleanup(modssl_ctx_t *mctx) + { + MODSSL_CFG_ITEM_FREE(SSL_CTX_free, mctx->ssl_ctx); ++ ++#ifndef OPENSSL_NO_SRP ++ if (mctx->srp_vbase != NULL) { ++ SRP_VBASE_free(mctx->srp_vbase); ++ mctx->srp_vbase = NULL; ++ } ++#endif + } + + static void ssl_init_ctx_cleanup_proxy(modssl_ctx_t *mctx) +diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c +index 2ffe21f..12c9c7f 100644 +--- a/modules/ssl/ssl_engine_io.c ++++ b/modules/ssl/ssl_engine_io.c +@@ -28,6 +28,7 @@ + core keeps dumping.'' + -- Unknown */ + #include "ssl_private.h" ++#include "mod_ssl.h" + #include "apr_date.h" + + /* _________________________________________________________________ +@@ -297,6 +298,7 @@ typedef struct { apr_pool_t *pool; char buffer[AP_IOBUFSIZE]; ssl_filter_ctx_t *filter_ctx; @@ -53,44 +660,212 @@ Index: modules/ssl/ssl_engine_io.c } bio_filter_in_ctx_t; /* -@@ -1409,6 +1410,21 @@ +@@ -813,12 +815,12 @@ static apr_status_t ssl_filter_write(ap_filter_t *f, + /* Just use a simple request. Any request will work for this, because + * we use a flag in the conn_rec->conn_vector now. The fake request just + * gets the request back to the Apache core so that a response can be sent. +- * +- * To avoid calling back for more data from the socket, use an HTTP/0.9 +- * request, and tack on an EOS bucket. ++ * Since we use an HTTP/1.x request, we also have to inject the empty line ++ * that terminates the headers, or the core will read more data from the ++ * socket. + */ + #define HTTP_ON_HTTPS_PORT \ +- "GET /" CRLF ++ "GET / HTTP/1.0" CRLF + + #define HTTP_ON_HTTPS_PORT_BUCKET(alloc) \ + apr_bucket_immortal_create(HTTP_ON_HTTPS_PORT, \ +@@ -848,6 +850,7 @@ static apr_status_t ssl_io_filter_error(ap_filter_t *f, + { + SSLConnRec *sslconn = myConnConfig(f->c); + apr_bucket *bucket; ++ int send_eos = 1; + + switch (status) { + case MODSSL_ERROR_HTTP_ON_HTTPS: +@@ -857,11 +860,12 @@ static apr_status_t ssl_io_filter_error(ap_filter_t *f, + "trying to send HTML error page"); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_INFO, sslconn->server); + +- sslconn->non_ssl_request = 1; ++ sslconn->non_ssl_request = NON_SSL_SEND_HDR_SEP; + ssl_io_filter_disable(sslconn, f); + + /* fake the request line */ + bucket = HTTP_ON_HTTPS_PORT_BUCKET(f->c->bucket_alloc); ++ send_eos = 0; + break; + + case MODSSL_ERROR_BAD_GATEWAY: +@@ -877,9 +881,10 @@ static apr_status_t ssl_io_filter_error(ap_filter_t *f, + } + + APR_BRIGADE_INSERT_TAIL(bb, bucket); +- bucket = apr_bucket_eos_create(f->c->bucket_alloc); +- APR_BRIGADE_INSERT_TAIL(bb, bucket); +- ++ if (send_eos) { ++ bucket = apr_bucket_eos_create(f->c->bucket_alloc); ++ APR_BRIGADE_INSERT_TAIL(bb, bucket); ++ } + return APR_SUCCESS; + } + +@@ -1282,6 +1287,13 @@ static apr_status_t ssl_io_filter_input(ap_filter_t *f, + } + + if (!inctx->ssl) { ++ SSLConnRec *sslconn = myConnConfig(f->c); ++ if (sslconn->non_ssl_request == NON_SSL_SEND_HDR_SEP) { ++ apr_bucket *bucket = apr_bucket_immortal_create(CRLF, 2, f->c->bucket_alloc); ++ APR_BRIGADE_INSERT_TAIL(bb, bucket); ++ sslconn->non_ssl_request = NON_SSL_SET_ERROR_MSG; ++ return APR_SUCCESS; ++ } + return ap_get_brigade(f->next, bb, mode, block, readbytes); + } + +@@ -1364,6 +1376,26 @@ static apr_status_t ssl_io_filter_input(ap_filter_t *f, APR_BRIGADE_INSERT_TAIL(bb, bucket); } ++#ifdef HAVE_TLS_NPN + /* By this point, Next Protocol Negotiation (NPN) should be completed (if + * our version of OpenSSL supports it). If we haven't already, find out + * which protocol was decided upon and inform other modules by calling + * npn_proto_negotiated_hook. */ + if (!inctx->npn_finished) { -+ inctx->npn_finished = 1; -+#if OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) + const unsigned char *next_proto = NULL; + unsigned next_proto_len = 0; -+ SSL_get0_next_proto_negotiated(inctx->ssl, &next_proto, -+ &next_proto_len); -+ ssl_run_npn_proto_negotiated_hook(f->c, next_proto, next_proto_len); -+#endif ++ ++ SSL_get0_next_proto_negotiated( ++ inctx->ssl, &next_proto, &next_proto_len); ++ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, f->c, ++ APLOGNO(02306) "SSL NPN negotiated protocol: '%*s'", ++ next_proto_len, (const char*)next_proto); ++ modssl_run_npn_proto_negotiated_hook( ++ f->c, (const char*)next_proto, next_proto_len); ++ inctx->npn_finished = 1; + } ++#endif + return APR_SUCCESS; } -@@ -1753,6 +1769,7 @@ +@@ -1845,6 +1877,7 @@ static void ssl_io_input_add_filter(ssl_filter_ctx_t *filter_ctx, conn_rec *c, inctx->block = APR_BLOCK_READ; inctx->pool = c->pool; inctx->filter_ctx = filter_ctx; + inctx->npn_finished = 0; } - void ssl_io_filter_init(conn_rec *c, SSL *ssl) -Index: modules/ssl/ssl_engine_kernel.c -=================================================================== ---- modules/ssl/ssl_engine_kernel.c (revision 1202283) -+++ modules/ssl/ssl_engine_kernel.c (working copy) -@@ -1969,6 +1969,77 @@ - } - } + /* The request_rec pointer is passed in here only to ensure that the +diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c +index 35b2a85..1b69d4c 100644 +--- a/modules/ssl/ssl_engine_kernel.c ++++ b/modules/ssl/ssl_engine_kernel.c +@@ -29,6 +29,7 @@ + time I was too famous.'' + -- Unknown */ + #include "ssl_private.h" ++#include "mod_ssl.h" + #include "util_md5.h" + static void ssl_configure_env(request_rec *r, SSLConnRec *sslconn); +@@ -140,37 +141,16 @@ int ssl_hook_ReadReq(request_rec *r) + return DECLINED; + } + +- if (sslconn->non_ssl_request) { +- const char *errmsg; +- char *thisurl; +- char *thisport = ""; +- int port = ap_get_server_port(r); +- +- if (!ap_is_default_port(port, r)) { +- thisport = apr_psprintf(r->pool, ":%u", port); +- } +- +- thisurl = ap_escape_html(r->pool, +- apr_psprintf(r->pool, "https://%s%s/", +- ap_get_server_name_for_url(r), +- thisport)); +- +- errmsg = apr_psprintf(r->pool, +- "Reason: You're speaking plain HTTP " +- "to an SSL-enabled server port.
\n" +- "Instead use the HTTPS scheme to access " +- "this URL, please.
\n" +- "
Hint: " +- "%s
", +- thisurl, thisurl); +- +- apr_table_setn(r->notes, "error-notes", errmsg); ++ if (sslconn->non_ssl_request == NON_SSL_SET_ERROR_MSG) { ++ apr_table_setn(r->notes, "error-notes", ++ "Reason: You're speaking plain HTTP to an SSL-enabled " ++ "server port.
\n Instead use the HTTPS scheme to " ++ "access this URL, please.
\n"); + + /* Now that we have caught this error, forget it. we are done + * with using SSL on this request. + */ +- sslconn->non_ssl_request = 0; +- ++ sslconn->non_ssl_request = NON_SSL_OK; + + return HTTP_BAD_REQUEST; + } +@@ -350,6 +330,19 @@ int ssl_hook_Access(request_rec *r) + return DECLINED; + } + ++#ifndef OPENSSL_NO_SRP ++ /* ++ * Support for per-directory reconfigured SSL connection parameters ++ * ++ * We do not force any renegotiation if the user is already authenticated ++ * via SRP. ++ * ++ */ ++ if (SSL_get_srp_username(ssl)) { ++ return DECLINED; ++ } ++#endif ++ + /* + * Support for per-directory reconfigured SSL connection parameters. + * +@@ -1109,6 +1102,10 @@ static const char *ssl_hook_Fixup_vars[] = { + "SSL_SERVER_A_SIG", + "SSL_SESSION_ID", + "SSL_SESSION_RESUMED", ++#ifndef OPENSSL_NO_SRP ++ "SSL_SRP_USER", ++ "SSL_SRP_USERINFO", ++#endif + NULL + }; + +@@ -2093,7 +2090,7 @@ static int ssl_find_vhost(void *servername, conn_rec *c, server_rec *s) + + return 0; + } +-#endif ++#endif /* OPENSSL_NO_TLSEXT */ + + #ifdef HAVE_TLS_SESSION_TICKETS + /* +@@ -2163,4 +2160,114 @@ int ssl_callback_SessionTicket(SSL *ssl, + /* OpenSSL is not expected to call us with modes other than 1 or 0 */ + return -1; + } +-#endif ++#endif /* HAVE_TLS_SESSION_TICKETS */ ++ ++#ifdef HAVE_TLS_NPN +/* + * This callback function is executed when SSL needs to decide what protocols + * to advertise during Next Protocol Negotiation (NPN). It must produce a @@ -101,55 +876,65 @@ Index: modules/ssl/ssl_engine_kernel.c +int ssl_callback_AdvertiseNextProtos(SSL *ssl, const unsigned char **data_out, + unsigned int *size_out, void *arg) +{ ++ conn_rec *c = (conn_rec*)SSL_get_app_data(ssl); ++ apr_array_header_t *protos; ++ int num_protos; ++ unsigned int size; ++ int i; ++ unsigned char *data; ++ unsigned char *start; ++ + *data_out = NULL; + *size_out = 0; + -+ /* Get the connection object. If it's not available, then there's nothing -+ * for us to do. */ -+ conn_rec *c = (conn_rec*)SSL_get_app_data(ssl); ++ /* If the connection object is not available, then there's nothing for us ++ * to do. */ + if (c == NULL) { + return SSL_TLSEXT_ERR_OK; + } + + /* Invoke our npn_advertise_protos hook, giving other modules a chance to + * add alternate protocol names to advertise. */ -+ apr_array_header_t *protos = apr_array_make(c->pool, 0, sizeof(char*)); -+ ssl_run_npn_advertise_protos_hook(c, protos); -+ int num_protos = protos->nelts; -+ -+ /* If no other modules added any alternate protocols, then we're done. */ -+ if (num_protos == 0) { -+ return SSL_TLSEXT_ERR_OK; -+ } ++ protos = apr_array_make(c->pool, 0, sizeof(char*)); ++ modssl_run_npn_advertise_protos_hook(c, protos); ++ num_protos = protos->nelts; + + /* We now have a list of null-terminated strings; we need to concatenate + * them together into a single string, where each protocol name is prefixed + * by its length. First, calculate how long that string will be. */ -+ unsigned int size = 0; -+ int i; ++ size = 0; + for (i = 0; i < num_protos; ++i) { -+ const char* string = APR_ARRAY_IDX(protos, i, const char*); ++ const char *string = APR_ARRAY_IDX(protos, i, const char*); + unsigned int length = strlen(string); + /* If the protocol name is too long (the length must fit in one byte), -+ * then log an error and quit. */ ++ * then log an error and skip it. */ + if (length > 255) { -+ ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, ++ ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02307) + "SSL NPN protocol name too long (length=%u): %s", + length, string); -+ return SSL_TLSEXT_ERR_OK; ++ continue; + } + /* Leave room for the length prefix (one byte) plus the protocol name + * itself. */ + size += 1 + length; + } + ++ /* If there is nothing to advertise (either because no modules added ++ * anything to the protos array, or because all strings added to the array ++ * were skipped), then we're done. */ ++ if (size == 0) { ++ return SSL_TLSEXT_ERR_OK; ++ } ++ + /* Now we can build the string. Copy each protocol name string into the + * larger string, prefixed by its length. */ -+ unsigned char* data = apr_palloc(c->pool, size * sizeof(unsigned char)); -+ unsigned char* start = data; ++ data = apr_palloc(c->pool, size * sizeof(unsigned char)); ++ start = data; + for (i = 0; i < num_protos; ++i) { -+ const char* string = APR_ARRAY_IDX(protos, i, const char*); -+ size_t length = strlen(string); ++ const char *string = APR_ARRAY_IDX(protos, i, const char*); ++ apr_size_t length = strlen(string); ++ if (length > 255) ++ continue; + *start = (unsigned char)length; + ++start; + memcpy(start, string, length * sizeof(unsigned char)); @@ -162,60 +947,427 @@ Index: modules/ssl/ssl_engine_kernel.c + return SSL_TLSEXT_ERR_OK; +} + - #ifndef OPENSSL_NO_TLSEXT - /* - * This callback function is executed when OpenSSL encounters an extended -Index: modules/ssl/mod_ssl.c -=================================================================== ---- modules/ssl/mod_ssl.c (revision 1202283) -+++ modules/ssl/mod_ssl.c (working copy) -@@ -220,6 +220,18 @@ - AP_END_CMD ++#endif /* HAVE_TLS_NPN */ ++ ++#ifndef OPENSSL_NO_SRP ++ ++int ssl_callback_SRPServerParams(SSL *ssl, int *ad, void *arg) ++{ ++ modssl_ctx_t *mctx = (modssl_ctx_t *)arg; ++ char *username = SSL_get_srp_username(ssl); ++ SRP_user_pwd *u; ++ ++ if (username == NULL ++ || (u = SRP_VBASE_get_by_user(mctx->srp_vbase, username)) == NULL) { ++ *ad = SSL_AD_UNKNOWN_PSK_IDENTITY; ++ return SSL3_AL_FATAL; ++ } ++ ++ if (SSL_set_srp_server_param(ssl, u->N, u->g, u->s, u->v, u->info) < 0) { ++ *ad = SSL_AD_INTERNAL_ERROR; ++ return SSL3_AL_FATAL; ++ } ++ ++ /* reset all other options */ ++ SSL_set_verify(ssl, SSL_VERIFY_NONE, ssl_callback_SSLVerify); ++ return SSL_ERROR_NONE; ++} ++ ++#endif /* OPENSSL_NO_SRP */ +diff --git a/modules/ssl/ssl_engine_log.c b/modules/ssl/ssl_engine_log.c +index 31861ca..3f6d6ed 100644 +--- a/modules/ssl/ssl_engine_log.c ++++ b/modules/ssl/ssl_engine_log.c +@@ -63,12 +63,23 @@ static const char *ssl_log_annotation(const char *error) + return ssl_log_annotate[i].cpAnnotation; + } + +-void ssl_die(void) ++void ssl_die(server_rec *s) + { ++ if (s != NULL && s->is_virtual && s->error_fname != NULL) ++ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, NULL, APLOGNO(02311) ++ "Fatal error initialising mod_ssl, exiting. " ++ "See %s for more information", ++ ap_server_root_relative(s->process->pool, ++ s->error_fname)); ++ else ++ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, NULL, APLOGNO(02312) ++ "Fatal error initialising mod_ssl, exiting."); ++ + /* + * This is used for fatal errors and here + * it is common module practice to really + * exit from the complete program. ++ * XXX: The config hooks should return errors instead of calling exit(). + */ + exit(1); + } +diff --git a/modules/ssl/ssl_engine_pphrase.c b/modules/ssl/ssl_engine_pphrase.c +index 1fa4a2e..23ccaf4 100644 +--- a/modules/ssl/ssl_engine_pphrase.c ++++ b/modules/ssl/ssl_engine_pphrase.c +@@ -196,7 +196,7 @@ void ssl_pphrase_Handle(server_rec *s, apr_pool_t *p) + "Server should be SSL-aware but has no certificate " + "configured [Hint: SSLCertificateFile] (%s:%d)", + pServ->defn_name, pServ->defn_line_number); +- ssl_die(); ++ ssl_die(pServ); + } + + /* Bitmasks for all key algorithms configured for this server; +@@ -225,14 +225,14 @@ void ssl_pphrase_Handle(server_rec *s, apr_pool_t *p) + ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(02201) + "Init: Can't open server certificate file %s", + szPath); +- ssl_die(); ++ ssl_die(s); + } + if ((pX509Cert = SSL_read_X509(szPath, NULL, NULL)) == NULL) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02241) + "Init: Unable to read server certificate from" + " file %s", szPath); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); +- ssl_die(); ++ ssl_die(s); + } + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02202) + "Init: Read server certificate from '%s'", +@@ -249,7 +249,7 @@ void ssl_pphrase_Handle(server_rec *s, apr_pool_t *p) + "Init: Multiple %s server certificates not " + "allowed", an); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); +- ssl_die(); ++ ssl_die(s); + } + algoCert |= at; + +@@ -328,7 +328,7 @@ void ssl_pphrase_Handle(server_rec *s, apr_pool_t *p) + ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(02243) + "Init: Can't open server private key file " + "%s",szPath); +- ssl_die(); ++ ssl_die(s); + } + + /* +@@ -425,7 +425,7 @@ void ssl_pphrase_Handle(server_rec *s, apr_pool_t *p) + "Init: SSLPassPhraseDialog builtin is not " + "supported on Win32 (key file " + "%s)", szPath); +- ssl_die(); ++ ssl_die(s); + } + #endif /* WIN32 */ + +@@ -464,7 +464,7 @@ void ssl_pphrase_Handle(server_rec *s, apr_pool_t *p) + apr_file_printf(writetty, "**Stopped\n"); + } + } +- ssl_die(); ++ ssl_die(pServ); + } + + /* If a cached private key was found, nothing more to do +@@ -479,7 +479,7 @@ void ssl_pphrase_Handle(server_rec *s, apr_pool_t *p) + "file %s [Hint: Perhaps it is in a separate file? " + " See SSLCertificateKeyFile]", szPath); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); +- ssl_die(); ++ ssl_die(s); + } + + /* +@@ -493,7 +493,7 @@ void ssl_pphrase_Handle(server_rec *s, apr_pool_t *p) + "Init: Multiple %s server private keys not " + "allowed", an); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); +- ssl_die(); ++ ssl_die(s); + } + algoKey |= at; + +diff --git a/modules/ssl/ssl_engine_vars.c b/modules/ssl/ssl_engine_vars.c +index febc176..8af1c26 100644 +--- a/modules/ssl/ssl_engine_vars.c ++++ b/modules/ssl/ssl_engine_vars.c +@@ -395,6 +395,18 @@ 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 ++ else if (ssl != NULL && strcEQ(var, "SRP_USER")) { ++ if ((result = SSL_get_srp_username(ssl)) != NULL) { ++ result = apr_pstrdup(p, result); ++ } ++ } ++ else if (ssl != NULL && strcEQ(var, "SRP_USERINFO")) { ++ if ((result = SSL_get_srp_userinfo(ssl)) != NULL) { ++ result = apr_pstrdup(p, result); ++ } ++ } ++#endif + + return result; + } +diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h +index 1b5d042..63e401d 100644 +--- a/modules/ssl/ssl_private.h ++++ b/modules/ssl/ssl_private.h +@@ -139,6 +139,11 @@ + #define HAVE_FIPS + #endif + ++#if OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_NEXTPROTONEG) \ ++ && !defined(OPENSSL_NO_TLSEXT) ++#define HAVE_TLS_NPN ++#endif ++ + #if (OPENSSL_VERSION_NUMBER >= 0x10000000) + #define MODSSL_SSL_CIPHER_CONST const + #define MODSSL_SSL_METHOD_CONST const +@@ -180,6 +185,20 @@ + #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 ++#include ++#else ++#define OPENSSL_NO_SRP ++#endif ++#endif ++ + /* mod_ssl headers */ + #include "ssl_util_ssl.h" + +@@ -454,7 +473,11 @@ typedef struct { + int verify_depth; + int is_proxy; + int disabled; +- int non_ssl_request; ++ enum { ++ NON_SSL_OK = 0, /* is SSL request, or error handling completed */ ++ NON_SSL_SEND_HDR_SEP, /* Need to send the header separator */ ++ NON_SSL_SET_ERROR_MSG /* Need to set the error message */ ++ } non_ssl_request; + + /* Track the handshake/renegotiation state for the connection so + * that all client-initiated renegotiations can be rejected, as a +@@ -638,6 +661,17 @@ typedef struct { + const char *stapling_force_url; + #endif + ++#ifndef OPENSSL_NO_SRP ++ char *srp_vfile; ++ char *srp_unknown_user_seed; ++ SRP_VBASE *srp_vbase; ++#endif ++ ++ /** RFC 5878 */ ++ const char *rsa_authz_file; ++ const char *dsa_authz_file; ++ const char *ec_authz_file; ++ + modssl_auth_ctx_t auth; + + BOOL ocsp_enabled; /* true if OCSP verification enabled */ +@@ -669,6 +703,9 @@ struct SSLSrvConfigRec { + #ifdef HAVE_FIPS + BOOL fips; + #endif ++#ifndef OPENSSL_NO_COMP ++ BOOL compression; ++#endif }; -+/* Implement 'ssl_run_npn_advertise_protos_hook'. */ -+APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL( -+ ssl, AP, int, npn_advertise_protos_hook, -+ (conn_rec* connection, apr_array_header_t* protos), -+ (connection, protos), OK, DECLINED); -+ -+/* Implement 'ssl_run_npn_proto_negotiated_hook'. */ -+APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL( -+ ssl, AP, int, npn_proto_negotiated_hook, -+ (conn_rec* connection, char* proto_name, apr_size_t proto_name_len), -+ (connection, proto_name, proto_name_len), OK, DECLINED); -+ - /* - * the various processing hooks - */ -Index: modules/ssl/mod_ssl.h -=================================================================== ---- modules/ssl/mod_ssl.h (revision 1202283) -+++ modules/ssl/mod_ssl.h (working copy) -@@ -60,5 +60,26 @@ + /** +@@ -711,6 +748,9 @@ const char *ssl_cmd_SSLCryptoDevice(cmd_parms *, void *, const char *); + const char *ssl_cmd_SSLRandomSeed(cmd_parms *, void *, const char *, const char *, const char *); + const char *ssl_cmd_SSLEngine(cmd_parms *, void *, const char *); + const char *ssl_cmd_SSLCipherSuite(cmd_parms *, void *, const char *); ++const char *ssl_cmd_SSLRSAAuthzFile(cmd_parms *, void *, const char *); ++const char *ssl_cmd_SSLDSAAuthzFile(cmd_parms *, void *, const char *); ++const char *ssl_cmd_SSLECAuthzFile(cmd_parms *, void *, const char *); + const char *ssl_cmd_SSLCertificateFile(cmd_parms *, void *, const char *); + const char *ssl_cmd_SSLCertificateKeyFile(cmd_parms *, void *, const char *); + const char *ssl_cmd_SSLCertificateChainFile(cmd_parms *, void *, const char *); +@@ -723,6 +763,7 @@ const char *ssl_cmd_SSLCARevocationPath(cmd_parms *, void *, const char *); + const char *ssl_cmd_SSLCARevocationFile(cmd_parms *, void *, const char *); + const char *ssl_cmd_SSLCARevocationCheck(cmd_parms *, void *, const char *); + const char *ssl_cmd_SSLHonorCipherOrder(cmd_parms *cmd, void *dcfg, int flag); ++const char *ssl_cmd_SSLCompression(cmd_parms *, void *, int flag); + const char *ssl_cmd_SSLVerifyClient(cmd_parms *, void *, const char *); + const char *ssl_cmd_SSLVerifyDepth(cmd_parms *, void *, const char *); + const char *ssl_cmd_SSLSessionCache(cmd_parms *, void *, const char *); +@@ -762,6 +803,11 @@ 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); - APR_DECLARE_OPTIONAL_FN(apr_array_header_t *, ssl_extlist_by_oid, (request_rec *r, const char *oidstr)); ++#ifndef OPENSSL_NO_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 ++ + const char *ssl_cmd_SSLFIPS(cmd_parms *cmd, void *dcfg, int flag); -+/** The npn_advertise_protos optional hook allows other modules to add entries -+ * to the list of protocol names advertised by the server during the Next -+ * Protocol Negotiation (NPN) portion of the SSL handshake. The hook callee is -+ * given the connection and an APR array; it should push one or more char*'s -+ * pointing to null-terminated strings (such as "http/1.1" or "spdy/2") onto -+ * the array and return OK, or do nothing and return DECLINED. */ -+APR_DECLARE_EXTERNAL_HOOK(ssl, AP, int, npn_advertise_protos_hook, -+ (conn_rec* connection, apr_array_header_t* protos)); + /** module initialization */ +@@ -807,6 +853,7 @@ int ssl_callback_ServerNameIndication(SSL *, int *, modssl_ctx_t *); + int ssl_callback_SessionTicket(SSL *, unsigned char *, unsigned char *, + EVP_CIPHER_CTX *, HMAC_CTX *, int); + #endif ++int ssl_callback_AdvertiseNextProtos(SSL *ssl, const unsigned char **data, unsigned int *len, void *arg); + + /** Session Cache Support */ + void ssl_scache_init(server_rec *, apr_pool_t *); +@@ -838,6 +885,9 @@ 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 ++int ssl_callback_SRPServerParams(SSL *, int *, void *); ++#endif + + /** I/O */ + void ssl_io_filter_init(conn_rec *, request_rec *r, SSL *); +@@ -902,7 +952,7 @@ int ssl_stapling_mutex_reinit(server_rec *, apr_pool_t *); + #define SSL_STAPLING_MUTEX_TYPE "ssl-stapling" + + /** Logfile Support */ +-void ssl_die(void); ++void ssl_die(server_rec *); + void ssl_log_ssl_error(const char *, int, int, server_rec *); + + /* ssl_log_xerror, ssl_log_cxerror and ssl_log_rxerror are wrappers for the +diff --git a/modules/ssl/ssl_scache.c b/modules/ssl/ssl_scache.c +index 2c8d1bc..d32f8e1 100644 +--- a/modules/ssl/ssl_scache.c ++++ b/modules/ssl/ssl_scache.c +@@ -63,7 +63,7 @@ void ssl_scache_init(server_rec *s, apr_pool_t *p) + if (rv) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01872) + "Could not initialize stapling cache. Exiting."); +- ssl_die(); ++ ssl_die(s); + } + } + #endif +@@ -88,7 +88,7 @@ void ssl_scache_init(server_rec *s, apr_pool_t *p) + if (rv) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01874) + "Could not initialize session cache. Exiting."); +- ssl_die(); ++ ssl_die(s); + } + } + +diff --git a/modules/ssl/ssl_util.c b/modules/ssl/ssl_util.c +index 6b5a7de..475fe4d 100644 +--- a/modules/ssl/ssl_util.c ++++ b/modules/ssl/ssl_util.c +@@ -76,8 +76,7 @@ apr_file_t *ssl_util_ppopen(server_rec *s, apr_pool_t *p, const char *cmd, + return NULL; + if (apr_procattr_cmdtype_set(procattr, APR_PROGRAM) != APR_SUCCESS) + return NULL; +- if ((proc = (apr_proc_t *)apr_pcalloc(p, sizeof(apr_proc_t))) == NULL) +- return NULL; ++ proc = apr_pcalloc(p, sizeof(apr_proc_t)); + if (apr_proc_create(proc, cmd, argv, NULL, procattr, p) != APR_SUCCESS) + return NULL; + return proc->out; +@@ -287,7 +286,7 @@ STACK_OF(X509) *ssl_read_pkcs7(server_rec *s, const char *pkcs7) + f = fopen(pkcs7, "r"); + if (!f) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02212) "Can't open %s", pkcs7); +- ssl_die(); ++ ssl_die(s); + } + + p7 = PEM_read_PKCS7(f, NULL, NULL, NULL); +@@ -314,13 +313,13 @@ STACK_OF(X509) *ssl_read_pkcs7(server_rec *s, const char *pkcs7) + default: + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02213) + "Don't understand PKCS7 file %s", pkcs7); +- ssl_die(); ++ ssl_die(s); + } + + if (!certs) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02214) + "No certificates in %s", pkcs7); +- ssl_die(); ++ ssl_die(s); + } + + fclose(f); +@@ -376,24 +375,11 @@ static struct CRYPTO_dynlock_value *ssl_dyn_create_function(const char *file, + * allocated memory from a pool, create a subpool that we can blow + * away in the destruction callback. + */ +- rv = apr_pool_create(&p, dynlockpool); +- if (rv != APR_SUCCESS) { +- ap_log_perror(file, line, APLOG_MODULE_INDEX, APLOG_ERR, rv, dynlockpool, +- APLOGNO(02183) "Failed to create subpool for dynamic lock"); +- return NULL; +- } +- ++ apr_pool_create(&p, dynlockpool); + ap_log_perror(file, line, APLOG_MODULE_INDEX, APLOG_TRACE1, 0, p, + "Creating dynamic lock"); + +- value = (struct CRYPTO_dynlock_value *)apr_palloc(p, +- sizeof(struct CRYPTO_dynlock_value)); +- if (!value) { +- ap_log_perror(file, line, APLOG_MODULE_INDEX, APLOG_ERR, 0, p, +- APLOGNO(02185) "Failed to allocate dynamic lock structure"); +- return NULL; +- } +- ++ value = apr_palloc(p, sizeof(struct CRYPTO_dynlock_value)); + value->pool = p; + /* Keep our own copy of the place from which we were created, + using our own pool. */ +diff --git a/modules/ssl/ssl_util_ocsp.c b/modules/ssl/ssl_util_ocsp.c +index 94ef4cd..e5c5e58 100644 +--- a/modules/ssl/ssl_util_ocsp.c ++++ b/modules/ssl/ssl_util_ocsp.c +@@ -153,7 +153,13 @@ static char *get_line(apr_bucket_brigade *bbout, apr_bucket_brigade *bbin, + return NULL; + } + +- if (len && line[len-1] != APR_ASCII_LF) { ++ if (len == 0) { ++ ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(02321) ++ "empty response from OCSP server"); ++ return NULL; ++ } + -+/** The npn_proto_negotiated optional hook allows other modules to discover the -+ * name of the protocol that was chosen during the Next Protocol Negotiation -+ * (NPN) portion of the SSL handshake. Note that this may be the empty string -+ * (in which case modules should probably assume HTTP), or it may be a protocol -+ * that was never even advertised by the server. The hook callee is given the -+ * connection, a non-null-terminated string containing the protocol name, and -+ * the length of the string; it should do something appropriate (i.e. insert or -+ * remove filters) and return OK, or do nothing and return DECLINED. */ -+APR_DECLARE_EXTERNAL_HOOK(ssl, AP, int, npn_proto_negotiated_hook, -+ (conn_rec* connection, char* proto_name, -+ apr_size_t proto_name_len)); -+ - #endif /* __MOD_SSL_H__ */ - /** @} */ ++ if (line[len-1] != APR_ASCII_LF) { + ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(01979) + "response header line too long from OCSP server"); + return NULL; +diff --git a/modules/ssl/ssl_util_stapling.c b/modules/ssl/ssl_util_stapling.c +index 3ff08dc..89be7f5 100644 +--- a/modules/ssl/ssl_util_stapling.c ++++ b/modules/ssl/ssl_util_stapling.c +@@ -662,12 +662,12 @@ void modssl_init_stapling(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, + if (mc->stapling_cache == NULL) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01958) + "SSLStapling: no stapling cache available"); +- ssl_die(); ++ ssl_die(s); + } + if (ssl_stapling_mutex_init(s, ptemp) == FALSE) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01959) + "SSLStapling: cannot initialise stapling mutex"); +- ssl_die(); ++ ssl_die(s); + } + /* Set some default values for parameters if they are not set */ + if (mctx->stapling_resptime_skew == UNSET) { diff --git a/apache2.4-mpm-itk-2.4.2-01.patch b/apache2.4-mpm-itk-2.4.2-01.patch new file mode 100644 index 0000000..ba21410 --- /dev/null +++ b/apache2.4-mpm-itk-2.4.2-01.patch @@ -0,0 +1,2159 @@ +Index: httpd-2.4.2/server/mpm/itk/Makefile.in +=================================================================== +--- /dev/null ++++ httpd-2.4.2/server/mpm/itk/Makefile.in +@@ -0,0 +1 @@ ++include $(top_srcdir)/build/special.mk +Index: httpd-2.4.2/server/mpm/itk/config.m4 +=================================================================== +--- /dev/null ++++ httpd-2.4.2/server/mpm/itk/config.m4 +@@ -0,0 +1,7 @@ ++AC_MSG_CHECKING(if itk MPM supports this platform) ++if test $forking_mpms_supported != yes; then ++ AC_MSG_RESULT(no - This is not a forking platform) ++else ++ AC_MSG_RESULT(yes) ++ APACHE_MPM_SUPPORTED(itk, yes, no) ++fi +Index: httpd-2.4.2/server/mpm/itk/config3.m4 +=================================================================== +--- /dev/null ++++ httpd-2.4.2/server/mpm/itk/config3.m4 +@@ -0,0 +1 @@ ++APACHE_MPM_MODULE(itk, $enable_mpm_itk) +Index: httpd-2.4.2/server/mpm/itk/itk.c +=================================================================== +--- /dev/null ++++ httpd-2.4.2/server/mpm/itk/itk.c +@@ -0,0 +1,1917 @@ ++/* 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. ++ * ++ * Portions copyright 2005-2012 Steinar H. Gunderson . ++ * Licensed under the same terms as the rest of Apache. ++ * ++ * Portions copyright 2008 Knut Auvor Grythe . ++ * Licensed under the same terms as the rest of Apache. ++ */ ++ ++#include "apr.h" ++#include "apr_portable.h" ++#include "apr_strings.h" ++#include "apr_thread_proc.h" ++#include "apr_signal.h" ++ ++# define _DBG(text,par...) \ ++ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, \ ++ "(itkmpm: pid=%d uid=%d, gid=%d) %s(): " text, \ ++ getpid(), getuid(), getgid(), __FUNCTION__, par) ++ ++#define APR_WANT_STDIO ++#define APR_WANT_STRFUNC ++#include "apr_want.h" ++ ++#if APR_HAVE_UNISTD_H ++#include ++#endif ++#if APR_HAVE_SYS_TYPES_H ++#include ++#endif ++#include ++#include ++ ++#include "ap_config.h" ++#include "httpd.h" ++#include "mpm_default.h" ++#include "http_main.h" ++#include "http_log.h" ++#include "http_config.h" ++#include "http_core.h" /* for get_remote_host */ ++#include "http_connection.h" ++#include "scoreboard.h" ++#include "ap_mpm.h" ++#include "util_mutex.h" ++#include "unixd.h" ++#include "mpm_common.h" ++#include "ap_listen.h" ++#include "ap_mmn.h" ++#include "apr_poll.h" ++#include "ap_expr.h" ++ ++#ifdef HAVE_TIME_H ++#include ++#endif ++#ifdef HAVE_SYS_PROCESSOR_H ++#include /* for bindprocessor() */ ++#endif ++ ++#if HAVE_LIBCAP ++#include ++#endif ++ ++#include ++#include ++ ++/* Import our private hook. */ ++AP_DECLARE_HOOK(int,post_perdir_config,(request_rec *r)) ++ ++/* Limit on the total --- clients will be locked out if more servers than ++ * this are needed. It is intended solely to keep the server from crashing ++ * when things get out of hand. ++ * ++ * We keep a hard maximum number of servers, for two reasons --- first off, ++ * in case something goes seriously wrong, we want to stop the fork bomb ++ * short of actually crashing the machine we're running on by filling some ++ * kernel table. Secondly, it keeps the size of the scoreboard file small ++ * enough that we can read the whole thing without worrying too much about ++ * the overhead. ++ */ ++#ifndef DEFAULT_SERVER_LIMIT ++#define DEFAULT_SERVER_LIMIT 256 ++#endif ++ ++/* Admin can't tune ServerLimit beyond MAX_SERVER_LIMIT. We want ++ * some sort of compile-time limit to help catch typos. ++ */ ++#ifndef MAX_SERVER_LIMIT ++#define MAX_SERVER_LIMIT 200000 ++#endif ++ ++#ifndef HARD_THREAD_LIMIT ++#define HARD_THREAD_LIMIT 1 ++#endif ++ ++/* config globals */ ++ ++static apr_proc_mutex_t *accept_mutex; ++static int ap_daemons_to_start=0; ++static int ap_daemons_min_free=0; ++static int ap_daemons_max_free=0; ++static int ap_daemons_limit=0; /* MaxRequestWorkers */ ++static int server_limit = 0; ++static int mpm_state = AP_MPMQ_STARTING; ++static ap_pod_t *pod; ++ ++/* data retained by itk across load/unload of the module ++ * allocated on first call to pre-config hook; located on ++ * subsequent calls to pre-config hook ++ */ ++typedef struct itk_retained_data { ++ int first_server_limit; ++ int module_loads; ++ ap_generation_t my_generation; ++ int volatile is_graceful; /* set from signal handler */ ++ int maxclients_reported; ++ /* ++ * The max child slot ever assigned, preserved across restarts. Necessary ++ * to deal with MaxRequestWorkers changes across AP_SIG_GRACEFUL restarts. We ++ * use this value to optimize routines that have to scan the entire scoreboard. ++ */ ++ int max_daemons_limit; ++ /* ++ * idle_spawn_rate is the number of children that will be spawned on the ++ * next maintenance cycle if there aren't enough idle servers. It is ++ * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by ++ * without the need to spawn. ++ */ ++ int idle_spawn_rate; ++#ifndef MAX_SPAWN_RATE ++#define MAX_SPAWN_RATE (32) ++#endif ++ int hold_off_on_exponential_spawning; ++} itk_retained_data; ++static itk_retained_data *retained; ++ ++#define MPM_CHILD_PID(i) (ap_scoreboard_image->parent[i].pid) ++ ++/* one_process --- debugging mode variable; can be set from the command line ++ * with the -X flag. If set, this gets you the child_main loop running ++ * in the process which originally started up (no detach, no make_child), ++ * which is a pretty nice debugging environment. (You'll get a SIGHUP ++ * early in standalone_main; just continue through. This is the server ++ * trying to kill off any child processes which it might have lying ++ * around --- Apache doesn't keep track of their pids, it just sends ++ * SIGHUP to the process group, ignoring it in the root process. ++ * Continue through and you'll be fine.). ++ */ ++ ++static int one_process = 0; ++ ++static apr_pool_t *pconf; /* Pool for config stuff */ ++static apr_pool_t *pchild; /* Pool for httpd child stuff */ ++ ++static pid_t ap_my_pid; /* it seems silly to call getpid all the time */ ++static pid_t parent_pid; ++static int my_child_num; ++ ++#define UNSET_NICE_VALUE 100 ++ ++typedef struct ++{ ++ uid_t uid; ++ gid_t gid; ++ char *username; ++ int nice_value; ++ ap_expr_info_t *uid_expr; ++ ap_expr_info_t *gid_expr; ++} itk_per_dir_conf; ++ ++typedef struct ++{ ++ int max_clients_vhost; ++} itk_server_conf; ++ ++module AP_MODULE_DECLARE_DATA mpm_itk_module; ++extern AP_DECLARE_DATA int ap_running_under_mpm_itk; ++ ++#ifdef GPROF ++/* ++ * change directory for gprof to plop the gmon.out file ++ * configure in httpd.conf: ++ * GprofDir $RuntimeDir/ -> $ServerRoot/$RuntimeDir/gmon.out ++ * GprofDir $RuntimeDir/% -> $ServerRoot/$RuntimeDir/gprof.$pid/gmon.out ++ */ ++static void chdir_for_gprof(void) ++{ ++ core_server_config *sconf = ++ ap_get_core_module_config(ap_server_conf->module_config); ++ char *dir = sconf->gprof_dir; ++ const char *use_dir; ++ ++ if(dir) { ++ apr_status_t res; ++ char *buf = NULL ; ++ int len = strlen(sconf->gprof_dir) - 1; ++ if(*(dir + len) == '%') { ++ dir[len] = '\0'; ++ buf = ap_append_pid(pconf, dir, "gprof."); ++ } ++ use_dir = ap_server_root_relative(pconf, buf ? buf : dir); ++ res = apr_dir_make(use_dir, ++ APR_UREAD | APR_UWRITE | APR_UEXECUTE | ++ APR_GREAD | APR_GEXECUTE | ++ APR_WREAD | APR_WEXECUTE, pconf); ++ if(res != APR_SUCCESS && !APR_STATUS_IS_EEXIST(res)) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, res, ap_server_conf, APLOGNO(00142) ++ "gprof: error creating directory %s", dir); ++ } ++ } ++ else { ++ use_dir = ap_server_root_relative(pconf, DEFAULT_REL_RUNTIMEDIR); ++ } ++ ++ chdir(use_dir); ++} ++#else ++#define chdir_for_gprof() ++#endif ++ ++static void itk_note_child_killed(int childnum, pid_t pid, ++ ap_generation_t gen) ++{ ++ AP_DEBUG_ASSERT(childnum != -1); /* no scoreboard squatting with this MPM */ ++ ap_run_child_status(ap_server_conf, ++ ap_scoreboard_image->parent[childnum].pid, ++ ap_scoreboard_image->parent[childnum].generation, ++ childnum, MPM_CHILD_EXITED); ++ ap_scoreboard_image->parent[childnum].pid = 0; ++} ++ ++static void itk_note_child_started(int slot, pid_t pid) ++{ ++ ap_scoreboard_image->parent[slot].pid = pid; ++ ap_run_child_status(ap_server_conf, ++ ap_scoreboard_image->parent[slot].pid, ++ retained->my_generation, slot, MPM_CHILD_STARTED); ++} ++ ++/* a clean exit from a child with proper cleanup */ ++static void clean_child_exit(int code) __attribute__ ((noreturn)); ++static void clean_child_exit(int code) ++{ ++ mpm_state = AP_MPMQ_STOPPING; ++ ++ if (pchild) { ++ apr_pool_destroy(pchild); ++ } ++ ++ if (one_process) { ++ itk_note_child_killed(/* slot */ 0, 0, 0); ++ } ++ ++ ap_mpm_pod_close(pod); ++ chdir_for_gprof(); ++ exit(code); ++} ++ ++static void accept_mutex_on(void) ++{ ++ apr_status_t rv = apr_proc_mutex_lock(accept_mutex); ++ if (rv != APR_SUCCESS) { ++ const char *msg = "couldn't grab the accept mutex"; ++ ++ if (retained->my_generation != ++ ap_scoreboard_image->global->running_generation) { ++ ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, ap_server_conf, APLOGNO(00143) "%s", msg); ++ clean_child_exit(0); ++ } ++ else { ++ ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, APLOGNO(00144) "%s", msg); ++ exit(APEXIT_CHILDFATAL); ++ } ++ } ++} ++ ++static void accept_mutex_off(void) ++{ ++ apr_status_t rv = apr_proc_mutex_unlock(accept_mutex); ++ if (rv != APR_SUCCESS) { ++ const char *msg = "couldn't release the accept mutex"; ++ ++ if (retained->my_generation != ++ ap_scoreboard_image->global->running_generation) { ++ ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, ap_server_conf, APLOGNO(00145) "%s", msg); ++ /* don't exit here... we have a connection to ++ * process, after which point we'll see that the ++ * generation changed and we'll exit cleanly ++ */ ++ } ++ else { ++ ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf, APLOGNO(00146) "%s", msg); ++ exit(APEXIT_CHILDFATAL); ++ } ++ } ++} ++ ++/* On some architectures it's safe to do unserialized accept()s in the single ++ * Listen case. But it's never safe to do it in the case where there's ++ * multiple Listen statements. Define SINGLE_LISTEN_UNSERIALIZED_ACCEPT ++ * when it's safe in the single Listen case. ++ */ ++#ifdef SINGLE_LISTEN_UNSERIALIZED_ACCEPT ++#define SAFE_ACCEPT(stmt) do {if (ap_listeners->next) {stmt;}} while(0) ++#else ++#define SAFE_ACCEPT(stmt) do {stmt;} while(0) ++#endif ++ ++static int itk_query(int query_code, int *result, apr_status_t *rv) ++{ ++ *rv = APR_SUCCESS; ++ switch(query_code){ ++ case AP_MPMQ_MAX_DAEMON_USED: ++ *result = ap_daemons_limit; ++ break; ++ case AP_MPMQ_IS_THREADED: ++ *result = AP_MPMQ_NOT_SUPPORTED; ++ break; ++ case AP_MPMQ_IS_FORKED: ++ *result = AP_MPMQ_DYNAMIC; ++ break; ++ case AP_MPMQ_HARD_LIMIT_DAEMONS: ++ *result = server_limit; ++ break; ++ case AP_MPMQ_HARD_LIMIT_THREADS: ++ *result = HARD_THREAD_LIMIT; ++ break; ++ case AP_MPMQ_MAX_THREADS: ++ *result = 1; ++ break; ++ case AP_MPMQ_MIN_SPARE_DAEMONS: ++ *result = ap_daemons_min_free; ++ break; ++ case AP_MPMQ_MIN_SPARE_THREADS: ++ *result = 0; ++ break; ++ case AP_MPMQ_MAX_SPARE_DAEMONS: ++ *result = ap_daemons_max_free; ++ break; ++ case AP_MPMQ_MAX_SPARE_THREADS: ++ *result = 0; ++ break; ++ case AP_MPMQ_MAX_REQUESTS_DAEMON: ++ *result = ap_max_requests_per_child; ++ break; ++ case AP_MPMQ_MAX_DAEMONS: ++ *result = ap_daemons_limit; ++ break; ++ case AP_MPMQ_MPM_STATE: ++ *result = mpm_state; ++ break; ++ case AP_MPMQ_GENERATION: ++ *result = retained->my_generation; ++ break; ++ default: ++ *rv = APR_ENOTIMPL; ++ break; ++ } ++ return OK; ++} ++ ++static const char *itk_get_name(void) ++{ ++ return "itk"; ++} ++ ++/***************************************************************** ++ * Connection structures and accounting... ++ */ ++ ++static void just_die(int sig) ++{ ++ clean_child_exit(0); ++} ++ ++/* volatile because they're updated from a signal handler */ ++static int volatile shutdown_pending; ++static int volatile restart_pending; ++static int volatile die_now = 0; ++ ++static void stop_listening(int sig) ++{ ++ mpm_state = AP_MPMQ_STOPPING; ++ ap_close_listeners(); ++ ++ /* For a graceful stop, we want the child to exit when done */ ++ die_now = 1; ++} ++ ++static void sig_term(int sig) ++{ ++ if (shutdown_pending == 1) { ++ /* Um, is this _probably_ not an error, if the user has ++ * tried to do a shutdown twice quickly, so we won't ++ * worry about reporting it. ++ */ ++ return; ++ } ++ mpm_state = AP_MPMQ_STOPPING; ++ shutdown_pending = 1; ++ retained->is_graceful = (sig == AP_SIG_GRACEFUL_STOP); ++} ++ ++/* restart() is the signal handler for SIGHUP and AP_SIG_GRACEFUL ++ * in the parent process, unless running in ONE_PROCESS mode ++ */ ++static void restart(int sig) ++{ ++ if (restart_pending == 1) { ++ /* Probably not an error - don't bother reporting it */ ++ return; ++ } ++ mpm_state = AP_MPMQ_STOPPING; ++ restart_pending = 1; ++ retained->is_graceful = (sig == AP_SIG_GRACEFUL); ++} ++ ++static void set_signals(void) ++{ ++#ifndef NO_USE_SIGACTION ++ struct sigaction sa; ++#endif ++ ++ if (!one_process) { ++ ap_fatal_signal_setup(ap_server_conf, pconf); ++ } ++ ++#ifndef NO_USE_SIGACTION ++ sigemptyset(&sa.sa_mask); ++ sa.sa_flags = 0; ++ ++ sa.sa_handler = sig_term; ++ if (sigaction(SIGTERM, &sa, NULL) < 0) ++ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00147) "sigaction(SIGTERM)"); ++#ifdef AP_SIG_GRACEFUL_STOP ++ if (sigaction(AP_SIG_GRACEFUL_STOP, &sa, NULL) < 0) ++ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00148) ++ "sigaction(" AP_SIG_GRACEFUL_STOP_STRING ")"); ++#endif ++#ifdef SIGINT ++ if (sigaction(SIGINT, &sa, NULL) < 0) ++ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00149) "sigaction(SIGINT)"); ++#endif ++#ifdef SIGXCPU ++ sa.sa_handler = SIG_DFL; ++ if (sigaction(SIGXCPU, &sa, NULL) < 0) ++ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00150) "sigaction(SIGXCPU)"); ++#endif ++#ifdef SIGXFSZ ++ /* For systems following the LFS standard, ignoring SIGXFSZ allows ++ * a write() beyond the 2GB limit to fail gracefully with E2BIG ++ * rather than terminate the process. */ ++ sa.sa_handler = SIG_IGN; ++ if (sigaction(SIGXFSZ, &sa, NULL) < 0) ++ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00151) "sigaction(SIGXFSZ)"); ++#endif ++#ifdef SIGPIPE ++ sa.sa_handler = SIG_IGN; ++ if (sigaction(SIGPIPE, &sa, NULL) < 0) ++ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00152) "sigaction(SIGPIPE)"); ++#endif ++ ++ /* we want to ignore HUPs and AP_SIG_GRACEFUL while we're busy ++ * processing one ++ */ ++ sigaddset(&sa.sa_mask, SIGHUP); ++ sigaddset(&sa.sa_mask, AP_SIG_GRACEFUL); ++ sa.sa_handler = restart; ++ if (sigaction(SIGHUP, &sa, NULL) < 0) ++ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00153) "sigaction(SIGHUP)"); ++ if (sigaction(AP_SIG_GRACEFUL, &sa, NULL) < 0) ++ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00154) "sigaction(" AP_SIG_GRACEFUL_STRING ")"); ++#else ++ if (!one_process) { ++#ifdef SIGXCPU ++ apr_signal(SIGXCPU, SIG_DFL); ++#endif /* SIGXCPU */ ++#ifdef SIGXFSZ ++ apr_signal(SIGXFSZ, SIG_IGN); ++#endif /* SIGXFSZ */ ++ } ++ ++ apr_signal(SIGTERM, sig_term); ++#ifdef SIGHUP ++ apr_signal(SIGHUP, restart); ++#endif /* SIGHUP */ ++#ifdef AP_SIG_GRACEFUL ++ apr_signal(AP_SIG_GRACEFUL, restart); ++#endif /* AP_SIG_GRACEFUL */ ++#ifdef AP_SIG_GRACEFUL_STOP ++ apr_signal(AP_SIG_GRACEFUL_STOP, sig_term); ++#endif /* AP_SIG_GRACEFUL */ ++#ifdef SIGPIPE ++ apr_signal(SIGPIPE, SIG_IGN); ++#endif /* SIGPIPE */ ++ ++#endif ++} ++ ++/***************************************************************** ++ * Child process main loop. ++ * The following vars are static to avoid getting clobbered by longjmp(); ++ * they are really private to child_main. ++ */ ++ ++static int requests_this_child; ++static int num_listensocks = 0; ++ ++static void child_main(int child_num_arg) ++{ ++#if APR_HAS_THREADS ++ apr_thread_t *thd = NULL; ++ apr_os_thread_t osthd; ++#endif ++ apr_pool_t *ptrans; ++ apr_allocator_t *allocator; ++ apr_status_t status; ++ int i; ++ ap_listen_rec *lr; ++ apr_pollset_t *pollset; ++ ap_sb_handle_t *sbh; ++ apr_bucket_alloc_t *bucket_alloc; ++ int last_poll_idx = 0; ++ const char *lockfile; ++ ++#if HAVE_LIBCAP ++ cap_t caps; ++ cap_value_t suidcaps[] = { ++ CAP_SETUID, ++ CAP_SETGID, ++ CAP_DAC_READ_SEARCH, ++ CAP_SYS_NICE, ++ }; ++#endif ++ ++ mpm_state = AP_MPMQ_STARTING; /* for benefit of any hooks that run as this ++ * child initializes ++ */ ++ ++ ap_running_under_mpm_itk = 1; ++ my_child_num = child_num_arg; ++ ap_my_pid = getpid(); ++ requests_this_child = 0; ++ ++ ap_fatal_signal_child_setup(ap_server_conf); ++ ++ /* Get a sub context for global allocations in this child, so that ++ * we can have cleanups occur when the child exits. ++ */ ++ apr_allocator_create(&allocator); ++ apr_allocator_max_free_set(allocator, ap_max_mem_free); ++ apr_pool_create_ex(&pchild, pconf, NULL, allocator); ++ apr_allocator_owner_set(allocator, pchild); ++ apr_pool_tag(pchild, "pchild"); ++ ++#if APR_HAS_THREADS ++ osthd = apr_os_thread_current(); ++ apr_os_thread_put(&thd, &osthd, pchild); ++#endif ++ ++ apr_pool_create(&ptrans, pchild); ++ apr_pool_tag(ptrans, "transaction"); ++ ++ /* needs to be done before we switch UIDs so we have permissions */ ++ ap_reopen_scoreboard(pchild, NULL, 0); ++ lockfile = apr_proc_mutex_lockfile(accept_mutex); ++ status = apr_proc_mutex_child_init(&accept_mutex, ++ lockfile, ++ pchild); ++ if (status != APR_SUCCESS) { ++ ap_log_error(APLOG_MARK, APLOG_EMERG, status, ap_server_conf, APLOGNO(00155) ++ "Couldn't initialize cross-process lock in child " ++ "(%s) (%s)", ++ lockfile ? lockfile : "none", ++ apr_proc_mutex_name(accept_mutex)); ++ clean_child_exit(APEXIT_CHILDFATAL); ++ } ++ ++ ap_run_child_init(pchild, ap_server_conf); ++ ++ ap_create_sb_handle(&sbh, pchild, my_child_num, 0); ++ ++ (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL); ++ ++ /* Set up the pollfd array */ ++ status = apr_pollset_create(&pollset, num_listensocks, pchild, 0); ++ if (status != APR_SUCCESS) { ++ ap_log_error(APLOG_MARK, APLOG_EMERG, status, ap_server_conf, APLOGNO(00156) ++ "Couldn't create pollset in child; check system or user limits"); ++ clean_child_exit(APEXIT_CHILDSICK); /* assume temporary resource issue */ ++ } ++ ++ for (lr = ap_listeners, i = num_listensocks; i--; lr = lr->next) { ++ apr_pollfd_t pfd = { 0 }; ++ ++ pfd.desc_type = APR_POLL_SOCKET; ++ pfd.desc.s = lr->sd; ++ pfd.reqevents = APR_POLLIN; ++ pfd.client_data = lr; ++ ++ status = apr_pollset_add(pollset, &pfd); ++ if (status != APR_SUCCESS) { ++ ap_log_error(APLOG_MARK, APLOG_EMERG, status, ap_server_conf, APLOGNO(00157) ++ "Couldn't add listener to pollset; check system or user limits"); ++ clean_child_exit(APEXIT_CHILDSICK); ++ } ++ ++ lr->accept_func = ap_unixd_accept; ++ } ++ ++#if HAVE_LIBCAP ++ /* Drop as many privileges as we can. We'll still ++ * access files with uid=0, and we can setuid() to anything, but ++ * at least there's tons of other evilness (like loading kernel ++ * modules) we can't do directly. (The setuid() capability will ++ * go away automatically when we setuid() or exec() -- the former ++ * is likely to come first.) ++ */ ++ caps = cap_init(); ++ cap_clear(caps); ++ cap_set_flag(caps, CAP_PERMITTED, sizeof(suidcaps)/sizeof(cap_value_t), suidcaps, CAP_SET); ++ cap_set_flag(caps, CAP_EFFECTIVE, sizeof(suidcaps)/sizeof(cap_value_t), suidcaps, CAP_SET); ++ cap_set_proc(caps); ++ cap_free(caps); ++#endif ++ ++ mpm_state = AP_MPMQ_RUNNING; ++ ++ bucket_alloc = apr_bucket_alloc_create(pchild); ++ ++ /* die_now is set when AP_SIG_GRACEFUL is received in the child; ++ * shutdown_pending is set when SIGTERM is received when running ++ * in single process mode. */ ++ while (!die_now && !shutdown_pending) { ++ conn_rec *current_conn; ++ void *csd; ++ ++ /* ++ * (Re)initialize this child to a pre-connection state. ++ */ ++ ++ apr_pool_clear(ptrans); ++ ++ if ((ap_max_requests_per_child > 0 ++ && requests_this_child++ >= ap_max_requests_per_child)) { ++ clean_child_exit(0); ++ } ++ ++ (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL); ++ ++ /* ++ * Wait for an acceptable connection to arrive. ++ */ ++ ++ /* Lock around "accept", if necessary */ ++ SAFE_ACCEPT(accept_mutex_on()); ++ ++ if (num_listensocks == 1) { ++ /* There is only one listener record, so refer to that one. */ ++ lr = ap_listeners; ++ } ++ else { ++ /* multiple listening sockets - need to poll */ ++ for (;;) { ++ apr_int32_t numdesc; ++ const apr_pollfd_t *pdesc; ++ ++ /* check for termination first so we don't sleep for a while in ++ * poll if already signalled ++ */ ++ if (die_now /* in graceful stop/restart */ ++ || (one_process && shutdown_pending)) { ++ SAFE_ACCEPT(accept_mutex_off()); ++ clean_child_exit(0); ++ } ++ ++ /* timeout == 10 seconds to avoid a hang at graceful restart/stop ++ * caused by the closing of sockets by the signal handler ++ */ ++ status = apr_pollset_poll(pollset, apr_time_from_sec(10), ++ &numdesc, &pdesc); ++ if (status != APR_SUCCESS) { ++ if (APR_STATUS_IS_TIMEUP(status) || ++ APR_STATUS_IS_EINTR(status)) { ++ continue; ++ } ++ /* Single Unix documents select as returning errnos ++ * EBADF, EINTR, and EINVAL... and in none of those ++ * cases does it make sense to continue. In fact ++ * on Linux 2.0.x we seem to end up with EFAULT ++ * occasionally, and we'd loop forever due to it. ++ */ ++ ap_log_error(APLOG_MARK, APLOG_ERR, status, ++ ap_server_conf, APLOGNO(00158) "apr_pollset_poll: (listen)"); ++ SAFE_ACCEPT(accept_mutex_off()); ++ clean_child_exit(1); ++ } ++ ++ /* We can always use pdesc[0], but sockets at position N ++ * could end up completely starved of attention in a very ++ * busy server. Therefore, we round-robin across the ++ * returned set of descriptors. While it is possible that ++ * the returned set of descriptors might flip around and ++ * continue to starve some sockets, we happen to know the ++ * internal pollset implementation retains ordering ++ * stability of the sockets. Thus, the round-robin should ++ * ensure that a socket will eventually be serviced. ++ */ ++ if (last_poll_idx >= numdesc) ++ last_poll_idx = 0; ++ ++ /* Grab a listener record from the client_data of the poll ++ * descriptor, and advance our saved index to round-robin ++ * the next fetch. ++ * ++ * ### hmm... this descriptor might have POLLERR rather ++ * ### than POLLIN ++ */ ++ lr = pdesc[last_poll_idx++].client_data; ++ goto got_fd; ++ } ++ } ++ got_fd: ++ /* if we accept() something we don't want to die, so we have to ++ * defer the exit ++ */ ++ status = lr->accept_func(&csd, lr, ptrans); ++ ++ SAFE_ACCEPT(accept_mutex_off()); /* unlock after "accept" */ ++ ++ if (status == APR_EGENERAL) { ++ /* resource shortage or should-not-occur occured */ ++ clean_child_exit(1); ++ } ++ else if (status != APR_SUCCESS) { ++ continue; ++ } ++ ++ /* ++ * We now have a connection, so set it up with the appropriate ++ * socket options, file descriptors, and read/write buffers. ++ */ ++ ++ { ++ pid_t pid = fork(), child_pid; ++ int status; ++ switch (pid) { ++ case -1: ++ ap_log_error(APLOG_MARK, APLOG_ERR, errno, NULL, "fork: Unable to fork new process"); ++ break; ++ case 0: /* child */ ++ current_conn = ap_run_create_connection(ptrans, ap_server_conf, csd, my_child_num, sbh, bucket_alloc); ++ if (current_conn) { ++#if APR_HAS_THREADS ++ current_conn->current_thread = thd; ++#endif ++ ap_process_connection(current_conn, csd); ++ ap_lingering_close(current_conn); ++ } ++ clean_child_exit(0); ++ default: /* parent; just wait for child to be done */ ++ do { ++ child_pid = waitpid(pid, &status, 0); ++ } while (child_pid == -1 && errno == EINTR); ++ ++ if (child_pid != pid || !WIFEXITED(status)) { ++ if (WIFSIGNALED(status)) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, "child died with signal %u", WTERMSIG(status)); ++ } else if (WEXITSTATUS(status) != 0) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, "child exited with non-zero exit status %u", WEXITSTATUS(status)); ++ } else { ++ ap_log_error(APLOG_MARK, APLOG_ERR, errno, NULL, "waitpid() failed"); ++ } ++ clean_child_exit(1); ++ } ++ break; ++ } ++ } ++ ++ /* Check the pod and the generation number after processing a ++ * connection so that we'll go away if a graceful restart occurred ++ * while we were processing the connection or we are the lucky ++ * idle server process that gets to die. ++ */ ++ if (ap_mpm_pod_check(pod) == APR_SUCCESS) { /* selected as idle? */ ++ die_now = 1; ++ } ++ else if (retained->my_generation != ++ ap_scoreboard_image->global->running_generation) { /* restart? */ ++ /* yeah, this could be non-graceful restart, in which case the ++ * parent will kill us soon enough, but why bother checking? ++ */ ++ die_now = 1; ++ } ++ ++ /* if we have already setuid(), die (we can't be used anyhow) */ ++ if (getuid()) ++ die_now = 1; ++ } ++ apr_pool_clear(ptrans); /* kludge to avoid crash in APR reslist cleanup code */ ++ clean_child_exit(0); ++} ++ ++ ++static int make_child(server_rec *s, int slot) ++{ ++ int pid; ++ ++ if (slot + 1 > retained->max_daemons_limit) { ++ retained->max_daemons_limit = slot + 1; ++ } ++ ++ if (one_process) { ++ apr_signal(SIGHUP, sig_term); ++ /* Don't catch AP_SIG_GRACEFUL in ONE_PROCESS mode :) */ ++ apr_signal(SIGINT, sig_term); ++#ifdef SIGQUIT ++ apr_signal(SIGQUIT, SIG_DFL); ++#endif ++ apr_signal(SIGTERM, sig_term); ++ itk_note_child_started(slot, getpid()); ++ child_main(slot); ++ /* NOTREACHED */ ++ } ++ ++ (void) ap_update_child_status_from_indexes(slot, 0, SERVER_STARTING, ++ (request_rec *) NULL); ++ ++ ++#ifdef _OSD_POSIX ++ /* BS2000 requires a "special" version of fork() before a setuid() call */ ++ if ((pid = os_fork(ap_unixd_config.user_name)) == -1) { ++#else ++ if ((pid = fork()) == -1) { ++#endif ++ ap_log_error(APLOG_MARK, APLOG_ERR, errno, s, APLOGNO(00159) "fork: Unable to fork new process"); ++ ++ /* fork didn't succeed. Fix the scoreboard or else ++ * it will say SERVER_STARTING forever and ever ++ */ ++ (void) ap_update_child_status_from_indexes(slot, 0, SERVER_DEAD, ++ (request_rec *) NULL); ++ ++ /* In case system resources are maxxed out, we don't want ++ * Apache running away with the CPU trying to fork over and ++ * over and over again. ++ */ ++ sleep(10); ++ ++ return -1; ++ } ++ ++ if (!pid) { ++#ifdef HAVE_BINDPROCESSOR ++ /* by default AIX binds to a single processor ++ * this bit unbinds children which will then bind to another cpu ++ */ ++ int status = bindprocessor(BINDPROCESS, (int)getpid(), ++ PROCESSOR_CLASS_ANY); ++ if (status != OK) { ++ ap_log_error(APLOG_MARK, APLOG_DEBUG, errno, ++ ap_server_conf, APLOGNO(00160) "processor unbind failed"); ++ } ++#endif ++ RAISE_SIGSTOP(MAKE_CHILD); ++ AP_MONCONTROL(1); ++ /* Disable the parent's signal handlers and set up proper handling in ++ * the child. ++ */ ++ apr_signal(SIGHUP, just_die); ++ apr_signal(SIGTERM, just_die); ++ /* The child process just closes listeners on AP_SIG_GRACEFUL. ++ * The pod is used for signalling the graceful restart. ++ */ ++ apr_signal(AP_SIG_GRACEFUL, stop_listening); ++ child_main(slot); ++ } ++ ++ itk_note_child_started(slot, pid); ++ ++ return 0; ++} ++ ++ ++/* start up a bunch of children */ ++static void startup_children(int number_to_start) ++{ ++ int i; ++ ++ for (i = 0; number_to_start && i < ap_daemons_limit; ++i) { ++ if (ap_scoreboard_image->servers[i][0].status != SERVER_DEAD) { ++ continue; ++ } ++ if (make_child(ap_server_conf, i) < 0) { ++ break; ++ } ++ --number_to_start; ++ } ++} ++ ++static void perform_idle_server_maintenance(apr_pool_t *p) ++{ ++ int i; ++ int idle_count; ++ worker_score *ws; ++ int free_length; ++ int free_slots[MAX_SPAWN_RATE]; ++ int last_non_dead; ++ int total_non_dead; ++ ++ /* initialize the free_list */ ++ free_length = 0; ++ ++ idle_count = 0; ++ last_non_dead = -1; ++ total_non_dead = 0; ++ ++ for (i = 0; i < ap_daemons_limit; ++i) { ++ int status; ++ ++ if (i >= retained->max_daemons_limit && free_length == retained->idle_spawn_rate) ++ break; ++ ws = &ap_scoreboard_image->servers[i][0]; ++ status = ws->status; ++ if (status == SERVER_DEAD) { ++ /* try to keep children numbers as low as possible */ ++ if (free_length < retained->idle_spawn_rate) { ++ free_slots[free_length] = i; ++ ++free_length; ++ } ++ } ++ else { ++ /* We consider a starting server as idle because we started it ++ * at least a cycle ago, and if it still hasn't finished starting ++ * then we're just going to swamp things worse by forking more. ++ * So we hopefully won't need to fork more if we count it. ++ * This depends on the ordering of SERVER_READY and SERVER_STARTING. ++ */ ++ if (status <= SERVER_READY) { ++ ++ idle_count; ++ } ++ ++ ++total_non_dead; ++ last_non_dead = i; ++ } ++ } ++ retained->max_daemons_limit = last_non_dead + 1; ++ if (idle_count > ap_daemons_max_free) { ++ /* kill off one child... we use the pod because that'll cause it to ++ * shut down gracefully, in case it happened to pick up a request ++ * while we were counting ++ */ ++ ap_mpm_pod_signal(pod); ++ retained->idle_spawn_rate = 1; ++ } ++ else if (idle_count < ap_daemons_min_free) { ++ /* terminate the free list */ ++ if (free_length == 0) { ++ /* only report this condition once */ ++ if (!retained->maxclients_reported) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, APLOGNO(00161) ++ "server reached MaxRequestWorkers setting, consider" ++ " raising the MaxRequestWorkers setting"); ++ retained->maxclients_reported = 1; ++ } ++ retained->idle_spawn_rate = 1; ++ } ++ else { ++ if (retained->idle_spawn_rate >= 8) { ++ ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf, APLOGNO(00162) ++ "server seems busy, (you may need " ++ "to increase StartServers, or Min/MaxSpareServers), " ++ "spawning %d children, there are %d idle, and " ++ "%d total children", retained->idle_spawn_rate, ++ idle_count, total_non_dead); ++ } ++ for (i = 0; i < free_length; ++i) { ++ make_child(ap_server_conf, free_slots[i]); ++ } ++ /* the next time around we want to spawn twice as many if this ++ * wasn't good enough, but not if we've just done a graceful ++ */ ++ if (retained->hold_off_on_exponential_spawning) { ++ --retained->hold_off_on_exponential_spawning; ++ } ++ else if (retained->idle_spawn_rate < MAX_SPAWN_RATE) { ++ retained->idle_spawn_rate *= 2; ++ } ++ } ++ } ++ else { ++ retained->idle_spawn_rate = 1; ++ } ++} ++ ++/***************************************************************** ++ * Executive routines. ++ */ ++ ++static int itk_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) ++{ ++ int index; ++ int remaining_children_to_start; ++ apr_status_t rv; ++ ++ ap_log_pid(pconf, ap_pid_fname); ++ ++ /* Initialize cross-process accept lock */ ++ rv = ap_proc_mutex_create(&accept_mutex, NULL, AP_ACCEPT_MUTEX_TYPE, NULL, ++ s, _pconf, 0); ++ if (rv != APR_SUCCESS) { ++ mpm_state = AP_MPMQ_STOPPING; ++ return DONE; ++ } ++ ++ if (!retained->is_graceful) { ++ if (ap_run_pre_mpm(s->process->pool, SB_SHARED) != OK) { ++ mpm_state = AP_MPMQ_STOPPING; ++ return DONE; ++ } ++ /* fix the generation number in the global score; we just got a new, ++ * cleared scoreboard ++ */ ++ ap_scoreboard_image->global->running_generation = retained->my_generation; ++ } ++ ++ restart_pending = shutdown_pending = 0; ++ set_signals(); ++ ++ if (one_process) { ++ AP_MONCONTROL(1); ++ make_child(ap_server_conf, 0); ++ /* NOTREACHED */ ++ } ++ else { ++ if (ap_daemons_max_free < ap_daemons_min_free + 1) /* Don't thrash... */ ++ ap_daemons_max_free = ap_daemons_min_free + 1; ++ ++ /* If we're doing a graceful_restart then we're going to see a lot ++ * of children exiting immediately when we get into the main loop ++ * below (because we just sent them AP_SIG_GRACEFUL). This happens pretty ++ * rapidly... and for each one that exits we'll start a new one until ++ * we reach at least daemons_min_free. But we may be permitted to ++ * start more than that, so we'll just keep track of how many we're ++ * supposed to start up without the 1 second penalty between each fork. ++ */ ++ remaining_children_to_start = ap_daemons_to_start; ++ if (remaining_children_to_start > ap_daemons_limit) { ++ remaining_children_to_start = ap_daemons_limit; ++ } ++ if (!retained->is_graceful) { ++ startup_children(remaining_children_to_start); ++ remaining_children_to_start = 0; ++ } ++ else { ++ /* give the system some time to recover before kicking into ++ * exponential mode ++ */ ++ retained->hold_off_on_exponential_spawning = 10; ++ } ++ ++ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, APLOGNO(00163) ++ "%s configured -- resuming normal operations", ++ ap_get_server_description()); ++ ap_log_error(APLOG_MARK, APLOG_INFO, 0, ap_server_conf, APLOGNO(00164) ++ "Server built: %s", ap_get_server_built()); ++ ap_log_command_line(plog, s); ++ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(00165) ++ "Accept mutex: %s (default: %s)", ++ apr_proc_mutex_name(accept_mutex), ++ apr_proc_mutex_defname()); ++ ++ mpm_state = AP_MPMQ_RUNNING; ++ ++ while (!restart_pending && !shutdown_pending) { ++ int child_slot; ++ apr_exit_why_e exitwhy; ++ int status, processed_status; ++ /* this is a memory leak, but I'll fix it later. */ ++ apr_proc_t pid; ++ ++ ap_wait_or_timeout(&exitwhy, &status, &pid, pconf, ap_server_conf); ++ ++ /* XXX: if it takes longer than 1 second for all our children ++ * to start up and get into IDLE state then we may spawn an ++ * extra child ++ */ ++ if (pid.pid != -1) { ++ processed_status = ap_process_child_status(&pid, exitwhy, status); ++ child_slot = ap_find_child_by_pid(&pid); ++ if (processed_status == APEXIT_CHILDFATAL) { ++ /* fix race condition found in PR 39311 ++ * A child created at the same time as a graceful happens ++ * can find the lock missing and create a fatal error. ++ * It is not fatal for the last generation to be in this state. ++ */ ++ if (child_slot < 0 ++ || ap_get_scoreboard_process(child_slot)->generation ++ == retained->my_generation) { ++ mpm_state = AP_MPMQ_STOPPING; ++ return DONE; ++ } ++ else { ++ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, ap_server_conf, APLOGNO(00166) ++ "Ignoring fatal error in child of previous " ++ "generation (pid %ld).", ++ (long)pid.pid); ++ } ++ } ++ ++ /* non-fatal death... note that it's gone in the scoreboard. */ ++ if (child_slot >= 0) { ++ (void) ap_update_child_status_from_indexes(child_slot, 0, SERVER_DEAD, ++ (request_rec *) NULL); ++ itk_note_child_killed(child_slot, 0, 0); ++ if (processed_status == APEXIT_CHILDSICK) { ++ /* child detected a resource shortage (E[NM]FILE, ENOBUFS, etc) ++ * cut the fork rate to the minimum ++ */ ++ retained->idle_spawn_rate = 1; ++ } ++ else if (remaining_children_to_start ++ && child_slot < ap_daemons_limit) { ++ /* we're still doing a 1-for-1 replacement of dead ++ * children with new children ++ */ ++ make_child(ap_server_conf, child_slot); ++ --remaining_children_to_start; ++ } ++#if APR_HAS_OTHER_CHILD ++ } ++ else if (apr_proc_other_child_alert(&pid, APR_OC_REASON_DEATH, status) == APR_SUCCESS) { ++ /* handled */ ++#endif ++ } ++ else if (retained->is_graceful) { ++ /* Great, we've probably just lost a slot in the ++ * scoreboard. Somehow we don't know about this ++ * child. ++ */ ++ ap_log_error(APLOG_MARK, APLOG_WARNING, ++ 0, ap_server_conf, APLOGNO(00167) ++ "long lost child came home! (pid %ld)", (long)pid.pid); ++ } ++ /* Don't perform idle maintenance when a child dies, ++ * only do it when there's a timeout. Remember only a ++ * finite number of children can die, and it's pretty ++ * pathological for a lot to die suddenly. ++ */ ++ continue; ++ } ++ else if (remaining_children_to_start) { ++ /* we hit a 1 second timeout in which none of the previous ++ * generation of children needed to be reaped... so assume ++ * they're all done, and pick up the slack if any is left. ++ */ ++ startup_children(remaining_children_to_start); ++ remaining_children_to_start = 0; ++ /* In any event we really shouldn't do the code below because ++ * few of the servers we just started are in the IDLE state ++ * yet, so we'd mistakenly create an extra server. ++ */ ++ continue; ++ } ++ ++ perform_idle_server_maintenance(pconf); ++ } ++ } /* one_process */ ++ ++ mpm_state = AP_MPMQ_STOPPING; ++ ++ if (shutdown_pending && !retained->is_graceful) { ++ /* Time to shut down: ++ * Kill child processes, tell them to call child_exit, etc... ++ */ ++ if (ap_unixd_killpg(getpgrp(), SIGTERM) < 0) { ++ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00168) "killpg SIGTERM"); ++ } ++ ap_reclaim_child_processes(1, /* Start with SIGTERM */ ++ itk_note_child_killed); ++ ++ /* cleanup pid file on normal shutdown */ ++ ap_remove_pid(pconf, ap_pid_fname); ++ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, APLOGNO(00169) ++ "caught SIGTERM, shutting down"); ++ ++ return DONE; ++ } else if (shutdown_pending) { ++ /* Time to perform a graceful shut down: ++ * Reap the inactive children, and ask the active ones ++ * to close their listeners, then wait until they are ++ * all done to exit. ++ */ ++ int active_children; ++ apr_time_t cutoff = 0; ++ ++ /* Stop listening */ ++ ap_close_listeners(); ++ ++ /* kill off the idle ones */ ++ ap_mpm_pod_killpg(pod, retained->max_daemons_limit); ++ ++ /* Send SIGUSR1 to the active children */ ++ active_children = 0; ++ for (index = 0; index < ap_daemons_limit; ++index) { ++ if (ap_scoreboard_image->servers[index][0].status != SERVER_DEAD) { ++ /* Ask each child to close its listeners. */ ++ ap_mpm_safe_kill(MPM_CHILD_PID(index), AP_SIG_GRACEFUL); ++ active_children++; ++ } ++ } ++ ++ /* Allow each child which actually finished to exit */ ++ ap_relieve_child_processes(itk_note_child_killed); ++ ++ /* cleanup pid file */ ++ ap_remove_pid(pconf, ap_pid_fname); ++ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, APLOGNO(00170) ++ "caught " AP_SIG_GRACEFUL_STOP_STRING ", shutting down gracefully"); ++ ++ if (ap_graceful_shutdown_timeout) { ++ cutoff = apr_time_now() + ++ apr_time_from_sec(ap_graceful_shutdown_timeout); ++ } ++ ++ /* Don't really exit until each child has finished */ ++ shutdown_pending = 0; ++ do { ++ /* Pause for a second */ ++ sleep(1); ++ ++ /* Relieve any children which have now exited */ ++ ap_relieve_child_processes(itk_note_child_killed); ++ ++ active_children = 0; ++ for (index = 0; index < ap_daemons_limit; ++index) { ++ if (ap_mpm_safe_kill(MPM_CHILD_PID(index), 0) == APR_SUCCESS) { ++ active_children = 1; ++ /* Having just one child is enough to stay around */ ++ break; ++ } ++ } ++ } while (!shutdown_pending && active_children && ++ (!ap_graceful_shutdown_timeout || apr_time_now() < cutoff)); ++ ++ /* We might be here because we received SIGTERM, either ++ * way, try and make sure that all of our processes are ++ * really dead. ++ */ ++ ap_unixd_killpg(getpgrp(), SIGTERM); ++ ++ return DONE; ++ } ++ ++ /* we've been told to restart */ ++ apr_signal(SIGHUP, SIG_IGN); ++ apr_signal(AP_SIG_GRACEFUL, SIG_IGN); ++ if (one_process) { ++ /* not worth thinking about */ ++ return DONE; ++ } ++ ++ /* advance to the next generation */ ++ /* XXX: we really need to make sure this new generation number isn't in ++ * use by any of the children. ++ */ ++ ++retained->my_generation; ++ ap_scoreboard_image->global->running_generation = retained->my_generation; ++ ++ if (retained->is_graceful) { ++ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, APLOGNO(00171) ++ "Graceful restart requested, doing restart"); ++ ++ /* kill off the idle ones */ ++ ap_mpm_pod_killpg(pod, retained->max_daemons_limit); ++ ++ /* This is mostly for debugging... so that we know what is still ++ * gracefully dealing with existing request. This will break ++ * in a very nasty way if we ever have the scoreboard totally ++ * file-based (no shared memory) ++ */ ++ for (index = 0; index < ap_daemons_limit; ++index) { ++ if (ap_scoreboard_image->servers[index][0].status != SERVER_DEAD) { ++ ap_scoreboard_image->servers[index][0].status = SERVER_GRACEFUL; ++ /* Ask each child to close its listeners. ++ * ++ * NOTE: we use the scoreboard, because if we send SIGUSR1 ++ * to every process in the group, this may include CGI's, ++ * piped loggers, etc. They almost certainly won't handle ++ * it gracefully. ++ */ ++ ap_mpm_safe_kill(ap_scoreboard_image->parent[index].pid, AP_SIG_GRACEFUL); ++ } ++ } ++ } ++ else { ++ /* Kill 'em off */ ++ if (ap_unixd_killpg(getpgrp(), SIGHUP) < 0) { ++ ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf, APLOGNO(00172) "killpg SIGHUP"); ++ } ++ ap_reclaim_child_processes(0, /* Not when just starting up */ ++ itk_note_child_killed); ++ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, APLOGNO(00173) ++ "SIGHUP received. Attempting to restart"); ++ } ++ ++ return OK; ++} ++ ++/* This really should be a post_config hook, but the error log is already ++ * redirected by that point, so we need to do this in the open_logs phase. ++ */ ++static int itk_open_logs(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) ++{ ++ int startup = 0; ++ int level_flags = 0; ++ apr_status_t rv; ++ ++ pconf = p; ++ ++ /* the reverse of pre_config, we want this only the first time around */ ++ if (retained->module_loads == 1) { ++ startup = 1; ++ level_flags |= APLOG_STARTUP; ++ } ++ ++ if ((num_listensocks = ap_setup_listeners(ap_server_conf)) < 1) { ++ ap_log_error(APLOG_MARK, APLOG_ALERT | level_flags, 0, ++ (startup ? NULL : s), ++ "no listening sockets available, shutting down"); ++ return DONE; ++ } ++ ++ if ((rv = ap_mpm_pod_open(pconf, &pod))) { ++ ap_log_error(APLOG_MARK, APLOG_CRIT | level_flags, rv, ++ (startup ? NULL : s), ++ "could not open pipe-of-death"); ++ return DONE; ++ } ++ return OK; ++} ++ ++static int itk_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp) ++{ ++ int no_detach, debug, foreground; ++ apr_status_t rv; ++ const char *userdata_key = "mpm_itk_module"; ++ ++ mpm_state = AP_MPMQ_STARTING; ++ ++ debug = ap_exists_config_define("DEBUG"); ++ ++ if (debug) { ++ foreground = one_process = 1; ++ no_detach = 0; ++ } ++ else ++ { ++ no_detach = ap_exists_config_define("NO_DETACH"); ++ one_process = ap_exists_config_define("ONE_PROCESS"); ++ foreground = ap_exists_config_define("FOREGROUND"); ++ } ++ ++ ap_mutex_register(p, AP_ACCEPT_MUTEX_TYPE, NULL, APR_LOCK_DEFAULT, 0); ++ ++ /* sigh, want this only the second time around */ ++ retained = ap_retained_data_get(userdata_key); ++ if (!retained) { ++ retained = ap_retained_data_create(userdata_key, sizeof(*retained)); ++ retained->max_daemons_limit = -1; ++ retained->idle_spawn_rate = 1; ++ } ++ ++retained->module_loads; ++ if (retained->module_loads == 2) { ++ if (!one_process && !foreground) { ++ /* before we detach, setup crash handlers to log to errorlog */ ++ ap_fatal_signal_setup(ap_server_conf, pconf); ++ rv = apr_proc_detach(no_detach ? APR_PROC_DETACH_FOREGROUND ++ : APR_PROC_DETACH_DAEMONIZE); ++ if (rv != APR_SUCCESS) { ++ ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL, APLOGNO(00174) ++ "apr_proc_detach failed"); ++ return HTTP_INTERNAL_SERVER_ERROR; ++ } ++ } ++ } ++ ++ parent_pid = ap_my_pid = getpid(); ++ ++ ap_listen_pre_config(); ++ ap_daemons_to_start = DEFAULT_START_DAEMON; ++ ap_daemons_min_free = DEFAULT_MIN_FREE_DAEMON; ++ ap_daemons_max_free = DEFAULT_MAX_FREE_DAEMON; ++ server_limit = DEFAULT_SERVER_LIMIT; ++ ap_daemons_limit = server_limit; ++ ap_extended_status = 0; ++ ++ return OK; ++} ++ ++static int itk_check_config(apr_pool_t *p, apr_pool_t *plog, ++ apr_pool_t *ptemp, server_rec *s) ++{ ++ int startup = 0; ++ ++ /* the reverse of pre_config, we want this only the first time around */ ++ if (retained->module_loads == 1) { ++ startup = 1; ++ } ++ ++ if (server_limit > MAX_SERVER_LIMIT) { ++ if (startup) { ++ ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, APLOGNO(00175) ++ "WARNING: ServerLimit of %d exceeds compile-time " ++ "limit of", server_limit); ++ ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, ++ " %d servers, decreasing to %d.", ++ MAX_SERVER_LIMIT, MAX_SERVER_LIMIT); ++ } else { ++ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(00176) ++ "ServerLimit of %d exceeds compile-time limit " ++ "of %d, decreasing to match", ++ server_limit, MAX_SERVER_LIMIT); ++ } ++ server_limit = MAX_SERVER_LIMIT; ++ } ++ else if (server_limit < 1) { ++ if (startup) { ++ ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, APLOGNO(00177) ++ "WARNING: ServerLimit of %d not allowed, " ++ "increasing to 1.", server_limit); ++ } else { ++ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(00178) ++ "ServerLimit of %d not allowed, increasing to 1", ++ server_limit); ++ } ++ server_limit = 1; ++ } ++ ++ /* you cannot change ServerLimit across a restart; ignore ++ * any such attempts ++ */ ++ if (!retained->first_server_limit) { ++ retained->first_server_limit = server_limit; ++ } ++ else if (server_limit != retained->first_server_limit) { ++ /* don't need a startup console version here */ ++ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(00179) ++ "changing ServerLimit to %d from original value of %d " ++ "not allowed during restart", ++ server_limit, retained->first_server_limit); ++ server_limit = retained->first_server_limit; ++ } ++ ++ if (ap_daemons_limit > server_limit) { ++ if (startup) { ++ ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, APLOGNO(00180) ++ "WARNING: MaxRequestWorkers of %d exceeds ServerLimit " ++ "value of", ap_daemons_limit); ++ ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, ++ " %d servers, decreasing MaxRequestWorkers to %d.", ++ server_limit, server_limit); ++ ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, ++ " To increase, please see the ServerLimit " ++ "directive."); ++ } else { ++ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(00181) ++ "MaxRequestWorkers of %d exceeds ServerLimit value " ++ "of %d, decreasing to match", ++ ap_daemons_limit, server_limit); ++ } ++ ap_daemons_limit = server_limit; ++ } ++ else if (ap_daemons_limit < 1) { ++ if (startup) { ++ ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, APLOGNO(00182) ++ "WARNING: MaxRequestWorkers of %d not allowed, " ++ "increasing to 1.", ap_daemons_limit); ++ } else { ++ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(00183) ++ "MaxRequestWorkers of %d not allowed, increasing to 1", ++ ap_daemons_limit); ++ } ++ ap_daemons_limit = 1; ++ } ++ ++ /* ap_daemons_to_start > ap_daemons_limit checked in itk_run() */ ++ if (ap_daemons_to_start < 0) { ++ if (startup) { ++ ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, APLOGNO(00184) ++ "WARNING: StartServers of %d not allowed, " ++ "increasing to 1.", ap_daemons_to_start); ++ } else { ++ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(00185) ++ "StartServers of %d not allowed, increasing to 1", ++ ap_daemons_to_start); ++ } ++ ap_daemons_to_start = 1; ++ } ++ ++ if (ap_daemons_min_free < 1) { ++ if (startup) { ++ ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, APLOGNO(00186) ++ "WARNING: MinSpareServers of %d not allowed, " ++ "increasing to 1", ap_daemons_min_free); ++ ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, ++ " to avoid almost certain server failure."); ++ ap_log_error(APLOG_MARK, APLOG_WARNING | APLOG_STARTUP, 0, NULL, ++ " Please read the documentation."); ++ } else { ++ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(00187) ++ "MinSpareServers of %d not allowed, increasing to 1", ++ ap_daemons_min_free); ++ } ++ ap_daemons_min_free = 1; ++ } ++ ++ /* ap_daemons_max_free < ap_daemons_min_free + 1 checked in itk_run() */ ++ ++ return OK; ++} ++ ++static int itk_post_perdir_config(request_rec *r) ++{ ++ uid_t wanted_uid; ++ gid_t wanted_gid; ++ const char *wanted_username; ++ int err = 0; ++ ++ itk_server_conf *sconf = ++ (itk_server_conf *) ap_get_module_config(r->server->module_config, &mpm_itk_module); ++ itk_per_dir_conf *dconf; ++ ++ /* Enforce MaxClientsVhost. */ ++ if (sconf->max_clients_vhost > 0) { ++ int i, num_other_servers = 0; ++ for (i = 0; i < ap_daemons_limit; ++i) { ++ worker_score *ws = &ap_scoreboard_image->servers[i][0]; ++ if (ws->status >= SERVER_BUSY_READ && strncmp(ws->vhost, r->server->server_hostname, 31) == 0) ++ ++num_other_servers; ++ } ++ ++ if (num_other_servers > sconf->max_clients_vhost) { ++ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, \ ++ "MaxClientsVhost reached for %s, refusing client.", ++ r->server->server_hostname); ++ return HTTP_SERVICE_UNAVAILABLE; ++ } ++ } ++ ++ dconf = (itk_per_dir_conf *) ap_get_module_config(r->per_dir_config, &mpm_itk_module); ++ ++ strncpy(ap_scoreboard_image->servers[my_child_num][0].vhost, r->server->server_hostname, 31); ++ ap_scoreboard_image->servers[my_child_num][0].vhost[31] = 0; ++ ++ if (dconf->nice_value != UNSET_NICE_VALUE && ++ setpriority(PRIO_PROCESS, 0, dconf->nice_value)) { ++ _DBG("setpriority(): %s", strerror(errno)); ++ err = 1; ++ } ++ ++ wanted_uid = dconf->uid; ++ wanted_gid = dconf->gid; ++ wanted_username = dconf->username; ++ ++ if (wanted_uid == -1 || wanted_gid == -1) { ++ wanted_uid = ap_unixd_config.user_id; ++ wanted_gid = ap_unixd_config.group_id; ++ wanted_username = ap_unixd_config.user_name; ++ } ++ ++ /* AssignUserIDExpr and AssignGroupIDExpr override AssignUserID and defaults. */ ++ if (dconf->uid_expr != NULL) { ++ struct passwd *ent; ++ const char *err; ++ wanted_username = ap_expr_str_exec(r, dconf->uid_expr, &err); ++ if (err) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, \ ++ "Error while parsing AssignUserIDExpr expression: %s", ++ err); ++ return HTTP_INTERNAL_SERVER_ERROR; ++ } ++ ++ if (!(ent = getpwnam(wanted_username))) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, \ ++ "AssignUserIDExpr returned '%s', which is not a valid user name", ++ wanted_username); ++ return HTTP_INTERNAL_SERVER_ERROR; ++ } ++ ++ wanted_uid = ent->pw_uid; ++ } ++ if (dconf->gid_expr != NULL) { ++ struct group *ent; ++ const char *err; ++ const char *wanted_groupname = ap_expr_str_exec(r, dconf->gid_expr, &err); ++ if (err) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, \ ++ "Error while parsing AssignGroupIDExpr expression: %s", ++ err); ++ return HTTP_INTERNAL_SERVER_ERROR; ++ } ++ ++ if (!(ent = getgrnam(wanted_groupname))) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, \ ++ "AssignGroupIDExpr returned '%s', which is not a valid group name", ++ wanted_username); ++ return HTTP_INTERNAL_SERVER_ERROR; ++ } ++ ++ wanted_gid = ent->gr_gid; ++ } ++ ++ if (!err && wanted_uid != -1 && wanted_gid != -1 && (getuid() != wanted_uid || getgid() != wanted_gid)) { ++ if (setgid(wanted_gid)) { ++ _DBG("setgid(%d): %s", wanted_gid, strerror(errno)); ++ err = 1; ++ } else if (initgroups(wanted_username, wanted_gid)) { ++ _DBG("initgroups(%s, %d): %s", wanted_username, wanted_gid, strerror(errno)); ++ err = 1; ++ } else if (setuid(wanted_uid)) { ++ _DBG("setuid(%d): %s", wanted_uid, strerror(errno)); ++ err = 1; ++ } ++ } ++ ++ /* ++ * Most likely a case of switching uid/gid within a persistent ++ * connection; the RFCs allow us to just close the connection ++ * at anytime, so we excercise our right. :-) ++ */ ++ if (err) { ++ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, \ ++ "Couldn't set uid/gid/priority, closing connection."); ++ ap_lingering_close(r->connection); ++ exit(0); ++ } ++ return OK; ++} ++ ++static void itk_hooks(apr_pool_t *p) ++{ ++ /* Our open_logs hook function must run before the core's, or stderr ++ * will be redirected to a file, and the messages won't print to the ++ * console. ++ */ ++ static const char *const aszSucc[] = {"core.c", NULL}; ++ ++ ap_hook_open_logs(itk_open_logs, NULL, aszSucc, APR_HOOK_REALLY_FIRST); ++ /* we need to set the MPM state before other pre-config hooks use MPM query ++ * to retrieve it, so register as REALLY_FIRST ++ */ ++ ap_hook_pre_config(itk_pre_config, NULL, NULL, APR_HOOK_REALLY_FIRST); ++ ap_hook_check_config(itk_check_config, NULL, NULL, APR_HOOK_MIDDLE); ++ ap_hook_mpm(itk_run, NULL, NULL, APR_HOOK_MIDDLE); ++ ap_hook_mpm_query(itk_query, NULL, NULL, APR_HOOK_MIDDLE); ++ ap_hook_mpm_get_name(itk_get_name, NULL, NULL, APR_HOOK_MIDDLE); ++ ++ /* set the uid as fast as possible, but not before merging per-dir config */ ++ ap_hook_header_parser(itk_post_perdir_config, NULL, NULL, APR_HOOK_REALLY_FIRST); ++} ++ ++static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy, const char *arg) ++{ ++ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); ++ if (err != NULL) { ++ return err; ++ } ++ ++ ap_daemons_to_start = atoi(arg); ++ return NULL; ++} ++ ++static const char *set_min_free_servers(cmd_parms *cmd, void *dummy, const char *arg) ++{ ++ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); ++ if (err != NULL) { ++ return err; ++ } ++ ++ ap_daemons_min_free = atoi(arg); ++ return NULL; ++} ++ ++static const char *set_max_free_servers(cmd_parms *cmd, void *dummy, const char *arg) ++{ ++ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); ++ if (err != NULL) { ++ return err; ++ } ++ ++ ap_daemons_max_free = atoi(arg); ++ return NULL; ++} ++ ++static const char *set_max_clients (cmd_parms *cmd, void *dummy, const char *arg) ++{ ++ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); ++ if (err != NULL) { ++ return err; ++ } ++ if (!strcasecmp(cmd->cmd->name, "MaxClients")) { ++ ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, APLOGNO(00188) ++ "MaxClients is deprecated, use MaxRequestWorkers " ++ "instead."); ++ } ++ ap_daemons_limit = atoi(arg); ++ return NULL; ++} ++ ++static const char *set_server_limit (cmd_parms *cmd, void *dummy, const char *arg) ++{ ++ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); ++ if (err != NULL) { ++ return err; ++ } ++ ++ server_limit = atoi(arg); ++ return NULL; ++} ++ ++static const char *assign_user_id (cmd_parms *cmd, void *ptr, const char *user_name, const char *group_name) ++{ ++ itk_per_dir_conf *dconf = (itk_per_dir_conf *) ptr; ++ ++ const char *err = ap_check_cmd_context(cmd, NOT_IN_HTACCESS); ++ if (err) { ++ return err; ++ } ++ ++ dconf->username = apr_pstrdup(cmd->pool, user_name); ++ dconf->uid = ap_uname2id(user_name); ++ dconf->gid = ap_gname2id(group_name); ++ return NULL; ++} ++ ++static const char *assign_user_id_expr (cmd_parms *cmd, void *ptr, const char *user_name_expr) ++{ ++ itk_per_dir_conf *dconf = (itk_per_dir_conf *) ptr; ++ ++ const char *err; ++ ++ err = ap_check_cmd_context(cmd, NOT_IN_HTACCESS); ++ if (err) { ++ return err; ++ } ++ ++ dconf->uid_expr = ap_expr_parse_cmd_mi(cmd, ++ user_name_expr, ++ AP_EXPR_FLAG_STRING_RESULT, ++ &err, ++ NULL, ++ AP_CORE_MODULE_INDEX); ++ if (err) { ++ return err; ++ } ++ ++ return NULL; ++} ++ ++static const char *assign_group_id_expr (cmd_parms *cmd, void *ptr, const char *group_name_expr) ++{ ++ itk_per_dir_conf *dconf = (itk_per_dir_conf *) ptr; ++ ++ const char *err; ++ ++ err = ap_check_cmd_context(cmd, NOT_IN_HTACCESS); ++ if (err) { ++ return err; ++ } ++ ++ dconf->gid_expr = ap_expr_parse_cmd_mi(cmd, ++ group_name_expr, ++ AP_EXPR_FLAG_STRING_RESULT, ++ &err, ++ NULL, ++ AP_CORE_MODULE_INDEX); ++ if (err) { ++ return err; ++ } ++ return NULL; ++} ++ ++static const char *set_max_clients_vhost (cmd_parms *cmd, void *dummy, const char *arg) ++{ ++ itk_server_conf *sconf = ++ (itk_server_conf *) ap_get_module_config(cmd->server->module_config, &mpm_itk_module); ++ sconf->max_clients_vhost = atoi(arg); ++ return NULL; ++} ++ ++static const char *set_nice_value (cmd_parms *cmd, void *ptr, const char *arg) ++{ ++ itk_per_dir_conf *dconf = (itk_per_dir_conf *) ptr; ++ int nice_value = atoi(arg); ++ ++ if (nice_value < -20) { ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, ++ "WARNING: NiceValue of %d is below -20, increasing NiceValue to -20.", ++ nice_value); ++ nice_value = -20; ++ } ++ else if (nice_value > 19) { ++ ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, ++ "WARNING: NiceValue of %d is above 19, lowering NiceValue to 19.", ++ nice_value); ++ nice_value = 19; ++ } ++ dconf->nice_value = nice_value; ++ return NULL; ++} ++ ++static const command_rec itk_cmds[] = { ++LISTEN_COMMANDS, ++AP_INIT_TAKE1("StartServers", set_daemons_to_start, NULL, RSRC_CONF, ++ "Number of child processes launched at server startup"), ++AP_INIT_TAKE1("MinSpareServers", set_min_free_servers, NULL, RSRC_CONF, ++ "Minimum number of idle children, to handle request spikes"), ++AP_INIT_TAKE1("MaxSpareServers", set_max_free_servers, NULL, RSRC_CONF, ++ "Maximum number of idle children"), ++AP_INIT_TAKE1("MaxClients", set_max_clients, NULL, RSRC_CONF, ++ "Deprecated name of MaxRequestWorkers"), ++AP_INIT_TAKE1("MaxRequestWorkers", set_max_clients, NULL, RSRC_CONF, ++ "Maximum number of children alive at the same time"), ++AP_INIT_TAKE1("ServerLimit", set_server_limit, NULL, RSRC_CONF, ++ "Maximum value of MaxRequestWorkers for this run of Apache"), ++AP_INIT_TAKE2("AssignUserID", assign_user_id, NULL, RSRC_CONF|ACCESS_CONF, ++ "Tie a virtual host to a specific child process."), ++AP_INIT_RAW_ARGS("AssignUserIDExpr", assign_user_id_expr, NULL, RSRC_CONF|ACCESS_CONF, ++ "Choose user ID given an expression. Will override AssignUserID."), ++AP_INIT_RAW_ARGS("AssignGroupIDExpr", assign_group_id_expr, NULL, RSRC_CONF|ACCESS_CONF, ++ "Choose group ID given an expression. Will override AssignUserID."), ++AP_INIT_TAKE1("MaxClientsVHost", set_max_clients_vhost, NULL, RSRC_CONF, ++ "Maximum number of children alive at the same time for this virtual host."), ++AP_INIT_TAKE1("NiceValue", set_nice_value, NULL, RSRC_CONF|ACCESS_CONF, ++ "Set nice value for the given vhost, from -20 (highest priority) to 19 (lowest priority)."), ++AP_GRACEFUL_SHUTDOWN_TIMEOUT_COMMAND, ++{ NULL } ++}; ++ ++/* == allocate a private per-dir config structure == */ ++static void *itk_create_dir_config(apr_pool_t *p, char *dummy) ++{ ++ itk_per_dir_conf *c = (itk_per_dir_conf *) ++ apr_pcalloc(p, sizeof(itk_per_dir_conf)); ++ c->uid = c->gid = -1; ++ c->uid_expr = c->gid_expr = NULL; ++ c->nice_value = UNSET_NICE_VALUE; ++ return c; ++} ++ ++/* == merge the parent per-dir config structure into ours == */ ++static void *itk_merge_dir_config(apr_pool_t *p, void *parent_ptr, void *child_ptr) ++{ ++ itk_per_dir_conf *c = (itk_per_dir_conf *) ++ itk_create_dir_config(p, NULL); ++ itk_per_dir_conf *parent = (itk_per_dir_conf *) parent_ptr; ++ itk_per_dir_conf *child = (itk_per_dir_conf *) child_ptr; ++ ++ if (child->username != NULL) { ++ c->username = child->username; ++ c->uid = child->uid; ++ c->gid = child->gid; ++ } else { ++ c->username = parent->username; ++ c->uid = parent->uid; ++ c->gid = parent->gid; ++ } ++ if (child->uid_expr != NULL) { ++ c->uid_expr = child->uid_expr; ++ } else { ++ c->uid_expr = parent->uid_expr; ++ } ++ if (child->gid_expr != NULL) { ++ c->gid_expr = child->gid_expr; ++ } else { ++ c->gid_expr = parent->gid_expr; ++ } ++ if (child->nice_value != UNSET_NICE_VALUE) { ++ c->nice_value = child->nice_value; ++ } else { ++ c->nice_value = parent->nice_value; ++ } ++ return c; ++} ++ ++/* == allocate a private server config structure == */ ++static void *itk_create_server_config(apr_pool_t *p, server_rec *s) ++{ ++ itk_server_conf *c = (itk_server_conf *) ++ apr_pcalloc(p, sizeof(itk_server_conf)); ++ c->max_clients_vhost = -1; ++ return c; ++} ++ ++AP_DECLARE_MODULE(mpm_itk) = { ++ MPM20_MODULE_STUFF, ++ NULL, /* hook to run before apache parses args */ ++ itk_create_dir_config, /* create per-directory config structure */ ++ itk_merge_dir_config, /* merge per-directory config structures */ ++ itk_create_server_config, /* create per-server config structure */ ++ NULL, /* merge per-server config structures */ ++ itk_cmds, /* command apr_table_t */ ++ itk_hooks, /* register hooks */ ++}; +Index: httpd-2.4.2/server/mpm/itk/mpm_default.h +=================================================================== +--- /dev/null ++++ httpd-2.4.2/server/mpm/itk/mpm_default.h +@@ -0,0 +1,57 @@ ++/* 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. ++ * ++ * Portions copyright 2005-2012 Steinar H. Gunderson . ++ * Licensed under the same terms as the rest of Apache. ++ * ++ * Portions copyright 2008 Knut Auvor Grythe . ++ * Licensed under the same terms as the rest of Apache. ++ */ ++ ++/** ++ * @file itk/mpm_default.h ++ * @brief ITK MPM defaults ++ * ++ * @defgroup APACHE_MPM_ITK Apache ITK ++ * @ingroup APACHE_INTERNAL ++ * @{ ++ */ ++ ++#ifndef APACHE_MPM_DEFAULT_H ++#define APACHE_MPM_DEFAULT_H ++ ++/* Number of servers to spawn off by default --- also, if fewer than ++ * this free when the caretaker checks, it will spawn more. ++ */ ++#ifndef DEFAULT_START_DAEMON ++#define DEFAULT_START_DAEMON 5 ++#endif ++ ++/* Maximum number of *free* server processes --- more than this, and ++ * they will die off. ++ */ ++ ++#ifndef DEFAULT_MAX_FREE_DAEMON ++#define DEFAULT_MAX_FREE_DAEMON 10 ++#endif ++ ++/* Minimum --- fewer than this, and more will be created */ ++ ++#ifndef DEFAULT_MIN_FREE_DAEMON ++#define DEFAULT_MIN_FREE_DAEMON 5 ++#endif ++ ++#endif /* AP_MPM_DEFAULT_H */ ++/** @} */ +Index: httpd-2.4.2/server/mpm/config2.m4 +=================================================================== +--- httpd-2.4.2.orig/server/mpm/config2.m4 ++++ httpd-2.4.2/server/mpm/config2.m4 +@@ -1,7 +1,7 @@ + AC_MSG_CHECKING(which MPM to use by default) + AC_ARG_WITH(mpm, + APACHE_HELP_STRING(--with-mpm=MPM,Choose the process model for Apache to use by default. +- MPM={event|worker|prefork|winnt} ++ MPM={event|worker|prefork|winnt|itk} + This will be statically linked as the only available MPM unless + --enable-mpms-shared is also specified. + ),[ +@@ -66,6 +66,9 @@ for i in $ap_enabled_mpms; do + else + AC_MSG_ERROR([MPM $i is not supported on this platform.]) + fi ++ if test "$i" = "itk" ; then ++ AC_CHECK_LIB(cap, cap_init) ++ fi + done + + if test $mpm_build = "shared"; then +Index: httpd-2.4.2/modules/arch/unix/config5.m4 +=================================================================== +--- httpd-2.4.2.orig/modules/arch/unix/config5.m4 ++++ httpd-2.4.2/modules/arch/unix/config5.m4 +@@ -3,6 +3,7 @@ APACHE_MODPATH_INIT(arch/unix) + + if ap_mpm_is_enabled "worker" \ + || ap_mpm_is_enabled "event" \ ++ || ap_mpm_is_enabled "itk" \ + || ap_mpm_is_enabled "prefork"; then + unixd_mods_enable=yes + else +Index: httpd-2.4.2/server/request.c +=================================================================== +--- httpd-2.4.2.orig/server/request.c ++++ httpd-2.4.2/server/request.c +@@ -69,6 +69,7 @@ APR_HOOK_STRUCT( + APR_HOOK_LINK(auth_checker) + APR_HOOK_LINK(insert_filter) + APR_HOOK_LINK(create_request) ++ APR_HOOK_LINK(post_perdir_config) + ) + + AP_IMPLEMENT_HOOK_RUN_FIRST(int,translate_name, +@@ -91,10 +92,26 @@ AP_IMPLEMENT_HOOK_VOID(insert_filter, (r + AP_IMPLEMENT_HOOK_RUN_ALL(int, create_request, + (request_rec *r), (r), OK, DECLINED) + ++/** ++ * This hook allows modules to affect the request immediately after the ++ * per-directory configuration for the request has been generated. This allows ++ * modules to make decisions based upon the current directory configuration ++ * ++ * This hook is private to mpm-itk, so it is not exposed in http_request.h. ++ * ++ * @param r The current request ++ * @return OK or DECLINED ++ */ ++AP_DECLARE_HOOK(int,post_perdir_config,(request_rec *r)) ++ ++AP_IMPLEMENT_HOOK_RUN_ALL(int,post_perdir_config, ++ (request_rec *r), (r), OK, DECLINED) ++ + static int auth_internal_per_conf = 0; + static int auth_internal_per_conf_hooks = 0; + static int auth_internal_per_conf_providers = 0; + ++extern AP_DECLARE_DATA int ap_running_under_mpm_itk; + + static int decl_die(int status, const char *phase, request_rec *r) + { +@@ -191,6 +208,13 @@ AP_DECLARE(int) ap_process_request_inter + r->log = d->log; + } + ++ /* First chance to handle the request after per-directory configuration is ++ * generated ++ */ ++ if ((access_status = ap_run_post_perdir_config(r))) { ++ return access_status; ++ } ++ + /* Only on the main request! */ + if (r->main == NULL) { + if ((access_status = ap_run_header_parser(r))) { +@@ -1093,6 +1117,16 @@ AP_DECLARE(int) ap_directory_walk(reques + break; + } + else if (APR_STATUS_IS_EACCES(rv)) { ++ /* See the corresponding section in server/config.c for the rationale ++ * behind this logic. ++ */ ++ if (ap_running_under_mpm_itk && r->main == NULL && getuid() != 0) { ++ ap_log_rerror(APLOG_MARK, APLOG_WARNING, rv, r, ++ "Access to %s denied, closing connection.", ++ r->filename); ++ ap_lingering_close(r->connection); ++ exit(0); ++ } + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(00035) + "access to %s denied (filesystem path '%s') " + "because search permissions are missing on a " +Index: httpd-2.4.2/server/config.c +=================================================================== +--- httpd-2.4.2.orig/server/config.c ++++ httpd-2.4.2/server/config.c +@@ -69,6 +69,8 @@ AP_DECLARE_DATA apr_array_header_t *ap_s + + AP_DECLARE_DATA ap_directive_t *ap_conftree = NULL; + ++AP_DECLARE_DATA int ap_running_under_mpm_itk = 0; ++ + APR_HOOK_STRUCT( + APR_HOOK_LINK(header_parser) + APR_HOOK_LINK(pre_config) +@@ -2129,6 +2131,32 @@ AP_CORE_DECLARE(int) ap_parse_htaccess(a + else { + if (!APR_STATUS_IS_ENOENT(status) + && !APR_STATUS_IS_ENOTDIR(status)) { ++ /* ++ * If we are in a persistent connection, we might end up in a state ++ * where we can no longer read .htaccess files because we have already ++ * setuid(). This can either be because the previous request was for ++ * another vhost (basically the same problem as when setuid() fails in ++ * itk.c), or it can be because a .htaccess file is readable only by ++ * root. ++ * ++ * In any case, we don't want to give out a 403, since the request has ++ * a very real chance of succeeding on a fresh connection (where ++ * presumably uid=0). Thus, we give up serving the request on this ++ * TCP connection, and do a hard close of the socket. As long as we're ++ * in a persistent connection (and there _should_ not be a way this ++ * would happen on the first request in a connection, save for subrequests, ++ * which we special-case), this is allowed, as it is what happens on ++ * a timeout. The browser will simply open a new connection and try ++ * again (there's of course a performance hit, though, both due to ++ * the new connection setup and the fork() of a new server child). ++ */ ++ if (ap_running_under_mpm_itk && r->main == NULL && getuid() != 0) { ++ ap_log_rerror(APLOG_MARK, APLOG_WARNING, status, r, ++ "Couldn't read %s, closing connection.", ++ filename); ++ ap_lingering_close(r->connection); ++ exit(0); ++ } + ap_log_rerror(APLOG_MARK, APLOG_CRIT, status, r, APLOGNO(00529) + "%s pcfg_openfile: unable to check htaccess file, " + "ensure it is readable and that '%s' " diff --git a/apache2.changes b/apache2.changes index 11bf6f7..a457da8 100644 --- a/apache2.changes +++ b/apache2.changes @@ -1,3 +1,15 @@ +------------------------------------------------------------------- +Wed Aug 1 01:14:35 UTC 2012 - crrodriguez@opensuse.org + +- Upgrade to apache 2.4.2 +** ATTENTION, before installing this update YOU MUST +READ http://httpd.apache.org/docs/2.4/upgrading.html +CAREFULLY otherwise your server will most likely +fail to start due to backward incompatible changes. + +* You can read the huge complete list of changes + at http://httpd.apache.org/docs/2.4/new_features_2_4.html + ------------------------------------------------------------------- Wed Jul 25 11:32:34 UTC 2012 - saschpe@suse.de diff --git a/apache2.spec b/apache2.spec index 6b7bf9b..61ec81a 100644 --- a/apache2.spec +++ b/apache2.spec @@ -47,7 +47,7 @@ BuildRequires: expat-devel %define pname apache2 %define vers 2 %define httpd httpd2 -%define apache_mmn %(test -s %{S:0} && { echo -n apache_mmn_; bzcat %{S:0} | awk '/^#define MODULE_MAGIC_NUMBER_MAJOR/ {printf "%d", $3}'; }) +%define apache_mmn %(test -s %{S:0} && { echo -n apache_mmn_; xzcat %{S:0} | awk '/^#define MODULE_MAGIC_NUMBER_MAJOR/ {printf "%d", $3}'; }) %define default_mpm prefork %{!?prefork:%define prefork 1} %{!?worker:%define worker 1} @@ -74,14 +74,13 @@ BuildRequires: expat-devel # "Server:" header %define VENDOR SUSE %define platform_string Linux/%VENDOR -%define realver 2.2.22 -Version: 2.2.22 +%define realver 2.4.2 +Version: 2.4.2 Release: 0 #Source0: http://www.apache.org/dist/httpd-%{version}.tar.bz2 -Source0: http://httpd.apache.org/dev/dist/httpd-%{realver}.tar.bz2 +Source0: http://httpd.apache.org/dev/dist/httpd-%{realver}.tar.xz # Add file to take mtime from it in prep section Source1: apache2.changes -Source5: http://httpd.apache.org/dev/dist/httpd-%{realver}.tar.bz2.asc Source6: 60C5442D.key Source10: SUSE-NOTICE Source11: rc.%{pname} @@ -139,14 +138,8 @@ Patch66: httpd-2.0.54-envvars.dif Patch67: httpd-2.2.0-apxs-a2enmod.dif Patch68: httpd-2.x.x-logresolve.patch Patch69: httpd-2.2.x-bnc690734.patch -Patch100: apache2.2-mpm-itk-20090414-00.patch +Patch100: apache2.4-mpm-itk-2.4.2-01.patch Patch101: httpd-2.2.19-linux3.patch -Patch102: httpd-keepalivetimeout-millisecs.patch -Patch104: httpd-mod_deflate_head.patch -Patch105: ssl-mode-release-buffers.patch -Patch106: httpd-2.2.x-CVE-2011-3368-server_protocl_c.diff -# PATCH-FIX-UPSTREAM https://issues.apache.org/bugzilla/show_bug.cgi?id=52623 -Patch107: httpd-new_pcre.patch # PATCH-FEATURE-UPSTREAM apache2-mod_ssl_npn.patch dimstar@opensuse.org -- Add npn support to mod_ssl (needed for spdy) Patch108: apache2-mod_ssl_npn.patch Provides: apache2(mod_ssl+npn) @@ -362,22 +355,15 @@ to administrators of web servers in general. # %setup -q -n httpd-%{realver} %patch2 -p1 -%patch23 -p1 +%patch23 %patch65 -p1 -%patch66 -p1 +%patch66 %patch67 -p1 %patch68 -p1 %patch69 -%patch100 +%patch100 -p1 %patch101 -%patch102 -%patch104 -%patch105 -%patch106 -%if 0%{?suse_version} >= 1220 -%patch107 -%endif -%patch108 +%patch108 -p1 # cat $RPM_SOURCE_DIR/SUSE-NOTICE >> NOTICE @@ -480,7 +466,8 @@ function configure { --with-suexec-userdir=%{userdir} \ --with-suexec-uidmin=96 \ --with-suexec-gidmin=96 \ - --with-suexec-safepath=%{suexec_safepath} + --with-suexec-safepath=%{suexec_safepath} \ + --disable-heartbeat } # @@ -737,17 +724,21 @@ pushd $RPM_BUILD_ROOT/%{_mandir} mv $i ${i%.*}%{vers}.${i#*.*.} || true done popd + +pushd $RPM_BUILD_ROOT/%{_bindir} +for i in ab dbmmanage htdbm htdigest htpasswd logresolve;do +mv $i ${i}%{vers} || true +done +popd + pushd $RPM_BUILD_ROOT/%{_sbindir} - for i in ab dbmmanage htdbm htdigest htpasswd logresolve rotatelogs suexec; do + for i in rotatelogs suexec; do mv $i ${i}%{vers} || true done mv apachectl apachectl.tmp; mv apachectl.tmp apache%{vers}ctl - for i in dbmmanage htdbm htdigest htpasswd; do - mv ${i}%{vers} ../bin/ - done popd # fix up apxs -pushd $RPM_BUILD_ROOT/%{_sbindir} +pushd $RPM_BUILD_ROOT/%{_bindir} for mpm in %{mpms_to_build}; do cat <<-EOT_ED | ed -s apxs H @@ -785,7 +776,7 @@ for mpm in %{mpms_to_build}; do echo %dir %{_libdir}/%{pname}-$mpm >> filelist ( echo %dir %{includedir}-$mpm - echo %{_sbindir}/apxs%{vers}-$mpm + echo %{_bindir}/apxs%{vers}-$mpm ) >> filelist-devel done find $RPM_BUILD_ROOT/%{includedir}/.. -type f -o -type l \ @@ -827,6 +818,7 @@ sed -e 's+/usr/%_lib+'$RPM_BUILD_ROOT'/usr/%_lib+' \ -e 's+%{sysconfdir}+'$RPM_BUILD_ROOT'%{sysconfdir}+' \ -e 's+%{datadir}+'$RPM_BUILD_ROOT'%{datadir}+' \ -e 's+\.conf$+&.test+' \ + -e 's+/var/log+'$RPM_BUILD_ROOT'/var/log+' \ httpd.conf > httpd.conf.test sed -e 's+%{sysconfdir}+'$RPM_BUILD_ROOT'%{sysconfdir}+' \ default-server.conf > default-server.conf.test @@ -973,7 +965,7 @@ mv $RPM_BUILD_ROOT/%{sysconfdir}/original . %dir %{_prefix}/share/%{pname} %dir %{installbuilddir} %dir %{includedir} -%{_sbindir}/apxs%{vers} +%{_bindir}/apxs%{vers} %files doc %defattr(-,root,root) @@ -999,6 +991,8 @@ mv $RPM_BUILD_ROOT/%{sysconfdir}/original . %doc %{_mandir}/man?/logresolve%{vers}.?.* %doc %{_mandir}/man?/rotatelogs%{vers}.?.* %doc %{_mandir}/man?/suexec%{vers}.?.* +%{_sbindir}/fcgistarter +%{_mandir}/man8/fcgistarter2.8.* %{_bindir}/check_forensic%{vers} %{_bindir}/dbmmanage%{vers} %{_bindir}/gensslcert @@ -1006,10 +1000,10 @@ mv $RPM_BUILD_ROOT/%{sysconfdir}/original . %{_bindir}/htdigest%{vers} %{_bindir}/htpasswd%{vers} %{_bindir}/split-logfile%{vers} -%{_sbindir}/ab%{vers} -%{_sbindir}/httxt2dbm +%{_bindir}/ab%{vers} +%{_bindir}/httxt2dbm %{_sbindir}/logresolve.pl%{vers} -%{_sbindir}/logresolve%{vers} +%{_bindir}/logresolve%{vers} %{_sbindir}/rotatelogs%{vers} %verify(not mode) %attr(0755,root,root) %_sbindir/suexec2 %if %prefork diff --git a/httpd-2.0.54-envvars.dif b/httpd-2.0.54-envvars.dif index 7c1f3fe..7e0ea8e 100644 --- a/httpd-2.0.54-envvars.dif +++ b/httpd-2.0.54-envvars.dif @@ -1,11 +1,17 @@ -diff -uNr httpd-2.0.54.orig/support/envvars-std.in httpd-2.0.54/support/envvars-std.in ---- httpd-2.0.54.orig/support/envvars-std.in 2005-02-04 21:21:18.000000000 +0100 -+++ httpd-2.0.54/support/envvars-std.in 2005-10-07 13:56:49.223546288 +0200 -@@ -19,6 +19,6 @@ +--- support/envvars-std.in.orig ++++ support/envvars-std.in +@@ -18,11 +18,9 @@ + # # This file is generated from envvars-std.in # --@SHLIBPATH_VAR@="@exp_libdir@:$@SHLIBPATH_VAR@" +-if test "x$@SHLIBPATH_VAR@" != "x" ; then +- @SHLIBPATH_VAR@="@exp_libdir@:$@SHLIBPATH_VAR@" +-else +- @SHLIBPATH_VAR@="@exp_libdir@" +-fi ++ +@SHLIBPATH_VAR@="@exp_libdir@${@SHLIBPATH_VAR@+:$@SHLIBPATH_VAR@}" ++ export @SHLIBPATH_VAR@ # @OS_SPECIFIC_VARS@ diff --git a/httpd-2.1.9-apachectl.dif b/httpd-2.1.9-apachectl.dif index 3d25d4c..abe1651 100644 --- a/httpd-2.1.9-apachectl.dif +++ b/httpd-2.1.9-apachectl.dif @@ -1,7 +1,6 @@ -diff -uNr httpd-2.1.3-alpha.orig/support/apachectl.in httpd-2.1.3-alpha/support/apachectl.in ---- httpd-2.1.3-alpha.orig/support/apachectl.in 2005-02-04 21:28:49.000000000 +0100 -+++ httpd-2.1.3-alpha/support/apachectl.in 2005-02-25 02:52:49.203566813 +0100 -@@ -41,17 +41,32 @@ +--- support/apachectl.in.orig ++++ support/apachectl.in +@@ -42,17 +42,32 @@ ARGV="$@" # -------------------- -------------------- # # the path to your httpd binary, including options if necessary @@ -36,16 +35,16 @@ diff -uNr httpd-2.1.3-alpha.orig/support/apachectl.in httpd-2.1.3-alpha/support/ # # the URL to your server's mod_status status page. If you do not # have one, then status and fullstatus will not work. -@@ -77,7 +92,7 @@ +@@ -78,7 +93,7 @@ fi - case $ARGV in + case $ACMD in start|stop|restart|graceful|graceful-stop) - $HTTPD -k $ARGV + $HTTPD ${httpd_conf+-f $httpd_conf} -k $ARGV ERROR=$? ;; startssl|sslstart|start-SSL) -@@ -87,7 +102,7 @@ +@@ -88,7 +103,7 @@ startssl|sslstart|start-SSL) ERROR=2 ;; configtest) @@ -54,12 +53,3 @@ diff -uNr httpd-2.1.3-alpha.orig/support/apachectl.in httpd-2.1.3-alpha/support/ ERROR=$? ;; status) -@@ -97,7 +112,7 @@ - $LYNX $STATUSURL - ;; - *) -- $HTTPD $ARGV -+ $HTTPD ${httpd_conf+-f $httpd_conf} $ARGV - ERROR=$? - esac - diff --git a/httpd-2.2.22.tar.bz2 b/httpd-2.2.22.tar.bz2 deleted file mode 100644 index 01c3754..0000000 --- a/httpd-2.2.22.tar.bz2 +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:dcdc9f1dc722f84798caf69d69dca78daa5e09a4269060045aeca7e4f44cb231 -size 5378934 diff --git a/httpd-2.2.22.tar.bz2.asc b/httpd-2.2.22.tar.bz2.asc deleted file mode 100644 index b8ef53be8e5a843edf4fed8cf0b458cac42076d48c92ba03797aa588c6e5719f..0000000000000000000000000000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 678 zcmV;X0$KeZiwFP!0000018tMHlA~Av0CT=V;cZbf=;7I_3-Cq=FF<5~5Kef{*YE7b z*I|cU)n8vfaH6al7fZG-t|}X>_i)6&`U~>2aVop^_eE|OOTMh&8~XT zRWq$a6L}4H+eCuZVQtI+0W%e&34hvECoYfUJspDN6>KNHPF#23zB+Ad-=WSdSNd@0 zYiK^gLBg#;0YQ3#y{v9tBCtDb4TOejgM-t1>Iq{s!b2wP4XxjX`K>}6-EUaLhe5Jz zfk@o}@;-7qjiZykV)Bu6&7vHwTQ&1B6|)n~!Sre2|{%J6|%$phKV~O0Y?Z?bd z`OgdFKBk9O8PjItp5+FpN+y7lehjAC#K>5Mz0J6lFQCNyjAU9k!4{Ibm%=RZTyT44 z%;z&Mb089!!-*Lw^yuuLoRPggIq?E8F$9B;CCdnDPK&^jy)9QC)%Nm9_2G@I7Qb=T z&EPBanPud@MhuGQ?}hFC*Iw7RNW!_#+QbQ&O3UiwZg6d|$304KRpq5uE@ diff --git a/httpd-2.2.x-CVE-2011-3368-server_protocl_c.diff b/httpd-2.2.x-CVE-2011-3368-server_protocl_c.diff deleted file mode 100644 index 63b9b6f..0000000 --- a/httpd-2.2.x-CVE-2011-3368-server_protocl_c.diff +++ /dev/null @@ -1,68 +0,0 @@ -diff -rNU 20 ../httpd-2.2.21-o/server/protocol.c ./server/protocol.c ---- ../httpd-2.2.21-o/server/protocol.c 2011-05-07 13:39:29.000000000 +0200 -+++ ./server/protocol.c 2011-10-07 17:10:46.000000000 +0200 -@@ -623,40 +623,64 @@ - - #if 0 - /* XXX If we want to keep track of the Method, the protocol module should do - * it. That support isn't in the scoreboard yet. Hopefully next week - * sometime. rbb */ - ap_update_connection_status(AP_CHILD_THREAD_FROM_ID(conn->id), "Method", - r->method); - #endif - - uri = ap_getword_white(r->pool, &ll); - - /* Provide quick information about the request method as soon as known */ - - r->method_number = ap_method_number_of(r->method); - if (r->method_number == M_GET && r->method[0] == 'H') { - r->header_only = 1; - } - - ap_parse_uri(r, uri); - -+/* -+ https://svn.apache.org/viewvc/httpd/httpd/trunk/server/protocol.c?r1=1178566&r2=1179239&pathrev=1179239&view=patch -+ This is the fix for CVE-2011-3368; via bnc#722545. -+ */ -+ -+ /* RFC 2616: -+ * Request-URI = "*" | absoluteURI | abs_path | authority -+ * -+ * authority is a special case for CONNECT. If the request is not -+ * using CONNECT, and the parsed URI does not have scheme, and -+ * it does not begin with '/', and it is not '*', then, fail -+ * and give a 400 response. */ -+ if (r->method_number != M_CONNECT -+ && !r->parsed_uri.scheme -+ && uri[0] != '/' -+ && !(uri[0] == '*' && uri[1] == '\0')) { -+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, -+ "invalid request-URI %s", uri); -+ r->args = NULL; -+ r->hostname = NULL; -+ r->status = HTTP_BAD_REQUEST; -+ r->uri = apr_pstrdup(r->pool, uri); -+ } -+ - if (ll[0]) { - r->assbackwards = 0; - pro = ll; - len = strlen(ll); - } else { - r->assbackwards = 1; - pro = "HTTP/0.9"; - len = 8; - } - r->protocol = apr_pstrmemdup(r->pool, pro, len); - - /* XXX ap_update_connection_status(conn->id, "Protocol", r->protocol); */ - - /* Avoid sscanf in the common case */ - if (len == 8 - && pro[0] == 'H' && pro[1] == 'T' && pro[2] == 'T' && pro[3] == 'P' - && pro[4] == '/' && apr_isdigit(pro[5]) && pro[6] == '.' - && apr_isdigit(pro[7])) { - r->proto_num = HTTP_VERSION(pro[5] - '0', pro[7] - '0'); - } diff --git a/httpd-2.2.x-bnc690734.patch b/httpd-2.2.x-bnc690734.patch index 68e142a..87ce840 100644 --- a/httpd-2.2.x-bnc690734.patch +++ b/httpd-2.2.x-bnc690734.patch @@ -1,7 +1,6 @@ -diff -ruN ../httpd-2.2.17-o/server/util_script.c ./server/util_script.c ---- ../httpd-2.2.17-o/server/util_script.c 2009-01-12 14:59:56.000000000 +0100 -+++ ./server/util_script.c 2011-07-26 15:39:50.000000000 +0200 -@@ -406,6 +406,7 @@ +--- server/util_script.c.orig ++++ server/util_script.c +@@ -415,6 +415,7 @@ AP_DECLARE(int) ap_scan_script_header_er { char x[MAX_STRING_LEN]; char *w, *l; @@ -9,7 +8,7 @@ diff -ruN ../httpd-2.2.17-o/server/util_script.c ./server/util_script.c int p; int cgi_status = HTTP_UNSET; apr_table_t *merge; -@@ -414,7 +415,14 @@ +@@ -425,7 +426,14 @@ AP_DECLARE(int) ap_scan_script_header_er if (buffer) { *buffer = '\0'; } @@ -25,17 +24,17 @@ diff -ruN ../httpd-2.2.17-o/server/util_script.c ./server/util_script.c /* temporary place to hold headers to merge in later */ merge = apr_table_make(r->pool, 10); -@@ -430,7 +438,7 @@ +@@ -441,7 +449,7 @@ AP_DECLARE(int) ap_scan_script_header_er while (1) { - int rv = (*getsfunc) (w, MAX_STRING_LEN - 1, getsfunc_data); + int rv = (*getsfunc) (w, wlen - 1, getsfunc_data); if (rv == 0) { - ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_TOCLIENT, 0, r, - "Premature end of script headers: %s", -@@ -537,9 +545,12 @@ - + const char *msg = "Premature end of script headers"; + if (first_header) +@@ -553,9 +561,12 @@ AP_DECLARE(int) ap_scan_script_header_er + if (!(l = strchr(w, ':'))) { if (!buffer) { /* Soak up all the script output - may save an outright kill */ - while ((*getsfunc) (w, MAX_STRING_LEN - 1, getsfunc_data)) { @@ -47,4 +46,4 @@ diff -ruN ../httpd-2.2.17-o/server/util_script.c ./server/util_script.c + buffer[MAX_STRING_LEN - 1] = 0; } - ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_TOCLIENT, 0, r, + ap_log_rerror(SCRIPT_LOG_MARK, APLOG_ERR|APLOG_TOCLIENT, 0, r, diff --git a/httpd-2.4.2.tar.xz b/httpd-2.4.2.tar.xz new file mode 100644 index 0000000..b80724c --- /dev/null +++ b/httpd-2.4.2.tar.xz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:932c695ff1ff7c907f67bed7462faf567d99744306b8491ba9db6bb0e8135905 +size 3645528 diff --git a/httpd-keepalivetimeout-millisecs.patch b/httpd-keepalivetimeout-millisecs.patch deleted file mode 100644 index 2970a91..0000000 --- a/httpd-keepalivetimeout-millisecs.patch +++ /dev/null @@ -1,20 +0,0 @@ ---- modules/http/http_core.c.orig -+++ modules/http/http_core.c -@@ -47,12 +47,15 @@ static int ap_process_http_connection(co - static const char *set_keep_alive_timeout(cmd_parms *cmd, void *dummy, - const char *arg) - { -+ apr_interval_time_t timeout; - const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); - if (err != NULL) { - return err; - } -- -- cmd->server->keep_alive_timeout = apr_time_from_sec(atoi(arg)); -+ /* Stolen from mod_proxy.c */ -+ if (ap_timeout_parameter_parse(arg, &timeout, "s") != APR_SUCCESS) -+ return "KeepAliveTimeout has wrong format"; -+ cmd->server->keep_alive_timeout = timeout; - return NULL; - } - diff --git a/httpd-mod_deflate_head.patch b/httpd-mod_deflate_head.patch deleted file mode 100644 index 6d4011a..0000000 --- a/httpd-mod_deflate_head.patch +++ /dev/null @@ -1,23 +0,0 @@ ---- modules/filters/mod_deflate.c.orig -+++ modules/filters/mod_deflate.c -@@ -582,6 +582,20 @@ static apr_status_t deflate_out_filter(a - apr_bucket *b; - apr_size_t len; - -+ /* -+ * Optimization: If we are a HEAD request and bytes_sent is not zero -+ * it means that we have passed the content-length filter once and -+ * have more data to sent. This means that the content-length filter -+ * could not determine our content-length for the response to the -+ * HEAD request anyway (the associated GET request would deliver the -+ * body in chunked encoding) and we can stop compressing. -+ */ -+ if (r->header_only && r->bytes_sent) { -+ ap_remove_output_filter(f); -+ return ap_pass_brigade(f->next, bb); -+ } -+ -+ - e = APR_BRIGADE_FIRST(bb); - - if (APR_BUCKET_IS_EOS(e)) { diff --git a/ssl-mode-release-buffers.patch b/ssl-mode-release-buffers.patch deleted file mode 100644 index 5898966..0000000 --- a/ssl-mode-release-buffers.patch +++ /dev/null @@ -1,13 +0,0 @@ ---- modules/ssl/ssl_engine_init.c.orig -+++ modules/ssl/ssl_engine_init.c -@@ -482,7 +482,9 @@ static void ssl_init_ctx_protocol(server - } - - mctx->ssl_ctx = ctx; -- -+#ifdef SSL_MODE_RELEASE_BUFFERS -+ SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS); -+#endif - SSL_CTX_set_options(ctx, SSL_OP_ALL); - - if (!(protocol & SSL_PROTOCOL_SSLV2)) {