diff --git a/httpd-2.4.43-mod_systemd.patch b/httpd-2.4.43-mod_systemd.patch new file mode 100644 index 0000000000000000000000000000000000000000..8d7922e74143b60ec855fa083307c8ff30d7d6cf --- /dev/null +++ b/httpd-2.4.43-mod_systemd.patch @@ -0,0 +1,96 @@ + +More verbose startup logging for mod_systemd. + +--- httpd-2.4.43/modules/arch/unix/mod_systemd.c.mod_systemd ++++ httpd-2.4.43/modules/arch/unix/mod_systemd.c +@@ -29,11 +29,14 @@ + #include "mpm_common.h" + + #include "systemd/sd-daemon.h" ++#include "systemd/sd-journal.h" + + #if APR_HAVE_UNISTD_H + #include + #endif + ++static char describe_listeners[30]; ++ + static int systemd_pre_config(apr_pool_t *pconf, apr_pool_t *plog, + apr_pool_t *ptemp) + { +@@ -44,6 +47,20 @@ + return OK; + } + ++static char *dump_listener(ap_listen_rec *lr, apr_pool_t *p) ++{ ++ apr_sockaddr_t *sa = lr->bind_addr; ++ char addr[128]; ++ ++ if (apr_sockaddr_is_wildcard(sa)) { ++ return apr_pstrcat(p, "port ", apr_itoa(p, sa->port), NULL); ++ } ++ ++ apr_sockaddr_ip_getbuf(addr, sizeof addr, sa); ++ ++ return apr_psprintf(p, "%s port %u", addr, sa->port); ++} ++ + /* Report the service is ready in post_config, which could be during + * startup or after a reload. The server could still hit a fatal + * startup error after this point during ap_run_mpm(), so this is +@@ -51,19 +68,51 @@ + * the TCP ports so new connections will not be rejected. There will + * always be a possible async failure event simultaneous to the + * service reporting "ready", so this should be good enough. */ +-static int systemd_post_config(apr_pool_t *p, apr_pool_t *plog, ++static int systemd_post_config(apr_pool_t *pconf, apr_pool_t *plog, + apr_pool_t *ptemp, server_rec *main_server) + { ++ ap_listen_rec *lr; ++ apr_size_t plen = sizeof describe_listeners; ++ char *p = describe_listeners; ++ ++ if (ap_state_query(AP_SQ_MAIN_STATE) == AP_SQ_MS_CREATE_PRE_CONFIG) ++ return OK; ++ ++ for (lr = ap_listeners; lr; lr = lr->next) { ++ char *s = dump_listener(lr, ptemp); ++ ++ if (strlen(s) + 3 < plen) { ++ char *newp = apr_cpystrn(p, s, plen); ++ if (lr->next) ++ newp = apr_cpystrn(newp, ", ", 3); ++ plen -= newp - p; ++ p = newp; ++ } ++ else { ++ if (plen < 4) { ++ p = describe_listeners + sizeof describe_listeners - 4; ++ plen = 4; ++ } ++ apr_cpystrn(p, "...", plen); ++ break; ++ } ++ } ++ + sd_notify(0, "READY=1\n" + "STATUS=Configuration loaded.\n"); ++ ++ sd_journal_print(LOG_INFO, "Server configured, listening on: %s", ++ describe_listeners); ++ + return OK; + } + + static int systemd_pre_mpm(apr_pool_t *p, ap_scoreboard_e sb_type) + { + sd_notifyf(0, "READY=1\n" +- "STATUS=Processing requests...\n" +- "MAINPID=%" APR_PID_T_FMT, getpid()); ++ "STATUS=Started, listening on: %s\n" ++ "MAINPID=%" APR_PID_T_FMT, ++ describe_listeners, getpid()); + + return OK; + } diff --git a/httpd-2.4.43-sslprotdefault.patch b/httpd-2.4.43-sslprotdefault.patch new file mode 100644 index 0000000000000000000000000000000000000000..d0898239dc52ffb5d8d7cac5607be514007c4411 --- /dev/null +++ b/httpd-2.4.43-sslprotdefault.patch @@ -0,0 +1,99 @@ +diff --git a/modules/ssl/ssl_engine_config.c b/modules/ssl/ssl_engine_config.c +index 27e7a53..b53f3f8 100644 +--- a/modules/ssl/ssl_engine_config.c ++++ b/modules/ssl/ssl_engine_config.c +@@ -119,7 +119,7 @@ static void modssl_ctx_init(modssl_ctx_t *mctx, apr_pool_t *p) + mctx->ticket_key = NULL; + #endif + +- mctx->protocol = SSL_PROTOCOL_DEFAULT; ++ mctx->protocol = SSL_PROTOCOL_NONE; + mctx->protocol_set = 0; + + mctx->pphrase_dialog_type = SSL_PPTYPE_UNSET; +@@ -263,6 +263,7 @@ static void modssl_ctx_cfg_merge(apr_pool_t *p, + if (add->protocol_set) { + mrg->protocol_set = 1; + mrg->protocol = add->protocol; ++ mrg->protocol_set = 1; + } + else { + mrg->protocol_set = base->protocol_set; + +diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c +index bfad47a..b0fcf81 100644 +--- a/modules/ssl/ssl_engine_init.c ++++ b/modules/ssl/ssl_engine_init.c +@@ -577,6 +577,7 @@ static apr_status_t ssl_init_ctx_protocol(server_rec *s, + MODSSL_SSL_METHOD_CONST SSL_METHOD *method = NULL; + char *cp; + int protocol = mctx->protocol; ++ int protocol_set = mctx->protocol_set; + SSLSrvConfigRec *sc = mySrvConfig(s); + #if OPENSSL_VERSION_NUMBER >= 0x10100000L + int prot; +@@ -586,12 +587,18 @@ static apr_status_t ssl_init_ctx_protocol(server_rec *s, + * Create the new per-server SSL context + */ + if (protocol == SSL_PROTOCOL_NONE) { +- ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02231) +- "No SSL protocols available [hint: SSLProtocol]"); +- return ssl_die(s); +- } ++ if (protocol_set) { ++ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02231) ++ "No SSL protocols available [hint: SSLProtocol]"); ++ return ssl_die(s); ++ } + +- cp = apr_pstrcat(p, ++ ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, s, ++ "Using OpenSSL/system default SSL/TLS protocols"); ++ cp = "default"; ++ } ++ else { ++ cp = apr_pstrcat(p, + #ifndef OPENSSL_NO_SSL3 + (protocol & SSL_PROTOCOL_SSLV3 ? "SSLv3, " : ""), + #endif +@@ -604,7 +611,8 @@ static apr_status_t ssl_init_ctx_protocol(server_rec *s, + #endif + #endif + NULL); +- cp[strlen(cp)-2] = NUL; ++ cp[strlen(cp)-2] = NUL; ++ } + + ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, s, + "Creating new SSL context (protocols: %s)", cp); +@@ -705,13 +713,15 @@ static apr_status_t ssl_init_ctx_protocol(server_rec *s, + prot = SSL3_VERSION; + #endif + } else { +- SSL_CTX_free(ctx); +- mctx->ssl_ctx = NULL; +- ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(03378) +- "No SSL protocols available [hint: SSLProtocol]"); +- return ssl_die(s); ++ if (protocol_set) { ++ SSL_CTX_free(ctx); ++ mctx->ssl_ctx = NULL; ++ ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(03378) ++ "No SSL protocols available [hint: SSLProtocol]"); ++ return ssl_die(s); ++ } + } +- SSL_CTX_set_max_proto_version(ctx, prot); ++ if (protocol != SSL_PROTOCOL_NONE) SSL_CTX_set_max_proto_version(ctx, prot); + + /* Next we scan for the minimal protocol version we should provide, + * but we do not allow holes between max and min */ +@@ -731,7 +741,7 @@ static apr_status_t ssl_init_ctx_protocol(server_rec *s, + prot = SSL3_VERSION; + } + #endif +- SSL_CTX_set_min_proto_version(ctx, prot); ++ if (protocol != SSL_PROTOCOL_NONE) SSL_CTX_set_min_proto_version(ctx, prot); + #endif /* if OPENSSL_VERSION_NUMBER < 0x10100000L */ + + #ifdef SSL_OP_CIPHER_SERVER_PREFERENCE diff --git a/httpd-2.4.48-export.patch b/httpd-2.4.48-export.patch new file mode 100644 index 0000000000000000000000000000000000000000..439f7689adb9d8fb62b621cde7abfff2aa7118a9 --- /dev/null +++ b/httpd-2.4.48-export.patch @@ -0,0 +1,63 @@ + +Reduce size of httpd binary by telling linker to export all symbols +from libmain.a, rather than bloating the symbol table with ap_hack_* +to do so indirectly. + +Upstream: https://svn.apache.org/r1861685 (as new default-off configure option) + +diff --git a/Makefile.in b/Makefile.in +index 40c7076..ac98e5f 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -4,8 +4,15 @@ CLEAN_SUBDIRS = test + + PROGRAM_NAME = $(progname) + PROGRAM_SOURCES = modules.c +-PROGRAM_LDADD = buildmark.o $(HTTPD_LDFLAGS) $(PROGRAM_DEPENDENCIES) $(HTTPD_LIBS) $(EXTRA_LIBS) $(AP_LIBS) $(LIBS) ++PROGRAM_LDADD = buildmark.o $(HTTPD_LDFLAGS) \ ++ $(PROGRAM_LDDEPS) \ ++ $(HTTPD_LIBS) $(EXTRA_LIBS) $(AP_LIBS) $(LIBS) + PROGRAM_PRELINK = $(COMPILE) -c $(top_srcdir)/server/buildmark.c ++PROGRAM_LDDEPS = \ ++ $(BUILTIN_LIBS) \ ++ $(MPM_LIB) \ ++ -Wl,--whole-archive,server/.libs/libmain.a,--no-whole-archive \ ++ os/$(OS_DIR)/libos.la + PROGRAM_DEPENDENCIES = \ + server/libmain.la \ + $(BUILTIN_LIBS) \ +diff --git a/server/Makefile.in b/server/Makefile.in +index 8111877..f00bb3f 100644 +--- a/server/Makefile.in ++++ b/server/Makefile.in +@@ -12,7 +12,7 @@ LTLIBRARY_SOURCES = \ + connection.c listen.c util_mutex.c \ + mpm_common.c mpm_unix.c mpm_fdqueue.c \ + util_charset.c util_cookies.c util_debug.c util_xml.c \ +- util_filter.c util_pcre.c util_regex.c exports.c \ ++ util_filter.c util_pcre.c util_regex.c \ + scoreboard.c error_bucket.c protocol.c core.c request.c ssl.c provider.c \ + eoc_bucket.c eor_bucket.c core_filters.c \ + util_expr_parse.c util_expr_scan.c util_expr_eval.c +diff --git a/server/main.c b/server/main.c +index 62e06df..17c09ee 100644 +--- a/server/main.c ++++ b/server/main.c +@@ -835,17 +835,3 @@ int main(int argc, const char * const argv[]) + return !OK; + } + +-#ifdef AP_USING_AUTOCONF +-/* This ugly little hack pulls any function referenced in exports.c into +- * the web server. exports.c is generated during the build, and it +- * has all of the APR functions specified by the apr/apr.exports and +- * apr-util/aprutil.exports files. +- */ +-const void *ap_suck_in_APR(void); +-const void *ap_suck_in_APR(void) +-{ +- extern const void *ap_ugly_hack; +- +- return ap_ugly_hack; +-} +-#endif diff --git a/httpd-2.4.48-full-release.patch b/httpd-2.4.48-full-release.patch new file mode 100644 index 0000000000000000000000000000000000000000..6e31cc7847e12dc0fa9c463782c09cece2827c67 --- /dev/null +++ b/httpd-2.4.48-full-release.patch @@ -0,0 +1,46 @@ +diff --git a/server/core.c b/server/core.c +index c36ff26..621c82a 100644 +--- a/server/core.c ++++ b/server/core.c +@@ -3569,6 +3569,7 @@ enum server_token_type { + SrvTk_MINIMAL, /* eg: Apache/2.0.41 */ + SrvTk_OS, /* eg: Apache/2.0.41 (UNIX) */ + SrvTk_FULL, /* eg: Apache/2.0.41 (UNIX) PHP/4.2.2 FooBar/1.2b */ ++ SrvTk_FULL_RELEASE, /* eg: Apache/2.0.41 (UNIX) (Release 32.el7) PHP/4.2.2 FooBar/1.2b */ + SrvTk_PRODUCT_ONLY /* eg: Apache */ + }; + static enum server_token_type ap_server_tokens = SrvTk_FULL; +@@ -3645,7 +3646,10 @@ static void set_banner(apr_pool_t *pconf) + else if (ap_server_tokens == SrvTk_MAJOR) { + ap_add_version_component(pconf, AP_SERVER_BASEPRODUCT "/" AP_SERVER_MAJORVERSION); + } +- else { ++ else if (ap_server_tokens == SrvTk_FULL_RELEASE) { ++ ap_add_version_component(pconf, AP_SERVER_BASEVERSION " (" PLATFORM ") (Release @RELEASE@)"); ++ } ++ else { + ap_add_version_component(pconf, AP_SERVER_BASEVERSION " (" PLATFORM ")"); + } + +@@ -3653,7 +3657,7 @@ static void set_banner(apr_pool_t *pconf) + * Lock the server_banner string if we're not displaying + * the full set of tokens + */ +- if (ap_server_tokens != SrvTk_FULL) { ++ if (ap_server_tokens != SrvTk_FULL && ap_server_tokens != SrvTk_FULL_RELEASE) { + banner_locked++; + } + server_description = AP_SERVER_BASEVERSION " (" PLATFORM ")"; +@@ -3686,8 +3690,11 @@ static const char *set_serv_tokens(cmd_parms *cmd, void *dummy, + else if (!ap_cstr_casecmp(arg, "Full")) { + ap_server_tokens = SrvTk_FULL; + } ++ else if (!strcasecmp(arg, "Full-Release")) { ++ ap_server_tokens = SrvTk_FULL_RELEASE; ++ } + else { +- return "ServerTokens takes 1 argument: 'Prod(uctOnly)', 'Major', 'Minor', 'Min(imal)', 'OS', or 'Full'"; ++ return "ServerTokens takes 1 argument: 'Prod(uctOnly)', 'Major', 'Minor', 'Min(imal)', 'OS', 'Full' or 'Full-Release'"; + } + + return NULL; diff --git a/httpd-2.4.48-proxy-ws-idle-timeout.patch b/httpd-2.4.48-proxy-ws-idle-timeout.patch new file mode 100644 index 0000000000000000000000000000000000000000..d04dc681e77bbda0d9d3c78993dfa580c652275f --- /dev/null +++ b/httpd-2.4.48-proxy-ws-idle-timeout.patch @@ -0,0 +1,109 @@ +diff --git a/docs/manual/mod/mod_proxy_wstunnel.html.en b/docs/manual/mod/mod_proxy_wstunnel.html.en +index 9f2c120..61ff7de 100644 +--- a/docs/manual/mod/mod_proxy_wstunnel.html.en ++++ b/docs/manual/mod/mod_proxy_wstunnel.html.en +@@ -83,6 +83,7 @@ in the response Upgrade

