From: Raphaël Gertz Date: Fri, 17 Jun 2016 21:06:34 +0000 (+0200) Subject: Initial import X-Git-Tag: 2.4.38-6~26 X-Git-Url: https://git.rapsys.eu/ihttpd/commitdiff_plain/034a5b59d291e9a01cc9fd6c77aeb1019174e5c6 Initial import --- 034a5b59d291e9a01cc9fd6c77aeb1019174e5c6 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bc67114 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +BUILD +BUILDROOT +RPMS +SRPMS +tmp diff --git a/SOURCES/httpd-2.4.1-apctl.patch b/SOURCES/httpd-2.4.1-apctl.patch new file mode 100644 index 0000000..b31c3c5 --- /dev/null +++ b/SOURCES/httpd-2.4.1-apctl.patch @@ -0,0 +1,94 @@ + +- fail gracefully if links is not installed on target system +- source sysconfig/httpd for custom env. vars etc. +- make httpd -t work even in SELinux +- pass $OPTIONS to all $HTTPD invocation + +Upstream-HEAD: vendor +Upstream-2.0: vendor +Upstream-Status: Vendor-specific changes for better initscript integration + +--- httpd-2.4.1/support/apachectl.in.apctl ++++ httpd-2.4.1/support/apachectl.in +@@ -44,19 +44,25 @@ ARGV="$@" + # the path to your httpd binary, including options if necessary + HTTPD='@exp_sbindir@/@progname@' + # +-# pick up any necessary environment variables +-if test -f @exp_sbindir@/envvars; then +- . @exp_sbindir@/envvars +-fi + # + # a command that outputs a formatted text version of the HTML at the + # url given on the command line. Designed for lynx, however other + # programs may work. +-LYNX="@LYNX_PATH@ -dump" ++if [ -x "@LYNX_PATH@" ]; then ++ LYNX="@LYNX_PATH@ -dump" ++else ++ LYNX=none ++fi + # + # the URL to your server's mod_status status page. If you do not + # have one, then status and fullstatus will not work. + STATUSURL="http://localhost:@PORT@/server-status" ++ ++# Source /etc/sysconfig/httpd for $HTTPD setting, etc. ++if [ -r /etc/sysconfig/httpd ]; then ++ . /etc/sysconfig/httpd ++fi ++ + # + # Set this variable to a command that increases the maximum + # number of file descriptors allowed per child process. This is +@@ -76,9 +82,27 @@ if [ "x$ARGV" = "x" ] ; then + ARGV="-h" + fi + ++function checklynx() { ++if [ "$LYNX" = "none" ]; then ++ echo "The 'links' package is required for this functionality." ++ exit 8 ++fi ++} ++ ++function testconfig() { ++# httpd is denied terminal access in SELinux, so run in the ++# current context to get stdout from $HTTPD -t. ++if test -x /usr/sbin/selinuxenabled && /usr/sbin/selinuxenabled; then ++ runcon -- `id -Z` $HTTPD $OPTIONS -t ++else ++ $HTTPD $OPTIONS -t ++fi ++ERROR=$? ++} ++ + case $ACMD in + start|stop|restart|graceful|graceful-stop) +- $HTTPD -k $ARGV ++ $HTTPD $OPTIONS -k $ARGV + ERROR=$? + ;; + startssl|sslstart|start-SSL) +@@ -88,17 +112,18 @@ startssl|sslstart|start-SSL) + ERROR=2 + ;; + configtest) +- $HTTPD -t +- ERROR=$? ++ testconfig + ;; + status) ++ checklynx + $LYNX $STATUSURL | awk ' /process$/ { print; exit } { print } ' + ;; + fullstatus) ++ checklynx + $LYNX $STATUSURL + ;; + *) +- $HTTPD "$@" ++ $HTTPD $OPTIONS "$@" + ERROR=$? + esac + diff --git a/SOURCES/httpd-2.4.1-corelimit.patch b/SOURCES/httpd-2.4.1-corelimit.patch new file mode 100644 index 0000000..96f8486 --- /dev/null +++ b/SOURCES/httpd-2.4.1-corelimit.patch @@ -0,0 +1,35 @@ + +Bump up the core size limit if CoreDumpDirectory is +configured. + +Upstream-Status: Was discussed but there are competing desires; + there are portability oddities here too. + +--- httpd-2.4.1/server/core.c.corelimit ++++ httpd-2.4.1/server/core.c +@@ -4433,6 +4433,25 @@ static int core_post_config(apr_pool_t * + } + apr_pool_cleanup_register(pconf, NULL, ap_mpm_end_gen_helper, + apr_pool_cleanup_null); ++ ++#ifdef RLIMIT_CORE ++ if (ap_coredumpdir_configured) { ++ struct rlimit lim; ++ ++ if (getrlimit(RLIMIT_CORE, &lim) == 0 && lim.rlim_cur == 0) { ++ lim.rlim_cur = lim.rlim_max; ++ if (setrlimit(RLIMIT_CORE, &lim) == 0) { ++ ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, ++ "core dump file size limit raised to %lu bytes", ++ lim.rlim_cur); ++ } else { ++ ap_log_error(APLOG_MARK, APLOG_NOTICE, errno, NULL, ++ "core dump file size is zero, setrlimit failed"); ++ } ++ } ++ } ++#endif ++ + return OK; + } + diff --git a/SOURCES/httpd-2.4.1-deplibs.patch b/SOURCES/httpd-2.4.1-deplibs.patch new file mode 100644 index 0000000..b73c21d --- /dev/null +++ b/SOURCES/httpd-2.4.1-deplibs.patch @@ -0,0 +1,19 @@ + +Link straight against .la files. + +Upstream-Status: vendor specific + +--- httpd-2.4.1/configure.in.deplibs ++++ httpd-2.4.1/configure.in +@@ -707,9 +707,9 @@ APACHE_HELP_STRING(--with-suexec-umask,u + + 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/SOURCES/httpd-2.4.10-detect-systemd.patch b/SOURCES/httpd-2.4.10-detect-systemd.patch new file mode 100644 index 0000000..a22178b --- /dev/null +++ b/SOURCES/httpd-2.4.10-detect-systemd.patch @@ -0,0 +1,48 @@ +diff --git a/acinclude.m4 b/acinclude.m4 +index 580eb4a..bd7e2c9 100644 +--- a/acinclude.m4 ++++ b/acinclude.m4 +@@ -594,6 +594,30 @@ AC_DEFUN(APACHE_CHECK_OPENSSL,[ + fi + ]) + ++AC_DEFUN(APACHE_CHECK_SYSTEMD, [ ++dnl Check for systemd support for listen.c's socket activation. ++case $host in ++*-linux-*) ++ if test -n "$PKGCONFIG" && $PKGCONFIG --exists libsystemd; then ++ SYSTEMD_LIBS=`$PKGCONFIG --libs libsystemd` ++ elif test -n "$PKGCONFIG" && $PKGCONFIG --exists libsystemd-daemon; then ++ SYSTEMD_LIBS=`$PKGCONFIG --libs libsystemd-daemon` ++ else ++ AC_CHECK_LIB(systemd-daemon, sd_notify, SYSTEMD_LIBS="-lsystemd-daemon") ++ fi ++ if test -n "$SYSTEMD_LIBS"; then ++ AC_CHECK_HEADERS(systemd/sd-daemon.h) ++ if test "${ac_cv_header_systemd_sd_daemon_h}" = "no" || test -z "${SYSTEMD_LIBS}"; then ++ AC_MSG_WARN([Your system does not support systemd.]) ++ else ++ APR_ADDTO(LIBS, [$SYSTEMD_LIBS]) ++ AC_DEFINE(HAVE_SYSTEMD, 1, [Define if systemd is supported]) ++ fi ++ fi ++ ;; ++esac ++]) ++ + dnl + dnl APACHE_EXPORT_ARGUMENTS + dnl Export (via APACHE_SUBST) the various path-related variables that +diff --git a/configure.in b/configure.in +index 19a5f88..f096de3 100644 +--- a/configure.in ++++ b/configure.in +@@ -509,6 +509,8 @@ if test "$ac_cv_struct_tm_gmtoff" = "yes"; then + AC_DEFINE(HAVE_GMTOFF, 1, [Define if struct tm has a tm_gmtoff field]) + fi + ++APACHE_CHECK_SYSTEMD ++ + dnl ## Set up any appropriate OS-specific environment variables for apachectl + + case $host in diff --git a/SOURCES/httpd-2.4.10-sigint.patch b/SOURCES/httpd-2.4.10-sigint.patch new file mode 100644 index 0000000..7574a9c --- /dev/null +++ b/SOURCES/httpd-2.4.10-sigint.patch @@ -0,0 +1,45 @@ +From 20656c3b77cc548b59fea3bde5e2b7705d71c427 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jan=20Kalu=C5=BEa?= +Date: Mon, 18 Aug 2014 07:43:43 +0000 +Subject: [PATCH] prefork: Ignore SIGINT in child. This fixes race-condition in + signals handling when httpd is runnning on foreground and user hits ctrl+c. + In this case, SIGINT is sent to all children followed by SIGTERM from the + main process, which interrupts the SIGINT handler and leads to inconsistency + (process freezes or crashes). + +git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1618555 13f79535-47bb-0310-9956-ffa450edef68 +--- + server/mpm/prefork/prefork.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/server/mpm/prefork/prefork.c b/server/mpm/prefork/prefork.c +index 8790ec0..d6c038b 100644 +--- a/server/mpm/prefork/prefork.c ++++ b/server/mpm/prefork/prefork.c +@@ -222,6 +222,9 @@ static void clean_child_exit(int code) + { + mpm_state = AP_MPMQ_STOPPING; + ++ apr_signal(SIGHUP, SIG_IGN); ++ apr_signal(SIGTERM, SIG_IGN); ++ + if (pchild) { + apr_pool_destroy(pchild); + } +@@ -817,6 +820,13 @@ static int make_child(server_rec *s, int slot) + */ + apr_signal(SIGHUP, just_die); + apr_signal(SIGTERM, just_die); ++ /* Ignore SIGINT in child. This fixes race-condition in signals ++ * handling when httpd is runnning on foreground and user hits ctrl+c. ++ * In this case, SIGINT is sent to all children followed by SIGTERM ++ * from the main process, which interrupts the SIGINT handler and ++ * leads to inconsistency. ++ */ ++ apr_signal(SIGINT, SIG_IGN); + /* The child process just closes listeners on AP_SIG_GRACEFUL. + * The pod is used for signalling the graceful restart. + */ +-- +2.0.4 + diff --git a/SOURCES/httpd-2.4.17-socket-activation.patch b/SOURCES/httpd-2.4.17-socket-activation.patch new file mode 100644 index 0000000..d5cbdf2 --- /dev/null +++ b/SOURCES/httpd-2.4.17-socket-activation.patch @@ -0,0 +1,301 @@ +diff --git a/server/listen.c b/server/listen.c +index 1d9be83..f5f7754 100644 +--- a/server/listen.c ++++ b/server/listen.c +@@ -34,6 +34,10 @@ + #include + #endif + ++#ifdef HAVE_SYSTEMD ++#include ++#endif ++ + /* we know core's module_index is 0 */ + #undef APLOG_MODULE_INDEX + #define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX +@@ -59,9 +63,12 @@ static int ap_listenbacklog; + static int ap_listencbratio; + static int send_buffer_size; + static int receive_buffer_size; ++#ifdef HAVE_SYSTEMD ++static int use_systemd = -1; ++#endif + + /* TODO: make_sock is just begging and screaming for APR abstraction */ +-static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server) ++static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server, int do_bind_listen) + { + apr_socket_t *s = server->sd; + int one = 1; +@@ -94,20 +101,6 @@ static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server) + return stat; + } + +-#if APR_HAVE_IPV6 +- if (server->bind_addr->family == APR_INET6) { +- stat = apr_socket_opt_set(s, APR_IPV6_V6ONLY, v6only_setting); +- if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) { +- ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p, APLOGNO(00069) +- "make_sock: for address %pI, apr_socket_opt_set: " +- "(IPV6_V6ONLY)", +- server->bind_addr); +- apr_socket_close(s); +- return stat; +- } +- } +-#endif +- + /* + * To send data over high bandwidth-delay connections at full + * speed we must force the TCP window to open wide enough to keep the +@@ -169,21 +162,37 @@ static apr_status_t make_sock(apr_pool_t *p, ap_listen_rec *server) + } + #endif + +- if ((stat = apr_socket_bind(s, server->bind_addr)) != APR_SUCCESS) { +- ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, stat, p, APLOGNO(00072) +- "make_sock: could not bind to address %pI", +- server->bind_addr); +- apr_socket_close(s); +- return stat; +- } ++ if (do_bind_listen) { ++#if APR_HAVE_IPV6 ++ if (server->bind_addr->family == APR_INET6) { ++ stat = apr_socket_opt_set(s, APR_IPV6_V6ONLY, v6only_setting); ++ if (stat != APR_SUCCESS && stat != APR_ENOTIMPL) { ++ ap_log_perror(APLOG_MARK, APLOG_CRIT, stat, p, APLOGNO(00069) ++ "make_sock: for address %pI, apr_socket_opt_set: " ++ "(IPV6_V6ONLY)", ++ server->bind_addr); ++ apr_socket_close(s); ++ return stat; ++ } ++ } ++#endif + +- if ((stat = apr_socket_listen(s, ap_listenbacklog)) != APR_SUCCESS) { +- ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_ERR, stat, p, APLOGNO(00073) +- "make_sock: unable to listen for connections " +- "on address %pI", +- server->bind_addr); +- apr_socket_close(s); +- return stat; ++ if ((stat = apr_socket_bind(s, server->bind_addr)) != APR_SUCCESS) { ++ ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_CRIT, stat, p, APLOGNO(00072) ++ "make_sock: could not bind to address %pI", ++ server->bind_addr); ++ apr_socket_close(s); ++ return stat; ++ } ++ ++ if ((stat = apr_socket_listen(s, ap_listenbacklog)) != APR_SUCCESS) { ++ ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_ERR, stat, p, APLOGNO(00073) ++ "make_sock: unable to listen for connections " ++ "on address %pI", ++ server->bind_addr); ++ apr_socket_close(s); ++ return stat; ++ } + } + + #ifdef WIN32 +@@ -277,6 +286,124 @@ static apr_status_t close_listeners_on_exec(void *v) + return APR_SUCCESS; + } + ++ ++#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, char *addr, + apr_port_t port, const char* proto, + void *slave) +@@ -479,7 +606,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 { +@@ -591,8 +718,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) { +@@ -682,7 +829,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); +@@ -809,6 +956,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) { +@@ -840,6 +992,12 @@ AP_DECLARE_NONSTD(const char *) ap_set_listener(cmd_parms *cmd, void *dummy, + ap_str_tolower(proto); + } + ++#ifdef HAVE_SYSTEMD ++ if (use_systemd) { ++ return set_systemd_listener(cmd->server->process, port, proto); ++ } ++#endif ++ + return alloc_listener(cmd->server->process, host, port, proto, NULL); + } + diff --git a/SOURCES/httpd-2.4.17-sslciphdefault.patch b/SOURCES/httpd-2.4.17-sslciphdefault.patch new file mode 100644 index 0000000..8efc461 --- /dev/null +++ b/SOURCES/httpd-2.4.17-sslciphdefault.patch @@ -0,0 +1,33 @@ + +https://bugzilla.redhat.com/show_bug.cgi?id=1109119 + +Don't prepend !aNULL etc if PROFILE= is used with SSLCipherSuite. + +--- httpd-2.4.17/modules/ssl/ssl_engine_config.c.sslciphdefault ++++ httpd-2.4.17/modules/ssl/ssl_engine_config.c +@@ -708,8 +708,10 @@ const char *ssl_cmd_SSLCipherSuite(cmd_p + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + SSLDirConfigRec *dc = (SSLDirConfigRec *)dcfg; + +- /* always disable null and export ciphers */ +- arg = apr_pstrcat(cmd->pool, arg, ":!aNULL:!eNULL:!EXP", NULL); ++ /* Disable null and export ciphers by default, except for PROFILE= ++ * configs where the parser doesn't cope. */ ++ if (strncmp(arg, "PROFILE=", 8) != 0) ++ arg = apr_pstrcat(cmd->pool, arg, ":!aNULL:!eNULL:!EXP", NULL); + + if (cmd->path) { + dc->szCipherSuite = arg; +@@ -1428,8 +1430,10 @@ const char *ssl_cmd_SSLProxyCipherSuite( + { + SSLSrvConfigRec *sc = mySrvConfig(cmd->server); + +- /* always disable null and export ciphers */ +- arg = apr_pstrcat(cmd->pool, arg, ":!aNULL:!eNULL:!EXP", NULL); ++ /* Disable null and export ciphers by default, except for PROFILE= ++ * configs where the parser doesn't cope. */ ++ if (strncmp(arg, "PROFILE=", 8) != 0) ++ arg = apr_pstrcat(cmd->pool, arg, ":!aNULL:!eNULL:!EXP", NULL); + + sc->proxy->auth.cipher_suite = arg; + diff --git a/SOURCES/httpd-2.4.18-sslmultiproxy.patch b/SOURCES/httpd-2.4.18-sslmultiproxy.patch new file mode 100644 index 0000000..3f00f3f --- /dev/null +++ b/SOURCES/httpd-2.4.18-sslmultiproxy.patch @@ -0,0 +1,98 @@ +diff --git a/modules/ssl/mod_ssl.c b/modules/ssl/mod_ssl.c +index 717a694..a3ce718 100644 +--- a/modules/ssl/mod_ssl.c ++++ b/modules/ssl/mod_ssl.c +@@ -395,6 +395,9 @@ static SSLConnRec *ssl_init_connection_ctx(conn_rec *c) + return sslconn; + } + ++static typeof(ssl_proxy_enable) *othermod_proxy_enable; ++static typeof(ssl_engine_disable) *othermod_engine_disable; ++ + int ssl_proxy_enable(conn_rec *c) + { + SSLSrvConfigRec *sc; +@@ -403,6 +406,12 @@ int ssl_proxy_enable(conn_rec *c) + sc = mySrvConfig(sslconn->server); + + if (!sc->proxy_enabled) { ++ if (othermod_proxy_enable) { ++ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, ++ "mod_ssl proxy not configured, passing through to other module."); ++ return othermod_proxy_enable(c); ++ } ++ + ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(01961) + "SSL Proxy requested for %s but not enabled " + "[Hint: SSLProxyEngine]", sc->vhost_id); +@@ -422,6 +431,10 @@ int ssl_engine_disable(conn_rec *c) + + SSLConnRec *sslconn = myConnConfig(c); + ++ if (othermod_engine_disable) { ++ othermod_engine_disable(c); ++ } ++ + if (sslconn) { + sc = mySrvConfig(sslconn->server); + } +@@ -621,6 +634,9 @@ static void ssl_register_hooks(apr_pool_t *p) + ap_hook_post_read_request(ssl_hook_ReadReq, pre_prr,NULL, APR_HOOK_MIDDLE); + + ssl_var_register(p); ++ ++ othermod_proxy_enable = APR_RETRIEVE_OPTIONAL_FN(ssl_proxy_enable); ++ othermod_engine_disable = APR_RETRIEVE_OPTIONAL_FN(ssl_engine_disable); + + APR_REGISTER_OPTIONAL_FN(ssl_proxy_enable); + APR_REGISTER_OPTIONAL_FN(ssl_engine_disable); +diff --git a/modules/ssl/ssl_engine_vars.c b/modules/ssl/ssl_engine_vars.c +index a6b0d0d..24fd8c7 100644 +--- a/modules/ssl/ssl_engine_vars.c ++++ b/modules/ssl/ssl_engine_vars.c +@@ -54,6 +54,8 @@ static char *ssl_var_lookup_ssl_cipher(apr_pool_t *p, SSLConnRec *sslconn, char + static void ssl_var_lookup_ssl_cipher_bits(SSL *ssl, int *usekeysize, int *algkeysize); + static char *ssl_var_lookup_ssl_version(apr_pool_t *p, char *var); + static char *ssl_var_lookup_ssl_compress_meth(SSL *ssl); ++static APR_OPTIONAL_FN_TYPE(ssl_is_https) *othermod_is_https; ++static APR_OPTIONAL_FN_TYPE(ssl_var_lookup) *othermod_var_lookup; + + static SSLConnRec *ssl_get_effective_config(conn_rec *c) + { +@@ -68,7 +70,9 @@ static SSLConnRec *ssl_get_effective_config(conn_rec *c) + static int ssl_is_https(conn_rec *c) + { + SSLConnRec *sslconn = ssl_get_effective_config(c); +- return sslconn && sslconn->ssl; ++ ++ return (sslconn && sslconn->ssl) ++ || (othermod_is_https && othermod_is_https(c)); + } + + static const char var_interface[] = "mod_ssl/" AP_SERVER_BASEREVISION; +@@ -137,6 +141,9 @@ void ssl_var_register(apr_pool_t *p) + { + char *cp, *cp2; + ++ othermod_is_https = APR_RETRIEVE_OPTIONAL_FN(ssl_is_https); ++ othermod_var_lookup = APR_RETRIEVE_OPTIONAL_FN(ssl_var_lookup); ++ + APR_REGISTER_OPTIONAL_FN(ssl_is_https); + APR_REGISTER_OPTIONAL_FN(ssl_var_lookup); + APR_REGISTER_OPTIONAL_FN(ssl_ext_list); +@@ -272,6 +279,15 @@ char *ssl_var_lookup(apr_pool_t *p, server_rec *s, conn_rec *c, request_rec *r, + */ + if (result == NULL && c != NULL) { + SSLConnRec *sslconn = ssl_get_effective_config(c); ++ ++ if (strlen(var) > 4 && strcEQn(var, "SSL_", 4) ++ && (!sslconn || !sslconn->ssl) && othermod_var_lookup) { ++ /* For an SSL_* variable, if mod_ssl is not enabled for ++ * this connection and another SSL module is present, pass ++ * through to that module. */ ++ return othermod_var_lookup(p, s, c, r, var); ++ } ++ + if (strlen(var) > 4 && strcEQn(var, "SSL_", 4) + && sslconn && sslconn->ssl) + result = ssl_var_lookup_ssl(p, sslconn, r, var+4); diff --git a/SOURCES/httpd-2.4.2-icons.patch b/SOURCES/httpd-2.4.2-icons.patch new file mode 100644 index 0000000..9f26494 --- /dev/null +++ b/SOURCES/httpd-2.4.2-icons.patch @@ -0,0 +1,25 @@ + +- Fix config for /icons/ dir to allow symlink to poweredby.png. + +- Avoid using coredump GIF for a directory called "core" + +--- httpd-2.4.2/docs/conf/extra/httpd-autoindex.conf.in.icons ++++ httpd-2.4.2/docs/conf/extra/httpd-autoindex.conf.in +@@ -21,7 +21,7 @@ IndexOptions FancyIndexing HTMLTable Ver + Alias /icons/ "@exp_iconsdir@/" + + +- Options Indexes MultiViews ++ Options Indexes MultiViews FollowSymlinks + AllowOverride None + Require all granted + +@@ -53,7 +53,7 @@ AddIcon /icons/dvi.gif .dvi + AddIcon /icons/uuencoded.gif .uu + AddIcon /icons/script.gif .conf .sh .shar .csh .ksh .tcl + AddIcon /icons/tex.gif .tex +-AddIcon /icons/bomb.gif core ++AddIcon /icons/bomb.gif core. + + AddIcon /icons/back.gif .. + AddIcon /icons/hand.right.gif README diff --git a/SOURCES/httpd-2.4.20.tar.bz2 b/SOURCES/httpd-2.4.20.tar.bz2 new file mode 100644 index 0000000..8d0b460 Binary files /dev/null and b/SOURCES/httpd-2.4.20.tar.bz2 differ diff --git a/SOURCES/httpd-2.4.3-apctl-systemd.patch b/SOURCES/httpd-2.4.3-apctl-systemd.patch new file mode 100644 index 0000000..5823aee --- /dev/null +++ b/SOURCES/httpd-2.4.3-apctl-systemd.patch @@ -0,0 +1,45 @@ + +Upstream-Status: vendor specific patch + +diff --git a/support/apachectl.in b/support/apachectl.in +index c6ac3ea..2599386 100644 +--- a/support/apachectl.in ++++ b/support/apachectl.in +@@ -100,9 +100,24 @@ fi + ERROR=$? + } + ++if [ "x$2" != "x" ] ; then ++ echo Passing arguments to httpd using apachectl is no longer supported. ++ echo You can only start/stop/restart httpd using this script. ++ echo If you want to pass extra arguments to httpd, edit the ++ echo /etc/sysconfig/httpd config file. ++fi ++ + case $ACMD in +-start|stop|restart|graceful|graceful-stop) +- $HTTPD $OPTIONS -k $ARGV ++start|stop|restart|status) ++ /usr/bin/systemctl $ACMD httpd.service ++ ERROR=$? ++ ;; ++graceful) ++ /usr/bin/systemctl reload httpd.service ++ ERROR=$? ++ ;; ++graceful-stop) ++ /usr/bin/systemctl stop httpd.service + ERROR=$? + ;; + startssl|sslstart|start-SSL) +@@ -114,10 +129,6 @@ startssl|sslstart|start-SSL) + configtest) + testconfig + ;; +-status) +- checklynx +- $LYNX $STATUSURL | awk ' /process$/ { print; exit } { print } ' +- ;; + fullstatus) + checklynx + $LYNX $STATUSURL diff --git a/SOURCES/httpd-2.4.3-release.patch b/SOURCES/httpd-2.4.3-release.patch new file mode 100644 index 0000000..0b2fb77 --- /dev/null +++ b/SOURCES/httpd-2.4.3-release.patch @@ -0,0 +1,16 @@ + +Upstream-HEAD: vendor +Upstream-2.0: vendor +Upstream-Status: vendor-specific change + +--- httpd-2.4.3/server/core.c.release ++++ httpd-2.4.3/server/core.c +@@ -3189,7 +3189,7 @@ static void set_banner(apr_pool_t *pconf + ap_add_version_component(pconf, AP_SERVER_BASEPRODUCT "/" AP_SERVER_MAJORVERSION); + } + else { +- ap_add_version_component(pconf, AP_SERVER_BASEVERSION " (" PLATFORM ")"); ++ ap_add_version_component(pconf, AP_SERVER_BASEVERSION " (@RELEASE@)"); + } + + /* diff --git a/SOURCES/httpd-2.4.4-cachehardmax.patch b/SOURCES/httpd-2.4.4-cachehardmax.patch new file mode 100644 index 0000000..de360ce --- /dev/null +++ b/SOURCES/httpd-2.4.4-cachehardmax.patch @@ -0,0 +1,82 @@ +diff --git a/modules/cache/cache_util.h b/modules/cache/cache_util.h +index eec38f3..1a2d5ee 100644 +--- a/modules/cache/cache_util.h ++++ b/modules/cache/cache_util.h +@@ -194,6 +194,9 @@ typedef struct { + unsigned int store_nostore_set:1; + unsigned int enable_set:1; + unsigned int disable_set:1; ++ /* treat maxex as hard limit */ ++ unsigned int hardmaxex:1; ++ unsigned int hardmaxex_set:1; + } cache_dir_conf; + + /* A linked-list of authn providers. */ +diff --git a/modules/cache/mod_cache.c b/modules/cache/mod_cache.c +index 4f2d3e0..30c88f4 100644 +--- a/modules/cache/mod_cache.c ++++ b/modules/cache/mod_cache.c +@@ -1299,6 +1299,11 @@ static apr_status_t cache_save_filter(ap_filter_t *f, apr_bucket_brigade *in) + exp = date + dconf->defex; + } + } ++ /* else, forcibly cap the expiry date if required */ ++ else if (dconf->hardmaxex && (date + dconf->maxex) < exp) { ++ exp = date + dconf->maxex; ++ } ++ + info->expire = exp; + + /* We found a stale entry which wasn't really stale. */ +@@ -1717,7 +1722,9 @@ static void *create_dir_config(apr_pool_t *p, char *dummy) + + /* array of providers for this URL space */ + dconf->cacheenable = apr_array_make(p, 10, sizeof(struct cache_enable)); +- ++ /* flag; treat maxex as hard limit */ ++ dconf->hardmaxex = 0; ++ dconf->hardmaxex_set = 0; + return dconf; + } + +@@ -1767,7 +1774,10 @@ static void *merge_dir_config(apr_pool_t *p, void *basev, void *addv) { + new->enable_set = add->enable_set || base->enable_set; + new->disable = (add->disable_set == 0) ? base->disable : add->disable; + new->disable_set = add->disable_set || base->disable_set; +- ++ new->hardmaxex = ++ (add->hardmaxex_set == 0) ++ ? base->hardmaxex ++ : add->hardmaxex; + return new; + } + +@@ -2096,12 +2106,18 @@ static const char *add_cache_disable(cmd_parms *parms, void *dummy, + } + + static const char *set_cache_maxex(cmd_parms *parms, void *dummy, +- const char *arg) ++ const char *arg, const char *hard) + { + cache_dir_conf *dconf = (cache_dir_conf *)dummy; + + dconf->maxex = (apr_time_t) (atol(arg) * MSEC_ONE_SEC); + dconf->maxex_set = 1; ++ ++ if (hard && strcasecmp(hard, "hard") == 0) { ++ dconf->hardmaxex = 1; ++ dconf->hardmaxex_set = 1; ++ } ++ + return NULL; + } + +@@ -2309,7 +2325,7 @@ static const command_rec cache_cmds[] = + "caching is enabled"), + AP_INIT_TAKE1("CacheDisable", add_cache_disable, NULL, RSRC_CONF|ACCESS_CONF, + "A partial URL prefix below which caching is disabled"), +- AP_INIT_TAKE1("CacheMaxExpire", set_cache_maxex, NULL, RSRC_CONF|ACCESS_CONF, ++ AP_INIT_TAKE12("CacheMaxExpire", set_cache_maxex, NULL, RSRC_CONF|ACCESS_CONF, + "The maximum time in seconds to cache a document"), + AP_INIT_TAKE1("CacheMinExpire", set_cache_minex, NULL, RSRC_CONF|ACCESS_CONF, + "The minimum time in seconds to cache a document"), diff --git a/SOURCES/httpd-2.4.4-export.patch b/SOURCES/httpd-2.4.4-export.patch new file mode 100644 index 0000000..eb670c6 --- /dev/null +++ b/SOURCES/httpd-2.4.4-export.patch @@ -0,0 +1,20 @@ + +There is no need to "suck in" the apr/apr-util symbols when using +a shared libapr{,util}, it just bloats the symbol table; so don't. + +Upstream-HEAD: needed +Upstream-2.0: omit +Upstream-Status: EXPORT_DIRS change is conditional on using shared apr + +--- httpd-2.4.4/server/Makefile.in.export ++++ httpd-2.4.4/server/Makefile.in +@@ -57,9 +57,6 @@ export_files: + ( for dir in $(EXPORT_DIRS); do \ + ls $$dir/*.h ; \ + done; \ +- for dir in $(EXPORT_DIRS_APR); do \ +- ls $$dir/ap[ru].h $$dir/ap[ru]_*.h 2>/dev/null; \ +- done; \ + ) | sed -e s,//,/,g | sort -u > $@ + + exports.c: export_files diff --git a/SOURCES/httpd-2.4.4-malformed-host.patch b/SOURCES/httpd-2.4.4-malformed-host.patch new file mode 100644 index 0000000..57975e5 --- /dev/null +++ b/SOURCES/httpd-2.4.4-malformed-host.patch @@ -0,0 +1,12 @@ +diff --git a/server/protocol.c b/server/protocol.c +index e1ef204..d6d9165 100644 +--- a/server/protocol.c ++++ b/server/protocol.c +@@ -1049,6 +1049,7 @@ request_rec *ap_read_request(conn_rec *conn) + * now read. may update status. + */ + ap_update_vhost_from_headers(r); ++ access_status = r->status; + + /* Toggle to the Host:-based vhost's timeout mode to fetch the + * request body and send the response body, if needed. diff --git a/SOURCES/httpd-2.4.4-mod_unique_id.patch b/SOURCES/httpd-2.4.4-mod_unique_id.patch new file mode 100644 index 0000000..30bdfe0 --- /dev/null +++ b/SOURCES/httpd-2.4.4-mod_unique_id.patch @@ -0,0 +1,239 @@ +--- trunk/modules/metadata/mod_unique_id.c 2011/12/02 23:02:04 1209766 ++++ trunk/modules/metadata/mod_unique_id.c 2013/07/10 16:20:31 1501827 +@@ -31,14 +31,11 @@ + #include "http_log.h" + #include "http_protocol.h" /* for ap_hook_post_read_request */ + +-#if APR_HAVE_UNISTD_H +-#include /* for getpid() */ +-#endif ++#define ROOT_SIZE 10 + + typedef struct { + unsigned int stamp; +- unsigned int in_addr; +- unsigned int pid; ++ char root[ROOT_SIZE]; + unsigned short counter; + unsigned int thread_index; + } unique_id_rec; +@@ -64,20 +61,15 @@ + * gethostbyname (gethostname()) is unique across all the machines at the + * "site". + * +- * We also further assume that pids fit in 32-bits. If something uses more +- * than 32-bits, the fix is trivial, but it requires the unrolled uuencoding +- * loop to be extended. * A similar fix is needed to support multithreaded +- * servers, using a pid/tid combo. +- * +- * Together, the in_addr and pid are assumed to absolutely uniquely identify +- * this one child from all other currently running children on all servers +- * (including this physical server if it is running multiple httpds) from each ++ * The root is assumed to absolutely uniquely identify this one child ++ * from all other currently running children on all servers (including ++ * this physical server if it is running multiple httpds) from each + * other. + * +- * The stamp and counter are used to distinguish all hits for a particular +- * (in_addr,pid) pair. The stamp is updated using r->request_time, +- * saving cpu cycles. The counter is never reset, and is used to permit up to +- * 64k requests in a single second by a single child. ++ * The stamp and counter are used to distinguish all hits for a ++ * particular root. The stamp is updated using r->request_time, ++ * saving cpu cycles. The counter is never reset, and is used to ++ * permit up to 64k requests in a single second by a single child. + * + * The 144-bits of unique_id_rec are encoded using the alphabet + * [A-Za-z0-9@-], resulting in 24 bytes of printable characters. That is then +@@ -92,7 +84,7 @@ + * module change. + * + * It is highly desirable that identifiers exist for "eternity". But future +- * needs (such as much faster webservers, moving to 64-bit pids, or moving to a ++ * needs (such as much faster webservers, or moving to a + * multithreaded server) may dictate a need to change the contents of + * unique_id_rec. Such a future implementation should ensure that the first + * field is still a time_t stamp. By doing that, it is possible for a site to +@@ -100,7 +92,15 @@ + * wait one entire second, and then start all of their new-servers. This + * procedure will ensure that the new space of identifiers is completely unique + * from the old space. (Since the first four unencoded bytes always differ.) ++ * ++ * Note: previous implementations used 32-bits of IP address plus pid ++ * in place of the PRNG output in the "root" field. This was ++ * insufficient for IPv6-only hosts, required working DNS to determine ++ * a unique IP address (fragile), and needed a [0, 1) second sleep ++ * call at startup to avoid pid reuse. Use of the PRNG avoids all ++ * these issues. + */ ++ + /* + * Sun Jun 7 05:43:49 CEST 1998 -- Alvaro + * More comments: +@@ -116,8 +116,6 @@ + * htonl/ntohl. Well, this shouldn't be a problem till year 2106. + */ + +-static unsigned global_in_addr; +- + /* + * XXX: We should have a per-thread counter and not use cur_unique_id.counter + * XXX: in all threads, because this is bad for performance on multi-processor +@@ -129,7 +127,7 @@ + /* + * Number of elements in the structure unique_id_rec. + */ +-#define UNIQUE_ID_REC_MAX 5 ++#define UNIQUE_ID_REC_MAX 4 + + static unsigned short unique_id_rec_offset[UNIQUE_ID_REC_MAX], + unique_id_rec_size[UNIQUE_ID_REC_MAX], +@@ -138,113 +136,32 @@ + + static int unique_id_global_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *main_server) + { +- char str[APRMAXHOSTLEN + 1]; +- apr_status_t rv; +- char *ipaddrstr; +- apr_sockaddr_t *sockaddr; +- + /* + * Calculate the sizes and offsets in cur_unique_id. + */ + unique_id_rec_offset[0] = APR_OFFSETOF(unique_id_rec, stamp); + unique_id_rec_size[0] = sizeof(cur_unique_id.stamp); +- unique_id_rec_offset[1] = APR_OFFSETOF(unique_id_rec, in_addr); +- unique_id_rec_size[1] = sizeof(cur_unique_id.in_addr); +- unique_id_rec_offset[2] = APR_OFFSETOF(unique_id_rec, pid); +- unique_id_rec_size[2] = sizeof(cur_unique_id.pid); +- unique_id_rec_offset[3] = APR_OFFSETOF(unique_id_rec, counter); +- unique_id_rec_size[3] = sizeof(cur_unique_id.counter); +- unique_id_rec_offset[4] = APR_OFFSETOF(unique_id_rec, thread_index); +- unique_id_rec_size[4] = sizeof(cur_unique_id.thread_index); ++ unique_id_rec_offset[1] = APR_OFFSETOF(unique_id_rec, root); ++ unique_id_rec_size[1] = sizeof(cur_unique_id.root); ++ unique_id_rec_offset[2] = APR_OFFSETOF(unique_id_rec, counter); ++ unique_id_rec_size[2] = sizeof(cur_unique_id.counter); ++ unique_id_rec_offset[3] = APR_OFFSETOF(unique_id_rec, thread_index); ++ unique_id_rec_size[3] = sizeof(cur_unique_id.thread_index); + unique_id_rec_total_size = unique_id_rec_size[0] + unique_id_rec_size[1] + +- unique_id_rec_size[2] + unique_id_rec_size[3] + +- unique_id_rec_size[4]; ++ unique_id_rec_size[2] + unique_id_rec_size[3]; + + /* + * Calculate the size of the structure when encoded. + */ + unique_id_rec_size_uu = (unique_id_rec_total_size*8+5)/6; + +- /* +- * Now get the global in_addr. Note that it is not sufficient to use one +- * of the addresses from the main_server, since those aren't as likely to +- * be unique as the physical address of the machine +- */ +- if ((rv = apr_gethostname(str, sizeof(str) - 1, p)) != APR_SUCCESS) { +- ap_log_error(APLOG_MARK, APLOG_ALERT, rv, main_server, APLOGNO(01563) +- "unable to find hostname of the server"); +- return HTTP_INTERNAL_SERVER_ERROR; +- } +- +- if ((rv = apr_sockaddr_info_get(&sockaddr, str, AF_INET, 0, 0, p)) == APR_SUCCESS) { +- global_in_addr = sockaddr->sa.sin.sin_addr.s_addr; +- } +- else { +- ap_log_error(APLOG_MARK, APLOG_ALERT, rv, main_server, APLOGNO(01564) +- "unable to find IPv4 address of \"%s\"", str); +-#if APR_HAVE_IPV6 +- if ((rv = apr_sockaddr_info_get(&sockaddr, str, AF_INET6, 0, 0, p)) == APR_SUCCESS) { +- memcpy(&global_in_addr, +- (char *)sockaddr->ipaddr_ptr + sockaddr->ipaddr_len - sizeof(global_in_addr), +- sizeof(global_in_addr)); +- ap_log_error(APLOG_MARK, APLOG_ALERT, rv, main_server, APLOGNO(01565) +- "using low-order bits of IPv6 address " +- "as if they were unique"); +- } +- else +-#endif +- return HTTP_INTERNAL_SERVER_ERROR; +- } +- +- apr_sockaddr_ip_get(&ipaddrstr, sockaddr); +- ap_log_error(APLOG_MARK, APLOG_INFO, 0, main_server, APLOGNO(01566) "using ip addr %s", +- ipaddrstr); +- +- /* +- * If the server is pummelled with restart requests we could possibly end +- * up in a situation where we're starting again during the same second +- * that has been used in previous identifiers. Avoid that situation. +- * +- * In truth, for this to actually happen not only would it have to restart +- * in the same second, but it would have to somehow get the same pids as +- * one of the other servers that was running in that second. Which would +- * mean a 64k wraparound on pids ... not very likely at all. +- * +- * But protecting against it is relatively cheap. We just sleep into the +- * next second. +- */ +- apr_sleep(apr_time_from_sec(1) - apr_time_usec(apr_time_now())); + return OK; + } + + static void unique_id_child_init(apr_pool_t *p, server_rec *s) + { +- pid_t pid; +- +- /* +- * Note that we use the pid because it's possible that on the same +- * physical machine there are multiple servers (i.e. using Listen). But +- * it's guaranteed that none of them will share the same pids between +- * children. +- * +- * XXX: for multithread this needs to use a pid/tid combo and probably +- * needs to be expanded to 32 bits +- */ +- pid = getpid(); +- cur_unique_id.pid = pid; +- +- /* +- * Test our assumption that the pid is 32-bits. It's possible that +- * 64-bit machines will declare pid_t to be 64 bits but only use 32 +- * of them. It would have been really nice to test this during +- * global_init ... but oh well. +- */ +- if ((pid_t)cur_unique_id.pid != pid) { +- ap_log_error(APLOG_MARK, APLOG_CRIT, 0, s, APLOGNO(01567) +- "oh no! pids are greater than 32-bits! I'm broken!"); +- } +- +- cur_unique_id.in_addr = global_in_addr; ++ ap_random_insecure_bytes(&cur_unique_id.root, ++ sizeof(cur_unique_id.root)); + + /* + * If we use 0 as the initial counter we have a little less protection +@@ -253,13 +170,6 @@ + */ + ap_random_insecure_bytes(&cur_unique_id.counter, + sizeof(cur_unique_id.counter)); +- +- /* +- * We must always use network ordering for these bytes, so that +- * identifiers are comparable between machines of different byte +- * orderings. Note in_addr is already in network order. +- */ +- cur_unique_id.pid = htonl(cur_unique_id.pid); + } + + /* NOTE: This is *NOT* the same encoding used by base64encode ... the last two +@@ -291,10 +201,8 @@ + unsigned short counter; + int i,j,k; + +- new_unique_id.in_addr = cur_unique_id.in_addr; +- new_unique_id.pid = cur_unique_id.pid; ++ memcpy(&new_unique_id.root, &cur_unique_id.root, ROOT_SIZE); + new_unique_id.counter = cur_unique_id.counter; +- + new_unique_id.stamp = htonl((unsigned int)apr_time_sec(r->request_time)); + new_unique_id.thread_index = htonl((unsigned int)r->connection->id); + diff --git a/SOURCES/httpd-2.4.4-r1332643+.patch b/SOURCES/httpd-2.4.4-r1332643+.patch new file mode 100644 index 0000000..849f6d0 --- /dev/null +++ b/SOURCES/httpd-2.4.4-r1332643+.patch @@ -0,0 +1,248 @@ +# ./pullrev.sh 1332643 1345599 + +https://bugzilla.redhat.com//show_bug.cgi?id=809599 + +http://svn.apache.org/viewvc?view=revision&revision=1332643 + +http://svn.apache.org/viewvc?view=revision&revision=1345599 + +--- httpd-2.4.4/modules/ssl/mod_ssl.c.r1332643+ ++++ httpd-2.4.4/modules/ssl/mod_ssl.c +@@ -272,6 +272,18 @@ static const command_rec ssl_config_cmds + AP_END_CMD + }; + ++/* Implement 'modssl_run_npn_advertise_protos_hook'. */ ++APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL( ++ modssl, AP, int, npn_advertise_protos_hook, ++ (conn_rec *connection, apr_array_header_t *protos), ++ (connection, protos), OK, DECLINED); ++ ++/* Implement 'modssl_run_npn_proto_negotiated_hook'. */ ++APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL( ++ modssl, AP, int, npn_proto_negotiated_hook, ++ (conn_rec *connection, const char *proto_name, apr_size_t proto_name_len), ++ (connection, proto_name, proto_name_len), OK, DECLINED); ++ + /* + * the various processing hooks + */ +--- httpd-2.4.4/modules/ssl/mod_ssl.h.r1332643+ ++++ httpd-2.4.4/modules/ssl/mod_ssl.h +@@ -63,5 +63,26 @@ APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_e + + APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *)); + ++/** The npn_advertise_protos optional hook allows other modules to add entries ++ * to the list of protocol names advertised by the server during the Next ++ * Protocol Negotiation (NPN) portion of the SSL handshake. The hook callee is ++ * given the connection and an APR array; it should push one or more char*'s ++ * pointing to null-terminated strings (such as "http/1.1" or "spdy/2") onto ++ * the array and return OK, or do nothing and return DECLINED. */ ++APR_DECLARE_EXTERNAL_HOOK(modssl, AP, int, npn_advertise_protos_hook, ++ (conn_rec *connection, apr_array_header_t *protos)); ++ ++/** The npn_proto_negotiated optional hook allows other modules to discover the ++ * name of the protocol that was chosen during the Next Protocol Negotiation ++ * (NPN) portion of the SSL handshake. Note that this may be the empty string ++ * (in which case modules should probably assume HTTP), or it may be a protocol ++ * that was never even advertised by the server. The hook callee is given the ++ * connection, a non-null-terminated string containing the protocol name, and ++ * the length of the string; it should do something appropriate (i.e. insert or ++ * remove filters) and return OK, or do nothing and return DECLINED. */ ++APR_DECLARE_EXTERNAL_HOOK(modssl, AP, int, npn_proto_negotiated_hook, ++ (conn_rec *connection, const char *proto_name, ++ apr_size_t proto_name_len)); ++ + #endif /* __MOD_SSL_H__ */ + /** @} */ +--- httpd-2.4.4/modules/ssl/ssl_engine_init.c.r1332643+ ++++ httpd-2.4.4/modules/ssl/ssl_engine_init.c +@@ -725,6 +725,11 @@ static void ssl_init_ctx_callbacks(serve + #endif + + SSL_CTX_set_info_callback(ctx, ssl_callback_Info); ++ ++#ifdef HAVE_TLS_NPN ++ SSL_CTX_set_next_protos_advertised_cb( ++ ctx, ssl_callback_AdvertiseNextProtos, NULL); ++#endif + } + + static void ssl_init_ctx_verify(server_rec *s, +--- httpd-2.4.4/modules/ssl/ssl_engine_io.c.r1332643+ ++++ httpd-2.4.4/modules/ssl/ssl_engine_io.c +@@ -28,6 +28,7 @@ + core keeps dumping.'' + -- Unknown */ + #include "ssl_private.h" ++#include "mod_ssl.h" + #include "apr_date.h" + + /* _________________________________________________________________ +@@ -297,6 +298,7 @@ typedef struct { + apr_pool_t *pool; + char buffer[AP_IOBUFSIZE]; + ssl_filter_ctx_t *filter_ctx; ++ int npn_finished; /* 1 if NPN has finished, 0 otherwise */ + } bio_filter_in_ctx_t; + + /* +@@ -1385,6 +1387,26 @@ static apr_status_t ssl_io_filter_input( + APR_BRIGADE_INSERT_TAIL(bb, bucket); + } + ++#ifdef HAVE_TLS_NPN ++ /* By this point, Next Protocol Negotiation (NPN) should be completed (if ++ * our version of OpenSSL supports it). If we haven't already, find out ++ * which protocol was decided upon and inform other modules by calling ++ * npn_proto_negotiated_hook. */ ++ if (!inctx->npn_finished) { ++ const unsigned char *next_proto = NULL; ++ unsigned next_proto_len = 0; ++ ++ SSL_get0_next_proto_negotiated( ++ inctx->ssl, &next_proto, &next_proto_len); ++ ap_log_cerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, f->c, ++ APLOGNO(02306) "SSL NPN negotiated protocol: '%*s'", ++ next_proto_len, (const char*)next_proto); ++ modssl_run_npn_proto_negotiated_hook( ++ f->c, (const char*)next_proto, next_proto_len); ++ inctx->npn_finished = 1; ++ } ++#endif ++ + return APR_SUCCESS; + } + +@@ -1866,6 +1888,7 @@ static void ssl_io_input_add_filter(ssl_ + inctx->block = APR_BLOCK_READ; + inctx->pool = c->pool; + inctx->filter_ctx = filter_ctx; ++ inctx->npn_finished = 0; + } + + /* The request_rec pointer is passed in here only to ensure that the +--- httpd-2.4.4/modules/ssl/ssl_engine_kernel.c.r1332643+ ++++ httpd-2.4.4/modules/ssl/ssl_engine_kernel.c +@@ -29,6 +29,7 @@ + time I was too famous.'' + -- Unknown */ + #include "ssl_private.h" ++#include "mod_ssl.h" + #include "util_md5.h" + + static void ssl_configure_env(request_rec *r, SSLConnRec *sslconn); +@@ -2161,6 +2162,90 @@ int ssl_callback_SessionTicket(SSL *ssl, + } + #endif /* HAVE_TLS_SESSION_TICKETS */ + ++#ifdef HAVE_TLS_NPN ++/* ++ * This callback function is executed when SSL needs to decide what protocols ++ * to advertise during Next Protocol Negotiation (NPN). It must produce a ++ * string in wire format -- a sequence of length-prefixed strings -- indicating ++ * the advertised protocols. Refer to SSL_CTX_set_next_protos_advertised_cb ++ * in OpenSSL for reference. ++ */ ++int ssl_callback_AdvertiseNextProtos(SSL *ssl, const unsigned char **data_out, ++ unsigned int *size_out, void *arg) ++{ ++ conn_rec *c = (conn_rec*)SSL_get_app_data(ssl); ++ apr_array_header_t *protos; ++ int num_protos; ++ unsigned int size; ++ int i; ++ unsigned char *data; ++ unsigned char *start; ++ ++ *data_out = NULL; ++ *size_out = 0; ++ ++ /* If the connection object is not available, then there's nothing for us ++ * to do. */ ++ if (c == NULL) { ++ return SSL_TLSEXT_ERR_OK; ++ } ++ ++ /* Invoke our npn_advertise_protos hook, giving other modules a chance to ++ * add alternate protocol names to advertise. */ ++ protos = apr_array_make(c->pool, 0, sizeof(char*)); ++ modssl_run_npn_advertise_protos_hook(c, protos); ++ num_protos = protos->nelts; ++ ++ /* We now have a list of null-terminated strings; we need to concatenate ++ * them together into a single string, where each protocol name is prefixed ++ * by its length. First, calculate how long that string will be. */ ++ size = 0; ++ for (i = 0; i < num_protos; ++i) { ++ const char *string = APR_ARRAY_IDX(protos, i, const char*); ++ unsigned int length = strlen(string); ++ /* If the protocol name is too long (the length must fit in one byte), ++ * then log an error and skip it. */ ++ if (length > 255) { ++ ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(02307) ++ "SSL NPN protocol name too long (length=%u): %s", ++ length, string); ++ continue; ++ } ++ /* Leave room for the length prefix (one byte) plus the protocol name ++ * itself. */ ++ size += 1 + length; ++ } ++ ++ /* If there is nothing to advertise (either because no modules added ++ * anything to the protos array, or because all strings added to the array ++ * were skipped), then we're done. */ ++ if (size == 0) { ++ return SSL_TLSEXT_ERR_OK; ++ } ++ ++ /* Now we can build the string. Copy each protocol name string into the ++ * larger string, prefixed by its length. */ ++ data = apr_palloc(c->pool, size * sizeof(unsigned char)); ++ start = data; ++ for (i = 0; i < num_protos; ++i) { ++ const char *string = APR_ARRAY_IDX(protos, i, const char*); ++ apr_size_t length = strlen(string); ++ if (length > 255) ++ continue; ++ *start = (unsigned char)length; ++ ++start; ++ memcpy(start, string, length * sizeof(unsigned char)); ++ start += length; ++ } ++ ++ /* Success. */ ++ *data_out = data; ++ *size_out = size; ++ return SSL_TLSEXT_ERR_OK; ++} ++ ++#endif /* HAVE_TLS_NPN */ ++ + #ifndef OPENSSL_NO_SRP + + int ssl_callback_SRPServerParams(SSL *ssl, int *ad, void *arg) +--- httpd-2.4.4/modules/ssl/ssl_private.h.r1332643+ ++++ httpd-2.4.4/modules/ssl/ssl_private.h +@@ -139,6 +139,11 @@ + #define HAVE_FIPS + #endif + ++#if OPENSSL_VERSION_NUMBER >= 0x10001000L && !defined(OPENSSL_NO_NEXTPROTONEG) \ ++ && !defined(OPENSSL_NO_TLSEXT) ++#define HAVE_TLS_NPN ++#endif ++ + #if (OPENSSL_VERSION_NUMBER >= 0x10000000) + #define MODSSL_SSL_CIPHER_CONST const + #define MODSSL_SSL_METHOD_CONST const +@@ -840,6 +845,7 @@ int ssl_callback_ServerNameIndi + int ssl_callback_SessionTicket(SSL *, unsigned char *, unsigned char *, + EVP_CIPHER_CTX *, HMAC_CTX *, int); + #endif ++int ssl_callback_AdvertiseNextProtos(SSL *ssl, const unsigned char **data, unsigned int *len, void *arg); + + /** Session Cache Support */ + void ssl_scache_init(server_rec *, apr_pool_t *); diff --git a/SOURCES/httpd-2.4.4-r1337344+.patch b/SOURCES/httpd-2.4.4-r1337344+.patch new file mode 100644 index 0000000..6e5c3e7 --- /dev/null +++ b/SOURCES/httpd-2.4.4-r1337344+.patch @@ -0,0 +1,250 @@ +# ./pullrev.sh 1337344 1341905 1342065 1341930 + +suexec enhancements: + +1) use syslog for logging +2) use capabilities not setuid/setgid root binary + +http://svn.apache.org/viewvc?view=revision&revision=1337344 +http://svn.apache.org/viewvc?view=revision&revision=1341905 +http://svn.apache.org/viewvc?view=revision&revision=1342065 +http://svn.apache.org/viewvc?view=revision&revision=1341930 + +--- httpd-2.4.4/configure.in.r1337344+ ++++ httpd-2.4.4/configure.in +@@ -734,7 +734,24 @@ APACHE_HELP_STRING(--with-suexec-gidmin, + + AC_ARG_WITH(suexec-logfile, + APACHE_HELP_STRING(--with-suexec-logfile,Set the logfile),[ +- AC_DEFINE_UNQUOTED(AP_LOG_EXEC, "$withval", [SuExec log file] ) ] ) ++ if test "x$withval" = "xyes"; then ++ AC_DEFINE_UNQUOTED(AP_LOG_EXEC, "$withval", [SuExec log file]) ++ fi ++]) ++ ++AC_ARG_WITH(suexec-syslog, ++APACHE_HELP_STRING(--with-suexec-syslog,Set the logfile),[ ++ if test $withval = "yes"; then ++ if test "x${with_suexec_logfile}" != "xno"; then ++ AC_MSG_NOTICE([hint: use "--without-suexec-logfile --with-suexec-syslog"]) ++ AC_MSG_ERROR([suexec does not support both logging to file and syslog]) ++ fi ++ AC_CHECK_FUNCS([vsyslog], [], [ ++ AC_MSG_ERROR([cannot support syslog from suexec without vsyslog()])]) ++ AC_DEFINE(AP_LOG_SYSLOG, 1, [SuExec log to syslog]) ++ fi ++]) ++ + + AC_ARG_WITH(suexec-safepath, + APACHE_HELP_STRING(--with-suexec-safepath,Set the safepath),[ +@@ -744,6 +761,15 @@ AC_ARG_WITH(suexec-umask, + APACHE_HELP_STRING(--with-suexec-umask,umask for suexec'd process),[ + AC_DEFINE_UNQUOTED(AP_SUEXEC_UMASK, 0$withval, [umask for suexec'd process] ) ] ) + ++INSTALL_SUEXEC=setuid ++AC_ARG_ENABLE([suexec-capabilities], ++APACHE_HELP_STRING(--enable-suexec-capabilities,Use Linux capability bits not setuid root suexec), [ ++INSTALL_SUEXEC=caps ++AC_DEFINE(AP_SUEXEC_CAPABILITIES, 1, ++ [Enable if suexec is installed with Linux capabilities, not setuid]) ++]) ++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`" +--- httpd-2.4.4/docs/manual/suexec.html.en.r1337344+ ++++ httpd-2.4.4/docs/manual/suexec.html.en +@@ -372,6 +372,21 @@ + together with the --enable-suexec option to let + APACI accept your request for using the suEXEC feature. + ++
--enable-suexec-capabilities
++ ++
Linux specific: Normally, ++ the suexec binary is installed "setuid/setgid ++ root", which allows it to run with the full privileges of the ++ root user. If this option is used, the suexec ++ binary will instead be installed with only the setuid/setgid ++ "capability" bits set, which is the subset of full root ++ priviliges required for suexec operation. Note that ++ the suexec binary may not be able to write to a log ++ file in this mode; it is recommended that the ++ --with-suexec-syslog --without-suexec-logfile ++ options are used in conjunction with this mode, so that syslog ++ logging is used instead.
++ +
--with-suexec-bin=PATH
+ +
The path to the suexec binary must be hard-coded +@@ -433,6 +448,12 @@ + "suexec_log" and located in your standard logfile + directory (--logfiledir).
+ ++
--with-suexec-syslog
++ ++
If defined, suexec will log notices and errors to syslog ++ instead of a logfile. This option must be combined ++ with --without-suexec-logfile.
++ +
--with-suexec-safepath=PATH
+ +
Define a safe PATH environment to pass to CGI +@@ -550,9 +571,12 @@ Group webgroup + +

