Compare commits

...

No commits in common. 'c9' and 'i8c-stream-2.4' have entirely different histories.

2
.gitignore vendored

@ -1,2 +1,2 @@
SOURCES/apache-poweredby.png
SOURCES/httpd-2.4.62.tar.bz2
SOURCES/httpd-2.4.37.tar.bz2

@ -1,2 +1,2 @@
3a7449d6cff00e5ccb3ed8571f34c0528555d38f SOURCES/apache-poweredby.png
c968e2a0e556a8d3b7f6d6fc9732ddc456b5c229 SOURCES/httpd-2.4.62.tar.bz2
4a38471de821288b0300148016f2b03dfee8adf2 SOURCES/httpd-2.4.37.tar.bz2

@ -23,6 +23,7 @@ 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
@ -54,7 +55,6 @@ 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_redis_module modules/mod_socache_redis.so
LoadModule socache_shmcb_module modules/mod_socache_shmcb.so
LoadModule status_module modules/mod_status.so
LoadModule substitute_module modules/mod_substitute.so

@ -1 +0,0 @@
LoadModule brotli_module modules/mod_brotli.so

@ -4,7 +4,6 @@
#
#LoadModule asis_module modules/mod_asis.so
#LoadModule authnz_fcgi_module modules/mod_authnz_fcgi.so
#LoadModule buffer_module modules/mod_buffer.so
#LoadModule heartbeat_module modules/mod_heartbeat.so
#LoadModule heartmonitor_module modules/mod_heartmonitor.so

@ -2,7 +2,10 @@
# which has been configured in 00-mpm.conf. mod_cgid should be used
# with a threaded MPM; mod_cgi with the prefork MPM.
<IfModule !mpm_prefork_module>
<IfModule mpm_worker_module>
LoadModule cgid_module modules/mod_cgid.so
</IfModule>
<IfModule mpm_event_module>
LoadModule cgid_module modules/mod_cgid.so
</IfModule>
<IfModule mpm_prefork_module>

File diff suppressed because it is too large Load Diff

@ -1,2 +1,2 @@
#!/bin/sh
exec /usr/sbin/httpd -t
exec /sbin/apachectl configtest "$@"

@ -1,2 +1,2 @@
#!/bin/sh
exec /sbin/apachectl graceful
exec /sbin/apachectl graceful "$@"

@ -1,74 +0,0 @@
#!/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

@ -1,191 +0,0 @@
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">[
]>
<!--
Copyright 2020 Red Hat, Inc.
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.
-->
<refentry>
<refentryinfo>
<title>apachectl</title>
<productname>httpd</productname>
<author><contrib>Apache man page</contrib><othername>Apache Software Foundation contributors</othername></author>
<author><contrib>Fedora man page</contrib><surname>Dana</surname><firstname>Frank</firstname></author>
</refentryinfo>
<refmeta>
<refentrytitle>apachectl</refentrytitle>
<manvolnum>8</manvolnum>
</refmeta>
<refnamediv>
<refname>apachectl</refname>
<refpurpose>Server control interface for httpd</refpurpose>
</refnamediv>
<refsynopsisdiv id='synopsis'>
<cmdsynopsis>
<command>apachectl</command>
<arg choice='opt'><replaceable>command</replaceable> </arg>
<sbr/>
</cmdsynopsis>
</refsynopsisdiv>
<!-- body begins here -->
<refsect1 id='description'>
<title>Description</title>
<para><command>apachectl</command> 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
<command>httpd</command> daemon.</para>
<para>The <command>apachectl</command> script takes one-word arguments like
<option>start</option>,
<option>restart</option>, and
<option>stop</option>, and translates them
into appropriate signals to <command>httpd</command>.</para>
<para>The <command>apachectl</command> script returns a 0 exit value on
success, and &gt;0 if an error occurs.</para>
<refsect2 id="compatibility">
<title>Compatibility</title>
<para>The version of <command>apachectl</command> used on this
system is a replacement script intended to be mostly (but not
completely) compatible with version provided with
<emphasis>Apache httpd</emphasis>. This
<command>apachectl</command> mostly acts as a wrapper around
<command>systemctl</command> and manipulates the
<command>systemd</command> service for <command>httpd</command>.
The interface to the <emphasis>Apache</emphasis> version of
<command>apachectl</command> is described at <ulink
url="https://httpd.apache.org/docs/2.4/programs/apachectl.html"/>.</para>
<para>The following differences are present in the version of
<command>apachectl</command> present on this system:
<itemizedlist>
<listitem><para>Option arguments passed when starting
<command>httpd</command> are not allowed. These should be
configured in the systemd service directly (see <citerefentry><refentrytitle>httpd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>).</para></listitem>
<listitem><para>The <command>"fullstatus"</command> option is
not available.</para></listitem>
<listitem><para>The <command>"status"</command> option does
not use or rely on the running server's
<emphasis>server-status</emphasis> output.</para></listitem>
</itemizedlist>
</para>
</refsect2>
</refsect1>
<refsect1 id='options'>
<title>Options</title>
<variablelist remap='TP'>
<varlistentry>
<term><option>start</option></term>
<listitem>
<para>Start the Apache <command>httpd</command> daemon. Gives an error if it
is already running. This is equivalent to <command>systemctl start httpd.service</command>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>stop</option></term>
<listitem>
<para>Stops the Apache <command>httpd</command> daemon. This is equivalent to
<command>systemctl stop httpd.service</command>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>restart</option></term>
<listitem>
<para>Restarts the Apache <command>httpd</command> daemon. If the daemon is
not running, it is started. This is equivalent
to <command>systemctl restart httpd.service</command>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>status</option></term>
<listitem>
<para>Displays a brief status report. This is equivalent to <command>systemctl status httpd.service.</command></para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>graceful</option></term>
<listitem>
<para>Gracefully restarts the Apache <command>httpd</command> 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
<command>systemctl kill --signal=SIGUSR1 --kill-who=main httpd.service</command>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>graceful-stop</option></term>
<listitem>
<para>Gracefully stops the Apache <command>httpd</command> 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
<command>systemctl kill --signal=SIGWINCH --kill-who=main httpd.service</command>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>configtest</option></term>
<listitem>
<para>Run a configuration file syntax test. It parses the configuration
files and either reports <literal>Syntax OK</literal>
or detailed information about the particular syntax error. This is
equivalent to <command>httpd -t</command>.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1 id='bugs'>
<title>Bugs</title>
<para>Please report bugs by filing an issue in Bugzilla via <ulink url='https://bugzilla.redhat.com/'/>.</para>
</refsect1>
<refsect1>
<title>See also</title>
<para>
<citerefentry><refentrytitle>httpd</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>httpd.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>httpd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
</refsect1>
</refentry>

@ -7,10 +7,5 @@ Documentation=man:htcacheclean.service(8)
Type=forking
User=apache
PIDFile=/run/httpd/htcacheclean/pid
Environment=LANG=C
EnvironmentFile=/etc/sysconfig/htcacheclean
ExecStart=/usr/sbin/htcacheclean -P /run/httpd/htcacheclean/pid -d $INTERVAL -p $CACHE_ROOT -l $LIMIT $OPTIONS
PrivateTmp=true
[Install]
WantedBy=multi-user.target

@ -1,8 +1,8 @@
diff --git a/support/apxs.in b/support/apxs.in
index b2705fa..c331631 100644
index ad1287f..efcfcf6 100644
--- a/support/apxs.in
+++ b/support/apxs.in
@@ -35,7 +35,18 @@ if ($ddi >= 0) {
@@ -25,7 +25,18 @@ package apxs;
my %config_vars = ();
@ -19,10 +19,10 @@ index b2705fa..c331631 100644
+
+my $installbuilddir = $libdir . "/httpd/build";
+
get_config_vars($destdir . "$installbuilddir/config_vars.mk",\%config_vars);
get_config_vars("$installbuilddir/config_vars.mk",\%config_vars);
# read the configuration variables once
@@ -285,7 +296,7 @@ if ($opt_g) {
@@ -275,7 +286,7 @@ if ($opt_g) {
$data =~ s|%NAME%|$name|sg;
$data =~ s|%TARGET%|$CFG_TARGET|sg;
$data =~ s|%PREFIX%|$prefix|sg;
@ -31,7 +31,7 @@ index b2705fa..c331631 100644
my ($mkf, $mods, $src) = ($data =~ m|^(.+)-=#=-\n(.+)-=#=-\n(.+)|s);
@@ -463,11 +474,11 @@ if ($opt_c) {
@@ -453,11 +464,11 @@ if ($opt_c) {
my $ldflags = "$CFG_LDFLAGS";
if ($opt_p == 1) {
@ -45,7 +45,7 @@ index b2705fa..c331631 100644
chomp($apu_libs);
}
@@ -682,8 +693,8 @@ __DATA__
@@ -672,8 +683,8 @@ __DATA__
builddir=.
top_srcdir=%PREFIX%

@ -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@/"
<Directory "@exp_iconsdir@">
- Options Indexes MultiViews
+ Options Indexes MultiViews FollowSymlinks
AllowOverride None
Require all granted
</Directory>
@@ -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

@ -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));

@ -1,8 +1,8 @@
diff --git a/server/listen.c b/server/listen.c
index 9577d60..d718db1 100644
index a8e9e6f..1a6c1d3 100644
--- a/server/listen.c
+++ b/server/listen.c
@@ -35,6 +35,10 @@
@@ -34,6 +34,10 @@
#include <unistd.h>
#endif
@ -13,7 +13,7 @@ index 9577d60..d718db1 100644
/* we know core's module_index is 0 */
#undef APLOG_MODULE_INDEX
#define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
@@ -60,9 +64,12 @@ static int ap_listenbacklog;
@@ -59,9 +63,12 @@ static int ap_listenbacklog;
static int ap_listencbratio;
static int send_buffer_size;
static int receive_buffer_size;
@ -27,7 +27,7 @@ index 9577d60..d718db1 100644
{
apr_socket_t *s = server->sd;
int one = 1;
@@ -95,20 +102,6 @@ static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server)
@@ -94,20 +101,6 @@ static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server)
return stat;
}
@ -48,7 +48,7 @@ index 9577d60..d718db1 100644
/*
* To send data over high bandwidth-delay connections at full
* speed we must force the TCP window to open wide enough to keep the
@@ -170,21 +163,37 @@ static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server)
@@ -169,21 +162,37 @@ static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server)
}
#endif
@ -100,7 +100,7 @@ index 9577d60..d718db1 100644
}
#ifdef WIN32
@@ -335,6 +344,123 @@ static int find_listeners(ap_listen_rec **from, ap_listen_rec **to,
@@ -315,6 +324,123 @@ static int find_listeners(ap_listen_rec **from, ap_listen_rec **to,
return found;
}
@ -223,8 +223,8 @@ index 9577d60..d718db1 100644
+
static const char *alloc_listener(process_rec *process, const char *addr,
apr_port_t port, const char* proto,
const char *scope_id, void *slave,
@@ -529,7 +655,7 @@ static int open_listeners(apr_pool_t *pool)
void *slave)
@@ -495,7 +621,7 @@ static int open_listeners(apr_pool_t *pool)
}
}
#endif
@ -233,7 +233,7 @@ index 9577d60..d718db1 100644
++num_open;
}
else {
@@ -641,8 +767,28 @@ AP_DECLARE(int) ap_setup_listeners(server_rec *s)
@@ -607,8 +733,28 @@ AP_DECLARE(int) ap_setup_listeners(server_rec *s)
}
}
@ -264,7 +264,7 @@ index 9577d60..d718db1 100644
}
for (lr = ap_listeners; lr; lr = lr->next) {
@@ -732,7 +878,7 @@ AP_DECLARE(apr_status_t) ap_duplicate_listeners(apr_pool_t *p, server_rec *s,
@@ -698,7 +844,7 @@ AP_DECLARE(apr_status_t) ap_duplicate_listeners(apr_pool_t *p, server_rec *s,
duplr->bind_addr);
return stat;
}
@ -273,7 +273,7 @@ index 9577d60..d718db1 100644
#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);
@@ -859,6 +1005,11 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy,
@@ -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.";
}
@ -285,7 +285,7 @@ index 9577d60..d718db1 100644
rv = apr_parse_addr_port(&host, &scope_id, &port, argv[0], cmd->pool);
if (rv != APR_SUCCESS) {
@@ -894,6 +1045,12 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy,
@@ -856,6 +1007,12 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy,
ap_str_tolower(proto);
}
@ -295,6 +295,6 @@ index 9577d60..d718db1 100644
+ }
+#endif
+
return alloc_listener(cmd->server->process, host, port, proto,
scope_id, NULL, cmd->temp_pool);
return alloc_listener(cmd->server->process, host, port, proto, NULL);
}

@ -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;

@ -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

@ -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);

@ -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

@ -13,7 +13,7 @@ index 6b92151..4c42a8e 100644
/* A linked-list of authn providers. */
diff --git a/modules/cache/mod_cache.c b/modules/cache/mod_cache.c
index 3b9aa4f..8268503 100644
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)

@ -1,8 +1,15 @@
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 79b2a82..dc0f17a 100644
index aa62e15..ec74029 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
@@ -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);

@ -1,8 +1,13 @@
Link straight against .la files.
Upstream-Status: vendor specific
diff --git a/configure.in b/configure.in
index 7194de5..00e2369 100644
index 9feaceb..82bfeef 100644
--- a/configure.in
+++ b/configure.in
@@ -843,9 +843,9 @@ APACHE_SUBST(INSTALL_SUEXEC)
@@ -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

@ -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 ""'

@ -1,52 +1,8 @@
diff --git a/docs/manual/mod/mpm_common.html.en b/docs/manual/mod/mpm_common.html.en
index d7a2fea..c911a4e 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)</td></tr>
<li><img alt="" src="../images/down.gif" /> <a href="#enableexceptionhook">EnableExceptionHook</a></li>
<li><img alt="" src="../images/down.gif" /> <a href="#gracefulshutdowntimeout">GracefulShutdownTimeout</a></li>
<li><img alt="" src="../images/down.gif" /> <a href="#listen">Listen</a></li>
+<li><img alt="" src="../images/down.gif" /> <a href="#listenfree">ListenFree</a></li>
<li><img alt="" src="../images/down.gif" /> <a href="#listenbacklog">ListenBackLog</a></li>
<li><img alt="" src="../images/down.gif" /> <a href="#listencoresbucketsratio">ListenCoresBucketsRatio</a></li>
<li><img alt="" src="../images/down.gif" /> <a href="#maxconnectionsperchild">MaxConnectionsPerChild</a></li>
@@ -244,6 +245,31 @@ discussion of the <code>Address already in use</code> error message,
including other causes.</a></li>
</ul>
</div>
+
+<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
+<div class="directive-section"><h2><a name="ListenFree" id="ListenFree">ListenFree</a> <a name="listenfree" id="listenfree">Directive</a></h2>
+<table class="directive">
+<tr><th><a href="directive-dict.html#Description">Description:</a></th><td>IP addresses and ports that the server
+listens to. Doesn't require IP address to be up</td></tr>
+<tr><th><a href="directive-dict.html#Syntax">Syntax:</a></th><td><code>ListenFree [<var>IP-address</var>:]<var>portnumber</var> [<var>protocol</var>]</code></td></tr>
+<tr><th><a href="directive-dict.html#Context">Context:</a></th><td>server config</td></tr>
+<tr><th><a href="directive-dict.html#Status">Status:</a></th><td>MPM</td></tr>
+<tr><th><a href="directive-dict.html#Module">Module:</a></th><td><code class="module"><a href="../mod/event.html">event</a></code>, <code class="module"><a href="../mod/worker.html">worker</a></code>, <code class="module"><a href="../mod/prefork.html">prefork</a></code>, <code class="module"><a href="../mod/mpm_winnt.html">mpm_winnt</a></code>, <code class="module"><a href="../mod/mpm_netware.html">mpm_netware</a></code>, <code class="module"><a href="../mod/mpmt_os2.html">mpmt_os2</a></code></td></tr>
+<tr><th><a href="directive-dict.html#Compatibility">Compatibility:</a></th><td>This directive is currently available only in Red Hat Enterprise Linux</td></tr>
+</table>
+ <p>The <code class="directive">ListenFree</code> directive is
+ identical to the <code class="directive">Listen</code> directive.
+ The only difference is in the usage of the IP_FREEBIND socket
+ option, which is enabled by default with <code class="directive">ListenFree</code>.
+ 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.
+ </p>
+</div>
+
+
<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
<div class="directive-section"><h2><a name="ListenBackLog" id="ListenBackLog">ListenBackLog</a> <a name="listenbacklog" id="listenbacklog">Directive</a></h2>
<table class="directive">
diff --git a/include/ap_listen.h b/include/ap_listen.h
index d5ed968..be1a60c 100644
index 58c2574..1a53292 100644
--- a/include/ap_listen.h
+++ b/include/ap_listen.h
@@ -138,6 +138,9 @@ AP_DECLARE_NONSTD(const char *) ap_set_listenbacklog(cmd_parms *cmd, void *dummy
@@ -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[]);
@ -56,7 +12,7 @@ index d5ed968..be1a60c 100644
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,
@@ -160,6 +163,8 @@ AP_INIT_TAKE1("ListenCoresBucketsRatio", ap_set_listencbratio, NULL, RSRC_CONF,
@@ -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"), \
@ -66,10 +22,10 @@ index d5ed968..be1a60c 100644
"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 2a4e87a..280bbe7 100644
index 1a6c1d3..d375fee 100644
--- a/server/listen.c
+++ b/server/listen.c
@@ -60,6 +60,7 @@ static int ap_listenbacklog;
@@ -63,6 +63,7 @@ static int ap_listenbacklog;
static int ap_listencbratio;
static int send_buffer_size;
static int receive_buffer_size;
@ -77,7 +33,7 @@ index 2a4e87a..280bbe7 100644
#ifdef HAVE_SYSTEMD
static int use_systemd = -1;
#endif
@@ -159,6 +160,21 @@ static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server, int do_bind_
@@ -162,6 +163,21 @@ static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server, int do_bind_
}
#endif
@ -99,7 +55,7 @@ index 2a4e87a..280bbe7 100644
if (do_bind_listen) {
#if APR_HAVE_IPV6
if (server->bind_addr->family == APR_INET6) {
@@ -971,6 +987,7 @@ AP_DECLARE(void) ap_listen_pre_config(void)
@@ -956,6 +972,7 @@ AP_DECLARE(void) ap_listen_pre_config(void)
}
}
@ -107,8 +63,8 @@ index 2a4e87a..280bbe7 100644
AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy,
int argc, char *const argv[])
{
@@ -1044,6 +1061,14 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy,
scope_id, NULL, cmd->temp_pool);
@@ -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,
@ -122,3 +78,48 @@ index 2a4e87a..280bbe7 100644
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)</td></tr>
<li><img alt="" src="../images/down.gif" /> <a href="#enableexceptionhook">EnableExceptionHook</a></li>
<li><img alt="" src="../images/down.gif" /> <a href="#gracefulshutdowntimeout">GracefulShutdownTimeout</a></li>
<li><img alt="" src="../images/down.gif" /> <a href="#listen">Listen</a></li>
+<li><img alt="" src="../images/down.gif" /> <a href="#listenfree">ListenFree</a></li>
<li><img alt="" src="../images/down.gif" /> <a href="#listenbacklog">ListenBackLog</a></li>
<li><img alt="" src="../images/down.gif" /> <a href="#listencoresbucketsratio">ListenCoresBucketsRatio</a></li>
<li><img alt="" src="../images/down.gif" /> <a href="#maxconnectionsperchild">MaxConnectionsPerChild</a></li>
@@ -233,6 +234,31 @@ discussion of the <code>Address already in use</code> error message,
including other causes.</a></li>
</ul>
</div>
+
+<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
+<div class="directive-section"><h2><a name="ListenFree" id="ListenFree">ListenFree</a> <a name="listenfree" id="listenfree">Directive</a></h2>
+<table class="directive">
+<tr><th><a href="directive-dict.html#Description">Description:</a></th><td>IP addresses and ports that the server
+listens to. Doesn't require IP address to be up</td></tr>
+<tr><th><a href="directive-dict.html#Syntax">Syntax:</a></th><td><code>ListenFree [<var>IP-address</var>:]<var>portnumber</var> [<var>protocol</var>]</code></td></tr>
+<tr><th><a href="directive-dict.html#Context">Context:</a></th><td>server config</td></tr>
+<tr><th><a href="directive-dict.html#Status">Status:</a></th><td>MPM</td></tr>
+<tr><th><a href="directive-dict.html#Module">Module:</a></th><td><code class="module"><a href="../mod/event.html">event</a></code>, <code class="module"><a href="../mod/worker.html">worker</a></code>, <code class="module"><a href="../mod/prefork.html">prefork</a></code>, <code class="module"><a href="../mod/mpm_winnt.html">mpm_winnt</a></code>, <code class="module"><a href="../mod/mpm_netware.html">mpm_netware</a></code>, <code class="module"><a href="../mod/mpmt_os2.html">mpmt_os2</a></code></td></tr>
+<tr><th><a href="directive-dict.html#Compatibility">Compatibility:</a></th><td>This directive is currently available only in Red Hat Enterprise Linux</td></tr>
+</table>
+ <p>The <code class="directive">ListenFree</code> directive is
+ identical to the <code class="directive">Listen</code> directive.
+ The only difference is in the usage of the IP_FREEBIND socket
+ option, which is enabled by default with <code class="directive">ListenFree</code>.
+ 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.
+ </p>
+</div>
+
+
<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
<div class="directive-section"><h2><a name="ListenBackLog" id="ListenBackLog">ListenBackLog</a> <a name="listenbacklog" id="listenbacklog">Directive</a></h2>
<table class="directive">

