diff options
Diffstat (limited to 'debian/patches')
-rw-r--r-- | debian/patches/build_suexec-custom.patch | 69 | ||||
-rw-r--r-- | debian/patches/child_processes_fail_to_start.patch | 75 | ||||
-rw-r--r-- | debian/patches/customize_apxs.patch | 220 | ||||
-rw-r--r-- | debian/patches/fhs_compliance.patch | 70 | ||||
-rw-r--r-- | debian/patches/fix-macro.patch | 160 | ||||
-rw-r--r-- | debian/patches/no_LD_LIBRARY_PATH.patch | 18 | ||||
-rw-r--r-- | debian/patches/pcre2.patch | 377 | ||||
-rw-r--r-- | debian/patches/reproducible_builds.diff | 40 | ||||
-rw-r--r-- | debian/patches/series | 15 | ||||
-rw-r--r-- | debian/patches/suexec-CVE-2007-1742.patch | 66 | ||||
-rw-r--r-- | debian/patches/suexec-custom.patch | 190 |
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, ¯o->contents); ++ where, ¯o->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); |