+
Support Apache!

Directives

+ +

Bugfix checklist

See also

+
++ ++

ProxyWebsocketIdleTimeout Directive

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

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

++ ++
++ + +
+

Available Languages:  en  | +diff --git a/modules/proxy/mod_proxy_wstunnel.c b/modules/proxy/mod_proxy_wstunnel.c +index bcbba42..c29ded1 100644 +--- a/modules/proxy/mod_proxy_wstunnel.c ++++ b/modules/proxy/mod_proxy_wstunnel.c +@@ -22,6 +22,7 @@ module AP_MODULE_DECLARE_DATA proxy_wstunnel_module; + typedef struct { + unsigned int fallback_to_proxy_http :1, + fallback_to_proxy_http_set :1; ++ apr_time_t idle_timeout; + } proxyws_dir_conf; + + static int can_fallback_to_proxy_http; +@@ -152,6 +153,8 @@ static int proxy_wstunnel_request(apr_pool_t *p, request_rec *r, + conn_rec *c = r->connection; + apr_socket_t *sock = conn->sock; + conn_rec *backconn = conn->connection; ++ proxyws_dir_conf *dconf = ap_get_module_config(r->per_dir_config, ++ &proxy_wstunnel_module); + char *buf; + apr_bucket_brigade *header_brigade; + apr_bucket *e; +@@ -229,10 +232,13 @@ static int proxy_wstunnel_request(apr_pool_t *p, request_rec *r, + c->keepalive = AP_CONN_CLOSE; + + do { /* Loop until done (one side closes the connection, or an error) */ +- rv = apr_pollset_poll(pollset, -1, &pollcnt, &signalled); ++ rv = apr_pollset_poll(pollset, dconf->idle_timeout, &pollcnt, &signalled); + if (rv != APR_SUCCESS) { + if (APR_STATUS_IS_EINTR(rv)) { + continue; ++ } else if(APR_STATUS_IS_TIMEUP(rv)){ ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, "RH: the connection has timed out"); ++ return HTTP_REQUEST_TIME_OUT; + } + ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(02444) "error apr_poll()"); + return HTTP_INTERNAL_SERVER_ERROR; +@@ -418,11 +424,26 @@ cleanup: + return status; + } + ++static const char * proxyws_set_idle(cmd_parms *cmd, void *conf, const char *val) ++{ ++ proxyws_dir_conf *dconf = conf; ++ if (ap_timeout_parameter_parse(val, &(dconf->idle_timeout), "s") != APR_SUCCESS) ++ return "ProxyWebsocketIdleTimeout timeout has wrong format"; ++ ++ if (dconf->idle_timeout < 0) ++ return "ProxyWebsocketIdleTimeout timeout has to be a non-negative number"; ++ ++ if (!dconf->idle_timeout) dconf->idle_timeout = -1; /* loop indefinitely */ ++ ++ return NULL; ++} ++ + static void *create_proxyws_dir_config(apr_pool_t *p, char *dummy) + { + proxyws_dir_conf *new = + (proxyws_dir_conf *) apr_pcalloc(p, sizeof(proxyws_dir_conf)); + ++ new->idle_timeout = -1; /* no timeout */ + new->fallback_to_proxy_http = 1; + + return (void *) new; +@@ -465,7 +486,8 @@ static const command_rec ws_proxy_cmds[] = + proxyws_fallback_to_proxy_http, NULL, RSRC_CONF|ACCESS_CONF, + "whether to let mod_proxy_http handle the upgrade and tunneling, " + "On by default"), +- ++ AP_INIT_TAKE1("ProxyWebsocketIdleTimeout", proxyws_set_idle, NULL, RSRC_CONF|ACCESS_CONF, ++ "timeout for activity in either direction, unlimited by default."), + {NULL} + }; + diff --git a/httpd-2.4.57-r1912477+.patch b/httpd-2.4.57-r1912477+.patch new file mode 100644 index 0000000000000000000000000000000000000000..6458df8148ab68d715f5e956a4ba26765206d480 --- /dev/null +++ b/httpd-2.4.57-r1912477+.patch @@ -0,0 +1,381 @@ +# ./pullrev.sh 1912477 1912571 1912718 1913654 1914438 +http://svn.apache.org/viewvc?view=revision&revision=1912477 +http://svn.apache.org/viewvc?view=revision&revision=1912571 +http://svn.apache.org/viewvc?view=revision&revision=1912718 +http://svn.apache.org/viewvc?view=revision&revision=1913654 +http://svn.apache.org/viewvc?view=revision&revision=1914438 + +--- httpd-2.4.58/modules/dav/fs/config6.m4.r1912477+ ++++ httpd-2.4.58/modules/dav/fs/config6.m4 +@@ -20,4 +20,10 @@ + + APACHE_MODULE(dav_fs, DAV provider for the filesystem. --enable-dav also enables mod_dav_fs., $dav_fs_objects, , $dav_fs_enable,,dav) + ++if test "x$enable_dav_fs" = "xshared"; then ++ # The only symbol which needs to be exported is the module ++ # structure, so ask libtool to hide everything else: ++ APR_ADDTO(MOD_DAV_FS_LDADD, [-export-symbols-regex dav_fs_module]) ++fi ++ + APACHE_MODPATH_FINISH +--- httpd-2.4.58/modules/dav/fs/dbm.c.r1912477+ ++++ httpd-2.4.58/modules/dav/fs/dbm.c +@@ -47,6 +47,10 @@ + #include "http_log.h" + #include "http_main.h" /* for ap_server_conf */ + ++#ifndef DEFAULT_PROPDB_DBM_TYPE ++#define DEFAULT_PROPDB_DBM_TYPE "default" ++#endif ++ + APLOG_USE_MODULE(dav_fs); + + struct dav_db { +@@ -100,7 +104,7 @@ + /* There might not be a if we had problems creating it. */ + if (db == NULL) { + errcode = 1; +- errstr = "Could not open property database."; ++ errstr = "Could not open database."; + if (APR_STATUS_IS_EDSOOPEN(status)) + ap_log_error(APLOG_MARK, APLOG_CRIT, status, ap_server_conf, APLOGNO(00576) + "The DBM driver could not be loaded"); +@@ -129,10 +133,10 @@ + /* dav_dbm_open_direct: Opens a *dbm database specified by path. + * ro = boolean read-only flag. + */ +-dav_error * dav_dbm_open_direct(apr_pool_t *p, const char *pathname, int ro, +- dav_db **pdb) ++dav_error * dav_dbm_open_direct(apr_pool_t *p, const char *pathname, ++ const char *dbmtype, int ro, dav_db **pdb) + { +-#if APU_MAJOR_VERSION > 1 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 7) ++#if APR_MAJOR_VERSION > 1 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 7) + const apr_dbm_driver_t *driver; + const apu_err_t *err; + #endif +@@ -141,13 +145,13 @@ + + *pdb = NULL; + +-#if APU_MAJOR_VERSION > 1 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 7) +- if ((status = apr_dbm_get_driver(&driver, NULL, &err, p)) != APR_SUCCESS) { ++#if APR_MAJOR_VERSION > 1 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION >= 7) ++ if ((status = apr_dbm_get_driver(&driver, dbmtype, &err, p)) != APR_SUCCESS) { + ap_log_error(APLOG_MARK, APLOG_ERR, status, ap_server_conf, APLOGNO(10289) +- "mod_dav_fs: The DBM library '%s' could not be loaded: %s", +- err->reason, err->msg); ++ "mod_dav_fs: The DBM library '%s' for '%s' could not be loaded: %s", ++ err->reason, dbmtype, err->msg); + return dav_new_error(p, HTTP_INTERNAL_SERVER_ERROR, 1, status, +- "Could not load library for property database."); ++ "Could not load library for database."); + } + if ((status = apr_dbm_open2(&file, driver, pathname, + ro ? APR_DBM_READONLY : APR_DBM_RWCREATE, +@@ -156,7 +160,7 @@ + return dav_fs_dbm_error(NULL, p, status); + } + #else +- if ((status = apr_dbm_open(&file, pathname, ++ if ((status = apr_dbm_open_ex(&file, dbmtype, pathname, + ro ? APR_DBM_READONLY : APR_DBM_RWCREATE, + APR_OS_DEFAULT, p)) + != APR_SUCCESS +@@ -206,7 +210,7 @@ + + /* ### do we need to deal with the umask? */ + +- return dav_dbm_open_direct(p, pathname, ro, pdb); ++ return dav_dbm_open_direct(p, pathname, DEFAULT_PROPDB_DBM_TYPE, ro, pdb); + } + + void dav_dbm_close(dav_db *db) +--- httpd-2.4.58/modules/dav/fs/lock.c.r1912477+ ++++ httpd-2.4.58/modules/dav/fs/lock.c +@@ -181,8 +181,7 @@ + { + request_rec *r; /* for accessing the uuid state */ + apr_pool_t *pool; /* a pool to use */ +- const char *lockdb_path; /* where is the lock database? */ +- ++ const dav_fs_server_conf *conf; /* lock database config & metadata */ + int opened; /* we opened the database */ + dav_db *db; /* if non-NULL, the lock database */ + }; +@@ -292,6 +291,19 @@ + return dav_compare_locktoken(lt1, lt2); + } + ++static apr_status_t dav_fs_lockdb_cleanup(void *data) ++{ ++ dav_lockdb *lockdb = data; ++ ++ apr_global_mutex_unlock(lockdb->info->conf->lockdb_mutex); ++ ++ if (lockdb->info->db) { ++ dav_dbm_close(lockdb->info->db); ++ } ++ ++ return APR_SUCCESS; ++} ++ + /* + ** dav_fs_really_open_lockdb: + ** +@@ -300,15 +312,27 @@ + static dav_error * dav_fs_really_open_lockdb(dav_lockdb *lockdb) + { + dav_error *err; ++ apr_status_t rv; + + if (lockdb->info->opened) + return NULL; + ++ rv = apr_global_mutex_lock(lockdb->info->conf->lockdb_mutex); ++ if (rv) { ++ return dav_new_error(lockdb->info->pool, ++ HTTP_INTERNAL_SERVER_ERROR, ++ DAV_ERR_LOCK_OPENDB, rv, ++ "Could not lock mutex for lock database."); ++ } ++ + err = dav_dbm_open_direct(lockdb->info->pool, +- lockdb->info->lockdb_path, ++ lockdb->info->conf->lockdb_path, ++ lockdb->info->conf->lockdb_type, + lockdb->ro, + &lockdb->info->db); + if (err != NULL) { ++ apr_global_mutex_unlock(lockdb->info->conf->lockdb_mutex); ++ + return dav_push_error(lockdb->info->pool, + HTTP_INTERNAL_SERVER_ERROR, + DAV_ERR_LOCK_OPENDB, +@@ -316,6 +340,10 @@ + err); + } + ++ apr_pool_cleanup_register(lockdb->info->pool, lockdb, ++ dav_fs_lockdb_cleanup, ++ dav_fs_lockdb_cleanup); ++ + /* all right. it is opened now. */ + lockdb->info->opened = 1; + +@@ -341,9 +369,9 @@ + comb->pub.info = &comb->priv; + comb->priv.r = r; + comb->priv.pool = r->pool; +- +- comb->priv.lockdb_path = dav_get_lockdb_path(r); +- if (comb->priv.lockdb_path == NULL) { ++ comb->priv.conf = dav_fs_get_server_conf(r); ++ ++ if (comb->priv.conf == NULL || comb->priv.conf->lockdb_path == NULL) { + return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, + DAV_ERR_LOCK_NO_DB, 0, + "A lock database was not specified with the " +@@ -369,8 +397,8 @@ + */ + static void dav_fs_close_lockdb(dav_lockdb *lockdb) + { +- if (lockdb->info->db != NULL) +- dav_dbm_close(lockdb->info->db); ++ apr_pool_cleanup_run(lockdb->info->pool, lockdb, ++ dav_fs_lockdb_cleanup); + } + + /* +--- httpd-2.4.58/modules/dav/fs/mod_dav_fs.c.r1912477+ ++++ httpd-2.4.58/modules/dav/fs/mod_dav_fs.c +@@ -14,31 +14,35 @@ + * limitations under the License. + */ + ++#if !defined(_MSC_VER) && !defined(NETWARE) ++#include "ap_config_auto.h" ++#endif ++ + #include "httpd.h" + #include "http_config.h" ++#include "http_core.h" ++#include "http_log.h" + #include "apr_strings.h" + + #include "mod_dav.h" + #include "repos.h" + +-/* per-server configuration */ +-typedef struct { +- const char *lockdb_path; +- +-} dav_fs_server_conf; +- + extern module AP_MODULE_DECLARE_DATA dav_fs_module; + + #ifndef DEFAULT_DAV_LOCKDB + #define DEFAULT_DAV_LOCKDB "davlockdb" + #endif ++#ifndef DEFAULT_DAV_LOCKDB_TYPE ++#define DEFAULT_DAV_LOCKDB_TYPE "default" ++#endif + +-const char *dav_get_lockdb_path(const request_rec *r) +-{ +- dav_fs_server_conf *conf; ++static const char dav_fs_mutexid[] = "dav_fs-lockdb"; + +- conf = ap_get_module_config(r->server->module_config, &dav_fs_module); +- return conf->lockdb_path; ++static apr_global_mutex_t *dav_fs_lockdb_mutex; ++ ++const dav_fs_server_conf *dav_fs_get_server_conf(const request_rec *r) ++{ ++ return ap_get_module_config(r->server->module_config, &dav_fs_module); + } + + static void *dav_fs_create_server_config(apr_pool_t *p, server_rec *s) +@@ -57,15 +61,50 @@ + + newconf->lockdb_path = + child->lockdb_path ? child->lockdb_path : parent->lockdb_path; ++ newconf->lockdb_type = ++ child->lockdb_type ? child->lockdb_type : parent->lockdb_type; + + return newconf; + } + ++static int dav_fs_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp) ++{ ++ if (ap_mutex_register(pconf, dav_fs_mutexid, NULL, APR_LOCK_DEFAULT, 0)) ++ return !OK; ++ return OK; ++} ++ ++static void dav_fs_child_init(apr_pool_t *p, server_rec *s) ++{ ++ apr_status_t rv; ++ ++ rv = apr_global_mutex_child_init(&dav_fs_lockdb_mutex, ++ apr_global_mutex_lockfile(dav_fs_lockdb_mutex), ++ p); ++ if (rv) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, ++ APLOGNO(10488) "child init failed for mutex"); ++ } ++} ++ + static apr_status_t dav_fs_post_config(apr_pool_t *p, apr_pool_t *plog, + apr_pool_t *ptemp, server_rec *base_server) + { + server_rec *s; ++ apr_status_t rv; + ++ /* Ignore first pass through the config. */ ++ if (ap_state_query(AP_SQ_MAIN_STATE) == AP_SQ_MS_CREATE_PRE_CONFIG) ++ return OK; ++ ++ rv = ap_global_mutex_create(&dav_fs_lockdb_mutex, NULL, dav_fs_mutexid, NULL, ++ base_server, p, 0); ++ if (rv) { ++ ap_log_error(APLOG_MARK, APLOG_ERR, rv, base_server, ++ APLOGNO(10489) "could not create lock mutex"); ++ return !OK; ++ } ++ + for (s = base_server; s; s = s->next) { + dav_fs_server_conf *conf; + +@@ -74,6 +113,13 @@ + if (!conf->lockdb_path) { + conf->lockdb_path = ap_state_dir_relative(p, DEFAULT_DAV_LOCKDB); + } ++ if (!conf->lockdb_type) { ++ conf->lockdb_type = DEFAULT_DAV_LOCKDB_TYPE; ++ } ++ ++ /* Mutex is common across all vhosts, but could have one per ++ * vhost if required. */ ++ conf->lockdb_mutex = dav_fs_lockdb_mutex; + } + + return OK; +@@ -98,19 +144,36 @@ + return NULL; + } + ++/* ++ * Command handler for the DAVLockDBType directive, which is TAKE1 ++ */ ++static const char *dav_fs_cmd_davlockdbtype(cmd_parms *cmd, void *config, ++ const char *arg1) ++{ ++ dav_fs_server_conf *conf = ap_get_module_config(cmd->server->module_config, ++ &dav_fs_module); ++ conf->lockdb_type = arg1; ++ ++ return NULL; ++} ++ + static const command_rec dav_fs_cmds[] = + { + /* per server */ + AP_INIT_TAKE1("DAVLockDB", dav_fs_cmd_davlockdb, NULL, RSRC_CONF, + "specify a lock database"), ++ AP_INIT_TAKE1("DAVLockDBType", dav_fs_cmd_davlockdbtype, NULL, RSRC_CONF, ++ "specify a lock database DBM type"), + + { NULL } + }; + + static void register_hooks(apr_pool_t *p) + { ++ ap_hook_pre_config(dav_fs_pre_config, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_post_config(dav_fs_post_config, NULL, NULL, APR_HOOK_MIDDLE); +- ++ ap_hook_child_init(dav_fs_child_init, NULL, NULL, APR_HOOK_MIDDLE); ++ + dav_hook_gather_propsets(dav_fs_gather_propsets, NULL, NULL, + APR_HOOK_MIDDLE); + dav_hook_find_liveprop(dav_fs_find_liveprop, NULL, NULL, APR_HOOK_MIDDLE); +--- httpd-2.4.58/modules/dav/fs/repos.h.r1912477+ ++++ httpd-2.4.58/modules/dav/fs/repos.h +@@ -25,6 +25,8 @@ + #ifndef _DAV_FS_REPOS_H_ + #define _DAV_FS_REPOS_H_ + ++#include "util_mutex.h" ++ + /* the subdirectory to hold all DAV-related information for a directory */ + #define DAV_FS_STATE_DIR ".DAV" + #define DAV_FS_STATE_FILE_FOR_DIR ".state_for_dir" +@@ -53,8 +55,8 @@ + /* DBM functions used by the repository and locking providers */ + extern const dav_hooks_db dav_hooks_db_dbm; + +-dav_error * dav_dbm_open_direct(apr_pool_t *p, const char *pathname, int ro, +- dav_db **pdb); ++dav_error * dav_dbm_open_direct(apr_pool_t *p, const char *pathname, ++ const char *dbmtype, int ro, dav_db **pdb); + void dav_dbm_get_statefiles(apr_pool_t *p, const char *fname, + const char **state1, const char **state2); + dav_error * dav_dbm_delete(dav_db *db, apr_datum_t key); +@@ -64,8 +66,15 @@ + int dav_dbm_exists(dav_db *db, apr_datum_t key); + void dav_dbm_close(dav_db *db); + +-/* where is the lock database located? */ +-const char *dav_get_lockdb_path(const request_rec *r); ++/* Per-server configuration. */ ++typedef struct { ++ const char *lockdb_path; ++ const char *lockdb_type; ++ apr_global_mutex_t *lockdb_mutex; ++} dav_fs_server_conf; ++ ++/* Returns server configuration for the request. */ ++const dav_fs_server_conf *dav_fs_get_server_conf(const request_rec *r); + + const dav_hooks_locks *dav_fs_get_lock_hooks(request_rec *r); + const dav_hooks_propdb *dav_fs_get_propdb_hooks(request_rec *r); diff --git a/httpd-2.4.57-selinux.patch b/httpd-2.4.57-selinux.patch new file mode 100644 index 0000000000000000000000000000000000000000..20babde25ad6a40d8dc8007e8de760bf455b99d7 --- /dev/null +++ b/httpd-2.4.57-selinux.patch @@ -0,0 +1,60 @@ +diff --git a/configure.in b/configure.in +index 3932407..00e2369 100644 +--- a/configure.in ++++ b/configure.in +@@ -531,6 +531,11 @@ gettid + dnl confirm that a void pointer is large enough to store a long integer + APACHE_CHECK_VOID_PTR_LEN + ++AC_CHECK_LIB(selinux, is_selinux_enabled, [ ++ AC_DEFINE(HAVE_SELINUX, 1, [Defined if SELinux is supported]) ++ APR_ADDTO(HTTPD_LIBS, [-lselinux]) ++]) ++ + 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, +diff --git a/server/core.c b/server/core.c +index 8970a50..ff1024d 100644 +--- a/server/core.c ++++ b/server/core.c +@@ -65,6 +65,10 @@ + #include + #endif + ++#ifdef HAVE_SELINUX ++#include ++#endif ++ + /* LimitRequestBody handling */ + #define AP_LIMIT_REQ_BODY_UNSET ((apr_off_t) -1) + #define AP_DEFAULT_LIMIT_REQ_BODY ((apr_off_t) 1<<30) /* 1GB */ +@@ -5170,6 +5174,28 @@ static int core_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *pte + } + #endif + ++#ifdef HAVE_SELINUX ++ { ++ static int already_warned = 0; ++ int is_enabled = is_selinux_enabled() > 0; ++ ++ if (is_enabled && !already_warned) { ++ security_context_t con; ++ ++ if (getcon(&con) == 0) { ++ ++ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, ++ "SELinux policy enabled; " ++ "httpd running as context %s", con); ++ ++ already_warned = 1; ++ ++ freecon(con); ++ } ++ } ++ } ++#endif ++ + return OK; + } + diff --git a/httpd-2.4.59-deplibs.patch b/httpd-2.4.59-deplibs.patch new file mode 100644 index 0000000000000000000000000000000000000000..fc730ab59c63560656c3c5e84800a5590ee23e2f --- /dev/null +++ b/httpd-2.4.59-deplibs.patch @@ -0,0 +1,16 @@ +diff --git a/configure.in b/configure.in +index 7194de5..00e2369 100644 +--- a/configure.in ++++ b/configure.in +@@ -843,9 +843,9 @@ APACHE_SUBST(INSTALL_SUEXEC) + + dnl APR should go after the other libs, so the right symbols can be picked up + if test x${apu_found} != xobsolete; then +- AP_LIBS="$AP_LIBS `$apu_config --avoid-ldap --link-libtool --libs`" ++ AP_LIBS="$AP_LIBS `$apu_config --avoid-ldap --link-libtool`" + fi +-AP_LIBS="$AP_LIBS `$apr_config --link-libtool --libs`" ++AP_LIBS="$AP_LIBS `$apr_config --link-libtool`" + APACHE_SUBST(AP_LIBS) + APACHE_SUBST(AP_BUILD_SRCLIB_DIRS) + APACHE_SUBST(AP_CLEAN_SRCLIB_DIRS) diff --git a/httpd-2.4.62-engine-fallback.patch b/httpd-2.4.62-engine-fallback.patch new file mode 100644 index 0000000000000000000000000000000000000000..d10d2c5f35178ef05ce6c7ec483a49c91c2bd2df --- /dev/null +++ b/httpd-2.4.62-engine-fallback.patch @@ -0,0 +1,64 @@ +Index: modules/ssl/ssl_engine_pphrase.c +=================================================================== +--- modules/ssl/ssl_engine_pphrase.c (revision 1920590) ++++ modules/ssl/ssl_engine_pphrase.c (working copy) +@@ -806,6 +806,9 @@ + return APR_SUCCESS; + } + ++/* Tries to load the key and optionally certificate via the ENGINE ++ * API. Returns APR_ENOTIMPL if the keypair could not be loaded via an ++ * ENGINE implementation. */ + static apr_status_t modssl_load_keypair_engine(server_rec *s, apr_pool_t *pconf, + apr_pool_t *ptemp, + const char *vhostid, +@@ -831,7 +834,7 @@ + ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10131) + "Init: Unrecognized private key identifier `%s'", + keyid); +- return ssl_die(s); ++ return APR_ENOTIMPL; + } + + scheme = apr_pstrmemdup(ptemp, keyid, c - keyid); +@@ -839,8 +842,8 @@ + 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); ++ ssl_log_ssl_error(SSLLOG_MARK, APLOG_NOTICE, s); ++ return APR_ENOTIMPL; + } + + if (!ENGINE_init(e)) { +@@ -996,15 +999,21 @@ + X509 **pubkey, EVP_PKEY **privkey) + { + #if MODSSL_HAVE_ENGINE_API +- SSLModConfigRec *mc = myModConfig(s); ++ apr_status_t rv; + +- /* For OpenSSL 3.x, use the STORE-based API if either ENGINE +- * support was not present compile-time, or if it's built but +- * SSLCryptoDevice is not configured. */ +- if (mc->szCryptoDevice) +- return modssl_load_keypair_engine(s, pconf, ptemp, +- vhostid, certid, keyid, +- pubkey, privkey); ++ rv = modssl_load_keypair_engine(s, pconf, ptemp, ++ vhostid, certid, keyid, ++ pubkey, privkey); ++ if (rv == APR_SUCCESS) { ++ return rv; ++ } ++ /* If STORE support is not present, all errors are fatal here; if ++ * STORE is present and the ENGINE could not be loaded, ignore the ++ * error and fall through to try loading via the STORE API. */ ++ else if (!MODSSL_HAVE_OPENSSL_STORE || rv != APR_ENOTIMPL) { ++ return ssl_die(s); ++ } ++ + #endif + #if MODSSL_HAVE_OPENSSL_STORE + return modssl_load_keypair_store(s, ptemp, vhostid, certid, keyid, diff --git a/httpd-2.4.62-freebind.patch b/httpd-2.4.62-freebind.patch new file mode 100644 index 0000000000000000000000000000000000000000..93a0143966c0db746c111bb59e48d67aa1f9e32e --- /dev/null +++ b/httpd-2.4.62-freebind.patch @@ -0,0 +1,124 @@ +diff --git a/docs/manual/mod/mpm_common.html.en b/docs/manual/mod/mpm_common.html.en +index 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) +

  • EnableExceptionHook
  • +
  • GracefulShutdownTimeout
  • +
  • Listen
  • ++
  • ListenFree
  • +
  • ListenBackLog
  • +
  • ListenCoresBucketsRatio
  • +
  • MaxConnectionsPerChild
  • +@@ -244,6 +245,31 @@ discussion of the Address already in use error message, + including other causes. + +
    ++ ++
    top
    ++

    ListenFree Directive

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

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

    ++
    ++ ++ +
    top
    +

    ListenBackLog Directive

    + +diff --git a/include/ap_listen.h b/include/ap_listen.h +index d5ed968..be1a60c 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 + AP_DECLARE_NONSTD(const char *) ap_set_listencbratio(cmd_parms *cmd, void *dummy, const char *arg); + AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, + int argc, char *const argv[]); ++AP_DECLARE_NONSTD(const char *) ap_set_freelistener(cmd_parms *cmd, void *dummy, ++ int argc, char *const argv[]); ++ + AP_DECLARE_NONSTD(const char *) ap_set_send_buffer_size(cmd_parms *cmd, void *dummy, + const char *arg); + AP_DECLARE_NONSTD(const char *) ap_set_receive_buffer_size(cmd_parms *cmd, +@@ -160,6 +163,8 @@ AP_INIT_TAKE1("ListenCoresBucketsRatio", ap_set_listencbratio, NULL, RSRC_CONF, + "Ratio between the number of CPU cores (online) and the number of listeners buckets"), \ + AP_INIT_TAKE_ARGV("Listen", ap_set_listener, NULL, RSRC_CONF, \ + "A port number or a numeric IP address and a port number, and an optional protocol"), \ ++AP_INIT_TAKE_ARGV("ListenFree", ap_set_freelistener, NULL, RSRC_CONF, \ ++ "A port number or a numeric IP address and a port number, and an optional protocol"), \ + AP_INIT_TAKE1("SendBufferSize", ap_set_send_buffer_size, NULL, RSRC_CONF, \ + "Send buffer size in bytes"), \ + AP_INIT_TAKE1("ReceiveBufferSize", ap_set_receive_buffer_size, NULL, \ +diff --git a/server/listen.c b/server/listen.c +index 2a4e87a..280bbe7 100644 +--- a/server/listen.c ++++ b/server/listen.c +@@ -60,6 +60,7 @@ static int ap_listenbacklog; + static int ap_listencbratio; + static int send_buffer_size; + static int receive_buffer_size; ++static int ap_listenfreebind; + #ifdef HAVE_SYSTEMD + static int use_systemd = -1; + #endif +@@ -159,6 +160,21 @@ static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server, int do_bind_ + } + #endif + ++ ++#if defined(APR_SO_FREEBIND) ++ if (ap_listenfreebind) { ++ if (apr_socket_opt_set(s, APR_SO_FREEBIND, one) < 0) { ++ stat = apr_get_netos_error(); ++ ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p, APLOGNO(02182) ++ "make_sock: apr_socket_opt_set: " ++ "error setting APR_SO_FREEBIND"); ++ apr_socket_close(s); ++ return stat; ++ } ++ } ++#endif ++ ++ + if (do_bind_listen) { + #if APR_HAVE_IPV6 + if (server->bind_addr->family == APR_INET6) { +@@ -971,6 +987,7 @@ AP_DECLARE(void) ap_listen_pre_config(void) + } + } + ++ + AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, + int argc, char *const argv[]) + { +@@ -1044,6 +1061,14 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, + scope_id, NULL, cmd->temp_pool); + } + ++AP_DECLARE_NONSTD(const char *) ap_set_freelistener(cmd_parms *cmd, void *dummy, ++ int argc, ++ char *const argv[]) ++{ ++ ap_listenfreebind = 1; ++ return ap_set_listener(cmd, dummy, argc, argv); ++} ++ + AP_DECLARE_NONSTD(const char *) ap_set_listenbacklog(cmd_parms *cmd, + void *dummy, + const char *arg) diff --git a/httpd-2.4.62-r1919325.patch b/httpd-2.4.62-r1919325.patch new file mode 100644 index 0000000000000000000000000000000000000000..1b344e547b8f6eabb2d75d804f83c692fc63dc99 --- /dev/null +++ b/httpd-2.4.62-r1919325.patch @@ -0,0 +1,242 @@ +From a0a68b99d131741c1867cff321424892838fc4b3 Mon Sep 17 00:00:00 2001 +From: Yann Ylavic +Date: Sat, 27 Jul 2024 13:35:53 +0000 +Subject: [PATCH] mod_rewrite: Better question mark tracking to avoid + UnsafeAllow3F. PR 69197. + +Track in do_expand() whether a '?' in the uri-path comes from a literal in +the substitution string or from an expansion (variable, lookup, ...). +In the former case it's safe to assume that it's the query-string separator +but for the other case it's not (could be a decoded %3f from r->uri). + +This allows to avoid [UnsafeAllow3F] for most cases. + + +Merges r1919325 from trunk +Reviewed by: ylavic, covener, jorton +Github: closes #462 + + +git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919545 13f79535-47bb-0310-9956-ffa450edef68 +--- + modules/mappers/mod_rewrite.c | 107 ++++++++++++++++++++++++++++------ + 1 file changed, 89 insertions(+), 18 deletions(-) + +diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c +index f1c22e3235b..53fb1e91ffb 100644 +--- a/modules/mappers/mod_rewrite.c ++++ b/modules/mappers/mod_rewrite.c +@@ -2376,9 +2376,16 @@ static APR_INLINE char *find_char_in_curlies(char *s, int c) + * of an earlier expansion to include expansion specifiers that + * are interpreted by a later expansion, producing results that + * were not intended by the administrator. ++ * ++ * unsafe_qmark if not NULL will be set to 1 or 0 if a question mark ++ * is found respectively in a literal or in a lookup/expansion (whether ++ * it's the first or last qmark depends on [QSL]). Should be initialized ++ * to -1 and remains so if no qmark is found. + */ +-static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry) ++static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry, ++ int *unsafe_qmark) + { ++#define EXPAND_SPECIALS "\\$%" + result_list *result, *current; + result_list sresult[SMALL_EXPANSION]; + unsigned spc = 0; +@@ -2386,8 +2393,29 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry) + char *p, *c; + apr_pool_t *pool = ctx->r->pool; + +- span = strcspn(input, "\\$%"); + inputlen = strlen(input); ++ if (!unsafe_qmark) { ++ span = strcspn(input, EXPAND_SPECIALS); ++ } ++ else { ++ span = strcspn(input, EXPAND_SPECIALS "?"); ++ if (input[span] == '?') { ++ /* this qmark is not from an expansion thus safe */ ++ *unsafe_qmark = 0; ++ ++ /* keep tracking only if interested in the last qmark */ ++ if (entry && (entry->flags & RULEFLAG_QSLAST)) { ++ do { ++ span++; ++ span += strcspn(input + span, EXPAND_SPECIALS "?"); ++ } while (input[span] == '?'); ++ } ++ else { ++ unsafe_qmark = NULL; ++ span += strcspn(input + span, EXPAND_SPECIALS); ++ } ++ } ++ } + + /* fast exit */ + if (inputlen == span) { +@@ -2405,6 +2433,8 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry) + + /* loop for specials */ + do { ++ int expanded = 0; ++ + /* prepare next entry */ + if (current->len) { + current->next = (spc < SMALL_EXPANSION) +@@ -2450,6 +2480,8 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry) + current->len = span; + current->string = p; + outlen += span; ++ ++ expanded = 1; + p = endp + 1; + } + +@@ -2489,19 +2521,18 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry) + } + + /* reuse of key variable as result */ +- key = lookup_map(ctx->r, map, do_expand(key, ctx, entry)); +- ++ key = lookup_map(ctx->r, map, do_expand(key, ctx, entry, NULL)); + if (!key && dflt && *dflt) { +- key = do_expand(dflt, ctx, entry); ++ key = do_expand(dflt, ctx, entry, NULL); + } +- +- if (key) { ++ if (key && *key) { + span = strlen(key); + current->len = span; + current->string = key; + outlen += span; + } + ++ expanded = 1; + p = endp + 1; + } + } +@@ -2531,8 +2562,9 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry) + current->len = span; + current->string = bri->source + bri->regmatch[n].rm_so; + } +- + outlen += span; ++ ++ expanded = 1; + } + + p += 2; +@@ -2545,8 +2577,41 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry) + ++outlen; + } + ++ if (unsafe_qmark && expanded && current->len ++ && memchr(current->string, '?', current->len)) { ++ /* this qmark is from an expansion thus unsafe */ ++ *unsafe_qmark = 1; ++ ++ /* keep tracking only if interested in the last qmark */ ++ if (!entry || !(entry->flags & RULEFLAG_QSLAST)) { ++ unsafe_qmark = NULL; ++ } ++ } ++ + /* check the remainder */ +- if (*p && (span = strcspn(p, "\\$%")) > 0) { ++ if (!unsafe_qmark) { ++ span = strcspn(p, EXPAND_SPECIALS); ++ } ++ else { ++ span = strcspn(p, EXPAND_SPECIALS "?"); ++ if (p[span] == '?') { ++ /* this qmark is not from an expansion thus safe */ ++ *unsafe_qmark = 0; ++ ++ /* keep tracking only if interested in the last qmark */ ++ if (entry && (entry->flags & RULEFLAG_QSLAST)) { ++ do { ++ span++; ++ span += strcspn(p + span, EXPAND_SPECIALS "?"); ++ } while (p[span] == '?'); ++ } ++ else { ++ unsafe_qmark = NULL; ++ span += strcspn(p + span, EXPAND_SPECIALS); ++ } ++ } ++ } ++ if (span > 0) { + if (current->len) { + current->next = (spc < SMALL_EXPANSION) + ? &(sresult[spc++]) +@@ -2591,7 +2656,7 @@ static void do_expand_env(data_item *env, rewrite_ctx *ctx) + char *name, *val; + + while (env) { +- name = do_expand(env->data, ctx, NULL); ++ name = do_expand(env->data, ctx, NULL, NULL); + if (*name == '!') { + name++; + apr_table_unset(ctx->r->subprocess_env, name); +@@ -2725,7 +2790,7 @@ static void add_cookie(request_rec *r, char *s) + static void do_expand_cookie(data_item *cookie, rewrite_ctx *ctx) + { + while (cookie) { +- add_cookie(ctx->r, do_expand(cookie->data, ctx, NULL)); ++ add_cookie(ctx->r, do_expand(cookie->data, ctx, NULL, NULL)); + cookie = cookie->next; + } + +@@ -4014,7 +4079,7 @@ static int apply_rewrite_cond(rewritecond_entry *p, rewrite_ctx *ctx) + int basis; + + if (p->ptype != CONDPAT_AP_EXPR) +- input = do_expand(p->input, ctx, NULL); ++ input = do_expand(p->input, ctx, NULL, NULL); + + switch (p->ptype) { + case CONDPAT_FILE_EXISTS: +@@ -4178,7 +4243,7 @@ static APR_INLINE void force_type_handler(rewriterule_entry *p, + char *expanded; + + if (p->forced_mimetype) { +- expanded = do_expand(p->forced_mimetype, ctx, p); ++ expanded = do_expand(p->forced_mimetype, ctx, p, NULL); + + if (*expanded) { + ap_str_tolower(expanded); +@@ -4192,7 +4257,7 @@ static APR_INLINE void force_type_handler(rewriterule_entry *p, + } + + if (p->forced_handler) { +- expanded = do_expand(p->forced_handler, ctx, p); ++ expanded = do_expand(p->forced_handler, ctx, p, NULL); + + if (*expanded) { + ap_str_tolower(expanded); +@@ -4329,12 +4394,18 @@ static rule_return_type apply_rewrite_rule(rewriterule_entry *p, + + /* expand the result */ + if (!(p->flags & RULEFLAG_NOSUB)) { +- newuri = do_expand(p->output, ctx, p); ++ int unsafe_qmark = -1; ++ ++ if (p->flags & RULEFLAG_UNSAFE_ALLOW3F) { ++ newuri = do_expand(p->output, ctx, p, NULL); ++ } ++ else { ++ newuri = do_expand(p->output, ctx, p, &unsafe_qmark); ++ } + 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, '?')) { ++ ++ if (unsafe_qmark > 0) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10508) + "Unsafe URL with %%3f URL rewritten without " + "UnsafeAllow3F"); + diff --git a/httpd-2.4.62-r1921299.patch b/httpd-2.4.62-r1921299.patch new file mode 100644 index 0000000000000000000000000000000000000000..589e7e89ad4fa885d5745840328cd6698484480a --- /dev/null +++ b/httpd-2.4.62-r1921299.patch @@ -0,0 +1,133 @@ +diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c +index 53fb1e9..f735c50 100644 +--- a/modules/mappers/mod_rewrite.c ++++ b/modules/mappers/mod_rewrite.c +@@ -4477,20 +4477,6 @@ static rule_return_type apply_rewrite_rule(rewriterule_entry *p, + * ourself). + */ + if (p->flags & RULEFLAG_PROXY) { +- /* For rules evaluated in server context, the mod_proxy fixup +- * hook can be relied upon to escape the URI as and when +- * necessary, since it occurs later. If in directory context, +- * the ordering of the fixup hooks is forced such that +- * mod_proxy comes first, so the URI must be escaped here +- * instead. See PR 39746, 46428, and other headaches. */ +- if (ctx->perdir && (p->flags & RULEFLAG_NOESCAPE) == 0) { +- char *old_filename = r->filename; +- +- r->filename = ap_escape_uri(r->pool, r->filename); +- rewritelog((r, 2, ctx->perdir, "escaped URI in per-dir context " +- "for proxy, %s -> %s", old_filename, r->filename)); +- } +- + fully_qualify_uri(r); + + rewritelog((r, 2, ctx->perdir, "forcing proxy-throughput with %s", +@@ -5013,7 +4999,7 @@ static int hook_uri2file(request_rec *r) + } + if ((r->args != NULL) + && ((r->proxyreq == PROXYREQ_PROXY) +- || (rulestatus == ACTION_NOESCAPE))) { ++ || apr_table_get(r->notes, "proxy-nocanon"))) { + /* see proxy_http:proxy_http_canon() */ + r->filename = apr_pstrcat(r->pool, r->filename, + "?", r->args, NULL); +@@ -5304,13 +5290,28 @@ static int hook_fixup(request_rec *r) + if (to_proxyreq) { + /* it should go on as an internal proxy request */ + +- /* make sure the QUERY_STRING and +- * PATH_INFO parts get incorporated ++ /* check if the proxy module is enabled, so ++ * we can actually use it! ++ */ ++ if (!proxy_available) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10160) ++ "attempt to make remote request from mod_rewrite " ++ "without proxy enabled: %s", r->filename); ++ return HTTP_FORBIDDEN; ++ } ++ ++ if (rulestatus == ACTION_NOESCAPE) { ++ apr_table_setn(r->notes, "proxy-nocanon", "1"); ++ } ++ ++ /* make sure the QUERY_STRING gets incorporated in the case ++ * [NE] was specified on the Proxy rule. We are preventing ++ * mod_proxy canon handler from incorporating r->args as well ++ * as escaping the URL. + * (r->path_info was already appended by the + * rewriting engine because of the per-dir context!) + */ +- if (r->args != NULL) { +- /* see proxy_http:proxy_http_canon() */ ++ if ((r->args != NULL) && apr_table_get(r->notes, "proxy-nocanon")) { + r->filename = apr_pstrcat(r->pool, r->filename, + "?", r->args, NULL); + } +@@ -5610,10 +5611,7 @@ static void ap_register_rewrite_mapfunc(char *name, rewrite_mapfunc_t *func) + + static void register_hooks(apr_pool_t *p) + { +- /* fixup after mod_proxy, so that the proxied url will not +- * escaped accidentally by mod_proxy's fixup. +- */ +- static const char * const aszPre[]={ "mod_proxy.c", NULL }; ++ static const char * const aszModProxy[] = { "mod_proxy.c", NULL }; + + /* make the hashtable before registering the function, so that + * other modules are prevented from accessing uninitialized memory. +@@ -5625,10 +5623,12 @@ static void register_hooks(apr_pool_t *p) + ap_hook_pre_config(pre_config, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_post_config(post_config, NULL, NULL, APR_HOOK_MIDDLE); + ap_hook_child_init(init_child, NULL, NULL, APR_HOOK_MIDDLE); +- +- ap_hook_fixups(hook_fixup, aszPre, NULL, APR_HOOK_FIRST); ++ ++ /* allow to change the uri before mod_proxy takes over it */ ++ ap_hook_translate_name(hook_uri2file, NULL, aszModProxy, APR_HOOK_FIRST); ++ /* fixup before mod_proxy so that a [P] URL gets fixed up there */ ++ ap_hook_fixups(hook_fixup, NULL, aszModProxy, APR_HOOK_FIRST); + ap_hook_fixups(hook_mimetype, NULL, NULL, APR_HOOK_LAST); +- ap_hook_translate_name(hook_uri2file, NULL, NULL, APR_HOOK_FIRST); + } + + /* the main config structure */ +diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c +index 8f13e68..bd0aa68 100644 +--- a/modules/proxy/mod_proxy.c ++++ b/modules/proxy/mod_proxy.c +@@ -3344,27 +3344,26 @@ static int proxy_pre_config(apr_pool_t *pconf, apr_pool_t *plog, + } + static void register_hooks(apr_pool_t *p) + { +- /* fixup before mod_rewrite, so that the proxied url will not +- * escaped accidentally by our fixup. +- */ +- static const char * const aszSucc[] = { "mod_rewrite.c", NULL}; + /* Only the mpm_winnt has child init hook handler. + * make sure that we are called after the mpm + * initializes. + */ + static const char *const aszPred[] = { "mpm_winnt.c", "mod_proxy_balancer.c", + "mod_proxy_hcheck.c", NULL}; ++ static const char * const aszModRewrite[] = { "mod_rewrite.c", NULL }; ++ + /* handler */ + ap_hook_handler(proxy_handler, NULL, NULL, APR_HOOK_FIRST); + /* filename-to-URI translation */ + ap_hook_pre_translate_name(proxy_pre_translate_name, NULL, NULL, + APR_HOOK_MIDDLE); +- ap_hook_translate_name(proxy_translate_name, aszSucc, NULL, ++ /* mod_rewrite has a say on the uri before proxy translation */ ++ ap_hook_translate_name(proxy_translate_name, aszModRewrite, NULL, + APR_HOOK_FIRST); + /* walk entries and suppress default TRACE behavior */ + ap_hook_map_to_storage(proxy_map_location, NULL,NULL, APR_HOOK_FIRST); +- /* fixups */ +- ap_hook_fixups(proxy_fixup, NULL, aszSucc, APR_HOOK_FIRST); ++ /* fixup after mod_rewrite so that a [P] URL from there gets fixed up */ ++ ap_hook_fixups(proxy_fixup, aszModRewrite, NULL, APR_HOOK_FIRST); + /* post read_request handling */ + ap_hook_post_read_request(proxy_detect, NULL, NULL, APR_HOOK_FIRST); + /* pre config handling */ diff --git a/httpd-2.4.62-r1922080.patch b/httpd-2.4.62-r1922080.patch new file mode 100644 index 0000000000000000000000000000000000000000..9b1b3a4e4ecf18ae08e46527005b9293ebbd5242 --- /dev/null +++ b/httpd-2.4.62-r1922080.patch @@ -0,0 +1,136 @@ +From 2aa446f5b08a10c37e952daf96d0c80d3460873a Mon Sep 17 00:00:00 2001 +From: Eric Covener +Date: Mon, 25 Nov 2024 13:32:44 +0000 +Subject: [PATCH] Merge r1919620, r1919621, r1919623, r1919628, r1921237 from + trunk: + +mod_proxy_fcgi: Don't re-encode SCRIPT_FILENAME. PR 69203 + +Before r1918550 (r1918559 in 2.4.60), "SetHandler proxy:..." configurations +did not pass through proxy_fixup() hence the proxy_canon_handler hooks, leaving +fcgi's SCRIPT_FILENAME environment variable (from r->filename) decoded, or more +exactly not re-encoded. + +We still want to call ap_proxy_canon_url() for "fcgi:" to handle/strip the UDS +"unix:" case and check that r->filename is valid and contains no controls, but +proxy_fcgi_canon() will not ap_proxy_canonenc_ex() thus re-encode anymore. + +Note that this will do the same for "ProxyPass fcgi:...", there is no reason +that using SetHandler or ProxyPass don't result in the same thing. If an opt +in/out makes sense we should probably look at ProxyFCGIBackendType. + + + +Follow up to r1919620: CHANGES entry indent. + +Follow up to r1919620: init path after "proxy:" is skipped. + +Follow up to r1919620: Restore r->filename re-encoding for ProxyPass URLs. + + + +mod_proxy_fgci: Follow up to r1919628: Simplify. + +Variable from_handler is used once so axe it. + + + +Submitted by: ylavic +Reviewed by: ylavic, covener, jorton + +Github: closes #470 + + +git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1922080 13f79535-47bb-0310-9956-ffa450edef68 +--- + CHANGES | 3 +++ + changes-entries/bz69203.txt | 2 ++ + modules/proxy/mod_proxy.c | 2 ++ + modules/proxy/mod_proxy_fcgi.c | 37 +++++++++++++++++++++++----------- + 4 files changed, 32 insertions(+), 12 deletions(-) + create mode 100644 changes-entries/bz69203.txt + +diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c +index ab29c321df8..4047d58f2aa 100644 +--- a/modules/proxy/mod_proxy.c ++++ b/modules/proxy/mod_proxy.c +@@ -1240,6 +1240,7 @@ static int proxy_handler(request_rec *r) + + r->proxyreq = PROXYREQ_REVERSE; + r->filename = apr_pstrcat(r->pool, r->handler, r->filename, NULL); ++ apr_table_setn(r->notes, "proxy-sethandler", "1"); + + /* Still need to canonicalize r->filename */ + rc = ap_proxy_canon_url(r); +@@ -1249,6 +1250,7 @@ static int proxy_handler(request_rec *r) + } + } + else if (r->proxyreq && strncmp(r->filename, "proxy:", 6) == 0) { ++ apr_table_unset(r->notes, "proxy-sethandler"); + rc = OK; + } + if (rc != OK) { +diff --git a/modules/proxy/mod_proxy_fcgi.c b/modules/proxy/mod_proxy_fcgi.c +index d420df6a77a..50f443e50d9 100644 +--- a/modules/proxy/mod_proxy_fcgi.c ++++ b/modules/proxy/mod_proxy_fcgi.c +@@ -63,6 +63,8 @@ static int proxy_fcgi_canon(request_rec *r, char *url) + apr_port_t port, def_port; + fcgi_req_config_t *rconf = NULL; + const char *pathinfo_type = NULL; ++ fcgi_dirconf_t *dconf = ap_get_module_config(r->per_dir_config, ++ &proxy_fcgi_module); + + if (ap_cstr_casecmpn(url, "fcgi:", 5) == 0) { + url += 5; +@@ -92,9 +94,30 @@ static int proxy_fcgi_canon(request_rec *r, char *url) + host = apr_pstrcat(r->pool, "[", host, "]", NULL); + } + +- if (apr_table_get(r->notes, "proxy-nocanon") ++ if (apr_table_get(r->notes, "proxy-sethandler") ++ || apr_table_get(r->notes, "proxy-nocanon") + || apr_table_get(r->notes, "proxy-noencode")) { +- path = url; /* this is the raw/encoded path */ ++ char *c = url; ++ ++ /* We do not call ap_proxy_canonenc_ex() on the path here, don't ++ * let control characters pass still, and for php-fpm no '?' either. ++ */ ++ if (FCGI_MAY_BE_FPM(dconf)) { ++ while (!apr_iscntrl(*c) && *c != '?') ++ c++; ++ } ++ else { ++ while (!apr_iscntrl(*c)) ++ c++; ++ } ++ if (*c) { ++ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10414) ++ "To be forwarded path contains control characters%s (%s)", ++ FCGI_MAY_BE_FPM(dconf) ? " or '?'" : "", url); ++ return HTTP_FORBIDDEN; ++ } ++ ++ path = url; /* this is the raw path */ + } + else { + core_dir_config *d = ap_get_core_module_config(r->per_dir_config); +@@ -106,16 +129,6 @@ static int proxy_fcgi_canon(request_rec *r, char *url) + return HTTP_BAD_REQUEST; + } + } +- /* +- * If we have a raw control character or a ' ' in nocanon path, +- * correct encoding was missed. +- */ +- if (path == url && *ap_scan_vchar_obstext(path)) { +- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10414) +- "To be forwarded path contains control " +- "characters or spaces"); +- return HTTP_FORBIDDEN; +- } + + r->filename = apr_pstrcat(r->pool, "proxy:fcgi://", host, sport, "/", + path, NULL); + diff --git a/httpd-2.4.62-r1926064.patch b/httpd-2.4.62-r1926064.patch new file mode 100644 index 0000000000000000000000000000000000000000..350d52f28b633bfc6c00035fd4cac4640f230c84 --- /dev/null +++ b/httpd-2.4.62-r1926064.patch @@ -0,0 +1,44 @@ +# ./pullrev.sh 1926064 +http://svn.apache.org/viewvc?view=revision&revision=1926064 + +Since we can't jump from the 2.4.62-level MMN to the 2.4.64-level +MMN added in the upstream 2.4.x backport without adding all other APIs, +this patch defines a custom macro: + + #define AP_X_RH_DAV_GET_BASE_PATH 1 + +which can be tested in the mod_dav_svn code which consumes this. + +--- httpd-2.4.62/modules/dav/main/mod_dav.c ++++ httpd-2.4.62/modules/dav/main/mod_dav.c +@@ -250,6 +250,13 @@ + return dav_get_provider(r)->search; + } + ++DAV_DECLARE(const char *) dav_get_base_path(request_rec *r) ++{ ++ dav_dir_conf *conf = ap_get_module_config(r->per_dir_config, &dav_module); ++ ++ return conf && conf->base ? conf->base : NULL; ++} ++ + /* + * Command handler for the DAV directive, which is TAKE1. + */ +--- httpd-2.4.62/modules/dav/main/mod_dav.h ++++ httpd-2.4.62/modules/dav/main/mod_dav.h +@@ -430,6 +430,14 @@ + DAV_DECLARE(dav_error *) dav_get_resource(request_rec *r, int label_allowed, + int use_checked_in, dav_resource **res_p); + ++/* Defined for backported dav_get_base_path(). */ ++#define AP_X_RH_DAV_GET_BASE_PATH 1 ++ ++/* ++** If DavBasePath is configured for the request location, return the ++** configured path, otherwise NULL. ++*/ ++DAV_DECLARE(const char *) dav_get_base_path(request_rec *r); + + /* -------------------------------------------------------------------- + ** diff --git a/httpd-2.4.62-r1926317.patch b/httpd-2.4.62-r1926317.patch new file mode 100644 index 0000000000000000000000000000000000000000..ff0ff9fbc12366625e0c8765986bfc3ea0fa4922 --- /dev/null +++ b/httpd-2.4.62-r1926317.patch @@ -0,0 +1,454 @@ +From 73360a7509796ea2ed551d3c2cd7661b3703ab0c Mon Sep 17 00:00:00 2001 +From: Yann Ylavic +Date: Tue, 10 Jun 2025 10:43:58 +0000 +Subject: [PATCH] Merge r1912460, r1925743 from trunk: + +mod_proxy: Consistently close the socket on failure to reuse the connection. + +proxy_connection_create() and ap_proxy_connect_backend() sometimes close the +connection on failure, sometimes not. Always close it. + +mod_proxy: restore reuse of ProxyRemote connections when possible. + +Fixes a regression from 2.4.59 (r1913907). + +For a reverse proxy setup with a worker (enablereuse=on) and a +forward/CONNECT ProxyRemote to reach it, an open connection/tunnel +to/through the remote proxy for the same origin server (and using the +same proxy auth) should be reusable. Avoid closing them like r1913534 +did. + +* modules/proxy/proxy_util.c: + Rename the struct to remote_connect_info since it's only used for + connecting through remote CONNECT proxies. Axe the use_http_connect + field, always true. + +* modules/proxy/proxy_util.c(ap_proxy_connection_reusable): + Remote CONNECT (forward) proxy connections can be reused if the auth + and origin server infos are the same, so conn->forward != NULL is not + a condition to prevent reusability. + +* modules/proxy/proxy_util.c(ap_proxy_determine_connection): + Fix the checks around conn->forward reuse and connection cleanup if + that's not possible. + +Submitted by: jfclere, ylavic +Reviewed by: ylavic, jfclere, rpluem + +Github: closes #532 + +git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1926317 13f79535-47bb-0310-9956-ffa450edef68 +--- + modules/proxy/proxy_util.c | 193 ++++++++++++++++++------------------- + 1 file changed, 94 insertions(+), 99 deletions(-) + +diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c +index 7c0d315..cd13401 100644 +--- a/modules/proxy/proxy_util.c ++++ b/modules/proxy/proxy_util.c +@@ -45,16 +45,16 @@ + APLOG_USE_MODULE(proxy); + + /* +- * Opaque structure containing target server info when +- * using a forward proxy. +- * Up to now only used in combination with HTTP CONNECT to ProxyRemote ++ * Opaque structure containing infos for CONNECT-ing an origin server through a ++ * remote (forward) proxy. Saved in the (opaque) proxy_conn_rec::forward pointer ++ * field for backend connections kept alive, allowing for reuse when subsequent ++ * requests should be routed through the same remote proxy. + */ + typedef struct { +- int use_http_connect; /* Use SSL Tunneling via HTTP CONNECT */ +- const char *target_host; /* Target hostname */ +- apr_port_t target_port; /* Target port */ + const char *proxy_auth; /* Proxy authorization */ +-} forward_info; ++ const char *target_host; /* Target/origin hostname */ ++ apr_port_t target_port; /* Target/origin port */ ++} remote_connect_info; + + /* + * Opaque structure containing a refcounted and TTL'ed address. +@@ -1508,6 +1508,7 @@ static void socket_cleanup(proxy_conn_rec *conn) + conn->connection = NULL; + conn->ssl_hostname = NULL; + apr_pool_clear(conn->scpool); ++ conn->close = 0; + } + + static void conn_cleanup(proxy_conn_rec *conn) +@@ -1525,6 +1526,7 @@ static void conn_cleanup(proxy_conn_rec *conn) + + static apr_status_t conn_pool_cleanup(void *theworker) + { ++ /* Signal that the child is exiting */ + ((proxy_worker *)theworker)->cp = NULL; + return APR_SUCCESS; + } +@@ -1603,10 +1605,7 @@ PROXY_DECLARE(int) ap_proxy_connection_reusable(proxy_conn_rec *conn) + { + proxy_worker *worker = conn->worker; + +- return !(conn->close +- || conn->forward +- || worker->s->disablereuse +- || !worker->s->is_address_reusable); ++ return !(conn->close || worker->s->disablereuse); + } + + static proxy_conn_rec *connection_make(apr_pool_t *p, proxy_worker *worker) +@@ -1659,18 +1658,17 @@ static void connection_cleanup(void *theconn) + apr_pool_clear(p); + conn = connection_make(p, worker); + } +- else if (conn->close +- || conn->forward ++ else if (!conn->sock + || (conn->connection + && conn->connection->keepalive == AP_CONN_CLOSE) +- || worker->s->disablereuse) { ++ || !ap_proxy_connection_reusable(conn)) { + socket_cleanup(conn); +- conn->close = 0; + } + else if (conn->is_ssl) { +- /* Unbind/reset the SSL connection dir config (sslconn->dc) from +- * r->per_dir_config, r will likely get destroyed before this proxy +- * conn is reused. ++ /* The current ssl section/dir config of the conn is not necessarily ++ * the one it will be reused for, so while the conn is in the reslist ++ * reset its ssl config to the worker's, until a new user sets its own ++ * ssl config eventually in proxy_connection_create() and so on. + */ + ap_proxy_ssl_engine(conn->connection, worker->section_config, 1); + } +@@ -2800,7 +2798,6 @@ PROXY_DECLARE(int) ap_proxy_acquire_connection(const char *proxy_function, + (int)worker->s->port); + + (*conn)->worker = worker; +- (*conn)->close = 0; + (*conn)->inreslist = 0; + + return OK; +@@ -3245,7 +3242,6 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, + /* Close a possible existing socket if we are told to do so */ + if (conn->close) { + socket_cleanup(conn); +- conn->close = 0; + } + + /* +@@ -3311,12 +3307,10 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, + uri->scheme, conn->uds_path, conn->hostname, conn->port); + } + else { ++ remote_connect_info *connect_info = NULL; + const char *hostname = uri->hostname; + apr_port_t hostport = uri->port; + +- /* Not a remote CONNECT until further notice */ +- conn->forward = NULL; +- + if (proxyname) { + hostname = proxyname; + hostport = proxyport; +@@ -3327,7 +3321,6 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, + * sending our actual HTTPS requests. + */ + if (conn->is_ssl) { +- forward_info *forward; + const char *proxy_auth; + + /* Do we want to pass Proxy-Authorization along? +@@ -3346,13 +3339,15 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, + proxy_auth = NULL; + } + +- /* Reset forward info if they changed */ +- if (!(forward = conn->forward) +- || forward->target_port != uri->port +- || ap_cstr_casecmp(forward->target_host, uri->hostname) != 0 +- || (forward->proxy_auth != NULL) != (proxy_auth != NULL) +- || (forward->proxy_auth != NULL && proxy_auth != NULL && +- strcmp(forward->proxy_auth, proxy_auth) != 0)) { ++ /* Save our real backend data for using it later during HTTP CONNECT */ ++ connect_info = conn->forward; ++ if (!connect_info ++ /* reset connect info if they changed */ ++ || connect_info->target_port != uri->port ++ || ap_cstr_casecmp(connect_info->target_host, uri->hostname) != 0 ++ || (connect_info->proxy_auth != NULL) != (proxy_auth != NULL) ++ || (connect_info->proxy_auth != NULL && proxy_auth != NULL && ++ strcmp(connect_info->proxy_auth, proxy_auth) != 0)) { + apr_pool_t *fwd_pool = conn->pool; + if (worker->s->is_address_reusable) { + if (conn->fwd_pool) { +@@ -3363,26 +3358,24 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, + } + fwd_pool = conn->fwd_pool; + } +- forward = apr_pcalloc(fwd_pool, sizeof(forward_info)); +- conn->forward = forward; +- +- /* +- * Save our real backend data for using it later during HTTP CONNECT. +- */ +- forward->use_http_connect = 1; +- forward->target_host = apr_pstrdup(fwd_pool, uri->hostname); +- forward->target_port = uri->port; ++ connect_info = apr_pcalloc(fwd_pool, sizeof(*connect_info)); ++ connect_info->target_host = apr_pstrdup(fwd_pool, uri->hostname); ++ connect_info->target_port = uri->port; + if (proxy_auth) { +- forward->proxy_auth = apr_pstrdup(fwd_pool, proxy_auth); ++ connect_info->proxy_auth = apr_pstrdup(fwd_pool, proxy_auth); + } ++ conn->forward = NULL; + } + } + } + +- if (conn->hostname +- && (conn->port != hostport +- || ap_cstr_casecmp(conn->hostname, hostname) != 0)) { ++ /* Close the connection if the remote proxy or origin server don't match */ ++ if (conn->forward != connect_info ++ || (conn->hostname ++ && (conn->port != hostport ++ || ap_cstr_casecmp(conn->hostname, hostname) != 0))) { + conn_cleanup(conn); ++ conn->forward = connect_info; + } + + /* Resolve the connection address with the determined hostname/port */ +@@ -3426,9 +3419,8 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, + if (dconf->preserve_host) { + ssl_hostname = r->hostname; + } +- else if (conn->forward +- && ((forward_info *)(conn->forward))->use_http_connect) { +- ssl_hostname = ((forward_info *)conn->forward)->target_host; ++ else if (conn->forward) { ++ ssl_hostname = ((remote_connect_info *)conn->forward)->target_host; + } + else { + ssl_hostname = conn->hostname; +@@ -3525,7 +3517,7 @@ PROXY_DECLARE(int) ap_proxy_is_socket_connected(apr_socket_t *sock) + + + /* +- * Send a HTTP CONNECT request to a forward proxy. ++ * Send a HTTP CONNECT request to a remote proxy. + * The proxy is given by "backend", the target server + * is contained in the "forward" member of "backend". + */ +@@ -3538,24 +3530,24 @@ static apr_status_t send_http_connect(proxy_conn_rec *backend, + int complete = 0; + char buffer[HUGE_STRING_LEN]; + char drain_buffer[HUGE_STRING_LEN]; +- forward_info *forward = (forward_info *)backend->forward; ++ remote_connect_info *connect_info = backend->forward; + int len = 0; + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00948) + "CONNECT: sending the CONNECT request for %s:%d " + "to the remote proxy %pI (%s)", +- forward->target_host, forward->target_port, ++ connect_info->target_host, connect_info->target_port, + backend->addr, backend->hostname); + /* Create the CONNECT request */ + nbytes = apr_snprintf(buffer, sizeof(buffer), + "CONNECT %s:%d HTTP/1.0" CRLF, +- forward->target_host, forward->target_port); ++ connect_info->target_host, connect_info->target_port); + /* Add proxy authorization from the configuration, or initial + * request if necessary */ +- if (forward->proxy_auth != NULL) { ++ if (connect_info->proxy_auth != NULL) { + nbytes += apr_snprintf(buffer + nbytes, sizeof(buffer) - nbytes, + "Proxy-Authorization: %s" CRLF, +- forward->proxy_auth); ++ connect_info->proxy_auth); + } + /* Set a reasonable agent and send everything */ + nbytes += apr_snprintf(buffer + nbytes, sizeof(buffer) - nbytes, +@@ -3599,7 +3591,7 @@ static apr_status_t send_http_connect(proxy_conn_rec *backend, + char code_str[4]; + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00949) +- "send_http_connect: response from the forward proxy: %s", ++ "send_http_connect: response from the remote proxy: %s", + buffer); + + /* Extract the returned code */ +@@ -3610,7 +3602,7 @@ static apr_status_t send_http_connect(proxy_conn_rec *backend, + } + else { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(00950) +- "send_http_connect: the forward proxy returned code is '%s'", ++ "send_http_connect: the remote proxy returned code is '%s'", + code_str); + status = APR_INCOMPLETE; + } +@@ -3774,7 +3766,7 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, + { + apr_status_t rv; + int loglevel; +- forward_info *forward = conn->forward; ++ remote_connect_info *connect_info = conn->forward; + apr_sockaddr_t *backend_addr; + /* the local address to use for the outgoing connection */ + apr_sockaddr_t *local_addr; +@@ -3975,27 +3967,25 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, + + conn->sock = newsock; + +- if (forward && forward->use_http_connect) { +- /* +- * For HTTP CONNECT we need to prepend CONNECT request before +- * sending our actual HTTPS requests. +- */ +- { +- rv = send_http_connect(conn, s); +- /* If an error occurred, loop round and try again */ +- if (rv != APR_SUCCESS) { +- conn->sock = NULL; +- apr_socket_close(newsock); +- loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR; +- ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(00958) +- "%s: attempt to connect to %s:%hu " +- "via http CONNECT through %pI (%s:%hu) failed", +- proxy_function, +- forward->target_host, forward->target_port, +- backend_addr, conn->hostname, conn->port); +- backend_addr = backend_addr->next; +- continue; +- } ++ /* ++ * For HTTP CONNECT we need to prepend CONNECT request before ++ * sending our actual HTTPS requests. ++ */ ++ if (connect_info) { ++ rv = send_http_connect(conn, s); ++ /* If an error occurred, loop round and try again */ ++ if (rv != APR_SUCCESS) { ++ conn->sock = NULL; ++ apr_socket_close(newsock); ++ loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR; ++ ap_log_error(APLOG_MARK, loglevel, rv, s, APLOGNO(00958) ++ "%s: attempt to connect to %s:%hu " ++ "via http CONNECT through %pI (%s:%hu) failed", ++ proxy_function, ++ connect_info->target_host, connect_info->target_port, ++ backend_addr, conn->hostname, conn->port); ++ backend_addr = backend_addr->next; ++ continue; + } + } + } +@@ -4036,13 +4026,13 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, + * e.g. for a timeout or bad status. We should respect this and should + * not continue with a connection via this worker even if we got one. + */ +- if (rv == APR_SUCCESS) { +- socket_cleanup(conn); +- } + rv = APR_EINVAL; + } +- +- return rv == APR_SUCCESS ? OK : DECLINED; ++ if (rv != APR_SUCCESS) { ++ socket_cleanup(conn); ++ return DECLINED; ++ } ++ return OK; + } + + static apr_status_t connection_shutdown(void *theconn) +@@ -4079,9 +4069,9 @@ static int proxy_connection_create(const char *proxy_function, + ap_conf_vector_t *per_dir_config = (r) ? r->per_dir_config + : conn->worker->section_config; + apr_sockaddr_t *backend_addr = conn->addr; +- int rc; + apr_interval_time_t current_timeout; + apr_bucket_alloc_t *bucket_alloc; ++ int rc = OK; + + if (conn->connection) { + if (conn->is_ssl) { +@@ -4093,15 +4083,15 @@ static int proxy_connection_create(const char *proxy_function, + return OK; + } + +- bucket_alloc = apr_bucket_alloc_create(conn->scpool); +- conn->tmp_bb = apr_brigade_create(conn->scpool, bucket_alloc); +- /* +- * The socket is now open, create a new backend server connection +- */ +- conn->connection = ap_run_create_connection(conn->scpool, s, conn->sock, +- 0, NULL, +- bucket_alloc); +- ++ if (conn->sock) { ++ bucket_alloc = apr_bucket_alloc_create(conn->scpool); ++ conn->tmp_bb = apr_brigade_create(conn->scpool, bucket_alloc); ++ /* ++ * The socket is now open, create a new backend server connection ++ */ ++ conn->connection = ap_run_create_connection(conn->scpool, s, conn->sock, ++ 0, NULL, bucket_alloc); ++ } + if (!conn->connection) { + /* + * the peer reset the connection already; ap_run_create_connection() +@@ -4109,11 +4099,11 @@ static int proxy_connection_create(const char *proxy_function, + */ + ap_log_error(APLOG_MARK, APLOG_ERR, 0, + s, APLOGNO(00960) "%s: an error occurred creating a " +- "new connection to %pI (%s)", proxy_function, +- backend_addr, conn->hostname); +- /* XXX: Will be closed when proxy_conn is closed */ +- socket_cleanup(conn); +- return HTTP_INTERNAL_SERVER_ERROR; ++ "new connection to %pI (%s)%s", ++ proxy_function, backend_addr, conn->hostname, ++ conn->sock ? "" : " (not connected)"); ++ rc = HTTP_INTERNAL_SERVER_ERROR; ++ goto cleanup; + } + + /* For ssl connection to backend */ +@@ -4123,7 +4113,8 @@ static int proxy_connection_create(const char *proxy_function, + s, APLOGNO(00961) "%s: failed to enable ssl support " + "for %pI (%s)", proxy_function, + backend_addr, conn->hostname); +- return HTTP_INTERNAL_SERVER_ERROR; ++ rc = HTTP_INTERNAL_SERVER_ERROR; ++ goto cleanup; + } + if (conn->ssl_hostname) { + /* Set a note on the connection about what CN is requested, +@@ -4158,7 +4149,7 @@ static int proxy_connection_create(const char *proxy_function, + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(00963) + "%s: pre_connection setup failed (%d)", + proxy_function, rc); +- return rc; ++ goto cleanup; + } + apr_socket_timeout_set(conn->sock, current_timeout); + +@@ -4168,6 +4159,10 @@ static int proxy_connection_create(const char *proxy_function, + apr_pool_pre_cleanup_register(conn->scpool, conn, connection_shutdown); + + return OK; ++ ++cleanup: ++ socket_cleanup(conn); ++ return rc; + } + + PROXY_DECLARE(int) ap_proxy_connection_create_ex(const char *proxy_function, +-- +2.44.0 + diff --git a/httpd-2.4.62-socket-activation.patch b/httpd-2.4.62-socket-activation.patch new file mode 100644 index 0000000000000000000000000000000000000000..77eaa4558c0b467b4d4fb404f427a78d13f86606 --- /dev/null +++ b/httpd-2.4.62-socket-activation.patch @@ -0,0 +1,300 @@ +diff --git a/server/listen.c b/server/listen.c +index 9577d60..d718db1 100644 +--- a/server/listen.c ++++ b/server/listen.c +@@ -35,6 +35,10 @@ + #include + #endif + ++#ifdef HAVE_SYSTEMD ++#include ++#endif ++ + /* we know core's module_index is 0 */ + #undef APLOG_MODULE_INDEX + #define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX +@@ -60,9 +64,12 @@ static int ap_listenbacklog; + static int ap_listencbratio; + static int send_buffer_size; + static int receive_buffer_size; ++#ifdef HAVE_SYSTEMD ++static int use_systemd = -1; ++#endif + + /* TODO: make_sock is just begging and screaming for APR abstraction */ +-static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server) ++static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server, int do_bind_listen) + { + apr_socket_t *s = server->sd; + int one = 1; +@@ -95,20 +102,6 @@ static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server) + return stat; + } + +-#if APR_HAVE_IPV6 +- if (server->bind_addr->family == APR_INET6) { +- stat = apr_socket_opt_set(s, APR_IPV6_V6ONLY, v6only_setting); +- if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) { +- ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p, APLOGNO(00069) +- "make_sock: for address %pI, apr_socket_opt_set: " +- "(IPV6_V6ONLY)", +- server->bind_addr); +- apr_socket_close(s); +- return stat; +- } +- } +-#endif +- + /* + * To send data over high bandwidth-delay connections at full + * speed we must force the TCP window to open wide enough to keep the +@@ -170,21 +163,37 @@ static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server) + } + #endif + +- if ((stat = apr_socket_bind(s, server->bind_addr)) != APR_SUCCESS) { +- ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, stat, p, APLOGNO(00072) +- "make_sock: could not bind to address %pI", +- server->bind_addr); +- apr_socket_close(s); +- return stat; +- } ++ if (do_bind_listen) { ++#if APR_HAVE_IPV6 ++ if (server->bind_addr->family == APR_INET6) { ++ stat = apr_socket_opt_set(s, APR_IPV6_V6ONLY, v6only_setting); ++ if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) { ++ ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p, APLOGNO(00069) ++ "make_sock: for address %pI, apr_socket_opt_set: " ++ "(IPV6_V6ONLY)", ++ server->bind_addr); ++ apr_socket_close(s); ++ return stat; ++ } ++ } ++#endif + +- if ((stat = apr_socket_listen(s, ap_listenbacklog)) != APR_SUCCESS) { +- ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_ERR, stat, p, APLOGNO(00073) +- "make_sock: unable to listen for connections " +- "on address %pI", +- server->bind_addr); +- apr_socket_close(s); +- return stat; ++ if ((stat = apr_socket_bind(s, server->bind_addr)) != APR_SUCCESS) { ++ ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, stat, p, APLOGNO(00072) ++ "make_sock: could not bind to address %pI", ++ server->bind_addr); ++ apr_socket_close(s); ++ return stat; ++ } ++ ++ if ((stat = apr_socket_listen(s, ap_listenbacklog)) != APR_SUCCESS) { ++ ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_ERR, stat, p, APLOGNO(00073) ++ "make_sock: unable to listen for connections " ++ "on address %pI", ++ server->bind_addr); ++ apr_socket_close(s); ++ return stat; ++ } + } + + #ifdef WIN32 +@@ -335,6 +344,123 @@ static int find_listeners(ap_listen_rec **from, ap_listen_rec **to, + return found; + } + ++#ifdef HAVE_SYSTEMD ++ ++static int find_systemd_socket(process_rec * process, apr_port_t port) { ++ int fdcount, fd; ++ int sdc = sd_listen_fds(0); ++ ++ if (sdc < 0) { ++ ap_log_perror(APLOG_MARK, APLOG_CRIT, sdc, process->pool, APLOGNO(02486) ++ "find_systemd_socket: Error parsing enviroment, sd_listen_fds returned %d", ++ sdc); ++ return -1; ++ } ++ ++ if (sdc == 0) { ++ ap_log_perror(APLOG_MARK, APLOG_CRIT, sdc, process->pool, APLOGNO(02487) ++ "find_systemd_socket: At least one socket must be set."); ++ return -1; ++ } ++ ++ fdcount = atoi(getenv("LISTEN_FDS")); ++ for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + fdcount; fd++) { ++ if (sd_is_socket_inet(fd, 0, 0, -1, port) > 0) { ++ return fd; ++ } ++ } ++ ++ return -1; ++} ++ ++static apr_status_t alloc_systemd_listener(process_rec * process, ++ int fd, const char *proto, ++ ap_listen_rec **out_rec) ++{ ++ apr_status_t rv; ++ struct sockaddr sa; ++ socklen_t len = sizeof(struct sockaddr); ++ apr_os_sock_info_t si; ++ ap_listen_rec *rec; ++ *out_rec = NULL; ++ ++ memset(&si, 0, sizeof(si)); ++ ++ rv = getsockname(fd, &sa, &len); ++ ++ if (rv != 0) { ++ rv = apr_get_netos_error(); ++ ap_log_perror(APLOG_MARK, APLOG_CRIT, rv, process->pool, APLOGNO(02489) ++ "getsockname on %d failed.", fd); ++ return rv; ++ } ++ ++ si.os_sock = &fd; ++ si.family = sa.sa_family; ++ si.local = &sa; ++ si.type = SOCK_STREAM; ++ si.protocol = APR_PROTO_TCP; ++ ++ rec = apr_palloc(process->pool, sizeof(ap_listen_rec)); ++ rec->active = 0; ++ rec->next = 0; ++ ++ ++ rv = apr_os_sock_make(&rec->sd, &si, process->pool); ++ if (rv != APR_SUCCESS) { ++ ap_log_perror(APLOG_MARK, APLOG_CRIT, rv, process->pool, APLOGNO(02490) ++ "apr_os_sock_make on %d failed.", fd); ++ return rv; ++ } ++ ++ rv = apr_socket_addr_get(&rec->bind_addr, APR_LOCAL, rec->sd); ++ if (rv != APR_SUCCESS) { ++ ap_log_perror(APLOG_MARK, APLOG_CRIT, rv, process->pool, APLOGNO(02491) ++ "apr_socket_addr_get on %d failed.", fd); ++ return rv; ++ } ++ ++ rec->protocol = apr_pstrdup(process->pool, proto); ++ ++ *out_rec = rec; ++ ++ return make_sock(process->pool, rec, 0); ++} ++ ++static const char *set_systemd_listener(process_rec *process, apr_port_t port, ++ const char *proto) ++{ ++ ap_listen_rec *last, *new; ++ apr_status_t rv; ++ int fd = find_systemd_socket(process, port); ++ if (fd < 0) { ++ return "Systemd socket activation is used, but this port is not " ++ "configured in systemd"; ++ } ++ ++ last = ap_listeners; ++ while (last && last->next) { ++ last = last->next; ++ } ++ ++ rv = alloc_systemd_listener(process, fd, proto, &new); ++ if (rv != APR_SUCCESS) { ++ return "Failed to setup socket passed by systemd using socket activation"; ++ } ++ ++ if (last == NULL) { ++ ap_listeners = last = new; ++ } ++ else { ++ last->next = new; ++ last = new; ++ } ++ ++ return NULL; ++} ++ ++#endif /* HAVE_SYSTEMD */ ++ + static const char *alloc_listener(process_rec *process, const char *addr, + apr_port_t port, const char* proto, + const char *scope_id, void *slave, +@@ -529,7 +655,7 @@ static int open_listeners(apr_pool_t *pool) + } + } + #endif +- if (make_sock(pool, lr) == APR_SUCCESS) { ++ if (make_sock(pool, lr, 1) == APR_SUCCESS) { + ++num_open; + } + else { +@@ -641,8 +767,28 @@ AP_DECLARE(int) ap_setup_listeners(server_rec *s) + } + } + +- if (open_listeners(s->process->pool)) { +- return 0; ++#ifdef HAVE_SYSTEMD ++ if (use_systemd) { ++ const char *userdata_key = "ap_open_systemd_listeners"; ++ void *data; ++ /* clear the enviroment on our second run ++ * so that none of our future children get confused. ++ */ ++ apr_pool_userdata_get(&data, userdata_key, s->process->pool); ++ if (!data) { ++ apr_pool_userdata_set((const void *)1, userdata_key, ++ apr_pool_cleanup_null, s->process->pool); ++ } ++ else { ++ sd_listen_fds(1); ++ } ++ } ++ else ++#endif ++ { ++ if (open_listeners(s->process->pool)) { ++ return 0; ++ } + } + + for (lr = ap_listeners; lr; lr = lr->next) { +@@ -732,7 +878,7 @@ AP_DECLARE(apr_status_t) ap_duplicate_listeners(apr_pool_t *p, server_rec *s, + duplr->bind_addr); + return stat; + } +- make_sock(p, duplr); ++ make_sock(p, duplr, 1); + #if AP_NONBLOCK_WHEN_MULTI_LISTEN + use_nonblock = (ap_listeners && ap_listeners->next); + stat = apr_socket_opt_set(duplr->sd, APR_SO_NONBLOCK, use_nonblock); +@@ -859,6 +1005,11 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, + if (argc < 1 || argc > 2) { + return "Listen requires 1 or 2 arguments."; + } ++#ifdef HAVE_SYSTEMD ++ if (use_systemd == -1) { ++ use_systemd = sd_listen_fds(0) > 0; ++ } ++#endif + + rv = apr_parse_addr_port(&host, &scope_id, &port, argv[0], cmd->pool); + if (rv != APR_SUCCESS) { +@@ -894,6 +1045,12 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, + ap_str_tolower(proto); + } + ++#ifdef HAVE_SYSTEMD ++ if (use_systemd) { ++ return set_systemd_listener(cmd->server->process, port, proto); ++ } ++#endif ++ + return alloc_listener(cmd->server->process, host, port, proto, + scope_id, NULL, cmd->temp_pool); + } diff --git a/httpd-2.4.62.tar.bz2 b/httpd-2.4.62.tar.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..fa3f2c8eae9c4fb2bb5ecc2568dadce757a509f3 Binary files /dev/null and b/httpd-2.4.62.tar.bz2 differ diff --git a/httpd-2.4.62.tar.bz2.asc b/httpd-2.4.62.tar.bz2.asc new file mode 100644 index 0000000000000000000000000000000000000000..be203e8b38c4151c9abe4160c9914df36ce142f9 --- /dev/null +++ b/httpd-2.4.62.tar.bz2.asc @@ -0,0 +1,16 @@ +-----BEGIN PGP SIGNATURE----- + +iQIzBAABCgAdFiEEZbLUT+dL1ePeOsPwgngd5G1ZVPoFAmaVEjgACgkQgngd5G1Z +VPqlUA//dMZ01CalmRf4Li2gDH+ETlQXkMST+2IYNCWZzV78g5wfjpZtApKOk+6O +73WxdNSvnB15CJVIi/wXN/8ZQHu3u9kHCHw+ydDhOq7CiSAe1x5k0PcodR+me299 +PErBiAaBct+oJOnPCRdw5c5g3jomZgg1Nt5xS5NmI83UnbT9KHd92nNFdIjp6nFE +mKzsQSWSSXkObj83inJ3HvT8ALGr5TpMjHSJAC/YP9B9FuTW4lQh0XFEESz6LcR/ +Z8GWAV0qfauRhNYcp5qYcVdreVAk0J9vfnruv9OdYsMI/sDM2PYAyDk9pCMuVIfv +PuZd8n/EpMuQfeWBOLzkft2TjNYx0UAt0xLK0/FLQqbZSKgCxce3mnbm0N3qXl8h +OpWYC86h4y4shaBOCAHI4oqRFbIlbf9bssMRSYfBYTJ1k8zmADWAhIsr5276A33G +S8Z+Ah1XeYkvy1blSJDRqECAPLtAXgesLadpkTKTwu+9BmHXYllSmfdhW8D3v6SA +Ab7RMonp7poBexO0o0mm14cEAwetffUhSrFfvGp7sTBjQYH3s309HtRBuLJOwmP2 +uZvAKo84nJVaZIe7TTjpA/om7sq08Jq8xdzGbEhfGnOrtg/34d3K5S9tDvBMkmDq +HfYjFxCmfTbUDy4nqVNZcwno6jApweon+KAHbG/vJ2uMWozn2Bo= +=Lelg +-----END PGP SIGNATURE----- diff --git a/httpd.spec b/httpd.spec index fe42e09fa0965cc68b8bba93baa8c5a71da78f64..81bb18959658e64e5a5b816718fc6dd51500a3b6 100644 --- a/httpd.spec +++ b/httpd.spec @@ -1,4 +1,4 @@ -%define anolis_release 1 +%define anolis_release 2 %define contentdir %{_datadir}/%{name} %define docroot /var/www %define suexec_caller apache @@ -14,7 +14,7 @@ Summary: Apache HTTP Server Name: httpd -Version: 2.4.64 +Version: 2.4.64 Release: %{anolis_release}%{?dist} License: ASL 2.0 URL: https://httpd.apache.org/ @@ -80,6 +80,22 @@ Patch0023: httpd-2.4.64-r1927270.patch # modify for anolis Patch1000: 1000-httpd-anolis-rebrand.patch +Patch1001: httpd-2.4.62-engine-fallback.patch +Patch1002: httpd-2.4.57-r1912477+.patch +Patch1003: httpd-2.4.62-r1921299.patch +Patch1004: httpd-2.4.59-deplibs.patch +Patch1005: httpd-2.4.62-freebind.patch +Patch1006: httpd-2.4.62-r1922080.patch +Patch1007: httpd-2.4.48-export.patch +Patch1008: httpd-2.4.62-socket-activation.patch +Patch1009: httpd-2.4.57-selinux.patch +Patch1010: httpd-2.4.62-r1926064.patch +Patch1011: httpd-2.4.43-sslprotdefault.patch +Patch1012: httpd-2.4.62-r1919325.patch +Patch1013: httpd-2.4.62-r1926317.patch +Patch1014: httpd-2.4.48-full-release.patch +Patch1015: httpd-2.4.43-mod_systemd.patch +Patch1016: httpd-2.4.48-proxy-ws-idle-timeout.patch BuildRequires: gcc > 12.0 @@ -179,6 +195,8 @@ Requires: %{name} = 0:%{version}-%{release} Requires: %{name}-mmn = %{mmnisa} BuildRequires: libxml2-devel BuildRequires: make +BuildRequires: 5.0 +BuildRequires: systemd-devel Obsoletes: mod_proxy_html < 1:2.4.1 %description -n mod_proxy_html @@ -755,6 +773,9 @@ exit $rv %changelog +* Fri Aug 29 2025 zhoujiajia111 - 2.4.64-2 +- Fix URI escaping issues, prevent proxy errors, and ensure safe, predictable URL handling in mod_rewrite and mod_proxy. +- Fix connection reuse regression, ensure consistent socket closure on failure. * Fri Aug 22 2025 wenxin - 2.4.64-1 - update to 2.4.64 to fix cves - fix CVE-2024-43204