@ -1,8 +1,8 @@
diff --git a/server/core.c b/server/core.c
index c36ff26..621c82a 100644
index cb8e463..daf76b3 100644
--- a/server/core.c
+++ b/server/core.c
@@ -3569,6 +3569,7 @@ enum server_token_type {
@@ -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 */
@ -10,7 +10,7 @@ index c36ff26..621c82a 100644
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)
@@ -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);
}
@ -22,7 +22,7 @@ index c36ff26..621c82a 100644
ap_add_version_component(pconf, AP_SERVER_BASEVERSION " (" PLATFORM ")");
}
@@ -3653,7 +3657,7 @@ static void set_banner(apr_pool_t *pconf)
@@ -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
*/
@ -31,8 +31,8 @@ index c36ff26..621c82a 100644
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")) {
@@ -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")) {

@ -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. */

@ -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 ?

@ -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)

@ -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;
}

@ -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, &params, 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,

@ -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) {

@ -1,8 +1,13 @@
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 3932407..00e2369 100644
index eedba50..a208b53 100644
--- a/configure.in
+++ b/configure.in
@@ -531,6 +531,11 @@ gettid
@@ -484,6 +484,11 @@ getloadavg
dnl confirm that a void pointer is large enough to store a long integer
APACHE_CHECK_VOID_PTR_LEN
@ -11,14 +16,14 @@ index 3932407..00e2369 100644
+ APR_ADDTO(HTTPD_LIBS, [-lselinux])
+])
+
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_CACHE_CHECK([for gettid()], ac_cv_gettid,
[AC_TRY_RUN(#define _GNU_SOURCE
#include <unistd.h>
diff --git a/server/core.c b/server/core.c
index 8970a50..ff1024d 100644
index ec74029..cb8e463 100644
--- a/server/core.c
+++ b/server/core.c
@@ -65,6 +65,10 @@
@@ -59,6 +59,10 @@
#include <unistd.h>
#endif
@ -28,8 +33,8 @@ index 8970a50..ff1024d 100644
+
/* LimitRequestBody handling */
#define AP_LIMIT_REQ_BODY_UNSET ((apr_off_t) -1)
#define AP_DEFAULT_LIMIT_REQ_BODY ((apr_off_t) 1<<30) /* 1GB */
@@ -5170,6 +5174,28 @@ static int core_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *pte
#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

@ -1,8 +1,8 @@
diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c
index 97778a8..27e7a53 100644
index 4cfd2d0..6ac55bd 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,
@@ -776,9 +776,11 @@ const char *ssl_cmd_SSLCipherSuite(cmd_parms *cmd,
}
if (!strcmp("SSL", arg1)) {
@ -16,7 +16,7 @@ index 97778a8..27e7a53 100644
dc->szCipherSuite = arg2;
}
else {
@@ -1544,8 +1546,10 @@ const char *ssl_cmd_SSLProxyCipherSuite(cmd_parms *cmd,
@@ -1542,8 +1544,10 @@ const char *ssl_cmd_SSLProxyCipherSuite(cmd_parms *cmd,
}
if (!strcmp("SSL", arg1)) {

@ -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 <stdint.h>
+#include <ap_config.h>
+#include "ap_mpm.h"
+#include <http_core.h>
+#include <httpd.h>
+#include <http_log.h>
+#include <apr_version.h>
+#include <apr_pools.h>
+#include <apr_strings.h>
+#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 <unistd.h>
+#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,
+};

@ -0,0 +1,20 @@
diff --git a/modules/dav/main/util.c b/modules/dav/main/util.c
index 1ae5914027c..3f7822fc931 100644
--- a/modules/dav/main/util.c
+++ b/modules/dav/main/util.c
@@ -801,8 +801,14 @@ static dav_error * dav_process_if_header(request_rec *r, dav_if_header **p_ih)
"for the same state.");
}
condition = DAV_IF_COND_NOT;
+ list += 2;
+ }
+ else {
+ return dav_new_error(r->pool, HTTP_BAD_REQUEST,
+ DAV_ERR_IF_UNK_CHAR, 0,
+ "Invalid \"If:\" header: "
+ "Unexpected character in List");
}
- list += 2;
break;
case ' ':

@ -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;
}
}

@ -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;
}
}

@ -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.<br />");
+ 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;
}
}

@ -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);

@ -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</td></tr>
<li><img alt="" src="../images/down.gif" /> <a href="#maxrangeoverlaps">MaxRangeOverlaps</a></li>
<li><img alt="" src="../images/down.gif" /> <a href="#maxrangereversals">MaxRangeReversals</a></li>
<li><img alt="" src="../images/down.gif" /> <a href="#maxranges">MaxRanges</a></li>
+<li><img alt="" src="../images/down.gif" /> <a href="#mergeslashes">MergeSlashes</a></li>
<li><img alt="" src="../images/down.gif" /> <a href="#mergetrailers">MergeTrailers</a></li>
<li><img alt="" src="../images/down.gif" /> <a href="#mutex">Mutex</a></li>
<li><img alt="" src="../images/down.gif" /> <a href="#namevirtualhost">NameVirtualHost</a></li>
@@ -3465,6 +3466,30 @@ resource </td></tr>
</div>
<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
+<div class="directive-section"><h2><a name="MergeSlashes" id="MergeSlashes">MergeSlashes</a> <a name="mergeslashes" id="mergeslashes">Directive</a></h2>
+<table class="directive">
+<tr><th><a href="directive-dict.html#Description">Description:</a></th><td>Controls whether the server merges consecutive slashes in URLs. </td></tr>
+<tr><th><a href="directive-dict.html#Syntax">Syntax:</a></th><td><code>MergeSlashes ON | OFF</code></td></tr>
+<tr><th><a href="directive-dict.html#Default">Default:</a></th><td><code>MergeSlashes ON</code></td></tr>
+<tr><th><a href="directive-dict.html#Context">Context:</a></th><td>server config, virtual host</td></tr>
+<tr><th><a href="directive-dict.html#Status">Status:</a></th><td>Core</td></tr>
+<tr><th><a href="directive-dict.html#Module">Module:</a></th><td>core</td></tr>
+<tr><th><a href="directive-dict.html#Compatibility">Compatibility:</a></th><td>Available in Apache HTTP Server 2.4.6 in Red Hat Enterprise Linux 7</td></tr>
+</table>
+ <p>By default, the server merges (or collapses) multiple consecutive slash
+ ('/') characters in the path component of the request URL.</p>
+
+ <p>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 <code class="directive">MergeSlashes</code> can be set to
+ <em>OFF</em> to retain the multiple consecutive slashes. In these
+ configurations, regular expressions used in the configuration file that match
+ the path component of the URL (<code class="directive">LocationMatch</code>,
+ <code class="directive">RewriteRule</code>, ...) need to take into account multiple
+ consecutive slashes.</p>
+</div>
+<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
<div class="directive-section"><h2><a name="MergeTrailers" id="MergeTrailers">MergeTrailers</a> <a name="mergetrailers" id="mergetrailers">Directive</a></h2>
<table class="directive">
<tr><th><a href="directive-dict.html#Description">Description:</a></th><td>Determines whether trailers are merged into headers</td></tr>
--- 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 }
};

@ -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</a>.</p>\n",
NULL));
case HTTP_USE_PROXY:
- return(apr_pstrcat(p,
- "<p>This resource is only accessible "
- "through the proxy\n",
- ap_escape_html(r->pool, location),
- "<br />\nYou will need to configure "
- "your client to use that proxy.</p>\n",
- NULL));
+ return("<p>This resource is only accessible "
+ "through the proxy\n"
+ "<br />\nYou will need to configure "
+ "your client to use that proxy.</p>\n");
case HTTP_PROXY_AUTHENTICATION_REQUIRED:
case HTTP_UNAUTHORIZED:
return("<p>This server could not verify that you\n"
@@ -1154,34 +1151,20 @@ static const char *get_canned_error_string(int status,
"error-notes",
"</p>\n"));
case HTTP_FORBIDDEN:
- s1 = apr_pstrcat(p,
- "<p>You don't have permission to access ",
- ap_escape_html(r->pool, r->uri),
- "\non this server.<br />\n",
- NULL);
- return(add_optional_notes(r, s1, "error-notes", "</p>\n"));
+ return(add_optional_notes(r, "<p>You don't have permission to access this resource.", "error-notes", "</p>\n"));
case HTTP_NOT_FOUND:
- return(apr_pstrcat(p,
- "<p>The requested URL ",
- ap_escape_html(r->pool, r->uri),
- " was not found on this server.</p>\n",
- NULL));
+ return("<p>The requested URL was not found on this server.</p>\n");
case HTTP_METHOD_NOT_ALLOWED:
return(apr_pstrcat(p,
"<p>The requested method ",
ap_escape_html(r->pool, r->method),
- " is not allowed for the URL ",
- ap_escape_html(r->pool, r->uri),
- ".</p>\n",
+ " is not allowed for this URL.</p>\n",
NULL));
case HTTP_NOT_ACCEPTABLE:
- s1 = apr_pstrcat(p,
- "<p>An appropriate representation of the "
- "requested resource ",
- ap_escape_html(r->pool, r->uri),
- " could not be found on this server.</p>\n",
- NULL);
- return(add_optional_notes(r, s1, "variant-list", ""));
+ return(add_optional_notes(r,
+ "<p>An appropriate representation of the requested resource "
+ "could not be found on this server.</p>\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", "</p>\n"));
case HTTP_PRECONDITION_FAILED:
- return(apr_pstrcat(p,
- "<p>The precondition on the request "
- "for the URL ",
- ap_escape_html(r->pool, r->uri),
- " evaluated to false.</p>\n",
- NULL));
+ return("<p>The precondition on the request "
+ "for this URL evaluated to false.</p>\n");
case HTTP_NOT_IMPLEMENTED:
s1 = apr_pstrcat(p,
"<p>",
- ap_escape_html(r->pool, r->method), " to ",
- ap_escape_html(r->pool, r->uri),
- " not supported.<br />\n",
+ ap_escape_html(r->pool, r->method), " ",
+ " not supported for current URL.<br />\n",
NULL);
return(add_optional_notes(r, s1, "error-notes", "</p>\n"));
case HTTP_BAD_GATEWAY:
@@ -1211,29 +1189,19 @@ static const char *get_canned_error_string(int status,
"response from an upstream server.<br />" CRLF;
return(add_optional_notes(r, s1, "error-notes", "</p>\n"));
case HTTP_VARIANT_ALSO_VARIES:
- return(apr_pstrcat(p,
- "<p>A variant for the requested "
- "resource\n<pre>\n",
- ap_escape_html(r->pool, r->uri),
- "\n</pre>\nis itself a negotiable resource. "
- "This indicates a configuration error.</p>\n",
- NULL));
+ return("<p>A variant for the requested "
+ "resource\n<pre>\n"
+ "\n</pre>\nis itself a negotiable resource. "
+ "This indicates a configuration error.</p>\n");
case HTTP_REQUEST_TIME_OUT:
return("<p>Server timeout waiting for the HTTP request from the client.</p>\n");
case HTTP_GONE:
- return(apr_pstrcat(p,
- "<p>The requested resource<br />",
- ap_escape_html(r->pool, r->uri),
- "<br />\nis no longer available on this server "
- "and there is no forwarding address.\n"
- "Please remove all references to this "
- "resource.</p>\n",
- NULL));
+ return("<p>The requested resource is no longer available on this server"
+ " and there is no forwarding address.\n"
+ "Please remove all references to this resource.</p>\n");
case HTTP_REQUEST_ENTITY_TOO_LARGE:
return(apr_pstrcat(p,
- "The requested resource<br />",
- ap_escape_html(r->pool, r->uri), "<br />\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.</p>\n");
case HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
- s1 = apr_pstrcat(p,
- "<p>Access to ", ap_escape_html(r->pool, r->uri),
- "\nhas been denied for legal reasons.<br />\n",
- NULL);
- return(add_optional_notes(r, s1, "error-notes", "</p>\n"));
+ return(add_optional_notes(r,
+ "<p>Access to this URL has been denied for legal reasons.<br />\n",
+ "error-notes", "</p>\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 <em><a href=\"",
- uri, "\">", ap_escape_html(r->pool, r->method), "&nbsp;", uri,
- "</a></em>.<p>\n"
+ "The proxy server could not handle the request<p>"
"Reason: <strong>", ap_escape_html(r->pool, message),
"</strong></p>",
NULL));

@ -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,

@ -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);
}

@ -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);

@ -0,0 +1,12 @@
diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c
index 5786ea8..7da9bde 100644
--- a/modules/proxy/mod_proxy_http.c
+++ b/modules/proxy/mod_proxy_http.c
@@ -637,7 +637,6 @@ static int ap_proxy_http_prefetch(proxy_http_req_t *req,
"chunked body with Content-Length (C-L ignored)",
c->client_ip, c->remote_host ? c->remote_host: "");
req->old_cl_val = NULL;
- origin->keepalive = AP_CONN_CLOSE;
p_conn->close = 1;
}

@ -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);

@ -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;

@ -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);
}

@ -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;
}

@ -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));
}
}

@ -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 <arpa/inet.h>
@@ -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;
}
/**

@ -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 {

@ -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 */

@ -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++;
}

@ -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;
+ }
}
}
}

@ -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 <Proxy > 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 "<Proxy/ProxyMatch > 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.

@ -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);

@ -0,0 +1,70 @@
--- a/modules/lua/lua_request.c 2022/03/07 14:48:54 1898693
+++ b/modules/lua/lua_request.c 2022/03/07 14:51:19 1898694
@@ -235,14 +235,16 @@
{
int rc = OK;
+ *rbuf = NULL;
+ *size = 0;
+
if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) {
return (rc);
}
if (ap_should_client_block(r)) {
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- char argsbuffer[HUGE_STRING_LEN];
- apr_off_t rsize, len_read, rpos = 0;
+ apr_off_t len_read, rpos = 0;
apr_off_t length = r->remaining;
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
@@ -250,18 +252,18 @@
return APR_EINCOMPLETE; /* Only room for incomplete data chunk :( */
}
*rbuf = (const char *) apr_pcalloc(r->pool, (apr_size_t) (length + 1));
- *size = length;
- while ((len_read = ap_get_client_block(r, argsbuffer, sizeof(argsbuffer))) > 0) {
- if ((rpos + len_read) > length) {
- rsize = length - rpos;
- }
- else {
- rsize = len_read;
- }
-
- memcpy((char *) *rbuf + rpos, argsbuffer, (size_t) rsize);
- rpos += rsize;
+ while ((rpos < length)
+ && (len_read = ap_get_client_block(r, (char *) *rbuf + rpos,
+ length - rpos)) > 0) {
+ rpos += len_read;
}
+ if (len_read < 0) {
+ return APR_EINCOMPLETE;
+ }
+ *size = rpos;
+ }
+ else {
+ rc = DONE;
}
return (rc);
@@ -278,6 +280,8 @@
{
apr_status_t rc = OK;
+ *size = 0;
+
if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR)))
return rc;
if (ap_should_client_block(r)) {
@@ -303,6 +307,9 @@
rpos += rsize;
}
}
+ else {
+ rc = DONE;
+ }
return rc;
}

@ -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);
}
}

@ -0,0 +1,103 @@
diff --git a/docs/manual/mod/core.html.en b/docs/manual/mod/core.html.en
index 20d1e5a..e1ec8d0 100644
--- a/docs/manual/mod/core.html.en
+++ b/docs/manual/mod/core.html.en
@@ -2935,12 +2935,19 @@ from the client</td></tr>
<tr><th><a href="directive-dict.html#Status">Status:</a></th><td>Core</td></tr>
<tr><th><a href="directive-dict.html#Module">Module:</a></th><td>core</td></tr>
</table>
- <p>Limit (in bytes) on maximum size of an XML-based request
- body. A value of <code>0</code> will disable any checking.</p>
+ <p>Limit (in bytes) on the maximum size of an XML-based request
+ body. A value of <code>0</code> will apply a hard limit (depending on
+ 32bit vs 64bit system) allowing for XML escaping within the bounds of
+ the system addressable memory, but it exists for compatibility only
+ and is not recommended since it does not account for memory consumed
+ elsewhere or concurrent requests, which might result in an overall
+ system out-of-memory.
+ </p>
<p>Example:</p>
- <pre class="prettyprint lang-config">LimitXMLRequestBody 0</pre>
+ <pre class="prettyprint lang-config"># Limit of 1 MiB
+ LimitXMLRequestBody 1073741824</pre>
diff --git a/server/core.c b/server/core.c
index e32613d..8abfa65 100644
--- a/server/core.c
+++ b/server/core.c
@@ -70,6 +70,8 @@
/* LimitXMLRequestBody handling */
#define AP_LIMIT_UNSET ((long) -1)
#define AP_DEFAULT_LIMIT_XML_BODY ((apr_size_t)1000000)
+/* Hard limit for ap_escape_html2() */
+#define AP_MAX_LIMIT_XML_BODY ((apr_size_t)(APR_SIZE_MAX / 6 - 1))
#define AP_MIN_SENDFILE_BYTES (256)
@@ -3689,6 +3691,11 @@ static const char *set_limit_xml_req_body(cmd_parms *cmd, void *conf_,
if (conf->limit_xml_body < 0)
return "LimitXMLRequestBody requires a non-negative integer.";
+ /* zero is AP_MAX_LIMIT_XML_BODY (implicitly) */
+ if ((apr_size_t)conf->limit_xml_body > AP_MAX_LIMIT_XML_BODY)
+ return apr_psprintf(cmd->pool, "LimitXMLRequestBody must not exceed "
+ "%" APR_SIZE_T_FMT, AP_MAX_LIMIT_XML_BODY);
+
return NULL;
}
@@ -3777,6 +3784,8 @@ AP_DECLARE(apr_size_t) ap_get_limit_xml_body(const request_rec *r)
conf = ap_get_core_module_config(r->per_dir_config);
if (conf->limit_xml_body == AP_LIMIT_UNSET)
return AP_DEFAULT_LIMIT_XML_BODY;
+ if (conf->limit_xml_body == 0)
+ return AP_MAX_LIMIT_XML_BODY;
return (apr_size_t)conf->limit_xml_body;
}
diff --git a/server/util.c b/server/util.c
index 2a5dd04..eefdafa 100644
--- a/server/util.c
+++ b/server/util.c
@@ -2037,11 +2037,14 @@ AP_DECLARE(char *) ap_escape_urlencoded(apr_pool_t *p, const char *buffer)
AP_DECLARE(char *) ap_escape_html2(apr_pool_t *p, const char *s, int toasc)
{
- int i, j;
+ apr_size_t i, j;
char *x;
/* first, count the number of extra characters */
- for (i = 0, j = 0; s[i] != '\0'; i++)
+ for (i = 0, j = 0; s[i] != '\0'; i++) {
+ if (i + j > APR_SIZE_MAX - 6) {
+ abort();
+ }
if (s[i] == '<' || s[i] == '>')
j += 3;
else if (s[i] == '&')
@@ -2050,6 +2053,7 @@ AP_DECLARE(char *) ap_escape_html2(apr_pool_t *p, const char *s, int toasc)
j += 5;
else if (toasc && !apr_isascii(s[i]))
j += 5;
+ }
if (j == 0)
return apr_pstrmemdup(p, s, i);
diff --git a/server/util_xml.c b/server/util_xml.c
index 4845194..22806fa 100644
--- a/server/util_xml.c
+++ b/server/util_xml.c
@@ -85,7 +85,7 @@ AP_DECLARE(int) ap_xml_parse_input(request_rec * r, apr_xml_doc **pdoc)
}
total_read += len;
- if (limit_xml_body && total_read > limit_xml_body) {
+ if (total_read > limit_xml_body) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00539)
"XML request body is larger than the configured "
"limit of %lu", (unsigned long)limit_xml_body);

