From 6adfc1fc307720912f0d244708f05a14123e0b5c Mon Sep 17 00:00:00 2001 From: webbuilder_pel7x64builder0 Date: Wed, 5 Sep 2018 15:53:23 +0200 Subject: [PATCH] httpd package update Signed-off-by: webbuilder_pel7x64builder0 --- SOURCES/00-base.conf | 77 + SOURCES/00-dav.conf | 3 + SOURCES/00-lua.conf | 1 + SOURCES/00-mpm.conf | 19 + SOURCES/00-proxy.conf | 16 + SOURCES/00-proxyhtml.conf | 3 + SOURCES/00-ssl.conf | 1 + SOURCES/00-systemd.conf | 2 + SOURCES/01-cgi.conf | 14 + SOURCES/01-ldap.conf | 3 + SOURCES/01-session.conf | 6 + SOURCES/httpd-2.4.1-apctl.patch | 94 + SOURCES/httpd-2.4.1-corelimit.patch | 35 + SOURCES/httpd-2.4.1-deplibs.patch | 19 + SOURCES/httpd-2.4.1-selinux.patch | 61 + SOURCES/httpd-2.4.2-icons.patch | 26 + SOURCES/httpd-2.4.3-apctl-systemd.patch | 45 + SOURCES/httpd-2.4.3-apxs.patch | 56 + SOURCES/httpd-2.4.3-layout.patch | 34 + SOURCES/httpd-2.4.3-mod_systemd.patch | 163 ++ SOURCES/httpd-2.4.3-sslsninotreq.patch | 83 + SOURCES/httpd-2.4.4-cachehardmax.patch | 82 + SOURCES/httpd-2.4.4-export.patch | 20 + SOURCES/httpd-2.4.4-malformed-host.patch | 12 + SOURCES/httpd-2.4.4-mod_unique_id.patch | 239 ++ SOURCES/httpd-2.4.4-r1337344+.patch | 250 ++ SOURCES/httpd-2.4.6-CVE-2013-4352.patch | 25 + SOURCES/httpd-2.4.6-CVE-2013-5704.patch | 381 +++ SOURCES/httpd-2.4.6-CVE-2013-6438.patch | 14 + SOURCES/httpd-2.4.6-CVE-2014-0098.patch | 41 + SOURCES/httpd-2.4.6-CVE-2014-0117.patch | 11 + SOURCES/httpd-2.4.6-CVE-2014-0118.patch | 266 +++ SOURCES/httpd-2.4.6-CVE-2014-0226.patch | 119 + SOURCES/httpd-2.4.6-CVE-2014-0231.patch | 144 ++ SOURCES/httpd-2.4.6-CVE-2014-3581.patch | 17 + SOURCES/httpd-2.4.6-CVE-2015-3183.patch | 982 ++++++++ SOURCES/httpd-2.4.6-CVE-2015-3185.patch | 175 ++ SOURCES/httpd-2.4.6-CVE-2016-0736.patch | 325 +++ SOURCES/httpd-2.4.6-CVE-2016-2161.patch | 121 + SOURCES/httpd-2.4.6-CVE-2016-5387.patch | 16 + SOURCES/httpd-2.4.6-CVE-2016-8743.patch | 2124 +++++++++++++++++ SOURCES/httpd-2.4.6-CVE-2017-3167.patch | 343 +++ SOURCES/httpd-2.4.6-CVE-2017-3169.patch | 64 + SOURCES/httpd-2.4.6-CVE-2017-7668.patch | 15 + SOURCES/httpd-2.4.6-CVE-2017-7679.patch | 14 + SOURCES/httpd-2.4.6-CVE-2017-9788.patch | 29 + SOURCES/httpd-2.4.6-CVE-2017-9798.patch | 17 + SOURCES/httpd-2.4.6-ab-overflow.patch | 20 + SOURCES/httpd-2.4.6-ab-ssl-error.patch | 27 + SOURCES/httpd-2.4.6-ap-ipv6.patch | 139 ++ SOURCES/httpd-2.4.6-apachectl-httpd-env.patch | 38 + SOURCES/httpd-2.4.6-apachectl-status.patch | 13 + SOURCES/httpd-2.4.6-bomb.patch | 14 + SOURCES/httpd-2.4.6-dhparams-free.patch | 31 + SOURCES/httpd-2.4.6-full-release.patch | 48 + ...d-2.4.6-http-protocol-options-define.patch | 17 + SOURCES/httpd-2.4.6-ldaprefer.patch | 73 + ...pd-2.4.6-mod_authz_dbd-missing-query.patch | 55 + SOURCES/httpd-2.4.6-mpm-segfault.patch | 10 + SOURCES/httpd-2.4.6-pre_htaccess.patch | 140 ++ SOURCES/httpd-2.4.6-r1332643+.patch | 313 +++ SOURCES/httpd-2.4.6-r1348019.patch | 77 + SOURCES/httpd-2.4.6-r1420184.patch | 154 ++ SOURCES/httpd-2.4.6-r1506474.patch | 13 + SOURCES/httpd-2.4.6-r1507681+.patch | 62 + SOURCES/httpd-2.4.6-r1524368.patch | 20 + SOURCES/httpd-2.4.6-r1526189.patch | 62 + SOURCES/httpd-2.4.6-r1527509.patch | 21 + SOURCES/httpd-2.4.6-r1528556.patch | 23 + SOURCES/httpd-2.4.6-r1528958.patch | 46 + SOURCES/httpd-2.4.6-r1530280.patch | 59 + SOURCES/httpd-2.4.6-r1530999.patch | 19 + SOURCES/httpd-2.4.6-r1533448.patch | 155 ++ SOURCES/httpd-2.4.6-r1537535.patch | 38 + SOURCES/httpd-2.4.6-r1542327.patch | 868 +++++++ SOURCES/httpd-2.4.6-r1553540.patch | 28 + SOURCES/httpd-2.4.6-r1556473.patch | 31 + SOURCES/httpd-2.4.6-r1556818.patch | 26 + SOURCES/httpd-2.4.6-r1560093.patch | 16 + SOURCES/httpd-2.4.6-r1569006.patch | 19 + SOURCES/httpd-2.4.6-r1570327.patch | 20 + SOURCES/httpd-2.4.6-r1573626.patch | 29 + SOURCES/httpd-2.4.6-r1587053.patch | 92 + SOURCES/httpd-2.4.6-r1593002.patch | 35 + SOURCES/httpd-2.4.6-r1594625.patch | 25 + SOURCES/httpd-2.4.6-r1604460.patch | 22 + SOURCES/httpd-2.4.6-r1610013.patch | 141 ++ SOURCES/httpd-2.4.6-r1610396.patch | 189 ++ SOURCES/httpd-2.4.6-r1618851.patch | 28 + SOURCES/httpd-2.4.6-r1621601.patch | 21 + SOURCES/httpd-2.4.6-r1624349.patch | 21 + SOURCES/httpd-2.4.6-r1631119.patch | 16 + SOURCES/httpd-2.4.6-r1633085.patch | 14 + SOURCES/httpd-2.4.6-r1634529.patch | 275 +++ SOURCES/httpd-2.4.6-r1650310.patch | 132 + SOURCES/httpd-2.4.6-r1650655.patch | 41 + SOURCES/httpd-2.4.6-r1650677.patch | 49 + SOURCES/httpd-2.4.6-r1651083.patch | 10 + SOURCES/httpd-2.4.6-r1651653.patch | 100 + SOURCES/httpd-2.4.6-r1651658.patch | 22 + SOURCES/httpd-2.4.6-r1662640.patch | 40 + SOURCES/httpd-2.4.6-r1663647.patch | 22 + SOURCES/httpd-2.4.6-r1664565.patch | 68 + SOURCES/httpd-2.4.6-r1668532.patch | 67 + SOURCES/httpd-2.4.6-r1674222.patch | 81 + SOURCES/httpd-2.4.6-r1681107.patch | 84 + SOURCES/httpd-2.4.6-r1681114.patch | 157 ++ SOURCES/httpd-2.4.6-r1681289.patch | 19 + SOURCES/httpd-2.4.6-r1683112.patch | 45 + SOURCES/httpd-2.4.6-r1684462.patch | 34 + SOURCES/httpd-2.4.6-r1688399.patch | 11 + SOURCES/httpd-2.4.6-r1705528.patch | 24 + SOURCES/httpd-2.4.6-r1723522.patch | 13 + SOURCES/httpd-2.4.6-r1726019.patch | 20 + SOURCES/httpd-2.4.6-r1738878.patch | 139 ++ SOURCES/httpd-2.4.6-r1748212.patch | 70 + SOURCES/httpd-2.4.6-r1775832.patch | 16 + SOURCES/httpd-2.4.6-r1805099.patch | 46 + SOURCES/httpd-2.4.6-r1811746.patch | 128 + SOURCES/httpd-2.4.6-r1811831.patch | 79 + SOURCES/httpd-2.4.6-r1811976.patch | 156 ++ SOURCES/httpd-2.4.6-rewrite-clientaddr.patch | 14 + SOURCES/httpd-2.4.6-rewrite-dir.patch | 59 + SOURCES/httpd-2.4.6-rotatelog-timezone.patch | 97 + SOURCES/httpd-2.4.6-rotatelogs-zombie.patch | 23 + SOURCES/httpd-2.4.6-sigint.patch | 45 + SOURCES/httpd-2.4.6-ssl-ecdh-auto.patch | 22 + SOURCES/httpd-2.4.6-ssl-error-free.patch | 46 + SOURCES/httpd-2.4.6-ssl-large-keys.patch | 173 ++ SOURCES/httpd-2.4.6-sslmultiproxy.patch | 94 + SOURCES/httpd-2.4.6-statements-comment.patch | 16 + SOURCES/httpd-2.4.6-uds.patch | 1456 +++++++++++ SOURCES/httpd-2.4.6-upn.patch | 381 +++ SOURCES/httpd-ssl-pass-dialog | 3 + SOURCES/httpd.conf | 353 +++ SOURCES/httpd.logrotate | 9 + SOURCES/httpd.service | 22 + SOURCES/httpd.sysconf | 25 + SOURCES/httpd.tmpfiles | 2 + SOURCES/manual.conf | 13 + SOURCES/ssl.conf | 217 ++ SOURCES/userdir.conf | 36 + SOURCES/welcome.conf | 22 + SPECS/httpd.spec | 1534 ++++++++++++ 144 files changed, 16545 insertions(+) create mode 100644 SOURCES/00-base.conf create mode 100644 SOURCES/00-dav.conf create mode 100644 SOURCES/00-lua.conf create mode 100644 SOURCES/00-mpm.conf create mode 100644 SOURCES/00-proxy.conf create mode 100644 SOURCES/00-proxyhtml.conf create mode 100644 SOURCES/00-ssl.conf create mode 100644 SOURCES/00-systemd.conf create mode 100644 SOURCES/01-cgi.conf create mode 100644 SOURCES/01-ldap.conf create mode 100644 SOURCES/01-session.conf create mode 100644 SOURCES/httpd-2.4.1-apctl.patch create mode 100644 SOURCES/httpd-2.4.1-corelimit.patch create mode 100644 SOURCES/httpd-2.4.1-deplibs.patch create mode 100644 SOURCES/httpd-2.4.1-selinux.patch create mode 100644 SOURCES/httpd-2.4.2-icons.patch create mode 100644 SOURCES/httpd-2.4.3-apctl-systemd.patch create mode 100644 SOURCES/httpd-2.4.3-apxs.patch create mode 100644 SOURCES/httpd-2.4.3-layout.patch create mode 100644 SOURCES/httpd-2.4.3-mod_systemd.patch create mode 100644 SOURCES/httpd-2.4.3-sslsninotreq.patch create mode 100644 SOURCES/httpd-2.4.4-cachehardmax.patch create mode 100644 SOURCES/httpd-2.4.4-export.patch create mode 100644 SOURCES/httpd-2.4.4-malformed-host.patch create mode 100644 SOURCES/httpd-2.4.4-mod_unique_id.patch create mode 100644 SOURCES/httpd-2.4.4-r1337344+.patch create mode 100644 SOURCES/httpd-2.4.6-CVE-2013-4352.patch create mode 100644 SOURCES/httpd-2.4.6-CVE-2013-5704.patch create mode 100644 SOURCES/httpd-2.4.6-CVE-2013-6438.patch create mode 100644 SOURCES/httpd-2.4.6-CVE-2014-0098.patch create mode 100644 SOURCES/httpd-2.4.6-CVE-2014-0117.patch create mode 100644 SOURCES/httpd-2.4.6-CVE-2014-0118.patch create mode 100644 SOURCES/httpd-2.4.6-CVE-2014-0226.patch create mode 100644 SOURCES/httpd-2.4.6-CVE-2014-0231.patch create mode 100644 SOURCES/httpd-2.4.6-CVE-2014-3581.patch create mode 100644 SOURCES/httpd-2.4.6-CVE-2015-3183.patch create mode 100644 SOURCES/httpd-2.4.6-CVE-2015-3185.patch create mode 100644 SOURCES/httpd-2.4.6-CVE-2016-0736.patch create mode 100644 SOURCES/httpd-2.4.6-CVE-2016-2161.patch create mode 100644 SOURCES/httpd-2.4.6-CVE-2016-5387.patch create mode 100644 SOURCES/httpd-2.4.6-CVE-2016-8743.patch create mode 100644 SOURCES/httpd-2.4.6-CVE-2017-3167.patch create mode 100644 SOURCES/httpd-2.4.6-CVE-2017-3169.patch create mode 100644 SOURCES/httpd-2.4.6-CVE-2017-7668.patch create mode 100644 SOURCES/httpd-2.4.6-CVE-2017-7679.patch create mode 100644 SOURCES/httpd-2.4.6-CVE-2017-9788.patch create mode 100644 SOURCES/httpd-2.4.6-CVE-2017-9798.patch create mode 100644 SOURCES/httpd-2.4.6-ab-overflow.patch create mode 100644 SOURCES/httpd-2.4.6-ab-ssl-error.patch create mode 100644 SOURCES/httpd-2.4.6-ap-ipv6.patch create mode 100644 SOURCES/httpd-2.4.6-apachectl-httpd-env.patch create mode 100644 SOURCES/httpd-2.4.6-apachectl-status.patch create mode 100644 SOURCES/httpd-2.4.6-bomb.patch create mode 100644 SOURCES/httpd-2.4.6-dhparams-free.patch create mode 100644 SOURCES/httpd-2.4.6-full-release.patch create mode 100644 SOURCES/httpd-2.4.6-http-protocol-options-define.patch create mode 100644 SOURCES/httpd-2.4.6-ldaprefer.patch create mode 100644 SOURCES/httpd-2.4.6-mod_authz_dbd-missing-query.patch create mode 100644 SOURCES/httpd-2.4.6-mpm-segfault.patch create mode 100644 SOURCES/httpd-2.4.6-pre_htaccess.patch create mode 100644 SOURCES/httpd-2.4.6-r1332643+.patch create mode 100644 SOURCES/httpd-2.4.6-r1348019.patch create mode 100644 SOURCES/httpd-2.4.6-r1420184.patch create mode 100644 SOURCES/httpd-2.4.6-r1506474.patch create mode 100644 SOURCES/httpd-2.4.6-r1507681+.patch create mode 100644 SOURCES/httpd-2.4.6-r1524368.patch create mode 100644 SOURCES/httpd-2.4.6-r1526189.patch create mode 100644 SOURCES/httpd-2.4.6-r1527509.patch create mode 100644 SOURCES/httpd-2.4.6-r1528556.patch create mode 100644 SOURCES/httpd-2.4.6-r1528958.patch create mode 100644 SOURCES/httpd-2.4.6-r1530280.patch create mode 100644 SOURCES/httpd-2.4.6-r1530999.patch create mode 100644 SOURCES/httpd-2.4.6-r1533448.patch create mode 100644 SOURCES/httpd-2.4.6-r1537535.patch create mode 100644 SOURCES/httpd-2.4.6-r1542327.patch create mode 100644 SOURCES/httpd-2.4.6-r1553540.patch create mode 100644 SOURCES/httpd-2.4.6-r1556473.patch create mode 100644 SOURCES/httpd-2.4.6-r1556818.patch create mode 100644 SOURCES/httpd-2.4.6-r1560093.patch create mode 100644 SOURCES/httpd-2.4.6-r1569006.patch create mode 100644 SOURCES/httpd-2.4.6-r1570327.patch create mode 100644 SOURCES/httpd-2.4.6-r1573626.patch create mode 100644 SOURCES/httpd-2.4.6-r1587053.patch create mode 100644 SOURCES/httpd-2.4.6-r1593002.patch create mode 100644 SOURCES/httpd-2.4.6-r1594625.patch create mode 100644 SOURCES/httpd-2.4.6-r1604460.patch create mode 100644 SOURCES/httpd-2.4.6-r1610013.patch create mode 100644 SOURCES/httpd-2.4.6-r1610396.patch create mode 100644 SOURCES/httpd-2.4.6-r1618851.patch create mode 100644 SOURCES/httpd-2.4.6-r1621601.patch create mode 100644 SOURCES/httpd-2.4.6-r1624349.patch create mode 100644 SOURCES/httpd-2.4.6-r1631119.patch create mode 100644 SOURCES/httpd-2.4.6-r1633085.patch create mode 100644 SOURCES/httpd-2.4.6-r1634529.patch create mode 100644 SOURCES/httpd-2.4.6-r1650310.patch create mode 100644 SOURCES/httpd-2.4.6-r1650655.patch create mode 100644 SOURCES/httpd-2.4.6-r1650677.patch create mode 100644 SOURCES/httpd-2.4.6-r1651083.patch create mode 100644 SOURCES/httpd-2.4.6-r1651653.patch create mode 100644 SOURCES/httpd-2.4.6-r1651658.patch create mode 100644 SOURCES/httpd-2.4.6-r1662640.patch create mode 100644 SOURCES/httpd-2.4.6-r1663647.patch create mode 100644 SOURCES/httpd-2.4.6-r1664565.patch create mode 100644 SOURCES/httpd-2.4.6-r1668532.patch create mode 100644 SOURCES/httpd-2.4.6-r1674222.patch create mode 100644 SOURCES/httpd-2.4.6-r1681107.patch create mode 100644 SOURCES/httpd-2.4.6-r1681114.patch create mode 100644 SOURCES/httpd-2.4.6-r1681289.patch create mode 100644 SOURCES/httpd-2.4.6-r1683112.patch create mode 100644 SOURCES/httpd-2.4.6-r1684462.patch create mode 100644 SOURCES/httpd-2.4.6-r1688399.patch create mode 100644 SOURCES/httpd-2.4.6-r1705528.patch create mode 100644 SOURCES/httpd-2.4.6-r1723522.patch create mode 100644 SOURCES/httpd-2.4.6-r1726019.patch create mode 100644 SOURCES/httpd-2.4.6-r1738878.patch create mode 100644 SOURCES/httpd-2.4.6-r1748212.patch create mode 100644 SOURCES/httpd-2.4.6-r1775832.patch create mode 100644 SOURCES/httpd-2.4.6-r1805099.patch create mode 100644 SOURCES/httpd-2.4.6-r1811746.patch create mode 100644 SOURCES/httpd-2.4.6-r1811831.patch create mode 100644 SOURCES/httpd-2.4.6-r1811976.patch create mode 100644 SOURCES/httpd-2.4.6-rewrite-clientaddr.patch create mode 100644 SOURCES/httpd-2.4.6-rewrite-dir.patch create mode 100644 SOURCES/httpd-2.4.6-rotatelog-timezone.patch create mode 100644 SOURCES/httpd-2.4.6-rotatelogs-zombie.patch create mode 100644 SOURCES/httpd-2.4.6-sigint.patch create mode 100644 SOURCES/httpd-2.4.6-ssl-ecdh-auto.patch create mode 100644 SOURCES/httpd-2.4.6-ssl-error-free.patch create mode 100644 SOURCES/httpd-2.4.6-ssl-large-keys.patch create mode 100644 SOURCES/httpd-2.4.6-sslmultiproxy.patch create mode 100644 SOURCES/httpd-2.4.6-statements-comment.patch create mode 100644 SOURCES/httpd-2.4.6-uds.patch create mode 100644 SOURCES/httpd-2.4.6-upn.patch create mode 100755 SOURCES/httpd-ssl-pass-dialog create mode 100644 SOURCES/httpd.conf create mode 100644 SOURCES/httpd.logrotate create mode 100644 SOURCES/httpd.service create mode 100644 SOURCES/httpd.sysconf create mode 100644 SOURCES/httpd.tmpfiles create mode 100644 SOURCES/manual.conf create mode 100644 SOURCES/ssl.conf create mode 100644 SOURCES/userdir.conf create mode 100644 SOURCES/welcome.conf create mode 100644 SPECS/httpd.spec diff --git a/SOURCES/00-base.conf b/SOURCES/00-base.conf new file mode 100644 index 0000000..31d979f --- /dev/null +++ b/SOURCES/00-base.conf @@ -0,0 +1,77 @@ +# +# This file loads most of the modules included with the Apache HTTP +# Server itself. +# + +LoadModule access_compat_module modules/mod_access_compat.so +LoadModule actions_module modules/mod_actions.so +LoadModule alias_module modules/mod_alias.so +LoadModule allowmethods_module modules/mod_allowmethods.so +LoadModule auth_basic_module modules/mod_auth_basic.so +LoadModule auth_digest_module modules/mod_auth_digest.so +LoadModule authn_anon_module modules/mod_authn_anon.so +LoadModule authn_core_module modules/mod_authn_core.so +LoadModule authn_dbd_module modules/mod_authn_dbd.so +LoadModule authn_dbm_module modules/mod_authn_dbm.so +LoadModule authn_file_module modules/mod_authn_file.so +LoadModule authn_socache_module modules/mod_authn_socache.so +LoadModule authz_core_module modules/mod_authz_core.so +LoadModule authz_dbd_module modules/mod_authz_dbd.so +LoadModule authz_dbm_module modules/mod_authz_dbm.so +LoadModule authz_groupfile_module modules/mod_authz_groupfile.so +LoadModule authz_host_module modules/mod_authz_host.so +LoadModule authz_owner_module modules/mod_authz_owner.so +LoadModule authz_user_module modules/mod_authz_user.so +LoadModule autoindex_module modules/mod_autoindex.so +LoadModule cache_module modules/mod_cache.so +LoadModule cache_disk_module modules/mod_cache_disk.so +LoadModule data_module modules/mod_data.so +LoadModule dbd_module modules/mod_dbd.so +LoadModule deflate_module modules/mod_deflate.so +LoadModule dir_module modules/mod_dir.so +LoadModule dumpio_module modules/mod_dumpio.so +LoadModule echo_module modules/mod_echo.so +LoadModule env_module modules/mod_env.so +LoadModule expires_module modules/mod_expires.so +LoadModule ext_filter_module modules/mod_ext_filter.so +LoadModule filter_module modules/mod_filter.so +LoadModule headers_module modules/mod_headers.so +LoadModule include_module modules/mod_include.so +LoadModule info_module modules/mod_info.so +LoadModule log_config_module modules/mod_log_config.so +LoadModule logio_module modules/mod_logio.so +LoadModule mime_magic_module modules/mod_mime_magic.so +LoadModule mime_module modules/mod_mime.so +LoadModule negotiation_module modules/mod_negotiation.so +LoadModule remoteip_module modules/mod_remoteip.so +LoadModule reqtimeout_module modules/mod_reqtimeout.so +LoadModule rewrite_module modules/mod_rewrite.so +LoadModule setenvif_module modules/mod_setenvif.so +LoadModule slotmem_plain_module modules/mod_slotmem_plain.so +LoadModule slotmem_shm_module modules/mod_slotmem_shm.so +LoadModule socache_dbm_module modules/mod_socache_dbm.so +LoadModule socache_memcache_module modules/mod_socache_memcache.so +LoadModule socache_shmcb_module modules/mod_socache_shmcb.so +LoadModule status_module modules/mod_status.so +LoadModule substitute_module modules/mod_substitute.so +LoadModule suexec_module modules/mod_suexec.so +LoadModule unique_id_module modules/mod_unique_id.so +LoadModule unixd_module modules/mod_unixd.so +LoadModule userdir_module modules/mod_userdir.so +LoadModule version_module modules/mod_version.so +LoadModule vhost_alias_module modules/mod_vhost_alias.so + +#LoadModule buffer_module modules/mod_buffer.so +#LoadModule watchdog_module modules/mod_watchdog.so +#LoadModule heartbeat_module modules/mod_heartbeat.so +#LoadModule heartmonitor_module modules/mod_heartmonitor.so +#LoadModule usertrack_module modules/mod_usertrack.so +#LoadModule dialup_module modules/mod_dialup.so +#LoadModule charset_lite_module modules/mod_charset_lite.so +#LoadModule log_debug_module modules/mod_log_debug.so +#LoadModule ratelimit_module modules/mod_ratelimit.so +#LoadModule reflector_module modules/mod_reflector.so +#LoadModule request_module modules/mod_request.so +#LoadModule sed_module modules/mod_sed.so +#LoadModule speling_module modules/mod_speling.so + diff --git a/SOURCES/00-dav.conf b/SOURCES/00-dav.conf new file mode 100644 index 0000000..e6af8de --- /dev/null +++ b/SOURCES/00-dav.conf @@ -0,0 +1,3 @@ +LoadModule dav_module modules/mod_dav.so +LoadModule dav_fs_module modules/mod_dav_fs.so +LoadModule dav_lock_module modules/mod_dav_lock.so diff --git a/SOURCES/00-lua.conf b/SOURCES/00-lua.conf new file mode 100644 index 0000000..9e0d0db --- /dev/null +++ b/SOURCES/00-lua.conf @@ -0,0 +1 @@ +LoadModule lua_module modules/mod_lua.so diff --git a/SOURCES/00-mpm.conf b/SOURCES/00-mpm.conf new file mode 100644 index 0000000..7bfd1d4 --- /dev/null +++ b/SOURCES/00-mpm.conf @@ -0,0 +1,19 @@ +# Select the MPM module which should be used by uncommenting exactly +# one of the following LoadModule lines: + +# prefork MPM: Implements a non-threaded, pre-forking web server +# See: http://httpd.apache.org/docs/2.4/mod/prefork.html +LoadModule mpm_prefork_module modules/mod_mpm_prefork.so + +# worker MPM: Multi-Processing Module implementing a hybrid +# multi-threaded multi-process web server +# See: http://httpd.apache.org/docs/2.4/mod/worker.html +# +#LoadModule mpm_worker_module modules/mod_mpm_worker.so + +# event MPM: A variant of the worker MPM with the goal of consuming +# threads only for connections with active processing +# See: http://httpd.apache.org/docs/2.4/mod/event.html +# +#LoadModule mpm_event_module modules/mod_mpm_event.so + diff --git a/SOURCES/00-proxy.conf b/SOURCES/00-proxy.conf new file mode 100644 index 0000000..cc0bca0 --- /dev/null +++ b/SOURCES/00-proxy.conf @@ -0,0 +1,16 @@ +# This file configures all the proxy modules: +LoadModule proxy_module modules/mod_proxy.so +LoadModule lbmethod_bybusyness_module modules/mod_lbmethod_bybusyness.so +LoadModule lbmethod_byrequests_module modules/mod_lbmethod_byrequests.so +LoadModule lbmethod_bytraffic_module modules/mod_lbmethod_bytraffic.so +LoadModule lbmethod_heartbeat_module modules/mod_lbmethod_heartbeat.so +LoadModule proxy_ajp_module modules/mod_proxy_ajp.so +LoadModule proxy_balancer_module modules/mod_proxy_balancer.so +LoadModule proxy_connect_module modules/mod_proxy_connect.so +LoadModule proxy_express_module modules/mod_proxy_express.so +LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so +LoadModule proxy_fdpass_module modules/mod_proxy_fdpass.so +LoadModule proxy_ftp_module modules/mod_proxy_ftp.so +LoadModule proxy_http_module modules/mod_proxy_http.so +LoadModule proxy_scgi_module modules/mod_proxy_scgi.so +LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so diff --git a/SOURCES/00-proxyhtml.conf b/SOURCES/00-proxyhtml.conf new file mode 100644 index 0000000..9a9b107 --- /dev/null +++ b/SOURCES/00-proxyhtml.conf @@ -0,0 +1,3 @@ +# This file configures mod_proxy_html and mod_xml2enc: +LoadModule xml2enc_module modules/mod_xml2enc.so +LoadModule proxy_html_module modules/mod_proxy_html.so diff --git a/SOURCES/00-ssl.conf b/SOURCES/00-ssl.conf new file mode 100644 index 0000000..53235cd --- /dev/null +++ b/SOURCES/00-ssl.conf @@ -0,0 +1 @@ +LoadModule ssl_module modules/mod_ssl.so diff --git a/SOURCES/00-systemd.conf b/SOURCES/00-systemd.conf new file mode 100644 index 0000000..b208c97 --- /dev/null +++ b/SOURCES/00-systemd.conf @@ -0,0 +1,2 @@ +# This file configures systemd module: +LoadModule systemd_module modules/mod_systemd.so diff --git a/SOURCES/01-cgi.conf b/SOURCES/01-cgi.conf new file mode 100644 index 0000000..5b8b936 --- /dev/null +++ b/SOURCES/01-cgi.conf @@ -0,0 +1,14 @@ +# This configuration file loads a CGI module appropriate to the MPM +# which has been configured in 00-mpm.conf. mod_cgid should be used +# with a threaded MPM; mod_cgi with the prefork MPM. + + + LoadModule cgid_module modules/mod_cgid.so + + + LoadModule cgid_module modules/mod_cgid.so + + + LoadModule cgi_module modules/mod_cgi.so + + diff --git a/SOURCES/01-ldap.conf b/SOURCES/01-ldap.conf new file mode 100644 index 0000000..f2ac2a2 --- /dev/null +++ b/SOURCES/01-ldap.conf @@ -0,0 +1,3 @@ +# This file configures the LDAP modules: +LoadModule ldap_module modules/mod_ldap.so +LoadModule authnz_ldap_module modules/mod_authnz_ldap.so diff --git a/SOURCES/01-session.conf b/SOURCES/01-session.conf new file mode 100644 index 0000000..f8d4d92 --- /dev/null +++ b/SOURCES/01-session.conf @@ -0,0 +1,6 @@ +LoadModule session_module modules/mod_session.so +LoadModule session_cookie_module modules/mod_session_cookie.so +LoadModule session_dbd_module modules/mod_session_dbd.so +LoadModule auth_form_module modules/mod_auth_form.so + +#LoadModule session_crypto_module modules/mod_session_crypto.so diff --git a/SOURCES/httpd-2.4.1-apctl.patch b/SOURCES/httpd-2.4.1-apctl.patch new file mode 100644 index 0000000..b31c3c5 --- /dev/null +++ b/SOURCES/httpd-2.4.1-apctl.patch @@ -0,0 +1,94 @@ + +- fail gracefully if links is not installed on target system +- source sysconfig/httpd for custom env. vars etc. +- make httpd -t work even in SELinux +- pass $OPTIONS to all $HTTPD invocation + +Upstream-HEAD: vendor +Upstream-2.0: vendor +Upstream-Status: Vendor-specific changes for better initscript integration + +--- httpd-2.4.1/support/apachectl.in.apctl ++++ httpd-2.4.1/support/apachectl.in +@@ -44,19 +44,25 @@ ARGV="$@" + # the path to your httpd binary, including options if necessary + HTTPD='@exp_sbindir@/@progname@' + # +-# pick up any necessary environment variables +-if test -f @exp_sbindir@/envvars; then +- . @exp_sbindir@/envvars +-fi + # + # a command that outputs a formatted text version of the HTML at the + # url given on the command line. Designed for lynx, however other + # programs may work. +-LYNX="@LYNX_PATH@ -dump" ++if [ -x "@LYNX_PATH@" ]; then ++ LYNX="@LYNX_PATH@ -dump" ++else ++ LYNX=none ++fi + # + # the URL to your server's mod_status status page. If you do not + # have one, then status and fullstatus will not work. + STATUSURL="http://localhost:@PORT@/server-status" ++ ++# Source /etc/sysconfig/httpd for $HTTPD setting, etc. ++if [ -r /etc/sysconfig/httpd ]; then ++ . /etc/sysconfig/httpd ++fi ++ + # + # Set this variable to a command that increases the maximum + # number of file descriptors allowed per child process. This is +@@ -76,9 +82,27 @@ if [ "x$ARGV" = "x" ] ; then + ARGV="-h" + fi + ++function checklynx() { ++if [ "$LYNX" = "none" ]; then ++ echo "The 'links' package is required for this functionality." ++ exit 8 ++fi ++} ++ ++function testconfig() { ++# httpd is denied terminal access in SELinux, so run in the ++# current context to get stdout from $HTTPD -t. ++if test -x /usr/sbin/selinuxenabled && /usr/sbin/selinuxenabled; then ++ runcon -- `id -Z` $HTTPD $OPTIONS -t ++else ++ $HTTPD $OPTIONS -t ++fi ++ERROR=$? ++} ++ + case $ACMD in + start|stop|restart|graceful|graceful-stop) +- $HTTPD -k $ARGV ++ $HTTPD $OPTIONS -k $ARGV + ERROR=$? + ;; + startssl|sslstart|start-SSL) +@@ -88,17 +112,18 @@ startssl|sslstart|start-SSL) + ERROR=2 + ;; + configtest) +- $HTTPD -t +- ERROR=$? ++ testconfig + ;; + status) ++ checklynx + $LYNX $STATUSURL | awk ' /process$/ { print; exit } { print } ' + ;; + fullstatus) ++ checklynx + $LYNX $STATUSURL + ;; + *) +- $HTTPD "$@" ++ $HTTPD $OPTIONS "$@" + ERROR=$? + esac + diff --git a/SOURCES/httpd-2.4.1-corelimit.patch b/SOURCES/httpd-2.4.1-corelimit.patch new file mode 100644 index 0000000..96f8486 --- /dev/null +++ b/SOURCES/httpd-2.4.1-corelimit.patch @@ -0,0 +1,35 @@ + +Bump up the core size limit if CoreDumpDirectory is +configured. + +Upstream-Status: Was discussed but there are competing desires; + there are portability oddities here too. + +--- httpd-2.4.1/server/core.c.corelimit ++++ httpd-2.4.1/server/core.c +@@ -4433,6 +4433,25 @@ static int core_post_config(apr_pool_t * + } + apr_pool_cleanup_register(pconf, NULL, ap_mpm_end_gen_helper, + apr_pool_cleanup_null); ++ ++#ifdef RLIMIT_CORE ++ if (ap_coredumpdir_configured) { ++ struct rlimit lim; ++ ++ if (getrlimit(RLIMIT_CORE, &lim) == 0 && lim.rlim_cur == 0) { ++ lim.rlim_cur = lim.rlim_max; ++ if (setrlimit(RLIMIT_CORE, &lim) == 0) { ++ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, ++ "core dump file size limit raised to %lu bytes", ++ lim.rlim_cur); ++ } else { ++ ap_log_error(APLOG_MARK, APLOG_NOTICE, errno, NULL, ++ "core dump file size is zero, setrlimit failed"); ++ } ++ } ++ } ++#endif ++ + return OK; + } + diff --git a/SOURCES/httpd-2.4.1-deplibs.patch b/SOURCES/httpd-2.4.1-deplibs.patch new file mode 100644 index 0000000..b73c21d --- /dev/null +++ b/SOURCES/httpd-2.4.1-deplibs.patch @@ -0,0 +1,19 @@ + +Link straight against .la files. + +Upstream-Status: vendor specific + +--- httpd-2.4.1/configure.in.deplibs ++++ httpd-2.4.1/configure.in +@@ -707,9 +707,9 @@ APACHE_HELP_STRING(--with-suexec-umask,u + + dnl APR should go after the other libs, so the right symbols can be picked up + if test x${apu_found} != xobsolete; then +- AP_LIBS="$AP_LIBS `$apu_config --avoid-ldap --link-libtool --libs`" ++ AP_LIBS="$AP_LIBS `$apu_config --avoid-ldap --link-libtool`" + fi +-AP_LIBS="$AP_LIBS `$apr_config --link-libtool --libs`" ++AP_LIBS="$AP_LIBS `$apr_config --link-libtool`" + APACHE_SUBST(AP_LIBS) + APACHE_SUBST(AP_BUILD_SRCLIB_DIRS) + APACHE_SUBST(AP_CLEAN_SRCLIB_DIRS) diff --git a/SOURCES/httpd-2.4.1-selinux.patch b/SOURCES/httpd-2.4.1-selinux.patch new file mode 100644 index 0000000..e97c5a4 --- /dev/null +++ b/SOURCES/httpd-2.4.1-selinux.patch @@ -0,0 +1,61 @@ + +Log the SELinux context at startup. + +Upstream-Status: unlikely to be any interest in this upstream + +--- httpd-2.4.1/configure.in.selinux ++++ httpd-2.4.1/configure.in +@@ -458,6 +458,11 @@ fopen64 + dnl confirm that a void pointer is large enough to store a long integer + APACHE_CHECK_VOID_PTR_LEN + ++AC_CHECK_LIB(selinux, is_selinux_enabled, [ ++ AC_DEFINE(HAVE_SELINUX, 1, [Defined if SELinux is supported]) ++ APR_ADDTO(AP_LIBS, [-lselinux]) ++]) ++ + AC_CACHE_CHECK([for gettid()], ac_cv_gettid, + [AC_TRY_RUN(#define _GNU_SOURCE + #include +--- httpd-2.4.1/server/core.c.selinux ++++ httpd-2.4.1/server/core.c +@@ -58,6 +58,10 @@ + #include + #endif + ++#ifdef HAVE_SELINUX ++#include ++#endif ++ + /* LimitRequestBody handling */ + #define AP_LIMIT_REQ_BODY_UNSET ((apr_off_t) -1) + #define AP_DEFAULT_LIMIT_REQ_BODY ((apr_off_t) 0) +@@ -4452,6 +4456,28 @@ static int core_post_config(apr_pool_t * + } + #endif + ++#ifdef HAVE_SELINUX ++ { ++ static int already_warned = 0; ++ int is_enabled = is_selinux_enabled() > 0; ++ ++ if (is_enabled && !already_warned) { ++ security_context_t con; ++ ++ if (getcon(&con) == 0) { ++ ++ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, ++ "SELinux policy enabled; " ++ "httpd running as context %s", con); ++ ++ already_warned = 1; ++ ++ freecon(con); ++ } ++ } ++ } ++#endif ++ + return OK; + } + diff --git a/SOURCES/httpd-2.4.2-icons.patch b/SOURCES/httpd-2.4.2-icons.patch new file mode 100644 index 0000000..1341999 --- /dev/null +++ b/SOURCES/httpd-2.4.2-icons.patch @@ -0,0 +1,26 @@ + +- Fix config for /icons/ dir to allow symlink to poweredby.png. +- Avoid using coredump GIF for a directory called "core" + +Upstream-Status: vendor specific patch + +--- httpd-2.4.2/docs/conf/extra/httpd-autoindex.conf.in.icons ++++ httpd-2.4.2/docs/conf/extra/httpd-autoindex.conf.in +@@ -21,7 +21,7 @@ IndexOptions FancyIndexing HTMLTable Ver + Alias /icons/ "@exp_iconsdir@/" + + +- Options Indexes MultiViews ++ Options Indexes MultiViews FollowSymlinks + AllowOverride None + Require all granted + +@@ -53,7 +53,7 @@ AddIcon /icons/dvi.gif .dvi + AddIcon /icons/uuencoded.gif .uu + AddIcon /icons/script.gif .conf .sh .shar .csh .ksh .tcl + AddIcon /icons/tex.gif .tex +-AddIcon /icons/bomb.gif core ++AddIcon /icons/bomb.gif core. + + AddIcon /icons/back.gif .. + AddIcon /icons/hand.right.gif README diff --git a/SOURCES/httpd-2.4.3-apctl-systemd.patch b/SOURCES/httpd-2.4.3-apctl-systemd.patch new file mode 100644 index 0000000..5823aee --- /dev/null +++ b/SOURCES/httpd-2.4.3-apctl-systemd.patch @@ -0,0 +1,45 @@ + +Upstream-Status: vendor specific patch + +diff --git a/support/apachectl.in b/support/apachectl.in +index c6ac3ea..2599386 100644 +--- a/support/apachectl.in ++++ b/support/apachectl.in +@@ -100,9 +100,24 @@ fi + ERROR=$? + } + ++if [ "x$2" != "x" ] ; then ++ echo Passing arguments to httpd using apachectl is no longer supported. ++ echo You can only start/stop/restart httpd using this script. ++ echo If you want to pass extra arguments to httpd, edit the ++ echo /etc/sysconfig/httpd config file. ++fi ++ + case $ACMD in +-start|stop|restart|graceful|graceful-stop) +- $HTTPD $OPTIONS -k $ARGV ++start|stop|restart|status) ++ /usr/bin/systemctl $ACMD httpd.service ++ ERROR=$? ++ ;; ++graceful) ++ /usr/bin/systemctl reload httpd.service ++ ERROR=$? ++ ;; ++graceful-stop) ++ /usr/bin/systemctl stop httpd.service + ERROR=$? + ;; + startssl|sslstart|start-SSL) +@@ -114,10 +129,6 @@ startssl|sslstart|start-SSL) + configtest) + testconfig + ;; +-status) +- checklynx +- $LYNX $STATUSURL | awk ' /process$/ { print; exit } { print } ' +- ;; + fullstatus) + checklynx + $LYNX $STATUSURL diff --git a/SOURCES/httpd-2.4.3-apxs.patch b/SOURCES/httpd-2.4.3-apxs.patch new file mode 100644 index 0000000..f4d2a87 --- /dev/null +++ b/SOURCES/httpd-2.4.3-apxs.patch @@ -0,0 +1,56 @@ +--- httpd-2.4.3/support/apxs.in.apxs ++++ httpd-2.4.3/support/apxs.in +@@ -25,7 +25,18 @@ package apxs; + + my %config_vars = (); + +-my $installbuilddir = "@exp_installbuilddir@"; ++# Awful hack to make apxs libdir-agnostic: ++my $pkg_config = "/usr/bin/pkg-config"; ++if (! -x "$pkg_config") { ++ error("$pkg_config not found!"); ++ exit(1); ++} ++ ++my $libdir = `pkg-config --variable=libdir apr-1`; ++chomp $libdir; ++ ++my $installbuilddir = $libdir . "/httpd/build"; ++ + get_config_vars("$installbuilddir/config_vars.mk",\%config_vars); + + # read the configuration variables once +@@ -275,7 +286,7 @@ if ($opt_g) { + $data =~ s|%NAME%|$name|sg; + $data =~ s|%TARGET%|$CFG_TARGET|sg; + $data =~ s|%PREFIX%|$prefix|sg; +- $data =~ s|%INSTALLBUILDDIR%|$installbuilddir|sg; ++ $data =~ s|%LIBDIR%|$libdir|sg; + + my ($mkf, $mods, $src) = ($data =~ m|^(.+)-=#=-\n(.+)-=#=-\n(.+)|s); + +@@ -453,11 +464,11 @@ if ($opt_c) { + my $ldflags = "$CFG_LDFLAGS"; + if ($opt_p == 1) { + +- my $apr_libs=`$apr_config --cflags --ldflags --link-libtool --libs`; ++ my $apr_libs=`$apr_config --cflags --ldflags --link-libtool`; + chomp($apr_libs); + my $apu_libs=""; + if ($apr_major_version < 2) { +- $apu_libs=`$apu_config --ldflags --link-libtool --libs`; ++ $apu_libs=`$apu_config --ldflags --link-libtool`; + chomp($apu_libs); + } + +@@ -672,8 +683,8 @@ __DATA__ + + builddir=. + top_srcdir=%PREFIX% +-top_builddir=%PREFIX% +-include %INSTALLBUILDDIR%/special.mk ++top_builddir=%LIBDIR%/httpd ++include %LIBDIR%/httpd/build/special.mk + + # the used tools + APXS=apxs diff --git a/SOURCES/httpd-2.4.3-layout.patch b/SOURCES/httpd-2.4.3-layout.patch new file mode 100644 index 0000000..f3ee9ec --- /dev/null +++ b/SOURCES/httpd-2.4.3-layout.patch @@ -0,0 +1,34 @@ + +Add layout for Fedora. + +--- httpd-2.4.3/config.layout.layout ++++ httpd-2.4.3/config.layout +@@ -370,3 +370,28 @@ + logfiledir: ${localstatedir}/log/httpd + proxycachedir: ${localstatedir}/cache/httpd + ++ ++# Fedora/RHEL layout ++ ++ prefix: /usr ++ exec_prefix: ${prefix} ++ bindir: ${prefix}/bin ++ sbindir: ${prefix}/sbin ++ libdir: ${prefix}/lib ++ libexecdir: ${prefix}/libexec ++ mandir: ${prefix}/man ++ sysconfdir: /etc/httpd/conf ++ datadir: ${prefix}/share/httpd ++ installbuilddir: ${libdir}/httpd/build ++ errordir: ${datadir}/error ++ iconsdir: ${datadir}/icons ++ htdocsdir: /var/www/html ++ manualdir: ${datadir}/manual ++ cgidir: /var/www/cgi-bin ++ includedir: ${prefix}/include/httpd ++ localstatedir: /var ++ runtimedir: /run/httpd ++ logfiledir: ${localstatedir}/log/httpd ++ proxycachedir: ${localstatedir}/cache/httpd/proxy ++ davlockdb: ${localstatedir}/lib/dav/lockdb ++ diff --git a/SOURCES/httpd-2.4.3-mod_systemd.patch b/SOURCES/httpd-2.4.3-mod_systemd.patch new file mode 100644 index 0000000..a9b1fd9 --- /dev/null +++ b/SOURCES/httpd-2.4.3-mod_systemd.patch @@ -0,0 +1,163 @@ +--- httpd-2.4.3/modules/arch/unix/config5.m4.systemd ++++ httpd-2.4.3/modules/arch/unix/config5.m4 +@@ -18,6 +18,19 @@ APACHE_MODULE(privileges, Per-virtualhos + fi + ]) + ++ ++APACHE_MODULE(systemd, Systemd support, , , $unixd_mods_enabled, [ ++ AC_CHECK_LIB(systemd-daemon, sd_notify, SYSTEMD_LIBS="-lsystemd-daemon") ++ AC_CHECK_HEADERS(systemd/sd-daemon.h, [ap_HAVE_SD_DAEMON_H="yes"], [ap_HAVE_SD_DAEMON_H="no"]) ++ if test $ap_HAVE_SD_DAEMON_H = "no" || test -z "${SYSTEMD_LIBS}"; then ++ AC_MSG_WARN([Your system does not support systemd.]) ++ enable_systemd="no" ++ else ++ APR_ADDTO(MOD_SYSTEMD_LDADD, [$SYSTEMD_LIBS]) ++ enable_systemd="yes" ++ fi ++]) ++ + APR_ADDTO(INCLUDES, [-I\$(top_srcdir)/$modpath_current]) + + APACHE_MODPATH_FINISH +--- httpd-2.4.3/modules/arch/unix/mod_systemd.c.systemd ++++ httpd-2.4.3/modules/arch/unix/mod_systemd.c +@@ -0,0 +1,138 @@ ++/* 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. ++ * ++ */ ++ ++#include ++#include ++#include "ap_mpm.h" ++#include ++#include ++#include ++#include ++#include ++#include "unixd.h" ++#include "scoreboard.h" ++#include "mpm_common.h" ++ ++#include "systemd/sd-daemon.h" ++ ++#if APR_HAVE_UNISTD_H ++#include ++#endif ++ ++#define KBYTE 1024 ++ ++static pid_t pid; /* PID of the main httpd instance */ ++static int server_limit, thread_limit, threads_per_child, max_servers; ++static time_t last_update_time; ++static unsigned long last_update_access; ++static unsigned long last_update_kbytes; ++ ++static int systemd_pre_mpm(apr_pool_t *p, ap_scoreboard_e sb_type) ++{ ++ int rv; ++ last_update_time = time(0); ++ ++ ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit); ++ ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &server_limit); ++ ap_mpm_query(AP_MPMQ_MAX_THREADS, &threads_per_child); ++ /* work around buggy MPMs */ ++ if (threads_per_child == 0) ++ threads_per_child = 1; ++ ap_mpm_query(AP_MPMQ_MAX_DAEMONS, &max_servers); ++ ++ pid = getpid(); ++ ++ rv = sd_notifyf(0, "READY=1\n" ++ "STATUS=Processing requests...\n" ++ "MAINPID=%lu", ++ (unsigned long) pid); ++ if (rv < 0) { ++ ap_log_perror(APLOG_MARK, APLOG_ERR, 0, p, ++ "sd_notifyf returned an error %d", rv); ++ } ++ ++ return OK; ++} ++ ++static int systemd_monitor(apr_pool_t *p, server_rec *s) ++{ ++ int i, j, res, rv; ++ process_score *ps_record; ++ worker_score *ws_record; ++ unsigned long access = 0; ++ unsigned long bytes = 0; ++ unsigned long kbytes = 0; ++ char bps[5]; ++ time_t now = time(0); ++ time_t elapsed = now - last_update_time; ++ ++ for (i = 0; i < server_limit; ++i) { ++ ps_record = ap_get_scoreboard_process(i); ++ for (j = 0; j < thread_limit; ++j) { ++ ws_record = ap_get_scoreboard_worker_from_indexes(i, j); ++ if (ap_extended_status && !ps_record->quiescing && ps_record->pid) { ++ res = ws_record->status; ++ if (ws_record->access_count != 0 || ++ (res != SERVER_READY && res != SERVER_DEAD)) { ++ access += ws_record->access_count; ++ bytes += ws_record->bytes_served; ++ if (bytes >= KBYTE) { ++ kbytes += (bytes >> 10); ++ bytes = bytes & 0x3ff; ++ } ++ } ++ } ++ } ++ } ++ ++ apr_strfsize((unsigned long)(KBYTE *(float) (kbytes - last_update_kbytes) ++ / (float) elapsed), bps); ++ ++ rv = sd_notifyf(0, "READY=1\n" ++ "STATUS=Total requests: %lu; Current requests/sec: %.3g; " ++ "Current traffic: %sB/sec\n", access, ++ ((float)access - last_update_access) / (float) elapsed, bps); ++ if (rv < 0) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00000) ++ "sd_notifyf returned an error %d", rv); ++ } ++ ++ last_update_access = access; ++ last_update_kbytes = kbytes; ++ last_update_time = now; ++ ++ return DECLINED; ++} ++ ++static void systemd_register_hooks(apr_pool_t *p) ++{ ++ /* We know the PID in this hook ... */ ++ ap_hook_pre_mpm(systemd_pre_mpm, NULL, NULL, APR_HOOK_LAST); ++ /* Used to update httpd's status line using sd_notifyf */ ++ ap_hook_monitor(systemd_monitor, NULL, NULL, APR_HOOK_MIDDLE); ++} ++ ++module AP_MODULE_DECLARE_DATA systemd_module = ++{ ++ STANDARD20_MODULE_STUFF, ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ systemd_register_hooks, ++}; diff --git a/SOURCES/httpd-2.4.3-sslsninotreq.patch b/SOURCES/httpd-2.4.3-sslsninotreq.patch new file mode 100644 index 0000000..6e158c6 --- /dev/null +++ b/SOURCES/httpd-2.4.3-sslsninotreq.patch @@ -0,0 +1,83 @@ +diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c +index 15993f1..53ed6f1 100644 +--- a/modules/ssl/ssl_engine_config.c ++++ b/modules/ssl/ssl_engine_config.c +@@ -55,6 +55,7 @@ SSLModConfigRec *ssl_config_global_create(server_rec *s) + mc = (SSLModConfigRec *)apr_palloc(pool, sizeof(*mc)); + mc->pPool = pool; + mc->bFixed = FALSE; ++ mc->sni_required = FALSE; + + /* + * initialize per-module configuration +diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c +index bf1f0e4..a7523de 100644 +--- a/modules/ssl/ssl_engine_init.c ++++ b/modules/ssl/ssl_engine_init.c +@@ -409,7 +409,7 @@ int ssl_init_Module(apr_pool_t *p, apr_pool_t *plog, + /* + * Configuration consistency checks + */ +- ssl_init_CheckServers(base_server, ptemp); ++ ssl_init_CheckServers(mc, base_server, ptemp); + + /* + * Announce mod_ssl and SSL library in HTTP Server field +@@ -1475,7 +1475,7 @@ void ssl_init_ConfigureServer(server_rec *s, + } + } + +-void ssl_init_CheckServers(server_rec *base_server, apr_pool_t *p) ++void ssl_init_CheckServers(SSLModConfigRec *mc, server_rec *base_server, apr_pool_t *p) + { + server_rec *s, *ps; + SSLSrvConfigRec *sc; +@@ -1557,6 +1557,7 @@ void ssl_init_CheckServers(server_rec *base_server, apr_pool_t *p) + } + + if (conflict) { ++ mc->sni_required = TRUE; + #ifdef OPENSSL_NO_TLSEXT + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, base_server, APLOGNO(01917) + "Init: You should not use name-based " +diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c +index bc9e26b..2460f01 100644 +--- a/modules/ssl/ssl_engine_kernel.c ++++ b/modules/ssl/ssl_engine_kernel.c +@@ -164,6 +164,7 @@ int ssl_hook_ReadReq(request_rec *r) + return DECLINED; + } + #ifndef OPENSSL_NO_TLSEXT ++ if (myModConfig(r->server)->sni_required) { + if ((servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name))) { + char *host, *scope_id; + apr_port_t port; +@@ -206,6 +207,7 @@ int ssl_hook_ReadReq(request_rec *r) + " virtual host"); + return HTTP_FORBIDDEN; + } ++ } + #endif + SSL_set_app_data2(ssl, r); + +diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h +index 75fc0e3..31dbfa9 100644 +--- a/modules/ssl/ssl_private.h ++++ b/modules/ssl/ssl_private.h +@@ -554,6 +554,7 @@ typedef struct { + struct { + void *pV1, *pV2, *pV3, *pV4, *pV5, *pV6, *pV7, *pV8, *pV9, *pV10; + } rCtx; ++ BOOL sni_required; + } SSLModConfigRec; + + /** Structure representing configured filenames for certs and keys for +@@ -786,7 +787,7 @@ const char *ssl_cmd_SSLFIPS(cmd_parms *cmd, void *dcfg, int flag); + int ssl_init_Module(apr_pool_t *, apr_pool_t *, apr_pool_t *, server_rec *); + void ssl_init_Engine(server_rec *, apr_pool_t *); + void ssl_init_ConfigureServer(server_rec *, apr_pool_t *, apr_pool_t *, SSLSrvConfigRec *); +-void ssl_init_CheckServers(server_rec *, apr_pool_t *); ++void ssl_init_CheckServers(SSLModConfigRec *mc, server_rec *, apr_pool_t *); + STACK_OF(X509_NAME) + *ssl_init_FindCAList(server_rec *, apr_pool_t *, const char *, const char *); + void ssl_init_Child(apr_pool_t *, server_rec *); diff --git a/SOURCES/httpd-2.4.4-cachehardmax.patch b/SOURCES/httpd-2.4.4-cachehardmax.patch new file mode 100644 index 0000000..de360ce --- /dev/null +++ b/SOURCES/httpd-2.4.4-cachehardmax.patch @@ -0,0 +1,82 @@ +diff --git a/modules/cache/cache_util.h b/modules/cache/cache_util.h +index eec38f3..1a2d5ee 100644 +--- a/modules/cache/cache_util.h ++++ b/modules/cache/cache_util.h +@@ -194,6 +194,9 @@ typedef struct { + unsigned int store_nostore_set:1; + unsigned int enable_set:1; + unsigned int disable_set:1; ++ /* treat maxex as hard limit */ ++ unsigned int hardmaxex:1; ++ unsigned int hardmaxex_set:1; + } cache_dir_conf; + + /* A linked-list of authn providers. */ +diff --git a/modules/cache/mod_cache.c b/modules/cache/mod_cache.c +index 4f2d3e0..30c88f4 100644 +--- a/modules/cache/mod_cache.c ++++ b/modules/cache/mod_cache.c +@@ -1299,6 +1299,11 @@ static apr_status_t cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in) + exp = date + dconf->defex; + } + } ++ /* else, forcibly cap the expiry date if required */ ++ else if (dconf->hardmaxex && (date + dconf->maxex) < exp) { ++ exp = date + dconf->maxex; ++ } ++ + info->expire = exp; + + /* We found a stale entry which wasn't really stale. */ +@@ -1717,7 +1722,9 @@ static void *create_dir_config(apr_pool_t *p, char *dummy) + + /* array of providers for this URL space */ + dconf->cacheenable = apr_array_make(p, 10, sizeof(struct cache_enable)); +- ++ /* flag; treat maxex as hard limit */ ++ dconf->hardmaxex = 0; ++ dconf->hardmaxex_set = 0; + return dconf; + } + +@@ -1767,7 +1774,10 @@ static void *merge_dir_config(apr_pool_t *p, void *basev, void *addv) { + new->enable_set = add->enable_set || base->enable_set; + new->disable = (add->disable_set == 0) ? base->disable : add->disable; + new->disable_set = add->disable_set || base->disable_set; +- ++ new->hardmaxex = ++ (add->hardmaxex_set == 0) ++ ? base->hardmaxex ++ : add->hardmaxex; + return new; + } + +@@ -2096,12 +2106,18 @@ static const char *add_cache_disable(cmd_parms *parms, void *dummy, + } + + static const char *set_cache_maxex(cmd_parms *parms, void *dummy, +- const char *arg) ++ const char *arg, const char *hard) + { + cache_dir_conf *dconf = (cache_dir_conf *)dummy; + + dconf->maxex = (apr_time_t) (atol(arg) * MSEC_ONE_SEC); + dconf->maxex_set = 1; ++ ++ if (hard && strcasecmp(hard, "hard") == 0) { ++ dconf->hardmaxex = 1; ++ dconf->hardmaxex_set = 1; ++ } ++ + return NULL; + } + +@@ -2309,7 +2325,7 @@ static const command_rec cache_cmds[] = + "caching is enabled"), + AP_INIT_TAKE1("CacheDisable", add_cache_disable, NULL, RSRC_CONF|ACCESS_CONF, + "A partial URL prefix below which caching is disabled"), +- AP_INIT_TAKE1("CacheMaxExpire", set_cache_maxex, NULL, RSRC_CONF|ACCESS_CONF, ++ AP_INIT_TAKE12("CacheMaxExpire", set_cache_maxex, NULL, RSRC_CONF|ACCESS_CONF, + "The maximum time in seconds to cache a document"), + AP_INIT_TAKE1("CacheMinExpire", set_cache_minex, NULL, RSRC_CONF|ACCESS_CONF, + "The minimum time in seconds to cache a document"), diff --git a/SOURCES/httpd-2.4.4-export.patch b/SOURCES/httpd-2.4.4-export.patch new file mode 100644 index 0000000..eb670c6 --- /dev/null +++ b/SOURCES/httpd-2.4.4-export.patch @@ -0,0 +1,20 @@ + +There is no need to "suck in" the apr/apr-util symbols when using +a shared libapr{,util}, it just bloats the symbol table; so don't. + +Upstream-HEAD: needed +Upstream-2.0: omit +Upstream-Status: EXPORT_DIRS change is conditional on using shared apr + +--- httpd-2.4.4/server/Makefile.in.export ++++ httpd-2.4.4/server/Makefile.in +@@ -57,9 +57,6 @@ export_files: + ( for dir in $(EXPORT_DIRS); do \ + ls $$dir/*.h ; \ + done; \ +- for dir in $(EXPORT_DIRS_APR); do \ +- ls $$dir/ap[ru].h $$dir/ap[ru]_*.h 2>/dev/null; \ +- done; \ + ) | sed -e s,//,/,g | sort -u > $@ + + exports.c: export_files diff --git a/SOURCES/httpd-2.4.4-malformed-host.patch b/SOURCES/httpd-2.4.4-malformed-host.patch new file mode 100644 index 0000000..57975e5 --- /dev/null +++ b/SOURCES/httpd-2.4.4-malformed-host.patch @@ -0,0 +1,12 @@ +diff --git a/server/protocol.c b/server/protocol.c +index e1ef204..d6d9165 100644 +--- a/server/protocol.c ++++ b/server/protocol.c +@@ -1049,6 +1049,7 @@ request_rec *ap_read_request(conn_rec *conn) + * now read. may update status. + */ + ap_update_vhost_from_headers(r); ++ access_status = r->status; + + /* Toggle to the Host:-based vhost's timeout mode to fetch the + * request body and send the response body, if needed. diff --git a/SOURCES/httpd-2.4.4-mod_unique_id.patch b/SOURCES/httpd-2.4.4-mod_unique_id.patch new file mode 100644 index 0000000..30bdfe0 --- /dev/null +++ b/SOURCES/httpd-2.4.4-mod_unique_id.patch @@ -0,0 +1,239 @@ +--- trunk/modules/metadata/mod_unique_id.c 2011/12/02 23:02:04 1209766 ++++ trunk/modules/metadata/mod_unique_id.c 2013/07/10 16:20:31 1501827 +@@ -31,14 +31,11 @@ + #include "http_log.h" + #include "http_protocol.h" /* for ap_hook_post_read_request */ + +-#if APR_HAVE_UNISTD_H +-#include /* for getpid() */ +-#endif ++#define ROOT_SIZE 10 + + typedef struct { + unsigned int stamp; +- unsigned int in_addr; +- unsigned int pid; ++ char root[ROOT_SIZE]; + unsigned short counter; + unsigned int thread_index; + } unique_id_rec; +@@ -64,20 +61,15 @@ + * gethostbyname (gethostname()) is unique across all the machines at the + * "site". + * +- * We also further assume that pids fit in 32-bits. If something uses more +- * than 32-bits, the fix is trivial, but it requires the unrolled uuencoding +- * loop to be extended. * A similar fix is needed to support multithreaded +- * servers, using a pid/tid combo. +- * +- * Together, the in_addr and pid are assumed to absolutely uniquely identify +- * this one child from all other currently running children on all servers +- * (including this physical server if it is running multiple httpds) from each ++ * The root is assumed to absolutely uniquely identify this one child ++ * from all other currently running children on all servers (including ++ * this physical server if it is running multiple httpds) from each + * other. + * +- * The stamp and counter are used to distinguish all hits for a particular +- * (in_addr,pid) pair. The stamp is updated using r->request_time, +- * saving cpu cycles. The counter is never reset, and is used to permit up to +- * 64k requests in a single second by a single child. ++ * The stamp and counter are used to distinguish all hits for a ++ * particular root. The stamp is updated using r->request_time, ++ * saving cpu cycles. The counter is never reset, and is used to ++ * permit up to 64k requests in a single second by a single child. + * + * The 144-bits of unique_id_rec are encoded using the alphabet + * [A-Za-z0-9@-], resulting in 24 bytes of printable characters. That is then +@@ -92,7 +84,7 @@ + * module change. + * + * It is highly desirable that identifiers exist for "eternity". But future +- * needs (such as much faster webservers, moving to 64-bit pids, or moving to a ++ * needs (such as much faster webservers, or moving to a + * multithreaded server) may dictate a need to change the contents of + * unique_id_rec. Such a future implementation should ensure that the first + * field is still a time_t stamp. By doing that, it is possible for a site to +@@ -100,7 +92,15 @@ + * wait one entire second, and then start all of their new-servers. This + * procedure will ensure that the new space of identifiers is completely unique + * from the old space. (Since the first four unencoded bytes always differ.) ++ * ++ * Note: previous implementations used 32-bits of IP address plus pid ++ * in place of the PRNG output in the "root" field. This was ++ * insufficient for IPv6-only hosts, required working DNS to determine ++ * a unique IP address (fragile), and needed a [0, 1) second sleep ++ * call at startup to avoid pid reuse. Use of the PRNG avoids all ++ * these issues. + */ ++ + /* + * Sun Jun 7 05:43:49 CEST 1998 -- Alvaro + * More comments: +@@ -116,8 +116,6 @@ + * htonl/ntohl. Well, this shouldn't be a problem till year 2106. + */ + +-static unsigned global_in_addr; +- + /* + * XXX: We should have a per-thread counter and not use cur_unique_id.counter + * XXX: in all threads, because this is bad for performance on multi-processor +@@ -129,7 +127,7 @@ + /* + * Number of elements in the structure unique_id_rec. + */ +-#define UNIQUE_ID_REC_MAX 5 ++#define UNIQUE_ID_REC_MAX 4 + + static unsigned short unique_id_rec_offset[UNIQUE_ID_REC_MAX], + unique_id_rec_size[UNIQUE_ID_REC_MAX], +@@ -138,113 +136,32 @@ + + static int unique_id_global_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *main_server) + { +- char str[APRMAXHOSTLEN + 1]; +- apr_status_t rv; +- char *ipaddrstr; +- apr_sockaddr_t *sockaddr; +- + /* + * Calculate the sizes and offsets in cur_unique_id. + */ + unique_id_rec_offset[0] = APR_OFFSETOF(unique_id_rec, stamp); + unique_id_rec_size[0] = sizeof(cur_unique_id.stamp); +- unique_id_rec_offset[1] = APR_OFFSETOF(unique_id_rec, in_addr); +- unique_id_rec_size[1] = sizeof(cur_unique_id.in_addr); +- unique_id_rec_offset[2] = APR_OFFSETOF(unique_id_rec, pid); +- unique_id_rec_size[2] = sizeof(cur_unique_id.pid); +- unique_id_rec_offset[3] = APR_OFFSETOF(unique_id_rec, counter); +- unique_id_rec_size[3] = sizeof(cur_unique_id.counter); +- unique_id_rec_offset[4] = APR_OFFSETOF(unique_id_rec, thread_index); +- unique_id_rec_size[4] = sizeof(cur_unique_id.thread_index); ++ unique_id_rec_offset[1] = APR_OFFSETOF(unique_id_rec, root); ++ unique_id_rec_size[1] = sizeof(cur_unique_id.root); ++ unique_id_rec_offset[2] = APR_OFFSETOF(unique_id_rec, counter); ++ unique_id_rec_size[2] = sizeof(cur_unique_id.counter); ++ unique_id_rec_offset[3] = APR_OFFSETOF(unique_id_rec, thread_index); ++ unique_id_rec_size[3] = sizeof(cur_unique_id.thread_index); + unique_id_rec_total_size = unique_id_rec_size[0] + unique_id_rec_size[1] + +- unique_id_rec_size[2] + unique_id_rec_size[3] + +- unique_id_rec_size[4]; ++ unique_id_rec_size[2] + unique_id_rec_size[3]; + + /* + * Calculate the size of the structure when encoded. + */ + unique_id_rec_size_uu = (unique_id_rec_total_size*8+5)/6; + +- /* +- * Now get the global in_addr. Note that it is not sufficient to use one +- * of the addresses from the main_server, since those aren't as likely to +- * be unique as the physical address of the machine +- */ +- if ((rv = apr_gethostname(str, sizeof(str) - 1, p)) != APR_SUCCESS) { +- ap_log_error(APLOG_MARK, APLOG_ALERT, rv, main_server, APLOGNO(01563) +- "unable to find hostname of the server"); +- return HTTP_INTERNAL_SERVER_ERROR; +- } +- +- if ((rv = apr_sockaddr_info_get(&sockaddr, str, AF_INET, 0, 0, p)) == APR_SUCCESS) { +- global_in_addr = sockaddr->sa.sin.sin_addr.s_addr; +- } +- else { +- ap_log_error(APLOG_MARK, APLOG_ALERT, rv, main_server, APLOGNO(01564) +- "unable to find IPv4 address of \"%s\"", str); +-#if APR_HAVE_IPV6 +- if ((rv = apr_sockaddr_info_get(&sockaddr, str, AF_INET6, 0, 0, p)) == APR_SUCCESS) { +- memcpy(&global_in_addr, +- (char *)sockaddr->ipaddr_ptr + sockaddr->ipaddr_len - sizeof(global_in_addr), +- sizeof(global_in_addr)); +- ap_log_error(APLOG_MARK, APLOG_ALERT, rv, main_server, APLOGNO(01565) +- "using low-order bits of IPv6 address " +- "as if they were unique"); +- } +- else +-#endif +- return HTTP_INTERNAL_SERVER_ERROR; +- } +- +- apr_sockaddr_ip_get(&ipaddrstr, sockaddr); +- ap_log_error(APLOG_MARK, APLOG_INFO, 0, main_server, APLOGNO(01566) "using ip addr %s", +- ipaddrstr); +- +- /* +- * If the server is pummelled with restart requests we could possibly end +- * up in a situation where we're starting again during the same second +- * that has been used in previous identifiers. Avoid that situation. +- * +- * In truth, for this to actually happen not only would it have to restart +- * in the same second, but it would have to somehow get the same pids as +- * one of the other servers that was running in that second. Which would +- * mean a 64k wraparound on pids ... not very likely at all. +- * +- * But protecting against it is relatively cheap. We just sleep into the +- * next second. +- */ +- apr_sleep(apr_time_from_sec(1) - apr_time_usec(apr_time_now())); + return OK; + } + + static void unique_id_child_init(apr_pool_t *p, server_rec *s) + { +- pid_t pid; +- +- /* +- * Note that we use the pid because it's possible that on the same +- * physical machine there are multiple servers (i.e. using Listen). But +- * it's guaranteed that none of them will share the same pids between +- * children. +- * +- * XXX: for multithread this needs to use a pid/tid combo and probably +- * needs to be expanded to 32 bits +- */ +- pid = getpid(); +- cur_unique_id.pid = pid; +- +- /* +- * Test our assumption that the pid is 32-bits. It's possible that +- * 64-bit machines will declare pid_t to be 64 bits but only use 32 +- * of them. It would have been really nice to test this during +- * global_init ... but oh well. +- */ +- if ((pid_t)cur_unique_id.pid != pid) { +- ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s, APLOGNO(01567) +- "oh no! pids are greater than 32-bits! I'm broken!"); +- } +- +- cur_unique_id.in_addr = global_in_addr; ++ ap_random_insecure_bytes(&cur_unique_id.root, ++ sizeof(cur_unique_id.root)); + + /* + * If we use 0 as the initial counter we have a little less protection +@@ -253,13 +170,6 @@ + */ + ap_random_insecure_bytes(&cur_unique_id.counter, + sizeof(cur_unique_id.counter)); +- +- /* +- * We must always use network ordering for these bytes, so that +- * identifiers are comparable between machines of different byte +- * orderings. Note in_addr is already in network order. +- */ +- cur_unique_id.pid = htonl(cur_unique_id.pid); + } + + /* NOTE: This is *NOT* the same encoding used by base64encode ... the last two +@@ -291,10 +201,8 @@ + unsigned short counter; + int i,j,k; + +- new_unique_id.in_addr = cur_unique_id.in_addr; +- new_unique_id.pid = cur_unique_id.pid; ++ memcpy(&new_unique_id.root, &cur_unique_id.root, ROOT_SIZE); + new_unique_id.counter = cur_unique_id.counter; +- + new_unique_id.stamp = htonl((unsigned int)apr_time_sec(r->request_time)); + new_unique_id.thread_index = htonl((unsigned int)r->connection->id); + diff --git a/SOURCES/httpd-2.4.4-r1337344+.patch b/SOURCES/httpd-2.4.4-r1337344+.patch new file mode 100644 index 0000000..6e5c3e7 --- /dev/null +++ b/SOURCES/httpd-2.4.4-r1337344+.patch @@ -0,0 +1,250 @@ +# ./pullrev.sh 1337344 1341905 1342065 1341930 + +suexec enhancements: + +1) use syslog for logging +2) use capabilities not setuid/setgid root binary + +http://svn.apache.org/viewvc?view=revision&revision=1337344 +http://svn.apache.org/viewvc?view=revision&revision=1341905 +http://svn.apache.org/viewvc?view=revision&revision=1342065 +http://svn.apache.org/viewvc?view=revision&revision=1341930 + +--- httpd-2.4.4/configure.in.r1337344+ ++++ httpd-2.4.4/configure.in +@@ -734,7 +734,24 @@ APACHE_HELP_STRING(--with-suexec-gidmin, + + AC_ARG_WITH(suexec-logfile, + APACHE_HELP_STRING(--with-suexec-logfile,Set the logfile),[ +- AC_DEFINE_UNQUOTED(AP_LOG_EXEC, "$withval", [SuExec log file] ) ] ) ++ if test "x$withval" = "xyes"; then ++ AC_DEFINE_UNQUOTED(AP_LOG_EXEC, "$withval", [SuExec log file]) ++ fi ++]) ++ ++AC_ARG_WITH(suexec-syslog, ++APACHE_HELP_STRING(--with-suexec-syslog,Set the logfile),[ ++ if test $withval = "yes"; then ++ if test "x${with_suexec_logfile}" != "xno"; then ++ AC_MSG_NOTICE([hint: use "--without-suexec-logfile --with-suexec-syslog"]) ++ AC_MSG_ERROR([suexec does not support both logging to file and syslog]) ++ fi ++ AC_CHECK_FUNCS([vsyslog], [], [ ++ AC_MSG_ERROR([cannot support syslog from suexec without vsyslog()])]) ++ AC_DEFINE(AP_LOG_SYSLOG, 1, [SuExec log to syslog]) ++ fi ++]) ++ + + AC_ARG_WITH(suexec-safepath, + APACHE_HELP_STRING(--with-suexec-safepath,Set the safepath),[ +@@ -744,6 +761,15 @@ AC_ARG_WITH(suexec-umask, + APACHE_HELP_STRING(--with-suexec-umask,umask for suexec'd process),[ + AC_DEFINE_UNQUOTED(AP_SUEXEC_UMASK, 0$withval, [umask for suexec'd process] ) ] ) + ++INSTALL_SUEXEC=setuid ++AC_ARG_ENABLE([suexec-capabilities], ++APACHE_HELP_STRING(--enable-suexec-capabilities,Use Linux capability bits not setuid root suexec), [ ++INSTALL_SUEXEC=caps ++AC_DEFINE(AP_SUEXEC_CAPABILITIES, 1, ++ [Enable if suexec is installed with Linux capabilities, not setuid]) ++]) ++APACHE_SUBST(INSTALL_SUEXEC) ++ + dnl APR should go after the other libs, so the right symbols can be picked up + if test x${apu_found} != xobsolete; then + AP_LIBS="$AP_LIBS `$apu_config --avoid-ldap --link-libtool`" +--- httpd-2.4.4/docs/manual/suexec.html.en.r1337344+ ++++ httpd-2.4.4/docs/manual/suexec.html.en +@@ -372,6 +372,21 @@ + together with the --enable-suexec option to let + APACI accept your request for using the suEXEC feature. + ++
--enable-suexec-capabilities
++ ++
Linux specific: Normally, ++ the suexec binary is installed "setuid/setgid ++ root", which allows it to run with the full privileges of the ++ root user. If this option is used, the suexec ++ binary will instead be installed with only the setuid/setgid ++ "capability" bits set, which is the subset of full root ++ priviliges required for suexec operation. Note that ++ the suexec binary may not be able to write to a log ++ file in this mode; it is recommended that the ++ --with-suexec-syslog --without-suexec-logfile ++ options are used in conjunction with this mode, so that syslog ++ logging is used instead.
++ +
--with-suexec-bin=PATH
+ +
The path to the suexec binary must be hard-coded +@@ -433,6 +448,12 @@ + "suexec_log" and located in your standard logfile + directory (--logfiledir).
+ ++
--with-suexec-syslog
++ ++
If defined, suexec will log notices and errors to syslog ++ instead of a logfile. This option must be combined ++ with --without-suexec-logfile.
++ +
--with-suexec-safepath=PATH
+ +
Define a safe PATH environment to pass to CGI +@@ -550,9 +571,12 @@ Group webgroup + +

The suEXEC wrapper will write log information + to the file defined with the --with-suexec-logfile +- option as indicated above. If you feel you have configured and +- installed the wrapper properly, have a look at this log and the +- error_log for the server to see where you may have gone astray.

++ option as indicated above, or to syslog if --with-suexec-syslog ++ is used. If you feel you have configured and ++ installed the wrapper properly, have a look at the log and the ++ error_log for the server to see where you may have gone astray. ++ The output of "suexec -V" will show the options ++ used to compile suexec, if using a binary distribution.

+ +
top
+
+@@ -640,4 +664,4 @@ if (typeof(prettyPrint) !== 'undefined') + prettyPrint(); + } + //--> +- +\ No newline at end of file ++ +--- httpd-2.4.4/Makefile.in.r1337344+ ++++ httpd-2.4.4/Makefile.in +@@ -238,11 +238,22 @@ install-man: + cd $(DESTDIR)$(manualdir) && find . -name ".svn" -type d -print | xargs rm -rf 2>/dev/null || true; \ + fi + +-install-suexec: ++install-suexec: install-suexec-binary install-suexec-$(INSTALL_SUEXEC) ++ ++install-suexec-binary: + @if test -f $(builddir)/support/suexec; then \ + test -d $(DESTDIR)$(sbindir) || $(MKINSTALLDIRS) $(DESTDIR)$(sbindir); \ + $(INSTALL_PROGRAM) $(top_builddir)/support/suexec $(DESTDIR)$(sbindir); \ +- chmod 4755 $(DESTDIR)$(sbindir)/suexec; \ ++ fi ++ ++install-suexec-setuid: ++ @if test -f $(builddir)/support/suexec; then \ ++ chmod 4755 $(DESTDIR)$(sbindir)/suexec; \ ++ fi ++ ++install-suexec-caps: ++ @if test -f $(builddir)/support/suexec; then \ ++ setcap 'cap_setuid,cap_setgid+pe' $(DESTDIR)$(sbindir)/suexec; \ + fi + + suexec: +--- httpd-2.4.4/modules/arch/unix/mod_unixd.c.r1337344+ ++++ httpd-2.4.4/modules/arch/unix/mod_unixd.c +@@ -284,6 +284,13 @@ unixd_set_suexec(cmd_parms *cmd, void *d + return NULL; + } + ++#ifdef AP_SUEXEC_CAPABILITIES ++/* If suexec is using capabilities, don't test for the setuid bit. */ ++#define SETUID_TEST(finfo) (1) ++#else ++#define SETUID_TEST(finfo) (finfo.protection & APR_USETID) ++#endif ++ + static int + unixd_pre_config(apr_pool_t *pconf, apr_pool_t *plog, + apr_pool_t *ptemp) +@@ -300,7 +307,7 @@ unixd_pre_config(apr_pool_t *pconf, apr_ + ap_unixd_config.suexec_enabled = 0; + if ((apr_stat(&wrapper, SUEXEC_BIN, APR_FINFO_NORM, ptemp)) + == APR_SUCCESS) { +- if ((wrapper.protection & APR_USETID) && wrapper.user == 0 ++ if (SETUID_TEST(wrapper) && wrapper.user == 0 + && (access(SUEXEC_BIN, R_OK|X_OK) == 0)) { + ap_unixd_config.suexec_enabled = 1; + ap_unixd_config.suexec_disabled_reason = ""; +--- httpd-2.4.4/support/suexec.c.r1337344+ ++++ httpd-2.4.4/support/suexec.c +@@ -58,6 +58,10 @@ + #include + #endif + ++#ifdef AP_LOG_SYSLOG ++#include ++#endif ++ + #if defined(PATH_MAX) + #define AP_MAXPATH PATH_MAX + #elif defined(MAXPATHLEN) +@@ -69,7 +73,20 @@ + #define AP_ENVBUF 256 + + extern char **environ; ++ ++#ifdef AP_LOG_SYSLOG ++/* Syslog support. */ ++#if !defined(AP_LOG_FACILITY) && defined(LOG_AUTHPRIV) ++#define AP_LOG_FACILITY LOG_AUTHPRIV ++#elif !defined(AP_LOG_FACILITY) ++#define AP_LOG_FACILITY LOG_AUTH ++#endif ++ ++static int log_open; ++#else ++/* Non-syslog support. */ + static FILE *log = NULL; ++#endif + + static const char *const safe_env_lst[] = + { +@@ -137,7 +154,14 @@ static void err_output(int is_error, con + + static void err_output(int is_error, const char *fmt, va_list ap) + { +-#ifdef AP_LOG_EXEC ++#if defined(AP_LOG_SYSLOG) ++ if (!log_open) { ++ openlog("suexec", LOG_PID, AP_LOG_FACILITY); ++ log_open = 1; ++ } ++ ++ vsyslog(is_error ? LOG_ERR : LOG_INFO, fmt, ap); ++#elif defined(AP_LOG_EXEC) + time_t timevar; + struct tm *lt; + +@@ -295,7 +319,9 @@ int main(int argc, char *argv[]) + #ifdef AP_HTTPD_USER + fprintf(stderr, " -D AP_HTTPD_USER=\"%s\"\n", AP_HTTPD_USER); + #endif +-#ifdef AP_LOG_EXEC ++#if defined(AP_LOG_SYSLOG) ++ fprintf(stderr, " -D AP_LOG_SYSLOG\n"); ++#elif defined(AP_LOG_EXEC) + fprintf(stderr, " -D AP_LOG_EXEC=\"%s\"\n", AP_LOG_EXEC); + #endif + #ifdef AP_SAFE_PATH +@@ -591,6 +617,12 @@ int main(int argc, char *argv[]) + #endif /* AP_SUEXEC_UMASK */ + + /* Be sure to close the log file so the CGI can't mess with it. */ ++#ifdef AP_LOG_SYSLOG ++ if (log_open) { ++ closelog(); ++ log_open = 0; ++ } ++#else + if (log != NULL) { + #if APR_HAVE_FCNTL_H + /* +@@ -612,6 +644,7 @@ int main(int argc, char *argv[]) + log = NULL; + #endif + } ++#endif + + /* + * Execute the command, replacing our image with its own. diff --git a/SOURCES/httpd-2.4.6-CVE-2013-4352.patch b/SOURCES/httpd-2.4.6-CVE-2013-4352.patch new file mode 100644 index 0000000..48a52f2 --- /dev/null +++ b/SOURCES/httpd-2.4.6-CVE-2013-4352.patch @@ -0,0 +1,25 @@ +--- a/modules/cache/cache_storage.c 2013/09/14 13:30:39 1523234 ++++ b/modules/cache/cache_storage.c 2013/09/14 13:32:25 1523235 +@@ -713,7 +713,9 @@ + || APR_SUCCESS + != cache_canonicalise_key(r, r->pool, location, + &location_uri, &location_key) +- || strcmp(r->parsed_uri.hostname, location_uri.hostname)) { ++ || !(r->parsed_uri.hostname && location_uri.hostname ++ && !strcmp(r->parsed_uri.hostname, ++ location_uri.hostname))) { + location_key = NULL; + } + } +@@ -726,8 +728,9 @@ + || APR_SUCCESS + != cache_canonicalise_key(r, r->pool, content_location, + &content_location_uri, &content_location_key) +- || strcmp(r->parsed_uri.hostname, +- content_location_uri.hostname)) { ++ || !(r->parsed_uri.hostname && content_location_uri.hostname ++ && !strcmp(r->parsed_uri.hostname, ++ content_location_uri.hostname))) { + content_location_key = NULL; + } + } diff --git a/SOURCES/httpd-2.4.6-CVE-2013-5704.patch b/SOURCES/httpd-2.4.6-CVE-2013-5704.patch new file mode 100644 index 0000000..ee42b25 --- /dev/null +++ b/SOURCES/httpd-2.4.6-CVE-2013-5704.patch @@ -0,0 +1,381 @@ +diff --git a/include/http_core.h b/include/http_core.h +index 3c47989..f6f4aa2 100644 +--- a/include/http_core.h ++++ b/include/http_core.h +@@ -663,6 +663,10 @@ typedef struct { + #define AP_TRACE_ENABLE 1 + #define AP_TRACE_EXTENDED 2 + int trace_enable; ++#define AP_MERGE_TRAILERS_UNSET 0 ++#define AP_MERGE_TRAILERS_ENABLE 1 ++#define AP_MERGE_TRAILERS_DISABLE 2 ++ int merge_trailers; + + } core_server_config; + +diff --git a/include/httpd.h b/include/httpd.h +index 36cd58d..2e415f9 100644 +--- a/include/httpd.h ++++ b/include/httpd.h +@@ -1032,6 +1032,11 @@ struct request_rec { + */ + apr_sockaddr_t *useragent_addr; + char *useragent_ip; ++ ++ /** MIME trailer environment from the request */ ++ apr_table_t *trailers_in; ++ /** MIME trailer environment from the response */ ++ apr_table_t *trailers_out; + }; + + /** +diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c +index 24a939a..2ae8f46 100644 +--- a/modules/http/http_filters.c ++++ b/modules/http/http_filters.c +@@ -214,6 +214,49 @@ static apr_status_t get_chunk_line(http_ctx_t *ctx, apr_bucket_brigade *b, + } + + ++static apr_status_t read_chunked_trailers(http_ctx_t *ctx, ap_filter_t *f, ++ apr_bucket_brigade *b, int merge) ++{ ++ int rv; ++ apr_bucket *e; ++ request_rec *r = f->r; ++ apr_table_t *saved_headers_in = r->headers_in; ++ int saved_status = r->status; ++ ++ r->status = HTTP_OK; ++ r->headers_in = r->trailers_in; ++ apr_table_clear(r->headers_in); ++ ctx->state = BODY_NONE; ++ ap_get_mime_headers(r); ++ ++ if(r->status == HTTP_OK) { ++ r->status = saved_status; ++ e = apr_bucket_eos_create(f->c->bucket_alloc); ++ APR_BRIGADE_INSERT_TAIL(b, e); ++ ctx->eos_sent = 1; ++ rv = APR_SUCCESS; ++ } ++ else { ++ const char *error_notes = apr_table_get(r->notes, ++ "error-notes"); ++ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, ++ "Error while reading HTTP trailer: %i%s%s", ++ r->status, error_notes ? ": " : "", ++ error_notes ? error_notes : ""); ++ rv = APR_EINVAL; ++ } ++ ++ if(!merge) { ++ r->headers_in = saved_headers_in; ++ } ++ else { ++ r->headers_in = apr_table_overlay(r->pool, saved_headers_in, ++ r->trailers_in); ++ } ++ ++ return rv; ++} ++ + /* This is the HTTP_INPUT filter for HTTP requests and responses from + * proxied servers (mod_proxy). It handles chunked and content-length + * bodies. This can only be inserted/used after the headers +@@ -223,6 +266,7 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, + ap_input_mode_t mode, apr_read_type_e block, + apr_off_t readbytes) + { ++ core_server_config *conf; + apr_bucket *e; + http_ctx_t *ctx = f->ctx; + apr_status_t rv; +@@ -230,6 +274,9 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, + int http_error = HTTP_REQUEST_ENTITY_TOO_LARGE; + apr_bucket_brigade *bb; + ++ conf = (core_server_config *) ++ ap_get_module_config(f->r->server->module_config, &core_module); ++ + /* just get out of the way of things we don't want. */ + if (mode != AP_MODE_READBYTES && mode != AP_MODE_GETLINE) { + return ap_get_brigade(f->next, b, mode, block, readbytes); +@@ -403,13 +450,8 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, + } + + if (!ctx->remaining) { +- /* Handle trailers by calling ap_get_mime_headers again! */ +- ctx->state = BODY_NONE; +- ap_get_mime_headers(f->r); +- e = apr_bucket_eos_create(f->c->bucket_alloc); +- APR_BRIGADE_INSERT_TAIL(b, e); +- ctx->eos_sent = 1; +- return APR_SUCCESS; ++ return read_chunked_trailers(ctx, f, b, ++ conf->merge_trailers == AP_MERGE_TRAILERS_ENABLE); + } + } + } +@@ -509,13 +551,8 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, + } + + if (!ctx->remaining) { +- /* Handle trailers by calling ap_get_mime_headers again! */ +- ctx->state = BODY_NONE; +- ap_get_mime_headers(f->r); +- e = apr_bucket_eos_create(f->c->bucket_alloc); +- APR_BRIGADE_INSERT_TAIL(b, e); +- ctx->eos_sent = 1; +- return APR_SUCCESS; ++ return read_chunked_trailers(ctx, f, b, ++ conf->merge_trailers == AP_MERGE_TRAILERS_ENABLE); + } + } + break; +diff --git a/modules/http/http_request.c b/modules/http/http_request.c +index 796d506..cdfec8b 100644 +--- a/modules/http/http_request.c ++++ b/modules/http/http_request.c +@@ -463,6 +463,7 @@ static request_rec *internal_internal_redirect(const char *new_uri, + new->main = r->main; + + new->headers_in = r->headers_in; ++ new->trailers_in = r->trailers_in; + new->headers_out = apr_table_make(r->pool, 12); + if (ap_is_HTTP_REDIRECT(new->status)) { + const char *location = apr_table_get(r->headers_out, "Location"); +@@ -470,6 +471,7 @@ static request_rec *internal_internal_redirect(const char *new_uri, + apr_table_setn(new->headers_out, "Location", location); + } + new->err_headers_out = r->err_headers_out; ++ new->trailers_out = apr_table_make(r->pool, 5); + new->subprocess_env = rename_original_env(r->pool, r->subprocess_env); + new->notes = apr_table_make(r->pool, 5); + +@@ -583,6 +585,8 @@ AP_DECLARE(void) ap_internal_fast_redirect(request_rec *rr, request_rec *r) + r->headers_out); + r->err_headers_out = apr_table_overlay(r->pool, rr->err_headers_out, + r->err_headers_out); ++ r->trailers_out = apr_table_overlay(r->pool, rr->trailers_out, ++ r->trailers_out); + r->subprocess_env = apr_table_overlay(r->pool, rr->subprocess_env, + r->subprocess_env); + +diff --git a/modules/loggers/mod_log_config.c b/modules/loggers/mod_log_config.c +index 25f5030..b021dd3 100644 +--- a/modules/loggers/mod_log_config.c ++++ b/modules/loggers/mod_log_config.c +@@ -431,6 +431,12 @@ static const char *log_header_in(request_rec *r, char *a) + return ap_escape_logitem(r->pool, apr_table_get(r->headers_in, a)); + } + ++static const char *log_trailer_in(request_rec *r, char *a) ++{ ++ return ap_escape_logitem(r->pool, apr_table_get(r->trailers_in, a)); ++} ++ ++ + static APR_INLINE char *find_multiple_headers(apr_pool_t *pool, + const apr_table_t *table, + const char *key) +@@ -514,6 +520,11 @@ static const char *log_header_out(request_rec *r, char *a) + return ap_escape_logitem(r->pool, cp); + } + ++static const char *log_trailer_out(request_rec *r, char *a) ++{ ++ return ap_escape_logitem(r->pool, apr_table_get(r->trailers_out, a)); ++} ++ + static const char *log_note(request_rec *r, char *a) + { + return ap_escape_logitem(r->pool, apr_table_get(r->notes, a)); +@@ -916,7 +927,7 @@ static char *parse_log_misc_string(apr_pool_t *p, log_format_item *it, + static char *parse_log_item(apr_pool_t *p, log_format_item *it, const char **sa) + { + const char *s = *sa; +- ap_log_handler *handler; ++ ap_log_handler *handler = NULL; + + if (*s != '%') { + return parse_log_misc_string(p, it, sa); +@@ -986,7 +997,16 @@ static char *parse_log_item(apr_pool_t *p, log_format_item *it, const char **sa) + break; + + default: +- handler = (ap_log_handler *)apr_hash_get(log_hash, s++, 1); ++ /* check for '^' + two character format first */ ++ if (*s == '^' && *(s+1) && *(s+2)) { ++ handler = (ap_log_handler *)apr_hash_get(log_hash, s, 3); ++ if (handler) { ++ s += 3; ++ } ++ } ++ if (!handler) { ++ handler = (ap_log_handler *)apr_hash_get(log_hash, s++, 1); ++ } + if (!handler) { + char dummy[2]; + +@@ -1516,7 +1536,7 @@ static void ap_register_log_handler(apr_pool_t *p, char *tag, + log_struct->func = handler; + log_struct->want_orig_default = def; + +- apr_hash_set(log_hash, tag, 1, (const void *)log_struct); ++ apr_hash_set(log_hash, tag, strlen(tag), (const void *)log_struct); + } + static ap_log_writer_init* ap_log_set_writer_init(ap_log_writer_init *handle) + { +@@ -1686,6 +1706,9 @@ static int log_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp) + log_pfn_register(p, "U", log_request_uri, 1); + log_pfn_register(p, "s", log_status, 1); + log_pfn_register(p, "R", log_handler, 1); ++ ++ log_pfn_register(p, "^ti", log_trailer_in, 0); ++ log_pfn_register(p, "^to", log_trailer_out, 0); + } + + /* reset to default conditions */ +diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c +index 7ae0fa4..05f33b4 100644 +--- a/modules/proxy/mod_proxy_http.c ++++ b/modules/proxy/mod_proxy_http.c +@@ -994,8 +994,11 @@ static request_rec *make_fake_req(conn_rec *c, request_rec *r) + rp->status = HTTP_OK; + + rp->headers_in = apr_table_make(pool, 50); ++ rp->trailers_in = apr_table_make(pool, 5); ++ + rp->subprocess_env = apr_table_make(pool, 50); + rp->headers_out = apr_table_make(pool, 12); ++ rp->trailers_out = apr_table_make(pool, 5); + rp->err_headers_out = apr_table_make(pool, 5); + rp->notes = apr_table_make(pool, 5); + +@@ -1076,6 +1079,7 @@ static void ap_proxy_read_headers(request_rec *r, request_rec *rr, + psc = (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module); + + r->headers_out = apr_table_make(r->pool, 20); ++ r->trailers_out = apr_table_make(r->pool, 5); + *pread_len = 0; + + /* +@@ -1206,6 +1210,14 @@ apr_status_t ap_proxygetline(apr_bucket_brigade *bb, char *s, int n, request_rec + #define AP_MAX_INTERIM_RESPONSES 10 + #endif + ++static int add_trailers(void *data, const char *key, const char *val) ++{ ++ if (val) { ++ apr_table_add((apr_table_t*)data, key, val); ++ } ++ return 1; ++} ++ + static + apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, + proxy_conn_rec **backend_ptr, +@@ -1717,6 +1729,12 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, + /* next time try a non-blocking read */ + mode = APR_NONBLOCK_READ; + ++ if (!apr_is_empty_table(backend->r->trailers_in)) { ++ apr_table_do(add_trailers, r->trailers_out, ++ backend->r->trailers_in, NULL); ++ apr_table_clear(backend->r->trailers_in); ++ } ++ + apr_brigade_length(bb, 0, &readbytes); + backend->worker->s->read += readbytes; + #if DEBUGGING +diff --git a/server/core.c b/server/core.c +index 024bab6..7cfde63 100644 +--- a/server/core.c ++++ b/server/core.c +@@ -523,6 +523,10 @@ static void *merge_core_server_configs(apr_pool_t *p, void *basev, void *virtv) + if (virt->error_log_req) + conf->error_log_req = virt->error_log_req; + ++ conf->merge_trailers = (virt->merge_trailers != AP_MERGE_TRAILERS_UNSET) ++ ? virt->merge_trailers ++ : base->merge_trailers; ++ + return conf; + } + +@@ -3877,6 +3881,16 @@ AP_DECLARE(void) ap_register_errorlog_handler(apr_pool_t *p, char *tag, + } + + ++static const char *set_merge_trailers(cmd_parms *cmd, void *dummy, int arg) ++{ ++ core_server_config *conf = ap_get_module_config(cmd->server->module_config, ++ &core_module); ++ conf->merge_trailers = (arg ? AP_MERGE_TRAILERS_ENABLE : ++ AP_MERGE_TRAILERS_DISABLE); ++ ++ return NULL; ++} ++ + /* Note --- ErrorDocument will now work from .htaccess files. + * The AllowOverride of Fileinfo allows webmasters to turn it off + */ +@@ -4124,6 +4138,8 @@ AP_INIT_TAKE1("EnableExceptionHook", ap_mpm_set_exception_hook, NULL, RSRC_CONF, + #endif + AP_INIT_TAKE1("TraceEnable", set_trace_enable, NULL, RSRC_CONF, + "'on' (default), 'off' or 'extended' to trace request body content"), ++AP_INIT_FLAG("MergeTrailers", set_merge_trailers, NULL, RSRC_CONF, ++ "merge request trailers into request headers or not"), + { NULL } + }; + +@@ -4206,7 +4222,6 @@ static int core_map_to_storage(request_rec *r) + + static int do_nothing(request_rec *r) { return OK; } + +- + static int core_override_type(request_rec *r) + { + core_dir_config *conf = +diff --git a/server/protocol.c b/server/protocol.c +index 14329eb..46fc034 100644 +--- a/server/protocol.c ++++ b/server/protocol.c +@@ -718,6 +718,8 @@ AP_DECLARE(void) ap_get_mime_headers_core(request_rec *r, apr_bucket_brigade *bb + r->status = HTTP_REQUEST_TIME_OUT; + } + else { ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, rv, r, ++ "Failed to read request header line %s", field); + r->status = HTTP_BAD_REQUEST; + } + +@@ -917,9 +919,11 @@ request_rec *ap_read_request(conn_rec *conn) + r->allowed_methods = ap_make_method_list(p, 2); + + r->headers_in = apr_table_make(r->pool, 25); ++ r->trailers_in = apr_table_make(r->pool, 5); + r->subprocess_env = apr_table_make(r->pool, 25); + r->headers_out = apr_table_make(r->pool, 12); + r->err_headers_out = apr_table_make(r->pool, 5); ++ r->trailers_out = apr_table_make(r->pool, 5); + r->notes = apr_table_make(r->pool, 5); + + r->request_config = ap_create_request_config(r->pool); +@@ -1162,6 +1166,7 @@ AP_DECLARE(void) ap_set_sub_req_protocol(request_rec *rnew, + rnew->status = HTTP_OK; + + rnew->headers_in = apr_table_copy(rnew->pool, r->headers_in); ++ rnew->trailers_in = apr_table_copy(rnew->pool, r->trailers_in); + + /* did the original request have a body? (e.g. POST w/SSI tags) + * if so, make sure the subrequest doesn't inherit body headers +@@ -1173,6 +1178,7 @@ AP_DECLARE(void) ap_set_sub_req_protocol(request_rec *rnew, + rnew->subprocess_env = apr_table_copy(rnew->pool, r->subprocess_env); + rnew->headers_out = apr_table_make(rnew->pool, 5); + rnew->err_headers_out = apr_table_make(rnew->pool, 5); ++ rnew->trailers_out = apr_table_make(rnew->pool, 5); + rnew->notes = apr_table_make(rnew->pool, 5); + + rnew->expecting_100 = r->expecting_100; diff --git a/SOURCES/httpd-2.4.6-CVE-2013-6438.patch b/SOURCES/httpd-2.4.6-CVE-2013-6438.patch new file mode 100644 index 0000000..1b154f5 --- /dev/null +++ b/SOURCES/httpd-2.4.6-CVE-2013-6438.patch @@ -0,0 +1,14 @@ +--- a/modules/dav/main/util.c 2014/01/09 14:28:39 1556815 ++++ b/modules/dav/main/util.c 2014/01/09 14:29:47 1556816 +@@ -396,8 +396,10 @@ + + if (strip_white) { + /* trim leading whitespace */ +- while (apr_isspace(*cdata)) /* assume: return false for '\0' */ ++ while (apr_isspace(*cdata)) { /* assume: return false for '\0' */ + ++cdata; ++ --len; ++ } + + /* trim trailing whitespace */ + while (len-- > 0 && apr_isspace(cdata[len])) diff --git a/SOURCES/httpd-2.4.6-CVE-2014-0098.patch b/SOURCES/httpd-2.4.6-CVE-2014-0098.patch new file mode 100644 index 0000000..64d5064 --- /dev/null +++ b/SOURCES/httpd-2.4.6-CVE-2014-0098.patch @@ -0,0 +1,41 @@ +--- a/modules/loggers/mod_log_config.c 2013/11/15 17:07:52 1542329 ++++ b/modules/loggers/mod_log_config.c 2014/03/10 11:23:47 1575904 +@@ -543,14 +543,24 @@ + + while ((cookie = apr_strtok(cookies, ";", &last1))) { + char *name = apr_strtok(cookie, "=", &last2); +- if (name) { +- char *value = name + strlen(name) + 1; +- apr_collapse_spaces(name, name); ++ /* last2 points to the next char following an '=' delim, ++ or the trailing NUL char of the string */ ++ char *value = last2; ++ if (name && *name && value && *value) { ++ char *last = value - 2; ++ /* Move past leading WS */ ++ name += strspn(name, " \t"); ++ while (last >= name && apr_isspace(*last)) { ++ *last = '\0'; ++ --last; ++ } + + if (!strcasecmp(name, a)) { +- char *last; +- value += strspn(value, " \t"); /* Move past leading WS */ +- last = value + strlen(value) - 1; ++ /* last1 points to the next char following the ';' delim, ++ or the trailing NUL char of the string */ ++ last = last1 - (*last1 ? 2 : 1); ++ /* Move past leading WS */ ++ value += strspn(value, " \t"); + while (last >= value && apr_isspace(*last)) { + *last = '\0'; + --last; +@@ -559,6 +569,7 @@ + return ap_escape_logitem(r->pool, value); + } + } ++ /* Iterate the remaining tokens using apr_strtok(NULL, ...) */ + cookies = NULL; + } + } diff --git a/SOURCES/httpd-2.4.6-CVE-2014-0117.patch b/SOURCES/httpd-2.4.6-CVE-2014-0117.patch new file mode 100644 index 0000000..f548d99 --- /dev/null +++ b/SOURCES/httpd-2.4.6-CVE-2014-0117.patch @@ -0,0 +1,11 @@ +--- a/modules/proxy/proxy_util.c 2014/07/15 16:07:44 1610736 ++++ b/modules/proxy/proxy_util.c 2014/07/15 16:11:04 1610737 +@@ -3132,7 +3132,7 @@ + const char *name; + + do { +- while (*val == ',') { ++ while (*val == ',' || *val == ';') { + val++; + } + name = ap_get_token(x->pool, &val, 0); diff --git a/SOURCES/httpd-2.4.6-CVE-2014-0118.patch b/SOURCES/httpd-2.4.6-CVE-2014-0118.patch new file mode 100644 index 0000000..e82b79f --- /dev/null +++ b/SOURCES/httpd-2.4.6-CVE-2014-0118.patch @@ -0,0 +1,266 @@ +diff --git a/modules/filters/mod_deflate.c b/modules/filters/mod_deflate.c +index 79f6f8d..6c415c8 100644 +--- a/modules/filters/mod_deflate.c ++++ b/modules/filters/mod_deflate.c +@@ -37,6 +37,7 @@ + #include "httpd.h" + #include "http_config.h" + #include "http_log.h" ++#include "http_core.h" + #include "apr_lib.h" + #include "apr_strings.h" + #include "apr_general.h" +@@ -52,6 +53,9 @@ + static const char deflateFilterName[] = "DEFLATE"; + module AP_MODULE_DECLARE_DATA deflate_module; + ++#define AP_INFLATE_RATIO_LIMIT 200 ++#define AP_INFLATE_RATIO_BURST 3 ++ + typedef struct deflate_filter_config_t + { + int windowSize; +@@ -63,6 +67,12 @@ typedef struct deflate_filter_config_t + char *note_output_name; + } deflate_filter_config; + ++typedef struct deflate_dirconf_t { ++ apr_off_t inflate_limit; ++ int ratio_limit, ++ ratio_burst; ++} deflate_dirconf_t; ++ + /* RFC 1952 Section 2.3 defines the gzip header: + * + * +---+---+---+---+---+---+---+---+---+---+ +@@ -204,6 +214,14 @@ static void *create_deflate_server_config(apr_pool_t *p, server_rec *s) + return c; + } + ++static void *create_deflate_dirconf(apr_pool_t *p, char *dummy) ++{ ++ deflate_dirconf_t *dc = apr_pcalloc(p, sizeof(*dc)); ++ dc->ratio_limit = AP_INFLATE_RATIO_LIMIT; ++ dc->ratio_burst = AP_INFLATE_RATIO_BURST; ++ return dc; ++} ++ + static const char *deflate_set_window_size(cmd_parms *cmd, void *dummy, + const char *arg) + { +@@ -295,6 +313,55 @@ static const char *deflate_set_compressionlevel(cmd_parms *cmd, void *dummy, + return NULL; + } + ++ ++static const char *deflate_set_inflate_limit(cmd_parms *cmd, void *dirconf, ++ const char *arg) ++{ ++ deflate_dirconf_t *dc = (deflate_dirconf_t*) dirconf; ++ char *errp; ++ ++ if (APR_SUCCESS != apr_strtoff(&dc->inflate_limit, arg, &errp, 10)) { ++ return "DeflateInflateLimitRequestBody is not parsable."; ++ } ++ if (*errp || dc->inflate_limit < 0) { ++ return "DeflateInflateLimitRequestBody requires a non-negative integer."; ++ } ++ ++ return NULL; ++} ++ ++static const char *deflate_set_inflate_ratio_limit(cmd_parms *cmd, ++ void *dirconf, ++ const char *arg) ++{ ++ deflate_dirconf_t *dc = (deflate_dirconf_t*) dirconf; ++ int i; ++ ++ i = atoi(arg); ++ if (i <= 0) ++ return "DeflateInflateRatioLimit must be positive"; ++ ++ dc->ratio_limit = i; ++ ++ return NULL; ++} ++ ++static const char *deflate_set_inflate_ratio_burst(cmd_parms *cmd, ++ void *dirconf, ++ const char *arg) ++{ ++ deflate_dirconf_t *dc = (deflate_dirconf_t*) dirconf; ++ int i; ++ ++ i = atoi(arg); ++ if (i <= 0) ++ return "DeflateInflateRatioBurst must be positive"; ++ ++ dc->ratio_burst = i; ++ ++ return NULL; ++} ++ + typedef struct deflate_ctx_t + { + z_stream stream; +@@ -304,6 +371,8 @@ typedef struct deflate_ctx_t + int (*libz_end_func)(z_streamp); + unsigned char *validation_buffer; + apr_size_t validation_buffer_length; ++ int ratio_hits; ++ apr_off_t inflate_total; + unsigned int inflate_init:1; + unsigned int filter_init:1; + unsigned int done:1; +@@ -422,6 +491,22 @@ static void deflate_check_etag(request_rec *r, const char *transform) + } + } + ++/* Check whether the (inflate) ratio exceeds the configured limit/burst. */ ++static int check_ratio(request_rec *r, deflate_ctx *ctx, ++ const deflate_dirconf_t *dc) ++{ ++ if (ctx->stream.total_in) { ++ int ratio = ctx->stream.total_out / ctx->stream.total_in; ++ if (ratio < dc->ratio_limit) { ++ ctx->ratio_hits = 0; ++ } ++ else if (++ctx->ratio_hits > dc->ratio_burst) { ++ return 0; ++ } ++ } ++ return 1; ++} ++ + static int have_ssl_compression(request_rec *r) + { + const char *comp; +@@ -897,6 +982,8 @@ static apr_status_t deflate_in_filter(ap_filter_t *f, + int zRC; + apr_status_t rv; + deflate_filter_config *c; ++ deflate_dirconf_t *dc; ++ apr_off_t inflate_limit; + + /* just get out of the way of things we don't want. */ + if (mode != AP_MODE_READBYTES) { +@@ -904,6 +991,7 @@ static apr_status_t deflate_in_filter(ap_filter_t *f, + } + + c = ap_get_module_config(r->server->module_config, &deflate_module); ++ dc = ap_get_module_config(r->per_dir_config, &deflate_module); + + if (!ctx) { + char deflate_hdr[10]; +@@ -994,6 +1082,12 @@ static apr_status_t deflate_in_filter(ap_filter_t *f, + apr_brigade_cleanup(ctx->bb); + } + ++ inflate_limit = dc->inflate_limit; ++ if (inflate_limit == 0) { ++ /* The core is checking the deflated body, we'll check the inflated */ ++ inflate_limit = ap_get_limit_req_body(f->r); ++ } ++ + if (APR_BRIGADE_EMPTY(ctx->proc_bb)) { + rv = ap_get_brigade(f->next, ctx->bb, mode, block, readbytes); + +@@ -1038,6 +1132,17 @@ static apr_status_t deflate_in_filter(ap_filter_t *f, + + ctx->stream.next_out = ctx->buffer; + len = c->bufferSize - ctx->stream.avail_out; ++ ++ ctx->inflate_total += len; ++ if (inflate_limit && ctx->inflate_total > inflate_limit) { ++ inflateEnd(&ctx->stream); ++ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(02647) ++ "Inflated content length of %" APR_OFF_T_FMT ++ " is larger than the configured limit" ++ " of %" APR_OFF_T_FMT, ++ ctx->inflate_total, inflate_limit); ++ return APR_ENOSPC; ++ } + + ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len); + tmp_heap = apr_bucket_heap_create((char *)ctx->buffer, len, +@@ -1073,6 +1178,26 @@ static apr_status_t deflate_in_filter(ap_filter_t *f, + ctx->stream.next_out = ctx->buffer; + len = c->bufferSize - ctx->stream.avail_out; + ++ ctx->inflate_total += len; ++ if (inflate_limit && ctx->inflate_total > inflate_limit) { ++ inflateEnd(&ctx->stream); ++ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(02648) ++ "Inflated content length of %" APR_OFF_T_FMT ++ " is larger than the configured limit" ++ " of %" APR_OFF_T_FMT, ++ ctx->inflate_total, inflate_limit); ++ return APR_ENOSPC; ++ } ++ ++ if (!check_ratio(r, ctx, dc)) { ++ inflateEnd(&ctx->stream); ++ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(02649) ++ "Inflated content ratio is larger than the " ++ "configured limit %i by %i time(s)", ++ dc->ratio_limit, dc->ratio_burst); ++ return APR_EINVAL; ++ } ++ + ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len); + tmp_heap = apr_bucket_heap_create((char *)ctx->buffer, len, + NULL, f->c->bucket_alloc); +@@ -1193,6 +1318,7 @@ static apr_status_t inflate_out_filter(ap_filter_t *f, + int zRC; + apr_status_t rv; + deflate_filter_config *c; ++ deflate_dirconf_t *dc; + + /* Do nothing if asked to filter nothing. */ + if (APR_BRIGADE_EMPTY(bb)) { +@@ -1200,6 +1326,7 @@ static apr_status_t inflate_out_filter(ap_filter_t *f, + } + + c = ap_get_module_config(r->server->module_config, &deflate_module); ++ dc = ap_get_module_config(r->per_dir_config, &deflate_module); + + if (!ctx) { + +@@ -1462,6 +1589,14 @@ static apr_status_t inflate_out_filter(ap_filter_t *f, + while (ctx->stream.avail_in != 0) { + if (ctx->stream.avail_out == 0) { + ++ if (!check_ratio(r, ctx, dc)) { ++ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(02650) ++ "Inflated content ratio is larger than the " ++ "configured limit %i by %i time(s)", ++ dc->ratio_limit, dc->ratio_burst); ++ return APR_EINVAL; ++ } ++ + ctx->stream.next_out = ctx->buffer; + len = c->bufferSize - ctx->stream.avail_out; + +@@ -1548,12 +1683,20 @@ static const command_rec deflate_filter_cmds[] = { + "Set the Deflate Memory Level (1-9)"), + AP_INIT_TAKE1("DeflateCompressionLevel", deflate_set_compressionlevel, NULL, RSRC_CONF, + "Set the Deflate Compression Level (1-9)"), ++ AP_INIT_TAKE1("DeflateInflateLimitRequestBody", deflate_set_inflate_limit, NULL, OR_ALL, ++ "Set a limit on size of inflated input"), ++ AP_INIT_TAKE1("DeflateInflateRatioLimit", deflate_set_inflate_ratio_limit, NULL, OR_ALL, ++ "Set the inflate ratio limit above which inflation is " ++ "aborted (default: " APR_STRINGIFY(AP_INFLATE_RATIO_LIMIT) ")"), ++ AP_INIT_TAKE1("DeflateInflateRatioBurst", deflate_set_inflate_ratio_burst, NULL, OR_ALL, ++ "Set the maximum number of following inflate ratios above limit " ++ "(default: " APR_STRINGIFY(AP_INFLATE_RATIO_BURST) ")"), + {NULL} + }; + + AP_DECLARE_MODULE(deflate) = { + STANDARD20_MODULE_STUFF, +- NULL, /* dir config creater */ ++ create_deflate_dirconf, /* dir config creater */ + NULL, /* dir merger --- default is to override */ + create_deflate_server_config, /* server config */ + NULL, /* merge server config */ diff --git a/SOURCES/httpd-2.4.6-CVE-2014-0226.patch b/SOURCES/httpd-2.4.6-CVE-2014-0226.patch new file mode 100644 index 0000000..67c7046 --- /dev/null +++ b/SOURCES/httpd-2.4.6-CVE-2014-0226.patch @@ -0,0 +1,119 @@ +Index: server/scoreboard.c +=================================================================== +--- a/server/scoreboard.c (revision 1610498) ++++ b/server/scoreboard.c (revision 1610499) +@@ -579,6 +579,21 @@ + sbh->thread_num); + } + ++AP_DECLARE(void) ap_copy_scoreboard_worker(worker_score *dest, ++ int child_num, ++ int thread_num) ++{ ++ worker_score *ws = ap_get_scoreboard_worker_from_indexes(child_num, thread_num); ++ ++ memcpy(dest, ws, sizeof *ws); ++ ++ /* For extra safety, NUL-terminate the strings returned, though it ++ * should be true those last bytes are always zero anyway. */ ++ dest->client[sizeof(dest->client) - 1] = '\0'; ++ dest->request[sizeof(dest->request) - 1] = '\0'; ++ dest->vhost[sizeof(dest->vhost) - 1] = '\0'; ++} ++ + AP_DECLARE(process_score *) ap_get_scoreboard_process(int x) + { + if ((x < 0) || (x >= server_limit)) { +Index: modules/generators/mod_status.c +=================================================================== +--- a/modules/generators/mod_status.c (revision 1610498) ++++ b/modules/generators/mod_status.c (revision 1610499) +@@ -194,7 +194,7 @@ + long req_time; + int short_report; + int no_table_report; +- worker_score *ws_record; ++ worker_score *ws_record = apr_palloc(r->pool, sizeof *ws_record); + process_score *ps_record; + char *stat_buffer; + pid_t *pid_buffer, worker_pid; +@@ -306,7 +306,7 @@ + for (j = 0; j < thread_limit; ++j) { + int indx = (i * thread_limit) + j; + +- ws_record = ap_get_scoreboard_worker_from_indexes(i, j); ++ ap_copy_scoreboard_worker(ws_record, i, j); + res = ws_record->status; + + if ((i >= max_servers || j >= threads_per_child) +@@ -637,7 +637,7 @@ + + for (i = 0; i < server_limit; ++i) { + for (j = 0; j < thread_limit; ++j) { +- ws_record = ap_get_scoreboard_worker_from_indexes(i, j); ++ ap_copy_scoreboard_worker(ws_record, i, j); + + if (ws_record->access_count == 0 && + (ws_record->status == SERVER_READY || +Index: modules/lua/lua_request.c +=================================================================== +--- a/modules/lua/lua_request.c (revision 1610498) ++++ b/modules/lua/lua_request.c (revision 1610499) +@@ -1245,16 +1245,22 @@ + */ + static int lua_ap_scoreboard_worker(lua_State *L) + { +- int i, +- j; +- worker_score *ws_record; ++ int i, j; ++ worker_score *ws_record = NULL; ++ request_rec *r = NULL; + + luaL_checktype(L, 1, LUA_TUSERDATA); + luaL_checktype(L, 2, LUA_TNUMBER); + luaL_checktype(L, 3, LUA_TNUMBER); ++ ++ r = ap_lua_check_request_rec(L, 1); ++ if (!r) return 0; ++ + i = lua_tointeger(L, 2); + j = lua_tointeger(L, 3); +- ws_record = ap_get_scoreboard_worker_from_indexes(i, j); ++ ws_record = apr_palloc(r->pool, sizeof *ws_record); ++ ++ ap_copy_scoreboard_worker(ws_record, i, j); + if (ws_record) { + lua_newtable(L); + +Index: include/scoreboard.h +=================================================================== +--- a/include/scoreboard.h (revision 1610498) ++++ b/include/scoreboard.h (revision 1610499) +@@ -183,8 +183,25 @@ + AP_DECLARE(void) ap_time_process_request(ap_sb_handle_t *sbh, int status); + + AP_DECLARE(worker_score *) ap_get_scoreboard_worker(ap_sb_handle_t *sbh); ++ ++/** Return a pointer to the worker_score for a given child, thread pair. ++ * @param child_num The child number. ++ * @param thread_num The thread number. ++ * @return A pointer to the worker_score structure. ++ * @deprecated This function is deprecated, use ap_copy_scoreboard_worker instead. */ + AP_DECLARE(worker_score *) ap_get_scoreboard_worker_from_indexes(int child_num, + int thread_num); ++ ++/** Copy the contents of a worker scoreboard entry. The contents of ++ * the worker_score structure are copied verbatim into the dest ++ * structure. ++ * @param dest Output parameter. ++ * @param child_num The child number. ++ * @param thread_num The thread number. ++ */ ++AP_DECLARE(void) ap_copy_scoreboard_worker(worker_score *dest, ++ int child_num, int thread_num); ++ + AP_DECLARE(process_score *) ap_get_scoreboard_process(int x); + AP_DECLARE(global_score *) ap_get_scoreboard_global(void); + + diff --git a/SOURCES/httpd-2.4.6-CVE-2014-0231.patch b/SOURCES/httpd-2.4.6-CVE-2014-0231.patch new file mode 100644 index 0000000..580123a --- /dev/null +++ b/SOURCES/httpd-2.4.6-CVE-2014-0231.patch @@ -0,0 +1,144 @@ +--- a/modules/generators/mod_cgid.c 2014/07/14 20:16:45 1610511 ++++ b/modules/generators/mod_cgid.c 2014/07/14 20:18:26 1610512 +@@ -97,6 +97,10 @@ + static pid_t parent_pid; + static ap_unix_identity_t empty_ugid = { (uid_t)-1, (gid_t)-1, -1 }; + ++typedef struct { ++ apr_interval_time_t timeout; ++} cgid_dirconf; ++ + /* The APR other-child API doesn't tell us how the daemon exited + * (SIGSEGV vs. exit(1)). The other-child maintenance function + * needs to decide whether to restart the daemon after a failure +@@ -968,7 +972,14 @@ + return overrides->logname ? overrides : base; + } + ++static void *create_cgid_dirconf(apr_pool_t *p, char *dummy) ++{ ++ cgid_dirconf *c = (cgid_dirconf *) apr_pcalloc(p, sizeof(cgid_dirconf)); ++ return c; ++} ++ + static const char *set_scriptlog(cmd_parms *cmd, void *dummy, const char *arg) ++ + { + server_rec *s = cmd->server; + cgid_server_conf *conf = ap_get_module_config(s->module_config, +@@ -1021,7 +1032,16 @@ + + return NULL; + } ++static const char *set_script_timeout(cmd_parms *cmd, void *dummy, const char *arg) ++{ ++ cgid_dirconf *dc = dummy; + ++ if (ap_timeout_parameter_parse(arg, &dc->timeout, "s") != APR_SUCCESS) { ++ return "CGIDScriptTimeout has wrong format"; ++ } ++ ++ return NULL; ++} + static const command_rec cgid_cmds[] = + { + AP_INIT_TAKE1("ScriptLog", set_scriptlog, NULL, RSRC_CONF, +@@ -1033,6 +1053,10 @@ + AP_INIT_TAKE1("ScriptSock", set_script_socket, NULL, RSRC_CONF, + "the name of the socket to use for communication with " + "the cgi daemon."), ++ AP_INIT_TAKE1("CGIDScriptTimeout", set_script_timeout, NULL, RSRC_CONF | ACCESS_CONF, ++ "The amount of time to wait between successful reads from " ++ "the CGI script, in seconds."), ++ + {NULL} + }; + +@@ -1356,12 +1380,16 @@ + apr_file_t *tempsock; + struct cleanup_script_info *info; + apr_status_t rv; ++ cgid_dirconf *dc; + + if (strcmp(r->handler, CGI_MAGIC_TYPE) && strcmp(r->handler, "cgi-script")) { + return DECLINED; + } + + conf = ap_get_module_config(r->server->module_config, &cgid_module); ++ dc = ap_get_module_config(r->per_dir_config, &cgid_module); ++ ++ + is_included = !strcmp(r->protocol, "INCLUDED"); + + if ((argv0 = strrchr(r->filename, '/')) != NULL) { +@@ -1441,6 +1469,12 @@ + */ + + apr_os_pipe_put_ex(&tempsock, &sd, 1, r->pool); ++ if (dc->timeout > 0) { ++ apr_file_pipe_timeout_set(tempsock, dc->timeout); ++ } ++ else { ++ apr_file_pipe_timeout_set(tempsock, r->server->timeout); ++ } + apr_pool_cleanup_kill(r->pool, (void *)((long)sd), close_unix_socket); + + /* Transfer any put/post args, CERN style... +@@ -1517,6 +1551,10 @@ + if (rv != APR_SUCCESS) { + /* silly script stopped reading, soak up remaining message */ + child_stopped_reading = 1; ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(02651) ++ "Error writing request body to script %s", ++ r->filename); ++ + } + } + apr_brigade_cleanup(bb); +@@ -1610,7 +1648,13 @@ + return HTTP_MOVED_TEMPORARILY; + } + +- ap_pass_brigade(r->output_filters, bb); ++ rv = ap_pass_brigade(r->output_filters, bb); ++ if (rv != APR_SUCCESS) { ++ /* APLOG_ERR because the core output filter message is at error, ++ * but doesn't know it's passing CGI output ++ */ ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(02550) "Failed to flush CGI output to client"); ++ } + } + + if (nph) { +@@ -1741,6 +1785,8 @@ + request_rec *r = f->r; + cgid_server_conf *conf = ap_get_module_config(r->server->module_config, + &cgid_module); ++ cgid_dirconf *dc = ap_get_module_config(r->per_dir_config, &cgid_module); ++ + struct cleanup_script_info *info; + + add_ssi_vars(r); +@@ -1770,6 +1816,13 @@ + * get rid of the cleanup we registered when we created the socket. + */ + apr_os_pipe_put_ex(&tempsock, &sd, 1, r->pool); ++ if (dc->timeout > 0) { ++ apr_file_pipe_timeout_set(tempsock, dc->timeout); ++ } ++ else { ++ apr_file_pipe_timeout_set(tempsock, r->server->timeout); ++ } ++ + apr_pool_cleanup_kill(r->pool, (void *)((long)sd), close_unix_socket); + + APR_BRIGADE_INSERT_TAIL(bb, apr_bucket_pipe_create(tempsock, +@@ -1875,7 +1928,7 @@ + + AP_DECLARE_MODULE(cgid) = { + STANDARD20_MODULE_STUFF, +- NULL, /* dir config creater */ ++ create_cgid_dirconf, /* dir config creater */ + NULL, /* dir merger --- default is to override */ + create_cgid_config, /* server config */ + merge_cgid_config, /* merge server config */ diff --git a/SOURCES/httpd-2.4.6-CVE-2014-3581.patch b/SOURCES/httpd-2.4.6-CVE-2014-3581.patch new file mode 100644 index 0000000..2f2217d --- /dev/null +++ b/SOURCES/httpd-2.4.6-CVE-2014-3581.patch @@ -0,0 +1,17 @@ +diff --git a/modules/cache/cache_util.c b/modules/cache/cache_util.c +index 7b7fb45..fbebb1e 100644 +--- a/modules/cache/cache_util.c ++++ b/modules/cache/cache_util.c +@@ -1251,8 +1251,10 @@ CACHE_DECLARE(apr_table_t *)ap_cache_cacheable_headers_out(request_rec *r) + + if (!apr_table_get(headers_out, "Content-Type") + && r->content_type) { +- apr_table_setn(headers_out, "Content-Type", +- ap_make_content_type(r, r->content_type)); ++ const char *ctype = ap_make_content_type(r, r->content_type); ++ if (ctype) { ++ apr_table_setn(headers_out, "Content-Type", ctype); ++ } + } + + if (!apr_table_get(headers_out, "Content-Encoding") diff --git a/SOURCES/httpd-2.4.6-CVE-2015-3183.patch b/SOURCES/httpd-2.4.6-CVE-2015-3183.patch new file mode 100644 index 0000000..da4d4fa --- /dev/null +++ b/SOURCES/httpd-2.4.6-CVE-2015-3183.patch @@ -0,0 +1,982 @@ +diff --git a/include/http_protocol.h b/include/http_protocol.h +index 415270b..67fa02f 100644 +--- a/include/http_protocol.h ++++ b/include/http_protocol.h +@@ -502,6 +502,23 @@ AP_DECLARE(int) ap_should_client_block(request_rec *r); + */ + AP_DECLARE(long) ap_get_client_block(request_rec *r, char *buffer, apr_size_t bufsiz); + ++/* ++ * Map specific APR codes returned by the filter stack to HTTP error ++ * codes, or the default status code provided. Use it as follows: ++ * ++ * return ap_map_http_request_error(rv, HTTP_BAD_REQUEST); ++ * ++ * If the filter has already handled the error, AP_FILTER_ERROR will ++ * be returned, which is cleanly passed through. ++ * ++ * These mappings imply that the filter stack is reading from the ++ * downstream client, the proxy will map these codes differently. ++ * @param rv APR status code ++ * @param status Default HTTP code should the APR code not be recognised ++ * @return Mapped HTTP status code ++ */ ++AP_DECLARE(int) ap_map_http_request_error(apr_status_t rv, int status); ++ + /** + * In HTTP/1.1, any method can have a body. However, most GET handlers + * wouldn't know what to do with a request body if they received one. +diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c +index 1dde402..ed8749f 100644 +--- a/modules/http/http_filters.c ++++ b/modules/http/http_filters.c +@@ -57,24 +57,29 @@ + + APLOG_USE_MODULE(http); + +-#define INVALID_CHAR -2 +- +-static long get_chunk_size(char *); +- +-typedef struct http_filter_ctx { ++typedef struct http_filter_ctx ++{ + apr_off_t remaining; + apr_off_t limit; + apr_off_t limit_used; +- enum { +- BODY_NONE, +- BODY_LENGTH, +- BODY_CHUNK, +- BODY_CHUNK_PART ++ apr_int32_t chunk_used; ++ apr_int32_t chunk_bws; ++ apr_int32_t chunkbits; ++ enum ++ { ++ BODY_NONE, /* streamed data */ ++ BODY_LENGTH, /* data constrained by content length */ ++ BODY_CHUNK, /* chunk expected */ ++ BODY_CHUNK_PART, /* chunk digits */ ++ BODY_CHUNK_EXT, /* chunk extension */ ++ BODY_CHUNK_CR, /* got space(s) after digits, expect [CR]LF or ext */ ++ BODY_CHUNK_LF, /* got CR after digits or ext, expect LF */ ++ BODY_CHUNK_DATA, /* data constrained by chunked encoding */ ++ BODY_CHUNK_END, /* chunked data terminating CRLF */ ++ BODY_CHUNK_END_LF, /* got CR after data, expect LF */ ++ BODY_CHUNK_TRAILER /* trailers */ + } state; +- int eos_sent; +- char chunk_ln[32]; +- char *pos; +- apr_off_t linesize; ++ unsigned int eos_sent :1; + apr_bucket_brigade *bb; + } http_ctx_t; + +@@ -87,6 +92,23 @@ static apr_status_t bail_out_on_error(http_ctx_t *ctx, + apr_bucket_brigade *bb = ctx->bb; + + apr_brigade_cleanup(bb); ++ ++ if (f->r->proxyreq == PROXYREQ_RESPONSE) { ++ switch (http_error) { ++ case HTTP_REQUEST_ENTITY_TOO_LARGE: ++ return APR_ENOSPC; ++ ++ case HTTP_REQUEST_TIME_OUT: ++ return APR_INCOMPLETE; ++ ++ case HTTP_NOT_IMPLEMENTED: ++ return APR_ENOTIMPL; ++ ++ default: ++ return APR_EGENERAL; ++ } ++ } ++ + e = ap_bucket_error_create(http_error, + NULL, f->r->pool, + f->c->bucket_alloc); +@@ -102,117 +124,154 @@ static apr_status_t bail_out_on_error(http_ctx_t *ctx, + return ap_pass_brigade(f->r->output_filters, bb); + } + +-static apr_status_t get_remaining_chunk_line(http_ctx_t *ctx, +- apr_bucket_brigade *b, +- int linelimit) ++/** ++ * Parse a chunk line with optional extension, detect overflow. ++ * There are two error cases: ++ * 1) If the conversion would require too many bits, APR_EGENERAL is returned. ++ * 2) If the conversion used the correct number of bits, but an overflow ++ * caused only the sign bit to flip, then APR_ENOSPC is returned. ++ * In general, any negative number can be considered an overflow error. ++ */ ++static apr_status_t parse_chunk_size(http_ctx_t *ctx, const char *buffer, ++ apr_size_t len, int linelimit) + { +- apr_status_t rv; +- apr_off_t brigade_length; +- apr_bucket *e; +- const char *lineend; +- apr_size_t len = 0; ++ apr_size_t i = 0; + +- /* +- * As the brigade b should have been requested in mode AP_MODE_GETLINE +- * all buckets in this brigade are already some type of memory +- * buckets (due to the needed scanning for LF in mode AP_MODE_GETLINE) +- * or META buckets. +- */ +- rv = apr_brigade_length(b, 0, &brigade_length); +- if (rv != APR_SUCCESS) { +- return rv; +- } +- /* Sanity check. Should never happen. See above. */ +- if (brigade_length == -1) { +- return APR_EGENERAL; +- } +- if (!brigade_length) { +- return APR_EAGAIN; +- } +- ctx->linesize += brigade_length; +- if (ctx->linesize > linelimit) { +- return APR_ENOSPC; +- } +- /* +- * As all buckets are already some type of memory buckets or META buckets +- * (see above), we only need to check the last byte in the last data bucket. +- */ +- for (e = APR_BRIGADE_LAST(b); +- e != APR_BRIGADE_SENTINEL(b); +- e = APR_BUCKET_PREV(e)) { ++ while (i < len) { ++ char c = buffer[i]; ++ ++ ap_xlate_proto_from_ascii(&c, 1); + +- if (APR_BUCKET_IS_METADATA(e)) { ++ /* handle CRLF after the chunk */ ++ if (ctx->state == BODY_CHUNK_END ++ || ctx->state == BODY_CHUNK_END_LF) { ++ if (c == LF) { ++ ctx->state = BODY_CHUNK; ++ } ++ else if (c == CR && ctx->state == BODY_CHUNK_END) { ++ ctx->state = BODY_CHUNK_END_LF; ++ } ++ else { ++ /* ++ * LF expected. ++ */ ++ return APR_EINVAL; ++ } ++ i++; + continue; + } +- rv = apr_bucket_read(e, &lineend, &len, APR_BLOCK_READ); +- if (rv != APR_SUCCESS) { +- return rv; ++ ++ /* handle start of the chunk */ ++ if (ctx->state == BODY_CHUNK) { ++ if (!apr_isxdigit(c)) { ++ /* ++ * Detect invalid character at beginning. This also works for ++ * empty chunk size lines. ++ */ ++ return APR_EINVAL; ++ } ++ else { ++ ctx->state = BODY_CHUNK_PART; ++ } ++ ctx->remaining = 0; ++ ctx->chunkbits = sizeof(apr_off_t) * 8; ++ ctx->chunk_used = 0; ++ ctx->chunk_bws = 0; + } +- if (len > 0) { +- break; /* we got the data we want */ ++ ++ if (c == LF) { ++ if (ctx->remaining) { ++ ctx->state = BODY_CHUNK_DATA; ++ } ++ else { ++ ctx->state = BODY_CHUNK_TRAILER; ++ } + } +- /* If we got a zero-length data bucket, we try the next one */ +- } +- /* We had no data in this brigade */ +- if (!len || e == APR_BRIGADE_SENTINEL(b)) { +- return APR_EAGAIN; +- } +- if (lineend[len - 1] != APR_ASCII_LF) { +- return APR_EAGAIN; +- } +- /* Line is complete. So reset ctx for next round. */ +- ctx->linesize = 0; +- ctx->pos = ctx->chunk_ln; +- return APR_SUCCESS; +-} ++ else if (ctx->state == BODY_CHUNK_LF) { ++ /* ++ * LF expected. ++ */ ++ return APR_EINVAL; ++ } ++ else if (c == CR) { ++ ctx->state = BODY_CHUNK_LF; ++ } ++ else if (c == ';') { ++ ctx->state = BODY_CHUNK_EXT; ++ } ++ else if (ctx->state == BODY_CHUNK_EXT) { ++ /* ++ * Control chars (but tabs) are invalid. ++ */ ++ if (c != '\t' && apr_iscntrl(c)) { ++ return APR_EINVAL; ++ } ++ } ++ else if (c == ' ' || c == '\t') { ++ /* Be lenient up to 10 BWS (term from rfc7230 - 3.2.3). ++ */ ++ ctx->state = BODY_CHUNK_CR; ++ if (++ctx->chunk_bws > 10) { ++ return APR_EINVAL; ++ } ++ } ++ else if (ctx->state == BODY_CHUNK_CR) { ++ /* ++ * ';', CR or LF expected. ++ */ ++ return APR_EINVAL; ++ } ++ else if (ctx->state == BODY_CHUNK_PART) { ++ int xvalue; + +-static apr_status_t get_chunk_line(http_ctx_t *ctx, apr_bucket_brigade *b, +- int linelimit) +-{ +- apr_size_t len; +- int tmp_len; +- apr_status_t rv; ++ /* ignore leading zeros */ ++ if (!ctx->remaining && c == '0') { ++ i++; ++ continue; ++ } + +- tmp_len = sizeof(ctx->chunk_ln) - (ctx->pos - ctx->chunk_ln) - 1; +- /* Saveguard ourselves against underflows */ +- if (tmp_len < 0) { +- len = 0; +- } +- else { +- len = (apr_size_t) tmp_len; +- } +- /* +- * Check if there is space left in ctx->chunk_ln. If not, then either +- * the chunk size is insane or we have chunk-extensions. Ignore both +- * by discarding the remaining part of the line via +- * get_remaining_chunk_line. Only bail out if the line is too long. +- */ +- if (len > 0) { +- rv = apr_brigade_flatten(b, ctx->pos, &len); +- if (rv != APR_SUCCESS) { +- return rv; ++ ctx->chunkbits -= 4; ++ if (ctx->chunkbits < 0) { ++ /* overflow */ ++ return APR_ENOSPC; ++ } ++ ++ if (c >= '0' && c <= '9') { ++ xvalue = c - '0'; ++ } ++ else if (c >= 'A' && c <= 'F') { ++ xvalue = c - 'A' + 0xa; ++ } ++ else if (c >= 'a' && c <= 'f') { ++ xvalue = c - 'a' + 0xa; ++ } ++ else { ++ /* bogus character */ ++ return APR_EINVAL; ++ } ++ ++ ctx->remaining = (ctx->remaining << 4) | xvalue; ++ if (ctx->remaining < 0) { ++ /* overflow */ ++ return APR_ENOSPC; ++ } + } +- ctx->pos += len; +- ctx->linesize += len; +- *(ctx->pos) = '\0'; +- /* +- * Check if we really got a full line. If yes the +- * last char in the just read buffer must be LF. +- * If not advance the buffer and return APR_EAGAIN. +- * We do not start processing until we have the +- * full line. +- */ +- if (ctx->pos[-1] != APR_ASCII_LF) { +- /* Check if the remaining data in the brigade has the LF */ +- return get_remaining_chunk_line(ctx, b, linelimit); ++ else { ++ /* Should not happen */ ++ return APR_EGENERAL; + } +- /* Line is complete. So reset ctx->pos for next round. */ +- ctx->pos = ctx->chunk_ln; +- return APR_SUCCESS; ++ ++ i++; + } +- return get_remaining_chunk_line(ctx, b, linelimit); +-} + ++ /* sanity check */ ++ ctx->chunk_used += len; ++ if (ctx->chunk_used < 0 || ctx->chunk_used > linelimit) { ++ return APR_ENOSPC; ++ } ++ ++ return APR_SUCCESS; ++} + + static apr_status_t read_chunked_trailers(http_ctx_t *ctx, ap_filter_t *f, + apr_bucket_brigade *b, int merge) +@@ -226,7 +285,6 @@ static apr_status_t read_chunked_trailers(http_ctx_t *ctx, ap_filter_t *f, + r->status = HTTP_OK; + r->headers_in = r->trailers_in; + apr_table_clear(r->headers_in); +- ctx->state = BODY_NONE; + ap_get_mime_headers(r); + + if(r->status == HTTP_OK) { +@@ -239,7 +297,7 @@ static apr_status_t read_chunked_trailers(http_ctx_t *ctx, ap_filter_t *f, + else { + const char *error_notes = apr_table_get(r->notes, + "error-notes"); +- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, ++ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(02656) + "Error while reading HTTP trailer: %i%s%s", + r->status, error_notes ? ": " : "", + error_notes ? error_notes : ""); +@@ -270,9 +328,9 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, + apr_bucket *e; + http_ctx_t *ctx = f->ctx; + apr_status_t rv; +- apr_off_t totalread; + int http_error = HTTP_REQUEST_ENTITY_TOO_LARGE; + apr_bucket_brigade *bb; ++ int again; + + conf = (core_server_config *) + ap_get_module_config(f->r->server->module_config, &core_module); +@@ -286,7 +344,6 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, + const char *tenc, *lenp; + f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(*ctx)); + ctx->state = BODY_NONE; +- ctx->pos = ctx->chunk_ln; + ctx->bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc); + bb = ctx->bb; + +@@ -306,25 +363,33 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, + lenp = apr_table_get(f->r->headers_in, "Content-Length"); + + if (tenc) { +- if (!strcasecmp(tenc, "chunked")) { ++ if (strcasecmp(tenc, "chunked") == 0 /* fast path */ ++ || ap_find_last_token(f->r->pool, tenc, "chunked")) { + ctx->state = BODY_CHUNK; + } +- /* test lenp, because it gives another case we can handle */ +- else if (!lenp) { +- /* Something that isn't in HTTP, unless some future ++ else if (f->r->proxyreq == PROXYREQ_RESPONSE) { ++ /* http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-23 ++ * Section 3.3.3.3: "If a Transfer-Encoding header field is ++ * present in a response and the chunked transfer coding is not ++ * the final encoding, the message body length is determined by ++ * reading the connection until it is closed by the server." ++ */ ++ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, f->r, APLOGNO(02555) ++ "Unknown Transfer-Encoding: %s; " ++ "using read-until-close", tenc); ++ tenc = NULL; ++ } ++ else { ++ /* Something that isn't a HTTP request, unless some future + * edition defines new transfer encodings, is unsupported. + */ + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, f->r, APLOGNO(01585) + "Unknown Transfer-Encoding: %s", tenc); +- return bail_out_on_error(ctx, f, HTTP_NOT_IMPLEMENTED); +- } +- else { +- ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, f->r, APLOGNO(01586) +- "Unknown Transfer-Encoding: %s; using Content-Length", tenc); +- tenc = NULL; ++ return bail_out_on_error(ctx, f, HTTP_BAD_REQUEST); + } ++ lenp = NULL; + } +- if (lenp && !tenc) { ++ if (lenp) { + char *endstr; + + ctx->state = BODY_LENGTH; +@@ -339,7 +404,7 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, f->r, APLOGNO(01587) + "Invalid Content-Length"); + +- return bail_out_on_error(ctx, f, HTTP_REQUEST_ENTITY_TOO_LARGE); ++ return bail_out_on_error(ctx, f, HTTP_BAD_REQUEST); + } + + /* If we have a limit in effect and we know the C-L ahead of +@@ -381,7 +446,8 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, + if (!ap_is_HTTP_SUCCESS(f->r->status)) { + ctx->state = BODY_NONE; + ctx->eos_sent = 1; +- } else { ++ } ++ else { + char *tmp; + int len; + +@@ -389,7 +455,7 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, + * in a state of expecting one. + */ + f->r->expecting_100 = 0; +- tmp = apr_pstrcat(f->r->pool, AP_SERVER_PROTOCOL, " ", ++ tmp = apr_pstrcat(f->r->pool, AP_SERVER_PROTOCOL " ", + ap_get_status_line(HTTP_CONTINUE), CRLF CRLF, + NULL); + len = strlen(tmp); +@@ -401,279 +467,205 @@ apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b, + e = apr_bucket_flush_create(f->c->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(bb, e); + +- ap_pass_brigade(f->c->output_filters, bb); +- } +- } +- +- /* We can't read the chunk until after sending 100 if required. */ +- if (ctx->state == BODY_CHUNK) { +- apr_brigade_cleanup(bb); +- +- rv = ap_get_brigade(f->next, bb, AP_MODE_GETLINE, +- block, 0); +- +- /* for timeout */ +- if (block == APR_NONBLOCK_READ && +- ( (rv == APR_SUCCESS && APR_BRIGADE_EMPTY(bb)) || +- (APR_STATUS_IS_EAGAIN(rv)) )) { +- ctx->state = BODY_CHUNK_PART; +- return APR_EAGAIN; +- } +- +- if (rv == APR_SUCCESS) { +- rv = get_chunk_line(ctx, bb, f->r->server->limit_req_line); +- if (APR_STATUS_IS_EAGAIN(rv)) { +- apr_brigade_cleanup(bb); +- ctx->state = BODY_CHUNK_PART; +- return rv; +- } +- if (rv == APR_SUCCESS) { +- ctx->remaining = get_chunk_size(ctx->chunk_ln); +- if (ctx->remaining == INVALID_CHAR) { +- rv = APR_EGENERAL; +- http_error = HTTP_BAD_REQUEST; +- } ++ rv = ap_pass_brigade(f->c->output_filters, bb); ++ if (rv != APR_SUCCESS) { ++ return AP_FILTER_ERROR; + } + } +- apr_brigade_cleanup(bb); +- +- /* Detect chunksize error (such as overflow) */ +- if (rv != APR_SUCCESS || ctx->remaining < 0) { +- ap_log_rerror(APLOG_MARK, APLOG_INFO, rv, f->r, APLOGNO(01589) "Error reading first chunk %s ", +- (ctx->remaining < 0) ? "(overflow)" : ""); +- ctx->remaining = 0; /* Reset it in case we have to +- * come back here later */ +- if (APR_STATUS_IS_TIMEUP(rv)) { +- http_error = HTTP_REQUEST_TIME_OUT; +- } +- return bail_out_on_error(ctx, f, http_error); +- } +- +- if (!ctx->remaining) { +- return read_chunked_trailers(ctx, f, b, +- conf->merge_trailers == AP_MERGE_TRAILERS_ENABLE); +- } + } + } +- else { +- bb = ctx->bb; +- } + ++ /* sanity check in case we're read twice */ + if (ctx->eos_sent) { + e = apr_bucket_eos_create(f->c->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(b, e); + return APR_SUCCESS; + } + +- if (!ctx->remaining) { ++ do { ++ apr_brigade_cleanup(b); ++ again = 0; /* until further notice */ ++ ++ /* read and handle the brigade */ + switch (ctx->state) { +- case BODY_NONE: +- break; +- case BODY_LENGTH: +- e = apr_bucket_eos_create(f->c->bucket_alloc); +- APR_BRIGADE_INSERT_TAIL(b, e); +- ctx->eos_sent = 1; +- return APR_SUCCESS; + case BODY_CHUNK: + case BODY_CHUNK_PART: +- { +- apr_brigade_cleanup(bb); ++ case BODY_CHUNK_EXT: ++ case BODY_CHUNK_CR: ++ case BODY_CHUNK_LF: ++ case BODY_CHUNK_END: ++ case BODY_CHUNK_END_LF: { + +- /* We need to read the CRLF after the chunk. */ +- if (ctx->state == BODY_CHUNK) { +- rv = ap_get_brigade(f->next, bb, AP_MODE_GETLINE, +- block, 0); +- if (block == APR_NONBLOCK_READ && +- ( (rv == APR_SUCCESS && APR_BRIGADE_EMPTY(bb)) || +- (APR_STATUS_IS_EAGAIN(rv)) )) { +- return APR_EAGAIN; +- } +- /* If we get an error, then leave */ +- if (rv != APR_SUCCESS) { +- return rv; +- } +- /* +- * We really don't care whats on this line. If it is RFC +- * compliant it should be only \r\n. If there is more +- * before we just ignore it as long as we do not get over +- * the limit for request lines. +- */ +- rv = get_remaining_chunk_line(ctx, bb, +- f->r->server->limit_req_line); +- apr_brigade_cleanup(bb); +- if (APR_STATUS_IS_EAGAIN(rv)) { +- return rv; +- } +- } else { +- rv = APR_SUCCESS; +- } ++ rv = ap_get_brigade(f->next, b, AP_MODE_GETLINE, block, 0); ++ ++ /* for timeout */ ++ if (block == APR_NONBLOCK_READ ++ && ((rv == APR_SUCCESS && APR_BRIGADE_EMPTY(b)) ++ || (APR_STATUS_IS_EAGAIN(rv)))) { ++ return APR_EAGAIN; ++ } ++ ++ if (rv == APR_EOF) { ++ return APR_INCOMPLETE; ++ } ++ ++ if (rv != APR_SUCCESS) { ++ return rv; ++ } ++ ++ e = APR_BRIGADE_FIRST(b); ++ while (e != APR_BRIGADE_SENTINEL(b)) { ++ const char *buffer; ++ apr_size_t len; ++ ++ if (!APR_BUCKET_IS_METADATA(e)) { ++ int parsing = 0; ++ ++ rv = apr_bucket_read(e, &buffer, &len, APR_BLOCK_READ); + +- if (rv == APR_SUCCESS) { +- /* Read the real chunk line. */ +- rv = ap_get_brigade(f->next, bb, AP_MODE_GETLINE, +- block, 0); +- /* Test timeout */ +- if (block == APR_NONBLOCK_READ && +- ( (rv == APR_SUCCESS && APR_BRIGADE_EMPTY(bb)) || +- (APR_STATUS_IS_EAGAIN(rv)) )) { +- ctx->state = BODY_CHUNK_PART; +- return APR_EAGAIN; +- } +- ctx->state = BODY_CHUNK; + if (rv == APR_SUCCESS) { +- rv = get_chunk_line(ctx, bb, f->r->server->limit_req_line); +- if (APR_STATUS_IS_EAGAIN(rv)) { +- ctx->state = BODY_CHUNK_PART; +- apr_brigade_cleanup(bb); +- return rv; +- } +- if (rv == APR_SUCCESS) { +- ctx->remaining = get_chunk_size(ctx->chunk_ln); +- if (ctx->remaining == INVALID_CHAR) { +- rv = APR_EGENERAL; ++ parsing = 1; ++ rv = parse_chunk_size(ctx, buffer, len, ++ f->r->server->limit_req_fieldsize); ++ } ++ if (rv != APR_SUCCESS) { ++ ap_log_rerror(APLOG_MARK, APLOG_INFO, rv, f->r, APLOGNO(01590) ++ "Error reading/parsing chunk %s ", ++ (APR_ENOSPC == rv) ? "(overflow)" : ""); ++ if (parsing) { ++ if (rv != APR_ENOSPC) { + http_error = HTTP_BAD_REQUEST; + } ++ return bail_out_on_error(ctx, f, http_error); + } ++ return rv; + } +- apr_brigade_cleanup(bb); + } + +- /* Detect chunksize error (such as overflow) */ +- if (rv != APR_SUCCESS || ctx->remaining < 0) { +- ap_log_rerror(APLOG_MARK, APLOG_INFO, rv, f->r, APLOGNO(01590) "Error reading chunk %s ", +- (ctx->remaining < 0) ? "(overflow)" : ""); +- ctx->remaining = 0; /* Reset it in case we have to +- * come back here later */ +- if (APR_STATUS_IS_TIMEUP(rv)) { +- http_error = HTTP_REQUEST_TIME_OUT; +- } +- return bail_out_on_error(ctx, f, http_error); +- } ++ apr_bucket_delete(e); ++ e = APR_BRIGADE_FIRST(b); ++ } ++ again = 1; /* come around again */ + +- if (!ctx->remaining) { +- return read_chunked_trailers(ctx, f, b, ++ if (ctx->state == BODY_CHUNK_TRAILER) { ++ /* Treat UNSET as DISABLE - trailers aren't merged by default */ ++ return read_chunked_trailers(ctx, f, b, + conf->merge_trailers == AP_MERGE_TRAILERS_ENABLE); +- } + } ++ + break; + } +- } ++ case BODY_NONE: ++ case BODY_LENGTH: ++ case BODY_CHUNK_DATA: { + +- /* Ensure that the caller can not go over our boundary point. */ +- if (ctx->state == BODY_LENGTH || ctx->state == BODY_CHUNK) { +- if (ctx->remaining < readbytes) { +- readbytes = ctx->remaining; +- } +- AP_DEBUG_ASSERT(readbytes > 0); +- } ++ /* Ensure that the caller can not go over our boundary point. */ ++ if (ctx->state != BODY_NONE && ctx->remaining < readbytes) { ++ readbytes = ctx->remaining; ++ } ++ if (readbytes > 0) { ++ apr_off_t totalread; + +- rv = ap_get_brigade(f->next, b, mode, block, readbytes); ++ rv = ap_get_brigade(f->next, b, mode, block, readbytes); + +- if (rv != APR_SUCCESS) { +- return rv; +- } ++ /* for timeout */ ++ if (block == APR_NONBLOCK_READ ++ && ((rv == APR_SUCCESS && APR_BRIGADE_EMPTY(b)) ++ || (APR_STATUS_IS_EAGAIN(rv)))) { ++ return APR_EAGAIN; ++ } + +- /* How many bytes did we just read? */ +- apr_brigade_length(b, 0, &totalread); ++ if (rv == APR_EOF && ctx->state != BODY_NONE ++ && ctx->remaining > 0) { ++ return APR_INCOMPLETE; ++ } + +- /* If this happens, we have a bucket of unknown length. Die because +- * it means our assumptions have changed. */ +- AP_DEBUG_ASSERT(totalread >= 0); ++ if (rv != APR_SUCCESS) { ++ return rv; ++ } + +- if (ctx->state != BODY_NONE) { +- ctx->remaining -= totalread; +- if (ctx->remaining > 0) { +- e = APR_BRIGADE_LAST(b); +- if (APR_BUCKET_IS_EOS(e)) +- return APR_EOF; +- } +- } ++ /* How many bytes did we just read? */ ++ apr_brigade_length(b, 0, &totalread); + +- /* If we have no more bytes remaining on a C-L request, +- * save the callter a roundtrip to discover EOS. +- */ +- if (ctx->state == BODY_LENGTH && ctx->remaining == 0) { +- e = apr_bucket_eos_create(f->c->bucket_alloc); +- APR_BRIGADE_INSERT_TAIL(b, e); +- } ++ /* If this happens, we have a bucket of unknown length. Die because ++ * it means our assumptions have changed. */ ++ AP_DEBUG_ASSERT(totalread >= 0); + +- /* We have a limit in effect. */ +- if (ctx->limit) { +- /* FIXME: Note that we might get slightly confused on chunked inputs +- * as we'd need to compensate for the chunk lengths which may not +- * really count. This seems to be up for interpretation. */ +- ctx->limit_used += totalread; +- if (ctx->limit < ctx->limit_used) { +- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, f->r, APLOGNO(01591) +- "Read content-length of %" APR_OFF_T_FMT +- " is larger than the configured limit" +- " of %" APR_OFF_T_FMT, ctx->limit_used, ctx->limit); +- apr_brigade_cleanup(bb); +- e = ap_bucket_error_create(HTTP_REQUEST_ENTITY_TOO_LARGE, NULL, +- f->r->pool, +- f->c->bucket_alloc); +- APR_BRIGADE_INSERT_TAIL(bb, e); +- e = apr_bucket_eos_create(f->c->bucket_alloc); +- APR_BRIGADE_INSERT_TAIL(bb, e); +- ctx->eos_sent = 1; +- return ap_pass_brigade(f->r->output_filters, bb); +- } +- } ++ if (ctx->state != BODY_NONE) { ++ ctx->remaining -= totalread; ++ if (ctx->remaining > 0) { ++ e = APR_BRIGADE_LAST(b); ++ if (APR_BUCKET_IS_EOS(e)) { ++ apr_bucket_delete(e); ++ return APR_INCOMPLETE; ++ } ++ } ++ else if (ctx->state == BODY_CHUNK_DATA) { ++ /* next chunk please */ ++ ctx->state = BODY_CHUNK_END; ++ ctx->chunk_used = 0; ++ } ++ } + +- return APR_SUCCESS; +-} ++ /* We have a limit in effect. */ ++ if (ctx->limit) { ++ /* FIXME: Note that we might get slightly confused on ++ * chunked inputs as we'd need to compensate for the chunk ++ * lengths which may not really count. This seems to be up ++ * for interpretation. ++ */ ++ ctx->limit_used += totalread; ++ if (ctx->limit < ctx->limit_used) { ++ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, f->r, ++ APLOGNO(01591) "Read content length of " ++ "%" APR_OFF_T_FMT " is larger than the " ++ "configured limit of %" APR_OFF_T_FMT, ++ ctx->limit_used, ctx->limit); ++ return bail_out_on_error(ctx, f, ++ HTTP_REQUEST_ENTITY_TOO_LARGE); ++ } ++ } ++ } + +-/** +- * Parse a chunk extension, detect overflow. +- * There are two error cases: +- * 1) If the conversion would require too many bits, a -1 is returned. +- * 2) If the conversion used the correct number of bits, but an overflow +- * caused only the sign bit to flip, then that negative number is +- * returned. +- * In general, any negative number can be considered an overflow error. +- */ +-static long get_chunk_size(char *b) +-{ +- long chunksize = 0; +- size_t chunkbits = sizeof(long) * 8; ++ /* If we have no more bytes remaining on a C-L request, ++ * save the caller a round trip to discover EOS. ++ */ ++ if (ctx->state == BODY_LENGTH && ctx->remaining == 0) { ++ e = apr_bucket_eos_create(f->c->bucket_alloc); ++ APR_BRIGADE_INSERT_TAIL(b, e); ++ ctx->eos_sent = 1; ++ } + +- ap_xlate_proto_from_ascii(b, strlen(b)); ++ break; ++ } ++ case BODY_CHUNK_TRAILER: { + +- if (!apr_isxdigit(*b)) { +- /* +- * Detect invalid character at beginning. This also works for empty +- * chunk size lines. +- */ +- return INVALID_CHAR; +- } +- /* Skip leading zeros */ +- while (*b == '0') { +- ++b; +- } ++ rv = ap_get_brigade(f->next, b, mode, block, readbytes); + +- while (apr_isxdigit(*b) && (chunkbits > 0)) { +- int xvalue = 0; ++ /* for timeout */ ++ if (block == APR_NONBLOCK_READ ++ && ((rv == APR_SUCCESS && APR_BRIGADE_EMPTY(b)) ++ || (APR_STATUS_IS_EAGAIN(rv)))) { ++ return APR_EAGAIN; ++ } ++ ++ if (rv != APR_SUCCESS) { ++ return rv; ++ } + +- if (*b >= '0' && *b <= '9') { +- xvalue = *b - '0'; ++ break; + } +- else if (*b >= 'A' && *b <= 'F') { +- xvalue = *b - 'A' + 0xa; ++ default: { ++ /* Should not happen */ ++ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, f->r, APLOGNO(02901) ++ "Unexpected body state (%i)", (int)ctx->state); ++ return APR_EGENERAL; + } +- else if (*b >= 'a' && *b <= 'f') { +- xvalue = *b - 'a' + 0xa; + } + +- chunksize = (chunksize << 4) | xvalue; +- chunkbits -= 4; +- ++b; +- } +- if (apr_isxdigit(*b)) { +- /* overflow */ +- return -1; +- } ++ } while (again); + +- return chunksize; ++ return APR_SUCCESS; + } + + typedef struct header_struct { +@@ -1385,6 +1377,39 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f, + return ap_pass_brigade(f->next, b); + } + ++/* ++ * Map specific APR codes returned by the filter stack to HTTP error ++ * codes, or the default status code provided. Use it as follows: ++ * ++ * return ap_map_http_request_error(rv, HTTP_BAD_REQUEST); ++ * ++ * If the filter has already handled the error, AP_FILTER_ERROR will ++ * be returned, which is cleanly passed through. ++ * ++ * These mappings imply that the filter stack is reading from the ++ * downstream client, the proxy will map these codes differently. ++ */ ++AP_DECLARE(int) ap_map_http_request_error(apr_status_t rv, int status) ++{ ++ switch (rv) { ++ case AP_FILTER_ERROR: { ++ return AP_FILTER_ERROR; ++ } ++ case APR_ENOSPC: { ++ return HTTP_REQUEST_ENTITY_TOO_LARGE; ++ } ++ case APR_ENOTIMPL: { ++ return HTTP_NOT_IMPLEMENTED; ++ } ++ case APR_ETIMEDOUT: { ++ return HTTP_REQUEST_TIME_OUT; ++ } ++ default: { ++ return status; ++ } ++ } ++} ++ + /* In HTTP/1.1, any method can have a body. However, most GET handlers + * wouldn't know what to do with a request body if they received one. + * This helper routine tests for and reads any message body in the request, +@@ -1402,7 +1427,8 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f, + AP_DECLARE(int) ap_discard_request_body(request_rec *r) + { + apr_bucket_brigade *bb; +- int rv, seen_eos; ++ int seen_eos; ++ apr_status_t rv; + + /* Sometimes we'll get in a state where the input handling has + * detected an error where we want to drop the connection, so if +@@ -1425,21 +1451,8 @@ AP_DECLARE(int) ap_discard_request_body(request_rec *r) + APR_BLOCK_READ, HUGE_STRING_LEN); + + if (rv != APR_SUCCESS) { +- /* FIXME: If we ever have a mapping from filters (apr_status_t) +- * to HTTP error codes, this would be a good place for them. +- * +- * If we received the special case AP_FILTER_ERROR, it means +- * that the filters have already handled this error. +- * Otherwise, we should assume we have a bad request. +- */ +- if (rv == AP_FILTER_ERROR) { +- apr_brigade_destroy(bb); +- return rv; +- } +- else { +- apr_brigade_destroy(bb); +- return HTTP_BAD_REQUEST; +- } ++ apr_brigade_destroy(bb); ++ return ap_map_http_request_error(rv, HTTP_BAD_REQUEST); + } + + for (bucket = APR_BRIGADE_FIRST(bb); +@@ -1608,6 +1621,13 @@ AP_DECLARE(long) ap_get_client_block(request_rec *r, char *buffer, + /* We lose the failure code here. This is why ap_get_client_block should + * not be used. + */ ++ if (rv == AP_FILTER_ERROR) { ++ /* AP_FILTER_ERROR means a filter has responded already, ++ * we are DONE. ++ */ ++ apr_brigade_destroy(bb); ++ return -1; ++ } + if (rv != APR_SUCCESS) { + /* if we actually fail here, we want to just return and + * stop trying to read data from the client. diff --git a/SOURCES/httpd-2.4.6-CVE-2015-3185.patch b/SOURCES/httpd-2.4.6-CVE-2015-3185.patch new file mode 100644 index 0000000..e8bb688 --- /dev/null +++ b/SOURCES/httpd-2.4.6-CVE-2015-3185.patch @@ -0,0 +1,175 @@ +Index: server/request.c +=================================================================== +--- a/server/request.c (revision 1684524) ++++ b/server/request.c (revision 1684525) +@@ -71,6 +71,7 @@ + APR_HOOK_LINK(create_request) + APR_HOOK_LINK(post_perdir_config) + APR_HOOK_LINK(dirwalk_stat) ++ APR_HOOK_LINK(force_authn) + ) + + AP_IMPLEMENT_HOOK_RUN_FIRST(int,translate_name, +@@ -97,6 +98,8 @@ + AP_IMPLEMENT_HOOK_RUN_FIRST(apr_status_t,dirwalk_stat, + (apr_finfo_t *finfo, request_rec *r, apr_int32_t wanted), + (finfo, r, wanted), AP_DECLINED) ++AP_IMPLEMENT_HOOK_RUN_FIRST(int,force_authn, ++ (request_rec *r), (r), DECLINED) + + static int auth_internal_per_conf = 0; + static int auth_internal_per_conf_hooks = 0; +@@ -118,6 +121,39 @@ + } + } + ++AP_DECLARE(int) ap_some_authn_required(request_rec *r) ++{ ++ int access_status; ++ ++ switch (ap_satisfies(r)) { ++ case SATISFY_ALL: ++ case SATISFY_NOSPEC: ++ if ((access_status = ap_run_access_checker(r)) != OK) { ++ break; ++ } ++ ++ access_status = ap_run_access_checker_ex(r); ++ if (access_status == DECLINED) { ++ return TRUE; ++ } ++ ++ break; ++ case SATISFY_ANY: ++ if ((access_status = ap_run_access_checker(r)) == OK) { ++ break; ++ } ++ ++ access_status = ap_run_access_checker_ex(r); ++ if (access_status == DECLINED) { ++ return TRUE; ++ } ++ ++ break; ++ } ++ ++ return FALSE; ++} ++ + /* This is the master logic for processing requests. Do NOT duplicate + * this logic elsewhere, or the security model will be broken by future + * API changes. Each phase must be individually optimized to pick up +@@ -232,15 +268,8 @@ + } + + access_status = ap_run_access_checker_ex(r); +- if (access_status == OK) { +- ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r, +- "request authorized without authentication by " +- "access_checker_ex hook: %s", r->uri); +- } +- else if (access_status != DECLINED) { +- return decl_die(access_status, "check access", r); +- } +- else { ++ if (access_status == DECLINED ++ || (access_status == OK && ap_run_force_authn(r) == OK)) { + if ((access_status = ap_run_check_user_id(r)) != OK) { + return decl_die(access_status, "check user", r); + } +@@ -258,6 +287,14 @@ + return decl_die(access_status, "check authorization", r); + } + } ++ else if (access_status == OK) { ++ ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r, ++ "request authorized without authentication by " ++ "access_checker_ex hook: %s", r->uri); ++ } ++ else { ++ return decl_die(access_status, "check access", r); ++ } + break; + case SATISFY_ANY: + if ((access_status = ap_run_access_checker(r)) == OK) { +@@ -269,15 +306,8 @@ + } + + access_status = ap_run_access_checker_ex(r); +- if (access_status == OK) { +- ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r, +- "request authorized without authentication by " +- "access_checker_ex hook: %s", r->uri); +- } +- else if (access_status != DECLINED) { +- return decl_die(access_status, "check access", r); +- } +- else { ++ if (access_status == DECLINED ++ || (access_status == OK && ap_run_force_authn(r) == OK)) { + if ((access_status = ap_run_check_user_id(r)) != OK) { + return decl_die(access_status, "check user", r); + } +@@ -295,6 +325,14 @@ + return decl_die(access_status, "check authorization", r); + } + } ++ else if (access_status == OK) { ++ ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r, ++ "request authorized without authentication by " ++ "access_checker_ex hook: %s", r->uri); ++ } ++ else { ++ return decl_die(access_status, "check access", r); ++ } + break; + } + } +Index: include/http_request.h +=================================================================== +--- a/include/http_request.h (revision 1684524) ++++ b/include/http_request.h (revision 1684525) +@@ -185,6 +185,8 @@ + * is required for the current request + * @param r The current request + * @return 1 if authentication is required, 0 otherwise ++ * @bug Behavior changed in 2.4.x refactoring, API no longer usable ++ * @deprecated @see ap_some_authn_required() + */ + AP_DECLARE(int) ap_some_auth_required(request_rec *r); + +@@ -539,6 +541,16 @@ + AP_DECLARE_HOOK(int,post_perdir_config,(request_rec *r)) + + /** ++ * This hook allows a module to force authn to be required when ++ * processing a request. ++ * This hook should be registered with ap_hook_force_authn(). ++ * @param r The current request ++ * @return OK (force authn), DECLINED (let later modules decide) ++ * @ingroup hooks ++ */ ++AP_DECLARE_HOOK(int,force_authn,(request_rec *r)) ++ ++/** + * This hook allows modules to handle/emulate the apr_stat() calls + * needed for directory walk. + * @param r The current request +@@ -584,6 +596,17 @@ + AP_DECLARE(apr_bucket *) ap_bucket_eor_create(apr_bucket_alloc_t *list, + request_rec *r); + ++/** ++ * Can be used within any handler to determine if any authentication ++ * is required for the current request. Note that if used with an ++ * access_checker hook, an access_checker_ex hook or an authz provider; the ++ * caller should take steps to avoid a loop since this function is ++ * implemented by calling these hooks. ++ * @param r The current request ++ * @return TRUE if authentication is required, FALSE otherwise ++ */ ++AP_DECLARE(int) ap_some_authn_required(request_rec *r); ++ + #ifdef __cplusplus + } + #endif diff --git a/SOURCES/httpd-2.4.6-CVE-2016-0736.patch b/SOURCES/httpd-2.4.6-CVE-2016-0736.patch new file mode 100644 index 0000000..cb80fa0 --- /dev/null +++ b/SOURCES/httpd-2.4.6-CVE-2016-0736.patch @@ -0,0 +1,325 @@ +diff --git a/modules/session/mod_session_crypto.c b/modules/session/mod_session_crypto.c +index 4d65bb8..9231a5e 100644 +--- a/modules/session/mod_session_crypto.c ++++ b/modules/session/mod_session_crypto.c +@@ -18,6 +18,7 @@ + #include "apu_version.h" + #include "apr_base64.h" /* for apr_base64_decode et al */ + #include "apr_lib.h" ++#include "apr_md5.h" + #include "apr_strings.h" + #include "http_log.h" + #include "http_core.h" +@@ -57,6 +58,146 @@ typedef struct { + int library_set; + } session_crypto_conf; + ++/* Wrappers around apr_siphash24() and apr_crypto_equals(), ++ * available in APU-1.6/APR-2.0 only. ++ */ ++#if APU_MAJOR_VERSION > 1 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 6) ++ ++#include "apr_siphash.h" ++ ++#define AP_SIPHASH_DSIZE APR_SIPHASH_DSIZE ++#define AP_SIPHASH_KSIZE APR_SIPHASH_KSIZE ++#define ap_siphash24_auth apr_siphash24_auth ++ ++#define ap_crypto_equals apr_crypto_equals ++ ++#else ++ ++#define AP_SIPHASH_DSIZE 8 ++#define AP_SIPHASH_KSIZE 16 ++ ++#define ROTL64(x, n) (((x) << (n)) | ((x) >> (64 - (n)))) ++ ++#define U8TO64_LE(p) \ ++ (((apr_uint64_t)((p)[0]) ) | \ ++ ((apr_uint64_t)((p)[1]) << 8) | \ ++ ((apr_uint64_t)((p)[2]) << 16) | \ ++ ((apr_uint64_t)((p)[3]) << 24) | \ ++ ((apr_uint64_t)((p)[4]) << 32) | \ ++ ((apr_uint64_t)((p)[5]) << 40) | \ ++ ((apr_uint64_t)((p)[6]) << 48) | \ ++ ((apr_uint64_t)((p)[7]) << 56)) ++ ++#define U64TO8_LE(p, v) \ ++do { \ ++ (p)[0] = (unsigned char)((v) ); \ ++ (p)[1] = (unsigned char)((v) >> 8); \ ++ (p)[2] = (unsigned char)((v) >> 16); \ ++ (p)[3] = (unsigned char)((v) >> 24); \ ++ (p)[4] = (unsigned char)((v) >> 32); \ ++ (p)[5] = (unsigned char)((v) >> 40); \ ++ (p)[6] = (unsigned char)((v) >> 48); \ ++ (p)[7] = (unsigned char)((v) >> 56); \ ++} while (0) ++ ++#define SIPROUND() \ ++do { \ ++ v0 += v1; v1=ROTL64(v1,13); v1 ^= v0; v0=ROTL64(v0,32); \ ++ v2 += v3; v3=ROTL64(v3,16); v3 ^= v2; \ ++ v0 += v3; v3=ROTL64(v3,21); v3 ^= v0; \ ++ v2 += v1; v1=ROTL64(v1,17); v1 ^= v2; v2=ROTL64(v2,32); \ ++} while(0) ++ ++static apr_uint64_t ap_siphash24(const void *src, apr_size_t len, ++ const unsigned char key[AP_SIPHASH_KSIZE]) ++{ ++ const unsigned char *ptr, *end; ++ apr_uint64_t v0, v1, v2, v3, m; ++ apr_uint64_t k0, k1; ++ unsigned int rem; ++ ++ k0 = U8TO64_LE(key + 0); ++ k1 = U8TO64_LE(key + 8); ++ v3 = k1 ^ (apr_uint64_t)0x7465646279746573ULL; ++ v2 = k0 ^ (apr_uint64_t)0x6c7967656e657261ULL; ++ v1 = k1 ^ (apr_uint64_t)0x646f72616e646f6dULL; ++ v0 = k0 ^ (apr_uint64_t)0x736f6d6570736575ULL; ++ ++ rem = (unsigned int)(len & 0x7); ++ for (ptr = src, end = ptr + len - rem; ptr < end; ptr += 8) { ++ m = U8TO64_LE(ptr); ++ v3 ^= m; ++ SIPROUND(); ++ SIPROUND(); ++ v0 ^= m; ++ } ++ m = (apr_uint64_t)(len & 0xff) << 56; ++ switch (rem) { ++ case 7: m |= (apr_uint64_t)ptr[6] << 48; ++ case 6: m |= (apr_uint64_t)ptr[5] << 40; ++ case 5: m |= (apr_uint64_t)ptr[4] << 32; ++ case 4: m |= (apr_uint64_t)ptr[3] << 24; ++ case 3: m |= (apr_uint64_t)ptr[2] << 16; ++ case 2: m |= (apr_uint64_t)ptr[1] << 8; ++ case 1: m |= (apr_uint64_t)ptr[0]; ++ case 0: break; ++ } ++ v3 ^= m; ++ SIPROUND(); ++ SIPROUND(); ++ v0 ^= m; ++ ++ v2 ^= 0xff; ++ SIPROUND(); ++ SIPROUND(); ++ SIPROUND(); ++ SIPROUND(); ++ ++ return v0 ^ v1 ^ v2 ^ v3; ++} ++ ++static void ap_siphash24_auth(unsigned char out[AP_SIPHASH_DSIZE], ++ const void *src, apr_size_t len, ++ const unsigned char key[AP_SIPHASH_KSIZE]) ++{ ++ apr_uint64_t h; ++ h = ap_siphash24(src, len, key); ++ U64TO8_LE(out, h); ++} ++ ++static int ap_crypto_equals(const void *buf1, const void *buf2, ++ apr_size_t size) ++{ ++ const unsigned char *p1 = buf1; ++ const unsigned char *p2 = buf2; ++ unsigned char diff = 0; ++ apr_size_t i; ++ ++ for (i = 0; i < size; ++i) { ++ diff |= p1[i] ^ p2[i]; ++ } ++ ++ return 1 & ((diff - 1) >> 8); ++} ++ ++#endif ++ ++static void compute_auth(const void *src, apr_size_t len, ++ const char *passphrase, apr_size_t passlen, ++ unsigned char auth[AP_SIPHASH_DSIZE]) ++{ ++ unsigned char key[APR_MD5_DIGESTSIZE]; ++ ++ /* XXX: if we had a way to get the raw bytes from an apr_crypto_key_t ++ * we could use them directly (not available in APR-1.5.x). ++ * MD5 is 128bit too, so use it to get a suitable siphash key ++ * from the passphrase. ++ */ ++ apr_md5(key, passphrase, passlen); ++ ++ ap_siphash24_auth(auth, src, len, key); ++} ++ + /** + * Initialise the encryption as per the current config. + * +@@ -128,21 +269,14 @@ static apr_status_t encrypt_string(request_rec * r, const apr_crypto_t *f, + apr_crypto_block_t *block = NULL; + unsigned char *encrypt = NULL; + unsigned char *combined = NULL; +- apr_size_t encryptlen, tlen; ++ apr_size_t encryptlen, tlen, combinedlen; + char *base64; + apr_size_t blockSize = 0; + const unsigned char *iv = NULL; + apr_uuid_t salt; + apr_crypto_block_key_type_e *cipher; + const char *passphrase; +- +- /* by default, return an empty string */ +- *out = ""; +- +- /* don't attempt to encrypt an empty string, trying to do so causes a segfault */ +- if (!in || !*in) { +- return APR_SUCCESS; +- } ++ apr_size_t passlen; + + /* use a uuid as a salt value, and prepend it to our result */ + apr_uuid_get(&salt); +@@ -152,9 +286,9 @@ static apr_status_t encrypt_string(request_rec * r, const apr_crypto_t *f, + } + + /* encrypt using the first passphrase in the list */ +- passphrase = APR_ARRAY_IDX(dconf->passphrases, 0, char *); +- res = apr_crypto_passphrase(&key, &ivSize, passphrase, +- strlen(passphrase), ++ passphrase = APR_ARRAY_IDX(dconf->passphrases, 0, const char *); ++ passlen = strlen(passphrase); ++ res = apr_crypto_passphrase(&key, &ivSize, passphrase, passlen, + (unsigned char *) (&salt), sizeof(apr_uuid_t), + *cipher, APR_MODE_CBC, 1, 4096, f, r->pool); + if (APR_STATUS_IS_ENOKEY(res)) { +@@ -183,8 +317,9 @@ static apr_status_t encrypt_string(request_rec * r, const apr_crypto_t *f, + } + + /* encrypt the given string */ +- res = apr_crypto_block_encrypt(&encrypt, &encryptlen, (unsigned char *)in, +- strlen(in), block); ++ res = apr_crypto_block_encrypt(&encrypt, &encryptlen, ++ (const unsigned char *)in, strlen(in), ++ block); + if (APR_SUCCESS != res) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, res, r, APLOGNO(01830) + "apr_crypto_block_encrypt failed"); +@@ -198,18 +333,20 @@ static apr_status_t encrypt_string(request_rec * r, const apr_crypto_t *f, + } + encryptlen += tlen; + +- /* prepend the salt and the iv to the result */ +- combined = apr_palloc(r->pool, ivSize + encryptlen + sizeof(apr_uuid_t)); +- memcpy(combined, &salt, sizeof(apr_uuid_t)); +- memcpy(combined + sizeof(apr_uuid_t), iv, ivSize); +- memcpy(combined + sizeof(apr_uuid_t) + ivSize, encrypt, encryptlen); +- +- /* base64 encode the result */ +- base64 = apr_palloc(r->pool, apr_base64_encode_len(ivSize + encryptlen + +- sizeof(apr_uuid_t) + 1) +- * sizeof(char)); +- apr_base64_encode(base64, (const char *) combined, +- ivSize + encryptlen + sizeof(apr_uuid_t)); ++ /* prepend the salt and the iv to the result (keep room for the MAC) */ ++ combinedlen = AP_SIPHASH_DSIZE + sizeof(apr_uuid_t) + ivSize + encryptlen; ++ combined = apr_palloc(r->pool, combinedlen); ++ memcpy(combined + AP_SIPHASH_DSIZE, &salt, sizeof(apr_uuid_t)); ++ memcpy(combined + AP_SIPHASH_DSIZE + sizeof(apr_uuid_t), iv, ivSize); ++ memcpy(combined + AP_SIPHASH_DSIZE + sizeof(apr_uuid_t) + ivSize, ++ encrypt, encryptlen); ++ /* authenticate the whole salt+IV+ciphertext with a leading MAC */ ++ compute_auth(combined + AP_SIPHASH_DSIZE, combinedlen - AP_SIPHASH_DSIZE, ++ passphrase, passlen, combined); ++ ++ /* base64 encode the result (APR handles the trailing '\0') */ ++ base64 = apr_palloc(r->pool, apr_base64_encode_len(combinedlen)); ++ apr_base64_encode(base64, (const char *) combined, combinedlen); + *out = base64; + + return res; +@@ -234,6 +371,7 @@ static apr_status_t decrypt_string(request_rec * r, const apr_crypto_t *f, + char *decoded; + apr_size_t blockSize = 0; + apr_crypto_block_key_type_e *cipher; ++ unsigned char auth[AP_SIPHASH_DSIZE]; + int i = 0; + + /* strip base64 from the string */ +@@ -241,6 +379,13 @@ static apr_status_t decrypt_string(request_rec * r, const apr_crypto_t *f, + decodedlen = apr_base64_decode(decoded, in); + decoded[decodedlen] = '\0'; + ++ /* sanity check - decoded too short? */ ++ if (decodedlen < (AP_SIPHASH_DSIZE + sizeof(apr_uuid_t))) { ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO() ++ "too short to decrypt, aborting"); ++ return APR_ECRYPT; ++ } ++ + res = crypt_init(r, f, &cipher, dconf); + if (res != APR_SUCCESS) { + return res; +@@ -249,14 +394,25 @@ static apr_status_t decrypt_string(request_rec * r, const apr_crypto_t *f, + /* try each passphrase in turn */ + for (; i < dconf->passphrases->nelts; i++) { + const char *passphrase = APR_ARRAY_IDX(dconf->passphrases, i, char *); +- apr_size_t len = decodedlen; +- char *slider = decoded; ++ apr_size_t passlen = strlen(passphrase); ++ apr_size_t len = decodedlen - AP_SIPHASH_DSIZE; ++ unsigned char *slider = (unsigned char *)decoded + AP_SIPHASH_DSIZE; ++ ++ /* Verify authentication of the whole salt+IV+ciphertext by computing ++ * the MAC and comparing it (timing safe) with the one in the payload. ++ */ ++ compute_auth(slider, len, passphrase, passlen, auth); ++ if (!ap_crypto_equals(auth, decoded, AP_SIPHASH_DSIZE)) { ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, res, r, APLOGNO() ++ "auth does not match, skipping"); ++ continue; ++ } + + /* encrypt using the first passphrase in the list */ +- res = apr_crypto_passphrase(&key, &ivSize, passphrase, +- strlen(passphrase), +- (unsigned char *)decoded, sizeof(apr_uuid_t), +- *cipher, APR_MODE_CBC, 1, 4096, f, r->pool); ++ res = apr_crypto_passphrase(&key, &ivSize, passphrase, passlen, ++ slider, sizeof(apr_uuid_t), ++ *cipher, APR_MODE_CBC, 1, 4096, ++ f, r->pool); + if (APR_STATUS_IS_ENOKEY(res)) { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, res, r, APLOGNO(01832) + "the passphrase '%s' was empty", passphrase); +@@ -279,7 +435,7 @@ static apr_status_t decrypt_string(request_rec * r, const apr_crypto_t *f, + } + + /* sanity check - decoded too short? */ +- if (decodedlen < (sizeof(apr_uuid_t) + ivSize)) { ++ if (len < (sizeof(apr_uuid_t) + ivSize)) { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(01836) + "too short to decrypt, skipping"); + res = APR_ECRYPT; +@@ -290,8 +446,8 @@ static apr_status_t decrypt_string(request_rec * r, const apr_crypto_t *f, + slider += sizeof(apr_uuid_t); + len -= sizeof(apr_uuid_t); + +- res = apr_crypto_block_decrypt_init(&block, &blockSize, (unsigned char *)slider, key, +- r->pool); ++ res = apr_crypto_block_decrypt_init(&block, &blockSize, slider, key, ++ r->pool); + if (APR_SUCCESS != res) { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, res, r, APLOGNO(01837) + "apr_crypto_block_decrypt_init failed"); +@@ -304,7 +460,7 @@ static apr_status_t decrypt_string(request_rec * r, const apr_crypto_t *f, + + /* decrypt the given string */ + res = apr_crypto_block_decrypt(&decrypted, &decryptedlen, +- (unsigned char *)slider, len, block); ++ slider, len, block); + if (res) { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, res, r, APLOGNO(01838) + "apr_crypto_block_decrypt failed"); + diff --git a/SOURCES/httpd-2.4.6-CVE-2016-2161.patch b/SOURCES/httpd-2.4.6-CVE-2016-2161.patch new file mode 100644 index 0000000..d45c2d9 --- /dev/null +++ b/SOURCES/httpd-2.4.6-CVE-2016-2161.patch @@ -0,0 +1,121 @@ +diff --git a/modules/aaa/mod_auth_digest.c b/modules/aaa/mod_auth_digest.c +index 44b5fc8..6a50ba7 100644 +--- a/modules/aaa/mod_auth_digest.c ++++ b/modules/aaa/mod_auth_digest.c +@@ -261,6 +261,26 @@ static void log_error_and_cleanup(char *msg, apr_status_t sts, server_rec *s) + cleanup_tables(NULL); + } + ++/* RMM helper functions that behave like single-step malloc/free. */ ++ ++static void *rmm_malloc(apr_rmm_t *rmm, apr_size_t size) ++{ ++ apr_rmm_off_t offset = apr_rmm_malloc(rmm, size); ++ ++ if (!offset) { ++ return NULL; ++ } ++ ++ return apr_rmm_addr_get(rmm, offset); ++} ++ ++static apr_status_t rmm_free(apr_rmm_t *rmm, void *alloc) ++{ ++ apr_rmm_off_t offset = apr_rmm_offset_get(rmm, alloc); ++ ++ return apr_rmm_free(rmm, offset); ++} ++ + #if APR_HAS_SHARED_MEMORY + + static int initialize_tables(server_rec *s, apr_pool_t *ctx) +@@ -299,8 +319,8 @@ static int initialize_tables(server_rec *s, apr_pool_t *ctx) + return !OK; + } + +- client_list = apr_rmm_addr_get(client_rmm, apr_rmm_malloc(client_rmm, sizeof(*client_list) + +- sizeof(client_entry*)*num_buckets)); ++ client_list = rmm_malloc(client_rmm, sizeof(*client_list) + ++ sizeof(client_entry *) * num_buckets); + if (!client_list) { + log_error_and_cleanup("failed to allocate shared memory", -1, s); + return !OK; +@@ -322,7 +342,7 @@ static int initialize_tables(server_rec *s, apr_pool_t *ctx) + + /* setup opaque */ + +- opaque_cntr = apr_rmm_addr_get(client_rmm, apr_rmm_malloc(client_rmm, sizeof(*opaque_cntr))); ++ opaque_cntr = rmm_malloc(client_rmm, sizeof(*opaque_cntr)); + if (opaque_cntr == NULL) { + log_error_and_cleanup("failed to allocate shared memory", -1, s); + return !OK; +@@ -339,7 +359,7 @@ static int initialize_tables(server_rec *s, apr_pool_t *ctx) + + /* setup one-time-nonce counter */ + +- otn_counter = apr_rmm_addr_get(client_rmm, apr_rmm_malloc(client_rmm, sizeof(*otn_counter))); ++ otn_counter = rmm_malloc(client_rmm, sizeof(*otn_counter)); + if (otn_counter == NULL) { + log_error_and_cleanup("failed to allocate shared memory", -1, s); + return !OK; +@@ -779,7 +799,7 @@ static client_entry *get_client(unsigned long key, const request_rec *r) + * last entry in each bucket and updates the counters. Returns the + * number of removed entries. + */ +-static long gc(void) ++static long gc(server_rec *s) + { + client_entry *entry, *prev; + unsigned long num_removed = 0, idx; +@@ -789,6 +809,12 @@ static long gc(void) + for (idx = 0; idx < client_list->tbl_len; idx++) { + entry = client_list->table[idx]; + prev = NULL; ++ ++ if (!entry) { ++ /* This bucket is empty. */ ++ continue; ++ } ++ + while (entry->next) { /* find last entry */ + prev = entry; + entry = entry->next; +@@ -800,8 +826,16 @@ static long gc(void) + client_list->table[idx] = NULL; + } + if (entry) { /* remove entry */ +- apr_rmm_free(client_rmm, apr_rmm_offset_get(client_rmm, entry)); ++ apr_status_t err; ++ ++ err = rmm_free(client_rmm, entry); + num_removed++; ++ ++ if (err) { ++ /* Nothing we can really do but log... */ ++ ap_log_error(APLOG_MARK, APLOG_ERR, err, s, APLOGNO() ++ "Failed to free auth_digest client allocation"); ++ } + } + } + +@@ -835,16 +869,16 @@ static client_entry *add_client(unsigned long key, client_entry *info, + + /* try to allocate a new entry */ + +- entry = apr_rmm_addr_get(client_rmm, apr_rmm_malloc(client_rmm, sizeof(client_entry))); ++ entry = rmm_malloc(client_rmm, sizeof(client_entry)); + if (!entry) { +- long num_removed = gc(); ++ long num_removed = gc(s); + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(01766) + "gc'd %ld client entries. Total new clients: " + "%ld; Total removed clients: %ld; Total renewed clients: " + "%ld", num_removed, + client_list->num_created - client_list->num_renewed, + client_list->num_removed, client_list->num_renewed); +- entry = apr_rmm_addr_get(client_rmm, apr_rmm_malloc(client_rmm, sizeof(client_entry))); ++ entry = rmm_malloc(client_rmm, sizeof(client_entry)); + if (!entry) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01767) + "unable to allocate new auth_digest client"); + diff --git a/SOURCES/httpd-2.4.6-CVE-2016-5387.patch b/SOURCES/httpd-2.4.6-CVE-2016-5387.patch new file mode 100644 index 0000000..9f22044 --- /dev/null +++ b/SOURCES/httpd-2.4.6-CVE-2016-5387.patch @@ -0,0 +1,16 @@ + +https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2016-5387 + +--- httpd-2.4.6/server/util_script.c.cve5387 ++++ httpd-2.4.6/server/util_script.c +@@ -190,6 +190,10 @@ + continue; + } + #endif ++ else if (!strcasecmp(hdrs[i].key, "Proxy")) { ++ /* Don't pass through HTTP_PROXY */ ++ continue; ++ } + else + add_unless_null(e, http2env(r, hdrs[i].key), hdrs[i].val); + } diff --git a/SOURCES/httpd-2.4.6-CVE-2016-8743.patch b/SOURCES/httpd-2.4.6-CVE-2016-8743.patch new file mode 100644 index 0000000..5a6fd58 --- /dev/null +++ b/SOURCES/httpd-2.4.6-CVE-2016-8743.patch @@ -0,0 +1,2124 @@ + +https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2016-8743 + +diff -uap httpd-2.4.6/docs/manual/mod/core.html.en.cve8743 httpd-2.4.6/docs/manual/mod/core.html.en +--- httpd-2.4.6/docs/manual/mod/core.html.en.cve8743 ++++ httpd-2.4.6/docs/manual/mod/core.html.en +@@ -67,6 +67,7 @@ +
  • ForceType
  • +
  • GprofDir
  • +
  • HostnameLookups
  • ++
  • HttpProtocolOptions
  • +
  • <If>
  • +
  • <IfDefine>
  • +
  • <IfModule>
  • +@@ -93,6 +94,7 @@ +
  • NameVirtualHost
  • +
  • Options
  • +
  • Protocol
  • ++
  • RegisterHttpMethod
  • +
  • RLimitCPU
  • +
  • RLimitMEM
  • +
  • RLimitNPROC
  • +@@ -1918,6 +1920,74 @@ + +
    +
    top
    ++

    HttpProtocolOptions Directive

    ++ ++ ++ ++ ++ ++ ++ ++ ++
    Description:Modify restrictions on HTTP Request Messages
    Syntax:HttpProtocolOptions [Strict|Unsafe] [RegisteredMethods|LenientMethods] ++ [Allow0.9|Require1.0]
    Default:HttpProtocolOptions Strict LenientMethods Allow0.9
    Context:server config, virtual host
    Status:Core
    Module:core
    Compatibility:2.2.32 or 2.4.24 and later
    ++

    This directive changes the rules applied to the HTTP Request Line ++ (RFC 7230 §3.1.1) and the HTTP Request Header Fields ++ (RFC 7230 §3.2), which are now applied by default or using ++ the Strict option. Due to legacy modules, applications or ++ custom user-agents which must be deperecated the Unsafe ++ option has been added to revert to the legacy behaviors. These rules ++ are applied prior to request processing, so must be configured at the ++ global or default (first) matching virtual host section, by IP/port ++ interface (and not by name) to be honored.

    ++ ++

    Prior to the introduction of this directive, the Apache HTTP Server ++ request message parsers were tolerant of a number of forms of input ++ which did not conform to the protocol. ++ RFC 7230 §9.4 Request Splitting and ++ §9.5 Response Smuggling call out only two of the potential ++ risks of accepting non-conformant request messages, while ++ RFC 7230 §3.5 "Message Parsing Robustness" identify the ++ risks of accepting obscure whitespace and request message formatting. ++ As of the introduction of this directive, all grammer rules of the ++ specification are enforced in the default Strict operating ++ mode, and the strict whitespace suggested by section 3.5 is enforced ++ and cannot be relaxed.

    ++ ++

    Users are strongly cautioned against toggling the Unsafe ++ mode of operation, particularly on outward-facing, publicly accessible ++ server deployments. If an interface is required for faulty monitoring ++ or other custom service consumers running on an intranet, users should ++ toggle the Unsafe option only on a specific virtual host configured ++ to service their internal private network.

    ++ ++

    Reviewing the messages logged to the ErrorLog, ++ configured with LogLevel debug level, ++ can help identify such faulty requests along with their origin. ++ Users should pay particular attention to the 400 responses in the access ++ log for invalid requests which were unexpectedly rejected.

    ++ ++

    RFC 7231 §4.1 "Request Methods" "Overview" requires that ++ origin servers shall respond with an error when an unsupported method ++ is encountered in the request line. This already happens when the ++ LenientMethods option is used, but administrators may wish ++ to toggle the RegisteredMethods option and register any ++ non-standard methods using the RegisterHttpMethod ++ directive, particularly if the Unsafe option has been toggled. ++ The RegisteredMethods option should not ++ be toggled for forward proxy hosts, as the methods supported by the ++ origin servers are unknown to the proxy server.

    ++ ++

    RFC 2616 §19.6 "Compatibility With Previous Versions" had ++ encouraged HTTP servers to support legacy HTTP/0.9 requests. RFC 7230 ++ superceeds this with "The expectation to support HTTP/0.9 requests has ++ been removed" and offers additional comments in ++ RFC 7230 Appendix A. The Require1.0 option allows ++ the user to remove support of the default Allow0.9 option's ++ behavior.

    ++ ++
    ++
    top
    +

    <If> Directive

    + +
    Description:Contains directives that apply only if a condition is +@@ -3541,6 +3611,23 @@ + + +
    top
    ++

    RegisterHttpMethod Directive

    ++ ++ ++ ++ ++ ++ ++
    Description:Register non-standard HTTP methods
    Syntax:RegisterHttpMethod method [method [...]]
    Context:server config
    Status:Core
    Module:core
    ++

    HTTP Methods that are not conforming to the relvant RFCs are normally ++rejected by request processing in Apache HTTPD. To avoid this, modules ++can register non-standard HTTP methods they support. ++The RegisterHttpMethod allows to register such ++methods manually. This can be useful for if such methods are forwared ++for external processing, e.g. to a CGI script.

    ++ ++
    ++
    top
    +

    RLimitCPU Directive

    + +
    Description:Limits the CPU consumption of processes launched +diff -uap httpd-2.4.6/include/http_core.h.cve8743 httpd-2.4.6/include/http_core.h +--- httpd-2.4.6/include/http_core.h.cve8743 ++++ httpd-2.4.6/include/http_core.h +@@ -668,6 +668,21 @@ + #define AP_MERGE_TRAILERS_DISABLE 2 + int merge_trailers; + ++#define AP_HTTP09_UNSET 0 ++#define AP_HTTP09_ENABLE 1 ++#define AP_HTTP09_DISABLE 2 ++ char http09_enable; ++ ++#define AP_HTTP_CONFORMANCE_UNSET 0 ++#define AP_HTTP_CONFORMANCE_UNSAFE 1 ++#define AP_HTTP_CONFORMANCE_STRICT 2 ++ char http_conformance; ++ ++#define AP_HTTP_METHODS_UNSET 0 ++#define AP_HTTP_METHODS_LENIENT 1 ++#define AP_HTTP_METHODS_REGISTERED 2 ++ char http_methods; ++ + } core_server_config; + + /* for AddOutputFiltersByType in core.c */ +diff -uap httpd-2.4.6/include/httpd.h.cve8743 httpd-2.4.6/include/httpd.h +--- httpd-2.4.6/include/httpd.h.cve8743 ++++ httpd-2.4.6/include/httpd.h +@@ -1584,6 +1584,28 @@ + */ + AP_DECLARE(int) ap_unescape_url(char *url); + ++/* Scan a string for field content chars, as defined by RFC7230 section 3.2 ++ * including VCHAR/obs-text, as well as HT and SP ++ * @param ptr The string to scan ++ * @return A pointer to the first (non-HT) ASCII ctrl character. ++ * @note lws and trailing whitespace are scanned, the caller is responsible ++ * for trimming leading and trailing whitespace ++ */ ++AP_DECLARE(const char *) ap_scan_http_field_content(const char *ptr); ++ ++/* Scan a string for token characters, as defined by RFC7230 section 3.2.6 ++ * @param ptr The string to scan ++ * @return A pointer to the first non-token character. ++ */ ++AP_DECLARE(const char *) ap_scan_http_token(const char *ptr); ++ ++/* Scan a string for visible ASCII (0x21-0x7E) or obstext (0x80+) ++ * and return a pointer to the first SP/CTL/NUL character encountered. ++ * @param ptr The string to scan ++ * @return A pointer to the first SP/CTL character. ++ */ ++AP_DECLARE(const char *) ap_scan_vchar_obstext(const char *ptr); ++ + /** + * Unescape a URL, but leaving %2f (slashes) escaped + * @param url The url to unescape +diff -uap httpd-2.4.6/include/http_protocol.h.cve8743 httpd-2.4.6/include/http_protocol.h +--- httpd-2.4.6/include/http_protocol.h.cve8743 ++++ httpd-2.4.6/include/http_protocol.h +@@ -582,17 +582,22 @@ + */ + AP_CORE_DECLARE(void) ap_parse_uri(request_rec *r, const char *uri); + ++#define AP_GETLINE_FOLD 1 /* Whether to merge continuation lines */ ++#define AP_GETLINE_CRLF 2 /*Whether line ends must be in the form CR LF */ ++ + /** + * Get the next line of input for the request + * @param s The buffer into which to read the line + * @param n The size of the buffer + * @param r The request +- * @param fold Whether to merge continuation lines ++ * @param flags Bit flag of multiple parsing options ++ * AP_GETLINE_FOLD Whether to merge continuation lines ++ * AP_GETLINE_CRLF Whether line ends must be in the form CR LF + * @return The length of the line, if successful + * n, if the line is too big to fit in the buffer + * -1 for miscellaneous errors + */ +-AP_DECLARE(int) ap_getline(char *s, int n, request_rec *r, int fold); ++AP_DECLARE(int) ap_getline(char *s, int n, request_rec *r, int flags); + + /** + * Get the next line of input for the request +@@ -610,7 +615,9 @@ + * @param n The size of the buffer + * @param read The length of the line. + * @param r The request +- * @param fold Whether to merge continuation lines ++ * @param flags Bit flag of multiple parsing options ++ * AP_GETLINE_FOLD Whether to merge continuation lines ++ * AP_GETLINE_CRLF Whether line ends must be in the form CR LF + * @param bb Working brigade to use when reading buckets + * @return APR_SUCCESS, if successful + * APR_ENOSPC, if the line is too big to fit in the buffer +@@ -619,7 +626,7 @@ + #if APR_CHARSET_EBCDIC + AP_DECLARE(apr_status_t) ap_rgetline(char **s, apr_size_t n, + apr_size_t *read, +- request_rec *r, int fold, ++ request_rec *r, int flags, + apr_bucket_brigade *bb); + #else /* ASCII box */ + #define ap_rgetline(s, n, read, r, fold, bb) \ +@@ -629,7 +636,7 @@ + /** @see ap_rgetline */ + AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, + apr_size_t *read, +- request_rec *r, int fold, ++ request_rec *r, int flags, + apr_bucket_brigade *bb); + + /** +diff -uap httpd-2.4.6/modules/http/http_filters.c.cve8743 httpd-2.4.6/modules/http/http_filters.c +--- httpd-2.4.6/modules/http/http_filters.c.cve8743 ++++ httpd-2.4.6/modules/http/http_filters.c +@@ -126,14 +126,15 @@ + + /** + * Parse a chunk line with optional extension, detect overflow. +- * There are two error cases: +- * 1) If the conversion would require too many bits, APR_EGENERAL is returned. +- * 2) If the conversion used the correct number of bits, but an overflow ++ * There are several error cases: ++ * 1) If the chunk link is misformatted, APR_EINVAL is returned. ++ * 2) If the conversion would require too many bits, APR_EGENERAL is returned. ++ * 3) If the conversion used the correct number of bits, but an overflow + * caused only the sign bit to flip, then APR_ENOSPC is returned. +- * In general, any negative number can be considered an overflow error. ++ * A negative chunk length always indicates an overflow error. + */ + static apr_status_t parse_chunk_size(http_ctx_t *ctx, const char *buffer, +- apr_size_t len, int linelimit) ++ apr_size_t len, int linelimit, int strict) + { + apr_size_t i = 0; + +@@ -146,6 +147,12 @@ + if (ctx->state == BODY_CHUNK_END + || ctx->state == BODY_CHUNK_END_LF) { + if (c == LF) { ++ if (strict && (ctx->state != BODY_CHUNK_END_LF)) { ++ /* ++ * CR missing before LF. ++ */ ++ return APR_EINVAL; ++ } + ctx->state = BODY_CHUNK; + } + else if (c == CR && ctx->state == BODY_CHUNK_END) { +@@ -153,7 +160,7 @@ + } + else { + /* +- * LF expected. ++ * CRLF expected. + */ + return APR_EINVAL; + } +@@ -180,6 +187,12 @@ + } + + if (c == LF) { ++ if (strict && (ctx->state != BODY_CHUNK_LF)) { ++ /* ++ * CR missing before LF. ++ */ ++ return APR_EINVAL; ++ } + if (ctx->remaining) { + ctx->state = BODY_CHUNK_DATA; + } +@@ -201,14 +214,17 @@ + } + else if (ctx->state == BODY_CHUNK_EXT) { + /* +- * Control chars (but tabs) are invalid. ++ * Control chars (excluding tabs) are invalid. ++ * TODO: more precisely limit input + */ + if (c != '\t' && apr_iscntrl(c)) { + return APR_EINVAL; + } + } + else if (c == ' ' || c == '\t') { +- /* Be lenient up to 10 BWS (term from rfc7230 - 3.2.3). ++ /* Be lenient up to 10 implied *LWS, a legacy of RFC 2616, ++ * and noted as errata to RFC7230; ++ * https://www.rfc-editor.org/errata_search.php?rfc=7230&eid=4667 + */ + ctx->state = BODY_CHUNK_CR; + if (++ctx->chunk_bws > 10) { +@@ -324,7 +340,10 @@ + ap_input_mode_t mode, apr_read_type_e block, + apr_off_t readbytes) + { +- core_server_config *conf; ++ core_server_config *conf = ++ (core_server_config *) ap_get_module_config(f->r->server->module_config, ++ &core_module); ++ int strict = (conf->http_conformance != AP_HTTP_CONFORMANCE_UNSAFE); + apr_bucket *e; + http_ctx_t *ctx = f->ctx; + apr_status_t rv; +@@ -332,9 +351,6 @@ + apr_bucket_brigade *bb; + int again; + +- conf = (core_server_config *) +- ap_get_module_config(f->r->server->module_config, &core_module); +- + /* just get out of the way of things we don't want. */ + if (mode != AP_MODE_READBYTES && mode != AP_MODE_GETLINE) { + return ap_get_brigade(f->next, b, mode, block, readbytes); +@@ -526,7 +542,7 @@ + if (rv == APR_SUCCESS) { + parsing = 1; + rv = parse_chunk_size(ctx, buffer, len, +- f->r->server->limit_req_fieldsize); ++ f->r->server->limit_req_fieldsize, strict); + } + if (rv != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_INFO, rv, f->r, APLOGNO(01590) +@@ -668,14 +684,121 @@ + return APR_SUCCESS; + } + ++struct check_header_ctx { ++ request_rec *r; ++ int strict; ++}; ++ ++/* check a single header, to be used with apr_table_do() */ ++static int check_header(struct check_header_ctx *ctx, ++ const char *name, const char **val) ++{ ++ const char *pos, *end; ++ char *dst = NULL; ++ ++ if (name[0] == '\0') { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, ctx->r, APLOGNO(02428) ++ "Empty response header name, aborting request"); ++ return 0; ++ } ++ ++ if (ctx->strict) { ++ end = ap_scan_http_token(name); ++ } ++ else { ++ end = ap_scan_vchar_obstext(name); ++ } ++ if (*end) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, ctx->r, APLOGNO(02429) ++ "Response header name '%s' contains invalid " ++ "characters, aborting request", ++ name); ++ return 0; ++ } ++ ++ for (pos = *val; *pos; pos = end) { ++ end = ap_scan_http_field_content(pos); ++ if (*end) { ++ if (end[0] != CR || end[1] != LF || (end[2] != ' ' && ++ end[2] != '\t')) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, ctx->r, APLOGNO(02430) ++ "Response header '%s' value of '%s' contains " ++ "invalid characters, aborting request", ++ name, pos); ++ return 0; ++ } ++ if (!dst) { ++ *val = dst = apr_palloc(ctx->r->pool, strlen(*val) + 1); ++ } ++ } ++ if (dst) { ++ memcpy(dst, pos, end - pos); ++ dst += end - pos; ++ if (*end) { ++ /* skip folding and replace with a single space */ ++ end += 3 + strspn(end + 3, "\t "); ++ *dst++ = ' '; ++ } ++ } ++ } ++ if (dst) { ++ *dst = '\0'; ++ } ++ return 1; ++} ++ ++static int check_headers_table(apr_table_t *t, struct check_header_ctx *ctx) ++{ ++ const apr_array_header_t *headers = apr_table_elts(t); ++ apr_table_entry_t *header; ++ int i; ++ ++ for (i = 0; i < headers->nelts; ++i) { ++ header = &APR_ARRAY_IDX(headers, i, apr_table_entry_t); ++ if (!header->key) { ++ continue; ++ } ++ if (!check_header(ctx, header->key, (const char **)&header->val)) { ++ return 0; ++ } ++ } ++ return 1; ++} ++ ++/** ++ * Check headers for HTTP conformance ++ * @return 1 if ok, 0 if bad ++ */ ++static APR_INLINE int check_headers(request_rec *r) ++{ ++ struct check_header_ctx ctx; ++ core_server_config *conf = ++ ap_get_core_module_config(r->server->module_config); ++ ++ ctx.r = r; ++ ctx.strict = (conf->http_conformance != AP_HTTP_CONFORMANCE_UNSAFE); ++ return check_headers_table(r->headers_out, &ctx) && ++ check_headers_table(r->err_headers_out, &ctx); ++} ++ ++static int check_headers_recursion(request_rec *r) ++{ ++ void *check = NULL; ++ apr_pool_userdata_get(&check, "check_headers_recursion", r->pool); ++ if (check) { ++ return 1; ++ } ++ apr_pool_userdata_setn("true", "check_headers_recursion", NULL, r->pool); ++ return 0; ++} ++ + typedef struct header_struct { + apr_pool_t *pool; + apr_bucket_brigade *bb; + } header_struct; + + /* Send a single HTTP header field to the client. Note that this function +- * is used in calls to table_do(), so their interfaces are co-dependent. +- * In other words, don't change this one without checking table_do in alloc.c. ++ * is used in calls to apr_table_do(), so don't change its interface. + * It returns true unless there was a write error of some kind. + */ + static int form_header_field(header_struct *h, +@@ -1160,6 +1283,7 @@ + + typedef struct header_filter_ctx { + int headers_sent; ++ int headers_error; + } header_filter_ctx; + + AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f, +@@ -1175,19 +1299,23 @@ + header_filter_ctx *ctx = f->ctx; + const char *ctype; + ap_bucket_error *eb = NULL; ++ apr_bucket *eos = NULL; + + AP_DEBUG_ASSERT(!r->main); + +- if (r->header_only) { +- if (!ctx) { +- ctx = f->ctx = apr_pcalloc(r->pool, sizeof(header_filter_ctx)); +- } +- else if (ctx->headers_sent) { ++ if (!ctx) { ++ ctx = f->ctx = apr_pcalloc(r->pool, sizeof(header_filter_ctx)); ++ } ++ if (ctx->headers_sent) { ++ /* Eat body if response must not have one. */ ++ if (r->header_only || r->status == HTTP_NO_CONTENT) { + apr_brigade_cleanup(b); +- return OK; ++ return APR_SUCCESS; + } + } +- ++ else if (!ctx->headers_error && !check_headers(r)) { ++ ctx->headers_error = 1; ++ } + for (e = APR_BRIGADE_FIRST(b); + e != APR_BRIGADE_SENTINEL(b); + e = APR_BUCKET_NEXT(e)) +@@ -1204,10 +1332,44 @@ + ap_remove_output_filter(f); + return ap_pass_brigade(f->next, b); + } ++ if (ctx->headers_error && APR_BUCKET_IS_EOS(e)) { ++ eos = e; ++ } + } +- if (eb) { +- int status; ++ if (ctx->headers_error) { ++ if (!eos) { ++ /* Eat body until EOS */ ++ apr_brigade_cleanup(b); ++ return APR_SUCCESS; ++ } + ++ /* We may come back here from ap_die() below, ++ * so clear anything from this response. ++ */ ++ ctx->headers_error = 0; ++ apr_table_clear(r->headers_out); ++ apr_table_clear(r->err_headers_out); ++ ++ /* Don't recall ap_die() if we come back here (from its own internal ++ * redirect or error response), otherwise we can end up in infinite ++ * recursion; better fall through with 500, minimal headers and an ++ * empty body (EOS only). ++ */ ++ if (!check_headers_recursion(r)) { ++ apr_brigade_cleanup(b); ++ ap_die(HTTP_INTERNAL_SERVER_ERROR, r); ++ return AP_FILTER_ERROR; ++ } ++ APR_BUCKET_REMOVE(eos); ++ apr_brigade_cleanup(b); ++ APR_BRIGADE_INSERT_TAIL(b, eos); ++ r->status = HTTP_INTERNAL_SERVER_ERROR; ++ r->content_type = r->content_encoding = NULL; ++ r->content_languages = NULL; ++ ap_set_content_length(r, 0); ++ } ++ else if (eb) { ++ int status; + status = eb->status; + apr_brigade_cleanup(b); + ap_die(status, r); +@@ -1264,6 +1426,10 @@ + apr_table_unset(r->headers_out, "Content-Length"); + } + ++ if (r->status == HTTP_NO_CONTENT) { ++ apr_table_unset(r->headers_out, "Content-Length"); ++ } ++ + ctype = ap_make_content_type(r, r->content_type); + if (ctype) { + apr_table_setn(r->headers_out, "Content-Type", ctype); +@@ -1352,11 +1518,11 @@ + terminate_header(b2); + + ap_pass_brigade(f->next, b2); ++ ctx->headers_sent = 1; + +- if (r->header_only) { ++ if (r->header_only || r->status == HTTP_NO_CONTENT) { + apr_brigade_cleanup(b); +- ctx->headers_sent = 1; +- return OK; ++ return APR_SUCCESS; + } + + r->sent_bodyct = 1; /* Whatever follows is real body stuff... */ +diff -uap httpd-2.4.6/server/core.c.cve8743 httpd-2.4.6/server/core.c +--- httpd-2.4.6/server/core.c.cve8743 ++++ httpd-2.4.6/server/core.c +@@ -506,6 +506,15 @@ + if (virt->trace_enable != AP_TRACE_UNSET) + conf->trace_enable = virt->trace_enable; + ++ if (virt->http09_enable != AP_HTTP09_UNSET) ++ conf->http09_enable = virt->http09_enable; ++ ++ if (virt->http_conformance != AP_HTTP_CONFORMANCE_UNSET) ++ conf->http_conformance = virt->http_conformance; ++ ++ if (virt->http_methods != AP_HTTP_METHODS_UNSET) ++ conf->http_methods = virt->http_methods; ++ + /* no action for virt->accf_map, not allowed per-vhost */ + + if (virt->protocol) +@@ -3632,6 +3641,57 @@ + return NULL; + } + ++static const char *set_http_protocol_options(cmd_parms *cmd, void *dummy, ++ const char *arg) ++{ ++ core_server_config *conf = ++ ap_get_core_module_config(cmd->server->module_config); ++ ++ if (strcasecmp(arg, "allow0.9") == 0) ++ conf->http09_enable |= AP_HTTP09_ENABLE; ++ else if (strcasecmp(arg, "require1.0") == 0) ++ conf->http09_enable |= AP_HTTP09_DISABLE; ++ else if (strcasecmp(arg, "strict") == 0) ++ conf->http_conformance |= AP_HTTP_CONFORMANCE_STRICT; ++ else if (strcasecmp(arg, "unsafe") == 0) ++ conf->http_conformance |= AP_HTTP_CONFORMANCE_UNSAFE; ++ else if (strcasecmp(arg, "registeredmethods") == 0) ++ conf->http_methods |= AP_HTTP_METHODS_REGISTERED; ++ else if (strcasecmp(arg, "lenientmethods") == 0) ++ conf->http_methods |= AP_HTTP_METHODS_LENIENT; ++ else ++ return "HttpProtocolOptions accepts " ++ "'Unsafe' or 'Strict' (default), " ++ "'RegisteredMethods' or 'LenientMethods' (default), and " ++ "'Require1.0' or 'Allow0.9' (default)"; ++ ++ if ((conf->http09_enable & AP_HTTP09_ENABLE) ++ && (conf->http09_enable & AP_HTTP09_DISABLE)) ++ return "HttpProtocolOptions 'Allow0.9' and 'Require1.0'" ++ " are mutually exclusive"; ++ ++ if ((conf->http_conformance & AP_HTTP_CONFORMANCE_STRICT) ++ && (conf->http_conformance & AP_HTTP_CONFORMANCE_UNSAFE)) ++ return "HttpProtocolOptions 'Strict' and 'Unsafe'" ++ " are mutually exclusive"; ++ ++ if ((conf->http_methods & AP_HTTP_METHODS_REGISTERED) ++ && (conf->http_methods & AP_HTTP_METHODS_LENIENT)) ++ return "HttpProtocolOptions 'RegisteredMethods' and 'LenientMethods'" ++ " are mutually exclusive"; ++ ++ return NULL; ++} ++ ++static const char *set_http_method(cmd_parms *cmd, void *conf, const char *arg) ++{ ++ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); ++ if (err != NULL) ++ return err; ++ ap_method_register(cmd->pool, arg); ++ return NULL; ++} ++ + static apr_hash_t *errorlog_hash; + + static int log_constant_item(const ap_errorlog_info *info, const char *arg, +@@ -4143,6 +4203,13 @@ + "'on' (default), 'off' or 'extended' to trace request body content"), + AP_INIT_FLAG("MergeTrailers", set_merge_trailers, NULL, RSRC_CONF, + "merge request trailers into request headers or not"), ++AP_INIT_ITERATE("HttpProtocolOptions", set_http_protocol_options, NULL, RSRC_CONF, ++ "'Allow0.9' or 'Require1.0' (default); " ++ "'RegisteredMethods' or 'LenientMethods' (default); " ++ "'Unsafe' or 'Strict' (default). Sets HTTP acceptance rules") ++, ++AP_INIT_ITERATE("RegisterHttpMethod", set_http_method, NULL, RSRC_CONF, ++ "Registers non-standard HTTP methods"), + { NULL } + }; + +diff -uap httpd-2.4.6/server/gen_test_char.c.cve8743 httpd-2.4.6/server/gen_test_char.c +--- httpd-2.4.6/server/gen_test_char.c.cve8743 ++++ httpd-2.4.6/server/gen_test_char.c +@@ -16,11 +16,11 @@ + + #ifdef CROSS_COMPILE + ++#include + #define apr_isalnum(c) (isalnum(((unsigned char)(c)))) + #define apr_isalpha(c) (isalpha(((unsigned char)(c)))) + #define apr_iscntrl(c) (iscntrl(((unsigned char)(c)))) + #define apr_isprint(c) (isprint(((unsigned char)(c)))) +-#include + #define APR_HAVE_STDIO_H 1 + #define APR_HAVE_STRING_H 1 + +@@ -52,11 +52,13 @@ + #define T_ESCAPE_LOGITEM (0x10) + #define T_ESCAPE_FORENSIC (0x20) + #define T_ESCAPE_URLENCODED (0x40) ++#define T_HTTP_CTRLS (0x80) ++#define T_VCHAR_OBSTEXT (0x100) + + int main(int argc, char *argv[]) + { + unsigned c; +- unsigned char flags; ++ unsigned short flags; + + printf("/* this file is automatically generated by gen_test_char, " + "do not edit */\n" +@@ -67,19 +69,23 @@ + "#define T_ESCAPE_LOGITEM (%u)\n" + "#define T_ESCAPE_FORENSIC (%u)\n" + "#define T_ESCAPE_URLENCODED (%u)\n" ++ "#define T_HTTP_CTRLS (%u)\n" ++ "#define T_VCHAR_OBSTEXT (%u)\n" + "\n" +- "static const unsigned char test_char_table[256] = {", ++ "static const unsigned short test_char_table[256] = {", + T_ESCAPE_SHELL_CMD, + T_ESCAPE_PATH_SEGMENT, + T_OS_ESCAPE_PATH, + T_HTTP_TOKEN_STOP, + T_ESCAPE_LOGITEM, + T_ESCAPE_FORENSIC, +- T_ESCAPE_URLENCODED); ++ T_ESCAPE_URLENCODED, ++ T_HTTP_CTRLS, ++ T_VCHAR_OBSTEXT); + + for (c = 0; c < 256; ++c) { + flags = 0; +- if (c % 20 == 0) ++ if (c % 8 == 0) + printf("\n "); + + /* escape_shell_cmd */ +@@ -107,7 +113,7 @@ + flags |= T_ESCAPE_PATH_SEGMENT; + } + +- if (!apr_isalnum(c) && !strchr("$-_.+!*'(),:@&=/~", c)) { ++ if (!apr_isalnum(c) && !strchr("$-_.+!*'(),:;@&=/~", c)) { + flags |= T_OS_ESCAPE_PATH; + } + +@@ -115,11 +121,32 @@ + flags |= T_ESCAPE_URLENCODED; + } + +- /* these are the "tspecials" (RFC2068) or "separators" (RFC2616) */ +- if (c && (apr_iscntrl(c) || strchr(" \t()<>@,;:\\\"/[]?={}", c))) { ++ /* Stop for any non-'token' character, including ctrls, obs-text, ++ * and "tspecials" (RFC2068) a.k.a. "separators" (RFC2616), which ++ * is easer to express as characters remaining in the ASCII token set ++ */ ++ if (!c || !(apr_isalnum(c) || strchr("!#$%&'*+-.^_`|~", c))) { + flags |= T_HTTP_TOKEN_STOP; + } + ++ /* Catch CTRLs other than VCHAR, HT and SP, and obs-text (RFC7230 3.2) ++ * This includes only the C0 plane, not C1 (which is obs-text itself.) ++ * XXX: We should verify that all ASCII C0 ctrls/DEL corresponding to ++ * the current EBCDIC translation are captured, and ASCII C1 ctrls ++ * corresponding are all permitted (as they fall under obs-text rule) ++ */ ++ if (!c || (apr_iscntrl(c) && c != '\t')) { ++ flags |= T_HTTP_CTRLS; ++ } ++ ++ /* From RFC3986, the specific sets of gen-delims, sub-delims (2.2), ++ * and unreserved (2.3) that are possible somewhere within a URI. ++ * Spec requires all others to be %XX encoded, including obs-text. ++ */ ++ if (c && !apr_iscntrl(c) && c != ' ') { ++ flags |= T_VCHAR_OBSTEXT; ++ } ++ + /* For logging, escape all control characters, + * double quotes (because they delimit the request in the log file) + * backslashes (because we use backslash for escaping) +@@ -137,7 +164,7 @@ + flags |= T_ESCAPE_FORENSIC; + } + +- printf("%u%c", flags, (c < 255) ? ',' : ' '); ++ printf("0x%03x%c", flags, (c < 255) ? ',' : ' '); + } + + printf("\n};\n"); +diff -uap httpd-2.4.6/server/protocol.c.cve8743 httpd-2.4.6/server/protocol.c +--- httpd-2.4.6/server/protocol.c.cve8743 ++++ httpd-2.4.6/server/protocol.c +@@ -189,6 +189,10 @@ + * caused by MIME folding (or broken clients) if fold != 0, and place it + * in the buffer s, of size n bytes, without the ending newline. + * ++ * Pulls from r->proto_input_filters instead of r->input_filters for ++ * stricter protocol adherence and better input filter behavior during ++ * chunked trailer processing (for http). ++ * + * If s is NULL, ap_rgetline_core will allocate necessary memory from r->pool. + * + * Returns APR_SUCCESS if there are no problems and sets *read to be +@@ -197,7 +201,7 @@ + * APR_ENOSPC is returned if there is not enough buffer space. + * Other errors may be returned on other errors. + * +- * The LF is *not* returned in the buffer. Therefore, a *read of 0 ++ * The [CR]LF are *not* returned in the buffer. Therefore, a *read of 0 + * indicates that an empty line was read. + * + * Notes: Because the buffer uses 1 char for NUL, the most we can return is +@@ -208,13 +212,15 @@ + */ + AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, + apr_size_t *read, request_rec *r, +- int fold, apr_bucket_brigade *bb) ++ int flags, apr_bucket_brigade *bb) + { + apr_status_t rv; + apr_bucket *e; + apr_size_t bytes_handled = 0, current_alloc = 0; + char *pos, *last_char = *s; + int do_alloc = (*s == NULL), saw_eos = 0; ++ int fold = flags & AP_GETLINE_FOLD; ++ int crlf = flags & AP_GETLINE_CRLF; + + /* + * Initialize last_char as otherwise a random value will be compared +@@ -226,13 +232,15 @@ + + for (;;) { + apr_brigade_cleanup(bb); +- rv = ap_get_brigade(r->input_filters, bb, AP_MODE_GETLINE, ++ rv = ap_get_brigade(r->proto_input_filters, bb, AP_MODE_GETLINE, + APR_BLOCK_READ, 0); + if (rv != APR_SUCCESS) { + return rv; + } + +- /* Something horribly wrong happened. Someone didn't block! */ ++ /* Something horribly wrong happened. Someone didn't block! ++ * (this also happens at the end of each keepalive connection) ++ */ + if (APR_BRIGADE_EMPTY(bb)) { + return APR_EGENERAL; + } +@@ -318,6 +326,13 @@ + } + } + ++ if (crlf && (last_char <= *s || last_char[-1] != APR_ASCII_CR)) { ++ *last_char = '\0'; ++ bytes_handled = last_char - *s; ++ *read = bytes_handled; ++ return APR_EINVAL; ++ } ++ + /* Now NUL-terminate the string at the end of the line; + * if the last-but-one character is a CR, terminate there */ + if (last_char > *s && last_char[-1] == APR_ASCII_CR) { +@@ -340,7 +355,7 @@ + apr_brigade_cleanup(bb); + + /* We only care about the first byte. */ +- rv = ap_get_brigade(r->input_filters, bb, AP_MODE_SPECULATIVE, ++ rv = ap_get_brigade(r->proto_input_filters, bb, AP_MODE_SPECULATIVE, + APR_BLOCK_READ, 1); + if (rv != APR_SUCCESS) { + return rv; +@@ -391,7 +406,8 @@ + */ + if (do_alloc) { + tmp = NULL; +- } else { ++ } ++ else { + /* We're null terminated. */ + tmp = last_char; + } +@@ -461,7 +477,7 @@ + } + #endif + +-AP_DECLARE(int) ap_getline(char *s, int n, request_rec *r, int fold) ++AP_DECLARE(int) ap_getline(char *s, int n, request_rec *r, int flags) + { + char *tmp_s = s; + apr_status_t rv; +@@ -469,7 +485,7 @@ + apr_bucket_brigade *tmp_bb; + + tmp_bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); +- rv = ap_rgetline(&tmp_s, n, &len, r, fold, tmp_bb); ++ rv = ap_rgetline(&tmp_s, n, &len, r, flags, tmp_bb); + apr_brigade_destroy(tmp_bb); + + /* Map the out-of-space condition to the old API. */ +@@ -549,16 +565,29 @@ + } + } + +-static int read_request_line(request_rec *r, apr_bucket_brigade *bb) ++/* get the length of the field name for logging, but no more than 80 bytes */ ++#define LOG_NAME_MAX_LEN 80 ++static int field_name_len(const char *field) + { +- const char *ll; +- const char *uri; +- const char *pro; ++ const char *end = ap_strchr_c(field, ':'); ++ if (end == NULL || end - field > LOG_NAME_MAX_LEN) ++ return LOG_NAME_MAX_LEN; ++ return end - field; ++} + +- int major = 1, minor = 0; /* Assume HTTP/1.0 if non-"HTTP" protocol */ +- char http[5]; ++static int read_request_line(request_rec *r, apr_bucket_brigade *bb) ++{ ++ enum { ++ rrl_none, rrl_badmethod, rrl_badwhitespace, rrl_excesswhitespace, ++ rrl_missinguri, rrl_baduri, rrl_badprotocol, rrl_trailingtext, ++ rrl_badmethod09, rrl_reject09 ++ } deferred_error = rrl_none; ++ char *ll; ++ char *uri; + apr_size_t len; + int num_blank_lines = 0; ++ core_server_config *conf = ap_get_core_module_config(r->server->module_config); ++ int strict = (conf->http_conformance != AP_HTTP_CONFORMANCE_UNSAFE); + int max_blank_lines = r->server->limit_req_fields; + + if (max_blank_lines <= 0) { +@@ -588,7 +617,7 @@ + */ + r->the_request = NULL; + rv = ap_rgetline(&(r->the_request), (apr_size_t)(r->server->limit_req_line + 2), +- &len, r, 0, bb); ++ &len, r, strict ? AP_GETLINE_CRLF : 0, bb); + + if (rv != APR_SUCCESS) { + r->request_time = apr_time_now(); +@@ -599,8 +628,6 @@ + */ + if (APR_STATUS_IS_ENOSPC(rv)) { + r->status = HTTP_REQUEST_URI_TOO_LARGE; +- r->proto_num = HTTP_VERSION(1,0); +- r->protocol = apr_pstrdup(r->pool, "HTTP/1.0"); + } + else if (APR_STATUS_IS_TIMEUP(rv)) { + r->status = HTTP_REQUEST_TIME_OUT; +@@ -608,6 +635,8 @@ + else if (APR_STATUS_IS_EINVAL(rv)) { + r->status = HTTP_BAD_REQUEST; + } ++ r->proto_num = HTTP_VERSION(1,0); ++ r->protocol = apr_pstrdup(r->pool, "HTTP/1.0"); + return 0; + } + } while ((len <= 0) && (++num_blank_lines < max_blank_lines)); +@@ -619,46 +648,263 @@ + } + + r->request_time = apr_time_now(); +- ll = r->the_request; +- r->method = ap_getword_white(r->pool, &ll); ++ r->method = r->the_request; ++ ++ /* If there is whitespace before a method, skip it and mark in error */ ++ if (apr_isspace(*r->method)) { ++ deferred_error = rrl_badwhitespace; ++ for ( ; apr_isspace(*r->method); ++r->method) ++ ; ++ } + +- uri = ap_getword_white(r->pool, &ll); ++ /* Scan the method up to the next whitespace, ensure it contains only ++ * valid http-token characters, otherwise mark in error ++ */ ++ if (strict) { ++ ll = (char*) ap_scan_http_token(r->method); ++ } ++ else { ++ ll = (char*) ap_scan_vchar_obstext(r->method); ++ } + +- /* Provide quick information about the request method as soon as known */ ++ if (((ll == r->method) || (*ll && !apr_isspace(*ll))) ++ && deferred_error == rrl_none) { ++ deferred_error = rrl_badmethod; ++ ll = strpbrk(ll, "\t\n\v\f\r "); ++ } + +- r->method_number = ap_method_number_of(r->method); +- if (r->method_number == M_GET && r->method[0] == 'H') { +- r->header_only = 1; ++ /* Verify method terminated with a single SP, or mark as specific error */ ++ if (!ll) { ++ if (deferred_error == rrl_none) ++ deferred_error = rrl_missinguri; ++ r->protocol = uri = ""; ++ len = 0; ++ goto rrl_done; ++ } ++ else if (strict && ll[0] && apr_isspace(ll[1]) ++ && deferred_error == rrl_none) { ++ deferred_error = rrl_excesswhitespace; + } + +- ap_parse_uri(r, uri); ++ /* Advance uri pointer over leading whitespace, NUL terminate the method ++ * If non-SP whitespace is encountered, mark as specific error ++ */ ++ for (uri = ll; apr_isspace(*uri); ++uri) ++ if (*uri != ' ' && deferred_error == rrl_none) ++ deferred_error = rrl_badwhitespace; ++ *ll = '\0'; ++ ++ if (!*uri && deferred_error == rrl_none) ++ deferred_error = rrl_missinguri; ++ ++ /* Scan the URI up to the next whitespace, ensure it contains no raw ++ * control characters, otherwise mark in error ++ */ ++ ll = (char*) ap_scan_vchar_obstext(uri); ++ if (ll == uri || (*ll && !apr_isspace(*ll))) { ++ deferred_error = rrl_baduri; ++ ll = strpbrk(ll, "\t\n\v\f\r "); ++ } + +- if (ll[0]) { ++ /* Verify URI terminated with a single SP, or mark as specific error */ ++ if (!ll) { ++ r->protocol = ""; ++ len = 0; ++ goto rrl_done; ++ } ++ else if (strict && ll[0] && apr_isspace(ll[1]) ++ && deferred_error == rrl_none) { ++ deferred_error = rrl_excesswhitespace; ++ } ++ ++ /* Advance protocol pointer over leading whitespace, NUL terminate the uri ++ * If non-SP whitespace is encountered, mark as specific error ++ */ ++ for (r->protocol = ll; apr_isspace(*r->protocol); ++r->protocol) ++ if (*r->protocol != ' ' && deferred_error == rrl_none) ++ deferred_error = rrl_badwhitespace; ++ *ll = '\0'; ++ ++ /* Scan the protocol up to the next whitespace, validation comes later */ ++ if (!(ll = (char*) ap_scan_vchar_obstext(r->protocol))) { ++ len = strlen(r->protocol); ++ goto rrl_done; ++ } ++ len = ll - r->protocol; ++ ++ /* Advance over trailing whitespace, if found mark in error, ++ * determine if trailing text is found, unconditionally mark in error, ++ * finally NUL terminate the protocol string ++ */ ++ if (*ll && !apr_isspace(*ll)) { ++ deferred_error = rrl_badprotocol; ++ } ++ else if (strict && *ll) { ++ deferred_error = rrl_excesswhitespace; ++ } ++ else { ++ for ( ; apr_isspace(*ll); ++ll) ++ if (*ll != ' ' && deferred_error == rrl_none) ++ deferred_error = rrl_badwhitespace; ++ if (*ll && deferred_error == rrl_none) ++ deferred_error = rrl_trailingtext; ++ } ++ *((char *)r->protocol + len) = '\0'; ++ ++rrl_done: ++ /* For internal integrety and palloc efficiency, reconstruct the_request ++ * in one palloc, using only single SP characters, per spec. ++ */ ++ r->the_request = apr_pstrcat(r->pool, r->method, *uri ? " " : NULL, uri, ++ *r->protocol ? " " : NULL, r->protocol, NULL); ++ ++ if (len == 8 ++ && r->protocol[0] == 'H' && r->protocol[1] == 'T' ++ && r->protocol[2] == 'T' && r->protocol[3] == 'P' ++ && r->protocol[4] == '/' && apr_isdigit(r->protocol[5]) ++ && r->protocol[6] == '.' && apr_isdigit(r->protocol[7]) ++ && r->protocol[5] != '0') { ++ r->assbackwards = 0; ++ r->proto_num = HTTP_VERSION(r->protocol[5] - '0', r->protocol[7] - '0'); ++ } ++ else if (len == 8 ++ && (r->protocol[0] == 'H' || r->protocol[0] == 'h') ++ && (r->protocol[1] == 'T' || r->protocol[1] == 't') ++ && (r->protocol[2] == 'T' || r->protocol[2] == 't') ++ && (r->protocol[3] == 'P' || r->protocol[3] == 'p') ++ && r->protocol[4] == '/' && apr_isdigit(r->protocol[5]) ++ && r->protocol[6] == '.' && apr_isdigit(r->protocol[7]) ++ && r->protocol[5] != '0') { + r->assbackwards = 0; +- pro = ll; +- len = strlen(ll); +- } else { ++ r->proto_num = HTTP_VERSION(r->protocol[5] - '0', r->protocol[7] - '0'); ++ if (strict && deferred_error == rrl_none) ++ deferred_error = rrl_badprotocol; ++ else ++ memcpy((char*)r->protocol, "HTTP", 4); ++ } else if (r->protocol[0]) { ++ r->proto_num = HTTP_VERSION(0, 9); ++ /* Defer setting the r->protocol string till error msg is composed */ ++ if (deferred_error == rrl_none) ++ deferred_error = rrl_badprotocol; ++ } ++ else { + r->assbackwards = 1; +- pro = "HTTP/0.9"; +- len = 8; ++ r->protocol = apr_pstrdup(r->pool, "HTTP/0.9"); ++ r->proto_num = HTTP_VERSION(0, 9); + } +- r->protocol = apr_pstrmemdup(r->pool, pro, len); + +- /* 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'); +- } +- else if (3 == sscanf(r->protocol, "%4s/%u.%u", http, &major, &minor) +- && (strcasecmp("http", http) == 0) +- && (minor < HTTP_VERSION(1, 0)) ) /* don't allow HTTP/0.1000 */ +- r->proto_num = HTTP_VERSION(major, minor); +- else +- r->proto_num = HTTP_VERSION(1, 0); ++ /* Determine the method_number and parse the uri prior to invoking error ++ * handling, such that these fields are available for subsitution ++ */ ++ 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); ++ ++ /* With the request understood, we can consider HTTP/0.9 specific errors */ ++ if (r->proto_num == HTTP_VERSION(0, 9) && deferred_error == rrl_none) { ++ if (conf->http09_enable == AP_HTTP09_DISABLE) ++ deferred_error = rrl_reject09; ++ else if (strict && (r->method_number != M_GET || r->header_only)) ++ deferred_error = rrl_badmethod09; ++ } ++ ++ /* Now that the method, uri and protocol are all processed, ++ * we can safely resume any deferred error reporting ++ */ ++ if (deferred_error != rrl_none) { ++ if (deferred_error == rrl_badmethod) ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03445) ++ "HTTP Request Line; Invalid method token: '%.*s'", ++ field_name_len(r->method), r->method); ++ else if (deferred_error == rrl_badmethod09) ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03444) ++ "HTTP Request Line; Invalid method token: '%.*s'" ++ " (only GET is allowed for HTTP/0.9 requests)", ++ field_name_len(r->method), r->method); ++ else if (deferred_error == rrl_missinguri) ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03446) ++ "HTTP Request Line; Missing URI"); ++ else if (deferred_error == rrl_baduri) ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03454) ++ "HTTP Request Line; URI incorrectly encoded: '%.*s'", ++ field_name_len(r->uri), r->uri); ++ else if (deferred_error == rrl_badwhitespace) ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03447) ++ "HTTP Request Line; Invalid whitespace"); ++ else if (deferred_error == rrl_excesswhitespace) ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03448) ++ "HTTP Request Line; Excess whitespace " ++ "(disallowed by HttpProtocolOptions Strict"); ++ else if (deferred_error == rrl_trailingtext) ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03449) ++ "HTTP Request Line; Extraneous text found '%.*s' " ++ "(perhaps whitespace was injected?)", ++ field_name_len(ll), ll); ++ else if (deferred_error == rrl_reject09) ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02401) ++ "HTTP Request Line; Rejected HTTP/0.9 request"); ++ else if (deferred_error == rrl_badprotocol) ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02418) ++ "HTTP Request Line; Unrecognized protocol '%.*s' " ++ "(perhaps whitespace was injected?)", ++ field_name_len(r->protocol), r->protocol); ++ r->status = HTTP_BAD_REQUEST; ++ goto rrl_failed; ++ } ++ ++ if (conf->http_methods == AP_HTTP_METHODS_REGISTERED ++ && r->method_number == M_INVALID) { ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02423) ++ "HTTP Request Line; Unrecognized HTTP method: '%.*s' " ++ "(disallowed by RegisteredMethods)", ++ field_name_len(r->method), r->method); ++ r->status = HTTP_NOT_IMPLEMENTED; ++ /* This can't happen in an HTTP/0.9 request, we verified GET above */ ++ return 0; ++ } ++ ++ if (r->status != HTTP_OK) { ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03450) ++ "HTTP Request Line; Unable to parse URI: '%.*s'", ++ field_name_len(r->uri), r->uri); ++ goto rrl_failed; ++ } ++ ++ if (strict) { ++ if (r->parsed_uri.fragment) { ++ /* RFC3986 3.5: no fragment */ ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02421) ++ "HTTP Request Line; URI must not contain a fragment"); ++ r->status = HTTP_BAD_REQUEST; ++ goto rrl_failed; ++ } ++ if (r->parsed_uri.user || r->parsed_uri.password) { ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02422) ++ "HTTP Request Line; URI must not contain a " ++ "username/password"); ++ r->status = HTTP_BAD_REQUEST; ++ goto rrl_failed; ++ } ++ } + + return 1; ++rrl_failed: ++ if (r->proto_num == HTTP_VERSION(0, 9)) { ++ /* Send all parsing and protocol error response with 1.x behavior, ++ * and reserve 505 errors for actual HTTP protocols presented. ++ * As called out in RFC7230 3.5, any errors parsing the protocol ++ * from the request line are nearly always misencoded HTTP/1.x ++ * requests. Only a valid 0.9 request with no parsing errors ++ * at all may be treated as a simple request, if allowed. ++ */ ++ r->assbackwards = 0; ++ r->connection->keepalive = AP_CONN_CLOSE; ++ r->proto_num = HTTP_VERSION(1, 0); ++ r->protocol = apr_pstrdup(r->pool, "HTTP/1.0"); ++ } ++ return 0; + } + + static int table_do_fn_check_lengths(void *r_, const char *key, +@@ -670,26 +916,13 @@ + + r->status = HTTP_BAD_REQUEST; + apr_table_setn(r->notes, "error-notes", +- apr_pstrcat(r->pool, "Size of a request header field " +- "after merging exceeds server limit.
    " +- "\n
    \n",
    +-                               ap_escape_html(r->pool, key),
    +-                               "
    \n", NULL)); +- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00560) "Request header " +- "exceeds LimitRequestFieldSize after merging: %s", key); ++ "Size of a request header field exceeds server limit."); ++ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00560) "Request " ++ "header exceeds LimitRequestFieldSize after merging: %.*s", ++ field_name_len(key), key); + return 0; + } + +-/* get the length of the field name for logging, but no more than 80 bytes */ +-#define LOG_NAME_MAX_LEN 80 +-static int field_name_len(const char *field) +-{ +- const char *end = ap_strchr_c(field, ':'); +- if (end == NULL || end - field > LOG_NAME_MAX_LEN) +- return LOG_NAME_MAX_LEN; +- return end - field; +-} +- + AP_DECLARE(void) ap_get_mime_headers_core(request_rec *r, apr_bucket_brigade *bb) + { + char *last_field = NULL; +@@ -700,6 +933,8 @@ + apr_size_t len; + int fields_read = 0; + char *tmp_field; ++ core_server_config *conf = ap_get_core_module_config(r->server->module_config); ++ int strict = (conf->http_conformance != AP_HTTP_CONFORMANCE_UNSAFE); + + /* + * Read header lines until we get the empty separator line, a read error, +@@ -707,11 +942,10 @@ + */ + while(1) { + apr_status_t rv; +- int folded = 0; + + field = NULL; + rv = ap_rgetline(&field, r->server->limit_req_fieldsize + 2, +- &len, r, 0, bb); ++ &len, r, strict ? AP_GETLINE_CRLF : 0, bb); + + if (rv != APR_SUCCESS) { + if (APR_STATUS_IS_TIMEUP(rv)) { +@@ -728,153 +962,217 @@ + * exceeds the configured limit for a field size. + */ + if (rv == APR_ENOSPC) { +- const char *field_escaped; +- if (field) { +- /* ensure ap_escape_html will terminate correctly */ +- field[len - 1] = '\0'; +- field_escaped = ap_escape_html(r->pool, field); +- } +- else { +- field_escaped = field = ""; +- } +- + apr_table_setn(r->notes, "error-notes", +- apr_psprintf(r->pool, +- "Size of a request header field " +- "exceeds server limit.
    \n" +- "
    \n%.*s\n
    \n", +- field_name_len(field_escaped), +- field_escaped)); ++ "Size of a request header field " ++ "exceeds server limit."); + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00561) + "Request header exceeds LimitRequestFieldSize%s" + "%.*s", +- *field ? ": " : "", +- field_name_len(field), field); ++ (field && *field) ? ": " : "", ++ (field) ? field_name_len(field) : 0, ++ (field) ? field : ""); + } + return; + } + +- if (last_field != NULL) { +- if ((len > 0) && ((*field == '\t') || *field == ' ')) { +- /* This line is a continuation of the preceding line(s), +- * so append it to the line that we've set aside. +- * Note: this uses a power-of-two allocator to avoid +- * doing O(n) allocs and using O(n^2) space for +- * continuations that span many many lines. +- */ +- apr_size_t fold_len = last_len + len + 1; /* trailing null */ + +- if (fold_len >= (apr_size_t)(r->server->limit_req_fieldsize)) { +- r->status = HTTP_BAD_REQUEST; +- /* report what we have accumulated so far before the +- * overflow (last_field) as the field with the problem +- */ +- apr_table_setn(r->notes, "error-notes", +- apr_psprintf(r->pool, +- "Size of a request header field " +- "after folding " +- "exceeds server limit.
    \n" +- "
    \n%.*s\n
    \n", +- field_name_len(last_field), +- ap_escape_html(r->pool, last_field))); +- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00562) +- "Request header exceeds LimitRequestFieldSize " +- "after folding: %.*s", +- field_name_len(last_field), last_field); +- return; +- } ++ /* For all header values, and all obs-fold lines, the presence of ++ * additional whitespace is a no-op, so collapse trailing whitespace ++ * to save buffer allocation and optimize copy operations. ++ * Do not remove the last single whitespace under any condition. ++ */ ++ while (len > 1 && (field[len-1] == '\t' || field[len-1] == ' ')) { ++ field[--len] = '\0'; ++ } ++ ++ if (*field == '\t' || *field == ' ') { ++ /* Append any newly-read obs-fold line onto the preceding ++ * last_field line we are processing ++ */ ++ apr_size_t fold_len; + ++ if (last_field == NULL) { ++ r->status = HTTP_BAD_REQUEST; ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03442) ++ "Line folding encountered before first" ++ " header line"); ++ return; ++ } ++ ++ if (field[1] == '\0') { ++ r->status = HTTP_BAD_REQUEST; ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03443) ++ "Empty folded line encountered"); ++ return; ++ } ++ ++ /* Leading whitespace on an obs-fold line can be ++ * similarly discarded */ ++ while (field[1] == '\t' || field[1] == ' ') { ++ ++field; --len; ++ } ++ ++ /* This line is a continuation of the preceding line(s), ++ * so append it to the line that we've set aside. ++ * Note: this uses a power-of-two allocator to avoid ++ * doing O(n) allocs and using O(n^2) space for ++ * continuations that span many many lines. ++ */ ++ fold_len = last_len + len + 1; /* trailing null */ ++ ++ if (fold_len >= (apr_size_t)(r->server->limit_req_fieldsize)) { ++ r->status = HTTP_BAD_REQUEST; ++ /* report what we have accumulated so far before the ++ * overflow (last_field) as the field with the problem ++ */ ++ apr_table_setn(r->notes, "error-notes", ++ "Size of a request header field " ++ "exceeds server limit."); ++ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00562) ++ "Request header exceeds LimitRequestFieldSize " ++ "after folding: %.*s", ++ field_name_len(last_field), last_field); ++ return; ++ } ++ ++ if (fold_len > alloc_len) { ++ char *fold_buf; ++ alloc_len += alloc_len; + if (fold_len > alloc_len) { +- char *fold_buf; +- alloc_len += alloc_len; +- if (fold_len > alloc_len) { +- alloc_len = fold_len; +- } +- fold_buf = (char *)apr_palloc(r->pool, alloc_len); +- memcpy(fold_buf, last_field, last_len); +- last_field = fold_buf; ++ alloc_len = fold_len; + } +- memcpy(last_field + last_len, field, len +1); /* +1 for nul */ +- last_len += len; +- folded = 1; +- } +- else /* not a continuation line */ { ++ fold_buf = (char *)apr_palloc(r->pool, alloc_len); ++ memcpy(fold_buf, last_field, last_len); ++ last_field = fold_buf; ++ } ++ memcpy(last_field + last_len, field, len +1); /* +1 for nul */ ++ /* Replace obs-fold w/ SP per RFC 7230 3.2.4 */ ++ last_field[last_len] = ' '; ++ last_len += len; + +- if (r->server->limit_req_fields ++ /* We've appended this obs-fold line to last_len, proceed to ++ * read the next input line ++ */ ++ continue; ++ } ++ else if (last_field != NULL) { ++ /* Process the previous last_field header line with all obs-folded ++ * segments already concatinated (this is not operating on the ++ * most recently read input line). ++ */ ++ if (r->server->limit_req_fields + && (++fields_read > r->server->limit_req_fields)) { +- r->status = HTTP_BAD_REQUEST; +- apr_table_setn(r->notes, "error-notes", +- "The number of request header fields " +- "exceeds this server's limit."); +- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00563) +- "Number of request headers exceeds " +- "LimitRequestFields"); +- return; +- } ++ r->status = HTTP_BAD_REQUEST; ++ apr_table_setn(r->notes, "error-notes", ++ "The number of request header fields " ++ "exceeds this server's limit."); ++ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00563) ++ "Number of request headers exceeds " ++ "LimitRequestFields"); ++ return; ++ } + +- if (!(value = strchr(last_field, ':'))) { /* Find ':' or */ +- r->status = HTTP_BAD_REQUEST; /* abort bad request */ +- apr_table_setn(r->notes, "error-notes", +- apr_psprintf(r->pool, +- "Request header field is " +- "missing ':' separator.
    \n" +- "
    \n%.*s
    \n", +- (int)LOG_NAME_MAX_LEN, +- ap_escape_html(r->pool, +- last_field))); +- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00564) ++ if (!strict) ++ { ++ /* Not Strict ('Unsafe' mode), using the legacy parser */ ++ ++ if (!(value = strchr(last_field, ':'))) { /* Find ':' or */ ++ r->status = HTTP_BAD_REQUEST; /* abort bad request */ ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00564) + "Request header field is missing ':' " + "separator: %.*s", (int)LOG_NAME_MAX_LEN, + last_field); ++ + return; + } + +- tmp_field = value - 1; /* last character of field-name */ ++ /* last character of field-name */ ++ tmp_field = value - (value > last_field ? 1 : 0); + + *value++ = '\0'; /* NUL-terminate at colon */ + ++ if (strpbrk(last_field, "\t\n\v\f\r ")) { ++ r->status = HTTP_BAD_REQUEST; ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03452) ++ "Request header field name presented" ++ " invalid whitespace"); ++ return; ++ } ++ + while (*value == ' ' || *value == '\t') { +- ++value; /* Skip to start of value */ ++ ++value; /* Skip to start of value */ ++ } ++ ++ if (strpbrk(value, "\n\v\f\r")) { ++ r->status = HTTP_BAD_REQUEST; ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03451) ++ "Request header field value presented" ++ " bad whitespace"); ++ return; + } + +- /* Strip LWS after field-name: */ +- while (tmp_field > last_field +- && (*tmp_field == ' ' || *tmp_field == '\t')) { +- *tmp_field-- = '\0'; ++ if (tmp_field == last_field) { ++ r->status = HTTP_BAD_REQUEST; ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03453) ++ "Request header field name was empty"); ++ return; ++ } ++ } ++ else /* Using strict RFC7230 parsing */ ++ { ++ /* Ensure valid token chars before ':' per RFC 7230 3.2.4 */ ++ value = (char *)ap_scan_http_token(last_field); ++ if ((value == last_field) || *value != ':') { ++ r->status = HTTP_BAD_REQUEST; ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02426) ++ "Request header field name is malformed: " ++ "%.*s", (int)LOG_NAME_MAX_LEN, last_field); ++ return; + } + +- /* Strip LWS after field-value: */ +- tmp_field = last_field + last_len - 1; +- while (tmp_field > value +- && (*tmp_field == ' ' || *tmp_field == '\t')) { +- *tmp_field-- = '\0'; ++ *value++ = '\0'; /* NUL-terminate last_field name at ':' */ ++ ++ while (*value == ' ' || *value == '\t') { ++ ++value; /* Skip LWS of value */ + } + +- apr_table_addn(r->headers_in, last_field, value); ++ /* Find invalid, non-HT ctrl char, or the trailing NULL */ ++ tmp_field = (char *)ap_scan_http_field_content(value); + +- /* reset the alloc_len so that we'll allocate a new +- * buffer if we have to do any more folding: we can't +- * use the previous buffer because its contents are +- * now part of r->headers_in ++ /* Reject value for all garbage input (CTRLs excluding HT) ++ * e.g. only VCHAR / SP / HT / obs-text are allowed per ++ * RFC7230 3.2.6 - leave all more explicit rule enforcement ++ * for specific header handler logic later in the cycle + */ +- alloc_len = 0; ++ if (*tmp_field != '\0') { ++ r->status = HTTP_BAD_REQUEST; ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02427) ++ "Request header value is malformed: " ++ "%.*s", (int)LOG_NAME_MAX_LEN, value); ++ return; ++ } ++ } ++ ++ apr_table_addn(r->headers_in, last_field, value); + +- } /* end if current line is not a continuation starting with tab */ ++ /* This last_field header is now stored in headers_in, ++ * resume processing of the current input line. ++ */ + } + +- /* Found a blank line, stop. */ ++ /* Found the terminating empty end-of-headers line, stop. */ + if (len == 0) { + break; + } + +- /* Keep track of this line so that we can parse it on +- * the next loop iteration. (In the folded case, last_field +- * has been updated already.) ++ /* Keep track of this new header line so that we can extend it across ++ * any obs-fold or parse it on the next loop iteration. We referenced ++ * our previously allocated buffer in r->headers_in, ++ * so allocate a fresh buffer if required. + */ +- if (!folded) { +- last_field = field; +- last_len = len; +- } ++ alloc_len = 0; ++ last_field = field; ++ last_len = len; + } + + /* Combine multiple message-header fields with the same +@@ -899,7 +1197,7 @@ + request_rec *r; + apr_pool_t *p; + const char *expect; +- int access_status = HTTP_OK; ++ int access_status; + apr_bucket_brigade *tmp_bb; + apr_socket_t *csd; + apr_interval_time_t cur_timeout; +@@ -958,35 +1256,39 @@ + + /* Get the request... */ + if (!read_request_line(r, tmp_bb)) { +- if (r->status == HTTP_REQUEST_URI_TOO_LARGE +- || r->status == HTTP_BAD_REQUEST) { ++ switch (r->status) { ++ case HTTP_REQUEST_URI_TOO_LARGE: ++ case HTTP_BAD_REQUEST: ++ case HTTP_VERSION_NOT_SUPPORTED: ++ case HTTP_NOT_IMPLEMENTED: + if (r->status == HTTP_REQUEST_URI_TOO_LARGE) { + ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00565) + "request failed: client's request-line exceeds LimitRequestLine (longer than %d)", + r->server->limit_req_line); + } + else if (r->method == NULL) { +- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00566) +- "request failed: invalid characters in URI"); ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00566) ++ "request failed: malformed request line"); + } +- ap_send_error_response(r, 0); ++ access_status = r->status; ++ r->status = HTTP_OK; ++ ap_die(access_status, r); + ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r); + ap_run_log_transaction(r); ++ r = NULL; + apr_brigade_destroy(tmp_bb); + goto traceout; +- } +- else if (r->status == HTTP_REQUEST_TIME_OUT) { +- ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r); +- if (!r->connection->keepalives) { ++ case HTTP_REQUEST_TIME_OUT: ++ ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, NULL); ++ if (!r->connection->keepalives) + ap_run_log_transaction(r); +- } + apr_brigade_destroy(tmp_bb); + goto traceout; ++ default: ++ apr_brigade_destroy(tmp_bb); ++ r = NULL; ++ goto traceout; + } +- +- apr_brigade_destroy(tmp_bb); +- r = NULL; +- goto traceout; + } + + /* We may have been in keep_alive_timeout mode, so toggle back +@@ -1003,7 +1305,7 @@ + if (!r->assbackwards) { + ap_get_mime_headers_core(r, tmp_bb); + if (r->status != HTTP_OK) { +- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00567) ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00567) + "request failed: error reading the headers"); + ap_send_error_response(r, 0); + ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r); +@@ -1021,25 +1323,6 @@ + apr_table_unset(r->headers_in, "Content-Length"); + } + } +- else { +- if (r->header_only) { +- /* +- * Client asked for headers only with HTTP/0.9, which doesn't send +- * headers! Have to dink things just to make sure the error message +- * comes through... +- */ +- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00568) +- "client sent invalid HTTP/0.9 request: HEAD %s", +- r->uri); +- r->header_only = 0; +- r->status = HTTP_BAD_REQUEST; +- ap_send_error_response(r, 0); +- ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r); +- ap_run_log_transaction(r); +- apr_brigade_destroy(tmp_bb); +- goto traceout; +- } +- } + + apr_brigade_destroy(tmp_bb); + +@@ -1071,7 +1354,7 @@ + * a Host: header, and the server MUST respond with 400 if it doesn't. + */ + access_status = HTTP_BAD_REQUEST; +- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00569) ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00569) + "client sent HTTP/1.1 request without hostname " + "(see RFC2616 section 14.23): %s", r->uri); + } +diff -uap httpd-2.4.6/server/util.c.cve8743 httpd-2.4.6/server/util.c +--- httpd-2.4.6/server/util.c.cve8743 ++++ httpd-2.4.6/server/util.c +@@ -79,7 +79,7 @@ + * char in here and get it to work, because if char is signed then it + * will first be sign extended. + */ +-#define TEST_CHAR(c, f) (test_char_table[(unsigned)(c)] & (f)) ++#define TEST_CHAR(c, f) (test_char_table[(unsigned char)(c)] & (f)) + + /* Win32/NetWare/OS2 need to check for both forward and back slashes + * in ap_getparents() and ap_escape_url. +@@ -1449,6 +1449,37 @@ + return find_list_item(p, line, tok, AP_ETAG_WEAK); + } + ++/* Scan a string for HTTP VCHAR/obs-text characters including HT and SP ++ * (as used in header values, for example, in RFC 7230 section 3.2) ++ * returning the pointer to the first non-HT ASCII ctrl character. ++ */ ++AP_DECLARE(const char *) ap_scan_http_field_content(const char *ptr) ++{ ++ for ( ; !TEST_CHAR(*ptr, T_HTTP_CTRLS); ++ptr) ; ++ ++ return ptr; ++} ++ ++/* Scan a string for HTTP token characters, returning the pointer to ++ * the first non-token character. ++ */ ++AP_DECLARE(const char *) ap_scan_http_token(const char *ptr) ++{ ++ for ( ; !TEST_CHAR(*ptr, T_HTTP_TOKEN_STOP); ++ptr) ; ++ ++ return ptr; ++} ++ ++/* Scan a string for visible ASCII (0x21-0x7E) or obstext (0x80+) ++ * and return a pointer to the first ctrl/space character encountered. ++ */ ++AP_DECLARE(const char *) ap_scan_vchar_obstext(const char *ptr) ++{ ++ for ( ; TEST_CHAR(*ptr, T_VCHAR_OBSTEXT); ++ptr) ; ++ ++ return ptr; ++} ++ + /* Retrieve a token, spacing over it and returning a pointer to + * the first non-white byte afterwards. Note that these tokens + * are delimited by semis and commas; and can also be delimited +diff -uap httpd-2.4.6/server/vhost.c.cve8743 httpd-2.4.6/server/vhost.c +--- httpd-2.4.6/server/vhost.c.cve8743 ++++ httpd-2.4.6/server/vhost.c +@@ -685,6 +685,116 @@ + * run-time vhost matching functions + */ + ++static apr_status_t fix_hostname_v6_literal(request_rec *r, char *host) ++{ ++ char *dst; ++ int double_colon = 0; ++ ++ for (dst = host; *dst; dst++) { ++ if (apr_isxdigit(*dst)) { ++ if (apr_isupper(*dst)) { ++ *dst = apr_tolower(*dst); ++ } ++ } ++ else if (*dst == ':') { ++ if (*(dst + 1) == ':') { ++ if (double_colon) ++ return APR_EINVAL; ++ double_colon = 1; ++ } ++ else if (*(dst + 1) == '.') { ++ return APR_EINVAL; ++ } ++ } ++ else if (*dst == '.') { ++ /* For IPv4-mapped IPv6 addresses like ::FFFF:129.144.52.38 */ ++ if (*(dst + 1) == ':' || *(dst + 1) == '.') ++ return APR_EINVAL; ++ } ++ else { ++ return APR_EINVAL; ++ } ++ } ++ return APR_SUCCESS; ++} ++ ++static apr_status_t fix_hostname_non_v6(request_rec *r, char *host) ++{ ++ char *dst; ++ ++ for (dst = host; *dst; dst++) { ++ if (apr_islower(*dst)) { ++ /* leave char unchanged */ ++ } ++ else if (*dst == '.') { ++ if (*(dst + 1) == '.') { ++ return APR_EINVAL; ++ } ++ } ++ else if (apr_isupper(*dst)) { ++ *dst = apr_tolower(*dst); ++ } ++ else if (*dst == '/' || *dst == '\\') { ++ return APR_EINVAL; ++ } ++ } ++ /* strip trailing gubbins */ ++ if (dst > host && dst[-1] == '.') { ++ dst[-1] = '\0'; ++ } ++ return APR_SUCCESS; ++} ++ ++/* ++ * If strict mode ever becomes the default, this should be folded into ++ * fix_hostname_non_v6() ++ */ ++static apr_status_t strict_hostname_check(request_rec *r, char *host) ++{ ++ char *ch; ++ int is_dotted_decimal = 1, leading_zeroes = 0, dots = 0; ++ ++ for (ch = host; *ch; ch++) { ++ if (!apr_isascii(*ch)) { ++ goto bad; ++ } ++ else if (apr_isalpha(*ch) || *ch == '-') { ++ is_dotted_decimal = 0; ++ } ++ else if (ch[0] == '.') { ++ dots++; ++ if (ch[1] == '0' && apr_isdigit(ch[2])) ++ leading_zeroes = 1; ++ } ++ else if (!apr_isdigit(*ch)) { ++ /* also takes care of multiple Host headers by denying commas */ ++ goto bad; ++ } ++ } ++ if (is_dotted_decimal) { ++ if (host[0] == '.' || (host[0] == '0' && apr_isdigit(host[1]))) ++ leading_zeroes = 1; ++ if (leading_zeroes || dots != 3) { ++ /* RFC 3986 7.4 */ ++ goto bad; ++ } ++ } ++ else { ++ /* The top-level domain must start with a letter (RFC 1123 2.1) */ ++ while (ch > host && *ch != '.') ++ ch--; ++ if (ch[0] == '.' && ch[1] != '\0' && !apr_isalpha(ch[1])) ++ goto bad; ++ } ++ return APR_SUCCESS; ++ ++bad: ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02415) ++ "[strict] Invalid host name '%s'%s%.6s", ++ host, *ch ? ", problem near: " : "", ch); ++ return APR_EINVAL; ++} ++ + /* Lowercase and remove any trailing dot and/or :port from the hostname, + * and check that it is sane. + * +@@ -698,79 +808,90 @@ + * Instead we just check for filesystem metacharacters: directory + * separators / and \ and sequences of more than one dot. + */ +-static void fix_hostname(request_rec *r) ++static int fix_hostname(request_rec *r, const char *host_header, ++ unsigned http_conformance) + { ++ const char *src; + char *host, *scope_id; +- char *dst; + apr_port_t port; + apr_status_t rv; + const char *c; ++ int is_v6literal = 0; ++ int strict = (http_conformance != AP_HTTP_CONFORMANCE_UNSAFE); + +- /* According to RFC 2616, Host header field CAN be blank. */ +- if (!*r->hostname) { +- return; ++ src = host_header ? host_header : r->hostname; ++ ++ /* According to RFC 2616, Host header field CAN be blank */ ++ if (!*src) { ++ return is_v6literal; + } + + /* apr_parse_addr_port will interpret a bare integer as a port + * which is incorrect in this context. So treat it separately. + */ +- for (c = r->hostname; apr_isdigit(*c); ++c); +- if (!*c) { /* pure integer */ +- return; ++ for (c = src; apr_isdigit(*c); ++c); ++ if (!*c) { ++ /* pure integer */ ++ if (strict) { ++ /* RFC 3986 7.4 */ ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02416) ++ "[strict] purely numeric host names not allowed: %s", ++ src); ++ goto bad_nolog; ++ } ++ r->hostname = src; ++ return is_v6literal; ++ } ++ ++ if (host_header) { ++ rv = apr_parse_addr_port(&host, &scope_id, &port, src, r->pool); ++ if (rv != APR_SUCCESS || scope_id) ++ goto bad; ++ if (port) { ++ /* Don't throw the Host: header's port number away: ++ save it in parsed_uri -- ap_get_server_port() needs it! */ ++ /* @@@ XXX there should be a better way to pass the port. ++ * Like r->hostname, there should be a r->portno ++ */ ++ r->parsed_uri.port = port; ++ r->parsed_uri.port_str = apr_itoa(r->pool, (int)port); ++ } ++ if (host_header[0] == '[') ++ is_v6literal = 1; ++ } ++ else { ++ /* ++ * Already parsed, surrounding [ ] (if IPv6 literal) and :port have ++ * already been removed. ++ */ ++ host = apr_pstrdup(r->pool, r->hostname); ++ if (ap_strchr(host, ':') != NULL) ++ is_v6literal = 1; + } + +- rv = apr_parse_addr_port(&host, &scope_id, &port, r->hostname, r->pool); +- if (rv != APR_SUCCESS || scope_id) { +- goto bad; ++ if (is_v6literal) { ++ rv = fix_hostname_v6_literal(r, host); + } +- +- if (port) { +- /* Don't throw the Host: header's port number away: +- save it in parsed_uri -- ap_get_server_port() needs it! */ +- /* @@@ XXX there should be a better way to pass the port. +- * Like r->hostname, there should be a r->portno +- */ +- r->parsed_uri.port = port; +- r->parsed_uri.port_str = apr_itoa(r->pool, (int)port); ++ else { ++ rv = fix_hostname_non_v6(r, host); ++ if (strict && rv == APR_SUCCESS) ++ rv = strict_hostname_check(r, host); + } ++ if (rv != APR_SUCCESS) ++ goto bad; + +- /* if the hostname is an IPv6 numeric address string, it was validated +- * already; otherwise, further validation is needed +- */ +- if (r->hostname[0] != '[') { +- for (dst = host; *dst; dst++) { +- if (apr_islower(*dst)) { +- /* leave char unchanged */ +- } +- else if (*dst == '.') { +- if (*(dst + 1) == '.') { +- goto bad; +- } +- } +- else if (apr_isupper(*dst)) { +- *dst = apr_tolower(*dst); +- } +- else if (*dst == '/' || *dst == '\\') { +- goto bad; +- } +- } +- /* strip trailing gubbins */ +- if (dst > host && dst[-1] == '.') { +- dst[-1] = '\0'; +- } +- } + r->hostname = host; +- return; ++ return is_v6literal; + + bad: +- r->status = HTTP_BAD_REQUEST; + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00550) + "Client sent malformed Host header: %s", +- r->hostname); +- return; ++ src); ++bad_nolog: ++ r->status = HTTP_BAD_REQUEST; ++ return is_v6literal; + } + +- + /* return 1 if host matches ServerName or ServerAliases */ + static int matches_aliases(server_rec *s, const char *host) + { +@@ -980,15 +1101,76 @@ + } + } + ++static APR_INLINE const char *construct_host_header(request_rec *r, ++ int is_v6literal) ++{ ++ struct iovec iov[5]; ++ apr_size_t nvec = 0; ++ /* ++ * We cannot use ap_get_server_name/port here, because we must ++ * ignore UseCanonicalName/Port. ++ */ ++ if (is_v6literal) { ++ iov[nvec].iov_base = "["; ++ iov[nvec].iov_len = 1; ++ nvec++; ++ } ++ iov[nvec].iov_base = (void *)r->hostname; ++ iov[nvec].iov_len = strlen(r->hostname); ++ nvec++; ++ if (is_v6literal) { ++ iov[nvec].iov_base = "]"; ++ iov[nvec].iov_len = 1; ++ nvec++; ++ } ++ if (r->parsed_uri.port_str) { ++ iov[nvec].iov_base = ":"; ++ iov[nvec].iov_len = 1; ++ nvec++; ++ iov[nvec].iov_base = r->parsed_uri.port_str; ++ iov[nvec].iov_len = strlen(r->parsed_uri.port_str); ++ nvec++; ++ } ++ return apr_pstrcatv(r->pool, iov, nvec, NULL); ++} + + AP_DECLARE(void) ap_update_vhost_from_headers(request_rec *r) + { +- /* must set this for HTTP/1.1 support */ +- if (r->hostname || (r->hostname = apr_table_get(r->headers_in, "Host"))) { +- fix_hostname(r); +- if (r->status != HTTP_OK) +- return; ++ core_server_config *conf = ap_get_core_module_config(r->server->module_config); ++ const char *host_header = apr_table_get(r->headers_in, "Host"); ++ int is_v6literal = 0; ++ int have_hostname_from_url = 0; ++ ++ if (r->hostname) { ++ /* ++ * If there was a host part in the Request-URI, ignore the 'Host' ++ * header. ++ */ ++ have_hostname_from_url = 1; ++ is_v6literal = fix_hostname(r, NULL, conf->http_conformance); ++ } ++ else if (host_header != NULL) { ++ is_v6literal = fix_hostname(r, host_header, conf->http_conformance); ++ } ++ if (r->status != HTTP_OK) ++ return; ++ ++ if (conf->http_conformance != AP_HTTP_CONFORMANCE_UNSAFE) { ++ /* ++ * If we have both hostname from an absoluteURI and a Host header, ++ * we must ignore the Host header (RFC 2616 5.2). ++ * To enforce this, we reset the Host header to the value from the ++ * request line. ++ */ ++ if (have_hostname_from_url && host_header != NULL) { ++ const char *repl = construct_host_header(r, is_v6literal); ++ apr_table_set(r->headers_in, "Host", repl); ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02417) ++ "Replacing host header '%s' with host '%s' given " ++ "in the request uri", host_header, repl); ++ } + } ++ + /* check if we tucked away a name_chain */ + if (r->connection->vhost_lookup_data) { + if (r->hostname) diff --git a/SOURCES/httpd-2.4.6-CVE-2017-3167.patch b/SOURCES/httpd-2.4.6-CVE-2017-3167.patch new file mode 100644 index 0000000..3272598 --- /dev/null +++ b/SOURCES/httpd-2.4.6-CVE-2017-3167.patch @@ -0,0 +1,343 @@ +diff --git a/include/http_protocol.h b/include/http_protocol.h +index 5ac0ce3..f3a5137 100644 +--- a/include/http_protocol.h ++++ b/include/http_protocol.h +@@ -558,7 +558,11 @@ AP_DECLARE(void) ap_note_digest_auth_failure(request_rec *r); + AP_DECLARE_HOOK(int, note_auth_failure, (request_rec *r, const char *auth_type)) + + /** +- * Get the password from the request headers ++ * Get the password from the request headers. This function has multiple side ++ * effects due to its prior use in the old authentication framework. ++ * ap_get_basic_auth_components() should be preferred. ++ * ++ * @deprecated @see ap_get_basic_auth_components + * @param r The current request + * @param pw The password as set in the headers + * @return 0 (OK) if it set the 'pw' argument (and assured +@@ -571,6 +575,25 @@ AP_DECLARE_HOOK(int, note_auth_failure, (request_rec *r, const char *auth_type)) + */ + AP_DECLARE(int) ap_get_basic_auth_pw(request_rec *r, const char **pw); + ++#define AP_GET_BASIC_AUTH_PW_NOTE "AP_GET_BASIC_AUTH_PW_NOTE" ++ ++/** ++ * Get the username and/or password from the request's Basic authentication ++ * headers. Unlike ap_get_basic_auth_pw(), calling this function has no side ++ * effects on the passed request_rec. ++ * ++ * @param r The current request ++ * @param username If not NULL, set to the username sent by the client ++ * @param password If not NULL, set to the password sent by the client ++ * @return APR_SUCCESS if the credentials were successfully parsed and returned; ++ * APR_EINVAL if there was no authentication header sent or if the ++ * client was not using the Basic authentication scheme. username and ++ * password are unchanged on failure. ++ */ ++AP_DECLARE(apr_status_t) ap_get_basic_auth_components(const request_rec *r, ++ const char **username, ++ const char **password); ++ + /** + * parse_uri: break apart the uri + * @warning Side Effects: +diff --git a/include/httpd.h b/include/httpd.h +index 652a212..176ef5e 100644 +--- a/include/httpd.h ++++ b/include/httpd.h +@@ -2272,6 +2272,34 @@ AP_DECLARE(char *) ap_get_exec_line(apr_pool_t *p, + + #define AP_NORESTART APR_OS_START_USEERR + 1 + ++/** ++ * Perform a case-insensitive comparison of two strings @a atr1 and @a atr2, ++ * treating upper and lower case values of the 26 standard C/POSIX alphabetic ++ * characters as equivalent. Extended latin characters outside of this set ++ * are treated as unique octets, irrespective of the current locale. ++ * ++ * Returns in integer greater than, equal to, or less than 0, ++ * according to whether @a str1 is considered greater than, equal to, ++ * or less than @a str2. ++ * ++ * @note Same code as apr_cstr_casecmp, which arrives in APR 1.6 ++ */ ++AP_DECLARE(int) ap_cstr_casecmp(const char *s1, const char *s2); ++ ++/** ++ * Perform a case-insensitive comparison of two strings @a atr1 and @a atr2, ++ * treating upper and lower case values of the 26 standard C/POSIX alphabetic ++ * characters as equivalent. Extended latin characters outside of this set ++ * are treated as unique octets, irrespective of the current locale. ++ * ++ * Returns in integer greater than, equal to, or less than 0, ++ * according to whether @a str1 is considered greater than, equal to, ++ * or less than @a str2. ++ * ++ * @note Same code as apr_cstr_casecmpn, which arrives in APR 1.6 ++ */ ++AP_DECLARE(int) ap_cstr_casecmpn(const char *s1, const char *s2, apr_size_t n); ++ + #ifdef __cplusplus + } + #endif +diff --git a/server/protocol.c b/server/protocol.c +index 24355c7..868c3e3 100644 +--- a/server/protocol.c ++++ b/server/protocol.c +@@ -1567,6 +1567,7 @@ AP_DECLARE(int) ap_get_basic_auth_pw(request_rec *r, const char **pw) + + t = ap_pbase64decode(r->pool, auth_line); + r->user = ap_getword_nulls (r->pool, &t, ':'); ++ apr_table_setn(r->notes, AP_GET_BASIC_AUTH_PW_NOTE, "1"); + r->ap_auth_type = "Basic"; + + *pw = t; +@@ -1574,6 +1575,53 @@ AP_DECLARE(int) ap_get_basic_auth_pw(request_rec *r, const char **pw) + return OK; + } + ++AP_DECLARE(apr_status_t) ap_get_basic_auth_components(const request_rec *r, ++ const char **username, ++ const char **password) ++{ ++ const char *auth_header; ++ const char *credentials; ++ const char *decoded; ++ const char *user; ++ ++ auth_header = (PROXYREQ_PROXY == r->proxyreq) ? "Proxy-Authorization" ++ : "Authorization"; ++ credentials = apr_table_get(r->headers_in, auth_header); ++ ++ if (!credentials) { ++ /* No auth header. */ ++ return APR_EINVAL; ++ } ++ ++ if (ap_cstr_casecmp(ap_getword(r->pool, &credentials, ' '), "Basic")) { ++ /* These aren't Basic credentials. */ ++ return APR_EINVAL; ++ } ++ ++ while (*credentials == ' ' || *credentials == '\t') { ++ credentials++; ++ } ++ ++ /* XXX Our base64 decoding functions don't actually error out if the string ++ * we give it isn't base64; they'll just silently stop and hand us whatever ++ * they've parsed up to that point. ++ * ++ * Since this function is supposed to be a drop-in replacement for the ++ * deprecated ap_get_basic_auth_pw(), don't fix this for 2.4.x. ++ */ ++ decoded = ap_pbase64decode(r->pool, credentials); ++ user = ap_getword_nulls(r->pool, &decoded, ':'); ++ ++ if (username) { ++ *username = user; ++ } ++ if (password) { ++ *password = decoded; ++ } ++ ++ return APR_SUCCESS; ++} ++ + struct content_length_ctx { + int data_sent; /* true if the C-L filter has already sent at + * least one bucket on to the next output filter +diff --git a/server/request.c b/server/request.c +index 2711bed..4eef097 100644 +--- a/server/request.c ++++ b/server/request.c +@@ -124,6 +124,8 @@ static int decl_die(int status, const char *phase, request_rec *r) + AP_DECLARE(int) ap_some_authn_required(request_rec *r) + { + int access_status; ++ char *olduser = r->user; ++ int rv = FALSE; + + switch (ap_satisfies(r)) { + case SATISFY_ALL: +@@ -134,7 +136,7 @@ AP_DECLARE(int) ap_some_authn_required(request_rec *r) + + access_status = ap_run_access_checker_ex(r); + if (access_status == DECLINED) { +- return TRUE; ++ rv = TRUE; + } + + break; +@@ -145,13 +147,14 @@ AP_DECLARE(int) ap_some_authn_required(request_rec *r) + + access_status = ap_run_access_checker_ex(r); + if (access_status == DECLINED) { +- return TRUE; ++ rv = TRUE; + } + + break; + } + +- return FALSE; ++ r->user = olduser; ++ return rv; + } + + /* This is the master logic for processing requests. Do NOT duplicate +@@ -259,6 +262,14 @@ AP_DECLARE(int) ap_process_request_internal(request_rec *r) + r->ap_auth_type = r->main->ap_auth_type; + } + else { ++ /* A module using a confusing API (ap_get_basic_auth_pw) caused ++ ** r->user to be filled out prior to check_authn hook. We treat ++ ** it is inadvertent. ++ */ ++ if (r->user && apr_table_get(r->notes, AP_GET_BASIC_AUTH_PW_NOTE)) { ++ r->user = NULL; ++ } ++ + switch (ap_satisfies(r)) { + case SATISFY_ALL: + case SATISFY_NOSPEC: +diff --git a/server/util.c b/server/util.c +index db22b50..70fd662 100644 +--- a/server/util.c ++++ b/server/util.c +@@ -96,7 +96,6 @@ + #undef APLOG_MODULE_INDEX + #define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX + +- + /* + * Examine a field value (such as a media-/content-type) string and return + * it sans any parameters; e.g., strip off any ';charset=foo' and the like. +@@ -3036,3 +3035,128 @@ AP_DECLARE(char *) ap_get_exec_line(apr_pool_t *p, + + return apr_pstrndup(p, buf, k); + } ++ ++#if !APR_CHARSET_EBCDIC ++/* ++ * Our own known-fast translation table for casecmp by character. ++ * Only ASCII alpha characters 41-5A are folded to 61-7A, other ++ * octets (such as extended latin alphabetics) are never case-folded. ++ * NOTE: Other than Alpha A-Z/a-z, each code point is unique! ++*/ ++static const short ucharmap[] = { ++ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, ++ 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, ++ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, ++ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, ++ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, ++ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, ++ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, ++ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, ++ 0x40, 'a', 'b', 'c', 'd', 'e', 'f', 'g', ++ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', ++ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', ++ 'x', 'y', 'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, ++ 0x60, 'a', 'b', 'c', 'd', 'e', 'f', 'g', ++ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', ++ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', ++ 'x', 'y', 'z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, ++ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, ++ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, ++ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, ++ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, ++ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, ++ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, ++ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, ++ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, ++ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, ++ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, ++ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, ++ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, ++ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, ++ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, ++ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff ++}; ++#else /* APR_CHARSET_EBCDIC */ ++/* ++ * Derived from apr-iconv/ccs/cp037.c for EBCDIC case comparison, ++ * provides unique identity of every char value (strict ISO-646 ++ * conformance, arbitrary election of an ISO-8859-1 ordering, and ++ * very arbitrary control code assignments into C1 to achieve ++ * identity and a reversible mapping of code points), ++ * then folding the equivalences of ASCII 41-5A into 61-7A, ++ * presenting comparison results in a somewhat ISO/IEC 10646 ++ * (ASCII-like) order, depending on the EBCDIC code page in use. ++ * ++ * NOTE: Other than Alpha A-Z/a-z, each code point is unique! ++ */ ++static const short ucharmap[] = { ++ 0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F, ++ 0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, ++ 0x10, 0x11, 0x12, 0x13, 0x9D, 0x85, 0x08, 0x87, ++ 0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F, ++ 0x80, 0x81, 0x82, 0x83, 0x84, 0x0A, 0x17, 0x1B, ++ 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07, ++ 0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04, ++ 0x98, 0x99, 0x9A, 0x9B, 0x14, 0x15, 0x9E, 0x1A, ++ 0x20, 0xA0, 0xE2, 0xE4, 0xE0, 0xE1, 0xE3, 0xE5, ++ 0xE7, 0xF1, 0xA2, 0x2E, 0x3C, 0x28, 0x2B, 0x7C, ++ 0x26, 0xE9, 0xEA, 0xEB, 0xE8, 0xED, 0xEE, 0xEF, ++ 0xEC, 0xDF, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAC, ++ 0x2D, 0x2F, 0xC2, 0xC4, 0xC0, 0xC1, 0xC3, 0xC5, ++ 0xC7, 0xD1, 0xA6, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, ++ 0xF8, 0xC9, 0xCA, 0xCB, 0xC8, 0xCD, 0xCE, 0xCF, ++ 0xCC, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, ++ 0xD8, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, ++ 0x68, 0x69, 0xAB, 0xBB, 0xF0, 0xFD, 0xFE, 0xB1, ++ 0xB0, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, ++ 0x71, 0x72, 0xAA, 0xBA, 0xE6, 0xB8, 0xC6, 0xA4, ++ 0xB5, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, ++ 0x79, 0x7A, 0xA1, 0xBF, 0xD0, 0xDD, 0xDE, 0xAE, ++ 0x5E, 0xA3, 0xA5, 0xB7, 0xA9, 0xA7, 0xB6, 0xBC, ++ 0xBD, 0xBE, 0x5B, 0x5D, 0xAF, 0xA8, 0xB4, 0xD7, ++ 0x7B, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, ++ 0x68, 0x69, 0xAD, 0xF4, 0xF6, 0xF2, 0xF3, 0xF5, ++ 0x7D, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, ++ 0x71, 0x72, 0xB9, 0xFB, 0xFC, 0xF9, 0xFA, 0xFF, ++ 0x5C, 0xF7, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, ++ 0x79, 0x7A, 0xB2, 0xD4, 0xD6, 0xD2, 0xD3, 0xD5, ++ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, ++ 0x38, 0x39, 0xB3, 0xDB, 0xDC, 0xD9, 0xDA, 0x9F ++}; ++#endif ++ ++AP_DECLARE(int) ap_cstr_casecmp(const char *s1, const char *s2) ++{ ++ const unsigned char *str1 = (const unsigned char *)s1; ++ const unsigned char *str2 = (const unsigned char *)s2; ++ for (;;) ++ { ++ const int c1 = (int)(*str1); ++ const int c2 = (int)(*str2); ++ const int cmp = ucharmap[c1] - ucharmap[c2]; ++ /* Not necessary to test for !c2, this is caught by cmp */ ++ if (cmp || !c1) ++ return cmp; ++ str1++; ++ str2++; ++ } ++} ++ ++AP_DECLARE(int) ap_cstr_casecmpn(const char *s1, const char *s2, apr_size_t n) ++{ ++ const unsigned char *str1 = (const unsigned char *)s1; ++ const unsigned char *str2 = (const unsigned char *)s2; ++ while (n--) ++ { ++ const int c1 = (int)(*str1); ++ const int c2 = (int)(*str2); ++ const int cmp = ucharmap[c1] - ucharmap[c2]; ++ /* Not necessary to test for !c2, this is caught by cmp */ ++ if (cmp || !c1) ++ return cmp; ++ str1++; ++ str2++; ++ } ++ return 0; ++} diff --git a/SOURCES/httpd-2.4.6-CVE-2017-3169.patch b/SOURCES/httpd-2.4.6-CVE-2017-3169.patch new file mode 100644 index 0000000..36e2611 --- /dev/null +++ b/SOURCES/httpd-2.4.6-CVE-2017-3169.patch @@ -0,0 +1,64 @@ +diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c +index 85c6ce7..4a9fc9a 100644 +--- a/modules/ssl/ssl_engine_io.c ++++ b/modules/ssl/ssl_engine_io.c +@@ -834,19 +834,20 @@ static apr_status_t ssl_filter_write(ap_filter_t *f, + * establish an outgoing SSL connection. */ + #define MODSSL_ERROR_BAD_GATEWAY (APR_OS_START_USERERR + 1) + +-static void ssl_io_filter_disable(SSLConnRec *sslconn, ap_filter_t *f) ++static void ssl_io_filter_disable(SSLConnRec *sslconn, ++ bio_filter_in_ctx_t *inctx) + { +- bio_filter_in_ctx_t *inctx = f->ctx; + SSL_free(inctx->ssl); + sslconn->ssl = NULL; + inctx->ssl = NULL; + inctx->filter_ctx->pssl = NULL; + } + +-static apr_status_t ssl_io_filter_error(ap_filter_t *f, ++static apr_status_t ssl_io_filter_error(bio_filter_in_ctx_t *inctx, + apr_bucket_brigade *bb, + apr_status_t status) + { ++ ap_filter_t *f = inctx->f; + SSLConnRec *sslconn = myConnConfig(f->c); + apr_bucket *bucket; + int send_eos = 1; +@@ -860,7 +861,7 @@ static apr_status_t ssl_io_filter_error(ap_filter_t *f, + ssl_log_ssl_error(SSLLOG_MARK, APLOG_INFO, sslconn->server); + + sslconn->non_ssl_request = NON_SSL_SEND_HDR_SEP; +- ssl_io_filter_disable(sslconn, f); ++ ssl_io_filter_disable(sslconn, inctx); + + /* fake the request line */ + bucket = HTTP_ON_HTTPS_PORT_BUCKET(f->c->bucket_alloc); +@@ -1342,7 +1343,7 @@ static apr_status_t ssl_io_filter_input(ap_filter_t *f, + * rather than have SSLEngine On configured. + */ + if ((status = ssl_io_filter_handshake(inctx->filter_ctx)) != APR_SUCCESS) { +- return ssl_io_filter_error(f, bb, status); ++ return ssl_io_filter_error(inctx, bb, status); + } + + if (is_init) { +@@ -1396,7 +1397,7 @@ static apr_status_t ssl_io_filter_input(ap_filter_t *f, + + /* Handle custom errors. */ + if (status != APR_SUCCESS) { +- return ssl_io_filter_error(f, bb, status); ++ return ssl_io_filter_error(inctx, bb, status); + } + + /* Create a transient bucket out of the decrypted data. */ +@@ -1613,7 +1614,7 @@ static apr_status_t ssl_io_filter_output(ap_filter_t *f, + inctx->block = APR_BLOCK_READ; + + if ((status = ssl_io_filter_handshake(filter_ctx)) != APR_SUCCESS) { +- return ssl_io_filter_error(f, bb, status); ++ return ssl_io_filter_error(inctx, bb, status); + } + + while (!APR_BRIGADE_EMPTY(bb)) { diff --git a/SOURCES/httpd-2.4.6-CVE-2017-7668.patch b/SOURCES/httpd-2.4.6-CVE-2017-7668.patch new file mode 100644 index 0000000..8dd73e5 --- /dev/null +++ b/SOURCES/httpd-2.4.6-CVE-2017-7668.patch @@ -0,0 +1,15 @@ +--- a/server/util.c 2017/05/30 12:27:41 1796855 ++++ b/server/util.c 2017/05/30 12:28:20 1796856 +@@ -1679,10 +1679,8 @@ + + s = (const unsigned char *)line; + for (;;) { +- /* find start of token, skip all stop characters, note NUL +- * isn't a token stop, so we don't need to test for it +- */ +- while (TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) { ++ /* find start of token, skip all stop characters */ ++ while (*s && TEST_CHAR(*s, T_HTTP_TOKEN_STOP)) { + ++s; + } + if (!*s) { diff --git a/SOURCES/httpd-2.4.6-CVE-2017-7679.patch b/SOURCES/httpd-2.4.6-CVE-2017-7679.patch new file mode 100644 index 0000000..a68d3f6 --- /dev/null +++ b/SOURCES/httpd-2.4.6-CVE-2017-7679.patch @@ -0,0 +1,14 @@ +--- a/modules/http/mod_mime.c 2017/06/05 12:10:05 1797652 ++++ b/modules/http/mod_mime.c 2017/06/05 12:12:31 1797653 +@@ -528,9 +528,9 @@ + int res = -1; + int c; + +- if (((s + 1) != NULL) && (*s == '\\')) { ++ if (*s == '\\') { + c = (int) *(s + 1); +- if (apr_isascii(c)) { ++ if (c && apr_isascii(c)) { + res = 1; + } + } diff --git a/SOURCES/httpd-2.4.6-CVE-2017-9788.patch b/SOURCES/httpd-2.4.6-CVE-2017-9788.patch new file mode 100644 index 0000000..d1a3480 --- /dev/null +++ b/SOURCES/httpd-2.4.6-CVE-2017-9788.patch @@ -0,0 +1,29 @@ +diff --git a/modules/aaa/mod_auth_digest.c b/modules/aaa/mod_auth_digest.c +index 0ff47f7..cbb4434 100644 +--- a/modules/aaa/mod_auth_digest.c ++++ b/modules/aaa/mod_auth_digest.c +@@ -956,13 +956,13 @@ static int get_digest_rec(request_rec *r, digest_header_rec *resp) + + /* find value */ + ++ vv = 0; + if (auth_line[0] == '=') { + auth_line++; + while (apr_isspace(auth_line[0])) { + auth_line++; + } + +- vv = 0; + if (auth_line[0] == '\"') { /* quoted string */ + auth_line++; + while (auth_line[0] != '\"' && auth_line[0] != '\0') { +@@ -981,8 +981,8 @@ static int get_digest_rec(request_rec *r, digest_header_rec *resp) + value[vv++] = *auth_line++; + } + } +- value[vv] = '\0'; + } ++ value[vv] = '\0'; + + while (auth_line[0] != ',' && auth_line[0] != '\0') { + auth_line++; diff --git a/SOURCES/httpd-2.4.6-CVE-2017-9798.patch b/SOURCES/httpd-2.4.6-CVE-2017-9798.patch new file mode 100644 index 0000000..b615488 --- /dev/null +++ b/SOURCES/httpd-2.4.6-CVE-2017-9798.patch @@ -0,0 +1,17 @@ +diff --git a/server/core.c b/server/core.c +index f60e8fa..245fcb6 100644 +--- a/server/core.c ++++ b/server/core.c +@@ -2061,6 +2061,12 @@ AP_CORE_DECLARE_NONSTD(const char *) ap_limit_section(cmd_parms *cmd, + /* method has not been registered yet, but resorce restriction + * is always checked before method handling, so register it. + */ ++ if (cmd->pool == cmd->temp_pool) { ++ /* In .htaccess, we can't globally register new methods. */ ++ return apr_psprintf(cmd->pool, "Could not register method '%s' " ++ "for %s from .htaccess configuration", ++ method, cmd->cmd->name); ++ } + methnum = ap_method_register(cmd->pool, + apr_pstrdup(cmd->pool, method)); + } diff --git a/SOURCES/httpd-2.4.6-ab-overflow.patch b/SOURCES/httpd-2.4.6-ab-overflow.patch new file mode 100644 index 0000000..91a76b2 --- /dev/null +++ b/SOURCES/httpd-2.4.6-ab-overflow.patch @@ -0,0 +1,20 @@ +--- a/support/ab.c 2014/08/14 12:12:38 1617912 ++++ b/support/ab.c 2014/08/14 12:15:31 1617913 +@@ -1029,7 +1029,7 @@ + ap_round_ms(stats[done - 1].time)); + else + printf(" %d%% %5" APR_TIME_T_FMT "\n", percs[i], +- ap_round_ms(stats[(int) (done * percs[i] / 100)].time)); ++ ap_round_ms(stats[(unsigned long)done * percs[i] / 100].time)); + } + } + if (csvperc) { +@@ -1046,7 +1046,7 @@ + else if (i == 100) + t = ap_double_ms(stats[done - 1].time); + else +- t = ap_double_ms(stats[(int) (0.5 + done * i / 100.0)].time); ++ t = ap_double_ms(stats[(unsigned long) (0.5 + (double)done * i / 100.0)].time); + fprintf(out, "%d,%.3f\n", i, t); + } + fclose(out); diff --git a/SOURCES/httpd-2.4.6-ab-ssl-error.patch b/SOURCES/httpd-2.4.6-ab-ssl-error.patch new file mode 100644 index 0000000..8f169f7 --- /dev/null +++ b/SOURCES/httpd-2.4.6-ab-ssl-error.patch @@ -0,0 +1,27 @@ +diff --git a/support/ab.c b/support/ab.c +index bf76406..80c1b74 100644 +--- a/support/ab.c ++++ b/support/ab.c +@@ -1346,11 +1346,21 @@ static void read_connection(struct connection * c) + && good == 0) { + return; + } ++ else if (scode == SSL_ERROR_SYSCALL ++ && status == 0 ++ && c->read != 0) { ++ /* connection closed, but in violation of the protocol, after ++ * some data has already been read; this commonly happens, so ++ * let the length check catch any response errors ++ */ ++ good++; ++ close_connection(c); ++ } + else if (scode != SSL_ERROR_WANT_WRITE + && scode != SSL_ERROR_WANT_READ) { + /* some fatal error: */ + c->read = 0; +- BIO_printf(bio_err, "SSL read failed (%d) - closing connection\n", scode); ++ BIO_printf(bio_err, "SSL read failed (%d) - closing connection\n", scode); + ERR_print_errors(bio_err); + close_connection(c); + } diff --git a/SOURCES/httpd-2.4.6-ap-ipv6.patch b/SOURCES/httpd-2.4.6-ap-ipv6.patch new file mode 100644 index 0000000..e1eba14 --- /dev/null +++ b/SOURCES/httpd-2.4.6-ap-ipv6.patch @@ -0,0 +1,139 @@ +diff --git a/support/ab.c b/support/ab.c +index f54c402..93c9066 100644 +--- a/support/ab.c ++++ b/support/ab.c +@@ -344,6 +344,7 @@ apr_time_t start, lasttime, stoptime; + char _request[2048]; + char *request = _request; + apr_size_t reqlen; ++int requests_initialized = 0; + + /* one global throw-away buffer to read stuff into */ + char buffer[8192]; +@@ -1253,12 +1254,18 @@ static void start_connect(struct connection * c) + else { + set_conn_state(c, STATE_UNCONNECTED); + apr_socket_close(c->aprsock); +- err_conn++; +- if (bad++ > 10) { ++ if (good == 0 && destsa->next) { ++ destsa = destsa->next; ++ err_conn = 0; ++ } ++ else if (bad++ > 10) { + fprintf(stderr, + "\nTest aborted after 10 failures\n\n"); + apr_err("apr_socket_connect()", rv); + } ++ else { ++ err_conn++; ++ } + + start_connect(c); + return; +@@ -1339,6 +1346,7 @@ static void read_connection(struct connection * c) + apr_status_t status; + char *part; + char respcode[4]; /* 3 digits and null */ ++ int i; + + r = sizeof(buffer); + #ifdef USE_SSL +@@ -1362,6 +1370,13 @@ static void read_connection(struct connection * c) + good++; + close_connection(c); + } ++ else if (scode == SSL_ERROR_SYSCALL ++ && c->read == 0 ++ && destsa->next ++ && c->state == STATE_CONNECTING ++ && good == 0) { ++ return; ++ } + else if (scode != SSL_ERROR_WANT_WRITE + && scode != SSL_ERROR_WANT_READ) { + /* some fatal error: */ +@@ -1387,8 +1402,8 @@ static void read_connection(struct connection * c) + } + /* catch legitimate fatal apr_socket_recv errors */ + else if (status != APR_SUCCESS) { +- err_recv++; + if (recverrok) { ++ err_recv++; + bad++; + close_connection(c); + if (verbosity >= 1) { +@@ -1396,7 +1411,12 @@ static void read_connection(struct connection * c) + fprintf(stderr,"%s: %s (%d)\n", "apr_socket_recv", apr_strerror(status, buf, sizeof buf), status); + } + return; +- } else { ++ } else if (destsa->next && c->state == STATE_CONNECTING ++ && c->read == 0 && good == 0) { ++ return; ++ } ++ else { ++ err_recv++; + apr_err("apr_socket_recv", status); + } + } +@@ -1523,6 +1543,16 @@ static void read_connection(struct connection * c) + } + c->bread += c->cbx - (s + l - c->cbuff) + r - tocopy; + totalbread += c->bread; ++ ++ /* We have received the header, so we know this destination socket ++ * address is working, so initialize all remaining requests. */ ++ if (!requests_initialized) { ++ for (i = 1; i < concurrency; i++) { ++ con[i].socknum = i; ++ start_connect(&con[i]); ++ } ++ requests_initialized = 1; ++ } + } + } + else { +@@ -1734,11 +1764,10 @@ static void test(void) + apr_signal(SIGINT, output_results); + #endif + +- /* initialise lots of requests */ +- for (i = 0; i < concurrency; i++) { +- con[i].socknum = i; +- start_connect(&con[i]); +- } ++ /* initialise first connection to determine destination socket address ++ * which should be used for next connections. */ ++ con[0].socknum = 0; ++ start_connect(&con[0]); + + do { + apr_int32_t n; +@@ -1786,14 +1815,20 @@ static void test(void) + if ((rtnev & APR_POLLIN) || (rtnev & APR_POLLPRI) || (rtnev & APR_POLLHUP)) + read_connection(c); + if ((rtnev & APR_POLLERR) || (rtnev & APR_POLLNVAL)) { +- bad++; +- err_except++; +- /* avoid apr_poll/EINPROGRESS loop on HP-UX, let recv discover ECONNREFUSED */ +- if (c->state == STATE_CONNECTING) { +- read_connection(c); ++ if (destsa->next && c->state == STATE_CONNECTING && good == 0) { ++ destsa = destsa->next; ++ start_connect(c); + } + else { +- start_connect(c); ++ bad++; ++ err_except++; ++ /* avoid apr_poll/EINPROGRESS loop on HP-UX, let recv discover ECONNREFUSED */ ++ if (c->state == STATE_CONNECTING) { ++ read_connection(c); ++ } ++ else { ++ start_connect(c); ++ } + } + continue; + } diff --git a/SOURCES/httpd-2.4.6-apachectl-httpd-env.patch b/SOURCES/httpd-2.4.6-apachectl-httpd-env.patch new file mode 100644 index 0000000..3e884b9 --- /dev/null +++ b/SOURCES/httpd-2.4.6-apachectl-httpd-env.patch @@ -0,0 +1,38 @@ +diff --git a/docs/man/apachectl.8 b/docs/man/apachectl.8 +index 054550f..4bfc7cb 100644 +--- a/docs/man/apachectl.8 ++++ b/docs/man/apachectl.8 +@@ -77,7 +77,7 @@ status + Displays a brief status report\&. Similar to the fullstatus option, except that the list of requests currently being served is omitted\&. + .TP + graceful +-Gracefully restarts the Apache httpd daemon\&. If the daemon is not running, it is started\&. This differs from a normal restart in that currently open connections are not aborted\&. A side effect is that old log files will not be closed immediately\&. This means that if used in a log rotation script, a substantial delay may be necessary to ensure that the old log files are closed before processing them\&. This command automatically checks the configuration files as in configtest before initiating the restart to make sure Apache doesn't die\&. This is equivalent to apachectl -k graceful\&. ++Gracefully restarts the Apache httpd daemon\&. If the daemon is not running, it is not started\&. This differs from a normal restart in that currently open connections are not aborted\&. A side effect is that old log files will not be closed immediately\&. This means that if used in a log rotation script, a substantial delay may be necessary to ensure that the old log files are closed before processing them\&. This command automatically checks the configuration files as in configtest before initiating the restart to make sure Apache doesn't die\&. This is equivalent to apachectl -k graceful\&. + .TP + graceful-stop + Gracefully stops the Apache httpd daemon\&. This differs from a normal stop in that currently open connections are not aborted\&. A side effect is that old log files will not be closed immediately\&. This is equivalent to apachectl -k graceful-stop\&. +diff --git a/support/apachectl.in b/support/apachectl.in +index 2d59623..10fc280 100644 +--- a/support/apachectl.in ++++ b/support/apachectl.in +@@ -93,9 +93,9 @@ function testconfig() { + # httpd is denied terminal access in SELinux, so run in the + # current context to get stdout from $HTTPD -t. + if test -x /usr/sbin/selinuxenabled && /usr/sbin/selinuxenabled; then +- runcon -- `id -Z` $HTTPD $OPTIONS -t ++ runcon -- `id -Z` /usr/sbin/httpd $OPTIONS -t + else +- $HTTPD $OPTIONS -t ++ /usr/sbin/httpd $OPTIONS -t + fi + ERROR=$? + } +@@ -134,7 +134,7 @@ fullstatus) + $LYNX $STATUSURL + ;; + *) +- $HTTPD $OPTIONS "$@" ++ /usr/sbin/httpd $OPTIONS "$@" + ERROR=$? + esac + diff --git a/SOURCES/httpd-2.4.6-apachectl-status.patch b/SOURCES/httpd-2.4.6-apachectl-status.patch new file mode 100644 index 0000000..779a9ab --- /dev/null +++ b/SOURCES/httpd-2.4.6-apachectl-status.patch @@ -0,0 +1,13 @@ +diff --git a/docs/man/apachectl.8 b/docs/man/apachectl.8 +index 4bfc7cb..372c08e 100644 +--- a/docs/man/apachectl.8 ++++ b/docs/man/apachectl.8 +@@ -74,7 +74,7 @@ fullstatus + Displays a full status report from mod_status\&. For this to work, you need to have mod_status enabled on your server and a text-based browser such as lynx available on your system\&. The URL used to access the status report can be set by editing the STATUSURL variable in the script\&. + .TP + status +-Displays a brief status report\&. Similar to the fullstatus option, except that the list of requests currently being served is omitted\&. ++Displays a brief status report using systemd\&. + .TP + graceful + Gracefully restarts the Apache httpd daemon\&. If the daemon is not running, it is not started\&. This differs from a normal restart in that currently open connections are not aborted\&. A side effect is that old log files will not be closed immediately\&. This means that if used in a log rotation script, a substantial delay may be necessary to ensure that the old log files are closed before processing them\&. This command automatically checks the configuration files as in configtest before initiating the restart to make sure Apache doesn't die\&. This is equivalent to apachectl -k graceful\&. diff --git a/SOURCES/httpd-2.4.6-bomb.patch b/SOURCES/httpd-2.4.6-bomb.patch new file mode 100644 index 0000000..42dbb93 --- /dev/null +++ b/SOURCES/httpd-2.4.6-bomb.patch @@ -0,0 +1,14 @@ +diff --git a/docs/conf/extra/httpd-autoindex.conf.in b/docs/conf/extra/httpd-autoindex.conf.in +index 0e8b626..dd6f2c6 100644 +--- a/docs/conf/extra/httpd-autoindex.conf.in ++++ b/docs/conf/extra/httpd-autoindex.conf.in +@@ -53,7 +53,8 @@ AddIcon /icons/dvi.gif .dvi + AddIcon /icons/uuencoded.gif .uu + AddIcon /icons/script.gif .conf .sh .shar .csh .ksh .tcl + AddIcon /icons/tex.gif .tex +-AddIcon /icons/bomb.gif core. ++AddIcon /icons/bomb.gif /core ++AddIcon /icons/bomb.gif */core.* + + AddIcon /icons/back.gif .. + AddIcon /icons/hand.right.gif README diff --git a/SOURCES/httpd-2.4.6-dhparams-free.patch b/SOURCES/httpd-2.4.6-dhparams-free.patch new file mode 100644 index 0000000..2319ff8 --- /dev/null +++ b/SOURCES/httpd-2.4.6-dhparams-free.patch @@ -0,0 +1,31 @@ +diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c +index ee46db4..c560422 100644 +--- a/modules/ssl/ssl_engine_init.c ++++ b/modules/ssl/ssl_engine_init.c +@@ -915,7 +915,7 @@ static void ssl_init_server_certs(server_rec *s, + const char *rsa_id, *dsa_id; + #ifndef OPENSSL_NO_EC + const char *ecc_id; +- EC_GROUP *ecparams; ++ EC_GROUP *ecparams = NULL; + int nid; + EC_KEY *eckey = NULL; + #endif +@@ -988,6 +988,7 @@ static void ssl_init_server_certs(server_rec *s, + "Custom DH parameters (%d bits) for %s loaded from %s", + BN_num_bits(dhparams->p), vhost_id, + mctx->pks->cert_files[0]); ++ DH_free(dhparams); + } + + #ifndef OPENSSL_NO_EC +@@ -1012,6 +1013,9 @@ static void ssl_init_server_certs(server_rec *s, + SSL_CTX_set_tmp_ecdh(mctx->ssl_ctx, eckey); + #endif + } ++ if (ecparams) { ++ EC_GROUP_free(ecparams); ++ } + EC_KEY_free(eckey); + #endif + } diff --git a/SOURCES/httpd-2.4.6-full-release.patch b/SOURCES/httpd-2.4.6-full-release.patch new file mode 100644 index 0000000..118c57c --- /dev/null +++ b/SOURCES/httpd-2.4.6-full-release.patch @@ -0,0 +1,48 @@ +diff --git a/server/core.c b/server/core.c +index fb5e34a..e71f716 100644 +--- a/server/core.c ++++ b/server/core.c +@@ -3115,7 +3115,8 @@ enum server_token_type { + SrvTk_MINIMAL, /* eg: Apache/2.0.41 */ + SrvTk_OS, /* eg: Apache/2.0.41 (UNIX) */ + SrvTk_FULL, /* eg: Apache/2.0.41 (UNIX) PHP/4.2.2 FooBar/1.2b */ +- SrvTk_PRODUCT_ONLY /* eg: Apache */ ++ SrvTk_FULL_RELEASE, /* eg: Apache/2.0.41 (UNIX) (Release 32.el7) PHP/4.2.2 FooBar/1.2b */ ++ SrvTk_PRODUCT_ONLY /* eg: Apache */ + }; + static enum server_token_type ap_server_tokens = SrvTk_FULL; + +@@ -3191,7 +3192,10 @@ static void set_banner(apr_pool_t *pconf) + else if (ap_server_tokens == SrvTk_MAJOR) { + ap_add_version_component(pconf, AP_SERVER_BASEPRODUCT "/" AP_SERVER_MAJORVERSION); + } +- else { ++ else if (ap_server_tokens == SrvTk_FULL_RELEASE) { ++ ap_add_version_component(pconf, AP_SERVER_BASEVERSION " (" PLATFORM ") (Release @RELEASE@)"); ++ } ++ else { + ap_add_version_component(pconf, AP_SERVER_BASEVERSION " (" PLATFORM ")"); + } + +@@ -3199,7 +3203,7 @@ static void set_banner(apr_pool_t *pconf) + * Lock the server_banner string if we're not displaying + * the full set of tokens + */ +- if (ap_server_tokens != SrvTk_FULL) { ++ if (ap_server_tokens != SrvTk_FULL && ap_server_tokens != SrvTk_FULL_RELEASE) { + banner_locked++; + } + server_description = AP_SERVER_BASEVERSION " (" PLATFORM ")"; +@@ -3232,8 +3236,11 @@ static const char *set_serv_tokens(cmd_parms *cmd, void *dummy, + else if (!strcasecmp(arg1, "Full")) { + ap_server_tokens = SrvTk_FULL; + } ++ else if (!strcasecmp(arg1, "Full-Release")) { ++ ap_server_tokens = SrvTk_FULL_RELEASE; ++ } + else { +- return "ServerTokens takes 1 argument, 'Prod', 'Major', 'Minor', 'Min', 'OS', or 'Full'"; ++ return "ServerTokens takes 1 argument, 'Prod', 'Major', 'Minor', 'Min', 'OS', 'Full' or 'Full-Release'"; + } + + return NULL; diff --git a/SOURCES/httpd-2.4.6-http-protocol-options-define.patch b/SOURCES/httpd-2.4.6-http-protocol-options-define.patch new file mode 100644 index 0000000..eb6e5e5 --- /dev/null +++ b/SOURCES/httpd-2.4.6-http-protocol-options-define.patch @@ -0,0 +1,17 @@ +diff --git a/server/main.c b/server/main.c +index 28d1872..544882d 100644 +--- a/server/main.c ++++ b/server/main.c +@@ -478,6 +478,12 @@ int main(int argc, const char * const argv[]) + ap_server_post_read_config = apr_array_make(pcommands, 1, sizeof(char *)); + ap_server_config_defines = apr_array_make(pcommands, 1, sizeof(char *)); + ++ { ++ char **new = (char **)apr_array_push(ap_server_config_defines); ++ ++ *new = "_RH_HAS_HTTPPROTOCOLOPTIONS"; ++ } ++ + error = ap_setup_prelinked_modules(process); + if (error) { + ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_EMERG, 0, NULL, APLOGNO(00012) diff --git a/SOURCES/httpd-2.4.6-ldaprefer.patch b/SOURCES/httpd-2.4.6-ldaprefer.patch new file mode 100644 index 0000000..29b79c9 --- /dev/null +++ b/SOURCES/httpd-2.4.6-ldaprefer.patch @@ -0,0 +1,73 @@ +http://svn.apache.org/viewvc/httpd/httpd/trunk/modules/ldap/util_ldap.c?r1=1517388&r2=1517387&pathrev=1517388&view=patch + +--- trunk/modules/ldap/util_ldap.c 2013/08/25 21:46:27 1517387 ++++ trunk/modules/ldap/util_ldap.c 2013/08/25 22:42:29 1517388 +@@ -60,6 +60,7 @@ + #endif + + #define AP_LDAP_HOPLIMIT_UNSET -1 ++#define AP_LDAP_CHASEREFERRALS_SDKDEFAULT -1 + #define AP_LDAP_CHASEREFERRALS_OFF 0 + #define AP_LDAP_CHASEREFERRALS_ON 1 + +@@ -371,7 +372,7 @@ + ldap_option = ldc->deref; + ldap_set_option(ldc->ldap, LDAP_OPT_DEREF, &ldap_option); + +- if (ldc->ChaseReferrals == AP_LDAP_CHASEREFERRALS_ON) { ++ if (ldc->ChaseReferrals != AP_LDAP_CHASEREFERRALS_SDKDEFAULT) { + /* Set options for rebind and referrals. */ + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, APLOGNO(01278) + "LDAP: Setting referrals to %s.", +@@ -391,7 +392,9 @@ + uldap_connection_unbind(ldc); + return(result->rc); + } ++ } + ++ if (ldc->ChaseReferrals == AP_LDAP_CHASEREFERRALS_ON) { + if ((ldc->ReferralHopLimit != AP_LDAP_HOPLIMIT_UNSET) && ldc->ChaseReferrals == AP_LDAP_CHASEREFERRALS_ON) { + /* Referral hop limit - only if referrals are enabled and a hop limit is explicitly requested */ + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, APLOGNO(01280) +@@ -2584,15 +2587,25 @@ + + static const char *util_ldap_set_chase_referrals(cmd_parms *cmd, + void *config, +- int mode) ++ const char *arg) + { + util_ldap_config_t *dc = config; + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01311) +- "LDAP: Setting referral chasing %s", +- (mode == AP_LDAP_CHASEREFERRALS_ON) ? "ON" : "OFF"); ++ "LDAP: Setting referral chasing %s", arg); + +- dc->ChaseReferrals = mode; ++ if (0 == strcasecmp(arg, "on")) { ++ dc->ChaseReferrals = AP_LDAP_CHASEREFERRALS_ON; ++ } ++ else if (0 == strcasecmp(arg, "off")) { ++ dc->ChaseReferrals = AP_LDAP_CHASEREFERRALS_OFF; ++ } ++ else if (0 == strcasecmp(arg, "default")) { ++ dc->ChaseReferrals = AP_LDAP_CHASEREFERRALS_SDKDEFAULT; ++ } ++ else { ++ return "LDAPReferrals must be 'on', 'off', or 'default'"; ++ } + + return(NULL); + } +@@ -3116,9 +3129,9 @@ + "Specify the LDAP socket connection timeout in seconds " + "(default: 10)"), + +- AP_INIT_FLAG("LDAPReferrals", util_ldap_set_chase_referrals, ++ AP_INIT_TAKE1("LDAPReferrals", util_ldap_set_chase_referrals, + NULL, OR_AUTHCFG, +- "Choose whether referrals are chased ['ON'|'OFF']. Default 'ON'"), ++ "Choose whether referrals are chased ['ON'|'OFF'|'DEFAULT']. Default 'ON'"), + + AP_INIT_TAKE1("LDAPReferralHopLimit", util_ldap_set_referral_hop_limit, + NULL, OR_AUTHCFG, diff --git a/SOURCES/httpd-2.4.6-mod_authz_dbd-missing-query.patch b/SOURCES/httpd-2.4.6-mod_authz_dbd-missing-query.patch new file mode 100644 index 0000000..a763f89 --- /dev/null +++ b/SOURCES/httpd-2.4.6-mod_authz_dbd-missing-query.patch @@ -0,0 +1,55 @@ +diff --git a/modules/aaa/mod_authz_dbd.c b/modules/aaa/mod_authz_dbd.c +index 1a456fe..6a0f705 100644 +--- a/modules/aaa/mod_authz_dbd.c ++++ b/modules/aaa/mod_authz_dbd.c +@@ -116,7 +116,7 @@ static int authz_dbd_login(request_rec *r, authz_dbd_cfg *cfg, + const char *newuri = NULL; + int nrows; + const char *message; +- ap_dbd_t *dbd = dbd_handle(r); ++ ap_dbd_t *dbd; + apr_dbd_prepared_t *query; + apr_dbd_results_t *res = NULL; + apr_dbd_row_t *row = NULL; +@@ -126,6 +126,16 @@ static int authz_dbd_login(request_rec *r, authz_dbd_cfg *cfg, + "No query configured for %s!", action); + return HTTP_INTERNAL_SERVER_ERROR; + } ++ ++ dbd = dbd_handle(r); ++ if (dbd == NULL) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02902) ++ "No db handle available for %s! " ++ "Check your database access", ++ action); ++ return HTTP_INTERNAL_SERVER_ERROR; ++ } ++ + query = apr_hash_get(dbd->prepared, cfg->query, APR_HASH_KEY_STRING); + if (query == NULL) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01643) +@@ -202,7 +212,7 @@ static int authz_dbd_group_query(request_rec *r, authz_dbd_cfg *cfg, + /* SELECT group FROM authz WHERE user = %s */ + int rv; + const char *message; +- ap_dbd_t *dbd = dbd_handle(r); ++ ap_dbd_t *dbd; + apr_dbd_prepared_t *query; + apr_dbd_results_t *res = NULL; + apr_dbd_row_t *row = NULL; +@@ -212,6 +222,15 @@ static int authz_dbd_group_query(request_rec *r, authz_dbd_cfg *cfg, + "No query configured for dbd-group!"); + return HTTP_INTERNAL_SERVER_ERROR; + } ++ ++ dbd = dbd_handle(r); ++ if (dbd == NULL) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02903) ++ "No db handle available for dbd-query! " ++ "Check your database access"); ++ return HTTP_INTERNAL_SERVER_ERROR; ++ } ++ + query = apr_hash_get(dbd->prepared, cfg->query, APR_HASH_KEY_STRING); + if (query == NULL) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01650) diff --git a/SOURCES/httpd-2.4.6-mpm-segfault.patch b/SOURCES/httpd-2.4.6-mpm-segfault.patch new file mode 100644 index 0000000..d42be44 --- /dev/null +++ b/SOURCES/httpd-2.4.6-mpm-segfault.patch @@ -0,0 +1,10 @@ +--- a/server/mpm/event/event.c ++++ a/server/mpm/event/event.c +@@ -2735,6 +2735,7 @@ static int event_run(apr_pool_t * _pconf, apr_pool_t * plog, server_rec * s) + + /* 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 */ diff --git a/SOURCES/httpd-2.4.6-pre_htaccess.patch b/SOURCES/httpd-2.4.6-pre_htaccess.patch new file mode 100644 index 0000000..ff7bd5a --- /dev/null +++ b/SOURCES/httpd-2.4.6-pre_htaccess.patch @@ -0,0 +1,140 @@ +diff --git a/include/ap_mmn.h b/include/ap_mmn.h +index 89c4140..82a0acb 100644 +--- a/include/ap_mmn.h ++++ b/include/ap_mmn.h +@@ -418,6 +418,7 @@ + * ap_proxy_pass_brigade() + * 20120211.22 (2.4.5-dev) No longer prevent usage of strtoul() + * 20120211.23 (2.4.5-dev) Add ap_proxy_clear_connection() ++ * 20120211.24 (2.4.7-dev) add open_htaccess hook. + */ + + #define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */ +@@ -425,7 +426,7 @@ + #ifndef MODULE_MAGIC_NUMBER_MAJOR + #define MODULE_MAGIC_NUMBER_MAJOR 20120211 + #endif +-#define MODULE_MAGIC_NUMBER_MINOR 23 /* 0...n */ ++#define MODULE_MAGIC_NUMBER_MINOR 24 /* 0...n */ + + /** + * Determine if the server's current MODULE_MAGIC_NUMBER is at least a +diff --git a/include/http_config.h b/include/http_config.h +index 7ee3760..c93c3b2 100644 +--- a/include/http_config.h ++++ b/include/http_config.h +@@ -1322,6 +1322,31 @@ AP_DECLARE_HOOK(int,quick_handler,(request_rec *r, int lookup_uri)) + AP_DECLARE_HOOK(void,optional_fn_retrieve,(void)) + + /** ++ * Allow modules to open htaccess files or perform operations before doing so ++ * @param r The current request ++ * @param dir_name The directory for which the htaccess file should be opened ++ * @param access_name The filename for which the htaccess file should be opened ++ * @param conffile Where the pointer to the opened ap_configfile_t must be ++ * stored ++ * @param full_name Where the full file name of the htaccess file must be ++ * stored. ++ * @return APR_SUCCESS on success, ++ * APR_ENOENT or APR_ENOTDIR if no htaccess file exists, ++ * AP_DECLINED to let later modules do the opening, ++ * any other error code on error. ++ */ ++AP_DECLARE_HOOK(apr_status_t,open_htaccess, ++ (request_rec *r, const char *dir_name, const char *access_name, ++ ap_configfile_t **conffile, const char **full_name)) ++ ++/** ++ * Core internal function, use ap_run_open_htaccess() instead. ++ */ ++apr_status_t ap_open_htaccess(request_rec *r, const char *dir_name, ++ const char *access_name, ap_configfile_t **conffile, ++ const char **full_name); ++ ++/** + * A generic pool cleanup that will reset a pointer to NULL. For use with + * apr_pool_cleanup_register. + * @param data The address of the pointer +diff --git a/server/config.c b/server/config.c +index c1aae17..265744e 100644 +--- a/server/config.c ++++ b/server/config.c +@@ -80,6 +80,7 @@ APR_HOOK_STRUCT( + APR_HOOK_LINK(quick_handler) + APR_HOOK_LINK(optional_fn_retrieve) + APR_HOOK_LINK(test_config) ++ APR_HOOK_LINK(open_htaccess) + ) + + AP_IMPLEMENT_HOOK_RUN_ALL(int, header_parser, +@@ -171,6 +172,12 @@ AP_IMPLEMENT_HOOK_RUN_FIRST(int, handler, (request_rec *r), + AP_IMPLEMENT_HOOK_RUN_FIRST(int, quick_handler, (request_rec *r, int lookup), + (r, lookup), DECLINED) + ++AP_IMPLEMENT_HOOK_RUN_FIRST(apr_status_t, open_htaccess, ++ (request_rec *r, const char *dir_name, const char *access_name, ++ ap_configfile_t **conffile, const char **full_name), ++ (r, dir_name, access_name, conffile, full_name), ++ AP_DECLINED) ++ + /* hooks with no args are implemented last, after disabling APR hook probes */ + #if defined(APR_HOOK_PROBES_ENABLED) + #undef APR_HOOK_PROBES_ENABLED +@@ -2073,14 +2080,23 @@ AP_DECLARE(int) ap_process_config_tree(server_rec *s, + return OK; + } + ++apr_status_t ap_open_htaccess(request_rec *r, const char *dir_name, ++ const char *access_name, ++ ap_configfile_t **conffile, ++ const char **full_name) ++{ ++ *full_name = ap_make_full_path(r->pool, dir_name, access_name); ++ return ap_pcfg_openfile(conffile, r->pool, *full_name); ++} ++ + AP_CORE_DECLARE(int) ap_parse_htaccess(ap_conf_vector_t **result, + request_rec *r, int override, + int override_opts, apr_table_t *override_list, +- const char *d, const char *access_name) ++ const char *d, const char *access_names) + { + ap_configfile_t *f = NULL; + cmd_parms parms; +- char *filename = NULL; ++ const char *filename; + const struct htaccess_result *cache; + struct htaccess_result *new; + ap_conf_vector_t *dc = NULL; +@@ -2104,15 +2120,11 @@ AP_CORE_DECLARE(int) ap_parse_htaccess(ap_conf_vector_t **result, + parms.path = apr_pstrdup(r->pool, d); + + /* loop through the access names and find the first one */ +- while (access_name[0]) { +- /* AFAICT; there is no use of the actual 'filename' against +- * any canonicalization, so we will simply take the given +- * name, ignoring case sensitivity and aliases +- */ +- filename = ap_make_full_path(r->pool, d, +- ap_getword_conf(r->pool, &access_name)); +- status = ap_pcfg_openfile(&f, r->pool, filename); ++ while (access_names[0]) { ++ const char *access_name = ap_getword_conf(r->pool, &access_names); + ++ filename = NULL; ++ status = ap_run_open_htaccess(r, d, access_name, &f, &filename); + if (status == APR_SUCCESS) { + const char *errmsg; + ap_directive_t *temptree = NULL; +diff --git a/server/core.c b/server/core.c +index f3965ca..85f876b 100644 +--- a/server/core.c ++++ b/server/core.c +@@ -4930,6 +4930,7 @@ static void register_hooks(apr_pool_t *p) + ap_hook_insert_network_bucket(core_insert_network_bucket, NULL, NULL, + APR_HOOK_REALLY_LAST); + ap_hook_dirwalk_stat(core_dirwalk_stat, NULL, NULL, APR_HOOK_REALLY_LAST); ++ ap_hook_open_htaccess(ap_open_htaccess, NULL, NULL, APR_HOOK_REALLY_LAST); + + /* register the core's insert_filter hook and register core-provided + * filters diff --git a/SOURCES/httpd-2.4.6-r1332643+.patch b/SOURCES/httpd-2.4.6-r1332643+.patch new file mode 100644 index 0000000..cfe6d7b --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1332643+.patch @@ -0,0 +1,313 @@ +# ./pullrev.sh 1332643 1345599 1487772 + +https://bugzilla.redhat.com//show_bug.cgi?id=809599 + +http://svn.apache.org/viewvc?view=revision&revision=1332643 +http://svn.apache.org/viewvc?view=revision&revision=1345599 +http://svn.apache.org/viewvc?view=revision&revision=1487772 + +--- httpd-2.4.6/modules/ssl/mod_ssl.c.r1332643+ ++++ httpd-2.4.6/modules/ssl/mod_ssl.c +@@ -413,6 +413,37 @@ int ssl_engine_disable(conn_rec *c) + return 1; + } + ++static int modssl_register_npn(conn_rec *c, ++ ssl_npn_advertise_protos advertisefn, ++ ssl_npn_proto_negotiated negotiatedfn) ++{ ++#ifdef HAVE_TLS_NPN ++ SSLConnRec *sslconn = myConnConfig(c); ++ ++ if (!sslconn) { ++ return DECLINED; ++ } ++ ++ if (!sslconn->npn_advertfns) { ++ sslconn->npn_advertfns = ++ apr_array_make(c->pool, 5, sizeof(ssl_npn_advertise_protos)); ++ sslconn->npn_negofns = ++ apr_array_make(c->pool, 5, sizeof(ssl_npn_proto_negotiated)); ++ } ++ ++ if (advertisefn) ++ APR_ARRAY_PUSH(sslconn->npn_advertfns, ssl_npn_advertise_protos) = ++ advertisefn; ++ if (negotiatedfn) ++ APR_ARRAY_PUSH(sslconn->npn_negofns, ssl_npn_proto_negotiated) = ++ negotiatedfn; ++ ++ return OK; ++#else ++ return DECLINED; ++#endif ++} ++ + int ssl_init_ssl_connection(conn_rec *c, request_rec *r) + { + SSLSrvConfigRec *sc; +@@ -584,6 +615,7 @@ static void ssl_register_hooks(apr_pool_ + + APR_REGISTER_OPTIONAL_FN(ssl_proxy_enable); + APR_REGISTER_OPTIONAL_FN(ssl_engine_disable); ++ APR_REGISTER_OPTIONAL_FN(modssl_register_npn); + + ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "ssl", + AUTHZ_PROVIDER_VERSION, +--- httpd-2.4.6/modules/ssl/mod_ssl.h.r1332643+ ++++ httpd-2.4.6/modules/ssl/mod_ssl.h +@@ -63,5 +63,40 @@ APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_e + + APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *)); + ++/** The npn_advertise_protos callback allows another 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 callback is given the connection and an APR array; ++ * it should push one or more char*'s pointing to NUL-terminated ++ * strings (such as "http/1.1" or "spdy/2") onto the array and return ++ * OK. To prevent further processing of (other modules') callbacks, ++ * return DONE. */ ++typedef int (*ssl_npn_advertise_protos)(conn_rec *connection, ++ apr_array_header_t *protos); ++ ++/** The npn_proto_negotiated callback 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 callback is given the connection, a ++ * non-NUL-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. To prevent further ++ * processing of (other modules') callbacks, return DONE. */ ++typedef int (*ssl_npn_proto_negotiated)(conn_rec *connection, ++ const char *proto_name, ++ apr_size_t proto_name_len); ++ ++/* An optional function which can be used to register a pair of ++ * callbacks for NPN handling. This optional function should be ++ * invoked from a pre_connection hook which runs *after* mod_ssl.c's ++ * pre_connection hook. The function returns OK if the callbacks are ++ * register, or DECLINED otherwise (for example if mod_ssl does not ++l * support NPN). */ ++APR_DECLARE_OPTIONAL_FN(int, modssl_register_npn, (conn_rec *conn, ++ ssl_npn_advertise_protos advertisefn, ++ ssl_npn_proto_negotiated negotiatedfn)); ++ + #endif /* __MOD_SSL_H__ */ + /** @} */ +--- httpd-2.4.6/modules/ssl/ssl_engine_init.c.r1332643+ ++++ httpd-2.4.6/modules/ssl/ssl_engine_init.c +@@ -725,6 +725,11 @@ static void ssl_init_ctx_callbacks(serve + #endif + + SSL_CTX_set_info_callback(ctx, ssl_callback_Info); ++ ++#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, +--- httpd-2.4.6/modules/ssl/ssl_engine_io.c.r1332643+ ++++ httpd-2.4.6/modules/ssl/ssl_engine_io.c +@@ -297,6 +297,7 @@ typedef struct { + apr_pool_t *pool; + char buffer[AP_IOBUFSIZE]; + ssl_filter_ctx_t *filter_ctx; ++ int npn_finished; /* 1 if NPN has finished, 0 otherwise */ + } bio_filter_in_ctx_t; + + /* +@@ -1400,6 +1401,37 @@ static apr_status_t ssl_io_filter_input( + 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) { ++ SSLConnRec *sslconn = myConnConfig(f->c); ++ const unsigned char *next_proto = NULL; ++ unsigned next_proto_len = 0; ++ int n; ++ ++ if (sslconn->npn_negofns) { ++ 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); ++ ++ for (n = 0; n < sslconn->npn_negofns->nelts; n++) { ++ ssl_npn_proto_negotiated fn = ++ APR_ARRAY_IDX(sslconn->npn_negofns, n, ssl_npn_proto_negotiated); ++ ++ if (fn(f->c, (const char *)next_proto, next_proto_len) == DONE) ++ break; ++ } ++ } ++ ++ inctx->npn_finished = 1; ++ } ++#endif ++ + return APR_SUCCESS; + } + +@@ -1881,6 +1913,7 @@ static void ssl_io_input_add_filter(ssl_ + inctx->block = APR_BLOCK_READ; + inctx->pool = c->pool; + inctx->filter_ctx = filter_ctx; ++ inctx->npn_finished = 0; + } + + /* The request_rec pointer is passed in here only to ensure that the +--- httpd-2.4.6/modules/ssl/ssl_engine_kernel.c.r1332643+ ++++ httpd-2.4.6/modules/ssl/ssl_engine_kernel.c +@@ -2161,6 +2161,97 @@ int ssl_callback_SessionTicket(SSL *ssl, + } + #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 ++ * string in wire format -- a sequence of length-prefixed strings -- indicating ++ * the advertised protocols. Refer to SSL_CTX_set_next_protos_advertised_cb ++ * in OpenSSL for reference. ++ */ ++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); ++ SSLConnRec *sslconn = myConnConfig(c); ++ 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; ++ ++ /* If the connection object is not available, or there are no NPN ++ * hooks registered, then there's nothing for us to do. */ ++ if (c == NULL || sslconn->npn_advertfns == NULL) { ++ return SSL_TLSEXT_ERR_NOACK; ++ } ++ ++ /* Invoke our npn_advertise_protos hook, giving other modules a chance to ++ * add alternate protocol names to advertise. */ ++ protos = apr_array_make(c->pool, 0, sizeof(char *)); ++ for (i = 0; i < sslconn->npn_advertfns->nelts; i++) { ++ ssl_npn_advertise_protos fn = ++ APR_ARRAY_IDX(sslconn->npn_advertfns, i, ssl_npn_advertise_protos); ++ ++ if (fn(c, protos) == DONE) ++ break; ++ } ++ 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. */ ++ size = 0; ++ for (i = 0; i < num_protos; ++i) { ++ 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 skip it. */ ++ if (length > 255) { ++ ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02307) ++ "SSL NPN protocol name too long (length=%u): %s", ++ length, string); ++ 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_NOACK; ++ } ++ ++ /* Now we can build the string. Copy each protocol name string into the ++ * larger string, prefixed by its length. */ ++ 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*); ++ apr_size_t length = strlen(string); ++ if (length > 255) ++ continue; ++ *start = (unsigned char)length; ++ ++start; ++ memcpy(start, string, length * sizeof(unsigned char)); ++ start += length; ++ } ++ ++ /* Success. */ ++ *data_out = data; ++ *size_out = size; ++ return SSL_TLSEXT_ERR_OK; ++} ++ ++#endif /* HAVE_TLS_NPN */ ++ + #ifndef OPENSSL_NO_SRP + + int ssl_callback_SRPServerParams(SSL *ssl, int *ad, void *arg) +--- httpd-2.4.6/modules/ssl/ssl_private.h.r1332643+ ++++ httpd-2.4.6/modules/ssl/ssl_private.h +@@ -98,6 +98,8 @@ + #include + #include + ++#include "mod_ssl.h" ++ + /* Avoid tripping over an engine build installed globally and detected + * when the user points at an explicit non-engine flavor of OpenSSL + */ +@@ -139,6 +141,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 +@@ -487,6 +494,12 @@ typedef struct { + * connection */ + } reneg_state; + ++#ifdef HAVE_TLS_NPN ++ /* Poor man's inter-module optional hooks for NPN. */ ++ apr_array_header_t *npn_advertfns; /* list of ssl_npn_advertise_protos callbacks */ ++ apr_array_header_t *npn_negofns; /* list of ssl_npn_proto_negotiated callbacks. */ ++#endif ++ + server_rec *server; + } SSLConnRec; + +@@ -842,6 +855,7 @@ int ssl_callback_ServerNameIndi + 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 *); diff --git a/SOURCES/httpd-2.4.6-r1348019.patch b/SOURCES/httpd-2.4.6-r1348019.patch new file mode 100644 index 0000000..b8cca1c --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1348019.patch @@ -0,0 +1,77 @@ +diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c +index 2121892..6f904b2 100644 +--- a/modules/proxy/proxy_util.c ++++ b/modules/proxy/proxy_util.c +@@ -2838,33 +2838,48 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, + + connected = 1; + } +- /* +- * Put the entire worker to error state if +- * the PROXY_WORKER_IGNORE_ERRORS flag is not set. +- * Altrough some connections may be alive +- * no further connections to the worker could be made +- */ +- if (!connected && PROXY_WORKER_IS_USABLE(worker) && +- !(worker->s->status & PROXY_WORKER_IGNORE_ERRORS)) { +- worker->s->error_time = apr_time_now(); +- worker->s->status |= PROXY_WORKER_IN_ERROR; +- ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00959) +- "ap_proxy_connect_backend disabling worker for (%s) for %" +- APR_TIME_T_FMT "s", +- worker->s->hostname, apr_time_sec(worker->s->retry)); ++ ++ if (PROXY_WORKER_IS_USABLE(worker)) { ++ /* ++ * Put the entire worker to error state if ++ * the PROXY_WORKER_IGNORE_ERRORS flag is not set. ++ * Although some connections may be alive ++ * no further connections to the worker could be made ++ */ ++ if (!connected) { ++ if (!(worker->s->status & PROXY_WORKER_IGNORE_ERRORS)) { ++ worker->s->error_time = apr_time_now(); ++ worker->s->status |= PROXY_WORKER_IN_ERROR; ++ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00959) ++ "ap_proxy_connect_backend disabling worker for (%s) for %" ++ APR_TIME_T_FMT "s", ++ worker->s->hostname, apr_time_sec(worker->s->retry)); ++ } ++ } ++ else { ++ if (worker->s->retries) { ++ /* ++ * A worker came back. So here is where we need to ++ * either reset all params to initial conditions or ++ * apply some sort of aging ++ */ ++ } ++ worker->s->error_time = 0; ++ worker->s->retries = 0; ++ } ++ return connected ? OK : DECLINED; + } + else { +- if (worker->s->retries) { +- /* +- * A worker came back. So here is where we need to +- * either reset all params to initial conditions or +- * apply some sort of aging +- */ +- } +- worker->s->error_time = 0; +- worker->s->retries = 0; ++ /* ++ * The worker is in error likely done by a different thread / process ++ * e.g. for a timeout or bad status. We should respect this and should ++ * not continue with a connection via this worker even if we got one. ++ */ ++ if (connected) { ++ socket_cleanup(conn); ++ } ++ return DECLINED; + } +- return connected ? OK : DECLINED; + } + + PROXY_DECLARE(int) ap_proxy_connection_create(const char *proxy_function, diff --git a/SOURCES/httpd-2.4.6-r1420184.patch b/SOURCES/httpd-2.4.6-r1420184.patch new file mode 100644 index 0000000..7de3031 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1420184.patch @@ -0,0 +1,154 @@ +Index: modules/aaa/mod_authz_owner.c +=================================================================== +--- a/modules/aaa/mod_authz_owner.c (revision 1420183) ++++ b/modules/aaa/mod_authz_owner.c (revision 1420184) +@@ -28,9 +28,8 @@ + #include "http_request.h" + + #include "mod_auth.h" ++#include "mod_authz_owner.h" + +-APR_DECLARE_OPTIONAL_FN(char*, authz_owner_get_file_group, (request_rec *r)); +- + static const command_rec authz_owner_cmds[] = + { + {NULL} +Index: modules/aaa/mod_authz_owner.h +=================================================================== +--- a/modules/aaa/mod_authz_owner.h (revision 0) ++++ b/modules/aaa/mod_authz_owner.h (revision 1420184) +@@ -0,0 +1,27 @@ ++/* 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. ++ */ ++ ++#ifndef MOD_AUTHZ_OWNER_H ++#define MOD_AUTHZ_OWNER_H ++ ++#include "http_request.h" ++ ++/* mod_authz_owner exports an optional function which retrieves the ++ * group name of the file identified by r->filename, if available, or ++ * else returns NULL. */ ++APR_DECLARE_OPTIONAL_FN(char*, authz_owner_get_file_group, (request_rec *r)); ++ ++#endif /* MOD_AUTHZ_OWNER_H */ +Index: modules/aaa/mod_authz_groupfile.c +=================================================================== +--- a/modules/aaa/mod_authz_groupfile.c (revision 1420183) ++++ b/modules/aaa/mod_authz_groupfile.c (revision 1420184) +@@ -55,13 +55,12 @@ + #include "util_varbuf.h" + + #include "mod_auth.h" ++#include "mod_authz_owner.h" + + typedef struct { + char *groupfile; + } authz_groupfile_config_rec; + +-APR_DECLARE_OPTIONAL_FN(char*, authz_owner_get_file_group, (request_rec *r)); +- + static void *create_authz_groupfile_dir_config(apr_pool_t *p, char *d) + { + authz_groupfile_config_rec *conf = apr_palloc(p, sizeof(*conf)); +@@ -200,7 +199,7 @@ + return AUTHZ_DENIED; + } + +-APR_OPTIONAL_FN_TYPE(authz_owner_get_file_group) *authz_owner_get_file_group; ++static APR_OPTIONAL_FN_TYPE(authz_owner_get_file_group) *authz_owner_get_file_group; + + static authz_status filegroup_check_authorization(request_rec *r, + const char *require_args, +@@ -279,10 +278,14 @@ + NULL, + }; + +-static void register_hooks(apr_pool_t *p) ++ ++static void authz_groupfile_getfns(void) + { + authz_owner_get_file_group = APR_RETRIEVE_OPTIONAL_FN(authz_owner_get_file_group); ++} + ++static void register_hooks(apr_pool_t *p) ++{ + ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "group", + AUTHZ_PROVIDER_VERSION, + &authz_group_provider, +@@ -291,6 +294,7 @@ + AUTHZ_PROVIDER_VERSION, + &authz_filegroup_provider, + AP_AUTH_INTERNAL_PER_CONF); ++ ap_hook_optional_fn_retrieve(authz_groupfile_getfns, NULL, NULL, APR_HOOK_MIDDLE); + } + + AP_DECLARE_MODULE(authz_groupfile) = +Index: modules/aaa/mod_authz_dbm.c +=================================================================== +--- a/modules/aaa/mod_authz_dbm.c (revision 1420183) ++++ b/modules/aaa/mod_authz_dbm.c (revision 1420184) +@@ -29,6 +29,7 @@ + #include "http_request.h" /* for ap_hook_(check_user_id | auth_checker)*/ + + #include "mod_auth.h" ++#include "mod_authz_owner.h" + + typedef struct { + const char *grpfile; +@@ -35,9 +36,7 @@ + const char *dbmtype; + } authz_dbm_config_rec; + +-APR_DECLARE_OPTIONAL_FN(char*, authz_owner_get_file_group, (request_rec *r)); + +- + /* This should go into APR; perhaps with some nice + * caching/locking/flocking of the open dbm file. + */ +@@ -199,7 +198,7 @@ + return AUTHZ_DENIED; + } + +-APR_OPTIONAL_FN_TYPE(authz_owner_get_file_group) *authz_owner_get_file_group; ++static APR_OPTIONAL_FN_TYPE(authz_owner_get_file_group) *authz_owner_get_file_group; + + static authz_status dbmfilegroup_check_authorization(request_rec *r, + const char *require_args, +@@ -279,11 +278,13 @@ + NULL, + }; + ++static void authz_dbm_getfns(void) ++{ ++ authz_owner_get_file_group = APR_RETRIEVE_OPTIONAL_FN(authz_owner_get_file_group); ++} + + static void register_hooks(apr_pool_t *p) + { +- authz_owner_get_file_group = APR_RETRIEVE_OPTIONAL_FN(authz_owner_get_file_group); +- + ap_register_auth_provider(p, AUTHZ_PROVIDER_GROUP, "dbm-group", + AUTHZ_PROVIDER_VERSION, + &authz_dbmgroup_provider, +@@ -292,6 +293,7 @@ + AUTHZ_PROVIDER_VERSION, + &authz_dbmfilegroup_provider, + AP_AUTH_INTERNAL_PER_CONF); ++ ap_hook_optional_fn_retrieve(authz_dbm_getfns, NULL, NULL, APR_HOOK_MIDDLE); + } + + AP_DECLARE_MODULE(authz_dbm) = diff --git a/SOURCES/httpd-2.4.6-r1506474.patch b/SOURCES/httpd-2.4.6-r1506474.patch new file mode 100644 index 0000000..182bc04 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1506474.patch @@ -0,0 +1,13 @@ +--- a/server/core.c 2013/07/24 09:49:38 1506473 ++++ b/server/core.c 2013/07/24 09:51:14 1506474 +@@ -1481,7 +1481,9 @@ + conf->ap_document_root = arg; + } + else { +- return "DocumentRoot must be a directory"; ++ return apr_psprintf(cmd->pool, ++ "DocumentRoot '%s' is not a directory, or is not readable", ++ arg); + } + } + return NULL; diff --git a/SOURCES/httpd-2.4.6-r1507681+.patch b/SOURCES/httpd-2.4.6-r1507681+.patch new file mode 100644 index 0000000..82a3b41 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1507681+.patch @@ -0,0 +1,62 @@ +# ./pullrev.sh 1507681 1533447 + +https://bugzilla.redhat.com/show_bug.cgi?id=1004046 + +http://svn.apache.org/viewvc?view=revision&revision=1507681 +http://svn.apache.org/viewvc?view=revision&revision=1533447 + +--- httpd-2.4.6/modules/dav/main/mod_dav.c ++++ httpd-2.4.6/modules/dav/main/mod_dav.c +@@ -2756,7 +2756,7 @@ + * The multistatus responses will contain the information about any + * resource that fails the validation. + * +- * We check the parent resource, too, since this is a MOVE. Moving the ++ * We check the parent resource, too, if this is a MOVE. Moving the + * resource effectively removes it from the parent collection, so we + * must ensure that we have met the appropriate conditions. + * +@@ -2765,7 +2765,9 @@ + */ + if ((err = dav_validate_request(r, resource, depth, NULL, + &multi_response, +- DAV_VALIDATE_PARENT ++ (is_move ? DAV_VALIDATE_PARENT ++ : DAV_VALIDATE_RESOURCE ++ | DAV_VALIDATE_NO_MODIFY) + | DAV_VALIDATE_USE_424, + NULL)) != NULL) { + err = dav_push_error(r->pool, err->status, 0, +--- httpd-2.4.6/modules/dav/main/util.c ++++ httpd-2.4.6/modules/dav/main/util.c +@@ -954,13 +954,16 @@ + /* + ** For methods other than LOCK: + ** +- ** If we have no locks, then can be set to true -- ++ ** If we have no locks or if the resource is not being modified ++ ** (per RFC 4918 the lock token is not required on resources ++ ** we are not changing), then can be set to true -- + ** pretending that we've already met the requirement of seeing one + ** of the resource's locks in the If: header. + ** + ** Otherwise, it must be cleared and we'll look for one. + */ +- seen_locktoken = (lock_list == NULL); ++ seen_locktoken = (lock_list == NULL ++ || flags & DAV_VALIDATE_NO_MODIFY); + } + + /* +--- httpd-2.4.6/modules/dav/main/mod_dav.h ++++ httpd-2.4.6/modules/dav/main/mod_dav.h +@@ -1297,6 +1297,9 @@ + the 424 DAV:response */ + #define DAV_VALIDATE_USE_424 0x0080 /* return 424 status, not 207 */ + #define DAV_VALIDATE_IS_PARENT 0x0100 /* for internal use */ ++#define DAV_VALIDATE_NO_MODIFY 0x0200 /* resource is not being modified ++ so allow even if lock token ++ is not provided */ + + /* Lock-null related public lock functions */ + DAV_DECLARE(int) dav_get_resource_state(request_rec *r, diff --git a/SOURCES/httpd-2.4.6-r1524368.patch b/SOURCES/httpd-2.4.6-r1524368.patch new file mode 100644 index 0000000..235d977 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1524368.patch @@ -0,0 +1,20 @@ +--- a/modules/proxy/mod_proxy_fcgi.c 2013/09/18 11:17:28 1524367 ++++ b/modules/proxy/mod_proxy_fcgi.c 2013/09/18 11:18:02 1524368 +@@ -429,15 +429,13 @@ + ob = apr_brigade_create(r->pool, c->bucket_alloc); + + while (! done) { +- apr_interval_time_t timeout = conn->worker->s->timeout; ++ apr_interval_time_t timeout; + apr_size_t len; + int n; + + /* We need SOME kind of timeout here, or virtually anything will + * cause timeout errors. */ +- if (! conn->worker->s->timeout_set) { +- timeout = apr_time_from_sec(30); +- } ++ apr_socket_timeout_get(conn->sock, &timeout); + + rv = apr_poll(&pfd, 1, &n, timeout); + if (rv != APR_SUCCESS) { diff --git a/SOURCES/httpd-2.4.6-r1526189.patch b/SOURCES/httpd-2.4.6-r1526189.patch new file mode 100644 index 0000000..f1a7333 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1526189.patch @@ -0,0 +1,62 @@ +diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h +index 81fd14c..cd1710f 100644 +--- a/modules/proxy/mod_proxy.h ++++ b/modules/proxy/mod_proxy.h +@@ -856,6 +856,17 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, + PROXY_DECLARE(int) ap_proxy_connection_create(const char *proxy_function, + proxy_conn_rec *conn, + conn_rec *c, server_rec *s); ++ ++/** ++ * Determine if proxy connection can potentially be reused at the ++ * end of this request. ++ * @param conn proxy connection ++ * @return non-zero if reusable, 0 otherwise ++ * @note Even if this function returns non-zero, the connection may ++ * be subsequently marked for closure. ++ */ ++PROXY_DECLARE(int) ap_proxy_connection_reusable(proxy_conn_rec *conn); ++ + /** + * Signal the upstream chain that the connection to the backend broke in the + * middle of the response. This is done by sending an error bucket with +diff --git a/modules/proxy/mod_proxy_fcgi.c b/modules/proxy/mod_proxy_fcgi.c +index 0f84416..c57696a 100644 +--- a/modules/proxy/mod_proxy_fcgi.c ++++ b/modules/proxy/mod_proxy_fcgi.c +@@ -247,7 +247,7 @@ static apr_status_t send_begin_request(proxy_conn_rec *conn, int request_id) + + brb.roleB1 = ((FCGI_RESPONDER >> 8) & 0xff); + brb.roleB0 = ((FCGI_RESPONDER) & 0xff); +- brb.flags = FCGI_KEEP_CONN; ++ brb.flags = ap_proxy_connection_reusable(conn) ? FCGI_KEEP_CONN : 0; + brb.reserved[0] = 0; + brb.reserved[1] = 0; + brb.reserved[2] = 0; +diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c +index 8bc9fab..ca70ae4 100644 +--- a/modules/proxy/proxy_util.c ++++ b/modules/proxy/proxy_util.c +@@ -1333,6 +1333,13 @@ static void init_conn_pool(apr_pool_t *p, proxy_worker *worker) + worker->cp = cp; + } + ++PROXY_DECLARE(int) ap_proxy_connection_reusable(proxy_conn_rec *conn) ++{ ++ proxy_worker *worker = conn->worker; ++ ++ return ! (conn->close || !worker->s->is_address_reusable || worker->s->disablereuse); ++} ++ + static apr_status_t connection_cleanup(void *theconn) + { + proxy_conn_rec *conn = (proxy_conn_rec *)theconn; +@@ -1361,7 +1368,7 @@ static apr_status_t connection_cleanup(void *theconn) + } + + /* determine if the connection need to be closed */ +- if (conn->close || !worker->s->is_address_reusable || worker->s->disablereuse) { ++ if (!ap_proxy_connection_reusable(conn)) { + apr_pool_t *p = conn->pool; + apr_pool_clear(p); + conn = apr_pcalloc(p, sizeof(proxy_conn_rec)); diff --git a/SOURCES/httpd-2.4.6-r1527509.patch b/SOURCES/httpd-2.4.6-r1527509.patch new file mode 100644 index 0000000..103a460 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1527509.patch @@ -0,0 +1,21 @@ +diff -Npru httpd-2.4.6.orig/modules/dav/main/mod_dav.c httpd-2.4.6/modules/dav/main/mod_dav.c +--- httpd-2.4.6.orig/modules/dav/main/mod_dav.c 2015-06-24 12:24:47.920000000 -0400 ++++ httpd-2.4.6/modules/dav/main/mod_dav.c 2015-06-24 12:27:19.706000000 -0400 +@@ -316,6 +316,8 @@ static int dav_error_response(request_re + { + r->status = status; + ++ r->status_line = ap_get_status_line(status); ++ + ap_set_content_type(r, "text/html; charset=ISO-8859-1"); + + /* begin the response now... */ +@@ -347,6 +349,8 @@ static int dav_error_response_tag(reques + { + r->status = err->status; + ++ r->status_line = ap_get_status_line(err->status); ++ + ap_set_content_type(r, DAV_XML_CONTENT_TYPE); + + ap_rputs(DAV_XML_HEADER DEBUG_CR diff --git a/SOURCES/httpd-2.4.6-r1528556.patch b/SOURCES/httpd-2.4.6-r1528556.patch new file mode 100644 index 0000000..bab51aa --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1528556.patch @@ -0,0 +1,23 @@ +Index: modules/mappers/mod_rewrite.c +=================================================================== +--- a/modules/mappers/mod_rewrite.c (revision 1499025) ++++ b/modules/mappers/mod_rewrite.c (revision 1528556) +@@ -589,6 +589,18 @@ + return 7; + } + break; ++ ++ case 'w': ++ case 'W': ++ if (!strncasecmp(uri, "s://", 4)) { /* ws:// */ ++ *sqs = 1; ++ return 5; ++ } ++ else if (!strncasecmp(uri, "ss://", 5)) { /* wss:// */ ++ *sqs = 1; ++ return 6; ++ } ++ break; + } + + return 0; diff --git a/SOURCES/httpd-2.4.6-r1528958.patch b/SOURCES/httpd-2.4.6-r1528958.patch new file mode 100644 index 0000000..82bfd6e --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1528958.patch @@ -0,0 +1,46 @@ +--- a/server/vhost.c 2013/07/15 11:50:50 1503188 ++++ b/server/vhost.c 2013/10/03 18:31:22 1528958 +@@ -577,14 +577,22 @@ + */ + + for (s = main_s->next; s; s = s->next) { ++ server_addr_rec *sar_prev = NULL; + has_default_vhost_addr = 0; + for (sar = s->addrs; sar; sar = sar->next) { + ipaddr_chain *ic; + char inaddr_any[16] = {0}; /* big enough to handle IPv4 or IPv6 */ +- ++ /* XXX: this treats 0.0.0.0 as a "default" server which matches no-exact-match for IPv6 */ + if (!memcmp(sar->host_addr->ipaddr_ptr, inaddr_any, sar->host_addr->ipaddr_len)) { + ic = find_default_server(sar->host_port); +- if (!ic || sar->host_port != ic->sar->host_port) { ++ ++ if (ic && sar->host_port == ic->sar->host_port) { /* we're a match for an existing "default server" */ ++ if (!sar_prev || memcmp(sar_prev->host_addr->ipaddr_ptr, inaddr_any, sar_prev->host_addr->ipaddr_len) ++ || sar_prev->host_port != sar->host_port) { ++ add_name_vhost_config(p, main_s, s, sar, ic); ++ } ++ } ++ else { + /* No default server, or we found a default server but + ** exactly one of us is a wildcard port, which means we want + ** two ip-based vhosts not an NVH with two names +@@ -592,6 +600,7 @@ + ic = new_ipaddr_chain(p, s, sar); + ic->next = default_list; + default_list = ic; ++ add_name_vhost_config(p, main_s, s, sar, ic); + } + has_default_vhost_addr = 1; + } +@@ -609,8 +618,9 @@ + ic->next = *iphash_table_tail[bucket]; + *iphash_table_tail[bucket] = ic; + } ++ add_name_vhost_config(p, main_s, s, sar, ic); + } +- add_name_vhost_config(p, main_s, s, sar, ic); ++ sar_prev = sar; + } + + /* Ok now we want to set up a server_hostname if the user was diff --git a/SOURCES/httpd-2.4.6-r1530280.patch b/SOURCES/httpd-2.4.6-r1530280.patch new file mode 100644 index 0000000..ea748e1 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1530280.patch @@ -0,0 +1,59 @@ +--- a/modules/http/http_filters.c 2013/10/08 14:17:33 1530279 ++++ b/modules/http/http_filters.c 2013/10/08 14:18:44 1530280 +@@ -825,7 +825,7 @@ + * handler. + * Zap r->status_line if bad. + */ +-static void validate_status_line(request_rec *r) ++static apr_status_t validate_status_line(request_rec *r) + { + char *end; + +@@ -836,15 +836,19 @@ + || (end - 3) != r->status_line + || (len >= 4 && ! apr_isspace(r->status_line[3]))) { + r->status_line = NULL; ++ return APR_EGENERAL; + } + /* Since we passed the above check, we know that length three + * is equivalent to only a 3 digit numeric http status. + * RFC2616 mandates a trailing space, let's add it. + */ +- else if (len == 3) { ++ if (len == 3) { + r->status_line = apr_pstrcat(r->pool, r->status_line, " ", NULL); ++ return APR_EGENERAL; + } ++ return APR_SUCCESS; + } ++ return APR_EGENERAL; + } + + /* +@@ -856,15 +860,25 @@ + static void basic_http_header_check(request_rec *r, + const char **protocol) + { ++ apr_status_t rv; ++ + if (r->assbackwards) { + /* no such thing as a response protocol */ + return; + } + +- validate_status_line(r); ++ rv = validate_status_line(r); + + if (!r->status_line) { + r->status_line = ap_get_status_line(r->status); ++ } else if (rv != APR_SUCCESS) { ++ /* Status line is OK but our own reason phrase ++ * would be preferred if defined ++ */ ++ const char *tmp = ap_get_status_line(r->status); ++ if (!strncmp(tmp, r->status_line, 3)) { ++ r->status_line = tmp; ++ } + } + + /* Note that we must downgrade before checking for force responses. */ diff --git a/SOURCES/httpd-2.4.6-r1530999.patch b/SOURCES/httpd-2.4.6-r1530999.patch new file mode 100644 index 0000000..2c13959 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1530999.patch @@ -0,0 +1,19 @@ +# ./pullrev.sh 1530999 + +http://svn.apache.org/viewvc?view=revision&revision=1530999 + +https://bugzilla.redhat.com/show_bug.cgi?id=1557785 + +--- httpd-2.4.6/server/core_filters.c ++++ httpd-2.4.6/server/core_filters.c +@@ -745,7 +745,9 @@ + pollset.reqevents = APR_POLLOUT; + pollset.desc.s = s; + apr_socket_timeout_get(s, &timeout); +- rv = apr_poll(&pollset, 1, &nsds, timeout); ++ do { ++ rv = apr_poll(&pollset, 1, &nsds, timeout); ++ } while (APR_STATUS_IS_EINTR(rv)); + if (rv != APR_SUCCESS) { + break; + } diff --git a/SOURCES/httpd-2.4.6-r1533448.patch b/SOURCES/httpd-2.4.6-r1533448.patch new file mode 100644 index 0000000..3b90cb1 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1533448.patch @@ -0,0 +1,155 @@ +Index: modules/dav/fs/repos.c +=================================================================== +--- a/modules/dav/fs/repos.c (revision 1533447) ++++ b/modules/dav/fs/repos.c (revision 1533448) +@@ -717,13 +717,13 @@ + resource->pool = r->pool; + + /* make sure the URI does not have a trailing "/" */ +- len = strlen(r->uri); +- if (len > 1 && r->uri[len - 1] == '/') { +- s = apr_pstrmemdup(r->pool, r->uri, len-1); ++ len = strlen(r->unparsed_uri); ++ if (len > 1 && r->unparsed_uri[len - 1] == '/') { ++ s = apr_pstrmemdup(r->pool, r->unparsed_uri, len-1); + resource->uri = s; + } + else { +- resource->uri = r->uri; ++ resource->uri = r->unparsed_uri; + } + + if (r->finfo.filetype != APR_NOFILE) { +@@ -1482,6 +1482,18 @@ + return dav_fs_deleteset(info->pool, resource); + } + ++/* Take an unescaped path component and escape it and append it onto a ++ * dav_buffer for a URI */ ++static apr_size_t dav_fs_append_uri(apr_pool_t *p, dav_buffer *pbuf, ++ const char *path, apr_size_t pad) ++{ ++ const char *epath = ap_escape_uri(p, path); ++ apr_size_t epath_len = strlen(epath); ++ ++ dav_buffer_place_mem(p, pbuf, epath, epath_len + 1, pad); ++ return epath_len; ++} ++ + /* ### move this to dav_util? */ + /* Walk recursively down through directories, * + * including lock-null resources as we go. */ +@@ -1537,6 +1549,7 @@ + } + while ((apr_dir_read(&dirent, APR_FINFO_DIRENT, dirp)) == APR_SUCCESS) { + apr_size_t len; ++ apr_size_t escaped_len; + + len = strlen(dirent.name); + +@@ -1579,7 +1592,7 @@ + + /* copy the file to the URI, too. NOTE: we will pad an extra byte + for the trailing slash later. */ +- dav_buffer_place_mem(pool, &fsctx->uri_buf, dirent.name, len + 1, 1); ++ escaped_len = dav_fs_append_uri(pool, &fsctx->uri_buf, dirent.name, 1); + + /* if there is a secondary path, then do that, too */ + if (fsctx->path2.buf != NULL) { +@@ -1612,7 +1625,7 @@ + fsctx->path2.cur_len += len; + + /* adjust URI length to incorporate subdir and a slash */ +- fsctx->uri_buf.cur_len += len + 1; ++ fsctx->uri_buf.cur_len += escaped_len + 1; + fsctx->uri_buf.buf[fsctx->uri_buf.cur_len - 1] = '/'; + fsctx->uri_buf.buf[fsctx->uri_buf.cur_len] = '\0'; + +@@ -1678,8 +1691,8 @@ + */ + dav_buffer_place_mem(pool, &fsctx->path1, + fsctx->locknull_buf.buf + offset, len + 1, 0); +- dav_buffer_place_mem(pool, &fsctx->uri_buf, +- fsctx->locknull_buf.buf + offset, len + 1, 0); ++ dav_fs_append_uri(pool, &fsctx->uri_buf, ++ fsctx->locknull_buf.buf + offset, 0); + if (fsctx->path2.buf != NULL) { + dav_buffer_place_mem(pool, &fsctx->path2, + fsctx->locknull_buf.buf + offset, +Index: modules/dav/main/mod_dav.c +=================================================================== +--- a/modules/dav/main/mod_dav.c (revision 1533447) ++++ b/modules/dav/main/mod_dav.c (revision 1533448) +@@ -396,11 +396,9 @@ + */ + static const char *dav_xml_escape_uri(apr_pool_t *p, const char *uri) + { +- const char *e_uri = ap_escape_uri(p, uri); +- + /* check the easy case... */ +- if (ap_strchr_c(e_uri, '&') == NULL) +- return e_uri; ++ if (ap_strchr_c(uri, '&') == NULL) ++ return uri; + + /* there was a '&', so more work is needed... sigh. */ + +@@ -408,7 +406,7 @@ + * Note: this is a teeny bit of overkill since we know there are no + * '<' or '>' characters, but who cares. + */ +- return apr_xml_quote_string(p, e_uri, 0); ++ return apr_xml_quote_string(p, uri, 0); + } + + +@@ -604,7 +602,8 @@ + return DONE; + } + +-/* handy function for return values of methods that (may) create things */ ++/* handy function for return values of methods that (may) create things. ++ * locn if provided is assumed to be escaped. */ + static int dav_created(request_rec *r, const char *locn, const char *what, + int replaced) + { +@@ -612,8 +611,6 @@ + + if (locn == NULL) { + locn = r->unparsed_uri; +- } else { +- locn = ap_escape_uri(r->pool, locn); + } + + /* did the target resource already exist? */ +@@ -3004,7 +3001,7 @@ + } + + /* return an appropriate response (HTTP_CREATED or HTTP_NO_CONTENT) */ +- return dav_created(r, lookup.rnew->uri, "Destination", ++ return dav_created(r, lookup.rnew->unparsed_uri, "Destination", + resnew_state == DAV_RESOURCE_EXISTS); + } + +@@ -4610,7 +4607,7 @@ + + /* return an appropriate response (HTTP_CREATED) */ + /* ### spec doesn't say what happens when destination was replaced */ +- return dav_created(r, lookup.rnew->uri, "Binding", 0); ++ return dav_created(r, lookup.rnew->unparsed_uri, "Binding", 0); + } + + +Index: modules/dav/main/mod_dav.h +=================================================================== +--- a/modules/dav/main/mod_dav.h (revision 1533447) ++++ b/modules/dav/main/mod_dav.h (revision 1533448) +@@ -386,7 +386,7 @@ + * REGULAR and WORKSPACE resources, + * and is always 1 for WORKING */ + +- const char *uri; /* the URI for this resource */ ++ const char *uri; /* the escaped URI for this resource */ + + dav_resource_private *info; /* the provider's private info */ + diff --git a/SOURCES/httpd-2.4.6-r1537535.patch b/SOURCES/httpd-2.4.6-r1537535.patch new file mode 100644 index 0000000..dc2c6c9 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1537535.patch @@ -0,0 +1,38 @@ +# ./pullrev.sh 1537535 + +http://svn.apache.org/viewvc?view=revision&revision=1537535 + +--- httpd-2.4.6/modules/ssl/ssl_engine_config.c.r1537535 ++++ httpd-2.4.6/modules/ssl/ssl_engine_config.c +@@ -198,7 +198,7 @@ static SSLSrvConfigRec *ssl_config_serve + SSLSrvConfigRec *sc = apr_palloc(p, sizeof(*sc)); + + sc->mc = NULL; +- sc->enabled = SSL_ENABLED_FALSE; ++ sc->enabled = SSL_ENABLED_UNSET; + sc->proxy_enabled = UNSET; + sc->vhost_id = NULL; /* set during module init */ + sc->vhost_id_len = 0; /* set during module init */ +--- httpd-2.4.6/modules/ssl/ssl_engine_init.c.r1537535 ++++ httpd-2.4.6/modules/ssl/ssl_engine_init.c +@@ -289,13 +289,16 @@ int ssl_init_Module(apr_pool_t *p, apr_p + sc->vhost_id = ssl_util_vhostid(p, s); + sc->vhost_id_len = strlen(sc->vhost_id); + +- if (ap_get_server_protocol(s) && +- strcmp("https", ap_get_server_protocol(s)) == 0) { ++ /* Default to enabled if SSLEngine is not set explicitly, and ++ * the protocol is https. */ ++ if (ap_get_server_protocol(s) ++ && strcmp("https", ap_get_server_protocol(s)) == 0 ++ && sc->enabled == SSL_ENABLED_UNSET) { + sc->enabled = SSL_ENABLED_TRUE; + } + +- /* If sc->enabled is UNSET, then SSL is optional on this vhost */ +- /* Fix up stuff that may not have been set */ ++ /* Fix up stuff that may not have been set. If sc->enabled is ++ * UNSET, then SSL is disabled on this vhost. */ + if (sc->enabled == SSL_ENABLED_UNSET) { + sc->enabled = SSL_ENABLED_FALSE; + } diff --git a/SOURCES/httpd-2.4.6-r1542327.patch b/SOURCES/httpd-2.4.6-r1542327.patch new file mode 100644 index 0000000..b11b535 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1542327.patch @@ -0,0 +1,868 @@ +# ./pullrev.sh 1542327 +http://svn.apache.org/viewvc?view=revision&revision=1542327 + +--- httpd-2.4.6/LAYOUT.r1542327 ++++ httpd-2.4.6/LAYOUT +@@ -108,7 +108,6 @@ modules/ ................ Manditory and + mod_ssl.c ............... main source file containing API structures + mod_ssl.h ............... common header file of mod_ssl + ssl_engine_config.c ..... module configuration handling +- ssl_engine_dh.c ......... DSA/DH support + ssl_engine_init.c ....... module initialization + ssl_engine_io.c ......... I/O support + ssl_engine_kernel.c ..... SSL engine kernel +--- httpd-2.4.6/modules/ssl/config.m4.r1542327 ++++ httpd-2.4.6/modules/ssl/config.m4 +@@ -20,7 +20,6 @@ dnl # list of module object files + ssl_objs="dnl + mod_ssl.lo dnl + ssl_engine_config.lo dnl +-ssl_engine_dh.lo dnl + ssl_engine_init.lo dnl + ssl_engine_io.lo dnl + ssl_engine_kernel.lo dnl +--- httpd-2.4.6/modules/ssl/mod_ssl.c.r1542327 ++++ httpd-2.4.6/modules/ssl/mod_ssl.c +@@ -515,15 +515,6 @@ int ssl_init_ssl_connection(conn_rec *c, + + sslconn->ssl = ssl; + +- /* +- * Configure callbacks for SSL connection +- */ +- SSL_set_tmp_rsa_callback(ssl, ssl_callback_TmpRSA); +- SSL_set_tmp_dh_callback(ssl, ssl_callback_TmpDH); +-#ifndef OPENSSL_NO_EC +- SSL_set_tmp_ecdh_callback(ssl, ssl_callback_TmpECDH); +-#endif +- + SSL_set_verify_result(ssl, X509_V_OK); + + ssl_io_filter_init(c, r, ssl); +--- httpd-2.4.6/modules/ssl/mod_ssl.dsp.r1542327 ++++ httpd-2.4.6/modules/ssl/mod_ssl.dsp +@@ -112,10 +112,6 @@ SOURCE=.\ssl_engine_config.c + # End Source File + # Begin Source File + +-SOURCE=.\ssl_engine_dh.c +-# End Source File +-# Begin Source File +- + SOURCE=.\ssl_engine_init.c + # End Source File + # Begin Source File +--- httpd-2.4.6/modules/ssl/ssl_engine_config.c.r1542327 ++++ httpd-2.4.6/modules/ssl/ssl_engine_config.c +@@ -76,8 +76,6 @@ SSLModConfigRec *ssl_config_global_creat + mc->stapling_mutex = NULL; + #endif + +- memset(mc->pTmpKeys, 0, sizeof(mc->pTmpKeys)); +- + apr_pool_userdata_set(mc, SSL_MOD_CONFIG_KEY, + apr_pool_cleanup_null, + pool); +--- httpd-2.4.6/modules/ssl/ssl_engine_dh.c.r1542327 ++++ httpd-2.4.6/modules/ssl/ssl_engine_dh.c +@@ -1,244 +0,0 @@ +-#if 0 +-=pod +-#endif +- +-/* Licensed to the Apache Software Foundation (ASF) under one or more +- * contributor license agreements. See the NOTICE file distributed with +- * this work for additional information regarding copyright ownership. +- * The ASF licenses this file to You under the Apache License, Version 2.0 +- * (the "License"); you may not use this file except in compliance with +- * the License. You may obtain a copy of the License at +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License is distributed on an "AS IS" BASIS, +- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +- * See the License for the specific language governing permissions and +- * limitations under the License. +- */ +- +-/* _ _ +- * _ __ ___ ___ __| | ___ ___| | mod_ssl +- * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL +- * | | | | | | (_) | (_| | \__ \__ \ | +- * |_| |_| |_|\___/ \__,_|___|___/___/_| +- * |_____| +- * ssl_engine_dh.c +- * Diffie-Hellman Built-in Temporary Parameters +- */ +- +-#include "ssl_private.h" +- +-/* ----BEGIN GENERATED SECTION-------- */ +- +-/* +-** Diffie-Hellman-Parameters: (512 bit) +-** prime: +-** 00:9f:db:8b:8a:00:45:44:f0:04:5f:17:37:d0:ba: +-** 2e:0b:27:4c:df:1a:9f:58:82:18:fb:43:53:16:a1: +-** 6e:37:41:71:fd:19:d8:d8:f3:7c:39:bf:86:3f:d6: +-** 0e:3e:30:06:80:a3:03:0c:6e:4c:37:57:d0:8f:70: +-** e6:aa:87:10:33 +-** generator: 2 (0x2) +-** Diffie-Hellman-Parameters: (1024 bit) +-** prime: +-** 00:d6:7d:e4:40:cb:bb:dc:19:36:d6:93:d3:4a:fd: +-** 0a:d5:0c:84:d2:39:a4:5f:52:0b:b8:81:74:cb:98: +-** bc:e9:51:84:9f:91:2e:63:9c:72:fb:13:b4:b4:d7: +-** 17:7e:16:d5:5a:c1:79:ba:42:0b:2a:29:fe:32:4a: +-** 46:7a:63:5e:81:ff:59:01:37:7b:ed:dc:fd:33:16: +-** 8a:46:1a:ad:3b:72:da:e8:86:00:78:04:5b:07:a7: +-** db:ca:78:74:08:7d:15:10:ea:9f:cc:9d:dd:33:05: +-** 07:dd:62:db:88:ae:aa:74:7d:e0:f4:d6:e2:bd:68: +-** b0:e7:39:3e:0f:24:21:8e:b3 +-** generator: 2 (0x2) +-*/ +- +-static unsigned char dh512_p[] = { +- 0x9F, 0xDB, 0x8B, 0x8A, 0x00, 0x45, 0x44, 0xF0, 0x04, 0x5F, 0x17, 0x37, +- 0xD0, 0xBA, 0x2E, 0x0B, 0x27, 0x4C, 0xDF, 0x1A, 0x9F, 0x58, 0x82, 0x18, +- 0xFB, 0x43, 0x53, 0x16, 0xA1, 0x6E, 0x37, 0x41, 0x71, 0xFD, 0x19, 0xD8, +- 0xD8, 0xF3, 0x7C, 0x39, 0xBF, 0x86, 0x3F, 0xD6, 0x0E, 0x3E, 0x30, 0x06, +- 0x80, 0xA3, 0x03, 0x0C, 0x6E, 0x4C, 0x37, 0x57, 0xD0, 0x8F, 0x70, 0xE6, +- 0xAA, 0x87, 0x10, 0x33, +-}; +-static unsigned char dh512_g[] = { +- 0x02, +-}; +- +-static DH *get_dh512(void) +-{ +- DH *dh; +- +- if (!(dh = DH_new())) { +- return NULL; +- } +- +- dh->p = BN_bin2bn(dh512_p, sizeof(dh512_p), NULL); +- dh->g = BN_bin2bn(dh512_g, sizeof(dh512_g), NULL); +- if (!(dh->p && dh->g)) { +- DH_free(dh); +- return NULL; +- } +- +- return dh; +-} +- +-static unsigned char dh1024_p[] = { +- 0xD6, 0x7D, 0xE4, 0x40, 0xCB, 0xBB, 0xDC, 0x19, 0x36, 0xD6, 0x93, 0xD3, +- 0x4A, 0xFD, 0x0A, 0xD5, 0x0C, 0x84, 0xD2, 0x39, 0xA4, 0x5F, 0x52, 0x0B, +- 0xB8, 0x81, 0x74, 0xCB, 0x98, 0xBC, 0xE9, 0x51, 0x84, 0x9F, 0x91, 0x2E, +- 0x63, 0x9C, 0x72, 0xFB, 0x13, 0xB4, 0xB4, 0xD7, 0x17, 0x7E, 0x16, 0xD5, +- 0x5A, 0xC1, 0x79, 0xBA, 0x42, 0x0B, 0x2A, 0x29, 0xFE, 0x32, 0x4A, 0x46, +- 0x7A, 0x63, 0x5E, 0x81, 0xFF, 0x59, 0x01, 0x37, 0x7B, 0xED, 0xDC, 0xFD, +- 0x33, 0x16, 0x8A, 0x46, 0x1A, 0xAD, 0x3B, 0x72, 0xDA, 0xE8, 0x86, 0x00, +- 0x78, 0x04, 0x5B, 0x07, 0xA7, 0xDB, 0xCA, 0x78, 0x74, 0x08, 0x7D, 0x15, +- 0x10, 0xEA, 0x9F, 0xCC, 0x9D, 0xDD, 0x33, 0x05, 0x07, 0xDD, 0x62, 0xDB, +- 0x88, 0xAE, 0xAA, 0x74, 0x7D, 0xE0, 0xF4, 0xD6, 0xE2, 0xBD, 0x68, 0xB0, +- 0xE7, 0x39, 0x3E, 0x0F, 0x24, 0x21, 0x8E, 0xB3, +-}; +-static unsigned char dh1024_g[] = { +- 0x02, +-}; +- +-static DH *get_dh1024(void) +-{ +- DH *dh; +- +- if (!(dh = DH_new())) { +- return NULL; +- } +- +- dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL); +- dh->g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL); +- if (!(dh->p && dh->g)) { +- DH_free(dh); +- return NULL; +- } +- +- return dh; +-} +- +-/* ----END GENERATED SECTION---------- */ +- +-DH *ssl_dh_GetTmpParam(int nKeyLen) +-{ +- DH *dh; +- +- if (nKeyLen == 512) +- dh = get_dh512(); +- else if (nKeyLen == 1024) +- dh = get_dh1024(); +- else +- dh = get_dh1024(); +- return dh; +-} +- +-DH *ssl_dh_GetParamFromFile(char *file) +-{ +- DH *dh = NULL; +- BIO *bio; +- +- if ((bio = BIO_new_file(file, "r")) == NULL) +- return NULL; +- dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); +- BIO_free(bio); +- return (dh); +-} +- +-/* +-=cut +-## +-## Embedded Perl script for generating the temporary DH parameters +-## +- +-require 5.003; +-use strict; +- +-# configuration +-my $file = $0; +-my $begin = '----BEGIN GENERATED SECTION--------'; +-my $end = '----END GENERATED SECTION----------'; +- +-# read ourself and keep a backup +-open(FP, "<$file") || die; +-my $source = ''; +-$source .= $_ while (); +-close(FP); +-open(FP, ">$file.bak") || die; +-print FP $source; +-close(FP); +- +-# generate the DH parameters +-print "1. Generate 512 and 1024 bit Diffie-Hellman parameters (p, g)\n"; +-my $rand = ''; +-foreach $file (qw(/var/log/messages /var/adm/messages +- /kernel /vmunix /vmlinuz /etc/hosts /etc/resolv.conf)) { +- if (-f $file) { +- $rand = $file if ($rand eq ''); +- $rand .= ":$file" if ($rand ne ''); +- } +-} +-$rand = "-rand $rand" if ($rand ne ''); +-system("openssl gendh $rand -out dh512.pem 512"); +-system("openssl gendh $rand -out dh1024.pem 1024"); +- +-# generate DH param info +-my $dhinfo = ''; +-open(FP, "openssl dh -noout -text -in dh512.pem |") || die; +-$dhinfo .= $_ while (); +-close(FP); +-open(FP, "openssl dh -noout -text -in dh1024.pem |") || die; +-$dhinfo .= $_ while (); +-close(FP); +-$dhinfo =~ s|^|** |mg; +-$dhinfo = "\n\/\*\n$dhinfo\*\/\n\n"; +- +-my $indent_args = "-i4 -npsl -di0 -br -nce -d0 -cli0 -npcs -nfc1"; +- +-# generate C source from DH params +-my $dhsource = ''; +-open(FP, "openssl dh -noout -C -in dh512.pem | indent $indent_args | expand |") || die; +-$dhsource .= $_ while (); +-close(FP); +-open(FP, "openssl dh -noout -C -in dh1024.pem | indent $indent_args | expand |") || die; +-$dhsource .= $_ while (); +-close(FP); +-$dhsource =~ s|(DH\s+\*get_dh)(\d+)[^}]*\n}|static $1$2(void) +-{ +- DH *dh; +- +- if (!(dh = DH_new())) { +- return NULL; +- } +- +- dh->p = BN_bin2bn(dh$2_p, sizeof(dh$2_p), NULL); +- dh->g = BN_bin2bn(dh$2_g, sizeof(dh$2_g), NULL); +- if (!(dh->p && dh->g)) { +- DH_free(dh); +- return NULL; +- } +- +- return dh; +-} +-|sg; +- +-# generate output +-my $o = $dhinfo . $dhsource; +- +-# insert the generated code at the target location +-$source =~ s|(\/\* $begin.+?\n).*\n(.*?\/\* $end)|$1$o$2|s; +- +-# and update the source on disk +-print "Updating file `$file'\n"; +-open(FP, ">$file") || die; +-print FP $source; +-close(FP); +- +-# cleanup +-unlink("dh512.pem"); +-unlink("dh1024.pem"); +- +-=pod +-*/ +--- httpd-2.4.6/modules/ssl/ssl_engine_init.c.r1542327 ++++ httpd-2.4.6/modules/ssl/ssl_engine_init.c +@@ -56,180 +56,6 @@ static void ssl_add_version_components(a + modver, AP_SERVER_BASEVERSION, incver); + } + +- +-/* +- * Handle the Temporary RSA Keys and DH Params +- */ +- +-#define MODSSL_TMP_KEY_FREE(mc, type, idx) \ +- if (mc->pTmpKeys[idx]) { \ +- type##_free((type *)mc->pTmpKeys[idx]); \ +- mc->pTmpKeys[idx] = NULL; \ +- } +- +-#define MODSSL_TMP_KEYS_FREE(mc, type) \ +- MODSSL_TMP_KEY_FREE(mc, type, SSL_TMP_KEY_##type##_512); \ +- MODSSL_TMP_KEY_FREE(mc, type, SSL_TMP_KEY_##type##_1024) +- +-static void ssl_tmp_keys_free(server_rec *s) +-{ +- SSLModConfigRec *mc = myModConfig(s); +- +- MODSSL_TMP_KEYS_FREE(mc, RSA); +- MODSSL_TMP_KEYS_FREE(mc, DH); +-#ifndef OPENSSL_NO_EC +- MODSSL_TMP_KEY_FREE(mc, EC_KEY, SSL_TMP_KEY_EC_256); +-#endif +-} +- +-static int ssl_tmp_key_init_rsa(server_rec *s, +- int bits, int idx) +-{ +- SSLModConfigRec *mc = myModConfig(s); +- +-#ifdef HAVE_FIPS +- +- if (FIPS_mode() && bits < 1024) { +- mc->pTmpKeys[idx] = NULL; +- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01877) +- "Init: Skipping generating temporary " +- "%d bit RSA private key in FIPS mode", bits); +- return OK; +- } +- +-#endif +-#ifdef HAVE_GENERATE_EX +- { +- RSA *tkey; +- BIGNUM *bn_f4; +- if (!(tkey = RSA_new()) +- || !(bn_f4 = BN_new()) +- || !BN_set_word(bn_f4, RSA_F4) +- || !RSA_generate_key_ex(tkey, bits, bn_f4, NULL)) +- { +- ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01878) +- "Init: Failed to generate temporary " +- "%d bit RSA private key", bits); +- ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s); +- return !OK; +- } +- BN_free(bn_f4); +- mc->pTmpKeys[idx] = tkey; +- } +-#else +- if (!(mc->pTmpKeys[idx] = +- RSA_generate_key(bits, RSA_F4, NULL, NULL))) +- { +- ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01879) +- "Init: Failed to generate temporary " +- "%d bit RSA private key", bits); +- ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s); +- return !OK; +- } +-#endif +- +- return OK; +-} +- +-static int ssl_tmp_key_init_dh(server_rec *s, +- int bits, int idx) +-{ +- SSLModConfigRec *mc = myModConfig(s); +- +-#ifdef HAVE_FIPS +- +- if (FIPS_mode() && bits < 1024) { +- mc->pTmpKeys[idx] = NULL; +- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01880) +- "Init: Skipping generating temporary " +- "%d bit DH parameters in FIPS mode", bits); +- return OK; +- } +- +-#endif +- +- if (!(mc->pTmpKeys[idx] = +- ssl_dh_GetTmpParam(bits))) +- { +- ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01881) +- "Init: Failed to generate temporary " +- "%d bit DH parameters", bits); +- return !OK; +- } +- +- return OK; +-} +- +-#ifndef OPENSSL_NO_EC +-static int ssl_tmp_key_init_ec(server_rec *s, +- int bits, int idx) +-{ +- SSLModConfigRec *mc = myModConfig(s); +- EC_KEY *ecdh = NULL; +- +- /* XXX: Are there any FIPS constraints we should enforce? */ +- +- if (bits != 256) { +- ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02298) +- "Init: Failed to generate temporary " +- "%d bit EC parameters, only 256 bits supported", bits); +- return !OK; +- } +- +- if ((ecdh = EC_KEY_new()) == NULL || +- EC_KEY_set_group(ecdh, EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)) != 1) +- { +- ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02299) +- "Init: Failed to generate temporary " +- "%d bit EC parameters", bits); +- return !OK; +- } +- +- mc->pTmpKeys[idx] = ecdh; +- return OK; +-} +- +-#define MODSSL_TMP_KEY_INIT_EC(s, bits) \ +- ssl_tmp_key_init_ec(s, bits, SSL_TMP_KEY_EC_##bits) +- +-#endif +- +-#define MODSSL_TMP_KEY_INIT_RSA(s, bits) \ +- ssl_tmp_key_init_rsa(s, bits, SSL_TMP_KEY_RSA_##bits) +- +-#define MODSSL_TMP_KEY_INIT_DH(s, bits) \ +- ssl_tmp_key_init_dh(s, bits, SSL_TMP_KEY_DH_##bits) +- +-static int ssl_tmp_keys_init(server_rec *s) +-{ +- ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s, +- "Init: Generating temporary RSA private keys (512/1024 bits)"); +- +- if (MODSSL_TMP_KEY_INIT_RSA(s, 512) || +- MODSSL_TMP_KEY_INIT_RSA(s, 1024)) { +- return !OK; +- } +- +- ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s, +- "Init: Generating temporary DH parameters (512/1024 bits)"); +- +- if (MODSSL_TMP_KEY_INIT_DH(s, 512) || +- MODSSL_TMP_KEY_INIT_DH(s, 1024)) { +- return !OK; +- } +- +-#ifndef OPENSSL_NO_EC +- ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s, +- "Init: Generating temporary EC parameters (256 bits)"); +- +- if (MODSSL_TMP_KEY_INIT_EC(s, 256)) { +- return !OK; +- } +-#endif +- +- return OK; +-} +- + /* + * Per-module initialization + */ +@@ -370,10 +196,6 @@ int ssl_init_Module(apr_pool_t *p, apr_p + */ + ssl_pphrase_Handle(base_server, ptemp); + +- if (ssl_tmp_keys_init(base_server)) { +- return !OK; +- } +- + /* + * initialize the mutex handling + */ +@@ -681,6 +503,9 @@ static void ssl_init_ctx_protocol(server + * Configure additional context ingredients + */ + SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE); ++#ifndef OPENSSL_NO_EC ++ SSL_CTX_set_options(ctx, SSL_OP_SINGLE_ECDH_USE); ++#endif + + #ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION + /* +@@ -721,11 +546,7 @@ static void ssl_init_ctx_callbacks(serve + { + SSL_CTX *ctx = mctx->ssl_ctx; + +- SSL_CTX_set_tmp_rsa_callback(ctx, ssl_callback_TmpRSA); + SSL_CTX_set_tmp_dh_callback(ctx, ssl_callback_TmpDH); +-#ifndef OPENSSL_NO_EC +- SSL_CTX_set_tmp_ecdh_callback(ctx,ssl_callback_TmpECDH); +-#endif + + SSL_CTX_set_info_callback(ctx, ssl_callback_Info); + +@@ -1165,12 +986,16 @@ static void ssl_init_server_certs(server + modssl_ctx_t *mctx) + { + const char *rsa_id, *dsa_id; +-#ifndef OPENSSL_NO_EC ++#ifndef OPENSSL_NO_EC + const char *ecc_id; ++ EC_GROUP *ecparams; ++ int nid; ++ EC_KEY *eckey; + #endif + const char *vhost_id = mctx->sc->vhost_id; + int i; + int have_rsa, have_dsa; ++ DH *dhparams; + #ifndef OPENSSL_NO_EC + int have_ecc; + #endif +@@ -1217,6 +1042,40 @@ static void ssl_init_server_certs(server + "Oops, no " KEYTYPES " server private key found?!"); + ssl_die(s); + } ++ ++ /* ++ * Try to read DH parameters from the (first) SSLCertificateFile ++ */ ++ if ((mctx->pks->cert_files[0] != NULL) && ++ (dhparams = ssl_dh_GetParamFromFile(mctx->pks->cert_files[0]))) { ++ SSL_CTX_set_tmp_dh(mctx->ssl_ctx, dhparams); ++ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02540) ++ "Custom DH parameters (%d bits) for %s loaded from %s", ++ BN_num_bits(dhparams->p), vhost_id, ++ mctx->pks->cert_files[0]); ++ } ++ ++#ifndef OPENSSL_NO_EC ++ /* ++ * Similarly, try to read the ECDH curve name from SSLCertificateFile... ++ */ ++ if ((mctx->pks->cert_files[0] != NULL) && ++ (ecparams = ssl_ec_GetParamFromFile(mctx->pks->cert_files[0])) && ++ (nid = EC_GROUP_get_curve_name(ecparams)) && ++ (eckey = EC_KEY_new_by_curve_name(nid))) { ++ SSL_CTX_set_tmp_ecdh(mctx->ssl_ctx, eckey); ++ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02541) ++ "ECDH curve %s for %s specified in %s", ++ OBJ_nid2sn(nid), vhost_id, mctx->pks->cert_files[0]); ++ } ++ /* ++ * ...otherwise, configure NIST P-256 (required to enable ECDHE) ++ */ ++ else { ++ SSL_CTX_set_tmp_ecdh(mctx->ssl_ctx, ++ EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); ++ } ++#endif + } + + #ifdef HAVE_TLS_SESSION_TICKETS +@@ -1754,11 +1613,6 @@ apr_status_t ssl_init_ModuleKill(void *d + ssl_scache_kill(base_server); + + /* +- * Destroy the temporary keys and params +- */ +- ssl_tmp_keys_free(base_server); +- +- /* + * Free the non-pool allocated structures + * in the per-server configurations + */ +--- httpd-2.4.6/modules/ssl/ssl_engine_kernel.c.r1542327 ++++ httpd-2.4.6/modules/ssl/ssl_engine_kernel.c +@@ -1289,117 +1289,70 @@ const authz_provider ssl_authz_provider_ + */ + + /* +- * Handle out temporary RSA private keys on demand +- * +- * The background of this as the TLSv1 standard explains it: +- * +- * | D.1. Temporary RSA keys +- * | +- * | US Export restrictions limit RSA keys used for encryption to 512 +- * | bits, but do not place any limit on lengths of RSA keys used for +- * | signing operations. Certificates often need to be larger than 512 +- * | bits, since 512-bit RSA keys are not secure enough for high-value +- * | transactions or for applications requiring long-term security. Some +- * | certificates are also designated signing-only, in which case they +- * | cannot be used for key exchange. +- * | +- * | When the public key in the certificate cannot be used for encryption, +- * | the server signs a temporary RSA key, which is then exchanged. In +- * | exportable applications, the temporary RSA key should be the maximum +- * | allowable length (i.e., 512 bits). Because 512-bit RSA keys are +- * | relatively insecure, they should be changed often. For typical +- * | electronic commerce applications, it is suggested that keys be +- * | changed daily or every 500 transactions, and more often if possible. +- * | Note that while it is acceptable to use the same temporary key for +- * | multiple transactions, it must be signed each time it is used. +- * | +- * | RSA key generation is a time-consuming process. In many cases, a +- * | low-priority process can be assigned the task of key generation. +- * | Whenever a new key is completed, the existing temporary key can be +- * | replaced with the new one. +- * +- * XXX: base on comment above, if thread support is enabled, +- * we should spawn a low-priority thread to generate new keys +- * on the fly. +- * +- * So we generated 512 and 1024 bit temporary keys on startup +- * which we now just hand out on demand.... ++ * Grab well-defined DH parameters from OpenSSL, see ++ * (get_rfc*) for all available primes. + */ +- +-RSA *ssl_callback_TmpRSA(SSL *ssl, int export, int keylen) +-{ +- conn_rec *c = (conn_rec *)SSL_get_app_data(ssl); +- SSLModConfigRec *mc = myModConfigFromConn(c); +- int idx; +- +- ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, +- "handing out temporary %d bit RSA key", keylen); +- +- /* doesn't matter if export flag is on, +- * we won't be asked for keylen > 512 in that case. +- * if we are asked for a keylen > 1024, it is too expensive +- * to generate on the fly. +- * XXX: any reason not to generate 2048 bit keys at startup? +- */ +- +- switch (keylen) { +- case 512: +- idx = SSL_TMP_KEY_RSA_512; +- break; +- +- case 1024: +- default: +- idx = SSL_TMP_KEY_RSA_1024; +- } +- +- return (RSA *)mc->pTmpKeys[idx]; ++#define make_get_dh(rfc,size,gen) \ ++static DH *get_dh##size(void) \ ++{ \ ++ DH *dh; \ ++ if (!(dh = DH_new())) { \ ++ return NULL; \ ++ } \ ++ dh->p = get_##rfc##_prime_##size(NULL); \ ++ BN_dec2bn(&dh->g, #gen); \ ++ if (!dh->p || !dh->g) { \ ++ DH_free(dh); \ ++ return NULL; \ ++ } \ ++ return dh; \ + } + + /* +- * Hand out the already generated DH parameters... ++ * Prepare DH parameters from 1024 to 4096 bits, in 1024-bit increments ++ */ ++make_get_dh(rfc2409, 1024, 2) ++make_get_dh(rfc3526, 2048, 2) ++make_get_dh(rfc3526, 3072, 2) ++make_get_dh(rfc3526, 4096, 2) ++ ++/* ++ * Hand out standard DH parameters, based on the authentication strength + */ + DH *ssl_callback_TmpDH(SSL *ssl, int export, int keylen) + { + conn_rec *c = (conn_rec *)SSL_get_app_data(ssl); +- SSLModConfigRec *mc = myModConfigFromConn(c); +- int idx; +- +- ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, +- "handing out temporary %d bit DH key", keylen); ++ EVP_PKEY *pkey = SSL_get_privatekey(ssl); ++ int type = pkey ? EVP_PKEY_type(pkey->type) : EVP_PKEY_NONE; + +- switch (keylen) { +- case 512: +- idx = SSL_TMP_KEY_DH_512; +- break; +- +- case 1024: +- default: +- idx = SSL_TMP_KEY_DH_1024; ++ /* ++ * OpenSSL will call us with either keylen == 512 or keylen == 1024 ++ * (see the definition of SSL_EXPORT_PKEYLENGTH in ssl_locl.h). ++ * Adjust the DH parameter length according to the size of the ++ * RSA/DSA private key used for the current connection, and always ++ * use at least 1024-bit parameters. ++ * Note: This may cause interoperability issues with implementations ++ * which limit their DH support to 1024 bit - e.g. Java 7 and earlier. ++ * In this case, SSLCertificateFile can be used to specify fixed ++ * 1024-bit DH parameters (with the effect that OpenSSL skips this ++ * callback). ++ */ ++ if ((type == EVP_PKEY_RSA) || (type == EVP_PKEY_DSA)) { ++ keylen = EVP_PKEY_bits(pkey); + } + +- return (DH *)mc->pTmpKeys[idx]; +-} +- +-#ifndef OPENSSL_NO_EC +-EC_KEY *ssl_callback_TmpECDH(SSL *ssl, int export, int keylen) +-{ +- conn_rec *c = (conn_rec *)SSL_get_app_data(ssl); +- SSLModConfigRec *mc = myModConfigFromConn(c); +- int idx; +- +- /* XXX Uses 256-bit key for now. TODO: support other sizes. */ + ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, +- "handing out temporary 256 bit ECC key"); +- +- switch (keylen) { +- case 256: +- default: +- idx = SSL_TMP_KEY_EC_256; +- } ++ "handing out built-in DH parameters for %d-bit authenticated connection", keylen); + +- return (EC_KEY *)mc->pTmpKeys[idx]; ++ if (keylen >= 4096) ++ return get_dh4096(); ++ else if (keylen >= 3072) ++ return get_dh3072(); ++ else if (keylen >= 2048) ++ return get_dh2048(); ++ else ++ return get_dh1024(); + } +-#endif + + /* + * This OpenSSL callback function is called when OpenSSL +--- httpd-2.4.6/modules/ssl/ssl_private.h.r1542327 ++++ httpd-2.4.6/modules/ssl/ssl_private.h +@@ -310,22 +310,6 @@ typedef int ssl_algo_t; + #define SSL_AIDX_MAX (2) + #endif + +- +-/** +- * Define IDs for the temporary RSA keys and DH params +- */ +- +-#define SSL_TMP_KEY_RSA_512 (0) +-#define SSL_TMP_KEY_RSA_1024 (1) +-#define SSL_TMP_KEY_DH_512 (2) +-#define SSL_TMP_KEY_DH_1024 (3) +-#ifndef OPENSSL_NO_EC +-#define SSL_TMP_KEY_EC_256 (4) +-#define SSL_TMP_KEY_MAX (5) +-#else +-#define SSL_TMP_KEY_MAX (4) +-#endif +- + /** + * Define the SSL options + */ +@@ -547,7 +531,6 @@ typedef struct { + apr_global_mutex_t *pMutex; + apr_array_header_t *aRandSeed; + apr_hash_t *tVHostKeys; +- void *pTmpKeys[SSL_TMP_KEY_MAX]; + + /* Two hash tables of pointers to ssl_asn1_t structures. The + * structures are used to store certificates and private keys +@@ -837,11 +820,7 @@ extern const authz_provider ssl_authz_pr + extern const authz_provider ssl_authz_provider_verify_client; + + /** OpenSSL callbacks */ +-RSA *ssl_callback_TmpRSA(SSL *, int, int); + DH *ssl_callback_TmpDH(SSL *, int, int); +-#ifndef OPENSSL_NO_EC +-EC_KEY *ssl_callback_TmpECDH(SSL *, int, int); +-#endif + int ssl_callback_SSLVerify(int, X509_STORE_CTX *); + int ssl_callback_SSLVerify_CRL(int, X509_STORE_CTX *, conn_rec *); + int ssl_callback_proxy_cert(SSL *ssl, X509 **x509, EVP_PKEY **pkey); +@@ -921,8 +900,10 @@ int ssl_init_ssl_connection(con + void ssl_pphrase_Handle(server_rec *, apr_pool_t *); + + /** Diffie-Hellman Parameter Support */ +-DH *ssl_dh_GetTmpParam(int); +-DH *ssl_dh_GetParamFromFile(char *); ++DH *ssl_dh_GetParamFromFile(const char *); ++#ifndef OPNESSL_NO_EC ++EC_GROUP *ssl_ec_GetParamFromFile(const char *); ++#endif + + unsigned char *ssl_asn1_table_set(apr_hash_t *table, + const char *key, +--- httpd-2.4.6/modules/ssl/ssl_util_ssl.c.r1542327 ++++ httpd-2.4.6/modules/ssl/ssl_util_ssl.c +@@ -483,6 +483,38 @@ BOOL SSL_X509_INFO_load_path(apr_pool_t + + /* _________________________________________________________________ + ** ++** Custom (EC)DH parameter support ++** _________________________________________________________________ ++*/ ++ ++DH *ssl_dh_GetParamFromFile(const char *file) ++{ ++ DH *dh = NULL; ++ BIO *bio; ++ ++ if ((bio = BIO_new_file(file, "r")) == NULL) ++ return NULL; ++ dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); ++ BIO_free(bio); ++ return (dh); ++} ++ ++#ifndef OPENSSL_NO_EC ++EC_GROUP *ssl_ec_GetParamFromFile(const char *file) ++{ ++ EC_GROUP *group = NULL; ++ BIO *bio; ++ ++ if ((bio = BIO_new_file(file, "r")) == NULL) ++ return NULL; ++ group = PEM_read_bio_ECPKParameters(bio, NULL, NULL, NULL); ++ BIO_free(bio); ++ return (group); ++} ++#endif ++ ++/* _________________________________________________________________ ++** + ** Extra Server Certificate Chain Support + ** _________________________________________________________________ + */ diff --git a/SOURCES/httpd-2.4.6-r1553540.patch b/SOURCES/httpd-2.4.6-r1553540.patch new file mode 100644 index 0000000..6677cbb --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1553540.patch @@ -0,0 +1,28 @@ +# ./pullrev.sh 1553540 + +https://bugzilla.redhat.com/show_bug.cgi?id=1040447 + +http://svn.apache.org/viewvc?view=revision&revision=1553540 + +--- httpd-2.4.6/modules/proxy/mod_proxy_http.c ++++ httpd-2.4.6/modules/proxy/mod_proxy_http.c +@@ -710,7 +710,7 @@ + force10 = 0; + } + +- header_brigade = apr_brigade_create(p, origin->bucket_alloc); ++ header_brigade = apr_brigade_create(p, bucket_alloc); + rv = ap_proxy_create_hdrbrgd(p, header_brigade, r, p_conn, + worker, conf, uri, url, server_portstr, + &old_cl_val, &old_te_val); +@@ -1813,6 +1813,10 @@ + } + } while (interim_response && (interim_response < AP_MAX_INTERIM_RESPONSES)); + ++ /* We have to cleanup bb brigade, because buckets inserted to it could be ++ * created from scpool and this pool can be freed before this brigade. */ ++ apr_brigade_cleanup(bb); ++ + /* See define of AP_MAX_INTERIM_RESPONSES for why */ + if (interim_response >= AP_MAX_INTERIM_RESPONSES) { + return ap_proxyerror(r, HTTP_BAD_GATEWAY, diff --git a/SOURCES/httpd-2.4.6-r1556473.patch b/SOURCES/httpd-2.4.6-r1556473.patch new file mode 100644 index 0000000..009baa7 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1556473.patch @@ -0,0 +1,31 @@ +# ./pullrev.sh 1556473 + +https://bugzilla.redhat.com/show_bug.cgi?id=1036666 + +http://svn.apache.org/viewvc?view=revision&revision=1556473 + +--- httpd-2.4.6/modules/ssl/ssl_engine_config.c ++++ httpd-2.4.6/modules/ssl/ssl_engine_config.c +@@ -699,9 +699,20 @@ + #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."; ++ return "This version of OpenSSL does not support enabling " ++ "SSLCompression within sections."; + #endif ++ if (flag) { ++ /* Some (packaged) versions of OpenSSL do not support ++ * compression by default. Enabling this directive would not ++ * have the desired effect, so fail with an error. */ ++ STACK_OF(SSL_COMP) *meths = SSL_COMP_get_compression_methods(); ++ ++ if (sk_SSL_COMP_num(meths) == 0) { ++ return "This version of OpenSSL does not have any compression methods " ++ "available, cannot enable SSLCompression."; ++ } ++ } + sc->compression = flag ? TRUE : FALSE; + return NULL; + #else diff --git a/SOURCES/httpd-2.4.6-r1556818.patch b/SOURCES/httpd-2.4.6-r1556818.patch new file mode 100644 index 0000000..93195e1 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1556818.patch @@ -0,0 +1,26 @@ +# ./pullrev.sh r1556818 +http://svn.apache.org/viewvc?view=revision&revision=r1556818 +--- httpd-2.4.6/modules/aaa/mod_authn_core.c 2014/01/09 14:30:23 1556817 ++++ httpd-2.4.6/modules/aaa/mod_authn_core.c 2014/01/09 14:32:47 1556818 +@@ -179,6 +179,12 @@ + return (void *) authcfg; + } + ++/* Only per-server directive we have is GLOBAL_ONLY */ ++static void *merge_authn_alias_svr_config(apr_pool_t *p, void *basev, void *overridesv) ++{ ++ return basev; ++} ++ + static const authn_provider authn_alias_provider = + { + &authn_alias_check_password, +@@ -373,7 +379,7 @@ + create_authn_core_dir_config, /* dir config creater */ + merge_authn_core_dir_config, /* dir merger --- default is to override */ + create_authn_alias_svr_config, /* server config */ +- NULL, /* merge server config */ ++ merge_authn_alias_svr_config, /* merge server config */ + authn_cmds, + register_hooks /* register hooks */ + }; diff --git a/SOURCES/httpd-2.4.6-r1560093.patch b/SOURCES/httpd-2.4.6-r1560093.patch new file mode 100644 index 0000000..664699a --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1560093.patch @@ -0,0 +1,16 @@ +# ./pullrev.sh 1560093 + +https://bugzilla.redhat.com/show_bug.cgi?id=1331341 + +http://svn.apache.org/viewvc?view=revision&revision=1560093 + +--- httpd-2.4.6/modules/cache/mod_cache.c ++++ httpd-2.4.6/modules/cache/mod_cache.c +@@ -1130,7 +1130,6 @@ + "Content-Range"))) + || ((reason = cache_header_cmp(r->pool, left, right, + "Content-Type"))) +- || ((reason = cache_header_cmp(r->pool, left, right, "Expires"))) + || ((reason = cache_header_cmp(r->pool, left, right, "ETag"))) + || ((reason = cache_header_cmp(r->pool, left, right, + "Last-Modified")))) { diff --git a/SOURCES/httpd-2.4.6-r1569006.patch b/SOURCES/httpd-2.4.6-r1569006.patch new file mode 100644 index 0000000..32dd900 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1569006.patch @@ -0,0 +1,19 @@ +--- a/modules/metadata/mod_remoteip.c 2014/02/17 14:11:38 1569005 ++++ b/modules/metadata/mod_remoteip.c 2014/02/17 14:12:30 1569006 +@@ -246,14 +246,14 @@ + + while (remote) { + +- /* verify c->client_addr is trusted if there is a trusted proxy list ++ /* verify user agent IP against the trusted proxy list + */ + if (config->proxymatch_ip) { + int i; + remoteip_proxymatch_t *match; + match = (remoteip_proxymatch_t *)config->proxymatch_ip->elts; + for (i = 0; i < config->proxymatch_ip->nelts; ++i) { +- if (apr_ipsubnet_test(match[i].ip, c->client_addr)) { ++ if (apr_ipsubnet_test(match[i].ip, temp_sa)) { + internal = match[i].internal; + break; + } diff --git a/SOURCES/httpd-2.4.6-r1570327.patch b/SOURCES/httpd-2.4.6-r1570327.patch new file mode 100644 index 0000000..35cdce8 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1570327.patch @@ -0,0 +1,20 @@ +# ./pullrev.sh 1570327 +http://svn.apache.org/viewvc?view=revision&revision=1570327 + +https://bugzilla.redhat.com/show_bug.cgi?id=1327624 + +--- httpd-2.4.6/server/mpm_unix.c ++++ httpd-2.4.6/server/mpm_unix.c +@@ -742,7 +742,12 @@ + * readers stranded (a number of them could be tied up for + * a while serving time-consuming requests) + */ ++ /* Recall: we only worry about IDLE child processes here */ + for (i = 0; i < num && rv == APR_SUCCESS; i++) { ++ if (ap_scoreboard_image->servers[i][0].status != SERVER_READY || ++ ap_scoreboard_image->servers[i][0].pid == 0) { ++ continue; ++ } + rv = dummy_connection(pod); + } + } diff --git a/SOURCES/httpd-2.4.6-r1573626.patch b/SOURCES/httpd-2.4.6-r1573626.patch new file mode 100644 index 0000000..58d116b --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1573626.patch @@ -0,0 +1,29 @@ +--- a/modules/proxy/mod_proxy.c 2014/03/03 17:28:10 1573625 ++++ b/modules/proxy/mod_proxy.c 2014/03/03 17:28:17 1573626 +@@ -927,8 +927,25 @@ + struct dirconn_entry *list = (struct dirconn_entry *)conf->dirconn->elts; + + /* is this for us? */ +- if (!r->proxyreq || !r->filename || strncmp(r->filename, "proxy:", 6) != 0) ++ if (!r->filename) { + return DECLINED; ++ } ++ ++ if (!r->proxyreq) { ++ /* We may have forced the proxy handler via config or .htaccess */ ++ if (r->handler && ++ strncmp(r->handler, "proxy:", 6) == 0 && ++ strncmp(r->filename, "proxy:", 6) != 0) { ++ r->proxyreq = PROXYREQ_REVERSE; ++ r->filename = apr_pstrcat(r->pool, r->handler, r->filename, NULL); ++ apr_table_setn(r->notes, "rewrite-proxy", "1"); ++ } ++ else { ++ return DECLINED; ++ } ++ } else if (strncmp(r->filename, "proxy:", 6) != 0) { ++ return DECLINED; ++ } + + /* handle max-forwards / OPTIONS / TRACE */ + if ((str = apr_table_get(r->headers_in, "Max-Forwards"))) { diff --git a/SOURCES/httpd-2.4.6-r1587053.patch b/SOURCES/httpd-2.4.6-r1587053.patch new file mode 100644 index 0000000..5bee0b1 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1587053.patch @@ -0,0 +1,92 @@ +diff --git a/modules/proxy/mod_proxy_wstunnel.c b/modules/proxy/mod_proxy_wstunnel.c +index 525109a..eb34eee 100644 +--- a/modules/proxy/mod_proxy_wstunnel.c ++++ b/modules/proxy/mod_proxy_wstunnel.c +@@ -103,10 +103,12 @@ static int proxy_wstunnel_transfer(request_rec *r, conn_rec *c_i, conn_rec *c_o, + rv = ap_get_brigade(c_i->input_filters, bb, AP_MODE_READBYTES, + APR_NONBLOCK_READ, AP_IOBUFSIZE); + if (rv == APR_SUCCESS) { +- if (c_o->aborted) ++ if (c_o->aborted) { + return APR_EPIPE; +- if (APR_BRIGADE_EMPTY(bb)) ++ } ++ if (APR_BRIGADE_EMPTY(bb)){ + break; ++ } + #ifdef DEBUGGING + len = -1; + apr_brigade_length(bb, 0, &len); +@@ -178,7 +180,6 @@ static int ap_proxy_wstunnel_request(apr_pool_t *p, request_rec *r, + conn_rec *c = r->connection; + apr_socket_t *sock = conn->sock; + conn_rec *backconn = conn->connection; +- int client_error = 0; + char *buf; + apr_bucket_brigade *header_brigade; + apr_bucket *e; +@@ -224,7 +225,7 @@ static int ap_proxy_wstunnel_request(apr_pool_t *p, request_rec *r, + + pollfd.p = p; + pollfd.desc_type = APR_POLL_SOCKET; +- pollfd.reqevents = APR_POLLIN; ++ pollfd.reqevents = APR_POLLIN | APR_POLLHUP; + pollfd.desc.s = sock; + pollfd.client_data = NULL; + apr_pollset_add(pollset, &pollfd); +@@ -237,6 +238,9 @@ static int ap_proxy_wstunnel_request(apr_pool_t *p, request_rec *r, + r->proto_output_filters = c->output_filters; + r->input_filters = c->input_filters; + r->proto_input_filters = c->input_filters; ++ /* This handler should take care of the entire connection; make it so that ++ * nothing else is attempted on the connection after returning. */ ++ c->keepalive = AP_CONN_CLOSE; + + remove_reqtimeout(r->input_filters); + +@@ -257,26 +261,28 @@ static int ap_proxy_wstunnel_request(apr_pool_t *p, request_rec *r, + + if (cur->desc.s == sock) { + pollevent = cur->rtnevents; +- if (pollevent & APR_POLLIN) { ++ if (pollevent & (APR_POLLIN | APR_POLLHUP)) { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02446) + "sock was readable"); + rv = proxy_wstunnel_transfer(r, backconn, c, bb, "sock"); + } +- else if ((pollevent & APR_POLLERR) +- || (pollevent & APR_POLLHUP)) { ++ else if (pollevent & APR_POLLERR) { + rv = APR_EPIPE; + ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, APLOGNO(02447) +- "err/hup on backconn"); ++ "err on backconn"); + } +- if (rv != APR_SUCCESS) +- client_error = 1; + } + else if (cur->desc.s == client_socket) { + pollevent = cur->rtnevents; +- if (pollevent & APR_POLLIN) { ++ if (pollevent & (APR_POLLIN | APR_POLLHUP)) { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02448) + "client was readable"); + rv = proxy_wstunnel_transfer(r, c, backconn, bb, "client"); ++ } else if (pollevent & APR_POLLERR) { ++ rv = APR_EPIPE; ++ c->aborted = 1; ++ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, APLOGNO(02607) ++ "error on client conn"); + } + } + else { +@@ -294,9 +300,6 @@ static int ap_proxy_wstunnel_request(apr_pool_t *p, request_rec *r, + ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, + "finished with poll() - cleaning up"); + +- if (client_error) { +- return HTTP_INTERNAL_SERVER_ERROR; +- } + return OK; + } + diff --git a/SOURCES/httpd-2.4.6-r1593002.patch b/SOURCES/httpd-2.4.6-r1593002.patch new file mode 100644 index 0000000..6aa0688 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1593002.patch @@ -0,0 +1,35 @@ +--- a/modules/ssl/ssl_util_stapling.c 2014/05/07 12:51:38 1593001 ++++ b/modules/ssl/ssl_util_stapling.c 2014/05/07 12:52:13 1593002 +@@ -145,14 +145,15 @@ + X509_digest(x, EVP_sha1(), cinf->idx, NULL); + + aia = X509_get1_ocsp(x); +- if (aia) ++ if (aia) { + cinf->uri = sk_OPENSSL_STRING_pop(aia); ++ X509_email_free(aia); ++ } + if (!cinf->uri && !mctx->stapling_force_url) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02218) + "ssl_stapling_init_cert: no responder URL"); ++ return 0; + } +- if (aia) +- X509_email_free(aia); + return 1; + } + +@@ -403,6 +404,13 @@ + else + ocspuri = cinf->uri; + ++ if (!ocspuri) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02621) ++ "stapling_renew_response: no uri for responder"); ++ rv = FALSE; ++ goto done; ++ } ++ + /* Create a temporary pool to constrain memory use */ + apr_pool_create(&vpool, conn->pool); + diff --git a/SOURCES/httpd-2.4.6-r1594625.patch b/SOURCES/httpd-2.4.6-r1594625.patch new file mode 100644 index 0000000..487b2ad --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1594625.patch @@ -0,0 +1,25 @@ +Index: modules/proxy/mod_proxy_wstunnel.c +=================================================================== +--- a/modules/proxy/mod_proxy_wstunnel.c (revision 1593857) ++++ b/modules/proxy/mod_proxy_wstunnel.c (revision 1594625) +@@ -477,9 +477,11 @@ + conn_rec *c = r->connection; + apr_pool_t *p = r->pool; + apr_uri_t *uri; ++ int is_ssl = 0; + + if (strncasecmp(url, "wss:", 4) == 0) { + scheme = "WSS"; ++ is_ssl = 1; + } + else if (strncasecmp(url, "ws:", 3) == 0) { + scheme = "WS"; +@@ -503,7 +505,7 @@ + return status; + } + +- backend->is_ssl = 0; ++ backend->is_ssl = is_ssl; + backend->close = 0; + + retry = 0; diff --git a/SOURCES/httpd-2.4.6-r1604460.patch b/SOURCES/httpd-2.4.6-r1604460.patch new file mode 100644 index 0000000..465005d --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1604460.patch @@ -0,0 +1,22 @@ +--- a/modules/filters/mod_deflate.c 2014/02/26 15:24:07 1572091 ++++ b/modules/filters/mod_deflate.c 2014/02/26 15:30:25 1572092 +@@ -1125,7 +1125,8 @@ + } + ctx->stream.next_in += 4; + compLen = getLong(ctx->stream.next_in); +- if (ctx->stream.total_out != compLen) { ++ /* gzip stores original size only as 4 byte value */ ++ if ((ctx->stream.total_out & 0xFFFFFFFF) != compLen) { + inflateEnd(&ctx->stream); + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01395) + "Zlib: Length %ld of inflated data does " +@@ -1322,7 +1323,8 @@ + } + ctx->validation_buffer += VALIDATION_SIZE / 2; + compLen = getLong(ctx->validation_buffer); +- if (ctx->stream.total_out != compLen) { ++ /* gzip stores original size only as 4 byte value */ ++ if ((ctx->stream.total_out & 0xFFFFFFFF) != compLen) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01400) + "Zlib: Length of inflated stream invalid"); + return APR_EGENERAL; diff --git a/SOURCES/httpd-2.4.6-r1610013.patch b/SOURCES/httpd-2.4.6-r1610013.patch new file mode 100644 index 0000000..b53ae60 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1610013.patch @@ -0,0 +1,141 @@ +Index: modules/dav/main/mod_dav.c +=================================================================== +--- a/modules/dav/main/mod_dav.c (revision 1610012) ++++ b/modules/dav/main/mod_dav.c (revision 1610013) +@@ -396,9 +396,11 @@ + */ + static const char *dav_xml_escape_uri(apr_pool_t *p, const char *uri) + { ++ const char *e_uri = ap_escape_uri(p, uri); ++ + /* check the easy case... */ +- if (ap_strchr_c(uri, '&') == NULL) +- return uri; ++ if (ap_strchr_c(e_uri, '&') == NULL) ++ return e_uri; + + /* there was a '&', so more work is needed... sigh. */ + +@@ -406,7 +408,7 @@ + * Note: this is a teeny bit of overkill since we know there are no + * '<' or '>' characters, but who cares. + */ +- return apr_xml_quote_string(p, uri, 0); ++ return apr_xml_quote_string(p, e_uri, 0); + } + + +Index: modules/dav/main/mod_dav.h +=================================================================== +--- a/modules/dav/main/mod_dav.h (revision 1610012) ++++ b/modules/dav/main/mod_dav.h (revision 1610013) +@@ -386,7 +386,9 @@ + * REGULAR and WORKSPACE resources, + * and is always 1 for WORKING */ + +- const char *uri; /* the escaped URI for this resource */ ++ const char *uri; /* the URI for this resource; ++ * currently has an ABI flaw where sometimes it is ++ * assumed to be encoded and sometimes not */ + + dav_resource_private *info; /* the provider's private info */ + +Index: modules/dav/main/props.c +=================================================================== +--- a/modules/dav/main/props.c (revision 1610012) ++++ b/modules/dav/main/props.c (revision 1610013) +@@ -321,10 +321,14 @@ + /* do a sub-request to fetch properties for the target resource's URI. */ + static void dav_do_prop_subreq(dav_propdb *propdb) + { ++ /* need to escape the uri that's in the resource struct because during ++ * the property walker it's not encoded. */ ++ const char *e_uri = ap_escape_uri(propdb->resource->pool, ++ propdb->resource->uri); ++ + /* perform a "GET" on the resource's URI (note that the resource + may not correspond to the current request!). */ +- propdb->subreq = ap_sub_req_lookup_uri(propdb->resource->uri, propdb->r, +- NULL); ++ propdb->subreq = ap_sub_req_lookup_uri(e_uri, propdb->r, NULL); + } + + static dav_error * dav_insert_coreprop(dav_propdb *propdb, +Index: modules/dav/fs/repos.c +=================================================================== +--- a/modules/dav/fs/repos.c (revision 1610012) ++++ b/modules/dav/fs/repos.c (revision 1610013) +@@ -717,13 +717,13 @@ + resource->pool = r->pool; + + /* make sure the URI does not have a trailing "/" */ +- len = strlen(r->unparsed_uri); +- if (len > 1 && r->unparsed_uri[len - 1] == '/') { +- s = apr_pstrmemdup(r->pool, r->unparsed_uri, len-1); ++ len = strlen(r->uri); ++ if (len > 1 && r->uri[len - 1] == '/') { ++ s = apr_pstrmemdup(r->pool, r->uri, len-1); + resource->uri = s; + } + else { +- resource->uri = r->unparsed_uri; ++ resource->uri = r->uri; + } + + if (r->finfo.filetype != APR_NOFILE) { +@@ -1482,18 +1482,6 @@ + return dav_fs_deleteset(info->pool, resource); + } + +-/* Take an unescaped path component and escape it and append it onto a +- * dav_buffer for a URI */ +-static apr_size_t dav_fs_append_uri(apr_pool_t *p, dav_buffer *pbuf, +- const char *path, apr_size_t pad) +-{ +- const char *epath = ap_escape_uri(p, path); +- apr_size_t epath_len = strlen(epath); +- +- dav_buffer_place_mem(p, pbuf, epath, epath_len + 1, pad); +- return epath_len; +-} +- + /* ### move this to dav_util? */ + /* Walk recursively down through directories, * + * including lock-null resources as we go. */ +@@ -1549,7 +1537,6 @@ + } + while ((apr_dir_read(&dirent, APR_FINFO_DIRENT, dirp)) == APR_SUCCESS) { + apr_size_t len; +- apr_size_t escaped_len; + + len = strlen(dirent.name); + +@@ -1592,7 +1579,7 @@ + + /* copy the file to the URI, too. NOTE: we will pad an extra byte + for the trailing slash later. */ +- escaped_len = dav_fs_append_uri(pool, &fsctx->uri_buf, dirent.name, 1); ++ dav_buffer_place_mem(pool, &fsctx->uri_buf, dirent.name, len + 1, 1); + + /* if there is a secondary path, then do that, too */ + if (fsctx->path2.buf != NULL) { +@@ -1625,7 +1612,7 @@ + fsctx->path2.cur_len += len; + + /* adjust URI length to incorporate subdir and a slash */ +- fsctx->uri_buf.cur_len += escaped_len + 1; ++ fsctx->uri_buf.cur_len += len + 1; + fsctx->uri_buf.buf[fsctx->uri_buf.cur_len - 1] = '/'; + fsctx->uri_buf.buf[fsctx->uri_buf.cur_len] = '\0'; + +@@ -1691,8 +1678,8 @@ + */ + dav_buffer_place_mem(pool, &fsctx->path1, + fsctx->locknull_buf.buf + offset, len + 1, 0); +- dav_fs_append_uri(pool, &fsctx->uri_buf, +- fsctx->locknull_buf.buf + offset, 0); ++ dav_buffer_place_mem(pool, &fsctx->uri_buf, ++ fsctx->locknull_buf.buf + offset, len + 1, 0); + if (fsctx->path2.buf != NULL) { + dav_buffer_place_mem(pool, &fsctx->path2, + fsctx->locknull_buf.buf + offset, diff --git a/SOURCES/httpd-2.4.6-r1610396.patch b/SOURCES/httpd-2.4.6-r1610396.patch new file mode 100644 index 0000000..39edd6b --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1610396.patch @@ -0,0 +1,189 @@ +Index: modules/ldap/util_ldap.c +=================================================================== +--- a/modules/ldap/util_ldap.c (revision 1610395) ++++ b/modules/ldap/util_ldap.c (revision 1610396) +@@ -157,10 +157,12 @@ + */ + if (!ldc->keep) { + uldap_connection_unbind(ldc); ++ ldc->r = NULL; + } + else { + /* mark our connection as available for reuse */ + ldc->freed = apr_time_now(); ++ ldc->r = NULL; + #if APR_HAS_THREADS + apr_thread_mutex_unlock(ldc->lock); + #endif +@@ -179,6 +181,9 @@ + + if (ldc) { + if (ldc->ldap) { ++ if (ldc->r) { ++ ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, ldc->r, "LDC %pp unbind", ldc); ++ } + ldap_unbind_s(ldc->ldap); + ldc->ldap = NULL; + } +@@ -319,6 +324,8 @@ + return(result->rc); + } + ++ ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, r, "LDC %pp init", ldc); ++ + if (ldc->ChaseReferrals == AP_LDAP_CHASEREFERRALS_ON) { + /* Now that we have an ldap struct, add it to the referral list for rebinds. */ + rc = apr_ldap_rebind_add(ldc->rebind_pool, ldc->ldap, ldc->binddn, ldc->bindpw); +@@ -516,6 +523,10 @@ + ldc->reason = "LDAP: ldap_simple_bind() parse result failed"; + return uldap_ld_errno(ldc); + } ++ else { ++ ldc->last_backend_conn = ldc->r->request_time; ++ ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, ldc->r, "LDC %pp bind", ldc); ++ } + return rc; + } + +@@ -540,7 +551,7 @@ + + /* If the connection is already bound, return + */ +- if (ldc->bound) ++ if (ldc->bound && !ldc->must_rebind) + { + ldc->reason = "LDAP: connection open successful (already bound)"; + return LDAP_SUCCESS; +@@ -621,6 +632,7 @@ + } + else { + ldc->bound = 1; ++ ldc->must_rebind = 0; + ldc->reason = "LDAP: connection open successful"; + } + +@@ -718,13 +730,17 @@ + && !compare_client_certs(dc->client_certs, l->client_certs)) + { + if (st->connection_pool_ttl > 0) { +- if (l->bound && (now - l->freed) > st->connection_pool_ttl) { ++ if (l->bound && (now - l->last_backend_conn) > st->connection_pool_ttl) { + ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, + "Removing LDAP connection last used %" APR_TIME_T_FMT " seconds ago", +- (now - l->freed) / APR_USEC_PER_SEC); ++ (now - l->last_backend_conn) / APR_USEC_PER_SEC); ++ l->r = r; + uldap_connection_unbind(l); + /* Go ahead (by falling through) and use it, so we don't create more just to unbind some other old ones */ + } ++ ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, r, ++ "Reuse %s LDC %pp", ++ l->bound ? "bound" : "unbound", l); + } + break; + } +@@ -751,12 +767,25 @@ + (l->deref == deref) && (l->secure == secureflag) && + !compare_client_certs(dc->client_certs, l->client_certs)) + { ++ if (st->connection_pool_ttl > 0) { ++ if (l->bound && (now - l->last_backend_conn) > st->connection_pool_ttl) { ++ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, ++ "Removing LDAP connection last used %" APR_TIME_T_FMT " seconds ago", ++ (now - l->last_backend_conn) / APR_USEC_PER_SEC); ++ l->r = r; ++ uldap_connection_unbind(l); ++ /* Go ahead (by falling through) and use it, so we don't create more just to unbind some other old ones */ ++ } ++ ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, r, ++ "Reuse %s LDC %pp (will rebind)", ++ l->bound ? "bound" : "unbound", l); ++ } ++ + /* the bind credentials have changed */ +- /* no check for connection_pool_ttl, since we are unbinding any way */ +- uldap_connection_unbind(l); +- ++ l->must_rebind = 1; + util_ldap_strdup((char**)&(l->binddn), binddn); + util_ldap_strdup((char**)&(l->bindpw), bindpw); ++ + break; + } + #if APR_HAS_THREADS +@@ -846,6 +875,7 @@ + #if APR_HAS_THREADS + apr_thread_mutex_unlock(st->mutex); + #endif ++ l->r = r; + return l; + } + +@@ -965,6 +995,7 @@ + return result; + } + ++ ldc->last_backend_conn = r->request_time; + entry = ldap_first_entry(ldc->ldap, res); + searchdn = ldap_get_dn(ldc->ldap, entry); + +@@ -1116,6 +1147,7 @@ + goto start_over; + } + ++ ldc->last_backend_conn = r->request_time; + ldc->reason = "Comparison complete"; + if ((LDAP_COMPARE_TRUE == result) || + (LDAP_COMPARE_FALSE == result) || +@@ -1241,6 +1273,7 @@ + return res; + } + ++ ldc->last_backend_conn = r->request_time; + entry = ldap_first_entry(ldc->ldap, sga_res); + + /* +@@ -1723,6 +1756,7 @@ + * We should have found exactly one entry; to find a different + * number is an error. + */ ++ ldc->last_backend_conn = r->request_time; + count = ldap_count_entries(ldc->ldap, res); + if (count != 1) + { +@@ -1788,10 +1822,10 @@ + /* + * We have just bound the connection to a different user and password + * combination, which might be reused unintentionally next time this +- * connection is used from the connection pool. To ensure no confusion, +- * we mark the connection as unbound. ++ * connection is used from the connection pool. + */ +- ldc->bound = 0; ++ ldc->must_rebind = 0; ++ ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, r, "LDC %pp used for authn, must be rebound", ldc); + } + + /* +@@ -1983,6 +2017,7 @@ + * We should have found exactly one entry; to find a different + * number is an error. + */ ++ ldc->last_backend_conn = r->request_time; + count = ldap_count_entries(ldc->ldap, res); + if (count != 1) + { +Index: include/util_ldap.h +=================================================================== +--- a/include/util_ldap.h (revision 1610395) ++++ b/include/util_ldap.h (revision 1610396) +@@ -133,6 +133,9 @@ + int ReferralHopLimit; /* # of referral hops to follow (default = AP_LDAP_DEFAULT_HOPLIMIT) */ + apr_time_t freed; /* the time this conn was placed back in the pool */ + apr_pool_t *rebind_pool; /* frequently cleared pool for rebind data */ ++ int must_rebind; /* The connection was last bound with other then binddn/bindpw */ ++ request_rec *r; /* request_rec used to find this util_ldap_connection_t */ ++ apr_time_t last_backend_conn; /* the approximate time of the last backend LDAP requst */ + } util_ldap_connection_t; + + typedef struct util_ldap_config_t { diff --git a/SOURCES/httpd-2.4.6-r1618851.patch b/SOURCES/httpd-2.4.6-r1618851.patch new file mode 100644 index 0000000..fa84b0c --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1618851.patch @@ -0,0 +1,28 @@ +# ./pullrev.sh r1618851 +http://svn.apache.org/viewvc?view=revision&revision=r1618851 + +--- httpd-2.4.6/modules/aaa/mod_authz_core.c ++++ httpd-2.4.6/modules/aaa/mod_authz_core.c +@@ -168,6 +168,13 @@ + return (void*)conf; + } + ++/* Only per-server directive we have is GLOBAL_ONLY */ ++static void *merge_authz_core_svr_config(apr_pool_t *p, ++ void *basev, void *newv) ++{ ++ return basev; ++} ++ + static void *create_authz_core_svr_config(apr_pool_t *p, server_rec *s) + { + authz_core_srv_conf *authcfg; +@@ -1140,7 +1148,7 @@ AP_DECLARE_MODULE(authz_core) = + create_authz_core_dir_config, /* dir config creater */ + merge_authz_core_dir_config, /* dir merger */ + create_authz_core_svr_config, /* server config */ +- NULL, /* merge server config */ ++ merge_authz_core_svr_config , /* merge server config */ + authz_cmds, + register_hooks /* register hooks */ + }; diff --git a/SOURCES/httpd-2.4.6-r1621601.patch b/SOURCES/httpd-2.4.6-r1621601.patch new file mode 100644 index 0000000..4296804 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1621601.patch @@ -0,0 +1,21 @@ +--- a/modules/proxy/mod_proxy_http.c 2014/08/31 16:06:36 1621600 ++++ b/modules/proxy/mod_proxy_http.c 2014/08/31 16:07:45 1621601 +@@ -1652,6 +1652,18 @@ + if (!r->header_only && /* not HEAD request */ + (proxy_status != HTTP_NO_CONTENT) && /* not 204 */ + (proxy_status != HTTP_NOT_MODIFIED)) { /* not 304 */ ++ const char *tmp; ++ /* Add minimal headers needed to allow http_in filter ++ * detecting end of body without waiting for a timeout. */ ++ if ((tmp = apr_table_get(r->headers_out, "Transfer-Encoding"))) { ++ apr_table_set(backend->r->headers_in, "Transfer-Encoding", tmp); ++ } ++ else if ((tmp = apr_table_get(r->headers_out, "Content-Length"))) { ++ apr_table_set(backend->r->headers_in, "Content-Length", tmp); ++ } ++ else if (te) { ++ apr_table_set(backend->r->headers_in, "Transfer-Encoding", te); ++ } + ap_discard_request_body(backend->r); + } + return proxy_status; diff --git a/SOURCES/httpd-2.4.6-r1624349.patch b/SOURCES/httpd-2.4.6-r1624349.patch new file mode 100644 index 0000000..c2e93f8 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1624349.patch @@ -0,0 +1,21 @@ +diff --git a/server/scoreboard.c b/server/scoreboard.c +index bef2b90..c8ef6a3 100644 +--- a/server/scoreboard.c ++++ b/server/scoreboard.c +@@ -484,8 +484,14 @@ static int update_child_status_internal(int child_num, + ws->conn_bytes = 0; + } + if (r) { +- apr_cpystrn(ws->client, ap_get_remote_host(c, r->per_dir_config, +- REMOTE_NOLOOKUP, NULL), sizeof(ws->client)); ++ const char *client = ap_get_remote_host(c, r->per_dir_config, ++ REMOTE_NOLOOKUP, NULL); ++ if (!client || !strcmp(client, c->client_ip)) { ++ apr_cpystrn(ws->client, r->useragent_ip, sizeof(ws->client)); ++ } ++ else { ++ apr_cpystrn(ws->client, client, sizeof(ws->client)); ++ } + copy_request(ws->request, sizeof(ws->request), r); + if (r->server) { + apr_snprintf(ws->vhost, sizeof(ws->vhost), "%s:%d", diff --git a/SOURCES/httpd-2.4.6-r1631119.patch b/SOURCES/httpd-2.4.6-r1631119.patch new file mode 100644 index 0000000..f0f48e4 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1631119.patch @@ -0,0 +1,16 @@ +# ./pullrev.sh 1631119 +http://svn.apache.org/viewvc?view=revision&revision=1631119 + +https://bugzilla.redhat.com/show_bug.cgi?id=1415257 + +--- httpd-2.4.6/modules/ldap/util_ldap.c ++++ httpd-2.4.6/modules/ldap/util_ldap.c +@@ -1824,7 +1824,7 @@ + * combination, which might be reused unintentionally next time this + * connection is used from the connection pool. + */ +- ldc->must_rebind = 0; ++ ldc->must_rebind = 1; + ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, r, "LDC %pp used for authn, must be rebound", ldc); + } + diff --git a/SOURCES/httpd-2.4.6-r1633085.patch b/SOURCES/httpd-2.4.6-r1633085.patch new file mode 100644 index 0000000..ec10a6a --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1633085.patch @@ -0,0 +1,14 @@ +--- a/modules/ssl/ssl_engine_io.c 2014/10/20 09:11:19 1633084 ++++ b/modules/ssl/ssl_engine_io.c 2014/10/20 09:18:22 1633085 +@@ -1322,6 +1322,11 @@ + "\"SSLVerifyClient optional_no_ca\" " + "configuration"); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_INFO, server); ++ ++ /* on session resumption ssl_callback_SSLVerify() ++ * will not be called, therefore we have to set it here ++ */ ++ sslconn->verify_info = "GENEROUS"; + } + else { + const char *error = sslconn->verify_error ? diff --git a/SOURCES/httpd-2.4.6-r1634529.patch b/SOURCES/httpd-2.4.6-r1634529.patch new file mode 100644 index 0000000..9b831c6 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1634529.patch @@ -0,0 +1,275 @@ +diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c +index 9811af8..568627f 100644 +--- a/modules/ssl/ssl_engine_init.c ++++ b/modules/ssl/ssl_engine_init.c +@@ -276,7 +276,7 @@ int ssl_init_Module(apr_pool_t *p, apr_pool_t *plog, + return HTTP_INTERNAL_SERVER_ERROR; + } + #ifdef HAVE_OCSP_STAPLING +- ssl_stapling_ex_init(); ++ ssl_stapling_certinfo_hash_init(p); + #endif + + /* +@@ -899,6 +899,8 @@ static void ssl_init_ctx(server_rec *s, + } + + static int ssl_server_import_cert(server_rec *s, ++ apr_pool_t *p, ++ apr_pool_t *ptemp, + modssl_ctx_t *mctx, + const char *id, + int idx) +@@ -933,7 +935,7 @@ static int ssl_server_import_cert(server_rec *s, + + #ifdef HAVE_OCSP_STAPLING + if ((mctx->pkp == FALSE) && (mctx->stapling_enabled == TRUE)) { +- if (!ssl_stapling_init_cert(s, mctx, cert)) { ++ if (!ssl_stapling_init_cert(s, p, ptemp, mctx, cert)) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02235) + "Unable to configure server certificate for stapling"); + } +@@ -1081,10 +1083,10 @@ 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, p, ptemp, mctx, rsa_id, SSL_AIDX_RSA); ++ have_dsa = ssl_server_import_cert(s, p, ptemp, mctx, dsa_id, SSL_AIDX_DSA); + #ifndef OPENSSL_NO_EC +- have_ecc = ssl_server_import_cert(s, mctx, ecc_id, SSL_AIDX_ECC); ++ have_ecc = ssl_server_import_cert(s, p, ptemp, mctx, ecc_id, SSL_AIDX_ECC); + #endif + + if (!(have_rsa || have_dsa +diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h +index 80e1e8e..0cc6d3f 100644 +--- a/modules/ssl/ssl_private.h ++++ b/modules/ssl/ssl_private.h +@@ -132,6 +132,13 @@ + #if OPENSSL_VERSION_NUMBER >= 0x00908080 && !defined(OPENSSL_NO_OCSP) \ + && !defined(OPENSSL_NO_TLSEXT) + #define HAVE_OCSP_STAPLING ++/* backward compatibility with OpenSSL < 1.0 */ ++#ifndef sk_OPENSSL_STRING_num ++#define sk_OPENSSL_STRING_num sk_num ++#endif ++#ifndef sk_OPENSSL_STRING_value ++#define sk_OPENSSL_STRING_value sk_value ++#endif + #if (OPENSSL_VERSION_NUMBER < 0x10000000) + #define sk_OPENSSL_STRING_pop sk_pop + #endif +@@ -862,10 +869,10 @@ const char *ssl_cmd_SSLStaplingErrorCacheTimeout(cmd_parms *, void *, const char + const char *ssl_cmd_SSLStaplingReturnResponderErrors(cmd_parms *, void *, int); + const char *ssl_cmd_SSLStaplingFakeTryLater(cmd_parms *, void *, int); + const char *ssl_cmd_SSLStaplingResponderTimeout(cmd_parms *, void *, const char *); +-const char *ssl_cmd_SSLStaplingForceURL(cmd_parms *, void *, const char *); ++const char *ssl_cmd_SSLStaplingForceURL(cmd_parms *, void *, const char *); + void modssl_init_stapling(server_rec *, apr_pool_t *, apr_pool_t *, modssl_ctx_t *); +-void ssl_stapling_ex_init(void); +-int ssl_stapling_init_cert(server_rec *s, modssl_ctx_t *mctx, X509 *x); ++void ssl_stapling_certinfo_hash_init(apr_pool_t *); ++int ssl_stapling_init_cert(server_rec *, apr_pool_t *, apr_pool_t *, modssl_ctx_t *, X509 *); + #endif + #ifndef OPENSSL_NO_SRP + int ssl_callback_SRPServerParams(SSL *, int *, void *); +diff --git a/modules/ssl/ssl_util_stapling.c b/modules/ssl/ssl_util_stapling.c +index 2be2c36..2387ae1 100644 +--- a/modules/ssl/ssl_util_stapling.c ++++ b/modules/ssl/ssl_util_stapling.c +@@ -43,36 +43,32 @@ + + #define MAX_STAPLING_DER 10240 + +-/* Cached info stored in certificate ex_info. */ ++/* Cached info stored in the global stapling_certinfo hash. */ + typedef struct { +- /* Index in session cache SHA1 hash of certificate */ +- UCHAR idx[20]; +- /* Certificate ID for OCSP requests or NULL if ID cannot be determined */ ++ /* Index in session cache (SHA-1 digest of DER encoded certificate) */ ++ UCHAR idx[SHA_DIGEST_LENGTH]; ++ /* Certificate ID for OCSP request */ + OCSP_CERTID *cid; +- /* Responder details */ ++ /* URI of the OCSP responder */ + char *uri; + } certinfo; + +-static void certinfo_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, +- int idx, long argl, void *argp) ++static apr_status_t ssl_stapling_certid_free(void *data) + { +- certinfo *cinf = ptr; ++ OCSP_CERTID *cid = data; + +- if (!cinf) +- return; +- if (cinf->uri) +- OPENSSL_free(cinf->uri); +- OPENSSL_free(cinf); ++ if (cid) { ++ OCSP_CERTID_free(cid); ++ } ++ ++ return APR_SUCCESS; + } + +-static int stapling_ex_idx = -1; ++static apr_hash_t *stapling_certinfo; + +-void ssl_stapling_ex_init(void) ++void ssl_stapling_certinfo_hash_init(apr_pool_t *p) + { +- if (stapling_ex_idx != -1) +- return; +- stapling_ex_idx = X509_get_ex_new_index(0, "X509 cached OCSP info", 0, 0, +- certinfo_free); ++ stapling_certinfo = apr_hash_make(p); + } + + static X509 *stapling_get_issuer(modssl_ctx_t *mctx, X509 *x) +@@ -106,70 +102,97 @@ static X509 *stapling_get_issuer(modssl_ctx_t *mctx, X509 *x) + + } + +-int ssl_stapling_init_cert(server_rec *s, modssl_ctx_t *mctx, X509 *x) ++int ssl_stapling_init_cert(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, ++ modssl_ctx_t *mctx, X509 *x) + { +- certinfo *cinf; ++ UCHAR idx[SHA_DIGEST_LENGTH]; ++ certinfo *cinf = NULL; + X509 *issuer = NULL; ++ OCSP_CERTID *cid = NULL; + STACK_OF(OPENSSL_STRING) *aia = NULL; + +- if (x == NULL) ++ if ((x == NULL) || (X509_digest(x, EVP_sha1(), idx, NULL) != 1)) + return 0; +- cinf = X509_get_ex_data(x, stapling_ex_idx); ++ ++ cinf = apr_hash_get(stapling_certinfo, idx, sizeof(idx)); + if (cinf) { +- ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02215) +- "ssl_stapling_init_cert: certificate already initialized!"); +- return 0; +- } +- cinf = OPENSSL_malloc(sizeof(certinfo)); +- if (!cinf) { +- ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02216) +- "ssl_stapling_init_cert: error allocating memory!"); +- return 0; ++ /* ++ * We already parsed the certificate, and no OCSP URI was found. ++ * The certificate might be used for multiple vhosts, though, ++ * so we check for a ForceURL for this vhost. ++ */ ++ if (!cinf->uri && !mctx->stapling_force_url) { ++ ssl_log_xerror(SSLLOG_MARK, APLOG_ERR, 0, ptemp, s, x, ++ APLOGNO(02814) "ssl_stapling_init_cert: no OCSP URI " ++ "in certificate and no SSLStaplingForceURL " ++ "configured for server %s", mctx->sc->vhost_id); ++ return 0; ++ } ++ return 1; + } +- cinf->cid = NULL; +- cinf->uri = NULL; +- X509_set_ex_data(x, stapling_ex_idx, cinf); +- +- issuer = stapling_get_issuer(mctx, x); + +- if (issuer == NULL) { +- ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02217) +- "ssl_stapling_init_cert: Can't retrieve issuer certificate!"); ++ if (!(issuer = stapling_get_issuer(mctx, x))) { ++ ssl_log_xerror(SSLLOG_MARK, APLOG_ERR, 0, ptemp, s, x, APLOGNO(02217) ++ "ssl_stapling_init_cert: can't retrieve issuer " ++ "certificate!"); + return 0; + } + +- cinf->cid = OCSP_cert_to_id(NULL, x, issuer); ++ cid = OCSP_cert_to_id(NULL, x, issuer); + X509_free(issuer); +- if (!cinf->cid) ++ if (!cid) { ++ ssl_log_xerror(SSLLOG_MARK, APLOG_ERR, 0, ptemp, s, x, APLOGNO(02815) ++ "ssl_stapling_init_cert: can't create CertID " ++ "for OCSP request"); + return 0; +- X509_digest(x, EVP_sha1(), cinf->idx, NULL); ++ } + + aia = X509_get1_ocsp(x); +- if (aia) { +- cinf->uri = sk_OPENSSL_STRING_pop(aia); +- X509_email_free(aia); +- } +- if (!cinf->uri && !mctx->stapling_force_url) { +- ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02218) +- "ssl_stapling_init_cert: no responder URL"); ++ ++ if (!aia && !mctx->stapling_force_url) { ++ OCSP_CERTID_free(cid); ++ ssl_log_xerror(SSLLOG_MARK, APLOG_ERR, 0, ptemp, s, x, ++ APLOGNO(02218) "ssl_stapling_init_cert: no OCSP URI " ++ "in certificate and no SSLStaplingForceURL set"); + return 0; + } ++ ++ /* At this point, we have determined that there's something to store */ ++ cinf = apr_pcalloc(p, sizeof(certinfo)); ++ memcpy (cinf->idx, idx, sizeof(idx)); ++ cinf->cid = cid; ++ /* make sure cid is also freed at pool cleanup */ ++ apr_pool_cleanup_register(p, cid, ssl_stapling_certid_free, ++ apr_pool_cleanup_null); ++ if (aia) { ++ /* allocate uri from the pconf pool */ ++ cinf->uri = apr_pstrdup(p, sk_OPENSSL_STRING_value(aia, 0)); ++ X509_email_free(aia); ++ } ++ ++ ssl_log_xerror(SSLLOG_MARK, APLOG_TRACE1, 0, ptemp, s, x, ++ "ssl_stapling_init_cert: storing certinfo for server %s", ++ mctx->sc->vhost_id); ++ ++ apr_hash_set(stapling_certinfo, cinf->idx, sizeof(cinf->idx), cinf); ++ + return 1; + } + +-static certinfo *stapling_get_cert_info(server_rec *s, modssl_ctx_t *mctx, ++static certinfo *stapling_get_certinfo(server_rec *s, modssl_ctx_t *mctx, + SSL *ssl) + { + certinfo *cinf; + X509 *x; ++ UCHAR idx[SHA_DIGEST_LENGTH]; + x = SSL_get_certificate(ssl); +- if (x == NULL) ++ if ((x == NULL) || (X509_digest(x, EVP_sha1(), idx, NULL) != 1)) + return NULL; +- cinf = X509_get_ex_data(x, stapling_ex_idx); ++ cinf = apr_hash_get(stapling_certinfo, idx, sizeof(idx)); + if (cinf && cinf->cid) + return cinf; + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(01926) +- "stapling_get_cert_info: stapling not supported for certificate"); ++ "stapling_get_certinfo: stapling not supported for certificate"); + return NULL; + } + +@@ -585,7 +608,7 @@ static int stapling_cb(SSL *ssl, void *arg) + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01951) + "stapling_cb: OCSP Stapling callback called"); + +- cinf = stapling_get_cert_info(s, mctx, ssl); ++ cinf = stapling_get_certinfo(s, mctx, ssl); + if (cinf == NULL) { + return SSL_TLSEXT_ERR_NOACK; + } diff --git a/SOURCES/httpd-2.4.6-r1650310.patch b/SOURCES/httpd-2.4.6-r1650310.patch new file mode 100644 index 0000000..1561282 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1650310.patch @@ -0,0 +1,132 @@ +diff --git a/docs/manual/mod/mod_ssl.html.en b/docs/manual/mod/mod_ssl.html.en +index ca178ab..4580f1c 100644 +--- a/docs/manual/mod/mod_ssl.html.en ++++ b/docs/manual/mod/mod_ssl.html.en +@@ -57,6 +57,7 @@ to provide the cryptography engine.

    +
  • SSLCertificateKeyFile
  • +
  • SSLCipherSuite
  • +
  • SSLCompression
  • ++
  • SSLSessionTickets
  • +
  • SSLCryptoDevice
  • +
  • SSLEngine
  • +
  • SSLFIPS
  • +@@ -797,6 +798,26 @@ CRIME attack).

    + + + ++ ++
    top
    ++

    SSLSessionTickets Directive

    ++ ++ ++ ++ ++ ++ ++ ++ ++
    Description:Enable or disable use of TLS session tickets
    Syntax:SSLSessionTickets on|off
    Default:SSLCompression on
    Context:server config, virtual host
    Status:Extension
    Module:mod_ssl
    Compatibility:Available.
    ++

    This directive allows to enable or disable the use of TLS session tickets(RFC 5077).

    ++
    ++

    TLS session tickets are enabled by default. Using them without restarting ++the web server with an appropriate frequency (e.g. daily) compromises perfect ++forward secrecy.

    ++
    ++ ++
    +
    top
    +

    SSLCryptoDevice Directive

    + +diff --git a/modules/ssl/mod_ssl.c b/modules/ssl/mod_ssl.c +index bbe1d20..4a8b661 100644 +--- a/modules/ssl/mod_ssl.c ++++ b/modules/ssl/mod_ssl.c +@@ -141,6 +141,9 @@ static const command_rec ssl_config_cmds[] = { + SSL_CMD_SRV(Compression, FLAG, + "Enable SSL level compression" + "(`on', `off')") ++ SSL_CMD_SRV(SessionTickets, FLAG, ++ "Enable or disable TLS session tickets" ++ "(`on', `off')") + SSL_CMD_SRV(InsecureRenegotiation, FLAG, + "Enable support for insecure renegotiation") + SSL_CMD_ALL(UserName, TAKE1, +diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c +index 9530fcc..86a7f0f 100644 +--- a/modules/ssl/ssl_engine_config.c ++++ b/modules/ssl/ssl_engine_config.c +@@ -216,6 +216,7 @@ static SSLSrvConfigRec *ssl_config_server_new(apr_pool_t *p) + #ifndef OPENSSL_NO_COMP + sc->compression = UNSET; + #endif ++ sc->session_tickets = UNSET; + + modssl_ctx_init_proxy(sc, p); + +@@ -346,6 +347,7 @@ void *ssl_config_server_merge(apr_pool_t *p, void *basev, void *addv) + #ifndef OPENSSL_NO_COMP + cfgMergeBool(compression); + #endif ++ cfgMergeBool(session_tickets); + + modssl_ctx_cfg_merge_proxy(base->proxy, add->proxy, mrg->proxy); + +@@ -720,6 +722,17 @@ const char *ssl_cmd_SSLHonorCipherOrder(cmd_parms *cmd, void *dcfg, int flag) + #endif + } + ++const char *ssl_cmd_SSLSessionTickets(cmd_parms *cmd, void *dcfg, int flag) ++{ ++ SSLSrvConfigRec *sc = mySrvConfig(cmd->server); ++#ifndef SSL_OP_NO_TICKET ++ return "This version of OpenSSL does not support using " ++ "SSLSessionTickets."; ++#endif ++ sc->session_tickets = flag ? TRUE : FALSE; ++ return NULL; ++} ++ + const char *ssl_cmd_SSLInsecureRenegotiation(cmd_parms *cmd, void *dcfg, int flag) + { + #ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION +diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c +index 568627f..672760c 100644 +--- a/modules/ssl/ssl_engine_init.c ++++ b/modules/ssl/ssl_engine_init.c +@@ -566,6 +566,16 @@ static void ssl_init_ctx_protocol(server_rec *s, + } + #endif + ++#ifdef SSL_OP_NO_TICKET ++ /* ++ * Configure using RFC 5077 TLS session tickets ++ * for session resumption. ++ */ ++ if (sc->session_tickets == FALSE) { ++ SSL_CTX_set_options(ctx, SSL_OP_NO_TICKET); ++ } ++#endif ++ + #ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION + if (sc->insecure_reneg == TRUE) { + SSL_CTX_set_options(ctx, SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION); +diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h +index 0cc6d3f..b601316 100644 +--- a/modules/ssl/ssl_private.h ++++ b/modules/ssl/ssl_private.h +@@ -701,6 +701,7 @@ struct SSLSrvConfigRec { + #ifndef OPENSSL_NO_COMP + BOOL compression; + #endif ++ BOOL session_tickets; + }; + + /** +@@ -756,6 +757,7 @@ 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_SSLSessionTickets(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 *); diff --git a/SOURCES/httpd-2.4.6-r1650655.patch b/SOURCES/httpd-2.4.6-r1650655.patch new file mode 100644 index 0000000..1791419 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1650655.patch @@ -0,0 +1,41 @@ +diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c +index c37a09b..2121892 100644 +--- a/modules/proxy/proxy_util.c ++++ b/modules/proxy/proxy_util.c +@@ -1733,6 +1733,9 @@ PROXY_DECLARE(char *) ap_proxy_define_worker(apr_pool_t *p, + + memset(wshared, 0, sizeof(proxy_worker_shared)); + ++ if (uri.port && uri.port == ap_proxy_port_of_scheme(uri.scheme)) { ++ uri.port = 0; ++ } + ptr = apr_uri_unparse(p, &uri, APR_URI_UNP_REVEALPASSWORD); + if (PROXY_STRNCPY(wshared->name, ptr) != APR_SUCCESS) { + return apr_psprintf(p, "worker name (%s) too long", ptr); +@@ -2688,6 +2691,13 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, + worker->s->hostname); + break; + } ++ ++ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02823) ++ "%s: connection established with Unix domain socket " ++ "%s (%s)", ++ proxy_function, ++ conn->uds_path, ++ worker->s->hostname); + } + else + #endif +@@ -2780,6 +2790,12 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, + backend_addr = backend_addr->next; + continue; + } ++ ++ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02824) ++ "%s: connection established with %pI (%s)", ++ proxy_function, ++ backend_addr, ++ worker->s->hostname); + } + + /* Set a timeout on the socket */ diff --git a/SOURCES/httpd-2.4.6-r1650677.patch b/SOURCES/httpd-2.4.6-r1650677.patch new file mode 100644 index 0000000..6599d98 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1650677.patch @@ -0,0 +1,49 @@ +--- a/modules/proxy/mod_proxy_fcgi.c 2015/01/09 21:25:26 1650676 ++++ b/modules/proxy/mod_proxy_fcgi.c 2015/01/09 21:33:12 1650677 +@@ -367,7 +367,7 @@ + request_rec *r, int request_id) + { + apr_bucket_brigade *ib, *ob; +- int seen_end_of_headers = 0, done = 0; ++ int seen_end_of_headers = 0, done = 0, ignore_body = 0; + apr_status_t rv = APR_SUCCESS; + int script_error_status = HTTP_OK; + conn_rec *c = r->connection; +@@ -577,9 +577,16 @@ + APR_BRIGADE_INSERT_TAIL(ob, tmp_b); + r->status = status; + ap_pass_brigade(r->output_filters, ob); +- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01070) +- "Error parsing script headers"); +- rv = APR_EINVAL; ++ if (status == HTTP_NOT_MODIFIED) { ++ /* The 304 response MUST NOT contain ++ * a message-body, ignore it. */ ++ ignore_body = 1; ++ } ++ else { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01070) ++ "Error parsing script headers"); ++ rv = APR_EINVAL; ++ } + break; + } + +@@ -598,7 +605,7 @@ + r->status = HTTP_OK; + } + +- if (script_error_status == HTTP_OK) { ++ if (script_error_status == HTTP_OK && !ignore_body) { + rv = ap_pass_brigade(r->output_filters, ob); + if (rv != APR_SUCCESS) { + break; +@@ -626,7 +633,7 @@ + * but that could be a huge amount of data; so we pass + * along smaller chunks + */ +- if (script_error_status == HTTP_OK) { ++ if (script_error_status == HTTP_OK && !ignore_body) { + rv = ap_pass_brigade(r->output_filters, ob); + if (rv != APR_SUCCESS) { + break; diff --git a/SOURCES/httpd-2.4.6-r1651083.patch b/SOURCES/httpd-2.4.6-r1651083.patch new file mode 100644 index 0000000..57505ad --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1651083.patch @@ -0,0 +1,10 @@ +--- a/server/core.c 2015/01/12 13:37:20 1651082 ++++ b/server/core.c 2015/01/12 13:38:02 1651083 +@@ -1271,6 +1271,7 @@ + static int reset_config_defines(void *dummy) + { + ap_server_config_defines = saved_server_config_defines; ++ saved_server_config_defines = NULL; + server_config_defined_vars = NULL; + return OK; + } diff --git a/SOURCES/httpd-2.4.6-r1651653.patch b/SOURCES/httpd-2.4.6-r1651653.patch new file mode 100644 index 0000000..a67093e --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1651653.patch @@ -0,0 +1,100 @@ +diff --git a/server/util.c b/server/util.c +index e0ba5c2..a6516d4 100644 +--- a/server/util.c ++++ b/server/util.c +@@ -968,20 +968,20 @@ AP_DECLARE(const char *) ap_pcfg_strerror(apr_pool_t *p, ap_configfile_t *cfp, + /* Read one line from open ap_configfile_t, strip LF, increase line number */ + /* If custom handler does not define a getstr() function, read char by char */ + static apr_status_t ap_cfg_getline_core(char *buf, apr_size_t bufsize, +- ap_configfile_t *cfp) ++ apr_size_t offset, ap_configfile_t *cfp) + { + apr_status_t rc; + /* If a "get string" function is defined, use it */ + if (cfp->getstr != NULL) { + char *cp; +- char *cbuf = buf; +- apr_size_t cbufsize = bufsize; ++ char *cbuf = buf + offset; ++ apr_size_t cbufsize = bufsize - offset; + + while (1) { + ++cfp->line_number; + rc = cfp->getstr(cbuf, cbufsize, cfp->param); + if (rc == APR_EOF) { +- if (cbuf != buf) { ++ if (cbuf != buf + offset) { + *cbuf = '\0'; + break; + } +@@ -999,11 +999,11 @@ static apr_status_t ap_cfg_getline_core(char *buf, apr_size_t bufsize, + */ + cp = cbuf; + cp += strlen(cp); +- if (cp > cbuf && cp[-1] == LF) { ++ if (cp > buf && cp[-1] == LF) { + cp--; +- if (cp > cbuf && cp[-1] == CR) ++ if (cp > buf && cp[-1] == CR) + cp--; +- if (cp > cbuf && cp[-1] == '\\') { ++ if (cp > buf && cp[-1] == '\\') { + cp--; + /* + * line continuation requested - +@@ -1021,19 +1021,19 @@ static apr_status_t ap_cfg_getline_core(char *buf, apr_size_t bufsize, + } + } else { + /* No "get string" function defined; read character by character */ +- apr_size_t i = 0; ++ apr_size_t i = offset; + + if (bufsize < 2) { + /* too small, assume caller is crazy */ + return APR_EINVAL; + } +- buf[0] = '\0'; ++ buf[offset] = '\0'; + + while (1) { + char c; + rc = cfp->getch(&c, cfp->param); + if (rc == APR_EOF) { +- if (i > 0) ++ if (i > offset) + break; + else + return APR_EOF; +@@ -1051,11 +1051,11 @@ static apr_status_t ap_cfg_getline_core(char *buf, apr_size_t bufsize, + break; + } + } +- else if (i >= bufsize - 2) { +- return APR_ENOSPC; +- } + buf[i] = c; + ++i; ++ if (i >= bufsize - 1) { ++ return APR_ENOSPC; ++ } + } + buf[i] = '\0'; + } +@@ -1089,7 +1089,7 @@ static int cfg_trim_line(char *buf) + AP_DECLARE(apr_status_t) ap_cfg_getline(char *buf, apr_size_t bufsize, + ap_configfile_t *cfp) + { +- apr_status_t rc = ap_cfg_getline_core(buf, bufsize, cfp); ++ apr_status_t rc = ap_cfg_getline_core(buf, bufsize, 0, cfp); + if (rc == APR_SUCCESS) + cfg_trim_line(buf); + return rc; +@@ -1116,7 +1116,7 @@ AP_DECLARE(apr_status_t) ap_varbuf_cfg_getline(struct ap_varbuf *vb, + } + + for (;;) { +- rc = ap_cfg_getline_core(vb->buf + vb->strlen, vb->avail - vb->strlen, cfp); ++ rc = ap_cfg_getline_core(vb->buf, vb->avail, vb->strlen, cfp); + if (rc == APR_ENOSPC || rc == APR_SUCCESS) + vb->strlen += strlen(vb->buf + vb->strlen); + if (rc != APR_ENOSPC) diff --git a/SOURCES/httpd-2.4.6-r1651658.patch b/SOURCES/httpd-2.4.6-r1651658.patch new file mode 100644 index 0000000..d0de5d5 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1651658.patch @@ -0,0 +1,22 @@ +--- a/modules/proxy/mod_proxy_fcgi.c 2015/01/14 13:22:50 1651657 ++++ b/modules/proxy/mod_proxy_fcgi.c 2015/01/14 13:24:10 1651658 +@@ -204,9 +204,19 @@ + apr_status_t rv; + apr_size_t len; + int i, numenv; ++ char *proxyfilename = r->filename; ++ ++ /* Strip balancer prefix */ ++ if (r->filename && !strncmp(r->filename, "proxy:balancer://", 17)) { ++ char *newfname = apr_pstrdup(r->pool, r->filename+17); ++ newfname = ap_strchr(newfname, '/'); ++ r->filename = newfname; ++ } + + ap_add_common_vars(r); + ap_add_cgi_vars(r); ++ ++ r->filename = proxyfilename; + + /* XXX are there any FastCGI specific env vars we need to send? */ + diff --git a/SOURCES/httpd-2.4.6-r1662640.patch b/SOURCES/httpd-2.4.6-r1662640.patch new file mode 100644 index 0000000..3d1f726 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1662640.patch @@ -0,0 +1,40 @@ +--- a/modules/ssl/ssl_engine_kernel.c 2015/02/27 06:05:11 1662639 ++++ b/modules/ssl/ssl_engine_kernel.c 2015/02/27 06:18:31 1662640 +@@ -80,7 +80,8 @@ + + if (SSL_get_state(ssl) != SSL_ST_OK) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02030) +- "TLS upgrade handshake failed: not accepted by client!?"); ++ "TLS upgrade handshake failed"); ++ ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, r->server); + + return APR_ECONNABORTED; + } +@@ -314,6 +315,16 @@ + int depth, verify_old, verify, n; + + if (ssl) { ++ /* ++ * We should have handshaken here (on handshakeserver), ++ * otherwise we are being redirected (ErrorDocument) from ++ * a renegotiation failure below. The access is still ++ * forbidden in the latter case, let ap_die() handle ++ * this recursive (same) error. ++ */ ++ if (SSL_get_state(ssl) != SSL_ST_OK) { ++ return HTTP_FORBIDDEN; ++ } + ctx = SSL_get_SSL_CTX(ssl); + } + +@@ -828,8 +839,8 @@ + + if (SSL_get_state(ssl) != SSL_ST_OK) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02261) +- "Re-negotiation handshake failed: " +- "Not accepted by client!?"); ++ "Re-negotiation handshake failed"); ++ ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, r->server); + + r->connection->keepalive = AP_CONN_CLOSE; + return HTTP_FORBIDDEN; diff --git a/SOURCES/httpd-2.4.6-r1663647.patch b/SOURCES/httpd-2.4.6-r1663647.patch new file mode 100644 index 0000000..4d082cf --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1663647.patch @@ -0,0 +1,22 @@ +--- a/modules/aaa/mod_authn_dbd.c 2015/03/03 11:11:33 1663646 ++++ b/modules/aaa/mod_authn_dbd.c 2015/03/03 11:12:18 1663647 +@@ -174,7 +174,8 @@ + i++; + } + #endif +- dbd_password = apr_dbd_get_entry(dbd->driver, row, 0); ++ dbd_password = apr_pstrdup(r->pool, ++ apr_dbd_get_entry(dbd->driver, row, 0)); + } + /* we can't break out here or row won't get cleaned up */ + } +@@ -269,7 +270,8 @@ + i++; + } + #endif +- dbd_hash = apr_dbd_get_entry(dbd->driver, row, 0); ++ dbd_hash = apr_pstrdup(r->pool, ++ apr_dbd_get_entry(dbd->driver, row, 0)); + } + /* we can't break out here or row won't get cleaned up */ + } diff --git a/SOURCES/httpd-2.4.6-r1664565.patch b/SOURCES/httpd-2.4.6-r1664565.patch new file mode 100644 index 0000000..65f9a99 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1664565.patch @@ -0,0 +1,68 @@ +--- httpd/modules/mappers/mod_rewrite.c 2015/03/06 08:55:34 1664564 ++++ httpd/modules/mappers/mod_rewrite.c 2015/03/06 09:14:07 1664565 +@@ -267,6 +267,8 @@ + const char *dbdq; /* SQL SELECT statement for rewritemap */ + const char *checkfile2; /* filename to check for map existence + NULL if only one file */ ++ const char *user; /* run RewriteMap program as this user */ ++ const char *group; /* run RewriteMap program as this group */ + } rewritemap_entry; + + /* special pattern types for RewriteCond */ +@@ -1171,6 +1173,7 @@ + + static apr_status_t rewritemap_program_child(apr_pool_t *p, + const char *progname, char **argv, ++ const char *user, const char *group, + apr_file_t **fpout, + apr_file_t **fpin) + { +@@ -1183,6 +1186,8 @@ + APR_FULL_BLOCK, APR_NO_PIPE)) + && APR_SUCCESS == (rc=apr_procattr_dir_set(procattr, + ap_make_dirstr_parent(p, argv[0]))) ++ && (!user || APR_SUCCESS == (rc=apr_procattr_user_set(procattr, user, ""))) ++ && (!group || APR_SUCCESS == (rc=apr_procattr_group_set(procattr, group))) + && APR_SUCCESS == (rc=apr_procattr_cmdtype_set(procattr, APR_PROGRAM)) + && APR_SUCCESS == (rc=apr_procattr_child_errfn_set(procattr, + rewrite_child_errfn)) +@@ -1240,6 +1245,7 @@ + } + + rc = rewritemap_program_child(p, map->argv[0], map->argv, ++ map->user, map->group, + &fpout, &fpin); + if (rc != APR_SUCCESS || fpin == NULL || fpout == NULL) { + ap_log_error(APLOG_MARK, APLOG_ERR, rc, s, APLOGNO(00654) +@@ -3018,7 +3024,7 @@ + } + + static const char *cmd_rewritemap(cmd_parms *cmd, void *dconf, const char *a1, +- const char *a2) ++ const char *a2, const char *a3) + { + rewrite_server_conf *sconf; + rewritemap_entry *newmap; +@@ -3124,6 +3130,11 @@ + + newmap->type = MAPTYPE_PRG; + newmap->checkfile = newmap->argv[0]; ++ if (a3) { ++ char *tok_cntx; ++ newmap->user = apr_strtok(apr_pstrdup(cmd->pool, a3), ":", &tok_cntx); ++ newmap->group = apr_strtok(NULL, ":", &tok_cntx); ++ } + } + else if (strncasecmp(a2, "int:", 4) == 0) { + newmap->type = MAPTYPE_INT; +@@ -5205,8 +5216,8 @@ + "an input string and a to be applied regexp-pattern"), + AP_INIT_RAW_ARGS("RewriteRule", cmd_rewriterule, NULL, OR_FILEINFO, + "an URL-applied regexp-pattern and a substitution URL"), +- AP_INIT_TAKE2( "RewriteMap", cmd_rewritemap, NULL, RSRC_CONF, +- "a mapname and a filename"), ++ AP_INIT_TAKE23( "RewriteMap", cmd_rewritemap, NULL, RSRC_CONF, ++ "a mapname and a filename and options"), + { NULL } + }; + diff --git a/SOURCES/httpd-2.4.6-r1668532.patch b/SOURCES/httpd-2.4.6-r1668532.patch new file mode 100644 index 0000000..6973eeb --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1668532.patch @@ -0,0 +1,67 @@ +diff --git a/server/scoreboard.c b/server/scoreboard.c +index a2e5daf..f989b99 100644 +--- a/server/scoreboard.c ++++ b/server/scoreboard.c +@@ -138,8 +138,6 @@ AP_DECLARE(int) ap_calc_scoreboard_size(void) + scoreboard_size += sizeof(process_score) * server_limit; + scoreboard_size += sizeof(worker_score) * server_limit * thread_limit; + +- pfn_ap_logio_get_last_bytes = APR_RETRIEVE_OPTIONAL_FN(ap_logio_get_last_bytes); +- + return scoreboard_size; + } + +@@ -148,6 +146,11 @@ AP_DECLARE(void) ap_init_scoreboard(void *shared_score) + char *more_storage; + int i; + ++ pfn_ap_logio_get_last_bytes = APR_RETRIEVE_OPTIONAL_FN(ap_logio_get_last_bytes); ++ if (!shared_score) { ++ return; ++ } ++ + ap_calc_scoreboard_size(); + ap_scoreboard_image = + ap_calloc(1, sizeof(scoreboard) + server_limit * sizeof(worker_score *)); +@@ -299,8 +302,6 @@ int ap_create_scoreboard(apr_pool_t *p, ap_scoreboard_e sb_type) + apr_status_t rv; + #endif + +- pfn_ap_logio_get_last_bytes = APR_RETRIEVE_OPTIONAL_FN(ap_logio_get_last_bytes); +- + if (ap_scoreboard_image) { + ap_scoreboard_image->global->restart_time = apr_time_now(); + memset(ap_scoreboard_image->parent, 0, +@@ -309,6 +310,7 @@ int ap_create_scoreboard(apr_pool_t *p, ap_scoreboard_e sb_type) + memset(ap_scoreboard_image->servers[i], 0, + sizeof(worker_score) * thread_limit); + } ++ ap_init_scoreboard(NULL); + return OK; + } + +diff --git a/server/core.c b/server/core.c +index c125015..eaa81a6 100644 +--- a/server/core.c ++++ b/server/core.c +@@ -4843,6 +4843,11 @@ static void core_child_init(apr_pool_t *pchild, server_rec *s) + apr_random_after_fork(&proc); + } + ++static void core_optional_fn_retrieve(void) ++{ ++ ap_init_scoreboard(NULL); ++} ++ + AP_CORE_DECLARE(void) ap_random_parent_after_fork(void) + { + /* +@@ -5022,6 +5027,8 @@ static void register_hooks(apr_pool_t *p) + APR_HOOK_REALLY_LAST); + ap_hook_dirwalk_stat(core_dirwalk_stat, NULL, NULL, APR_HOOK_REALLY_LAST); + ap_hook_open_htaccess(ap_open_htaccess, NULL, NULL, APR_HOOK_REALLY_LAST); ++ ap_hook_optional_fn_retrieve(core_optional_fn_retrieve, NULL, NULL, ++ APR_HOOK_MIDDLE); + + /* register the core's insert_filter hook and register core-provided + * filters diff --git a/SOURCES/httpd-2.4.6-r1674222.patch b/SOURCES/httpd-2.4.6-r1674222.patch new file mode 100644 index 0000000..60356b0 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1674222.patch @@ -0,0 +1,81 @@ +Index: acinclude.m4 +=================================================================== +--- a/acinclude.m4 (revision 1667671) ++++ b/acinclude.m4 (working copy) +@@ -43,6 +43,7 @@ + APACHE_SUBST(installbuilddir) + APACHE_SUBST(runtimedir) + APACHE_SUBST(proxycachedir) ++ APACHE_SUBST(davlockdb) + APACHE_SUBST(other_targets) + APACHE_SUBST(progname) + APACHE_SUBST(prefix) +@@ -710,6 +711,7 @@ + APACHE_SUBST_EXPANDED_ARG(runtimedir) + APACHE_SUBST_EXPANDED_ARG(logfiledir) + APACHE_SUBST_EXPANDED_ARG(proxycachedir) ++ APACHE_SUBST_EXPANDED_ARG(davlockdb) + ]) + + dnl +Index: build/mkconfNW.awk +=================================================================== +--- a/build/mkconfNW.awk (revision 1667671) ++++ b/build/mkconfNW.awk (working copy) +@@ -26,6 +26,7 @@ + A["runtimedir"] = "logs" + A["errordir"] = "error" + A["proxycachedir"] = "proxy" ++ A["davlockdb"] = "davlockdb" + + B["htdocsdir"] = A["ServerRoot"]"/"A["htdocsdir"] + B["iconsdir"] = A["ServerRoot"]"/"A["iconsdir"] +@@ -32,6 +33,7 @@ + B["manualdir"] = A["ServerRoot"]"/"A["manualdir"] + B["errordir"] = A["ServerRoot"]"/"A["errordir"] + B["proxycachedir"] = A["ServerRoot"]"/"A["proxycachedir"] ++ B["davlockdb"] = A["ServerRoot"]"/"A["davlockdb"] + B["cgidir"] = A["ServerRoot"]"/"A["cgidir"] + B["logfiledir"] = A["logfiledir"] + B["sysconfdir"] = A["sysconfdir"] +Index: include/ap_config_layout.h.in +=================================================================== +--- a/include/ap_config_layout.h.in (revision 1667671) ++++ b/include/ap_config_layout.h.in (working copy) +@@ -60,5 +60,7 @@ + #define DEFAULT_REL_LOGFILEDIR "@rel_logfiledir@" + #define DEFAULT_EXP_PROXYCACHEDIR "@exp_proxycachedir@" + #define DEFAULT_REL_PROXYCACHEDIR "@rel_proxycachedir@" ++#define DEFAULT_EXP_DAVLOCKDB "@exp_davlockdb@" ++#define DEFAULT_REL_DAVLOCKDB "@rel_davlockdb@" + + #endif /* AP_CONFIG_LAYOUT_H */ +Index: modules/dav/fs/mod_dav_fs.c +=================================================================== +--- a/modules/dav/fs/mod_dav_fs.c (revision 1667671) ++++ b/modules/dav/fs/mod_dav_fs.c (working copy) +@@ -17,6 +17,7 @@ + #include "httpd.h" + #include "http_config.h" + #include "apr_strings.h" ++#include "ap_config_auto.h" + + #include "mod_dav.h" + #include "repos.h" +@@ -39,7 +40,15 @@ + + static void *dav_fs_create_server_config(apr_pool_t *p, server_rec *s) + { +- return apr_pcalloc(p, sizeof(dav_fs_server_conf)); ++ dav_fs_server_conf *conf = apr_pcalloc(p, sizeof(dav_fs_server_conf)); ++#ifdef DEFAULT_EXP_DAVLOCKDB ++ conf->lockdb_path = DEFAULT_EXP_DAVLOCKDB; ++ if (*conf->lockdb_path == '\0') { ++ conf->lockdb_path = NULL; ++ } ++#endif ++ ++ return conf; + } + + static void *dav_fs_merge_server_config(apr_pool_t *p, diff --git a/SOURCES/httpd-2.4.6-r1681107.patch b/SOURCES/httpd-2.4.6-r1681107.patch new file mode 100644 index 0000000..9a02995 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1681107.patch @@ -0,0 +1,84 @@ +Index: modules/aaa/mod_authz_dbd.c +=================================================================== +--- a/modules/aaa/mod_authz_dbd.c (revision 1681106) ++++ b/modules/aaa/mod_authz_dbd.c (revision 1681107) +@@ -174,7 +174,9 @@ + action, r->user, message?message:noerror); + } + else if (newuri == NULL) { +- newuri = apr_dbd_get_entry(dbd->driver, row, 0); ++ newuri = ++ apr_pstrdup(r->pool, ++ apr_dbd_get_entry(dbd->driver, row, 0)); + } + /* we can't break out here or row won't get cleaned up */ + } +@@ -204,7 +206,6 @@ + apr_dbd_prepared_t *query; + apr_dbd_results_t *res = NULL; + apr_dbd_row_t *row = NULL; +- const char **group; + + if (cfg->query == NULL) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01649) +@@ -224,8 +225,9 @@ + rv != -1; + rv = apr_dbd_get_row(dbd->driver, r->pool, res, &row, -1)) { + if (rv == 0) { +- group = apr_array_push(groups); +- *group = apr_dbd_get_entry(dbd->driver, row, 0); ++ APR_ARRAY_PUSH(groups, const char *) = ++ apr_pstrdup(r->pool, ++ apr_dbd_get_entry(dbd->driver, row, 0)); + } + else { + message = apr_dbd_error(dbd->driver, dbd->handle, rv); +Index: modules/session/mod_session_dbd.c +=================================================================== +--- a/modules/session/mod_session_dbd.c (revision 1681106) ++++ b/modules/session/mod_session_dbd.c (revision 1681107) +@@ -138,7 +138,8 @@ + return APR_EGENERAL; + } + if (*val == NULL) { +- *val = apr_dbd_get_entry(dbd->driver, row, 0); ++ *val = apr_pstrdup(r->pool, ++ apr_dbd_get_entry(dbd->driver, row, 0)); + } + /* we can't break out here or row won't get cleaned up */ + } +Index: modules/mappers/mod_rewrite.c +=================================================================== +--- a/modules/mappers/mod_rewrite.c (revision 1681106) ++++ b/modules/mappers/mod_rewrite.c (revision 1681107) +@@ -1352,12 +1352,14 @@ + while ((rv = apr_dbd_get_row(db->driver, r->pool, res, &row, -1)) == 0) { + ++n; + if (ret == NULL) { +- ret = apr_dbd_get_entry(db->driver, row, 0); ++ ret = apr_pstrdup(r->pool, ++ apr_dbd_get_entry(db->driver, row, 0)); + } + else { + /* randomise crudely amongst multiple results */ + if ((double)rand() < (double)RAND_MAX/(double)n) { +- ret = apr_dbd_get_entry(db->driver, row, 0); ++ ret = apr_pstrdup(r->pool, ++ apr_dbd_get_entry(db->driver, row, 0)); + } + } + } +@@ -1370,11 +1372,11 @@ + case 0: + return NULL; + case 1: +- return apr_pstrdup(r->pool, ret); ++ return ret; + default: + /* what's a fair rewritelog level for this? */ + rewritelog((r, 3, NULL, "Multiple values found for %s", key)); +- return apr_pstrdup(r->pool, ret); ++ return ret; + } + } + diff --git a/SOURCES/httpd-2.4.6-r1681114.patch b/SOURCES/httpd-2.4.6-r1681114.patch new file mode 100644 index 0000000..d112972 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1681114.patch @@ -0,0 +1,157 @@ +diff --git a/modules/http/http_request.c b/modules/http/http_request.c +index cdfec8b..c97dc77 100644 +--- a/modules/http/http_request.c ++++ b/modules/http/http_request.c +@@ -73,19 +73,22 @@ static void update_r_in_filters(ap_filter_t *f, + } + } + +-AP_DECLARE(void) ap_die(int type, request_rec *r) ++static void ap_die_r(int type, request_rec *r, int recursive_error) + { +- int error_index = ap_index_of_response(type); +- char *custom_response = ap_response_code_string(r, error_index); +- int recursive_error = 0; ++ char *custom_response; + request_rec *r_1st_err = r; + +- if (type == AP_FILTER_ERROR) { ++ if (type == OK || type == DONE){ ++ ap_finalize_request_protocol(r); ++ return; ++ } ++ ++ if (!ap_is_HTTP_VALID_RESPONSE(type)) { + ap_filter_t *next; + + /* + * Check if we still have the ap_http_header_filter in place. If +- * this is the case we should not ignore AP_FILTER_ERROR here because ++ * this is the case we should not ignore the error here because + * it means that we have not sent any response at all and never + * will. This is bad. Sent an internal server error instead. + */ +@@ -99,8 +102,14 @@ AP_DECLARE(void) ap_die(int type, request_rec *r) + * next->frec == ap_http_header_filter + */ + if (next) { +- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01579) +- "Custom error page caused AP_FILTER_ERROR"); ++ if (type != AP_FILTER_ERROR) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01579) ++ "Invalid response status %i", type); ++ } ++ else { ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02831) ++ "Response from AP_FILTER_ERROR"); ++ } + type = HTTP_INTERNAL_SERVER_ERROR; + } + else { +@@ -108,20 +117,13 @@ AP_DECLARE(void) ap_die(int type, request_rec *r) + } + } + +- if (type == DONE) { +- ap_finalize_request_protocol(r); +- return; +- } +- + /* + * The following takes care of Apache redirects to custom response URLs + * Note that if we are already dealing with the response to some other + * error condition, we just report on the original error, and give up on + * any attempt to handle the other thing "intelligently"... + */ +- if (r->status != HTTP_OK) { +- recursive_error = type; +- ++ if (recursive_error != HTTP_OK) { + while (r_1st_err->prev && (r_1st_err->prev->status != HTTP_OK)) + r_1st_err = r_1st_err->prev; /* Get back to original error */ + +@@ -140,6 +142,10 @@ AP_DECLARE(void) ap_die(int type, request_rec *r) + } + + custom_response = NULL; /* Do NOT retry the custom thing! */ ++ } else { ++ int error_index = ap_index_of_response(type); ++ custom_response = ap_response_code_string(r, error_index); ++ recursive_error = 0; + } + + r->status = type; +@@ -216,6 +222,11 @@ AP_DECLARE(void) ap_die(int type, request_rec *r) + ap_send_error_response(r_1st_err, recursive_error); + } + ++AP_DECLARE(void) ap_die(int type, request_rec *r) ++{ ++ ap_die_r(type, r, r->status); ++} ++ + static void check_pipeline(conn_rec *c) + { + if (c->keepalive != AP_CONN_CLOSE) { +@@ -337,18 +348,7 @@ void ap_process_async_request(request_rec *r) + apr_thread_mutex_unlock(r->invoke_mtx); + #endif + +- if (access_status == DONE) { +- /* e.g., something not in storage like TRACE */ +- access_status = OK; +- } +- +- if (access_status == OK) { +- ap_finalize_request_protocol(r); +- } +- else { +- r->status = HTTP_OK; +- ap_die(access_status, r); +- } ++ ap_die_r(access_status, r, HTTP_OK); + + ap_process_request_after_handler(r); + } +@@ -631,8 +631,8 @@ AP_DECLARE(void) ap_internal_fast_redirect(request_rec *rr, request_rec *r) + + AP_DECLARE(void) ap_internal_redirect(const char *new_uri, request_rec *r) + { +- request_rec *new = internal_internal_redirect(new_uri, r); + int access_status; ++ request_rec *new = internal_internal_redirect(new_uri, r); + + AP_INTERNAL_REDIRECT(r->uri, new_uri); + +@@ -648,12 +648,7 @@ AP_DECLARE(void) ap_internal_redirect(const char *new_uri, request_rec *r) + access_status = ap_invoke_handler(new); + } + } +- if (access_status == OK) { +- ap_finalize_request_protocol(new); +- } +- else { +- ap_die(access_status, new); +- } ++ ap_die(access_status, new); + } + + /* This function is designed for things like actions or CGI scripts, when +@@ -674,15 +669,9 @@ AP_DECLARE(void) ap_internal_redirect_handler(const char *new_uri, request_rec * + ap_set_content_type(new, r->content_type); + access_status = ap_process_request_internal(new); + if (access_status == OK) { +- if ((access_status = ap_invoke_handler(new)) != 0) { +- ap_die(access_status, new); +- return; +- } +- ap_finalize_request_protocol(new); +- } +- else { +- ap_die(access_status, new); ++ access_status = ap_invoke_handler(new); + } ++ ap_die(access_status, new); + } + + AP_DECLARE(void) ap_allow_methods(request_rec *r, int reset, ...) diff --git a/SOURCES/httpd-2.4.6-r1681289.patch b/SOURCES/httpd-2.4.6-r1681289.patch new file mode 100644 index 0000000..f4f63ac --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1681289.patch @@ -0,0 +1,19 @@ +diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c +index a78224b..e672e4a 100644 +--- a/modules/proxy/proxy_util.c ++++ b/modules/proxy/proxy_util.c +@@ -2260,8 +2260,12 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, + * The scheme handler decides if this is permanent or + * short living pool. + */ +- /* are we connecting directly, or via a proxy? */ +- if (!proxyname) { ++ /* Unless we are connecting the backend via a (forward Proxy)Remote, we ++ * have to use the original form of the URI (non absolute), but this is ++ * also the case via a remote proxy using the CONNECT method since the ++ * original request (and URI) is to be embedded in the body. ++ */ ++ if (!proxyname || conn->is_ssl) { + *url = apr_pstrcat(p, uri->path, uri->query ? "?" : "", + uri->query ? uri->query : "", + uri->fragment ? "#" : "", diff --git a/SOURCES/httpd-2.4.6-r1683112.patch b/SOURCES/httpd-2.4.6-r1683112.patch new file mode 100644 index 0000000..bb412c9 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1683112.patch @@ -0,0 +1,45 @@ +diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c +index 7f96aff..5517e08 100644 +--- a/modules/proxy/mod_proxy.c ++++ b/modules/proxy/mod_proxy.c +@@ -1118,7 +1118,7 @@ static int proxy_handler(request_rec *r) + AP_PROXY_RUN(r, worker, conf, url, attempts); + access_status = proxy_run_scheme_handler(r, worker, conf, + url, NULL, 0); +- if (access_status == OK) ++ if (access_status == OK || apr_table_get(r->notes, "proxy-error-override")) + break; + else if (access_status == HTTP_INTERNAL_SERVER_ERROR) { + /* Unrecoverable server error. +diff --git a/modules/proxy/mod_proxy_ajp.c b/modules/proxy/mod_proxy_ajp.c +index cf52a7d..380b870 100644 +--- a/modules/proxy/mod_proxy_ajp.c ++++ b/modules/proxy/mod_proxy_ajp.c +@@ -636,6 +636,11 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r, + */ + rv = r->status; + r->status = HTTP_OK; ++ /* ++ * prevent proxy_handler() from treating this as an ++ * internal error. ++ */ ++ apr_table_setn(r->notes, "proxy-error-override", "1"); + } + else { + rv = OK; +diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c +index 89b5d15..bb5cdf9 100644 +--- a/modules/proxy/mod_proxy_http.c ++++ b/modules/proxy/mod_proxy_http.c +@@ -1648,6 +1648,11 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, + } + ap_discard_request_body(backend->r); + } ++ /* ++ * prevent proxy_handler() from treating this as an ++ * internal error. ++ */ ++ apr_table_setn(r->notes, "proxy-error-override", "1"); + return proxy_status; + } + diff --git a/SOURCES/httpd-2.4.6-r1684462.patch b/SOURCES/httpd-2.4.6-r1684462.patch new file mode 100644 index 0000000..ff5fe4b --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1684462.patch @@ -0,0 +1,34 @@ +--- a/modules/ssl/ssl_engine_kernel.c 2015/06/09 15:55:41 1684461 ++++ b/modules/ssl/ssl_engine_kernel.c 2015/06/09 16:09:28 1684462 +@@ -1940,7 +1940,7 @@ + #ifndef OPENSSL_NO_TLSEXT + /* + * This callback function is executed when OpenSSL encounters an extended +- * client hello with a server name indication extension ("SNI", cf. RFC 4366). ++ * client hello with a server name indication extension ("SNI", cf. RFC 6066). + */ + int ssl_callback_ServerNameIndication(SSL *ssl, int *al, modssl_ctx_t *mctx) + { +@@ -1962,7 +1962,21 @@ + "No matching SSL virtual host for servername " + "%s found (using default/first virtual host)", + servername); +- return SSL_TLSEXT_ERR_ALERT_WARNING; ++ /* ++ * RFC 6066 section 3 says "It is NOT RECOMMENDED to send ++ * a warning-level unrecognized_name(112) alert, because ++ * the client's behavior in response to warning-level alerts ++ * is unpredictable." ++ * ++ * To maintain backwards compatibility in mod_ssl, we ++ * no longer send any alert (neither warning- nor fatal-level), ++ * i.e. we take the second action suggested in RFC 6066: ++ * "If the server understood the ClientHello extension but ++ * does not recognize the server name, the server SHOULD take ++ * one of two actions: either abort the handshake by sending ++ * a fatal-level unrecognized_name(112) alert or continue ++ * the handshake." ++ */ + } + } + } diff --git a/SOURCES/httpd-2.4.6-r1688399.patch b/SOURCES/httpd-2.4.6-r1688399.patch new file mode 100644 index 0000000..91f94ee --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1688399.patch @@ -0,0 +1,11 @@ +--- a/modules/metadata/mod_remoteip.c 2015/06/30 08:36:49 1688398 ++++ b/modules/metadata/mod_remoteip.c 2015/06/30 08:40:17 1688399 +@@ -255,7 +255,7 @@ + } + remote = apr_pstrdup(r->pool, remote); + +- temp_sa = c->client_addr; ++ temp_sa = r->useragent_addr ? r->useragent_addr : c->client_addr; + + while (remote) { + diff --git a/SOURCES/httpd-2.4.6-r1705528.patch b/SOURCES/httpd-2.4.6-r1705528.patch new file mode 100644 index 0000000..0be0309 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1705528.patch @@ -0,0 +1,24 @@ +Index: modules/cache/cache_util.c +=================================================================== +--- a/modules/cache/cache_util.c (revision 1705527) ++++ b/modules/cache/cache_util.c (revision 1705528) +@@ -1254,7 +1254,6 @@ + headers_out = apr_table_overlay(r->pool, r->headers_out, + r->err_headers_out); + +- apr_table_clear(r->err_headers_out); + + headers_out = ap_cache_cacheable_headers(r->pool, headers_out, + r->server); +Index: modules/cache/mod_cache.c +=================================================================== +--- a/modules/cache/mod_cache.c (revision 1705527) ++++ b/modules/cache/mod_cache.c (revision 1705528) +@@ -1452,6 +1452,7 @@ + * headers that might have snuck in. + */ + r->headers_out = ap_cache_cacheable_headers_out(r); ++ apr_table_clear(r->err_headers_out); + + /* Merge in our cached headers. However, keep any updated values. */ + /* take output, overlay on top of cached */ diff --git a/SOURCES/httpd-2.4.6-r1723522.patch b/SOURCES/httpd-2.4.6-r1723522.patch new file mode 100644 index 0000000..83db1c8 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1723522.patch @@ -0,0 +1,13 @@ +diff --git a/docs/manual/mod/mod_log_debug.html.en b/docs/manual/mod/mod_log_debug.html.en +index d3d4bd7..1ffd37f 100644 +--- a/docs/manual/mod/mod_log_debug.html.en ++++ b/docs/manual/mod/mod_log_debug.html.en +@@ -61,7 +61,7 @@ + Log message if request to /foo/* is processed in a sub-request: +
    + <Location /foo/>
    +-  LogMessage "subrequest to /foo/" hook=type_checker expr=%{IS_SUBREQ}
    ++  LogMessage "subrequest to /foo/" hook=type_checker "expr=-T %{IS_SUBREQ}"
    + </Location>
    +         
    + diff --git a/SOURCES/httpd-2.4.6-r1726019.patch b/SOURCES/httpd-2.4.6-r1726019.patch new file mode 100644 index 0000000..4408d8c --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1726019.patch @@ -0,0 +1,20 @@ +diff --git a/modules/proxy/mod_proxy_fcgi.c b/modules/proxy/mod_proxy_fcgi.c +index 19fed62..7889b0e 100644 +--- a/modules/proxy/mod_proxy_fcgi.c ++++ b/modules/proxy/mod_proxy_fcgi.c +@@ -927,6 +927,15 @@ static int fcgi_do_request(apr_pool_t *p, request_rec *r, + /* Step 3: Read records from the back end server and handle them. */ + rv = dispatch(conn, conf, r, request_id); + if (rv != APR_SUCCESS) { ++ /* If the client aborted the connection during retrieval or (partially) ++ * sending the response, dont't return a HTTP_SERVICE_UNAVAILABLE, since ++ * this is not a backend problem. */ ++ if (r->connection->aborted) { ++ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, r, ++ "The client aborted the connection."); ++ conn->close = 1; ++ return OK; ++ } + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01075) + "Error dispatching request to %s:", server_portstr); + conn->close = 1; diff --git a/SOURCES/httpd-2.4.6-r1738878.patch b/SOURCES/httpd-2.4.6-r1738878.patch new file mode 100644 index 0000000..0aab1c4 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1738878.patch @@ -0,0 +1,139 @@ +diff --git a/modules/proxy/ajp.h b/modules/proxy/ajp.h +index c65ebe5..330573b 100644 +--- a/modules/proxy/ajp.h ++++ b/modules/proxy/ajp.h +@@ -413,11 +413,13 @@ apr_status_t ajp_ilink_receive(apr_socket_t *sock, ajp_msg_t *msg); + * @param r current request + * @param buffsize max size of the AJP packet. + * @param uri requested uri ++ * @param secret authentication secret + * @return APR_SUCCESS or error + */ + apr_status_t ajp_send_header(apr_socket_t *sock, request_rec *r, + apr_size_t buffsize, +- apr_uri_t *uri); ++ apr_uri_t *uri, ++ const char *secret); + + /** + * Read the ajp message and return the type of the message. +diff --git a/modules/proxy/ajp_header.c b/modules/proxy/ajp_header.c +index 074f0a8..53571ee 100644 +--- a/modules/proxy/ajp_header.c ++++ b/modules/proxy/ajp_header.c +@@ -213,7 +213,8 @@ AJPV13_REQUEST/AJPV14_REQUEST= + + static apr_status_t ajp_marshal_into_msgb(ajp_msg_t *msg, + request_rec *r, +- apr_uri_t *uri) ++ apr_uri_t *uri, ++ const char *secret) + { + int method; + apr_uint32_t i, num_headers = 0; +@@ -293,17 +294,15 @@ static apr_status_t ajp_marshal_into_msgb(ajp_msg_t *msg, + i, elts[i].key, elts[i].val); + } + +-/* XXXX need to figure out how to do this +- if (s->secret) { ++ if (secret) { + if (ajp_msg_append_uint8(msg, SC_A_SECRET) || +- ajp_msg_append_string(msg, s->secret)) { ++ ajp_msg_append_string(msg, secret)) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, +- "Error ajp_marshal_into_msgb - " ++ "ajp_marshal_into_msgb: " + "Error appending secret"); + return APR_EGENERAL; + } + } +- */ + + if (r->user) { + if (ajp_msg_append_uint8(msg, SC_A_REMOTE_USER) || +@@ -628,7 +627,8 @@ static apr_status_t ajp_unmarshal_response(ajp_msg_t *msg, + apr_status_t ajp_send_header(apr_socket_t *sock, + request_rec *r, + apr_size_t buffsize, +- apr_uri_t *uri) ++ apr_uri_t *uri, ++ const char *secret) + { + ajp_msg_t *msg; + apr_status_t rc; +@@ -640,7 +640,7 @@ apr_status_t ajp_send_header(apr_socket_t *sock, + return rc; + } + +- rc = ajp_marshal_into_msgb(msg, r, uri); ++ rc = ajp_marshal_into_msgb(msg, r, uri, secret); + if (rc != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00988) + "ajp_send_header: ajp_marshal_into_msgb failed"); +diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c +index 5517e08..e998f58 100644 +--- a/modules/proxy/mod_proxy.c ++++ b/modules/proxy/mod_proxy.c +@@ -260,6 +260,12 @@ static const char *set_worker_param(apr_pool_t *p, + return "flusher name length must be < 16 characters"; + PROXY_STRNCPY(worker->s->flusher, val); + } ++ else if (!strcasecmp(key, "secret")) { ++ if (PROXY_STRNCPY(worker->s->secret, val) != APR_SUCCESS) { ++ return apr_psprintf(p, "Secret length must be < %d characters", ++ (int)sizeof(worker->s->secret)); ++ } ++ } + else { + return "unknown Worker parameter"; + } +diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h +index b702028..06f2b17 100644 +--- a/modules/proxy/mod_proxy.h ++++ b/modules/proxy/mod_proxy.h +@@ -317,6 +317,7 @@ PROXY_WORKER_DISABLED | PROXY_WORKER_STOPPED | PROXY_WORKER_IN_ERROR ) + #define PROXY_WORKER_MAX_HOSTNAME_SIZE 64 + #define PROXY_BALANCER_MAX_HOSTNAME_SIZE PROXY_WORKER_MAX_HOSTNAME_SIZE + #define PROXY_BALANCER_MAX_STICKY_SIZE 64 ++#define PROXY_WORKER_MAX_SECRET_SIZE 64 + + #define PROXY_MAX_PROVIDER_NAME_SIZE 16 + +@@ -394,6 +395,7 @@ typedef struct { + unsigned int disablereuse_set:1; + unsigned int was_malloced:1; + unsigned int is_name_matchable:1; ++ char secret[PROXY_WORKER_MAX_SECRET_SIZE]; /* authentication secret (e.g. AJP13) */ + } proxy_worker_shared; + + #define ALIGNED_PROXY_WORKER_SHARED_SIZE (APR_ALIGN_DEFAULT(sizeof(proxy_worker_shared))) +diff --git a/modules/proxy/mod_proxy_ajp.c b/modules/proxy/mod_proxy_ajp.c +index 380b870..81039bf 100644 +--- a/modules/proxy/mod_proxy_ajp.c ++++ b/modules/proxy/mod_proxy_ajp.c +@@ -196,6 +196,7 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r, + apr_off_t content_length = 0; + int original_status = r->status; + const char *original_status_line = r->status_line; ++ const char *secret = NULL; + + if (psf->io_buffer_size_set) + maxsize = psf->io_buffer_size; +@@ -205,12 +206,15 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r, + maxsize = AJP_MSG_BUFFER_SZ; + maxsize = APR_ALIGN(maxsize, 1024); + ++ if (*conn->worker->s->secret) ++ secret = conn->worker->s->secret; ++ + /* + * Send the AJP request to the remote server + */ + + /* send request headers */ +- status = ajp_send_header(conn->sock, r, maxsize, uri); ++ status = ajp_send_header(conn->sock, r, maxsize, uri, secret); + if (status != APR_SUCCESS) { + conn->close = 1; + ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(00868) diff --git a/SOURCES/httpd-2.4.6-r1748212.patch b/SOURCES/httpd-2.4.6-r1748212.patch new file mode 100644 index 0000000..69ff27f --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1748212.patch @@ -0,0 +1,70 @@ +# ./pullrev.sh 1748212 +http://svn.apache.org/viewvc?view=revision&revision=1748212 + +https://bugzilla.redhat.com/show_bug.cgi?id=1343582 + +diff -uap httpd-2.4.6/include/httpd.h.r1748212 httpd-2.4.6/include/httpd.h +--- httpd-2.4.6/include/httpd.h.r1748212 ++++ httpd-2.4.6/include/httpd.h +@@ -477,7 +477,7 @@ AP_DECLARE(const char *) ap_get_server_b + * When adding a new code here add it to status_lines as well. + * A future version should dynamically generate the apr_table_t at startup. + */ +-#define RESPONSE_CODES 83 ++#define RESPONSE_CODES 103 + + #define HTTP_CONTINUE 100 + #define HTTP_SWITCHING_PROTOCOLS 101 +@@ -525,6 +525,7 @@ AP_DECLARE(const char *) ap_get_server_b + #define HTTP_PRECONDITION_REQUIRED 428 + #define HTTP_TOO_MANY_REQUESTS 429 + #define HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE 431 ++#define HTTP_UNAVAILABLE_FOR_LEGAL_REASONS 451 + #define HTTP_INTERNAL_SERVER_ERROR 500 + #define HTTP_NOT_IMPLEMENTED 501 + #define HTTP_BAD_GATEWAY 502 +diff -uap httpd-2.4.6/modules/http/http_protocol.c.r1748212 httpd-2.4.6/modules/http/http_protocol.c +--- httpd-2.4.6/modules/http/http_protocol.c.r1748212 ++++ httpd-2.4.6/modules/http/http_protocol.c +@@ -146,7 +146,27 @@ static const char * const status_lines[R + "429 Too Many Requests", + NULL, /* 430 */ + "431 Request Header Fields Too Large", +-#define LEVEL_500 71 ++ NULL, /* 432 */ ++ NULL, /* 433 */ ++ NULL, /* 434 */ ++ NULL, /* 435 */ ++ NULL, /* 436 */ ++ NULL, /* 437 */ ++ NULL, /* 438 */ ++ NULL, /* 439 */ ++ NULL, /* 440 */ ++ NULL, /* 441 */ ++ NULL, /* 442 */ ++ NULL, /* 443 */ ++ NULL, /* 444 */ ++ NULL, /* 445 */ ++ NULL, /* 446 */ ++ NULL, /* 447 */ ++ NULL, /* 448 */ ++ NULL, /* 449 */ ++ NULL, /* 450 */ ++ "451 Unavailable For Legal Reasons", ++#define LEVEL_500 91 + "500 Internal Server Error", + "501 Not Implemented", + "502 Bad Gateway", +@@ -1295,6 +1315,12 @@ static const char *get_canned_error_stri + case HTTP_NETWORK_AUTHENTICATION_REQUIRED: + return("

    The client needs to authenticate to gain\n" + "network access.

    \n"); ++ case HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: ++ s1 = apr_pstrcat(p, ++ "

    Access to ", ap_escape_html(r->pool, r->uri), ++ "\nhas been denied for legal reasons.
    \n", ++ NULL); ++ return(add_optional_notes(r, s1, "error-notes", "

    \n")); + default: /* HTTP_INTERNAL_SERVER_ERROR */ + /* + * This comparison to expose error-notes could be modified to diff --git a/SOURCES/httpd-2.4.6-r1775832.patch b/SOURCES/httpd-2.4.6-r1775832.patch new file mode 100644 index 0000000..97c5f5f --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1775832.patch @@ -0,0 +1,16 @@ +--- a/modules/filters/mod_ext_filter.c 2016/12/23 12:35:43 1775831 ++++ b/modules/filters/mod_ext_filter.c 2016/12/23 12:36:26 1775832 +@@ -757,6 +757,13 @@ + break; + } + ++ if (AP_BUCKET_IS_ERROR(b)) { ++ apr_bucket *cpy; ++ apr_bucket_copy(b, &cpy); ++ APR_BRIGADE_INSERT_TAIL(bb_tmp, cpy); ++ break; ++ } ++ + rv = apr_bucket_read(b, &data, &len, APR_BLOCK_READ); + if (rv != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01463) "apr_bucket_read()"); diff --git a/SOURCES/httpd-2.4.6-r1805099.patch b/SOURCES/httpd-2.4.6-r1805099.patch new file mode 100644 index 0000000..4d7f419 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1805099.patch @@ -0,0 +1,46 @@ +diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c +index b10be15..506a046 100644 +--- a/modules/proxy/mod_proxy.c ++++ b/modules/proxy/mod_proxy.c +@@ -1320,6 +1320,7 @@ static void *create_proxy_dir_config(apr_pool_t *p, char *dummy) + new->error_override = 0; + new->error_override_set = 0; + new->add_forwarded_headers = 1; ++ new->add_forwarded_headers_set = 0; + + return (void *) new; + } +@@ -1350,7 +1351,12 @@ static void *merge_proxy_dir_config(apr_pool_t *p, void *basev, void *addv) + new->error_override_set = add->error_override_set || base->error_override_set; + new->alias = (add->alias_set == 0) ? base->alias : add->alias; + new->alias_set = add->alias_set || base->alias_set; +- new->add_forwarded_headers = add->add_forwarded_headers; ++ new->add_forwarded_headers = ++ (add->add_forwarded_headers_set == 0) ? base->add_forwarded_headers ++ : add->add_forwarded_headers; ++ new->add_forwarded_headers_set = add->add_forwarded_headers_set ++ || base->add_forwarded_headers_set; ++ + return new; + } + +@@ -1837,6 +1843,7 @@ static const char * + { + proxy_dir_conf *conf = dconf; + conf->add_forwarded_headers = flag; ++ conf->add_forwarded_headers_set = 1; + return NULL; + } + static const char * +diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h +index 06f2b17..8c76d4c 100644 +--- a/modules/proxy/mod_proxy.h ++++ b/modules/proxy/mod_proxy.h +@@ -219,6 +219,7 @@ typedef struct { + unsigned int error_override_set:1; + unsigned int alias_set:1; + unsigned int add_forwarded_headers:1; ++ unsigned int add_forwarded_headers_set:1; + } proxy_dir_conf; + + /* if we interpolate env vars per-request, we'll need a per-request diff --git a/SOURCES/httpd-2.4.6-r1811746.patch b/SOURCES/httpd-2.4.6-r1811746.patch new file mode 100644 index 0000000..6dc47bf --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1811746.patch @@ -0,0 +1,128 @@ +--- a/server/protocol.c 2017/10/10 17:47:25 1811745 ++++ b/server/protocol.c 2017/10/10 17:51:13 1811746 +@@ -1674,62 +1674,88 @@ + ctx->tmpbb = apr_brigade_create(r->pool, r->connection->bucket_alloc); + } + +- /* Loop through this set of buckets to compute their length +- */ ++ /* Loop through the brigade to count the length. To avoid ++ * arbitrary memory consumption with morphing bucket types, this ++ * loop will stop and pass on the brigade when necessary. */ + e = APR_BRIGADE_FIRST(b); + while (e != APR_BRIGADE_SENTINEL(b)) { ++ apr_status_t rv; ++ + if (APR_BUCKET_IS_EOS(e)) { + eos = 1; + break; + } +- if (e->length == (apr_size_t)-1) { ++ /* For a flush bucket, fall through to pass the brigade and ++ * flush now. */ ++ else if (APR_BUCKET_IS_FLUSH(e)) { ++ e = APR_BUCKET_NEXT(e); ++ } ++ /* For metadata bucket types other than FLUSH, loop. */ ++ else if (APR_BUCKET_IS_METADATA(e)) { ++ e = APR_BUCKET_NEXT(e); ++ continue; ++ } ++ /* For determinate length data buckets, count the length and ++ * continue. */ ++ else if (e->length != (apr_size_t)-1) { ++ r->bytes_sent += e->length; ++ e = APR_BUCKET_NEXT(e); ++ continue; ++ } ++ /* For indeterminate length data buckets, perform one read. */ ++ else /* e->length == (apr_size_t)-1 */ { + apr_size_t len; + const char *ignored; +- apr_status_t rv; +- +- /* This is probably a pipe bucket. Send everything +- * prior to this, and then read the data for this bucket. +- */ ++ + rv = apr_bucket_read(e, &ignored, &len, eblock); ++ if ((rv != APR_SUCCESS) && !APR_STATUS_IS_EAGAIN(rv)) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(00574) ++ "ap_content_length_filter: " ++ "apr_bucket_read() failed"); ++ return rv; ++ } + if (rv == APR_SUCCESS) { +- /* Attempt a nonblocking read next time through */ + eblock = APR_NONBLOCK_READ; ++ e = APR_BUCKET_NEXT(e); + r->bytes_sent += len; + } + else if (APR_STATUS_IS_EAGAIN(rv)) { +- /* Output everything prior to this bucket, and then +- * do a blocking read on the next batch. +- */ +- if (e != APR_BRIGADE_FIRST(b)) { +- apr_bucket *flush; +- apr_brigade_split_ex(b, e, ctx->tmpbb); +- flush = apr_bucket_flush_create(r->connection->bucket_alloc); +- +- APR_BRIGADE_INSERT_TAIL(b, flush); +- rv = ap_pass_brigade(f->next, b); +- if (rv != APR_SUCCESS || f->c->aborted) { +- return rv; +- } +- apr_brigade_cleanup(b); +- APR_BRIGADE_CONCAT(b, ctx->tmpbb); +- e = APR_BRIGADE_FIRST(b); ++ apr_bucket *flush; + +- ctx->data_sent = 1; +- } ++ /* Next read must block. */ + eblock = APR_BLOCK_READ; +- continue; +- } +- else { +- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(00574) +- "ap_content_length_filter: " +- "apr_bucket_read() failed"); +- return rv; ++ ++ /* Ensure the last bucket to pass down is a flush if ++ * the next read will block. */ ++ flush = apr_bucket_flush_create(f->c->bucket_alloc); ++ APR_BUCKET_INSERT_BEFORE(e, flush); + } + } +- else { +- r->bytes_sent += e->length; ++ ++ /* Optimization: if the next bucket is EOS (directly after a ++ * bucket morphed to the heap, or a flush), short-cut to ++ * handle EOS straight away - allowing C-L to be determined ++ * for content which is already entirely in memory. */ ++ if (e != APR_BRIGADE_SENTINEL(b) && APR_BUCKET_IS_EOS(e)) { ++ continue; ++ } ++ ++ /* On reaching here, pass on everything in the brigade up to ++ * this point. */ ++ apr_brigade_split_ex(b, e, ctx->tmpbb); ++ ++ rv = ap_pass_brigade(f->next, b); ++ if (rv != APR_SUCCESS) { ++ return rv; ++ } ++ else if (f->c->aborted) { ++ return APR_ECONNABORTED; + } +- e = APR_BUCKET_NEXT(e); ++ apr_brigade_cleanup(b); ++ APR_BRIGADE_CONCAT(b, ctx->tmpbb); ++ e = APR_BRIGADE_FIRST(b); ++ ++ ctx->data_sent = 1; + } + + /* If we've now seen the entire response and it's otherwise diff --git a/SOURCES/httpd-2.4.6-r1811831.patch b/SOURCES/httpd-2.4.6-r1811831.patch new file mode 100644 index 0000000..1f63e14 --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1811831.patch @@ -0,0 +1,79 @@ +--- a/server/util_script.c 2017/10/11 14:41:00 1811830 ++++ b/server/util_script.c 2017/10/11 14:48:55 1811831 +@@ -92,9 +92,21 @@ + } + } + +-static void env2env(apr_table_t *table, const char *name) ++/* Sets variable @name in table @dest from r->subprocess_env if ++ * available, else from the environment, else from @fallback if ++ * non-NULL. */ ++static void env2env(apr_table_t *dest, request_rec *r, ++ const char *name, const char *fallback) + { +- add_unless_null(table, name, getenv(name)); ++ const char *val; ++ ++ val = apr_table_get(r->subprocess_env, name); ++ if (!val) ++ val = apr_pstrdup(r->pool, getenv(name)); ++ if (!val) ++ val = apr_pstrdup(r->pool, fallback); ++ if (val) ++ apr_table_addn(dest, name, val); + } + + AP_DECLARE(char **) ap_create_environment(apr_pool_t *p, apr_table_t *t) +@@ -211,37 +223,29 @@ + add_unless_null(e, http2env(r, hdrs[i].key), hdrs[i].val); + } + +- env_temp = apr_table_get(r->subprocess_env, "PATH"); +- if (env_temp == NULL) { +- env_temp = getenv("PATH"); +- } +- if (env_temp == NULL) { +- env_temp = DEFAULT_PATH; +- } +- apr_table_addn(e, "PATH", apr_pstrdup(r->pool, env_temp)); +- ++ env2env(e, r, "PATH", DEFAULT_PATH); + #if defined(WIN32) +- env2env(e, "SystemRoot"); +- env2env(e, "COMSPEC"); +- env2env(e, "PATHEXT"); +- env2env(e, "WINDIR"); ++ env2env(e, r, "SystemRoot", NULL); ++ env2env(e, r, "COMSPEC", NULL); ++ env2env(e, r, "PATHEXT", NULL); ++ env2env(e, r, "WINDIR", NULL); + #elif defined(OS2) +- env2env(e, "COMSPEC"); +- env2env(e, "ETC"); +- env2env(e, "DPATH"); +- env2env(e, "PERLLIB_PREFIX"); ++ env2env(e, r, "COMSPEC", NULL); ++ env2env(e, r, "ETC", NULL); ++ env2env(e, r, "DPATH", NULL); ++ env2env(e, r, "PERLLIB_PREFIX", NULL); + #elif defined(BEOS) +- env2env(e, "LIBRARY_PATH"); ++ env2env(e, r, "LIBRARY_PATH", NULL); + #elif defined(DARWIN) +- env2env(e, "DYLD_LIBRARY_PATH"); ++ env2env(e, r, "DYLD_LIBRARY_PATH", NULL); + #elif defined(_AIX) +- env2env(e, "LIBPATH"); ++ env2env(e, r, "LIBPATH", NULL); + #elif defined(__HPUX__) + /* HPUX PARISC 2.0W knows both, otherwise redundancy is harmless */ +- env2env(e, "SHLIB_PATH"); +- env2env(e, "LD_LIBRARY_PATH"); ++ env2env(e, r, "SHLIB_PATH", NULL); ++ env2env(e, r, "LD_LIBRARY_PATH", NULL); + #else /* Some Unix */ +- env2env(e, "LD_LIBRARY_PATH"); ++ env2env(e, r, "LD_LIBRARY_PATH", NULL); + #endif + + apr_table_addn(e, "SERVER_SIGNATURE", ap_psignature("", r)); diff --git a/SOURCES/httpd-2.4.6-r1811976.patch b/SOURCES/httpd-2.4.6-r1811976.patch new file mode 100644 index 0000000..166cc9e --- /dev/null +++ b/SOURCES/httpd-2.4.6-r1811976.patch @@ -0,0 +1,156 @@ +diff --git a/docs/manual/mod/mod_ssl.html.en b/docs/manual/mod/mod_ssl.html.en +index 98540cd..4580f1c 100644 +--- a/docs/manual/mod/mod_ssl.html.en ++++ b/docs/manual/mod/mod_ssl.html.en +@@ -197,6 +197,12 @@ the SSLOptions directiv + first (or only) attribute of any DN is added only under a non-suffixed + name; i.e. no _0 suffixed entries are added.

    + ++

    The _RAW suffix may now be added to mod_ssl DN variable names ++(such as SSL_CLIENT_I_O_RAW). When this suffix is used, conversion ++of certificate name attributes to UTF-8 is omitted. This allows variable ++lookups and comparisons for certificates with incorrectly tagged name ++attributes.

    ++ +

    The format of the *_DN variables has changed in Apache HTTPD + 2.3.11. See the LegacyDNStringFormat option for + SSLOptions for details.

    +@@ -861,7 +867,7 @@ SSLEngine on + </VirtualHost> + + +-

    In Apache 2.1 and later, SSLEngine can be set to ++

    In httpd 2.2.0 and later, SSLEngine can be set to + optional. This enables support for + RFC 2817, Upgrading to TLS + Within HTTP/1.1. At this time no web browsers support RFC 2817.

    +diff --git a/modules/ssl/ssl_engine_vars.c b/modules/ssl/ssl_engine_vars.c +index 2b7c9ba..e25a6d4 100644 +--- a/modules/ssl/ssl_engine_vars.c ++++ b/modules/ssl/ssl_engine_vars.c +@@ -41,7 +41,7 @@ + + static char *ssl_var_lookup_ssl(apr_pool_t *p, conn_rec *c, request_rec *r, char *var); + static char *ssl_var_lookup_ssl_cert(apr_pool_t *p, request_rec *r, X509 *xs, char *var); +-static char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname, char *var); ++static char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname, const char *var); + static char *ssl_var_lookup_ssl_cert_san(apr_pool_t *p, X509 *xs, char *var); + static char *ssl_var_lookup_ssl_cert_valid(apr_pool_t *p, ASN1_TIME *tm); + static char *ssl_var_lookup_ssl_cert_remain(apr_pool_t *p, ASN1_TIME *tm); +@@ -562,15 +562,23 @@ static const struct { + { NULL, 0, 0 } + }; + +-static char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname, char *var) ++static char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname, ++ const char *var) + { +- char *result, *ptr; ++ const char *ptr; ++ char *result; + X509_NAME_ENTRY *xsne; +- int i, j, n, idx = 0; ++ int i, j, n, idx = 0, raw = 0; + apr_size_t varlen; + ++ ptr = ap_strrchr_c(var, '_'); ++ if (ptr && ptr > var && strcmp(ptr + 1, "RAW") == 0) { ++ var = apr_pstrmemdup(p, var, ptr - var); ++ raw = 1; ++ } ++ + /* if an _N suffix is used, find the Nth attribute of given name */ +- ptr = strchr(var, '_'); ++ ptr = ap_strchr_c(var, '_'); + if (ptr != NULL && strspn(ptr + 1, "0123456789") == strlen(ptr + 1)) { + idx = atoi(ptr + 1); + varlen = ptr - var; +@@ -592,7 +600,7 @@ static char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname, char * + n =OBJ_obj2nid((ASN1_OBJECT *)X509_NAME_ENTRY_get_object(xsne)); + + if (n == ssl_var_lookup_ssl_cert_dn_rec[i].nid && idx-- == 0) { +- result = SSL_X509_NAME_ENTRY_to_string(p, xsne); ++ result = SSL_X509_NAME_ENTRY_to_string(p, xsne, raw); + break; + } + } +@@ -897,7 +905,7 @@ static void extract_dn(apr_table_t *t, apr_hash_t *nids, const char *pfx, + apr_hash_set(count, &nid, sizeof nid, dup); + key = apr_pstrcat(p, pfx, tag, NULL); + } +- value = SSL_X509_NAME_ENTRY_to_string(p, xsne); ++ value = SSL_X509_NAME_ENTRY_to_string(p, xsne, 0); + apr_table_setn(t, key, value); + } + } +diff --git a/modules/ssl/ssl_util_ssl.c b/modules/ssl/ssl_util_ssl.c +index 09a9877..fbd701f 100644 +--- a/modules/ssl/ssl_util_ssl.c ++++ b/modules/ssl/ssl_util_ssl.c +@@ -236,18 +236,21 @@ BOOL SSL_X509_getBC(X509 *cert, int *ca, int *pathlen) + return TRUE; + } + +-/* convert an ASN.1 string to a UTF-8 string (escaping control characters) */ +-char *SSL_ASN1_STRING_to_utf8(apr_pool_t *p, ASN1_STRING *asn1str) ++/* Convert ASN.1 string to a pool-allocated char * string, escaping ++ * control characters. If raw is zero, convert to UTF-8, otherwise ++ * unchanged from the character set. */ ++char *SSL_ASN1_STRING_convert(apr_pool_t *p, ASN1_STRING *asn1str, int raw) + { + char *result = NULL; + BIO *bio; +- int len; ++ int len, flags = ASN1_STRFLGS_ESC_CTRL; + + if ((bio = BIO_new(BIO_s_mem())) == NULL) + return NULL; + +- ASN1_STRING_print_ex(bio, asn1str, ASN1_STRFLGS_ESC_CTRL| +- ASN1_STRFLGS_UTF8_CONVERT); ++ if (!raw) flags |= ASN1_STRFLGS_UTF8_CONVERT; ++ ++ ASN1_STRING_print_ex(bio, asn1str, flags); + len = BIO_pending(bio); + if (len > 0) { + result = apr_palloc(p, len+1); +@@ -258,10 +261,13 @@ char *SSL_ASN1_STRING_to_utf8(apr_pool_t *p, ASN1_STRING *asn1str) + return result; + } + ++#define SSL_ASN1_STRING_to_utf8(p, a) SSL_ASN1_STRING_convert(p, a, 0) ++ + /* convert a NAME_ENTRY to UTF8 string */ +-char *SSL_X509_NAME_ENTRY_to_string(apr_pool_t *p, X509_NAME_ENTRY *xsne) ++char *SSL_X509_NAME_ENTRY_to_string(apr_pool_t *p, X509_NAME_ENTRY *xsne, ++ int raw) + { +- char *result = SSL_ASN1_STRING_to_utf8(p, X509_NAME_ENTRY_get_data(xsne)); ++ char *result = SSL_ASN1_STRING_convert(p, X509_NAME_ENTRY_get_data(xsne), raw); + ap_xlate_proto_from_ascii(result, len); + return result; + } +@@ -414,7 +420,7 @@ BOOL SSL_X509_getIDs(apr_pool_t *p, X509 *x509, apr_array_header_t **ids) + subj = X509_get_subject_name(x509); + while ((i = X509_NAME_get_index_by_NID(subj, NID_commonName, i)) != -1) { + APR_ARRAY_PUSH(*ids, const char *) = +- SSL_X509_NAME_ENTRY_to_string(p, X509_NAME_get_entry(subj, i)); ++ SSL_X509_NAME_ENTRY_to_string(p, X509_NAME_get_entry(subj, i), 0); + } + + return apr_is_empty_array(*ids) ? FALSE : TRUE; +diff --git a/modules/ssl/ssl_util_ssl.h b/modules/ssl/ssl_util_ssl.h +index be07ab7..611957e 100644 +--- a/modules/ssl/ssl_util_ssl.h ++++ b/modules/ssl/ssl_util_ssl.h +@@ -65,8 +65,8 @@ EVP_PKEY *SSL_read_PrivateKey(char *, EVP_PKEY **, pem_password_cb *, void *); + int SSL_smart_shutdown(SSL *ssl); + BOOL SSL_X509_isSGC(X509 *); + BOOL SSL_X509_getBC(X509 *, int *, int *); +-char *SSL_ASN1_STRING_to_utf8(apr_pool_t *, ASN1_STRING *); +-char *SSL_X509_NAME_ENTRY_to_string(apr_pool_t *p, X509_NAME_ENTRY *xsne); ++char *SSL_ASN1_STRING_to_utf8(apr_pool_t *, ASN1_STRING *, int raw); ++char *SSL_X509_NAME_ENTRY_to_string(apr_pool_t *p, X509_NAME_ENTRY *xsne, int raw); + char *SSL_X509_NAME_to_string(apr_pool_t *, X509_NAME *, int); + BOOL SSL_X509_getSAN(apr_pool_t *, X509 *, int, const char *, int, apr_array_header_t **); + BOOL SSL_X509_getIDs(apr_pool_t *, X509 *, apr_array_header_t **); diff --git a/SOURCES/httpd-2.4.6-rewrite-clientaddr.patch b/SOURCES/httpd-2.4.6-rewrite-clientaddr.patch new file mode 100644 index 0000000..e2bd079 --- /dev/null +++ b/SOURCES/httpd-2.4.6-rewrite-clientaddr.patch @@ -0,0 +1,14 @@ +--- a/modules/mappers/mod_rewrite.c 2014/01/28 19:40:17 1562174 ++++ b/modules/mappers/mod_rewrite.c 2014/02/10 18:54:23 1566702 +@@ -2139,7 +2139,10 @@ + break; + + case 16: +- if (!strcmp(var, "REQUEST_FILENAME")) { ++ if (*var == 'C' && !strcmp(var, "CONN_REMOTE_ADDR")) { ++ result = r->connection->client_ip; ++ } ++ else if (!strcmp(var, "REQUEST_FILENAME")) { + result = r->filename; /* same as script_filename (15) */ + } + break; diff --git a/SOURCES/httpd-2.4.6-rewrite-dir.patch b/SOURCES/httpd-2.4.6-rewrite-dir.patch new file mode 100644 index 0000000..c29f0a6 --- /dev/null +++ b/SOURCES/httpd-2.4.6-rewrite-dir.patch @@ -0,0 +1,59 @@ +Index: modules/mappers/mod_rewrite.h +=================================================================== +--- a/modules/mappers/mod_rewrite.h (revision 1560696) ++++ b/modules/mappers/mod_rewrite.h (revision 1560697) +@@ -29,6 +29,8 @@ + #include "apr_optional.h" + #include "httpd.h" + ++#define REWRITE_REDIRECT_HANDLER_NAME "redirect-handler" ++ + /* rewrite map function prototype */ + typedef char *(rewrite_mapfunc_t)(request_rec *r, char *key); + +Index: modules/mappers/mod_dir.c +=================================================================== +--- a/modules/mappers/mod_dir.c (revision 1560696) ++++ b/modules/mappers/mod_dir.c (revision 1560697) +@@ -29,6 +29,7 @@ + #include "http_log.h" + #include "http_main.h" + #include "util_script.h" ++#include "mod_rewrite.h" + + module AP_MODULE_DECLARE_DATA dir_module; + +@@ -260,6 +261,11 @@ + return HTTP_MOVED_PERMANENTLY; + } + ++ /* we're running between mod_rewrites fixup and its internal redirect handler, step aside */ ++ if (!strcmp(r->handler, REWRITE_REDIRECT_HANDLER_NAME)) { ++ return DECLINED; ++ } ++ + if (d->index_names) { + names_ptr = (char **)d->index_names->elts; + num_names = d->index_names->nelts; +Index: modules/mappers/mod_rewrite.c +=================================================================== +--- a/modules/mappers/mod_rewrite.c (revision 1560696) ++++ b/modules/mappers/mod_rewrite.c (revision 1560697) +@@ -5004,7 +5004,7 @@ + rewritelog((r, 1, dconf->directory, "internal redirect with %s " + "[INTERNAL REDIRECT]", r->filename)); + r->filename = apr_pstrcat(r->pool, "redirect:", r->filename, NULL); +- r->handler = "redirect-handler"; ++ r->handler = REWRITE_REDIRECT_HANDLER_NAME; + return OK; + } + } +@@ -5050,7 +5050,7 @@ + */ + static int handler_redirect(request_rec *r) + { +- if (strcmp(r->handler, "redirect-handler")) { ++ if (strcmp(r->handler, REWRITE_REDIRECT_HANDLER_NAME)) { + return DECLINED; + } + diff --git a/SOURCES/httpd-2.4.6-rotatelog-timezone.patch b/SOURCES/httpd-2.4.6-rotatelog-timezone.patch new file mode 100644 index 0000000..2ef4f11 --- /dev/null +++ b/SOURCES/httpd-2.4.6-rotatelog-timezone.patch @@ -0,0 +1,97 @@ +diff --git a/support/rotatelogs.c b/support/rotatelogs.c +index d75d018..216bb12 100644 +--- a/support/rotatelogs.c ++++ b/support/rotatelogs.c +@@ -178,14 +178,14 @@ static void usage(const char *argv0, const char *reason) + exit(1); + } + +-/* +- * Get the unix time with timezone corrections +- * given in the config struct. +- */ +-static int get_now(rotate_config_t *config) ++/* This function returns the current Unix time (time_t) plus any ++ * configured or derived local time offset. The offset applied is ++ * returned via *offset. */ ++static int get_now(rotate_config_t *config, apr_int32_t *offset) + { + apr_time_t tNow = apr_time_now(); +- int utc_offset = config->utc_offset; ++ int utc_offset; ++ + if (config->use_localtime) { + /* Check for our UTC offset before using it, since it might + * change if there's a switch between standard and daylight +@@ -195,6 +195,13 @@ static int get_now(rotate_config_t *config) + apr_time_exp_lt(<, tNow); + utc_offset = lt.tm_gmtoff; + } ++ else { ++ utc_offset = config->utc_offset; ++ } ++ ++ if (offset) ++ *offset = utc_offset; ++ + return (int)apr_time_sec(tNow) + utc_offset; + } + +@@ -258,13 +265,13 @@ static void checkRotate(rotate_config_t *config, rotate_status_t *status) + status->rotateReason = ROTATE_SIZE; + } + else if (config->tRotation) { +- if (get_now(config) >= status->tLogEnd) { ++ if (get_now(config, NULL) >= status->tLogEnd) { + status->rotateReason = ROTATE_TIME; + } + } + } + else if (config->tRotation) { +- if (get_now(config) >= status->tLogEnd) { ++ if (get_now(config, NULL) >= status->tLogEnd) { + status->rotateReason = ROTATE_TIME; + } + } +@@ -371,12 +378,16 @@ static void post_rotate(apr_pool_t *pool, struct logfile *newlog, + static void doRotate(rotate_config_t *config, rotate_status_t *status) + { + +- int now = get_now(config); ++ apr_int32_t offset; ++ int now; + int tLogStart; + apr_status_t rv; + struct logfile newlog; + int thisLogNum = -1; + ++ /* Retrieve local-time-adjusted-Unix-time. */ ++ now = get_now(config, &offset); ++ + status->rotateReason = ROTATE_NONE; + + if (config->tRotation) { +@@ -401,7 +412,13 @@ static void doRotate(rotate_config_t *config, rotate_status_t *status) + apr_time_exp_t e; + apr_size_t rs; + +- apr_time_exp_gmt(&e, tNow); ++ /* Explode the local-time-adjusted-Unix-time into a struct tm, ++ * first *reversing* local-time-adjustment applied by ++ * get_now() if we are using localtime. */ ++ if (config->use_localtime) ++ apr_time_exp_lt(&e, tNow - apr_time_from_sec(offset)); ++ else ++ apr_time_exp_gmt(&e, tNow); + apr_strftime(newlog.name, &rs, sizeof(newlog.name), config->szLogRoot, &e); + } + else { +@@ -648,7 +665,7 @@ int main (int argc, const char * const argv[]) + nRead = sizeof(buf); + #if APR_FILES_AS_SOCKETS + if (config.create_empty && config.tRotation) { +- polltimeout = status.tLogEnd ? status.tLogEnd - get_now(&config) : config.tRotation; ++ polltimeout = status.tLogEnd ? status.tLogEnd - get_now(&config, NULL) : config.tRotation; + if (polltimeout <= 0) { + pollret = APR_TIMEUP; + } diff --git a/SOURCES/httpd-2.4.6-rotatelogs-zombie.patch b/SOURCES/httpd-2.4.6-rotatelogs-zombie.patch new file mode 100644 index 0000000..04a2c33 --- /dev/null +++ b/SOURCES/httpd-2.4.6-rotatelogs-zombie.patch @@ -0,0 +1,23 @@ +diff --git a/support/rotatelogs.c b/support/rotatelogs.c +index 55c4406..f4c6490 100644 +--- a/support/rotatelogs.c ++++ b/support/rotatelogs.c +@@ -49,6 +49,7 @@ + #include "apr_time.h" + #include "apr_getopt.h" + #include "apr_thread_proc.h" ++#include "apr_signal.h" + #if APR_FILES_AS_SOCKETS + #include "apr_poll.h" + #endif +@@ -595,6 +596,10 @@ int main (int argc, const char * const argv[]) + break; + case 'p': + config.postrotate_prog = opt_arg; ++#ifdef SIGCHLD ++ /* Prevent creation of zombies (on modern Unix systems). */ ++ apr_signal(SIGCHLD, SIG_IGN); ++#endif + break; + case 'f': + config.force_open = 1; diff --git a/SOURCES/httpd-2.4.6-sigint.patch b/SOURCES/httpd-2.4.6-sigint.patch new file mode 100644 index 0000000..7574a9c --- /dev/null +++ b/SOURCES/httpd-2.4.6-sigint.patch @@ -0,0 +1,45 @@ +From 20656c3b77cc548b59fea3bde5e2b7705d71c427 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jan=20Kalu=C5=BEa?= +Date: Mon, 18 Aug 2014 07:43:43 +0000 +Subject: [PATCH] prefork: Ignore SIGINT in child. This fixes race-condition in + signals handling when httpd is runnning on foreground and user hits ctrl+c. + In this case, SIGINT is sent to all children followed by SIGTERM from the + main process, which interrupts the SIGINT handler and leads to inconsistency + (process freezes or crashes). + +git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1618555 13f79535-47bb-0310-9956-ffa450edef68 +--- + server/mpm/prefork/prefork.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/server/mpm/prefork/prefork.c b/server/mpm/prefork/prefork.c +index 8790ec0..d6c038b 100644 +--- a/server/mpm/prefork/prefork.c ++++ b/server/mpm/prefork/prefork.c +@@ -222,6 +222,9 @@ static void clean_child_exit(int code) + { + mpm_state = AP_MPMQ_STOPPING; + ++ apr_signal(SIGHUP, SIG_IGN); ++ apr_signal(SIGTERM, SIG_IGN); ++ + if (pchild) { + apr_pool_destroy(pchild); + } +@@ -817,6 +820,13 @@ static int make_child(server_rec *s, int slot) + */ + apr_signal(SIGHUP, just_die); + apr_signal(SIGTERM, just_die); ++ /* Ignore SIGINT in child. This fixes race-condition in signals ++ * handling when httpd is runnning on foreground and user hits ctrl+c. ++ * In this case, SIGINT is sent to all children followed by SIGTERM ++ * from the main process, which interrupts the SIGINT handler and ++ * leads to inconsistency. ++ */ ++ apr_signal(SIGINT, SIG_IGN); + /* The child process just closes listeners on AP_SIG_GRACEFUL. + * The pod is used for signalling the graceful restart. + */ +-- +2.0.4 + diff --git a/SOURCES/httpd-2.4.6-ssl-ecdh-auto.patch b/SOURCES/httpd-2.4.6-ssl-ecdh-auto.patch new file mode 100644 index 0000000..7cbb1ec --- /dev/null +++ b/SOURCES/httpd-2.4.6-ssl-ecdh-auto.patch @@ -0,0 +1,22 @@ +diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c +index 0275452..8efdcd7 100644 +--- a/modules/ssl/ssl_engine_init.c ++++ b/modules/ssl/ssl_engine_init.c +@@ -1144,11 +1144,16 @@ static void ssl_init_server_certs(server_rec *s, + OBJ_nid2sn(nid), vhost_id, mctx->pks->cert_files[0]); + } + /* +- * ...otherwise, configure NIST P-256 (required to enable ECDHE) ++ * ...otherwise, enable auto curve selection (OpenSSL 1.0.2 and later) ++ * or configure NIST P-256 (required to enable ECDHE for earlier versions) + */ + else { ++#if defined(SSL_CTX_set_ecdh_auto) ++ SSL_CTX_set_ecdh_auto(mctx->ssl_ctx, 1); ++#else + SSL_CTX_set_tmp_ecdh(mctx->ssl_ctx, + EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); ++#endif + } + #endif + } diff --git a/SOURCES/httpd-2.4.6-ssl-error-free.patch b/SOURCES/httpd-2.4.6-ssl-error-free.patch new file mode 100644 index 0000000..6f268d2 --- /dev/null +++ b/SOURCES/httpd-2.4.6-ssl-error-free.patch @@ -0,0 +1,46 @@ +diff --git a/modules/ssl/mod_ssl.c b/modules/ssl/mod_ssl.c +index 19d3ec7..926e05e 100644 +--- a/modules/ssl/mod_ssl.c ++++ b/modules/ssl/mod_ssl.c +@@ -295,9 +295,12 @@ static apr_status_t ssl_cleanup_pre_config(void *data) + #endif + ERR_remove_state(0); + +- /* Don't call ERR_free_strings here; ERR_load_*_strings only +- * actually load the error strings once per process due to static ++ /* Don't call ERR_free_strings in earlier versions, ERR_load_*_strings only ++ * actually loaded the error strings once per process due to static + * variable abuse in OpenSSL. */ ++#if (OPENSSL_VERSION_NUMBER >= 0x00090805f) ++ ERR_free_strings(); ++#endif + + /* Also don't call CRYPTO_cleanup_all_ex_data here; any registered + * ex_data indices may have been cached in static variables in +diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c +index 8425acb..508991e 100644 +--- a/modules/ssl/ssl_engine_init.c ++++ b/modules/ssl/ssl_engine_init.c +@@ -1065,7 +1065,7 @@ static void ssl_init_server_certs(server_rec *s, + const char *ecc_id; + EC_GROUP *ecparams; + int nid; +- EC_KEY *eckey; ++ EC_KEY *eckey = NULL; + #endif + const char *vhost_id = mctx->sc->vhost_id; + int i; +@@ -1151,10 +1151,11 @@ static void ssl_init_server_certs(server_rec *s, + #if defined(SSL_CTX_set_ecdh_auto) + SSL_CTX_set_ecdh_auto(mctx->ssl_ctx, 1); + #else +- SSL_CTX_set_tmp_ecdh(mctx->ssl_ctx, +- EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); ++ eckey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); ++ SSL_CTX_set_tmp_ecdh(mctx->ssl_ctx, eckey); + #endif + } ++ EC_KEY_free(eckey); + #endif + } + diff --git a/SOURCES/httpd-2.4.6-ssl-large-keys.patch b/SOURCES/httpd-2.4.6-ssl-large-keys.patch new file mode 100644 index 0000000..46078ba --- /dev/null +++ b/SOURCES/httpd-2.4.6-ssl-large-keys.patch @@ -0,0 +1,173 @@ +diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c +index 46769e9..0275452 100644 +--- a/modules/ssl/ssl_engine_init.c ++++ b/modules/ssl/ssl_engine_init.c +@@ -41,6 +41,79 @@ + #define KEYTYPES "RSA or DSA" + #endif + ++/* ++ * Grab well-defined DH parameters from OpenSSL, see the get_rfc* ++ * functions in for all available primes. ++ */ ++static DH *make_dh_params(BIGNUM *(*prime)(BIGNUM *), const char *gen) ++{ ++ DH *dh = DH_new(); ++ ++ if (!dh) { ++ return NULL; ++ } ++ dh->p = prime(NULL); ++ BN_dec2bn(&dh->g, gen); ++ if (!dh->p || !dh->g) { ++ DH_free(dh); ++ return NULL; ++ } ++ return dh; ++} ++ ++/* Storage and initialization for DH parameters. */ ++static struct dhparam { ++ BIGNUM *(*const prime)(BIGNUM *); /* function to generate... */ ++ DH *dh; /* ...this, used for keys.... */ ++ const unsigned int min; /* ...of length >= this. */ ++} dhparams[] = { ++ { get_rfc3526_prime_8192, NULL, 6145 }, ++ { get_rfc3526_prime_6144, NULL, 4097 }, ++ { get_rfc3526_prime_4096, NULL, 3073 }, ++ { get_rfc3526_prime_3072, NULL, 2049 }, ++ { get_rfc3526_prime_2048, NULL, 1025 }, ++ { get_rfc2409_prime_1024, NULL, 0 } ++}; ++ ++static void init_dh_params(void) ++{ ++ unsigned n; ++ ++ for (n = 0; n < sizeof(dhparams)/sizeof(dhparams[0]); n++) ++ dhparams[n].dh = make_dh_params(dhparams[n].prime, "2"); ++} ++ ++static void free_dh_params(void) ++{ ++ unsigned n; ++ ++ /* DH_free() is a noop for a NULL parameter, so these are harmless ++ * in the (unexpected) case where these variables are already ++ * NULL. */ ++ for (n = 0; n < sizeof(dhparams)/sizeof(dhparams[0]); n++) { ++ DH_free(dhparams[n].dh); ++ dhparams[n].dh = NULL; ++ } ++} ++ ++/* Hand out the same DH structure though once generated as we leak ++ * memory otherwise and freeing the structure up after use would be ++ * hard to track and in fact is not needed at all as it is safe to ++ * use the same parameters over and over again security wise (in ++ * contrast to the keys itself) and code safe as the returned structure ++ * is duplicated by OpenSSL anyway. Hence no modification happens ++ * to our copy. */ ++DH *modssl_get_dh_params(unsigned keylen) ++{ ++ unsigned n; ++ ++ for (n = 0; n < sizeof(dhparams)/sizeof(dhparams[0]); n++) ++ if (keylen >= dhparams[n].min) ++ return dhparams[n].dh; ++ ++ return NULL; /* impossible to reach. */ ++} ++ + static void ssl_add_version_components(apr_pool_t *p, + server_rec *s) + { +@@ -244,6 +317,8 @@ int ssl_init_Module(apr_pool_t *p, apr_pool_t *plog, + + SSL_init_app_data2_idx(); /* for SSL_get_app_data2() at request time */ + ++ init_dh_params(); ++ + return OK; + } + +@@ -1623,6 +1698,8 @@ apr_status_t ssl_init_ModuleKill(void *data) + ssl_init_ctx_cleanup_server(sc->server); + } + ++ free_dh_params(); ++ + return APR_SUCCESS; + } + +diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c +index 2d6d59e..1ecbccd 100644 +--- a/modules/ssl/ssl_engine_kernel.c ++++ b/modules/ssl/ssl_engine_kernel.c +@@ -1287,34 +1287,6 @@ const authz_provider ssl_authz_provider_verify_client = + */ + + /* +- * Grab well-defined DH parameters from OpenSSL, see +- * (get_rfc*) for all available primes. +- */ +-#define make_get_dh(rfc,size,gen) \ +-static DH *get_dh##size(void) \ +-{ \ +- DH *dh; \ +- if (!(dh = DH_new())) { \ +- return NULL; \ +- } \ +- dh->p = get_##rfc##_prime_##size(NULL); \ +- BN_dec2bn(&dh->g, #gen); \ +- if (!dh->p || !dh->g) { \ +- DH_free(dh); \ +- return NULL; \ +- } \ +- return dh; \ +-} +- +-/* +- * Prepare DH parameters from 1024 to 4096 bits, in 1024-bit increments +- */ +-make_get_dh(rfc2409, 1024, 2) +-make_get_dh(rfc3526, 2048, 2) +-make_get_dh(rfc3526, 3072, 2) +-make_get_dh(rfc3526, 4096, 2) +- +-/* + * Hand out standard DH parameters, based on the authentication strength + */ + DH *ssl_callback_TmpDH(SSL *ssl, int export, int keylen) +@@ -1342,14 +1314,7 @@ DH *ssl_callback_TmpDH(SSL *ssl, int export, int keylen) + ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, + "handing out built-in DH parameters for %d-bit authenticated connection", keylen); + +- if (keylen >= 4096) +- return get_dh4096(); +- else if (keylen >= 3072) +- return get_dh3072(); +- else if (keylen >= 2048) +- return get_dh2048(); +- else +- return get_dh1024(); ++ return modssl_get_dh_params(keylen); + } + + /* +diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h +index 744af9e..f47ed47 100644 +--- a/modules/ssl/ssl_private.h ++++ b/modules/ssl/ssl_private.h +@@ -990,6 +990,11 @@ OCSP_RESPONSE *modssl_dispatch_ocsp_request(const apr_uri_t *uri, + conn_rec *c, apr_pool_t *p); + #endif + ++/* Retrieve DH parameters for given key length. Return value should ++ * be treated as unmutable, since it is stored in process-global ++ * memory. */ ++DH *modssl_get_dh_params(unsigned keylen); ++ + #endif /* SSL_PRIVATE_H */ + /** @} */ + diff --git a/SOURCES/httpd-2.4.6-sslmultiproxy.patch b/SOURCES/httpd-2.4.6-sslmultiproxy.patch new file mode 100644 index 0000000..f8a3b4b --- /dev/null +++ b/SOURCES/httpd-2.4.6-sslmultiproxy.patch @@ -0,0 +1,94 @@ + +Ugly hack to enable mod_ssl and mod_nss to "share" hooks. + +--- httpd-2.4.6/modules/ssl/mod_ssl.c.sslmultiproxy ++++ httpd-2.4.6/modules/ssl/mod_ssl.c +@@ -369,6 +369,9 @@ static SSLConnRec *ssl_init_connection_c + return sslconn; + } + ++static typeof(ssl_proxy_enable) *othermod_proxy_enable; ++static typeof(ssl_engine_disable) *othermod_engine_disable; ++ + int ssl_proxy_enable(conn_rec *c) + { + SSLSrvConfigRec *sc; +@@ -377,6 +380,12 @@ int ssl_proxy_enable(conn_rec *c) + sc = mySrvConfig(sslconn->server); + + if (!sc->proxy_enabled) { ++ if (othermod_proxy_enable) { ++ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, ++ "mod_ssl proxy not configured, passing through to other module."); ++ return othermod_proxy_enable(c); ++ } ++ + ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(01961) + "SSL Proxy requested for %s but not enabled " + "[Hint: SSLProxyEngine]", sc->vhost_id); +@@ -396,6 +405,10 @@ int ssl_engine_disable(conn_rec *c) + + SSLConnRec *sslconn = myConnConfig(c); + ++ if (othermod_engine_disable) { ++ othermod_engine_disable(c); ++ } ++ + if (sslconn) { + sc = mySrvConfig(sslconn->server); + } +@@ -612,6 +625,9 @@ static void ssl_register_hooks(apr_pool_ + ap_hook_post_read_request(ssl_hook_ReadReq, pre_prr,NULL, APR_HOOK_MIDDLE); + + ssl_var_register(p); ++ ++ othermod_proxy_enable = APR_RETRIEVE_OPTIONAL_FN(ssl_proxy_enable); ++ othermod_engine_disable = APR_RETRIEVE_OPTIONAL_FN(ssl_engine_disable); + + APR_REGISTER_OPTIONAL_FN(ssl_proxy_enable); + APR_REGISTER_OPTIONAL_FN(ssl_engine_disable); +--- httpd-2.4.6/modules/ssl/ssl_engine_vars.c.sslmultiproxy ++++ httpd-2.4.6/modules/ssl/ssl_engine_vars.c +@@ -53,10 +53,15 @@ static void ssl_var_lookup_ssl_cipher_b + static char *ssl_var_lookup_ssl_version(apr_pool_t *p, char *var); + static char *ssl_var_lookup_ssl_compress_meth(SSL *ssl); + ++static APR_OPTIONAL_FN_TYPE(ssl_is_https) *othermod_is_https; ++static APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *othermod_var_lookup; ++ + static int ssl_is_https(conn_rec *c) + { + SSLConnRec *sslconn = myConnConfig(c); +- return sslconn && sslconn->ssl; ++ ++ return (sslconn && sslconn->ssl) ++ || (othermod_is_https && othermod_is_https(c)); + } + + static const char var_interface[] = "mod_ssl/" AP_SERVER_BASEREVISION; +@@ -106,6 +111,9 @@ void ssl_var_register(apr_pool_t *p) + { + char *cp, *cp2; + ++ othermod_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https); ++ othermod_var_lookup = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup); ++ + APR_REGISTER_OPTIONAL_FN(ssl_is_https); + APR_REGISTER_OPTIONAL_FN(ssl_var_lookup); + APR_REGISTER_OPTIONAL_FN(ssl_ext_list); +@@ -241,6 +249,15 @@ char *ssl_var_lookup(apr_pool_t *p, serv + */ + if (result == NULL && c != NULL) { + SSLConnRec *sslconn = myConnConfig(c); ++ ++ if (strlen(var) > 4 && strcEQn(var, "SSL_", 4) ++ && (!sslconn || !sslconn->ssl) && othermod_var_lookup) { ++ /* For an SSL_* variable, if mod_ssl is not enabled for ++ * this connection and another SSL module is present, pass ++ * through to that module. */ ++ return othermod_var_lookup(p, s, c, r, var); ++ } ++ + if (strlen(var) > 4 && strcEQn(var, "SSL_", 4) + && sslconn && sslconn->ssl) + result = ssl_var_lookup_ssl(p, c, r, var+4); diff --git a/SOURCES/httpd-2.4.6-statements-comment.patch b/SOURCES/httpd-2.4.6-statements-comment.patch new file mode 100644 index 0000000..fd56e11 --- /dev/null +++ b/SOURCES/httpd-2.4.6-statements-comment.patch @@ -0,0 +1,16 @@ +diff --git a/modules/aaa/mod_access_compat.c b/modules/aaa/mod_access_compat.c +index 46d8da0..0a5d5a1 100644 +--- a/modules/aaa/mod_access_compat.c ++++ b/modules/aaa/mod_access_compat.c +@@ -152,6 +152,11 @@ static const char *allow_cmd(cmd_parms *cmd, void *dv, const char *from, + if (strcasecmp(from, "from")) + return "allow and deny must be followed by 'from'"; + ++ s = ap_strchr(where, '#'); ++ if (s) { ++ *s = '\0'; ++ } ++ + a = (allowdeny *) apr_array_push(cmd->info ? d->allows : d->denys); + a->x.from = where; + a->limited = cmd->limited; diff --git a/SOURCES/httpd-2.4.6-uds.patch b/SOURCES/httpd-2.4.6-uds.patch new file mode 100644 index 0000000..8a00b5a --- /dev/null +++ b/SOURCES/httpd-2.4.6-uds.patch @@ -0,0 +1,1456 @@ +diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c +index 6061e53..75c2a35 100644 +--- a/modules/mappers/mod_rewrite.c ++++ b/modules/mappers/mod_rewrite.c +@@ -4120,6 +4120,7 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx) + r->filename)); + + r->filename = apr_pstrcat(r->pool, "proxy:", r->filename, NULL); ++ apr_table_setn(r->notes, "rewrite-proxy", "1"); + return 1; + } + +diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c +index b9d71fa..7f96aff 100644 +--- a/modules/proxy/mod_proxy.c ++++ b/modules/proxy/mod_proxy.c +@@ -1348,7 +1348,6 @@ static void *merge_proxy_dir_config(apr_pool_t *p, void *basev, void *addv) + return new; + } + +- + static const char * + add_proxy(cmd_parms *cmd, void *dummy, const char *f1, const char *r1, int regex) + { +@@ -1423,6 +1422,36 @@ static const char * + return add_proxy(cmd, dummy, f1, r1, 1); + } + ++static char *de_socketfy(apr_pool_t *p, char *url) ++{ ++ char *ptr; ++ /* ++ * We could be passed a URL during the config stage that contains ++ * the UDS path... ignore it ++ */ ++ if (!strncasecmp(url, "unix:", 5) && ++ ((ptr = ap_strchr(url, '|')) != NULL)) { ++ /* move past the 'unix:...|' UDS path info */ ++ char *ret, *c; ++ ++ ret = ptr + 1; ++ /* special case: "unix:....|scheme:" is OK, expand ++ * to "unix:....|scheme://localhost" ++ * */ ++ c = ap_strchr(ret, ':'); ++ if (c == NULL) { ++ return NULL; ++ } ++ if (c[1] == '\0') { ++ return apr_pstrcat(p, ret, "//localhost", NULL); ++ } ++ else { ++ return ret; ++ } ++ } ++ return url; ++} ++ + static const char * + add_pass(cmd_parms *cmd, void *dummy, const char *arg, int is_regex) + { +@@ -1514,7 +1543,7 @@ static const char * + } + + new->fake = apr_pstrdup(cmd->pool, f); +- new->real = apr_pstrdup(cmd->pool, r); ++ new->real = apr_pstrdup(cmd->pool, de_socketfy(cmd->pool, r)); + new->flags = flags; + if (use_regex) { + new->regex = ap_pregcomp(cmd->pool, f, AP_REG_EXTENDED); +@@ -1550,26 +1579,41 @@ static const char * + new->balancer = balancer; + } + else { +- proxy_worker *worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, r); ++ proxy_worker *worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, new->real); + int reuse = 0; + if (!worker) { +- const char *err = ap_proxy_define_worker(cmd->pool, &worker, NULL, conf, r, 0); ++ const char *err; ++ if (use_regex) { ++ err = ap_proxy_define_match_worker(cmd->pool, &worker, NULL, ++ conf, r, 0); ++ } ++ else { ++ err = ap_proxy_define_worker(cmd->pool, &worker, NULL, ++ conf, r, 0); ++ } + if (err) + return apr_pstrcat(cmd->temp_pool, "ProxyPass ", err, NULL); + + PROXY_COPY_CONF_PARAMS(worker, conf); +- } else { ++ } ++ else if ((use_regex != 0) ^ (worker->s->is_name_matchable)) { ++ return apr_pstrcat(cmd->temp_pool, "ProxyPass/ and " ++ "ProxyPassMatch/ can't be used " ++ "altogether with the same worker name ", ++ "(", worker->s->name, ")", NULL); ++ } ++ else { + reuse = 1; + ap_log_error(APLOG_MARK, APLOG_INFO, 0, cmd->server, APLOGNO(01145) + "Sharing worker '%s' instead of creating new worker '%s'", +- worker->s->name, new->real); ++ ap_proxy_worker_name(cmd->pool, worker), new->real); + } + + for (i = 0; i < arr->nelts; i++) { + if (reuse) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server, APLOGNO(01146) + "Ignoring parameter '%s=%s' for worker '%s' because of worker sharing", +- elts[i].key, elts[i].val, worker->s->name); ++ elts[i].key, elts[i].val, ap_proxy_worker_name(cmd->pool, worker)); + } else { + const char *err = set_worker_param(cmd->pool, worker, elts[i].key, + elts[i].val); +@@ -2026,7 +2070,7 @@ static const char *add_member(cmd_parms *cmd, void *dummy, const char *arg) + } + + /* Try to find existing worker */ +- worker = ap_proxy_get_worker(cmd->temp_pool, balancer, conf, name); ++ worker = ap_proxy_get_worker(cmd->temp_pool, balancer, conf, de_socketfy(cmd->temp_pool, name)); + if (!worker) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01147) + "Defining worker '%s' for balancer '%s'", +@@ -2035,13 +2079,13 @@ static const char *add_member(cmd_parms *cmd, void *dummy, const char *arg) + return apr_pstrcat(cmd->temp_pool, "BalancerMember ", err, NULL); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01148) + "Defined worker '%s' for balancer '%s'", +- worker->s->name, balancer->s->name); ++ ap_proxy_worker_name(cmd->pool, worker), balancer->s->name); + PROXY_COPY_CONF_PARAMS(worker, conf); + } else { + reuse = 1; + ap_log_error(APLOG_MARK, APLOG_INFO, 0, cmd->server, APLOGNO(01149) + "Sharing worker '%s' instead of creating new worker '%s'", +- worker->s->name, name); ++ ap_proxy_worker_name(cmd->pool, worker), name); + } + + arr = apr_table_elts(params); +@@ -2050,7 +2094,7 @@ static const char *add_member(cmd_parms *cmd, void *dummy, const char *arg) + if (reuse) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server, APLOGNO(01150) + "Ignoring parameter '%s=%s' for worker '%s' because of worker sharing", +- elts[i].key, elts[i].val, worker->s->name); ++ elts[i].key, elts[i].val, ap_proxy_worker_name(cmd->pool, worker)); + } else { + err = set_worker_param(cmd->pool, worker, elts[i].key, + elts[i].val); +@@ -2112,7 +2156,7 @@ static const char * + } + } + else { +- worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, name); ++ worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, de_socketfy(cmd->temp_pool, name)); + if (!worker) { + if (in_proxy_section) { + err = ap_proxy_define_worker(cmd->pool, &worker, NULL, +@@ -2170,6 +2214,7 @@ static const char *proxysection(cmd_parms *cmd, void *mconfig, const char *arg) + char *word, *val; + proxy_balancer *balancer = NULL; + proxy_worker *worker = NULL; ++ int use_regex = 0; + + const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE); + proxy_server_conf *sconf = +@@ -2219,6 +2264,7 @@ static const char *proxysection(cmd_parms *cmd, void *mconfig, const char *arg) + if (!r) { + return "Regex could not be compiled"; + } ++ use_regex = 1; + } + + /* initialize our config and fetch it */ +@@ -2258,14 +2304,26 @@ static const char *proxysection(cmd_parms *cmd, void *mconfig, const char *arg) + } + else { + worker = ap_proxy_get_worker(cmd->temp_pool, NULL, sconf, +- conf->p); ++ de_socketfy(cmd->temp_pool, (char*)conf->p)); + if (!worker) { +- err = ap_proxy_define_worker(cmd->pool, &worker, NULL, +- sconf, conf->p, 0); ++ if (use_regex) { ++ err = ap_proxy_define_match_worker(cmd->pool, &worker, NULL, ++ sconf, conf->p, 0); ++ } ++ else { ++ err = ap_proxy_define_worker(cmd->pool, &worker, NULL, ++ sconf, conf->p, 0); ++ } + if (err) + return apr_pstrcat(cmd->temp_pool, thiscmd->name, + " ", err, NULL); + } ++ else if ((use_regex != 0) ^ (worker->s->is_name_matchable)) { ++ return apr_pstrcat(cmd->temp_pool, "ProxyPass/ and " ++ "ProxyPassMatch/ can't be used " ++ "altogether with the same worker name ", ++ "(", worker->s->name, ")", NULL); ++ } + } + if (worker == NULL && balancer == NULL) { + return apr_pstrcat(cmd->pool, thiscmd->name, +@@ -2570,6 +2628,8 @@ static void child_init(apr_pool_t *p, server_rec *s) + ap_proxy_hashfunc(conf->forward->s->name, PROXY_HASHFUNC_FNV); + /* Do not disable worker in case of errors */ + conf->forward->s->status |= PROXY_WORKER_IGNORE_ERRORS; ++ /* Mark as the "generic" worker */ ++ conf->forward->s->status |= PROXY_WORKER_GENERIC; + ap_proxy_initialize_worker(conf->forward, s, conf->pool); + /* Disable address cache for generic forward worker */ + conf->forward->s->is_address_reusable = 0; +@@ -2585,6 +2645,8 @@ static void child_init(apr_pool_t *p, server_rec *s) + ap_proxy_hashfunc(reverse->s->name, PROXY_HASHFUNC_FNV); + /* Do not disable worker in case of errors */ + reverse->s->status |= PROXY_WORKER_IGNORE_ERRORS; ++ /* Mark as the "generic" worker */ ++ reverse->s->status |= PROXY_WORKER_GENERIC; + conf->reverse = reverse; + ap_proxy_initialize_worker(conf->reverse, s, conf->pool); + /* Disable address cache for generic reverse worker */ +diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h +index 81fd14c..4fb21c7 100644 +--- a/modules/proxy/mod_proxy.h ++++ b/modules/proxy/mod_proxy.h +@@ -249,6 +249,7 @@ typedef struct { + unsigned int need_flush:1; /* Flag to decide whether we need to flush the + * filter chain or not */ + unsigned int inreslist:1; /* connection in apr_reslist? */ ++ const char *uds_path; /* Unix domain socket path */ + } proxy_conn_rec; + + typedef struct { +@@ -269,6 +270,7 @@ struct proxy_conn_pool { + #define PROXY_WORKER_INITIALIZED 0x0001 + #define PROXY_WORKER_IGNORE_ERRORS 0x0002 + #define PROXY_WORKER_DRAIN 0x0004 ++#define PROXY_WORKER_GENERIC 0x0008 + #define PROXY_WORKER_IN_SHUTDOWN 0x0010 + #define PROXY_WORKER_DISABLED 0x0020 + #define PROXY_WORKER_STOPPED 0x0040 +@@ -280,6 +282,7 @@ struct proxy_conn_pool { + #define PROXY_WORKER_INITIALIZED_FLAG 'O' + #define PROXY_WORKER_IGNORE_ERRORS_FLAG 'I' + #define PROXY_WORKER_DRAIN_FLAG 'N' ++#define PROXY_WORKER_GENERIC_FLAG 'G' + #define PROXY_WORKER_IN_SHUTDOWN_FLAG 'U' + #define PROXY_WORKER_DISABLED_FLAG 'D' + #define PROXY_WORKER_STOPPED_FLAG 'S' +@@ -300,6 +303,8 @@ PROXY_WORKER_DISABLED | PROXY_WORKER_STOPPED | PROXY_WORKER_IN_ERROR ) + + #define PROXY_WORKER_IS_DRAINING(f) ( (f)->s->status & PROXY_WORKER_DRAIN ) + ++#define PROXY_WORKER_IS_GENERIC(f) ( (f)->s->status & PROXY_WORKER_GENERIC ) ++ + /* default worker retry timeout in seconds */ + #define PROXY_WORKER_DEFAULT_RETRY 60 + +@@ -341,6 +346,7 @@ typedef struct { + char route[PROXY_WORKER_MAX_ROUTE_SIZE]; /* balancing route */ + char redirect[PROXY_WORKER_MAX_ROUTE_SIZE]; /* temporary balancing redirection route */ + char flusher[PROXY_WORKER_MAX_SCHEME_SIZE]; /* flush provider used by mod_proxy_fdpass */ ++ char uds_path[PROXY_WORKER_MAX_NAME_SIZE]; /* path to worker's unix domain socket if applicable */ + int lbset; /* load balancer cluster set */ + int retries; /* number of retries on this worker */ + int lbstatus; /* Current lbstatus */ +@@ -387,6 +393,7 @@ typedef struct { + unsigned int keepalive_set:1; + unsigned int disablereuse_set:1; + unsigned int was_malloced:1; ++ unsigned int is_name_matchable:1; + } proxy_worker_shared; + + #define ALIGNED_PROXY_WORKER_SHARED_SIZE (APR_ALIGN_DEFAULT(sizeof(proxy_worker_shared))) +@@ -586,6 +593,16 @@ typedef __declspec(dllimport) const char * + + /* Connection pool API */ + /** ++ * Return the user-land, UDS aware worker name ++ * @param p memory pool used for displaying worker name ++ * @param worker the worker ++ * @return name ++ */ ++ ++PROXY_DECLARE(char *) ap_proxy_worker_name(apr_pool_t *p, ++ proxy_worker *worker); ++ ++/** + * Get the worker from proxy configuration + * @param p memory pool used for finding worker + * @param balancer the balancer that the worker belongs to +@@ -615,6 +632,24 @@ PROXY_DECLARE(char *) ap_proxy_define_worker(apr_pool_t *p, + int do_malloc); + + /** ++ * Define and Allocate space for the ap_strcmp_match()able worker to proxy ++ * configuration. ++ * @param p memory pool to allocate worker from ++ * @param worker the new worker ++ * @param balancer the balancer that the worker belongs to ++ * @param conf current proxy server configuration ++ * @param url url containing worker name (produces match pattern) ++ * @param do_malloc true if shared struct should be malloced ++ * @return error message or NULL if successful (*worker is new worker) ++ */ ++PROXY_DECLARE(char *) ap_proxy_define_match_worker(apr_pool_t *p, ++ proxy_worker **worker, ++ proxy_balancer *balancer, ++ proxy_server_conf *conf, ++ const char *url, ++ int do_malloc); ++ ++/** + * Share a defined proxy worker via shm + * @param worker worker to be shared + * @param shm location of shared info +@@ -983,6 +1018,13 @@ APR_DECLARE_OPTIONAL_FN(int, ap_proxy_clear_connection, + */ + int ap_proxy_lb_workers(void); + ++/** ++ * Return the port number of a known scheme (eg: http -> 80). ++ * @param scheme scheme to test ++ * @return port number or 0 if unknown ++ */ ++PROXY_DECLARE(apr_port_t) ap_proxy_port_of_scheme(const char *scheme); ++ + extern module PROXY_DECLARE_DATA proxy_module; + + #endif /*MOD_PROXY_H*/ +diff --git a/modules/proxy/mod_proxy_ajp.c b/modules/proxy/mod_proxy_ajp.c +index 3736156..cf52a7d 100644 +--- a/modules/proxy/mod_proxy_ajp.c ++++ b/modules/proxy/mod_proxy_ajp.c +@@ -32,7 +32,7 @@ static int proxy_ajp_canon(request_rec *r, char *url) + char *host, *path, sport[7]; + char *search = NULL; + const char *err; +- apr_port_t port = AJP13_DEF_PORT; ++ apr_port_t port, def_port; + + /* ap_port_of_scheme() */ + if (strncasecmp(url, "ajp:", 4) == 0) { +@@ -48,6 +48,8 @@ static int proxy_ajp_canon(request_rec *r, char *url) + * do syntactic check. + * We break the URL into host, port, path, search + */ ++ port = def_port = ap_proxy_port_of_scheme("ajp"); ++ + err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port); + if (err) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00867) "error parsing URL %s: %s", +@@ -71,7 +73,10 @@ static int proxy_ajp_canon(request_rec *r, char *url) + if (path == NULL) + return HTTP_BAD_REQUEST; + +- apr_snprintf(sport, sizeof(sport), ":%d", port); ++ if (port != def_port) ++ apr_snprintf(sport, sizeof(sport), ":%d", port); ++ else ++ sport[0] = '\0'; + + if (ap_strchr_c(host, ':')) { + /* if literal IPv6 address */ +diff --git a/modules/proxy/mod_proxy_balancer.c b/modules/proxy/mod_proxy_balancer.c +index 0f45be7..514b8d8 100644 +--- a/modules/proxy/mod_proxy_balancer.c ++++ b/modules/proxy/mod_proxy_balancer.c +@@ -118,7 +118,8 @@ static void init_balancer_members(apr_pool_t *p, server_rec *s, + int worker_is_initialized; + proxy_worker *worker = *workers; + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01158) +- "Looking at %s -> %s initialized?", balancer->s->name, worker->s->name); ++ "Looking at %s -> %s initialized?", balancer->s->name, ++ ap_proxy_worker_name(p, worker)); + worker_is_initialized = PROXY_WORKER_IS_INITIALIZED(worker); + if (!worker_is_initialized) { + ap_proxy_initialize_worker(worker, s, p); +@@ -638,10 +639,11 @@ static int proxy_balancer_post_request(proxy_worker *worker, + int val = ((int *)balancer->errstatuses->elts)[i]; + if (r->status == val) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01174) +- "%s: Forcing worker (%s) into error state " ++ "%s: Forcing worker (%s) into error state " + "due to status code %d matching 'failonstatus' " + "balancer parameter", +- balancer->s->name, worker->s->name, val); ++ balancer->s->name, ap_proxy_worker_name(r->pool, worker), ++ val); + worker->s->status |= PROXY_WORKER_IN_ERROR; + worker->s->error_time = apr_time_now(); + break; +@@ -654,7 +656,7 @@ static int proxy_balancer_post_request(proxy_worker *worker, + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02460) + "%s: Forcing worker (%s) into error state " + "due to timeout and 'failonstatus' parameter being set", +- balancer->s->name, worker->s->name); ++ balancer->s->name, ap_proxy_worker_name(r->pool, worker)); + worker->s->status |= PROXY_WORKER_IN_ERROR; + worker->s->error_time = apr_time_now(); + +@@ -1282,7 +1284,7 @@ static int balancer_handler(request_rec *r) + worker = *workers; + /* Start proxy_worker */ + ap_rputs(" \n", r); +- ap_rvputs(r, " ", worker->s->name, ++ ap_rvputs(r, " ", ap_proxy_worker_name(r->pool, worker), + "\n", NULL); + ap_rvputs(r, " ", worker->s->scheme, + "\n", NULL); +@@ -1524,7 +1526,8 @@ static int balancer_handler(request_rec *r) + ap_escape_uri(r->pool, worker->s->name), + "&nonce=", balancer->s->nonce, + "\">", NULL); +- ap_rvputs(r, worker->s->name, "", NULL); ++ ap_rvputs(r, (*worker->s->uds_path ? "" : ""), ap_proxy_worker_name(r->pool, worker), ++ (*worker->s->uds_path ? "" : ""), "", NULL); + ap_rvputs(r, "
    ", ap_escape_html(r->pool, worker->s->route), + NULL); + ap_rvputs(r, "", +@@ -1549,7 +1552,7 @@ static int balancer_handler(request_rec *r) + ap_rputs("
    \n", r); + if (wsel && bsel) { + ap_rputs("

    Edit worker settings for ", r); +- ap_rvputs(r, wsel->s->name, "

    \n", NULL); ++ ap_rvputs(r, (*wsel->s->uds_path?"":""), ap_proxy_worker_name(r->pool, wsel), (*wsel->s->uds_path?"":""), "\n", NULL); + ap_rputs("
    pool, action), "\">\n", NULL); + ap_rputs("
    \n
    Load factor:pool, &url, NULL, NULL, &host, &port); + if (err) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01059) +@@ -96,7 +97,10 @@ static int proxy_fcgi_canon(request_rec *r, char *url) + return HTTP_BAD_REQUEST; + } + +- apr_snprintf(sport, sizeof(sport), ":%d", port); ++ if (port != def_port) ++ apr_snprintf(sport, sizeof(sport), ":%d", port); ++ else ++ sport[0] = '\0'; + + if (ap_strchr_c(host, ':')) { + /* if literal IPv6 address */ +@@ -930,7 +934,7 @@ static int proxy_fcgi_handler(request_rec *r, proxy_worker *worker, + int status; + char server_portstr[32]; + conn_rec *origin = NULL; +- proxy_conn_rec *backend = NULL; ++ proxy_conn_rec *backend; + + proxy_dir_conf *dconf = ap_get_module_config(r->per_dir_config, + &proxy_module); +@@ -943,10 +947,7 @@ static int proxy_fcgi_handler(request_rec *r, proxy_worker *worker, + "url: %s proxyname: %s proxyport: %d", + url, proxyname, proxyport); + +- if (strncasecmp(url, "fcgi:", 5) == 0) { +- url += 5; +- } +- else { ++ if (strncasecmp(url, "fcgi:", 5) != 0) { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01077) "declining URL %s", url); + return DECLINED; + } +@@ -954,16 +955,14 @@ static int proxy_fcgi_handler(request_rec *r, proxy_worker *worker, + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01078) "serving URL %s", url); + + /* Create space for state information */ +- if (! backend) { +- status = ap_proxy_acquire_connection(FCGI_SCHEME, &backend, worker, +- r->server); +- if (status != OK) { +- if (backend) { +- backend->close = 1; +- ap_proxy_release_connection(FCGI_SCHEME, backend, r->server); +- } +- return status; ++ status = ap_proxy_acquire_connection(FCGI_SCHEME, &backend, worker, ++ r->server); ++ if (status != OK) { ++ if (backend) { ++ backend->close = 1; ++ ap_proxy_release_connection(FCGI_SCHEME, backend, r->server); + } ++ return status; + } + + backend->is_ssl = 0; +diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c +index 05f33b4..f0bb0ed 100644 +--- a/modules/proxy/mod_proxy_http.c ++++ b/modules/proxy/mod_proxy_http.c +@@ -54,7 +54,7 @@ static int proxy_http_canon(request_rec *r, char *url) + else { + return DECLINED; + } +- def_port = apr_uri_port_of_scheme(scheme); ++ port = def_port = ap_proxy_port_of_scheme(scheme); + + ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, + "HTTP: canonicalising URL %s", url); +@@ -62,7 +62,6 @@ static int proxy_http_canon(request_rec *r, char *url) + /* do syntatic check. + * We break the URL into host, port, path, search + */ +- port = def_port; + err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port); + if (err) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01083) +diff --git a/modules/proxy/mod_proxy_scgi.c b/modules/proxy/mod_proxy_scgi.c +index f77a986..6deae78 100644 +--- a/modules/proxy/mod_proxy_scgi.c ++++ b/modules/proxy/mod_proxy_scgi.c +@@ -176,13 +176,15 @@ static int scgi_canon(request_rec *r, char *url) + { + char *host, sport[sizeof(":65535")]; + const char *err, *path; +- apr_port_t port = SCGI_DEFAULT_PORT; ++ apr_port_t port, def_port; + + if (strncasecmp(url, SCHEME "://", sizeof(SCHEME) + 2)) { + return DECLINED; + } + url += sizeof(SCHEME); /* Keep slashes */ + ++ port = def_port = SCGI_DEFAULT_PORT; ++ + err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port); + if (err) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00857) +@@ -190,7 +192,12 @@ static int scgi_canon(request_rec *r, char *url) + return HTTP_BAD_REQUEST; + } + +- apr_snprintf(sport, sizeof(sport), ":%u", port); ++ if (port != def_port) { ++ apr_snprintf(sport, sizeof(sport), ":%u", port); ++ } ++ else { ++ sport[0] = '\0'; ++ } + + if (ap_strchr(host, ':')) { /* if literal IPv6 address */ + host = apr_pstrcat(r->pool, "[", host, "]", NULL); +diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c +index 8bc9fab..dea2b10 100644 +--- a/modules/proxy/proxy_util.c ++++ b/modules/proxy/proxy_util.c +@@ -21,6 +21,7 @@ + #include "apr_version.h" + #include "apr_hash.h" + #include "proxy_util.h" ++#include "ajp.h" + + #if APR_HAVE_UNISTD_H + #include /* for getpid() */ +@@ -31,6 +32,13 @@ + #define apr_socket_create apr_socket_create_ex + #endif + ++#if APR_HAVE_SYS_UN_H ++#include ++#endif ++#if (APR_MAJOR_VERSION < 2) ++#include "apr_support.h" /* for apr_wait_for_io_or_timeout() */ ++#endif ++ + APLOG_USE_MODULE(proxy); + + /* +@@ -86,14 +94,20 @@ PROXY_DECLARE(apr_status_t) ap_proxy_strncpy(char *dst, const char *src, + char *thenil; + apr_size_t thelen; + ++ /* special case handling */ ++ if (!dlen) { ++ /* XXX: APR_ENOSPACE would be better */ ++ return APR_EGENERAL; ++ } ++ if (!src) { ++ *dst = '\0'; ++ return APR_SUCCESS; ++ } + thenil = apr_cpystrn(dst, src, dlen); + thelen = thenil - dst; +- /* Assume the typical case is smaller copying into bigger +- so we have a fast return */ +- if ((thelen < dlen-1) || ((strlen(src)) == thelen)) { ++ if (src[thelen] == '\0') { + return APR_SUCCESS; + } +- /* XXX: APR_ENOSPACE would be better */ + return APR_EGENERAL; + } + +@@ -1218,11 +1232,11 @@ PROXY_DECLARE(apr_status_t) ap_proxy_share_balancer(proxy_balancer *balancer, + } else { + action = "re-using"; + } ++ balancer->s = shm; ++ balancer->s->index = i; + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02337) + "%s shm[%d] (0x%pp) for %s", action, i, (void *)shm, + balancer->s->name); +- balancer->s = shm; +- balancer->s->index = i; + /* the below should always succeed */ + lbmethod = ap_lookup_provider(PROXY_LBMETHOD, balancer->s->lbpname, "0"); + if (lbmethod) { +@@ -1356,7 +1370,7 @@ static apr_status_t connection_cleanup(void *theconn) + ap_log_perror(APLOG_MARK, APLOG_ERR, 0, conn->pool, APLOGNO(00923) + "Pooled connection 0x%pp for worker %s has been" + " already returned to the connection pool.", conn, +- worker->s->name); ++ ap_proxy_worker_name(conn->pool, worker)); + return APR_SUCCESS; + } + +@@ -1480,6 +1494,55 @@ static apr_status_t connection_destructor(void *resource, void *params, + * WORKER related... + */ + ++PROXY_DECLARE(char *) ap_proxy_worker_name(apr_pool_t *p, ++ proxy_worker *worker) ++{ ++ if (!(*worker->s->uds_path) || !p) { ++ /* just in case */ ++ return worker->s->name; ++ } ++ return apr_pstrcat(p, "unix:", worker->s->uds_path, "|", worker->s->name, NULL); ++} ++ ++/* ++ * Taken from ap_strcmp_match() : ++ * Match = 0, NoMatch = 1, Abort = -1, Inval = -2 ++ * Based loosely on sections of wildmat.c by Rich Salz ++ * Hmmm... shouldn't this really go component by component? ++ * ++ * Adds handling of the "\" => "" unescaping. ++ */ ++static int ap_proxy_strcmp_ematch(const char *str, const char *expected) ++{ ++ apr_size_t x, y; ++ ++ for (x = 0, y = 0; expected[y]; ++y, ++x) { ++ if ((!str[x]) && (expected[y] != '$' || !apr_isdigit(expected[y + 1]))) ++ return -1; ++ if (expected[y] == '$' && apr_isdigit(expected[y + 1])) { ++ while (expected[y] == '$' && apr_isdigit(expected[y + 1])) ++ y += 2; ++ if (!expected[y]) ++ return 0; ++ while (str[x]) { ++ int ret; ++ if ((ret = ap_proxy_strcmp_ematch(&str[x++], &expected[y])) != 1) ++ return ret; ++ } ++ return -1; ++ } ++ else if (expected[y] == '\\') { ++ /* NUL is an invalid char! */ ++ if (!expected[++y]) ++ return -2; ++ } ++ if (str[x] != expected[y]) ++ return 1; ++ } ++ /* We got all the way through the worker path without a difference */ ++ return 0; ++} ++ + PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p, + proxy_balancer *balancer, + proxy_server_conf *conf, +@@ -1495,6 +1558,10 @@ PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p, + char *url_copy; + int i; + ++ if (!url) { ++ return NULL; ++ } ++ + c = ap_strchr_c(url, ':'); + if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0') { + return NULL; +@@ -1536,11 +1603,15 @@ PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p, + if ( ((worker_name_length = strlen(worker->s->name)) <= url_length) + && (worker_name_length >= min_match) + && (worker_name_length > max_match) +- && (strncmp(url_copy, worker->s->name, worker_name_length) == 0) ) { ++ && (worker->s->is_name_matchable ++ || strncmp(url_copy, worker->s->name, ++ worker_name_length) == 0) ++ && (!worker->s->is_name_matchable ++ || ap_proxy_strcmp_ematch(url_copy, ++ worker->s->name) == 0) ) { + max_worker = worker; + max_match = worker_name_length; + } +- + } + } else { + worker = (proxy_worker *)conf->workers->elts; +@@ -1548,7 +1619,12 @@ PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p, + if ( ((worker_name_length = strlen(worker->s->name)) <= url_length) + && (worker_name_length >= min_match) + && (worker_name_length > max_match) +- && (strncmp(url_copy, worker->s->name, worker_name_length) == 0) ) { ++ && (worker->s->is_name_matchable ++ || strncmp(url_copy, worker->s->name, ++ worker_name_length) == 0) ++ && (!worker->s->is_name_matchable ++ || ap_proxy_strcmp_ematch(url_copy, ++ worker->s->name) == 0) ) { + max_worker = worker; + max_match = worker_name_length; + } +@@ -1573,20 +1649,47 @@ PROXY_DECLARE(char *) ap_proxy_define_worker(apr_pool_t *p, + int do_malloc) + { + int rv; +- apr_uri_t uri; ++ apr_uri_t uri, urisock; + proxy_worker_shared *wshared; +- char *ptr; ++ char *ptr, *sockpath = NULL; + ++ /* ++ * Look to see if we are using UDS: ++ * require format: unix:/path/foo/bar.sock|http://ignored/path2/ ++ * This results in talking http to the socket at /path/foo/bar.sock ++ */ ++ ptr = ap_strchr((char *)url, '|'); ++ if (ptr) { ++ *ptr = '\0'; ++ rv = apr_uri_parse(p, url, &urisock); ++ if (rv == APR_SUCCESS && !strcasecmp(urisock.scheme, "unix")) { ++ sockpath = ap_runtime_dir_relative(p, urisock.path);; ++ url = ptr+1; /* so we get the scheme for the uds */ ++ } ++ else { ++ *ptr = '|'; ++ } ++ } + rv = apr_uri_parse(p, url, &uri); + + if (rv != APR_SUCCESS) { +- return "Unable to parse URL"; ++ return apr_pstrcat(p, "Unable to parse URL: ", url, NULL); + } +- if (!uri.hostname || !uri.scheme) { +- return "URL must be absolute!"; ++ if (!uri.scheme) { ++ return apr_pstrcat(p, "URL must be absolute!: ", url, NULL); ++ } ++ /* allow for unix:/path|http: */ ++ if (!uri.hostname) { ++ if (sockpath) { ++ uri.hostname = "localhost"; ++ } ++ else { ++ return apr_pstrcat(p, "URL must be absolute!: ", url, NULL); ++ } ++ } ++ else { ++ ap_str_tolower(uri.hostname); + } +- +- ap_str_tolower(uri.hostname); + ap_str_tolower(uri.scheme); + /* + * Workers can be associated w/ balancers or on their +@@ -1642,6 +1745,16 @@ PROXY_DECLARE(char *) ap_proxy_define_worker(apr_pool_t *p, + wshared->hash.def = ap_proxy_hashfunc(wshared->name, PROXY_HASHFUNC_DEFAULT); + wshared->hash.fnv = ap_proxy_hashfunc(wshared->name, PROXY_HASHFUNC_FNV); + wshared->was_malloced = (do_malloc != 0); ++ wshared->is_name_matchable = 0; ++ if (sockpath) { ++ if (PROXY_STRNCPY(wshared->uds_path, sockpath) != APR_SUCCESS) { ++ return apr_psprintf(p, "worker uds path (%s) too long", sockpath); ++ } ++ ++ } ++ else { ++ *wshared->uds_path = '\0'; ++ } + + (*worker)->hash = wshared->hash; + (*worker)->context = NULL; +@@ -1652,6 +1765,24 @@ PROXY_DECLARE(char *) ap_proxy_define_worker(apr_pool_t *p, + return NULL; + } + ++PROXY_DECLARE(char *) ap_proxy_define_match_worker(apr_pool_t *p, ++ proxy_worker **worker, ++ proxy_balancer *balancer, ++ proxy_server_conf *conf, ++ const char *url, ++ int do_malloc) ++{ ++ char *err; ++ ++ err = ap_proxy_define_worker(p, worker, balancer, conf, url, do_malloc); ++ if (err) { ++ return err; ++ } ++ ++ (*worker)->s->is_name_matchable = 1; ++ return NULL; ++} ++ + /* + * Create an already defined worker and free up memory + */ +@@ -1670,12 +1801,18 @@ PROXY_DECLARE(apr_status_t) ap_proxy_share_worker(proxy_worker *worker, proxy_wo + } else { + action = "re-using"; + } +- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02338) +- "%s shm[%d] (0x%pp) for worker: %s", action, i, (void *)shm, +- worker->s->name); +- + worker->s = shm; + worker->s->index = i; ++ { ++ apr_pool_t *pool; ++ apr_pool_create(&pool, ap_server_conf->process->pool); ++ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02338) ++ "%s shm[%d] (0x%pp) for worker: %s", action, i, (void *)shm, ++ ap_proxy_worker_name(pool, worker)); ++ if (pool) { ++ apr_pool_destroy(pool); ++ } ++ } + return APR_SUCCESS; + } + +@@ -1687,11 +1824,13 @@ PROXY_DECLARE(apr_status_t) ap_proxy_initialize_worker(proxy_worker *worker, ser + if (worker->s->status & PROXY_WORKER_INITIALIZED) { + /* The worker is already initialized */ + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00924) +- "worker %s shared already initialized", worker->s->name); ++ "worker %s shared already initialized", ++ ap_proxy_worker_name(p, worker)); + } + else { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00925) +- "initializing worker %s shared", worker->s->name); ++ "initializing worker %s shared", ++ ap_proxy_worker_name(p, worker)); + /* Set default parameters */ + if (!worker->s->retry_set) { + worker->s->retry = apr_time_from_sec(PROXY_WORKER_DEFAULT_RETRY); +@@ -1727,11 +1866,13 @@ PROXY_DECLARE(apr_status_t) ap_proxy_initialize_worker(proxy_worker *worker, ser + /* What if local is init'ed and shm isn't?? Even possible? */ + if (worker->local_status & PROXY_WORKER_INITIALIZED) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00926) +- "worker %s local already initialized", worker->s->name); ++ "worker %s local already initialized", ++ ap_proxy_worker_name(p, worker)); + } + else { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00927) +- "initializing worker %s local", worker->s->name); ++ "initializing worker %s local", ++ ap_proxy_worker_name(p, worker)); + apr_global_mutex_lock(proxy_mutex); + /* Now init local worker data */ + if (worker->tmutex == NULL) { +@@ -1853,6 +1994,8 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker, + } + else if (r->proxyreq == PROXYREQ_REVERSE) { + if (conf->reverse) { ++ char *ptr; ++ char *ptr2; + ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, + "*: found reverse proxy worker for %s", *url); + *balancer = NULL; +@@ -1864,6 +2007,36 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker, + * regarding the Connection header in the request. + */ + apr_table_setn(r->subprocess_env, "proxy-nokeepalive", "1"); ++ /* ++ * In the case of the generic reverse proxy, we need to see if we ++ * were passed a UDS url (eg: from mod_proxy) and adjust uds_path ++ * as required. ++ * ++ * NOTE: Here we use a quick note lookup, but we could also ++ * check to see if r->filename starts with 'proxy:' ++ */ ++ if (apr_table_get(r->notes, "rewrite-proxy") && ++ (ptr2 = ap_strcasestr(r->filename, "unix:")) && ++ (ptr = ap_strchr(ptr2, '|'))) { ++ apr_uri_t urisock; ++ apr_status_t rv; ++ *ptr = '\0'; ++ rv = apr_uri_parse(r->pool, ptr2, &urisock); ++ if (rv == APR_SUCCESS) { ++ char *rurl = ptr+1; ++ char *sockpath = ap_runtime_dir_relative(r->pool, urisock.path); ++ apr_table_setn(r->notes, "uds_path", sockpath); ++ *url = apr_pstrdup(r->pool, rurl); /* so we get the scheme for the uds */ ++ /* r->filename starts w/ "proxy:", so add after that */ ++ memmove(r->filename+6, rurl, strlen(rurl)+1); ++ ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, ++ "*: rewrite of url due to UDS(%s): %s (%s)", ++ sockpath, *url, r->filename); ++ } ++ else { ++ *ptr = '|'; ++ } ++ } + } + } + } +@@ -2053,6 +2226,7 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, + int server_port; + apr_status_t err = APR_SUCCESS; + apr_status_t uerr = APR_SUCCESS; ++ const char *uds_path; + + /* + * Break up the URL to determine the host to connect to +@@ -2065,7 +2239,7 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, + NULL)); + } + if (!uri->port) { +- uri->port = apr_uri_port_of_scheme(uri->scheme); ++ uri->port = ap_proxy_port_of_scheme(uri->scheme); + } + + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00944) +@@ -2093,73 +2267,117 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, + * to check host and port on the conn and be careful about + * spilling the cached addr from the worker. + */ +- if (!conn->hostname || !worker->s->is_address_reusable || +- worker->s->disablereuse) { +- if (proxyname) { +- conn->hostname = apr_pstrdup(conn->pool, proxyname); +- conn->port = proxyport; +- /* +- * If we have a forward proxy and the protocol is HTTPS, +- * then we need to prepend a HTTP CONNECT request before +- * sending our actual HTTPS requests. +- * Save our real backend data for using it later during HTTP CONNECT. +- */ +- if (conn->is_ssl) { +- const char *proxy_auth; +- +- forward_info *forward = apr_pcalloc(conn->pool, sizeof(forward_info)); +- conn->forward = forward; +- forward->use_http_connect = 1; +- forward->target_host = apr_pstrdup(conn->pool, uri->hostname); +- forward->target_port = uri->port; +- /* Do we want to pass Proxy-Authorization along? +- * If we haven't used it, then YES +- * If we have used it then MAYBE: RFC2616 says we MAY propagate it. +- * So let's make it configurable by env. +- * The logic here is the same used in mod_proxy_http. +- */ +- proxy_auth = apr_table_get(r->headers_in, "Proxy-Authorization"); +- if (proxy_auth != NULL && +- proxy_auth[0] != '\0' && +- r->user == NULL && /* we haven't yet authenticated */ +- apr_table_get(r->subprocess_env, "Proxy-Chain-Auth")) { +- forward->proxy_auth = apr_pstrdup(conn->pool, proxy_auth); +- } +- } ++ uds_path = (*worker->s->uds_path ? worker->s->uds_path : apr_table_get(r->notes, "uds_path")); ++ if (uds_path) { ++ if (conn->uds_path == NULL) { ++ /* use (*conn)->pool instead of worker->cp->pool to match lifetime */ ++ conn->uds_path = apr_pstrdup(conn->pool, uds_path); + } +- else { +- conn->hostname = apr_pstrdup(conn->pool, uri->hostname); +- conn->port = uri->port; +- } +- socket_cleanup(conn); +- err = apr_sockaddr_info_get(&(conn->addr), +- conn->hostname, APR_UNSPEC, +- conn->port, 0, +- conn->pool); +- } +- else if (!worker->cp->addr) { +- if ((err = PROXY_THREAD_LOCK(worker)) != APR_SUCCESS) { +- ap_log_rerror(APLOG_MARK, APLOG_ERR, err, r, APLOGNO(00945) "lock"); +- return HTTP_INTERNAL_SERVER_ERROR; ++ if (conn->uds_path) { ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02545) ++ "%s: has determined UDS as %s", ++ uri->scheme, conn->uds_path); + } ++ else { ++ /* should never happen */ ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02546) ++ "%s: cannot determine UDS (%s)", ++ uri->scheme, uds_path); + ++ } + /* +- * Worker can have the single constant backend adress. +- * The single DNS lookup is used once per worker. +- * If dynamic change is needed then set the addr to NULL +- * inside dynamic config to force the lookup. ++ * In UDS cases, some structs are NULL. Protect from de-refs ++ * and provide info for logging at the same time. + */ +- err = apr_sockaddr_info_get(&(worker->cp->addr), +- conn->hostname, APR_UNSPEC, +- conn->port, 0, +- worker->cp->pool); +- conn->addr = worker->cp->addr; +- if ((uerr = PROXY_THREAD_UNLOCK(worker)) != APR_SUCCESS) { +- ap_log_rerror(APLOG_MARK, APLOG_ERR, uerr, r, APLOGNO(00946) "unlock"); ++ if (!conn->addr) { ++ apr_sockaddr_t *sa; ++ apr_sockaddr_info_get(&sa, NULL, APR_UNSPEC, 0, 0, conn->pool); ++ conn->addr = sa; + } ++ conn->hostname = "httpd-UDS"; ++ conn->port = 0; + } + else { +- conn->addr = worker->cp->addr; ++ int will_reuse = worker->s->is_address_reusable && !worker->s->disablereuse; ++ if (!conn->hostname || !will_reuse) { ++ if (proxyname) { ++ conn->hostname = apr_pstrdup(conn->pool, proxyname); ++ conn->port = proxyport; ++ /* ++ * If we have a forward proxy and the protocol is HTTPS, ++ * then we need to prepend a HTTP CONNECT request before ++ * sending our actual HTTPS requests. ++ * Save our real backend data for using it later during HTTP CONNECT. ++ */ ++ if (conn->is_ssl) { ++ const char *proxy_auth; ++ ++ forward_info *forward = apr_pcalloc(conn->pool, sizeof(forward_info)); ++ conn->forward = forward; ++ forward->use_http_connect = 1; ++ forward->target_host = apr_pstrdup(conn->pool, uri->hostname); ++ forward->target_port = uri->port; ++ /* Do we want to pass Proxy-Authorization along? ++ * If we haven't used it, then YES ++ * If we have used it then MAYBE: RFC2616 says we MAY propagate it. ++ * So let's make it configurable by env. ++ * The logic here is the same used in mod_proxy_http. ++ */ ++ proxy_auth = apr_table_get(r->headers_in, "Proxy-Authorization"); ++ if (proxy_auth != NULL && ++ proxy_auth[0] != '\0' && ++ r->user == NULL && /* we haven't yet authenticated */ ++ apr_table_get(r->subprocess_env, "Proxy-Chain-Auth")) { ++ forward->proxy_auth = apr_pstrdup(conn->pool, proxy_auth); ++ } ++ } ++ } ++ else { ++ conn->hostname = apr_pstrdup(conn->pool, uri->hostname); ++ conn->port = uri->port; ++ } ++ if (!will_reuse) { ++ /* ++ * Only do a lookup if we should not reuse the backend address. ++ * Otherwise we will look it up once for the worker. ++ */ ++ err = apr_sockaddr_info_get(&(conn->addr), ++ conn->hostname, APR_UNSPEC, ++ conn->port, 0, ++ conn->pool); ++ } ++ socket_cleanup(conn); ++ } ++ if (will_reuse) { ++ /* ++ * Looking up the backend address for the worker only makes sense if ++ * we can reuse the address. ++ */ ++ if (!worker->cp->addr) { ++ if ((err = PROXY_THREAD_LOCK(worker)) != APR_SUCCESS) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, err, r, APLOGNO(00945) "lock"); ++ return HTTP_INTERNAL_SERVER_ERROR; ++ } ++ ++ /* ++ * Worker can have the single constant backend adress. ++ * The single DNS lookup is used once per worker. ++ * If dynamic change is needed then set the addr to NULL ++ * inside dynamic config to force the lookup. ++ */ ++ err = apr_sockaddr_info_get(&(worker->cp->addr), ++ conn->hostname, APR_UNSPEC, ++ conn->port, 0, ++ worker->cp->pool); ++ conn->addr = worker->cp->addr; ++ if ((uerr = PROXY_THREAD_UNLOCK(worker)) != APR_SUCCESS) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, uerr, r, APLOGNO(00946) "unlock"); ++ } ++ } ++ else { ++ conn->addr = worker->cp->addr; ++ } ++ } + } + /* Close a possible existing socket if we are told to do so */ + if (conn->close) { +@@ -2360,6 +2578,52 @@ static apr_status_t send_http_connect(proxy_conn_rec *backend, + } + + ++#if APR_HAVE_SYS_UN_H ++/* lifted from mod_proxy_fdpass.c; tweaked addrlen in connect() call */ ++static apr_status_t socket_connect_un(apr_socket_t *sock, ++ struct sockaddr_un *sa) ++{ ++ apr_status_t rv; ++ apr_os_sock_t rawsock; ++ apr_interval_time_t t; ++ ++ rv = apr_os_sock_get(&rawsock, sock); ++ if (rv != APR_SUCCESS) { ++ return rv; ++ } ++ ++ rv = apr_socket_timeout_get(sock, &t); ++ if (rv != APR_SUCCESS) { ++ return rv; ++ } ++ ++ do { ++ const socklen_t addrlen = APR_OFFSETOF(struct sockaddr_un, sun_path) ++ + strlen(sa->sun_path) + 1; ++ rv = connect(rawsock, (struct sockaddr*)sa, addrlen); ++ } while (rv == -1 && errno == EINTR); ++ ++ if ((rv == -1) && (errno == EINPROGRESS || errno == EALREADY) ++ && (t > 0)) { ++#if APR_MAJOR_VERSION < 2 ++ rv = apr_wait_for_io_or_timeout(NULL, sock, 0); ++#else ++ rv = apr_socket_wait(sock, APR_WAIT_WRITE); ++#endif ++ ++ if (rv != APR_SUCCESS) { ++ return rv; ++ } ++ } ++ ++ if (rv == -1 && errno != EISCONN) { ++ return errno; ++ } ++ ++ return APR_SUCCESS; ++} ++#endif ++ + PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, + proxy_conn_rec *conn, + proxy_worker *worker, +@@ -2384,93 +2648,131 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, + proxy_function); + } + } +- while (backend_addr && !connected) { +- if ((rv = apr_socket_create(&newsock, backend_addr->family, +- SOCK_STREAM, APR_PROTO_TCP, +- conn->scpool)) != APR_SUCCESS) { +- loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR; +- ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(00952) +- "%s: error creating fam %d socket for target %s", +- proxy_function, +- backend_addr->family, +- worker->s->hostname); +- /* +- * this could be an IPv6 address from the DNS but the +- * local machine won't give us an IPv6 socket; hopefully the +- * DNS returned an additional address to try +- */ +- backend_addr = backend_addr->next; +- continue; +- } +- conn->connection = NULL; ++ while ((backend_addr || conn->uds_path) && !connected) { ++#if APR_HAVE_SYS_UN_H ++ if (conn->uds_path) ++ { ++ struct sockaddr_un sa; + +- if (worker->s->recv_buffer_size > 0 && +- (rv = apr_socket_opt_set(newsock, APR_SO_RCVBUF, +- worker->s->recv_buffer_size))) { +- ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00953) +- "apr_socket_opt_set(SO_RCVBUF): Failed to set " +- "ProxyReceiveBufferSize, using default"); +- } ++ rv = apr_socket_create(&newsock, AF_UNIX, SOCK_STREAM, 0, ++ conn->scpool); ++ if (rv != APR_SUCCESS) { ++ loglevel = APLOG_ERR; ++ ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(02453) ++ "%s: error creating Unix domain socket for " ++ "target %s", ++ proxy_function, ++ worker->s->hostname); ++ break; ++ } ++ conn->connection = NULL; + +- rv = apr_socket_opt_set(newsock, APR_TCP_NODELAY, 1); +- if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) { +- ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00954) +- "apr_socket_opt_set(APR_TCP_NODELAY): " +- "Failed to set"); +- } ++ sa.sun_family = AF_UNIX; ++ apr_cpystrn(sa.sun_path, conn->uds_path, sizeof(sa.sun_path)); + +- /* Set a timeout for connecting to the backend on the socket */ +- if (worker->s->conn_timeout_set) { +- apr_socket_timeout_set(newsock, worker->s->conn_timeout); +- } +- else if (worker->s->timeout_set) { +- apr_socket_timeout_set(newsock, worker->s->timeout); +- } +- else if (conf->timeout_set) { +- apr_socket_timeout_set(newsock, conf->timeout); +- } +- else { +- apr_socket_timeout_set(newsock, s->timeout); +- } +- /* Set a keepalive option */ +- if (worker->s->keepalive) { +- if ((rv = apr_socket_opt_set(newsock, +- APR_SO_KEEPALIVE, 1)) != APR_SUCCESS) { +- ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00955) +- "apr_socket_opt_set(SO_KEEPALIVE): Failed to set" +- " Keepalive"); ++ rv = socket_connect_un(newsock, &sa); ++ if (rv != APR_SUCCESS) { ++ apr_socket_close(newsock); ++ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(02454) ++ "%s: attempt to connect to Unix domain socket " ++ "%s (%s) failed", ++ proxy_function, ++ conn->uds_path, ++ worker->s->hostname); ++ break; + } + } +- ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, s, +- "%s: fam %d socket created to connect to %s", +- proxy_function, backend_addr->family, worker->s->hostname); ++ else ++#endif ++ { ++ if ((rv = apr_socket_create(&newsock, backend_addr->family, ++ SOCK_STREAM, APR_PROTO_TCP, ++ conn->scpool)) != APR_SUCCESS) { ++ loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR; ++ ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(00952) ++ "%s: error creating fam %d socket for " ++ "target %s", ++ proxy_function, ++ backend_addr->family, ++ worker->s->hostname); ++ /* ++ * this could be an IPv6 address from the DNS but the ++ * local machine won't give us an IPv6 socket; hopefully the ++ * DNS returned an additional address to try ++ */ ++ backend_addr = backend_addr->next; ++ continue; ++ } ++ conn->connection = NULL; ++ ++ if (worker->s->recv_buffer_size > 0 && ++ (rv = apr_socket_opt_set(newsock, APR_SO_RCVBUF, ++ worker->s->recv_buffer_size))) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00953) ++ "apr_socket_opt_set(SO_RCVBUF): Failed to set " ++ "ProxyReceiveBufferSize, using default"); ++ } + +- if (conf->source_address_set) { +- local_addr = apr_pmemdup(conn->pool, conf->source_address, +- sizeof(apr_sockaddr_t)); +- local_addr->pool = conn->pool; +- rv = apr_socket_bind(newsock, local_addr); +- if (rv != APR_SUCCESS) { +- ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00956) +- "%s: failed to bind socket to local address", +- proxy_function); ++ rv = apr_socket_opt_set(newsock, APR_TCP_NODELAY, 1); ++ if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00954) ++ "apr_socket_opt_set(APR_TCP_NODELAY): " ++ "Failed to set"); + } +- } + +- /* make the connection out of the socket */ +- rv = apr_socket_connect(newsock, backend_addr); ++ /* Set a timeout for connecting to the backend on the socket */ ++ if (worker->s->conn_timeout_set) { ++ apr_socket_timeout_set(newsock, worker->s->conn_timeout); ++ } ++ else if (worker->s->timeout_set) { ++ apr_socket_timeout_set(newsock, worker->s->timeout); ++ } ++ else if (conf->timeout_set) { ++ apr_socket_timeout_set(newsock, conf->timeout); ++ } ++ else { ++ apr_socket_timeout_set(newsock, s->timeout); ++ } ++ /* Set a keepalive option */ ++ if (worker->s->keepalive) { ++ if ((rv = apr_socket_opt_set(newsock, ++ APR_SO_KEEPALIVE, 1)) != APR_SUCCESS) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00955) ++ "apr_socket_opt_set(SO_KEEPALIVE): Failed to set" ++ " Keepalive"); ++ } ++ } ++ ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, s, ++ "%s: fam %d socket created to connect to %s", ++ proxy_function, backend_addr->family, worker->s->hostname); ++ ++ if (conf->source_address_set) { ++ local_addr = apr_pmemdup(conn->pool, conf->source_address, ++ sizeof(apr_sockaddr_t)); ++ local_addr->pool = conn->pool; ++ rv = apr_socket_bind(newsock, local_addr); ++ if (rv != APR_SUCCESS) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00956) ++ "%s: failed to bind socket to local address", ++ proxy_function); ++ } ++ } + +- /* if an error occurred, loop round and try again */ +- if (rv != APR_SUCCESS) { +- apr_socket_close(newsock); +- loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR; +- ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(00957) +- "%s: attempt to connect to %pI (%s) failed", +- proxy_function, +- backend_addr, +- worker->s->hostname); +- backend_addr = backend_addr->next; +- continue; ++ /* make the connection out of the socket */ ++ rv = apr_socket_connect(newsock, backend_addr); ++ ++ /* if an error occurred, loop round and try again */ ++ if (rv != APR_SUCCESS) { ++ apr_socket_close(newsock); ++ loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR; ++ ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(00957) ++ "%s: attempt to connect to %pI (%s) failed", ++ proxy_function, ++ backend_addr, ++ worker->s->hostname); ++ backend_addr = backend_addr->next; ++ continue; ++ } + } + + /* Set a timeout on the socket */ +@@ -2486,7 +2788,7 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, + + conn->sock = newsock; + +- if (conn->forward) { ++ if (!conn->uds_path && conn->forward) { + forward_info *forward = (forward_info *)conn->forward; + /* + * For HTTP CONNECT we need to prepend CONNECT request before +@@ -2767,7 +3069,7 @@ PROXY_DECLARE(apr_status_t) ap_proxy_sync_balancer(proxy_balancer *b, server_rec + found = 1; + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02402) + "re-grabbing shm[%d] (0x%pp) for worker: %s", i, (void *)shm, +- worker->s->name); ++ ap_proxy_worker_name(conf->pool, worker)); + break; + } + } +@@ -3201,6 +3503,39 @@ PROXY_DECLARE(int) ap_proxy_pass_brigade(apr_bucket_alloc_t *bucket_alloc, + return OK; + } + ++/* Fill in unknown schemes from apr_uri_port_of_scheme() */ ++ ++typedef struct proxy_schemes_t { ++ const char *name; ++ apr_port_t default_port; ++} proxy_schemes_t ; ++ ++static proxy_schemes_t pschemes[] = ++{ ++ {"fcgi", 8000}, ++ {"ajp", AJP13_DEF_PORT}, ++ {"scgi", 4000}, ++ { NULL, 0xFFFF } /* unknown port */ ++}; ++ ++PROXY_DECLARE(apr_port_t) ap_proxy_port_of_scheme(const char *scheme) ++{ ++ if (scheme) { ++ apr_port_t port; ++ if ((port = apr_uri_port_of_scheme(scheme)) != 0) { ++ return port; ++ } else { ++ proxy_schemes_t *pscheme; ++ for (pscheme = pschemes; pscheme->name != NULL; ++pscheme) { ++ if (strcasecmp(scheme, pscheme->name) == 0) { ++ return pscheme->default_port; ++ } ++ } ++ } ++ } ++ return 0; ++} ++ + void proxy_util_register_hooks(apr_pool_t *p) + { + APR_REGISTER_OPTIONAL_FN(ap_proxy_retry_worker); diff --git a/SOURCES/httpd-2.4.6-upn.patch b/SOURCES/httpd-2.4.6-upn.patch new file mode 100644 index 0000000..ce7f19c --- /dev/null +++ b/SOURCES/httpd-2.4.6-upn.patch @@ -0,0 +1,381 @@ +diff --git a/modules/ssl/mod_ssl.c b/modules/ssl/mod_ssl.c +index 926e05e..bbe1d20 100644 +--- a/modules/ssl/mod_ssl.c ++++ b/modules/ssl/mod_ssl.c +@@ -333,6 +333,11 @@ static int ssl_hook_pre_config(apr_pool_t *pconf, + OpenSSL_add_all_algorithms(); + OPENSSL_load_builtin_modules(); + ++ if (OBJ_txt2nid("id-on-dnsSRV") == NID_undef) { ++ (void)OBJ_create("1.3.6.1.5.5.7.8.7", "id-on-dnsSRV", ++ "SRVName otherName form"); ++ } ++ + /* + * Let us cleanup the ssl library when the module is unloaded + */ +diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c +index eb11a38..27eaa5a 100644 +--- a/modules/ssl/ssl_engine_kernel.c ++++ b/modules/ssl/ssl_engine_kernel.c +@@ -1156,6 +1156,7 @@ int ssl_hook_Fixup(request_rec *r) + /* standard SSL environment variables */ + if (dc->nOptions & SSL_OPT_STDENVVARS) { + modssl_var_extract_dns(env, sslconn->ssl, r->pool); ++ modssl_var_extract_san_entries(env, sslconn->ssl, r->pool); + + for (i = 0; ssl_hook_Fixup_vars[i]; i++) { + var = (char *)ssl_hook_Fixup_vars[i]; +diff --git a/modules/ssl/ssl_engine_vars.c b/modules/ssl/ssl_engine_vars.c +index c508fff..2b7c9ba 100644 +--- a/modules/ssl/ssl_engine_vars.c ++++ b/modules/ssl/ssl_engine_vars.c +@@ -42,6 +42,7 @@ + static char *ssl_var_lookup_ssl(apr_pool_t *p, conn_rec *c, request_rec *r, char *var); + static char *ssl_var_lookup_ssl_cert(apr_pool_t *p, request_rec *r, X509 *xs, char *var); + static char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname, char *var); ++static char *ssl_var_lookup_ssl_cert_san(apr_pool_t *p, X509 *xs, char *var); + static char *ssl_var_lookup_ssl_cert_valid(apr_pool_t *p, ASN1_TIME *tm); + static char *ssl_var_lookup_ssl_cert_remain(apr_pool_t *p, ASN1_TIME *tm); + static char *ssl_var_lookup_ssl_cert_serial(apr_pool_t *p, X509 *xs); +@@ -509,6 +510,10 @@ static char *ssl_var_lookup_ssl_cert(apr_pool_t *p, request_rec *r, X509 *xs, + result = ssl_var_lookup_ssl_cert_dn(p, xsname, var+5); + resdup = FALSE; + } ++ else if (strlen(var) > 4 && strcEQn(var, "SAN_", 4)) { ++ result = ssl_var_lookup_ssl_cert_san(p, xs, var+4); ++ resdup = FALSE; ++ } + else if (strcEQ(var, "A_SIG")) { + nid = OBJ_obj2nid((ASN1_OBJECT *)(xs->cert_info->signature->algorithm)); + result = apr_pstrdup(p, +@@ -597,6 +602,49 @@ static char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname, char * + return result; + } + ++static char *ssl_var_lookup_ssl_cert_san(apr_pool_t *p, X509 *xs, char *var) ++{ ++ int type, numlen; ++ const char *onf = NULL; ++ apr_array_header_t *entries; ++ ++ if (strcEQn(var, "Email_", 6)) { ++ type = GEN_EMAIL; ++ var += 6; ++ } ++ else if (strcEQn(var, "DNS_", 4)) { ++ type = GEN_DNS; ++ var += 4; ++ } ++ else if (strcEQn(var, "OTHER_", 6)) { ++ type = GEN_OTHERNAME; ++ var += 6; ++ if (strEQn(var, "msUPN_", 6)) { ++ var += 6; ++ onf = "msUPN"; ++ } ++ else if (strEQn(var, "dnsSRV_", 7)) { ++ var += 7; ++ onf = "id-on-dnsSRV"; ++ } ++ else ++ return NULL; ++ } ++ else ++ return NULL; ++ ++ /* sanity check: number must be between 1 and 4 digits */ ++ numlen = strspn(var, "0123456789"); ++ if ((numlen < 1) || (numlen > 4) || (numlen != strlen(var))) ++ return NULL; ++ ++ if (SSL_X509_getSAN(p, xs, type, onf, atoi(var), &entries)) ++ /* return the first entry from this 1-element array */ ++ return APR_ARRAY_IDX(entries, 0, char *); ++ else ++ return NULL; ++} ++ + static char *ssl_var_lookup_ssl_cert_valid(apr_pool_t *p, ASN1_TIME *tm) + { + char *result; +@@ -890,6 +938,54 @@ void modssl_var_extract_dns(apr_table_t *t, SSL *ssl, apr_pool_t *p) + } + } + ++static void extract_san_array(apr_table_t *t, const char *pfx, ++ apr_array_header_t *entries, apr_pool_t *p) ++{ ++ int i; ++ ++ for (i = 0; i < entries->nelts; i++) { ++ const char *key = apr_psprintf(p, "%s_%d", pfx, i); ++ apr_table_setn(t, key, APR_ARRAY_IDX(entries, i, const char *)); ++ } ++} ++ ++void modssl_var_extract_san_entries(apr_table_t *t, SSL *ssl, apr_pool_t *p) ++{ ++ X509 *xs; ++ apr_array_header_t *entries; ++ ++ /* subjectAltName entries of the server certificate */ ++ xs = SSL_get_certificate(ssl); ++ if (xs) { ++ if (SSL_X509_getSAN(p, xs, GEN_EMAIL, NULL, -1, &entries)) { ++ extract_san_array(t, "SSL_SERVER_SAN_Email", entries, p); ++ } ++ if (SSL_X509_getSAN(p, xs, GEN_DNS, NULL, -1, &entries)) { ++ extract_san_array(t, "SSL_SERVER_SAN_DNS", entries, p); ++ } ++ if (SSL_X509_getSAN(p, xs, GEN_OTHERNAME, "id-on-dnsSRV", -1, ++ &entries)) { ++ extract_san_array(t, "SSL_SERVER_SAN_OTHER_dnsSRV", entries, p); ++ } ++ /* no need to free xs (refcount does not increase) */ ++ } ++ ++ /* subjectAltName entries of the client certificate */ ++ xs = SSL_get_peer_certificate(ssl); ++ if (xs) { ++ if (SSL_X509_getSAN(p, xs, GEN_EMAIL, NULL, -1, &entries)) { ++ extract_san_array(t, "SSL_CLIENT_SAN_Email", entries, p); ++ } ++ if (SSL_X509_getSAN(p, xs, GEN_DNS, NULL, -1, &entries)) { ++ extract_san_array(t, "SSL_CLIENT_SAN_DNS", entries, p); ++ } ++ if (SSL_X509_getSAN(p, xs, GEN_OTHERNAME, "msUPN", -1, &entries)) { ++ extract_san_array(t, "SSL_CLIENT_SAN_OTHER_msUPN", entries, p); ++ } ++ X509_free(xs); ++ } ++} ++ + /* For an extension type which OpenSSL does not recognize, attempt to + * parse the extension type as a primitive string. This will fail for + * any structured extension type per the docs. Returns non-zero on +diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h +index a5ede6e..80e1e8e 100644 +--- a/modules/ssl/ssl_private.h ++++ b/modules/ssl/ssl_private.h +@@ -974,6 +974,10 @@ void ssl_var_log_config_register(apr_pool_t *p); + * allocating from 'p': */ + void modssl_var_extract_dns(apr_table_t *t, SSL *ssl, apr_pool_t *p); + ++/* Extract SSL_*_SAN_* variables (subjectAltName entries) into table 't' ++ * from SSL object 'ssl', allocating from 'p'. */ ++void modssl_var_extract_san_entries(apr_table_t *t, SSL *ssl, apr_pool_t *p); ++ + #ifndef OPENSSL_NO_OCSP + /* Perform OCSP validation of the current cert in the given context. + * Returns non-zero on success or zero on failure. On failure, the +diff --git a/modules/ssl/ssl_util_ssl.c b/modules/ssl/ssl_util_ssl.c +index 588ceba..09a9877 100644 +--- a/modules/ssl/ssl_util_ssl.c ++++ b/modules/ssl/ssl_util_ssl.c +@@ -236,22 +236,32 @@ BOOL SSL_X509_getBC(X509 *cert, int *ca, int *pathlen) + return TRUE; + } + +-/* convert a NAME_ENTRY to UTF8 string */ +-char *SSL_X509_NAME_ENTRY_to_string(apr_pool_t *p, X509_NAME_ENTRY *xsne) ++/* convert an ASN.1 string to a UTF-8 string (escaping control characters) */ ++char *SSL_ASN1_STRING_to_utf8(apr_pool_t *p, ASN1_STRING *asn1str) + { + char *result = NULL; +- BIO* bio; ++ BIO *bio; + int len; + + if ((bio = BIO_new(BIO_s_mem())) == NULL) + return NULL; +- ASN1_STRING_print_ex(bio, X509_NAME_ENTRY_get_data(xsne), +- ASN1_STRFLGS_ESC_CTRL|ASN1_STRFLGS_UTF8_CONVERT); ++ ++ ASN1_STRING_print_ex(bio, asn1str, ASN1_STRFLGS_ESC_CTRL| ++ ASN1_STRFLGS_UTF8_CONVERT); + len = BIO_pending(bio); +- result = apr_palloc(p, len+1); +- len = BIO_read(bio, result, len); +- result[len] = NUL; ++ if (len > 0) { ++ result = apr_palloc(p, len+1); ++ len = BIO_read(bio, result, len); ++ result[len] = NUL; ++ } + BIO_free(bio); ++ return result; ++} ++ ++/* convert a NAME_ENTRY to UTF8 string */ ++char *SSL_X509_NAME_ENTRY_to_string(apr_pool_t *p, X509_NAME_ENTRY *xsne) ++{ ++ char *result = SSL_ASN1_STRING_to_utf8(p, X509_NAME_ENTRY_get_data(xsne)); + ap_xlate_proto_from_ascii(result, len); + return result; + } +@@ -288,51 +298,123 @@ char *SSL_X509_NAME_to_string(apr_pool_t *p, X509_NAME *dn, int maxlen) + return result; + } + +-/* return an array of (RFC 6125 coined) DNS-IDs and CN-IDs in a certificate */ +-BOOL SSL_X509_getIDs(apr_pool_t *p, X509 *x509, apr_array_header_t **ids) ++static void parse_otherName_value(apr_pool_t *p, ASN1_TYPE *value, ++ const char *onf, apr_array_header_t **entries) ++{ ++ const char *str; ++ int nid = onf ? OBJ_txt2nid(onf) : NID_undef; ++ ++ if (!value || (nid == NID_undef) || !*entries) ++ return; ++ ++ /* ++ * Currently supported otherName forms (values for "onf"): ++ * "msUPN" (1.3.6.1.4.1.311.20.2.3): Microsoft User Principal Name ++ * "id-on-dnsSRV" (1.3.6.1.5.5.7.8.7): SRVName, as specified in RFC 4985 ++ */ ++ if ((nid == NID_ms_upn) && (value->type == V_ASN1_UTF8STRING) && ++ (str = SSL_ASN1_STRING_to_utf8(p, value->value.utf8string))) { ++ APR_ARRAY_PUSH(*entries, const char *) = str; ++ } else if (strEQ(onf, "id-on-dnsSRV") && ++ (value->type == V_ASN1_IA5STRING) && ++ (str = SSL_ASN1_STRING_to_utf8(p, value->value.ia5string))) { ++ APR_ARRAY_PUSH(*entries, const char *) = str; ++ } ++} ++ ++/* ++ * Return an array of subjectAltName entries of type "type". If idx is -1, ++ * return all entries of the given type, otherwise return an array consisting ++ * of the n-th occurrence of that type only. Currently supported types: ++ * GEN_EMAIL (rfc822Name) ++ * GEN_DNS (dNSName) ++ * GEN_OTHERNAME (requires the otherName form ["onf"] argument to be supplied, ++ * see parse_otherName_value for the currently supported forms) ++ */ ++BOOL SSL_X509_getSAN(apr_pool_t *p, X509 *x509, int type, const char *onf, ++ int idx, apr_array_header_t **entries) + { + STACK_OF(GENERAL_NAME) *names; +- BIO *bio; +- X509_NAME *subj; +- char **cpp; +- int i, n; ++ int nid = onf ? OBJ_txt2nid(onf) : NID_undef; + +- if (!x509 || !(*ids = apr_array_make(p, 0, sizeof(char *)))) { +- *ids = NULL; ++ if (!x509 || (type < GEN_OTHERNAME) || ++ ((type == GEN_OTHERNAME) && (nid == NID_undef)) || ++ (type > GEN_RID) || (idx < -1) || ++ !(*entries = apr_array_make(p, 0, sizeof(char *)))) { ++ *entries = NULL; + return FALSE; + } + +- /* First, the DNS-IDs (dNSName entries in the subjectAltName extension) */ +- if ((names = X509_get_ext_d2i(x509, NID_subject_alt_name, NULL, NULL)) && +- (bio = BIO_new(BIO_s_mem()))) { ++ if ((names = X509_get_ext_d2i(x509, NID_subject_alt_name, NULL, NULL))) { ++ int i, n = 0; + GENERAL_NAME *name; ++ const char *utf8str; + + for (i = 0; i < sk_GENERAL_NAME_num(names); i++) { + name = sk_GENERAL_NAME_value(names, i); +- if (name->type == GEN_DNS) { +- ASN1_STRING_print_ex(bio, name->d.ia5, ASN1_STRFLGS_ESC_CTRL| +- ASN1_STRFLGS_UTF8_CONVERT); +- n = BIO_pending(bio); +- if (n > 0) { +- cpp = (char **)apr_array_push(*ids); +- *cpp = apr_palloc(p, n+1); +- n = BIO_read(bio, *cpp, n); +- (*cpp)[n] = NUL; ++ ++ if (name->type != type) ++ continue; ++ ++ switch (type) { ++ case GEN_EMAIL: ++ case GEN_DNS: ++ if (((idx == -1) || (n == idx)) && ++ (utf8str = SSL_ASN1_STRING_to_utf8(p, name->d.ia5))) { ++ APR_ARRAY_PUSH(*entries, const char *) = utf8str; ++ } ++ n++; ++ break; ++ case GEN_OTHERNAME: ++ if (OBJ_obj2nid(name->d.otherName->type_id) == nid) { ++ if (((idx == -1) || (n == idx))) { ++ parse_otherName_value(p, name->d.otherName->value, ++ onf, entries); ++ } ++ n++; + } ++ break; ++ default: ++ /* ++ * Not implemented right now: ++ * GEN_X400 (x400Address) ++ * GEN_DIRNAME (directoryName) ++ * GEN_EDIPARTY (ediPartyName) ++ * GEN_URI (uniformResourceIdentifier) ++ * GEN_IPADD (iPAddress) ++ * GEN_RID (registeredID) ++ */ ++ break; + } ++ ++ if ((idx != -1) && (n > idx)) ++ break; + } +- BIO_free(bio); +- } + +- if (names) + sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); ++ } ++ ++ return apr_is_empty_array(*entries) ? FALSE : TRUE; ++} ++ ++/* return an array of (RFC 6125 coined) DNS-IDs and CN-IDs in a certificate */ ++BOOL SSL_X509_getIDs(apr_pool_t *p, X509 *x509, apr_array_header_t **ids) ++{ ++ X509_NAME *subj; ++ int i = -1; ++ ++ /* First, the DNS-IDs (dNSName entries in the subjectAltName extension) */ ++ if (!x509 || ++ (SSL_X509_getSAN(p, x509, GEN_DNS, NULL, -1, ids) == FALSE && !*ids)) { ++ *ids = NULL; ++ return FALSE; ++ } + + /* Second, the CN-IDs (commonName attributes in the subject DN) */ + subj = X509_get_subject_name(x509); +- i = -1; + while ((i = X509_NAME_get_index_by_NID(subj, NID_commonName, i)) != -1) { +- cpp = (char **)apr_array_push(*ids); +- *cpp = SSL_X509_NAME_ENTRY_to_string(p, X509_NAME_get_entry(subj, i)); ++ APR_ARRAY_PUSH(*ids, const char *) = ++ SSL_X509_NAME_ENTRY_to_string(p, X509_NAME_get_entry(subj, i)); + } + + return apr_is_empty_array(*ids) ? FALSE : TRUE; +diff --git a/modules/ssl/ssl_util_ssl.h b/modules/ssl/ssl_util_ssl.h +index 4b882db..be07ab7 100644 +--- a/modules/ssl/ssl_util_ssl.h ++++ b/modules/ssl/ssl_util_ssl.h +@@ -65,8 +65,10 @@ EVP_PKEY *SSL_read_PrivateKey(char *, EVP_PKEY **, pem_password_cb *, void *); + int SSL_smart_shutdown(SSL *ssl); + BOOL SSL_X509_isSGC(X509 *); + BOOL SSL_X509_getBC(X509 *, int *, int *); ++char *SSL_ASN1_STRING_to_utf8(apr_pool_t *, ASN1_STRING *); + char *SSL_X509_NAME_ENTRY_to_string(apr_pool_t *p, X509_NAME_ENTRY *xsne); + char *SSL_X509_NAME_to_string(apr_pool_t *, X509_NAME *, int); ++BOOL SSL_X509_getSAN(apr_pool_t *, X509 *, int, const char *, int, apr_array_header_t **); + BOOL SSL_X509_getIDs(apr_pool_t *, X509 *, apr_array_header_t **); + BOOL SSL_X509_match_name(apr_pool_t *, X509 *, const char *, BOOL, server_rec *); + BOOL SSL_X509_INFO_load_file(apr_pool_t *, STACK_OF(X509_INFO) *, const char *); diff --git a/SOURCES/httpd-ssl-pass-dialog b/SOURCES/httpd-ssl-pass-dialog new file mode 100755 index 0000000..1e850cd --- /dev/null +++ b/SOURCES/httpd-ssl-pass-dialog @@ -0,0 +1,3 @@ +#!/bin/sh + +exec /bin/systemd-ask-password "Enter SSL pass phrase for $1 ($2) : " diff --git a/SOURCES/httpd.conf b/SOURCES/httpd.conf new file mode 100644 index 0000000..a7af0dc --- /dev/null +++ b/SOURCES/httpd.conf @@ -0,0 +1,353 @@ +# +# This is the main Apache HTTP server configuration file. It contains the +# configuration directives that give the server its instructions. +# See for detailed information. +# In particular, see +# +# for a discussion of each configuration directive. +# +# Do NOT simply read the instructions in here without understanding +# what they do. They're here only as hints or reminders. If you are unsure +# consult the online docs. You have been warned. +# +# Configuration and logfile names: If the filenames you specify for many +# of the server's control files begin with "/" (or "drive:/" for Win32), the +# server will use that explicit path. If the filenames do *not* begin +# with "/", the value of ServerRoot is prepended -- so 'log/access_log' +# with ServerRoot set to '/www' will be interpreted by the +# server as '/www/log/access_log', where as '/log/access_log' will be +# interpreted as '/log/access_log'. + +# +# ServerRoot: The top of the directory tree under which the server's +# configuration, error, and log files are kept. +# +# Do not add a slash at the end of the directory path. If you point +# ServerRoot at a non-local disk, be sure to specify a local disk on the +# Mutex directive, if file-based mutexes are used. If you wish to share the +# same ServerRoot for multiple httpd daemons, you will need to change at +# least PidFile. +# +ServerRoot "/etc/httpd" + +# +# Listen: Allows you to bind Apache to specific IP addresses and/or +# ports, instead of the default. See also the +# directive. +# +# Change this to Listen on specific IP addresses as shown below to +# prevent Apache from glomming onto all bound IP addresses. +# +#Listen 12.34.56.78:80 +Listen 80 + +# +# Dynamic Shared Object (DSO) Support +# +# To be able to use the functionality of a module which was built as a DSO you +# have to place corresponding `LoadModule' lines at this location so the +# directives contained in it are actually available _before_ they are used. +# Statically compiled modules (those listed by `httpd -l') do not need +# to be loaded here. +# +# Example: +# LoadModule foo_module modules/mod_foo.so +# +Include conf.modules.d/*.conf + +# +# If you wish httpd to run as a different user or group, you must run +# httpd as root initially and it will switch. +# +# User/Group: The name (or #number) of the user/group to run httpd as. +# It is usually good practice to create a dedicated user and group for +# running httpd, as with most system services. +# +User apache +Group apache + +# 'Main' server configuration +# +# The directives in this section set up the values used by the 'main' +# server, which responds to any requests that aren't handled by a +# definition. These values also provide defaults for +# any containers you may define later in the file. +# +# All of these directives may appear inside containers, +# in which case these default settings will be overridden for the +# virtual host being defined. +# + +# +# ServerAdmin: Your address, where problems with the server should be +# e-mailed. This address appears on some server-generated pages, such +# as error documents. e.g. admin@your-domain.com +# +ServerAdmin root@localhost + +# +# ServerName gives the name and port that the server uses to identify itself. +# This can often be determined automatically, but we recommend you specify +# it explicitly to prevent problems during startup. +# +# If your host doesn't have a registered DNS name, enter its IP address here. +# +#ServerName www.example.com:80 + +# +# Deny access to the entirety of your server's filesystem. You must +# explicitly permit access to web content directories in other +# blocks below. +# + + AllowOverride none + Require all denied + + +# +# Note that from this point forward you must specifically allow +# particular features to be enabled - so if something's not working as +# you might expect, make sure that you have specifically enabled it +# below. +# + +# +# DocumentRoot: The directory out of which you will serve your +# documents. By default, all requests are taken from this directory, but +# symbolic links and aliases may be used to point to other locations. +# +DocumentRoot "/var/www/html" + +# +# Relax access to content within /var/www. +# + + AllowOverride None + # Allow open access: + Require all granted + + +# Further relax access to the default document root: + + # + # Possible values for the Options directive are "None", "All", + # or any combination of: + # Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews + # + # Note that "MultiViews" must be named *explicitly* --- "Options All" + # doesn't give it to you. + # + # The Options directive is both complicated and important. Please see + # http://httpd.apache.org/docs/2.4/mod/core.html#options + # for more information. + # + Options Indexes FollowSymLinks + + # + # AllowOverride controls what directives may be placed in .htaccess files. + # It can be "All", "None", or any combination of the keywords: + # Options FileInfo AuthConfig Limit + # + AllowOverride None + + # + # Controls who can get stuff from this server. + # + Require all granted + + +# +# DirectoryIndex: sets the file that Apache will serve if a directory +# is requested. +# + + DirectoryIndex index.html + + +# +# The following lines prevent .htaccess and .htpasswd files from being +# viewed by Web clients. +# + + Require all denied + + +# +# ErrorLog: The location of the error log file. +# If you do not specify an ErrorLog directive within a +# container, error messages relating to that virtual host will be +# logged here. If you *do* define an error logfile for a +# container, that host's errors will be logged there and not here. +# +ErrorLog "logs/error_log" + +# +# LogLevel: Control the number of messages logged to the error_log. +# Possible values include: debug, info, notice, warn, error, crit, +# alert, emerg. +# +LogLevel warn + + + # + # The following directives define some format nicknames for use with + # a CustomLog directive (see below). + # + LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined + LogFormat "%h %l %u %t \"%r\" %>s %b" common + + + # You need to enable mod_logio.c to use %I and %O + LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio + + + # + # The location and format of the access logfile (Common Logfile Format). + # If you do not define any access logfiles within a + # container, they will be logged here. Contrariwise, if you *do* + # define per- access logfiles, transactions will be + # logged therein and *not* in this file. + # + #CustomLog "logs/access_log" common + + # + # If you prefer a logfile with access, agent, and referer information + # (Combined Logfile Format) you can use the following directive. + # + CustomLog "logs/access_log" combined + + + + # + # Redirect: Allows you to tell clients about documents that used to + # exist in your server's namespace, but do not anymore. The client + # will make a new request for the document at its new location. + # Example: + # Redirect permanent /foo http://www.example.com/bar + + # + # Alias: Maps web paths into filesystem paths and is used to + # access content that does not live under the DocumentRoot. + # Example: + # Alias /webpath /full/filesystem/path + # + # If you include a trailing / on /webpath then the server will + # require it to be present in the URL. You will also likely + # need to provide a section to allow access to + # the filesystem path. + + # + # ScriptAlias: This controls which directories contain server scripts. + # ScriptAliases are essentially the same as Aliases, except that + # documents in the target directory are treated as applications and + # run by the server when requested rather than as documents sent to the + # client. The same rules about trailing "/" apply to ScriptAlias + # directives as to Alias. + # + ScriptAlias /cgi-bin/ "/var/www/cgi-bin/" + + + +# +# "/var/www/cgi-bin" should be changed to whatever your ScriptAliased +# CGI directory exists, if you have that configured. +# + + AllowOverride None + Options None + Require all granted + + + + # + # TypesConfig points to the file containing the list of mappings from + # filename extension to MIME-type. + # + TypesConfig /etc/mime.types + + # + # AddType allows you to add to or override the MIME configuration + # file specified in TypesConfig for specific file types. + # + #AddType application/x-gzip .tgz + # + # AddEncoding allows you to have certain browsers uncompress + # information on the fly. Note: Not all browsers support this. + # + #AddEncoding x-compress .Z + #AddEncoding x-gzip .gz .tgz + # + # If the AddEncoding directives above are commented-out, then you + # probably should define those extensions to indicate media types: + # + AddType application/x-compress .Z + AddType application/x-gzip .gz .tgz + + # + # AddHandler allows you to map certain file extensions to "handlers": + # actions unrelated to filetype. These can be either built into the server + # or added with the Action directive (see below) + # + # To use CGI scripts outside of ScriptAliased directories: + # (You will also need to add "ExecCGI" to the "Options" directive.) + # + #AddHandler cgi-script .cgi + + # For type maps (negotiated resources): + #AddHandler type-map var + + # + # Filters allow you to process content before it is sent to the client. + # + # To parse .shtml files for server-side includes (SSI): + # (You will also need to add "Includes" to the "Options" directive.) + # + AddType text/html .shtml + AddOutputFilter INCLUDES .shtml + + +# +# Specify a default charset for all content served; this enables +# interpretation of all content as UTF-8 by default. To use the +# default browser choice (ISO-8859-1), or to allow the META tags +# in HTML content to override this choice, comment out this +# directive: +# +AddDefaultCharset UTF-8 + + + # + # The mod_mime_magic module allows the server to use various hints from the + # contents of the file itself to determine its type. The MIMEMagicFile + # directive tells the module where the hint definitions are located. + # + MIMEMagicFile conf/magic + + +# +# Customizable error responses come in three flavors: +# 1) plain text 2) local redirects 3) external redirects +# +# Some examples: +#ErrorDocument 500 "The server made a boo boo." +#ErrorDocument 404 /missing.html +#ErrorDocument 404 "/cgi-bin/missing_handler.pl" +#ErrorDocument 402 http://www.example.com/subscription_info.html +# + +# +# EnableMMAP and EnableSendfile: On systems that support it, +# memory-mapping or the sendfile syscall may be used to deliver +# files. This usually improves server performance, but must +# be turned off when serving from networked-mounted +# filesystems or if support for these functions is otherwise +# broken on your system. +# Defaults if commented: EnableMMAP On, EnableSendfile Off +# +#EnableMMAP off +EnableSendfile on + +# Supplemental configuration +# +# Load config files in the "/etc/httpd/conf.d" directory, if any. +IncludeOptional conf.d/*.conf diff --git a/SOURCES/httpd.logrotate b/SOURCES/httpd.logrotate new file mode 100644 index 0000000..28c9730 --- /dev/null +++ b/SOURCES/httpd.logrotate @@ -0,0 +1,9 @@ +/var/log/httpd/*log { + missingok + notifempty + sharedscripts + delaycompress + postrotate + /bin/systemctl reload httpd.service > /dev/null 2>/dev/null || true + endscript +} diff --git a/SOURCES/httpd.service b/SOURCES/httpd.service new file mode 100644 index 0000000..e5538ee --- /dev/null +++ b/SOURCES/httpd.service @@ -0,0 +1,22 @@ +[Unit] +Description=The Apache HTTP Server +After=network.target remote-fs.target nss-lookup.target +Documentation=man:httpd(8) +Documentation=man:apachectl(8) + +[Service] +Type=notify +EnvironmentFile=/etc/sysconfig/httpd +ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND +ExecReload=/usr/sbin/httpd $OPTIONS -k graceful +ExecStop=/bin/kill -WINCH ${MAINPID} +# We want systemd to give httpd some time to finish gracefully, but still want +# it to kill httpd after TimeoutStopSec if something went wrong during the +# graceful stop. Normally, Systemd sends SIGTERM signal right after the +# ExecStop, which would kill httpd. We are sending useless SIGCONT here to give +# httpd time to finish. +KillSignal=SIGCONT +PrivateTmp=true + +[Install] +WantedBy=multi-user.target diff --git a/SOURCES/httpd.sysconf b/SOURCES/httpd.sysconf new file mode 100644 index 0000000..1b38411 --- /dev/null +++ b/SOURCES/httpd.sysconf @@ -0,0 +1,25 @@ +# +# This file can be used to set additional environment variables for +# the httpd process, or pass additional options to the httpd +# executable. +# +# Note: With previous versions of httpd, the MPM could be changed by +# editing an "HTTPD" variable here. With the current version, that +# variable is now ignored. The MPM is a loadable module, and the +# choice of MPM can be changed by editing the configuration file +# /etc/httpd/conf.modules.d/00-mpm.conf. +# + +# +# To pass additional options (for instance, -D definitions) to the +# httpd binary at startup, set OPTIONS here. +# +#OPTIONS= + +# +# This setting ensures the httpd process is started in the "C" locale +# by default. (Some modules will not behave correctly if +# case-sensitive string comparisons are performed in a different +# locale.) +# +LANG=C diff --git a/SOURCES/httpd.tmpfiles b/SOURCES/httpd.tmpfiles new file mode 100644 index 0000000..f148886 --- /dev/null +++ b/SOURCES/httpd.tmpfiles @@ -0,0 +1,2 @@ +d /run/httpd 710 root apache +d /run/httpd/htcacheclean 700 apache apache diff --git a/SOURCES/manual.conf b/SOURCES/manual.conf new file mode 100644 index 0000000..cf626ac --- /dev/null +++ b/SOURCES/manual.conf @@ -0,0 +1,13 @@ +# +# This configuration file allows the manual to be accessed at +# http://localhost/manual/ +# +Alias /manual /usr/share/httpd/manual + + + Options Indexes + AllowOverride None + Require all granted + + RedirectMatch 301 ^/manual/(?:de|en|fr|ja|ko|ru)(/.*)$ "/manual$1" + diff --git a/SOURCES/ssl.conf b/SOURCES/ssl.conf new file mode 100644 index 0000000..5283a93 --- /dev/null +++ b/SOURCES/ssl.conf @@ -0,0 +1,217 @@ +# +# When we also provide SSL we have to listen to the +# the HTTPS port in addition. +# +Listen 443 https + +## +## SSL Global Context +## +## All SSL configuration in this context applies both to +## the main server and all SSL-enabled virtual hosts. +## + +# Pass Phrase Dialog: +# Configure the pass phrase gathering process. +# The filtering dialog program (`builtin' is a internal +# terminal dialog) has to provide the pass phrase on stdout. +SSLPassPhraseDialog exec:/usr/libexec/httpd-ssl-pass-dialog + +# Inter-Process Session Cache: +# Configure the SSL Session Cache: First the mechanism +# to use and second the expiring timeout (in seconds). +SSLSessionCache shmcb:/run/httpd/sslcache(512000) +SSLSessionCacheTimeout 300 + +# Pseudo Random Number Generator (PRNG): +# Configure one or more sources to seed the PRNG of the +# SSL library. The seed data should be of good random quality. +# WARNING! On some platforms /dev/random blocks if not enough entropy +# is available. This means you then cannot use the /dev/random device +# because it would lead to very long connection times (as long as +# it requires to make more entropy available). But usually those +# platforms additionally provide a /dev/urandom device which doesn't +# block. So, if available, use this one instead. Read the mod_ssl User +# Manual for more details. +SSLRandomSeed startup file:/dev/urandom 256 +SSLRandomSeed connect builtin +#SSLRandomSeed startup file:/dev/random 512 +#SSLRandomSeed connect file:/dev/random 512 +#SSLRandomSeed connect file:/dev/urandom 512 + +# +# Use "SSLCryptoDevice" to enable any supported hardware +# accelerators. Use "openssl engine -v" to list supported +# engine names. NOTE: If you enable an accelerator and the +# server does not start, consult the error logs and ensure +# your accelerator is functioning properly. +# +SSLCryptoDevice builtin +#SSLCryptoDevice ubsec + +## +## SSL Virtual Host Context +## + + + +# General setup for the virtual host, inherited from global configuration +#DocumentRoot "/var/www/html" +#ServerName www.example.com:443 + +# Use separate log files for the SSL virtual host; note that LogLevel +# is not inherited from httpd.conf. +ErrorLog logs/ssl_error_log +TransferLog logs/ssl_access_log +LogLevel warn + +# SSL Engine Switch: +# Enable/Disable SSL for this virtual host. +SSLEngine on + +# SSL Protocol support: +# List the enable protocol levels with which clients will be able to +# connect. Disable SSLv2 access by default: +SSLProtocol all -SSLv2 -SSLv3 + +# SSL Cipher Suite: +# List the ciphers that the client is permitted to negotiate. +# See the mod_ssl documentation for a complete list. +SSLCipherSuite HIGH:3DES:!aNULL:!MD5:!SEED:!IDEA + +# Speed-optimized SSL Cipher configuration: +# If speed is your main concern (on busy HTTPS servers e.g.), +# you might want to force clients to specific, performance +# optimized ciphers. In this case, prepend those ciphers +# to the SSLCipherSuite list, and enable SSLHonorCipherOrder. +# Caveat: by giving precedence to RC4-SHA and AES128-SHA +# (as in the example below), most connections will no longer +# have perfect forward secrecy - if the server's key is +# compromised, captures of past or future traffic must be +# considered compromised, too. +#SSLCipherSuite RC4-SHA:AES128-SHA:HIGH:MEDIUM:!aNULL:!MD5 +#SSLHonorCipherOrder on + +# Server Certificate: +# Point SSLCertificateFile at a PEM encoded certificate. If +# the certificate is encrypted, then you will be prompted for a +# pass phrase. Note that a kill -HUP will prompt again. A new +# certificate can be generated using the genkey(1) command. +SSLCertificateFile /etc/pki/tls/certs/localhost.crt + +# Server Private Key: +# If the key is not combined with the certificate, use this +# directive to point at the key file. Keep in mind that if +# you've both a RSA and a DSA private key you can configure +# both in parallel (to also allow the use of DSA ciphers, etc.) +SSLCertificateKeyFile /etc/pki/tls/private/localhost.key + +# Server Certificate Chain: +# Point SSLCertificateChainFile at a file containing the +# concatenation of PEM encoded CA certificates which form the +# certificate chain for the server certificate. Alternatively +# the referenced file can be the same as SSLCertificateFile +# when the CA certificates are directly appended to the server +# certificate for convinience. +#SSLCertificateChainFile /etc/pki/tls/certs/server-chain.crt + +# Certificate Authority (CA): +# Set the CA certificate verification path where to find CA +# certificates for client authentication or alternatively one +# huge file containing all of them (file must be PEM encoded) +#SSLCACertificateFile /etc/pki/tls/certs/ca-bundle.crt + +# Client Authentication (Type): +# Client certificate verification type and depth. Types are +# none, optional, require and optional_no_ca. Depth is a +# number which specifies how deeply to verify the certificate +# issuer chain before deciding the certificate is not valid. +#SSLVerifyClient require +#SSLVerifyDepth 10 + +# Access Control: +# With SSLRequire you can do per-directory access control based +# on arbitrary complex boolean expressions containing server +# variable checks and other lookup directives. The syntax is a +# mixture between C and Perl. See the mod_ssl documentation +# for more details. +# +#SSLRequire ( %{SSL_CIPHER} !~ m/^(EXP|NULL)/ \ +# and %{SSL_CLIENT_S_DN_O} eq "Snake Oil, Ltd." \ +# and %{SSL_CLIENT_S_DN_OU} in {"Staff", "CA", "Dev"} \ +# and %{TIME_WDAY} >= 1 and %{TIME_WDAY} <= 5 \ +# and %{TIME_HOUR} >= 8 and %{TIME_HOUR} <= 20 ) \ +# or %{REMOTE_ADDR} =~ m/^192\.76\.162\.[0-9]+$/ +# + +# SSL Engine Options: +# Set various options for the SSL engine. +# o FakeBasicAuth: +# Translate the client X.509 into a Basic Authorisation. This means that +# the standard Auth/DBMAuth methods can be used for access control. The +# user name is the `one line' version of the client's X.509 certificate. +# Note that no password is obtained from the user. Every entry in the user +# file needs this password: `xxj31ZMTZzkVA'. +# o ExportCertData: +# This exports two additional environment variables: SSL_CLIENT_CERT and +# SSL_SERVER_CERT. These contain the PEM-encoded certificates of the +# server (always existing) and the client (only existing when client +# authentication is used). This can be used to import the certificates +# into CGI scripts. +# o StdEnvVars: +# This exports the standard SSL/TLS related `SSL_*' environment variables. +# Per default this exportation is switched off for performance reasons, +# because the extraction step is an expensive operation and is usually +# useless for serving static content. So one usually enables the +# exportation for CGI and SSI requests only. +# o StrictRequire: +# This denies access when "SSLRequireSSL" or "SSLRequire" applied even +# under a "Satisfy any" situation, i.e. when it applies access is denied +# and no other module can change it. +# o OptRenegotiate: +# This enables optimized SSL connection renegotiation handling when SSL +# directives are used in per-directory context. +#SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire + + SSLOptions +StdEnvVars + + + SSLOptions +StdEnvVars + + +# SSL Protocol Adjustments: +# The safe and default but still SSL/TLS standard compliant shutdown +# approach is that mod_ssl sends the close notify alert but doesn't wait for +# the close notify alert from client. When you need a different shutdown +# approach you can use one of the following variables: +# o ssl-unclean-shutdown: +# This forces an unclean shutdown when the connection is closed, i.e. no +# SSL close notify alert is send or allowed to received. This violates +# the SSL/TLS standard but is needed for some brain-dead browsers. Use +# this when you receive I/O errors because of the standard approach where +# mod_ssl sends the close notify alert. +# o ssl-accurate-shutdown: +# This forces an accurate shutdown when the connection is closed, i.e. a +# SSL close notify alert is send and mod_ssl waits for the close notify +# alert of the client. This is 100% SSL/TLS standard compliant, but in +# practice often causes hanging connections with brain-dead browsers. Use +# this only for browsers where you know that their SSL implementation +# works correctly. +# Notice: Most problems of broken clients are also related to the HTTP +# keep-alive facility, so you usually additionally want to disable +# keep-alive for those clients, too. Use variable "nokeepalive" for this. +# Similarly, one has to force some clients to use HTTP/1.0 to workaround +# their broken HTTP/1.1 implementation. Use variables "downgrade-1.0" and +# "force-response-1.0" for this. +BrowserMatch "MSIE [2-5]" \ + nokeepalive ssl-unclean-shutdown \ + downgrade-1.0 force-response-1.0 + +# Per-Server Logging: +# The home of a custom SSL log file. Use this when you want a +# compact non-error SSL logfile on a virtual host basis. +CustomLog logs/ssl_request_log \ + "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b" + + + diff --git a/SOURCES/userdir.conf b/SOURCES/userdir.conf new file mode 100644 index 0000000..b5d7a49 --- /dev/null +++ b/SOURCES/userdir.conf @@ -0,0 +1,36 @@ +# +# UserDir: The name of the directory that is appended onto a user's home +# directory if a ~user request is received. +# +# The path to the end user account 'public_html' directory must be +# accessible to the webserver userid. This usually means that ~userid +# must have permissions of 711, ~userid/public_html must have permissions +# of 755, and documents contained therein must be world-readable. +# Otherwise, the client will only receive a "403 Forbidden" message. +# + + # + # UserDir is disabled by default since it can confirm the presence + # of a username on the system (depending on home directory + # permissions). + # + UserDir disabled + + # + # To enable requests to /~user/ to serve the user's public_html + # directory, remove the "UserDir disabled" line above, and uncomment + # the following line instead: + # + #UserDir public_html + + +# +# Control access to UserDir directories. The following is an example +# for a site where these directories are restricted to read-only. +# + + AllowOverride FileInfo AuthConfig Limit Indexes + Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec + Require method GET POST OPTIONS + + diff --git a/SOURCES/welcome.conf b/SOURCES/welcome.conf new file mode 100644 index 0000000..c1b6c11 --- /dev/null +++ b/SOURCES/welcome.conf @@ -0,0 +1,22 @@ +# +# This configuration file enables the default "Welcome" page if there +# is no default index page present for the root URL. To disable the +# Welcome page, comment out all the lines below. +# +# NOTE: if this file is removed, it will be restored on upgrades. +# + + Options -Indexes + ErrorDocument 403 /.noindex.html + + + + AllowOverride None + Require all granted + + +Alias /.noindex.html /usr/share/httpd/noindex/index.html +Alias /noindex/css/bootstrap.min.css /usr/share/httpd/noindex/css/bootstrap.min.css +Alias /noindex/css/open-sans.css /usr/share/httpd/noindex/css/open-sans.css +Alias /images/apache_pb.gif /usr/share/httpd/noindex/images/apache_pb.gif +Alias /images/poweredby.png /usr/share/httpd/noindex/images/poweredby.png diff --git a/SPECS/httpd.spec b/SPECS/httpd.spec new file mode 100644 index 0000000..94d3eec --- /dev/null +++ b/SPECS/httpd.spec @@ -0,0 +1,1534 @@ +%define contentdir %{_datadir}/httpd +%define docroot /var/www +%define suexec_caller apache +%define mmn 20120211 +%define oldmmnisa %{mmn}-%{__isa_name}-%{__isa_bits} +%define mmnisa %{mmn}%{__isa_name}%{__isa_bits} +%define vstring PowerEL + +# Drop automatic provides for module DSOs +%{?filter_setup: +%filter_provides_in %{_libdir}/httpd/modules/.*\.so$ +%filter_setup +} + +Summary: Apache HTTP Server +Name: httpd +Version: 2.4.6 +Release: 80%{?dist} +URL: http://httpd.apache.org/ +Source0: http://www.apache.org/dist/httpd/httpd-%{version}.tar.bz2 +Source1: centos-noindex.tar.gz +Source2: httpd.logrotate +Source3: httpd.sysconf +Source4: httpd-ssl-pass-dialog +Source5: httpd.tmpfiles +Source6: httpd.service +Source7: action-graceful.sh +Source8: action-configtest.sh +Source10: httpd.conf +Source11: 00-base.conf +Source12: 00-mpm.conf +Source13: 00-lua.conf +Source14: 01-cgi.conf +Source15: 00-dav.conf +Source16: 00-proxy.conf +Source17: 00-ssl.conf +Source18: 01-ldap.conf +Source19: 00-proxyhtml.conf +Source20: userdir.conf +Source21: ssl.conf +Source22: welcome.conf +Source23: manual.conf +Source24: 00-systemd.conf +Source25: 01-session.conf +# Documentation +Source30: README.confd +Source40: htcacheclean.service +Source41: htcacheclean.sysconf +# build/scripts patches +Patch1: httpd-2.4.1-apctl.patch +Patch2: httpd-2.4.3-apxs.patch +Patch3: httpd-2.4.1-deplibs.patch +Patch5: httpd-2.4.3-layout.patch +Patch6: httpd-2.4.3-apctl-systemd.patch +# Features/functional changes +Patch21: httpd-2.4.6-full-release.patch +Patch23: httpd-2.4.4-export.patch +Patch24: httpd-2.4.1-corelimit.patch +Patch25: httpd-2.4.1-selinux.patch +Patch26: httpd-2.4.4-r1337344+.patch +Patch27: httpd-2.4.2-icons.patch +Patch28: httpd-2.4.6-r1332643+.patch +Patch29: httpd-2.4.3-mod_systemd.patch +Patch30: httpd-2.4.4-cachehardmax.patch +Patch31: httpd-2.4.6-sslmultiproxy.patch +Patch32: httpd-2.4.6-r1537535.patch +Patch33: httpd-2.4.6-r1542327.patch +Patch34: httpd-2.4.6-ssl-large-keys.patch +Patch35: httpd-2.4.6-pre_htaccess.patch +Patch36: httpd-2.4.6-r1573626.patch +Patch37: httpd-2.4.6-uds.patch +Patch38: httpd-2.4.6-upn.patch +Patch39: httpd-2.4.6-r1664565.patch +# Bug fixes +Patch51: httpd-2.4.3-sslsninotreq.patch +Patch55: httpd-2.4.4-malformed-host.patch +Patch56: httpd-2.4.4-mod_unique_id.patch +Patch57: httpd-2.4.6-ldaprefer.patch +Patch58: httpd-2.4.6-r1507681+.patch +Patch59: httpd-2.4.6-r1556473.patch +Patch60: httpd-2.4.6-r1553540.patch +Patch61: httpd-2.4.6-rewrite-clientaddr.patch +Patch62: httpd-2.4.6-ab-overflow.patch +Patch63: httpd-2.4.6-sigint.patch +Patch64: httpd-2.4.6-ssl-ecdh-auto.patch +Patch65: httpd-2.4.6-r1556818.patch +Patch66: httpd-2.4.6-r1618851.patch +Patch67: httpd-2.4.6-r1526189.patch +Patch68: httpd-2.4.6-r1663647.patch +Patch69: httpd-2.4.6-r1569006.patch +Patch70: httpd-2.4.6-r1506474.patch +Patch71: httpd-2.4.6-bomb.patch +Patch72: httpd-2.4.6-r1604460.patch +Patch73: httpd-2.4.6-r1624349.patch +Patch74: httpd-2.4.6-ap-ipv6.patch +Patch75: httpd-2.4.6-r1530280.patch +Patch76: httpd-2.4.6-r1633085.patch +Patch78: httpd-2.4.6-ssl-error-free.patch +Patch79: httpd-2.4.6-r1528556.patch +Patch80: httpd-2.4.6-r1594625.patch +Patch81: httpd-2.4.6-r1674222.patch +Patch82: httpd-2.4.6-apachectl-httpd-env.patch +Patch83: httpd-2.4.6-rewrite-dir.patch +Patch84: httpd-2.4.6-r1420184.patch +Patch85: httpd-2.4.6-r1524368.patch +Patch86: httpd-2.4.6-r1528958.patch +Patch87: httpd-2.4.6-r1651083.patch +Patch88: httpd-2.4.6-r1688399.patch +Patch89: httpd-2.4.6-r1527509.patch +Patch90: httpd-2.4.6-apachectl-status.patch +Patch91: httpd-2.4.6-r1650655.patch +Patch92: httpd-2.4.6-r1533448.patch +Patch93: httpd-2.4.6-r1610013.patch +Patch94: httpd-2.4.6-r1705528.patch +Patch95: httpd-2.4.6-r1684462.patch +Patch96: httpd-2.4.6-r1650677.patch +Patch97: httpd-2.4.6-r1621601.patch +Patch98: httpd-2.4.6-r1610396.patch +Patch99: httpd-2.4.6-rotatelog-timezone.patch +Patch100: httpd-2.4.6-ab-ssl-error.patch +Patch101: httpd-2.4.6-r1723522.patch +Patch102: httpd-2.4.6-r1681107.patch +Patch103: httpd-2.4.6-dhparams-free.patch +Patch104: httpd-2.4.6-r1651658.patch +Patch105: httpd-2.4.6-r1560093.patch +Patch106: httpd-2.4.6-r1748212.patch +Patch107: httpd-2.4.6-r1570327.patch +Patch108: httpd-2.4.6-r1631119.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1406184 +Patch109: httpd-2.4.6-r1593002.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1389535 +Patch110: httpd-2.4.6-r1662640.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1348019 +Patch111: httpd-2.4.6-r1348019.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1396197 +Patch112: httpd-2.4.6-r1587053.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1376835 +Patch113: httpd-2.4.6-mpm-segfault.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1372692 +Patch114: httpd-2.4.6-r1681114.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1371876 +Patch115: httpd-2.4.6-r1775832.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1353740 +Patch116: httpd-2.4.6-r1726019.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1364604 +Patch117: httpd-2.4.6-r1683112.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1378946 +Patch118: httpd-2.4.6-r1651653.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1414258 +Patch119: httpd-2.4.6-r1634529.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1397241 +Patch120: httpd-2.4.6-r1738878.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1445885 +Patch121: httpd-2.4.6-http-protocol-options-define.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1332242 +Patch122: httpd-2.4.6-statements-comment.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1451333 +Patch123: httpd-2.4.6-rotatelogs-zombie.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1368491 +Patch124: httpd-2.4.6-mod_authz_dbd-missing-query.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1288395 +Patch125: httpd-2.4.6-r1668532.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1499253 +Patch126: httpd-2.4.6-r1681289.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1430640 +Patch127: httpd-2.4.6-r1805099.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1448892 +Patch128: httpd-2.4.6-r1811831.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1464406 +Patch129: httpd-2.4.6-r1811746.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1440590 +Patch130: httpd-2.4.6-r1811976.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1506392 +Patch131: httpd-2.4.6-r1650310.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1557785 +Patch132: httpd-2.4.6-r1530999.patch + +# Security fixes +Patch200: httpd-2.4.6-CVE-2013-6438.patch +Patch201: httpd-2.4.6-CVE-2014-0098.patch +Patch202: httpd-2.4.6-CVE-2014-0231.patch +Patch203: httpd-2.4.6-CVE-2014-0117.patch +Patch204: httpd-2.4.6-CVE-2014-0118.patch +Patch205: httpd-2.4.6-CVE-2014-0226.patch +Patch206: httpd-2.4.6-CVE-2013-4352.patch +Patch207: httpd-2.4.6-CVE-2013-5704.patch +Patch208: httpd-2.4.6-CVE-2014-3581.patch +Patch209: httpd-2.4.6-CVE-2015-3185.patch +Patch210: httpd-2.4.6-CVE-2015-3183.patch +Patch211: httpd-2.4.6-CVE-2016-5387.patch +Patch212: httpd-2.4.6-CVE-2016-8743.patch +Patch213: httpd-2.4.6-CVE-2016-0736.patch +Patch214: httpd-2.4.6-CVE-2016-2161.patch +Patch215: httpd-2.4.6-CVE-2017-3167.patch +Patch216: httpd-2.4.6-CVE-2017-3169.patch +Patch217: httpd-2.4.6-CVE-2017-7668.patch +Patch218: httpd-2.4.6-CVE-2017-7679.patch +Patch219: httpd-2.4.6-CVE-2017-9788.patch +Patch220: httpd-2.4.6-CVE-2017-9798.patch + +License: ASL 2.0 +Group: System Environment/Daemons +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root +BuildRequires: autoconf, perl, pkgconfig, findutils, xmlto +BuildRequires: zlib-devel, libselinux-devel, lua-devel +BuildRequires: apr-devel >= 1.4.0, apr-util-devel >= 1.2.0, pcre-devel >= 5.0 +BuildRequires: systemd-devel +Requires: /etc/mime.types, system-logos >= 7.92.1-1 +Obsoletes: httpd-suexec +Provides: webserver +Provides: mod_dav = %{version}-%{release}, httpd-suexec = %{version}-%{release} +Provides: httpd-mmn = %{mmn}, httpd-mmn = %{mmnisa}, httpd-mmn = %{oldmmnisa} +Requires: httpd-tools = %{version}-%{release} +Requires(pre): /usr/sbin/useradd +Requires(pre): /usr/sbin/groupadd +Requires(preun): systemd-units +Requires(postun): systemd-units +Requires(post): systemd-units + +%description +The Apache HTTP Server is a powerful, efficient, and extensible +web server. + +%package devel +Group: Development/Libraries +Summary: Development interfaces for the Apache HTTP server +Obsoletes: secureweb-devel, apache-devel, stronghold-apache-devel +Requires: apr-devel, apr-util-devel, pkgconfig +Requires: httpd = %{version}-%{release} + +%description devel +The httpd-devel package contains the APXS binary and other files +that you need to build Dynamic Shared Objects (DSOs) for the +Apache HTTP Server. + +If you are installing the Apache HTTP server and you want to be +able to compile or develop additional modules for Apache, you need +to install this package. + +%package manual +Group: Documentation +Summary: Documentation for the Apache HTTP server +Requires: httpd = %{version}-%{release} +Obsoletes: secureweb-manual, apache-manual +BuildArch: noarch + +%description manual +The httpd-manual package contains the complete manual and +reference guide for the Apache HTTP server. The information can +also be found at http://httpd.apache.org/docs/2.2/. + +%package tools +Group: System Environment/Daemons +Summary: Tools for use with the Apache HTTP Server + +%description tools +The httpd-tools package contains tools which can be used with +the Apache HTTP Server. + +%package -n mod_ssl +Group: System Environment/Daemons +Summary: SSL/TLS module for the Apache HTTP Server +Epoch: 1 +BuildRequires: openssl-devel >= 1:1.0.1e-37 +Requires: openssl-libs >= 1:1.0.1e-37 +Requires(post): openssl, /bin/cat +Requires(pre): httpd +Requires: httpd = 0:%{version}-%{release}, httpd-mmn = %{mmnisa} +Obsoletes: stronghold-mod_ssl + +%description -n mod_ssl +The mod_ssl module provides strong cryptography for the Apache Web +server via the Secure Sockets Layer (SSL) and Transport Layer +Security (TLS) protocols. + +%package -n mod_proxy_html +Group: System Environment/Daemons +Summary: HTML and XML content filters for the Apache HTTP Server +Requires: httpd = 0:%{version}-%{release}, httpd-mmn = %{mmnisa} +BuildRequires: libxml2-devel +Epoch: 1 +Obsoletes: mod_proxy_html < 1:2.4.1-2 + +%description -n mod_proxy_html +The mod_proxy_html and mod_xml2enc modules provide filters which can +transform and modify HTML and XML content. + +%package -n mod_ldap +Group: System Environment/Daemons +Summary: LDAP authentication modules for the Apache HTTP Server +Requires: httpd = 0:%{version}-%{release}, httpd-mmn = %{mmnisa} +Requires: apr-util-ldap + +%description -n mod_ldap +The mod_ldap and mod_authnz_ldap modules add support for LDAP +authentication to the Apache HTTP Server. + +%package -n mod_session +Group: System Environment/Daemons +Summary: Session interface for the Apache HTTP Server +Requires: httpd = 0:%{version}-%{release}, httpd-mmn = %{mmnisa} + +%description -n mod_session +The mod_session module and associated backends provide an abstract +interface for storing and accessing per-user session data. + +%prep +%setup -q +%patch1 -p1 -b .apctl +%patch2 -p1 -b .apxs +%patch3 -p1 -b .deplibs +%patch5 -p1 -b .layout +%patch6 -p1 -b .apctlsystemd + +%patch21 -p1 -b .fullrelease +%patch23 -p1 -b .export +%patch24 -p1 -b .corelimit +%patch25 -p1 -b .selinux +%patch26 -p1 -b .r1337344+ +%patch27 -p1 -b .icons +%patch28 -p1 -b .r1332643+ +%patch29 -p1 -b .systemd +%patch30 -p1 -b .cachehardmax +%patch31 -p1 -b .sslmultiproxy +%patch32 -p1 -b .r1537535 +%patch33 -p1 -b .r1542327 +rm modules/ssl/ssl_engine_dh.c +%patch34 -p1 -b .ssllargekeys +%patch35 -p1 -b .prehtaccess +%patch36 -p1 -b .r1573626 +%patch37 -p1 -b .uds +%patch38 -p1 -b .upn +%patch39 -p1 -b .r1664565 + +%patch51 -p1 -b .sninotreq +%patch55 -p1 -b .malformedhost +%patch56 -p1 -b .uniqueid +%patch57 -p1 -b .ldaprefer +%patch58 -p1 -b .r1507681+ +%patch59 -p1 -b .r1556473 +%patch60 -p1 -b .r1553540 +%patch61 -p1 -b .clientaddr +%patch62 -p1 -b .aboverflow +%patch63 -p1 -b .sigint +%patch64 -p1 -b .sslecdhauto +%patch65 -p1 -b .r1556818 +%patch66 -p1 -b .r1618851 +%patch67 -p1 -b .r1526189 +%patch68 -p1 -b .r1663647 +%patch69 -p1 -b .1569006 +%patch70 -p1 -b .r1506474 +%patch71 -p1 -b .bomb +%patch72 -p1 -b .r1604460 +%patch73 -p1 -b .r1624349 +%patch74 -p1 -b .abipv6 +%patch75 -p1 -b .r1530280 +%patch76 -p1 -b .r1633085 +%patch78 -p1 -b .sslerrorfree +%patch79 -p1 -b .r1528556 +%patch80 -p1 -b .r1594625 +%patch81 -p1 -b .r1674222 +%patch82 -p1 -b .envhttpd +%patch83 -p1 -b .rewritedir +%patch84 -p1 -b .r1420184 +%patch85 -p1 -b .r1524368 +%patch86 -p1 -b .r1528958 +%patch87 -p1 -b .r1651083 +%patch88 -p1 -b .r1688399 +%patch89 -p1 -b .r1527509 +%patch90 -p1 -b .apachectlstatus +%patch91 -p1 -b .r1650655 +%patch92 -p1 -b .r1533448 +%patch93 -p1 -b .r1610013 +%patch94 -p1 -b .r1705528 +%patch95 -p1 -b .r1684462 +%patch96 -p1 -b .r1650677 +%patch97 -p1 -b .r1621601 +%patch98 -p1 -b .r1610396 +%patch99 -p1 -b .rotatelogtimezone +%patch100 -p1 -b .absslerror +%patch101 -p1 -b .r1723522 +%patch102 -p1 -b .r1681107 +%patch103 -p1 -b .dhparamsfree +%patch104 -p1 -b .r1651658 +%patch105 -p1 -b .r1560093 +%patch106 -p1 -b .r1748212 +%patch107 -p1 -b .r1570327 +%patch108 -p1 -b .r1631119 +%patch109 -p1 -b .r1593002 +%patch110 -p1 -b .r1662640 +%patch111 -p1 -b .r1348019 +%patch112 -p1 -b .r1587053 +%patch113 -p1 -b .mpmsegfault +%patch114 -p1 -b .r1681114 +%patch115 -p1 -b .r1371876 +%patch116 -p1 -b .r1726019 +%patch117 -p1 -b .r1683112 +%patch118 -p1 -b .r1651653 +%patch119 -p1 -b .r1634529 +%patch120 -p1 -b .r1738878 +%patch121 -p1 -b .httpprotdefine +%patch122 -p1 -b .statement-comment +%patch123 -p1 -b .logrotate-zombie +%patch124 -p1 -b .modauthzdbd-segfault +%patch125 -p1 -b .r1668532 +%patch126 -p1 -b .r1681289 +%patch127 -p1 -b .r1805099 +%patch128 -p1 -b .r1811831 +%patch129 -p1 -b .r1811746 +%patch130 -p1 -b .r1811976 +%patch131 -p1 -b .r1650310 +%patch132 -p1 -b .r1530999 + +%patch200 -p1 -b .cve6438 +%patch201 -p1 -b .cve0098 +%patch202 -p1 -b .cve0231 +%patch203 -p1 -b .cve0117 +%patch204 -p1 -b .cve0118 +%patch205 -p1 -b .cve0226 +%patch206 -p1 -b .cve4352 +%patch207 -p1 -b .cve5704 +%patch208 -p1 -b .cve3581 +%patch209 -p1 -b .cve3185 +%patch210 -p1 -b .cve3183 +%patch211 -p1 -b .cve5387 +%patch212 -p1 -b .cve8743 +%patch213 -p1 -b .cve0736 +%patch214 -p1 -b .cve2161 +%patch215 -p1 -b .cve3167 +%patch216 -p1 -b .cve3169 +%patch217 -p1 -b .cve7668 +%patch218 -p1 -b .cve7679 +%patch219 -p1 -b .cve9788 +%patch220 -p1 -b .cve9798 + +# Patch in the vendor string and the release string +sed -i '/^#define PLATFORM/s/Unix/%{vstring}/' os/unix/os.h +sed -i 's/@RELEASE@/%{release}/' server/core.c + +# Prevent use of setcap in "install-suexec-caps" target. +sed -i '/suexec/s,setcap ,echo Skipping setcap for ,' Makefile.in + +# Safety check: prevent build if defined MMN does not equal upstream MMN. +vmmn=`echo MODULE_MAGIC_NUMBER_MAJOR | cpp -include include/ap_mmn.h | sed -n '/^2/p'` +if test "x${vmmn}" != "x%{mmn}"; then + : Error: Upstream MMN is now ${vmmn}, packaged MMN is %{mmn} + : Update the mmn macro and rebuild. + exit 1 +fi + +: Building with MMN %{mmn}, MMN-ISA %{mmnisa} and vendor string '%{vstring}' + +%build +# forcibly prevent use of bundled apr, apr-util, pcre +rm -rf srclib/{apr,apr-util,pcre} + +# regenerate configure scripts +autoheader && autoconf || exit 1 + +# Before configure; fix location of build dir in generated apxs +%{__perl} -pi -e "s:\@exp_installbuilddir\@:%{_libdir}/httpd/build:g" \ + support/apxs.in + +export CFLAGS=$RPM_OPT_FLAGS +export LDFLAGS="-Wl,-z,relro,-z,now" + +%global _performance_build 1 + +# Hard-code path to links to avoid unnecessary builddep +export LYNX_PATH=/usr/bin/links + +# Build the daemon +%configure \ + --prefix=%{_sysconfdir}/httpd \ + --exec-prefix=%{_prefix} \ + --bindir=%{_bindir} \ + --sbindir=%{_sbindir} \ + --mandir=%{_mandir} \ + --libdir=%{_libdir} \ + --sysconfdir=%{_sysconfdir}/httpd/conf \ + --includedir=%{_includedir}/httpd \ + --libexecdir=%{_libdir}/httpd/modules \ + --datadir=%{contentdir} \ + --enable-layout=Fedora \ + --with-installbuilddir=%{_libdir}/httpd/build \ + --enable-mpms-shared=all \ + --with-apr=%{_prefix} --with-apr-util=%{_prefix} \ + --enable-suexec --with-suexec \ + --enable-suexec-capabilities \ + --with-suexec-caller=%{suexec_caller} \ + --with-suexec-docroot=%{docroot} \ + --without-suexec-logfile \ + --with-suexec-syslog \ + --with-suexec-bin=%{_sbindir}/suexec \ + --with-suexec-uidmin=500 --with-suexec-gidmin=100 \ + --enable-pie \ + --with-pcre \ + --enable-mods-shared=all \ + --enable-ssl --with-ssl --disable-distcache \ + --enable-proxy \ + --enable-cache \ + --enable-disk-cache \ + --enable-ldap --enable-authnz-ldap \ + --enable-cgid --enable-cgi \ + --enable-authn-anon --enable-authn-alias \ + --disable-imagemap \ + $* +make %{?_smp_mflags} + +%install +rm -rf $RPM_BUILD_ROOT + +make DESTDIR=$RPM_BUILD_ROOT install + +# Install systemd service files +mkdir -p $RPM_BUILD_ROOT%{_unitdir} +for s in httpd htcacheclean; do + install -p -m 644 $RPM_SOURCE_DIR/${s}.service \ + $RPM_BUILD_ROOT%{_unitdir}/${s}.service +done + +# install conf file/directory +mkdir $RPM_BUILD_ROOT%{_sysconfdir}/httpd/conf.d \ + $RPM_BUILD_ROOT%{_sysconfdir}/httpd/conf.modules.d +install -m 644 $RPM_SOURCE_DIR/README.confd \ + $RPM_BUILD_ROOT%{_sysconfdir}/httpd/conf.d/README +for f in 00-base.conf 00-mpm.conf 00-lua.conf 01-cgi.conf 00-dav.conf \ + 00-proxy.conf 00-ssl.conf 01-ldap.conf 00-proxyhtml.conf \ + 01-ldap.conf 00-systemd.conf 01-session.conf; do + install -m 644 -p $RPM_SOURCE_DIR/$f \ + $RPM_BUILD_ROOT%{_sysconfdir}/httpd/conf.modules.d/$f +done + +for f in welcome.conf ssl.conf manual.conf userdir.conf; do + install -m 644 -p $RPM_SOURCE_DIR/$f \ + $RPM_BUILD_ROOT%{_sysconfdir}/httpd/conf.d/$f +done + +# Split-out extra config shipped as default in conf.d: +for f in autoindex; do + mv docs/conf/extra/httpd-${f}.conf \ + $RPM_BUILD_ROOT%{_sysconfdir}/httpd/conf.d/${f}.conf +done + +# Extra config trimmed: +rm -v docs/conf/extra/httpd-{ssl,userdir}.conf + +rm $RPM_BUILD_ROOT%{_sysconfdir}/httpd/conf/*.conf +install -m 644 -p $RPM_SOURCE_DIR/httpd.conf \ + $RPM_BUILD_ROOT%{_sysconfdir}/httpd/conf/httpd.conf + +mkdir $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig +for s in httpd htcacheclean; do + install -m 644 -p $RPM_SOURCE_DIR/${s}.sysconf \ + $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig/${s} +done + +# tmpfiles.d configuration +mkdir -p $RPM_BUILD_ROOT%{_prefix}/lib/tmpfiles.d +install -m 644 -p $RPM_SOURCE_DIR/httpd.tmpfiles \ + $RPM_BUILD_ROOT%{_prefix}/lib/tmpfiles.d/httpd.conf + +# Other directories +mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/lib/dav \ + $RPM_BUILD_ROOT/run/httpd/htcacheclean + +# Create cache directory +mkdir -p $RPM_BUILD_ROOT%{_localstatedir}/cache/httpd \ + $RPM_BUILD_ROOT%{_localstatedir}/cache/httpd/proxy \ + $RPM_BUILD_ROOT%{_localstatedir}/cache/httpd/ssl + +# Make the MMN accessible to module packages +echo %{mmnisa} > $RPM_BUILD_ROOT%{_includedir}/httpd/.mmn +mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/rpm +cat > $RPM_BUILD_ROOT%{_sysconfdir}/rpm/macros.httpd < $RPM_BUILD_ROOT%{_mandir}/man8/httpd.8 + +# Make ap_config_layout.h libdir-agnostic +sed -i '/.*DEFAULT_..._LIBEXECDIR/d;/DEFAULT_..._INSTALLBUILDDIR/d' \ + $RPM_BUILD_ROOT%{_includedir}/httpd/ap_config_layout.h + +# Fix path to instdso in special.mk +sed -i '/instdso/s,top_srcdir,top_builddir,' \ + $RPM_BUILD_ROOT%{_libdir}/httpd/build/special.mk + +# Remove unpackaged files +rm -vf \ + $RPM_BUILD_ROOT%{_libdir}/*.exp \ + $RPM_BUILD_ROOT/etc/httpd/conf/mime.types \ + $RPM_BUILD_ROOT%{_libdir}/httpd/modules/*.exp \ + $RPM_BUILD_ROOT%{_libdir}/httpd/build/config.nice \ + $RPM_BUILD_ROOT%{_bindir}/{ap?-config,dbmmanage} \ + $RPM_BUILD_ROOT%{_sbindir}/{checkgid,envvars*} \ + $RPM_BUILD_ROOT%{contentdir}/htdocs/* \ + $RPM_BUILD_ROOT%{_mandir}/man1/dbmmanage.* \ + $RPM_BUILD_ROOT%{contentdir}/cgi-bin/* + +rm -rf $RPM_BUILD_ROOT/etc/httpd/conf/{original,extra} + +%pre +# Add the "apache" group and user +/usr/sbin/groupadd -g 48 -r apache 2> /dev/null || : +/usr/sbin/useradd -c "Apache" -u 48 -g apache \ + -s /sbin/nologin -r -d %{contentdir} apache 2> /dev/null || : + +%post +%systemd_post httpd.service htcacheclean.service + +%preun +%systemd_preun httpd.service htcacheclean.service + +%postun +%systemd_postun + +# Trigger for conversion from SysV, per guidelines at: +# https://fedoraproject.org/wiki/Packaging:ScriptletSnippets#Systemd +%triggerun -- httpd < 2.2.21-5 +# Save the current service runlevel info +# User must manually run systemd-sysv-convert --apply httpd +# to migrate them to systemd targets +/usr/bin/systemd-sysv-convert --save httpd.service >/dev/null 2>&1 ||: + +# Run these because the SysV package being removed won't do them +/sbin/chkconfig --del httpd >/dev/null 2>&1 || : + +%posttrans +test -f /etc/sysconfig/httpd-disable-posttrans || \ + /bin/systemctl try-restart httpd.service htcacheclean.service >/dev/null 2>&1 || : + +%define sslcert %{_sysconfdir}/pki/tls/certs/localhost.crt +%define sslkey %{_sysconfdir}/pki/tls/private/localhost.key + +%post -n mod_ssl +umask 077 + +if [ -f %{sslkey} -o -f %{sslcert} ]; then + exit 0 +fi + +%{_bindir}/openssl genrsa -rand /proc/apm:/proc/cpuinfo:/proc/dma:/proc/filesystems:/proc/interrupts:/proc/ioports:/proc/pci:/proc/rtc:/proc/uptime 2048 > %{sslkey} 2> /dev/null + +FQDN=`hostname` +if [ "x${FQDN}" = "x" -o ${#FQDN} -gt 59 ]; then + FQDN=localhost.localdomain +fi + +cat << EOF | %{_bindir}/openssl req -new -key %{sslkey} \ + -x509 -sha256 -days 365 -set_serial $RANDOM -extensions v3_req \ + -out %{sslcert} 2>/dev/null +-- +SomeState +SomeCity +SomeOrganization +SomeOrganizationalUnit +${FQDN} +root@${FQDN} +EOF + +%check +# Check the built modules are all PIC +if readelf -d $RPM_BUILD_ROOT%{_libdir}/httpd/modules/*.so | grep TEXTREL; then + : modules contain non-relocatable code + exit 1 +fi + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root) + +%doc ABOUT_APACHE README CHANGES LICENSE VERSIONING NOTICE +%doc docs/conf/extra/*.conf + +%dir %{_sysconfdir}/httpd +%{_sysconfdir}/httpd/modules +%{_sysconfdir}/httpd/logs +%{_sysconfdir}/httpd/run +%dir %{_sysconfdir}/httpd/conf +%config(noreplace) %{_sysconfdir}/httpd/conf/httpd.conf +%config(noreplace) %{_sysconfdir}/httpd/conf/magic + +%config(noreplace) %{_sysconfdir}/logrotate.d/httpd + +%dir %{_sysconfdir}/httpd/conf.d +%{_sysconfdir}/httpd/conf.d/README +%config(noreplace) %{_sysconfdir}/httpd/conf.d/*.conf +%exclude %{_sysconfdir}/httpd/conf.d/ssl.conf +%exclude %{_sysconfdir}/httpd/conf.d/manual.conf + +%dir %{_sysconfdir}/httpd/conf.modules.d +%config(noreplace) %{_sysconfdir}/httpd/conf.modules.d/*.conf +%exclude %{_sysconfdir}/httpd/conf.modules.d/00-ssl.conf +%exclude %{_sysconfdir}/httpd/conf.modules.d/00-proxyhtml.conf +%exclude %{_sysconfdir}/httpd/conf.modules.d/01-ldap.conf +%exclude %{_sysconfdir}/httpd/conf.modules.d/01-session.conf + +%config(noreplace) %{_sysconfdir}/sysconfig/ht* +%{_prefix}/lib/tmpfiles.d/httpd.conf + +%dir %{_libexecdir}/initscripts/legacy-actions/httpd +%{_libexecdir}/initscripts/legacy-actions/httpd/* + +%{_sbindir}/ht* +%{_sbindir}/fcgistarter +%{_sbindir}/apachectl +%{_sbindir}/rotatelogs +%caps(cap_setuid,cap_setgid+pe) %attr(510,root,%{suexec_caller}) %{_sbindir}/suexec + +%dir %{_libdir}/httpd +%dir %{_libdir}/httpd/modules +%{_libdir}/httpd/modules/mod*.so +%exclude %{_libdir}/httpd/modules/mod_auth_form.so +%exclude %{_libdir}/httpd/modules/mod_ssl.so +%exclude %{_libdir}/httpd/modules/mod_*ldap.so +%exclude %{_libdir}/httpd/modules/mod_proxy_html.so +%exclude %{_libdir}/httpd/modules/mod_xml2enc.so +%exclude %{_libdir}/httpd/modules/mod_session*.so + +%dir %{contentdir} +%dir %{contentdir}/icons +%dir %{contentdir}/error +%dir %{contentdir}/error/include +%dir %{contentdir}/noindex +%{contentdir}/icons/* +%{contentdir}/error/README +%{contentdir}/error/*.var +%{contentdir}/error/include/*.html +%{contentdir}/noindex/* + +%dir %{docroot} +%dir %{docroot}/cgi-bin +%dir %{docroot}/html + +%attr(0710,root,apache) %dir /run/httpd +%attr(0700,apache,apache) %dir /run/httpd/htcacheclean +%attr(0700,root,root) %dir %{_localstatedir}/log/httpd +%attr(0700,apache,apache) %dir %{_localstatedir}/lib/dav +%attr(0700,apache,apache) %dir %{_localstatedir}/cache/httpd +%attr(0700,apache,apache) %dir %{_localstatedir}/cache/httpd/proxy + +%{_mandir}/man8/* + +%{_unitdir}/*.service + +%files tools +%defattr(-,root,root) +%{_bindir}/* +%{_mandir}/man1/* +%doc LICENSE NOTICE +%exclude %{_bindir}/apxs +%exclude %{_mandir}/man1/apxs.1* + +%files manual +%defattr(-,root,root) +%{contentdir}/manual +%config(noreplace) %{_sysconfdir}/httpd/conf.d/manual.conf + +%files -n mod_ssl +%defattr(-,root,root) +%{_libdir}/httpd/modules/mod_ssl.so +%config(noreplace) %{_sysconfdir}/httpd/conf.modules.d/00-ssl.conf +%config(noreplace) %{_sysconfdir}/httpd/conf.d/ssl.conf +%attr(0700,apache,root) %dir %{_localstatedir}/cache/httpd/ssl +%{_libexecdir}/httpd-ssl-pass-dialog + +%files -n mod_proxy_html +%defattr(-,root,root) +%{_libdir}/httpd/modules/mod_proxy_html.so +%{_libdir}/httpd/modules/mod_xml2enc.so +%config(noreplace) %{_sysconfdir}/httpd/conf.modules.d/00-proxyhtml.conf + +%files -n mod_ldap +%defattr(-,root,root) +%{_libdir}/httpd/modules/mod_*ldap.so +%config(noreplace) %{_sysconfdir}/httpd/conf.modules.d/01-ldap.conf + +%files -n mod_session +%defattr(-,root,root) +%{_libdir}/httpd/modules/mod_session*.so +%{_libdir}/httpd/modules/mod_auth_form.so +%config(noreplace) %{_sysconfdir}/httpd/conf.modules.d/01-session.conf + +%files devel +%defattr(-,root,root) +%{_includedir}/httpd +%{_bindir}/apxs +%{_mandir}/man1/apxs.1* +%dir %{_libdir}/httpd/build +%{_libdir}/httpd/build/*.mk +%{_libdir}/httpd/build/*.sh +%{_sysconfdir}/rpm/macros.httpd + +%changelog +* Tue Jun 26 2018 CentOS Sources - 2.4.6-80.el7.centos.1 +- Remove index.html, add centos-noindex.tar.gz +- change vstring +- change symlink for poweredby.png +- update welcome.conf with proper aliases + +* Mon May 28 2018 Luboš Uhliarik - 2.4.6-80.1 +- Resolves: #1560609 - httpd: active connections being terminated when httpd + gets gracefully stopped/restarted, GracefulShutdownTimeout is not being + honored + +* Mon Jan 08 2018 Luboš Uhliarik - 2.4.6-80 +- Related: #1288395 - httpd segfault when logrotate invoked + +* Wed Nov 01 2017 Luboš Uhliarik - 2.4.6-79 +- Resolves: #1274890 - mod_ssl config: tighten defaults + +* Tue Oct 31 2017 Luboš Uhliarik - 2.4.6-78 +- Resolves: #1506392 - Backport: SSLSessionTickets directive support + +* Mon Oct 16 2017 Luboš Uhliarik - 2.4.6-77 +- Resolves: #1440590 - Need an option to disable UTF8-conversion + of certificate DN + +* Thu Oct 12 2017 Luboš Uhliarik - 2.4.6-76 +- Resolves: #1464406 - Apache consumes too much memory for CGI output + +* Thu Oct 12 2017 Luboš Uhliarik - 2.4.6-75 +- Resolves: #1448892 - Cannot override LD_LIBARY_PATH in Apache HTTPD + using SetEnv or PassEnv. Needs documentation. + +* Mon Oct 09 2017 Luboš Uhliarik - 2.4.6-74 +- Resolves: #1430640 - "ProxyAddHeaders Off" does not become effective + when it's defined outside setting + +* Fri Oct 06 2017 Luboš Uhliarik - 2.4.6-73 +- Resolves: #1499253 - ProxyRemote with HTTPS backend sends requests + with absoluteURI instead of abs_path + +* Tue Oct 03 2017 Luboš Uhliarik - 2.4.6-72 +- Resolves: #1288395 - httpd segfault when logrotate invoked + +* Tue Oct 03 2017 Luboš Uhliarik - 2.4.6-71 +- Resolves: #1368491 - mod_authz_dbd segfaults when AuthzDBDQuery missing + +* Mon Oct 02 2017 Luboš Uhliarik - 2.4.6-70 +- Resolves: #1467402 - rotatelogs: creation of zombie processes when -p is used + +* Tue Sep 19 2017 Luboš Uhliarik - 2.4.6-69 +- Resolves: #1493065 - CVE-2017-9798 httpd: Use-after-free by limiting + unregistered HTTP method + +* Tue Jul 25 2017 Luboš Uhliarik - 2.4.6-68 +- Resolves: #1463194 - CVE-2017-3167 httpd: ap_get_basic_auth_pw() + authentication bypass +- Resolves: #1463197 - CVE-2017-3169 httpd: mod_ssl NULL pointer dereference +- Resolves: #1463207 - CVE-2017-7679 httpd: mod_mime buffer overread +- Resolves: #1463205 - CVE-2017-7668 httpd: ap_find_token() buffer overread +- Resolves: #1470748 - CVE-2017-9788 httpd: Uninitialized memory reflection + in mod_auth_digest + +* Tue May 09 2017 Luboš Uhliarik - 2.4.6-67 +- Related: #1332242 - Explicitly disallow the '#' character in allow,deny + directives + +* Tue May 09 2017 Luboš Uhliarik - 2.4.6-66 +- Related: #1332242 - Explicitly disallow the '#' character in allow,deny + directives + +* Thu Apr 27 2017 Luboš Uhliarik - 2.4.6-65 +- Resolves: #1445885 - define _RH_HAS_HTTPPROTOCOLOPTIONS + +* Tue Apr 18 2017 Luboš Uhliarik - 2.4.6-64 +- Resolves: #1442872 - apache user is not created during httpd installation + when apache group already exist with GID other than 48 + +* Wed Mar 22 2017 Luboš Uhliarik - 2.4.6-63 +- Related: #1412976 - CVE-2016-0736 CVE-2016-2161 CVE-2016-8743 + httpd: various flaws + +* Wed Mar 15 2017 Luboš Uhliarik - 2.4.6-62 +- Resolves: #1397241 - Backport Apache Bug 53098 - mod_proxy_ajp: + patch to set worker secret passed to tomcat + +* Wed Mar 15 2017 Luboš Uhliarik - 2.4.6-61 +- Related: #1414258 - Crash during restart or at startup in mod_ssl, + in certinfo_free() function registered by ssl_stapling_ex_init() + +* Tue Mar 14 2017 Luboš Uhliarik - 2.4.6-60 +- Resolves: #1414258 - Crash during restart or at startup in mod_ssl, + in certinfo_free() function registered by ssl_stapling_ex_init() + +* Mon Mar 13 2017 Luboš Uhliarik - 2.4.6-59 +- Resolves: #1378946 - Backport of apache bug 55910: Continuation lines + are broken during buffer resize + +* Fri Mar 10 2017 Luboš Uhliarik - 2.4.6-58 +- Resolves: #1364604 - Upstream Bug 56925 - ErrorDocument directive misbehaves + with mod_proxy_http and mod_proxy_ajp + +* Thu Mar 09 2017 Luboš Uhliarik - 2.4.6-57 +- Resolves: #1324416 - Error 404 when switching language in HTML manual + more than once + +* Wed Mar 08 2017 Luboš Uhliarik - 2.4.6-56 +- Resolves: #1353740 - Backport Apache PR58118 to fix mod_proxy_fcgi + spamming non-errors: AH01075: Error dispatching request to : (passing + brigade to output filters) + +* Wed Mar 08 2017 Luboš Uhliarik - 2.4.6-55 +- Resolves: #1371876 - Apache httpd returns "200 OK" for a request + exceeding LimitRequestBody when enabling mod_ext_filter + +* Tue Mar 07 2017 Luboš Uhliarik - 2.4.6-54 +- Resolves: #1372692 - Apache httpd does not log status code "413" in + access_log when exceeding LimitRequestBody + +* Tue Mar 07 2017 Luboš Uhliarik - 2.4.6-53 +- Resolves: #1376835 - httpd with worker/event mpm segfaults after multiple + successive graceful reloads + +* Tue Mar 07 2017 Luboš Uhliarik - 2.4.6-52 +- Resolves: #1332242 - Explicitly disallow the '#' character in allow,deny + directives + +* Mon Mar 06 2017 Luboš Uhliarik - 2.4.6-51 +- Resolves: #1396197 - Backport: mod_proxy_wstunnel - AH02447: err/hup + on backconn + +* Mon Mar 06 2017 Luboš Uhliarik - 2.4.6-50 +- Resolves: #1348019 - mod_proxy: Fix a race condition that caused a failed + worker to be retried before the retry period is over + +* Mon Mar 06 2017 Luboš Uhliarik - 2.4.6-49 +- Resolves: #1389535 - Segmentation fault in SSL_renegotiate + +* Mon Mar 06 2017 Luboš Uhliarik - 2.4.6-48 +- Resolves: #1406184 - stapling_renew_response: abort early + (before apr_uri_parse) if ocspuri is empty + +* Tue Feb 7 2017 Joe Orton - 2.4.6-47 +- prefork: fix delay completing graceful restart (#1327624) +- mod_ldap: fix authz regression, failing to rebind (#1415257) + +* Thu Jan 26 2017 Luboš Uhliarik - 2.4.6-46 +- Resolves: #1412976 - CVE-2016-0736 CVE-2016-2161 CVE-2016-8743 + httpd: various flaws + +* Wed Aug 03 2016 Luboš Uhliarik - 2.4.6-45 +- RFE: run mod_rewrite external mapping program as non-root (#1316900) + +* Tue Jul 12 2016 Joe Orton - 2.4.6-44 +- add security fix for CVE-2016-5387 + +* Tue Jul 5 2016 Joe Orton - 2.4.6-43 +- add 451 (Unavailable For Legal Reasons) response status-code (#1343582) + +* Fri Jun 17 2016 Joe Orton - 2.4.6-42 +- mod_cache: treat cache as valid with changed Expires in 304 (#1331341) + +* Wed Feb 24 2016 Jan Kaluza - 2.4.6-41 +- mod_cache: merge r->err_headers_out into r->headers when the response + is cached for the first time (#1264989) +- mod_ssl: Do not send SSL warning when SNI hostname is not found as per + RFC 6066 (#1298148) +- mod_proxy_fcgi: Ignore body data from backend for 304 responses (#1263038) +- fix apache user creation when apache group already exists (#1299889) +- fix apache user creation when USERGROUPS_ENAB is set to 'no' (#1288757) +- mod_proxy: fix slow response time for reponses with error status code + when using ProxyErrorOverride (#1283653) +- mod_ldap: Respect LDAPConnectionPoolTTL for authn connections (#1300149) +- mod_ssl: use "localhost" in the dummy SSL cert for long FQDNs (#1240495) +- rotatelogs: improve support for localtime (#1244545) +- ab: fix read failure when targeting SSL server (#1255331) +- mod_log_debug: fix LogMessage example in documentation (#1279465) +- mod_authz_dbd, mod_authn_dbd, mod_session_dbd, mod_rewrite: Fix lifetime + of DB lookup entries independently of the selected DB engine (#1287844) +- mod_ssl: fix hardware crypto support with custom DH parms (#1291865) +- mod_proxy_fcgi: fix SCRIPT_FILENAME when a balancer is used (#1302797) + +* Thu Sep 17 2015 Jan Kaluza - 2.4.6-40 +- mod_dav: follow up fix for previous commit (#1263975) + +* Wed Aug 26 2015 Jan Kaluza - 2.4.6-39 +- mod_dav: treat dav_resource uri as escaped (#1255480) + +* Wed Aug 19 2015 Jan Kaluza - 2.4.6-38 +- mod_ssl: add support for User Principal Name in SSLUserName (#1242503) + +* Mon Aug 10 2015 Jan Kaluza - 2.4.6-37 +- core: fix chunk header parsing defect (CVE-2015-3183) +- core: replace of ap_some_auth_required with ap_some_authn_required + and ap_force_authn hook (CVE-2015-3185) + +* Tue Jul 14 2015 Jan Kaluza - 2.4.6-36 +- Revert fix for #1162152, it is not needed in RHEL7 +- mod_proxy_ajp: fix settings ProxyPass parameters for AJP backends (#1242416) + +* Wed Jul 01 2015 Jan Kaluza - 2.4.6-35 +- mod_remoteip: correct the trusted proxy match test (#1179306) +- mod_dav: send complete response when resource is created (#1235383) +- apachectl: correct the apachectl status man page (#1231924) + +* Wed Jun 03 2015 Jan Kaluza - 2.4.6-34 +- mod_proxy_fcgi: honor Timeout / ProxyTimeout (#1222328) +- do not show all vhosts twice in httpd -D DUMP_VHOSTS output (#1225820) +- fix -D[efined] or [d] variables lifetime accross restarts (#1227219) +- mod_ssl: do not send NPN extension with not configured (#1226015) + +* Mon May 18 2015 Jan Kaluza - 2.4.6-33 +- mod_authz_dbm: fix crash when using "Require dbm-file-group" (#1221575) + +* Wed Apr 15 2015 Jan Kaluza - 2.4.6-32 +- mod_authn_dbd: fix use-after-free bug with postgresql (#1188779) +- mod_remoteip: correct the trusted proxy match test (#1179306) +- mod_status: honor remote_ip as documented (#1169081) +- mod_deflate: fix decompression of files larger than 4GB (#1170214) +- core: improve error message for inaccessible DocumentRoot (#1170220) +- ab: try all addresses instead of failing on first one when not available (#1125276) +- mod_proxy_wstunnel: add support for SSL (#1180745) +- mod_proxy_wstunnel: load this module by default (#1180745) +- mod_rewrite: add support for WebSockets (#1180745) +- mod_rewrite: do not search for directory if a URL will be rewritten (#1210091) +- mod_ssl: Fix SSL_CLIENT_VERIFY value when optional_no_ca and SSLSessionCache + are used and SSL session is resumed (#1170206) +- mod_ssl: fix memory leak on httpd reloads (#1181690) +- mod_ssl: use SSLCipherSuite HIGH:MEDIUM:!aNULL:!MD5:!SEED:!IDEA (#1118476) +- mod_cgi: return error code 408 on timeout (#1162152) +- mod_dav_fs: set default value of DAVLockDB (#1176449) +- add Documentation= to the httpd.service and htcacheclean.service (#1184118) +- do not display "bomb" icon for files ending with "core" (#1170215) +- add missing Reason-Phrase in HTTP response headers (#1162159) +- fix BuildRequires to require openssl-devel >= 1:1.0.1e-37 (#1160625) +- apachectl: ignore HTTPD variable from sysconfig (#1214401) +- apachectl: fix "graceful" documentation (#1214398) +- apachectl: fix "graceful" behaviour when httpd is not running (#1214430) + +* Tue Dec 02 2014 Jan Kaluza - 2.4.6-31 +- mod_proxy_fcgi: determine if FCGI_CONN_CLOSE should be enabled + instead of hardcoding it (#1168050) +- mod_proxy: support Unix Domain Sockets (#1168081) + +* Tue Nov 25 2014 Jan Kaluza - 2.4.6-30 +- core: fix bypassing of mod_headers rules via chunked requests (CVE-2013-5704) +- mod_cache: fix NULL pointer dereference on empty Content-Type (CVE-2014-3581) + +* Tue Nov 04 2014 Jan Kaluza - 2.4.6-29 +- rebuild against proper version of OpenSSL (#1080125) + +* Wed Oct 22 2014 Jan Kaluza - 2.4.6-28 +- set vstring based on /etc/os-release (#1114123) + +* Mon Oct 06 2014 Jan Kaluza - 2.4.6-27 +- fix the dependency on openssl-libs to match the fix for #1080125 + +* Mon Sep 22 2014 Jan Kaluza - 2.4.6-26 +- allow 'es to be seen under virtual hosts (#1131847) + +* Fri Sep 19 2014 Jan Kaluza - 2.4.6-25 +- do not use hardcoded curve for ECDHE suites (#1080125) + +* Wed Sep 03 2014 Jan Kaluza - 2.4.6-24 +- allow reverse-proxy to be set via SetHandler (#1136290) + +* Thu Aug 21 2014 Jan Kaluza - 2.4.6-23 +- fix possible crash in SIGINT handling (#1131006) + +* Mon Aug 18 2014 Jan Kaluza - 2.4.6-22 +- ab: fix integer overflow when printing stats with lot of requests (#1092420) + +* Mon Aug 11 2014 Jan Kaluza - 2.4.6-21 +- add pre_htaccess so mpm-itk can be build as separate module (#1059143) + +* Tue Aug 05 2014 Jan Kaluza - 2.4.6-20 +- mod_ssl: prefer larger keys and support up to 8192-bit keys (#1073078) + +* Mon Aug 04 2014 Jan Kaluza - 2.4.6-19 +- fix build on ppc64le by using configure macro (#1125545) +- compile httpd with -O3 on ppc64le (#1123490) +- mod_rewrite: expose CONN_REMOTE_ADDR (#1060536) + +* Thu Jul 17 2014 Jan Kaluza - 2.4.6-18 +- mod_cgid: add security fix for CVE-2014-0231 (#1120608) +- mod_proxy: add security fix for CVE-2014-0117 (#1120608) +- mod_deflate: add security fix for CVE-2014-0118 (#1120608) +- mod_status: add security fix for CVE-2014-0226 (#1120608) +- mod_cache: add secutiry fix for CVE-2013-4352 (#1120608) + +* Thu Mar 20 2014 Jan Kaluza - 2.4.6-17 +- mod_dav: add security fix for CVE-2013-6438 (#1077907) +- mod_log_config: add security fix for CVE-2014-0098 (#1077907) + +* Wed Mar 5 2014 Joe Orton - 2.4.6-16 +- mod_ssl: improve DH temp key handling (#1057687) + +* Wed Mar 5 2014 Joe Orton - 2.4.6-15 +- mod_ssl: use 2048-bit RSA key with SHA-256 signature in dummy certificate (#1071276) + +* Fri Jan 24 2014 Daniel Mach - 2.4.6-14 +- Mass rebuild 2014-01-24 + +* Mon Jan 13 2014 Joe Orton - 2.4.6-13 +- mod_ssl: sanity-check use of "SSLCompression" (#1036666) +- mod_proxy_http: fix brigade memory usage (#1040447) + +* Fri Jan 10 2014 Joe Orton - 2.4.6-12 +- rebuild + +* Thu Jan 9 2014 Joe Orton - 2.4.6-11 +- build with -O3 on ppc64 (#1051066) + +* Tue Jan 7 2014 Joe Orton - 2.4.6-10 +- mod_dav: fix locktoken handling (#1004046) + +* Fri Dec 27 2013 Daniel Mach - 2.4.6-9 +- Mass rebuild 2013-12-27 + +* Fri Dec 20 2013 Joe Orton - 2.4.6-8 +- use unambiguous httpd-mmn (#1029360) + +* Fri Nov 1 2013 Jan Kaluza - 2.4.6-7 +- mod_ssl: allow SSLEngine to override Listen-based default (#1023168) + +* Thu Oct 31 2013 Jan Kaluza - 2.4.6-6 +- systemd: Use {MAINPID} notation in service file (#969972) + +* Thu Oct 24 2013 Jan Kaluza - 2.4.6-5 +- systemd: send SIGWINCH signal without httpd -k in ExecStop (#969972) + +* Thu Oct 03 2013 Jan Kaluza - 2.4.6-4 +- expand macros in macros.httpd (#1011393) + +* Mon Aug 26 2013 Jan Kaluza - 2.4.6-3 +- fix "LDAPReferrals off" to really disable LDAP Referrals + +* Wed Jul 31 2013 Jan Kaluza - 2.4.6-2 +- revert fix for dumping vhosts twice + +* Mon Jul 22 2013 Joe Orton - 2.4.6-1 +- update to 2.4.6 +- mod_ssl: use revised NPN API (r1487772) + +* Thu Jul 11 2013 Jan Kaluza - 2.4.4-12 +- mod_unique_id: replace use of hostname + pid with PRNG output (#976666) +- apxs: mention -p option in manpage + +* Tue Jul 2 2013 Joe Orton - 2.4.4-11 +- add patch for aarch64 (Dennis Gilmore, #925558) + +* Mon Jul 1 2013 Joe Orton - 2.4.4-10 +- remove duplicate apxs man page from httpd-tools + +* Mon Jun 17 2013 Joe Orton - 2.4.4-9 +- remove zombie dbmmanage script + +* Fri May 31 2013 Jan Kaluza - 2.4.4-8 +- return 400 Bad Request on malformed Host header + +* Mon May 20 2013 Jan Kaluza - 2.4.4-6 +- htpasswd/htdbm: fix hash generation bug (#956344) +- do not dump vhosts twice in httpd -S output (#928761) +- mod_cache: fix potential crash caused by uninitialized variable (#954109) + +* Thu Apr 18 2013 Jan Kaluza - 2.4.4-5 +- execute systemctl reload as result of apachectl graceful +- mod_ssl: ignore SNI hints unless required by config +- mod_cache: forward-port CacheMaxExpire "hard" option +- mod_ssl: fall back on another module's proxy hook if mod_ssl proxy + is not configured. + +* Tue Apr 16 2013 Jan Kaluza - 2.4.4-4 +- fix service file to not send SIGTERM after ExecStop (#906321, #912288) + +* Tue Mar 26 2013 Jan Kaluza - 2.4.4-3 +- protect MIMEMagicFile with IfModule (#893949) + +* Tue Feb 26 2013 Joe Orton - 2.4.4-2 +- really package mod_auth_form in mod_session (#915438) + +* Tue Feb 26 2013 Joe Orton - 2.4.4-1 +- update to 2.4.4 +- fix duplicate ownership of mod_session config (#914901) + +* Fri Feb 22 2013 Joe Orton - 2.4.3-17 +- add mod_session subpackage, move mod_auth_form there (#894500) + +* Thu Feb 14 2013 Fedora Release Engineering - 2.4.3-16 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild + +* Tue Jan 8 2013 Joe Orton - 2.4.3-15 +- add systemd service for htcacheclean + +* Tue Nov 13 2012 Joe Orton - 2.4.3-14 +- drop patch for r1344712 + +* Tue Nov 13 2012 Joe Orton - 2.4.3-13 +- filter mod_*.so auto-provides (thanks to rcollet) +- pull in syslog logging fix from upstream (r1344712) + +* Fri Oct 26 2012 Joe Orton - 2.4.3-12 +- rebuild to pick up new apr-util-ldap + +* Tue Oct 23 2012 Joe Orton - 2.4.3-11 +- rebuild + +* Wed Oct 3 2012 Joe Orton - 2.4.3-10 +- pull upstream patch r1392850 in addition to r1387633 + +* Mon Oct 1 2012 Joe Orton - 2.4.3-9.1 +- restore "ServerTokens Full-Release" support (#811714) + +* Mon Oct 1 2012 Joe Orton - 2.4.3-9 +- define PLATFORM in os.h using vendor string + +* Mon Oct 1 2012 Joe Orton - 2.4.3-8 +- use systemd script unconditionally (#850149) + +* Mon Oct 1 2012 Joe Orton - 2.4.3-7 +- use systemd scriptlets if available (#850149) +- don't run posttrans restart if /etc/sysconfig/httpd-disable-posttrans exists + +* Mon Oct 01 2012 Jan Kaluza - 2.4.3-6 +- use systemctl from apachectl (#842736) + +* Wed Sep 19 2012 Joe Orton - 2.4.3-5 +- fix some error log spam with graceful-stop (r1387633) +- minor mod_systemd tweaks + +* Thu Sep 13 2012 Joe Orton - 2.4.3-4 +- use IncludeOptional for conf.d/*.conf inclusion + +* Fri Sep 07 2012 Jan Kaluza - 2.4.3-3 +- adding mod_systemd to integrate with systemd better + +* Tue Aug 21 2012 Joe Orton - 2.4.3-2 +- mod_ssl: add check for proxy keypair match (upstream r1374214) + +* Tue Aug 21 2012 Joe Orton - 2.4.3-1 +- update to 2.4.3 (#849883) +- own the docroot (#848121) + +* Mon Aug 6 2012 Joe Orton - 2.4.2-23 +- add mod_proxy fixes from upstream (r1366693, r1365604) + +* Thu Jul 19 2012 Fedora Release Engineering - 2.4.2-22 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Fri Jul 6 2012 Joe Orton - 2.4.2-21 +- drop explicit version requirement on initscripts + +* Thu Jul 5 2012 Joe Orton - 2.4.2-20 +- mod_ext_filter: fix error_log warnings + +* Mon Jul 2 2012 Joe Orton - 2.4.2-19 +- support "configtest" and "graceful" as initscripts "legacy actions" + +* Fri Jun 8 2012 Joe Orton - 2.4.2-18 +- avoid use of "core" GIF for a "core" directory (#168776) +- drop use of "syslog.target" in systemd unit file + +* Thu Jun 7 2012 Joe Orton - 2.4.2-17 +- use _unitdir for systemd unit file +- use /run in unit file, ssl.conf + +* Thu Jun 7 2012 Joe Orton - 2.4.2-16 +- mod_ssl: fix NPN patch merge + +* Wed Jun 6 2012 Joe Orton - 2.4.2-15 +- move tmpfiles.d fragment into /usr/lib per new guidelines +- package /run/httpd not /var/run/httpd +- set runtimedir to /run/httpd likewise + +* Wed Jun 6 2012 Joe Orton - 2.4.2-14 +- fix htdbm/htpasswd crash on crypt() failure (#818684) + +* Wed Jun 6 2012 Joe Orton - 2.4.2-13 +- pull fix for NPN patch from upstream (r1345599) + +* Thu May 31 2012 Joe Orton - 2.4.2-12 +- update suexec patch to use LOG_AUTHPRIV facility + +* Thu May 24 2012 Joe Orton - 2.4.2-11 +- really fix autoindex.conf (thanks to remi@) + +* Thu May 24 2012 Joe Orton - 2.4.2-10 +- fix autoindex.conf to allow symlink to poweredby.png + +* Wed May 23 2012 Joe Orton - 2.4.2-9 +- suexec: use upstream version of patch for capability bit support + +* Wed May 23 2012 Joe Orton - 2.4.2-8 +- suexec: use syslog rather than suexec.log, drop dac_override capability + +* Tue May 1 2012 Joe Orton - 2.4.2-7 +- mod_ssl: add TLS NPN support (r1332643, #809599) + +* Tue May 1 2012 Joe Orton - 2.4.2-6 +- add BR on APR >= 1.4.0 + +* Fri Apr 27 2012 Joe Orton - 2.4.2-5 +- use systemctl from logrotate (#221073) + +* Fri Apr 27 2012 Joe Orton - 2.4.2-4 +- pull from upstream: + * use TLS close_notify alert for dummy_connection (r1326980+) + * cleanup symbol exports (r1327036+) + +* Fri Apr 27 2012 Joe Orton - 2.4.2-3.2 +- rebuild + +* Fri Apr 20 2012 Joe Orton - 2.4.2-3 +- really fix restart + +* Fri Apr 20 2012 Joe Orton - 2.4.2-2 +- tweak default ssl.conf +- fix restart handling (#814645) +- use graceful restart by default + +* Wed Apr 18 2012 Jan Kaluza - 2.4.2-1 +- update to 2.4.2 + +* Fri Mar 23 2012 Joe Orton - 2.4.1-6 +- fix macros + +* Fri Mar 23 2012 Joe Orton - 2.4.1-5 +- add _httpd_moddir to macros + +* Tue Mar 13 2012 Joe Orton - 2.4.1-4 +- fix symlink for poweredby.png +- fix manual.conf + +* Tue Mar 13 2012 Joe Orton - 2.4.1-3 +- add mod_proxy_html subpackage (w/mod_proxy_html + mod_xml2enc) +- move mod_ldap, mod_authnz_ldap to mod_ldap subpackage + +* Tue Mar 13 2012 Joe Orton - 2.4.1-2 +- clean docroot better +- ship proxy, ssl directories within /var/cache/httpd +- default config: + * unrestricted access to (only) /var/www + * remove (commented) Mutex, MaxRanges, ScriptSock + * split autoindex config to conf.d/autoindex.conf +- ship additional example configs in docdir + +* Tue Mar 6 2012 Joe Orton - 2.4.1-1 +- update to 2.4.1 +- adopt upstream default httpd.conf (almost verbatim) +- split all LoadModules to conf.modules.d/*.conf +- include conf.d/*.conf at end of httpd.conf +- trim %%changelog + +* Mon Feb 13 2012 Joe Orton - 2.2.22-2 +- fix build against PCRE 8.30 + +* Mon Feb 13 2012 Joe Orton - 2.2.22-1 +- update to 2.2.22 + +* Fri Feb 10 2012 Petr Pisar - 2.2.21-8 +- Rebuild against PCRE 8.30 + +* Mon Jan 23 2012 Jan Kaluza - 2.2.21-7 +- fix #783629 - start httpd after named + +* Mon Jan 16 2012 Joe Orton - 2.2.21-6 +- complete conversion to systemd, drop init script (#770311) +- fix comments in /etc/sysconfig/httpd (#771024) +- enable PrivateTmp in service file (#781440) +- set LANG=C in /etc/sysconfig/httpd + +* Fri Jan 13 2012 Fedora Release Engineering - 2.2.21-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Tue Dec 06 2011 Jan Kaluza - 2.2.21-4 +- fix #751591 - start httpd after remote-fs + +* Mon Oct 24 2011 Jan Kaluza - 2.2.21-3 +- allow change state of BalancerMember in mod_proxy_balancer web interface + +* Thu Sep 22 2011 Ville Skyttä - 2.2.21-2 +- Make mmn available as %%{_httpd_mmn}. +- Add .svgz to AddEncoding x-gzip example in httpd.conf. + +* Tue Sep 13 2011 Joe Orton - 2.2.21-1 +- update to 2.2.21 + +* Mon Sep 5 2011 Joe Orton - 2.2.20-1 +- update to 2.2.20 +- fix MPM stub man page generation + +* Wed Aug 10 2011 Jan Kaluza - 2.2.19-5 +- fix #707917 - add httpd-ssl-pass-dialog to ask for SSL password using systemd + +* Fri Jul 22 2011 Iain Arnell 1:2.2.19-4 +- rebuild while rpm-4.9.1 is untagged to remove trailing slash in provided + directory names + +* Wed Jul 20 2011 Jan Kaluza - 2.2.19-3 +- fix #716621 - suexec now works without setuid bit + +* Thu Jul 14 2011 Jan Kaluza - 2.2.19-2 +- fix #689091 - backported patch from 2.3 branch to support IPv6 in logresolve + +* Fri Jul 1 2011 Joe Orton - 2.2.19-1 +- update to 2.2.19 +- enable dbd, authn_dbd in default config + +* Thu Apr 14 2011 Joe Orton - 2.2.17-13 +- fix path expansion in service files + +* Tue Apr 12 2011 Joe Orton - 2.2.17-12 +- add systemd service files (#684175, thanks to Jóhann B. Guðmundsson) + +* Wed Mar 23 2011 Joe Orton - 2.2.17-11 +- minor updates to httpd.conf +- drop old patches + +* Wed Mar 2 2011 Joe Orton - 2.2.17-10 +- rebuild + +* Wed Feb 23 2011 Joe Orton - 2.2.17-9 +- use arch-specific mmn + +* Wed Feb 09 2011 Fedora Release Engineering - 2.2.17-8 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Mon Jan 31 2011 Joe Orton - 2.2.17-7 +- generate dummy mod_ssl cert with CA:FALSE constraint (#667841) +- add man page stubs for httpd.event, httpd.worker +- drop distcache support +- add STOP_TIMEOUT support to init script + +* Sat Jan 8 2011 Joe Orton - 2.2.17-6 +- update default SSLCipherSuite per upstream trunk + +* Wed Jan 5 2011 Joe Orton - 2.2.17-5 +- fix requires (#667397) + +* Wed Jan 5 2011 Joe Orton - 2.2.17-4 +- de-ghost /var/run/httpd + +* Tue Jan 4 2011 Joe Orton - 2.2.17-3 +- add tmpfiles.d configuration, ghost /var/run/httpd (#656600) + +* Sat Nov 20 2010 Joe Orton - 2.2.17-2 +- drop setuid bit, use capabilities for suexec binary + +* Wed Oct 27 2010 Joe Orton - 2.2.17-1 +- update to 2.2.17 + +* Fri Sep 10 2010 Joe Orton - 2.2.16-2 +- link everything using -z relro and -z now + +* Mon Jul 26 2010 Joe Orton - 2.2.16-1 +- update to 2.2.16 + +* Fri Jul 9 2010 Joe Orton - 2.2.15-3 +- default config tweaks: + * harden httpd.conf w.r.t. .htaccess restriction (#591293) + * load mod_substitute, mod_version by default + * drop proxy_ajp.conf, load mod_proxy_ajp in httpd.conf + * add commented list of shipped-but-unloaded modules + * bump up worker defaults a little + * drop KeepAliveTimeout to 5 secs per upstream +- fix LSB compliance in init script (#522074) +- bundle NOTICE in -tools +- use init script in logrotate postrotate to pick up PIDFILE +- drop some old Obsoletes/Conflicts + +* Sun Apr 04 2010 Robert Scheck - 2.2.15-1 +- update to 2.2.15 (#572404, #579311) +