The suEXEC wrapper will write log information + to the file defined with the --with-suexec-logfile +- option as indicated above. If you feel you have configured and +- installed the wrapper properly, have a look at this log and the +- error_log for the server to see where you may have gone astray.

++ option as indicated above, or to syslog if --with-suexec-syslog ++ is used. If you feel you have configured and ++ installed the wrapper properly, have a look at the log and the ++ error_log for the server to see where you may have gone astray. ++ The output of "suexec -V" will show the options ++ used to compile suexec, if using a binary distribution.

+ +
top
+
+@@ -640,4 +664,4 @@ if (typeof(prettyPrint) !== 'undefined') + prettyPrint(); + } + //--> +- +\ No newline at end of file ++ +--- httpd-2.4.4/Makefile.in.r1337344+ ++++ httpd-2.4.4/Makefile.in +@@ -238,11 +238,22 @@ install-man: + cd $(DESTDIR)$(manualdir) && find . -name ".svn" -type d -print | xargs rm -rf 2>/dev/null || true; \ + fi + +-install-suexec: ++install-suexec: install-suexec-binary 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); \ +- chmod 4755 $(DESTDIR)$(sbindir)/suexec; \ ++ fi ++ ++install-suexec-setuid: ++ @if test -f $(builddir)/support/suexec; then \ ++ chmod 4755 $(DESTDIR)$(sbindir)/suexec; \ ++ fi ++ ++install-suexec-caps: ++ @if test -f $(builddir)/support/suexec; then \ ++ setcap 'cap_setuid,cap_setgid+pe' $(DESTDIR)$(sbindir)/suexec; \ + fi + + suexec: +--- httpd-2.4.4/modules/arch/unix/mod_unixd.c.r1337344+ ++++ httpd-2.4.4/modules/arch/unix/mod_unixd.c +@@ -284,6 +284,13 @@ unixd_set_suexec(cmd_parms *cmd, void *d + return NULL; + } + ++#ifdef AP_SUEXEC_CAPABILITIES ++/* If suexec is using capabilities, don't test for the setuid bit. */ ++#define SETUID_TEST(finfo) (1) ++#else ++#define SETUID_TEST(finfo) (finfo.protection & APR_USETID) ++#endif ++ + static int + unixd_pre_config(apr_pool_t *pconf, apr_pool_t *plog, + apr_pool_t *ptemp) +@@ -300,7 +307,7 @@ unixd_pre_config(apr_pool_t *pconf, apr_ + ap_unixd_config.suexec_enabled = 0; + if ((apr_stat(&wrapper, SUEXEC_BIN, APR_FINFO_NORM, ptemp)) + == APR_SUCCESS) { +- if ((wrapper.protection & APR_USETID) && wrapper.user == 0 ++ if (SETUID_TEST(wrapper) && wrapper.user == 0 + && (access(SUEXEC_BIN, R_OK|X_OK) == 0)) { + ap_unixd_config.suexec_enabled = 1; + ap_unixd_config.suexec_disabled_reason = ""; +--- httpd-2.4.4/support/suexec.c.r1337344+ ++++ httpd-2.4.4/support/suexec.c +@@ -58,6 +58,10 @@ + #include + #endif + ++#ifdef AP_LOG_SYSLOG ++#include ++#endif ++ + #if defined(PATH_MAX) + #define AP_MAXPATH PATH_MAX + #elif defined(MAXPATHLEN) +@@ -69,7 +73,20 @@ + #define AP_ENVBUF 256 + + extern char **environ; ++ ++#ifdef AP_LOG_SYSLOG ++/* Syslog support. */ ++#if !defined(AP_LOG_FACILITY) && defined(LOG_AUTHPRIV) ++#define AP_LOG_FACILITY LOG_AUTHPRIV ++#elif !defined(AP_LOG_FACILITY) ++#define AP_LOG_FACILITY LOG_AUTH ++#endif ++ ++static int log_open; ++#else ++/* Non-syslog support. */ + static FILE *log = NULL; ++#endif + + static const char *const safe_env_lst[] = + { +@@ -137,7 +154,14 @@ static void err_output(int is_error, con + + static void err_output(int is_error, const char *fmt, va_list ap) + { +-#ifdef AP_LOG_EXEC ++#if defined(AP_LOG_SYSLOG) ++ if (!log_open) { ++ openlog("suexec", LOG_PID, AP_LOG_FACILITY); ++ log_open = 1; ++ } ++ ++ vsyslog(is_error ? LOG_ERR : LOG_INFO, fmt, ap); ++#elif defined(AP_LOG_EXEC) + time_t timevar; + struct tm *lt; + +@@ -295,7 +319,9 @@ int main(int argc, char *argv[]) + #ifdef AP_HTTPD_USER + fprintf(stderr, " -D AP_HTTPD_USER=\"%s\"\n", AP_HTTPD_USER); + #endif +-#ifdef AP_LOG_EXEC ++#if defined(AP_LOG_SYSLOG) ++ fprintf(stderr, " -D AP_LOG_SYSLOG\n"); ++#elif defined(AP_LOG_EXEC) + fprintf(stderr, " -D AP_LOG_EXEC=\"%s\"\n", AP_LOG_EXEC); + #endif + #ifdef AP_SAFE_PATH +@@ -591,6 +617,12 @@ int main(int argc, char *argv[]) + #endif /* AP_SUEXEC_UMASK */ + + /* Be sure to close the log file so the CGI can't mess with it. */ ++#ifdef AP_LOG_SYSLOG ++ if (log_open) { ++ closelog(); ++ log_open = 0; ++ } ++#else + if (log != NULL) { + #if APR_HAVE_FCNTL_H + /* +@@ -612,6 +644,7 @@ int main(int argc, char *argv[]) + log = NULL; + #endif + } ++#endif + + /* + * Execute the command, replacing our image with its own. diff --git a/SOURCES/httpd-2.4.9-apxs.patch b/SOURCES/httpd-2.4.9-apxs.patch new file mode 100644 index 0000000..7016dec --- /dev/null +++ b/SOURCES/httpd-2.4.9-apxs.patch @@ -0,0 +1,58 @@ +diff --git a/support/apxs.in b/support/apxs.in +index ad1287f..efcfcf6 100644 +--- a/support/apxs.in ++++ b/support/apxs.in +@@ -25,7 +25,18 @@ package apxs; + + my %config_vars = (); + +-my $installbuilddir = "@exp_installbuilddir@"; ++# Awful hack to make apxs libdir-agnostic: ++my $pkg_config = "/usr/bin/pkg-config"; ++if (! -x "$pkg_config") { ++ error("$pkg_config not found!"); ++ exit(1); ++} ++ ++my $libdir = `pkg-config --variable=libdir apr-1`; ++chomp $libdir; ++ ++my $installbuilddir = $libdir . "/httpd/build"; ++ + get_config_vars("$installbuilddir/config_vars.mk",\%config_vars); + + # read the configuration variables once +@@ -275,7 +286,7 @@ if ($opt_g) { + $data =~ s|%NAME%|$name|sg; + $data =~ s|%TARGET%|$CFG_TARGET|sg; + $data =~ s|%PREFIX%|$prefix|sg; +- $data =~ s|%INSTALLBUILDDIR%|$installbuilddir|sg; ++ $data =~ s|%LIBDIR%|$libdir|sg; + + my ($mkf, $mods, $src) = ($data =~ m|^(.+)-=#=-\n(.+)-=#=-\n(.+)|s); + +@@ -453,11 +464,11 @@ if ($opt_c) { + my $ldflags = "$CFG_LDFLAGS"; + if ($opt_p == 1) { + +- my $apr_libs=`$apr_config --cflags --ldflags --link-libtool --libs`; ++ my $apr_libs=`$apr_config --cflags --ldflags --link-libtool`; + chomp($apr_libs); + my $apu_libs=""; + if ($apr_major_version < 2) { +- $apu_libs=`$apu_config --ldflags --link-libtool --libs`; ++ $apu_libs=`$apu_config --ldflags --link-libtool`; + chomp($apu_libs); + } + +@@ -672,8 +683,8 @@ __DATA__ + + builddir=. + top_srcdir=%PREFIX% +-top_builddir=%PREFIX% +-include %INSTALLBUILDDIR%/special.mk ++top_builddir=%LIBDIR%/httpd ++include %LIBDIR%/httpd/build/special.mk + + # the used tools + APACHECTL=apachectl diff --git a/SOURCES/ihttpd-2.4.20-layout.patch b/SOURCES/ihttpd-2.4.20-layout.patch new file mode 100644 index 0000000..8afcfdd --- /dev/null +++ b/SOURCES/ihttpd-2.4.20-layout.patch @@ -0,0 +1,33 @@ + +Add layout for IHttpd. + +--- httpd-2.4.20/config.layout.orig ++++ httpd-2.4.20/config.layout +@@ -370,3 +370,27 @@ + logfiledir: ${localstatedir}/log/httpd + proxycachedir: ${localstatedir}/cache/httpd + ++ ++# IHttpd layout ++ ++ prefix: /usr ++ exec_prefix: ${prefix} ++ bindir: ${prefix}/bin ++ sbindir: ${prefix}/sbin ++ libdir: ${prefix}/lib ++ libexecdir: ${prefix}/libexec ++ mandir: ${prefix}/man ++ sysconfdir: /etc ++ datadir: ${prefix}/share/ihttpd ++ installbuilddir: ${libdir}/ihttpd/build ++ errordir: ${datadir}/error ++ iconsdir: ${datadir}/icons ++ htdocsdir: /var/www/html ++ manualdir: ${datadir}/manual ++ cgidir: /var/www/cgi-bin ++ includedir: ${prefix}/include/ihttpd ++ localstatedir: /var ++ runtimedir: /run/ihttpd ++ logfiledir: ${localstatedir}/log/ihttpd ++ proxycachedir: ${localstatedir}/cache/ihttpd/proxy ++ diff --git a/SOURCES/ihttpd.conf b/SOURCES/ihttpd.conf new file mode 100644 index 0000000..02a62b2 --- /dev/null +++ b/SOURCES/ihttpd.conf @@ -0,0 +1,79 @@ +# Fix server root +#XXX: useless now ??? +ServerRoot "/etc" + +# Listen on port 80 and 443 +Listen 80 +Listen 443 + +# Server admin +ServerAdmin root@localhost + +# Fix user +User root +Group root + +# Send charset +AddDefaultCharset UTF-8 + +# Allow file send +EnableSendfile on + +# Set document root +DocumentRoot "/var/www/html" + + + AllowOverride None + + + AllowOverride None + Require all granted + + + AllowOverride None + Options Indexes FollowSymLinks ExecCGI + Require all granted + DirectoryIndex index.bin + AddHandler cgi-script .bin + + +# Fix mime type file location +TypesConfig /etc/mime.types + +# Fix pid location +PidFile /run/ihttpd/ihttpd.pid + +# Fix dir for rewrite map lock files +Mutex file:/run/ihttpd rewrite-map +Mutex file:/run/ihttpd mpm-accept + +# Disable version info +ServerSignature Off +ServerTokens Prod + +# SSL configuration +SSLCipherSuite HIGH:MEDIUM:!aNULL:!MD5 +SSLSessionCache shmcb:/run/ihttpd/ssl_scache(512000) +SSLProtocol all -SSLv3 + +# Redirect to https +RewriteEngine On +RewriteCond %{HTTPS} !=on +RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R,L] + +# SSL vhost + + ServerName localhost + SSLEngine on + SSLCertificateFile /etc/pki/tls/certs/ihttpd.pem + SSLCertificateKeyFile /etc/pki/tls/private/ihttpd.pem + CustomLog "/run/ihttpd/log/https.log" "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b" + + +# Log section +ErrorLog "/run/ihttpd/log/error.log" +LogLevel warn + + + CustomLog "/run/ihttpd/log/http.log" "%h %l %u %t \"%r\" %>s %b" + diff --git a/SOURCES/ihttpd.dracut b/SOURCES/ihttpd.dracut new file mode 100644 index 0000000..abcafd1 --- /dev/null +++ b/SOURCES/ihttpd.dracut @@ -0,0 +1,4 @@ +# Unomit mageia's omited network and systemd modules +omit_dracutmodules=" network " +# Force dhcp and net in initramfs +#kernel_cmdline+=" ip=dhcp rd.neednet=1 " diff --git a/SOURCES/ihttpd.module-setup b/SOURCES/ihttpd.module-setup new file mode 100644 index 0000000..c5ba6d2 --- /dev/null +++ b/SOURCES/ihttpd.module-setup @@ -0,0 +1,203 @@ +#!/bin/bash + +# called by dracut +check() { + local fs + + # Fix tmpfiledir + #XXX: fix installation of /usr/lib/tmpfileS.d/{dracut-tmpfiles,systemd}.conf + #XXX: should be removed when bug 18642 (mageia) or 1343230 (fedora) will be fixed in /usr/bin/dracut +1262-1282 + [ -z "$tmpfilesdir" -o ! -d "$tmpfilesdir" -a -d /usr/lib/tmpfiles.d ] && tmpfilesdir=/usr/lib/tmpfiles.d + [ -z "$tmpfilesdir" -o ! -d "$tmpfilesdir" -a -d /etc/tmpfiles.d ] && tmpfilesdir=/etc/tmpfiles.d + [ -z "$tmpfilesdir" -o ! -d "$tmpfilesdir" -a -d /lib/tmpfiles.d ] && tmpfilesdir=/lib/tmpfiles.d + + # if cryptsetup is not installed, then we cannot support encrypted devices. + require_binaries cryptsetup || return 1 + + # if hostonly or mount_needs include if required by other module + # if one of fs types is crypto_LUKS include it + [[ $hostonly ]] || [[ $mount_needs ]] && { + for fs in "${host_fs_types[@]}"; do + [[ $fs = "crypto_LUKS" ]] && return 0 + done + return 255 + } + + return 0 +} + +# called by dracut +depends() { + # depend on crypt for /etc/crypttab + # depend on systemd-networkd for ip=dhcp and rd.neednet=1 + # depend on dracut-systemd for appending to $tmpfilesdir/dracut-tmpfiles.conf + echo crypt systemd-networkd dracut-systemd + return 0 +} + +# called by dracut +cmdline() { + local fs + for fs in "${host_fs_types[@]}"; do + if [[ "$fs" == "crypto_LUKS" ]]; then + printf "%s" " ip=dhcp rd.neednet=1" + break + fi + done +} + +# called by dracut +install() { + local _ihttpdconf=$(cmdline) + local fs + [[ $_ihttpdconf ]] && printf "%s\n" "$_ihttpdconf" >> "${initdir}/etc/cmdline.d/99ihttpd.conf" + + # Install cert dirs + inst_dir /etc/pki/tls/certs + inst_dir /etc/pki/tls/private + inst_dir /etc/systemd/network + inst_dir /var/www/html + inst_dir $systemdsystemunitdir/ihttpd.service.wants + + # Install favicon + inst_simple -o /var/www/html/favicon.ico + + # Install network + for nc in `ls /etc/systemd/network/`; do + inst_simple /etc/systemd/network/$nc + done + + # Install index.bin + inst_simple /usr/lib/ihttpd/index.bin /var/www/html/index.bin + + # Install reboot.bin + inst_simple /usr/lib/ihttpd/reboot.bin /var/www/html/reboot.bin + + # Install all files + inst_multiple \ + /etc/hosts \ + /etc/mime.types \ + /etc/localtime \ + /etc/nsswitch.conf \ + /etc/ihttpd.conf \ + /etc/pki/tls/certs/ihttpd.pem \ + /etc/pki/tls/private/ihttpd.pem \ + $tmpfilesdir/ihttpd.conf \ + $systemdsystemunitdir/ihttpd.path \ + $systemdsystemunitdir/ihttpd.service \ + $systemdsystemunitdir/systemd-networkd.service \ + $systemdsystemunitdir/systemd-tmpfiles-setup.service \ + '/usr/bin/false' \ + '/usr/bin/reboot' \ + /usr/sbin/ihttpd + + # Install ihttpd.path + ln -fs ../ihttpd.path $initdir$systemdsystemunitdir/sysinit.target.wants/ + + # Install resolv.conf as resolved service + #TODO: change this to have a content or depend on systemd-resolved + if [ -L /etc/resolv.conf ]; then + + # Install systemd-resolved + if [ `readlink /etc/resolv.conf` = '/run/systemd/resolve/resolv.conf' ]; then + + # Install resolv.conf as symlink + ln -fs '/run/systemd/resolve/resolv.conf' $initdir/etc/resolv.conf + + # Install systemd-resolved + inst_multiple \ + $systemdsystemunitdir/systemd-resolved.service \ + $systemdutildir/systemd-resolved \ + /etc/systemd/resolved.conf + + # Require systemd-resolve user and group for our ihttpd process + `egrep -q '^systemd-resolve:' $initdir/etc/group` || egrep '^systemd-resolve:' /etc/group >> "$initdir/etc/group" + `egrep -q '^systemd-resolve:' $initdir/etc/passwd` || egrep '^systemd-resolve:' /etc/passwd >> "$initdir/etc/passwd" + + # Install in ihttpd.service.wants + ln -fs ../systemd-resolved.service $initdir$systemdsystemunitdir/ihttpd.service.wants/ + + # Cleanup resolved.conf + perl -pne 'undef $_ if /^(?:#.*|Domains=|FallbackDNS=|DNS=(?:127.0.0.1|::1)$|$)/;/^DNS=/ && $_ =~ s/(?:127.0.0.1|::1)[ \t]*//g' \ + -i "$initdir/etc/systemd/resolved.conf" + + # Cleanup systemd-resolved.service + perl -pne 'undef $_ if /^(?:#|(?:Wants|After)=org\.freedesktop\.resolve1\.busname)/' \ + -i "$initdir$systemdsystemunitdir/systemd-resolved.service" + + # Try install the target file + else + inst_simple /etc/resolv.conf + fi + + # Install resolv.conf as file + elif [ -e /etc/resolv.conf ]; then + + # Install resolv.conf as file + inst_simple /etc/resolv.conf + + # Cleanup resolv.conf + #XXX: strip search, localhost and ipv6 + perl -pne 'undef $_ if /^(?:#.*|search\s+|nameserver\s+127.0.0.1|nameserver\s+[^:\s]+:[^\s]+|$)/' \ + -i "$initdir/etc/resolv.conf" + + # Touch resolv.conf file + else + # We did what we could + touch "$initdir/etc/resolv.conf" + fi + + # Install ihttpd log + ln -fs ../../../run/ihttpd/log/{http,https,child.{askpassword,ihttpd},error}.log $initdir/var/www/html/ + + # Install in ihttpd.service.wants + ln -fs ../systemd-networkd.service $initdir$systemdsystemunitdir/ihttpd.service.wants/ + ln -fs ../systemd-tmpfiles-setup.service $initdir$systemdsystemunitdir/ihttpd.service.wants/ + + # Include all ihttpd deps + inst_libdir_file \ + "ld-linux-*.so.*" \ + "libapr-1.so.*" \ + "libaprutil-1.so.*" \ + "libcrypto.so.*" \ + "libcrypt.so.*" \ + "libc.so.*" \ + "libdb-*.so" \ + "libdl.so.*" \ + "libexpat.so.*" \ + "libnsl.so.*" \ + "libpcre.so.*" \ + "libpthread.so.*" \ + "libresolv.so.*" \ + "librt.so.*" \ + "libuuid.so.*" \ + "libz.so.*" \ + "libnss_files.so.*" \ + "libnss_dns.so.*" \ + "libnss_myhostname.so.*" \ + {"tls/$_arch/",tls/,"$_arch/",}"libssl.so.*" + + # Cleanup nsswitch.conf + if [ -f "$initdir/etc/nsswitch.conf" ]; then + perl -pne 'undef $_ if /^(?:#|$)/;s/compat/files/;s/ ?(?:nis|wins|mdns4_minimal |mdns4)( )?/\1/g' \ + -i "$initdir/etc/nsswitch.conf" + fi + + # Cleanup systemd-networkd.service + if [ -f "$initdir$systemdsystemunitdir/systemd-networkd.service" ]; then + perl -pne 'undef $_ if /^(?:#|(?:Wants|After)=org\.freedesktop\.network1\.busname)/;s/^After=(systemd-udevd.service )dbus.service network-pre.target systemd-sysusers.service /After=\1/' \ + -i "$initdir$systemdsystemunitdir/systemd-networkd.service" + fi + + # Cleanup systemd-tmpfiles-setup.service + if [ -f "$initdir$systemdsystemunitdir/systemd-tmpfiles-setup.service" ]; then + perl -pne 'undef $_ if /^#/;s/After=(.*) systemd-sysusers.service/After=\1/' \ + -i "$initdir$systemdsystemunitdir/systemd-tmpfiles-setup.service" + fi + + #XXX: bug: fix /usr/lib/tmpfiles.d/{systemd,dracut-tmpfiles}.conf missing user and group + `egrep -q '^utmp:' $initdir/etc/group` || egrep '^utmp:' /etc/group >> "$initdir/etc/group" + # Require root user and group for our ihttpd process + `egrep -q '^root:' $initdir/etc/group` || egrep '^root:' /etc/group >> "$initdir/etc/group" + `egrep -q '^root:' $initdir/etc/passwd` || egrep '^root:' /etc/passwd >> "$initdir/etc/passwd" +} diff --git a/SOURCES/ihttpd.path b/SOURCES/ihttpd.path new file mode 100644 index 0000000..a258268 --- /dev/null +++ b/SOURCES/ihttpd.path @@ -0,0 +1,12 @@ +# Path unit starting ihttpd.service on password request +[Unit] +Description=The Apache IHTTP Server that will unlock crypttab device +DefaultDependencies=no +Conflicts=shutdown.target multi-user.target graphical.target +After=plymouth-start.service +Before=paths.target shutdown.target +ConditionPathExists=!/run/plymouth/pid + +[Path] +DirectoryNotEmpty=/run/systemd/ask-password +MakeDirectory=yes diff --git a/SOURCES/ihttpd.service b/SOURCES/ihttpd.service new file mode 100644 index 0000000..9961633 --- /dev/null +++ b/SOURCES/ihttpd.service @@ -0,0 +1,17 @@ +# Service unit starting ihttpd.service on password request +[Unit] +Description=Answer Password Requests from the Apache IHTTP Server +DefaultDependencies=no +Conflicts=shutdown.target multi-user.target graphical.target +After=plymouth-start.service +Before=paths.target shutdown.target +ConditionPathExists=!/run/plymouth/pid + +[Service] +Type=simple +Environment=LANG=C +ExecStart=/usr/sbin/ihttpd $OPTIONS -DFOREGROUND +ExecReload=/usr/sbin/ihttpd $OPTIONS -k graceful +KillSignal=SIGWINCH +KillMode=mixed +PIDFile=/run/ihttpd/ihttpd.pid diff --git a/SOURCES/ihttpd.tmpfiles b/SOURCES/ihttpd.tmpfiles new file mode 100644 index 0000000..b422ac9 --- /dev/null +++ b/SOURCES/ihttpd.tmpfiles @@ -0,0 +1,2 @@ +d /run/ihttpd 755 root root +d /run/ihttpd/log 755 root root diff --git a/SOURCES/index.bin.c b/SOURCES/index.bin.c new file mode 100644 index 0000000..e6780a1 --- /dev/null +++ b/SOURCES/index.bin.c @@ -0,0 +1,1135 @@ +/** + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Written by Raphaël Gertz + */ + +//Required for mkostemp, O_CLOEXEC, strdup, memmem +#define _GNU_SOURCE + +//Required for SSIZE_MAX, LONG_MAX +#include + +//Required for pid_t, kill, waitpid +#include +#include + +//Required for printf, sscanf, sprintf +#include + +//Required for struct stat, fstat +#include + +//Required for closedir, DIR, opendir, readdir, struct dirent +#include + +//Required for close, dup2, execve, fork, read, STDERR_FILENO, STDOUT_FILENO, STDIN_FILENO, write +#include + +//Required for open, O_CLOEXEC, O_NOATIME, O_NOFOLLOW +#include + +//Required for atoi, calloc, exit, EXIT_FAILURE, EXIT_SUCCESS, free, getenv, malloc, realloc +#include + +//Required for memchr, memcpy, memmem, strdup, strlen, strncmp +#include + +//Required for bool +#include + +//Required for nanosleep +#include + +//Default passphrase max size +#define DEFAULT_PASSPHRASE_SIZE_MAX 512 + +//Default keyfile max size +//XXX: file should be maximum 8192*1024-1 character long +#define DEFAULT_KEYFILE_SIZE_MAX (8192 * 1024) + +//Default crypttab +#define CRYPTTAB "/etc/crypttab" + +//Default cryptsetup +#define CRYPTSETUP "/sbin/cryptsetup" + +//Default pid file +#define IHTTPDPID "/run/ihttpd/ihttpd.pid" + +//Default systemd ask-password dir +#define ASKPASSWORDDIR "/run/systemd/ask-password" + +//Define child log +#define ASKPASSWORDLOG "/run/ihttpd/log/child.askpassword.log" +#define IHTTPDLOG "/run/ihttpd/log/child.ihttpd.log" + +//Create struct for http error status +struct httpStatusStruct { + int value; + char *description; +}; + +//Declare http error status array +const struct httpStatusStruct httpStatuses[] = { + {200, "OK"}, + {400, "Bad Request"}, + {405, "Method Not Allowed"}, + {411, "Length Required"}, + {500, "Internal Server Error"} +}; + +/** + * Prototype + */ +void die(const int, const char*); +void header(const int, const char*); +void showForm(const char*, const int, const int); +int extractValue(char**, int*, char*, int); +int extractLuksDevice(char**, char**); +int extractIHttpdPid(pid_t *); +int extractAskPasswordPid(pid_t *); + +/** + * Die with error + */ +void die(const int code, const char *err) { + //TODO: see if we add a nice text/html template ? + //Send content as text + header(code, "text/plain"); + //Print error line if available + if (err != NULL) + printf("%s", err); + //Flush all + if (fflush(NULL) == -1) { + perror("fflush"); + } + //Exit with failure code + exit(EXIT_FAILURE); +} + +/** + * Send header + */ +void header(const int code, const char *ctype) { + int k; + switch(code) { + case 400: + k = 1; + break; + case 405: + k = 2; + break; + case 411: + k = 3; + break; + case 500: + k = 4; + break; + default: + k = 0; + } + //Send http status + printf("Status: %d %s\r\n", httpStatuses[k].value, httpStatuses[k].description); + //Make sure no cache + printf("Cache-Control: no-cache, no-store, must-revalidate\r\n"); + printf("Pragma: no-cache\r\n"); + printf("Expires: 0\r\n"); + printf("X-Robots-Tag: noindex, nofollow, noarchive, nosnippet, noodp\r\n"); + printf("Content-type: %s\r\n\r\n", ctype); +} + +/** + * Show form + */ +void showForm(const char *requestUri, const int keyfileSizeMax, const int passphraseSizeMax) { + header(200, "text/html"); + printf("\r\n"); + printf("\r\n"); + printf("Key upload form\r\n"); + printf("\r\n"); + printf("
\r\n"); + printf("
Upload key
\r\n", requestUri, keyfileSizeMax); + printf("
Type key
\r\n", requestUri, passphraseSizeMax); + printf("
\r\n"); + printf("\r\n"); + printf("\r\n"); +} + +/** + * Extract value + */ +int extractValue(char **value, int *valueLength, char *contentType, int contentLength) { + //Handle application/x-www-form-urlencoded request + if (contentType != NULL && !strncmp(contentType, "application/x-www-form-urlencoded", 33)) { + //Indexes and return + int i, k, v, r; + //Declare key and buf + char *key, *buf; + //Allocate key + if ((key = malloc(4*sizeof(char))) == NULL) { + //Unable to allocate key + return -1; + } + //Allocate buf to maximum possible value size + 1 for trailing \0 + if ((buf = calloc(1, (DEFAULT_PASSPHRASE_SIZE_MAX+1)*sizeof(char))) == NULL) { + //Unable to allocate value + free(key); + return -2; + } + //Char buffer + char d = '\0'; + //Char delimiter + //XXX: initialised as & for new key, becomes = when fetching value + char delim = '&'; + for (i = 0, k = 0, v = 0; i < contentLength; i++) { + //Safeguard against a value greater than DEFAULT_PASSPHRASE_SIZE_MAX + //XXX: this should never happen because we should be protected by contentLength already + if (v == DEFAULT_PASSPHRASE_SIZE_MAX+1) { + //Invalid value + free(key); + free(buf); + return -3; + } + //Read one character from stdin + r = read(STDIN_FILENO, &d, 1); + //Handle errors + if (r < 0) { + //Error while parsing post data + free(key); + free(buf); + return -4; + } else if (r == 0) { + //Partial receive + free(key); + free(buf); + return -5; + } + //Handle case where key has an other name + if (i == 3) { + //Check key is "key" and we get '=' as new char and assign delim to = + if (strncmp(key, "key", 3) || (delim = d) != '=') { + //Invalid key + free(key); + free(buf); + return -6; + } + //Handle key or value separator in query string + } else if (d == '&' || d == '=') { + //Invalid query string + free(key); + free(buf); + return -7; + //Handle a value + } else { + //Save key char + if (delim == '&') { + key[k] = d; + k++; + //Save buf char + } else { + buf[v] = d; + v++; + } + } + } + //Free key + free(key); + //Unescape and reduce value if not empty + if (v > 0) { + //Declare iterators + int l,m, s = v; + //Loop on value and reduce length on the fly + for(l=0,m=0; m < v; l++,m++) { + //Replace + with space + if (buf[m] == '+') { + buf[l] = ' '; + //Skip partial present %XX + } else if ( + //Assign char + (buf[l] = buf[m]) == '%' && + //Check we didn't reach valueStrLength + (m+2 < v) && + //Check next two digits are valid + ((buf[m+1] >= 'A' && buf[m+1] <= 'F') || (buf[m+1] >= 'a' && buf[m+1] <= 'f') || (buf[m+1] >= '0' && buf[m+1] <= '9')) && + ((buf[m+2] >= 'A' && buf[m+2] <= 'F') || (buf[m+2] >= 'a' && buf[m+2] <= 'f') || (buf[m+2] >= '0' && buf[m+2] <= '9')) + ) { + buf[l] = (buf[m+1] >= 'A' ? (buf[m+1] & 0xdf) - 'A' + 10 : buf[m+1] - '0') * 16 + (buf[m+2] >= 'A' ? (buf[m+2] & 0xdf) - 'A' + 10 : buf[m+2] - '0'); + m += 2; + s -= 2; + } + } + //Set value length + *valueLength = s; + //Alloc value + if ((*value = malloc((*valueLength)*sizeof(char))) == NULL) { + //Unable to alloc value + free(key); + free(buf); + return -8; + } + //Copy value + memcpy(*value, buf, *valueLength); + } + //Free buf + free(buf); + //Handle multipart/form-data request + } else if (contentType != NULL && !strncmp(contentType, "multipart/form-data", 19)) { + //Indexes and return + int b, s, r; + //Boundary length + int boundaryLength = strlen(contentType) - 30 + 1; + //Client send LF ending without CR + int lfstyle = 0; + //Declare boundary + char *boundary; + //Allocate boundary + if ((boundary = calloc(1, boundaryLength*sizeof(char))) == NULL) { + //Unable to allocate boundary + return -9; + } + //Extract boundary + memcpy(boundary, contentType + 30, boundaryLength - 1); + + //Declare buffers + char *start, *buf; + //Allocate buffer + if ((buf = malloc(contentLength*sizeof(char))) == NULL) { + //Unable to allocate buffer + free(boundary); + return -10; + } + //Char buffer + char d = '\0'; + + //Loop + for (b = 0, s = 0; b < contentLength; b++) { + //Detect possible boundary + //XXX: b is boundaryLength-1 + 2 after s + //XXX: d will be a CR(CRLF line ending) or LF(LF line ending) or -(of final --) + if (b == s + 2 + boundaryLength - 1 && !strncmp(boundary, buf + b - boundaryLength + 1, boundaryLength - 1)) { + //Only after first boundary match + if (s > 0) { + //Trim line jump + if (start[0] == '\r' && start[1] == '\n') { + start += 2; + lfstyle = 1; + } else if (start[0] == '\n') { + start++; + } + //Found flag + bool found = false; + //Allocate pointers + char *new = start, *prev = start, *name = NULL; + //Search for a new line + while ((new = memchr(new, '\n', b - (new - buf)))) { + //Jump to first character after new line + new++; + //Init line length + int lineLength = new - prev - 1; + //Remove chariage return if necessary + if (prev[lineLength] == '\r') { + lineLength--; + lfstyle = 1; + } + //Break loop after headers end + if (lineLength == 1) { + break; + } + //Allocate a name buf of maximum line length + //XXX: need to be filled with zero as we don't know what will comes with sscanf call and we rely on strlen + if ((name = calloc(1, lineLength*sizeof(char))) == NULL) { + //Unable to allocate name + free(boundary); + free(buf); + return -11; + } + //Search for name + if (sscanf(prev, "Content-Disposition: form-data; name=\"%[^\"]\"", name)) { + //Realloc name + if ((name = realloc(name, (strlen(name)+1)*sizeof(char))) == NULL) { + //Unable to reduce name + free(boundary); + free(buf); + free(name); + return -12; + } + if (!strncmp(name, "key", 3)) { + found = true; + } + } + //Free name + free(name); + //Jump to next one + prev = new; + } + //Init value if found + if (found) { + //Declare end + char *end = buf + b - boundaryLength - 3; + //Remove CR at end if provided + //XXX: only remove CR at end if we encountered one before + if (lfstyle) { + end++; + } + //On too big keyfile + if (end - new - 1 >= DEFAULT_KEYFILE_SIZE_MAX) { + //Keyfile too large + free(boundary); + free(buf); + return -13; + } + //On non empty value + if (end - new > 1) { + //Set value length + *valueLength = end - new - 1; + //Allocate value + if ((*value = malloc((*valueLength)*sizeof(char))) == NULL) { + //Unable to allocate value + free(boundary); + free(buf); + return -14; + } + //Copy value + memcpy(*value, new, *valueLength); + } + } + } + //Set start to matched boundary + start = buf + b; + } + //Read one character from stdin + r = read(STDIN_FILENO, &d, 1); + //Handle errors + if (r < 0) { + //Error while parsing post data + free(boundary); + free(buf); + return -15; + } else if (r == 0) { + //Partial receive + free(boundary); + free(buf); + return -16; + } + //New line case + if (d == '\n') { + //Store new possible boundary start + s = b + 1; + } + buf[b] = d; + } + + //Free buffers + free(boundary); + free(buf); + //Unhandled request + } else { + return -17; + } + + //Send value + return 0; +} + +/** + * Extract luks and device + */ +int extractLuksDevice(char **luks, char **device) { + //Declare file descriptor + int fd, bufLength; + //Declare buf, device and luks pointer + char *buf, *d, *l; + //Declare stat struct + struct stat *stats; + //Open file + if ((fd = open(CRYPTTAB, O_RDONLY|O_NOATIME|O_NOFOLLOW|O_CLOEXEC)) == -1) { + //Can't open crypttab file + return -1; + } + //Allocate stats + if ((stats = calloc(1, sizeof(struct stat))) == NULL) { + //Unable to allocate stats + return -2; + } + //Stat file + if (fstat(fd, stats) == -1) { + //Can't stat crypttab + return -3; + } + //Check file size + if ((bufLength = stats->st_size) > SSIZE_MAX) { + //Crypttab too big + return -4; + } + //Allocate buf + if ((buf = malloc(bufLength*sizeof(char))) == NULL) { + //Unable to allocate buf + return -5; + } + //Read file + if ((read(fd, buf, bufLength)) < bufLength) { + //Fail to read crypttab file + return -6; + } + //Close file + close(fd); + //Free stats buffer + free(stats); + + //Search first separator (\s|\t) after luks + if ((l = memchr(buf, ' ', bufLength)) == NULL && (l = memchr(buf, ' ', bufLength)) == NULL) { + return -7; + } + //Jump to next char + l++; + //Search first separator (\s|\t) after device + if ((d = memchr(l, ' ', bufLength - (l - buf))) == NULL && (d = memchr(l, ' ', bufLength - (l - buf))) == NULL && (d = memchr(l, '\n', bufLength - (l - buf))) == NULL) { + return -8; + } + //Jump to next char + d++; + + //Alloc luks + if ((*luks = malloc((l - buf - 1)*sizeof(char))) == NULL) { + return -9; + } + //Allocate device + if ((*device = malloc((d - l - 1)*sizeof(char))) == NULL) { + //Free and reset luks + free(luks); + luks=NULL; + return -10; + } + + //Copy luks + memcpy(*luks, buf, l - buf - 1); + //Terminate luks + (*luks)[l - buf - 1] = '\0'; + + //Copy device + memcpy(*device, l, d - l - 1); + //Terminate device + (*device)[d - l - 1] = '\0'; + + //Free buffer + free(buf); + + //Success + return 0; +} + +/** + * Extract ask-password pid + */ +int extractAskPasswordPid(pid_t *pid) { + //Declare stuct dirent + struct dirent *entry; + //Declare askdir + DIR *askdir; + //Declare found + int found = 0; + + //Allocate dirent struct + if ((entry = calloc(1, sizeof(struct dirent))) == NULL) { + //Unable to allocate entry + return -1; + } + + //Open systemd ask-password dir + if ((askdir = opendir(ASKPASSWORDDIR)) == NULL) { + //Can't open ask dir + return -2; + } + + //Change dir + if (chdir(ASKPASSWORDDIR) == -1) { + //Can't change to ask dir + return -3; + } + + //Loop on dir content + while((entry = readdir(askdir))) { + //Handle each ask.XXXXXX file + if (!strncmp(entry->d_name, "ask.", 4) && strlen(entry->d_name) == 10) { + //Declare file descriptor + int fd, bufLength; + //Declare buf + char *buf; + //Declare stat struct + struct stat *stats; + //Open file + if ((fd = open(entry->d_name, O_RDONLY|O_NOATIME|O_NOFOLLOW|O_CLOEXEC)) == -1) { + //Can't open ask file + return -4; + } + //Allocate stats + if ((stats = calloc(1, sizeof(struct stat))) == NULL) { + //Unable to allocate stats + return -5; + } + //Stat file + if (fstat(fd, stats) == -1) { + //Can't stat ask file + return -6; + } + //Check file size + if ((bufLength = stats->st_size) > SSIZE_MAX) { + //Ask file too big + return -7; + } + //Allocate buf + if ((buf = malloc(bufLength*sizeof(char))) == NULL) { + //Unable to allocate buf + return -8; + } + //Read file + if ((read(fd, buf, bufLength)) < bufLength) { + //Fail to read ask file + return -9; + } + //Close file + close(fd); + //Free stats buffer + free(stats); + + //Allocate pointers + char *nl = buf, *pl = buf, *e; + //Allocate pid + *pid = 0; + + //Search for a new line + while ((nl = memmem(nl, bufLength - (nl - buf), "\n", strlen("\n")))) { + //Jump to next char + nl++; + + //Check if we have a = in line but not empty value ("=\n") + if ((e = memmem(pl, bufLength - (pl - buf), "=", strlen("="))) && e < nl - 2) { + //Jump to next char + e++; + //Look for PID + if (!strncmp(pl, "PID", 3)) { + //Declade pid string + char *pidStr; + //Allocate pid string + if ((pidStr = malloc((nl - e)*sizeof(char))) == NULL) { + //Unable to allocate pid string + return -10; + } + //Copy pid + memcpy(pidStr, e, nl - e - 1); + //Terminate pid string + pidStr[nl - e] = '\0'; + //Check pid value + if ((*pid = atoi(pidStr)) <= 1) { + //Invalid pid + return -11; + } + //Free pid string + free(pidStr); + //Found a valid process + found++; + } + } + + //Jump prev line to new line + pl = nl; + } + + //Free buffers + free(buf); + } + } + + //Close systemd ask-password dir + if (closedir(askdir) == -1) { + //Can't close ask dir + return -13; + } + + //Free entry + free(entry); + + //Found no valid pid + if (found == 0) { + //No pid found + return -14; + //Found more than one pid + } else if (found > 1) { + //No pid found + return -15; + } + + //Success + return 0; +} + +/** + * Extract ihttpd pid + */ +int extractIHttpdPid(pid_t *pid) { + //Declare file descriptor + int fd, bufLength; + //Declare buf, device and luks pointer + char *buf, *l, *pidStr; + //Declare stat struct + struct stat *stats; + //Open file + if ((fd = open(IHTTPDPID, O_RDONLY|O_NOATIME|O_NOFOLLOW|O_CLOEXEC)) == -1) { + //Can't open crypttab file + return -1; + } + //Allocate stats + if ((stats = calloc(1, sizeof(struct stat))) == NULL) { + //Unable to allocate stats + return -2; + } + //Stat file + if (fstat(fd, stats) == -1) { + //Can't stat crypttab + return -3; + } + //Check file size + if ((bufLength = stats->st_size) > SSIZE_MAX) { + //Crypttab too big + return -4; + } + //Allocate buf + if ((buf = malloc(bufLength*sizeof(char))) == NULL) { + //Unable to allocate buf + return -5; + } + //Read file + if ((read(fd, buf, bufLength)) < bufLength) { + //Fail to read crypttab file + return -6; + } + //Close file + close(fd); + //Free stats buffer + free(stats); + + //Search first separator (\s|\t|\n) after pid + if ((l = memchr(buf, ' ', bufLength)) == NULL && (l = memchr(buf, ' ', bufLength)) == NULL && (l = memchr(buf, '\n', bufLength)) == NULL) { + return -7; + } + //Jump to next char + l++; + + //Alloc pid string + if ((pidStr = malloc((l - buf - 1)*sizeof(char))) == NULL) { + return -9; + } + + //Copy luks + memcpy(pidStr, buf, l - buf - 1); + //Terminate luks + pidStr[l - buf - 1] = '\0'; + + //Free buffer + free(buf); + + //Store pid + if ((*pid = atoi(pidStr)) <= 1) { + //Invalid pid + return -10; + } + + //Free pid string + free(pidStr); + + //Success + return 0; +} + +/** + * Main function + */ +int main(int argc, char **argv) { + + //Get request method + char *requestMethod = getenv("REQUEST_METHOD"); + + //Handle unknown requests + if (requestMethod == NULL || (strncmp(requestMethod, "GET", 3) && strncmp(requestMethod, "HEAD", 4) && strncmp(requestMethod, "POST", 4))) { + //Send method not allowed + die(405, "Unsupported request method"); + //Handle get and head + } else if (!strncmp(requestMethod, "GET", 3) || !strncmp(requestMethod, "HEAD", 4)) { + //Send form + showForm(getenv("REQUEST_URI")?getenv("REQUEST_URI"):"/", DEFAULT_KEYFILE_SIZE_MAX, DEFAULT_PASSPHRASE_SIZE_MAX); + //Handle post + } else /*if (!strncmp(requestMethod, "POST", 4))*/ { + //Return value + int ret; + + //Child pid + pid_t pid; + + //Value length + //XXX: will contain number of char in value without trailing \0 + int valueLength; + //Value string + //XXX: will contain value without a tailing \0 + char *value = NULL; + + //Content length + int contentLength; + //Content length string from env + char *contentLengthStr = getenv("CONTENT_LENGTH"); + //Content type + char *contentType = getenv("CONTENT_TYPE"); + + //Declare luks and device + char *luks = NULL, *device = NULL; + + //Pairs of pipe for stdin, stdout and stderr + int inPipe[2], errPipe[2]; + + //Handle unknown content type + if (contentType == NULL || (strncmp(contentType, "application/x-www-form-urlencoded", 33) && strncmp(contentType, "multipart/form-data", 19))) { + die(400, "Unknown content type"); + } + + //Handle invalid multipart/form-data content type + //XXX: max boundary length is 70 as per rfc1521 & rfc2046 + if (!strncmp(contentType, "multipart/form-data", 19) && (strncmp(contentType, "multipart/form-data; boundary=", 30) || strlen(contentType) <= 30 || strlen(contentType) > 100)) { + die(400, "Malformed boundary in multipart/form-data request"); + } + + //Handle invalid content length + //XXX: deny empty contentLength as chrome send a contentLength even for a device + if (contentLengthStr == NULL || (contentLength = atoi(contentLengthStr)) <= 0) { + die(411, "Invalid content length"); + } + + //Handle application/x-www-form-urlencoded request length + //XXX: limit to key=xyz where xyz can be all encoded in %XX + if (!strncmp(contentType, "application/x-www-form-urlencoded", 33) && contentLength > (DEFAULT_PASSPHRASE_SIZE_MAX * 3 + 4)) { + die(400, "Invalid application/x-www-form-urlencoded request length"); + } + + //Handle multipart/form-data request length + //XXX: limit to arbitrary 3 times the keyfile max size + if (!strncmp(contentType, "multipart/form-data", 19) && contentLength > (DEFAULT_KEYFILE_SIZE_MAX * 3)) { + die(400, "Invalid multipart/form-data request length"); + } + + //Extract value + if ((ret = extractValue(&value, &valueLength, contentType, contentLength)) < 0) { + die(500, "Failed to extract value"); + } + + + //Extract luks and device + if ((ret = extractLuksDevice(&luks, &device)) < 0) { + die(500, "Failed to extract luks and device"); + } + + //Create stdin pipe + if (pipe(inPipe) == -1) { + die(500, "Failed to create in pipe"); + } + + //Create stderr pipe + if (pipe(errPipe) == -1) { + die(500, "Failed to create err pipe"); + } + + //Fork process + if ((pid = fork()) == -1) { + die(500, "Failed to fork"); + } + + //Child process + if (pid == 0) { + //Child argv + char *cargv[] = { CRYPTSETUP, "-d", "-", "luksOpen", device, luks, NULL }; + char *carge[] = { NULL }; + //Free value + free(value); + //Redirect stdin to pipe + if (dup2(inPipe[0], STDIN_FILENO) == -1) { + die(500, "Failed to redirect in pipe"); + } + //Close inPipe + close(inPipe[0]); + close(inPipe[1]); + //Redirect stderr to pipe + if (dup2(errPipe[1], STDERR_FILENO) == -1) { + die(500, "Failed to redirect err pipe"); + } + //Close errPipe + close(errPipe[0]); + close(errPipe[1]); + //Call cryptsetup + if (execve(CRYPTSETUP, cargv, carge) == -1) { + die(500, "Failed to call cryptsetup"); + } + //Parent process + } else { + //Free luks + free(luks); + //Free device + free(device); + + //Close unused inPipe end + close(inPipe[0]); + //Close unused errPipe end + close(errPipe[1]); + + //Send password on stdin anyway + //XXX: this fail if device is already unlocked for example + write(inPipe[1], value, valueLength); + + //Free value + free(value); + + //Close stdin with EOF + close(inPipe[1]); + + //Wait child + if (waitpid(pid, &ret, 0) == -1) { + die(500, "Failed to wait child"); + } + + //Handle already unlocked device + if (ret == 1280) { + die(200, "Device already unlocked"); + //Handle already in use device + } else if (ret == 5) { + die(500, "Device already in use"); + //Handle invalid luks device + } else if (ret == 256) { + die(500, "Device is now a valid device"); + //Handle no key available with this passphrase + } else if (ret == 512) { + die(500, "No slot for this value"); + //Handle unexisting device or permission denied + } else if (ret == 1014) { + die(500, "Device doesn't exist or access denied"); + //Unknown error + } else if (ret != 0) { + //Err length and counter + int errLength = 2048, e = 0; + //Declare err buffer + char *err; + //Buffer char + char c; + //Alloc err buffer + if ((err = malloc(errLength*sizeof(char))) == NULL) { + die(500, "Couldn't alloc err buffer"); + } + //Advance after ret code + e = sprintf(err, "%d:", ret); + //Fetch stderr and store in err buffer + while(read(errPipe[0], &c, 1) > 0) { + //Grow buffer if we reach end + if (e == errLength) { + if ((err = realloc(err, (errLength+2048)*sizeof(char))) == NULL) { + die(500, "Couldn't grow err buffer"); + } + errLength += 2048; + } + //Store character + err[e] = c; + //Pass to next + e++; + } + //Terminate err buffer + err[e] = '\0'; + //Realloc err buffer + if ((err = realloc(err, (e+1)*sizeof(char))) == NULL) { + die(500, "Couldn't ungrow err buffer"); + } + //Die with luks error + die(500, err); + } + //Close errPipe + close(errPipe[0]); + } + + //Fork process + if ((pid = fork()) == -1) { + die(500, "Failed to fork"); + } + + //IHttpd killing child process + if (pid == 0) { + //File descriptor + int fd; + + //Declare ihttpd pid + pid_t ihttpdPid; + + //Close stdin + close(STDIN_FILENO); + + //Disable line buffering on stdout and stderr + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); + + //Redirect output to log + if ((fd = open(IHTTPDLOG, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR)) == -1) { + fprintf(stderr, "Open ihttpd child log failed\n"); + } else { + //Close stdout + close(STDOUT_FILENO); + //Redirect stdout on childlog + if (dup2(fd, STDOUT_FILENO) == -1) { + fprintf(stderr, "Redirect stdout to ihttpd child log failed\n"); + } + //Close stderr + close(STDERR_FILENO); + //Redirect stderr on childlog + if (dup2(fd, STDERR_FILENO) == -1) { + fprintf(stderr, "Redirect stderr to ihttpd child log failed\n"); + } + //Close childlog fd + close(fd); + } + + //Extract ihttpd pid + if (extractIHttpdPid(&ihttpdPid) < 0) { + fprintf(stderr, "Failed to extract ihttpd pid"); + exit(EXIT_FAILURE); + } + + //Close stdout and stderr without childlog + if (fd == -1) { + close(STDOUT_FILENO); + close(STDERR_FILENO); + } + + //Wait until get rattached to init(getppid()==1) + //XXX: we are really blind here + while(getppid() != 1) { + //Sleep half a second + if (usleep(500000) == -1 && fd != -1) { + printf("Usleep failed\n"); + } + } + + //Termiate ihttpd + if (kill(ihttpdPid, 0) == 0 && kill(ihttpdPid, SIGTERM) == -1 && fd != -1) { + printf("Termiate ihttpd failed\n"); + } + + //Sleep half a second + if (usleep(500000) == -1 && fd != -1) { + printf("Usleep failed\n"); + } + + //Kill ihttpd + if (kill(ihttpdPid, 0) == 0 && kill(ihttpdPid, SIGKILL) == -1) { + printf("Kill ihttpd failed\n"); + } + + //Parent process + } else { + + //Fork process + if ((pid = fork()) == -1) { + die(500, "Failed to fork"); + } + + //Ask password killing child process + //XXX: we are blind here + if (pid == 0) { + //File descriptor + int fd; + + //Declare ask password pid + pid_t askPasswordPid; + + //Close stdin + close(STDIN_FILENO); + + //Disable line buffering on stdout and stderr + setvbuf(stdout, NULL, _IONBF, 0); + setvbuf(stderr, NULL, _IONBF, 0); + + //Redirect output to log + if ((fd = open(ASKPASSWORDLOG, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR)) == -1) { + fprintf(stderr, "Open ask password child log failed\n"); + } else { + //Close stdout + close(STDOUT_FILENO); + //Redirect stdout on childlog + if (dup2(fd, STDOUT_FILENO) == -1) { + fprintf(stderr, "Redirect stdout to ask password child log failed\n"); + } + //Close stderr + close(STDERR_FILENO); + //Redirect stderr on childlog + if (dup2(fd, STDERR_FILENO) == -1) { + fprintf(stderr, "Redirect stderr to ask password child log failed\n"); + } + //Close childlog fd + close(fd); + } + + //Extract ask password pid + if (extractAskPasswordPid(&askPasswordPid) < 0) { + fprintf(stderr, "Failed to extract ask password pid"); + exit(EXIT_FAILURE); + } + + //Close stdout and stderr without childlog + if (fd == -1) { + close(STDOUT_FILENO); + close(STDERR_FILENO); + } + + //Wait until get rattached to init(getppid()==1) + //XXX: we are really blind here + while(getppid() != 1) { + //Sleep half a second + if (usleep(500000) == -1 && fd != -1) { + printf("Usleep failed\n"); + } + } + + //Termitate ask password + if (kill(askPasswordPid, 0) == 0 && kill(askPasswordPid, SIGTERM) == -1 && fd != -1) { + printf("Termiate ask password failed\n"); + } + + + //Sleep half a second + if (usleep(500000) == -1 && fd != -1) { + printf("Usleep failed\n"); + } + + //Kill ask password + if (kill(askPasswordPid, 0) == 0 && kill(askPasswordPid, SIGKILL) == -1) { + printf("Kill ask password failed\n"); + } + + //Parent process + } else { + + //Process success + header(200, "text/plain"); + printf("Sent value, boot should resume now"); + fflush(NULL); + + } + + } + + } + + exit(EXIT_SUCCESS); +} diff --git a/SOURCES/reboot.sh b/SOURCES/reboot.sh new file mode 100644 index 0000000..5184469 --- /dev/null +++ b/SOURCES/reboot.sh @@ -0,0 +1,2 @@ +#! /bin/sh +/usr/bin/reboot -f -i -h diff --git a/SPECS/ihttpd.spec b/SPECS/ihttpd.spec new file mode 100644 index 0000000..8de2616 --- /dev/null +++ b/SPECS/ihttpd.spec @@ -0,0 +1,223 @@ +%define contentdir %{_datadir}/httpd +%define docroot /var/www + +%{?!maxmodules:%global maxmodules 128} +%{?!serverlimit:%global serverlimit 1024} + +Name: ihttpd +Version: 2.4.20 +Release: %mkrel 1 +Summary: The most widely used Web server on the Internet +License: Apache License +Group: System/Servers +URL: http://httpd.apache.org/ +Source0: http://www.apache.org/dist/httpd/httpd-%version.tar.bz2 +Source1: index.bin.c +Source2: reboot.sh +Source14: ihttpd.tmpfiles +Source15: ihttpd.service +Source17: ihttpd.path +Source18: ihttpd.dracut +Source19: ihttpd.module-setup +Source20: ihttpd.conf +# build/scripts patches +Patch1: httpd-2.4.1-apctl.patch +Patch2: httpd-2.4.9-apxs.patch +Patch3: httpd-2.4.1-deplibs.patch +Patch5: ihttpd-2.4.20-layout.patch +Patch6: httpd-2.4.3-apctl-systemd.patch +Patch7: httpd-2.4.10-detect-systemd.patch +# Features/functional changes +Patch20: httpd-2.4.3-release.patch +Patch23: httpd-2.4.4-export.patch +Patch24: httpd-2.4.1-corelimit.patch +Patch26: httpd-2.4.4-r1337344+.patch +Patch27: httpd-2.4.2-icons.patch +Patch28: httpd-2.4.4-r1332643+.patch +Patch30: httpd-2.4.4-cachehardmax.patch +Patch31: httpd-2.4.18-sslmultiproxy.patch +Patch34: httpd-2.4.17-socket-activation.patch +Patch35: httpd-2.4.17-sslciphdefault.patch +# Bug fixes +Patch55: httpd-2.4.4-malformed-host.patch +Patch56: httpd-2.4.4-mod_unique_id.patch +Patch57: httpd-2.4.10-sigint.patch + +# For /var/www/html +Requires: webserver-base +# For /etc/mime.types +Requires: mailcap + +Requires(post): systemd >= %{systemd_required_version} +Requires(post): rpm-helper >= 0.24.8-1 +Requires(post): openssl makedev +Requires(preun): rpm-helper >= 0.24.8-1 + +%description +This package contains the main binary of apache, a powerful, full-featured, +efficient and freely-available Web server. Apache is also the most popular Web +server on the Internet. + +This version of apache is fully static, and few modules are available built-in. + +%prep +%setup -q -n httpd-%{version} + +%patch1 -p1 -b .apctl +%patch2 -p1 -b .apxs +%patch3 -p1 -b .deplibs +%patch5 -p1 -b .layout +%patch6 -p1 -b .apctlsystemd +%patch7 -p1 -b .detectsystemd + +%patch23 -p1 -b .export +%patch24 -p1 -b .corelimit +%patch26 -p1 -b .r1337344+ +%patch27 -p1 -b .icons +%patch30 -p1 -b .cachehardmax +%patch31 -p1 -b .sslmultiproxy +%patch34 -p1 -b .socketactivation +%patch35 -p1 -b .sslciphdefault + +%patch55 -p1 -b .malformedhost +%patch56 -p1 -b .uniqueid +%patch57 -p1 -b .sigint + +# Patch in vendor/release string +sed "s/@RELEASE@/%{product_distribution}/" < %{PATCH20} | patch -p1 + +# forcibly prevent use of bundled apr, apr-util, pcre +rm -rf srclib/{apr,apr-util,pcre} + +# fix apxs +perl -pi \ + -e 's|\@exp_installbuilddir\@|%{_libdir}/httpd/build|;' \ + -e 's|get_vars\("prefix"\)|"%{_libdir}/httpd/build"|;' \ + -e 's|get_vars\("sbindir"\) . "/envvars"|"\$installbuilddir/envvars"|;' \ + support/apxs.in + +# correct perl paths +find -type f -print0 | xargs -0 perl -pi \ + -e 's|/usr/local/bin/perl|perl|g;' \ + -e 's|/usr/local/bin/perl5|perl|g;' \ + -e 's|/path/to/bin/perl|perl|g;' + +# bump max modules +perl -pi \ + -e 's/DYNAMIC_MODULE_LIMIT \d+/DYNAMIC_MODULE_LIMIT %{maxmodules}/;' \ + include/httpd.h + +# bump server limit +perl -pi \ + -e 's/DEFAULT_SERVER_LIMIT \d+/DEFAULT_SERVER_LIMIT %{serverlimit}/' \ + server/mpm/prefork/prefork.c \ + server/mpm/worker/worker.c \ + server/mpm/event/event.c + +# don't try to touch srclib +perl -pi -e "s|^SUBDIRS = .*|SUBDIRS = os server modules support|g" Makefile.in + +# this will only work if configured correctly in the config (FullOs)... +cp server/core.c server/core.c.untagged + +# Install index.bin source +install -m 644 %{SOURCE1} index.bin.c + +%build +%serverbuild +# regenerate configure scripts +autoheader && autoconf || exit 1 + +export CFLAGS="$RPM_OPT_FLAGS -DBIG_SECURITY_HOLE" +export LDFLAGS="-Wl,-z,relro,-z,now" + +# Hard-code path to links to avoid unnecessary builddep +export LYNX_PATH=/usr/bin/links + +%configure2_5x \ + --enable-layout=IHttpd \ + --sysconfdir='/etc' \ + --includedir='/usr/include/ihttpd' \ + --libexecdir='/usr/lib64/ihttpd/modules' \ + --datadir='/usr/share/ihttpd' \ + --with-ssl \ + --with-mpm=prefork \ + --with-cgi \ + --with-program-name='%name' \ + --disable-suexec \ + --without-suexec \ + --disable-distcache \ + --enable-unixd \ + --enable-auth-basic \ + --enable-authn-core \ + --enable-authn-file \ + --enable-authz-core \ + --enable-authz-host \ + --enable-authz-user \ + --enable-rewrite \ + --enable-socache-shmcb \ + --enable-mime \ + --enable-dir \ + --enable-ssl \ + --enable-log-config \ + --enable-cgi \ + --enable-pie \ + --enable-modules=none \ + --enable-mods-static='unixd auth_basic authn_core authn_file authz_core authz_host authz_user rewrite socache_shmcb dir mime log_config cgi ssl' + +%make + +export CFLAGS="$RPM_OPT_FLAGS" +# -m64 -std=c99 -pedantic -Wall -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes +gcc index.bin.c -o index.bin + +%install + +#IHttpd sbin +install -D -p -m 755 ihttpd %{buildroot}%{_sbindir}/ihttpd + +#IHttpd config +install -D -p -m 644 %{SOURCE20} %{buildroot}%{_sysconfdir}/ihttpd.conf + +#Tmpfiles.d config +install -D -p -m 644 %{SOURCE14} %{buildroot}%{_tmpfilesdir}/ihttpd.conf + +#IHttpd service +install -D -p -m 644 %{SOURCE15} %{buildroot}%{_unitdir}/ihttpd.service + +#IHttpd path +install -D -p -m 644 %{SOURCE17} %{buildroot}%{_unitdir}/ihttpd.path + +#IHttpd dracut config +install -D -p -m 644 %{SOURCE18} %{buildroot}%{_sysconfdir}/dracut.conf.d/99-%{name}.conf + +#IHttpd dracut module +install -d -m 755 %{buildroot}%{_prefix}/lib/dracut/modules.d/99ihttpd +install -D -p -m 755 %{SOURCE19} %{buildroot}%{_prefix}/lib/dracut/modules.d/99ihttpd/module-setup.sh + +#Ihttpd index.bin +install -d -m 755 %{buildroot}%{_prefix}/lib/%{name} +install -D -p -m 755 index.bin %{buildroot}%{_prefix}/lib/%{name}/index.bin +install -D -p -m 755 %{SOURCE2} %{buildroot}%{_prefix}/lib/%{name}/reboot.bin + +%find_lang %name + +%post +%_tmpfilescreate %{name} +%_post_service %{name} +%_create_ssl_certificate %{name} + +%preun +%_preun_service %{name} + +%files -n %name +%config(noreplace) %{_sysconfdir}/%{name}.conf +%config(noreplace) %{_sysconfdir}/dracut.conf.d/99-%{name}.conf +%{_sbindir}/%{name} +%{_tmpfilesdir}/%{name}.conf +%{_unitdir}/%{name}.path +%dir %{_prefix}/lib/dracut/modules.d/99ihttpd +%{_prefix}/lib/dracut/modules.d/99ihttpd/module-setup.sh +%{_unitdir}/%{name}.service +%{_prefix}/lib/%{name}/index.bin +%{_prefix}/lib/%{name}/reboot.bin