@ -0,0 +1,377 @@
diff --git a/modules/filters/libsed.h b/modules/filters/libsed.h
index 76cbc0c..0256b1e 100644
--- a/modules/filters/libsed.h
+++ b/modules/filters/libsed.h
@@ -60,7 +60,7 @@ struct sed_label_s {
};
typedef apr_status_t (sed_err_fn_t)(void *data, const char *error);
-typedef apr_status_t (sed_write_fn_t)(void *ctx, char *buf, int sz);
+typedef apr_status_t (sed_write_fn_t)(void *ctx, char *buf, apr_size_t sz);
typedef struct sed_commands_s sed_commands_t;
#define NWFILES 11 /* 10 plus one for standard output */
@@ -69,7 +69,7 @@ struct sed_commands_s {
sed_err_fn_t *errfn;
void *data;
- unsigned lsize;
+ apr_size_t lsize;
char *linebuf;
char *lbend;
const char *saveq;
@@ -116,15 +116,15 @@ struct sed_eval_s {
apr_int64_t lnum;
void *fout;
- unsigned lsize;
+ apr_size_t lsize;
char *linebuf;
char *lspend;
- unsigned hsize;
+ apr_size_t hsize;
char *holdbuf;
char *hspend;
- unsigned gsize;
+ apr_size_t gsize;
char *genbuf;
char *lcomend;
@@ -160,7 +160,7 @@ apr_status_t sed_init_eval(sed_eval_t *eval, sed_commands_t *commands,
sed_err_fn_t *errfn, void *data,
sed_write_fn_t *writefn, apr_pool_t *p);
apr_status_t sed_reset_eval(sed_eval_t *eval, sed_commands_t *commands, sed_err_fn_t *errfn, void *data);
-apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, int bufsz, void *fout);
+apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, apr_size_t bufsz, void *fout);
apr_status_t sed_eval_file(sed_eval_t *eval, apr_file_t *fin, void *fout);
apr_status_t sed_finalize_eval(sed_eval_t *eval, void *f);
void sed_destroy_eval(sed_eval_t *eval);
diff --git a/modules/filters/mod_sed.c b/modules/filters/mod_sed.c
index 346c210..8595e41 100644
--- a/modules/filters/mod_sed.c
+++ b/modules/filters/mod_sed.c
@@ -51,7 +51,7 @@ typedef struct sed_filter_ctxt
apr_bucket_brigade *bbinp;
char *outbuf;
char *curoutbuf;
- int bufsize;
+ apr_size_t bufsize;
apr_pool_t *tpool;
int numbuckets;
} sed_filter_ctxt;
@@ -100,7 +100,7 @@ static void alloc_outbuf(sed_filter_ctxt* ctx)
/* append_bucket
* Allocate a new bucket from buf and sz and append to ctx->bb
*/
-static apr_status_t append_bucket(sed_filter_ctxt* ctx, char* buf, int sz)
+static apr_status_t append_bucket(sed_filter_ctxt* ctx, char* buf, apr_size_t sz)
{
apr_status_t status = APR_SUCCESS;
apr_bucket *b;
@@ -133,7 +133,7 @@ static apr_status_t append_bucket(sed_filter_ctxt* ctx, char* buf, int sz)
*/
static apr_status_t flush_output_buffer(sed_filter_ctxt *ctx)
{
- int size = ctx->curoutbuf - ctx->outbuf;
+ apr_size_t size = ctx->curoutbuf - ctx->outbuf;
char *out;
apr_status_t status = APR_SUCCESS;
if ((ctx->outbuf == NULL) || (size <=0))
@@ -147,12 +147,12 @@ static apr_status_t flush_output_buffer(sed_filter_ctxt *ctx)
/* This is a call back function. When libsed wants to generate the output,
* this function will be invoked.
*/
-static apr_status_t sed_write_output(void *dummy, char *buf, int sz)
+static apr_status_t sed_write_output(void *dummy, char *buf, apr_size_t sz)
{
/* dummy is basically filter context. Context is passed during invocation
* of sed_eval_buffer
*/
- int remainbytes = 0;
+ apr_size_t remainbytes = 0;
apr_status_t status = APR_SUCCESS;
sed_filter_ctxt *ctx = (sed_filter_ctxt *) dummy;
if (ctx->outbuf == NULL) {
@@ -168,21 +168,29 @@ static apr_status_t sed_write_output(void *dummy, char *buf, int sz)
}
/* buffer is now full */
status = append_bucket(ctx, ctx->outbuf, ctx->bufsize);
- /* old buffer is now used so allocate new buffer */
- alloc_outbuf(ctx);
- /* if size is bigger than the allocated buffer directly add to output
- * brigade */
- if ((status == APR_SUCCESS) && (sz >= ctx->bufsize)) {
- char* newbuf = apr_pmemdup(ctx->tpool, buf, sz);
- status = append_bucket(ctx, newbuf, sz);
- /* pool might get clear after append_bucket */
- if (ctx->outbuf == NULL) {
+ if (status == APR_SUCCESS) {
+ /* if size is bigger than the allocated buffer directly add to output
+ * brigade */
+ if (sz >= ctx->bufsize) {
+ char* newbuf = apr_pmemdup(ctx->tpool, buf, sz);
+ status = append_bucket(ctx, newbuf, sz);
+ if (status == APR_SUCCESS) {
+ /* old buffer is now used so allocate new buffer */
+ alloc_outbuf(ctx);
+ }
+ else {
+ clear_ctxpool(ctx);
+ }
+ }
+ else {
+ /* old buffer is now used so allocate new buffer */
alloc_outbuf(ctx);
+ memcpy(ctx->curoutbuf, buf, sz);
+ ctx->curoutbuf += sz;
}
}
else {
- memcpy(ctx->curoutbuf, buf, sz);
- ctx->curoutbuf += sz;
+ clear_ctxpool(ctx);
}
}
else {
diff --git a/modules/filters/sed1.c b/modules/filters/sed1.c
index be03506..67a8d06 100644
--- a/modules/filters/sed1.c
+++ b/modules/filters/sed1.c
@@ -71,7 +71,7 @@ static apr_status_t dosub(sed_eval_t *eval, char *rhsbuf, int n,
static char *place(sed_eval_t *eval, char *asp, char *al1, char *al2);
static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc,
step_vars_storage *step_vars);
-static apr_status_t wline(sed_eval_t *eval, char *buf, int sz);
+static apr_status_t wline(sed_eval_t *eval, char *buf, apr_size_t sz);
static apr_status_t arout(sed_eval_t *eval);
static void eval_errf(sed_eval_t *eval, const char *fmt, ...)
@@ -92,11 +92,11 @@ static void eval_errf(sed_eval_t *eval, const char *fmt, ...)
* grow_buffer
*/
static void grow_buffer(apr_pool_t *pool, char **buffer,
- char **spend, unsigned int *cursize,
- unsigned int newsize)
+ char **spend, apr_size_t *cursize,
+ apr_size_t newsize)
{
char* newbuffer = NULL;
- int spendsize = 0;
+ apr_size_t spendsize = 0;
if (*cursize >= newsize)
return;
/* Avoid number of times realloc is called. It could cause huge memory
@@ -124,7 +124,7 @@ static void grow_buffer(apr_pool_t *pool, char **buffer,
/*
* grow_line_buffer
*/
-static void grow_line_buffer(sed_eval_t *eval, int newsize)
+static void grow_line_buffer(sed_eval_t *eval, apr_size_t newsize)
{
grow_buffer(eval->pool, &eval->linebuf, &eval->lspend,
&eval->lsize, newsize);
@@ -133,7 +133,7 @@ static void grow_line_buffer(sed_eval_t *eval, int newsize)
/*
* grow_hold_buffer
*/
-static void grow_hold_buffer(sed_eval_t *eval, int newsize)
+static void grow_hold_buffer(sed_eval_t *eval, apr_size_t newsize)
{
grow_buffer(eval->pool, &eval->holdbuf, &eval->hspend,
&eval->hsize, newsize);
@@ -142,7 +142,7 @@ static void grow_hold_buffer(sed_eval_t *eval, int newsize)
/*
* grow_gen_buffer
*/
-static void grow_gen_buffer(sed_eval_t *eval, int newsize,
+static void grow_gen_buffer(sed_eval_t *eval, apr_size_t newsize,
char **gspend)
{
if (gspend == NULL) {
@@ -156,9 +156,9 @@ static void grow_gen_buffer(sed_eval_t *eval, int newsize,
/*
* appendmem_to_linebuf
*/
-static void appendmem_to_linebuf(sed_eval_t *eval, const char* sz, int len)
+static void appendmem_to_linebuf(sed_eval_t *eval, const char* sz, apr_size_t len)
{
- unsigned int reqsize = (eval->lspend - eval->linebuf) + len;
+ apr_size_t reqsize = (eval->lspend - eval->linebuf) + len;
if (eval->lsize < reqsize) {
grow_line_buffer(eval, reqsize);
}
@@ -169,21 +169,36 @@ static void appendmem_to_linebuf(sed_eval_t *eval, const char* sz, int len)
/*
* append_to_linebuf
*/
-static void append_to_linebuf(sed_eval_t *eval, const char* sz)
+static void append_to_linebuf(sed_eval_t *eval, const char* sz,
+ step_vars_storage *step_vars)
{
- int len = strlen(sz);
+ apr_size_t len = strlen(sz);
+ char *old_linebuf = eval->linebuf;
/* Copy string including null character */
appendmem_to_linebuf(eval, sz, len + 1);
--eval->lspend; /* lspend will now point to NULL character */
+ /* Sync step_vars after a possible linebuf expansion */
+ if (step_vars && old_linebuf != eval->linebuf) {
+ if (step_vars->loc1) {
+ step_vars->loc1 = step_vars->loc1 - old_linebuf + eval->linebuf;
+ }
+ if (step_vars->loc2) {
+ step_vars->loc2 = step_vars->loc2 - old_linebuf + eval->linebuf;
+ }
+ if (step_vars->locs) {
+ step_vars->locs = step_vars->locs - old_linebuf + eval->linebuf;
+ }
+ }
}
/*
* copy_to_linebuf
*/
-static void copy_to_linebuf(sed_eval_t *eval, const char* sz)
+static void copy_to_linebuf(sed_eval_t *eval, const char* sz,
+ step_vars_storage *step_vars)
{
eval->lspend = eval->linebuf;
- append_to_linebuf(eval, sz);
+ append_to_linebuf(eval, sz, step_vars);
}
/*
@@ -191,8 +206,8 @@ static void copy_to_linebuf(sed_eval_t *eval, const char* sz)
*/
static void append_to_holdbuf(sed_eval_t *eval, const char* sz)
{
- int len = strlen(sz);
- unsigned int reqsize = (eval->hspend - eval->holdbuf) + len + 1;
+ apr_size_t len = strlen(sz);
+ apr_size_t reqsize = (eval->hspend - eval->holdbuf) + len + 1;
if (eval->hsize <= reqsize) {
grow_hold_buffer(eval, reqsize);
}
@@ -215,8 +230,8 @@ static void copy_to_holdbuf(sed_eval_t *eval, const char* sz)
*/
static void append_to_genbuf(sed_eval_t *eval, const char* sz, char **gspend)
{
- int len = strlen(sz);
- unsigned int reqsize = (*gspend - eval->genbuf) + len + 1;
+ apr_size_t len = strlen(sz);
+ apr_size_t reqsize = (*gspend - eval->genbuf) + len + 1;
if (eval->gsize < reqsize) {
grow_gen_buffer(eval, reqsize, gspend);
}
@@ -230,8 +245,8 @@ static void append_to_genbuf(sed_eval_t *eval, const char* sz, char **gspend)
*/
static void copy_to_genbuf(sed_eval_t *eval, const char* sz)
{
- int len = strlen(sz);
- unsigned int reqsize = len + 1;
+ apr_size_t len = strlen(sz);
+ apr_size_t reqsize = len + 1;
if (eval->gsize < reqsize) {
grow_gen_buffer(eval, reqsize, NULL);
}
@@ -353,7 +368,7 @@ apr_status_t sed_eval_file(sed_eval_t *eval, apr_file_t *fin, void *fout)
/*
* sed_eval_buffer
*/
-apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, int bufsz, void *fout)
+apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, apr_size_t bufsz, void *fout)
{
apr_status_t rv;
@@ -383,7 +398,7 @@ apr_status_t sed_eval_buffer(sed_eval_t *eval, const char *buf, int bufsz, void
while (bufsz) {
char *n;
- int llen;
+ apr_size_t llen;
n = memchr(buf, '\n', bufsz);
if (n == NULL)
@@ -442,7 +457,7 @@ 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, "");
+ append_to_linebuf(eval, "", NULL);
}
*eval->lspend = '\0';
@@ -666,7 +681,7 @@ static apr_status_t dosub(sed_eval_t *eval, char *rhsbuf, int n,
lp = step_vars->loc2;
step_vars->loc2 = sp - eval->genbuf + eval->linebuf;
append_to_genbuf(eval, lp, &sp);
- copy_to_linebuf(eval, eval->genbuf);
+ copy_to_linebuf(eval, eval->genbuf, step_vars);
return rv;
}
@@ -676,8 +691,8 @@ static apr_status_t dosub(sed_eval_t *eval, char *rhsbuf, int n,
static char *place(sed_eval_t *eval, char *asp, char *al1, char *al2)
{
char *sp = asp;
- int n = al2 - al1;
- unsigned int reqsize = (sp - eval->genbuf) + n + 1;
+ apr_size_t n = al2 - al1;
+ apr_size_t reqsize = (sp - eval->genbuf) + n + 1;
if (eval->gsize < reqsize) {
grow_gen_buffer(eval, reqsize, &sp);
@@ -735,7 +750,7 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc,
}
p1++;
- copy_to_linebuf(eval, p1);
+ copy_to_linebuf(eval, p1, step_vars);
eval->jflag++;
break;
@@ -745,12 +760,12 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc,
break;
case GCOM:
- copy_to_linebuf(eval, eval->holdbuf);
+ copy_to_linebuf(eval, eval->holdbuf, step_vars);
break;
case CGCOM:
- append_to_linebuf(eval, "\n");
- append_to_linebuf(eval, eval->holdbuf);
+ append_to_linebuf(eval, "\n", step_vars);
+ append_to_linebuf(eval, eval->holdbuf, step_vars);
break;
case HCOM:
@@ -881,7 +896,7 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc,
if (rv != APR_SUCCESS)
return rv;
}
- append_to_linebuf(eval, "\n");
+ append_to_linebuf(eval, "\n", step_vars);
eval->pending = ipc->next;
break;
@@ -956,7 +971,7 @@ static apr_status_t command(sed_eval_t *eval, sed_reptr_t *ipc,
case XCOM:
copy_to_genbuf(eval, eval->linebuf);
- copy_to_linebuf(eval, eval->holdbuf);
+ copy_to_linebuf(eval, eval->holdbuf, step_vars);
copy_to_holdbuf(eval, eval->genbuf);
break;
@@ -1013,7 +1028,7 @@ static apr_status_t arout(sed_eval_t *eval)
/*
* wline
*/
-static apr_status_t wline(sed_eval_t *eval, char *buf, int sz)
+static apr_status_t wline(sed_eval_t *eval, char *buf, apr_size_t sz)
{
apr_status_t rv = APR_SUCCESS;
rv = eval->writefn(eval->fout, buf, sz);

@ -0,0 +1,26 @@
diff --git a/modules/proxy/mod_proxy_ajp.c b/modules/proxy/mod_proxy_ajp.c
index 6faabea..058b03f 100644
--- a/modules/proxy/mod_proxy_ajp.c
+++ b/modules/proxy/mod_proxy_ajp.c
@@ -249,9 +249,18 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
/* read the first bloc of data */
input_brigade = apr_brigade_create(p, r->connection->bucket_alloc);
tenc = apr_table_get(r->headers_in, "Transfer-Encoding");
- if (tenc && (strcasecmp(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);

@ -0,0 +1,47 @@
diff --git a/include/http_protocol.h b/include/http_protocol.h
index e1572dc..8ed77ac 100644
--- a/include/http_protocol.h
+++ b/include/http_protocol.h
@@ -439,7 +439,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 a554970..ea461a2 100644
--- a/server/protocol.c
+++ b/server/protocol.c
@@ -2107,6 +2107,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;

@ -0,0 +1,22 @@
diff --git a/server/util.c b/server/util.c
index eefdafa..45051b7 100644
--- a/server/util.c
+++ b/server/util.c
@@ -186,7 +186,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 ((!str[x]) && (expected[y] != '*'))
@@ -210,7 +210,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] != '*')

@ -0,0 +1,90 @@
diff --git a/docs/manual/mod/core.html.en b/docs/manual/mod/core.html.en
index e1ec8d0..833fa7b 100644
--- a/docs/manual/mod/core.html.en
+++ b/docs/manual/mod/core.html.en
@@ -2748,16 +2748,16 @@ subrequests</td></tr>
<tr><th><a href="directive-dict.html#Description">Description:</a></th><td>Restricts the total size of the HTTP request body sent
from the client</td></tr>
<tr><th><a href="directive-dict.html#Syntax">Syntax:</a></th><td><code>LimitRequestBody <var>bytes</var></code></td></tr>
-<tr><th><a href="directive-dict.html#Default">Default:</a></th><td><code>LimitRequestBody 0</code></td></tr>
+<tr><th><a href="directive-dict.html#Default">Default:</a></th><td><code>LimitRequestBody 1073741824</code></td></tr>
<tr><th><a href="directive-dict.html#Context">Context:</a></th><td>server config, virtual host, directory, .htaccess</td></tr>
<tr><th><a href="directive-dict.html#Override">Override:</a></th><td>All</td></tr>
<tr><th><a href="directive-dict.html#Status">Status:</a></th><td>Core</td></tr>
<tr><th><a href="directive-dict.html#Module">Module:</a></th><td>core</td></tr>
+<tr><th><a href="directive-dict.html#Compatibility">Compatibility:</a></th><td>In Apache HTTP Server 2.4.53 and earlier, the default value
+ was 0 (unlimited)</td></tr>
</table>
- <p>This directive specifies the number of <var>bytes</var> 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.</p>
+ <p>This directive specifies the number of <var>bytes</var>
+ that are allowed in a request body. A value of <var>0</var> means unlimited.</p>
<p>The <code class="directive">LimitRequestBody</code> directive allows
the user to set a limit on the allowed size of an HTTP request
@@ -2783,12 +2783,6 @@ from the client</td></tr>
<pre class="prettyprint lang-config">LimitRequestBody 102400</pre>
-
- <div class="note"><p>For a full description of how this directive is interpreted by
- proxy requests, see the <code class="module"><a href="../mod/mod_proxy.html">mod_proxy</a></code> documentation.</p>
- </div>
-
-
</div>
<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
<div class="directive-section"><h2><a name="LimitRequestFields" id="LimitRequestFields">LimitRequestFields</a> <a name="limitrequestfields" id="limitrequestfields">Directive</a></h2>
diff --git a/docs/manual/mod/mod_proxy.html.en b/docs/manual/mod/mod_proxy.html.en
index 2cc6ace..c9e4634 100644
--- a/docs/manual/mod/mod_proxy.html.en
+++ b/docs/manual/mod/mod_proxy.html.en
@@ -459,9 +459,6 @@ ProxyPass "/examples" "http://backend.example.com/examples" timeout=10</pre>
Content-Length header, but the server is configured to filter incoming
request bodies.</p>
- <p><code class="directive"><a href="../mod/core.html#limitrequestbody">LimitRequestBody</a></code> only applies to
- request bodies that the server will spool to disk</p>
-
</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
<div class="section">
<h2><a name="x-headers" id="x-headers">Reverse Proxy Request Headers</a></h2>
diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c
index 6bedcac..393343a 100644
--- a/modules/http/http_filters.c
+++ b/modules/http/http_filters.c
@@ -1710,6 +1710,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;
@@ -1748,6 +1749,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/server/core.c b/server/core.c
index a0bfaad..6556f20 100644
--- a/server/core.c
+++ b/server/core.c
@@ -65,7 +65,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)

@ -0,0 +1,541 @@
diff --git a/modules/filters/mod_sed.c b/modules/filters/mod_sed.c
index 8595e41..9b99a6b 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)
{
@@ -276,7 +276,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;
@@ -301,9 +301,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.
@@ -325,63 +325,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);
@@ -432,7 +421,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
@@ -474,8 +463,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 67a8d06..047f49b 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:

@ -0,0 +1,233 @@
diff --git a/modules/lua/lua_request.c b/modules/lua/lua_request.c
index ba63584..c1ba74a 100644
--- a/modules/lua/lua_request.c
+++ b/modules/lua/lua_request.c
@@ -2193,23 +2193,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);
@@ -2239,35 +2236,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;
@@ -2277,12 +2267,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 */
@@ -2293,40 +2278,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",
@@ -2335,46 +2305,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];
@@ -2386,14 +2337,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;
}
}

@ -0,0 +1,229 @@
diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c
index efcc6ca..6626ea0 100644
--- a/modules/proxy/proxy_util.c
+++ b/modules/proxy/proxy_util.c
@@ -3631,12 +3631,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;
@@ -3672,6 +3674,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) {
@@ -3693,7 +3741,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)
@@ -3707,21 +3755,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) {
@@ -3788,8 +3822,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.
*/
@@ -3799,8 +3831,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
@@ -3812,10 +3845,27 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
}
}
+ /* 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);
- if (ap_proxy_clear_connection(r, r->headers_in) < 0) {
- return HTTP_BAD_REQUEST;
- }
creds = apr_table_get(r->notes, "proxy-basic-creds");
if (creds) {
@@ -3827,55 +3877,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 */
- || !strcasecmp(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
- */
- || !strcasecmp(headers_in[counter].key, "Keep-Alive")
- || !strcasecmp(headers_in[counter].key, "TE")
- || !strcasecmp(headers_in[counter].key, "Trailer")
- || !strcasecmp(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 (!strcasecmp(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 (!strcasecmp(headers_in[counter].key, "Transfer-Encoding")) {
- *old_te_val = headers_in[counter].val;
- continue;
- }
- if (!strcasecmp(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 ( !strcasecmp(headers_in[counter].key, "If-Match")
- || !strcasecmp(headers_in[counter].key, "If-Modified-Since")
- || !strcasecmp(headers_in[counter].key, "If-Range")
- || !strcasecmp(headers_in[counter].key, "If-Unmodified-Since")
- || !strcasecmp(headers_in[counter].key, "If-None-Match")) {
- continue;
- }
+ || headers_in[counter].val == NULL) {
+ continue;
}
buf = apr_pstrcat(p, headers_in[counter].key, ": ",
@@ -3886,11 +3889,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,

@ -0,0 +1,23 @@
From 5efc9507c487c37dfe2a279a4a0335cad701cd5f Mon Sep 17 00:00:00 2001
From: Eric Covener <covener@apache.org>
Date: Tue, 10 Jan 2023 13:19:07 +0000
Subject: [PATCH] cleanup on error
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1906540 13f79535-47bb-0310-9956-ffa450edef68
---
modules/proxy/mod_proxy_ajp.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/modules/proxy/mod_proxy_ajp.c b/modules/proxy/mod_proxy_ajp.c
index 9cd7adbcbbf..07f37392d88 100644
--- a/modules/proxy/mod_proxy_ajp.c
+++ b/modules/proxy/mod_proxy_ajp.c
@@ -255,6 +255,8 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10396)
"%s Transfer-Encoding is not supported",
tenc);
+ /* We had a failure: Close connection to backend */
+ conn->close = 1;
return HTTP_INTERNAL_SERVER_ERROR;
}
} else {

@ -0,0 +1,129 @@
From 8b6d55f6a047acf62675e32606b037f5eea8ccc7 Mon Sep 17 00:00:00 2001
From: Eric Covener <covener@apache.org>
Date: Tue, 10 Jan 2023 13:20:09 +0000
Subject: [PATCH] Merge r1906539 from trunk:
fail on bad header
Submitted By: covener
Reviewed By: covener, rpluem, gbechis
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1906541 13f79535-47bb-0310-9956-ffa450edef68
---
modules/proxy/mod_proxy_http.c | 46 ++++++++++++++++++++--------------
server/protocol.c | 2 ++
2 files changed, 29 insertions(+), 19 deletions(-)
diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c
index d74ae054ac9..ec4e7fb06b5 100644
--- a/modules/proxy/mod_proxy_http.c
+++ b/modules/proxy/mod_proxy_http.c
@@ -788,7 +788,7 @@ static void process_proxy_header(request_rec *r, proxy_dir_conf *c,
* any sense at all, since we depend on buffer still containing
* what was read by ap_getline() upon return.
*/
-static void ap_proxy_read_headers(request_rec *r, request_rec *rr,
+static apr_status_t ap_proxy_read_headers(request_rec *r, request_rec *rr,
char *buffer, int size,
conn_rec *c, int *pread_len)
{
@@ -820,19 +820,26 @@ static void ap_proxy_read_headers(request_rec *r, request_rec *rr,
rc = ap_proxygetline(tmp_bb, buffer, size, rr,
AP_GETLINE_FOLD | AP_GETLINE_NOSPC_EOL, &len);
- if (len <= 0)
- break;
- if (APR_STATUS_IS_ENOSPC(rc)) {
- /* The header could not fit in the provided buffer, warn.
- * XXX: falls through with the truncated header, 5xx instead?
- */
- int trunc = (len > 128 ? 128 : len) / 2;
- ap_log_rerror(APLOG_MARK, APLOG_WARNING, rc, r, APLOGNO(10124)
- "header size is over the limit allowed by "
- "ResponseFieldSize (%d bytes). "
- "Bad response header: '%.*s[...]%s'",
- size, trunc, buffer, buffer + len - trunc);
+ if (rc != APR_SUCCESS) {
+ if (APR_STATUS_IS_ENOSPC(rc)) {
+ int trunc = (len > 128 ? 128 : len) / 2;
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, rc, r, APLOGNO(10124)
+ "header size is over the limit allowed by "
+ "ResponseFieldSize (%d bytes). "
+ "Bad response header: '%.*s[...]%s'",
+ size, trunc, buffer, buffer + len - trunc);
+ }
+ else {
+ ap_log_rerror(APLOG_MARK, APLOG_WARNING, rc, r, APLOGNO(10404)
+ "Error reading headers from backend");
+ }
+ r->headers_out = NULL;
+ return rc;
+ }
+
+ if (len <= 0) {
+ break;
}
else {
ap_log_rerror(APLOG_MARK, APLOG_TRACE4, 0, r, "%s", buffer);
@@ -855,7 +862,7 @@ static void ap_proxy_read_headers(request_rec *r, request_rec *rr,
if (psc->badopt == bad_error) {
/* Nope, it wasn't even an extra HTTP header. Give up. */
r->headers_out = NULL;
- return;
+ return APR_EINVAL;
}
else if (psc->badopt == bad_body) {
/* if we've already started loading headers_out, then
@@ -869,13 +876,13 @@ static void ap_proxy_read_headers(request_rec *r, request_rec *rr,
"in headers returned by %s (%s)",
r->uri, r->method);
*pread_len = len;
- return;
+ return APR_SUCCESS;
}
else {
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01099)
"No HTTP headers returned by %s (%s)",
r->uri, r->method);
- return;
+ return APR_SUCCESS;
}
}
}
@@ -905,6 +912,7 @@ static void ap_proxy_read_headers(request_rec *r, request_rec *rr,
process_proxy_header(r, dconf, buffer, value);
saw_headers = 1;
}
+ return APR_SUCCESS;
}
@@ -1218,10 +1226,10 @@ int ap_proxy_http_process_response(proxy_http_req_t *req)
"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);
+ rc = ap_proxy_read_headers(r, backend->r, buffer, response_field_size,
+ origin, &pread_len);
- if (r->headers_out == NULL) {
+ if (rc != APR_SUCCESS || r->headers_out == NULL) {
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, r, APLOGNO(01106)
"bad HTTP/%d.%d header returned by %s (%s)",
major, minor, r->uri, r->method);
diff --git a/server/protocol.c b/server/protocol.c
index 7adc7f75c10..6f9540ad1de 100644
--- a/server/protocol.c
+++ b/server/protocol.c
@@ -508,6 +508,8 @@ AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n,
/* PR#43039: We shouldn't accept NULL bytes within the line */
bytes_handled = strlen(*s);
if (bytes_handled < *read) {
+ ap_log_data(APLOG_MARK, APLOG_DEBUG, ap_server_conf,
+ "NULL bytes in header", *s, *read, 0);
*read = bytes_handled;
if (rv == APR_SUCCESS) {
rv = APR_EINVAL;

@ -0,0 +1,586 @@
diff --git a/docs/manual/mod/mod_rewrite.html.en b/docs/manual/mod/mod_rewrite.html.en
index 815ec72..2b8ed35 100644
--- a/docs/manual/mod/mod_rewrite.html.en
+++ b/docs/manual/mod/mod_rewrite.html.en
@@ -1265,7 +1265,17 @@ cannot use <code>$N</code> in the substitution string!
<td>B</td>
<td>Escape non-alphanumeric characters in backreferences <em>before</em>
applying the transformation. <em><a href="../rewrite/flags.html#flag_b">details ...</a></em></td>
- </tr>
+ </tr>
+<tr class="odd">
+ <td>BCTLS</td>
+ <td>Like [B], but only escape control characters and spaces.
+ <em><a href="../rewrite/flags.html#flag_bctls">details ...</a></em></td>
+</tr>
+ <tr>
+ <td>BNE</td>
+ <td>Characters of [B] or [BCTLS] which should <strong>not</strong> be escaped.
+ <em><a href="../rewrite/flags.html#flag_bne">details ...</a></em></td>
+ </tr>
<tr class="odd">
<td>backrefnoplus|BNP</td>
<td>If backreferences are being escaped, spaces should be escaped to
diff --git a/docs/manual/rewrite/flags.html.en b/docs/manual/rewrite/flags.html.en
index 80d0759..734809a 100644
--- a/docs/manual/rewrite/flags.html.en
+++ b/docs/manual/rewrite/flags.html.en
@@ -85,10 +85,6 @@ of how you might use them.</p>
<h2><a name="flag_b" id="flag_b">B (escape backreferences)</a></h2>
<p>The [B] flag instructs <code class="directive"><a href="../mod/mod_rewrite.html#rewriterule">RewriteRule</a></code> to escape non-alphanumeric
characters before applying the transformation.</p>
-<p>In 2.4.26 and later, you can limit the escaping to specific characters
-in backreferences by listing them: <code>[B=#?;]</code>. Note: The space
-character can be used in the list of characters to escape, but it cannot be
-the last character in the list.</p>
<p><code>mod_rewrite</code> has to unescape URLs before mapping them,
so backreferences are unescaped at the time they are applied.
@@ -120,6 +116,20 @@ when the backend may break if presented with an unescaped URL.</p>
<p>An alternative to this flag is using a <code class="directive"><a href="../mod/mod_rewrite.html#rewritecond">RewriteCond</a></code> to capture against %{THE_REQUEST} which will capture
strings in the encoded form.</p>
+
+<p>In 2.4.26 and later, you can limit the escaping to specific characters
+in backreferences by listing them: <code>[B=#?;]</code>. Note: The space
+character can be used in the list of characters to escape, but you must quote
+the entire third argument of <code class="directive"><a href="../mod/mod_rewrite.html#rewriterule">RewriteRule</a></code>
+and the space must not be the last character in the list.</p>
+
+<pre class="prettyprint lang-config"># Escape spaces and question marks. The quotes around the final argument
+# are required when a space is included.
+RewriteRule "^search/(.*)$" "/search.php?term=$1" "[B= ?]"</pre>
+
+<p>To limit the characters escaped this way, see <a href="#flag_bne">#flag_bne</a>
+and <a href="#flag_bctls">#flag_bctls</a></p>
+
</div><div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
<div class="section">
<h2><a name="flag_bnp" id="flag_bnp">BNP|backrefnoplus (don't escape space to +)</a></h2>
diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c
index 38dbb24..b71c67c 100644
--- a/modules/mappers/mod_rewrite.c
+++ b/modules/mappers/mod_rewrite.c
@@ -101,6 +101,8 @@
#include "mod_rewrite.h"
#include "ap_expr.h"
+#include "test_char.h"
+
static ap_dbd_t *(*dbd_acquire)(request_rec*) = NULL;
static void (*dbd_prepare)(server_rec*, const char*, const char*) = NULL;
static const char* really_last_key = "rewrite_really_last";
@@ -168,6 +170,8 @@ static const char* really_last_key = "rewrite_really_last";
#define RULEFLAG_END (1<<17)
#define RULEFLAG_ESCAPENOPLUS (1<<18)
#define RULEFLAG_QSLAST (1<<19)
+#define RULEFLAG_QSNONE (1<<20) /* programattic only */
+#define RULEFLAG_ESCAPECTLS (1<<21)
/* return code of the rewrite rule
* the result may be escaped - or not
@@ -321,7 +325,8 @@ typedef struct {
data_item *cookie; /* added cookies */
int skip; /* number of next rules to skip */
int maxrounds; /* limit on number of loops with N flag */
- char *escapes; /* specific backref escapes */
+ const char *escapes; /* specific backref escapes */
+ const char *noescapes; /* specific backref chars not to escape */
} rewriterule_entry;
typedef struct {
@@ -422,7 +427,9 @@ static const char *rewritemap_mutex_type = "rewrite-map";
/* Optional functions imported from mod_ssl when loaded: */
static APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *rewrite_ssl_lookup = NULL;
static APR_OPTIONAL_FN_TYPE(ssl_is_https) *rewrite_is_https = NULL;
-static char *escape_backref(apr_pool_t *p, const char *path, const char *escapeme, int noplus);
+static char *escape_backref(apr_pool_t *p, const char *path,
+ const char *escapeme, const char *noescapeme,
+ int flags);
/*
* +-------------------------------------------------------+
@@ -645,18 +652,26 @@ static APR_INLINE unsigned char *c2x(unsigned what, unsigned char prefix,
return where;
}
+
/*
* Escapes a backreference in a similar way as php's urlencode does.
* Based on ap_os_escape_path in server/util.c
*/
-static char *escape_backref(apr_pool_t *p, const char *path, const char *escapeme, int noplus) {
- char *copy = apr_palloc(p, 3 * strlen(path) + 3);
+static char *escape_backref(apr_pool_t *p, const char *path,
+ const char *escapeme, const char *noescapeme,
+ int flags)
+{
+ char *copy = apr_palloc(p, 3 * strlen(path) + 1);
const unsigned char *s = (const unsigned char *)path;
unsigned char *d = (unsigned char *)copy;
- unsigned c;
+ int noplus = (flags & RULEFLAG_ESCAPENOPLUS) != 0;
+ int ctls = (flags & RULEFLAG_ESCAPECTLS) != 0;
+ unsigned char c;
while ((c = *s)) {
- if (!escapeme) {
+ if (((ctls ? !TEST_CHAR(c, T_VCHAR_OBSTEXT) : !escapeme)
+ || (escapeme && ap_strchr_c(escapeme, c)))
+ && (!noescapeme || !ap_strchr_c(noescapeme, c))) {
if (apr_isalnum(c) || c == '_') {
*d++ = c;
}
@@ -667,23 +682,8 @@ static char *escape_backref(apr_pool_t *p, const char *path, const char *escapem
d = c2x(c, '%', d);
}
}
- else {
- const char *esc = escapeme;
- while (*esc) {
- if (c == *esc) {
- if (c == ' ' && !noplus) {
- *d++ = '+';
- }
- else {
- d = c2x(c, '%', d);
- }
- break;
- }
- ++esc;
- }
- if (!*esc) {
- *d++ = c;
- }
+ else {
+ *d++ = c;
}
++s;
}
@@ -761,15 +761,24 @@ static char *escape_absolute_uri(apr_pool_t *p, char *uri, unsigned scheme)
ap_escape_uri(p, cp), NULL);
}
+
/*
* split out a QUERY_STRING part from
* the current URI string
*/
-static void splitout_queryargs(request_rec *r, int qsappend, int qsdiscard,
- int qslast)
+static void splitout_queryargs(request_rec *r, int flags)
{
char *q;
int split;
+ int qsappend = flags & RULEFLAG_QSAPPEND;
+ int qsdiscard = flags & RULEFLAG_QSDISCARD;
+ int qslast = flags & RULEFLAG_QSLAST;
+
+ if (flags & RULEFLAG_QSNONE) {
+ rewritelog((r, 2, NULL, "discarding query string, no parse from substitution"));
+ r->args = NULL;
+ return;
+ }
/* don't touch, unless it's a scheme for which a query string makes sense.
* See RFC 1738 and RFC 2368.
@@ -794,7 +803,7 @@ static void splitout_queryargs(request_rec *r, int qsappend, int qsdiscard,
olduri = apr_pstrdup(r->pool, r->filename);
*q++ = '\0';
if (qsappend) {
- if (*q) {
+ if (*q) {
r->args = apr_pstrcat(r->pool, q, "&" , r->args, NULL);
}
}
@@ -802,9 +811,9 @@ static void splitout_queryargs(request_rec *r, int qsappend, int qsdiscard,
r->args = apr_pstrdup(r->pool, q);
}
- if (r->args) {
+ if (r->args) {
len = strlen(r->args);
-
+
if (!len) {
r->args = NULL;
}
@@ -2436,7 +2445,8 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry)
/* escape the backreference */
char *tmp2, *tmp;
tmp = apr_pstrmemdup(pool, bri->source + bri->regmatch[n].rm_so, span);
- tmp2 = escape_backref(pool, tmp, entry->escapes, entry->flags & RULEFLAG_ESCAPENOPLUS);
+ tmp2 = escape_backref(pool, tmp, entry->escapes, entry->noescapes,
+ entry->flags);
rewritelog((ctx->r, 5, ctx->perdir, "escaping backreference '%s' to '%s'",
tmp, tmp2));
@@ -2733,7 +2743,7 @@ static apr_status_t rewritelock_remove(void *data)
* XXX: what an inclined parser. Seems we have to leave it so
* for backwards compat. *sigh*
*/
-static int parseargline(char *str, char **a1, char **a2, char **a3)
+static int parseargline(char *str, char **a1, char **a2, char **a2_end, char **a3)
{
char quote;
@@ -2784,8 +2794,10 @@ static int parseargline(char *str, char **a1, char **a2, char **a3)
if (!*str) {
*a3 = NULL; /* 3rd argument is optional */
+ *a2_end = str;
return 0;
}
+ *a2_end = str;
*str++ = '\0';
while (apr_isspace(*str)) {
@@ -3323,7 +3335,7 @@ static const char *cmd_rewritecond(cmd_parms *cmd, void *in_dconf,
rewrite_server_conf *sconf;
rewritecond_entry *newcond;
ap_regex_t *regexp;
- char *a1 = NULL, *a2 = NULL, *a3 = NULL;
+ char *a1 = NULL, *a2 = NULL, *a2_end, *a3 = NULL;
const char *err;
sconf = ap_get_module_config(cmd->server->module_config, &rewrite_module);
@@ -3341,7 +3353,7 @@ static const char *cmd_rewritecond(cmd_parms *cmd, void *in_dconf,
* of the argument line. So we can use a1 .. a3 without
* copying them again.
*/
- if (parseargline(str, &a1, &a2, &a3)) {
+ if (parseargline(str, &a1, &a2, &a2_end, &a3)) {
return apr_pstrcat(cmd->pool, "RewriteCond: bad argument line '", str,
"'", NULL);
}
@@ -3500,13 +3512,24 @@ static const char *cmd_rewriterule_setflag(apr_pool_t *p, void *_cfg,
case 'B':
if (!*key || !strcasecmp(key, "ackrefescaping")) {
cfg->flags |= RULEFLAG_ESCAPEBACKREF;
- if (val && *val) {
+ if (val && *val) {
cfg->escapes = val;
}
}
+ else if (!strcasecmp(key, "NE")) {
+ if (val && *val) {
+ cfg->noescapes = val;
+ }
+ else {
+ return "flag 'BNE' wants a list of characters (i.e. [BNE=...])";
+ }
+ }
else if (!strcasecmp(key, "NP") || !strcasecmp(key, "ackrefernoplus")) {
cfg->flags |= RULEFLAG_ESCAPENOPLUS;
}
+ else if (!strcasecmp(key, "CTLS")) {
+ cfg->flags |= RULEFLAG_ESCAPECTLS|RULEFLAG_ESCAPEBACKREF;
+ }
else {
++error;
}
@@ -3749,7 +3772,7 @@ static const char *cmd_rewriterule(cmd_parms *cmd, void *in_dconf,
rewrite_server_conf *sconf;
rewriterule_entry *newrule;
ap_regex_t *regexp;
- char *a1 = NULL, *a2 = NULL, *a3 = NULL;
+ char *a1 = NULL, *a2 = NULL, *a2_end, *a3 = NULL;
const char *err;
sconf = ap_get_module_config(cmd->server->module_config, &rewrite_module);
@@ -3763,12 +3786,11 @@ static const char *cmd_rewriterule(cmd_parms *cmd, void *in_dconf,
}
/* parse the argument line ourself */
- if (parseargline(str, &a1, &a2, &a3)) {
+ if (parseargline(str, &a1, &a2, &a2_end, &a3)) {
return apr_pstrcat(cmd->pool, "RewriteRule: bad argument line '", str,
"'", NULL);
}
- /* arg3: optional flags field */
newrule->forced_mimetype = NULL;
newrule->forced_handler = NULL;
newrule->forced_responsecode = HTTP_MOVED_TEMPORARILY;
@@ -3777,6 +3799,9 @@ static const char *cmd_rewriterule(cmd_parms *cmd, void *in_dconf,
newrule->cookie = NULL;
newrule->skip = 0;
newrule->maxrounds = REWRITE_MAX_ROUNDS;
+ newrule->escapes = newrule->noescapes = NULL;
+
+ /* arg3: optional flags field */
if (a3 != NULL) {
if ((err = cmd_parseflagfield(cmd->pool, newrule, a3,
cmd_rewriterule_setflag)) != NULL) {
@@ -3810,6 +3835,17 @@ static const char *cmd_rewriterule(cmd_parms *cmd, void *in_dconf,
newrule->flags |= RULEFLAG_NOSUB;
}
+ if (*(a2_end-1) == '?') {
+ /* a literal ? at the end of the unsubstituted rewrite rule */
+ newrule->flags |= RULEFLAG_QSNONE;
+ *(a2_end-1) = '\0'; /* trailing ? has done its job */
+ }
+ else if (newrule->flags & RULEFLAG_QSDISCARD) {
+ if (NULL == ap_strchr(newrule->output, '?')) {
+ newrule->flags |= RULEFLAG_QSNONE;
+ }
+ }
+
/* now, if the server or per-dir config holds an
* array of RewriteCond entries, we take it for us
* and clear the array
@@ -4215,9 +4251,7 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx)
r->path_info = NULL;
}
- splitout_queryargs(r, p->flags & RULEFLAG_QSAPPEND,
- p->flags & RULEFLAG_QSDISCARD,
- p->flags & RULEFLAG_QSLAST);
+ splitout_queryargs(r, p->flags);
/* Add the previously stripped per-directory location prefix, unless
* (1) it's an absolute URL path and
@@ -4696,8 +4730,25 @@ static int hook_uri2file(request_rec *r)
}
if (rulestatus) {
- unsigned skip;
- apr_size_t flen;
+ unsigned skip_absolute = is_absolute_uri(r->filename, NULL);
+ apr_size_t flen = r->filename ? strlen(r->filename) : 0;
+ int to_proxyreq = (flen > 6 && strncmp(r->filename, "proxy:", 6) == 0);
+ int will_escape = skip_absolute && (rulestatus != ACTION_NOESCAPE);
+
+ if (r->args
+ && !will_escape
+ && *(ap_scan_vchar_obstext(r->args))) {
+ /*
+ * We have a raw control character or a ' ' in r->args.
+ * Correct encoding was missed.
+ * Correct encoding was missed and we're not going to escape
+ * it before returning.
+ */
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10410)
+ "Rewritten query string contains control "
+ "characters or spaces");
+ return HTTP_FORBIDDEN;
+ }
if (ACTION_STATUS == rulestatus) {
int n = r->status;
@@ -4706,8 +4757,7 @@ static int hook_uri2file(request_rec *r)
return n;
}
- flen = r->filename ? strlen(r->filename) : 0;
- if (flen > 6 && strncmp(r->filename, "proxy:", 6) == 0) {
+ if (to_proxyreq) {
/* it should be go on as an internal proxy request */
/* check if the proxy module is enabled, so
@@ -4749,7 +4799,7 @@ static int hook_uri2file(request_rec *r)
r->filename));
return OK;
}
- else if ((skip = is_absolute_uri(r->filename, NULL)) > 0) {
+ else if (skip_absolute > 0) {
int n;
/* it was finally rewritten to a remote URL */
@@ -4757,7 +4807,7 @@ static int hook_uri2file(request_rec *r)
if (rulestatus != ACTION_NOESCAPE) {
rewritelog((r, 1, NULL, "escaping %s for redirect",
r->filename));
- r->filename = escape_absolute_uri(r->pool, r->filename, skip);
+ r->filename = escape_absolute_uri(r->pool, r->filename, skip_absolute);
}
/* append the QUERY_STRING part */
@@ -4981,7 +5031,26 @@ static int hook_fixup(request_rec *r)
*/
rulestatus = apply_rewrite_list(r, dconf->rewriterules, dconf->directory);
if (rulestatus) {
- unsigned skip;
+ unsigned skip_absolute = is_absolute_uri(r->filename, NULL);
+ int to_proxyreq = 0;
+ int will_escape = 0;
+
+ l = strlen(r->filename);
+ to_proxyreq = l > 6 && strncmp(r->filename, "proxy:", 6) == 0;
+ will_escape = skip_absolute && (rulestatus != ACTION_NOESCAPE);
+
+ if (r->args
+ && !will_escape
+ && *(ap_scan_vchar_obstext(r->args))) {
+ /*
+ * We have a raw control character or a ' ' in r->args.
+ * Correct encoding was missed.
+ */
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10411)
+ "Rewritten query string contains control "
+ "characters or spaces");
+ return HTTP_FORBIDDEN;
+ }
if (ACTION_STATUS == rulestatus) {
int n = r->status;
@@ -4990,8 +5059,7 @@ static int hook_fixup(request_rec *r)
return n;
}
- l = strlen(r->filename);
- if (l > 6 && strncmp(r->filename, "proxy:", 6) == 0) {
+ if (to_proxyreq) {
/* it should go on as an internal proxy request */
/* make sure the QUERY_STRING and
@@ -5015,7 +5083,7 @@ static int hook_fixup(request_rec *r)
"%s [OK]", r->filename));
return OK;
}
- else if ((skip = is_absolute_uri(r->filename, NULL)) > 0) {
+ else if (skip_absolute > 0) {
/* it was finally rewritten to a remote URL */
/* because we are in a per-dir context
@@ -5024,7 +5092,7 @@ static int hook_fixup(request_rec *r)
*/
if (dconf->baseurl != NULL) {
/* skip 'scheme://' */
- cp = r->filename + skip;
+ cp = r->filename + skip_absolute;
if ((cp = ap_strchr(cp, '/')) != NULL && *(++cp)) {
rewritelog((r, 2, dconf->directory,
@@ -5069,7 +5137,7 @@ static int hook_fixup(request_rec *r)
if (rulestatus != ACTION_NOESCAPE) {
rewritelog((r, 1, dconf->directory, "escaping %s for redirect",
r->filename));
- r->filename = escape_absolute_uri(r->pool, r->filename, skip);
+ r->filename = escape_absolute_uri(r->pool, r->filename, skip_absolute);
}
/* append the QUERY_STRING part */
diff --git a/modules/proxy/mod_proxy_ajp.c b/modules/proxy/mod_proxy_ajp.c
index cbb0872..873ccf1 100644
--- a/modules/proxy/mod_proxy_ajp.c
+++ b/modules/proxy/mod_proxy_ajp.c
@@ -69,6 +69,16 @@ static int proxy_ajp_canon(request_rec *r, char *url)
path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0,
r->proxyreq);
search = r->args;
+ if (search && *(ap_scan_vchar_obstext(search))) {
+ /*
+ * We have a raw control character or a ' ' in r->args.
+ * Correct encoding was missed.
+ */
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10406)
+ "To be forwarded query string contains control "
+ "characters or spaces");
+ return HTTP_FORBIDDEN;
+ }
}
if (path == NULL)
return HTTP_BAD_REQUEST;
diff --git a/modules/proxy/mod_proxy_balancer.c b/modules/proxy/mod_proxy_balancer.c
index 3a28038..c599e1a 100644
--- a/modules/proxy/mod_proxy_balancer.c
+++ b/modules/proxy/mod_proxy_balancer.c
@@ -106,6 +106,16 @@ static int proxy_balancer_canon(request_rec *r, char *url)
path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0,
r->proxyreq);
search = r->args;
+ if (search && *(ap_scan_vchar_obstext(search))) {
+ /*
+ * We have a raw control character or a ' ' in r->args.
+ * Correct encoding was missed.
+ */
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10407)
+ "To be forwarded query string contains control "
+ "characters or spaces");
+ return HTTP_FORBIDDEN;
+ }
}
if (path == NULL)
return HTTP_BAD_REQUEST;
diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c
index 7573638..fe7b322 100644
--- a/modules/proxy/mod_proxy_http.c
+++ b/modules/proxy/mod_proxy_http.c
@@ -90,6 +90,16 @@ static int proxy_http_canon(request_rec *r, char *url)
path = ap_proxy_canonenc(r->pool, url, strlen(url),
enc_path, 0, r->proxyreq);
search = r->args;
+ if (search && *(ap_scan_vchar_obstext(search))) {
+ /*
+ * We have a raw control character or a ' ' in r->args.
+ * Correct encoding was missed.
+ */
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10408)
+ "To be forwarded query string contains control "
+ "characters or spaces");
+ return HTTP_FORBIDDEN;
+ }
}
break;
case PROXYREQ_PROXY:
diff --git a/modules/proxy/mod_proxy_wstunnel.c b/modules/proxy/mod_proxy_wstunnel.c
index e005a94..f5e27d9 100644
--- a/modules/proxy/mod_proxy_wstunnel.c
+++ b/modules/proxy/mod_proxy_wstunnel.c
@@ -77,6 +77,16 @@ static int proxy_wstunnel_canon(request_rec *r, char *url)
path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, 0,
r->proxyreq);
search = r->args;
+ if (search && *(ap_scan_vchar_obstext(search))) {
+ /*
+ * We have a raw control character or a ' ' in r->args.
+ * Correct encoding was missed.
+ */
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10409)
+ "To be forwarded query string contains control "
+ "characters or spaces");
+ return HTTP_FORBIDDEN;
+ }
}
if (path == NULL)
return HTTP_BAD_REQUEST;
diff --git a/server/gen_test_char.c b/server/gen_test_char.c
index 48ae6f4..6a153a3 100644
--- a/server/gen_test_char.c
+++ b/server/gen_test_char.c
@@ -169,5 +169,15 @@ int main(int argc, char *argv[])
printf("\n};\n");
+
+ printf(
+ "/* we assume the folks using this ensure 0 <= c < 256... which means\n"
+ " * you need a cast to (unsigned char) first, you can't just plug a\n"
+ " * char in here and get it to work, because if char is signed then it\n"
+ " * will first be sign extended.\n"
+ " */\n"
+ "#define TEST_CHAR(c, f) (test_char_table[(unsigned char)(c)] & (f))\n"
+ );
+
return 0;
}
diff --git a/server/util.c b/server/util.c
index 45051b7..9d897d4 100644
--- a/server/util.c
+++ b/server/util.c
@@ -74,13 +74,6 @@
*/
#include "test_char.h"
-/* we assume the folks using this ensure 0 <= c < 256... which means
- * you need a cast to (unsigned char) first, you can't just plug a
- * char in here and get it to work, because if char is signed then it
- * will first be sign extended.
- */
-#define TEST_CHAR(c, f) (test_char_table[(unsigned char)(c)] & (f))
-
/* Win32/NetWare/OS2 need to check for both forward and back slashes
* in ap_getparents() and ap_escape_url.
*/

@ -0,0 +1,89 @@
diff --git a/modules/proxy/mod_proxy_uwsgi.c b/modules/proxy/mod_proxy_uwsgi.c
index 9dcbed1..a1b564d 100644
--- a/modules/proxy/mod_proxy_uwsgi.c
+++ b/modules/proxy/mod_proxy_uwsgi.c
@@ -304,18 +304,16 @@ static int uwsgi_response(request_rec *r, proxy_conn_rec * backend,
pass_bb = apr_brigade_create(r->pool, c->bucket_alloc);
len = ap_getline(buffer, sizeof(buffer), rp, 1);
-
if (len <= 0) {
- /* oops */
+ /* invalid or empty */
return HTTP_INTERNAL_SERVER_ERROR;
}
-
backend->worker->s->read += len;
-
- if (len >= sizeof(buffer) - 1) {
- /* oops */
+ if ((apr_size_t)len >= sizeof(buffer)) {
+ /* too long */
return HTTP_INTERNAL_SERVER_ERROR;
}
+
/* Position of http status code */
if (apr_date_checkmask(buffer, "HTTP/#.# ###*")) {
status_start = 9;
@@ -324,8 +322,8 @@ static int uwsgi_response(request_rec *r, proxy_conn_rec * backend,
status_start = 7;
}
else {
- /* oops */
- return HTTP_INTERNAL_SERVER_ERROR;
+ /* not HTTP */
+ return HTTP_BAD_GATEWAY;
}
status_end = status_start + 3;
@@ -345,21 +343,44 @@ static int uwsgi_response(request_rec *r, proxy_conn_rec * backend,
}
r->status_line = apr_pstrdup(r->pool, &buffer[status_start]);
- /* start parsing headers */
+ /* parse headers */
while ((len = ap_getline(buffer, sizeof(buffer), rp, 1)) > 0) {
+ if ((apr_size_t)len >= sizeof(buffer)) {
+ /* too long */
+ len = -1;
+ break;
+ }
value = strchr(buffer, ':');
- /* invalid header skip */
- if (!value)
- continue;
- *value = '\0';
- ++value;
+ if (!value) {
+ /* invalid header */
+ len = -1;
+ break;
+ }
+ *value++ = '\0';
+ if (*ap_scan_http_token(buffer)) {
+ /* invalid name */
+ len = -1;
+ break;
+ }
while (apr_isspace(*value))
++value;
for (end = &value[strlen(value) - 1];
end > value && apr_isspace(*end); --end)
*end = '\0';
+ if (*ap_scan_http_field_content(value)) {
+ /* invalid value */
+ len = -1;
+ break;
+ }
apr_table_add(r->headers_out, buffer, value);
}
+ if (len < 0) {
+ /* Reset headers, but not to NULL because things below the chain expect
+ * this to be non NULL e.g. the ap_content_length_filter.
+ */
+ r->headers_out = apr_table_make(r->pool, 1);
+ return HTTP_BAD_GATEWAY;
+ }
if ((buf = apr_table_get(r->headers_out, "Content-Type"))) {
ap_set_content_type(r, apr_pstrdup(r->pool, buf));

@ -0,0 +1,11 @@
--- a/modules/core/mod_macro.c 2023/10/16 06:19:16 1912992
+++ b/modules/core/mod_macro.c 2023/10/16 06:38:32 1912993
@@ -483,7 +483,7 @@
for (i = 0; i < contents->nelts; i++) {
const char *errmsg;
/* copy the line and substitute macro parameters */
- strncpy(line, ((char **) contents->elts)[i], MAX_STRING_LEN - 1);
+ apr_cpystrn(line, ((char **) contents->elts)[i], MAX_STRING_LEN);
errmsg = substitute_macro_args(line, MAX_STRING_LEN,
macro, replacements, used);
if (errmsg) {

@ -0,0 +1,74 @@
diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c
index 393343a..16cb23c 100644
--- a/modules/http/http_filters.c
+++ b/modules/http/http_filters.c
@@ -1348,6 +1348,9 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f,
*/
apr_table_clear(r->headers_out);
apr_table_clear(r->err_headers_out);
+ r->content_type = r->content_encoding = NULL;
+ r->content_languages = NULL;
+ r->clength = r->chunked = 0;
apr_brigade_cleanup(b);
/* Don't recall ap_die() if we come back here (from its own internal
@@ -1364,8 +1367,6 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f,
APR_BRIGADE_INSERT_TAIL(b, e);
e = apr_bucket_eos_create(c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(b, e);
- r->content_type = r->content_encoding = NULL;
- r->content_languages = NULL;
ap_set_content_length(r, 0);
recursive_error = 1;
}
@@ -1392,6 +1393,7 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f,
if (!apr_is_empty_table(r->err_headers_out)) {
r->headers_out = apr_table_overlay(r->pool, r->err_headers_out,
r->headers_out);
+ apr_table_clear(r->err_headers_out);
}
/*
@@ -1411,6 +1413,17 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f,
fixup_vary(r);
}
+
+ /*
+ * Control cachability for non-cacheable responses if not already set by
+ * some other part of the server configuration.
+ */
+ if (r->no_cache && !apr_table_get(r->headers_out, "Expires")) {
+ char *date = apr_palloc(r->pool, APR_RFC822_DATE_LEN);
+ ap_recent_rfc822_date(date, r->request_time);
+ apr_table_addn(r->headers_out, "Expires", date);
+ }
+
/*
* Now remove any ETag response header field if earlier processing
* says so (such as a 'FileETag None' directive).
@@ -1423,6 +1436,7 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f,
basic_http_header_check(r, &protocol);
ap_set_keepalive(r);
+ /* 204/304 responses don't have content related headers */
if (AP_STATUS_IS_HEADER_ONLY(r->status)) {
apr_table_unset(r->headers_out, "Transfer-Encoding");
apr_table_unset(r->headers_out, "Content-Length");
@@ -1465,16 +1479,6 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f,
apr_table_setn(r->headers_out, "Content-Language", field);
}
- /*
- * Control cachability for non-cacheable responses if not already set by
- * some other part of the server configuration.
- */
- if (r->no_cache && !apr_table_get(r->headers_out, "Expires")) {
- char *date = apr_palloc(r->pool, APR_RFC822_DATE_LEN);
- ap_recent_rfc822_date(date, r->request_time);
- apr_table_addn(r->headers_out, "Expires", date);
- }
-
/* This is a hack, but I can't find anyway around it. The idea is that
* we don't want to send out 0 Content-Lengths if it is a head request.
* This happens when modules try to outsmart the server, and return

@ -0,0 +1,172 @@
diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c
index a6df1b8..94ec87e 100644
--- a/modules/proxy/mod_proxy.c
+++ b/modules/proxy/mod_proxy.c
@@ -968,6 +968,7 @@ static int proxy_fixup(request_rec *r)
return OK; /* otherwise; we've done the best we can */
}
+
/* Send a redirection if the request contains a hostname which is not */
/* fully qualified, i.e. doesn't have a domain name appended. Some proxy */
/* servers like Netscape's allow this and access hosts from the local */
@@ -1021,7 +1022,7 @@ static int proxy_handler(request_rec *r)
ap_get_module_config(sconf, &proxy_module);
apr_array_header_t *proxies = conf->proxies;
struct proxy_remote *ents = (struct proxy_remote *) proxies->elts;
- int i, rc, access_status;
+ int rc = DECLINED, access_status, i;
int direct_connect = 0;
const char *str;
apr_int64_t maxfwd;
@@ -1036,19 +1037,28 @@ static int proxy_handler(request_rec *r)
return DECLINED;
}
- if (!r->proxyreq) {
- /* We may have forced the proxy handler via config or .htaccess */
- if (r->handler &&
- strncmp(r->handler, "proxy:", 6) == 0 &&
- strncmp(r->filename, "proxy:", 6) != 0) {
- r->proxyreq = PROXYREQ_REVERSE;
- r->filename = apr_pstrcat(r->pool, r->handler, r->filename, NULL);
+ /* We may have forced the proxy handler via config or .htaccess */
+ if (!r->proxyreq && r->handler && strncmp(r->handler, "proxy:", 6) == 0) {
+ char *old_filename = r->filename;
+
+ r->proxyreq = PROXYREQ_REVERSE;
+ r->filename = apr_pstrcat(r->pool, r->handler, r->filename, NULL);
+
+ /* Still need to fixup/canonicalize r->filename */
+ rc = ap_proxy_fixup_uds_filename(r);
+ if (rc <= OK) {
+ rc = proxy_fixup(r);
}
- else {
- return DECLINED;
+ if (rc != OK) {
+ r->filename = old_filename;
+ r->proxyreq = 0;
}
- } else if (strncmp(r->filename, "proxy:", 6) != 0) {
- return DECLINED;
+ }
+ else if (r->proxyreq && strncmp(r->filename, "proxy:", 6) == 0) {
+ rc = OK;
+ }
+ if (rc != OK) {
+ return rc;
}
/* handle max-forwards / OPTIONS / TRACE */
diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h
index e5c0a26..354f395 100644
--- a/modules/proxy/mod_proxy.h
+++ b/modules/proxy/mod_proxy.h
@@ -921,6 +921,14 @@ PROXY_DECLARE(proxy_balancer_shared *) ap_proxy_find_balancershm(ap_slotmem_prov
proxy_balancer *balancer,
unsigned int *index);
+/*
+ * Strip the UDS part of r->filename if any, and put the UDS path in
+ * r->notes ("uds_path")
+ * @param r current request
+ * @return OK if fixed up, DECLINED if not UDS, or an HTTP_XXX error
+ */
+PROXY_DECLARE(int) ap_proxy_fixup_uds_filename(request_rec *r);
+
/**
* Get the most suitable worker and/or balancer for the request
* @param worker worker used for processing request
diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c
index 6626ea0..6244e74 100644
--- a/modules/proxy/proxy_util.c
+++ b/modules/proxy/proxy_util.c
@@ -2098,7 +2098,7 @@ 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 int fix_uds_filename(request_rec *r, char **url)
+PROXY_DECLARE(int) ap_proxy_fixup_uds_filename(request_rec *r)
{
char *uds_url = r->filename + 6, *origin_url;
@@ -2106,7 +2106,6 @@ static int fix_uds_filename(request_rec *r, char **url)
!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;
@@ -2122,21 +2121,20 @@ static int fix_uds_filename(request_rec *r, char **url)
if (!uds_path) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10292)
"Invalid proxy UDS filename (%s)", r->filename);
- return 0;
+ return HTTP_BAD_REQUEST;
}
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);
+ "*: fixup UDS from %s: %s (%s)",
+ r->filename, origin_url, uds_path);
+
+ /* Overwrite the UDS part in place */
+ memmove(uds_url, origin_url, strlen(origin_url) + 1);
+ return OK;
}
- return 1;
+ return DECLINED;
}
PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker,
@@ -2155,9 +2153,6 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker,
ap_log_rerror(APLOG_MARK, APLOG_TRACE2, 0, r,
"%s: found worker %s for %s",
(*worker)->s->scheme, (*worker)->s->name, *url);
- if (!forward && !fix_uds_filename(r, url)) {
- return HTTP_INTERNAL_SERVER_ERROR;
- }
access_status = OK;
}
else if (forward) {
@@ -2187,9 +2182,6 @@ 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");
- if (!fix_uds_filename(r, url)) {
- return HTTP_INTERNAL_SERVER_ERROR;
- }
}
}
}
@@ -2199,6 +2191,20 @@ PROXY_DECLARE(int) ap_proxy_pre_request(proxy_worker **worker,
"all workers are busy. Unable to serve %s", *url);
access_status = HTTP_SERVICE_UNAVAILABLE;
}
+
+ if (access_status == OK && r->proxyreq == PROXYREQ_REVERSE) {
+ int rc = ap_proxy_fixup_uds_filename(r);
+ if (ap_is_HTTP_ERROR(rc)) {
+ return rc;
+ }
+ /* If the URL has changed in r->filename, take everything after
+ * the "proxy:" prefix.
+ */
+ if (rc == OK) {
+ *url = apr_pstrdup(r->pool, r->filename + 6);
+ }
+ }
+
return access_status;
}

@ -0,0 +1,439 @@
diff --git a/docs/manual/mod/mod_rewrite.html.en b/docs/manual/mod/mod_rewrite.html.en
index 2b8ed35..b7f1c31 100644
--- a/docs/manual/mod/mod_rewrite.html.en
+++ b/docs/manual/mod/mod_rewrite.html.en
@@ -1403,6 +1403,16 @@ cannot use <code>$N</code> in the substitution string!
<td>Force the <a class="glossarylink" href="../glossary.html#mime-type" title="see glossary">MIME-type</a> of the target file
to be the specified type. <em><a href="../rewrite/flags.html#flag_t">details ...</a></em></td>
</tr>
+<tr>
+ <td>UnsafeAllow3F</td>
+ <td>Allows substitutions from URL's that may be unsafe.
+ <em><a href="../rewrite/flags.html#flag_unsafe_allow_3f">details ...</a></em></td>
+ </tr>
+<tr>
+ <td>UnsafePrefixStat</td>
+ <td>Allows potentially unsafe substitutions from a leading variable or backreference to a filesystem path.
+ <em><a href="../rewrite/flags.html#flag_unsafe_prefix_stat">details ...</a></em></td>
+ </tr>
</table>
<div class="note"><h3>Home directory expansion</h3>
diff --git a/docs/manual/rewrite/flags.html.en b/docs/manual/rewrite/flags.html.en
index 734809a..30d549d 100644
--- a/docs/manual/rewrite/flags.html.en
+++ b/docs/manual/rewrite/flags.html.en
@@ -768,6 +768,30 @@ re-processing (including subsequent rounds of mod_rewrite processing).
The <code>L</code> flag can be useful in this context to end the
<em>current</em> round of mod_rewrite processing.</p>
+</div>
+
+<div class="section">
+<h2><a name="flag_unsafe_allow_3f" id="flag_unsafe_allow_3f">UnsafeAllow3F</a></h2>
+
+<p>
+Setting this flag is required to allow a rewrite to continue If the
+HTTP request being written has an encoded question mark, '%3f', and the
+rewritten result has a '?' in the substiution. This protects from a malicious
+URL taking advantage of a capture and re-substitution of the encoded
+question mark.</p>
+
+</div>
+<div class="section">
+<h2><a name="flag_unsafe_prefix_status" id="flag_unsafe_prefix_status">UnsafePrefixStat</a></h2>
+
+<p>
+Setting this flag is required in server-scoped substitutions
+start with a variable or backreference and resolve to a filesystem path.
+These substitutions are not prefixed with the document root.
+This protects from a malicious URL causing the expanded substitution to
+map to an unexpected filesystem location.
+</p>
+
</div></div>
<div class="bottomlang">
<p><span>Available Languages: </span><a href="../en/rewrite/flags.html" title="English">&nbsp;en&nbsp;</a> |
diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c
index b71c67c..797f093 100644
--- a/modules/mappers/mod_rewrite.c
+++ b/modules/mappers/mod_rewrite.c
@@ -172,6 +172,8 @@ static const char* really_last_key = "rewrite_really_last";
#define RULEFLAG_QSLAST (1<<19)
#define RULEFLAG_QSNONE (1<<20) /* programattic only */
#define RULEFLAG_ESCAPECTLS (1<<21)
+#define RULEFLAG_UNSAFE_PREFIX_STAT (1<<22)
+#define RULEFLAG_UNSAFE_ALLOW3F (1<<23)
/* return code of the rewrite rule
* the result may be escaped - or not
@@ -179,7 +181,7 @@ static const char* really_last_key = "rewrite_really_last";
#define ACTION_NORMAL (1<<0)
#define ACTION_NOESCAPE (1<<1)
#define ACTION_STATUS (1<<2)
-
+#define ACTION_STATUS_SET (1<<3)
#define MAPTYPE_TXT (1<<0)
#define MAPTYPE_DBM (1<<1)
@@ -203,6 +205,7 @@ static const char* really_last_key = "rewrite_really_last";
#define OPTION_IGNORE_INHERIT (1<<8)
#define OPTION_IGNORE_CONTEXT_INFO (1<<9)
#define OPTION_LEGACY_PREFIX_DOCROOT (1<<10)
+#define OPTION_UNSAFE_PREFIX_STAT (1<<12)
#ifndef RAND_MAX
#define RAND_MAX 32767
@@ -296,6 +299,14 @@ typedef enum {
CONDPAT_AP_EXPR
} pattern_type;
+typedef enum {
+ RULE_RC_NOMATCH = 0, /* the rule didn't match */
+ RULE_RC_MATCH = 1, /* a matching rule w/ substitution */
+ RULE_RC_NOSUB = 2, /* a matching rule w/ no substitution */
+ RULE_RC_STATUS_SET = 3 /* a matching rule that has set an HTTP error
+ to be returned in r->status */
+} rule_return_type;
+
typedef struct {
char *input; /* Input string of RewriteCond */
char *pattern; /* the RegExp pattern string */
@@ -927,10 +938,15 @@ static void fully_qualify_uri(request_rec *r)
return;
}
+static int startsWith(request_rec *r, const char *haystack, const char *needle) {
+ int rc = (ap_strstr_c(haystack, needle) == haystack);
+ rewritelog((r, 5, NULL, "prefix_stat startsWith(%s, %s) %d", haystack, needle, rc));
+ return rc;
+}
/*
- * stat() only the first segment of a path
+ * stat() only the first segment of a path, and only if it matches the output of the last matching rule
*/
-static int prefix_stat(const char *path, apr_pool_t *pool)
+static int prefix_stat(request_rec *r, const char *path, apr_pool_t *pool, rewriterule_entry *lastsub)
{
const char *curpath = path;
const char *root;
@@ -964,10 +980,36 @@ static int prefix_stat(const char *path, apr_pool_t *pool)
apr_finfo_t sb;
if (apr_stat(&sb, statpath, APR_FINFO_MIN, pool) == APR_SUCCESS) {
- return 1;
+ if (!lastsub) {
+ rewritelog((r, 3, NULL, "prefix_stat no lastsub subst prefix %s", statpath));
+ return 1;
+ }
+
+ rewritelog((r, 3, NULL, "prefix_stat compare statpath %s and lastsub output %s STATOK %d ",
+ statpath, lastsub->output, lastsub->flags & RULEFLAG_UNSAFE_PREFIX_STAT));
+ if (lastsub->flags & RULEFLAG_UNSAFE_PREFIX_STAT) {
+ return 1;
+ }
+ else {
+ const char *docroot = ap_document_root(r);
+ const char *context_docroot = ap_context_document_root(r);
+ /*
+ * As an example, path (r->filename) is /var/foo/bar/baz.html
+ * even if the flag is not set, we can accept a rule that
+ * began with a literal /var (stapath), or if the entire path
+ * starts with the docroot or context document root
+ */
+ if (startsWith(r, lastsub->output, statpath) ||
+ startsWith(r, path, docroot) ||
+ ((docroot != context_docroot) &&
+ startsWith(r, path, context_docroot))) {
+ return 1;
+ }
+ }
}
}
+ /* prefix will be added */
return 0;
}
@@ -3046,6 +3088,9 @@ static const char *cmd_rewriteoptions(cmd_parms *cmd,
else if (!strcasecmp(w, "legacyprefixdocroot")) {
options |= OPTION_LEGACY_PREFIX_DOCROOT;
}
+ else if (!strcasecmp(w, "UnsafePrefixStat")) {
+ options |= OPTION_UNSAFE_PREFIX_STAT;
+ }
else {
return apr_pstrcat(cmd->pool, "RewriteOptions: unknown option '",
w, "'", NULL);
@@ -3752,6 +3797,18 @@ static const char *cmd_rewriterule_setflag(apr_pool_t *p, void *_cfg,
++error;
}
break;
+ case 'u':
+ case 'U':
+ if (!strcasecmp(key, "nsafePrefixStat")){
+ cfg->flags |= (RULEFLAG_UNSAFE_PREFIX_STAT);
+ }
+ else if(!strcasecmp(key, "nsafeAllow3F")) {
+ cfg->flags |= RULEFLAG_UNSAFE_ALLOW3F;
+ }
+ else {
+ ++error;
+ }
+ break;
default:
++error;
break;
@@ -4102,7 +4159,8 @@ static APR_INLINE void force_type_handler(rewriterule_entry *p,
/*
* Apply a single RewriteRule
*/
-static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx)
+static rule_return_type apply_rewrite_rule(rewriterule_entry *p,
+ rewrite_ctx *ctx)
{
ap_regmatch_t regmatch[AP_MAX_REG_MATCH];
apr_array_header_t *rewriteconds;
@@ -4153,7 +4211,7 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx)
rc = !ap_regexec(p->regexp, ctx->uri, AP_MAX_REG_MATCH, regmatch, 0);
if (! (( rc && !(p->flags & RULEFLAG_NOTMATCH)) ||
(!rc && (p->flags & RULEFLAG_NOTMATCH)) ) ) {
- return 0;
+ return RULE_RC_NOMATCH;
}
/* It matched, wow! Now it's time to prepare the context structure for
@@ -4204,7 +4262,7 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx)
}
}
else if (!rc) {
- return 0;
+ return RULE_RC_NOMATCH;
}
/* If some HTTP header was involved in the condition, remember it
@@ -4224,6 +4282,15 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx)
newuri = do_expand(p->output, ctx, p);
rewritelog((r, 2, ctx->perdir, "rewrite '%s' -> '%s'", ctx->uri,
newuri));
+ if (!(p->flags & RULEFLAG_UNSAFE_ALLOW3F) &&
+ ap_strcasestr(r->unparsed_uri, "%3f") &&
+ ap_strchr_c(newuri, '?')) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO()
+ "Unsafe URL with %%3f URL rewritten without "
+ "UnsafeAllow3F");
+ r->status = HTTP_FORBIDDEN;
+ return RULE_RC_STATUS_SET;
+ }
}
/* expand [E=var:val] and [CO=<cookie>] */
@@ -4241,7 +4308,7 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx)
r->status = p->forced_responsecode;
}
- return 2;
+ return RULE_RC_NOSUB;
}
/* Now adjust API's knowledge about r->filename and r->args */
@@ -4293,7 +4360,7 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx)
r->filename));
r->filename = apr_pstrcat(r->pool, "proxy:", r->filename, NULL);
- return 1;
+ return RULE_RC_MATCH;
}
/* If this rule is explicitly forced for HTTP redirection
@@ -4308,7 +4375,7 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx)
r->filename));
r->status = p->forced_responsecode;
- return 1;
+ return RULE_RC_MATCH;
}
/* Special Rewriting Feature: Self-Reduction
@@ -4330,7 +4397,7 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx)
"with %s", p->forced_responsecode, r->filename));
r->status = p->forced_responsecode;
- return 1;
+ return RULE_RC_MATCH;
}
/* Finally remember the forced mime-type */
@@ -4339,7 +4406,7 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx)
/* Puuhhhhhhhh... WHAT COMPLICATED STUFF ;_)
* But now we're done for this particular rule.
*/
- return 1;
+ return RULE_RC_MATCH;
}
/*
@@ -4347,13 +4414,13 @@ static int apply_rewrite_rule(rewriterule_entry *p, rewrite_ctx *ctx)
* i.e. a list of rewrite rules
*/
static int apply_rewrite_list(request_rec *r, apr_array_header_t *rewriterules,
- char *perdir)
+ char *perdir, rewriterule_entry **lastsub)
{
rewriterule_entry *entries;
rewriterule_entry *p;
int i;
int changed;
- int rc;
+ rule_return_type rc;
int s;
rewrite_ctx *ctx;
int round = 1;
@@ -4361,6 +4428,7 @@ static int apply_rewrite_list(request_rec *r, apr_array_header_t *rewriterules,
ctx = apr_palloc(r->pool, sizeof(*ctx));
ctx->perdir = perdir;
ctx->r = r;
+ *lastsub = NULL;
/*
* Iterate over all existing rules
@@ -4388,7 +4456,12 @@ static int apply_rewrite_list(request_rec *r, apr_array_header_t *rewriterules,
ctx->vary = NULL;
rc = apply_rewrite_rule(p, ctx);
- if (rc) {
+ if (rc != RULE_RC_NOMATCH) {
+
+ if (!(p->flags & RULEFLAG_NOSUB)) {
+ rewritelog((r, 2, perdir, "setting lastsub to rule with output %s", p->output));
+ *lastsub = p;
+ }
/* Catch looping rules with pathinfo growing unbounded */
if ( strlen( r->filename ) > 2*r->server->limit_req_line ) {
@@ -4408,6 +4481,12 @@ static int apply_rewrite_list(request_rec *r, apr_array_header_t *rewriterules,
apr_table_merge(r->headers_out, "Vary", ctx->vary);
}
+
+ /* Error while evaluating rule, r->status set */
+ if (RULE_RC_STATUS_SET == rc) {
+ return ACTION_STATUS_SET;
+ }
+
/*
* The rule sets the response code (implies match-only)
*/
@@ -4418,7 +4497,7 @@ static int apply_rewrite_list(request_rec *r, apr_array_header_t *rewriterules,
/*
* Indicate a change if this was not a match-only rule.
*/
- if (rc != 2) {
+ if (rc != RULE_RC_NOSUB) {
changed = ((p->flags & RULEFLAG_NOESCAPE)
? ACTION_NOESCAPE : ACTION_NORMAL);
}
@@ -4607,6 +4686,7 @@ static int hook_uri2file(request_rec *r)
int rulestatus;
void *skipdata;
const char *oargs;
+ rewriterule_entry *lastsub = NULL;
/*
* retrieve the config structures
@@ -4718,7 +4798,7 @@ static int hook_uri2file(request_rec *r)
/*
* now apply the rules ...
*/
- rulestatus = apply_rewrite_list(r, conf->rewriterules, NULL);
+ rulestatus = apply_rewrite_list(r, conf->rewriterules, NULL, &lastsub);
apr_table_setn(r->notes, "mod_rewrite_rewritten",
apr_psprintf(r->pool,"%d",rulestatus));
}
@@ -4756,6 +4836,9 @@ static int hook_uri2file(request_rec *r)
r->status = HTTP_OK;
return n;
}
+ else if (ACTION_STATUS_SET == rulestatus) {
+ return r->status;
+ }
if (to_proxyreq) {
/* it should be go on as an internal proxy request */
@@ -4875,23 +4958,29 @@ static int hook_uri2file(request_rec *r)
return HTTP_BAD_REQUEST;
}
- /* if there is no valid prefix, we call
- * the translator from the core and
- * prefix the filename with document_root
+ /* We have r->filename as a path in a server-context rewrite without
+ * the PT flag. The historical behavior is to treat it as a verbatim
+ * filesystem path iff the first component of the path exists and is
+ * readable by httpd. Otherwise, it is interpreted as DocumentRoot
+ * relative.
*
* NOTICE:
* We cannot leave out the prefix_stat because
- * - when we always prefix with document_root
- * then no absolute path can be created, e.g. via
- * emulating a ScriptAlias directive, etc.
- * - when we always NOT prefix with document_root
+ * - If we always prefix with document_root
+ * then no absolute path can could ever be used in
+ * a substitution. e.g. emulating an Alias.
+ * - If we never prefix with document_root
* then the files under document_root have to
* be references directly and document_root
* gets never used and will be a dummy parameter -
- * this is also bad
+ * this is also bad.
+ * - Later addition: This part is questionable.
+ * If we had never prefixed, users would just
+ * need %{DOCUMENT_ROOT} in substitutions or the
+ * [PT] flag.
*
* BUT:
- * Under real Unix systems this is no problem,
+ * Under real Unix systems this is no perf problem,
* because we only do stat() on the first directory
* and this gets cached by the kernel for along time!
*/
@@ -4900,7 +4989,9 @@ static int hook_uri2file(request_rec *r)
uri_reduced = apr_table_get(r->notes, "mod_rewrite_uri_reduced");
}
- if (!prefix_stat(r->filename, r->pool) || uri_reduced != NULL) {
+ if (!prefix_stat(r, r->filename, r->pool,
+ conf->options & OPTION_UNSAFE_PREFIX_STAT ? NULL : lastsub)
+ || uri_reduced != NULL) {
int res;
char *tmp = r->uri;
@@ -4945,6 +5036,7 @@ static int hook_fixup(request_rec *r)
char *ofilename, *oargs;
int is_proxyreq;
void *skipdata;
+ rewriterule_entry *lastsub;
dconf = (rewrite_perdir_conf *)ap_get_module_config(r->per_dir_config,
&rewrite_module);
@@ -5029,7 +5121,7 @@ static int hook_fixup(request_rec *r)
/*
* now apply the rules ...
*/
- rulestatus = apply_rewrite_list(r, dconf->rewriterules, dconf->directory);
+ rulestatus = apply_rewrite_list(r, dconf->rewriterules, dconf->directory, &lastsub);
if (rulestatus) {
unsigned skip_absolute = is_absolute_uri(r->filename, NULL);
int to_proxyreq = 0;
@@ -5058,6 +5150,9 @@ static int hook_fixup(request_rec *r)
r->status = HTTP_OK;
return n;
}
+ else if (ACTION_STATUS_SET == rulestatus) {
+ return r->status;
+ }
if (to_proxyreq) {
/* it should go on as an internal proxy request */

@ -0,0 +1,301 @@
-- backported bnotes needed by this CVE fix from https://svn.apache.org/viewvc?view=revision&revision=1887384
-- modified it a little bit so it actually doesn't store bnotes into req structure to not brake compatibility
-- but it stores AP_REQUEST_TRUSTED_CT info into r->notes
diff --git a/include/http_protocol.h b/include/http_protocol.h
index 8ed77ac..81949ca 100644
--- a/include/http_protocol.h
+++ b/include/http_protocol.h
@@ -402,6 +402,17 @@ AP_DECLARE(void) ap_clear_method_list(ap_method_list_t *l);
*/
AP_DECLARE(void) ap_set_content_type(request_rec *r, const char *ct);
+/**
+ * Set the content type for this request (r->content_type).
+ * @param r The current request
+ * @param ct The new content type
+ * @param trusted If non-zero, The content-type should come from a
+ * trusted source such as server configuration rather
+ * than application output.
+ * for the AddOutputFilterByType directive to work correctly.
+ */
+AP_DECLARE(void) ap_set_content_type_ex(request_rec *r, const char *ct, int trusted);
+
/**
* Set the Accept-Ranges header for this response
* @param r The current request
diff --git a/include/httpd.h b/include/httpd.h
index 99f7f04..d8746c1 100644
--- a/include/httpd.h
+++ b/include/httpd.h
@@ -645,6 +645,7 @@ struct ap_method_list_t {
/** the array used for extension methods */
apr_array_header_t *method_list;
};
+/** @} */
/**
* @defgroup module_magic Module Magic mime types
@@ -715,6 +716,31 @@ struct ap_method_list_t {
/** @} // values_request_rec_used_path_info */
+#define AP_REQUEST_TRUSTED_CT "rh-bnotes-trusted-ct"
+
+/**
+ * This is a convenience macro to ease with getting specific request
+ * binary notes.
+ */
+#define AP_REQUEST_GET_BNOTE(r, mask) (apr_table_get(r->notes, mask) ? 1 : 0)
+
+/**
+ * This is a convenience macro to ease with setting specific request
+ * binary notes.
+ */
+#define AP_REQUEST_SET_BNOTE(r, mask, val) do { \
+ if (val) \
+ apr_table_setn(r->notes, mask, "1"); \
+ else \
+ apr_table_unset(r->notes, mask); \
+} while (0)
+
+/**
+ * Returns true if the content-type field is from a trusted source
+ */
+#define AP_REQUEST_IS_TRUSTED_CT(r) \
+ (!!AP_REQUEST_GET_BNOTE((r), AP_REQUEST_TRUSTED_CT))
+/** @} */
/*
* Things which may vary per file-lookup WITHIN a request ---
diff --git a/modules/http/http_protocol.c b/modules/http/http_protocol.c
index df862e0..d003aea 100644
--- a/modules/http/http_protocol.c
+++ b/modules/http/http_protocol.c
@@ -1077,8 +1077,14 @@ AP_DECLARE(void) ap_set_content_type(request_rec *r, const char *ct)
}
else if (!r->content_type || strcmp(r->content_type, ct)) {
r->content_type = ct;
+ AP_REQUEST_SET_BNOTE(r, AP_REQUEST_TRUSTED_CT, 0);
}
}
+AP_DECLARE(void) ap_set_content_type_ex(request_rec *r, const char *ct, int trusted)
+{
+ ap_set_content_type(r, ct);
+ AP_REQUEST_SET_BNOTE(r, AP_REQUEST_TRUSTED_CT, trusted ? AP_REQUEST_TRUSTED_CT : 0);
+}
AP_DECLARE(void) ap_set_accept_ranges(request_rec *r)
{
diff --git a/modules/http/mod_mime.c b/modules/http/mod_mime.c
index 28c53be..4cd1c48 100644
--- a/modules/http/mod_mime.c
+++ b/modules/http/mod_mime.c
@@ -759,7 +759,7 @@ static int find_ct(request_rec *r)
int found_metadata = 0;
if (r->finfo.filetype == APR_DIR) {
- ap_set_content_type(r, DIR_MAGIC_TYPE);
+ ap_set_content_type_ex(r, DIR_MAGIC_TYPE, 1);
return OK;
}
@@ -837,7 +837,7 @@ static int find_ct(request_rec *r)
if (exinfo == NULL || !exinfo->forced_type) {
if ((type = apr_hash_get(mime_type_extensions, ext,
APR_HASH_KEY_STRING)) != NULL) {
- ap_set_content_type(r, (char*) type);
+ ap_set_content_type_ex(r, (char*) type, 1);
found = 1;
}
}
@@ -846,7 +846,7 @@ static int find_ct(request_rec *r)
/* empty string is treated as special case for RemoveType */
if (exinfo->forced_type && *exinfo->forced_type) {
- ap_set_content_type(r, exinfo->forced_type);
+ ap_set_content_type_ex(r, exinfo->forced_type, 1);
found = 1;
}
@@ -951,33 +951,33 @@ static int find_ct(request_rec *r)
memcpy(tmp, ctp->subtype, ctp->subtype_len);
tmp += ctp->subtype_len;
*tmp = 0;
- ap_set_content_type(r, base_content_type);
+ ap_set_content_type_ex(r, base_content_type, AP_REQUEST_IS_TRUSTED_CT(r));
while (pp != NULL) {
if (charset && !strcmp(pp->attr, "charset")) {
if (!override) {
- ap_set_content_type(r,
+ ap_set_content_type_ex(r,
apr_pstrcat(r->pool,
r->content_type,
"; charset=",
charset,
- NULL));
+ NULL), AP_REQUEST_IS_TRUSTED_CT(r));
override = 1;
}
}
else {
- ap_set_content_type(r,
+ ap_set_content_type_ex(r,
apr_pstrcat(r->pool,
r->content_type,
"; ", pp->attr,
"=", pp->val,
- NULL));
+ NULL), AP_REQUEST_IS_TRUSTED_CT(r));
}
pp = pp->next;
}
if (charset && !override) {
- ap_set_content_type(r, apr_pstrcat(r->pool, r->content_type,
+ ap_set_content_type_ex(r, apr_pstrcat(r->pool, r->content_type,
"; charset=", charset,
- NULL));
+ NULL), AP_REQUEST_IS_TRUSTED_CT(r));
}
}
}
diff --git a/modules/mappers/mod_actions.c b/modules/mappers/mod_actions.c
index ac9c3b7..5e398b5 100644
--- a/modules/mappers/mod_actions.c
+++ b/modules/mappers/mod_actions.c
@@ -182,8 +182,10 @@ static int action_handler(request_rec *r)
return DECLINED;
/* Second, check for actions (which override the method scripts) */
- action = r->handler ? r->handler :
- ap_field_noparam(r->pool, r->content_type);
+ action = r->handler;
+ if (!action && AP_REQUEST_IS_TRUSTED_CT(r)) {
+ action = ap_field_noparam(r->pool, r->content_type);
+ }
if (action && (t = apr_table_get(conf->action_types, action))) {
int virtual = (*t++ == '0' ? 0 : 1);
diff --git a/modules/mappers/mod_negotiation.c b/modules/mappers/mod_negotiation.c
index da68353..e91ba5f 100644
--- a/modules/mappers/mod_negotiation.c
+++ b/modules/mappers/mod_negotiation.c
@@ -1169,7 +1169,7 @@ static int read_types_multi(negotiation_state *neg)
* might be doing.
*/
if (sub_req->handler && !sub_req->content_type) {
- ap_set_content_type(sub_req, CGI_MAGIC_TYPE);
+ ap_set_content_type_ex(sub_req, CGI_MAGIC_TYPE, 1);
}
/*
@@ -3008,14 +3008,14 @@ static int handle_map_file(request_rec *r)
/* set MIME type and charset as negotiated */
if (best->mime_type && *best->mime_type) {
if (best->content_charset && *best->content_charset) {
- ap_set_content_type(r, apr_pstrcat(r->pool,
+ ap_set_content_type_ex(r, apr_pstrcat(r->pool,
best->mime_type,
"; charset=",
best->content_charset,
- NULL));
+ NULL), 1);
}
else {
- ap_set_content_type(r, apr_pstrdup(r->pool, best->mime_type));
+ ap_set_content_type_ex(r, apr_pstrdup(r->pool, best->mime_type), 1);
}
}
diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c
index a25c7ae..2b70d66 100644
--- a/modules/mappers/mod_rewrite.c
+++ b/modules/mappers/mod_rewrite.c
@@ -5477,7 +5477,7 @@ static int hook_mimetype(request_rec *r)
rewritelog((r, 1, NULL, "force filename %s to have MIME-type '%s'",
r->filename, t));
- ap_set_content_type(r, t);
+ ap_set_content_type_ex(r, t, 1);
}
/* handler */
diff --git a/modules/metadata/mod_headers.c b/modules/metadata/mod_headers.c
index 1ea970d..55ab281 100644
--- a/modules/metadata/mod_headers.c
+++ b/modules/metadata/mod_headers.c
@@ -792,14 +792,14 @@ static int do_headers_fixup(request_rec *r, apr_table_t *headers,
break;
case hdr_set:
if (!strcasecmp(hdr->header, "Content-Type")) {
- ap_set_content_type(r, process_tags(hdr, r));
+ ap_set_content_type_ex(r, process_tags(hdr, r), 1);
}
apr_table_setn(headers, hdr->header, process_tags(hdr, r));
break;
case hdr_setifempty:
if (NULL == apr_table_get(headers, hdr->header)) {
if (!strcasecmp(hdr->header, "Content-Type")) {
- ap_set_content_type(r, process_tags(hdr, r));
+ ap_set_content_type_ex(r, process_tags(hdr, r), 1);
}
apr_table_setn(headers, hdr->header, process_tags(hdr, r));
}
@@ -818,7 +818,7 @@ static int do_headers_fixup(request_rec *r, apr_table_t *headers,
const char *repl = process_regexp(hdr, r->content_type, r);
if (repl == NULL)
return 0;
- ap_set_content_type(r, repl);
+ ap_set_content_type_ex(r, repl, 1);
}
if (apr_table_get(headers, hdr->header)) {
edit_do ed;
diff --git a/modules/metadata/mod_mime_magic.c b/modules/metadata/mod_mime_magic.c
index c12529a..fe30f27 100644
--- a/modules/metadata/mod_mime_magic.c
+++ b/modules/metadata/mod_mime_magic.c
@@ -789,7 +789,7 @@ static int magic_rsl_to_request(request_rec *r)
/* XXX: this could be done at config time I'm sure... but I'm
* confused by all this magic_rsl stuff. -djg */
ap_content_type_tolower(tmp);
- ap_set_content_type(r, tmp);
+ ap_set_content_type_ex(r, tmp, 1);
if (state == rsl_encoding) {
tmp = rsl_strdup(r, encoding_frag,
@@ -2326,7 +2326,7 @@ static int revision_suffix(request_rec *r)
/* extract content type/encoding/language from sub-request */
if (sub->content_type) {
- ap_set_content_type(r, apr_pstrdup(r->pool, sub->content_type));
+ ap_set_content_type_ex(r, apr_pstrdup(r->pool, sub->content_type), 1);
#if MIME_MAGIC_DEBUG
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01557)
MODNAME ": subrequest %s got %s",
diff --git a/server/config.c b/server/config.c
index f815b22..fc4d76b 100644
--- a/server/config.c
+++ b/server/config.c
@@ -419,7 +419,7 @@ AP_CORE_DECLARE(int) ap_invoke_handler(request_rec *r)
}
if (!r->handler) {
- if (r->content_type) {
+ if (r->content_type && AP_REQUEST_IS_TRUSTED_CT(r)) {
handler = r->content_type;
if ((p=ap_strchr_c(handler, ';')) != NULL) {
char *new_handler = (char *)apr_pmemdup(r->pool, handler,
diff --git a/server/core.c b/server/core.c
index 8575aae..82706cf 100644
--- a/server/core.c
+++ b/server/core.c
@@ -4722,7 +4722,7 @@ static int core_override_type(request_rec *r)
/* Check for overrides with ForceType / SetHandler
*/
if (conf->mime_type && strcmp(conf->mime_type, "none"))
- ap_set_content_type(r, (char*) conf->mime_type);
+ ap_set_content_type_ex(r, (char*) conf->mime_type, 1);
if (conf->expr_handler) {
const char *err;

@ -0,0 +1,29 @@
diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c
index 6244e74..f5c3283 100644
--- a/modules/proxy/proxy_util.c
+++ b/modules/proxy/proxy_util.c
@@ -2406,6 +2406,13 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r,
apr_pstrcat(p,"URI cannot be parsed: ", *url,
NULL));
}
+
+ if (!uri->hostname) {
+ return ap_proxyerror(r, HTTP_BAD_REQUEST,
+ apr_pstrcat(p,"URI has no hostname: ", *url,
+ NULL));
+ }
+
if (!uri->port) {
uri->port = ap_proxy_port_of_scheme(uri->scheme);
}
@@ -3727,6 +3734,10 @@ PROXY_DECLARE(int) ap_proxy_create_hdrbrgd(apr_pool_t *p,
* way. No telling which legacy backend is relying no this.
*/
if (dconf->preserve_host == 0) {
+ if (!uri->hostname) {
+ rc = HTTP_BAD_REQUEST;
+ goto cleanup;
+ }
if (ap_strchr_c(uri->hostname, ':')) { /* if literal IPv6 address */
if (uri->port_str && uri->port != DEFAULT_HTTP_PORT) {
buf = apr_pstrcat(p, "Host: [", uri->hostname, "]:",

@ -0,0 +1,56 @@
diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c
index 797f093..114b126 100644
--- a/modules/mappers/mod_rewrite.c
+++ b/modules/mappers/mod_rewrite.c
@@ -4311,6 +4311,32 @@ static rule_return_type apply_rewrite_rule(rewriterule_entry *p,
return RULE_RC_NOSUB;
}
+ /* Add the previously stripped per-directory location prefix, unless
+ * (1) it's an absolute URL path and
+ * (2) it's a full qualified URL
+ */
+ if (!is_proxyreq && *newuri != '/' && !is_absolute_uri(newuri, NULL)) {
+ if (ctx->perdir) {
+ rewritelog((r, 3, ctx->perdir, "add per-dir prefix: %s -> %s%s",
+ newuri, ctx->perdir, newuri));
+
+ newuri = apr_pstrcat(r->pool, ctx->perdir, newuri, NULL);
+ }
+ else if (!(p->flags & (RULEFLAG_PROXY | RULEFLAG_FORCEREDIRECT))) {
+ /* Not an absolute URI-path and the scheme (if any) is unknown,
+ * and it won't be passed to fully_qualify_uri() below either,
+ * so add an implicit '/' prefix. This avoids potentially a common
+ * rule like "RewriteRule ^/some/path(.*) $1" that is given a path
+ * like "/some/pathscheme:..." to produce the fully qualified URL
+ * "scheme:..." which could be misinterpreted later.
+ */
+ rewritelog((r, 3, ctx->perdir, "add root prefix: %s -> /%s",
+ newuri, newuri));
+
+ newuri = apr_pstrcat(r->pool, "/", newuri, NULL);
+ }
+ }
+
/* Now adjust API's knowledge about r->filename and r->args */
r->filename = newuri;
@@ -4320,18 +4346,6 @@ static rule_return_type apply_rewrite_rule(rewriterule_entry *p,
splitout_queryargs(r, p->flags);
- /* Add the previously stripped per-directory location prefix, unless
- * (1) it's an absolute URL path and
- * (2) it's a full qualified URL
- */
- if ( ctx->perdir && !is_proxyreq && *r->filename != '/'
- && !is_absolute_uri(r->filename, NULL)) {
- rewritelog((r, 3, ctx->perdir, "add per-dir prefix: %s -> %s%s",
- r->filename, ctx->perdir, r->filename));
-
- r->filename = apr_pstrcat(r->pool, ctx->perdir, r->filename, NULL);
- }
-
/* If this rule is forced for proxy throughput
* (`RewriteRule ... ... [P]') then emulate mod_proxy's
* URL-to-filename handler to be sure mod_proxy is triggered

@ -0,0 +1,266 @@
diff --git a/modules/cluster/mod_heartmonitor.c b/modules/cluster/mod_heartmonitor.c
index 965fef5..6df3bf4 100644
--- a/modules/cluster/mod_heartmonitor.c
+++ b/modules/cluster/mod_heartmonitor.c
@@ -782,7 +782,7 @@ static int hm_handler(request_rec *r)
hmserver.seen = apr_time_now();
hm_update_stat(ctx, &hmserver, r->pool);
- ap_set_content_type(r, "text/plain");
+ ap_set_content_type_ex(r, "text/plain", 1);
ap_set_content_length(r, 2);
ap_rputs("OK", r);
ap_rflush(r);
diff --git a/modules/dav/main/mod_dav.c b/modules/dav/main/mod_dav.c
index 792b514..28479b9 100644
--- a/modules/dav/main/mod_dav.c
+++ b/modules/dav/main/mod_dav.c
@@ -323,7 +323,7 @@ static int dav_error_response(request_rec *r, int status, const char *body)
r->status = status;
r->status_line = ap_get_status_line(status);
- ap_set_content_type(r, "text/html; charset=ISO-8859-1");
+ ap_set_content_type_ex(r, "text/html; charset=ISO-8859-1", 1);
/* begin the response now... */
ap_rvputs(r,
@@ -354,7 +354,7 @@ static int dav_error_response_tag(request_rec *r,
{
r->status = err->status;
- ap_set_content_type(r, DAV_XML_CONTENT_TYPE);
+ ap_set_content_type_ex(r, DAV_XML_CONTENT_TYPE, 1);
ap_rputs(DAV_XML_HEADER DEBUG_CR
"<D:error xmlns:D=\"DAV:\"", r);
@@ -512,7 +512,7 @@ DAV_DECLARE(void) dav_begin_multistatus(apr_bucket_brigade *bb,
{
/* Set the correct status and Content-Type */
r->status = status;
- ap_set_content_type(r, DAV_XML_CONTENT_TYPE);
+ ap_set_content_type_ex(r, DAV_XML_CONTENT_TYPE, 1);
/* Send the headers and actual multistatus response now... */
ap_fputs(r->output_filters, bb, DAV_XML_HEADER DEBUG_CR
@@ -1923,7 +1923,7 @@ static int dav_method_options(request_rec *r)
/* send the options response */
r->status = HTTP_OK;
- ap_set_content_type(r, DAV_XML_CONTENT_TYPE);
+ ap_set_content_type_ex(r, DAV_XML_CONTENT_TYPE, 1);
/* send the headers and response body */
ap_rputs(DAV_XML_HEADER DEBUG_CR
@@ -3191,7 +3191,7 @@ static int dav_method_lock(request_rec *r)
(*locks_hooks->close_lockdb)(lockdb);
r->status = HTTP_OK;
- ap_set_content_type(r, DAV_XML_CONTENT_TYPE);
+ ap_set_content_type_ex(r, DAV_XML_CONTENT_TYPE, 1);
ap_rputs(DAV_XML_HEADER DEBUG_CR "<D:prop xmlns:D=\"DAV:\">" DEBUG_CR, r);
if (lock == NULL)
diff --git a/modules/examples/mod_example_hooks.c b/modules/examples/mod_example_hooks.c
index d818dc1..4d79b86 100644
--- a/modules/examples/mod_example_hooks.c
+++ b/modules/examples/mod_example_hooks.c
@@ -993,7 +993,7 @@ static int x_handler(request_rec *r)
* Set the Content-type header. Note that we do not actually have to send
* the headers: this is done by the http core.
*/
- ap_set_content_type(r, "text/html");
+ ap_set_content_type_ex(r, "text/html", 1);
/*
* If we're only supposed to send header information (HEAD request), we're
* already there.
diff --git a/modules/filters/mod_data.c b/modules/filters/mod_data.c
index d083d32..489e76c 100644
--- a/modules/filters/mod_data.c
+++ b/modules/filters/mod_data.c
@@ -117,7 +117,7 @@ static apr_status_t data_out_filter(ap_filter_t *f, apr_bucket_brigade *bb)
}
}
- ap_set_content_type(r, "text/plain");
+ ap_set_content_type_ex(r, "text/plain", 1);
}
diff --git a/modules/filters/mod_include.c b/modules/filters/mod_include.c
index a46a944..05f994c 100644
--- a/modules/filters/mod_include.c
+++ b/modules/filters/mod_include.c
@@ -3971,7 +3971,7 @@ static int include_fixup(request_rec *r)
if (r->handler && (strcmp(r->handler, "server-parsed") == 0))
{
if (!r->content_type || !*r->content_type) {
- ap_set_content_type(r, "text/html");
+ ap_set_content_type_ex(r, "text/html", 1);
}
r->handler = "default-handler";
}
diff --git a/modules/filters/mod_proxy_html.c b/modules/filters/mod_proxy_html.c
index ea6bf03..8b619e8 100644
--- a/modules/filters/mod_proxy_html.c
+++ b/modules/filters/mod_proxy_html.c
@@ -933,7 +933,7 @@ static apr_status_t proxy_html_filter(ap_filter_t *f, apr_bucket_brigade *bb)
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, f->r, APLOGNO(01422)
"No i18n support found. Install mod_xml2enc if required");
enc = XML_CHAR_ENCODING_NONE;
- ap_set_content_type(f->r, "text/html;charset=utf-8");
+ ap_set_content_type_ex(f->r, "text/html;charset=utf-8", 1);
}
else {
/* if we wanted a non-default charset_out, insert the
@@ -949,7 +949,7 @@ static apr_status_t proxy_html_filter(ap_filter_t *f, apr_bucket_brigade *bb)
cenc, NULL));
}
else /* Normal case, everything worked, utf-8 output */
- ap_set_content_type(f->r, "text/html;charset=utf-8");
+ ap_set_content_type_ex(f->r, "text/html;charset=utf-8", 1);
}
ap_fputs(f->next, ctxt->bb, ctxt->cfg->doctype);
diff --git a/modules/generators/mod_cgi.c b/modules/generators/mod_cgi.c
index 66cd31c..4650d18 100644
--- a/modules/generators/mod_cgi.c
+++ b/modules/generators/mod_cgi.c
@@ -795,7 +795,7 @@ static apr_status_t include_cgi(include_ctx_t *ctx, ap_filter_t *f,
/* Force sub_req to be treated as a CGI request, even if ordinary
* typing rules would have called it something else.
*/
- ap_set_content_type(rr, CGI_MAGIC_TYPE);
+ ap_set_content_type_ex(rr, CGI_MAGIC_TYPE, 1);
/* Run it. */
rr_status = ap_run_sub_req(rr);
diff --git a/modules/generators/mod_cgid.c b/modules/generators/mod_cgid.c
index 102d2b3..57e119f 100644
--- a/modules/generators/mod_cgid.c
+++ b/modules/generators/mod_cgid.c
@@ -1801,7 +1801,7 @@ static apr_status_t include_cgi(include_ctx_t *ctx, ap_filter_t *f,
/* Force sub_req to be treated as a CGI request, even if ordinary
* typing rules would have called it something else.
*/
- ap_set_content_type(rr, CGI_MAGIC_TYPE);
+ ap_set_content_type_ex(rr, CGI_MAGIC_TYPE, 1);
/* Run it. */
rr_status = ap_run_sub_req(rr);
diff --git a/modules/generators/mod_info.c b/modules/generators/mod_info.c
index e5e63de..67df675 100644
--- a/modules/generators/mod_info.c
+++ b/modules/generators/mod_info.c
@@ -777,7 +777,7 @@ static int display_info(request_rec * r)
return DECLINED;
}
- ap_set_content_type(r, "text/html; charset=ISO-8859-1");
+ ap_set_content_type_ex(r, "text/html; charset=ISO-8859-1", 1);
ap_rputs(DOCTYPE_XHTML_1_0T
"<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
diff --git a/modules/generators/mod_status.c b/modules/generators/mod_status.c
index 5bada07..2cb38c7 100644
--- a/modules/generators/mod_status.c
+++ b/modules/generators/mod_status.c
@@ -273,7 +273,7 @@ static int status_handler(request_rec *r)
if (r->method_number != M_GET)
return DECLINED;
- ap_set_content_type(r, "text/html; charset=ISO-8859-1");
+ ap_set_content_type_ex(r, "text/html; charset=ISO-8859-1", 1);
/*
* Simple table-driven form data set parser that lets you alter the header
@@ -301,7 +301,7 @@ static int status_handler(request_rec *r)
no_table_report = 1;
break;
case STAT_OPT_AUTO:
- ap_set_content_type(r, "text/plain; charset=ISO-8859-1");
+ ap_set_content_type_ex(r, "text/plain; charset=ISO-8859-1", 1);
short_report = 1;
break;
}
diff --git a/modules/http/http_filters.c b/modules/http/http_filters.c
index 16cb23c..27c44b2 100644
--- a/modules/http/http_filters.c
+++ b/modules/http/http_filters.c
@@ -1245,7 +1245,7 @@ AP_DECLARE_NONSTD(int) ap_send_http_trace(request_rec *r)
}
}
- ap_set_content_type(r, "message/http");
+ ap_set_content_type_ex(r, "message/http", 1);
/* Now we recreate the request, and echo it back */
diff --git a/modules/http/http_protocol.c b/modules/http/http_protocol.c
index 417fee6..d003aea 100644
--- a/modules/http/http_protocol.c
+++ b/modules/http/http_protocol.c
@@ -1423,10 +1423,10 @@ AP_DECLARE(void) ap_send_error_response(request_rec *r, int recursive_error)
request_conf->suppress_charset = 1; /* avoid adding default
* charset later
*/
- ap_set_content_type(r, "text/html");
+ ap_set_content_type_ex(r, "text/html", 1);
}
else {
- ap_set_content_type(r, "text/html; charset=iso-8859-1");
+ ap_set_content_type_ex(r, "text/html; charset=iso-8859-1", 1);
}
if ((status == HTTP_METHOD_NOT_ALLOWED)
diff --git a/modules/http/http_request.c b/modules/http/http_request.c
index e873aab..3521cfb 100644
--- a/modules/http/http_request.c
+++ b/modules/http/http_request.c
@@ -709,7 +709,7 @@ AP_DECLARE(void) ap_internal_fast_redirect(request_rec *rr, request_rec *r)
r->args = rr->args;
r->finfo = rr->finfo;
r->handler = rr->handler;
- ap_set_content_type(r, rr->content_type);
+ ap_set_content_type_ex(r, rr->content_type, AP_REQUEST_IS_TRUSTED_CT(rr));
r->content_encoding = rr->content_encoding;
r->content_languages = rr->content_languages;
r->per_dir_config = rr->per_dir_config;
diff --git a/modules/ldap/util_ldap.c b/modules/ldap/util_ldap.c
index eecb3f7..b71dc98 100644
--- a/modules/ldap/util_ldap.c
+++ b/modules/ldap/util_ldap.c
@@ -125,7 +125,7 @@ static int util_ldap_handler(request_rec *r)
st = (util_ldap_state_t *) ap_get_module_config(r->server->module_config,
&ldap_module);
- ap_set_content_type(r, "text/html; charset=ISO-8859-1");
+ ap_set_content_type_ex(r, "text/html; charset=ISO-8859-1", 1);
if (r->header_only)
return OK;
diff --git a/modules/mappers/mod_imagemap.c b/modules/mappers/mod_imagemap.c
index 187a500..3e14933 100644
--- a/modules/mappers/mod_imagemap.c
+++ b/modules/mappers/mod_imagemap.c
@@ -475,7 +475,7 @@ static int imap_reply(request_rec *r, const char *redirect)
static void menu_header(request_rec *r, char *menu)
{
- ap_set_content_type(r, "text/html; charset=ISO-8859-1");
+ ap_set_content_type_ex(r, "text/html; charset=ISO-8859-1", 1);
ap_rvputs(r, DOCTYPE_HTML_3_2, "<html><head>\n<title>Menu for ",
ap_escape_html(r->pool, r->uri),
diff --git a/modules/proxy/mod_proxy_balancer.c b/modules/proxy/mod_proxy_balancer.c
index c599e1a..d5c20af 100644
--- a/modules/proxy/mod_proxy_balancer.c
+++ b/modules/proxy/mod_proxy_balancer.c
@@ -1480,7 +1480,7 @@ static int balancer_handler(request_rec *r)
if (apr_table_get(params, "xml")) {
char date[APR_RFC822_DATE_LEN];
- ap_set_content_type(r, "text/xml");
+ ap_set_content_type_ex(r, "text/xml", 1);
ap_rputs("<?xml version='1.0' encoding='UTF-8' ?>\n", r);
ap_rputs("<httpd:manager xmlns:httpd='http://httpd.apache.org'>\n", r);
ap_rputs(" <httpd:balancers>\n", r);

@ -0,0 +1,92 @@
commit 4c0e27d7bfbf46f14dfbd5d888e56c64ad8c8de5
Author: Tomas Korbar <tkorbar@redhat.com>
Date: Mon Sep 19 13:22:27 2022 +0200
Backport refactor of SNI support to httpd-2.4.37
diff --git a/modules/http2/mod_proxy_http2.c b/modules/http2/mod_proxy_http2.c
index a7e0dcd..31ccd32 100644
--- a/modules/http2/mod_proxy_http2.c
+++ b/modules/http2/mod_proxy_http2.c
@@ -591,16 +591,6 @@ run_connect:
}
if (!ctx->p_conn->data) {
- /* New conection: set a note on the connection what CN is
- * requested and what protocol we want */
- if (ctx->p_conn->ssl_hostname) {
- ap_log_cerror(APLOG_MARK, APLOG_TRACE1, status, ctx->owner,
- "set SNI to %s for (%s)",
- ctx->p_conn->ssl_hostname,
- ctx->p_conn->hostname);
- apr_table_setn(ctx->p_conn->connection->notes,
- "proxy-request-hostname", ctx->p_conn->ssl_hostname);
- }
if (ctx->is_ssl) {
apr_table_setn(ctx->p_conn->connection->notes,
"proxy-request-alpn-protos", "h2");
diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c
index 1b7bb81..c1c591a 100644
--- a/modules/proxy/mod_proxy_http.c
+++ b/modules/proxy/mod_proxy_http.c
@@ -2111,19 +2111,6 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker,
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
diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c
index ec9a414..805820d 100644
--- a/modules/proxy/proxy_util.c
+++ b/modules/proxy/proxy_util.c
@@ -3261,6 +3261,16 @@ static int proxy_connection_create(const char *proxy_function,
backend_addr, conn->hostname);
return HTTP_INTERNAL_SERVER_ERROR;
}
+ if (conn->ssl_hostname) {
+ /* Set a note on the connection about what CN is requested,
+ * such that mod_ssl can check if it is requested to do so.
+ */
+ ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, conn->connection,
+ "%s: set SNI to %s for (%s)", proxy_function,
+ conn->ssl_hostname, conn->hostname);
+ apr_table_setn(conn->connection->notes, "proxy-request-hostname",
+ conn->ssl_hostname);
+ }
}
else {
/* TODO: See if this will break FTP */
diff --git a/modules/ssl/ssl_engine_io.c b/modules/ssl/ssl_engine_io.c
index 4e3875a..9b4280c 100644
--- a/modules/ssl/ssl_engine_io.c
+++ b/modules/ssl/ssl_engine_io.c
@@ -1273,7 +1273,6 @@ static apr_status_t ssl_io_filter_handshake(ssl_filter_ctx_t *filter_ctx)
((dc->proxy->ssl_check_peer_cn != FALSE) ||
(dc->proxy->ssl_check_peer_name == TRUE)) &&
hostname_note) {
- apr_table_unset(c->notes, "proxy-request-hostname");
if (!cert
|| modssl_X509_match_name(c->pool, cert, hostname_note,
TRUE, server) == FALSE) {
@@ -1290,7 +1289,6 @@ static apr_status_t ssl_io_filter_handshake(ssl_filter_ctx_t *filter_ctx)
hostname = ssl_var_lookup(NULL, server, c, NULL,
"SSL_CLIENT_S_DN_CN");
- apr_table_unset(c->notes, "proxy-request-hostname");
/* Do string match or simplest wildcard match if that
* fails. */

@ -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;

@ -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");

@ -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,

@ -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;
}
}
}

@ -1,5 +1,5 @@
diff --git a/modules/loggers/config.m4 b/modules/loggers/config.m4
index 762e773..0848d2e 100644
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]]]])
@ -12,7 +12,7 @@ index 762e773..0848d2e 100644
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
index 996c09cf49..50a056a2f8 100644
--- a/modules/loggers/mod_log_config.c
+++ b/modules/loggers/mod_log_config.c
@@ -172,6 +172,10 @@

@ -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;
}

@ -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

@ -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 */

@ -0,0 +1,170 @@
commit 84e6f25f67de9a9bddefdcdbfee3f251fead647e
Author: Tomas Korbar <tkorbar@redhat.com>
Date: Thu Jul 20 14:41:33 2023 +0200
Fix duplicate presence of keys printed by mod_status
diff --git a/modules/generators/mod_status.c b/modules/generators/mod_status.c
index 5917953..5bada07 100644
--- a/modules/generators/mod_status.c
+++ b/modules/generators/mod_status.c
@@ -186,7 +186,8 @@ static int status_handler(request_rec *r)
apr_uint32_t up_time;
ap_loadavg_t t;
int j, i, res, written;
- int ready;
+ int idle;
+ int graceful;
int busy;
unsigned long count;
unsigned long lres, my_lres, conn_lres;
@@ -203,6 +204,7 @@ static int status_handler(request_rec *r)
char *stat_buffer;
pid_t *pid_buffer, worker_pid;
int *thread_idle_buffer = NULL;
+ int *thread_graceful_buffer = NULL;
int *thread_busy_buffer = NULL;
clock_t tu, ts, tcu, tcs;
clock_t gu, gs, gcu, gcs;
@@ -231,7 +233,8 @@ static int status_handler(request_rec *r)
#endif
#endif
- ready = 0;
+ idle = 0;
+ graceful = 0;
busy = 0;
count = 0;
bcount = 0;
@@ -250,6 +253,7 @@ static int status_handler(request_rec *r)
stat_buffer = apr_palloc(r->pool, server_limit * thread_limit * sizeof(char));
if (is_async) {
thread_idle_buffer = apr_palloc(r->pool, server_limit * sizeof(int));
+ thread_graceful_buffer = apr_palloc(r->pool, server_limit * sizeof(int));
thread_busy_buffer = apr_palloc(r->pool, server_limit * sizeof(int));
}
@@ -318,6 +322,7 @@ static int status_handler(request_rec *r)
ps_record = ap_get_scoreboard_process(i);
if (is_async) {
thread_idle_buffer[i] = 0;
+ thread_graceful_buffer[i] = 0;
thread_busy_buffer[i] = 0;
}
for (j = 0; j < thread_limit; ++j) {
@@ -336,18 +341,20 @@ static int status_handler(request_rec *r)
&& ps_record->pid) {
if (res == SERVER_READY) {
if (ps_record->generation == mpm_generation)
- ready++;
+ idle++;
if (is_async)
thread_idle_buffer[i]++;
}
else if (res != SERVER_DEAD &&
res != SERVER_STARTING &&
res != SERVER_IDLE_KILL) {
- busy++;
- if (is_async) {
- if (res == SERVER_GRACEFUL)
- thread_idle_buffer[i]++;
- else
+ if (res == SERVER_GRACEFUL) {
+ graceful++;
+ if (is_async)
+ thread_graceful_buffer[i]++;
+ } else {
+ busy++;
+ if (is_async)
thread_busy_buffer[i]++;
}
}
@@ -548,10 +555,10 @@ static int status_handler(request_rec *r)
} /* ap_extended_status */
if (!short_report)
- ap_rprintf(r, "<dt>%d requests currently being processed, "
- "%d idle workers</dt>\n", busy, ready);
+ ap_rprintf(r, "<dt>%d requests currently being processed, %d workers gracefully restarting, "
+ "%d idle workers</dt>\n", busy, graceful, idle);
else
- ap_rprintf(r, "BusyWorkers: %d\nIdleWorkers: %d\n", busy, ready);
+ ap_rprintf(r, "BusyWorkers: %d\nGracefulWorkers: %d\nIdleWorkers: %d\n", busy, graceful, idle);
if (!short_report)
ap_rputs("</dl>", r);
@@ -559,11 +566,6 @@ static int status_handler(request_rec *r)
if (is_async) {
int write_completion = 0, lingering_close = 0, keep_alive = 0,
connections = 0, stopping = 0, procs = 0;
- /*
- * These differ from 'busy' and 'ready' in how gracefully finishing
- * threads are counted. XXX: How to make this clear in the html?
- */
- int busy_workers = 0, idle_workers = 0;
if (!short_report)
ap_rputs("\n\n<table rules=\"all\" cellpadding=\"1%\">\n"
"<tr><th rowspan=\"2\">Slot</th>"
@@ -573,7 +575,7 @@ static int status_handler(request_rec *r)
"<th colspan=\"2\">Threads</th>"
"<th colspan=\"3\">Async connections</th></tr>\n"
"<tr><th>total</th><th>accepting</th>"
- "<th>busy</th><th>idle</th>"
+ "<th>busy</th><th>graceful</th><th>idle</th>"
"<th>writing</th><th>keep-alive</th><th>closing</th></tr>\n", r);
for (i = 0; i < server_limit; ++i) {
ps_record = ap_get_scoreboard_process(i);
@@ -582,8 +584,6 @@ static int status_handler(request_rec *r)
write_completion += ps_record->write_completion;
keep_alive += ps_record->keep_alive;
lingering_close += ps_record->lingering_close;
- busy_workers += thread_busy_buffer[i];
- idle_workers += thread_idle_buffer[i];
procs++;
if (ps_record->quiescing) {
stopping++;
@@ -599,7 +599,7 @@ static int status_handler(request_rec *r)
ap_rprintf(r, "<tr><td>%u</td><td>%" APR_PID_T_FMT "</td>"
"<td>%s%s</td>"
"<td>%u</td><td>%s</td>"
- "<td>%u</td><td>%u</td>"
+ "<td>%u</td><td>%u</td><td>%u</td>"
"<td>%u</td><td>%u</td><td>%u</td>"
"</tr>\n",
i, ps_record->pid,
@@ -607,6 +607,7 @@ static int status_handler(request_rec *r)
ps_record->connections,
ps_record->not_accepting ? "no" : "yes",
thread_busy_buffer[i],
+ thread_graceful_buffer[i],
thread_idle_buffer[i],
ps_record->write_completion,
ps_record->keep_alive,
@@ -618,25 +619,22 @@ static int status_handler(request_rec *r)
ap_rprintf(r, "<tr><td>Sum</td>"
"<td>%d</td><td>%d</td>"
"<td>%d</td><td>&nbsp;</td>"
- "<td>%d</td><td>%d</td>"
+ "<td>%d</td><td>%d</td><td>%d</td>"
"<td>%d</td><td>%d</td><td>%d</td>"
"</tr>\n</table>\n",
procs, stopping,
connections,
- busy_workers, idle_workers,
+ busy, graceful, idle,
write_completion, keep_alive, lingering_close);
}
else {
ap_rprintf(r, "Processes: %d\n"
"Stopping: %d\n"
- "BusyWorkers: %d\n"
- "IdleWorkers: %d\n"
"ConnsTotal: %d\n"
"ConnsAsyncWriting: %d\n"
"ConnsAsyncKeepAlive: %d\n"
"ConnsAsyncClosing: %d\n",
procs, stopping,
- busy_workers, idle_workers,
connections,
write_completion, keep_alive, lingering_close);
}

@ -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;

File diff suppressed because it is too large Load Diff

@ -1,20 +1,25 @@
diff --git a/docs/manual/mod/mod_proxy_wstunnel.html.en b/docs/manual/mod/mod_proxy_wstunnel.html.en
index 9f2c120..61ff7de 100644
index 21ffbe2..16e1628 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 <code>Upgrade</code></p>
<div id="quickview"><a href="https://www.apache.org/foundation/contributing.html" class="badge"><img src="https://www.apache.org/images/SupportApache-small.png" alt="Support Apache!" /></a><h3 class="directives">Directives</h3>
<ul id="toc">
<li><img alt="" src="../images/down.gif" /> <a href="#proxywebsocketfallbacktoproxyhttp">ProxyWebsocketFallbackToProxyHttp</a></li>
@@ -60,14 +60,33 @@ NONE means you bypass the check for the header but still upgrade to WebSocket.
ANY means that <code>Upgrade</code> will read in the request headers and use
in the response <code>Upgrade</code></p>
</div>
-<div id="quickview"><a href="https://www.apache.org/foundation/contributing.html" class="badge"><img src="https://www.apache.org/images/SupportApache-small.png" alt="Support Apache!" /></a><h3 class="directives">Directives</h3>
-<p>This module provides no
- directives.</p>
+<div id="quickview"><h3 class="directives">Directives</h3>
+<ul id="toc">
+<li><img alt="" src="../images/down.gif" /> <a href="#proxywebsocketidletimeout">ProxyWebsocketIdleTimeout</a></li>
</ul>
+</ul>
+
<h3>Bugfix checklist</h3><ul class="seealso"><li><a href="https://www.apache.org/dist/httpd/CHANGES_2.4">httpd changelog</a></li><li><a href="https://bz.apache.org/bugzilla/buglist.cgi?bug_status=__open__&amp;list_id=144532&amp;product=Apache%20httpd-2&amp;query_format=specific&amp;order=changeddate%20DESC%2Cpriority%2Cbug_severity&amp;component=mod_proxy_wstunnel">Known issues</a></li><li><a href="https://bz.apache.org/bugzilla/enter_bug.cgi?product=Apache%20httpd-2&amp;component=mod_proxy_wstunnel">Report a bug</a></li></ul><h3>See also</h3>
<ul class="seealso">
@@ -108,6 +109,23 @@ in the response <code>Upgrade</code></p>
WebSocket requests as in httpd 2.4.46 and earlier.</p>
<li><code class="module"><a href="../mod/mod_proxy.html">mod_proxy</a></code></li>
<li><a href="#comments_section">Comments</a></li></ul></div>
</div>
+
+<div class="top"><a href="#page-header"><img alt="top" src="../images/up.gif" /></a></div>
+<div class="directive-section"><h2><a name="ProxyWebsocketIdleTimeout" id="ProxyWebsocketIdleTimeout">ProxyWebsocketIdleTimeout</a> <a name="proxywebsocketidletimeout" id="proxywebsocketidletimeout">Directive</a> <a title="Permanent link" href="#proxywebsocketidletimeout" class="permalink">&para;</a></h2>
+<table class="directive">
+<tr><th><a href="directive-dict.html#Description">Description:</a></th><td>Sets the maximum amount of time to wait for data on the websockets tunnel</td></tr>
@ -35,18 +40,21 @@ index 9f2c120..61ff7de 100644
<div class="bottomlang">
<p><span>Available Languages: </span><a href="../en/mod/mod_proxy_wstunnel.html" title="English">&nbsp;en&nbsp;</a> |
diff --git a/modules/proxy/mod_proxy_wstunnel.c b/modules/proxy/mod_proxy_wstunnel.c
index bcbba42..c29ded1 100644
index 4aadbab..ca3ed3a 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;
@@ -18,6 +18,10 @@
module AP_MODULE_DECLARE_DATA proxy_wstunnel_module;
static int can_fallback_to_proxy_http;
@@ -152,6 +153,8 @@ static int proxy_wstunnel_request(apr_pool_t *p, request_rec *r,
+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;
@ -55,7 +63,7 @@ index bcbba42..c29ded1 100644
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,
@@ -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) */
@ -70,7 +78,7 @@ index bcbba42..c29ded1 100644
}
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(02444) "error apr_poll()");
return HTTP_INTERNAL_SERVER_ERROR;
@@ -418,11 +424,26 @@ cleanup:
@@ -366,6 +375,38 @@ cleanup:
return status;
}
@ -88,22 +96,37 @@ index bcbba42..c29ded1 100644
+ 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));
+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"),
-
+
+ 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}
};
+
+ {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 */
};

File diff suppressed because it is too large Load Diff

@ -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 */

@ -1,8 +1,15 @@
# ./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 6747aea..40c7076 100644
index 06b8c5a..9eeb5c7 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -233,6 +233,7 @@ install-cgi:
@@ -213,6 +213,7 @@ install-cgi:
install-other:
@test -d $(DESTDIR)$(logfiledir) || $(MKINSTALLDIRS) $(DESTDIR)$(logfiledir)
@test -d $(DESTDIR)$(runtimedir) || $(MKINSTALLDIRS) $(DESTDIR)$(runtimedir)
@ -11,7 +18,7 @@ index 6747aea..40c7076 100644
file=apachecore.$$ext; \
if test -f $$file; then \
diff --git a/acinclude.m4 b/acinclude.m4
index b6ef442..98f1441 100644
index 0ad0c13..a8c2804 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -45,6 +45,7 @@ AC_DEFUN([APACHE_GEN_CONFIG_VARS],[
@ -22,7 +29,7 @@ index b6ef442..98f1441 100644
APACHE_SUBST(other_targets)
APACHE_SUBST(progname)
APACHE_SUBST(prefix)
@@ -665,6 +666,7 @@ AC_DEFUN([APACHE_EXPORT_ARGUMENTS],[
@@ -663,6 +664,7 @@ AC_DEFUN([APACHE_EXPORT_ARGUMENTS],[
APACHE_SUBST_EXPANDED_ARG(runtimedir)
APACHE_SUBST_EXPANDED_ARG(logfiledir)
APACHE_SUBST_EXPANDED_ARG(proxycachedir)
@ -31,7 +38,7 @@ index b6ef442..98f1441 100644
dnl
diff --git a/configure.in b/configure.in
index 37346b2..f303784 100644
index a208b53..de6a8ad 100644
--- a/configure.in
+++ b/configure.in
@@ -41,7 +41,7 @@ dnl Something seems broken here.
@ -56,7 +63,7 @@ index 2b4a70c..e076f41 100644
#endif /* AP_CONFIG_LAYOUT_H */
diff --git a/include/http_config.h b/include/http_config.h
index 77657ae..384a90f 100644
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);
@ -123,11 +130,48 @@ index addfd7e..2389f8f 100644
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 d135764..c2176b9 100644
index bbe52e0..b5ab429 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;
@@ -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;
@ -136,7 +180,7 @@ index d135764..c2176b9 100644
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)
@@ -1411,12 +1413,15 @@ AP_DECLARE(const char *) ap_resolve_env(apr_pool_t *p, const char * word)
return res_buf;
}
@ -147,7 +191,6 @@ index d135764..c2176b9 100644
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;
+
@ -155,7 +198,7 @@ index d135764..c2176b9 100644
}
/*
@@ -3220,6 +3225,24 @@ static const char *set_runtime_dir(cmd_parms *cmd, void *dummy, const char *arg)
@@ -3108,6 +3113,24 @@ static const char *set_runtime_dir(cmd_parms *cmd, void *dummy, const char *arg)
return NULL;
}
@ -180,7 +223,7 @@ index d135764..c2176b9 100644
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,
@@ -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.)"),
@ -189,7 +232,7 @@ index d135764..c2176b9 100644
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
@@ -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);
@ -197,9 +240,9 @@ index d135764..c2176b9 100644
- apr_pool_cleanup_null);
+ apr_pool_cleanup_register(pconf, NULL, reset_config, apr_pool_cleanup_null);
ap_regcomp_set_default_cflags(AP_REG_DEFAULT);
ap_regcomp_set_default_cflags(AP_REG_DOLLAR_ENDONLY);
@@ -5303,6 +5327,27 @@ AP_DECLARE(int) ap_state_query(int query)
@@ -5202,6 +5226,27 @@ AP_DECLARE(int) ap_state_query(int query)
}
}

@ -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();

@ -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;

@ -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 <crypt.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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,

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save