summaryrefslogtreecommitdiffstats
path: root/debian/patches
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches')
-rw-r--r--debian/patches/build_suexec-custom.patch69
-rw-r--r--debian/patches/child_processes_fail_to_start.patch75
-rw-r--r--debian/patches/customize_apxs.patch220
-rw-r--r--debian/patches/fhs_compliance.patch70
-rw-r--r--debian/patches/fix-macro.patch160
-rw-r--r--debian/patches/no_LD_LIBRARY_PATH.patch18
-rw-r--r--debian/patches/pcre2.patch377
-rw-r--r--debian/patches/reproducible_builds.diff40
-rw-r--r--debian/patches/series15
-rw-r--r--debian/patches/suexec-CVE-2007-1742.patch66
-rw-r--r--debian/patches/suexec-custom.patch190
11 files changed, 1300 insertions, 0 deletions
diff --git a/debian/patches/build_suexec-custom.patch b/debian/patches/build_suexec-custom.patch
new file mode 100644
index 0000000..a509cd5
--- /dev/null
+++ b/debian/patches/build_suexec-custom.patch
@@ -0,0 +1,69 @@
+Description: add suexec-custom to the build system
+Forwarded: not-needed
+Author: Stefan Fritsch <sf@debian.org>
+Last-Update: 2012-02-25
+--- a/Makefile.in
++++ b/Makefile.in
+@@ -293,23 +293,26 @@
+ install-suexec: install-suexec-$(INSTALL_SUEXEC)
+
+ install-suexec-binary:
+- @if test -f $(builddir)/support/suexec; then \
+- test -d $(DESTDIR)$(sbindir) || $(MKINSTALLDIRS) $(DESTDIR)$(sbindir); \
+- $(INSTALL_PROGRAM) $(top_builddir)/support/suexec $(DESTDIR)$(sbindir); \
++ @if test -f $(builddir)/support/suexec-pristine && test -f $(builddir)/support/suexec-custom; then \
++ test -d $(DESTDIR)$(sbindir) || $(MKINSTALLDIRS) $(DESTDIR)$(sbindir); \
++ $(INSTALL_PROGRAM) $(top_builddir)/support/suexec-pristine $(DESTDIR)$(sbindir); \
++ $(INSTALL_PROGRAM) $(top_builddir)/support/suexec-custom $(DESTDIR)$(sbindir); \
+ fi
+
+ install-suexec-setuid: install-suexec-binary
+- @if test -f $(builddir)/support/suexec; then \
+- chmod 4755 $(DESTDIR)$(sbindir)/suexec; \
++ @if test -f $(builddir)/support/suexec-pristine && test -f $(builddir)/support/suexec-custom; then \
++ chmod 4755 $(DESTDIR)$(sbindir)/suexec-pristine; \
++ chmod 4755 $(DESTDIR)$(sbindir)/suexec-custom; \
+ fi
+
+ install-suexec-caps: install-suexec-binary
+- @if test -f $(builddir)/support/suexec; then \
+- setcap 'cap_setuid,cap_setgid+pe' $(DESTDIR)$(sbindir)/suexec; \
++ @if test -f $(builddir)/support/suexec-pristine && test -f $(builddir)/support/suexec-custom; then \
++ setcap 'cap_setuid,cap_setgid+pe' $(DESTDIR)$(sbindir)/suexec-pristine; \
++ setcap 'cap_setuid,cap_setgid+pe' $(DESTDIR)$(sbindir)/suexec-custom; \
+ fi
+
+ suexec:
+- cd support && $(MAKE) suexec
++ cd support && $(MAKE) suexec-pristine suexec-custom
+
+ x-local-distclean:
+ @rm -rf autom4te.cache
+--- a/support/Makefile.in
++++ b/support/Makefile.in
+@@ -1,7 +1,7 @@
+ DISTCLEAN_TARGETS = apxs apachectl dbmmanage log_server_status \
+ logresolve.pl phf_abuse_log.cgi split-logfile envvars-std
+
+-CLEAN_TARGETS = suexec
++CLEAN_TARGETS = suexec-pristine suexec-custom
+
+ bin_PROGRAMS = htpasswd htdigest htdbm ab logresolve httxt2dbm
+ sbin_PROGRAMS = htcacheclean rotatelogs $(NONPORTABLE_SUPPORT)
+@@ -72,9 +72,13 @@
+ checkgid: $(checkgid_OBJECTS)
+ $(LINK) $(checkgid_LTFLAGS) $(checkgid_OBJECTS) $(PROGRAM_LDADD)
+
+-suexec_OBJECTS = suexec.lo
+-suexec: $(suexec_OBJECTS)
+- $(LINK) $(suexec_OBJECTS)
++suexec-pristine_OBJECTS = suexec.lo
++suexec-pristine: $(suexec-pristine_OBJECTS)
++ $(LINK) $(suexec-pristine_OBJECTS)
++
++suexec-custom_OBJECTS = suexec-custom.lo
++suexec-custom: $(suexec-custom_OBJECTS)
++ $(LINK) $(suexec-custom_OBJECTS)
+
+ htcacheclean_OBJECTS = htcacheclean.lo
+ htcacheclean: $(htcacheclean_OBJECTS)
diff --git a/debian/patches/child_processes_fail_to_start.patch b/debian/patches/child_processes_fail_to_start.patch
new file mode 100644
index 0000000..957c857
--- /dev/null
+++ b/debian/patches/child_processes_fail_to_start.patch
@@ -0,0 +1,75 @@
+Description: Add upstream patch to fix active daemon accounting
+Author: Ondřej Surý <ondrej@sury.org>
+Forwarded: not-needed
+Reviewed-By: Yadd <yadd@debian.org>
+Last-Update: 2022-03-14
+
+--- a/server/mpm/event/event.c
++++ b/server/mpm/event/event.c
+@@ -1864,11 +1864,9 @@
+ else if (connections_above_limit(&workers_were_busy)) {
+ disable_listensocks();
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
+- "Too many open connections (%u), "
++ "Too many open connections (%u, %u idlers), "
+ "not accepting new conns in this process",
+- apr_atomic_read32(&connection_count));
+- ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, ap_server_conf,
+- "Idle workers: %u",
++ apr_atomic_read32(&connection_count),
+ ap_queue_info_num_idlers(worker_queue_info));
+ }
+ else if (!listener_may_exit) {
+@@ -2173,6 +2171,12 @@
+ }
+ }
+
++#if 0
++ if (is_idle) {
++ ap_queue_info_unset_idle(worker_queue_info);
++ }
++#endif
++
+ ap_update_child_status_from_indexes(process_slot, thread_slot,
+ dying ? SERVER_DEAD
+ : SERVER_GRACEFUL, NULL);
+@@ -2817,6 +2821,12 @@
+ int i, j;
+
+ for (i = 0; i < server_limit; ++i) {
++ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
++ "perform_idle_server_maintenance(%i/%i): "
++ "slot %i/%i, free %i/%i",
++ child_bucket, num_buckets,
++ i, retained->max_daemons_limit,
++ free_length, retained->idle_spawn_rate[child_bucket]);
+ if (num_buckets > 1 && (i % num_buckets) != child_bucket) {
+ /* We only care about child_bucket in this call */
+ continue;
+@@ -2832,6 +2842,13 @@
+ ps = &ap_scoreboard_image->parent[i];
+ if (ps->pid != 0) {
+ int child_threads_active = 0;
++ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
++ "perform_idle_server_maintenance(%i/%i): "
++ "slot %i/%i, pid %i, quiescing %i, daemons %i/%i",
++ child_bucket, num_buckets,
++ i, retained->max_daemons_limit,
++ (int)ps->pid, ps->quiescing,
++ retained->active_daemons, retained->total_daemons);
+ if (ps->quiescing == 1) {
+ ps->quiescing = 2;
+ retained->active_daemons--;
+@@ -3069,6 +3086,12 @@
+
+ event_note_child_killed(child_slot, 0, 0);
+ ps = &ap_scoreboard_image->parent[child_slot];
++ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
++ "server_main_loop(): "
++ "slot %i/%i, pid %i, quiescing %i, daemons %i/%i",
++ child_slot, retained->max_daemons_limit,
++ (int)ps->pid, ps->quiescing,
++ retained->active_daemons, retained->total_daemons);
+ if (ps->quiescing != 2)
+ retained->active_daemons--;
+ ps->quiescing = 0;
diff --git a/debian/patches/customize_apxs.patch b/debian/patches/customize_apxs.patch
new file mode 100644
index 0000000..281b910
--- /dev/null
+++ b/debian/patches/customize_apxs.patch
@@ -0,0 +1,220 @@
+Description: Adapt apxs to Debian specific changes
+ - Make apxs2 use a2enmod and /etc/apache2/mods-available
+ - Make libtool happier
+ - Use LDFLAGS from config_vars.mk, allows one to override them
+Forwarded: not-needed
+Author: Stefan Fritsch <sf@debian.org>
+Last-Update: 2012-03-17
+
+--- a/support/apxs.in
++++ b/support/apxs.in
+@@ -48,7 +48,7 @@
+ my $CFG_TARGET = get_vars("progname");
+ my $CFG_SYSCONFDIR = get_vars("sysconfdir");
+ my $CFG_CFLAGS = join ' ', map { get_vars($_) }
+- qw(SHLTCFLAGS CFLAGS NOTEST_CPPFLAGS EXTRA_CPPFLAGS EXTRA_CFLAGS);
++ qw(SHLTCFLAGS CFLAGS CPPFLAGS NOTEST_CPPFLAGS EXTRA_CPPFLAGS EXTRA_CFLAGS);
+ my $CFG_LDFLAGS = join ' ', map { get_vars($_) }
+ qw(LDFLAGS NOTEST_LDFLAGS SH_LDFLAGS);
+ my $includedir = $destdir . get_vars("includedir");
+@@ -59,7 +59,7 @@
+ my $sbindir = get_vars("sbindir");
+ my $CFG_SBINDIR = eval qq("$sbindir");
+ my $ltflags = $ENV{'LTFLAGS'};
+-$ltflags or $ltflags = "--silent";
++$ltflags or $ltflags = "";
+
+ my %internal_vars = map {$_ => 1}
+ qw(TARGET CC CFLAGS CFLAGS_SHLIB LD_SHLIB LDFLAGS_SHLIB LIBS_SHLIB
+@@ -286,6 +286,7 @@
+ $data =~ s|%TARGET%|$CFG_TARGET|sg;
+ $data =~ s|%PREFIX%|$prefix|sg;
+ $data =~ s|%INSTALLBUILDDIR%|$installbuilddir|sg;
++ $data =~ s|%DATADIR%|$datadir|sg;
+
+ my ($mkf, $mods, $src) = ($data =~ m|^(.+)-=#=-\n(.+)-=#=-\n(.+)|s);
+
+@@ -438,7 +439,7 @@
+ $la =~ s|\.c$|.la|;
+ my $o = $s;
+ $o =~ s|\.c$|.o|;
+- push(@cmds, "$libtool $ltflags --mode=compile $CFG_CC $cflags -I$CFG_INCLUDEDIR $apr_includedir $apu_includedir $opt -c -o $lo $s && touch $slo");
++ push(@cmds, "$libtool $ltflags --mode=compile --tag=disable-static $CFG_CC $cflags -I$CFG_INCLUDEDIR $apr_includedir $apu_includedir $opt -c -o $lo $s && touch $slo");
+ unshift(@objs, $lo);
+ }
+
+@@ -479,7 +480,7 @@
+ $opt .= " -rpath $CFG_LIBEXECDIR -module -avoid-version $apr_ldflags";
+ }
+
+- push(@cmds, "$libtool $ltflags --mode=link $CFG_CC $ldflags -o $dso_file $opt $lo");
++ push(@cmds, "$libtool $ltflags --mode=link --tag=disable-static $CFG_CC $ldflags -o $dso_file $opt $lo");
+
+ # execute the commands
+ &execute_cmds(@cmds);
+@@ -513,7 +514,7 @@
+ if ($opt_i) {
+ push(@cmds, $destdir . "$installbuilddir/instdso.sh SH_LIBTOOL='" .
+ "$libtool' $f $CFG_LIBEXECDIR");
+- push(@cmds, "chmod 755 $CFG_LIBEXECDIR/$t");
++ push(@cmds, "chmod 644 $CFG_LIBEXECDIR/$t");
+ }
+
+ # determine module symbolname and filename
+@@ -549,10 +550,11 @@
+ $filename = "mod_${name}.c";
+ }
+ my $dir = $CFG_LIBEXECDIR;
+- $dir =~ s|^$CFG_PREFIX/?||;
++ # Debian doesn't have a CFG_PREFIX, so this stuffs up:
++ # $dir =~ s|^$CFG_PREFIX/?||;
+ $dir =~ s|(.)$|$1/|;
+ $t =~ s|\.la$|.so|;
+- push(@lmd, sprintf("LoadModule %-18s %s", "${name}_module", "$dir$t"));
++ push(@lmd, [ $name, sprintf("LoadModule %-18s %s", "${name}_module", "$dir$t") ] );
+ }
+
+ # execute the commands
+@@ -560,108 +562,35 @@
+
+ # activate module via LoadModule/AddModule directive
+ if ($opt_a or $opt_A) {
+- if (not -f "$CFG_SYSCONFDIR/$CFG_TARGET.conf") {
+- error("Config file $CFG_SYSCONFDIR/$CFG_TARGET.conf not found");
++ if (not -d "$CFG_SYSCONFDIR/mods-available") {
++ error("Config file $CFG_SYSCONFDIR/mods-available not found");
+ exit(1);
+ }
+
+- open(FP, "<$CFG_SYSCONFDIR/$CFG_TARGET.conf") || die;
+- my $content = join('', <FP>);
+- close(FP);
+-
+- if ($content !~ m|\n#?\s*LoadModule\s+|) {
+- error("Activation failed for custom $CFG_SYSCONFDIR/$CFG_TARGET.conf file.");
+- error("At least one `LoadModule' directive already has to exist.");
+- exit(1);
+- }
+-
+- my $lmd;
+- my $c = '';
+- $c = '#' if ($opt_A);
+- foreach $lmd (@lmd) {
+- my $what = $opt_A ? "preparing" : "activating";
+- my $lmd_re = $lmd;
+- $lmd_re =~ s/\s+/\\s+/g;
+-
+- if ($content !~ m|\n#?\s*$lmd_re|) {
+- # check for open <containers>, so that the new LoadModule
+- # directive always appears *outside* of an <container>.
+-
+- my $before = ($content =~ m|^(.*\n)#?\s*LoadModule\s+[^\n]+\n|s)[0];
+-
+- # the '()=' trick forces list context and the scalar
+- # assignment counts the number of list members (aka number
+- # of matches) then
+- my $cntopen = () = ($before =~ m|^\s*<[^/].*$|mg);
+- my $cntclose = () = ($before =~ m|^\s*</.*$|mg);
+-
+- if ($cntopen == $cntclose) {
+- # fine. Last LoadModule is contextless.
+- $content =~ s|^(.*\n#?\s*LoadModule\s+[^\n]+\n)|$1$c$lmd\n|s;
++ my $entry;
++ foreach $entry (@lmd) {
++ my ($name, $lmd) = @{$entry};
++ my $filename = "$CFG_SYSCONFDIR/mods-available/$name.load";
++ if (-f $filename) {
++ my $cmd = "mv $filename $filename.bak~";
++ if (system($cmd) != 0) {
++ die "'$cmd' failed\n";
+ }
+- elsif ($cntopen < $cntclose) {
+- error('Configuration file is not valid. There are sections'
+- . ' closed before opened.');
+- exit(1);
+- }
+- else {
+- # put our cmd after the section containing the last
+- # LoadModule.
+- my $found =
+- $content =~ s!\A ( # string and capture start
+- (?:(?:
+- ^\s* # start of conf line with a
+- (?:[^<]|<[^/]) # directive which does not
+- # start with '</'
+-
+- .*(?:$)\n # rest of the line.
+- # the '$' is in parentheses
+- # to avoid misinterpreting
+- # the string "$\" as
+- # perl variable.
+-
+- )* # catch as much as possible
+- # of such lines. (including
+- # zero)
+-
+- ^\s*</.*(?:$)\n? # after the above, we
+- # expect a config line with
+- # a closing container (</)
+-
+- ) {$cntopen} # the whole pattern (bunch
+- # of lines that end up with
+- # a closing directive) must
+- # be repeated $cntopen
+- # times. That's it.
+- # Simple, eh? ;-)
+-
+- ) # capture end
+- !$1$c$lmd\n!mx;
+-
+- unless ($found) {
+- error('Configuration file is not valid. There are '
+- . 'sections opened and not closed.');
+- exit(1);
+- }
++ }
++
++ notice("[preparing module `$name' in $filename]");
++ open(FP, ">$filename") || die;
++ print FP "$lmd\n";
++ close(FP);
++
++ if ($opt_a) {
++ my $cmd = "a2enmod $name";
++ if (system($cmd) != 0) {
++ die "'$cmd' failed\n";
+ }
+- } else {
+- # replace already existing LoadModule line
+- $content =~ s|^(.*\n)#?\s*$lmd_re[^\n]*\n|$1$c$lmd\n|s;
+- }
+- $lmd =~ m|LoadModule\s+(.+?)_module.*|;
+- notice("[$what module `$1' in $CFG_SYSCONFDIR/$CFG_TARGET.conf]");
+- }
+- if (@lmd) {
+- if (open(FP, ">$CFG_SYSCONFDIR/$CFG_TARGET.conf.new")) {
+- print FP $content;
+- close(FP);
+- system("cp $CFG_SYSCONFDIR/$CFG_TARGET.conf $CFG_SYSCONFDIR/$CFG_TARGET.conf.bak && " .
+- "cp $CFG_SYSCONFDIR/$CFG_TARGET.conf.new $CFG_SYSCONFDIR/$CFG_TARGET.conf && " .
+- "rm $CFG_SYSCONFDIR/$CFG_TARGET.conf.new");
+- } else {
+- notice("unable to open configuration file");
+ }
+- }
++
++ }
+ }
+ }
+
+@@ -681,8 +610,8 @@
+ ##
+
+ builddir=.
+-top_srcdir=%PREFIX%
+-top_builddir=%PREFIX%
++top_srcdir=%DATADIR%
++top_builddir=%DATADIR%
+ include %INSTALLBUILDDIR%/special.mk
+
+ # the used tools
diff --git a/debian/patches/fhs_compliance.patch b/debian/patches/fhs_compliance.patch
new file mode 100644
index 0000000..1d5fc98
--- /dev/null
+++ b/debian/patches/fhs_compliance.patch
@@ -0,0 +1,70 @@
+Description: Fix up FHS file locations for apache2 droppings.
+Forwarded: not-needed
+Author: Adam Conrad <adconrad@0c3.net>
+Reviewed-By: Yadd <yadd@debian.org>
+Last-Update: 2023-10-19
+
+--- a/configure
++++ b/configure
+@@ -41291,17 +41291,17 @@
+
+
+ cat >>confdefs.h <<_ACEOF
+-#define HTTPD_ROOT "${ap_prefix}"
++#define HTTPD_ROOT "/etc/apache2"
+ _ACEOF
+
+
+ cat >>confdefs.h <<_ACEOF
+-#define SERVER_CONFIG_FILE "${rel_sysconfdir}/${progname}.conf"
++#define SERVER_CONFIG_FILE "${progname}.conf"
+ _ACEOF
+
+
+ cat >>confdefs.h <<_ACEOF
+-#define AP_TYPES_CONFIG_FILE "${rel_sysconfdir}/mime.types"
++#define AP_TYPES_CONFIG_FILE "mime.types"
+ _ACEOF
+
+
+--- a/configure.in
++++ b/configure.in
+@@ -902,11 +902,11 @@
+ echo $MODLIST | $AWK -f $srcdir/build/build-modules-c.awk > modules.c
+
+ APR_EXPAND_VAR(ap_prefix, $prefix)
+-AC_DEFINE_UNQUOTED(HTTPD_ROOT, "${ap_prefix}",
++AC_DEFINE_UNQUOTED(HTTPD_ROOT, "/etc/apache2",
+ [Root directory of the Apache install area])
+-AC_DEFINE_UNQUOTED(SERVER_CONFIG_FILE, "${rel_sysconfdir}/${progname}.conf",
++AC_DEFINE_UNQUOTED(SERVER_CONFIG_FILE, "${progname}.conf",
+ [Location of the config file, relative to the Apache root directory])
+-AC_DEFINE_UNQUOTED(AP_TYPES_CONFIG_FILE, "${rel_sysconfdir}/mime.types",
++AC_DEFINE_UNQUOTED(AP_TYPES_CONFIG_FILE, "mime.types",
+ [Location of the MIME types config file, relative to the Apache root directory])
+
+ perlbin=`$ac_aux_dir/PrintPath perl`
+--- a/include/ap_config_layout.h.in
++++ b/include/ap_config_layout.h.in
+@@ -60,5 +60,6 @@
+ #define DEFAULT_REL_LOGFILEDIR "@rel_logfiledir@"
+ #define DEFAULT_EXP_PROXYCACHEDIR "@exp_proxycachedir@"
+ #define DEFAULT_REL_PROXYCACHEDIR "@rel_proxycachedir@"
++#define DEFAULT_PIDLOG "/var/run/apache2.pid"
+
+ #endif /* AP_CONFIG_LAYOUT_H */
+--- a/include/httpd.h
++++ b/include/httpd.h
+@@ -107,10 +107,10 @@
+ #ifndef DOCUMENT_LOCATION
+ #ifdef OS2
+ /* Set default for OS/2 file system */
+-#define DOCUMENT_LOCATION HTTPD_ROOT "/docs"
++#define DOCUMENT_LOCATION "/var/www/html"
+ #else
+ /* Set default for non OS/2 file system */
+-#define DOCUMENT_LOCATION HTTPD_ROOT "/htdocs"
++#define DOCUMENT_LOCATION "/var/www/html"
+ #endif
+ #endif /* DOCUMENT_LOCATION */
+
diff --git a/debian/patches/fix-macro.patch b/debian/patches/fix-macro.patch
new file mode 100644
index 0000000..ea83a64
--- /dev/null
+++ b/debian/patches/fix-macro.patch
@@ -0,0 +1,160 @@
+Description: add macro_ignore_empty and macro_ignore_bad_nesting parameters
+Author: Upstream authors
+Origin: upstream, https://svn.apache.org/viewvc/httpd/httpd/trunk/modules/core/mod_macro.c?r1=1770843&r2=1770842&pathrev=1770843
+Forwarded: not-needed
+Reviewed-By: Yadd <yadd@debian.org>
+Last-Update: 2021-10-25
+
+--- a/modules/core/mod_macro.c
++++ b/modules/core/mod_macro.c
+@@ -49,6 +49,10 @@
+
+ /********************************************************** MACRO MANAGEMENT */
+
++/* Global warning modifiers */
++int ignore_empty = FALSE; /* no warning about empty argument */
++int ignore_bad_nesting = FALSE; /* no warning about bad nesting */
++
+ /*
+ this is a macro: name, arguments, contents, location.
+ */
+@@ -58,6 +62,8 @@
+ apr_array_header_t *arguments; /* of char*, macro parameter names */
+ apr_array_header_t *contents; /* of char*, macro body */
+ char *location; /* of macro definition, for error messages */
++ int ignore_empty; /* no warning about empty argument */
++ int ignore_bad_nesting; /* no warning about bad nesting */
+ } ap_macro_t;
+
+ /* configuration tokens.
+@@ -67,6 +73,10 @@
+ #define USE_MACRO "Use"
+ #define UNDEF_MACRO "UndefMacro"
+
++#define IGNORE_EMPTY_MACRO_FLAG "/IgnoreEmptyArgs"
++#define IGNORE_BAD_NESTING_MACRO_FLAG "/IgnoreBadNesting"
++#define IGNORE_EMPTY_MACRO_DIRECTIVE "MacroIgnoreEmptyArgs"
++#define IGNORE_BAD_NESTING_MACRO_DIRECTIVE "MacroIgnoreBadNesting"
+ /*
+ Macros are kept globally...
+ They are not per-server or per-directory entities.
+@@ -135,7 +145,8 @@
+ const char *end_token,
+ const char *begin_token,
+ const char *where,
+- apr_array_header_t ** plines)
++ apr_array_header_t ** plines,
++ int ignore_nesting)
+ {
+ apr_array_header_t *lines = apr_array_make(pool, 1, sizeof(char *));
+ char line[MAX_STRING_LEN]; /* sorry, but this is expected by getline:-( */
+@@ -153,7 +164,7 @@
+ /* detect nesting... */
+ if (!strncmp(first, "</", 2)) {
+ any_nesting--;
+- if (any_nesting < 0) {
++ if (!ignore_nesting && (any_nesting < 0)) {
+ ap_log_error(APLOG_MARK, APLOG_WARNING,
+ 0, NULL, APLOGNO(02793)
+ "bad (negative) nesting on line %d of %s",
+@@ -180,7 +191,7 @@
+
+ macro_nesting--;
+ if (!macro_nesting) {
+- if (any_nesting) {
++ if (!ignore_nesting && any_nesting) {
+ ap_log_error(APLOG_MARK,
+ APLOG_WARNING, 0, NULL, APLOGNO(02795)
+ "bad cumulated nesting (%+d) in %s",
+@@ -255,6 +266,13 @@
+ tab[i], i + 1, ARG_PREFIX);
+ }
+
++ if ((tab[i][0] == '$') && (tab[i][1] == '{')) {
++ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, APLOGNO(02805)
++ "macro '%s' (%s) "
++ "argument name '%s' (#%d) clashes with 'Define' syntax '${...}', better use '$(...)'.",
++ macro->name, macro->location, tab[i], i + 1);
++ }
++
+ for (j = i + 1; j < nelts; j++) {
+ size_t ltabj = strlen(tab[j]);
+
+@@ -763,7 +781,25 @@
+ where, ARG_PREFIX);
+ }
+
+- /* get macro parameters */
++ /* get/remove macro modifiers from parameters */
++#define CHECK_MACRO_FLAG(arg_, flag_str, flag_val) if (!strncasecmp(arg_, flag_str, strlen(flag_str))) { flag_val = TRUE; arg_ += strlen(flag_str); if (!*arg) break;}
++ while (*arg == '/') {
++ CHECK_MACRO_FLAG(arg, IGNORE_EMPTY_MACRO_FLAG, macro->ignore_empty);
++ CHECK_MACRO_FLAG(arg, IGNORE_BAD_NESTING_MACRO_FLAG, macro->ignore_bad_nesting);
++ if (*arg != ' ') {
++ char *c = ap_strchr(arg, ' ');
++ if (c) *c = '\0';
++ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, NULL, APLOGNO(02804)
++ "%s: unknown flag '%s'", where, arg);
++ if (c) {
++ *c = ' ';
++ arg = c;
++ }
++ }
++ arg++;
++ }
++
++ /* get macro parameters */
+ macro->arguments = get_arguments(pool, arg);
+
+ errmsg = check_macro_arguments(cmd->temp_pool, macro);
+@@ -774,7 +810,7 @@
+
+ errmsg = get_lines_till_end_token(pool, cmd->config_file,
+ END_MACRO, BEGIN_MACRO,
+- where, &macro->contents);
++ where, &macro->contents, ignore_bad_nesting || macro->ignore_bad_nesting);
+
+ if (errmsg) {
+ return apr_psprintf(cmd->temp_pool,
+@@ -860,7 +896,8 @@
+ cmd->config_file->line_number,
+ cmd->config_file->name);
+
+- check_macro_use_arguments(where, replacements);
++ if (!ignore_empty && !macro->ignore_empty)
++ check_macro_use_arguments(where, replacements);
+
+ errmsg = process_content(cmd->temp_pool, macro, replacements,
+ NULL, &contents);
+@@ -911,6 +948,18 @@
+ return NULL;
+ }
+
++static const char *macro_ignore_empty(cmd_parms * cmd, void *dummy)
++{
++ ignore_empty = TRUE;
++ return NULL;
++}
++
++static const char *macro_ignore_bad_nesting(cmd_parms * cmd, void *dummy)
++{
++ ignore_bad_nesting = TRUE;
++ return NULL;
++}
++
+ /************************************************************* EXPORT MODULE */
+
+ /*
+@@ -924,7 +973,11 @@
+ AP_INIT_RAW_ARGS(USE_MACRO, use_macro, NULL, EXEC_ON_READ | OR_ALL,
+ "Use of a macro."),
+ AP_INIT_TAKE1(UNDEF_MACRO, undef_macro, NULL, EXEC_ON_READ | OR_ALL,
+- "Remove a macro definition."),
++ "Remove a macro definition."),
++ AP_INIT_NO_ARGS(IGNORE_EMPTY_MACRO_DIRECTIVE, macro_ignore_empty, NULL, EXEC_ON_READ | OR_ALL,
++ "Globally ignore warnings about empty arguments."),
++ AP_INIT_NO_ARGS(IGNORE_BAD_NESTING_MACRO_DIRECTIVE, macro_ignore_bad_nesting, NULL, EXEC_ON_READ | OR_ALL,
++ "Globally ignore warnings about bad nesting."),
+
+ {NULL}
+ };
diff --git a/debian/patches/no_LD_LIBRARY_PATH.patch b/debian/patches/no_LD_LIBRARY_PATH.patch
new file mode 100644
index 0000000..85966fd
--- /dev/null
+++ b/debian/patches/no_LD_LIBRARY_PATH.patch
@@ -0,0 +1,18 @@
+Description: Remove LD_LIBRARY_PATH from envvars-std
+Forwarded: no
+Author: Adam Conrad <adconrad@0c3.net>
+Last-Update: 2012-04-15
+--- a/support/envvars-std.in
++++ b/support/envvars-std.in
+@@ -18,11 +18,4 @@
+ #
+ # This file is generated from envvars-std.in
+ #
+-if test "x$@SHLIBPATH_VAR@" != "x" ; then
+- @SHLIBPATH_VAR@="@exp_libdir@:$@SHLIBPATH_VAR@"
+-else
+- @SHLIBPATH_VAR@="@exp_libdir@"
+-fi
+-export @SHLIBPATH_VAR@
+-#
+ @OS_SPECIFIC_VARS@
diff --git a/debian/patches/pcre2.patch b/debian/patches/pcre2.patch
new file mode 100644
index 0000000..0ddb041
--- /dev/null
+++ b/debian/patches/pcre2.patch
@@ -0,0 +1,377 @@
+Description: build with pcre2
+Origin: other, https://helperbyte.com/questions/457338/how-to-make-pcre2-support-for-apache-24
+Bug-Debian: https://bugs.debian.org/1000114
+Forwarded: not-needed
+Reviewed-By: Yadd <yadd@debian.org>
+Last-Update: 2021-12-28
+
+--- a/build/NWGNUmakefile
++++ b/build/NWGNUmakefile
+@@ -20,7 +20,7 @@
+ $(SRC)/include/ap_config_layout.h \
+ $(NWOS)/test_char.h \
+ $(PCRE)/config.h \
+- $(PCRE)/pcre.h \
++ $(PCRE)/pcre2.h \
+ $(EOLIST)
+
+ nlms :: libs $(NWOS)/httpd.imp $(DAV)/main/dav.imp $(STDMOD)/cache/mod_cache.imp
+@@ -77,7 +77,7 @@
+ @echo $(DL)GEN $@$(DL)
+ $< $@
+
+-%.exe: $(PCRE)/%.c $(PCRE)/config.h $(PCRE)/pcre.h
++%.exe: $(PCRE)/%.c $(PCRE)/config.h $(PCRE)/pcre2.h
+ @echo $(DL)Creating Build Helper $@$(DL)
+ $(CC_FOR_BUILD) $(CFLAGS_FOR_BUILD) -DHAVE_CONFIG_H $< -o $@
+
+@@ -117,7 +117,7 @@
+ clean ::
+ $(call DEL,$(SRC)/include/ap_config_layout.h)
+ $(call DEL,$(PCRE)/config.h)
+- $(call DEL,$(PCRE)/pcre.h)
++ $(call DEL,$(PCRE)/pcre2.h)
+ $(call DEL,$(STDMOD)/cache/mod_cache.imp)
+ $(call DEL,$(DAV)/main/dav.imp)
+ $(call DEL,$(NWOS)/httpd.imp)
+--- a/include/ap_config_auto.h.in
++++ b/include/ap_config_auto.h.in
+@@ -393,3 +393,6 @@
+
+ /* Define to 'int' if <sys/resource.h> doesn't define it for us */
+ #undef rlim_t
++
++/* Load PCRE2 */
++#define HAVE_PCRE2 1
+--- a/include/ap_regex.h
++++ b/include/ap_regex.h
+@@ -70,19 +70,22 @@
+
+ /* Options for ap_regcomp, ap_regexec, and ap_rxplus versions: */
+
+-#define AP_REG_ICASE 0x01 /** use a case-insensitive match */
+-#define AP_REG_NEWLINE 0x02 /** don't match newlines against '.' etc */
+-#define AP_REG_NOTBOL 0x04 /** ^ will not match against start-of-string */
+-#define AP_REG_NOTEOL 0x08 /** $ will not match against end-of-string */
+-
+-#define AP_REG_EXTENDED (0) /** unused */
+-#define AP_REG_NOSUB (0) /** unused */
+-
+-#define AP_REG_MULTI 0x10 /* perl's /g (needs fixing) */
+-#define AP_REG_NOMEM 0x20 /* nomem in our code */
+-#define AP_REG_DOTALL 0x40 /* perl's /s flag */
++#define AP_REG_ICASE 0x01 /**< use a case-insensitive match */
++#define AP_REG_NEWLINE 0x02 /**< don't match newlines against '.' etc */
++#define AP_REG_NOTBOL 0x04 /**< ^ will not match against start-of-string */
++#define AP_REG_NOTEOL 0x08 /**< $ will not match against end-of-string */
++
++#define AP_REG_EXTENDED (0) /**< unused */
++#define AP_REG_NOSUB (0) /**< unused */
++
++#define AP_REG_MULTI 0x10 /**< perl's /g (needs fixing) */
++#define AP_REG_NOMEM 0x20 /**< nomem in our code */
++#define AP_REG_DOTALL 0x40 /**< perl's /s flag */
++
++#define AP_REG_NOTEMPTY 0x080 /**< Empty match not valid */
++#define AP_REG_ANCHORED 0x100 /**< Match at the first position */
+
+-#define AP_REG_DOLLAR_ENDONLY 0x200 /* '$' matches at end of subject string only */
++#define AP_REG_DOLLAR_ENDONLY 0x200 /**< '$' matches at end of subject string only */
+
+ #define AP_REG_NO_DEFAULT 0x400 /**< Don't implicitely add AP_REG_DEFAULT options */
+
+@@ -90,6 +93,12 @@
+
+ #define AP_REG_DEFAULT (AP_REG_DOTALL|AP_REG_DOLLAR_ENDONLY)
+
++/* Arguments for ap_pcre_version_string */
++enum {
++ AP_REG_PCRE_COMPILED = 0, /** PCRE version used during program compilation */
++ AP_REG_PCRE_LOADED /** PCRE version loaded at runtime */
++};
++
+ /* Error values: */
+ enum {
+ AP_REG_ASSERT = 1, /** internal error ? */
+@@ -114,6 +123,15 @@
+ /* The functions */
+
+ /**
++ * Return PCRE version string.
++ * @param which Either AP_REG_PCRE_COMPILED (PCRE version used
++ * during program compilation) or AP_REG_PCRE_LOADED
++ * (PCRE version used at runtime)
++ * @return The PCRE version string
++ */
++AP_DECLARE(const char *) ap_pcre_version_string(int which);
++
++/**
+ * Get default compile flags
+ * @return Bitwise OR of AP_REG_* flags
+ */
+@@ -277,5 +295,4 @@
+ } /* extern "C" */
+ #endif
+
+-#endif /* AP_REGEX_T */
+-
++#endif /* AP_REGEX_H */
+--- a/server/util_pcre.c
++++ b/server/util_pcre.c
+@@ -55,19 +55,17 @@
+ #include "httpd.h"
+ #include "apr_strings.h"
+ #include "apr_tables.h"
+-#include "pcre.h"
+
+-/* PCRE_DUPNAMES is only present since version 6.7 of PCRE */
+-#ifndef PCRE_DUPNAMES
+-#error PCRE Version 6.7 or later required!
+-#else
++#define PCRE2_CODE_UNIT_WIDTH 8
++#include "pcre2.h"
++#define PCREn(x) PCRE2_ ## x
+
++/* PCRE_DUPNAMES is only present since version 6.7 of PCRE */
+ #define APR_WANT_STRFUNC
+ #include "apr_want.h"
+
+ #ifndef POSIX_MALLOC_THRESHOLD
+ #define POSIX_MALLOC_THRESHOLD (10)
+-#endif
+
+ /* Table of error strings corresponding to POSIX error codes; must be
+ * kept in synch with include/ap_regex.h's AP_REG_E* definitions.
+@@ -81,6 +79,20 @@
+ "match failed" /* AP_REG_NOMATCH */
+ };
+
++AP_DECLARE(const char *) ap_pcre_version_string(int which)
++{
++ static char buf[80];
++ switch (which) {
++ case AP_REG_PCRE_COMPILED:
++ return APR_STRINGIFY(PCREn(MAJOR)) "." APR_STRINGIFY(PCREn(MINOR)) " " APR_STRINGIFY(PCREn(DATE));
++ case AP_REG_PCRE_LOADED:
++ pcre2_config(PCRE2_CONFIG_VERSION, buf);
++ return buf;
++ default:
++ return "Unknown";
++ }
++}
++
+ AP_DECLARE(apr_size_t) ap_regerror(int errcode, const ap_regex_t *preg,
+ char *errbuf, apr_size_t errbuf_size)
+ {
+@@ -115,7 +127,7 @@
+
+ AP_DECLARE(void) ap_regfree(ap_regex_t *preg)
+ {
+- (pcre_free)(preg->re_pcre);
++ pcre2_code_free(preg->re_pcre);
+ }
+
+
+@@ -168,39 +180,38 @@
+ */
+ AP_DECLARE(int) ap_regcomp(ap_regex_t * preg, const char *pattern, int cflags)
+ {
+- const char *errorptr;
+- int erroffset;
++ uint32_t capcount;
++ size_t erroffset;
+ int errcode = 0;
+- int options = PCRE_DUPNAMES;
++ int options = PCREn(DUPNAMES);
+
+ if ((cflags & AP_REG_NO_DEFAULT) == 0)
+ cflags |= default_cflags;
+
+ if ((cflags & AP_REG_ICASE) != 0)
+- options |= PCRE_CASELESS;
++ options |= PCREn(CASELESS);
+ if ((cflags & AP_REG_NEWLINE) != 0)
+- options |= PCRE_MULTILINE;
++ options |= PCREn(MULTILINE);
+ if ((cflags & AP_REG_DOTALL) != 0)
+- options |= PCRE_DOTALL;
++ options |= PCREn(DOTALL);
+ if ((cflags & AP_REG_DOLLAR_ENDONLY) != 0)
+- options |= PCRE_DOLLAR_ENDONLY;
++ options |= PCREn(DOLLAR_ENDONLY);
+
+- preg->re_pcre =
+- pcre_compile2(pattern, options, &errcode, &errorptr, &erroffset, NULL);
+- preg->re_erroffset = erroffset;
++ preg->re_pcre = pcre2_compile((const unsigned char *)pattern,
++ PCRE2_ZERO_TERMINATED, options, &errcode,
++ &erroffset, NULL);
+
++ preg->re_erroffset = erroffset;
+ if (preg->re_pcre == NULL) {
+- /*
+- * There doesn't seem to be constants defined for compile time error
+- * codes. 21 is "failed to get memory" according to pcreapi(3).
+- */
++ /* Internal ERR21 is "failed to get memory" according to pcreapi(3) */
+ if (errcode == 21)
+ return AP_REG_ESPACE;
+ return AP_REG_INVARG;
+ }
+
+- pcre_fullinfo((const pcre *)preg->re_pcre, NULL,
+- PCRE_INFO_CAPTURECOUNT, &(preg->re_nsub));
++ pcre2_pattern_info((const pcre2_code *)preg->re_pcre,
++ PCRE2_INFO_CAPTURECOUNT, &capcount);
++ preg->re_nsub = capcount;
+ return 0;
+ }
+
+@@ -232,74 +243,77 @@
+ {
+ int rc;
+ int options = 0;
+- int *ovector = NULL;
+- int small_ovector[POSIX_MALLOC_THRESHOLD * 3];
+- int allocated_ovector = 0;
++ apr_size_t nlim;
++ pcre2_match_data *matchdata;
++ size_t *ovector;
+
+ if ((eflags & AP_REG_NOTBOL) != 0)
+- options |= PCRE_NOTBOL;
++ options |= PCREn(NOTBOL);
+ if ((eflags & AP_REG_NOTEOL) != 0)
+- options |= PCRE_NOTEOL;
+-
+- ((ap_regex_t *)preg)->re_erroffset = (apr_size_t)(-1); /* Only has meaning after compile */
+-
+- if (nmatch > 0) {
+- if (nmatch <= POSIX_MALLOC_THRESHOLD) {
+- ovector = &(small_ovector[0]);
+- }
+- else {
+- ovector = (int *)malloc(sizeof(int) * nmatch * 3);
+- if (ovector == NULL)
+- return AP_REG_ESPACE;
+- allocated_ovector = 1;
+- }
+- }
+-
+- rc = pcre_exec((const pcre *)preg->re_pcre, NULL, buff, (int)len,
+- 0, options, ovector, nmatch * 3);
+-
++ options |= PCREn(NOTEOL);
++ if ((eflags & AP_REG_NOTEMPTY) != 0)
++ options |= PCREn(NOTEMPTY);
++ if ((eflags & AP_REG_ANCHORED) != 0)
++ options |= PCREn(ANCHORED);
++
++ /* TODO: create a generic TLS matchdata buffer of some nmatch limit,
++ * e.g. 10 matches, to avoid a malloc-per-call. If it must be allocated,
++ * implement a general context using palloc and no free implementation.
++ */
++ nlim = ((apr_size_t)preg->re_nsub + 1) > nmatch
++ ? ((apr_size_t)preg->re_nsub + 1) : nmatch;
++ matchdata = pcre2_match_data_create(nlim, NULL);
++ if (matchdata == NULL)
++ return AP_REG_ESPACE;
++ ovector = pcre2_get_ovector_pointer(matchdata);
++ rc = pcre2_match((const pcre2_code *)preg->re_pcre,
++ (const unsigned char *)buff, len,
++ 0, options, matchdata, NULL);
+ if (rc == 0)
+- rc = nmatch; /* All captured slots were filled in */
++ rc = nlim; /* All captured slots were filled in */
+
+ if (rc >= 0) {
+ apr_size_t i;
+- for (i = 0; i < (apr_size_t)rc; i++) {
++ nlim = (apr_size_t)rc < nmatch ? (apr_size_t)rc : nmatch;
++ for (i = 0; i < nlim; i++) {
+ pmatch[i].rm_so = ovector[i * 2];
+ pmatch[i].rm_eo = ovector[i * 2 + 1];
+ }
+- if (allocated_ovector)
+- free(ovector);
+ for (; i < nmatch; i++)
+ pmatch[i].rm_so = pmatch[i].rm_eo = -1;
+- return 0;
+ }
+
++ pcre2_match_data_free(matchdata);
++
++ if (rc >= 0) {
++ return 0;
++ }
+ else {
+- if (allocated_ovector)
+- free(ovector);
++ if (rc <= PCRE2_ERROR_UTF8_ERR1 && rc >= PCRE2_ERROR_UTF8_ERR21)
++ return AP_REG_INVARG;
+ switch (rc) {
+- case PCRE_ERROR_NOMATCH:
++ case PCREn(ERROR_NOMATCH):
+ return AP_REG_NOMATCH;
+- case PCRE_ERROR_NULL:
++ case PCREn(ERROR_NULL):
+ return AP_REG_INVARG;
+- case PCRE_ERROR_BADOPTION:
++ case PCREn(ERROR_BADOPTION):
+ return AP_REG_INVARG;
+- case PCRE_ERROR_BADMAGIC:
++ case PCREn(ERROR_BADMAGIC):
+ return AP_REG_INVARG;
+- case PCRE_ERROR_UNKNOWN_NODE:
+- return AP_REG_ASSERT;
+- case PCRE_ERROR_NOMEMORY:
++ case PCREn(ERROR_NOMEMORY):
+ return AP_REG_ESPACE;
+-#ifdef PCRE_ERROR_MATCHLIMIT
+- case PCRE_ERROR_MATCHLIMIT:
++ case PCREn(ERROR_MATCHLIMIT):
+ return AP_REG_ESPACE;
++#if defined(PCRE_ERROR_UNKNOWN_NODE)
++ case PCRE_ERROR_UNKNOWN_NODE:
++ return AP_REG_ASSERT;
+ #endif
+-#ifdef PCRE_ERROR_BADUTF8
+- case PCRE_ERROR_BADUTF8:
++#if defined(PCRE_ERROR_BADUTF8)
++ case PCREn(ERROR_BADUTF8):
+ return AP_REG_INVARG;
+ #endif
+-#ifdef PCRE_ERROR_BADUTF8_OFFSET
+- case PCRE_ERROR_BADUTF8_OFFSET:
++#if defined(PCRE_ERROR_BADUTF8_OFFSET)
++ case PCREn(ERROR_BADUTF8_OFFSET):
+ return AP_REG_INVARG;
+ #endif
+ default:
+@@ -312,17 +326,17 @@
+ apr_array_header_t *names, const char *prefix,
+ int upper)
+ {
+- int namecount;
+- int nameentrysize;
+- int i;
+ char *nametable;
+
+- pcre_fullinfo((const pcre *)preg->re_pcre, NULL,
+- PCRE_INFO_NAMECOUNT, &namecount);
+- pcre_fullinfo((const pcre *)preg->re_pcre, NULL,
+- PCRE_INFO_NAMEENTRYSIZE, &nameentrysize);
+- pcre_fullinfo((const pcre *)preg->re_pcre, NULL,
+- PCRE_INFO_NAMETABLE, &nametable);
++ uint32_t namecount;
++ uint32_t nameentrysize;
++ uint32_t i;
++ pcre2_pattern_info((const pcre2_code *)preg->re_pcre,
++ PCRE2_INFO_NAMECOUNT, &namecount);
++ pcre2_pattern_info((const pcre2_code *)preg->re_pcre,
++ PCRE2_INFO_NAMEENTRYSIZE, &nameentrysize);
++ pcre2_pattern_info((const pcre2_code *)preg->re_pcre,
++ PCRE2_INFO_NAMETABLE, &nametable);
+
+ for (i = 0; i < namecount; i++) {
+ const char *offset = nametable + i * nameentrysize;
diff --git a/debian/patches/reproducible_builds.diff b/debian/patches/reproducible_builds.diff
new file mode 100644
index 0000000..36f71e2
--- /dev/null
+++ b/debian/patches/reproducible_builds.diff
@@ -0,0 +1,40 @@
+Description: Make builds reproducible
+ Don't use __DATE__ __TIME__. Use changelog date instead.
+ Sort exported symbols.
+Author: Jean-Michel Vourgère <nirgal@debian.org>
+Forwarded: no
+Last-Update: 2015-08-11
+
+--- a/server/buildmark.c
++++ b/server/buildmark.c
+@@ -17,11 +17,7 @@
+ #include "ap_config.h"
+ #include "httpd.h"
+
+-#if defined(__DATE__) && defined(__TIME__)
+-static const char server_built[] = __DATE__ " " __TIME__;
+-#else
+-static const char server_built[] = "unknown";
+-#endif
++static const char server_built[] = BUILD_DATETIME;
+
+ AP_DECLARE(const char *) ap_get_server_built()
+ {
+--- a/server/Makefile.in
++++ b/server/Makefile.in
+@@ -1,3 +1,4 @@
++export LC_ALL = C
+
+ CLEAN_TARGETS = gen_test_char test_char.h \
+ ApacheCoreOS2.def httpd.exp export_files \
+@@ -82,8 +83,8 @@
+ @echo "#! ." > $@
+ @echo "* This file was AUTOGENERATED at build time." >> $@
+ @echo "* Please do not edit by hand." >> $@
+- $(CPP) $(ALL_CPPFLAGS) $(ALL_INCLUDES) exports.c | grep "ap_hack_" | grep -v apr_ | sed -e 's/^.*[)]\(.*\);$$/\1/' >> $@
+- $(CPP) $(ALL_CPPFLAGS) $(ALL_INCLUDES) export_vars.h | grep -v apr_ | sed -e 's/^\#[^!]*//' | sed -e '/^$$/d' >> $@
++ $(CPP) $(ALL_CPPFLAGS) $(ALL_INCLUDES) exports.c | grep "ap_hack_" | grep -v apr_ | sed -e 's/^.*[)]\(.*\);$$/\1/' | sort >> $@
++ $(CPP) $(ALL_CPPFLAGS) $(ALL_INCLUDES) export_vars.h | grep -v apr_ | sed -e 's/^\#[^!]*//' | sed -e '/^$$/d' | sort >> $@
+
+
+ # developer stuff
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 0000000..d2c00e2
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1,15 @@
+fhs_compliance.patch
+no_LD_LIBRARY_PATH.patch
+suexec-CVE-2007-1742.patch
+customize_apxs.patch
+build_suexec-custom.patch
+reproducible_builds.diff
+#mod_proxy_ajp-add-secret-parameter.diff
+#buffer-http-request-bodies-for-tlsv13.diff
+#tlsv13-add-logno.diff
+fix-macro.patch
+#pcre2.patch
+#child_processes_fail_to_start.patch
+
+# This patch is applied manually
+#suexec-custom.patch
diff --git a/debian/patches/suexec-CVE-2007-1742.patch b/debian/patches/suexec-CVE-2007-1742.patch
new file mode 100644
index 0000000..159c2c9
--- /dev/null
+++ b/debian/patches/suexec-CVE-2007-1742.patch
@@ -0,0 +1,66 @@
+Description: Fix race condition with chdir
+ Fix /var/www* being accepted as docroot instead of /var/www/*
+ (the same for public_html* instead of public_html/* )
+Author: Stefan Fritsch <sf@debian.org>
+Last-Update: 2014-05-29
+Bug: https://issues.apache.org/bugzilla/show_bug.cgi?id=44752
+--- a/support/suexec.c
++++ b/support/suexec.c
+@@ -42,6 +42,7 @@
+ #if APR_HAVE_UNISTD_H
+ #include <unistd.h>
+ #endif
++#include <fcntl.h>
+
+ #include <stdio.h>
+ #include <stdarg.h>
+@@ -279,11 +280,12 @@
+ char *actual_gname; /* actual group name */
+ char *cmd; /* command to be executed */
+ char cwd[AP_MAXPATH]; /* current working directory */
+- char dwd[AP_MAXPATH]; /* docroot working directory */
++ char dwd[AP_MAXPATH+1]; /* docroot working directory */
+ struct passwd *pw; /* password entry holder */
+ struct group *gr; /* group entry holder */
+ struct stat dir_info; /* directory info holder */
+ struct stat prg_info; /* program info holder */
++ int cwdh; /* handle to cwd */
+
+ /*
+ * Start with a "clean" environment
+@@ -529,11 +531,16 @@
+ exit(111);
+ }
+
++ if ( (cwdh = open(".", O_RDONLY)) == -1 ) {
++ log_err("cannot open current working directory\n");
++ exit(111);
++ }
++
+ if (userdir) {
+ if (((chdir(target_homedir)) != 0) ||
+ ((chdir(AP_USERDIR_SUFFIX)) != 0) ||
+ ((getcwd(dwd, AP_MAXPATH)) == NULL) ||
+- ((chdir(cwd)) != 0)) {
++ ((fchdir(cwdh)) != 0)) {
+ log_err("cannot get docroot information (%s)\n", target_homedir);
+ exit(112);
+ }
+@@ -541,12 +548,16 @@
+ else {
+ if (((chdir(AP_DOC_ROOT)) != 0) ||
+ ((getcwd(dwd, AP_MAXPATH)) == NULL) ||
+- ((chdir(cwd)) != 0)) {
++ ((fchdir(cwdh)) != 0)) {
+ log_err("cannot get docroot information (%s)\n", AP_DOC_ROOT);
+ exit(113);
+ }
+ }
+
++ close(cwdh);
++
++ if (strlen(cwd) > strlen(dwd))
++ strncat(dwd, "/", 1);
+ if ((strncmp(cwd, dwd, strlen(dwd))) != 0) {
+ log_err("command not in docroot (%s/%s)\n", cwd, cmd);
+ exit(114);
diff --git a/debian/patches/suexec-custom.patch b/debian/patches/suexec-custom.patch
new file mode 100644
index 0000000..37b761d
--- /dev/null
+++ b/debian/patches/suexec-custom.patch
@@ -0,0 +1,190 @@
+Description: the actual patch to make suexec-custom read a config file
+Forwarded: not-needed
+Author: Stefan Fritsch <sf@debian.org>
+Last-Update: 2018-07-17
+--- a/support/suexec-custom.c
++++ b/support/suexec-custom.c
+@@ -29,6 +29,7 @@
+ *
+ *
+ */
++#define SUEXEC_CONFIG_DIR "/etc/apache2/suexec/"
+
+ #include "apr.h"
+ #include "ap_config.h"
+@@ -39,6 +40,7 @@
+ #include <sys/types.h>
+ #include <string.h>
+ #include <time.h>
++#include <ctype.h>
+ #if APR_HAVE_UNISTD_H
+ #include <unistd.h>
+ #endif
+@@ -222,6 +224,26 @@
+ return;
+ }
+
++static int read_line(char *buf, FILE *file) {
++ char *p;
++ p = fgets(buf, AP_MAXPATH+1, file);
++ if (!p) return 0;
++ if (*p == '\0') return 1;
++
++ p = buf;
++ while (*p)
++ p++;
++ p--;
++
++ /* remove trailing space and slash */
++ while ( isspace(*p) && p >= buf )
++ *p-- = '\0';
++ while ( *p == '/' && p >= buf )
++ *p-- = '\0';
++
++ return 1;
++}
++
+ static void clean_env(void)
+ {
+ char **cleanenv;
+@@ -286,6 +308,11 @@
+ struct stat dir_info; /* directory info holder */
+ struct stat prg_info; /* program info holder */
+ int cwdh; /* handle to cwd */
++ char *suexec_docroot = NULL;
++ char *suexec_userdir_suffix = NULL;
++ char *filename = NULL;
++ FILE *configfile;
++
+
+ /*
+ * Start with a "clean" environment
+@@ -315,15 +342,10 @@
+ || (! strcmp(AP_HTTPD_USER, pw->pw_name)))
+ #endif /* _OSD_POSIX */
+ ) {
+-#ifdef AP_DOC_ROOT
+- fprintf(stderr, " -D AP_DOC_ROOT=\"%s\"\n", AP_DOC_ROOT);
+-#endif
++ fprintf(stderr, " -D SUEXEC_CONFIG_DIR=%s\n", SUEXEC_CONFIG_DIR);
+ #ifdef AP_GID_MIN
+ fprintf(stderr, " -D AP_GID_MIN=%d\n", AP_GID_MIN);
+ #endif
+-#ifdef AP_HTTPD_USER
+- fprintf(stderr, " -D AP_HTTPD_USER=\"%s\"\n", AP_HTTPD_USER);
+-#endif
+ #if defined(AP_LOG_SYSLOG)
+ fprintf(stderr, " -D AP_LOG_SYSLOG\n");
+ #elif defined(AP_LOG_EXEC)
+@@ -338,9 +360,6 @@
+ #ifdef AP_UID_MIN
+ fprintf(stderr, " -D AP_UID_MIN=%d\n", AP_UID_MIN);
+ #endif
+-#ifdef AP_USERDIR_SUFFIX
+- fprintf(stderr, " -D AP_USERDIR_SUFFIX=\"%s\"\n", AP_USERDIR_SUFFIX);
+-#endif
+ exit(0);
+ }
+ /*
+@@ -355,23 +374,6 @@
+ target_gname = argv[2];
+ cmd = argv[3];
+
+- /*
+- * Check to see if the user running this program
+- * is the user allowed to do so as defined in
+- * suexec.h. If not the allowed user, error out.
+- */
+-#ifdef _OSD_POSIX
+- /* User name comparisons are case insensitive on BS2000/OSD */
+- if (strcasecmp(AP_HTTPD_USER, pw->pw_name)) {
+- log_err("user mismatch (%s instead of %s)\n", pw->pw_name, AP_HTTPD_USER);
+- exit(103);
+- }
+-#else /*_OSD_POSIX*/
+- if (strcmp(AP_HTTPD_USER, pw->pw_name)) {
+- log_err("user mismatch (%s instead of %s)\n", pw->pw_name, AP_HTTPD_USER);
+- exit(103);
+- }
+-#endif /*_OSD_POSIX*/
+
+ /*
+ * Check for a leading '/' (absolute path) in the command to be executed,
+@@ -396,6 +398,59 @@
+ }
+
+ /*
++ * Check to see if the user running this program
++ * is the user allowed to do so as defined in
++ * SUEXEC_CONFIG_DIR/username
++ * If not, error out.
++ */
++ suexec_docroot = malloc(AP_MAXPATH+1);
++ suexec_userdir_suffix = malloc(AP_MAXPATH+1);
++ if (!suexec_docroot || !suexec_userdir_suffix ||
++ asprintf(&filename, SUEXEC_CONFIG_DIR "%s", pw->pw_name) == -1) {
++ log_err("malloc failed\n");
++ exit(120);
++ }
++
++ configfile = fopen(filename, "r");
++ if (!configfile) {
++ log_err("User %s not allowed: Could not open config file %s\n", pw->pw_name, filename);
++ exit(123);
++ }
++
++ if (!read_line(suexec_docroot, configfile)) {
++ log_err("Could not read docroot from %s\n", filename);
++ exit(124);
++ }
++
++ if (!read_line(suexec_userdir_suffix, configfile)) {
++ log_err("Could not read userdir suffix from %s\n", filename);
++ exit(125);
++ }
++
++ fclose(configfile);
++
++ if (userdir) {
++ if ( !isalnum(*suexec_userdir_suffix) && suexec_userdir_suffix[0] != '.') {
++ log_err("userdir suffix disabled in %s\n", filename);
++ exit(126);
++ }
++ }
++ else {
++ if (suexec_docroot[0] != '/') {
++ log_err("docroot disabled in %s\n", filename);
++ exit(127);
++ }
++
++ if (suexec_docroot[1] == '/' ||
++ suexec_docroot[1] == '.' ||
++ suexec_docroot[1] == '\0' )
++ {
++ log_err("invalid docroot %s in %s\n", suexec_docroot, filename);
++ exit(128);
++ }
++ }
++
++ /*
+ * Error out if the target username is invalid.
+ */
+ if (strspn(target_uname, "1234567890") != strlen(target_uname)) {
+@@ -538,7 +593,7 @@
+
+ if (userdir) {
+ if (((chdir(target_homedir)) != 0) ||
+- ((chdir(AP_USERDIR_SUFFIX)) != 0) ||
++ ((chdir(suexec_userdir_suffix)) != 0) ||
+ ((getcwd(dwd, AP_MAXPATH)) == NULL) ||
+ ((fchdir(cwdh)) != 0)) {
+ log_err("cannot get docroot information (%s)\n", target_homedir);
+@@ -546,7 +601,7 @@
+ }
+ }
+ else {
+- if (((chdir(AP_DOC_ROOT)) != 0) ||
++ if (((chdir(suexec_docroot)) != 0) ||
+ ((getcwd(dwd, AP_MAXPATH)) == NULL) ||
+ ((fchdir(cwdh)) != 0)) {
+ log_err("cannot get docroot information (%s)\n", AP_DOC_ROOT);