commit c70039816503574a203f6e86f6dc1f1e31823dc5 Author: James Antill Date: Mon Aug 8 12:28:54 2022 -0400 Import rpm: 692b48d0dcb7d82ec523751d970b07dfeede90a9 diff --git a/.fmf/version b/.fmf/version new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/.fmf/version @@ -0,0 +1 @@ +1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cfbe234 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +SOURCES/apache-poweredby.png +SOURCES/httpd-2.4.37.tar.bz2 diff --git a/00-base.conf b/00-base.conf new file mode 100644 index 0000000..28dacb3 --- /dev/null +++ b/00-base.conf @@ -0,0 +1,68 @@ +# +# 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 brotli_module modules/mod_brotli.so +LoadModule cache_module modules/mod_cache.so +LoadModule cache_disk_module modules/mod_cache_disk.so +LoadModule cache_socache_module modules/mod_cache_socache.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 macro_module modules/mod_macro.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 request_module modules/mod_request.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 watchdog_module modules/mod_watchdog.so + diff --git a/00-brotli.conf b/00-brotli.conf new file mode 100644 index 0000000..c2e0e9e --- /dev/null +++ b/00-brotli.conf @@ -0,0 +1 @@ +LoadModule brotli_module modules/mod_brotli.so diff --git a/00-dav.conf b/00-dav.conf new file mode 100644 index 0000000..e6af8de --- /dev/null +++ b/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/00-lua.conf b/00-lua.conf new file mode 100644 index 0000000..9e0d0db --- /dev/null +++ b/00-lua.conf @@ -0,0 +1 @@ +LoadModule lua_module modules/mod_lua.so diff --git a/00-mpm.conf b/00-mpm.conf new file mode 100644 index 0000000..a4a70b8 --- /dev/null +++ b/00-mpm.conf @@ -0,0 +1,23 @@ +# Select the MPM module which should be used by uncommenting exactly +# one of the following LoadModule lines. See the httpd.conf(5) man +# page for more information on changing the MPM. + +# prefork MPM: Implements a non-threaded, pre-forking web server +# See: http://httpd.apache.org/docs/2.4/mod/prefork.html +# +# NOTE: If enabling prefork, the httpd_graceful_shutdown SELinux +# boolean should be enabled, to allow graceful stop/shutdown. +# +#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/00-optional.conf b/00-optional.conf new file mode 100644 index 0000000..ef584ec --- /dev/null +++ b/00-optional.conf @@ -0,0 +1,18 @@ +# +# This file lists modules included with the Apache HTTP Server +# which are not enabled by default. +# + +#LoadModule asis_module modules/mod_asis.so +#LoadModule buffer_module modules/mod_buffer.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 log_forensic_module modules/mod_log_forensic.so +#LoadModule ratelimit_module modules/mod_ratelimit.so +#LoadModule reflector_module modules/mod_reflector.so +#LoadModule sed_module modules/mod_sed.so +#LoadModule speling_module modules/mod_speling.so diff --git a/00-proxy.conf b/00-proxy.conf new file mode 100644 index 0000000..f0f84c2 --- /dev/null +++ b/00-proxy.conf @@ -0,0 +1,18 @@ +# 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_hcheck_module modules/mod_proxy_hcheck.so +LoadModule proxy_scgi_module modules/mod_proxy_scgi.so +LoadModule proxy_uwsgi_module modules/mod_proxy_uwsgi.so +LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so diff --git a/00-proxyhtml.conf b/00-proxyhtml.conf new file mode 100644 index 0000000..9a9b107 --- /dev/null +++ b/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/00-ssl.conf b/00-ssl.conf new file mode 100644 index 0000000..53235cd --- /dev/null +++ b/00-ssl.conf @@ -0,0 +1 @@ +LoadModule ssl_module modules/mod_ssl.so diff --git a/00-systemd.conf b/00-systemd.conf new file mode 100644 index 0000000..b208c97 --- /dev/null +++ b/00-systemd.conf @@ -0,0 +1,2 @@ +# This file configures systemd module: +LoadModule systemd_module modules/mod_systemd.so diff --git a/01-cgi.conf b/01-cgi.conf new file mode 100644 index 0000000..5b8b936 --- /dev/null +++ b/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/01-ldap.conf b/01-ldap.conf new file mode 100644 index 0000000..f2ac2a2 --- /dev/null +++ b/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/01-session.conf b/01-session.conf new file mode 100644 index 0000000..f8d4d92 --- /dev/null +++ b/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/10-listen443.conf b/10-listen443.conf new file mode 100644 index 0000000..7e2df97 --- /dev/null +++ b/10-listen443.conf @@ -0,0 +1,5 @@ +# This file is part of mod_ssl. It enables listening on port 443 when +# socket activation is used. + +[Socket] +ListenStream=443 diff --git a/README.confd b/README.confd new file mode 100644 index 0000000..6071deb --- /dev/null +++ b/README.confd @@ -0,0 +1,9 @@ + +This directory holds configuration files for the Apache HTTP Server; +any files in this directory which have the ".conf" extension will be +processed as httpd configuration files. The directory is used in +addition to the directory /etc/httpd/conf.modules.d/, which contains +configuration files necessary to load modules. + +Files are processed in sorted order. See httpd.conf(5) for more +information. diff --git a/README.confmod b/README.confmod new file mode 100644 index 0000000..f4b055d --- /dev/null +++ b/README.confmod @@ -0,0 +1,10 @@ + +This directory holds configuration files for the Apache HTTP Server; +any files in this directory which have the ".conf" extension will be +processed as httpd configuration files. This directory contains +configuration fragments necessary only to load modules. +Administrators should use the directory "/etc/httpd/conf.d" to modify +the configuration of httpd, or any modules. + +Files are processed in sorted order and should have a two digit +numeric prefix. See httpd.conf(5) for more information. diff --git a/action-configtest.sh b/action-configtest.sh new file mode 100644 index 0000000..6685b0a --- /dev/null +++ b/action-configtest.sh @@ -0,0 +1,2 @@ +#!/bin/sh +exec /sbin/apachectl configtest "$@" diff --git a/action-graceful.sh b/action-graceful.sh new file mode 100644 index 0000000..dc68b2e --- /dev/null +++ b/action-graceful.sh @@ -0,0 +1,2 @@ +#!/bin/sh +exec /sbin/apachectl graceful "$@" diff --git a/apache-poweredby.png b/apache-poweredby.png new file mode 100644 index 0000000..5663a23 Binary files /dev/null and b/apache-poweredby.png differ diff --git a/apachectl.sh b/apachectl.sh new file mode 100755 index 0000000..823db3b --- /dev/null +++ b/apachectl.sh @@ -0,0 +1,74 @@ +#!/usr/bin/sh +# +# 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. + +### +### NOTE: This is a replacement version of the "apachectl" script with +### some differences in behaviour to the version distributed with +### Apache httpd. Please read the apachectl(8) man page for more +### information. +### + +if [ "x$1" = "x-k" ]; then + shift +fi + +ACMD="$1" +ARGV="$@" +SVC='httpd.service' +HTTPD='@HTTPDBIN@' + +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 To pass extra arguments to httpd, see the $SVC'(8)' + echo man page. + exit 1 +fi + +case $ACMD in +start|stop|restart|status) + /usr/bin/systemctl --no-pager $ACMD $SVC + ERROR=$? + ;; +graceful) + if /usr/bin/systemctl -q is-active $SVC; then + /usr/bin/systemctl kill --signal=SIGUSR1 --kill-who=main $SVC + else + /usr/bin/systemctl start $SVC + fi + ERROR=$? + ;; +graceful-stop) + /usr/bin/systemctl kill --signal=SIGWINCH --kill-who=main $SVC + ERROR=$? + ;; +configtest|-t) + $HTTPD -t + ERROR=$? + ;; +-v|-V) + $HTTPD $ACMD + ERROR=$? + ;; +*) + echo apachectl: The \"$ACMD\" option is not supported. 1>&2 + ERROR=2 + ;; +esac + +exit $ERROR + diff --git a/apachectl.xml b/apachectl.xml new file mode 100644 index 0000000..5e40832 --- /dev/null +++ b/apachectl.xml @@ -0,0 +1,191 @@ + +[ + +]> + + + + apachectl + httpd + Apache man pageApache Software Foundation contributors + Fedora man pageDanaFrank + + + + apachectl + 8 + + + + apachectl + Server control interface for httpd + + + + + apachectl + command + + + + + + + Description + + apachectl is a front end to the Apache HyperText + Transfer Protocol (HTTP) server. It is designed to help the + administrator control the functioning of the Apache + httpd daemon. + + The apachectl script takes one-word arguments like + , + , and + , and translates them + into appropriate signals to httpd. + + The apachectl script returns a 0 exit value on + success, and >0 if an error occurs. + + + Compatibility + + The version of apachectl used on this + system is a replacement script intended to be mostly (but not + completely) compatible with version provided with + Apache httpd. This + apachectl mostly acts as a wrapper around + systemctl and manipulates the + systemd service for httpd. + The interface to the Apache version of + apachectl is described at . + + The following differences are present in the version of + apachectl present on this system: + + + Option arguments passed when starting + httpd are not allowed. These should be + configured in the systemd service directly (see httpd.service8). + + The "fullstatus" option is + not available. + + The "status" option does + not use or rely on the running server's + server-status output. + + + + + + + + Options + + + + + Start the Apache httpd daemon. Gives an error if it + is already running. This is equivalent to systemctl start httpd.service. + + + + + + + Stops the Apache httpd daemon. This is equivalent to + systemctl stop httpd.service. + + + + + + + Restarts the Apache httpd daemon. If the daemon is + not running, it is started. This is equivalent + to systemctl restart httpd.service. + + + + + + + Displays a brief status report. This is equivalent to systemctl status httpd.service. + + + + + + + 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 is equivalent to + systemctl kill --signal=SIGUSR1 --kill-who=main httpd.service. + + + + + + + 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 + systemctl kill --signal=SIGWINCH --kill-who=main httpd.service. + + + + + + + Run a configuration file syntax test. It parses the configuration + files and either reports Syntax OK + or detailed information about the particular syntax error. This is + equivalent to httpd -t. + + + + + + + Bugs + Please report bugs by filing an issue in Bugzilla via . + + + + See also + + + httpd8, + httpd.conf5, + systemd1, + systemctl1, + httpd.service8 + + + + diff --git a/ci.fmf b/ci.fmf new file mode 100644 index 0000000..c5aa0e0 --- /dev/null +++ b/ci.fmf @@ -0,0 +1 @@ +resultsdb-testcase: separate diff --git a/config.layout b/config.layout new file mode 100644 index 0000000..3a9f6c8 --- /dev/null +++ b/config.layout @@ -0,0 +1,24 @@ +# Layout used in Fedora httpd packaging. + + prefix: /etc/httpd + localstatedir: /var + exec_prefix: /usr + bindir: ${exec_prefix}/bin + sbindir: ${exec_prefix}/sbin + libdir: ${exec_prefix}/lib + libexecdir: ${exec_prefix}/libexec + mandir: ${exec_prefix}/man + sysconfdir: /etc/httpd/conf + datadir: ${exec_prefix}/share/httpd + installbuilddir: ${libdir}/httpd/build + errordir: ${datadir}/error + iconsdir: ${datadir}/icons + htdocsdir: ${localstatedir}/www/html + manualdir: ${datadir}/manual + cgidir: ${localstatedir}/www/cgi-bin + includedir: ${exec_prefix}/include/httpd + runtimedir: ${prefix}/run + logfiledir: ${localstatedir}/log/httpd + statedir: ${prefix}/state + proxycachedir: ${localstatedir}/cache/httpd/proxy + diff --git a/gating.yaml b/gating.yaml new file mode 100644 index 0000000..a33ec0c --- /dev/null +++ b/gating.yaml @@ -0,0 +1,11 @@ +--- !Policy +product_versions: + - rhel-9 +decision_context: osci_compose_gate +rules: + - !PassingTestCaseRule {test_case_name: baseos-ci.brew-build.tier1.functional} + - !PassingTestCaseRule {test_case_name: baseos-ci.brew-build.tier2.functional} + - !PassingTestCaseRule {test_case_name: baseos-ci.brew-build.tier3.functional} + - !PassingTestCaseRule {test_case_name: baseos-ci.brew-build.acceptance-tier.functional} + - !PassingTestCaseRule {test_case_name: osci.brew-build./plans/tier1-internal.functional} + diff --git a/htcacheclean.service b/htcacheclean.service new file mode 100644 index 0000000..d1e9d60 --- /dev/null +++ b/htcacheclean.service @@ -0,0 +1,11 @@ +[Unit] +Description=Disk Cache Cleaning Daemon for the Apache HTTP Server +After=httpd.service +Documentation=man:htcacheclean.service(8) + +[Service] +Type=forking +User=apache +PIDFile=/run/httpd/htcacheclean/pid +EnvironmentFile=/etc/sysconfig/htcacheclean +ExecStart=/usr/sbin/htcacheclean -P /run/httpd/htcacheclean/pid -d $INTERVAL -p $CACHE_ROOT -l $LIMIT $OPTIONS diff --git a/htcacheclean.service.xml b/htcacheclean.service.xml new file mode 100644 index 0000000..01b68e4 --- /dev/null +++ b/htcacheclean.service.xml @@ -0,0 +1,123 @@ + + + + + + htcacheclean systemd unit + httpd + AuthorOrtonJoejorton@redhat.com + + + + htcacheclean.service + 8 + + + + htcacheclean.service + htcacheclean unit file for systemd + + + + + /usr/lib/systemd/system/htcacheclean.service + + + + + Description + + This manual page describes the systemd + unit file for the htcacheclean daemon. This + unit file provides a service which runs + htcacheclean in daemon mode, + periodically cleaning the disk cache root to ensure disk space + usage is within configured limits. + + + + + Options + + The service is configured by configuration file + /etc/sysconfig/htcacheclean. The following + variables are used, following standard systemd + EnvironmentFile= syntax: + + + + INTERVAL= + + Sets the interval between cache clean runs, in + minutes. By default this is configured as + 15. + + + + CACHE_ROOT= + + Sets the directory name used for the cache + root. By default this is configured as + /var/cache/httpd/proxy. + + + + LIMIT= + + Sets the total disk cache space limit, in + bytes. Use a K or M + suffix to signify kilobytes or megabytes. By default this is + set to 100M. + + + + OPTIONS= + + Any other options to pass to + htcacheclean. + + + + + + Files + + /usr/lib/systemd/system/htcacheclean.service, + /etc/sysconfig/htcacheclean + + + + See also + + + htcacheclean8, + httpd8, + httpd.service8, + systemd.exec8 + + + + + + diff --git a/htcacheclean.sysconf b/htcacheclean.sysconf new file mode 100644 index 0000000..fffa17b --- /dev/null +++ b/htcacheclean.sysconf @@ -0,0 +1,16 @@ +# +# Configuration options for systemd service, htcacheclean.service. +# See htcacheclean(8) for more information on available options. +# + +# Interval between cache clean runs, in minutes +INTERVAL=15 + +# Default cache root. +CACHE_ROOT=/var/cache/httpd/proxy + +# Cache size limit in bytes (K=Kbytes, M=Mbytes) +LIMIT=100M + +# Any other options... +OPTIONS= diff --git a/httpd-2.4.28-apxs.patch b/httpd-2.4.28-apxs.patch new file mode 100644 index 0000000..7016dec --- /dev/null +++ b/httpd-2.4.28-apxs.patch @@ -0,0 +1,58 @@ +diff --git a/support/apxs.in b/support/apxs.in +index ad1287f..efcfcf6 100644 +--- a/support/apxs.in ++++ b/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 + APACHECTL=apachectl diff --git a/httpd-2.4.28-icons.patch b/httpd-2.4.28-icons.patch new file mode 100644 index 0000000..904d6a4 --- /dev/null +++ b/httpd-2.4.28-icons.patch @@ -0,0 +1,29 @@ + +- 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 + +diff --git a/docs/conf/extra/httpd-autoindex.conf.in b/docs/conf/extra/httpd-autoindex.conf.in +index 51b02ed..dd6f2c6 100644 +--- a/docs/conf/extra/httpd-autoindex.conf.in ++++ b/docs/conf/extra/httpd-autoindex.conf.in +@@ -21,7 +21,7 @@ IndexOptions FancyIndexing HTMLTable VersionSort + Alias /icons/ "@exp_iconsdir@/" + + +- Options Indexes MultiViews ++ Options Indexes MultiViews FollowSymlinks + AllowOverride None + Require all granted + +@@ -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/httpd-2.4.28-r1811831.patch b/httpd-2.4.28-r1811831.patch new file mode 100644 index 0000000..b8d8215 --- /dev/null +++ b/httpd-2.4.28-r1811831.patch @@ -0,0 +1,81 @@ +diff --git a/server/util_script.c b/server/util_script.c +index 4121ae0..b7f8674 100644 +--- a/server/util_script.c ++++ b/server/util_script.c +@@ -92,9 +92,21 @@ static void add_unless_null(apr_table_t *table, const char *name, const char *va + } + } + +-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 @@ AP_DECLARE(void) ap_add_common_vars(request_rec *r) + 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/httpd-2.4.28-socket-activation.patch b/httpd-2.4.28-socket-activation.patch new file mode 100644 index 0000000..dbdd80c --- /dev/null +++ b/httpd-2.4.28-socket-activation.patch @@ -0,0 +1,300 @@ +diff --git a/server/listen.c b/server/listen.c +index a8e9e6f..1a6c1d3 100644 +--- a/server/listen.c ++++ b/server/listen.c +@@ -34,6 +34,10 @@ + #include + #endif + ++#ifdef HAVE_SYSTEMD ++#include ++#endif ++ + /* we know core's module_index is 0 */ + #undef APLOG_MODULE_INDEX + #define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX +@@ -59,9 +63,12 @@ static int ap_listenbacklog; + static int ap_listencbratio; + static int send_buffer_size; + static int receive_buffer_size; ++#ifdef HAVE_SYSTEMD ++static int use_systemd = -1; ++#endif + + /* TODO: make_sock is just begging and screaming for APR abstraction */ +-static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server) ++static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server, int do_bind_listen) + { + apr_socket_t *s = server->sd; + int one = 1; +@@ -94,20 +101,6 @@ static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server) + return stat; + } + +-#if APR_HAVE_IPV6 +- if (server->bind_addr->family == APR_INET6) { +- stat = apr_socket_opt_set(s, APR_IPV6_V6ONLY, v6only_setting); +- if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) { +- ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p, APLOGNO(00069) +- "make_sock: for address %pI, apr_socket_opt_set: " +- "(IPV6_V6ONLY)", +- server->bind_addr); +- apr_socket_close(s); +- return stat; +- } +- } +-#endif +- + /* + * To send data over high bandwidth-delay connections at full + * speed we must force the TCP window to open wide enough to keep the +@@ -169,21 +162,37 @@ static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server) + } + #endif + +- if ((stat = apr_socket_bind(s, server->bind_addr)) != APR_SUCCESS) { +- ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, stat, p, APLOGNO(00072) +- "make_sock: could not bind to address %pI", +- server->bind_addr); +- apr_socket_close(s); +- return stat; +- } ++ if (do_bind_listen) { ++#if APR_HAVE_IPV6 ++ if (server->bind_addr->family == APR_INET6) { ++ stat = apr_socket_opt_set(s, APR_IPV6_V6ONLY, v6only_setting); ++ if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) { ++ ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p, APLOGNO(00069) ++ "make_sock: for address %pI, apr_socket_opt_set: " ++ "(IPV6_V6ONLY)", ++ server->bind_addr); ++ apr_socket_close(s); ++ return stat; ++ } ++ } ++#endif + +- if ((stat = apr_socket_listen(s, ap_listenbacklog)) != APR_SUCCESS) { +- ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_ERR, stat, p, APLOGNO(00073) +- "make_sock: unable to listen for connections " +- "on address %pI", +- server->bind_addr); +- apr_socket_close(s); +- return stat; ++ if ((stat = apr_socket_bind(s, server->bind_addr)) != APR_SUCCESS) { ++ ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, stat, p, APLOGNO(00072) ++ "make_sock: could not bind to address %pI", ++ server->bind_addr); ++ apr_socket_close(s); ++ return stat; ++ } ++ ++ if ((stat = apr_socket_listen(s, ap_listenbacklog)) != APR_SUCCESS) { ++ ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_ERR, stat, p, APLOGNO(00073) ++ "make_sock: unable to listen for connections " ++ "on address %pI", ++ server->bind_addr); ++ apr_socket_close(s); ++ return stat; ++ } + } + + #ifdef WIN32 +@@ -315,6 +324,123 @@ static int find_listeners(ap_listen_rec **from, ap_listen_rec **to, + return found; + } + ++#ifdef HAVE_SYSTEMD ++ ++static int find_systemd_socket(process_rec * process, apr_port_t port) { ++ int fdcount, fd; ++ int sdc = sd_listen_fds(0); ++ ++ if (sdc < 0) { ++ ap_log_perror(APLOG_MARK, APLOG_CRIT, sdc, process->pool, APLOGNO(02486) ++ "find_systemd_socket: Error parsing enviroment, sd_listen_fds returned %d", ++ sdc); ++ return -1; ++ } ++ ++ if (sdc == 0) { ++ ap_log_perror(APLOG_MARK, APLOG_CRIT, sdc, process->pool, APLOGNO(02487) ++ "find_systemd_socket: At least one socket must be set."); ++ return -1; ++ } ++ ++ fdcount = atoi(getenv("LISTEN_FDS")); ++ for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + fdcount; fd++) { ++ if (sd_is_socket_inet(fd, 0, 0, -1, port) > 0) { ++ return fd; ++ } ++ } ++ ++ return -1; ++} ++ ++static apr_status_t alloc_systemd_listener(process_rec * process, ++ int fd, const char *proto, ++ ap_listen_rec **out_rec) ++{ ++ apr_status_t rv; ++ struct sockaddr sa; ++ socklen_t len = sizeof(struct sockaddr); ++ apr_os_sock_info_t si; ++ ap_listen_rec *rec; ++ *out_rec = NULL; ++ ++ memset(&si, 0, sizeof(si)); ++ ++ rv = getsockname(fd, &sa, &len); ++ ++ if (rv != 0) { ++ rv = apr_get_netos_error(); ++ ap_log_perror(APLOG_MARK, APLOG_CRIT, rv, process->pool, APLOGNO(02489) ++ "getsockname on %d failed.", fd); ++ return rv; ++ } ++ ++ si.os_sock = &fd; ++ si.family = sa.sa_family; ++ si.local = &sa; ++ si.type = SOCK_STREAM; ++ si.protocol = APR_PROTO_TCP; ++ ++ rec = apr_palloc(process->pool, sizeof(ap_listen_rec)); ++ rec->active = 0; ++ rec->next = 0; ++ ++ ++ rv = apr_os_sock_make(&rec->sd, &si, process->pool); ++ if (rv != APR_SUCCESS) { ++ ap_log_perror(APLOG_MARK, APLOG_CRIT, rv, process->pool, APLOGNO(02490) ++ "apr_os_sock_make on %d failed.", fd); ++ return rv; ++ } ++ ++ rv = apr_socket_addr_get(&rec->bind_addr, APR_LOCAL, rec->sd); ++ if (rv != APR_SUCCESS) { ++ ap_log_perror(APLOG_MARK, APLOG_CRIT, rv, process->pool, APLOGNO(02491) ++ "apr_socket_addr_get on %d failed.", fd); ++ return rv; ++ } ++ ++ rec->protocol = apr_pstrdup(process->pool, proto); ++ ++ *out_rec = rec; ++ ++ return make_sock(process->pool, rec, 0); ++} ++ ++static const char *set_systemd_listener(process_rec *process, apr_port_t port, ++ const char *proto) ++{ ++ ap_listen_rec *last, *new; ++ apr_status_t rv; ++ int fd = find_systemd_socket(process, port); ++ if (fd < 0) { ++ return "Systemd socket activation is used, but this port is not " ++ "configured in systemd"; ++ } ++ ++ last = ap_listeners; ++ while (last && last->next) { ++ last = last->next; ++ } ++ ++ rv = alloc_systemd_listener(process, fd, proto, &new); ++ if (rv != APR_SUCCESS) { ++ return "Failed to setup socket passed by systemd using socket activation"; ++ } ++ ++ if (last == NULL) { ++ ap_listeners = last = new; ++ } ++ else { ++ last->next = new; ++ last = new; ++ } ++ ++ return NULL; ++} ++ ++#endif /* HAVE_SYSTEMD */ ++ + static const char *alloc_listener(process_rec *process, const char *addr, + apr_port_t port, const char* proto, + void *slave) +@@ -495,7 +621,7 @@ static int open_listeners(apr_pool_t *pool) + } + } + #endif +- if (make_sock(pool, lr) == APR_SUCCESS) { ++ if (make_sock(pool, lr, 1) == APR_SUCCESS) { + ++num_open; + } + else { +@@ -607,8 +733,28 @@ AP_DECLARE(int) ap_setup_listeners(server_rec *s) + } + } + +- if (open_listeners(s->process->pool)) { +- return 0; ++#ifdef HAVE_SYSTEMD ++ if (use_systemd) { ++ const char *userdata_key = "ap_open_systemd_listeners"; ++ void *data; ++ /* clear the enviroment on our second run ++ * so that none of our future children get confused. ++ */ ++ apr_pool_userdata_get(&data, userdata_key, s->process->pool); ++ if (!data) { ++ apr_pool_userdata_set((const void *)1, userdata_key, ++ apr_pool_cleanup_null, s->process->pool); ++ } ++ else { ++ sd_listen_fds(1); ++ } ++ } ++ else ++#endif ++ { ++ if (open_listeners(s->process->pool)) { ++ return 0; ++ } + } + + for (lr = ap_listeners; lr; lr = lr->next) { +@@ -698,7 +844,7 @@ AP_DECLARE(apr_status_t) ap_duplicate_listeners(apr_pool_t *p, server_rec *s, + duplr->bind_addr); + return stat; + } +- make_sock(p, duplr); ++ make_sock(p, duplr, 1); + #if AP_NONBLOCK_WHEN_MULTI_LISTEN + use_nonblock = (ap_listeners && ap_listeners->next); + stat = apr_socket_opt_set(duplr->sd, APR_SO_NONBLOCK, use_nonblock); +@@ -825,6 +971,11 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, + if (argc < 1 || argc > 2) { + return "Listen requires 1 or 2 arguments."; + } ++#ifdef HAVE_SYSTEMD ++ if (use_systemd == -1) { ++ use_systemd = sd_listen_fds(0) > 0; ++ } ++#endif + + rv = apr_parse_addr_port(&host, &scope_id, &port, argv[0], cmd->pool); + if (rv != APR_SUCCESS) { +@@ -856,6 +1007,12 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, + ap_str_tolower(proto); + } + ++#ifdef HAVE_SYSTEMD ++ if (use_systemd) { ++ return set_systemd_listener(cmd->server->process, port, proto); ++ } ++#endif ++ + return alloc_listener(cmd->server->process, host, port, proto, NULL); + } + diff --git a/httpd-2.4.28-statements-comment.patch b/httpd-2.4.28-statements-comment.patch new file mode 100644 index 0000000..65f1bfb --- /dev/null +++ b/httpd-2.4.28-statements-comment.patch @@ -0,0 +1,16 @@ +diff --git a/modules/aaa/mod_access_compat.c b/modules/aaa/mod_access_compat.c +index 3023803..2edf440 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/httpd-2.4.32-export.patch b/httpd-2.4.32-export.patch new file mode 100644 index 0000000..18cdafa --- /dev/null +++ b/httpd-2.4.32-export.patch @@ -0,0 +1,22 @@ + +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 + +diff --git a/server/Makefile.in b/server/Makefile.in +index 1fa3344..f635d76 100644 +--- a/server/Makefile.in ++++ b/server/Makefile.in +@@ -60,9 +60,6 @@ export_files: + ls $$dir/*.h ; \ + done; \ + echo "$(top_srcdir)/server/mpm_fdqueue.h"; \ +- 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/httpd-2.4.34-CVE-2019-9511-and-9516-and-9517.patch b/httpd-2.4.34-CVE-2019-9511-and-9516-and-9517.patch new file mode 100644 index 0000000..7cee845 --- /dev/null +++ b/httpd-2.4.34-CVE-2019-9511-and-9516-and-9517.patch @@ -0,0 +1,19 @@ +diff --git a/server/mpm/event/event.c b/server/mpm/event/event.c +index 16e39be..2543693 100644 +--- a/server/mpm/event/event.c ++++ b/server/mpm/event/event.c +@@ -1111,10 +1111,11 @@ read_request: + "network write failure in core output filter"); + cs->pub.state = CONN_STATE_LINGER; + } +- else if (c->data_in_output_filters) { ++ else if (c->data_in_output_filters || ++ cs->pub.sense == CONN_SENSE_WANT_READ) { + /* Still in WRITE_COMPLETION_STATE: +- * Set a write timeout for this connection, and let the +- * event thread poll for writeability. ++ * Set a read/write timeout for this connection, and let the ++ * event thread poll for read/writeability. + */ + cs->queue_timestamp = apr_time_now(); + notify_suspend(cs); diff --git a/httpd-2.4.35-apachectl.patch b/httpd-2.4.35-apachectl.patch new file mode 100644 index 0000000..f24b834 --- /dev/null +++ b/httpd-2.4.35-apachectl.patch @@ -0,0 +1,113 @@ +diff --git a/docs/man/apachectl.8 b/docs/man/apachectl.8 +index 870a048..32d3ee5 100644 +--- a/docs/man/apachectl.8 ++++ b/docs/man/apachectl.8 +@@ -74,7 +74,7 @@ Restarts the Apache httpd daemon\&. If the daemon is not running, it is started\ + 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 \fBlynx\fR available on your system\&. The URL used to access the status report can be set by editing the \fBSTATUSURL\fR variable in the script\&. + .TP + \fBstatus\fR +-Displays a brief status report\&. Similar to the \fBfullstatus\fR option, except that the list of requests currently being served is omitted\&. ++Displays a brief status report using systemd\&. + .TP + \fBgraceful\fR + 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 \fBconfigtest\fR before initiating the restart to make sure Apache doesn't die\&. This is equivalent to \fBapachectl -k graceful\fR\&. +diff --git a/support/apachectl.in b/support/apachectl.in +index 3281c2e..8ce6f2b 100644 +--- a/support/apachectl.in ++++ b/support/apachectl.in +@@ -44,19 +44,20 @@ 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" ++ + # + # Set this variable to a command that increases the maximum + # number of file descriptors allowed per child process. This is +@@ -76,9 +77,46 @@ 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` /usr/sbin/httpd $OPTIONS -t ++else ++ /usr/sbin/httpd $OPTIONS -t ++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 -k $ARGV ++start|stop|restart|status) ++ /usr/bin/systemctl $ACMD httpd.service ++ ERROR=$? ++ ;; ++graceful) ++ if /usr/bin/systemctl -q is-active httpd.service; then ++ /usr/bin/systemctl reload httpd.service ++ else ++ /usr/bin/systemctl start httpd.service ++ fi ++ ERROR=$? ++ ;; ++graceful-stop) ++ /usr/bin/systemctl stop httpd.service + ERROR=$? + ;; + startssl|sslstart|start-SSL) +@@ -88,17 +126,14 @@ startssl|sslstart|start-SSL) + ERROR=2 + ;; + configtest) +- $HTTPD -t +- ERROR=$? +- ;; +-status) +- $LYNX $STATUSURL | awk ' /process$/ { print; exit } { print } ' ++ testconfig + ;; + fullstatus) ++ checklynx + $LYNX $STATUSURL + ;; + *) +- $HTTPD "$@" ++ /usr/sbin/httpd $OPTIONS "$@" + ERROR=$? + esac + diff --git a/httpd-2.4.35-cachehardmax.patch b/httpd-2.4.35-cachehardmax.patch new file mode 100644 index 0000000..5051099 --- /dev/null +++ b/httpd-2.4.35-cachehardmax.patch @@ -0,0 +1,82 @@ +diff --git a/modules/cache/cache_util.h b/modules/cache/cache_util.h +index 6b92151..4c42a8e 100644 +--- a/modules/cache/cache_util.h ++++ b/modules/cache/cache_util.h +@@ -195,6 +195,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 56a09f5..41015b5 100644 +--- a/modules/cache/mod_cache.c ++++ b/modules/cache/mod_cache.c +@@ -1455,6 +1455,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. */ +@@ -1954,7 +1959,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; + } + +@@ -2004,7 +2011,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; + } + +@@ -2332,12 +2342,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; + } + +@@ -2545,7 +2561,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/httpd-2.4.35-corelimit.patch b/httpd-2.4.35-corelimit.patch new file mode 100644 index 0000000..22768d4 --- /dev/null +++ b/httpd-2.4.35-corelimit.patch @@ -0,0 +1,37 @@ + +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. + +diff --git a/server/core.c b/server/core.c +index aa62e15..ec74029 100644 +--- a/server/core.c ++++ b/server/core.c +@@ -4952,6 +4952,25 @@ static int core_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *pte + } + 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/httpd-2.4.35-deplibs.patch b/httpd-2.4.35-deplibs.patch new file mode 100644 index 0000000..f7bc129 --- /dev/null +++ b/httpd-2.4.35-deplibs.patch @@ -0,0 +1,21 @@ + +Link straight against .la files. + +Upstream-Status: vendor specific + +diff --git a/configure.in b/configure.in +index 9feaceb..82bfeef 100644 +--- a/configure.in ++++ b/configure.in +@@ -784,9 +784,9 @@ 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 --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/httpd-2.4.35-detect-systemd.patch b/httpd-2.4.35-detect-systemd.patch new file mode 100644 index 0000000..60dffb6 --- /dev/null +++ b/httpd-2.4.35-detect-systemd.patch @@ -0,0 +1,77 @@ +diff --git a/Makefile.in b/Makefile.in +index ea8366e..06b8c5a 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -4,7 +4,7 @@ CLEAN_SUBDIRS = test + + PROGRAM_NAME = $(progname) + PROGRAM_SOURCES = modules.c +-PROGRAM_LDADD = buildmark.o $(HTTPD_LDFLAGS) $(PROGRAM_DEPENDENCIES) $(PCRE_LIBS) $(EXTRA_LIBS) $(AP_LIBS) $(LIBS) ++PROGRAM_LDADD = buildmark.o $(HTTPD_LDFLAGS) $(PROGRAM_DEPENDENCIES) $(HTTPD_LIBS) $(EXTRA_LIBS) $(AP_LIBS) $(LIBS) + PROGRAM_PRELINK = $(COMPILE) -c $(top_srcdir)/server/buildmark.c + PROGRAM_DEPENDENCIES = \ + server/libmain.la \ +diff --git a/acinclude.m4 b/acinclude.m4 +index ce1d637..0ad0c13 100644 +--- a/acinclude.m4 ++++ b/acinclude.m4 +@@ -606,6 +606,30 @@ AC_DEFUN([APACHE_CHECK_OPENSSL],[ + fi + ]) + ++AC_DEFUN(APACHE_CHECK_SYSTEMD, [ ++dnl Check for systemd support for listen.c's socket activation. ++case $host in ++*-linux-*) ++ if test -n "$PKGCONFIG" && $PKGCONFIG --exists libsystemd; then ++ SYSTEMD_LIBS=`$PKGCONFIG --libs libsystemd` ++ elif test -n "$PKGCONFIG" && $PKGCONFIG --exists libsystemd-daemon; then ++ SYSTEMD_LIBS=`$PKGCONFIG --libs libsystemd-daemon` ++ else ++ AC_CHECK_LIB(systemd-daemon, sd_notify, SYSTEMD_LIBS="-lsystemd-daemon") ++ fi ++ if test -n "$SYSTEMD_LIBS"; then ++ AC_CHECK_HEADERS(systemd/sd-daemon.h) ++ if test "${ac_cv_header_systemd_sd_daemon_h}" = "no" || test -z "${SYSTEMD_LIBS}"; then ++ AC_MSG_WARN([Your system does not support systemd.]) ++ else ++ APR_ADDTO(HTTPD_LIBS, [$SYSTEMD_LIBS]) ++ AC_DEFINE(HAVE_SYSTEMD, 1, [Define if systemd is supported]) ++ fi ++ fi ++ ;; ++esac ++]) ++ + dnl + dnl APACHE_EXPORT_ARGUMENTS + dnl Export (via APACHE_SUBST) the various path-related variables that +diff --git a/configure.in b/configure.in +index 82bfeef..eedba50 100644 +--- a/configure.in ++++ b/configure.in +@@ -234,6 +234,7 @@ if test "$PCRE_CONFIG" != "false"; then + AC_MSG_NOTICE([Using external PCRE library from $PCRE_CONFIG]) + APR_ADDTO(PCRE_INCLUDES, [`$PCRE_CONFIG --cflags`]) + APR_ADDTO(PCRE_LIBS, [`$PCRE_CONFIG --libs`]) ++ APR_ADDTO(HTTPD_LIBS, [\$(PCRE_LIBS)]) + else + AC_MSG_ERROR([pcre-config for libpcre not found. PCRE is required and available from http://pcre.org/]) + fi +@@ -504,6 +505,8 @@ if test "$ac_cv_struct_tm_gmtoff" = "yes"; then + AC_DEFINE(HAVE_GMTOFF, 1, [Define if struct tm has a tm_gmtoff field]) + fi + ++APACHE_CHECK_SYSTEMD ++ + dnl ## Set up any appropriate OS-specific environment variables for apachectl + + case $host in +@@ -677,6 +680,7 @@ APACHE_SUBST(OS_DIR) + APACHE_SUBST(BUILTIN_LIBS) + APACHE_SUBST(SHLIBPATH_VAR) + APACHE_SUBST(OS_SPECIFIC_VARS) ++APACHE_SUBST(HTTPD_LIBS) + + PRE_SHARED_CMDS='echo ""' + POST_SHARED_CMDS='echo ""' diff --git a/httpd-2.4.35-freebind.patch b/httpd-2.4.35-freebind.patch new file mode 100644 index 0000000..dc34c4e --- /dev/null +++ b/httpd-2.4.35-freebind.patch @@ -0,0 +1,125 @@ +diff --git a/include/ap_listen.h b/include/ap_listen.h +index 58c2574..1a53292 100644 +--- a/include/ap_listen.h ++++ b/include/ap_listen.h +@@ -137,6 +137,9 @@ AP_DECLARE_NONSTD(const char *) ap_set_listenbacklog(cmd_parms *cmd, void *dummy + AP_DECLARE_NONSTD(const char *) ap_set_listencbratio(cmd_parms *cmd, void *dummy, const char *arg); + AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, + int argc, char *const argv[]); ++AP_DECLARE_NONSTD(const char *) ap_set_freelistener(cmd_parms *cmd, void *dummy, ++ int argc, char *const argv[]); ++ + AP_DECLARE_NONSTD(const char *) ap_set_send_buffer_size(cmd_parms *cmd, void *dummy, + const char *arg); + AP_DECLARE_NONSTD(const char *) ap_set_receive_buffer_size(cmd_parms *cmd, +@@ -150,6 +153,8 @@ AP_INIT_TAKE1("ListenCoresBucketsRatio", ap_set_listencbratio, NULL, RSRC_CONF, + "Ratio between the number of CPU cores (online) and the number of listeners buckets"), \ + AP_INIT_TAKE_ARGV("Listen", ap_set_listener, NULL, RSRC_CONF, \ + "A port number or a numeric IP address and a port number, and an optional protocol"), \ ++AP_INIT_TAKE_ARGV("ListenFree", ap_set_freelistener, NULL, RSRC_CONF, \ ++ "A port number or a numeric IP address and a port number, and an optional protocol"), \ + AP_INIT_TAKE1("SendBufferSize", ap_set_send_buffer_size, NULL, RSRC_CONF, \ + "Send buffer size in bytes"), \ + AP_INIT_TAKE1("ReceiveBufferSize", ap_set_receive_buffer_size, NULL, \ +diff --git a/server/listen.c b/server/listen.c +index 1a6c1d3..d375fee 100644 +--- a/server/listen.c ++++ b/server/listen.c +@@ -63,6 +63,7 @@ static int ap_listenbacklog; + static int ap_listencbratio; + static int send_buffer_size; + static int receive_buffer_size; ++static int ap_listenfreebind; + #ifdef HAVE_SYSTEMD + static int use_systemd = -1; + #endif +@@ -162,6 +163,21 @@ static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server, int do_bind_ + } + #endif + ++ ++#if defined(APR_SO_FREEBIND) ++ if (ap_listenfreebind) { ++ if (apr_socket_opt_set(s, APR_SO_FREEBIND, one) < 0) { ++ stat = apr_get_netos_error(); ++ ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p, APLOGNO(02182) ++ "make_sock: apr_socket_opt_set: " ++ "error setting APR_SO_FREEBIND"); ++ apr_socket_close(s); ++ return stat; ++ } ++ } ++#endif ++ ++ + if (do_bind_listen) { + #if APR_HAVE_IPV6 + if (server->bind_addr->family == APR_INET6) { +@@ -956,6 +972,7 @@ AP_DECLARE(void) ap_listen_pre_config(void) + } + } + ++ + AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, + int argc, char *const argv[]) + { +@@ -1016,6 +1033,14 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, + return alloc_listener(cmd->server->process, host, port, proto, NULL); + } + ++AP_DECLARE_NONSTD(const char *) ap_set_freelistener(cmd_parms *cmd, void *dummy, ++ int argc, ++ char *const argv[]) ++{ ++ ap_listenfreebind = 1; ++ return ap_set_listener(cmd, dummy, argc, argv); ++} ++ + AP_DECLARE_NONSTD(const char *) ap_set_listenbacklog(cmd_parms *cmd, + void *dummy, + const char *arg) +diff --git a/docs/manual/mod/mpm_common.html.en b/docs/manual/mod/mpm_common.html.en +index 5d688e4..eb66c19 100644 +--- a/docs/manual/mod/mpm_common.html.en ++++ b/docs/manual/mod/mpm_common.html.en +@@ -42,6 +42,7 @@ more than one multi-processing module (MPM) +
  • EnableExceptionHook
  • +
  • GracefulShutdownTimeout
  • +
  • Listen
  • ++
  • ListenFree
  • +
  • ListenBackLog
  • +
  • ListenCoresBucketsRatio
  • +
  • MaxConnectionsPerChild
  • +@@ -233,6 +234,31 @@ discussion of the Address already in use error message, + including other causes. + + ++ ++
    top
    ++

    ListenFree Directive

    ++ ++ ++ ++ ++ ++ ++ ++
    Description:IP addresses and ports that the server ++listens to. Doesn't require IP address to be up
    Syntax:ListenFree [IP-address:]portnumber [protocol]
    Context:server config
    Status:MPM
    Module:event, worker, prefork, mpm_winnt, mpm_netware, mpmt_os2
    Compatibility:This directive is currently available only in Red Hat Enterprise Linux
    ++

    The ListenFree directive is ++ identical to the Listen directive. ++ The only difference is in the usage of the IP_FREEBIND socket ++ option, which is enabled by default with ListenFree. ++ If IP_FREEBIND is enabled, it allows httpd to bind to an IP ++ address that is nonlocal or does not (yet) exist. This allows httpd to ++ listen on a socket without requiring the underlying network interface ++ or the specified dynamic IP address to be up at the time when httpd ++ is trying to bind to it. ++

    ++
    ++ ++ +
    top
    +

    ListenBackLog Directive

    + + diff --git a/httpd-2.4.35-full-release.patch b/httpd-2.4.35-full-release.patch new file mode 100644 index 0000000..ab8cc2a --- /dev/null +++ b/httpd-2.4.35-full-release.patch @@ -0,0 +1,46 @@ +diff --git a/server/core.c b/server/core.c +index cb8e463..daf76b3 100644 +--- a/server/core.c ++++ b/server/core.c +@@ -3430,6 +3430,7 @@ 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_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; +@@ -3506,7 +3507,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 ")"); + } + +@@ -3514,7 +3518,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 ")"; +@@ -3547,8 +3551,11 @@ static const char *set_serv_tokens(cmd_parms *cmd, void *dummy, + else if (!strcasecmp(arg, "Full")) { + ap_server_tokens = SrvTk_FULL; + } ++ else if (!strcasecmp(arg, "Full-Release")) { ++ ap_server_tokens = SrvTk_FULL_RELEASE; ++ } + else { +- return "ServerTokens takes 1 argument: 'Prod(uctOnly)', 'Major', 'Minor', 'Min(imal)', 'OS', or 'Full'"; ++ return "ServerTokens takes 1 argument: 'Prod(uctOnly)', 'Major', 'Minor', 'Min(imal)', 'OS', 'Full' or 'Full-Release'"; + } + + return NULL; diff --git a/httpd-2.4.35-ocsp-wrong-ctx.patch b/httpd-2.4.35-ocsp-wrong-ctx.patch new file mode 100644 index 0000000..5523ea5 --- /dev/null +++ b/httpd-2.4.35-ocsp-wrong-ctx.patch @@ -0,0 +1,15 @@ +diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c +index a5e86e4..6611610 100644 +--- a/modules/ssl/ssl_engine_kernel.c ++++ b/modules/ssl/ssl_engine_kernel.c +@@ -1823,8 +1823,8 @@ int ssl_callback_SSLVerify(int ok, X509_STORE_CTX *ctx) + /* + * Perform OCSP-based revocation checks + */ +- if (ok && ((sc->server->ocsp_mask & SSL_OCSPCHECK_CHAIN) || +- (errdepth == 0 && (sc->server->ocsp_mask & SSL_OCSPCHECK_LEAF)))) { ++ if (ok && ((mctx->ocsp_mask & SSL_OCSPCHECK_CHAIN) || ++ (errdepth == 0 && (mctx->ocsp_mask & SSL_OCSPCHECK_LEAF)))) { + /* If there was an optional verification error, it's not + * possible to perform OCSP validation since the issuer may be + * missing/untrusted. Fail in that case. */ diff --git a/httpd-2.4.35-r1633085.patch b/httpd-2.4.35-r1633085.patch new file mode 100644 index 0000000..a14b626 --- /dev/null +++ b/httpd-2.4.35-r1633085.patch @@ -0,0 +1,16 @@ +diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c +index d52d5e3..8a57659 100644 +--- a/modules/ssl/ssl_engine_io.c ++++ b/modules/ssl/ssl_engine_io.c +@@ -1415,6 +1415,11 @@ static apr_status_t ssl_io_filter_handshake(ssl_filter_ctx_t *filter_ctx) + "\"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/httpd-2.4.35-r1738878.patch b/httpd-2.4.35-r1738878.patch new file mode 100644 index 0000000..700e80a --- /dev/null +++ b/httpd-2.4.35-r1738878.patch @@ -0,0 +1,140 @@ +diff --git a/modules/proxy/ajp.h b/modules/proxy/ajp.h +index c119a7e..267150a 100644 +--- a/modules/proxy/ajp.h ++++ b/modules/proxy/ajp.h +@@ -413,12 +413,14 @@ apr_status_t ajp_ilink_receive(apr_socket_t *sock, ajp_msg_t *msg); + * @param sock backend socket + * @param r current request + * @param buffsize max size of the AJP packet. ++ * @param secret authentication secret + * @param uri requested uri + * @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 67353a7..680a8f3 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, APLOGNO(03228) +- "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) || +@@ -671,7 +670,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; +@@ -683,7 +683,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 69a35ce..800ede1 100644 +--- a/modules/proxy/mod_proxy.c ++++ b/modules/proxy/mod_proxy.c +@@ -327,6 +327,12 @@ static const char *set_worker_param(apr_pool_t *p, + worker->s->response_field_size = (s ? s : HUGE_STRING_LEN); + worker->s->response_field_size_set = 1; + } ++ 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 { + if (set_worker_hc_param_f) { + return set_worker_hc_param_f(p, s, worker, key, val, NULL); +diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h +index aabd09f..3419023 100644 +--- a/modules/proxy/mod_proxy.h ++++ b/modules/proxy/mod_proxy.h +@@ -357,6 +357,7 @@ PROXY_WORKER_HC_FAIL ) + #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_RFC1035_HOSTNAME_SIZE 256 + +@@ -450,6 +451,7 @@ typedef struct { + hcmethod_t method; /* method to use for health check */ + apr_interval_time_t interval; + char upgrade[PROXY_WORKER_MAX_SCHEME_SIZE];/* upgrade protocol used by mod_proxy_wstunnel */ ++ char secret[PROXY_WORKER_MAX_SECRET_SIZE]; /* authentication secret (e.g. AJP13) */ + char hostname_ex[PROXY_RFC1035_HOSTNAME_SIZE]; /* RFC1035 compliant version of the remote backend address */ + apr_size_t response_field_size; /* Size of proxy response buffer in bytes. */ + unsigned int response_field_size_set:1; +diff --git a/modules/proxy/mod_proxy_ajp.c b/modules/proxy/mod_proxy_ajp.c +index 73716af..6faabea 100644 +--- a/modules/proxy/mod_proxy_ajp.c ++++ b/modules/proxy/mod_proxy_ajp.c +@@ -193,6 +193,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; +@@ -202,12 +203,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/httpd-2.4.35-r1825120.patch b/httpd-2.4.35-r1825120.patch new file mode 100644 index 0000000..6611872 --- /dev/null +++ b/httpd-2.4.35-r1825120.patch @@ -0,0 +1,96 @@ +diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c +index 19cb611..79d5219 100644 +--- a/modules/ssl/ssl_engine_init.c ++++ b/modules/ssl/ssl_engine_init.c +@@ -2070,70 +2070,18 @@ int ssl_proxy_section_post_config(apr_pool_t *p, apr_pool_t *plog, + return OK; + } + +-static int ssl_init_FindCAList_X509NameCmp(const X509_NAME * const *a, +- const X509_NAME * const *b) +-{ +- return(X509_NAME_cmp(*a, *b)); +-} +- +-static void ssl_init_PushCAList(STACK_OF(X509_NAME) *ca_list, +- server_rec *s, apr_pool_t *ptemp, +- const char *file) +-{ +- int n; +- STACK_OF(X509_NAME) *sk; +- +- sk = (STACK_OF(X509_NAME) *) +- SSL_load_client_CA_file(file); +- +- if (!sk) { +- return; +- } +- +- for (n = 0; n < sk_X509_NAME_num(sk); n++) { +- X509_NAME *name = sk_X509_NAME_value(sk, n); +- +- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02209) +- "CA certificate: %s", +- modssl_X509_NAME_to_string(ptemp, name, 0)); +- +- /* +- * note that SSL_load_client_CA_file() checks for duplicates, +- * but since we call it multiple times when reading a directory +- * we must also check for duplicates ourselves. +- */ +- +- if (sk_X509_NAME_find(ca_list, name) < 0) { +- /* this will be freed when ca_list is */ +- sk_X509_NAME_push(ca_list, name); +- } +- else { +- /* need to free this ourselves, else it will leak */ +- X509_NAME_free(name); +- } +- } +- +- sk_X509_NAME_free(sk); +-} +- + STACK_OF(X509_NAME) *ssl_init_FindCAList(server_rec *s, + apr_pool_t *ptemp, + const char *ca_file, + const char *ca_path) + { +- STACK_OF(X509_NAME) *ca_list; +- +- /* +- * Start with a empty stack/list where new +- * entries get added in sorted order. +- */ +- ca_list = sk_X509_NAME_new(ssl_init_FindCAList_X509NameCmp); ++ STACK_OF(X509_NAME) *ca_list = sk_X509_NAME_new_null();; + + /* + * Process CA certificate bundle file + */ + if (ca_file) { +- ssl_init_PushCAList(ca_list, s, ptemp, ca_file); ++ SSL_add_file_cert_subjects_to_stack(ca_list, ca_file); + /* + * If ca_list is still empty after trying to load ca_file + * then the file failed to load, and users should hear about that. +@@ -2168,17 +2116,12 @@ STACK_OF(X509_NAME) *ssl_init_FindCAList(server_rec *s, + continue; /* don't try to load directories */ + } + file = apr_pstrcat(ptemp, ca_path, "/", direntry.name, NULL); +- ssl_init_PushCAList(ca_list, s, ptemp, file); ++ SSL_add_file_cert_subjects_to_stack(ca_list, file); + } + + apr_dir_close(dir); + } + +- /* +- * Cleanup +- */ +- (void) sk_X509_NAME_set_cmp_func(ca_list, NULL); +- + return ca_list; + } + diff --git a/httpd-2.4.35-r1830819+.patch b/httpd-2.4.35-r1830819+.patch new file mode 100644 index 0000000..18ae1d3 --- /dev/null +++ b/httpd-2.4.35-r1830819+.patch @@ -0,0 +1,708 @@ +# ./pullrev.sh 1830819 1830836 1830912 1830913 1830927 1831168 1831173 + +http://svn.apache.org/viewvc?view=revision&revision=1830819 +http://svn.apache.org/viewvc?view=revision&revision=1830912 +http://svn.apache.org/viewvc?view=revision&revision=1830913 +http://svn.apache.org/viewvc?view=revision&revision=1830927 +http://svn.apache.org/viewvc?view=revision&revision=1831168 +http://svn.apache.org/viewvc?view=revision&revision=1831173 +http://svn.apache.org/viewvc?view=revision&revision=1835240 +http://svn.apache.org/viewvc?view=revision&revision=1835242 +http://svn.apache.org/viewvc?view=revision&revision=1835615 + +diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c +index 43397f9..ff8f429 100644 +--- httpd-2.4.35/modules/ssl/ssl_engine_config.c.r1830819+ ++++ httpd-2.4.35/modules/ssl/ssl_engine_config.c +@@ -899,7 +899,9 @@ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + const char *err; + +- if ((err = ssl_cmd_check_file(cmd, &arg))) { ++ /* Only check for non-ENGINE based certs. */ ++ if (!modssl_is_engine_id(arg) ++ && (err = ssl_cmd_check_file(cmd, &arg))) { + return err; + } + +@@ -915,7 +917,9 @@ + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + const char *err; + +- if ((err = ssl_cmd_check_file(cmd, &arg))) { ++ /* Check keyfile exists for non-ENGINE keys. */ ++ if (!modssl_is_engine_id(arg) ++ && (err = ssl_cmd_check_file(cmd, &arg))) { + return err; + } + +--- httpd-2.4.35/modules/ssl/ssl_engine_init.c.r1830819+ ++++ httpd-2.4.35/modules/ssl/ssl_engine_init.c +@@ -1186,12 +1186,18 @@ + (certfile = APR_ARRAY_IDX(mctx->pks->cert_files, i, + const char *)); + i++) { ++ EVP_PKEY *pkey; ++ const char *engine_certfile = NULL; ++ + key_id = apr_psprintf(ptemp, "%s:%d", vhost_id, i); + + ERR_clear_error(); + + /* first the certificate (public key) */ +- if (mctx->cert_chain) { ++ if (modssl_is_engine_id(certfile)) { ++ engine_certfile = certfile; ++ } ++ else if (mctx->cert_chain) { + if ((SSL_CTX_use_certificate_file(mctx->ssl_ctx, certfile, + SSL_FILETYPE_PEM) < 1)) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02561) +@@ -1220,12 +1226,46 @@ + + ERR_clear_error(); + +- if ((SSL_CTX_use_PrivateKey_file(mctx->ssl_ctx, keyfile, +- SSL_FILETYPE_PEM) < 1) && +- (ERR_GET_FUNC(ERR_peek_last_error()) +- != X509_F_X509_CHECK_PRIVATE_KEY)) { ++ if (modssl_is_engine_id(keyfile)) { ++ apr_status_t rv; ++ ++ cert = NULL; ++ ++ if ((rv = modssl_load_engine_keypair(s, ptemp, vhost_id, ++ engine_certfile, keyfile, ++ &cert, &pkey))) { ++ return rv; ++ } ++ ++ if (cert) { ++ if (SSL_CTX_use_certificate(mctx->ssl_ctx, cert) < 1) { ++ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10137) ++ "Failed to configure engine certificate %s, check %s", ++ key_id, certfile); ++ ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); ++ return APR_EGENERAL; ++ } ++ ++ /* SSL_CTX now owns the cert. */ ++ X509_free(cert); ++ } ++ ++ if (SSL_CTX_use_PrivateKey(mctx->ssl_ctx, pkey) < 1) { ++ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10130) ++ "Failed to configure private key %s from engine", ++ keyfile); ++ ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); ++ return APR_EGENERAL; ++ } ++ ++ /* SSL_CTX now owns the key */ ++ EVP_PKEY_free(pkey); ++ } ++ else if ((SSL_CTX_use_PrivateKey_file(mctx->ssl_ctx, keyfile, ++ SSL_FILETYPE_PEM) < 1) ++ && (ERR_GET_FUNC(ERR_peek_last_error()) ++ != X509_F_X509_CHECK_PRIVATE_KEY)) { + ssl_asn1_t *asn1; +- EVP_PKEY *pkey; + const unsigned char *ptr; + + ERR_clear_error(); +@@ -1312,8 +1352,9 @@ + /* + * Try to read DH parameters from the (first) SSLCertificateFile + */ +- if ((certfile = APR_ARRAY_IDX(mctx->pks->cert_files, 0, const char *)) && +- (dhparams = ssl_dh_GetParamFromFile(certfile))) { ++ certfile = APR_ARRAY_IDX(mctx->pks->cert_files, 0, const char *); ++ if (certfile && !modssl_is_engine_id(certfile) ++ && (dhparams = ssl_dh_GetParamFromFile(certfile))) { + 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", +@@ -1325,10 +1366,10 @@ + /* + * Similarly, try to read the ECDH curve name from SSLCertificateFile... + */ +- if ((certfile != NULL) && +- (ecparams = ssl_ec_GetParamFromFile(certfile)) && +- (nid = EC_GROUP_get_curve_name(ecparams)) && +- (eckey = EC_KEY_new_by_curve_name(nid))) { ++ if (certfile && !modssl_is_engine_id(certfile) ++ && (ecparams = ssl_ec_GetParamFromFile(certfile)) ++ && (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", +--- httpd-2.4.35/modules/ssl/ssl_engine_pphrase.c.r1830819+ ++++ httpd-2.4.35/modules/ssl/ssl_engine_pphrase.c +@@ -143,9 +143,6 @@ + const char *key_id = asn1_table_vhost_key(mc, p, sc->vhost_id, idx); + EVP_PKEY *pPrivateKey = NULL; + ssl_asn1_t *asn1; +- unsigned char *ucp; +- long int length; +- BOOL bReadable; + int nPassPhrase = (*pphrases)->nelts; + int nPassPhraseRetry = 0; + apr_time_t pkey_mtime = 0; +@@ -222,16 +219,12 @@ + * is not empty. */ + ERR_clear_error(); + +- bReadable = ((pPrivateKey = modssl_read_privatekey(ppcb_arg.pkey_file, +- NULL, ssl_pphrase_Handle_CB, &ppcb_arg)) != NULL ? +- TRUE : FALSE); +- +- /* +- * when the private key file now was readable, +- * it's fine and we go out of the loop +- */ +- if (bReadable) +- break; ++ pPrivateKey = modssl_read_privatekey(ppcb_arg.pkey_file, ++ ssl_pphrase_Handle_CB, &ppcb_arg); ++ /* If the private key was successfully read, nothing more to ++ do here. */ ++ if (pPrivateKey != NULL) ++ break; + + /* + * when we have more remembered pass phrases +@@ -356,19 +349,12 @@ + nPassPhrase++; + } + +- /* +- * Insert private key into the global module configuration +- * (we convert it to a stand-alone DER byte sequence +- * because the SSL library uses static variables inside a +- * RSA structure which do not survive DSO reloads!) +- */ +- length = i2d_PrivateKey(pPrivateKey, NULL); +- ucp = ssl_asn1_table_set(mc->tPrivateKey, key_id, length); +- (void)i2d_PrivateKey(pPrivateKey, &ucp); /* 2nd arg increments */ ++ /* Cache the private key in the global module configuration so it ++ * can be used after subsequent reloads. */ ++ asn1 = ssl_asn1_table_set(mc->tPrivateKey, key_id, pPrivateKey); + + if (ppcb_arg.nPassPhraseDialogCur != 0) { + /* remember mtime of encrypted keys */ +- asn1 = ssl_asn1_table_get(mc->tPrivateKey, key_id); + asn1->source_mtime = pkey_mtime; + } + +@@ -619,3 +605,303 @@ + */ + return (len); + } ++ ++ ++#if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT) ++ ++/* OpenSSL UI implementation for passphrase entry; largely duplicated ++ * from ssl_pphrase_Handle_CB but adjusted for UI API. TODO: Might be ++ * worth trying to shift pphrase handling over to the UI API ++ * completely. */ ++static int passphrase_ui_open(UI *ui) ++{ ++ pphrase_cb_arg_t *ppcb = UI_get0_user_data(ui); ++ SSLSrvConfigRec *sc = mySrvConfig(ppcb->s); ++ ++ ppcb->nPassPhraseDialog++; ++ ppcb->nPassPhraseDialogCur++; ++ ++ /* ++ * Builtin or Pipe dialog ++ */ ++ if (sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN ++ || sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE) { ++ if (sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE) { ++ if (!readtty) { ++ ap_log_error(APLOG_MARK, APLOG_INFO, 0, ppcb->s, ++ APLOGNO(10143) ++ "Init: Creating pass phrase dialog pipe child " ++ "'%s'", sc->server->pphrase_dialog_path); ++ if (ssl_pipe_child_create(ppcb->p, ++ sc->server->pphrase_dialog_path) ++ != APR_SUCCESS) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, 0, ppcb->s, ++ APLOGNO(10144) ++ "Init: Failed to create pass phrase pipe '%s'", ++ sc->server->pphrase_dialog_path); ++ return 0; ++ } ++ } ++ ap_log_error(APLOG_MARK, APLOG_INFO, 0, ppcb->s, APLOGNO(10145) ++ "Init: Requesting pass phrase via piped dialog"); ++ } ++ else { /* sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN */ ++#ifdef WIN32 ++ ap_log_error(APLOG_MARK, APLOG_ERR, 0, ppcb->s, APLOGNO(10146) ++ "Init: Failed to create pass phrase pipe '%s'", ++ sc->server->pphrase_dialog_path); ++ return 0; ++#else ++ /* ++ * stderr has already been redirected to the error_log. ++ * rather than attempting to temporarily rehook it to the terminal, ++ * we print the prompt to stdout before EVP_read_pw_string turns ++ * off tty echo ++ */ ++ apr_file_open_stdout(&writetty, ppcb->p); ++ ++ ap_log_error(APLOG_MARK, APLOG_INFO, 0, ppcb->s, APLOGNO(10147) ++ "Init: Requesting pass phrase via builtin terminal " ++ "dialog"); ++#endif ++ } ++ ++ /* ++ * The first time display a header to inform the user about what ++ * program he actually speaks to, which module is responsible for ++ * this terminal dialog and why to the hell he has to enter ++ * something... ++ */ ++ if (ppcb->nPassPhraseDialog == 1) { ++ apr_file_printf(writetty, "%s mod_ssl (Pass Phrase Dialog)\n", ++ AP_SERVER_BASEVERSION); ++ apr_file_printf(writetty, ++ "A pass phrase is required to access the private key.\n"); ++ } ++ if (ppcb->bPassPhraseDialogOnce) { ++ ppcb->bPassPhraseDialogOnce = FALSE; ++ apr_file_printf(writetty, "\n"); ++ apr_file_printf(writetty, "Private key %s (%s)\n", ++ ppcb->key_id, ppcb->pkey_file); ++ } ++ } ++ ++ return 1; ++} ++ ++static int passphrase_ui_read(UI *ui, UI_STRING *uis) ++{ ++ pphrase_cb_arg_t *ppcb = UI_get0_user_data(ui); ++ SSLSrvConfigRec *sc = mySrvConfig(ppcb->s); ++ const char *prompt; ++ int i; ++ int bufsize; ++ int len; ++ char *buf; ++ ++ prompt = UI_get0_output_string(uis); ++ if (prompt == NULL) { ++ prompt = "Enter pass phrase:"; ++ } ++ ++ /* ++ * Get the maximum expected size and allocate the buffer ++ */ ++ bufsize = UI_get_result_maxsize(uis); ++ buf = apr_pcalloc(ppcb->p, bufsize); ++ ++ if (sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN ++ || sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE) { ++ /* ++ * Get the pass phrase through a callback. ++ * Empty input is not accepted. ++ */ ++ for (;;) { ++ if (sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE) { ++ i = pipe_get_passwd_cb(buf, bufsize, "", FALSE); ++ } ++ else { /* sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN */ ++ i = EVP_read_pw_string(buf, bufsize, "", FALSE); ++ } ++ if (i != 0) { ++ OPENSSL_cleanse(buf, bufsize); ++ return 0; ++ } ++ len = strlen(buf); ++ if (len < 1){ ++ apr_file_printf(writetty, "Apache:mod_ssl:Error: Pass phrase" ++ "empty (needs to be at least 1 character).\n"); ++ apr_file_puts(prompt, writetty); ++ } ++ else { ++ break; ++ } ++ } ++ } ++ /* ++ * Filter program ++ */ ++ else if (sc->server->pphrase_dialog_type == SSL_PPTYPE_FILTER) { ++ const char *cmd = sc->server->pphrase_dialog_path; ++ const char **argv = apr_palloc(ppcb->p, sizeof(char *) * 3); ++ char *result; ++ ++ ap_log_error(APLOG_MARK, APLOG_INFO, 0, ppcb->s, APLOGNO(10148) ++ "Init: Requesting pass phrase from dialog filter " ++ "program (%s)", cmd); ++ ++ argv[0] = cmd; ++ argv[1] = ppcb->key_id; ++ argv[2] = NULL; ++ ++ result = ssl_util_readfilter(ppcb->s, ppcb->p, cmd, argv); ++ apr_cpystrn(buf, result, bufsize); ++ len = strlen(buf); ++ } ++ ++ /* ++ * Ok, we now have the pass phrase, so give it back ++ */ ++ ppcb->cpPassPhraseCur = apr_pstrdup(ppcb->p, buf); ++ UI_set_result(ui, uis, buf); ++ ++ /* Clear sensitive data. */ ++ OPENSSL_cleanse(buf, bufsize); ++ return 1; ++} ++ ++static int passphrase_ui_write(UI *ui, UI_STRING *uis) ++{ ++ pphrase_cb_arg_t *ppcb = UI_get0_user_data(ui); ++ SSLSrvConfigRec *sc; ++ const char *prompt; ++ ++ sc = mySrvConfig(ppcb->s); ++ ++ if (sc->server->pphrase_dialog_type == SSL_PPTYPE_BUILTIN ++ || sc->server->pphrase_dialog_type == SSL_PPTYPE_PIPE) { ++ prompt = UI_get0_output_string(uis); ++ apr_file_puts(prompt, writetty); ++ } ++ ++ return 1; ++} ++ ++static int passphrase_ui_close(UI *ui) ++{ ++ /* ++ * Close the pipes if they were opened ++ */ ++ if (readtty) { ++ apr_file_close(readtty); ++ apr_file_close(writetty); ++ readtty = writetty = NULL; ++ } ++ return 1; ++} ++ ++static apr_status_t pp_ui_method_cleanup(void *uip) ++{ ++ UI_METHOD *uim = uip; ++ ++ UI_destroy_method(uim); ++ ++ return APR_SUCCESS; ++} ++ ++static UI_METHOD *get_passphrase_ui(apr_pool_t *p) ++{ ++ UI_METHOD *ui_method = UI_create_method("Passphrase UI"); ++ ++ UI_method_set_opener(ui_method, passphrase_ui_open); ++ UI_method_set_reader(ui_method, passphrase_ui_read); ++ UI_method_set_writer(ui_method, passphrase_ui_write); ++ UI_method_set_closer(ui_method, passphrase_ui_close); ++ ++ apr_pool_cleanup_register(p, ui_method, pp_ui_method_cleanup, ++ pp_ui_method_cleanup); ++ ++ return ui_method; ++} ++ ++ ++apr_status_t modssl_load_engine_keypair(server_rec *s, apr_pool_t *p, ++ const char *vhostid, ++ const char *certid, const char *keyid, ++ X509 **pubkey, EVP_PKEY **privkey) ++{ ++ const char *c, *scheme; ++ ENGINE *e; ++ UI_METHOD *ui_method = get_passphrase_ui(p); ++ pphrase_cb_arg_t ppcb; ++ ++ memset(&ppcb, 0, sizeof ppcb); ++ ppcb.s = s; ++ ppcb.p = p; ++ ppcb.bPassPhraseDialogOnce = TRUE; ++ ppcb.key_id = vhostid; ++ ppcb.pkey_file = keyid; ++ ++ c = ap_strchr_c(keyid, ':'); ++ if (!c || c == keyid) { ++ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10131) ++ "Init: Unrecognized private key identifier `%s'", ++ keyid); ++ return ssl_die(s); ++ } ++ ++ scheme = apr_pstrmemdup(p, keyid, c - keyid); ++ if (!(e = ENGINE_by_id(scheme))) { ++ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10132) ++ "Init: Failed to load engine for private key %s", ++ keyid); ++ ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); ++ return ssl_die(s); ++ } ++ ++ if (!ENGINE_init(e)) { ++ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10149) ++ "Init: Failed to initialize engine %s for private key %s", ++ scheme, keyid); ++ ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); ++ return ssl_die(s); ++ } ++ ++ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, ++ "Init: Initialized engine %s for private key %s", ++ scheme, keyid); ++ ++ if (APLOGdebug(s)) { ++ ENGINE_ctrl_cmd_string(e, "VERBOSE", NULL, 0); ++ } ++ ++ if (certid) { ++ struct { ++ const char *cert_id; ++ X509 *cert; ++ } params = { certid, NULL }; ++ ++ if (!ENGINE_ctrl_cmd(e, "LOAD_CERT_CTRL", 0, ¶ms, NULL, 1)) { ++ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10136) ++ "Init: Unable to get the certificate"); ++ ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); ++ return ssl_die(s); ++ } ++ ++ *pubkey = params.cert; ++ } ++ ++ *privkey = ENGINE_load_private_key(e, keyid, ui_method, &ppcb); ++ if (*privkey == NULL) { ++ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10133) ++ "Init: Unable to get the private key"); ++ ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); ++ return ssl_die(s); ++ } ++ ++ ENGINE_finish(e); ++ ENGINE_free(e); ++ ++ return APR_SUCCESS; ++} ++#endif +--- httpd-2.4.35/modules/ssl/ssl_private.h.r1830819+ ++++ httpd-2.4.35/modules/ssl/ssl_private.h +@@ -986,21 +986,28 @@ + apr_status_t ssl_load_encrypted_pkey(server_rec *, apr_pool_t *, int, + const char *, apr_array_header_t **); + ++/* Load public and/or private key from the configured ENGINE. Private ++ * key returned as *pkey. certid can be NULL, in which case *pubkey ++ * is not altered. Errors logged on failure. */ ++apr_status_t modssl_load_engine_keypair(server_rec *s, apr_pool_t *p, ++ const char *vhostid, ++ const char *certid, const char *keyid, ++ X509 **pubkey, EVP_PKEY **privkey); ++ + /** Diffie-Hellman Parameter Support */ + DH *ssl_dh_GetParamFromFile(const char *); + #ifdef HAVE_ECC + EC_GROUP *ssl_ec_GetParamFromFile(const char *); + #endif + +-unsigned char *ssl_asn1_table_set(apr_hash_t *table, +- const char *key, +- long int length); +- +-ssl_asn1_t *ssl_asn1_table_get(apr_hash_t *table, +- const char *key); +- +-void ssl_asn1_table_unset(apr_hash_t *table, +- const char *key); ++/* Store the EVP_PKEY key (serialized into DER) in the hash table with ++ * key, returning the ssl_asn1_t structure pointer. */ ++ssl_asn1_t *ssl_asn1_table_set(apr_hash_t *table, const char *key, ++ EVP_PKEY *pkey); ++/* Retrieve the ssl_asn1_t structure with given key from the hash. */ ++ssl_asn1_t *ssl_asn1_table_get(apr_hash_t *table, const char *key); ++/* Remove and free the ssl_asn1_t structure with given key. */ ++void ssl_asn1_table_unset(apr_hash_t *table, const char *key); + + /** Mutex Support */ + int ssl_mutex_init(server_rec *, apr_pool_t *); +@@ -1088,6 +1095,10 @@ + int ssl_is_challenge(conn_rec *c, const char *servername, + X509 **pcert, EVP_PKEY **pkey); + ++/* Returns non-zero if the cert/key filename should be handled through ++ * the configured ENGINE. */ ++int modssl_is_engine_id(const char *name); ++ + #endif /* SSL_PRIVATE_H */ + /** @} */ + +--- httpd-2.4.35/modules/ssl/ssl_util.c.r1830819+ ++++ httpd-2.4.35/modules/ssl/ssl_util.c +@@ -175,45 +175,37 @@ + return TRUE; + } + +-/* +- * certain key data needs to survive restarts, +- * which are stored in the user data table of s->process->pool. +- * to prevent "leaking" of this data, we use malloc/free +- * rather than apr_palloc and these wrappers to help make sure +- * we do not leak the malloc-ed data. +- */ +-unsigned char *ssl_asn1_table_set(apr_hash_t *table, +- const char *key, +- long int length) ++/* Decrypted private keys are cached to survive restarts. The cached ++ * data must have lifetime of the process (hence malloc/free rather ++ * than pools), and uses raw DER since the EVP_PKEY structure ++ * internals may not survive across a module reload. */ ++ssl_asn1_t *ssl_asn1_table_set(apr_hash_t *table, const char *key, ++ EVP_PKEY *pkey) + { + apr_ssize_t klen = strlen(key); + ssl_asn1_t *asn1 = apr_hash_get(table, key, klen); ++ apr_size_t length = i2d_PrivateKey(pkey, NULL); ++ unsigned char *p; + +- /* +- * if a value for this key already exists, +- * reuse as much of the already malloc-ed data +- * as possible. +- */ ++ /* Re-use structure if cached previously. */ + if (asn1) { + if (asn1->nData != length) { +- free(asn1->cpData); /* XXX: realloc? */ +- asn1->cpData = NULL; ++ asn1->cpData = ap_realloc(asn1->cpData, length); + } + } + else { + asn1 = ap_malloc(sizeof(*asn1)); + asn1->source_mtime = 0; /* used as a note for encrypted private keys */ +- asn1->cpData = NULL; +- } +- +- asn1->nData = length; +- if (!asn1->cpData) { + asn1->cpData = ap_malloc(length); ++ ++ apr_hash_set(table, key, klen, asn1); + } + +- apr_hash_set(table, key, klen, asn1); ++ asn1->nData = length; ++ p = asn1->cpData; ++ i2d_PrivateKey(pkey, &p); /* increases p by length */ + +- return asn1->cpData; /* caller will assign a value to this */ ++ return asn1; + } + + ssl_asn1_t *ssl_asn1_table_get(apr_hash_t *table, +@@ -463,3 +455,13 @@ + } + + #endif /* #if APR_HAS_THREADS && MODSSL_USE_OPENSSL_PRE_1_1_API */ ++ ++int modssl_is_engine_id(const char *name) ++{ ++#if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT) ++ /* ### Can handle any other special ENGINE key names here? */ ++ return strncmp(name, "pkcs11:", 7) == 0; ++#else ++ return 0; ++#endif ++} +--- httpd-2.4.35/modules/ssl/ssl_util_ssl.c.r1830819+ ++++ httpd-2.4.35/modules/ssl/ssl_util_ssl.c +@@ -74,7 +74,7 @@ + ** _________________________________________________________________ + */ + +-EVP_PKEY *modssl_read_privatekey(const char* filename, EVP_PKEY **key, pem_password_cb *cb, void *s) ++EVP_PKEY *modssl_read_privatekey(const char *filename, pem_password_cb *cb, void *s) + { + EVP_PKEY *rc; + BIO *bioS; +@@ -83,7 +83,7 @@ + /* 1. try PEM (= DER+Base64+headers) */ + if ((bioS=BIO_new_file(filename, "r")) == NULL) + return NULL; +- rc = PEM_read_bio_PrivateKey(bioS, key, cb, s); ++ rc = PEM_read_bio_PrivateKey(bioS, NULL, cb, s); + BIO_free(bioS); + + if (rc == NULL) { +@@ -107,41 +107,9 @@ + BIO_free(bioS); + } + } +- if (rc != NULL && key != NULL) { +- if (*key != NULL) +- EVP_PKEY_free(*key); +- *key = rc; +- } + return rc; + } + +-typedef struct { +- const char *pass; +- int pass_len; +-} pass_ctx; +- +-static int provide_pass(char *buf, int size, int rwflag, void *baton) +-{ +- pass_ctx *ctx = baton; +- if (ctx->pass_len > 0) { +- if (ctx->pass_len < size) { +- size = (int)ctx->pass_len; +- } +- memcpy(buf, ctx->pass, size); +- } +- return ctx->pass_len; +-} +- +-EVP_PKEY *modssl_read_encrypted_pkey(const char *filename, EVP_PKEY **key, +- const char *pass, apr_size_t pass_len) +-{ +- pass_ctx ctx; +- +- ctx.pass = pass; +- ctx.pass_len = pass_len; +- return modssl_read_privatekey(filename, key, provide_pass, &ctx); +-} +- + /* _________________________________________________________________ + ** + ** Smart shutdown +--- httpd-2.4.35/modules/ssl/ssl_util_ssl.h.r1830819+ ++++ httpd-2.4.35/modules/ssl/ssl_util_ssl.h +@@ -64,8 +64,11 @@ + void modssl_init_app_data2_idx(void); + void *modssl_get_app_data2(SSL *); + void modssl_set_app_data2(SSL *, void *); +-EVP_PKEY *modssl_read_privatekey(const char *, EVP_PKEY **, pem_password_cb *, void *); +-EVP_PKEY *modssl_read_encrypted_pkey(const char *, EVP_PKEY **, const char *, apr_size_t); ++ ++/* Read private key from filename in either PEM or raw base64(DER) ++ * format, using password entry callback cb and userdata. */ ++EVP_PKEY *modssl_read_privatekey(const char *filename, pem_password_cb *cb, void *ud); ++ + int modssl_smart_shutdown(SSL *ssl); + BOOL modssl_X509_getBC(X509 *, int *, int *); + char *modssl_X509_NAME_ENTRY_to_string(apr_pool_t *p, X509_NAME_ENTRY *xsne, diff --git a/httpd-2.4.35-r1842888.patch b/httpd-2.4.35-r1842888.patch new file mode 100644 index 0000000..02a25dc --- /dev/null +++ b/httpd-2.4.35-r1842888.patch @@ -0,0 +1,22 @@ +diff --git a/modules/filters/mod_deflate.c b/modules/filters/mod_deflate.c +index d218bab..9f86b09 100644 +--- a/modules/filters/mod_deflate.c ++++ b/modules/filters/mod_deflate.c +@@ -864,7 +864,7 @@ static apr_status_t deflate_out_filter(ap_filter_t *f, + + if (c->note_output_name) { + apr_table_setn(r->notes, c->note_output_name, +- (ctx->stream.total_in > 0) ++ (ctx->stream.total_out > 0) + ? apr_off_t_toa(r->pool, + ctx->stream.total_out) + : "-"); +@@ -1336,8 +1336,6 @@ static apr_status_t deflate_in_filter(ap_filter_t *f, + ctx->stream.next_in = (unsigned char *)data; + ctx->stream.avail_in = (int)len; + +- zRC = Z_OK; +- + if (!ctx->validation_buffer) { + while (ctx->stream.avail_in != 0) { + if (ctx->stream.avail_out == 0) { diff --git a/httpd-2.4.35-selinux.patch b/httpd-2.4.35-selinux.patch new file mode 100644 index 0000000..574259b --- /dev/null +++ b/httpd-2.4.35-selinux.patch @@ -0,0 +1,65 @@ + +Log the SELinux context at startup. + +Upstream-Status: unlikely to be any interest in this upstream + +diff --git a/configure.in b/configure.in +index eedba50..a208b53 100644 +--- a/configure.in ++++ b/configure.in +@@ -484,6 +484,11 @@ getloadavg + 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(HTTPD_LIBS, [-lselinux]) ++]) ++ + AC_CACHE_CHECK([for gettid()], ac_cv_gettid, + [AC_TRY_RUN(#define _GNU_SOURCE + #include +diff --git a/server/core.c b/server/core.c +index ec74029..cb8e463 100644 +--- a/server/core.c ++++ b/server/core.c +@@ -59,6 +59,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) +@@ -4971,6 +4975,28 @@ static int core_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *pte + } + #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/httpd-2.4.35-sslciphdefault.patch b/httpd-2.4.35-sslciphdefault.patch new file mode 100644 index 0000000..9e740dd --- /dev/null +++ b/httpd-2.4.35-sslciphdefault.patch @@ -0,0 +1,31 @@ +diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c +index 4cfd2d0..6ac55bd 100644 +--- a/modules/ssl/ssl_engine_config.c ++++ b/modules/ssl/ssl_engine_config.c +@@ -776,9 +776,11 @@ const char *ssl_cmd_SSLCipherSuite(cmd_parms *cmd, + } + + if (!strcmp("SSL", arg1)) { +- /* always disable null and export ciphers */ +- arg2 = apr_pstrcat(cmd->pool, arg2, ":!aNULL:!eNULL:!EXP", NULL); + if (cmd->path) { ++ /* Disable null and export ciphers by default, except for PROFILE= ++ * configs where the parser doesn't cope. */ ++ if (strncmp(arg2, "PROFILE=", 8) != 0) ++ arg2 = apr_pstrcat(cmd->pool, arg2, ":!aNULL:!eNULL:!EXP", NULL); + dc->szCipherSuite = arg2; + } + else { +@@ -1542,8 +1544,10 @@ const char *ssl_cmd_SSLProxyCipherSuite(cmd_parms *cmd, + } + + if (!strcmp("SSL", arg1)) { +- /* always disable null and export ciphers */ +- arg2 = apr_pstrcat(cmd->pool, arg2, ":!aNULL:!eNULL:!EXP", NULL); ++ /* Disable null and export ciphers by default, except for PROFILE= ++ * configs where the parser doesn't cope. */ ++ if (strncmp(arg2, "PROFILE=", 8) != 0) ++ arg2 = apr_pstrcat(cmd->pool, arg2, ":!aNULL:!eNULL:!EXP", NULL); + dc->proxy->auth.cipher_suite = arg2; + return NULL; + } diff --git a/httpd-2.4.35-systemd.patch b/httpd-2.4.35-systemd.patch new file mode 100644 index 0000000..7f5ee3b --- /dev/null +++ b/httpd-2.4.35-systemd.patch @@ -0,0 +1,245 @@ +--- httpd-2.4.33/modules/arch/unix/config5.m4.systemd ++++ httpd-2.4.33/modules/arch/unix/config5.m4 +@@ -18,6 +18,16 @@ + fi + ]) + ++APACHE_MODULE(systemd, Systemd support, , , all, [ ++ if test "${ac_cv_header_systemd_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.33/modules/arch/unix/mod_systemd.c.systemd ++++ httpd-2.4.33/modules/arch/unix/mod_systemd.c +@@ -0,0 +1,223 @@ ++/* 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 ++#include "unixd.h" ++#include "scoreboard.h" ++#include "mpm_common.h" ++ ++#include "systemd/sd-daemon.h" ++#include "systemd/sd-journal.h" ++ ++#if APR_HAVE_UNISTD_H ++#include ++#endif ++ ++static int shutdown_timer = 0; ++static int shutdown_counter = 0; ++static unsigned long bytes_served; ++static pid_t mainpid; ++static char describe_listeners[50]; ++ ++static int systemd_pre_config(apr_pool_t *pconf, apr_pool_t *plog, ++ apr_pool_t *ptemp) ++{ ++ sd_notify(0, ++ "RELOADING=1\n" ++ "STATUS=Reading configuration...\n"); ++ ap_extended_status = 1; ++ return OK; ++} ++ ++static char *dump_listener(ap_listen_rec *lr, apr_pool_t *p) ++{ ++ apr_sockaddr_t *sa = lr->bind_addr; ++ char addr[128]; ++ ++ if (apr_sockaddr_is_wildcard(sa)) { ++ return apr_pstrcat(p, "port ", apr_itoa(p, sa->port), NULL); ++ } ++ ++ apr_sockaddr_ip_getbuf(addr, sizeof addr, sa); ++ ++ return apr_psprintf(p, "%s port %u", addr, sa->port); ++} ++ ++static int systemd_post_config(apr_pool_t *pconf, apr_pool_t *plog, ++ apr_pool_t *ptemp, server_rec *s) ++{ ++ ap_listen_rec *lr; ++ apr_size_t plen = sizeof describe_listeners; ++ char *p = describe_listeners; ++ ++ if (ap_state_query(AP_SQ_MAIN_STATE) == AP_SQ_MS_CREATE_PRE_CONFIG) ++ return OK; ++ ++ for (lr = ap_listeners; lr; lr = lr->next) { ++ char *s = dump_listener(lr, ptemp); ++ ++ if (strlen(s) + 3 < plen) { ++ char *newp = apr_cpystrn(p, s, plen); ++ if (lr->next) ++ newp = apr_cpystrn(newp, ", ", 3); ++ plen -= newp - p; ++ p = newp; ++ } ++ else { ++ if (plen < 4) { ++ p = describe_listeners + sizeof describe_listeners - 4; ++ plen = 4; ++ } ++ apr_cpystrn(p, "...", plen); ++ break; ++ } ++ } ++ ++ sd_journal_print(LOG_INFO, "Server configured, listening on: %s", describe_listeners); ++ ++ return OK; ++} ++ ++static int systemd_pre_mpm(apr_pool_t *p, ap_scoreboard_e sb_type) ++{ ++ int rv; ++ ++ mainpid = getpid(); ++ ++ rv = sd_notifyf(0, "READY=1\n" ++ "STATUS=Started, listening on: %s\n" ++ "MAINPID=%" APR_PID_T_FMT, ++ describe_listeners, mainpid); ++ if (rv < 0) { ++ ap_log_perror(APLOG_MARK, APLOG_ERR, 0, p, APLOGNO(02395) ++ "sd_notifyf returned an error %d", rv); ++ } ++ ++ return OK; ++} ++ ++static int systemd_monitor(apr_pool_t *p, server_rec *s) ++{ ++ ap_sload_t sload; ++ apr_interval_time_t up_time; ++ char bps[5]; ++ int rv; ++ ++ if (!ap_extended_status) { ++ /* Nothing useful to report if ExtendedStatus disabled. */ ++ return DECLINED; ++ } ++ ++ ap_get_sload(&sload); ++ ++ if (sload.access_count == 0) { ++ rv = sd_notifyf(0, "READY=1\n" ++ "STATUS=Running, listening on: %s\n", ++ describe_listeners); ++ } ++ else { ++ /* up_time in seconds */ ++ up_time = (apr_uint32_t) apr_time_sec(apr_time_now() - ++ ap_scoreboard_image->global->restart_time); ++ ++ apr_strfsize((unsigned long)((float) (sload.bytes_served) ++ / (float) up_time), bps); ++ ++ rv = sd_notifyf(0, "READY=1\n" ++ "STATUS=Total requests: %lu; Idle/Busy workers %d/%d;" ++ "Requests/sec: %.3g; Bytes served/sec: %sB/sec\n", ++ sload.access_count, sload.idle, sload.busy, ++ ((float) sload.access_count) / (float) up_time, bps); ++ } ++ ++ if (rv < 0) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02396) ++ "sd_notifyf returned an error %d", rv); ++ } ++ ++ /* Shutdown httpd when nothing is sent for shutdown_timer seconds. */ ++ if (sload.bytes_served == bytes_served) { ++ /* mpm_common.c: INTERVAL_OF_WRITABLE_PROBES is 10 */ ++ shutdown_counter += 10; ++ if (shutdown_timer > 0 && shutdown_counter >= shutdown_timer) { ++ rv = sd_notifyf(0, "READY=1\n" ++ "STATUS=Stopped as result of IdleShutdown " ++ "timeout."); ++ if (rv < 0) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02804) ++ "sd_notifyf returned an error %d", rv); ++ } ++ kill(mainpid, AP_SIG_GRACEFUL); ++ } ++ } ++ else { ++ shutdown_counter = 0; ++ } ++ ++ bytes_served = sload.bytes_served; ++ ++ return DECLINED; ++} ++ ++static void systemd_register_hooks(apr_pool_t *p) ++{ ++ /* Enable ap_extended_status. */ ++ ap_hook_pre_config(systemd_pre_config, NULL, NULL, APR_HOOK_LAST); ++ /* Grab the listener config. */ ++ ap_hook_post_config(systemd_post_config, NULL, NULL, APR_HOOK_LAST); ++ /* 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); ++} ++ ++static const char *set_shutdown_timer(cmd_parms *cmd, void *dummy, ++ const char *arg) ++{ ++ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); ++ if (err != NULL) { ++ return err; ++ } ++ ++ shutdown_timer = atoi(arg); ++ return NULL; ++} ++ ++static const command_rec systemd_cmds[] = ++{ ++AP_INIT_TAKE1("IdleShutdown", set_shutdown_timer, NULL, RSRC_CONF, ++ "Number of seconds in idle-state after which httpd is shutdown"), ++ {NULL} ++}; ++ ++AP_DECLARE_MODULE(systemd) = { ++ STANDARD20_MODULE_STUFF, ++ NULL, ++ NULL, ++ NULL, ++ NULL, ++ systemd_cmds, ++ systemd_register_hooks, ++}; diff --git a/httpd-2.4.37-CVE-2018-17199.patch b/httpd-2.4.37-CVE-2018-17199.patch new file mode 100644 index 0000000..e98a26e --- /dev/null +++ b/httpd-2.4.37-CVE-2018-17199.patch @@ -0,0 +1,39 @@ +diff --git a/modules/session/mod_session.c b/modules/session/mod_session.c +index 10e6396..7ee477c 100644 +--- a/modules/session/mod_session.c ++++ b/modules/session/mod_session.c +@@ -126,20 +126,23 @@ static apr_status_t ap_session_load(request_rec * r, session_rec ** z) + + /* found a session that hasn't expired? */ + now = apr_time_now(); ++ + if (zz) { +- if (zz->expiry && zz->expiry < now) { ++ /* load the session attibutes */ ++ rv = ap_run_session_decode(r, zz); ++ ++ /* having a session we cannot decode is just as good as having ++ none at all */ ++ if (OK != rv) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01817) ++ "error while decoding the session, " ++ "session not loaded: %s", r->uri); + zz = NULL; + } +- else { +- /* having a session we cannot decode is just as good as having +- none at all */ +- rv = ap_run_session_decode(r, zz); +- if (OK != rv) { +- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01817) +- "error while decoding the session, " +- "session not loaded: %s", r->uri); +- zz = NULL; +- } ++ ++ /* invalidate session if session is expired */ ++ if (zz && zz->expiry && zz->expiry < now) { ++ zz = NULL; + } + } + diff --git a/httpd-2.4.37-CVE-2019-0211.patch b/httpd-2.4.37-CVE-2019-0211.patch new file mode 100644 index 0000000..043476a --- /dev/null +++ b/httpd-2.4.37-CVE-2019-0211.patch @@ -0,0 +1,207 @@ +diff --git a/include/scoreboard.h b/include/scoreboard.h +index 9376da2..92d198d 100644 +--- a/include/scoreboard.h ++++ b/include/scoreboard.h +@@ -148,7 +148,9 @@ struct process_score { + apr_uint32_t lingering_close; /* async connections in lingering close */ + apr_uint32_t keep_alive; /* async connections in keep alive */ + apr_uint32_t suspended; /* connections suspended by some module */ +- int bucket; /* Listener bucket used by this child */ ++ int bucket; /* Listener bucket used by this child; this field is DEPRECATED ++ * and no longer updated by the MPMs (i.e. always zero). ++ */ + }; + + /* Scoreboard is now in 'local' memory, since it isn't updated once created, +diff --git a/server/mpm/event/event.c b/server/mpm/event/event.c +index ffe8a23..048ae61 100644 +--- a/server/mpm/event/event.c ++++ b/server/mpm/event/event.c +@@ -2695,7 +2695,6 @@ static int make_child(server_rec * s, int slot, int bucket) + + ap_scoreboard_image->parent[slot].quiescing = 0; + ap_scoreboard_image->parent[slot].not_accepting = 0; +- ap_scoreboard_image->parent[slot].bucket = bucket; + event_note_child_started(slot, pid); + active_daemons++; + retained->total_daemons++; +@@ -2734,6 +2733,7 @@ static void perform_idle_server_maintenance(int child_bucket, int num_buckets) + * that threads_per_child is always > 0 */ + int status = SERVER_DEAD; + int child_threads_active = 0; ++ int bucket = i % num_buckets; + + if (i >= retained->max_daemons_limit && + free_length == retained->idle_spawn_rate[child_bucket]) { +@@ -2757,7 +2757,7 @@ static void perform_idle_server_maintenance(int child_bucket, int num_buckets) + */ + if (status <= SERVER_READY && !ps->quiescing && !ps->not_accepting + && ps->generation == retained->mpm->my_generation +- && ps->bucket == child_bucket) ++ && bucket == child_bucket) + { + ++idle_thread_count; + } +@@ -2768,7 +2768,9 @@ static void perform_idle_server_maintenance(int child_bucket, int num_buckets) + last_non_dead = i; + } + active_thread_count += child_threads_active; +- if (!ps->pid && free_length < retained->idle_spawn_rate[child_bucket]) ++ if (!ps->pid ++ && bucket == child_bucket ++ && free_length < retained->idle_spawn_rate[child_bucket]) + free_slots[free_length++] = i; + else if (child_threads_active == threads_per_child) + had_healthy_child = 1; +@@ -2951,13 +2953,14 @@ static void server_main_loop(int remaining_children_to_start, int num_buckets) + retained->total_daemons--; + if (processed_status == APEXIT_CHILDSICK) { + /* resource shortage, minimize the fork rate */ +- retained->idle_spawn_rate[ps->bucket] = 1; ++ retained->idle_spawn_rate[child_slot % num_buckets] = 1; + } + else if (remaining_children_to_start) { + /* we're still doing a 1-for-1 replacement of dead + * children with new children + */ +- make_child(ap_server_conf, child_slot, ps->bucket); ++ make_child(ap_server_conf, child_slot, ++ child_slot % num_buckets); + --remaining_children_to_start; + } + } +diff --git a/server/mpm/prefork/prefork.c b/server/mpm/prefork/prefork.c +index 8efda72..7c00625 100644 +--- a/server/mpm/prefork/prefork.c ++++ b/server/mpm/prefork/prefork.c +@@ -637,8 +637,9 @@ static void child_main(int child_num_arg, int child_bucket) + } + + +-static int make_child(server_rec *s, int slot, int bucket) ++static int make_child(server_rec *s, int slot) + { ++ int bucket = slot % retained->mpm->num_buckets; + int pid; + + if (slot + 1 > retained->max_daemons_limit) { +@@ -716,7 +717,6 @@ static int make_child(server_rec *s, int slot, int bucket) + child_main(slot, bucket); + } + +- ap_scoreboard_image->parent[slot].bucket = bucket; + prefork_note_child_started(slot, pid); + + return 0; +@@ -732,7 +732,7 @@ static void startup_children(int number_to_start) + if (ap_scoreboard_image->servers[i][0].status != SERVER_DEAD) { + continue; + } +- if (make_child(ap_server_conf, i, i % retained->mpm->num_buckets) < 0) { ++ if (make_child(ap_server_conf, i) < 0) { + break; + } + --number_to_start; +@@ -741,8 +741,6 @@ static void startup_children(int number_to_start) + + static void perform_idle_server_maintenance(apr_pool_t *p) + { +- static int bucket_make_child_record = -1; +- static int bucket_kill_child_record = -1; + int i; + int idle_count; + worker_score *ws; +@@ -789,6 +787,7 @@ static void perform_idle_server_maintenance(apr_pool_t *p) + } + retained->max_daemons_limit = last_non_dead + 1; + if (idle_count > ap_daemons_max_free) { ++ static int bucket_kill_child_record = -1; + /* kill off one child... we use the pod because that'll cause it to + * shut down gracefully, in case it happened to pick up a request + * while we were counting +@@ -819,10 +818,7 @@ static void perform_idle_server_maintenance(apr_pool_t *p) + idle_count, total_non_dead); + } + for (i = 0; i < free_length; ++i) { +- bucket_make_child_record++; +- bucket_make_child_record %= retained->mpm->num_buckets; +- make_child(ap_server_conf, free_slots[i], +- bucket_make_child_record); ++ make_child(ap_server_conf, free_slots[i]); + } + /* the next time around we want to spawn twice as many if this + * wasn't good enough, but not if we've just done a graceful +@@ -867,7 +863,7 @@ static int prefork_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) + + if (one_process) { + AP_MONCONTROL(1); +- make_child(ap_server_conf, 0, 0); ++ make_child(ap_server_conf, 0); + /* NOTREACHED */ + ap_assert(0); + return !OK; +@@ -976,8 +972,7 @@ static int prefork_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s) + /* we're still doing a 1-for-1 replacement of dead + * children with new children + */ +- make_child(ap_server_conf, child_slot, +- ap_get_scoreboard_process(child_slot)->bucket); ++ make_child(ap_server_conf, child_slot); + --remaining_children_to_start; + } + #if APR_HAS_OTHER_CHILD +diff --git a/server/mpm/worker/worker.c b/server/mpm/worker/worker.c +index 8012fe2..a927942 100644 +--- a/server/mpm/worker/worker.c ++++ b/server/mpm/worker/worker.c +@@ -1339,7 +1339,6 @@ static int make_child(server_rec *s, int slot, int bucket) + worker_note_child_lost_slot(slot, pid); + } + ap_scoreboard_image->parent[slot].quiescing = 0; +- ap_scoreboard_image->parent[slot].bucket = bucket; + worker_note_child_started(slot, pid); + return 0; + } +@@ -1388,6 +1387,7 @@ static void perform_idle_server_maintenance(int child_bucket, int num_buckets) + int any_dead_threads = 0; + int all_dead_threads = 1; + int child_threads_active = 0; ++ int bucket = i % num_buckets; + + if (i >= retained->max_daemons_limit && + totally_free_length == retained->idle_spawn_rate[child_bucket]) { +@@ -1420,7 +1420,7 @@ static void perform_idle_server_maintenance(int child_bucket, int num_buckets) + if (status <= SERVER_READY && + !ps->quiescing && + ps->generation == retained->mpm->my_generation && +- ps->bucket == child_bucket) { ++ bucket == child_bucket) { + ++idle_thread_count; + } + if (status >= SERVER_READY && status < SERVER_GRACEFUL) { +@@ -1430,6 +1430,7 @@ static void perform_idle_server_maintenance(int child_bucket, int num_buckets) + } + active_thread_count += child_threads_active; + if (any_dead_threads ++ && bucket == child_bucket + && totally_free_length < retained->idle_spawn_rate[child_bucket] + && free_length < MAX_SPAWN_RATE / num_buckets + && (!ps->pid /* no process in the slot */ +@@ -1615,14 +1616,15 @@ static void server_main_loop(int remaining_children_to_start, int num_buckets) + ps->quiescing = 0; + if (processed_status == APEXIT_CHILDSICK) { + /* resource shortage, minimize the fork rate */ +- retained->idle_spawn_rate[ps->bucket] = 1; ++ retained->idle_spawn_rate[child_slot % num_buckets] = 1; + } + else if (remaining_children_to_start + && child_slot < ap_daemons_limit) { + /* we're still doing a 1-for-1 replacement of dead + * children with new children + */ +- make_child(ap_server_conf, child_slot, ps->bucket); ++ make_child(ap_server_conf, child_slot, ++ child_slot % num_buckets); + --remaining_children_to_start; + } + } diff --git a/httpd-2.4.37-CVE-2019-0215.patch b/httpd-2.4.37-CVE-2019-0215.patch new file mode 100644 index 0000000..2967584 --- /dev/null +++ b/httpd-2.4.37-CVE-2019-0215.patch @@ -0,0 +1,20 @@ +diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c +index de0ffb0..e6a9f67 100644 +--- a/modules/ssl/ssl_engine_kernel.c ++++ b/modules/ssl/ssl_engine_kernel.c +@@ -1154,6 +1154,7 @@ static int ssl_hook_Access_modern(request_rec *r, SSLSrvConfigRec *sc, SSLDirCon + ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, r->server); + apr_table_setn(r->notes, "error-notes", + "Reason: Cannot perform Post-Handshake Authentication.
    "); ++ SSL_set_verify(ssl, vmode_inplace, NULL); + return HTTP_FORBIDDEN; + } + +@@ -1175,6 +1176,7 @@ static int ssl_hook_Access_modern(request_rec *r, SSLSrvConfigRec *sc, SSLDirCon + * Finally check for acceptable renegotiation results + */ + if (OK != (rc = ssl_check_post_client_verify(r, sc, dc, sslconn, ssl))) { ++ SSL_set_verify(ssl, vmode_inplace, NULL); + return rc; + } + } diff --git a/httpd-2.4.37-CVE-2019-0217.patch b/httpd-2.4.37-CVE-2019-0217.patch new file mode 100644 index 0000000..1614e72 --- /dev/null +++ b/httpd-2.4.37-CVE-2019-0217.patch @@ -0,0 +1,111 @@ +--- a/modules/aaa/mod_auth_digest.c 2019/03/12 09:24:19 1855297 ++++ b/modules/aaa/mod_auth_digest.c 2019/03/12 09:24:26 1855298 +@@ -92,7 +92,6 @@ + int check_nc; + const char *algorithm; + char *uri_list; +- const char *ha1; + } digest_config_rec; + + +@@ -153,6 +152,7 @@ + apr_time_t nonce_time; + enum hdr_sts auth_hdr_sts; + int needed_auth; ++ const char *ha1; + client_entry *client; + } digest_header_rec; + +@@ -1304,7 +1304,7 @@ + */ + + static authn_status get_hash(request_rec *r, const char *user, +- digest_config_rec *conf) ++ digest_config_rec *conf, const char **rethash) + { + authn_status auth_result; + char *password; +@@ -1356,7 +1356,7 @@ + } while (current_provider); + + if (auth_result == AUTH_USER_FOUND) { +- conf->ha1 = password; ++ *rethash = password; + } + + return auth_result; +@@ -1483,25 +1483,24 @@ + + /* RFC-2069 */ + static const char *old_digest(const request_rec *r, +- const digest_header_rec *resp, const char *ha1) ++ const digest_header_rec *resp) + { + const char *ha2; + + ha2 = ap_md5(r->pool, (unsigned char *)apr_pstrcat(r->pool, resp->method, ":", + resp->uri, NULL)); + return ap_md5(r->pool, +- (unsigned char *)apr_pstrcat(r->pool, ha1, ":", resp->nonce, +- ":", ha2, NULL)); ++ (unsigned char *)apr_pstrcat(r->pool, resp->ha1, ":", ++ resp->nonce, ":", ha2, NULL)); + } + + /* RFC-2617 */ + static const char *new_digest(const request_rec *r, +- digest_header_rec *resp, +- const digest_config_rec *conf) ++ digest_header_rec *resp) + { + const char *ha1, *ha2, *a2; + +- ha1 = conf->ha1; ++ ha1 = resp->ha1; + + a2 = apr_pstrcat(r->pool, resp->method, ":", resp->uri, NULL); + ha2 = ap_md5(r->pool, (const unsigned char *)a2); +@@ -1514,7 +1513,6 @@ + NULL)); + } + +- + static void copy_uri_components(apr_uri_t *dst, + apr_uri_t *src, request_rec *r) { + if (src->scheme && src->scheme[0] != '\0') { +@@ -1759,7 +1757,7 @@ + return HTTP_UNAUTHORIZED; + } + +- return_code = get_hash(r, r->user, conf); ++ return_code = get_hash(r, r->user, conf, &resp->ha1); + + if (return_code == AUTH_USER_NOT_FOUND) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01790) +@@ -1789,7 +1787,7 @@ + + if (resp->message_qop == NULL) { + /* old (rfc-2069) style digest */ +- if (strcmp(resp->digest, old_digest(r, resp, conf->ha1))) { ++ if (strcmp(resp->digest, old_digest(r, resp))) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01792) + "user %s: password mismatch: %s", r->user, + r->uri); +@@ -1819,7 +1817,7 @@ + return HTTP_UNAUTHORIZED; + } + +- exp_digest = new_digest(r, resp, conf); ++ exp_digest = new_digest(r, resp); + if (!exp_digest) { + /* we failed to allocate a client struct */ + return HTTP_INTERNAL_SERVER_ERROR; +@@ -1903,7 +1901,7 @@ + + /* calculate rspauth attribute + */ +- ha1 = conf->ha1; ++ ha1 = resp->ha1; + + a2 = apr_pstrcat(r->pool, ":", resp->uri, NULL); + ha2 = ap_md5(r->pool, (const unsigned char *)a2); diff --git a/httpd-2.4.37-CVE-2019-0220.patch b/httpd-2.4.37-CVE-2019-0220.patch new file mode 100644 index 0000000..1fcb68e --- /dev/null +++ b/httpd-2.4.37-CVE-2019-0220.patch @@ -0,0 +1,235 @@ +diff --git a/docs/manual/mod/core.html.en b/docs/manual/mod/core.html.en +index 0a24bc8..20d1e5a 100644 +--- a/docs/manual/mod/core.html.en ++++ b/docs/manual/mod/core.html.en +@@ -97,6 +97,7 @@ available +
  • MaxRangeOverlaps
  • +
  • MaxRangeReversals
  • +
  • MaxRanges
  • ++
  • MergeSlashes
  • +
  • MergeTrailers
  • +
  • Mutex
  • +
  • NameVirtualHost
  • +@@ -3465,6 +3466,30 @@ resource + + +
    top
    ++
    ++ ++ ++ ++ ++ ++ ++ ++
    Description:Controls whether the server merges consecutive slashes in URLs.
    Syntax:MergeSlashes ON | OFF
    Default:MergeSlashes ON
    Context:server config, virtual host
    Status:Core
    Module:core
    Compatibility:Available in Apache HTTP Server 2.4.6 in Red Hat Enterprise Linux 7
    ++

    By default, the server merges (or collapses) multiple consecutive slash ++ ('/') characters in the path component of the request URL.

    ++ ++

    When mapping URL's to the filesystem, these multiple slashes are not ++ significant. However, URL's handled other ways, such as by CGI or proxy, ++ might prefer to retain the significance of multiple consecutive slashes. ++ In these cases MergeSlashes can be set to ++ OFF to retain the multiple consecutive slashes. In these ++ configurations, regular expressions used in the configuration file that match ++ the path component of the URL (LocationMatch, ++ RewriteRule, ...) need to take into account multiple ++ consecutive slashes.

    ++
    ++
    top
    +

    MergeTrailers Directive

    + + +--- a/include/http_core.h 2019/03/18 08:49:19 1855736 ++++ b/include/http_core.h 2019/03/18 08:49:59 1855737 +@@ -740,7 +740,7 @@ + #define AP_HTTP_METHODS_LENIENT 1 + #define AP_HTTP_METHODS_REGISTERED 2 + char http_methods; +- ++ unsigned int merge_slashes; + } core_server_config; + + /* for AddOutputFiltersByType in core.c */ +diff --git a/include/httpd.h b/include/httpd.h +index 65392f8..99f7f04 100644 +--- a/include/httpd.h ++++ b/include/httpd.h +@@ -1697,11 +1697,21 @@ AP_DECLARE(int) ap_unescape_url_keep2f(char *url, int decode_slashes); + AP_DECLARE(int) ap_unescape_urlencoded(char *query); + + /** +- * Convert all double slashes to single slashes +- * @param name The string to convert ++ * Convert all double slashes to single slashes, except where significant ++ * to the filesystem on the current platform. ++ * @param name The string to convert, assumed to be a filesystem path + */ + AP_DECLARE(void) ap_no2slash(char *name); + ++/** ++ * Convert all double slashes to single slashes, except where significant ++ * to the filesystem on the current platform. ++ * @param name The string to convert ++ * @param is_fs_path if set to 0, the significance of any double-slashes is ++ * ignored. ++ */ ++AP_DECLARE(void) ap_no2slash_ex(char *name, int is_fs_path); ++ + /** + * Remove all ./ and xx/../ substrings from a file name. Also remove + * any leading ../ or /../ substrings. +diff --git a/server/request.c b/server/request.c +index dbe3e07..d5c558a 100644 +--- a/server/request.c ++++ b/server/request.c +@@ -167,6 +167,8 @@ AP_DECLARE(int) ap_process_request_internal(request_rec *r) + int file_req = (r->main && r->filename); + int access_status; + core_dir_config *d; ++ core_server_config *sconf = ++ ap_get_core_module_config(r->server->module_config); + + /* Ignore embedded %2F's in path for proxy requests */ + if (!r->proxyreq && r->parsed_uri.path) { +@@ -191,6 +193,12 @@ AP_DECLARE(int) ap_process_request_internal(request_rec *r) + } + + ap_getparents(r->uri); /* OK --- shrinking transformations... */ ++ if (sconf->merge_slashes != AP_CORE_CONFIG_OFF) { ++ ap_no2slash(r->uri); ++ if (r->parsed_uri.path) { ++ ap_no2slash(r->parsed_uri.path); ++ } ++ } + + /* All file subrequests are a huge pain... they cannot bubble through the + * next several steps. Only file subrequests are allowed an empty uri, +@@ -1411,20 +1419,7 @@ AP_DECLARE(int) ap_location_walk(request_rec *r) + + cache = prep_walk_cache(AP_NOTE_LOCATION_WALK, r); + cached = (cache->cached != NULL); +- +- /* Location and LocationMatch differ on their behaviour w.r.t. multiple +- * slashes. Location matches multiple slashes with a single slash, +- * LocationMatch doesn't. An exception, for backwards brokenness is +- * absoluteURIs... in which case neither match multiple slashes. +- */ +- if (r->uri[0] != '/') { +- entry_uri = r->uri; +- } +- else { +- char *uri = apr_pstrdup(r->pool, r->uri); +- ap_no2slash(uri); +- entry_uri = uri; +- } ++ entry_uri = r->uri; + + /* If we have an cache->cached location that matches r->uri, + * and the vhost's list of locations hasn't changed, we can skip +@@ -1491,7 +1486,7 @@ AP_DECLARE(int) ap_location_walk(request_rec *r) + pmatch = apr_palloc(rxpool, nmatch*sizeof(ap_regmatch_t)); + } + +- if (ap_regexec(entry_core->r, r->uri, nmatch, pmatch, 0)) { ++ if (ap_regexec(entry_core->r, entry_uri, nmatch, pmatch, 0)) { + continue; + } + +@@ -1501,7 +1496,7 @@ AP_DECLARE(int) ap_location_walk(request_rec *r) + apr_table_setn(r->subprocess_env, + ((const char **)entry_core->refs->elts)[i], + apr_pstrndup(r->pool, +- r->uri + pmatch[i].rm_so, ++ entry_uri + pmatch[i].rm_so, + pmatch[i].rm_eo - pmatch[i].rm_so)); + } + } +diff --git a/server/util.c b/server/util.c +index fd7a0a1..e0c558c 100644 +--- a/server/util.c ++++ b/server/util.c +@@ -561,16 +561,20 @@ AP_DECLARE(void) ap_getparents(char *name) + name[l] = '\0'; + } + } +- +-AP_DECLARE(void) ap_no2slash(char *name) ++AP_DECLARE(void) ap_no2slash_ex(char *name, int is_fs_path) + { ++ + char *d, *s; + ++ if (!*name) { ++ return; ++ } ++ + s = d = name; + + #ifdef HAVE_UNC_PATHS + /* Check for UNC names. Leave leading two slashes. */ +- if (s[0] == '/' && s[1] == '/') ++ if (is_fs_path && s[0] == '/' && s[1] == '/') + *d++ = *s++; + #endif + +@@ -587,6 +591,10 @@ AP_DECLARE(void) ap_no2slash(char *name) + *d = '\0'; + } + ++AP_DECLARE(void) ap_no2slash(char *name) ++{ ++ ap_no2slash_ex(name, 1); ++} + + /* + * copy at most n leading directories of s into d +diff --git a/server/core.c b/server/core.c +index b5ab429..a31f1e4 100644 +--- a/server/core.c ++++ b/server/core.c +@@ -493,6 +493,7 @@ static void *create_core_server_config(apr_pool_t *a, server_rec *s) + */ + + conf->trace_enable = AP_TRACE_UNSET; ++ conf->merge_slashes = AP_CORE_CONFIG_UNSET; + + conf->protocols = apr_array_make(a, 5, sizeof(const char *)); + conf->protocols_honor_order = -1; +@@ -561,7 +562,9 @@ static void *merge_core_server_configs(apr_pool_t *p, void *basev, void *virtv) + conf->protocols_honor_order = ((virt->protocols_honor_order < 0)? + base->protocols_honor_order : + virt->protocols_honor_order); +- ++ ++ AP_CORE_MERGE_FLAG(merge_slashes, conf, base, virt); ++ + return conf; + } + +@@ -1872,6 +1875,13 @@ static const char *set_qualify_redirect_url(cmd_parms *cmd, void *d_, int flag) + return NULL; + } + ++static const char *set_core_server_flag(cmd_parms *cmd, void *s_, int flag) ++{ ++ core_server_config *conf = ++ ap_get_core_module_config(cmd->server->module_config); ++ return ap_set_flag_slot(cmd, conf, flag); ++} ++ + static const char *set_override_list(cmd_parms *cmd, void *d_, int argc, char *const argv[]) + { + core_dir_config *d = d_; +@@ -4598,6 +4608,10 @@ AP_INIT_ITERATE("HttpProtocolOptions", set_http_protocol_options, NULL, RSRC_CON + "'Unsafe' or 'Strict' (default). Sets HTTP acceptance rules"), + AP_INIT_ITERATE("RegisterHttpMethod", set_http_method, NULL, RSRC_CONF, + "Registers non-standard HTTP methods"), ++AP_INIT_FLAG("MergeSlashes", set_core_server_flag, ++ (void *)APR_OFFSETOF(core_server_config, merge_slashes), ++ RSRC_CONF, ++ "Controls whether consecutive slashes in the URI path are merged"), + { NULL } + }; + diff --git a/httpd-2.4.37-CVE-2019-10092.patch b/httpd-2.4.37-CVE-2019-10092.patch new file mode 100644 index 0000000..a06d9c2 --- /dev/null +++ b/httpd-2.4.37-CVE-2019-10092.patch @@ -0,0 +1,192 @@ +diff --git a/modules/http/http_protocol.c b/modules/http/http_protocol.c +index e419eb6..dcafa9c 100644 +--- a/modules/http/http_protocol.c ++++ b/modules/http/http_protocol.c +@@ -1132,13 +1132,10 @@ static const char *get_canned_error_string(int status, + "\">here.

    \n", + NULL)); + case HTTP_USE_PROXY: +- return(apr_pstrcat(p, +- "

    This resource is only accessible " +- "through the proxy\n", +- ap_escape_html(r->pool, location), +- "
    \nYou will need to configure " +- "your client to use that proxy.

    \n", +- NULL)); ++ return("

    This resource is only accessible " ++ "through the proxy\n" ++ "
    \nYou will need to configure " ++ "your client to use that proxy.

    \n"); + case HTTP_PROXY_AUTHENTICATION_REQUIRED: + case HTTP_UNAUTHORIZED: + return("

    This server could not verify that you\n" +@@ -1154,34 +1151,20 @@ static const char *get_canned_error_string(int status, + "error-notes", + "

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

    You don't have permission to access ", +- ap_escape_html(r->pool, r->uri), +- "\non this server.
    \n", +- NULL); +- return(add_optional_notes(r, s1, "error-notes", "

    \n")); ++ return(add_optional_notes(r, "

    You don't have permission to access this resource.", "error-notes", "

    \n")); + case HTTP_NOT_FOUND: +- return(apr_pstrcat(p, +- "

    The requested URL ", +- ap_escape_html(r->pool, r->uri), +- " was not found on this server.

    \n", +- NULL)); ++ return("

    The requested URL was not found on this server.

    \n"); + case HTTP_METHOD_NOT_ALLOWED: + return(apr_pstrcat(p, + "

    The requested method ", + ap_escape_html(r->pool, r->method), +- " is not allowed for the URL ", +- ap_escape_html(r->pool, r->uri), +- ".

    \n", ++ " is not allowed for this URL.

    \n", + NULL)); + case HTTP_NOT_ACCEPTABLE: +- s1 = apr_pstrcat(p, +- "

    An appropriate representation of the " +- "requested resource ", +- ap_escape_html(r->pool, r->uri), +- " could not be found on this server.

    \n", +- NULL); +- return(add_optional_notes(r, s1, "variant-list", "")); ++ return(add_optional_notes(r, ++ "

    An appropriate representation of the requested resource " ++ "could not be found on this server.

    \n", ++ "variant-list", "")); + case HTTP_MULTIPLE_CHOICES: + return(add_optional_notes(r, "", "variant-list", "")); + case HTTP_LENGTH_REQUIRED: +@@ -1192,18 +1175,13 @@ static const char *get_canned_error_string(int status, + NULL); + return(add_optional_notes(r, s1, "error-notes", "

    \n")); + case HTTP_PRECONDITION_FAILED: +- return(apr_pstrcat(p, +- "

    The precondition on the request " +- "for the URL ", +- ap_escape_html(r->pool, r->uri), +- " evaluated to false.

    \n", +- NULL)); ++ return("

    The precondition on the request " ++ "for this URL evaluated to false.

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

    ", +- ap_escape_html(r->pool, r->method), " to ", +- ap_escape_html(r->pool, r->uri), +- " not supported.
    \n", ++ ap_escape_html(r->pool, r->method), " ", ++ " not supported for current URL.
    \n", + NULL); + return(add_optional_notes(r, s1, "error-notes", "

    \n")); + case HTTP_BAD_GATEWAY: +@@ -1211,29 +1189,19 @@ static const char *get_canned_error_string(int status, + "response from an upstream server.
    " CRLF; + return(add_optional_notes(r, s1, "error-notes", "

    \n")); + case HTTP_VARIANT_ALSO_VARIES: +- return(apr_pstrcat(p, +- "

    A variant for the requested " +- "resource\n

    \n",
    +-                           ap_escape_html(r->pool, r->uri),
    +-                           "\n
    \nis itself a negotiable resource. " +- "This indicates a configuration error.

    \n", +- NULL)); ++ return("

    A variant for the requested " ++ "resource\n

    \n"
    ++               "\n
    \nis itself a negotiable resource. " ++ "This indicates a configuration error.

    \n"); + case HTTP_REQUEST_TIME_OUT: + return("

    Server timeout waiting for the HTTP request from the client.

    \n"); + case HTTP_GONE: +- return(apr_pstrcat(p, +- "

    The requested resource
    ", +- ap_escape_html(r->pool, r->uri), +- "
    \nis no longer available on this server " +- "and there is no forwarding address.\n" +- "Please remove all references to this " +- "resource.

    \n", +- NULL)); ++ return("

    The requested resource is no longer available on this server" ++ " and there is no forwarding address.\n" ++ "Please remove all references to this resource.

    \n"); + case HTTP_REQUEST_ENTITY_TOO_LARGE: + return(apr_pstrcat(p, +- "The requested resource
    ", +- ap_escape_html(r->pool, r->uri), "
    \n", +- "does not allow request data with ", ++ "The requested resource does not allow request data with ", + ap_escape_html(r->pool, r->method), + " requests, or the amount of data provided in\n" + "the request exceeds the capacity limit.\n", +@@ -1317,11 +1285,9 @@ static const char *get_canned_error_string(int status, + "the Server Name Indication (SNI) in use for this\n" + "connection.

    \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")); ++ return(add_optional_notes(r, ++ "

    Access to this URL has been denied for legal reasons.
    \n", ++ "error-notes", "

    \n")); + default: /* HTTP_INTERNAL_SERVER_ERROR */ + /* + * This comparison to expose error-notes could be modified to +diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c +index 800ede1..de48735 100644 +--- a/modules/proxy/mod_proxy.c ++++ b/modules/proxy/mod_proxy.c +@@ -1055,9 +1055,10 @@ static int proxy_handler(request_rec *r) + char *end; + maxfwd = apr_strtoi64(str, &end, 10); + if (maxfwd < 0 || maxfwd == APR_INT64_MAX || *end) { +- return ap_proxyerror(r, HTTP_BAD_REQUEST, +- apr_psprintf(r->pool, +- "Max-Forwards value '%s' could not be parsed", str)); ++ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO() ++ "Max-Forwards value '%s' could not be parsed", str); ++ return ap_proxyerror(r, HTTP_BAD_REQUEST, ++ "Max-Forwards request header could not be parsed"); + } + else if (maxfwd == 0) { + switch (r->method_number) { +diff --git a/modules/proxy/mod_proxy_ftp.c b/modules/proxy/mod_proxy_ftp.c +index 4a10987..8f6f853 100644 +--- a/modules/proxy/mod_proxy_ftp.c ++++ b/modules/proxy/mod_proxy_ftp.c +@@ -1024,8 +1024,9 @@ static int proxy_ftp_handler(request_rec *r, proxy_worker *worker, + /* We break the URL into host, port, path-search */ + if (r->parsed_uri.hostname == NULL) { + if (APR_SUCCESS != apr_uri_parse(p, url, &uri)) { +- return ap_proxyerror(r, HTTP_BAD_REQUEST, +- apr_psprintf(p, "URI cannot be parsed: %s", url)); ++ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO() ++ "URI cannot be parsed: %s", url); ++ return ap_proxyerror(r, HTTP_BAD_REQUEST, "URI cannot be parsed"); + } + connectname = uri.hostname; + connectport = uri.port; +diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c +index 6501c68..0bbfa59 100644 +--- a/modules/proxy/proxy_util.c ++++ b/modules/proxy/proxy_util.c +@@ -368,12 +368,9 @@ PROXY_DECLARE(char *) + + PROXY_DECLARE(int) ap_proxyerror(request_rec *r, int statuscode, const char *message) + { +- const char *uri = ap_escape_html(r->pool, r->uri); + apr_table_setn(r->notes, "error-notes", + apr_pstrcat(r->pool, +- "The proxy server could not handle the request ", ap_escape_html(r->pool, r->method), " ", uri, +- ".

    \n" ++ "The proxy server could not handle the request

    " + "Reason: ", ap_escape_html(r->pool, message), + "

    ", + NULL)); diff --git a/httpd-2.4.37-CVE-2019-10097.patch b/httpd-2.4.37-CVE-2019-10097.patch new file mode 100644 index 0000000..b0132a9 --- /dev/null +++ b/httpd-2.4.37-CVE-2019-10097.patch @@ -0,0 +1,66 @@ +diff --git a/modules/metadata/mod_remoteip.c b/modules/metadata/mod_remoteip.c +index 4572ce1..a0cbc0f 100644 +--- a/modules/metadata/mod_remoteip.c ++++ b/modules/metadata/mod_remoteip.c +@@ -987,15 +987,13 @@ static remoteip_parse_status_t remoteip_process_v2_header(conn_rec *c, + return HDR_ERROR; + #endif + default: +- /* unsupported protocol, keep local connection address */ +- return HDR_DONE; ++ /* unsupported protocol */ ++ ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(10183) ++ "RemoteIPProxyProtocol: unsupported protocol %.2hx", ++ (unsigned short)hdr->v2.fam); ++ return HDR_ERROR; + } + break; /* we got a sockaddr now */ +- +- case 0x00: /* LOCAL command */ +- /* keep local connection address for LOCAL */ +- return HDR_DONE; +- + default: + /* not a supported command */ + ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(03507) +@@ -1087,11 +1085,24 @@ static apr_status_t remoteip_input_filter(ap_filter_t *f, + /* try to read a header's worth of data */ + while (!ctx->done) { + if (APR_BRIGADE_EMPTY(ctx->bb)) { +- ret = ap_get_brigade(f->next, ctx->bb, ctx->mode, block, +- ctx->need - ctx->rcvd); ++ apr_off_t got, want = ctx->need - ctx->rcvd; ++ ++ ret = ap_get_brigade(f->next, ctx->bb, ctx->mode, block, want); + if (ret != APR_SUCCESS) { ++ ap_log_cerror(APLOG_MARK, APLOG_ERR, ret, f->c, APLOGNO(10184) ++ "failed reading input"); + return ret; + } ++ ++ ret = apr_brigade_length(ctx->bb, 1, &got); ++ if (ret || got > want) { ++ ap_log_cerror(APLOG_MARK, APLOG_ERR, ret, f->c, APLOGNO(10185) ++ "RemoteIPProxyProtocol header too long, " ++ "got %" APR_OFF_T_FMT " expected %" APR_OFF_T_FMT, ++ got, want); ++ f->c->aborted = 1; ++ return APR_ECONNABORTED; ++ } + } + if (APR_BRIGADE_EMPTY(ctx->bb)) { + return block == APR_NONBLOCK_READ ? APR_SUCCESS : APR_EOF; +@@ -1139,6 +1150,13 @@ static apr_status_t remoteip_input_filter(ap_filter_t *f, + if (ctx->rcvd >= MIN_V2_HDR_LEN) { + ctx->need = MIN_V2_HDR_LEN + + remoteip_get_v2_len((proxy_header *) ctx->header); ++ if (ctx->need > sizeof(proxy_v2)) { ++ ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, f->c, APLOGNO(10186) ++ "RemoteIPProxyProtocol protocol header length too long"); ++ f->c->aborted = 1; ++ apr_brigade_destroy(ctx->bb); ++ return APR_ECONNABORTED; ++ } + } + if (ctx->rcvd >= ctx->need) { + psts = remoteip_process_v2_header(f->c, conn_conf, diff --git a/httpd-2.4.37-CVE-2019-10098.patch b/httpd-2.4.37-CVE-2019-10098.patch new file mode 100644 index 0000000..c3a559f --- /dev/null +++ b/httpd-2.4.37-CVE-2019-10098.patch @@ -0,0 +1,91 @@ +diff --git a/include/ap_regex.h b/include/ap_regex.h +index 7d8df79..7af2f99 100644 +--- a/include/ap_regex.h ++++ b/include/ap_regex.h +@@ -84,7 +84,11 @@ extern "C" { + + #define AP_REG_DOLLAR_ENDONLY 0x200 /* '$' matches at end of subject string only */ + +-#define AP_REG_MATCH "MATCH_" /** suggested prefix for ap_regname */ ++#define AP_REG_NO_DEFAULT 0x400 /**< Don't implicitely add AP_REG_DEFAULT options */ ++ ++#define AP_REG_MATCH "MATCH_" /**< suggested prefix for ap_regname */ ++ ++#define AP_REG_DEFAULT (AP_REG_DOTALL|AP_REG_DOLLAR_ENDONLY) + + /* Error values: */ + enum { +diff --git a/modules/filters/mod_substitute.c b/modules/filters/mod_substitute.c +index b7d5296..e976c51 100644 +--- a/modules/filters/mod_substitute.c ++++ b/modules/filters/mod_substitute.c +@@ -667,8 +667,10 @@ static const char *set_pattern(cmd_parms *cmd, void *cfg, const char *line) + + /* first see if we can compile the regex */ + if (!is_pattern) { +- r = ap_pregcomp(cmd->pool, from, AP_REG_EXTENDED | +- (ignore_case ? AP_REG_ICASE : 0)); ++ int flags = AP_REG_NO_DEFAULT ++ | (ap_regcomp_get_default_cflags() & AP_REG_DOLLAR_ENDONLY) ++ | (ignore_case ? AP_REG_ICASE : 0); ++ r = ap_pregcomp(cmd->pool, from, flags); + if (!r) + return "Substitute could not compile regex"; + } +diff --git a/server/core.c b/server/core.c +index 76432ce..6d00777 100644 +--- a/server/core.c ++++ b/server/core.c +@@ -4973,7 +4973,7 @@ static int core_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptem + init_config_defines(pconf); + apr_pool_cleanup_register(pconf, NULL, reset_config, apr_pool_cleanup_null); + +- ap_regcomp_set_default_cflags(AP_REG_DOLLAR_ENDONLY); ++ ap_regcomp_set_default_cflags(AP_REG_DEFAULT); + + mpm_common_pre_config(pconf); + +diff --git a/server/util_pcre.c b/server/util_pcre.c +index f2cb1bb..2a665c8 100644 +--- a/server/util_pcre.c ++++ b/server/util_pcre.c +@@ -120,7 +120,7 @@ AP_DECLARE(void) ap_regfree(ap_regex_t *preg) + * Compile a regular expression * + *************************************************/ + +-static int default_cflags = AP_REG_DOLLAR_ENDONLY; ++static int default_cflags = AP_REG_DEFAULT; + + AP_DECLARE(int) ap_regcomp_get_default_cflags(void) + { +@@ -168,7 +168,8 @@ AP_DECLARE(int) ap_regcomp(ap_regex_t * preg, const char *pattern, int cflags) + int errcode = 0; + int options = PCRE_DUPNAMES; + +- cflags |= default_cflags; ++ if ((cflags & AP_REG_NO_DEFAULT) == 0) ++ cflags |= default_cflags; + if ((cflags & AP_REG_ICASE) != 0) + options |= PCRE_CASELESS; + if ((cflags & AP_REG_NEWLINE) != 0) +diff --git a/server/util_regex.c b/server/util_regex.c +index 2a30d68..5405f8d 100644 +--- a/server/util_regex.c ++++ b/server/util_regex.c +@@ -94,6 +94,7 @@ AP_DECLARE(ap_rxplus_t*) ap_rxplus_compile(apr_pool_t *pool, + } + + /* anything after the current delimiter is flags */ ++ ret->flags = ap_regcomp_get_default_cflags() & AP_REG_DOLLAR_ENDONLY; + while (*++endp) { + switch (*endp) { + case 'i': ret->flags |= AP_REG_ICASE; break; +@@ -106,7 +107,7 @@ AP_DECLARE(ap_rxplus_t*) ap_rxplus_compile(apr_pool_t *pool, + default: break; /* we should probably be stricter here */ + } + } +- if (ap_regcomp(&ret->rx, rxstr, ret->flags) == 0) { ++ if (ap_regcomp(&ret->rx, rxstr, AP_REG_NO_DEFAULT | ret->flags) == 0) { + apr_pool_cleanup_register(pool, &ret->rx, rxplus_cleanup, + apr_pool_cleanup_null); + } diff --git a/httpd-2.4.37-CVE-2020-11984.patch b/httpd-2.4.37-CVE-2020-11984.patch new file mode 100644 index 0000000..4bb9ea2 --- /dev/null +++ b/httpd-2.4.37-CVE-2020-11984.patch @@ -0,0 +1,36 @@ +--- a/modules/proxy/mod_proxy_uwsgi.c 2020/07/24 09:31:46 1880250 ++++ b/modules/proxy/mod_proxy_uwsgi.c 2020/07/24 09:35:25 1880251 +@@ -136,7 +136,7 @@ + int j; + + apr_size_t headerlen = 4; +- apr_uint16_t pktsize, keylen, vallen; ++ apr_size_t pktsize, keylen, vallen; + const char *script_name; + const char *path_info; + const char *auth; +@@ -178,6 +178,15 @@ + headerlen += 2 + strlen(env[j].key) + 2 + strlen(env[j].val); + } + ++ pktsize = headerlen - 4; ++ if (pktsize > APR_UINT16_MAX) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10259) ++ "can't send headers to %s:%u: packet size too " ++ "large (%" APR_SIZE_T_FMT ")", ++ conn->hostname, conn->port, pktsize); ++ return HTTP_INTERNAL_SERVER_ERROR; ++ } ++ + ptr = buf = apr_palloc(r->pool, headerlen); + + ptr += 4; +@@ -196,8 +205,6 @@ + ptr += vallen; + } + +- pktsize = headerlen - 4; +- + buf[0] = 0; + buf[1] = (apr_byte_t) (pktsize & 0xff); + buf[2] = (apr_byte_t) ((pktsize >> 8) & 0xff); diff --git a/httpd-2.4.37-CVE-2020-1934.patch b/httpd-2.4.37-CVE-2020-1934.patch new file mode 100644 index 0000000..69088b9 --- /dev/null +++ b/httpd-2.4.37-CVE-2020-1934.patch @@ -0,0 +1,68 @@ +--- a/modules/proxy/mod_proxy_ftp.c 2020/02/07 17:01:07 1873744 ++++ b/modules/proxy/mod_proxy_ftp.c 2020/02/07 17:04:45 1873745 +@@ -218,7 +218,7 @@ + * (EBCDIC) machines either. + */ + static apr_status_t ftp_string_read(conn_rec *c, apr_bucket_brigade *bb, +- char *buff, apr_size_t bufflen, int *eos) ++ char *buff, apr_size_t bufflen, int *eos, apr_size_t *outlen) + { + apr_bucket *e; + apr_status_t rv; +@@ -230,6 +230,7 @@ + /* start with an empty string */ + buff[0] = 0; + *eos = 0; ++ *outlen = 0; + + /* loop through each brigade */ + while (!found) { +@@ -273,6 +274,7 @@ + if (len > 0) { + memcpy(pos, response, len); + pos += len; ++ *outlen += len; + } + } + apr_bucket_delete(e); +@@ -385,28 +387,36 @@ + char buff[5]; + char *mb = msgbuf, *me = &msgbuf[msglen]; + apr_status_t rv; ++ apr_size_t nread; ++ + int eos; + +- if (APR_SUCCESS != (rv = ftp_string_read(ftp_ctrl, bb, response, sizeof(response), &eos))) { ++ if (APR_SUCCESS != (rv = ftp_string_read(ftp_ctrl, bb, response, sizeof(response), &eos, &nread))) { + return -1; + } + /* + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, APLOGNO(03233) + "<%s", response); + */ ++ if (nread < 4) { ++ ap_log_error(APLOG_MARK, APLOG_INFO, 0, NULL, APLOGNO(10229) "Malformed FTP response '%s'", response); ++ *mb = '\0'; ++ return -1; ++ } ++ + if (!apr_isdigit(response[0]) || !apr_isdigit(response[1]) || +- !apr_isdigit(response[2]) || (response[3] != ' ' && response[3] != '-')) ++ !apr_isdigit(response[2]) || (response[3] != ' ' && response[3] != '-')) + status = 0; + else + status = 100 * response[0] + 10 * response[1] + response[2] - 111 * '0'; + + mb = apr_cpystrn(mb, response + 4, me - mb); + +- if (response[3] == '-') { ++ if (response[3] == '-') { /* multi-line reply "123-foo\nbar\n123 baz" */ + memcpy(buff, response, 3); + buff[3] = ' '; + do { +- if (APR_SUCCESS != (rv = ftp_string_read(ftp_ctrl, bb, response, sizeof(response), &eos))) { ++ if (APR_SUCCESS != (rv = ftp_string_read(ftp_ctrl, bb, response, sizeof(response), &eos, &nread))) { + return -1; + } + mb = apr_cpystrn(mb, response + (' ' == response[0] ? 1 : 4), me - mb); diff --git a/httpd-2.4.37-CVE-2020-35452.patch b/httpd-2.4.37-CVE-2020-35452.patch new file mode 100644 index 0000000..998c1e5 --- /dev/null +++ b/httpd-2.4.37-CVE-2020-35452.patch @@ -0,0 +1,21 @@ +diff --git a/modules/aaa/mod_auth_digest.c b/modules/aaa/mod_auth_digest.c +index b760941..0825b1b 100644 +--- a/modules/aaa/mod_auth_digest.c ++++ b/modules/aaa/mod_auth_digest.c +@@ -1422,9 +1422,14 @@ static int check_nonce(request_rec *r, digest_header_rec *resp, + time_rec nonce_time; + char tmp, hash[NONCE_HASH_LEN+1]; + +- if (strlen(resp->nonce) != NONCE_LEN) { ++ /* Since the time part of the nonce is a base64 encoding of an ++ * apr_time_t (8 bytes), it should end with a '=', fail early otherwise. ++ */ ++ if (strlen(resp->nonce) != NONCE_LEN ++ || resp->nonce[NONCE_TIME_LEN - 1] != '=') { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01775) +- "invalid nonce %s received - length is not %d", ++ "invalid nonce '%s' received - length is not %d " ++ "or time encoding is incorrect", + resp->nonce, NONCE_LEN); + note_digest_auth_failure(r, conf, resp, 1); + return HTTP_UNAUTHORIZED; diff --git a/httpd-2.4.37-CVE-2021-26690.patch b/httpd-2.4.37-CVE-2021-26690.patch new file mode 100644 index 0000000..f606576 --- /dev/null +++ b/httpd-2.4.37-CVE-2021-26690.patch @@ -0,0 +1,14 @@ +diff --git a/modules/session/mod_session.c b/modules/session/mod_session.c +index 7ee477c..049255d 100644 +--- a/modules/session/mod_session.c ++++ b/modules/session/mod_session.c +@@ -404,8 +404,8 @@ static apr_status_t session_identity_decode(request_rec * r, session_rec * z) + char *plast = NULL; + const char *psep = "="; + char *key = apr_strtok(pair, psep, &plast); +- char *val = apr_strtok(NULL, psep, &plast); + if (key && *key) { ++ char *val = apr_strtok(NULL, sep, &plast); + if (!val || !*val) { + apr_table_unset(z->entries, key); + } diff --git a/httpd-2.4.37-CVE-2021-26691.patch b/httpd-2.4.37-CVE-2021-26691.patch new file mode 100644 index 0000000..786aea2 --- /dev/null +++ b/httpd-2.4.37-CVE-2021-26691.patch @@ -0,0 +1,13 @@ +diff --git a/modules/session/mod_session.c b/modules/session/mod_session.c +index 049255d..af70f6b 100644 +--- a/modules/session/mod_session.c ++++ b/modules/session/mod_session.c +@@ -317,7 +317,7 @@ static apr_status_t ap_session_set(request_rec * r, session_rec * z, + static int identity_count(void *v, const char *key, const char *val) + { + int *count = v; +- *count += strlen(key) * 3 + strlen(val) * 3 + 1; ++ *count += strlen(key) * 3 + strlen(val) * 3 + 2; + return 1; + } + diff --git a/httpd-2.4.37-CVE-2021-30641.patch b/httpd-2.4.37-CVE-2021-30641.patch new file mode 100644 index 0000000..5a34afb --- /dev/null +++ b/httpd-2.4.37-CVE-2021-30641.patch @@ -0,0 +1,44 @@ +diff --git a/server/request.c b/server/request.c +index d5c558a..18625af 100644 +--- a/server/request.c ++++ b/server/request.c +@@ -1419,7 +1419,20 @@ AP_DECLARE(int) ap_location_walk(request_rec *r) + + cache = prep_walk_cache(AP_NOTE_LOCATION_WALK, r); + cached = (cache->cached != NULL); +- entry_uri = r->uri; ++ ++ /* ++ * When merge_slashes is set to AP_CORE_CONFIG_OFF the slashes in r->uri ++ * have not been merged. But for Location walks we always go with merged ++ * slashes no matter what merge_slashes is set to. ++ */ ++ if (sconf->merge_slashes != AP_CORE_CONFIG_OFF) { ++ entry_uri = r->uri; ++ } ++ else { ++ char *uri = apr_pstrdup(r->pool, r->uri); ++ ap_no2slash(uri); ++ entry_uri = uri; ++ } + + /* If we have an cache->cached location that matches r->uri, + * and the vhost's list of locations hasn't changed, we can skip +@@ -1486,7 +1499,7 @@ AP_DECLARE(int) ap_location_walk(request_rec *r) + pmatch = apr_palloc(rxpool, nmatch*sizeof(ap_regmatch_t)); + } + +- if (ap_regexec(entry_core->r, entry_uri, nmatch, pmatch, 0)) { ++ if (ap_regexec(entry_core->r, r->uri, nmatch, pmatch, 0)) { + continue; + } + +@@ -1496,7 +1509,7 @@ AP_DECLARE(int) ap_location_walk(request_rec *r) + apr_table_setn(r->subprocess_env, + ((const char **)entry_core->refs->elts)[i], + apr_pstrndup(r->pool, +- entry_uri + pmatch[i].rm_so, ++ r->uri + pmatch[i].rm_so, + pmatch[i].rm_eo - pmatch[i].rm_so)); + } + } diff --git a/httpd-2.4.37-CVE-2021-33193.patch b/httpd-2.4.37-CVE-2021-33193.patch new file mode 100644 index 0000000..cec1c96 --- /dev/null +++ b/httpd-2.4.37-CVE-2021-33193.patch @@ -0,0 +1,706 @@ +diff --git a/include/http_core.h b/include/http_core.h +index 8e10988..3ba8069 100644 +--- a/include/http_core.h ++++ b/include/http_core.h +@@ -741,6 +741,7 @@ typedef struct { + #define AP_HTTP_METHODS_REGISTERED 2 + char http_methods; + unsigned int merge_slashes; ++ unsigned int strict_host_check; + } core_server_config; + + /* for AddOutputFiltersByType in core.c */ +@@ -769,6 +770,11 @@ AP_DECLARE(void) ap_set_server_protocol(server_rec* s, const char* proto); + typedef struct core_output_filter_ctx core_output_filter_ctx_t; + typedef struct core_filter_ctx core_ctx_t; + ++struct core_filter_ctx { ++ apr_bucket_brigade *b; ++ apr_bucket_brigade *tmpbb; ++}; ++ + typedef struct core_net_rec { + /** Connection to the client */ + apr_socket_t *client_socket; +diff --git a/include/http_protocol.h b/include/http_protocol.h +index 11c7b2d..e7abdd9 100644 +--- a/include/http_protocol.h ++++ b/include/http_protocol.h +@@ -53,6 +53,13 @@ AP_DECLARE_DATA extern ap_filter_rec_t *ap_old_write_func; + * or control the ones that eventually do. + */ + ++/** ++ * Read an empty request and set reasonable defaults. ++ * @param c The current connection ++ * @return The new request_rec ++ */ ++AP_DECLARE(request_rec *) ap_create_request(conn_rec *c); ++ + /** + * Read a request and fill in the fields. + * @param c The current connection +@@ -60,6 +67,20 @@ AP_DECLARE_DATA extern ap_filter_rec_t *ap_old_write_func; + */ + request_rec *ap_read_request(conn_rec *c); + ++/** ++ * Parse and validate the request line. ++ * @param r The current request ++ * @return 1 on success, 0 on failure ++ */ ++AP_DECLARE(int) ap_parse_request_line(request_rec *r); ++ ++/** ++ * Validate the request header and select vhost. ++ * @param r The current request ++ * @return 1 on success, 0 on failure ++ */ ++AP_DECLARE(int) ap_check_request_header(request_rec *r); ++ + /** + * Read the mime-encoded headers. + * @param r The current request +diff --git a/include/http_vhost.h b/include/http_vhost.h +index 473c9c7..d2d9c97 100644 +--- a/include/http_vhost.h ++++ b/include/http_vhost.h +@@ -99,6 +99,19 @@ AP_DECLARE(void) ap_update_vhost_given_ip(conn_rec *conn); + */ + AP_DECLARE(void) ap_update_vhost_from_headers(request_rec *r); + ++/** ++ * Updates r->server with the best name-based virtual host match, within ++ * the chain of matching virtual hosts selected by ap_update_vhost_given_ip. ++ * @param r The current request ++ * @param require_match 1 to return an HTTP error if the requested hostname is ++ * not explicitly matched to a VirtualHost. ++ * @return return HTTP_OK unless require_match was specified and the requested ++ * hostname did not match any ServerName, ServerAlias, or VirtualHost ++ * address-spec. ++ */ ++AP_DECLARE(int) ap_update_vhost_from_headers_ex(request_rec *r, int require_match); ++ ++ + /** + * Match the host in the header with the hostname of the server for this + * request. +diff --git a/server/core.c b/server/core.c +index 84e80f2..23abf57 100644 +--- a/server/core.c ++++ b/server/core.c +@@ -498,6 +498,8 @@ static void *create_core_server_config(apr_pool_t *a, server_rec *s) + conf->protocols = apr_array_make(a, 5, sizeof(const char *)); + conf->protocols_honor_order = -1; + ++ conf->strict_host_check= AP_CORE_CONFIG_UNSET; ++ + return (void *)conf; + } + +@@ -565,6 +567,12 @@ static void *merge_core_server_configs(apr_pool_t *p, void *basev, void *virtv) + + AP_CORE_MERGE_FLAG(merge_slashes, conf, base, virt); + ++ conf->strict_host_check = (virt->strict_host_check != AP_CORE_CONFIG_UNSET) ++ ? virt->strict_host_check ++ : base->strict_host_check; ++ ++ AP_CORE_MERGE_FLAG(strict_host_check, conf, base, virt); ++ + return conf; + } + +@@ -4546,7 +4554,10 @@ AP_INIT_TAKE2("CGIVar", set_cgi_var, NULL, OR_FILEINFO, + AP_INIT_FLAG("QualifyRedirectURL", set_qualify_redirect_url, NULL, OR_FILEINFO, + "Controls whether HTTP authorization headers, normally hidden, will " + "be passed to scripts"), +- ++AP_INIT_FLAG("StrictHostCheck", set_core_server_flag, ++ (void *)APR_OFFSETOF(core_server_config, strict_host_check), ++ RSRC_CONF, ++ "Controls whether a hostname match is required"), + AP_INIT_TAKE1("ForceType", ap_set_string_slot_lower, + (void *)APR_OFFSETOF(core_dir_config, mime_type), OR_FILEINFO, + "a mime type that overrides other configured type"), +@@ -5581,4 +5592,3 @@ AP_DECLARE_MODULE(core) = { + core_cmds, /* command apr_table_t */ + register_hooks /* register hooks */ + }; +- +diff --git a/server/core_filters.c b/server/core_filters.c +index a6c2bd6..e08801f 100644 +--- a/server/core_filters.c ++++ b/server/core_filters.c +@@ -84,11 +84,6 @@ struct core_output_filter_ctx { + apr_size_t bytes_written; + }; + +-struct core_filter_ctx { +- apr_bucket_brigade *b; +- apr_bucket_brigade *tmpbb; +-}; +- + + apr_status_t ap_core_input_filter(ap_filter_t *f, apr_bucket_brigade *b, + ap_input_mode_t mode, apr_read_type_e block, +diff --git a/server/protocol.c b/server/protocol.c +index 8d1fdd2..430d91e 100644 +--- a/server/protocol.c ++++ b/server/protocol.c +@@ -609,8 +609,15 @@ AP_CORE_DECLARE(void) ap_parse_uri(request_rec *r, const char *uri) + } + + r->args = r->parsed_uri.query; +- r->uri = r->parsed_uri.path ? r->parsed_uri.path +- : apr_pstrdup(r->pool, "/"); ++ if (r->parsed_uri.path) { ++ r->uri = r->parsed_uri.path; ++ } ++ else if (r->method_number == M_OPTIONS) { ++ r->uri = apr_pstrdup(r->pool, "*"); ++ } ++ else { ++ r->uri = apr_pstrdup(r->pool, "/"); ++ } + + #if defined(OS2) || defined(WIN32) + /* Handle path translations for OS/2 and plug security hole. +@@ -645,13 +652,6 @@ static int field_name_len(const char *field) + + 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 = DEFAULT_LIMIT_BLANK_LINES; + core_server_config *conf = ap_get_core_module_config(r->server->module_config); +@@ -711,6 +711,20 @@ static int read_request_line(request_rec *r, apr_bucket_brigade *bb) + } + + r->request_time = apr_time_now(); ++ return 1; ++} ++ ++AP_DECLARE(int) ap_parse_request_line(request_rec *r) ++{ ++ core_server_config *conf = ap_get_core_module_config(r->server->module_config); ++ int strict = (conf->http_conformance != AP_HTTP_CONFORMANCE_UNSAFE); ++ 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; ++ apr_size_t len = 0; ++ char *uri, *ll; + + r->method = r->the_request; + +@@ -742,7 +756,6 @@ static int read_request_line(request_rec *r, apr_bucket_brigade *bb) + 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]) +@@ -773,7 +786,6 @@ static int read_request_line(request_rec *r, apr_bucket_brigade *bb) + /* 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]) +@@ -866,6 +878,14 @@ rrl_done: + r->header_only = 1; + + ap_parse_uri(r, uri); ++ if (r->status == HTTP_OK ++ && (r->parsed_uri.path != NULL) ++ && (r->parsed_uri.path[0] != '/') ++ && (r->method_number != M_OPTIONS ++ || strcmp(r->parsed_uri.path, "*") != 0)) { ++ /* Invalid request-target per RFC 7230 section 5.3 */ ++ r->status = HTTP_BAD_REQUEST; ++ } + + /* With the request understood, we can consider HTTP/0.9 specific errors */ + if (r->proto_num == HTTP_VERSION(0, 9) && deferred_error == rrl_none) { +@@ -973,6 +993,79 @@ rrl_failed: + return 0; + } + ++AP_DECLARE(int) ap_check_request_header(request_rec *r) ++{ ++ core_server_config *conf; ++ int strict_host_check; ++ const char *expect; ++ int access_status; ++ ++ conf = ap_get_core_module_config(r->server->module_config); ++ ++ /* update what we think the virtual host is based on the headers we've ++ * now read. may update status. ++ */ ++ strict_host_check = (conf->strict_host_check == AP_CORE_CONFIG_ON); ++ access_status = ap_update_vhost_from_headers_ex(r, strict_host_check); ++ if (strict_host_check && access_status != HTTP_OK) { ++ if (r->server == ap_server_conf) { ++ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(10156) ++ "Requested hostname '%s' did not match any ServerName/ServerAlias " ++ "in the global server configuration ", r->hostname); ++ } ++ else { ++ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(10157) ++ "Requested hostname '%s' did not match any ServerName/ServerAlias " ++ "in the matching virtual host (default vhost for " ++ "current connection is %s:%u)", ++ r->hostname, r->server->defn_name, r->server->defn_line_number); ++ } ++ r->status = access_status; ++ } ++ if (r->status != HTTP_OK) { ++ return 0; ++ } ++ ++ if ((!r->hostname && (r->proto_num >= HTTP_VERSION(1, 1))) ++ || ((r->proto_num == HTTP_VERSION(1, 1)) ++ && !apr_table_get(r->headers_in, "Host"))) { ++ /* ++ * Client sent us an HTTP/1.1 or later request without telling us the ++ * hostname, either with a full URL or a Host: header. We therefore ++ * need to (as per the 1.1 spec) send an error. As a special case, ++ * HTTP/1.1 mentions twice (S9, S14.23) that a request MUST contain ++ * a Host: header, and the server MUST respond with 400 if it doesn't. ++ */ ++ 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); ++ r->status = HTTP_BAD_REQUEST; ++ return 0; ++ } ++ ++ if (((expect = apr_table_get(r->headers_in, "Expect")) != NULL) ++ && (expect[0] != '\0')) { ++ /* ++ * The Expect header field was added to HTTP/1.1 after RFC 2068 ++ * as a means to signal when a 100 response is desired and, ++ * unfortunately, to signal a poor man's mandatory extension that ++ * the server must understand or return 417 Expectation Failed. ++ */ ++ if (ap_cstr_casecmp(expect, "100-continue") == 0) { ++ r->expecting_100 = 1; ++ } ++ else { ++ ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00570) ++ "client sent an unrecognized expectation value " ++ "of Expect: %s", expect); ++ r->status = HTTP_EXPECTATION_FAILED; ++ return 0; ++ } ++ } ++ ++ return 1; ++} ++ + static int table_do_fn_check_lengths(void *r_, const char *key, + const char *value) + { +@@ -1256,16 +1349,10 @@ AP_DECLARE(void) ap_get_mime_headers(request_rec *r) + apr_brigade_destroy(tmp_bb); + } + +-request_rec *ap_read_request(conn_rec *conn) ++AP_DECLARE(request_rec *) ap_create_request(conn_rec *conn) + { + request_rec *r; + apr_pool_t *p; +- const char *expect; +- int access_status; +- apr_bucket_brigade *tmp_bb; +- apr_socket_t *csd; +- apr_interval_time_t cur_timeout; +- + + apr_pool_create(&p, conn->pool); + apr_pool_tag(p, "request"); +@@ -1304,6 +1391,7 @@ request_rec *ap_read_request(conn_rec *conn) + r->read_body = REQUEST_NO_BODY; + + r->status = HTTP_OK; /* Until further notice */ ++ r->header_only = 0; + r->the_request = NULL; + + /* Begin by presuming any module can make its own path_info assumptions, +@@ -1314,12 +1402,33 @@ request_rec *ap_read_request(conn_rec *conn) + r->useragent_addr = conn->client_addr; + r->useragent_ip = conn->client_ip; + ++ return r; ++} ++ ++/* Apply the server's timeout/config to the connection/request. */ ++static void apply_server_config(request_rec *r) ++{ ++ apr_socket_t *csd; ++ ++ csd = ap_get_conn_socket(r->connection); ++ apr_socket_timeout_set(csd, r->server->timeout); ++ ++ r->per_dir_config = r->server->lookup_defaults; ++} ++ ++request_rec *ap_read_request(conn_rec *conn) ++{ ++ int access_status; ++ apr_bucket_brigade *tmp_bb; ++ ++ request_rec *r = ap_create_request(conn); + tmp_bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); + + ap_run_pre_read_request(r, conn); + + /* Get the request... */ +- if (!read_request_line(r, tmp_bb)) { ++ if (!read_request_line(r, tmp_bb) || !ap_parse_request_line(r)) { ++ apr_brigade_cleanup(tmp_bb); + switch (r->status) { + case HTTP_REQUEST_URI_TOO_LARGE: + case HTTP_BAD_REQUEST: +@@ -1335,49 +1444,38 @@ request_rec *ap_read_request(conn_rec *conn) + "request failed: malformed request line"); + } + 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; ++ goto die_unusable_input; ++ + case HTTP_REQUEST_TIME_OUT: ++ /* Just log, no further action on this connection. */ + 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; ++ break; + } ++ /* Not worth dying with. */ ++ conn->keepalive = AP_CONN_CLOSE; ++ apr_pool_destroy(r->pool); ++ goto ignore; + } ++ apr_brigade_cleanup(tmp_bb); + + /* We may have been in keep_alive_timeout mode, so toggle back + * to the normal timeout mode as we fetch the header lines, + * as necessary. + */ +- csd = ap_get_conn_socket(conn); +- apr_socket_timeout_get(csd, &cur_timeout); +- if (cur_timeout != conn->base_server->timeout) { +- apr_socket_timeout_set(csd, conn->base_server->timeout); +- cur_timeout = conn->base_server->timeout; +- } ++ apply_server_config(r); + + if (!r->assbackwards) { + const char *tenc; + + ap_get_mime_headers_core(r, tmp_bb); ++ apr_brigade_cleanup(tmp_bb); + if (r->status != HTTP_OK) { + 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); +- ap_run_log_transaction(r); +- apr_brigade_destroy(tmp_bb); +- goto traceout; ++ access_status = r->status; ++ goto die_unusable_input; + } + + tenc = apr_table_get(r->headers_in, "Transfer-Encoding"); +@@ -1393,13 +1491,8 @@ request_rec *ap_read_request(conn_rec *conn) + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02539) + "client sent unknown Transfer-Encoding " + "(%s): %s", tenc, r->uri); +- r->status = HTTP_BAD_REQUEST; +- conn->keepalive = AP_CONN_CLOSE; +- 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; ++ access_status = HTTP_BAD_REQUEST; ++ goto die_unusable_input; + } + + /* http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-23 +@@ -1412,88 +1505,81 @@ request_rec *ap_read_request(conn_rec *conn) + } + } + +- apr_brigade_destroy(tmp_bb); +- +- /* update what we think the virtual host is based on the headers we've +- * 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. +- */ +- if (cur_timeout != r->server->timeout) { +- apr_socket_timeout_set(csd, r->server->timeout); +- cur_timeout = r->server->timeout; +- } +- +- /* we may have switched to another server */ +- r->per_dir_config = r->server->lookup_defaults; +- +- if ((!r->hostname && (r->proto_num >= HTTP_VERSION(1, 1))) +- || ((r->proto_num == HTTP_VERSION(1, 1)) +- && !apr_table_get(r->headers_in, "Host"))) { +- /* +- * Client sent us an HTTP/1.1 or later request without telling us the +- * hostname, either with a full URL or a Host: header. We therefore +- * need to (as per the 1.1 spec) send an error. As a special case, +- * HTTP/1.1 mentions twice (S9, S14.23) that a request MUST contain +- * 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_DEBUG, 0, r, APLOGNO(00569) +- "client sent HTTP/1.1 request without hostname " +- "(see RFC2616 section 14.23): %s", r->uri); +- } +- + /* + * Add the HTTP_IN filter here to ensure that ap_discard_request_body + * called by ap_die and by ap_send_error_response works correctly on + * status codes that do not cause the connection to be dropped and + * in situations where the connection should be kept alive. + */ +- + ap_add_input_filter_handle(ap_http_input_filter_handle, + NULL, r, r->connection); + +- if (access_status != HTTP_OK +- || (access_status = ap_run_post_read_request(r))) { +- ap_die(access_status, r); +- ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r); +- ap_run_log_transaction(r); +- r = NULL; +- goto traceout; ++ /* Validate Host/Expect headers and select vhost. */ ++ if (!ap_check_request_header(r)) { ++ /* we may have switched to another server still */ ++ apply_server_config(r); ++ access_status = r->status; ++ goto die_before_hooks; + } + +- if (((expect = apr_table_get(r->headers_in, "Expect")) != NULL) +- && (expect[0] != '\0')) { +- /* +- * The Expect header field was added to HTTP/1.1 after RFC 2068 +- * as a means to signal when a 100 response is desired and, +- * unfortunately, to signal a poor man's mandatory extension that +- * the server must understand or return 417 Expectation Failed. +- */ +- if (strcasecmp(expect, "100-continue") == 0) { +- r->expecting_100 = 1; +- } +- else { +- r->status = HTTP_EXPECTATION_FAILED; +- ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, APLOGNO(00570) +- "client sent an unrecognized expectation value of " +- "Expect: %s", expect); +- ap_send_error_response(r, 0); +- ap_update_child_status(conn->sbh, SERVER_BUSY_LOG, r); +- ap_run_log_transaction(r); +- goto traceout; +- } ++ /* we may have switched to another server */ ++ apply_server_config(r); ++ ++ if ((access_status = ap_run_post_read_request(r))) { ++ goto die; + } + +- AP_READ_REQUEST_SUCCESS((uintptr_t)r, (char *)r->method, (char *)r->uri, (char *)r->server->defn_name, r->status); ++ AP_READ_REQUEST_SUCCESS((uintptr_t)r, (char *)r->method, ++ (char *)r->uri, (char *)r->server->defn_name, ++ r->status); ++ + return r; +- traceout: ++ ++ /* Everything falls through on failure */ ++ ++die_unusable_input: ++ /* Input filters are in an undeterminate state, cleanup (including ++ * CORE_IN's socket) such that any further attempt to read is EOF. ++ */ ++ { ++ ap_filter_t *f = conn->input_filters; ++ while (f) { ++ if (f->frec == ap_core_input_filter_handle) { ++ core_net_rec *net = f->ctx; ++ apr_brigade_cleanup(net->in_ctx->b); ++ break; ++ } ++ ap_remove_input_filter(f); ++ f = f->next; ++ } ++ conn->input_filters = r->input_filters = f; ++ conn->keepalive = AP_CONN_CLOSE; ++ } ++ ++die_before_hooks: ++ /* First call to ap_die() (non recursive) */ ++ r->status = HTTP_OK; ++ ++die: ++ ap_die(access_status, r); ++ ++ /* ap_die() sent the response through the output filters, we must now ++ * end the request with an EOR bucket for stream/pipeline accounting. ++ */ ++ { ++ apr_bucket_brigade *eor_bb; ++ eor_bb = apr_brigade_create(conn->pool, conn->bucket_alloc); ++ APR_BRIGADE_INSERT_TAIL(eor_bb, ++ ap_bucket_eor_create(conn->bucket_alloc, r)); ++ ap_pass_brigade(conn->output_filters, eor_bb); ++ apr_brigade_cleanup(eor_bb); ++ } ++ ++ignore: ++ r = NULL; ++ + AP_READ_REQUEST_FAILURE((uintptr_t)r); +- return r; ++ return NULL; + } + + /* if a request with a body creates a subrequest, remove original request's +diff --git a/server/vhost.c b/server/vhost.c +index b23b2dd..6e233b5 100644 +--- a/server/vhost.c ++++ b/server/vhost.c +@@ -34,6 +34,7 @@ + #include "http_vhost.h" + #include "http_protocol.h" + #include "http_core.h" ++#include "http_main.h" + + #if APR_HAVE_ARPA_INET_H + #include +@@ -973,7 +974,13 @@ AP_DECLARE(int) ap_matches_request_vhost(request_rec *r, const char *host, + } + + +-static void check_hostalias(request_rec *r) ++/* ++ * Updates r->server from ServerName/ServerAlias. Per the interaction ++ * of ip and name-based vhosts, it only looks in the best match from the ++ * connection-level ip-based matching. ++ * Returns HTTP_BAD_REQUEST if there was no match. ++ */ ++static int update_server_from_aliases(request_rec *r) + { + /* + * Even if the request has a Host: header containing a port we ignore +@@ -1050,11 +1057,18 @@ static void check_hostalias(request_rec *r) + goto found; + } + +- return; ++ if (!r->connection->vhost_lookup_data) { ++ if (matches_aliases(r->server, host)) { ++ s = r->server; ++ goto found; ++ } ++ } ++ return HTTP_BAD_REQUEST; + + found: + /* s is the first matching server, we're done */ + r->server = s; ++ return HTTP_OK; + } + + +@@ -1071,7 +1085,7 @@ static void check_serverpath(request_rec *r) + * This is in conjunction with the ServerPath code in http_core, so we + * get the right host attached to a non- Host-sending request. + * +- * See the comment in check_hostalias about how each vhost can be ++ * See the comment in update_server_from_aliases about how each vhost can be + * listed multiple times. + */ + +@@ -1134,11 +1148,17 @@ static APR_INLINE const char *construct_host_header(request_rec *r, + } + + AP_DECLARE(void) ap_update_vhost_from_headers(request_rec *r) ++{ ++ ap_update_vhost_from_headers_ex(r, 0); ++} ++ ++AP_DECLARE(int) ap_update_vhost_from_headers_ex(request_rec *r, int require_match) + { + 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; ++ int rc = HTTP_OK; + + if (r->hostname) { + /* +@@ -1151,8 +1171,8 @@ AP_DECLARE(void) ap_update_vhost_from_headers(request_rec *r) + else if (host_header != NULL) { + is_v6literal = fix_hostname(r, host_header, conf->http_conformance); + } +- if (r->status != HTTP_OK) +- return; ++ if (!require_match && r->status != HTTP_OK) ++ return HTTP_OK; + + if (conf->http_conformance != AP_HTTP_CONFORMANCE_UNSAFE) { + /* +@@ -1173,10 +1193,16 @@ AP_DECLARE(void) ap_update_vhost_from_headers(request_rec *r) + /* check if we tucked away a name_chain */ + if (r->connection->vhost_lookup_data) { + if (r->hostname) +- check_hostalias(r); ++ rc = update_server_from_aliases(r); + else + check_serverpath(r); + } ++ else if (require_match && r->hostname) { ++ /* check the base server config */ ++ rc = update_server_from_aliases(r); ++ } ++ ++ return rc; + } + + /** diff --git a/httpd-2.4.37-CVE-2021-34798.patch b/httpd-2.4.37-CVE-2021-34798.patch new file mode 100644 index 0000000..4a03341 --- /dev/null +++ b/httpd-2.4.37-CVE-2021-34798.patch @@ -0,0 +1,13 @@ +diff --git a/server/scoreboard.c b/server/scoreboard.c +index 23e3d70..7b01bdf 100644 +--- a/server/scoreboard.c ++++ b/server/scoreboard.c +@@ -376,7 +376,7 @@ AP_DECLARE(void) ap_increment_counts(ap_sb_handle_t *sb, request_rec *r) + if (pfn_ap_logio_get_last_bytes != NULL) { + bytes = pfn_ap_logio_get_last_bytes(r->connection); + } +- else if (r->method_number == M_GET && r->method[0] == 'H') { ++ else if (r->method_number == M_GET && r->method && r->method[0] == 'H') { + bytes = 0; + } + else { diff --git a/httpd-2.4.37-CVE-2021-36160.patch b/httpd-2.4.37-CVE-2021-36160.patch new file mode 100644 index 0000000..f67a391 --- /dev/null +++ b/httpd-2.4.37-CVE-2021-36160.patch @@ -0,0 +1,45 @@ +diff --git a/modules/proxy/mod_proxy_uwsgi.c b/modules/proxy/mod_proxy_uwsgi.c +index 792d35e..9dcbed1 100644 +--- a/modules/proxy/mod_proxy_uwsgi.c ++++ b/modules/proxy/mod_proxy_uwsgi.c +@@ -453,11 +453,8 @@ static int uwsgi_handler(request_rec *r, proxy_worker * worker, + const char *proxyname, apr_port_t proxyport) + { + int status; +- int delta = 0; +- int decode_status; + proxy_conn_rec *backend = NULL; + apr_pool_t *p = r->pool; +- size_t w_len; + char server_portstr[32]; + char *u_path_info; + apr_uri_t *uri; +@@ -469,23 +466,14 @@ static int uwsgi_handler(request_rec *r, proxy_worker * worker, + + uri = apr_palloc(r->pool, sizeof(*uri)); + +- /* ADD PATH_INFO */ +-#if AP_MODULE_MAGIC_AT_LEAST(20111130,0) +- w_len = strlen(worker->s->name); +-#else +- w_len = strlen(worker->name); +-#endif +- u_path_info = r->filename + 6 + w_len; +- if (u_path_info[0] != '/') { +- delta = 1; +- } +- decode_status = ap_unescape_url(url + w_len - delta); +- if (decode_status) { ++ /* ADD PATH_INFO (unescaped) */ ++ u_path_info = ap_strchr(url + sizeof(UWSGI_SCHEME) + 2, '/'); ++ if (!u_path_info || ap_unescape_url(u_path_info) != OK) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10100) +- "unable to decode uri: %s", url + w_len - delta); ++ "unable to decode uwsgi uri: %s", url); + return HTTP_INTERNAL_SERVER_ERROR; + } +- apr_table_add(r->subprocess_env, "PATH_INFO", url + w_len - delta); ++ apr_table_add(r->subprocess_env, "PATH_INFO", u_path_info); + + + /* Create space for state information */ diff --git a/httpd-2.4.37-CVE-2021-39275.patch b/httpd-2.4.37-CVE-2021-39275.patch new file mode 100644 index 0000000..590268f --- /dev/null +++ b/httpd-2.4.37-CVE-2021-39275.patch @@ -0,0 +1,21 @@ +diff --git a/server/util.c b/server/util.c +index e0c558c..2a5dd04 100644 +--- a/server/util.c ++++ b/server/util.c +@@ -2460,13 +2460,12 @@ AP_DECLARE(char *) ap_escape_quotes(apr_pool_t *p, const char *instring) + * in front of every " that doesn't already have one. + */ + while (*inchr != '\0') { +- if ((*inchr == '\\') && (inchr[1] != '\0')) { +- *outchr++ = *inchr++; +- *outchr++ = *inchr++; +- } + if (*inchr == '"') { + *outchr++ = '\\'; + } ++ if ((*inchr == '\\') && (inchr[1] != '\0')) { ++ *outchr++ = *inchr++; ++ } + if (*inchr != '\0') { + *outchr++ = *inchr++; + } diff --git a/httpd-2.4.37-CVE-2021-40438.patch b/httpd-2.4.37-CVE-2021-40438.patch new file mode 100644 index 0000000..39758c7 --- /dev/null +++ b/httpd-2.4.37-CVE-2021-40438.patch @@ -0,0 +1,126 @@ +diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c +index fb897a9..38dbb24 100644 +--- a/modules/mappers/mod_rewrite.c ++++ b/modules/mappers/mod_rewrite.c +@@ -619,6 +619,13 @@ static unsigned is_absolute_uri(char *uri, int *supportsqs) + return 6; + } + break; ++ ++ case 'u': ++ case 'U': ++ if (!ap_cstr_casecmpn(uri, "nix:", 4)) { /* unix: */ ++ *sqs = 1; ++ return (uri[4] == '/' && uri[5] == '/') ? 7 : 5; ++ } + } + + return 0; +diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c +index f383996..6a9ef55 100644 +--- a/modules/proxy/mod_proxy.c ++++ b/modules/proxy/mod_proxy.c +@@ -1717,7 +1717,8 @@ PROXY_DECLARE(const char *) ap_proxy_de_socketfy(apr_pool_t *p, const char *url) + * the UDS path... ignore it + */ + if (!strncasecmp(url, "unix:", 5) && +- ((ptr = ap_strchr_c(url, '|')) != NULL)) { ++ ((ptr = ap_strchr_c(url + 5, '|')) != NULL)) { ++ + /* move past the 'unix:...|' UDS path info */ + const char *ret, *c; + +diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c +index 7714b6c..3dd570c 100644 +--- a/modules/proxy/proxy_util.c ++++ b/modules/proxy/proxy_util.c +@@ -2084,33 +2084,45 @@ static int ap_proxy_retry_worker(const char *proxy_function, proxy_worker *worke + * were passed a UDS url (eg: from mod_proxy) and adjust uds_path + * as required. + */ +-static void fix_uds_filename(request_rec *r, char **url) ++static int fix_uds_filename(request_rec *r, char **url) + { +- char *ptr, *ptr2; +- if (!r || !r->filename) return; ++ char *uds_url = r->filename + 6, *origin_url; + + if (!strncmp(r->filename, "proxy:", 6) && +- (ptr2 = ap_strcasestr(r->filename, "unix:")) && +- (ptr = ap_strchr(ptr2, '|'))) { ++ !ap_cstr_casecmpn(uds_url, "unix:", 5) && ++ (origin_url = ap_strchr(uds_url + 5, '|'))) { ++ char *uds_path = NULL; ++ apr_size_t url_len; + 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 = '|'; +- } +- } ++ ++ *origin_url = '\0'; ++ rv = apr_uri_parse(r->pool, uds_url, &urisock); ++ *origin_url++ = '|'; ++ ++ if (rv == APR_SUCCESS && urisock.path && (!urisock.hostname ++ || !urisock.hostname[0])) { ++ uds_path = ap_runtime_dir_relative(r->pool, urisock.path); ++ } ++ ++ if (!uds_path) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10292) ++ "Invalid proxy UDS filename (%s)", r->filename); ++ return 0; ++ } ++ apr_table_setn(r->notes, "uds_path", uds_path); ++ ++ /* Remove the UDS path from *url and r->filename */ ++ url_len = strlen(origin_url); ++ *url = apr_pstrmemdup(r->pool, origin_url, url_len); ++ memcpy(uds_url, *url, url_len + 1); ++ ++ ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, ++ "*: rewrite of url due to UDS(%s): %s (%s)", ++ uds_path, *url, r->filename); ++ } ++ ++ return 1; + } + + PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker, +@@ -2128,7 +2140,9 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker, + "%s: found worker %s for %s", + (*worker)->s->scheme, (*worker)->s->name, *url); + *balancer = NULL; +- fix_uds_filename(r, url); ++ if (!fix_uds_filename(r, url)) { ++ return HTTP_INTERNAL_SERVER_ERROR; ++ } + access_status = OK; + } + else if (r->proxyreq == PROXYREQ_PROXY) { +@@ -2159,7 +2173,9 @@ 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"); +- fix_uds_filename(r, url); ++ if (!fix_uds_filename(r, url)) { ++ return HTTP_INTERNAL_SERVER_ERROR; ++ } + } + } + } diff --git a/httpd-2.4.37-CVE-2021-44224.patch b/httpd-2.4.37-CVE-2021-44224.patch new file mode 100644 index 0000000..d3633fc --- /dev/null +++ b/httpd-2.4.37-CVE-2021-44224.patch @@ -0,0 +1,315 @@ +diff --git a/include/http_protocol.h b/include/http_protocol.h +index e7abdd9..e1572dc 100644 +--- a/include/http_protocol.h ++++ b/include/http_protocol.h +@@ -96,6 +96,13 @@ AP_DECLARE(void) ap_get_mime_headers(request_rec *r); + AP_DECLARE(void) ap_get_mime_headers_core(request_rec *r, + apr_bucket_brigade *bb); + ++/** ++ * Run post_read_request hook and validate. ++ * @param r The current request ++ * @return OK or HTTP_... ++ */ ++AP_DECLARE(int) ap_post_read_request(request_rec *r); ++ + /* Finish up stuff after a request */ + + /** +diff --git a/modules/http/http_request.c b/modules/http/http_request.c +index 9e7c4db..e873aab 100644 +--- a/modules/http/http_request.c ++++ b/modules/http/http_request.c +@@ -681,7 +681,7 @@ static request_rec *internal_internal_redirect(const char *new_uri, + * to do their thing on internal redirects as well. Perhaps this is a + * misnamed function. + */ +- if ((access_status = ap_run_post_read_request(new))) { ++ if ((access_status = ap_post_read_request(new))) { + ap_die(access_status, new); + return NULL; + } +diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c +index 6a9ef55..a6df1b8 100644 +--- a/modules/proxy/mod_proxy.c ++++ b/modules/proxy/mod_proxy.c +@@ -584,11 +584,12 @@ static int proxy_detect(request_rec *r) + + if (conf->req && r->parsed_uri.scheme) { + /* but it might be something vhosted */ +- if (!(r->parsed_uri.hostname +- && !strcasecmp(r->parsed_uri.scheme, ap_http_scheme(r)) +- && ap_matches_request_vhost(r, r->parsed_uri.hostname, +- (apr_port_t)(r->parsed_uri.port_str ? r->parsed_uri.port +- : ap_default_port(r))))) { ++ if (!r->parsed_uri.hostname ++ || ap_cstr_casecmp(r->parsed_uri.scheme, ap_http_scheme(r)) != 0 ++ || !ap_matches_request_vhost(r, r->parsed_uri.hostname, ++ (apr_port_t)(r->parsed_uri.port_str ++ ? r->parsed_uri.port ++ : ap_default_port(r)))) { + r->proxyreq = PROXYREQ_PROXY; + r->uri = r->unparsed_uri; + r->filename = apr_pstrcat(r->pool, "proxy:", r->uri, NULL); +@@ -1750,6 +1751,7 @@ static const char * + struct proxy_alias *new; + char *f = cmd->path; + char *r = NULL; ++ const char *real; + char *word; + apr_table_t *params = apr_table_make(cmd->pool, 5); + const apr_array_header_t *arr; +@@ -1815,6 +1817,10 @@ static const char * + if (r == NULL) { + return "ProxyPass|ProxyPassMatch needs a path when not defined in a location"; + } ++ if (!(real = ap_proxy_de_socketfy(cmd->temp_pool, r))) { ++ return "ProxyPass|ProxyPassMatch uses an invalid \"unix:\" URL"; ++ } ++ + + /* if per directory, save away the single alias */ + if (cmd->path) { +@@ -1831,7 +1837,7 @@ static const char * + } + + new->fake = apr_pstrdup(cmd->pool, f); +- new->real = apr_pstrdup(cmd->pool, ap_proxy_de_socketfy(cmd->pool, r)); ++ new->real = apr_pstrdup(cmd->pool, real); + new->flags = flags; + if (use_regex) { + new->regex = ap_pregcomp(cmd->pool, f, AP_REG_EXTENDED); +@@ -2316,6 +2322,7 @@ static const char *add_member(cmd_parms *cmd, void *dummy, const char *arg) + proxy_worker *worker; + char *path = cmd->path; + char *name = NULL; ++ const char *real; + char *word; + apr_table_t *params = apr_table_make(cmd->pool, 5); + const apr_array_header_t *arr; +@@ -2356,6 +2363,9 @@ static const char *add_member(cmd_parms *cmd, void *dummy, const char *arg) + return "BalancerMember must define balancer name when outside section"; + if (!name) + return "BalancerMember must define remote proxy server"; ++ if (!(real = ap_proxy_de_socketfy(cmd->temp_pool, name))) { ++ return "BalancerMember uses an invalid \"unix:\" URL"; ++ } + + ap_str_tolower(path); /* lowercase scheme://hostname */ + +@@ -2368,7 +2378,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, ap_proxy_de_socketfy(cmd->temp_pool, name)); ++ worker = ap_proxy_get_worker(cmd->temp_pool, balancer, conf, real); + if (!worker) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, APLOGNO(01147) + "Defining worker '%s' for balancer '%s'", +@@ -2457,7 +2467,13 @@ static const char * + } + } + else { +- worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, ap_proxy_de_socketfy(cmd->temp_pool, name)); ++ const char *real; ++ ++ if (!(real = ap_proxy_de_socketfy(cmd->temp_pool, name))) { ++ return "ProxySet uses an invalid \"unix:\" URL"; ++ } ++ ++ worker = ap_proxy_get_worker(cmd->temp_pool, NULL, conf, real); + if (!worker) { + if (in_proxy_section) { + err = ap_proxy_define_worker(cmd->pool, &worker, NULL, +@@ -2599,8 +2615,14 @@ static const char *proxysection(cmd_parms *cmd, void *mconfig, const char *arg) + } + } + else { ++ const char *real; ++ ++ if (!(real = ap_proxy_de_socketfy(cmd->temp_pool, conf->p))) { ++ return " uses an invalid \"unix:\" URL"; ++ } ++ + worker = ap_proxy_get_worker(cmd->temp_pool, NULL, sconf, +- ap_proxy_de_socketfy(cmd->temp_pool, (char*)conf->p)); ++ real); + if (!worker) { + err = ap_proxy_define_worker(cmd->pool, &worker, NULL, + sconf, conf->p, 0); +diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h +index fbbd508..dca6f69 100644 +--- a/modules/proxy/mod_proxy.h ++++ b/modules/proxy/mod_proxy.h +@@ -713,6 +713,8 @@ typedef __declspec(dllimport) const char * + proxy_dir_conf *, const char *); + #endif + ++#define AP_PROXY_WORKER_NO_UDS (1u << 3) ++ + + /* Connection pool API */ + /** +@@ -725,6 +727,24 @@ typedef __declspec(dllimport) const char * + PROXY_DECLARE(char *) ap_proxy_worker_name(apr_pool_t *p, + proxy_worker *worker); + ++ ++/** ++ * Get the worker from proxy configuration, looking for either PREFIXED or ++ * MATCHED or both types of workers according to given mask ++ * @param p memory pool used for finding worker ++ * @param balancer the balancer that the worker belongs to ++ * @param conf current proxy server configuration ++ * @param url url to find the worker from ++ * @param mask bitmask of AP_PROXY_WORKER_IS_* ++ * @return proxy_worker or NULL if not found ++ */ ++PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker_ex(apr_pool_t *p, ++ proxy_balancer *balancer, ++ proxy_server_conf *conf, ++ const char *url, ++ unsigned int mask); ++ ++ + /** + * Get the worker from proxy configuration + * @param p memory pool used for finding worker +@@ -737,6 +757,8 @@ PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p, + proxy_balancer *balancer, + proxy_server_conf *conf, + const char *url); ++ ++ + /** + * Define and Allocate space for the worker to proxy configuration + * @param p memory pool to allocate worker from +diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c +index 032e0c4..3d5b220 100644 +--- a/modules/proxy/proxy_util.c ++++ b/modules/proxy/proxy_util.c +@@ -1643,10 +1643,11 @@ PROXY_DECLARE(char *) ap_proxy_worker_name(apr_pool_t *p, + return apr_pstrcat(p, "unix:", worker->s->uds_path, "|", worker->s->name, NULL); + } + +-PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p, +- proxy_balancer *balancer, +- proxy_server_conf *conf, +- const char *url) ++PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker_ex(apr_pool_t *p, ++ proxy_balancer *balancer, ++ proxy_server_conf *conf, ++ const char *url, ++ unsigned int mask) + { + proxy_worker *worker; + proxy_worker *max_worker = NULL; +@@ -1662,7 +1663,12 @@ PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p, + return NULL; + } + +- url = ap_proxy_de_socketfy(p, url); ++ if (!(mask & AP_PROXY_WORKER_NO_UDS)) { ++ url = ap_proxy_de_socketfy(p, url); ++ if (!url) { ++ return NULL; ++ } ++ } + + c = ap_strchr_c(url, ':'); + if (c == NULL || c[1] != '/' || c[2] != '/' || c[3] == '\0') { +@@ -1727,6 +1733,14 @@ PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p, + return max_worker; + } + ++PROXY_DECLARE(proxy_worker *) ap_proxy_get_worker(apr_pool_t *p, ++ proxy_balancer *balancer, ++ proxy_server_conf *conf, ++ const char *url) ++{ ++ return ap_proxy_get_worker_ex(p, balancer, conf, url, 0); ++} ++ + /* + * To create a worker from scratch first we define the + * specifics of the worker; this is all local data. +@@ -2134,22 +2148,22 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker, + + access_status = proxy_run_pre_request(worker, balancer, r, conf, url); + if (access_status == DECLINED && *balancer == NULL) { +- *worker = ap_proxy_get_worker(r->pool, NULL, conf, *url); ++ const int forward = (r->proxyreq == PROXYREQ_PROXY); ++ *worker = ap_proxy_get_worker_ex(r->pool, NULL, conf, *url, ++ forward ? AP_PROXY_WORKER_NO_UDS : 0); + if (*worker) { + ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, + "%s: found worker %s for %s", + (*worker)->s->scheme, (*worker)->s->name, *url); +- *balancer = NULL; +- if (!fix_uds_filename(r, url)) { ++ if (!forward && !fix_uds_filename(r, url)) { + return HTTP_INTERNAL_SERVER_ERROR; + } + access_status = OK; + } +- else if (r->proxyreq == PROXYREQ_PROXY) { ++ else if (forward) { + if (conf->forward) { + ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, + "*: found forward proxy worker for %s", *url); +- *balancer = NULL; + *worker = conf->forward; + access_status = OK; + /* +@@ -2163,8 +2177,8 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker, + else if (r->proxyreq == PROXYREQ_REVERSE) { + if (conf->reverse) { + ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, +- "*: using default reverse proxy worker for %s (no keepalive)", *url); +- *balancer = NULL; ++ "*: using default reverse proxy worker for %s " ++ "(no keepalive)", *url); + *worker = conf->reverse; + access_status = OK; + /* +diff --git a/server/protocol.c b/server/protocol.c +index 430d91e..a2aa081 100644 +--- a/server/protocol.c ++++ b/server/protocol.c +@@ -1525,7 +1525,7 @@ request_rec *ap_read_request(conn_rec *conn) + /* we may have switched to another server */ + apply_server_config(r); + +- if ((access_status = ap_run_post_read_request(r))) { ++ if ((access_status = ap_post_read_request(r))) { + goto die; + } + +@@ -1582,6 +1582,27 @@ ignore: + return NULL; + } + ++AP_DECLARE(int) ap_post_read_request(request_rec *r) ++{ ++ int status; ++ ++ if ((status = ap_run_post_read_request(r))) { ++ return status; ++ } ++ ++ /* Enforce http(s) only scheme for non-forward-proxy requests */ ++ if (!r->proxyreq ++ && r->parsed_uri.scheme ++ && (ap_cstr_casecmpn(r->parsed_uri.scheme, "http", 4) != 0 ++ || (r->parsed_uri.scheme[4] != '\0' ++ && (apr_tolower(r->parsed_uri.scheme[4]) != 's' ++ || r->parsed_uri.scheme[5] != '\0')))) { ++ return HTTP_BAD_REQUEST; ++ } ++ ++ return OK; ++} ++ + /* if a request with a body creates a subrequest, remove original request's + * input headers which pertain to the body which has already been read. + * out-of-line helper function for ap_set_sub_req_protocol. diff --git a/httpd-2.4.37-CVE-2021-44790.patch b/httpd-2.4.37-CVE-2021-44790.patch new file mode 100644 index 0000000..4f244a8 --- /dev/null +++ b/httpd-2.4.37-CVE-2021-44790.patch @@ -0,0 +1,12 @@ +diff --git a/modules/lua/lua_request.c b/modules/lua/lua_request.c +index 77a88b4..1d8be2e 100644 +--- a/modules/lua/lua_request.c ++++ b/modules/lua/lua_request.c +@@ -376,6 +376,7 @@ static int req_parsebody(lua_State *L) + if (end == NULL) break; + key = (char *) apr_pcalloc(r->pool, 256); + filename = (char *) apr_pcalloc(r->pool, 256); ++ if (end - crlf <= 8) break; + vlen = end - crlf - 8; + buffer = (char *) apr_pcalloc(r->pool, vlen+1); + memcpy(buffer, crlf + 4, vlen); diff --git a/httpd-2.4.37-CVE-2022-22720.patch b/httpd-2.4.37-CVE-2022-22720.patch new file mode 100644 index 0000000..e4abca2 --- /dev/null +++ b/httpd-2.4.37-CVE-2022-22720.patch @@ -0,0 +1,154 @@ +diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c +index 9828cdf..6bedcac 100644 +--- a/modules/http/http_filters.c ++++ b/modules/http/http_filters.c +@@ -1605,9 +1605,9 @@ AP_DECLARE(int) ap_map_http_request_error(apr_status_t rv, int status) + */ + AP_DECLARE(int) ap_discard_request_body(request_rec *r) + { ++ int rc = OK; ++ conn_rec *c = r->connection; + apr_bucket_brigade *bb; +- 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 +@@ -1616,54 +1616,57 @@ AP_DECLARE(int) ap_discard_request_body(request_rec *r) + * + * This function is also a no-op on a subrequest. + */ +- if (r->main || r->connection->keepalive == AP_CONN_CLOSE || +- ap_status_drops_connection(r->status)) { ++ if (r->main || c->keepalive == AP_CONN_CLOSE) { ++ return OK; ++ } ++ if (ap_status_drops_connection(r->status)) { ++ c->keepalive = AP_CONN_CLOSE; + return OK; + } + + bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); +- seen_eos = 0; +- do { +- apr_bucket *bucket; ++ for (;;) { ++ apr_status_t rv; + + rv = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES, + APR_BLOCK_READ, HUGE_STRING_LEN); +- + if (rv != APR_SUCCESS) { +- apr_brigade_destroy(bb); +- return ap_map_http_request_error(rv, HTTP_BAD_REQUEST); ++ rc = ap_map_http_request_error(rv, HTTP_BAD_REQUEST); ++ goto cleanup; + } + +- for (bucket = APR_BRIGADE_FIRST(bb); +- bucket != APR_BRIGADE_SENTINEL(bb); +- bucket = APR_BUCKET_NEXT(bucket)) +- { +- const char *data; +- apr_size_t len; ++ while (!APR_BRIGADE_EMPTY(bb)) { ++ apr_bucket *b = APR_BRIGADE_FIRST(bb); + +- if (APR_BUCKET_IS_EOS(bucket)) { +- seen_eos = 1; +- break; ++ if (APR_BUCKET_IS_EOS(b)) { ++ goto cleanup; + } + +- /* These are metadata buckets. */ +- if (bucket->length == 0) { +- continue; +- } +- +- /* We MUST read because in case we have an unknown-length +- * bucket or one that morphs, we want to exhaust it. ++ /* There is no need to read empty or metadata buckets or ++ * buckets of known length, but we MUST read buckets of ++ * unknown length in order to exhaust them. + */ +- rv = apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ); ++ if (b->length == (apr_size_t)-1) { ++ apr_size_t len; ++ const char *data; ++ ++ rv = apr_bucket_read(b, &data, &len, APR_BLOCK_READ); + if (rv != APR_SUCCESS) { +- apr_brigade_destroy(bb); +- return HTTP_BAD_REQUEST; ++ rc = HTTP_BAD_REQUEST; ++ goto cleanup; + } + } +- apr_brigade_cleanup(bb); +- } while (!seen_eos); + +- return OK; ++ apr_bucket_delete(b); ++ } ++ } ++ ++cleanup: ++ apr_brigade_cleanup(bb); ++ if (rc != OK) { ++ c->keepalive = AP_CONN_CLOSE; ++ } ++ return rc; + } + + /* Here we deal with getting the request message body from the client. +diff --git a/server/protocol.c b/server/protocol.c +index a2aa081..a554970 100644 +--- a/server/protocol.c ++++ b/server/protocol.c +@@ -1666,23 +1666,29 @@ AP_DECLARE(void) ap_set_sub_req_protocol(request_rec *rnew, + rnew->main = (request_rec *) r; + } + +-static void end_output_stream(request_rec *r) ++static void end_output_stream(request_rec *r, int status) + { + conn_rec *c = r->connection; + apr_bucket_brigade *bb; + apr_bucket *b; + + bb = apr_brigade_create(r->pool, c->bucket_alloc); ++ if (status != OK) { ++ b = ap_bucket_error_create(status, NULL, r->pool, c->bucket_alloc); ++ APR_BRIGADE_INSERT_TAIL(bb, b); ++ } + b = apr_bucket_eos_create(c->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(bb, b); ++ + ap_pass_brigade(r->output_filters, bb); ++ apr_brigade_cleanup(bb); + } + + AP_DECLARE(void) ap_finalize_sub_req_protocol(request_rec *sub) + { + /* tell the filter chain there is no more content coming */ + if (!sub->eos_sent) { +- end_output_stream(sub); ++ end_output_stream(sub, OK); + } + } + +@@ -1693,11 +1699,11 @@ AP_DECLARE(void) ap_finalize_sub_req_protocol(request_rec *sub) + */ + AP_DECLARE(void) ap_finalize_request_protocol(request_rec *r) + { +- (void) ap_discard_request_body(r); ++ int status = ap_discard_request_body(r); + + /* tell the filter chain there is no more content coming */ + if (!r->eos_sent) { +- end_output_stream(r); ++ end_output_stream(r, status); + } + } + diff --git a/httpd-2.4.37-balancer-failover.patch b/httpd-2.4.37-balancer-failover.patch new file mode 100644 index 0000000..ca691f7 --- /dev/null +++ b/httpd-2.4.37-balancer-failover.patch @@ -0,0 +1,225 @@ +diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c +index ec1e042..2c0500f 100644 +--- a/modules/proxy/mod_proxy_http.c ++++ b/modules/proxy/mod_proxy_http.c +@@ -310,16 +310,18 @@ static int stream_reqbody_read(proxy_http_req_t *req, apr_bucket_brigade *bb, + return OK; + } + +-static int stream_reqbody(proxy_http_req_t *req, rb_methods rb_method) ++static int stream_reqbody(proxy_http_req_t *req) + { + request_rec *r = req->r; + int seen_eos = 0, rv = OK; + apr_size_t hdr_len; + char chunk_hdr[20]; /* must be here due to transient bucket. */ ++ conn_rec *origin = req->origin; + proxy_conn_rec *p_conn = req->backend; + apr_bucket_alloc_t *bucket_alloc = req->bucket_alloc; + apr_bucket_brigade *header_brigade = req->header_brigade; + apr_bucket_brigade *input_brigade = req->input_brigade; ++ rb_methods rb_method = req->rb_method; + apr_off_t bytes, bytes_streamed = 0; + apr_bucket *e; + +@@ -333,7 +335,7 @@ static int stream_reqbody(proxy_http_req_t *req, rb_methods rb_method) + } + + if (!APR_BRIGADE_EMPTY(input_brigade)) { +- /* If this brigade contains EOS, either stop or remove it. */ ++ /* If this brigade contains EOS, remove it and be done. */ + if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { + seen_eos = 1; + +@@ -375,7 +377,8 @@ static int stream_reqbody(proxy_http_req_t *req, rb_methods rb_method) + APR_BRIGADE_INSERT_TAIL(input_brigade, e); + } + } +- else if (bytes_streamed > req->cl_val) { ++ else if (rb_method == RB_STREAM_CL ++ && bytes_streamed > req->cl_val) { + /* C-L < bytes streamed?!? + * We will error out after the body is completely + * consumed, but we can't stream more bytes at the +@@ -407,7 +410,7 @@ static int stream_reqbody(proxy_http_req_t *req, rb_methods rb_method) + APR_BRIGADE_PREPEND(input_brigade, header_brigade); + + /* Flush here on EOS because we won't stream_reqbody_read() again */ +- rv = ap_proxy_pass_brigade(bucket_alloc, r, p_conn, req->origin, ++ rv = ap_proxy_pass_brigade(bucket_alloc, r, p_conn, origin, + input_brigade, seen_eos); + if (rv != OK) { + return rv; +@@ -454,10 +457,6 @@ static int spool_reqbody_cl(proxy_http_req_t *req, apr_off_t *bytes_spooled) + /* If this brigade contains EOS, either stop or remove it. */ + if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { + seen_eos = 1; +- +- /* We can't pass this EOS to the output_filters. */ +- e = APR_BRIGADE_LAST(input_brigade); +- apr_bucket_delete(e); + } + + apr_brigade_length(input_brigade, 1, &bytes); +@@ -644,7 +643,18 @@ static int ap_proxy_http_prefetch(proxy_http_req_t *req, + */ + temp_brigade = apr_brigade_create(p, bucket_alloc); + block = req->prefetch_nonblocking ? APR_NONBLOCK_READ : APR_BLOCK_READ; +- do { ++ ++ /* Account for saved input, if any. */ ++ apr_brigade_length(input_brigade, 0, &bytes_read); ++ ++ /* Ensure we don't hit a wall where we have a buffer too small ++ * for ap_get_brigade's filters to fetch us another bucket, ++ * surrender once we hit 80 bytes less than MAX_MEM_SPOOL ++ * (an arbitrary value). ++ */ ++ while (bytes_read < MAX_MEM_SPOOL - 80 ++ && (APR_BRIGADE_EMPTY(input_brigade) ++ || !APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade)))) { + status = ap_get_brigade(r->input_filters, temp_brigade, + AP_MODE_READBYTES, block, + MAX_MEM_SPOOL - bytes_read); +@@ -686,15 +696,7 @@ static int ap_proxy_http_prefetch(proxy_http_req_t *req, + c->client_ip, c->remote_host ? c->remote_host: ""); + return HTTP_INTERNAL_SERVER_ERROR; + } +- +- /* Ensure we don't hit a wall where we have a buffer too small +- * for ap_get_brigade's filters to fetch us another bucket, +- * surrender once we hit 80 bytes less than MAX_MEM_SPOOL +- * (an arbitrary value.) +- */ +- } while ((bytes_read < MAX_MEM_SPOOL - 80) +- && !APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade)) +- && !req->prefetch_nonblocking); ++ } + + /* Use chunked request body encoding or send a content-length body? + * +@@ -838,35 +840,21 @@ static int ap_proxy_http_request(proxy_http_req_t *req) + { + int rv; + request_rec *r = req->r; +- apr_bucket_alloc_t *bucket_alloc = req->bucket_alloc; +- apr_bucket_brigade *header_brigade = req->header_brigade; +- apr_bucket_brigade *input_brigade = req->input_brigade; + + /* send the request header/body, if any. */ + switch (req->rb_method) { ++ case RB_SPOOL_CL: + case RB_STREAM_CL: + case RB_STREAM_CHUNKED: + if (req->do_100_continue) { +- rv = ap_proxy_pass_brigade(bucket_alloc, r, req->backend, +- req->origin, header_brigade, 1); ++ rv = ap_proxy_pass_brigade(req->bucket_alloc, r, req->backend, ++ req->origin, req->header_brigade, 1); + } + else { +- rv = stream_reqbody(req, req->rb_method); ++ rv = stream_reqbody(req); + } + break; + +- case RB_SPOOL_CL: +- /* Prefetch has built the header and spooled the whole body; +- * if we don't expect 100-continue we can flush both all at once, +- * otherwise flush the header only. +- */ +- if (!req->do_100_continue) { +- APR_BRIGADE_CONCAT(header_brigade, input_brigade); +- } +- rv = ap_proxy_pass_brigade(bucket_alloc, r, req->backend, +- req->origin, header_brigade, 1); +- break; +- + default: + /* shouldn't be possible */ + rv = HTTP_INTERNAL_SERVER_ERROR; +@@ -1577,15 +1565,10 @@ int ap_proxy_http_process_response(proxy_http_req_t *req) + + /* Send the request body (fully). */ + switch(req->rb_method) { ++ case RB_SPOOL_CL: + case RB_STREAM_CL: + case RB_STREAM_CHUNKED: +- status = stream_reqbody(req, req->rb_method); +- break; +- case RB_SPOOL_CL: +- /* Prefetch has spooled the whole body, flush it. */ +- status = ap_proxy_pass_brigade(req->bucket_alloc, r, +- backend, origin, +- req->input_brigade, 1); ++ status = stream_reqbody(req); + break; + default: + /* Shouldn't happen */ +@@ -1940,6 +1923,7 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker, + const char *u; + proxy_http_req_t *req = NULL; + proxy_conn_rec *backend = NULL; ++ apr_bucket_brigade *input_brigade = NULL; + int is_ssl = 0; + conn_rec *c = r->connection; + proxy_dir_conf *dconf; +@@ -2005,8 +1989,20 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker, + + dconf = ap_get_module_config(r->per_dir_config, &proxy_module); + ++ /* We possibly reuse input data prefetched in previous call(s), e.g. for a ++ * balancer fallback scenario, and in this case the 100 continue settings ++ * should be consistent between balancer members. If not, we need to ignore ++ * Proxy100Continue on=>off once we tried to prefetch already, otherwise ++ * the HTTP_IN filter won't send 100 Continue for us anymore, and we might ++ * deadlock with the client waiting for each other. Note that off=>on is ++ * not an issue because in this case r->expecting_100 is false (the 100 ++ * Continue is out already), but we make sure that prefetch will be ++ * nonblocking to avoid passing more time there. ++ */ ++ apr_pool_userdata_get((void **)&input_brigade, "proxy-req-input", p); ++ + /* Should we handle end-to-end or ping 100-continue? */ +- if ((r->expecting_100 && dconf->forward_100_continue) ++ if ((r->expecting_100 && (dconf->forward_100_continue || input_brigade)) + || PROXY_DO_100_CONTINUE(worker, r)) { + /* We need to reset r->expecting_100 or prefetching will cause + * ap_http_filter() to send "100 Continue" response by itself. So +@@ -2023,7 +2019,8 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker, + /* Should we block while prefetching the body or try nonblocking and flush + * data to the backend ASAP? + */ +- else if (apr_table_get(r->subprocess_env, "proxy-prefetch-nonblocking")) { ++ else if (input_brigade || apr_table_get(r->subprocess_env, ++ "proxy-prefetch-nonblocking")) { + req->prefetch_nonblocking = 1; + } + +@@ -2048,6 +2045,17 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker, + sizeof(req->server_portstr)))) + goto cleanup; + ++ /* The header is always (re-)built since it depends on worker settings, ++ * but the body can be fetched only once (even partially), so it's saved ++ * in between proxy_http_handler() calls should we come back here. ++ */ ++ req->header_brigade = apr_brigade_create(p, req->bucket_alloc); ++ if (input_brigade == NULL) { ++ input_brigade = apr_brigade_create(p, req->bucket_alloc); ++ apr_pool_userdata_setn(input_brigade, "proxy-req-input", NULL, p); ++ } ++ req->input_brigade = input_brigade; ++ + /* Prefetch (nonlocking) the request body so to increase the chance to get + * the whole (or enough) body and determine Content-Length vs chunked or + * spooled. By doing this before connecting or reusing the backend, we want +@@ -2058,8 +2066,6 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker, + * to reduce to the minimum the unavoidable local is_socket_connected() vs + * remote keepalive race condition. + */ +- req->input_brigade = apr_brigade_create(p, req->bucket_alloc); +- req->header_brigade = apr_brigade_create(p, req->bucket_alloc); + if ((status = ap_proxy_http_prefetch(req, uri, locurl)) != OK) + goto cleanup; + diff --git a/httpd-2.4.37-fips-segfault.patch b/httpd-2.4.37-fips-segfault.patch new file mode 100644 index 0000000..6039980 --- /dev/null +++ b/httpd-2.4.37-fips-segfault.patch @@ -0,0 +1,42 @@ +diff --git a/modules/ssl/mod_ssl.c b/modules/ssl/mod_ssl.c +index 37947e7..b50c259 100644 +--- a/modules/ssl/mod_ssl.c ++++ b/modules/ssl/mod_ssl.c +@@ -331,9 +331,6 @@ static apr_status_t ssl_cleanup_pre_config(void *data) + /* + * Try to kill the internals of the SSL library. + */ +-#ifdef HAVE_FIPS +- FIPS_mode_set(0); +-#endif + /* Corresponds to OBJ_create()s */ + OBJ_cleanup(); + /* Corresponds to OPENSSL_load_builtin_modules() */ +diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c +index 5063a72..21e41e2 100644 +--- a/modules/ssl/ssl_engine_init.c ++++ b/modules/ssl/ssl_engine_init.c +@@ -183,6 +183,14 @@ int ssl_is_challenge(conn_rec *c, const char *servername, + return 0; + } + ++#ifdef HAVE_FIPS ++static apr_status_t ssl_fips_cleanup(void *data) ++{ ++ FIPS_mode_set(0); ++ return APR_SUCCESS; ++} ++#endif ++ + /* + * Per-module initialization + */ +@@ -316,6 +324,8 @@ apr_status_t ssl_init_Module(apr_pool_t *p, apr_pool_t *plog, + if (FIPS_mode_set(1)) { + ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, APLOGNO(01884) + "Operating in SSL FIPS mode"); ++ apr_pool_cleanup_register(p, NULL, ssl_fips_cleanup, ++ apr_pool_cleanup_null); + } + else { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01885) "FIPS mode failed"); diff --git a/httpd-2.4.37-hcheck-mem-issues.patch b/httpd-2.4.37-hcheck-mem-issues.patch new file mode 100644 index 0000000..810b9f2 --- /dev/null +++ b/httpd-2.4.37-hcheck-mem-issues.patch @@ -0,0 +1,199 @@ +diff --git a/modules/proxy/mod_proxy_hcheck.c b/modules/proxy/mod_proxy_hcheck.c +index bd89779..d7c0a68 100644 +--- a/modules/proxy/mod_proxy_hcheck.c ++++ b/modules/proxy/mod_proxy_hcheck.c +@@ -33,7 +33,6 @@ module AP_MODULE_DECLARE_DATA proxy_hcheck_module; + #endif + #else + #define HC_USE_THREADS 0 +-typedef void apr_thread_pool_t; + #endif + + typedef struct { +@@ -73,7 +72,7 @@ typedef struct { + proxy_balancer *balancer; + proxy_worker *worker; + proxy_worker *hc; +- apr_time_t now; ++ apr_time_t *now; + } baton_t; + + static void *hc_create_config(apr_pool_t *p, server_rec *s) +@@ -89,7 +88,10 @@ static void *hc_create_config(apr_pool_t *p, server_rec *s) + } + + static ap_watchdog_t *watchdog; +-static int tpsize = HC_THREADPOOL_SIZE; ++#if HC_USE_THREADS ++static apr_thread_pool_t *hctp; ++static int tpsize; ++#endif + + /* + * This serves double duty by not only validating (and creating) +@@ -825,29 +827,28 @@ static void * APR_THREAD_FUNC hc_check(apr_thread_t *thread, void *b) + server_rec *s = baton->ctx->s; + proxy_worker *worker = baton->worker; + proxy_worker *hc = baton->hc; +- apr_time_t now = baton->now; ++ apr_time_t now; + apr_status_t rv; + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(03256) + "%sHealth checking %s", (thread ? "Threaded " : ""), + worker->s->name); + +- worker->s->updated = now; + if (hc->s->method == TCP) { + rv = hc_check_tcp(baton); + } + else { + rv = hc_check_http(baton); + } ++ ++ now = apr_time_now(); + if (rv == APR_ENOTIMPL) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(03257) + "Somehow tried to use unimplemented hcheck method: %d", + (int)hc->s->method); +- apr_pool_destroy(baton->ptemp); +- return NULL; + } + /* what state are we in ? */ +- if (PROXY_WORKER_IS_HCFAILED(worker)) { ++ else if (PROXY_WORKER_IS_HCFAILED(worker)) { + if (rv == APR_SUCCESS) { + worker->s->pcount += 1; + if (worker->s->pcount >= worker->s->passes) { +@@ -860,7 +861,8 @@ static void * APR_THREAD_FUNC hc_check(apr_thread_t *thread, void *b) + + } + } +- } else { ++ } ++ else { + if (rv != APR_SUCCESS) { + worker->s->error_time = now; + worker->s->fcount += 1; +@@ -873,7 +875,12 @@ static void * APR_THREAD_FUNC hc_check(apr_thread_t *thread, void *b) + } + } + } ++ if (baton->now) { ++ *baton->now = now; ++ } + apr_pool_destroy(baton->ptemp); ++ worker->s->updated = now; ++ + return NULL; + } + +@@ -881,12 +888,10 @@ static apr_status_t hc_watchdog_callback(int state, void *data, + apr_pool_t *pool) + { + apr_status_t rv = APR_SUCCESS; +- apr_time_t now = apr_time_now(); + proxy_balancer *balancer; + sctx_t *ctx = (sctx_t *)data; + server_rec *s = ctx->s; + proxy_server_conf *conf; +- static apr_thread_pool_t *hctp = NULL; + + switch (state) { + case AP_WATCHDOG_STATE_STARTING: +@@ -913,7 +918,6 @@ static apr_status_t hc_watchdog_callback(int state, void *data, + "Skipping apr_thread_pool_create()"); + hctp = NULL; + } +- + #endif + break; + +@@ -929,45 +933,53 @@ static apr_status_t hc_watchdog_callback(int state, void *data, + ctx->s = s; + for (i = 0; i < conf->balancers->nelts; i++, balancer++) { + int n; ++ apr_time_t now; + proxy_worker **workers; + proxy_worker *worker; + /* Have any new balancers or workers been added dynamically? */ + ap_proxy_sync_balancer(balancer, s, conf); + workers = (proxy_worker **)balancer->workers->elts; ++ now = apr_time_now(); + for (n = 0; n < balancer->workers->nelts; n++) { + worker = *workers; + if (!PROXY_WORKER_IS(worker, PROXY_WORKER_STOPPED) && +- (worker->s->method != NONE) && +- (now > worker->s->updated + worker->s->interval)) { ++ (worker->s->method != NONE) && ++ (worker->s->updated != 0) && ++ (now > worker->s->updated + worker->s->interval)) { + baton_t *baton; + apr_pool_t *ptemp; ++ + ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, s, + "Checking %s worker: %s [%d] (%pp)", balancer->s->name, + worker->s->name, worker->s->method, worker); + + if ((rv = hc_init_worker(ctx, worker)) != APR_SUCCESS) { ++ worker->s->updated = now; + return rv; + } +- /* This pool must last the lifetime of the (possible) thread */ ++ worker->s->updated = 0; ++ ++ /* This pool has the lifetime of the check */ + apr_pool_create(&ptemp, ctx->p); + apr_pool_tag(ptemp, "hc_request"); +- baton = apr_palloc(ptemp, sizeof(baton_t)); ++ baton = apr_pcalloc(ptemp, sizeof(baton_t)); + baton->ctx = ctx; +- baton->now = now; + baton->balancer = balancer; + baton->worker = worker; + baton->ptemp = ptemp; + baton->hc = hc_get_hcworker(ctx, worker, ptemp); +- +- if (!hctp) { +- hc_check(NULL, baton); +- } + #if HC_USE_THREADS +- else { +- rv = apr_thread_pool_push(hctp, hc_check, (void *)baton, +- APR_THREAD_TASK_PRIORITY_NORMAL, NULL); ++ if (hctp) { ++ apr_thread_pool_push(hctp, hc_check, (void *)baton, ++ APR_THREAD_TASK_PRIORITY_NORMAL, ++ NULL); + } ++ else + #endif ++ { ++ baton->now = &now; ++ hc_check(NULL, baton); ++ } + } + workers++; + } +@@ -986,9 +998,9 @@ static apr_status_t hc_watchdog_callback(int state, void *data, + ap_log_error(APLOG_MARK, APLOG_INFO, rv, s, APLOGNO(03315) + "apr_thread_pool_destroy() failed"); + } ++ hctp = NULL; + } + #endif +- hctp = NULL; + break; + } + return rv; +@@ -996,7 +1008,10 @@ static apr_status_t hc_watchdog_callback(int state, void *data, + static int hc_pre_config(apr_pool_t *pconf, apr_pool_t *plog, + apr_pool_t *ptemp) + { ++#if HC_USE_THREADS ++ hctp = NULL; + tpsize = HC_THREADPOOL_SIZE; ++#endif + return OK; + } + static int hc_post_config(apr_pool_t *p, apr_pool_t *plog, diff --git a/httpd-2.4.37-htcacheclean-dont-break.patch b/httpd-2.4.37-htcacheclean-dont-break.patch new file mode 100644 index 0000000..17cc64e --- /dev/null +++ b/httpd-2.4.37-htcacheclean-dont-break.patch @@ -0,0 +1,13 @@ +diff --git a/support/htcacheclean.c b/support/htcacheclean.c +index 8692377..fde34c9 100644 +--- a/support/htcacheclean.c ++++ b/support/htcacheclean.c +@@ -557,8 +557,6 @@ static int list_urls(char *path, apr_pool_t *pool, apr_off_t round) + } + } + } +- +- break; + } + } + } diff --git a/httpd-2.4.37-logjournal.patch b/httpd-2.4.37-logjournal.patch new file mode 100644 index 0000000..721911c --- /dev/null +++ b/httpd-2.4.37-logjournal.patch @@ -0,0 +1,87 @@ +diff --git a/modules/loggers/config.m4 b/modules/loggers/config.m4 +index 762e773e94..0848d2e377 100644 +--- a/modules/loggers/config.m4 ++++ b/modules/loggers/config.m4 +@@ -5,6 +5,8 @@ dnl APACHE_MODULE(name, helptext[, objects[, structname[, default[, config]]]]) + APACHE_MODPATH_INIT(loggers) + + APACHE_MODULE(log_config, logging configuration. You won't be able to log requests to the server without this module., , , yes) ++APR_ADDTO(MOD_LOG_CONFIG_LDADD, [$SYSTEMD_LIBS]) ++ + APACHE_MODULE(log_debug, configurable debug logging, , , most) + APACHE_MODULE(log_forensic, forensic logging) + +diff --git a/modules/loggers/mod_log_config.c b/modules/loggers/mod_log_config.c +index 996c09cf49..50a056a2f8 100644 +--- a/modules/loggers/mod_log_config.c ++++ b/modules/loggers/mod_log_config.c +@@ -172,6 +172,10 @@ + #include + #endif + ++#ifdef HAVE_SYSTEMD ++#include ++#endif ++ + #define DEFAULT_LOG_FORMAT "%h %l %u %t \"%r\" %>s %b" + + module AP_MODULE_DECLARE_DATA log_config_module; +@@ -1638,6 +1642,25 @@ static apr_status_t ap_default_log_writer( request_rec *r, + + return rv; + } ++ ++static apr_status_t wrap_journal_stream(apr_pool_t *p, apr_file_t **outfd, ++ int priority) ++{ ++#ifdef HAVE_SYSTEMD ++ int fd; ++ ++ fd = sd_journal_stream_fd("httpd", priority, 0); ++ if (fd < 0) return fd; ++ ++ /* This is an AF_UNIX socket fd so is more pipe-like than ++ * file-like (the fd is neither seekable or readable), and use of ++ * apr_os_pipe_put_ex() allows cleanup registration. */ ++ return apr_os_pipe_put_ex(outfd, &fd, 1, p); ++#else ++ return APR_ENOTIMPL; ++#endif ++} ++ + static void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s, + const char* name) + { +@@ -1650,6 +1673,32 @@ static void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s, + } + return ap_piped_log_write_fd(pl); + } ++ else if (strncasecmp(name, "journald:", 9) == 0) { ++ int priority; ++ const char *err = ap_parse_log_level(name + 9, &priority); ++ apr_status_t rv; ++ apr_file_t *fd; ++ ++ if (err == NULL && priority > LOG_DEBUG) { ++ err = "TRACE level debugging not supported with journald"; ++ } ++ ++ if (err) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, APR_EBADPATH, s, ++ "invalid journald log priority name %s: %s", ++ name, err); ++ return NULL; ++ } ++ ++ rv = wrap_journal_stream(p, &fd, priority); ++ if (rv) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, ++ "could not open journald log stream"); ++ return NULL; ++ } ++ ++ return fd; ++ } + else { + const char *fname = ap_server_root_relative(p, name); + apr_file_t *fd; diff --git a/httpd-2.4.37-mod-md-mod-ssl-hooks.patch b/httpd-2.4.37-mod-md-mod-ssl-hooks.patch new file mode 100644 index 0000000..d7df65a --- /dev/null +++ b/httpd-2.4.37-mod-md-mod-ssl-hooks.patch @@ -0,0 +1,544 @@ +diff --git a/modules/ssl/mod_ssl.h b/modules/ssl/mod_ssl.h +index 24a65a0..a360911 100644 +--- a/modules/ssl/mod_ssl.h ++++ b/modules/ssl/mod_ssl.h +@@ -29,6 +29,7 @@ + #include "httpd.h" + #include "http_config.h" + #include "apr_optional.h" ++#include "apr_tables.h" /* for apr_array_header_t */ + + /* Create a set of SSL_DECLARE(type), SSL_DECLARE_NONSTD(type) and + * SSL_DECLARE_DATA with appropriate export and import tags for the platform +@@ -86,6 +87,34 @@ APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *)); + APR_DECLARE_OPTIONAL_FN(int, ssl_engine_set, (conn_rec *, + ap_conf_vector_t *, + int proxy, int enable)); ++ ++/* Check for availability of new hooks */ ++#define SSL_CERT_HOOKS ++#ifdef SSL_CERT_HOOKS ++ ++/** Lets others add certificate and key files to the given server. ++ * For each cert a key must also be added. ++ * @param cert_file and array of const char* with the path to the certificate chain ++ * @param key_file and array of const char* with the path to the private key file ++ */ ++APR_DECLARE_EXTERNAL_HOOK(ssl, SSL, int, add_cert_files, ++ (server_rec *s, apr_pool_t *p, ++ apr_array_header_t *cert_files, ++ apr_array_header_t *key_files)) ++ ++/** In case no certificates are available for a server, this ++ * lets other modules add a fallback certificate for the time ++ * being. Regular requests against this server will be answered ++ * with a 503. ++ * @param cert_file and array of const char* with the path to the certificate chain ++ * @param key_file and array of const char* with the path to the private key file ++ */ ++APR_DECLARE_EXTERNAL_HOOK(ssl, SSL, int, add_fallback_cert_files, ++ (server_rec *s, apr_pool_t *p, ++ apr_array_header_t *cert_files, ++ apr_array_header_t *key_files)) ++ ++#endif /* SSL_CERT_HOOKS */ + + #endif /* __MOD_SSL_H__ */ + /** @} */ +diff --git a/modules/ssl/mod_ssl_openssl.h b/modules/ssl/mod_ssl_openssl.h +index 0fa654a..d4f684f 100644 +--- a/modules/ssl/mod_ssl_openssl.h ++++ b/modules/ssl/mod_ssl_openssl.h +@@ -69,5 +69,45 @@ APR_DECLARE_EXTERNAL_HOOK(ssl, SSL, int, pre_handshake, + APR_DECLARE_EXTERNAL_HOOK(ssl, SSL, int, proxy_post_handshake, + (conn_rec *c, SSL *ssl)) + ++/** On TLS connections that do not relate to a configured virtual host, ++ * allow other modules to provide a X509 certificate and EVP_PKEY to ++ * be used on the connection. This first hook which does not ++ * return DECLINED will determine the outcome. */ ++APR_DECLARE_EXTERNAL_HOOK(ssl, SSL, int, answer_challenge, ++ (conn_rec *c, const char *server_name, ++ X509 **pcert, EVP_PKEY **pkey)) ++ ++/** During post_config phase, ask around if someone wants to provide ++ * OCSP stapling status information for the given cert (with the also ++ * provided issuer certificate). The first hook which does not ++ * return DECLINED promises to take responsibility (and respond ++ * in later calls via hook ssl_get_stapling_status). ++ * If no hook takes over, mod_ssl's own stapling implementation will ++ * be applied (if configured). ++ */ ++APR_DECLARE_EXTERNAL_HOOK(ssl, SSL, int, init_stapling_status, ++ (server_rec *s, apr_pool_t *p, ++ X509 *cert, X509 *issuer)) ++ ++/** Anyone answering positive to ssl_init_stapling_status for a ++ * certificate, needs to register here and supply the actual OCSP stapling ++ * status data (OCSP_RESP) for a new connection. ++ * A hook supplying the response data must return APR_SUCCESS. ++ * The data is returned in DER encoded bytes via pder and pderlen. The ++ * returned pointer may be NULL, which indicates that data is (currently) ++ * unavailable. ++ * If DER data is returned, it MUST come from a response with ++ * status OCSP_RESPONSE_STATUS_SUCCESSFUL and V_OCSP_CERTSTATUS_GOOD ++ * or V_OCSP_CERTSTATUS_REVOKED, not V_OCSP_CERTSTATUS_UNKNOWN. This means ++ * errors in OCSP retrieval are to be handled/logged by the hook and ++ * are not done by mod_ssl. ++ * Any DER bytes returned MUST be allocated via malloc() and ownership ++ * passes to mod_ssl. Meaning, the hook must return a malloced copy of ++ * the data it has. mod_ssl (or OpenSSL) will free it. ++ */ ++APR_DECLARE_EXTERNAL_HOOK(ssl, SSL, int, get_stapling_status, ++ (unsigned char **pder, int *pderlen, ++ conn_rec *c, server_rec *s, X509 *cert)) ++ + #endif /* __MOD_SSL_OPENSSL_H__ */ + /** @} */ +diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c +index 21e41e2..ef631c1 100644 +--- a/modules/ssl/ssl_engine_init.c ++++ b/modules/ssl/ssl_engine_init.c +@@ -36,6 +36,25 @@ APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ssl, SSL, int, init_server, + (server_rec *s,apr_pool_t *p,int is_proxy,SSL_CTX *ctx), + (s,p,is_proxy,ctx), OK, DECLINED) + ++APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ssl, SSL, int, add_cert_files, ++ (server_rec *s, apr_pool_t *p, ++ apr_array_header_t *cert_files, apr_array_header_t *key_files), ++ (s, p, cert_files, key_files), ++ OK, DECLINED) ++ ++APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ssl, SSL, int, add_fallback_cert_files, ++ (server_rec *s, apr_pool_t *p, ++ apr_array_header_t *cert_files, apr_array_header_t *key_files), ++ (s, p, cert_files, key_files), ++ OK, DECLINED) ++ ++APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ssl, SSL, int, answer_challenge, ++ (conn_rec *c, const char *server_name, ++ X509 **pcert, EVP_PKEY **pkey), ++ (c, server_name, pcert, pkey), ++ DECLINED, DECLINED) ++ ++ + /* _________________________________________________________________ + ** + ** Module Initialization +@@ -165,18 +184,18 @@ static void ssl_add_version_components(apr_pool_t *p, + modver, AP_SERVER_BASEVERSION, incver); + } + +-/**************************************************************************************************/ +-/* Managed Domains Interface */ +- +-static APR_OPTIONAL_FN_TYPE(md_is_managed) *md_is_managed; +-static APR_OPTIONAL_FN_TYPE(md_get_certificate) *md_get_certificate; +-static APR_OPTIONAL_FN_TYPE(md_is_challenge) *md_is_challenge; ++/* _________________________________________________________________ ++** ++** Let other answer special connection attempts. ++** Used in ACME challenge handling by mod_md. ++** _________________________________________________________________ ++*/ + + int ssl_is_challenge(conn_rec *c, const char *servername, + X509 **pcert, EVP_PKEY **pkey) + { +- if (md_is_challenge) { +- return md_is_challenge(c, servername, pcert, pkey); ++ if (APR_SUCCESS == ssl_run_answer_challenge(c, servername, pcert, pkey)) { ++ return 1; + } + *pcert = NULL; + *pkey = NULL; +@@ -231,16 +250,6 @@ apr_status_t ssl_init_Module(apr_pool_t *p, apr_pool_t *plog, + ssl_config_global_create(base_server); /* just to avoid problems */ + ssl_config_global_fix(mc); + +- /* Initialize our interface to mod_md, if it is loaded +- */ +- md_is_managed = APR_RETRIEVE_OPTIONAL_FN(md_is_managed); +- md_get_certificate = APR_RETRIEVE_OPTIONAL_FN(md_get_certificate); +- md_is_challenge = APR_RETRIEVE_OPTIONAL_FN(md_is_challenge); +- if (!md_is_managed || !md_get_certificate) { +- md_is_managed = NULL; +- md_get_certificate = NULL; +- } +- + /* + * try to fix the configuration and open the dedicated SSL + * logfile as early as possible +@@ -1392,8 +1401,7 @@ static apr_status_t ssl_init_server_certs(server_rec *s, + * loaded via SSLOpenSSLConfCmd Certificate), so for 1.0.2 and + * later, we defer to the code in ssl_init_server_ctx. + */ +- if ((mctx->stapling_enabled == TRUE) && +- !ssl_stapling_init_cert(s, p, ptemp, mctx, cert)) { ++ if (!ssl_stapling_init_cert(s, p, ptemp, mctx, cert)) { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02567) + "Unable to configure certificate %s for stapling", + key_id); +@@ -1788,11 +1796,13 @@ static apr_status_t ssl_init_server_ctx(server_rec *s, + apr_array_header_t *pphrases) + { + apr_status_t rv; ++ modssl_pk_server_t *pks; + #ifdef HAVE_SSL_CONF_CMD + ssl_ctx_param_t *param = (ssl_ctx_param_t *)sc->server->ssl_ctx_param->elts; + SSL_CONF_CTX *cctx = sc->server->ssl_ctx_config; + int i; + #endif ++ int n; + + /* + * Check for problematic re-initializations +@@ -1804,50 +1814,24 @@ static apr_status_t ssl_init_server_ctx(server_rec *s, + return APR_EGENERAL; + } + +- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(10083) +- "Init: (%s) mod_md support is %s.", ssl_util_vhostid(p, s), +- md_is_managed? "available" : "unavailable"); +- if (md_is_managed && md_is_managed(s)) { +- modssl_pk_server_t *const pks = sc->server->pks; +- if (pks->cert_files->nelts > 0 || pks->key_files->nelts > 0) { +- ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(10084) +- "Init: (%s) You configured certificate/key files on this host, but " +- "is is covered by a Managed Domain. You need to remove these directives " +- "for the Managed Domain to take over.", ssl_util_vhostid(p, s)); +- } +- else { +- const char *key_file, *cert_file, *chain_file; +- +- key_file = cert_file = chain_file = NULL; +- +- if (md_get_certificate) { +- rv = md_get_certificate(s, p, &key_file, &cert_file); +- } +- else { +- rv = APR_ENOTIMPL; +- } +- +- if (key_file && cert_file) { +- ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s, +- "%s: installing key=%s, cert=%s, chain=%s", +- ssl_util_vhostid(p, s), key_file, cert_file, chain_file); +- APR_ARRAY_PUSH(pks->key_files, const char *) = key_file; +- APR_ARRAY_PUSH(pks->cert_files, const char *) = cert_file; +- sc->server->cert_chain = chain_file; +- } +- +- if (APR_STATUS_IS_EAGAIN(rv)) { +- /* Managed Domain not ready yet. This is not a reason to fail the config */ +- ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(10085) +- "Init: %s will respond with '503 Service Unavailable' for now. This " +- "host is part of a Managed Domain, but no SSL certificate is " +- "available (yet).", ssl_util_vhostid(p, s)); +- pks->service_unavailable = 1; +- } +- else if (rv != APR_SUCCESS) { +- return rv; +- } +- } ++ /* Allow others to provide certificate files */ ++ pks = sc->server->pks; ++ n = pks->cert_files->nelts; ++ ssl_run_add_cert_files(s, p, pks->cert_files, pks->key_files); ++ ++ if (n < pks->cert_files->nelts) { ++ /* this overrides any old chain configuration */ ++ sc->server->cert_chain = NULL; ++ } ++ ++ if (apr_is_empty_array(pks->cert_files) && !sc->server->cert_chain) { ++ ssl_run_add_fallback_cert_files(s, p, pks->cert_files, pks->key_files); ++ ++ pks->service_unavailable = 1; ++ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(10085) ++ "Init: %s will respond with '503 Service Unavailable' for now. There " ++ "are no SSL certificates configured and no other module contributed any.", ++ ssl_util_vhostid(p, s)); + } + + if ((rv = ssl_init_ctx(s, p, ptemp, sc->server)) != APR_SUCCESS) { +@@ -1900,7 +1884,7 @@ static apr_status_t ssl_init_server_ctx(server_rec *s, + * (late) point makes sure that we catch both certificates loaded + * via SSLCertificateFile and SSLOpenSSLConfCmd Certificate. + */ +- if (sc->server->stapling_enabled == TRUE) { ++ do { + X509 *cert; + int i = 0; + int ret = SSL_CTX_set_current_cert(sc->server->ssl_ctx, +@@ -1917,7 +1901,7 @@ static apr_status_t ssl_init_server_ctx(server_rec *s, + SSL_CERT_SET_NEXT); + i++; + } +- } ++ } while(0); + #endif + + #ifdef HAVE_TLS_SESSION_TICKETS +diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c +index e6a9f67..a5e86e4 100644 +--- a/modules/ssl/ssl_engine_kernel.c ++++ b/modules/ssl/ssl_engine_kernel.c +@@ -2303,6 +2303,37 @@ void ssl_callback_Info(const SSL *ssl, int where, int rc) + } + + #ifdef HAVE_TLSEXT ++ ++static apr_status_t set_challenge_creds(conn_rec *c, const char *servername, ++ SSL *ssl, X509 *cert, EVP_PKEY *key) ++{ ++ SSLConnRec *sslcon = myConnConfig(c); ++ ++ sslcon->service_unavailable = 1; ++ if ((SSL_use_certificate(ssl, cert) < 1)) { ++ ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c, APLOGNO(10086) ++ "Failed to configure challenge certificate %s", ++ servername); ++ return APR_EGENERAL; ++ } ++ ++ if (!SSL_use_PrivateKey(ssl, key)) { ++ ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c, APLOGNO(10087) ++ "error '%s' using Challenge key: %s", ++ ERR_error_string(ERR_peek_last_error(), NULL), ++ servername); ++ return APR_EGENERAL; ++ } ++ ++ if (SSL_check_private_key(ssl) < 1) { ++ ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c, APLOGNO(10088) ++ "Challenge certificate and private key %s " ++ "do not match", servername); ++ return APR_EGENERAL; ++ } ++ return APR_SUCCESS; ++} ++ + /* + * This function sets the virtual host from an extended + * client hello with a server name indication extension ("SNI", cf. RFC 6066). +@@ -2332,30 +2363,12 @@ static apr_status_t init_vhost(conn_rec *c, SSL *ssl) + return APR_SUCCESS; + } + else if (ssl_is_challenge(c, servername, &cert, &key)) { +- +- sslcon->service_unavailable = 1; +- if ((SSL_use_certificate(ssl, cert) < 1)) { +- ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c, APLOGNO(10086) +- "Failed to configure challenge certificate %s", +- servername); ++ /* With ACMEv1 we can have challenge connections to a unknown domains ++ * that need to be answered with a special certificate and will ++ * otherwise not answer any requests. */ ++ if (set_challenge_creds(c, servername, ssl, cert, key) != APR_SUCCESS) { + return APR_EGENERAL; + } +- +- if (!SSL_use_PrivateKey(ssl, key)) { +- ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c, APLOGNO(10087) +- "error '%s' using Challenge key: %s", +- ERR_error_string(ERR_peek_last_error(), NULL), +- servername); +- return APR_EGENERAL; +- } +- +- if (SSL_check_private_key(ssl) < 1) { +- ap_log_cerror(APLOG_MARK, APLOG_WARNING, 0, c, APLOGNO(10088) +- "Challenge certificate and private key %s " +- "do not match", servername); +- return APR_EGENERAL; +- } +- + } + else { + ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(02044) +@@ -2648,6 +2661,23 @@ int ssl_callback_alpn_select(SSL *ssl, + proposed); + return SSL_TLSEXT_ERR_ALERT_FATAL; + } ++ ++ /* protocol was switched, this could be a challenge protocol such as "acme-tls/1". ++ * For that to work, we need to allow overrides to our ssl certificate. ++ * However, exclude challenge checks on our best known traffic protocol. ++ * (http/1.1 is the default, we never switch to it anyway.) ++ */ ++ if (strcmp("h2", proposed)) { ++ const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); ++ X509 *cert; ++ EVP_PKEY *key; ++ ++ if (ssl_is_challenge(c, servername, &cert, &key)) { ++ if (set_challenge_creds(c, servername, ssl, cert, key) != APR_SUCCESS) { ++ return SSL_TLSEXT_ERR_ALERT_FATAL; ++ } ++ } ++ } + } + + return SSL_TLSEXT_ERR_OK; +diff --git a/modules/ssl/ssl_util_stapling.c b/modules/ssl/ssl_util_stapling.c +index c3e2cfa..4df0a9a 100644 +--- a/modules/ssl/ssl_util_stapling.c ++++ b/modules/ssl/ssl_util_stapling.c +@@ -31,12 +31,28 @@ + #include "ssl_private.h" + #include "ap_mpm.h" + #include "apr_thread_mutex.h" ++#include "mod_ssl_openssl.h" ++ ++APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ssl, SSL, int, init_stapling_status, ++ (server_rec *s, apr_pool_t *p, ++ X509 *cert, X509 *issuer), ++ (s, p, cert, issuer), ++ DECLINED, DECLINED) ++ ++APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ssl, SSL, int, get_stapling_status, ++ (unsigned char **pder, int *pderlen, ++ conn_rec *c, server_rec *s, X509 *cert), ++ (pder, pderlen, c, s, cert), ++ DECLINED, DECLINED) ++ + + #ifdef HAVE_OCSP_STAPLING + + static int stapling_cache_mutex_on(server_rec *s); + static int stapling_cache_mutex_off(server_rec *s); + ++static int stapling_cb(SSL *ssl, void *arg); ++ + /** + * Maxiumum OCSP stapling response size. This should be the response for a + * single certificate and will typically include the responder certificate chain +@@ -119,7 +135,38 @@ int ssl_stapling_init_cert(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, + OCSP_CERTID *cid = NULL; + STACK_OF(OPENSSL_STRING) *aia = NULL; + +- if ((x == NULL) || (X509_digest(x, EVP_sha1(), idx, NULL) != 1)) ++ if (x == NULL) ++ return 0; ++ ++ if (!(issuer = stapling_get_issuer(mctx, x))) { ++ /* In Apache pre 2.4.40, we use to come here only when mod_ssl stapling ++ * was enabled. With the new hooks, we give other modules the chance ++ * to provide stapling status. However, we do not want to log ssl errors ++ * where we did not do so in the past. */ ++ if (mctx->stapling_enabled == TRUE) { ++ ssl_log_xerror(SSLLOG_MARK, APLOG_ERR, 0, ptemp, s, x, APLOGNO(02217) ++ "ssl_stapling_init_cert: can't retrieve issuer " ++ "certificate!"); ++ return 0; ++ } ++ return 1; ++ } ++ ++ if (ssl_run_init_stapling_status(s, p, x, issuer) == APR_SUCCESS) { ++ /* Someone's taken over or mod_ssl's own implementation is not enabled */ ++ if (mctx->stapling_enabled != TRUE) { ++ SSL_CTX_set_tlsext_status_cb(mctx->ssl_ctx, stapling_cb); ++ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO() "OCSP stapling added via hook"); ++ } ++ return 1; ++ } ++ ++ if (mctx->stapling_enabled != TRUE) { ++ /* mod_ssl's own implementation is not enabled */ ++ return 1; ++ } ++ ++ if (X509_digest(x, EVP_sha1(), idx, NULL) != 1) + return 0; + + cinf = apr_hash_get(stapling_certinfo, idx, sizeof(idx)); +@@ -139,13 +186,6 @@ int ssl_stapling_init_cert(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, + return 1; + } + +- 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; +- } +- + cid = OCSP_cert_to_id(NULL, x, issuer); + X509_free(issuer); + if (!cid) { +@@ -182,18 +222,16 @@ int ssl_stapling_init_cert(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, + mctx->sc->vhost_id); + + apr_hash_set(stapling_certinfo, cinf->idx, sizeof(cinf->idx), cinf); +- ++ + return 1; + } + +-static certinfo *stapling_get_certinfo(server_rec *s, modssl_ctx_t *mctx, ++static certinfo *stapling_get_certinfo(server_rec *s, X509 *x, modssl_ctx_t *mctx, + SSL *ssl) + { + certinfo *cinf; +- X509 *x; + UCHAR idx[SHA_DIGEST_LENGTH]; +- x = SSL_get_certificate(ssl); +- if ((x == NULL) || (X509_digest(x, EVP_sha1(), idx, NULL) != 1)) ++ if (X509_digest(x, EVP_sha1(), idx, NULL) != 1) + return NULL; + cinf = apr_hash_get(stapling_certinfo, idx, sizeof(idx)); + if (cinf && cinf->cid) +@@ -750,18 +788,34 @@ static int stapling_cb(SSL *ssl, void *arg) + OCSP_RESPONSE *rsp = NULL; + int rv; + BOOL ok = TRUE; ++ X509 *x; ++ unsigned char *rspder = NULL; ++ int rspderlen; + ++ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01951) ++ "stapling_cb: OCSP Stapling callback called"); ++ ++ x = SSL_get_certificate(ssl); ++ if (x == NULL) { ++ return SSL_TLSEXT_ERR_NOACK; ++ } ++ ++ if (ssl_run_get_stapling_status(&rspder, &rspderlen, conn, s, x) == APR_SUCCESS) { ++ /* a hook handles stapling for this certicate and determines the response */ ++ if (rspder == NULL || rspderlen <= 0) { ++ return SSL_TLSEXT_ERR_NOACK; ++ } ++ SSL_set_tlsext_status_ocsp_resp(ssl, rspder, rspderlen); ++ return SSL_TLSEXT_ERR_OK; ++ } ++ + if (sc->server->stapling_enabled != TRUE) { + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01950) + "stapling_cb: OCSP Stapling disabled"); + return SSL_TLSEXT_ERR_NOACK; + } + +- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01951) +- "stapling_cb: OCSP Stapling callback called"); +- +- cinf = stapling_get_certinfo(s, mctx, ssl); +- if (cinf == NULL) { ++ if ((cinf = stapling_get_certinfo(s, x, mctx, ssl)) == NULL) { + return SSL_TLSEXT_ERR_NOACK; + } + +@@ -864,9 +918,10 @@ apr_status_t modssl_init_stapling(server_rec *s, apr_pool_t *p, + if (mctx->stapling_responder_timeout == UNSET) { + mctx->stapling_responder_timeout = 10 * APR_USEC_PER_SEC; + } ++ + SSL_CTX_set_tlsext_status_cb(ctx, stapling_cb); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01960) "OCSP stapling initialized"); +- ++ + return APR_SUCCESS; + } + diff --git a/httpd-2.4.37-mod-md-perms.patch b/httpd-2.4.37-mod-md-perms.patch new file mode 100644 index 0000000..78c0fc3 --- /dev/null +++ b/httpd-2.4.37-mod-md-perms.patch @@ -0,0 +1,44 @@ +diff --git a/modules/md/mod_md_os.c b/modules/md/mod_md_os.c +index f96d566..8df0248 100644 +--- a/modules/md/mod_md_os.c ++++ b/modules/md/mod_md_os.c +@@ -41,14 +41,20 @@ + + apr_status_t md_try_chown(const char *fname, unsigned int uid, int gid, apr_pool_t *p) + { +-#if AP_NEED_SET_MUTEX_PERMS +- if (-1 == chown(fname, (uid_t)uid, (gid_t)gid)) { +- apr_status_t rv = APR_FROM_OS_ERROR(errno); +- if (!APR_STATUS_IS_ENOENT(rv)) { +- ap_log_perror(APLOG_MARK, APLOG_ERR, rv, p, APLOGNO(10082) +- "Can't change owner of %s", fname); ++#if AP_NEED_SET_MUTEX_PERMS && HAVE_UNISTD_H ++ /* Since we only switch user when running as root, we only need to chown directories ++ * in that case. Otherwise, the server will ignore any "user/group" directives and ++ * child processes have the same privileges as the parent. ++ */ ++ if (!geteuid()) { ++ if (-1 == chown(fname, (uid_t)uid, (gid_t)gid)) { ++ apr_status_t rv = APR_FROM_OS_ERROR(errno); ++ if (!APR_STATUS_IS_ENOENT(rv)) { ++ ap_log_perror(APLOG_MARK, APLOG_ERR, rv, p, APLOGNO(10082) ++ "Can't change owner of %s", fname); ++ } ++ return rv; + } +- return rv; + } + return APR_SUCCESS; + #else +@@ -58,11 +64,7 @@ apr_status_t md_try_chown(const char *fname, unsigned int uid, int gid, apr_pool + + apr_status_t md_make_worker_accessible(const char *fname, apr_pool_t *p) + { +-#if AP_NEED_SET_MUTEX_PERMS + return md_try_chown(fname, ap_unixd_config.user_id, -1, p); +-#else +- return APR_ENOTIMPL; +-#endif + } + + #ifdef WIN32 diff --git a/httpd-2.4.37-mod-mime-magic-strdup.patch b/httpd-2.4.37-mod-mime-magic-strdup.patch new file mode 100644 index 0000000..e093818 --- /dev/null +++ b/httpd-2.4.37-mod-mime-magic-strdup.patch @@ -0,0 +1,24 @@ +diff --git a/docs/conf/magic b/docs/conf/magic +index 7c56119..bc891d9 100644 +--- a/docs/conf/magic ++++ b/docs/conf/magic +@@ -87,7 +87,7 @@ + # Microsoft WAVE format (*.wav) + # [GRR 950115: probably all of the shorts and longs should be leshort/lelong] + # Microsoft RIFF +-0 string RIFF audio/unknown ++0 string RIFF + # - WAVE format + >8 string WAVE audio/x-wav + # MPEG audio. +--- a/modules/metadata/mod_mime_magic.c 2013/06/11 07:36:13 1491699 ++++ b/modules/metadata/mod_mime_magic.c 2013/06/11 07:41:40 1491700 +@@ -606,7 +606,7 @@ + /* high overhead for 1 char - just hope they don't do this much */ + str[0] = c; + str[1] = '\0'; +- return magic_rsl_add(r, str); ++ return magic_rsl_add(r, apr_pstrdup(r->pool, str)); + } + + /* allocate and copy a contiguous string from a result string list */ diff --git a/httpd-2.4.37-pr37355.patch b/httpd-2.4.37-pr37355.patch new file mode 100644 index 0000000..0d161a5 --- /dev/null +++ b/httpd-2.4.37-pr37355.patch @@ -0,0 +1,143 @@ +diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c +index d13c249..f383996 100644 +--- a/modules/proxy/mod_proxy.c ++++ b/modules/proxy/mod_proxy.c +@@ -1200,11 +1200,20 @@ static int proxy_handler(request_rec *r) + /* handle the scheme */ + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01142) + "Trying to run scheme_handler against proxy"); ++ ++ if (ents[i].creds) { ++ apr_table_set(r->notes, "proxy-basic-creds", ents[i].creds); ++ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, ++ "Using proxy auth creds %s", ents[i].creds); ++ } ++ + access_status = proxy_run_scheme_handler(r, worker, + conf, url, + ents[i].hostname, + ents[i].port); + ++ if (ents[i].creds) apr_table_unset(r->notes, "proxy-basic-creds"); ++ + /* Did the scheme handler process the request? */ + if (access_status != DECLINED) { + const char *cl_a; +@@ -1621,8 +1630,8 @@ 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) ++static const char *add_proxy(cmd_parms *cmd, void *dummy, const char *f1, ++ const char *r1, const char *creds, int regex) + { + server_rec *s = cmd->server; + proxy_server_conf *conf = +@@ -1680,19 +1689,24 @@ static const char * + new->port = port; + new->regexp = reg; + new->use_regex = regex; ++ if (creds) { ++ new->creds = apr_pstrcat(cmd->pool, "Basic ", ++ ap_pbase64encode(cmd->pool, (char *)creds), ++ NULL); ++ } + return NULL; + } + +-static const char * +- add_proxy_noregex(cmd_parms *cmd, void *dummy, const char *f1, const char *r1) ++static const char *add_proxy_noregex(cmd_parms *cmd, void *dummy, const char *f1, ++ const char *r1, const char *creds) + { +- return add_proxy(cmd, dummy, f1, r1, 0); ++ return add_proxy(cmd, dummy, f1, r1, creds, 0); + } + +-static const char * +- add_proxy_regex(cmd_parms *cmd, void *dummy, const char *f1, const char *r1) ++static const char *add_proxy_regex(cmd_parms *cmd, void *dummy, const char *f1, ++ const char *r1, const char *creds) + { +- return add_proxy(cmd, dummy, f1, r1, 1); ++ return add_proxy(cmd, dummy, f1, r1, creds, 1); + } + + PROXY_DECLARE(const char *) ap_proxy_de_socketfy(apr_pool_t *p, const char *url) +@@ -2638,9 +2652,9 @@ static const command_rec proxy_cmds[] = + "location, in regular expression syntax"), + AP_INIT_FLAG("ProxyRequests", set_proxy_req, NULL, RSRC_CONF, + "on if the true proxy requests should be accepted"), +- AP_INIT_TAKE2("ProxyRemote", add_proxy_noregex, NULL, RSRC_CONF, ++ AP_INIT_TAKE23("ProxyRemote", add_proxy_noregex, NULL, RSRC_CONF, + "a scheme, partial URL or '*' and a proxy server"), +- AP_INIT_TAKE2("ProxyRemoteMatch", add_proxy_regex, NULL, RSRC_CONF, ++ AP_INIT_TAKE23("ProxyRemoteMatch", add_proxy_regex, NULL, RSRC_CONF, + "a regex pattern and a proxy server"), + AP_INIT_FLAG("ProxyPassInterpolateEnv", ap_set_flag_slot_char, + (void*)APR_OFFSETOF(proxy_dir_conf, interpolate_env), +diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h +index 288c5d4..57cc92f 100644 +--- a/modules/proxy/mod_proxy.h ++++ b/modules/proxy/mod_proxy.h +@@ -116,6 +116,7 @@ struct proxy_remote { + const char *protocol; /* the scheme used to talk to this proxy */ + const char *hostname; /* the hostname of this proxy */ + ap_regex_t *regexp; /* compiled regex (if any) for the remote */ ++ const char *creds; /* auth credentials (if any) for the proxy */ + int use_regex; /* simple boolean. True if we have a regex pattern */ + apr_port_t port; /* the port for this proxy */ + }; +diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c +index 0759dac..2bfc8f0 100644 +--- a/modules/proxy/proxy_util.c ++++ b/modules/proxy/proxy_util.c +@@ -2446,11 +2446,14 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, + * 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"); ++ proxy_auth = apr_table_get(r->notes, "proxy-basic-creds"); ++ if (proxy_auth == NULL) ++ 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")) { ++ (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); + } + } +@@ -2672,7 +2675,8 @@ static apr_status_t send_http_connect(proxy_conn_rec *backend, + nbytes = apr_snprintf(buffer, sizeof(buffer), + "CONNECT %s:%d HTTP/1.0" CRLF, + forward->target_host, forward->target_port); +- /* Add proxy authorization from the initial request if necessary */ ++ /* Add proxy authorization from the configuration, or initial ++ * request if necessary */ + if (forward->proxy_auth != NULL) { + nbytes += apr_snprintf(buffer + nbytes, sizeof(buffer) - nbytes, + "Proxy-Authorization: %s" CRLF, +@@ -3567,6 +3571,7 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, + apr_bucket *e; + int do_100_continue; + conn_rec *origin = p_conn->connection; ++ const char *creds; + proxy_dir_conf *dconf = ap_get_module_config(r->per_dir_config, &proxy_module); + + /* +@@ -3743,6 +3748,11 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, + return HTTP_BAD_REQUEST; + } + ++ creds = apr_table_get(r->notes, "proxy-basic-creds"); ++ if (creds) { ++ apr_table_mergen(r->headers_in, "Proxy-Authorization", creds); ++ } ++ + /* send request headers */ + headers_in_array = apr_table_elts(r->headers_in); + headers_in = (const apr_table_entry_t *) headers_in_array->elts; diff --git a/httpd-2.4.37-proxy-continue.patch b/httpd-2.4.37-proxy-continue.patch new file mode 100644 index 0000000..932b043 --- /dev/null +++ b/httpd-2.4.37-proxy-continue.patch @@ -0,0 +1,1713 @@ +diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c +index de48735..d13c249 100644 +--- a/modules/proxy/mod_proxy.c ++++ b/modules/proxy/mod_proxy.c +@@ -1574,6 +1574,8 @@ static void *create_proxy_dir_config(apr_pool_t *p, char *dummy) + new->error_override_set = 0; + new->add_forwarded_headers = 1; + new->add_forwarded_headers_set = 0; ++ new->forward_100_continue = 1; ++ new->forward_100_continue_set = 0; + + return (void *) new; + } +@@ -1610,6 +1612,11 @@ static void *merge_proxy_dir_config(apr_pool_t *p, void *basev, void *addv) + : add->add_forwarded_headers; + new->add_forwarded_headers_set = add->add_forwarded_headers_set + || base->add_forwarded_headers_set; ++ new->forward_100_continue = ++ (add->forward_100_continue_set == 0) ? base->forward_100_continue ++ : add->forward_100_continue; ++ new->forward_100_continue_set = add->forward_100_continue_set ++ || base->forward_100_continue_set; + + return new; + } +@@ -2110,6 +2117,14 @@ static const char * + conf->preserve_host_set = 1; + return NULL; + } ++static const char * ++ forward_100_continue(cmd_parms *parms, void *dconf, int flag) ++{ ++ proxy_dir_conf *conf = dconf; ++ conf->forward_100_continue = flag; ++ conf->forward_100_continue_set = 1; ++ return NULL; ++} + + static const char * + set_recv_buffer_size(cmd_parms *parms, void *dummy, const char *arg) +@@ -2683,6 +2698,9 @@ static const command_rec proxy_cmds[] = + "Configure local source IP used for request forward"), + AP_INIT_FLAG("ProxyAddHeaders", add_proxy_http_headers, NULL, RSRC_CONF|ACCESS_CONF, + "on if X-Forwarded-* headers should be added or completed"), ++ AP_INIT_FLAG("Proxy100Continue", forward_100_continue, NULL, RSRC_CONF|ACCESS_CONF, ++ "on if 100-Continue should be forwarded to the origin server, off if the " ++ "proxy should handle it by itself"), + {NULL} + }; + +diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h +index 3419023..288c5d4 100644 +--- a/modules/proxy/mod_proxy.h ++++ b/modules/proxy/mod_proxy.h +@@ -240,6 +240,8 @@ typedef struct { + /** Named back references */ + apr_array_header_t *refs; + ++ unsigned int forward_100_continue:1; ++ unsigned int forward_100_continue_set:1; + } proxy_dir_conf; + + /* if we interpolate env vars per-request, we'll need a per-request +@@ -380,6 +382,12 @@ do { \ + (w)->s->io_buffer_size_set = (c)->io_buffer_size_set; \ + } while (0) + ++#define PROXY_DO_100_CONTINUE(w, r) \ ++((w)->s->ping_timeout_set \ ++ && (PROXYREQ_REVERSE == (r)->proxyreq) \ ++ && !(apr_table_get((r)->subprocess_env, "force-proxy-request-1.0")) \ ++ && ap_request_has_body((r))) ++ + /* use 2 hashes */ + typedef struct { + unsigned int def; +diff --git a/modules/proxy/mod_proxy_ftp.c b/modules/proxy/mod_proxy_ftp.c +index 8f6f853..8d66b4a 100644 +--- a/modules/proxy/mod_proxy_ftp.c ++++ b/modules/proxy/mod_proxy_ftp.c +@@ -1181,12 +1181,10 @@ static int proxy_ftp_handler(request_rec *r, proxy_worker *worker, + return HTTP_SERVICE_UNAVAILABLE; + } + +- if (!backend->connection) { +- status = ap_proxy_connection_create_ex("FTP", backend, r); +- if (status != OK) { +- proxy_ftp_cleanup(r, backend); +- return status; +- } ++ status = ap_proxy_connection_create_ex("FTP", backend, r); ++ if (status != OK) { ++ proxy_ftp_cleanup(r, backend); ++ return status; + } + + /* Use old naming */ +diff --git a/modules/proxy/mod_proxy_hcheck.c b/modules/proxy/mod_proxy_hcheck.c +index 2783a58..dd8e407 100644 +--- a/modules/proxy/mod_proxy_hcheck.c ++++ b/modules/proxy/mod_proxy_hcheck.c +@@ -762,10 +762,8 @@ static apr_status_t hc_check_http(baton_t *baton) + } + + r = create_request_rec(ptemp, ctx->s, baton->balancer, wctx->method); +- if (!backend->connection) { +- if ((status = ap_proxy_connection_create_ex("HCOH", backend, r)) != OK) { +- return backend_cleanup("HCOH", backend, ctx->s, status); +- } ++ if ((status = ap_proxy_connection_create_ex("HCOH", backend, r)) != OK) { ++ return backend_cleanup("HCOH", backend, ctx->s, status); + } + set_request_connection(r, backend->connection); + +diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c +index 56af9a8..f007ad6 100644 +--- a/modules/proxy/mod_proxy_http.c ++++ b/modules/proxy/mod_proxy_http.c +@@ -216,8 +216,12 @@ static void add_cl(apr_pool_t *p, + APR_BRIGADE_INSERT_TAIL(header_brigade, e); + } + +-#define ASCII_CRLF "\015\012" +-#define ASCII_ZERO "\060" ++#ifndef CRLF_ASCII ++#define CRLF_ASCII "\015\012" ++#endif ++#ifndef ZERO_ASCII ++#define ZERO_ASCII "\060" ++#endif + + static void terminate_headers(apr_bucket_alloc_t *bucket_alloc, + apr_bucket_brigade *header_brigade) +@@ -225,304 +229,228 @@ static void terminate_headers(apr_bucket_alloc_t *bucket_alloc, + apr_bucket *e; + + /* add empty line at the end of the headers */ +- e = apr_bucket_immortal_create(ASCII_CRLF, 2, bucket_alloc); ++ e = apr_bucket_immortal_create(CRLF_ASCII, 2, bucket_alloc); + APR_BRIGADE_INSERT_TAIL(header_brigade, e); + } + + + #define MAX_MEM_SPOOL 16384 + +-static int stream_reqbody_chunked(apr_pool_t *p, +- request_rec *r, +- proxy_conn_rec *p_conn, +- conn_rec *origin, +- apr_bucket_brigade *header_brigade, +- apr_bucket_brigade *input_brigade) +-{ +- int seen_eos = 0, rv = OK; +- apr_size_t hdr_len; +- apr_off_t bytes; +- apr_status_t status; +- apr_bucket_alloc_t *bucket_alloc = r->connection->bucket_alloc; +- apr_bucket_brigade *bb; +- apr_bucket *e; +- +- add_te_chunked(p, bucket_alloc, header_brigade); +- terminate_headers(bucket_alloc, header_brigade); ++typedef enum { ++ RB_INIT = 0, ++ RB_STREAM_CL, ++ RB_STREAM_CHUNKED, ++ RB_SPOOL_CL ++} rb_methods; + +- while (!APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade))) +- { +- char chunk_hdr[20]; /* must be here due to transient bucket. */ ++typedef struct { ++ apr_pool_t *p; ++ request_rec *r; ++ proxy_worker *worker; ++ proxy_server_conf *sconf; + +- /* If this brigade contains EOS, either stop or remove it. */ +- if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { +- seen_eos = 1; +- +- /* We can't pass this EOS to the output_filters. */ +- e = APR_BRIGADE_LAST(input_brigade); +- apr_bucket_delete(e); +- } +- +- apr_brigade_length(input_brigade, 1, &bytes); ++ char server_portstr[32]; ++ proxy_conn_rec *backend; ++ conn_rec *origin; + +- hdr_len = apr_snprintf(chunk_hdr, sizeof(chunk_hdr), +- "%" APR_UINT64_T_HEX_FMT CRLF, +- (apr_uint64_t)bytes); ++ apr_bucket_alloc_t *bucket_alloc; ++ apr_bucket_brigade *header_brigade; ++ apr_bucket_brigade *input_brigade; ++ char *old_cl_val, *old_te_val; ++ apr_off_t cl_val; + +- ap_xlate_proto_to_ascii(chunk_hdr, hdr_len); +- e = apr_bucket_transient_create(chunk_hdr, hdr_len, +- bucket_alloc); +- APR_BRIGADE_INSERT_HEAD(input_brigade, e); ++ rb_methods rb_method; + +- /* +- * Append the end-of-chunk CRLF +- */ +- e = apr_bucket_immortal_create(ASCII_CRLF, 2, bucket_alloc); +- APR_BRIGADE_INSERT_TAIL(input_brigade, e); ++ int expecting_100; ++ unsigned int do_100_continue:1, ++ prefetch_nonblocking:1; ++} proxy_http_req_t; + +- if (header_brigade) { +- /* we never sent the header brigade, so go ahead and +- * take care of that now +- */ +- bb = header_brigade; +- +- /* +- * Save input_brigade in bb brigade. (At least) in the SSL case +- * input_brigade contains transient buckets whose data would get +- * overwritten during the next call of ap_get_brigade in the loop. +- * ap_save_brigade ensures these buckets to be set aside. +- * Calling ap_save_brigade with NULL as filter is OK, because +- * bb brigade already has been created and does not need to get +- * created by ap_save_brigade. +- */ +- status = ap_save_brigade(NULL, &bb, &input_brigade, p); +- if (status != APR_SUCCESS) { +- return HTTP_INTERNAL_SERVER_ERROR; +- } +- +- header_brigade = NULL; +- } +- else { +- bb = input_brigade; ++/* Read what's in the client pipe. If nonblocking is set and read is EAGAIN, ++ * pass a FLUSH bucket to the backend and read again in blocking mode. ++ */ ++static int stream_reqbody_read(proxy_http_req_t *req, apr_bucket_brigade *bb, ++ int nonblocking) ++{ ++ request_rec *r = req->r; ++ proxy_conn_rec *p_conn = req->backend; ++ apr_bucket_alloc_t *bucket_alloc = req->bucket_alloc; ++ apr_read_type_e block = nonblocking ? APR_NONBLOCK_READ : APR_BLOCK_READ; ++ apr_status_t status; ++ int rv; ++ ++ for (;;) { ++ status = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES, ++ block, HUGE_STRING_LEN); ++ if (block == APR_BLOCK_READ ++ || (!APR_STATUS_IS_EAGAIN(status) ++ && (status != APR_SUCCESS || !APR_BRIGADE_EMPTY(bb)))) { ++ break; + } + +- /* The request is flushed below this loop with chunk EOS header */ +- rv = ap_proxy_pass_brigade(bucket_alloc, r, p_conn, origin, bb, 0); ++ /* Flush and retry (blocking) */ ++ apr_brigade_cleanup(bb); ++ rv = ap_proxy_pass_brigade(bucket_alloc, r, p_conn, req->origin, bb, 1); + if (rv != OK) { + return rv; + } +- +- if (seen_eos) { +- break; +- } +- +- status = ap_get_brigade(r->input_filters, input_brigade, +- AP_MODE_READBYTES, APR_BLOCK_READ, +- HUGE_STRING_LEN); +- +- if (status != APR_SUCCESS) { +- conn_rec *c = r->connection; +- ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(02608) +- "read request body failed to %pI (%s)" +- " from %s (%s)", p_conn->addr, +- p_conn->hostname ? p_conn->hostname: "", +- c->client_ip, c->remote_host ? c->remote_host: ""); +- return ap_map_http_request_error(status, HTTP_BAD_REQUEST); +- } ++ block = APR_BLOCK_READ; + } + +- if (header_brigade) { +- /* we never sent the header brigade because there was no request body; +- * send it now +- */ +- bb = header_brigade; +- } +- else { +- if (!APR_BRIGADE_EMPTY(input_brigade)) { +- /* input brigade still has an EOS which we can't pass to the output_filters. */ +- e = APR_BRIGADE_LAST(input_brigade); +- AP_DEBUG_ASSERT(APR_BUCKET_IS_EOS(e)); +- apr_bucket_delete(e); +- } +- bb = input_brigade; +- } +- +- e = apr_bucket_immortal_create(ASCII_ZERO ASCII_CRLF +- /* */ +- ASCII_CRLF, +- 5, bucket_alloc); +- APR_BRIGADE_INSERT_TAIL(bb, e); +- +- if (apr_table_get(r->subprocess_env, "proxy-sendextracrlf")) { +- e = apr_bucket_immortal_create(ASCII_CRLF, 2, bucket_alloc); +- APR_BRIGADE_INSERT_TAIL(bb, e); ++ if (status != APR_SUCCESS) { ++ conn_rec *c = r->connection; ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(02608) ++ "read request body failed to %pI (%s)" ++ " from %s (%s)", p_conn->addr, ++ p_conn->hostname ? p_conn->hostname: "", ++ c->client_ip, c->remote_host ? c->remote_host: ""); ++ return ap_map_http_request_error(status, HTTP_BAD_REQUEST); + } + +- /* Now we have headers-only, or the chunk EOS mark; flush it */ +- rv = ap_proxy_pass_brigade(bucket_alloc, r, p_conn, origin, bb, 1); +- return rv; ++ return OK; + } + +-static int stream_reqbody_cl(apr_pool_t *p, +- request_rec *r, +- proxy_conn_rec *p_conn, +- conn_rec *origin, +- apr_bucket_brigade *header_brigade, +- apr_bucket_brigade *input_brigade, +- char *old_cl_val) ++static int stream_reqbody(proxy_http_req_t *req, rb_methods rb_method) + { +- int seen_eos = 0, rv = 0; +- apr_status_t status = APR_SUCCESS; +- apr_bucket_alloc_t *bucket_alloc = r->connection->bucket_alloc; +- apr_bucket_brigade *bb; ++ request_rec *r = req->r; ++ int seen_eos = 0, rv = OK; ++ apr_size_t hdr_len; ++ char chunk_hdr[20]; /* must be here due to transient bucket. */ ++ proxy_conn_rec *p_conn = req->backend; ++ apr_bucket_alloc_t *bucket_alloc = req->bucket_alloc; ++ apr_bucket_brigade *header_brigade = req->header_brigade; ++ apr_bucket_brigade *input_brigade = req->input_brigade; ++ apr_off_t bytes, bytes_streamed = 0; + apr_bucket *e; +- apr_off_t cl_val = 0; +- apr_off_t bytes; +- apr_off_t bytes_streamed = 0; +- +- if (old_cl_val) { +- char *endstr; + +- add_cl(p, bucket_alloc, header_brigade, old_cl_val); +- status = apr_strtoff(&cl_val, old_cl_val, &endstr, 10); +- +- if (status || *endstr || endstr == old_cl_val || cl_val < 0) { +- ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01085) +- "could not parse request Content-Length (%s)", +- old_cl_val); +- return HTTP_BAD_REQUEST; ++ do { ++ if (APR_BRIGADE_EMPTY(input_brigade) ++ && APR_BRIGADE_EMPTY(header_brigade)) { ++ rv = stream_reqbody_read(req, input_brigade, 1); ++ if (rv != OK) { ++ return rv; ++ } + } +- } +- terminate_headers(bucket_alloc, header_brigade); +- +- while (!APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade))) +- { +- apr_brigade_length(input_brigade, 1, &bytes); +- bytes_streamed += bytes; +- +- /* If this brigade contains EOS, either stop or remove it. */ +- if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { +- seen_eos = 1; + +- /* We can't pass this EOS to the output_filters. */ +- e = APR_BRIGADE_LAST(input_brigade); +- apr_bucket_delete(e); ++ if (!APR_BRIGADE_EMPTY(input_brigade)) { ++ /* If this brigade contains EOS, either stop or remove it. */ ++ if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { ++ seen_eos = 1; + +- if (apr_table_get(r->subprocess_env, "proxy-sendextracrlf")) { +- e = apr_bucket_immortal_create(ASCII_CRLF, 2, bucket_alloc); +- APR_BRIGADE_INSERT_TAIL(input_brigade, e); ++ /* We can't pass this EOS to the output_filters. */ ++ e = APR_BRIGADE_LAST(input_brigade); ++ apr_bucket_delete(e); + } +- } + +- /* C-L < bytes streamed?!? +- * We will error out after the body is completely +- * consumed, but we can't stream more bytes at the +- * back end since they would in part be interpreted +- * as another request! If nothing is sent, then +- * just send nothing. +- * +- * Prevents HTTP Response Splitting. +- */ +- if (bytes_streamed > cl_val) { +- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01086) +- "read more bytes of request body than expected " +- "(got %" APR_OFF_T_FMT ", expected %" APR_OFF_T_FMT ")", +- bytes_streamed, cl_val); +- return HTTP_INTERNAL_SERVER_ERROR; +- } +- +- if (header_brigade) { +- /* we never sent the header brigade, so go ahead and +- * take care of that now +- */ +- bb = header_brigade; ++ apr_brigade_length(input_brigade, 1, &bytes); ++ bytes_streamed += bytes; + +- /* +- * Save input_brigade in bb brigade. (At least) in the SSL case +- * input_brigade contains transient buckets whose data would get +- * overwritten during the next call of ap_get_brigade in the loop. +- * ap_save_brigade ensures these buckets to be set aside. +- * Calling ap_save_brigade with NULL as filter is OK, because +- * bb brigade already has been created and does not need to get +- * created by ap_save_brigade. +- */ +- status = ap_save_brigade(NULL, &bb, &input_brigade, p); +- if (status != APR_SUCCESS) { ++ if (rb_method == RB_STREAM_CHUNKED) { ++ if (bytes) { ++ /* ++ * Prepend the size of the chunk ++ */ ++ hdr_len = apr_snprintf(chunk_hdr, sizeof(chunk_hdr), ++ "%" APR_UINT64_T_HEX_FMT CRLF, ++ (apr_uint64_t)bytes); ++ ap_xlate_proto_to_ascii(chunk_hdr, hdr_len); ++ e = apr_bucket_transient_create(chunk_hdr, hdr_len, ++ bucket_alloc); ++ APR_BRIGADE_INSERT_HEAD(input_brigade, e); ++ ++ /* ++ * Append the end-of-chunk CRLF ++ */ ++ e = apr_bucket_immortal_create(CRLF_ASCII, 2, bucket_alloc); ++ APR_BRIGADE_INSERT_TAIL(input_brigade, e); ++ } ++ if (seen_eos) { ++ /* ++ * Append the tailing 0-size chunk ++ */ ++ e = apr_bucket_immortal_create(ZERO_ASCII CRLF_ASCII ++ /* */ ++ CRLF_ASCII, ++ 5, bucket_alloc); ++ APR_BRIGADE_INSERT_TAIL(input_brigade, e); ++ } ++ } ++ else if (bytes_streamed > req->cl_val) { ++ /* C-L < bytes streamed?!? ++ * We will error out after the body is completely ++ * consumed, but we can't stream more bytes at the ++ * back end since they would in part be interpreted ++ * as another request! If nothing is sent, then ++ * just send nothing. ++ * ++ * Prevents HTTP Response Splitting. ++ */ ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01086) ++ "read more bytes of request body than expected " ++ "(got %" APR_OFF_T_FMT ", expected " ++ "%" APR_OFF_T_FMT ")", ++ bytes_streamed, req->cl_val); + return HTTP_INTERNAL_SERVER_ERROR; + } + +- header_brigade = NULL; +- } +- else { +- bb = input_brigade; +- } +- +- /* Once we hit EOS, we are ready to flush. */ +- rv = ap_proxy_pass_brigade(bucket_alloc, r, p_conn, origin, bb, seen_eos); +- if (rv != OK) { +- return rv ; +- } +- +- if (seen_eos) { +- break; ++ if (seen_eos && apr_table_get(r->subprocess_env, ++ "proxy-sendextracrlf")) { ++ e = apr_bucket_immortal_create(CRLF_ASCII, 2, bucket_alloc); ++ APR_BRIGADE_INSERT_TAIL(input_brigade, e); ++ } + } + +- status = ap_get_brigade(r->input_filters, input_brigade, +- AP_MODE_READBYTES, APR_BLOCK_READ, +- HUGE_STRING_LEN); ++ /* If we never sent the header brigade, go ahead and take care of ++ * that now by prepending it (once only since header_brigade will be ++ * empty afterward). ++ */ ++ APR_BRIGADE_PREPEND(input_brigade, header_brigade); + +- if (status != APR_SUCCESS) { +- conn_rec *c = r->connection; +- ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(02609) +- "read request body failed to %pI (%s)" +- " from %s (%s)", p_conn->addr, +- p_conn->hostname ? p_conn->hostname: "", +- c->client_ip, c->remote_host ? c->remote_host: ""); +- return ap_map_http_request_error(status, HTTP_BAD_REQUEST); ++ /* Flush here on EOS because we won't stream_reqbody_read() again */ ++ rv = ap_proxy_pass_brigade(bucket_alloc, r, p_conn, req->origin, ++ input_brigade, seen_eos); ++ if (rv != OK) { ++ return rv; + } +- } ++ } while (!seen_eos); + +- if (bytes_streamed != cl_val) { ++ if (rb_method == RB_STREAM_CL && bytes_streamed != req->cl_val) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01087) + "client %s given Content-Length did not match" + " number of body bytes read", r->connection->client_ip); + return HTTP_BAD_REQUEST; + } + +- if (header_brigade) { +- /* we never sent the header brigade since there was no request +- * body; send it now with the flush flag +- */ +- bb = header_brigade; +- return(ap_proxy_pass_brigade(bucket_alloc, r, p_conn, origin, bb, 1)); +- } +- + return OK; + } + +-static int spool_reqbody_cl(apr_pool_t *p, +- request_rec *r, +- proxy_conn_rec *p_conn, +- conn_rec *origin, +- apr_bucket_brigade *header_brigade, +- apr_bucket_brigade *input_brigade, +- int force_cl) ++static int spool_reqbody_cl(proxy_http_req_t *req, apr_off_t *bytes_spooled) + { +- int seen_eos = 0; +- apr_status_t status; +- apr_bucket_alloc_t *bucket_alloc = r->connection->bucket_alloc; ++ apr_pool_t *p = req->p; ++ request_rec *r = req->r; ++ int seen_eos = 0, rv = OK; ++ apr_status_t status = APR_SUCCESS; ++ apr_bucket_alloc_t *bucket_alloc = req->bucket_alloc; ++ apr_bucket_brigade *input_brigade = req->input_brigade; + apr_bucket_brigade *body_brigade; + apr_bucket *e; +- apr_off_t bytes, bytes_spooled = 0, fsize = 0; ++ apr_off_t bytes, fsize = 0; + apr_file_t *tmpfile = NULL; + apr_off_t limit; + + body_brigade = apr_brigade_create(p, bucket_alloc); ++ *bytes_spooled = 0; + + limit = ap_get_limit_req_body(r); + +- while (!APR_BUCKET_IS_EOS(APR_BRIGADE_FIRST(input_brigade))) +- { ++ do { ++ if (APR_BRIGADE_EMPTY(input_brigade)) { ++ rv = stream_reqbody_read(req, input_brigade, 0); ++ if (rv != OK) { ++ return rv; ++ } ++ } ++ + /* If this brigade contains EOS, either stop or remove it. */ + if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { + seen_eos = 1; +@@ -534,13 +462,13 @@ static int spool_reqbody_cl(apr_pool_t *p, + + apr_brigade_length(input_brigade, 1, &bytes); + +- if (bytes_spooled + bytes > MAX_MEM_SPOOL) { ++ if (*bytes_spooled + bytes > MAX_MEM_SPOOL) { + /* + * LimitRequestBody does not affect Proxy requests (Should it?). + * Let it take effect if we decide to store the body in a + * temporary file on disk. + */ +- if (limit && (bytes_spooled + bytes > limit)) { ++ if (limit && (*bytes_spooled + bytes > limit)) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01088) + "Request body is larger than the configured " + "limit of %" APR_OFF_T_FMT, limit); +@@ -610,69 +538,42 @@ static int spool_reqbody_cl(apr_pool_t *p, + + } + +- bytes_spooled += bytes; +- +- if (seen_eos) { +- break; +- } +- +- status = ap_get_brigade(r->input_filters, input_brigade, +- AP_MODE_READBYTES, APR_BLOCK_READ, +- HUGE_STRING_LEN); +- +- if (status != APR_SUCCESS) { +- conn_rec *c = r->connection; +- ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(02610) +- "read request body failed to %pI (%s)" +- " from %s (%s)", p_conn->addr, +- p_conn->hostname ? p_conn->hostname: "", +- c->client_ip, c->remote_host ? c->remote_host: ""); +- return ap_map_http_request_error(status, HTTP_BAD_REQUEST); +- } +- } ++ *bytes_spooled += bytes; ++ } while (!seen_eos); + +- if (bytes_spooled || force_cl) { +- add_cl(p, bucket_alloc, header_brigade, apr_off_t_toa(p, bytes_spooled)); +- } +- terminate_headers(bucket_alloc, header_brigade); +- APR_BRIGADE_CONCAT(header_brigade, body_brigade); ++ APR_BRIGADE_CONCAT(input_brigade, body_brigade); + if (tmpfile) { +- apr_brigade_insert_file(header_brigade, tmpfile, 0, fsize, p); ++ apr_brigade_insert_file(input_brigade, tmpfile, 0, fsize, p); + } + if (apr_table_get(r->subprocess_env, "proxy-sendextracrlf")) { +- e = apr_bucket_immortal_create(ASCII_CRLF, 2, bucket_alloc); +- APR_BRIGADE_INSERT_TAIL(header_brigade, e); ++ e = apr_bucket_immortal_create(CRLF_ASCII, 2, bucket_alloc); ++ APR_BRIGADE_INSERT_TAIL(input_brigade, e); + } +- /* This is all a single brigade, pass with flush flagged */ +- return(ap_proxy_pass_brigade(bucket_alloc, r, p_conn, origin, header_brigade, 1)); ++ return OK; + } + +-static +-int ap_proxy_http_request(apr_pool_t *p, request_rec *r, +- proxy_conn_rec *p_conn, proxy_worker *worker, +- proxy_server_conf *conf, +- apr_uri_t *uri, +- char *url, char *server_portstr) ++static int ap_proxy_http_prefetch(proxy_http_req_t *req, ++ apr_uri_t *uri, char *url) + { ++ apr_pool_t *p = req->p; ++ request_rec *r = req->r; + conn_rec *c = r->connection; +- apr_bucket_alloc_t *bucket_alloc = c->bucket_alloc; +- apr_bucket_brigade *header_brigade; +- apr_bucket_brigade *input_brigade; ++ proxy_conn_rec *p_conn = req->backend; ++ apr_bucket_alloc_t *bucket_alloc = req->bucket_alloc; ++ apr_bucket_brigade *header_brigade = req->header_brigade; ++ apr_bucket_brigade *input_brigade = req->input_brigade; + apr_bucket_brigade *temp_brigade; + apr_bucket *e; + char *buf; + apr_status_t status; +- enum rb_methods {RB_INIT, RB_STREAM_CL, RB_STREAM_CHUNKED, RB_SPOOL_CL}; +- enum rb_methods rb_method = RB_INIT; +- char *old_cl_val = NULL; +- char *old_te_val = NULL; + apr_off_t bytes_read = 0; + apr_off_t bytes; + int force10, rv; ++ apr_read_type_e block; + conn_rec *origin = p_conn->connection; + + if (apr_table_get(r->subprocess_env, "force-proxy-request-1.0")) { +- if (r->expecting_100) { ++ if (req->expecting_100) { + return HTTP_EXPECTATION_FAILED; + } + force10 = 1; +@@ -680,17 +581,14 @@ int ap_proxy_http_request(apr_pool_t *p, request_rec *r, + force10 = 0; + } + +- 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); ++ req->worker, req->sconf, ++ uri, url, req->server_portstr, ++ &req->old_cl_val, &req->old_te_val); + if (rv != OK) { + return rv; + } + +- /* We have headers, let's figure out our request body... */ +- input_brigade = apr_brigade_create(p, bucket_alloc); +- + /* sub-requests never use keepalives, and mustn't pass request bodies. + * Because the new logic looks at input_brigade, we will self-terminate + * input_brigade and jump past all of the request body logic... +@@ -703,9 +601,9 @@ int ap_proxy_http_request(apr_pool_t *p, request_rec *r, + if (!r->kept_body && r->main) { + /* XXX: Why DON'T sub-requests use keepalives? */ + p_conn->close = 1; +- old_cl_val = NULL; +- old_te_val = NULL; +- rb_method = RB_STREAM_CL; ++ req->old_te_val = NULL; ++ req->old_cl_val = NULL; ++ req->rb_method = RB_STREAM_CL; + e = apr_bucket_eos_create(input_brigade->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(input_brigade, e); + goto skip_body; +@@ -719,18 +617,19 @@ int ap_proxy_http_request(apr_pool_t *p, request_rec *r, + * encoding has been done by the extensions' handler, and + * do not modify add_te_chunked's logic + */ +- if (old_te_val && strcasecmp(old_te_val, "chunked") != 0) { ++ if (req->old_te_val && ap_cstr_casecmp(req->old_te_val, "chunked") != 0) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01093) +- "%s Transfer-Encoding is not supported", old_te_val); ++ "%s Transfer-Encoding is not supported", ++ req->old_te_val); + return HTTP_INTERNAL_SERVER_ERROR; + } + +- if (old_cl_val && old_te_val) { ++ if (req->old_cl_val && req->old_te_val) { + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01094) + "client %s (%s) requested Transfer-Encoding " + "chunked body with Content-Length (C-L ignored)", + c->client_ip, c->remote_host ? c->remote_host: ""); +- old_cl_val = NULL; ++ req->old_cl_val = NULL; + origin->keepalive = AP_CONN_CLOSE; + p_conn->close = 1; + } +@@ -744,10 +643,19 @@ int ap_proxy_http_request(apr_pool_t *p, request_rec *r, + * reasonable size. + */ + temp_brigade = apr_brigade_create(p, bucket_alloc); ++ block = req->prefetch_nonblocking ? APR_NONBLOCK_READ : APR_BLOCK_READ; + do { + status = ap_get_brigade(r->input_filters, temp_brigade, +- AP_MODE_READBYTES, APR_BLOCK_READ, ++ AP_MODE_READBYTES, block, + MAX_MEM_SPOOL - bytes_read); ++ /* ap_get_brigade may return success with an empty brigade ++ * for a non-blocking read which would block ++ */ ++ if (block == APR_NONBLOCK_READ ++ && ((status == APR_SUCCESS && APR_BRIGADE_EMPTY(temp_brigade)) ++ || APR_STATUS_IS_EAGAIN(status))) { ++ break; ++ } + if (status != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01095) + "prefetch request body failed to %pI (%s)" +@@ -785,7 +693,8 @@ int ap_proxy_http_request(apr_pool_t *p, request_rec *r, + * (an arbitrary value.) + */ + } while ((bytes_read < MAX_MEM_SPOOL - 80) +- && !APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))); ++ && !APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade)) ++ && !req->prefetch_nonblocking); + + /* Use chunked request body encoding or send a content-length body? + * +@@ -822,7 +731,8 @@ int ap_proxy_http_request(apr_pool_t *p, request_rec *r, + * is absent, and the filters are unchanged (the body won't + * be resized by another content filter). + */ +- if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { ++ if (!APR_BRIGADE_EMPTY(input_brigade) ++ && APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(input_brigade))) { + /* The whole thing fit, so our decision is trivial, use + * the filtered bytes read from the client for the request + * body Content-Length. +@@ -830,34 +740,43 @@ int ap_proxy_http_request(apr_pool_t *p, request_rec *r, + * If we expected no body, and read no body, do not set + * the Content-Length. + */ +- if (old_cl_val || old_te_val || bytes_read) { +- old_cl_val = apr_off_t_toa(r->pool, bytes_read); ++ if (req->old_cl_val || req->old_te_val || bytes_read) { ++ req->old_cl_val = apr_off_t_toa(r->pool, bytes_read); ++ req->cl_val = bytes_read; + } +- rb_method = RB_STREAM_CL; ++ req->rb_method = RB_STREAM_CL; + } +- else if (old_te_val) { ++ else if (req->old_te_val) { + if (force10 + || (apr_table_get(r->subprocess_env, "proxy-sendcl") + && !apr_table_get(r->subprocess_env, "proxy-sendchunks") + && !apr_table_get(r->subprocess_env, "proxy-sendchunked"))) { +- rb_method = RB_SPOOL_CL; ++ req->rb_method = RB_SPOOL_CL; + } + else { +- rb_method = RB_STREAM_CHUNKED; ++ req->rb_method = RB_STREAM_CHUNKED; + } + } +- else if (old_cl_val) { ++ else if (req->old_cl_val) { + if (r->input_filters == r->proto_input_filters) { +- rb_method = RB_STREAM_CL; ++ char *endstr; ++ status = apr_strtoff(&req->cl_val, req->old_cl_val, &endstr, 10); ++ if (status != APR_SUCCESS || *endstr || req->cl_val < 0) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(01085) ++ "could not parse request Content-Length (%s)", ++ req->old_cl_val); ++ return HTTP_BAD_REQUEST; ++ } ++ req->rb_method = RB_STREAM_CL; + } + else if (!force10 + && (apr_table_get(r->subprocess_env, "proxy-sendchunks") + || apr_table_get(r->subprocess_env, "proxy-sendchunked")) + && !apr_table_get(r->subprocess_env, "proxy-sendcl")) { +- rb_method = RB_STREAM_CHUNKED; ++ req->rb_method = RB_STREAM_CHUNKED; + } + else { +- rb_method = RB_SPOOL_CL; ++ req->rb_method = RB_SPOOL_CL; + } + } + else { +@@ -865,7 +784,31 @@ int ap_proxy_http_request(apr_pool_t *p, request_rec *r, + * requests, and has the behavior that it will not add any C-L + * when the old_cl_val is NULL. + */ +- rb_method = RB_SPOOL_CL; ++ req->rb_method = RB_SPOOL_CL; ++ } ++ ++ switch (req->rb_method) { ++ case RB_STREAM_CHUNKED: ++ add_te_chunked(req->p, bucket_alloc, header_brigade); ++ break; ++ ++ case RB_STREAM_CL: ++ if (req->old_cl_val) { ++ add_cl(req->p, bucket_alloc, header_brigade, req->old_cl_val); ++ } ++ break; ++ ++ default: /* => RB_SPOOL_CL */ ++ /* If we have to spool the body, do it now, before connecting or ++ * reusing the backend connection. ++ */ ++ rv = spool_reqbody_cl(req, &bytes); ++ if (rv != OK) { ++ return rv; ++ } ++ if (bytes || req->old_te_val || req->old_cl_val) { ++ add_cl(p, bucket_alloc, header_brigade, apr_off_t_toa(p, bytes)); ++ } + } + + /* Yes I hate gotos. This is the subrequest shortcut */ +@@ -886,23 +829,44 @@ skip_body: + e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(header_brigade, e); + } ++ terminate_headers(bucket_alloc, header_brigade); + +- /* send the request body, if any. */ +- switch(rb_method) { +- case RB_STREAM_CHUNKED: +- rv = stream_reqbody_chunked(p, r, p_conn, origin, header_brigade, +- input_brigade); +- break; ++ return OK; ++} ++ ++static int ap_proxy_http_request(proxy_http_req_t *req) ++{ ++ int rv; ++ request_rec *r = req->r; ++ apr_bucket_alloc_t *bucket_alloc = req->bucket_alloc; ++ apr_bucket_brigade *header_brigade = req->header_brigade; ++ apr_bucket_brigade *input_brigade = req->input_brigade; ++ ++ /* send the request header/body, if any. */ ++ switch (req->rb_method) { + case RB_STREAM_CL: +- rv = stream_reqbody_cl(p, r, p_conn, origin, header_brigade, +- input_brigade, old_cl_val); ++ case RB_STREAM_CHUNKED: ++ if (req->do_100_continue) { ++ rv = ap_proxy_pass_brigade(bucket_alloc, r, req->backend, ++ req->origin, header_brigade, 1); ++ } ++ else { ++ rv = stream_reqbody(req, req->rb_method); ++ } + break; ++ + case RB_SPOOL_CL: +- rv = spool_reqbody_cl(p, r, p_conn, origin, header_brigade, +- input_brigade, (old_cl_val != NULL) +- || (old_te_val != NULL) +- || (bytes_read > 0)); ++ /* Prefetch has built the header and spooled the whole body; ++ * if we don't expect 100-continue we can flush both all at once, ++ * otherwise flush the header only. ++ */ ++ if (!req->do_100_continue) { ++ APR_BRIGADE_CONCAT(header_brigade, input_brigade); ++ } ++ rv = ap_proxy_pass_brigade(bucket_alloc, r, req->backend, ++ req->origin, header_brigade, 1); + break; ++ + default: + /* shouldn't be possible */ + rv = HTTP_INTERNAL_SERVER_ERROR; +@@ -910,10 +874,12 @@ skip_body: + } + + if (rv != OK) { ++ conn_rec *c = r->connection; + /* apr_status_t value has been logged in lower level method */ + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01097) + "pass request body failed to %pI (%s) from %s (%s)", +- p_conn->addr, p_conn->hostname ? p_conn->hostname: "", ++ req->backend->addr, ++ req->backend->hostname ? req->backend->hostname: "", + c->client_ip, c->remote_host ? c->remote_host: ""); + return rv; + } +@@ -1189,12 +1155,16 @@ static int add_trailers(void *data, const char *key, const char *val) + } + + static +-apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, +- proxy_conn_rec **backend_ptr, +- proxy_worker *worker, +- proxy_server_conf *conf, +- char *server_portstr) { ++int ap_proxy_http_process_response(proxy_http_req_t *req) ++{ ++ apr_pool_t *p = req->p; ++ request_rec *r = req->r; + conn_rec *c = r->connection; ++ proxy_worker *worker = req->worker; ++ proxy_conn_rec *backend = req->backend; ++ conn_rec *origin = req->origin; ++ int do_100_continue = req->do_100_continue; ++ + char *buffer; + char fixed_buffer[HUGE_STRING_LEN]; + const char *buf; +@@ -1217,19 +1187,11 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, + int proxy_status = OK; + const char *original_status_line = r->status_line; + const char *proxy_status_line = NULL; +- proxy_conn_rec *backend = *backend_ptr; +- conn_rec *origin = backend->connection; + apr_interval_time_t old_timeout = 0; + proxy_dir_conf *dconf; +- int do_100_continue; + + dconf = ap_get_module_config(r->per_dir_config, &proxy_module); + +- do_100_continue = (worker->s->ping_timeout_set +- && ap_request_has_body(r) +- && (PROXYREQ_REVERSE == r->proxyreq) +- && !(apr_table_get(r->subprocess_env, "force-proxy-request-1.0"))); +- + bb = apr_brigade_create(p, c->bucket_alloc); + pass_bb = apr_brigade_create(p, c->bucket_alloc); + +@@ -1248,7 +1210,7 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, + } + + /* Setup for 100-Continue timeout if appropriate */ +- if (do_100_continue) { ++ if (do_100_continue && worker->s->ping_timeout_set) { + apr_socket_timeout_get(backend->sock, &old_timeout); + if (worker->s->ping_timeout != old_timeout) { + apr_status_t rc; +@@ -1273,6 +1235,8 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, + origin->local_addr->port)); + do { + apr_status_t rc; ++ int major = 0, minor = 0; ++ int toclose = 0; + + apr_brigade_cleanup(bb); + +@@ -1360,9 +1324,6 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, + * This is buggy if we ever see an HTTP/1.10 + */ + if (apr_date_checkmask(buffer, "HTTP/#.# ###*")) { +- int major, minor; +- int toclose; +- + major = buffer[5] - '0'; + minor = buffer[7] - '0'; + +@@ -1412,8 +1373,8 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, + "Set-Cookie", NULL); + + /* shove the headers direct into r->headers_out */ +- ap_proxy_read_headers(r, backend->r, buffer, response_field_size, origin, +- &pread_len); ++ ap_proxy_read_headers(r, backend->r, buffer, response_field_size, ++ origin, &pread_len); + + if (r->headers_out == NULL) { + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01106) +@@ -1491,7 +1452,8 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, + r->headers_out = ap_proxy_clean_warnings(p, r->headers_out); + + /* handle Via header in response */ +- if (conf->viaopt != via_off && conf->viaopt != via_block) { ++ if (req->sconf->viaopt != via_off ++ && req->sconf->viaopt != via_block) { + const char *server_name = ap_get_server_name(r); + /* If USE_CANONICAL_NAME_OFF was configured for the proxy virtual host, + * then the server name returned by ap_get_server_name() is the +@@ -1502,18 +1464,18 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, + server_name = r->server->server_hostname; + /* create a "Via:" response header entry and merge it */ + apr_table_addn(r->headers_out, "Via", +- (conf->viaopt == via_full) ++ (req->sconf->viaopt == via_full) + ? apr_psprintf(p, "%d.%d %s%s (%s)", + HTTP_VERSION_MAJOR(r->proto_num), + HTTP_VERSION_MINOR(r->proto_num), + server_name, +- server_portstr, ++ req->server_portstr, + AP_SERVER_BASEVERSION) + : apr_psprintf(p, "%d.%d %s%s", + HTTP_VERSION_MAJOR(r->proto_num), + HTTP_VERSION_MINOR(r->proto_num), + server_name, +- server_portstr) ++ req->server_portstr) + ); + } + +@@ -1531,18 +1493,6 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, + } + + if (ap_is_HTTP_INFO(proxy_status)) { +- interim_response++; +- /* Reset to old timeout iff we've adjusted it */ +- if (do_100_continue +- && (r->status == HTTP_CONTINUE) +- && (worker->s->ping_timeout != old_timeout)) { +- apr_socket_timeout_set(backend->sock, old_timeout); +- } +- } +- else { +- interim_response = 0; +- } +- if (interim_response) { + /* RFC2616 tells us to forward this. + * + * OTOH, an interim response here may mean the backend +@@ -1563,7 +1513,13 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, + ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, + "HTTP: received interim %d response", r->status); + if (!policy +- || (!strcasecmp(policy, "RFC") && ((r->expecting_100 = 1)))) { ++ || (!strcasecmp(policy, "RFC") ++ && (proxy_status != HTTP_CONTINUE ++ || (req->expecting_100 = 1)))) { ++ if (proxy_status == HTTP_CONTINUE) { ++ r->expecting_100 = req->expecting_100; ++ req->expecting_100 = 0; ++ } + ap_send_interim_response(r, 1); + } + /* FIXME: refine this to be able to specify per-response-status +@@ -1573,7 +1529,106 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01108) + "undefined proxy interim response policy"); + } ++ interim_response++; + } ++ else { ++ interim_response = 0; ++ } ++ ++ /* If we still do 100-continue (end-to-end or ping), either the ++ * current response is the expected "100 Continue" and we are done ++ * with this mode, or this is another interim response and we'll wait ++ * for the next one, or this is a final response and hence the backend ++ * did not honor our expectation. ++ */ ++ if (do_100_continue && (!interim_response ++ || proxy_status == HTTP_CONTINUE)) { ++ /* RFC 7231 - Section 5.1.1 - Expect - Requirement for servers ++ * A server that responds with a final status code before ++ * reading the entire message body SHOULD indicate in that ++ * response whether it intends to close the connection or ++ * continue reading and discarding the request message. ++ * ++ * So, if this response is not an interim 100 Continue, we can ++ * avoid sending the request body if the backend responded with ++ * "Connection: close" or HTTP < 1.1, and either let the core ++ * discard it or the caller try another balancer member with the ++ * same body (given status 503, though not implemented yet). ++ */ ++ int do_send_body = (proxy_status == HTTP_CONTINUE ++ || (!toclose && major > 0 && minor > 0)); ++ ++ /* Reset to old timeout iff we've adjusted it. */ ++ if (worker->s->ping_timeout_set) { ++ apr_socket_timeout_set(backend->sock, old_timeout); ++ } ++ ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(10153) ++ "HTTP: %s100 continue sent by %pI (%s): " ++ "%ssending body (response: HTTP/%i.%i %s)", ++ proxy_status != HTTP_CONTINUE ? "no " : "", ++ backend->addr, ++ backend->hostname ? backend->hostname : "", ++ do_send_body ? "" : "not ", ++ major, minor, proxy_status_line); ++ ++ if (do_send_body) { ++ int status; ++ ++ /* Send the request body (fully). */ ++ switch(req->rb_method) { ++ case RB_STREAM_CL: ++ case RB_STREAM_CHUNKED: ++ status = stream_reqbody(req, req->rb_method); ++ break; ++ case RB_SPOOL_CL: ++ /* Prefetch has spooled the whole body, flush it. */ ++ status = ap_proxy_pass_brigade(req->bucket_alloc, r, ++ backend, origin, ++ req->input_brigade, 1); ++ break; ++ default: ++ /* Shouldn't happen */ ++ status = HTTP_INTERNAL_SERVER_ERROR; ++ break; ++ } ++ if (status != OK) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, ++ APLOGNO(10154) "pass request body failed " ++ "to %pI (%s) from %s (%s) with status %i", ++ backend->addr, ++ backend->hostname ? backend->hostname : "", ++ c->client_ip, ++ c->remote_host ? c->remote_host : "", ++ status); ++ backend->close = 1; ++ return status; ++ } ++ } ++ else { ++ /* If we don't read the client connection any further, since ++ * there are pending data it should be "Connection: close"d to ++ * prevent reuse. We don't exactly c->keepalive = AP_CONN_CLOSE ++ * here though, because error_override or a potential retry on ++ * another backend could finally read that data and finalize ++ * the request processing, making keep-alive possible. So what ++ * we do is restoring r->expecting_100 for ap_set_keepalive() ++ * to do the right thing according to the final response and ++ * any later update of r->expecting_100. ++ */ ++ r->expecting_100 = req->expecting_100; ++ req->expecting_100 = 0; ++ } ++ ++ /* Once only! */ ++ do_100_continue = 0; ++ } ++ ++ if (interim_response) { ++ /* Already forwarded above, read next response */ ++ continue; ++ } ++ + /* Moved the fixups of Date headers and those affected by + * ProxyPassReverse/etc from here to ap_proxy_read_headers + */ +@@ -1648,7 +1703,6 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, + + /* send body - but only if a body is expected */ + if ((!r->header_only) && /* not HEAD request */ +- !interim_response && /* not any 1xx response */ + (proxy_status != HTTP_NO_CONTENT) && /* not 204 */ + (proxy_status != HTTP_NOT_MODIFIED)) { /* not 304 */ + +@@ -1697,7 +1751,7 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, + + rv = ap_get_brigade(backend->r->input_filters, bb, + AP_MODE_READBYTES, mode, +- conf->io_buffer_size); ++ req->sconf->io_buffer_size); + + /* ap_get_brigade will return success with an empty brigade + * for a non-blocking read which would block: */ +@@ -1789,7 +1843,7 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, + ap_proxy_release_connection(backend->worker->s->scheme, + backend, r->server); + /* Ensure that the backend is not reused */ +- *backend_ptr = NULL; ++ req->backend = NULL; + + } + +@@ -1798,12 +1852,13 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, + || c->aborted) { + /* Ack! Phbtt! Die! User aborted! */ + /* Only close backend if we haven't got all from the +- * backend. Furthermore if *backend_ptr is NULL it is no ++ * backend. Furthermore if req->backend is NULL it is no + * longer safe to fiddle around with backend as it might + * be already in use by another thread. + */ +- if (*backend_ptr) { +- backend->close = 1; /* this causes socket close below */ ++ if (req->backend) { ++ /* this causes socket close below */ ++ req->backend->close = 1; + } + finish = TRUE; + } +@@ -1816,7 +1871,7 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, + } + ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "end body send"); + } +- else if (!interim_response) { ++ else { + ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r, "header only"); + + /* make sure we release the backend connection as soon +@@ -1826,7 +1881,7 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, + */ + ap_proxy_release_connection(backend->worker->s->scheme, + backend, r->server); +- *backend_ptr = NULL; ++ req->backend = NULL; + + /* Pass EOS bucket down the filter chain. */ + e = apr_bucket_eos_create(c->bucket_alloc); +@@ -1880,14 +1935,17 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker, + apr_port_t proxyport) + { + int status; +- char server_portstr[32]; + char *scheme; + const char *proxy_function; + const char *u; ++ proxy_http_req_t *req = NULL; + proxy_conn_rec *backend = NULL; + int is_ssl = 0; + conn_rec *c = r->connection; ++ proxy_dir_conf *dconf; + int retry = 0; ++ char *locurl = url; ++ int toclose = 0; + /* + * Use a shorter-lived pool to reduce memory usage + * and avoid a memory leak +@@ -1928,14 +1986,47 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker, + } + ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, "HTTP: serving URL %s", url); + +- + /* create space for state information */ + if ((status = ap_proxy_acquire_connection(proxy_function, &backend, +- worker, r->server)) != OK) +- goto cleanup; ++ worker, r->server)) != OK) { ++ return status; ++ } + + backend->is_ssl = is_ssl; + ++ req = apr_pcalloc(p, sizeof(*req)); ++ req->p = p; ++ req->r = r; ++ req->sconf = conf; ++ req->worker = worker; ++ req->backend = backend; ++ req->bucket_alloc = c->bucket_alloc; ++ req->rb_method = RB_INIT; ++ ++ dconf = ap_get_module_config(r->per_dir_config, &proxy_module); ++ ++ /* Should we handle end-to-end or ping 100-continue? */ ++ if ((r->expecting_100 && dconf->forward_100_continue) ++ || PROXY_DO_100_CONTINUE(worker, r)) { ++ /* We need to reset r->expecting_100 or prefetching will cause ++ * ap_http_filter() to send "100 Continue" response by itself. So ++ * we'll use req->expecting_100 in mod_proxy_http to determine whether ++ * the client should be forwarded "100 continue", and r->expecting_100 ++ * will be restored at the end of the function with the actual value of ++ * req->expecting_100 (i.e. cleared only if mod_proxy_http sent the ++ * "100 Continue" according to its policy). ++ */ ++ req->do_100_continue = req->prefetch_nonblocking = 1; ++ req->expecting_100 = r->expecting_100; ++ r->expecting_100 = 0; ++ } ++ /* Should we block while prefetching the body or try nonblocking and flush ++ * data to the backend ASAP? ++ */ ++ else if (apr_table_get(r->subprocess_env, "proxy-prefetch-nonblocking")) { ++ req->prefetch_nonblocking = 1; ++ } ++ + /* + * In the case that we are handling a reverse proxy connection and this + * is not a request that is coming over an already kept alive connection +@@ -1949,15 +2040,53 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker, + backend->close = 1; + } + ++ /* Step One: Determine Who To Connect To */ ++ if ((status = ap_proxy_determine_connection(p, r, conf, worker, backend, ++ uri, &locurl, proxyname, ++ proxyport, req->server_portstr, ++ sizeof(req->server_portstr)))) ++ goto cleanup; ++ ++ /* Prefetch (nonlocking) the request body so to increase the chance to get ++ * the whole (or enough) body and determine Content-Length vs chunked or ++ * spooled. By doing this before connecting or reusing the backend, we want ++ * to minimize the delay between this connection is considered alive and ++ * the first bytes sent (should the client's link be slow or some input ++ * filter retain the data). This is a best effort to prevent the backend ++ * from closing (from under us) what it thinks is an idle connection, hence ++ * to reduce to the minimum the unavoidable local is_socket_connected() vs ++ * remote keepalive race condition. ++ */ ++ req->input_brigade = apr_brigade_create(p, req->bucket_alloc); ++ req->header_brigade = apr_brigade_create(p, req->bucket_alloc); ++ if ((status = ap_proxy_http_prefetch(req, uri, locurl)) != OK) ++ goto cleanup; ++ ++ /* We need to reset backend->close now, since ap_proxy_http_prefetch() set ++ * it to disable the reuse of the connection *after* this request (no keep- ++ * alive), not to close any reusable connection before this request. However ++ * assure what is expected later by using a local flag and do the right thing ++ * when ap_proxy_connect_backend() below provides the connection to close. ++ */ ++ toclose = backend->close; ++ backend->close = 0; ++ + while (retry < 2) { +- char *locurl = url; ++ if (retry) { ++ char *newurl = url; + +- /* Step One: Determine Who To Connect To */ +- if ((status = ap_proxy_determine_connection(p, r, conf, worker, backend, +- uri, &locurl, proxyname, +- proxyport, server_portstr, +- sizeof(server_portstr))) != OK) +- break; ++ /* Step One (again): (Re)Determine Who To Connect To */ ++ if ((status = ap_proxy_determine_connection(p, r, conf, worker, ++ backend, uri, &newurl, proxyname, proxyport, ++ req->server_portstr, sizeof(req->server_portstr)))) ++ break; ++ ++ /* The code assumes locurl is not changed during the loop, or ++ * ap_proxy_http_prefetch() would have to be called every time, ++ * and header_brigade be changed accordingly... ++ */ ++ AP_DEBUG_ASSERT(strcmp(newurl, locurl) == 0); ++ } + + /* Step Two: Make the Connection */ + if (ap_proxy_check_connection(proxy_function, backend, r->server, 1, +@@ -1972,54 +2101,64 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker, + } + + /* Step Three: Create conn_rec */ +- if (!backend->connection) { +- if ((status = ap_proxy_connection_create_ex(proxy_function, +- backend, r)) != OK) +- break; +- /* +- * On SSL connections set a note on the connection what CN is +- * requested, such that mod_ssl can check if it is requested to do +- * so. +- */ +- if (backend->ssl_hostname) { +- apr_table_setn(backend->connection->notes, +- "proxy-request-hostname", +- backend->ssl_hostname); +- } ++ if ((status = ap_proxy_connection_create_ex(proxy_function, ++ backend, r)) != OK) ++ break; ++ req->origin = backend->connection; ++ ++ /* Don't recycle the connection if prefetch (above) told not to do so */ ++ if (toclose) { ++ backend->close = 1; ++ req->origin->keepalive = AP_CONN_CLOSE; ++ } ++ ++ /* ++ * On SSL connections set a note on the connection what CN is ++ * requested, such that mod_ssl can check if it is requested to do ++ * so. ++ * ++ * https://github.com/apache/httpd/commit/7d272e2628b4ae05f68cdc74b070707250896a34 ++ */ ++ if (backend->ssl_hostname) { ++ apr_table_setn(backend->connection->notes, ++ "proxy-request-hostname", ++ backend->ssl_hostname); + } + + /* Step Four: Send the Request + * On the off-chance that we forced a 100-Continue as a + * kinda HTTP ping test, allow for retries + */ +- if ((status = ap_proxy_http_request(p, r, backend, worker, +- conf, uri, locurl, server_portstr)) != OK) { +- if ((status == HTTP_SERVICE_UNAVAILABLE) && worker->s->ping_timeout_set) { +- backend->close = 1; ++ status = ap_proxy_http_request(req); ++ if (status != OK) { ++ if (req->do_100_continue && status == HTTP_SERVICE_UNAVAILABLE) { + ap_log_rerror(APLOG_MARK, APLOG_INFO, status, r, APLOGNO(01115) + "HTTP: 100-Continue failed to %pI (%s)", + worker->cp->addr, worker->s->hostname_ex); ++ backend->close = 1; + retry++; + continue; +- } else { +- break; +- } ++ } + ++ break; + } + + /* Step Five: Receive the Response... Fall thru to cleanup */ +- status = ap_proxy_http_process_response(p, r, &backend, worker, +- conf, server_portstr); ++ status = ap_proxy_http_process_response(req); + + break; + } + + /* Step Six: Clean Up */ + cleanup: +- if (backend) { ++ if (req->backend) { + if (status != OK) +- backend->close = 1; +- ap_proxy_http_cleanup(proxy_function, r, backend); ++ req->backend->close = 1; ++ ap_proxy_http_cleanup(proxy_function, r, req->backend); ++ } ++ if (req->expecting_100) { ++ /* Restore r->expecting_100 if we didn't touch it */ ++ r->expecting_100 = req->expecting_100; + } + return status; + } +diff --git a/modules/proxy/mod_proxy_uwsgi.c b/modules/proxy/mod_proxy_uwsgi.c +index c5d4f8e..e1253e4 100644 +--- a/modules/proxy/mod_proxy_uwsgi.c ++++ b/modules/proxy/mod_proxy_uwsgi.c +@@ -509,12 +509,11 @@ static int uwsgi_handler(request_rec *r, proxy_worker * worker, + } + + /* Step Three: Create conn_rec */ +- if (!backend->connection) { +- if ((status = ap_proxy_connection_create(UWSGI_SCHEME, backend, +- r->connection, +- r->server)) != OK) +- goto cleanup; +- } ++ if ((status = ap_proxy_connection_create(UWSGI_SCHEME, backend, ++ r->connection, ++ r->server)) != OK) ++ goto cleanup; ++ + + /* Step Four: Process the Request */ + if (((status = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR)) != OK) +diff --git a/modules/proxy/mod_proxy_wstunnel.c b/modules/proxy/mod_proxy_wstunnel.c +index 9dda010..4aadbab 100644 +--- a/modules/proxy/mod_proxy_wstunnel.c ++++ b/modules/proxy/mod_proxy_wstunnel.c +@@ -284,8 +284,8 @@ static int proxy_wstunnel_handler(request_rec *r, proxy_worker *worker, + char server_portstr[32]; + proxy_conn_rec *backend = NULL; + char *scheme; +- int retry; + apr_pool_t *p = r->pool; ++ char *locurl = url; + apr_uri_t *uri; + int is_ssl = 0; + const char *upgrade_method = *worker->s->upgrade ? worker->s->upgrade : "WebSocket"; +@@ -318,59 +318,51 @@ static int proxy_wstunnel_handler(request_rec *r, proxy_worker *worker, + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(02451) "serving URL %s", url); + + /* create space for state information */ +- status = ap_proxy_acquire_connection(scheme, &backend, worker, +- r->server); ++ status = ap_proxy_acquire_connection(scheme, &backend, worker, r->server); + if (status != OK) { +- if (backend) { +- backend->close = 1; +- ap_proxy_release_connection(scheme, backend, r->server); +- } +- return status; ++ goto cleanup; + } + + backend->is_ssl = is_ssl; + backend->close = 0; + +- retry = 0; +- while (retry < 2) { +- char *locurl = url; +- /* Step One: Determine Who To Connect To */ +- status = ap_proxy_determine_connection(p, r, conf, worker, backend, +- uri, &locurl, proxyname, proxyport, +- server_portstr, +- sizeof(server_portstr)); +- +- if (status != OK) +- break; +- +- /* Step Two: Make the Connection */ +- if (ap_proxy_connect_backend(scheme, backend, worker, r->server)) { +- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02452) +- "failed to make connection to backend: %s", +- backend->hostname); +- status = HTTP_SERVICE_UNAVAILABLE; +- break; +- } +- +- /* Step Three: Create conn_rec */ +- if (!backend->connection) { +- status = ap_proxy_connection_create_ex(scheme, backend, r); +- if (status != OK) { +- break; +- } +- } +- +- backend->close = 1; /* must be after ap_proxy_determine_connection */ +- ++ /* Step One: Determine Who To Connect To */ ++ status = ap_proxy_determine_connection(p, r, conf, worker, backend, ++ uri, &locurl, proxyname, proxyport, ++ server_portstr, ++ sizeof(server_portstr)); ++ ++ if (status != OK) { ++ goto cleanup; ++ } ++ ++ /* Step Two: Make the Connection */ ++ if (ap_proxy_connect_backend(scheme, backend, worker, r->server)) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02452) ++ "failed to make connection to backend: %s", ++ backend->hostname); ++ status = HTTP_SERVICE_UNAVAILABLE; ++ goto cleanup; ++ } + +- /* Step Three: Process the Request */ +- status = proxy_wstunnel_request(p, r, backend, worker, conf, uri, locurl, +- server_portstr); +- break; ++ /* Step Three: Create conn_rec */ ++ /* keep it because of */ ++ /* https://github.com/apache/httpd/commit/313d5ee40f390da1a6ee2c2752864ad3aad0a1c3 */ ++ status = ap_proxy_connection_create_ex(scheme, backend, r); ++ if (status != OK) { ++ goto cleanup; + } ++ ++ /* Step Four: Process the Request */ ++ status = proxy_wstunnel_request(p, r, backend, worker, conf, uri, locurl, ++ server_portstr); + ++cleanup: + /* Do not close the socket */ +- ap_proxy_release_connection(scheme, backend, r->server); ++ if (backend) { ++ backend->close = 1; ++ ap_proxy_release_connection(scheme, backend, r->server); ++ } + return status; + } + +diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c +index 0bbfa59..0759dac 100644 +--- a/modules/proxy/proxy_util.c ++++ b/modules/proxy/proxy_util.c +@@ -3573,10 +3573,7 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, + * To be compliant, we only use 100-Continue for requests with bodies. + * We also make sure we won't be talking HTTP/1.0 as well. + */ +- do_100_continue = (worker->s->ping_timeout_set +- && ap_request_has_body(r) +- && (PROXYREQ_REVERSE == r->proxyreq) +- && !(apr_table_get(r->subprocess_env, "force-proxy-request-1.0"))); ++ do_100_continue = PROXY_DO_100_CONTINUE(worker, r); + + if (apr_table_get(r->subprocess_env, "force-proxy-request-1.0")) { + /* +@@ -3593,7 +3590,9 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, + buf = apr_pstrcat(p, r->method, " ", url, " HTTP/1.1" CRLF, NULL); + } + if (apr_table_get(r->subprocess_env, "proxy-nokeepalive")) { +- origin->keepalive = AP_CONN_CLOSE; ++ if (origin) { ++ origin->keepalive = AP_CONN_CLOSE; ++ } + p_conn->close = 1; + } + ap_xlate_proto_to_ascii(buf, strlen(buf)); +@@ -3685,14 +3684,6 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, + if (do_100_continue) { + const char *val; + +- if (!r->expecting_100) { +- /* Don't forward any "100 Continue" response if the client is +- * not expecting it. +- */ +- apr_table_setn(r->subprocess_env, "proxy-interim-response", +- "Suppress"); +- } +- + /* Add the Expect header if not already there. */ + if (((val = apr_table_get(r->headers_in, "Expect")) == NULL) + || (strcasecmp(val, "100-Continue") != 0 /* fast path */ +diff --git a/server/protocol.c b/server/protocol.c +index 8d90055..8d1fdd2 100644 +--- a/server/protocol.c ++++ b/server/protocol.c +@@ -2188,21 +2188,23 @@ AP_DECLARE(void) ap_send_interim_response(request_rec *r, int send_headers) + "Status is %d - not sending interim response", r->status); + return; + } +- if ((r->status == HTTP_CONTINUE) && !r->expecting_100) { +- /* +- * Don't send 100-Continue when there was no Expect: 100-continue +- * in the request headers. For origin servers this is a SHOULD NOT +- * for proxies it is a MUST NOT according to RFC 2616 8.2.3 +- */ +- return; +- } ++ if (r->status == HTTP_CONTINUE) { ++ if (!r->expecting_100) { ++ /* ++ * Don't send 100-Continue when there was no Expect: 100-continue ++ * in the request headers. For origin servers this is a SHOULD NOT ++ * for proxies it is a MUST NOT according to RFC 2616 8.2.3 ++ */ ++ return; ++ } + +- /* if we send an interim response, we're no longer in a state of +- * expecting one. Also, this could feasibly be in a subrequest, +- * so we need to propagate the fact that we responded. +- */ +- for (rr = r; rr != NULL; rr = rr->main) { +- rr->expecting_100 = 0; ++ /* if we send an interim response, we're no longer in a state of ++ * expecting one. Also, this could feasibly be in a subrequest, ++ * so we need to propagate the fact that we responded. ++ */ ++ for (rr = r; rr != NULL; rr = rr->main) { ++ rr->expecting_100 = 0; ++ } + } + + status_line = apr_pstrcat(r->pool, AP_SERVER_PROTOCOL, " ", r->status_line, CRLF, NULL); diff --git a/httpd-2.4.37-proxy-ws-idle-timeout.patch b/httpd-2.4.37-proxy-ws-idle-timeout.patch new file mode 100644 index 0000000..ef4408c --- /dev/null +++ b/httpd-2.4.37-proxy-ws-idle-timeout.patch @@ -0,0 +1,132 @@ +diff --git a/docs/manual/mod/mod_proxy_wstunnel.html.en b/docs/manual/mod/mod_proxy_wstunnel.html.en +index 21ffbe2..16e1628 100644 +--- a/docs/manual/mod/mod_proxy_wstunnel.html.en ++++ b/docs/manual/mod/mod_proxy_wstunnel.html.en +@@ -60,14 +60,33 @@ NONE means you bypass the check for the header but still upgrade to WebSocket. + ANY means that Upgrade will read in the request headers and use + in the response Upgrade

    + +-
    Support Apache!

    Directives

    +-

    This module provides no +- directives.

    ++

    Directives

    ++ ++ +

    Bugfix checklist

    See also

    +
    + ++
    top
    ++
    Description:Determines whether trailers are merged into headers
    ++ ++ ++ ++ ++ ++ ++
    Description:Sets the maximum amount of time to wait for data on the websockets tunnel
    Syntax:ProxyWebsocketIdleTimeout num[ms]
    Default:ProxyWebsocketIdleTimeout 0
    Context:server config, virtual host
    Status:Extension
    Module:mod_proxy_wstunnel
    ++

    This directive imposes a maximum amount of time for the tunnel to be ++ left open while idle. The timeout is considered in seconds by default, but ++ it is possible to increase the time resolution to milliseconds ++ adding the ms suffix.

    ++ ++
    ++ + +
    +

    Available Languages:  en  | +diff --git a/modules/proxy/mod_proxy_wstunnel.c b/modules/proxy/mod_proxy_wstunnel.c +index 4aadbab..ca3ed3a 100644 +--- a/modules/proxy/mod_proxy_wstunnel.c ++++ b/modules/proxy/mod_proxy_wstunnel.c +@@ -18,6 +18,10 @@ + + module AP_MODULE_DECLARE_DATA proxy_wstunnel_module; + ++typedef struct { ++ apr_time_t idle_timeout; ++} proxyws_dir_conf; ++ + /* + * Canonicalise http-like URLs. + * scheme is the scheme for the URL +@@ -108,6 +112,8 @@ static int 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; ++ proxyws_dir_conf *dconf = ap_get_module_config(r->per_dir_config, ++ &proxy_wstunnel_module); + char *buf; + apr_bucket_brigade *header_brigade; + apr_bucket *e; +@@ -185,10 +191,13 @@ static int proxy_wstunnel_request(apr_pool_t *p, request_rec *r, + c->keepalive = AP_CONN_CLOSE; + + do { /* Loop until done (one side closes the connection, or an error) */ +- rv = apr_pollset_poll(pollset, -1, &pollcnt, &signalled); ++ rv = apr_pollset_poll(pollset, dconf->idle_timeout, &pollcnt, &signalled); + if (rv != APR_SUCCESS) { + if (APR_STATUS_IS_EINTR(rv)) { + continue; ++ } else if(APR_STATUS_IS_TIMEUP(rv)){ ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "RH: the connection has timed out"); ++ return HTTP_REQUEST_TIME_OUT; + } + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(02444) "error apr_poll()"); + return HTTP_INTERNAL_SERVER_ERROR; +@@ -366,6 +375,38 @@ cleanup: + return status; + } + ++static const char * proxyws_set_idle(cmd_parms *cmd, void *conf, const char *val) ++{ ++ proxyws_dir_conf *dconf = conf; ++ if (ap_timeout_parameter_parse(val, &(dconf->idle_timeout), "s") != APR_SUCCESS) ++ return "ProxyWebsocketIdleTimeout timeout has wrong format"; ++ ++ if (dconf->idle_timeout < 0) ++ return "ProxyWebsocketIdleTimeout timeout has to be a non-negative number"; ++ ++ if (!dconf->idle_timeout) dconf->idle_timeout = -1; /* loop indefinitely */ ++ ++ return NULL; ++} ++ ++static void *create_proxyws_dir_config(apr_pool_t *p, char *dummy) ++{ ++ proxyws_dir_conf *new = ++ (proxyws_dir_conf *) apr_pcalloc(p, sizeof(proxyws_dir_conf)); ++ ++ new->idle_timeout = -1; /* no timeout */ ++ ++ return (void *) new; ++} ++ ++static const command_rec ws_proxy_cmds[] = ++{ ++ AP_INIT_TAKE1("ProxyWebsocketIdleTimeout", proxyws_set_idle, NULL, RSRC_CONF|ACCESS_CONF, ++ "timeout for activity in either direction, unlimited by default."), ++ ++ {NULL} ++}; ++ + static void ap_proxy_http_register_hook(apr_pool_t *p) + { + proxy_hook_scheme_handler(proxy_wstunnel_handler, NULL, NULL, APR_HOOK_FIRST); +@@ -374,10 +415,10 @@ static void ap_proxy_http_register_hook(apr_pool_t *p) + + AP_DECLARE_MODULE(proxy_wstunnel) = { + STANDARD20_MODULE_STUFF, +- NULL, /* create per-directory config structure */ ++ create_proxyws_dir_config, /* create per-directory config structure */ + NULL, /* merge per-directory config structures */ + NULL, /* create per-server config structure */ + NULL, /* merge per-server config structures */ +- NULL, /* command apr_table_t */ ++ ws_proxy_cmds, /* command apr_table_t */ + ap_proxy_http_register_hook /* register hooks */ + }; diff --git a/httpd-2.4.37-r1828172+.patch b/httpd-2.4.37-r1828172+.patch new file mode 100644 index 0000000..72b124b --- /dev/null +++ b/httpd-2.4.37-r1828172+.patch @@ -0,0 +1,1420 @@ +# ./pullrev.sh 1828172 1862968 1863191 1867878 1867882 1867968 1867970 1867971 +http://svn.apache.org/viewvc?view=revision&revision=1828172 +http://svn.apache.org/viewvc?view=revision&revision=1862968 +http://svn.apache.org/viewvc?view=revision&revision=1863191 +http://svn.apache.org/viewvc?view=revision&revision=1867878 +http://svn.apache.org/viewvc?view=revision&revision=1867882 +http://svn.apache.org/viewvc?view=revision&revision=1867968 +http://svn.apache.org/viewvc?view=revision&revision=1867970 +http://svn.apache.org/viewvc?view=revision&revision=1867971 + +--- httpd-2.4.41/modules/generators/mod_cgi.c ++++ httpd-2.4.41/modules/generators/mod_cgi.c +@@ -92,6 +92,10 @@ + apr_size_t bufbytes; + } cgi_server_conf; + ++typedef struct { ++ apr_interval_time_t timeout; ++} cgi_dirconf; ++ + static void *create_cgi_config(apr_pool_t *p, server_rec *s) + { + cgi_server_conf *c = +@@ -112,6 +116,12 @@ + return overrides->logname ? overrides : base; + } + ++static void *create_cgi_dirconf(apr_pool_t *p, char *dummy) ++{ ++ cgi_dirconf *c = (cgi_dirconf *) apr_pcalloc(p, sizeof(cgi_dirconf)); ++ return c; ++} ++ + static const char *set_scriptlog(cmd_parms *cmd, void *dummy, const char *arg) + { + server_rec *s = cmd->server; +@@ -150,6 +160,17 @@ + return NULL; + } + ++static const char *set_script_timeout(cmd_parms *cmd, void *dummy, const char *arg) ++{ ++ cgi_dirconf *dc = dummy; ++ ++ if (ap_timeout_parameter_parse(arg, &dc->timeout, "s") != APR_SUCCESS) { ++ return "CGIScriptTimeout has wrong format"; ++ } ++ ++ return NULL; ++} ++ + static const command_rec cgi_cmds[] = + { + AP_INIT_TAKE1("ScriptLog", set_scriptlog, NULL, RSRC_CONF, +@@ -158,6 +179,9 @@ + "the maximum length (in bytes) of the script debug log"), + AP_INIT_TAKE1("ScriptLogBuffer", set_scriptlog_buffer, NULL, RSRC_CONF, + "the maximum size (in bytes) to record of a POST request"), ++AP_INIT_TAKE1("CGIScriptTimeout", set_script_timeout, NULL, RSRC_CONF | ACCESS_CONF, ++ "The amount of time to wait between successful reads from " ++ "the CGI script, in seconds."), + {NULL} + }; + +@@ -471,23 +495,26 @@ + apr_filepath_name_get(r->filename)); + } + else { ++ cgi_dirconf *dc = ap_get_module_config(r->per_dir_config, &cgi_module); ++ apr_interval_time_t timeout = dc->timeout > 0 ? dc->timeout : r->server->timeout; ++ + apr_pool_note_subprocess(p, procnew, APR_KILL_AFTER_TIMEOUT); + + *script_in = procnew->out; + if (!*script_in) + return APR_EBADF; +- apr_file_pipe_timeout_set(*script_in, r->server->timeout); ++ apr_file_pipe_timeout_set(*script_in, timeout); + + if (e_info->prog_type == RUN_AS_CGI) { + *script_out = procnew->in; + if (!*script_out) + return APR_EBADF; +- apr_file_pipe_timeout_set(*script_out, r->server->timeout); ++ apr_file_pipe_timeout_set(*script_out, timeout); + + *script_err = procnew->err; + if (!*script_err) + return APR_EBADF; +- apr_file_pipe_timeout_set(*script_err, r->server->timeout); ++ apr_file_pipe_timeout_set(*script_err, timeout); + } + } + } +@@ -541,212 +568,10 @@ + return APR_SUCCESS; + } + +-static void discard_script_output(apr_bucket_brigade *bb) +-{ +- apr_bucket *e; +- const char *buf; +- apr_size_t len; +- apr_status_t rv; +- +- for (e = APR_BRIGADE_FIRST(bb); +- e != APR_BRIGADE_SENTINEL(bb); +- e = APR_BUCKET_NEXT(e)) +- { +- if (APR_BUCKET_IS_EOS(e)) { +- break; +- } +- rv = apr_bucket_read(e, &buf, &len, APR_BLOCK_READ); +- if (rv != APR_SUCCESS) { +- break; +- } +- } +-} +- + #if APR_FILES_AS_SOCKETS +- +-/* A CGI bucket type is needed to catch any output to stderr from the +- * script; see PR 22030. */ +-static const apr_bucket_type_t bucket_type_cgi; +- +-struct cgi_bucket_data { +- apr_pollset_t *pollset; +- request_rec *r; +-}; +- +-/* Create a CGI bucket using pipes from script stdout 'out' +- * and stderr 'err', for request 'r'. */ +-static apr_bucket *cgi_bucket_create(request_rec *r, +- apr_file_t *out, apr_file_t *err, +- apr_bucket_alloc_t *list) +-{ +- apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); +- apr_status_t rv; +- apr_pollfd_t fd; +- struct cgi_bucket_data *data = apr_palloc(r->pool, sizeof *data); +- +- APR_BUCKET_INIT(b); +- b->free = apr_bucket_free; +- b->list = list; +- b->type = &bucket_type_cgi; +- b->length = (apr_size_t)(-1); +- b->start = -1; +- +- /* Create the pollset */ +- rv = apr_pollset_create(&data->pollset, 2, r->pool, 0); +- if (rv != APR_SUCCESS) { +- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01217) +- "apr_pollset_create(); check system or user limits"); +- return NULL; +- } +- +- fd.desc_type = APR_POLL_FILE; +- fd.reqevents = APR_POLLIN; +- fd.p = r->pool; +- fd.desc.f = out; /* script's stdout */ +- fd.client_data = (void *)1; +- rv = apr_pollset_add(data->pollset, &fd); +- if (rv != APR_SUCCESS) { +- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01218) +- "apr_pollset_add(); check system or user limits"); +- return NULL; +- } +- +- fd.desc.f = err; /* script's stderr */ +- fd.client_data = (void *)2; +- rv = apr_pollset_add(data->pollset, &fd); +- if (rv != APR_SUCCESS) { +- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01219) +- "apr_pollset_add(); check system or user limits"); +- return NULL; +- } +- +- data->r = r; +- b->data = data; +- return b; +-} +- +-/* Create a duplicate CGI bucket using given bucket data */ +-static apr_bucket *cgi_bucket_dup(struct cgi_bucket_data *data, +- apr_bucket_alloc_t *list) +-{ +- apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); +- APR_BUCKET_INIT(b); +- b->free = apr_bucket_free; +- b->list = list; +- b->type = &bucket_type_cgi; +- b->length = (apr_size_t)(-1); +- b->start = -1; +- b->data = data; +- return b; +-} +- +-/* Handle stdout from CGI child. Duplicate of logic from the _read +- * method of the real APR pipe bucket implementation. */ +-static apr_status_t cgi_read_stdout(apr_bucket *a, apr_file_t *out, +- const char **str, apr_size_t *len) +-{ +- char *buf; +- apr_status_t rv; +- +- *str = NULL; +- *len = APR_BUCKET_BUFF_SIZE; +- buf = apr_bucket_alloc(*len, a->list); /* XXX: check for failure? */ +- +- rv = apr_file_read(out, buf, len); +- +- if (rv != APR_SUCCESS && rv != APR_EOF) { +- apr_bucket_free(buf); +- return rv; +- } +- +- if (*len > 0) { +- struct cgi_bucket_data *data = a->data; +- apr_bucket_heap *h; +- +- /* Change the current bucket to refer to what we read */ +- a = apr_bucket_heap_make(a, buf, *len, apr_bucket_free); +- h = a->data; +- h->alloc_len = APR_BUCKET_BUFF_SIZE; /* note the real buffer size */ +- *str = buf; +- APR_BUCKET_INSERT_AFTER(a, cgi_bucket_dup(data, a->list)); +- } +- else { +- apr_bucket_free(buf); +- a = apr_bucket_immortal_make(a, "", 0); +- *str = a->data; +- } +- return rv; +-} +- +-/* Read method of CGI bucket: polls on stderr and stdout of the child, +- * sending any stderr output immediately away to the error log. */ +-static apr_status_t cgi_bucket_read(apr_bucket *b, const char **str, +- apr_size_t *len, apr_read_type_e block) +-{ +- struct cgi_bucket_data *data = b->data; +- apr_interval_time_t timeout; +- apr_status_t rv; +- int gotdata = 0; +- +- timeout = block == APR_NONBLOCK_READ ? 0 : data->r->server->timeout; +- +- do { +- const apr_pollfd_t *results; +- apr_int32_t num; +- +- rv = apr_pollset_poll(data->pollset, timeout, &num, &results); +- if (APR_STATUS_IS_TIMEUP(rv)) { +- if (timeout) { +- ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, data->r, APLOGNO(01220) +- "Timeout waiting for output from CGI script %s", +- data->r->filename); +- return rv; +- } +- else { +- return APR_EAGAIN; +- } +- } +- else if (APR_STATUS_IS_EINTR(rv)) { +- continue; +- } +- else if (rv != APR_SUCCESS) { +- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, data->r, APLOGNO(01221) +- "poll failed waiting for CGI child"); +- return rv; +- } +- +- for (; num; num--, results++) { +- if (results[0].client_data == (void *)1) { +- /* stdout */ +- rv = cgi_read_stdout(b, results[0].desc.f, str, len); +- if (APR_STATUS_IS_EOF(rv)) { +- rv = APR_SUCCESS; +- } +- gotdata = 1; +- } else { +- /* stderr */ +- apr_status_t rv2 = log_script_err(data->r, results[0].desc.f); +- if (APR_STATUS_IS_EOF(rv2)) { +- apr_pollset_remove(data->pollset, &results[0]); +- } +- } +- } +- +- } while (!gotdata); +- +- return rv; +-} +- +-static const apr_bucket_type_t bucket_type_cgi = { +- "CGI", 5, APR_BUCKET_DATA, +- apr_bucket_destroy_noop, +- cgi_bucket_read, +- apr_bucket_setaside_notimpl, +- apr_bucket_split_notimpl, +- apr_bucket_copy_notimpl +-}; +- ++#define WANT_CGI_BUCKET + #endif ++#include "cgi_common.h" + + static int cgi_handler(request_rec *r) + { +@@ -766,6 +591,8 @@ + apr_status_t rv; + cgi_exec_info_t e_info; + conn_rec *c; ++ cgi_dirconf *dc = ap_get_module_config(r->per_dir_config, &cgi_module); ++ apr_interval_time_t timeout = dc->timeout > 0 ? dc->timeout : r->server->timeout; + + if (strcmp(r->handler, CGI_MAGIC_TYPE) && strcmp(r->handler, "cgi-script")) { + return DECLINED; +@@ -925,10 +752,7 @@ + AP_DEBUG_ASSERT(script_in != NULL); + + #if APR_FILES_AS_SOCKETS +- apr_file_pipe_timeout_set(script_in, 0); +- apr_file_pipe_timeout_set(script_err, 0); +- +- b = cgi_bucket_create(r, script_in, script_err, c->bucket_alloc); ++ b = cgi_bucket_create(r, dc->timeout, script_in, script_err, c->bucket_alloc); + if (b == NULL) + return HTTP_INTERNAL_SERVER_ERROR; + #else +@@ -938,111 +762,7 @@ + b = apr_bucket_eos_create(c->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(bb, b); + +- /* Handle script return... */ +- if (!nph) { +- const char *location; +- char sbuf[MAX_STRING_LEN]; +- int ret; +- +- if ((ret = ap_scan_script_header_err_brigade_ex(r, bb, sbuf, +- APLOG_MODULE_INDEX))) +- { +- ret = log_script(r, conf, ret, dbuf, sbuf, bb, script_err); +- +- /* +- * ret could be HTTP_NOT_MODIFIED in the case that the CGI script +- * does not set an explicit status and ap_meets_conditions, which +- * is called by ap_scan_script_header_err_brigade, detects that +- * the conditions of the requests are met and the response is +- * not modified. +- * In this case set r->status and return OK in order to prevent +- * running through the error processing stack as this would +- * break with mod_cache, if the conditions had been set by +- * mod_cache itself to validate a stale entity. +- * BTW: We circumvent the error processing stack anyway if the +- * CGI script set an explicit status code (whatever it is) and +- * the only possible values for ret here are: +- * +- * HTTP_NOT_MODIFIED (set by ap_meets_conditions) +- * HTTP_PRECONDITION_FAILED (set by ap_meets_conditions) +- * HTTP_INTERNAL_SERVER_ERROR (if something went wrong during the +- * processing of the response of the CGI script, e.g broken headers +- * or a crashed CGI process). +- */ +- if (ret == HTTP_NOT_MODIFIED) { +- r->status = ret; +- return OK; +- } +- +- return ret; +- } +- +- location = apr_table_get(r->headers_out, "Location"); +- +- if (location && r->status == 200) { +- /* For a redirect whether internal or not, discard any +- * remaining stdout from the script, and log any remaining +- * stderr output, as normal. */ +- discard_script_output(bb); +- apr_brigade_destroy(bb); +- apr_file_pipe_timeout_set(script_err, r->server->timeout); +- log_script_err(r, script_err); +- } +- +- if (location && location[0] == '/' && r->status == 200) { +- /* This redirect needs to be a GET no matter what the original +- * method was. +- */ +- r->method = "GET"; +- r->method_number = M_GET; +- +- /* We already read the message body (if any), so don't allow +- * the redirected request to think it has one. We can ignore +- * Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR. +- */ +- apr_table_unset(r->headers_in, "Content-Length"); +- +- ap_internal_redirect_handler(location, r); +- return OK; +- } +- else if (location && r->status == 200) { +- /* XXX: Note that if a script wants to produce its own Redirect +- * body, it now has to explicitly *say* "Status: 302" +- */ +- return HTTP_MOVED_TEMPORARILY; +- } +- +- rv = ap_pass_brigade(r->output_filters, bb); +- } +- else /* nph */ { +- struct ap_filter_t *cur; +- +- /* get rid of all filters up through protocol... since we +- * haven't parsed off the headers, there is no way they can +- * work +- */ +- +- cur = r->proto_output_filters; +- while (cur && cur->frec->ftype < AP_FTYPE_CONNECTION) { +- cur = cur->next; +- } +- r->output_filters = r->proto_output_filters = cur; +- +- rv = ap_pass_brigade(r->output_filters, bb); +- } +- +- /* don't soak up script output if errors occurred writing it +- * out... otherwise, we prolong the life of the script when the +- * connection drops or we stopped sending output for some other +- * reason */ +- if (rv == APR_SUCCESS && !r->connection->aborted) { +- apr_file_pipe_timeout_set(script_err, r->server->timeout); +- log_script_err(r, script_err); +- } +- +- apr_file_close(script_err); +- +- return OK; /* NOT r->status, even if it has changed. */ ++ return cgi_handle_response(r, nph, bb, timeout, conf, dbuf, script_err); + } + + /*============================================================================ +@@ -1277,7 +997,7 @@ + AP_DECLARE_MODULE(cgi) = + { + STANDARD20_MODULE_STUFF, +- NULL, /* dir config creater */ ++ create_cgi_dirconf, /* dir config creater */ + NULL, /* dir merger --- default is to override */ + create_cgi_config, /* server config */ + merge_cgi_config, /* merge server config */ +--- httpd-2.4.41/modules/generators/config5.m4 ++++ httpd-2.4.41/modules/generators/config5.m4 +@@ -78,4 +78,15 @@ + + APR_ADDTO(INCLUDES, [-I\$(top_srcdir)/$modpath_current]) + ++AC_ARG_ENABLE(cgid-fdpassing, ++ [APACHE_HELP_STRING(--enable-cgid-fdpassing,Enable experimental mod_cgid support for fd passing)], ++ [if test "$enableval" = "yes"; then ++ AC_CHECK_DECL(CMSG_DATA, ++ [AC_DEFINE([HAVE_CGID_FDPASSING], 1, [Enable FD passing support in mod_cgid])], ++ [AC_MSG_ERROR([cannot support mod_cgid fd-passing on this system])], [ ++#include ++#include ]) ++ fi ++]) ++ + APACHE_MODPATH_FINISH +--- httpd-2.4.41/modules/generators/mod_cgid.c ++++ httpd-2.4.41/modules/generators/mod_cgid.c +@@ -342,15 +342,19 @@ + return close(fd); + } + +-/* deal with incomplete reads and signals +- * assume you really have to read buf_size bytes +- */ +-static apr_status_t sock_read(int fd, void *vbuf, size_t buf_size) ++/* Read from the socket dealing with incomplete messages and signals. ++ * Returns 0 on success or errno on failure. Stderr fd passed as ++ * auxiliary data from other end is written to *errfd, or else stderr ++ * fileno if not present. */ ++static apr_status_t sock_readhdr(int fd, int *errfd, void *vbuf, size_t buf_size) + { +- char *buf = vbuf; + int rc; ++#ifndef HAVE_CGID_FDPASSING ++ char *buf = vbuf; + size_t bytes_read = 0; + ++ if (errfd) *errfd = 0; ++ + do { + do { + rc = read(fd, buf + bytes_read, buf_size - bytes_read); +@@ -365,9 +369,60 @@ + } + } while (bytes_read < buf_size); + ++ ++#else /* with FD passing */ ++ struct msghdr msg = {0}; ++ struct iovec vec = {vbuf, buf_size}; ++ struct cmsghdr *cmsg; ++ union { /* union to ensure alignment */ ++ struct cmsghdr cm; ++ char buf[CMSG_SPACE(sizeof(int))]; ++ } u; ++ ++ msg.msg_iov = &vec; ++ msg.msg_iovlen = 1; ++ ++ if (errfd) { ++ msg.msg_control = u.buf; ++ msg.msg_controllen = sizeof(u.buf); ++ *errfd = 0; ++ } ++ ++ /* use MSG_WAITALL to skip loop on truncated reads */ ++ do { ++ rc = recvmsg(fd, &msg, MSG_WAITALL); ++ } while (rc < 0 && errno == EINTR); ++ ++ if (rc == 0) { ++ return ECONNRESET; ++ } ++ else if (rc < 0) { ++ return errno; ++ } ++ else if (rc != buf_size) { ++ /* MSG_WAITALL should ensure the recvmsg blocks until the ++ * entire length is read, but let's be paranoid. */ ++ return APR_INCOMPLETE; ++ } ++ ++ if (errfd ++ && (cmsg = CMSG_FIRSTHDR(&msg)) != NULL ++ && cmsg->cmsg_len == CMSG_LEN(sizeof(*errfd)) ++ && cmsg->cmsg_level == SOL_SOCKET ++ && cmsg->cmsg_type == SCM_RIGHTS) { ++ *errfd = *((int *) CMSG_DATA(cmsg)); ++ } ++#endif ++ + return APR_SUCCESS; + } + ++/* As sock_readhdr but without auxiliary fd passing. */ ++static apr_status_t sock_read(int fd, void *vbuf, size_t buf_size) ++{ ++ return sock_readhdr(fd, NULL, vbuf, buf_size); ++} ++ + /* deal with signals + */ + static apr_status_t sock_write(int fd, const void *buf, size_t buf_size) +@@ -384,7 +439,7 @@ + return APR_SUCCESS; + } + +-static apr_status_t sock_writev(int fd, request_rec *r, int count, ...) ++static apr_status_t sock_writev(int fd, int auxfd, request_rec *r, int count, ...) + { + va_list ap; + int rc; +@@ -399,9 +454,39 @@ + } + va_end(ap); + ++#ifndef HAVE_CGID_FDPASSING + do { + rc = writev(fd, vec, count); + } while (rc < 0 && errno == EINTR); ++#else ++ { ++ struct msghdr msg = { 0 }; ++ struct cmsghdr *cmsg; ++ union { /* union for alignment */ ++ char buf[CMSG_SPACE(sizeof(int))]; ++ struct cmsghdr align; ++ } u; ++ ++ msg.msg_iov = vec; ++ msg.msg_iovlen = count; ++ ++ if (auxfd) { ++ msg.msg_control = u.buf; ++ msg.msg_controllen = sizeof(u.buf); ++ ++ cmsg = CMSG_FIRSTHDR(&msg); ++ cmsg->cmsg_level = SOL_SOCKET; ++ cmsg->cmsg_type = SCM_RIGHTS; ++ cmsg->cmsg_len = CMSG_LEN(sizeof(int)); ++ *((int *) CMSG_DATA(cmsg)) = auxfd; ++ } ++ ++ do { ++ rc = sendmsg(fd, &msg, 0); ++ } while (rc < 0 && errno == EINTR); ++ } ++#endif ++ + if (rc < 0) { + return errno; + } +@@ -410,7 +495,7 @@ + } + + static apr_status_t get_req(int fd, request_rec *r, char **argv0, char ***env, +- cgid_req_t *req) ++ int *errfd, cgid_req_t *req) + { + int i; + char **environ; +@@ -421,7 +506,7 @@ + r->server = apr_pcalloc(r->pool, sizeof(server_rec)); + + /* read the request header */ +- stat = sock_read(fd, req, sizeof(*req)); ++ stat = sock_readhdr(fd, errfd, req, sizeof(*req)); + if (stat != APR_SUCCESS) { + return stat; + } +@@ -479,14 +564,15 @@ + return APR_SUCCESS; + } + +-static apr_status_t send_req(int fd, request_rec *r, char *argv0, char **env, +- int req_type) ++static apr_status_t send_req(int fd, apr_file_t *errpipe, request_rec *r, ++ char *argv0, char **env, int req_type) + { + int i; + cgid_req_t req = {0}; + apr_status_t stat; + ap_unix_identity_t * ugid = ap_run_get_suexec_identity(r); + core_dir_config *core_conf = ap_get_core_module_config(r->per_dir_config); ++ int errfd; + + + if (ugid == NULL) { +@@ -507,16 +593,21 @@ + req.args_len = r->args ? strlen(r->args) : 0; + req.loglevel = r->server->log.level; + ++ if (errpipe) ++ apr_os_file_get(&errfd, errpipe); ++ else ++ errfd = 0; ++ + /* Write the request header */ + if (req.args_len) { +- stat = sock_writev(fd, r, 5, ++ stat = sock_writev(fd, errfd, r, 5, + &req, sizeof(req), + r->filename, req.filename_len, + argv0, req.argv0_len, + r->uri, req.uri_len, + r->args, req.args_len); + } else { +- stat = sock_writev(fd, r, 4, ++ stat = sock_writev(fd, errfd, r, 4, + &req, sizeof(req), + r->filename, req.filename_len, + argv0, req.argv0_len, +@@ -531,7 +622,7 @@ + for (i = 0; i < req.env_count; i++) { + apr_size_t curlen = strlen(env[i]); + +- if ((stat = sock_writev(fd, r, 2, &curlen, sizeof(curlen), ++ if ((stat = sock_writev(fd, 0, r, 2, &curlen, sizeof(curlen), + env[i], curlen)) != APR_SUCCESS) { + return stat; + } +@@ -582,20 +673,34 @@ + } + } + ++/* Callback executed in the forked child process if exec of the CGI ++ * script fails. For the fd-passing case, output to stderr goes to ++ * the client (request handling thread) and is logged via ++ * ap_log_rerror there. For the non-fd-passing case, the "fake" ++ * request_rec passed via userdata is used to log. */ + static void cgid_child_errfn(apr_pool_t *pool, apr_status_t err, + const char *description) + { +- request_rec *r; + void *vr; + + apr_pool_userdata_get(&vr, ERRFN_USERDATA_KEY, pool); +- r = vr; +- +- /* sure we got r, but don't call ap_log_rerror() because we don't +- * have r->headers_in and possibly other storage referenced by +- * ap_log_rerror() +- */ +- ap_log_error(APLOG_MARK, APLOG_ERR, err, r->server, APLOGNO(01241) "%s", description); ++ if (vr) { ++ request_rec *r = vr; ++ ++ /* sure we got r, but don't call ap_log_rerror() because we don't ++ * have r->headers_in and possibly other storage referenced by ++ * ap_log_rerror() ++ */ ++ ap_log_error(APLOG_MARK, APLOG_ERR, err, r->server, APLOGNO(01241) "%s", description); ++ } ++ else { ++ const char *logstr; ++ ++ logstr = apr_psprintf(pool, APLOGNO(01241) "error spawning CGI child: %s (%pm)\n", ++ description, &err); ++ fputs(logstr, stderr); ++ fflush(stderr); ++ } + } + + static int cgid_server(void *data) +@@ -669,7 +774,7 @@ + } + + while (!daemon_should_exit) { +- int errfileno = STDERR_FILENO; ++ int errfileno; + char *argv0 = NULL; + char **env = NULL; + const char * const *argv; +@@ -709,7 +814,7 @@ + r = apr_pcalloc(ptrans, sizeof(request_rec)); + procnew = apr_pcalloc(ptrans, sizeof(*procnew)); + r->pool = ptrans; +- stat = get_req(sd2, r, &argv0, &env, &cgid_req); ++ stat = get_req(sd2, r, &argv0, &env, &errfileno, &cgid_req); + if (stat != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, stat, + main_server, APLOGNO(01248) +@@ -741,6 +846,16 @@ + continue; + } + ++ if (errfileno == 0) { ++ errfileno = STDERR_FILENO; ++ } ++ else { ++ ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, main_server, ++ "using passed fd %d as stderr", errfileno); ++ /* Limit the received fd lifetime to pool lifetime */ ++ apr_pool_cleanup_register(ptrans, (void *)((long)errfileno), ++ close_unix_socket, close_unix_socket); ++ } + apr_os_file_put(&r->server->error_log, &errfileno, 0, r->pool); + apr_os_file_put(&inout, &sd2, 0, r->pool); + +@@ -800,7 +915,10 @@ + close(sd2); + } + else { +- apr_pool_userdata_set(r, ERRFN_USERDATA_KEY, apr_pool_cleanup_null, ptrans); ++ if (errfileno == STDERR_FILENO) { ++ /* Used by cgid_child_errfn without fd-passing. */ ++ apr_pool_userdata_set(r, ERRFN_USERDATA_KEY, apr_pool_cleanup_null, ptrans); ++ } + + argv = (const char * const *)create_argv(r->pool, NULL, NULL, NULL, argv0, r->args); + +@@ -1099,6 +1217,33 @@ + return ret; + } + ++/* Soak up stderr from a script and redirect it to the error log. ++ * TODO: log_scripterror() and this could move to cgi_common.h. */ ++static apr_status_t log_script_err(request_rec *r, apr_file_t *script_err) ++{ ++ char argsbuffer[HUGE_STRING_LEN]; ++ char *newline; ++ apr_status_t rv; ++ cgid_server_conf *conf = ap_get_module_config(r->server->module_config, &cgid_module); ++ ++ while ((rv = apr_file_gets(argsbuffer, HUGE_STRING_LEN, ++ script_err)) == APR_SUCCESS) { ++ ++ newline = strchr(argsbuffer, '\n'); ++ if (newline) { ++ char *prev = newline - 1; ++ if (prev >= argsbuffer && *prev == '\r') { ++ newline = prev; ++ } ++ ++ *newline = '\0'; ++ } ++ log_scripterror(r, conf, r->status, 0, argsbuffer); ++ } ++ ++ return rv; ++} ++ + static int log_script(request_rec *r, cgid_server_conf * conf, int ret, + char *dbuf, const char *sbuf, apr_bucket_brigade *bb, + apr_file_t *script_err) +@@ -1204,6 +1349,13 @@ + return ret; + } + ++/* Pull in CGI bucket implementation. */ ++#define cgi_server_conf cgid_server_conf ++#ifdef HAVE_CGID_FDPASSING ++#define WANT_CGI_BUCKET ++#endif ++#include "cgi_common.h" ++ + static int connect_to_daemon(int *sdptr, request_rec *r, + cgid_server_conf *conf) + { +@@ -1270,27 +1422,6 @@ + return OK; + } + +-static void discard_script_output(apr_bucket_brigade *bb) +-{ +- apr_bucket *e; +- const char *buf; +- apr_size_t len; +- apr_status_t rv; +- +- for (e = APR_BRIGADE_FIRST(bb); +- e != APR_BRIGADE_SENTINEL(bb); +- e = APR_BUCKET_NEXT(e)) +- { +- if (APR_BUCKET_IS_EOS(e)) { +- break; +- } +- rv = apr_bucket_read(e, &buf, &len, APR_BLOCK_READ); +- if (rv != APR_SUCCESS) { +- break; +- } +- } +-} +- + /**************************************************************** + * + * Actual cgid handling... +@@ -1395,6 +1526,7 @@ + + static int cgid_handler(request_rec *r) + { ++ conn_rec *c = r->connection; + int retval, nph, dbpos; + char *argv0, *dbuf; + apr_bucket_brigade *bb; +@@ -1404,10 +1536,11 @@ + int seen_eos, child_stopped_reading; + int sd; + char **env; +- apr_file_t *tempsock; ++ apr_file_t *tempsock, *script_err, *errpipe_out; + struct cleanup_script_info *info; + apr_status_t rv; + cgid_dirconf *dc; ++ apr_interval_time_t timeout; + + if (strcmp(r->handler, CGI_MAGIC_TYPE) && strcmp(r->handler, "cgi-script")) { + return DECLINED; +@@ -1416,7 +1549,7 @@ + conf = ap_get_module_config(r->server->module_config, &cgid_module); + dc = ap_get_module_config(r->per_dir_config, &cgid_module); + +- ++ timeout = dc->timeout > 0 ? dc->timeout : r->server->timeout; + is_included = !strcmp(r->protocol, "INCLUDED"); + + if ((argv0 = strrchr(r->filename, '/')) != NULL) { +@@ -1469,6 +1602,17 @@ + } + */ + ++#ifdef HAVE_CGID_FDPASSING ++ rv = apr_file_pipe_create(&script_err, &errpipe_out, r->pool); ++ if (rv) { ++ return log_scripterror(r, conf, HTTP_SERVICE_UNAVAILABLE, rv, APLOGNO(10176) ++ "could not create pipe for stderr"); ++ } ++#else ++ script_err = NULL; ++ errpipe_out = NULL; ++#endif ++ + /* + * httpd core function used to add common environment variables like + * DOCUMENT_ROOT. +@@ -1481,12 +1625,16 @@ + return retval; + } + +- rv = send_req(sd, r, argv0, env, CGI_REQ); ++ rv = send_req(sd, errpipe_out, r, argv0, env, CGI_REQ); + if (rv != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01268) + "write to cgi daemon process"); + } + ++ /* The write-end of the pipe is only used by the server, so close ++ * it here. */ ++ if (errpipe_out) apr_file_close(errpipe_out); ++ + info = apr_palloc(r->pool, sizeof(struct cleanup_script_info)); + info->conf = conf; + info->r = r; +@@ -1508,12 +1656,7 @@ + */ + + 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_file_pipe_timeout_set(tempsock, timeout); + apr_pool_cleanup_kill(r->pool, (void *)((long)sd), close_unix_socket); + + /* Transfer any put/post args, CERN style... +@@ -1605,114 +1748,19 @@ + */ + shutdown(sd, 1); + +- /* Handle script return... */ +- if (!nph) { +- conn_rec *c = r->connection; +- const char *location; +- char sbuf[MAX_STRING_LEN]; +- int ret; +- +- bb = apr_brigade_create(r->pool, c->bucket_alloc); +- b = apr_bucket_pipe_create(tempsock, c->bucket_alloc); +- APR_BRIGADE_INSERT_TAIL(bb, b); +- b = apr_bucket_eos_create(c->bucket_alloc); +- APR_BRIGADE_INSERT_TAIL(bb, b); +- +- if ((ret = ap_scan_script_header_err_brigade_ex(r, bb, sbuf, +- APLOG_MODULE_INDEX))) +- { +- ret = log_script(r, conf, ret, dbuf, sbuf, bb, NULL); +- +- /* +- * ret could be HTTP_NOT_MODIFIED in the case that the CGI script +- * does not set an explicit status and ap_meets_conditions, which +- * is called by ap_scan_script_header_err_brigade, detects that +- * the conditions of the requests are met and the response is +- * not modified. +- * In this case set r->status and return OK in order to prevent +- * running through the error processing stack as this would +- * break with mod_cache, if the conditions had been set by +- * mod_cache itself to validate a stale entity. +- * BTW: We circumvent the error processing stack anyway if the +- * CGI script set an explicit status code (whatever it is) and +- * the only possible values for ret here are: +- * +- * HTTP_NOT_MODIFIED (set by ap_meets_conditions) +- * HTTP_PRECONDITION_FAILED (set by ap_meets_conditions) +- * HTTP_INTERNAL_SERVER_ERROR (if something went wrong during the +- * processing of the response of the CGI script, e.g broken headers +- * or a crashed CGI process). +- */ +- if (ret == HTTP_NOT_MODIFIED) { +- r->status = ret; +- return OK; +- } +- +- return ret; +- } +- +- location = apr_table_get(r->headers_out, "Location"); +- +- if (location && location[0] == '/' && r->status == 200) { +- +- /* Soak up all the script output */ +- discard_script_output(bb); +- apr_brigade_destroy(bb); +- /* This redirect needs to be a GET no matter what the original +- * method was. +- */ +- r->method = "GET"; +- r->method_number = M_GET; +- +- /* We already read the message body (if any), so don't allow +- * the redirected request to think it has one. We can ignore +- * Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR. +- */ +- apr_table_unset(r->headers_in, "Content-Length"); +- +- ap_internal_redirect_handler(location, r); +- return OK; +- } +- else if (location && r->status == 200) { +- /* XXX: Note that if a script wants to produce its own Redirect +- * body, it now has to explicitly *say* "Status: 302" +- */ +- discard_script_output(bb); +- apr_brigade_destroy(bb); +- return HTTP_MOVED_TEMPORARILY; +- } +- +- rv = ap_pass_brigade(r->output_filters, bb); +- if (rv != APR_SUCCESS) { +- ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, r, +- "Failed to flush CGI output to client"); +- } +- } +- +- if (nph) { +- conn_rec *c = r->connection; +- struct ap_filter_t *cur; +- +- /* get rid of all filters up through protocol... since we +- * haven't parsed off the headers, there is no way they can +- * work +- */ +- +- cur = r->proto_output_filters; +- while (cur && cur->frec->ftype < AP_FTYPE_CONNECTION) { +- cur = cur->next; +- } +- r->output_filters = r->proto_output_filters = cur; +- +- bb = apr_brigade_create(r->pool, c->bucket_alloc); +- b = apr_bucket_pipe_create(tempsock, c->bucket_alloc); +- APR_BRIGADE_INSERT_TAIL(bb, b); +- b = apr_bucket_eos_create(c->bucket_alloc); +- APR_BRIGADE_INSERT_TAIL(bb, b); +- ap_pass_brigade(r->output_filters, bb); +- } ++ bb = apr_brigade_create(r->pool, c->bucket_alloc); ++#ifdef HAVE_CGID_FDPASSING ++ b = cgi_bucket_create(r, dc->timeout, tempsock, script_err, c->bucket_alloc); ++ if (b == NULL) ++ return HTTP_INTERNAL_SERVER_ERROR; /* should call log_scripterror() w/ _UNAVAILABLE? */ ++#else ++ b = apr_bucket_pipe_create(tempsock, c->bucket_alloc); ++#endif ++ APR_BRIGADE_INSERT_TAIL(bb, b); ++ b = apr_bucket_eos_create(c->bucket_alloc); ++ APR_BRIGADE_INSERT_TAIL(bb, b); + +- return OK; /* NOT r->status, even if it has changed. */ ++ return cgi_handle_response(r, nph, bb, timeout, conf, dbuf, script_err); + } + + +@@ -1829,7 +1877,7 @@ + return retval; + } + +- send_req(sd, r, command, env, SSI_REQ); ++ send_req(sd, NULL, r, command, env, SSI_REQ); + + info = apr_palloc(r->pool, sizeof(struct cleanup_script_info)); + info->conf = conf; +--- httpd-2.4.41/modules/generators/cgi_common.h ++++ httpd-2.4.41/modules/generators/cgi_common.h +@@ -0,0 +1,359 @@ ++/* 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 "apr.h" ++#include "apr_strings.h" ++#include "apr_buckets.h" ++#include "apr_lib.h" ++#include "apr_poll.h" ++ ++#define APR_WANT_STRFUNC ++#define APR_WANT_MEMFUNC ++#include "apr_want.h" ++ ++#include "httpd.h" ++#include "util_filter.h" ++ ++static void discard_script_output(apr_bucket_brigade *bb) ++{ ++ apr_bucket *e; ++ const char *buf; ++ apr_size_t len; ++ ++ for (e = APR_BRIGADE_FIRST(bb); ++ e != APR_BRIGADE_SENTINEL(bb) && !APR_BUCKET_IS_EOS(e); ++ e = APR_BRIGADE_FIRST(bb)) ++ { ++ if (apr_bucket_read(e, &buf, &len, APR_BLOCK_READ)) { ++ break; ++ } ++ apr_bucket_delete(e); ++ } ++} ++ ++#ifdef WANT_CGI_BUCKET ++/* A CGI bucket type is needed to catch any output to stderr from the ++ * script; see PR 22030. */ ++static const apr_bucket_type_t bucket_type_cgi; ++ ++struct cgi_bucket_data { ++ apr_pollset_t *pollset; ++ request_rec *r; ++ apr_interval_time_t timeout; ++}; ++ ++/* Create a CGI bucket using pipes from script stdout 'out' ++ * and stderr 'err', for request 'r'. */ ++static apr_bucket *cgi_bucket_create(request_rec *r, ++ apr_interval_time_t timeout, ++ apr_file_t *out, apr_file_t *err, ++ apr_bucket_alloc_t *list) ++{ ++ apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); ++ apr_status_t rv; ++ apr_pollfd_t fd; ++ struct cgi_bucket_data *data = apr_palloc(r->pool, sizeof *data); ++ ++ /* Disable APR timeout handling since we'll use poll() entirely. */ ++ apr_file_pipe_timeout_set(out, 0); ++ apr_file_pipe_timeout_set(err, 0); ++ ++ APR_BUCKET_INIT(b); ++ b->free = apr_bucket_free; ++ b->list = list; ++ b->type = &bucket_type_cgi; ++ b->length = (apr_size_t)(-1); ++ b->start = -1; ++ ++ /* Create the pollset */ ++ rv = apr_pollset_create(&data->pollset, 2, r->pool, 0); ++ if (rv != APR_SUCCESS) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01217) ++ "apr_pollset_create(); check system or user limits"); ++ return NULL; ++ } ++ ++ fd.desc_type = APR_POLL_FILE; ++ fd.reqevents = APR_POLLIN; ++ fd.p = r->pool; ++ fd.desc.f = out; /* script's stdout */ ++ fd.client_data = (void *)1; ++ rv = apr_pollset_add(data->pollset, &fd); ++ if (rv != APR_SUCCESS) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01218) ++ "apr_pollset_add(); check system or user limits"); ++ return NULL; ++ } ++ ++ fd.desc.f = err; /* script's stderr */ ++ fd.client_data = (void *)2; ++ rv = apr_pollset_add(data->pollset, &fd); ++ if (rv != APR_SUCCESS) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01219) ++ "apr_pollset_add(); check system or user limits"); ++ return NULL; ++ } ++ ++ data->r = r; ++ data->timeout = timeout; ++ b->data = data; ++ return b; ++} ++ ++/* Create a duplicate CGI bucket using given bucket data */ ++static apr_bucket *cgi_bucket_dup(struct cgi_bucket_data *data, ++ apr_bucket_alloc_t *list) ++{ ++ apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); ++ APR_BUCKET_INIT(b); ++ b->free = apr_bucket_free; ++ b->list = list; ++ b->type = &bucket_type_cgi; ++ b->length = (apr_size_t)(-1); ++ b->start = -1; ++ b->data = data; ++ return b; ++} ++ ++/* Handle stdout from CGI child. Duplicate of logic from the _read ++ * method of the real APR pipe bucket implementation. */ ++static apr_status_t cgi_read_stdout(apr_bucket *a, apr_file_t *out, ++ const char **str, apr_size_t *len) ++{ ++ char *buf; ++ apr_status_t rv; ++ ++ *str = NULL; ++ *len = APR_BUCKET_BUFF_SIZE; ++ buf = apr_bucket_alloc(*len, a->list); /* XXX: check for failure? */ ++ ++ rv = apr_file_read(out, buf, len); ++ ++ if (rv != APR_SUCCESS && rv != APR_EOF) { ++ apr_bucket_free(buf); ++ return rv; ++ } ++ ++ if (*len > 0) { ++ struct cgi_bucket_data *data = a->data; ++ apr_bucket_heap *h; ++ ++ /* Change the current bucket to refer to what we read */ ++ a = apr_bucket_heap_make(a, buf, *len, apr_bucket_free); ++ h = a->data; ++ h->alloc_len = APR_BUCKET_BUFF_SIZE; /* note the real buffer size */ ++ *str = buf; ++ APR_BUCKET_INSERT_AFTER(a, cgi_bucket_dup(data, a->list)); ++ } ++ else { ++ apr_bucket_free(buf); ++ a = apr_bucket_immortal_make(a, "", 0); ++ *str = a->data; ++ } ++ return rv; ++} ++ ++/* Read method of CGI bucket: polls on stderr and stdout of the child, ++ * sending any stderr output immediately away to the error log. */ ++static apr_status_t cgi_bucket_read(apr_bucket *b, const char **str, ++ apr_size_t *len, apr_read_type_e block) ++{ ++ struct cgi_bucket_data *data = b->data; ++ apr_interval_time_t timeout = 0; ++ apr_status_t rv; ++ int gotdata = 0; ++ ++ if (block != APR_NONBLOCK_READ) { ++ timeout = data->timeout > 0 ? data->timeout : data->r->server->timeout; ++ } ++ ++ do { ++ const apr_pollfd_t *results; ++ apr_int32_t num; ++ ++ rv = apr_pollset_poll(data->pollset, timeout, &num, &results); ++ if (APR_STATUS_IS_TIMEUP(rv)) { ++ if (timeout) { ++ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, data->r, APLOGNO(01220) ++ "Timeout waiting for output from CGI script %s", ++ data->r->filename); ++ return rv; ++ } ++ else { ++ return APR_EAGAIN; ++ } ++ } ++ else if (APR_STATUS_IS_EINTR(rv)) { ++ continue; ++ } ++ else if (rv != APR_SUCCESS) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, data->r, APLOGNO(01221) ++ "poll failed waiting for CGI child"); ++ return rv; ++ } ++ ++ for (; num; num--, results++) { ++ if (results[0].client_data == (void *)1) { ++ /* stdout */ ++ rv = cgi_read_stdout(b, results[0].desc.f, str, len); ++ if (APR_STATUS_IS_EOF(rv)) { ++ rv = APR_SUCCESS; ++ } ++ gotdata = 1; ++ } else { ++ /* stderr */ ++ apr_status_t rv2 = log_script_err(data->r, results[0].desc.f); ++ if (APR_STATUS_IS_EOF(rv2)) { ++ apr_pollset_remove(data->pollset, &results[0]); ++ } ++ } ++ } ++ ++ } while (!gotdata); ++ ++ return rv; ++} ++ ++static const apr_bucket_type_t bucket_type_cgi = { ++ "CGI", 5, APR_BUCKET_DATA, ++ apr_bucket_destroy_noop, ++ cgi_bucket_read, ++ apr_bucket_setaside_notimpl, ++ apr_bucket_split_notimpl, ++ apr_bucket_copy_notimpl ++}; ++ ++#endif /* WANT_CGI_BUCKET */ ++ ++/* Handle the CGI response output, having set up the brigade with the ++ * CGI or PIPE bucket as appropriate. */ ++static int cgi_handle_response(request_rec *r, int nph, apr_bucket_brigade *bb, ++ apr_interval_time_t timeout, cgi_server_conf *conf, ++ char *logdata, apr_file_t *script_err) ++{ ++ apr_status_t rv; ++ ++ /* Handle script return... */ ++ if (!nph) { ++ const char *location; ++ char sbuf[MAX_STRING_LEN]; ++ int ret; ++ ++ if ((ret = ap_scan_script_header_err_brigade_ex(r, bb, sbuf, ++ APLOG_MODULE_INDEX))) ++ { ++ ret = log_script(r, conf, ret, logdata, sbuf, bb, script_err); ++ ++ /* ++ * ret could be HTTP_NOT_MODIFIED in the case that the CGI script ++ * does not set an explicit status and ap_meets_conditions, which ++ * is called by ap_scan_script_header_err_brigade, detects that ++ * the conditions of the requests are met and the response is ++ * not modified. ++ * In this case set r->status and return OK in order to prevent ++ * running through the error processing stack as this would ++ * break with mod_cache, if the conditions had been set by ++ * mod_cache itself to validate a stale entity. ++ * BTW: We circumvent the error processing stack anyway if the ++ * CGI script set an explicit status code (whatever it is) and ++ * the only possible values for ret here are: ++ * ++ * HTTP_NOT_MODIFIED (set by ap_meets_conditions) ++ * HTTP_PRECONDITION_FAILED (set by ap_meets_conditions) ++ * HTTP_INTERNAL_SERVER_ERROR (if something went wrong during the ++ * processing of the response of the CGI script, e.g broken headers ++ * or a crashed CGI process). ++ */ ++ if (ret == HTTP_NOT_MODIFIED) { ++ r->status = ret; ++ return OK; ++ } ++ ++ return ret; ++ } ++ ++ location = apr_table_get(r->headers_out, "Location"); ++ ++ if (location && r->status == 200) { ++ /* For a redirect whether internal or not, discard any ++ * remaining stdout from the script, and log any remaining ++ * stderr output, as normal. */ ++ discard_script_output(bb); ++ apr_brigade_destroy(bb); ++ ++ if (script_err) { ++ apr_file_pipe_timeout_set(script_err, timeout); ++ log_script_err(r, script_err); ++ } ++ } ++ ++ if (location && location[0] == '/' && r->status == 200) { ++ /* This redirect needs to be a GET no matter what the original ++ * method was. ++ */ ++ r->method = "GET"; ++ r->method_number = M_GET; ++ ++ /* We already read the message body (if any), so don't allow ++ * the redirected request to think it has one. We can ignore ++ * Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR. ++ */ ++ apr_table_unset(r->headers_in, "Content-Length"); ++ ++ ap_internal_redirect_handler(location, r); ++ return OK; ++ } ++ else if (location && r->status == 200) { ++ /* XXX: Note that if a script wants to produce its own Redirect ++ * body, it now has to explicitly *say* "Status: 302" ++ */ ++ discard_script_output(bb); ++ apr_brigade_destroy(bb); ++ return HTTP_MOVED_TEMPORARILY; ++ } ++ ++ rv = ap_pass_brigade(r->output_filters, bb); ++ } ++ else /* nph */ { ++ struct ap_filter_t *cur; ++ ++ /* get rid of all filters up through protocol... since we ++ * haven't parsed off the headers, there is no way they can ++ * work ++ */ ++ ++ cur = r->proto_output_filters; ++ while (cur && cur->frec->ftype < AP_FTYPE_CONNECTION) { ++ cur = cur->next; ++ } ++ r->output_filters = r->proto_output_filters = cur; ++ ++ rv = ap_pass_brigade(r->output_filters, bb); ++ } ++ ++ /* don't soak up script output if errors occurred writing it ++ * out... otherwise, we prolong the life of the script when the ++ * connection drops or we stopped sending output for some other ++ * reason */ ++ if (script_err && rv == APR_SUCCESS && !r->connection->aborted) { ++ apr_file_pipe_timeout_set(script_err, timeout); ++ log_script_err(r, script_err); ++ } ++ ++ if (script_err) apr_file_close(script_err); ++ ++ return OK; /* NOT r->status, even if it has changed. */ ++} diff --git a/httpd-2.4.37-r1840554.patch b/httpd-2.4.37-r1840554.patch new file mode 100644 index 0000000..7b379e1 --- /dev/null +++ b/httpd-2.4.37-r1840554.patch @@ -0,0 +1,35 @@ +diff --git a/modules/arch/unix/mod_systemd.c b/modules/arch/unix/mod_systemd.c +index 7a82a90..6c244b6 100644 +--- a/modules/arch/unix/mod_systemd.c ++++ b/modules/arch/unix/mod_systemd.c +@@ -100,6 +100,21 @@ static int systemd_post_config(apr_pool_t *pconf, apr_pool_t *plog, + return OK; + } + ++/* Report the service is ready in post_config, which could be during ++ * startup or after a reload. The server could still hit a fatal ++ * startup error after this point during ap_run_mpm(), so this is ++ * perhaps too early, but by post_config listen() has been called on ++ * the TCP ports so new connections will not be rejected. There will ++ * always be a possible async failure event simultaneous to the ++ * service reporting "ready", so this should be good enough. */ ++static int systemd_post_config_last(apr_pool_t *p, apr_pool_t *plog, ++ apr_pool_t *ptemp, server_rec *main_server) ++{ ++ sd_notify(0, "READY=1\n" ++ "STATUS=Configuration loaded.\n"); ++ return OK; ++} ++ + static int systemd_pre_mpm(apr_pool_t *p, ap_scoreboard_e sb_type) + { + int rv; +@@ -187,6 +202,8 @@ static void systemd_register_hooks(apr_pool_t *p) + ap_hook_pre_config(systemd_pre_config, NULL, NULL, APR_HOOK_LAST); + /* Grab the listener config. */ + ap_hook_post_config(systemd_post_config, NULL, NULL, APR_HOOK_LAST); ++ /* Signal service is ready. */ ++ ap_hook_post_config(systemd_post_config_last, NULL, NULL, APR_HOOK_REALLY_LAST); + /* 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 */ diff --git a/httpd-2.4.37-r1842929+.patch b/httpd-2.4.37-r1842929+.patch new file mode 100644 index 0000000..ab5bba6 --- /dev/null +++ b/httpd-2.4.37-r1842929+.patch @@ -0,0 +1,272 @@ +# ./pullrev.sh 1842929 1842931 1852982 1853631 1857731 +http://svn.apache.org/viewvc?view=revision&revision=1842929 +http://svn.apache.org/viewvc?view=revision&revision=1842931 +http://svn.apache.org/viewvc?view=revision&revision=1852982 +http://svn.apache.org/viewvc?view=revision&revision=1857731 +http://svn.apache.org/viewvc?view=revision&revision=1853631 + +diff --git a/Makefile.in b/Makefile.in +index 06b8c5a..9eeb5c7 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -213,6 +213,7 @@ install-cgi: + install-other: + @test -d $(DESTDIR)$(logfiledir) || $(MKINSTALLDIRS) $(DESTDIR)$(logfiledir) + @test -d $(DESTDIR)$(runtimedir) || $(MKINSTALLDIRS) $(DESTDIR)$(runtimedir) ++ @test -d $(DESTDIR)$(statedir) || $(MKINSTALLDIRS) $(DESTDIR)$(statedir) + @for ext in dll x; do \ + file=apachecore.$$ext; \ + if test -f $$file; then \ +diff --git a/acinclude.m4 b/acinclude.m4 +index 0ad0c13..a8c2804 100644 +--- a/acinclude.m4 ++++ b/acinclude.m4 +@@ -45,6 +45,7 @@ AC_DEFUN([APACHE_GEN_CONFIG_VARS],[ + APACHE_SUBST(installbuilddir) + APACHE_SUBST(runtimedir) + APACHE_SUBST(proxycachedir) ++ APACHE_SUBST(statedir) + APACHE_SUBST(other_targets) + APACHE_SUBST(progname) + APACHE_SUBST(prefix) +@@ -663,6 +664,7 @@ AC_DEFUN([APACHE_EXPORT_ARGUMENTS],[ + APACHE_SUBST_EXPANDED_ARG(runtimedir) + APACHE_SUBST_EXPANDED_ARG(logfiledir) + APACHE_SUBST_EXPANDED_ARG(proxycachedir) ++ APACHE_SUBST_EXPANDED_ARG(statedir) + ]) + + dnl +diff --git a/configure.in b/configure.in +index a208b53..de6a8ad 100644 +--- a/configure.in ++++ b/configure.in +@@ -41,7 +41,7 @@ dnl Something seems broken here. + AC_PREFIX_DEFAULT(/usr/local/apache2) + + dnl Get the layout here, so we can pass the required variables to apr +-APR_ENABLE_LAYOUT(Apache, [errordir iconsdir htdocsdir cgidir]) ++APR_ENABLE_LAYOUT(Apache, [errordir iconsdir htdocsdir cgidir statedir]) + + dnl reparse the configure arguments. + APR_PARSE_ARGUMENTS +diff --git a/include/ap_config_layout.h.in b/include/ap_config_layout.h.in +index 2b4a70c..e076f41 100644 +--- a/include/ap_config_layout.h.in ++++ b/include/ap_config_layout.h.in +@@ -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_STATEDIR "@exp_statedir@" ++#define DEFAULT_REL_STATEDIR "@rel_statedir@" + + #endif /* AP_CONFIG_LAYOUT_H */ +diff --git a/include/http_config.h b/include/http_config.h +index adc5825..effccc1 100644 +--- a/include/http_config.h ++++ b/include/http_config.h +@@ -757,6 +757,14 @@ AP_DECLARE(char *) ap_server_root_relative(apr_pool_t *p, const char *fname); + */ + AP_DECLARE(char *) ap_runtime_dir_relative(apr_pool_t *p, const char *fname); + ++/** ++ * Compute the name of a persistent state file (e.g. a database or ++ * long-lived cache) relative to the appropriate state directory. ++ * Absolute paths are returned as-is. The state directory is ++ * configured via the DefaultStateDir directive or at build time. ++ */ ++AP_DECLARE(char *) ap_state_dir_relative(apr_pool_t *p, const char *fname); ++ + /* Finally, the hook for dynamically loading modules in... */ + + /** +diff --git a/modules/dav/fs/mod_dav_fs.c b/modules/dav/fs/mod_dav_fs.c +index addfd7e..2389f8f 100644 +--- a/modules/dav/fs/mod_dav_fs.c ++++ b/modules/dav/fs/mod_dav_fs.c +@@ -29,6 +29,10 @@ typedef struct { + + extern module AP_MODULE_DECLARE_DATA dav_fs_module; + ++#ifndef DEFAULT_DAV_LOCKDB ++#define DEFAULT_DAV_LOCKDB "davlockdb" ++#endif ++ + const char *dav_get_lockdb_path(const request_rec *r) + { + dav_fs_server_conf *conf; +@@ -57,6 +61,24 @@ static void *dav_fs_merge_server_config(apr_pool_t *p, + return newconf; + } + ++static apr_status_t dav_fs_post_config(apr_pool_t *p, apr_pool_t *plog, ++ apr_pool_t *ptemp, server_rec *base_server) ++{ ++ server_rec *s; ++ ++ for (s = base_server; s; s = s->next) { ++ dav_fs_server_conf *conf; ++ ++ conf = ap_get_module_config(s->module_config, &dav_fs_module); ++ ++ if (!conf->lockdb_path) { ++ conf->lockdb_path = ap_state_dir_relative(p, DEFAULT_DAV_LOCKDB); ++ } ++ } ++ ++ return OK; ++} ++ + /* + * Command handler for the DAVLockDB directive, which is TAKE1 + */ +@@ -87,6 +109,8 @@ static const command_rec dav_fs_cmds[] = + + static void register_hooks(apr_pool_t *p) + { ++ ap_hook_post_config(dav_fs_post_config, NULL, NULL, APR_HOOK_MIDDLE); ++ + dav_hook_gather_propsets(dav_fs_gather_propsets, NULL, NULL, + APR_HOOK_MIDDLE); + dav_hook_find_liveprop(dav_fs_find_liveprop, NULL, NULL, APR_HOOK_MIDDLE); +diff --git a/modules/md/mod_md_config.c b/modules/md/mod_md_config.c +index 336a21b..4d50e26 100644 +--- a/modules/md/mod_md_config.c ++++ b/modules/md/mod_md_config.c +@@ -54,10 +54,18 @@ + + #define DEF_VAL (-1) + ++#ifndef MD_DEFAULT_BASE_DIR ++#define MD_DEFAULT_BASE_DIR "md" ++#endif ++ + /* Default settings for the global conf */ + static md_mod_conf_t defmc = { + NULL, +- "md", ++#if 1 ++ NULL, /* apply default state-dir-relative */ ++#else ++ MD_DEFAULT_BASE_DIR, ++#endif + NULL, + NULL, + 80, +@@ -864,6 +872,12 @@ apr_status_t md_config_post_config(server_rec *s, apr_pool_t *p) + if (mc->hsts_max_age > 0) { + mc->hsts_header = apr_psprintf(p, "max-age=%d", mc->hsts_max_age); + } ++ ++#if 1 ++ if (mc->base_dir == NULL) { ++ mc->base_dir = ap_state_dir_relative(p, MD_DEFAULT_BASE_DIR); ++ } ++#endif + + return APR_SUCCESS; + } +diff --git a/server/core.c b/server/core.c +index bbe52e0..b5ab429 100644 +--- a/server/core.c ++++ b/server/core.c +@@ -133,6 +133,8 @@ AP_DECLARE_DATA int ap_main_state = AP_SQ_MS_INITIAL_STARTUP; + AP_DECLARE_DATA int ap_run_mode = AP_SQ_RM_UNKNOWN; + AP_DECLARE_DATA int ap_config_generation = 0; + ++static const char *core_state_dir; ++ + static void *create_core_dir_config(apr_pool_t *a, char *dir) + { + core_dir_config *conf; +@@ -1411,12 +1413,15 @@ AP_DECLARE(const char *) ap_resolve_env(apr_pool_t *p, const char * word) + return res_buf; + } + +-static int reset_config_defines(void *dummy) ++/* pconf cleanup - clear global variables set from config here. */ ++static apr_status_t reset_config(void *dummy) + { + ap_server_config_defines = saved_server_config_defines; + saved_server_config_defines = NULL; + server_config_defined_vars = NULL; +- return OK; ++ core_state_dir = NULL; ++ ++ return APR_SUCCESS; + } + + /* +@@ -3108,6 +3113,24 @@ static const char *set_runtime_dir(cmd_parms *cmd, void *dummy, const char *arg) + return NULL; + } + ++static const char *set_state_dir(cmd_parms *cmd, void *dummy, const char *arg) ++{ ++ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); ++ ++ if (err != NULL) { ++ return err; ++ } ++ ++ if ((apr_filepath_merge((char**)&core_state_dir, NULL, ++ ap_server_root_relative(cmd->temp_pool, arg), ++ APR_FILEPATH_TRUENAME, cmd->pool) != APR_SUCCESS) ++ || !ap_is_directory(cmd->temp_pool, core_state_dir)) { ++ return "DefaultStateDir must be a valid directory, absolute or relative to ServerRoot"; ++ } ++ ++ return NULL; ++} ++ + static const char *set_timeout(cmd_parms *cmd, void *dummy, const char *arg) + { + const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_CONTEXT); +@@ -4409,6 +4432,8 @@ AP_INIT_TAKE1("ServerRoot", set_server_root, NULL, RSRC_CONF | EXEC_ON_READ, + "Common directory of server-related files (logs, confs, etc.)"), + AP_INIT_TAKE1("DefaultRuntimeDir", set_runtime_dir, NULL, RSRC_CONF | EXEC_ON_READ, + "Common directory for run-time files (shared memory, locks, etc.)"), ++AP_INIT_TAKE1("DefaultStateDir", set_state_dir, NULL, RSRC_CONF | EXEC_ON_READ, ++ "Common directory for persistent state (databases, long-lived caches, etc.)"), + AP_INIT_TAKE1("ErrorLog", set_server_string_slot, + (void *)APR_OFFSETOF(server_rec, error_fname), RSRC_CONF, + "The filename of the error log"), +@@ -4932,8 +4957,7 @@ static int core_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptem + + if (!saved_server_config_defines) + init_config_defines(pconf); +- apr_pool_cleanup_register(pconf, NULL, reset_config_defines, +- apr_pool_cleanup_null); ++ apr_pool_cleanup_register(pconf, NULL, reset_config, apr_pool_cleanup_null); + + ap_regcomp_set_default_cflags(AP_REG_DOLLAR_ENDONLY); + +@@ -5202,6 +5226,27 @@ AP_DECLARE(int) ap_state_query(int query) + } + } + ++AP_DECLARE(char *) ap_state_dir_relative(apr_pool_t *p, const char *file) ++{ ++ char *newpath = NULL; ++ apr_status_t rv; ++ const char *state_dir; ++ ++ state_dir = core_state_dir ++ ? core_state_dir ++ : ap_server_root_relative(p, DEFAULT_REL_STATEDIR); ++ ++ rv = apr_filepath_merge(&newpath, state_dir, file, APR_FILEPATH_TRUENAME, p); ++ if (newpath && (rv == APR_SUCCESS || APR_STATUS_IS_EPATHWILD(rv) ++ || APR_STATUS_IS_ENOENT(rv) ++ || APR_STATUS_IS_ENOTDIR(rv))) { ++ return newpath; ++ } ++ else { ++ return NULL; ++ } ++} ++ + static apr_random_t *rng = NULL; + #if APR_HAS_THREADS + static apr_thread_mutex_t *rng_mutex = NULL; diff --git a/httpd-2.4.37-r1845768+.patch b/httpd-2.4.37-r1845768+.patch new file mode 100644 index 0000000..a51934f --- /dev/null +++ b/httpd-2.4.37-r1845768+.patch @@ -0,0 +1,48 @@ +diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c +index 70d151e..e4f5fc8 100644 +--- a/modules/ssl/ssl_engine_init.c ++++ b/modules/ssl/ssl_engine_init.c +@@ -1095,7 +1095,9 @@ static apr_status_t ssl_init_ctx_crl(server_rec *s, + /* + * Read a file that optionally contains the server certificate in PEM + * format, possibly followed by a sequence of CA certificates that +- * should be sent to the peer in the SSL Certificate message. ++ * should be sent to the peer in the SSL Certificate message. Returns ++ * 0 on success, otherwise the OpenSSL error stack contents should be ++ * reported. + */ + static int use_certificate_chain( + SSL_CTX *ctx, char *file, int skipfirst, pem_password_cb *cb) +@@ -1128,8 +1130,10 @@ static int use_certificate_chain( + ctx->extra_certs = NULL; + } + #endif ++ + /* create new extra chain by loading the certs */ + n = 0; ++ ERR_clear_error(); + while ((x509 = PEM_read_bio_X509(bio, NULL, cb, NULL)) != NULL) { + if (!SSL_CTX_add_extra_chain_cert(ctx, x509)) { + X509_free(x509); +@@ -1190,6 +1194,7 @@ static apr_status_t ssl_init_ctx_cert_chain(server_rec *s, + if (n < 0) { + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01903) + "Failed to configure CA certificate chain!"); ++ ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); + return ssl_die(s); + } + +diff --git a/modules/ssl/ssl_util_ocsp.c b/modules/ssl/ssl_util_ocsp.c +index b11a6e9..b66e151 100644 +--- a/modules/ssl/ssl_util_ocsp.c ++++ b/modules/ssl/ssl_util_ocsp.c +@@ -363,7 +363,9 @@ static STACK_OF(X509) *modssl_read_ocsp_certificates(const char *file) + BIO_free(bio); + return NULL; + } ++ + /* create new extra chain by loading the certs */ ++ ERR_clear_error(); + while ((x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) { + if (!other_certs) { + other_certs = sk_X509_new_null(); diff --git a/httpd-2.4.37-r1851471.patch b/httpd-2.4.37-r1851471.patch new file mode 100644 index 0000000..03e3301 --- /dev/null +++ b/httpd-2.4.37-r1851471.patch @@ -0,0 +1,44 @@ +diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c +index 0958135..018b667 100644 +--- a/modules/ssl/ssl_engine_io.c ++++ b/modules/ssl/ssl_engine_io.c +@@ -200,6 +200,8 @@ static int bio_filter_out_write(BIO *bio, const char *in, int inl) + apr_bucket *e; + int need_flush; + ++ BIO_clear_retry_flags(bio); ++ + #ifndef SSL_OP_NO_RENEGOTIATION + /* Abort early if the client has initiated a renegotiation. */ + if (outctx->filter_ctx->config->reneg_state == RENEG_ABORT) { +@@ -208,12 +210,6 @@ static int bio_filter_out_write(BIO *bio, const char *in, int inl) + } + #endif + +- /* when handshaking we'll have a small number of bytes. +- * max size SSL will pass us here is about 16k. +- * (16413 bytes to be exact) +- */ +- BIO_clear_retry_flags(bio); +- + /* Use a transient bucket for the output data - any downstream + * filter must setaside if necessary. */ + e = apr_bucket_transient_create(in, inl, outctx->bb->bucket_alloc); +@@ -460,6 +456,8 @@ static int bio_filter_in_read(BIO *bio, char *in, int inlen) + if (!in) + return 0; + ++ BIO_clear_retry_flags(bio); ++ + #ifndef SSL_OP_NO_RENEGOTIATION + /* Abort early if the client has initiated a renegotiation. */ + if (inctx->filter_ctx->config->reneg_state == RENEG_ABORT) { +@@ -468,8 +466,6 @@ static int bio_filter_in_read(BIO *bio, char *in, int inlen) + } + #endif + +- BIO_clear_retry_flags(bio); +- + if (!inctx->bb) { + inctx->rc = APR_EOF; + return -1; diff --git a/httpd-2.4.37-r1861793+.patch b/httpd-2.4.37-r1861793+.patch new file mode 100644 index 0000000..4ac9c2d --- /dev/null +++ b/httpd-2.4.37-r1861793+.patch @@ -0,0 +1,209 @@ +diff --git a/configure.in b/configure.in +index de6a8ad..4ca489d 100644 +--- a/configure.in ++++ b/configure.in +@@ -465,6 +465,28 @@ LIBS="" + AC_SEARCH_LIBS(crypt, crypt) + CRYPT_LIBS="$LIBS" + APACHE_SUBST(CRYPT_LIBS) ++ ++if test "$ac_cv_search_crypt" != "no"; then ++ # Test crypt() with the SHA-512 test vector from https://akkadia.org/drepper/SHA-crypt.txt ++ AC_CACHE_CHECK([whether crypt() supports SHA-2], [ap_cv_crypt_sha2], [ ++ AC_RUN_IFELSE([AC_LANG_PROGRAM([[ ++#include ++#include ++#include ++ ++#define PASSWD_0 "Hello world!" ++#define SALT_0 "\$6\$saltstring" ++#define EXPECT_0 "\$6\$saltstring\$svn8UoSVapNtMuq1ukKS4tPQd8iKwSMHWjl/O817G3uBnIFNjnQJu" \ ++ "esI68u4OTLiBFdcbYEdFCoEOfaS35inz1" ++]], [char *result = crypt(PASSWD_0, SALT_0); ++ if (!result) return 1; ++ if (strcmp(result, EXPECT_0)) return 2; ++])], [ap_cv_crypt_sha2=yes], [ap_cv_crypt_sha2=no])]) ++ if test "$ap_cv_crypt_sha2" = yes; then ++ AC_DEFINE([HAVE_CRYPT_SHA2], 1, [Define if crypt() supports SHA-2 hashes]) ++ fi ++fi ++ + LIBS="$saved_LIBS" + + dnl See Comment #Spoon +diff --git a/support/htpasswd.c b/support/htpasswd.c +index 660a27c..136f62a 100644 +--- a/support/htpasswd.c ++++ b/support/htpasswd.c +@@ -98,28 +98,32 @@ static int mkrecord(struct passwd_ctx *ctx, char *user) + static void usage(void) + { + apr_file_printf(errfile, "Usage:" NL +- "\thtpasswd [-cimBdpsDv] [-C cost] passwordfile username" NL +- "\thtpasswd -b[cmBdpsDv] [-C cost] passwordfile username password" NL ++ "\thtpasswd [-cimB25dpsDv] [-C cost] [-r rounds] passwordfile username" NL ++ "\thtpasswd -b[cmB25dpsDv] [-C cost] [-r rounds] passwordfile username password" NL + NL +- "\thtpasswd -n[imBdps] [-C cost] username" NL +- "\thtpasswd -nb[mBdps] [-C cost] username password" NL ++ "\thtpasswd -n[imB25dps] [-C cost] [-r rounds] username" NL ++ "\thtpasswd -nb[mB25dps] [-C cost] [-r rounds] username password" NL + " -c Create a new file." NL + " -n Don't update file; display results on stdout." NL + " -b Use the password from the command line rather than prompting " + "for it." NL + " -i Read password from stdin without verification (for script usage)." NL + " -m Force MD5 encryption of the password (default)." NL +- " -B Force bcrypt encryption of the password (very secure)." NL ++ " -2 Force SHA-256 crypt() hash of the password (secure)." NL ++ " -5 Force SHA-512 crypt() hash of the password (secure)." NL ++ " -B Force bcrypt encryption of the password (very secure)." NL + " -C Set the computing time used for the bcrypt algorithm" NL + " (higher is more secure but slower, default: %d, valid: 4 to 31)." NL ++ " -r Set the number of rounds used for the SHA-256, SHA-512 algorithms" NL ++ " (higher is more secure but slower, default: 5000)." NL + " -d Force CRYPT encryption of the password (8 chars max, insecure)." NL +- " -s Force SHA encryption of the password (insecure)." NL ++ " -s Force SHA-1 encryption of the password (insecure)." NL + " -p Do not encrypt the password (plaintext, insecure)." NL + " -D Delete the specified user." NL + " -v Verify password for the specified user." NL + "On other systems than Windows and NetWare the '-p' flag will " + "probably not work." NL +- "The SHA algorithm does not use a salt and is less secure than the " ++ "The SHA-1 algorithm does not use a salt and is less secure than the " + "MD5 algorithm." NL, + BCRYPT_DEFAULT_COST + ); +@@ -178,7 +182,7 @@ static void check_args(int argc, const char *const argv[], + if (rv != APR_SUCCESS) + exit(ERR_SYNTAX); + +- while ((rv = apr_getopt(state, "cnmspdBbDiC:v", &opt, &opt_arg)) == APR_SUCCESS) { ++ while ((rv = apr_getopt(state, "cnmspdBbDi25C:r:v", &opt, &opt_arg)) == APR_SUCCESS) { + switch (opt) { + case 'c': + *mask |= APHTP_NEWFILE; +diff --git a/support/passwd_common.c b/support/passwd_common.c +index 664e509..d45657c 100644 +--- a/support/passwd_common.c ++++ b/support/passwd_common.c +@@ -185,10 +185,15 @@ int mkhash(struct passwd_ctx *ctx) + #if CRYPT_ALGO_SUPPORTED + char *cbuf; + #endif ++#ifdef HAVE_CRYPT_SHA2 ++ const char *setting; ++ char method; ++#endif + +- if (ctx->cost != 0 && ctx->alg != ALG_BCRYPT) { ++ if (ctx->cost != 0 && ctx->alg != ALG_BCRYPT ++ && ctx->alg != ALG_CRYPT_SHA256 && ctx->alg != ALG_CRYPT_SHA512 ) { + apr_file_printf(errfile, +- "Warning: Ignoring -C argument for this algorithm." NL); ++ "Warning: Ignoring -C/-r argument for this algorithm." NL); + } + + if (ctx->passwd == NULL) { +@@ -246,6 +251,34 @@ int mkhash(struct passwd_ctx *ctx) + break; + #endif /* CRYPT_ALGO_SUPPORTED */ + ++#ifdef HAVE_CRYPT_SHA2 ++ case ALG_CRYPT_SHA256: ++ case ALG_CRYPT_SHA512: ++ ret = generate_salt(salt, 16, &ctx->errstr, ctx->pool); ++ if (ret != 0) ++ break; ++ ++ method = ctx->alg == ALG_CRYPT_SHA256 ? '5': '6'; ++ ++ if (ctx->cost) ++ setting = apr_psprintf(ctx->pool, "$%c$rounds=%d$%s", ++ method, ctx->cost, salt); ++ else ++ setting = apr_psprintf(ctx->pool, "$%c$%s", ++ method, salt); ++ ++ cbuf = crypt(pw, setting); ++ if (cbuf == NULL) { ++ rv = APR_FROM_OS_ERROR(errno); ++ ctx->errstr = apr_psprintf(ctx->pool, "crypt() failed: %pm", &rv); ++ ret = ERR_PWMISMATCH; ++ break; ++ } ++ ++ apr_cpystrn(ctx->out, cbuf, ctx->out_len - 1); ++ break; ++#endif /* HAVE_CRYPT_SHA2 */ ++ + #if BCRYPT_ALGO_SUPPORTED + case ALG_BCRYPT: + rv = apr_generate_random_bytes((unsigned char*)salt, 16); +@@ -294,6 +327,19 @@ int parse_common_options(struct passwd_ctx *ctx, char opt, + case 's': + ctx->alg = ALG_APSHA; + break; ++#ifdef HAVE_CRYPT_SHA2 ++ case '2': ++ ctx->alg = ALG_CRYPT_SHA256; ++ break; ++ case '5': ++ ctx->alg = ALG_CRYPT_SHA512; ++ break; ++#else ++ case '2': ++ case '5': ++ ctx->errstr = "SHA-2 crypt() algorithms are not supported on this platform."; ++ return ERR_ALG_NOT_SUPP; ++#endif + case 'p': + ctx->alg = ALG_PLAIN; + #if !PLAIN_ALGO_SUPPORTED +@@ -324,11 +370,12 @@ int parse_common_options(struct passwd_ctx *ctx, char opt, + return ERR_ALG_NOT_SUPP; + #endif + break; +- case 'C': { ++ case 'C': ++ case 'r': { + char *endptr; + long num = strtol(opt_arg, &endptr, 10); + if (*endptr != '\0' || num <= 0) { +- ctx->errstr = "argument to -C must be a positive integer"; ++ ctx->errstr = "argument to -C/-r must be a positive integer"; + return ERR_SYNTAX; + } + ctx->cost = num; +diff --git a/support/passwd_common.h b/support/passwd_common.h +index 660081e..f1b3cd7 100644 +--- a/support/passwd_common.h ++++ b/support/passwd_common.h +@@ -28,6 +28,8 @@ + #include "apu_version.h" + #endif + ++#include "ap_config_auto.h" ++ + #define MAX_STRING_LEN 256 + + #define ALG_PLAIN 0 +@@ -35,6 +37,8 @@ + #define ALG_APMD5 2 + #define ALG_APSHA 3 + #define ALG_BCRYPT 4 ++#define ALG_CRYPT_SHA256 5 ++#define ALG_CRYPT_SHA512 6 + + #define BCRYPT_DEFAULT_COST 5 + +@@ -84,7 +88,7 @@ struct passwd_ctx { + apr_size_t out_len; + char *passwd; + int alg; +- int cost; ++ int cost; /* cost for bcrypt, rounds for SHA-2 */ + enum { + PW_PROMPT = 0, + PW_ARG, diff --git a/httpd-2.4.37-r1862410.patch b/httpd-2.4.37-r1862410.patch new file mode 100644 index 0000000..a21d24d --- /dev/null +++ b/httpd-2.4.37-r1862410.patch @@ -0,0 +1,108 @@ +--- a/modules/dav/main/mod_dav.c ++++ b/modules/dav/main/mod_dav.c +@@ -557,6 +557,7 @@ + dav_begin_multistatus(bb, r, status, namespaces); + + apr_pool_create(&subpool, r->pool); ++ apr_pool_tag(subpool, "mod_dav-multistatus"); + + for (; first != NULL; first = first->next) { + apr_pool_clear(subpool); +@@ -1980,8 +1981,9 @@ + ** Note: we cast to lose the "const". The propdb won't try to change + ** the resource, however, since we are opening readonly. + */ +- err = dav_open_propdb(ctx->r, ctx->w.lockdb, wres->resource, 1, +- ctx->doc ? ctx->doc->namespaces : NULL, &propdb); ++ err = dav_popen_propdb(ctx->scratchpool, ++ ctx->r, ctx->w.lockdb, wres->resource, 1, ++ ctx->doc ? ctx->doc->namespaces : NULL, &propdb); + if (err != NULL) { + /* ### do something with err! */ + +--- a/modules/dav/main/mod_dav.h ++++ b/modules/dav/main/mod_dav.h +@@ -1590,6 +1590,16 @@ + apr_array_header_t *ns_xlate, + dav_propdb **propdb); + ++DAV_DECLARE(dav_error *) dav_popen_propdb( ++ apr_pool_t *p, ++ request_rec *r, ++ dav_lockdb *lockdb, ++ const dav_resource *resource, ++ int ro, ++ apr_array_header_t *ns_xlate, ++ dav_propdb **propdb); ++ ++ + DAV_DECLARE(void) dav_close_propdb(dav_propdb *db); + + DAV_DECLARE(dav_get_props_result) dav_get_props( +--- a/modules/dav/main/props.c ++++ b/modules/dav/main/props.c +@@ -323,7 +323,7 @@ + { + /* 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, ++ const char *e_uri = ap_escape_uri(propdb->p, + propdb->resource->uri); + + /* perform a "GET" on the resource's URI (note that the resource +@@ -524,8 +524,21 @@ + apr_array_header_t * ns_xlate, + dav_propdb **p_propdb) + { +- dav_propdb *propdb = apr_pcalloc(r->pool, sizeof(*propdb)); ++ return dav_popen_propdb(r->pool, r, lockdb, resource, ro, ns_xlate, p_propdb); ++} + ++DAV_DECLARE(dav_error *)dav_popen_propdb(apr_pool_t *p, ++ request_rec *r, dav_lockdb *lockdb, ++ const dav_resource *resource, ++ int ro, ++ apr_array_header_t * ns_xlate, ++ dav_propdb **p_propdb) ++{ ++ dav_propdb *propdb = NULL; ++ ++ propdb = apr_pcalloc(p, sizeof(*propdb)); ++ propdb->p = p; ++ + *p_propdb = NULL; + + #if DAV_DEBUG +@@ -537,7 +550,6 @@ + #endif + + propdb->r = r; +- apr_pool_create(&propdb->p, r->pool); + propdb->resource = resource; + propdb->ns_xlate = ns_xlate; + +@@ -562,10 +574,10 @@ + (*propdb->db_hooks->close)(propdb->db); + } + +- /* Currently, mod_dav's pool usage doesn't allow clearing this pool. */ +-#if 0 +- apr_pool_destroy(propdb->p); +-#endif ++ if (propdb->subreq) { ++ ap_destroy_sub_req(propdb->subreq); ++ propdb->subreq = NULL; ++ } + } + + DAV_DECLARE(dav_get_props_result) dav_get_allprops(dav_propdb *propdb, +@@ -739,7 +751,8 @@ + */ + + if (elem->priv == NULL) { +- elem->priv = apr_pcalloc(propdb->p, sizeof(*priv)); ++ /* elem->priv outlives propdb->p. Hence use the request pool */ ++ elem->priv = apr_pcalloc(propdb->r->pool, sizeof(*priv)); + } + priv = elem->priv; + diff --git a/httpd-2.4.37-r1864000.patch b/httpd-2.4.37-r1864000.patch new file mode 100644 index 0000000..8adecfa --- /dev/null +++ b/httpd-2.4.37-r1864000.patch @@ -0,0 +1,40 @@ +--- a/modules/proxy/mod_proxy_hcheck.c 2019/07/30 13:01:08 1863999 ++++ b/modules/proxy/mod_proxy_hcheck.c 2019/07/30 13:01:21 1864000 +@@ -110,6 +110,10 @@ + if (!worker && !v) { + return "Bad call to set_worker_hc_param()"; + } ++ if (!ctx) { ++ ctx = hc_create_config(p, s); ++ ap_set_module_config(s->module_config, &proxy_hcheck_module, ctx); ++ } + temp = (hc_template_t *)v; + if (!strcasecmp(key, "hctemplate")) { + hc_template_t *template; +@@ -1059,6 +1063,8 @@ + int i; + sctx_t *ctx = (sctx_t *) ap_get_module_config(r->server->module_config, + &proxy_hcheck_module); ++ if (!ctx) ++ return; + if (apr_is_empty_table(ctx->conditions)) + return; + +@@ -1088,6 +1094,8 @@ + int i; + sctx_t *ctx = (sctx_t *) ap_get_module_config(r->server->module_config, + &proxy_hcheck_module); ++ if (!ctx) ++ return; + if (apr_is_empty_table(ctx->conditions)) + return; + +@@ -1111,6 +1119,8 @@ + int i; + sctx_t *ctx = (sctx_t *) ap_get_module_config(r->server->module_config, + &proxy_hcheck_module); ++ if (!ctx) ++ return 0; + if (apr_is_empty_table(ctx->conditions)) + return 0; + diff --git a/httpd-2.4.37-r1870095+.patch b/httpd-2.4.37-r1870095+.patch new file mode 100644 index 0000000..bd43c5c --- /dev/null +++ b/httpd-2.4.37-r1870095+.patch @@ -0,0 +1,117 @@ +# ./pullrev.sh 1870095 1870097 +http://svn.apache.org/viewvc?view=revision&revision=1870095 +http://svn.apache.org/viewvc?view=revision&revision=1870097 + +--- httpd-2.4.37/modules/ssl/ssl_engine_kernel.c ++++ httpd-2.4.37/modules/ssl/ssl_engine_kernel.c +@@ -114,6 +114,45 @@ + return result; + } + ++/* If a renegotiation is required for the location, and the request ++ * includes a message body (and the client has not requested a "100 ++ * Continue" response), then the client will be streaming the request ++ * body over the wire already. In that case, it is not possible to ++ * stop and perform a new SSL handshake immediately; once the SSL ++ * library moves to the "accept" state, it will reject the SSL packets ++ * which the client is sending for the request body. ++ * ++ * To allow authentication to complete in the hook, the solution used ++ * here is to fill a (bounded) buffer with the request body, and then ++ * to reinject that request body later. ++ * ++ * This function is called to fill the renegotiation buffer for the ++ * location as required, or fail. Returns zero on success or HTTP_ ++ * error code on failure. ++ */ ++static int fill_reneg_buffer(request_rec *r, SSLDirConfigRec *dc) ++{ ++ int rv; ++ apr_size_t rsize; ++ ++ /* ### this is HTTP/1.1 specific, special case for protocol? */ ++ if (r->expecting_100 || !ap_request_has_body(r)) { ++ return 0; ++ } ++ ++ rsize = dc->nRenegBufferSize == UNSET ? DEFAULT_RENEG_BUFFER_SIZE : dc->nRenegBufferSize; ++ if (rsize > 0) { ++ /* Fill the I/O buffer with the request body if possible. */ ++ rv = ssl_io_buffer_fill(r, rsize); ++ } ++ else { ++ /* If the reneg buffer size is set to zero, just fail. */ ++ rv = HTTP_REQUEST_ENTITY_TOO_LARGE; ++ } ++ ++ return rv; ++} ++ + #ifdef HAVE_TLSEXT + static int ap_array_same_str_set(apr_array_header_t *s1, apr_array_header_t *s2) + { +@@ -814,41 +853,14 @@ + } + } + +- /* If a renegotiation is now required for this location, and the +- * request includes a message body (and the client has not +- * requested a "100 Continue" response), then the client will be +- * streaming the request body over the wire already. In that +- * case, it is not possible to stop and perform a new SSL +- * handshake immediately; once the SSL library moves to the +- * "accept" state, it will reject the SSL packets which the client +- * is sending for the request body. +- * +- * To allow authentication to complete in this auth hook, the +- * solution used here is to fill a (bounded) buffer with the +- * request body, and then to reinject that request body later. +- */ +- if (renegotiate && !renegotiate_quick +- && !r->expecting_100 +- && ap_request_has_body(r)) { +- int rv; +- apr_size_t rsize; +- +- rsize = dc->nRenegBufferSize == UNSET ? DEFAULT_RENEG_BUFFER_SIZE : +- dc->nRenegBufferSize; +- if (rsize > 0) { +- /* Fill the I/O buffer with the request body if possible. */ +- rv = ssl_io_buffer_fill(r, rsize); +- } +- else { +- /* If the reneg buffer size is set to zero, just fail. */ +- rv = HTTP_REQUEST_ENTITY_TOO_LARGE; +- } +- +- if (rv) { ++ /* Fill reneg buffer if required. */ ++ if (renegotiate && !renegotiate_quick) { ++ rc = fill_reneg_buffer(r, dc); ++ if (rc) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02257) + "could not buffer message body to allow " + "SSL renegotiation to proceed"); +- return rv; ++ return rc; + } + } + +@@ -1132,6 +1144,17 @@ + } + } + ++ /* Fill reneg buffer if required. */ ++ if (change_vmode) { ++ rc = fill_reneg_buffer(r, dc); ++ if (rc) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10228) ++ "could not buffer message body to allow " ++ "TLS Post-Handshake Authentication to proceed"); ++ return rc; ++ } ++ } ++ + if (change_vmode) { + char peekbuf[1]; + diff --git a/httpd-2.4.37-r1872790.patch b/httpd-2.4.37-r1872790.patch new file mode 100644 index 0000000..2cab606 --- /dev/null +++ b/httpd-2.4.37-r1872790.patch @@ -0,0 +1,636 @@ +diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h +index 57cc92f..fbbd508 100644 +--- a/modules/proxy/mod_proxy.h ++++ b/modules/proxy/mod_proxy.h +@@ -288,12 +288,15 @@ typedef struct { + + /* Connection pool */ + struct proxy_conn_pool { +- apr_pool_t *pool; /* The pool used in constructor and destructor calls */ +- apr_sockaddr_t *addr; /* Preparsed remote address info */ +- apr_reslist_t *res; /* Connection resource list */ +- proxy_conn_rec *conn; /* Single connection for prefork mpm */ ++ apr_pool_t *pool; /* The pool used in constructor and destructor calls */ ++ apr_sockaddr_t *addr; /* Preparsed remote address info */ ++ apr_reslist_t *res; /* Connection resource list */ ++ proxy_conn_rec *conn; /* Single connection for prefork mpm */ ++ apr_pool_t *dns_pool; /* The pool used for worker scoped DNS resolutions */ + }; + ++#define AP_VOLATILIZE_T(T, x) (*(T volatile *)&(x)) ++ + /* worker status bits */ + /* + * NOTE: Keep up-to-date w/ proxy_wstat_tbl[] +@@ -475,7 +478,9 @@ struct proxy_worker { + proxy_conn_pool *cp; /* Connection pool to use */ + proxy_worker_shared *s; /* Shared data */ + proxy_balancer *balancer; /* which balancer am I in? */ ++#if APR_HAS_THREADS + apr_thread_mutex_t *tmutex; /* Thread lock for updating address cache */ ++#endif + void *context; /* general purpose storage */ + ap_conf_vector_t *section_config; /* -section wherein defined */ + }; +@@ -534,7 +539,9 @@ struct proxy_balancer { + apr_time_t wupdated; /* timestamp of last change to workers list */ + proxy_balancer_method *lbmethod; + apr_global_mutex_t *gmutex; /* global lock for updating list of workers */ ++#if APR_HAS_THREADS + apr_thread_mutex_t *tmutex; /* Thread lock for updating shm */ ++#endif + proxy_server_conf *sconf; + void *context; /* general purpose storage */ + proxy_balancer_shared *s; /* Shared data */ +diff --git a/modules/proxy/mod_proxy_balancer.c b/modules/proxy/mod_proxy_balancer.c +index c59f5e9..3a28038 100644 +--- a/modules/proxy/mod_proxy_balancer.c ++++ b/modules/proxy/mod_proxy_balancer.c +@@ -346,23 +346,27 @@ static proxy_worker *find_best_worker(proxy_balancer *balancer, + proxy_worker *candidate = NULL; + apr_status_t rv; + ++#if APR_HAS_THREADS + if ((rv = PROXY_THREAD_LOCK(balancer)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01163) + "%s: Lock failed for find_best_worker()", + balancer->s->name); + return NULL; + } ++#endif + + candidate = (*balancer->lbmethod->finder)(balancer, r); + + if (candidate) + candidate->s->elected++; + ++#if APR_HAS_THREADS + if ((rv = PROXY_THREAD_UNLOCK(balancer)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01164) + "%s: Unlock failed for find_best_worker()", + balancer->s->name); + } ++#endif + + if (candidate == NULL) { + /* All the workers are in error state or disabled. +@@ -492,11 +496,13 @@ static int proxy_balancer_pre_request(proxy_worker **worker, + /* Step 2: Lock the LoadBalancer + * XXX: perhaps we need the process lock here + */ ++#if APR_HAS_THREADS + if ((rv = PROXY_THREAD_LOCK(*balancer)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01166) + "%s: Lock failed for pre_request", (*balancer)->s->name); + return DECLINED; + } ++#endif + + /* Step 3: force recovery */ + force_recovery(*balancer, r->server); +@@ -557,20 +563,24 @@ static int proxy_balancer_pre_request(proxy_worker **worker, + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01167) + "%s: All workers are in error state for route (%s)", + (*balancer)->s->name, route); ++#if APR_HAS_THREADS + if ((rv = PROXY_THREAD_UNLOCK(*balancer)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01168) + "%s: Unlock failed for pre_request", + (*balancer)->s->name); + } ++#endif + return HTTP_SERVICE_UNAVAILABLE; + } + } + ++#if APR_HAS_THREADS + if ((rv = PROXY_THREAD_UNLOCK(*balancer)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01169) + "%s: Unlock failed for pre_request", + (*balancer)->s->name); + } ++#endif + if (!*worker) { + runtime = find_best_worker(*balancer, r); + if (!runtime) { +@@ -644,12 +654,14 @@ static int proxy_balancer_post_request(proxy_worker *worker, + + apr_status_t rv; + ++#if APR_HAS_THREADS + if ((rv = PROXY_THREAD_LOCK(balancer)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01173) + "%s: Lock failed for post_request", + balancer->s->name); + return HTTP_INTERNAL_SERVER_ERROR; + } ++#endif + + if (!apr_is_empty_array(balancer->errstatuses) + && !(worker->s->status & PROXY_WORKER_IGNORE_ERRORS)) { +@@ -681,11 +693,12 @@ static int proxy_balancer_post_request(proxy_worker *worker, + worker->s->error_time = apr_time_now(); + + } +- ++#if APR_HAS_THREADS + if ((rv = PROXY_THREAD_UNLOCK(balancer)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01175) + "%s: Unlock failed for post_request", balancer->s->name); + } ++#endif + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01176) + "proxy_balancer_post_request for (%s)", balancer->s->name); + +@@ -945,7 +958,6 @@ static int balancer_post_config(apr_pool_t *pconf, apr_pool_t *plog, + PROXY_STRNCPY(balancer->s->sname, sname); /* We know this will succeed */ + + balancer->max_workers = balancer->workers->nelts + balancer->growth; +- + /* Create global mutex */ + rv = ap_global_mutex_create(&(balancer->gmutex), NULL, balancer_mutex_type, + balancer->s->sname, s, pconf, 0); +@@ -955,7 +967,6 @@ static int balancer_post_config(apr_pool_t *pconf, apr_pool_t *plog, + balancer->s->sname); + return HTTP_INTERNAL_SERVER_ERROR; + } +- + apr_pool_cleanup_register(pconf, (void *)s, lock_remove, + apr_pool_cleanup_null); + +@@ -1135,17 +1146,21 @@ static int balancer_handler(request_rec *r) + + balancer = (proxy_balancer *)conf->balancers->elts; + for (i = 0; i < conf->balancers->nelts; i++, balancer++) { ++#if APR_HAS_THREADS + if ((rv = PROXY_THREAD_LOCK(balancer)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01189) + "%s: Lock failed for balancer_handler", + balancer->s->name); + } ++#endif + ap_proxy_sync_balancer(balancer, r->server, conf); ++#if APR_HAS_THREADS + if ((rv = PROXY_THREAD_UNLOCK(balancer)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01190) + "%s: Unlock failed for balancer_handler", + balancer->s->name); + } ++#endif + } + + if (r->args && (r->method_number == M_GET)) { +@@ -1359,11 +1374,13 @@ static int balancer_handler(request_rec *r) + proxy_worker *nworker; + nworker = ap_proxy_get_worker(r->pool, bsel, conf, val); + if (!nworker && storage->num_free_slots(bsel->wslot)) { ++#if APR_HAS_THREADS + if ((rv = PROXY_GLOBAL_LOCK(bsel)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01194) + "%s: Lock failed for adding worker", + bsel->s->name); + } ++#endif + ret = ap_proxy_define_worker(conf->pool, &nworker, bsel, conf, val, 0); + if (!ret) { + unsigned int index; +@@ -1372,53 +1389,76 @@ static int balancer_handler(request_rec *r) + if ((rv = storage->grab(bsel->wslot, &index)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_EMERG, rv, r, APLOGNO(01195) + "worker slotmem_grab failed"); ++#if APR_HAS_THREADS + if ((rv = PROXY_GLOBAL_UNLOCK(bsel)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01196) + "%s: Unlock failed for adding worker", + bsel->s->name); + } ++#endif + return HTTP_BAD_REQUEST; + } + if ((rv = storage->dptr(bsel->wslot, index, (void *)&shm)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_EMERG, rv, r, APLOGNO(01197) + "worker slotmem_dptr failed"); ++#if APR_HAS_THREADS + if ((rv = PROXY_GLOBAL_UNLOCK(bsel)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01198) + "%s: Unlock failed for adding worker", + bsel->s->name); + } ++#endif + return HTTP_BAD_REQUEST; + } + if ((rv = ap_proxy_share_worker(nworker, shm, index)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_EMERG, rv, r, APLOGNO(01199) + "Cannot share worker"); ++#if APR_HAS_THREADS + if ((rv = PROXY_GLOBAL_UNLOCK(bsel)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01200) + "%s: Unlock failed for adding worker", + bsel->s->name); + } ++#endif + return HTTP_BAD_REQUEST; + } + if ((rv = ap_proxy_initialize_worker(nworker, r->server, conf->pool)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_EMERG, rv, r, APLOGNO(01201) + "Cannot init worker"); ++#if APR_HAS_THREADS + if ((rv = PROXY_GLOBAL_UNLOCK(bsel)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01202) + "%s: Unlock failed for adding worker", + bsel->s->name); + } ++#endif + return HTTP_BAD_REQUEST; + } + /* sync all timestamps */ + bsel->wupdated = bsel->s->wupdated = nworker->s->updated = apr_time_now(); + /* by default, all new workers are disabled */ + ap_proxy_set_wstatus(PROXY_WORKER_DISABLED_FLAG, 1, nworker); ++ } else { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10163) ++ "%s: failed to add worker %s", ++ bsel->s->name, val); ++#if APR_HAS_THREADS ++ PROXY_GLOBAL_UNLOCK(bsel); ++#endif ++ return HTTP_BAD_REQUEST; + } ++#if APR_HAS_THREADS + if ((rv = PROXY_GLOBAL_UNLOCK(bsel)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01203) + "%s: Unlock failed for adding worker", + bsel->s->name); + } ++#endif ++ } else { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10164) ++ "%s: failed to add worker %s", ++ bsel->s->name, val); ++ return HTTP_BAD_REQUEST; + } + + } +diff --git a/modules/proxy/mod_proxy_ftp.c b/modules/proxy/mod_proxy_ftp.c +index 5d9175e..5c4d641 100644 +--- a/modules/proxy/mod_proxy_ftp.c ++++ b/modules/proxy/mod_proxy_ftp.c +@@ -979,8 +979,10 @@ static int proxy_ftp_handler(request_rec *r, proxy_worker *worker, + apr_status_t rv; + conn_rec *origin, *data = NULL; + apr_status_t err = APR_SUCCESS; ++#if APR_HAS_THREADS + apr_status_t uerr = APR_SUCCESS; +- apr_bucket_brigade *bb = apr_brigade_create(p, c->bucket_alloc); ++#endif ++ apr_bucket_brigade *bb; + char *buf, *connectname; + apr_port_t connectport; + char *ftpmessage = NULL; +@@ -1120,13 +1122,15 @@ static int proxy_ftp_handler(request_rec *r, proxy_worker *worker, + + if (worker->s->is_address_reusable) { + if (!worker->cp->addr) { ++#if APR_HAS_THREADS + if ((err = PROXY_THREAD_LOCK(worker->balancer)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, err, r, APLOGNO(01037) "lock"); + return HTTP_INTERNAL_SERVER_ERROR; + } ++#endif + } +- connect_addr = worker->cp->addr; +- address_pool = worker->cp->pool; ++ connect_addr = AP_VOLATILIZE_T(apr_sockaddr_t *, worker->cp->addr); ++ address_pool = worker->cp->dns_pool; + } + else + address_pool = r->pool; +@@ -1139,9 +1143,11 @@ static int proxy_ftp_handler(request_rec *r, proxy_worker *worker, + address_pool); + if (worker->s->is_address_reusable && !worker->cp->addr) { + worker->cp->addr = connect_addr; ++#if APR_HAS_THREADS + if ((uerr = PROXY_THREAD_UNLOCK(worker->balancer)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, uerr, r, APLOGNO(01038) "unlock"); + } ++#endif + } + /* + * get all the possible IP addresses for the destname and loop through +@@ -1212,6 +1218,7 @@ static int proxy_ftp_handler(request_rec *r, proxy_worker *worker, + * correct directory... + */ + ++ bb = apr_brigade_create(p, c->bucket_alloc); + + /* possible results: */ + /* 120 Service ready in nnn minutes. */ +diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c +index 2bfc8f0..7714b6c 100644 +--- a/modules/proxy/proxy_util.c ++++ b/modules/proxy/proxy_util.c +@@ -1167,8 +1167,10 @@ PROXY_DECLARE(char *) ap_proxy_define_balancer(apr_pool_t *p, + lbmethod = ap_lookup_provider(PROXY_LBMETHOD, "byrequests", "0"); + + (*balancer)->workers = apr_array_make(p, 5, sizeof(proxy_worker *)); ++#if APR_HAS_THREADS + (*balancer)->gmutex = NULL; + (*balancer)->tmutex = NULL; ++#endif + (*balancer)->lbmethod = lbmethod; + + if (do_malloc) +@@ -1257,7 +1259,9 @@ PROXY_DECLARE(apr_status_t) ap_proxy_share_balancer(proxy_balancer *balancer, + + PROXY_DECLARE(apr_status_t) ap_proxy_initialize_balancer(proxy_balancer *balancer, server_rec *s, apr_pool_t *p) + { ++#if APR_HAS_THREADS + apr_status_t rv = APR_SUCCESS; ++#endif + ap_slotmem_provider_t *storage = balancer->storage; + apr_size_t size; + unsigned int num; +@@ -1297,6 +1301,7 @@ PROXY_DECLARE(apr_status_t) ap_proxy_initialize_balancer(proxy_balancer *balance + if (balancer->lbmethod && balancer->lbmethod->reset) + balancer->lbmethod->reset(balancer, s); + ++#if APR_HAS_THREADS + if (balancer->tmutex == NULL) { + rv = apr_thread_mutex_create(&(balancer->tmutex), APR_THREAD_MUTEX_DEFAULT, p); + if (rv != APR_SUCCESS) { +@@ -1305,6 +1310,7 @@ PROXY_DECLARE(apr_status_t) ap_proxy_initialize_balancer(proxy_balancer *balance + return rv; + } + } ++#endif + return APR_SUCCESS; + } + +@@ -1446,16 +1452,14 @@ static void socket_cleanup(proxy_conn_rec *conn) + + static apr_status_t conn_pool_cleanup(void *theworker) + { +- proxy_worker *worker = (proxy_worker *)theworker; +- if (worker->cp->res) { +- worker->cp->pool = NULL; +- } ++ ((proxy_worker *)theworker)->cp = NULL; + return APR_SUCCESS; + } + + static void init_conn_pool(apr_pool_t *p, proxy_worker *worker) + { + apr_pool_t *pool; ++ apr_pool_t *dns_pool; + proxy_conn_pool *cp; + + /* +@@ -1466,12 +1470,21 @@ static void init_conn_pool(apr_pool_t *p, proxy_worker *worker) + */ + apr_pool_create(&pool, p); + apr_pool_tag(pool, "proxy_worker_cp"); ++ /* ++ * Create a subpool of the connection pool for worker ++ * scoped DNS resolutions. This is needed to avoid race ++ * conditions in using the connection pool by multiple ++ * threads during ramp up. ++ */ ++ apr_pool_create(&dns_pool, pool); ++ apr_pool_tag(dns_pool, "proxy_worker_dns"); + /* + * Alloc from the same pool as worker. + * proxy_conn_pool is permanently attached to the worker. + */ + cp = (proxy_conn_pool *)apr_pcalloc(p, sizeof(proxy_conn_pool)); + cp->pool = pool; ++ cp->dns_pool = dns_pool; + worker->cp = cp; + } + +@@ -1487,14 +1500,6 @@ static apr_status_t connection_cleanup(void *theconn) + proxy_conn_rec *conn = (proxy_conn_rec *)theconn; + proxy_worker *worker = conn->worker; + +- /* +- * If the connection pool is NULL the worker +- * cleanup has been run. Just return. +- */ +- if (!worker->cp->pool) { +- return APR_SUCCESS; +- } +- + if (conn->r) { + apr_pool_destroy(conn->r->pool); + conn->r = NULL; +@@ -1616,7 +1621,7 @@ static apr_status_t connection_destructor(void *resource, void *params, + proxy_worker *worker = params; + + /* Destroy the pool only if not called from reslist_destroy */ +- if (worker->cp->pool) { ++ if (worker->cp) { + proxy_conn_rec *conn = resource; + apr_pool_destroy(conn->pool); + } +@@ -1972,67 +1977,73 @@ PROXY_DECLARE(apr_status_t) ap_proxy_initialize_worker(proxy_worker *worker, ser + ap_proxy_worker_name(p, worker)); + } + else { +- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00927) +- "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) { +- rv = apr_thread_mutex_create(&(worker->tmutex), APR_THREAD_MUTEX_DEFAULT, p); +- if (rv != APR_SUCCESS) { +- ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00928) +- "can not create worker thread mutex"); ++ /* Check again after we got the lock if we are still uninitialized */ ++ if (!(AP_VOLATILIZE_T(unsigned int, worker->local_status) & PROXY_WORKER_INITIALIZED)) { ++ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00927) ++ "initializing worker %s local", ++ ap_proxy_worker_name(p, worker)); ++ /* Now init local worker data */ ++#if APR_HAS_THREADS ++ if (worker->tmutex == NULL) { ++ rv = apr_thread_mutex_create(&(worker->tmutex), APR_THREAD_MUTEX_DEFAULT, p); ++ if (rv != APR_SUCCESS) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(00928) ++ "can not create worker thread mutex"); ++ apr_global_mutex_unlock(proxy_mutex); ++ return rv; ++ } ++ } ++#endif ++ if (worker->cp == NULL) ++ init_conn_pool(p, worker); ++ if (worker->cp == NULL) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00929) ++ "can not create connection pool"); + apr_global_mutex_unlock(proxy_mutex); +- return rv; ++ return APR_EGENERAL; + } +- } +- if (worker->cp == NULL) +- init_conn_pool(p, worker); +- if (worker->cp == NULL) { +- ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00929) +- "can not create connection pool"); +- apr_global_mutex_unlock(proxy_mutex); +- return APR_EGENERAL; +- } + +- if (worker->s->hmax) { +- rv = apr_reslist_create(&(worker->cp->res), +- worker->s->min, worker->s->smax, +- worker->s->hmax, worker->s->ttl, +- connection_constructor, connection_destructor, +- worker, worker->cp->pool); ++ if (worker->s->hmax) { ++ rv = apr_reslist_create(&(worker->cp->res), ++ worker->s->min, worker->s->smax, ++ worker->s->hmax, worker->s->ttl, ++ connection_constructor, connection_destructor, ++ worker, worker->cp->pool); + +- apr_pool_cleanup_register(worker->cp->pool, (void *)worker, +- conn_pool_cleanup, +- apr_pool_cleanup_null); ++ apr_pool_pre_cleanup_register(worker->cp->pool, worker, ++ conn_pool_cleanup); + +- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00930) +- "initialized pool in child %" APR_PID_T_FMT " for (%s) min=%d max=%d smax=%d", +- getpid(), worker->s->hostname_ex, worker->s->min, +- worker->s->hmax, worker->s->smax); ++ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00930) ++ "initialized pool in child %" APR_PID_T_FMT " for (%s) min=%d max=%d smax=%d", ++ getpid(), worker->s->hostname_ex, worker->s->min, ++ worker->s->hmax, worker->s->smax); + +- /* Set the acquire timeout */ +- if (rv == APR_SUCCESS && worker->s->acquire_set) { +- apr_reslist_timeout_set(worker->cp->res, worker->s->acquire); +- } ++ /* Set the acquire timeout */ ++ if (rv == APR_SUCCESS && worker->s->acquire_set) { ++ apr_reslist_timeout_set(worker->cp->res, worker->s->acquire); ++ } + +- } +- else { +- void *conn; ++ } ++ else { ++ void *conn; + +- rv = connection_constructor(&conn, worker, worker->cp->pool); +- worker->cp->conn = conn; ++ rv = connection_constructor(&conn, worker, worker->cp->pool); ++ worker->cp->conn = conn; + +- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00931) +- "initialized single connection worker in child %" APR_PID_T_FMT " for (%s)", +- getpid(), worker->s->hostname_ex); ++ ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, s, APLOGNO(00931) ++ "initialized single connection worker in child %" APR_PID_T_FMT " for (%s)", ++ getpid(), worker->s->hostname_ex); ++ } ++ if (rv == APR_SUCCESS) { ++ worker->local_status |= (PROXY_WORKER_INITIALIZED); ++ } + } + apr_global_mutex_unlock(proxy_mutex); + + } + if (rv == APR_SUCCESS) { + worker->s->status |= (PROXY_WORKER_INITIALIZED); +- worker->local_status |= (PROXY_WORKER_INITIALIZED); + } + return rv; + } +@@ -2292,13 +2303,13 @@ PROXY_DECLARE(int) ap_proxy_acquire_connection(const char *proxy_function, + else { + /* create the new connection if the previous was destroyed */ + if (!worker->cp->conn) { +- connection_constructor((void **)conn, worker, worker->cp->pool); ++ rv = connection_constructor((void **)conn, worker, worker->cp->pool); + } + else { + *conn = worker->cp->conn; + worker->cp->conn = NULL; ++ rv = APR_SUCCESS; + } +- rv = APR_SUCCESS; + } + + if (rv != APR_SUCCESS) { +@@ -2344,7 +2355,9 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, + { + int server_port; + apr_status_t err = APR_SUCCESS; ++#if APR_HAS_THREADS + apr_status_t uerr = APR_SUCCESS; ++#endif + const char *uds_path; + + /* +@@ -2481,25 +2494,39 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, + * we can reuse the address. + */ + if (!worker->cp->addr) { ++#if APR_HAS_THREADS + 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; + } ++#endif + + /* +- * Worker can have the single constant backend address. +- * 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. ++ * Recheck addr after we got the lock. This may have changed ++ * while waiting for the lock. + */ +- err = apr_sockaddr_info_get(&(worker->cp->addr), +- conn->hostname, APR_UNSPEC, +- conn->port, 0, +- worker->cp->pool); ++ if (!AP_VOLATILIZE_T(apr_sockaddr_t *, worker->cp->addr)) { ++ ++ apr_sockaddr_t *addr; ++ ++ /* ++ * Worker can have the single constant backend address. ++ * 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(&addr, ++ conn->hostname, APR_UNSPEC, ++ conn->port, 0, ++ worker->cp->dns_pool); ++ worker->cp->addr = addr; ++ } + conn->addr = worker->cp->addr; ++#if APR_HAS_THREADS + if ((uerr = PROXY_THREAD_UNLOCK(worker)) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, uerr, r, APLOGNO(00946) "unlock"); + } ++#endif + } + else { + conn->addr = worker->cp->addr; +@@ -3422,7 +3449,9 @@ PROXY_DECLARE(apr_status_t) ap_proxy_sync_balancer(proxy_balancer *b, server_rec + (*runtime)->cp = NULL; + (*runtime)->balancer = b; + (*runtime)->s = shm; ++#if APR_HAS_THREADS + (*runtime)->tmutex = NULL; ++#endif + rv = ap_proxy_initialize_worker(*runtime, s, conf->pool); + if (rv != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, APLOGNO(00966) "Cannot init worker"); diff --git a/httpd-2.4.37-r1873907.patch b/httpd-2.4.37-r1873907.patch new file mode 100644 index 0000000..4ec0cfa --- /dev/null +++ b/httpd-2.4.37-r1873907.patch @@ -0,0 +1,265 @@ +diff --git a/docs/manual/mod/mod_ssl.html.en b/docs/manual/mod/mod_ssl.html.en +index b543150..ab72d4f 100644 +--- a/docs/manual/mod/mod_ssl.html.en ++++ b/docs/manual/mod/mod_ssl.html.en +@@ -1524,6 +1524,32 @@ The available (case-insensitive) protocols are:

    +

    Example

    SSLProtocol TLSv1
    +
    + ++
    ++

    SSLProtocol for name-based virtual hosts

    ++

    ++Before OpenSSL 1.1.1, even though the Server Name Indication (SNI) allowed to ++determine the targeted virtual host early in the TLS handshake, it was not ++possible to switch the TLS protocol version of the connection at this point, ++and thus the SSLProtocol negotiated was always based off ++the one of the base virtual host (first virtual host declared on the ++listening IP:port of the connection). ++

    ++

    ++Beginning with Apache HTTP server version 2.4.42, when built/linked against ++OpenSSL 1.1.1 or later, and when the SNI is provided by the client in the TLS ++handshake, the SSLProtocol of each (name-based) virtual ++host can and will be honored. ++

    ++

    ++For compatibility with previous versions, if no ++SSLProtocol is configured in a name-based virtual host, ++the one from the base virtual host still applies, unless ++SSLProtocol is configured globally in which case the ++global value applies (this latter exception is more sensible than compatible, ++though). ++

    ++
    ++ +
    +
    top
    +

    SSLProxyCACertificateFile Directive

    +diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c +index 0c4bf1f..ca5f702 100644 +--- a/modules/ssl/ssl_engine_config.c ++++ b/modules/ssl/ssl_engine_config.c +@@ -269,6 +269,7 @@ static void modssl_ctx_cfg_merge(apr_pool_t *p, + mrg->protocol_set = 1; + } + else { ++ mrg->protocol_set = base->protocol_set; + mrg->protocol = base->protocol; + } + +diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c +index 31062bc..70d151e 100644 +--- a/modules/ssl/ssl_engine_init.c ++++ b/modules/ssl/ssl_engine_init.c +@@ -520,7 +520,9 @@ static apr_status_t ssl_init_ctx_tls_extensions(server_rec *s, + "Configuring TLS extension handling"); + + /* +- * Server name indication (SNI) ++ * The Server Name Indication (SNI) provided by the ClientHello can be ++ * used to select the right (name-based-)vhost and its SSL configuration ++ * before the handshake takes place. + */ + if (!SSL_CTX_set_tlsext_servername_callback(mctx->ssl_ctx, + ssl_callback_ServerNameIndication) || +@@ -532,6 +534,16 @@ static apr_status_t ssl_init_ctx_tls_extensions(server_rec *s, + return ssl_die(s); + } + ++#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER) ++ /* ++ * The ClientHello callback also allows to retrieve the SNI, but since it ++ * runs at the earliest possible connection stage we can even set the TLS ++ * protocol version(s) according to the selected (name-based-)vhost, which ++ * is not possible at the SNI callback stage (due to OpenSSL internals). ++ */ ++ SSL_CTX_set_client_hello_cb(mctx->ssl_ctx, ssl_callback_ClientHello, NULL); ++#endif ++ + #ifdef HAVE_OCSP_STAPLING + /* + * OCSP Stapling support, status_request extension +@@ -708,7 +720,7 @@ static apr_status_t ssl_init_ctx_protocol(server_rec *s, + #else /* #if OPENSSL_VERSION_NUMBER < 0x10100000L */ + /* We first determine the maximum protocol version we should provide */ + #if SSL_HAVE_PROTOCOL_TLSV1_3 +- if (SSL_HAVE_PROTOCOL_TLSV1_3 && (protocol & SSL_PROTOCOL_TLSV1_3)) { ++ if (protocol & SSL_PROTOCOL_TLSV1_3) { + prot = TLS1_3_VERSION; + } else + #endif +diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c +index 8b44674..7313a55 100644 +--- a/modules/ssl/ssl_engine_kernel.c ++++ b/modules/ssl/ssl_engine_kernel.c +@@ -2357,28 +2357,31 @@ static apr_status_t set_challenge_creds(conn_rec *c, const char *servername, + * This function sets the virtual host from an extended + * client hello with a server name indication extension ("SNI", cf. RFC 6066). + */ +-static apr_status_t init_vhost(conn_rec *c, SSL *ssl) ++static apr_status_t init_vhost(conn_rec *c, SSL *ssl, const char *servername) + { +- const char *servername; + X509 *cert; + EVP_PKEY *key; + + if (c) { + SSLConnRec *sslcon = myConnConfig(c); +- +- if (sslcon->server != c->base_server) { +- /* already found the vhost */ +- return APR_SUCCESS; ++ ++ if (sslcon->vhost_found) { ++ /* already found the vhost? */ ++ return sslcon->vhost_found > 0 ? APR_SUCCESS : APR_NOTFOUND; + } ++ sslcon->vhost_found = -1; + +- servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); ++ if (!servername) { ++ servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); ++ } + if (servername) { + if (ap_vhost_iterate_given_conn(c, ssl_find_vhost, + (void *)servername)) { + ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(02043) + "SSL virtual host for servername %s found", + servername); +- ++ ++ sslcon->vhost_found = +1; + return APR_SUCCESS; + } + else if (ssl_is_challenge(c, servername, &cert, &key)) { +@@ -2428,11 +2431,72 @@ static apr_status_t init_vhost(conn_rec *c, SSL *ssl) + int ssl_callback_ServerNameIndication(SSL *ssl, int *al, modssl_ctx_t *mctx) + { + conn_rec *c = (conn_rec *)SSL_get_app_data(ssl); +- apr_status_t status = init_vhost(c, ssl); ++ apr_status_t status = init_vhost(c, ssl, NULL); + + return (status == APR_SUCCESS)? SSL_TLSEXT_ERR_OK : SSL_TLSEXT_ERR_NOACK; + } + ++#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER) ++/* ++ * This callback function is called when the ClientHello is received. ++ */ ++int ssl_callback_ClientHello(SSL *ssl, int *al, void *arg) ++{ ++ char *servername = NULL; ++ conn_rec *c = (conn_rec *)SSL_get_app_data(ssl); ++ const unsigned char *pos; ++ size_t len, remaining; ++ (void)arg; ++ ++ /* We can't use SSL_get_servername() at this earliest OpenSSL connection ++ * stage, and there is no SSL_client_hello_get0_servername() provided as ++ * of OpenSSL 1.1.1. So the code below, that extracts the SNI from the ++ * ClientHello's TLS extensions, is taken from some test code in OpenSSL, ++ * i.e. client_hello_select_server_ctx() in "test/handshake_helper.c". ++ */ ++ ++ /* ++ * The server_name extension was given too much extensibility when it ++ * was written, so parsing the normal case is a bit complex. ++ */ ++ if (!SSL_client_hello_get0_ext(ssl, TLSEXT_TYPE_server_name, &pos, ++ &remaining) ++ || remaining <= 2) ++ goto give_up; ++ ++ /* Extract the length of the supplied list of names. */ ++ len = (*(pos++) << 8); ++ len += *(pos++); ++ if (len + 2 != remaining) ++ goto give_up; ++ remaining = len; ++ ++ /* ++ * The list in practice only has a single element, so we only consider ++ * the first one. ++ */ ++ if (remaining <= 3 || *pos++ != TLSEXT_NAMETYPE_host_name) ++ goto give_up; ++ remaining--; ++ ++ /* Now we can finally pull out the byte array with the actual hostname. */ ++ len = (*(pos++) << 8); ++ len += *(pos++); ++ if (len + 2 != remaining) ++ goto give_up; ++ ++ /* Use the SNI to switch to the relevant vhost, should it differ from ++ * c->base_server. ++ */ ++ servername = apr_pstrmemdup(c->pool, (const char *)pos, len); ++ ++give_up: ++ init_vhost(c, ssl, servername); ++ return SSL_CLIENT_HELLO_SUCCESS; ++} ++#endif /* OPENSSL_VERSION_NUMBER < 0x10101000L */ ++ ++ + /* + * Find a (name-based) SSL virtual host where either the ServerName + * or one of the ServerAliases matches the supplied name (to be used +@@ -2452,12 +2516,25 @@ static int ssl_find_vhost(void *servername, conn_rec *c, server_rec *s) + if (found && (ssl = sslcon->ssl) && + (sc = mySrvConfig(s))) { + SSL_CTX *ctx = SSL_set_SSL_CTX(ssl, sc->server->ssl_ctx); ++ + /* + * SSL_set_SSL_CTX() only deals with the server cert, + * so we need to duplicate a few additional settings + * from the ctx by hand + */ + SSL_set_options(ssl, SSL_CTX_get_options(ctx)); ++#if OPENSSL_VERSION_NUMBER >= 0x10100000L \ ++ && (!defined(LIBRESSL_VERSION_NUMBER) \ ++ || LIBRESSL_VERSION_NUMBER >= 0x20800000L) ++ /* ++ * Don't switch the protocol if none is configured for this vhost, ++ * the default in this case is still the base server's SSLProtocol. ++ */ ++ if (myCtxConfig(sslcon, sc)->protocol_set) { ++ SSL_set_min_proto_version(ssl, SSL_CTX_get_min_proto_version(ctx)); ++ SSL_set_max_proto_version(ssl, SSL_CTX_get_max_proto_version(ctx)); ++ } ++#endif + if ((SSL_get_verify_mode(ssl) == SSL_VERIFY_NONE) || + (SSL_num_renegotiations(ssl) == 0)) { + /* +@@ -2654,7 +2731,7 @@ int ssl_callback_alpn_select(SSL *ssl, + * they callback the SNI. We need to make sure that we know which vhost + * we are dealing with so we respect the correct protocols. + */ +- init_vhost(c, ssl); ++ init_vhost(c, ssl, NULL); + + proposed = ap_select_protocol(c, NULL, sslconn->server, client_protos); + if (!proposed) { +diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h +index 8055200..f8a1db7 100644 +--- a/modules/ssl/ssl_private.h ++++ b/modules/ssl/ssl_private.h +@@ -563,6 +563,7 @@ typedef struct { + + const char *cipher_suite; /* cipher suite used in last reneg */ + int service_unavailable; /* thouugh we negotiate SSL, no requests will be served */ ++ int vhost_found; /* whether we found vhost from SNI already */ + } SSLConnRec; + + /* BIG FAT WARNING: SSLModConfigRec has unusual memory lifetime: it is +@@ -946,6 +947,9 @@ void ssl_callback_Info(const SSL *, int, int); + #ifdef HAVE_TLSEXT + int ssl_callback_ServerNameIndication(SSL *, int *, modssl_ctx_t *); + #endif ++#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER) ++int ssl_callback_ClientHello(SSL *, int *, void *); ++#endif + #ifdef HAVE_TLS_SESSION_TICKETS + int ssl_callback_SessionTicket(SSL *, unsigned char *, unsigned char *, + EVP_CIPHER_CTX *, HMAC_CTX *, int); diff --git a/httpd-2.4.37-r1877397.patch b/httpd-2.4.37-r1877397.patch new file mode 100644 index 0000000..93aeb2e --- /dev/null +++ b/httpd-2.4.37-r1877397.patch @@ -0,0 +1,249 @@ +diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c +index b286053..8b6c34f 100644 +--- a/modules/ssl/ssl_engine_init.c ++++ b/modules/ssl/ssl_engine_init.c +@@ -824,6 +824,13 @@ static apr_status_t ssl_init_ctx_protocol(server_rec *s, + SSL_CTX_set_keylog_callback(ctx, modssl_callback_keylog); + } + #endif ++ ++#ifdef SSL_OP_NO_RENEGOTIATION ++ /* For server-side SSL_CTX, disable renegotiation by default.. */ ++ if (!mctx->pkp) { ++ SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION); ++ } ++#endif + + return APR_SUCCESS; + } +@@ -845,6 +852,14 @@ static void ssl_init_ctx_session_cache(server_rec *s, + } + } + ++#ifdef SSL_OP_NO_RENEGOTIATION ++/* OpenSSL-level renegotiation protection. */ ++#define MODSSL_BLOCKS_RENEG (0) ++#else ++/* mod_ssl-level renegotiation protection. */ ++#define MODSSL_BLOCKS_RENEG (1) ++#endif ++ + static void ssl_init_ctx_callbacks(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, +@@ -854,7 +869,13 @@ static void ssl_init_ctx_callbacks(server_rec *s, + + SSL_CTX_set_tmp_dh_callback(ctx, ssl_callback_TmpDH); + +- SSL_CTX_set_info_callback(ctx, ssl_callback_Info); ++ /* The info callback is used for debug-level tracing. For OpenSSL ++ * versions where SSL_OP_NO_RENEGOTIATION is not available, the ++ * callback is also used to prevent use of client-initiated ++ * renegotiation. Enable it in either case. */ ++ if (APLOGdebug(s) || MODSSL_BLOCKS_RENEG) { ++ SSL_CTX_set_info_callback(ctx, ssl_callback_Info); ++ } + + #ifdef HAVE_TLS_ALPN + SSL_CTX_set_alpn_select_cb(ctx, ssl_callback_alpn_select, NULL); +diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c +index 836bfdb..0958135 100644 +--- a/modules/ssl/ssl_engine_io.c ++++ b/modules/ssl/ssl_engine_io.c +@@ -200,11 +200,13 @@ static int bio_filter_out_write(BIO *bio, const char *in, int inl) + apr_bucket *e; + int need_flush; + ++#ifndef SSL_OP_NO_RENEGOTIATION + /* Abort early if the client has initiated a renegotiation. */ + if (outctx->filter_ctx->config->reneg_state == RENEG_ABORT) { + outctx->rc = APR_ECONNABORTED; + return -1; + } ++#endif + + /* when handshaking we'll have a small number of bytes. + * max size SSL will pass us here is about 16k. +@@ -458,11 +460,13 @@ static int bio_filter_in_read(BIO *bio, char *in, int inlen) + if (!in) + return 0; + ++#ifndef SSL_OP_NO_RENEGOTIATION + /* Abort early if the client has initiated a renegotiation. */ + if (inctx->filter_ctx->config->reneg_state == RENEG_ABORT) { + inctx->rc = APR_ECONNABORTED; + return -1; + } ++#endif + + BIO_clear_retry_flags(bio); + +diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c +index e217b9d..21f701f 100644 +--- a/modules/ssl/ssl_engine_kernel.c ++++ b/modules/ssl/ssl_engine_kernel.c +@@ -992,7 +992,7 @@ static int ssl_hook_Access_classic(request_rec *r, SSLSrvConfigRec *sc, SSLDirCo + + /* Toggle the renegotiation state to allow the new + * handshake to proceed. */ +- sslconn->reneg_state = RENEG_ALLOW; ++ modssl_set_reneg_state(sslconn, RENEG_ALLOW); + + SSL_renegotiate(ssl); + SSL_do_handshake(ssl); +@@ -1019,7 +1019,7 @@ static int ssl_hook_Access_classic(request_rec *r, SSLSrvConfigRec *sc, SSLDirCo + */ + SSL_peek(ssl, peekbuf, 0); + +- sslconn->reneg_state = RENEG_REJECT; ++ modssl_set_reneg_state(sslconn, RENEG_REJECT); + + if (!SSL_is_init_finished(ssl)) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02261) +@@ -1078,7 +1078,7 @@ static int ssl_hook_Access_modern(request_rec *r, SSLSrvConfigRec *sc, SSLDirCon + (sc->server->auth.verify_mode != SSL_CVERIFY_UNSET)) { + int vmode_inplace, vmode_needed; + int change_vmode = FALSE; +- int old_state, n, rc; ++ int n, rc; + + vmode_inplace = SSL_get_verify_mode(ssl); + vmode_needed = SSL_VERIFY_NONE; +@@ -1180,8 +1180,6 @@ static int ssl_hook_Access_modern(request_rec *r, SSLSrvConfigRec *sc, SSLDirCon + return HTTP_FORBIDDEN; + } + +- old_state = sslconn->reneg_state; +- sslconn->reneg_state = RENEG_ALLOW; + modssl_set_app_data2(ssl, r); + + SSL_do_handshake(ssl); +@@ -1191,7 +1189,6 @@ static int ssl_hook_Access_modern(request_rec *r, SSLSrvConfigRec *sc, SSLDirCon + */ + SSL_peek(ssl, peekbuf, 0); + +- sslconn->reneg_state = old_state; + modssl_set_app_data2(ssl, NULL); + + /* +@@ -2271,8 +2268,8 @@ static void log_tracing_state(const SSL *ssl, conn_rec *c, + /* + * This callback function is executed while OpenSSL processes the SSL + * handshake and does SSL record layer stuff. It's used to trap +- * client-initiated renegotiations, and for dumping everything to the +- * log. ++ * client-initiated renegotiations (where SSL_OP_NO_RENEGOTIATION is ++ * not available), and for dumping everything to the log. + */ + void ssl_callback_Info(const SSL *ssl, int where, int rc) + { +@@ -2284,14 +2281,12 @@ void ssl_callback_Info(const SSL *ssl, int where, int rc) + return; + } + +- /* With TLS 1.3 this callback may be called multiple times on the first +- * negotiation, so the below logic to detect renegotiations can't work. +- * Fortunately renegotiations are forbidden starting with TLS 1.3, and +- * this is enforced by OpenSSL so there's nothing to be done here. +- */ +-#if SSL_HAVE_PROTOCOL_TLSV1_3 +- if (SSL_version(ssl) < TLS1_3_VERSION) +-#endif ++#ifndef SSL_OP_NO_RENEGOTIATION ++ /* With OpenSSL < 1.1.1 (implying TLS v1.2 or earlier), this ++ * callback is used to block client-initiated renegotiation. With ++ * TLSv1.3 it is unnecessary since renegotiation is forbidden at ++ * protocol level. Otherwise (TLSv1.2 with OpenSSL >=1.1.1), ++ * SSL_OP_NO_RENEGOTIATION is used to block renegotiation. */ + { + SSLConnRec *sslconn; + +@@ -2316,6 +2311,7 @@ void ssl_callback_Info(const SSL *ssl, int where, int rc) + sslconn->reneg_state = RENEG_REJECT; + } + } ++#endif + + s = mySrvFromConn(c); + if (s && APLOGdebug(s)) { +diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h +index 2514407..f4e5ac9 100644 +--- a/modules/ssl/ssl_private.h ++++ b/modules/ssl/ssl_private.h +@@ -508,6 +508,16 @@ typedef struct { + apr_time_t source_mtime; + } ssl_asn1_t; + ++typedef enum { ++ RENEG_INIT = 0, /* Before initial handshake */ ++ RENEG_REJECT, /* After initial handshake; any client-initiated ++ * renegotiation should be rejected */ ++ RENEG_ALLOW, /* A server-initiated renegotiation is taking ++ * place (as dictated by configuration) */ ++ RENEG_ABORT /* Renegotiation initiated by client, abort the ++ * connection */ ++} modssl_reneg_state; ++ + /** + * Define the mod_ssl per-module configuration structure + * (i.e. the global configuration for each httpd process) +@@ -540,18 +550,13 @@ typedef struct { + NON_SSL_SET_ERROR_MSG /* Need to set the error message */ + } non_ssl_request; + +- /* Track the handshake/renegotiation state for the connection so +- * that all client-initiated renegotiations can be rejected, as a +- * partial fix for CVE-2009-3555. */ +- enum { +- RENEG_INIT = 0, /* Before initial handshake */ +- RENEG_REJECT, /* After initial handshake; any client-initiated +- * renegotiation should be rejected */ +- RENEG_ALLOW, /* A server-initiated renegotiation is taking +- * place (as dictated by configuration) */ +- RENEG_ABORT /* Renegotiation initiated by client, abort the +- * connection */ +- } reneg_state; ++#ifndef SSL_OP_NO_RENEGOTIATION ++ /* For OpenSSL < 1.1.1, track the handshake/renegotiation state ++ * for the connection to block client-initiated renegotiations. ++ * For OpenSSL >=1.1.1, the SSL_OP_NO_RENEGOTIATION flag is used in ++ * the SSL * options state with equivalent effect. */ ++ modssl_reneg_state reneg_state; ++#endif + + server_rec *server; + SSLDirConfigRec *dc; +@@ -1130,6 +1135,9 @@ int ssl_is_challenge(conn_rec *c, const char *servername, + * the configured ENGINE. */ + int modssl_is_engine_id(const char *name); + ++/* Set the renegotation state for connection. */ ++void modssl_set_reneg_state(SSLConnRec *sslconn, modssl_reneg_state state); ++ + #endif /* SSL_PRIVATE_H */ + /** @} */ + +diff --git a/modules/ssl/ssl_util_ssl.c b/modules/ssl/ssl_util_ssl.c +index 4fa089b..3413d83 100644 +--- a/modules/ssl/ssl_util_ssl.c ++++ b/modules/ssl/ssl_util_ssl.c +@@ -504,3 +504,19 @@ char *modssl_SSL_SESSION_id2sz(IDCONST unsigned char *id, int idlen, + + return str; + } ++ ++void modssl_set_reneg_state(SSLConnRec *sslconn, modssl_reneg_state state) ++{ ++#ifdef SSL_OP_NO_RENEGOTIATION ++ switch (state) { ++ case RENEG_ALLOW: ++ SSL_clear_options(sslconn->ssl, SSL_OP_NO_RENEGOTIATION); ++ break; ++ default: ++ SSL_set_options(sslconn->ssl, SSL_OP_NO_RENEGOTIATION); ++ break; ++ } ++#else ++ sslconn->reneg_state = state; ++#endif ++} diff --git a/httpd-2.4.37-r1878280.patch b/httpd-2.4.37-r1878280.patch new file mode 100644 index 0000000..8393411 --- /dev/null +++ b/httpd-2.4.37-r1878280.patch @@ -0,0 +1,47 @@ +From ced24e032ebe185a2d885fa309d6de47668ba31e Mon Sep 17 00:00:00 2001 +From: Yann Ylavic +Date: Fri, 26 Jun 2020 10:21:19 +0000 +Subject: [PATCH] Merge r1878280 from trunk: + +mod_proxy_http: don't strip EOS when spooling request body to file. + +To prevent stream_reqbody() from sending the FILE and FLUSH bucket in separate +brigades, and thus apr_file_setaside() to trigger if network congestion occurs +with the backend, restore the EOS in spool_reqbody_cl() which was stripped +when spooling the request body to a file. + +Until APR r1878279 is released (and installed by users), apr_file_setaside() +on a temporary file (mktemp) will simply drop the file cleanup, leaking the +fd and inode.. + +This fixes BZ 64452. + + +Submitted by: ylavic +Reviewed by: ylavic, jorton, rpluem + + +git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1879226 13f79535-47bb-0310-9956-ffa450edef68 +--- + modules/proxy/mod_proxy_http.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c +index e94bf26d412..7a0f063f705 100644 +--- a/modules/proxy/mod_proxy_http.c ++++ b/modules/proxy/mod_proxy_http.c +@@ -548,6 +548,14 @@ static int spool_reqbody_cl(proxy_http_req_t *req, apr_off_t *bytes_spooled) + e = apr_bucket_immortal_create(CRLF_ASCII, 2, bucket_alloc); + APR_BRIGADE_INSERT_TAIL(input_brigade, e); + } ++ if (tmpfile) { ++ /* We dropped metadata buckets when spooling to tmpfile, ++ * terminate with EOS for stream_reqbody() to flush the ++ * whole in one go. ++ */ ++ e = apr_bucket_eos_create(bucket_alloc); ++ APR_BRIGADE_INSERT_TAIL(input_brigade, e); ++ } + return OK; + } + diff --git a/httpd-2.4.37-r1878890.patch b/httpd-2.4.37-r1878890.patch new file mode 100644 index 0000000..0dcc4b0 --- /dev/null +++ b/httpd-2.4.37-r1878890.patch @@ -0,0 +1,116 @@ +diff --git a/include/util_ldap.h b/include/util_ldap.h +index f7cd736..f401e79 100644 +--- a/include/util_ldap.h ++++ b/include/util_ldap.h +@@ -32,7 +32,6 @@ + #if APR_MAJOR_VERSION < 2 + /* The LDAP API is currently only present in APR 1.x */ + #include "apr_ldap.h" +-#include "apr_ldap_rebind.h" + #else + #define APR_HAS_LDAP 0 + #endif +diff --git a/modules/ldap/util_ldap.c b/modules/ldap/util_ldap.c +index 08f986c..eecb3f7 100644 +--- a/modules/ldap/util_ldap.c ++++ b/modules/ldap/util_ldap.c +@@ -140,6 +140,38 @@ static int util_ldap_handler(request_rec *r) + return OK; + } + ++/* For OpenLDAP with the 3-arg version of ldap_set_rebind_proc(), use ++ * a simpler rebind callback than the implementation in APR-util. ++ * Testing for API version >= 3001 appears safe although OpenLDAP ++ * 2.1.x (API version = 2004) also has the 3-arg API. */ ++#if APR_HAS_OPENLDAP_LDAPSDK && defined(LDAP_API_VERSION) && LDAP_API_VERSION >= 3001 ++ ++#define uldap_rebind_init(p) APR_SUCCESS /* noop */ ++ ++static int uldap_rebind_proc(LDAP *ld, const char *url, ber_tag_t request, ++ ber_int_t msgid, void *params) ++{ ++ util_ldap_connection_t *ldc = params; ++ ++ return ldap_bind_s(ld, ldc->binddn, ldc->bindpw, LDAP_AUTH_SIMPLE); ++} ++ ++static apr_status_t uldap_rebind_add(util_ldap_connection_t *ldc) ++{ ++ ldap_set_rebind_proc(ldc->ldap, uldap_rebind_proc, ldc); ++ return APR_SUCCESS; ++} ++ ++#else /* !APR_HAS_OPENLDAP_LDAPSDK */ ++ ++#define USE_APR_LDAP_REBIND ++#include ++ ++#define uldap_rebind_init(p) apr_ldap_rebind_init(p) ++#define uldap_rebind_add(ldc) apr_ldap_rebind_add((ldc)->rebind_pool, \ ++ (ldc)->ldap, (ldc)->binddn, \ ++ (ldc)->bindpw) ++#endif + + + /* ------------------------------------------------------------------ */ +@@ -181,6 +213,13 @@ static apr_status_t uldap_connection_unbind(void *param) + util_ldap_connection_t *ldc = param; + + if (ldc) { ++#ifdef USE_APR_LDAP_REBIND ++ /* forget the rebind info for this conn */ ++ if (ldc->ChaseReferrals == AP_LDAP_CHASEREFERRALS_ON) { ++ apr_pool_clear(ldc->rebind_pool); ++ } ++#endif ++ + if (ldc->ldap) { + if (ldc->r) { + ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, ldc->r, "LDC %pp unbind", ldc); +@@ -189,12 +228,6 @@ static apr_status_t uldap_connection_unbind(void *param) + ldc->ldap = NULL; + } + ldc->bound = 0; +- +- /* forget the rebind info for this conn */ +- if (ldc->ChaseReferrals == AP_LDAP_CHASEREFERRALS_ON) { +- apr_ldap_rebind_remove(ldc->ldap); +- apr_pool_clear(ldc->rebind_pool); +- } + } + + return APR_SUCCESS; +@@ -330,7 +363,7 @@ static int uldap_connection_init(request_rec *r, + + 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); ++ rc = uldap_rebind_add(ldc); + if (rc != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, rc, r->server, APLOGNO(01277) + "LDAP: Unable to add rebind cross reference entry. Out of memory?"); +@@ -855,6 +888,7 @@ static util_ldap_connection_t * + /* whether or not to keep this connection in the pool when it's returned */ + l->keep = (st->connection_pool_ttl == 0) ? 0 : 1; + ++#ifdef USE_APR_LDAP_REBIND + if (l->ChaseReferrals == AP_LDAP_CHASEREFERRALS_ON) { + if (apr_pool_create(&(l->rebind_pool), l->pool) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(01286) +@@ -865,6 +899,7 @@ static util_ldap_connection_t * + return NULL; + } + } ++#endif + + if (p) { + p->next = l; +@@ -3051,7 +3086,7 @@ static int util_ldap_post_config(apr_pool_t *p, apr_pool_t *plog, + } + + /* Initialize the rebind callback's cross reference list. */ +- apr_ldap_rebind_init (p); ++ (void) uldap_rebind_init(p); + + #ifdef AP_LDAP_OPT_DEBUG + if (st->debug_level > 0) { diff --git a/httpd-2.4.37-r1879224.patch b/httpd-2.4.37-r1879224.patch new file mode 100644 index 0000000..2566d8f --- /dev/null +++ b/httpd-2.4.37-r1879224.patch @@ -0,0 +1,13 @@ +diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c +index c217a0d..d07d0ba 100644 +--- a/modules/ssl/ssl_engine_kernel.c ++++ b/modules/ssl/ssl_engine_kernel.c +@@ -1947,7 +1947,7 @@ static void modssl_proxy_info_log(conn_rec *c, + *cert = info->x509; \ + CRYPTO_add(&(*cert)->references, +1, CRYPTO_LOCK_X509); \ + *pkey = info->x_pkey->dec_pkey; \ +- CRYPTO_add(&(*pkey)->references, +1, CRYPTO_LOCK_X509_PKEY) ++ CRYPTO_add(&(*pkey)->references, +1, CRYPTO_LOCK_EVP_PKEY) + #else + #define modssl_set_cert_info(info, cert, pkey) \ + *cert = info->x509; \ diff --git a/httpd-2.4.37-r1881459.patch b/httpd-2.4.37-r1881459.patch new file mode 100644 index 0000000..0f73c06 --- /dev/null +++ b/httpd-2.4.37-r1881459.patch @@ -0,0 +1,16 @@ +--- a/modules/generators/cgi_common.h 2020/09/04 13:16:53 1881458 ++++ b/modules/generators/cgi_common.h 2020/09/04 13:56:25 1881459 +@@ -259,6 +259,13 @@ + if ((ret = ap_scan_script_header_err_brigade_ex(r, bb, sbuf, + APLOG_MODULE_INDEX))) + { ++ /* In the case of a timeout reading script output, clear ++ * the brigade to avoid a second attempt to read the ++ * output. */ ++ if (ret == HTTP_GATEWAY_TIME_OUT) { ++ apr_brigade_cleanup(bb); ++ } ++ + ret = log_script(r, conf, ret, logdata, sbuf, bb, script_err); + + /* diff --git a/httpd-2.4.37-reply-two-tls-rec.patch b/httpd-2.4.37-reply-two-tls-rec.patch new file mode 100644 index 0000000..a4a3835 --- /dev/null +++ b/httpd-2.4.37-reply-two-tls-rec.patch @@ -0,0 +1,188 @@ +diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c +index 018b667..4e3875a 100644 +--- a/modules/ssl/ssl_engine_io.c ++++ b/modules/ssl/ssl_engine_io.c +@@ -1598,18 +1598,32 @@ static apr_status_t ssl_io_filter_input(ap_filter_t *f, + } + + +-/* ssl_io_filter_output() produces one SSL/TLS message per bucket ++/* ssl_io_filter_output() produces one SSL/TLS record per bucket + * passed down the output filter stack. This results in a high +- * overhead (network packets) for any output comprising many small +- * buckets. SSI page applied through the HTTP chunk filter, for +- * example, may produce many brigades containing small buckets - +- * [chunk-size CRLF] [chunk-data] [CRLF]. ++ * overhead (more network packets & TLS processing) for any output ++ * comprising many small buckets. SSI output passed through the HTTP ++ * chunk filter, for example, may produce many brigades containing ++ * small buckets - [chunk-size CRLF] [chunk-data] [CRLF]. + * +- * The coalescing filter merges many small buckets into larger buckets +- * where possible, allowing the SSL I/O output filter to handle them +- * more efficiently. */ ++ * Sending HTTP response headers as a separate TLS record to the ++ * response body also reveals information to a network observer (the ++ * size of headers) which can be significant. ++ * ++ * The coalescing filter merges data buckets with the aim of producing ++ * fewer, larger TLS records - without copying/buffering all content ++ * and introducing unnecessary overhead. ++ * ++ * ### This buffering could be probably be done more comprehensively ++ * ### in ssl_io_filter_output itself. ++ * ++ * ### Another possible performance optimisation in particular for the ++ * ### [HEAP] [FILE] HTTP response case is using a brigade rather than ++ * ### a char array to buffer; using apr_brigade_write() to append ++ * ### will use already-allocated memory from the HEAP, reducing # of ++ * ### copies. ++ */ + +-#define COALESCE_BYTES (2048) ++#define COALESCE_BYTES (AP_IOBUFSIZE) + + struct coalesce_ctx { + char buffer[COALESCE_BYTES]; +@@ -1622,11 +1636,12 @@ static apr_status_t ssl_io_filter_coalesce(ap_filter_t *f, + apr_bucket *e, *upto; + apr_size_t bytes = 0; + struct coalesce_ctx *ctx = f->ctx; ++ apr_size_t buffered = ctx ? ctx->bytes : 0; /* space used on entry */ + unsigned count = 0; + + /* The brigade consists of zero-or-more small data buckets which +- * can be coalesced (the prefix), followed by the remainder of the +- * brigade. ++ * can be coalesced (referred to as the "prefix"), followed by the ++ * remainder of the brigade. + * + * Find the last bucket - if any - of that prefix. count gives + * the number of buckets in the prefix. The "prefix" must contain +@@ -1641,24 +1656,97 @@ static apr_status_t ssl_io_filter_coalesce(ap_filter_t *f, + e != APR_BRIGADE_SENTINEL(bb) + && !APR_BUCKET_IS_METADATA(e) + && e->length != (apr_size_t)-1 +- && e->length < COALESCE_BYTES +- && (bytes + e->length) < COALESCE_BYTES +- && (ctx == NULL +- || bytes + ctx->bytes + e->length < COALESCE_BYTES); ++ && e->length <= COALESCE_BYTES ++ && (buffered + bytes + e->length) <= COALESCE_BYTES; + e = APR_BUCKET_NEXT(e)) { + if (e->length) count++; /* don't count zero-length buckets */ + bytes += e->length; + } ++ ++ /* If there is room remaining and the next bucket is a data ++ * bucket, try to include it in the prefix to coalesce. For a ++ * typical [HEAP] [FILE] HTTP response brigade, this handles ++ * merging the headers and the start of the body into a single TLS ++ * record. */ ++ if (bytes + buffered > 0 ++ && bytes + buffered < COALESCE_BYTES ++ && e != APR_BRIGADE_SENTINEL(bb) ++ && !APR_BUCKET_IS_METADATA(e)) { ++ apr_status_t rv = APR_SUCCESS; ++ ++ /* For an indeterminate length bucket (PIPE/CGI/...), try a ++ * non-blocking read to have it morph into a HEAP. If the ++ * read fails with EAGAIN, it is harmless to try a split ++ * anyway, split is ENOTIMPL for most PIPE-like buckets. */ ++ if (e->length == (apr_size_t)-1) { ++ const char *discard; ++ apr_size_t ignore; ++ ++ rv = apr_bucket_read(e, &discard, &ignore, APR_NONBLOCK_READ); ++ if (rv != APR_SUCCESS && !APR_STATUS_IS_EAGAIN(rv)) { ++ ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, f->c, APLOGNO(10232) ++ "coalesce failed to read from %s bucket", ++ e->type->name); ++ return AP_FILTER_ERROR; ++ } ++ } ++ ++ if (rv == APR_SUCCESS) { ++ /* If the read above made the bucket morph, it may now fit ++ * entirely within the buffer. Otherwise, split it so it does ++ * fit. */ ++ if (e->length > COALESCE_BYTES ++ || e->length + buffered + bytes > COALESCE_BYTES) { ++ rv = apr_bucket_split(e, COALESCE_BYTES - (buffered + bytes)); ++ } ++ ++ if (rv == APR_SUCCESS && e->length == 0) { ++ /* As above, don't count in the prefix if the bucket is ++ * now zero-length. */ ++ } ++ else if (rv == APR_SUCCESS) { ++ ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, f->c, ++ "coalesce: adding %" APR_SIZE_T_FMT " bytes " ++ "from split %s bucket, total %" APR_SIZE_T_FMT, ++ e->length, e->type->name, bytes + buffered); ++ ++ count++; ++ bytes += e->length; ++ e = APR_BUCKET_NEXT(e); ++ } ++ else if (rv != APR_ENOTIMPL) { ++ ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, f->c, APLOGNO(10233) ++ "coalesce: failed to split data bucket"); ++ return AP_FILTER_ERROR; ++ } ++ } ++ } ++ ++ /* The prefix is zero or more buckets. upto now points to the ++ * bucket AFTER the end of the prefix, which may be the brigade ++ * sentinel. */ + upto = e; + +- /* Coalesce the prefix, if: +- * a) more than one bucket is found to coalesce, or +- * b) the brigade contains only a single data bucket, or +- * c) the data bucket is not last but we have buffered data already. ++ /* Coalesce the prefix, if any of the following are true: ++ * ++ * a) the prefix is more than one bucket ++ * OR ++ * b) the prefix is the entire brigade, which is a single bucket ++ * AND the prefix length is smaller than the buffer size, ++ * OR ++ * c) the prefix is a single bucket ++ * AND there is buffered data from a previous pass. ++ * ++ * The aim with (b) is to buffer a small bucket so it can be ++ * coalesced with future invocations of this filter. e.g. three ++ * calls each with a single 100 byte HEAP bucket should get ++ * coalesced together. But an invocation with a 8192 byte HEAP ++ * should pass through untouched. + */ + if (bytes > 0 + && (count > 1 +- || (upto == APR_BRIGADE_SENTINEL(bb)) ++ || (upto == APR_BRIGADE_SENTINEL(bb) ++ && bytes < COALESCE_BYTES) + || (ctx && ctx->bytes > 0))) { + /* If coalescing some bytes, ensure a context has been + * created. */ +@@ -1669,7 +1757,8 @@ static apr_status_t ssl_io_filter_coalesce(ap_filter_t *f, + + ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, f->c, + "coalesce: have %" APR_SIZE_T_FMT " bytes, " +- "adding %" APR_SIZE_T_FMT " more", ctx->bytes, bytes); ++ "adding %" APR_SIZE_T_FMT " more (buckets=%u)", ++ ctx->bytes, bytes, count); + + /* Iterate through the prefix segment. For non-fatal errors + * in this loop it is safe to break out and fall back to the +@@ -1684,7 +1773,8 @@ static apr_status_t ssl_io_filter_coalesce(ap_filter_t *f, + if (APR_BUCKET_IS_METADATA(e) + || e->length == (apr_size_t)-1) { + ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, f->c, APLOGNO(02012) +- "unexpected bucket type during coalesce"); ++ "unexpected %s bucket during coalesce", ++ e->type->name); + break; /* non-fatal error; break out */ + } + diff --git a/httpd-2.4.37-session-expiry-updt-int.patch b/httpd-2.4.37-session-expiry-updt-int.patch new file mode 100644 index 0000000..8c5b852 --- /dev/null +++ b/httpd-2.4.37-session-expiry-updt-int.patch @@ -0,0 +1,194 @@ +diff --git a/docs/manual/mod/mod_session.html.en b/docs/manual/mod/mod_session.html.en +index 6834f8e..9f8301f 100644 +--- a/docs/manual/mod/mod_session.html.en ++++ b/docs/manual/mod/mod_session.html.en +@@ -82,6 +82,7 @@ +
  • SessionHeader
  • +
  • SessionInclude
  • +
  • SessionMaxAge
  • ++
  • SessionExpiryUpdateInterval
  • + +

    Bugfix checklist

    See also

    +
      +@@ -482,6 +483,37 @@ AuthName realm + +

      Setting the maxage to zero disables session expiry.

      + ++
    ++
    top
    ++

    SessionExpiryUpdateInterval Directive

    ++ ++ ++ ++ ++ ++ ++
    Description:Define the number of seconds a session's expiry may change without the session being updated
    Syntax:SessionExpiryUpdateInterval interval
    Default:SessionExpiryUpdateInterval 0 (always update)
    Context:server config, virtual host, directory, .htaccess
    Module:mod_session
    ++

    The SessionExpiryUpdateInterval directive allows ++ sessions to avoid the cost associated with writing the session each request ++ when only the expiry time has changed. This can be used to make a website ++ more efficient or reduce load on a database when using ++ mod_session_dbd. The session is always written if the data ++ stored in the session has changed or the expiry has changed by more than the ++ configured interval.

    ++ ++

    Setting the interval to zero disables this directive, and the session ++ expiry is refreshed for each request.

    ++ ++

    This directive only has an effect when combined with SessionMaxAge to enable session ++ expiry. Sessions without an expiry are only written when the data stored in ++ the session has changed.

    ++ ++

    Warning

    ++

    Because the session expiry may not be refreshed with each request, it's ++ possible for sessions to expire up to interval seconds early. ++ Using a small interval usually provides sufficient savings while having a ++ minimal effect on expiry resolution.

    ++ +
    + +
    +diff --git a/modules/session/mod_session.c b/modules/session/mod_session.c +index d517020..10e6396 100644 +--- a/modules/session/mod_session.c ++++ b/modules/session/mod_session.c +@@ -177,6 +177,7 @@ static apr_status_t ap_session_save(request_rec * r, session_rec * z) + { + if (z) { + apr_time_t now = apr_time_now(); ++ apr_time_t initialExpiry = z->expiry; + int rv = 0; + + session_dir_conf *dconf = ap_get_module_config(r->per_dir_config, +@@ -207,6 +208,17 @@ static apr_status_t ap_session_save(request_rec * r, session_rec * z) + z->expiry = now + z->maxage * APR_USEC_PER_SEC; + } + ++ /* don't save if the only change is the expiry by a small amount */ ++ if (!z->dirty && dconf->expiry_update_time ++ && (z->expiry - initialExpiry < dconf->expiry_update_time)) { ++ return APR_SUCCESS; ++ } ++ ++ /* also don't save sessions that didn't change at all */ ++ if (!z->dirty && !z->maxage) { ++ return APR_SUCCESS; ++ } ++ + /* encode the session */ + rv = ap_run_session_encode(r, z); + if (OK != rv) { +@@ -553,6 +565,10 @@ static void *merge_session_dir_config(apr_pool_t * p, void *basev, void *addv) + new->env_set = add->env_set || base->env_set; + new->includes = apr_array_append(p, base->includes, add->includes); + new->excludes = apr_array_append(p, base->excludes, add->excludes); ++ new->expiry_update_time = (add->expiry_update_set == 0) ++ ? base->expiry_update_time ++ : add->expiry_update_time; ++ new->expiry_update_set = add->expiry_update_set || base->expiry_update_set; + + return new; + } +@@ -622,6 +638,21 @@ static const char *add_session_exclude(cmd_parms * cmd, void *dconf, const char + return NULL; + } + ++static const char * ++ set_session_expiry_update(cmd_parms * parms, void *dconf, const char *arg) ++{ ++ session_dir_conf *conf = dconf; ++ ++ conf->expiry_update_time = atoi(arg); ++ if (conf->expiry_update_time < 0) { ++ return "SessionExpiryUpdateInterval must be positive or nul"; ++ } ++ conf->expiry_update_time = apr_time_from_sec(conf->expiry_update_time); ++ conf->expiry_update_set = 1; ++ ++ return NULL; ++} ++ + + static const command_rec session_cmds[] = + { +@@ -637,6 +668,9 @@ static const command_rec session_cmds[] = + "URL prefixes to include in the session. Defaults to all URLs"), + AP_INIT_TAKE1("SessionExclude", add_session_exclude, NULL, RSRC_CONF|OR_AUTHCFG, + "URL prefixes to exclude from the session. Defaults to no URLs"), ++ AP_INIT_TAKE1("SessionExpiryUpdateInterval", set_session_expiry_update, NULL, RSRC_CONF|OR_AUTHCFG, ++ "time interval for which a session's expiry time may change " ++ "without having to be rewritten. Zero to disable"), + {NULL} + }; + +diff --git a/modules/session/mod_session.h b/modules/session/mod_session.h +index a6dd5e9..bdeb532 100644 +--- a/modules/session/mod_session.h ++++ b/modules/session/mod_session.h +@@ -115,6 +115,9 @@ typedef struct { + * URLs included if empty */ + apr_array_header_t *excludes; /* URL prefixes to be excluded. No + * URLs excluded if empty */ ++ apr_time_t expiry_update_time; /* seconds the session expiry may change and ++ * not have to be rewritten */ ++ int expiry_update_set; + } session_dir_conf; + + /** +diff --git a/modules/session/mod_session_cookie.c b/modules/session/mod_session_cookie.c +index 6a02322..4aa75e4 100644 +--- a/modules/session/mod_session_cookie.c ++++ b/modules/session/mod_session_cookie.c +@@ -60,9 +60,6 @@ static apr_status_t session_cookie_save(request_rec * r, session_rec * z) + session_cookie_dir_conf *conf = ap_get_module_config(r->per_dir_config, + &session_cookie_module); + +- /* don't cache auth protected pages */ +- apr_table_addn(r->headers_out, "Cache-Control", "no-cache"); +- + /* create RFC2109 compliant cookie */ + if (conf->name_set) { + if (z->encoded && z->encoded[0]) { +@@ -162,6 +159,9 @@ static apr_status_t session_cookie_load(request_rec * r, session_rec ** z) + /* put the session in the notes so we don't have to parse it again */ + apr_table_setn(m->notes, note, (char *)zz); + ++ /* don't cache auth protected pages */ ++ apr_table_addn(r->headers_out, "Cache-Control", "no-cache, private"); ++ + return OK; + + } +diff --git a/modules/session/mod_session_dbd.c b/modules/session/mod_session_dbd.c +index 0be7306..f683da2 100644 +--- a/modules/session/mod_session_dbd.c ++++ b/modules/session/mod_session_dbd.c +@@ -245,6 +245,9 @@ static apr_status_t session_dbd_load(request_rec * r, session_rec ** z) + /* put the session in the notes so we don't have to parse it again */ + apr_table_setn(m->notes, note, (char *)zz); + ++ /* don't cache pages with a session */ ++ apr_table_addn(r->headers_out, "Cache-Control", "no-cache, private"); ++ + return OK; + + } +@@ -409,9 +412,6 @@ static apr_status_t session_dbd_save(request_rec * r, session_rec * z) + if (conf->name_set || conf->name2_set) { + char *oldkey = NULL, *newkey = NULL; + +- /* don't cache pages with a session */ +- apr_table_addn(r->headers_out, "Cache-Control", "no-cache"); +- + /* if the session is new or changed, make a new session ID */ + if (z->uuid) { + oldkey = apr_pcalloc(r->pool, APR_UUID_FORMATTED_LENGTH + 1); +@@ -458,7 +458,7 @@ static apr_status_t session_dbd_save(request_rec * r, session_rec * z) + else if (conf->peruser) { + + /* don't cache pages with a session */ +- apr_table_addn(r->headers_out, "Cache-Control", "no-cache"); ++ apr_table_addn(r->headers_out, "Cache-Control", "no-cache, private"); + + if (r->user) { + ret = dbd_save(r, r->user, r->user, z->encoded, z->expiry); diff --git a/httpd-2.4.37-ssl-proxy-chains.patch b/httpd-2.4.37-ssl-proxy-chains.patch new file mode 100644 index 0000000..e7ec218 --- /dev/null +++ b/httpd-2.4.37-ssl-proxy-chains.patch @@ -0,0 +1,101 @@ +diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c +index 8b6c34f..3587fb5 100644 +--- a/modules/ssl/ssl_engine_init.c ++++ b/modules/ssl/ssl_engine_init.c +@@ -1609,6 +1609,10 @@ static apr_status_t ssl_init_proxy_certs(server_rec *s, + STACK_OF(X509) *chain; + X509_STORE_CTX *sctx; + X509_STORE *store = SSL_CTX_get_cert_store(mctx->ssl_ctx); ++ int addl_chain = 0; /* non-zero if additional chain certs were ++ * added to store */ ++ ++ ap_assert(store != NULL); /* safe to assume always non-NULL? */ + + #if OPENSSL_VERSION_NUMBER >= 0x1010100fL + /* For OpenSSL >=1.1.1, turn on client cert support which is +@@ -1653,20 +1657,28 @@ static apr_status_t ssl_init_proxy_certs(server_rec *s, + } + } + +- if ((ncerts = sk_X509_INFO_num(sk)) <= 0) { +- sk_X509_INFO_free(sk); +- ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(02206) +- "no client certs found for SSL proxy"); +- return APR_SUCCESS; +- } +- + /* Check that all client certs have got certificates and private +- * keys. */ +- for (n = 0; n < ncerts; n++) { ++ * keys. Note the number of certs in the stack may decrease ++ * during the loop. */ ++ for (n = 0; n < sk_X509_INFO_num(sk); n++) { + X509_INFO *inf = sk_X509_INFO_value(sk, n); ++ int has_privkey = inf->x_pkey && inf->x_pkey->dec_pkey; ++ ++ /* For a lone certificate in the file, trust it as a ++ * CA/intermediate certificate. */ ++ if (inf->x509 && !has_privkey && !inf->enc_data) { ++ ssl_log_xerror(SSLLOG_MARK, APLOG_DEBUG, 0, ptemp, s, inf->x509, ++ APLOGNO(10261) "Trusting non-leaf certificate"); ++ X509_STORE_add_cert(store, inf->x509); /* increments inf->x509 */ ++ /* Delete from the stack and iterate again. */ ++ X509_INFO_free(inf); ++ sk_X509_INFO_delete(sk, n); ++ n--; ++ addl_chain = 1; ++ continue; ++ } + +- if (!inf->x509 || !inf->x_pkey || !inf->x_pkey->dec_pkey || +- inf->enc_data) { ++ if (!has_privkey || inf->enc_data) { + sk_X509_INFO_free(sk); + ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, APLOGNO(02252) + "incomplete client cert configured for SSL proxy " +@@ -1683,13 +1695,21 @@ static apr_status_t ssl_init_proxy_certs(server_rec *s, + } + } + ++ if ((ncerts = sk_X509_INFO_num(sk)) <= 0) { ++ sk_X509_INFO_free(sk); ++ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(02206) ++ "no client certs found for SSL proxy"); ++ return APR_SUCCESS; ++ } ++ + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02207) + "loaded %d client certs for SSL proxy", + ncerts); + pkp->certs = sk; + +- +- if (!pkp->ca_cert_file || !store) { ++ /* If any chain certs are configured, build the ->ca_certs chains ++ * corresponding to the loaded keypairs. */ ++ if (!pkp->ca_cert_file && !addl_chain) { + return APR_SUCCESS; + } + +diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h +index 2a08d1c..8055200 100644 +--- a/modules/ssl/ssl_private.h ++++ b/modules/ssl/ssl_private.h +@@ -655,10 +655,13 @@ typedef struct { + const char *cert_file; + const char *cert_path; + const char *ca_cert_file; +- STACK_OF(X509_INFO) *certs; /* Contains End Entity certs */ +- STACK_OF(X509) **ca_certs; /* Contains ONLY chain certs for +- * each item in certs. +- * (ptr to array of ptrs) */ ++ /* certs is a stack of configured cert, key pairs. */ ++ STACK_OF(X509_INFO) *certs; ++ /* ca_certs contains ONLY chain certs for each item in certs. ++ * ca_certs[n] is a pointer to the (STACK_OF(X509) *) stack which ++ * holds the cert chain for the 'n'th cert in the certs stack, or ++ * NULL if no chain is configured. */ ++ STACK_OF(X509) **ca_certs; + } modssl_pk_proxy_t; + + /** stuff related to authentication that can also be per-dir */ diff --git a/httpd-2.4.37-sslkeylogfile-support.patch b/httpd-2.4.37-sslkeylogfile-support.patch new file mode 100644 index 0000000..9d4cc19 --- /dev/null +++ b/httpd-2.4.37-sslkeylogfile-support.patch @@ -0,0 +1,123 @@ +diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c +index 1d201d9..0c4bf1f 100644 +--- a/modules/ssl/ssl_engine_config.c ++++ b/modules/ssl/ssl_engine_config.c +@@ -75,6 +75,10 @@ SSLModConfigRec *ssl_config_global_create(server_rec *s) + mc->stapling_refresh_mutex = NULL; + #endif + ++#ifdef HAVE_OPENSSL_KEYLOG ++ mc->keylog_file = NULL; ++#endif ++ + apr_pool_userdata_set(mc, SSL_MOD_CONFIG_KEY, + apr_pool_cleanup_null, + pool); +diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c +index ef631c1..b286053 100644 +--- a/modules/ssl/ssl_engine_init.c ++++ b/modules/ssl/ssl_engine_init.c +@@ -437,6 +437,28 @@ apr_status_t ssl_init_Module(apr_pool_t *p, apr_pool_t *plog, + init_bio_methods(); + #endif + ++#ifdef HAVE_OPENSSL_KEYLOG ++ { ++ const char *logfn = getenv("SSLKEYLOGFILE"); ++ ++ if (logfn) { ++ rv = apr_file_open(&mc->keylog_file, logfn, ++ APR_FOPEN_CREATE|APR_FOPEN_WRITE|APR_FOPEN_APPEND|APR_FOPEN_LARGEFILE, ++ APR_FPROT_UREAD|APR_FPROT_UWRITE, ++ mc->pPool); ++ if (rv) { ++ ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, s, APLOGNO(10226) ++ "Could not open log file '%s' configured via SSLKEYLOGFILE", ++ logfn); ++ return rv; ++ } ++ ++ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, APLOGNO(10227) ++ "Init: Logging SSL private key material to %s", logfn); ++ } ++ } ++#endif ++ + return OK; + } + +@@ -796,6 +818,12 @@ static apr_status_t ssl_init_ctx_protocol(server_rec *s, + * https://github.com/openssl/openssl/issues/7178 */ + SSL_CTX_clear_mode(ctx, SSL_MODE_AUTO_RETRY); + #endif ++ ++#ifdef HAVE_OPENSSL_KEYLOG ++ if (mctx->sc->mc->keylog_file) { ++ SSL_CTX_set_keylog_callback(ctx, modssl_callback_keylog); ++ } ++#endif + + return APR_SUCCESS; + } +diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c +index 6611610..7058865 100644 +--- a/modules/ssl/ssl_engine_kernel.c ++++ b/modules/ssl/ssl_engine_kernel.c +@@ -2719,3 +2719,17 @@ int ssl_callback_SRPServerParams(SSL *ssl, int *ad, void *arg) + } + + #endif /* HAVE_SRP */ ++ ++ ++#ifdef HAVE_OPENSSL_KEYLOG ++/* Callback used with SSL_CTX_set_keylog_callback. */ ++void modssl_callback_keylog(const SSL *ssl, const char *line) ++{ ++ conn_rec *conn = SSL_get_app_data(ssl); ++ SSLSrvConfigRec *sc = mySrvConfig(conn->base_server); ++ ++ if (sc && sc->mc->keylog_file) { ++ apr_file_printf(sc->mc->keylog_file, "%s\n", line); ++ } ++} ++#endif +diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h +index 0fac5d1..2514407 100644 +--- a/modules/ssl/ssl_private.h ++++ b/modules/ssl/ssl_private.h +@@ -250,6 +250,10 @@ void free_bio_methods(void); + #endif + #endif + ++#if OPENSSL_VERSION_NUMBER >= 0x10101000L && !defined(LIBRESSL_VERSION_NUMBER) ++#define HAVE_OPENSSL_KEYLOG ++#endif ++ + /* mod_ssl headers */ + #include "ssl_util_ssl.h" + +@@ -617,6 +621,12 @@ typedef struct { + apr_global_mutex_t *stapling_cache_mutex; + apr_global_mutex_t *stapling_refresh_mutex; + #endif ++ ++#ifdef HAVE_OPENSSL_KEYLOG ++ /* Used for logging if SSLKEYLOGFILE is set at startup. */ ++ apr_file_t *keylog_file; ++#endif ++ + } SSLModConfigRec; + + /** Structure representing configured filenames for certs and keys for +@@ -970,6 +980,11 @@ int ssl_stapling_init_cert(server_rec *, apr_pool_t *, apr_pool_t *, + int ssl_callback_SRPServerParams(SSL *, int *, void *); + #endif + ++#ifdef HAVE_OPENSSL_KEYLOG ++/* Callback used with SSL_CTX_set_keylog_callback. */ ++void modssl_callback_keylog(const SSL *ssl, const char *line); ++#endif ++ + /** I/O */ + void ssl_io_filter_init(conn_rec *, request_rec *r, SSL *); + void ssl_io_filter_register(apr_pool_t *); diff --git a/httpd-2.4.37-sslprotdefault.patch b/httpd-2.4.37-sslprotdefault.patch new file mode 100644 index 0000000..546fa1f --- /dev/null +++ b/httpd-2.4.37-sslprotdefault.patch @@ -0,0 +1,98 @@ +diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c +index 55c237e..5467d23 100644 +--- a/modules/ssl/ssl_engine_config.c ++++ b/modules/ssl/ssl_engine_config.c +@@ -119,7 +119,7 @@ static void modssl_ctx_init(modssl_ctx_t *mctx, apr_pool_t *p) + mctx->ticket_key = NULL; + #endif + +- mctx->protocol = SSL_PROTOCOL_DEFAULT; ++ mctx->protocol = SSL_PROTOCOL_NONE; + mctx->protocol_set = 0; + + mctx->pphrase_dialog_type = SSL_PPTYPE_UNSET; +@@ -262,6 +262,7 @@ static void modssl_ctx_cfg_merge(apr_pool_t *p, + { + if (add->protocol_set) { + mrg->protocol = add->protocol; ++ mrg->protocol_set = 1; + } + else { + mrg->protocol = base->protocol; +diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c +index e3f62fe..31fc0e6 100644 +--- a/modules/ssl/ssl_engine_init.c ++++ b/modules/ssl/ssl_engine_init.c +@@ -568,6 +568,7 @@ static apr_status_t ssl_init_ctx_protocol(server_rec *s, + MODSSL_SSL_METHOD_CONST SSL_METHOD *method = NULL; + char *cp; + int protocol = mctx->protocol; ++ int protocol_set = mctx->protocol_set; + SSLSrvConfigRec *sc = mySrvConfig(s); + #if OPENSSL_VERSION_NUMBER >= 0x10100000L + int prot; +@@ -577,12 +578,18 @@ static apr_status_t ssl_init_ctx_protocol(server_rec *s, + * Create the new per-server SSL context + */ + if (protocol == SSL_PROTOCOL_NONE) { +- ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02231) +- "No SSL protocols available [hint: SSLProtocol]"); +- return ssl_die(s); +- } ++ if (protocol_set) { ++ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02231) ++ "No SSL protocols available [hint: SSLProtocol]"); ++ return ssl_die(s); ++ } + +- cp = apr_pstrcat(p, ++ ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, s, ++ "Using OpenSSL/system default SSL/TLS protocols"); ++ cp = "default"; ++ } ++ else { ++ cp = apr_pstrcat(p, + #ifndef OPENSSL_NO_SSL3 + (protocol & SSL_PROTOCOL_SSLV3 ? "SSLv3, " : ""), + #endif +@@ -595,7 +602,8 @@ static apr_status_t ssl_init_ctx_protocol(server_rec *s, + #endif + #endif + NULL); +- cp[strlen(cp)-2] = NUL; ++ cp[strlen(cp)-2] = NUL; ++ } + + ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, s, + "Creating new SSL context (protocols: %s)", cp); +@@ -696,13 +704,15 @@ static apr_status_t ssl_init_ctx_protocol(server_rec *s, + prot = SSL3_VERSION; + #endif + } else { +- SSL_CTX_free(ctx); +- mctx->ssl_ctx = NULL; +- ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(03378) +- "No SSL protocols available [hint: SSLProtocol]"); +- return ssl_die(s); ++ if (protocol_set) { ++ SSL_CTX_free(ctx); ++ mctx->ssl_ctx = NULL; ++ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(03378) ++ "No SSL protocols available [hint: SSLProtocol]"); ++ return ssl_die(s); ++ } + } +- SSL_CTX_set_max_proto_version(ctx, prot); ++ if (protocol != SSL_PROTOCOL_NONE) SSL_CTX_set_max_proto_version(ctx, prot); + + /* Next we scan for the minimal protocol version we should provide, + * but we do not allow holes between max and min */ +@@ -726,7 +736,7 @@ static apr_status_t ssl_init_ctx_protocol(server_rec *s, + prot = SSL3_VERSION; + } + #endif +- SSL_CTX_set_min_proto_version(ctx, prot); ++ if (protocol != SSL_PROTOCOL_NONE) SSL_CTX_set_min_proto_version(ctx, prot); + #endif /* if OPENSSL_VERSION_NUMBER < 0x10100000L */ + + #ifdef SSL_OP_CIPHER_SERVER_PREFERENCE diff --git a/httpd-2.4.37-usertrack-samesite.patch b/httpd-2.4.37-usertrack-samesite.patch new file mode 100644 index 0000000..592616e --- /dev/null +++ b/httpd-2.4.37-usertrack-samesite.patch @@ -0,0 +1,178 @@ +diff --git a/docs/manual/mod/mod_usertrack.html.en b/docs/manual/mod/mod_usertrack.html.en +index b212747..d2da9b9 100644 +--- a/docs/manual/mod/mod_usertrack.html.en ++++ b/docs/manual/mod/mod_usertrack.html.en +@@ -47,7 +47,10 @@ + +@@ -127,6 +130,22 @@ CustomLog "logs/clickstream.log" usertrack +
    CookieExpires "3 weeks"
    + + ++
    ++
    top
    ++

    CookieHTTPOnly Directive

    ++ ++ ++ ++ ++ ++ ++ ++ ++
    Description:Adds the 'HTTPOnly' attribute to the cookie
    Syntax:CookieHTTPOnly on|off
    Default:CookieHTTPOnly off
    Context:server config, virtual host, directory, .htaccess
    Override:FileInfo
    Status:Extension
    Module:mod_usertrack
    ++

    When set to 'ON', the 'HTTPOnly' cookie attribute is added to this ++ modules tracking cookie. This attribute instructs browsers to block javascript ++ from reading the value of the cookie.

    ++ +
    +
    top
    +

    CookieName Directive

    +@@ -150,6 +169,45 @@ CustomLog "logs/clickstream.log" usertrack +
    CookieName clicktrack
    + + ++
    ++
    top
    ++

    CookieSameSite Directive

    ++ ++ ++ ++ ++ ++ ++ ++ ++
    Description:Adds the 'SameSite' attribute to the cookie
    Syntax:CookieSameSite None|Lax|Strict
    Default:unset
    Context:server config, virtual host, directory, .htaccess
    Override:FileInfo
    Status:Extension
    Module:mod_usertrack
    ++

    When set to 'None', 'Lax', or 'Strict', the 'SameSite' cookie attribute ++ is added to this modules tracking cookie with the corresponding value. ++ This attribute instructs browser on how to treat the cookie when it is ++ requested in a cross-site context.

    ++ ++
    ++

    A value of 'None' sets 'SameSite=None', which is the most liberal setting. To ++ omit this attribute, omit the directive entirely.

    ++
    ++ ++ ++
    ++
    top
    ++

    CookieSecure Directive

    ++ ++ ++ ++ ++ ++ ++ ++ ++
    Description:Adds the 'Secure' attribute to the cookie
    Syntax:CookieSecure on|off
    Default:CookieSecure off
    Context:server config, virtual host, directory, .htaccess
    Override:FileInfo
    Status:Extension
    Module:mod_usertrack
    ++

    When set to 'ON', the 'Secure' cookie attribute is added to this ++ modules tracking cookie. This attribute instructs browsers to only ++ transmit the cookie over HTTPS.

    ++ +
    +
    top
    +

    CookieStyle Directive

    +diff --git a/modules/metadata/mod_usertrack.c b/modules/metadata/mod_usertrack.c +index 73a9f45..65759c2 100644 +--- a/modules/metadata/mod_usertrack.c ++++ b/modules/metadata/mod_usertrack.c +@@ -86,6 +86,9 @@ typedef struct { + const char *cookie_domain; + char *regexp_string; /* used to compile regexp; save for debugging */ + ap_regex_t *regexp; /* used to find usertrack cookie in cookie header */ ++ int is_secure; ++ int is_httponly; ++ const char *samesite; + } cookie_dir_rec; + + /* Make Cookie: Now we have to generate something that is going to be +@@ -143,6 +146,21 @@ static void make_cookie(request_rec *r) + : ""), + NULL); + } ++ if (dcfg->samesite != NULL) { ++ new_cookie = apr_pstrcat(r->pool, new_cookie, "; ", ++ dcfg->samesite, ++ NULL); ++ } ++ if (dcfg->is_secure) { ++ new_cookie = apr_pstrcat(r->pool, new_cookie, "; Secure", ++ NULL); ++ } ++ if (dcfg->is_httponly) { ++ new_cookie = apr_pstrcat(r->pool, new_cookie, "; HttpOnly", ++ NULL); ++ } ++ ++ + + apr_table_addn(r->err_headers_out, + (dcfg->style == CT_COOKIE2 ? "Set-Cookie2" : "Set-Cookie"), +@@ -269,6 +287,7 @@ static void *make_cookie_dir(apr_pool_t *p, char *d) + dcfg->cookie_domain = NULL; + dcfg->style = CT_UNSET; + dcfg->enabled = 0; ++ /* calloc'ed to disabled: samesite, is_secure, is_httponly */ + + /* In case the user does not use the CookieName directive, + * we need to compile the regexp for the default cookie name. */ +@@ -429,6 +448,31 @@ static const char *set_cookie_style(cmd_parms *cmd, void *mconfig, + return NULL; + } + ++/* ++ * SameSite enabled disabled ++ */ ++ ++static const char *set_samesite_value(cmd_parms *cmd, void *mconfig, ++ const char *name) ++{ ++ cookie_dir_rec *dcfg; ++ ++ dcfg = (cookie_dir_rec *) mconfig; ++ ++ if (strcasecmp(name, "strict") == 0) { ++ dcfg->samesite = "SameSite=Strict"; ++ } else if (strcasecmp(name, "lax") == 0) { ++ dcfg->samesite = "SameSite=Lax"; ++ } else if (strcasecmp(name, "none") == 0) { ++ dcfg->samesite = "SameSite=None"; ++ } else { ++ return "CookieSameSite accepts 'Strict', 'Lax', or 'None'"; ++ } ++ ++ ++ return NULL; ++} ++ + static const command_rec cookie_log_cmds[] = { + AP_INIT_TAKE1("CookieExpires", set_cookie_exp, NULL, OR_FILEINFO, + "an expiry date code"), +@@ -440,6 +484,17 @@ static const command_rec cookie_log_cmds[] = { + "whether or not to enable cookies"), + AP_INIT_TAKE1("CookieName", set_cookie_name, NULL, OR_FILEINFO, + "name of the tracking cookie"), ++ AP_INIT_FLAG("CookieTracking", set_cookie_enable, NULL, OR_FILEINFO, ++ "whether or not to enable cookies"), ++ AP_INIT_TAKE1("CookieSameSite", set_samesite_value, NULL, OR_FILEINFO, ++ "SameSite setting"), ++ AP_INIT_FLAG("CookieSecure", ap_set_flag_slot, ++ (void *)APR_OFFSETOF(cookie_dir_rec, is_secure), OR_FILEINFO, ++ "is cookie secure"), ++ AP_INIT_FLAG("CookieHttpOnly", ap_set_flag_slot, ++ (void *)APR_OFFSETOF(cookie_dir_rec, is_httponly),OR_FILEINFO, ++ "is cookie http only"), ++ + {NULL} + }; + diff --git a/httpd-2.4.43-apxs.patch b/httpd-2.4.43-apxs.patch new file mode 100644 index 0000000..b1185b2 --- /dev/null +++ b/httpd-2.4.43-apxs.patch @@ -0,0 +1,58 @@ +diff --git a/support/apxs.in b/support/apxs.in +index b2705fa..c331631 100644 +--- a/support/apxs.in ++++ b/support/apxs.in +@@ -35,7 +35,18 @@ if ($ddi >= 0) { + + 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($destdir . "$installbuilddir/config_vars.mk",\%config_vars); + + # read the configuration variables once +@@ -285,7 +296,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); + +@@ -463,11 +474,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); + } + +@@ -682,8 +693,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 + APACHECTL=apachectl diff --git a/httpd-2.4.43-cachehardmax.patch b/httpd-2.4.43-cachehardmax.patch new file mode 100644 index 0000000..755f822 --- /dev/null +++ b/httpd-2.4.43-cachehardmax.patch @@ -0,0 +1,82 @@ +diff --git a/modules/cache/cache_util.h b/modules/cache/cache_util.h +index 6b92151..4c42a8e 100644 +--- a/modules/cache/cache_util.h ++++ b/modules/cache/cache_util.h +@@ -195,6 +195,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 3b9aa4f..8268503 100644 +--- a/modules/cache/mod_cache.c ++++ b/modules/cache/mod_cache.c +@@ -1455,6 +1455,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. */ +@@ -1954,7 +1959,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; + } + +@@ -2004,7 +2011,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; + } + +@@ -2332,12 +2342,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; + } + +@@ -2545,7 +2561,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/httpd-2.4.43-corelimit.patch b/httpd-2.4.43-corelimit.patch new file mode 100644 index 0000000..dd4b874 --- /dev/null +++ b/httpd-2.4.43-corelimit.patch @@ -0,0 +1,30 @@ +diff --git a/server/core.c b/server/core.c +index 79b2a82..dc0f17a 100644 +--- a/server/core.c ++++ b/server/core.c +@@ -4996,6 +4996,25 @@ static int core_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *pte + } + 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/httpd-2.4.43-deplibs.patch b/httpd-2.4.43-deplibs.patch new file mode 100644 index 0000000..c60f5a5 --- /dev/null +++ b/httpd-2.4.43-deplibs.patch @@ -0,0 +1,16 @@ +diff --git a/configure.in b/configure.in +index f8f9442..f276550 100644 +--- a/configure.in ++++ b/configure.in +@@ -786,9 +786,9 @@ 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 --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/httpd-2.4.43-enable-sslv3.patch b/httpd-2.4.43-enable-sslv3.patch new file mode 100644 index 0000000..2861605 --- /dev/null +++ b/httpd-2.4.43-enable-sslv3.patch @@ -0,0 +1,62 @@ +diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c +index 979489c..3d6443b 100644 +--- a/modules/ssl/ssl_engine_config.c ++++ b/modules/ssl/ssl_engine_config.c +@@ -1485,6 +1485,10 @@ static const char *ssl_cmd_protocol_parse(cmd_parms *parms, + #endif + else if (strcEQ(w, "all")) { + thisopt = SSL_PROTOCOL_ALL; ++#ifndef OPENSSL_NO_SSL3 ++ /* by default, ALL kw doesn't turn on SSLv3 */ ++ thisopt &= ~SSL_PROTOCOL_SSLV3; ++#endif + } + else { + return apr_pstrcat(parms->temp_pool, +diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c +index b0fcf81..ab6f263 100644 +--- a/modules/ssl/ssl_engine_init.c ++++ b/modules/ssl/ssl_engine_init.c +@@ -568,6 +568,28 @@ static apr_status_t ssl_init_ctx_tls_extensions(server_rec *s, + } + #endif + ++/* ++ * Enable/disable SSLProtocol. If the mod_ssl enables protocol ++ * which is disabled by default by OpenSSL, show a warning. ++ * "option" is for example SSL_OP_NO_SSLv3. ++ */ ++static void ssl_set_ctx_protocol_option(server_rec *s, ++ SSL_CTX *ctx, ++ long option, ++ int enabled, ++ const char *name) ++{ ++ if (!enabled) { ++ SSL_CTX_set_options(ctx, option); ++ } ++ else if (SSL_CTX_get_options(ctx) & option) { ++ SSL_CTX_clear_options(ctx, option); ++ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(02904) ++ "Allowing SSLProtocol %s even though it is disabled " ++ "by OpenSSL by default on this system", name); ++ } ++} ++ + static apr_status_t ssl_init_ctx_protocol(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, +@@ -735,9 +757,13 @@ static apr_status_t ssl_init_ctx_protocol(server_rec *s, + } + if (prot == TLS1_1_VERSION && protocol & SSL_PROTOCOL_TLSV1) { + prot = TLS1_VERSION; ++ ssl_set_ctx_protocol_option(s, ctx, SSL_OP_NO_TLSv1, ++ protocol & SSL_PROTOCOL_TLSV1, "TLSv1"); + } + #ifndef OPENSSL_NO_SSL3 + if (prot == TLS1_VERSION && protocol & SSL_PROTOCOL_SSLV3) { ++ ssl_set_ctx_protocol_option(s, ctx, SSL_OP_NO_SSLv3, ++ protocol & SSL_PROTOCOL_SSLV3, "SSLv3"); + prot = SSL3_VERSION; + } + #endif diff --git a/httpd-2.4.43-gettid.patch b/httpd-2.4.43-gettid.patch new file mode 100644 index 0000000..f80b3a7 --- /dev/null +++ b/httpd-2.4.43-gettid.patch @@ -0,0 +1,93 @@ +From d4e5b6e1e5585d341d1e51f1ddc637c099111076 Mon Sep 17 00:00:00 2001 +From: Joe Orton +Date: Tue, 7 Jul 2020 09:48:01 +0100 +Subject: [PATCH] Check and use gettid() directly with glibc 2.30+. + +* configure.in: Check for gettid() and define HAVE_SYS_GETTID if + gettid() is only usable via syscall(). + +* server/log.c (log_tid): Use gettid() directly if available. +--- + configure.in | 14 +++++++++----- + server/log.c | 8 ++++++-- + 2 files changed, 15 insertions(+), 7 deletions(-) + +diff --git a/configure.in b/configure.in +index 423d58d4b9a..60cbf7b7f81 100644 +--- httpd-2.4.43/configure.in.gettid ++++ httpd-2.4.43/configure.in +@@ -478,7 +500,8 @@ + timegm \ + getpgid \ + fopen64 \ +-getloadavg ++getloadavg \ ++gettid + ) + + dnl confirm that a void pointer is large enough to store a long integer +@@ -489,16 +512,19 @@ + APR_ADDTO(HTTPD_LIBS, [-lselinux]) + ]) + +-AC_CACHE_CHECK([for gettid()], ac_cv_gettid, ++if test $ac_cv_func_gettid = no; then ++ # On Linux before glibc 2.30, gettid() is only usable via syscall() ++ AC_CACHE_CHECK([for gettid() via syscall], ap_cv_gettid, + [AC_TRY_RUN(#define _GNU_SOURCE + #include + #include + #include + int main(int argc, char **argv) { + pid_t t = syscall(SYS_gettid); return t == -1 ? 1 : 0; }, +-[ac_cv_gettid=yes], [ac_cv_gettid=no], [ac_cv_gettid=no])]) +-if test "$ac_cv_gettid" = "yes"; then +- AC_DEFINE(HAVE_GETTID, 1, [Define if you have gettid()]) ++ [ap_cv_gettid=yes], [ap_cv_gettid=no], [ap_cv_gettid=no])]) ++ if test "$ap_cv_gettid" = "yes"; then ++ AC_DEFINE(HAVE_SYS_GETTID, 1, [Define if you have gettid() via syscall()]) ++ fi + fi + + dnl ## Check for the tm_gmtoff field in struct tm to get the timezone diffs +--- httpd-2.4.43/server/log.c.gettid ++++ httpd-2.4.43/server/log.c +@@ -55,7 +55,7 @@ + #include "ap_mpm.h" + #include "ap_listen.h" + +-#if HAVE_GETTID ++#if HAVE_SYS_GETTID + #include + #include + #endif +@@ -625,14 +625,18 @@ + #if APR_HAS_THREADS + int result; + #endif +-#if HAVE_GETTID ++#if defined(HAVE_GETTID) || defined(HAVE_SYS_GETTID) + if (arg && *arg == 'g') { ++#ifdef HAVE_GETTID ++ pid_t tid = gettid(); ++#else + pid_t tid = syscall(SYS_gettid); ++#endif + if (tid == -1) + return 0; + return apr_snprintf(buf, buflen, "%"APR_PID_T_FMT, tid); + } +-#endif ++#endif /* HAVE_GETTID || HAVE_SYS_GETTID */ + #if APR_HAS_THREADS + if (ap_mpm_query(AP_MPMQ_IS_THREADED, &result) == APR_SUCCESS + && result != AP_MPMQ_NOT_SUPPORTED) +@@ -966,7 +970,7 @@ + #if APR_HAS_THREADS + field_start = len; + len += cpystrn(buf + len, ":tid ", buflen - len); +- item_len = log_tid(info, NULL, buf + len, buflen - len); ++ item_len = log_tid(info, "g", buf + len, buflen - len); + if (!item_len) + len = field_start; + else diff --git a/httpd-2.4.43-logjournal.patch b/httpd-2.4.43-logjournal.patch new file mode 100644 index 0000000..cfbd9dc --- /dev/null +++ b/httpd-2.4.43-logjournal.patch @@ -0,0 +1,87 @@ +diff --git a/modules/loggers/config.m4 b/modules/loggers/config.m4 +index 762e773..0848d2e 100644 +--- a/modules/loggers/config.m4 ++++ b/modules/loggers/config.m4 +@@ -5,6 +5,8 @@ dnl APACHE_MODULE(name, helptext[, objects[, structname[, default[, config]]]]) + APACHE_MODPATH_INIT(loggers) + + APACHE_MODULE(log_config, logging configuration. You won't be able to log requests to the server without this module., , , yes) ++APR_ADDTO(MOD_LOG_CONFIG_LDADD, [$SYSTEMD_LIBS]) ++ + APACHE_MODULE(log_debug, configurable debug logging, , , most) + APACHE_MODULE(log_forensic, forensic logging) + +diff --git a/modules/loggers/mod_log_config.c b/modules/loggers/mod_log_config.c +index 996c09c..50a056a 100644 +--- a/modules/loggers/mod_log_config.c ++++ b/modules/loggers/mod_log_config.c +@@ -172,6 +172,10 @@ + #include + #endif + ++#ifdef HAVE_SYSTEMD ++#include ++#endif ++ + #define DEFAULT_LOG_FORMAT "%h %l %u %t \"%r\" %>s %b" + + module AP_MODULE_DECLARE_DATA log_config_module; +@@ -1638,6 +1642,25 @@ static apr_status_t ap_default_log_writer( request_rec *r, + + return rv; + } ++ ++static apr_status_t wrap_journal_stream(apr_pool_t *p, apr_file_t **outfd, ++ int priority) ++{ ++#ifdef HAVE_SYSTEMD ++ int fd; ++ ++ fd = sd_journal_stream_fd("httpd", priority, 0); ++ if (fd < 0) return fd; ++ ++ /* This is an AF_UNIX socket fd so is more pipe-like than ++ * file-like (the fd is neither seekable or readable), and use of ++ * apr_os_pipe_put_ex() allows cleanup registration. */ ++ return apr_os_pipe_put_ex(outfd, &fd, 1, p); ++#else ++ return APR_ENOTIMPL; ++#endif ++} ++ + static void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s, + const char* name) + { +@@ -1650,6 +1673,32 @@ static void *ap_default_log_writer_init(apr_pool_t *p, server_rec *s, + } + return ap_piped_log_write_fd(pl); + } ++ else if (strncasecmp(name, "journald:", 9) == 0) { ++ int priority; ++ const char *err = ap_parse_log_level(name + 9, &priority); ++ apr_status_t rv; ++ apr_file_t *fd; ++ ++ if (err == NULL && priority > LOG_DEBUG) { ++ err = "TRACE level debugging not supported with journald"; ++ } ++ ++ if (err) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, APR_EBADPATH, s, ++ "invalid journald log priority name %s: %s", ++ name, err); ++ return NULL; ++ } ++ ++ rv = wrap_journal_stream(p, &fd, priority); ++ if (rv) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, ++ "could not open journald log stream"); ++ return NULL; ++ } ++ ++ return fd; ++ } + else { + const char *fname = ap_server_root_relative(p, name); + apr_file_t *fd; diff --git a/httpd-2.4.43-mod_systemd.patch b/httpd-2.4.43-mod_systemd.patch new file mode 100644 index 0000000..8d7922e --- /dev/null +++ b/httpd-2.4.43-mod_systemd.patch @@ -0,0 +1,96 @@ + +More verbose startup logging for mod_systemd. + +--- httpd-2.4.43/modules/arch/unix/mod_systemd.c.mod_systemd ++++ httpd-2.4.43/modules/arch/unix/mod_systemd.c +@@ -29,11 +29,14 @@ + #include "mpm_common.h" + + #include "systemd/sd-daemon.h" ++#include "systemd/sd-journal.h" + + #if APR_HAVE_UNISTD_H + #include + #endif + ++static char describe_listeners[30]; ++ + static int systemd_pre_config(apr_pool_t *pconf, apr_pool_t *plog, + apr_pool_t *ptemp) + { +@@ -44,6 +47,20 @@ + return OK; + } + ++static char *dump_listener(ap_listen_rec *lr, apr_pool_t *p) ++{ ++ apr_sockaddr_t *sa = lr->bind_addr; ++ char addr[128]; ++ ++ if (apr_sockaddr_is_wildcard(sa)) { ++ return apr_pstrcat(p, "port ", apr_itoa(p, sa->port), NULL); ++ } ++ ++ apr_sockaddr_ip_getbuf(addr, sizeof addr, sa); ++ ++ return apr_psprintf(p, "%s port %u", addr, sa->port); ++} ++ + /* Report the service is ready in post_config, which could be during + * startup or after a reload. The server could still hit a fatal + * startup error after this point during ap_run_mpm(), so this is +@@ -51,19 +68,51 @@ + * the TCP ports so new connections will not be rejected. There will + * always be a possible async failure event simultaneous to the + * service reporting "ready", so this should be good enough. */ +-static int systemd_post_config(apr_pool_t *p, apr_pool_t *plog, ++static int systemd_post_config(apr_pool_t *pconf, apr_pool_t *plog, + apr_pool_t *ptemp, server_rec *main_server) + { ++ ap_listen_rec *lr; ++ apr_size_t plen = sizeof describe_listeners; ++ char *p = describe_listeners; ++ ++ if (ap_state_query(AP_SQ_MAIN_STATE) == AP_SQ_MS_CREATE_PRE_CONFIG) ++ return OK; ++ ++ for (lr = ap_listeners; lr; lr = lr->next) { ++ char *s = dump_listener(lr, ptemp); ++ ++ if (strlen(s) + 3 < plen) { ++ char *newp = apr_cpystrn(p, s, plen); ++ if (lr->next) ++ newp = apr_cpystrn(newp, ", ", 3); ++ plen -= newp - p; ++ p = newp; ++ } ++ else { ++ if (plen < 4) { ++ p = describe_listeners + sizeof describe_listeners - 4; ++ plen = 4; ++ } ++ apr_cpystrn(p, "...", plen); ++ break; ++ } ++ } ++ + sd_notify(0, "READY=1\n" + "STATUS=Configuration loaded.\n"); ++ ++ sd_journal_print(LOG_INFO, "Server configured, listening on: %s", ++ describe_listeners); ++ + return OK; + } + + static int systemd_pre_mpm(apr_pool_t *p, ap_scoreboard_e sb_type) + { + sd_notifyf(0, "READY=1\n" +- "STATUS=Processing requests...\n" +- "MAINPID=%" APR_PID_T_FMT, getpid()); ++ "STATUS=Started, listening on: %s\n" ++ "MAINPID=%" APR_PID_T_FMT, ++ describe_listeners, getpid()); + + return OK; + } diff --git a/httpd-2.4.43-pr37355.patch b/httpd-2.4.43-pr37355.patch new file mode 100644 index 0000000..e23a432 --- /dev/null +++ b/httpd-2.4.43-pr37355.patch @@ -0,0 +1,143 @@ +diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c +index e599515..154ab21 100644 +--- a/modules/proxy/mod_proxy.c ++++ b/modules/proxy/mod_proxy.c +@@ -1200,11 +1200,20 @@ static int proxy_handler(request_rec *r) + /* handle the scheme */ + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01142) + "Trying to run scheme_handler against proxy"); ++ ++ if (ents[i].creds) { ++ apr_table_set(r->notes, "proxy-basic-creds", ents[i].creds); ++ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, ++ "Using proxy auth creds %s", ents[i].creds); ++ } ++ + access_status = proxy_run_scheme_handler(r, worker, + conf, url, + ents[i].hostname, + ents[i].port); + ++ if (ents[i].creds) apr_table_unset(r->notes, "proxy-basic-creds"); ++ + /* Did the scheme handler process the request? */ + if (access_status != DECLINED) { + const char *cl_a; +@@ -1620,8 +1629,8 @@ 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) ++static const char *add_proxy(cmd_parms *cmd, void *dummy, const char *f1, ++ const char *r1, const char *creds, int regex) + { + server_rec *s = cmd->server; + proxy_server_conf *conf = +@@ -1679,19 +1688,24 @@ static const char * + new->port = port; + new->regexp = reg; + new->use_regex = regex; ++ if (creds) { ++ new->creds = apr_pstrcat(cmd->pool, "Basic ", ++ ap_pbase64encode(cmd->pool, (char *)creds), ++ NULL); ++ } + return NULL; + } + +-static const char * +- add_proxy_noregex(cmd_parms *cmd, void *dummy, const char *f1, const char *r1) ++static const char *add_proxy_noregex(cmd_parms *cmd, void *dummy, const char *f1, ++ const char *r1, const char *creds) + { +- return add_proxy(cmd, dummy, f1, r1, 0); ++ return add_proxy(cmd, dummy, f1, r1, creds, 0); + } + +-static const char * +- add_proxy_regex(cmd_parms *cmd, void *dummy, const char *f1, const char *r1) ++static const char *add_proxy_regex(cmd_parms *cmd, void *dummy, const char *f1, ++ const char *r1, const char *creds) + { +- return add_proxy(cmd, dummy, f1, r1, 1); ++ return add_proxy(cmd, dummy, f1, r1, creds, 1); + } + + PROXY_DECLARE(const char *) ap_proxy_de_socketfy(apr_pool_t *p, const char *url) +@@ -2637,9 +2651,9 @@ static const command_rec proxy_cmds[] = + "location, in regular expression syntax"), + AP_INIT_FLAG("ProxyRequests", set_proxy_req, NULL, RSRC_CONF, + "on if the true proxy requests should be accepted"), +- AP_INIT_TAKE2("ProxyRemote", add_proxy_noregex, NULL, RSRC_CONF, ++ AP_INIT_TAKE23("ProxyRemote", add_proxy_noregex, NULL, RSRC_CONF, + "a scheme, partial URL or '*' and a proxy server"), +- AP_INIT_TAKE2("ProxyRemoteMatch", add_proxy_regex, NULL, RSRC_CONF, ++ AP_INIT_TAKE23("ProxyRemoteMatch", add_proxy_regex, NULL, RSRC_CONF, + "a regex pattern and a proxy server"), + AP_INIT_FLAG("ProxyPassInterpolateEnv", ap_set_flag_slot_char, + (void*)APR_OFFSETOF(proxy_dir_conf, interpolate_env), +diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h +index 895b937..538839f 100644 +--- a/modules/proxy/mod_proxy.h ++++ b/modules/proxy/mod_proxy.h +@@ -116,6 +116,7 @@ struct proxy_remote { + const char *protocol; /* the scheme used to talk to this proxy */ + const char *hostname; /* the hostname of this proxy */ + ap_regex_t *regexp; /* compiled regex (if any) for the remote */ ++ const char *creds; /* auth credentials (if any) for the proxy */ + int use_regex; /* simple boolean. True if we have a regex pattern */ + apr_port_t port; /* the port for this proxy */ + }; +diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c +index e7ffe33..50561a4 100644 +--- a/modules/proxy/proxy_util.c ++++ b/modules/proxy/proxy_util.c +@@ -2474,11 +2474,14 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, + * 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"); ++ proxy_auth = apr_table_get(r->notes, "proxy-basic-creds"); ++ if (proxy_auth == NULL) ++ 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")) { ++ (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); + } + } +@@ -2714,7 +2717,8 @@ static apr_status_t send_http_connect(proxy_conn_rec *backend, + nbytes = apr_snprintf(buffer, sizeof(buffer), + "CONNECT %s:%d HTTP/1.0" CRLF, + forward->target_host, forward->target_port); +- /* Add proxy authorization from the initial request if necessary */ ++ /* Add proxy authorization from the configuration, or initial ++ * request if necessary */ + if (forward->proxy_auth != NULL) { + nbytes += apr_snprintf(buffer + nbytes, sizeof(buffer) - nbytes, + "Proxy-Authorization: %s" CRLF, +@@ -3627,6 +3631,7 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, + apr_bucket *e; + int do_100_continue; + conn_rec *origin = p_conn->connection; ++ const char *creds; + proxy_dir_conf *dconf = ap_get_module_config(r->per_dir_config, &proxy_module); + + /* +@@ -3803,6 +3808,11 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, + return HTTP_BAD_REQUEST; + } + ++ creds = apr_table_get(r->notes, "proxy-basic-creds"); ++ if (creds) { ++ apr_table_mergen(r->headers_in, "Proxy-Authorization", creds); ++ } ++ + /* send request headers */ + headers_in_array = apr_table_elts(r->headers_in); + headers_in = (const apr_table_entry_t *) headers_in_array->elts; diff --git a/httpd-2.4.43-r1861269.patch b/httpd-2.4.43-r1861269.patch new file mode 100644 index 0000000..9bff242 --- /dev/null +++ b/httpd-2.4.43-r1861269.patch @@ -0,0 +1,20 @@ +diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c +index b53f3f8..979489c 100644 +--- a/modules/ssl/ssl_engine_config.c ++++ b/modules/ssl/ssl_engine_config.c +@@ -812,8 +812,14 @@ const char *ssl_cmd_SSLCipherSuite(cmd_parms *cmd, + static const char *ssl_cmd_check_file(cmd_parms *parms, + const char **file) + { +- const char *filepath = ap_server_root_relative(parms->pool, *file); ++ const char *filepath; + ++ /* If only dumping the config, don't verify the paths */ ++ if (ap_state_query(AP_SQ_RUN_MODE) == AP_SQ_RM_CONFIG_DUMP) { ++ return NULL; ++ } ++ ++ filepath = ap_server_root_relative(parms->pool, *file); + if (!filepath) { + return apr_pstrcat(parms->pool, parms->cmd->name, + ": Invalid file path ", *file, NULL); diff --git a/httpd-2.4.43-r1861793+.patch b/httpd-2.4.43-r1861793+.patch new file mode 100644 index 0000000..08e96cb --- /dev/null +++ b/httpd-2.4.43-r1861793+.patch @@ -0,0 +1,271 @@ +diff --git a/configure.in b/configure.in +index cb43246..0bb6b0d 100644 +--- httpd-2.4.43/configure.in.r1861793+ ++++ httpd-2.4.43/configure.in +@@ -465,6 +465,28 @@ + AC_SEARCH_LIBS(crypt, crypt) + CRYPT_LIBS="$LIBS" + APACHE_SUBST(CRYPT_LIBS) ++ ++if test "$ac_cv_search_crypt" != "no"; then ++ # Test crypt() with the SHA-512 test vector from https://akkadia.org/drepper/SHA-crypt.txt ++ AC_CACHE_CHECK([whether crypt() supports SHA-2], [ap_cv_crypt_sha2], [ ++ AC_RUN_IFELSE([AC_LANG_PROGRAM([[ ++#include ++#include ++#include ++ ++#define PASSWD_0 "Hello world!" ++#define SALT_0 "\$6\$saltstring" ++#define EXPECT_0 "\$6\$saltstring\$svn8UoSVapNtMuq1ukKS4tPQd8iKwSMHWjl/O817G3uBnIFNjnQJu" \ ++ "esI68u4OTLiBFdcbYEdFCoEOfaS35inz1" ++]], [char *result = crypt(PASSWD_0, SALT_0); ++ if (!result) return 1; ++ if (strcmp(result, EXPECT_0)) return 2; ++])], [ap_cv_crypt_sha2=yes], [ap_cv_crypt_sha2=no])]) ++ if test "$ap_cv_crypt_sha2" = yes; then ++ AC_DEFINE([HAVE_CRYPT_SHA2], 1, [Define if crypt() supports SHA-2 hashes]) ++ fi ++fi ++ + LIBS="$saved_LIBS" + + dnl See Comment #Spoon +--- httpd-2.4.43/docs/man/htpasswd.1.r1861793+ ++++ httpd-2.4.43/docs/man/htpasswd.1 +@@ -27,16 +27,16 @@ + .SH "SYNOPSIS" + + .PP +-\fB\fBhtpasswd\fR [ -\fBc\fR ] [ -\fBi\fR ] [ -\fBm\fR | -\fBB\fR | -\fBd\fR | -\fBs\fR | -\fBp\fR ] [ -\fBC\fR \fIcost\fR ] [ -\fBD\fR ] [ -\fBv\fR ] \fIpasswdfile\fR \fIusername\fR\fR ++\fB\fBhtpasswd\fR [ -\fBc\fR ] [ -\fBi\fR ] [ -\fBm\fR | -\fBB\fR | -\fB2\fR | -\fB5\fR | -\fBd\fR | -\fBs\fR | -\fBp\fR ] [ -\fBr\fR \fIrounds\fR ] [ -\fBC\fR \fIcost\fR ] [ -\fBD\fR ] [ -\fBv\fR ] \fIpasswdfile\fR \fIusername\fR\fR + + .PP +-\fB\fBhtpasswd\fR -\fBb\fR [ -\fBc\fR ] [ -\fBm\fR | -\fBB\fR | -\fBd\fR | -\fBs\fR | -\fBp\fR ] [ -\fBC\fR \fIcost\fR ] [ -\fBD\fR ] [ -\fBv\fR ] \fIpasswdfile\fR \fIusername\fR \fIpassword\fR\fR ++\fB\fBhtpasswd\fR -\fBb\fR [ -\fBc\fR ] [ -\fBm\fR | -\fBB\fR | -\fB2\fR | -\fB5\fR | -\fBd\fR | -\fBs\fR | -\fBp\fR ] [ -\fBr\fR \fIrounds\fR ] [ -\fBC\fR \fIcost\fR ] [ -\fBD\fR ] [ -\fBv\fR ] \fIpasswdfile\fR \fIusername\fR \fIpassword\fR\fR + + .PP +-\fB\fBhtpasswd\fR -\fBn\fR [ -\fBi\fR ] [ -\fBm\fR | -\fBB\fR | -\fBd\fR | -\fBs\fR | -\fBp\fR ] [ -\fBC\fR \fIcost\fR ] \fIusername\fR\fR ++\fB\fBhtpasswd\fR -\fBn\fR [ -\fBi\fR ] [ -\fBm\fR | -\fBB\fR | -\fB2\fR | -\fB5\fR | -\fBd\fR | -\fBs\fR | -\fBp\fR ] [ -\fBr\fR \fIrounds\fR ] [ -\fBC\fR \fIcost\fR ] \fIusername\fR\fR + + .PP +-\fB\fBhtpasswd\fR -\fBnb\fR [ -\fBm\fR | -\fBB\fR | -\fBd\fR | -\fBs\fR | -\fBp\fR ] [ -\fBC\fR \fIcost\fR ] \fIusername\fR \fIpassword\fR\fR ++\fB\fBhtpasswd\fR -\fBnb\fR [ -\fBm\fR | -\fBB\fR | -\fB2\fR | -\fB5\fR | -\fBd\fR | -\fBs\fR | -\fBp\fR ] [ -\fBr\fR \fIrounds\fR ] [ -\fBC\fR \fIcost\fR ] \fIusername\fR \fIpassword\fR\fR + + + .SH "SUMMARY" +@@ -48,7 +48,7 @@ + Resources available from the Apache HTTP server can be restricted to just the users listed in the files created by \fBhtpasswd\fR\&. This program can only manage usernames and passwords stored in a flat-file\&. It can encrypt and display password information for use in other types of data stores, though\&. To use a DBM database see dbmmanage or htdbm\&. + + .PP +-\fBhtpasswd\fR encrypts passwords using either bcrypt, a version of MD5 modified for Apache, SHA1, or the system's \fBcrypt()\fR routine\&. Files managed by \fBhtpasswd\fR may contain a mixture of different encoding types of passwords; some user records may have bcrypt or MD5-encrypted passwords while others in the same file may have passwords encrypted with \fBcrypt()\fR\&. ++\fBhtpasswd\fR encrypts passwords using either bcrypt, a version of MD5 modified for Apache, SHA-1, or the system's \fBcrypt()\fR routine\&. SHA-2-based hashes (SHA-256 and SHA-512) are supported for \fBcrypt()\fR\&. Files managed by \fBhtpasswd\fR may contain a mixture of different encoding types of passwords; some user records may have bcrypt or MD5-encrypted passwords while others in the same file may have passwords encrypted with \fBcrypt()\fR\&. + + .PP + This manual page only lists the command line arguments\&. For details of the directives necessary to configure user authentication in httpd see the Apache manual, which is part of the Apache distribution or can be found at http://httpd\&.apache\&.org/\&. +@@ -73,17 +73,26 @@ + \fB-m\fR + Use MD5 encryption for passwords\&. This is the default (since version 2\&.2\&.18)\&. + .TP ++\fB-2\fR ++Use SHA-256 \fBcrypt()\fR based hashes for passwords\&. This is supported on most Unix platforms\&. ++.TP ++\fB-5\fR ++Use SHA-512 \fBcrypt()\fR based hashes for passwords\&. This is supported on most Unix platforms\&. ++.TP + \fB-B\fR + Use bcrypt encryption for passwords\&. This is currently considered to be very secure\&. + .TP + \fB-C\fR + This flag is only allowed in combination with \fB-B\fR (bcrypt encryption)\&. It sets the computing time used for the bcrypt algorithm (higher is more secure but slower, default: 5, valid: 4 to 17)\&. + .TP ++\fB-r\fR ++This flag is only allowed in combination with \fB-2\fR or \fB-5\fR\&. It sets the number of hash rounds used for the SHA-2 algorithms (higher is more secure but slower; the default is 5,000)\&. ++.TP + \fB-d\fR + Use \fBcrypt()\fR encryption for passwords\&. This is not supported by the httpd server on Windows and Netware\&. This algorithm limits the password length to 8 characters\&. This algorithm is \fBinsecure\fR by today's standards\&. It used to be the default algorithm until version 2\&.2\&.17\&. + .TP + \fB-s\fR +-Use SHA encryption for passwords\&. Facilitates migration from/to Netscape servers using the LDAP Directory Interchange Format (ldif)\&. This algorithm is \fBinsecure\fR by today's standards\&. ++Use SHA-1 (160-bit) encryption for passwords\&. Facilitates migration from/to Netscape servers using the LDAP Directory Interchange Format (ldif)\&. This algorithm is \fBinsecure\fR by today's standards\&. + .TP + \fB-p\fR + Use plaintext passwords\&. Though \fBhtpasswd\fR will support creation on all platforms, the httpd daemon will only accept plain text passwords on Windows and Netware\&. +@@ -152,10 +161,13 @@ + When using the \fBcrypt()\fR algorithm, note that only the first 8 characters of the password are used to form the password\&. If the supplied password is longer, the extra characters will be silently discarded\&. + + .PP +-The SHA encryption format does not use salting: for a given password, there is only one encrypted representation\&. The \fBcrypt()\fR and MD5 formats permute the representation by prepending a random salt string, to make dictionary attacks against the passwords more difficult\&. ++The SHA-1 encryption format does not use salting: for a given password, there is only one encrypted representation\&. The \fBcrypt()\fR and MD5 formats permute the representation by prepending a random salt string, to make dictionary attacks against the passwords more difficult\&. ++ ++.PP ++The SHA-1 and \fBcrypt()\fR formats are insecure by today's standards\&. + + .PP +-The SHA and \fBcrypt()\fR formats are insecure by today's standards\&. ++The SHA-2-based \fBcrypt()\fR formats (SHA-256 and SHA-512) are supported on most modern Unix systems, and follow the specification at https://www\&.akkadia\&.org/drepper/SHA-crypt\&.txt\&. + + .SH "RESTRICTIONS" + +--- httpd-2.4.43/support/htpasswd.c.r1861793+ ++++ httpd-2.4.43/support/htpasswd.c +@@ -109,17 +109,21 @@ + "for it." NL + " -i Read password from stdin without verification (for script usage)." NL + " -m Force MD5 encryption of the password (default)." NL +- " -B Force bcrypt encryption of the password (very secure)." NL ++ " -2 Force SHA-256 crypt() hash of the password (very secure)." NL ++ " -5 Force SHA-512 crypt() hash of the password (very secure)." NL ++ " -B Force bcrypt encryption of the password (very secure)." NL + " -C Set the computing time used for the bcrypt algorithm" NL + " (higher is more secure but slower, default: %d, valid: 4 to 17)." NL ++ " -r Set the number of rounds used for the SHA-256, SHA-512 algorithms" NL ++ " (higher is more secure but slower, default: 5000)." NL + " -d Force CRYPT encryption of the password (8 chars max, insecure)." NL +- " -s Force SHA encryption of the password (insecure)." NL ++ " -s Force SHA-1 encryption of the password (insecure)." NL + " -p Do not encrypt the password (plaintext, insecure)." NL + " -D Delete the specified user." NL + " -v Verify password for the specified user." NL + "On other systems than Windows and NetWare the '-p' flag will " + "probably not work." NL +- "The SHA algorithm does not use a salt and is less secure than the " ++ "The SHA-1 algorithm does not use a salt and is less secure than the " + "MD5 algorithm." NL, + BCRYPT_DEFAULT_COST + ); +@@ -178,7 +182,7 @@ + if (rv != APR_SUCCESS) + exit(ERR_SYNTAX); + +- while ((rv = apr_getopt(state, "cnmspdBbDiC:v", &opt, &opt_arg)) == APR_SUCCESS) { ++ while ((rv = apr_getopt(state, "cnmspdBbDi25C:r:v", &opt, &opt_arg)) == APR_SUCCESS) { + switch (opt) { + case 'c': + *mask |= APHTP_NEWFILE; +--- httpd-2.4.43/support/passwd_common.c.r1861793+ ++++ httpd-2.4.43/support/passwd_common.c +@@ -179,16 +179,21 @@ + int mkhash(struct passwd_ctx *ctx) + { + char *pw; +- char salt[16]; ++ char salt[17]; + apr_status_t rv; + int ret = 0; + #if CRYPT_ALGO_SUPPORTED + char *cbuf; + #endif ++#ifdef HAVE_CRYPT_SHA2 ++ const char *setting; ++ char method; ++#endif + +- if (ctx->cost != 0 && ctx->alg != ALG_BCRYPT) { ++ if (ctx->cost != 0 && ctx->alg != ALG_BCRYPT ++ && ctx->alg != ALG_CRYPT_SHA256 && ctx->alg != ALG_CRYPT_SHA512 ) { + apr_file_printf(errfile, +- "Warning: Ignoring -C argument for this algorithm." NL); ++ "Warning: Ignoring -C/-r argument for this algorithm." NL); + } + + if (ctx->passwd == NULL) { +@@ -246,6 +251,34 @@ + break; + #endif /* CRYPT_ALGO_SUPPORTED */ + ++#ifdef HAVE_CRYPT_SHA2 ++ case ALG_CRYPT_SHA256: ++ case ALG_CRYPT_SHA512: ++ ret = generate_salt(salt, 16, &ctx->errstr, ctx->pool); ++ if (ret != 0) ++ break; ++ ++ method = ctx->alg == ALG_CRYPT_SHA256 ? '5': '6'; ++ ++ if (ctx->cost) ++ setting = apr_psprintf(ctx->pool, "$%c$rounds=%d$%s", ++ method, ctx->cost, salt); ++ else ++ setting = apr_psprintf(ctx->pool, "$%c$%s", ++ method, salt); ++ ++ cbuf = crypt(pw, setting); ++ if (cbuf == NULL) { ++ rv = APR_FROM_OS_ERROR(errno); ++ ctx->errstr = apr_psprintf(ctx->pool, "crypt() failed: %pm", &rv); ++ ret = ERR_PWMISMATCH; ++ break; ++ } ++ ++ apr_cpystrn(ctx->out, cbuf, ctx->out_len - 1); ++ break; ++#endif /* HAVE_CRYPT_SHA2 */ ++ + #if BCRYPT_ALGO_SUPPORTED + case ALG_BCRYPT: + rv = apr_generate_random_bytes((unsigned char*)salt, 16); +@@ -294,6 +327,19 @@ + case 's': + ctx->alg = ALG_APSHA; + break; ++#ifdef HAVE_CRYPT_SHA2 ++ case '2': ++ ctx->alg = ALG_CRYPT_SHA256; ++ break; ++ case '5': ++ ctx->alg = ALG_CRYPT_SHA512; ++ break; ++#else ++ case '2': ++ case '5': ++ ctx->errstr = "SHA-2 crypt() algorithms are not supported on this platform."; ++ return ERR_ALG_NOT_SUPP; ++#endif + case 'p': + ctx->alg = ALG_PLAIN; + #if !PLAIN_ALGO_SUPPORTED +@@ -324,11 +370,12 @@ + return ERR_ALG_NOT_SUPP; + #endif + break; +- case 'C': { ++ case 'C': ++ case 'r': { + char *endptr; + long num = strtol(opt_arg, &endptr, 10); + if (*endptr != '\0' || num <= 0) { +- ctx->errstr = "argument to -C must be a positive integer"; ++ ctx->errstr = "argument to -C/-r must be a positive integer"; + return ERR_SYNTAX; + } + ctx->cost = num; +--- httpd-2.4.43/support/passwd_common.h.r1861793+ ++++ httpd-2.4.43/support/passwd_common.h +@@ -28,6 +28,8 @@ + #include "apu_version.h" + #endif + ++#include "ap_config_auto.h" ++ + #define MAX_STRING_LEN 256 + + #define ALG_PLAIN 0 +@@ -35,6 +37,8 @@ + #define ALG_APMD5 2 + #define ALG_APSHA 3 + #define ALG_BCRYPT 4 ++#define ALG_CRYPT_SHA256 5 ++#define ALG_CRYPT_SHA512 6 + + #define BCRYPT_DEFAULT_COST 5 + +@@ -84,7 +88,7 @@ + apr_size_t out_len; + char *passwd; + int alg; +- int cost; ++ int cost; /* cost for bcrypt, rounds for SHA-2 */ + enum { + PW_PROMPT = 0, + PW_ARG, diff --git a/httpd-2.4.43-selinux.patch b/httpd-2.4.43-selinux.patch new file mode 100644 index 0000000..3c3176f --- /dev/null +++ b/httpd-2.4.43-selinux.patch @@ -0,0 +1,60 @@ +diff --git a/configure.in b/configure.in +index c8f9aa2..cb43246 100644 +--- a/configure.in ++++ b/configure.in +@@ -484,6 +484,11 @@ getloadavg + 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(HTTPD_LIBS, [-lselinux]) ++]) ++ + AC_CACHE_CHECK([for gettid()], ac_cv_gettid, + [AC_TRY_RUN(#define _GNU_SOURCE + #include +diff --git a/server/core.c b/server/core.c +index dc0f17a..7ed9527 100644 +--- a/server/core.c ++++ b/server/core.c +@@ -59,6 +59,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) +@@ -5015,6 +5019,28 @@ static int core_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *pte + } + #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/httpd-2.4.43-socket-activation.patch b/httpd-2.4.43-socket-activation.patch new file mode 100644 index 0000000..511f476 --- /dev/null +++ b/httpd-2.4.43-socket-activation.patch @@ -0,0 +1,300 @@ +diff --git a/server/listen.c b/server/listen.c +index 5242c2a..e2e028a 100644 +--- a/server/listen.c ++++ b/server/listen.c +@@ -34,6 +34,10 @@ + #include + #endif + ++#ifdef HAVE_SYSTEMD ++#include ++#endif ++ + /* we know core's module_index is 0 */ + #undef APLOG_MODULE_INDEX + #define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX +@@ -59,9 +63,12 @@ static int ap_listenbacklog; + static int ap_listencbratio; + static int send_buffer_size; + static int receive_buffer_size; ++#ifdef HAVE_SYSTEMD ++static int use_systemd = -1; ++#endif + + /* TODO: make_sock is just begging and screaming for APR abstraction */ +-static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server) ++static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server, int do_bind_listen) + { + apr_socket_t *s = server->sd; + int one = 1; +@@ -94,20 +101,6 @@ static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server) + return stat; + } + +-#if APR_HAVE_IPV6 +- if (server->bind_addr->family == APR_INET6) { +- stat = apr_socket_opt_set(s, APR_IPV6_V6ONLY, v6only_setting); +- if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) { +- ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p, APLOGNO(00069) +- "make_sock: for address %pI, apr_socket_opt_set: " +- "(IPV6_V6ONLY)", +- server->bind_addr); +- apr_socket_close(s); +- return stat; +- } +- } +-#endif +- + /* + * To send data over high bandwidth-delay connections at full + * speed we must force the TCP window to open wide enough to keep the +@@ -169,21 +162,37 @@ static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server) + } + #endif + +- if ((stat = apr_socket_bind(s, server->bind_addr)) != APR_SUCCESS) { +- ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, stat, p, APLOGNO(00072) +- "make_sock: could not bind to address %pI", +- server->bind_addr); +- apr_socket_close(s); +- return stat; +- } ++ if (do_bind_listen) { ++#if APR_HAVE_IPV6 ++ if (server->bind_addr->family == APR_INET6) { ++ stat = apr_socket_opt_set(s, APR_IPV6_V6ONLY, v6only_setting); ++ if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) { ++ ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p, APLOGNO(00069) ++ "make_sock: for address %pI, apr_socket_opt_set: " ++ "(IPV6_V6ONLY)", ++ server->bind_addr); ++ apr_socket_close(s); ++ return stat; ++ } ++ } ++#endif + +- if ((stat = apr_socket_listen(s, ap_listenbacklog)) != APR_SUCCESS) { +- ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_ERR, stat, p, APLOGNO(00073) +- "make_sock: unable to listen for connections " +- "on address %pI", +- server->bind_addr); +- apr_socket_close(s); +- return stat; ++ if ((stat = apr_socket_bind(s, server->bind_addr)) != APR_SUCCESS) { ++ ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, stat, p, APLOGNO(00072) ++ "make_sock: could not bind to address %pI", ++ server->bind_addr); ++ apr_socket_close(s); ++ return stat; ++ } ++ ++ if ((stat = apr_socket_listen(s, ap_listenbacklog)) != APR_SUCCESS) { ++ ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_ERR, stat, p, APLOGNO(00073) ++ "make_sock: unable to listen for connections " ++ "on address %pI", ++ server->bind_addr); ++ apr_socket_close(s); ++ return stat; ++ } + } + + #ifdef WIN32 +@@ -315,6 +324,123 @@ static int find_listeners(ap_listen_rec **from, ap_listen_rec **to, + return found; + } + ++#ifdef HAVE_SYSTEMD ++ ++static int find_systemd_socket(process_rec * process, apr_port_t port) { ++ int fdcount, fd; ++ int sdc = sd_listen_fds(0); ++ ++ if (sdc < 0) { ++ ap_log_perror(APLOG_MARK, APLOG_CRIT, sdc, process->pool, APLOGNO(02486) ++ "find_systemd_socket: Error parsing enviroment, sd_listen_fds returned %d", ++ sdc); ++ return -1; ++ } ++ ++ if (sdc == 0) { ++ ap_log_perror(APLOG_MARK, APLOG_CRIT, sdc, process->pool, APLOGNO(02487) ++ "find_systemd_socket: At least one socket must be set."); ++ return -1; ++ } ++ ++ fdcount = atoi(getenv("LISTEN_FDS")); ++ for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + fdcount; fd++) { ++ if (sd_is_socket_inet(fd, 0, 0, -1, port) > 0) { ++ return fd; ++ } ++ } ++ ++ return -1; ++} ++ ++static apr_status_t alloc_systemd_listener(process_rec * process, ++ int fd, const char *proto, ++ ap_listen_rec **out_rec) ++{ ++ apr_status_t rv; ++ struct sockaddr sa; ++ socklen_t len = sizeof(struct sockaddr); ++ apr_os_sock_info_t si; ++ ap_listen_rec *rec; ++ *out_rec = NULL; ++ ++ memset(&si, 0, sizeof(si)); ++ ++ rv = getsockname(fd, &sa, &len); ++ ++ if (rv != 0) { ++ rv = apr_get_netos_error(); ++ ap_log_perror(APLOG_MARK, APLOG_CRIT, rv, process->pool, APLOGNO(02489) ++ "getsockname on %d failed.", fd); ++ return rv; ++ } ++ ++ si.os_sock = &fd; ++ si.family = sa.sa_family; ++ si.local = &sa; ++ si.type = SOCK_STREAM; ++ si.protocol = APR_PROTO_TCP; ++ ++ rec = apr_palloc(process->pool, sizeof(ap_listen_rec)); ++ rec->active = 0; ++ rec->next = 0; ++ ++ ++ rv = apr_os_sock_make(&rec->sd, &si, process->pool); ++ if (rv != APR_SUCCESS) { ++ ap_log_perror(APLOG_MARK, APLOG_CRIT, rv, process->pool, APLOGNO(02490) ++ "apr_os_sock_make on %d failed.", fd); ++ return rv; ++ } ++ ++ rv = apr_socket_addr_get(&rec->bind_addr, APR_LOCAL, rec->sd); ++ if (rv != APR_SUCCESS) { ++ ap_log_perror(APLOG_MARK, APLOG_CRIT, rv, process->pool, APLOGNO(02491) ++ "apr_socket_addr_get on %d failed.", fd); ++ return rv; ++ } ++ ++ rec->protocol = apr_pstrdup(process->pool, proto); ++ ++ *out_rec = rec; ++ ++ return make_sock(process->pool, rec, 0); ++} ++ ++static const char *set_systemd_listener(process_rec *process, apr_port_t port, ++ const char *proto) ++{ ++ ap_listen_rec *last, *new; ++ apr_status_t rv; ++ int fd = find_systemd_socket(process, port); ++ if (fd < 0) { ++ return "Systemd socket activation is used, but this port is not " ++ "configured in systemd"; ++ } ++ ++ last = ap_listeners; ++ while (last && last->next) { ++ last = last->next; ++ } ++ ++ rv = alloc_systemd_listener(process, fd, proto, &new); ++ if (rv != APR_SUCCESS) { ++ return "Failed to setup socket passed by systemd using socket activation"; ++ } ++ ++ if (last == NULL) { ++ ap_listeners = last = new; ++ } ++ else { ++ last->next = new; ++ last = new; ++ } ++ ++ return NULL; ++} ++ ++#endif /* HAVE_SYSTEMD */ ++ + static const char *alloc_listener(process_rec *process, const char *addr, + apr_port_t port, const char* proto, + void *slave) +@@ -495,7 +621,7 @@ static int open_listeners(apr_pool_t *pool) + } + } + #endif +- if (make_sock(pool, lr) == APR_SUCCESS) { ++ if (make_sock(pool, lr, 1) == APR_SUCCESS) { + ++num_open; + } + else { +@@ -607,8 +733,28 @@ AP_DECLARE(int) ap_setup_listeners(server_rec *s) + } + } + +- if (open_listeners(s->process->pool)) { +- return 0; ++#ifdef HAVE_SYSTEMD ++ if (use_systemd) { ++ const char *userdata_key = "ap_open_systemd_listeners"; ++ void *data; ++ /* clear the enviroment on our second run ++ * so that none of our future children get confused. ++ */ ++ apr_pool_userdata_get(&data, userdata_key, s->process->pool); ++ if (!data) { ++ apr_pool_userdata_set((const void *)1, userdata_key, ++ apr_pool_cleanup_null, s->process->pool); ++ } ++ else { ++ sd_listen_fds(1); ++ } ++ } ++ else ++#endif ++ { ++ if (open_listeners(s->process->pool)) { ++ return 0; ++ } + } + + for (lr = ap_listeners; lr; lr = lr->next) { +@@ -698,7 +844,7 @@ AP_DECLARE(apr_status_t) ap_duplicate_listeners(apr_pool_t *p, server_rec *s, + duplr->bind_addr); + return stat; + } +- make_sock(p, duplr); ++ make_sock(p, duplr, 1); + #if AP_NONBLOCK_WHEN_MULTI_LISTEN + use_nonblock = (ap_listeners && ap_listeners->next); + stat = apr_socket_opt_set(duplr->sd, APR_SO_NONBLOCK, use_nonblock); +@@ -825,6 +971,11 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, + if (argc < 1 || argc > 2) { + return "Listen requires 1 or 2 arguments."; + } ++#ifdef HAVE_SYSTEMD ++ if (use_systemd == -1) { ++ use_systemd = sd_listen_fds(0) > 0; ++ } ++#endif + + rv = apr_parse_addr_port(&host, &scope_id, &port, argv[0], cmd->pool); + if (rv != APR_SUCCESS) { +@@ -856,6 +1007,12 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, + ap_str_tolower(proto); + } + ++#ifdef HAVE_SYSTEMD ++ if (use_systemd) { ++ return set_systemd_listener(cmd->server->process, port, proto); ++ } ++#endif ++ + return alloc_listener(cmd->server->process, host, port, proto, NULL); + } + diff --git a/httpd-2.4.43-sslciphdefault.patch b/httpd-2.4.43-sslciphdefault.patch new file mode 100644 index 0000000..85ae568 --- /dev/null +++ b/httpd-2.4.43-sslciphdefault.patch @@ -0,0 +1,31 @@ +diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c +index 97778a8..27e7a53 100644 +--- a/modules/ssl/ssl_engine_config.c ++++ b/modules/ssl/ssl_engine_config.c +@@ -778,9 +778,11 @@ const char *ssl_cmd_SSLCipherSuite(cmd_parms *cmd, + } + + if (!strcmp("SSL", arg1)) { +- /* always disable null and export ciphers */ +- arg2 = apr_pstrcat(cmd->pool, arg2, ":!aNULL:!eNULL:!EXP", NULL); + if (cmd->path) { ++ /* Disable null and export ciphers by default, except for PROFILE= ++ * configs where the parser doesn't cope. */ ++ if (strncmp(arg2, "PROFILE=", 8) != 0) ++ arg2 = apr_pstrcat(cmd->pool, arg2, ":!aNULL:!eNULL:!EXP", NULL); + dc->szCipherSuite = arg2; + } + else { +@@ -1544,8 +1546,10 @@ const char *ssl_cmd_SSLProxyCipherSuite(cmd_parms *cmd, + } + + if (!strcmp("SSL", arg1)) { +- /* always disable null and export ciphers */ +- arg2 = apr_pstrcat(cmd->pool, arg2, ":!aNULL:!eNULL:!EXP", NULL); ++ /* Disable null and export ciphers by default, except for PROFILE= ++ * configs where the parser doesn't cope. */ ++ if (strncmp(arg2, "PROFILE=", 8) != 0) ++ arg2 = apr_pstrcat(cmd->pool, arg2, ":!aNULL:!eNULL:!EXP", NULL); + dc->proxy->auth.cipher_suite = arg2; + return NULL; + } diff --git a/httpd-2.4.43-sslprotdefault.patch b/httpd-2.4.43-sslprotdefault.patch new file mode 100644 index 0000000..d089823 --- /dev/null +++ b/httpd-2.4.43-sslprotdefault.patch @@ -0,0 +1,99 @@ +diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c +index 27e7a53..b53f3f8 100644 +--- a/modules/ssl/ssl_engine_config.c ++++ b/modules/ssl/ssl_engine_config.c +@@ -119,7 +119,7 @@ static void modssl_ctx_init(modssl_ctx_t *mctx, apr_pool_t *p) + mctx->ticket_key = NULL; + #endif + +- mctx->protocol = SSL_PROTOCOL_DEFAULT; ++ mctx->protocol = SSL_PROTOCOL_NONE; + mctx->protocol_set = 0; + + mctx->pphrase_dialog_type = SSL_PPTYPE_UNSET; +@@ -263,6 +263,7 @@ static void modssl_ctx_cfg_merge(apr_pool_t *p, + if (add->protocol_set) { + mrg->protocol_set = 1; + mrg->protocol = add->protocol; ++ mrg->protocol_set = 1; + } + else { + mrg->protocol_set = base->protocol_set; + +diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c +index bfad47a..b0fcf81 100644 +--- a/modules/ssl/ssl_engine_init.c ++++ b/modules/ssl/ssl_engine_init.c +@@ -577,6 +577,7 @@ static apr_status_t ssl_init_ctx_protocol(server_rec *s, + MODSSL_SSL_METHOD_CONST SSL_METHOD *method = NULL; + char *cp; + int protocol = mctx->protocol; ++ int protocol_set = mctx->protocol_set; + SSLSrvConfigRec *sc = mySrvConfig(s); + #if OPENSSL_VERSION_NUMBER >= 0x10100000L + int prot; +@@ -586,12 +587,18 @@ static apr_status_t ssl_init_ctx_protocol(server_rec *s, + * Create the new per-server SSL context + */ + if (protocol == SSL_PROTOCOL_NONE) { +- ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02231) +- "No SSL protocols available [hint: SSLProtocol]"); +- return ssl_die(s); +- } ++ if (protocol_set) { ++ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02231) ++ "No SSL protocols available [hint: SSLProtocol]"); ++ return ssl_die(s); ++ } + +- cp = apr_pstrcat(p, ++ ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, s, ++ "Using OpenSSL/system default SSL/TLS protocols"); ++ cp = "default"; ++ } ++ else { ++ cp = apr_pstrcat(p, + #ifndef OPENSSL_NO_SSL3 + (protocol & SSL_PROTOCOL_SSLV3 ? "SSLv3, " : ""), + #endif +@@ -604,7 +611,8 @@ static apr_status_t ssl_init_ctx_protocol(server_rec *s, + #endif + #endif + NULL); +- cp[strlen(cp)-2] = NUL; ++ cp[strlen(cp)-2] = NUL; ++ } + + ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, s, + "Creating new SSL context (protocols: %s)", cp); +@@ -705,13 +713,15 @@ static apr_status_t ssl_init_ctx_protocol(server_rec *s, + prot = SSL3_VERSION; + #endif + } else { +- SSL_CTX_free(ctx); +- mctx->ssl_ctx = NULL; +- ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(03378) +- "No SSL protocols available [hint: SSLProtocol]"); +- return ssl_die(s); ++ if (protocol_set) { ++ SSL_CTX_free(ctx); ++ mctx->ssl_ctx = NULL; ++ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(03378) ++ "No SSL protocols available [hint: SSLProtocol]"); ++ return ssl_die(s); ++ } + } +- SSL_CTX_set_max_proto_version(ctx, prot); ++ if (protocol != SSL_PROTOCOL_NONE) SSL_CTX_set_max_proto_version(ctx, prot); + + /* Next we scan for the minimal protocol version we should provide, + * but we do not allow holes between max and min */ +@@ -731,7 +741,7 @@ static apr_status_t ssl_init_ctx_protocol(server_rec *s, + prot = SSL3_VERSION; + } + #endif +- SSL_CTX_set_min_proto_version(ctx, prot); ++ if (protocol != SSL_PROTOCOL_NONE) SSL_CTX_set_min_proto_version(ctx, prot); + #endif /* if OPENSSL_VERSION_NUMBER < 0x10100000L */ + + #ifdef SSL_OP_CIPHER_SERVER_PREFERENCE diff --git a/httpd-2.4.46-freebind.patch b/httpd-2.4.46-freebind.patch new file mode 100644 index 0000000..b348dcc --- /dev/null +++ b/httpd-2.4.46-freebind.patch @@ -0,0 +1,124 @@ +diff --git a/docs/manual/mod/mpm_common.html.en b/docs/manual/mod/mpm_common.html.en +index e7af21d..01d54b7 100644 +--- a/docs/manual/mod/mpm_common.html.en ++++ b/docs/manual/mod/mpm_common.html.en +@@ -42,6 +42,7 @@ more than one multi-processing module (MPM) +
  • EnableExceptionHook
  • +
  • GracefulShutdownTimeout
  • +
  • Listen
  • ++
  • ListenFree
  • +
  • ListenBackLog
  • +
  • ListenCoresBucketsRatio
  • +
  • MaxConnectionsPerChild
  • +@@ -244,6 +245,31 @@ discussion of the Address already in use error message, + including other causes. + +
    ++ ++
    top
    ++

    ListenFree Directive

    ++ ++ ++ ++ ++ ++ ++ ++
    Description:IP addresses and ports that the server ++listens to. Doesn't require IP address to be up
    Syntax:ListenFree [IP-address:]portnumber [protocol]
    Context:server config
    Status:MPM
    Module:event, worker, prefork, mpm_winnt, mpm_netware, mpmt_os2
    Compatibility:This directive is currently available only in Red Hat Enterprise Linux
    ++

    The ListenFree directive is ++ identical to the Listen directive. ++ The only difference is in the usage of the IP_FREEBIND socket ++ option, which is enabled by default with ListenFree. ++ If IP_FREEBIND is enabled, it allows httpd to bind to an IP ++ address that is nonlocal or does not (yet) exist. This allows httpd to ++ listen on a socket without requiring the underlying network interface ++ or the specified dynamic IP address to be up at the time when httpd ++ is trying to bind to it. ++

    ++
    ++ ++ +
    top
    +

    ListenBackLog Directive

    + +diff --git a/include/ap_listen.h b/include/ap_listen.h +index 58c2574..1a53292 100644 +--- a/include/ap_listen.h ++++ b/include/ap_listen.h +@@ -137,6 +137,9 @@ AP_DECLARE_NONSTD(const char *) ap_set_listenbacklog(cmd_parms *cmd, void *dummy + AP_DECLARE_NONSTD(const char *) ap_set_listencbratio(cmd_parms *cmd, void *dummy, const char *arg); + AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, + int argc, char *const argv[]); ++AP_DECLARE_NONSTD(const char *) ap_set_freelistener(cmd_parms *cmd, void *dummy, ++ int argc, char *const argv[]); ++ + AP_DECLARE_NONSTD(const char *) ap_set_send_buffer_size(cmd_parms *cmd, void *dummy, + const char *arg); + AP_DECLARE_NONSTD(const char *) ap_set_receive_buffer_size(cmd_parms *cmd, +@@ -150,6 +153,8 @@ AP_INIT_TAKE1("ListenCoresBucketsRatio", ap_set_listencbratio, NULL, RSRC_CONF, + "Ratio between the number of CPU cores (online) and the number of listeners buckets"), \ + AP_INIT_TAKE_ARGV("Listen", ap_set_listener, NULL, RSRC_CONF, \ + "A port number or a numeric IP address and a port number, and an optional protocol"), \ ++AP_INIT_TAKE_ARGV("ListenFree", ap_set_freelistener, NULL, RSRC_CONF, \ ++ "A port number or a numeric IP address and a port number, and an optional protocol"), \ + AP_INIT_TAKE1("SendBufferSize", ap_set_send_buffer_size, NULL, RSRC_CONF, \ + "Send buffer size in bytes"), \ + AP_INIT_TAKE1("ReceiveBufferSize", ap_set_receive_buffer_size, NULL, \ +diff --git a/server/listen.c b/server/listen.c +index e2e028a..6ef664b 100644 +--- a/server/listen.c ++++ b/server/listen.c +@@ -63,6 +63,7 @@ static int ap_listenbacklog; + static int ap_listencbratio; + static int send_buffer_size; + static int receive_buffer_size; ++static int ap_listenfreebind; + #ifdef HAVE_SYSTEMD + static int use_systemd = -1; + #endif +@@ -162,6 +163,21 @@ static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server, int do_bind_ + } + #endif + ++ ++#if defined(APR_SO_FREEBIND) ++ if (ap_listenfreebind) { ++ if (apr_socket_opt_set(s, APR_SO_FREEBIND, one) < 0) { ++ stat = apr_get_netos_error(); ++ ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p, APLOGNO(02182) ++ "make_sock: apr_socket_opt_set: " ++ "error setting APR_SO_FREEBIND"); ++ apr_socket_close(s); ++ return stat; ++ } ++ } ++#endif ++ ++ + if (do_bind_listen) { + #if APR_HAVE_IPV6 + if (server->bind_addr->family == APR_INET6) { +@@ -956,6 +972,7 @@ AP_DECLARE(void) ap_listen_pre_config(void) + } + } + ++ + AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, + int argc, char *const argv[]) + { +@@ -1016,6 +1033,14 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, + return alloc_listener(cmd->server->process, host, port, proto, NULL); + } + ++AP_DECLARE_NONSTD(const char *) ap_set_freelistener(cmd_parms *cmd, void *dummy, ++ int argc, ++ char *const argv[]) ++{ ++ ap_listenfreebind = 1; ++ return ap_set_listener(cmd, dummy, argc, argv); ++} ++ + AP_DECLARE_NONSTD(const char *) ap_set_listenbacklog(cmd_parms *cmd, + void *dummy, + const char *arg) diff --git a/httpd-2.4.46-htcacheclean-dont-break.patch b/httpd-2.4.46-htcacheclean-dont-break.patch new file mode 100644 index 0000000..e52318a --- /dev/null +++ b/httpd-2.4.46-htcacheclean-dont-break.patch @@ -0,0 +1,13 @@ +diff --git a/support/htcacheclean.c b/support/htcacheclean.c +index 958ba6d..0a7fe3c 100644 +--- a/support/htcacheclean.c ++++ b/support/htcacheclean.c +@@ -557,8 +557,6 @@ static int list_urls(char *path, apr_pool_t *pool, apr_off_t round) + } + } + } +- +- break; + } + } + } diff --git a/httpd-2.4.48-export.patch b/httpd-2.4.48-export.patch new file mode 100644 index 0000000..439f768 --- /dev/null +++ b/httpd-2.4.48-export.patch @@ -0,0 +1,63 @@ + +Reduce size of httpd binary by telling linker to export all symbols +from libmain.a, rather than bloating the symbol table with ap_hack_* +to do so indirectly. + +Upstream: https://svn.apache.org/r1861685 (as new default-off configure option) + +diff --git a/Makefile.in b/Makefile.in +index 40c7076..ac98e5f 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -4,8 +4,15 @@ CLEAN_SUBDIRS = test + + PROGRAM_NAME = $(progname) + PROGRAM_SOURCES = modules.c +-PROGRAM_LDADD = buildmark.o $(HTTPD_LDFLAGS) $(PROGRAM_DEPENDENCIES) $(HTTPD_LIBS) $(EXTRA_LIBS) $(AP_LIBS) $(LIBS) ++PROGRAM_LDADD = buildmark.o $(HTTPD_LDFLAGS) \ ++ $(PROGRAM_LDDEPS) \ ++ $(HTTPD_LIBS) $(EXTRA_LIBS) $(AP_LIBS) $(LIBS) + PROGRAM_PRELINK = $(COMPILE) -c $(top_srcdir)/server/buildmark.c ++PROGRAM_LDDEPS = \ ++ $(BUILTIN_LIBS) \ ++ $(MPM_LIB) \ ++ -Wl,--whole-archive,server/.libs/libmain.a,--no-whole-archive \ ++ os/$(OS_DIR)/libos.la + PROGRAM_DEPENDENCIES = \ + server/libmain.la \ + $(BUILTIN_LIBS) \ +diff --git a/server/Makefile.in b/server/Makefile.in +index 8111877..f00bb3f 100644 +--- a/server/Makefile.in ++++ b/server/Makefile.in +@@ -12,7 +12,7 @@ LTLIBRARY_SOURCES = \ + connection.c listen.c util_mutex.c \ + mpm_common.c mpm_unix.c mpm_fdqueue.c \ + util_charset.c util_cookies.c util_debug.c util_xml.c \ +- util_filter.c util_pcre.c util_regex.c exports.c \ ++ util_filter.c util_pcre.c util_regex.c \ + scoreboard.c error_bucket.c protocol.c core.c request.c ssl.c provider.c \ + eoc_bucket.c eor_bucket.c core_filters.c \ + util_expr_parse.c util_expr_scan.c util_expr_eval.c +diff --git a/server/main.c b/server/main.c +index 62e06df..17c09ee 100644 +--- a/server/main.c ++++ b/server/main.c +@@ -835,17 +835,3 @@ int main(int argc, const char * const argv[]) + return !OK; + } + +-#ifdef AP_USING_AUTOCONF +-/* This ugly little hack pulls any function referenced in exports.c into +- * the web server. exports.c is generated during the build, and it +- * has all of the APR functions specified by the apr/apr.exports and +- * apr-util/aprutil.exports files. +- */ +-const void *ap_suck_in_APR(void); +-const void *ap_suck_in_APR(void) +-{ +- extern const void *ap_ugly_hack; +- +- return ap_ugly_hack; +-} +-#endif diff --git a/httpd-2.4.48-full-release.patch b/httpd-2.4.48-full-release.patch new file mode 100644 index 0000000..6e31cc7 --- /dev/null +++ b/httpd-2.4.48-full-release.patch @@ -0,0 +1,46 @@ +diff --git a/server/core.c b/server/core.c +index c36ff26..621c82a 100644 +--- a/server/core.c ++++ b/server/core.c +@@ -3569,6 +3569,7 @@ 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_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; +@@ -3645,7 +3646,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 ")"); + } + +@@ -3653,7 +3657,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 ")"; +@@ -3686,8 +3690,11 @@ static const char *set_serv_tokens(cmd_parms *cmd, void *dummy, + else if (!ap_cstr_casecmp(arg, "Full")) { + ap_server_tokens = SrvTk_FULL; + } ++ else if (!strcasecmp(arg, "Full-Release")) { ++ ap_server_tokens = SrvTk_FULL_RELEASE; ++ } + else { +- return "ServerTokens takes 1 argument: 'Prod(uctOnly)', 'Major', 'Minor', 'Min(imal)', 'OS', or 'Full'"; ++ return "ServerTokens takes 1 argument: 'Prod(uctOnly)', 'Major', 'Minor', 'Min(imal)', 'OS', 'Full' or 'Full-Release'"; + } + + return NULL; diff --git a/httpd-2.4.48-proxy-ws-idle-timeout.patch b/httpd-2.4.48-proxy-ws-idle-timeout.patch new file mode 100644 index 0000000..d04dc68 --- /dev/null +++ b/httpd-2.4.48-proxy-ws-idle-timeout.patch @@ -0,0 +1,109 @@ +diff --git a/docs/manual/mod/mod_proxy_wstunnel.html.en b/docs/manual/mod/mod_proxy_wstunnel.html.en +index 9f2c120..61ff7de 100644 +--- a/docs/manual/mod/mod_proxy_wstunnel.html.en ++++ b/docs/manual/mod/mod_proxy_wstunnel.html.en +@@ -83,6 +83,7 @@ in the response Upgrade

    +
    Support Apache!

    Directives

    + +

    Bugfix checklist

    See also

    +
      +@@ -108,6 +109,23 @@ in the response Upgrade

      + WebSocket requests as in httpd 2.4.46 and earlier.

      + +
    ++ ++
    ++ ++ ++ ++ ++ ++ ++
    Description:Sets the maximum amount of time to wait for data on the websockets tunnel
    Syntax:ProxyWebsocketIdleTimeout num[ms]
    Default:ProxyWebsocketIdleTimeout 0
    Context:server config, virtual host
    Status:Extension
    Module:mod_proxy_wstunnel
    ++

    This directive imposes a maximum amount of time for the tunnel to be ++ left open while idle. The timeout is considered in seconds by default, but ++ it is possible to increase the time resolution to milliseconds ++ adding the ms suffix.

    ++ ++
    ++ + +
    +

    Available Languages:  en  | +diff --git a/modules/proxy/mod_proxy_wstunnel.c b/modules/proxy/mod_proxy_wstunnel.c +index bcbba42..c29ded1 100644 +--- a/modules/proxy/mod_proxy_wstunnel.c ++++ b/modules/proxy/mod_proxy_wstunnel.c +@@ -22,6 +22,7 @@ module AP_MODULE_DECLARE_DATA proxy_wstunnel_module; + typedef struct { + unsigned int fallback_to_proxy_http :1, + fallback_to_proxy_http_set :1; ++ apr_time_t idle_timeout; + } proxyws_dir_conf; + + static int can_fallback_to_proxy_http; +@@ -152,6 +153,8 @@ static int 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; ++ proxyws_dir_conf *dconf = ap_get_module_config(r->per_dir_config, ++ &proxy_wstunnel_module); + char *buf; + apr_bucket_brigade *header_brigade; + apr_bucket *e; +@@ -229,10 +232,13 @@ static int proxy_wstunnel_request(apr_pool_t *p, request_rec *r, + c->keepalive = AP_CONN_CLOSE; + + do { /* Loop until done (one side closes the connection, or an error) */ +- rv = apr_pollset_poll(pollset, -1, &pollcnt, &signalled); ++ rv = apr_pollset_poll(pollset, dconf->idle_timeout, &pollcnt, &signalled); + if (rv != APR_SUCCESS) { + if (APR_STATUS_IS_EINTR(rv)) { + continue; ++ } else if(APR_STATUS_IS_TIMEUP(rv)){ ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "RH: the connection has timed out"); ++ return HTTP_REQUEST_TIME_OUT; + } + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(02444) "error apr_poll()"); + return HTTP_INTERNAL_SERVER_ERROR; +@@ -418,11 +424,26 @@ cleanup: + return status; + } + ++static const char * proxyws_set_idle(cmd_parms *cmd, void *conf, const char *val) ++{ ++ proxyws_dir_conf *dconf = conf; ++ if (ap_timeout_parameter_parse(val, &(dconf->idle_timeout), "s") != APR_SUCCESS) ++ return "ProxyWebsocketIdleTimeout timeout has wrong format"; ++ ++ if (dconf->idle_timeout < 0) ++ return "ProxyWebsocketIdleTimeout timeout has to be a non-negative number"; ++ ++ if (!dconf->idle_timeout) dconf->idle_timeout = -1; /* loop indefinitely */ ++ ++ return NULL; ++} ++ + static void *create_proxyws_dir_config(apr_pool_t *p, char *dummy) + { + proxyws_dir_conf *new = + (proxyws_dir_conf *) apr_pcalloc(p, sizeof(proxyws_dir_conf)); + ++ new->idle_timeout = -1; /* no timeout */ + new->fallback_to_proxy_http = 1; + + return (void *) new; +@@ -465,7 +486,8 @@ static const command_rec ws_proxy_cmds[] = + proxyws_fallback_to_proxy_http, NULL, RSRC_CONF|ACCESS_CONF, + "whether to let mod_proxy_http handle the upgrade and tunneling, " + "On by default"), +- ++ AP_INIT_TAKE1("ProxyWebsocketIdleTimeout", proxyws_set_idle, NULL, RSRC_CONF|ACCESS_CONF, ++ "timeout for activity in either direction, unlimited by default."), + {NULL} + }; + diff --git a/httpd-2.4.48-r1825120.patch b/httpd-2.4.48-r1825120.patch new file mode 100644 index 0000000..4eb0a59 --- /dev/null +++ b/httpd-2.4.48-r1825120.patch @@ -0,0 +1,99 @@ +diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c +index 4e2e80d..10a2c86 100644 +--- a/modules/ssl/ssl_engine_init.c ++++ b/modules/ssl/ssl_engine_init.c +@@ -2256,51 +2256,6 @@ int ssl_proxy_section_post_config(apr_pool_t *p, apr_pool_t *plog, + return OK; + } + +-static int ssl_init_FindCAList_X509NameCmp(const X509_NAME * const *a, +- const X509_NAME * const *b) +-{ +- return(X509_NAME_cmp(*a, *b)); +-} +- +-static void ssl_init_PushCAList(STACK_OF(X509_NAME) *ca_list, +- server_rec *s, apr_pool_t *ptemp, +- const char *file) +-{ +- int n; +- STACK_OF(X509_NAME) *sk; +- +- sk = (STACK_OF(X509_NAME) *) +- SSL_load_client_CA_file(file); +- +- if (!sk) { +- return; +- } +- +- for (n = 0; n < sk_X509_NAME_num(sk); n++) { +- X509_NAME *name = sk_X509_NAME_value(sk, n); +- +- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02209) +- "CA certificate: %s", +- modssl_X509_NAME_to_string(ptemp, name, 0)); +- +- /* +- * note that SSL_load_client_CA_file() checks for duplicates, +- * but since we call it multiple times when reading a directory +- * we must also check for duplicates ourselves. +- */ +- +- if (sk_X509_NAME_find(ca_list, name) < 0) { +- /* this will be freed when ca_list is */ +- sk_X509_NAME_push(ca_list, name); +- } +- else { +- /* need to free this ourselves, else it will leak */ +- X509_NAME_free(name); +- } +- } +- +- sk_X509_NAME_free(sk); +-} + + static apr_status_t ssl_init_ca_cert_path(server_rec *s, + apr_pool_t *ptemp, +@@ -2324,7 +2279,7 @@ static apr_status_t ssl_init_ca_cert_path(server_rec *s, + } + file = apr_pstrcat(ptemp, path, "/", direntry.name, NULL); + if (ca_list) { +- ssl_init_PushCAList(ca_list, s, ptemp, file); ++ SSL_add_file_cert_subjects_to_stack(ca_list, file); + } + if (xi_list) { + load_x509_info(ptemp, xi_list, file); +@@ -2341,19 +2296,13 @@ STACK_OF(X509_NAME) *ssl_init_FindCAList(server_rec *s, + const char *ca_file, + const char *ca_path) + { +- STACK_OF(X509_NAME) *ca_list; +- +- /* +- * Start with a empty stack/list where new +- * entries get added in sorted order. +- */ +- ca_list = sk_X509_NAME_new(ssl_init_FindCAList_X509NameCmp); ++ STACK_OF(X509_NAME) *ca_list = sk_X509_NAME_new_null();; + + /* + * Process CA certificate bundle file + */ + if (ca_file) { +- ssl_init_PushCAList(ca_list, s, ptemp, ca_file); ++ SSL_add_file_cert_subjects_to_stack(ca_list, ca_file); + /* + * If ca_list is still empty after trying to load ca_file + * then the file failed to load, and users should hear about that. +@@ -2377,11 +2326,6 @@ STACK_OF(X509_NAME) *ssl_init_FindCAList(server_rec *s, + return NULL; + } + +- /* +- * Cleanup +- */ +- (void) sk_X509_NAME_set_cmp_func(ca_list, NULL); +- + return ca_list; + } + diff --git a/httpd-2.4.48-r1828172+.patch b/httpd-2.4.48-r1828172+.patch new file mode 100644 index 0000000..2b99d69 --- /dev/null +++ b/httpd-2.4.48-r1828172+.patch @@ -0,0 +1,1411 @@ +--- httpd-2.4.48/modules/generators/cgi_common.h.r1828172+ ++++ httpd-2.4.48/modules/generators/cgi_common.h +@@ -0,0 +1,366 @@ ++/* 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 "apr.h" ++#include "apr_strings.h" ++#include "apr_buckets.h" ++#include "apr_lib.h" ++#include "apr_poll.h" ++ ++#define APR_WANT_STRFUNC ++#define APR_WANT_MEMFUNC ++#include "apr_want.h" ++ ++#include "httpd.h" ++#include "util_filter.h" ++ ++static void discard_script_output(apr_bucket_brigade *bb) ++{ ++ apr_bucket *e; ++ const char *buf; ++ apr_size_t len; ++ ++ for (e = APR_BRIGADE_FIRST(bb); ++ e != APR_BRIGADE_SENTINEL(bb) && !APR_BUCKET_IS_EOS(e); ++ e = APR_BRIGADE_FIRST(bb)) ++ { ++ if (apr_bucket_read(e, &buf, &len, APR_BLOCK_READ)) { ++ break; ++ } ++ apr_bucket_delete(e); ++ } ++} ++ ++#ifdef WANT_CGI_BUCKET ++/* A CGI bucket type is needed to catch any output to stderr from the ++ * script; see PR 22030. */ ++static const apr_bucket_type_t bucket_type_cgi; ++ ++struct cgi_bucket_data { ++ apr_pollset_t *pollset; ++ request_rec *r; ++ apr_interval_time_t timeout; ++}; ++ ++/* Create a CGI bucket using pipes from script stdout 'out' ++ * and stderr 'err', for request 'r'. */ ++static apr_bucket *cgi_bucket_create(request_rec *r, ++ apr_interval_time_t timeout, ++ apr_file_t *out, apr_file_t *err, ++ apr_bucket_alloc_t *list) ++{ ++ apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); ++ apr_status_t rv; ++ apr_pollfd_t fd; ++ struct cgi_bucket_data *data = apr_palloc(r->pool, sizeof *data); ++ ++ /* Disable APR timeout handling since we'll use poll() entirely. */ ++ apr_file_pipe_timeout_set(out, 0); ++ apr_file_pipe_timeout_set(err, 0); ++ ++ APR_BUCKET_INIT(b); ++ b->free = apr_bucket_free; ++ b->list = list; ++ b->type = &bucket_type_cgi; ++ b->length = (apr_size_t)(-1); ++ b->start = -1; ++ ++ /* Create the pollset */ ++ rv = apr_pollset_create(&data->pollset, 2, r->pool, 0); ++ if (rv != APR_SUCCESS) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01217) ++ "apr_pollset_create(); check system or user limits"); ++ return NULL; ++ } ++ ++ fd.desc_type = APR_POLL_FILE; ++ fd.reqevents = APR_POLLIN; ++ fd.p = r->pool; ++ fd.desc.f = out; /* script's stdout */ ++ fd.client_data = (void *)1; ++ rv = apr_pollset_add(data->pollset, &fd); ++ if (rv != APR_SUCCESS) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01218) ++ "apr_pollset_add(); check system or user limits"); ++ return NULL; ++ } ++ ++ fd.desc.f = err; /* script's stderr */ ++ fd.client_data = (void *)2; ++ rv = apr_pollset_add(data->pollset, &fd); ++ if (rv != APR_SUCCESS) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01219) ++ "apr_pollset_add(); check system or user limits"); ++ return NULL; ++ } ++ ++ data->r = r; ++ data->timeout = timeout; ++ b->data = data; ++ return b; ++} ++ ++/* Create a duplicate CGI bucket using given bucket data */ ++static apr_bucket *cgi_bucket_dup(struct cgi_bucket_data *data, ++ apr_bucket_alloc_t *list) ++{ ++ apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); ++ APR_BUCKET_INIT(b); ++ b->free = apr_bucket_free; ++ b->list = list; ++ b->type = &bucket_type_cgi; ++ b->length = (apr_size_t)(-1); ++ b->start = -1; ++ b->data = data; ++ return b; ++} ++ ++/* Handle stdout from CGI child. Duplicate of logic from the _read ++ * method of the real APR pipe bucket implementation. */ ++static apr_status_t cgi_read_stdout(apr_bucket *a, apr_file_t *out, ++ const char **str, apr_size_t *len) ++{ ++ char *buf; ++ apr_status_t rv; ++ ++ *str = NULL; ++ *len = APR_BUCKET_BUFF_SIZE; ++ buf = apr_bucket_alloc(*len, a->list); /* XXX: check for failure? */ ++ ++ rv = apr_file_read(out, buf, len); ++ ++ if (rv != APR_SUCCESS && rv != APR_EOF) { ++ apr_bucket_free(buf); ++ return rv; ++ } ++ ++ if (*len > 0) { ++ struct cgi_bucket_data *data = a->data; ++ apr_bucket_heap *h; ++ ++ /* Change the current bucket to refer to what we read */ ++ a = apr_bucket_heap_make(a, buf, *len, apr_bucket_free); ++ h = a->data; ++ h->alloc_len = APR_BUCKET_BUFF_SIZE; /* note the real buffer size */ ++ *str = buf; ++ APR_BUCKET_INSERT_AFTER(a, cgi_bucket_dup(data, a->list)); ++ } ++ else { ++ apr_bucket_free(buf); ++ a = apr_bucket_immortal_make(a, "", 0); ++ *str = a->data; ++ } ++ return rv; ++} ++ ++/* Read method of CGI bucket: polls on stderr and stdout of the child, ++ * sending any stderr output immediately away to the error log. */ ++static apr_status_t cgi_bucket_read(apr_bucket *b, const char **str, ++ apr_size_t *len, apr_read_type_e block) ++{ ++ struct cgi_bucket_data *data = b->data; ++ apr_interval_time_t timeout = 0; ++ apr_status_t rv; ++ int gotdata = 0; ++ ++ if (block != APR_NONBLOCK_READ) { ++ timeout = data->timeout > 0 ? data->timeout : data->r->server->timeout; ++ } ++ ++ do { ++ const apr_pollfd_t *results; ++ apr_int32_t num; ++ ++ rv = apr_pollset_poll(data->pollset, timeout, &num, &results); ++ if (APR_STATUS_IS_TIMEUP(rv)) { ++ if (timeout) { ++ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, data->r, APLOGNO(01220) ++ "Timeout waiting for output from CGI script %s", ++ data->r->filename); ++ return rv; ++ } ++ else { ++ return APR_EAGAIN; ++ } ++ } ++ else if (APR_STATUS_IS_EINTR(rv)) { ++ continue; ++ } ++ else if (rv != APR_SUCCESS) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, data->r, APLOGNO(01221) ++ "poll failed waiting for CGI child"); ++ return rv; ++ } ++ ++ for (; num; num--, results++) { ++ if (results[0].client_data == (void *)1) { ++ /* stdout */ ++ rv = cgi_read_stdout(b, results[0].desc.f, str, len); ++ if (APR_STATUS_IS_EOF(rv)) { ++ rv = APR_SUCCESS; ++ } ++ gotdata = 1; ++ } else { ++ /* stderr */ ++ apr_status_t rv2 = log_script_err(data->r, results[0].desc.f); ++ if (APR_STATUS_IS_EOF(rv2)) { ++ apr_pollset_remove(data->pollset, &results[0]); ++ } ++ } ++ } ++ ++ } while (!gotdata); ++ ++ return rv; ++} ++ ++static const apr_bucket_type_t bucket_type_cgi = { ++ "CGI", 5, APR_BUCKET_DATA, ++ apr_bucket_destroy_noop, ++ cgi_bucket_read, ++ apr_bucket_setaside_notimpl, ++ apr_bucket_split_notimpl, ++ apr_bucket_copy_notimpl ++}; ++ ++#endif /* WANT_CGI_BUCKET */ ++ ++/* Handle the CGI response output, having set up the brigade with the ++ * CGI or PIPE bucket as appropriate. */ ++static int cgi_handle_response(request_rec *r, int nph, apr_bucket_brigade *bb, ++ apr_interval_time_t timeout, cgi_server_conf *conf, ++ char *logdata, apr_file_t *script_err) ++{ ++ apr_status_t rv; ++ ++ /* Handle script return... */ ++ if (!nph) { ++ const char *location; ++ char sbuf[MAX_STRING_LEN]; ++ int ret; ++ ++ if ((ret = ap_scan_script_header_err_brigade_ex(r, bb, sbuf, ++ APLOG_MODULE_INDEX))) ++ { ++ /* In the case of a timeout reading script output, clear ++ * the brigade to avoid a second attempt to read the ++ * output. */ ++ if (ret == HTTP_GATEWAY_TIME_OUT) { ++ apr_brigade_cleanup(bb); ++ } ++ ++ ret = log_script(r, conf, ret, logdata, sbuf, bb, script_err); ++ ++ /* ++ * ret could be HTTP_NOT_MODIFIED in the case that the CGI script ++ * does not set an explicit status and ap_meets_conditions, which ++ * is called by ap_scan_script_header_err_brigade, detects that ++ * the conditions of the requests are met and the response is ++ * not modified. ++ * In this case set r->status and return OK in order to prevent ++ * running through the error processing stack as this would ++ * break with mod_cache, if the conditions had been set by ++ * mod_cache itself to validate a stale entity. ++ * BTW: We circumvent the error processing stack anyway if the ++ * CGI script set an explicit status code (whatever it is) and ++ * the only possible values for ret here are: ++ * ++ * HTTP_NOT_MODIFIED (set by ap_meets_conditions) ++ * HTTP_PRECONDITION_FAILED (set by ap_meets_conditions) ++ * HTTP_INTERNAL_SERVER_ERROR (if something went wrong during the ++ * processing of the response of the CGI script, e.g broken headers ++ * or a crashed CGI process). ++ */ ++ if (ret == HTTP_NOT_MODIFIED) { ++ r->status = ret; ++ return OK; ++ } ++ ++ return ret; ++ } ++ ++ location = apr_table_get(r->headers_out, "Location"); ++ ++ if (location && r->status == 200) { ++ /* For a redirect whether internal or not, discard any ++ * remaining stdout from the script, and log any remaining ++ * stderr output, as normal. */ ++ discard_script_output(bb); ++ apr_brigade_destroy(bb); ++ ++ if (script_err) { ++ apr_file_pipe_timeout_set(script_err, timeout); ++ log_script_err(r, script_err); ++ } ++ } ++ ++ if (location && location[0] == '/' && r->status == 200) { ++ /* This redirect needs to be a GET no matter what the original ++ * method was. ++ */ ++ r->method = "GET"; ++ r->method_number = M_GET; ++ ++ /* We already read the message body (if any), so don't allow ++ * the redirected request to think it has one. We can ignore ++ * Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR. ++ */ ++ apr_table_unset(r->headers_in, "Content-Length"); ++ ++ ap_internal_redirect_handler(location, r); ++ return OK; ++ } ++ else if (location && r->status == 200) { ++ /* XXX: Note that if a script wants to produce its own Redirect ++ * body, it now has to explicitly *say* "Status: 302" ++ */ ++ discard_script_output(bb); ++ apr_brigade_destroy(bb); ++ return HTTP_MOVED_TEMPORARILY; ++ } ++ ++ rv = ap_pass_brigade(r->output_filters, bb); ++ } ++ else /* nph */ { ++ struct ap_filter_t *cur; ++ ++ /* get rid of all filters up through protocol... since we ++ * haven't parsed off the headers, there is no way they can ++ * work ++ */ ++ ++ cur = r->proto_output_filters; ++ while (cur && cur->frec->ftype < AP_FTYPE_CONNECTION) { ++ cur = cur->next; ++ } ++ r->output_filters = r->proto_output_filters = cur; ++ ++ rv = ap_pass_brigade(r->output_filters, bb); ++ } ++ ++ /* don't soak up script output if errors occurred writing it ++ * out... otherwise, we prolong the life of the script when the ++ * connection drops or we stopped sending output for some other ++ * reason */ ++ if (script_err && rv == APR_SUCCESS && !r->connection->aborted) { ++ apr_file_pipe_timeout_set(script_err, timeout); ++ log_script_err(r, script_err); ++ } ++ ++ if (script_err) apr_file_close(script_err); ++ ++ return OK; /* NOT r->status, even if it has changed. */ ++} +--- httpd-2.4.48/modules/generators/config5.m4.r1828172+ ++++ httpd-2.4.48/modules/generators/config5.m4 +@@ -78,4 +78,15 @@ + + APR_ADDTO(INCLUDES, [-I\$(top_srcdir)/$modpath_current]) + ++AC_ARG_ENABLE(cgid-fdpassing, ++ [APACHE_HELP_STRING(--enable-cgid-fdpassing,Enable experimental mod_cgid support for fd passing)], ++ [if test "$enableval" = "yes"; then ++ AC_CHECK_DECL(CMSG_DATA, ++ [AC_DEFINE([HAVE_CGID_FDPASSING], 1, [Enable FD passing support in mod_cgid])], ++ [AC_MSG_ERROR([cannot support mod_cgid fd-passing on this system])], [ ++#include ++#include ]) ++ fi ++]) ++ + APACHE_MODPATH_FINISH +--- httpd-2.4.48/modules/generators/mod_cgi.c.r1828172+ ++++ httpd-2.4.48/modules/generators/mod_cgi.c +@@ -92,6 +92,10 @@ + apr_size_t bufbytes; + } cgi_server_conf; + ++typedef struct { ++ apr_interval_time_t timeout; ++} cgi_dirconf; ++ + static void *create_cgi_config(apr_pool_t *p, server_rec *s) + { + cgi_server_conf *c = +@@ -112,6 +116,12 @@ + return overrides->logname ? overrides : base; + } + ++static void *create_cgi_dirconf(apr_pool_t *p, char *dummy) ++{ ++ cgi_dirconf *c = (cgi_dirconf *) apr_pcalloc(p, sizeof(cgi_dirconf)); ++ return c; ++} ++ + static const char *set_scriptlog(cmd_parms *cmd, void *dummy, const char *arg) + { + server_rec *s = cmd->server; +@@ -150,6 +160,17 @@ + return NULL; + } + ++static const char *set_script_timeout(cmd_parms *cmd, void *dummy, const char *arg) ++{ ++ cgi_dirconf *dc = dummy; ++ ++ if (ap_timeout_parameter_parse(arg, &dc->timeout, "s") != APR_SUCCESS) { ++ return "CGIScriptTimeout has wrong format"; ++ } ++ ++ return NULL; ++} ++ + static const command_rec cgi_cmds[] = + { + AP_INIT_TAKE1("ScriptLog", set_scriptlog, NULL, RSRC_CONF, +@@ -158,6 +179,9 @@ + "the maximum length (in bytes) of the script debug log"), + AP_INIT_TAKE1("ScriptLogBuffer", set_scriptlog_buffer, NULL, RSRC_CONF, + "the maximum size (in bytes) to record of a POST request"), ++AP_INIT_TAKE1("CGIScriptTimeout", set_script_timeout, NULL, RSRC_CONF | ACCESS_CONF, ++ "The amount of time to wait between successful reads from " ++ "the CGI script, in seconds."), + {NULL} + }; + +@@ -466,23 +490,26 @@ + apr_filepath_name_get(r->filename)); + } + else { ++ cgi_dirconf *dc = ap_get_module_config(r->per_dir_config, &cgi_module); ++ apr_interval_time_t timeout = dc->timeout > 0 ? dc->timeout : r->server->timeout; ++ + apr_pool_note_subprocess(p, procnew, APR_KILL_AFTER_TIMEOUT); + + *script_in = procnew->out; + if (!*script_in) + return APR_EBADF; +- apr_file_pipe_timeout_set(*script_in, r->server->timeout); ++ apr_file_pipe_timeout_set(*script_in, timeout); + + if (e_info->prog_type == RUN_AS_CGI) { + *script_out = procnew->in; + if (!*script_out) + return APR_EBADF; +- apr_file_pipe_timeout_set(*script_out, r->server->timeout); ++ apr_file_pipe_timeout_set(*script_out, timeout); + + *script_err = procnew->err; + if (!*script_err) + return APR_EBADF; +- apr_file_pipe_timeout_set(*script_err, r->server->timeout); ++ apr_file_pipe_timeout_set(*script_err, timeout); + } + } + } +@@ -536,209 +563,12 @@ + return APR_SUCCESS; + } + +-static void discard_script_output(apr_bucket_brigade *bb) +-{ +- apr_bucket *e; +- const char *buf; +- apr_size_t len; +- +- for (e = APR_BRIGADE_FIRST(bb); +- e != APR_BRIGADE_SENTINEL(bb) && !APR_BUCKET_IS_EOS(e); +- e = APR_BRIGADE_FIRST(bb)) +- { +- if (apr_bucket_read(e, &buf, &len, APR_BLOCK_READ)) { +- break; +- } +- apr_bucket_delete(e); +- } +-} +- + #if APR_FILES_AS_SOCKETS +- +-/* A CGI bucket type is needed to catch any output to stderr from the +- * script; see PR 22030. */ +-static const apr_bucket_type_t bucket_type_cgi; +- +-struct cgi_bucket_data { +- apr_pollset_t *pollset; +- request_rec *r; +-}; +- +-/* Create a CGI bucket using pipes from script stdout 'out' +- * and stderr 'err', for request 'r'. */ +-static apr_bucket *cgi_bucket_create(request_rec *r, +- apr_file_t *out, apr_file_t *err, +- apr_bucket_alloc_t *list) +-{ +- apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); +- apr_status_t rv; +- apr_pollfd_t fd; +- struct cgi_bucket_data *data = apr_palloc(r->pool, sizeof *data); +- +- APR_BUCKET_INIT(b); +- b->free = apr_bucket_free; +- b->list = list; +- b->type = &bucket_type_cgi; +- b->length = (apr_size_t)(-1); +- b->start = -1; +- +- /* Create the pollset */ +- rv = apr_pollset_create(&data->pollset, 2, r->pool, 0); +- if (rv != APR_SUCCESS) { +- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01217) +- "apr_pollset_create(); check system or user limits"); +- return NULL; +- } +- +- fd.desc_type = APR_POLL_FILE; +- fd.reqevents = APR_POLLIN; +- fd.p = r->pool; +- fd.desc.f = out; /* script's stdout */ +- fd.client_data = (void *)1; +- rv = apr_pollset_add(data->pollset, &fd); +- if (rv != APR_SUCCESS) { +- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01218) +- "apr_pollset_add(); check system or user limits"); +- return NULL; +- } +- +- fd.desc.f = err; /* script's stderr */ +- fd.client_data = (void *)2; +- rv = apr_pollset_add(data->pollset, &fd); +- if (rv != APR_SUCCESS) { +- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01219) +- "apr_pollset_add(); check system or user limits"); +- return NULL; +- } +- +- data->r = r; +- b->data = data; +- return b; +-} +- +-/* Create a duplicate CGI bucket using given bucket data */ +-static apr_bucket *cgi_bucket_dup(struct cgi_bucket_data *data, +- apr_bucket_alloc_t *list) +-{ +- apr_bucket *b = apr_bucket_alloc(sizeof(*b), list); +- APR_BUCKET_INIT(b); +- b->free = apr_bucket_free; +- b->list = list; +- b->type = &bucket_type_cgi; +- b->length = (apr_size_t)(-1); +- b->start = -1; +- b->data = data; +- return b; +-} +- +-/* Handle stdout from CGI child. Duplicate of logic from the _read +- * method of the real APR pipe bucket implementation. */ +-static apr_status_t cgi_read_stdout(apr_bucket *a, apr_file_t *out, +- const char **str, apr_size_t *len) +-{ +- char *buf; +- apr_status_t rv; +- +- *str = NULL; +- *len = APR_BUCKET_BUFF_SIZE; +- buf = apr_bucket_alloc(*len, a->list); /* XXX: check for failure? */ +- +- rv = apr_file_read(out, buf, len); +- +- if (rv != APR_SUCCESS && rv != APR_EOF) { +- apr_bucket_free(buf); +- return rv; +- } +- +- if (*len > 0) { +- struct cgi_bucket_data *data = a->data; +- apr_bucket_heap *h; +- +- /* Change the current bucket to refer to what we read */ +- a = apr_bucket_heap_make(a, buf, *len, apr_bucket_free); +- h = a->data; +- h->alloc_len = APR_BUCKET_BUFF_SIZE; /* note the real buffer size */ +- *str = buf; +- APR_BUCKET_INSERT_AFTER(a, cgi_bucket_dup(data, a->list)); +- } +- else { +- apr_bucket_free(buf); +- a = apr_bucket_immortal_make(a, "", 0); +- *str = a->data; +- } +- return rv; +-} +- +-/* Read method of CGI bucket: polls on stderr and stdout of the child, +- * sending any stderr output immediately away to the error log. */ +-static apr_status_t cgi_bucket_read(apr_bucket *b, const char **str, +- apr_size_t *len, apr_read_type_e block) +-{ +- struct cgi_bucket_data *data = b->data; +- apr_interval_time_t timeout; +- apr_status_t rv; +- int gotdata = 0; +- +- timeout = block == APR_NONBLOCK_READ ? 0 : data->r->server->timeout; +- +- do { +- const apr_pollfd_t *results; +- apr_int32_t num; +- +- rv = apr_pollset_poll(data->pollset, timeout, &num, &results); +- if (APR_STATUS_IS_TIMEUP(rv)) { +- if (timeout) { +- ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, data->r, APLOGNO(01220) +- "Timeout waiting for output from CGI script %s", +- data->r->filename); +- return rv; +- } +- else { +- return APR_EAGAIN; +- } +- } +- else if (APR_STATUS_IS_EINTR(rv)) { +- continue; +- } +- else if (rv != APR_SUCCESS) { +- ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, data->r, APLOGNO(01221) +- "poll failed waiting for CGI child"); +- return rv; +- } +- +- for (; num; num--, results++) { +- if (results[0].client_data == (void *)1) { +- /* stdout */ +- rv = cgi_read_stdout(b, results[0].desc.f, str, len); +- if (APR_STATUS_IS_EOF(rv)) { +- rv = APR_SUCCESS; +- } +- gotdata = 1; +- } else { +- /* stderr */ +- apr_status_t rv2 = log_script_err(data->r, results[0].desc.f); +- if (APR_STATUS_IS_EOF(rv2)) { +- apr_pollset_remove(data->pollset, &results[0]); +- } +- } +- } +- +- } while (!gotdata); +- +- return rv; +-} +- +-static const apr_bucket_type_t bucket_type_cgi = { +- "CGI", 5, APR_BUCKET_DATA, +- apr_bucket_destroy_noop, +- cgi_bucket_read, +- apr_bucket_setaside_notimpl, +- apr_bucket_split_notimpl, +- apr_bucket_copy_notimpl +-}; +- ++#define WANT_CGI_BUCKET + #endif + ++#include "cgi_common.h" ++ + static int cgi_handler(request_rec *r) + { + int nph; +@@ -757,6 +587,8 @@ + apr_status_t rv; + cgi_exec_info_t e_info; + conn_rec *c; ++ cgi_dirconf *dc = ap_get_module_config(r->per_dir_config, &cgi_module); ++ apr_interval_time_t timeout = dc->timeout > 0 ? dc->timeout : r->server->timeout; + + if (strcmp(r->handler, CGI_MAGIC_TYPE) && strcmp(r->handler, "cgi-script")) { + return DECLINED; +@@ -916,10 +748,7 @@ + AP_DEBUG_ASSERT(script_in != NULL); + + #if APR_FILES_AS_SOCKETS +- apr_file_pipe_timeout_set(script_in, 0); +- apr_file_pipe_timeout_set(script_err, 0); +- +- b = cgi_bucket_create(r, script_in, script_err, c->bucket_alloc); ++ b = cgi_bucket_create(r, dc->timeout, script_in, script_err, c->bucket_alloc); + if (b == NULL) + return HTTP_INTERNAL_SERVER_ERROR; + #else +@@ -929,111 +758,7 @@ + b = apr_bucket_eos_create(c->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(bb, b); + +- /* Handle script return... */ +- if (!nph) { +- const char *location; +- char sbuf[MAX_STRING_LEN]; +- int ret; +- +- if ((ret = ap_scan_script_header_err_brigade_ex(r, bb, sbuf, +- APLOG_MODULE_INDEX))) +- { +- ret = log_script(r, conf, ret, dbuf, sbuf, bb, script_err); +- +- /* +- * ret could be HTTP_NOT_MODIFIED in the case that the CGI script +- * does not set an explicit status and ap_meets_conditions, which +- * is called by ap_scan_script_header_err_brigade, detects that +- * the conditions of the requests are met and the response is +- * not modified. +- * In this case set r->status and return OK in order to prevent +- * running through the error processing stack as this would +- * break with mod_cache, if the conditions had been set by +- * mod_cache itself to validate a stale entity. +- * BTW: We circumvent the error processing stack anyway if the +- * CGI script set an explicit status code (whatever it is) and +- * the only possible values for ret here are: +- * +- * HTTP_NOT_MODIFIED (set by ap_meets_conditions) +- * HTTP_PRECONDITION_FAILED (set by ap_meets_conditions) +- * HTTP_INTERNAL_SERVER_ERROR (if something went wrong during the +- * processing of the response of the CGI script, e.g broken headers +- * or a crashed CGI process). +- */ +- if (ret == HTTP_NOT_MODIFIED) { +- r->status = ret; +- return OK; +- } +- +- return ret; +- } +- +- location = apr_table_get(r->headers_out, "Location"); +- +- if (location && r->status == 200) { +- /* For a redirect whether internal or not, discard any +- * remaining stdout from the script, and log any remaining +- * stderr output, as normal. */ +- discard_script_output(bb); +- apr_brigade_destroy(bb); +- apr_file_pipe_timeout_set(script_err, r->server->timeout); +- log_script_err(r, script_err); +- } +- +- if (location && location[0] == '/' && r->status == 200) { +- /* This redirect needs to be a GET no matter what the original +- * method was. +- */ +- r->method = "GET"; +- r->method_number = M_GET; +- +- /* We already read the message body (if any), so don't allow +- * the redirected request to think it has one. We can ignore +- * Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR. +- */ +- apr_table_unset(r->headers_in, "Content-Length"); +- +- ap_internal_redirect_handler(location, r); +- return OK; +- } +- else if (location && r->status == 200) { +- /* XXX: Note that if a script wants to produce its own Redirect +- * body, it now has to explicitly *say* "Status: 302" +- */ +- return HTTP_MOVED_TEMPORARILY; +- } +- +- rv = ap_pass_brigade(r->output_filters, bb); +- } +- else /* nph */ { +- struct ap_filter_t *cur; +- +- /* get rid of all filters up through protocol... since we +- * haven't parsed off the headers, there is no way they can +- * work +- */ +- +- cur = r->proto_output_filters; +- while (cur && cur->frec->ftype < AP_FTYPE_CONNECTION) { +- cur = cur->next; +- } +- r->output_filters = r->proto_output_filters = cur; +- +- rv = ap_pass_brigade(r->output_filters, bb); +- } +- +- /* don't soak up script output if errors occurred writing it +- * out... otherwise, we prolong the life of the script when the +- * connection drops or we stopped sending output for some other +- * reason */ +- if (rv == APR_SUCCESS && !r->connection->aborted) { +- apr_file_pipe_timeout_set(script_err, r->server->timeout); +- log_script_err(r, script_err); +- } +- +- apr_file_close(script_err); +- +- return OK; /* NOT r->status, even if it has changed. */ ++ return cgi_handle_response(r, nph, bb, timeout, conf, dbuf, script_err); + } + + /*============================================================================ +@@ -1268,7 +993,7 @@ + AP_DECLARE_MODULE(cgi) = + { + STANDARD20_MODULE_STUFF, +- NULL, /* dir config creater */ ++ create_cgi_dirconf, /* dir config creater */ + NULL, /* dir merger --- default is to override */ + create_cgi_config, /* server config */ + merge_cgi_config, /* merge server config */ +--- httpd-2.4.48/modules/generators/mod_cgid.c.r1828172+ ++++ httpd-2.4.48/modules/generators/mod_cgid.c +@@ -342,15 +342,19 @@ + return close(fd); + } + +-/* deal with incomplete reads and signals +- * assume you really have to read buf_size bytes +- */ +-static apr_status_t sock_read(int fd, void *vbuf, size_t buf_size) ++/* Read from the socket dealing with incomplete messages and signals. ++ * Returns 0 on success or errno on failure. Stderr fd passed as ++ * auxiliary data from other end is written to *errfd, or else stderr ++ * fileno if not present. */ ++static apr_status_t sock_readhdr(int fd, int *errfd, void *vbuf, size_t buf_size) + { +- char *buf = vbuf; + int rc; ++#ifndef HAVE_CGID_FDPASSING ++ char *buf = vbuf; + size_t bytes_read = 0; + ++ if (errfd) *errfd = 0; ++ + do { + do { + rc = read(fd, buf + bytes_read, buf_size - bytes_read); +@@ -365,9 +369,60 @@ + } + } while (bytes_read < buf_size); + ++ ++#else /* with FD passing */ ++ struct msghdr msg = {0}; ++ struct iovec vec = {vbuf, buf_size}; ++ struct cmsghdr *cmsg; ++ union { /* union to ensure alignment */ ++ struct cmsghdr cm; ++ char buf[CMSG_SPACE(sizeof(int))]; ++ } u; ++ ++ msg.msg_iov = &vec; ++ msg.msg_iovlen = 1; ++ ++ if (errfd) { ++ msg.msg_control = u.buf; ++ msg.msg_controllen = sizeof(u.buf); ++ *errfd = 0; ++ } ++ ++ /* use MSG_WAITALL to skip loop on truncated reads */ ++ do { ++ rc = recvmsg(fd, &msg, MSG_WAITALL); ++ } while (rc < 0 && errno == EINTR); ++ ++ if (rc == 0) { ++ return ECONNRESET; ++ } ++ else if (rc < 0) { ++ return errno; ++ } ++ else if (rc != buf_size) { ++ /* MSG_WAITALL should ensure the recvmsg blocks until the ++ * entire length is read, but let's be paranoid. */ ++ return APR_INCOMPLETE; ++ } ++ ++ if (errfd ++ && (cmsg = CMSG_FIRSTHDR(&msg)) != NULL ++ && cmsg->cmsg_len == CMSG_LEN(sizeof(*errfd)) ++ && cmsg->cmsg_level == SOL_SOCKET ++ && cmsg->cmsg_type == SCM_RIGHTS) { ++ *errfd = *((int *) CMSG_DATA(cmsg)); ++ } ++#endif ++ + return APR_SUCCESS; + } + ++/* As sock_readhdr but without auxiliary fd passing. */ ++static apr_status_t sock_read(int fd, void *vbuf, size_t buf_size) ++{ ++ return sock_readhdr(fd, NULL, vbuf, buf_size); ++} ++ + /* deal with signals + */ + static apr_status_t sock_write(int fd, const void *buf, size_t buf_size) +@@ -384,7 +439,7 @@ + return APR_SUCCESS; + } + +-static apr_status_t sock_writev(int fd, request_rec *r, int count, ...) ++static apr_status_t sock_writev(int fd, int auxfd, request_rec *r, int count, ...) + { + va_list ap; + int rc; +@@ -399,9 +454,39 @@ + } + va_end(ap); + ++#ifndef HAVE_CGID_FDPASSING + do { + rc = writev(fd, vec, count); + } while (rc < 0 && errno == EINTR); ++#else ++ { ++ struct msghdr msg = { 0 }; ++ struct cmsghdr *cmsg; ++ union { /* union for alignment */ ++ char buf[CMSG_SPACE(sizeof(int))]; ++ struct cmsghdr align; ++ } u; ++ ++ msg.msg_iov = vec; ++ msg.msg_iovlen = count; ++ ++ if (auxfd) { ++ msg.msg_control = u.buf; ++ msg.msg_controllen = sizeof(u.buf); ++ ++ cmsg = CMSG_FIRSTHDR(&msg); ++ cmsg->cmsg_level = SOL_SOCKET; ++ cmsg->cmsg_type = SCM_RIGHTS; ++ cmsg->cmsg_len = CMSG_LEN(sizeof(int)); ++ *((int *) CMSG_DATA(cmsg)) = auxfd; ++ } ++ ++ do { ++ rc = sendmsg(fd, &msg, 0); ++ } while (rc < 0 && errno == EINTR); ++ } ++#endif ++ + if (rc < 0) { + return errno; + } +@@ -410,7 +495,7 @@ + } + + static apr_status_t get_req(int fd, request_rec *r, char **argv0, char ***env, +- cgid_req_t *req) ++ int *errfd, cgid_req_t *req) + { + int i; + char **environ; +@@ -421,7 +506,7 @@ + r->server = apr_pcalloc(r->pool, sizeof(server_rec)); + + /* read the request header */ +- stat = sock_read(fd, req, sizeof(*req)); ++ stat = sock_readhdr(fd, errfd, req, sizeof(*req)); + if (stat != APR_SUCCESS) { + return stat; + } +@@ -479,14 +564,15 @@ + return APR_SUCCESS; + } + +-static apr_status_t send_req(int fd, request_rec *r, char *argv0, char **env, +- int req_type) ++static apr_status_t send_req(int fd, apr_file_t *errpipe, request_rec *r, ++ char *argv0, char **env, int req_type) + { + int i; + cgid_req_t req = {0}; + apr_status_t stat; + ap_unix_identity_t * ugid = ap_run_get_suexec_identity(r); + core_dir_config *core_conf = ap_get_core_module_config(r->per_dir_config); ++ int errfd; + + + if (ugid == NULL) { +@@ -507,16 +593,21 @@ + req.args_len = r->args ? strlen(r->args) : 0; + req.loglevel = r->server->log.level; + ++ if (errpipe) ++ apr_os_file_get(&errfd, errpipe); ++ else ++ errfd = 0; ++ + /* Write the request header */ + if (req.args_len) { +- stat = sock_writev(fd, r, 5, ++ stat = sock_writev(fd, errfd, r, 5, + &req, sizeof(req), + r->filename, req.filename_len, + argv0, req.argv0_len, + r->uri, req.uri_len, + r->args, req.args_len); + } else { +- stat = sock_writev(fd, r, 4, ++ stat = sock_writev(fd, errfd, r, 4, + &req, sizeof(req), + r->filename, req.filename_len, + argv0, req.argv0_len, +@@ -531,7 +622,7 @@ + for (i = 0; i < req.env_count; i++) { + apr_size_t curlen = strlen(env[i]); + +- if ((stat = sock_writev(fd, r, 2, &curlen, sizeof(curlen), ++ if ((stat = sock_writev(fd, 0, r, 2, &curlen, sizeof(curlen), + env[i], curlen)) != APR_SUCCESS) { + return stat; + } +@@ -582,20 +673,34 @@ + } + } + ++/* Callback executed in the forked child process if exec of the CGI ++ * script fails. For the fd-passing case, output to stderr goes to ++ * the client (request handling thread) and is logged via ++ * ap_log_rerror there. For the non-fd-passing case, the "fake" ++ * request_rec passed via userdata is used to log. */ + static void cgid_child_errfn(apr_pool_t *pool, apr_status_t err, + const char *description) + { +- request_rec *r; + void *vr; + + apr_pool_userdata_get(&vr, ERRFN_USERDATA_KEY, pool); +- r = vr; +- +- /* sure we got r, but don't call ap_log_rerror() because we don't +- * have r->headers_in and possibly other storage referenced by +- * ap_log_rerror() +- */ +- ap_log_error(APLOG_MARK, APLOG_ERR, err, r->server, APLOGNO(01241) "%s", description); ++ if (vr) { ++ request_rec *r = vr; ++ ++ /* sure we got r, but don't call ap_log_rerror() because we don't ++ * have r->headers_in and possibly other storage referenced by ++ * ap_log_rerror() ++ */ ++ ap_log_error(APLOG_MARK, APLOG_ERR, err, r->server, APLOGNO(01241) "%s", description); ++ } ++ else { ++ const char *logstr; ++ ++ logstr = apr_psprintf(pool, APLOGNO(01241) "error spawning CGI child: %s (%pm)\n", ++ description, &err); ++ fputs(logstr, stderr); ++ fflush(stderr); ++ } + } + + static int cgid_server(void *data) +@@ -670,7 +775,7 @@ + } + + while (!daemon_should_exit) { +- int errfileno = STDERR_FILENO; ++ int errfileno; + char *argv0 = NULL; + char **env = NULL; + const char * const *argv; +@@ -710,7 +815,7 @@ + r = apr_pcalloc(ptrans, sizeof(request_rec)); + procnew = apr_pcalloc(ptrans, sizeof(*procnew)); + r->pool = ptrans; +- stat = get_req(sd2, r, &argv0, &env, &cgid_req); ++ stat = get_req(sd2, r, &argv0, &env, &errfileno, &cgid_req); + if (stat != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, stat, + main_server, APLOGNO(01248) +@@ -742,6 +847,16 @@ + continue; + } + ++ if (errfileno == 0) { ++ errfileno = STDERR_FILENO; ++ } ++ else { ++ ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, main_server, ++ "using passed fd %d as stderr", errfileno); ++ /* Limit the received fd lifetime to pool lifetime */ ++ apr_pool_cleanup_register(ptrans, (void *)((long)errfileno), ++ close_unix_socket, close_unix_socket); ++ } + apr_os_file_put(&r->server->error_log, &errfileno, 0, r->pool); + apr_os_file_put(&inout, &sd2, 0, r->pool); + +@@ -801,7 +916,10 @@ + close(sd2); + } + else { +- apr_pool_userdata_set(r, ERRFN_USERDATA_KEY, apr_pool_cleanup_null, ptrans); ++ if (errfileno == STDERR_FILENO) { ++ /* Used by cgid_child_errfn without fd-passing. */ ++ apr_pool_userdata_set(r, ERRFN_USERDATA_KEY, apr_pool_cleanup_null, ptrans); ++ } + + argv = (const char * const *)create_argv(r->pool, NULL, NULL, NULL, argv0, r->args); + +@@ -1101,6 +1219,33 @@ + return ret; + } + ++/* Soak up stderr from a script and redirect it to the error log. ++ * TODO: log_scripterror() and this could move to cgi_common.h. */ ++static apr_status_t log_script_err(request_rec *r, apr_file_t *script_err) ++{ ++ char argsbuffer[HUGE_STRING_LEN]; ++ char *newline; ++ apr_status_t rv; ++ cgid_server_conf *conf = ap_get_module_config(r->server->module_config, &cgid_module); ++ ++ while ((rv = apr_file_gets(argsbuffer, HUGE_STRING_LEN, ++ script_err)) == APR_SUCCESS) { ++ ++ newline = strchr(argsbuffer, '\n'); ++ if (newline) { ++ char *prev = newline - 1; ++ if (prev >= argsbuffer && *prev == '\r') { ++ newline = prev; ++ } ++ ++ *newline = '\0'; ++ } ++ log_scripterror(r, conf, r->status, 0, argsbuffer); ++ } ++ ++ return rv; ++} ++ + static int log_script(request_rec *r, cgid_server_conf * conf, int ret, + char *dbuf, const char *sbuf, apr_bucket_brigade *bb, + apr_file_t *script_err) +@@ -1206,6 +1351,13 @@ + return ret; + } + ++/* Pull in CGI bucket implementation. */ ++#define cgi_server_conf cgid_server_conf ++#ifdef HAVE_CGID_FDPASSING ++#define WANT_CGI_BUCKET ++#endif ++#include "cgi_common.h" ++ + static int connect_to_daemon(int *sdptr, request_rec *r, + cgid_server_conf *conf) + { +@@ -1272,23 +1424,6 @@ + return OK; + } + +-static void discard_script_output(apr_bucket_brigade *bb) +-{ +- apr_bucket *e; +- const char *buf; +- apr_size_t len; +- +- for (e = APR_BRIGADE_FIRST(bb); +- e != APR_BRIGADE_SENTINEL(bb) && !APR_BUCKET_IS_EOS(e); +- e = APR_BRIGADE_FIRST(bb)) +- { +- if (apr_bucket_read(e, &buf, &len, APR_BLOCK_READ)) { +- break; +- } +- apr_bucket_delete(e); +- } +-} +- + /**************************************************************** + * + * Actual cgid handling... +@@ -1393,6 +1528,7 @@ + + static int cgid_handler(request_rec *r) + { ++ conn_rec *c = r->connection; + int retval, nph, dbpos; + char *argv0, *dbuf; + apr_bucket_brigade *bb; +@@ -1402,10 +1538,11 @@ + int seen_eos, child_stopped_reading; + int sd; + char **env; +- apr_file_t *tempsock; ++ apr_file_t *tempsock, *script_err, *errpipe_out; + struct cleanup_script_info *info; + apr_status_t rv; + cgid_dirconf *dc; ++ apr_interval_time_t timeout; + + if (strcmp(r->handler, CGI_MAGIC_TYPE) && strcmp(r->handler, "cgi-script")) { + return DECLINED; +@@ -1414,7 +1551,7 @@ + conf = ap_get_module_config(r->server->module_config, &cgid_module); + dc = ap_get_module_config(r->per_dir_config, &cgid_module); + +- ++ timeout = dc->timeout > 0 ? dc->timeout : r->server->timeout; + is_included = !strcmp(r->protocol, "INCLUDED"); + + if ((argv0 = strrchr(r->filename, '/')) != NULL) { +@@ -1467,6 +1604,17 @@ + } + */ + ++#ifdef HAVE_CGID_FDPASSING ++ rv = apr_file_pipe_create(&script_err, &errpipe_out, r->pool); ++ if (rv) { ++ return log_scripterror(r, conf, HTTP_SERVICE_UNAVAILABLE, rv, APLOGNO(10176) ++ "could not create pipe for stderr"); ++ } ++#else ++ script_err = NULL; ++ errpipe_out = NULL; ++#endif ++ + /* + * httpd core function used to add common environment variables like + * DOCUMENT_ROOT. +@@ -1479,12 +1627,16 @@ + return retval; + } + +- rv = send_req(sd, r, argv0, env, CGI_REQ); ++ rv = send_req(sd, errpipe_out, r, argv0, env, CGI_REQ); + if (rv != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(01268) + "write to cgi daemon process"); + } + ++ /* The write-end of the pipe is only used by the server, so close ++ * it here. */ ++ if (errpipe_out) apr_file_close(errpipe_out); ++ + info = apr_palloc(r->pool, sizeof(struct cleanup_script_info)); + info->conf = conf; + info->r = r; +@@ -1506,12 +1658,7 @@ + */ + + 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_file_pipe_timeout_set(tempsock, timeout); + apr_pool_cleanup_kill(r->pool, (void *)((long)sd), close_unix_socket); + + /* Transfer any put/post args, CERN style... +@@ -1603,114 +1750,19 @@ + */ + shutdown(sd, 1); + +- /* Handle script return... */ +- if (!nph) { +- conn_rec *c = r->connection; +- const char *location; +- char sbuf[MAX_STRING_LEN]; +- int ret; +- +- bb = apr_brigade_create(r->pool, c->bucket_alloc); +- b = apr_bucket_pipe_create(tempsock, c->bucket_alloc); +- APR_BRIGADE_INSERT_TAIL(bb, b); +- b = apr_bucket_eos_create(c->bucket_alloc); +- APR_BRIGADE_INSERT_TAIL(bb, b); +- +- if ((ret = ap_scan_script_header_err_brigade_ex(r, bb, sbuf, +- APLOG_MODULE_INDEX))) +- { +- ret = log_script(r, conf, ret, dbuf, sbuf, bb, NULL); +- +- /* +- * ret could be HTTP_NOT_MODIFIED in the case that the CGI script +- * does not set an explicit status and ap_meets_conditions, which +- * is called by ap_scan_script_header_err_brigade, detects that +- * the conditions of the requests are met and the response is +- * not modified. +- * In this case set r->status and return OK in order to prevent +- * running through the error processing stack as this would +- * break with mod_cache, if the conditions had been set by +- * mod_cache itself to validate a stale entity. +- * BTW: We circumvent the error processing stack anyway if the +- * CGI script set an explicit status code (whatever it is) and +- * the only possible values for ret here are: +- * +- * HTTP_NOT_MODIFIED (set by ap_meets_conditions) +- * HTTP_PRECONDITION_FAILED (set by ap_meets_conditions) +- * HTTP_INTERNAL_SERVER_ERROR (if something went wrong during the +- * processing of the response of the CGI script, e.g broken headers +- * or a crashed CGI process). +- */ +- if (ret == HTTP_NOT_MODIFIED) { +- r->status = ret; +- return OK; +- } +- +- return ret; +- } +- +- location = apr_table_get(r->headers_out, "Location"); +- +- if (location && location[0] == '/' && r->status == 200) { +- +- /* Soak up all the script output */ +- discard_script_output(bb); +- apr_brigade_destroy(bb); +- /* This redirect needs to be a GET no matter what the original +- * method was. +- */ +- r->method = "GET"; +- r->method_number = M_GET; +- +- /* We already read the message body (if any), so don't allow +- * the redirected request to think it has one. We can ignore +- * Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR. +- */ +- apr_table_unset(r->headers_in, "Content-Length"); +- +- ap_internal_redirect_handler(location, r); +- return OK; +- } +- else if (location && r->status == 200) { +- /* XXX: Note that if a script wants to produce its own Redirect +- * body, it now has to explicitly *say* "Status: 302" +- */ +- discard_script_output(bb); +- apr_brigade_destroy(bb); +- return HTTP_MOVED_TEMPORARILY; +- } +- +- rv = ap_pass_brigade(r->output_filters, bb); +- if (rv != APR_SUCCESS) { +- ap_log_rerror(APLOG_MARK, APLOG_TRACE1, rv, r, +- "Failed to flush CGI output to client"); +- } +- } +- +- if (nph) { +- conn_rec *c = r->connection; +- struct ap_filter_t *cur; +- +- /* get rid of all filters up through protocol... since we +- * haven't parsed off the headers, there is no way they can +- * work +- */ +- +- cur = r->proto_output_filters; +- while (cur && cur->frec->ftype < AP_FTYPE_CONNECTION) { +- cur = cur->next; +- } +- r->output_filters = r->proto_output_filters = cur; +- +- bb = apr_brigade_create(r->pool, c->bucket_alloc); +- b = apr_bucket_pipe_create(tempsock, c->bucket_alloc); +- APR_BRIGADE_INSERT_TAIL(bb, b); +- b = apr_bucket_eos_create(c->bucket_alloc); +- APR_BRIGADE_INSERT_TAIL(bb, b); +- ap_pass_brigade(r->output_filters, bb); +- } ++ bb = apr_brigade_create(r->pool, c->bucket_alloc); ++#ifdef HAVE_CGID_FDPASSING ++ b = cgi_bucket_create(r, dc->timeout, tempsock, script_err, c->bucket_alloc); ++ if (b == NULL) ++ return HTTP_INTERNAL_SERVER_ERROR; /* should call log_scripterror() w/ _UNAVAILABLE? */ ++#else ++ b = apr_bucket_pipe_create(tempsock, c->bucket_alloc); ++#endif ++ APR_BRIGADE_INSERT_TAIL(bb, b); ++ b = apr_bucket_eos_create(c->bucket_alloc); ++ APR_BRIGADE_INSERT_TAIL(bb, b); + +- return OK; /* NOT r->status, even if it has changed. */ ++ return cgi_handle_response(r, nph, bb, timeout, conf, dbuf, script_err); + } + + +@@ -1827,7 +1879,7 @@ + return retval; + } + +- send_req(sd, r, command, env, SSI_REQ); ++ send_req(sd, NULL, r, command, env, SSI_REQ); + + info = apr_palloc(r->pool, sizeof(struct cleanup_script_info)); + info->conf = conf; diff --git a/httpd-2.4.48-r1842929+.patch b/httpd-2.4.48-r1842929+.patch new file mode 100644 index 0000000..f83a21d --- /dev/null +++ b/httpd-2.4.48-r1842929+.patch @@ -0,0 +1,229 @@ +diff --git a/Makefile.in b/Makefile.in +index 6747aea..40c7076 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -233,6 +233,7 @@ install-cgi: + install-other: + @test -d $(DESTDIR)$(logfiledir) || $(MKINSTALLDIRS) $(DESTDIR)$(logfiledir) + @test -d $(DESTDIR)$(runtimedir) || $(MKINSTALLDIRS) $(DESTDIR)$(runtimedir) ++ @test -d $(DESTDIR)$(statedir) || $(MKINSTALLDIRS) $(DESTDIR)$(statedir) + @for ext in dll x; do \ + file=apachecore.$$ext; \ + if test -f $$file; then \ +diff --git a/acinclude.m4 b/acinclude.m4 +index b6ef442..98f1441 100644 +--- a/acinclude.m4 ++++ b/acinclude.m4 +@@ -45,6 +45,7 @@ AC_DEFUN([APACHE_GEN_CONFIG_VARS],[ + APACHE_SUBST(installbuilddir) + APACHE_SUBST(runtimedir) + APACHE_SUBST(proxycachedir) ++ APACHE_SUBST(statedir) + APACHE_SUBST(other_targets) + APACHE_SUBST(progname) + APACHE_SUBST(prefix) +@@ -665,6 +666,7 @@ AC_DEFUN([APACHE_EXPORT_ARGUMENTS],[ + APACHE_SUBST_EXPANDED_ARG(runtimedir) + APACHE_SUBST_EXPANDED_ARG(logfiledir) + APACHE_SUBST_EXPANDED_ARG(proxycachedir) ++ APACHE_SUBST_EXPANDED_ARG(statedir) + ]) + + dnl +diff --git a/configure.in b/configure.in +index 37346b2..f303784 100644 +--- a/configure.in ++++ b/configure.in +@@ -41,7 +41,7 @@ dnl Something seems broken here. + AC_PREFIX_DEFAULT(/usr/local/apache2) + + dnl Get the layout here, so we can pass the required variables to apr +-APR_ENABLE_LAYOUT(Apache, [errordir iconsdir htdocsdir cgidir]) ++APR_ENABLE_LAYOUT(Apache, [errordir iconsdir htdocsdir cgidir statedir]) + + dnl reparse the configure arguments. + APR_PARSE_ARGUMENTS +diff --git a/include/ap_config_layout.h.in b/include/ap_config_layout.h.in +index 2b4a70c..e076f41 100644 +--- a/include/ap_config_layout.h.in ++++ b/include/ap_config_layout.h.in +@@ -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_STATEDIR "@exp_statedir@" ++#define DEFAULT_REL_STATEDIR "@rel_statedir@" + + #endif /* AP_CONFIG_LAYOUT_H */ +diff --git a/include/http_config.h b/include/http_config.h +index 77657ae..384a90f 100644 +--- a/include/http_config.h ++++ b/include/http_config.h +@@ -757,6 +757,14 @@ AP_DECLARE(char *) ap_server_root_relative(apr_pool_t *p, const char *fname); + */ + AP_DECLARE(char *) ap_runtime_dir_relative(apr_pool_t *p, const char *fname); + ++/** ++ * Compute the name of a persistent state file (e.g. a database or ++ * long-lived cache) relative to the appropriate state directory. ++ * Absolute paths are returned as-is. The state directory is ++ * configured via the DefaultStateDir directive or at build time. ++ */ ++AP_DECLARE(char *) ap_state_dir_relative(apr_pool_t *p, const char *fname); ++ + /* Finally, the hook for dynamically loading modules in... */ + + /** +diff --git a/modules/dav/fs/mod_dav_fs.c b/modules/dav/fs/mod_dav_fs.c +index addfd7e..2389f8f 100644 +--- a/modules/dav/fs/mod_dav_fs.c ++++ b/modules/dav/fs/mod_dav_fs.c +@@ -29,6 +29,10 @@ typedef struct { + + extern module AP_MODULE_DECLARE_DATA dav_fs_module; + ++#ifndef DEFAULT_DAV_LOCKDB ++#define DEFAULT_DAV_LOCKDB "davlockdb" ++#endif ++ + const char *dav_get_lockdb_path(const request_rec *r) + { + dav_fs_server_conf *conf; +@@ -57,6 +61,24 @@ static void *dav_fs_merge_server_config(apr_pool_t *p, + return newconf; + } + ++static apr_status_t dav_fs_post_config(apr_pool_t *p, apr_pool_t *plog, ++ apr_pool_t *ptemp, server_rec *base_server) ++{ ++ server_rec *s; ++ ++ for (s = base_server; s; s = s->next) { ++ dav_fs_server_conf *conf; ++ ++ conf = ap_get_module_config(s->module_config, &dav_fs_module); ++ ++ if (!conf->lockdb_path) { ++ conf->lockdb_path = ap_state_dir_relative(p, DEFAULT_DAV_LOCKDB); ++ } ++ } ++ ++ return OK; ++} ++ + /* + * Command handler for the DAVLockDB directive, which is TAKE1 + */ +@@ -87,6 +109,8 @@ static const command_rec dav_fs_cmds[] = + + static void register_hooks(apr_pool_t *p) + { ++ ap_hook_post_config(dav_fs_post_config, NULL, NULL, APR_HOOK_MIDDLE); ++ + dav_hook_gather_propsets(dav_fs_gather_propsets, NULL, NULL, + APR_HOOK_MIDDLE); + dav_hook_find_liveprop(dav_fs_find_liveprop, NULL, NULL, APR_HOOK_MIDDLE); +diff --git a/server/core.c b/server/core.c +index d135764..c2176b9 100644 +--- a/server/core.c ++++ b/server/core.c +@@ -142,6 +142,8 @@ AP_DECLARE_DATA int ap_main_state = AP_SQ_MS_INITIAL_STARTUP; + AP_DECLARE_DATA int ap_run_mode = AP_SQ_RM_UNKNOWN; + AP_DECLARE_DATA int ap_config_generation = 0; + ++static const char *core_state_dir; ++ + static void *create_core_dir_config(apr_pool_t *a, char *dir) + { + core_dir_config *conf; +@@ -1444,13 +1446,16 @@ AP_DECLARE(const char *) ap_resolve_env(apr_pool_t *p, const char * word) + return res_buf; + } + +-static int reset_config_defines(void *dummy) ++/* pconf cleanup - clear global variables set from config here. */ ++static apr_status_t reset_config(void *dummy) + { + ap_server_config_defines = saved_server_config_defines; + saved_server_config_defines = NULL; + server_config_defined_vars = NULL; + ap_runtime_dir = NULL; +- return OK; ++ core_state_dir = NULL; ++ ++ return APR_SUCCESS; + } + + /* +@@ -3220,6 +3225,24 @@ static const char *set_runtime_dir(cmd_parms *cmd, void *dummy, const char *arg) + return NULL; + } + ++static const char *set_state_dir(cmd_parms *cmd, void *dummy, const char *arg) ++{ ++ const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); ++ ++ if (err != NULL) { ++ return err; ++ } ++ ++ if ((apr_filepath_merge((char**)&core_state_dir, NULL, ++ ap_server_root_relative(cmd->temp_pool, arg), ++ APR_FILEPATH_TRUENAME, cmd->pool) != APR_SUCCESS) ++ || !ap_is_directory(cmd->temp_pool, core_state_dir)) { ++ return "DefaultStateDir must be a valid directory, absolute or relative to ServerRoot"; ++ } ++ ++ return NULL; ++} ++ + static const char *set_timeout(cmd_parms *cmd, void *dummy, const char *arg) + { + const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_CONTEXT); +@@ -4521,6 +4544,8 @@ AP_INIT_TAKE1("ServerRoot", set_server_root, NULL, RSRC_CONF | EXEC_ON_READ, + "Common directory of server-related files (logs, confs, etc.)"), + AP_INIT_TAKE1("DefaultRuntimeDir", set_runtime_dir, NULL, RSRC_CONF | EXEC_ON_READ, + "Common directory for run-time files (shared memory, locks, etc.)"), ++AP_INIT_TAKE1("DefaultStateDir", set_state_dir, NULL, RSRC_CONF | EXEC_ON_READ, ++ "Common directory for persistent state (databases, long-lived caches, etc.)"), + AP_INIT_TAKE1("ErrorLog", set_server_string_slot, + (void *)APR_OFFSETOF(server_rec, error_fname), RSRC_CONF, + "The filename of the error log"), +@@ -5055,8 +5080,7 @@ static int core_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptem + + if (!saved_server_config_defines) + init_config_defines(pconf); +- apr_pool_cleanup_register(pconf, NULL, reset_config_defines, +- apr_pool_cleanup_null); ++ apr_pool_cleanup_register(pconf, NULL, reset_config, apr_pool_cleanup_null); + + ap_regcomp_set_default_cflags(AP_REG_DEFAULT); + +@@ -5303,6 +5327,27 @@ AP_DECLARE(int) ap_state_query(int query) + } + } + ++AP_DECLARE(char *) ap_state_dir_relative(apr_pool_t *p, const char *file) ++{ ++ char *newpath = NULL; ++ apr_status_t rv; ++ const char *state_dir; ++ ++ state_dir = core_state_dir ++ ? core_state_dir ++ : ap_server_root_relative(p, DEFAULT_REL_STATEDIR); ++ ++ rv = apr_filepath_merge(&newpath, state_dir, file, APR_FILEPATH_TRUENAME, p); ++ if (newpath && (rv == APR_SUCCESS || APR_STATUS_IS_EPATHWILD(rv) ++ || APR_STATUS_IS_ENOENT(rv) ++ || APR_STATUS_IS_ENOTDIR(rv))) { ++ return newpath; ++ } ++ else { ++ return NULL; ++ } ++} ++ + static apr_random_t *rng = NULL; + #if APR_HAS_THREADS + static apr_thread_mutex_t *rng_mutex = NULL; diff --git a/httpd-2.4.48-ssl-proxy-chains.patch b/httpd-2.4.48-ssl-proxy-chains.patch new file mode 100644 index 0000000..95c31c8 --- /dev/null +++ b/httpd-2.4.48-ssl-proxy-chains.patch @@ -0,0 +1,79 @@ +diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c +index 15f68f9..e67c81d 100644 +--- a/modules/ssl/ssl_engine_init.c ++++ b/modules/ssl/ssl_engine_init.c +@@ -1682,6 +1682,10 @@ static apr_status_t ssl_init_proxy_certs(server_rec *s, + STACK_OF(X509) *chain; + X509_STORE_CTX *sctx; + X509_STORE *store = SSL_CTX_get_cert_store(mctx->ssl_ctx); ++ int addl_chain = 0; /* non-zero if additional chain certs were ++ * added to store */ ++ ++ ap_assert(store != NULL); /* safe to assume always non-NULL? */ + + #if OPENSSL_VERSION_NUMBER >= 0x1010100fL + /* For OpenSSL >=1.1.1, turn on client cert support which is +@@ -1707,20 +1711,28 @@ static apr_status_t ssl_init_proxy_certs(server_rec *s, + ssl_init_ca_cert_path(s, ptemp, pkp->cert_path, NULL, sk); + } + +- if ((ncerts = sk_X509_INFO_num(sk)) <= 0) { +- sk_X509_INFO_free(sk); +- ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(02206) +- "no client certs found for SSL proxy"); +- return APR_SUCCESS; +- } +- + /* Check that all client certs have got certificates and private +- * keys. */ +- for (n = 0; n < ncerts; n++) { ++ * keys. Note the number of certs in the stack may decrease ++ * during the loop. */ ++ for (n = 0; n < sk_X509_INFO_num(sk); n++) { + X509_INFO *inf = sk_X509_INFO_value(sk, n); ++ int has_privkey = inf->x_pkey && inf->x_pkey->dec_pkey; + +- if (!inf->x509 || !inf->x_pkey || !inf->x_pkey->dec_pkey || +- inf->enc_data) { ++ /* For a lone certificate in the file, trust it as a ++ * CA/intermediate certificate. */ ++ if (inf->x509 && !has_privkey && !inf->enc_data) { ++ ssl_log_xerror(SSLLOG_MARK, APLOG_DEBUG, 0, ptemp, s, inf->x509, ++ APLOGNO(10261) "Trusting non-leaf certificate"); ++ X509_STORE_add_cert(store, inf->x509); /* increments inf->x509 */ ++ /* Delete from the stack and iterate again. */ ++ X509_INFO_free(inf); ++ sk_X509_INFO_delete(sk, n); ++ n--; ++ addl_chain = 1; ++ continue; ++ } ++ ++ if (!has_privkey || inf->enc_data) { + sk_X509_INFO_free(sk); + ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, APLOGNO(02252) + "incomplete client cert configured for SSL proxy " +@@ -1737,13 +1749,21 @@ static apr_status_t ssl_init_proxy_certs(server_rec *s, + } + } + ++ if ((ncerts = sk_X509_INFO_num(sk)) <= 0) { ++ sk_X509_INFO_free(sk); ++ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(02206) ++ "no client certs found for SSL proxy"); ++ return APR_SUCCESS; ++ } ++ + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(02207) + "loaded %d client certs for SSL proxy", + ncerts); + pkp->certs = sk; + +- +- if (!pkp->ca_cert_file || !store) { ++ /* If any chain certs are configured, build the ->ca_certs chains ++ * corresponding to the loaded keypairs. */ ++ if (!pkp->ca_cert_file && !addl_chain) { + return APR_SUCCESS; + } + diff --git a/httpd-2.4.51-r1811831.patch b/httpd-2.4.51-r1811831.patch new file mode 100644 index 0000000..b8d8215 --- /dev/null +++ b/httpd-2.4.51-r1811831.patch @@ -0,0 +1,81 @@ +diff --git a/server/util_script.c b/server/util_script.c +index 4121ae0..b7f8674 100644 +--- a/server/util_script.c ++++ b/server/util_script.c +@@ -92,9 +92,21 @@ static void add_unless_null(apr_table_t *table, const char *name, const char *va + } + } + +-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 @@ AP_DECLARE(void) ap_add_common_vars(request_rec *r) + 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/httpd-2.4.51-r1877397.patch b/httpd-2.4.51-r1877397.patch new file mode 100644 index 0000000..f629317 --- /dev/null +++ b/httpd-2.4.51-r1877397.patch @@ -0,0 +1,249 @@ +diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c +index 211ebff..c8cb1af 100644 +--- a/modules/ssl/ssl_engine_init.c ++++ b/modules/ssl/ssl_engine_init.c +@@ -871,6 +871,13 @@ static apr_status_t ssl_init_ctx_protocol(server_rec *s, + SSL_CTX_set_keylog_callback(ctx, modssl_callback_keylog); + } + #endif ++ ++#ifdef SSL_OP_NO_RENEGOTIATION ++ /* For server-side SSL_CTX, disable renegotiation by default.. */ ++ if (!mctx->pkp) { ++ SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION); ++ } ++#endif + + return APR_SUCCESS; + } +@@ -892,6 +899,14 @@ static void ssl_init_ctx_session_cache(server_rec *s, + } + } + ++#ifdef SSL_OP_NO_RENEGOTIATION ++/* OpenSSL-level renegotiation protection. */ ++#define MODSSL_BLOCKS_RENEG (0) ++#else ++/* mod_ssl-level renegotiation protection. */ ++#define MODSSL_BLOCKS_RENEG (1) ++#endif ++ + static void ssl_init_ctx_callbacks(server_rec *s, + apr_pool_t *p, + apr_pool_t *ptemp, +@@ -905,7 +920,13 @@ static void ssl_init_ctx_callbacks(server_rec *s, + SSL_CTX_set_tmp_dh_callback(ctx, ssl_callback_TmpDH); + #endif + +- SSL_CTX_set_info_callback(ctx, ssl_callback_Info); ++ /* The info callback is used for debug-level tracing. For OpenSSL ++ * versions where SSL_OP_NO_RENEGOTIATION is not available, the ++ * callback is also used to prevent use of client-initiated ++ * renegotiation. Enable it in either case. */ ++ if (APLOGdebug(s) || MODSSL_BLOCKS_RENEG) { ++ SSL_CTX_set_info_callback(ctx, ssl_callback_Info); ++ } + + #ifdef HAVE_TLS_ALPN + SSL_CTX_set_alpn_select_cb(ctx, ssl_callback_alpn_select, NULL); +diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c +index 79b9a70..3a0c22a 100644 +--- a/modules/ssl/ssl_engine_io.c ++++ b/modules/ssl/ssl_engine_io.c +@@ -209,11 +209,13 @@ static int bio_filter_out_write(BIO *bio, const char *in, int inl) + + BIO_clear_retry_flags(bio); + ++#ifndef SSL_OP_NO_RENEGOTIATION + /* Abort early if the client has initiated a renegotiation. */ + if (outctx->filter_ctx->config->reneg_state == RENEG_ABORT) { + outctx->rc = APR_ECONNABORTED; + return -1; + } ++#endif + + ap_log_cerror(APLOG_MARK, APLOG_TRACE6, 0, outctx->c, + "bio_filter_out_write: %i bytes", inl); +@@ -474,11 +476,13 @@ static int bio_filter_in_read(BIO *bio, char *in, int inlen) + + BIO_clear_retry_flags(bio); + ++#ifndef SSL_OP_NO_RENEGOTIATION + /* Abort early if the client has initiated a renegotiation. */ + if (inctx->filter_ctx->config->reneg_state == RENEG_ABORT) { + inctx->rc = APR_ECONNABORTED; + return -1; + } ++#endif + + if (!inctx->bb) { + inctx->rc = APR_EOF; +diff --git a/modules/ssl/ssl_engine_kernel.c b/modules/ssl/ssl_engine_kernel.c +index 591f6ae..8416864 100644 +--- a/modules/ssl/ssl_engine_kernel.c ++++ b/modules/ssl/ssl_engine_kernel.c +@@ -992,7 +992,7 @@ static int ssl_hook_Access_classic(request_rec *r, SSLSrvConfigRec *sc, SSLDirCo + + /* Toggle the renegotiation state to allow the new + * handshake to proceed. */ +- sslconn->reneg_state = RENEG_ALLOW; ++ modssl_set_reneg_state(sslconn, RENEG_ALLOW); + + SSL_renegotiate(ssl); + SSL_do_handshake(ssl); +@@ -1019,7 +1019,7 @@ static int ssl_hook_Access_classic(request_rec *r, SSLSrvConfigRec *sc, SSLDirCo + */ + SSL_peek(ssl, peekbuf, 0); + +- sslconn->reneg_state = RENEG_REJECT; ++ modssl_set_reneg_state(sslconn, RENEG_REJECT); + + if (!SSL_is_init_finished(ssl)) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(02261) +@@ -1078,7 +1078,7 @@ static int ssl_hook_Access_modern(request_rec *r, SSLSrvConfigRec *sc, SSLDirCon + (sc->server->auth.verify_mode != SSL_CVERIFY_UNSET)) { + int vmode_inplace, vmode_needed; + int change_vmode = FALSE; +- int old_state, n, rc; ++ int n, rc; + + vmode_inplace = SSL_get_verify_mode(ssl); + vmode_needed = SSL_VERIFY_NONE; +@@ -1180,8 +1180,6 @@ static int ssl_hook_Access_modern(request_rec *r, SSLSrvConfigRec *sc, SSLDirCon + return HTTP_FORBIDDEN; + } + +- old_state = sslconn->reneg_state; +- sslconn->reneg_state = RENEG_ALLOW; + modssl_set_app_data2(ssl, r); + + SSL_do_handshake(ssl); +@@ -1191,7 +1189,6 @@ static int ssl_hook_Access_modern(request_rec *r, SSLSrvConfigRec *sc, SSLDirCon + */ + SSL_peek(ssl, peekbuf, 0); + +- sslconn->reneg_state = old_state; + modssl_set_app_data2(ssl, NULL); + + /* +@@ -2263,8 +2260,8 @@ static void log_tracing_state(const SSL *ssl, conn_rec *c, + /* + * This callback function is executed while OpenSSL processes the SSL + * handshake and does SSL record layer stuff. It's used to trap +- * client-initiated renegotiations, and for dumping everything to the +- * log. ++ * client-initiated renegotiations (where SSL_OP_NO_RENEGOTIATION is ++ * not available), and for dumping everything to the log. + */ + void ssl_callback_Info(const SSL *ssl, int where, int rc) + { +@@ -2276,14 +2273,12 @@ void ssl_callback_Info(const SSL *ssl, int where, int rc) + return; + } + +- /* With TLS 1.3 this callback may be called multiple times on the first +- * negotiation, so the below logic to detect renegotiations can't work. +- * Fortunately renegotiations are forbidden starting with TLS 1.3, and +- * this is enforced by OpenSSL so there's nothing to be done here. +- */ +-#if SSL_HAVE_PROTOCOL_TLSV1_3 +- if (SSL_version(ssl) < TLS1_3_VERSION) +-#endif ++#ifndef SSL_OP_NO_RENEGOTIATION ++ /* With OpenSSL < 1.1.1 (implying TLS v1.2 or earlier), this ++ * callback is used to block client-initiated renegotiation. With ++ * TLSv1.3 it is unnecessary since renegotiation is forbidden at ++ * protocol level. Otherwise (TLSv1.2 with OpenSSL >=1.1.1), ++ * SSL_OP_NO_RENEGOTIATION is used to block renegotiation. */ + { + SSLConnRec *sslconn; + +@@ -2308,6 +2303,7 @@ void ssl_callback_Info(const SSL *ssl, int where, int rc) + sslconn->reneg_state = RENEG_REJECT; + } + } ++#endif + + s = mySrvFromConn(c); + if (s && APLOGdebug(s)) { +diff --git a/modules/ssl/ssl_private.h b/modules/ssl/ssl_private.h +index a329d99..7666c31 100644 +--- a/modules/ssl/ssl_private.h ++++ b/modules/ssl/ssl_private.h +@@ -512,6 +512,16 @@ typedef struct { + apr_time_t source_mtime; + } ssl_asn1_t; + ++typedef enum { ++ RENEG_INIT = 0, /* Before initial handshake */ ++ RENEG_REJECT, /* After initial handshake; any client-initiated ++ * renegotiation should be rejected */ ++ RENEG_ALLOW, /* A server-initiated renegotiation is taking ++ * place (as dictated by configuration) */ ++ RENEG_ABORT /* Renegotiation initiated by client, abort the ++ * connection */ ++} modssl_reneg_state; ++ + /** + * Define the mod_ssl per-module configuration structure + * (i.e. the global configuration for each httpd process) +@@ -543,18 +553,13 @@ typedef struct { + NON_SSL_SET_ERROR_MSG /* Need to set the error message */ + } non_ssl_request; + +- /* Track the handshake/renegotiation state for the connection so +- * that all client-initiated renegotiations can be rejected, as a +- * partial fix for CVE-2009-3555. */ +- enum { +- RENEG_INIT = 0, /* Before initial handshake */ +- RENEG_REJECT, /* After initial handshake; any client-initiated +- * renegotiation should be rejected */ +- RENEG_ALLOW, /* A server-initiated renegotiation is taking +- * place (as dictated by configuration) */ +- RENEG_ABORT /* Renegotiation initiated by client, abort the +- * connection */ +- } reneg_state; ++#ifndef SSL_OP_NO_RENEGOTIATION ++ /* For OpenSSL < 1.1.1, track the handshake/renegotiation state ++ * for the connection to block client-initiated renegotiations. ++ * For OpenSSL >=1.1.1, the SSL_OP_NO_RENEGOTIATION flag is used in ++ * the SSL * options state with equivalent effect. */ ++ modssl_reneg_state reneg_state; ++#endif + + server_rec *server; + SSLDirConfigRec *dc; +@@ -1158,6 +1163,9 @@ int ssl_is_challenge(conn_rec *c, const char *servername, + * the configured ENGINE. */ + int modssl_is_engine_id(const char *name); + ++/* Set the renegotation state for connection. */ ++void modssl_set_reneg_state(SSLConnRec *sslconn, modssl_reneg_state state); ++ + #endif /* SSL_PRIVATE_H */ + /** @} */ + +diff --git a/modules/ssl/ssl_util_ssl.c b/modules/ssl/ssl_util_ssl.c +index 38079a9..dafb833 100644 +--- a/modules/ssl/ssl_util_ssl.c ++++ b/modules/ssl/ssl_util_ssl.c +@@ -589,3 +589,19 @@ cleanup: + } + return rv; + } ++ ++void modssl_set_reneg_state(SSLConnRec *sslconn, modssl_reneg_state state) ++{ ++#ifdef SSL_OP_NO_RENEGOTIATION ++ switch (state) { ++ case RENEG_ALLOW: ++ SSL_clear_options(sslconn->ssl, SSL_OP_NO_RENEGOTIATION); ++ break; ++ default: ++ SSL_set_options(sslconn->ssl, SSL_OP_NO_RENEGOTIATION); ++ break; ++ } ++#else ++ sslconn->reneg_state = state; ++#endif ++} diff --git a/httpd-2.4.51-r1892413+.patch b/httpd-2.4.51-r1892413+.patch new file mode 100644 index 0000000..59e2319 --- /dev/null +++ b/httpd-2.4.51-r1892413+.patch @@ -0,0 +1,156 @@ +# ./pullrev.sh 1892413 1895552 + +https://bugzilla.redhat.com/show_bug.cgi?id=1938740 + +http://svn.apache.org/viewvc?view=revision&revision=1892413 +http://svn.apache.org/viewvc?view=revision&revision=1895552 + +- also mod_cgi/mod_cgid log_flags fix from r1881559 + +--- httpd-2.4.51/modules/filters/mod_deflate.c.r1892413+ ++++ httpd-2.4.51/modules/filters/mod_deflate.c +@@ -1275,44 +1275,46 @@ + if (APR_BUCKET_IS_FLUSH(bkt)) { + apr_bucket *tmp_b; + +- ctx->inflate_total += ctx->stream.avail_out; +- zRC = inflate(&(ctx->stream), Z_SYNC_FLUSH); +- ctx->inflate_total -= ctx->stream.avail_out; +- if (zRC != Z_OK) { +- inflateEnd(&ctx->stream); +- ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01391) +- "Zlib error %d inflating data (%s)", zRC, +- ctx->stream.msg); +- return APR_EGENERAL; +- } ++ if (!ctx->done) { ++ ctx->inflate_total += ctx->stream.avail_out; ++ zRC = inflate(&(ctx->stream), Z_SYNC_FLUSH); ++ ctx->inflate_total -= ctx->stream.avail_out; ++ if (zRC != Z_OK) { ++ inflateEnd(&ctx->stream); ++ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01391) ++ "Zlib error %d inflating data (%s)", zRC, ++ ctx->stream.msg); ++ return APR_EGENERAL; ++ } + +- 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; +- } ++ 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; ++ } + +- if (!check_ratio(r, ctx, dc)) { +- inflateEnd(&ctx->stream); +- ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(02805) +- "Inflated content ratio is larger than the " +- "configured limit %i by %i time(s)", +- dc->ratio_limit, dc->ratio_burst); +- return APR_EINVAL; +- } ++ if (!check_ratio(r, ctx, dc)) { ++ inflateEnd(&ctx->stream); ++ ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(02805) ++ "Inflated content ratio is larger than the " ++ "configured limit %i by %i time(s)", ++ dc->ratio_limit, dc->ratio_burst); ++ return APR_EINVAL; ++ } + +- len = c->bufferSize - ctx->stream.avail_out; +- ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len); +- tmp_b = apr_bucket_heap_create((char *)ctx->buffer, len, +- NULL, f->c->bucket_alloc); +- APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, tmp_b); ++ len = c->bufferSize - ctx->stream.avail_out; ++ ctx->crc = crc32(ctx->crc, (const Bytef *)ctx->buffer, len); ++ tmp_b = apr_bucket_heap_create((char *)ctx->buffer, len, ++ NULL, f->c->bucket_alloc); ++ APR_BRIGADE_INSERT_TAIL(ctx->proc_bb, tmp_b); + +- ctx->stream.next_out = ctx->buffer; +- ctx->stream.avail_out = c->bufferSize; ++ ctx->stream.next_out = ctx->buffer; ++ ctx->stream.avail_out = c->bufferSize; ++ } + + /* Flush everything so far in the returning brigade, but continue + * reading should EOS/more follow (don't lose them). +--- httpd-2.4.51/modules/generators/mod_cgi.c.r1892413+ ++++ httpd-2.4.51/modules/generators/mod_cgi.c +@@ -191,11 +191,10 @@ + apr_file_t *f = NULL; + apr_finfo_t finfo; + char time_str[APR_CTIME_LEN]; +- int log_flags = rv ? APLOG_ERR : APLOG_ERR; + + /* Intentional no APLOGNO */ + /* Callee provides APLOGNO in error text */ +- ap_log_rerror(APLOG_MARK, log_flags, rv, r, ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, + "%s%s: %s", logno ? logno : "", error, r->filename); + + /* XXX Very expensive mainline case! Open, then getfileinfo! */ +--- httpd-2.4.51/modules/generators/mod_cgid.c.r1892413+ ++++ httpd-2.4.51/modules/generators/mod_cgid.c +@@ -1190,11 +1190,10 @@ + apr_file_t *f = NULL; + struct stat finfo; + char time_str[APR_CTIME_LEN]; +- int log_flags = rv ? APLOG_ERR : APLOG_ERR; + + /* Intentional no APLOGNO */ + /* Callee provides APLOGNO in error text */ +- ap_log_rerror(APLOG_MARK, log_flags, rv, r, ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, + "%s: %s", error, r->filename); + + /* XXX Very expensive mainline case! Open, then getfileinfo! */ +--- httpd-2.4.51/server/mpm_unix.c.r1892413+ ++++ httpd-2.4.51/server/mpm_unix.c +@@ -259,10 +259,12 @@ + while (cur_extra) { + ap_generation_t old_gen; + extra_process_t *next = cur_extra->next; ++ pid_t pid = cur_extra->pid; + +- if (reclaim_one_pid(cur_extra->pid, action_table[cur_action].action)) { +- if (ap_unregister_extra_mpm_process(cur_extra->pid, &old_gen) == 1) { +- mpm_callback(-1, cur_extra->pid, old_gen); ++ if (reclaim_one_pid(pid, action_table[cur_action].action)) { ++ if (ap_unregister_extra_mpm_process(pid, &old_gen) == 1) { ++ /* cur_extra dangling pointer from here. */ ++ mpm_callback(-1, pid, old_gen); + } + else { + AP_DEBUG_ASSERT(1 == 0); +@@ -307,10 +309,12 @@ + while (cur_extra) { + ap_generation_t old_gen; + extra_process_t *next = cur_extra->next; ++ pid_t pid = cur_extra->pid; + +- if (reclaim_one_pid(cur_extra->pid, DO_NOTHING)) { +- if (ap_unregister_extra_mpm_process(cur_extra->pid, &old_gen) == 1) { +- mpm_callback(-1, cur_extra->pid, old_gen); ++ if (reclaim_one_pid(pid, DO_NOTHING)) { ++ if (ap_unregister_extra_mpm_process(pid, &old_gen) == 1) { ++ /* cur_extra dangling pointer from here. */ ++ mpm_callback(-1, pid, old_gen); + } + else { + AP_DEBUG_ASSERT(1 == 0); diff --git a/httpd-2.4.53-CVE-2022-26377.patch b/httpd-2.4.53-CVE-2022-26377.patch new file mode 100644 index 0000000..0b05fec --- /dev/null +++ b/httpd-2.4.53-CVE-2022-26377.patch @@ -0,0 +1,26 @@ +diff --git a/modules/proxy/mod_proxy_ajp.c b/modules/proxy/mod_proxy_ajp.c +index e2992fc..46d42bc 100644 +--- a/modules/proxy/mod_proxy_ajp.c ++++ b/modules/proxy/mod_proxy_ajp.c +@@ -246,9 +246,18 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r, + /* read the first block of data */ + input_brigade = apr_brigade_create(p, r->connection->bucket_alloc); + tenc = apr_table_get(r->headers_in, "Transfer-Encoding"); +- if (tenc && (ap_cstr_casecmp(tenc, "chunked") == 0)) { +- /* The AJP protocol does not want body data yet */ +- ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00870) "request is chunked"); ++ if (tenc) { ++ if (ap_cstr_casecmp(tenc, "chunked") == 0) { ++ /* The AJP protocol does not want body data yet */ ++ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(00870) ++ "request is chunked"); ++ } ++ else { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10396) ++ "%s Transfer-Encoding is not supported", ++ tenc); ++ return HTTP_INTERNAL_SERVER_ERROR; ++ } + } else { + /* Get client provided Content-Length header */ + content_length = get_content_length(r); diff --git a/httpd-2.4.53-CVE-2022-28614.patch b/httpd-2.4.53-CVE-2022-28614.patch new file mode 100644 index 0000000..ef2b535 --- /dev/null +++ b/httpd-2.4.53-CVE-2022-28614.patch @@ -0,0 +1,61 @@ +From 8c14927162cf3b4f810683e1c5505e9ef9e1f123 Mon Sep 17 00:00:00 2001 +From: Eric Covener +Date: Wed, 1 Jun 2022 12:34:16 +0000 +Subject: [PATCH] Merge r1901500 from trunk: + +handle large writes in ap_rputs + + +git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1901501 13f79535-47bb-0310-9956-ffa450edef68 +--- + include/http_protocol.h | 22 +++++++++++++++++++++- + server/protocol.c | 3 +++ + 2 files changed, 24 insertions(+), 1 deletion(-) + +diff --git a/include/http_protocol.h b/include/http_protocol.h +index 20bd2022266..94c481e5f43 100644 +--- a/include/http_protocol.h ++++ b/include/http_protocol.h +@@ -475,7 +475,27 @@ AP_DECLARE(int) ap_rwrite(const void *buf, int nbyte, request_rec *r); + */ + static APR_INLINE int ap_rputs(const char *str, request_rec *r) + { +- return ap_rwrite(str, (int)strlen(str), r); ++ apr_size_t len; ++ ++ len = strlen(str); ++ ++ for (;;) { ++ if (len <= INT_MAX) { ++ return ap_rwrite(str, (int)len, r); ++ } ++ else { ++ int rc; ++ ++ rc = ap_rwrite(str, INT_MAX, r); ++ if (rc < 0) { ++ return rc; ++ } ++ else { ++ str += INT_MAX; ++ len -= INT_MAX; ++ } ++ } ++ } + } + + /** +diff --git a/server/protocol.c b/server/protocol.c +index 298f61e1fb8..7adc7f75c10 100644 +--- a/server/protocol.c ++++ b/server/protocol.c +@@ -2128,6 +2128,9 @@ AP_DECLARE(int) ap_rputc(int c, request_rec *r) + + AP_DECLARE(int) ap_rwrite(const void *buf, int nbyte, request_rec *r) + { ++ if (nbyte < 0) ++ return -1; ++ + if (r->connection->aborted) + return -1; + diff --git a/httpd-2.4.53-CVE-2022-28615.patch b/httpd-2.4.53-CVE-2022-28615.patch new file mode 100644 index 0000000..75a3d0f --- /dev/null +++ b/httpd-2.4.53-CVE-2022-28615.patch @@ -0,0 +1,22 @@ +diff --git a/server/util.c b/server/util.c +index 604be1a..6808164 100644 +--- a/server/util.c ++++ b/server/util.c +@@ -185,7 +185,7 @@ AP_DECLARE(char *) ap_ht_time(apr_pool_t *p, apr_time_t t, const char *fmt, + */ + AP_DECLARE(int) ap_strcmp_match(const char *str, const char *expected) + { +- int x, y; ++ apr_size_t x, y; + + for (x = 0, y = 0; expected[y]; ++y, ++x) { + if (expected[y] == '*') { +@@ -209,7 +209,7 @@ AP_DECLARE(int) ap_strcmp_match(const char *str, const char *expected) + + AP_DECLARE(int) ap_strcasecmp_match(const char *str, const char *expected) + { +- int x, y; ++ apr_size_t x, y; + + for (x = 0, y = 0; expected[y]; ++y, ++x) { + if (!str[x] && expected[y] != '*') diff --git a/httpd-2.4.53-CVE-2022-29404.patch b/httpd-2.4.53-CVE-2022-29404.patch new file mode 100644 index 0000000..df4f70f --- /dev/null +++ b/httpd-2.4.53-CVE-2022-29404.patch @@ -0,0 +1,126 @@ +diff --git a/docs/manual/mod/core.html.en b/docs/manual/mod/core.html.en +index bb6b90a..d14aed4 100644 +--- a/docs/manual/mod/core.html.en ++++ b/docs/manual/mod/core.html.en +@@ -2796,16 +2796,16 @@ subrequests + Description:Restricts the total size of the HTTP request body sent + from the client + Syntax:LimitRequestBody bytes +-Default:LimitRequestBody 0 ++Default:LimitRequestBody 1073741824 + Context:server config, virtual host, directory, .htaccess + Override:All + Status:Core + Module:core ++Compatibility:In Apache HTTP Server 2.4.53 and earlier, the default value ++ was 0 (unlimited) + +-

    This directive specifies the number of bytes from 0 +- (meaning unlimited) to 2147483647 (2GB) that are allowed in a +- request body. See the note below for the limited applicability +- to proxy requests.

    ++

    This directive specifies the number of bytes ++ that are allowed in a request body. A value of 0 means unlimited.

    + +

    The LimitRequestBody directive allows + the user to set a limit on the allowed size of an HTTP request +@@ -2831,12 +2831,6 @@ from the client + +

    LimitRequestBody 102400
    + +- +-

    For a full description of how this directive is interpreted by +- proxy requests, see the mod_proxy documentation.

    +-
    +- +- +
    +
    top
    +

    LimitRequestFields Directive

    +diff --git a/docs/manual/mod/mod_proxy.html.en b/docs/manual/mod/mod_proxy.html.en +index ee7b1e3..233d234 100644 +--- a/docs/manual/mod/mod_proxy.html.en ++++ b/docs/manual/mod/mod_proxy.html.en +@@ -463,9 +463,6 @@ ProxyPass "/examples" "http://backend.example.com/examples" timeout=10 + Content-Length header, but the server is configured to filter incoming + request bodies.

    + +-

    LimitRequestBody only applies to +- request bodies that the server will spool to disk

    +- +
    top
    +
    +

    Reverse Proxy Request Headers

    +diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c +index 43e8c6d..33c78f3 100644 +--- a/modules/http/http_filters.c ++++ b/modules/http/http_filters.c +@@ -1703,6 +1703,7 @@ AP_DECLARE(int) ap_setup_client_block(request_rec *r, int read_policy) + { + const char *tenc = apr_table_get(r->headers_in, "Transfer-Encoding"); + const char *lenp = apr_table_get(r->headers_in, "Content-Length"); ++ apr_off_t limit_req_body = ap_get_limit_req_body(r); + + r->read_body = read_policy; + r->read_chunked = 0; +@@ -1738,6 +1739,11 @@ AP_DECLARE(int) ap_setup_client_block(request_rec *r, int read_policy) + return HTTP_REQUEST_ENTITY_TOO_LARGE; + } + ++ if (limit_req_body > 0 && (r->remaining > limit_req_body)) { ++ /* will be logged when the body is discarded */ ++ return HTTP_REQUEST_ENTITY_TOO_LARGE; ++ } ++ + #ifdef AP_DEBUG + { + /* Make sure ap_getline() didn't leave any droppings. */ +diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c +index bc86253..85f2f9c 100644 +--- a/modules/proxy/proxy_util.c ++++ b/modules/proxy/proxy_util.c +@@ -4260,13 +4260,10 @@ PROXY_DECLARE(int) ap_proxy_spool_input(request_rec *r, + apr_bucket *e; + apr_off_t bytes, fsize = 0; + apr_file_t *tmpfile = NULL; +- apr_off_t limit; + + *bytes_spooled = 0; + body_brigade = apr_brigade_create(p, bucket_alloc); + +- limit = ap_get_limit_req_body(r); +- + do { + if (APR_BRIGADE_EMPTY(input_brigade)) { + rv = ap_proxy_read_input(r, backend, input_brigade, +@@ -4284,17 +4281,6 @@ PROXY_DECLARE(int) ap_proxy_spool_input(request_rec *r, + apr_brigade_length(input_brigade, 1, &bytes); + + if (*bytes_spooled + bytes > max_mem_spool) { +- /* +- * LimitRequestBody does not affect Proxy requests (Should it?). +- * Let it take effect if we decide to store the body in a +- * temporary file on disk. +- */ +- if (limit && (*bytes_spooled + bytes > limit)) { +- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(01088) +- "Request body is larger than the configured " +- "limit of %" APR_OFF_T_FMT, limit); +- return HTTP_REQUEST_ENTITY_TOO_LARGE; +- } + /* can't spool any more in memory; write latest brigade to disk */ + if (tmpfile == NULL) { + const char *temp_dir; +diff --git a/server/core.c b/server/core.c +index 3d44e0e..682259f 100644 +--- a/server/core.c ++++ b/server/core.c +@@ -71,7 +71,7 @@ + + /* LimitRequestBody handling */ + #define AP_LIMIT_REQ_BODY_UNSET ((apr_off_t) -1) +-#define AP_DEFAULT_LIMIT_REQ_BODY ((apr_off_t) 0) ++#define AP_DEFAULT_LIMIT_REQ_BODY ((apr_off_t) 1<<30) /* 1GB */ + + /* LimitXMLRequestBody handling */ + #define AP_LIMIT_UNSET ((long) -1) diff --git a/httpd-2.4.53-CVE-2022-30522.patch b/httpd-2.4.53-CVE-2022-30522.patch new file mode 100644 index 0000000..50e0ea3 --- /dev/null +++ b/httpd-2.4.53-CVE-2022-30522.patch @@ -0,0 +1,557 @@ +From db47781128e42bd49f55076665b3f6ca4e2bc5e2 Mon Sep 17 00:00:00 2001 +From: Eric Covener +Date: Wed, 1 Jun 2022 12:50:40 +0000 +Subject: [PATCH] Merge r1901506 from trunk: + +limit mod_sed memory use + +Resync mod_sed.c with trunk due to merge conflicts. + + +git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1901509 13f79535-47bb-0310-9956-ffa450edef68 +--- + modules/filters/mod_sed.c | 75 ++++++++---------- + modules/filters/sed1.c | 158 +++++++++++++++++++++++++++----------- + 2 files changed, 147 insertions(+), 86 deletions(-) + +diff --git a/modules/filters/mod_sed.c b/modules/filters/mod_sed.c +index 4bdb4ce33ae..12cb04a20f9 100644 +--- a/modules/filters/mod_sed.c ++++ b/modules/filters/mod_sed.c +@@ -59,7 +59,7 @@ typedef struct sed_filter_ctxt + module AP_MODULE_DECLARE_DATA sed_module; + + /* This function will be call back from libsed functions if there is any error +- * happend during execution of sed scripts ++ * happened during execution of sed scripts + */ + static apr_status_t log_sed_errf(void *data, const char *error) + { +@@ -277,7 +277,7 @@ static apr_status_t sed_response_filter(ap_filter_t *f, + apr_bucket_brigade *bb) + { + apr_bucket *b; +- apr_status_t status; ++ apr_status_t status = APR_SUCCESS; + sed_config *cfg = ap_get_module_config(f->r->per_dir_config, + &sed_module); + sed_filter_ctxt *ctx = f->ctx; +@@ -302,9 +302,9 @@ static apr_status_t sed_response_filter(ap_filter_t *f, + return status; + ctx = f->ctx; + apr_table_unset(f->r->headers_out, "Content-Length"); +- } + +- ctx->bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc); ++ ctx->bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc); ++ } + + /* Here is the main logic. Iterate through all the buckets, read the + * content of the bucket, call sed_eval_buffer on the data. +@@ -326,63 +326,52 @@ static apr_status_t sed_response_filter(ap_filter_t *f, + * in sed's internal buffer which can't be flushed until new line + * character is arrived. + */ +- for (b = APR_BRIGADE_FIRST(bb); b != APR_BRIGADE_SENTINEL(bb);) { +- const char *buf = NULL; +- apr_size_t bytes = 0; ++ while (!APR_BRIGADE_EMPTY(bb)) { ++ b = APR_BRIGADE_FIRST(bb); + if (APR_BUCKET_IS_EOS(b)) { +- apr_bucket *b1 = APR_BUCKET_NEXT(b); + /* Now clean up the internal sed buffer */ + sed_finalize_eval(&ctx->eval, ctx); + status = flush_output_buffer(ctx); + if (status != APR_SUCCESS) { +- clear_ctxpool(ctx); +- return status; ++ break; + } ++ /* Move the eos bucket to ctx->bb brigade */ + APR_BUCKET_REMOVE(b); +- /* Insert the eos bucket to ctx->bb brigade */ + APR_BRIGADE_INSERT_TAIL(ctx->bb, b); +- b = b1; + } + else if (APR_BUCKET_IS_FLUSH(b)) { +- apr_bucket *b1 = APR_BUCKET_NEXT(b); +- APR_BUCKET_REMOVE(b); + status = flush_output_buffer(ctx); + if (status != APR_SUCCESS) { +- clear_ctxpool(ctx); +- return status; ++ break; + } ++ /* Move the flush bucket to ctx->bb brigade */ ++ APR_BUCKET_REMOVE(b); + APR_BRIGADE_INSERT_TAIL(ctx->bb, b); +- b = b1; +- } +- else if (APR_BUCKET_IS_METADATA(b)) { +- b = APR_BUCKET_NEXT(b); + } +- else if (apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ) +- == APR_SUCCESS) { +- apr_bucket *b1 = APR_BUCKET_NEXT(b); +- status = sed_eval_buffer(&ctx->eval, buf, bytes, ctx); +- if (status != APR_SUCCESS) { +- clear_ctxpool(ctx); +- return status; ++ else { ++ if (!APR_BUCKET_IS_METADATA(b)) { ++ const char *buf = NULL; ++ apr_size_t bytes = 0; ++ ++ status = apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ); ++ if (status == APR_SUCCESS) { ++ status = sed_eval_buffer(&ctx->eval, buf, bytes, ctx); ++ } ++ if (status != APR_SUCCESS) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, status, f->r, APLOGNO(10394) "error evaluating sed on output"); ++ break; ++ } + } +- APR_BUCKET_REMOVE(b); + apr_bucket_delete(b); +- b = b1; +- } +- else { +- apr_bucket *b1 = APR_BUCKET_NEXT(b); +- APR_BUCKET_REMOVE(b); +- b = b1; + } + } +- apr_brigade_cleanup(bb); +- status = flush_output_buffer(ctx); +- if (status != APR_SUCCESS) { +- clear_ctxpool(ctx); +- return status; ++ if (status == APR_SUCCESS) { ++ status = flush_output_buffer(ctx); + } + if (!APR_BRIGADE_EMPTY(ctx->bb)) { +- status = ap_pass_brigade(f->next, ctx->bb); ++ if (status == APR_SUCCESS) { ++ status = ap_pass_brigade(f->next, ctx->bb); ++ } + apr_brigade_cleanup(ctx->bb); + } + clear_ctxpool(ctx); +@@ -433,7 +422,7 @@ static apr_status_t sed_request_filter(ap_filter_t *f, + * the buckets in bbinp and read the data from buckets and invoke + * sed_eval_buffer on the data. libsed will generate its output using + * sed_write_output which will add data in ctx->bb. Do it until it have +- * atleast one bucket in ctx->bb. At the end of data eos bucket ++ * at least one bucket in ctx->bb. At the end of data eos bucket + * should be there. + * + * Once eos bucket is seen, then invoke sed_finalize_eval to clear the +@@ -475,8 +464,10 @@ static apr_status_t sed_request_filter(ap_filter_t *f, + if (apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ) + == APR_SUCCESS) { + status = sed_eval_buffer(&ctx->eval, buf, bytes, ctx); +- if (status != APR_SUCCESS) ++ if (status != APR_SUCCESS) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, status, f->r, APLOGNO(10395) "error evaluating sed on input"); + return status; ++ } + flush_output_buffer(ctx); + } + } +diff --git a/modules/filters/sed1.c b/modules/filters/sed1.c +index 67a8d06515e..047f49ba131 100644 +--- a/modules/filters/sed1.c ++++ b/modules/filters/sed1.c +@@ -87,18 +87,20 @@ static void eval_errf(sed_eval_t *eval, const char *fmt, ...) + } + + #define INIT_BUF_SIZE 1024 ++#define MAX_BUF_SIZE 1024*8192 + + /* + * grow_buffer + */ +-static void grow_buffer(apr_pool_t *pool, char **buffer, ++static apr_status_t grow_buffer(apr_pool_t *pool, char **buffer, + char **spend, apr_size_t *cursize, + apr_size_t newsize) + { + char* newbuffer = NULL; + apr_size_t spendsize = 0; +- if (*cursize >= newsize) +- return; ++ if (*cursize >= newsize) { ++ return APR_SUCCESS; ++ } + /* Avoid number of times realloc is called. It could cause huge memory + * requirement if line size is huge e.g 2 MB */ + if (newsize < *cursize * 2) { +@@ -107,6 +109,9 @@ static void grow_buffer(apr_pool_t *pool, char **buffer, + + /* Align it to 4 KB boundary */ + newsize = (newsize + ((1 << 12) - 1)) & ~((1 << 12) - 1); ++ if (newsize > MAX_BUF_SIZE) { ++ return APR_ENOMEM; ++ } + newbuffer = apr_pcalloc(pool, newsize); + if (*spend && *buffer && (*cursize > 0)) { + spendsize = *spend - *buffer; +@@ -119,63 +124,77 @@ static void grow_buffer(apr_pool_t *pool, char **buffer, + if (spend != buffer) { + *spend = *buffer + spendsize; + } ++ return APR_SUCCESS; + } + + /* + * grow_line_buffer + */ +-static void grow_line_buffer(sed_eval_t *eval, apr_size_t newsize) ++static apr_status_t grow_line_buffer(sed_eval_t *eval, apr_size_t newsize) + { +- grow_buffer(eval->pool, &eval->linebuf, &eval->lspend, ++ return grow_buffer(eval->pool, &eval->linebuf, &eval->lspend, + &eval->lsize, newsize); + } + + /* + * grow_hold_buffer + */ +-static void grow_hold_buffer(sed_eval_t *eval, apr_size_t newsize) ++static apr_status_t grow_hold_buffer(sed_eval_t *eval, apr_size_t newsize) + { +- grow_buffer(eval->pool, &eval->holdbuf, &eval->hspend, ++ return grow_buffer(eval->pool, &eval->holdbuf, &eval->hspend, + &eval->hsize, newsize); + } + + /* + * grow_gen_buffer + */ +-static void grow_gen_buffer(sed_eval_t *eval, apr_size_t newsize, ++static apr_status_t grow_gen_buffer(sed_eval_t *eval, apr_size_t newsize, + char **gspend) + { ++ apr_status_t rc = 0; + if (gspend == NULL) { + gspend = &eval->genbuf; + } +- grow_buffer(eval->pool, &eval->genbuf, gspend, +- &eval->gsize, newsize); +- eval->lcomend = &eval->genbuf[71]; ++ rc = grow_buffer(eval->pool, &eval->genbuf, gspend, ++ &eval->gsize, newsize); ++ if (rc == APR_SUCCESS) { ++ eval->lcomend = &eval->genbuf[71]; ++ } ++ return rc; + } + + /* + * appendmem_to_linebuf + */ +-static void appendmem_to_linebuf(sed_eval_t *eval, const char* sz, apr_size_t len) ++static apr_status_t appendmem_to_linebuf(sed_eval_t *eval, const char* sz, apr_size_t len) + { ++ apr_status_t rc = 0; + apr_size_t reqsize = (eval->lspend - eval->linebuf) + len; + if (eval->lsize < reqsize) { +- grow_line_buffer(eval, reqsize); ++ rc = grow_line_buffer(eval, reqsize); ++ if (rc != APR_SUCCESS) { ++ return rc; ++ } + } + memcpy(eval->lspend, sz, len); + eval->lspend += len; ++ return APR_SUCCESS; + } + + /* + * append_to_linebuf + */ +-static void append_to_linebuf(sed_eval_t *eval, const char* sz, ++static apr_status_t append_to_linebuf(sed_eval_t *eval, const char* sz, + step_vars_storage *step_vars) + { + apr_size_t len = strlen(sz); + char *old_linebuf = eval->linebuf; ++ apr_status_t rc = 0; + /* Copy string including null character */ +- appendmem_to_linebuf(eval, sz, len + 1); ++ rc = appendmem_to_linebuf(eval, sz, len + 1); ++ if (rc != APR_SUCCESS) { ++ return rc; ++ } + --eval->lspend; /* lspend will now point to NULL character */ + /* Sync step_vars after a possible linebuf expansion */ + if (step_vars && old_linebuf != eval->linebuf) { +@@ -189,68 +208,84 @@ static void append_to_linebuf(sed_eval_t *eval, const char* sz, + step_vars->locs = step_vars->locs - old_linebuf + eval->linebuf; + } + } ++ return APR_SUCCESS; + } + + /* + * copy_to_linebuf + */ +-static void copy_to_linebuf(sed_eval_t *eval, const char* sz, ++static apr_status_t copy_to_linebuf(sed_eval_t *eval, const char* sz, + step_vars_storage *step_vars) + { + eval->lspend = eval->linebuf; +- append_to_linebuf(eval, sz, step_vars); ++ return append_to_linebuf(eval, sz, step_vars); + } + + /* + * append_to_holdbuf + */ +-static void append_to_holdbuf(sed_eval_t *eval, const char* sz) ++static apr_status_t append_to_holdbuf(sed_eval_t *eval, const char* sz) + { + apr_size_t len = strlen(sz); + apr_size_t reqsize = (eval->hspend - eval->holdbuf) + len + 1; ++ apr_status_t rc = 0; + if (eval->hsize <= reqsize) { +- grow_hold_buffer(eval, reqsize); ++ rc = grow_hold_buffer(eval, reqsize); ++ if (rc != APR_SUCCESS) { ++ return rc; ++ } + } + memcpy(eval->hspend, sz, len + 1); + /* hspend will now point to NULL character */ + eval->hspend += len; ++ return APR_SUCCESS; + } + + /* + * copy_to_holdbuf + */ +-static void copy_to_holdbuf(sed_eval_t *eval, const char* sz) ++static apr_status_t copy_to_holdbuf(sed_eval_t *eval, const char* sz) + { + eval->hspend = eval->holdbuf; +- append_to_holdbuf(eval, sz); ++ return append_to_holdbuf(eval, sz); + } + + /* + * append_to_genbuf + */ +-static void append_to_genbuf(sed_eval_t *eval, const char* sz, char **gspend) ++static apr_status_t append_to_genbuf(sed_eval_t *eval, const char* sz, char **gspend) + { + apr_size_t len = strlen(sz); + apr_size_t reqsize = (*gspend - eval->genbuf) + len + 1; ++ apr_status_t rc = 0; + if (eval->gsize < reqsize) { +- grow_gen_buffer(eval, reqsize, gspend); ++ rc = grow_gen_buffer(eval, reqsize, gspend); ++ if (rc != APR_SUCCESS) { ++ return rc; ++ } + } + memcpy(*gspend, sz, len + 1); + /* *gspend will now point to NULL character */ + *gspend += len; ++ return APR_SUCCESS; + } + + /* + * copy_to_genbuf + */ +-static void copy_to_genbuf(sed_eval_t *eval, const char* sz) ++static apr_status_t copy_to_genbuf(sed_eval_t *eval, const char* sz) + { + apr_size_t len = strlen(sz); + apr_size_t reqsize = len + 1; ++ apr_status_t rc = APR_SUCCESS;; + if (eval->gsize < reqsize) { +- grow_gen_buffer(eval, reqsize, NULL); ++ rc = grow_gen_buffer(eval, reqsize, NULL); ++ if (rc != APR_SUCCESS) { ++ return rc; ++ } + } + memcpy(eval->genbuf, sz, len + 1); ++ return rc; + } + + /* +@@ -397,6 +432,7 @@ apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, apr_size_t bufsz + } + + while (bufsz) { ++ apr_status_t rc = 0; + char *n; + apr_size_t llen; + +@@ -411,7 +447,10 @@ apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, apr_size_t bufsz + break; + } + +- appendmem_to_linebuf(eval, buf, llen + 1); ++ rc = appendmem_to_linebuf(eval, buf, llen + 1); ++ if (rc != APR_SUCCESS) { ++ return rc; ++ } + --eval->lspend; + /* replace new line character with NULL */ + *eval->lspend = '\0'; +@@ -426,7 +465,10 @@ apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, apr_size_t bufsz + + /* Save the leftovers for later */ + if (bufsz) { +- appendmem_to_linebuf(eval, buf, bufsz); ++ apr_status_t rc = appendmem_to_linebuf(eval, buf, bufsz); ++ if (rc != APR_SUCCESS) { ++ return rc; ++ } + } + + return APR_SUCCESS; +@@ -448,6 +490,7 @@ apr_status_t sed_finalize_eval(sed_eval_t *eval, void *fout) + /* Process leftovers */ + if (eval->lspend > eval->linebuf) { + apr_status_t rv; ++ apr_status_t rc = 0; + + if (eval->lreadyflag) { + eval->lreadyflag = 0; +@@ -457,7 +500,10 @@ apr_status_t sed_finalize_eval(sed_eval_t *eval, void *fout) + * buffer is not a newline. + */ + /* Assure space for NULL */ +- append_to_linebuf(eval, "", NULL); ++ rc = append_to_linebuf(eval, "", NULL); ++ if (rc != APR_SUCCESS) { ++ return rc; ++ } + } + + *eval->lspend = '\0'; +@@ -655,11 +701,15 @@ static apr_status_t dosub(sed_eval_t *eval, char *rhsbuf, int n, + sp = eval->genbuf; + rp = rhsbuf; + sp = place(eval, sp, lp, step_vars->loc1); ++ if (sp == NULL) { ++ return APR_EGENERAL; ++ } + while ((c = *rp++) != 0) { + if (c == '&') { + sp = place(eval, sp, step_vars->loc1, step_vars->loc2); +- if (sp == NULL) ++ if (sp == NULL) { + return APR_EGENERAL; ++ } + } + else if (c == '\\') { + c = *rp++; +@@ -675,13 +725,19 @@ static apr_status_t dosub(sed_eval_t *eval, char *rhsbuf, int n, + *sp++ = c; + if (sp >= eval->genbuf + eval->gsize) { + /* expand genbuf and set the sp appropriately */ +- grow_gen_buffer(eval, eval->gsize + 1024, &sp); ++ rv = grow_gen_buffer(eval, eval->gsize + 1024, &sp); ++ if (rv != APR_SUCCESS) { ++ return rv; ++ } + } + } + lp = step_vars->loc2; + step_vars->loc2 = sp - eval->genbuf + eval->linebuf; +- append_to_genbuf(eval, lp, &sp); +- copy_to_linebuf(eval, eval->genbuf, step_vars); ++ rv = append_to_genbuf(eval, lp, &sp); ++ if (rv != APR_SUCCESS) { ++ return rv; ++ } ++ rv = copy_to_linebuf(eval, eval->genbuf, step_vars); + return rv; + } + +@@ -695,7 +751,10 @@ static char *place(sed_eval_t *eval, char *asp, char *al1, char *al2) + apr_size_t reqsize = (sp - eval->genbuf) + n + 1; + + if (eval->gsize < reqsize) { +- grow_gen_buffer(eval, reqsize, &sp); ++ apr_status_t rc = grow_gen_buffer(eval, reqsize, &sp); ++ if (rc != APR_SUCCESS) { ++ return NULL; ++ } + } + memcpy(sp, al1, n); + return sp + n; +@@ -750,7 +809,8 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc, + } + + p1++; +- copy_to_linebuf(eval, p1, step_vars); ++ rv = copy_to_linebuf(eval, p1, step_vars); ++ if (rv != APR_SUCCESS) return rv; + eval->jflag++; + break; + +@@ -760,21 +820,27 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc, + break; + + case GCOM: +- copy_to_linebuf(eval, eval->holdbuf, step_vars); ++ rv = copy_to_linebuf(eval, eval->holdbuf, step_vars); ++ if (rv != APR_SUCCESS) return rv; + break; + + case CGCOM: +- append_to_linebuf(eval, "\n", step_vars); +- append_to_linebuf(eval, eval->holdbuf, step_vars); ++ rv = append_to_linebuf(eval, "\n", step_vars); ++ if (rv != APR_SUCCESS) return rv; ++ rv = append_to_linebuf(eval, eval->holdbuf, step_vars); ++ if (rv != APR_SUCCESS) return rv; + break; + + case HCOM: +- copy_to_holdbuf(eval, eval->linebuf); ++ rv = copy_to_holdbuf(eval, eval->linebuf); ++ if (rv != APR_SUCCESS) return rv; + break; + + case CHCOM: +- append_to_holdbuf(eval, "\n"); +- append_to_holdbuf(eval, eval->linebuf); ++ rv = append_to_holdbuf(eval, "\n"); ++ if (rv != APR_SUCCESS) return rv; ++ rv = append_to_holdbuf(eval, eval->linebuf); ++ if (rv != APR_SUCCESS) return rv; + break; + + case ICOM: +@@ -896,7 +962,8 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc, + if (rv != APR_SUCCESS) + return rv; + } +- append_to_linebuf(eval, "\n", step_vars); ++ rv = append_to_linebuf(eval, "\n", step_vars); ++ if (rv != APR_SUCCESS) return rv; + eval->pending = ipc->next; + break; + +@@ -970,9 +1037,12 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc, + break; + + case XCOM: +- copy_to_genbuf(eval, eval->linebuf); +- copy_to_linebuf(eval, eval->holdbuf, step_vars); +- copy_to_holdbuf(eval, eval->genbuf); ++ rv = copy_to_genbuf(eval, eval->linebuf); ++ if (rv != APR_SUCCESS) return rv; ++ rv = copy_to_linebuf(eval, eval->holdbuf, step_vars); ++ if (rv != APR_SUCCESS) return rv; ++ rv = copy_to_holdbuf(eval, eval->genbuf); ++ if (rv != APR_SUCCESS) return rv; + break; + + case YCOM: diff --git a/httpd-2.4.53-CVE-2022-30556.patch b/httpd-2.4.53-CVE-2022-30556.patch new file mode 100644 index 0000000..1b8a112 --- /dev/null +++ b/httpd-2.4.53-CVE-2022-30556.patch @@ -0,0 +1,246 @@ +From 3a561759fcb37af179585adb8478922dc9bc6a85 Mon Sep 17 00:00:00 2001 +From: Eric Covener +Date: Wed, 1 Jun 2022 12:36:39 +0000 +Subject: [PATCH] Merge r1901502 from trunk: + +use filters consistently + + +git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1901503 13f79535-47bb-0310-9956-ffa450edef68 +--- + modules/lua/lua_request.c | 144 ++++++++++++++------------------------ + 1 file changed, 53 insertions(+), 91 deletions(-) + +diff --git a/modules/lua/lua_request.c b/modules/lua/lua_request.c +index a3e3b613bc9..2ec453e86b4 100644 +--- a/modules/lua/lua_request.c ++++ b/modules/lua/lua_request.c +@@ -2227,23 +2227,20 @@ static int lua_websocket_greet(lua_State *L) + return 0; + } + +-static apr_status_t lua_websocket_readbytes(conn_rec* c, char* buffer, +- apr_off_t len) ++static apr_status_t lua_websocket_readbytes(conn_rec* c, ++ apr_bucket_brigade *brigade, ++ char* buffer, apr_off_t len) + { +- apr_bucket_brigade *brigade = apr_brigade_create(c->pool, c->bucket_alloc); ++ apr_size_t delivered; + apr_status_t rv; ++ + rv = ap_get_brigade(c->input_filters, brigade, AP_MODE_READBYTES, + APR_BLOCK_READ, len); + if (rv == APR_SUCCESS) { +- if (!APR_BRIGADE_EMPTY(brigade)) { +- apr_bucket* bucket = APR_BRIGADE_FIRST(brigade); +- const char* data = NULL; +- apr_size_t data_length = 0; +- rv = apr_bucket_read(bucket, &data, &data_length, APR_BLOCK_READ); +- if (rv == APR_SUCCESS) { +- memcpy(buffer, data, len); +- } +- apr_bucket_delete(bucket); ++ delivered = len; ++ rv = apr_brigade_flatten(brigade, buffer, &delivered); ++ if ((rv == APR_SUCCESS) && (delivered < len)) { ++ rv = APR_INCOMPLETE; + } + } + apr_brigade_cleanup(brigade); +@@ -2273,35 +2270,28 @@ static int lua_websocket_peek(lua_State *L) + + static int lua_websocket_read(lua_State *L) + { +- apr_socket_t *sock; + apr_status_t rv; + int do_read = 1; + int n = 0; +- apr_size_t len = 1; + apr_size_t plen = 0; + unsigned short payload_short = 0; + apr_uint64_t payload_long = 0; + unsigned char *mask_bytes; + char byte; +- int plaintext; +- +- ++ apr_bucket_brigade *brigade; ++ conn_rec* c; ++ + request_rec *r = ap_lua_check_request_rec(L, 1); +- plaintext = ap_lua_ssl_is_https(r->connection) ? 0 : 1; ++ c = r->connection; + +- + mask_bytes = apr_pcalloc(r->pool, 4); +- sock = ap_get_conn_socket(r->connection); ++ ++ brigade = apr_brigade_create(r->pool, c->bucket_alloc); + + while (do_read) { + do_read = 0; + /* Get opcode and FIN bit */ +- if (plaintext) { +- rv = apr_socket_recv(sock, &byte, &len); +- } +- else { +- rv = lua_websocket_readbytes(r->connection, &byte, 1); +- } ++ rv = lua_websocket_readbytes(c, brigade, &byte, 1); + if (rv == APR_SUCCESS) { + unsigned char ubyte, fin, opcode, mask, payload; + ubyte = (unsigned char)byte; +@@ -2311,12 +2301,7 @@ static int lua_websocket_read(lua_State *L) + opcode = ubyte & 0xf; + + /* Get the payload length and mask bit */ +- if (plaintext) { +- rv = apr_socket_recv(sock, &byte, &len); +- } +- else { +- rv = lua_websocket_readbytes(r->connection, &byte, 1); +- } ++ rv = lua_websocket_readbytes(c, brigade, &byte, 1); + if (rv == APR_SUCCESS) { + ubyte = (unsigned char)byte; + /* Mask is the first bit */ +@@ -2327,40 +2312,25 @@ static int lua_websocket_read(lua_State *L) + + /* Extended payload? */ + if (payload == 126) { +- len = 2; +- if (plaintext) { +- /* XXX: apr_socket_recv does not receive len bits, only up to len bits! */ +- rv = apr_socket_recv(sock, (char*) &payload_short, &len); +- } +- else { +- rv = lua_websocket_readbytes(r->connection, +- (char*) &payload_short, 2); +- } +- payload_short = ntohs(payload_short); ++ rv = lua_websocket_readbytes(c, brigade, ++ (char*) &payload_short, 2); + +- if (rv == APR_SUCCESS) { +- plen = payload_short; +- } +- else { ++ if (rv != APR_SUCCESS) { + return 0; + } ++ ++ plen = ntohs(payload_short); + } + /* Super duper extended payload? */ + if (payload == 127) { +- len = 8; +- if (plaintext) { +- rv = apr_socket_recv(sock, (char*) &payload_long, &len); +- } +- else { +- rv = lua_websocket_readbytes(r->connection, +- (char*) &payload_long, 8); +- } +- if (rv == APR_SUCCESS) { +- plen = ap_ntoh64(&payload_long); +- } +- else { ++ rv = lua_websocket_readbytes(c, brigade, ++ (char*) &payload_long, 8); ++ ++ if (rv != APR_SUCCESS) { + return 0; + } ++ ++ plen = ap_ntoh64(&payload_long); + } + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(03210) + "Websocket: Reading %" APR_SIZE_T_FMT " (%s) bytes, masking is %s. %s", +@@ -2369,46 +2339,27 @@ static int lua_websocket_read(lua_State *L) + mask ? "on" : "off", + fin ? "This is a final frame" : "more to follow"); + if (mask) { +- len = 4; +- if (plaintext) { +- rv = apr_socket_recv(sock, (char*) mask_bytes, &len); +- } +- else { +- rv = lua_websocket_readbytes(r->connection, +- (char*) mask_bytes, 4); +- } ++ rv = lua_websocket_readbytes(c, brigade, ++ (char*) mask_bytes, 4); ++ + if (rv != APR_SUCCESS) { + return 0; + } + } + if (plen < (HUGE_STRING_LEN*1024) && plen > 0) { + apr_size_t remaining = plen; +- apr_size_t received; +- apr_off_t at = 0; + char *buffer = apr_palloc(r->pool, plen+1); + buffer[plen] = 0; + +- if (plaintext) { +- while (remaining > 0) { +- received = remaining; +- rv = apr_socket_recv(sock, buffer+at, &received); +- if (received > 0 ) { +- remaining -= received; +- at += received; +- } +- } +- ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, +- "Websocket: Frame contained %" APR_OFF_T_FMT " bytes, pushed to Lua stack", +- at); +- } +- else { +- rv = lua_websocket_readbytes(r->connection, buffer, +- remaining); +- ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, +- "Websocket: SSL Frame contained %" APR_SIZE_T_FMT " bytes, "\ +- "pushed to Lua stack", +- remaining); ++ rv = lua_websocket_readbytes(c, brigade, buffer, remaining); ++ ++ if (rv != APR_SUCCESS) { ++ return 0; + } ++ ++ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r, ++ "Websocket: Frame contained %" APR_SIZE_T_FMT \ ++ " bytes, pushed to Lua stack", remaining); + if (mask) { + for (n = 0; n < plen; n++) { + buffer[n] ^= mask_bytes[n%4]; +@@ -2420,14 +2371,25 @@ static int lua_websocket_read(lua_State *L) + return 2; + } + +- + /* Decide if we need to react to the opcode or not */ + if (opcode == 0x09) { /* ping */ + char frame[2]; +- plen = 2; ++ apr_bucket *b; ++ + frame[0] = 0x8A; + frame[1] = 0; +- apr_socket_send(sock, frame, &plen); /* Pong! */ ++ ++ /* Pong! */ ++ b = apr_bucket_transient_create(frame, 2, c->bucket_alloc); ++ APR_BRIGADE_INSERT_TAIL(brigade, b); ++ ++ rv = ap_pass_brigade(c->output_filters, brigade); ++ apr_brigade_cleanup(brigade); ++ ++ if (rv != APR_SUCCESS) { ++ return 0; ++ } ++ + do_read = 1; + } + } diff --git a/httpd-2.4.53-CVE-2022-31813.patch b/httpd-2.4.53-CVE-2022-31813.patch new file mode 100644 index 0000000..325b5cd --- /dev/null +++ b/httpd-2.4.53-CVE-2022-31813.patch @@ -0,0 +1,230 @@ +diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c +index 3af5aed..bc86253 100644 +--- a/modules/proxy/proxy_util.c ++++ b/modules/proxy/proxy_util.c +@@ -3854,12 +3854,14 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, + char **old_cl_val, + char **old_te_val) + { ++ int rc = OK; + conn_rec *c = r->connection; + int counter; + char *buf; ++ apr_table_t *saved_headers_in = r->headers_in; ++ const char *saved_host = apr_table_get(saved_headers_in, "Host"); + const apr_array_header_t *headers_in_array; + const apr_table_entry_t *headers_in; +- apr_table_t *saved_headers_in; + apr_bucket *e; + int do_100_continue; + conn_rec *origin = p_conn->connection; +@@ -3896,6 +3898,52 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, + ap_xlate_proto_to_ascii(buf, strlen(buf)); + e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(header_brigade, e); ++ ++ /* ++ * Make a copy on r->headers_in for the request we make to the backend, ++ * modify the copy in place according to our configuration and connection ++ * handling, use it to fill in the forwarded headers' brigade, and finally ++ * restore the saved/original ones in r->headers_in. ++ * ++ * Note: We need to take r->pool for apr_table_copy as the key / value ++ * pairs in r->headers_in have been created out of r->pool and ++ * p might be (and actually is) a longer living pool. ++ * This would trigger the bad pool ancestry abort in apr_table_copy if ++ * apr is compiled with APR_POOL_DEBUG. ++ * ++ * icing: if p indeed lives longer than r->pool, we should allocate ++ * all new header values from r->pool as well and avoid leakage. ++ */ ++ r->headers_in = apr_table_copy(r->pool, saved_headers_in); ++ ++ /* Return the original Transfer-Encoding and/or Content-Length values ++ * then drop the headers, they must be set by the proxy handler based ++ * on the actual body being forwarded. ++ */ ++ if ((*old_te_val = (char *)apr_table_get(r->headers_in, ++ "Transfer-Encoding"))) { ++ apr_table_unset(r->headers_in, "Transfer-Encoding"); ++ } ++ if ((*old_cl_val = (char *)apr_table_get(r->headers_in, ++ "Content-Length"))) { ++ apr_table_unset(r->headers_in, "Content-Length"); ++ } ++ ++ /* Clear out hop-by-hop request headers not to forward */ ++ if (ap_proxy_clear_connection(r, r->headers_in) < 0) { ++ rc = HTTP_BAD_REQUEST; ++ goto cleanup; ++ } ++ ++ /* RFC2616 13.5.1 says we should strip these */ ++ apr_table_unset(r->headers_in, "Keep-Alive"); ++ apr_table_unset(r->headers_in, "Upgrade"); ++ apr_table_unset(r->headers_in, "Trailer"); ++ apr_table_unset(r->headers_in, "TE"); ++ ++ /* We used to send `Host: ` always first, so let's keep it that ++ * way. No telling which legacy backend is relying no this. ++ */ + if (dconf->preserve_host == 0) { + if (ap_strchr_c(uri->hostname, ':')) { /* if literal IPv6 address */ + if (uri->port_str && uri->port != DEFAULT_HTTP_PORT) { +@@ -3917,7 +3965,7 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, + /* don't want to use r->hostname, as the incoming header might have a + * port attached + */ +- const char* hostname = apr_table_get(r->headers_in,"Host"); ++ const char* hostname = saved_host; + if (!hostname) { + hostname = r->server->server_hostname; + ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01092) +@@ -3931,21 +3979,7 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, + ap_xlate_proto_to_ascii(buf, strlen(buf)); + e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc); + APR_BRIGADE_INSERT_TAIL(header_brigade, e); +- +- /* +- * Save the original headers in here and restore them when leaving, since +- * we will apply proxy purpose only modifications (eg. clearing hop-by-hop +- * headers, add Via or X-Forwarded-* or Expect...), whereas the originals +- * will be needed later to prepare the correct response and logging. +- * +- * Note: We need to take r->pool for apr_table_copy as the key / value +- * pairs in r->headers_in have been created out of r->pool and +- * p might be (and actually is) a longer living pool. +- * This would trigger the bad pool ancestry abort in apr_table_copy if +- * apr is compiled with APR_POOL_DEBUG. +- */ +- saved_headers_in = r->headers_in; +- r->headers_in = apr_table_copy(r->pool, saved_headers_in); ++ apr_table_unset(r->headers_in, "Host"); + + /* handle Via */ + if (conf->viaopt == via_block) { +@@ -4012,8 +4046,6 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, + */ + if (dconf->add_forwarded_headers) { + if (PROXYREQ_REVERSE == r->proxyreq) { +- const char *buf; +- + /* Add X-Forwarded-For: so that the upstream has a chance to + * determine, where the original request came from. + */ +@@ -4023,8 +4055,9 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, + /* Add X-Forwarded-Host: so that upstream knows what the + * original request hostname was. + */ +- if ((buf = apr_table_get(r->headers_in, "Host"))) { +- apr_table_mergen(r->headers_in, "X-Forwarded-Host", buf); ++ if (saved_host) { ++ apr_table_mergen(r->headers_in, "X-Forwarded-Host", ++ saved_host); + } + + /* Add X-Forwarded-Server: so that upstream knows what the +@@ -4036,11 +4069,28 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, + } + } + +- proxy_run_fixups(r); +- if (ap_proxy_clear_connection(r, r->headers_in) < 0) { +- return HTTP_BAD_REQUEST; ++ /* Do we want to strip Proxy-Authorization ? ++ * If we haven't used it, then NO ++ * If we have used it then MAYBE: RFC2616 says we MAY propagate it. ++ * So let's make it configurable by env. ++ */ ++ if (r->user != NULL /* we've authenticated */ ++ && !apr_table_get(r->subprocess_env, "Proxy-Chain-Auth")) { ++ apr_table_unset(r->headers_in, "Proxy-Authorization"); + } + ++ /* for sub-requests, ignore freshness/expiry headers */ ++ if (r->main) { ++ apr_table_unset(r->headers_in, "If-Match"); ++ apr_table_unset(r->headers_in, "If-Modified-Since"); ++ apr_table_unset(r->headers_in, "If-Range"); ++ apr_table_unset(r->headers_in, "If-Unmodified-Since"); ++ apr_table_unset(r->headers_in, "If-None-Match"); ++ } ++ ++ /* run hook to fixup the request we are about to send */ ++ proxy_run_fixups(r); ++ + creds = apr_table_get(r->notes, "proxy-basic-creds"); + if (creds) { + apr_table_mergen(r->headers_in, "Proxy-Authorization", creds); +@@ -4051,55 +4101,8 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, + headers_in = (const apr_table_entry_t *) headers_in_array->elts; + for (counter = 0; counter < headers_in_array->nelts; counter++) { + if (headers_in[counter].key == NULL +- || headers_in[counter].val == NULL +- +- /* Already sent */ +- || !ap_cstr_casecmp(headers_in[counter].key, "Host") +- +- /* Clear out hop-by-hop request headers not to send +- * RFC2616 13.5.1 says we should strip these headers +- */ +- || !ap_cstr_casecmp(headers_in[counter].key, "Keep-Alive") +- || !ap_cstr_casecmp(headers_in[counter].key, "TE") +- || !ap_cstr_casecmp(headers_in[counter].key, "Trailer") +- || !ap_cstr_casecmp(headers_in[counter].key, "Upgrade") +- +- ) { +- continue; +- } +- /* Do we want to strip Proxy-Authorization ? +- * If we haven't used it, then NO +- * If we have used it then MAYBE: RFC2616 says we MAY propagate it. +- * So let's make it configurable by env. +- */ +- if (!ap_cstr_casecmp(headers_in[counter].key,"Proxy-Authorization")) { +- if (r->user != NULL) { /* we've authenticated */ +- if (!apr_table_get(r->subprocess_env, "Proxy-Chain-Auth")) { +- continue; +- } +- } +- } +- +- /* Skip Transfer-Encoding and Content-Length for now. +- */ +- if (!ap_cstr_casecmp(headers_in[counter].key, "Transfer-Encoding")) { +- *old_te_val = headers_in[counter].val; +- continue; +- } +- if (!ap_cstr_casecmp(headers_in[counter].key, "Content-Length")) { +- *old_cl_val = headers_in[counter].val; +- continue; +- } +- +- /* for sub-requests, ignore freshness/expiry headers */ +- if (r->main) { +- if ( !ap_cstr_casecmp(headers_in[counter].key, "If-Match") +- || !ap_cstr_casecmp(headers_in[counter].key, "If-Modified-Since") +- || !ap_cstr_casecmp(headers_in[counter].key, "If-Range") +- || !ap_cstr_casecmp(headers_in[counter].key, "If-Unmodified-Since") +- || !ap_cstr_casecmp(headers_in[counter].key, "If-None-Match")) { +- continue; +- } ++ || headers_in[counter].val == NULL) { ++ continue; + } + + buf = apr_pstrcat(p, headers_in[counter].key, ": ", +@@ -4110,11 +4113,9 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p, + APR_BRIGADE_INSERT_TAIL(header_brigade, e); + } + +- /* Restore the original headers in (see comment above), +- * we won't modify them anymore. +- */ ++cleanup: + r->headers_in = saved_headers_in; +- return OK; ++ return rc; + } + + PROXY_DECLARE(int) ap_proxy_prefetch_input(request_rec *r, diff --git a/httpd-2.4.53-detect-systemd.patch b/httpd-2.4.53-detect-systemd.patch new file mode 100644 index 0000000..d501b06 --- /dev/null +++ b/httpd-2.4.53-detect-systemd.patch @@ -0,0 +1,45 @@ +diff --git a/Makefile.in b/Makefile.in +index a2e9c82..bd8045c 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -4,7 +4,7 @@ CLEAN_SUBDIRS = test + + PROGRAM_NAME = $(progname) + PROGRAM_SOURCES = modules.c +-PROGRAM_LDADD = buildmark.o $(HTTPD_LDFLAGS) $(PROGRAM_DEPENDENCIES) $(PCRE_LIBS) $(EXTRA_LIBS) $(AP_LIBS) $(LIBS) ++PROGRAM_LDADD = buildmark.o $(HTTPD_LDFLAGS) $(PROGRAM_DEPENDENCIES) $(HTTPD_LIBS) $(EXTRA_LIBS) $(AP_LIBS) $(LIBS) + PROGRAM_PRELINK = $(COMPILE) -c $(top_srcdir)/server/buildmark.c + PROGRAM_DEPENDENCIES = \ + server/libmain.la \ +diff --git a/acinclude.m4 b/acinclude.m4 +index 97484c9..05abe18 100644 +--- a/acinclude.m4 ++++ b/acinclude.m4 +@@ -631,6 +631,7 @@ case $host in + if test "${ac_cv_header_systemd_sd_daemon_h}" = "no" || test -z "${SYSTEMD_LIBS}"; then + AC_MSG_WARN([Your system does not support systemd.]) + else ++ APR_ADDTO(HTTPD_LIBS, [$SYSTEMD_LIBS]) + AC_DEFINE(HAVE_SYSTEMD, 1, [Define if systemd is supported]) + fi + fi +diff --git a/configure.in b/configure.in +index cf437fe..521fc45 100644 +--- a/configure.in ++++ b/configure.in +@@ -239,6 +239,7 @@ if test "x$PCRE_CONFIG" != "x"; then + AC_MSG_NOTICE([Using external PCRE library from $PCRE_CONFIG]) + APR_ADDTO(PCRE_INCLUDES, [`$PCRE_CONFIG --cflags`]) + APR_ADDTO(PCRE_LIBS, [`$PCRE_CONFIG --libs8 2>/dev/null || $PCRE_CONFIG --libs`]) ++ APR_ADDTO(HTTPD_LIBS, [\$(PCRE_LIBS)]) + else + AC_MSG_ERROR([pcre(2)-config for libpcre not found. PCRE is required and available from http://pcre.org/]) + fi +@@ -734,6 +735,7 @@ APACHE_SUBST(OS_DIR) + APACHE_SUBST(BUILTIN_LIBS) + APACHE_SUBST(SHLIBPATH_VAR) + APACHE_SUBST(OS_SPECIFIC_VARS) ++APACHE_SUBST(HTTPD_LIBS) + + PRE_SHARED_CMDS='echo ""' + POST_SHARED_CMDS='echo ""' diff --git a/httpd-2.4.53-icons.patch b/httpd-2.4.53-icons.patch new file mode 100644 index 0000000..efc0c4d --- /dev/null +++ b/httpd-2.4.53-icons.patch @@ -0,0 +1,49 @@ +diff --git a/docs/conf/extra/httpd-autoindex.conf.in b/docs/conf/extra/httpd-autoindex.conf.in +index 51b02ed..93a2b87 100644 +--- a/docs/conf/extra/httpd-autoindex.conf.in ++++ b/docs/conf/extra/httpd-autoindex.conf.in +@@ -21,7 +21,7 @@ IndexOptions FancyIndexing HTMLTable VersionSort + Alias /icons/ "@exp_iconsdir@/" + + +- Options Indexes MultiViews ++ Options Indexes MultiViews FollowSymlinks + AllowOverride None + Require all granted + +@@ -37,6 +37,7 @@ AddIconByType (TXT,/icons/text.gif) text/* + AddIconByType (IMG,/icons/image2.gif) image/* + AddIconByType (SND,/icons/sound2.gif) audio/* + AddIconByType (VID,/icons/movie.gif) video/* ++AddIconByType /icons/bomb.gif application/x-coredump + + AddIcon /icons/binary.gif .bin .exe + AddIcon /icons/binhex.gif .hqx +@@ -53,7 +54,6 @@ 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/back.gif .. + AddIcon /icons/hand.right.gif README +diff --git a/docs/conf/magic b/docs/conf/magic +index bc891d9..9a41b44 100644 +--- a/docs/conf/magic ++++ b/docs/conf/magic +@@ -383,3 +383,15 @@ + 4 string moov video/quicktime + 4 string mdat video/quicktime + ++ ++#------------------------------------------------------------------------------ ++# application/x-coredump for LE/BE ELF ++# ++0 string \177ELF ++>5 byte 1 ++>16 leshort 4 application/x-coredump ++ ++0 string \177ELF ++>5 byte 2 ++>16 beshort 4 application/x-coredump ++ diff --git a/httpd-2.4.53-r1878890.patch b/httpd-2.4.53-r1878890.patch new file mode 100644 index 0000000..945c498 --- /dev/null +++ b/httpd-2.4.53-r1878890.patch @@ -0,0 +1,116 @@ +diff --git a/include/util_ldap.h b/include/util_ldap.h +index 28e0760..edb8a81 100644 +--- a/include/util_ldap.h ++++ b/include/util_ldap.h +@@ -32,7 +32,6 @@ + #if APR_MAJOR_VERSION < 2 + /* The LDAP API is currently only present in APR 1.x */ + #include "apr_ldap.h" +-#include "apr_ldap_rebind.h" + #else + #define APR_HAS_LDAP 0 + #endif +diff --git a/modules/ldap/util_ldap.c b/modules/ldap/util_ldap.c +index 4d92ec9..864bd62 100644 +--- a/modules/ldap/util_ldap.c ++++ b/modules/ldap/util_ldap.c +@@ -154,6 +154,38 @@ static int util_ldap_handler(request_rec *r) + return OK; + } + ++/* For OpenLDAP with the 3-arg version of ldap_set_rebind_proc(), use ++ * a simpler rebind callback than the implementation in APR-util. ++ * Testing for API version >= 3001 appears safe although OpenLDAP ++ * 2.1.x (API version = 2004) also has the 3-arg API. */ ++#if APR_HAS_OPENLDAP_LDAPSDK && defined(LDAP_API_VERSION) && LDAP_API_VERSION >= 3001 ++ ++#define uldap_rebind_init(p) APR_SUCCESS /* noop */ ++ ++static int uldap_rebind_proc(LDAP *ld, const char *url, ber_tag_t request, ++ ber_int_t msgid, void *params) ++{ ++ util_ldap_connection_t *ldc = params; ++ ++ return ldap_bind_s(ld, ldc->binddn, ldc->bindpw, LDAP_AUTH_SIMPLE); ++} ++ ++static apr_status_t uldap_rebind_add(util_ldap_connection_t *ldc) ++{ ++ ldap_set_rebind_proc(ldc->ldap, uldap_rebind_proc, ldc); ++ return APR_SUCCESS; ++} ++ ++#else /* !APR_HAS_OPENLDAP_LDAPSDK */ ++ ++#define USE_APR_LDAP_REBIND ++#include ++ ++#define uldap_rebind_init(p) apr_ldap_rebind_init(p) ++#define uldap_rebind_add(ldc) apr_ldap_rebind_add((ldc)->rebind_pool, \ ++ (ldc)->ldap, (ldc)->binddn, \ ++ (ldc)->bindpw) ++#endif + + + /* ------------------------------------------------------------------ */ +@@ -195,6 +227,13 @@ static apr_status_t uldap_connection_unbind(void *param) + util_ldap_connection_t *ldc = param; + + if (ldc) { ++#ifdef USE_APR_LDAP_REBIND ++ /* forget the rebind info for this conn */ ++ if (ldc->ChaseReferrals == AP_LDAP_CHASEREFERRALS_ON) { ++ apr_pool_clear(ldc->rebind_pool); ++ } ++#endif ++ + if (ldc->ldap) { + if (ldc->r) { + ap_log_rerror(APLOG_MARK, APLOG_TRACE5, 0, ldc->r, "LDC %pp unbind", ldc); +@@ -203,12 +242,6 @@ static apr_status_t uldap_connection_unbind(void *param) + ldc->ldap = NULL; + } + ldc->bound = 0; +- +- /* forget the rebind info for this conn */ +- if (ldc->ChaseReferrals == AP_LDAP_CHASEREFERRALS_ON) { +- apr_ldap_rebind_remove(ldc->ldap); +- apr_pool_clear(ldc->rebind_pool); +- } + } + + return APR_SUCCESS; +@@ -344,7 +377,7 @@ static int uldap_connection_init(request_rec *r, + + 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); ++ rc = uldap_rebind_add(ldc); + if (rc != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, rc, r->server, APLOGNO(01277) + "LDAP: Unable to add rebind cross reference entry. Out of memory?"); +@@ -870,6 +903,7 @@ static util_ldap_connection_t * + /* whether or not to keep this connection in the pool when it's returned */ + l->keep = (st->connection_pool_ttl == 0) ? 0 : 1; + ++#ifdef USE_APR_LDAP_REBIND + if (l->ChaseReferrals == AP_LDAP_CHASEREFERRALS_ON) { + if (apr_pool_create(&(l->rebind_pool), l->pool) != APR_SUCCESS) { + ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r, APLOGNO(01286) +@@ -881,6 +915,7 @@ static util_ldap_connection_t * + } + apr_pool_tag(l->rebind_pool, "util_ldap_rebind"); + } ++#endif + + if (p) { + p->next = l; +@@ -3068,7 +3103,7 @@ static int util_ldap_post_config(apr_pool_t *p, apr_pool_t *plog, + } + + /* Initialize the rebind callback's cross reference list. */ +- apr_ldap_rebind_init (p); ++ (void) uldap_rebind_init(p); + + #ifdef AP_LDAP_OPT_DEBUG + if (st->debug_level > 0) { diff --git a/httpd-2.4.53-r1901199.patch b/httpd-2.4.53-r1901199.patch new file mode 100644 index 0000000..978e653 --- /dev/null +++ b/httpd-2.4.53-r1901199.patch @@ -0,0 +1,336 @@ +--- a/server/mpm/event/event.c 2022/05/24 08:59:30 1901198 ++++ b/server/mpm/event/event.c 2022/05/24 09:00:19 1901199 +@@ -379,7 +379,7 @@ + * We use this value to optimize routines that have to scan the entire + * scoreboard. + */ +- int max_daemons_limit; ++ int max_daemon_used; + + /* + * All running workers, active and shutting down, including those that +@@ -645,7 +645,7 @@ + *rv = APR_SUCCESS; + switch (query_code) { + case AP_MPMQ_MAX_DAEMON_USED: +- *result = retained->max_daemons_limit; ++ *result = retained->max_daemon_used; + break; + case AP_MPMQ_IS_THREADED: + *result = AP_MPMQ_STATIC; +@@ -696,14 +696,32 @@ + return OK; + } + +-static void event_note_child_killed(int childnum, pid_t pid, ap_generation_t gen) ++static void event_note_child_stopped(int slot, pid_t pid, ap_generation_t gen) + { +- if (childnum != -1) { /* child had a scoreboard slot? */ +- ap_run_child_status(ap_server_conf, +- ap_scoreboard_image->parent[childnum].pid, +- ap_scoreboard_image->parent[childnum].generation, +- childnum, MPM_CHILD_EXITED); +- ap_scoreboard_image->parent[childnum].pid = 0; ++ if (slot != -1) { /* child had a scoreboard slot? */ ++ process_score *ps = &ap_scoreboard_image->parent[slot]; ++ int i; ++ ++ pid = ps->pid; ++ gen = ps->generation; ++ for (i = 0; i < threads_per_child; i++) { ++ ap_update_child_status_from_indexes(slot, i, SERVER_DEAD, NULL); ++ } ++ ap_run_child_status(ap_server_conf, pid, gen, slot, MPM_CHILD_EXITED); ++ if (ps->quiescing != 2) { /* vs perform_idle_server_maintenance() */ ++ retained->active_daemons--; ++ } ++ retained->total_daemons--; ++ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, ++ "Child %d stopped: pid %d, gen %d, " ++ "active %d/%d, total %d/%d/%d, quiescing %d", ++ slot, (int)pid, (int)gen, ++ retained->active_daemons, active_daemons_limit, ++ retained->total_daemons, retained->max_daemon_used, ++ server_limit, ps->quiescing); ++ ps->not_accepting = 0; ++ ps->quiescing = 0; ++ ps->pid = 0; + } + else { + ap_run_child_status(ap_server_conf, pid, gen, -1, MPM_CHILD_EXITED); +@@ -713,9 +731,19 @@ + static void event_note_child_started(int slot, pid_t pid) + { + ap_generation_t gen = retained->mpm->my_generation; ++ ++ retained->total_daemons++; ++ retained->active_daemons++; + ap_scoreboard_image->parent[slot].pid = pid; + ap_scoreboard_image->parent[slot].generation = gen; + ap_run_child_status(ap_server_conf, pid, gen, slot, MPM_CHILD_STARTED); ++ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, ++ "Child %d started: pid %d, gen %d, " ++ "active %d/%d, total %d/%d/%d", ++ slot, (int)pid, (int)gen, ++ retained->active_daemons, active_daemons_limit, ++ retained->total_daemons, retained->max_daemon_used, ++ server_limit); + } + + static const char *event_get_name(void) +@@ -737,7 +765,7 @@ + } + + if (one_process) { +- event_note_child_killed(/* slot */ 0, 0, 0); ++ event_note_child_stopped(/* slot */ 0, 0, 0); + } + + exit(code); +@@ -2712,8 +2740,8 @@ + { + int pid; + +- if (slot + 1 > retained->max_daemons_limit) { +- retained->max_daemons_limit = slot + 1; ++ if (slot + 1 > retained->max_daemon_used) { ++ retained->max_daemon_used = slot + 1; + } + + if (ap_scoreboard_image->parent[slot].pid != 0) { +@@ -2781,11 +2809,7 @@ + return -1; + } + +- ap_scoreboard_image->parent[slot].quiescing = 0; +- ap_scoreboard_image->parent[slot].not_accepting = 0; + event_note_child_started(slot, pid); +- retained->active_daemons++; +- retained->total_daemons++; + return 0; + } + +@@ -2805,7 +2829,8 @@ + } + } + +-static void perform_idle_server_maintenance(int child_bucket) ++static void perform_idle_server_maintenance(int child_bucket, ++ int *max_daemon_used) + { + int num_buckets = retained->mpm->num_buckets; + int idle_thread_count = 0; +@@ -2821,7 +2846,7 @@ + /* We only care about child_bucket in this call */ + continue; + } +- if (i >= retained->max_daemons_limit && ++ if (i >= retained->max_daemon_used && + free_length == retained->idle_spawn_rate[child_bucket]) { + /* short cut if all active processes have been examined and + * enough empty scoreboard slots have been found +@@ -2835,6 +2860,13 @@ + if (ps->quiescing == 1) { + ps->quiescing = 2; + retained->active_daemons--; ++ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, ++ "Child %d quiescing: pid %d, gen %d, " ++ "active %d/%d, total %d/%d/%d", ++ i, (int)ps->pid, (int)ps->generation, ++ retained->active_daemons, active_daemons_limit, ++ retained->total_daemons, retained->max_daemon_used, ++ server_limit); + } + for (j = 0; j < threads_per_child; j++) { + int status = ap_scoreboard_image->servers[i][j].status; +@@ -2863,8 +2895,9 @@ + free_slots[free_length++] = i; + } + } +- +- retained->max_daemons_limit = last_non_dead + 1; ++ if (*max_daemon_used < last_non_dead + 1) { ++ *max_daemon_used = last_non_dead + 1; ++ } + + if (retained->sick_child_detected) { + if (had_healthy_child) { +@@ -2893,6 +2926,10 @@ + } + } + ++ AP_DEBUG_ASSERT(retained->active_daemons <= retained->total_daemons ++ && retained->total_daemons <= retained->max_daemon_used ++ && retained->max_daemon_used <= server_limit); ++ + if (idle_thread_count > max_spare_threads / num_buckets) { + /* + * Child processes that we ask to shut down won't die immediately +@@ -2915,13 +2952,12 @@ + active_daemons_limit)); + ap_log_error(APLOG_MARK, APLOG_TRACE5, 0, ap_server_conf, + "%shutting down one child: " +- "active daemons %d / active limit %d / " +- "total daemons %d / ServerLimit %d / " +- "idle threads %d / max workers %d", ++ "active %d/%d, total %d/%d/%d, " ++ "idle threads %d, max workers %d", + (do_kill) ? "S" : "Not s", + retained->active_daemons, active_daemons_limit, +- retained->total_daemons, server_limit, +- idle_thread_count, max_workers); ++ retained->total_daemons, retained->max_daemon_used, ++ server_limit, idle_thread_count, max_workers); + if (do_kill) { + ap_mpm_podx_signal(all_buckets[child_bucket].pod, + AP_MPM_PODX_GRACEFUL); +@@ -2970,10 +3006,14 @@ + else { + ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, ap_server_conf, + "server is at active daemons limit, spawning " +- "of %d children cancelled: %d/%d active, " +- "rate %d", free_length, ++ "of %d children cancelled: active %d/%d, " ++ "total %d/%d/%d, rate %d", free_length, + retained->active_daemons, active_daemons_limit, +- retained->idle_spawn_rate[child_bucket]); ++ retained->total_daemons, retained->max_daemon_used, ++ server_limit, retained->idle_spawn_rate[child_bucket]); ++ /* reset the spawning rate and prevent its growth below */ ++ retained->idle_spawn_rate[child_bucket] = 1; ++ ++retained->hold_off_on_exponential_spawning; + free_length = 0; + } + } +@@ -2989,12 +3029,13 @@ + retained->total_daemons); + } + for (i = 0; i < free_length; ++i) { +- ap_log_error(APLOG_MARK, APLOG_TRACE5, 0, ap_server_conf, +- "Spawning new child: slot %d active / " +- "total daemons: %d/%d", +- free_slots[i], retained->active_daemons, +- retained->total_daemons); +- make_child(ap_server_conf, free_slots[i], child_bucket); ++ int slot = free_slots[i]; ++ if (make_child(ap_server_conf, slot, child_bucket) < 0) { ++ continue; ++ } ++ if (*max_daemon_used < slot + 1) { ++ *max_daemon_used = slot + 1; ++ } + } + /* the next time around we want to spawn twice as many if this + * wasn't good enough, but not if we've just done a graceful +@@ -3016,6 +3057,7 @@ + static void server_main_loop(int remaining_children_to_start) + { + int num_buckets = retained->mpm->num_buckets; ++ int max_daemon_used = 0; + int child_slot; + apr_exit_why_e exitwhy; + int status, processed_status; +@@ -3061,19 +3103,8 @@ + } + /* non-fatal death... note that it's gone in the scoreboard. */ + if (child_slot >= 0) { +- process_score *ps; ++ event_note_child_stopped(child_slot, 0, 0); + +- for (i = 0; i < threads_per_child; i++) +- ap_update_child_status_from_indexes(child_slot, i, +- SERVER_DEAD, NULL); +- +- event_note_child_killed(child_slot, 0, 0); +- ps = &ap_scoreboard_image->parent[child_slot]; +- if (ps->quiescing != 2) +- retained->active_daemons--; +- ps->quiescing = 0; +- /* NOTE: We don't dec in the (child_slot < 0) case! */ +- retained->total_daemons--; + if (processed_status == APEXIT_CHILDSICK) { + /* resource shortage, minimize the fork rate */ + retained->idle_spawn_rate[child_slot % num_buckets] = 1; +@@ -3123,9 +3154,11 @@ + continue; + } + ++ max_daemon_used = 0; + for (i = 0; i < num_buckets; i++) { +- perform_idle_server_maintenance(i); ++ perform_idle_server_maintenance(i, &max_daemon_used); + } ++ retained->max_daemon_used = max_daemon_used; + } + } + +@@ -3213,7 +3246,7 @@ + AP_MPM_PODX_RESTART); + } + ap_reclaim_child_processes(1, /* Start with SIGTERM */ +- event_note_child_killed); ++ event_note_child_stopped); + + if (!child_fatal) { + /* cleanup pid file on normal shutdown */ +@@ -3239,7 +3272,7 @@ + ap_mpm_podx_killpg(all_buckets[i].pod, active_daemons_limit, + AP_MPM_PODX_GRACEFUL); + } +- ap_relieve_child_processes(event_note_child_killed); ++ ap_relieve_child_processes(event_note_child_stopped); + + if (!child_fatal) { + /* cleanup pid file on normal shutdown */ +@@ -3261,10 +3294,10 @@ + apr_sleep(apr_time_from_sec(1)); + + /* Relieve any children which have now exited */ +- ap_relieve_child_processes(event_note_child_killed); ++ ap_relieve_child_processes(event_note_child_stopped); + + active_children = 0; +- for (index = 0; index < retained->max_daemons_limit; ++index) { ++ for (index = 0; index < retained->max_daemon_used; ++index) { + if (ap_mpm_safe_kill(MPM_CHILD_PID(index), 0) == APR_SUCCESS) { + active_children = 1; + /* Having just one child is enough to stay around */ +@@ -3282,7 +3315,7 @@ + ap_mpm_podx_killpg(all_buckets[i].pod, active_daemons_limit, + AP_MPM_PODX_RESTART); + } +- ap_reclaim_child_processes(1, event_note_child_killed); ++ ap_reclaim_child_processes(1, event_note_child_stopped); + + return DONE; + } +@@ -3302,8 +3335,7 @@ + + if (!retained->mpm->is_ungraceful) { + ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, APLOGNO(00493) +- AP_SIG_GRACEFUL_STRING +- " received. Doing graceful restart"); ++ AP_SIG_GRACEFUL_STRING " received. Doing graceful restart"); + /* wake up the children...time to die. But we'll have more soon */ + for (i = 0; i < num_buckets; i++) { + ap_mpm_podx_killpg(all_buckets[i].pod, active_daemons_limit, +@@ -3316,6 +3348,8 @@ + + } + else { ++ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, APLOGNO(00494) ++ "SIGHUP received. Attempting to restart"); + /* Kill 'em all. Since the child acts the same on the parents SIGTERM + * and a SIGHUP, we may as well use the same signal, because some user + * pthreads are stealing signals from us left and right. +@@ -3326,9 +3360,7 @@ + } + + ap_reclaim_child_processes(1, /* Start with SIGTERM */ +- event_note_child_killed); +- ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, ap_server_conf, APLOGNO(00494) +- "SIGHUP received. Attempting to restart"); ++ event_note_child_stopped); + } + + return OK; diff --git a/httpd-2.4.53-separate-systemd-fns.patch b/httpd-2.4.53-separate-systemd-fns.patch new file mode 100644 index 0000000..88b99ff --- /dev/null +++ b/httpd-2.4.53-separate-systemd-fns.patch @@ -0,0 +1,286 @@ +diff --git a/acinclude.m4 b/acinclude.m4 +index 05abe18..97484c9 100644 +--- a/acinclude.m4 ++++ b/acinclude.m4 +@@ -631,7 +631,6 @@ case $host in + if test "${ac_cv_header_systemd_sd_daemon_h}" = "no" || test -z "${SYSTEMD_LIBS}"; then + AC_MSG_WARN([Your system does not support systemd.]) + else +- APR_ADDTO(HTTPD_LIBS, [$SYSTEMD_LIBS]) + AC_DEFINE(HAVE_SYSTEMD, 1, [Define if systemd is supported]) + fi + fi +diff --git a/include/ap_listen.h b/include/ap_listen.h +index 58c2574..d5ed968 100644 +--- a/include/ap_listen.h ++++ b/include/ap_listen.h +@@ -29,6 +29,7 @@ + #include "apr_network_io.h" + #include "httpd.h" + #include "http_config.h" ++#include "apr_optional.h" + + #ifdef __cplusplus + extern "C" { +@@ -143,6 +144,15 @@ AP_DECLARE_NONSTD(const char *) ap_set_receive_buffer_size(cmd_parms *cmd, + void *dummy, + const char *arg); + ++#ifdef HAVE_SYSTEMD ++APR_DECLARE_OPTIONAL_FN(int, ++ ap_find_systemd_socket, (process_rec *, apr_port_t)); ++ ++APR_DECLARE_OPTIONAL_FN(int, ++ ap_systemd_listen_fds, (int)); ++#endif ++ ++ + #define LISTEN_COMMANDS \ + AP_INIT_TAKE1("ListenBacklog", ap_set_listenbacklog, NULL, RSRC_CONF, \ + "Maximum length of the queue of pending connections, as used by listen(2)"), \ +diff --git a/modules/arch/unix/mod_systemd.c b/modules/arch/unix/mod_systemd.c +index eda1272..fc059fc 100644 +--- a/modules/arch/unix/mod_systemd.c ++++ b/modules/arch/unix/mod_systemd.c +@@ -35,6 +35,15 @@ + #include + #endif + ++APR_DECLARE_OPTIONAL_FN(int, ++ ap_find_systemd_socket, (process_rec *, apr_port_t)); ++ ++APR_DECLARE_OPTIONAL_FN(int, ++ ap_systemd_listen_fds, (int)); ++ ++APR_DECLARE_OPTIONAL_FN(int, ++ ap_systemd_journal_stream_fd, (const char *, int, int)); ++ + static char describe_listeners[30]; + + static int systemd_pre_config(apr_pool_t *pconf, apr_pool_t *plog, +@@ -145,8 +154,47 @@ static int systemd_monitor(apr_pool_t *p, server_rec *s) + return DECLINED; + } + ++static int ap_find_systemd_socket(process_rec * process, apr_port_t port) { ++ int fdcount, fd; ++ int sdc = sd_listen_fds(0); ++ ++ if (sdc < 0) { ++ ap_log_perror(APLOG_MARK, APLOG_CRIT, sdc, process->pool, APLOGNO(02486) ++ "find_systemd_socket: Error parsing enviroment, sd_listen_fds returned %d", ++ sdc); ++ return -1; ++ } ++ ++ if (sdc == 0) { ++ ap_log_perror(APLOG_MARK, APLOG_CRIT, sdc, process->pool, APLOGNO(02487) ++ "find_systemd_socket: At least one socket must be set."); ++ return -1; ++ } ++ ++ fdcount = atoi(getenv("LISTEN_FDS")); ++ for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + fdcount; fd++) { ++ if (sd_is_socket_inet(fd, 0, 0, -1, port) > 0) { ++ return fd; ++ } ++ } ++ ++ return -1; ++} ++ ++static int ap_systemd_listen_fds(int unset_environment){ ++ return sd_listen_fds(unset_environment); ++} ++ ++static int ap_systemd_journal_stream_fd(const char *identifier, int priority, int level_prefix){ ++ return sd_journal_stream_fd("httpd", priority, 0); ++} ++ + static void systemd_register_hooks(apr_pool_t *p) + { ++ APR_REGISTER_OPTIONAL_FN(ap_systemd_listen_fds); ++ APR_REGISTER_OPTIONAL_FN(ap_find_systemd_socket); ++ APR_REGISTER_OPTIONAL_FN(ap_systemd_journal_stream_fd); ++ + /* Enable ap_extended_status. */ + ap_hook_pre_config(systemd_pre_config, NULL, NULL, APR_HOOK_LAST); + /* Signal service is ready. */ +diff --git a/modules/loggers/config.m4 b/modules/loggers/config.m4 +index 0848d2e..8af2299 100644 +--- a/modules/loggers/config.m4 ++++ b/modules/loggers/config.m4 +@@ -5,7 +5,6 @@ dnl APACHE_MODULE(name, helptext[, objects[, structname[, default[, config]]]]) + APACHE_MODPATH_INIT(loggers) + + APACHE_MODULE(log_config, logging configuration. You won't be able to log requests to the server without this module., , , yes) +-APR_ADDTO(MOD_LOG_CONFIG_LDADD, [$SYSTEMD_LIBS]) + + APACHE_MODULE(log_debug, configurable debug logging, , , most) + APACHE_MODULE(log_forensic, forensic logging) +diff --git a/modules/loggers/mod_log_config.c b/modules/loggers/mod_log_config.c +index 0b11f60..c3f0a51 100644 +--- a/modules/loggers/mod_log_config.c ++++ b/modules/loggers/mod_log_config.c +@@ -172,10 +172,6 @@ + #include + #endif + +-#ifdef HAVE_SYSTEMD +-#include +-#endif +- + #define DEFAULT_LOG_FORMAT "%h %l %u %t \"%r\" %>s %b" + + module AP_MODULE_DECLARE_DATA log_config_module; +@@ -1640,8 +1636,15 @@ static apr_status_t wrap_journal_stream(apr_pool_t *p, apr_file_t **outfd, + { + #ifdef HAVE_SYSTEMD + int fd; ++ APR_OPTIONAL_FN_TYPE(ap_systemd_journal_stream_fd) *systemd_journal_stream_fd; ++ ++ systemd_journal_stream_fd = APR_RETRIEVE_OPTIONAL_FN(ap_systemd_journal_stream_fd); ++ if (systemd_journal_stream_fd == NULL) { ++ return APR_ENOTIMPL; ++ } + +- fd = sd_journal_stream_fd("httpd", priority, 0); ++ fd = systemd_journal_stream_fd("httpd", priority, 0); ++ + if (fd < 0) return fd; + + /* This is an AF_UNIX socket fd so is more pipe-like than +diff --git a/modules/loggers/mod_log_config.h b/modules/loggers/mod_log_config.h +index 877a593..bd52a98 100644 +--- a/modules/loggers/mod_log_config.h ++++ b/modules/loggers/mod_log_config.h +@@ -69,6 +69,10 @@ APR_DECLARE_OPTIONAL_FN(ap_log_writer_init*, ap_log_set_writer_init,(ap_log_writ + */ + APR_DECLARE_OPTIONAL_FN(ap_log_writer*, ap_log_set_writer, (ap_log_writer* func)); + ++#ifdef HAVE_SYSTEMD ++APR_DECLARE_OPTIONAL_FN(int, ap_systemd_journal_stream_fd, (const char *, int, int)); ++#endif ++ + #endif /* MOD_LOG_CONFIG */ + /** @} */ + +diff --git a/server/listen.c b/server/listen.c +index e2e028a..5d1c0e1 100644 +--- a/server/listen.c ++++ b/server/listen.c +@@ -34,10 +34,6 @@ + #include + #endif + +-#ifdef HAVE_SYSTEMD +-#include +-#endif +- + /* we know core's module_index is 0 */ + #undef APLOG_MODULE_INDEX + #define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX +@@ -325,34 +321,6 @@ static int find_listeners(ap_listen_rec **from, ap_listen_rec **to, + } + + #ifdef HAVE_SYSTEMD +- +-static int find_systemd_socket(process_rec * process, apr_port_t port) { +- int fdcount, fd; +- int sdc = sd_listen_fds(0); +- +- if (sdc < 0) { +- ap_log_perror(APLOG_MARK, APLOG_CRIT, sdc, process->pool, APLOGNO(02486) +- "find_systemd_socket: Error parsing enviroment, sd_listen_fds returned %d", +- sdc); +- return -1; +- } +- +- if (sdc == 0) { +- ap_log_perror(APLOG_MARK, APLOG_CRIT, sdc, process->pool, APLOGNO(02487) +- "find_systemd_socket: At least one socket must be set."); +- return -1; +- } +- +- fdcount = atoi(getenv("LISTEN_FDS")); +- for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + fdcount; fd++) { +- if (sd_is_socket_inet(fd, 0, 0, -1, port) > 0) { +- return fd; +- } +- } +- +- return -1; +-} +- + static apr_status_t alloc_systemd_listener(process_rec * process, + int fd, const char *proto, + ap_listen_rec **out_rec) +@@ -412,6 +380,14 @@ static const char *set_systemd_listener(process_rec *process, apr_port_t port, + { + ap_listen_rec *last, *new; + apr_status_t rv; ++ APR_OPTIONAL_FN_TYPE(ap_find_systemd_socket) *find_systemd_socket; ++ ++ find_systemd_socket = APR_RETRIEVE_OPTIONAL_FN(ap_find_systemd_socket); ++ ++ if (!find_systemd_socket) ++ return "Systemd socket activation is used, but mod_systemd is probably " ++ "not loaded"; ++ + int fd = find_systemd_socket(process, port); + if (fd < 0) { + return "Systemd socket activation is used, but this port is not " +@@ -438,7 +414,6 @@ static const char *set_systemd_listener(process_rec *process, apr_port_t port, + + return NULL; + } +- + #endif /* HAVE_SYSTEMD */ + + static const char *alloc_listener(process_rec *process, const char *addr, +@@ -707,6 +682,9 @@ AP_DECLARE(int) ap_setup_listeners(server_rec *s) + int num_listeners = 0; + const char* proto; + int found; ++#ifdef HAVE_SYSTEMD ++ APR_OPTIONAL_FN_TYPE(ap_systemd_listen_fds) *systemd_listen_fds; ++#endif + + for (ls = s; ls; ls = ls->next) { + proto = ap_get_server_protocol(ls); +@@ -746,7 +724,10 @@ AP_DECLARE(int) ap_setup_listeners(server_rec *s) + apr_pool_cleanup_null, s->process->pool); + } + else { +- sd_listen_fds(1); ++ systemd_listen_fds = APR_RETRIEVE_OPTIONAL_FN(ap_systemd_listen_fds); ++ if (systemd_listen_fds != NULL) { ++ systemd_listen_fds(1); ++ } + } + } + else +@@ -963,6 +944,9 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, + apr_port_t port; + apr_status_t rv; + const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); ++#ifdef HAVE_SYSTEMD ++ APR_OPTIONAL_FN_TYPE(ap_systemd_listen_fds) *systemd_listen_fds; ++#endif + + if (err != NULL) { + return err; +@@ -973,7 +957,12 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, + } + #ifdef HAVE_SYSTEMD + if (use_systemd == -1) { +- use_systemd = sd_listen_fds(0) > 0; ++ systemd_listen_fds = APR_RETRIEVE_OPTIONAL_FN(ap_systemd_listen_fds); ++ if (systemd_listen_fds != NULL) { ++ use_systemd = systemd_listen_fds(0) > 0; ++ } else { ++ use_systemd = 0; ++ } + } + #endif + diff --git a/httpd-init.service b/httpd-init.service new file mode 100644 index 0000000..3074778 --- /dev/null +++ b/httpd-init.service @@ -0,0 +1,12 @@ +[Unit] +Description=One-time temporary TLS key generation for httpd.service +Documentation=man:httpd-init.service(8) + +ConditionPathExists=|!/etc/pki/tls/certs/localhost.crt +ConditionPathExists=|!/etc/pki/tls/private/localhost.key + +[Service] +Type=oneshot +RemainAfterExit=no + +ExecStart=/usr/libexec/httpd-ssl-gencerts diff --git a/httpd-ssl-gencerts b/httpd-ssl-gencerts new file mode 100755 index 0000000..350f5b5 --- /dev/null +++ b/httpd-ssl-gencerts @@ -0,0 +1,39 @@ +#!/usr/bin/bash + +set -e + +FQDN=`hostname` +ssldotconf=/etc/httpd/conf.d/ssl.conf + +if test -f /etc/pki/tls/certs/localhost.crt -a \ + -f /etc/pki/tls/private/localhost.key; then + exit 0 +fi + +if test -f /etc/pki/tls/certs/localhost.crt -a \ + ! -f /etc/pki/tls/private/localhost.key; then + echo "Missing certificate key!" + exit 1 +fi + +if test ! -f /etc/pki/tls/certs/localhost.crt -a \ + -f /etc/pki/tls/private/localhost.key; then + echo "Missing certificate, but key is present!" + exit 1 +fi + +if ! test -f ${ssldotconf} || \ + ! grep -q '^SSLCertificateFile /etc/pki/tls/certs/localhost.crt' ${ssldotconf} || \ + ! grep -q '^SSLCertificateKeyFile /etc/pki/tls/private/localhost.key' ${ssldotconf}; then + # Non-default configuration, do nothing. + exit 0 +fi + +sscg -q \ + --cert-file /etc/pki/tls/certs/localhost.crt \ + --cert-key-file /etc/pki/tls/private/localhost.key \ + --ca-file /etc/pki/tls/certs/localhost.crt \ + --lifetime 365 \ + --hostname $FQDN \ + --email root@$FQDN + diff --git a/httpd-ssl-pass-dialog b/httpd-ssl-pass-dialog new file mode 100755 index 0000000..79318a6 --- /dev/null +++ b/httpd-ssl-pass-dialog @@ -0,0 +1,3 @@ +#!/bin/sh + +exec /bin/systemd-ask-password "Enter TLS private key passphrase for $1 ($2) : " diff --git a/httpd.conf b/httpd.conf new file mode 100644 index 0000000..6ab68cb --- /dev/null +++ b/httpd.conf @@ -0,0 +1,356 @@ +# +# 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. +# +# See the httpd.conf(5) man page for more information on this configuration, +# and httpd.service(8) on using and configuring the httpd service. +# +# 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/httpd.conf.xml b/httpd.conf.xml new file mode 100644 index 0000000..705e527 --- /dev/null +++ b/httpd.conf.xml @@ -0,0 +1,259 @@ + + + + + + + httpd.conf + httpd + AuthorOrtonJoejorton@redhat.com + + + + httpd.conf + 5 + + + + httpd.conf + Configuration files for httpd + + + + + /etc/httpd/conf/httpd.conf, + /etc/httpd/conf.modules.d, + /etc/httpd/conf.d + + + + + Description + + The main configuration file for the httpd daemon is + /etc/httpd/conf/httpd.conf. The syntax of + this file is described at , and + the full set of available directives is listed at . + + + + Configuration structure + + The main configuration file + (httpd.conf) sets up various defaults and + includes configuration files from two directories - + /etc/httpd/conf.modules.d and + /etc/httpd/conf.d. Packages containing + loadable modules (like ) place files + in the conf.modules.d directory with the + appropriate directive so that module + is loaded by default. + + Some notable configured defaults are:. + + + + + The default document root from which content + is served. + + + + The daemon lists on TCP port 80. + + + + Error messages are logged to + @LOGDIR@/error_log. + + + + CGI scripts are served via the URL-path . + + + + + To remove any of the default configuration provided in + separate files covered below, replace that file with an empty + file rather than removing it from the filesystem, otherwise it + may be restored to the original when the package which provides + it is upgraded. + + + + + MPM configuration + + The configuration file at + /etc/httpd/conf.modules.d/00-mpm.conf is + used to select the multi-processing module (MPM), which governs + how httpd divides work between processes + and/or threads at run-time. Exactly one + directive must be uncommented in + this file; by default the MPM is enabled. + For more information on MPMs, see . + + If using the prefork MPM, the + "httpd_graceful_shutdown" SELinux boolean should also be + enabled, since with this MPM, httpd needs to establish TCP + connections to local ports to successfully complete a graceful + restart or shutdown. This boolean can be enabled by running the + command: semanage boolean -m --on + httpd_graceful_shutdown + + + + Module configuration files + + Module configuration files are provided in the + /etc/httpd/conf.modules.d/ directory. Filenames + in this directory are by convention prefixed with two digit numeric + prefix to ensure they are processed in the desired order. Core + modules provide with the httpd package are + loaded by files with a prefix to ensure + these are loaded first. Only filenames with a + suffix in this directory will be + processed. + + Other provided configuration files are listed below. + + + + /etc/httpd/conf.modules.d/00-base.conf + The set of core modules included with + httpd which are all loaded by + default. + + + + /etc/httpd/conf.modules.d/00-optional.conf + The set of non-core modules included with + httpd which are not + loaded by default. + + + + + /etc/httpd/conf.modules.d/00-systemd.conf + This file loads + which is necessary for the correct operation of the + httpd.service service, and should not be + removed or disabled. + + + + + + + Other configuration files + + Default module configuration files and site-specific + configuration files are loaded from the + /etc/httpd/conf.d/ directory. Only files + with a suffix will be loaded. The + following files are provided: + + + + /etc/httpd/conf.d/userdir.conf + This file gives an example configuration for + to map URLs such as + to + /home/jim/public_html/. Userdir mapping + is disabled by default. + + + + /etc/httpd/conf.d/autoindex.conf + This file provides the default configuration + for which generates HTML + directory listings when enabled. It also makes file icon + image files available at the + URL-path. + + + + /etc/httpd/conf.d/welcome.conf + This file enables a "welcome page" at + if no content is present + in the default documentation root + /var/www/html. + + + + /etc/httpd/conf.d/ssl.conf (present only if is installed) + This file configures a TLS + listening on port + . If the default configuration is used, + the referenced test certificate and private key are + generated the first time httpd.service is + started; see + httpd-init.service8 + for more information. + + + + + + + Instantiated services + + As an alternative to (or in addition to) the + httpd.service unit, the instantiated template + service httpd@.service unit file can be used, + which starts httpd using a different + configuration file to the default. For example, + systemctl start httpd@foobar.service will + start httpd using the configuration file + /etc/httpd/conf/foobar.conf. See httpd@.service8 for more information. + + + + + Files + + + /etc/httpd/conf/httpd.conf, + /etc/httpd/conf.d, + /etc/httpd/conf.modules.d + + + + + See also + + + httpd8, + httpd.service8, + , + + + + + + + diff --git a/httpd.logrotate b/httpd.logrotate new file mode 100644 index 0000000..28c9730 --- /dev/null +++ b/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/httpd.service b/httpd.service new file mode 100644 index 0000000..6ff4e8b --- /dev/null +++ b/httpd.service @@ -0,0 +1,32 @@ +# See httpd.service(8) for more information on using the httpd service. + +# Modifying this file in-place is not recommended, because changes +# will be overwritten during package upgrades. To customize the +# behaviour, run "systemctl edit httpd" to create an override unit. + +# For example, to pass additional options (such as -D definitions) to +# the httpd binary at startup, create an override unit (as is done by +# systemctl edit) and enter the following: + +# [Service] +# Environment=OPTIONS=-DMY_DEFINE + +[Unit] +Description=The Apache HTTP Server +Wants=httpd-init.service +After=network.target remote-fs.target nss-lookup.target httpd-init.service +Documentation=man:httpd.service(8) + +[Service] +Type=notify +Environment=LANG=C + +ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND +ExecReload=/usr/sbin/httpd $OPTIONS -k graceful +# Send SIGWINCH for graceful stop +KillSignal=SIGWINCH +KillMode=mixed +PrivateTmp=true + +[Install] +WantedBy=multi-user.target diff --git a/httpd.service.xml b/httpd.service.xml new file mode 100644 index 0000000..b2c72dd --- /dev/null +++ b/httpd.service.xml @@ -0,0 +1,332 @@ + + + + + + + httpd systemd units + httpd + AuthorOrtonJoejorton@redhat.com + + + + httpd.service + 8 + + + + httpd.service + httpd@.service + httpd.socket + httpd-init.service + httpd unit files for systemd + + + + + /usr/lib/systemd/system/httpd.service, + /usr/lib/systemd/system/httpd@.service, + /usr/lib/systemd/system/httpd-init.service, + /usr/lib/systemd/system/httpd.socket + + + + + Description + + This manual page describes the systemd + unit files used to integrate the httpd daemon + with systemd. Two main unit files are + available: httpd.service allows the + httpd daemon to be run as a system service, and + httpd.socket allows httpd to be started via + socket-based activation. Most systems will use + httpd.service. + + The apachectl command has been modified + to invoke systemctl for most uses, so for + example, running apachectl start is equivalent + to running systemctl start httpd.service. This + ensures that the running httpd daemon is tracked and managed by + systemd. In contrast, running + httpd directly from a root shell will start the + service outside of systemd; in this case, + default security restrictions described below (including, but not + limited to, SELinux) will not be enforced. + + + Changing default behaviour + + To change the default behaviour of the httpd service, an + over-ride file should be created, rather + than changing + /usr/lib/systemd/system/httpd.service + directly, since such changes would be lost over package + upgrades. Running systemctl edit + httpd.service or systemctl edit + httpd.socket as root will create a drop-in file (in + the former case, in + /etc/systemd/system/httpd.service.d) which + over-rides the system defaults. + + For example, to set the + environment variable for the daemon, run systemctl edit + httpd.service and enter: + + [Service] +Environment=LD_LIBRARY_PATH=/opt/vendor/lib + + + + Starting the service at boot time + + The httpd.service and httpd.socket units are + disabled by default. To start the httpd + service at boot time, run: systemctl enable + httpd.service. In the default configuration, the + httpd daemon will accept connections on port 80 (and, if mod_ssl + is installed, TLS connections on port 443) for any configured + IPv4 or IPv6 address. + + If httpd is configured to depend on any specific IP + address (for example, with a "Listen" directive) which may only + become available during start-up, or if httpd depends on other + services (such as a database daemon), the service + must be configured to ensure correct + start-up ordering. + + For example, to ensure httpd is only running after all + configured network interfaces are configured, create a drop-in + file (as described above) with the following section: + + [Unit] +After=network-online.target +Wants=network-online.target + + See + for more information on start-up ordering with systemd. + + + + + SSL/TLS certificate generation + + The httpd-init.service unit is provided + with the mod_ssl package. This oneshot unit automatically + creates a TLS server certificate and key (using a generated + self-signed CA certificate and key) for testing purposes before + httpd is started. To inhibit certificate generation, use + systemctl mask httpd-init.service after + installing mod_ssl, and adjust the mod_ssl configuration to use + an appropriate certificate and key. + + + + + Reloading and stopping the service + + When running systemctl reload + httpd.service, a graceful + restart is used, which sends a signal to the httpd parent + process to reload the configuration and re-open log files. Any + children with open connections at the time of reload will + terminate only once they have completed serving requests. This + prevents users of the server seeing errors (or potentially + losing data) due to the reload, but means some there is some + delay before any configuration changes take effect for all + users. + + Similarly, a graceful stop is used + when systemctl stop httpd.service is run, + which terminates the server only once active connections have + been processed. + + To "ungracefully" stop the server without waiting for + requests to complete, use systemctl kill + --kill-who=main httpd; similarly to "ungracefully" + reload the configuration, use systemctl kill + --kill-who=main --signal=HUP httpd. + + + + Automated service restarts + + System packages (including the httpd package itself) may + restart the httpd service automatically after packages are + upgraded, installed, or removed. This is done using the + systemctl reload httpd.service, which + produces a graceful restart by default as + described above. + + To suppress automatic reloads entirely, create the file + /etc/sysconfig/httpd-disable-posttrans. + + + + Changing the default MPM (Multi-Processing Module) + + httpd offers a choice of multi-processing modules (MPMs), + which can be configured in + /etc/httpd/conf.modules.d/00-mpm.conf. + See + httpd.conf5 + for more information on changing the MPM. + + + + systemd integration and mod_systemd + + The httpd service uses the systemd + service type. The mod_systemd module must be + loaded (as in the default configuration) for this to work + correctly - the service will fail if this module is not + loaded. mod_systemd also makes worker and + request statistics available when running systemctl status + httpd. See + systemd.exec5 + for more information on systemd service types. + + + + Security and SELinux + + The default SELinux policy restricts the httpd service in + various ways. For example, the default policy limits the ports + to which httpd can bind (using the Listen + directive), which parts of the filesystem can be accessed, and + whether outgoing TCP connections are possible. Many of these + restrictions can be relaxed or adjusted by using + semanage to change booleans or other + types. See + httpd_selinux8 + for more information. + + The httpd service enables PrivateTmp + by default. The /tmp and + /var/tmp directories available within the + httpd process (and CGI scripts, etc) are not shared by other + processes. See + systemd.exec5 + for more information. + + + + + Socket activation + + Socket activation (see + systemd.socket5 + for more information) can be used with httpd + by enabling the httpd.socket unit. The + httpd listener configuration must exactly + match the ListenStream options configured for + the httpd.socket unit. The default + httpd.socket has a + ListenStream=80 and, if mod_ssl is installed, + ListenStream=443 by a drop-in file. If + additional Listen directives are added to the + httpd configuration, corresponding + ListenStream options should be added via + drop-in files, for example via systemctl edit + httpd.socket. + + If using socket activation with httpd, only one listener + on any given TCP port is supported; a configuration with both + "Listen 127.0.0.1:80" and "Listen + 192.168.1.2:80" will not work. + + + + Instantiated services + + The httpd@.service unit is an + instantiated template service. An instance of this unit will be + started using the configuration file + /etc/httpd/conf/INSTANCE.conf, where + INSTANCE is replaced with the instance + name. For example, systemctl start + httpd@foobar.service will start httpd using the + configuration file + /etc/httpd/conf/foobar.conf. The + environment variable is set to + the instance name by the unit and is available for use within + the configuration file. + + To allow multiple instances of httpd to run + simultaneously, a number of configuration directives must be + changed, such as PidFile and + DefaultRuntimeDir to pick non-conflicting + paths, and Listen to choose different ports. + The example configuration file + /usr/share/doc/httpd/instance.conf + demonstrates how to make such changes using + variable. + + It can be useful to configure instances of + httpd@.service to reload when + httpd.service is reloaded; for example, + logrotate will reload only + httpd.service when logs are rotated. If this + behaviour is required, create a drop-in file for the instance as + follows: + + [Unit] +ReloadPropagatedFrom=httpd.service + + As with normal units, drop-in files for instances can be created + using systemctl edit, e.g. systemctl edit + httpd@foobar.service. + + + + + + Files + + /usr/lib/systemd/system/httpd.service, + /usr/lib/systemd/system/httpd.socket, + /usr/lib/systemd/system/httpd@.service, + /etc/systemd/systemd/httpd.service.d + + + + See also + + + httpd8, + httpd.conf5, + systemd1, + systemctl1, + systemd.service5, + systemd.exec5, + systemd.socket5, + httpd_selinux8, + semanage8 + + + + + + diff --git a/httpd.socket b/httpd.socket new file mode 100644 index 0000000..074695e --- /dev/null +++ b/httpd.socket @@ -0,0 +1,13 @@ +# See httpd.socket(8) for more information on using the httpd service. + +[Unit] +Description=Apache httpd Server Socket +Documentation=man:httpd.socket(8) + +[Socket] +ListenStream=80 +NoDelay=true +DeferAcceptSec=30 + +[Install] +WantedBy=sockets.target diff --git a/httpd.spec b/httpd.spec new file mode 100644 index 0000000..daa6a90 --- /dev/null +++ b/httpd.spec @@ -0,0 +1,1816 @@ +%define contentdir %{_datadir}/httpd +%define docroot /var/www +%define suexec_caller apache +%define mmn 20120211 +%define mmnisa %{mmn}%{__isa_name}%{__isa_bits} +%define vstring %(source /etc/os-release; echo ${REDHAT_SUPPORT_PRODUCT}) +%if 0%{?fedora} > 26 || 0%{?rhel} > 7 +%global mpm event +%else +%global mpm prefork +%endif + +Summary: Apache HTTP Server +Name: httpd +Version: 2.4.37 +Release: 47%{?dist}.1 +URL: https://httpd.apache.org/ +Source0: https://www.apache.org/dist/httpd/httpd-%{version}.tar.bz2 +Source2: httpd.logrotate +Source3: instance.conf +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 +Source26: 10-listen443.conf +Source27: httpd.socket +Source28: 00-optional.conf +# Documentation +Source30: README.confd +Source31: README.confmod +Source32: httpd.service.xml +Source33: htcacheclean.service.xml +Source34: httpd.conf.xml +Source40: htcacheclean.service +Source41: htcacheclean.sysconf +Source42: httpd-init.service +Source43: httpd-ssl-gencerts +Source44: httpd@.service +Source45: config.layout +Source46: apache-poweredby.png + +# build/scripts patches +# http://bugzilla.redhat.com/show_bug.cgi?id=1231924 +# http://bugzilla.redhat.com/show_bug.cgi?id=842736 +# http://bugzilla.redhat.com/show_bug.cgi?id=1214401 +Patch1: httpd-2.4.35-apachectl.patch +Patch2: httpd-2.4.28-apxs.patch +Patch3: httpd-2.4.35-deplibs.patch + +# Needed for socket activation and mod_systemd patch +Patch19: httpd-2.4.35-detect-systemd.patch + +# Features/functional changes +Patch20: httpd-2.4.32-export.patch +Patch21: httpd-2.4.35-corelimit.patch +Patch22: httpd-2.4.35-selinux.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1170215 +Patch23: httpd-2.4.28-icons.patch +Patch24: httpd-2.4.35-systemd.patch +Patch25: httpd-2.4.35-cachehardmax.patch +Patch26: httpd-2.4.28-socket-activation.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1109119 +Patch27: httpd-2.4.35-sslciphdefault.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1332242 +Patch28: httpd-2.4.28-statements-comment.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=811714 +Patch29: httpd-2.4.35-full-release.patch +Patch30: httpd-2.4.35-freebind.patch +Patch31: httpd-2.4.35-r1830819+.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1638738 +Patch32: httpd-2.4.37-sslprotdefault.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1747898 +Patch33: httpd-2.4.37-mod-md-mod-ssl-hooks.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1725031 +Patch34: httpd-2.4.37-r1861793+.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1704317 +Patch35: httpd-2.4.37-sslkeylogfile-support.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1794728 +Patch36: httpd-2.4.37-session-expiry-updt-int.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1209162 +Patch37: httpd-2.4.37-logjournal.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1869576 +Patch38: httpd-2.4.37-pr37355.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1896176 +Patch39: httpd-2.4.37-proxy-ws-idle-timeout.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1883648 +Patch40: httpd-2.4.37-ssl-proxy-chains.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1935742 +Patch41: httpd-2.4.37-usertrack-samesite.patch + +# Bug fixes +# https://bugzilla.redhat.com/show_bug.cgi?id=1397243 +Patch61: httpd-2.4.35-r1738878.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1170206 +Patch62: httpd-2.4.35-r1633085.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1448892 +Patch63: httpd-2.4.28-r1811831.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1602548 +Patch65: httpd-2.4.35-r1842888.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1653009 +# https://bugzilla.redhat.com/show_bug.cgi?id=1672977 +# https://bugzilla.redhat.com/show_bug.cgi?id=1673022 +Patch66: httpd-2.4.37-r1842929+.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1630432 +Patch67: httpd-2.4.35-r1825120.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1670716 +Patch68: httpd-2.4.37-fips-segfault.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1669221 +Patch70: httpd-2.4.37-r1840554.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1673022 +Patch71: httpd-2.4.37-mod-md-perms.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1724549 +Patch72: httpd-2.4.37-mod-mime-magic-strdup.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1724034 +Patch73: httpd-2.4.35-ocsp-wrong-ctx.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1633224 +Patch74: httpd-2.4.37-r1828172+.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1775158 +Patch75: httpd-2.4.37-r1870095+.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1771847 +Patch76: httpd-2.4.37-proxy-continue.patch +Patch77: httpd-2.4.37-balancer-failover.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1875844 +Patch78: httpd-2.4.37-r1881459.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1891829 +Patch79: httpd-2.4.37-r1864000.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1868608 +Patch80: httpd-2.4.37-r1872790.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1861380 +Patch81: httpd-2.4.37-r1879224.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1680118 +Patch82: httpd-2.4.37-r1877397.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1847585 +Patch83: httpd-2.4.37-r1878890.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1918741 +Patch84: httpd-2.4.37-r1878280.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1891594 +Patch85: httpd-2.4.37-htcacheclean-dont-break.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1937334 +Patch86: httpd-2.4.37-r1873907.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1680111 +Patch87: httpd-2.4.37-reply-two-tls-rec.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1905613 +Patch88: httpd-2.4.37-r1845768+.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2001046 +Patch89: httpd-2.4.37-r1862410.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1984828 +Patch90: httpd-2.4.37-hcheck-mem-issues.patch + +# Security fixes +Patch200: httpd-2.4.37-r1851471.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1694980 +Patch201: httpd-2.4.37-CVE-2019-0211.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1695025 +Patch202: httpd-2.4.37-CVE-2019-0215.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1696141 +Patch203: httpd-2.4.37-CVE-2019-0217.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1696097 +Patch204: httpd-2.4.37-CVE-2019-0220.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1741860 +# https://bugzilla.redhat.com/show_bug.cgi?id=1741864 +# https://bugzilla.redhat.com/show_bug.cgi?id=1741868 +Patch205: httpd-2.4.34-CVE-2019-9511-and-9516-and-9517.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1823259 +# https://bugzilla.redhat.com/show_bug.cgi?id=1747284 +# fixes both CVE-2020-1927 and CVE-2019-10098 +Patch206: httpd-2.4.37-CVE-2019-10098.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1747281 +Patch207: httpd-2.4.37-CVE-2019-10092.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1747291 +Patch208: httpd-2.4.37-CVE-2019-10097.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1820772 +Patch209: httpd-2.4.37-CVE-2020-1934.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1668493 +Patch210: httpd-2.4.37-CVE-2018-17199.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1866563 +Patch211: httpd-2.4.37-CVE-2020-11984.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1972500 +Patch212: httpd-2.4.37-CVE-2021-30641.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1968307 +Patch213: httpd-2.4.37-CVE-2021-26690.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2005117 +Patch214: httpd-2.4.37-CVE-2021-40438.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1966732 +Patch215: httpd-2.4.37-CVE-2021-26691.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1968278 +Patch216: httpd-2.4.37-CVE-2020-35452.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2005128 +Patch217: httpd-2.4.37-CVE-2021-34798.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2005119 +Patch218: httpd-2.4.37-CVE-2021-39275.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2005124 +Patch219: httpd-2.4.37-CVE-2021-36160.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1966728 +Patch220: httpd-2.4.37-CVE-2021-33193.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2034674 +Patch221: httpd-2.4.37-CVE-2021-44790.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2034672 +Patch222: httpd-2.4.37-CVE-2021-44224.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2064321 +Patch223: httpd-2.4.37-CVE-2022-22720.patch + +License: ASL 2.0 +Group: System Environment/Daemons +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root +BuildRequires: autoconf, perl-interpreter, perl-generators, pkgconfig, findutils, xmlto +BuildRequires: zlib-devel, libselinux-devel, lua-devel, brotli-devel +BuildRequires: apr-devel >= 1.5.0, apr-util-devel >= 1.5.0, pcre-devel >= 5.0 +BuildRequires: systemd-devel +# web server testpage added to redhat-logos in 82.0 (rhbz1896319) +# new logo requires new footer copyring which was added in rhbz1934800 +Requires: /etc/mime.types, system-logos(httpd-logo-ng) +Obsoletes: httpd-suexec +Provides: webserver +Provides: mod_dav = %{version}-%{release}, httpd-suexec = %{version}-%{release} +Provides: httpd-mmn = %{mmn}, httpd-mmn = %{mmnisa} +Requires: httpd-tools = %{version}-%{release} +Requires: httpd-filesystem = %{version}-%{release} +Requires: mod_http2 +Requires(pre): httpd-filesystem +Requires(preun): systemd-units +Requires(postun): systemd-units +Requires(post): systemd-units +Conflicts: apr < 1.5.0-1 + +%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 +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 filesystem +Group: System Environment/Daemons +Summary: The basic directory layout for the Apache HTTP server +BuildArch: noarch +Requires(pre): /usr/sbin/useradd + +%description filesystem +The httpd-filesystem package contains the basic directory layout +for the Apache HTTP server including the correct permissions +for the directories. + +%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 +Requires(pre): httpd-filesystem +Requires: httpd = 0:%{version}-%{release}, httpd-mmn = %{mmnisa} +Requires: sscg >= 2.2.0 +Obsoletes: stronghold-mod_ssl +# Require an OpenSSL which supports PROFILE=SYSTEM +Conflicts: openssl-libs < 1:1.0.1h-4 + +%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 + +%patch19 -p1 -b .detectsystemd +%patch20 -p1 -b .export +%patch21 -p1 -b .corelimit +%patch22 -p1 -b .selinux +%patch23 -p1 -b .icons +%patch24 -p1 -b .systemd +%patch25 -p1 -b .cachehardmax +%patch26 -p1 -b .socketactivation +%patch27 -p1 -b .sslciphdefault +%patch28 -p1 -b .statementscomment +%patch29 -p1 -b .fullrelease +%patch30 -p1 -b .freebind +%patch31 -p1 -b .r1830819+ +%patch32 -p1 -b .sslprotdefault +%patch33 -p1 -b .mod-md-mod-ssl-hooks +%patch34 -p1 -b .r1861793+ +%patch35 -p1 -b .sslkeylogfile-support +%patch36 -p1 -b .session-expiry +%patch37 -p1 -b .logjournal +%patch38 -p1 -b .pr37355 +%patch39 -p1 -b .proxy-ws-idle-timeout +%patch40 -p1 -b .ssl-proxy-chains +%patch41 -p1 -b .usertrack-samesite + +%patch61 -p1 -b .r1738878 +%patch62 -p1 -b .r1633085 +%patch63 -p1 -b .r1811831 +%patch65 -p1 -b .r1842888 +%patch66 -p1 -b .r1842929+ +%patch67 -p1 -b .r1825120 +%patch68 -p1 -b .fipscore +%patch70 -p1 -b .r1840554 +%patch71 -p1 -b .modmdperms +%patch72 -p1 -b .mimemagic +%patch73 -p1 -b .ocspwrongctx +%patch74 -p1 -b .r1828172+ +%patch75 -p1 -b .r1870095+ +%patch76 -p1 -b .proxy-continue +%patch77 -p1 -b .balancer-failover +%patch78 -p1 -b .r1881459 +%patch79 -p1 -b .r1864000 +%patch80 -p1 -b .r1872790 +%patch81 -p1 -b .r1879224 +%patch82 -p1 -b .r1877397 +%patch83 -p1 -b .r1878890 +%patch84 -p1 -b .r1878280 +%patch85 -p1 -b .htcacheclean-dont-break +%patch86 -p1 -b .r1873907 +%patch87 -p1 -b .reply-two-tls-rec +%patch88 -p1 -b .r1845768+ +%patch89 -p1 -b .r1862410 +%patch90 -p1 -b .hcheck-mem-issues + +%patch200 -p1 -b .r1851471 +%patch201 -p1 -b .CVE-2019-0211 +%patch202 -p1 -b .CVE-2019-0215 +%patch203 -p1 -b .CVE-2019-0217 +%patch204 -p1 -b .CVE-2019-0220 +%patch205 -p1 -b .CVE-2019-9511-and-9516-and-9517 +%patch206 -p1 -b .CVE-2019-10098 +%patch207 -p1 -b .CVE-2019-10092 +%patch208 -p1 -b .CVE-2019-10097 +%patch209 -p1 -b .CVE-2020-1934 +%patch210 -p1 -b .CVE-2018-17199 +%patch211 -p1 -b .CVE-2020-11984 +%patch212 -p1 -b .CVE-2021-30641 +%patch213 -p1 -b .CVE-2021-26690 +%patch214 -p1 -b .CVE-2021-40438 +%patch215 -p1 -b .CVE-2021-26691 +%patch216 -p1 -b .CVE-2020-35452 +%patch217 -p1 -b .CVE-2021-34798 +%patch218 -p1 -b .CVE-2021-39275 +%patch219 -p1 -b .CVE-2021-36160 +%patch220 -p1 -b .CVE-2021-33193 +%patch221 -p1 -b .CVE-2021-44790 +%patch222 -p1 -b .CVE-2021-44224 +%patch223 -p1 -b .CVE-2022-22720 + +# Patch in the vendor 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 + +# Example conf for instances +cp $RPM_SOURCE_DIR/instance.conf . +sed < $RPM_SOURCE_DIR/httpd.conf >> instance.conf ' +0,/^ServerRoot/d; +/# Supplemental configuration/,$d +/^ *CustomLog .logs/s,logs/,logs/${HTTPD_INSTANCE}_, +/^ *ErrorLog .logs/s,logs/,logs/${HTTPD_INSTANCE}_, +' +touch -r $RPM_SOURCE_DIR/instance.conf instance.conf + +# 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 + +# A new logo which comes together with a new test page +cp %{SOURCE46} ./docs/icons/apache_pb3.png + +# Provide default layout +cp $RPM_SOURCE_DIR/config.layout . + +sed ' +s,@MPM@,%{mpm},g +s,@DOCROOT@,%{docroot},g +s,@LOGDIR@,%{_localstatedir}/log/httpd,g +' < $RPM_SOURCE_DIR/httpd.conf.xml \ + > httpd.conf.xml + +xmlto man ./httpd.conf.xml +xmlto man $RPM_SOURCE_DIR/htcacheclean.service.xml +xmlto man $RPM_SOURCE_DIR/httpd.service.xml + +: Building with MMN %{mmn}, MMN-ISA %{mmnisa} +: Default MPM is %{mpm}, vendor string is '%{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" + +# 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=1000 --with-suexec-gidmin=1000 \ + --with-brotli \ + --enable-pie \ + --with-pcre \ + --enable-mods-shared=all \ + --enable-ssl --with-ssl --disable-distcache \ + --enable-proxy --enable-proxy-fdpass \ + --enable-cache \ + --enable-disk-cache \ + --enable-ldap --enable-authnz-ldap \ + --enable-cgid --enable-cgi \ + --enable-cgid-fdpassing \ + --enable-authn-anon --enable-authn-alias \ + --disable-imagemap --disable-file-cache \ + --disable-http2 \ + --disable-md \ + $* +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.service htcacheclean.service httpd.socket \ + httpd@.service httpd-init.service; do + install -p -m 644 $RPM_SOURCE_DIR/${s} \ + $RPM_BUILD_ROOT%{_unitdir}/${s} +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 +install -m 644 $RPM_SOURCE_DIR/README.confmod \ + $RPM_BUILD_ROOT%{_sysconfdir}/httpd/conf.modules.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 00-optional.conf; do + install -m 644 -p $RPM_SOURCE_DIR/$f \ + $RPM_BUILD_ROOT%{_sysconfdir}/httpd/conf.modules.d/$f +done + +sed -i '/^#LoadModule mpm_%{mpm}_module /s/^#//' \ + $RPM_BUILD_ROOT%{_sysconfdir}/httpd/conf.modules.d/00-mpm.conf +touch -r $RPM_SOURCE_DIR/00-mpm.conf \ + $RPM_BUILD_ROOT%{_sysconfdir}/httpd/conf.modules.d/00-mpm.conf + +# install systemd override drop directory +# Web application packages can drop snippets into this location if +# they need ExecStart[pre|post]. +mkdir $RPM_BUILD_ROOT%{_unitdir}/httpd.service.d +mkdir $RPM_BUILD_ROOT%{_unitdir}/httpd.socket.d + +install -m 644 -p $RPM_SOURCE_DIR/10-listen443.conf \ + $RPM_BUILD_ROOT%{_unitdir}/httpd.socket.d/10-listen443.conf + +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 + install -m 644 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 +install -m 644 -p $RPM_SOURCE_DIR/htcacheclean.sysconf \ + $RPM_BUILD_ROOT%{_sysconfdir}/sysconfig/htcacheclean + +# 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%{_localstatedir}/lib/httpd \ + $RPM_BUILD_ROOT/run/httpd/htcacheclean + +# Substitute in defaults which are usually done (badly) by "make install" +sed -i \ + "s,@@ServerRoot@@/var,%{_localstatedir}/lib/dav,; + s,@@ServerRoot@@/user.passwd,/etc/httpd/conf/user.passwd,; + s,@@ServerRoot@@/docs,%{docroot},; + s,@@ServerRoot@@,%{docroot},; + s,@@Port@@,80,;" \ + docs/conf/extra/*.conf + +# 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%{_rpmconfigdir}/macros.d +cat > $RPM_BUILD_ROOT%{_rpmconfigdir}/macros.d/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 filesystem +getent group apache >/dev/null || groupadd -g 48 -r apache +getent passwd apache >/dev/null || \ + useradd -r -u 48 -g apache -s /sbin/nologin \ + -d %{contentdir} -c "Apache" apache +exit 0 + +%post +%systemd_post httpd.service htcacheclean.service httpd.socket + +%preun +%systemd_preun httpd.service htcacheclean.service httpd.socket + +%postun +%systemd_postun httpd.service htcacheclean.service httpd.socket + +# 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 --no-block httpd.service htcacheclean.service >/dev/null 2>&1 || : + +%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 +set +x +rv=0 +# Ensure every mod_* that's built is loaded. +for f in $RPM_BUILD_ROOT%{_libdir}/httpd/modules/*.so; do + m=${f##*/} + if ! grep -q $m $RPM_BUILD_ROOT%{_sysconfdir}/httpd/conf.modules.d/*.conf; then + echo ERROR: Module $m not configured. Disable it, or load it. + rv=1 + fi +done +# Ensure every loaded mod_* is actually built +mods=`grep -h ^LoadModule $RPM_BUILD_ROOT%{_sysconfdir}/httpd/conf.modules.d/*.conf | sed 's,.*modules/,,'` +for m in $mods; do + f=$RPM_BUILD_ROOT%{_libdir}/httpd/modules/${m} + if ! test -x $f; then + echo ERROR: Module $m is configured but not built. + rv=1 + fi +done +set -x +exit $rv + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root) + +%doc ABOUT_APACHE README CHANGES LICENSE VERSIONING NOTICE +%doc docs/conf/extra/*.conf +%doc instance.conf + +%{_sysconfdir}/httpd/modules +%{_sysconfdir}/httpd/logs +%{_sysconfdir}/httpd/state +%{_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 + +%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 +%{_sysconfdir}/httpd/conf.modules.d/README +%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/htcacheclean +%{_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}/error +%dir %{contentdir}/error/include +%dir %{contentdir}/noindex +%{contentdir}/icons/* +%{contentdir}/error/README +%{contentdir}/error/*.var +%{contentdir}/error/include/*.html +%{contentdir}/noindex/index.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}/lib/httpd +%attr(0700,apache,apache) %dir %{_localstatedir}/cache/httpd +%attr(0700,apache,apache) %dir %{_localstatedir}/cache/httpd/proxy + +%{_mandir}/man8/* +%{_mandir}/man5/* +%exclude %{_mandir}/man8/httpd-init.* + +%{_unitdir}/httpd.service +%{_unitdir}/httpd@.service +%{_unitdir}/htcacheclean.service +%{_unitdir}/*.socket + +%files filesystem +%dir %{_sysconfdir}/httpd +%dir %{_sysconfdir}/httpd/conf.d +%{_sysconfdir}/httpd/conf.d/README +%dir %{docroot} +%dir %{docroot}/cgi-bin +%dir %{docroot}/html +%dir %{contentdir} +%dir %{contentdir}/icons +%attr(755,root,root) %dir %{_unitdir}/httpd.service.d +%attr(755,root,root) %dir %{_unitdir}/httpd.socket.d + +%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 +%{_unitdir}/httpd-init.service +%{_libexecdir}/httpd-ssl-pass-dialog +%{_libexecdir}/httpd-ssl-gencerts +%{_unitdir}/httpd.socket.d/10-listen443.conf +%{_mandir}/man8/httpd-init.* + +%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 +%{_rpmconfigdir}/macros.d/macros.httpd + +%changelog +* Mon Mar 21 2022 LuboÅ¡ Uhliarik - 2.4.37-47.1 +- Resolves: #2065248 - CVE-2022-22720 httpd:2.4/httpd: HTTP request smuggling + vulnerability in Apache HTTP Server 2.4.52 and earlier + +* Thu Jan 20 2022 LuboÅ¡ Uhliarik - 2.4.37-47 +- Resolves: #2035030 - CVE-2021-44224 httpd:2.4/httpd: possible NULL dereference + or SSRF in forward proxy configurations + +* Mon Jan 10 2022 LuboÅ¡ Uhliarik - 2.4.37-46 +- Resolves: #2035063 - CVE-2021-44790 httpd:2.4/httpd: mod_lua: possible buffer + overflow when parsing multipart content + +* Thu Jan 06 2022 LuboÅ¡ Uhliarik - 2.4.37-45 +- Resolves: #2007199 - CVE-2021-36160 httpd:2.4/httpd: mod_proxy_uwsgi: + out-of-bounds read via a crafted request uri-path +- Resolves: #1972491 - CVE-2021-33193 httpd:2.4/mod_http2: Request splitting via + HTTP/2 method injection and mod_proxy + +* Mon Nov 29 2021 LuboÅ¡ Uhliarik - 2.4.37-44 +- Resolves: #1968278 - CVE-2020-35452 httpd:2.4/httpd: Single zero byte stack + overflow in mod_auth_digest +- Resolves: #2001046 - Apache httpd OOME with mod_dav in RHEL 8 +- Resolves: #2005128 (CVE-2021-34798) - CVE-2021-34798 httpd: NULL pointer + dereference via malformed requests +- Resolves: #1984828 - mod_proxy_hcheck piles up health checks leading to high + memory consumption +- Resolves: #2005119 - CVE-2021-39275 httpd: out-of-bounds write in + ap_escape_quotes() via malicious input + +* Tue Oct 26 2021 LuboÅ¡ Uhliarik - 2.4.37-43 +- Related: #2007236 - CVE-2021-40438 httpd:2.4/httpd: mod_proxy: SSRF via + a crafted request uri-path + +* Thu Sep 30 2021 LuboÅ¡ Uhliarik - 2.4.37-42 +- Resolves: #2007236 - CVE-2021-40438 httpd:2.4/httpd: mod_proxy: SSRF via + a crafted request uri-path +- Resolves: #1969229 - CVE-2021-26691 httpd:2.4/httpd: Heap overflow in + mod_session + +* Fri Jul 09 2021 LuboÅ¡ Uhliarik - 2.4.37-41 +- Resolves: #1680111 - httpd sends reply to HTTPS GET using two TLS records +- Resolves: #1905613 - mod_ssl does not like valid certificate chain +- Resolves: #1935742 - [RFE] backport samesite/httponly/secure flags for + usertrack +- Resolves: #1972500 - CVE-2021-30641 httpd:2.4/httpd: MergeSlashes regression +- Resolves: #1968307 - CVE-2021-26690 httpd:2.4/httpd: mod_session NULL pointer + dereference in parser +- Resolves: #1934741 - Apache trademark update - new logo + +* Fri May 14 2021 Lubos Uhliarik - 2.4.37-40 +- Resolves: #1952557 - mod_proxy_wstunnel.html is a malformed XML +- Resolves: #1937334 - SSLProtocol with based virtual hosts + +* Tue Jan 26 2021 Artem Egorenkov - 2.4.37-39 +- prevent htcacheclean from while break when first file processed + +* Tue Jan 26 2021 Lubos Uhliarik - 2.4.37-38 +- Resolves: #1918741 - Thousands of /tmp/modproxy.tmp.* files created by apache + +* Wed Dec 09 2020 Lubos Uhliarik - 2.4.37-37 +- Resolves: #1883648 - [RFE] Update httpd directive SSLProxyMachineCertificateFile + to be able to handle certs without matching private key + +* Mon Nov 30 2020 Lubos Uhliarik - 2.4.37-36 +- Resolves: #1896176 - [RFE] ProxyWebsocketIdleTimeout from httpd + mod_proxy_wstunnel +- Resolves: #1847585 - mod_ldap: High CPU usage at apr_ldap_rebind_remove() + +* Wed Nov 11 2020 Lubos Uhliarik - 2.4.37-35 +- Resolves: #1651376 - centralizing default index.html for httpd + +* Fri Nov 06 2020 Lubos Uhliarik - 2.4.37-33 +- Resolves: #1868608 - Intermittent Segfault in Apache httpd due to pool + concurrency issues +- Resolves: #1861380 - httpd/mod_proxy_http/mod_ssl aborted when sending + a client cert to backend server +- Resolves: #1680118 - unorderly connection close when client attempts + renegotiation + +* Thu Oct 29 2020 Lubos Uhliarik - 2.4.37-31 +- Resolves: #1677590 - CVE-2018-17199 httpd:2.4/httpd: mod_session_cookie does + not respect expiry time +- Resolves: #1869075 - CVE-2020-11984 httpd:2.4/httpd: mod_proxy_uswgi buffer + overflow +- Resolves: #1872828 - httpd: typo in htpasswd, contained in httpd-tools package +- Resolves: #1869576 - httpd : mod_proxy should allow to specify + Proxy-Authorization in ProxyRemote directive +- Resolves: #1875844 - mod_cgid takes CGIDScriptTimeout x 2 seconds for timeout +- Resolves: #1891829 - mod_proxy_hcheck Doesn't perform checks when in + a balancer + +* Mon Jun 15 2020 Joe Orton - 2.4.37-30 +- Resolves: #1209162 - support logging to journald from CustomLog + +* Mon Jun 08 2020 Lubos Uhliarik - 2.4.37-29 +- Resolves: #1823263 (CVE-2020-1934) - CVE-2020-1934 httpd: mod_proxy_ftp use of + uninitialized value + +* Fri May 29 2020 Lubos Uhliarik - 2.4.37-28 +- Related: #1771847 - BalancerMember ping parameter for mod_proxy_http + doesn't work + +* Tue Apr 14 2020 Lubos Uhliarik - 2.4.37-27 +- Resolves: #1823259 - CVE-2020-1927 httpd:2.4/httpd: mod_rewrite configurations + vulnerable to open redirect +- Resolves: #1747284 - CVE-2019-10098 httpd:2.4/httpd: mod_rewrite potential + open redirect +- Resolves: #1747281 - CVE-2019-10092 httpd:2.4/httpd: limited cross-site + scripting in mod_proxy error page +- Resolves: #1747291 - CVE-2019-10097 httpd:2.4/httpd: null-pointer dereference + in mod_remoteip +- Resolves: #1771847 - BalancerMember ping parameter for mod_proxy_http + doesn't work +- Resolves: #1794728 - Backport of SessionExpiryUpdateInterval directive + +* Mon Dec 02 2019 Lubos Uhliarik - 2.4.37-21 +- Resolves: #1775158 - POST request with TLS 1.3 PHA client auth fails: + Re-negotiation handshake failed: Client certificate missing + +* Sun Dec 01 2019 Lubos Uhliarik - 2.4.37-20 +- Resolves: #1704317 - Add support for SSLKEYLOGFILE + +* Thu Nov 28 2019 Joe Orton - 2.4.37-19 +- mod_cgid: enable fd passing (#1633224) + +* Mon Nov 18 2019 Lubos Uhliarik - 2.4.37-18 +- Resolves: #1744121 - Unexpected OCSP in proxy SSL connection +- Resolves: #1725031 - htpasswd: support SHA-x passwords for FIPS compatibility +- Resolves: #1633224 - mod_cgid logging issues + +* Wed Oct 02 2019 Lubos Uhliarik - 2.4.37-17 +- remove bundled mod_md module +- Related: #1747898 - add mod_md package + +* Thu Aug 29 2019 Lubos Uhliarik - 2.4.37-16 +- Resolves: #1744999 - CVE-2019-9511 httpd:2.4/mod_http2: HTTP/2: large amount + of data request leads to denial of service +- Resolves: #1745086 - CVE-2019-9516 httpd:2.4/mod_http2: HTTP/2: 0-length + headers leads to denial of service +- Resolves: #1745154 - CVE-2019-9517 httpd:2.4/mod_http2: HTTP/2: request for + large response leads to denial of service + +* Tue Jul 16 2019 Lubos Uhliarik - 2.4.37-15 +- Resolves: #1730721 - absolute path used for default state and runtime dir by + default + +* Thu Jun 27 2019 Lubos Uhliarik - 2.4.37-14 +- Resolves: #1724549 - httpd response contains garbage in Content-Type header + +* Wed Jun 12 2019 Lubos Uhliarik - 2.4.37-13 +- Resolves: #1696142 - CVE-2019-0217 httpd:2.4/httpd: mod_auth_digest: access + control bypass due to race condition +- Resolves: #1696097 - CVE-2019-0220 httpd:2.4/httpd: URL normalization + inconsistency +- Resolves: #1669221 - `ExtendedStatus Off` directive when using mod_systemd + causes systemctl to hang +- Resolves: #1673022 - httpd can not be started with mod_md enabled + +* Mon Apr 08 2019 Lubos Uhliarik - 2.4.37-11 +- Resolves: #1695432 - CVE-2019-0211 httpd: privilege escalation + from modules scripts +- Resolves: #1696091 - CVE-2019-0215 httpd:2.4/httpd: mod_ssl: access control + bypass when using per-location client certification authentication + +* Wed Feb 06 2019 Lubos Uhliarik - 2.4.37-10 +- Resolves: #1672977 - state-dir corruption on reload + +* Tue Feb 05 2019 Lubos Uhliarik - 2.4.37-9 +- Resolves: #1670716 - Coredump when starting in FIPS mode + +* Fri Feb 1 2019 Joe Orton - 2.4.37-8 +- add security fix for CVE-2019-0190 (#1671282) + +* Tue Dec 11 2018 Joe Orton - 2.4.37-7 +- add DefaultStateDir/ap_state_dir_relative() (#1653009) +- mod_dav_fs: use state dir for default DAVLockDB +- mod_md: use state dir for default MDStoreDir + +* Mon Dec 10 2018 Joe Orton - 2.4.37-6 +- add httpd.conf(5) (#1611361) + +* Mon Nov 26 2018 LuboÅ¡ Uhliarik - 2.4.37-5 +- Resolves: #1652966 - Missing RELEASE in http header + +* Fri Nov 23 2018 LuboÅ¡ Uhliarik - 2.4.37-4 +- Resolves: #1641951 - No Documentation= line in htcacheclean.service files + +* Fri Nov 23 2018 LuboÅ¡ Uhliarik - 2.4.37-3 +- Resolves: #1643713 - TLS connection allowed while all protocols are forbidden + +* Thu Nov 22 2018 Joe Orton - 2.4.37-2 +- mod_ssl: fix off-by-one causing crashes in CGI children (#1649428) + +* Wed Nov 21 2018 Lubos Uhliarik - 2.4.37-1 +- Resolves: #1644625 - httpd rebase to 2.4.37 + +* Thu Oct 18 2018 LuboÅ¡ Uhliarik - 2.4.35-10 +- Related: #1493510 - RFE: httpd, add IP_FREEBIND support for Listen + +* Tue Oct 16 2018 Lubos Uhliarik - 2.4.35-9 +- mod_ssl: allow sending multiple CA names which differ only in case + +* Tue Oct 16 2018 Joe Orton - 2.4.35-7 +- mod_ssl: drop SSLRandomSeed from default config (#1638730) +- mod_ssl: follow OpenSSL protocol defaults if SSLProtocol + is not configured (Rob Crittenden, #1638738) + +* Mon Oct 15 2018 Joe Orton - 2.4.35-5 +- mod_ssl: don't require SSLCryptoDevice to be set for PKCS#11 cert + +* Mon Oct 15 2018 Lubos Uhliarik - 2.4.35-4 +- Resolves: #1635681 - sync with Fedora 28/29 httpd +- comment-out SSLProtocol, SSLProxyProtocol from ssl.conf in default + configuration; now follow OpenSSL system default (#1468322) +- dropped NPN support +- mod_md: change hard-coded default MdStoreDir to state/md (#1563846) +- don't block on service try-restart in posttrans scriptlet +- build and load mod_brotli +- mod_systemd: show bound ports in status and log to journal + at startup +- updated httpd.service.xml man page +- tweak wording in privkey passphrase prompt +- drop sslmultiproxy patch +- apachectl: don't read /etc/sysconfig/httpd +- drop irrelevant Obsoletes for devel subpackage +- move instantiated httpd@.service to main httpd package + +* Mon Oct 15 2018 Lubos Uhliarik - 2.4.35-3 +- Resolves: #1602548 - various covscan fixes + +* Thu Sep 27 2018 Lubos Uhliarik - 2.4.35-2 +- apache httpd can work with TLS 1.3 (#1617997) +- drop SSLv3 support patch + +* Thu Sep 27 2018 Lubos Uhliarik - 2.4.35-1 +- new version 2.4.35 (#1632754) + +* Mon Sep 03 2018 Lubos Uhliarik - 2.4.33-4 +- mod_ssl: enable SSLv3 and change behavior of "SSLProtocol All" + configuration (#1622630) + +* Thu Jul 26 2018 Joe Orton - 2.4.33-3 +- mod_ssl: add PKCS#11 cert/key support (Anderson Sasaki, #1527084) + +* Mon Apr 30 2018 LuboÅ¡ Uhliarik - 2.4.33-2 +- new version 2.4.33 +- add mod_md subpackage; load mod_proxy_uwsgi by default + +* Mon Apr 30 2018 Joe Orton - 2.4.28-8 +- remove %%ghosted /etc/sysconfig/httpd (#1572676) + +* Wed Mar 07 2018 LuboÅ¡ Uhliarik - 2.4.28-2 +- Resolves: #1512563 - httpd: update welcome page branding +- Resolves: #1511123 - RFE: httpd use event MPM by default +- Resolves: #1493510 - RFE: httpd, add IP_FREEBIND support for Listen + +* Fri Oct 06 2017 LuboÅ¡ Uhliarik - 2.4.28-1 +- new version 2.4.28 + +* Tue Oct 3 2017 Joe Orton - 2.4.27-14 +- add notes on enabling httpd_graceful_shutdown boolean for prefork + +* Fri Sep 22 2017 Joe Orton - 2.4.27-13 +- drop Requires(post) for mod_ssl + +* Fri Sep 22 2017 Joe Orton - 2.4.27-12 +- better error handling in httpd-ssl-gencerts (#1494556) + +* Thu Sep 21 2017 Stephen Gallagher - 2.4.27-11 +- Require sscg 2.2.0 for creating service and CA certificates together + +* Thu Sep 21 2017 Jeroen van Meeuwen - 2.4.27-10 +- Address CVE-2017-9798 by applying patch from upstream (#1490344) + +* Thu Sep 21 2017 Joe Orton - 2.4.27-9 +- use sscg defaults; append CA cert to generated cert +- document httpd-init.service in httpd-init.service(8) + +* Thu Sep 21 2017 Jeroen van Meeuwen - 2.4.27-8 +- Address CVE-2017-9798 by applying patch from upstream (#1490344) + +* Wed Sep 20 2017 Stephen Gallagher - 2.4.27-8.1 +- Generate SSL certificates on service start, not %%posttrans + +* Tue Sep 19 2017 Joe Orton - 2.4.27-8.1 +- move httpd.service.d, httpd.socket.d dirs to -filesystem + +* Wed Sep 13 2017 Joe Orton - 2.4.27-7 +- add new content-length filter (upstream PR 61222) + +* Wed Aug 02 2017 Fedora Release Engineering - 2.4.27-6 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Wed Jul 26 2017 Fedora Release Engineering - 2.4.27-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Tue Jul 18 2017 Joe Orton - 2.4.27-4 +- update mod_systemd (r1802251) + +* Mon Jul 17 2017 Joe Orton - 2.4.27-3 +- switch to event by default for Fedora 27 and later (#1471708) + +* Wed Jul 12 2017 LuboÅ¡ Uhliarik - 2.4.27-2 +- Resolves: #1469959 - httpd update cleaned out /etc/sysconfig + +* Mon Jul 10 2017 LuboÅ¡ Uhliarik - 2.4.27-1 +- new version 2.4.27 + +* Fri Jun 30 2017 Joe Orton - 2.4.26-2 +- mod_proxy_fcgi: fix further regressions (PR 61202) + +* Mon Jun 19 2017 LuboÅ¡ Uhliarik - 2.4.26-1 +- new version 2.4.26 + +* Mon Jun 5 2017 Joe Orton - 2.4.25-10 +- move unit man pages to section 8, add as Documentation= in units + +* Fri May 19 2017 Joe Orton - 2.4.25-9 +- add httpd.service(5) and httpd.socket(5) man pages + +* Tue May 16 2017 Joe Orton - 2.4.25-8 +- require mod_http2, now packaged separately + +* Wed Mar 29 2017 LuboÅ¡ Uhliarik - 2.4.25-7 +- Resolves: #1397243 - Backport Apache Bug 53098 - mod_proxy_ajp: + patch to set worker secret passed to tomcat + +* Tue Mar 28 2017 LuboÅ¡ Uhliarik - 2.4.25-6 +- Resolves: #1434916 - httpd.service: Failed with result timeout + +* Fri Mar 24 2017 Joe Orton - 2.4.25-5 +- link only httpd, not support/* against -lselinux -lsystemd + +* Fri Feb 10 2017 Fedora Release Engineering - 2.4.25-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Thu Jan 12 2017 Joe Orton - 2.4.25-3 +- mod_watchdog: restrict thread lifetime (#1410883) + +* Thu Dec 22 2016 LuboÅ¡ Uhliarik - 2.4.25-2 +- Resolves: #1358875 - require nghttp2 >= 1.5.0 + +* Thu Dec 22 2016 LuboÅ¡ Uhliarik - 2.4.25-1 +- new version 2.4.25 + +* Mon Dec 05 2016 LuboÅ¡ Uhliarik - 2.4.23-7 +- Resolves: #1401530 - CVE-2016-8740 httpd: Incomplete handling of + LimitRequestFields directive in mod_http2 + +* Mon Nov 14 2016 Joe Orton - 2.4.23-6 +- fix build with OpenSSL 1.1 (#1392900) +- fix typos in ssl.conf (josef randinger, #1379407) + +* Wed Nov 2 2016 Joe Orton - 2.4.23-5 +- no longer package /etc/sysconfig/httpd +- synch ssl.conf with upstream + +* Mon Jul 18 2016 Joe Orton - 2.4.23-4 +- add security fix for CVE-2016-5387 + +* Thu Jul 7 2016 Joe Orton - 2.4.23-3 +- load mod_watchdog by default (#1353582) + +* Thu Jul 7 2016 Joe Orton - 2.4.23-2 +- restore build of mod_proxy_fdpass (#1325883) +- improve check tests to catch configured-but-not-built modules + +* Thu Jul 7 2016 Joe Orton - 2.4.23-1 +- update to 2.4.23 (#1325883, #1353203) +- load mod_proxy_hcheck +- recommend use of "systemctl edit" in httpd.service + +* Thu Apr 7 2016 Joe Orton - 2.4.18-6 +- have "apachectl graceful" start httpd if not running, per man page + +* Wed Apr 6 2016 Joe Orton - 2.4.18-5 +- use redirects for lang-specific /manual/ URLs + +* Fri Mar 18 2016 Joe Orton - 2.4.18-4 +- fix welcome page HTML validity (Ville Skyttä) + +* Fri Mar 18 2016 Joe Orton - 2.4.18-3 +- remove httpd pre script (duplicate of httpd-filesystem's) +- in httpd-filesystem pre script, create group/user iff non-existent + +* Wed Feb 03 2016 Fedora Release Engineering - 2.4.18-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild + +* Mon Dec 14 2015 Jan Kaluza - 2.4.18-1 +- update to new version 2.4.18 + +* Wed Dec 9 2015 Joe Orton - 2.4.17-4 +- re-enable mod_asis due to popular demand (#1284315) + +* Mon Oct 26 2015 Jan Kaluza - 2.4.17-3 +- fix crash when using -X argument (#1272234) + +* Wed Oct 14 2015 Jan Kaluza - 2.4.17-2 +- rebase socket activation patch to 2.4.17 + +* Tue Oct 13 2015 Joe Orton - 2.4.17-1 +- update to 2.4.17 (#1271224) +- build, load mod_http2 +- don't build mod_asis, mod_file_cache +- load mod_cache_socache, mod_proxy_wstunnel by default +- check every built mod_* is configured +- synch ssl.conf with upstream; disable SSLv3 by default + +* Wed Jul 15 2015 Jan Kaluza - 2.4.12-4 +- update to 2.4.16 + +* Tue Jul 7 2015 Joe Orton - 2.4.12-3 +- mod_ssl: use "localhost" in the dummy SSL cert if len(FQDN) > 59 chars + +* Wed Jun 17 2015 Fedora Release Engineering - 2.4.12-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild + +* Fri Mar 27 2015 Jan Kaluza - 2.4.12-1 +- update to 2.4.12 + +* Tue Mar 24 2015 Jan Kaluza - 2.4.10-17 +- fix compilation with lua-5.3 + +* Tue Mar 24 2015 Jan Kaluza - 2.4.10-16 +- remove filter for auto-provides of httpd modules, it is not needed since F20 + +* Wed Dec 17 2014 Jan Kaluza - 2.4.10-15 +- 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) +- mod_proxy_fcgi: fix a potential crash with long headers (CVE-2014-3583) +- mod_lua: fix handling of the Require line when a LuaAuthzProvider is used + in multiple Require directives with different arguments (CVE-2014-8109) + +* Tue Oct 14 2014 Joe Orton - 2.4.10-14 +- require apr-util 1.5.x + +* Thu Sep 18 2014 Jan Kaluza - 2.4.10-13 +- use NoDelay and DeferAcceptSec in httpd.socket + +* Mon Sep 08 2014 Jan Kaluza - 2.4.10-12 +- increase suexec minimum acceptable uid/gid to 1000 (#1136391) + +* Wed Sep 03 2014 Jan Kaluza - 2.4.10-11 +- fix hostname requirement and conflict with openssl-libs + +* Mon Sep 01 2014 Jan Kaluza - 2.4.10-10 +- use KillMode=mixed in httpd.service (#1135122) + +* Fri Aug 29 2014 Joe Orton - 2.4.10-9 +- set vstring based on /etc/os-release (Pat Riehecky, #1114539) + +* Fri Aug 29 2014 Joe Orton - 2.4.10-8 +- pull in httpd-filesystem as Requires(pre) (#1128328) +- fix cipher selection in default ssl.conf, depend on new OpenSSL (#1134348) +- require hostname for mod_ssl post script (#1135118) + +* Fri Aug 22 2014 Jan Kaluza - 2.4.10-7 +- mod_systemd: updated to the latest version +- use -lsystemd instead of -lsystemd-daemon (#1125084) +- fix possible crash in SIGINT handling (#958934) + +* Thu Aug 21 2014 Joe Orton - 2.4.10-6 +- mod_ssl: treat "SSLCipherSuite PROFILE=..." as special (#1109119) +- switch default ssl.conf to use PROFILE=SYSTEM (#1109119) + +* Sat Aug 16 2014 Fedora Release Engineering - 2.4.10-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild + +* Fri Aug 15 2014 Jan Kaluza - 2.4.10-4 +- add /usr/bin/useradd dependency to -filesystem requires + +* Thu Aug 14 2014 Jan Kaluza - 2.4.10-3 +- fix creating apache user in pre script (#1128328) + +* Thu Jul 31 2014 Joe Orton - 2.4.10-2 +- enable mod_request by default for mod_auth_form +- move disabled-by-default modules from 00-base.conf to 00-optional.conf + +* Mon Jul 21 2014 Joe Orton - 2.4.10-1 +- update to 2.4.10 +- expand variables in docdir example configs + +* Tue Jul 08 2014 Jan Kaluza - 2.4.9-8 +- add support for systemd socket activation (#1111648) + +* Mon Jul 07 2014 Jan Kaluza - 2.4.9-7 +- remove conf.modules.d from httpd-filesystem subpackage (#1081453) + +* Mon Jul 07 2014 Jan Kaluza - 2.4.9-6 +- add httpd-filesystem subpackage (#1081453) + +* Fri Jun 20 2014 Joe Orton - 2.4.9-5 +- mod_ssl: don't use the default OpenSSL cipher suite in ssl.conf (#1109119) + +* Sat Jun 07 2014 Fedora Release Engineering - 2.4.9-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild + +* Fri Mar 28 2014 Jan Kaluza - 2.4.9-3 +- add support for SetHandler + proxy (#1078970) + +* Thu Mar 27 2014 Jan Kaluza - 2.4.9-2 +- move macros from /etc/rpm to macros.d (#1074277) +- remove unused patches + +* Mon Mar 17 2014 Jan Kaluza - 2.4.9-1 +- update to 2.4.9 + +* Fri Feb 28 2014 Joe Orton - 2.4.7-6 +- use 2048-bit RSA key with SHA-256 signature in dummy certificate + +* Fri Feb 28 2014 Stephen Gallagher 2.4.7-5 +- Create drop directory for systemd snippets + +* Thu Feb 27 2014 Jan Kaluza - 2.4.7-4 +- remove provides of old MMN, because it contained double-dash (#1068851) + +* Thu Feb 20 2014 Jan Kaluza - 2.4.7-3 +- fix graceful restart using legacy actions + +* Thu Dec 12 2013 Joe Orton - 2.4.7-2 +- conflict with pre-1.5.0 APR +- fix sslsninotreq patch + +* Wed Nov 27 2013 Joe Orton - 2.4.7-1 +- update to 2.4.7 (#1034071) + +* Fri Nov 22 2013 Joe Orton - 2.4.6-10 +- switch to requiring system-logos-httpd (#1031288) + +* Tue Nov 12 2013 Joe Orton - 2.4.6-9 +- change mmnisa to drop "-" altogether + +* Tue Nov 12 2013 Joe Orton - 2.4.6-8 +- drop ambiguous invalid "-" in RHS of httpd-mmn Provide, keeping old Provide + for transition + +* Fri Nov 1 2013 Jan Kaluza - 2.4.6-7 +- systemd: use {MAINPID} notation to ensure /bin/kill has always the second arg + +* Thu Oct 31 2013 Joe Orton - 2.4.6-6 +- mod_ssl: allow SSLEngine to override Listen-based default (r1537535) + +* Thu Oct 24 2013 Jan kaluza - 2.4.6-5 +- systemd: send SIGWINCH signal without httpd -k in ExecStop + +* Mon Oct 21 2013 Joe Orton - 2.4.6-4 +- load mod_macro by default (#998452) +- add README to conf.modules.d +- mod_proxy_http: add possible fix for threading issues (r1534321) +- core: add fix for truncated output with CGI scripts (r1530793) + +* Thu Oct 10 2013 Jan Kaluza - 2.4.6-3 +- require fedora-logos-httpd (#1009162) + +* 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 + +* Fri May 24 2013 Jan Kaluza - 2.4.4-7 +- ignore /etc/sysconfig/httpd and document systemd way of setting env variables + in this file + +* 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 +- 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 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) + diff --git a/httpd.tmpfiles b/httpd.tmpfiles new file mode 100644 index 0000000..f148886 --- /dev/null +++ b/httpd.tmpfiles @@ -0,0 +1,2 @@ +d /run/httpd 710 root apache +d /run/httpd/htcacheclean 700 apache apache diff --git a/httpd@.service b/httpd@.service new file mode 100644 index 0000000..c58ae88 --- /dev/null +++ b/httpd@.service @@ -0,0 +1,23 @@ +# This is a template for httpd instances. +# See httpd@.service(8) for more information. + +[Unit] +Description=The Apache HTTP Server +After=network.target remote-fs.target nss-lookup.target +Documentation=man:httpd@.service(8) + +[Service] +Type=notify +Environment=LANG=C +Environment=HTTPD_INSTANCE=%i +ExecStartPre=/bin/mkdir -m 710 -p /run/httpd/instance-%i +ExecStartPre=/bin/chown root.apache /run/httpd/instance-%i +ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND -f conf/%i.conf +ExecReload=/usr/sbin/httpd $OPTIONS -k graceful -f conf/%i.conf +# Send SIGWINCH for graceful stop +KillSignal=SIGWINCH +KillMode=mixed +PrivateTmp=true + +[Install] +WantedBy=multi-user.target diff --git a/instance.conf b/instance.conf new file mode 100644 index 0000000..f2b03f7 --- /dev/null +++ b/instance.conf @@ -0,0 +1,23 @@ +# +# This is an example instance-specific configuration file. See the +# httpd.service(8) man page for detailed information on using the +# the httpd@.service with instances. +# +# To use this example, copy instance.conf to /etc/httpd/conf/foobar.conf +# This config will then used as the default configuration when +# running: +# +# # systemctl start httpd@foobar.service +# +# The changes compared to the default are: +# - DefaultRuntime and Pidfile renamed to be instance-specific +# - default logfile names are prefixed with the instance name +# - /etc/httpd/conf.d is NOT included by default (conf.modules.d still is) +# +# Further customisations will be required for an instance to run +# simultaneously to httpd.service under the default configuration, +# e.g. changing the port used with Listen. +# + +DefaultRuntimeDir /run/httpd/instance-${HTTPD_INSTANCE} +PidFile /run/httpd/instance-${HTTPD_INSTANCE}.pid diff --git a/manual.conf b/manual.conf new file mode 100644 index 0000000..133652b --- /dev/null +++ b/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/(?:da|de|en|es|fr|ja|ko|pt-br|ru|tr|zh-cn)(/.*)$ "/manual$1" + diff --git a/mirrors b/mirrors new file mode 100644 index 0000000..dbfc379 --- /dev/null +++ b/mirrors @@ -0,0 +1 @@ +http://www.apache.org/dist/httpd/ diff --git a/mkstatus.sh b/mkstatus.sh new file mode 100755 index 0000000..6763424 --- /dev/null +++ b/mkstatus.sh @@ -0,0 +1,20 @@ +#!/bin/sh +echo '' +echo '' +for f in $*; do + n=${f//httpd-2\.[0-9]\.[0-9][0-9]-/} + n=${n//.patch/} + s_HEAD=`grep ^Upstream-HEAD $f | sed 's/Upstream-HEAD: //'` + s_20=`grep ^Upstream-2.0: $f | sed 's/Upstream-2.0: //'` + s_Com=`grep ^Upstream-Status: $f | sed 's/Upstream-Status: //'` + s_PR=`grep ^Upstream-PR: $f | sed 's/Upstream-PR: //'` + printf ' \n' $n + printf ' %s\n' "$s_HEAD" + printf ' %s\n' "$s_20" + printf ' %s\n' "$s_Com" + if [ -n "$s_PR" ]; then + printf ' \n' "$s_PR" + fi + printf ' \n' +done +echo '' diff --git a/plans/tier1-internal.fmf b/plans/tier1-internal.fmf new file mode 100644 index 0000000..ef4e59e --- /dev/null +++ b/plans/tier1-internal.fmf @@ -0,0 +1,10 @@ +summary: Internal Tier1 beakerlib tests +discover: + how: fmf + url: git://pkgs.devel.redhat.com/tests/httpd + filter: 'tier: 1' +execute: + how: tmt +adjust: + enabled: false + when: distro == centos-stream-9 diff --git a/plans/tier1-public.fmf b/plans/tier1-public.fmf new file mode 100644 index 0000000..c181caa --- /dev/null +++ b/plans/tier1-public.fmf @@ -0,0 +1,7 @@ +summary: Public (Fedora) Tier1 beakerlib tests +discover: + how: fmf + url: https://src.fedoraproject.org/tests/httpd.git + filter: 'tier: 1' +execute: + how: tmt diff --git a/plans/tier2-internal.fmf b/plans/tier2-internal.fmf new file mode 100644 index 0000000..2bc8233 --- /dev/null +++ b/plans/tier2-internal.fmf @@ -0,0 +1,10 @@ +summary: Internal Tier2 beakerlib tests +discover: + how: fmf + url: git://pkgs.devel.redhat.com/tests/httpd + filter: 'tier: 2' +execute: + how: tmt +adjust: + enabled: false + when: distro == centos-stream-9 diff --git a/pullrev.sh b/pullrev.sh new file mode 100755 index 0000000..87b7cd7 --- /dev/null +++ b/pullrev.sh @@ -0,0 +1,65 @@ +#!/bin/sh -e + +if [ $# -lt 1 ]; then + echo "What?" + exit 1 +fi + +repo="https://svn.apache.org/repos/asf/httpd/httpd/trunk" +#repo="https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x" +ver=2.4.51 +prefix="httpd-${ver}" +suffix="${SUFFIX:-r$1${2:++}}" +fn="${prefix}-${suffix}.patch" +vcurl="http://svn.apache.org/viewvc?view=revision&revision=" + +if test -f ${fn}; then + mv -v -f ${fn} ${fn}\~ + echo "# $0 $*" > ${fn} + sed '1{/#.*pullrev/d;};/^--- /,$d' < ${fn}\~ >> ${fn} +else + echo "# $0 $*" > ${fn} +fi + +new=0 +for r in $*; do + case $r in + http*) url=$r ;; + *) url=${vcurl}${r} ;; + esac + if ! grep -q "^${url}" ${fn}; then + echo "${url}" + new=1 + fi +done >> ${fn} + +[ $new -eq 0 ] || echo >> ${fn} + +prev=/dev/null +for r in $*; do + echo "+ fetching ${r}" + this=`mktemp /tmp/pullrevXXXXXX` + case $r in + http*) curl -s "$r" | filterdiff --strip=3 ;; + *) svn diff -c ${r} ${repo} ;; + esac | filterdiff --remove-timestamps --clean \ + -x 'CHANGES' -x '*/next-number' -x 'STATUS' -x '*.xml' \ + --addprefix="${prefix}/" > ${this} + next=`mktemp /tmp/pullrevXXXXXX` + if ! combinediff -w ${prev} ${this} > ${next}; then + echo "Failed combining previous ${prev} with ${this}"; + exit 1 + fi + rm -f "${this}" + [ "${prev}" = "/dev/null" ] || rm -f "${prev}" + prev=${next} +done + +cat ${prev} >> ${fn} + +vi "${fn}" +echo "+ git add ${fn}" +git add "${fn}" +echo "+ spec template:" +echo "PatchN: ${fn}" +echo "%patchN -p1 -b .${suffix}" diff --git a/rpminspect.yaml b/rpminspect.yaml new file mode 100644 index 0000000..1b4f2fe --- /dev/null +++ b/rpminspect.yaml @@ -0,0 +1,6 @@ +--- +badfuncs: + # mod_proxy uses inet_ntoa (safely) for IPv4 address matching, + # and APR interfaces for IPv6 addresses. + ignore: + - /usr/lib*/httpd/modules/mod_proxy.so diff --git a/server-status.conf b/server-status.conf new file mode 100644 index 0000000..be98f1b --- /dev/null +++ b/server-status.conf @@ -0,0 +1,10 @@ +# +# Lua-based server-status page; requires mod_lua to be loaded +# as per default configuration. +# +LuaMapHandler ^/server-status$ /usr/share/httpd/server-status/server-status.lua + + + AllowOverride None + Require local + diff --git a/sources b/sources new file mode 100644 index 0000000..e254bbd --- /dev/null +++ b/sources @@ -0,0 +1,2 @@ +SHA1 (apache-poweredby.png) = 3a7449d6cff00e5ccb3ed8571f34c0528555d38f +SHA1 (httpd-2.4.37.tar.bz2) = 4a38471de821288b0300148016f2b03dfee8adf2 diff --git a/ssl.conf b/ssl.conf new file mode 100644 index 0000000..d28adf3 --- /dev/null +++ b/ssl.conf @@ -0,0 +1,203 @@ +# +# When we also provide SSL we have to listen to the +# standard 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 + +# +# 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 + +# List the protocol versions which clients are allowed to connect with. +# The OpenSSL system profile is used by default. See +# update-crypto-policies(8) for more details. +#SSLProtocol all -SSLv3 +#SSLProxyProtocol all -SSLv3 + +# User agents such as web browsers are not configured for the user's +# own preference of either security or performance, therefore this +# must be the prerogative of the web server administrator who manages +# cpu load versus confidentiality, so enforce the server's cipher order. +SSLHonorCipherOrder on + +# SSL Cipher Suite: +# List the ciphers that the client is permitted to negotiate. +# See the mod_ssl documentation for a complete list. +# The OpenSSL system profile is configured by default. See +# update-crypto-policies(8) for more details. +SSLCipherSuite PROFILE=SYSTEM +SSLProxyCipherSuite PROFILE=SYSTEM + +# Point SSLCertificateFile at a PEM encoded certificate. If +# the certificate is encrypted, then you will be prompted for a +# pass phrase. Note that restarting httpd will prompt again. Keep +# in mind that if you have both an RSA and a DSA certificate you +# can configure both in parallel (to also allow the use of DSA +# ciphers, etc.) +# Some ECC cipher suites (http://www.ietf.org/rfc/rfc4492.txt) +# require an ECC certificate which can also be configured in +# parallel. +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.) +# ECC keys, when in use, can also be configured in parallel +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 convenience. +#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 sent or allowed to be 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 sent 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/tests/ignore_tests.yml b/tests/ignore_tests.yml new file mode 100644 index 0000000..802bea0 --- /dev/null +++ b/tests/ignore_tests.yml @@ -0,0 +1,12 @@ +--- +# Tests that run in all contexts +- hosts: localhost + roles: + - role: standard-test-beakerlib + tags: + - classic + tests: + - smoke + required_packages: + - findutils # beakerlib needs find command + - which # smoke requires which command diff --git a/tests/smoke/Makefile b/tests/smoke/Makefile new file mode 100644 index 0000000..6abde94 --- /dev/null +++ b/tests/smoke/Makefile @@ -0,0 +1,65 @@ +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Makefile of /CoreOS/httpd/Sanity/smoke +# Description: Simple check of httpd test page +# Author: Branislav Nater +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2021 Red Hat, Inc. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +export TEST=/CoreOS/httpd/Sanity/smoke +export TESTVERSION=1.0 + +BUILT_FILES= + +FILES=$(METADATA) runtest.sh Makefile PURPOSE + +.PHONY: all install download clean + +run: $(FILES) build + ./runtest.sh + +build: $(BUILT_FILES) + test -x runtest.sh || chmod a+x runtest.sh + +clean: + rm -f *~ $(BUILT_FILES) + + +include /usr/share/rhts/lib/rhts-make.include + +$(METADATA): Makefile + @echo "Owner: Branislav Nater " > $(METADATA) + @echo "Name: $(TEST)" >> $(METADATA) + @echo "TestVersion: $(TESTVERSION)" >> $(METADATA) + @echo "Path: $(TEST_DIR)" >> $(METADATA) + @echo "Description: Simple check of httpd test page" >> $(METADATA) + @echo "Type: Sanity" >> $(METADATA) + @echo "TestTime: 5m" >> $(METADATA) + @echo "RunFor: httpd" >> $(METADATA) + @echo "Requires: httpd mod_ssl" >> $(METADATA) + @echo "RhtsRequires: library(httpd/http)" >> $(METADATA) + @echo "Priority: Normal" >> $(METADATA) + @echo "License: GPLv2" >> $(METADATA) + @echo "Confidential: no" >> $(METADATA) + @echo "Destructive: no" >> $(METADATA) + @echo "Releases: -RHEL4 -RHELClient5 -RHELServer5" >> $(METADATA) + + rhts-lint $(METADATA) diff --git a/tests/smoke/PURPOSE b/tests/smoke/PURPOSE new file mode 100644 index 0000000..510e749 --- /dev/null +++ b/tests/smoke/PURPOSE @@ -0,0 +1,3 @@ +PURPOSE of /CoreOS/httpd/Sanity/smoke +Description: Simple check of httpd +Author: Branislav Nater diff --git a/tests/smoke/runtest.sh b/tests/smoke/runtest.sh new file mode 100755 index 0000000..f65c8ba --- /dev/null +++ b/tests/smoke/runtest.sh @@ -0,0 +1,64 @@ +#!/bin/bash +# vim: dict+=/usr/share/beakerlib/dictionary.vim cpt=.,w,b,u,t,i,k +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# runtest.sh of /CoreOS/httpd/Sanity/smoke +# Description: Simple check of httpd test page +# Author: Branislav Nater +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# Copyright (c) 2021 Red Hat, Inc. +# +# This copyrighted material is made available to anyone wishing +# to use, modify, copy, or redistribute it subject to the terms +# and conditions of the GNU General Public License version 2. +# +# This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied +# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +# PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public +# License along with this program; if not, write to the Free +# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. +# +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +# Include rhts environment +. /usr/share/beakerlib/beakerlib.sh || exit 1 + +PACKAGES="${PACKAGES:-httpd}" +REQUIRES=${REQUIRES:-} + +rlJournalStart + rlPhaseStartSetup + rlRun "rlImport --all" 0 "Importing Beaker libraries" || rlDie + rlAssertRpm --all + rlFileBackup --clean ${httpCONFDIR}/conf/ + rlFileBackup --clean ${httpCONFDIR}/conf.d/ + rlFileBackup --clean ${httpCONFDIR}/conf.modules.d/ + rlRun "TmpDir=\$(mktemp -d)" 0 "Creating tmp directory" + rlRun "pushd $TmpDir" + rlPhaseEnd + + rlPhaseStartTest + rlRun "httpStart" 0 "Start httpd" + rlRun "httpStatus" 0 "Check status" + rlRun "httpStop" 0 "Stop httpd" + + rlRun "httpSecureStart" 0 "Start httpd with ssl" + rlRun "httpInstallCa $(hostname)" 0 "Install CA" + rlRun "httpSecureStatus" 0 "Check status" + rlRun "httpRemoveCa" 0 "Remove CA" + rlRun "httpSecureStop" 0 "Stop httpd with ssl" + rlPhaseEnd + + rlPhaseStartCleanup + rlRun "rlFileRestore" 0 "Restoring original configuration" + rlRun "popd" + rlRun "rm -r $TmpDir" 0 "Removing tmp directory" + rlPhaseEnd +rlJournalEnd +rlJournalPrintText diff --git a/upstream b/upstream new file mode 100644 index 0000000..c785a88 --- /dev/null +++ b/upstream @@ -0,0 +1 @@ +httpd-2.2.16.tar.gz diff --git a/upstream-key.gpg b/upstream-key.gpg new file mode 100644 index 0000000..52f3bbc --- /dev/null +++ b/upstream-key.gpg @@ -0,0 +1,4981 @@ +This file contains the PGP keys of various developers that work on +the Apache HTTP Server and its subprojects. + +Please don't use these keys for email unless you have asked the owner +because some keys are only used for code signing. + +Please realize that this file itself or the public key servers may be +compromised. You are encouraged to validate the authenticity of these keys in +an out-of-band manner. For information about our validation and signing +policies, please read http://httpd.apache.org/dev/verification.html. + +Apache users: pgp < KEYS +Apache developers: + (pgpk -ll && pgpk -xa ) >> this file. + or + (gpg --fingerprint --list-sigs + && gpg --armor --export ) >> this file. + +Apache developers: please ensure that your key is also available via the +PGP keyservers (such as pgpkeys.mit.edu). + +Type Bits/KeyID Date User ID +pub 1024/2719AF35 1995/05/13 Ben Laurie + Ben Laurie + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: 2.6.3ia + +mQCNAi+0jQEAAAEEAK7oX0FeNncaHfa1v+V7SMUviAm8qB8orWG0zvja4ZtSrHVg +/PMwppUh44t5ERA9lltRBdHu30+YSh8a1dYt1XOD83nknzj9rhtpFAPqyywlLVhN +VY3PVLyMbULw27aEAGc+StFqrDoUQ0+j9QU/YH/IyVN9rBaJyhsIDEUnGa81AAUR +tB5CZW4gTGF1cmllIDxiZW5AYWxncm91cC5jby51az6JARUDBRAyb2Doc3AsNzyk +Yh0BARa6CACUBnsP9Vb+T/PvNYKVQBIODz+90tz5GozWwCVfPVSaRd8Dz+oF1sFs +YCz/KuxqBhL5PkiCuSMfOVlPA5nirjoktMF/af5saZqhPr5rvr67Z1OzZnVDvWe4 +DhFrn8EoLrY5YNJhUwfINnZqyKaQu8TW6p4caLkTCW0KM+4ztTe74xRG9NeE+K0+ +0RMpAF3jEY36LGRjq6miazt2bVZQDTl6CuWE+gAaFlX2ojV7e1xdxVvpBIEc34MP +g9ORJ0evx1QilMt1VyGcS/pe4IQgjdJqjU/4fzqFZkT2nntQMbV9kQyNe2+qfqP7 +giTryIanmBAfd3oOCTsRz2VKPfdhCqCRiQB1AwUQMRdzEEyr2GZv4ALJAQEuhAL6 +A8I84BR+87uNAHD0ZJkTM73WdyMEGvAKBvrZK/g0VLYj0NtgkSuRJfrXnGkuh27I +ZrjfL952Q/mXgMtHhJHJ9YfenGFWSEDHnolNzKOzTQJpE01IZ3nWv7ezA9N1LZVC +iQCVAgUQMROrdRsIDEUnGa81AQEUNgQAlvyjt534RDQd2AYGoZriaFzjaL7dTCRH +4b1zxuWBNWf3pI4W0iwU02Q5rEWEmY5DLl6/ie+vcQKOWSqXVgnM/s6EARdKEN56 +d6PzkwszgfEybDYrcAxReJcTCcV8ItJer/iqpBLgtaxyUpI77NvKcDGHp6BgYpnv +1lNkH0FISK+JAJUDBRAwtzlWdGx7qH+PTVkBARFWA/99NTCMihlOZS7LmHDVic/q +H1K1DVdMcv0iL39+7Pq4+AA/ET8dWIgcjaIreSqAZTpjwU1pMPaWgecDD1rEMCYX +R+JoofLJ24BLcSlpXJ/gWMifYNxqdDeMRkw/aW/kaXQJWIz+oDYNuOyi5VvB6faF +6Lm7P5cw1mX0I5rYc3woh7QoQmVuIExhdXJpZSA8YmVuQGdvbnpvLmJlbi5hbGdy +b3VwLmNvLnVrPokAlQIFEDEXgCUbCAxFJxmvNQEBiL8D/3MLjfHGvuByqP1VFQrF +QeMNd2aIQuC7ys3lkDvrLkkPJQANua0/MdDaZk6F5pCGcTmmmaJOjcOcCheD7FU5 +w9zxkQGR3Swr3opFHSr/CkEl83jRy3oq1MFydWoGajQjIr/c23X8zr+XntPyO6VX +q5He4RrTiXeAEFBzz+J+R+EQ +=zh1u +-----END PGP PUBLIC KEY BLOCK----- + + +Type Bits KeyID Created Expires Algorithm Use +sec+ 1024 0xA99F75DD 1997-01-24 ---------- RSA Sign & Encrypt +f16 Fingerprint16 = F7 E5 6D 20 58 AA B0 65 ED 0D B1 66 03 BA 9C C6 +uid Rodent of Unusual Size +uid Rodent of Unusual Size +uid Rodent of Unusual Size +uid Rodent of Unusual Size +uid Rodent of Unusual Size +uid Ken A L Coar +uid Rodent of Unusual Size +uid Rodent of Unusual Size +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: PGPfreeware 5.0i for non-commercial use + +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 +t89HbY/x/sBXuksvBGxFGhgs +=GI5x +-----END PGP PUBLIC KEY BLOCK----- + +Type Bits KeyID Created Expires Algorithm Use +sec 1024 0x302DA568 2001-02-13 ---------- DSS Sign & Encrypt +f20 Fingerprint20 = DE29 FB39 71E7 1543 FD2D C049 508E AEC5 302D A568 +sub 1024 0x04E15F28 2001-02-13 ---------- Diffie-Hellman +f20 Fingerprint20 = C41F 1F5C 6485 0100 B21B EB14 A14E 77B6 04E1 5F28 +uid Rodent of Unusual Size (DSA) +uid Rodent of Unusual Size (DSA) +uid Rodent of Unusual Size (DSA) +uid Rodent of Unusual Size (DSA) +uid Rodent of Unusual Size (DSA) +uid Rodent of Unusual Size (DSA) +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: PGPfreeware 5.0i for non-commercial use + +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 +oLSGqJ147DJuA6/pNp9OXD1q98vj +=DZH6 +-----END PGP PUBLIC KEY BLOCK----- + +Type Bits KeyID Created Expires Algorithm Use +sec+ 1024 0x2C312D2F 1998-10-17 ---------- DSS Sign & Encrypt +f20 Fingerprint20 = 1315 5B0E 9E63 4F42 BF6C 163F DDBA 64BA 2C31 2D2F +sub 2048 0xC9D00816 1998-10-17 ---------- Diffie-Hellman +f20 Fingerprint20 = F05E 8A42 A306 92F1 7B32 E3DE 2B88 4A28 C9D0 0816 +uid Rodent of Unusual Size (DSS) +uid Rodent of Unusual Size (DSS) +uid Rodent of Unusual Size (DSS) +uid Rodent of Unusual Size (DSS) +uid Rodent of Unusual Size (DSS) +uid Rodent of Unusual Size (DSS) +uid Rodent of Unusual Size +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: PGPfreeware 5.0i for non-commercial use + +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 +XgCg6ajZ164aAHwQStdF9x+Jn96GQTg= +=e95K +-----END PGP PUBLIC KEY BLOCK----- + +Type Bits/KeyID Date User ID +pub 768/A0BB71C1 1997/06/03 Jim Jagielski + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: 2.6.3 + +mQBtAzOUkNMAAAEDANZdTUJQPwrFI9526Qf+DEWL8dXgfhWW8o6CzewdcCoHYEpu +9CiOMD3f9bgo1VozOPceGzCu/9FF2hMLUvVsTAZkzC3rre5TtPo/vOf5HJ+ac9M7 +aqxW+gRu2/90oLtxwQAFEbQfSmltIEphZ2llbHNraSA8amltQGphZ3VORVQuY29t +PokAdQMFEDOUkNRu2/90oLtxwQEB8iEC/i9Qo55TlT8bRpcqeM3lzNDqzU9cqKRf +9X8pGJIVE5m2JPm99qPLs8RPeepLChi8ZZ+2hSfb7ldQhvVLgNqQqLpsjGtJjJOU +C+MrKDeSk2WAicg6Uo0FWCsEHxrssw139A== +=pwim +-----END PGP PUBLIC KEY BLOCK----- + +pub 1024D/08C975E5 1999-04-14 Jim Jagielski +sig 08C975E5 1999-04-14 Jim Jagielski +uid Jim Jagielski +sig 08C975E5 2001-04-03 Jim Jagielski +uid Jim Jagielski +sig 3 08C975E5 2002-11-11 Jim Jagielski +sub 2048g/4CCDB430 1999-04-14 +sig 08C975E5 1999-04-14 Jim Jagielski + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.2.1 (Darwin) + +mQGiBDcUl9QRBADl5tF8kOD0uddlnl9qsaG70/hwujGTsSXATnqoLseTsWORoVXf +oBklokEAGmT2+Cl8XIXZ31Wh+GaJ3CTbEv8Ok1vapOt+ltPgOKzZEB4uP25EbhC2 +LWf+lUoafcd2Xi0KBV4fqXqEEuDGP1TAdZ6k7NVqgpjvbJ5TdqL0LrWOOwCg/0b4 ++/p/avQr+uZRU2rdmYu/b/0D/2LnjcEqUjsslh2e9m0OgAu+gnYAmQH6Dbnp+iKl +jffWPChwIMFZd/7FnGOzYDzoqnzTFyA4VE5PHWL61V2lpHJWB21K9D6rbEcx0iYB +AHHxZQEmxSBU6PmGnbF+2P7vC0Jz9gZ5dCbjtGboYxd00/XQlZwCs8jHueTpSfx9 +n7dYBACFpW+v2pSlG0ReiS6Ult3gaGWiw81D0nFVvCp5BlxgQDymyF1MS6FbCj/g +FGILosMhlsIHTFaC0DD0LSXyN1rm0ykPvi+vULIlKNJwW7fCi+33j1Azx+zfMNeO +T5vqAfF6cvsZ6qPb9CcYvU4jEKvkovA1U3jMFehqcGkTV5sfvbQeSmltIEphZ2ll +bHNraSA8amltQGFwYWNoZS5vcmc+iE4EEBECAA4ECwMCAQIZAQUCNxSX1QAKCRCL +OmAfCMl15UklAKDq2PsXa7PbJPtGlXblJjD1OZgjTwCgkCz0EAdWS4Fuhi0mmSm7 +h1gtH/W0H0ppbSBKYWdpZWxza2kgPGppbUBqYWd1TkVULmNvbT6ISwQQEQIACwUC +OsodagQLAwIBAAoJEIs6YB8IyXXlajkAoL2wNKsEorxLhZQAPRNa8kcv5uaCAKCc +KvWB5TIgPvXc9KIyu7YwfYiLg7QeSmltIEphZ2llbHNraSA8amltQGppbWphZy5j +b20+iFwEExECABwFAj3P+LMCGwMECwcDAgMVAgMDFgIBAh4BAheAAAoJEIs6YB8I +yXXlb3AAoOOU1s/F8PJAxYQwAQmlKxYUnZHdAJ9uIWY2w2UUMpTw45tkJ3xplawX +Y7kCDQQ3FJfVEAgA9kJXtwh/CBdyorrWqULzBej5UxE5T7bxbrlLOCDaAadWoxTp +j0BV89AHxstDqZSt90xkhkn4DIO9ZekX1KHTUPj1WV/cdlJPPT2N286Z4VeSWc39 +uK50T8X8dryDxUcwYc58yWb/Ffm7/ZFexwGq01uejaClcjrUGvC/RgBYK+X0iP1Y +TknbzSC0neSRBzZrM2w4DUUdD3yIsxx8Wy2O9vPJI8BD8KVbGI2Ou1WMuF040zT9 +fBdXQ6MdGGzeMyEstSr/POGxKUAYEY18hKcKctaGxAMZyAcpesqVDNmWn6vQClCb +AkbTCD1mpF1Bn5x8vYlLIhkmuquiXsNV6TILOwACAggAhIc3ERhHN8t/+GDWhvPR +ZrSEaRVOc6GmccQ65lIktR3YahcpL/KM2k8o3yJgroavIugxteaBrncT5muxMrAn +AP6pkBAVa1xStg2ExVt1Jz8qohPNtqZaNHeObtXLCsz7xqR2FRguBzhCgoIUcv+e +Jx9H7Cld1UpSFwIURtyyLLcwLbJa0mBC1tS6L+dxivmGaUQyU2ywMYyGAfJBGIYk +GMx5v3GwXkaYxvQaaAUIeeHTTo9tglPBwuCr2Upw3CwM5g8q0BVxX337ybUO/hx9 +oiFijBTo6UR4dmSuroSW9N2KP7/mnZirNR0hBXVeVSVApKspoSk9Dolp15jR6kFH +5YhGBBgRAgAGBQI3FJfVAAoJEIs6YB8IyXXlME4AniogMeV3YLNf6C1Y2+k8F3rt +0S/OAKDHF+wfxLDzCxsoQbwesIUAKgb7Hg== +=5VyJ +-----END PGP PUBLIC KEY BLOCK----- + +Type Bits/KeyID Date User ID +pub 2048/DD919C31 1996/12/24 sameer@c2.net + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: 2.6.3ia + +mQENAzK/QZIAAAEIALrsEjuGlt6wkHy8fx2wPSkH7paAqJHDCbO1W/GMVs41BsH1 +xpyBi9lOtUXHsDC8Obx/TES4/xVPSsFKPQLa9Q/OsxjXmEPBvQ5PZdOXJ5zmRMI1 +1cfUp2s8w6i+IS68IWRKdPMshGWFGar1YUPM1UpVME7U+uGD3wgdC4DrVJHzS5Eh +gEDyQ9FPb+8CpsRO3AvUPzsZGG8Iy/9GiLzmaJG34zZ5fv5X7sr89xiWJ21ehk+X +ePO9kvq+nzfOCCK6a3GZD4g3KJX/Pm3oKeaXeL8WSCCPzpNbtRJk3ofeN7Zm1K0L +yChPiyui+OO063/WASv52bxUIlmzbX82a92RnDEABRG0DXNhbWVlckBjMi5uZXSJ +ARUDBRAyv0GTbX82a92RnDEBAfqVB/9GSzADIVqY0faFOLN6+E3qqg3hPRLBvjgC +5cvTlwT7W64zI+aiSZuN+xAXq+3lnKtmzn45F3hD7gBxRPJbSKsObn2zU4UcqW/o +qoiYEnO9EhoBomwPUbVy8C00CWvDLfeF4L5r+2oXgilTsCojSaWJX0QoPCwRQao1 +YwZ6CqAA78vdbBNkmA0WrPsVqwd3ijgFapcX671AqiT+pDbvK646I6uGPXJzN3ZU +vFuDim9D2uNk9CfvPhKGscr4qqP40TnNn5fjSsmrFyFxYsdwo7I4TFpnsEPOw226 +GU+TR7zdwnByP72AxPEBJ/F22LwNyreuph+fRpWCnCf+9gVW9Heh +=jS5Z +-----END PGP PUBLIC KEY BLOCK----- + + =========================== +Rob Hartill + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: 2.6.2 + +mQCNAzG6VfMAAAEEAOvtvphFG/D02vGLENBl5OVPgEJgP9E1xhUgKTZnJstv30kD +h1IqeIBkEAy5bpKapCbvvxukyQErhB0efTi2v5yTAlz5pVjgWM5Sa8CyTXJmXPHH +EuOfy1DqaiQSmZ6KWX0ygw3gKDZMiNMf06UURLLYtRlGKSYY3WVj2u2UCmS9AAUR +tB5Sb2JlcnQgSGFydGlsbCA8cm9iaEBpbWRiLmNvbT6JAJUDBRAx5eIAZWPa7ZQK +ZL0BAU2XBACXfopMzC8kW3KEqq+N9W9fkGNgy//8XqQ77FmfPQPbO4X7Zn3cyO46 +MxvPP+92zSyN3dyj/xWZYoRLwll+ync9d4KUFwKw45DALAvz1CKHMOpQPD7dIWdE +9poJQrcbKeOqLcGZTu/hY90gWBUZ++9umR8X8lyh/WEgcUolfgYHew== +=upYh +-----END PGP PUBLIC KEY BLOCK----- + +Type Bits/KeyID Date User ID +pub 1024/631B5749 1996/06/21 Randy Terbush + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: 2.6.3 + +mQCNAzHLBS8AAAEEANGFXb9o0NPVfVjSLvQh1j3fN6cMeVNA5BGUJ6HZGP/NDxTE +i8hwejJqakkU4ux/g6Kqckrx3h8WR7OXZZ+R8CsA0bg9Sr42ndEQCUISgArg+lXZ +gRUniARPPA7tamTSq8v1mnxqy9s26Ht2rAG2D6IiK/7v0JlezKirDeBjG1dJAAUR +tCFSYW5keSBUZXJidXNoIDxyYW5keUB6eXp6eXZhLmNvbT6JAJUDBRAxywUwqKsN +4GMbV0kBAegnA/sH63WyfwMFmn3nWe8T/5IXO/QkMYoMGLS1i7IxMY9O8BVvKQM+ +oxEcJdFAG7zPZkpgKzTBxmExz5hMZ9hwJ42XhrslWoP7JVvADJcdthrUAYW9W+jx +GcDYAW3qW5DpKsQchfvXq9QOBDxP+Kbbe2B8xGEyGUhLkacISFTrIhhQSg== +=8P8s +-----END PGP PUBLIC KEY BLOCK----- + +Type bits keyID Date User ID +RSA 1024 0x49A563D9 1997/02/24 Mark Cox + Mark Cox + Mark Cox + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: PGP 6.5.8 + +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 +ArpmDAcknLxcmsjp2J4= +=WGLR +-----END PGP PUBLIC KEY BLOCK----- + +Type Bits/KeyID Date User ID +pub 1024/2F90A69D 1997/02/24 Paul Sutton + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: 2.6.3ia + +mQCNAzMRsB0AAAEEAKj2XYYEGcZhT69x4gskQ3xz+KMTLn7gKSqqcyyeinJ0ZjLl +6AJjb1/68nGsF+IIY+IJS+5smq8do1qpC3UZcmw423Sg8F71GeqDO4HZXOAOieVy +rpVs6S5TaXlJOcrC7zZCx+iql97+xJFjUGkkS7j/jIkx1AajzMNkSr0vkKadAAUR +tBxQYXVsIFN1dHRvbiA8cGF1bEB1a3dlYi5jb20+iQCVAwUQMxGwHcNkSr0vkKad +AQGrigP9F43zbiOigYel+JCMiB0HK/UdqSrf3xWxHIKWKNhQNjhnyeF+jKQwFld6 +7KQYsqZIpHsWLWmSk0AmKQOUIw+DxclDxBL2dT4p+CjgTgIAcbvPpahWkBAw/E+c +EGTiYbe+Y3sHJhhP+d0TOLmsETG9tpi7gFZ6FfNcWPxFMdxGrf4= +=0jQW +-----END PGP PUBLIC KEY BLOCK----- + +Type bits/keyID Date User ID +pub 1024/BA20321D 1997/06/05 Chuck Murcko + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: 2.6.2 + +mQCNAzOW7moAAAEEAMYZlNOxWCjLR/PosadbG+xsrB2unid2LiYoakTFiDIBaZjx +bu6hNmVZPYfKOXQcqrCu0EY3uVLP/L89bST5pfIZOzz8GTm33zrETgfzpXYyFdbX +eZ5vc6aa3+7zmI7h/aU567P9ruB2C/RBLl1A59wmPRRVvjEIAkI4bAO6IDIdAAUR +tCBDaHVjayBNdXJja28gPGNodWNrQHRvcHNhaWwub3JnPg== +=vUdL +-----END PGP PUBLIC KEY BLOCK----- + +Type Bits/KeyID Date User ID +pub 1024/26BB437D 1997/04/28 Ralf S. Engelschall + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: 2.6.3ia + +mQCNAzNko/QAAAEEANZ2kpN/oMkz4tqzxvKPZws/XwsD0Y+E5/y7P2DIw4uHS/4N +syQbgkdrZhPBlXDv68DQioHXWsb904qyr7iZB1LC5ItK9MgqlK+Z2mvPqsGbHM8J ++oYib8kf2zJ6HvrYrP7NYB0tN9YYum2ICtx+hIi6aKGXdB1ATA5erwYmu0N9AAUR +tClSYWxmIFMuIEVuZ2Vsc2NoYWxsIDxyc2VAZW5nZWxzY2hhbGwuY29tPokAlQMF +EDNko/QOXq8GJrtDfQEBKVoD/2K/+4pcwhxok+FkuLwC5Pnuh/1oeOYHiKYwx0Z3 +p09RLvDtNldr6VD+aL9JltxdPTARzZ8M50UqoF9jMr25GifheFYhilww41OVZA3e +cLXlLgda1+t0vWs3Eg/i2b0arQQDaIq7PeRdjdEDgwnG4xBaqaAqfgxwOXJ+LPWF +hiXZ +=K7lL +-----END PGP PUBLIC KEY BLOCK----- + +Type bits/keyID Date User ID +pub 1024/45B91DF1 1996/03/02 Doug MacEachern + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: 2.6.2 + +mQCNAzE4lesAAAEEAKJYS1vL2iB3owwiZdCxp3JyvSNaC7h1p2jQXcJvY10gqyZm +VffDwFoSvJM1JdCx3o1mb3JpZ2OTV4SrDDkzcSpTXelgyh7k9O3HB7oG6pHTML9g +Dq9ZKydShMIvIJos7KuLWoM/eeeejtkv7r/gWsGHAyKbT8fs3r7nlmxFuR3xAAUX +tB9Eb3VnIE1hY0VhY2hlcm4gPGRvdWdtQG9zZi5vcmc+ +=yaR9 +-----END PGP PUBLIC KEY BLOCK----- + +Type Bits/KeyID Date User ID +pub 1023/163751F5 1997/08/18 Dean Gaudet + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: 2.6.3a + +mQCNAzP30QgAAAED/1k8hPKsJj8Il/TfhP1JIRGwnXuzfQ/etv+MZJMzeNeKa8OX +Kw0d4e1S/KdJ+AZwWQp3ZMDoX2ghZ79X4DDDLEAc/Fmy0Gg8t89CP+xJk7b4EHjk +F7HX69BRJp3On4aRTXRND3WviqEmn5ppzbBkTenF9WWudLRbqrc4NnoWN1H1AAUR +tCBEZWFuIEdhdWRldCA8ZGdhdWRldEBhcmN0aWMub3JnPokAlQMFEDP30Qm3ODZ6 +FjdR9QEB9VQD/0+zumFj1zzYZ1+bS9Az36gijDUb8rlEVf/lBShx4VEvha8fsRRy +vkwnmJyupYvGtrSIYAwB0VK+GZPZa7XfZvUCM83AZY9vGpE0LwW2Vcz9kWZdJ0t+ +B7zJElmBUrmj9aW6ICmSNbOBwVo1Y7hg6lPSFFMOOECFpT1WuTXXYpNA +=KWcF +-----END PGP PUBLIC KEY BLOCK----- + + +pub 1024R/EE65E321 1998-10-22 Martin Kraemer +sig BB1D9F6D 1998-11-09 ct magazine CERTIFICATE +sig E2449019 1998-10-22 Martin Kraemer +sig EE65E321 1998-10-22 Martin Kraemer +sig 43BEE6A8 2000-01-03 Michael Cook +sig 49A563D9 2001-04-04 Mark Cox +sig F88341D9 2001-11-18 Lars Eilebrecht +sig 4F09F055 2003-04-21 Daniel Schemmel +sig 3 CC78C893 2003-11-18 Rich Bowen +sig D20BA2ED 2001-06-03 ruf at tik +sig 2 F43C2F92 2002-11-25 Bruno Lustosa +rev 30B94B5C 2002-12-28 imacat (¨Ìº¿¿ß) +sig 3 3BAA3AE0 2003-11-18 Rasmus Lerdorf +sig 2 4C9165B6 2003-11-18 Aaron Mulder +sig 3 88C3A5A5 2003-11-18 Philippe M. Chiasson (http://perl.apache.org/) +sig 84F9264F 2003-04-21 Harno +sig 3 30B94B5C 2002-10-09 imacat (¨Ìº¿¿ß) +sig 3 A54DA2DF 2003-11-18 Erin Mulder +sig 2 A1D69759 2003-11-24 Michael Kellen +sig 152924AF 2003-11-22 Sander Temme +sig 964F31D9 2003-11-22 [User-ID nicht gefunden] +sig 3 76D83CC6 2003-11-22 Manoj Kasichainula +sig 3 CE19D5C6 2003-11-18 Jamie Wallingford (legobuff) +sig 3 F5FC4B42 2003-11-21 Theodore W. Leung +sig FD093C41 2003-11-23 James M. Turner +sig 3 A11D56FB 2003-11-25 Geoffrey Young (http://www.modperlcookbook.org/~geoff/) +sig 2 65FDCDEE 2003-11-23 James Howison +sig 40581837 2003-11-27 Nick Kew +sig 3 D147B776 2003-11-28 Mitch Comstock (RAID) +sig 3 142B509B 2003-11-28 Glenn L. Nielsen +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.2.3 (FreeBSD) + +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 +=Pz1L +-----END PGP PUBLIC KEY BLOCK----- +Type bits keyID Date User ID +RSA 768 0xFDE534D1 1997/10/19 Martin Kraemer +sig 0xFDE534D1 Martin Kraemer +sig 0xE2449019 Martin Kraemer +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: 2.6.3ia + +mQBtAzRKZDIAAAEDAON7JJtbjj6ZFEstbQS16Hd/BPlwdbczMGaQ0Mi3Xjfvi5Dq +4+Lf8bthb8YWu8pxIb+6ktmfzWmgshWwxNNYzaY/iqgH72zlgYSG4dYoozC4yj5n +Ov1Bc5xQ69dy/eU00QAFEbQiTWFydGluIEtyYWVtZXIgPG1hcnRpbkBhcGFjaGUu +b3JnPokAlQMFEDqfWqkrAsNF4kSQGQEBzfAD/1n9mcXRCQ/vUB6o96zcVe9ixQfd +3y4gFLP4omhBr9K8HnvexbULnSL4kRadV7x8BCzBBD4Xyr+QlqX56om9qnr6ujcp +EbUIZrbxpy5HMdyFKYboYmlSo5esV+jixsUIRcizZabCGjt3sC2es3yWx+piZrPV +Rz/KX7AclQlQi5sLiQB1AwUQNi9nP1Dr13L95TTRAQGHRQMAkvnovM0IcP/Nrxtp ++3KVNz6CDDVtT4NYqSd2O+IcJo/AFsyuV+wSd1UUuWOEzmXhuAFSGlMFAb608+H0 +ajW4AvaKOpxe8CymJxjZlKQBmULHF0U/YZJhUqpOheaVGyP2iQB1AwUQNi9m/zYq +11iPOU49AQGBegL+M8/0OUD77YhMwCbjyjmykiadBHQOBmtCTnK++dcUTSpQKjcJ +xsWNzFE7qS1tyA0NwiZNW6cVia+6vbn7+YP8mSagk0r0TcN/iXjyWlsPTfzhk9Up +ir1wcfWgKb9P2VwL +=ZxgG +-----END PGP PUBLIC KEY BLOCK----- + + +Type Bits/KeyID Date User ID +pub 1024/EC140B81 1997/04/10 Dirk-Willem van Gulik + Dirk-Willem van Gulik + Dirk-Willem van Gulik + Dirk-Willem van Gulik + Dirk-Willem van Gulik + Dirk-Willem van Gulik + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: 2.6.3i + +mQCNAzNNOsMAAAEEAJmwazRhNJB4mQkvp0rrxLkeOAxR9fGBXgJNa6HHdLv7YHwx +mwMorHYDCAMypO1yuznNTaMVT1z3cS+yqhOkTVxwNI1mxW6Zts1kOJB9pWuU33sk +sUuCkLHXMgyvP9cms6gcYgB5g3UP6M/aQ4T017+Gk/7crlH87DGmPZbsFAuBAAUR +tCxEaXJrLVdpbGxlbSB2YW4gR3VsaWsgPGRpcmt4QHdlYndlYXZpbmcub3JnPokA +lQMFEDRZ5+0xpj2W7BQLgQEB/KAD/1xniFNLHp+jxIVrEL6HcI06QZUYPvRuarWq +3aI2gdeXej59Ry96MOo2MU3MsuQ+wW+6gEJAuyCp2jyYfzF/8winNcFWc738s/hX +fRYCJe4bvtMcnhBV7GAlTgyw00fcrnaJaQ811+QwKnZvXXWb+QuoXC4ddTon25w4 +XHLjtDZHtCxEaXJrLVdpbGxlbSB2YW4gR3VsaWsgPERpcmsudmFuR3VsaWtAanJj +Lml0PokAlQMFEDNNOsMxpj2W7BQLgQEBzW8EAItAEaeuIzPIVlKOk1LnHlYc4FyW +aiNJC2+rRmftYu2bIp/JFuXu3xC0U0byyHu0p+Y1pcAnt2YrqmYUfM0d2cx1b4+L +8RQR4SGKhq9jWKS3icfKoyMnGiD2CeI8/Xx8V6b8Xg0QqsdlS0kz//qGCDWMz0vi +oxzasVEvFjqAse03tCtEaXJrLVdpbGxlbSB2YW4gR3VsaWsgPGRpcmt4QHdlYndl +YXZpbmcubmw+iQCVAwUQNFnn1DGmPZbsFAuBAQE0vAP/aOb/rXsE256tpi0+CRp6 +cd9b1oBmw894UK+Cf4DeNHWehPWJog4y0eNFUcAMdLIdubDzc6Kfxw5QyJt2EAXr +05XuJ2DJdG24S/aPzGq+6VzL7Nq7pylXuhrACTgeesaceEpUd/NeOCOyzNR7i8qM +zbGFtU7fH1ipfJjN6fXLo5K0JERpcmstV2lsbGVtIHZhbiBHdWxpayA8ZGlya3hA +ZGRzLm5sPokAlQMFEDRZ58Expj2W7BQLgQEBGRwD/jdUjCJXFcAbjx3Y2pWUkR7C +hwJTohM2TvhFp80Ffbhh1xT961XGuHL5l41fRAIg9FEHjQKNVfXeisLH68Qh73cF +5xuNE6c1x1VSqfDLl9fXZ6TA35qt0G599T67jmVai4F/LjHWDI1O6UvPRuZE3O7m +eRaCfbPLAJ1ztFujtS3btClEaXJrLVdpbGxlbSB2YW4gR3VsaWsgPGRpcmt4QGJp +Z2Zvb3QuY29tPokAlQMFEDRZ56Qxpj2W7BQLgQEBvOED/1LhhPP5OkeCCEMVnmyZ +jZexzv6XOH2I5qH0iuozsI987sSK+zfv8O0wEBwjUOQqBuzlvjKImYQ/oqR89egQ +AinPc4z1b3kgeGyqrmtea6ScmpKufcWUBbhH0qsXF41eU3ArKY4kB9znV+/PacCe +VrOD8roFaxIDZ2nW9FS0mriOtC5EaXJrLVdpbGxlbSB2YW4gR3VsaWsgPGRpcmt4 +QHRlY2hub2xvZ2lzdC5jb20+iQCVAwUQNFnnjTGmPZbsFAuBAQEaHwP/Q2Rs6MIu +z8all/xildFOPfRAX73InwBeInr1O4UU4l6yWRvuLkg+m6O8eJSHo21SNZBCu9gM +FoQsd0jVOitUr8+w2WkypBlJo5wl1nCw/1sLU4AxtBb0jyADvJzxFCeje/FkxEvs +6Y3eLxpJRBylbg6KFOsmSY46DyGc49B6cZo= +=xUw/ +-----END PGP PUBLIC KEY BLOCK----- + +Type Bits KeyID Created Expires Algorithm Use +sec+ 1024 0xF08E012A 1998-02-19 ---------- DSS Sign & Encrypt +sub 2048 0xD8F8125A 1998-02-19 ---------- Diffie-Hellman +uid Dean Gaudet +uid Dean Gaudet +uid Dean Gaudet + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: PGPfreeware 5.0i for non-commercial use + +mQGiBDTsCJkRBADJmDUiJL0xUaxg0yw7+VqqFUL6sjWxZeZ7kQZs4dyN3R1ilBUG +KmOXE6qSfb6Pi0qEmgCz1K7g1KaglMRrpANY4h1CjziEVmTH5s3ocxe77w2uaou1 +gHJERIqQuC4/z0DwFqq61ZVf5dUQTD8OmfOwG4pFs51Si9WS03ueVEFQFwCg/9Z2 +j6UzCLyUABpWeV1v4m0w82kEAK96GyKDcT20TymKJnMKuwya+ZwqrULH3Sdi2Mwi +1GOH7aomG2fK4D2yxWx5xTiYhmYNnRoopgu/Kv5a4x43tOKS3zeADMnHIw9dMSn9 +4Kba8vfKbZnlOgt9veV+iWZv7N2aS2z7w/i53Y6LAlV1hAIMvGJ3zLfmShZs0LDI +Ya18A/wNcdJazUk9mLGIoycCYOk5YhWL9sCaCBdmdfDPu++rLnqROSWkmfYkOTt+ +pG9SPnvv3XrX/SEwM8gYfpbZwrFDJFI9W63lc9hdSosFD+8xiRl6h2gKRwWvc1Ry +xIt3+gUrZxovNxBOv98BoSf/j3lkldU+ZjDGlCplRHSndxlN/bQgRGVhbiBHYXVk +ZXQgPGRnYXVkZXRAYXJjdGljLm9yZz6JAEsEEBECAAsFAjTsCJkECwMBAgAKCRB9 +bb/R8I4BKqqzAKDc/4H9iOXJxVE0yCEHeTQ2gAHfhgCg7VSq7eNhiJhBgblQav/R +XOhaHj20JkRlYW4gR2F1ZGV0IDxkZ2F1ZGV0LWRqZzIwQGFyY3RpYy5vcmc+iQBL +BBARAgALBQI07AjSBAsDAQIACgkQfW2/0fCOASoWOACfb+8OVvy6FCqN2MxdCqp6 +gffNbYgAoOxlTa4NjCUUO9dfLFFYpDfGrRy7tCBEZWFuIEdhdWRldCA8ZGdhdWRl +dEBhcGFjaGUub3JnPokASwQQEQIACwUCNOwI/gQLAwECAAoJEH1tv9HwjgEqiC8A +oJDu1HTuGOfChFSJJ31XvV8tnlo5AKCFceck4veIMP8pDC0f5UBGGC3mZLkCDQQ0 +7AiZEAgA9kJXtwh/CBdyorrWqULzBej5UxE5T7bxbrlLOCDaAadWoxTpj0BV89AH +xstDqZSt90xkhkn4DIO9ZekX1KHTUPj1WV/cdlJPPT2N286Z4VeSWc39uK50T8X8 +dryDxUcwYc58yWb/Ffm7/ZFexwGq01uejaClcjrUGvC/RgBYK+X0iP1YTknbzSC0 +neSRBzZrM2w4DUUdD3yIsxx8Wy2O9vPJI8BD8KVbGI2Ou1WMuF040zT9fBdXQ6Md +GGzeMyEstSr/POGxKUAYEY18hKcKctaGxAMZyAcpesqVDNmWn6vQClCbAkbTCD1m +pF1Bn5x8vYlLIhkmuquiXsNV6TILOwACAggAhb3cBmR67H4+9Rj4FeTwJ8kflX6I +pp2AeXXZiffiPVBv5cGzGn2RkGPAZqbp2AkrCb4TrJH//1GPdR8VmPeEGsm6u0uT +0M404l/4IW1FFQ4JBpTENPn4NYBHkKBNkPcls/ip0lSjlmLGVQVOtDOaFD7n44xV +hT4WpptCripg/5kymDmK9c8hv6rPUvNoVrDdWR4//MCvNAZvGq2bZGdFTyd5Tn6D +AmwbvL/UwgiDnm95qBBfCZtmGkkFaoOePtBevWFaviFZM2pErPRcjY8A/1cZsycj +JPMFYqBKGDIk76ulDSjU0Q8dqhCEDf0o2oQEg6msjDtetVFEDw9yJe0AGIkAPwMF +GDTsCJl9bb/R8I4BKhECBKgAoNRtRaRMdYNwajSO7056eKazCGSDAKDShamaRjAe +ThQ1KefmJKyzfcosZQ== +=25Cv +-----END PGP PUBLIC KEY BLOCK----- + + +Type Bits/KeyID Date User ID +pub 999R/F88341D9 1994-11-08 Lars Eilebrecht +uid Lars Eilebrecht +uid Lars Eilebrecht +uid Lars Eilebrecht +uid Lars Eilebrecht +uid Lars Eilebrecht +uid Lars Eilebrecht + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.2.1 (GNU/Linux) + +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 +=yvlm +-----END PGP PUBLIC KEY BLOCK----- + + + +Type Bits/KeyID Date User ID +pub 1024/28AA55C5 2000/03/02 Daniel Lopez Ridruejo + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: 2.6.2 + +mQCNAzi+5mgAAAEEAKRyfbHaGoNuWwHVSa/5mRbWdhDTkR26z3Uwq4KdCZ2Wp+b0 +VF4Tfh6d4IoK2jXKBUlUfq+v7FYzSzYdPCmwB9L9cHlaU/ItfcWD2G7rIHyO/lGn +VXK/BGUPoOhT2yeO8tf6oe81hmN5VzqqhG/SWEkwlJASRX3ApyanqCooqlXFAAUR +tCtEYW5pZWwgTG9wZXogUmlkcnVlam8gPHJpZHJ1ZWpvQGFwYWNoZS5vcmc+iQCV +AwUQOMAjHyanqCooqlXFAQF9swQAnVrUersSbO/SrT+nnwgRPL/xRMjGCQe93gUe +JPcOOYU2be1tFGynJl842SIDPTHcJVg1hHReO93K4jvQKsbmT5zrzIlQ7hVB2u48 +WNcgsIKWIxcGaMp4+qsDOhN7Fh7vIEZdRRYhL7YcGKZ2WnXOZnGsKSD8VZenycwQ +cAA4xkA= +=3hIM +-----END PGP PUBLIC KEY BLOCK----- + +Type Bits KeyID Created Expires Algorithm Use +sec+ 2048 0xC808A7BF 2000-03-09 ---------- RSA Sign & Encrypt +uid rbb@apache.org + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: PGPfreeware 5.0i for non-commercial use + +mQENAzjHNiMAAAEIAK+iTnKRHymuUYmRRe6JlH3oN4GfpakM6CITpS0aM/piJBX8 +MNgcCUK2tz8MSCqAlfF+2r0hGRMSQ+UpXqLXcJaCkGIvXtlKmxCcCX6R+LDCnzoa +QvOar3+rKFFJyiauyV7VPucZZhFKesReG6o53uoOAd0jyzcV9TdpAIn4Xl8W617T +L98GdODY9jK0zfgGo2bSgPpo2YswlDCGbYzRX6bfEGmAbP4t4UnP1ikVCE3NTIyz +gT4kywMb5AT1Tm3FbwTx7rXc/nL20t22VTJMjyCxqPrOTs91PxdXyTAQUKY82x+U +ZgW39f6aKrJHDEJtxOyym+B5NpYgeP5QQsgIp78ABRG0DnJiYkBhcGFjaGUub3Jn +iQEVAwUQOMc2I3j+UELICKe/AQE4yAgAkNXkalNn8Xi+v3BFCmHLlB7PKlItzlS2 +PnMcTJPgzO8w+PyXc5lzS3dnqLEBoCwRazEZh8ncVbeBJz1LjQU67gvCBqyFl+3n +r+Z8k6cJYw1AzSK9FLAgOEtG8IdE+jsPq39xORpu6Dhsuln++G1xaK6fePeAEgR3 +qH7gog/SFCa9QXQd85wsGRlQlmMwe/HDyoRd/iHg3X7mr4yB+zYkxYKDD+TKlSqq +V23n0H4n3oTI10PfaB8LDYVuPiQvIRn08XKUv0Att1KPH6iJTIJ/KRbZyGb2J+1r +RO1nBGw+qaOAw4wUQXOpJyXVUeanIt1tSe8Gczlf/uxJZdCNSpgeqIkAPwMFEDjH +OY/9b4jGIdCnGxECdl8AnAvSwMQ2v2ryh2NLL4FgfVLCjb40AJoDu0jaEqUinZnp +oMBmjFgtsDYp+w== +=5ByY +-----END PGP PUBLIC KEY BLOCK----- +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: 2.6.2 + +mQCNAzjJAagAAAEEAKkko/H+E4+c7OXgiNfBCwlU/PrxPovDS3/JCKuILnflbNtC +Lxbqvf7LccZ4LoiHOKd3+G4V8BgaTndqADx4crEsS0BpNrJdshPmXajzkdQeo6jN +nts6QJ8/mlL4Q+s2/8dnleCrgDkzP4DpAIRGK9OARE/TKmUFUonO2YYGoUwFAAUR +tA5yYmJAYXBhY2hlLm9yZw== +=dGNO +-----END PGP PUBLIC KEY BLOCK----- + + +Type Bits KeyID Created Expires Algorithm Use +sec+ 1024 0x00ADEBF5 2000-01-25 ---------- RSA Sign & Encrypt +uid Marc Slemko + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: PGPfreeware 5.0i for non-commercial use + +mQCNAziM6n8AAAEEAODTLW2h2homp9NCjlsNdQQQACaUgrEm0sO0Lr1BVSp35fFQ +a6XtrIxQXwcvBqM0py1ea2zcmYqnv6vY+7i6sBnxiNNugH3ShBnOYeCaO6AzQNaN +2OvLkB7+1AoDmbU4a/+APtLrhzYzUj4DmwSmr7wTwdO06PsdM1Qv/g4Arev1AAUR +tBxNYXJjIFNsZW1rbyA8bWFyY3NAem5lcC5jb20+iQCVAwUQOIzqf1Qv/g4Arev1 +AQFTZgP/Q+/pcNsCncKr4x39f/N5zXine0zQaKY46ek+PCUrhDm5N8cFTyijE7V0 +huRDVENAFkwtznz/H7BN0vtMRlvUQJOPFa2UaN8zIbcMIzSbiNEx5nvfFeT/Gr52 +GtnrQ+BvczfaauJ0Zw4p5uq6na/+0iyEf17d4qrhIBftlO3Ti+M= +=+laC +-----END PGP PUBLIC KEY BLOCK----- + + +Type bits keyID Date User ID +RSA 1024 0x62C48B29 1996/01/22 *** DEFAULT SIGNING KEY *** + Ask Bjoern Hansen + Ask Bjoern Hansen + Ask Bjoern Hansen + Ask Bjoern Hansen + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: PGP 6.5.1 + +mQCNAjEC6XcAAAEEALdrW5rH+2XOKX2zAPQmgomvHGADJedG4Dxf3Ci3HpGmKazV +Uoo/f7Vf21ldvBBYC2CMpJU5uiMstNdrJ8Rx0KDBH2pLXsfE4XvVm8cGLbHcJycj +cZsYl4yppOufL/76kmpP7q0Jni/pXrkYg2mLG3lCN3JoZqX9tvkoKP1ixIspAAUR +tCRBc2sgQmpvZXJuIEhhbnNlbiA8YXNrQG5ldGNldGVyYS5kaz6JAJUDBRA1eczx ++Sgo/WLEiykBAZIjA/4+uCJi5WD0p3EFzOnmkZRxf8egjQlFdBDVR7sixVToZCze +oZZ9EVianFbwv8XU0McA7FLSUala0FIxRtmOs8/yN96rhBqJnYfLxu3b/ZRpBf4Z +UExXQbussUX7AsPUmFim9Xp8mTy7xDEpcfiBnGY9Dtx+nmSvyLO38W5VvKP1qYkA +PwMFEDV7CdYJPTjw/8ByixECHSsAoKUySg0ht56Rjsct6ViXjWfVEF1xAKCldK5x +LXMjefgsiuW3n5seRVogQokARgQQEQIABgUCNgEYdgAKCRBoqAGJariS5S72AJ9N +JsXpts88tCq7uZiirWlL54vTUwCg4A2urEUCEPuSz5deMyMX4lpjN5GJAJUDBRA5 +Ix6ndTAZgHu8twkBAZDHA/0fiaJSxGAxIdgYQY1KqYJGWg/E7Gwn87kZyiRHKUaJ +gP4IA4PVnh0rMtTTo+CWyzcqMPjRAZNDW4ECWymrqqNrYgqy/NrcN4h7LZC5wmnW +hXF3HdgAgxIn7m2YQOLluNqIrhVKga5G9/xytZLsF15qZbvjyX4mqToOsRqAtUBI +ALQgQXNrIEJqb2VybiBIYW5zZW4gPGFza0BwbHlzLm5ldD6JAJUDBRAz6gMS+Sgo +/WLEiykBAd9fA/9YdBn26x/7DE0by/Zzelfxu8o4AgZOV0AuWqZJebXKjeFmkJ0B +lZRaC+NUcvpXOcANP6berJknvAMjNfTD1wi89XUVlbisDSW3UMR7Op8EpYjqLTo5 +u+KmyS+ehhQjA3somcJc8fBdnGJZ17cKWEbzJK+oJBvnzpjtgtvw6/oH/okAlQMF +EDV5zQX5KCj9YsSLKQEBbk0EAJ+CwSbR4QQ2pgyXV7U4P4+1xSXa8U6IuI7AX9Fm +LNlDu7a8DnJt8trZxjBcEMZcfoSNmbjIzMotzl0vvtDpqYgKfJ5Dd3eUTRCDYYS7 +8DoYcuB0cunBoGijkHS/2IkucAZGgcnNjPdhm7EnDJ/4F5VR9ZByqXiAIhZ746bs +Z+nrtCBBc2sgQmpvZXJuIEhhbnNlbiA8YXNrQHBlcmwub3JnPokAlQMFEDkjD+v5 +KCj9YsSLKQEBEK0EAJBYAopnB9/dun1G0t+TKWVwGQUi56sWd5bwLypHklf/fy2V +QPjCz9QoI0L/jAguBrqCfwtlIHRHMwzvvNWLRtuA8oiTDl4w2gO2vjy7V3Y4qneA +3U5CYRT/ekvK42d+aHA6yMeHSPlNEQg09Idmee5Lub7kV8ejjtRZ8s3jcZ0utCJB +c2sgQmpvZXJuIEhhbnNlbiA8YXNrQGFwYWNoZS5vcmc+iQCVAwUQOSMQB/koKP1i +xIspAQGtCwP9FFWCZN2540lomDAY6tXt7Q3AhP/CkAec5i/lsv21sUl09jlZQnr/ +Kc8hL1lPOuAlLFGqso3zL7KMVlrOIng+R/E5fcYpE60QhhIoHdvlxFKTJ5GZq7DG +stCrR34q2A4OWtoC7tF0Uu+Ew2ontVgvqsrgq4qt0h3yh/kABp/8mRw= +=GGxP +-----END PGP PUBLIC KEY BLOCK----- + + +Type bits/keyID Date User ID +pub 2048/10FDE075 2000/10/09 William A. Rowe, Jr. + Key fingerprint = 33 16 9B 46 FC 12 D4 01 CA 6D DB D7 DE EA 4F D7 + wrowe@lnd.com + wrowe@apache.org + wrowe@covalent.net + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: 5.0 +Comment: PGP Key Server 0.9.4+patch2 + +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 +Svnm3b8WAJ9sKeuYzFUrRi7+TMHG+5qjYCkaug== +=e23Z +-----END PGP PUBLIC KEY BLOCK----- + +Type bits keyID Date User ID +RSA 2048 0xB96CD0C7 2001/01/04 *** DEFAULT SIGNING KEY *** + Bill Stoddard + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: PGP 6.5.8 + +mQENAzpT47cAAAEIALLL4JXm/9vHTouYSWrdDvAvNNxa6UwOZ1Sp6urCgGtuRLz3 +ysFFY4hlfIhSUvMdBuLMY5X73Tzg0+LpzCBuvRHasSUWO/5UMlTdS4LnI6oIS+7T +Nc//iwPQaH+P3CU2QScftyI0kS6kxr49Ejf4UZrJwMXsgvk+oDzRIdx1X8F4A5oW +oAUl2njrqVodbO9nPifBPlooHg84Cm3r1xgMK8OPPSEiVnmypmwTXE0fMsxAmW/6 +AqPf6x54tKmAyFY6UWM1bX/XhjVlwUu0Ax7ndBTKgw2ZCZA3TY3GQTPNbiK7eOpr +PUYN69EIKwtyFZHDSalkVpaZB44/nZygsbls0McABRG0IkJpbGwgU3RvZGRhcmQg +PGJpbGxAd3N0b2RkYXJkLmNvbT6JARUDBRA6U+O3nZygsbls0McBAazZCACW0+ss +3zAcpJNVI8rBZGwRSCEHW+NVRCQvrT4WiXQmb0fcTMJD8WD7kkMrYxaDuRzx4Iqr +nwdTqzc0MieM8j0lqa7zaoncxYFh/iLeeZKvK1988UIrVmFDslRQpnzeSXLjUWnF +1JYsS9+sYt8NBJGSIGXALji8QwcjpjRagzNjyO9YEs3TkGqdNslTQo1LJ2ZNIH6T +aIWoTdnoU9WUUldsSQEbYB6JNNP67eiFTRZZnKradoQ0PVBXtYZAw1zOp5y/xPH+ +72vhKLk7+Tt3zaV/SmoB52ssE7AXazdQtHfH3N5XXtZJvjIIf/Y/Svw+OaJ2nD3n +Jn3b7QtvWvkY2geD +=0D9G +-----END PGP PUBLIC KEY BLOCK----- + + +Type bits keyID Date User ID +RSA 2048 0x423FF2F1 2001/03/16 *** DEFAULT SIGNING KEY *** + Paul J. Reder + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: PGP 6.5.8 + +mQENAzqyerAAAAEIAMPeottLIzgSNklzro66gEnshbRLeb8MRwlivgOMxl5MgDpx +sH44MPaYKaB1owFQdVSSA+k8ARrxSbki46mQvK53+t1yUeVtaPu85GBta4Q2paXJ ++2/JVB83Qt8ZdkR7bA3Rxet+Poye4wqZcNQW271FS+sUkTvhAF6nb+5nWFNyKkTe +ApG9eudukksFd4Uh6ekMjpOX0HPUXoyzf7CmwSERZIny+qwK0dkKkr6qKvZZOEXu +wjnFgQoqcj242usLpGUfrGZCDQsOheGmaWH+RxrmccOqqqfmjo/EoHNjmEvfRSDP +Mviq9p574VRsKdt3smkyo63DcaguX/FV7EI/8vEABRG0J1BhdWwgSi4gUmVkZXIg +PHJlZGVycGpAcmFsZWlnaC5pYm0uY29tPokBFQMFEDqyerBf8VXsQj/y8QEBX5AH +/iGMf93L2+1NP2MHZzuggQrcRcf7fkOdVRfx0GcMUFuet4G/0Qg/NKy24J2xMVLI +E03//bn99c47BmGWlSrsuKM3nHXDtLHfmX9ajWB2x5TGLsQqCubfvGyxviFKyUKr +tVLrvOmfiOGZkbRjD1r1mjNKWONKgUcjgFmSqsZPnZsclNjOMnqENVwOtSS14r0K +YMquMP/sk7xDNZlRVUPEVn2TlLSBJp0NiAzwzbafbszX6xHLRJzE23hCGjl0ZnX+ +zkBusLpUGkuRkK6phJO6pg0E41D5QRnts3pHaDQ4EI6jEnWwlIsavrHh0mAw6ocf +oO+6PlKrPkqjgRSHYewLqnU= +=WB/Q +-----END PGP PUBLIC KEY BLOCK----- + + +Type bits keyID Date User ID +RSA 2048 0x6BBA9D5D 2002/04/08 *** DEFAULT SIGNING KEY *** + Cliff Woolley +sig 0x6BBA9D5D Cliff Woolley +sig 0xCC8B0F7E Aaron Bannert +DSS 1024 0xB0D5F771 2001/07/24 Cliff Woolley +sig 0xB0D5F771 Cliff Woolley +sig 0x6BBA9D5D Cliff Woolley +sig 0xCC8B0F7E Aaron Bannert + +Key 0x6BBA9D5D fingerprint = B777 8235 B7D0 36BC + A8E7 C012 842F 3E99 +Key 0xB0D5F771 fingerprint = 3DE0 24AF DA7A 4B15 + CB6C 1441 0F81 AA8A + B0D5 F771 + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: PGP 6.5.8 + +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 +D7eRAKDOQjhlMF3OOD6KlGtnuBpdhpK6rw== +=gjEJ +-----END PGP PUBLIC KEY BLOCK----- +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: PGP 6.5.8 + +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 +=8dFY +-----END PGP PUBLIC KEY BLOCK----- + + +pub 1024D/751D7F27 1999-08-19 Graham Leggett + Key fingerprint = EB13 8C6A F0FC 6910 01B1 6D93 344A 844D 751D 7F27 +uid Graham Leggett + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.0.7 (GNU/Linux) + +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 +=qXzK +-----END PGP PUBLIC KEY BLOCK----- + + +pub 1024D/6D791A41 2001-10-26 Greg Ames + Key fingerprint = FA51 765D 3CE4 EB83 BFE1 BDB7 605E 165A 6D79 1A41 + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.0.4 (GNU/Linux) +Comment: For info see http://www.gnupg.org + +mQGiBDvZp3cRBACm75cSDrKQCCGZIv8QL/AvcNMidSpnuZn1Huvxq28bgl1eh3br +2JHBb8CYh1ijUNk9EQeB/fl6go8NiuWeLLVZkJGnqQRZSVGe+ukpZFLPFGb3mgGS +lBmO/88gQ3gld5Cfumy7VRmMA3EtLCQlI25h74RcPIw5Gzil7pSj9N4JywCgsLDR +olk/+Y4kTdHW1PTt0YbBETED+waq/aICopOLAtEC8W/G2uexi/m+FPXWwM80Mkxh +K+2tjZX9oxzQQ+/GDeFId3q5NbSndscAFMq57ZI9/daenkdGLQqG8gaO0Hto24dG +YNft/w92i5beYG0CPJoIFspCY46GeYaV0HoKaRkLVfcxXqN9UKvKmH18HhO6GO27 +idRMA/4l24wu/Qbp20PvEKTEAsPWQSfUjtbMECUdpmzC3/ZG6SWO1cICV/b+QlSC +p5agjTesvno7GJC5IVs09RAkW6NmX4wVLY1LROPIzCriJKoKfgEeJcEqXPZu8q2R +S3U2UPe0PEzzHjdWZlwps+iSr1qafaxRfZsnUXMU8X5KsV6GFbQfR3JlZyBBbWVz +IDxncmVnYW1lc0BhcGFjaGUub3JnPohdBBMRAgAdBQI72ad3BQkSzAMABQsHCgME +AxUDAgMWAgECF4AACgkQYF4WWm15GkGFuwCfaWyKPP8/CtIqgZkIBxUB4QqYwiMA +niSB7MFpia1iTSSLg7e9dum5wrasuQENBDvZp4UQBACBHtkysTqPXCHqzsr75CSL +7SbdmLQQamlMxw0crksTfDZyPIr6AVfZcojd+EHO/6bHU270FxuIwfR5n2NejIIx +oZzjkTJ/TAa2r5qFy1XoUMnodF4qSNPq/JTajIaHXTSgNtPfuw098h3ommZ8XGSh +OMEovonFFjNNXYCHeY5EBwAECwP+OJdDyBkt9r4Zr/5mbhsQJ78TlKhDpDy094zW +/pHgULSEsVKbGbRGcDLYnTZ8Hjs7pCuyGy7uaCuWArRrnAzP40LNHEao7svl1VmR +wZFsisZ10D5kRB8MRVh7ckdOqxq/lSC8AfMBaTmN81Z2ljMWQ7SEvdCGq5OU2wn7 +O59wAOmITAQYEQIADAUCO9mnhQUJEswDAAAKCRBgXhZabXkaQSHkAKCUveQ2Ews0 +yTd8V9Co3kVUq0E02QCfccreS0fXB9D57p8qPvXRWvJGiRs= +=SVx5 +-----END PGP PUBLIC KEY BLOCK----- + +pub 1024D/E04F9A89 2001-04-03 Roy T. Fielding + Key fingerprint = CBA5 A7C2 1EC1 4331 4C41 393E 5B96 8010 E04F 9A89 +uid Roy T. Fielding +uid Roy T. Fielding +uid Roy T. Fielding + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.1 (Darwin) + +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 +xkA8JT6eXcJrBJhGbcY= +=KQRI +-----END PGP PUBLIC KEY BLOCK----- + +pub 1024/E2226795 1999/09/19 Justin R. Erenkrantz + Key fingerprint = 3C 01 6F 2B 76 46 21 BB 54 9C 66 B5 16 A9 64 95 E2 22 67 95 + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: 5.0 +Comment: PGP Key Server 0.9.4+patch2 + +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 +=6s4E +-----END PGP PUBLIC KEY BLOCK----- + +pub 1024D/2CF86427 2002-02-01 Ian Holsman + Key fingerprint = 67D4 D4C4 79ED D9EC 88E1 734C AB7A 60BC 2CF8 6427 + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: For info see http://www.gnupg.org + +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 +3ufE48GfSyj2H+vBJijepA== +=XyM+ +-----END PGP PUBLIC KEY BLOCK----- + +pub 1024D/CC8B0F7E 2001-10-02 Aaron Bannert + Key fingerprint = 937F B399 4A24 2BA9 BF49 E930 2145 4AF0 CC8B 0F7E +uid Aaron Bannert +uid Aaron Bannert +uid Aaron Bannert + +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQGiBDu5G8kRBACUCvGTlqgxnukt9kkjFPIpr/xsyGJjq9XJ7SEMx8caA6uMAxtU +mBcbBFqiyYz2zp019B/RYdXkpyoKVYyxoTdpkkCp5leZwoPJob+kcTkAApfTf5Rq +xs3AbY8e/R3XAaqdhwMsBJ4Vsu96qE0/JRajf+0sw+kGN1HNCI0z1cKWKwCg30x1 +zjFAQBf5QZP29z4pijNAPT0D/3L75dA2cBhG+hXkvbaAPf6ophD/owMku7vHqYLj +SUHw8Cc1C+uXGbRvK4cYVFS7wfo/FiNCHxawdPWeak910/d3UsoUsrNcSSz95Vnl +RxSlYG71KKUi7us3dOEGzOnv62+zRUwA/Y32aLPkTwV+U4qC+zqYGGz/DUPsbeN5 +AY75A/9jACi6Tjd5kgi584FHYIlJKsoej5YRr5mz5tvVQnwCHsySzvKZhFNA+Naw +kImlDBtN5r6SzWaONCa2sW2cSbECfpmvmGl3uJe9uVvbs6lEhZPNggKQgYNzdJQU +HlvKHK1e09IPLFOE2xd/De11d9rFDnv/AUtIJrl439en7EziL7QfQWFyb24gQmFu +bmVydCA8YWFyb25AY2xvdmUub3JnPohXBBMRAgAXBQI7uRvJBQsHCgMEAxUDAgMW +AgECF4AACgkQIUVK8MyLD36GmQCgt177yUba4wl27GeLLngmvioBc+cAnApbnspx +CWUm61QppZdYAz44QwPSiEYEEBECAAYFAju6stAACgkQFqlkleIiZ5XUngCglWG4 +DejI6MJ496Vu1Tysc6J+ozsAoIe9QsA50cxCZalaxUrBT/XtT7HfiQEcBBABAQAG +BQI8RgEgAAoJEPcTqHkQ/eB1H9IH/0aV16LSzf1pimZLuARbymfdJK4/+wQ29H9D +XWf4wDLdBJvUMkHcN9YxsslTmhqlvudpqCbbrBXu0Q0en3Qa3gxlG8c2pxCFpNrE +vi7bCiCcpmS+OUPT4PAMz3P2Mmzx+i9/Y7yCSdb2eZOjakTz4EvYcn7naTz6TOQ6 +WvjkOA2kgz2fER+ciXF40A+465KxwyNJJlMVffRPm6PMgifTIGDqcewYo69uvltE +XweTzh2mX0FBOuBgi6NiI3Yu18LhWtpBXrLmz52eQBrrnUXDvuNYoWbHsxM/56Vf +BFxzUUd38ChFziaCsGvz5HbreDA523qe4k+r3YG0E5zU70kTAW2IRgQQEQIABgUC +PFrxagAKCRCremC8LPhkJ54XAJ9cZpEYbISKfHfd2aXI3orydfv8VQCeLXVQbC4I +U5vLvPQLx2uEMNr9csOIPwMFEDyuIwT9b4jGIdCnGxECG8wAnigF7KzIbslopWCe +fPGBgVv0bcHmAKDmVyKvqAj90Ejni/LngyPrkSWbuIkBHAQQAQEABgUCPLINwQAK +CRDXOpC4a7qdXVYFCACHrv4T0OjkSWpTVLHYm85Rtk6oS2PvbLKxmVYbBMG3B2bO +quVLhjFBbaQyUkr3ks1ebWcjgnJCf72DrUwbBIjtbm+BjpRTvqmQai/lkf4oyFb9 +nVcX0iUR0t4uf/ecsz2rjBLlVYmAxUi4GXPnAAmFJtego1qJbEuHUuh5ZNGJuaxZ +Pk1Qnu+5VMN9VBbXOFT5Nvnt2WQBrxYM+5SbxszF4BmpztIFoa64QrheRLIQ3jd0 +S2+xyQsNCFVfwYIvMQqVmCNC623sBhGrFiJffTdJv5Y8JcQwBSfU8KnBB+XNirDq +LiUUI4m2xBE0Vhg8dFLnSi8yshKjTOBNQegmcC2MiEYEEBECAAYFAjyznowACgkQ +W5aAEOBPmol1jQCfYu3bWUJ27UUERTXpWuCx0wGgi6MAoJbXTrlFWVN/ihAOeyoM ++K8J1lA4iEYEEBECAAYFAjy01ucACgkQZjW2wN6IXdO/bgCglVvYECJYH9LS56Ug +dx00l8NenM8AoIoyiqIRs27asHxwz4CRUAzM5SxStCJBYXJvbiBCYW5uZXJ0IDxh +YXJvbkBjb3ZhbGVudC5uZXQ+iFcEExECABcFAju5HOoFCwcKAwQDFQMCAxYCAQIX +gAAKCRAhRUrwzIsPfp/ZAKCcug8zNT2WbAXMt4PPJUzhPKch7gCglldxj1byfdKv +9NJnrQLTQ6mXsmaIRgQQEQIABgUCO7qy0wAKCRAWqWSV4iJnlZVJAJ9/sAIUBPzG +HfjRVuvkEPehgv5qpwCgm6FdzGwUXScv3jkqHGf8K5B3RNaJARwEEAEBAAYFAjxG +AVgACgkQ9xOoeRD94HUX/QgAp4deUjwvISoeBoB7KmD67ccpcvSscBtFzpWVbJIm +QSJEWkMwqU7ga616NgEV8e3BbOlpUrRCJg3l1lWGMVHFMlG7YRIDrCT91+M2IA0H +0G0VCilPg4nUhx4vEww9H5gQkNAI2l4ep9B7LJD/EYMvIOfJ2W6SX/cip36/eHAy +YjZbKw3+Af785A7H7lWWI+Umphq/rd103FcwCx4m7KGuZKZJlQse6l9PQqWcyjbP +RrwD/WNUEhP8eXgy8/+XrHpqo9g4XMi4YVTqxc5nJ3iNYei6+iy2mK6Um4GNJANR +70TNQBe3UlMFfvEZFQ8SrSxBBXk7Z7tdgi0/tb1saT7D4ohGBBARAgAGBQI8WvFv +AAoJEKt6YLws+GQnsEkAnRlkBVgiZ9pkgU4k+Ab16M2bTYhzAJ4wWf4JZASGJM5z +CVFQVpLsTcZAE4g/AwUQPK4jMf1viMYh0KcbEQKWqACg6oVtZOFNBi2KUiaiekea ++YROANQAnRaTUuA6FZT+8+8BGy75en8FJTWiiEYEEBECAAYFAjyznpIACgkQW5aA +EOBPmok1nwCdEaXD1JKXsqNwir4cDfH4JOHvH8UAn3CbHK98MQOAv30O1E86F0HB +CfUSiEYEEBECAAYFAjy01uwACgkQZjW2wN6IXdNaUgCcDgHxmicULGB2TbKrslpg +COhS2UkAnjgsAMSQLAPkvC4r+1gXa4c/e1v6tCBBYXJvbiBCYW5uZXJ0IDxhYXJv +bkBhcGFjaGUub3JnPohXBBMRAgAXBQI7uR0qBQsHCgMEAxUDAgMWAgECF4AACgkQ +IUVK8MyLD36V4QCfdB9Kqiag3T98Y6tQ5YSb259XJnYAoM9fQ30sbQxfmNKuOHbk +IuPuU24wiEYEEBECAAYFAju6stMACgkQFqlkleIiZ5V/dwCcDxamuhlGgk3a+T0V +bIRp6Qy8bB0AoK6jwOfUwTn5YJTsVH8k2D/lwWBNiQEcBBABAQAGBQI8RgFCAAoJ +EPcTqHkQ/eB1q90H/j1MMsFAQ6XpIpTSWNAt/wR9qp7ZIAv6KdrbYX3akO3bPy3b +KL+7gDjEAqVGHzEBjTnqU7erDaI2Ms2RVBFhx/jI5RwT02KHSw3OJkSKN002yVxQ +igBSmIm7aKig8Uk632x2ncQz/pLHk61jJ2h/62enIhROGCQvrbArZAdAzqxTrSkp +YZ0IJqfHgttzxXgllHgAqTia7dbMMymYDUH1xdSyD7SfyA0dsJ4M9HhSgXFzmOIH +/dXR6jMrj39jSHsVMHyaMn2WWEj/AHSqvQ5J+Hi1EmLpA4NC6sVOhttG/c9B6SZ4 +xVDrH+qciaL7fFBB7EsCXMYpYsfbybZ+rGuMGtGIRgQQEQIABgUCPFrxbwAKCRCr +emC8LPhkJ6s9AJ9Elq2KHVPSqEbv0KEX+qd1izAW6QCffYVRnR0OVdB624DHWIbq +BAKSsoSIPwMFEDyuIxL9b4jGIdCnGxECd5oAnjKUT4SFF4VIDS3HEc8BHGM4zqIx +AKDzxSD8YeZ0xw4cWb7JQYzpWmzmkIhGBBARAgAGBQI8s56SAAoJEFuWgBDgT5qJ +8D8AoIyG5L6TBB4IJWQ+hwfNrD9IwVXBAJoDckFzbkgxnvhIczlY33Q+EqoMgYhG +BBARAgAGBQI8tNbsAAoJEGY1tsDeiF3TlFsAn374e8DpYNe6vJM9istjZ1EWnFpq +AJwKMiSR90qBquj46vhZ7BYszuYKnbQhQWFyb24gQmFubmVydCA8YWJhbm5lcnRA +a3VjaS5vcmc+iFcEExECABcFAju5Sa8FCwcKAwQDFQMCAxYCAQIXgAAKCRAhRUrw +zIsPfnzfAJ9rFBBJky98n6vzgvqtl+3HNU6q0ACgxaSLwy0Ki6Ii/eTzqNm8fL34 +IX2IRgQQEQIABgUCO7qy0wAKCRAWqWSV4iJnlZksAJwO02q9t/zo5HypYme1NNZE +XkJf2wCdEmnVSdzJypGpZSod+8z+yWeH0P+JARwEEAEBAAYFAjxGAUwACgkQ9xOo +eRD94HXDwwf/ZrEtrxyCqkBk6epTjn+JIXhx4hyk2/7fWXIFduJee2Mkfum+ERP7 +fn5mAYblwCaVMG93av2zb2gkZySCGsdmF8W9/ntPKf3HZ9ZBbRXNamtYyIPHGmb+ +wJPENiGZcKkCgACw8SJ7/nbGu0ctJpgyWEg0vDc/A30zR1/GxGddTpJ5wIRdhss3 +JBZQnFXolu802XmOfnj0IZ+ddw8AlWKS2kQj5de1lc1/iMTObBaF2dxbIjFpKRN+ +ZuTsWTbS+ESNNKKoFHjoRwu+kScKh4EG4YXsH9lvEePHRNFVWJ4H4Iu3OZQ028Ll +dqnCs19XhV5jTR1iRESKsEvFzqsbDH2/DYhGBBARAgAGBQI8WvFvAAoJEKt6YLws ++GQn+h8AnjSdURKLWjGTe2tyZ6uFgZfHNFHtAJ0dqyM2kQE0hqvbna1ekOKhhJxJ +PIg/AwUQPK4jJv1viMYh0KcbEQJd5gCeNxmgjYHc8Rbskd/Rx6G4GLD8bf8AoKMb +KOkABzz/lMkWnFoSQTORgoByiEYEEBECAAYFAjyznpIACgkQW5aAEOBPmomJlQCf +YbwuwJSHLxlZ5X2e3S7NY1do6TUAnRi2BeKlVOINxZAgFsdzWtbyta8GiEYEEBEC +AAYFAjy01uwACgkQZjW2wN6IXdPTvACeKekzrpxWT0kznQkzCsrWT95xQL4Ani5w +hJTuQ4e2PItb0kLCyoRgMMmYuQINBDu5HBQQCACKePczRQE1gIWH6LZaCDY8pINs +W6SHl4MXDnBPgnuZ9H/6kFr++2OXatVKlAoQ3mK0sN/py/HeGkMwKBI9lWVldPik +4pgDhdmZU3B3spA+TTCBWNpKyXGY2c7P+ougUvwQAysifhxOGAvr1R6TpBqeSdZ7 +4ZzMPhHLSJGwOSq3BJ/uaViRzZORbVmUFV8s1Og3UlHdvoK+blnbj6eMVyrQ/n+U +LviDnPDxasWhP4an+v8c4Gk2qsAz1XmXccn7S4pa9x/yxiXLNHHrr90Dd0h5Lvvv +hgcQTUFbEwwcdfzKKaiOtuq6qA0Rki/wBBabEtLPzCgBIpUj2lUZZrySVR/7AAMF +B/0a9jaU9Gc25ZygMtftWMVIXEGG7aTqm95Q3ZebYRlpxnJJUkNyLuj09IwBuV7a +XkpEBdACHNTyPwl3khmswjxQO5tWj6JEvdijxMEHu8JtfTq43zRAc62bMq6uJshW +Nd1oVu7pS4JQGmJvUyZjJ+Q9iiyY92XtdSyN0QnB0BeXHyHJB7ZeHbzALkOBDKUJ +yK50/ACJz5JFXabvc0c0zwveU46rFFa2Vdqv2Tf3exL4Gix/Pd8cKfknrssXoIwm +UvpESL92XUUSm7Ozy43+UWq2J55NSLNuqNtZyoMJWiLv3RpBn1DdGbXpuIeyDHCD +MM59GnqTdrJWcVQ9WJ/9txxziEYEGBECAAYFAju5HBQACgkQIUVK8MyLD35AfACZ +AcAS375Fg+hea6FxD9qnqpaZpjMAoLY7tAaEc1bKdJ/8Za3ZPT/GON9J +=SyIW +-----END PGP PUBLIC KEY BLOCK----- + +pub 1024/3A4E7AC9 2000/10/11 Brad Nicholes + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: PGPfreeware 6.5.8 for non-commercial use + +mQGiBDnkyK0RBADedOdiCuVtn2awUpoc02Gq+BCHRjy/lnZ9p4wdgJPJIdImcEZo +agfLwU8iDY4L+w71FMiZjR6Lp0dRK5TupeUD/NWEsDM7we4KjafK1tGN9QlkXAtZ +WulDyUoR6c1cTNeMPowL8/MMs4IP1VGL+9SUjSsoJOm8VBu66NLne/WnfQCg/4bs +0pNeQCtdzCzeNnTFbDSFd7cD/2FWSh+CMrhhC9tqDjfkvLrjcTj1bEpOI/qYb8Ir +eivywJQ5u/tvIkW856SubuBDFRy9kMlJEJL7y8pxD+6xm4ZYexznLS2AjaiseqLE +tgR+AXtgjebiM7gQ/hOtDJjpTPeA5hLYIsDYYrXds7FTeYhsJVeXZpZt6T0Uqqjk +aIe7BADXsfg4lz9/ecmHjo4VAOII6A+Ax2P0FTkxSXqPfIK1AGebIpAGE9nrc9t3 +hKkaqFztHM/OS5/QFs0G+RBnSyMUd/HXUFSl71Bf8F9dq/CdhNK0KXnOuZqpXZaT +WuD3Fl96HsCXYF2Dvzwf7Yoyai/3wX+f04VZbBKuLM+AsZmG67QkQnJhZCBOaWNo +b2xlcyA8Ym5pY2hvbGVzQG5vdmVsbC5jb20+iQBOBBARAgAOBQI55MitBAsDAgEC +GQEACgkQ9V3wKTpOesnSzwCfQ73nPsRRK31if54rQKcVaa1A+68Aniks/MIcwGUC +xSxJZpCGICkXhueyuQENBDnkyLMQBADZi2ehJNymtM1VOMCzWkamCuIWaDZzUOmK +Hz7pFnceoFC2xynrUI+AJIzFqqiWqovQqv4V3GloRdWcw9Ye2IIi7H25r6v00Ng7 +kL1TzFpjC6yoHGXgEzYFfxa63plWCRGdfWU+3yzg7lQAF9a/ATUxXUXl+uIebQbo +ZI1Wt4l1kwACAgQA0bT3PCO4TT0yhTuS+Rgk3ROqZTNhmMAnrTpHW70E4N4hgBe1 +1ZEralIhzT/1/dpsPbouDMMUer6voDcAyq7kCZobu/84LKhvCgFLQAF7PAz6g5Rc +sPsoVv09UYYVgVi96EeGciA6ozVSGsVfNwEzZX7QOBoyrFozlNlX2Y+oF8iJAEYE +GBECAAYFAjnkyLMACgkQ9V3wKTpOesksrwCgwQImPBW83G11skRygzwEOm9DWHoA +oPpwZLqqLg4/dGQ0ZK0Qm3HXok7W +=YgRS +-----END PGP PUBLIC KEY BLOCK----- + +pub 1024D/DE885DD3 2002-04-10 Sander Striker + Key fingerprint = 4C1E ADAD B4EF 5007 579C 919C 6635 B6C0 DE88 5DD3 +sig DE885DD3 2002-04-10 Sander Striker +uid Sander Striker +sig DE885DD3 2002-04-10 Sander Striker +sub 2048g/532D14CA 2002-04-10 +sig DE885DD3 2002-04-10 Sander Striker + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: For info see http://www.gnupg.org + +mQGiBDy0wXgRBAD1J8+8rBKAXD3Z9n7LhdQ+gDcYIDw/sN0cZGz5kpc/1YWWaMQg +ArmoNW7y+BBwNu6Cn42Nid16avSC86H1zBzOdQscDc9/WLwBCiFDCSHB98+UId25 +JGS2cRSE6vt2oDOy99Ent8Eh3f165e0rWVdc7NMOcFGhCTquAFbqMfxYzwCgvGIC +KcMeykaY5QSHrX+ckJmc2QEEANDc4ZRPVF7cQ2wR2OIYzh5oXInhFFnyW2vYbTsx +NwREbizoKXqG7rmTmOQPz6DsifJEo97QrFrSOcD9FI6aUpDmu1Ns06QSjmzCSS6i +R1xPXBp5//2jcWjLs8td30N+AfwFnnB45sy8ILWel1CkGhdPoiHdI8Q0nJWahVwU +PKz1A/9xPsk9k0quKrhEKI7sYZFJn/vy77gh4/k26/jk7JERonO8ECDDlo+r/hfF +op8A/ljW2BDm6VxHSBUkIJvULUbN8rxvQGnpKplv9jgiwBHoPhKZ/TX7KvXAvdPg +bx8Z4EfSVJRQs7j/v/IhM8xn8tu0EEW+Fg1SHCFWV5iqe6aTZrQjU2FuZGVyIFN0 +cmlrZXIgPHN0cmlrZXJAc3RyaWtlci5ubD6IVwQTEQIAFwUCPLTBeAULBwoDBAMV +AwIDFgIBAheAAAoJEGY1tsDeiF3T18kAn2kAzhMXT0tOg5GvGVNi+rc+dpZcAJ4z +rKA/8TnQ88Lqq/OOwkuC/TXrHohGBBARAgAGBQI8z5oyAAoJEBapZJXiImeVyywA +n1wPiGQVC6Kwdz1XlXrFL6/yC98mAJ9MZZgOr/Kyh2mDgwqWi+Fa/bgqarQjU2Fu +ZGVyIFN0cmlrZXIgPHN0cmlrZXJAYXBhY2hlLm9yZz6IVwQTEQIAFwUCPLTB5gUL +BwoDBAMVAwIDFgIBAheAAAoJEGY1tsDeiF3TQNMAn0ear3DqKydi9oTzfBYFCidn +YhqJAJ9fvKcU27+jJCRHIPp3lQPX0C+UQIhGBBARAgAGBQI8z5o1AAoJEBapZJXi +ImeVXd0AoP+AlwMBWr5fJ9pERjvKmnnNJE5oAKCJTRBYnB/aYkt8/aqPMVtl3k1L +NrkCDQQ8tMGJEAgA2F8v1AMPGI7cv7cWuySfnd2CV7SXOZQpc3Pfv2UHgYP+1lTL +NJoRtfwXMiNjrEwgLrpLy7F0nHnVqb6MBYv/Dhx6eO7MoejJUc2pADijCS3Qcg5n +7hCZ+pWvCjdZAfZhHB1cpSm0FVuc07jrJYTbI/qsdbUHQ4r1jcIZR/ZU4mTnFgnE +bAw4NxSGJ8ikFNNfviDdb3O/XAYS27dgJcGHOHaQi54dWkJpYt5vayUHYt85pOMH +MR1AwkvM3AiqPO3688VbV6mIlGS9XvBr11kbZ5EHUCDPFJl5AMjX2fg4lMQu/ONj +rbxCqbJppPLLXu/MwfrV9Y4pb7L+riWqdQwEOwADBggAgOqiXCSsRXmbxC0hYNj3 +UCY9KKy6CmCwExigG8Irs3aqC3cPGi9/9lpuniMN5F9ieN/BJysJHAFWN8f3z4UC +fQH6os3ewQDZqoFrgkHqlrAjej8qD0X5Ue0dozXLuMFe05X1XCkTff9wXI88uRxq ++5s7cedGqZQUixpN15oK9FZSORPPxjGsUe8NVMsplYvH/2xt7tXzDfE09zwT2qnM +voQte/WBoVYdVCigUIeArRqNyCsk1yGUfiBcmJFHCyhKNtYNAUwWGPv8AmTAb5yf +FFVprAMbDlv2yhiTnEj7AvEC+OP1RH0Z4j0TDlpeKHoZtu3uP/gp7Mshs7ssE2mV +qohGBBgRAgAGBQI8tMGJAAoJEGY1tsDeiF3TPewAnj9AmBMuS8QvsuS5hUhSWNZ/ +uLN6AJ9FK1Wz3vBRoTloK5D3D3UaJ4x7Hg== +=AHY5 +-----END PGP PUBLIC KEY BLOCK----- + +pub 1024D/E005C9CB 2002-08-15 Greg Stein + Key fingerprint = 01E4 7536 0FCC F1D0 F24B 9D14 5D41 4AE1 E005 C9CB +sig E005C9CB 2002-08-15 Greg Stein +uid Greg Stein +sig E005C9CB 2002-08-15 Greg Stein +uid Greg Stein +sig E005C9CB 2002-08-15 Greg Stein + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.0.6 (GNU/Linux) +Comment: For info see http://www.gnupg.org + +mQGiBD1bRO4RBACFxCQEk8j9a9SSzVIFUg6EKAXabSii1f2vyhdsj7yLd4E2nybA +6907ohpFkIHdOGWAasKKDRG3rpL1X37c5dxUYgGFGyfbe7FapUPP0azq/Wsfn8Ax +6D0jcIHJKZg+L0zHqxSwItiyiSqt2YGRUO42Bo/8SF7PHnv5TNKQZOjBIwCgmyiQ +lVmqE7NiM2oR3P0kYUDDcWMD/j0v3uyNKPTTOgapzRM7ThACv/6KmF600HH4ZbHg +3B2JTaoHiCDoYs1kp/8F65N6KG8S8wzJb1ErpbZSCqy7ZjjFm+NDRsTkFHPZngUS +l4ctAthOwgg93STorWE+XRF9ZjzL/XcQog2XV3ZMZAGq0prgX0LjZ8lHWPkvYv63 +EEJIA/430y8P+3refqpeO2UtsrUeDaYEkNJg379USVdI1VDJXdS1G5lCRkNiRcyU +im6ZcgOlgf+7KNuBv9urIwk7GkcPl4QHHFk2Fex2+k2JDxn+8gafjG1O2bkDKEyi +csHOWFouQvxLhglC8WJCmPQtMwMWzVpNlOnKyN6MPyvFz0CKc7QeR3JlZyBTdGVp +biA8Z3N0ZWluQGFwYWNoZS5vcmc+iFcEExECABcFAj1b0FwFCwcKAwQDFQMCAxYC +AQIXgAAKCRBdQUrh4AXJyzFQAJ973oVmfVyH0w4cs8SljCxwPnhUCACfebmWhkt1 +aYuu0vSX34Req3TPZ9e0HkdyZWcgU3RlaW4gPGdzdGVpbkBjb2xsYWIubmV0PohX +BBMRAgAXBQI9W9BsBQsHCgMEAxUDAgMWAgECF4AACgkQXUFK4eAFycvhKQCdEvec +2nvVEx6OC95oTwYZSM2B0NoAn0Ju156UP6IwGwczI0UGYuezk/4xtBxHcmVnIFN0 +ZWluIDxnc3RlaW5AbHlyYS5vcmc+iFcEExECABcFAj1b1JEFCwcKAwQDFQMCAxYC +AQIXgAAKCRBdQUrh4AXJy2W3AJ9Q/SnukhlOxz2vHahHiQ7ZgDE5qwCfeCn6PL3H +VMW9xLKJtU0O+Fep6a4= +=2Mbf +-----END PGP PUBLIC KEY BLOCK----- + +pub 1024D/8103A37E 2002-07-18 Andre Malo + Key fingerprint = 92CC EF0A A7DD 46AC 3A0F 498B CA69 3974 8103 A37E +sig 3 8103A37E 2003-01-01 Andre Malo +sig 3 F88341D9 2003-03-17 Lars Eilebrecht +sig 3 5F6B8B72 2003-03-17 Stefan Bodewig +sig 3 2261D073 2003-01-02 Astrid Kessler (Kess) +sig 21D0A71B 2003-03-17 Dirk-Willem van Gulik +sig 75A67692 2003-03-18 Erik Abele +sig B3B2A12C 2003-05-13 ct magazine CERTIFICATE +sig 3 F43C2F92 2003-10-03 Bruno Lustosa +uid Andr\xe9\x20Malo +sig 3 8103A37E 2002-07-18 Andre Malo +sig 3 F88341D9 2003-03-17 Lars Eilebrecht +sig 3 5F6B8B72 2003-03-17 Stefan Bodewig +sig 3 2261D073 2003-01-02 Astrid Kessler (Kess) +sig 21D0A71B 2003-03-17 Dirk-Willem van Gulik +sig 75A67692 2003-03-18 Erik Abele +sig B3B2A12C 2003-05-13 ct magazine CERTIFICATE +sig 3 F43C2F92 2003-10-03 Bruno Lustosa +uid Andre Malo +sig 3 8103A37E 2002-07-18 Andre Malo +sig 3 F88341D9 2003-03-17 Lars Eilebrecht +sig 3 5F6B8B72 2003-03-17 Stefan Bodewig +sig 3 2261D073 2003-01-02 Astrid Kessler (Kess) +sig 21D0A71B 2003-03-17 Dirk-Willem van Gulik +sig 75A67692 2003-03-18 Erik Abele +sig B3B2A12C 2003-05-13 ct magazine CERTIFICATE +sig 3 F43C2F92 2003-10-03 Bruno Lustosa +sub 2048g/E71FD3A6 2002-07-18 +sig 8103A37E 2002-07-18 Andre Malo +sub 2048G/3EC3A5BB 2002-07-18 +rev 8103A37E 2003-11-28 Andre Malo +sig 8103A37E 2002-07-18 Andre Malo + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.2.3 (GNU/Linux) + +mQGiBD020E8RBACVdPw0jDJ4jXKx8hBllu73Vmoxz8amOq6J92XH0Ch3obgHKTa/ +JndsxvYFDy4onZItPXbb4TC8uJGwi717eU+w8dHvB/R972JveKgb0HMeHcrGFOvS ++AlggjSCSxGht0UzwvwQgTZAdWfM+14g0K7yPtpMr4eh3QjYI3Q65lZ21wCgwNS/ +9Jl0adHrs3VzLFpT669fcMMEAIaesoMbtU0YaSyKN6ohU612G3pNXG23FeqbOXTY +twhKxtefcG0xmssI4ylq4jxxn4iLQHJUn9wI/oS/rksJjdBWICq3vah6FV3NUev7 +LZcJ1X/TntztE0SKSdwjngW4jhzxnZlteCVRmeejIgotj0xOwBzRfNGpW8E9JJdA +uWeTA/4/b2+jlkcWnIYrfy0HwTeeN2Dzd0p1S+egfkFZOfD15G1iRCSVsDVaHyeL +2n9NMfjVlHV/OzuW1/786IpvwFXwy/4HUm7b3DwG6p1GIUFFgyk4CjezzUqBAaJK +vfiaGWAmPR/gVdPSI94RduQNBhvxFupdH6QsyXw8Rxp+dYM7WbQaQW5kcmUgTWFs +byA8bmRAYXBhY2hlLm9yZz6IXwQTEQIAFwUCPhN4hgULBwoDBAMVAwIDFgIBAheA +ABIJEMppOXSBA6N+B2VHUEcAAQFcggCdHaBDTO7VXi01WGveomeSLIvx//cAn3ov +xRtZ5FkPALFK8Gu3aqJOf3osiJkEEwECAAYFAj514TUACgkQPo+38viDQdneGgPn +RL56FbdifkKziqJVkXLNdPeHAH924v/k0SAoX4Z7UlLuzKGF9pyjeOl4XOWuD5yv +FyjPMByZmeVOzPdsjPRAo+6y72POePrXvxZn6wdy/gEgceWxCC23DOdq0iIN581E +Hc8mcKTrLj2ND1WPCNjz6iO74qoUKGxM3WbJpfeIRgQTEQIABgUCPnXlXQAKCRCi +EVrhX2uLcmOPAJ9Lyg2fvTxGVamEwgvP1cf7/VU35ACgsFKVNlQ3qlSmPgeKDYr3 +cE3QfcWIRgQTEQIABgUCPhOHsQAKCRDu0eo5ImHQcwvLAJ4tsiuDE2UY17kdNlbW +JUbGQim5bACeP/31gQEQBPKbbhSungcj/uiZHcOIPwMFED5119b9b4jGIdCnGxEC +KCsAoNiERBYp3lGM/e041l/Dp4NalwfoAJ4vPM9qLN+CwKKqkPcFWT361dd9mohG +BBARAgAGBQI+d6vlAAoJEBU/oM11pnaSFgYAnRXQPTwosdoB2tkdAixHt6r0SX5d +AKCF3u+4wK/1/3NJLbe0rsthERhpE4g/AwUQPsEPa9vSRfyzsqEsEQL7MgCggSp9 +AlkHuIEjWqWe+cf71MI0/m4AoNqapfJAGP3nrFopelr8X3SmXOLCiEYEExECAAYF +Aj99kD4ACgkQiNfNvfQ8L5JSDgCgtO3NvDQuGjMttuzQQ2q72/TKg0AAni7N9ZNz +IYiK2tDIGHuZpvJKey7NtBlBbmRy6SBNYWxvIDxuZEBwZXJsaWcuZGU+iF8EExEC +ABcFAj020E8FCwcKAwQDFQMCAxYCAQIXgAASCRDKaTl0gQOjfgdlR1BHAAEBkhUA +oJeJ/RvFnduhbVt7aBX525PsY2PEAJwIsvADai6FHkyc0awF8XwLjF3MoYiZBBMB +AgAGBQI+deEvAAoJED6Pt/L4g0HZAiQD50pdd3/xn1Ue76fQ9zShqBpP0YliD9Iu +Co0Gh3PfATMYDbXqNThtC6jEDOyyeR8ZiJsJGwTh2eSRRVK6YURYy8ef7FWXiT8P +MeMThCqui3mL3oovpZXTX7S7dkwY84OaWIyTc42Y0Yf+sI0WW0LTwnKId/NtxF5r +nfmrcgkgiEYEExECAAYFAj515VQACgkQohFa4V9ri3J1UQCeJ6XBQjbUpYRgsndw +2MD4p2WS8vUAn1Pe+uc60dzzIyzbJMLLI2CVro5+iEYEExECAAYFAj4Th6kACgkQ +7tHqOSJh0HOCRwCeJkoqsG6ofuGk1lZS/6EBwupfppQAn1cs8TPKywSVEF5/kXpz +MbFKMoAHiD8DBRA+ddfM/W+IxiHQpxsRAkHHAKD0TvgAFQkaIm3ihevb0A9bZdo6 +jQCdEG+yxufIV7YrMdR+ACF2YBRmQi6IRgQQEQIABgUCPner4gAKCRAVP6DNdaZ2 +kprhAJ0RKBvHof+L2PUAACwcNYxPmcdZzACfQn45gJqhY3iTuaSrxbtt9Uj+GAWI +PwMFED7BD2Lb0kX8s7KhLBECfpEAn2SgNqS1FFCAa0qswKr+0VXRCLlBAKDvAj4o +Fj0vMELaxdqLRpofJo6aDYhGBBMRAgAGBQI/fZA/AAoJEIjXzb30PC+SKbkAoIZv +HORjyXUWiVtvZp5IbOg7PpmAAJ91B+sAXSC0KZAYdKiREaU1LuRIz7QdQW5kcmUg +TWFsbyA8bmRwYXJrZXJAZ214Lm5ldD6IXwQTEQIAFwUCPTbeIQULBwoDBAMVAwID +FgIBAheAABIJEMppOXSBA6N+B2VHUEcAAQGl9ACeLEMFRQIDIyptxewoPoarWpv+ +PJsAoKSt98+huyZ8ZnJbi3rDyUs99FWViJkEEwECAAYFAj514TUACgkQPo+38viD +QdkofgPncrDfQy1Eqthl6zSIuqcy40VnIhZl6oG1QKQkpJFlWnfwBXGnxs3S91ZT +xePXizV8ZEsTMxo9WpYOVkWF3f6OUFs0wEvRWNbH1OFZ+J7m/04xk0aeWSaTBc0B +qDRDexm/kh7baUm7AHPVv5t6d4F9q2Udip1XSaEEXjGFW6+IRgQTEQIABgUCPnXl +XQAKCRCiEVrhX2uLcnROAJ4qfuGagTHfXOQZxgtbv/xNBuDTmgCbBxmInYjKqVi5 +PGc6WqRjXlGEtWGIRgQTEQIABgUCPhOHsQAKCRDu0eo5ImHQc/y0AJ9Ygmr9qBZp +gKtGY92gycOjY/nI+gCeOOMDnT20bRwsUY0KsPzfc3/n/lCIPwMFED511939b4jG +IdCnGxECtWQAnjSqf+kk+QE0ySD/dmGKtV6m7rZmAKDHJOzT1DbySPVPYsRI71Zy +LXRMyohGBBARAgAGBQI+d6vlAAoJEBU/oM11pnaSMpgAnjQjqqitLpaXEVX4xMyh +c+SWwwqfAJ99J4WGSjx2TP6jH5F+g3eIBvTgUYg/AwUQPsEPdNvSRfyzsqEsEQKo +KQCeMNi3xC7+A0W360cw2sVo3LFmEIMAoPiQkWR9p2nw2ZBw6fwFSC6ZjfG/iEYE +ExECAAYFAj99kD8ACgkQiNfNvfQ8L5ILRwCfR8G61cs1o2rtGRuLRVxkHFdLauEA +nR7PIdcv7egOVuEq7nI1/mVGyJ7UuQINBD020FwQCACzjBVkgyKm/qUtaK2pLCcA +TUKioRrdEROiw85ojD83rtV5mW1XrvFfwekCbWMyBvDAlF+jF0IjjKaH7o8Q3I9q +S4md8cetsH0PMpDqgxzX2sGXUO5oBckJ8InJM6QVj/FyUHmCaqcttaIJWSZBpv97 +NWKDrgscC5rCbmsZL0Hi1kLfxfllQvq0snP/88wWInRFyHrqHu3XVmyeA+08LJae +GX9T1zPvKL+nXO+7TBswxGszE1lJmkafKnGzg2NLpZKKZTUNaFJhQnPqMsGNu9x7 +fwqE9avYnNLyIrYPy+fSZPsMtn2VS1TkbhVPQOMhq8J6k2WiHSd+/rNx41X+6N/3 +AAMFB/0UOqYx/526cVcqufmTUjsZ/ZHa52VYL64czno5u8D0Y7yw96rKFscnNbRu +l6kY4RBZ3VRqWBPE8OLlNPU4NkpV3FsFnj3e1e+nmv4dRTHGENy4ufESDcu50JxT +4obM5FjbdfAH81MPGZee97O2CYP+usTS8I/6fd4D4wsU24WAfpKIuHChjgpUAFOG +9386j7TpRCMZfLQk7bIzZsa6fnNWxfdJGAfPrsKMAIc5JY4HHIfTjr8fZpe3Dxy8 +cxc+ZWdi6TUU2L9BAhsAh4OhuqnAN1/AChB1sCbe0zr8eLSwMkzvjBhYXBCpRDqR +1BafVsRm09g03ZOeUVX8aFVN3Dm1iE4EGBECAAYFAj020FwAEgkQymk5dIEDo34H +ZUdQRwABARO0AJ9KSq4YtCH0mEvc7bmtEYMg61OlzgCcDbnaS4zc3461d1GAxef2 +vZwJNc+5Ag0EPTbc1xQIALLx5n1nvDmOVjAGvYwXphGXDTdK2yoy5qhElUs3LtgV +2pCsLmh0USK1IXc2pJN/XWq3FKkQd3W85LisWcCF5GvYlKlYS2Y1NG5k5TOcdAx8 +4ZtIxu6a79we6dJCQ4QPQMHDCxejw1Zflgg8Ml8Jex9CgVsTH9dR2OunrnPFdWB1 +M7zanFa0oMOpSMtn8s2YyMES2SeiBlX/ZDDlPvwBAW0nfwJ6X6ybPq0WD134W73t +UqwU0lkXTtIVejix+3sUE7tHo/Q8u4Yr57uZlhgCCG5vYuMTmyRW7qSb2QkrNULf +6aR5BLN/3ghrmX3VkcZzsuuvi4eWNjFFBsB9sxNRo48ABAsIAK0QfXGaO9utxSWy +eOITFbv6p8rbsyv175hBeozB1mpEK8F01NJV5BkHGd03uOAjWo1e0IbJFdESG0tf +wy7GbvbA+b6NP6fg7BvX/i3ca8XrdwAoasaMck1+RyUO8CCRqc2RY3V1ngL7z824 +Vn113QO7bngykdbO8Ub4A+LYoFv7QMgtjlbKCS4PTx8dHKfQWVz1a8F1qUIb6Abe +UNt8GiehiUfZ2YaUE3CiMR0CYQYZJ61R8CmAw/ZwiKjbbde10n8uMhWOMmgCG5J4 +QCB1TAsBrH2fU+aMiobSp9Hz7UDdjDN1728LVdoEeaA5oArDhcEoIzwZ/Rgb4VxQ +ZB7NGE6IYAQoEQIAIAUCP8am1RkdAmdudXBnIHZ1bG5lcmFiaWxpdHkgOi0oAAoJ +EMppOXSBA6N+zfQAn3hYxwNd6/Zh9/9vSrBjnil4d1AMAJoD9Vi2J6DhxHDrUiw2 +i+8RU+4msYhOBBgRAgAGBQI9NtzXABIJEMppOXSBA6N+B2VHUEcAAQGSjACeKvXX +kfcE8otR7xgRu/nO0LOLjSIAoK4gCL2NJ80W8HgC8JIAkHU25Lv+ +=93VU +-----END PGP PUBLIC KEY BLOCK----- + +pub 1024D/75A67692 2002-09-28 Erik Abele + Key fingerprint = D395 C757 3A68 B979 6D38 C258 153F A0CD 75A6 7692 +sig 75A67692 2002-11-23 Erik Abele +sig 21D0A71B 2003-03-17 Dirk-Willem van Gulik +sig 3 F88341D9 2003-03-17 Lars Eilebrecht +sig 3 2261D073 2003-03-17 Astrid Kessler (Kess) +sig 3 5F6B8B72 2003-03-17 Stefan Bodewig +sig B3B2A12C 2003-05-13 ct magazine CERTIFICATE +sig 3 8103A37E 2003-04-04 Andre Malo +uid Erik Abele +sig 3 75A67692 2002-11-23 Erik Abele +sig 21D0A71B 2003-03-17 Dirk-Willem van Gulik +sig 3 F88341D9 2003-03-17 Lars Eilebrecht +sig 3 2261D073 2003-03-17 Astrid Kessler (Kess) +sig 3 5F6B8B72 2003-03-17 Stefan Bodewig +sig B3B2A12C 2003-05-13 ct magazine CERTIFICATE +sig 3 8103A37E 2003-04-04 Andre Malo +sub 2048g/A680673F 2002-09-28 + Key fingerprint = F2A1 2400 3799 B66C 7530 19E8 D8D1 82E4 A680 673F +sig 75A67692 2002-09-28 Erik Abele + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.2.1 (GNU/Linux) + +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 +=Yf4N +-----END PGP PUBLIC KEY BLOCK----- +pub 1024D/2261D073 2003-01-01 Astrid Kessler (Kess) + Key fingerprint = FA39 B617 B614 93FD 2835 03E7 EED1 EA39 2261 D073 +sig 3 2261D073 2003-04-04 Astrid Kessler (Kess) +uid Astrid Keáler (Kess) +sig 3 2261D073 2003-01-01 Astrid Kessler (Kess) +sig 8103A37E 2003-01-01 Andre Malo +sig 3 F88341D9 2003-03-17 Lars Eilebrecht +sig 21D0A71B 2003-03-17 Dirk-Willem van Gulik +sig 75A67692 2003-03-18 Erik Abele +sig 3 5F6B8B72 2003-03-17 Stefan Bodewig +sig B3B2A12C 2003-05-20 ct magazine CERTIFICATE +uid Astrid Keáler (Kess) +sig 3 2261D073 2003-01-01 Astrid Kessler (Kess) +sig 8103A37E 2003-01-01 Andre Malo +sig 3 F88341D9 2003-03-17 Lars Eilebrecht +sig 21D0A71B 2003-03-17 Dirk-Willem van Gulik +sig 75A67692 2003-03-18 Erik Abele +sig 3 5F6B8B72 2003-03-17 Stefan Bodewig +sig B3B2A12C 2003-05-20 ct magazine CERTIFICATE +uid Astrid Keáler (Kess) +sig 3 2261D073 2003-01-01 Astrid Kessler (Kess) +sig 8103A37E 2003-01-01 Andre Malo +sig 3 F88341D9 2003-03-17 Lars Eilebrecht +sig 21D0A71B 2003-03-17 Dirk-Willem van Gulik +sig 75A67692 2003-03-18 Erik Abele +sig 3 5F6B8B72 2003-03-17 Stefan Bodewig +sig B3B2A12C 2003-05-20 ct magazine CERTIFICATE +uid Astrid Keáler (Kess) +sig 3 2261D073 2003-01-01 Astrid Kessler (Kess) +sig 8103A37E 2003-01-01 Andre Malo +sig 3 F88341D9 2003-03-17 Lars Eilebrecht +sig 21D0A71B 2003-03-17 Dirk-Willem van Gulik +sig 75A67692 2003-03-18 Erik Abele +sig 3 5F6B8B72 2003-03-17 Stefan Bodewig +sig B3B2A12C 2003-05-20 ct magazine CERTIFICATE +sub 2048g/A676B84D 2003-01-01 +sig 2261D073 2003-01-01 Astrid Kessler (Kess) + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.2.1 (MingW32) + +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 +d6rncSGIlA== +=SNQD +-----END PGP PUBLIC KEY BLOCK----- + +pub 1024D/208F5064 2003-06-13 + Key fingerprint = 984F B335 0C1D 5C7A 3282 255B B31B 213D 208F 5064 +uid Joe Schaefer +sig 3 208F5064 2003-06-13 Joe Schaefer +uid Joe Schaefer +sig 3 208F5064 2003-06-13 Joe Schaefer +sub 1024g/ED4260B6 2003-06-13 +sig 208F5064 2003-06-13 Joe Schaefer +sub 1024D/F8B0462F 2003-06-13 [expires: 2007-07-19] +sig 208F5064 2005-07-19 Joe Schaefer + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +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 +=8SJS +-----END PGP PUBLIC KEY BLOCK----- + +Type Bits/KeyID Date User ID +pub 1024/0300A2E9 1997/10/12 Jeff Trawick + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: 2.6.2 + +mQCNAzRAzqIAAAEEAMJUorgTyMEZPP+vXvmW/W+kdoCqAx7PFNpepvxTsTc5CQLt +Up9PvWrCGT/lAWO6qQkOsyNju/g5c/+cbJv3G0h4bOZPBEbRH3pkmAOAFUVUdmIu +FM+piYLdoAeEcE5+bmvWpzddkuiRRNIsMjmNjuNkqgOtYEZnGaCc8zADAKLpAAUR +tB5KZWZmIFRyYXdpY2sgPHRyYXdpY2tAaWJtLm5ldD4= +=E80M +-----END PGP PUBLIC KEY BLOCK----- +pub 1024D/A879FCF5 2001-11-06 Gregory Trubetskoy (Grisha) + Key fingerprint = F8C2 405F 8893 395E 4DA8 68BA A01D BC9E A879 FCF5 +sig 3 A879FCF5 2001-11-06 Gregory Trubetskoy (Grisha) +sub 2048g/0596F229 2001-11-06 [expires: 2006-11-05] +sig A879FCF5 2001-11-06 Gregory Trubetskoy (Grisha) + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.2.2 (FreeBSD) + +mQGiBDvoUEkRBAC2ZKj/jb6WQEPH3pU3dfC654tnYU80UlbBo6HUUgj9CB6QtECr +GsV771OqbBm4YAxpIo1QCpCSqnQyE38TEayuEs+BVWgh3WvZb3mNHz/5NFc2kEpt +i9YxGUkQ9/2sSEvGSVbEYitbghjLAFzQxuPfxUhxW8GnDBSOdLhF7Qy7PwCgiJwq +406ZJz5UGvzuFgpMZsyRm6sD/AyAM3eeTMARQbYa2cKBFDwgy6wLZl+llDGYmT9G +D+N1uyyLtiqNwR2ANBJC7gJVfNtVFIMLnQ3ms/nVFzTugQKyunlg2Koq+3ORDw2w +Hc/IJZiDlW+oyYeKZNpze7FKFalC2BzKA2QJDG7sHOHuqN6GA3FpFpw+LnxPTjgX +OOPaBAC16on5pd6AXuC1BoJ/TAJgXlirlRysJQbcRVMBgb3sUouXcg2NvHGheVzd +BEwRRZWH5oSxQW+C/dcJJIzF5je49TgBUzKuKSIdZ7x7fM9mm83lVa9mFVE3DLZ9 +sL7f4QRcefAUdCvwl/9bQq5fx3ZiT2v12FNPkZKfoDpFvKbPrrQuR3JlZ29yeSBU +cnViZXRza295IChHcmlzaGEpIDxncmlzaGFAaXNwb2wuY29tPohdBBMRAgAdBQI7 +6FBJBQkJZgGABQsHCgMEAxUDAgMWAgECF4AACgkQoB28nqh5/PVGIwCfXKn6dGHw +ypchTj31SPs0mG8mmdMAnjmIG097j3WbwlA0cnLkd9cuyYq0uQINBDvoUG4QCADO +YvhOJQ5hYohZJrSrsMZMe49HBdiPnguxa6tVBbXwnJwPgk6ceYliKMhXe76r1cQz +pgqyVSXVqeM+dxlIb8+Oxjm78OcGXlGhRoN/0MdU5yvj05UnPhKX9PE0nfTHhP7P +ROEs1EBfSkKjBFri+pvPw6QS/3wAundM0sO3OcZgrZJhbpaKCwocI+QnVaXjOzPk +vhguMT1jboQH3H4qKHgu13neQ0T6g+29UkN6cr3lj8izTb78htybgKY+btRuF9IT +19yCa598prBka8F3weCTgrYm0D7gNA5Mh93TMvmuQT1xwL7KWrTpDF39mUJjdrs9 +LufCe6dVlCw/fs6Ler+LAAMGB/4ktRdYZB7IGXKzAm3Ga1mhM0uUsMEFnE04npKj +hA9VL2LbyGspHf+LH11SdN1SO3fOBN/6t82zI6/52oX5k5on/Ssa1Gjh86camewk +0DWHmnDSySsRU67ClBlRl0ZFTqVYld8NxzXihXN7OzJSIJQ2clz68iegVOg1zbWD +DhB/Hlysx72UOXLHi/KaXHMlW5A6lAmY61Qf9C0TR9Hcc5BJGimwF+hPNw0kIGw3 +oPYo6VGeFdm6P0LDVElw/gbQxjKW+qy3GYsINGZz2lYlz4H4DJkpW9gGFsM7l10M +/baQqcg9BpBrOE7QTzfFK3GLzrNV+zf8dseRLvLnZ92HYqoKiEwEGBECAAwFAjvo +UG4FCQlmAYAACgkQoB28nqh5/PVs8wCcCsMhi1SacFM1kpsM+JPdT/KN0qwAnA48 +NdqzrIzzrrlvI8FkkZZzKggV +=kwZz +-----END PGP PUBLIC KEY BLOCK----- + + + + +pub 1024D/E76CF6D0 2001-04-09 Stas Bekman +sub 2048g/01611FBE 2001-04-09 + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.0.4 (FreeBSD) +Comment: For info see http://www.gnupg.org + +mQGiBDrSKd8RBADpBhHzpCEB/tWZTNZ0B4oMSMsWBnukkYADPy7ydBUOZHw17ddL +oKj8IOveqkX9Fdl7e32At1cd25kitU2nNXeQWt27C47LfDVR0iPfnVg+YE4jfDDb +rnDAcMKROqjvTTwAuGw8S+m+yqmS2xXsKIBN8A7druhT8R3xg1uBBsueHQCg/ytA +mFM+SjmUXumdid73ZmyK8Y0EANA2uWUEUVQ7PFipydmy2AWY/ZwYrrh79wLy6hch +zF294PU8Ubx/lqENzZBLNfMTeA9l8mbc1jF+up1IBpG/0DRGiCDtWLBDjTGorIFo +ow2zkUKK603x+qpdXV0ghxBkb8KalUQrFAh4fr4gSdnvLhLP70C6hS6g3MbJYNHf +v78kA/9u9y05+tZyNTzeeEcFWXTJX4t2GT4G3J+85fjpxiO21bjNg/I3kUxEyIDc +sjsr0G0yfbSIdAKK88BC/YlRR9WfYKwd8vvH9VUyroYgo8ufFYvhhBZZwP+FWw60 +mvY5EWLPk5g7rwT8Fqrg5y8rVSXTsZs/baesQPqkhFLXT+g5TrQdU3RhcyBCZWtt +YW4gPHN0YXNAc3Rhc29uLm9yZz6ISwQQEQIACwUCOtIp3wQLAwECAAoJEMyy60bn +bPbQnXQAnj8fmeXLyodcHPASyt376IUzsar4AKC98XkNtS8gl4AfCCfOUkGNrh59 +B4icBBABAQAGBQI60Z9MAAoJEFMHR+Yj6eq1eLsD/inQzkDNOsCDEbOF9calmv/C +QkRZps0kLKEnxk9bS3SnwYZN3PbtZDNh4ImrrZ/xqBdkOds95jZm5Mo4mJUTzpX0 +gK2gEhajjeWUdQ4k0QZ7pb722DQ69PMJReNZQQkcV+rY3SaRLugeDUIzpexvcO1w +i4lKffrvJNVN0I/Yim4UiEYEEBECAAYFAjtSGwoACgkQVZHiwGZkwHhcpgCeNoZu +zqc9rVB62+Igb4pu6l65Bu8AniM2tGWqq6tFGLqvYtA7DC0mlFfhiEYEEBECAAYF +AjtXsjcACgkQyzKhB4jDpaXnwwCfSUCu5OKxMNtHZWQwv2HMt/DlgFYAnjoAbCqy +96V/aY/0rHMhPWlhd4SJuQINBDrSKd8QCAD2Qle3CH8IF3KiutapQvMF6PlTETlP +tvFuuUs4INoBp1ajFOmPQFXz0AfGy0OplK33TGSGSfgMg71l6RfUodNQ+PVZX9x2 +Uk89PY3bzpnhV5JZzf24rnRPxfx2vIPFRzBhznzJZv8V+bv9kV7HAarTW56NoKVy +OtQa8L9GAFgr5fSI/VhOSdvNILSd5JEHNmszbDgNRR0PfIizHHxbLY7288kjwEPw +pVsYjY67VYy4XTjTNP18F1dDox0YbN4zISy1Kv884bEpQBgRjXyEpwpy1obEAxnI +Byl6ypUM2Zafq9AKUJsCRtMIPWakXUGfnHy9iUsiGSa6q6Jew1XpMgs7AAICB/47 +TeZ/O+z41M9MMI2/4aKBqbfIWNzcWl+71KZwPymTQO5F+WR9fSlS+qTNz+h3gi+l +bAEQ4dI2d+tUZX6q5cszNn/60ffxUbEqa3uBIkOaE+ZuoFSM4I/3IWlZqH7q2x3N +Q/oQgthLOU7c8HnCv3hHL4a1nsvVZze7zT4Rasb07+kGydlYpkoVhFEp012s0PJT +vDHG062vs0sx9HmknX6Nu1y91UQCFE7GVfkixk991s/7qHbKNW3u7FC1F0WrwMDa +Sgp27uJmn8E+tFrb8mpLqvJko2852EL9xKWGDDUqI/sRtZtuxdTcqsLBRyGJqxFy +0yA+GHeueqiS5YeEX1Z1iD8DBRg60infzLLrRuds9tARAvtZAJ9YzzyCiEYU/s9p +NVbVevC9/OkwYQCg5fViSXktQM035ki0W14ocNEpXdI= +=oamg +-----END PGP PUBLIC KEY BLOCK----- + + + +pub 1024D/42721F00 2004-01-17 Paul Querna + Key fingerprint = 39F6 691A 0ECF 0C50 E8BB 849C F788 75F6 4272 1F00 + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.2.4 (Darwin) + +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 +nQCfbbvCK0fwZcra7ofd1z1Up1+ID94= +=xYye +-----END PGP PUBLIC KEY BLOCK----- + + +pub 1024D/F39B3750 2005-07-14 + Key fingerprint = 29A2 BA84 8177 B738 7827 7FA4 75CA A2A3 F39B 3750 +uid Colm MacCarthaigh +uid Colm MacCarthaigh +uid Colm MacCarthaigh +sub 2048g/2C7157D3 2005-07-14 + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.1 (GNU/Linux) + +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 +Wq8UfA31IsLnxfIOGQ== +=95yW +-----END PGP PUBLIC KEY BLOCK----- + + +pub 1024D/311A3DE5 2005-10-02 Ruediger Pluem + Key fingerprint = 120A 8667 241A EDD4 A78B 4610 4C04 2818 311A 3DE5 +sig 3 311A3DE5 2005-10-02 Ruediger Pluem +sub 2048g/A21CD598 2005-10-02 +sig 311A3DE5 2005-10-02 Ruediger Pluem + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.2.4 (GNU/Linux) + +mQGiBEM/yAsRBACVZVt6oK9fpc9B/7vPny00aHnuhDQ0MsM5rbEGZ57aBnmHYyX0 +gTKLWGBXhlkos0hxBBIc9UUbOmaVBp4VFu0rz8IQ2OUZ93J7lR/khRG3wlmYx25Z +CcN0tOFmiZuyV+J9zNP/dBdBfUqDwcJD8zmA7u8NLeUWljJJdKv8wcZ2/wCgwN+/ +PWz58JCvsvphQT1QjzP8a6UD/3DsCYMq0m2dOi3YXxtHpeF2Kn+k4BXnFt5dkPsd +O2MN5m66Ky3MndeIPj81Bw9ssc9zZGcP2PHej9mZPjKDQaJn0GkHem2sVQ5uDcbG +JCy7UKjgLqBl/AAJs3+0KdArvWVxsxBUl6wViAxUytwdsgK1KUA3Qyfj7oAM3p4S +iAWlBACVIZO0u3LzAN5halnEcsjWrCdNpvOLB7aopNMYQRm0X2OXgFWRuLa6X4/g +yA/aDZg5xbSBVzC9VwMS3Os1hqwuFW0DuP0PAal1KIRL2dzD/1XIuRBz7N1WgeSq +MqNqjFL8RuTh9jHlWOnHKd7GOitJazv2TNgP0KQgRoPKklas97QiUnVlZGlnZXIg +UGx1ZW0gPHJwbHVlbUBhcGFjaGUub3JnPohZBBMRAgAZBQJDP8gLBAsHAwIDFQID +AxYCAQIeAQIXgAAKCRBMBCgYMRo95X5YAJ4vjiI3FoXwZwWklyP4CnlhODshDQCf +XDn0eSGXJnnYZAYcunTQWQ24HIm5Ag0EQz/IGBAIALdVGzJqGf7qC0rRAtEn3IGy +1Rt8kxusRR+ai+be8OxxG6Ab2PTpF2KhyDJJQtzByVL/gZUX4Xr6PUdw3XjmN+gL +mBOccKdi1zs5gxbZqmeWmA+9uvY14+b9FXONTyt15EIJbcykFk7x3kQ/a/Q5ujF0 +P9p/v03w356YFaVvq171Pkl1K7uNft5GURINzXljHz3CO3mq7/FYfZhMxxbRePUG +rhWuBOHL70J5eWA//x6cbm3u6htyQ6e7UOB2KfsV+RyLlPnOeOVKdDRlkqZth58J +zM4bejRLFYqVpe53M9hElCd6B7eIA4toNzg82T53a0MK+1O6i7iwip+sBUxjHLcA +BA0H/iI6JX6Ua4oy66zFbbWvTzuiljRWYEKJTkzeRPjW7fnrxRglMzTXA1ZcqM5t +5bPTWhzlBlCrcFIYDeKhg8rgdA5FrajTExBecc4thS8s2KkmSY8f4pBSOuA9oY9U +3JZIM+enCbZ46EulNzpEO6EtZhw446NC1y2NF+528scKhOF3S3mDhYpa7xyKiV9C +gU62U5eRx6/WYUfh6OsoHCPoqdtoMYb6lVzVkxcyfOCf2at2CS6mVng7otRMxf8R +TiCXnJZtR19uBV+lSLGYJIWz8dIxv0L2CQzJ05qGTHj88/hGXTr4OsnKAoILYmYv +IOiSyYyXQFrXH0lRIyC/FkdxuaqIRgQYEQIABgUCQz/IGAAKCRBMBCgYMRo95c0z +AKCh4iGas+UlRksCX7cx52RHgYSGQgCgiGBe3aIUIBBqQRpjlDaPNEJgBdo= +=8v2D +-----END PGP PUBLIC KEY BLOCK----- + + +pub 1024D/83E6AE0D 2003-05-08 [expires: 2008-08-18] + Key fingerprint = D694 DAB9 8F4E 68A8 4C17 F011 ECAB 0E7B 83E6 AE0D +uid Maxime Petazzoni (Bulix.org) +uid Maxime Petazzoni (Bulix.org) +uid Maxime Petazzoni (Apache Software Foundation) +sub 1024g/EA644EE9 2003-05-08 + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.2 (GNU/Linux) + +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 +=DmIO +-----END PGP PUBLIC KEY BLOCK----- +pub 1024D/40581837 2000-10-23 + Key fingerprint = 4535 10BD A6C5 8556 24E0 0923 6D0B C73A 4058 1837 +uid Nick Kew +sub 1024g/6A4AF32A 2000-10-23 + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.2 (GNU/Linux) + +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 +W/Kdk2iuwPLJw9rN5PFA +=WPl7 +-----END PGP PUBLIC KEY BLOCK----- +pub 1024D/152924AF 2000-10-22 + Key fingerprint = 51B4 8727 466A 0BC3 69F4 B7B8 B2BE BC40 1529 24AF +uid Sander Temme +sig 21D0A71B 2002-11-17 Dirk-Willem van Gulik (http://www.anywi.com/ - Senior partner) +sig E76CF6D0 2004-03-22 Stas Bekman +sig B5840AB1 2001-07-08 Sander Temme +sig E005C9CB 2002-11-17 Greg Stein +sig F5FC4B42 2002-11-18 Theodore W. Leung +sig AC89894C 2003-02-28 Frederick Keith Wamsley +sig 46B262C6 2003-11-24 Thies C. Arntzen +sig 40581837 2003-11-27 Nick Kew +sig 30A21D55 2004-02-20 Shane Curcuru +sig 873CF1AD 2004-11-19 Cory Friend +sig 561558CB 2004-12-13 Andrew Euell +sig 8103A37E 2005-07-20 Andre Malo +sig 5793498F 2005-07-20 Tim Ellison +sig C4C57B42 2005-07-21 Marcus Crafter +sig 1CD4861F 2005-07-21 Eran Chinthaka (Web mail) +sig 333E4E84 2005-07-22 Chathura Kamalanath Herath (Apachecon Europe 2005) +sig EA1BA38D 2005-07-24 Ajith Harshana Ranabahu (Made at Apachecon 2005) +sig 2 82AB7BD1 2002-11-17 Cliff Woolley +sig 2 13046155 2002-11-17 Thom May +sig 2 4C9165B6 2003-11-18 Aaron Mulder +sig 2 CC69CEED 2004-02-16 Thomas DeWeese +sig 2 9284C452 2004-11-21 Michael A. Dickerson +sig 2 E4136392 2004-12-11 Noel J. Bergman +sig 2 11DF87E9 2005-01-10 Paul Weinstein (pdw@vortex4.net) +sig 2 5CE5BDF9 2005-07-18 cheche@apache.org +sig 2 FC243F3C 2005-07-20 Henk P. Penning +sig 3 F894BE12 2002-11-17 Brian W. Fitzpatrick +sig 3 DE885DD3 2002-11-17 Sander Striker +sig 3 5C1C3AD7 2002-11-18 David Reid +sig 3 A54DA2DF 2003-11-18 Erin Mulder +sig 3 CE19D5C6 2003-11-18 Jamie Wallingford (legobuff) +sig 3 88C3A5A5 2003-11-18 Philippe M. Chiasson (Home) +sig 3 A1D69759 2003-11-24 Michael Kellen +sig 3 F8EA2967 2003-11-24 Brian McCallister +sig 3 A11D56FB 2003-11-24 Geoffrey Young (http://www.modperlcookbook.org/~geoff/) +sig 3 EE56550E 2003-12-01 Cliff Schmidt +sig 3 E41EDC7E 2003-12-03 Carsten Ziegeler +sig 3 ADBF9E1A 2003-12-05 Santiago Gala (Santiago Juan Gala Perez) +sig 3 75A67692 2004-01-27 Erik Abele +sig 3 08C975E5 2004-11-16 Jim Jagielski +sig 3 12BFE79A 2004-11-22 Kevin L. Collins (General Purpose Key) +sig 3 2C312D2F 2004-11-23 Rodent of Unusual Size +sig 3 302DA568 2004-11-23 Rodent of Unusual Size (DSA) +sig 3 D1AA8962 2004-11-24 Brian Behlendorf +sig 3 16A8D3AB 2004-12-14 Julie MacNaught +sig 3 F39B3750 2005-07-21 Colm MacCarthaigh +sig 3 CC78C893 2005-07-22 Rich Bowen +sig 3 015AFC8A 2005-07-22 Bertrand Delacretaz +sig 3 E2D774DF 2005-07-22 Sylvain Wallez +sig 3 87315C31 2005-07-23 Raphaël Luta +sig 3 9978AF86 2005-07-25 Christoph Probst +sig 3 2A623F72 2005-07-25 Christoph Probst +sig 3 C152431A 2005-07-27 Steve Loughran +sig 3 82844984 2005-08-13 Theo E. Schlossnagle +sig 3 CE419C8F 2005-08-23 Upayavira +sig 152924AF 2000-10-22 Sander Temme +sig 152924AF 2000-10-22 Sander Temme +sig 7F4436ED 2000-10-22 Sander Temme +sig 152924AF 2005-07-02 Sander Temme +sig 152924AF 2005-07-19 Sander Temme +sig 152924AF 2005-07-19 Sander Temme +sig 5098216F 2001-08-20 Sander van Zoest +sig 3 EC140B81 2004-11-16 Dirk-Willem van Gulik (http://www.anywi.com/ - Senior partner) +sig 3 A99F75DD 2004-11-23 Rodent of Unusual Size +sig 3 EE65E321 2003-11-24 Martin Kraemer +sig C8628501 2006-03-31 Branko ÄŒibej +sig 2 76D83CC6 2003-11-22 Manoj Kasichainula +sig 3 33131B65 2005-08-13 Theo E. Schlossnagle +sig X CA57AD7C 2004-12-14 PGP Global Directory Verification Key +sig X CA57AD7C 2004-12-27 PGP Global Directory Verification Key +sig X CA57AD7C 2005-01-23 PGP Global Directory Verification Key +sig X CA57AD7C 2005-02-05 PGP Global Directory Verification Key +sig X CA57AD7C 2005-02-19 PGP Global Directory Verification Key +sig X CA57AD7C 2005-03-05 PGP Global Directory Verification Key +sig X CA57AD7C 2005-03-20 PGP Global Directory Verification Key +sig X CA57AD7C 2005-04-03 PGP Global Directory Verification Key +sig X CA57AD7C 2005-04-17 PGP Global Directory Verification Key +sig X CA57AD7C 2005-04-17 PGP Global Directory Verification Key +sig X CA57AD7C 2005-05-01 PGP Global Directory Verification Key +sig X CA57AD7C 2005-05-15 PGP Global Directory Verification Key +sig X CA57AD7C 2005-05-17 PGP Global Directory Verification Key +sig X CA57AD7C 2005-05-31 PGP Global Directory Verification Key +sig X CA57AD7C 2005-07-03 PGP Global Directory Verification Key +sig X CA57AD7C 2005-07-08 PGP Global Directory Verification Key +sig X CA57AD7C 2005-07-21 PGP Global Directory Verification Key +sig X CA57AD7C 2005-08-04 PGP Global Directory Verification Key +sig X CA57AD7C 2005-08-18 PGP Global Directory Verification Key +sig X CA57AD7C 2005-08-21 PGP Global Directory Verification Key +sig X CA57AD7C 2005-08-27 PGP Global Directory Verification Key +sig X CA57AD7C 2005-08-28 PGP Global Directory Verification Key +sig X CA57AD7C 2005-08-30 PGP Global Directory Verification Key +sig X CA57AD7C 2005-08-31 PGP Global Directory Verification Key +sig X CA57AD7C 2005-09-01 PGP Global Directory Verification Key +sig X CA57AD7C 2005-09-02 PGP Global Directory Verification Key +sig X CA57AD7C 2005-09-04 PGP Global Directory Verification Key +sig X CA57AD7C 2005-12-12 PGP Global Directory Verification Key +sig C59C3270 2002-11-17 Wilfredo Sánchez Vega +uid Sander Temme +sig F5FC4B42 2002-11-18 Theodore W. Leung +sig A3543C8A 2003-02-26 James Moore +sig AC89894C 2003-02-28 Frederick Keith Wamsley +sig 40581837 2003-11-27 Nick Kew +sig 8103A37E 2005-07-20 Andre Malo +sig 5793498F 2005-07-20 Tim Ellison +sig C4C57B42 2005-07-21 Marcus Crafter +sig 1CD4861F 2005-07-21 Eran Chinthaka (Web mail) +sig 333E4E84 2005-07-22 Chathura Kamalanath Herath (Apachecon Europe 2005) +sig EA1BA38D 2005-07-24 Ajith Harshana Ranabahu (Made at Apachecon 2005) +sig 2 4C9165B6 2003-11-18 Aaron Mulder +sig 2 CC69CEED 2004-02-16 Thomas DeWeese +sig 2 9284C452 2004-11-21 Michael A. Dickerson +sig 2 E4136392 2004-12-11 Noel J. Bergman +sig 2 11DF87E9 2005-01-10 Paul Weinstein (pdw@vortex4.net) +sig 2 5CE5BDF9 2005-07-18 cheche@apache.org +sig 3 A54DA2DF 2003-11-18 Erin Mulder +sig 3 CE19D5C6 2003-11-18 Jamie Wallingford (legobuff) +sig 3 88C3A5A5 2003-11-18 Philippe M. Chiasson (Home) +sig 3 A1D69759 2003-11-24 Michael Kellen +sig 3 F8EA2967 2003-11-24 Brian McCallister +sig 3 A11D56FB 2003-11-24 Geoffrey Young (http://www.modperlcookbook.org/~geoff/) +sig 3 EE56550E 2003-12-01 Cliff Schmidt +sig 3 E41EDC7E 2003-12-03 Carsten Ziegeler +sig 3 ADBF9E1A 2003-12-05 Santiago Gala (Santiago Juan Gala Perez) +sig 3 75A67692 2004-01-27 Erik Abele +sig 3 08C975E5 2004-11-16 Jim Jagielski +sig 3 12BFE79A 2004-11-22 Kevin L. Collins (General Purpose Key) +sig 3 2C312D2F 2004-11-23 Rodent of Unusual Size +sig 3 302DA568 2004-11-23 Rodent of Unusual Size (DSA) +sig 3 D1AA8962 2004-11-24 Brian Behlendorf +sig 3 21D0A71B 2005-07-20 Dirk-Willem van Gulik (http://www.anywi.com/ - Senior partner) +sig 3 F39B3750 2005-07-21 Colm MacCarthaigh +sig 3 CC78C893 2005-07-22 Rich Bowen +sig 3 015AFC8A 2005-07-22 Bertrand Delacretaz +sig 3 E2D774DF 2005-07-22 Sylvain Wallez +sig 3 87315C31 2005-07-23 Raphaël Luta +sig 3 9978AF86 2005-07-25 Christoph Probst +sig 3 2A623F72 2005-07-25 Christoph Probst +sig 3 C152431A 2005-07-27 Steve Loughran +sig 3 82844984 2005-08-13 Theo E. Schlossnagle +sig 3 CE419C8F 2005-08-23 Upayavira +sig 152924AF 2002-11-17 Sander Temme +sig 152924AF 2002-11-17 Sander Temme +sig 152924AF 2005-07-02 Sander Temme +sig 152924AF 2005-07-19 Sander Temme +sig 3 A99F75DD 2004-11-23 Rodent of Unusual Size +sig 3 EC140B81 2004-11-16 Dirk-Willem van Gulik (http://www.anywi.com/ - Senior partner) +sig C8628501 2006-03-31 Branko ÄŒibej +sig 2 76D83CC6 2003-11-22 Manoj Kasichainula +sig 3 33131B65 2005-08-13 Theo E. Schlossnagle +sig X CA57AD7C 2004-12-14 PGP Global Directory Verification Key +sig X CA57AD7C 2004-12-27 PGP Global Directory Verification Key +sig X CA57AD7C 2005-01-23 PGP Global Directory Verification Key +sig X CA57AD7C 2005-02-05 PGP Global Directory Verification Key +sig X CA57AD7C 2005-02-19 PGP Global Directory Verification Key +sig X CA57AD7C 2005-03-05 PGP Global Directory Verification Key +sig X CA57AD7C 2005-03-20 PGP Global Directory Verification Key +sig X CA57AD7C 2005-04-03 PGP Global Directory Verification Key +sig X CA57AD7C 2005-04-17 PGP Global Directory Verification Key +sig X CA57AD7C 2005-04-17 PGP Global Directory Verification Key +sig X CA57AD7C 2005-05-01 PGP Global Directory Verification Key +sig X CA57AD7C 2005-05-15 PGP Global Directory Verification Key +sig X CA57AD7C 2005-05-17 PGP Global Directory Verification Key +sig X CA57AD7C 2005-05-31 PGP Global Directory Verification Key +sig X CA57AD7C 2005-07-08 PGP Global Directory Verification Key +sig X CA57AD7C 2005-07-21 PGP Global Directory Verification Key +sig X CA57AD7C 2005-08-04 PGP Global Directory Verification Key +sig X CA57AD7C 2005-08-18 PGP Global Directory Verification Key +sig X CA57AD7C 2005-08-21 PGP Global Directory Verification Key +sig X CA57AD7C 2005-08-27 PGP Global Directory Verification Key +sig X CA57AD7C 2005-08-28 PGP Global Directory Verification Key +sig X CA57AD7C 2005-08-30 PGP Global Directory Verification Key +sig X CA57AD7C 2005-08-31 PGP Global Directory Verification Key +sig X CA57AD7C 2005-09-01 PGP Global Directory Verification Key +sig X CA57AD7C 2005-09-02 PGP Global Directory Verification Key +sig X CA57AD7C 2005-09-04 PGP Global Directory Verification Key +sig X CA57AD7C 2005-12-12 PGP Global Directory Verification Key +sig C59C3270 2002-11-18 Wilfredo Sánchez Vega +uid Sander Temme +sig F5FC4B42 2002-11-18 Theodore W. Leung +sig AC89894C 2003-02-28 Frederick Keith Wamsley +sig 40581837 2003-11-27 Nick Kew +sig 8103A37E 2005-07-20 Andre Malo +sig 5793498F 2005-07-20 Tim Ellison +sig C4C57B42 2005-07-21 Marcus Crafter +sig 1CD4861F 2005-07-21 Eran Chinthaka (Web mail) +sig 333E4E84 2005-07-22 Chathura Kamalanath Herath (Apachecon Europe 2005) +sig EA1BA38D 2005-07-24 Ajith Harshana Ranabahu (Made at Apachecon 2005) +sig 2 4C9165B6 2003-11-18 Aaron Mulder +sig 2 CC69CEED 2004-02-16 Thomas DeWeese +sig 2 9284C452 2004-11-21 Michael A. Dickerson +sig 2 E4136392 2004-12-11 Noel J. Bergman +sig 2 11DF87E9 2005-01-10 Paul Weinstein (pdw@vortex4.net) +sig 2 5CE5BDF9 2005-07-18 cheche@apache.org +sig 3 A54DA2DF 2003-11-18 Erin Mulder +sig 3 CE19D5C6 2003-11-18 Jamie Wallingford (legobuff) +sig 3 88C3A5A5 2003-11-18 Philippe M. Chiasson (Home) +sig 3 A1D69759 2003-11-24 Michael Kellen +sig 3 F8EA2967 2003-11-24 Brian McCallister +sig 3 A11D56FB 2003-11-24 Geoffrey Young (http://www.modperlcookbook.org/~geoff/) +sig 3 EE56550E 2003-12-01 Cliff Schmidt +sig 3 E41EDC7E 2003-12-03 Carsten Ziegeler +sig 3 ADBF9E1A 2003-12-05 Santiago Gala (Santiago Juan Gala Perez) +sig 3 75A67692 2004-01-27 Erik Abele +sig 3 08C975E5 2004-11-16 Jim Jagielski +sig 3 12BFE79A 2004-11-22 Kevin L. Collins (General Purpose Key) +sig 3 2C312D2F 2004-11-23 Rodent of Unusual Size +sig 3 302DA568 2004-11-23 Rodent of Unusual Size (DSA) +sig 3 D1AA8962 2004-11-24 Brian Behlendorf +sig 3 21D0A71B 2005-07-20 Dirk-Willem van Gulik (http://www.anywi.com/ - Senior partner) +sig 3 F39B3750 2005-07-21 Colm MacCarthaigh +sig 3 CC78C893 2005-07-22 Rich Bowen +sig 3 015AFC8A 2005-07-22 Bertrand Delacretaz +sig 3 E2D774DF 2005-07-22 Sylvain Wallez +sig 3 87315C31 2005-07-23 Raphaël Luta +sig 3 9978AF86 2005-07-25 Christoph Probst +sig 3 2A623F72 2005-07-25 Christoph Probst +sig 3 C152431A 2005-07-27 Steve Loughran +sig 3 82844984 2005-08-13 Theo E. Schlossnagle +sig 3 CE419C8F 2005-08-23 Upayavira +sig 152924AF 2002-11-17 Sander Temme +sig 152924AF 2002-11-17 Sander Temme +sig 152924AF 2005-07-02 Sander Temme +sig 152924AF 2005-07-19 Sander Temme +sig 152924AF 2005-07-19 Sander Temme +sig 3 A99F75DD 2004-11-23 Rodent of Unusual Size +sig 3 EE65E321 2003-11-24 Martin Kraemer +sig 3 EC140B81 2004-11-16 Dirk-Willem van Gulik (http://www.anywi.com/ - Senior partner) +sig C8628501 2006-03-31 Branko ÄŒibej +sig 2 76D83CC6 2003-11-22 Manoj Kasichainula +sig 3 33131B65 2005-08-13 Theo E. Schlossnagle +sig X CA57AD7C 2005-07-03 PGP Global Directory Verification Key +sig X CA57AD7C 2005-07-08 PGP Global Directory Verification Key +sig X CA57AD7C 2005-07-21 PGP Global Directory Verification Key +sig X CA57AD7C 2005-08-04 PGP Global Directory Verification Key +sig X CA57AD7C 2005-08-18 PGP Global Directory Verification Key +sig X CA57AD7C 2005-08-21 PGP Global Directory Verification Key +sig X CA57AD7C 2005-08-27 PGP Global Directory Verification Key +sig X CA57AD7C 2005-08-28 PGP Global Directory Verification Key +sig X CA57AD7C 2005-08-30 PGP Global Directory Verification Key +sig X CA57AD7C 2005-08-31 PGP Global Directory Verification Key +sig X CA57AD7C 2005-09-01 PGP Global Directory Verification Key +sig X CA57AD7C 2005-09-02 PGP Global Directory Verification Key +sig X CA57AD7C 2005-09-04 PGP Global Directory Verification Key +sig X CA57AD7C 2005-12-12 PGP Global Directory Verification Key +sig C59C3270 2002-11-18 Wilfredo Sánchez Vega +uid [jpeg image of size 2677] +sig 5793498F 2005-07-20 Tim Ellison +sig C4C57B42 2005-07-21 Marcus Crafter +sig 1CD4861F 2005-07-21 Eran Chinthaka (Web mail) +sig 333E4E84 2005-07-22 Chathura Kamalanath Herath (Apachecon Europe 2005) +sig EA1BA38D 2005-07-24 Ajith Harshana Ranabahu (Made at Apachecon 2005) +sig 2 4C9165B6 2003-11-18 Aaron Mulder +sig 2 CC69CEED 2004-02-16 Thomas DeWeese +sig 2 9284C452 2004-11-21 Michael A. Dickerson +sig 2 11DF87E9 2005-01-10 Paul Weinstein (pdw@vortex4.net) +sig 3 A54DA2DF 2003-11-18 Erin Mulder +sig 3 CE19D5C6 2003-11-18 Jamie Wallingford (legobuff) +sig 3 A1D69759 2003-11-24 Michael Kellen +sig 3 F8EA2967 2003-11-24 Brian McCallister +sig 3 A11D56FB 2003-11-24 Geoffrey Young (http://www.modperlcookbook.org/~geoff/) +sig 3 EE56550E 2003-12-01 Cliff Schmidt +sig 3 E41EDC7E 2003-12-03 Carsten Ziegeler +sig 3 ADBF9E1A 2003-12-05 Santiago Gala (Santiago Juan Gala Perez) +sig 3 12BFE79A 2004-11-22 Kevin L. Collins (General Purpose Key) +sig 3 D1AA8962 2004-11-24 Brian Behlendorf +sig 3 21D0A71B 2005-07-20 Dirk-Willem van Gulik (http://www.anywi.com/ - Senior partner) +sig 3 302DA568 2005-07-21 Rodent of Unusual Size (DSA) +sig 3 2C312D2F 2005-07-21 Rodent of Unusual Size +sig 3 F39B3750 2005-07-21 Colm MacCarthaigh +sig 3 CC78C893 2005-07-22 Rich Bowen +sig 3 015AFC8A 2005-07-22 Bertrand Delacretaz +sig 3 E2D774DF 2005-07-22 Sylvain Wallez +sig 3 87315C31 2005-07-23 Raphaël Luta +sig 3 9978AF86 2005-07-25 Christoph Probst +sig 3 2A623F72 2005-07-25 Christoph Probst +sig 3 C152431A 2005-07-27 Steve Loughran +sig 152924AF 2000-10-22 Sander Temme +sig 152924AF 2005-07-02 Sander Temme +sig 152924AF 2005-07-19 Sander Temme +sig 3 EC140B81 2004-11-16 Dirk-Willem van Gulik (http://www.anywi.com/ - Senior partner) +sig 3 A99F75DD 2005-07-21 Rodent of Unusual Size +sig C8628501 2006-03-31 Branko ÄŒibej +sig 2 76D83CC6 2003-11-22 Manoj Kasichainula +sig C59C3270 2002-11-17 Wilfredo Sánchez Vega +sub 1024D/D2C7F912 2005-07-19 [expires: 2008-07-18] +sig 152924AF 2005-07-19 Sander Temme +sub 2048g/51B42B56 2000-10-22 +sig 152924AF 2000-10-22 Sander Temme +sub 2048g/2982B2B6 2005-07-19 [expires: 2008-07-18] +sig 152924AF 2005-07-19 Sander Temme + +pub 512R/7F4436ED 1998-01-27 + Key fingerprint = 2B 0A 52 2B 49 CF 01 90 B4 A1 DF 78 7E 45 BE 32 +uid Sander Temme +sig 7F4436ED 2000-08-06 Sander Temme + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.2.2 (Darwin) + +mQGiBDny+tgRBADkQwHakdtjLmCDBhG8MOJQ2qQvnaPTOirFpYMGlYzHzUEyJ8me +ZeP1smfvtrDv/DjIsaBMf/YUNFBJ8038GWRSWtzrmAOD1ct9qF2tF9hHG9VhElTk +1cgLTP+4KZ7oFskRL0gr+efs2KWzu3N+6QxO65Ueo+zkRflEx+Mg6Br9NQCg/yil +McB/UMpT0IEqq48eDz9uOesD/2EcLdz1vAkPWWTbIp5SEO/OevdlSefBzPsyMW0S +rWFCra96z2VlKFuYZRnrQubR89/X8oYDtE0kyxZK2sZSd3DQL2HrXfY2Y+1wIYUz +wI/GCiVKnYcRYnAU9OA6obZAV83prvVD+gxVG3AkK5Bih+68SKRVbKjx4oZksbUU +J5LzBACDZnSB80iVprQgTvbD+fw+yGHQHa+4Y/pvM/PBv3+gsXXNRmANvRGp0fuq +C70Ha5HOo/4SnxH2BfmaJ0IyAXdKPE2eHmKXjZ7uZYOvjen4XPXnhLuedrIhLlMa +HApwd7Oayua3sMoflrj8Regpgle/ktSnlgohzdyZCC4BGtEtMrQdU2FuZGVyIFRl +bW1lIDxzYW5kZXJAbWFjLmNvbT6IRgQQEQIABgUCPdguXwAKCRC+uiuH9fxLQk9N +AKDlu4ooRTiGW1wLQT+m+rO55GSFiwCg8jvGc2gw3Q/uJ+0op4SvkyGmTSWIRgQQ +EQIABgUCPl1Q0wAKCRAzTmW2o1Q8ireKAJ9GJuPrs+2pWYGOnHN0L4IiJtZFDQCg +t3roYzS5DBJUMCiNWCWM6y79wBKIRgQQEQIABgUCPl6vYAAKCRByUICfrImJTBJW +AKDwVz2wkD9LwCT+B1KhSyX8imp9lACgqXGe0EcqhScAFAf2EfdgDKLRZzqIRgQQ +EQIABgUCP8YexQAKCRBtC8c6QFgYNzHlAJ43j5Af2p5dxfkAPaHT4Mmbqx7PeACf +W2UaQl8K0aowCAchv3MG7qwylAWIRgQQEQIABgUCQt7MJAAKCRDKaTl0gQOjfgEs +AJ0R82SDTJD7+g5r25Zo+KIXcyHmtQCgjm4KcTA8eX/acl/708RKy0WPApaIRgQQ +EQIABgUCQt7XMAAKCRBB6gmgV5NJj+WwAKC2lkGhMpsJQ0U+d0SE0gCXiZpN6ACf +RWJDb0M9SHKFRVsIrR+ewJCcx1GIRgQQEQIABgUCQt95KQAKCRA5TS/jxMV7Ql79 +AJsF0ESjrA0m5xwx2SRpLm9IQXFEDACfU1gbWn8zZWA3iaDpbeQa+mrKV7SIRgQQ +EQIABgUCQuAECwAKCRCM43a4HNSGHzQXAJ46ys/YBGTkXN1W/+zjTfo93N9RHgCd +E3fSANUDM1pCfwL14Ys4qHgsgCqIRgQQEQIABgUCQuDjTQAKCRBhGWouMz5OhB5i +AJwK1J0x2KuAJJ3x96QeGXEnT+kfWQCdFM53rGvEKPfrXVq10nTYad51Y6aIRgQQ +EQIABgUCQuOjbgAKCRAEkTRC6hujjSmzAKCcvcuXiXkNEpgb0r+YtdiEvutlOgCd +FXxVhtmR6z6THJ3Mm0YyP/H05ceIRgQSEQIABgUCP7nVRwAKCRC5JFKsTJFltjQB +AJ9Q7HjJWATBJsEqowuqVlR2IJby+ACgnglxrFr2Hsqz8hHr3K69z0VI0kOIRgQS +EQIABgUCQDAb4AAKCRAui9CAzGnO7TmEAJ4uVMO3FTU5tI4LFhiIBASgO6mQSgCg +rd5q4Lom2tbQs7Ohy2alGyX8TguIRgQSEQIABgUCQaB40wAKCRAHYXOxkoTEUr4X +AJ49FDJ5zixXqFxJ0IgD6K30Lc1zNQCdGlNDVwKbFpVdxoOH6t6G47RhpneIRgQS +EQIABgUCQbo8JAAKCRABBWa85BNjku3yAKCI74LyU6OFWOwwvOB3xchlTgOnCwCf +fbD5ujXIm3bksjWH4k+vCO+remqIRgQSEQIABgUCQeL6rwAKCRBMxE0AEd+H6WrW +AJsE09qhgSbOwaWGsvjLtmn0/7YYPACffBCgiec3cEuu+BaK1YQ5Znvz/UiIRgQS +EQIABgUCQtvJFAAKCRDNU6Y9XOW9+UhfAJwN5aiiz+KvD8pe2EFyZ1wQ6V7/WACg +1/frOe+ivmNMOLQXH2X5M5MlDz6IRgQTEQIABgUCP7mjxQAKCRAQ+kyIpU2i3yC3 +AKCxX3zQen6yaykmiI/Kv8kFplhKAQCgqJ3ev0COw2jyrdCE/1X6tJ+9ZXeIRgQT +EQIABgUCP7mrOwAKCRCoHuZJzhnVxqnZAJ9bp8FU+08Qv2ZcfXWA+C+IuR+EgACg +s6e5qbODYjTjziJ+Bo3VWvpFvjqIRgQTEQIABgUCP7pplQAKCRDLMqEHiMOlpRNp +AJ9y7uMmK4xRjyGJOVAcWKWjZkyF1QCgxGFEdTZkP2hFo+yuCZ02wVOhxPqIRgQT +EQIABgUCP8FRcAAKCRDMITAgodaXWU8RAJ4nogZkHnYSxuPxIwZuag4oOsDnbgCc +Dgrj9LDWV7J3MAQRFbBkUK860dqIRgQTEQIABgUCP8IgAQAKCRBo64x2+OopZ3im +AJ4q2YybRmvwLnYQmnrV82qami1p5QCfZvA00XrkLWWS6+E6dujYhY6i9j6IRgQT +EQIABgUCP8JpWAAKCRAJWkXcoR1W+5yAAJwLhxnC0GznK1YD208w2krACJhYpACf +c6XH+45Uz1GsRmVGEGeU6soVW12IRgQTEQIABgUCP8rmyQAKCRBoWnfK7lZVDkuF +AJ4+Qnh2Q+8vpyrmIHT57F39jyZ6NQCeOvAtsmM1R49zaNp11OHJ2qyNxEGIRgQT +EQIABgUCP83eLgAKCRATLknU5B7cfr3xAJ4uIyNVoEPR9oeAO/Tl4NsSMlx6EQCg +nBviKz5CQA20wEGmXeV2ulHNJhOIRgQTEQIABgUCP9DPIQAKCRBkB4bZrb+eGpGN +AKDCpLW7Xm3+xFrh6wKFXpWneqKJXgCeO7IK48ORVpIIKk5wmoVgFuWcDh6IRgQT +EQIABgUCQBXWNgAKCRAVP6DNdaZ2kqdFAJ9d59L6424GuoARgmBf0tGG0wjdMwCf +R/RU6KjKfxEg4yO561gn9c2tiCiIRgQTEQIABgUCQZomPwAKCRCLOmAfCMl15SqR +AKCNi67RXDy/xaVM8eTU0F3gIuxjAQCePh6BaZJ7gti2LdBkBZ+jF0s5j2OIRgQT +EQIABgUCQaJZhgAKCRAEl9WREr/nmpDYAJ97z/pS3IKiM1z0goCGtvGlEK02CwCg +gHw3Tv0Y3iCA91+lTO5Cjxa6Z/2IRgQTEQIABgUCQaNMLQAKCRDdumS6LDEtLwyj +AKDv/th79Bxh98lgkxFNqaBL1EwF1gCgsrG9bUjnZ6Rv/r3cHTeYZeV5SDeIRgQT +EQIABgUCQaNNTQAKCRBQjq7FMC2laClqAKCqIH/mrvMWxm9+OpQkkv1/Gq2bOgCg +kndCFfMXo9IKGa08O6jflCkYdemIRgQTEQIABgUCQaQwVQAKCRAXatnI0aqJYjNU +AKCkacSBxRp5mp2RJX1sHzU7SAP1pACgv8KMkW5MG9BEdbegefctw3HQgeCIRgQT +EQIABgUCQt6zqAAKCRD9b4jGIdCnG2YcAJ0eH7LOzlIYeGByRtNzKXyACVR12QCg +jewsoJi1gpidDV0ICv7qBjzYOTWIRgQTEQIABgUCQt++hgAKCRB1yqKj85s3ULnc +AKCYhUA5bihCpBjali4G6wGJN75ExwCfSFpWnwI2cFg7S7v48L4g4bPf07+IRgQT +EQIABgUCQuC/YwAKCRBc/Tf6zHjIk9MdAKD59FcS13hxm78FqCStgPWMw4s6uACg +ts8L3J3JlO+Gv6KJVGSdpDn2HqaIRgQTEQIABgUCQuDr9QAKCRA39o/1AVr8igwX +AKCO8U/K6TLUcWUI6V0DGk1Q6IHyeACfcjCUwj/4rjH3O2Yvbz3QIhSO2z6IRgQT +EQIABgUCQuDscAAKCRDJtabs4td03yIkAKCtIn+nVETFjH3mcPJ8dvEI4bD/yQCe +OtbZ2EuXWEk/unkDIfL8vcgxiuaIRgQTEQIABgUCQuJbhAAKCRBtmI0XhzFcMY50 +AJ9bAiGiZgZVlbltYt1hMVWWx4McdACdF5y7gTGaWxSzL7+Xmqd3YoAMnheIRgQT +EQIABgUCQuUQTAAKCRBSeS+vmXivhpfVAKDGWvcglNZYgaAiMAncznAF3bRPkQCg +nQf1Knu37vrGs9KatijlSMzWQZWIRgQTEQIABgUCQuURVAAKCRBrc6EGKmI/cqvr +AJ9q2FAsZORVtmGIIVncJbxFejToUQCeP7bR+IbUo4tV2cRBMaKHl9LGlsuIRgQT +EQIABgUCQudgZQAKCRBulHWUwVJDGmoQAJ9CjXByE2kv//uptTJWPCdnDOFBoACf +cEAbzJp6+/pwyILSTGioXy389YaIRgQTEQIABgUCQv04zgAKCRB+iDZMgoRJhLSQ +AKCSu/XIdlMDPIexgqJ1HwD+IoqHsQCeJ33JA2w4z4G18ZE44m6BxC9HarGIRgQT +EQIABgUCQwsx3AAKCRAhgklWzkGcj5MLAKC1eHjztfsU8gNu4hH3J8AVaWqYGwCg +ykAO23nclgickvefStcHXhN6Ca2ISwQQEQIACwUCPdgolwQLAwIBAAoJELK+vEAV +KSSvS3gAoMMrhcT/21RlQE02zx8g/MX6YOWpAKDYLt976gxjfxAQIiNxhd+qM29y +h4hTBBARAgALBQI92CiXBAsDAgEAEgkQsr68QBUpJK8HZUdQRwABAUt4AKDDK4XE +/9tUZUBNNs8fIPzF+mDlqQCg2C7fe+oMY38QECIjcYXfqjNvcoeIawQQEQIAKwUC +QsXxxAQLAwIBGRhsZGFwOi8va2V5c2VydmVyLnBncC5jb20FHgEAAAAACgkQsr68 +QBUpJK+I4QCdF8aPTZB5urwNNw7l8CKywVJ5/BMAoJRUvs1VY6EqfLKsfK2vfTOy +KnlViHgEEBECADgZGGxkYXA6Ly9rZXlzZXJ2ZXIucGdwLmNvbQUeAQAAAAUCQtzo +sQYLCQgHAwIDFQIDAxYCAQIXgAAKCRCyvrxAFSkkrwY+AJwJxcHDztKOd9Es8TvJ +r+2aXEv6XwCeKND3oriAPKliLhOSqU/Tq4ulW2WInAQTAQEABgUCQaNMJgAKCRCa +zTzAqZ913ZPnBAC6N+2L/Gq+Ex4UnTajhR6O+fr+izVn5eeqh533URcDr8RdZP6M +BLDjjzXlcTzHEF3VGsG/HpeZjm8BddkBjVNtA+rjYtPnJc84UbivmL7RvpwS8fF8 +j9wP3eMncjX5gKa2qnwlPFWv02mbq4zol5c8KLB+Q13AQx15pWB+79tcWYicBBMB +AgAGBQJBmYGvAAoJEDGmPZbsFAuBBWYEAIXzGlFfMBgraS6J210wZhEfy/u9VmTZ +ZLpsvxeispKwTIxsORgkqjGX8M0n126Uet86v0NQtWYw4vMJVbSIlNJzgaL8N8GN +wrf2LS1zudaPt597QXAg25EiYlMp3Cv0oVOqrK/HLqx/nLynpkCRisESQeQ2uF01 +4uaRHnHbWz+KiQEcBBABAgAGBQJELYhwAAoJECm4ktDIYoUBd1IH/0IeirCUdI6A +kDcHTt+Pd+V3YCHNOOMduLsKtfgXY9pOzRqv+CXpeaK9l1kmRiyir4zJR71DB4FC ++2CIa3orYTJAGY2d+R+GidpYYtv9FII7T0iTKkoJseLwHYsQYxSyHMI8v/k410sQ +T5UWbbbftitnOULPeeUelMfFgo9N0x2o+kj2mM+vFtwc5K9QXmuB0yr8vMibuNbr +DStL8/OAawgGSwaQKl4iXWZOm3n0kf6/8YEVcxPohXMwXAtI/00EaPv+GA8vcI4Z +rAtaGS2QIducZGOHx0oV7uPbu8CRLU5Ps1rdrT7KeLKRWCFn4E7K9XK0GKakOKrv +iVqeGTMkeNyJARwEEgECAAYFAj+/xj4ACgkQBurPqnbYPMaruAf/ZPnQYItt9xuD +m2hJkm/o7EU/PjYI+sBmhWpQXnmYdfuTdXTgmdwB4luFfLmbooak3j9mmDWJivgq +BLC2Ovaa3ircbLPUcshK2aOXZRjk77Ls8FxI0Ei/CPlrUJ3FoAy4z+Y7RxZ//zWG +TQOrSQ8Bo60/0rAykzzE6SNmET5Fx1sBI8p2OyCHjkEOurDKLy14IPzNtmEmNhRS +sm7hcdDR1F0J4pqTcQnnKtuwYxRmc9jN4jBHtoexs0pQ2Vf1RbJm16qGwvf5n8/B +uxfhbpt2YSJ/dIHF/wHbrhALTtMPGouIfYC0eTZXxGXVCLXOwR4JlMfD1hGuKQS7 +FrnsPWmibYkBHAQTAQIABgUCQv06RwAKCRBcMofHMxMbZfd9B/413Pi6erCC21fd +kXqdiTBVt6zld7R1HN/VN13dlCju6xIusIh1EBU0RqO29fb+yTbmooTiYr/u6B30 +QKxPpPf5KGI3Afn8ZWBCqme3gZKevL0MXYXFLopoL+cqRKWQJly4Ss1jHXLyJhnO +8fwf0HwwLiSavEpqwU1BkwFRjAbs3yNhqeweg1+fz0u1//IXq3brepam5RfAoGeF +7zDTeYvcgKYhKXrX+exiL7TsuvY3M9kS9ukMIWn0duBUOW7yTU21kbtl2uHyzYel +YIJGi4I1+JnGIj/z1uLY3kq5TC7jbPhu+/HBxWTmkdsKiR849Rmlpm2vARoNxI5n +X/VMe+vciQEiBBABAgAMBQJBvygrBQMAEnUAAAoJEJcQuJvKV6185V8IAIsE+yaV +4P+b7+oS1mN1lZRI/GbVZ+c2eylUlHMkpL+7gD1N8iEud/U+oQmhVYOwD8t3t/SK +xxgFm6CoE9na8M/EgPpiARkn1EBTc2xJTvxN3VKvF4Ks5iaOYQy/relbqZL3aiw4 +NLIsWAmntQ8gFCPTC2vZ6vf9fR6acs8mv2Z/AHtOs/GHMFpWRDa3EegM6+ZNnE1y +sDkOreL19XWSoG8PEROPb5mcqPkVT7rfssNtTUoD85sciDeCycSwgVdMdNPAvNA0 +JW3p7KoezPr3UMWOuoq9iYyUMBBKH51+truKTEPznFA28Yd1VSMSBR0Snotu9xXZ +4Wol4ItcdEbM9uKJASIEEAECAAwFAkHQaqAFAwASdQAACgkQlxC4m8pXrXxcjQf/ +bEAiRsIooPF13kqmri9ro2oMIwsnI2Ec01GHC48EwW8FEBo2u6Gkh5DHn2zQua67 +PcM3GWvp3tc2t/6Mj+IEnOLFdmuuLtathP2SG6J/1pTLmjBEQtaEyexyLTYI4+WQ +Hrm4cSTkwExjZE3YX9SlBKbTxQyyJB84Y+TXDUTliP2py+A/93ONagANwy1d06sj +nPtJWk7qxgOxSclmVxCecVwQI4MoATGjfkr+94Jc4a6j1ygZq6ubQqr12YKAwt2B +QIrSOmXScX+UJQ4b0fLQJcURZSTP3m1H7syCX05pxMtQo6Hryh43ncPZ4sGqNH5L +phyaiiTebbCl9u3RF9vMYYkBIgQQAQIADAUCQfNbFAUDABJ1AAAKCRCXELibylet +fL9SB/9YaW5uRavm/ZTtnj0zzVQWMwxKNbpfiHKH8uzLaydbT8lh/dNCxCJsypW1 +CpjmWJmYKJ62gkmSHYrg40HDLBSh6iAJ55z6Qpb8WwTJMZ89zx52XoiveAMc8waK +FRjajv/+aZYyxmRpx86SvTbSTPxIZvh0CJTyN5vXP1U7Vhm6nMzbuIiimsCOA9f2 +RyQacSwIK042j7km/kKSsoHd26oHtvs/dk2La43hqngfYrQmEmgpf4b/t5pChWBx +QkldSSCXuwGGg0C25UZArWh2DjFxW5uK1qCZyPxqsqsrj5IMr/xx2dFr7eO4+Ehq +pY1/t0PivHugnbxJI5+JkY5LlrU9iQEiBBABAgAMBQJCBIAiBQMAEnUAAAoJEJcQ +uJvKV6186qEH+QGUNVJOM3xHB0KRXoHUe0ZujcAbdgHKuPqvipiWV7ioMsB6K27G +xKAkgj25yJ9ON+ZBME92KO4H7w8hHY3jDkuCkyA0wD8sUC/OWkGb6D/S2fRVNEfc +b6hWFMPyk/OnoespD30rXDPujlaWMmreNO6YaVklf43mdrAPPZ+rjx0QHttmfA51 +9pEQAcKLOjhejdagwHiRVID0cwD5L5oAud/eSfb6T5wLgxmN3Tu50b94ugZL6f7+ +UqtyZoz5pvvORun06IyNii2SIVKipHYRy4+DHysgKGaJ3I8LJ1wgeVnboKZ1Nwt9 +ukSJZzkAOkUS2wPFdUshHJTTldt+A8ac9MeJASIEEAECAAwFAkIXIfAFAwASdQAA +CgkQlxC4m8pXrXy55Qf+P7HYDQc8VRBNyjbJywvxHbwQhaI10c2i2QokwwzC0ZzD +7gIhiU7LTFeLuaibobCvpg4GTvUTP9nEZ7qpEfy4U0NuPCuVFqsXrpgn7nSip4wY ++y6+3nGOXu7LQz3Z+P3KZNBZ3hdNyFffyUhAwKcOLf5bsg2fQ+7lxv+gun8e0RnV +16dgTq0g9YiewM06MoUadABOWydpvCLaMYIub+q6Ll167pI9LGjQ90c/BNoOvKfs +ef3/y54BYDVuVW+oPrwlc/EHRu1EF5jv8F6XFp1PrudI8pK34dxgSUl4SvCxjrM3 +AyqWntGFbTONKfPzlHlAtm9qbVV5tt0kXug98s/o+YkBIgQQAQIADAUCQilwOQUD +ABJ1AAAKCRCXELibyletfHwCCACD8m/Tt7U2i4Q6uLOmz6L9dGQdsQWV2ZqM77dx +LO5nQnXSrT/H2uItgSz/BR1NYrSnXwiEinzC6LTOYwLLOH0alLeZoKthyCMrl+2Y +RwUuXOrGFcBxf1Jj0kg8rUAg0x8uAeSWJnAnlG2zpeip5k2xJSrAX0JFs2V8IgG/ +0Q4EYH0h5G5S8XMAyOUNvM/WYrVri+7MzeRc3r8LsINFIIodV23qA1+WyFlK2ehu +Uq6Cb6/vd/it/3FslxdeAtaVPLiu+16BG4Lx8EaE4Y0FGeCMVnmLSerfrilFepmS +nY+QU1YoT2tlOF4ekZi9wVxax5ka9AnhAod6NIHWn2M0QCWliQEiBBABAgAMBQJC +PU4xBQMAEnUAAAoJEJcQuJvKV6184NwIAICyKezLJaxT8Jgqfh/C+C3LaS6uiXKF +/IzgWRF3G3mLDVpXCB8k0GMKZQo0h2empeybzViv/cnjwqTysskDPrsbYsChDvTY +CDtlcyaTVE+qcqP58zPl9XyCu1EF8TTIGkrKYqE0d0QzFHRNrguQD7gbGNo7yQx2 +Jtx/w14EYKPUj7Ho/Y+xPrdlW8AuhM86HRE5aw+qN0MaY4HWIsaUreZCkvW+fnvd +EykNolLjZ1RYBbMcWw3qrpBrU9+VurHuDKAPjnm1KfevtxlcfOw/MYP9v0svG/R0 +Gf33RIINQoUVC3yKbyJWBA3Nt4VZOSDYOsTP2nKZFkz+4/wbeQH74u6JASIEEAEC +AAwFAkJPxVgFAwASdQAACgkQlxC4m8pXrXxeUAgAk6VEEK0BMyqB0Co8F+PDDfRs +UIK+kuTzRnhWdU2ffJ6bileHtzJsRjOvxZQbAwAMHfoi3o5AhYHRoTnQAx2Ptgb1 +vtYJT/7H38OIL/DFFu//3WojJMVNCJ3WKcI79GA1y4Vcs+pb0CA7yai0/HRY9X5h +vsoKKgWq3gTWcAIUqtt08lTt9B6ETwSWn1bqKu4rOvwyhgEG169ekn4bVCUjzdyY +ukEGqJvY7VN1cVZZCITWglWZlRgUrYVItHAUdwkHi7URB85j0Pd7LfLD1IEWBZYh +olzJchqEmyri6usD6644AJGmyMBKielMOM7CBMGafOZKgvnOvchLEZzLP1kDsYkB +IgQQAQIADAUCQmIsbAUDABJ1AAAKCRCXELibyletfIGCB/oCHRax8KeK+0HfkIaI +X+mAz7/IWUVvI9SFyb20sa0jKhyM5cg7Qc2z+o+zyFQZjNsP4Jq12/FEHy/5pNu/ +FF/AkSZtFvkHcc1nv/Rh15BvwlHbuT1kVSTCbKQusJz+TZA5aD8oF0tis/YZ1a04 +CusG15wllEPUtcYgWQ0i3j7SRt1fpC6JaeRBrdny32f3wiDgfciV/j+2jTD1ax35 +IbaHglfGU6bqZTfCU9qEM5OCgkeUM7U5/D6DYvrbh2yt1I2LiPg5o93wPPLAuCdQ +aZ/hf3iHifZQGWmJo4zPqGN2iSx5EFws42ajmPRga8eE5Ztum3g7cx6weji8Qmyb +RPQ+iQEiBBABAgAMBQJCYtTjBQMAEnUAAAoJEJcQuJvKV618bm4H/R33Nty3NAjh +pYabN528deRDU4BuA7Lgt6RT+pQWl2uiu10AO8uaMzI9yqPlq98lIwz3D5P7tPeM +rt/+ZvAkQ6Vy/4oQgGOPrQXp3pR7RO/hMljnYLjW5uwJSXY3WcMs073UHPYS1N4R +pcuZ15gt5LEpw/hOf8CjAoSlEs16sxz32oLA4Rjth9Dx3OOhhDgbmA1QYOitEjv1 +LIqIolVTIjrXQWU6MHPLJa1930wHGaH7HUlVELCZv82HTbdk0Lzle6+FrDMYRhKL +gYxHklaLT6v3AdHjbPoIex3aEO85Hn66Ptfh4Cakqm/egI+xpaWjKrC+HEduZXNL +z0NXyYRRLPiJASIEEAECAAwFAkJ1VfAFAwASdQAACgkQlxC4m8pXrXzFXwf+MOdL +pb0Y2mXB02nnYvjwZCu7MTGNq7ktL1+D/1H7uBn1NE4KRKJmTzm4UzmC0UL+uSIg +VriRWUoqQLXX1m1EHY3YkMYwVtL2fr64vUZDuubabMuaZbFc4sMZisEHgJYjRaq+ +m0wEwelROXRcRXqQkz8AExa6S9GQAL2Kzv7vwPb2v0kC/GVvAmRMOP7J5YLehDfn +O4ISI76q6hiSXH2+LxvD2XP8TJebB96CQf1VjDcN20yCjyz0deB/c1ijsnGeU79l +JhuX1b9mfPlejlB1ssIClEANXV69W+vTs5KT5BM4OMZterMC/quP/kIcZzgrMEv3 +tvr2TTr85r05Jzs3N4kBIgQQAQIADAUCQocnlwUDABJ1AAAKCRCXELibyletfH5d +B/4zveaLhljCF0FbrXaHu0ldNmRmjnXPqsEtWslCfpTQ086gQHKrd2dVOai4x+Lm +1LsQblorESBRW345cnE/dn2ure2G5mICQDFqK4mbtIAfn6XRh6XkysKjRDsUfpRA +Lxmik7fnUT0OoMgUQP0DjssOY8V3Kxkifez73CGkSlK6Zf56cgdd6b3G14lEFbUX +WUHnE1x61bGwh3GYB/kwiaLU15hQXDtnF0aX6vHBB7/1Zt+B21fxi6Ww4MnreVVF +FCv9ksr9KB/0Dgk4pNfOJOdWJq5uvih1faDUE7dDYlvcxtTEny5n/ubM5oLdt9dl +Bp1CETuKAaIBLVUX1NHWUSZXiQEiBBABAgAMBQJCidDwBQMAEnUAAAoJEJcQuJvK +V6186nMH/iIJgIdCk4JHrTiTQ3fqTGxI8bxWpsnfRKVOXX7P8vtdfZl16cIoAgjv +BVvQzvgJBiabQM1kRwO6GXH6gLLjLNbYFL49YA1iz/N4liMmHK3x8Vlcvrm432Ua +E348LamDHaCs8H+hfIkGt0ZKPqOLKDG/RjeHC9fKfK8XOQ2bw7/kB3gtp5AySiGr +P6rircUmL3LHstmEdk+tHOPPbz1VcDcD5HdPKJC9chcmrYDmOCMf8ofiApo6/yq6 +KuRzASbWsHfRnDTmbqpuw3yw7Cl+Q2JwqGvK3P00/OHkN4BDxqzi9i7LIVrC8CcK +EnkxUGr88RbyFIQKsspOozf1FbOG3B+JASIEEAECAAwFAkKc7YoFAwASdQAACgkQ +lxC4m8pXrXxwWQf/aE/GF9Y5ljZOlp/HW0HO+chdsEBWNYEUg6AoJT1ObM/I/ItE +CiuEMebuZ7uloWSn6JwozZL25Jd9KhQ7xQVbpKE//nrn+FTJQQk/eE5ylPRjq/rU +1oYm21fbRVP3qv8SglUpg9RnurAKpZUgiqxPOsp2K61Eg77Dd2SxDChWCn9s4lRU +GGwrAPcvxjxYzqDhG9KTMR34Ngvtvdl6rtJRrvFCizAT5w4VmgFnDwKSqzUNE0Ta +7O3FEu2TqK9xmvD5wXxOQ3/SEP5WhuUTIsUTNSXxh5OubKgCmBag71rtwzNp/Rk9 +5yr+YNeUTZuBmmqZyzsk4wcKnuN5puyzLfLITIkBIgQQAQIADAUCQs6PfgUDABJ1 +AAAKCRCXELibyletfPsXCADCgbfenUjocTtzMTsrKeD5EkAWtpjRla9+YqUdD8n3 +UT7XXcHnTi6oXsb6CTzsPmAehl8eUJXfTDdT0WZ5h0sYaxHlz6JvfGlRz7oDwvl6 +BcF42nal7wX/VPy1RI9pbbkp4vFCJp+Tzr7BpyCkOvhBbtsRUY5KbmTOE9+jOtVc +CDHKN33710xcdEN4zIHgwyzW08AB5HB0KJVDtQZ4rRQyRDJHSB4mRGzAcie6NCQw +gzsjrjyixMoHamCfbo9H67g45hHVpuAlPQFLHSWCILdTKJvPsNNuhOEKe5Iic/q/ +KCb7yzJ4KMxwdqTsPklKFkyNtx1Tw2fxPeYV3otbdvc/iQEiBBABAgAMBQJC3/Fc +BQMAEnUAAAoJEJcQuJvKV618GUsH/1Yd0afVXyZBTVB+JHnOxzxBcrEHLzyUU7Ax +BR4KadYdWkQ2hvlxRoKB1WOJGXSmghLis5qee5JqX2vkMO5vM1nD4mya/Vra0eWW +2MwDYoHQVx+uQEc17GvSjiEJJuN7ikyaNpOadnSwtkCyiYGKdxMhQQECajwUKcHH +RumqWxpddZeTnLALtgjhCBwPdXUGSzrRXmM2maJ6J8zLhshFRG5PB8pGY3zb0WdX +jvJg/q+9BpOoXMgomTK/RdcdOlDO+N2K123yh1otr4IV7aGVhAjRLHw1A7gK2Hfz +1mBfcBcrLfcOwEvPYTNN6RSXpU2nqmIvclmpqFufbSrtYY1fJraJASIEEAECAAwF +AkLxvckFAwASdQAACgkQlxC4m8pXrXwvhAgAt7ewAH9Jpxowbunyz7wemw9iDkcr +KVVjKYA2GY9E7ceYTIztsFD2AcqA0g5ho7yukVy4afvz/2OpOoLVKvcJFyzko9to +ZU2TW+07qp30HAexFlOpAkMjapOP6K72s/C/aZ2iyJKZSJhorYl7qQMoSWwLWZb/ +/UQjDbbYdAPacDSDnjihCcj8GeP9kbDEISZjXRiTqHvbKhGm5UdXUsbuuARjhFjE +zL3874ZB32eXW4BTx84dlMnNMJXcV+FI2Xk6EqxmhQCCkpt3scfxfU1myGgSsjEI +JM7x1a1e7cq41jGYNi/aAo4PreqTnGo38jrHtMnMoWTe1qKXkP72v4Pz2okBIgQQ +AQIADAUCQwRQqwUDABJ1AAAKCRCXELibyletfLzuCADBvWHzNviCkaUo/Sdr/UAO +vZd/+HZKReDtsQL1t3bfiWYJIFzaEjAc45GLyo6ZIUodUor/2RlzvC6nTtjwuDQP +PILA+3BGnCTX/bmwRqNj9m1S0lzxuLqPRSsd6rK18/sdNe2wdQqMtWqWeetRBMms +FOi1QIG/BvNd5fj/VnIcPubHsHr2BkZNPSJJ422L6k3t5BLhn1rfJGIYuGzjwphL +wBiXUGB+kfv/cv9w8ieQEYzahtpFHBt1Po+3pSqrg08bbNX9U1dbvV1Es0Ei9UZe +tX5w7GN8jgyPEC4AUgEgk7WwKuJu+wfTlH9fUVdRq+DC1zRmOY2EomuzFaBqmSkQ +iQEiBBABAgAMBQJDCEUCBQMAEnUAAAoJEJcQuJvKV618E9gIALle6ST7H4tLZ3ZE +v2bwBUXY929kpxXTIm9Gl44s0DyEYUEN6RkXzGI+PcpT8ZrbSfwPlH34m9ontROp +qfRTgBz/SoBn5zx4F7ZfJT+JqO2/fAX5e5do65amcI90UrAx2Evoc+QcIbRvG91q +8NjBJxHlCKYHsBofmAu8vRz+4tyRCcEfAjhyP4wMcO3s0gAfOkq4vMMEWMCotY1z +JJ5UTanIokAh7r9+pzcfRnVmALHG+z8mKY7rJ9+3flo8s0hXJVdaRw6oprN8Xx79 +324DEO/EgFhUqtpi6HPZwRyCYAUY6jHUpyS2AyV/5YwA0FIN6oF7R3Gj9+QIFOhw +gzjPL5uJASIEEAECAAwFAkMQ1jkFAwASdQAACgkQlxC4m8pXrXx5lAf/ZcdgSPxX +sccyG7nnVffzBD0OWWOnwd0dFeZmVfJ6tZs8/xNU77EdE/gI13CnET1sxovEI6wk +n0WPSqEvyLSTwhx+IBuGHkcP19iakfst1blrSbwFOiPa7rG4CRE+G/GXXM+O/hA6 +A6OYf4mBAFQPM4VZC1BzHYkeVfm5atcrisIejs/8YIKumqZnfAjvv7IK8x24wuDj +O33kSA3kN80D8vgxVfx7D0jyXcGSbZvY4svAuGoI87NfZnrdbMX6GN0/jaLRshdj +mrsSV3opt2IGDBhruVlx6ReJJH6/4CDGOIo2xNp3IpKd8Z5kvIKPIFDNopd1vyYP +6aHntMnsnFBA1YkBIgQQAQIADAUCQxInrAUDABJ1AAAKCRCXELibyletfEMaB/9n +ykD7k/wrmfFqfwxbchj5mad3WbINJq++HuujPfsP1jP3B96cLjmtqrXl5PlCpYjr +46SkMzgGf6/59aBegMe7ISoLVrI6goLoUbDIejSrpYxw4F4J4IperLj/HdBNWrv+ +NSwNw+kbueCj5QSX92eRsaFAML3AIc6bNns5QWSZwqPTEoXvgfIVdrUcWvwSAwxo +CcpEU3Cs53oLXRHxKsZe0UFdGHKi60YzKsYriVFnXTajN6dxzhMMVUVko+dMIQ+z +8veSBEu7ufJMiQxJMc95ueAcK68C2UcqWx5LBcmEglsiq3+dB7aqLVB2IvouA2JM +/b6OyZL4Sg5B5HNmujiwiQEiBBABAgAMBQJDFCO2BQMAEnUAAAoJEJcQuJvKV618 +elQH+gL9TJ8iFrirYZmWBRrN1NGuGu3ibaX7WdXBuDYoryLDnrcS2h1QPSLBiOI7 +9AkfPHSZXeF7UghTmYznWbDuVAlGiEGDklQf/D0IPm/7o2YIN4WxqpDBS9VpdoCd +dsjcqCLQXQ3BGPfRVsTgHY9z/cnBZxg6Qc1778bC9lrWwOvMuQroL3wv8o8e7xZc +ylzEf7RKe6wlxhEmXH1K0LpjmjHJdy+mI4kE5v6tUAN39l8wxDe72zywVRT/E18+ +3YTj4UGGMXdyTysm12gtbtLsAt5bqe9lUMNpSXkQyCHM9dGWHXaXCvKWlxH/PGas +UJETNXDeQS3jTrLKnz2u3UD86xyJASIEEAECAAwFAkMWHdMFAwASdQAACgkQlxC4 +m8pXrXxpXAgAyyfHZq1mzSC2ItgSHWWzQnzvQ6EdNtoTMlVzxPIuw/LTipzZGHCl +ZeeMafEwiWApwhVi+In51pNalOXGUwbZ+z8n8QPc6dCOQwXjxlcNSdX2pDG1egUE +fTswzF7UcBcH1BUYChf52qejaMw4C/0JiOPFU0+ef4Dn6G3T7aIwzYnFVND9kGbC +jhAjoR68kPOI1TfBku8VMlrnzmOelWaWGApd6RPdhnEj7qn7sXtsibv/C41ELWNy +pmOTDJOV0kW72/teHl4NrkI19tCoX38KsN0802YIs6V6xpT5fSBinh1pvGsPMxYe +Qic3K44//H4XUXD5geeO9JsgE8OrLoBHzYkBIgQQAQIADAUCQxdvcQUDABJ1AAAK +CRCXELibyletfHfvB/9ZZ21W28vEldK1YMujg2Ed66xN9Xdyie1tWhDVWbUXUTVu +CQv4p52ZjIPHgOhX/6b8ynRdwCIKvsxY929PCrOAYZxIFLF3SVOQhOGOcrpa+wfJ +ga1ileWzO1GOdW7Qk1pLtHp+Bqpfn2uLlfJFKzt9/+UedNRzHSuTBq1z80zXuwAK +FKn08QFSwqHvhtpdY86/Z/gil59FGYbnaJWIvI7xZV6kmknN/E16/slyQUbXeQli +oR6D1kwkgwx3FTbfM0zKmcf/wQ6vBlM6caQA7MBJJI9MCFqipWaLBPbsOv0oqTg2 +LqfK7vsiZqJPHmGb2PkIH8BypLRKuTsnamPTdmYBiQEiBBABAgAMBQJDGMCcBQMA +EnUAAAoJEJcQuJvKV618kFkIALwOk7xF8xmipgztWcLwpyC0YEPevfvMHLo4yxg0 +ZPaQULt9r2hRK3fRdb7yjcckMawoM+aT6TeUVc5Uoi/gCfyvi7Crdr1EmHXMJeN4 +nKFs0Xzqax/wVIQKiZXBi481A+KAr7GaHDigdEBGoacImZSmCxnv/luxiEt9Uw1a +yS6/QN2Ytj/TSUH2TLWodryNs2pMVkmyFgYb4E5yI7fplYKiy8BPoDG0dnMkIz+9 +QENZV24Egt+vc+CvDmYhZlP7a4ElXWCvspXlJADcz4PobSP2+CRcgSRqfZSDjRax +w8sD3enKHaj6R3b/GAaAvgq1A/+7v3SkbQHJVv3mT3ddDc6JASIEEAECAAwFAkMb +YtkFAwASdQAACgkQlxC4m8pXrXxdSAf/SUeCnklH/bnOtesm/kyDF+ggI7ebStCH +SJwXdt5AtsAs5hRbQOp7sG8/gsSoenCT2IoMpd+/VeG98cpA/5Vbgs8l+SzWyCwt +TnKvcpD5i4kzgmu/ucjwyJ4J7G7QhZg7lqAo0TTePSzc7DMIuGo2EqeCtY4qZisK +O1uPgrNz3//FCiaRMDcZ5ViLIAqVa2fhBCBP2FNmUzLKl+ZyRsrjvMQfDeCW0BMi +ehUehsFVo+NWNcH1JiYLH8UqL0DFnlKS+RVJmLVFY9EbzgGo/7hNCWwMr4p7Z6no +OmtfAVwjDdAfTiGio56LWOUjvRScNfsL/TBBH4INUub0pjnl11MKAokBIgQQAQIA +DAUCQ51L9wUDABJ1AAAKCRCXELibyletfCbBCACc7EZl1AkgLLQ1v5vLPvhexEuW +G8Ovl3KXniJ4tv89cfgpPvnxonovP12jWX9geho+gCXXfgUoYgUMFG41RVkuVCR8 +ajZrKBC4lLRyGypOzZSG5pAQkgPByq8lph2gnzPMNcOMPgaZMwvN+L4LBEbo0vP+ +Vcj9/qmfvfXPhg3RkM13gLnF/J0ivxtO6jkS5Kg6c3mTD8uhbXQ1gFRsPp3dBWtM +hnijS3wFVQUSSv6xYz7ziHgE11HC48BimffYgMFdnaJ+vEsvGpAP5sIIGpGhPGyL +qXWhpxIGch/8/Poa5/lGY6Axyq6vnjjuv0GrK/KUQd9xkfiv5sIpV01MdVGOiQIc +BBABAgAGBQI92C6JAAoJECQOZvzFnDJwTUoP/2VFx/9CX58lCMy/6M+5xsdoZuOx +UTaKBZJhZAhtbmq+N2y+XcT7xiTMtkNfQBiGCR6BTAdKdHAgyqv91XbT49OI+i0S +Yrr2Q1KT2C9KM65COpv4/5fwqhcjJ6M5NdYDntMwAH3iN2yMe5Tu+kqc9FObsXTD +PrGpkicH+sji8NfzmLwDq1yz7Q55ADPC+hq6c3CZWKz1UAyBysmuPlUAbEM1Tudo +a/VG1gs6wQFqqb8cEethGxr9DIUQmAbaI9BEEPsM3wfC8LUqx2b/iv5hxV3dLSo8 +KVJ6sVhuiXCWX8zs+mW6iYZTVTXGybpwbrDOu1JSYdijQ7coJ/+oPs1klbpxCoYQ +g8rhCnJr8tyQ+xLkBBfIgj9edU4TTOqGIy+Pu0qVHr4Q1wMmzI3bDSn7B9A7zu7P +N2OG9VTweu2iABWPABj0FmwVHANGkZsg4c81zfsD+D7CnlKAaQLCwOhpojAjdm4Q +dZEJSvOnHR0Y6oNG86LyQMXRbnzfl6W9ku/Mh5YLpPTTN6qHc+5IfRnlfRQbkxyN +vWj4/9o4XuVav6eHDwRjJG/wi5uaIZmEi1jsmM8XFu7pwgSh7WjqJcsqROG7Rdd/ +WxmEvxYM480DxWzhBqE6N0sof0qATUvAc4EQsGuWsmkj5eaNQ1BJRBdIY+khEDTc +cgylxeJBeHFJR6vNtB9TYW5kZXIgVGVtbWUgPHNhbmRlckB0ZW1tZS5uZXQ+iD8D +BRA92AtC/W+IxiHQpxsRArzoAKCycX5cgVwHrfPuIghcZzAC7COi4ACeMDb0QwXQ +1J0khK/IFYHU2qkzJiCIPwMFEEBfU2DMsutG52z20BECGuMAoNY+5TVOXfVNpfZB +IfsKB5ytjZigAKCwR7olhzhYpDRJ2m3jZl3LMb6VO4hGBBARAgAGBQI7SJb3AAoJ +EK+xlq+1hAqxlBIAoOew4oVLuGMF/2D05csGqUuHQZ6FAKD4+Qunnwq+9iK+ng3u +QmZTH3merIhGBBARAgAGBQI92B4mAAoJEF1BSuHgBcnLCiUAmwdaBIuhWfJvp/uv +o6jAAetVHseuAJ9LnEujXb73zoOxI0KTtCZfiGJKUIhGBBARAgAGBQI92C5fAAoJ +EL66K4f1/EtCSVoAnik6wq7UCg6v5PwqLpKxXQ25Q0hfAKDe5U3qN2W5/ZkvzUfL +dBjznREpFYhGBBARAgAGBQI+Xq4WAAoJEHJQgJ+siYlMOIsAmwWLB2kEUrhwhpmK +D3/GikIeVObEAJ4ol6xaq/G8UTurFQTCOWLrAFAk0YhGBBARAgAGBQI/wheKAAoJ +EInYTK9GsmLGFLwAnRVTKQGsy/PWCftEnckK0FYX0zdkAJ9YkJxQZEe+nJxYP1tj +dC8gxUxuMIhGBBARAgAGBQI/xh7LAAoJEG0LxzpAWBg3pnUAnArOS6lbMXY2AwvZ +ohG2HYTn+/mWAJ9MVZpWrhBVUAV0Vd5+I6Mego0Rd4hGBBARAgAGBQJANWk1AAoJ +EDLsF1kwoh1V854AoKzfOkqCJUDAuM1xppuYlk2lvEwLAJ9nbI9iNTUMTdR9hp7A +UhYhjkb5aohGBBARAgAGBQJBnhF6AAoJECdGoiSHPPGtMXYAnj+H4yA1bcGQZI8b +iyl8u0gezMNtAKCQQCnkBSh0bD0OQUFgnewJcMqFRIhGBBARAgAGBQJBvOz4AAoJ +EJae0QxWFVjL878AoPKbdK5kl7Z3o3oH8xmFtAMGDu/JAKCGvZl0iltsqMa5lFDt +M5BlI8DM04hGBBARAgAGBQJC3swaAAoJEMppOXSBA6N+RukAnjqZme1YjKNyfAsf +YZjXUK5aU3YpAJ49fH70XFvgor3pSBgSbxV6jtIaFIhGBBARAgAGBQJC3tcnAAoJ +EEHqCaBXk0mPU+EAnR4y5YIZGiBytdZBg92PJui5htAkAKDPGjg2Y3D2zVC5CQ2k +KA9+AnyDWYhGBBARAgAGBQJC33kmAAoJEDlNL+PExXtC73IAoJJWyt4KJalQ/Pgq +Mh1V3ePog2hfAKC3yxWC/SbnLwIBluUoyOUMm1WHg4hGBBARAgAGBQJC4AQIAAoJ +EIzjdrgc1IYfdw0AnReGsGPIWfy5XjGJo9tEpfV0UnL9AJsEaKBItp5/KOaVmAth +GxapsO2cFIhGBBARAgAGBQJC4OM+AAoJEGEZai4zPk6EG9cAn1oa59ZvQsfQb7OV +BX5W5XXvCWnaAJ9lbuJkxgYVGUI+KeHMxXd6EyJC/YhGBBARAgAGBQJC46NlAAoJ +EASRNELqG6ON4e0AoIIYQ2P1ALfIbVErd4co9N8ZleFXAJ9m72Qi4+hwwwrK9CKL +fg525l1rmYhGBBIRAgAGBQI92B+kAAoJEDYVIteCq3vR49cAn1WwCZKvvQygratD +f2NFaYKKp3dJAKCtSj2Eo4du2vR9479l5NzdsVEO7IhGBBIRAgAGBQI92CGEAAoJ +ELNdEj0TBGFVZ20AoKQZt7ShnfFIxSQ8/o9yKYxaX4KDAJ0XtWwSTl1pWfTbfRAH +WHYnPX+BTYhGBBIRAgAGBQI/udU/AAoJELkkUqxMkWW2U0kAn2MLl2wPdfP3WE47 +nWcANzniCZ/zAJ4lNlBBAGhyPpN4qonesc9Yr1ptu4hGBBIRAgAGBQJAMBvdAAoJ +EC6L0IDMac7tiiIAn1ftqcXTJiGPjbRyT/Smd7kV/VmwAJ9DUzV4+p3HfRuaPPYb +q+b0Aw4xy4hGBBIRAgAGBQJBoHjPAAoJEAdhc7GShMRSbAwAoJMV0nKZOMe+iPud +SwKuM4O3iU4tAJ4sioH9oNbBe0BEity2nd17+TJPSohGBBIRAgAGBQJBujwjAAoJ +EAEFZrzkE2OS5DQAoIIi3Gff5j9RLAQCh9meccX1Tv0mAJ4ie0+zvRzd4IWz+UjH +4WD2JOQPzYhGBBIRAgAGBQJB4vqrAAoJEEzETQAR34fpBmIAn16e0nNRUaBuMBfr +hjT3Hn2zBf+5AJoCekOvVn6ksrXG0dVS0RKduTAeeYhGBBIRAgAGBQJC28g2AAoJ +EM1Tpj1c5b35DpcAn0QpwcjPZu2Ja5y/01Ipez/lGji6AJ9vh7fnUWrhbxE1tIsD +4i0gZEGFYohGBBIRAgAGBQJC3qOOAAoJEIuWKUP8JD88yAkAnjAY8j7Rnxqkvlw7 +flK5YdgwCWTfAJ4id/CMMHY9Ib/fsWZutmfNMcv+MohGBBMRAgAGBQI92CQ1AAoJ +EPwPhYn4lL4SK7QAnRrCEG8ImAJGGY15kkk0FNRhtQlwAJ4tXs6dckycYmJQ+T08 +/A86VP9ZlYhGBBMRAgAGBQI92CpEAAoJEGY1tsDeiF3TMlsAn1BTxqSDfBpMiYBE +h0AwkaVa8NZ2AJ0fkxEG119NU83sOIabvkNQZAV0q4hGBBMRAgAGBQI92C69AAoJ +EMl8UJZcHDrXUiIAoLHEw7Wj6eoKqSidEwbEu2B55in8AJ9++V6OtRzmSsfIJuHQ +xTbT+sAHJIhGBBMRAgAGBQI/uaPBAAoJEBD6TIilTaLfZqEAoPMDbDlxOAWbRZ62 +Zt1rz+l/5HffAKCBhnvoNXV/7Eu+Nk6mkB+3T/MR/IhGBBMRAgAGBQI/uas3AAoJ +EKge5knOGdXGHgcAoJeQ0d3pG0JuD/e1QM9sYzH5FN8hAJ0YKg755i7Aw5A71a+i +GpavpNxVkohGBBMRAgAGBQI/ummPAAoJEMsyoQeIw6WlJIkAoKp9/xCW5XZp7oXa +bPhQm/jsqApyAKCN8tcHunrUEDYgRlxe5u6FH8cmKohGBBMRAgAGBQI/wVFtAAoJ +EMwhMCCh1pdZSGgAn2B4X4illiapCUe4i8rjRmhaw8xYAJkBDLZcYstpJKbGtywe +BvCCCRZi64hGBBMRAgAGBQI/wh/+AAoJEGjrjHb46ilnhssAn3Nwx74qqHl4di11 +VCG2PWIBy/59AJ9gKfC5auUefW6KBWeGpKtbu+dR3IhGBBMRAgAGBQI/wmlVAAoJ +EAlaRdyhHVb7co4An1lYpG0s+mPPbH/6PFWXZhAnX8YrAKCLumNtT1JV5gBXx7la +3+9wqwvN24hGBBMRAgAGBQI/yubJAAoJEGhad8ruVlUO4GQAoKPRVEcioVRrswDB +W+A7rESxmXc7AJ9Jkp9FEF5rFNGWWI48xVlT7a9P6IhGBBMRAgAGBQI/zd4rAAoJ +EBMuSdTkHtx+V6gAn1tBctd8S2rk4CjFt+AgmtLjHkgbAJ4i51le+W9uoZ50MgP/ +Q4hjf+6EK4hGBBMRAgAGBQI/0M8fAAoJEGQHhtmtv54aKyYAn0cw1yCk3/YfeRQj +XxG+yHyORFaZAKC31T5YVKzn4KtyKd4zpzUUKXhGa4hGBBMRAgAGBQJAFdYyAAoJ +EBU/oM11pnaSYe8AoIewqiGQfWnoU9OBEEfAYk9bS5tQAJ47f4AsLuvn04AqQSS9 +NsIdMiRY/ohGBBMRAgAGBQJBmiY+AAoJEIs6YB8IyXXlJvwAoLF96DKsjuG50FIP +cSRrNujgwfGOAKDJ9d5I1FUfNJG7nzBohJE83XyYUohGBBMRAgAGBQJBolmEAAoJ +EASX1ZESv+eaV24An1H0YpbOLsI9LgguNfSlBfjUM4zoAJwKiI1UeX5LDIZdkrn9 +tvcrgA8t0IhGBBMRAgAGBQJBo0woAAoJEN26ZLosMS0v3YIAnibxvl1k3w2LKme5 +soS285D50FArAKDT97KLsfe9wYzWO3WrkvXWxSxQb4hGBBMRAgAGBQJBo01JAAoJ +EFCOrsUwLaVoZy8AnR7CAynHYuTYx3UfgleRgvRqlkqbAJ9AFMtizXSsyyaxe5w4 +/WYIki30TYhGBBMRAgAGBQJBpDBUAAoJEBdq2cjRqoliZZYAn1LSHINYz3P4Ff+d +YvWfvljEF1BCAJ4+1h8g25vGg6L16mDjMxstWByQK4hGBBMRAgAGBQJBvjUwAAoJ +EOgwGEgWqNOrm64An3Gu9p4kYN9VILj48axgNSsRSO2rAJ4nfbZB6dqnJi3W/6kx +W/OczeckDYhGBBMRAgAGBQJC376AAAoJEHXKoqPzmzdQdQ8Anj0sZwV4al9rjJyI +J2lXfrauR818AJ918M4mcObX48EXr4sUr5a5x40lhIhGBBMRAgAGBQJC4L9fAAoJ +EFz9N/rMeMiTjREAn1BIRuzgVi9itE3o7SqMGhyV3bXXAKD3PUMomazmefmlGg7n +DsZETruijYhGBBMRAgAGBQJC4OvbAAoJEDf2j/UBWvyKRRoAoJ44gRUHojQFAaTn +NlDGy6EVf9XSAKC2TVRAUUAjkIpfu52b4QSZvg9E7ohGBBMRAgAGBQJC4OxrAAoJ +EMm1puzi13Tf0+8AnjHEi+HKlAZ+9fyEM+AzDQzQ1A5KAKCYTziGxeKPFBa0+AKB +v7tDvqk8KohGBBMRAgAGBQJC4luEAAoJEG2YjReHMVwx+lIAnjmjoTVxLlNy9Ul2 +JMF5csHIvzitAKDaJOKr4XKKVvMiYkEzCmWp5rs3gohGBBMRAgAGBQJC5RBMAAoJ +EFJ5L6+ZeK+G6FUAn1zatZi8UAjOv6NtRc/DCjQdkO8IAKDTobTExS6uI4zYOsPT +VK0qiR0PsohGBBMRAgAGBQJC5RFUAAoJEGtzoQYqYj9ypWwAn0SiGRkFutvYdvNy +4xFQbQ7QOUd9AJ4zNX48UfJ48s3Dd1wDPUy5ycsPxohGBBMRAgAGBQJC52BfAAoJ +EG6UdZTBUkMaZ5AAoJF6B5URVPDzMdVpWGzzHm86kkz3AJ97bIF5CCbNa6IkyGMI +od9K0KG01YhGBBMRAgAGBQJC/TjKAAoJEH6INkyChEmEN+AAoJwC0hkuuidK6XSu +KW9Uyr+2Z00VAJ9ixN0j+X3MMYmNcqBU+nPrOyfx+4hGBBMRAgAGBQJDCzHNAAoJ +ECGCSVbOQZyPPTwAniE9iWYS4uMf5uYeVIecqktewZj8AKCg4OTJHo74OjvDcJTL +IwwBS9ZQ/4hOBBARAgAOBQI58vrYBAsDAgECGQEACgkQsr68QBUpJK8SKwCfZz3r +boWc8qpMS5GoAP1yo5/8tBYAoIlCaUBPn9wps4SroEJ6z1CrhrfOiFYEEBECAA4F +Ajny+tgECwMCAQIZAQASCRCyvrxAFSkkrwdlR1BHAAEBEisAn2c9626FnPKqTEuR +qAD9cqOf/LQWAKCJQmlAT5/cKbOEq6BCes9Qq4a3zohcBBABAQAGBQI58vwFAAoJ +ECoZYMR/RDbtbNICAKKJk0OIrzKvctpfqylQsegyvIbpc77q2GP16K2nJvNilRcx +NX2A6Rdq64J3ugpVS2BkUflTbYgTnHdBwKgx29SIbgQQEQIALgUCQsXxxAQLAwIB +AhkBGRhsZGFwOi8va2V5c2VydmVyLnBncC5jb20FHgEAAAAACgkQsr68QBUpJK/5 +pwCgqeZ+/ZQFwjHrI91IsD+XBfkSkhIAoN5AG1KUw6TnTKvSwYFSIY9IbVtEiG4E +EBECAC4FAkLcsaMECwMCAQIZARkYbGRhcDovL2tleXNlcnZlci5wZ3AuY29tBR4B +AAAAAAoJELK+vEAVKSSv5t8AoJlhQ+ybTNFIuqJ780lkcuNLeIxqAKCFpHC2sNP1 +u1FupyUwet59kt1PPoh7BBARAgA7AhkBGRhsZGFwOi8va2V5c2VydmVyLnBncC5j +b20FHgEAAAAFAkLc6KoGCwkIBwMCAxUCAwMWAgECF4AACgkQsr68QBUpJK9nxACg +tI2qQjWtNVO7xPosZ3eQouJ+0xcAnR3IBEA0/FZ8Ha2OTymLqk1RpIdaiQCVAwUQ +O4GTJ9xJ1A5QmCFvAQENTgQAqD4HhUjECEeX60ZZJG/dF5dSpmGBmVl09FXINXlu +7Xc1sC6mgivgsdFDip12OBTlLc4n7+x6Vp0dlg2rm1Hca/WfmUlRAkcMB4xNFSr9 +jkE27tpvkr790RmRwszvmc+FzP84u2BDOXGM9uVG9GmG42OL7VzhFYdijrH7dROT +z/CImwQTAQIABgUCQZmBrQAKCRAxpj2W7BQLgSFSA/d/M8Zm+uMJKMYjZpiEQOuG +v2+aupMiI4q9I+w4cckOis+r+Jf6OfzOt5ZzfJi8TWHCoGYPv/sS7UFOF4ZzJVcl +kPEd4nJ5BA2c4QA8nc2mTMwqpj0l3fAPAvPu2s3GZuMEMnNOV7d0rRbSNm2MVQpQ +u90rSAo9t1UUvnOrpIM8iJwEEwEBAAYFAkGjTCEACgkQms08wKmfdd0wUgQAhYIE +rpHELf4BBz5B6TTPKLvDHCjoWAyHZhVKHptrxt3mry1Z0vqkvnQWuCWj3XcSbKF7 +4IS2hqM6TAENv21/zdvKlS3Dl0HRqIvNuXm3qsBVq5/h1Zz2DDoVfkezx2AVligN +yS9CXH2+wk9Q3HKth61FancQ3vkG4caGgQQHCMuInAQTAQIABgUCP8HdsgAKCRA3 +4/Rf7mXjIXJHA/41BtLaBbaCKionRQ+NRFQb0+58ldv/Y2PwahI7/FDVQwaQNIhs +mdM6+kjCoyFqjFuRXb4oFMWF7u8jZ3FkkKyszOqK2NuoWqUpo5CQnnQ2mIIvf3cQ +pmgvW2w7uSxWCzd5Uzy/fSMS0/r6PRuVIc5Ew3saYzJREqJpvJKrr9+rsIkBHAQQ +AQIABgUCRC2IbQAKCRApuJLQyGKFAW8jB/9TXGI5DsCVVVhboCf5+IAODhS1OlJx +LQJwya63I/4Z+6Q3bU7EJ4dEZDvHsgmpX/npzSITUEnzr0uqT+Gq7xez/dt/2A5y +ub3yob9fIaCXzVQOY8p3dmk/QqQCamWtiPCPEgMDkUbD7vJfrTRmvDmAInn8Ye2Y +IxNYJEqC3gxjdZc34GJu0m1Bo2/RfZ9GKJm2YMi3NMHh5At+uhgDz0Sqk5l8IW5x +wPPZIjL6MdTzy6WcQWdP3V7yGP5f02t1GrXQ+rsbnOXWhlO5WonZpsqNuyGDTOLL +4UwBXUFE98DFJPJ3+jZtHBZBhb2J8lrJzEunUbUlpzkoy5la/OAMSOF7iQEcBBIB +AgAGBQI/v8Y9AAoJEAbqz6p22DzGQ0sH/A8zPAPm/VokQ/6Abnrm0HwsD7RlYKl1 +qNbaUq37W9Fa/iuqfLgEB1mDzsdWCL4GsOztS/TEYiUGyBq7vCeSWokcMeQB7mdP +kzzlvJf6R3LSwA0NFoPwTzXFjPmd8nVW51wPl7Qapam8gcX2sAeTYyRvDabV8MGP +V1gWQl8O5cKzCU10Bh3ifnwKVOIEV80vf1lpUxfA7D/6ejdmygKZpqoTe/bpug6v +7UiScSyvNCMquhBcgVUSn2+5ScEtvhE9qF6gxKjih6I/mZulj5WKeR3Katn4JsFH +MWSyH1GprQNMNId4x8EHDyJQqPufEGf77yKMyic318UjkWvXYHJsUWiJARwEEwEC +AAYFAkL9OkMACgkQXDKHxzMTG2VCqwf/WPGL9phyLdKyucNGV2t7uFfmU4zGVbKo +zfaWM3y7wmWh70pjhlWa9nwS22n8otKPIb7eLK5GSQYMZJmaaR6jdL/ERM2bgTUn +Va4MYt9Z/xUPfBWt/MH6I8Ugpzew78yLMbHWnq7CQhbHuoHEQd3keQrBw6qCFQI2 +2Mk/XZHQv14sFGihh6VGBqZfRTrHF1wgZo/u4XHl82AvvxQ2WCcic1ur2CTAeGB3 +hLZdPQeeCc2F8F8K3dEIygaxr1DfWZmEp0Ai5ndoMzUxrNelxrDudxAK1Fj/B875 +FI01HsIpTly6cNYiw8+vBFGDAc5pJJRq145PqJ9S+/9C5alfm8X4zYkBIgQQAQIA +DAUCQb8oKwUDABJ1AAAKCRCXELibyletfMK3CACdmPKobzv4csnwwl5zuDKs6Ik7 +SttfeVN6E6L+kAqtAEcWLX3vT4D7Wtr7B0EWYgmf0tHl+nhRsblr/vCZ88TpSNDq +lWC/SdrJu0w9it4sjvqv4UyVUFi4Rji2k+/EMktU0K3xN0/fvLvEY/wi9fjoAWtG +LuUeme6fFt0YM2Apf8s6hJxWD3natmmrFHChxLZDhIbgo+dWfuedblzdLCtku/Ub +CAy9HMkEzPzrOWzoBekOT0ANoDeS6cyWRoAen0js/vnzBoBISKZpWmYzoYhWa7gM +NBjW4gnwRI6tCN25lzjxbTOpHinX+A+aHi8QCOxTxuvNrvNdE40SjLQes1TriQEi +BBABAgAMBQJB0GqgBQMAEnUAAAoJEJcQuJvKV618T14H/3Lc9kksA6/MDawEA73T +XfbNWumYhNkOzb9K4I1W+yLCVAxb4vOrDkTTA7KZ8/nbgc7WHQurBsNN7qAKyUhN +lHBbwVlsEpLxK8UvP4uuUHMNaCvUSJ5CiiQZHdfB0fSypc3/9aaH+guJDPm2yBZM +aTgfITSk86Ez7GZQsXSCock/Pyuq41qspF+hF4txRhYRUuEe+GVoR9OJfoZYUipl +hCNXdeBD5bFBxlVKevBXLWEtdD4sHqCDlCvwshzGlwoa5sFyl7ddOguljqJeihBh +TW61xI+INBQoO48XrK11g4NzLy1i/JZkn02tvW2Oo/laRvw2SKb+FC2rjP4mmSSy +ITiJASIEEAECAAwFAkHzWxQFAwASdQAACgkQlxC4m8pXrXwTHwf/WqeLt1FxuN3O +55rh3BRxVFWrD6Pdfz0VL8Jm6pu+xIjaGeNK1FezmzgjQUZikfVMxNO4WhNorCrW +2gW4KZCicJKeCNAVeH+YaFS3LtKV65y6AhEhlb0UJ3J17V9n3xqcDz8XxoWpZfLa +r8J2dyRo5V4xVnIVEW6VSk7Tt1KDfSJwCpjShFvohCJfTx+8ChWSA+vYMaL46h2u +z++X/619qHQecEYkNtdvf8y8ZoWxS28VwaCLu11+Fk9c5t8xescbu9zCc9n/Zq+H +CGIItG0n5e/+/pXzu3ebOhe++svrSftW2+J81Db2gcpQoRWNFFyM10CQcWH945zy +PCSvq8rJNYkBIgQQAQIADAUCQgSAIgUDABJ1AAAKCRCXELibyletfNQ/CACbELo5 +sO7URXktD83oRlDXdl/YjvljK+3qMwkZnZ3xHpEU7rB8Br3QNb3ocwD1rAV70WCi +uXJrKOXdipylDmAESUdfpHMiyBgmY+LM61hnClFglOOEQQ/thy+DDvDdJudLOQPq +eCSgFKYfNId2fOjixgvPLKXzCvkURqD7mta/ugv+xoeykZx9LheLGLNKnWtGVoVK +omNDmd7p+SQuhVhslzaGn9Q2uoj9+9CjlWzOZkHnTnKC5RpEu8E2mkqnnWbppRvX +U9z5NRsDCOTp+8jVXVfeMrU4Bmlk/uS913CaR2LUJj98DzP92FEAbDfkgrCgZ5Nm +nrvRo4YfcIUqneeoiQEiBBABAgAMBQJCFyHwBQMAEnUAAAoJEJcQuJvKV618jl4I +AKU3ah8HL7XgRIgBHHO26hkuMZrsKA8ay1x7ILAsWhTa0+ulizV4XSFRUFT34u/p +RDsuowWpeQWMGkzmqLp4s/0B7W4kMdvrUrd2ZwuewNMBtDNrJfPpEdM7oVhU0mJO +nJVr1xUL7fvzGObLAWaZVNjGfSMlVBZiGB9a4Hj7owX2hicJ1VuCp5owI2mv7c8P +cuOT61FUv9YnzJtaH6NYr0xFXN8AiM05vOKbScYaqHuz137GlXyaXcMTrHctzDzv +REcrI+0pi0xTveCSJG9S5UvyXjCA2TqzvUg+eAJBJal4JCggRDia9W4v+Oz6JJ34 +FIEV/MogGAqh5MibbLYNkO2JASIEEAECAAwFAkIpcDkFAwASdQAACgkQlxC4m8pX +rXyOZAf/dTpRVWCW3bh+X7z/ow+MNVgg3/sAuOlZtJEz5I/KUKFmArFOrmnhnipV +sUMqCsFuGE1l4SznBhjXF0nnySj8yTbH/HSu3eHKmYyuMRXsGfeUwOopdfb/MGeJ +C0E+gmx/ySf5KzE91dc4pA7puAPRLR19luBtQ4bSE1fQ4XGoD5uFVFs3V2ZxUpZW +NwXf4Va2KvRK9jiu2fkBYh3ax11b9uV9Z6qH82Hj9stgh533N4vb3mf2xH4Yow2z +whldlboYwU2vMZmT7uP69RfWmM0tYNti9xEWxQhsYvQ2cWQqAb4PDfWyRPh5DEe1 +mySXhDiWDAYbYZkxZrxNHRmDUTK54okBIgQQAQIADAUCQj1OMQUDABJ1AAAKCRCX +ELibyletfBbtB/42X86Wv9PUkloVRQ1gGxVrg+b4kceZ3EIIyVVlo9UPXZLOMtyj +ApR2ledGjsqMctcrlimgm8/WqhAZYiWjGC1F6FI0izjC6H+OwkcdaUiyb6T1T2cA +2YoBcWurX57POAkIWTYu5Fz9jndmxCxgXEIf1hkF10p49IQEjlw4qj0LVNni2vjW +EVd9SJXbK6f3/vwClUzMKbdQwUxpFRGQATiA8nN7hiy2TDJWyovWdNBD74dRVZf/ +cNsax2Z945+sRyf+kkp3SDKBSc4rbLLxDhSo484Wo2116TqJ9hxmnlWnnc+QDs3H +QTUtKKmzVlffN0PaqS2p1fy0LcgdfDZoM5v6iQEiBBABAgAMBQJCT8VYBQMAEnUA +AAoJEJcQuJvKV618etAIAMhfBn1BfcSBJV4hRhl+cjSqFYBRDWRim39UUvOHfW/A +rprsFLC96i+K1u3wGQZGv3t0oN1Lkq+z9s+CLTpTe2lSZwgkOg15c5V07Hkxp+GX +dmaungouh7y7oNg/xVULA1nsmanwEvXKs5lwRJ6ggtP9dmMXU7EMPiESsT6jl5qC +a+wbOX83BWrCGgqWIJLjUobX+D95sU+AfKAgKIXd2h1K8L6sMFnq3ANUKywzwqZz +laoz6XiK6HQMb3QJeE4w9/XRtIGW1Mx9ar8GWXP6cOoG7jLQ0g5+Fp6GciSK8XNc +A3xTotpwbEnoVqs1QLIiHZH8cmjIphrGnKJ9c8vtIYuJASIEEAECAAwFAkJiLGwF +AwASdQAACgkQlxC4m8pXrXwf7wf+LOhShcZefh6Q/VfNqtRdZEmFozUPsC3+3da0 +r9evprnRo334MJLjSRZH9F5aRwomSbUOl5u3Qqkk8yAsSt/O7qt7g8OQrjrM7rM8 +L6uB1OK278KH5hvHbV7xiHPh8TOr0FS9x34MNFX/vUCZjf67lKeMgHGzDTw0BfLW +O12x4Q42oF8JEuBDMx6XjrFF7W432Bu1Jz5lolvsiL3PUZhzb3RF3hBooQoFq8p0 +JSRkkAwR9s6w1diknREIMS4MIxzKKVTEl9mzhFR8apjxseu1JO07NY1Txjlvs+Gq +iX0RTraAMnFgTROnlNNmFO6JiVs7i1nw+c6h0+cVxypg5H9vGYkBIgQQAQIADAUC +QmLU4wUDABJ1AAAKCRCXELibyletfIQZB/0VDAZSmaTtv1wkGB5AdXHJWUamG5BR +uaaYvWmASowFTJfAr3jvDUjV+4PglBHFDo/wUam5UydSem0O1aQEjDmiCoxHkIKK +s/k5+8W9pffTfi5BjzdeM3rNmmBQ7NInOlJM43drLlJs6hTQK4N5YSv0PC1geLf3 +J9DCcwCQK3xt2xObuy6IsVYb9phhC+kvYndYkBaVvlPxh6m0S4ZEAZq+/i11MZ1V +EnSfe6h14n9mCDi2hrCUOjRCy0eHTIAeaGmSFTZmqDlUCX4BdkNI0YvvtJ/NCg9P +dNvlNBPxPvJl43ntWkoBJ9r2t004fLMkkSKf2cVNg+M/PWDELvn3p2h+iQEiBBAB +AgAMBQJCdVXwBQMAEnUAAAoJEJcQuJvKV618uD4H+waCJjvMLFEHhtjwiZrm/Qi/ +9l+lFDDhnzxEsRS5aTV4JGju49s1evwwaZRiwu18U+SFsFfmgKPWY6Uv8AVCsEO+ +nkV106L9vAKRFyMWfwVNHtfvNuauXlHg73T1HypkUkTzeHbxTO+5rjeZTmfXub1R +wXoJOzOFeRa29c+RSIfz9w2/5jFh414ge0fy9zvlAdxkO+/gSVAn4oSOh7NUDcs5 +dCautjvjO3O9VFaus19WbuGHCDKyeOdLmqSmmkGuIQfmRRXvTDQSNc+v8hNOBEe5 +HwhJ3YbR0a7+wLEELYG2KylmSeCMQQsptIhlHDKgpp/GYqxayPKRRgmdLZyelmSJ +ASIEEAECAAwFAkKHJ5cFAwASdQAACgkQlxC4m8pXrXzbKAf+NwuJ/WPR52FKUIIJ ++kKmMp6Z8wnzPfiFS6LIh+D4cn316+X7vFQVH2p9nj/M/ZjkntSswpBPJSgaBp+4 +AhdjGJBMBn4zX3QjiWQiROfglKmGtIn9g6R9zshCEB4j0RQIHsD84Q9QuTawS00l +ak7iELrPF+6miwx/b/I5zMURbKkywr4fNkZGjpbeHQSCWy23Z1C8c7HqslGDMtI9 +M2J8Wk0P5ymGmB8qW04YcASPbPL0gmED44wm+ja7qCoPj/nNe9dEPkebpq+TNB11 +lK38IQdu7wdnpCshK26HlpljvZSiPnorXZg68a/041772xI8LO/BFOeOoP6zdmtX +xO95DokBIgQQAQIADAUCQonQ8AUDABJ1AAAKCRCXELibyletfOozB/4toUqvgmRF +90fqpats8Rvbe+cR7pwEa9GaGci8O2+UNDjfOrIISJDRbj5v0RUgZ4WBuOWJPGme +K3W3jGOvBvdIePhUm12ssSCzVHX4wX7blwuvdyDDuoVLupgHb2Fao0nAC165HyCJ +e6hLFvcxOEe2Qm7wwM7p1r0gK5Pz2vmHdOVJlXfKqfvORLuVpFgZPgaCDTaeFnrd +RtKMyNbD8hEoGGaSA3T90GrYsTpE5b4/Rcxh7858PmsCfmZILEZWw1VEJRll27rx +U77wz8Ph6DpkilEXmvfVbGRFB7fKRe7NgafJli7Y8CEMrX74eonREmXURxZpd1ef +9iQHeMsp/IKWiQEiBBABAgAMBQJCnO2KBQMAEnUAAAoJEJcQuJvKV618I3MIAMfG +dgDEWGEWzD9PRWBNWOtUwiq3S2/UY7XkgJioGpooXa0IM2YdeyJteqxpXu4JyUjM +uq04fKtZsRbfjB9/Vnv60koQpeGHk9eUxoZyxZ2zm5RTfUfeTH2DkP75Sam+xozl +JKe1gF5miatlvdsJFhopF1MC7lZtaVqQeXPJeTyfQ6jgwG+ODlvClgTCdDqJiFC8 +H86hOWZzHvBMUSeoXhAFiPN8fRhbISyKC0gIaFwYgf+o5PsaEn2twsp7TYpicYsU +bQSJOp3usXuZiVV5sMpoHZArqJ7TUYpLzOKXESyFKhqtNH997Oyw1XPTmATLNF5R +yZ683R6pz5H8HeRwg8uJASIEEAECAAwFAkLHef8FAwASdQAACgkQlxC4m8pXrXy1 +TQf+IQKU3MsBcQNKXW0zYh6VEjCnqM6W3S7iDWRMeqJ3gQgMMn7h1oPxkLMILvQs +YqSF5l//KXm+XdkJ5yBjVUsJ0JVYFsPM419Kn+AW/GQmIqgmdUdA2h04eqozv22h +swJtLNQH48rPnngHv/j7F7StZzeb+Fnem7WT/M/irHj5YBhECWj/lJ8eYKbSoL4P +Bk/0iOuvQZqITVMktydHF2FPL7l6rpvWyqSA/fN3AFd4/K12A0KfsMhkqpt3O8vi +/S6SCLztDZji7+gCjuSBMebHyP9zGOn5yfz0gEeMkxPWGZ+h0xvCEz4CIBuWif7q +gQ17oQsr6kpcuEYBt6d/yscIeIkBIgQQAQIADAUCQs6PfQUDABJ1AAAKCRCXELib +yletfHY6B/9ecRERgal/ZY9RNjSy+kK24gihEpkxIcUgSlVfQk4V2w7R4NjaRKGb +45Wd6aeNwsFOx2kkhO52duTMj7ltPQ+mnPamZMHE8pHvWo98RLzfoCK44hLmqzev +Hn+MkmDmBClt9cJ3GhT9xBbbH77EtPQxN59tJ7eRgVB6FieoIe9Qh/aDqqkgG4fw +tAGqYoisF3BmVgxizwyPy+/xtzkF3s1DUnZrw5LiVEB8p+gk0QKkOhVnRgUwWt4M +uB3kGSZyatiAnC5mkWTzwFgnq+3sbqS7JPfvYezfLXJYIaXbs7s6XAt1s7pCFNsK +WEYFZ9rINps69MLEpvfQ3to+kKNjUYYfiQEiBBABAgAMBQJC3/FcBQMAEnUAAAoJ +EJcQuJvKV618foMH/iRUDJrDwMv8YPJYdTp2KWaj+vE6u11DKFeQ50cJ8CVAllN0 +ckjLmkEFA2gwydgcaivW292hVLS8fioPPONaXDqwQgi3tjxZRLfOwk0Fn+KW8oAd +Qpkgzf0opmR5/VWeFnFqXd86b6E51yTUo7uaaMivMqOGzGsSMiMeyJqImELyNirK +XDO+Uoud1az0SWJvDZht7O4VmblhJq2XvHWmnS+BeFCTlUxAjkcWIxyj1yc1h6xi +655gTePLkrkvtsKOHuuazk3yD50MYr6Ssl8AmoB2tL7UftKmxC0FNM6jktq1SfpG +PzotLJqLIoHZmN8jSu/RfGaZcWXK0hcHoUzTUziJASIEEAECAAwFAkLxvckFAwAS +dQAACgkQlxC4m8pXrXzQrAf/RB68ayjn/Z2kRL+c6c1SEk6OWSRSXdK05OJ+tcax +c0X3gI0aGmcK9OyLkgEr3NZKyswJkHyPp9+fGrFaXau2vk4gp7b5qigMnHzmpIzr +2o3Q8ic3NsBR7PCfOy96eVUodLLHdyWVE2DpKb1N7aDNs7NbFfSPy3Ihx/i3CnVO +HWlPEffHRsHS5WfiEBv3sV3+XqzXvGV5TXmO7yVTxgoMjud1mC6gvbWrUCZq2FGG +1YV8hYn4ueNv4YL/ow0efiGg9ipYknux+DsFkZRz9+klmw7E6NacFlms8yWYIHNK +7HaBZ5OEZkXiEhGDryZxgdA4jiQJMca1+WaIw68lEGv9RIkBIgQQAQIADAUCQwRQ +qwUDABJ1AAAKCRCXELibyletfGfUCADJ8IRCkVt+GnG+nIXx08nJ9yXZ+Nj4jAL2 +pO9vSLKtKhzSavEzFhv+KQKbtVJ+eiA7kPE/LW36B9lYOeHqHeuHXg7YzjcTs92d +30PlOFh36OrsOFiHV9MFGi+GZyj27Y8t0Bvyq9a1yHdoV7rb8S321lJD6LRcdgwE +ZmPWQxHeraeyjdrEJjeotWFPNE7dlDfW/m22i7grZkCoUDzEagBYQ0WeduTdyWAK +KAKhUN3PX5rPMCD+K7EUdyQC6Z/PntWIUMj/6yxCPJqWTjiazVny5t4m9Wbs+CkM +9cHTY6+SPZZntn0uz+XSGREEiBblZDJ6Vpwvu2E9djL07qkEgTBgiQEiBBABAgAM +BQJDCEUCBQMAEnUAAAoJEJcQuJvKV618NAoIALT0nK808kOssfi4u24jKbdlj8z7 +GgzIj00p+dkd/mdzsZ+iMyaupuIUpJeew9ILL1xzL49gcl8WCm9Dn2MinlGblonp +BLA+DpYyZ1KibneATLSLf9HQY3evakXri6JLIlBacGgQaquBfCXNCRK7r5b5E6to +9rkZKUFtbIENwpNt6mGIHXCL3IOi/Efygpb6XEvvFd7krcS9EV6ifMcpIgHvvtBO +KnEkYoUvOmO6iJZhse+qFezqV1qM/TDLCKrp6MUdaCkJg4KAlz1gJ7pZERtZrwSf +n2DU7XlJV18w47or4L2UZGMbpswz/ZkiR9HbcYel9wnA7xSHDVrlbgsXgueJASIE +EAECAAwFAkMQ1jkFAwASdQAACgkQlxC4m8pXrXzaRQf+Pbmy6Ea7BuGlJK/kSJ3p +hukCBZtWG6s7LWkcVY5LRGsLD+r0SUI5azI4CMIII8+fYqrKupNF8v+aqRqPOd0+ +DH1Hx6zhgJoyT/BfFQ3i8HXoCC6TkFz+swXms6zRivpiQ/OFX6kTEd60+26tCrO0 +GR5NFtcfftzLsyzVJelO8Oh9pBXmVpOU7J+77r0vGnOJwYHaWnNJZFMMW4yzcFzN +bmxv/+kfXC8d9HkO1ITEq+ofbr1k7ZB1m+0Zx93j/tl3W30fybw4JE+1BAPzpjUb +SYIQ9OFZ9tk64WQn1OjbcGZOAET5aJDDuTokPQNCbeDxdnxk95hABXHFtjGTwqh+ +SIkBIgQQAQIADAUCQxInrAUDABJ1AAAKCRCXELibyletfAosB/9CDRnWg/UWwQJD +y9lXMmvV5/TRn2H+8ilSDH7isjTk7M/6EgxF6GvFv7VD61XP9jwPCdQPYqQnIVGV +1aVp13EbPAfZNpEYqhbaEgnHFJr2fdj+RFiTBgl+u/YDalgEBdRfOA8sXjybhPr1 +uar2STkoKeeaLRrTth2WDTdjWPgp4lHkkwHscrvZnz3U5BaR5H/f8lBPwiA+ZtTi +qMUaSSQ1fRwO9LIG9jvtLFQFcKu2WIgNJVtM6xIT7b1uvWxJ92JvcqRtPcmiNdeO +zaF0CqR0zItRDaADQ8PNi+ysr9eW+Cdyn/kkrYkS/X2aWy7Mb1qGoADvx3Hn7Vgo +9cgi2JZ2iQEiBBABAgAMBQJDFCO2BQMAEnUAAAoJEJcQuJvKV618sSQH/0ZgeNj5 +q6MtNklQ4T91KxHtt4yLYe35dckTObnrujd/tkPTyCGDfYyNZePR9jNpNhGZT9I+ +by37NgrqLv8zwuK0eoSHmtyfGvnRGln943elNgNPZ/LZxGYgazBW0pMXtF6efyL4 +EKM+IlhaZzDjsOzr4jI6kjtNoNH79iukVTDWCxEM7L3naX+ZMIzohIAooQRT5mFp +Vyn/U897v5yOc2w9LN6/XDxh1UYekku5nz0j7iTRMBSlmEW4SRXkdh6MG0r4ME7a +LFDz4FlCgfdfLGBa8ZhH2P77c34jAFb2KMbIY/3vzsMGmiwagiaga7M3XaA3YzaX +UQCq6WML4/uoVGuJASIEEAECAAwFAkMWHdMFAwASdQAACgkQlxC4m8pXrXwPpQf/ +eGCVghsYAn9yOr5oaKMdVcwmFwJyDkEDixFUhISwhocPrlZ1VKGhIc0GGiOW/YPh +H8kigh+mfjjVdezATyKzlhzzW5QhjE4VojhJZL0Xl2ZMhcty87xlLyxE60EyuYdo +riJv1zIozR1eNQcdcW8zTlaSwt8ezfXxSX41PecSkz2DLZL1Tjs6PZP1TowVsf1y +UHD2jXAShKLZEeqDUBq+j8blPggQe9AzWhKyZSlZBOYqaLt53ipe9P/OiyxASyi1 +AlgIwQ9qW5OrHLx4zUU5hRgoj9463/l3qzCpaOSrwIZrxVOLEe6fYcnoV9qL4dcN +ekqK2e6ooYGM2dXs2a4FjYkBIgQQAQIADAUCQxdvcQUDABJ1AAAKCRCXELibylet +fMWzB/wKmO2OCx3VXvHi6cIaRaifMyIjwhrjECsNqSiJmSSR1OlqvrlqAPFau4ee +sumnCXkti2G0O90GRd3CrwBPjzQr2UqOFmNBeL/QWsxIZ50pKZYJtCRzLVD0RxQI +4tjyAEvpkf95m6pRvoe3eBlpsDCesgLjHRJ8VJfYwB8O2yhfTXltKcrFJduWVR9A +p3DJVAU4+9WjVPLf6XnUQa2eEoi7X8cpeVB9le0grx4hMD8DU81lz5/EkldR9lbb +MqI4wSpDExKzRi61RGlMgyOBCGrtIK048h6l6OKXv63O9efh6c+FQUxlg/0eL3LF +UhhLRhIOhdSb9mgpoWL45KWWIjeGiQEiBBABAgAMBQJDGMCcBQMAEnUAAAoJEJcQ +uJvKV6188xoH/10HlG3nw/NluH9GAfR3+j9J5WCVw17gJvrexaI/glp4nFDqN8fY +cpBeyksxQvD2wlRp//lcIBjSsa0oXA2CxNDY4ITF6mV0zPnY1wn1r8WEDW6oaNYY +Glzvbe5nwB/aYwILV45I0eEVyTGtNzfYizU0ic1+M1bQMZunDE+HiolieDEo8OHc +4XaTj77GBPHAgdpq19SLdTRQV4cDD3u0MwIQNJQUeDN9QalFQRgEZobUwKgmI0EV +uyWvw7T25n2SOOEV9IgvxaFffQ3E2rWpGj+N1DuDR+Jpq/bovoab9JBI6rZjtzhn +V/tEjM/82sGlnZLt71hH5hoi7fK4bwG4p/iJASIEEAECAAwFAkMbYtkFAwASdQAA +CgkQlxC4m8pXrXx2UAgAyqEElSxF0+x/DbJbE/JSDFueR2sfEkkbbtQc92NnKLC9 +F9yYtksWcumgbQNDvAhwMFaV1s40JozemHbWtlPWdJaJP6NC/adiMOkoDpAk6mq0 +F1Ye8FFhR68DKAwmt1xikAnYxLRxFiZ53cA2R1oDZKbKo58CXTh8eiGTAQdl1C83 +SyUxZhTYQXFRfYThLG9lZUdVcMiL9EaPj2gSLuqRNVF+DB7vmCxlCwGpAgDPWXsl +Nhc3rHEZR1kthvSnMtmbeUggA1R6pKAwSydnH5oAVDs/stEmwyG4iHgpfXfjUbDU +t9C6rfMSWdLn2Q9z6omo+Gh9quWLzhTaVQbAiaQJ1YkBIgQQAQIADAUCQ51L9wUD +ABJ1AAAKCRCXELibyletfDWnB/sFi2u191JUhjvjYa0JjykPNmm3uLMAUEqmB7LW +rOdB1CyjjsyX8jKY3EmLJeLuIfAzfbX9Ila+jsKFUBEBLPuu4yUxE1ZwRrwTYmIO +CjTUj6oZBbM54mwChr9hnOP8M3NCstqwxmNORKAlYjFXiDrwtjbQAFaN2M4yUq6t +ZXmrJ7y5kbWjp3e6RUzHxMMCOqx4g+5zoYAqwzF4gBHXueprOthWwsBYd6RHAwxm +GjGdJ4dVXqOOXHZQVbE1Tr3Fnd9AAQbYc3zS7fOyqw4Gz01xxOHyQTNbDQh0Y6MJ +EWb1gJgdHNYUbLbQWUggV9uEiuMbLJsheF9ivzL3eKlERGrGiQIcBBABAgAGBQI9 +2AXUAAoJECQOZvzFnDJwGGIP/1PlTqOdNC9+HmJmopF+H8Zt1F28fwiPRDbj2cXF +TFSlTCpOOw9xstvnIJ3S/Gnk9ywpDYBupdY/04NHaU7U/ECNyuGrBXIHI5IOP3to +1GPVMJmpZtGf5nAoKAZYSOh7U4qw8wxkGGJlpyqOGkERth11ePI0xfvj7hu3BNwd +plgGxwKnX7+iMcmPsbNp7fUN2fSzf1mXEsUXtXoVZHq3oL3pDlEVqO8es4jzrXAu +P2tmEbZJ1Uo96PAx9ZFAJTgpQwTPmQ7eT8iFkm+T5x0JJbTLYjH2UEuU8Sy8on72 +hqCVHk84qgAGoaHehMapbi3bC70j8P90iRAAA7gT6LbI9SzkarqIljm8ri6lHWAT +zYG2LfNnnoc9gDKrRgr1S4jKAeJfZx9kEFDShuigLk2ZLYlhZa0xOhXZ1a9wis0d +qGWpkKXbAfmxmduGwAZBKRzQV31hJZwzmy5ms9wC0AxbZ1nBcuui2/rZP+/YUn22 +nUKhKc+740FA0KtW/CusHzaydDucZuFKn8NyCXSOLQhywMSqJvj99AzQWddTqdbE ++wXYVIDv/eqjwQK9ud9LkEm01eQ8C3kL3pwLFaCnJpQgWTmlTCGN2p9VOyls92xZ +riWqTbymxL+fAVBhbVqt04a7WLh2QrLhprx4o8Xb+Ff3P0Aj3KagqKw65+zLlPNg +2T7WtCFTYW5kZXIgVGVtbWUgPHNjdGVtbWVAYXBhY2hlLm9yZz6IRgQQEQIABgUC +PdguXwAKCRC+uiuH9fxLQoEwAKDeOyuAKnQB30/ckE7HvxrbxAVuUQCfc+8nIsjR +KBhH/hje4erxd94dfdaIRgQQEQIABgUCPl6u1wAKCRByUICfrImJTK99AKDeKtU9 +0JGWdhicBynVCbla9BJJPgCfSwaHeHbh4ykh/dI/6FtJZMgMSESIRgQQEQIABgUC +P8YeywAKCRBtC8c6QFgYN7gBAKCCdhyZ6UlaV/KzVsz+GrcrvL/A8gCgiur6JvyR +KvoW+Kpq6ZTcl/NdKcKIRgQQEQIABgUCQt7MJAAKCRDKaTl0gQOjfms+AJ4jj9/I +EH/soojR0evX94jXKZWOnwCbBmr3rIBRRqgt7mX0dg4prZhPSbaIRgQQEQIABgUC +Qt7XMAAKCRBB6gmgV5NJj80dAKCuVMmBoPLMrRP9gB3QlVqXa54T5QCgkIUHHvUp +/ITZOhReHAGu/uHnwDGIRgQQEQIABgUCQt95KQAKCRA5TS/jxMV7Qsc5AKCTF6GH +qSPq5wLMhAISHuhYD09iVACfenUbbq0zgMkc9ccpMY5zHgkAw2qIRgQQEQIABgUC +QuAECwAKCRCM43a4HNSGH8IyAKChFbf/ShaRuVsHFTQgMhgs0zhqkwCfV1UIm5Ie +gmshxV2HRQa/uxz/WN2IRgQQEQIABgUCQuDjTQAKCRBhGWouMz5OhMuAAJ9MUvWr +7ZrfY9WriHzrdsmCWfT0NACfePOOvTtL1xhykbup1r25iH3M8nWIRgQQEQIABgUC +QuOjbgAKCRAEkTRC6hujjX6bAJ9wp3Kc+gRbmrXwyoPtokmvqV8wjwCghgcbhAWZ +ZrifqzmJyeHAXlTF5yaIRgQSEQIABgUCP7nVRwAKCRC5JFKsTJFltji+AJ9LodYQ +fzjgUAlBc5Lr5alCA2pGfwCeNDeEgsuI193es2lWtg7uNP6ugp2IRgQSEQIABgUC +QDAb4AAKCRAui9CAzGnO7X5rAJ99DwRiMfS6GIU7vQG4q/i/DNdY7gCfSLfdDaQw +U6fdFJpHewxv3N5ahm6IRgQSEQIABgUCQaB40wAKCRAHYXOxkoTEUuwIAKCUmpaL +wbWNeFUUvQLG0RlOJ6q+UwCeNxnHUO/YnyHUYH5ewQ0N3vxbPWWIRgQSEQIABgUC +Qbo8JAAKCRABBWa85BNjkpBEAJwPdyHNU1xrb3oaA2vNcft2vVt9/QCbB3vCCkmR +NgKKRrby/Sa/2lRbSZiIRgQSEQIABgUCQeL6rwAKCRBMxE0AEd+H6acxAJ9zoTUY +Y36FWE4TU0lnKwxsPl9hTACfVjDF8K2pEBGv2IHIqT1dCUiZyMuIRgQSEQIABgUC +QtvJFQAKCRDNU6Y9XOW9+UMcAJ43jHZHQbsKHVDo+JInoXsHZGH99gCg8CYC+Ay4 +NbfhqP/ZXAnR/wvzZ12IRgQTEQIABgUCP7mjxQAKCRAQ+kyIpU2i3wAmAKCCfbhc +0qEIxg1ZHV5GiwmCPdOZ9QCgih/5cb7ITRWF2A4Y5xfHKHZ0mN+IRgQTEQIABgUC +P7mrOwAKCRCoHuZJzhnVxg8uAJ0ZbbY4dX4daFklblFQgD0ePeWnCwCgwRZ51j7X +VcLR9BpYRudX+tWKczSIRgQTEQIABgUCP7pplQAKCRDLMqEHiMOlpa+9AKCRE7VC +kMuR9QWdtb436bvb/wndfQCgxZjT4B9V8vSpZQJZ/UOobb1OQnaIRgQTEQIABgUC +P8FRcAAKCRDMITAgodaXWdHuAJ9HYUpq5RufF1lTnddpTRLshynqtwCeP/XM8oMy +7P2NtcFvVPJ1xp5x7laIRgQTEQIABgUCP8IgAQAKCRBo64x2+OopZ7y4AJ93S0xl +alQEV4pMp7g/itnNH5DHrACeL/p5WFyXEP1+5o282/0I+LTgYdaIRgQTEQIABgUC +P8JpWAAKCRAJWkXcoR1W+zLSAJ4hEAgh4x/7tVgi3hgzHtrQ64vxTwCgygGKI3i1 +lQp/YBbB4e/4AGoxkz+IRgQTEQIABgUCP8rmyQAKCRBoWnfK7lZVDjOmAJ9R4rzl +F9bKpBAMXPabmarRjdD/HwCgiNg28b410LzfIDKOJnt0QCa6nG6IRgQTEQIABgUC +P83eLgAKCRATLknU5B7cfsSCAJ95IXTtBM8vThylDXOVL9LiHCYq9wCeNhCk95LL +wLeKOLr3s6koZu0V3CmIRgQTEQIABgUCP9DPIQAKCRBkB4bZrb+eGqgTAKDKdIqU +BMDKEeCtcB9MUyDL5eFboACeM1iZcFzDRaTY3Ranhwz1+c4E0H+IRgQTEQIABgUC +QBXWNgAKCRAVP6DNdaZ2knU+AJ9bUKVBDvBvxqY2FV0topYLk8HmZQCfYmTmom5W +jlE0huRqVSwZVlqjs9+IRgQTEQIABgUCQZomPwAKCRCLOmAfCMl15eArAJ43/+l6 +PEaGUBFsp8YrzbfVHMHdiQCgwP+Vml1o1n7sNAoXqVvd/V0uR0WIRgQTEQIABgUC +QaJZhgAKCRAEl9WREr/nmpIWAJ0fW6hLmEzK9Drq+vOZ0MhBhA4IdwCgmcXBPOUr +nS5oeSqnZ42sUn2pdeuIRgQTEQIABgUCQaNMLQAKCRDdumS6LDEtL32RAKDdkGB9 +i2ovz0P95eYVj+rsDVrwVwCfVNAfaui7J3vnSaktH41hmJNofIGIRgQTEQIABgUC +QaNNTQAKCRBQjq7FMC2laC3jAKCKqmkTFCtZYo48RxhVIz9ZlknvfgCdF7iM2CQG +yXiUyZiu5MHQVWGrJe+IRgQTEQIABgUCQaQwVQAKCRAXatnI0aqJYm7xAJ9W0E6y +lHJJs9rAoEpoMb26L78OGgCbBPQ4w/yl0xMRa74nzts/5h4t1X6IRgQTEQIABgUC +Qt6zqAAKCRD9b4jGIdCnG/BeAKDdD2aIYDfx0cbsSd0p60Znr3UrKQCePxilDB2y +qSY1OWjKMGWQSqhCyIuIRgQTEQIABgUCQt++hgAKCRB1yqKj85s3UCryAJ9FWfPd +TSG6x2rN1K3WzcaoF0s7CwCgvKPLEBi08ma/LoWoG7G4gs+idp2IRgQTEQIABgUC +QuC/YwAKCRBc/Tf6zHjIk6WpAJ9ZhosB5WI6ONvnx1m/5KEj9RnmfQCg3mh5acTI +2mS/39ui5wRGnl39NdWIRgQTEQIABgUCQuDr9QAKCRA39o/1AVr8in3AAJ90z1Gw +Mxh5EaLeUu8E/Er4k1LVPQCgqwOAdPxFkw/naKelMTbliYnUcWGIRgQTEQIABgUC +QuDscAAKCRDJtabs4td030FeAJ445ZEjGBYoYNuWS8hQ6WgCQ4Q4TACfRz3tpfef +mPKZna6vmYaDD0lEpniIRgQTEQIABgUCQuJbhAAKCRBtmI0XhzFcMUQyAKCkbfi6 +QzywYkun7jmP6KaNlTcTnACgntvGL3c5aFmH2Ke2PSDsAVc3ZwyIRgQTEQIABgUC +QuUQTAAKCRBSeS+vmXivhqFLAKDaVTiBV595s7aeM7lLz97Rpn1DCACgk6q1pQc4 +4hYRtT5zV5xFLYtDXmmIRgQTEQIABgUCQuURVAAKCRBrc6EGKmI/cqcFAJ9k85+i +THVhkwLmgaepU56eNWUL0ACgz0VmqUbXaohOF4rADUrMTBcacHeIRgQTEQIABgUC +QudgZQAKCRBulHWUwVJDGqelAKCi02gKb31iXgfM37bK/1qlBc0UpgCeONbdpV/C +F7WWGDfiCvexEgKxXwuIRgQTEQIABgUCQv04zgAKCRB+iDZMgoRJhJftAKCX44LR +nJNRvfe4R3CCSsEPkR1WbgCgqV2jwAmB36v0nmTqV+UqCjb5Gj+IRgQTEQIABgUC +Qwsx3AAKCRAhgklWzkGcj3bEAJ9FMr/qXFCNA4wWiqkWIzLSrbSFaQCfdnuh06t9 +qCQ9ePir7tWxrckmzcaISwQQEQIACwUCPdgoWgQLAwIBAAoJELK+vEAVKSSvoFEA +oOfP0FpGayjm5eLztawcHpf0aJ8aAJ0Qr1QpXZcaLQQxKpdihY0Ui1VhFohTBBAR +AgALBQI92ChaBAsDAgEAEgkQsr68QBUpJK8HZUdQRwABAaBRAKDnz9BaRmso5uXi +87WsHB6X9GifGgCdEK9UKV2XGi0EMSqXYoWNFItVYRaIawQQEQIAKwUCQsXxxAQL +AwIBGRhsZGFwOi8va2V5c2VydmVyLnBncC5jb20FHgEAAAAACgkQsr68QBUpJK+4 +GQCgsMGXlKvu5SQQEw7CsGgNfXRJ+esAoIAYhaMIi90l5PNZGUc2NCETzgU8iG4E +EBECAC4FAkLcsaMECwMCAQIZABkYbGRhcDovL2tleXNlcnZlci5wZ3AuY29tBR4B +AAAAAAoJELK+vEAVKSSvKZkAoJ6yA4qdcwgLZ7lxexorQoRP5sw4AJ9nncpWgB8C +xg3qWBiZKYCCsyyGRYh7BBARAgA7AhkAGRhsZGFwOi8va2V5c2VydmVyLnBncC5j +b20FHgEAAAAFAkLc6LEGCwkIBwMCAxUCAwMWAgECF4AACgkQsr68QBUpJK87sACe +OYKfuz8X7M6Z/q+qpBLa+oXBRscAoMmHtNcKs8Q8XNIJl6eGsQCTaXzDiJwEEwEB +AAYFAkGjTCYACgkQms08wKmfdd2LRwP/cRi91eh8jWk5L3q465gASB3FoEGLui/7 +9aVDKSEgj8sCm1spfxnaM/8v8cAeQpR6LeM8NZkjNWC2AnEviCmJ/S+DZgheMRZ5 +KjtV53a3EHvBb8bTDh/hxmzf442zWJny/q8MWOir2IgMIHm8B8biUjLtNEYPnUsz +0f6ofXYUfPmInAQTAQIABgUCP8HdugAKCRA34/Rf7mXjIRuxBACapj9ETTis4Z+j +x7yogTLUAq5nbZpikze1dHjlZQJlsAeT8+k72YD5JHs3Yzn6VAfNZrMIYUltEiAt ++krV0qhmKitbeL8M7iExT8Yj+o3oLfwxW8SWdTpALqTftbo0qKmZNOZpUVf7WIRc +5HUi8xOASQR4sZMknQJYdkcgHnX9/YicBBMBAgAGBQJBmYGvAAoJEDGmPZbsFAuB +QW0D/j3CmvYxOVUQ4wp55+7hKSn332g/gPyXF8WleH8KQlPXyiQ6Gyv3jPSt+pPT +yYv0Srt9Z7xjksOA/9AMSzzI8y/jNsTYqWRXq6NrvMLQJSp8XJssBRCfqdXpqShJ +T1JRoxfacWMWCshxCEH5i0iVFGbwU3IAJGUvlzsgWbhHe4VLiQEcBBABAgAGBQJE +LYhwAAoJECm4ktDIYoUBldoIAJ64qtJA2yELc8R2b1+9jv5kSzl5JrrzaWnVBRkO +M/wh8bBN32Zq+jRtQwaHM6mT6gA8DRWfbgBbkCkzj9jAntpa5c4bppwhKWlWE4cm +7AmckqKdy38hSysBTEdjOleaiUgeCRd1EzKZYxs4Jy7Mb74NKIBpNBMf6il0qlnx +U8yey49lPecppUUqEWUSyaoFtk5xXIVPiXRyz/tAIq1nQBpM37WtnycKbpaFh0Nx +IpKe3Zc/e5Belu6nE+n6mjnRILGSdfwp0StfVp8Rbu5puezdRnZiFhihOCRHM9nl ++PegqEdOVca7/r2UnV8IvMRpqbe+JWy2uxE0FmeORcoThbaJARwEEgECAAYFAj+/ +xj4ACgkQBurPqnbYPMbReQf5AbP/woIpPFuyj/VDT1JNfiCyNZTsjHC3sQhQhhCe +xHx3GvW2h20fO0AAQMUlUx9ACCvCksTAWrMTHpy2N1AiGKr+OcxvlP8Jij6NhePH +m65KFmAG0sODsPGYk1g+3Qddz4ZqDaMiWfQSK1HpLoOgX2PUUCP44Y6AIkyu+hpA +KenZfSxYJJ1XdEDSyypLyBVGz86f753XMspw5veK5WyjMZSvC6mwXxt0xynEi9xH +soMWHd0/4V5tRNQ4ZtRnRsVH37fVEEAdFCIJndudhsVSyB8uOZZ0pDz7RzvkQUyh +ddveb3kSt12GRC1+Mv1KVQ8LC/4k+26KKqNopRkcUtZa9IkBHAQTAQIABgUCQv06 +RwAKCRBcMofHMxMbZbB7B/9ZSFensb3pJshK31LYma6S+lVzoIkslWWAdY5Y+3EJ +9QDh5NWMgNqIwKHXIl9Yw5vrwlBjVTKTaKfI2ux9IBu+/aWNxMf/x92RjbxKdzey +/JzoO08UO3x0q1Cd/3524zQjmqPxiQDxrg6VXag0A1WZfVJ5iQb9xyKtMa7UWuDN +YOrGKjPMLhjfdy/3gYotVGGRxDHkJhA/FPwztsvhFFxqmy4mleiZJ0qhOxJXrdQY +VRz8JvGQ7JBKfaT+H4ufWQyA/iB9Qdc55OW1f1EaW/lm+DvE/KhEd1Umim18ssfV +8Z0b5h1rVfW4DYtgeTXQcHkV2C74czIthUjqucNi3sP4iQEiBBABAgAMBQJCx3n/ +BQMAEnUAAAoJEJcQuJvKV618tTUH/0N0C1910PXPj6XJoopVMnQlEVImNUdgKOE1 +uAKIVizQoaud9IdY/uXInrYVFv0z144vAtnO8DdjwvGhCKew4mhX7pBV4sYkIj7q +qCaqTNDuFmHfqETmha8FN+TQTc+WH5Yal5sF1tmvg/vYccOsKS6cPTVz0TSYfdKr +y2HY1RcC7N5ULugd9UvBdbXIwwvo3KfKEKOTWWyGATCO2KvbDljgb4UWwcXGWPBH ++Cj4VJZlpyfoPZ/V3m1SUOjkUJD49/eMInbxS5hSShIaU50nJu3e/4CIfgpoIM01 +7EBW952ZBCwhx0yRRK7SBjm8MmdsvY0b0qeodiZibZ0880mDm1OJASIEEAECAAwF +AkLOj34FAwASdQAACgkQlxC4m8pXrXwnHggAjaoPgU7idkAQPDsQuQ6KI0po04dZ +pM/flKDtTmwnN0fQ8itzouD0OLnM2d8ouzygQfQt+Rm1GtYBvCJBe1eqtt/Z6o8b +UDyUOnjDOC7Y0gPoRpsBPrU3fDGtEf1wzh1kKJaQgPNZjTvIoj01ssjswU19H3TT +MWxdyN2UsN+nIbDGO5uHg+0bfc+9VnqWvIDetqlkyZbRDRTbfc9E5hW4von3dWgv +japOAndjQTJ0J0xg3qrzcBaxDHloAoRWdbhc2B3HES9hft0LeNPkJRh5KumWDj+X +MY+LKWpxvQYYYoO11D+Z7m3oQtL2iqZcYuA9WRXBEQa7G/nWcjTHozIMC4kBIgQQ +AQIADAUCQt/xXAUDABJ1AAAKCRCXELibyletfMpkB/4ySlnhPSmME3pQLmRvkLC6 +w7opcP+Aunh373MSjXZ3w5WvrLZ5dWQqm6dK/dE+RIItVbU8NdgxGI5XHCTlTpep +rVX1RrHxhDn/yud1zCQt/M7sYxTy+/irX3JmMF1Iile/843rbmW7ddePZPJr+0qt +x+ZbO0ZNzBf4HqwpN6BvH1i94C9ZZnGKkFjibZDiGLz8toov9zA2yXnoE6H+KkAS +5ERjPAOFO3HHhZrzUOg8iKMss7ZrEpIjUeqtF8qQ9JFBcN45xoXfeKnqa6+YqBr5 +Gpwk444HJuEX/1MaIhtRgV3jbKl71bIN3tCx8LrNpjFv4hqFYs50lKSXUhuwFrj3 +iQEiBBABAgAMBQJC8b3JBQMAEnUAAAoJEJcQuJvKV618ehUIAK9avhT9ZOaXILj/ +5zdCrqiPtIqtPgrrhnColuDYvdBMieL0mnJX9LQ2ne4YZJsnKjVUFjLQ5XrkFZVC +o0PW3zZa788AMr4s/e2p0eKi51Ax09pqj1ZWzCAplc7RszeKFTJ3wfLEKvi7Nuyp +egZl9BZlSBkGG3vCa0BawpN+UsxQW1vIwWEDewBgz8z1v1hxqi95w8xQv4Rc+oD7 +etNSe4g0E08VMk/hI9IYkWj5+895hic2zVEmbCljy4xOTCg+wcjk+5jAQmkH9um+ +icNcjuAJeXMbZEKk3rfpCUXInGFsun3vx5gqbOgo3eSw8ZNeQmJ2NoglhWKacVIu +aynM73OJASIEEAECAAwFAkMEUKsFAwASdQAACgkQlxC4m8pXrXwACAgAh0R7uIzz +LXFWKUbrAR4eq24G3xsmp2vol8I81CwO3M6B8RFw6OP42JodSbC1KQVxtvRMHZ2m +T0QPspI7n8bdTsnC6nEbfpRTcl2/MulWxZzttUx8R/3yfH2O+pnqn5nk7NwaZUcn +wgrPSaOFoI7TLdjKI64Vgv0uWAAydaKYiV1/Gjxc29lBKqX9ytBNLP1tXfEO+Ou0 +0CqpMy8mb+zOEmlCavdpJlOVX/YM69HA8Dj9AwmK880HtPwZQNO+piL7tjftFVdq +GEr/e57X6VHsyEogtQ55356qhamzGlSi0U4+Lr+pANT6/hd3aj4wyisWk4nXVydb +LboXDMsnme8/VIkBIgQQAQIADAUCQwhFAgUDABJ1AAAKCRCXELibyletfEcDB/0S +0nfn0HY38znxIdaTrXfe9pSVDIti+6OmyePdHyLzvwkiikSdv1mq50szbiftO4Bx +LSeiofi8mHjs3D1VkugBZ/OtQQgiDeLIbYvmGhEifhsT64X6L9yLjyzzLk5QQ9wN +w6zHLuHMKhfDSFRo+6ogNY4gnz3sG6/n7Nhta6CsluOwNNFxILyvbuh+/ixjWZ0S +9VHUbOMLKUsbhDlc/FOwk70ivbUrjb/zDjjUnRNNehFmU604nBlLzoZCOgSTqbsX +rmwMD5g+YZ1SUzOPP7EhFUrjOsGEaY+pKPxBnHV/h/ltdERxWff3Ho2AzSxDlDI9 +DQRAJl+H8paol6Moz1p8iQEiBBABAgAMBQJDENY5BQMAEnUAAAoJEJcQuJvKV618 +ickH/3xmHRymPa605x75TpVqrU9ixuF9la3kCxN5kuxn9XsKRjs4qbciXzjmTcgs +LyAxR7K5xd3JTIg2Kk9HUXXL7eRTDAFWJtig3rqt8AxADz4gxGxEBJgNOgWxBKop +B/eMi7w0PS62/XBHlP+BQux9ltJEHGWBww6ARhoukMvqTajiOGLuIZsYzNo3Aeww +II42ITg7KMFd4rEmCuAe74D36lIFmW2EClSlpuUbCMj1cqbRTBT2qDtov3Bm6na9 +jYfC1hnZ4uXJM4heJCJ5ii1xn6CNHHYbRqikBDJ1YFt6xhLDSlpELNCzWVQ8F+Xl +LA2Vils2b3aPLxoCWYcTzd8c3GmJASIEEAECAAwFAkMSJ6wFAwASdQAACgkQlxC4 +m8pXrXzUVgf+OhmeGHeRaVfmSJJGdfAq1iddpKpXKm9ot388ayo0anEyazZbtFiD +C85iFqK3zlFiDhp8lRS7WT3k5mOhk++8kI9JSnwWMi7lMSKhtXgUeyBRJrc9GJUq +o9H2p0AYwf60AYU6kSk01HURpCyAn2vL8/ye9xfQ3awBou5UjZ0e+5pdLzanCnWL +RZVCgGHam+R6H0NozSE0hMkMEBYpbXA7HGPMF7G4jfF25NVMWv79zp2RYcBhcUQk +9pUcUHFhc0GRj1Sy8PwHdIIzp3r/vukxXm0SbpAFm5h/jtwX1WMfCrjc3bYn0gmx +cjD0H8u8MkvsqcV/XvjZA1KzeK5OIBWXjYkBIgQQAQIADAUCQxQjtgUDABJ1AAAK +CRCXELibyletfAvsB/0Zs82wxJ7Xsit/AYaRQ2E7mgJg7bkys7tiUWnbuqglJoYf +v26ePDgNaac+FYm2rYiVdydZrTUNVxTh+iEK3AA/38X6EnMaRc73ND7CnUYg1nKS +b9KeKalD5J4mp63n7QLPF2+b+q4V/kSVYDQj/tgCT0mP9n3RKlHl2o3mC0IA/cH2 +ZNYY2m81fXOnWeprgch5gXk6dD1CTWUOOuxXbi5//XWI7PMlR9ggcuob4jwTE6dp +Lv8cWjBp5SzYlz9m8zuTq9/Z6EJO1qza0nV1RuNl5tQWxAcZwn/3PhfNF0SvKlin +5Rw70WulWl9ZbyIrHjnxTAAXqzyxYJEfMInAaR2giQEiBBABAgAMBQJDFh3TBQMA +EnUAAAoJEJcQuJvKV618poEIAIzmlgq6FuWg1NYvZZF0D1Nw56w6Hom1OtLtK3/A +1r7/3MH6P48cPr+02AA+DWOcpmnoXH1MZp65z3CLXL0tfdsj8rTtxTbvVl2LKzyY +24DH2fO3GrYz1BnjxHtZmG0W6hxjXqbyS+MrljHFUf88e2P3k71X8kWEojfxFOjF +2i/G3PBL5OyeVz5bytZJ0xV07f4eDJU1vx0NXFH1KAGUKcEP2ZKbvSP9z/nHr0UD +orJaatXL9cjhy2B6yM9ZRvs16gAdkrwDlO8L6rkTGo60wveqNF/a8z/eI1WkHtUC ++2vN116RP5IehVHVn16luxmqT37FXGAnZQBmmF6z2hGSSY+JASIEEAECAAwFAkMX +b3EFAwASdQAACgkQlxC4m8pXrXzv4Qf/eJGXLm2kvhVDugRpBsepA1wRvBDQy6Cn +PmupTIIodC6v46ix//BG8o51k4skSQz4FRg66VKweDI3TsxKHfNZumywrtocg1S0 +os5m3pNV54uSryBxNqvkkjy6oL1d0fa/RJg3StVMCQAdDt3x6PvzsX9HpLT09SAU +QXS9ewmeN0SnTj8VpocMV+GDj5YvERbqJ9JcxPZ17yHjMkZguO7x2t/3JEHWEQBa +kGQqSP9kIO0Y5TCRAA6eacnUFlohzDpBQBid8Jh2kztFsyYxZ+01kje9Om4Ps9R2 +Pddo28mUKm6xk2ZstWFlxZtrb4FzYbMX04l6kh9odvCi54rgwJnyiYkBIgQQAQIA +DAUCQxjAnAUDABJ1AAAKCRCXELibyletfCtAB/wJ4Gpdxp5sGLPlNr2nU7ZF93o5 +4N5n/BEX0JtvcNK/1Hj3/VPz0a/jPLuicIK2bfl7oWdb2K0GOqXESLUova09Eo6b +f5aSzhpVnPQri9d3R/p4LHftmFhEfgQHD7xjFbXzI+0ZkThFX2UlrwGLiiFuvzoL +6ZZJK7DapTIy6xjkj/caAqiWGAwApOAGCp8O9o2GHJ14w9g1Jq94VcPml0XtMbKj +zxsweHlzHipCGkM/BTgZwbTM7B90ydYKmNWMDBv9ERjnqJkLrtMMXG+G8vd22iXC +yJwn5LhfJMgJ9WqEovoA+uOGed1TOIFx3L9kNoB/30Cmx+3bCmpNQ4EoCvVNiQEi +BBABAgAMBQJDG2LZBQMAEnUAAAoJEJcQuJvKV618kfgIAJu0eIaJ/n9ALsfb6RBo +xzd8V7xbJpVBtIJLyVtBOfq4DWW1M71vKfFRhmx8ijJEJ7ZOUwz5oC5/EECMIP2a +Yp+kZij760hPJRdDE/wiyK5ZWzg04d/rh1WGsaOv7bJzx6dY25RBmTD3HUD34Ezw +dlRMHSENTUtV9Q2bCsdylj3Jxuydtg5tDIFFuVgTt3gI44+rWHgzwXAlq1BLHwBK +KcMbXrJZWeWyTk92Mc5xE1n4rKK3NyFTyk8d3IpItLUhsCK1YfrQLst8IGPOrw+e +fbwT0G/l4CpBgn0TbPq/ceLaeRSfg2zY76Sxd5HRcZyzs4+wWbfNbi3spfLgDKnW +Vz2JASIEEAECAAwFAkOdS/cFAwASdQAACgkQlxC4m8pXrXxgTwgAsQxCeTW0SdEk +WQ/R4TzDtWAhx5Me1xg24WOir+bg98pq8OCphyRyAgdJF0Zq7ZROtTuwo3lEFdqK +xKlJVfVXZz9XS84H8MEeNqnS0iOEmNcNfYv54FCLTcy3ZgJEXfRpvb5+9kVnNInm +J1s6ylNQ6IdhqnpMaBf5bGCFQXg2oAVUDbQNyIOm+kbSNqH8Tl8mXxAcSUfvgNCv +5n1QmL2sF4w2kMXKLRR+juEQvUwGB7sCjnCXArzpNnxARoM/CK0zyUmyBCx9UIAW +t1ayat24KdMlH39Jm42lIxTmoFG4U2i7zQphoFFBLXLnj6tGLGZ0Y/aEwqJq7w3l +ahiwMBHJLIkCHAQQAQIABgUCPdguiAAKCRAkDmb8xZwycNO1EADCb6/ChyABaXjf +Kgv86eqXNe0/RiMupbzw5Ndg/g91Zu4GdiBHoNvY0SMjzYZjTJWWCR5+4S60O8v7 +dxr3/CBcJOnNguWsF5ACNLFhfel24aPAp4k5uq6XlG4ZOZd8nyWuay9A9UVTEbb6 +j1xsd+u5peaqq6wANH4jxoI0x9j6PPce3NJ/DaDjHhX/6UQo6SRn0hlW2WeDPRAI +b3+rIeSM8mpYQKKUoMZTpZEChhux/7cYHn5uuhth7BrTPBkWioggSSv4S1psPXlH +ZuoWp7LWCBRYor0WS2WWP4Ly+AvqAHlZkyAApvN+cZegxc8ckzBSQFrnSXYCwosb +N3foI/MaO3UzEdhQWhCh3G8ObpJO+Mg5awrtA1BLN1OTaOTmTAi5IIk/E/J/zA07 +NJ8IvkYHKpXNnXIRgM/oGrbFi6iLcHYQP0GyBmJ3KSi1ucQaJXlO4vRX2EvgNRVw +MdRrFuKvQibU3BjU5k/UaLgvCw1iUJbSIHzynzkt7PFD0RDduOaoeUTabtTyMYJc +bn3GLlg7/BLq6Lql+0MhNAU234MWenQTPnRroECOAvMi7OFCLoDt3M9KpWkuP1lS +TbvIlQAta8y6OHgqMNBn6gY12NvIZjnTWNcJ7Fs0VYo8hn00Q3ybrSP/4G1LcCo/ +WJ4HLk9clrTeTdde7WWSU0NwIBe0V9HJy/8AAAqGARAAAQEAAAAAAAAAAAAAAAD/ +2P/gABBKRklGAAEBAAABAAEAAP/bAEMACgcHCAcGCggICAsKCgsOGBAODQ0OHRUW +ERgjHyUkIh8iISYrNy8mKTQpISIwQTE0OTs+Pj4lLkRJQzxINz0+O//bAEMBCgsL +Dg0OHBAQHDsoIig7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7 +Ozs7Ozs7Ozs7Ozs7O//AABEIAJAAeAMBIgACEQEDEQH/xAAfAAABBQEBAQEBAQAA +AAAAAAAAAQIDBAUGBwgJCgv/xAC1EAACAQMDAgQDBQUEBAAAAX0BAgMABBEFEiEx +QQYTUWEHInEUMoGRoQgjQrHBFVLR8CQzYnKCCQoWFxgZGiUmJygpKjQ1Njc4OTpD +REVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoOEhYaHiImKkpOUlZaXmJma +oqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4eLj5OXm5+jp6vHy +8/T19vf4+fr/xAAfAQADAQEBAQEBAQEBAAAAAAAAAQIDBAUGBwgJCgv/xAC1EQAC +AQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVi +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 +SvPaxhi2tYbG4Em5RG8Pm8pTcY+YE+ZrGOc= +=L9dU +-----END PGP PUBLIC KEY BLOCK----- +pub 1024D/EC88A0BF 2006-11-09 +uid Philip M. Gollucci +sub 2048g/315B27A0 2006-11-09 + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.2.2 (FreeBSD) + +mQGiBEVSy4ARBADrOOinwIJ4itmRYZkw8cecNVGDP/VwcD3p8rlYsjZe1MNEZhuR +9nsNb+QOTHdY2iw92zsXYsYuk3kFEppGf+pomFnfUARJiMYkV02USvACRNSN+aRt +d2y8FCmhBZinx1niYhOAD8J+B97/IUKXqEBOygpHXKQz3xN3770CNef1NwCgweIx +0jReKJvR9uUgfqhps+EEdPsEAOmN37+bs+WaG+u/cd3Q/bHqDs7bG/GiM3beLop0 +HQLu68yE8KjZYDuKojFVJcvupAzP1suV7XaaUhBY0xJWLmGI9ZwU71yTTsDqex4b +G3qQ+4gqYEzIVQkWHquHlBeH6Ipjgw+I0XctPklIGnA87pztTfycKy/Xk/6RnlBA +29ujBADHA1PYdImHpsPbko+OkjOjdGjS/29kAUmEsWSVZ/PAVgs92glGHjBTZDWv +QzvsDmceTWS8LCAQivo4FzZvn4hbMA5nhU3Nz5KwvA9fe2LhiSyMoKILk3D3odSr +w/bZF/0SOZgBynz1AcC+jaj+rTGF3pb72RKLYZa8ZRCyzJpUYrQpUGhpbGlwIE0u +IEdvbGx1Y2NpIDxwZ29sbHVjY2lAcDZtN2c4LmNvbT6IYAQTEQIAIAUCRVLLgAIb +AwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAAoJEBMkm0/siKC/X+8AoLnY1ra0mDdJ +8KzdBWBRgm1wG4JGAJ9C4K7yr1bF/LKXKzXWXJ7K+E5YT7kCDQRFUsuMEAgAm0d1 +14gWPOe4RaOYy9S3bsJlKww/eLF7pC4oQKi+aWf914Q0+iJ6XcPW5dJRZkZ8ZQEM +zwhDPn15mxedfuN2CQldgyi6DQKbAsNwnUKd5Ro6S0rcsNF4hJ9G7ZfTiSD58Vox +aGSexJwToB5GrmqshrTBr4zfy0nGOo/GfzqADz/hMIDjLMIDQYah1ihidZ+w3XOx +ei0aUsC45ZnoeAipiL8xlRljDq6h8dmTmXGBlyY8VaXghYkLhoF9bWZ6dUukVUIp +OI2KyQzOIa48X6wLD4FbnIdg9uvcwItmdgelPAZqiJbsbk7MktYNHwbMbOR+W7JK +we5eCKhiddD4v/ysmwADBggAhsI/RXL1qLwssop2cDs5oETekHHjRb/aDg2xLbL7 +KdB3wSnYPYwG5EmAc2jukCZonDEJYTZ1RePaK6QtPyHNZPWwYS4gZsQbTgNUmWvU +r69VwBg8i1USADlKiMCLvoiMOyNEQp56yrwAVldP9UWs3p0laTZTwaNeqDS0m0by +gDNTPuX5xIHwTe66dF2e6YKSXEEIqlluaHydK+K/l/Osxx8I+DcH3rkzi+/9bCk+ +iq3Q+qZh9uT2DadAbbPe/jHtcBzoQ2qFan0rNDOFGDkMGbF0y2cnjc9DXBLymcsd +UTsRkhsB/Mq5+aN4sG7SXT7DwDesMz6jNdkqrYP1fNsMdYhJBBgRAgAJBQJFUsuM +AhsMAAoJEBMkm0/siKC/mrMAn3/s778nZ6gU4+yCIwoVpf94/FYaAJ9XKasQwdyU +QrnWO3UkWeAgmGQ70w== +=wxvV +-----END PGP PUBLIC KEY BLOCK----- + +pub 1024D/0E44CF0C 2001-06-19 + Key fingerprint = 6D0C 7498 5535 060B 2330 0BFE 47F6 969D 0E44 CF0C +uid Joe Orton +sig 3 0E44CF0C 2001-06-19 Joe Orton +sig 2 78688BF5 2004-04-01 Nalin Dahyabhai +sig 1 D39DA0E3 2004-11-28 Jason Harris +sig D23A41C8 2004-12-21 Douglas J Hunley +sig 2 6F9E049D 2005-06-25 Pim Rupert +sub 1024g/54F12E58 2001-06-19 +sig 0E44CF0C 2001-06-19 Joe Orton + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.7 (GNU/Linux) + +mQGiBDsvsLgRBACsHi7eM94mA9jlBxxwLC4ntK0Mj9WWm85V0C1y0Ei1MGz7q6Vu +WdxKgkNMauWrqKCBDQxOI3q5InZd/tZcOXQzGMtA6DxdAa50ZthfCbo0+8bfm00a +wCa5s/1x2tu7zuqcA7/3nOscZgss2k1RrZIALFimfXvq6hkchQyj9mnfKwCg1aOA +Wk7psAeH7UZgBqGHLcEKLjsD/11APufZVhmQtwKP8+yVe4d6UI7e2r4lURoT942g +tLlye1Rvh+FggkWjxKrwmyUaTW4jNDWEO1Sy1KCy/zb17lDQJReBNb4Q6wQwuySL +QqpFYUy3LtCJHnWsriC2d/iuLbBuQJxxQQQ0B0gichI+pqyZN2fmtiyucA3EzXv2 +8WQQA/9eSsUHv1nq+t0mbOBg1wpo0qlofJ96kM6kh8tzD6SxsHx6WDqE2TkZ+6Kf +Lr6yFo4XLY+5DOZ5XgR5LBTyH4PH8M5gZkqfzDTCJfk4qc2XzVW91zSbzQ0fMGWq +CU937R2LwnIWyVXjBgT8QLO58ZW8/X17YIGcgqHW1i4VD7XwR7QdSm9lIE9ydG9u +IDxqb3J0b25AcmVkaGF0LmNvbT6IVwQTEQIAFwUCOy+wuAULBwoDBAMVAwIDFgIB +AheAAAoJEEf2lp0ORM8M6boAnAz/+oVQGgGcHIpF9ugtJumGRApTAJ4liHEQvna0 +FOuzpUZ6kMT3sgIaBIhGBBIRAgAGBQJAbHSUAAoJEDebzld4aIv1rb8An333fo64 +a38vUnnO6rRdVquUpYC4AJ9x3lLonu/WI5WmDHjTy1Ar2kDt/4hGBBERAgAGBQJB +qmYnAAoJEEsqSJfTnaDjyOEAn13slJuH8G6VVPpV2m9S7FxRWh0iAKCEUKMYF+ZI +mQIyWAv/y1Y7A0chi4hGBBARAgAGBQJByJzOAAoJELGJ9rTSOkHIqX4An0obHgj3 +3Oiudie1rqgHj1mxxAprAJ4ps3XhNLDkxtLgwdao85VYj34w4IhGBBIRAgAGBQJC +vW/eAAoJEPxPSY5vngSdRqwAn3BthXNxPJBzDHRBgZ5d/1xzmFfqAJ0eJfe52uvk +h6ZzEc1sdl0sjKuea7kBDQQ7L7C6EAQA3lBouLYzyMT83ZtRUNgYmDZqNai1crEl +kuctL678IwQoEr4zGWTfwIb+vXkqf1VL2HJRXMTamrDfWo/Vy6ZiyB9IRpXNcNXT +dYmf6wXqPZqOCK9Q1mp/sWJGafHVbjDsWzGYTl9XiJUrMBPwPIlLj9SEvNwG7Qrh +jbrsBKkTWwcAAwUD/RWNLmA2OGhkkau62AHi2i20+zmPGLH0AnyaIPJAB6HaZCxU +uOSNBIRsaZoOoizzvaF6Qtaa7KJw3SUviWTfyAv4Lob+bo0e9MdI2olIvjg7VOi5 +wNPldVa4Cs4desqeXecJowP71gFV/NBdBPr2DLMXG3aOhtRZkG7aueoUkuk+iEYE +GBECAAYFAjsvsLoACgkQR/aWnQ5EzwyKgACcD+v7ABREHJd0RglLfFoAuCcZ7FoA +oNQYheE5UpBrTY6qK063clE3Gt2J +=NWjz +-----END PGP PUBLIC KEY BLOCK----- diff --git a/userdir.conf b/userdir.conf new file mode 100644 index 0000000..b5d7a49 --- /dev/null +++ b/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/welcome.conf b/welcome.conf new file mode 100644 index 0000000..37b7394 --- /dev/null +++ b/welcome.conf @@ -0,0 +1,19 @@ +# +# 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 /poweredby.png /usr/share/httpd/icons/apache_pb3.png \ No newline at end of file