From b7595a3007a6251790ea510f858a2ba557fe5efb Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Mon, 15 Jul 2024 12:09:05 +0000 Subject: [PATCH 001/176] xforms [skip ci] git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919250 13f79535-47bb-0310-9956-ffa450edef68 --- docs/manual/mod/mod_rewrite.html.en | 6 ++++++ docs/manual/mod/mod_rewrite.xml.fr | 2 +- docs/manual/mod/mod_rewrite.xml.meta | 2 +- docs/manual/rewrite/flags.html.en | 7 +++++++ docs/manual/rewrite/flags.xml.fr | 2 +- docs/manual/rewrite/flags.xml.meta | 2 +- 6 files changed, 17 insertions(+), 4 deletions(-) diff --git a/docs/manual/mod/mod_rewrite.html.en b/docs/manual/mod/mod_rewrite.html.en index 83bce1b39c..5728d8f523 100644 --- a/docs/manual/mod/mod_rewrite.html.en +++ b/docs/manual/mod/mod_rewrite.html.en @@ -1463,6 +1463,12 @@ cannot use $N in the substitution string! details ... + + UNC + Prevents the merging of multiple leading slashes, as used by Windows UNC paths. + details ... + +

Home directory expansion

diff --git a/docs/manual/mod/mod_rewrite.xml.fr b/docs/manual/mod/mod_rewrite.xml.fr index 10688a2d34..41e41d64fe 100644 --- a/docs/manual/mod/mod_rewrite.xml.fr +++ b/docs/manual/mod/mod_rewrite.xml.fr @@ -1,7 +1,7 @@ - + diff --git a/docs/manual/mod/mod_rewrite.xml.meta b/docs/manual/mod/mod_rewrite.xml.meta index decc0a7b1e..0be21e86f4 100644 --- a/docs/manual/mod/mod_rewrite.xml.meta +++ b/docs/manual/mod/mod_rewrite.xml.meta @@ -8,6 +8,6 @@ en - fr + fr diff --git a/docs/manual/rewrite/flags.html.en b/docs/manual/rewrite/flags.html.en index 604e278d02..fa4aa932f2 100644 --- a/docs/manual/rewrite/flags.html.en +++ b/docs/manual/rewrite/flags.html.en @@ -59,6 +59,7 @@ providing detailed explanations and examples.

  • T|type
  • UnsafeAllow3F
  • UnsafePrefixStat
  • +
  • UNC
  • See also

    top
    @@ -838,6 +839,12 @@ The L flag can be useful in this context to end the These substitutions are not prefixed with the document root. This protects from a malicious URL causing the expanded substitution to map to an unexpected filesystem location.

    +
    top
    +
    +

    UNC

    +

    Setting this flag prevents the merging of multiple leading slashes, + as used in Windows UNC paths. The flag is not necessary when the rules + substitution starts with multiple literal slashes.

    Available Languages:  en  | diff --git a/docs/manual/rewrite/flags.xml.fr b/docs/manual/rewrite/flags.xml.fr index 82da3314ac..4c775ac54c 100644 --- a/docs/manual/rewrite/flags.xml.fr +++ b/docs/manual/rewrite/flags.xml.fr @@ -1,7 +1,7 @@ - + diff --git a/docs/manual/rewrite/flags.xml.meta b/docs/manual/rewrite/flags.xml.meta index 912229af03..e4f3ee6f49 100644 --- a/docs/manual/rewrite/flags.xml.meta +++ b/docs/manual/rewrite/flags.xml.meta @@ -8,6 +8,6 @@ en - fr + fr From cd2255e5cad9aa2e09d89dda00adaa6db2511799 Mon Sep 17 00:00:00 2001 From: Rainer Jung Date: Mon, 15 Jul 2024 22:42:20 +0000 Subject: [PATCH 002/176] Make sure pytest shuts down the web server after each package. Backport of r1919265 from trunk. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919267 13f79535-47bb-0310-9956-ffa450edef68 --- test/modules/core/conftest.py | 5 +++++ test/modules/http1/conftest.py | 5 +++++ test/modules/md/conftest.py | 4 ++++ test/modules/proxy/conftest.py | 5 +++++ test/modules/tls/conftest.py | 5 +++++ 5 files changed, 24 insertions(+) diff --git a/test/modules/core/conftest.py b/test/modules/core/conftest.py index 22906efbb0..a14bdfb675 100644 --- a/test/modules/core/conftest.py +++ b/test/modules/core/conftest.py @@ -28,3 +28,8 @@ def env(pytestconfig) -> CoreTestEnv: env.apache_access_log_clear() env.httpd_error_log.clear_log() return env + +@pytest.fixture(autouse=True, scope="package") +def _stop_package_scope(env): + yield + assert env.apache_stop() == 0 diff --git a/test/modules/http1/conftest.py b/test/modules/http1/conftest.py index 33a16a1170..45b26c1796 100644 --- a/test/modules/http1/conftest.py +++ b/test/modules/http1/conftest.py @@ -34,3 +34,8 @@ def env(pytestconfig) -> H1TestEnv: env.apache_access_log_clear() env.httpd_error_log.clear_log() return env + +@pytest.fixture(autouse=True, scope="package") +def _stop_package_scope(env): + yield + assert env.apache_stop() == 0 diff --git a/test/modules/md/conftest.py b/test/modules/md/conftest.py index 0f9e4a9f49..a7b064b6a9 100755 --- a/test/modules/md/conftest.py +++ b/test/modules/md/conftest.py @@ -59,3 +59,7 @@ def acme(env): if acme_server is not None: acme_server.stop() +@pytest.fixture(autouse=True, scope="package") +def _stop_package_scope(env): + yield + assert env.apache_stop() == 0 diff --git a/test/modules/proxy/conftest.py b/test/modules/proxy/conftest.py index 7e6f4e7b09..c92e363e2a 100644 --- a/test/modules/proxy/conftest.py +++ b/test/modules/proxy/conftest.py @@ -29,3 +29,8 @@ def env(pytestconfig) -> ProxyTestEnv: env.apache_access_log_clear() env.httpd_error_log.clear_log() return env + +@pytest.fixture(autouse=True, scope="package") +def _stop_package_scope(env): + yield + assert env.apache_stop() == 0 diff --git a/test/modules/tls/conftest.py b/test/modules/tls/conftest.py index c7cb85877d..6f6f983cfd 100644 --- a/test/modules/tls/conftest.py +++ b/test/modules/tls/conftest.py @@ -31,3 +31,8 @@ def env(pytestconfig) -> TlsTestEnv: env.apache_access_log_clear() env.httpd_error_log.clear_log() return env + +@pytest.fixture(autouse=True, scope="package") +def _stop_package_scope(env): + yield + assert env.apache_stop() == 0 From 363d239bede4bd4af25ce9a70cc4b9c1499f224c Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Wed, 17 Jul 2024 18:20:34 +0000 Subject: [PATCH 003/176] publishing release httpd-2.4.62 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919317 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES | 22 +++++++++++++++++++ STATUS | 3 ++- docs/manual/mod/core.html.de | 2 +- docs/manual/mod/core.html.es | 2 +- docs/manual/mod/core.html.ja.utf8 | 2 +- docs/manual/mod/core.html.tr.utf8 | 2 +- docs/manual/mod/mod_rewrite.html.fr.utf8 | 2 ++ docs/manual/mod/quickreference.html.de | 2 +- docs/manual/mod/quickreference.html.es | 2 +- docs/manual/mod/quickreference.html.ja.utf8 | 2 +- docs/manual/mod/quickreference.html.ko.euc-kr | 2 +- docs/manual/mod/quickreference.html.tr.utf8 | 2 +- .../manual/mod/quickreference.html.zh-cn.utf8 | 2 +- docs/manual/rewrite/flags.html.fr.utf8 | 2 ++ docs/manual/style/version.ent | 2 +- include/ap_release.h | 2 +- 16 files changed, 40 insertions(+), 13 deletions(-) diff --git a/CHANGES b/CHANGES index cd86fe7540..083208ee42 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,28 @@ -*- coding: utf-8 -*- +Changes with Apache 2.4.63 + Changes with Apache 2.4.62 + *) SECURITY: CVE-2024-40898: Apache HTTP Server: SSRF with + mod_rewrite in server/vhost context on Windows (cve.mitre.org) + SSRF in Apache HTTP Server on Windows with mod_rewrite in + server/vhost context, allows to potentially leak NTML hashes to + a malicious server via SSRF and malicious requests. + Users are recommended to upgrade to version 2.4.62 which fixes + this issue. + Credits: Smi1e (DBAPPSecurity Ltd.) + + *) SECURITY: CVE-2024-40725: Apache HTTP Server: source code + disclosure with handlers configured via AddType (cve.mitre.org) + A partial fix for CVE-2024-39884 in the core of Apache HTTP + Server 2.4.61 ignores some use of the legacy content-type based + configuration of handlers. "AddType" and similar configuration, + under some circumstances where files are requested indirectly, + result in source code disclosure of local content. For example, + PHP scripts may be served instead of interpreted. + Users are recommended to upgrade to version 2.4.62, which fixes + this issue. + *) mod_proxy: Fix canonicalisation and FCGI env (PATH_INFO, SCRIPT_NAME) for "balancer:" URLs set via SetHandler, also allowing for "unix:" sockets with BalancerMember(s). PR 69168. [Yann Ylavic] diff --git a/STATUS b/STATUS index b3689bedc3..96161c7fef 100644 --- a/STATUS +++ b/STATUS @@ -29,7 +29,8 @@ Release history: [NOTE that x.{odd}.z versions are strictly Alpha/Beta releases, while x.{even}.z versions are Stable/GA releases.] - 2.4.62 : In development + 2.4.63 : In development + 2.4.62 : Released on July 17, 2024 2.4.61 : Released on July 03, 2024 2.4.60 : Released on July 01, 2024 2.4.59 : Released on April 04, 2024 diff --git a/docs/manual/mod/core.html.de b/docs/manual/mod/core.html.de index a025992d21..06368d2729 100644 --- a/docs/manual/mod/core.html.de +++ b/docs/manual/mod/core.html.de @@ -3624,7 +3624,7 @@ bevor er die Anfrage abbricht - + diff --git a/docs/manual/mod/core.html.es b/docs/manual/mod/core.html.es index a563573c4e..5efc11de56 100644 --- a/docs/manual/mod/core.html.es +++ b/docs/manual/mod/core.html.es @@ -4323,7 +4323,7 @@ certain events before failing a request
    Beschreibung:Controls what UNC host names can be accessed by the server
    Syntax:UNCListhostname ...
    Syntax:UNCList hostname [hostname...]
    Voreinstellung:unset
    Kontext:Serverkonfiguration
    Status:Core
    - + diff --git a/docs/manual/mod/core.html.ja.utf8 b/docs/manual/mod/core.html.ja.utf8 index e807744543..96d4454b72 100644 --- a/docs/manual/mod/core.html.ja.utf8 +++ b/docs/manual/mod/core.html.ja.utf8 @@ -3552,7 +3552,7 @@ of a request or the last 63, assuming the request itself is greater than
    Descripción:Controls what UNC host names can be accessed by the server
    Sintaxis:UNCListhostname ...
    Sintaxis:UNCList hostname [hostname...]
    Valor por defecto:unset
    Contexto:server config
    Estado:Core
    - + diff --git a/docs/manual/mod/core.html.tr.utf8 b/docs/manual/mod/core.html.tr.utf8 index c3743b8ec2..cbe05acb91 100644 --- a/docs/manual/mod/core.html.tr.utf8 +++ b/docs/manual/mod/core.html.tr.utf8 @@ -4971,7 +4971,7 @@ gerçekleşmesi için sunucunun geçmesini bekleyeceği süre.
    説明:Controls what UNC host names can be accessed by the server
    構文:UNCListhostname ...
    構文:UNCList hostname [hostname...]
    デフォルト:unset
    コンテキスト:サーバ設定ファイル
    ステータス:Core
    - + diff --git a/docs/manual/mod/mod_rewrite.html.fr.utf8 b/docs/manual/mod/mod_rewrite.html.fr.utf8 index d69f368ddb..41867ce911 100644 --- a/docs/manual/mod/mod_rewrite.html.fr.utf8 +++ b/docs/manual/mod/mod_rewrite.html.fr.utf8 @@ -29,6 +29,8 @@

    Langues Disponibles:  en  |  fr 

    +
    Cette traduction peut être périmée. Vérifiez la version + anglaise pour les changements récents.
    Açıklama:Controls what UNC host names can be accessed by the server
    Sözdizimi:UNCListhostname ...
    Sözdizimi:UNCList hostname [hostname...]
    Öntanımlı:unset
    Bağlam:sunucu geneli
    Durum:Çekirdek
    diff --git a/docs/manual/mod/quickreference.html.de b/docs/manual/mod/quickreference.html.de index eb417c027e..fbd90a9384 100644 --- a/docs/manual/mod/quickreference.html.de +++ b/docs/manual/mod/quickreference.html.de @@ -1197,7 +1197,7 @@ bevor er die Anfrage abbricht - diff --git a/docs/manual/mod/quickreference.html.es b/docs/manual/mod/quickreference.html.es index 84d952f740..4773df593c 100644 --- a/docs/manual/mod/quickreference.html.es +++ b/docs/manual/mod/quickreference.html.es @@ -1186,7 +1186,7 @@ certain events before failing a request - diff --git a/docs/manual/mod/quickreference.html.ja.utf8 b/docs/manual/mod/quickreference.html.ja.utf8 index fa80388146..74e84a69d2 100644 --- a/docs/manual/mod/quickreference.html.ja.utf8 +++ b/docs/manual/mod/quickreference.html.ja.utf8 @@ -1114,7 +1114,7 @@ Certificate verification - diff --git a/docs/manual/mod/quickreference.html.ko.euc-kr b/docs/manual/mod/quickreference.html.ko.euc-kr index 60a7ae287b..e4096378ca 100644 --- a/docs/manual/mod/quickreference.html.ko.euc-kr +++ b/docs/manual/mod/quickreference.html.ko.euc-kr @@ -1142,7 +1142,7 @@ certain events before failing a request - diff --git a/docs/manual/mod/quickreference.html.tr.utf8 b/docs/manual/mod/quickreference.html.tr.utf8 index 2c5261eb04..9dc9099f74 100644 --- a/docs/manual/mod/quickreference.html.tr.utf8 +++ b/docs/manual/mod/quickreference.html.tr.utf8 @@ -1181,7 +1181,7 @@ gerçekleşmesi için sunucunun geçmesini bekleyeceği süre. - diff --git a/docs/manual/mod/quickreference.html.zh-cn.utf8 b/docs/manual/mod/quickreference.html.zh-cn.utf8 index a358a1a156..22748a65b4 100644 --- a/docs/manual/mod/quickreference.html.zh-cn.utf8 +++ b/docs/manual/mod/quickreference.html.zh-cn.utf8 @@ -1178,7 +1178,7 @@ certain events before failing a request - diff --git a/docs/manual/rewrite/flags.html.fr.utf8 b/docs/manual/rewrite/flags.html.fr.utf8 index 3d0c3ae17c..35d76ccac5 100644 --- a/docs/manual/rewrite/flags.html.fr.utf8 +++ b/docs/manual/rewrite/flags.html.fr.utf8 @@ -26,6 +26,8 @@

    Langues Disponibles:  en  |  fr 

    +
    Cette traduction peut être périmée. Vérifiez la version + anglaise pour les changements récents.

    Ce document décrit les drapeaux disponibles dans la directive RewriteRule, en fournissant diff --git a/docs/manual/style/version.ent b/docs/manual/style/version.ent index e3df8e231f..6f52c11c18 100644 --- a/docs/manual/style/version.ent +++ b/docs/manual/style/version.ent @@ -19,6 +19,6 @@ - + diff --git a/include/ap_release.h b/include/ap_release.h index 72129fa2fd..d2a93751c7 100644 --- a/include/ap_release.h +++ b/include/ap_release.h @@ -43,7 +43,7 @@ #define AP_SERVER_MAJORVERSION_NUMBER 2 #define AP_SERVER_MINORVERSION_NUMBER 4 -#define AP_SERVER_PATCHLEVEL_NUMBER 62 +#define AP_SERVER_PATCHLEVEL_NUMBER 63 #define AP_SERVER_DEVBUILD_BOOLEAN 1 /* Synchronize the above with docs/manual/style/version.ent */ From 806a335062f1aa75ba1a5aba3c88fff9a367e6e6 Mon Sep 17 00:00:00 2001 From: Rainer Jung Date: Wed, 17 Jul 2024 18:37:41 +0000 Subject: [PATCH 004/176] Fix copy and paste typo in comment git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919318 13f79535-47bb-0310-9956-ffa450edef68 --- test/modules/tls/test_07_alpn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/modules/tls/test_07_alpn.py b/test/modules/tls/test_07_alpn.py index 06aff3caae..aa449104c5 100644 --- a/test/modules/tls/test_07_alpn.py +++ b/test/modules/tls/test_07_alpn.py @@ -36,7 +36,7 @@ def test_tls_07_alpn_get_a(self, env): assert protocol == "http/1.1", r.stderr def test_tls_07_alpn_get_b(self, env): - # do we see the correct json for the domain_a? + # do we see the correct json for the domain_b? r = env.tls_get(env.domain_b, "/index.json", options=["-vvvvvv"]) assert r.exit_code == 0, r.stderr protocol = self._get_protocol(r.stderr) From d5c35ddf09b97deaec79e0b8a0df22685ebb126f Mon Sep 17 00:00:00 2001 From: Yann Ylavic Date: Wed, 17 Jul 2024 21:51:33 +0000 Subject: [PATCH 005/176] Propose x 1, vote x 1 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919329 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/STATUS b/STATUS index 96161c7fef..9c111427ae 100644 --- a/STATUS +++ b/STATUS @@ -222,7 +222,15 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: *) CMake: Use full path to gen_test_char.exe in CUSTOM_COMMAND. trunk patch: http://svn.apache.org/r1902366 2.4.x patch: svn merge -c r1902366 ^/httpd/httpd/trunk . - +1: ivan + +1: ivan, ylavic + + *) mod_rewrite: Better question mark tracking to avoid UnsafeAllow3F. PR 69197. + Trunk version of patch: + https://svn.apache.org/r1919325 + 2.4.x version of patch: + https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/462.diff + PR: https://github.com/apache/httpd/pull/462 + +1: ylavic, PATCHES/ISSUES THAT ARE BEING WORKED [ New entries should be added at the START of the list ] From b0a3a17797940b88b1a97f4e97f55f0dc6728df5 Mon Sep 17 00:00:00 2001 From: Rainer Jung Date: Wed, 17 Jul 2024 21:59:39 +0000 Subject: [PATCH 006/176] Fix typo in test name. Backport of r1919330 from trunk. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919331 13f79535-47bb-0310-9956-ffa450edef68 --- test/modules/tls/test_14_proxy_ssl.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/modules/tls/test_14_proxy_ssl.py b/test/modules/tls/test_14_proxy_ssl.py index 87e04c28af..f5ed445f84 100644 --- a/test/modules/tls/test_14_proxy_ssl.py +++ b/test/modules/tls/test_14_proxy_ssl.py @@ -76,7 +76,7 @@ def test_tls_14_proxy_ssl_h2_get(self, env): ("SSL_CIPHER_EXPORT", "false"), ("SSL_CLIENT_VERIFY", "NONE"), ]) - def test_tls_14_proxy_tsl_vars_const(self, env, name: str, value: str): + def test_tls_14_proxy_ssl_vars_const(self, env, name: str, value: str): if not HttpdTestEnv.has_shared_module("tls"): return r = env.tls_get(env.domain_b, f"/proxy-ssl/vars.py?name={name}") @@ -102,7 +102,7 @@ def test_tls_14_proxy_ssl_vars_const(self, env, name: str, value: str): ("SSL_VERSION_INTERFACE", r'mod_tls/\d+\.\d+\.\d+'), ("SSL_VERSION_LIBRARY", r'rustls-ffi/\d+\.\d+\.\d+/rustls/\d+\.\d+(\.\d+)?'), ]) - def test_tls_14_proxy_tsl_vars_match(self, env, name: str, pattern: str): + def test_tls_14_proxy_ssl_vars_match(self, env, name: str, pattern: str): if not HttpdTestEnv.has_shared_module("tls"): return r = env.tls_get(env.domain_b, f"/proxy-ssl/vars.py?name={name}") From b41c53fa1118a9ce9ec330b5ead350af591d5e86 Mon Sep 17 00:00:00 2001 From: Rainer Jung Date: Wed, 17 Jul 2024 22:04:01 +0000 Subject: [PATCH 007/176] Skip h2 tests on prefork. Backport of r1919332 from trunk. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919333 13f79535-47bb-0310-9956-ffa450edef68 --- test/modules/tls/env.py | 6 ++++++ test/modules/tls/test_07_alpn.py | 2 ++ test/modules/tls/test_14_proxy_ssl.py | 2 ++ test/modules/tls/test_15_proxy_tls.py | 3 +++ 4 files changed, 13 insertions(+) diff --git a/test/modules/tls/env.py b/test/modules/tls/env.py index 6afc472cb0..efc4f0b247 100644 --- a/test/modules/tls/env.py +++ b/test/modules/tls/env.py @@ -55,6 +55,12 @@ class TlsTestEnv(HttpdTestEnv): CURL_SUPPORTS_TLS_1_3 = None + @classmethod + @property + def is_unsupported(cls): + mpm_module = f"mpm_{os.environ['MPM']}" if 'MPM' in os.environ else 'mpm_event' + return mpm_module == 'mpm_prefork' + @classmethod def curl_supports_tls_1_3(cls) -> bool: if cls.CURL_SUPPORTS_TLS_1_3 is None: diff --git a/test/modules/tls/test_07_alpn.py b/test/modules/tls/test_07_alpn.py index aa449104c5..6017372020 100644 --- a/test/modules/tls/test_07_alpn.py +++ b/test/modules/tls/test_07_alpn.py @@ -4,8 +4,10 @@ import pytest from .conf import TlsTestConf +from .env import TlsTestEnv +@pytest.mark.skipif(condition=TlsTestEnv.is_unsupported, reason="h2 not supported here") class TestAlpn: @pytest.fixture(autouse=True, scope='class') diff --git a/test/modules/tls/test_14_proxy_ssl.py b/test/modules/tls/test_14_proxy_ssl.py index f5ed445f84..81cb4f31b0 100644 --- a/test/modules/tls/test_14_proxy_ssl.py +++ b/test/modules/tls/test_14_proxy_ssl.py @@ -2,6 +2,7 @@ import pytest from .conf import TlsTestConf +from .env import TlsTestEnv from pyhttpd.env import HttpdTestEnv @@ -63,6 +64,7 @@ def test_tls_14_proxy_ssl_get_local(self, env): ] ) + @pytest.mark.skipif(condition=TlsTestEnv.is_unsupported, reason="h2 not supported here") def test_tls_14_proxy_ssl_h2_get(self, env): r = env.tls_get(env.domain_b, "/proxy-h2-ssl/index.json") assert r.exit_code == 0 diff --git a/test/modules/tls/test_15_proxy_tls.py b/test/modules/tls/test_15_proxy_tls.py index e7eb10362b..3fe6cfe478 100644 --- a/test/modules/tls/test_15_proxy_tls.py +++ b/test/modules/tls/test_15_proxy_tls.py @@ -3,6 +3,7 @@ import pytest from .conf import TlsTestConf +from .env import TlsTestEnv from pyhttpd.env import HttpdTestEnv @pytest.mark.skipif(condition=not HttpdTestEnv.has_shared_module("tls"), reason="no mod_tls available") @@ -62,6 +63,7 @@ def test_tls_15_proxy_tls_get_local(self, env): ] ) + @pytest.mark.skipif(condition=TlsTestEnv.is_unsupported, reason="h2 not supported here") def test_tls_15_proxy_tls_h2_get(self, env): r = env.tls_get(env.domain_b, "/proxy-h2-tls/index.json") assert r.exit_code == 0 @@ -88,6 +90,7 @@ def test_tls_15_proxy_tls_h1_vars(self, env, name: str, value: str): ("SSL_CIPHER", "TLS_CHACHA20_POLY1305_SHA256"), ("SSL_SESSION_RESUMED", "Initial"), ]) + @pytest.mark.skipif(condition=TlsTestEnv.is_unsupported, reason="h2 not supported here") def test_tls_15_proxy_tls_h2_vars(self, env, name: str, value: str): r = env.tls_get(env.domain_b, f"/proxy-h2-tls/vars.py?name={name}") assert r.exit_code == 0, r.stderr From 3da8255f382beaf834ba963ce55100dfaad0adf5 Mon Sep 17 00:00:00 2001 From: Rainer Jung Date: Wed, 17 Jul 2024 22:12:49 +0000 Subject: [PATCH 008/176] Skip more h2 tests in prefork. Backport of r1919334 from trunk. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919335 13f79535-47bb-0310-9956-ffa450edef68 --- test/modules/http2/test_202_trailer.py | 3 ++- test/modules/http2/test_203_rfc9113.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/test/modules/http2/test_202_trailer.py b/test/modules/http2/test_202_trailer.py index 4b4fc42c78..6c4e05d3d9 100644 --- a/test/modules/http2/test_202_trailer.py +++ b/test/modules/http2/test_202_trailer.py @@ -1,7 +1,7 @@ import os import pytest -from .env import H2Conf +from .env import H2Conf, H2TestEnv def setup_data(env): @@ -13,6 +13,7 @@ def setup_data(env): # The trailer tests depend on "nghttp" as no other client seems to be able to send those # rare things. +@pytest.mark.skipif(condition=H2TestEnv.is_unsupported, reason="mod_http2 not supported here") class TestTrailers: @pytest.fixture(autouse=True, scope='class') diff --git a/test/modules/http2/test_203_rfc9113.py b/test/modules/http2/test_203_rfc9113.py index 1fe3e13159..143c0fc930 100644 --- a/test/modules/http2/test_203_rfc9113.py +++ b/test/modules/http2/test_203_rfc9113.py @@ -2,9 +2,10 @@ from typing import List, Optional from pyhttpd.env import HttpdTestEnv -from .env import H2Conf +from .env import H2Conf, H2TestEnv +@pytest.mark.skipif(condition=H2TestEnv.is_unsupported, reason="mod_http2 not supported here") class TestRfc9113: @pytest.fixture(autouse=True, scope='class') From 774b5b744c4f920838573e8ab5570f5e7cc96c9e Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Wed, 17 Jul 2024 23:34:06 +0000 Subject: [PATCH 009/176] vote/promote/stall git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919336 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/STATUS b/STATUS index 9c111427ae..ac663299d0 100644 --- a/STATUS +++ b/STATUS @@ -181,6 +181,12 @@ PATCHES ACCEPTED TO BACKPORT FROM TRUNK: Added r1919148 too for another old) colspan issue Tiny fix which needs vote reset? + *) CMake: Use full path to gen_test_char.exe in CUSTOM_COMMAND. + trunk patch: http://svn.apache.org/r1902366 + 2.4.x patch: svn merge -c r1902366 ^/httpd/httpd/trunk . + +1: ivan, ylavic, covener + + PATCHES PROPOSED TO BACKPORT FROM TRUNK: [ New proposals should be added at the end of the list ] @@ -199,30 +205,12 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: https://svn.apache.org/r1914281 Backport version for 2.4.x of patch: https://svn.apache.org/repos/asf/httpd/httpd/patches/2.4.x/httpd-2.4-ldap-search5.patch - +1: minfrin - - *) mod_proxy: prevent bad busy values and problems with bybusyness - Trunk version of patch: - https://svn.apache.org/r1912245 - https://svn.apache.org/r1913930 - svn merge -c 1912245 ^/httpd/httpd/trunk . - svn merge -c 1913930 ^/httpd/httpd/trunk . - +1: minfrin - minfrin: r1913930 added, votes reset, mmn bump needed - ylavic: not sure since it's not public (i.e. in mod_proxy.h)? - minfrin: true, mmn bump not needed - ylavic: new proposal in https://github.com/apache/httpd/pull/396 - -1: jfclere The new proposal is NOT in trunk + +1: minfrin, covener - *) mod_ldap: Add a hint to install the apr_ldap module on init failure. + *) mod_ldap: Add a hint to install the apr_ldap module on init failure. trunk patch: http://svn.apache.org/r1914038 2.4.x patch: svn merge -c r1914038 ^/httpd/httpd/trunk . - +1: minfrin - - *) CMake: Use full path to gen_test_char.exe in CUSTOM_COMMAND. - trunk patch: http://svn.apache.org/r1902366 - 2.4.x patch: svn merge -c r1902366 ^/httpd/httpd/trunk . - +1: ivan, ylavic + +1: minfrin, covener *) mod_rewrite: Better question mark tracking to avoid UnsafeAllow3F. PR 69197. Trunk version of patch: @@ -230,7 +218,7 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: 2.4.x version of patch: https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/462.diff PR: https://github.com/apache/httpd/pull/462 - +1: ylavic, + +1: ylavic, covener PATCHES/ISSUES THAT ARE BEING WORKED [ New entries should be added at the START of the list ] @@ -420,4 +408,17 @@ PATCHES/ISSUES THAT ARE STALLED +1: minfrin -1: jorton, appears to be a duplicate of the existing -B option + *) mod_proxy: prevent bad busy values and problems with bybusyness + Trunk version of patch: + https://svn.apache.org/r1912245 + https://svn.apache.org/r1913930 + svn merge -c 1912245 ^/httpd/httpd/trunk . + svn merge -c 1913930 ^/httpd/httpd/trunk . + +1: minfrin + minfrin: r1913930 added, votes reset, mmn bump needed + ylavic: not sure since it's not public (i.e. in mod_proxy.h)? + minfrin: true, mmn bump not needed + ylavic: new proposal in https://github.com/apache/httpd/pull/396 + -1: jfclere The new proposal is NOT in trunk + From e26640308b37f577d586540a2061d8b0544e489d Mon Sep 17 00:00:00 2001 From: Lucien Gentis Date: Sat, 20 Jul 2024 13:43:33 +0000 Subject: [PATCH 010/176] fr doc XML files updates. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919406 13f79535-47bb-0310-9956-ffa450edef68 --- docs/manual/mod/mod_rewrite.xml.fr | 10 +++++++++- docs/manual/rewrite/flags.xml.fr | 9 ++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/docs/manual/mod/mod_rewrite.xml.fr b/docs/manual/mod/mod_rewrite.xml.fr index 41e41d64fe..b484c60863 100644 --- a/docs/manual/mod/mod_rewrite.xml.fr +++ b/docs/manual/mod/mod_rewrite.xml.fr @@ -1,7 +1,7 @@ - + @@ -1647,6 +1647,14 @@ substitution ! détails ... +

    + + +
    Description:Ce module fournit un moteur de réécriture à base de règles permettant de réécrire les URLs des requêtes à la volée
    TraceEnable [on|off|extended] on sC
    Legt das Verhalten von TRACE-Anfragen fest
    TransferLog file|pipesvB
    Specify location of a log file
    TypesConfig file-path conf/mime.types sB
    The location of the mime.types file
    UNCListhostname ...sC
    Controls what UNC host names can be accessed by the server +
    UNCList hostname [hostname...]sC
    Controls what UNC host names can be accessed by the server
    UnDefine parameter-namesC
    Undefine the existence of a variable
    UndefMacro namesvdB
    Undefine a macro
    TraceEnable [on|off|extended] on sC
    Determines the behaviour on TRACE requests
    TransferLog file|pipesvB
    Specify location of a log file
    TypesConfig file-path conf/mime.types sB
    The location of the mime.types file
    UNCListhostname ...sC
    Controls what UNC host names can be accessed by the server +
    UNCList hostname [hostname...]sC
    Controls what UNC host names can be accessed by the server
    UnDefine parameter-namesC
    Undefine the existence of a variable
    UndefMacro namesvdB
    Undefine a macro
    TransferLog file|pipesvB
    ログファイルの位置を指定
    TypesConfig file-path conf/mime.types s
    mime.types ファイルの位置
    UNCListhostname ...sC
    Controls what UNC host names can be accessed by the server +
    UNCList hostname [hostname...]sC
    Controls what UNC host names can be accessed by the server
    UnDefine parameter-namesC
    Undefine the existence of a variable
    UndefMacro namesvdB
    Undefine a macro
    TraceEnable [on|off|extended] on svC
    Determines the behavior on TRACE requests
    TransferLog file|pipesvB
    α ġ Ѵ
    TypesConfig file-path conf/mime.types sB
    The location of the mime.types file
    UNCListhostname ...sC
    Controls what UNC host names can be accessed by the server +
    UNCList hostname [hostname...]sC
    Controls what UNC host names can be accessed by the server
    UnDefine parameter-namesC
    Undefine the existence of a variable
    UndefMacro namesvdB
    Undefine a macro
    TransferLog dosya|borulu-süreç [takma-ad]skT
    Bir günlük dosyasının yerini belirtir.
    TypesConfig file-path conf/mime.types sT
    The location of the mime.types file
    UNCListhostname ...sÇ
    Controls what UNC host names can be accessed by the server +
    UNCList hostname [hostname...]sÇ
    Controls what UNC host names can be accessed by the server
    UnDefine değişken-ismisÇ
    Bir değişkeni tanımsız yapar
    UndefMacro nameskdT
    Undefine a macro
    TraceEnable [on|off|extended] on svC
    Determines the behavior on TRACE requests
    TransferLog file|pipesvB
    Specify location of a log file
    TypesConfig file-path conf/mime.types sB
    The location of the mime.types file
    UNCListhostname ...sC
    Controls what UNC host names can be accessed by the server +
    UNCList hostname [hostname...]sC
    Controls what UNC host names can be accessed by the server
    UnDefine parameter-namesC
    Undefine the existence of a variable
    UndefMacro namesvdB
    Undefine a macro
    UNC + Empêche la fusion des slashes de début multiples tels que ceux utilisés + dans les chemins UNC de Windows. + détails ... +
    Développement du répertoire home diff --git a/docs/manual/rewrite/flags.xml.fr b/docs/manual/rewrite/flags.xml.fr index 4c775ac54c..e6681d0b1f 100644 --- a/docs/manual/rewrite/flags.xml.fr +++ b/docs/manual/rewrite/flags.xml.fr @@ -1,7 +1,7 @@ - + @@ -927,5 +927,12 @@ utiliser le drapeau L pour terminer la séquence emplacement non souhaité du système de fichiers.

    +
    UNC +

    Définir ce drapeau empêche la fusion des slashes de début multiples tels + que ceux utilisés dans les chemins UNC de Windows. Ce drapeau n’est pas + nécessaire lorsque la substitution de la règle commence par des slashes + multiples littéraux.

    +
    + From 50f5b4a1e8edb64df55440fbd7b4104b8d0a5b08 Mon Sep 17 00:00:00 2001 From: Lucien Gentis Date: Sat, 20 Jul 2024 13:44:57 +0000 Subject: [PATCH 011/176] fr doc rebuild. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919407 13f79535-47bb-0310-9956-ffa450edef68 --- docs/manual/mod/mod_rewrite.html.fr.utf8 | 10 ++++++++-- docs/manual/mod/mod_rewrite.xml.meta | 2 +- docs/manual/rewrite/flags.html.fr.utf8 | 12 +++++++++--- docs/manual/rewrite/flags.xml.meta | 2 +- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/docs/manual/mod/mod_rewrite.html.fr.utf8 b/docs/manual/mod/mod_rewrite.html.fr.utf8 index 41867ce911..32e5be75bd 100644 --- a/docs/manual/mod/mod_rewrite.html.fr.utf8 +++ b/docs/manual/mod/mod_rewrite.html.fr.utf8 @@ -29,8 +29,6 @@

    Langues Disponibles:  en  |  fr 

    -
    Cette traduction peut être périmée. Vérifiez la version - anglaise pour les changements récents.
    @@ -1579,6 +1577,14 @@ substitution ! détails ... + + + +
    Description:Ce module fournit un moteur de réécriture à base de règles permettant de réécrire les URLs des requêtes à la volée
    UNC + Empêche la fusion des slashes de début multiples tels que ceux utilisés + dans les chemins UNC de Windows. + détails ... +

    Développement du répertoire home

    diff --git a/docs/manual/mod/mod_rewrite.xml.meta b/docs/manual/mod/mod_rewrite.xml.meta index 0be21e86f4..decc0a7b1e 100644 --- a/docs/manual/mod/mod_rewrite.xml.meta +++ b/docs/manual/mod/mod_rewrite.xml.meta @@ -8,6 +8,6 @@ en - fr + fr diff --git a/docs/manual/rewrite/flags.html.fr.utf8 b/docs/manual/rewrite/flags.html.fr.utf8 index 35d76ccac5..6d6a05d786 100644 --- a/docs/manual/rewrite/flags.html.fr.utf8 +++ b/docs/manual/rewrite/flags.html.fr.utf8 @@ -26,8 +26,6 @@

    Langues Disponibles:  en  |  fr 

    -
    Cette traduction peut être périmée. Vérifiez la version - anglaise pour les changements récents.

    Ce document décrit les drapeaux disponibles dans la directive RewriteRule, en fournissant @@ -60,6 +58,7 @@ l'espace en +)

  • T|type
  • UnsafeAllow3F
  • UnsafePrefixStat
  • +
  • UNC
  • Voir aussi

    top
    @@ -900,7 +899,14 @@ utiliser le drapeau L pour terminer la séquence substitutions ne sont pas préfixées par la racine des documents. Cela protège d’une URL malveillante faisant correspondre la substitution expansée à un emplacement non souhaité du système de fichiers.

    - +
    top
    +
    +

    UNC

    +

    Définir ce drapeau empêche la fusion des slashes de début multiples tels + que ceux utilisés dans les chemins UNC de Windows. Ce drapeau n’est pas + nécessaire lorsque la substitution de la règle commence par des slashes + multiples littéraux.

    +

    Langues Disponibles:  en  |  fr 

    diff --git a/docs/manual/rewrite/flags.xml.meta b/docs/manual/rewrite/flags.xml.meta index e4f3ee6f49..912229af03 100644 --- a/docs/manual/rewrite/flags.xml.meta +++ b/docs/manual/rewrite/flags.xml.meta @@ -8,6 +8,6 @@ en - fr + fr From 06b32a39d093a8ccdbdcdd8a167c1faf5e21b0ef Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Tue, 23 Jul 2024 12:56:43 +0000 Subject: [PATCH 012/176] Merge r1919468 from trunk: use UNCList in UNC examples git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919470 13f79535-47bb-0310-9956-ffa450edef68 --- docs/manual/platform/windows.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/manual/platform/windows.xml b/docs/manual/platform/windows.xml index f68eaa0d12..1c11655ca5 100644 --- a/docs/manual/platform/windows.xml +++ b/docs/manual/platform/windows.xml @@ -609,22 +609,30 @@ RewriteRule "(.*)" "${lowercase:$1}" [R,L] Example DocumentRoot with UNC path + UNCList dochost DocumentRoot "//dochost/www/html/" Example DocumentRoot with IP address in UNC path + UNCList 192.168.1.50 DocumentRoot "//192.168.1.50/docs/" Example Alias and corresponding Directory with UNC path + +UNCList imagehost1 imagehost2 Alias "/images/" "//imagehost/www/images/" +Alias "/images2/" "//imagehost2/www/images/" <Directory "//imagehost/www/images/"> #... +</Directory> +<Directory "//imagehost2/www/images/"> +#... </Directory> From 2b278b9a35b5443701812b3a90d6b88516f86f2a Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Tue, 23 Jul 2024 12:56:59 +0000 Subject: [PATCH 013/176] xforms [skip ci] git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919471 13f79535-47bb-0310-9956-ffa450edef68 --- docs/manual/platform/windows.html.en | 13 ++++++++++--- docs/manual/platform/windows.xml.fr | 2 +- docs/manual/platform/windows.xml.ko | 2 +- docs/manual/platform/windows.xml.meta | 2 +- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/docs/manual/platform/windows.html.en b/docs/manual/platform/windows.html.en index d7e2b8638e..0e35c410d5 100644 --- a/docs/manual/platform/windows.html.en +++ b/docs/manual/platform/windows.html.en @@ -613,16 +613,23 @@ RewriteRule "(.*)" "${lowercase:$1}" [R,L] (Arcane and error prone procedures may work around the restriction on mapped drive letters, but this is not recommended.)

    -

    Example DocumentRoot with UNC path

    DocumentRoot "//dochost/www/html/"
    +

    Example DocumentRoot with UNC path

      UNCList dochost
    +  DocumentRoot "//dochost/www/html/"
    -

    Example DocumentRoot with IP address in UNC path

    DocumentRoot "//192.168.1.50/docs/"
    +

    Example DocumentRoot with IP address in UNC path

      UNCList 192.168.1.50
    +  DocumentRoot "//192.168.1.50/docs/"
    -

    Example Alias and corresponding Directory with UNC path

    Alias "/images/" "//imagehost/www/images/"
    +  

    Example Alias and corresponding Directory with UNC path

    UNCList imagehost1 imagehost2
    +Alias "/images/" "//imagehost/www/images/"
    +Alias "/images2/" "//imagehost2/www/images/"
     
     <Directory "//imagehost/www/images/">
     #...
    +</Directory>
    +<Directory "//imagehost2/www/images/">
    +#...
     </Directory>
    diff --git a/docs/manual/platform/windows.xml.fr b/docs/manual/platform/windows.xml.fr index 65835a6e6d..deba3bcb35 100644 --- a/docs/manual/platform/windows.xml.fr +++ b/docs/manual/platform/windows.xml.fr @@ -1,7 +1,7 @@ - + diff --git a/docs/manual/platform/windows.xml.ko b/docs/manual/platform/windows.xml.ko index b373c074ec..608441295e 100644 --- a/docs/manual/platform/windows.xml.ko +++ b/docs/manual/platform/windows.xml.ko @@ -1,7 +1,7 @@ - + + @@ -674,12 +674,14 @@ RewriteRule "(.*)" "${lowercase:$1}" [R,L] Exemple de DocumentRoot avec chemin UNC + UNCList dochost DocumentRoot "//dochost/www/html/" Exemple de DocumentRoot avec adresse IP dans le chemin UNC + UNCList 192.168.1.50 DocumentRoot "//192.168.1.50/docs/" @@ -687,10 +689,16 @@ RewriteRule "(.*)" "${lowercase:$1}" [R,L] Exemple d'Alias et répertoire correspondant avec chemin UNC + +UNCList imagehost1 imagehost2 Alias "/images/" "//imagehost/www/images/" +Alias "/images2/" "//imagehost2/www/images/" <Directory "//imagehost/www/images/"> #... +</Directory> +<Directory "//imagehost2/www/images/"> +#... </Directory> From cb266eda1810f18db521c1c5f048731a671ee091 Mon Sep 17 00:00:00 2001 From: Lucien Gentis Date: Fri, 26 Jul 2024 12:35:49 +0000 Subject: [PATCH 017/176] fr doc rebuild. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919529 13f79535-47bb-0310-9956-ffa450edef68 --- docs/manual/platform/windows.html.fr.utf8 | 13 ++++++++++--- docs/manual/platform/windows.xml.meta | 2 +- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/docs/manual/platform/windows.html.fr.utf8 b/docs/manual/platform/windows.html.fr.utf8 index 489cf7ffa7..bdafb63f8e 100644 --- a/docs/manual/platform/windows.html.fr.utf8 +++ b/docs/manual/platform/windows.html.fr.utf8 @@ -666,17 +666,24 @@ RewriteRule "(.*)" "${lowercase:$1}" [R,L]
    restriction due aux associations de lettres de lecteur, mais leur utilisation est déconseillée).

    -

    Exemple de DocumentRoot avec chemin UNC

    DocumentRoot "//dochost/www/html/"
    +

    Exemple de DocumentRoot avec chemin UNC

      UNCList dochost
    +  DocumentRoot "//dochost/www/html/"
    -

    Exemple de DocumentRoot avec adresse IP dans le chemin UNC

    DocumentRoot "//192.168.1.50/docs/"
    +

    Exemple de DocumentRoot avec adresse IP dans le chemin UNC

      UNCList 192.168.1.50
    +  DocumentRoot "//192.168.1.50/docs/"

    Exemple d'Alias et répertoire correspondant avec - chemin UNC

    Alias "/images/" "//imagehost/www/images/"
    +  chemin UNC
    UNCList imagehost1 imagehost2  
    +Alias "/images/" "//imagehost/www/images/"
    +Alias "/images2/" "//imagehost2/www/images/"
     
     <Directory "//imagehost/www/images/">
     #...
    +</Directory>
    +<Directory "//imagehost2/www/images/">
    +#...
     </Directory>
    diff --git a/docs/manual/platform/windows.xml.meta b/docs/manual/platform/windows.xml.meta index 166e6d7d31..df994e4ed6 100644 --- a/docs/manual/platform/windows.xml.meta +++ b/docs/manual/platform/windows.xml.meta @@ -8,7 +8,7 @@ en - fr + fr ko From d9c5d4b0ebb10dc474d54eb5f305e657bdbca1e6 Mon Sep 17 00:00:00 2001 From: Yann Ylavic Date: Fri, 26 Jul 2024 14:11:49 +0000 Subject: [PATCH 018/176] Vote x 1 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919531 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STATUS b/STATUS index 0fcf0a801b..e92a381aa9 100644 --- a/STATUS +++ b/STATUS @@ -224,7 +224,7 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: trunk patch: https://svn.apache.org/r1866894 2.4.x patch: https://github.com/apache/httpd/commit/d2cd162d79d532ae14d273e835b4b6799a185a98.patch PR: https://github.com/apache/httpd/pull/464 - +1: jorton, + +1: jorton, ylavic, PATCHES/ISSUES THAT ARE BEING WORKED From 591934e14f1e603ba3f69573b81f3af17b0aa746 Mon Sep 17 00:00:00 2001 From: Yann Ylavic Date: Sat, 27 Jul 2024 13:27:49 +0000 Subject: [PATCH 019/176] Trigger ci Merges r1919543 from trunk git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919544 13f79535-47bb-0310-9956-ffa450edef68 --- .github/workflows/linux.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 1a883c8c23..cbc6fd55d6 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -29,7 +29,7 @@ jobs: strategy: fail-fast: false matrix: - include: + include: # ------------------------------------------------------------------------- - name: Empty APLOGNO() test env: | From a0a68b99d131741c1867cff321424892838fc4b3 Mon Sep 17 00:00:00 2001 From: Yann Ylavic Date: Sat, 27 Jul 2024 13:35:53 +0000 Subject: [PATCH 020/176] mod_rewrite: Better question mark tracking to avoid UnsafeAllow3F. PR 69197. Track in do_expand() whether a '?' in the uri-path comes from a literal in the substitution string or from an expansion (variable, lookup, ...). In the former case it's safe to assume that it's the query-string separator but for the other case it's not (could be a decoded %3f from r->uri). This allows to avoid [UnsafeAllow3F] for most cases. Merges r1919325 from trunk Reviewed by: ylavic, covener, jorton Github: closes #462 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919545 13f79535-47bb-0310-9956-ffa450edef68 --- modules/mappers/mod_rewrite.c | 107 ++++++++++++++++++++++++++++------ 1 file changed, 89 insertions(+), 18 deletions(-) diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c index f1c22e3235..53fb1e91ff 100644 --- a/modules/mappers/mod_rewrite.c +++ b/modules/mappers/mod_rewrite.c @@ -2376,9 +2376,16 @@ static APR_INLINE char *find_char_in_curlies(char *s, int c) * of an earlier expansion to include expansion specifiers that * are interpreted by a later expansion, producing results that * were not intended by the administrator. + * + * unsafe_qmark if not NULL will be set to 1 or 0 if a question mark + * is found respectively in a literal or in a lookup/expansion (whether + * it's the first or last qmark depends on [QSL]). Should be initialized + * to -1 and remains so if no qmark is found. */ -static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry) +static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry, + int *unsafe_qmark) { +#define EXPAND_SPECIALS "\\$%" result_list *result, *current; result_list sresult[SMALL_EXPANSION]; unsigned spc = 0; @@ -2386,8 +2393,29 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry) char *p, *c; apr_pool_t *pool = ctx->r->pool; - span = strcspn(input, "\\$%"); inputlen = strlen(input); + if (!unsafe_qmark) { + span = strcspn(input, EXPAND_SPECIALS); + } + else { + span = strcspn(input, EXPAND_SPECIALS "?"); + if (input[span] == '?') { + /* this qmark is not from an expansion thus safe */ + *unsafe_qmark = 0; + + /* keep tracking only if interested in the last qmark */ + if (entry && (entry->flags & RULEFLAG_QSLAST)) { + do { + span++; + span += strcspn(input + span, EXPAND_SPECIALS "?"); + } while (input[span] == '?'); + } + else { + unsafe_qmark = NULL; + span += strcspn(input + span, EXPAND_SPECIALS); + } + } + } /* fast exit */ if (inputlen == span) { @@ -2405,6 +2433,8 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry) /* loop for specials */ do { + int expanded = 0; + /* prepare next entry */ if (current->len) { current->next = (spc < SMALL_EXPANSION) @@ -2450,6 +2480,8 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry) current->len = span; current->string = p; outlen += span; + + expanded = 1; p = endp + 1; } @@ -2489,19 +2521,18 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry) } /* reuse of key variable as result */ - key = lookup_map(ctx->r, map, do_expand(key, ctx, entry)); - + key = lookup_map(ctx->r, map, do_expand(key, ctx, entry, NULL)); if (!key && dflt && *dflt) { - key = do_expand(dflt, ctx, entry); + key = do_expand(dflt, ctx, entry, NULL); } - - if (key) { + if (key && *key) { span = strlen(key); current->len = span; current->string = key; outlen += span; } + expanded = 1; p = endp + 1; } } @@ -2531,8 +2562,9 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry) current->len = span; current->string = bri->source + bri->regmatch[n].rm_so; } - outlen += span; + + expanded = 1; } p += 2; @@ -2545,8 +2577,41 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry) ++outlen; } + if (unsafe_qmark && expanded && current->len + && memchr(current->string, '?', current->len)) { + /* this qmark is from an expansion thus unsafe */ + *unsafe_qmark = 1; + + /* keep tracking only if interested in the last qmark */ + if (!entry || !(entry->flags & RULEFLAG_QSLAST)) { + unsafe_qmark = NULL; + } + } + /* check the remainder */ - if (*p && (span = strcspn(p, "\\$%")) > 0) { + if (!unsafe_qmark) { + span = strcspn(p, EXPAND_SPECIALS); + } + else { + span = strcspn(p, EXPAND_SPECIALS "?"); + if (p[span] == '?') { + /* this qmark is not from an expansion thus safe */ + *unsafe_qmark = 0; + + /* keep tracking only if interested in the last qmark */ + if (entry && (entry->flags & RULEFLAG_QSLAST)) { + do { + span++; + span += strcspn(p + span, EXPAND_SPECIALS "?"); + } while (p[span] == '?'); + } + else { + unsafe_qmark = NULL; + span += strcspn(p + span, EXPAND_SPECIALS); + } + } + } + if (span > 0) { if (current->len) { current->next = (spc < SMALL_EXPANSION) ? &(sresult[spc++]) @@ -2591,7 +2656,7 @@ static void do_expand_env(data_item *env, rewrite_ctx *ctx) char *name, *val; while (env) { - name = do_expand(env->data, ctx, NULL); + name = do_expand(env->data, ctx, NULL, NULL); if (*name == '!') { name++; apr_table_unset(ctx->r->subprocess_env, name); @@ -2725,7 +2790,7 @@ static void add_cookie(request_rec *r, char *s) static void do_expand_cookie(data_item *cookie, rewrite_ctx *ctx) { while (cookie) { - add_cookie(ctx->r, do_expand(cookie->data, ctx, NULL)); + add_cookie(ctx->r, do_expand(cookie->data, ctx, NULL, NULL)); cookie = cookie->next; } @@ -4014,7 +4079,7 @@ static int apply_rewrite_cond(rewritecond_entry *p, rewrite_ctx *ctx) int basis; if (p->ptype != CONDPAT_AP_EXPR) - input = do_expand(p->input, ctx, NULL); + input = do_expand(p->input, ctx, NULL, NULL); switch (p->ptype) { case CONDPAT_FILE_EXISTS: @@ -4178,7 +4243,7 @@ static APR_INLINE void force_type_handler(rewriterule_entry *p, char *expanded; if (p->forced_mimetype) { - expanded = do_expand(p->forced_mimetype, ctx, p); + expanded = do_expand(p->forced_mimetype, ctx, p, NULL); if (*expanded) { ap_str_tolower(expanded); @@ -4192,7 +4257,7 @@ static APR_INLINE void force_type_handler(rewriterule_entry *p, } if (p->forced_handler) { - expanded = do_expand(p->forced_handler, ctx, p); + expanded = do_expand(p->forced_handler, ctx, p, NULL); if (*expanded) { ap_str_tolower(expanded); @@ -4329,12 +4394,18 @@ static rule_return_type apply_rewrite_rule(rewriterule_entry *p, /* expand the result */ if (!(p->flags & RULEFLAG_NOSUB)) { - newuri = do_expand(p->output, ctx, p); + int unsafe_qmark = -1; + + if (p->flags & RULEFLAG_UNSAFE_ALLOW3F) { + newuri = do_expand(p->output, ctx, p, NULL); + } + else { + newuri = do_expand(p->output, ctx, p, &unsafe_qmark); + } rewritelog((r, 2, ctx->perdir, "rewrite '%s' -> '%s'", ctx->uri, newuri)); - if (!(p->flags & RULEFLAG_UNSAFE_ALLOW3F) && - ap_strcasestr(r->unparsed_uri, "%3f") && - ap_strchr_c(newuri, '?')) { + + if (unsafe_qmark > 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10508) "Unsafe URL with %%3f URL rewritten without " "UnsafeAllow3F"); From 0f6944358cf468d7d80bd63f33fbed7c4c0c6311 Mon Sep 17 00:00:00 2001 From: Yann Ylavic Date: Sat, 27 Jul 2024 13:36:31 +0000 Subject: [PATCH 021/176] Backported in r1919545. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919546 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 8 -------- 1 file changed, 8 deletions(-) diff --git a/STATUS b/STATUS index e92a381aa9..c0a28ac350 100644 --- a/STATUS +++ b/STATUS @@ -186,14 +186,6 @@ PATCHES ACCEPTED TO BACKPORT FROM TRUNK: 2.4.x patch: svn merge -c r1902366 ^/httpd/httpd/trunk . +1: ivan, ylavic, covener - *) mod_rewrite: Better question mark tracking to avoid UnsafeAllow3F. PR 69197. - Trunk version of patch: - https://svn.apache.org/r1919325 - 2.4.x version of patch: - https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/462.diff - PR: https://github.com/apache/httpd/pull/462 - +1: ylavic, covener, jorton - PATCHES PROPOSED TO BACKPORT FROM TRUNK: [ New proposals should be added at the end of the list ] From 8ace8c7fc931a5e1cb26eba8bf476323917dc6b6 Mon Sep 17 00:00:00 2001 From: Yann Ylavic Date: Sat, 27 Jul 2024 14:18:49 +0000 Subject: [PATCH 022/176] Merge r1918003, r1918022, r1918035, r1918078, r1918098, r1918099, r1918257, r1918482, r1918483, r1918491, r1919141, r1919148 from trunk *) mod_http2: sync with module's github. - on newer HTTPD versions, return connection monitoring to the event MPM when block on client updates. 2.4.x versions still treat connections in the event MPM as KeepAlive and purge them on load in the middle of response processing. - spelling fixes - support for yield calls in c2 "network" filter mpm_event,core: Handle async POLLIN/POLLOUT in CONN_STATE_PROCESS state. * include/httpd.h: Rename CONN_STATE_CHECK_REQUEST_LINE_READABLE to CONN_STATE_KEEPALIVE and CONN_STATE_READ_REQUEST_LINE to CONN_STATE_PROCESS, keeping the old enums as aliases. Rework comments about each state. * server/mpm/event/event.c: Use the new states names. Let the process_connection hooks return CONN_STATE_PROCESS for mpm_event to POLLIN or POLLOUT depending on c->cs->sense being CONN_SENSE_WANT_READ or CONN_SENSE_WANT_WRITE respectively. Remove (ab)use of CONN_STATE_WRITE_COMPLETION with CONN_SENSE_WANT_READ to mean poll() for read (and the need for the obscure c->clogging_input_filters to make it work as expected). This is what CONN_STATE_PROCESS is for now. Update the comment about the states that can be returned by process_connection hooks (and their usage). Use the same queue (process_q renamed from write_completion_q) for polling connections in both CONN_STATE_PROCESS and CONN_STATE_WRITE_COMPLETION states since they both use the same (server_rec's) Timeout. This implies that both states are accounted as "write-completion" in mod_status for now. * server/mpm/motorz/motorz.c, server/mpm/simple/simple_io.c, modules/http/http_core.c: Use the new states names (only). * include/scoreboard.h: Change comment about process_score->write_completion to note that the counter refers to CONN_STATE_PROCESS connections returned to the MPM too. * modules/http2/h2_c1.c: Return the c1 connection with the CONN_STATE_PROCESS state rather than CONN_STATE_WRITE_COMPLETION when waiting for a window update (i.e. ask the MPM to poll for read directly). This avoids the transition to CONN_STATE_KEEPALIVE which could kill the connection under high load. Github: closes #448 Follow up to r1918022: MMN minor bump and checks for the new conn_state_e aliases' usability. mpm_event: Don't spam with "Stopping process due to MaxConnectionsPerChild" When MaxConnectionsPerChild is reached there may be some connections to process still and the listener should stop writing this at every loop. Logging once is enough. * server/mpm/event/event.c(check_infinite_requests): Raise conns_this_child unconditionally. mpm_event, mod_status: Separate processing and write completion queues. As a follow up to r1918022 which handled the new CONN_STATE_PROCESS(ing) and existing CONN_STATE_WRITE_COMPLETION in the same async queue, let's now have two separates ones which allows more relevant async accounting in mod_status. Rename CONN_STATE_PROCESS to CONN_STATE_PROCESSING as it's how it will be called in mod_status. * include/ap_mmn.h: MMN minor bump for process_score->processing counter. * include/httpd.h: Rename CONN_STATE_PROCESS to CONN_STATE_PROCESSING. * include/scoreboard.h: Add process_score->processing field. * include/httpd.h, modules/http/http_core.c, modules/http2/h2_c1.c, server/mpm/event/event.c, server/mpm/motorz/motorz.c, server/mpm/simple/simple_io.c: Rename CONN_STATE_PROCESS to CONN_STATE_PROCESSING. * server/mpm/event/event.c: Restore write_completion_q to handle connections in CONN_STATE_WRITE_COMPLETION. Use processing_q (renamed from process_q) solely for CONN_STATE_PROCESSING. Update process_score->processing according to the length of processing_q. * modules/generators/mod_status.c: Show the value of process_score->processing in the stats. Follow up to r1918098 (and r1918022): Push missing changes. mpm_event,mod_http2: Keep compatibility with CONN_STATE_PROCESSING + OK Before r1918022, returning OK with CONN_STATE_PROCESSING to mpm_event was handled like/by CONN_STATE_LINGER "to not break old or third-party modules which might return OK w/o touching the state and expect lingering close, like with worker or prefork MPMs". So we need a new return code to be allowed to apply the new POLLIN/POLLOUT behaviour for CONN_STATE_PROCESSING, thus revive AGAIN as introduced by Graham some times ago for a nonblocking WIP (moved to a branch/PR since then). MPM event will advertise its ability to handle CONN_STATE_PROCESSING + AGAIN with AP_MPMQ_CAN_AGAIN, and mod_http2 can use that to know how to return to the MPM as expected. When !AP_MPMQ_CAN_AGAIN modules/mod_http2 can still use CONN_STATE_WRITE_COMPLETION + CONN_SENSE_WANT_READ + c->clogging_input_filters which will work in mpm_even-2.4.x still. * include/ap_mmn.h: Bump MMN minor for AP_MPMQ_CAN_AGAIN and AGAIN. * include/ap_mpm.h: Define AP_MPMQ_CAN_AGAIN. * include/httpd.h: Define AGAIN. * modules/http2/h2.h: No need for H2_USE_STATE_PROCESSING anymore with AP_MPMQ_CAN_AGAIN. * modules/http2/h2_c1.c: For !keepalive case return to the MPM using CONN_STATE_PROCESSING + AGAIN or CONN_STATE_WRITE_COMPLETION + c->clogging_input_filters depending on AP_MPMQ_CAN_AGAIN only. * modules/http2/h2_session.c: Can return to the MPM for h2_send_flow_blocked() provided it's async only. * server/mpm/event/event.c: Rework process_socket()'s CONN_STATE_PROCESSING to handle AGAIN and preserve compatibility. Have a lingering_close label to goto there faster when process_lingering_close() is to be called. Improve relevant comments. mpm_event,mod_http2,mod_status: Follow up to r1918257: CONN_STATE_ASYNC_WAITIO. Per discussion on PR #449, have a separate state for returning the connection to the MPM to wait for an IO (namely CONN_STATE_ASYNC_WAITIO), rather than (ab)using CONN_STATE_PROCESSING. This removes the need for AGAIN added in r1918257 (for now), and AP_MPMQ_CAN_AGAIN is renamed to AP_MPMQ_CAN_WAITIO. This is also the state that mod_status accounts for, so rename ->processing to ->wait_io in process_score (shows as "wait-io" in mod_status and mod_lua). mpm_event: Follow up to r1918482: CONN_STATE_ASYNC_WAITIO > CONN_STATE_LINGER. mpm_event: Follow up to r1918482: CONN_STATE_LINGER* are not the last anymore. Since CONN_STATE_ASYNC_WAITIO, we cannot check for < or >= CONN_STATE_LINGER anymore to determine if in an lingering close state, so let's add a new CONN_STATE_IS_LINGERING_CLOSE() macro for this and use it in mpm_event. The test for state == CONN_STATE_LINGER in process_lingering_close() is a bit weak too in order to call ap_start_lingering_close() the first time only, so have a conn_state->linger_started flag instead. mod_status: Follow up to r1918482: Bump colspan for the new wait-io colomn mod_status: "Threads" span three colomns (busy, graceful, idle), not two. Submitted by: icing, ylavic, ylavic, ylavic, ylavic, ylavic, ylavic, ylavic, ylavic, ylavic, ylavic, ylavic Reviewed by: ylavic, icing, gbechis Github: closes #449 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919548 13f79535-47bb-0310-9956-ffa450edef68 --- include/ap_mmn.h | 6 +- include/ap_mpm.h | 3 + include/httpd.h | 43 ++-- include/scoreboard.h | 3 +- modules/generators/mod_status.c | 22 +- modules/http/http_core.c | 4 +- modules/http2/h2_c1.c | 65 ++++-- modules/http2/h2_mplx.c | 24 +++ modules/http2/h2_mplx.h | 5 + modules/http2/h2_session.c | 44 +++- modules/http2/h2_session.h | 5 +- modules/http2/h2_version.h | 4 +- modules/lua/lua_request.c | 4 + server/mpm/event/event.c | 364 ++++++++++++++++++++------------ 14 files changed, 399 insertions(+), 197 deletions(-) diff --git a/include/ap_mmn.h b/include/ap_mmn.h index 00475bf5df..85dd97d099 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -603,6 +603,10 @@ * and AP_REQUEST_TRUSTED_CT BNOTE. * 20120211.133 (2.4.60-dev) Add ap_proxy_fixup_uds_filename() * 20120211.134 (2.4.60-dev) AP_SLASHES and AP_IS_SLASH + * 20120211.135 (2.4.59-dev) Add CONN_STATE_ASYNC_WAITIO, CONN_STATE_KEEPALIVE + * and CONN_STATE_PROCESSING + * 20120211.136 (2.4.59-dev) Add wait_io field to struct process_score + * 20120211.137 (2.4.59-dev) Add AP_MPMQ_CAN_WAITIO */ #define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */ @@ -610,7 +614,7 @@ #ifndef MODULE_MAGIC_NUMBER_MAJOR #define MODULE_MAGIC_NUMBER_MAJOR 20120211 #endif -#define MODULE_MAGIC_NUMBER_MINOR 134 /* 0...n */ +#define MODULE_MAGIC_NUMBER_MINOR 137 /* 0...n */ /** * Determine if the server's current MODULE_MAGIC_NUMBER is at least a diff --git a/include/ap_mpm.h b/include/ap_mpm.h index e3a58aa2a3..158496fd7a 100644 --- a/include/ap_mpm.h +++ b/include/ap_mpm.h @@ -178,6 +178,9 @@ AP_DECLARE(apr_status_t) ap_os_create_privileged_process( #define AP_MPMQ_GENERATION 15 /** MPM can drive serf internally */ #define AP_MPMQ_HAS_SERF 16 +/* 17-18 are trunk only */ +/** MPM supports CONN_STATE_ASYNC_WAITIO */ +#define AP_MPMQ_CAN_WAITIO 19 /** @} */ /** diff --git a/include/httpd.h b/include/httpd.h index 3aa05ba64a..21a91f3724 100644 --- a/include/httpd.h +++ b/include/httpd.h @@ -453,13 +453,13 @@ AP_DECLARE(const char *) ap_get_server_built(void); /* non-HTTP status codes returned by hooks */ -#define OK 0 /**< Module has handled this stage. */ -#define DECLINED -1 /**< Module declines to handle */ -#define DONE -2 /**< Module has served the response completely - * - it's safe to die() with no more output - */ -#define SUSPENDED -3 /**< Module will handle the remainder of the request. - * The core will never invoke the request again, */ +#define OK 0 /**< Module has handled this stage. */ +#define DECLINED -1 /**< Module declines to handle */ +#define DONE -2 /**< Module has served the response completely + * - it's safe to die() with no more output + */ +#define SUSPENDED -3 /**< Module will handle the remainder of the request. + * The core will never invoke the request again */ /** Returned by the bottom-most filter if no data was written. * @see ap_pass_brigade(). */ @@ -1256,16 +1256,25 @@ struct conn_rec { * only be set by the MPM. Use CONN_STATE_LINGER outside of the MPM. */ typedef enum { - CONN_STATE_CHECK_REQUEST_LINE_READABLE, - CONN_STATE_READ_REQUEST_LINE, - CONN_STATE_HANDLER, - CONN_STATE_WRITE_COMPLETION, - CONN_STATE_SUSPENDED, - CONN_STATE_LINGER, /* connection may be closed with lingering */ - CONN_STATE_LINGER_NORMAL, /* MPM has started lingering close with normal timeout */ - CONN_STATE_LINGER_SHORT, /* MPM has started lingering close with short timeout */ - - CONN_STATE_NUM /* Number of states (keep/kept last) */ + CONN_STATE_KEEPALIVE, /* Kept alive in the MPM (using KeepAliveTimeout) */ + CONN_STATE_PROCESSING, /* Processed by process_connection hooks */ + CONN_STATE_HANDLER, /* Processed by the modules handlers */ + CONN_STATE_WRITE_COMPLETION, /* Flushed by the MPM before entering CONN_STATE_KEEPALIVE */ + CONN_STATE_SUSPENDED, /* Suspended in the MPM until ap_run_resume_suspended() */ + CONN_STATE_LINGER, /* MPM flushes then closes the connection with lingering */ + CONN_STATE_LINGER_NORMAL, /* MPM has started lingering close with normal timeout */ + CONN_STATE_LINGER_SHORT, /* MPM has started lingering close with short timeout */ + + CONN_STATE_ASYNC_WAITIO, /* Returning this state to the MPM will make it wait for + * the connection to be readable or writable according to + * c->cs->sense (resp. CONN_SENSE_WANT_READ or _WRITE), + * using the configured Timeout */ + + CONN_STATE_NUM, /* Number of states (keep here before aliases) */ + + /* Aliases (legacy) */ + CONN_STATE_CHECK_REQUEST_LINE_READABLE = CONN_STATE_KEEPALIVE, + CONN_STATE_READ_REQUEST_LINE = CONN_STATE_PROCESSING, } conn_state_e; typedef enum { diff --git a/include/scoreboard.h b/include/scoreboard.h index 0142aa9204..4af9132031 100644 --- a/include/scoreboard.h +++ b/include/scoreboard.h @@ -144,13 +144,14 @@ struct process_score { * connections (for async MPMs) */ apr_uint32_t connections; /* total connections (for async MPMs) */ - apr_uint32_t write_completion; /* async connections doing write completion */ + apr_uint32_t write_completion; /* async connections in write completion */ apr_uint32_t lingering_close; /* async connections in lingering close */ apr_uint32_t keep_alive; /* async connections in keep alive */ apr_uint32_t suspended; /* connections suspended by some module */ int bucket; /* Listener bucket used by this child; this field is DEPRECATED * and no longer updated by the MPMs (i.e. always zero). */ + apr_uint32_t wait_io; /* async connections waiting an IO in the MPM */ }; /* Scoreboard is now in 'local' memory, since it isn't updated once created, diff --git a/modules/generators/mod_status.c b/modules/generators/mod_status.c index 2cb38c747f..c1c856d41d 100644 --- a/modules/generators/mod_status.c +++ b/modules/generators/mod_status.c @@ -564,7 +564,7 @@ static int status_handler(request_rec *r) ap_rputs("", r); if (is_async) { - int write_completion = 0, lingering_close = 0, keep_alive = 0, + int wait_io = 0, write_completion = 0, lingering_close = 0, keep_alive = 0, connections = 0, stopping = 0, procs = 0; if (!short_report) ap_rputs("\n\n\n" @@ -572,15 +572,17 @@ static int status_handler(request_rec *r) "" "" "\n" - "" - "\n" + "" + "\n" "" "" - "\n", r); + "" + "\n", r); for (i = 0; i < server_limit; ++i) { ps_record = ap_get_scoreboard_process(i); if (ps_record->pid) { connections += ps_record->connections; + wait_io += ps_record->wait_io; write_completion += ps_record->write_completion; keep_alive += ps_record->keep_alive; lingering_close += ps_record->lingering_close; @@ -600,7 +602,7 @@ static int status_handler(request_rec *r) "" "" "" - "" + "" "\n", i, ps_record->pid, dying, old, @@ -609,6 +611,7 @@ static int status_handler(request_rec *r) thread_busy_buffer[i], thread_graceful_buffer[i], thread_idle_buffer[i], + ps_record->wait_io, ps_record->write_completion, ps_record->keep_alive, ps_record->lingering_close); @@ -620,23 +623,26 @@ static int status_handler(request_rec *r) "" "" "" - "" + "" "\n
    PIDStoppingConnectionsThreadsAsync connections
    ThreadsAsync connections
    totalacceptingbusygracefulidlewritingkeep-aliveclosing
    wait-iowritingkeep-aliveclosing
    %s%s%u%s%u%u%u%u%u%u%u%u%u%u
    %d%d%d %d%d%d%d%d%d%d%d%d%d
    \n", procs, stopping, connections, busy, graceful, idle, - write_completion, keep_alive, lingering_close); + wait_io, write_completion, keep_alive, + lingering_close); } else { ap_rprintf(r, "Processes: %d\n" "Stopping: %d\n" "ConnsTotal: %d\n" + "ConnsAsyncWaitIO: %d\n" "ConnsAsyncWriting: %d\n" "ConnsAsyncKeepAlive: %d\n" "ConnsAsyncClosing: %d\n", procs, stopping, connections, - write_completion, keep_alive, lingering_close); + wait_io, write_completion, keep_alive, + lingering_close); } } diff --git a/modules/http/http_core.c b/modules/http/http_core.c index c6cb473dbc..a86465085d 100644 --- a/modules/http/http_core.c +++ b/modules/http/http_core.c @@ -138,9 +138,9 @@ static int ap_process_http_async_connection(conn_rec *c) conn_state_t *cs = c->cs; AP_DEBUG_ASSERT(cs != NULL); - AP_DEBUG_ASSERT(cs->state == CONN_STATE_READ_REQUEST_LINE); + AP_DEBUG_ASSERT(cs->state == CONN_STATE_PROCESSING); - if (cs->state == CONN_STATE_READ_REQUEST_LINE) { + if (cs->state == CONN_STATE_PROCESSING) { ap_update_child_status_from_conn(c->sbh, SERVER_BUSY_READ, c); if (ap_extended_status) { ap_set_conn_count(c->sbh, r, c->keepalives); diff --git a/modules/http2/h2_c1.c b/modules/http2/h2_c1.c index afb26fc073..626e665b3f 100644 --- a/modules/http2/h2_c1.c +++ b/modules/http2/h2_c1.c @@ -47,23 +47,25 @@ static struct h2_workers *workers; -static int async_mpm; +static int async_mpm, mpm_can_waitio; APR_OPTIONAL_FN_TYPE(ap_logio_add_bytes_in) *h2_c_logio_add_bytes_in; APR_OPTIONAL_FN_TYPE(ap_logio_add_bytes_out) *h2_c_logio_add_bytes_out; apr_status_t h2_c1_child_init(apr_pool_t *pool, server_rec *s) { - apr_status_t status = APR_SUCCESS; int minw, maxw; apr_time_t idle_limit; - status = ap_mpm_query(AP_MPMQ_IS_ASYNC, &async_mpm); - if (status != APR_SUCCESS) { + if (ap_mpm_query(AP_MPMQ_IS_ASYNC, &async_mpm)) { /* some MPMs do not implemnent this */ async_mpm = 0; - status = APR_SUCCESS; } +#ifdef AP_MPMQ_CAN_WAITIO + if (!async_mpm || ap_mpm_query(AP_MPMQ_CAN_WAITIO, &mpm_can_waitio)) { + mpm_can_waitio = 0; + } +#endif h2_config_init(pool); @@ -113,23 +115,22 @@ apr_status_t h2_c1_setup(conn_rec *c, request_rec *r, server_rec *s) return rv; } -apr_status_t h2_c1_run(conn_rec *c) +int h2_c1_run(conn_rec *c) { apr_status_t status; - int mpm_state = 0; + int mpm_state = 0, keepalive = 0; h2_conn_ctx_t *conn_ctx = h2_conn_ctx_get(c); ap_assert(conn_ctx); ap_assert(conn_ctx->session); + c->clogging_input_filters = 0; do { if (c->cs) { - c->cs->sense = CONN_SENSE_DEFAULT; c->cs->state = CONN_STATE_HANDLER; } - status = h2_session_process(conn_ctx->session, async_mpm); - - if (APR_STATUS_IS_EOF(status)) { + status = h2_session_process(conn_ctx->session, async_mpm, &keepalive); + if (status != APR_SUCCESS) { ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, c, H2_SSSN_LOG(APLOGNO(03045), conn_ctx->session, "process, closing conn")); @@ -152,24 +153,51 @@ apr_status_t h2_c1_run(conn_rec *c) case H2_SESSION_ST_IDLE: case H2_SESSION_ST_BUSY: case H2_SESSION_ST_WAIT: - c->cs->state = CONN_STATE_WRITE_COMPLETION; - if (c->cs && !conn_ctx->session->remote.emitted_count) { - /* let the MPM know that we are not done and want - * the Timeout behaviour instead of a KeepAliveTimeout + if (keepalive) { + /* Flush then keep-alive */ + c->cs->sense = CONN_SENSE_DEFAULT; + c->cs->state = CONN_STATE_WRITE_COMPLETION; + } + else { + /* Let the MPM know that we are not done and want to wait + * for read using Timeout instead of KeepAliveTimeout. * See PR 63534. */ c->cs->sense = CONN_SENSE_WANT_READ; +#ifdef AP_MPMQ_CAN_WAITIO + if (mpm_can_waitio) { + /* This tells the MPM to wait for the connection to be + * readable (CONN_SENSE_WANT_READ) within the configured + * Timeout and then come back to the process_connection() + * hooks again when ready. + */ + c->cs->state = CONN_STATE_ASYNC_WAITIO; + } + else +#endif + { + /* This is a compat workaround to do the same using the + * CONN_STATE_WRITE_COMPLETION state but with both + * CONN_SENSE_WANT_READ to wait for readability rather + * than writing and c->clogging_input_filters to force + * reentering the process_connection() hooks from any + * state when ready. This somehow will use Timeout too. + */ + c->cs->state = CONN_STATE_WRITE_COMPLETION; + c->clogging_input_filters = 1; + } } break; + case H2_SESSION_ST_CLEANUP: case H2_SESSION_ST_DONE: default: c->cs->state = CONN_STATE_LINGER; - break; + break; } } - return APR_SUCCESS; + return OK; } apr_status_t h2_c1_pre_close(struct h2_conn_ctx_t *ctx, conn_rec *c) @@ -275,8 +303,7 @@ static int h2_c1_hook_process_connection(conn_rec* c) return !OK; } } - h2_c1_run(c); - return OK; + return h2_c1_run(c); declined: ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "h2_h2, declined"); diff --git a/modules/http2/h2_mplx.c b/modules/http2/h2_mplx.c index 2aeea42b5d..b5153082b5 100644 --- a/modules/http2/h2_mplx.c +++ b/modules/http2/h2_mplx.c @@ -397,6 +397,7 @@ apr_status_t h2_mplx_c1_streams_do(h2_mplx *m, h2_mplx_stream_cb *cb, void *ctx) typedef struct { int stream_count; int stream_want_send; + int stream_send_win_exhausted; } stream_iter_aws_t; static int m_stream_want_send_data(void *ctx, void *stream) @@ -419,6 +420,29 @@ int h2_mplx_c1_all_streams_want_send_data(h2_mplx *m) return x.stream_count && (x.stream_count == x.stream_want_send); } +static int m_stream_send_win_exh(void *ctx, void *s) +{ + h2_stream *stream = s; + int win; + stream_iter_aws_t *x = ctx; + ++x->stream_count; + win = nghttp2_session_get_stream_remote_window_size(stream->session->ngh2, stream->id); + if (win == 0) + ++x->stream_send_win_exhausted; + return 1; +} + +int h2_mplx_c1_all_streams_send_win_exhausted(h2_mplx *m) +{ + stream_iter_aws_t x; + x.stream_count = 0; + x.stream_send_win_exhausted = 0; + H2_MPLX_ENTER(m); + h2_ihash_iter(m->streams, m_stream_send_win_exh, &x); + H2_MPLX_LEAVE(m); + return x.stream_count && (x.stream_count == x.stream_send_win_exhausted); +} + static int m_report_stream_iter(void *ctx, void *val) { h2_mplx *m = ctx; h2_stream *stream = val; diff --git a/modules/http2/h2_mplx.h b/modules/http2/h2_mplx.h index 860f916039..12e36f766f 100644 --- a/modules/http2/h2_mplx.h +++ b/modules/http2/h2_mplx.h @@ -196,6 +196,11 @@ apr_status_t h2_mplx_c1_streams_do(h2_mplx *m, h2_mplx_stream_cb *cb, void *ctx) */ int h2_mplx_c1_all_streams_want_send_data(h2_mplx *m); +/** + * Return != 0 iff all open streams have send window exhausted + */ +int h2_mplx_c1_all_streams_send_win_exhausted(h2_mplx *m); + /** * A stream has been RST_STREAM by the client. Abort * any processing going on and remove from processing diff --git a/modules/http2/h2_session.c b/modules/http2/h2_session.c index 5724fdadb0..ba248d0cc2 100644 --- a/modules/http2/h2_session.c +++ b/modules/http2/h2_session.c @@ -323,8 +323,8 @@ static int on_header_cb(nghttp2_session *ngh2, const nghttp2_frame *frame, (!stream->rtmp || stream->rtmp->http_status == H2_HTTP_STATUS_UNSET || /* We accept a certain amount of failures in order to reply - * with an informative HTTP error response like 413. But if the - * client is too wrong, we fail the request a RESET of the stream */ + * with an informative HTTP error response like 413. But of the + * client is too wrong, we RESET the stream */ stream->request_headers_failed > 100)) { return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; } @@ -1762,12 +1762,22 @@ static void unblock_c1_out(h2_session *session) { } } -apr_status_t h2_session_process(h2_session *session, int async) +static int h2_send_flow_blocked(h2_session *session) +{ + /* We are completely send blocked if either the connection window + * is 0 or all stream flow windows are 0. */ + return ((nghttp2_session_get_remote_window_size(session->ngh2) <= 0) || + h2_mplx_c1_all_streams_send_win_exhausted(session->mplx)); +} + +apr_status_t h2_session_process(h2_session *session, int async, + int *pkeepalive) { apr_status_t status = APR_SUCCESS; conn_rec *c = session->c1; int rv, mpm_state, trace = APLOGctrace3(c); + *pkeepalive = 0; if (trace) { ap_log_cerror( APLOG_MARK, APLOG_TRACE3, status, c, H2_SSSN_MSG(session, "process start, async=%d"), async); @@ -1922,6 +1932,14 @@ apr_status_t h2_session_process(h2_session *session, int async) break; case H2_SESSION_ST_WAIT: + /* In this state, we might have returned processing to the MPM + * before. On a connection socket event, we are invoked again and + * need to process any input before proceeding. */ + h2_c1_read(session); + if (session->state != H2_SESSION_ST_WAIT) { + break; + } + status = h2_c1_io_assure_flushed(&session->io); if (APR_SUCCESS != status) { h2_session_dispatch_event(session, H2_SESSION_EV_CONN_ERROR, status, NULL); @@ -1934,8 +1952,16 @@ apr_status_t h2_session_process(h2_session *session, int async) break; } } - /* No IO happening and input is exhausted. Make sure we have - * flushed any possibly pending output and then wait with + else if (async && h2_send_flow_blocked(session)) { + /* By returning to the MPM, we do not block a worker + * and async wait for the client send window updates. */ + ap_log_cerror(APLOG_MARK, APLOG_DEBUG, status, c, + H2_SSSN_LOG(APLOGNO(10502), session, + "BLOCKED, return to mpm c1 monitoring")); + goto leaving; + } + + /* No IO happening and input is exhausted. Wait with * the c1 connection timeout for sth to happen in our c1/c2 sockets/pipes */ ap_log_cerror(APLOG_MARK, APLOG_TRACE2, status, c, H2_SSSN_MSG(session, "polling timeout=%d, open_streams=%d"), @@ -1976,9 +2002,13 @@ apr_status_t h2_session_process(h2_session *session, int async) } leaving: + /* entering KeepAlive timing when we have no more open streams AND + * we have processed at least one stream. */ + *pkeepalive = (session->open_streams == 0 && session->remote.emitted_count); if (trace) { - ap_log_cerror( APLOG_MARK, APLOG_TRACE3, status, c, - H2_SSSN_MSG(session, "process returns")); + ap_log_cerror(APLOG_MARK, APLOG_TRACE3, status, c, + H2_SSSN_MSG(session, "process returns, keepalive=%d"), + *pkeepalive); } h2_mplx_c1_going_keepalive(session->mplx); diff --git a/modules/http2/h2_session.h b/modules/http2/h2_session.h index 3328509de8..2c8f334cce 100644 --- a/modules/http2/h2_session.h +++ b/modules/http2/h2_session.h @@ -144,8 +144,11 @@ void h2_session_event(h2_session *session, h2_session_event_t ev, * error occurred. * * @param session the sessionm to process + * @param async if mpm is async + * @param pkeepalive on return, != 0 if connection to be put into keepalive + * behaviour and timouts */ -apr_status_t h2_session_process(h2_session *session, int async); +apr_status_t h2_session_process(h2_session *session, int async, int *pkeepalive); /** * Last chance to do anything before the connection is closed. diff --git a/modules/http2/h2_version.h b/modules/http2/h2_version.h index 7e7da2106a..bf222078e7 100644 --- a/modules/http2/h2_version.h +++ b/modules/http2/h2_version.h @@ -27,7 +27,7 @@ * @macro * Version number of the http2 module as c string */ -#define MOD_HTTP2_VERSION "2.0.22" +#define MOD_HTTP2_VERSION "2.0.27" /** * @macro @@ -35,7 +35,7 @@ * release. This is a 24 bit number with 8 bits for major number, 8 bits * for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203. */ -#define MOD_HTTP2_VERSION_NUM 0x020016 +#define MOD_HTTP2_VERSION_NUM 0x02001b #endif /* mod_h2_h2_version_h */ diff --git a/modules/lua/lua_request.c b/modules/lua/lua_request.c index bec8580754..cfb89b80ca 100644 --- a/modules/lua/lua_request.c +++ b/modules/lua/lua_request.c @@ -1264,6 +1264,10 @@ static int lua_ap_scoreboard_process(lua_State *L) lua_pushnumber(L, ps_record->suspended); lua_settable(L, -3); + lua_pushstring(L, "wait_io"); + lua_pushnumber(L, ps_record->wait_io); + lua_settable(L, -3); + lua_pushstring(L, "write_completion"); lua_pushnumber(L, ps_record->write_completion); lua_settable(L, -3); diff --git a/server/mpm/event/event.c b/server/mpm/event/event.c index 7e7a7e91ba..050d823809 100644 --- a/server/mpm/event/event.c +++ b/server/mpm/event/event.c @@ -146,6 +146,8 @@ #define apr_time_from_msec(x) (x * 1000) #endif +#define CONN_STATE_IS_LINGERING_CLOSE(s) ((s) >= CONN_STATE_LINGER && \ + (s) <= CONN_STATE_LINGER_SHORT) #ifndef MAX_SECS_TO_LINGER #define MAX_SECS_TO_LINGER 30 #endif @@ -246,8 +248,11 @@ struct event_conn_state_t { conn_state_t pub; /** chaining in defer_linger_chain */ struct event_conn_state_t *chain; - /** Is lingering close from defer_lingering_close()? */ - int deferred_linger; + unsigned int + /** Is lingering close from defer_lingering_close()? */ + deferred_linger :1, + /** Has ap_start_lingering_close() been called? */ + linger_started :1; }; APR_RING_HEAD(timeout_head_t, event_conn_state_t); @@ -262,12 +267,14 @@ struct timeout_queue { /* * Several timeout queues that use different timeouts, so that we always can * simply append to the end. + * waitio_q uses vhost's TimeOut * write_completion_q uses vhost's TimeOut * keepalive_q uses vhost's KeepAliveTimeOut * linger_q uses MAX_SECS_TO_LINGER * short_linger_q uses SECONDS_TO_LINGER */ -static struct timeout_queue *write_completion_q, +static struct timeout_queue *waitio_q, + *write_completion_q, *keepalive_q, *linger_q, *short_linger_q; @@ -413,7 +420,8 @@ static event_child_bucket *all_buckets, /* All listeners buckets */ *my_bucket; /* Current child bucket */ struct event_srv_cfg_s { - struct timeout_queue *wc_q, + struct timeout_queue *io_q, + *wc_q, *ka_q; }; @@ -689,6 +697,9 @@ static int event_query(int query_code, int *result, apr_status_t *rv) case AP_MPMQ_GENERATION: *result = retained->mpm->my_generation; break; + case AP_MPMQ_CAN_WAITIO: + *result = 1; + break; default: *rv = APR_ENOTIMPL; break; @@ -884,7 +895,7 @@ static void close_connection(event_conn_state_t *cs) */ static int shutdown_connection(event_conn_state_t *cs) { - if (cs->pub.state < CONN_STATE_LINGER) { + if (!CONN_STATE_IS_LINGERING_CLOSE(cs->pub.state)) { apr_table_setn(cs->c->notes, "short-lingering-close", "1"); defer_lingering_close(cs); } @@ -963,11 +974,18 @@ static int event_post_read_request(request_rec *r) /* Forward declare */ static void process_lingering_close(event_conn_state_t *cs); -static void update_reqevents_from_sense(event_conn_state_t *cs, int sense) +static void update_reqevents_from_sense(event_conn_state_t *cs, + int default_sense) { - if (sense < 0) { + int sense = default_sense; + + if (cs->pub.sense != CONN_SENSE_DEFAULT) { sense = cs->pub.sense; + + /* Reset to default for the next round */ + cs->pub.sense = CONN_SENSE_DEFAULT; } + if (sense == CONN_SENSE_WANT_READ) { cs->pfd.reqevents = APR_POLLIN | APR_POLLHUP; } @@ -979,9 +997,6 @@ static void update_reqevents_from_sense(event_conn_state_t *cs, int sense) * so it shouldn't hurt (ignored otherwise). */ cs->pfd.reqevents |= APR_POLLERR; - - /* Reset to default for the next round */ - cs->pub.sense = CONN_SENSE_DEFAULT; } /* @@ -1020,7 +1035,6 @@ static void process_socket(apr_thread_t *thd, apr_pool_t * p, apr_socket_t * soc &mpm_event_module); cs->pfd.desc_type = APR_POLL_SOCKET; cs->pfd.desc.s = sock; - update_reqevents_from_sense(cs, CONN_SENSE_WANT_READ); pt->type = PT_CSD; pt->baton = cs; cs->pfd.client_data = pt; @@ -1033,6 +1047,8 @@ static void process_socket(apr_thread_t *thd, apr_pool_t * p, apr_socket_t * soc if (rc != OK && rc != DONE) { ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(00469) "process_socket: connection aborted"); + close_connection(cs); + return; } /** @@ -1041,17 +1057,15 @@ static void process_socket(apr_thread_t *thd, apr_pool_t * p, apr_socket_t * soc * and there are measurable delays before the * socket is readable due to the first data packet arriving, * it might be better to create the cs on the listener thread - * with the state set to CONN_STATE_CHECK_REQUEST_LINE_READABLE + * with the state set to CONN_STATE_KEEPALIVE * * FreeBSD users will want to enable the HTTP accept filter * module in their kernel for the highest performance * When the accept filter is active, sockets are kept in the * kernel until a HTTP request is received. */ - cs->pub.state = CONN_STATE_READ_REQUEST_LINE; - + cs->pub.state = CONN_STATE_PROCESSING; cs->pub.sense = CONN_SENSE_DEFAULT; - rc = OK; } else { c = cs->c; @@ -1062,83 +1076,124 @@ static void process_socket(apr_thread_t *thd, apr_pool_t * p, apr_socket_t * soc c->id = conn_id; } - if (c->aborted) { - /* do lingering close below */ - cs->pub.state = CONN_STATE_LINGER; + if (CONN_STATE_IS_LINGERING_CLOSE(cs->pub.state)) { + goto lingering_close; } - else if (cs->pub.state >= CONN_STATE_LINGER) { - /* fall through */ - } - else { - if (cs->pub.state == CONN_STATE_READ_REQUEST_LINE - /* If we have an input filter which 'clogs' the input stream, - * like mod_ssl used to, lets just do the normal read from input - * filters, like the Worker MPM does. Filters that need to write - * where they would otherwise read, or read where they would - * otherwise write, should set the sense appropriately. - */ - || c->clogging_input_filters) { -read_request: - clogging = c->clogging_input_filters; - if (clogging) { - apr_atomic_inc32(&clogged_count); - } - rc = ap_run_process_connection(c); - if (clogging) { - apr_atomic_dec32(&clogged_count); - } - if (cs->pub.state > CONN_STATE_LINGER) { + + if (cs->pub.state == CONN_STATE_PROCESSING + /* If we have an input filter which 'clogs' the input stream, + * like mod_ssl used to, lets just do the normal read from input + * filters, like the Worker MPM does. Filters that need to write + * where they would otherwise read, or read where they would + * otherwise write, should set the sense appropriately. + */ + || c->clogging_input_filters) { + process_connection: + cs->pub.state = CONN_STATE_PROCESSING; + + clogging = c->clogging_input_filters; + if (clogging) { + apr_atomic_inc32(&clogged_count); + } + rc = ap_run_process_connection(c); + if (clogging) { + apr_atomic_dec32(&clogged_count); + } + /* + * The process_connection hooks should set the appropriate connection + * state upon return, for event MPM to either: + * - CONN_STATE_LINGER: do lingering close; + * - CONN_STATE_WRITE_COMPLETION: flush pending outputs using Timeout + * and wait for next incoming data using KeepAliveTimeout, then come + * back to process_connection() hooks; + * - CONN_STATE_SUSPENDED: suspend the connection such that it now + * interacts with the MPM through suspend/resume_connection() hooks, + * and/or registered poll callbacks (PT_USER), and/or registered + * timed callbacks triggered by timer events; + * - CONN_STATE_ASYNC_WAITIO: wait for read/write-ability of the underlying + * socket using Timeout and come back to process_connection() hooks when + * ready; + * - CONN_STATE_KEEPALIVE: now handled by CONN_STATE_WRITE_COMPLETION + * to flush before waiting for next data (that might depend on it). + * If a process_connection hook returns an error or no hook sets the state + * to one of the above expected value, forcibly close the connection w/ + * CONN_STATE_LINGER. This covers the cases where no process_connection + * hook executes (DECLINED), or one returns OK w/o touching the state (i.e. + * CONN_STATE_PROCESSING remains after the call) which can happen with + * third-party modules not updated to work specifically with event MPM + * while this was expected to do lingering close unconditionally with + * worker or prefork MPMs for instance. + */ + switch (rc) { + case DONE: + rc = OK; /* same as OK, fall through */ + case OK: + if (cs->pub.state == CONN_STATE_PROCESSING) { cs->pub.state = CONN_STATE_LINGER; } - if (rc == DONE) { - rc = OK; + else if (cs->pub.state == CONN_STATE_KEEPALIVE) { + cs->pub.state = CONN_STATE_WRITE_COMPLETION; } + break; + } + if (rc != OK || (cs->pub.state != CONN_STATE_LINGER + && cs->pub.state != CONN_STATE_ASYNC_WAITIO + && cs->pub.state != CONN_STATE_WRITE_COMPLETION + && cs->pub.state != CONN_STATE_SUSPENDED)) { + ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(10111) + "process_socket: connection processing returned %i " + "(%sstate %i): closing", + rc, rc ? "" : "unexpected ", (int)cs->pub.state); + cs->pub.state = CONN_STATE_LINGER; + } + else if (c->aborted) { + cs->pub.state = CONN_STATE_LINGER; + } + if (cs->pub.state == CONN_STATE_LINGER) { + goto lingering_close; } } - /* - * The process_connection hooks above should set the connection state - * appropriately upon return, for event MPM to either: - * - do lingering close (CONN_STATE_LINGER), - * - wait for readability of the next request with respect to the keepalive - * timeout (state CONN_STATE_CHECK_REQUEST_LINE_READABLE), - * - wait for read/write-ability of the underlying socket with respect to - * its timeout by setting c->clogging_input_filters to 1 and the sense - * to CONN_SENSE_WANT_READ/WRITE (state CONN_STATE_WRITE_COMPLETION), - * - keep flushing the output filters stack in nonblocking mode, and then - * if required wait for read/write-ability of the underlying socket with - * respect to its own timeout (state CONN_STATE_WRITE_COMPLETION); since - * completion at some point may require reads (e.g. SSL_ERROR_WANT_READ), - * an output filter can also set the sense to CONN_SENSE_WANT_READ at any - * time for event MPM to do the right thing, - * - suspend the connection (SUSPENDED) such that it now interacts with - * the MPM through suspend/resume_connection() hooks, and/or registered - * poll callbacks (PT_USER), and/or registered timed callbacks triggered - * by timer events. - * If a process_connection hook returns an error or no hook sets the state - * to one of the above expected value, we forcibly close the connection w/ - * CONN_STATE_LINGER. This covers the cases where no process_connection - * hook executes (DECLINED), or one returns OK w/o touching the state (i.e. - * CONN_STATE_READ_REQUEST_LINE remains after the call) which can happen - * with third-party modules not updated to work specifically with event MPM - * while this was expected to do lingering close unconditionally with - * worker or prefork MPMs for instance. - */ - if (rc != OK || (cs->pub.state >= CONN_STATE_NUM) - || (cs->pub.state < CONN_STATE_LINGER - && cs->pub.state != CONN_STATE_WRITE_COMPLETION - && cs->pub.state != CONN_STATE_CHECK_REQUEST_LINE_READABLE - && cs->pub.state != CONN_STATE_SUSPENDED)) { - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(10111) - "process_socket: connection processing %s: closing", - rc ? apr_psprintf(c->pool, "returned error %i", rc) - : apr_psprintf(c->pool, "unexpected state %i", - (int)cs->pub.state)); - cs->pub.state = CONN_STATE_LINGER; + + if (cs->pub.state == CONN_STATE_ASYNC_WAITIO) { + /* Set a read/write timeout for this connection, and let the + * event thread poll for read/writeability. + */ + cs->queue_timestamp = apr_time_now(); + notify_suspend(cs); + + ap_update_child_status(cs->sbh, SERVER_BUSY_READ, NULL); + + /* Modules might set c->cs->sense to CONN_SENSE_WANT_WRITE, + * the default is CONN_SENSE_WANT_READ still. + */ + update_reqevents_from_sense(cs, CONN_SENSE_WANT_READ); + apr_thread_mutex_lock(timeout_mutex); + TO_QUEUE_APPEND(cs->sc->io_q, cs); + rv = apr_pollset_add(event_pollset, &cs->pfd); + if (rv != APR_SUCCESS && !APR_STATUS_IS_EEXIST(rv)) { + AP_DEBUG_ASSERT(0); + TO_QUEUE_REMOVE(cs->sc->io_q, cs); + apr_thread_mutex_unlock(timeout_mutex); + ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, APLOGNO(10503) + "process_socket: apr_pollset_add failure in " + "CONN_STATE_ASYNC_WAITIO"); + close_connection(cs); + signal_threads(ST_GRACEFUL); + } + else { + apr_thread_mutex_unlock(timeout_mutex); + } + return; } if (cs->pub.state == CONN_STATE_WRITE_COMPLETION) { ap_filter_t *output_filter = c->output_filters; apr_status_t rv; + + /* Flush all pending outputs before going to CONN_STATE_KEEPALIVE or + * straight to CONN_STATE_PROCESSING if inputs are pending already. + */ + ap_update_child_status(cs->sbh, SERVER_BUSY_WRITE, NULL); while (output_filter->next != NULL) { output_filter = output_filter->next; @@ -1148,9 +1203,9 @@ static void process_socket(apr_thread_t *thd, apr_pool_t * p, apr_socket_t * soc ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c, APLOGNO(00470) "network write failure in core output filter"); cs->pub.state = CONN_STATE_LINGER; + goto lingering_close; } - else if (c->data_in_output_filters || - cs->pub.sense == CONN_SENSE_WANT_READ) { + if (c->data_in_output_filters || cs->pub.sense == CONN_SENSE_WANT_READ) { /* Still in WRITE_COMPLETION_STATE: * Set a read/write timeout for this connection, and let the * event thread poll for read/writeability. @@ -1158,7 +1213,8 @@ static void process_socket(apr_thread_t *thd, apr_pool_t * p, apr_socket_t * soc cs->queue_timestamp = apr_time_now(); notify_suspend(cs); - update_reqevents_from_sense(cs, -1); + /* Add work to pollset. */ + update_reqevents_from_sense(cs, CONN_SENSE_WANT_WRITE); apr_thread_mutex_lock(timeout_mutex); TO_QUEUE_APPEND(cs->sc->wc_q, cs); rv = apr_pollset_add(event_pollset, &cs->pfd); @@ -1167,8 +1223,8 @@ static void process_socket(apr_thread_t *thd, apr_pool_t * p, apr_socket_t * soc TO_QUEUE_REMOVE(cs->sc->wc_q, cs); apr_thread_mutex_unlock(timeout_mutex); ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf, APLOGNO(03465) - "process_socket: apr_pollset_add failure for " - "write completion"); + "process_socket: apr_pollset_add failure in " + "CONN_STATE_WRITE_COMPLETION"); close_connection(cs); signal_threads(ST_GRACEFUL); } @@ -1177,22 +1233,23 @@ static void process_socket(apr_thread_t *thd, apr_pool_t * p, apr_socket_t * soc } return; } - else if (c->keepalive != AP_CONN_KEEPALIVE || c->aborted) { + if (c->keepalive != AP_CONN_KEEPALIVE || c->aborted) { cs->pub.state = CONN_STATE_LINGER; + goto lingering_close; } - else if (c->data_in_input_filters) { - cs->pub.state = CONN_STATE_READ_REQUEST_LINE; - goto read_request; - } - else if (!listener_may_exit) { - cs->pub.state = CONN_STATE_CHECK_REQUEST_LINE_READABLE; + if (c->data_in_input_filters) { + goto process_connection; } - else { + if (listener_may_exit) { cs->pub.state = CONN_STATE_LINGER; + goto lingering_close; } + + /* Fall through */ + cs->pub.state = CONN_STATE_KEEPALIVE; } - if (cs->pub.state == CONN_STATE_CHECK_REQUEST_LINE_READABLE) { + if (cs->pub.state == CONN_STATE_KEEPALIVE) { ap_update_child_status(cs->sbh, SERVER_BUSY_KEEPALIVE, NULL); /* It greatly simplifies the logic to use a single timeout value per q @@ -1207,6 +1264,7 @@ static void process_socket(apr_thread_t *thd, apr_pool_t * p, apr_socket_t * soc notify_suspend(cs); /* Add work to pollset. */ + cs->pub.sense = CONN_SENSE_DEFAULT; update_reqevents_from_sense(cs, CONN_SENSE_WANT_READ); apr_thread_mutex_lock(timeout_mutex); TO_QUEUE_APPEND(cs->sc->ka_q, cs); @@ -1233,11 +1291,9 @@ static void process_socket(apr_thread_t *thd, apr_pool_t * p, apr_socket_t * soc return; } + lingering_close: /* CONN_STATE_LINGER[_*] fall through process_lingering_close() */ - if (cs->pub.state >= CONN_STATE_LINGER) { - process_lingering_close(cs); - return; - } + process_lingering_close(cs); } /* conns_this_child has gone to zero or below. See if the admin coded @@ -1250,10 +1306,8 @@ static void check_infinite_requests(void) "Stopping process due to MaxConnectionsPerChild"); signal_threads(ST_GRACEFUL); } - else { - /* keep going */ - conns_this_child = APR_INT32_MAX; - } + /* keep going */ + conns_this_child = APR_INT32_MAX; } static int close_listeners(int *closed) @@ -1488,9 +1542,12 @@ static void process_lingering_close(event_conn_state_t *cs) ap_log_cerror(APLOG_MARK, APLOG_TRACE6, 0, cs->c, "lingering close from state %i", (int)cs->pub.state); - AP_DEBUG_ASSERT(cs->pub.state >= CONN_STATE_LINGER); + AP_DEBUG_ASSERT(CONN_STATE_IS_LINGERING_CLOSE(cs->pub.state)); + + if (!cs->linger_started) { + cs->pub.state = CONN_STATE_LINGER; + cs->linger_started = 1; - if (cs->pub.state == CONN_STATE_LINGER) { /* defer_lingering_close() may have bumped lingering_count already */ if (!cs->deferred_linger) { apr_atomic_inc32(&lingering_count); @@ -1502,12 +1559,11 @@ static void process_lingering_close(event_conn_state_t *cs) close_connection(cs); return; } - - cs->queue_timestamp = apr_time_now(); - /* Clear APR_INCOMPLETE_READ if it was ever set, we'll do the poll() - * at the listener only from now, if needed. - */ + + /* All nonblocking from now, no need for APR_INCOMPLETE_READ either */ + apr_socket_timeout_set(csd, 0); apr_socket_opt_set(csd, APR_INCOMPLETE_READ, 0); + /* * If some module requested a shortened waiting period, only wait for * 2s (SECONDS_TO_LINGER). This is useful for mitigating certain @@ -1519,10 +1575,19 @@ static void process_lingering_close(event_conn_state_t *cs) else { cs->pub.state = CONN_STATE_LINGER_NORMAL; } + cs->pub.sense = CONN_SENSE_DEFAULT; notify_suspend(cs); + + /* One timestamp/duration for the whole lingering close time. + * XXX: This makes the (short_)linger_q not sorted/ordered by expiring + * timeouts whenever multiple schedules are necessary (EAGAIN below), + * but we probabaly don't care since these connections do not count + * for connections_above_limit() and all of them will be killed when + * busy or gracefully stopping anyway. + */ + cs->queue_timestamp = apr_time_now(); } - apr_socket_timeout_set(csd, 0); do { nbytes = sizeof(dummybuf); rv = apr_socket_recv(csd, dummybuf, &nbytes); @@ -1699,24 +1764,20 @@ static void * APR_THREAD_FUNC listener_thread(apr_thread_t * thd, void *dummy) if (APLOGtrace6(ap_server_conf)) { /* trace log status every second */ if (now - last_log > apr_time_from_sec(1)) { - last_log = now; - apr_thread_mutex_lock(timeout_mutex); ap_log_error(APLOG_MARK, APLOG_TRACE6, 0, ap_server_conf, - "connections: %u (clogged: %u write-completion: %d " - "keep-alive: %d lingering: %d suspended: %u)", + "connections: %u (waitio:%u write-completion:%u" + "keep-alive:%u lingering:%u suspended:%u clogged:%u), " + "workers: %u/%u shutdown", apr_atomic_read32(&connection_count), - apr_atomic_read32(&clogged_count), + apr_atomic_read32(waitio_q->total), apr_atomic_read32(write_completion_q->total), apr_atomic_read32(keepalive_q->total), apr_atomic_read32(&lingering_count), - apr_atomic_read32(&suspended_count)); - if (dying) { - ap_log_error(APLOG_MARK, APLOG_TRACE6, 0, ap_server_conf, - "%u/%u workers shutdown", - apr_atomic_read32(&threads_shutdown), - threads_per_child); - } - apr_thread_mutex_unlock(timeout_mutex); + apr_atomic_read32(&suspended_count), + apr_atomic_read32(&clogged_count), + apr_atomic_read32(&threads_shutdown), + threads_per_child); + last_log = now; } } @@ -1824,8 +1885,14 @@ static void * APR_THREAD_FUNC listener_thread(apr_thread_t * thd, void *dummy) blocking = 1; break; - case CONN_STATE_CHECK_REQUEST_LINE_READABLE: - cs->pub.state = CONN_STATE_READ_REQUEST_LINE; + case CONN_STATE_ASYNC_WAITIO: + cs->pub.state = CONN_STATE_PROCESSING; + remove_from_q = cs->sc->io_q; + blocking = 1; + break; + + case CONN_STATE_KEEPALIVE: + cs->pub.state = CONN_STATE_PROCESSING; remove_from_q = cs->sc->ka_q; break; @@ -1978,23 +2045,28 @@ static void * APR_THREAD_FUNC listener_thread(apr_thread_t * thd, void *dummy) /* Steps below will recompute this. */ queues_next_expiry = 0; - /* Step 1: keepalive timeouts */ + /* Step 1: keepalive queue timeouts are closed */ if (workers_were_busy || dying) { process_keepalive_queue(0); /* kill'em all \m/ */ } else { process_keepalive_queue(now); } - /* Step 2: write completion timeouts */ - process_timeout_queue(write_completion_q, now, - defer_lingering_close); - /* Step 3: (normal) lingering close completion timeouts */ + + /* Step 2: waitio queue timeouts are flushed */ + process_timeout_queue(waitio_q, now, defer_lingering_close); + + /* Step 3: write completion queue timeouts are flushed */ + process_timeout_queue(write_completion_q, now, defer_lingering_close); + + /* Step 4: normal lingering close queue timeouts are closed */ if (dying && linger_q->timeout > short_linger_q->timeout) { /* Dying, force short timeout for normal lingering close */ linger_q->timeout = short_linger_q->timeout; } process_timeout_queue(linger_q, now, shutdown_connection); - /* Step 4: (short) lingering close completion timeouts */ + + /* Step 5: short lingering close queue timeouts are closed */ process_timeout_queue(short_linger_q, now, shutdown_connection); apr_thread_mutex_unlock(timeout_mutex); @@ -2003,11 +2075,12 @@ static void * APR_THREAD_FUNC listener_thread(apr_thread_t * thd, void *dummy) queues_next_expiry > now ? queues_next_expiry - now : -1); - ps->keep_alive = apr_atomic_read32(keepalive_q->total); + ps->wait_io = apr_atomic_read32(waitio_q->total); ps->write_completion = apr_atomic_read32(write_completion_q->total); - ps->connections = apr_atomic_read32(&connection_count); - ps->suspended = apr_atomic_read32(&suspended_count); + ps->keep_alive = apr_atomic_read32(keepalive_q->total); ps->lingering_close = apr_atomic_read32(&lingering_count); + ps->suspended = apr_atomic_read32(&suspended_count); + ps->connections = apr_atomic_read32(&connection_count); } else if ((workers_were_busy || dying) && apr_atomic_read32(keepalive_q->total)) { @@ -3403,7 +3476,7 @@ static void setup_slave_conn(conn_rec *c, void *csd) cs->bucket_alloc = c->bucket_alloc; cs->pfd = mcs->pfd; cs->pub = mcs->pub; - cs->pub.state = CONN_STATE_READ_REQUEST_LINE; + cs->pub.state = CONN_STATE_PROCESSING; cs->pub.sense = CONN_SENSE_DEFAULT; c->cs = &(cs->pub); @@ -3630,16 +3703,17 @@ static int event_post_config(apr_pool_t *pconf, apr_pool_t *plog, struct { struct timeout_queue *tail, *q; apr_hash_t *hash; - } wc, ka; + } io, wc, ka; /* Not needed in pre_config stage */ if (ap_state_query(AP_SQ_MAIN_STATE) == AP_SQ_MS_CREATE_PRE_CONFIG) { return OK; } - wc.tail = ka.tail = NULL; + io.hash = apr_hash_make(ptemp); wc.hash = apr_hash_make(ptemp); ka.hash = apr_hash_make(ptemp); + io.tail = wc.tail = ka.tail = NULL; linger_q = TO_QUEUE_MAKE(pconf, apr_time_from_sec(MAX_SECS_TO_LINGER), NULL); @@ -3650,8 +3724,12 @@ static int event_post_config(apr_pool_t *pconf, apr_pool_t *plog, event_srv_cfg *sc = apr_pcalloc(pconf, sizeof *sc); ap_set_module_config(s->module_config, &mpm_event_module, sc); - if (!wc.tail) { + if (!io.tail) { /* The main server uses the global queues */ + io.q = TO_QUEUE_MAKE(pconf, s->timeout, NULL); + apr_hash_set(io.hash, &s->timeout, sizeof s->timeout, io.q); + io.tail = waitio_q = io.q; + wc.q = TO_QUEUE_MAKE(pconf, s->timeout, NULL); apr_hash_set(wc.hash, &s->timeout, sizeof s->timeout, wc.q); wc.tail = write_completion_q = wc.q; @@ -3664,6 +3742,13 @@ static int event_post_config(apr_pool_t *pconf, apr_pool_t *plog, else { /* The vhosts use any existing queue with the same timeout, * or their own queue(s) if there isn't */ + io.q = apr_hash_get(io.hash, &s->timeout, sizeof s->timeout); + if (!io.q) { + io.q = TO_QUEUE_MAKE(pconf, s->timeout, io.tail); + apr_hash_set(io.hash, &s->timeout, sizeof s->timeout, io.q); + io.tail = io.tail->next = io.q; + } + wc.q = apr_hash_get(wc.hash, &s->timeout, sizeof s->timeout); if (!wc.q) { wc.q = TO_QUEUE_MAKE(pconf, s->timeout, wc.tail); @@ -3680,6 +3765,7 @@ static int event_post_config(apr_pool_t *pconf, apr_pool_t *plog, ka.tail = ka.tail->next = ka.q; } } + sc->io_q = io.q; sc->wc_q = wc.q; sc->ka_q = ka.q; } From 06b9602fdf3c60c8f50dcd58bf403e387c4dbd01 Mon Sep 17 00:00:00 2001 From: Yann Ylavic Date: Sat, 27 Jul 2024 14:19:32 +0000 Subject: [PATCH 023/176] Backported in r1919548. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919549 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/STATUS b/STATUS index c0a28ac350..6bc3402fcf 100644 --- a/STATUS +++ b/STATUS @@ -157,30 +157,6 @@ RELEASE SHOWSTOPPERS: PATCHES ACCEPTED TO BACKPORT FROM TRUNK: [ start all new proposals below, under PATCHES PROPOSED. ] - *) mod_http2: sync with github module. Add async handling - on newer httpd for blocked connections, fix yield handling. - Trunk version of patch: - https://svn.apache.org/r1918003 - https://svn.apache.org/r1918022 - https://svn.apache.org/r1918035 - https://svn.apache.org/r1918078 - https://svn.apache.org/r1918098 - https://svn.apache.org/r1918099 - https://svn.apache.org/r1918257 - https://svn.apache.org/r1918482 - https://svn.apache.org/r1918483 - https://svn.apache.org/r1918491 - https://svn.apache.org/r1919141 - https://svn.apache.org/r1919148 - 2.4.x version of patch: - https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/449.diff - PR: https://github.com/apache/httpd/pull/449 - +1: ylavic, icing, gbechis - rpluem says: PR currently has merge conflicts that need to be resolved - ylavic says: PR rebased and r1919141 added (colspan adjustment in mod_status) - Added r1919148 too for another old) colspan issue - Tiny fix which needs vote reset? - *) CMake: Use full path to gen_test_char.exe in CUSTOM_COMMAND. trunk patch: http://svn.apache.org/r1902366 2.4.x patch: svn merge -c r1902366 ^/httpd/httpd/trunk . From c418e929b0631ca6b7cac68c2ec8b6ea864c6e18 Mon Sep 17 00:00:00 2001 From: Joe Orton Date: Mon, 29 Jul 2024 09:08:06 +0000 Subject: [PATCH 024/176] Rebased mod_rewrite rewritelog() backport. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919581 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STATUS b/STATUS index 6bc3402fcf..20b0b716a0 100644 --- a/STATUS +++ b/STATUS @@ -190,7 +190,7 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: *) mod_rewrite: backport better/simpler rewritelog() macro to fix line numbers logged and make merging trunk->2.4.x easier trunk patch: https://svn.apache.org/r1866894 - 2.4.x patch: https://github.com/apache/httpd/commit/d2cd162d79d532ae14d273e835b4b6799a185a98.patch + 2.4.x patch: https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/464.diff PR: https://github.com/apache/httpd/pull/464 +1: jorton, ylavic, From 10533422afab7326df1e91fe3284a69ea8236e50 Mon Sep 17 00:00:00 2001 From: Yann Ylavic Date: Thu, 1 Aug 2024 09:15:39 +0000 Subject: [PATCH 025/176] Backported in 2.4.41 (r1860166). git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919614 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/STATUS b/STATUS index 20b0b716a0..218a6fd99b 100644 --- a/STATUS +++ b/STATUS @@ -219,33 +219,6 @@ PATCHES/ISSUES THAT ARE BEING WORKED does a minor bump only. minfrin: Two new directives need to be documented. - * mod_proxy_http: Don't establish or reuse a backend connection before pre- - fetching the request body, so to minimize the delay between it is supposed - to be alive and the first bytes sent: this is a best effort to prevent the - backend from closing because of idle or keepalive timeout in the meantime. - Also, handle a new "proxy-flushall" environment variable which allows to - flush any forwarded body data immediately. PR 56541+37920. - trunk patch: http://svn.apache.org/r1656259 - http://svn.apache.org/r1656359 (CHANGES entry) - 2.4.x patch: trunk works (modulo CHANGES, docs/log-message-tags) - +1: ylavic - -0: jim: This seems to be a hit to normal performance, to handle an - error and/or non-normal condition. The pre-fetch is - expensive, and is always done, even before we know that - the backend is available to rec' it. I understand the - error described, but is the fix actually worth it (plus - it seems to allow for a DDoS vector). - ylavic: It seems to me that the problem is real since we reuse the - connection before prefetching 16K (either controlled by the - client, or by an input filter), we currently always prefetch - these bytes already. Regarding performance I don't see any - difference (more cycles) compared with the current code. - However I think I failed to rebuild the header_brigade when - the proxy loop is retried (ping), so I need to rework this. - Do you think we'd better remove the prefetch, or maybe just - make it nonblocking (by default)? - jim: Non-blocking seems the best way to handle... - PATCHES/ISSUES THAT ARE STALLED *) core: avoid duplicate headers when using ap_send_error_response. From 34d4568d4c226cb6d49a6709c827b92023e044fe Mon Sep 17 00:00:00 2001 From: Yann Ylavic Date: Thu, 1 Aug 2024 10:07:59 +0000 Subject: [PATCH 026/176] Add missing CHANGES entry from r1919545 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919615 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES b/CHANGES index 083208ee42..396d113ab3 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ -*- coding: utf-8 -*- Changes with Apache 2.4.63 + *) mod_rewrite: Better question mark tracking to avoid UnsafeAllow3F. + PR 69197 [Yann Ylavic, Eric Covener] + Changes with Apache 2.4.62 *) SECURITY: CVE-2024-40898: Apache HTTP Server: SSRF with From 996525f6d7874a633334d7e76834a2d5849b24ad Mon Sep 17 00:00:00 2001 From: Yann Ylavic Date: Thu, 1 Aug 2024 10:15:08 +0000 Subject: [PATCH 027/176] Add missing CHANGES entry from r1919548 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919616 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 396d113ab3..b79ec2b77e 100644 --- a/CHANGES +++ b/CHANGES @@ -2,7 +2,10 @@ Changes with Apache 2.4.63 *) mod_rewrite: Better question mark tracking to avoid UnsafeAllow3F. - PR 69197 [Yann Ylavic, Eric Covener] + PR 69197. [Yann Ylavic, Eric Covener] + + *) mod_http2: Return connection monitoring to the event MPM when blocking + on client updates. [Stefan Eissing, Yann Ylavic] Changes with Apache 2.4.62 From f4a5fbe55d14d5fbd8871dbd3ab9bfbe04fed667 Mon Sep 17 00:00:00 2001 From: Yann Ylavic Date: Thu, 1 Aug 2024 12:48:02 +0000 Subject: [PATCH 028/176] Fix 2.4 versions of latest MMN entries. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919618 13f79535-47bb-0310-9956-ffa450edef68 --- include/ap_mmn.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/ap_mmn.h b/include/ap_mmn.h index 85dd97d099..2e63617271 100644 --- a/include/ap_mmn.h +++ b/include/ap_mmn.h @@ -603,10 +603,10 @@ * and AP_REQUEST_TRUSTED_CT BNOTE. * 20120211.133 (2.4.60-dev) Add ap_proxy_fixup_uds_filename() * 20120211.134 (2.4.60-dev) AP_SLASHES and AP_IS_SLASH - * 20120211.135 (2.4.59-dev) Add CONN_STATE_ASYNC_WAITIO, CONN_STATE_KEEPALIVE + * 20120211.135 (2.4.63-dev) Add CONN_STATE_ASYNC_WAITIO, CONN_STATE_KEEPALIVE * and CONN_STATE_PROCESSING - * 20120211.136 (2.4.59-dev) Add wait_io field to struct process_score - * 20120211.137 (2.4.59-dev) Add AP_MPMQ_CAN_WAITIO + * 20120211.136 (2.4.63-dev) Add wait_io field to struct process_score + * 20120211.137 (2.4.63-dev) Add AP_MPMQ_CAN_WAITIO */ #define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */ From ddb375b40a34440c49eb79fe434632f565a42b56 Mon Sep 17 00:00:00 2001 From: Yann Ylavic Date: Thu, 1 Aug 2024 17:41:33 +0000 Subject: [PATCH 029/176] Propose x 3 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919624 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/STATUS b/STATUS index 218a6fd99b..c17714f101 100644 --- a/STATUS +++ b/STATUS @@ -193,7 +193,32 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: 2.4.x patch: https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/464.diff PR: https://github.com/apache/httpd/pull/464 +1: jorton, ylavic, - + + *) mod_proxy: Avoid AH01059 parsing error for SetHandler "unix:" URLs + in (incomplete fix in 2.4.62). PR 69160. + trunk patch: https://svn.apache.org/r1919532 + https://svn.apache.org/r1919533 + 2.4.x patch: https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/467.diff + PR: https://github.com/apache/httpd/pull/467 + +1: ylavic, + + *) mod_proxy: Honor parameters of ProxyPassMatch workers with substitution + in the host name or port. PR 69233. + trunk patch: https://svn.apache.org/r1912462 + https://svn.apache.org/r1919617 + https://svn.apache.org/r1919619 + 2.4.x patch: https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/469.diff + PR: https://github.com/apache/httpd/pull/469 + +1: ylavic, + + *) mod_proxy_fcgi: Don't re-encode SCRIPT_FILENAME. PR 69203. + trunk patch: https://svn.apache.org/r1919547 + https://svn.apache.org/r1919620 + https://svn.apache.org/r1919621 + https://svn.apache.org/r1919623 + 2.4.x patch: https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/470.diff + PR: https://github.com/apache/httpd/pull/470 + +1: ylavic, PATCHES/ISSUES THAT ARE BEING WORKED [ New entries should be added at the START of the list ] From eab1e70cb00d0b7dfbe8e6df98aee0fbca8afd5c Mon Sep 17 00:00:00 2001 From: Yann Ylavic Date: Fri, 2 Aug 2024 01:01:37 +0000 Subject: [PATCH 030/176] Update proposal git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919629 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/STATUS b/STATUS index c17714f101..587ece39f8 100644 --- a/STATUS +++ b/STATUS @@ -211,11 +211,12 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: PR: https://github.com/apache/httpd/pull/469 +1: ylavic, - *) mod_proxy_fcgi: Don't re-encode SCRIPT_FILENAME. PR 69203. + *) mod_proxy_fcgi: Don't re-encode SCRIPT_FILENAME when set via SetHandler. PR 69203. trunk patch: https://svn.apache.org/r1919547 https://svn.apache.org/r1919620 https://svn.apache.org/r1919621 https://svn.apache.org/r1919623 + https://svn.apache.org/r1919628 2.4.x patch: https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/470.diff PR: https://github.com/apache/httpd/pull/470 +1: ylavic, From d4bcc1062fa2da8931fbf1ce3db0c9da150a30e7 Mon Sep 17 00:00:00 2001 From: Ivan Zhakov Date: Sun, 4 Aug 2024 11:01:17 +0000 Subject: [PATCH 031/176] Merge r1902366 from trunk: *) CMake: Use full path to gen_test_char.exe in CUSTOM_COMMAND. Submitted by: ivan Reviewed By: ylavic, covener git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919663 13f79535-47bb-0310-9956-ffa450edef68 --- CMakeLists.txt | 3 +-- STATUS | 5 ----- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b30547d39..2fc767f333 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -628,11 +628,10 @@ ENDIF() CONFIGURE_FILE(os/win32/BaseAddr.ref ${PROJECT_BINARY_DIR}/ COPYONLY) ADD_EXECUTABLE(gen_test_char server/gen_test_char.c) -GET_TARGET_PROPERTY(GEN_TEST_CHAR_EXE gen_test_char LOCATION) ADD_CUSTOM_COMMAND( COMMENT "Generating character tables, test_char.h, for current locale" DEPENDS gen_test_char - COMMAND ${GEN_TEST_CHAR_EXE} > ${PROJECT_BINARY_DIR}/test_char.h + COMMAND $ > ${PROJECT_BINARY_DIR}/test_char.h OUTPUT ${PROJECT_BINARY_DIR}/test_char.h ) ADD_CUSTOM_TARGET( diff --git a/STATUS b/STATUS index 587ece39f8..5e7e282d1f 100644 --- a/STATUS +++ b/STATUS @@ -157,11 +157,6 @@ RELEASE SHOWSTOPPERS: PATCHES ACCEPTED TO BACKPORT FROM TRUNK: [ start all new proposals below, under PATCHES PROPOSED. ] - *) CMake: Use full path to gen_test_char.exe in CUSTOM_COMMAND. - trunk patch: http://svn.apache.org/r1902366 - 2.4.x patch: svn merge -c r1902366 ^/httpd/httpd/trunk . - +1: ivan, ylavic, covener - PATCHES PROPOSED TO BACKPORT FROM TRUNK: [ New proposals should be added at the end of the list ] From c5863e87599b20322743b881112daa8348e199b3 Mon Sep 17 00:00:00 2001 From: Ivan Zhakov Date: Sun, 4 Aug 2024 11:03:16 +0000 Subject: [PATCH 032/176] Merge r1919395 from trunk: *) CMake: By default use PCRE2 CMake package if supported. Use non-Unix build exception to backport with CTR. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919664 13f79535-47bb-0310-9956-ffa450edef68 --- CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2fc767f333..9b38f699db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,6 +27,7 @@ FIND_PACKAGE(Lua51) FIND_PACKAGE(OpenSSL) FIND_PACKAGE(ZLIB) FIND_PACKAGE(CURL) +FIND_PACKAGE(PCRE2 COMPONENTS 8BIT) # Options for support libraries not supported by cmake-bundled FindFOO @@ -47,7 +48,10 @@ ENDIF() # PCRE names its libraries differently for debug vs. release builds. # We can't query our own CMAKE_BUILD_TYPE at configure time. # If the debug version exists in PREFIX/lib, default to that one. -IF(EXISTS "${CMAKE_INSTALL_PREFIX}/lib/pcre2-8d.lib") +IF(PCRE2_FOUND) + SET(default_pcre_libraries "PCRE2::8BIT") + SET(default_pcre_cflags "-DHAVE_PCRE2") +ELSEIF(EXISTS "${CMAKE_INSTALL_PREFIX}/lib/pcre2-8d.lib") SET(default_pcre_libraries ${CMAKE_INSTALL_PREFIX}/lib/pcre2-8d.lib) SET(default_pcre_cflags "-DHAVE_PCRE2") ELSEIF(EXISTS "${CMAKE_INSTALL_PREFIX}/lib/pcre2-8.lib") From 55363595457f504207087b4c69aefc77f1a1736e Mon Sep 17 00:00:00 2001 From: Ivan Zhakov Date: Sun, 4 Aug 2024 11:21:30 +0000 Subject: [PATCH 033/176] Merge r1919397, r1919398, r1919399, r1919411, r1919414, r1919415, r1919416, r1919417, r1919665 from trunk [ CTR for CI changes ] CI: Add Windows GitHub Actions job. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919666 13f79535-47bb-0310-9956-ffa450edef68 --- .github/workflows/windows.yml | 63 +++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 .github/workflows/windows.yml diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml new file mode 100644 index 0000000000..ac9cb119a8 --- /dev/null +++ b/.github/workflows/windows.yml @@ -0,0 +1,63 @@ +name: Windows + +on: + push: + branches: [ "*" ] + paths-ignore: + - 'docs/**' + - STATUS + - CHANGES + - changes-entries/* + pull_request: + branches: [ "trunk", "2.4.x" ] + paths-ignore: + - 'docs/**' + - STATUS + - CHANGES + - changes-entries/* + +jobs: + build: + strategy: + fail-fast: false + matrix: + include: + - name: Default + triplet: x64-windows + arch: x64 + build-type: Debug + generator: "Ninja" + + runs-on: windows-latest + timeout-minutes: 30 + name: ${{ matrix.name }} + env: + VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite" + steps: + - name: Export GitHub Actions cache environment variables + uses: actions/github-script@v7 + with: + script: | + core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + + - name: Install dependencies + run: vcpkg install --triplet ${{ matrix.triplet }} apr[private-headers] apr-util pcre2 openssl + + - uses: actions/checkout@v3 + + - name: Configure CMake + shell: cmd + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=${{ matrix.arch }} + cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} ^ + -G "${{ matrix.generator }}" ^ + -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake ^ + -DAPR_INCLUDE_DIR=C:/vcpkg/installed/${{ matrix.triplet }}/include ^ + "-DAPR_LIBRARIES=C:/vcpkg/installed/${{ matrix.triplet }}/lib/libapr-1.lib;C:/vcpkg/installed/${{ matrix.triplet }}/lib/libaprutil-1.lib" + + - name: Build + shell: cmd + run: | + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\Tools\VsDevCmd.bat" -arch=${{ matrix.arch }} + cmake --build ${{github.workspace}}/build --config ${{ matrix.build-type }} From 270e7081d18dc4987ce707a865f68c11d98d7f18 Mon Sep 17 00:00:00 2001 From: Ivan Zhakov Date: Sun, 4 Aug 2024 11:53:29 +0000 Subject: [PATCH 034/176] Propose. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919667 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/STATUS b/STATUS index 5e7e282d1f..8fec5846b6 100644 --- a/STATUS +++ b/STATUS @@ -216,6 +216,14 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: PR: https://github.com/apache/httpd/pull/470 +1: ylavic, + *) CMake: Remove awk dependency when building using CMake. Before this awk was + required for -DWITH_MODULES option. + trunk patch: https://svn.apache.org/r1919413 + https://svn.apache.org/r1919587 + https://svn.apache.org/r1919602 + 2.4.x patch: svn merge -c r1919413 -c r1919587 -c r1919602 ^/httpd/httpd/trunk . + +1: ivan + PATCHES/ISSUES THAT ARE BEING WORKED [ New entries should be added at the START of the list ] From f325a987635f76557d92d7630426e4af3cd3042f Mon Sep 17 00:00:00 2001 From: Christophe Jaillet Date: Fri, 9 Aug 2024 09:26:19 +0000 Subject: [PATCH 035/176] Add a new tag to ease writing compatibility notes. This is much less verbose and will make wording more consistent in the generated html files. It is declared in synopsis.xsl because its main use should be here, but it is usable anywhere. Only the French translation is provided. (1919560 and 1919653 in trunk git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919773 13f79535-47bb-0310-9956-ffa450edef68 --- docs/manual/style/common.dtd | 4 +++- docs/manual/style/lang/da.xml | 2 ++ docs/manual/style/lang/de.xml | 2 ++ docs/manual/style/lang/en.xml | 2 ++ docs/manual/style/lang/es.xml | 2 ++ docs/manual/style/lang/fr.xml | 2 ++ docs/manual/style/lang/ja.xml | 2 ++ docs/manual/style/lang/ko.xml | 2 ++ docs/manual/style/lang/pt-br.xml | 2 ++ docs/manual/style/lang/ru.xml | 2 ++ docs/manual/style/lang/tr.xml | 2 ++ docs/manual/style/lang/zh-cn.xml | 2 ++ docs/manual/style/xsl/synopsis.xsl | 10 ++++++++++ 13 files changed, 35 insertions(+), 1 deletion(-) diff --git a/docs/manual/style/common.dtd b/docs/manual/style/common.dtd index 2cd308078c..8402f9e36e 100644 --- a/docs/manual/style/common.dtd +++ b/docs/manual/style/common.dtd @@ -42,7 +42,7 @@ +program | img | cite | q | dfn | var | transnote | glossary | phonetic | since"> @@ -111,6 +111,8 @@ highlight | blockquote"> + + diff --git a/docs/manual/style/lang/da.xml b/docs/manual/style/lang/da.xml index c7be52ae55..7483e7cdf7 100644 --- a/docs/manual/style/lang/da.xml +++ b/docs/manual/style/lang/da.xml @@ -64,6 +64,8 @@ Modul Identifikation Kilde Fil Kompatibilitet + Available in Apache HTTP Server + and later. Relaterede moduler diff --git a/docs/manual/style/lang/de.xml b/docs/manual/style/lang/de.xml index 653f3db0dc..234563df35 100644 --- a/docs/manual/style/lang/de.xml +++ b/docs/manual/style/lang/de.xml @@ -59,6 +59,8 @@ Modulbezeichner Quelltext-Datei Kompatibilität + Available in Apache HTTP Server + and later. Referenzierte Module diff --git a/docs/manual/style/lang/en.xml b/docs/manual/style/lang/en.xml index 031f74e4cb..9a135b0b08 100644 --- a/docs/manual/style/lang/en.xml +++ b/docs/manual/style/lang/en.xml @@ -63,6 +63,8 @@ Module Identifier Source File Compatibility + Available in Apache HTTP Server + and later. Related Modules diff --git a/docs/manual/style/lang/es.xml b/docs/manual/style/lang/es.xml index 6e6eea8603..5388826c09 100644 --- a/docs/manual/style/lang/es.xml +++ b/docs/manual/style/lang/es.xml @@ -67,6 +67,8 @@ Identificador de Módulos Fichero de Código Fuente Compatibilidad + Available in Apache HTTP Server + and later. Módulos Relacionados diff --git a/docs/manual/style/lang/fr.xml b/docs/manual/style/lang/fr.xml index fa2bc79f35..339f2b79f5 100644 --- a/docs/manual/style/lang/fr.xml +++ b/docs/manual/style/lang/fr.xml @@ -63,6 +63,8 @@ Identificateur de Module Fichier Source Compatibilité + Disponible à partir de la version + du serveur HTTP Apache. Modules Apparentés diff --git a/docs/manual/style/lang/ja.xml b/docs/manual/style/lang/ja.xml index 060bf2d5a2..56e3072d71 100644 --- a/docs/manual/style/lang/ja.xml +++ b/docs/manual/style/lang/ja.xml @@ -58,6 +58,8 @@ モジュール識別子 ソースファイル 互換性 + Available in Apache HTTP Server + and later. 関連モジュール diff --git a/docs/manual/style/lang/ko.xml b/docs/manual/style/lang/ko.xml index b219246ffb..90de25e677 100644 --- a/docs/manual/style/lang/ko.xml +++ b/docs/manual/style/lang/ko.xml @@ -64,6 +64,8 @@ ҽ + Available in Apache HTTP Server + and later. õ diff --git a/docs/manual/style/lang/pt-br.xml b/docs/manual/style/lang/pt-br.xml index d2e4ad5486..fe316f0c45 100644 --- a/docs/manual/style/lang/pt-br.xml +++ b/docs/manual/style/lang/pt-br.xml @@ -66,6 +66,8 @@ Identificador de Módulo Arquivo Fonte Compatibilidade + Available in Apache HTTP Server + and later. Módulos Relacionados diff --git a/docs/manual/style/lang/ru.xml b/docs/manual/style/lang/ru.xml index 670651bf53..fa21d799aa 100644 --- a/docs/manual/style/lang/ru.xml +++ b/docs/manual/style/lang/ru.xml @@ -62,6 +62,8 @@ Идентификатор модуля Исходный код Совместимость + Available in Apache HTTP Server + and later. Смотрите также модули diff --git a/docs/manual/style/lang/tr.xml b/docs/manual/style/lang/tr.xml index f86ab6577f..19d1720395 100644 --- a/docs/manual/style/lang/tr.xml +++ b/docs/manual/style/lang/tr.xml @@ -65,6 +65,8 @@ Modül Betimleyici Kaynak Dosyası Uyumluluk + Available in Apache HTTP Server + and later. İlgili Modüller diff --git a/docs/manual/style/lang/zh-cn.xml b/docs/manual/style/lang/zh-cn.xml index 04b7f851d4..4983052974 100644 --- a/docs/manual/style/lang/zh-cn.xml +++ b/docs/manual/style/lang/zh-cn.xml @@ -61,6 +61,8 @@ 模块标识 源文件 兼容性 + Available in Apache HTTP Server + and later. 相关模块 diff --git a/docs/manual/style/xsl/synopsis.xsl b/docs/manual/style/xsl/synopsis.xsl index b3bd96be6c..b04553cbe2 100644 --- a/docs/manual/style/xsl/synopsis.xsl +++ b/docs/manual/style/xsl/synopsis.xsl @@ -671,4 +671,14 @@ + + + + + + + + + + From 20c4d07c0269f4b0ee46a3276b8df268aab1e5eb Mon Sep 17 00:00:00 2001 From: Christophe Jaillet Date: Fri, 9 Aug 2024 09:30:31 +0000 Subject: [PATCH 036/176] Add some compatibility notes. (r1919564 in trunk, modified to match the 2.4.x release versions) git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919774 13f79535-47bb-0310-9956-ffa450edef68 --- docs/manual/mod/mod_rewrite.xml | 6 ++++-- docs/manual/rewrite/flags.xml | 6 +++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/manual/mod/mod_rewrite.xml b/docs/manual/mod/mod_rewrite.xml index 69efd70f61..a10f3f38c0 100644 --- a/docs/manual/mod/mod_rewrite.xml +++ b/docs/manual/mod/mod_rewrite.xml @@ -1494,13 +1494,15 @@ cannot use $N in the substitution string! UnsafePrefixStat Allows potentially unsafe substitutions from a leading variable or backreference to a filesystem path. - details ... + details ...
    + 2.4.60 UNC Prevents the merging of multiple leading slashes, as used by Windows UNC paths. - details ... + details ...
    + 2.4.62 diff --git a/docs/manual/rewrite/flags.xml b/docs/manual/rewrite/flags.xml index 7d638aaf87..9e287ec9ee 100644 --- a/docs/manual/rewrite/flags.xml +++ b/docs/manual/rewrite/flags.xml @@ -865,11 +865,15 @@ The L flag can be useful in this context to end the These substitutions are not prefixed with the document root. This protects from a malicious URL causing the expanded substitution to map to an unexpected filesystem location.

    + +

    2.4.60

    UNC

    Setting this flag prevents the merging of multiple leading slashes, as used in Windows UNC paths. The flag is not necessary when the rules - substitution starts with multiple literal slashes.

    + substitution starts with multiple literal slashes.

    + +

    2.4.62

    From b9dcbce41cbec0316f311eb7b40e78959d1580cb Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Tue, 13 Aug 2024 14:19:32 +0000 Subject: [PATCH 037/176] add/vote/promote [skip ci] git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919861 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/STATUS b/STATUS index 8fec5846b6..fc5866e206 100644 --- a/STATUS +++ b/STATUS @@ -157,6 +157,13 @@ RELEASE SHOWSTOPPERS: PATCHES ACCEPTED TO BACKPORT FROM TRUNK: [ start all new proposals below, under PATCHES PROPOSED. ] + *) mod_rewrite: backport better/simpler rewritelog() macro to fix + line numbers logged and make merging trunk->2.4.x easier + trunk patch: https://svn.apache.org/r1866894 + 2.4.x patch: https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/464.diff + PR: https://github.com/apache/httpd/pull/464 + +1: jorton, ylavic, covener + PATCHES PROPOSED TO BACKPORT FROM TRUNK: [ New proposals should be added at the end of the list ] @@ -182,13 +189,6 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: 2.4.x patch: svn merge -c r1914038 ^/httpd/httpd/trunk . +1: minfrin, covener - *) mod_rewrite: backport better/simpler rewritelog() macro to fix - line numbers logged and make merging trunk->2.4.x easier - trunk patch: https://svn.apache.org/r1866894 - 2.4.x patch: https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/464.diff - PR: https://github.com/apache/httpd/pull/464 - +1: jorton, ylavic, - *) mod_proxy: Avoid AH01059 parsing error for SetHandler "unix:" URLs in (incomplete fix in 2.4.62). PR 69160. trunk patch: https://svn.apache.org/r1919532 @@ -224,6 +224,15 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: 2.4.x patch: svn merge -c r1919413 -c r1919587 -c r1919602 ^/httpd/httpd/trunk . +1: ivan + *) mod_rewrite: don't merge leading slashes when they come from a perdir prefix + (rather than the substitution) + Trunk version of patch: + https://svn.apache.org/r1919860 + Backport version for 2.4.x of patch: + https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/473.diff + Can be applied via apply_backport_pr.sh 473 + +1: covener + PATCHES/ISSUES THAT ARE BEING WORKED [ New entries should be added at the START of the list ] From e160f5e37dc99ca2a2243417b9195fafbf78ad39 Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Tue, 13 Aug 2024 14:33:21 +0000 Subject: [PATCH 038/176] a few addl votes [skip ci] git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919862 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/STATUS b/STATUS index fc5866e206..201e73a48f 100644 --- a/STATUS +++ b/STATUS @@ -195,7 +195,7 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: https://svn.apache.org/r1919533 2.4.x patch: https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/467.diff PR: https://github.com/apache/httpd/pull/467 - +1: ylavic, + +1: ylavic, covener *) mod_proxy: Honor parameters of ProxyPassMatch workers with substitution in the host name or port. PR 69233. @@ -214,7 +214,7 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: https://svn.apache.org/r1919628 2.4.x patch: https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/470.diff PR: https://github.com/apache/httpd/pull/470 - +1: ylavic, + +1: ylavic, covener *) CMake: Remove awk dependency when building using CMake. Before this awk was required for -DWITH_MODULES option. From 82b7c5f46244636d7c33b0f5c846ede0210882ba Mon Sep 17 00:00:00 2001 From: Ruediger Pluem Date: Thu, 15 Aug 2024 08:17:06 +0000 Subject: [PATCH 039/176] * Vote and promote git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919903 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/STATUS b/STATUS index 201e73a48f..76c5de2789 100644 --- a/STATUS +++ b/STATUS @@ -164,6 +164,14 @@ PATCHES ACCEPTED TO BACKPORT FROM TRUNK: PR: https://github.com/apache/httpd/pull/464 +1: jorton, ylavic, covener + *) mod_proxy: Avoid AH01059 parsing error for SetHandler "unix:" URLs + in (incomplete fix in 2.4.62). PR 69160. + trunk patch: https://svn.apache.org/r1919532 + https://svn.apache.org/r1919533 + 2.4.x patch: https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/467.diff + PR: https://github.com/apache/httpd/pull/467 + +1: ylavic, covener, rpluem + PATCHES PROPOSED TO BACKPORT FROM TRUNK: [ New proposals should be added at the end of the list ] @@ -189,14 +197,6 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: 2.4.x patch: svn merge -c r1914038 ^/httpd/httpd/trunk . +1: minfrin, covener - *) mod_proxy: Avoid AH01059 parsing error for SetHandler "unix:" URLs - in (incomplete fix in 2.4.62). PR 69160. - trunk patch: https://svn.apache.org/r1919532 - https://svn.apache.org/r1919533 - 2.4.x patch: https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/467.diff - PR: https://github.com/apache/httpd/pull/467 - +1: ylavic, covener - *) mod_proxy: Honor parameters of ProxyPassMatch workers with substitution in the host name or port. PR 69233. trunk patch: https://svn.apache.org/r1912462 @@ -204,7 +204,7 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: https://svn.apache.org/r1919619 2.4.x patch: https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/469.diff PR: https://github.com/apache/httpd/pull/469 - +1: ylavic, + +1: ylavic, rpluem *) mod_proxy_fcgi: Don't re-encode SCRIPT_FILENAME when set via SetHandler. PR 69203. trunk patch: https://svn.apache.org/r1919547 @@ -231,7 +231,7 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: Backport version for 2.4.x of patch: https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/473.diff Can be applied via apply_backport_pr.sh 473 - +1: covener + +1: covener, rpluem PATCHES/ISSUES THAT ARE BEING WORKED [ New entries should be added at the START of the list ] From 187984ff38cea3cc0acbb531a522a650f985b508 Mon Sep 17 00:00:00 2001 From: Ruediger Pluem Date: Thu, 15 Aug 2024 08:20:59 +0000 Subject: [PATCH 040/176] * Vote, promote, comment [skip ci] git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919904 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/STATUS b/STATUS index 76c5de2789..08def88f9d 100644 --- a/STATUS +++ b/STATUS @@ -172,6 +172,11 @@ PATCHES ACCEPTED TO BACKPORT FROM TRUNK: PR: https://github.com/apache/httpd/pull/467 +1: ylavic, covener, rpluem + *) mod_ldap: Add a hint to install the apr_ldap module on init failure. + trunk patch: http://svn.apache.org/r1914038 + 2.4.x patch: svn merge -c r1914038 ^/httpd/httpd/trunk . + +1: minfrin, covener, rpluem + PATCHES PROPOSED TO BACKPORT FROM TRUNK: [ New proposals should be added at the end of the list ] @@ -191,11 +196,7 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: Backport version for 2.4.x of patch: https://svn.apache.org/repos/asf/httpd/httpd/patches/2.4.x/httpd-2.4-ldap-search5.patch +1: minfrin, covener - - *) mod_ldap: Add a hint to install the apr_ldap module on init failure. - trunk patch: http://svn.apache.org/r1914038 - 2.4.x patch: svn merge -c r1914038 ^/httpd/httpd/trunk . - +1: minfrin, covener + rpluem says: https://svn.apache.org/repos/asf/httpd/httpd/patches/2.4.x/httpd-2.4-ldap-search5.patch returns 404 *) mod_proxy: Honor parameters of ProxyPassMatch workers with substitution in the host name or port. PR 69233. From 2242ac46e98d2c23f689b6d8b7543b7aad96b310 Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Fri, 16 Aug 2024 17:38:53 +0000 Subject: [PATCH 041/176] found in directoryindex, update link git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919933 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STATUS b/STATUS index 08def88f9d..8dc2dd4673 100644 --- a/STATUS +++ b/STATUS @@ -194,7 +194,7 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: https://svn.apache.org/r1914091 https://svn.apache.org/r1914281 Backport version for 2.4.x of patch: - https://svn.apache.org/repos/asf/httpd/httpd/patches/2.4.x/httpd-2.4-ldap-search5.patch + https://svn.apache.org/repos/asf/httpd/httpd/patches/2.4.x/httpd-2.4-httpd-2.4-ldap-search5.patch +1: minfrin, covener rpluem says: https://svn.apache.org/repos/asf/httpd/httpd/patches/2.4.x/httpd-2.4-ldap-search5.patch returns 404 From 8a8fcaf1a443b748f2bb1f4d9085c9e5e0ef9387 Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Fri, 16 Aug 2024 17:40:26 +0000 Subject: [PATCH 042/176] WIP [skip ci] git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1919934 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/STATUS b/STATUS index 8dc2dd4673..e473e5cef2 100644 --- a/STATUS +++ b/STATUS @@ -215,7 +215,8 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: https://svn.apache.org/r1919628 2.4.x patch: https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/470.diff PR: https://github.com/apache/httpd/pull/470 - +1: ylavic, covener + +1: ylavic + covener: pending https://github.com/apache/httpd/pull/470#discussion_r1718079315 outcome *) CMake: Remove awk dependency when building using CMake. Before this awk was required for -DWITH_MODULES option. From 140a837d7a6259113f80f146da235d05f18606ee Mon Sep 17 00:00:00 2001 From: Joe Orton Date: Tue, 20 Aug 2024 08:33:00 +0000 Subject: [PATCH 043/176] Merge r1866894 from trunk: * modules/mappers/mod_rewrite.c: Enhance trace-level logging to log line numbers accurately for C99 compilers, and remove odd/awkward double-parentheses using the rewritelog() macro. For non-C99 compilers do_rewritelog() will now be defined - but as a noop - if REWRITELOG_DISABLED is defined at compile time. No functional change at runtime apart from the line numbers being fixed. Submitted by: jorton Reviewed by: jorton, ylavic, covener git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1920052 13f79535-47bb-0310-9956-ffa450edef68 --- modules/mappers/mod_rewrite.c | 387 +++++++++++++++++++--------------- 1 file changed, 213 insertions(+), 174 deletions(-) diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c index 53fb1e91ff..24e21c6f4d 100644 --- a/modules/mappers/mod_rewrite.c +++ b/modules/mappers/mod_rewrite.c @@ -130,15 +130,21 @@ static const char* really_last_key = "rewrite_really_last"; #endif #ifndef REWRITELOG_DISABLED - -#define rewritelog(x) do_rewritelog x +#ifdef AP_HAVE_C99 +#define rewritelog(...) do_rewritelog(__LINE__, __VA_ARGS__) +#else +#define rewritelog do_rewritelog +#endif #define REWRITELOG_MODE ( APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD ) #define REWRITELOG_FLAGS ( APR_WRITE | APR_APPEND | APR_CREATE ) #else /* !REWRITELOG_DISABLED */ -#define rewritelog(x) - +#ifdef AP_HAVE_C99 +#define rewritelog(...) +#else +#define rewritelog do_rewritelog +#endif #endif /* REWRITELOG_DISABLED */ /* remembered mime-type for [T=...] */ @@ -455,14 +461,42 @@ static char *escape_backref(apr_pool_t *p, const char *path, * +-------------------------------------------------------+ */ -#ifndef REWRITELOG_DISABLED +/* Slightly complicated definitions follow here to support + * compile-time choice of enabled/disabled of rewritelog both with or + * without C99 support, where varargs macros are only available with + * C99. + * + * do_rewritelog is defined for (rewritelog enabled) or (rewritelog + * disabled AND no C99 support) but is an noop for the latter case and + * should get optimized away. + * + * For the (rewritelog disabled) case the function is defined + * differently for C99/non-C99. For C99, the rewritelog() macro passes + * __LINE__, allowing accurate logging of line numbers. For non-C99 + * the line number used for rewritelog() tracing is always + * constant. */ + +#if !defined(REWRITELOG_DISABLED) || !defined(AP_HAVE_C99) + +#ifdef AP_HAVE_C99 +static void do_rewritelog(int line, + request_rec *r, int level, char *perdir, + const char *fmt, ...) + __attribute__((format(printf,5,6))); +#else static void do_rewritelog(request_rec *r, int level, char *perdir, const char *fmt, ...) __attribute__((format(printf,4,5))); +#endif -static void do_rewritelog(request_rec *r, int level, char *perdir, +static void do_rewritelog( +#ifdef AP_HAVE_C99 + int line, +#endif + request_rec *r, int level, char *perdir, const char *fmt, ...) { +#ifndef REWRITELOG_DISABLED char *logline, *text; const char *rhost, *rname; int redir; @@ -502,11 +536,15 @@ static void do_rewritelog(request_rec *r, int level, char *perdir, AP_REWRITE_LOG((uintptr_t)r, level, r->main ? 0 : 1, (char *)ap_get_server_name(r), logline); /* Intentional no APLOGNO */ +#ifdef AP_HAVE_C99 + ap_log_rerror(__FILE__, line, APLOG_MODULE_INDEX, APLOG_DEBUG + level, 0, r, "%s", logline); +#else ap_log_rerror(APLOG_MARK, APLOG_DEBUG + level, 0, r, "%s", logline); - - return; -} +#endif + #endif /* !REWRITELOG_DISABLED */ +} +#endif /* !defined(REWRITELOG_DISABLED) || !defined(AP_HAVE_C99) */ /* @@ -799,7 +837,7 @@ static void splitout_queryargs(request_rec *r, int flags) int qslast = flags & RULEFLAG_QSLAST; if (flags & RULEFLAG_QSNONE) { - rewritelog((r, 2, NULL, "discarding query string, no parse from substitution")); + rewritelog(r, 2, NULL, "discarding query string, no parse from substitution"); r->args = NULL; return; } @@ -815,7 +853,7 @@ static void splitout_queryargs(request_rec *r, int flags) if (qsdiscard) { r->args = NULL; /* Discard query string */ - rewritelog((r, 2, NULL, "discarding query string")); + rewritelog(r, 2, NULL, "discarding query string"); } q = qslast ? ap_strrchr(r->filename + skip, '?') : ap_strchr(r->filename + skip, '?'); @@ -846,8 +884,8 @@ static void splitout_queryargs(request_rec *r, int flags) } } - rewritelog((r, 3, NULL, "split uri=%s -> uri=%s, args=%s", olduri, - r->filename, r->args ? r->args : "")); + rewritelog(r, 3, NULL, "split uri=%s -> uri=%s, args=%s", olduri, + r->filename, r->args ? r->args : ""); } } @@ -907,7 +945,7 @@ static void reduce_uri(request_rec *r) if (ap_matches_request_vhost(r, host, port)) { rewrite_server_conf *conf = ap_get_module_config(r->server->module_config, &rewrite_module); - rewritelog((r, 3, NULL, "reduce %s -> %s", r->filename, url)); + rewritelog(r, 3, NULL, "reduce %s -> %s", r->filename, url); r->filename = apr_pstrdup(r->pool, url); /* remember that the uri was reduced */ @@ -951,7 +989,7 @@ static void fully_qualify_uri(request_rec *r) static int startsWith(request_rec *r, const char *haystack, const char *needle) { int rc = (ap_strstr_c(haystack, needle) == haystack); - rewritelog((r, 5, NULL, "prefix_stat startsWith(%s, %s) %d", haystack, needle, rc)); + rewritelog(r, 5, NULL, "prefix_stat startsWith(%s, %s) %d", haystack, needle, rc); return rc; } /* @@ -992,12 +1030,12 @@ static int prefix_stat(request_rec *r, const char *path, apr_pool_t *pool, rewri if (apr_stat(&sb, statpath, APR_FINFO_MIN, pool) == APR_SUCCESS) { if (!lastsub) { - rewritelog((r, 3, NULL, "prefix_stat no lastsub subst prefix %s", statpath)); + rewritelog(r, 3, NULL, "prefix_stat no lastsub subst prefix %s", statpath); return 1; } - rewritelog((r, 3, NULL, "prefix_stat compare statpath %s and lastsub output %s STATOK %d ", - statpath, lastsub->output, lastsub->flags & RULEFLAG_UNSAFE_PREFIX_STAT)); + rewritelog(r, 3, NULL, "prefix_stat compare statpath %s and lastsub output %s STATOK %d ", + statpath, lastsub->output, lastsub->flags & RULEFLAG_UNSAFE_PREFIX_STAT); if (lastsub->flags & RULEFLAG_UNSAFE_PREFIX_STAT) { return 1; } @@ -1040,8 +1078,8 @@ static char *subst_prefix_path(request_rec *r, char *input, const char *match, apr_size_t slen, outlen; char *output; - rewritelog((r, 5, NULL, "strip matching prefix: %s -> %s", input, - input+len)); + rewritelog(r, 5, NULL, "strip matching prefix: %s -> %s", input, + input+len); slen = strlen(subst); if (slen && subst[slen - 1] != '/') { @@ -1058,8 +1096,8 @@ static char *subst_prefix_path(request_rec *r, char *input, const char *match, memcpy(output+slen, input+len, outlen - slen); output[outlen] = '\0'; - rewritelog((r, 4, NULL, "add subst prefix: %s -> %s", input+len, - output)); + rewritelog(r, 4, NULL, "add subst prefix: %s -> %s", input+len, + output); return output; } @@ -1525,7 +1563,7 @@ static char *lookup_map_dbd(request_rec *r, char *key, const char *label) return ret; default: /* what's a fair rewritelog level for this? */ - rewritelog((r, 3, NULL, "Multiple values found for %s", key)); + rewritelog(r, 3, NULL, "Multiple values found for %s", key); return ret; } } @@ -1730,29 +1768,29 @@ static char *lookup_map(request_rec *r, char *name, char *key) value = get_cache_value(s->cachename, st.mtime, key, r->pool); if (!value) { - rewritelog((r, 6, NULL, - "cache lookup FAILED, forcing new map lookup")); - + rewritelog(r, 6, NULL, + "cache lookup FAILED, forcing new map lookup"); + value = lookup_map_txtfile(r, s->datafile, key); if (!value) { - rewritelog((r, 5, NULL, "map lookup FAILED: map=%s[txt] key=%s", - name, key)); + rewritelog(r, 5, NULL, "map lookup FAILED: map=%s[txt] key=%s", + name, key); set_cache_value(s->cachename, st.mtime, key, ""); return NULL; } - rewritelog((r, 5, NULL,"map lookup OK: map=%s[txt] key=%s -> val=%s", - name, key, value)); + rewritelog(r, 5, NULL, "map lookup OK: map=%s[txt] key=%s -> val=%s", + name, key, value); set_cache_value(s->cachename, st.mtime, key, value); } else { - rewritelog((r,5,NULL,"cache lookup OK: map=%s[txt] key=%s -> val=%s", - name, key, value)); + rewritelog(r, 5, NULL, "cache lookup OK: map=%s[txt] key=%s -> val=%s", + name, key, value); } if (s->type == MAPTYPE_RND && *value) { value = select_random_value_part(r, value); - rewritelog((r, 5, NULL, "randomly chosen the subvalue `%s'",value)); + rewritelog(r, 5, NULL, "randomly chosen the subvalue `%s'",value); } return *value ? value : NULL; @@ -1786,26 +1824,26 @@ static char *lookup_map(request_rec *r, char *name, char *key) value = get_cache_value(s->cachename, st.mtime, key, r->pool); if (!value) { - rewritelog((r, 6, NULL, - "cache lookup FAILED, forcing new map lookup")); + rewritelog(r, 6, NULL, + "cache lookup FAILED, forcing new map lookup"); value = lookup_map_dbmfile(r, s->datafile, s->dbmtype, key); if (!value) { - rewritelog((r, 5, NULL, "map lookup FAILED: map=%s[dbm] key=%s", - name, key)); + rewritelog(r, 5, NULL, "map lookup FAILED: map=%s[dbm] key=%s", + name, key); set_cache_value(s->cachename, st.mtime, key, ""); return NULL; } - rewritelog((r, 5, NULL, "map lookup OK: map=%s[dbm] key=%s -> " - "val=%s", name, key, value)); + rewritelog(r, 5, NULL, "map lookup OK: map=%s[dbm] key=%s -> " + "val=%s", name, key, value); set_cache_value(s->cachename, st.mtime, key, value); return value; } - rewritelog((r, 5, NULL, "cache lookup OK: map=%s[dbm] key=%s -> val=%s", - name, key, value)); + rewritelog(r, 5, NULL, "cache lookup OK: map=%s[dbm] key=%s -> val=%s", + name, key, value); return *value ? value : NULL; /* @@ -1814,13 +1852,13 @@ static char *lookup_map(request_rec *r, char *name, char *key) case MAPTYPE_DBD: value = lookup_map_dbd(r, key, s->dbdq); if (!value) { - rewritelog((r, 5, NULL, "SQL map lookup FAILED: map %s key=%s", - name, key)); + rewritelog(r, 5, NULL, "SQL map lookup FAILED: map %s key=%s", + name, key); return NULL; } - rewritelog((r, 5, NULL, "SQL map lookup OK: map %s key=%s, val=%s", - name, key, value)); + rewritelog(r, 5, NULL, "SQL map lookup OK: map %s key=%s, val=%s", + name, key, value); return value; @@ -1830,26 +1868,26 @@ static char *lookup_map(request_rec *r, char *name, char *key) case MAPTYPE_DBD_CACHE: value = get_cache_value(s->cachename, 0, key, r->pool); if (!value) { - rewritelog((r, 6, NULL, - "cache lookup FAILED, forcing new map lookup")); + rewritelog(r, 6, NULL, + "cache lookup FAILED, forcing new map lookup"); value = lookup_map_dbd(r, key, s->dbdq); if (!value) { - rewritelog((r, 5, NULL, "SQL map lookup FAILED: map %s key=%s", - name, key)); + rewritelog(r, 5, NULL, "SQL map lookup FAILED: map %s key=%s", + name, key); set_cache_value(s->cachename, 0, key, ""); return NULL; } - rewritelog((r, 5, NULL, "SQL map lookup OK: map %s key=%s, val=%s", - name, key, value)); + rewritelog(r, 5, NULL, "SQL map lookup OK: map %s key=%s, val=%s", + name, key, value); set_cache_value(s->cachename, 0, key, value); return value; } - rewritelog((r, 5, NULL, "cache lookup OK: map=%s[SQL] key=%s, val=%s", - name, key, value)); + rewritelog(r, 5, NULL, "cache lookup OK: map=%s[SQL] key=%s, val=%s", + name, key, value); return *value ? value : NULL; /* @@ -1858,13 +1896,13 @@ static char *lookup_map(request_rec *r, char *name, char *key) case MAPTYPE_PRG: value = lookup_map_program(r, s->fpin, s->fpout, key); if (!value) { - rewritelog((r, 5,NULL,"map lookup FAILED: map=%s key=%s", name, - key)); + rewritelog(r, 5, NULL, "map lookup FAILED: map=%s key=%s", name, + key); return NULL; } - rewritelog((r, 5, NULL, "map lookup OK: map=%s key=%s -> val=%s", - name, key, value)); + rewritelog(r, 5, NULL, "map lookup OK: map=%s key=%s -> val=%s", + name, key, value); return value; /* @@ -1873,13 +1911,13 @@ static char *lookup_map(request_rec *r, char *name, char *key) case MAPTYPE_INT: value = s->func(r, key); if (!value) { - rewritelog((r, 5,NULL,"map lookup FAILED: map=%s key=%s", name, - key)); + rewritelog(r, 5, NULL, "map lookup FAILED: map=%s key=%s", name, + key); return NULL; } - rewritelog((r, 5, NULL, "map lookup OK: map=%s key=%s -> val=%s", - name, key, value)); + rewritelog(r, 5, NULL, "map lookup OK: map=%s key=%s -> val=%s", + name, key, value); return value; } @@ -1976,8 +2014,8 @@ static char *lookup_variable(char *var, rewrite_ctx *ctx) ctx->r = r; ap_destroy_sub_req(rr); - rewritelog((r, 5, ctx->perdir, "lookahead: path=%s var=%s " - "-> val=%s", path, var+5, result)); + rewritelog(r, 5, ctx->perdir, "lookahead: path=%s var=%s " + "-> val=%s", path, var+5, result); return (char *)result; } @@ -2011,8 +2049,8 @@ static char *lookup_variable(char *var, rewrite_ctx *ctx) ctx->r = r; ap_destroy_sub_req(rr); - rewritelog((r, 5, ctx->perdir, "lookahead: path=%s var=%s " - "-> val=%s", path, var+5, result)); + rewritelog(r, 5, ctx->perdir, "lookahead: path=%s var=%s " + "-> val=%s", path, var+5, result); return (char *)result; } @@ -2034,7 +2072,7 @@ static char *lookup_variable(char *var, rewrite_ctx *ctx) result = apr_psprintf(r->pool, "%04d%02d%02d%02d%02d%02d", tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); - rewritelog((r, 1, ctx->perdir, "RESULT='%s'", result)); + rewritelog(r, 1, ctx->perdir, "RESULT='%s'", result); return (char *)result; } else if (!strcmp(var, "IPV6")) { @@ -2043,9 +2081,9 @@ static char *lookup_variable(char *var, rewrite_ctx *ctx) apr_sockaddr_t *addr = r->useragent_addr; flag = (addr->family == AF_INET6 && !IN6_IS_ADDR_V4MAPPED((struct in6_addr *)addr->ipaddr_ptr)); - rewritelog((r, 1, ctx->perdir, "IPV6='%s'", flag ? "on" : "off")); + rewritelog(r, 1, ctx->perdir, "IPV6='%s'", flag ? "on" : "off"); #else - rewritelog((r, 1, ctx->perdir, "IPV6='off' (IPv6 is not enabled)")); + rewritelog(r, 1, ctx->perdir, "IPV6='off' (IPv6 is not enabled)"); #endif result = (flag ? "on" : "off"); } @@ -2553,8 +2591,8 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry, tmp = apr_pstrmemdup(pool, bri->source + bri->regmatch[n].rm_so, span); tmp2 = escape_backref(pool, tmp, entry->escapes, entry->noescapes, entry->flags); - rewritelog((ctx->r, 5, ctx->perdir, "escaping backreference '%s' to '%s'", - tmp, tmp2)); + rewritelog(ctx->r, 5, ctx->perdir, "escaping backreference '%s' to '%s'", + tmp, tmp2); current->len = span = strlen(tmp2); current->string = tmp2; @@ -2660,7 +2698,7 @@ static void do_expand_env(data_item *env, rewrite_ctx *ctx) if (*name == '!') { name++; apr_table_unset(ctx->r->subprocess_env, name); - rewritelog((ctx->r, 5, NULL, "unsetting env variable '%s'", name)); + rewritelog(ctx->r, 5, NULL, "unsetting env variable '%s'", name); } else { if ((val = ap_strchr(name, ':')) != NULL) { @@ -2670,8 +2708,8 @@ static void do_expand_env(data_item *env, rewrite_ctx *ctx) } apr_table_set(ctx->r->subprocess_env, name, val); - rewritelog((ctx->r, 5, NULL, "setting env variable '%s' to '%s'", - name, val)); + rewritelog(ctx->r, 5, NULL, "setting env variable '%s' to '%s'", + name, val); } env = env->next; @@ -2776,11 +2814,11 @@ static void add_cookie(request_rec *r, char *s) apr_table_addn(rmain->err_headers_out, "Set-Cookie", cookie); apr_pool_userdata_set("set", notename, NULL, rmain->pool); - rewritelog((rmain, 5, NULL, "setting cookie '%s'", cookie)); + rewritelog(rmain, 5, NULL, "setting cookie '%s'", cookie); } else { - rewritelog((rmain, 5, NULL, "skipping already set cookie '%s'", - var)); + rewritelog(rmain, 5, NULL, "skipping already set cookie '%s'", + var); } } @@ -4126,8 +4164,8 @@ static int apply_rewrite_cond(rewritecond_entry *p, rewrite_ctx *ctx) if (rsub->status < 400) { rc = 1; } - rewritelog((r, 5, NULL, "RewriteCond URI (-U) check: " - "path=%s -> status=%d", input, rsub->status)); + rewritelog(r, 5, NULL, "RewriteCond URI (-U check: " + "path=%s -> status=%d", input, rsub->status); ap_destroy_sub_req(rsub); } break; @@ -4141,9 +4179,9 @@ static int apply_rewrite_cond(rewritecond_entry *p, rewrite_ctx *ctx) r->pool) == APR_SUCCESS) { rc = 1; } - rewritelog((r, 5, NULL, "RewriteCond file (-F) check: path=%s " + rewritelog(r, 5, NULL, "RewriteCond file (-F check: path=%s " "-> file=%s status=%d", input, rsub->filename, - rsub->status)); + rsub->status); ap_destroy_sub_req(rsub); } break; @@ -4200,9 +4238,9 @@ static int apply_rewrite_cond(rewritecond_entry *p, rewrite_ctx *ctx) rc = ap_expr_exec_re(r, p->expr, AP_MAX_REG_MATCH, regmatch, &source, &err); if (rc < 0 || err) { - rewritelog((r, 1, ctx->perdir, + rewritelog(r, 1, ctx->perdir, "RewriteCond: expr='%s' evaluation failed: %s", - p->pattern - p->pskip, err)); + p->pattern - p->pskip, err); rc = 0; } /* update briRC backref info */ @@ -4228,10 +4266,10 @@ static int apply_rewrite_cond(rewritecond_entry *p, rewrite_ctx *ctx) rc = !rc; } - rewritelog((r, 4, ctx->perdir, "RewriteCond: input='%s' pattern='%s'%s " - "=> %s", input, p->pattern - p->pskip, - (p->flags & CONDFLAG_NOCASE) ? " [NC]" : "", - rc ? "matched" : "not-matched")); + rewritelog(r, 4, ctx->perdir, "RewriteCond: input='%s' pattern='%s'%s " + "=> %s", input, p->pattern - p->pskip, + (p->flags & CONDFLAG_NOCASE) ? " [NC]" : "", + rc ? "matched" : "not-matched"); return rc; } @@ -4248,8 +4286,8 @@ static APR_INLINE void force_type_handler(rewriterule_entry *p, if (*expanded) { ap_str_tolower(expanded); - rewritelog((ctx->r, 2, ctx->perdir, "remember %s to have MIME-type " - "'%s'", ctx->r->filename, expanded)); + rewritelog(ctx->r, 2, ctx->perdir, "remember %s to have MIME-type " + "'%s'", ctx->r->filename, expanded); apr_table_setn(ctx->r->notes, REWRITE_FORCED_MIMETYPE_NOTEVAR, expanded); @@ -4262,8 +4300,8 @@ static APR_INLINE void force_type_handler(rewriterule_entry *p, if (*expanded) { ap_str_tolower(expanded); - rewritelog((ctx->r, 2, ctx->perdir, "remember %s to have " - "Content-handler '%s'", ctx->r->filename, expanded)); + rewritelog(ctx->r, 2, ctx->perdir, "remember %s to have " + "Content-handler '%s'", ctx->r->filename, expanded); apr_table_setn(ctx->r->notes, REWRITE_FORCED_HANDLER_NOTEVAR, expanded); @@ -4300,8 +4338,8 @@ static rule_return_type apply_rewrite_rule(rewriterule_entry *p, * to re-add the PATH_INFO postfix */ if (r->path_info && *r->path_info) { - rewritelog((r, 3, ctx->perdir, "add path info postfix: %s -> %s%s", - ctx->uri, ctx->uri, r->path_info)); + rewritelog(r, 3, ctx->perdir, "add path info postfix: %s -> %s%s", + ctx->uri, ctx->uri, r->path_info); ctx->uri = apr_pstrcat(r->pool, ctx->uri, r->path_info, NULL); } @@ -4311,8 +4349,8 @@ static rule_return_type apply_rewrite_rule(rewriterule_entry *p, if (!is_proxyreq && strlen(ctx->uri) >= dirlen && !strncmp(ctx->uri, ctx->perdir, dirlen)) { - rewritelog((r, 3, ctx->perdir, "strip per-dir prefix: %s -> %s", - ctx->uri, ctx->uri + dirlen)); + rewritelog(r, 3, ctx->perdir, "strip per-dir prefix: %s -> %s", + ctx->uri, ctx->uri + dirlen); ctx->uri = ctx->uri + dirlen; } } @@ -4320,8 +4358,8 @@ static rule_return_type apply_rewrite_rule(rewriterule_entry *p, /* Try to match the URI against the RewriteRule pattern * and exit immediately if it didn't apply. */ - rewritelog((r, 3, ctx->perdir, "applying pattern '%s' to uri '%s'", - p->pattern, ctx->uri)); + rewritelog(r, 3, ctx->perdir, "applying pattern '%s' to uri '%s'", + p->pattern, ctx->uri); rc = !ap_regexec(p->regexp, ctx->uri, AP_MAX_REG_MATCH, regmatch, 0); if (! (( rc && !(p->flags & RULEFLAG_NOTMATCH)) || @@ -4402,8 +4440,8 @@ static rule_return_type apply_rewrite_rule(rewriterule_entry *p, else { newuri = do_expand(p->output, ctx, p, &unsafe_qmark); } - rewritelog((r, 2, ctx->perdir, "rewrite '%s' -> '%s'", ctx->uri, - newuri)); + rewritelog(r, 2, ctx->perdir, "rewrite '%s' -> '%s'", ctx->uri, + newuri); if (unsafe_qmark > 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10508) @@ -4423,8 +4461,8 @@ static rule_return_type apply_rewrite_rule(rewriterule_entry *p, force_type_handler(p, ctx); if (p->flags & RULEFLAG_STATUS) { - rewritelog((r, 2, ctx->perdir, "forcing responsecode %d for %s", - p->forced_responsecode, r->filename)); + rewritelog(r, 2, ctx->perdir, "forcing responsecode %d for %s", + p->forced_responsecode, r->filename); r->status = p->forced_responsecode; } @@ -4441,8 +4479,9 @@ static rule_return_type apply_rewrite_rule(rewriterule_entry *p, && !AP_IS_SLASH(*newuri) && !is_absolute_uri(newuri, NULL)) { if (ctx->perdir) { - rewritelog((r, 3, ctx->perdir, "add per-dir prefix: %s -> %s%s", - newuri, ctx->perdir, newuri)); + rewritelog(r, 3, ctx->perdir, "add per-dir prefix: %s -> %s%s", + newuri, ctx->perdir, newuri); + newuri = apr_pstrcat(r->pool, ctx->perdir, newuri, NULL); } else if (!(p->flags & (RULEFLAG_PROXY | RULEFLAG_FORCEREDIRECT))) { @@ -4453,8 +4492,8 @@ static rule_return_type apply_rewrite_rule(rewriterule_entry *p, * like "/some/pathscheme:..." to produce the fully qualified URL * "scheme:..." which could be misinterpreted later. */ - rewritelog((r, 3, ctx->perdir, "add root prefix: %s -> /%s", - newuri, newuri)); + rewritelog(r, 3, ctx->perdir, "add root prefix: %s -> /%s", + newuri, newuri); newuri = apr_pstrcat(r->pool, "/", newuri, NULL); } @@ -4487,14 +4526,14 @@ static rule_return_type apply_rewrite_rule(rewriterule_entry *p, char *old_filename = r->filename; r->filename = ap_escape_uri(r->pool, r->filename); - rewritelog((r, 2, ctx->perdir, "escaped URI in per-dir context " - "for proxy, %s -> %s", old_filename, r->filename)); + rewritelog(r, 2, ctx->perdir, "escaped URI in per-dir context " + "for proxy, %s -> %s", old_filename, r->filename); } fully_qualify_uri(r); - rewritelog((r, 2, ctx->perdir, "forcing proxy-throughput with %s", - r->filename)); + rewritelog(r, 2, ctx->perdir, "forcing proxy-throughput with %s", + r->filename); r->filename = apr_pstrcat(r->pool, "proxy:", r->filename, NULL); return RULE_RC_MATCH; @@ -4508,8 +4547,8 @@ static rule_return_type apply_rewrite_rule(rewriterule_entry *p, if (p->flags & RULEFLAG_FORCEREDIRECT) { fully_qualify_uri(r); - rewritelog((r, 2, ctx->perdir, "explicitly forcing redirect with %s", - r->filename)); + rewritelog(r, 2, ctx->perdir, "explicitly forcing redirect with %s", + r->filename); r->status = p->forced_responsecode; return RULE_RC_MATCH; @@ -4530,8 +4569,8 @@ static rule_return_type apply_rewrite_rule(rewriterule_entry *p, * directly force an external HTTP redirect. */ if (is_absolute_uri(r->filename, NULL)) { - rewritelog((r, 2, ctx->perdir, "implicitly forcing redirect (rc=%d) " - "with %s", p->forced_responsecode, r->filename)); + rewritelog(r, 2, ctx->perdir, "implicitly forcing redirect (rc=%d " + "with %s", p->forced_responsecode, r->filename); r->status = p->forced_responsecode; return RULE_RC_MATCH; @@ -4606,7 +4645,7 @@ static int apply_rewrite_list(request_rec *r, apr_array_header_t *rewriterules, if (rc != RULE_RC_NOMATCH) { if (!(p->flags & RULEFLAG_NOSUB)) { - rewritelog((r, 2, perdir, "setting lastsub to rule with output %s", p->output)); + rewritelog(r, 2, perdir, "setting lastsub to rule with output %s", p->output); *lastsub = p; } @@ -4656,8 +4695,8 @@ static int apply_rewrite_list(request_rec *r, apr_array_header_t *rewriterules, * modules like mod_alias, mod_userdir, etc. */ if (p->flags & RULEFLAG_PASSTHROUGH) { - rewritelog((r, 2, perdir, "forcing '%s' to get passed through " - "to next API URI-to-filename handler", r->filename)); + rewritelog(r, 2, perdir, "forcing '%s' to get passed through " + "to next API URI-to-filename handler", r->filename); r->filename = apr_pstrcat(r->pool, "passthrough:", r->filename, NULL); changed = ACTION_NORMAL; @@ -4665,7 +4704,7 @@ static int apply_rewrite_list(request_rec *r, apr_array_header_t *rewriterules, } if (p->flags & RULEFLAG_END) { - rewritelog((r, 8, perdir, "Rule has END flag, no further rewriting for this request")); + rewritelog(r, 8, perdir, "Rule has END flag, no further rewriting for this request"); apr_pool_userdata_set("1", really_last_key, apr_pool_cleanup_null, r->pool); break; } @@ -4866,7 +4905,7 @@ static int hook_uri2file(request_rec *r) /* END flag was used as a RewriteRule flag on this request */ apr_pool_userdata_get(&skipdata, really_last_key, r->pool); if (skipdata != NULL) { - rewritelog((r, 8, NULL, "Declining, no further rewriting due to END flag")); + rewritelog(r, 8, NULL, "Declining, no further rewriting due to END flag"); return DECLINED; } @@ -4876,10 +4915,10 @@ static int hook_uri2file(request_rec *r) if ((dconf->options & OPTION_ANYURI) == 0 && ((r->unparsed_uri[0] == '*' && r->unparsed_uri[1] == '\0') || !r->uri || r->uri[0] != '/')) { - rewritelog((r, 8, NULL, "Declining, request-URI '%s' is not a URL-path. " + rewritelog(r, 8, NULL, "Declining, request-URI '%s' is not a URL-path. " "Consult the manual entry for the RewriteOptions directive " "for options and caveats about matching other strings.", - r->uri)); + r->uri); return DECLINED; } @@ -4934,12 +4973,12 @@ static int hook_uri2file(request_rec *r) */ if (r->filename == NULL) { r->filename = apr_pstrdup(r->pool, r->uri); - rewritelog((r, 2, NULL, "init rewrite engine with requested uri %s", - r->filename)); + rewritelog(r, 2, NULL, "init rewrite engine with requested uri %s", + r->filename); } else { - rewritelog((r, 2, NULL, "init rewrite engine with passed filename " - "%s. Original uri = %s", r->filename, r->uri)); + rewritelog(r, 2, NULL, "init rewrite engine with passed filename " + "%s. Original uri = %s", r->filename, r->uri); } /* @@ -4950,8 +4989,8 @@ static int hook_uri2file(request_rec *r) apr_psprintf(r->pool,"%d",rulestatus)); } else { - rewritelog((r, 2, NULL, "uri already rewritten. Status %s, Uri %s, " - "r->filename %s", saved_rulestatus, r->uri, r->filename)); + rewritelog(r, 2, NULL, "uri already rewritten. Status %s, Uri %s, " + "r->filename %s", saved_rulestatus, r->uri, r->filename); rulestatus = atoi(saved_rulestatus); } @@ -5025,8 +5064,8 @@ static int hook_uri2file(request_rec *r) } r->handler = "proxy-server"; - rewritelog((r, 1, NULL, "go-ahead with proxy request %s [OK]", - r->filename)); + rewritelog(r, 1, NULL, "go-ahead with proxy request %s [OK]", + r->filename); return OK; } else if (skip_absolute > 0) { @@ -5035,8 +5074,8 @@ static int hook_uri2file(request_rec *r) /* it was finally rewritten to a remote URL */ if (rulestatus != ACTION_NOESCAPE) { - rewritelog((r, 1, NULL, "escaping %s for redirect", - r->filename)); + rewritelog(r, 1, NULL, "escaping %s for redirect", + r->filename); r->filename = escape_absolute_uri(r->pool, r->filename, skip_absolute); } @@ -5053,10 +5092,10 @@ static int hook_uri2file(request_rec *r) ap_escape_uri(r->pool, r->args)), NULL); - rewritelog((r, 1, NULL, "%s %s to query string for redirect %s", - noescape ? "copying" : "escaping", - r->args , - noescape ? "" : escaped_args)); + rewritelog(r, 1, NULL, "%s %s to query string for redirect %s", + noescape ? "copying" : "escaping", + r->args , + noescape ? "" : escaped_args); } /* determine HTTP redirect response code */ @@ -5070,8 +5109,8 @@ static int hook_uri2file(request_rec *r) /* now do the redirection */ apr_table_setn(r->headers_out, "Location", r->filename); - rewritelog((r, 1, NULL, "redirect to %s [REDIRECT/%d]", r->filename, - n)); + rewritelog(r, 1, NULL, "redirect to %s [REDIRECT/%d]", r->filename, + n); return n; } @@ -5095,7 +5134,7 @@ static int hook_uri2file(request_rec *r) #if APR_HAS_USER r->filename = expand_tildepaths(r, r->filename); #endif - rewritelog((r, 2, NULL, "local path result: %s", r->filename)); + rewritelog(r, 2, NULL, "local path result: %s", r->filename); /* the filename must be either an absolute local path or an * absolute local URL. @@ -5147,22 +5186,22 @@ static int hook_uri2file(request_rec *r) r->uri = tmp; if (res != OK) { - rewritelog((r, 1, NULL, "prefixing with document_root of %s" - " FAILED", r->filename)); + rewritelog(r, 1, NULL, "prefixing with document_root of %s" + " FAILED", r->filename); return res; } - rewritelog((r, 2, NULL, "prefixed with document_root to %s", - r->filename)); + rewritelog(r, 2, NULL, "prefixed with document_root to %s", + r->filename); } - rewritelog((r, 1, NULL, "go-ahead with %s [OK]", r->filename)); + rewritelog(r, 1, NULL, "go-ahead with %s [OK]", r->filename); return OK; } } else { - rewritelog((r, 1, NULL, "pass through %s", r->filename)); + rewritelog(r, 1, NULL, "pass through %s", r->filename); return DECLINED; } } @@ -5231,7 +5270,7 @@ static int hook_fixup(request_rec *r) /* END flag was used as a RewriteRule flag on this request */ apr_pool_userdata_get(&skipdata, really_last_key, r->pool); if (skipdata != NULL) { - rewritelog((r, 8, dconf->directory, "Declining, no further rewriting due to END flag")); + rewritelog(r, 8, dconf->directory, "Declining, no further rewriting due to END flag"); return DECLINED; } @@ -5261,8 +5300,8 @@ static int hook_fixup(request_rec *r) if (r->filename == NULL) { r->filename = apr_pstrdup(r->pool, r->uri); - rewritelog((r, 2, dconf->directory, "init rewrite engine with" - " requested uri %s", r->filename)); + rewritelog(r, 2, dconf->directory, "init rewrite engine with" + " requested uri %s", r->filename); } /* @@ -5321,8 +5360,8 @@ static int hook_fixup(request_rec *r) } r->handler = "proxy-server"; - rewritelog((r, 1, dconf->directory, "go-ahead with proxy request " - "%s [OK]", r->filename)); + rewritelog(r, 1, dconf->directory, "go-ahead with proxy request " + "%s [OK]", r->filename); return OK; } else if (skip_absolute > 0) { @@ -5337,9 +5376,9 @@ static int hook_fixup(request_rec *r) cp = r->filename + skip_absolute; if ((cp = ap_strchr(cp, '/')) != NULL && *(++cp)) { - rewritelog((r, 2, dconf->directory, - "trying to replace prefix %s with %s", - dconf->directory, dconf->baseurl)); + rewritelog(r, 2, dconf->directory, + "trying to replace prefix %s with %s", + dconf->directory, dconf->baseurl); /* I think, that hack needs an explanation: * well, here is it: @@ -5377,8 +5416,8 @@ static int hook_fixup(request_rec *r) /* now prepare the redirect... */ if (rulestatus != ACTION_NOESCAPE) { - rewritelog((r, 1, dconf->directory, "escaping %s for redirect", - r->filename)); + rewritelog(r, 1, dconf->directory, "escaping %s for redirect", + r->filename); r->filename = escape_absolute_uri(r->pool, r->filename, skip_absolute); } @@ -5394,10 +5433,10 @@ static int hook_fixup(request_rec *r) : (escaped_args = ap_escape_uri(r->pool, r->args)), NULL); - rewritelog((r, 1, dconf->directory, "%s %s to query string for redirect %s", - noescape ? "copying" : "escaping", - r->args , - noescape ? "" : escaped_args)); + rewritelog(r, 1, dconf->directory, "%s %s to query string for redirect %s", + noescape ? "copying" : "escaping", + r->args , + noescape ? "" : escaped_args); } /* determine HTTP redirect response code */ @@ -5411,8 +5450,8 @@ static int hook_fixup(request_rec *r) /* now do the redirection */ apr_table_setn(r->headers_out, "Location", r->filename); - rewritelog((r, 1, dconf->directory, "redirect to %s [REDIRECT/%d]", - r->filename, n)); + rewritelog(r, 1, dconf->directory, "redirect to %s [REDIRECT/%d]", + r->filename, n); return n; } else { @@ -5443,8 +5482,8 @@ static int hook_fixup(request_rec *r) * this would lead to a deadloop. */ if (ofilename != NULL && strcmp(r->filename, ofilename) == 0) { - rewritelog((r, 1, dconf->directory, "initial URL equal rewritten" - " URL: %s [IGNORING REWRITE]", r->filename)); + rewritelog(r, 1, dconf->directory, "initial URL equal rewritten" + " URL: %s [IGNORING REWRITE]", r->filename); return OK; } @@ -5457,8 +5496,8 @@ static int hook_fixup(request_rec *r) * plain URL */ if (dconf->baseurl != NULL) { - rewritelog((r, 2, dconf->directory, "trying to replace prefix " - "%s with %s", dconf->directory, dconf->baseurl)); + rewritelog(r, 2, dconf->directory, "trying to replace prefix " + "%s with %s", dconf->directory, dconf->baseurl); r->filename = subst_prefix_path(r, r->filename, dconf->directory, @@ -5478,9 +5517,9 @@ static int hook_fixup(request_rec *r) } if (!strncmp(r->filename, ccp, l) && r->filename[l] == '/') { - rewritelog((r, 2,dconf->directory, "strip document_root" - " prefix: %s -> %s", r->filename, - r->filename+l)); + rewritelog(r, 2,dconf->directory, "strip document_root" + " prefix: %s -> %s", r->filename, + r->filename+l); r->filename = apr_pstrdup(r->pool, r->filename+l); } @@ -5499,9 +5538,9 @@ static int hook_fixup(request_rec *r) if ((ccp = ap_context_document_root(r)) != NULL) { const char *prefix = ap_context_prefix(r); if (prefix != NULL) { - rewritelog((r, 2, dconf->directory, "trying to replace " + rewritelog(r, 2, dconf->directory, "trying to replace " "context docroot %s with context prefix %s", - ccp, prefix)); + ccp, prefix); r->filename = subst_prefix_path(r, r->filename, ccp, prefix); } @@ -5511,15 +5550,15 @@ static int hook_fixup(request_rec *r) apr_table_setn(r->notes, "redirect-keeps-vary", ""); /* now initiate the internal redirect */ - rewritelog((r, 1, dconf->directory, "internal redirect with %s " - "[INTERNAL REDIRECT]", r->filename)); + rewritelog(r, 1, dconf->directory, "internal redirect with %s " + "[INTERNAL REDIRECT]", r->filename); r->filename = apr_pstrcat(r->pool, "redirect:", r->filename, NULL); r->handler = REWRITE_REDIRECT_HANDLER_NAME; return OK; } } else { - rewritelog((r, 1, dconf->directory, "pass through %s", r->filename)); + rewritelog(r, 1, dconf->directory, "pass through %s", r->filename); r->filename = ofilename; return DECLINED; } @@ -5536,8 +5575,8 @@ static int hook_mimetype(request_rec *r) /* type */ t = apr_table_get(r->notes, REWRITE_FORCED_MIMETYPE_NOTEVAR); if (t && *t) { - rewritelog((r, 1, NULL, "force filename %s to have MIME-type '%s'", - r->filename, t)); + rewritelog(r, 1, NULL, "force filename %s to have MIME-type '%s'", + r->filename, t); ap_set_content_type_ex(r, t, 1); } @@ -5545,8 +5584,8 @@ static int hook_mimetype(request_rec *r) /* handler */ t = apr_table_get(r->notes, REWRITE_FORCED_HANDLER_NOTEVAR); if (t && *t) { - rewritelog((r, 1, NULL, "force filename %s to have the " - "Content-handler '%s'", r->filename, t)); + rewritelog(r, 1, NULL, "force filename %s to have the " + "Content-handler '%s'", r->filename, t); r->handler = t; } From 2ced3538006e4f4b27631aad637d3f184ba5762a Mon Sep 17 00:00:00 2001 From: Joe Orton Date: Tue, 20 Aug 2024 08:35:28 +0000 Subject: [PATCH 044/176] Merged x1. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1920053 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 7 ------- 1 file changed, 7 deletions(-) diff --git a/STATUS b/STATUS index e473e5cef2..821ffe19e6 100644 --- a/STATUS +++ b/STATUS @@ -157,13 +157,6 @@ RELEASE SHOWSTOPPERS: PATCHES ACCEPTED TO BACKPORT FROM TRUNK: [ start all new proposals below, under PATCHES PROPOSED. ] - *) mod_rewrite: backport better/simpler rewritelog() macro to fix - line numbers logged and make merging trunk->2.4.x easier - trunk patch: https://svn.apache.org/r1866894 - 2.4.x patch: https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/464.diff - PR: https://github.com/apache/httpd/pull/464 - +1: jorton, ylavic, covener - *) mod_proxy: Avoid AH01059 parsing error for SetHandler "unix:" URLs in (incomplete fix in 2.4.62). PR 69160. trunk patch: https://svn.apache.org/r1919532 From 2b6395afa785521d7ab5c12176dd26b3706e4d82 Mon Sep 17 00:00:00 2001 From: Ruediger Pluem Date: Wed, 21 Aug 2024 11:17:34 +0000 Subject: [PATCH 045/176] * Propose [skip ci] git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1920106 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/STATUS b/STATUS index 821ffe19e6..1b212e536a 100644 --- a/STATUS +++ b/STATUS @@ -228,6 +228,18 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: Can be applied via apply_backport_pr.sh 473 +1: covener, rpluem + *) mod_http: Trust content-type values set from configuration + r1918823 takes care of the content-type fix, while r1427465 + is backported to avoid a conflict. It removes support for Request-Range + header sent by Navigator 2-3 and MSIE 3. + Trunk version of patch: + https://svn.apache.org/r1427465 + https://svn.apache.org/r1918823 + Backport version for 2.4.x of patch: + https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/475.diff + Can be applied via apply_backport_pr.sh 475 + +1: rpluem, + PATCHES/ISSUES THAT ARE BEING WORKED [ New entries should be added at the START of the list ] From 6b57064ce81eb6ab8e3babc749b994f68fbd4fe1 Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Wed, 21 Aug 2024 11:37:03 +0000 Subject: [PATCH 046/176] vote [skip ci] git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1920108 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STATUS b/STATUS index 1b212e536a..c521598bee 100644 --- a/STATUS +++ b/STATUS @@ -238,7 +238,7 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: Backport version for 2.4.x of patch: https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/475.diff Can be applied via apply_backport_pr.sh 475 - +1: rpluem, + +1: rpluem, covener PATCHES/ISSUES THAT ARE BEING WORKED [ New entries should be added at the START of the list ] From 0505437f3c33cd45ebaf97d5c2819071e3ca791a Mon Sep 17 00:00:00 2001 From: Ruediger Pluem Date: Wed, 21 Aug 2024 12:38:12 +0000 Subject: [PATCH 047/176] Merge r1920109 from trunk: * Fix typo in anchor [skip ci] Submitted by: rpluem Reviewed by: rpluem git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1920110 13f79535-47bb-0310-9956-ffa450edef68 --- docs/manual/rewrite/flags.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/manual/rewrite/flags.xml b/docs/manual/rewrite/flags.xml index 9e287ec9ee..bd1c52a4b3 100644 --- a/docs/manual/rewrite/flags.xml +++ b/docs/manual/rewrite/flags.xml @@ -859,7 +859,7 @@ The L flag can be useful in this context to end the URL taking advantage of a capture and re-substitution of the encoded question mark.

    -
    UnsafePrefixStat +
    UnsafePrefixStat

    Setting this flag is required in server-scoped substitutions start with a variable or backreference and resolve to a filesystem path. These substitutions are not prefixed with the document root. From 9bf076ffa60265b0e1f350c241ef0d892e8acc06 Mon Sep 17 00:00:00 2001 From: Joe Orton Date: Wed, 21 Aug 2024 14:05:50 +0000 Subject: [PATCH 048/176] Merge r1920050 from trunk: CI: Install libsasl2-dev to fix build errors with APR trunk/apr-util 1.7.x https://lists.apache.org/thread/8hhs2otod7fo44964yd1csck3ddm1fq2 CI: Add job to test LDAP with the (apr 1.7.x, apr-util 1.7.x) combination. Github: closes #474 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1920118 13f79535-47bb-0310-9956-ffa450edef68 --- .github/workflows/linux.yml | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index cbc6fd55d6..e3ff70d341 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -153,6 +153,20 @@ jobs: TEST_ARGS="-defines LDAP" TESTS="t/modules/" # ------------------------------------------------------------------------- + - name: APR 1.7.x, APR-util 1.7.x, LDAP + config: --enable-mods-shared=reallyall + pkgs: ldap-utils + env: | + APR_VERSION=1.7.x + APU_VERSION=1.7.x + APU_CONFIG="--with-crypto --with-ldap" + TEST_MALLOC=1 + TEST_LDAP=1 + TEST_ARGS="-defines LDAP" + TESTS="t/modules/" + CLEAR_CACHE=1 + # ------------------------------------------------------------------------- + ### TODO: if: *condition_not_24x - name: APR trunk thread debugging config: --enable-mods-shared=reallyall --with-mpm=event env: | @@ -258,7 +272,7 @@ jobs: cpanminus libtool-bin libapr1-dev libaprutil1-dev liblua5.3-dev libbrotli-dev libcurl4-openssl-dev libnghttp2-dev libjansson-dev libpcre2-dev gdb - perl-doc ${{ matrix.pkgs }} + perl-doc libsasl2-dev ${{ matrix.pkgs }} - uses: actions/checkout@v4 - name: Cache installed libraries uses: actions/cache@v4 From 59242738846df0ec41caf0e6acd29292012b469e Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Thu, 22 Aug 2024 12:09:36 +0000 Subject: [PATCH 049/176] start noting some must-have PRs git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1920134 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/STATUS b/STATUS index c521598bee..9237019254 100644 --- a/STATUS +++ b/STATUS @@ -153,6 +153,8 @@ CURRENT RELEASE NOTES: RELEASE SHOWSTOPPERS: +- PR69235 +- PR69260 PATCHES ACCEPTED TO BACKPORT FROM TRUNK: [ start all new proposals below, under PATCHES PROPOSED. ] From 0e1c74fac1057b67756698e6fa0c4c793abc4409 Mon Sep 17 00:00:00 2001 From: Lucien Gentis Date: Sat, 24 Aug 2024 16:23:33 +0000 Subject: [PATCH 050/176] fr doc XML files updates. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1920162 13f79535-47bb-0310-9956-ffa450edef68 --- docs/manual/mod/mod_rewrite.xml.fr | 6 ++++-- docs/manual/rewrite/flags.xml.fr | 8 ++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/manual/mod/mod_rewrite.xml.fr b/docs/manual/mod/mod_rewrite.xml.fr index b484c60863..60601caf55 100644 --- a/docs/manual/mod/mod_rewrite.xml.fr +++ b/docs/manual/mod/mod_rewrite.xml.fr @@ -1644,7 +1644,8 @@ substitution ! Autorise les substitutions potentiellement non fiables à partir d’une variable de tête ou d’une référence arrière vers un chemin du système de fichiers. - détails ... + détails ...
    + 2.4.60 @@ -1652,7 +1653,8 @@ substitution ! Empêche la fusion des slashes de début multiples tels que ceux utilisés dans les chemins UNC de Windows. - détails ... + détails ...
    + 2.4.62 diff --git a/docs/manual/rewrite/flags.xml.fr b/docs/manual/rewrite/flags.xml.fr index e6681d0b1f..059bea3780 100644 --- a/docs/manual/rewrite/flags.xml.fr +++ b/docs/manual/rewrite/flags.xml.fr @@ -1,7 +1,7 @@ - + @@ -918,13 +918,15 @@ utiliser le drapeau L pour terminer la séquence la substitution. Cela protège d’une URL malveillante tirant avantage d’une capture et d’une resubstitution du point d'interrogation encodé.

    -
    UnsafePrefixStat +
    UnsafePrefixStat

    La définition de ce drapeau est requise dans les substitutions à l'échelle du serveur qui commencent par une variable ou une référence arrière et se résolvent en un chemin du système de fichiers. Ces substitutions ne sont pas préfixées par la racine des documents. Cela protège d’une URL malveillante faisant correspondre la substitution expansée à un emplacement non souhaité du système de fichiers.

    + +

    2.4.60

    UNC @@ -932,6 +934,8 @@ utiliser le drapeau L pour terminer la séquence que ceux utilisés dans les chemins UNC de Windows. Ce drapeau n’est pas nécessaire lorsque la substitution de la règle commence par des slashes multiples littéraux.

    + +

    2.4.62

    From fac4547cd03aae7383d02cb1c117a660f4fc88cd Mon Sep 17 00:00:00 2001 From: Lucien Gentis Date: Sat, 24 Aug 2024 16:27:25 +0000 Subject: [PATCH 051/176] fr doc XML file update. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1920163 13f79535-47bb-0310-9956-ffa450edef68 --- docs/manual/mod/mod_rewrite.xml.fr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/manual/mod/mod_rewrite.xml.fr b/docs/manual/mod/mod_rewrite.xml.fr index 60601caf55..2b4b47dec7 100644 --- a/docs/manual/mod/mod_rewrite.xml.fr +++ b/docs/manual/mod/mod_rewrite.xml.fr @@ -1,7 +1,7 @@ - + From 668512cbfced165c7eed5432e8798b24bb9fb1e9 Mon Sep 17 00:00:00 2001 From: Lucien Gentis Date: Sat, 24 Aug 2024 16:28:38 +0000 Subject: [PATCH 052/176] fr doc rebuild. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1920164 13f79535-47bb-0310-9956-ffa450edef68 --- docs/manual/mod/mod_rewrite.html.fr.utf8 | 6 ++++-- docs/manual/rewrite/flags.html.fr.utf8 | 8 ++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/manual/mod/mod_rewrite.html.fr.utf8 b/docs/manual/mod/mod_rewrite.html.fr.utf8 index 32e5be75bd..afdec670b5 100644 --- a/docs/manual/mod/mod_rewrite.html.fr.utf8 +++ b/docs/manual/mod/mod_rewrite.html.fr.utf8 @@ -1574,7 +1574,8 @@ substitution ! Autorise les substitutions potentiellement non fiables à partir d’une variable de tête ou d’une référence arrière vers un chemin du système de fichiers. - détails ... + détails ...
    + Disponible à partir de la version 2.4.60 du serveur HTTP Apache. @@ -1582,7 +1583,8 @@ substitution ! Empêche la fusion des slashes de début multiples tels que ceux utilisés dans les chemins UNC de Windows. - détails ... + détails ...
    + Disponible à partir de la version 2.4.62 du serveur HTTP Apache. diff --git a/docs/manual/rewrite/flags.html.fr.utf8 b/docs/manual/rewrite/flags.html.fr.utf8 index 6d6a05d786..0d01cfac50 100644 --- a/docs/manual/rewrite/flags.html.fr.utf8 +++ b/docs/manual/rewrite/flags.html.fr.utf8 @@ -57,7 +57,7 @@ l'espace en +)
  • S|skip
  • T|type
  • UnsafeAllow3F
  • -
  • UnsafePrefixStat
  • +
  • UnsafePrefixStat
  • UNC
  • Voir aussi

    @@ -892,13 +892,15 @@ utiliser le drapeau L pour terminer la séquence capture et d’une resubstitution du point d'interrogation encodé.

    top
    -

    UnsafePrefixStat

    +

    UnsafePrefixStat

    La définition de ce drapeau est requise dans les substitutions à l'échelle du serveur qui commencent par une variable ou une référence arrière et se résolvent en un chemin du système de fichiers. Ces substitutions ne sont pas préfixées par la racine des documents. Cela protège d’une URL malveillante faisant correspondre la substitution expansée à un emplacement non souhaité du système de fichiers.

    + +

    Disponible à partir de la version 2.4.60 du serveur HTTP Apache.

    top

    UNC

    @@ -906,6 +908,8 @@ utiliser le drapeau L pour terminer la séquence que ceux utilisés dans les chemins UNC de Windows. Ce drapeau n’est pas nécessaire lorsque la substitution de la règle commence par des slashes multiples littéraux.

    + +

    Disponible à partir de la version 2.4.62 du serveur HTTP Apache.

    Langues Disponibles:  en  | From 3ee5a5bc0171c41eac42d6364a3eee3574f903c7 Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Wed, 11 Sep 2024 13:09:55 +0000 Subject: [PATCH 053/176] propose [skip CI] git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1920565 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/STATUS b/STATUS index 9237019254..6331c6b930 100644 --- a/STATUS +++ b/STATUS @@ -242,6 +242,14 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: Can be applied via apply_backport_pr.sh 475 +1: rpluem, covener + *) Windows: Make UNCList EXEC_ON_READ to be early enough for + `Include //computername/include.conf`. PR69313 + Trunk version of patch: + https://svn.apache.org/r1920564 + Backport version for 2.4.x of patch: + svn merge -c r1920564 ^/httpd/httpd/trunk . + +1 covener + PATCHES/ISSUES THAT ARE BEING WORKED [ New entries should be added at the START of the list ] From 4ce009c695b6372dde7195ebfe52742b8d044df1 Mon Sep 17 00:00:00 2001 From: Ruediger Pluem Date: Wed, 11 Sep 2024 14:39:08 +0000 Subject: [PATCH 054/176] * Vote [skip ci] git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1920567 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STATUS b/STATUS index 6331c6b930..ae5a5b81de 100644 --- a/STATUS +++ b/STATUS @@ -248,7 +248,7 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: https://svn.apache.org/r1920564 Backport version for 2.4.x of patch: svn merge -c r1920564 ^/httpd/httpd/trunk . - +1 covener + +1 covener, rpluem PATCHES/ISSUES THAT ARE BEING WORKED [ New entries should be added at the START of the list ] From 76034c2c8aca0ba58189e0501fdfa805cc290e6c Mon Sep 17 00:00:00 2001 From: Ruediger Pluem Date: Wed, 11 Sep 2024 14:42:32 +0000 Subject: [PATCH 055/176] * Add proposal [skip ci] git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1920568 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/STATUS b/STATUS index ae5a5b81de..35e9307c36 100644 --- a/STATUS +++ b/STATUS @@ -250,6 +250,14 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: svn merge -c r1920564 ^/httpd/httpd/trunk . +1 covener, rpluem + *) mod_rewrite: Improve safe question mark detection + Trunk version of patch: + https://svn.apache.org/r1920566 + Backport version for 2.4.x of patch: + Trunk version of patch works + svn merge -c 1920566 ^/httpd/httpd/trunk . + +1: rpluem, + PATCHES/ISSUES THAT ARE BEING WORKED [ New entries should be added at the START of the list ] From 057549f50c31d13688697bccddb701dd6fbe3b10 Mon Sep 17 00:00:00 2001 From: Steffen Land Date: Wed, 11 Sep 2024 15:27:41 +0000 Subject: [PATCH 056/176] git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1920569 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/STATUS b/STATUS index 35e9307c36..b6fb667eb8 100644 --- a/STATUS +++ b/STATUS @@ -248,7 +248,7 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: https://svn.apache.org/r1920564 Backport version for 2.4.x of patch: svn merge -c r1920564 ^/httpd/httpd/trunk . - +1 covener, rpluem + +1 covener, rpluem, steffenal *) mod_rewrite: Improve safe question mark detection Trunk version of patch: From a723338e1f4184ba14525dd372e0a9f76fffc022 Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Thu, 12 Sep 2024 10:16:52 +0000 Subject: [PATCH 057/176] promote, track another must-have [skip ci] git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1920590 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/STATUS b/STATUS index b6fb667eb8..7e4449c693 100644 --- a/STATUS +++ b/STATUS @@ -155,6 +155,8 @@ RELEASE SHOWSTOPPERS: - PR69235 - PR69260 +- PR69203 + PATCHES ACCEPTED TO BACKPORT FROM TRUNK: [ start all new proposals below, under PATCHES PROPOSED. ] @@ -172,6 +174,15 @@ PATCHES ACCEPTED TO BACKPORT FROM TRUNK: 2.4.x patch: svn merge -c r1914038 ^/httpd/httpd/trunk . +1: minfrin, covener, rpluem + *) Windows: Make UNCList EXEC_ON_READ to be early enough for + `Include //computername/include.conf`. PR69313 + Trunk version of patch: + https://svn.apache.org/r1920564 + Backport version for 2.4.x of patch: + svn merge -c r1920564 ^/httpd/httpd/trunk . + +1 covener, rpluem, steffenal + + PATCHES PROPOSED TO BACKPORT FROM TRUNK: [ New proposals should be added at the end of the list ] @@ -242,14 +253,6 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: Can be applied via apply_backport_pr.sh 475 +1: rpluem, covener - *) Windows: Make UNCList EXEC_ON_READ to be early enough for - `Include //computername/include.conf`. PR69313 - Trunk version of patch: - https://svn.apache.org/r1920564 - Backport version for 2.4.x of patch: - svn merge -c r1920564 ^/httpd/httpd/trunk . - +1 covener, rpluem, steffenal - *) mod_rewrite: Improve safe question mark detection Trunk version of patch: https://svn.apache.org/r1920566 From b7988b2d974872fd8f66f45b7b9600926c04aaf7 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Tue, 17 Sep 2024 11:17:23 +0000 Subject: [PATCH 058/176] Merged /httpd/httpd/trunk:r1920744 *) mod_tls: removed the experimental module. It now is availble standalone from https://github.com/icing/mod_tls. The rustls provided API is not stable and does not align with the httpd release cycle. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1920745 13f79535-47bb-0310-9956-ffa450edef68 --- .github/workflows/linux.yml | 11 - changes-entries/tls_removed.txt | 4 + docs/manual/mod/allmodules.xml | 1 - docs/manual/mod/mod_tls.xml | 640 -------- modules/tls/Makefile.in | 20 - modules/tls/config2.m4 | 173 -- modules/tls/mod_tls.c | 288 ---- modules/tls/mod_tls.h | 19 - modules/tls/tls_cache.c | 310 ---- modules/tls/tls_cache.h | 63 - modules/tls/tls_cert.c | 583 ------- modules/tls/tls_cert.h | 211 --- modules/tls/tls_conf.c | 780 --------- modules/tls/tls_conf.h | 185 --- modules/tls/tls_core.c | 1439 ----------------- modules/tls/tls_core.h | 184 --- modules/tls/tls_filter.c | 1017 ------------ modules/tls/tls_filter.h | 90 -- modules/tls/tls_ocsp.c | 120 -- modules/tls/tls_ocsp.h | 47 - modules/tls/tls_proto.c | 603 ------- modules/tls/tls_proto.h | 124 -- modules/tls/tls_util.c | 367 ----- modules/tls/tls_util.h | 157 -- modules/tls/tls_var.c | 397 ----- modules/tls/tls_var.h | 39 - modules/tls/tls_version.h | 39 - test/modules/tls/__init__.py | 0 test/modules/tls/conf.py | 68 - test/modules/tls/conftest.py | 38 - test/modules/tls/env.py | 199 --- .../tls/htdocs/a.mod-tls.test/index.json | 3 - .../modules/tls/htdocs/a.mod-tls.test/vars.py | 56 - .../tls/htdocs/b.mod-tls.test/dir1/vars.py | 23 - .../tls/htdocs/b.mod-tls.test/index.json | 3 - .../tls/htdocs/b.mod-tls.test/resp-jitter.py | 23 - .../modules/tls/htdocs/b.mod-tls.test/vars.py | 56 - test/modules/tls/htdocs/index.html | 9 - test/modules/tls/htdocs/index.json | 3 - test/modules/tls/test_01_apache.py | 14 - test/modules/tls/test_02_conf.py | 144 -- test/modules/tls/test_03_sni.py | 89 - test/modules/tls/test_04_get.py | 67 - test/modules/tls/test_05_proto.py | 64 - test/modules/tls/test_06_ciphers.py | 212 --- test/modules/tls/test_07_alpn.py | 45 - test/modules/tls/test_08_vars.py | 75 - test/modules/tls/test_09_timeout.py | 43 - test/modules/tls/test_10_session_id.py | 50 - test/modules/tls/test_11_md.py | 37 - test/modules/tls/test_12_cauth.py | 235 --- test/modules/tls/test_13_proxy.py | 40 - test/modules/tls/test_14_proxy_ssl.py | 125 -- test/modules/tls/test_15_proxy_tls.py | 97 -- test/modules/tls/test_16_proxy_mixed.py | 50 - .../modules/tls/test_17_proxy_machine_cert.py | 70 - test/travis_run_linux.sh | 8 - 57 files changed, 4 insertions(+), 9853 deletions(-) create mode 100644 changes-entries/tls_removed.txt delete mode 100644 docs/manual/mod/mod_tls.xml delete mode 100644 modules/tls/Makefile.in delete mode 100644 modules/tls/config2.m4 delete mode 100644 modules/tls/mod_tls.c delete mode 100644 modules/tls/mod_tls.h delete mode 100644 modules/tls/tls_cache.c delete mode 100644 modules/tls/tls_cache.h delete mode 100644 modules/tls/tls_cert.c delete mode 100644 modules/tls/tls_cert.h delete mode 100644 modules/tls/tls_conf.c delete mode 100644 modules/tls/tls_conf.h delete mode 100644 modules/tls/tls_core.c delete mode 100644 modules/tls/tls_core.h delete mode 100644 modules/tls/tls_filter.c delete mode 100644 modules/tls/tls_filter.h delete mode 100644 modules/tls/tls_ocsp.c delete mode 100644 modules/tls/tls_ocsp.h delete mode 100644 modules/tls/tls_proto.c delete mode 100644 modules/tls/tls_proto.h delete mode 100644 modules/tls/tls_util.c delete mode 100644 modules/tls/tls_util.h delete mode 100644 modules/tls/tls_var.c delete mode 100644 modules/tls/tls_var.h delete mode 100644 modules/tls/tls_version.h delete mode 100644 test/modules/tls/__init__.py delete mode 100644 test/modules/tls/conf.py delete mode 100644 test/modules/tls/conftest.py delete mode 100644 test/modules/tls/env.py delete mode 100644 test/modules/tls/htdocs/a.mod-tls.test/index.json delete mode 100755 test/modules/tls/htdocs/a.mod-tls.test/vars.py delete mode 100755 test/modules/tls/htdocs/b.mod-tls.test/dir1/vars.py delete mode 100644 test/modules/tls/htdocs/b.mod-tls.test/index.json delete mode 100755 test/modules/tls/htdocs/b.mod-tls.test/resp-jitter.py delete mode 100755 test/modules/tls/htdocs/b.mod-tls.test/vars.py delete mode 100644 test/modules/tls/htdocs/index.html delete mode 100644 test/modules/tls/htdocs/index.json delete mode 100644 test/modules/tls/test_01_apache.py delete mode 100644 test/modules/tls/test_02_conf.py delete mode 100644 test/modules/tls/test_03_sni.py delete mode 100644 test/modules/tls/test_04_get.py delete mode 100644 test/modules/tls/test_05_proto.py delete mode 100644 test/modules/tls/test_06_ciphers.py delete mode 100644 test/modules/tls/test_07_alpn.py delete mode 100644 test/modules/tls/test_08_vars.py delete mode 100644 test/modules/tls/test_09_timeout.py delete mode 100644 test/modules/tls/test_10_session_id.py delete mode 100644 test/modules/tls/test_11_md.py delete mode 100644 test/modules/tls/test_12_cauth.py delete mode 100644 test/modules/tls/test_13_proxy.py delete mode 100644 test/modules/tls/test_14_proxy_ssl.py delete mode 100644 test/modules/tls/test_15_proxy_tls.py delete mode 100644 test/modules/tls/test_16_proxy_mixed.py delete mode 100644 test/modules/tls/test_17_proxy_machine_cert.py diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index e3ff70d341..69c3fd380c 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -224,17 +224,6 @@ jobs: # TEST_MD=1 # ------------------------------------------------------------------------- ### TODO: if: *condition_not_24x - - name: MOD_TLS test suite - config: --enable-mods-shared=reallyall --with-mpm=event --enable-mpms-shared=event - pkgs: curl python3-pytest nghttp2-client python3-cryptography python3-requests python3-multipart python3-filelock python3-websockets cargo cbindgen - env: | - APR_VERSION=1.7.4 - APU_VERSION=1.6.3 - APU_CONFIG="--with-crypto" - RUSTLS_VERSION="v0.13.0" - NO_TEST_FRAMEWORK=1 - TEST_INSTALL=1 - TEST_MOD_TLS=1 # ------------------------------------------------------------------------- ### TODO if: *condition_not_24x ### TODO: Fails because :i386 packages are not being found. diff --git a/changes-entries/tls_removed.txt b/changes-entries/tls_removed.txt new file mode 100644 index 0000000000..d56a3dc4e9 --- /dev/null +++ b/changes-entries/tls_removed.txt @@ -0,0 +1,4 @@ + *) mod_tls: removed the experimental module. It now is availble standalone + from https://github.com/icing/mod_tls. The rustls provided API is not + stable and does not align with the httpd release cycle. + [Stefan Eissing] diff --git a/docs/manual/mod/allmodules.xml b/docs/manual/mod/allmodules.xml index 9f45eaafed..8fdd483eaa 100644 --- a/docs/manual/mod/allmodules.xml +++ b/docs/manual/mod/allmodules.xml @@ -119,7 +119,6 @@ mod_substitute.xml mod_suexec.xml mod_systemd.xml - mod_tls.xml mod_unique_id.xml mod_unixd.xml mod_userdir.xml diff --git a/docs/manual/mod/mod_tls.xml b/docs/manual/mod/mod_tls.xml deleted file mode 100644 index 8e88923482..0000000000 --- a/docs/manual/mod/mod_tls.xml +++ /dev/null @@ -1,640 +0,0 @@ - - - - - - - - - - mod_tls - TLS v1.2 and v1.3 implemented in memory-safe Rust via - the rustls library - - Experimental - mod_tls.c - tls_module - Available in version 2.4.52 and later -

    -

    - mod_tls is an alternative to mod_ssl for providing https to a server. - It's feature set is a subset, described in more detail below. It can - be used as a companion to mod_ssl, e.g. both modules can be loaded at - the same time. -

    - mod_tls, being written in C, used the Rust implementation of TLS named - rustls via its C interface - rustls-ffi. This gives - memory safe cryptography and protocol handling at comparable - performance. -

    - It can be configured for frontend and backend connections. The configuration - directive have been kept mostly similar to mod_ssl ones. -

    -
    -
    - TLS in a VirtualHost context - -Listen 443 -TLSEngine 443 - -<VirtualHost *:443> - ServerName example.net - TLSCertificate file_with_certificate.pem file_with_key.pem - ... -</VirtualHost> - -

    - The above is a minimal configuration. Instead of enabling mod_tls - in every virtual host, the port for incoming TLS connections is - specified. -

    - You cannot mix virtual hosts with mod_ssl and mod_tls on the same - port. It's either or. SNI and ALPN are supported. You may use several - virtual hosts on the same port and a mix of protocols like http/1.1 - and h2. -

    -
    - -
    Feature Comparison with mod_ssl -

    - The table below gives a comparison of feature between - mod_ssl and mod_tls. If a feature of mod_ssl is no listed here, - it is not supported by mod_tls. The one difference, probably most relevant - is the lack for client certificate support in the current version of - mod_tls. -

    - - - - - - - - - - - - - - - - - - - - - - - -
    Featuremod_sslmod_tlsComment
    Frontend TLSyesyes
    Backend TLSyesyes
    TLS v1.3yes*yes*)with recent OpenSSL
    TLS v1.2yesyes
    TLS v1.0yes*no*)if enabled in OpenSSL
    SNI Virtual Hostsyesyes
    Client Certificatesyesno
    Machine Certificates for Backendyesyes
    OCSP Staplingyesyes**)via mod_md
    Backend OCSP checkyesno**)stapling will be verified
    TLS version to allowmin-maxmin
    TLS ciphersexclusive listpreferred/suppressed
    TLS cipher orderingclient/serverclient/server
    TLS sessionsyesyes
    SNI strictnessdefault nodefault yes
    Option EnvVarsexhaustivelimited**)see var list
    Option ExportCertDataclient+serverserver
    Backend CAfile/dirfile
    Revocation CRLsyesno
    TLS Renegotiationyes*no*)in TLS v1.2
    Encrypted Cert Keysyesno
    -

    -

    -
    - -
    TLS Protocols -

    - mod_tls supports TLS protocol version 1.2 and 1.3. Should there ever be - a version 1.4 and rustls supports it, it will be available as well. -

    -

    - In mod_tls, you configure the minimum version to use, never the maximum: -

    - -TLSProtocol TLSv1.3+ - -

    - This allows only version 1.3 and whatever may be its successor one day when talking - to your server or to a particular virtual host. -

    -
    - -
    TLS Ciphers -

    - The list of TLS ciphers supported in the rustls library, - can be found here. All TLS v1.3 - ciphers are supported. For TLS v1.2, only ciphers that rustls considers - secure are available. -

    - mod_tls supports the following names for TLS ciphers: -

    -
      -
    1. - The IANA assigned name - which uses `_` to separate parts. Example: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 -
    2. -
    3. - The OpenSSL name, using `-` as separator (for 1.2). Example: ECDHE-ECDSA-AES256-SHA384. - Such names often appear in documentation. `mod_tls` defines them for all TLS v1.2 ciphers. - For TLS v1.3 ciphers, names starting with TLS13_ are also supported. -
    4. -
    5. - The IANA assigned identifier, - which is a 16-bit numeric value. Example: 0xc024. - You can use this in configurations as TLS_CIPHER_0xc024. -
    6. -
    -

    - You can configure a preference for ciphers, which means they will be used - for clients that support them. If you do not configure a preference, rustls - will use the one that it considers best. This is recommended. -

    -

    - Should you nevertheless have the need to prefer one cipher over another, you - may configure it like this: -

    - -TLSCiphersPrefer ECDHE-ECDSA-AES256-SHA384 -# or several -TLSCiphersPrefer ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305 - -

    - If you name a cipher that is unknown, the configuration will fail. - If you name a cipher is not supported by rustls (or no - longer supported in an updated version of rustls for security - reasons), mod_tls will log a WARNING, but continue to work. -

    -

    - A similar mechanism exists, if you want to disable a particular cipher: -

    - -TLSCipherSuppress ECDHE-ECDSA-AES256-SHA384 - -

    - A suppressed cipher will not longer be used. - If you name a cipher that is unknown, the configuration will fail. - If you name a cipher is not supported by rustls (or no - longer supported in an updated version of rustls for security - reasons), mod_tls will log a WARNING, but continue to work. -

    -
    - -
    Virtual Hosts -

    - mod_tls uses the SNI (Server Name Indicator) to select one of the - configured virtual hosts that match the port being served. Should - the client not provide an SNI, the first configured - virtual host will be selected. If the client does provide - an SNI (as all today's clients do), it must match one - virtual host (ServerName or - ServerAlias) - or the connection will fail. -

    -

    - As with mod_ssl, you may specify ciphers and protocol - versions for the base server (global) and/or individual virtual hosts - that are selected via SNI by the client. -

    - -Listen 443 -TLSEngine 443 - -<VirtualHost *:443> - ServerName example1.net - TLSCertificate example1-cert.pem - ... -</VirtualHost> - -<VirtualHost *:443> - ServerName example2.net - TLSCertificate example2-cert.pem - ... - TLSProtocol v1.3+ -</VirtualHost> - -

    - The example above show different TLS settings for virtual hosts on the - same port. This is supported. example1 can be contacted via - all TLS versions and example2 only allows v1.3 or later. -

    -
    - -
    ACME Certificates -

    - ACME certificates via mod_md are supported, just as - for mod_ssl. A minimal configuration: -

    - -Listen 443 -TLSEngine 443 -MDomain example.net - -<VirtualHost *:443> - ServerName example.net - ... -</VirtualHost> - -
    - -
    OCSP Stapling -

    - mod_tls has no own implementation to retrieve OCSP information for - a certificate. However, it will use such for Stapling if it is provided - by mod_md. See mod_md's documentation - on how to enable this. -

    -
    - -
    TLS Variables -

    - Via the directive TLSOptions, several variables - are placed into the environment of requests and can be inspected, for - example in a CGI script. -

    -

    - The variable names are given by mod_ssl. Note that these - are only a subset of the many variables that mod_ssl exposes. -

    - - - - - - - - - - - - - -
    VariableTLSOptionDescription
    SSL_TLS_SNI*the server name indicator (SNI) send by the client
    SSL_PROTOCOL*the TLS protocol negotiated
    SSL_CIPHER*the name of the TLS cipher negotiated
    SSL_VERSION_INTERFACEStdEnvVarsthe module version
    SSL_VERSION_LIBRARYStdEnvVarsthe rustls-ffi version
    SSL_SECURE_RENEGStdEnvVarsalways `false`
    SSL_COMPRESS_METHODStdEnvVarsalways `false`
    SSL_CIPHER_EXPORTStdEnvVarsalways `false`
    SSL_CLIENT_VERIFYStdEnvVarsalways `false`
    SSL_SESSION_RESUMEDStdEnvVarseither `Resumed` if a known TLS session id was presented by the client or `Initial` otherwise
    SSL_SERVER_CERTExportCertDatathe selected server certificate in PEM format
    -

    - The variable SSL_SESSION_ID is intentionally not supported as - it contains sensitive information. -

    -
    - -
    Client Certificates -

    - While rustls supports client certificates in principle, parts - of the infrastructure to make use of these in a server are not - offered. -

    -

    - Among these features are: revocation lists, inspection of certificate - extensions and the matched issuer chain for OCSP validation. Without these, - revocation of client certificates is not possible. Offering authentication - without revocation is not considered an option. -

    -

    - Work will continue on this and client certificate support may become - available in a future release. -

    -
    - - - TLSEngine - defines on which address+port the module shall handle incoming connections. - TLSEngine [address:]port - - server config - - -

    - This is set on a global level, not in individual VirtualHosts. - It will affect all VirtualHost - that match the specified address/port. - You can use TLSEngine several times to use more than one address/port. -

    -

    - Example - - TLSEngine 443 - - -

    - The example tells mod_tls to handle incoming connection on port 443 for - all listeners. -

    -
    -
    - - - TLSCertificate - adds a certificate and key (PEM encoded) to a server/virtual host. - TLSCertificate cert_file [key_file] - - server config - virtual host - - -

    - If you do not specify a separate key file, the key is assumed to also be - found in the first file. You may add more than one certificate to a - server/virtual host. The first certificate suitable for a client is then chosen. -

    - The path can be specified relative to the server root. -

    -
    -
    - - - TLSProtocol - specifies the minimum version of the TLS protocol to use. - TLSProtocol version+ - TLSProtocol v1.2+ - - server config - virtual host - - -

    - The default is `v1.2+`. Settings this to `v1.3+` would disable TLSv1.2. -

    -
    -
    - - - TLSCiphersPrefer - defines ciphers that are preferred. - TLSCiphersPrefer cipher(-list) - - server config - virtual host - - -

    - This will not disable any ciphers supported by `rustls`. If you - specify a cipher that is completely unknown, the configuration will - fail. If you specify a cipher that is known but not supported by `rustls`, - a warning will be logged but the server will continue. -

    -

    - Example - -TLSCiphersPrefer ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305 - - -

    - The example gives 2 ciphers preference over others, in the - order they are mentioned. -

    -
    -
    - - - TLSCiphersSuppress - defines ciphers that are not to be used. - TLSCiphersSuppress cipher(-list) - - server config - virtual host - - -

    - This will not disable any unmentioned ciphers supported by `rustls`. - If you specify a cipher that is completely unknown, the configuration will fail. - If you specify a cipher that is known but not supported by `rustls`, - a warning will be logged but the server will continue. -

    -

    - Example - -TLSCiphersSuppress ECDHE-ECDSA-CHACHA20-POLY1305 - - -

    - The example removes a cipher for use in connections. -

    -
    -
    - - - TLSHonorClientOrder - determines if the order of ciphers supported by the client is honored - TLSHonorClientOrder on|off - TLSHonorClientOrder on - - server config - virtual host - - -

    - TLSHonorClientOrder determines if the order of ciphers - supported by the client is honored. -

    -

    -
    -
    - - - TLSOptions - enables SSL variables for requests. - TLSOptions [+|-]option - - server config - virtual host - directory - .htaccess - - -

    - TLSOptions is analog to SSLOptions in mod_ssl. - It can be set per directory/location and `option` can be: -

    -
      -
    • `StdEnvVars`: adds more variables to the requests environment, - as forwarded for example to CGI processing and other applications. -
    • -
    • `ExportCertData`: adds certificate related variables to the request environment. -
    • -
    • `Defaults`: resets all options to their default values.
    • -
    -

    - Adding variables to a request environment adds overhead, especially - when certificates need to be inspected and fields extracted. - Therefore most variables are not set by default. -

    -

    - You can configure TLSOptions per location or generally on a - server/virtual host. Prefixing an option with `-` disables this - option while leaving others unchanged. - A `+` prefix is the same as writing the option without one. -

    -

    - The `Defaults` value can be used to reset any options that are - inherited from other locations or the virtual host/server. -

    - Example - -<Location /myplace/app> - TLSOptions Defaults StdEnvVars - ... -</Location> - - -
    -
    - - - TLSProxyEngine - enables TLS for backend connections. - TLSProxyEngine on|off - - server config - virtual host - proxy section - - -

    - TLSProxyEngine is analog to SSLProxyEngine in mod_ssl. -

    - This can be used in a server/virtual host or Proxy section to - enable the module for outgoing connections using mod_proxy. -

    -
    -
    - - - TLSProxyCA - sets the root certificates to validate the backend server with. - TLSProxyCA file.pem - - server config - virtual host - proxy section - - -

    - -

    -
    -
    - - - TLSProxyProtocol - specifies the minimum version of the TLS protocol to use in proxy connections. - TLSProxyProtocol version+ - TLSProxyProtocol v1.2+ - - server config - virtual host - proxy section - - -

    - The default is `v1.2+`. Settings this to `v1.3+` would disable TLSv1.2. -

    -
    -
    - - - TLSProxyCiphersPrefer - defines ciphers that are preferred for a proxy connection. - TLSProxyCiphersPrefer cipher(-list) - - server config - virtual host - proxy section - - -

    - This will not disable any ciphers supported by `rustls`. - If you specify a cipher that is completely unknown, the configuration will fail. - If you specify a cipher that is known but not supported by `rustls`, - a warning will be logged but the server will continue. -

    -
    -
    - - - TLSProxyCiphersSuppress - defines ciphers that are not to be used for a proxy connection. - TLSProxyCiphersSuppress cipher(-list) - - server config - virtual host - proxy section - - -

    - This will not disable any unmentioned ciphers supported by `rustls`. - If you specify a cipher that is completely unknown, the configuration will fail. - If you specify a cipher that is known but not supported by `rustls`, - a warning will be logged but the server will continue. -

    -
    -
    - - - TLSProxyMachineCertificate - adds a certificate and key file (PEM encoded) to a proxy setup. - TLSProxyMachineCertificate cert_file [key_file] - - server config - virtual host - proxy section - - -

    - The certificate is used to authenticate against a proxied backend server. -

    - If you do not specify a separate key file, the key is assumed to also be - found in the first file. You may add more than one certificate to a proxy - setup. The first certificate suitable for a proxy connection to a backend - is then chosen by rustls. -

    -

    - The path can be specified relative to the server root. -

    -
    -
    - - - TLSStrictSNI - enforces exact matches of client server indicators (SNI) against host names. - TLSStrictSNI on|off - TLSStrictSNI on - - server config - - -

    - Client connections using SNI will be unsuccessful if no match is found. -

    -
    -
    - - - TLSSessionCache - specifies the cache for TLS session resumption. - TLSSessionCache cache-spec - - server config - - -

    - This uses a cache on the server side to allow clients to resume connections. -

    - You can set this to `none` or define a cache as in the SSLSessionCache - directive of mod_ssl. -

    - If not configured, `mod_tls` will try to create a shared memory cache on its own, - using `shmcb:tls/session-cache` as specification. - Should that fail, a warning is logged, but the server continues. -

    -
    -
    - - diff --git a/modules/tls/Makefile.in b/modules/tls/Makefile.in deleted file mode 100644 index 4395bc3ac7..0000000000 --- a/modules/tls/Makefile.in +++ /dev/null @@ -1,20 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one or more -# contributor license agreements. See the NOTICE file distributed with -# this work for additional information regarding copyright ownership. -# The ASF licenses this file to You under the Apache License, Version 2.0 -# (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# -# standard stuff -# - -include $(top_srcdir)/build/special.mk diff --git a/modules/tls/config2.m4 b/modules/tls/config2.m4 deleted file mode 100644 index 8a32490cb6..0000000000 --- a/modules/tls/config2.m4 +++ /dev/null @@ -1,173 +0,0 @@ -dnl Licensed to the Apache Software Foundation (ASF) under one or more -dnl contributor license agreements. See the NOTICE file distributed with -dnl this work for additional information regarding copyright ownership. -dnl The ASF licenses this file to You under the Apache License, Version 2.0 -dnl (the "License"); you may not use this file except in compliance with -dnl the License. You may obtain a copy of the License at -dnl -dnl http://www.apache.org/licenses/LICENSE-2.0 -dnl -dnl Unless required by applicable law or agreed to in writing, software -dnl distributed under the License is distributed on an "AS IS" BASIS, -dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -dnl See the License for the specific language governing permissions and -dnl limitations under the License. - -dnl # start of module specific part -APACHE_MODPATH_INIT(tls) - -dnl # list of module object files -tls_objs="dnl -mod_tls.lo dnl -tls_cache.lo dnl -tls_cert.lo dnl -tls_conf.lo dnl -tls_core.lo dnl -tls_filter.lo dnl -tls_ocsp.lo dnl -tls_proto.lo dnl -tls_util.lo dnl -tls_var.lo dnl -" - -dnl -dnl APACHE_CHECK_TLS -dnl -dnl Configure for rustls, giving preference to -dnl "--with-rustls=" if it was specified. -dnl -AC_DEFUN([APACHE_CHECK_RUSTLS],[ - AC_CACHE_CHECK([for rustls], [ac_cv_rustls], [ - dnl initialise the variables we use - ac_cv_rustls=no - ap_rustls_found="" - ap_rustls_base="" - ap_rustls_libs="" - - dnl Determine the rustls base directory, if any - AC_MSG_CHECKING([for user-provided rustls base directory]) - AC_ARG_WITH(rustls, APACHE_HELP_STRING(--with-rustls=PATH, rustls installation directory), [ - dnl If --with-rustls specifies a directory, we use that directory - if test "x$withval" != "xyes" -a "x$withval" != "x"; then - dnl This ensures $withval is actually a directory and that it is absolute - ap_rustls_base="`cd $withval ; pwd`" - fi - ]) - if test "x$ap_rustls_base" = "x"; then - AC_MSG_RESULT(none) - else - AC_MSG_RESULT($ap_rustls_base) - fi - - dnl Run header and version checks - saved_CPPFLAGS="$CPPFLAGS" - saved_LIBS="$LIBS" - saved_LDFLAGS="$LDFLAGS" - - dnl Before doing anything else, load in pkg-config variables - if test -n "$PKGCONFIG"; then - saved_PKG_CONFIG_PATH="$PKG_CONFIG_PATH" - AC_MSG_CHECKING([for pkg-config along $PKG_CONFIG_PATH]) - if test "x$ap_rustls_base" != "x" ; then - if test -f "${ap_rustls_base}/lib/pkgconfig/librustls.pc"; then - dnl Ensure that the given path is used by pkg-config too, otherwise - dnl the system librustls.pc might be picked up instead. - PKG_CONFIG_PATH="${ap_rustls_base}/lib/pkgconfig${PKG_CONFIG_PATH+:}${PKG_CONFIG_PATH}" - export PKG_CONFIG_PATH - elif test -f "${ap_rustls_base}/lib64/pkgconfig/librustls.pc"; then - dnl Ensure that the given path is used by pkg-config too, otherwise - dnl the system librustls.pc might be picked up instead. - PKG_CONFIG_PATH="${ap_rustls_base}/lib64/pkgconfig${PKG_CONFIG_PATH+:}${PKG_CONFIG_PATH}" - export PKG_CONFIG_PATH - fi - fi - ap_rustls_libs="`$PKGCONFIG $PKGCONFIG_LIBOPTS --libs-only-l --silence-errors librustls`" - if test $? -eq 0; then - ap_rustls_found="yes" - pkglookup="`$PKGCONFIG --cflags-only-I librustls`" - APR_ADDTO(CPPFLAGS, [$pkglookup]) - APR_ADDTO(MOD_CFLAGS, [$pkglookup]) - pkglookup="`$PKGCONFIG $PKGCONFIG_LIBOPTS --libs-only-L librustls`" - APR_ADDTO(LDFLAGS, [$pkglookup]) - APR_ADDTO(MOD_LDFLAGS, [$pkglookup]) - pkglookup="`$PKGCONFIG $PKGCONFIG_LIBOPTS --libs-only-other librustls`" - APR_ADDTO(LDFLAGS, [$pkglookup]) - APR_ADDTO(MOD_LDFLAGS, [$pkglookup]) - fi - PKG_CONFIG_PATH="$saved_PKG_CONFIG_PATH" - fi - - dnl fall back to the user-supplied directory if not found via pkg-config - if test "x$ap_rustls_base" != "x" -a "x$ap_rustls_found" = "x"; then - APR_ADDTO(CPPFLAGS, [-I$ap_rustls_base/include]) - APR_ADDTO(MOD_CFLAGS, [-I$ap_rustls_base/include]) - APR_ADDTO(LDFLAGS, [-L$ap_rustls_base/lib]) - APR_ADDTO(MOD_LDFLAGS, [-L$ap_rustls_base/lib]) - if test "x$ap_platform_runtime_link_flag" != "x"; then - APR_ADDTO(LDFLAGS, [$ap_platform_runtime_link_flag$ap_rustls_base/lib]) - APR_ADDTO(MOD_LDFLAGS, [$ap_platform_runtime_link_flag$ap_rustls_base/lib]) - fi - fi - - AC_MSG_CHECKING([for rustls version >= 0.9.2]) - AC_TRY_COMPILE([#include ],[ -rustls_version(); -rustls_acceptor_new(); -], - [AC_MSG_RESULT(OK) - ac_cv_rustls=yes], - [AC_MSG_RESULT(FAILED)]) - - dnl restore - CPPFLAGS="$saved_CPPFLAGS" - LIBS="$saved_LIBS" - LDFLAGS="$saved_LDFLAGS" - ]) - if test "x$ac_cv_rustls" = "xyes"; then - AC_DEFINE(HAVE_RUSTLS, 1, [Define if rustls is available]) - fi -]) - - -dnl # hook module into the Autoconf mechanism (--enable-http2) -APACHE_MODULE(tls, [TLS protocol handling using rustls. Implemented by mod_tls. -This module requires a librustls installation. -See --with-rustls on how to manage non-standard locations. This module -is usually linked shared and requires loading. ], $tls_objs, , most, [ - APACHE_CHECK_RUSTLS - if test "$ac_cv_rustls" = "yes" ; then - if test "x$enable_tls" = "xshared"; then - case `uname` in - "Darwin") - MOD_TLS_LINK_LIBS="-lrustls -framework Security -framework Foundation" - ;; - *) - MOD_TLS_LINK_LIBS="-lrustls" - ;; - esac - - # Some rustls versions need an extra -lm when linked - # See https://github.com/rustls/rustls-ffi/issues/133 - rustls_version=`rustc --version` - case "$rustls_version" in - *1.55*) need_lm="yes" ;; - *1.56*) need_lm="yes" ;; - *1.57*) need_lm="yes" ;; - esac - if test "$need_lm" = "yes" ; then - MOD_TLS_LINK_LIBS="$MOD_TLS_LINK_LIBS -lm" - fi - - # The only symbol which needs to be exported is the module - # structure, so ask libtool to hide everything else: - APR_ADDTO(MOD_TLS_LDADD, [$MOD_TLS_LINK_LIBS -export-symbols-regex tls_module]) - fi - else - enable_tls=no - fi -]) - - -dnl # end of module specific part -APACHE_MODPATH_FINISH - diff --git a/modules/tls/mod_tls.c b/modules/tls/mod_tls.c deleted file mode 100644 index 9d795210a3..0000000000 --- a/modules/tls/mod_tls.c +++ /dev/null @@ -1,288 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "mod_tls.h" -#include "tls_conf.h" -#include "tls_core.h" -#include "tls_cache.h" -#include "tls_proto.h" -#include "tls_filter.h" -#include "tls_var.h" -#include "tls_version.h" - -#include "mod_proxy.h" - -static void tls_hooks(apr_pool_t *pool); - -AP_DECLARE_MODULE(tls) = { - STANDARD20_MODULE_STUFF, - tls_conf_create_dir, /* create per dir config */ - tls_conf_merge_dir, /* merge per dir config */ - tls_conf_create_svr, /* create per server config */ - tls_conf_merge_svr, /* merge per server config (inheritance) */ - tls_conf_cmds, /* command handlers */ - tls_hooks, -#if defined(AP_MODULE_FLAG_NONE) - AP_MODULE_FLAG_ALWAYS_MERGE -#endif -}; - -static const char* crustls_version(apr_pool_t *p) -{ - struct rustls_str rversion; - - rversion = rustls_version(); - return apr_pstrndup(p, rversion.data, rversion.len); -} - -static int tls_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp) -{ - tls_proto_pre_config(pconf, ptemp); - tls_cache_pre_config(pconf, plog, ptemp); - return OK; -} - -static apr_status_t tls_post_config(apr_pool_t *p, apr_pool_t *plog, - apr_pool_t *ptemp, server_rec *s) -{ - const char *tls_init_key = "mod_tls_init_counter"; - tls_conf_server_t *sc; - void *data = NULL; - - (void)plog; - sc = tls_conf_server_get(s); - assert(sc); - assert(sc->global); - sc->global->module_version = "mod_tls/" MOD_TLS_VERSION; - sc->global->crustls_version = crustls_version(p); - - apr_pool_userdata_get(&data, tls_init_key, s->process->pool); - if (data == NULL) { - /* At the first start, httpd makes a config check dry run - * to see if the config is ok in principle. - */ - ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s, "post config dry run"); - apr_pool_userdata_set((const void *)1, tls_init_key, - apr_pool_cleanup_null, s->process->pool); - } - else { - ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(10365) - "%s (%s), initializing...", - sc->global->module_version, - sc->global->crustls_version); - } - - return tls_core_init(p, ptemp, s); -} - -static apr_status_t tls_post_proxy_config( - apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) -{ - tls_conf_server_t *sc = tls_conf_server_get(s); - (void)plog; - sc->global->mod_proxy_post_config_done = 1; - return tls_core_init(p, ptemp, s); -} - -#if AP_MODULE_MAGIC_AT_LEAST(20120211, 109) -static int tls_ssl_outgoing(conn_rec *c, ap_conf_vector_t *dir_conf, int enable_ssl) -{ - /* we are not handling proxy connections - for now */ - tls_core_conn_bind(c, dir_conf); - if (enable_ssl && tls_core_setup_outgoing(c) == OK) { - ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, c->base_server, - "accepted ssl_bind_outgoing(enable=%d) for %s", - enable_ssl, c->base_server->server_hostname); - return OK; - } - tls_core_conn_disable(c); - ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, c->base_server, - "declined ssl_bind_outgoing(enable=%d) for %s", - enable_ssl, c->base_server->server_hostname); - return DECLINED; -} - -#else /* #if AP_MODULE_MAGIC_AT_LEAST(20120211, 109) */ - -APR_DECLARE_OPTIONAL_FN(int, ssl_proxy_enable, (conn_rec *)); -APR_DECLARE_OPTIONAL_FN(int, ssl_engine_disable, (conn_rec *)); -APR_DECLARE_OPTIONAL_FN(int, ssl_engine_set, (conn_rec *, - ap_conf_vector_t *, - int proxy, int enable)); -static APR_OPTIONAL_FN_TYPE(ssl_engine_set) *module_ssl_engine_set; - -static int ssl_engine_set( - conn_rec *c, ap_conf_vector_t *dir_conf, int proxy, int enable) -{ - ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, c->base_server, - "ssl_engine_set(proxy=%d, enable=%d) for %s", - proxy, enable, c->base_server->server_hostname); - tls_core_conn_bind(c, dir_conf); - if (enable && tls_core_setup_outgoing(c) == OK) { - if (module_ssl_engine_set) { - module_ssl_engine_set(c, dir_conf, proxy, 0); - } - return 1; - } - if (proxy || !enable) { - /* we are not handling proxy connections - for now */ - tls_core_conn_disable(c); - } - if (module_ssl_engine_set) { - return module_ssl_engine_set(c, dir_conf, proxy, enable); - } - return 0; -} - -static int ssl_proxy_enable(conn_rec *c) -{ - return ssl_engine_set(c, NULL, 1, 1); -} - -static int ssl_engine_disable(conn_rec *c) -{ - return ssl_engine_set(c, NULL, 0, 0); -} - -static apr_status_t tls_post_config_proxy_ssl( - apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) -{ - if (1) { - const char *tls_init_key = "mod_tls_proxy_ssl_counter"; - void *data = NULL; - APR_OPTIONAL_FN_TYPE(ssl_engine_set) *fn_ssl_engine_set; - - (void)p; - (void)plog; - (void)ptemp; - apr_pool_userdata_get(&data, tls_init_key, s->process->pool); - if (data == NULL) { - /* At the first start, httpd makes a config check dry run - * to see if the config is ok in principle. - */ - apr_pool_userdata_set((const void *)1, tls_init_key, - apr_pool_cleanup_null, s->process->pool); - return APR_SUCCESS; - } - - /* mod_ssl (if so loaded, has registered its optional functions. - * When mod_proxy runs in post-config, it looks up those functions and uses - * them to manipulate SSL status for backend connections. - * We provide our own implementations to avoid becoming active on such - * connections for now. - * */ - fn_ssl_engine_set = APR_RETRIEVE_OPTIONAL_FN(ssl_engine_set); - module_ssl_engine_set = (fn_ssl_engine_set - && fn_ssl_engine_set != ssl_engine_set)? fn_ssl_engine_set : NULL; - APR_REGISTER_OPTIONAL_FN(ssl_engine_set); - APR_REGISTER_OPTIONAL_FN(ssl_proxy_enable); - APR_REGISTER_OPTIONAL_FN(ssl_engine_disable); - } - return APR_SUCCESS; -} -#endif /* #if AP_MODULE_MAGIC_AT_LEAST(20120211, 109) */ - -static void tls_init_child(apr_pool_t *p, server_rec *s) -{ - tls_cache_init_child(p, s); -} - -static int hook_pre_connection(conn_rec *c, void *csd) -{ - (void)csd; /* mpm specific socket data, not used */ - - /* are we on a primary connection? */ - if (c->master) return DECLINED; - - /* Decide connection TLS stats and install our - * input/output filters for handling TLS/application data - * if enabled. - */ - return tls_filter_pre_conn_init(c); -} - -static int hook_connection(conn_rec* c) -{ - tls_filter_conn_init(c); - /* we do *not* take over. we are not processing requests. */ - return DECLINED; -} - -static const char *tls_hook_http_scheme(const request_rec *r) -{ - return (tls_conn_check_ssl(r->connection) == OK)? "https" : NULL; -} - -static apr_port_t tls_hook_default_port(const request_rec *r) -{ - return (tls_conn_check_ssl(r->connection) == OK) ? 443 : 0; -} - -static const char* const mod_http2[] = { "mod_http2.c", NULL}; - -static void tls_hooks(apr_pool_t *pool) -{ - /* If our request check denies further processing, certain things - * need to be in place for the response to be correctly generated. */ - static const char *dep_req_check[] = { "mod_setenvif.c", NULL }; - static const char *dep_proxy[] = { "mod_proxy.c", NULL }; - - ap_log_perror(APLOG_MARK, APLOG_TRACE1, 0, pool, "installing hooks"); - tls_filter_register(pool); - - ap_hook_pre_config(tls_pre_config, NULL,NULL, APR_HOOK_MIDDLE); - /* run post-config hooks one before, one after mod_proxy, as the - * mod_proxy's own one calls us in its "section_post_config" hook. */ - ap_hook_post_config(tls_post_config, NULL, dep_proxy, APR_HOOK_MIDDLE); - APR_OPTIONAL_HOOK(proxy, section_post_config, - tls_proxy_section_post_config, NULL, NULL, - APR_HOOK_MIDDLE); - ap_hook_post_config(tls_post_proxy_config, dep_proxy, NULL, APR_HOOK_MIDDLE); - ap_hook_child_init(tls_init_child, NULL,NULL, APR_HOOK_MIDDLE); - /* connection things */ - ap_hook_pre_connection(hook_pre_connection, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_process_connection(hook_connection, NULL, mod_http2, APR_HOOK_MIDDLE); - /* request things */ - ap_hook_default_port(tls_hook_default_port, NULL,NULL, APR_HOOK_MIDDLE); - ap_hook_http_scheme(tls_hook_http_scheme, NULL,NULL, APR_HOOK_MIDDLE); - ap_hook_post_read_request(tls_core_request_check, dep_req_check, NULL, APR_HOOK_MIDDLE); - ap_hook_fixups(tls_var_request_fixup, NULL,NULL, APR_HOOK_MIDDLE); - - ap_hook_ssl_conn_is_ssl(tls_conn_check_ssl, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_ssl_var_lookup(tls_var_lookup, NULL, NULL, APR_HOOK_MIDDLE); - -#if AP_MODULE_MAGIC_AT_LEAST(20120211, 109) - ap_hook_ssl_bind_outgoing(tls_ssl_outgoing, NULL, NULL, APR_HOOK_MIDDLE); -#else - ap_hook_post_config(tls_post_config_proxy_ssl, NULL, dep_proxy, APR_HOOK_MIDDLE); -#endif - -} diff --git a/modules/tls/mod_tls.h b/modules/tls/mod_tls.h deleted file mode 100644 index db7dc418c6..0000000000 --- a/modules/tls/mod_tls.h +++ /dev/null @@ -1,19 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef mod_tls_h -#define mod_tls_h - -#endif /* mod_tls_h */ \ No newline at end of file diff --git a/modules/tls/tls_cache.c b/modules/tls/tls_cache.c deleted file mode 100644 index de4be18810..0000000000 --- a/modules/tls/tls_cache.c +++ /dev/null @@ -1,310 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include "tls_conf.h" -#include "tls_core.h" -#include "tls_cache.h" - -extern module AP_MODULE_DECLARE_DATA tls_module; -APLOG_USE_MODULE(tls); - -#define TLS_CACHE_DEF_PROVIDER "shmcb" -#define TLS_CACHE_DEF_DIR "tls" -#define TLS_CACHE_DEF_FILE "session_cache" -#define TLS_CACHE_DEF_SIZE 512000 - -static const char *cache_provider_unknown(const char *name, apr_pool_t *p) -{ - apr_array_header_t *known; - const char *known_names; - - known = ap_list_provider_names(p, AP_SOCACHE_PROVIDER_GROUP, - AP_SOCACHE_PROVIDER_VERSION); - known_names = apr_array_pstrcat(p, known, ','); - return apr_psprintf(p, "cache type '%s' not supported " - "(known names: %s). Maybe you need to load the " - "appropriate socache module (mod_socache_%s?).", - name, known_names, name); -} - -void tls_cache_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp) -{ - (void)plog; - (void)ptemp; - /* we make this visible, in case someone wants to configure it. - * this does not mean that we will really use it, which is determined - * by configuration and cache provider capabilities. */ - ap_mutex_register(pconf, TLS_SESSION_CACHE_MUTEX_TYPE, NULL, APR_LOCK_DEFAULT, 0); -} - -static const char *cache_init(tls_conf_global_t *gconf, apr_pool_t *p, apr_pool_t *ptemp) -{ - const char *err = NULL; - const char *name, *args = NULL; - apr_status_t rv; - - if (gconf->session_cache) { - goto cleanup; - } - else if (!apr_strnatcasecmp("none", gconf->session_cache_spec)) { - gconf->session_cache_provider = NULL; - gconf->session_cache = NULL; - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, gconf->ap_server, APLOGNO(10346) - "session cache explicitly disabled"); - goto cleanup; - } - else if (!apr_strnatcasecmp("default", gconf->session_cache_spec)) { - const char *path = TLS_CACHE_DEF_DIR; - -#if AP_MODULE_MAGIC_AT_LEAST(20180906, 2) - path = ap_state_dir_relative(p, path); -#endif - gconf->session_cache_spec = apr_psprintf(p, "%s:%s/%s(%ld)", - TLS_CACHE_DEF_PROVIDER, path, TLS_CACHE_DEF_FILE, (long)TLS_CACHE_DEF_SIZE); - gconf->session_cache_spec = "shmcb:mod_tls-sesss(64000)"; - } - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, gconf->ap_server, APLOGNO(10347) - "Using session cache: %s", gconf->session_cache_spec); - name = gconf->session_cache_spec; - args = ap_strchr((char*)name, ':'); - if (args) { - name = apr_pstrmemdup(p, name, (apr_size_t)(args - name)); - ++args; - } - gconf->session_cache_provider = ap_lookup_provider(AP_SOCACHE_PROVIDER_GROUP, - name, AP_SOCACHE_PROVIDER_VERSION); - if (!gconf->session_cache_provider) { - err = cache_provider_unknown(name, p); - goto cleanup; - } - err = gconf->session_cache_provider->create(&gconf->session_cache, args, ptemp, p); - if (err != NULL) goto cleanup; - - if (gconf->session_cache_provider->flags & AP_SOCACHE_FLAG_NOTMPSAFE - && !gconf->session_cache_mutex) { - /* we need a global lock to access the cache */ - rv = ap_global_mutex_create(&gconf->session_cache_mutex, NULL, - TLS_SESSION_CACHE_MUTEX_TYPE, NULL, gconf->ap_server, p, 0); - if (APR_SUCCESS != rv) { - err = apr_psprintf(p, "error setting up global %s mutex: %d", - TLS_SESSION_CACHE_MUTEX_TYPE, rv); - gconf->session_cache_mutex = NULL; - goto cleanup; - } - } - -cleanup: - if (NULL != err) { - gconf->session_cache_provider = NULL; - gconf->session_cache = NULL; - } - return err; -} - -const char *tls_cache_set_specification( - const char *spec, tls_conf_global_t *gconf, apr_pool_t *p, apr_pool_t *ptemp) -{ - gconf->session_cache_spec = spec; - return cache_init(gconf, p, ptemp); -} - -apr_status_t tls_cache_post_config(apr_pool_t *p, apr_pool_t *ptemp, server_rec *s) -{ - tls_conf_server_t *sc = tls_conf_server_get(s); - const char *err; - apr_status_t rv = APR_SUCCESS; - - err = cache_init(sc->global, p, ptemp); - if (err) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(10348) - "session cache [%s] could not be initialized, will continue " - "without session one. Since this will impact performance, " - "consider making use of the 'TLSSessionCache' directive. The " - "error was: %s", sc->global->session_cache_spec, err); - } - - if (sc->global->session_cache) { - struct ap_socache_hints hints; - - ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s, "provider init session cache [%s]", - sc->global->session_cache_spec); - memset(&hints, 0, sizeof(hints)); - hints.avg_obj_size = 100; - hints.avg_id_len = 33; - hints.expiry_interval = 30; - - rv = sc->global->session_cache_provider->init( - sc->global->session_cache, "mod_tls-sess", &hints, s, p); - if (APR_SUCCESS != rv) { - ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10349) - "error initializing session cache."); - } - } - return rv; -} - -void tls_cache_init_child(apr_pool_t *p, server_rec *s) -{ - tls_conf_server_t *sc = tls_conf_server_get(s); - const char *lockfile; - apr_status_t rv; - - if (sc->global->session_cache_mutex) { - lockfile = apr_global_mutex_lockfile(sc->global->session_cache_mutex); - rv = apr_global_mutex_child_init(&sc->global->session_cache_mutex, lockfile, p); - if (APR_SUCCESS != rv) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(10350) - "Cannot reinit %s mutex (file `%s`)", - TLS_SESSION_CACHE_MUTEX_TYPE, lockfile? lockfile : "-"); - } - } -} - -void tls_cache_free(server_rec *s) -{ - tls_conf_server_t *sc = tls_conf_server_get(s); - if (sc->global->session_cache_provider) { - sc->global->session_cache_provider->destroy(sc->global->session_cache, s); - } -} - -static void tls_cache_lock(tls_conf_global_t *gconf) -{ - if (gconf->session_cache_mutex) { - apr_status_t rv = apr_global_mutex_lock(gconf->session_cache_mutex); - if (APR_SUCCESS != rv) { - ap_log_error(APLOG_MARK, APLOG_WARNING, rv, gconf->ap_server, APLOGNO(10351) - "Failed to acquire TLS session cache lock"); - } - } -} - -static void tls_cache_unlock(tls_conf_global_t *gconf) -{ - if (gconf->session_cache_mutex) { - apr_status_t rv = apr_global_mutex_unlock(gconf->session_cache_mutex); - if (APR_SUCCESS != rv) { - ap_log_error(APLOG_MARK, APLOG_WARNING, rv, gconf->ap_server, APLOGNO(10352) - "Failed to release TLS session cache lock"); - } - } -} - -static rustls_result tls_cache_get( - void *userdata, - const rustls_slice_bytes *key, - int remove_after, - unsigned char *buf, - size_t count, - size_t *out_n) -{ - conn_rec *c = userdata; - tls_conf_conn_t *cc = tls_conf_conn_get(c); - tls_conf_server_t *sc = tls_conf_server_get(cc->server); - apr_status_t rv = APR_ENOENT; - unsigned int vlen, klen; - const unsigned char *kdata; - - if (!sc->global->session_cache) goto not_found; - tls_cache_lock(sc->global); - - kdata = key->data; - klen = (unsigned int)key->len; - vlen = (unsigned int)count; - rv = sc->global->session_cache_provider->retrieve( - sc->global->session_cache, cc->server, kdata, klen, buf, &vlen, c->pool); - - if (APLOGctrace4(c)) { - apr_ssize_t n = klen; - ap_log_cerror(APLOG_MARK, APLOG_TRACE4, rv, c, "retrieve key %d[%8x], found %d val", - klen, apr_hashfunc_default((const char*)kdata, &n), vlen); - } - if (remove_after || (APR_SUCCESS != rv && !APR_STATUS_IS_NOTFOUND(rv))) { - sc->global->session_cache_provider->remove( - sc->global->session_cache, cc->server, key->data, klen, c->pool); - } - - tls_cache_unlock(sc->global); - if (APR_SUCCESS != rv) goto not_found; - cc->session_id_cache_hit = 1; - *out_n = count; - return RUSTLS_RESULT_OK; - -not_found: - *out_n = 0; - return RUSTLS_RESULT_NOT_FOUND; -} - -static rustls_result tls_cache_put( - void *userdata, - const rustls_slice_bytes *key, - const rustls_slice_bytes *val) -{ - conn_rec *c = userdata; - tls_conf_conn_t *cc = tls_conf_conn_get(c); - tls_conf_server_t *sc = tls_conf_server_get(cc->server); - apr_status_t rv = APR_ENOENT; - apr_time_t expires_at; - unsigned int klen, vlen; - const unsigned char *kdata; - - if (!sc->global->session_cache) goto not_stored; - tls_cache_lock(sc->global); - - expires_at = apr_time_now() + apr_time_from_sec(300); - kdata = key->data; - klen = (unsigned int)key->len; - vlen = (unsigned int)val->len; - rv = sc->global->session_cache_provider->store(sc->global->session_cache, cc->server, - kdata, klen, expires_at, - (unsigned char*)val->data, vlen, c->pool); - if (APLOGctrace4(c)) { - ap_log_cerror(APLOG_MARK, APLOG_TRACE4, rv, c, - "stored %d key bytes, with %d val bytes", klen, vlen); - } - tls_cache_unlock(sc->global); - if (APR_SUCCESS != rv) goto not_stored; - return RUSTLS_RESULT_OK; - -not_stored: - return RUSTLS_RESULT_NOT_FOUND; -} - -apr_status_t tls_cache_init_server( - rustls_server_config_builder *builder, server_rec *s) -{ - tls_conf_server_t *sc = tls_conf_server_get(s); - - if (sc && sc->global->session_cache) { - ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, s, "adding session persistence to rustls"); - rustls_server_config_builder_set_persistence( - builder, tls_cache_get, tls_cache_put); - } - return APR_SUCCESS; -} diff --git a/modules/tls/tls_cache.h b/modules/tls/tls_cache.h deleted file mode 100644 index 64ca0778ca..0000000000 --- a/modules/tls/tls_cache.h +++ /dev/null @@ -1,63 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef tls_cache_h -#define tls_cache_h - -/* name of the global session cache mutex, should we need it */ -#define TLS_SESSION_CACHE_MUTEX_TYPE "tls-session-cache" - - -/** - * Set the specification of the session cache to use. The syntax is - * "default|none|(:)?" - * - * @param spec the cache specification - * @param gconf the modules global configuration - * @param p pool for permanent allocations - * @param ptemp pool for temporary allocations - * @return NULL on success or an error message - */ -const char *tls_cache_set_specification( - const char *spec, tls_conf_global_t *gconf, apr_pool_t *p, apr_pool_t *ptemp); - -/** - * Setup before configuration runs, announces our potential global mutex. - */ -void tls_cache_pre_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp); - -/** - * Verify the cache settings at the end of the configuration and - * create the default session cache, if not already done. - */ -apr_status_t tls_cache_post_config(apr_pool_t *p, apr_pool_t *ptemp, server_rec *s); - -/** - * Started a new child, make sure that global mutex we might use is set up. - */ -void tls_cache_init_child(apr_pool_t *p, server_rec *s); - -/** - * Free all cache related resources. - */ -void tls_cache_free(server_rec *s); - -/** - * Initialize the session store for the server's config builder. - */ -apr_status_t tls_cache_init_server( - rustls_server_config_builder *builder, server_rec *s); - -#endif /* tls_cache_h */ \ No newline at end of file diff --git a/modules/tls/tls_cert.c b/modules/tls/tls_cert.c deleted file mode 100644 index ffb941cae4..0000000000 --- a/modules/tls/tls_cert.c +++ /dev/null @@ -1,583 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include "tls_cert.h" -#include "tls_util.h" - -extern module AP_MODULE_DECLARE_DATA tls_module; -APLOG_USE_MODULE(tls); - - -apr_status_t tls_cert_load_pem( - apr_pool_t *p, const tls_cert_spec_t *cert, tls_cert_pem_t **ppem) -{ - apr_status_t rv; - const char *fpath; - tls_cert_pem_t *cpem; - - ap_assert(cert->cert_file); - cpem = apr_pcalloc(p, sizeof(*cpem)); - fpath = ap_server_root_relative(p, cert->cert_file); - if (NULL == fpath) { - rv = APR_ENOENT; goto cleanup; - } - rv = tls_util_file_load(p, fpath, 0, 100*1024, &cpem->cert_pem); - if (APR_SUCCESS != rv) goto cleanup; - - if (cert->pkey_file) { - fpath = ap_server_root_relative(p, cert->pkey_file); - if (NULL == fpath) { - rv = APR_ENOENT; goto cleanup; - } - rv = tls_util_file_load(p, fpath, 0, 100*1024, &cpem->pkey_pem); - if (APR_SUCCESS != rv) goto cleanup; - } - else { - cpem->pkey_pem = cpem->cert_pem; - } -cleanup: - *ppem = (APR_SUCCESS == rv)? cpem : NULL; - return rv; -} - -#define PEM_IN_CHUNK 48 /* PEM demands at most 64 chars per line */ - -static apr_status_t tls_der_to_pem( - const char **ppem, apr_pool_t *p, - const unsigned char *der_data, apr_size_t der_len, - const char *header, const char *footer) -{ - apr_status_t rv = APR_SUCCESS; - char *pem = NULL, *s; - apr_size_t b64_len, n, hd_len, ft_len; - apr_ssize_t in_len, i; - - if (der_len > INT_MAX) { - rv = APR_ENOMEM; - goto cleanup; - } - in_len = (apr_ssize_t)der_len; - rv = apr_encode_base64(NULL, (const char*)der_data, in_len, APR_ENCODE_NONE, &b64_len); - if (APR_SUCCESS != rv) goto cleanup; - if (b64_len > INT_MAX) { - rv = APR_ENOMEM; - goto cleanup; - } - hd_len = header? strlen(header) : 0; - ft_len = footer? strlen(footer) : 0; - s = pem = apr_pcalloc(p, - + b64_len + (der_len/PEM_IN_CHUNK) + 1 /* \n per chunk */ - + hd_len +1 + ft_len + 1 /* adding \n */ - + 1); /* NUL-terminated */ - if (header) { - strcpy(s, header); - s += hd_len; - *s++ = '\n'; - } - for (i = 0; in_len > 0; i += PEM_IN_CHUNK, in_len -= PEM_IN_CHUNK) { - rv = apr_encode_base64(s, - (const char*)der_data + i, in_len > PEM_IN_CHUNK? PEM_IN_CHUNK : in_len, - APR_ENCODE_NONE, &n); - s += n; - *s++ = '\n'; - } - if (footer) { - strcpy(s, footer); - s += ft_len; - *s++ = '\n'; - } -cleanup: - *ppem = (APR_SUCCESS == rv)? pem : NULL; - return rv; -} - -#define PEM_CERT_HD "-----BEGIN CERTIFICATE-----" -#define PEM_CERT_FT "-----END CERTIFICATE-----" - -apr_status_t tls_cert_to_pem(const char **ppem, apr_pool_t *p, const rustls_certificate *cert) -{ - const unsigned char* der_data; - size_t der_len; - rustls_result rr = RUSTLS_RESULT_OK; - apr_status_t rv = APR_SUCCESS; - const char *pem = NULL; - - rr = rustls_certificate_get_der(cert, &der_data, &der_len); - if (RUSTLS_RESULT_OK != rr) goto cleanup; - rv = tls_der_to_pem(&pem, p, der_data, der_len, PEM_CERT_HD, PEM_CERT_FT); -cleanup: - if (RUSTLS_RESULT_OK != rr) { - rv = tls_util_rustls_error(p, rr, NULL); - } - *ppem = (APR_SUCCESS == rv)? pem : NULL; - return rv; -} - -static void nullify_key_pem(tls_cert_pem_t *pems) -{ - if (pems->pkey_pem.len) { - memset((void*)pems->pkey_pem.data, 0, pems->pkey_pem.len); - } -} - -static apr_status_t make_certified_key( - apr_pool_t *p, const char *name, - const tls_data_t *cert_pem, const tls_data_t *pkey_pem, - const rustls_certified_key **pckey) -{ - const rustls_certified_key *ckey = NULL; - rustls_result rr = RUSTLS_RESULT_OK; - apr_status_t rv = APR_SUCCESS; - - rr = rustls_certified_key_build( - cert_pem->data, cert_pem->len, - pkey_pem->data, pkey_pem->len, - &ckey); - - if (RUSTLS_RESULT_OK != rr) { - const char *err_descr; - rv = tls_util_rustls_error(p, rr, &err_descr); - ap_log_perror(APLOG_MARK, APLOG_ERR, rv, p, APLOGNO(10363) - "Failed to load certified key %s: [%d] %s", - name, (int)rr, err_descr); - } - if (APR_SUCCESS == rv) { - *pckey = ckey; - } - else if (ckey) { - rustls_certified_key_free(ckey); - } - return rv; -} - -apr_status_t tls_cert_load_cert_key( - apr_pool_t *p, const tls_cert_spec_t *spec, - const char **pcert_pem, const rustls_certified_key **pckey) -{ - apr_status_t rv = APR_SUCCESS; - - if (spec->cert_file) { - tls_cert_pem_t *pems; - - rv = tls_cert_load_pem(p, spec, &pems); - if (APR_SUCCESS != rv) goto cleanup; - if (pcert_pem) *pcert_pem = tls_data_to_str(p, &pems->cert_pem); - rv = make_certified_key(p, spec->cert_file, &pems->cert_pem, &pems->pkey_pem, pckey); - /* dont want them hanging around in memory unnecessarily. */ - nullify_key_pem(pems); - } - else if (spec->cert_pem) { - tls_data_t pkey_pem, pem; - pem = tls_data_from_str(spec->cert_pem); - if (spec->pkey_pem) { - pkey_pem = tls_data_from_str(spec->pkey_pem); - } - else { - pkey_pem = pem; - } - if (pcert_pem) *pcert_pem = spec->cert_pem; - rv = make_certified_key(p, "memory", &pem, &pkey_pem, pckey); - /* pems provided from outside are responsibility of the caller */ - } - else { - rv = APR_ENOENT; goto cleanup; - } -cleanup: - return rv; -} - -typedef struct { - const char *id; - const char *cert_pem; - server_rec *server; - const rustls_certified_key *certified_key; -} tls_cert_reg_entry_t; - -static int reg_entry_cleanup(void *ctx, const void *key, apr_ssize_t klen, const void *val) -{ - tls_cert_reg_entry_t *entry = (tls_cert_reg_entry_t*)val; - (void)ctx; (void)key; (void)klen; - if (entry->certified_key) { - rustls_certified_key_free(entry->certified_key); - entry->certified_key = NULL; - } - return 1; -} - -static apr_status_t reg_cleanup(void *data) -{ - tls_cert_reg_t *reg = data; - if (reg->id2entry) { - apr_hash_do(reg_entry_cleanup, reg, reg->id2entry); - apr_hash_clear(reg->id2entry); - if (reg->key2entry) apr_hash_clear(reg->key2entry); - } - return APR_SUCCESS; -} - -tls_cert_reg_t *tls_cert_reg_make(apr_pool_t *p) -{ - tls_cert_reg_t *reg; - - reg = apr_pcalloc(p, sizeof(*reg)); - reg->pool = p; - reg->id2entry = apr_hash_make(p); - reg->key2entry = apr_hash_make(p); - apr_pool_cleanup_register(p, reg, reg_cleanup, apr_pool_cleanup_null); - return reg; -} - -apr_size_t tls_cert_reg_count(tls_cert_reg_t *reg) -{ - return apr_hash_count(reg->id2entry); -} - -static const char *cert_spec_to_id(const tls_cert_spec_t *spec) -{ - if (spec->cert_file) return spec->cert_file; - if (spec->cert_pem) return spec->cert_pem; - return NULL; -} - -apr_status_t tls_cert_reg_get_certified_key( - tls_cert_reg_t *reg, server_rec *s, const tls_cert_spec_t *spec, - const rustls_certified_key **pckey) -{ - apr_status_t rv = APR_SUCCESS; - const char *id; - tls_cert_reg_entry_t *entry; - - id = cert_spec_to_id(spec); - assert(id); - entry = apr_hash_get(reg->id2entry, id, APR_HASH_KEY_STRING); - if (!entry) { - const rustls_certified_key *certified_key; - const char *cert_pem; - rv = tls_cert_load_cert_key(reg->pool, spec, &cert_pem, &certified_key); - if (APR_SUCCESS != rv) goto cleanup; - entry = apr_pcalloc(reg->pool, sizeof(*entry)); - entry->id = apr_pstrdup(reg->pool, id); - entry->cert_pem = cert_pem; - entry->server = s; - entry->certified_key = certified_key; - apr_hash_set(reg->id2entry, entry->id, APR_HASH_KEY_STRING, entry); - /* associates the pointer value */ - apr_hash_set(reg->key2entry, &entry->certified_key, sizeof(entry->certified_key), entry); - } - -cleanup: - if (APR_SUCCESS == rv) { - *pckey = entry->certified_key; - } - else { - *pckey = NULL; - } - return rv; -} - -typedef struct { - void *userdata; - tls_cert_reg_visitor *visitor; -} reg_visit_ctx_t; - -static int reg_visit(void *vctx, const void *key, apr_ssize_t klen, const void *val) -{ - reg_visit_ctx_t *ctx = vctx; - tls_cert_reg_entry_t *entry = (tls_cert_reg_entry_t*)val; - - (void)key; (void)klen; - return ctx->visitor(ctx->userdata, entry->server, entry->id, entry->cert_pem, entry->certified_key); -} - -void tls_cert_reg_do( - tls_cert_reg_visitor *visitor, void *userdata, tls_cert_reg_t *reg) -{ - reg_visit_ctx_t ctx; - ctx.visitor = visitor; - ctx.userdata = userdata; - apr_hash_do(reg_visit, &ctx, reg->id2entry); -} - -const char *tls_cert_reg_get_id(tls_cert_reg_t *reg, const rustls_certified_key *certified_key) -{ - tls_cert_reg_entry_t *entry; - - entry = apr_hash_get(reg->key2entry, &certified_key, sizeof(certified_key)); - return entry? entry->id : NULL; -} - -apr_status_t tls_cert_load_root_store( - apr_pool_t *p, const char *store_file, const rustls_root_cert_store **pstore) -{ - const char *fpath; - tls_data_t pem; - rustls_root_cert_store_builder *store_builder = NULL; - const rustls_root_cert_store *store = NULL; - rustls_result rr = RUSTLS_RESULT_OK; - apr_pool_t *ptemp = NULL; - apr_status_t rv; - - ap_assert(store_file); - - rv = apr_pool_create(&ptemp, p); - if (APR_SUCCESS != rv) goto cleanup; - apr_pool_tag(ptemp, "tls_load_root_cert_store"); - fpath = ap_server_root_relative(ptemp, store_file); - if (NULL == fpath) { - rv = APR_ENOENT; goto cleanup; - } - /* we use this for client auth CAs. 1MB seems large enough. */ - rv = tls_util_file_load(ptemp, fpath, 0, 1024*1024, &pem); - if (APR_SUCCESS != rv) goto cleanup; - - store_builder = rustls_root_cert_store_builder_new(); - rr = rustls_root_cert_store_builder_add_pem(store_builder, pem.data, pem.len, 1); - if (RUSTLS_RESULT_OK != rr) goto cleanup; - - rr = rustls_root_cert_store_builder_build(store_builder, &store); - if (RUSTLS_RESULT_OK != rr) goto cleanup; - -cleanup: - if (store_builder != NULL) { - rustls_root_cert_store_builder_free(store_builder); - } - if (RUSTLS_RESULT_OK != rr) { - const char *err_descr; - rv = tls_util_rustls_error(p, rr, &err_descr); - ap_log_perror(APLOG_MARK, APLOG_ERR, rv, p, APLOGNO(10364) - "Failed to load root store %s: [%d] %s", - store_file, (int)rr, err_descr); - } - if (APR_SUCCESS == rv) { - *pstore = store; - } - else { - *pstore = NULL; - if (store) rustls_root_cert_store_free(store); - } - if (ptemp) apr_pool_destroy(ptemp); - return rv; -} - -typedef struct { - const char *id; - const rustls_root_cert_store *store; -} tls_cert_root_stores_entry_t; - -static int stores_entry_cleanup(void *ctx, const void *key, apr_ssize_t klen, const void *val) -{ - tls_cert_root_stores_entry_t *entry = (tls_cert_root_stores_entry_t*)val; - (void)ctx; (void)key; (void)klen; - if (entry->store) { - rustls_root_cert_store_free(entry->store); - entry->store = NULL; - } - return 1; -} - -static apr_status_t stores_cleanup(void *data) -{ - tls_cert_root_stores_t *stores = data; - tls_cert_root_stores_clear(stores); - return APR_SUCCESS; -} - -tls_cert_root_stores_t *tls_cert_root_stores_make(apr_pool_t *p) -{ - tls_cert_root_stores_t *stores; - - stores = apr_pcalloc(p, sizeof(*stores)); - stores->pool = p; - stores->file2store = apr_hash_make(p); - apr_pool_cleanup_register(p, stores, stores_cleanup, apr_pool_cleanup_null); - return stores; -} - -void tls_cert_root_stores_clear(tls_cert_root_stores_t *stores) -{ - if (stores->file2store) { - apr_hash_do(stores_entry_cleanup, stores, stores->file2store); - apr_hash_clear(stores->file2store); - } -} - -apr_status_t tls_cert_root_stores_get( - tls_cert_root_stores_t *stores, - const char *store_file, - const rustls_root_cert_store **pstore) -{ - apr_status_t rv = APR_SUCCESS; - tls_cert_root_stores_entry_t *entry; - - entry = apr_hash_get(stores->file2store, store_file, APR_HASH_KEY_STRING); - if (!entry) { - const rustls_root_cert_store *store; - rv = tls_cert_load_root_store(stores->pool, store_file, &store); - if (APR_SUCCESS != rv) goto cleanup; - entry = apr_pcalloc(stores->pool, sizeof(*entry)); - entry->id = apr_pstrdup(stores->pool, store_file); - entry->store = store; - apr_hash_set(stores->file2store, entry->id, APR_HASH_KEY_STRING, entry); - } - -cleanup: - if (APR_SUCCESS == rv) { - *pstore = entry->store; - } - else { - *pstore = NULL; - } - return rv; -} - -typedef struct { - const char *id; - rustls_client_cert_verifier *client_verifier; - rustls_client_cert_verifier *client_verifier_opt; -} tls_cert_verifiers_entry_t; - -static int verifiers_entry_cleanup(void *ctx, const void *key, apr_ssize_t klen, const void *val) -{ - tls_cert_verifiers_entry_t *entry = (tls_cert_verifiers_entry_t*)val; - (void)ctx; (void)key; (void)klen; - if (entry->client_verifier) { - rustls_client_cert_verifier_free(entry->client_verifier); - entry->client_verifier = NULL; - } - if (entry->client_verifier_opt) { - rustls_client_cert_verifier_free(entry->client_verifier_opt); - entry->client_verifier_opt = NULL; - } - return 1; -} - -static apr_status_t verifiers_cleanup(void *data) -{ - tls_cert_verifiers_t *verifiers = data; - tls_cert_verifiers_clear(verifiers); - return APR_SUCCESS; -} - -tls_cert_verifiers_t *tls_cert_verifiers_make( - apr_pool_t *p, tls_cert_root_stores_t *stores) -{ - tls_cert_verifiers_t *verifiers; - - verifiers = apr_pcalloc(p, sizeof(*verifiers)); - verifiers->pool = p; - verifiers->stores = stores; - verifiers->file2verifier = apr_hash_make(p); - apr_pool_cleanup_register(p, verifiers, verifiers_cleanup, apr_pool_cleanup_null); - return verifiers; -} - -void tls_cert_verifiers_clear(tls_cert_verifiers_t *verifiers) -{ - if (verifiers->file2verifier) { - apr_hash_do(verifiers_entry_cleanup, verifiers, verifiers->file2verifier); - apr_hash_clear(verifiers->file2verifier); - } -} - -static tls_cert_verifiers_entry_t * verifiers_get_or_make_entry( - tls_cert_verifiers_t *verifiers, - const char *store_file) -{ - tls_cert_verifiers_entry_t *entry; - - entry = apr_hash_get(verifiers->file2verifier, store_file, APR_HASH_KEY_STRING); - if (!entry) { - entry = apr_pcalloc(verifiers->pool, sizeof(*entry)); - entry->id = apr_pstrdup(verifiers->pool, store_file); - apr_hash_set(verifiers->file2verifier, entry->id, APR_HASH_KEY_STRING, entry); - } - return entry; -} - -static apr_status_t tls_cert_client_verifiers_get_internal( - tls_cert_verifiers_t *verifiers, - const char *store_file, - const rustls_client_cert_verifier **pverifier, - bool allow_unauthenticated) -{ - apr_status_t rv = APR_SUCCESS; - tls_cert_verifiers_entry_t *entry; - rustls_result rr = RUSTLS_RESULT_OK; - struct rustls_web_pki_client_cert_verifier_builder *verifier_builder = NULL; - - entry = verifiers_get_or_make_entry(verifiers, store_file); - if (!entry->client_verifier) { - const rustls_root_cert_store *store; - rv = tls_cert_root_stores_get(verifiers->stores, store_file, &store); - if (APR_SUCCESS != rv) goto cleanup; - verifier_builder = rustls_web_pki_client_cert_verifier_builder_new(store); - - if (allow_unauthenticated) { - rr = rustls_web_pki_client_cert_verifier_builder_allow_unauthenticated(verifier_builder); - if (rr != RUSTLS_RESULT_OK) { - goto cleanup; - } - } - - rr = rustls_web_pki_client_cert_verifier_builder_build(verifier_builder, &entry->client_verifier); - if (rr != RUSTLS_RESULT_OK) { - goto cleanup; - } - } - -cleanup: - if (verifier_builder != NULL) { - rustls_web_pki_client_cert_verifier_builder_free(verifier_builder); - } - if (rr != RUSTLS_RESULT_OK) { - rv = tls_util_rustls_error(verifiers->pool, rr, NULL); - } - if (APR_SUCCESS == rv) { - *pverifier = entry->client_verifier; - } - else { - *pverifier = NULL; - } - return rv; -} - - -apr_status_t tls_cert_client_verifiers_get( - tls_cert_verifiers_t *verifiers, - const char *store_file, - const rustls_client_cert_verifier **pverifier) -{ - return tls_cert_client_verifiers_get_internal(verifiers, store_file, pverifier, false); -} - -apr_status_t tls_cert_client_verifiers_get_optional( - tls_cert_verifiers_t *verifiers, - const char *store_file, - const rustls_client_cert_verifier **pverifier) -{ - return tls_cert_client_verifiers_get_internal(verifiers, store_file, pverifier, true); -} diff --git a/modules/tls/tls_cert.h b/modules/tls/tls_cert.h deleted file mode 100644 index 3326f0eb3e..0000000000 --- a/modules/tls/tls_cert.h +++ /dev/null @@ -1,211 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef tls_cert_h -#define tls_cert_h - -#include "tls_util.h" - -/** - * The PEM data of a certificate and its key. - */ -typedef struct { - tls_data_t cert_pem; - tls_data_t pkey_pem; -} tls_cert_pem_t; - -/** - * Specify a certificate via files or PEM data. - */ -typedef struct { - const char *cert_file; /* file path, relative to ap_root */ - const char *pkey_file; /* file path, relative to ap_root */ - const char *cert_pem; /* NUL-terminated PEM string */ - const char *pkey_pem; /* NUL-terminated PEM string */ -} tls_cert_spec_t; - -/** - * Load the PEM data for a certificate file and key file as given in `cert`. - */ -apr_status_t tls_cert_load_pem( - apr_pool_t *p, const tls_cert_spec_t *cert, tls_cert_pem_t **ppem); - -apr_status_t tls_cert_to_pem(const char **ppem, apr_pool_t *p, const rustls_certificate *cert); - -/** - * Load a rustls certified key from a certificate specification. - * The returned `rustls_certified_key` is owned by the caller. - * @param p the memory pool to use - * @param spec the specification for the certificate (file or PEM data) - * @param cert_pem return the PEM data used for loading the certificates, optional - * @param pckey the loaded certified key on return - */ -apr_status_t tls_cert_load_cert_key( - apr_pool_t *p, const tls_cert_spec_t *spec, - const char **pcert_pem, const rustls_certified_key **pckey); - -/** - * A registry of rustls_certified_key* by identifier. - */ -typedef struct tls_cert_reg_t tls_cert_reg_t; -struct tls_cert_reg_t{ - apr_pool_t *pool; - apr_hash_t *id2entry; - apr_hash_t *key2entry; -}; - -/** - * Create a new registry with lifetime based on the memory pool. - * The registry will take care of its memory and allocated keys when - * the pool is destroyed. - */ -tls_cert_reg_t *tls_cert_reg_make(apr_pool_t *p); - -/** - * Return the number of certified keys in the registry. - */ -apr_size_t tls_cert_reg_count(tls_cert_reg_t *reg); - -/** - * Get a the `rustls_certified_key` identified by `spec` from the registry. - * This will load the key the first time it is requested. - * The returned `rustls_certified_key` is owned by the registry. - * @param reg the certified key registry - * @param s the server_rec this is loaded into, useful for error logging - * @param spec the specification of the certified key - * @param pckey the certified key instance on return - */ -apr_status_t tls_cert_reg_get_certified_key( - tls_cert_reg_t *reg, server_rec *s, const tls_cert_spec_t *spec, const rustls_certified_key **pckey); - -/** - * Visit all certified keys in the registry. - * The callback may return 0 to abort the iteration. - * @param userdata supplied by the visit invocation - * @param s the server_rec the certified was load into first - * @param id internal identifier of the certified key - * @param cert_pem the PEM data of the certificate and its chain - * @param certified_key the key instance itself - */ -typedef int tls_cert_reg_visitor( - void *userdata, server_rec *s, - const char *id, const char *cert_pem, const rustls_certified_key *certified_key); - -/** - * Visit all certified_key entries in the registry. - * @param visitor callback invoked on each entry until it returns 0. - * @param userdata passed to callback - * @param reg the registry to iterate over - */ -void tls_cert_reg_do( - tls_cert_reg_visitor *visitor, void *userdata, tls_cert_reg_t *reg); - -/** - * Get the identity assigned to a loaded, certified key. Returns NULL, if the - * key is not part of the registry. The returned bytes are owned by the registry - * entry. - * @param reg the registry to look in. - * @param certified_key the key to get the identifier for - */ -const char *tls_cert_reg_get_id(tls_cert_reg_t *reg, const rustls_certified_key *certified_key); - -/** - * Load all root certificates from a PEM file into a rustls_root_cert_store. - * @param p the memory pool to use - * @param store_file the (server relative) path of the PEM file - * @param pstore the loaded root store on success - */ -apr_status_t tls_cert_load_root_store( - apr_pool_t *p, const char *store_file, const rustls_root_cert_store **pstore); - -typedef struct tls_cert_root_stores_t tls_cert_root_stores_t; -struct tls_cert_root_stores_t { - apr_pool_t *pool; - apr_hash_t *file2store; -}; - -/** - * Create a new root stores registry with lifetime based on the memory pool. - * The registry will take care of its memory and allocated stores when - * the pool is destroyed. - */ -tls_cert_root_stores_t *tls_cert_root_stores_make(apr_pool_t *p); - -/** - * Clear the root stores registry, freeing all stores. - */ -void tls_cert_root_stores_clear(tls_cert_root_stores_t *stores); - -/** - * Load all root certificates from a PEM file into a rustls_root_cert_store. - * @param p the memory pool to use - * @param store_file the (server relative) path of the PEM file - * @param pstore the loaded root store on success - */ -apr_status_t tls_cert_root_stores_get( - tls_cert_root_stores_t *stores, - const char *store_file, - const rustls_root_cert_store **pstore); - -typedef struct tls_cert_verifiers_t tls_cert_verifiers_t; -struct tls_cert_verifiers_t { - apr_pool_t *pool; - tls_cert_root_stores_t *stores; - apr_hash_t *file2verifier; -}; - -/** - * Create a new registry for certificate verifiers with lifetime based on the memory pool. - * The registry will take care of its memory and allocated verifiers when - * the pool is destroyed. - * @param p the memory pool to use - * @param stores the store registry for lookups - */ -tls_cert_verifiers_t *tls_cert_verifiers_make( - apr_pool_t *p, tls_cert_root_stores_t *stores); - -/** - * Clear the verifiers registry, freeing all verifiers. - */ -void tls_cert_verifiers_clear( - tls_cert_verifiers_t *verifiers); - -/** - * Get the mandatory client certificate verifier for the - * root certificate store in `store_file`. Will create - * the verifier if not already known. - * @param verifiers the registry of certificate verifiers - * @param store_file the (server relative) path of the PEM file with certificates - * @param pverifiers the verifier on success - */ -apr_status_t tls_cert_client_verifiers_get( - tls_cert_verifiers_t *verifiers, - const char *store_file, - const rustls_client_cert_verifier **pverifier); - -/** - * Get the optional client certificate verifier for the - * root certificate store in `store_file`. Will create - * the verifier if not already known. - * @param verifiers the registry of certificate verifiers - * @param store_file the (server relative) path of the PEM file with certificates - * @param pverifiers the verifier on success - */ -apr_status_t tls_cert_client_verifiers_get_optional( - tls_cert_verifiers_t *verifiers, - const char *store_file, - const rustls_client_cert_verifier **pverifier); - -#endif /* tls_cert_h */ diff --git a/modules/tls/tls_conf.c b/modules/tls/tls_conf.c deleted file mode 100644 index a9f27de87a..0000000000 --- a/modules/tls/tls_conf.c +++ /dev/null @@ -1,780 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include "tls_cert.h" -#include "tls_proto.h" -#include "tls_conf.h" -#include "tls_util.h" -#include "tls_var.h" -#include "tls_cache.h" - - -extern module AP_MODULE_DECLARE_DATA tls_module; -APLOG_USE_MODULE(tls); - -static tls_conf_global_t *conf_global_get_or_make(apr_pool_t *pool, server_rec *s) -{ - tls_conf_global_t *gconf; - - /* we create this only once for apache's one ap_server_conf. - * If this gets called for another server, we should already have - * done it for ap_server_conf. */ - if (ap_server_conf && s != ap_server_conf) { - tls_conf_server_t *sconf = tls_conf_server_get(ap_server_conf); - ap_assert(sconf); - ap_assert(sconf->global); - return sconf->global; - } - - gconf = apr_pcalloc(pool, sizeof(*gconf)); - gconf->ap_server = ap_server_conf; - gconf->status = TLS_CONF_ST_INIT; - gconf->proto = tls_proto_init(pool, s); - gconf->proxy_configs = apr_array_make(pool, 10, sizeof(tls_conf_proxy_t*)); - - gconf->var_lookups = apr_hash_make(pool); - tls_var_init_lookup_hash(pool, gconf->var_lookups); - gconf->session_cache_spec = "default"; - - return gconf; -} - -tls_conf_server_t *tls_conf_server_get(server_rec *s) -{ - tls_conf_server_t *sc = ap_get_module_config(s->module_config, &tls_module); - ap_assert(sc); - return sc; -} - - -#define CONF_S_NAME(s) (s && s->server_hostname? s->server_hostname : "default") - -void *tls_conf_create_svr(apr_pool_t *pool, server_rec *s) -{ - tls_conf_server_t *conf; - - conf = apr_pcalloc(pool, sizeof(*conf)); - conf->global = conf_global_get_or_make(pool, s); - conf->server = s; - - conf->enabled = TLS_FLAG_UNSET; - conf->cert_specs = apr_array_make(pool, 3, sizeof(tls_cert_spec_t*)); - conf->honor_client_order = TLS_FLAG_UNSET; - conf->strict_sni = TLS_FLAG_UNSET; - conf->tls_protocol_min = TLS_FLAG_UNSET; - conf->tls_pref_ciphers = apr_array_make(pool, 3, sizeof(apr_uint16_t));; - conf->tls_supp_ciphers = apr_array_make(pool, 3, sizeof(apr_uint16_t));; - return conf; -} - -#define MERGE_INT(base, add, field) \ - (add->field == TLS_FLAG_UNSET)? base->field : add->field; - -void *tls_conf_merge_svr(apr_pool_t *pool, void *basev, void *addv) -{ - tls_conf_server_t *base = basev; - tls_conf_server_t *add = addv; - tls_conf_server_t *nconf; - - nconf = apr_pcalloc(pool, sizeof(*nconf)); - nconf->server = add->server; - nconf->global = add->global? add->global : base->global; - - nconf->enabled = MERGE_INT(base, add, enabled); - nconf->cert_specs = apr_array_append(pool, base->cert_specs, add->cert_specs); - nconf->tls_protocol_min = MERGE_INT(base, add, tls_protocol_min); - nconf->tls_pref_ciphers = add->tls_pref_ciphers->nelts? - add->tls_pref_ciphers : base->tls_pref_ciphers; - nconf->tls_supp_ciphers = add->tls_supp_ciphers->nelts? - add->tls_supp_ciphers : base->tls_supp_ciphers; - nconf->honor_client_order = MERGE_INT(base, add, honor_client_order); - nconf->client_ca = add->client_ca? add->client_ca : base->client_ca; - nconf->client_auth = (add->client_auth != TLS_CLIENT_AUTH_UNSET)? - add->client_auth : base->client_auth; - nconf->var_user_name = add->var_user_name? add->var_user_name : base->var_user_name; - return nconf; -} - -tls_conf_dir_t *tls_conf_dir_get(request_rec *r) -{ - tls_conf_dir_t *dc = ap_get_module_config(r->per_dir_config, &tls_module); - ap_assert(dc); - return dc; -} - -tls_conf_dir_t *tls_conf_dir_server_get(server_rec *s) -{ - tls_conf_dir_t *dc = ap_get_module_config(s->lookup_defaults, &tls_module); - ap_assert(dc); - return dc; -} - -void *tls_conf_create_dir(apr_pool_t *pool, char *dir) -{ - tls_conf_dir_t *conf; - - (void)dir; - conf = apr_pcalloc(pool, sizeof(*conf)); - conf->std_env_vars = TLS_FLAG_UNSET; - conf->proxy_enabled = TLS_FLAG_UNSET; - conf->proxy_protocol_min = TLS_FLAG_UNSET; - conf->proxy_pref_ciphers = apr_array_make(pool, 3, sizeof(apr_uint16_t));; - conf->proxy_supp_ciphers = apr_array_make(pool, 3, sizeof(apr_uint16_t));; - conf->proxy_machine_cert_specs = apr_array_make(pool, 3, sizeof(tls_cert_spec_t*)); - return conf; -} - - -static int same_proxy_settings(tls_conf_dir_t *a, tls_conf_dir_t *b) -{ - return a->proxy_ca == b->proxy_ca; -} - -static void dir_assign_merge( - tls_conf_dir_t *dest, apr_pool_t *pool, tls_conf_dir_t *base, tls_conf_dir_t *add) -{ - tls_conf_dir_t local; - - memset(&local, 0, sizeof(local)); - local.std_env_vars = MERGE_INT(base, add, std_env_vars); - local.export_cert_vars = MERGE_INT(base, add, export_cert_vars); - local.proxy_enabled = MERGE_INT(base, add, proxy_enabled); - local.proxy_ca = add->proxy_ca? add->proxy_ca : base->proxy_ca; - local.proxy_protocol_min = MERGE_INT(base, add, proxy_protocol_min); - local.proxy_pref_ciphers = add->proxy_pref_ciphers->nelts? - add->proxy_pref_ciphers : base->proxy_pref_ciphers; - local.proxy_supp_ciphers = add->proxy_supp_ciphers->nelts? - add->proxy_supp_ciphers : base->proxy_supp_ciphers; - local.proxy_machine_cert_specs = apr_array_append(pool, - base->proxy_machine_cert_specs, add->proxy_machine_cert_specs); - if (local.proxy_enabled == TLS_FLAG_TRUE) { - if (add->proxy_config) { - local.proxy_config = same_proxy_settings(&local, add)? add->proxy_config : NULL; - } - else if (base->proxy_config) { - local.proxy_config = same_proxy_settings(&local, base)? add->proxy_config : NULL; - } - } - memcpy(dest, &local, sizeof(*dest)); -} - -void *tls_conf_merge_dir(apr_pool_t *pool, void *basev, void *addv) -{ - tls_conf_dir_t *base = basev; - tls_conf_dir_t *add = addv; - tls_conf_dir_t *nconf = apr_pcalloc(pool, sizeof(*nconf)); - dir_assign_merge(nconf, pool, base, add); - return nconf; -} - -static void tls_conf_dir_set_options_defaults(apr_pool_t *pool, tls_conf_dir_t *dc) -{ - (void)pool; - dc->std_env_vars = TLS_FLAG_FALSE; - dc->export_cert_vars = TLS_FLAG_FALSE; -} - -apr_status_t tls_conf_server_apply_defaults(tls_conf_server_t *sc, apr_pool_t *p) -{ - (void)p; - if (sc->enabled == TLS_FLAG_UNSET) sc->enabled = TLS_FLAG_FALSE; - if (sc->tls_protocol_min == TLS_FLAG_UNSET) sc->tls_protocol_min = 0; - if (sc->honor_client_order == TLS_FLAG_UNSET) sc->honor_client_order = TLS_FLAG_TRUE; - if (sc->strict_sni == TLS_FLAG_UNSET) sc->strict_sni = TLS_FLAG_TRUE; - if (sc->client_auth == TLS_CLIENT_AUTH_UNSET) sc->client_auth = TLS_CLIENT_AUTH_NONE; - return APR_SUCCESS; -} - -apr_status_t tls_conf_dir_apply_defaults(tls_conf_dir_t *dc, apr_pool_t *p) -{ - (void)p; - if (dc->std_env_vars == TLS_FLAG_UNSET) dc->std_env_vars = TLS_FLAG_FALSE; - if (dc->export_cert_vars == TLS_FLAG_UNSET) dc->export_cert_vars = TLS_FLAG_FALSE; - if (dc->proxy_enabled == TLS_FLAG_UNSET) dc->proxy_enabled = TLS_FLAG_FALSE; - return APR_SUCCESS; -} - -tls_conf_proxy_t *tls_conf_proxy_make( - apr_pool_t *p, tls_conf_dir_t *dc, tls_conf_global_t *gc, server_rec *s) -{ - tls_conf_proxy_t *pc = apr_pcalloc(p, sizeof(*pc)); - pc->defined_in = s; - pc->global = gc; - pc->proxy_ca = dc->proxy_ca; - pc->proxy_protocol_min = dc->proxy_protocol_min; - pc->proxy_pref_ciphers = dc->proxy_pref_ciphers; - pc->proxy_supp_ciphers = dc->proxy_supp_ciphers; - pc->machine_cert_specs = dc->proxy_machine_cert_specs; - pc->machine_certified_keys = apr_array_make(p, 3, sizeof(const rustls_certified_key*)); - return pc; -} - -int tls_proxy_section_post_config( - apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s, - ap_conf_vector_t *section_config) -{ - tls_conf_dir_t *proxy_dc, *server_dc; - tls_conf_server_t *sc; - - /* mod_proxy collects the ... sections per server (base server or virtualhost) - * and in its post_config hook, calls our function registered at its hook for each with - * s - the server they were define in - * section_config - the set of dir_configs for a section - * - * If none of _our_ config directives had been used, here or in the server, we get a NULL. - * Which means we have to do nothing. Otherwise, we add to `proxy_dc` the - * settings from `server_dc` - since this is not automagically done by apache. - * - * `proxy_dc` is then complete and tells us if we handle outgoing connections - * here and with what parameter settings. - */ - (void)ptemp; (void)plog; - ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, s, - "%s: tls_proxy_section_post_config called", s->server_hostname); - proxy_dc = ap_get_module_config(section_config, &tls_module); - if (!proxy_dc) goto cleanup; - server_dc = ap_get_module_config(s->lookup_defaults, &tls_module); - ap_assert(server_dc); - dir_assign_merge(proxy_dc, p, server_dc, proxy_dc); - tls_conf_dir_apply_defaults(proxy_dc, p); - if (proxy_dc->proxy_enabled && !proxy_dc->proxy_config) { - /* remember `proxy_dc` for subsequent configuration of outoing TLS setups */ - sc = tls_conf_server_get(s); - proxy_dc->proxy_config = tls_conf_proxy_make(p, proxy_dc, sc->global, s); - ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, s, - "%s: adding proxy_conf to globals in proxy_post_config_section", - s->server_hostname); - APR_ARRAY_PUSH(sc->global->proxy_configs, tls_conf_proxy_t*) = proxy_dc->proxy_config; - } -cleanup: - return OK; -} - -static const char *cmd_check_file(cmd_parms *cmd, const char *fpath) -{ - char *real_path; - - /* just a dump of the configuration, dont resolve/check */ - if (ap_state_query(AP_SQ_RUN_MODE) == AP_SQ_RM_CONFIG_DUMP) { - return NULL; - } - real_path = ap_server_root_relative(cmd->pool, fpath); - if (!real_path) { - return apr_pstrcat(cmd->pool, cmd->cmd->name, - ": Invalid file path ", fpath, NULL); - } - if (!tls_util_is_file(cmd->pool, real_path)) { - return apr_pstrcat(cmd->pool, cmd->cmd->name, - ": file '", real_path, - "' does not exist or is empty", NULL); - } - return NULL; -} - -static const char *tls_conf_add_engine(cmd_parms *cmd, void *dc, const char*v) -{ - tls_conf_server_t *sc = tls_conf_server_get(cmd->server); - tls_conf_global_t *gc = sc->global; - const char *err = NULL; - char *host, *scope_id; - apr_port_t port; - apr_sockaddr_t *sa; - server_addr_rec *sar; - apr_status_t rv; - - (void)dc; - /* Example of use: - * TLSEngine 443 - * TLSEngine hostname:443 - * TLSEngine 91.0.0.1:443 - * TLSEngine [::0]:443 - */ - rv = apr_parse_addr_port(&host, &scope_id, &port, v, cmd->pool); - if (APR_SUCCESS != rv) { - err = apr_pstrcat(cmd->pool, cmd->cmd->name, - ": invalid address/port in '", v, "'", NULL); - goto cleanup; - } - - /* translate host/port to a sockaddr that we can match with incoming connections */ - rv = apr_sockaddr_info_get(&sa, host, APR_UNSPEC, port, 0, cmd->pool); - if (APR_SUCCESS != rv) { - err = apr_pstrcat(cmd->pool, cmd->cmd->name, - ": unable to get sockaddr for '", host, "'", NULL); - goto cleanup; - } - - if (scope_id) { -#if APR_VERSION_AT_LEAST(1,7,0) - rv = apr_sockaddr_zone_set(sa, scope_id); - if (APR_SUCCESS != rv) { - err = apr_pstrcat(cmd->pool, cmd->cmd->name, - ": error setting ipv6 scope id: '", scope_id, "'", NULL); - goto cleanup; - } -#else - err = apr_pstrcat(cmd->pool, cmd->cmd->name, - ": IPv6 scopes not supported by your APR: '", scope_id, "'", NULL); - goto cleanup; -#endif - } - - sar = apr_pcalloc(cmd->pool, sizeof(*sar)); - sar->host_addr = sa; - sar->virthost = host; - sar->host_port = port; - - sar->next = gc->tls_addresses; - gc->tls_addresses = sar; -cleanup: - return err; -} - -static int flag_value( - const char *arg) -{ - if (!strcasecmp(arg, "On")) { - return TLS_FLAG_TRUE; - } - else if (!strcasecmp(arg, "Off")) { - return TLS_FLAG_FALSE; - } - return TLS_FLAG_UNSET; -} - -static const char *flag_err( - cmd_parms *cmd, const char *v) -{ - return apr_pstrcat(cmd->pool, cmd->cmd->name, - ": value must be 'On' or 'Off': '", v, "'", NULL); -} - -static const char *tls_conf_add_certificate( - cmd_parms *cmd, void *dc, const char *cert_file, const char *pkey_file) -{ - tls_conf_server_t *sc = tls_conf_server_get(cmd->server); - const char *err = NULL, *fpath; - tls_cert_spec_t *cert; - - (void)dc; - if (NULL != (err = cmd_check_file(cmd, cert_file))) goto cleanup; - /* key file may be NULL, in which case cert_file must contain the key PEM */ - if (pkey_file && NULL != (err = cmd_check_file(cmd, pkey_file))) goto cleanup; - - cert = apr_pcalloc(cmd->pool, sizeof(*cert)); - fpath = ap_server_root_relative(cmd->pool, cert_file); - if (!tls_util_is_file(cmd->pool, fpath)) { - return apr_pstrcat(cmd->pool, cmd->cmd->name, - ": unable to find certificate file: '", fpath, "'", NULL); - } - cert->cert_file = cert_file; - if (pkey_file) { - fpath = ap_server_root_relative(cmd->pool, pkey_file); - if (!tls_util_is_file(cmd->pool, fpath)) { - return apr_pstrcat(cmd->pool, cmd->cmd->name, - ": unable to find certificate key file: '", fpath, "'", NULL); - } - } - cert->pkey_file = pkey_file; - *(const tls_cert_spec_t **)apr_array_push(sc->cert_specs) = cert; - -cleanup: - return err; -} - -static const char *parse_ciphers( - cmd_parms *cmd, - tls_conf_global_t *gc, - const char *nop_name, - int argc, char *const argv[], - apr_array_header_t *ciphers) -{ - apr_array_clear(ciphers); - if (argc > 1 || apr_strnatcasecmp(nop_name, argv[0])) { - apr_uint16_t cipher; - int i; - - for (i = 0; i < argc; ++i) { - char *name, *last = NULL; - const char *value = argv[i]; - - name = apr_strtok(apr_pstrdup(cmd->pool, value), ":", &last); - while (name) { - if (tls_proto_get_cipher_by_name(gc->proto, name, &cipher) != APR_SUCCESS) { - return apr_pstrcat(cmd->pool, cmd->cmd->name, - ": cipher not recognized '", name, "'", NULL); - } - APR_ARRAY_PUSH(ciphers, apr_uint16_t) = cipher; - name = apr_strtok(NULL, ":", &last); - } - } - } - return NULL; -} - -static const char *tls_conf_set_preferred_ciphers( - cmd_parms *cmd, void *dc, int argc, char *const argv[]) -{ - tls_conf_server_t *sc = tls_conf_server_get(cmd->server); - const char *err = NULL; - - (void)dc; - if (!argc) { - err = "specify the TLS ciphers to prefer or 'default' for the rustls default ordering."; - goto cleanup; - } - err = parse_ciphers(cmd, sc->global, "default", argc, argv, sc->tls_pref_ciphers); -cleanup: - return err; -} - -static const char *tls_conf_set_suppressed_ciphers( - cmd_parms *cmd, void *dc, int argc, char *const argv[]) -{ - tls_conf_server_t *sc = tls_conf_server_get(cmd->server); - const char *err = NULL; - - (void)dc; - if (!argc) { - err = "specify the TLS ciphers to never use or 'none'."; - goto cleanup; - } - err = parse_ciphers(cmd, sc->global, "none", argc, argv, sc->tls_supp_ciphers); -cleanup: - return err; -} - -static const char *tls_conf_set_honor_client_order( - cmd_parms *cmd, void *dc, const char *v) -{ - tls_conf_server_t *sc = tls_conf_server_get(cmd->server); - int flag = flag_value(v); - - (void)dc; - if (TLS_FLAG_UNSET == flag) return flag_err(cmd, v); - sc->honor_client_order = flag; - return NULL; -} - -static const char *tls_conf_set_strict_sni( - cmd_parms *cmd, void *dc, const char *v) -{ - tls_conf_server_t *sc = tls_conf_server_get(cmd->server); - int flag = flag_value(v); - - (void)dc; - if (TLS_FLAG_UNSET == flag) return flag_err(cmd, v); - sc->strict_sni = flag; - return NULL; -} - -static const char *get_min_protocol( - cmd_parms *cmd, const char *v, int *pmin) -{ - tls_conf_server_t *sc = tls_conf_server_get(cmd->server); - const char *err = NULL; - - if (!apr_strnatcasecmp("default", v)) { - *pmin = 0; - } - else if (*v && v[strlen(v)-1] == '+') { - char *name = apr_pstrdup(cmd->pool, v); - name[strlen(name)-1] = '\0'; - *pmin = tls_proto_get_version_by_name(sc->global->proto, name); - if (!*pmin) { - err = apr_pstrcat(cmd->pool, cmd->cmd->name, - ": unrecognized protocol version specifier (try TLSv1.2+ or TLSv1.3+): '", v, "'", NULL); - goto cleanup; - } - } - else { - err = apr_pstrcat(cmd->pool, cmd->cmd->name, - ": value must be 'default', 'TLSv1.2+' or 'TLSv1.3+': '", v, "'", NULL); - goto cleanup; - } -cleanup: - return err; -} - -static const char *tls_conf_set_protocol( - cmd_parms *cmd, void *dc, const char *v) -{ - tls_conf_server_t *sc = tls_conf_server_get(cmd->server); - (void)dc; - return get_min_protocol(cmd, v, &sc->tls_protocol_min); -} - -static const char *tls_conf_set_options( - cmd_parms *cmd, void *dcv, int argc, char *const argv[]) -{ - tls_conf_dir_t *dc = dcv; - const char *err = NULL, *option; - int i, val; - - /* Are we only having deltas (+/-) or do we reset the options? */ - for (i = 0; i < argc; ++i) { - if (argv[i][0] != '+' && argv[i][0] != '-') { - tls_conf_dir_set_options_defaults(cmd->pool, dc); - break; - } - } - - for (i = 0; i < argc; ++i) { - option = argv[i]; - if (!apr_strnatcasecmp("Defaults", option)) { - dc->std_env_vars = TLS_FLAG_FALSE; - dc->export_cert_vars = TLS_FLAG_FALSE; - } - else { - val = TLS_FLAG_TRUE; - if (*option == '+' || *option == '-') { - val = (*option == '+')? TLS_FLAG_TRUE : TLS_FLAG_FALSE; - ++option; - } - - if (!apr_strnatcasecmp("StdEnvVars", option)) { - dc->std_env_vars = val; - } - else if (!apr_strnatcasecmp("ExportCertData", option)) { - dc->export_cert_vars = val; - } - else { - err = apr_pstrcat(cmd->pool, cmd->cmd->name, - ": unknown option '", option, "'", NULL); - goto cleanup; - } - } - } -cleanup: - return err; -} - -static const char *tls_conf_set_session_cache( - cmd_parms *cmd, void *dc, const char *value) -{ - tls_conf_server_t *sc = tls_conf_server_get(cmd->server); - const char *err = NULL; - - (void)dc; - if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) goto cleanup; - - err = tls_cache_set_specification(value, sc->global, cmd->pool, cmd->temp_pool); -cleanup: - return err; -} - -static const char *tls_conf_set_proxy_engine(cmd_parms *cmd, void *dir_conf, int flag) -{ - tls_conf_dir_t *dc = dir_conf; - (void)cmd; - dc->proxy_enabled = flag ? TLS_FLAG_TRUE : TLS_FLAG_FALSE; - return NULL; -} - -static const char *tls_conf_set_proxy_ca( - cmd_parms *cmd, void *dir_conf, const char *proxy_ca) -{ - tls_conf_dir_t *dc = dir_conf; - const char *err = NULL; - - if (strcasecmp(proxy_ca, "default") && NULL != (err = cmd_check_file(cmd, proxy_ca))) goto cleanup; - dc->proxy_ca = proxy_ca; -cleanup: - return err; -} - -static const char *tls_conf_set_proxy_protocol( - cmd_parms *cmd, void *dir_conf, const char *v) -{ - tls_conf_dir_t *dc = dir_conf; - return get_min_protocol(cmd, v, &dc->proxy_protocol_min); -} - -static const char *tls_conf_set_proxy_preferred_ciphers( - cmd_parms *cmd, void *dir_conf, int argc, char *const argv[]) -{ - tls_conf_server_t *sc = tls_conf_server_get(cmd->server); - tls_conf_dir_t *dc = dir_conf; - const char *err = NULL; - - if (!argc) { - err = "specify the proxy TLS ciphers to prefer or 'default' for the rustls default ordering."; - goto cleanup; - } - err = parse_ciphers(cmd, sc->global, "default", argc, argv, dc->proxy_pref_ciphers); -cleanup: - return err; -} - -static const char *tls_conf_set_proxy_suppressed_ciphers( - cmd_parms *cmd, void *dir_conf, int argc, char *const argv[]) -{ - tls_conf_server_t *sc = tls_conf_server_get(cmd->server); - tls_conf_dir_t *dc = dir_conf; - const char *err = NULL; - - if (!argc) { - err = "specify the proxy TLS ciphers to never use or 'none'."; - goto cleanup; - } - err = parse_ciphers(cmd, sc->global, "none", argc, argv, dc->proxy_supp_ciphers); -cleanup: - return err; -} - -#if TLS_CLIENT_CERTS - -static const char *tls_conf_set_client_ca( - cmd_parms *cmd, void *dc, const char *client_ca) -{ - tls_conf_server_t *sc = tls_conf_server_get(cmd->server); - const char *err; - - (void)dc; - if (NULL != (err = cmd_check_file(cmd, client_ca))) goto cleanup; - sc->client_ca = client_ca; -cleanup: - return err; -} - -static const char *tls_conf_set_client_auth( - cmd_parms *cmd, void *dc, const char *mode) -{ - tls_conf_server_t *sc = tls_conf_server_get(cmd->server); - const char *err = NULL; - (void)dc; - if (!strcasecmp(mode, "required")) { - sc->client_auth = TLS_CLIENT_AUTH_REQUIRED; - } - else if (!strcasecmp(mode, "optional")) { - sc->client_auth = TLS_CLIENT_AUTH_OPTIONAL; - } - else if (!strcasecmp(mode, "none")) { - sc->client_auth = TLS_CLIENT_AUTH_NONE; - } - else { - err = apr_pstrcat(cmd->pool, cmd->cmd->name, - ": unknown value: '", mode, "', use required/optional/none.", NULL); - } - return err; -} - -static const char *tls_conf_set_user_name( - cmd_parms *cmd, void *dc, const char *var_user_name) -{ - tls_conf_server_t *sc = tls_conf_server_get(cmd->server); - (void)dc; - sc->var_user_name = var_user_name; - return NULL; -} - -#endif /* if TLS_CLIENT_CERTS */ - -#if TLS_MACHINE_CERTS - -static const char *tls_conf_add_proxy_machine_certificate( - cmd_parms *cmd, void *dir_conf, const char *cert_file, const char *pkey_file) -{ - tls_conf_dir_t *dc = dir_conf; - const char *err = NULL, *fpath; - tls_cert_spec_t *cert; - - (void)dc; - if (NULL != (err = cmd_check_file(cmd, cert_file))) goto cleanup; - /* key file may be NULL, in which case cert_file must contain the key PEM */ - if (pkey_file && NULL != (err = cmd_check_file(cmd, pkey_file))) goto cleanup; - - cert = apr_pcalloc(cmd->pool, sizeof(*cert)); - fpath = ap_server_root_relative(cmd->pool, cert_file); - if (!tls_util_is_file(cmd->pool, fpath)) { - return apr_pstrcat(cmd->pool, cmd->cmd->name, - ": unable to find certificate file: '", fpath, "'", NULL); - } - cert->cert_file = cert_file; - if (pkey_file) { - fpath = ap_server_root_relative(cmd->pool, pkey_file); - if (!tls_util_is_file(cmd->pool, fpath)) { - return apr_pstrcat(cmd->pool, cmd->cmd->name, - ": unable to find certificate key file: '", fpath, "'", NULL); - } - } - cert->pkey_file = pkey_file; - *(const tls_cert_spec_t **)apr_array_push(dc->proxy_machine_cert_specs) = cert; - -cleanup: - return err; -} - -#endif /* if TLS_MACHINE_CERTS */ - -const command_rec tls_conf_cmds[] = { - AP_INIT_TAKE12("TLSCertificate", tls_conf_add_certificate, NULL, RSRC_CONF, - "Add a certificate to the server by specifying a file containing the " - "certificate PEM, followed by its chain PEMs. The PEM of the key must " - "either also be there or can be given as a separate file."), - AP_INIT_TAKE_ARGV("TLSCiphersPrefer", tls_conf_set_preferred_ciphers, NULL, RSRC_CONF, - "Set the TLS ciphers to prefer when negotiating with a client."), - AP_INIT_TAKE_ARGV("TLSCiphersSuppress", tls_conf_set_suppressed_ciphers, NULL, RSRC_CONF, - "Set the TLS ciphers to never use when negotiating with a client."), - AP_INIT_TAKE1("TLSHonorClientOrder", tls_conf_set_honor_client_order, NULL, RSRC_CONF, - "Set 'on' to have the server honor client preferences in cipher suites, default off."), - AP_INIT_TAKE1("TLSEngine", tls_conf_add_engine, NULL, RSRC_CONF, - "Specify an address+port where the module shall handle incoming TLS connections."), - AP_INIT_TAKE_ARGV("TLSOptions", tls_conf_set_options, NULL, OR_OPTIONS, - "En-/disables optional features in the module."), - AP_INIT_TAKE1("TLSProtocol", tls_conf_set_protocol, NULL, RSRC_CONF, - "Set the minimum TLS protocol version to use."), - AP_INIT_TAKE1("TLSStrictSNI", tls_conf_set_strict_sni, NULL, RSRC_CONF, - "Set strictness of client server name (SNI) check against hosts, default on."), - AP_INIT_TAKE1("TLSSessionCache", tls_conf_set_session_cache, NULL, RSRC_CONF, - "Set which cache to use for TLS sessions."), - AP_INIT_FLAG("TLSProxyEngine", tls_conf_set_proxy_engine, NULL, RSRC_CONF|PROXY_CONF, - "Enable TLS encryption of outgoing connections in this location/server."), - AP_INIT_TAKE1("TLSProxyCA", tls_conf_set_proxy_ca, NULL, RSRC_CONF|PROXY_CONF, - "Set the trust anchors for certificates from proxied backend servers from a PEM file."), - AP_INIT_TAKE1("TLSProxyProtocol", tls_conf_set_proxy_protocol, NULL, RSRC_CONF|PROXY_CONF, - "Set the minimum TLS protocol version to use for proxy connections."), - AP_INIT_TAKE_ARGV("TLSProxyCiphersPrefer", tls_conf_set_proxy_preferred_ciphers, NULL, RSRC_CONF|PROXY_CONF, - "Set the TLS ciphers to prefer when negotiating a proxy connection."), - AP_INIT_TAKE_ARGV("TLSProxyCiphersSuppress", tls_conf_set_proxy_suppressed_ciphers, NULL, RSRC_CONF|PROXY_CONF, - "Set the TLS ciphers to never use when negotiating a proxy connection."), -#if TLS_CLIENT_CERTS - AP_INIT_TAKE1("TLSClientCA", tls_conf_set_client_ca, NULL, RSRC_CONF, - "Set the trust anchors for client certificates from a PEM file."), - AP_INIT_TAKE1("TLSClientCertificate", tls_conf_set_client_auth, NULL, RSRC_CONF, - "If TLS client authentication is 'required', 'optional' or 'none'."), - AP_INIT_TAKE1("TLSUserName", tls_conf_set_user_name, NULL, RSRC_CONF, - "Set the SSL variable to be used as user name."), -#endif /* if TLS_CLIENT_CERTS */ -#if TLS_MACHINE_CERTS - AP_INIT_TAKE12("TLSProxyMachineCertificate", tls_conf_add_proxy_machine_certificate, NULL, RSRC_CONF|PROXY_CONF, - "Add a certificate to be used as client certificate on a proxy connection. "), -#endif /* if TLS_MACHINE_CERTS */ - AP_INIT_TAKE1(NULL, NULL, NULL, RSRC_CONF, NULL) -}; diff --git a/modules/tls/tls_conf.h b/modules/tls/tls_conf.h deleted file mode 100644 index e924412d54..0000000000 --- a/modules/tls/tls_conf.h +++ /dev/null @@ -1,185 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef tls_conf_h -#define tls_conf_h - -/* Configuration flags */ -#define TLS_FLAG_UNSET (-1) -#define TLS_FLAG_FALSE (0) -#define TLS_FLAG_TRUE (1) - -struct tls_proto_conf_t; -struct tls_cert_reg_t; -struct tls_cert_root_stores_t; -struct tls_cert_verifiers_t; -struct ap_socache_instance_t; -struct ap_socache_provider_t; -struct apr_global_mutex_t; - - -/* disabled, since rustls support is lacking - * - x.509 retrieval of certificate fields and extensions - * - certificate revocation lists (CRL) - * - x.509 access to issuer of trust chain in x.509 CA store: - * server CA has ca1, ca2, ca3 - * client present certA - * rustls verifies that it is signed by *one of* ca* certs - * OCSP check needs (certA, issuing cert) for query - */ -#define TLS_CLIENT_CERTS 0 - -/* support for this exists as PR - */ -#define TLS_MACHINE_CERTS 1 - - -typedef enum { - TLS_CLIENT_AUTH_UNSET, - TLS_CLIENT_AUTH_NONE, - TLS_CLIENT_AUTH_REQUIRED, - TLS_CLIENT_AUTH_OPTIONAL, -} tls_client_auth_t; - -typedef enum { - TLS_CONF_ST_INIT, - TLS_CONF_ST_INCOMING_DONE, - TLS_CONF_ST_OUTGOING_DONE, - TLS_CONF_ST_DONE, -} tls_conf_status_t; - -/* The global module configuration, created after post-config - * and then readonly. - */ -typedef struct { - server_rec *ap_server; /* the global server we initialized on */ - const char *module_version; - const char *crustls_version; - - tls_conf_status_t status; - int mod_proxy_post_config_done; /* if mod_proxy did its post-config things */ - - server_addr_rec *tls_addresses; /* the addresses/ports our engine is enabled on */ - apr_array_header_t *proxy_configs; /* tls_conf_proxy_t* collected from everywhere */ - - struct tls_proto_conf_t *proto; /* TLS protocol/rustls specific globals */ - apr_hash_t *var_lookups; /* variable lookup functions by var name */ - struct tls_cert_reg_t *cert_reg; /* all certified keys loaded */ - struct tls_cert_root_stores_t *stores; /* loaded certificate stores */ - struct tls_cert_verifiers_t *verifiers; /* registry of certificate verifiers */ - - const char *session_cache_spec; /* how the session cache was specified */ - const struct ap_socache_provider_t *session_cache_provider; /* provider used for session cache */ - struct ap_socache_instance_t *session_cache; /* session cache instance */ - struct apr_global_mutex_t *session_cache_mutex; /* global mutex for access to session cache */ - - const rustls_server_config *rustls_hello_config; /* used for initial client hello parsing */ -} tls_conf_global_t; - -/* The module configuration for a server (vhost). - * Populated during config parsing, merged and completed - * in the post config phase. Readonly after that. - */ -typedef struct { - server_rec *server; /* server this config belongs to */ - tls_conf_global_t *global; /* global module config, singleton */ - - int enabled; /* TLS_FLAG_TRUE if mod_tls is active on this server */ - apr_array_header_t *cert_specs; /* array of (tls_cert_spec_t*) of configured certificates */ - int tls_protocol_min; /* the minimum TLS protocol version to use */ - apr_array_header_t *tls_pref_ciphers; /* List of apr_uint16_t cipher ids to prefer */ - apr_array_header_t *tls_supp_ciphers; /* List of apr_uint16_t cipher ids to suppress */ - const apr_array_header_t *ciphersuites; /* Computed post-config, ordered list of rustls cipher suites */ - int honor_client_order; /* honor client cipher ordering */ - int strict_sni; - - const char *client_ca; /* PEM file with trust anchors for client certs */ - tls_client_auth_t client_auth; /* how client authentication with certificates is used */ - const char *var_user_name; /* which SSL variable to use as user name */ - - apr_array_header_t *certified_keys; /* rustls_certified_key list configured */ - int base_server; /* != 0 iff this is the base server */ - int service_unavailable; /* TLS not trustworthy configured, return 503s */ -} tls_conf_server_t; - -typedef struct { - server_rec *defined_in; /* the server/host defining this dir_conf */ - tls_conf_global_t *global; /* global module config, singleton */ - const char *proxy_ca; /* PEM file with trust anchors for proxied remote server certs */ - int proxy_protocol_min; /* the minimum TLS protocol version to use for proxy connections */ - apr_array_header_t *proxy_pref_ciphers; /* List of apr_uint16_t cipher ids to prefer */ - apr_array_header_t *proxy_supp_ciphers; /* List of apr_uint16_t cipher ids to suppress */ - apr_array_header_t *machine_cert_specs; /* configured machine certificates specs */ - apr_array_header_t *machine_certified_keys; /* rustls_certified_key list */ - const rustls_client_config *rustls_config; -} tls_conf_proxy_t; - -typedef struct { - int std_env_vars; - int export_cert_vars; - int proxy_enabled; /* TLS_FLAG_TRUE if mod_tls is active on outgoing connections */ - const char *proxy_ca; /* PEM file with trust anchors for proxied remote server certs */ - int proxy_protocol_min; /* the minimum TLS protocol version to use for proxy connections */ - apr_array_header_t *proxy_pref_ciphers; /* List of apr_uint16_t cipher ids to prefer */ - apr_array_header_t *proxy_supp_ciphers; /* List of apr_uint16_t cipher ids to suppress */ - apr_array_header_t *proxy_machine_cert_specs; /* configured machine certificates specs */ - - tls_conf_proxy_t *proxy_config; -} tls_conf_dir_t; - -/* our static registry of configuration directives. */ -extern const command_rec tls_conf_cmds[]; - -/* create the modules configuration for a server_rec. */ -void *tls_conf_create_svr(apr_pool_t *pool, server_rec *s); - -/* merge (inherit) server configurations for the module. - * Settings in 'add' overwrite the ones in 'base' and unspecified - * settings shine through. */ -void *tls_conf_merge_svr(apr_pool_t *pool, void *basev, void *addv); - -/* create the modules configuration for a directory. */ -void *tls_conf_create_dir(apr_pool_t *pool, char *dir); - -/* merge (inherit) directory configurations for the module. - * Settings in 'add' overwrite the ones in 'base' and unspecified - * settings shine through. */ -void *tls_conf_merge_dir(apr_pool_t *pool, void *basev, void *addv); - - -/* Get the server specific module configuration. */ -tls_conf_server_t *tls_conf_server_get(server_rec *s); - -/* Get the directory specific module configuration for the request. */ -tls_conf_dir_t *tls_conf_dir_get(request_rec *r); - -/* Get the directory specific module configuration for the server. */ -tls_conf_dir_t *tls_conf_dir_server_get(server_rec *s); - -/* If any configuration values are unset, supply the global server defaults. */ -apr_status_t tls_conf_server_apply_defaults(tls_conf_server_t *sc, apr_pool_t *p); - -/* If any configuration values are unset, supply the global dir defaults. */ -apr_status_t tls_conf_dir_apply_defaults(tls_conf_dir_t *dc, apr_pool_t *p); - -/* create a new proxy configuration from directory config in server */ -tls_conf_proxy_t *tls_conf_proxy_make( - apr_pool_t *p, tls_conf_dir_t *dc, tls_conf_global_t *gc, server_rec *s); - -int tls_proxy_section_post_config( - apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s, - ap_conf_vector_t *section_config); - -#endif /* tls_conf_h */ diff --git a/modules/tls/tls_core.c b/modules/tls/tls_core.c deleted file mode 100644 index 1cef254f10..0000000000 --- a/modules/tls/tls_core.c +++ /dev/null @@ -1,1439 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "tls_proto.h" -#include "tls_cert.h" -#include "tls_conf.h" -#include "tls_core.h" -#include "tls_ocsp.h" -#include "tls_util.h" -#include "tls_cache.h" -#include "tls_var.h" - - -extern module AP_MODULE_DECLARE_DATA tls_module; -APLOG_USE_MODULE(tls); - -tls_conf_conn_t *tls_conf_conn_get(conn_rec *c) -{ - return ap_get_module_config(c->conn_config, &tls_module); -} - -void tls_conf_conn_set(conn_rec *c, tls_conf_conn_t *cc) -{ - ap_set_module_config(c->conn_config, &tls_module, cc); -} - -int tls_conn_check_ssl(conn_rec *c) -{ - tls_conf_conn_t *cc = tls_conf_conn_get(c->master? c->master : c); - if (TLS_CONN_ST_IS_ENABLED(cc)) { - return OK; - } - return DECLINED; -} - -static int we_listen_on(tls_conf_global_t *gc, server_rec *s, tls_conf_server_t *sc) -{ - server_addr_rec *sa, *la; - - if (gc->tls_addresses && sc->base_server) { - /* The base server listens to every port and may be selected via SNI */ - return 1; - } - for (la = gc->tls_addresses; la; la = la->next) { - for (sa = s->addrs; sa; sa = sa->next) { - if (la->host_port == sa->host_port - && la->host_addr->ipaddr_len == sa->host_addr->ipaddr_len - && !memcmp(la->host_addr->ipaddr_ptr, - la->host_addr->ipaddr_ptr, (size_t)la->host_addr->ipaddr_len)) { - /* exact match */ - return 1; - } - } - } - return 0; -} - -static apr_status_t tls_core_free(void *data) -{ - server_rec *base_server = (server_rec *)data; - tls_conf_server_t *sc = tls_conf_server_get(base_server); - - if (sc && sc->global && sc->global->rustls_hello_config) { - rustls_server_config_free(sc->global->rustls_hello_config); - sc->global->rustls_hello_config = NULL; - } - tls_cache_free(base_server); - return APR_SUCCESS; -} - -static apr_status_t load_certified_keys( - apr_array_header_t *keys, server_rec *s, - apr_array_header_t *cert_specs, - tls_cert_reg_t *cert_reg) -{ - apr_status_t rv = APR_SUCCESS; - const rustls_certified_key *ckey; - tls_cert_spec_t *spec; - int i; - - if (cert_specs && cert_specs->nelts > 0) { - for (i = 0; i < cert_specs->nelts; ++i) { - spec = APR_ARRAY_IDX(cert_specs, i, tls_cert_spec_t*); - rv = tls_cert_reg_get_certified_key(cert_reg, s, spec, &ckey); - if (APR_SUCCESS != rv) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(10318) - "Failed to load certificate %d[cert=%s(%d), key=%s(%d)] for %s", - i, spec->cert_file, (int)(spec->cert_pem? strlen(spec->cert_pem) : 0), - spec->pkey_file, (int)(spec->pkey_pem? strlen(spec->pkey_pem) : 0), - s->server_hostname); - goto cleanup; - } - assert(ckey); - APR_ARRAY_PUSH(keys, const rustls_certified_key*) = ckey; - } - } -cleanup: - return rv; -} - -static apr_status_t use_local_key( - conn_rec *c, const char *cert_pem, const char *pkey_pem) -{ - tls_conf_conn_t *cc = tls_conf_conn_get(c); - const rustls_certified_key *ckey = NULL; - tls_cert_spec_t spec; - apr_status_t rv = APR_SUCCESS; - - memset(&spec, 0, sizeof(spec)); - spec.cert_pem = cert_pem; - spec.pkey_pem = pkey_pem; - rv = tls_cert_load_cert_key(c->pool, &spec, NULL, &ckey); - if (APR_SUCCESS != rv) goto cleanup; - - cc->local_keys = apr_array_make(c->pool, 2, sizeof(const rustls_certified_key*)); - APR_ARRAY_PUSH(cc->local_keys, const rustls_certified_key*) = ckey; - ckey = NULL; - -cleanup: - if (ckey != NULL) rustls_certified_key_free(ckey); - return rv; -} - -static void add_file_specs( - apr_array_header_t *certificates, - apr_pool_t *p, - apr_array_header_t *cert_files, - apr_array_header_t *key_files) -{ - tls_cert_spec_t *spec; - int i; - - for (i = 0; i < cert_files->nelts; ++i) { - spec = apr_pcalloc(p, sizeof(*spec)); - spec->cert_file = APR_ARRAY_IDX(cert_files, i, const char*); - spec->pkey_file = (i < key_files->nelts)? APR_ARRAY_IDX(key_files, i, const char*) : NULL; - *(const tls_cert_spec_t**)apr_array_push(certificates) = spec; - } -} - -static apr_status_t calc_ciphers( - apr_pool_t *pool, - server_rec *s, - tls_conf_global_t *gc, - const char *proxy, - apr_array_header_t *pref_ciphers, - apr_array_header_t *supp_ciphers, - const apr_array_header_t **pciphers) -{ - apr_array_header_t *ordered_ciphers; - const apr_array_header_t *ciphers; - apr_array_header_t *unsupported = NULL; - rustls_result rr = RUSTLS_RESULT_OK; - apr_status_t rv = APR_SUCCESS; - apr_uint16_t id; - int i; - - - /* remove all suppressed ciphers from the ones supported by rustls */ - ciphers = tls_util_array_uint16_remove(pool, gc->proto->supported_cipher_ids, supp_ciphers); - ordered_ciphers = NULL; - /* if preferred ciphers are actually still present in allowed_ciphers, put - * them into `ciphers` in this order */ - for (i = 0; i < pref_ciphers->nelts; ++i) { - id = APR_ARRAY_IDX(pref_ciphers, i, apr_uint16_t); - ap_log_error(APLOG_MARK, APLOG_TRACE4, rv, s, - "checking preferred cipher %s: %d", - s->server_hostname, id); - if (tls_util_array_uint16_contains(ciphers, id)) { - ap_log_error(APLOG_MARK, APLOG_TRACE4, rv, s, - "checking preferred cipher %s: %d is known", - s->server_hostname, id); - if (ordered_ciphers == NULL) { - ordered_ciphers = apr_array_make(pool, ciphers->nelts, sizeof(apr_uint16_t)); - } - APR_ARRAY_PUSH(ordered_ciphers, apr_uint16_t) = id; - } - else if (!tls_proto_is_cipher_supported(gc->proto, id)) { - ap_log_error(APLOG_MARK, APLOG_TRACE4, rv, s, - "checking preferred cipher %s: %d is unsupported", - s->server_hostname, id); - if (!unsupported) unsupported = apr_array_make(pool, 5, sizeof(apr_uint16_t)); - APR_ARRAY_PUSH(unsupported, apr_uint16_t) = id; - } - } - /* if we found ciphers with preference among allowed_ciphers, - * append all other allowed ciphers. */ - if (ordered_ciphers) { - for (i = 0; i < ciphers->nelts; ++i) { - id = APR_ARRAY_IDX(ciphers, i, apr_uint16_t); - if (!tls_util_array_uint16_contains(ordered_ciphers, id)) { - APR_ARRAY_PUSH(ordered_ciphers, apr_uint16_t) = id; - } - } - ciphers = ordered_ciphers; - } - - if (ciphers == gc->proto->supported_cipher_ids) { - ciphers = NULL; - } - - if (unsupported && unsupported->nelts) { - ap_log_error(APLOG_MARK, APLOG_WARNING, rv, s, APLOGNO(10319) - "Server '%s' has TLS%sCiphersPrefer configured that are not " - "supported by rustls. These will not have an effect: %s", - s->server_hostname, proxy, - tls_proto_get_cipher_names(gc->proto, unsupported, pool)); - } - - if (RUSTLS_RESULT_OK != rr) { - const char *err_descr; - rv = tls_util_rustls_error(pool, rr, &err_descr); - ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(10320) - "Failed to configure ciphers %s: [%d] %s", - s->server_hostname, (int)rr, err_descr); - } - *pciphers = (APR_SUCCESS == rv)? ciphers : NULL; - return rv; -} - -static apr_status_t get_server_ciphersuites( - const apr_array_header_t **pciphersuites, - apr_pool_t *pool, tls_conf_server_t *sc) -{ - const apr_array_header_t *ciphers, *suites = NULL; - apr_status_t rv = APR_SUCCESS; - - rv = calc_ciphers(pool, sc->server, sc->global, - "", sc->tls_pref_ciphers, sc->tls_supp_ciphers, - &ciphers); - if (APR_SUCCESS != rv) goto cleanup; - - if (ciphers) { - suites = tls_proto_get_rustls_suites( - sc->global->proto, ciphers, pool); - if (APLOGtrace2(sc->server)) { - tls_proto_conf_t *conf = sc->global->proto; - ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, sc->server, - "tls ciphers configured[%s]: %s", - sc->server->server_hostname, - tls_proto_get_cipher_names(conf, ciphers, pool)); - } - } - -cleanup: - *pciphersuites = (APR_SUCCESS == rv)? suites : NULL; - return rv; -} - -static apr_array_header_t *complete_cert_specs( - apr_pool_t *p, tls_conf_server_t *sc) -{ - apr_array_header_t *cert_adds, *key_adds, *specs; - - /* Take the configured certificate specifications and ask - * around for other modules to add specifications to this server. - * This is the way mod_md provides certificates. - * - * If the server then still has no cert specifications, ask - * around for `fallback` certificates which are commonly self-signed, - * temporary ones which let the server startup in order to - * obtain the `real` certificates from sources like ACME. - * Servers will fallbacks will answer all requests with 503. - */ - specs = apr_array_copy(p, sc->cert_specs); - cert_adds = apr_array_make(p, 2, sizeof(const char*)); - key_adds = apr_array_make(p, 2, sizeof(const char*)); - - ap_ssl_add_cert_files(sc->server, p, cert_adds, key_adds); - ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, sc->server, - "init server: complete_cert_specs added %d certs", cert_adds->nelts); - add_file_specs(specs, p, cert_adds, key_adds); - - if (apr_is_empty_array(specs)) { - ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, sc->server, - "init server: no certs configured, looking for fallback"); - ap_ssl_add_fallback_cert_files(sc->server, p, cert_adds, key_adds); - if (cert_adds->nelts > 0) { - add_file_specs(specs, p, cert_adds, key_adds); - sc->service_unavailable = 1; - ap_log_error(APLOG_MARK, APLOG_INFO, 0, sc->server, APLOGNO(10321) - "Init: %s will respond with '503 Service Unavailable' for now. There " - "are no SSL certificates configured and no other module contributed any.", - sc->server->server_hostname); - } - else if (!sc->base_server) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, sc->server, APLOGNO(10322) - "Init: %s has no certificates configured. Use 'TLSCertificate' to " - "configure a certificate and key file.", - sc->server->server_hostname); - } - } - return specs; -} - -static const rustls_certified_key *select_certified_key( - void* userdata, const rustls_client_hello *hello) -{ - conn_rec *c = userdata; - tls_conf_conn_t *cc; - tls_conf_server_t *sc; - apr_array_header_t *keys; - const rustls_certified_key *clone; - rustls_result rr = RUSTLS_RESULT_OK; - apr_status_t rv; - - ap_assert(c); - cc = tls_conf_conn_get(c); - ap_assert(cc); - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, "client hello select certified key"); - if (!cc || !cc->server) goto cleanup; - sc = tls_conf_server_get(cc->server); - if (!sc) goto cleanup; - - cc->key = NULL; - cc->key_cloned = 0; - if (cc->local_keys && cc->local_keys->nelts > 0) { - keys = cc->local_keys; - } - else { - keys = sc->certified_keys; - } - if (!keys || keys->nelts <= 0) goto cleanup; - - rr = rustls_client_hello_select_certified_key(hello, - (const rustls_certified_key**)keys->elts, (size_t)keys->nelts, &cc->key); - if (RUSTLS_RESULT_OK != rr) goto cleanup; - - if (APR_SUCCESS == tls_ocsp_update_key(c, cc->key, &clone)) { - /* got OCSP response data for it, meaning the key was cloned and we need to remember */ - cc->key_cloned = 1; - cc->key = clone; - } - if (APLOGctrace2(c)) { - const char *key_id = tls_cert_reg_get_id(sc->global->cert_reg, cc->key); - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, APLOGNO(10323) - "client hello selected key: %s", key_id? key_id : "unknown"); - } - return cc->key; - -cleanup: - if (RUSTLS_RESULT_OK != rr) { - const char *err_descr; - rv = tls_util_rustls_error(c->pool, rr, &err_descr); - ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, c, APLOGNO(10324) - "Failed to select certified key: [%d] %s", (int)rr, err_descr); - } - return NULL; -} - -static apr_status_t server_conf_setup( - apr_pool_t *p, apr_pool_t *ptemp, tls_conf_server_t *sc, tls_conf_global_t *gc) -{ - apr_array_header_t *cert_specs; - apr_status_t rv = APR_SUCCESS; - - /* TODO: most code has been stripped here with the changes in rustls-ffi v0.8.0 - * and this means that any errors are only happening at connection setup, which - * is too late. - */ - (void)p; - ap_log_error(APLOG_MARK, APLOG_TRACE1, rv, sc->server, - "init server: %s", sc->server->server_hostname); - - if (sc->client_auth != TLS_CLIENT_AUTH_NONE && !sc->client_ca) { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, sc->server, APLOGNO(10325) - "TLSClientAuthentication is enabled for %s, but no client CA file is set. " - "Use 'TLSClientCA ' to specify the trust anchors.", - sc->server->server_hostname); - rv = APR_EINVAL; goto cleanup; - } - - cert_specs = complete_cert_specs(ptemp, sc); - sc->certified_keys = apr_array_make(p, 3, sizeof(rustls_certified_key *)); - rv = load_certified_keys(sc->certified_keys, sc->server, cert_specs, gc->cert_reg); - if (APR_SUCCESS != rv) goto cleanup; - - rv = get_server_ciphersuites(&sc->ciphersuites, p, sc); - if (APR_SUCCESS != rv) goto cleanup; - - ap_log_error(APLOG_MARK, APLOG_TRACE1, rv, sc->server, - "init server: %s with %d certificates loaded", - sc->server->server_hostname, sc->certified_keys->nelts); -cleanup: - return rv; -} - -static apr_status_t get_proxy_ciphers(const apr_array_header_t **pciphersuites, - apr_pool_t *pool, tls_conf_proxy_t *pc) -{ - const apr_array_header_t *ciphers, *suites = NULL; - apr_status_t rv = APR_SUCCESS; - - rv = calc_ciphers(pool, pc->defined_in, pc->global, - "", pc->proxy_pref_ciphers, pc->proxy_supp_ciphers, &ciphers); - if (APR_SUCCESS != rv) goto cleanup; - - if (ciphers) { - suites = tls_proto_get_rustls_suites(pc->global->proto, ciphers, pool); - /* this changed the default rustls ciphers, configure it. */ - if (APLOGtrace2(pc->defined_in)) { - tls_proto_conf_t *conf = pc->global->proto; - ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, pc->defined_in, - "tls proxy ciphers configured[%s]: %s", - pc->defined_in->server_hostname, - tls_proto_get_cipher_names(conf, ciphers, pool)); - } - } - -cleanup: - *pciphersuites = (APR_SUCCESS == rv)? suites : NULL; - return rv; -} - -static apr_status_t proxy_conf_setup( - apr_pool_t *p, apr_pool_t *ptemp, tls_conf_proxy_t *pc, tls_conf_global_t *gc) -{ - apr_status_t rv = APR_SUCCESS; - - (void)p; (void)ptemp; - ap_assert(pc->defined_in); - pc->global = gc; - - if (pc->proxy_ca && strcasecmp(pc->proxy_ca, "default")) { - ap_log_error(APLOG_MARK, APLOG_TRACE2, rv, pc->defined_in, - "proxy: will use roots in %s from %s", - pc->defined_in->server_hostname, pc->proxy_ca); - } - else { - ap_log_error(APLOG_MARK, APLOG_WARNING, rv, pc->defined_in, - "proxy: there is no TLSProxyCA configured in %s which means " - "the certificates of remote servers contacted from here will not be trusted.", - pc->defined_in->server_hostname); - } - - if (pc->proxy_protocol_min > 0) { - apr_array_header_t *tls_versions; - - ap_log_error(APLOG_MARK, APLOG_TRACE1, rv, pc->defined_in, - "init server: set proxy protocol min version %04x", pc->proxy_protocol_min); - tls_versions = tls_proto_create_versions_plus( - gc->proto, (apr_uint16_t)pc->proxy_protocol_min, ptemp); - if (tls_versions->nelts > 0) { - if (pc->proxy_protocol_min != APR_ARRAY_IDX(tls_versions, 0, apr_uint16_t)) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, pc->defined_in, APLOGNO(10326) - "Init: the minimum proxy protocol version configured for %s (%04x) " - "is not supported and version %04x was selected instead.", - pc->defined_in->server_hostname, pc->proxy_protocol_min, - APR_ARRAY_IDX(tls_versions, 0, apr_uint16_t)); - } - } - else { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, pc->defined_in, APLOGNO(10327) - "Unable to configure the proxy protocol version for %s: " - "neither the configured minimum version (%04x), nor any higher one is " - "available.", pc->defined_in->server_hostname, pc->proxy_protocol_min); - rv = APR_ENOTIMPL; goto cleanup; - } - } - -#if TLS_MACHINE_CERTS - rv = load_certified_keys(pc->machine_certified_keys, pc->defined_in, - pc->machine_cert_specs, gc->cert_reg); - if (APR_SUCCESS != rv) goto cleanup; -#endif - -cleanup: - return rv; -} - -static const rustls_certified_key *extract_client_hello_values( - void* userdata, const rustls_client_hello *hello) -{ - conn_rec *c = userdata; - tls_conf_conn_t *cc = tls_conf_conn_get(c); - size_t i, len; - unsigned short n; - - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, "extract client hello values"); - if (!cc) goto cleanup; - cc->client_hello_seen = 1; - if (hello->server_name.len > 0) { - cc->sni_hostname = apr_pstrndup(c->pool, hello->server_name.data, hello->server_name.len); - ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "sni detected: %s", cc->sni_hostname); - } - else { - cc->sni_hostname = NULL; - ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "no sni from client"); - } - if (APLOGctrace4(c) && hello->signature_schemes.len > 0) { - for (i = 0; i < hello->signature_schemes.len; ++i) { - n = hello->signature_schemes.data[i]; - ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, c, - "client supports signature scheme: %x", (int)n); - } - } - if ((len = rustls_slice_slice_bytes_len(hello->alpn)) > 0) { - apr_array_header_t *alpn = apr_array_make(c->pool, 5, sizeof(const char*)); - const char *protocol; - ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "ALPN: client proposes %d protocols", (int)len); - for (i = 0; i < len; ++i) { - rustls_slice_bytes rs = rustls_slice_slice_bytes_get(hello->alpn, i); - protocol = apr_pstrndup(c->pool, (const char*)rs.data, rs.len); - APR_ARRAY_PUSH(alpn, const char*) = protocol; - ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, - "ALPN: client proposes %d: `%s`", (int)i, protocol); - } - cc->alpn = alpn; - } - else { - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, "ALPN: no alpn proposed by client"); - } -cleanup: - return NULL; -} - -static apr_status_t setup_hello_config(apr_pool_t *p, server_rec *base_server, tls_conf_global_t *gc) -{ - rustls_server_config_builder *builder; - rustls_result rr = RUSTLS_RESULT_OK; - apr_status_t rv = APR_SUCCESS; - - builder = rustls_server_config_builder_new(); - if (!builder) { - rr = RUSTLS_RESULT_PANIC; goto cleanup; - } - rustls_server_config_builder_set_hello_callback(builder, extract_client_hello_values); - gc->rustls_hello_config = rustls_server_config_builder_build(builder); - if (!gc->rustls_hello_config) { - rr = RUSTLS_RESULT_PANIC; goto cleanup; - } - -cleanup: - if (RUSTLS_RESULT_OK != rr) { - const char *err_descr = NULL; - rv = tls_util_rustls_error(p, rr, &err_descr); - ap_log_error(APLOG_MARK, APLOG_ERR, rv, base_server, APLOGNO(10328) - "Failed to init generic hello config: [%d] %s", (int)rr, err_descr); - goto cleanup; - } - return rv; -} - -static apr_status_t init_incoming(apr_pool_t *p, apr_pool_t *ptemp, server_rec *base_server) -{ - tls_conf_server_t *sc = tls_conf_server_get(base_server); - tls_conf_global_t *gc = sc->global; - server_rec *s; - apr_status_t rv = APR_ENOMEM; - - ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, base_server, "tls_core_init incoming"); - apr_pool_cleanup_register(p, base_server, tls_core_free, - apr_pool_cleanup_null); - - rv = tls_proto_post_config(p, ptemp, base_server); - if (APR_SUCCESS != rv) goto cleanup; - - for (s = base_server; s; s = s->next) { - sc = tls_conf_server_get(s); - assert(sc); - ap_assert(sc->global == gc); - - /* If 'TLSEngine' has been configured, use those addresses to - * decide if we are enabled on this server. */ - sc->base_server = (s == base_server); - sc->enabled = we_listen_on(gc, s, sc)? TLS_FLAG_TRUE : TLS_FLAG_FALSE; - } - - rv = tls_cache_post_config(p, ptemp, base_server); - if (APR_SUCCESS != rv) goto cleanup; - - rv = setup_hello_config(p, base_server, gc); - if (APR_SUCCESS != rv) goto cleanup; - - /* Setup server configs and collect all certificates we use. */ - gc->cert_reg = tls_cert_reg_make(p); - gc->stores = tls_cert_root_stores_make(p); - gc->verifiers = tls_cert_verifiers_make(p, gc->stores); - for (s = base_server; s; s = s->next) { - sc = tls_conf_server_get(s); - rv = tls_conf_server_apply_defaults(sc, p); - if (APR_SUCCESS != rv) goto cleanup; - if (sc->enabled != TLS_FLAG_TRUE) continue; - rv = server_conf_setup(p, ptemp, sc, gc); - if (APR_SUCCESS != rv) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, "server setup failed: %s", - s->server_hostname); - goto cleanup; - } - } - -cleanup: - if (APR_SUCCESS != rv) { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, base_server, "error during post_config"); - } - return rv; -} - -static apr_status_t init_outgoing(apr_pool_t *p, apr_pool_t *ptemp, server_rec *base_server) -{ - tls_conf_server_t *sc = tls_conf_server_get(base_server); - tls_conf_global_t *gc = sc->global; - tls_conf_dir_t *dc; - tls_conf_proxy_t *pc; - server_rec *s; - apr_status_t rv = APR_SUCCESS; - int i; - - (void)p; (void)ptemp; - (void)gc; - ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, base_server, "tls_core_init outgoing"); - ap_assert(gc->mod_proxy_post_config_done); - /* Collect all proxy'ing default server dir configs. - * All section dir_configs should already be there - if there were any. */ - for (s = base_server; s; s = s->next) { - dc = tls_conf_dir_server_get(s); - rv = tls_conf_dir_apply_defaults(dc, p); - if (APR_SUCCESS != rv) goto cleanup; - if (dc->proxy_enabled != TLS_FLAG_TRUE) continue; - dc->proxy_config = tls_conf_proxy_make(p, dc, gc, s); - ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, s, "%s: adding proxy_conf to globals", - s->server_hostname); - APR_ARRAY_PUSH(gc->proxy_configs, tls_conf_proxy_t*) = dc->proxy_config; - } - /* Now gc->proxy_configs contains all configurations we need to possibly - * act on for outgoing connections. */ - for (i = 0; i < gc->proxy_configs->nelts; ++i) { - pc = APR_ARRAY_IDX(gc->proxy_configs, i, tls_conf_proxy_t*); - rv = proxy_conf_setup(p, ptemp, pc, gc); - if (APR_SUCCESS != rv) goto cleanup; - } - -cleanup: - return rv; -} - -apr_status_t tls_core_init(apr_pool_t *p, apr_pool_t *ptemp, server_rec *base_server) -{ - tls_conf_server_t *sc = tls_conf_server_get(base_server); - tls_conf_global_t *gc = sc->global; - apr_status_t rv = APR_SUCCESS; - - ap_assert(gc); - if (TLS_CONF_ST_INIT == gc->status) { - rv = init_incoming(p, ptemp, base_server); - if (APR_SUCCESS != rv) goto cleanup; - gc->status = TLS_CONF_ST_INCOMING_DONE; - } - if (TLS_CONF_ST_INCOMING_DONE == gc->status) { - if (!gc->mod_proxy_post_config_done) goto cleanup; - - rv = init_outgoing(p, ptemp, base_server); - if (APR_SUCCESS != rv) goto cleanup; - gc->status = TLS_CONF_ST_OUTGOING_DONE; - } - if (TLS_CONF_ST_OUTGOING_DONE == gc->status) { - /* register all loaded certificates for OCSP stapling */ - rv = tls_ocsp_prime_certs(gc, p, base_server); - if (APR_SUCCESS != rv) goto cleanup; - - if (gc->verifiers) tls_cert_verifiers_clear(gc->verifiers); - if (gc->stores) tls_cert_root_stores_clear(gc->stores); - gc->status = TLS_CONF_ST_DONE; - } -cleanup: - return rv; -} - -static apr_status_t tls_core_conn_free(void *data) -{ - tls_conf_conn_t *cc = data; - - /* free all rustls things we are owning. */ - if (cc->rustls_connection) { - rustls_connection_free(cc->rustls_connection); - cc->rustls_connection = NULL; - } - if (cc->rustls_server_config) { - rustls_server_config_free(cc->rustls_server_config); - cc->rustls_server_config = NULL; - } - if (cc->rustls_client_config) { - rustls_client_config_free(cc->rustls_client_config); - cc->rustls_client_config = NULL; - } - if (cc->key_cloned && cc->key) { - rustls_certified_key_free(cc->key); - cc->key = NULL; - } - if (cc->local_keys) { - const rustls_certified_key *key; - int i; - - for (i = 0; i < cc->local_keys->nelts; ++i) { - key = APR_ARRAY_IDX(cc->local_keys, i, const rustls_certified_key*); - rustls_certified_key_free(key); - } - apr_array_clear(cc->local_keys); - } - return APR_SUCCESS; -} - -static tls_conf_conn_t *cc_get_or_make(conn_rec *c) -{ - tls_conf_conn_t *cc = tls_conf_conn_get(c); - if (!cc) { - cc = apr_pcalloc(c->pool, sizeof(*cc)); - cc->server = c->base_server; - cc->state = TLS_CONN_ST_INIT; - tls_conf_conn_set(c, cc); - apr_pool_cleanup_register(c->pool, cc, tls_core_conn_free, - apr_pool_cleanup_null); - } - return cc; -} - -void tls_core_conn_disable(conn_rec *c) -{ - tls_conf_conn_t *cc; - cc = cc_get_or_make(c); - if (cc->state == TLS_CONN_ST_INIT) { - cc->state = TLS_CONN_ST_DISABLED; - } -} - -void tls_core_conn_bind(conn_rec *c, ap_conf_vector_t *dir_conf) -{ - tls_conf_conn_t *cc = cc_get_or_make(c); - cc->dc = dir_conf? ap_get_module_config(dir_conf, &tls_module) : NULL; -} - - -static apr_status_t init_outgoing_connection(conn_rec *c) -{ - tls_conf_conn_t *cc = tls_conf_conn_get(c); - tls_conf_proxy_t *pc; - const apr_array_header_t *ciphersuites = NULL; - apr_array_header_t *tls_versions = NULL; - rustls_web_pki_server_cert_verifier_builder *verifier_builder = NULL; - struct rustls_server_cert_verifier *verifier = NULL; - rustls_client_config_builder *builder = NULL; - const rustls_root_cert_store *ca_store = NULL; - const char *hostname = NULL, *alpn_note = NULL; - rustls_result rr = RUSTLS_RESULT_OK; - apr_status_t rv = APR_SUCCESS; - - ap_assert(cc->outgoing); - ap_assert(cc->dc); - pc = cc->dc->proxy_config; - ap_assert(pc); - - hostname = apr_table_get(c->notes, "proxy-request-hostname"); - alpn_note = apr_table_get(c->notes, "proxy-request-alpn-protos"); - ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, c->base_server, - "setup_outgoing: to %s [ALPN: %s] from configuration in %s" - " using CA %s", hostname, alpn_note, pc->defined_in->server_hostname, pc->proxy_ca); - - rv = get_proxy_ciphers(&ciphersuites, c->pool, pc); - if (APR_SUCCESS != rv) goto cleanup; - - if (pc->proxy_protocol_min > 0) { - tls_versions = tls_proto_create_versions_plus( - pc->global->proto, (apr_uint16_t)pc->proxy_protocol_min, c->pool); - } - - if (ciphersuites && ciphersuites->nelts > 0 - && tls_versions && tls_versions->nelts >= 0) { - rr = rustls_client_config_builder_new_custom( - (const struct rustls_supported_ciphersuite *const *)ciphersuites->elts, - (size_t)ciphersuites->nelts, - (const uint16_t *)tls_versions->elts, (size_t)tls_versions->nelts, - &builder); - if (RUSTLS_RESULT_OK != rr) goto cleanup; - } - else { - builder = rustls_client_config_builder_new(); - if (NULL == builder) { - rv = APR_ENOMEM; - goto cleanup; - } - } - - if (pc->proxy_ca && strcasecmp(pc->proxy_ca, "default")) { - rv = tls_cert_root_stores_get(pc->global->stores, pc->proxy_ca, &ca_store); - if (APR_SUCCESS != rv) goto cleanup; - verifier_builder = rustls_web_pki_server_cert_verifier_builder_new(ca_store); - rr = rustls_web_pki_server_cert_verifier_builder_build(verifier_builder, &verifier); - if (RUSTLS_RESULT_OK != rr) goto cleanup; - rustls_client_config_builder_set_server_verifier(builder, verifier); - } - -#if TLS_MACHINE_CERTS - if (pc->machine_certified_keys->nelts > 0) { - ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, c->base_server, - "setup_outgoing: adding %d client certificate", (int)pc->machine_certified_keys->nelts); - rr = rustls_client_config_builder_set_certified_key( - builder, (const rustls_certified_key**)pc->machine_certified_keys->elts, - (size_t)pc->machine_certified_keys->nelts); - if (RUSTLS_RESULT_OK != rr) goto cleanup; - } -#endif - - if (hostname) { - rustls_client_config_builder_set_enable_sni(builder, true); - } - else { - hostname = "unknown.proxy.local"; - rustls_client_config_builder_set_enable_sni(builder, false); - } - - if (alpn_note) { - apr_array_header_t *alpn_proposed = NULL; - char *p, *last; - apr_size_t len; - - alpn_proposed = apr_array_make(c->pool, 3, sizeof(const char*)); - p = apr_pstrdup(c->pool, alpn_note); - while ((p = apr_strtok(p, ", ", &last))) { - len = (apr_size_t)(last - p - (*last? 1 : 0)); - if (len > 255) { - ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(10329) - "ALPN proxy protocol identifier too long: %s", p); - rv = APR_EGENERAL; - goto cleanup; - } - APR_ARRAY_PUSH(alpn_proposed, const char*) = apr_pstrndup(c->pool, p, len); - p = NULL; - } - if (alpn_proposed->nelts > 0) { - apr_array_header_t *rustls_protocols; - const char* proto; - rustls_slice_bytes bytes; - int i; - - rustls_protocols = apr_array_make(c->pool, alpn_proposed->nelts, sizeof(rustls_slice_bytes)); - for (i = 0; i < alpn_proposed->nelts; ++i) { - proto = APR_ARRAY_IDX(alpn_proposed, i, const char*); - bytes.data = (const unsigned char*)proto; - bytes.len = strlen(proto); - APR_ARRAY_PUSH(rustls_protocols, rustls_slice_bytes) = bytes; - } - - rr = rustls_client_config_builder_set_alpn_protocols(builder, - (rustls_slice_bytes*)rustls_protocols->elts, (size_t)rustls_protocols->nelts); - if (RUSTLS_RESULT_OK != rr) goto cleanup; - - ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, c->base_server, - "setup_outgoing: to %s, added %d ALPN protocols from %s", - hostname, rustls_protocols->nelts, alpn_note); - } - } - - cc->rustls_client_config = rustls_client_config_builder_build(builder); - builder = NULL; - - rr = rustls_client_connection_new(cc->rustls_client_config, hostname, &cc->rustls_connection); - if (RUSTLS_RESULT_OK != rr) goto cleanup; - rustls_connection_set_userdata(cc->rustls_connection, c); - -cleanup: - if (verifier_builder != NULL) rustls_web_pki_server_cert_verifier_builder_free(verifier_builder); - if (builder != NULL) rustls_client_config_builder_free(builder); - if (RUSTLS_RESULT_OK != rr) { - const char *err_descr = NULL; - rv = tls_util_rustls_error(c->pool, rr, &err_descr); - ap_log_error(APLOG_MARK, APLOG_ERR, rv, cc->server, APLOGNO(10330) - "Failed to init pre_session for outgoing %s to %s: [%d] %s", - cc->server->server_hostname, hostname, (int)rr, err_descr); - c->aborted = 1; - cc->state = TLS_CONN_ST_DISABLED; - goto cleanup; - } - return rv; -} - -int tls_core_pre_conn_init(conn_rec *c) -{ - tls_conf_server_t *sc = tls_conf_server_get(c->base_server); - tls_conf_conn_t *cc; - - cc = cc_get_or_make(c); - if (cc->state == TLS_CONN_ST_INIT) { - /* Need to decide if we TLS this connection or not */ - int enabled = -#if AP_MODULE_MAGIC_AT_LEAST(20120211, 109) - !c->outgoing && -#endif - sc->enabled == TLS_FLAG_TRUE; - cc->state = enabled? TLS_CONN_ST_CLIENT_HELLO : TLS_CONN_ST_DISABLED; - cc->client_auth = sc->client_auth; - ap_log_error(APLOG_MARK, APLOG_TRACE3, 0, c->base_server, - "tls_core_conn_init: %s for tls: %s", - enabled? "enabled" : "disabled", c->base_server->server_hostname); - } - else if (cc->state == TLS_CONN_ST_DISABLED) { - ap_log_error(APLOG_MARK, APLOG_TRACE4, 0, c->base_server, - "tls_core_conn_init, not our connection: %s", - c->base_server->server_hostname); - goto cleanup; - } - -cleanup: - return TLS_CONN_ST_IS_ENABLED(cc)? OK : DECLINED; -} - -apr_status_t tls_core_conn_init(conn_rec *c) -{ - tls_conf_server_t *sc = tls_conf_server_get(c->base_server); - tls_conf_conn_t *cc; - rustls_result rr = RUSTLS_RESULT_OK; - apr_status_t rv = APR_SUCCESS; - - cc = tls_conf_conn_get(c); - if (cc && TLS_CONN_ST_IS_ENABLED(cc) && !cc->rustls_connection) { - if (cc->outgoing) { - rv = init_outgoing_connection(c); - if (APR_SUCCESS != rv) goto cleanup; - } - else { - /* Use a generic rustls_connection with its defaults, which we feed - * the first TLS bytes from the client. Its Hello message will trigger - * our callback where we can inspect the (possibly) supplied SNI and - * select another server. - */ - rr = rustls_server_connection_new(sc->global->rustls_hello_config, &cc->rustls_connection); - if (RUSTLS_RESULT_OK != rr) goto cleanup; - /* we might refuse requests on this connection, e.g. ACME challenge */ - cc->service_unavailable = sc->service_unavailable; - } - rustls_connection_set_userdata(cc->rustls_connection, c); - } - -cleanup: - if (RUSTLS_RESULT_OK != rr) { - const char *err_descr = NULL; - rv = tls_util_rustls_error(c->pool, rr, &err_descr); - ap_log_error(APLOG_MARK, APLOG_ERR, rv, sc->server, APLOGNO(10331) - "Failed to init TLS connection for server %s: [%d] %s", - sc->server->server_hostname, (int)rr, err_descr); - c->aborted = 1; - cc->state = TLS_CONN_ST_DISABLED; - goto cleanup; - } - return rv; -} - -static int find_vhost(void *sni_hostname, conn_rec *c, server_rec *s) -{ - if (tls_util_name_matches_server(sni_hostname, s)) { - tls_conf_conn_t *cc = tls_conf_conn_get(c); - cc->server = s; - return 1; - } - return 0; -} - -static apr_status_t select_application_protocol( - conn_rec *c, server_rec *s, rustls_server_config_builder *builder) -{ - tls_conf_conn_t *cc = tls_conf_conn_get(c); - const char *proposed; - rustls_result rr = RUSTLS_RESULT_OK; - apr_status_t rv = APR_SUCCESS; - - /* The server always has a protocol it uses, normally "http/1.1". - * if the client, via ALPN, proposes protocols, they are in - * order of preference. - * We propose those to modules registered in the server and - * get the protocol back that someone is willing to run on this - * connection. - * If this is different from what the connection already does, - * we tell the server (and all protocol modules) to switch. - * If successful, we announce that protocol back to the client as - * our only ALPN protocol and then do the 'real' handshake. - */ - cc->application_protocol = ap_get_protocol(c); - if (cc->alpn && cc->alpn->nelts > 0) { - rustls_slice_bytes rsb; - - proposed = ap_select_protocol(c, NULL, s, cc->alpn); - if (!proposed) { - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, rv, c, - "ALPN: no protocol selected in server"); - goto cleanup; - } - - if (strcmp(proposed, cc->application_protocol)) { - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, rv, c, - "ALPN: switching protocol from `%s` to `%s`", cc->application_protocol, proposed); - rv = ap_switch_protocol(c, NULL, cc->server, proposed); - if (APR_SUCCESS != rv) goto cleanup; - } - - rsb.data = (const unsigned char*)proposed; - rsb.len = strlen(proposed); - rr = rustls_server_config_builder_set_alpn_protocols(builder, &rsb, 1); - if (RUSTLS_RESULT_OK != rr) goto cleanup; - - cc->application_protocol = proposed; - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, rv, c, - "ALPN: using connection protocol `%s`", cc->application_protocol); - - /* protocol was switched, this could be a challenge protocol - * such as "acme-tls/1". Give handlers the opportunity to - * override the certificate for this connection. */ - if (strcmp("h2", proposed) && strcmp("http/1.1", proposed)) { - const char *cert_pem = NULL, *key_pem = NULL; - if (ap_ssl_answer_challenge(c, cc->sni_hostname, &cert_pem, &key_pem)) { - /* With ACME we can have challenge connections to a unknown domains - * that need to be answered with a special certificate and will - * otherwise not answer any requests. See RFC 8555 */ - rv = use_local_key(c, cert_pem, key_pem); - if (APR_SUCCESS != rv) goto cleanup; - - cc->service_unavailable = 1; - cc->client_auth = TLS_CLIENT_AUTH_NONE; - } - } - } - -cleanup: - if (rr != RUSTLS_RESULT_OK) { - const char *err_descr = NULL; - rv = tls_util_rustls_error(c->pool, rr, &err_descr); - ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, APLOGNO(10332) - "Failed to init session for server %s: [%d] %s", - s->server_hostname, (int)rr, err_descr); - c->aborted = 1; - goto cleanup; - } - return rv; -} - -static apr_status_t build_server_connection(rustls_connection **pconnection, - const rustls_server_config **pconfig, - conn_rec *c) -{ - tls_conf_conn_t *cc = tls_conf_conn_get(c); - tls_conf_server_t *sc; - const apr_array_header_t *tls_versions = NULL; - rustls_server_config_builder *builder = NULL; - const rustls_server_config *config = NULL; - rustls_connection *rconnection = NULL; - rustls_result rr = RUSTLS_RESULT_OK; - apr_status_t rv = APR_SUCCESS; - - sc = tls_conf_server_get(cc->server); - - if (sc->tls_protocol_min > 0) { - ap_log_error(APLOG_MARK, APLOG_TRACE1, rv, sc->server, - "init server: set protocol min version %04x", sc->tls_protocol_min); - tls_versions = tls_proto_create_versions_plus( - sc->global->proto, (apr_uint16_t)sc->tls_protocol_min, c->pool); - if (tls_versions->nelts > 0) { - if (sc->tls_protocol_min != APR_ARRAY_IDX(tls_versions, 0, apr_uint16_t)) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, sc->server, APLOGNO(10333) - "Init: the minimum protocol version configured for %s (%04x) " - "is not supported and version %04x was selected instead.", - sc->server->server_hostname, sc->tls_protocol_min, - APR_ARRAY_IDX(tls_versions, 0, apr_uint16_t)); - } - } - else { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, sc->server, APLOGNO(10334) - "Unable to configure the protocol version for %s: " - "neither the configured minimum version (%04x), nor any higher one is " - "available.", sc->server->server_hostname, sc->tls_protocol_min); - rv = APR_ENOTIMPL; goto cleanup; - } - } - else if (sc->ciphersuites && sc->ciphersuites->nelts > 0) { - /* FIXME: rustls-ffi current has not way to make a builder with ALL_PROTOCOL_VERSIONS */ - tls_versions = tls_proto_create_versions_plus(sc->global->proto, 0, c->pool); - } - - if (sc->ciphersuites && sc->ciphersuites->nelts > 0 - && tls_versions && tls_versions->nelts >= 0) { - rr = rustls_server_config_builder_new_custom( - (const struct rustls_supported_ciphersuite *const *)sc->ciphersuites->elts, - (size_t)sc->ciphersuites->nelts, - (const uint16_t *)tls_versions->elts, (size_t)tls_versions->nelts, - &builder); - if (RUSTLS_RESULT_OK != rr) goto cleanup; - } - else { - builder = rustls_server_config_builder_new(); - if (NULL == builder) { - rv = APR_ENOMEM; - goto cleanup; - } - } - - /* decide on the application protocol, this may change other - * settings like client_auth. */ - rv = select_application_protocol(c, cc->server, builder); - - if (cc->client_auth != TLS_CLIENT_AUTH_NONE) { - ap_assert(sc->client_ca); /* checked in server_setup */ - if (cc->client_auth == TLS_CLIENT_AUTH_REQUIRED) { - const rustls_client_cert_verifier *verifier; - rv = tls_cert_client_verifiers_get(sc->global->verifiers, sc->client_ca, &verifier); - if (APR_SUCCESS != rv) goto cleanup; - rustls_server_config_builder_set_client_verifier(builder, verifier); - } - else { - const rustls_client_cert_verifier *verifier; - rv = tls_cert_client_verifiers_get_optional(sc->global->verifiers, sc->client_ca, &verifier); - if (APR_SUCCESS != rv) goto cleanup; - rustls_server_config_builder_set_client_verifier(builder, verifier); - } - } - - rustls_server_config_builder_set_hello_callback(builder, select_certified_key); - - rr = rustls_server_config_builder_set_ignore_client_order( - builder, sc->honor_client_order == TLS_FLAG_FALSE); - if (RUSTLS_RESULT_OK != rr) goto cleanup; - - rv = tls_cache_init_server(builder, sc->server); - if (APR_SUCCESS != rv) goto cleanup; - - config = rustls_server_config_builder_build(builder); - builder = NULL; - if (!config) { - rv = APR_ENOMEM; goto cleanup; - } - - rr = rustls_server_connection_new(config, &rconnection); - if (RUSTLS_RESULT_OK != rr) goto cleanup; - rustls_connection_set_userdata(rconnection, c); - -cleanup: - if (rr != RUSTLS_RESULT_OK) { - const char *err_descr = NULL; - rv = tls_util_rustls_error(c->pool, rr, &err_descr); - ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, sc->server, APLOGNO(10335) - "Failed to init session for server %s: [%d] %s", - sc->server->server_hostname, (int)rr, err_descr); - } - if (APR_SUCCESS == rv) { - *pconfig = config; - *pconnection = rconnection; - ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, sc->server, - "tls_core_conn_server_init done: %s", - sc->server->server_hostname); - } - else { - ap_log_error(APLOG_MARK, APLOG_ERR, rv, sc->server, APLOGNO(10336) - "Failed to init session for server %s", - sc->server->server_hostname); - c->aborted = 1; - if (config) rustls_server_config_free(config); - if (builder) rustls_server_config_builder_free(builder); - } - return rv; -} - -apr_status_t tls_core_conn_seen_client_hello(conn_rec *c) -{ - tls_conf_conn_t *cc = tls_conf_conn_get(c); - tls_conf_server_t *sc; - apr_status_t rv = APR_SUCCESS; - int sni_match = 0; - - /* The initial rustls generic session has been fed the client hello and - * we have extracted SNI and ALPN values (so present). - * Time to select the actual server_rec and application protocol that - * will be used on this connection. */ - ap_assert(cc); - sc = tls_conf_server_get(cc->server); - if (!cc->client_hello_seen) goto cleanup; - - if (cc->sni_hostname) { - if (ap_vhost_iterate_given_conn(c, find_vhost, (void*)cc->sni_hostname)) { - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c, APLOGNO(10337) - "vhost_init: virtual host found for SNI '%s'", cc->sni_hostname); - sni_match = 1; - } - else if (tls_util_name_matches_server(cc->sni_hostname, ap_server_conf)) { - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c, APLOGNO(10338) - "vhost_init: virtual host NOT found, but base server[%s] matches SNI '%s'", - ap_server_conf->server_hostname, cc->sni_hostname); - cc->server = ap_server_conf; - sni_match = 1; - } - else if (sc->strict_sni == TLS_FLAG_FALSE) { - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c, APLOGNO(10339) - "vhost_init: no virtual host found, relaxed SNI checking enabled, SNI '%s'", - cc->sni_hostname); - } - else { - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, c, APLOGNO(10340) - "vhost_init: no virtual host, nor base server[%s] matches SNI '%s'", - c->base_server->server_hostname, cc->sni_hostname); - cc->server = sc->global->ap_server; - rv = APR_NOTFOUND; goto cleanup; - } - } - else { - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(10341) - "vhost_init: no SNI hostname provided by client"); - } - - /* reinit, we might have a new server selected */ - sc = tls_conf_server_get(cc->server); - /* on relaxed SNI matches, we do not enforce the 503 of fallback - * certificates. */ - if (!cc->service_unavailable) { - cc->service_unavailable = sni_match? sc->service_unavailable : 0; - } - - /* if found or not, cc->server will be the server we use now to do - * the real handshake and, if successful, the traffic after that. - * Free the current session and create the real one for the - * selected server. */ - if (cc->rustls_server_config) { - rustls_server_config_free(cc->rustls_server_config); - cc->rustls_server_config = NULL; - } - rustls_connection_free(cc->rustls_connection); - cc->rustls_connection = NULL; - - rv = build_server_connection(&cc->rustls_connection, &cc->rustls_server_config, c); - -cleanup: - return rv; -} - -apr_status_t tls_core_conn_post_handshake(conn_rec *c) -{ - tls_conf_conn_t *cc = tls_conf_conn_get(c); - tls_conf_server_t *sc = tls_conf_server_get(cc->server); - const rustls_supported_ciphersuite *rsuite; - const rustls_certificate *cert; - apr_status_t rv = APR_SUCCESS; - - if (rustls_connection_is_handshaking(cc->rustls_connection)) { - rv = APR_EGENERAL; - ap_log_error(APLOG_MARK, APLOG_ERR, rv, cc->server, APLOGNO(10342) - "post handshake, but rustls claims to still be handshaking: %s", - cc->server->server_hostname); - goto cleanup; - } - - cc->tls_protocol_id = rustls_connection_get_protocol_version(cc->rustls_connection); - cc->tls_protocol_name = tls_proto_get_version_name(sc->global->proto, - cc->tls_protocol_id, c->pool); - rsuite = rustls_connection_get_negotiated_ciphersuite(cc->rustls_connection); - if (!rsuite) { - rv = APR_EGENERAL; - ap_log_error(APLOG_MARK, APLOG_ERR, rv, cc->server, APLOGNO(10343) - "post handshake, but rustls does not report negotiated cipher suite: %s", - cc->server->server_hostname); - goto cleanup; - } - cc->tls_cipher_id = rustls_supported_ciphersuite_get_suite(rsuite); - cc->tls_cipher_name = tls_proto_get_cipher_name(sc->global->proto, - cc->tls_cipher_id, c->pool); - ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, c, "post_handshake %s: %s [%s]", - cc->server->server_hostname, cc->tls_protocol_name, cc->tls_cipher_name); - - cert = rustls_connection_get_peer_certificate(cc->rustls_connection, 0); - if (cert) { - size_t i = 0; - - cc->peer_certs = apr_array_make(c->pool, 5, sizeof(const rustls_certificate*)); - while (cert) { - APR_ARRAY_PUSH(cc->peer_certs, const rustls_certificate*) = cert; - cert = rustls_connection_get_peer_certificate(cc->rustls_connection, ++i); - } - } - if (!cc->peer_certs && sc->client_auth == TLS_CLIENT_AUTH_REQUIRED) { - ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, c, APLOGNO(10344) - "A client certificate is required, but no acceptable certificate was presented."); - rv = APR_ECONNABORTED; - } - - rv = tls_var_handshake_done(c); -cleanup: - return rv; -} - -/** - * Return != 0, if a connection also serve requests for server . - */ -static int tls_conn_compatible_for(tls_conf_conn_t *cc, server_rec *other) -{ - tls_conf_server_t *oc, *sc; - const rustls_certified_key *sk, *ok; - int i; - - /* - differences in certificates are the responsibility of the client. - * if it thinks the SNI server works for r->server, we are fine with that. - * - if there are differences in requirements to client certificates, we - * need to deny the request. - */ - if (!cc->server || !other) return 0; - if (cc->server == other) return 1; - oc = tls_conf_server_get(other); - if (!oc) return 0; - sc = tls_conf_server_get(cc->server); - if (!sc) return 0; - - /* same certified keys used? */ - if (sc->certified_keys->nelts != oc->certified_keys->nelts) return 0; - for (i = 0; i < sc->certified_keys->nelts; ++i) { - sk = APR_ARRAY_IDX(sc->certified_keys, i, const rustls_certified_key*); - ok = APR_ARRAY_IDX(oc->certified_keys, i, const rustls_certified_key*); - if (sk != ok) return 0; - } - - /* If the connection TLS version is below other other min one, no */ - if (oc->tls_protocol_min > 0 && cc->tls_protocol_id < oc->tls_protocol_min) return 0; - /* If the connection TLS cipher is listed as suppressed by other, no */ - if (oc->tls_supp_ciphers && tls_util_array_uint16_contains( - oc->tls_supp_ciphers, cc->tls_cipher_id)) return 0; - return 1; -} - -int tls_core_request_check(request_rec *r) -{ - conn_rec *c = r->connection; - tls_conf_conn_t *cc = tls_conf_conn_get(c->master? c->master : c); - int rv = DECLINED; /* do not object to the request */ - - /* If we are not enabled on this connection, leave. We are not renegotiating. - * Otherwise: - * - service is unavailable when we have only a fallback certificate or - * when a challenge protocol is active (ACME tls-alpn-01 for example). - * - with vhosts configured and no SNI from the client, deny access. - * - are servers compatible for connection sharing? - */ - if (!TLS_CONN_ST_IS_ENABLED(cc)) goto cleanup; - - ap_log_rerror(APLOG_MARK, APLOG_TRACE3, 0, r, - "tls_core_request_check[%s, %d]: %s", r->hostname, - cc? cc->service_unavailable : 2, r->the_request); - if (cc->service_unavailable) { - rv = HTTP_SERVICE_UNAVAILABLE; goto cleanup; - } - if (!cc->sni_hostname && r->connection->vhost_lookup_data) { - rv = HTTP_FORBIDDEN; goto cleanup; - } - if (!tls_conn_compatible_for(cc, r->server)) { - rv = HTTP_MISDIRECTED_REQUEST; - ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(10345) - "Connection host %s, selected via SNI, and request host %s" - " have incompatible TLS configurations.", - cc->server->server_hostname, r->hostname); - goto cleanup; - } -cleanup: - return rv; -} - -apr_status_t tls_core_error(conn_rec *c, rustls_result rr, const char **perrstr) -{ - tls_conf_conn_t *cc = tls_conf_conn_get(c); - apr_status_t rv; - - rv = tls_util_rustls_error(c->pool, rr, perrstr); - if (cc) { - cc->last_error = rr; - cc->last_error_descr = *perrstr; - } - return rv; -} - -int tls_core_setup_outgoing(conn_rec *c) -{ - tls_conf_conn_t *cc; - int rv = DECLINED; - - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, - "tls_core_setup_outgoing called"); -#if AP_MODULE_MAGIC_AT_LEAST(20120211, 109) - if (!c->outgoing) goto cleanup; -#endif - cc = cc_get_or_make(c); - if (cc->state == TLS_CONN_ST_DISABLED) { - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, - "tls_core_setup_outgoing: already disabled"); - goto cleanup; - } - if (TLS_CONN_ST_IS_ENABLED(cc)) { - /* we already handle it, allow repeated calls */ - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, - "tls_core_setup_outgoing: already enabled"); - rv = OK; goto cleanup; - } - cc->outgoing = 1; - if (!cc->dc) { - /* In case there is not dir_conf bound for this connection, we fallback - * to the defaults in the base server (we have no virtual host config to use) */ - cc->dc = ap_get_module_config(c->base_server->lookup_defaults, &tls_module); - } - if (cc->dc->proxy_enabled != TLS_FLAG_TRUE) { - cc->state = TLS_CONN_ST_DISABLED; - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, - "tls_core_setup_outgoing: TLSProxyEngine not configured"); - goto cleanup; - } - /* we handle this connection */ - cc->state = TLS_CONN_ST_CLIENT_HELLO; - rv = OK; - -cleanup: - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, 0, c, - "tls_core_setup_outgoing returns %s", rv == OK? "OK" : "DECLINED"); - return rv; -} diff --git a/modules/tls/tls_core.h b/modules/tls/tls_core.h deleted file mode 100644 index 6ee1713b5e..0000000000 --- a/modules/tls/tls_core.h +++ /dev/null @@ -1,184 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef tls_core_h -#define tls_core_h - -/* The module's state handling of a connection in normal chronological order, - */ -typedef enum { - TLS_CONN_ST_INIT, /* being initialized */ - TLS_CONN_ST_DISABLED, /* TLS is disabled here */ - TLS_CONN_ST_CLIENT_HELLO, /* TLS is enabled, prep handshake */ - TLS_CONN_ST_HANDSHAKE, /* TLS is enabled, handshake ongonig */ - TLS_CONN_ST_TRAFFIC, /* TLS is enabled, handshake done */ - TLS_CONN_ST_NOTIFIED, /* TLS is enabled, notification to end sent */ - TLS_CONN_ST_DONE, /* TLS is enabled, TLS has shut down */ -} tls_conn_state_t; - -#define TLS_CONN_ST_IS_ENABLED(cc) (cc && cc->state >= TLS_CONN_ST_CLIENT_HELLO) - -struct tls_filter_ctx_t; - -/* The modules configuration for a connection. Created at connection - * start and mutable during the lifetime of the connection. - * (A conn_rec is only ever processed by one thread at a time.) - */ -typedef struct { - server_rec *server; /* the server_rec selected for this connection, - * initially c->base_server, to be negotiated via SNI. */ - tls_conf_dir_t *dc; /* directory config applying here */ - tls_conn_state_t state; - int outgoing; /* != 0 iff outgoing connection (redundant once c->outgoing is everywhere) */ - int service_unavailable; /* we 503 all requests on this connection */ - tls_client_auth_t client_auth; /* how client authentication with certificates is used */ - int client_hello_seen; /* the client hello has been inspected */ - - rustls_connection *rustls_connection; /* the session used on this connection or NULL */ - const rustls_server_config *rustls_server_config; /* the config made for this connection (incoming) or NULL */ - const rustls_client_config *rustls_client_config; /* the config made for this connection (outgoing) or NULL */ - struct tls_filter_ctx_t *filter_ctx; /* the context used by this connection's tls filters */ - - apr_array_header_t *local_keys; /* rustls_certified_key* array of connection specific keys */ - const rustls_certified_key *key; /* the key selected for the session */ - int key_cloned; /* != 0 iff the key is a unique clone, to be freed */ - apr_array_header_t *peer_certs; /* handshaked peer ceritificates or NULL */ - const char *sni_hostname; /* the SNI value from the client hello, or NULL */ - const apr_array_header_t *alpn; /* the protocols proposed via ALPN by the client */ - const char *application_protocol; /* the ALPN selected protocol or NULL */ - - int session_id_cache_hit; /* if a submitted session id was found in our cache */ - - apr_uint16_t tls_protocol_id; /* the TLS version negotiated */ - const char *tls_protocol_name; /* the name of the TLS version negotiated */ - apr_uint16_t tls_cipher_id; /* the TLS cipher suite negotiated */ - const char *tls_cipher_name; /* the name of TLS cipher suite negotiated */ - - const char *user_name; /* != NULL if we derived a TLSUserName from the client_cert */ - apr_table_t *subprocess_env; /* common TLS variables for this connection */ - - rustls_result last_error; - const char *last_error_descr; - -} tls_conf_conn_t; - -/* Get the connection specific module configuration. */ -tls_conf_conn_t *tls_conf_conn_get(conn_rec *c); - -/* Set the module configuration for a connection. */ -void tls_conf_conn_set(conn_rec *c, tls_conf_conn_t *cc); - -/* Return OK iff this connection is a TSL connection (or a secondary on a TLS connection). */ -int tls_conn_check_ssl(conn_rec *c); - -/** - * Initialize the module's global and server specific settings. This runs - * in Apache's "post-config" phase, meaning the configuration has been read - * and checked for syntactic and other easily verifiable errors and now - * it is time to load everything in and make it ready for traffic. - *

    a memory pool staying with us the whole time until the server stops/reloads. - * a temporary pool as a scratch buffer that will be destroyed shortly after. - * the server for the global configuration which links -> next to - * all contained virtual hosts configured. - */ -apr_status_t tls_core_init(apr_pool_t *p, apr_pool_t *ptemp, server_rec *base_server); - -/** - * Initialize the module's outgoing connection settings. This runs - * in Apache's "post-config" phase after mod_proxy. - */ -apr_status_t tls_core_init_outgoing(apr_pool_t *p, apr_pool_t *ptemp, server_rec *base_server); - -/** - * Supply a directory configuration for the connection to work with. This - * maybe NULL. This can be called several times during the lifetime of a - * connection and must not change the current TLS state. - * @param c the connection - * @param dir_conf optional directory configuration that applies - */ -void tls_core_conn_bind(conn_rec *c, ap_conf_vector_t *dir_conf); - -/** - * Disable TLS on a new connection. Will do nothing on already initialized - * connections. - * @param c a new connection - */ -void tls_core_conn_disable(conn_rec *c); - -/** - * Initialize the tls_conf_connt_t for the connection - * and decide if TLS is enabled or not. - * @return OK if enabled, DECLINED otherwise - */ -int tls_core_pre_conn_init(conn_rec *c); - -/** - * Initialize the module for a TLS enabled connection. - * @param c a new connection - */ -apr_status_t tls_core_conn_init(conn_rec *c); - -/** - * Called when the ClientHello has been received and values from it - * have been extracted into the `tls_conf_conn_t` of the connection. - * - * Decides: - * - which `server_rec` this connection is for (SNI) - * - which application protocol to use (ALPN) - * This may be unsuccessful for several reasons. The SNI - * from the client may not be known or the selected server - * has not certificates available. etc. - * On success, a proper `rustls_connection` will have been - * created and set in the `tls_conf_conn_t` of the connection. - */ -apr_status_t tls_core_conn_seen_client_hello(conn_rec *c); - -/** - * The TLS handshake for the connection has been successfully performed. - * This means that TLS related properties, such as TLS version and cipher, - * are known and the props in `tls_conf_conn_t` of the connection - * can be set. - */ -apr_status_t tls_core_conn_post_handshake(conn_rec *c); - -/** - * After a request has been read, but before processing is started, we - * check if everything looks good to us: - * - was an SNI hostname provided by the client when we have vhosts to choose from? - * if not, we deny it. - * - if the SNI hostname and request host are not the same, are they - from TLS - * point of view - 'compatible' enough? For example, if one server requires - * client certificates and the other not (or with different settings), such - * a request will also be denied. - * returns DECLINED if everything is ok, otherwise an HTTP response code to - * generate an error page for. - */ -int tls_core_request_check(request_rec *r); - -/** - * A Rustls error happened while processing the connection. Look up an - * error description, determine the apr_status_t to use for it and remember - * this as the last error at tls_conf_conn_t. - */ -apr_status_t tls_core_error(conn_rec *c, rustls_result rr, const char **perrstr); - -/** - * Determine if we handle the TLS for an outgoing connection or not. - * @param c the connection - * @return OK if we handle the TLS, DECLINED otherwise. - */ -int tls_core_setup_outgoing(conn_rec *c); - -#endif /* tls_core_h */ diff --git a/modules/tls/tls_filter.c b/modules/tls/tls_filter.c deleted file mode 100644 index 0ee6be61a2..0000000000 --- a/modules/tls/tls_filter.c +++ /dev/null @@ -1,1017 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include "tls_proto.h" -#include "tls_conf.h" -#include "tls_core.h" -#include "tls_filter.h" -#include "tls_util.h" - - -extern module AP_MODULE_DECLARE_DATA tls_module; -APLOG_USE_MODULE(tls); - - -static rustls_io_result tls_read_callback( - void *userdata, unsigned char *buf, size_t n, size_t *out_n) -{ - tls_data_t *d = userdata; - size_t len = d->len > n? n : d->len; - memcpy(buf, d->data, len); - *out_n = len; - return 0; -} - -/** - * Provide TLS encrypted data to the rustls server_session in cc->rustls_connection>. - * - * If fin_tls_bb> holds data, take it from there. Otherwise perform a - * read via the network filters below us into that brigade. - * - * fin_block> determines if we do a blocking read inititally or not. - * If the first read did to not produce enough data, any secondary read is done - * non-blocking. - * - * Had any data been added to cc->rustls_connection>, call its "processing" - * function to handle the added data before leaving. - */ -static apr_status_t read_tls_to_rustls( - tls_filter_ctx_t *fctx, apr_size_t len, apr_read_type_e block, int errors_expected) -{ - tls_data_t d; - apr_size_t rlen; - apr_off_t passed = 0; - rustls_result rr = RUSTLS_RESULT_OK; - int os_err; - apr_status_t rv = APR_SUCCESS; - - if (APR_BRIGADE_EMPTY(fctx->fin_tls_bb)) { - ap_log_error(APLOG_MARK, APLOG_TRACE2, rv, fctx->cc->server, - "read_tls_to_rustls, get data from network, block=%d", block); - rv = ap_get_brigade(fctx->fin_ctx->next, fctx->fin_tls_bb, - AP_MODE_READBYTES, block, (apr_off_t)len); - if (APR_SUCCESS != rv) { - goto cleanup; - } - } - - while (!APR_BRIGADE_EMPTY(fctx->fin_tls_bb) && passed < (apr_off_t)len) { - apr_bucket *b = APR_BRIGADE_FIRST(fctx->fin_tls_bb); - - if (APR_BUCKET_IS_EOS(b)) { - ap_log_error(APLOG_MARK, APLOG_TRACE2, rv, fctx->cc->server, - "read_tls_to_rustls, EOS"); - if (fctx->fin_tls_buffer_bb) { - apr_brigade_cleanup(fctx->fin_tls_buffer_bb); - } - rv = APR_EOF; goto cleanup; - } - - rv = apr_bucket_read(b, (const char**)&d.data, &d.len, block); - if (APR_STATUS_IS_EOF(rv)) { - apr_bucket_delete(b); - continue; - } - else if (APR_SUCCESS != rv) { - goto cleanup; - } - - if (d.len > 0) { - /* got something, do not block on getting more */ - block = APR_NONBLOCK_READ; - - os_err = rustls_connection_read_tls(fctx->cc->rustls_connection, - tls_read_callback, &d, &rlen); - if (os_err) { - rv = APR_FROM_OS_ERROR(os_err); - goto cleanup; - } - - if (fctx->fin_tls_buffer_bb) { - /* we buffer for later replay on the 'real' rustls_connection */ - apr_brigade_write(fctx->fin_tls_buffer_bb, NULL, NULL, (const char*)d.data, rlen); - } - if (rlen >= d.len) { - apr_bucket_delete(b); - } - else { - b->start += (apr_off_t)rlen; - b->length -= rlen; - } - fctx->fin_bytes_in_rustls += (apr_off_t)d.len; - passed += (apr_off_t)rlen; - } - else if (d.len == 0) { - apr_bucket_delete(b); - } - } - - if (passed > 0) { - rr = rustls_connection_process_new_packets(fctx->cc->rustls_connection); - if (rr != RUSTLS_RESULT_OK) goto cleanup; - } - -cleanup: - if (rr != RUSTLS_RESULT_OK) { - rv = APR_ECONNRESET; - if (!errors_expected) { - const char *err_descr = ""; - rv = tls_core_error(fctx->c, rr, &err_descr); - ap_log_cerror(APLOG_MARK, APLOG_WARNING, rv, fctx->c, APLOGNO(10353) - "processing TLS data: [%d] %s", (int)rr, err_descr); - } - } - else if (APR_STATUS_IS_EOF(rv) && passed > 0) { - /* encountering EOF while actually having read sth is a success. */ - rv = APR_SUCCESS; - } - else if (APR_SUCCESS == rv && passed == 0 && fctx->fin_block == APR_NONBLOCK_READ) { - rv = APR_EAGAIN; - } - else { - ap_log_error(APLOG_MARK, APLOG_TRACE2, rv, fctx->cc->server, - "read_tls_to_rustls, passed %ld bytes to rustls", (long)passed); - } - return rv; -} - -static apr_status_t fout_pass_tls_to_net(tls_filter_ctx_t *fctx) -{ - apr_status_t rv = APR_SUCCESS; - - if (!APR_BRIGADE_EMPTY(fctx->fout_tls_bb)) { - rv = ap_pass_brigade(fctx->fout_ctx->next, fctx->fout_tls_bb); - if (APR_SUCCESS == rv && fctx->c->aborted) { - rv = APR_ECONNRESET; - } - fctx->fout_bytes_in_tls_bb = 0; - apr_brigade_cleanup(fctx->fout_tls_bb); - } - return rv; -} - -static apr_status_t fout_pass_all_to_net( - tls_filter_ctx_t *fctx, int flush); - -static apr_status_t filter_abort( - tls_filter_ctx_t *fctx) -{ - apr_status_t rv; - - if (fctx->cc->state != TLS_CONN_ST_DONE) { - if (fctx->cc->state > TLS_CONN_ST_CLIENT_HELLO) { - rustls_connection_send_close_notify(fctx->cc->rustls_connection); - rv = fout_pass_all_to_net(fctx, 1); - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, rv, fctx->c, "filter_abort, flushed output"); - } - fctx->c->aborted = 1; - fctx->cc->state = TLS_CONN_ST_DONE; - } - return APR_ECONNABORTED; -} - -static apr_status_t filter_recv_client_hello(tls_filter_ctx_t *fctx) -{ - apr_status_t rv = APR_SUCCESS; - - ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, fctx->cc->server, - "tls_filter, server=%s, recv client hello", fctx->cc->server->server_hostname); - /* only for incoming connections */ - ap_assert(!fctx->cc->outgoing); - - if (rustls_connection_is_handshaking(fctx->cc->rustls_connection)) { - apr_bucket_brigade *bb_tmp; - - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, rv, fctx->c, "filter_recv_client_hello: start"); - fctx->fin_tls_buffer_bb = apr_brigade_create(fctx->c->pool, fctx->c->bucket_alloc); - do { - if (rustls_connection_wants_read(fctx->cc->rustls_connection)) { - rv = read_tls_to_rustls(fctx, fctx->fin_max_in_rustls, APR_BLOCK_READ, 1); - if (APR_SUCCESS != rv) { - if (fctx->cc->client_hello_seen) { - rv = APR_EAGAIN; /* we got what we needed */ - break; - } - /* Something went wrong before we saw the client hello. - * This is a real error on which we should not continue. */ - goto cleanup; - } - } - /* Notice: we never write here to the client. We just want to inspect - * the client hello. */ - } while (!fctx->cc->client_hello_seen); - - /* We have seen the client hello and selected the server (vhost) to use - * on this connection. Set up the 'real' rustls_connection based on the - * servers 'real' rustls_config. */ - rv = tls_core_conn_seen_client_hello(fctx->c); - if (APR_SUCCESS != rv) goto cleanup; - - bb_tmp = fctx->fin_tls_bb; /* data we have yet to feed to rustls */ - fctx->fin_tls_bb = fctx->fin_tls_buffer_bb; /* data we already fed to the pre_session */ - fctx->fin_tls_buffer_bb = NULL; - APR_BRIGADE_CONCAT(fctx->fin_tls_bb, bb_tmp); /* all tls data from the client so far, reloaded */ - apr_brigade_destroy(bb_tmp); - rv = APR_SUCCESS; - } - -cleanup: - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, rv, fctx->c, "filter_recv_client_hello: done"); - return rv; -} - -static apr_status_t filter_send_client_hello(tls_filter_ctx_t *fctx) -{ - apr_status_t rv = APR_SUCCESS; - - ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, fctx->cc->server, - "tls_filter, server=%s, send client hello", fctx->cc->server->server_hostname); - /* Only for outgoing connections */ - ap_assert(fctx->cc->outgoing); - if (rustls_connection_is_handshaking(fctx->cc->rustls_connection)) { - while (rustls_connection_wants_write(fctx->cc->rustls_connection)) { - /* write flushed, so it really gets out */ - rv = fout_pass_all_to_net(fctx, 1); - if (APR_SUCCESS != rv) goto cleanup; - } - } - -cleanup: - return rv; -} - -/** - * While cc->rustls_connection> indicates that a handshake is ongoing, - * write TLS data from and read network TLS data to the server session. - * - * @return APR_SUCCESS when the handshake is completed - */ -static apr_status_t filter_do_handshake( - tls_filter_ctx_t *fctx) -{ - apr_status_t rv = APR_SUCCESS; - - ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, fctx->cc->server, - "tls_filter, server=%s, do handshake", fctx->cc->server->server_hostname); - if (rustls_connection_is_handshaking(fctx->cc->rustls_connection)) { - do { - if (rustls_connection_wants_write(fctx->cc->rustls_connection)) { - rv = fout_pass_all_to_net(fctx, 1); - if (APR_SUCCESS != rv) goto cleanup; - } - else if (rustls_connection_wants_read(fctx->cc->rustls_connection)) { - rv = read_tls_to_rustls(fctx, fctx->fin_max_in_rustls, APR_BLOCK_READ, 0); - if (APR_SUCCESS != rv) goto cleanup; - } - } - while (rustls_connection_is_handshaking(fctx->cc->rustls_connection)); - - /* rustls reports the TLS handshake to be done, when it *internally* has - * processed everything into its buffers. Not when the buffers have been - * send to the other side. */ - if (rustls_connection_wants_write(fctx->cc->rustls_connection)) { - rv = fout_pass_all_to_net(fctx, 1); - if (APR_SUCCESS != rv) goto cleanup; - } - } -cleanup: - ap_log_error(APLOG_MARK, APLOG_TRACE2, rv, fctx->cc->server, - "tls_filter, server=%s, handshake done", fctx->cc->server->server_hostname); - if (APR_SUCCESS != rv) { - if (fctx->cc->last_error_descr) { - ap_log_cerror(APLOG_MARK, APLOG_INFO, APR_ECONNABORTED, fctx->c, APLOGNO(10354) - "handshake failed: %s", fctx->cc->last_error_descr); - } - } - return rv; -} - -static apr_status_t progress_tls_atleast_to(tls_filter_ctx_t *fctx, tls_conn_state_t state) -{ - apr_status_t rv = APR_SUCCESS; - - /* handle termination immediately */ - if (state == TLS_CONN_ST_DONE) { - rv = APR_ECONNABORTED; - goto cleanup; - } - - if (state > TLS_CONN_ST_CLIENT_HELLO - && TLS_CONN_ST_CLIENT_HELLO == fctx->cc->state) { - rv = tls_core_conn_init(fctx->c); - if (APR_SUCCESS != rv) goto cleanup; - - if (fctx->cc->outgoing) { - rv = filter_send_client_hello(fctx); - } - else { - rv = filter_recv_client_hello(fctx); - } - if (APR_SUCCESS != rv) goto cleanup; - fctx->cc->state = TLS_CONN_ST_HANDSHAKE; - } - - if (state > TLS_CONN_ST_HANDSHAKE - && TLS_CONN_ST_HANDSHAKE== fctx->cc->state) { - rv = filter_do_handshake(fctx); - if (APR_SUCCESS != rv) goto cleanup; - rv = tls_core_conn_post_handshake(fctx->c); - if (APR_SUCCESS != rv) goto cleanup; - fctx->cc->state = TLS_CONN_ST_TRAFFIC; - } - - if (state < fctx->cc->state) { - rv = APR_ECONNABORTED; - } - -cleanup: - if (APR_SUCCESS != rv) { - filter_abort(fctx); /* does change the state itself */ - } - return rv; -} - -/** - * The connection filter converting TLS encrypted network data into plain, unencrpyted - * traffic data to be processed by filters above it in the filter chain. - * - * Unfortunately, Apache's filter infrastructure places a heavy implementation - * complexity on its input filters for the various use cases its HTTP/1.x parser - * (mainly) finds convenient: - * - * the bucket brigade to place the data into. - * one of - * - AP_MODE_READBYTES: just add up to data into - * - AP_MODE_GETLINE: make a best effort to get data up to and including a CRLF. - * it can be less, but not more t than that. - * - AP_MODE_EATCRLF: never used, we puke on it. - * - AP_MODE_SPECULATIVE: read data without consuming it. - * - AP_MODE_EXHAUSTIVE: never used, we puke on it. - * - AP_MODE_INIT: called once on a connection. needs to pass down the filter - * chain, giving every filter the change to "INIT". - * do blocking or non-blocking reads - * max amount of data to add to , seems to be 0 for GETLINE - */ -static apr_status_t filter_conn_input( - ap_filter_t *f, apr_bucket_brigade *bb, ap_input_mode_t mode, - apr_read_type_e block, apr_off_t readbytes) -{ - tls_filter_ctx_t *fctx = f->ctx; - apr_status_t rv = APR_SUCCESS; - apr_off_t passed = 0, nlen; - rustls_result rr = RUSTLS_RESULT_OK; - apr_size_t in_buf_len; - char *in_buf = NULL; - - fctx->fin_block = block; - if (f->c->aborted) { - rv = filter_abort(fctx); goto cleanup; - } - - ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, fctx->cc->server, - "tls_filter_conn_input, server=%s, mode=%d, block=%d, readbytes=%ld", - fctx->cc->server->server_hostname, mode, block, (long)readbytes); - - rv = progress_tls_atleast_to(fctx, TLS_CONN_ST_TRAFFIC); - if (APR_SUCCESS != rv) goto cleanup; /* this also leaves on APR_EAGAIN */ - - if (!fctx->cc->rustls_connection) { - return ap_get_brigade(f->next, bb, mode, block, readbytes); - } - -#if AP_MODULE_MAGIC_AT_LEAST(20200420, 1) - ap_filter_reinstate_brigade(f, fctx->fin_plain_bb, NULL); -#endif - - if (AP_MODE_INIT == mode) { - /* INIT is used to trigger the handshake, it does not return any traffic data. */ - goto cleanup; - } - - /* If we have nothing buffered, try getting more input. - * a) ask rustls_connection for decrypted data, if it has any. - * Note that only full records can be decrypted. We might have - * written TLS data to the session, but that does not mean it - * can give unencryted data out again. - * b) read TLS bytes from the network and feed them to the rustls session. - * c) go back to a) if b) added data. - */ - while (APR_BRIGADE_EMPTY(fctx->fin_plain_bb)) { - apr_size_t rlen = 0; - apr_bucket *b; - - if (fctx->fin_bytes_in_rustls > 0) { - in_buf_len = APR_BUCKET_BUFF_SIZE; - in_buf = ap_calloc(in_buf_len, sizeof(char)); - rr = rustls_connection_read(fctx->cc->rustls_connection, - (unsigned char*)in_buf, in_buf_len, &rlen); - if (rr == RUSTLS_RESULT_PLAINTEXT_EMPTY) { - rr = RUSTLS_RESULT_OK; - rlen = 0; - } - if (rr != RUSTLS_RESULT_OK) goto cleanup; - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, rv, fctx->c, - "tls_filter_conn_input: got %ld plain bytes from rustls", (long)rlen); - if (rlen > 0) { - b = apr_bucket_heap_create(in_buf, rlen, free, fctx->c->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(fctx->fin_plain_bb, b); - } - else { - free(in_buf); - } - in_buf = NULL; - } - if (rlen == 0) { - /* that did not produce anything either. try getting more - * TLS data from the network into the rustls session. */ - fctx->fin_bytes_in_rustls = 0; - rv = read_tls_to_rustls(fctx, fctx->fin_max_in_rustls, block, 0); - if (APR_SUCCESS != rv) goto cleanup; /* this also leave on APR_EAGAIN */ - } - } - - if (AP_MODE_GETLINE == mode) { - if (readbytes <= 0) readbytes = HUGE_STRING_LEN; - rv = tls_util_brigade_split_line(bb, fctx->fin_plain_bb, block, readbytes, &nlen); - if (APR_SUCCESS != rv) goto cleanup; - passed += nlen; - } - else if (AP_MODE_READBYTES == mode) { - ap_assert(readbytes > 0); - rv = tls_util_brigade_transfer(bb, fctx->fin_plain_bb, readbytes, &nlen); - if (APR_SUCCESS != rv) goto cleanup; - passed += nlen; - } - else if (AP_MODE_SPECULATIVE == mode) { - ap_assert(readbytes > 0); - rv = tls_util_brigade_copy(bb, fctx->fin_plain_bb, readbytes, &nlen); - if (APR_SUCCESS != rv) goto cleanup; - passed += nlen; - } - else if (AP_MODE_EXHAUSTIVE == mode) { - /* return all we have */ - APR_BRIGADE_CONCAT(bb, fctx->fin_plain_bb); - } - else { - /* We do support any other mode */ - rv = APR_ENOTIMPL; goto cleanup; - } - - fout_pass_all_to_net(fctx, 0); - -cleanup: - if (NULL != in_buf) free(in_buf); - - if (APLOGctrace3(fctx->c)) { - tls_util_bb_log(fctx->c, APLOG_TRACE3, "tls_input, fctx->fin_plain_bb", fctx->fin_plain_bb); - tls_util_bb_log(fctx->c, APLOG_TRACE3, "tls_input, bb", bb); - } - if (rr != RUSTLS_RESULT_OK) { - const char *err_descr = ""; - - rv = tls_core_error(fctx->c, rr, &err_descr); - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, fctx->c, APLOGNO(10355) - "tls_filter_conn_input: [%d] %s", (int)rr, err_descr); - } - else if (APR_STATUS_IS_EAGAIN(rv)) { - ap_log_cerror(APLOG_MARK, APLOG_TRACE4, rv, fctx->c, - "tls_filter_conn_input: no data available"); - } - else if (APR_SUCCESS != rv) { - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, fctx->c, APLOGNO(10356) - "tls_filter_conn_input"); - } - else { - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, rv, fctx->c, - "tls_filter_conn_input: passed %ld bytes", (long)passed); - } - -#if AP_MODULE_MAGIC_AT_LEAST(20200420, 1) - if (APR_SUCCESS == rv || APR_STATUS_IS_EAGAIN(rv)) { - ap_filter_setaside_brigade(f, fctx->fin_plain_bb); - } -#endif - return rv; -} - -static rustls_io_result tls_write_callback( - void *userdata, const unsigned char *buf, size_t n, size_t *out_n) -{ - tls_filter_ctx_t *fctx = userdata; - apr_status_t rv; - - if ((apr_off_t)n + fctx->fout_bytes_in_tls_bb >= (apr_off_t)fctx->fout_auto_flush_size) { - apr_bucket *b = apr_bucket_transient_create((const char*)buf, n, fctx->fout_tls_bb->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(fctx->fout_tls_bb, b); - fctx->fout_bytes_in_tls_bb += (apr_off_t)n; - rv = fout_pass_tls_to_net(fctx); - *out_n = n; - } - else { - rv = apr_brigade_write(fctx->fout_tls_bb, NULL, NULL, (const char*)buf, n); - if (APR_SUCCESS != rv) goto cleanup; - fctx->fout_bytes_in_tls_bb += (apr_off_t)n; - *out_n = n; - } -cleanup: - ap_log_error(APLOG_MARK, APLOG_TRACE5, rv, fctx->cc->server, - "tls_write_callback: %ld bytes", (long)n); - return APR_TO_OS_ERROR(rv); -} - -static rustls_io_result tls_write_vectored_callback( - void *userdata, const rustls_iovec *riov, size_t count, size_t *out_n) -{ - tls_filter_ctx_t *fctx = userdata; - const struct iovec *iov = (const struct iovec*)riov; - apr_status_t rv; - size_t i, n = 0; - apr_bucket *b; - - for (i = 0; i < count; ++i, ++iov) { - b = apr_bucket_transient_create((const char*)iov->iov_base, iov->iov_len, fctx->fout_tls_bb->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(fctx->fout_tls_bb, b); - n += iov->iov_len; - } - fctx->fout_bytes_in_tls_bb += (apr_off_t)n; - rv = fout_pass_tls_to_net(fctx); - *out_n = n; - ap_log_error(APLOG_MARK, APLOG_TRACE5, rv, fctx->cc->server, - "tls_write_vectored_callback: %ld bytes in %d slices", (long)n, (int)count); - return APR_TO_OS_ERROR(rv); -} - -#define TLS_WRITE_VECTORED 1 -/** - * Read TLS encrypted data from cc->rustls_connection> and pass it down - * Apache's filter chain to the network. - * - * For now, we always FLUSH the data, since that is what we need during handshakes. - */ -static apr_status_t fout_pass_rustls_to_tls(tls_filter_ctx_t *fctx) -{ - apr_status_t rv = APR_SUCCESS; - - if (rustls_connection_wants_write(fctx->cc->rustls_connection)) { - size_t dlen; - int os_err; - - if (TLS_WRITE_VECTORED) { - do { - os_err = rustls_connection_write_tls_vectored( - fctx->cc->rustls_connection, tls_write_vectored_callback, fctx, &dlen); - if (os_err) { - rv = APR_FROM_OS_ERROR(os_err); - goto cleanup; - } - } - while (rustls_connection_wants_write(fctx->cc->rustls_connection)); - } - else { - do { - os_err = rustls_connection_write_tls( - fctx->cc->rustls_connection, tls_write_callback, fctx, &dlen); - if (os_err) { - rv = APR_FROM_OS_ERROR(os_err); - goto cleanup; - } - } - while (rustls_connection_wants_write(fctx->cc->rustls_connection)); - ap_log_cerror(APLOG_MARK, APLOG_TRACE3, rv, fctx->c, - "fout_pass_rustls_to_tls, %ld bytes ready for network", (long)fctx->fout_bytes_in_tls_bb); - fctx->fout_bytes_in_rustls = 0; - } - } -cleanup: - return rv; -} - -static apr_status_t fout_pass_buf_to_rustls( - tls_filter_ctx_t *fctx, const char *buf, apr_size_t len) -{ - apr_status_t rv = APR_SUCCESS; - rustls_result rr = RUSTLS_RESULT_OK; - apr_size_t written; - - while (len) { - /* check if we will exceed the limit of data in rustls. - * rustls does not guarantuee that it will accept all data, so we - * iterate and flush when needed. */ - if (fctx->fout_bytes_in_rustls + (apr_off_t)len > (apr_off_t)fctx->fout_max_in_rustls) { - rv = fout_pass_rustls_to_tls(fctx); - if (APR_SUCCESS != rv) goto cleanup; - } - - rr = rustls_connection_write(fctx->cc->rustls_connection, - (const unsigned char*)buf, len, &written); - if (rr != RUSTLS_RESULT_OK) goto cleanup; - ap_assert(written <= len); - fctx->fout_bytes_in_rustls += (apr_off_t)written; - buf += written; - len -= written; - if (written == 0) { - rv = APR_EAGAIN; - ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, fctx->c, APLOGNO(10357) - "fout_pass_buf_to_rustls: not read by rustls at all"); - goto cleanup; - } - } -cleanup: - if (rr != RUSTLS_RESULT_OK) { - const char *err_descr = ""; - rv = tls_core_error(fctx->c, rr, &err_descr); - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, fctx->c, APLOGNO(10358) - "fout_pass_buf_to_tls to rustls: [%d] %s", (int)rr, err_descr); - } - return rv; -} - -static apr_status_t fout_pass_all_to_tls(tls_filter_ctx_t *fctx) -{ - apr_status_t rv = APR_SUCCESS; - - if (fctx->fout_buf_plain_len) { - rv = fout_pass_buf_to_rustls(fctx, fctx->fout_buf_plain, fctx->fout_buf_plain_len); - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, rv, fctx->c, - "fout_pass_all_to_tls: %ld plain bytes written to rustls", - (long)fctx->fout_buf_plain_len); - if (APR_SUCCESS != rv) goto cleanup; - fctx->fout_buf_plain_len = 0; - } - - rv = fout_pass_rustls_to_tls(fctx); -cleanup: - return rv; -} - -static apr_status_t fout_pass_all_to_net(tls_filter_ctx_t *fctx, int flush) -{ - apr_status_t rv; - - rv = fout_pass_all_to_tls(fctx); - if (APR_SUCCESS != rv) goto cleanup; - if (flush) { - apr_bucket *b = apr_bucket_flush_create(fctx->fout_tls_bb->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(fctx->fout_tls_bb, b); - } - rv = fout_pass_tls_to_net(fctx); -cleanup: - return rv; -} - -static apr_status_t fout_add_bucket_to_plain(tls_filter_ctx_t *fctx, apr_bucket *b) -{ - const char *data; - apr_size_t dlen, buf_remain; - apr_status_t rv = APR_SUCCESS; - - ap_assert((apr_size_t)-1 != b->length); - if (b->length == 0) { - apr_bucket_delete(b); - goto cleanup; - } - - buf_remain = fctx->fout_buf_plain_size - fctx->fout_buf_plain_len; - if (buf_remain == 0) { - rv = fout_pass_all_to_tls(fctx); - if (APR_SUCCESS != rv) goto cleanup; - buf_remain = fctx->fout_buf_plain_size - fctx->fout_buf_plain_len; - ap_assert(buf_remain > 0); - } - if (b->length > buf_remain) { - apr_bucket_split(b, buf_remain); - } - rv = apr_bucket_read(b, &data, &dlen, APR_BLOCK_READ); - if (APR_SUCCESS != rv) goto cleanup; - /*if (dlen > TLS_PREF_PLAIN_CHUNK_SIZE)*/ - ap_assert(dlen <= buf_remain); - memcpy(fctx->fout_buf_plain + fctx->fout_buf_plain_len, data, dlen); - fctx->fout_buf_plain_len += dlen; - apr_bucket_delete(b); -cleanup: - return rv; -} - -static apr_status_t fout_add_bucket_to_tls(tls_filter_ctx_t *fctx, apr_bucket *b) -{ - apr_status_t rv; - - rv = fout_pass_all_to_tls(fctx); - if (APR_SUCCESS != rv) goto cleanup; - APR_BUCKET_REMOVE(b); - APR_BRIGADE_INSERT_TAIL(fctx->fout_tls_bb, b); - if (AP_BUCKET_IS_EOC(b)) { - rustls_connection_send_close_notify(fctx->cc->rustls_connection); - fctx->cc->state = TLS_CONN_ST_NOTIFIED; - rv = fout_pass_rustls_to_tls(fctx); - if (APR_SUCCESS != rv) goto cleanup; - } -cleanup: - return rv; -} - -static apr_status_t fout_append_plain(tls_filter_ctx_t *fctx, apr_bucket *b) -{ - const char *data; - apr_size_t dlen, buf_remain; - rustls_result rr = RUSTLS_RESULT_OK; - apr_status_t rv = APR_SUCCESS; - const char *lbuf = NULL; - int flush = 0; - - if (b) { - /* if our plain buffer is full, now is a good time to flush it. */ - buf_remain = fctx->fout_buf_plain_size - fctx->fout_buf_plain_len; - if (buf_remain == 0) { - rv = fout_pass_all_to_tls(fctx); - if (APR_SUCCESS != rv) goto cleanup; - buf_remain = fctx->fout_buf_plain_size - fctx->fout_buf_plain_len; - ap_assert(buf_remain > 0); - } - - /* Resolve any indeterminate bucket to a "real" one by reading it. */ - if ((apr_size_t)-1 == b->length) { - rv = apr_bucket_read(b, &data, &dlen, APR_BLOCK_READ); - if (APR_STATUS_IS_EOF(rv)) { - apr_bucket_delete(b); - goto maybe_flush; - } - else if (APR_SUCCESS != rv) goto cleanup; - } - /* Now `b` is the bucket that we need to append and consume */ - if (APR_BUCKET_IS_METADATA(b)) { - /* outgoing buckets: - * [PLAINDATA META PLAINDATA META META] - * need to become: - * [TLSDATA META TLSDATA META META] - * because we need to send the meta buckets down the - * network filters. */ - rv = fout_add_bucket_to_tls(fctx, b); - flush = 1; - } - else if (b->length == 0) { - apr_bucket_delete(b); - } - else if (b->length < 1024 || fctx->fout_buf_plain_len > 0) { - /* we want to buffer small chunks to create larger TLS records and - * not leak security relevant information. So, we buffer small - * chunks and add (parts of) later, larger chunks if the plain - * buffer contains data. */ - rv = fout_add_bucket_to_plain(fctx, b); - if (APR_SUCCESS != rv) goto cleanup; - } - else { - /* we have a large chunk and our plain buffer is empty, write it - * directly into rustls. */ -#define TLS_FILE_CHUNK_SIZE 4 * TLS_PREF_PLAIN_CHUNK_SIZE - if (b->length > TLS_FILE_CHUNK_SIZE) { - apr_bucket_split(b, TLS_FILE_CHUNK_SIZE); - } - - if (APR_BUCKET_IS_FILE(b) - && (lbuf = malloc(b->length))) { - /* A file bucket is a most wonderous thing. Since the dawn of time, - * it has been subject to many optimizations for efficient handling - * of large data in the server: - * - unless one reads from it, it will just consist of a file handle - * and the offset+length information. - * - a apr_bucket_read() will transform itself to a bucket holding - * some 8000 bytes of data (APR_BUCKET_BUFF_SIZE), plus a following - * bucket that continues to hold the file handle and updated offsets/length - * information. - * Using standard bucket brigade handling, one would send 8000 bytes - * chunks to the network and that is fine for many occasions. - * - to have improved performance, the http: network handler takes - * the file handle directly and uses sendfile() when the OS supports it. - * - But there is not sendfile() for TLS (netflix did some experiments). - * So. - * rustls will try to collect max length traffic data into ont TLS - * message, but it can only work with what we gave it. If we give it buffers - * that fit what it wants to assemble already, its work is much easier. - * - * We can read file buckets in large chunks than APR_BUCKET_BUFF_SIZE, - * with a bit of knowledge about how they work. - */ - apr_bucket_file *f = (apr_bucket_file *)b->data; - apr_file_t *fd = f->fd; - apr_off_t offset = b->start; - - dlen = b->length; - rv = apr_file_seek(fd, APR_SET, &offset); - if (APR_SUCCESS != rv) goto cleanup; - rv = apr_file_read(fd, (void*)lbuf, &dlen); - if (APR_SUCCESS != rv && !APR_STATUS_IS_EOF(rv)) goto cleanup; - rv = fout_pass_buf_to_rustls(fctx, lbuf, dlen); - if (APR_SUCCESS != rv) goto cleanup; - apr_bucket_delete(b); - } - else { - rv = apr_bucket_read(b, &data, &dlen, APR_BLOCK_READ); - if (APR_SUCCESS != rv) goto cleanup; - rv = fout_pass_buf_to_rustls(fctx, data, dlen); - if (APR_SUCCESS != rv) goto cleanup; - apr_bucket_delete(b); - } - } - } - -maybe_flush: - if (flush) { - rv = fout_pass_all_to_net(fctx, 1); - if (APR_SUCCESS != rv) goto cleanup; - } - -cleanup: - if (lbuf) free((void*)lbuf); - if (rr != RUSTLS_RESULT_OK) { - const char *err_descr = ""; - rv = tls_core_error(fctx->c, rr, &err_descr); - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, fctx->c, APLOGNO(10359) - "write_bucket_to_rustls: [%d] %s", (int)rr, err_descr); - } - return rv; -} - -/** - * The connection filter converting plain, unencrypted traffic data into TLS - * encrypted bytes and send the down the Apache filter chain out to the network. - * - * the data to send, including "meta data" such as FLUSH indicators - * to force filters to write any data set aside (an apache term for - * 'buffering'). - * The buckets in need to be completely consumed, e.g. will be - * empty on a successful return. but unless FLUSHed, filters may hold - * buckets back internally, for various reasons. However they always - * need to be processed in the order they arrive. - */ -static apr_status_t filter_conn_output( - ap_filter_t *f, apr_bucket_brigade *bb) -{ - tls_filter_ctx_t *fctx = f->ctx; - apr_status_t rv = APR_SUCCESS; - rustls_result rr = RUSTLS_RESULT_OK; - - if (f->c->aborted) { - ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, fctx->c, - "tls_filter_conn_output: aborted conn"); - apr_brigade_cleanup(bb); - rv = APR_ECONNABORTED; goto cleanup; - } - - rv = progress_tls_atleast_to(fctx, TLS_CONN_ST_TRAFFIC); - if (APR_SUCCESS != rv) goto cleanup; /* this also leaves on APR_EAGAIN */ - - if (fctx->cc->state == TLS_CONN_ST_DONE) { - /* have done everything, just pass through */ - ap_log_cerror(APLOG_MARK, APLOG_TRACE4, 0, fctx->c, - "tls_filter_conn_output: tls session is already done"); - rv = ap_pass_brigade(f->next, bb); - goto cleanup; - } - - ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, fctx->cc->server, - "tls_filter_conn_output, server=%s", fctx->cc->server->server_hostname); - if (APLOGctrace5(fctx->c)) { - tls_util_bb_log(fctx->c, APLOG_TRACE5, "filter_conn_output", bb); - } - - while (!APR_BRIGADE_EMPTY(bb)) { - rv = fout_append_plain(fctx, APR_BRIGADE_FIRST(bb)); - if (APR_SUCCESS != rv) goto cleanup; - } - - if (APLOGctrace5(fctx->c)) { - tls_util_bb_log(fctx->c, APLOG_TRACE5, "filter_conn_output, processed plain", bb); - tls_util_bb_log(fctx->c, APLOG_TRACE5, "filter_conn_output, tls", fctx->fout_tls_bb); - } - -cleanup: - if (rr != RUSTLS_RESULT_OK) { - const char *err_descr = ""; - rv = tls_core_error(fctx->c, rr, &err_descr); - ap_log_cerror(APLOG_MARK, APLOG_DEBUG, rv, fctx->c, APLOGNO(10360) - "tls_filter_conn_output: [%d] %s", (int)rr, err_descr); - } - else { - ap_log_cerror(APLOG_MARK, APLOG_TRACE2, rv, fctx->c, - "tls_filter_conn_output: done"); - } - return rv; -} - -int tls_filter_pre_conn_init(conn_rec *c) -{ - tls_conf_conn_t *cc; - tls_filter_ctx_t *fctx; - - if (OK != tls_core_pre_conn_init(c)) { - return DECLINED; - } - - ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, c->base_server, - "tls_filter_pre_conn_init on %s", c->base_server->server_hostname); - - cc = tls_conf_conn_get(c); - ap_assert(cc); - - fctx = apr_pcalloc(c->pool, sizeof(*fctx)); - fctx->c = c; - fctx->cc = cc; - cc->filter_ctx = fctx; - - /* a bit tricky: registering out filters returns the ap_filter_t* - * that it created for it. The ->next field points always - * to the filter "below" our filter. That will be other registered - * filters and last, but not least, the network filter on the socket. - * - * Therefore, wenn we need to read/write TLS data during handshake, we can - * pass the data to/call on ->next- Since ->next can change during the setup of - * a connections (other modules register also sth.), we keep the ap_filter_t* - * returned here, since httpd core will update the ->next whenever someone - * adds a filter or removes one. This can potentially happen all the time. - */ - fctx->fin_ctx = ap_add_input_filter(TLS_FILTER_RAW, fctx, NULL, c); - fctx->fin_tls_bb = apr_brigade_create(c->pool, c->bucket_alloc); - fctx->fin_tls_buffer_bb = NULL; - fctx->fin_plain_bb = apr_brigade_create(c->pool, c->bucket_alloc); - fctx->fout_ctx = ap_add_output_filter(TLS_FILTER_RAW, fctx, NULL, c); - fctx->fout_tls_bb = apr_brigade_create(c->pool, c->bucket_alloc); - fctx->fout_buf_plain_size = APR_BUCKET_BUFF_SIZE; - fctx->fout_buf_plain = apr_pcalloc(c->pool, fctx->fout_buf_plain_size); - fctx->fout_buf_plain_len = 0; - - /* Let the filters have 2 max-length TLS Messages in the rustls buffers. - * The effects we would like to achieve here are: - * 1. pass data out, so that every bucket becomes its own TLS message. - * This hides, if possible, the length of response parts. - * If we give rustls enough plain data, it will use the max TLS message - * size and things are more hidden. But we can only write what the application - * or protocol gives us. - * 2. max length records result in less overhead for all layers involved. - * 3. a TLS message from the client can only be decrypted when it has - * completely arrived. If we provide rustls with enough data (if the - * network has it for us), it should always be able to decrypt at least - * one TLS message and we have plain bytes to forward to the protocol - * handler. - */ - fctx->fin_max_in_rustls = 4 * TLS_REC_MAX_SIZE; - fctx->fout_max_in_rustls = 4 * TLS_PREF_PLAIN_CHUNK_SIZE; - fctx->fout_auto_flush_size = 2 * TLS_REC_MAX_SIZE; - - return OK; -} - -void tls_filter_conn_init(conn_rec *c) -{ - tls_conf_conn_t *cc = tls_conf_conn_get(c); - - if (cc && cc->filter_ctx && !cc->outgoing) { - /* We are one in a row of hooks that - possibly - want to process this - * connection, the (HTTP) protocol handlers among them. - * - * For incoming connections, we need to select the protocol to use NOW, - * so that the later protocol handlers do the right thing. - * Send an INIT down the input filter chain to trigger the TLS handshake, - * which will select a protocol via ALPN. */ - apr_bucket_brigade* temp; - - ap_log_error(APLOG_MARK, APLOG_TRACE2, 0, c->base_server, - "tls_filter_conn_init on %s, triggering handshake", c->base_server->server_hostname); - temp = apr_brigade_create(c->pool, c->bucket_alloc); - ap_get_brigade(c->input_filters, temp, AP_MODE_INIT, APR_BLOCK_READ, 0); - apr_brigade_destroy(temp); - } -} - -void tls_filter_register( - apr_pool_t *pool) -{ - (void)pool; - ap_register_input_filter(TLS_FILTER_RAW, filter_conn_input, NULL, AP_FTYPE_CONNECTION + 5); - ap_register_output_filter(TLS_FILTER_RAW, filter_conn_output, NULL, AP_FTYPE_CONNECTION + 5); -} diff --git a/modules/tls/tls_filter.h b/modules/tls/tls_filter.h deleted file mode 100644 index 4f3d38bbc1..0000000000 --- a/modules/tls/tls_filter.h +++ /dev/null @@ -1,90 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef tls_filter_h -#define tls_filter_h - -#define TLS_FILTER_RAW "TLS raw" - -typedef struct tls_filter_ctx_t tls_filter_ctx_t; - -struct tls_filter_ctx_t { - conn_rec *c; /* connection this context is for */ - tls_conf_conn_t *cc; /* tls module configuration of connection */ - - ap_filter_t *fin_ctx; /* Apache's entry into the input filter chain */ - apr_bucket_brigade *fin_tls_bb; /* TLS encrypted, incoming network data */ - apr_bucket_brigade *fin_tls_buffer_bb; /* TLS encrypted, incoming network data buffering */ - apr_bucket_brigade *fin_plain_bb; /* decrypted, incoming traffic data */ - apr_off_t fin_bytes_in_rustls; /* # of input TLS bytes in rustls_connection */ - apr_read_type_e fin_block; /* Do we block on input reads or not? */ - - ap_filter_t *fout_ctx; /* Apache's entry into the output filter chain */ - char *fout_buf_plain; /* a buffer to collect plain bytes for output */ - apr_size_t fout_buf_plain_len; /* the amount of bytes in the buffer */ - apr_size_t fout_buf_plain_size; /* the total size of the buffer */ - apr_bucket_brigade *fout_tls_bb; /* TLS encrypted, outgoing network data */ - apr_off_t fout_bytes_in_rustls; /* # of output plain bytes in rustls_connection */ - apr_off_t fout_bytes_in_tls_bb; /* # of output tls bytes in our brigade */ - - apr_size_t fin_max_in_rustls; /* how much tls we like to read into rustls */ - apr_size_t fout_max_in_rustls; /* how much plain bytes we like in rustls */ - apr_size_t fout_max_bucket_size; /* how large bucket chunks we handle before splitting */ - apr_size_t fout_auto_flush_size; /* on much outoing TLS data we flush to network */ -}; - -/** - * Register the in-/output filters for converting TLS to application data and vice versa. - */ -void tls_filter_register(apr_pool_t *pool); - -/** - * Initialize the pre_connection state. Install all filters. - * - * @return OK if TLS on connection is enabled, DECLINED otherwise - */ -int tls_filter_pre_conn_init(conn_rec *c); - -/** - * Initialize the connection for use, perform the TLS handshake. - * - * Any failure will lead to the connection becoming aborted. - */ -void tls_filter_conn_init(conn_rec *c); - -/* - * says: - * "For large data transfers, small record sizes can materially affect performance." - * and - * "For TLS 1.2 and earlier, that limit is 2^14 octets. TLS 1.3 uses a limit of - * 2^14+1 octets." - * Maybe future TLS versions will raise that value, but for now these limits stand. - * Given the choice, we would like rustls to provide traffic data in those chunks. - */ -#define TLS_PREF_PLAIN_CHUNK_SIZE (16384) - -/* - * When retrieving TLS chunks for rustls, or providing it a buffer - * to pass out TLS chunks (which are then bucketed and written to the - * network filters), we ideally would do that in multiples of TLS - * messages sizes. - * That would be TLS_PREF_WRITE_SIZE + TLS Message Overhead, such as - * MAC and padding. But these vary with protocol and ciphers chosen, so - * we define something which should be "large enough", but not overly so. - */ -#define TLS_REC_EXTRA (1024) -#define TLS_REC_MAX_SIZE (TLS_PREF_PLAIN_CHUNK_SIZE + TLS_REC_EXTRA) - -#endif /* tls_filter_h */ \ No newline at end of file diff --git a/modules/tls/tls_ocsp.c b/modules/tls/tls_ocsp.c deleted file mode 100644 index 37e95b1521..0000000000 --- a/modules/tls/tls_ocsp.c +++ /dev/null @@ -1,120 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include "tls_cert.h" -#include "tls_conf.h" -#include "tls_core.h" -#include "tls_proto.h" -#include "tls_ocsp.h" - -extern module AP_MODULE_DECLARE_DATA tls_module; -APLOG_USE_MODULE(tls); - - -static int prime_cert( - void *userdata, server_rec *s, const char *cert_id, const char *cert_pem, - const rustls_certified_key *certified_key) -{ - apr_pool_t *p = userdata; - apr_status_t rv; - - (void)certified_key; - rv = ap_ssl_ocsp_prime(s, p, cert_id, strlen(cert_id), cert_pem); - ap_log_error(APLOG_MARK, APLOG_TRACE1, rv, s, "ocsp prime of cert [%s] from %s", - cert_id, s->server_hostname); - return 1; -} - -apr_status_t tls_ocsp_prime_certs(tls_conf_global_t *gc, apr_pool_t *p, server_rec *s) -{ - ap_log_error(APLOG_MARK, APLOG_TRACE1, 0, s, "ocsp priming of %d certs", - (int)tls_cert_reg_count(gc->cert_reg)); - tls_cert_reg_do(prime_cert, p, gc->cert_reg); - return APR_SUCCESS; -} - -typedef struct { - conn_rec *c; - const rustls_certified_key *key_in; - const rustls_certified_key *key_out; -} ocsp_copy_ctx_t; - -static void ocsp_clone_key(const unsigned char *der, apr_size_t der_len, void *userdata) -{ - ocsp_copy_ctx_t *ctx = userdata; - rustls_slice_bytes rslice; - rustls_result rr; - - rslice.data = der; - rslice.len = der_len; - - rr = rustls_certified_key_clone_with_ocsp(ctx->key_in, der_len? &rslice : NULL, &ctx->key_out); - if (RUSTLS_RESULT_OK != rr) { - const char *err_descr = NULL; - apr_status_t rv = tls_util_rustls_error(ctx->c->pool, rr, &err_descr); - ap_log_cerror(APLOG_MARK, APLOG_ERR, rv, ctx->c, APLOGNO(10362) - "Failed add OCSP data to certificate: [%d] %s", (int)rr, err_descr); - } - else { - ap_log_cerror(APLOG_MARK, APLOG_TRACE1, 0, ctx->c, - "provided %ld bytes of ocsp response DER data to key.", (long)der_len); - } -} - -apr_status_t tls_ocsp_update_key( - conn_rec *c, const rustls_certified_key *certified_key, - const rustls_certified_key **pkey_out) -{ - tls_conf_conn_t *cc = tls_conf_conn_get(c); - tls_conf_server_t *sc; - const char *key_id; - apr_status_t rv = APR_SUCCESS; - ocsp_copy_ctx_t ctx; - - assert(cc); - assert(cc->server); - sc = tls_conf_server_get(cc->server); - key_id = tls_cert_reg_get_id(sc->global->cert_reg, certified_key); - if (!key_id) { - rv = APR_ENOENT; - ap_log_cerror(APLOG_MARK, APLOG_TRACE1, rv, c, "certified key not registered"); - goto cleanup; - } - - ctx.c = c; - ctx.key_in = certified_key; - ctx.key_out = NULL; - rv = ap_ssl_ocsp_get_resp(cc->server, c, key_id, strlen(key_id), ocsp_clone_key, &ctx); - if (APR_SUCCESS != rv) { - ap_log_cerror(APLOG_MARK, APLOG_TRACE1, rv, c, - "ocsp response not available for cert %s", key_id); - } - -cleanup: - *pkey_out = (APR_SUCCESS == rv)? ctx.key_out : NULL; - return rv; -} diff --git a/modules/tls/tls_ocsp.h b/modules/tls/tls_ocsp.h deleted file mode 100644 index 60770a9f8e..0000000000 --- a/modules/tls/tls_ocsp.h +++ /dev/null @@ -1,47 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef tls_ocsp_h -#define tls_ocsp_h - -/** - * Prime the collected certified keys for OCSP response provisioning (aka. Stapling). - * - * To be called in the post-config phase of the server before connections are handled. - * @param gc the global module configuration with the certified_key registry - * @param p the pool to use for allocations - * @param s the base server record - */ -apr_status_t tls_ocsp_prime_certs(tls_conf_global_t *gc, apr_pool_t *p, server_rec *s); - -/** - * Provide the OCSP response data for the certified_key into the offered buffer, - * so available. - * If not data is available `out_n` is set to 0. Same, if the offered buffer - * is not large enough to hold the complete response. - * If OCSP response DER data is copied, the number of copied bytes is given in `out_n`. - * - * Note that only keys that have been primed initially will have OCSP data available. - * @param c the current connection - * @param certified_key the key to get the OCSP response data for - * @param buf a buffer which can hold up to `buf_len` bytes - * @param buf_len the length of `buf` - * @param out_n the number of OCSP response DER bytes copied or 0. - */ -apr_status_t tls_ocsp_update_key( - conn_rec *c, const rustls_certified_key *certified_key, - const rustls_certified_key **key_out); - -#endif /* tls_ocsp_h */ diff --git a/modules/tls/tls_proto.c b/modules/tls/tls_proto.c deleted file mode 100644 index 95a903b715..0000000000 --- a/modules/tls/tls_proto.c +++ /dev/null @@ -1,603 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include "tls_proto.h" -#include "tls_conf.h" -#include "tls_util.h" - -extern module AP_MODULE_DECLARE_DATA tls_module; -APLOG_USE_MODULE(tls); - - - -/** - * Known cipher as registered in - * - */ -static tls_cipher_t KNOWN_CIPHERS[] = { - { 0x0000, "TLS_NULL_WITH_NULL_NULL", NULL }, - { 0x0001, "TLS_RSA_WITH_NULL_MD5", NULL }, - { 0x0002, "TLS_RSA_WITH_NULL_SHA", NULL }, - { 0x0003, "TLS_RSA_EXPORT_WITH_RC4_40_MD5", NULL }, - { 0x0004, "TLS_RSA_WITH_RC4_128_MD5", NULL }, - { 0x0005, "TLS_RSA_WITH_RC4_128_SHA", NULL }, - { 0x0006, "TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5", NULL }, - { 0x0007, "TLS_RSA_WITH_IDEA_CBC_SHA", NULL }, - { 0x0008, "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA", NULL }, - { 0x0009, "TLS_RSA_WITH_DES_CBC_SHA", NULL }, - { 0x000a, "TLS_RSA_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0x000b, "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA", NULL }, - { 0x000c, "TLS_DH_DSS_WITH_DES_CBC_SHA", NULL }, - { 0x000d, "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0x000e, "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA", NULL }, - { 0x000f, "TLS_DH_RSA_WITH_DES_CBC_SHA", NULL }, - { 0x0010, "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0x0011, "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", NULL }, - { 0x0012, "TLS_DHE_DSS_WITH_DES_CBC_SHA", NULL }, - { 0x0013, "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0x0014, "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", NULL }, - { 0x0015, "TLS_DHE_RSA_WITH_DES_CBC_SHA", NULL }, - { 0x0016, "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0x0017, "TLS_DH_anon_EXPORT_WITH_RC4_40_MD5", NULL }, - { 0x0018, "TLS_DH_anon_WITH_RC4_128_MD5", NULL }, - { 0x0019, "TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA", NULL }, - { 0x001a, "TLS_DH_anon_WITH_DES_CBC_SHA", NULL }, - { 0x001b, "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0x001c, "SSL_FORTEZZA_KEA_WITH_NULL_SHA", NULL }, - { 0x001d, "SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA", NULL }, - { 0x001e, "TLS_KRB5_WITH_DES_CBC_SHA_or_SSL_FORTEZZA_KEA_WITH_RC4_128_SHA", NULL }, - { 0x001f, "TLS_KRB5_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0x0020, "TLS_KRB5_WITH_RC4_128_SHA", NULL }, - { 0x0021, "TLS_KRB5_WITH_IDEA_CBC_SHA", NULL }, - { 0x0022, "TLS_KRB5_WITH_DES_CBC_MD5", NULL }, - { 0x0023, "TLS_KRB5_WITH_3DES_EDE_CBC_MD5", NULL }, - { 0x0024, "TLS_KRB5_WITH_RC4_128_MD5", NULL }, - { 0x0025, "TLS_KRB5_WITH_IDEA_CBC_MD5", NULL }, - { 0x0026, "TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA", NULL }, - { 0x0027, "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA", NULL }, - { 0x0028, "TLS_KRB5_EXPORT_WITH_RC4_40_SHA", NULL }, - { 0x0029, "TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5", NULL }, - { 0x002a, "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5", NULL }, - { 0x002b, "TLS_KRB5_EXPORT_WITH_RC4_40_MD5", NULL }, - { 0x002c, "TLS_PSK_WITH_NULL_SHA", NULL }, - { 0x002d, "TLS_DHE_PSK_WITH_NULL_SHA", NULL }, - { 0x002e, "TLS_RSA_PSK_WITH_NULL_SHA", NULL }, - { 0x002f, "TLS_RSA_WITH_AES_128_CBC_SHA", NULL }, - { 0x0030, "TLS_DH_DSS_WITH_AES_128_CBC_SHA", NULL }, - { 0x0031, "TLS_DH_RSA_WITH_AES_128_CBC_SHA", NULL }, - { 0x0032, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", NULL }, - { 0x0033, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", NULL }, - { 0x0034, "TLS_DH_anon_WITH_AES_128_CBC_SHA", NULL }, - { 0x0035, "TLS_RSA_WITH_AES_256_CBC_SHA", NULL }, - { 0x0036, "TLS_DH_DSS_WITH_AES_256_CBC_SHA", NULL }, - { 0x0037, "TLS_DH_RSA_WITH_AES_256_CBC_SHA", NULL }, - { 0x0038, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", NULL }, - { 0x0039, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", NULL }, - { 0x003a, "TLS_DH_anon_WITH_AES_256_CBC_SHA", NULL }, - { 0x003b, "TLS_RSA_WITH_NULL_SHA256", "NULL-SHA256" }, - { 0x003c, "TLS_RSA_WITH_AES_128_CBC_SHA256", "AES128-SHA256" }, - { 0x003d, "TLS_RSA_WITH_AES_256_CBC_SHA256", "AES256-SHA256" }, - { 0x003e, "TLS_DH_DSS_WITH_AES_128_CBC_SHA256", "DH-DSS-AES128-SHA256" }, - { 0x003f, "TLS_DH_RSA_WITH_AES_128_CBC_SHA256", "DH-RSA-AES128-SHA256" }, - { 0x0040, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", "DHE-DSS-AES128-SHA256" }, - { 0x0041, "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA", NULL }, - { 0x0042, "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA", NULL }, - { 0x0043, "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA", NULL }, - { 0x0044, "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA", NULL }, - { 0x0045, "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA", NULL }, - { 0x0046, "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA", NULL }, - { 0x0047, "TLS_ECDH_ECDSA_WITH_NULL_SHA_draft", NULL }, - { 0x0048, "TLS_ECDH_ECDSA_WITH_RC4_128_SHA_draft", NULL }, - { 0x0049, "TLS_ECDH_ECDSA_WITH_DES_CBC_SHA_draft", NULL }, - { 0x004a, "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA_draft", NULL }, - { 0x004b, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA_draft", NULL }, - { 0x004c, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA_draft", NULL }, - { 0x004d, "TLS_ECDH_ECNRA_WITH_DES_CBC_SHA_draft", NULL }, - { 0x004e, "TLS_ECDH_ECNRA_WITH_3DES_EDE_CBC_SHA_draft", NULL }, - { 0x004f, "TLS_ECMQV_ECDSA_NULL_SHA_draft", NULL }, - { 0x0050, "TLS_ECMQV_ECDSA_WITH_RC4_128_SHA_draft", NULL }, - { 0x0051, "TLS_ECMQV_ECDSA_WITH_DES_CBC_SHA_draft", NULL }, - { 0x0052, "TLS_ECMQV_ECDSA_WITH_3DES_EDE_CBC_SHA_draft", NULL }, - { 0x0053, "TLS_ECMQV_ECNRA_NULL_SHA_draft", NULL }, - { 0x0054, "TLS_ECMQV_ECNRA_WITH_RC4_128_SHA_draft", NULL }, - { 0x0055, "TLS_ECMQV_ECNRA_WITH_DES_CBC_SHA_draft", NULL }, - { 0x0056, "TLS_ECMQV_ECNRA_WITH_3DES_EDE_CBC_SHA_draft", NULL }, - { 0x0057, "TLS_ECDH_anon_NULL_WITH_SHA_draft", NULL }, - { 0x0058, "TLS_ECDH_anon_WITH_RC4_128_SHA_draft", NULL }, - { 0x0059, "TLS_ECDH_anon_WITH_DES_CBC_SHA_draft", NULL }, - { 0x005a, "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA_draft", NULL }, - { 0x005b, "TLS_ECDH_anon_EXPORT_WITH_DES40_CBC_SHA_draft", NULL }, - { 0x005c, "TLS_ECDH_anon_EXPORT_WITH_RC4_40_SHA_draft", NULL }, - { 0x0060, "TLS_RSA_EXPORT1024_WITH_RC4_56_MD5", NULL }, - { 0x0061, "TLS_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5", NULL }, - { 0x0062, "TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA", NULL }, - { 0x0063, "TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA", NULL }, - { 0x0064, "TLS_RSA_EXPORT1024_WITH_RC4_56_SHA", NULL }, - { 0x0065, "TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA", NULL }, - { 0x0066, "TLS_DHE_DSS_WITH_RC4_128_SHA", NULL }, - { 0x0067, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", "DHE-RSA-AES128-SHA256" }, - { 0x0068, "TLS_DH_DSS_WITH_AES_256_CBC_SHA256", "DH-DSS-AES256-SHA256" }, - { 0x0069, "TLS_DH_RSA_WITH_AES_256_CBC_SHA256", "DH-RSA-AES256-SHA256" }, - { 0x006a, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", "DHE-DSS-AES256-SHA256" }, - { 0x006b, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", "DHE-RSA-AES256-SHA256" }, - { 0x006c, "TLS_DH_anon_WITH_AES_128_CBC_SHA256", "ADH-AES128-SHA256" }, - { 0x006d, "TLS_DH_anon_WITH_AES_256_CBC_SHA256", "ADH-AES256-SHA256" }, - { 0x0072, "TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD", NULL }, - { 0x0073, "TLS_DHE_DSS_WITH_AES_128_CBC_RMD", NULL }, - { 0x0074, "TLS_DHE_DSS_WITH_AES_256_CBC_RMD", NULL }, - { 0x0077, "TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD", NULL }, - { 0x0078, "TLS_DHE_RSA_WITH_AES_128_CBC_RMD", NULL }, - { 0x0079, "TLS_DHE_RSA_WITH_AES_256_CBC_RMD", NULL }, - { 0x007c, "TLS_RSA_WITH_3DES_EDE_CBC_RMD", NULL }, - { 0x007d, "TLS_RSA_WITH_AES_128_CBC_RMD", NULL }, - { 0x007e, "TLS_RSA_WITH_AES_256_CBC_RMD", NULL }, - { 0x0080, "TLS_GOSTR341094_WITH_28147_CNT_IMIT", NULL }, - { 0x0081, "TLS_GOSTR341001_WITH_28147_CNT_IMIT", NULL }, - { 0x0082, "TLS_GOSTR341094_WITH_NULL_GOSTR3411", NULL }, - { 0x0083, "TLS_GOSTR341001_WITH_NULL_GOSTR3411", NULL }, - { 0x0084, "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA", NULL }, - { 0x0085, "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA", NULL }, - { 0x0086, "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA", NULL }, - { 0x0087, "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA", NULL }, - { 0x0088, "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA", NULL }, - { 0x0089, "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA", NULL }, - { 0x008a, "TLS_PSK_WITH_RC4_128_SHA", "PSK-RC4-SHA" }, - { 0x008b, "TLS_PSK_WITH_3DES_EDE_CBC_SHA", "PSK-3DES-EDE-CBC-SHA" }, - { 0x008c, "TLS_PSK_WITH_AES_128_CBC_SHA", NULL }, - { 0x008d, "TLS_PSK_WITH_AES_256_CBC_SHA", NULL }, - { 0x008e, "TLS_DHE_PSK_WITH_RC4_128_SHA", NULL }, - { 0x008f, "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0x0090, "TLS_DHE_PSK_WITH_AES_128_CBC_SHA", NULL }, - { 0x0091, "TLS_DHE_PSK_WITH_AES_256_CBC_SHA", NULL }, - { 0x0092, "TLS_RSA_PSK_WITH_RC4_128_SHA", NULL }, - { 0x0093, "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0x0094, "TLS_RSA_PSK_WITH_AES_128_CBC_SHA", NULL }, - { 0x0095, "TLS_RSA_PSK_WITH_AES_256_CBC_SHA", NULL }, - { 0x0096, "TLS_RSA_WITH_SEED_CBC_SHA", NULL }, - { 0x0097, "TLS_DH_DSS_WITH_SEED_CBC_SHA", NULL }, - { 0x0098, "TLS_DH_RSA_WITH_SEED_CBC_SHA", NULL }, - { 0x0099, "TLS_DHE_DSS_WITH_SEED_CBC_SHA", NULL }, - { 0x009a, "TLS_DHE_RSA_WITH_SEED_CBC_SHA", NULL }, - { 0x009b, "TLS_DH_anon_WITH_SEED_CBC_SHA", NULL }, - { 0x009c, "TLS_RSA_WITH_AES_128_GCM_SHA256", "AES128-GCM-SHA256" }, - { 0x009d, "TLS_RSA_WITH_AES_256_GCM_SHA384", "AES256-GCM-SHA384" }, - { 0x009e, "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "DHE-RSA-AES128-GCM-SHA256" }, - { 0x009f, "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "DHE-RSA-AES256-GCM-SHA384" }, - { 0x00a0, "TLS_DH_RSA_WITH_AES_128_GCM_SHA256", "DH-RSA-AES128-GCM-SHA256" }, - { 0x00a1, "TLS_DH_RSA_WITH_AES_256_GCM_SHA384", "DH-RSA-AES256-GCM-SHA384" }, - { 0x00a2, "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", "DHE-DSS-AES128-GCM-SHA256" }, - { 0x00a3, "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", "DHE-DSS-AES256-GCM-SHA384" }, - { 0x00a4, "TLS_DH_DSS_WITH_AES_128_GCM_SHA256", "DH-DSS-AES128-GCM-SHA256" }, - { 0x00a5, "TLS_DH_DSS_WITH_AES_256_GCM_SHA384", "DH-DSS-AES256-GCM-SHA384" }, - { 0x00a6, "TLS_DH_anon_WITH_AES_128_GCM_SHA256", "ADH-AES128-GCM-SHA256" }, - { 0x00a7, "TLS_DH_anon_WITH_AES_256_GCM_SHA384", "ADH-AES256-GCM-SHA384" }, - { 0x00a8, "TLS_PSK_WITH_AES_128_GCM_SHA256", NULL }, - { 0x00a9, "TLS_PSK_WITH_AES_256_GCM_SHA384", NULL }, - { 0x00aa, "TLS_DHE_PSK_WITH_AES_128_GCM_SHA256", NULL }, - { 0x00ab, "TLS_DHE_PSK_WITH_AES_256_GCM_SHA384", NULL }, - { 0x00ac, "TLS_RSA_PSK_WITH_AES_128_GCM_SHA256", NULL }, - { 0x00ad, "TLS_RSA_PSK_WITH_AES_256_GCM_SHA384", NULL }, - { 0x00ae, "TLS_PSK_WITH_AES_128_CBC_SHA256", "PSK-AES128-CBC-SHA" }, - { 0x00af, "TLS_PSK_WITH_AES_256_CBC_SHA384", "PSK-AES256-CBC-SHA" }, - { 0x00b0, "TLS_PSK_WITH_NULL_SHA256", NULL }, - { 0x00b1, "TLS_PSK_WITH_NULL_SHA384", NULL }, - { 0x00b2, "TLS_DHE_PSK_WITH_AES_128_CBC_SHA256", NULL }, - { 0x00b3, "TLS_DHE_PSK_WITH_AES_256_CBC_SHA384", NULL }, - { 0x00b4, "TLS_DHE_PSK_WITH_NULL_SHA256", NULL }, - { 0x00b5, "TLS_DHE_PSK_WITH_NULL_SHA384", NULL }, - { 0x00b6, "TLS_RSA_PSK_WITH_AES_128_CBC_SHA256", NULL }, - { 0x00b7, "TLS_RSA_PSK_WITH_AES_256_CBC_SHA384", NULL }, - { 0x00b8, "TLS_RSA_PSK_WITH_NULL_SHA256", NULL }, - { 0x00b9, "TLS_RSA_PSK_WITH_NULL_SHA384", NULL }, - { 0x00ba, "TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256", NULL }, - { 0x00bb, "TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256", NULL }, - { 0x00bc, "TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256", NULL }, - { 0x00bd, "TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256", NULL }, - { 0x00be, "TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", NULL }, - { 0x00bf, "TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256", NULL }, - { 0x00c0, "TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256", NULL }, - { 0x00c1, "TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256", NULL }, - { 0x00c2, "TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256", NULL }, - { 0x00c3, "TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256", NULL }, - { 0x00c4, "TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256", NULL }, - { 0x00c5, "TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256", NULL }, - { 0x00ff, "TLS_EMPTY_RENEGOTIATION_INFO_SCSV", NULL }, - { 0x1301, "TLS_AES_128_GCM_SHA256", "TLS13_AES_128_GCM_SHA256" }, - { 0x1302, "TLS_AES_256_GCM_SHA384", "TLS13_AES_256_GCM_SHA384" }, - { 0x1303, "TLS_CHACHA20_POLY1305_SHA256", "TLS13_CHACHA20_POLY1305_SHA256" }, - { 0x1304, "TLS_AES_128_CCM_SHA256", "TLS13_AES_128_CCM_SHA256" }, - { 0x1305, "TLS_AES_128_CCM_8_SHA256", "TLS13_AES_128_CCM_8_SHA256" }, - { 0xc001, "TLS_ECDH_ECDSA_WITH_NULL_SHA", NULL }, - { 0xc002, "TLS_ECDH_ECDSA_WITH_RC4_128_SHA", NULL }, - { 0xc003, "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0xc004, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", NULL }, - { 0xc005, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", NULL }, - { 0xc006, "TLS_ECDHE_ECDSA_WITH_NULL_SHA", NULL }, - { 0xc007, "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", NULL }, - { 0xc008, "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0xc009, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", NULL }, - { 0xc00a, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", NULL }, - { 0xc00b, "TLS_ECDH_RSA_WITH_NULL_SHA", NULL }, - { 0xc00c, "TLS_ECDH_RSA_WITH_RC4_128_SHA", NULL }, - { 0xc00d, "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0xc00e, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", NULL }, - { 0xc00f, "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", NULL }, - { 0xc010, "TLS_ECDHE_RSA_WITH_NULL_SHA", NULL }, - { 0xc011, "TLS_ECDHE_RSA_WITH_RC4_128_SHA", NULL }, - { 0xc012, "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0xc013, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", NULL }, - { 0xc014, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", NULL }, - { 0xc015, "TLS_ECDH_anon_WITH_NULL_SHA", NULL }, - { 0xc016, "TLS_ECDH_anon_WITH_RC4_128_SHA", NULL }, - { 0xc017, "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0xc018, "TLS_ECDH_anon_WITH_AES_128_CBC_SHA", NULL }, - { 0xc019, "TLS_ECDH_anon_WITH_AES_256_CBC_SHA", NULL }, - { 0xc01a, "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0xc01b, "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0xc01c, "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0xc01d, "TLS_SRP_SHA_WITH_AES_128_CBC_SHA", NULL }, - { 0xc01e, "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA", NULL }, - { 0xc01f, "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA", NULL }, - { 0xc020, "TLS_SRP_SHA_WITH_AES_256_CBC_SHA", NULL }, - { 0xc021, "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA", NULL }, - { 0xc022, "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA", NULL }, - { 0xc023, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "ECDHE-ECDSA-AES128-SHA256" }, - { 0xc024, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "ECDHE-ECDSA-AES256-SHA384" }, - { 0xc025, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", "ECDH-ECDSA-AES128-SHA256" }, - { 0xc026, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384", "ECDH-ECDSA-AES256-SHA384" }, - { 0xc027, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "ECDHE-RSA-AES128-SHA256" }, - { 0xc028, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", "ECDHE-RSA-AES256-SHA384" }, - { 0xc029, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", "ECDH-RSA-AES128-SHA256" }, - { 0xc02a, "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384", "ECDH-RSA-AES256-SHA384" }, - { 0xc02b, "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "ECDHE-ECDSA-AES128-GCM-SHA256" }, - { 0xc02c, "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "ECDHE-ECDSA-AES256-GCM-SHA384" }, - { 0xc02d, "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", "ECDH-ECDSA-AES128-GCM-SHA256" }, - { 0xc02e, "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", "ECDH-ECDSA-AES256-GCM-SHA384" }, - { 0xc02f, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "ECDHE-RSA-AES128-GCM-SHA256" }, - { 0xc030, "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "ECDHE-RSA-AES256-GCM-SHA384" }, - { 0xc031, "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", "ECDH-RSA-AES128-GCM-SHA256" }, - { 0xc032, "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", "ECDH-RSA-AES256-GCM-SHA384" }, - { 0xc033, "TLS_ECDHE_PSK_WITH_RC4_128_SHA", NULL }, - { 0xc034, "TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA", NULL }, - { 0xc035, "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA", NULL }, - { 0xc036, "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA", NULL }, - { 0xc037, "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256", NULL }, - { 0xc038, "TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384", NULL }, - { 0xc039, "TLS_ECDHE_PSK_WITH_NULL_SHA", NULL }, - { 0xc03a, "TLS_ECDHE_PSK_WITH_NULL_SHA256", NULL }, - { 0xc03b, "TLS_ECDHE_PSK_WITH_NULL_SHA384", NULL }, - { 0xc03c, "TLS_RSA_WITH_ARIA_128_CBC_SHA256", NULL }, - { 0xc03d, "TLS_RSA_WITH_ARIA_256_CBC_SHA384", NULL }, - { 0xc03e, "TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256", NULL }, - { 0xc03f, "TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384", NULL }, - { 0xc040, "TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256", NULL }, - { 0xc041, "TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384", NULL }, - { 0xc042, "TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256", NULL }, - { 0xc043, "TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384", NULL }, - { 0xc044, "TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256", NULL }, - { 0xc045, "TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384", NULL }, - { 0xc046, "TLS_DH_anon_WITH_ARIA_128_CBC_SHA256", NULL }, - { 0xc047, "TLS_DH_anon_WITH_ARIA_256_CBC_SHA384", NULL }, - { 0xc048, "TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256", NULL }, - { 0xc049, "TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384", NULL }, - { 0xc04a, "TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256", NULL }, - { 0xc04b, "TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384", NULL }, - { 0xc04c, "TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256", NULL }, - { 0xc04d, "TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384", NULL }, - { 0xc04e, "TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256", NULL }, - { 0xc04f, "TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384", NULL }, - { 0xc050, "TLS_RSA_WITH_ARIA_128_GCM_SHA256", NULL }, - { 0xc051, "TLS_RSA_WITH_ARIA_256_GCM_SHA384", NULL }, - { 0xc052, "TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256", NULL }, - { 0xc053, "TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384", NULL }, - { 0xc054, "TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256", NULL }, - { 0xc055, "TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384", NULL }, - { 0xc056, "TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256", NULL }, - { 0xc057, "TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384", NULL }, - { 0xc058, "TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256", NULL }, - { 0xc059, "TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384", NULL }, - { 0xc05a, "TLS_DH_anon_WITH_ARIA_128_GCM_SHA256", NULL }, - { 0xc05b, "TLS_DH_anon_WITH_ARIA_256_GCM_SHA384", NULL }, - { 0xc05c, "TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256", NULL }, - { 0xc05d, "TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384", NULL }, - { 0xc05e, "TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256", NULL }, - { 0xc05f, "TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384", NULL }, - { 0xc060, "TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256", NULL }, - { 0xc061, "TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384", NULL }, - { 0xc062, "TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256", NULL }, - { 0xc063, "TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384", NULL }, - { 0xc064, "TLS_PSK_WITH_ARIA_128_CBC_SHA256", NULL }, - { 0xc065, "TLS_PSK_WITH_ARIA_256_CBC_SHA384", NULL }, - { 0xc066, "TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256", NULL }, - { 0xc067, "TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384", NULL }, - { 0xc068, "TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256", NULL }, - { 0xc069, "TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384", NULL }, - { 0xc06a, "TLS_PSK_WITH_ARIA_128_GCM_SHA256", NULL }, - { 0xc06b, "TLS_PSK_WITH_ARIA_256_GCM_SHA384", NULL }, - { 0xc06c, "TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256", NULL }, - { 0xc06d, "TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384", NULL }, - { 0xc06e, "TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256", NULL }, - { 0xc06f, "TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384", NULL }, - { 0xc070, "TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256", NULL }, - { 0xc071, "TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384", NULL }, - { 0xc072, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", NULL }, - { 0xc073, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", NULL }, - { 0xc074, "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", NULL }, - { 0xc075, "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", NULL }, - { 0xc076, "TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", NULL }, - { 0xc077, "TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384", NULL }, - { 0xc078, "TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256", NULL }, - { 0xc079, "TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384", NULL }, - { 0xc07a, "TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256", NULL }, - { 0xc07b, "TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384", NULL }, - { 0xc07c, "TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256", NULL }, - { 0xc07d, "TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384", NULL }, - { 0xc07e, "TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256", NULL }, - { 0xc07f, "TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384", NULL }, - { 0xc080, "TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256", NULL }, - { 0xc081, "TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384", NULL }, - { 0xc082, "TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256", NULL }, - { 0xc083, "TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384", NULL }, - { 0xc084, "TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256", NULL }, - { 0xc085, "TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384", NULL }, - { 0xc086, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256", NULL }, - { 0xc087, "TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384", NULL }, - { 0xc088, "TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256", NULL }, - { 0xc089, "TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384", NULL }, - { 0xc08a, "TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256", NULL }, - { 0xc08b, "TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384", NULL }, - { 0xc08c, "TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256", NULL }, - { 0xc08d, "TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384", NULL }, - { 0xc08e, "TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256", NULL }, - { 0xc08f, "TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384", NULL }, - { 0xc090, "TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256", NULL }, - { 0xc091, "TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384", NULL }, - { 0xc092, "TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256", NULL }, - { 0xc093, "TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384", NULL }, - { 0xc094, "TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256", NULL }, - { 0xc095, "TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384", NULL }, - { 0xc096, "TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", NULL }, - { 0xc097, "TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", NULL }, - { 0xc098, "TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256", NULL }, - { 0xc099, "TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384", NULL }, - { 0xc09a, "TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", NULL }, - { 0xc09b, "TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", NULL }, - { 0xc09c, "TLS_RSA_WITH_AES_128_CCM", NULL }, - { 0xc09d, "TLS_RSA_WITH_AES_256_CCM", NULL }, - { 0xc09e, "TLS_DHE_RSA_WITH_AES_128_CCM", NULL }, - { 0xc09f, "TLS_DHE_RSA_WITH_AES_256_CCM", NULL }, - { 0xc0a0, "TLS_RSA_WITH_AES_128_CCM_8", NULL }, - { 0xc0a1, "TLS_RSA_WITH_AES_256_CCM_8", NULL }, - { 0xc0a2, "TLS_DHE_RSA_WITH_AES_128_CCM_8", NULL }, - { 0xc0a3, "TLS_DHE_RSA_WITH_AES_256_CCM_8", NULL }, - { 0xc0a4, "TLS_PSK_WITH_AES_128_CCM", NULL }, - { 0xc0a5, "TLS_PSK_WITH_AES_256_CCM", NULL }, - { 0xc0a6, "TLS_DHE_PSK_WITH_AES_128_CCM", NULL }, - { 0xc0a7, "TLS_DHE_PSK_WITH_AES_256_CCM", NULL }, - { 0xc0a8, "TLS_PSK_WITH_AES_128_CCM_8", NULL }, - { 0xc0a9, "TLS_PSK_WITH_AES_256_CCM_8", NULL }, - { 0xc0aa, "TLS_PSK_DHE_WITH_AES_128_CCM_8", NULL }, - { 0xc0ab, "TLS_PSK_DHE_WITH_AES_256_CCM_8", NULL }, - { 0xcca8, "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "ECDHE-RSA-CHACHA20-POLY1305" }, - { 0xcca9, "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", "ECDHE-ECDSA-CHACHA20-POLY1305" }, - { 0xccaa, "TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "DHE-RSA-CHACHA20-POLY1305" }, - { 0xccab, "TLS_PSK_WITH_CHACHA20_POLY1305_SHA256", "PSK-CHACHA20-POLY1305" }, - { 0xccac, "TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256", "ECDHE-PSK-CHACHA20-POLY1305" }, - { 0xccad, "TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256", "DHE-PSK-CHACHA20-POLY1305" }, - { 0xccae, "TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256", "RSA-PSK-CHACHA20-POLY1305" }, - { 0xfefe, "SSL_RSA_FIPS_WITH_DES_CBC_SHA", NULL }, - { 0xfeff, "SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA", NULL }, -}; - -typedef struct { - apr_uint16_t id; - const rustls_supported_ciphersuite *rustls_suite; -} rustls_cipher_t; - -tls_proto_conf_t *tls_proto_init(apr_pool_t *pool, server_rec *s) -{ - tls_proto_conf_t *conf; - tls_cipher_t *cipher; - const rustls_supported_ciphersuite *rustls_suite; - rustls_cipher_t *rcipher; - apr_uint16_t id; - apr_size_t i; - - (void)s; - conf = apr_pcalloc(pool, sizeof(*conf)); - - conf->supported_versions = apr_array_make(pool, 3, sizeof(apr_uint16_t)); - /* Until we can look that up at crustls, we assume what we currently know */ - APR_ARRAY_PUSH(conf->supported_versions, apr_uint16_t) = TLS_VERSION_1_2; - APR_ARRAY_PUSH(conf->supported_versions, apr_uint16_t) = TLS_VERSION_1_3; - - conf->known_ciphers_by_name = apr_hash_make(pool); - conf->known_ciphers_by_id = apr_hash_make(pool); - for (i = 0; i < TLS_DIM(KNOWN_CIPHERS); ++i) { - cipher = &KNOWN_CIPHERS[i]; - apr_hash_set(conf->known_ciphers_by_id, &cipher->id, sizeof(apr_uint16_t), cipher); - apr_hash_set(conf->known_ciphers_by_name, cipher->name, APR_HASH_KEY_STRING, cipher); - if (cipher->alias) { - apr_hash_set(conf->known_ciphers_by_name, cipher->alias, APR_HASH_KEY_STRING, cipher); - } - } - - conf->supported_cipher_ids = apr_array_make(pool, 10, sizeof(apr_uint16_t)); - conf->rustls_ciphers_by_id = apr_hash_make(pool); - i = 0; - while ((rustls_suite = rustls_all_ciphersuites_get_entry(i++))) { - id = rustls_supported_ciphersuite_get_suite(rustls_suite); - rcipher = apr_pcalloc(pool, sizeof(*rcipher)); - rcipher->id = id; - rcipher->rustls_suite = rustls_suite; - APR_ARRAY_PUSH(conf->supported_cipher_ids, apr_uint16_t) = id; - apr_hash_set(conf->rustls_ciphers_by_id, &rcipher->id, sizeof(apr_uint16_t), rcipher); - - } - - return conf; -} - -const char *tls_proto_get_cipher_names( - tls_proto_conf_t *conf, const apr_array_header_t *ciphers, apr_pool_t *pool) -{ - apr_array_header_t *names; - int n; - - names = apr_array_make(pool, ciphers->nelts, sizeof(const char*)); - for (n = 0; n < ciphers->nelts; ++n) { - apr_uint16_t id = APR_ARRAY_IDX(ciphers, n, apr_uint16_t); - APR_ARRAY_PUSH(names, const char *) = tls_proto_get_cipher_name(conf, id, pool); - } - return apr_array_pstrcat(pool, names, ':'); -} - -apr_status_t tls_proto_pre_config(apr_pool_t *pool, apr_pool_t *ptemp) -{ - (void)pool; - (void)ptemp; - return APR_SUCCESS; -} - -apr_status_t tls_proto_post_config(apr_pool_t *pool, apr_pool_t *ptemp, server_rec *s) -{ - tls_conf_server_t *sc = tls_conf_server_get(s); - tls_proto_conf_t *conf = sc->global->proto; - - (void)pool; - if (APLOGdebug(s)) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(10314) - "tls ciphers supported: %s", - tls_proto_get_cipher_names(conf, conf->supported_cipher_ids, ptemp)); - } - return APR_SUCCESS; -} - -static apr_status_t get_uint16_from(const char *name, const char *prefix, apr_uint16_t *pint) -{ - apr_size_t plen = strlen(prefix); - if (strlen(name) == plen+4 && !strncmp(name, prefix, plen)) { - /* may be a hex notation cipher id */ - char *end = NULL; - apr_int64_t code = apr_strtoi64(name + plen, &end, 16); - if ((!end || !*end) && code && code <= APR_UINT16_MAX) { - *pint = (apr_uint16_t)code; - return APR_SUCCESS; - } - } - return APR_ENOENT; -} - -apr_uint16_t tls_proto_get_version_by_name(tls_proto_conf_t *conf, const char *name) -{ - apr_uint16_t version; - (void)conf; - if (!apr_strnatcasecmp(name, "TLSv1.2")) { - return TLS_VERSION_1_2; - } - else if (!apr_strnatcasecmp(name, "TLSv1.3")) { - return TLS_VERSION_1_3; - } - if (APR_SUCCESS == get_uint16_from(name, "TLSv0x", &version)) { - return version; - } - return 0; -} - -const char *tls_proto_get_version_name( - tls_proto_conf_t *conf, apr_uint16_t id, apr_pool_t *pool) -{ - (void)conf; - switch (id) { - case TLS_VERSION_1_2: - return "TLSv1.2"; - case TLS_VERSION_1_3: - return "TLSv1.3"; - default: - return apr_psprintf(pool, "TLSv0x%04x", id); - } -} - -apr_array_header_t *tls_proto_create_versions_plus( - tls_proto_conf_t *conf, apr_uint16_t min_version, apr_pool_t *pool) -{ - apr_array_header_t *versions = apr_array_make(pool, 3, sizeof(apr_uint16_t)); - apr_uint16_t version; - int i; - - for (i = 0; i < conf->supported_versions->nelts; ++i) { - version = APR_ARRAY_IDX(conf->supported_versions, i, apr_uint16_t); - if (version >= min_version) { - APR_ARRAY_PUSH(versions, apr_uint16_t) = version; - } - } - return versions; -} - -int tls_proto_is_cipher_supported(tls_proto_conf_t *conf, apr_uint16_t cipher) -{ - return tls_util_array_uint16_contains(conf->supported_cipher_ids, cipher); -} - -apr_status_t tls_proto_get_cipher_by_name( - tls_proto_conf_t *conf, const char *name, apr_uint16_t *pcipher) -{ - tls_cipher_t *cipher = apr_hash_get(conf->known_ciphers_by_name, name, APR_HASH_KEY_STRING); - if (cipher) { - *pcipher = cipher->id; - return APR_SUCCESS; - } - return get_uint16_from(name, "TLS_CIPHER_0x", pcipher); -} - -const char *tls_proto_get_cipher_name( - tls_proto_conf_t *conf, apr_uint16_t id, apr_pool_t *pool) -{ - tls_cipher_t *cipher = apr_hash_get(conf->known_ciphers_by_id, &id, sizeof(apr_uint16_t)); - if (cipher) { - return cipher->name; - } - return apr_psprintf(pool, "TLS_CIPHER_0x%04x", id); -} - -apr_array_header_t *tls_proto_get_rustls_suites( - tls_proto_conf_t *conf, const apr_array_header_t *ids, apr_pool_t *pool) -{ - apr_array_header_t *suites; - rustls_cipher_t *rcipher; - apr_uint16_t id; - int i; - - suites = apr_array_make(pool, ids->nelts, sizeof(const rustls_supported_ciphersuite*)); - for (i = 0; i < ids->nelts; ++i) { - id = APR_ARRAY_IDX(ids, i, apr_uint16_t); - rcipher = apr_hash_get(conf->rustls_ciphers_by_id, &id, sizeof(apr_uint16_t)); - if (rcipher) { - APR_ARRAY_PUSH(suites, const rustls_supported_ciphersuite *) = rcipher->rustls_suite; - } - } - return suites; -} diff --git a/modules/tls/tls_proto.h b/modules/tls/tls_proto.h deleted file mode 100644 index a3fe881dba..0000000000 --- a/modules/tls/tls_proto.h +++ /dev/null @@ -1,124 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef tls_proto_h -#define tls_proto_h - -#include "tls_util.h" - - -#define TLS_VERSION_1_2 0x0303 -#define TLS_VERSION_1_3 0x0304 - -/** - * Specification of a TLS cipher by name, possible alias and its 16 bit value - * as assigned by IANA. - */ -typedef struct { - apr_uint16_t id; /* IANA 16-bit assigned value as used on the wire */ - const char *name; /* IANA given name of the cipher */ - const char *alias; /* Optional, commonly known alternate name */ -} tls_cipher_t; - -/** - * TLS protocol related definitions constructed - * by querying crustls lib. - */ -typedef struct tls_proto_conf_t tls_proto_conf_t; -struct tls_proto_conf_t { - apr_array_header_t *supported_versions; /* supported protocol versions (apr_uint16_t) */ - apr_hash_t *known_ciphers_by_name; /* hash by name of known tls_cipher_t* */ - apr_hash_t *known_ciphers_by_id; /* hash by id of known tls_cipher_t* */ - apr_hash_t *rustls_ciphers_by_id; /* hash by id of rustls rustls_supported_ciphersuite* */ - apr_array_header_t *supported_cipher_ids; /* cipher ids (apr_uint16_t) supported by rustls */ - const rustls_root_cert_store *native_roots; -}; - -/** - * Create and populate the protocol configuration. - */ -tls_proto_conf_t *tls_proto_init(apr_pool_t *p, server_rec *s); - -/** - * Called during pre-config phase to start initialization - * of the tls protocol configuration. - */ -apr_status_t tls_proto_pre_config(apr_pool_t *pool, apr_pool_t *ptemp); - -/** - * Called during post-config phase to conclude the initialization - * of the tls protocol configuration. - */ -apr_status_t tls_proto_post_config(apr_pool_t *p, apr_pool_t *ptemp, server_rec *s); - -/** - * Get the TLS protocol identifier (as used on the wire) for the TLS - * protocol of the given name. Returns 0 if protocol is unknown. - */ -apr_uint16_t tls_proto_get_version_by_name(tls_proto_conf_t *conf, const char *name); - -/** - * Get the name of the protocol version identified by its identifier. This - * will return the name from the protocol configuration or, if unknown, create - * the string `TLSv0x%04x` from the 16bit identifier. - */ -const char *tls_proto_get_version_name( - tls_proto_conf_t *conf, apr_uint16_t id, apr_pool_t *pool); - -/** - * Create an array of the given TLS protocol version identifier `min_version` - * and all supported new ones. The array carries apr_uint16_t values. - */ -apr_array_header_t *tls_proto_create_versions_plus( - tls_proto_conf_t *conf, apr_uint16_t min_version, apr_pool_t *pool); - -/** - * Get a TLS cipher spec by name/alias. - */ -apr_status_t tls_proto_get_cipher_by_name( - tls_proto_conf_t *conf, const char *name, apr_uint16_t *pcipher); - -/** - * Return != 0 iff the cipher is supported by the rustls library. - */ -int tls_proto_is_cipher_supported(tls_proto_conf_t *conf, apr_uint16_t cipher); - -/** - * Get the name of a TLS cipher for the IANA assigned 16bit value. This will - * return the name in the protocol configuration, if the cipher is known, and - * create the string `TLS_CIPHER_0x%04x` for the 16bit cipher value. - */ -const char *tls_proto_get_cipher_name( - tls_proto_conf_t *conf, apr_uint16_t cipher, apr_pool_t *pool); - -/** - * Get the concatenated names with ':' as separator of all TLS cipher identifiers - * as given in `ciphers`. - * @param conf the TLS protocol configuration - * @param ciphers the 16bit values of the TLS ciphers - * @param pool to use for allocation the string. - */ -const char *tls_proto_get_cipher_names( - tls_proto_conf_t *conf, const apr_array_header_t *ciphers, apr_pool_t *pool); - -/** - * Convert an array of TLS cipher 16bit identifiers into the `rustls_supported_ciphersuite` - * instances that can be passed to crustls in session configurations. - * Any cipher identifier not supported by rustls we be silently omitted. - */ -apr_array_header_t *tls_proto_get_rustls_suites( - tls_proto_conf_t *conf, const apr_array_header_t *ids, apr_pool_t *pool); - -#endif /* tls_proto_h */ diff --git a/modules/tls/tls_util.c b/modules/tls/tls_util.c deleted file mode 100644 index 9eac212815..0000000000 --- a/modules/tls/tls_util.c +++ /dev/null @@ -1,367 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include "tls_proto.h" -#include "tls_util.h" - - -extern module AP_MODULE_DECLARE_DATA tls_module; -APLOG_USE_MODULE(tls); - - -tls_data_t tls_data_from_str(const char *s) -{ - tls_data_t d; - d.data = (const unsigned char*)s; - d.len = s? strlen(s) : 0; - return d; -} - -tls_data_t tls_data_assign_copy(apr_pool_t *p, const tls_data_t *d) -{ - tls_data_t copy; - copy.data = apr_pmemdup(p, d->data, d->len); - copy.len = d->len; - return copy; -} - -tls_data_t *tls_data_copy(apr_pool_t *p, const tls_data_t *d) -{ - tls_data_t *copy; - copy = apr_pcalloc(p, sizeof(*copy)); - *copy = tls_data_assign_copy(p, d); - return copy; -} - -const char *tls_data_to_str(apr_pool_t *p, const tls_data_t *d) -{ - char *s = apr_pcalloc(p, d->len+1); - memcpy(s, d->data, d->len); - return s; -} - -apr_status_t tls_util_rustls_error( - apr_pool_t *p, rustls_result rr, const char **perr_descr) -{ - if (perr_descr) { - char buffer[HUGE_STRING_LEN]; - apr_size_t len = 0; - - rustls_error(rr, buffer, sizeof(buffer), &len); - *perr_descr = apr_pstrndup(p, buffer, len); - } - return APR_EGENERAL; -} - -int tls_util_is_file( - apr_pool_t *p, const char *fpath) -{ - apr_finfo_t finfo; - - return (fpath != NULL - && apr_stat(&finfo, fpath, APR_FINFO_TYPE|APR_FINFO_SIZE, p) == 0 - && finfo.filetype == APR_REG); -} - -apr_status_t tls_util_file_load( - apr_pool_t *p, const char *fpath, apr_size_t min_len, apr_size_t max_len, tls_data_t *data) -{ - apr_finfo_t finfo; - apr_status_t rv; - apr_file_t *f = NULL; - unsigned char *buffer; - apr_size_t len; - const char *err = NULL; - tls_data_t *d; - - rv = apr_stat(&finfo, fpath, APR_FINFO_TYPE|APR_FINFO_SIZE, p); - if (APR_SUCCESS != rv) { - err = "cannot stat"; goto cleanup; - } - if (finfo.filetype != APR_REG) { - err = "not a plain file"; - rv = APR_EINVAL; goto cleanup; - } - if (finfo.size > LONG_MAX) { - err = "file is too large"; - rv = APR_EINVAL; goto cleanup; - } - len = (apr_size_t)finfo.size; - if (len < min_len || len > max_len) { - err = "file size not in allowed range"; - rv = APR_EINVAL; goto cleanup; - } - d = apr_pcalloc(p, sizeof(*d)); - buffer = apr_pcalloc(p, len+1); /* keep it NUL terminated in any case */ - rv = apr_file_open(&f, fpath, APR_FOPEN_READ, 0, p); - if (APR_SUCCESS != rv) { - err = "error opening"; goto cleanup; - } - rv = apr_file_read(f, buffer, &len); - if (APR_SUCCESS != rv) { - err = "error reading"; goto cleanup; - } -cleanup: - if (f) apr_file_close(f); - if (APR_SUCCESS == rv) { - data->data = buffer; - data->len = len; - } - else { - memset(data, 0, sizeof(*data)); - ap_log_perror(APLOG_MARK, APLOG_ERR, rv, p, APLOGNO(10361) - "Failed to load file %s: %s", fpath, err? err: "-"); - } - return rv; -} - -int tls_util_array_uint16_contains(const apr_array_header_t* a, apr_uint16_t n) -{ - int i; - for (i = 0; i < a->nelts; ++i) { - if (APR_ARRAY_IDX(a, i, apr_uint16_t) == n) return 1; - } - return 0; -} - -const apr_array_header_t *tls_util_array_uint16_remove( - apr_pool_t *pool, const apr_array_header_t* from, const apr_array_header_t* others) -{ - apr_array_header_t *na = NULL; - apr_uint16_t id; - int i, j; - - for (i = 0; i < from->nelts; ++i) { - id = APR_ARRAY_IDX(from, i, apr_uint16_t); - if (tls_util_array_uint16_contains(others, id)) { - if (na == NULL) { - /* first removal, make a new result array, copy elements before */ - na = apr_array_make(pool, from->nelts, sizeof(apr_uint16_t)); - for (j = 0; j < i; ++j) { - APR_ARRAY_PUSH(na, apr_uint16_t) = APR_ARRAY_IDX(from, j, apr_uint16_t); - } - } - } - else if (na) { - APR_ARRAY_PUSH(na, apr_uint16_t) = id; - } - } - return na? na : from; -} - -apr_status_t tls_util_brigade_transfer( - apr_bucket_brigade *dest, apr_bucket_brigade *src, apr_off_t length, - apr_off_t *pnout) -{ - apr_bucket *b; - apr_off_t remain = length; - apr_status_t rv = APR_SUCCESS; - const char *ign; - apr_size_t ilen; - - *pnout = 0; - while (!APR_BRIGADE_EMPTY(src)) { - b = APR_BRIGADE_FIRST(src); - - if (APR_BUCKET_IS_METADATA(b)) { - APR_BUCKET_REMOVE(b); - APR_BRIGADE_INSERT_TAIL(dest, b); - } - else { - if (remain == (apr_off_t)b->length) { - /* fall through */ - } - else if (remain <= 0) { - goto cleanup; - } - else { - if (b->length == ((apr_size_t)-1)) { - rv= apr_bucket_read(b, &ign, &ilen, APR_BLOCK_READ); - if (APR_SUCCESS != rv) goto cleanup; - } - if (remain < (apr_off_t)b->length) { - apr_bucket_split(b, (apr_size_t)remain); - } - } - APR_BUCKET_REMOVE(b); - APR_BRIGADE_INSERT_TAIL(dest, b); - remain -= (apr_off_t)b->length; - *pnout += (apr_off_t)b->length; - } - } -cleanup: - return rv; -} - -apr_status_t tls_util_brigade_copy( - apr_bucket_brigade *dest, apr_bucket_brigade *src, apr_off_t length, - apr_off_t *pnout) -{ - apr_bucket *b, *next; - apr_off_t remain = length; - apr_status_t rv = APR_SUCCESS; - const char *ign; - apr_size_t ilen; - - *pnout = 0; - for (b = APR_BRIGADE_FIRST(src); - b != APR_BRIGADE_SENTINEL(src); - b = next) { - next = APR_BUCKET_NEXT(b); - - if (APR_BUCKET_IS_METADATA(b)) { - /* fall through */ - } - else { - if (remain == (apr_off_t)b->length) { - /* fall through */ - } - else if (remain <= 0) { - goto cleanup; - } - else { - if (b->length == ((apr_size_t)-1)) { - rv = apr_bucket_read(b, &ign, &ilen, APR_BLOCK_READ); - if (APR_SUCCESS != rv) goto cleanup; - } - if (remain < (apr_off_t)b->length) { - apr_bucket_split(b, (apr_size_t)remain); - } - } - } - rv = apr_bucket_copy(b, &b); - if (APR_SUCCESS != rv) goto cleanup; - APR_BRIGADE_INSERT_TAIL(dest, b); - remain -= (apr_off_t)b->length; - *pnout += (apr_off_t)b->length; - } -cleanup: - return rv; -} - -apr_status_t tls_util_brigade_split_line( - apr_bucket_brigade *dest, apr_bucket_brigade *src, - apr_read_type_e block, apr_off_t length, - apr_off_t *pnout) -{ - apr_off_t nstart, nend; - apr_status_t rv; - - apr_brigade_length(dest, 0, &nstart); - rv = apr_brigade_split_line(dest, src, block, length); - if (APR_SUCCESS != rv) goto cleanup; - apr_brigade_length(dest, 0, &nend); - /* apr_brigade_split_line() has the nasty habit of leaving a 0-length bucket - * at the start of the brigade when it transferred the whole content. Get rid of it. - */ - if (!APR_BRIGADE_EMPTY(src)) { - apr_bucket *b = APR_BRIGADE_FIRST(src); - if (!APR_BUCKET_IS_METADATA(b) && 0 == b->length) { - APR_BUCKET_REMOVE(b); - apr_bucket_delete(b); - } - } -cleanup: - *pnout = (APR_SUCCESS == rv)? (nend - nstart) : 0; - return rv; -} - -int tls_util_name_matches_server(const char *name, server_rec *s) -{ - apr_array_header_t *names; - char **alias; - int i; - - if (!s || !s->server_hostname) return 0; - if (!strcasecmp(name, s->server_hostname)) return 1; - /* first the fast equality match, then the pattern wild_name matches */ - names = s->names; - if (!names) return 0; - alias = (char **)names->elts; - for (i = 0; i < names->nelts; ++i) { - if (alias[i] && !strcasecmp(name, alias[i])) return 1; - } - names = s->wild_names; - if (!names) return 0; - alias = (char **)names->elts; - for (i = 0; i < names->nelts; ++i) { - if (alias[i] && !ap_strcasecmp_match(name, alias[i])) return 1; - } - return 0; -} - -apr_size_t tls_util_bucket_print(char *buffer, apr_size_t bmax, - apr_bucket *b, const char *sep) -{ - apr_size_t off = 0; - if (sep && *sep) { - off += (size_t)apr_snprintf(buffer+off, bmax-off, "%s", sep); - } - - if (bmax <= off) { - return off; - } - else if (APR_BUCKET_IS_METADATA(b)) { - off += (size_t)apr_snprintf(buffer+off, bmax-off, "%s", b->type->name); - } - else if (bmax > off) { - off += (size_t)apr_snprintf(buffer+off, bmax-off, "%s[%ld]", - b->type->name, (long)(b->length == ((apr_size_t)-1)? - -1 : (int)b->length)); - } - return off; -} - -apr_size_t tls_util_bb_print(char *buffer, apr_size_t bmax, - const char *tag, const char *sep, - apr_bucket_brigade *bb) -{ - apr_size_t off = 0; - const char *sp = ""; - apr_bucket *b; - - if (bmax > 1) { - if (bb) { - memset(buffer, 0, bmax--); - off += (size_t)apr_snprintf(buffer+off, bmax-off, "%s(", tag); - for (b = APR_BRIGADE_FIRST(bb); - (bmax > off) && (b != APR_BRIGADE_SENTINEL(bb)); - b = APR_BUCKET_NEXT(b)) { - - off += tls_util_bucket_print(buffer+off, bmax-off, b, sp); - sp = " "; - } - if (bmax > off) { - off += (size_t)apr_snprintf(buffer+off, bmax-off, ")%s", sep); - } - } - else { - off += (size_t)apr_snprintf(buffer+off, bmax-off, "%s(null)%s", tag, sep); - } - } - return off; -} - diff --git a/modules/tls/tls_util.h b/modules/tls/tls_util.h deleted file mode 100644 index 18ae4dff4a..0000000000 --- a/modules/tls/tls_util.h +++ /dev/null @@ -1,157 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef tls_util_h -#define tls_util_h - -#define TLS_DIM(a) (sizeof(a)/sizeof(a[0])) - - -/** - * Simple struct to hold a range of bytes and its length together. - */ -typedef struct tls_data_t tls_data_t; -struct tls_data_t { - const unsigned char* data; - apr_size_t len; -}; - -/** - * Return a tls_data_t for a string. - */ -tls_data_t tls_data_from_str(const char *s); - -/** - * Create a copy of a tls_data_t using the given pool. - */ -tls_data_t *tls_data_copy(apr_pool_t *p, const tls_data_t *d); - -/** - * Return a copy of a tls_data_t bytes allocated from pool. - */ -tls_data_t tls_data_assign_copy(apr_pool_t *p, const tls_data_t *d); - -/** - * Convert the data bytes in `d` into a NUL-terminated string. - * There is no check if the data bytes already contain NUL. - */ -const char *tls_data_to_str(apr_pool_t *p, const tls_data_t *d); - -/** - * Return != 0 if fpath is a 'real' file. - */ -int tls_util_is_file(apr_pool_t *p, const char *fpath); - -/** - * Inspect a 'rustls_result', retrieve the error description for it and - * return the apr_status_t to use as our error status. - */ -apr_status_t tls_util_rustls_error(apr_pool_t *p, rustls_result rr, const char **perr_descr); - -/** - * Load up to `max_len` bytes into a buffer allocated from the pool. - * @return ARP_SUCCESS on successful load. - * APR_EINVAL when the file was not a regular file or is too large. - */ -apr_status_t tls_util_file_load( - apr_pool_t *p, const char *fpath, size_t min_len, size_t max_len, tls_data_t *data); - -/** - * Return != 0 iff the array of apr_uint16_t contains value n. - */ -int tls_util_array_uint16_contains(const apr_array_header_t* a, apr_uint16_t n); - -/** - * Remove all apr_uint16_t in `others` from array `from`. - * Returns the new array or, if no overlap was found, the `from` array unchanged. - */ -const apr_array_header_t *tls_util_array_uint16_remove( - apr_pool_t *pool, const apr_array_header_t* from, const apr_array_header_t* others); - -/** - * Transfer up to bytes from to , including all - * encountered meta data buckets. The transferred buckets/data are - * removed from . - * Return the actual byte count transferred in . - */ -apr_status_t tls_util_brigade_transfer( - apr_bucket_brigade *dest, apr_bucket_brigade *src, apr_off_t length, - apr_off_t *pnout); - -/** - * Copy up to bytes from to , including all - * encountered meta data buckets. remains semantically unchaanged, - * meaning there might have been buckets split or changed while reading - * their content. - * Return the actual byte count copied in . - */ -apr_status_t tls_util_brigade_copy( - apr_bucket_brigade *dest, apr_bucket_brigade *src, apr_off_t length, - apr_off_t *pnout); - -/** - * Get a line of max `length` bytes from `src` into `dest`. - * Return the number of bytes transferred in `pnout`. - */ -apr_status_t tls_util_brigade_split_line( - apr_bucket_brigade *dest, apr_bucket_brigade *src, - apr_read_type_e block, apr_off_t length, - apr_off_t *pnout); - -/** - * Return != 0 iff the given matches the configured 'ServerName' - * or one of the 'ServerAlias' name of , including wildcard patterns - * as understood by ap_strcasecmp_match(). - */ -int tls_util_name_matches_server(const char *name, server_rec *s); - - -/** - * Print a bucket's meta data (type and length) to the buffer. - * @return number of characters printed - */ -apr_size_t tls_util_bucket_print(char *buffer, apr_size_t bmax, - apr_bucket *b, const char *sep); - -/** - * Prints the brigade bucket types and lengths into the given buffer - * up to bmax. - * @return number of characters printed - */ -apr_size_t tls_util_bb_print(char *buffer, apr_size_t bmax, - const char *tag, const char *sep, - apr_bucket_brigade *bb); -/** - * Logs the bucket brigade (which bucket types with what length) - * to the log at the given level. - * @param c the connection to log for - * @param sid the stream identifier this brigade belongs to - * @param level the log level (as in APLOG_*) - * @param tag a short message text about the context - * @param bb the brigade to log - */ -#define tls_util_bb_log(c, level, tag, bb) \ -do { \ - char buffer[4 * 1024]; \ - const char *line = "(null)"; \ - apr_size_t len, bmax = sizeof(buffer)/sizeof(buffer[0]); \ - len = tls_util_bb_print(buffer, bmax, (tag), "", (bb)); \ - ap_log_cerror(APLOG_MARK, level, 0, (c), "bb_dump(%ld): %s", \ - ((c)->master? (c)->master->id : (c)->id), (len? buffer : line)); \ -} while(0) - - - -#endif /* tls_util_h */ diff --git a/modules/tls/tls_var.c b/modules/tls/tls_var.c deleted file mode 100644 index fa4ae2aed6..0000000000 --- a/modules/tls/tls_var.c +++ /dev/null @@ -1,397 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include "tls_conf.h" -#include "tls_core.h" -#include "tls_cert.h" -#include "tls_util.h" -#include "tls_var.h" -#include "tls_version.h" - - -extern module AP_MODULE_DECLARE_DATA tls_module; -APLOG_USE_MODULE(tls); - -typedef struct { - apr_pool_t *p; - server_rec *s; - conn_rec *c; - request_rec *r; - tls_conf_conn_t *cc; - const char *name; - const char *arg_s; - int arg_i; -} tls_var_lookup_ctx_t; - -typedef const char *var_lookup(const tls_var_lookup_ctx_t *ctx); - -static const char *var_get_ssl_protocol(const tls_var_lookup_ctx_t *ctx) -{ - return ctx->cc->tls_protocol_name; -} - -static const char *var_get_ssl_cipher(const tls_var_lookup_ctx_t *ctx) -{ - return ctx->cc->tls_cipher_name; -} - -static const char *var_get_sni_hostname(const tls_var_lookup_ctx_t *ctx) -{ - return ctx->cc->sni_hostname; -} - -static const char *var_get_version_interface(const tls_var_lookup_ctx_t *ctx) -{ - tls_conf_server_t *sc = tls_conf_server_get(ctx->s); - return sc->global->module_version; -} - -static const char *var_get_version_library(const tls_var_lookup_ctx_t *ctx) -{ - tls_conf_server_t *sc = tls_conf_server_get(ctx->s); - return sc->global->crustls_version; -} - -static const char *var_get_false(const tls_var_lookup_ctx_t *ctx) -{ - (void)ctx; - return "false"; -} - -static const char *var_get_null(const tls_var_lookup_ctx_t *ctx) -{ - (void)ctx; - return "NULL"; -} - -static const char *var_get_client_s_dn_cn(const tls_var_lookup_ctx_t *ctx) -{ - /* There is no support in the crustls/rustls/webpki APIs to - * parse X.509 certificates and extract information about - * subject, issuer, etc. */ - if (!ctx->cc->peer_certs || !ctx->cc->peer_certs->nelts) return NULL; - return "Not Implemented"; -} - -static const char *var_get_client_verify(const tls_var_lookup_ctx_t *ctx) -{ - return ctx->cc->peer_certs? "SUCCESS" : "NONE"; -} - -static const char *var_get_session_resumed(const tls_var_lookup_ctx_t *ctx) -{ - return ctx->cc->session_id_cache_hit? "Resumed" : "Initial"; -} - -static const char *var_get_client_cert(const tls_var_lookup_ctx_t *ctx) -{ - const rustls_certificate *cert; - const char *pem; - apr_status_t rv; - int cert_idx = 0; - - if (ctx->arg_s) { - if (strcmp(ctx->arg_s, "chain")) return NULL; - /* ctx->arg_i'th chain cert, which is in out list as */ - cert_idx = ctx->arg_i + 1; - } - if (!ctx->cc->peer_certs || cert_idx >= ctx->cc->peer_certs->nelts) return NULL; - cert = APR_ARRAY_IDX(ctx->cc->peer_certs, cert_idx, const rustls_certificate*); - if (APR_SUCCESS != (rv = tls_cert_to_pem(&pem, ctx->p, cert))) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, ctx->s, APLOGNO(10315) - "Failed to create client certificate PEM"); - return NULL; - } - return pem; -} - -static const char *var_get_server_cert(const tls_var_lookup_ctx_t *ctx) -{ - const rustls_certificate *cert; - const char *pem; - apr_status_t rv; - - if (!ctx->cc->key) return NULL; - cert = rustls_certified_key_get_certificate(ctx->cc->key, 0); - if (!cert) return NULL; - if (APR_SUCCESS != (rv = tls_cert_to_pem(&pem, ctx->p, cert))) { - ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, ctx->s, APLOGNO(10316) - "Failed to create server certificate PEM"); - return NULL; - } - return pem; -} - -typedef struct { - const char *name; - var_lookup* fn; - const char *arg_s; - int arg_i; -} var_def_t; - -static const var_def_t VAR_DEFS[] = { - { "SSL_PROTOCOL", var_get_ssl_protocol, NULL, 0 }, - { "SSL_CIPHER", var_get_ssl_cipher, NULL, 0 }, - { "SSL_TLS_SNI", var_get_sni_hostname, NULL, 0 }, - { "SSL_CLIENT_S_DN_CN", var_get_client_s_dn_cn, NULL, 0 }, - { "SSL_VERSION_INTERFACE", var_get_version_interface, NULL, 0 }, - { "SSL_VERSION_LIBRARY", var_get_version_library, NULL, 0 }, - { "SSL_SECURE_RENEG", var_get_false, NULL, 0 }, - { "SSL_COMPRESS_METHOD", var_get_null, NULL, 0 }, - { "SSL_CIPHER_EXPORT", var_get_false, NULL, 0 }, - { "SSL_CLIENT_VERIFY", var_get_client_verify, NULL, 0 }, - { "SSL_SESSION_RESUMED", var_get_session_resumed, NULL, 0 }, - { "SSL_CLIENT_CERT", var_get_client_cert, NULL, 0 }, - { "SSL_CLIENT_CHAIN_0", var_get_client_cert, "chain", 0 }, - { "SSL_CLIENT_CHAIN_1", var_get_client_cert, "chain", 1 }, - { "SSL_CLIENT_CHAIN_2", var_get_client_cert, "chain", 2 }, - { "SSL_CLIENT_CHAIN_3", var_get_client_cert, "chain", 3 }, - { "SSL_CLIENT_CHAIN_4", var_get_client_cert, "chain", 4 }, - { "SSL_CLIENT_CHAIN_5", var_get_client_cert, "chain", 5 }, - { "SSL_CLIENT_CHAIN_6", var_get_client_cert, "chain", 6 }, - { "SSL_CLIENT_CHAIN_7", var_get_client_cert, "chain", 7 }, - { "SSL_CLIENT_CHAIN_8", var_get_client_cert, "chain", 8 }, - { "SSL_CLIENT_CHAIN_9", var_get_client_cert, "chain", 9 }, - { "SSL_SERVER_CERT", var_get_server_cert, NULL, 0 }, -}; - -static const char *const TlsAlwaysVars[] = { - "SSL_TLS_SNI", - "SSL_PROTOCOL", - "SSL_CIPHER", - "SSL_CLIENT_S_DN_CN", -}; - -/* what mod_ssl defines, plus server cert and client cert DN and SAN entries */ -static const char *const StdEnvVars[] = { - "SSL_VERSION_INTERFACE", /* implemented: module version string */ - "SSL_VERSION_LIBRARY", /* implemented: crustls/rustls version string */ - "SSL_SECURE_RENEG", /* implemented: always "false" */ - "SSL_COMPRESS_METHOD", /* implemented: always "NULL" */ - "SSL_CIPHER_EXPORT", /* implemented: always "false" */ - "SSL_CIPHER_USEKEYSIZE", - "SSL_CIPHER_ALGKEYSIZE", - "SSL_CLIENT_VERIFY", /* implemented: always "SUCCESS" or "NONE" */ - "SSL_CLIENT_M_VERSION", - "SSL_CLIENT_M_SERIAL", - "SSL_CLIENT_V_START", - "SSL_CLIENT_V_END", - "SSL_CLIENT_V_REMAIN", - "SSL_CLIENT_S_DN", - "SSL_CLIENT_I_DN", - "SSL_CLIENT_A_KEY", - "SSL_CLIENT_A_SIG", - "SSL_CLIENT_CERT_RFC4523_CEA", - "SSL_SERVER_M_VERSION", - "SSL_SERVER_M_SERIAL", - "SSL_SERVER_V_START", - "SSL_SERVER_V_END", - "SSL_SERVER_S_DN", - "SSL_SERVER_I_DN", - "SSL_SERVER_A_KEY", - "SSL_SERVER_A_SIG", - "SSL_SESSION_ID", /* not implemented: highly sensitive data we do not expose */ - "SSL_SESSION_RESUMED", /* implemented: if our cache was hit successfully */ -}; - -/* Cert related variables, export when TLSOption ExportCertData is set */ -static const char *const ExportCertVars[] = { - "SSL_CLIENT_CERT", /* implemented: */ - "SSL_CLIENT_CHAIN_0", /* implemented: */ - "SSL_CLIENT_CHAIN_1", /* implemented: */ - "SSL_CLIENT_CHAIN_2", /* implemented: */ - "SSL_CLIENT_CHAIN_3", /* implemented: */ - "SSL_CLIENT_CHAIN_4", /* implemented: */ - "SSL_CLIENT_CHAIN_5", /* implemented: */ - "SSL_CLIENT_CHAIN_6", /* implemented: */ - "SSL_CLIENT_CHAIN_7", /* implemented: */ - "SSL_CLIENT_CHAIN_8", /* implemented: */ - "SSL_CLIENT_CHAIN_9", /* implemented: */ - "SSL_SERVER_CERT", /* implemented: */ -}; - -void tls_var_init_lookup_hash(apr_pool_t *pool, apr_hash_t *map) -{ - const var_def_t *def; - apr_size_t i; - - (void)pool; - for (i = 0; i < TLS_DIM(VAR_DEFS); ++i) { - def = &VAR_DEFS[i]; - apr_hash_set(map, def->name, APR_HASH_KEY_STRING, def); - } -} - -static const char *invoke(var_def_t* def, tls_var_lookup_ctx_t *ctx) -{ - if (TLS_CONN_ST_IS_ENABLED(ctx->cc)) { - const char *val = ctx->cc->subprocess_env? - apr_table_get(ctx->cc->subprocess_env, def->name) : NULL; - if (val && *val) return val; - ctx->arg_s = def->arg_s; - ctx->arg_i = def->arg_i; - return def->fn(ctx); - } - return NULL; -} - -static void set_var( - tls_var_lookup_ctx_t *ctx, apr_hash_t *lookups, apr_table_t *table) -{ - var_def_t* def = apr_hash_get(lookups, ctx->name, APR_HASH_KEY_STRING); - if (def) { - const char *val = invoke(def, ctx); - if (val && *val) { - apr_table_setn(table, ctx->name, val); - } - } -} - -const char *tls_var_lookup( - apr_pool_t *p, server_rec *s, conn_rec *c, request_rec *r, const char *name) -{ - const char *val = NULL; - tls_conf_server_t *sc; - var_def_t* def; - - ap_assert(p); - ap_assert(name); - s = s? s : (r? r->server : (c? c->base_server : NULL)); - c = c? c : (r? r->connection : NULL); - - sc = tls_conf_server_get(s? s : ap_server_conf); - def = apr_hash_get(sc->global->var_lookups, name, APR_HASH_KEY_STRING); - if (def) { - tls_var_lookup_ctx_t ctx; - ctx.p = p; - ctx.s = s; - ctx.c = c; - ctx.r = r; - ctx.cc = c? tls_conf_conn_get(c->master? c->master : c) : NULL; - ctx.cc = c? tls_conf_conn_get(c->master? c->master : c) : NULL; - ctx.name = name; - val = invoke(def, &ctx); - ap_log_cerror(APLOG_MARK, APLOG_TRACE3, 0, c, "tls lookup of var '%s' -> '%s'", name, val); - } - return val; -} - -static void add_vars(apr_table_t *env, conn_rec *c, server_rec *s, request_rec *r) -{ - tls_conf_server_t *sc; - tls_conf_dir_t *dc, *sdc; - tls_var_lookup_ctx_t ctx; - apr_size_t i; - int overlap; - - sc = tls_conf_server_get(s); - dc = r? tls_conf_dir_get(r) : tls_conf_dir_server_get(s); - sdc = r? tls_conf_dir_server_get(s): dc; - ctx.p = r? r->pool : c->pool; - ctx.s = s; - ctx.c = c; - ctx.r = r; - ctx.cc = tls_conf_conn_get(c->master? c->master : c); - /* Can we re-use the precomputed connection values? */ - overlap = (r && ctx.cc->subprocess_env && r->server == ctx.cc->server); - if (overlap) { - apr_table_overlap(env, ctx.cc->subprocess_env, APR_OVERLAP_TABLES_SET); - } - else { - apr_table_setn(env, "HTTPS", "on"); - for (i = 0; i < TLS_DIM(TlsAlwaysVars); ++i) { - ctx.name = TlsAlwaysVars[i]; - set_var(&ctx, sc->global->var_lookups, env); - } - } - if (dc->std_env_vars == TLS_FLAG_TRUE) { - for (i = 0; i < TLS_DIM(StdEnvVars); ++i) { - ctx.name = StdEnvVars[i]; - set_var(&ctx, sc->global->var_lookups, env); - } - } - else if (overlap && sdc->std_env_vars == TLS_FLAG_TRUE) { - /* Remove variables added on connection init that are disabled here */ - for (i = 0; i < TLS_DIM(StdEnvVars); ++i) { - apr_table_unset(env, StdEnvVars[i]); - } - } - if (dc->export_cert_vars == TLS_FLAG_TRUE) { - for (i = 0; i < TLS_DIM(ExportCertVars); ++i) { - ctx.name = ExportCertVars[i]; - set_var(&ctx, sc->global->var_lookups, env); - } - } - else if (overlap && sdc->std_env_vars == TLS_FLAG_TRUE) { - /* Remove variables added on connection init that are disabled here */ - for (i = 0; i < TLS_DIM(ExportCertVars); ++i) { - apr_table_unset(env, ExportCertVars[i]); - } - } - } - -apr_status_t tls_var_handshake_done(conn_rec *c) -{ - tls_conf_conn_t *cc; - tls_conf_server_t *sc; - apr_status_t rv = APR_SUCCESS; - - cc = tls_conf_conn_get(c); - if (!TLS_CONN_ST_IS_ENABLED(cc)) goto cleanup; - - sc = tls_conf_server_get(cc->server); - if (cc->peer_certs && sc->var_user_name) { - cc->user_name = tls_var_lookup(c->pool, cc->server, c, NULL, sc->var_user_name); - if (!cc->user_name) { - ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cc->server, APLOGNO(10317) - "Failed to set r->user to '%s'", sc->var_user_name); - } - } - cc->subprocess_env = apr_table_make(c->pool, 5); - add_vars(cc->subprocess_env, c, cc->server, NULL); - -cleanup: - return rv; -} - -int tls_var_request_fixup(request_rec *r) -{ - conn_rec *c = r->connection; - tls_conf_conn_t *cc; - - cc = tls_conf_conn_get(c->master? c->master : c); - if (!TLS_CONN_ST_IS_ENABLED(cc)) goto cleanup; - if (cc->user_name) { - /* why is r->user a char* and not const? */ - r->user = apr_pstrdup(r->pool, cc->user_name); - } - add_vars(r->subprocess_env, c, r->server, r); - -cleanup: - return DECLINED; -} diff --git a/modules/tls/tls_var.h b/modules/tls/tls_var.h deleted file mode 100644 index 2e8c0bb09b..0000000000 --- a/modules/tls/tls_var.h +++ /dev/null @@ -1,39 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef tls_var_h -#define tls_var_h - -void tls_var_init_lookup_hash(apr_pool_t *pool, apr_hash_t *map); - -/** - * Callback for installation in Apache's 'ssl_var_lookup' hook to provide - * SSL related variable lookups to other modules. - */ -const char *tls_var_lookup( - apr_pool_t *p, server_rec *s, conn_rec *c, request_rec *r, const char *name); - -/** - * A connection has been handshaked. Prepare commond TLS variables on this connection. - */ -apr_status_t tls_var_handshake_done(conn_rec *c); - -/** - * A request is ready for processing, add TLS variables r->subprocess_env if applicable. - * This is a hook function returning OK/DECLINED. - */ -int tls_var_request_fixup(request_rec *r); - -#endif /* tls_var_h */ \ No newline at end of file diff --git a/modules/tls/tls_version.h b/modules/tls/tls_version.h deleted file mode 100644 index bc9fb0bbb7..0000000000 --- a/modules/tls/tls_version.h +++ /dev/null @@ -1,39 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef mod_tls_version_h -#define mod_tls_version_h - -#undef PACKAGE_VERSION -#undef PACKAGE_TARNAME -#undef PACKAGE_STRING -#undef PACKAGE_NAME -#undef PACKAGE_BUGREPORT - -/** - * @macro - * Version number of the md module as c string - */ -#define MOD_TLS_VERSION "0.9.0" - -/** - * @macro - * Numerical representation of the version number of the md module - * release. This is a 24 bit number with 8 bits for major number, 8 bits - * for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203. - */ -#define MOD_TLS_VERSION_NUM 0x000900 - -#endif /* mod_md_md_version_h */ diff --git a/test/modules/tls/__init__.py b/test/modules/tls/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/test/modules/tls/conf.py b/test/modules/tls/conf.py deleted file mode 100644 index b34f746004..0000000000 --- a/test/modules/tls/conf.py +++ /dev/null @@ -1,68 +0,0 @@ -import os -from typing import List, Dict, Any - -from pyhttpd.conf import HttpdConf -from pyhttpd.env import HttpdTestEnv - - -class TlsTestConf(HttpdConf): - - def __init__(self, env: HttpdTestEnv, extras: Dict[str, Any] = None): - extras = extras if extras is not None else {} - super().__init__(env=env, extras=extras) - - def start_tls_vhost(self, domains: List[str], port=None, ssl_module=None): - if ssl_module is None: - if not self.env.has_shared_module("tls"): - ssl_module = "mod_ssl" - else: - ssl_module = 'mod_tls' - super().start_vhost(domains=domains, port=port, doc_root=f"htdocs/{domains[0]}", ssl_module=ssl_module) - - def end_tls_vhost(self): - self.end_vhost() - - def add_tls_vhosts(self, domains: List[str], port=None, ssl_module=None): - for domain in domains: - self.start_tls_vhost(domains=[domain], port=port, ssl_module=ssl_module) - self.end_tls_vhost() - - def add_md_vhosts(self, domains: List[str], port = None): - self.add([ - f"LoadModule md_module {self.env.libexec_dir}/mod_md.so", - "LogLevel md:debug", - ]) - for domain in domains: - self.add(f"") - for cred in self.env.ca.get_credentials_for_name(domain): - cert_file = os.path.relpath(cred.cert_file, self.env.server_dir) - pkey_file = os.path.relpath(cred.pkey_file, self.env.server_dir) if cred.pkey_file else cert_file - self.add([ - f" MDCertificateFile {cert_file}", - f" MDCertificateKeyFile {pkey_file}", - ]) - self.add("") - if self.env.has_shared_module("tls"): - ssl_module= "mod_tls" - else: - ssl_module= "mod_ssl" - super().add_vhost(domains=[domain], port=port, doc_root=f"htdocs/{domain}", - with_ssl=True, with_certificates=False, ssl_module=ssl_module) - - def add_md_base(self, domain: str): - self.add([ - f"LoadModule md_module {self.env.libexec_dir}/mod_md.so", - "LogLevel md:debug", - f"ServerName {domain}", - "MDBaseServer on", - ]) - self.add(f"TLSEngine {self.env.https_port}") - self.add(f"") - for cred in self.env.ca.get_credentials_for_name(domain): - cert_file = os.path.relpath(cred.cert_file, self.env.server_dir) - pkey_file = os.path.relpath(cred.pkey_file, self.env.server_dir) if cred.pkey_file else cert_file - self.add([ - f"MDCertificateFile {cert_file}", - f"MDCertificateKeyFile {pkey_file}", - ]) - self.add("") diff --git a/test/modules/tls/conftest.py b/test/modules/tls/conftest.py deleted file mode 100644 index 6f6f983cfd..0000000000 --- a/test/modules/tls/conftest.py +++ /dev/null @@ -1,38 +0,0 @@ -import logging -import os -import sys -import pytest - -sys.path.append(os.path.join(os.path.dirname(__file__), '../..')) - -from .env import TlsTestEnv - - -def pytest_report_header(config, startdir): - _x = config - _x = startdir - env = TlsTestEnv() - return "mod_tls [apache: {aversion}({prefix})]".format( - prefix=env.prefix, - aversion=env.get_httpd_version() - ) - - -@pytest.fixture(scope="package") -def env(pytestconfig) -> TlsTestEnv: - level = logging.INFO - console = logging.StreamHandler() - console.setLevel(level) - console.setFormatter(logging.Formatter('%(levelname)s: %(message)s')) - logging.getLogger('').addHandler(console) - logging.getLogger('').setLevel(level=level) - env = TlsTestEnv(pytestconfig=pytestconfig) - env.setup_httpd() - env.apache_access_log_clear() - env.httpd_error_log.clear_log() - return env - -@pytest.fixture(autouse=True, scope="package") -def _stop_package_scope(env): - yield - assert env.apache_stop() == 0 diff --git a/test/modules/tls/env.py b/test/modules/tls/env.py deleted file mode 100644 index efc4f0b247..0000000000 --- a/test/modules/tls/env.py +++ /dev/null @@ -1,199 +0,0 @@ -import inspect -import logging -import os -import re -import subprocess - -from datetime import timedelta, datetime -from typing import List, Optional, Dict, Tuple, Union - -from pyhttpd.certs import CertificateSpec -from pyhttpd.env import HttpdTestEnv, HttpdTestSetup -from pyhttpd.result import ExecResult - -log = logging.getLogger(__name__) - - -class TlsTestSetup(HttpdTestSetup): - - def __init__(self, env: 'HttpdTestEnv'): - super().__init__(env=env) - self.add_source_dir(os.path.dirname(inspect.getfile(TlsTestSetup))) - self.add_modules(["tls", "http2", "cgid", "watchdog", "proxy_http2"]) - - -class TlsCipher: - - def __init__(self, id: int, name: str, flavour: str, - min_version: float, max_version: float = None, - openssl: str = None): - self.id = id - self.name = name - self.flavour = flavour - self.min_version = min_version - self.max_version = max_version if max_version is not None else self.min_version - if openssl is None: - if name.startswith('TLS13_'): - openssl = re.sub(r'^TLS13_', 'TLS_', name) - else: - openssl = re.sub(r'^TLS_', '', name) - openssl = re.sub(r'_WITH_([^_]+)_', r'_\1_', openssl) - openssl = re.sub(r'_AES_(\d+)', r'_AES\1', openssl) - openssl = re.sub(r'(_POLY1305)_\S+$', r'\1', openssl) - openssl = re.sub(r'_', '-', openssl) - self.openssl_name = openssl - self.id_name = "TLS_CIPHER_0x{0:04x}".format(self.id) - - def __repr__(self): - return self.name - - def __str__(self): - return self.name - - -class TlsTestEnv(HttpdTestEnv): - - CURL_SUPPORTS_TLS_1_3 = None - - @classmethod - @property - def is_unsupported(cls): - mpm_module = f"mpm_{os.environ['MPM']}" if 'MPM' in os.environ else 'mpm_event' - return mpm_module == 'mpm_prefork' - - @classmethod - def curl_supports_tls_1_3(cls) -> bool: - if cls.CURL_SUPPORTS_TLS_1_3 is None: - # Unfortunately, there is no reliable, platform-independant - # way to verify that TLSv1.3 is properly supported by curl. - # - # p = subprocess.run(['curl', '--tlsv1.3', 'https://shouldneverexistreally'], - # stderr=subprocess.PIPE, stdout=subprocess.PIPE) - # return code 6 means the site could not be resolved, but the - # tls parameter was recognized - cls.CURL_SUPPORTS_TLS_1_3 = False - return cls.CURL_SUPPORTS_TLS_1_3 - - - # current rustls supported ciphers in their order of preference - # used to test cipher selection, see test_06_ciphers.py - RUSTLS_CIPHERS = [ - TlsCipher(0x1303, "TLS13_CHACHA20_POLY1305_SHA256", "CHACHA", 1.3), - TlsCipher(0x1302, "TLS13_AES_256_GCM_SHA384", "AES", 1.3), - TlsCipher(0x1301, "TLS13_AES_128_GCM_SHA256", "AES", 1.3), - TlsCipher(0xcca9, "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", "ECDSA", 1.2), - TlsCipher(0xcca8, "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "RSA", 1.2), - TlsCipher(0xc02c, "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "ECDSA", 1.2), - TlsCipher(0xc02b, "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "ECDSA", 1.2), - TlsCipher(0xc030, "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "RSA", 1.2), - TlsCipher(0xc02f, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "RSA", 1.2), - ] - - def __init__(self, pytestconfig=None): - super().__init__(pytestconfig=pytestconfig) - self._domain_a = "a.mod-tls.test" - self._domain_b = "b.mod-tls.test" - self.add_httpd_conf([ - f'', - ' AllowOverride None', - ' Require all granted', - ' AddHandler cgi-script .py', - ' Options +ExecCGI', - '', - f'', - ' AllowOverride None', - ' Require all granted', - ' AddHandler cgi-script .py', - ' Options +ExecCGI', - '', - f'', - ' ServerName localhost', - ' DocumentRoot "htdocs"', - '', - f'', - f' ServerName {self.domain_a}', - ' DocumentRoot "htdocs/a.mod-tls.test"', - '', - f'', - f' ServerName {self.domain_b}', - ' DocumentRoot "htdocs/b.mod-tls.test"', - '', - ]) - self.add_cert_specs([ - CertificateSpec(domains=[self.domain_a]), - CertificateSpec(domains=[self.domain_b], key_type='secp256r1', single_file=True), - CertificateSpec(domains=[self.domain_b], key_type='rsa4096'), - CertificateSpec(name="clientsX", sub_specs=[ - CertificateSpec(name="user1", client=True, single_file=True), - CertificateSpec(name="user2", client=True, single_file=True), - CertificateSpec(name="user_expired", client=True, - single_file=True, valid_from=timedelta(days=-91), - valid_to=timedelta(days=-1)), - ]), - CertificateSpec(name="clientsY", sub_specs=[ - CertificateSpec(name="user1", client=True, single_file=True), - ]), - CertificateSpec(name="user1", client=True, single_file=True), - ]) - if not HttpdTestEnv.has_shared_module("tls"): - self.add_httpd_log_modules(['ssl']) - else: - self.add_httpd_log_modules(['tls']) - - - def setup_httpd(self, setup: TlsTestSetup = None): - if setup is None: - setup = TlsTestSetup(env=self) - super().setup_httpd(setup=setup) - - @property - def domain_a(self) -> str: - return self._domain_a - - @property - def domain_b(self) -> str: - return self._domain_b - - def tls_get(self, domain, paths: Union[str, List[str]], options: List[str] = None, no_stdout_list = False) -> ExecResult: - if isinstance(paths, str): - paths = [paths] - urls = [f"https://{domain}:{self.https_port}{path}" for path in paths] - return self.curl_raw(urls=urls, options=options, no_stdout_list=no_stdout_list) - - def tls_get_json(self, domain: str, path: str, options=None): - r = self.tls_get(domain=domain, paths=path, options=options) - return r.json - - def run_diff(self, fleft: str, fright: str) -> ExecResult: - return self.run(['diff', '-u', fleft, fright]) - - def openssl(self, args: List[str]) -> ExecResult: - return self.run(['openssl'] + args) - - def openssl_client(self, domain, extra_args: List[str] = None) -> ExecResult: - args = ["s_client", "-CAfile", self.ca.cert_file, "-servername", domain, - "-connect", "localhost:{port}".format( - port=self.https_port - )] - if extra_args: - args.extend(extra_args) - args.extend([]) - return self.openssl(args) - - OPENSSL_SUPPORTED_PROTOCOLS = None - - @staticmethod - def openssl_supports_tls_1_3() -> bool: - if TlsTestEnv.OPENSSL_SUPPORTED_PROTOCOLS is None: - env = TlsTestEnv() - r = env.openssl(args=["ciphers", "-v"]) - protos = set() - ciphers = set() - for line in r.stdout.splitlines(): - m = re.match(r'^(\S+)\s+(\S+)\s+(.*)$', line) - if m: - ciphers.add(m.group(1)) - protos.add(m.group(2)) - TlsTestEnv.OPENSSL_SUPPORTED_PROTOCOLS = protos - TlsTestEnv.OPENSSL_SUPPORTED_CIPHERS = ciphers - return "TLSv1.3" in TlsTestEnv.OPENSSL_SUPPORTED_PROTOCOLS diff --git a/test/modules/tls/htdocs/a.mod-tls.test/index.json b/test/modules/tls/htdocs/a.mod-tls.test/index.json deleted file mode 100644 index ffc32cb275..0000000000 --- a/test/modules/tls/htdocs/a.mod-tls.test/index.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "domain": "a.mod-tls.test" -} \ No newline at end of file diff --git a/test/modules/tls/htdocs/a.mod-tls.test/vars.py b/test/modules/tls/htdocs/a.mod-tls.test/vars.py deleted file mode 100755 index bd520e27bb..0000000000 --- a/test/modules/tls/htdocs/a.mod-tls.test/vars.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python3 -import json -import os, sys -from urllib import parse -import multipart # https://github.com/andrew-d/python-multipart (`apt install python3-multipart`) - - -def get_request_params(): - oforms = {} - ofiles = {} - if "REQUEST_URI" in os.environ: - qforms = parse.parse_qs(parse.urlsplit(os.environ["REQUEST_URI"]).query) - for name, values in qforms.items(): - oforms[name] = values[0] - if "HTTP_CONTENT_TYPE" in os.environ: - ctype = os.environ["HTTP_CONTENT_TYPE"] - if ctype == "application/x-www-form-urlencoded": - qforms = parse.parse_qs(parse.urlsplit(sys.stdin.read()).query) - for name, values in qforms.items(): - oforms[name] = values[0] - elif ctype.startswith("multipart/"): - def on_field(field): - oforms[field.field_name] = field.value - def on_file(file): - ofiles[field.field_name] = field.value - multipart.parse_form(headers={"Content-Type": ctype}, input_stream=sys.stdin.buffer, on_field=on_field, on_file=on_file) - return oforms, ofiles - - -forms, files = get_request_params() - -jenc = json.JSONEncoder() - -def get_var(name: str, def_val: str = ""): - if name in os.environ: - return os.environ[name] - return def_val - -def get_json_var(name: str, def_val: str = ""): - var = get_var(name, def_val=def_val) - return jenc.encode(var) - - -name = forms['name'] if 'name' in forms else None - -print("Content-Type: application/json\n") -if name: - print(f"""{{ "{name}" : {get_json_var(name, '')}}}""") -else: - print(f"""{{ "https" : {get_json_var('HTTPS', '')}, - "host" : {get_json_var('SERVER_NAME', '')}, - "protocol" : {get_json_var('SERVER_PROTOCOL', '')}, - "ssl_protocol" : {get_json_var('SSL_PROTOCOL', '')}, - "ssl_cipher" : {get_json_var('SSL_CIPHER', '')} -}}""") - diff --git a/test/modules/tls/htdocs/b.mod-tls.test/dir1/vars.py b/test/modules/tls/htdocs/b.mod-tls.test/dir1/vars.py deleted file mode 100755 index b86a968b55..0000000000 --- a/test/modules/tls/htdocs/b.mod-tls.test/dir1/vars.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env python3 -import os - -def get_var(name: str, def_val: str = ""): - if name in os.environ: - return os.environ[name] - return def_val - -print("Content-Type: application/json") -print() -print("""{{ "https" : "{https}", - "host" : "{server_name}", - "protocol" : "{protocol}", - "ssl_protocol" : "{ssl_protocol}", - "ssl_cipher" : "{ssl_cipher}" -}}""".format( - https=get_var('HTTPS', ''), - server_name=get_var('SERVER_NAME', ''), - protocol=get_var('SERVER_PROTOCOL', ''), - ssl_protocol=get_var('SSL_PROTOCOL', ''), - ssl_cipher=get_var('SSL_CIPHER', ''), -)) - diff --git a/test/modules/tls/htdocs/b.mod-tls.test/index.json b/test/modules/tls/htdocs/b.mod-tls.test/index.json deleted file mode 100644 index e5d3ccf1fa..0000000000 --- a/test/modules/tls/htdocs/b.mod-tls.test/index.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "domain": "b.mod-tls.test" -} \ No newline at end of file diff --git a/test/modules/tls/htdocs/b.mod-tls.test/resp-jitter.py b/test/modules/tls/htdocs/b.mod-tls.test/resp-jitter.py deleted file mode 100755 index f7b134999d..0000000000 --- a/test/modules/tls/htdocs/b.mod-tls.test/resp-jitter.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env python3 -import random -import sys -import time -from datetime import timedelta - -random.seed() -to_write = total_len = random.randint(1, 10*1024*1024) - -sys.stdout.write("Content-Type: application/octet-stream\n") -sys.stdout.write(f"Content-Length: {total_len}\n") -sys.stdout.write("\n") -sys.stdout.flush() - -while to_write > 0: - len = random.randint(1, 1024*1024) - len = min(len, to_write) - sys.stdout.buffer.write(random.randbytes(len)) - to_write -= len - delay = timedelta(seconds=random.uniform(0.0, 0.5)) - time.sleep(delay.total_seconds()) -sys.stdout.flush() - diff --git a/test/modules/tls/htdocs/b.mod-tls.test/vars.py b/test/modules/tls/htdocs/b.mod-tls.test/vars.py deleted file mode 100755 index bd520e27bb..0000000000 --- a/test/modules/tls/htdocs/b.mod-tls.test/vars.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python3 -import json -import os, sys -from urllib import parse -import multipart # https://github.com/andrew-d/python-multipart (`apt install python3-multipart`) - - -def get_request_params(): - oforms = {} - ofiles = {} - if "REQUEST_URI" in os.environ: - qforms = parse.parse_qs(parse.urlsplit(os.environ["REQUEST_URI"]).query) - for name, values in qforms.items(): - oforms[name] = values[0] - if "HTTP_CONTENT_TYPE" in os.environ: - ctype = os.environ["HTTP_CONTENT_TYPE"] - if ctype == "application/x-www-form-urlencoded": - qforms = parse.parse_qs(parse.urlsplit(sys.stdin.read()).query) - for name, values in qforms.items(): - oforms[name] = values[0] - elif ctype.startswith("multipart/"): - def on_field(field): - oforms[field.field_name] = field.value - def on_file(file): - ofiles[field.field_name] = field.value - multipart.parse_form(headers={"Content-Type": ctype}, input_stream=sys.stdin.buffer, on_field=on_field, on_file=on_file) - return oforms, ofiles - - -forms, files = get_request_params() - -jenc = json.JSONEncoder() - -def get_var(name: str, def_val: str = ""): - if name in os.environ: - return os.environ[name] - return def_val - -def get_json_var(name: str, def_val: str = ""): - var = get_var(name, def_val=def_val) - return jenc.encode(var) - - -name = forms['name'] if 'name' in forms else None - -print("Content-Type: application/json\n") -if name: - print(f"""{{ "{name}" : {get_json_var(name, '')}}}""") -else: - print(f"""{{ "https" : {get_json_var('HTTPS', '')}, - "host" : {get_json_var('SERVER_NAME', '')}, - "protocol" : {get_json_var('SERVER_PROTOCOL', '')}, - "ssl_protocol" : {get_json_var('SSL_PROTOCOL', '')}, - "ssl_cipher" : {get_json_var('SSL_CIPHER', '')} -}}""") - diff --git a/test/modules/tls/htdocs/index.html b/test/modules/tls/htdocs/index.html deleted file mode 100644 index 3c07626144..0000000000 --- a/test/modules/tls/htdocs/index.html +++ /dev/null @@ -1,9 +0,0 @@ - - - mod_h2 test site generic - - -

    mod_h2 test site generic

    - - - diff --git a/test/modules/tls/htdocs/index.json b/test/modules/tls/htdocs/index.json deleted file mode 100644 index 6d456e0af5..0000000000 --- a/test/modules/tls/htdocs/index.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "domain": "localhost" -} \ No newline at end of file diff --git a/test/modules/tls/test_01_apache.py b/test/modules/tls/test_01_apache.py deleted file mode 100644 index cb6af6d461..0000000000 --- a/test/modules/tls/test_01_apache.py +++ /dev/null @@ -1,14 +0,0 @@ -import pytest - -from .conf import TlsTestConf - - -class TestApache: - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(self, env): - TlsTestConf(env=env).install() - assert env.apache_restart() == 0 - - def test_tls_01_apache_http(self, env): - assert env.is_live(env.http_base_url) diff --git a/test/modules/tls/test_02_conf.py b/test/modules/tls/test_02_conf.py deleted file mode 100644 index 88be80c3a6..0000000000 --- a/test/modules/tls/test_02_conf.py +++ /dev/null @@ -1,144 +0,0 @@ -import os -from datetime import timedelta - -import pytest - -from .conf import TlsTestConf - - -class TestConf: - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(self, env): - TlsTestConf(env=env).install() - assert env.apache_restart() == 0 - - @pytest.fixture(autouse=True, scope='function') - def _function_scope(self, env): - if env.is_live(timeout=timedelta(milliseconds=100)): - assert env.apache_stop() == 0 - - def test_tls_02_conf_cert_args_missing(self, env): - conf = TlsTestConf(env=env) - conf.add("TLSCertificate") - conf.install() - assert env.apache_fail() == 0 - - def test_tls_02_conf_cert_single_arg(self, env): - conf = TlsTestConf(env=env) - conf.add("TLSCertificate cert.pem") - conf.install() - assert env.apache_fail() == 0 - - def test_tls_02_conf_cert_file_missing(self, env): - conf = TlsTestConf(env=env) - conf.add("TLSCertificate cert.pem key.pem") - conf.install() - assert env.apache_fail() == 0 - - def test_tls_02_conf_cert_file_exist(self, env): - conf = TlsTestConf(env=env) - conf.add("TLSCertificate test-02-cert.pem test-02-key.pem") - conf.install() - for name in ["test-02-cert.pem", "test-02-key.pem"]: - with open(os.path.join(env.server_dir, name), "w") as fd: - fd.write("") - assert env.apache_fail() == 0 - - def test_tls_02_conf_cert_listen_missing(self, env): - conf = TlsTestConf(env=env) - conf.add("TLSEngine") - conf.install() - assert env.apache_fail() == 0 - - def test_tls_02_conf_cert_listen_wrong(self, env): - conf = TlsTestConf(env=env) - conf.add("TLSEngine ^^^^^") - conf.install() - assert env.apache_fail() == 0 - - @pytest.mark.parametrize("listen", [ - "443", - "129.168.178.188:443", - "[::]:443", - ]) - def test_tls_02_conf_cert_listen_valid(self, env, listen: str): - conf = TlsTestConf(env=env) - if not env.has_shared_module("tls"): - # Without cert/key openssl will complain - conf.add("SSLEngine on"); - conf.install() - assert env.apache_restart() == 1 - else: - conf.add("TLSEngine {listen}".format(listen=listen)) - conf.install() - assert env.apache_restart() == 0 - - def test_tls_02_conf_cert_listen_cert(self, env): - domain = env.domain_a - conf = TlsTestConf(env=env) - conf.add_tls_vhosts(domains=[domain]) - conf.install() - assert env.apache_restart() == 0 - - def test_tls_02_conf_proto_wrong(self, env): - conf = TlsTestConf(env=env) - conf.add("TLSProtocol wrong") - conf.install() - assert env.apache_fail() == 0 - - @pytest.mark.parametrize("proto", [ - "default", - "TLSv1.2+", - "TLSv1.3+", - "TLSv0x0303+", - ]) - def test_tls_02_conf_proto_valid(self, env, proto): - conf = TlsTestConf(env=env) - conf.add("TLSProtocol {proto}".format(proto=proto)) - conf.install() - assert env.apache_restart() == 0 - - def test_tls_02_conf_honor_wrong(self, env): - conf = TlsTestConf(env=env) - conf.add("TLSHonorClientOrder wrong") - conf.install() - assert env.apache_fail() == 0 - - @pytest.mark.parametrize("honor", [ - "on", - "OfF", - ]) - def test_tls_02_conf_honor_valid(self, env, honor: str): - conf = TlsTestConf(env=env) - conf.add("TLSHonorClientOrder {honor}".format(honor=honor)) - conf.install() - assert env.apache_restart() == 0 - - @pytest.mark.parametrize("cipher", [ - "default", - "TLS13_AES_128_GCM_SHA256:TLS13_AES_256_GCM_SHA384:TLS13_CHACHA20_POLY1305_SHA256", - "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:" - "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:" - "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", - """TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 \\ - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384\\ - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256""" - ]) - def test_tls_02_conf_cipher_valid(self, env, cipher): - conf = TlsTestConf(env=env) - conf.add("TLSCiphersPrefer {cipher}".format(cipher=cipher)) - conf.install() - assert env.apache_restart() == 0 - - @pytest.mark.parametrize("cipher", [ - "wrong", - "YOLO", - "TLS_NULL_WITH_NULL_NULLX", # not supported - "TLS_DHE_RSA_WITH_AES128_GCM_SHA256", # not supported - ]) - def test_tls_02_conf_cipher_wrong(self, env, cipher): - conf = TlsTestConf(env=env) - conf.add("TLSCiphersPrefer {cipher}".format(cipher=cipher)) - conf.install() - assert env.apache_fail() == 0 diff --git a/test/modules/tls/test_03_sni.py b/test/modules/tls/test_03_sni.py deleted file mode 100644 index cbd142afbc..0000000000 --- a/test/modules/tls/test_03_sni.py +++ /dev/null @@ -1,89 +0,0 @@ -from datetime import timedelta - -import pytest - -from .conf import TlsTestConf -from .env import TlsTestEnv - - -class TestSni: - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(self, env): - conf = TlsTestConf(env=env) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - - @pytest.fixture(autouse=True, scope='function') - def _function_scope(self, env): - pass - - def test_tls_03_sni_get_a(self, env): - # do we see the correct json for the domain_a? - data = env.tls_get_json(env.domain_a, "/index.json") - assert data == {'domain': env.domain_a} - - def test_tls_03_sni_get_b(self, env): - # do we see the correct json for the domain_a? - data = env.tls_get_json(env.domain_b, "/index.json") - assert data == {'domain': env.domain_b} - - def test_tls_03_sni_unknown(self, env): - # connection will be denied as cert does not cover this domain - domain_unknown = "unknown.test" - r = env.tls_get(domain_unknown, "/index.json") - assert r.exit_code != 0 - # - env.httpd_error_log.ignore_recent( - lognos = [ - "AH10353" # cannot decrypt peer's message - ] - ) - - def test_tls_03_sni_request_other_same_config(self, env): - # do we see the first vhost response for another domain with different certs? - r = env.tls_get(env.domain_a, "/index.json", options=[ - "-vvvv", "--header", "Host: {0}".format(env.domain_b) - ]) - # request is marked as misdirected - assert r.exit_code == 0 - assert r.json is None - assert r.response['status'] == 421 - # - env.httpd_error_log.ignore_recent( - lognos = [ - "AH10345" # Connection host selected via SNI and request have incompatible TLS configurations - ] - ) - - def test_tls_03_sni_request_other_other_honor(self, env): - # do we see the first vhost response for an unknown domain? - conf = TlsTestConf(env=env, extras={ - env.domain_a: "TLSProtocol TLSv1.2+", - env.domain_b: "TLSProtocol TLSv1.3+" - }) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - r = env.tls_get(env.domain_a, "/index.json", options=[ - "-vvvv", "--tls-max", "1.2", "--header", "Host: {0}".format(env.domain_b) - ]) - # request denied - assert r.exit_code == 0 - assert r.json is None - # - env.httpd_error_log.ignore_recent( - lognos = [ - "AH10345" # Connection host selected via SNI and request have incompatible TLS configurations - ] - ) - - @pytest.mark.skip('openssl behaviour changed on ventura, unreliable') - def test_tls_03_sni_bad_hostname(self, env): - # curl checks hostnames we give it, but the openssl client - # does not. Good for us, since we need to test it. - r = env.openssl(["s_client", "-connect", - "localhost:{0}".format(env.https_port), - "-servername", b'x\x2f.y'.decode()]) - assert r.exit_code == 1, r.stderr diff --git a/test/modules/tls/test_04_get.py b/test/modules/tls/test_04_get.py deleted file mode 100644 index 6944381307..0000000000 --- a/test/modules/tls/test_04_get.py +++ /dev/null @@ -1,67 +0,0 @@ -import os -import time -from datetime import timedelta - -import pytest - -from .env import TlsTestEnv -from .conf import TlsTestConf - - -def mk_text_file(fpath: str, lines: int): - t110 = 11 * "0123456789" - with open(fpath, "w") as fd: - for i in range(lines): - fd.write("{0:015d}: ".format(i)) # total 128 bytes per line - fd.write(t110) - fd.write("\n") - - -class TestGet: - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(self, env): - conf = TlsTestConf(env=env) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - docs_a = os.path.join(env.server_docs_dir, env.domain_a) - mk_text_file(os.path.join(docs_a, "1k.txt"), 8) - mk_text_file(os.path.join(docs_a, "10k.txt"), 80) - mk_text_file(os.path.join(docs_a, "100k.txt"), 800) - mk_text_file(os.path.join(docs_a, "1m.txt"), 8000) - mk_text_file(os.path.join(docs_a, "10m.txt"), 80000) - assert env.apache_restart() == 0 - - @pytest.mark.parametrize("fname, flen", [ - ("1k.txt", 1024), - ("10k.txt", 10*1024), - ("100k.txt", 100 * 1024), - ("1m.txt", 1000 * 1024), - ("10m.txt", 10000 * 1024), - ]) - def test_tls_04_get(self, env, fname, flen): - # do we see the correct json for the domain_a? - docs_a = os.path.join(env.server_docs_dir, env.domain_a) - r = env.tls_get(env.domain_a, "/{0}".format(fname)) - assert r.exit_code == 0 - assert len(r.stdout) == flen - pref = os.path.join(docs_a, fname) - pout = os.path.join(docs_a, "{0}.out".format(fname)) - with open(pout, 'w') as fd: - fd.write(r.stdout) - dr = env.run_diff(pref, pout) - assert dr.exit_code == 0, "differences found:\n{0}".format(dr.stdout) - - @pytest.mark.parametrize("fname, flen", [ - ("1k.txt", 1024), - ]) - def test_tls_04_double_get(self, env, fname, flen): - # we'd like to check that we can do >1 requests on the same connection - # however curl hides that from us, unless we analyze its verbose output - docs_a = os.path.join(env.server_docs_dir, env.domain_a) - r = env.tls_get(env.domain_a, no_stdout_list=True, paths=[ - "/{0}".format(fname), - "/{0}".format(fname) - ]) - assert r.exit_code == 0 - assert len(r.stdout) == 2*flen diff --git a/test/modules/tls/test_05_proto.py b/test/modules/tls/test_05_proto.py deleted file mode 100644 index d874a905ef..0000000000 --- a/test/modules/tls/test_05_proto.py +++ /dev/null @@ -1,64 +0,0 @@ -import time -from datetime import timedelta -import socket -from threading import Thread - -import pytest - -from .conf import TlsTestConf -from .env import TlsTestEnv - - -class TestProto: - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(self, env): - conf = TlsTestConf(env=env, extras={ - env.domain_a: "TLSProtocol TLSv1.3+", - env.domain_b: [ - "# the commonly used name", - "TLSProtocol TLSv1.2+", - "# the numeric one (yes, this is 1.2)", - "TLSProtocol TLSv0x0303+", - ], - }) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - - @pytest.fixture(autouse=True, scope='function') - def _function_scope(self, env): - pass - - def test_tls_05_proto_1_2(self, env): - r = env.tls_get(env.domain_b, "/index.json", options=["--tlsv1.2"]) - assert r.exit_code == 0, r.stderr - - @pytest.mark.skip('curl does not have TLSv1.3 on all platforms') - def test_tls_05_proto_1_3(self, env): - r = env.tls_get(env.domain_a, "/index.json", options=["--tlsv1.3", '-v']) - if True: # testing TlsTestEnv.curl_supports_tls_1_3() is unreliable (curl should support TLS1.3 nowadays..) - assert r.exit_code == 0, f'{r}' - else: - assert r.exit_code == 4, f'{r}' - - def test_tls_05_proto_close(self, env): - s = socket.create_connection(('localhost', env.https_port)) - time.sleep(0.1) - s.close() - - def test_tls_05_proto_ssl_close(self, env): - conf = TlsTestConf(env=env, extras={ - 'base': "LogLevel ssl:debug", - env.domain_a: "SSLProtocol TLSv1.3", - env.domain_b: "SSLProtocol TLSv1.2", - }) - for d in [env.domain_a, env.domain_b]: - conf.add_vhost(domains=[d], port=env.https_port) - conf.install() - assert env.apache_restart() == 0 - s = socket.create_connection(('localhost', env.https_port)) - time.sleep(0.1) - s.close() - - diff --git a/test/modules/tls/test_06_ciphers.py b/test/modules/tls/test_06_ciphers.py deleted file mode 100644 index 4bedd692ce..0000000000 --- a/test/modules/tls/test_06_ciphers.py +++ /dev/null @@ -1,212 +0,0 @@ -import re -from datetime import timedelta - -import pytest - -from .env import TlsTestEnv -from .conf import TlsTestConf - - -class TestCiphers: - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(self, env): - conf = TlsTestConf(env=env, extras={ - 'base': "TLSHonorClientOrder off", - }) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - - @pytest.fixture(autouse=True, scope='function') - def _function_scope(self, env): - pass - - def _get_protocol_cipher(self, output: str): - protocol = None - cipher = None - for line in output.splitlines(): - m = re.match(r'^\s+Protocol\s*:\s*(\S+)$', line) - if m: - protocol = m.group(1) - continue - m = re.match(r'^\s+Cipher\s*:\s*(\S+)$', line) - if m: - cipher = m.group(1) - return protocol, cipher - - def test_tls_06_ciphers_ecdsa(self, env): - ecdsa_1_2 = [c for c in env.RUSTLS_CIPHERS - if c.max_version == 1.2 and c.flavour == 'ECDSA'][0] - # client speaks only this cipher, see that it gets it - r = env.openssl_client(env.domain_b, extra_args=[ - "-cipher", ecdsa_1_2.openssl_name, "-tls1_2" - ]) - protocol, cipher = self._get_protocol_cipher(r.stdout) - assert protocol == "TLSv1.2", r.stdout - assert cipher == ecdsa_1_2.openssl_name, r.stdout - - def test_tls_06_ciphers_rsa(self, env): - rsa_1_2 = [c for c in env.RUSTLS_CIPHERS - if c.max_version == 1.2 and c.flavour == 'RSA'][0] - # client speaks only this cipher, see that it gets it - r = env.openssl_client(env.domain_b, extra_args=[ - "-cipher", rsa_1_2.openssl_name, "-tls1_2" - ]) - protocol, cipher = self._get_protocol_cipher(r.stdout) - assert protocol == "TLSv1.2", r.stdout - assert cipher == rsa_1_2.openssl_name, r.stdout - - @pytest.mark.parametrize("cipher", [ - c for c in TlsTestEnv.RUSTLS_CIPHERS if c.max_version == 1.2 and c.flavour == 'ECDSA' - ], ids=[ - c.name for c in TlsTestEnv.RUSTLS_CIPHERS if c.max_version == 1.2 and c.flavour == 'ECDSA' - ]) - def test_tls_06_ciphers_server_prefer_ecdsa(self, env, cipher): - # Select a ECSDA ciphers as preference and suppress all RSA ciphers. - # The last is not strictly necessary since rustls prefers ECSDA anyway - suppress_names = [c.name for c in env.RUSTLS_CIPHERS - if c.max_version == 1.2 and c.flavour == 'RSA'] - conf = TlsTestConf(env=env, extras={ - env.domain_b: [ - "TLSHonorClientOrder off", - f"TLSCiphersPrefer {cipher.name}", - f"TLSCiphersSuppress {':'.join(suppress_names)}", - ] - }) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - r = env.openssl_client(env.domain_b, extra_args=["-tls1_2"]) - client_proto, client_cipher = self._get_protocol_cipher(r.stdout) - assert client_proto == "TLSv1.2", r.stdout - assert client_cipher == cipher.openssl_name, r.stdout - - @pytest.mark.skip(reason="Wrong certified key selected by rustls") - # see - @pytest.mark.parametrize("cipher", [ - c for c in TlsTestEnv.RUSTLS_CIPHERS if c.max_version == 1.2 and c.flavour == 'RSA' - ], ids=[ - c.name for c in TlsTestEnv.RUSTLS_CIPHERS if c.max_version == 1.2 and c.flavour == 'RSA' - ]) - def test_tls_06_ciphers_server_prefer_rsa(self, env, cipher): - # Select a RSA ciphers as preference and suppress all ECDSA ciphers. - # The last is necessary since rustls prefers ECSDA and openssl leaks that it can. - suppress_names = [c.name for c in env.RUSTLS_CIPHERS - if c.max_version == 1.2 and c.flavour == 'ECDSA'] - conf = TlsTestConf(env=env, extras={ - env.domain_b: [ - "TLSHonorClientOrder off", - f"TLSCiphersPrefer {cipher.name}", - f"TLSCiphersSuppress {':'.join(suppress_names)}", - ] - }) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - r = env.openssl_client(env.domain_b, extra_args=["-tls1_2"]) - client_proto, client_cipher = self._get_protocol_cipher(r.stdout) - assert client_proto == "TLSv1.2", r.stdout - assert client_cipher == cipher.openssl_name, r.stdout - - @pytest.mark.skip(reason="Wrong certified key selected by rustls") - # see - @pytest.mark.parametrize("cipher", [ - c for c in TlsTestEnv.RUSTLS_CIPHERS if c.max_version == 1.2 and c.flavour == 'RSA' - ], ids=[ - c.openssl_name for c in TlsTestEnv.RUSTLS_CIPHERS if c.max_version == 1.2 and c.flavour == 'RSA' - ]) - def test_tls_06_ciphers_server_prefer_rsa_alias(self, env, cipher): - # same as above, but using openssl names for ciphers - suppress_names = [c.openssl_name for c in env.RUSTLS_CIPHERS - if c.max_version == 1.2 and c.flavour == 'ECDSA'] - conf = TlsTestConf(env=env, extras={ - env.domain_b: [ - "TLSHonorClientOrder off", - f"TLSCiphersPrefer {cipher.openssl_name}", - f"TLSCiphersSuppress {':'.join(suppress_names)}", - ] - }) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - r = env.openssl_client(env.domain_b, extra_args=["-tls1_2"]) - client_proto, client_cipher = self._get_protocol_cipher(r.stdout) - assert client_proto == "TLSv1.2", r.stdout - assert client_cipher == cipher.openssl_name, r.stdout - - @pytest.mark.skip(reason="Wrong certified key selected by rustls") - # see - @pytest.mark.parametrize("cipher", [ - c for c in TlsTestEnv.RUSTLS_CIPHERS if c.max_version == 1.2 and c.flavour == 'RSA' - ], ids=[ - c.id_name for c in TlsTestEnv.RUSTLS_CIPHERS if c.max_version == 1.2 and c.flavour == 'RSA' - ]) - def test_tls_06_ciphers_server_prefer_rsa_id(self, env, cipher): - # same as above, but using openssl names for ciphers - suppress_names = [c.id_name for c in env.RUSTLS_CIPHERS - if c.max_version == 1.2 and c.flavour == 'ECDSA'] - conf = TlsTestConf(env=env, extras={ - env.domain_b: [ - "TLSHonorClientOrder off", - f"TLSCiphersPrefer {cipher.id_name}", - f"TLSCiphersSuppress {':'.join(suppress_names)}", - ] - }) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - r = env.openssl_client(env.domain_b, extra_args=["-tls1_2"]) - client_proto, client_cipher = self._get_protocol_cipher(r.stdout) - assert client_proto == "TLSv1.2", r.stdout - assert client_cipher == cipher.openssl_name, r.stdout - - def test_tls_06_ciphers_pref_unknown(self, env): - conf = TlsTestConf(env=env, extras={ - env.domain_b: "TLSCiphersPrefer TLS_MY_SUPER_CIPHER:SSL_WHAT_NOT" - }) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() != 0 - # get a working config again, so that subsequent test cases do not stumble - conf = TlsTestConf(env=env) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - env.apache_restart() - - def test_tls_06_ciphers_pref_unsupported(self, env): - # a warning on preferring a known, but not supported cipher - conf = TlsTestConf(env=env, extras={ - env.domain_b: "TLSCiphersPrefer TLS_NULL_WITH_NULL_NULL" - }) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - if not conf.env.has_shared_module("tls"): - assert env.apache_restart() != 0 - else: - assert env.apache_restart() == 0 - # - env.httpd_error_log.ignore_recent( - lognos = [ - "AH10319" # Server has TLSCiphersPrefer configured that are not supported by rustls - ] - ) - - def test_tls_06_ciphers_supp_unknown(self, env): - conf = TlsTestConf(env=env, extras={ - env.domain_b: "TLSCiphersSuppress TLS_MY_SUPER_CIPHER:SSL_WHAT_NOT" - }) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() != 0 - - def test_tls_06_ciphers_supp_unsupported(self, env): - # no warnings on suppressing known, but not supported ciphers - conf = TlsTestConf(env=env, extras={ - env.domain_b: "TLSCiphersSuppress TLS_NULL_WITH_NULL_NULL" - }) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - if not conf.env.has_shared_module("tls"): - return - assert env.apache_restart() == 0 diff --git a/test/modules/tls/test_07_alpn.py b/test/modules/tls/test_07_alpn.py deleted file mode 100644 index 6017372020..0000000000 --- a/test/modules/tls/test_07_alpn.py +++ /dev/null @@ -1,45 +0,0 @@ -import re -from datetime import timedelta - -import pytest - -from .conf import TlsTestConf -from .env import TlsTestEnv - - -@pytest.mark.skipif(condition=TlsTestEnv.is_unsupported, reason="h2 not supported here") -class TestAlpn: - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(self, env): - conf = TlsTestConf(env=env, extras={ - env.domain_b: "Protocols h2 http/1.1" - }) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - - @pytest.fixture(autouse=True, scope='function') - def _function_scope(self, env): - pass - - def _get_protocol(self, output: str): - for line in output.splitlines(): - m = re.match(r'^\*\s+ALPN[:,] server accepted (to use\s+)?(.*)$', line) - if m: - return m.group(2) - return None - - def test_tls_07_alpn_get_a(self, env): - # do we see the correct json for the domain_a? - r = env.tls_get(env.domain_a, "/index.json", options=["-vvvvvv", "--http1.1"]) - assert r.exit_code == 0, r.stderr - protocol = self._get_protocol(r.stderr) - assert protocol == "http/1.1", r.stderr - - def test_tls_07_alpn_get_b(self, env): - # do we see the correct json for the domain_b? - r = env.tls_get(env.domain_b, "/index.json", options=["-vvvvvv"]) - assert r.exit_code == 0, r.stderr - protocol = self._get_protocol(r.stderr) - assert protocol == "h2", r.stderr diff --git a/test/modules/tls/test_08_vars.py b/test/modules/tls/test_08_vars.py deleted file mode 100644 index 0e3ee74d2d..0000000000 --- a/test/modules/tls/test_08_vars.py +++ /dev/null @@ -1,75 +0,0 @@ -import re - -import pytest - -from .conf import TlsTestConf -from .env import TlsTestEnv - - -class TestVars: - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(self, env): - conf = TlsTestConf(env=env, extras={ - 'base': [ - "TLSHonorClientOrder off", - "TLSOptions +StdEnvVars", - ] - }) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - - def test_tls_08_vars_root(self, env): - # in domain_b root, the StdEnvVars is switch on - exp_proto = "TLSv1.2" - if env.has_shared_module("tls"): - exp_cipher = "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384" - else: - exp_cipher = "ECDHE-ECDSA-AES256-GCM-SHA384" - options = [ '--tls-max', '1.2'] - r = env.tls_get(env.domain_b, "/vars.py", options=options) - assert r.exit_code == 0, r.stderr - assert r.json == { - 'https': 'on', - 'host': 'b.mod-tls.test', - 'protocol': 'HTTP/1.1', - 'ssl_protocol': exp_proto, - # this will vary by client potentially - 'ssl_cipher': exp_cipher, - } - - @pytest.mark.parametrize("name, value", [ - ("SERVER_NAME", "b.mod-tls.test"), - ("SSL_SESSION_RESUMED", "Initial"), - ("SSL_SECURE_RENEG", "false"), - ("SSL_COMPRESS_METHOD", "NULL"), - ("SSL_CIPHER_EXPORT", "false"), - ("SSL_CLIENT_VERIFY", "NONE"), - ]) - def test_tls_08_vars_const(self, env, name: str, value: str): - r = env.tls_get(env.domain_b, f"/vars.py?name={name}") - assert r.exit_code == 0, r.stderr - if env.has_shared_module("tls"): - assert r.json == {name: value}, r.stdout - else: - if name == "SSL_SECURE_RENEG": - value = "true" - assert r.json == {name: value}, r.stdout - - @pytest.mark.parametrize("name, pattern", [ - ("SSL_VERSION_INTERFACE", r'mod_tls/\d+\.\d+\.\d+'), - ("SSL_VERSION_LIBRARY", r'rustls-ffi/\d+\.\d+\.\d+/rustls/\d+\.\d+(\.\d+)?'), - ]) - def test_tls_08_vars_match(self, env, name: str, pattern: str): - r = env.tls_get(env.domain_b, f"/vars.py?name={name}") - assert r.exit_code == 0, r.stderr - assert name in r.json - if env.has_shared_module("tls"): - assert re.match(pattern, r.json[name]), r.json - else: - if name == "SSL_VERSION_INTERFACE": - pattern = r'mod_ssl/\d+\.\d+\.\d+' - else: - pattern = r'OpenSSL/\d+\.\d+\.\d+' - assert re.match(pattern, r.json[name]), r.json diff --git a/test/modules/tls/test_09_timeout.py b/test/modules/tls/test_09_timeout.py deleted file mode 100644 index 70cc89417a..0000000000 --- a/test/modules/tls/test_09_timeout.py +++ /dev/null @@ -1,43 +0,0 @@ -import socket -from datetime import timedelta - -import pytest - -from .conf import TlsTestConf - - -class TestTimeout: - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(self, env): - conf = TlsTestConf(env=env, extras={ - 'base': "RequestReadTimeout handshake=1", - }) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - - @pytest.fixture(autouse=True, scope='function') - def _function_scope(self, env): - pass - - def test_tls_09_timeout_handshake(self, env): - # in domain_b root, the StdEnvVars is switch on - s = socket.create_connection(('localhost', env.https_port)) - s.send(b'1234') - s.settimeout(0.0) - try: - s.recv(1024) - assert False, "able to recv() on a TLS connection before we sent a hello" - except BlockingIOError: - pass - s.settimeout(3.0) - try: - while True: - buf = s.recv(1024) - if not buf: - break - print("recv() -> {0}".format(buf)) - except (socket.timeout, BlockingIOError): - assert False, "socket not closed as handshake timeout should trigger" - s.close() diff --git a/test/modules/tls/test_10_session_id.py b/test/modules/tls/test_10_session_id.py deleted file mode 100644 index 848bc1a556..0000000000 --- a/test/modules/tls/test_10_session_id.py +++ /dev/null @@ -1,50 +0,0 @@ -import re -from typing import List - -import pytest - -from pyhttpd.result import ExecResult -from .env import TlsTestEnv -from .conf import TlsTestConf - - -class TestSessionID: - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(self, env): - conf = TlsTestConf(env=env) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - - def find_openssl_session_ids(self, r: ExecResult) -> List[str]: - ids = [] - for line in r.stdout.splitlines(): - m = re.match(r'^\s*Session-ID: (\S+)$', line) - if m: - ids.append(m.group(1)) - return ids - - def test_tls_10_session_id_12(self, env): - r = env.openssl_client(env.domain_b, extra_args=[ - "-reconnect", "-tls1_2" - ]) - session_ids = self.find_openssl_session_ids(r) - assert 1 < len(session_ids), "expected several session-ids: {0}, stderr={1}".format( - session_ids, r.stderr - ) - assert 1 == len(set(session_ids)), "sesion-ids should all be the same: {0}".format(session_ids) - - @pytest.mark.skipif(True or not TlsTestEnv.openssl_supports_tls_1_3(), - reason="openssl TLSv1.3 session storage test incomplete") - def test_tls_10_session_id_13(self, env): - r = env.openssl_client(env.domain_b, extra_args=[ - "-reconnect", "-tls1_3" - ]) - # openssl -reconnect closes connection immediately after the handhshake, so - # the Session data in TLSv1.3 is not seen and not found in its output. - # FIXME: how to check session data with TLSv1.3? - session_ids = self.find_openssl_session_ids(r) - assert 0 == len(session_ids), "expected no session-ids: {0}, stderr={1}".format( - session_ids, r.stdout - ) diff --git a/test/modules/tls/test_11_md.py b/test/modules/tls/test_11_md.py deleted file mode 100644 index 9d733db9d1..0000000000 --- a/test/modules/tls/test_11_md.py +++ /dev/null @@ -1,37 +0,0 @@ -import time -from datetime import timedelta - -import pytest - -from .conf import TlsTestConf - - -class TestMD: - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(self, env): - conf = TlsTestConf(env=env, extras={ - 'base': "LogLevel md:trace4" - }) - conf.add_md_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - - def test_tls_11_get_a(self, env): - # do we see the correct json for the domain_a? - data = env.tls_get_json(env.domain_a, "/index.json") - assert data == {'domain': env.domain_a} - - def test_tls_11_get_b(self, env): - # do we see the correct json for the domain_a? - data = env.tls_get_json(env.domain_b, "/index.json") - assert data == {'domain': env.domain_b} - - def test_tls_11_get_base(self, env): - # give the base server domain_a and lookup its index.json - conf = TlsTestConf(env=env) - conf.add_md_base(domain=env.domain_a) - conf.install() - assert env.apache_restart() == 0 - data = env.tls_get_json(env.domain_a, "/index.json") - assert data == {'domain': 'localhost'} diff --git a/test/modules/tls/test_12_cauth.py b/test/modules/tls/test_12_cauth.py deleted file mode 100644 index 14116091c6..0000000000 --- a/test/modules/tls/test_12_cauth.py +++ /dev/null @@ -1,235 +0,0 @@ -import os -from datetime import timedelta -from typing import Optional - -import pytest - -from pyhttpd.certs import Credentials -from .conf import TlsTestConf - - -@pytest.fixture -def clients_x(env): - return env.ca.get_first("clientsX") - - -@pytest.fixture -def clients_y(env): - return env.ca.get_first("clientsY") - - -@pytest.fixture -def cax_file(clients_x): - return os.path.join(os.path.dirname(clients_x.cert_file), "clientX-ca.pem") - - -@pytest.mark.skip(reason="client certs disabled") -class TestTLS: - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(self, env, clients_x, cax_file): - with open(cax_file, 'w') as fd: - fd.write("".join(open(clients_x.cert_file).readlines())) - fd.write("".join(open(env.ca.cert_file).readlines())) - - @pytest.fixture(autouse=True, scope='function') - def _function_scope(self, env): - if env.is_live(timeout=timedelta(milliseconds=100)): - assert env.apache_stop() == 0 - - def get_ssl_var(self, env, domain: str, cert: Optional[Credentials], name: str): - r = env.tls_get(domain, f"/vars.py?name={name}", options=[ - "--cert", cert.cert_file - ] if cert else []) - assert r.exit_code == 0, r.stderr - assert r.json, r.stderr + r.stdout - return r.json[name] if name in r.json else None - - def test_tls_12_set_ca_non_existing(self, env): - conf = TlsTestConf(env=env, extras={ - env.domain_a: "TLSClientCA xxx" - }) - conf.add_md_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 1 - - def test_tls_12_set_ca_existing(self, env, cax_file): - conf = TlsTestConf(env=env, extras={ - env.domain_a: f"TLSClientCA {cax_file}" - }) - conf.add_md_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - - def test_tls_12_set_auth_no_ca(self, env): - conf = TlsTestConf(env=env, extras={ - env.domain_a: "TLSClientCertificate required" - }) - conf.add_md_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - # will fail bc lacking clien CA - assert env.apache_restart() == 1 - - def test_tls_12_auth_option_std(self, env, cax_file, clients_x): - conf = TlsTestConf(env=env, extras={ - env.domain_b: [ - f"TLSClientCertificate required", - f"TLSClientCA {cax_file}", - "# TODO: TLSUserName SSL_CLIENT_S_DN_CN", - "TLSOptions +StdEnvVars", - ] - }) - conf.add_md_vhosts(domains=[env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - # should be denied - r = env.tls_get(domain=env.domain_b, paths="/index.json") - assert r.exit_code != 0, r.stdout - # should work - ccert = clients_x.get_first("user1") - data = env.tls_get_json(env.domain_b, "/index.json", options=[ - "--cert", ccert.cert_file - ]) - assert data == {'domain': env.domain_b} - r = env.tls_get(env.domain_b, "/vars.py?name=SSL_CLIENT_S_DN_CN") - assert r.exit_code != 0, "should have been prevented" - val = self.get_ssl_var(env, env.domain_b, ccert, "SSL_CLIENT_S_DN_CN") - assert val == 'Not Implemented' - # TODO - # val = self.get_ssl_var(env, env.domain_b, ccert, "REMOTE_USER") - # assert val == 'Not Implemented' - # not set on StdEnvVars, needs option ExportCertData - val = self.get_ssl_var(env, env.domain_b, ccert, "SSL_CLIENT_CERT") - assert val == "" - - def test_tls_12_auth_option_cert(self, env, test_ca, cax_file, clients_x): - conf = TlsTestConf(env=env, extras={ - env.domain_b: [ - "TLSClientCertificate required", - f"TLSClientCA {cax_file}", - "TLSOptions Defaults +ExportCertData", - ] - }) - conf.add_md_vhosts(domains=[env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - ccert = clients_x.get_first("user1") - val = self.get_ssl_var(env, env.domain_b, ccert, "SSL_CLIENT_CERT") - assert val == ccert.cert_pem.decode() - # no chain should be present - val = self.get_ssl_var(env, env.domain_b, ccert, "SSL_CLIENT_CHAIN_0") - assert val == '' - val = self.get_ssl_var(env, env.domain_b, ccert, "SSL_SERVER_CERT") - assert val - server_certs = test_ca.get_credentials_for_name(env.domain_b) - assert val in [c.cert_pem.decode() for c in server_certs] - - def test_tls_12_auth_ssl_optional(self, env, cax_file, clients_x): - domain = env.domain_b - conf = TlsTestConf(env=env, extras={ - domain: [ - "SSLVerifyClient optional", - "SSLVerifyDepth 2", - "SSLOptions +StdEnvVars +ExportCertData", - f"SSLCACertificateFile {cax_file}", - "SSLUserName SSL_CLIENT_S_DN", - ] - }) - conf.add_ssl_vhosts(domains=[domain]) - conf.install() - assert env.apache_restart() == 0 - # should work either way - data = env.tls_get_json(domain, "/index.json") - assert data == {'domain': domain} - # no client cert given, we expect the server variable to be empty - val = self.get_ssl_var(env, env.domain_b, None, "SSL_CLIENT_S_DN_CN") - assert val == '' - ccert = clients_x.get_first("user1") - data = env.tls_get_json(domain, "/index.json", options=[ - "--cert", ccert.cert_file - ]) - assert data == {'domain': domain} - val = self.get_ssl_var(env, env.domain_b, ccert, "SSL_CLIENT_S_DN_CN") - assert val == 'user1' - val = self.get_ssl_var(env, env.domain_b, ccert, "SSL_CLIENT_S_DN") - assert val == 'O=abetterinternet-mod_tls,OU=clientsX,CN=user1' - val = self.get_ssl_var(env, env.domain_b, ccert, "REMOTE_USER") - assert val == 'O=abetterinternet-mod_tls,OU=clientsX,CN=user1' - val = self.get_ssl_var(env, env.domain_b, ccert, "SSL_CLIENT_I_DN") - assert val == 'O=abetterinternet-mod_tls,OU=clientsX' - val = self.get_ssl_var(env, env.domain_b, ccert, "SSL_CLIENT_I_DN_CN") - assert val == '' - val = self.get_ssl_var(env, env.domain_b, ccert, "SSL_CLIENT_I_DN_OU") - assert val == 'clientsX' - val = self.get_ssl_var(env, env.domain_b, ccert, "SSL_CLIENT_CERT") - assert val == ccert.cert_pem.decode() - - def test_tls_12_auth_optional(self, env, cax_file, clients_x): - domain = env.domain_b - conf = TlsTestConf(env=env, extras={ - domain: [ - "TLSClientCertificate optional", - f"TLSClientCA {cax_file}", - ] - }) - conf.add_md_vhosts(domains=[domain]) - conf.install() - assert env.apache_restart() == 0 - # should work either way - data = env.tls_get_json(domain, "/index.json") - assert data == {'domain': domain} - # no client cert given, we expect the server variable to be empty - r = env.tls_get(domain, "/vars.py?name=SSL_CLIENT_S_DN_CN") - assert r.exit_code == 0, r.stderr - assert r.json == { - 'SSL_CLIENT_S_DN_CN': '', - }, r.stdout - data = env.tls_get_json(domain, "/index.json", options=[ - "--cert", clients_x.get_first("user1").cert_file - ]) - assert data == {'domain': domain} - r = env.tls_get(domain, "/vars.py?name=SSL_CLIENT_S_DN_CN", options=[ - "--cert", clients_x.get_first("user1").cert_file - ]) - # with client cert, we expect the server variable to show? Do we? - assert r.exit_code == 0, r.stderr - assert r.json == { - 'SSL_CLIENT_S_DN_CN': 'Not Implemented', - }, r.stdout - - def test_tls_12_auth_expired(self, env, cax_file, clients_x): - conf = TlsTestConf(env=env, extras={ - env.domain_b: [ - "TLSClientCertificate required", - f"TLSClientCA {cax_file}", - ] - }) - conf.add_md_vhosts(domains=[env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - # should not work - r = env.tls_get(domain=env.domain_b, paths="/index.json", options=[ - "--cert", clients_x.get_first("user_expired").cert_file - ]) - assert r.exit_code != 0 - - def test_tls_12_auth_other_ca(self, env, cax_file, clients_y): - conf = TlsTestConf(env=env, extras={ - env.domain_b: [ - "TLSClientCertificate required", - f"TLSClientCA {cax_file}", - ] - }) - conf.add_md_vhosts(domains=[env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - # should not work - r = env.tls_get(domain=env.domain_b, paths="/index.json", options=[ - "--cert", clients_y.get_first("user1").cert_file - ]) - assert r.exit_code != 0 - # This will work, as the CA root is present in the CA file - r = env.tls_get(domain=env.domain_b, paths="/index.json", options=[ - "--cert", env.ca.get_first("user1").cert_file - ]) - assert r.exit_code == 0 diff --git a/test/modules/tls/test_13_proxy.py b/test/modules/tls/test_13_proxy.py deleted file mode 100644 index 8bd305f718..0000000000 --- a/test/modules/tls/test_13_proxy.py +++ /dev/null @@ -1,40 +0,0 @@ -from datetime import timedelta - -import pytest - -from .conf import TlsTestConf - - -class TestProxy: - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(self, env): - conf = TlsTestConf(env=env, extras={ - 'base': "LogLevel proxy:trace1 proxy_http:trace1 ssl:trace1", - env.domain_b: [ - "ProxyPreserveHost on", - f'ProxyPass "/proxy/" "http://127.0.0.1:{env.http_port}/"', - f'ProxyPassReverse "/proxy/" "http://{env.domain_b}:{env.http_port}"', - ] - }) - # add vhosts a+b and a ssl proxy from a to b - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - - def test_tls_13_proxy_http_get(self, env): - data = env.tls_get_json(env.domain_b, "/proxy/index.json") - assert data == {'domain': env.domain_b} - - @pytest.mark.parametrize("name, value", [ - ("SERVER_NAME", "b.mod-tls.test"), - ("SSL_SESSION_RESUMED", ""), - ("SSL_SECURE_RENEG", ""), - ("SSL_COMPRESS_METHOD", ""), - ("SSL_CIPHER_EXPORT", ""), - ("SSL_CLIENT_VERIFY", ""), - ]) - def test_tls_13_proxy_http_vars(self, env, name: str, value: str): - r = env.tls_get(env.domain_b, f"/proxy/vars.py?name={name}") - assert r.exit_code == 0, r.stderr - assert r.json == {name: value}, r.stdout diff --git a/test/modules/tls/test_14_proxy_ssl.py b/test/modules/tls/test_14_proxy_ssl.py deleted file mode 100644 index 81cb4f31b0..0000000000 --- a/test/modules/tls/test_14_proxy_ssl.py +++ /dev/null @@ -1,125 +0,0 @@ -import re -import pytest - -from .conf import TlsTestConf -from .env import TlsTestEnv -from pyhttpd.env import HttpdTestEnv - - -class TestProxySSL: - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(self, env): - # add vhosts a+b and a ssl proxy from a to b - if not HttpdTestEnv.has_shared_module("tls"): - myoptions="SSLOptions +StdEnvVars" - myssl="mod_ssl" - else: - myoptions="TLSOptions +StdEnvVars" - myssl="mod_tls" - conf = TlsTestConf(env=env, extras={ - 'base': [ - "LogLevel proxy:trace1 proxy_http:trace1 ssl:trace1 proxy_http2:trace1", - f"", - " SSLProxyEngine on", - " SSLProxyVerify require", - f" SSLProxyCACertificateFile {env.ca.cert_file}", - " ProxyPreserveHost on", - "", - f"", - " ProxyPreserveHost on", - "", - f"", - " SSLProxyEngine on", - " SSLProxyVerify require", - f" SSLProxyCACertificateFile {env.ca.cert_file}", - " ProxyPreserveHost on", - "", - ], - env.domain_b: [ - "Protocols h2 http/1.1", - f'ProxyPass /proxy-ssl/ https://127.0.0.1:{env.https_port}/', - f'ProxyPass /proxy-local/ https://localhost:{env.https_port}/', - f'ProxyPass /proxy-h2-ssl/ h2://127.0.0.1:{env.https_port}/', - myoptions, - ], - }) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b], ssl_module=myssl) - conf.install() - assert env.apache_restart() == 0 - - def test_tls_14_proxy_ssl_get(self, env): - data = env.tls_get_json(env.domain_b, "/proxy-ssl/index.json") - assert data == {'domain': env.domain_b} - - def test_tls_14_proxy_ssl_get_local(self, env): - # does not work, since SSLProxy* not configured - data = env.tls_get_json(env.domain_b, "/proxy-local/index.json") - assert data is None - # - env.httpd_error_log.ignore_recent( - lognos = [ - "AH01961", # failed to enable ssl support [Hint: if using mod_ssl, see SSLProxyEngine] - "AH00961" # failed to enable ssl support (mod_proxy) - ] - ) - - @pytest.mark.skipif(condition=TlsTestEnv.is_unsupported, reason="h2 not supported here") - def test_tls_14_proxy_ssl_h2_get(self, env): - r = env.tls_get(env.domain_b, "/proxy-h2-ssl/index.json") - assert r.exit_code == 0 - assert r.json == {'domain': env.domain_b} - - @pytest.mark.parametrize("name, value", [ - ("SERVER_NAME", "b.mod-tls.test"), - ("SSL_SESSION_RESUMED", "Initial"), - ("SSL_SECURE_RENEG", "false"), - ("SSL_COMPRESS_METHOD", "NULL"), - ("SSL_CIPHER_EXPORT", "false"), - ("SSL_CLIENT_VERIFY", "NONE"), - ]) - def test_tls_14_proxy_ssl_vars_const(self, env, name: str, value: str): - if not HttpdTestEnv.has_shared_module("tls"): - return - r = env.tls_get(env.domain_b, f"/proxy-ssl/vars.py?name={name}") - assert r.exit_code == 0, r.stderr - assert r.json == {name: value}, r.stdout - - @pytest.mark.parametrize("name, value", [ - ("SERVER_NAME", "b.mod-tls.test"), - ("SSL_SESSION_RESUMED", "Initial"), - ("SSL_SECURE_RENEG", "true"), - ("SSL_COMPRESS_METHOD", "NULL"), - ("SSL_CIPHER_EXPORT", "false"), - ("SSL_CLIENT_VERIFY", "NONE"), - ]) - def test_tls_14_proxy_ssl_vars_const(self, env, name: str, value: str): - if HttpdTestEnv.has_shared_module("tls"): - return - r = env.tls_get(env.domain_b, f"/proxy-ssl/vars.py?name={name}") - assert r.exit_code == 0, r.stderr - assert r.json == {name: value}, r.stdout - - @pytest.mark.parametrize("name, pattern", [ - ("SSL_VERSION_INTERFACE", r'mod_tls/\d+\.\d+\.\d+'), - ("SSL_VERSION_LIBRARY", r'rustls-ffi/\d+\.\d+\.\d+/rustls/\d+\.\d+(\.\d+)?'), - ]) - def test_tls_14_proxy_ssl_vars_match(self, env, name: str, pattern: str): - if not HttpdTestEnv.has_shared_module("tls"): - return - r = env.tls_get(env.domain_b, f"/proxy-ssl/vars.py?name={name}") - assert r.exit_code == 0, r.stderr - assert name in r.json - assert re.match(pattern, r.json[name]), r.json - - @pytest.mark.parametrize("name, pattern", [ - ("SSL_VERSION_INTERFACE", r'mod_ssl/\d+\.\d+\.\d+'), - ("SSL_VERSION_LIBRARY", r'OpenSSL/\d+\.\d+\.\d+'), - ]) - def test_tls_14_proxy_ssl_vars_match(self, env, name: str, pattern: str): - if HttpdTestEnv.has_shared_module("tls"): - return - r = env.tls_get(env.domain_b, f"/proxy-ssl/vars.py?name={name}") - assert r.exit_code == 0, r.stderr - assert name in r.json - assert re.match(pattern, r.json[name]), r.json diff --git a/test/modules/tls/test_15_proxy_tls.py b/test/modules/tls/test_15_proxy_tls.py deleted file mode 100644 index 3fe6cfe478..0000000000 --- a/test/modules/tls/test_15_proxy_tls.py +++ /dev/null @@ -1,97 +0,0 @@ -from datetime import timedelta - -import pytest - -from .conf import TlsTestConf -from .env import TlsTestEnv -from pyhttpd.env import HttpdTestEnv - -@pytest.mark.skipif(condition=not HttpdTestEnv.has_shared_module("tls"), reason="no mod_tls available") - -class TestProxyTLS: - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(self, env): - # add vhosts a+b and a ssl proxy from a to b - conf = TlsTestConf(env=env, extras={ - 'base': [ - "LogLevel proxy:trace1 proxy_http:trace1 proxy_http2:trace2 http2:trace2 cgid:trace4", - "TLSProxyProtocol TLSv1.3+", - f"", - " TLSProxyEngine on", - f" TLSProxyCA {env.ca.cert_file}", - " TLSProxyProtocol TLSv1.2+", - " TLSProxyCiphersPrefer TLS13_AES_256_GCM_SHA384", - " TLSProxyCiphersSuppress TLS13_AES_128_GCM_SHA256", - " ProxyPreserveHost on", - "", - f"", - " ProxyPreserveHost on", - "", - f"", - " TLSProxyEngine on", - f" TLSProxyCA {env.ca.cert_file}", - " TLSProxyCiphersSuppress TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256", - " ProxyPreserveHost on", - "", - ], - env.domain_b: [ - "Protocols h2 http/1.1", - f"ProxyPass /proxy-tls/ https://127.0.0.1:{env.https_port}/", - f"ProxyPass /proxy-local/ https://localhost:{env.https_port}/", - f"ProxyPass /proxy-h2-tls/ h2://127.0.0.1:{env.https_port}/", - "TLSOptions +StdEnvVars", - ], - }) - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - - def test_tls_15_proxy_tls_get(self, env): - data = env.tls_get_json(env.domain_b, "/proxy-tls/index.json") - assert data == {'domain': env.domain_b} - - def test_tls_15_proxy_tls_get_local(self, env): - # does not work, since SSLProxy* not configured - data = env.tls_get_json(env.domain_b, "/proxy-local/index.json") - assert data is None - # - env.httpd_error_log.ignore_recent( - lognos = [ - "AH01961", # failed to enable ssl support [Hint: if using mod_ssl, see SSLProxyEngine] - "AH00961" # failed to enable ssl support (mod_proxy) - ] - ) - - @pytest.mark.skipif(condition=TlsTestEnv.is_unsupported, reason="h2 not supported here") - def test_tls_15_proxy_tls_h2_get(self, env): - r = env.tls_get(env.domain_b, "/proxy-h2-tls/index.json") - assert r.exit_code == 0 - assert r.json == {'domain': env.domain_b}, f"{r.stdout}" - - @pytest.mark.parametrize("name, value", [ - ("SERVER_NAME", "b.mod-tls.test"), - ("SSL_PROTOCOL", "TLSv1.3"), - ("SSL_CIPHER", "TLS_AES_256_GCM_SHA384"), - ("SSL_SESSION_RESUMED", "Initial"), - ("SSL_SECURE_RENEG", "false"), - ("SSL_COMPRESS_METHOD", "NULL"), - ("SSL_CIPHER_EXPORT", "false"), - ("SSL_CLIENT_VERIFY", "NONE"), - ]) - def test_tls_15_proxy_tls_h1_vars(self, env, name: str, value: str): - r = env.tls_get(env.domain_b, f"/proxy-tls/vars.py?name={name}") - assert r.exit_code == 0, r.stderr - assert r.json == {name: value}, r.stdout - - @pytest.mark.parametrize("name, value", [ - ("SERVER_NAME", "b.mod-tls.test"), - ("SSL_PROTOCOL", "TLSv1.3"), - ("SSL_CIPHER", "TLS_CHACHA20_POLY1305_SHA256"), - ("SSL_SESSION_RESUMED", "Initial"), - ]) - @pytest.mark.skipif(condition=TlsTestEnv.is_unsupported, reason="h2 not supported here") - def test_tls_15_proxy_tls_h2_vars(self, env, name: str, value: str): - r = env.tls_get(env.domain_b, f"/proxy-h2-tls/vars.py?name={name}") - assert r.exit_code == 0, r.stderr - assert r.json == {name: value}, r.stdout diff --git a/test/modules/tls/test_16_proxy_mixed.py b/test/modules/tls/test_16_proxy_mixed.py deleted file mode 100644 index 88b351fd94..0000000000 --- a/test/modules/tls/test_16_proxy_mixed.py +++ /dev/null @@ -1,50 +0,0 @@ -import time - -import pytest - -from .conf import TlsTestConf -from pyhttpd.env import HttpdTestEnv - -@pytest.mark.skipif(condition=not HttpdTestEnv.has_shared_module("tls"), reason="no mod_tls available") - - -class TestProxyMixed: - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(self, env): - conf = TlsTestConf(env=env, extras={ - 'base': [ - "LogLevel proxy:trace1 proxy_http:trace1 ssl:trace1 proxy_http2:trace1 http2:debug", - "ProxyPreserveHost on", - ], - env.domain_a: [ - "Protocols h2 http/1.1", - "TLSProxyEngine on", - f"TLSProxyCA {env.ca.cert_file}", - "", - f" ProxyPass h2://127.0.0.1:{env.https_port}/", - "", - ], - env.domain_b: [ - "SSLProxyEngine on", - "SSLProxyVerify require", - f"SSLProxyCACertificateFile {env.ca.cert_file}", - "", - f" ProxyPass https://127.0.0.1:{env.https_port}/", - "", - ], - }) - # add vhosts a+b and a ssl proxy from a to b - conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b]) - conf.install() - assert env.apache_restart() == 0 - - def test_tls_16_proxy_mixed_ssl_get(self, env, repeat): - data = env.tls_get_json(env.domain_b, "/proxy-ssl/index.json") - assert data == {'domain': env.domain_b} - - def test_tls_16_proxy_mixed_tls_get(self, env, repeat): - data = env.tls_get_json(env.domain_a, "/proxy-tls/index.json") - if data is None: - time.sleep(300) - assert data == {'domain': env.domain_a} diff --git a/test/modules/tls/test_17_proxy_machine_cert.py b/test/modules/tls/test_17_proxy_machine_cert.py deleted file mode 100644 index a5410d63ad..0000000000 --- a/test/modules/tls/test_17_proxy_machine_cert.py +++ /dev/null @@ -1,70 +0,0 @@ -import os - -import pytest - -from .conf import TlsTestConf -from pyhttpd.env import HttpdTestEnv - -@pytest.mark.skipif(condition=not HttpdTestEnv.has_shared_module("tls"), reason="no mod_tls available") -class TestProxyMachineCert: - - @pytest.fixture(autouse=True, scope='class') - def clients_x(cls, env): - return env.ca.get_first("clientsX") - - @pytest.fixture(autouse=True, scope='class') - def clients_y(cls, env): - return env.ca.get_first("clientsY") - - @pytest.fixture(autouse=True, scope='class') - def cax_file(cls, clients_x): - return os.path.join(os.path.dirname(clients_x.cert_file), "clientsX-ca.pem") - - @pytest.fixture(autouse=True, scope='class') - def _class_scope(cls, env, cax_file, clients_x): - # add vhosts a(tls)+b(ssl, port2) and a ssl proxy from a to b with a machine cert - # host b requires a client certificate - conf = TlsTestConf(env=env, extras={ - 'base': [ - "LogLevel proxy:trace1 proxy_http:trace1 ssl:trace4 proxy_http2:trace1", - "ProxyPreserveHost on", - f"Listen {env.proxy_port}", - ], - }) - conf.start_tls_vhost(domains=[env.domain_a], port=env.https_port) - conf.add([ - "Protocols h2 http/1.1", - "TLSProxyEngine on", - f"TLSProxyCA {env.ca.cert_file}", - f"TLSProxyMachineCertificate {clients_x.get_first('user1').cert_file}", - "", - f" ProxyPass https://127.0.0.1:{env.proxy_port}/", - "", - ]) - conf.end_tls_vhost() - conf.start_vhost(domains=[env.domain_a], port=env.proxy_port, - doc_root=f"htdocs/{env.domain_a}", with_ssl=True) - conf.add([ - "SSLVerifyClient require", - "SSLVerifyDepth 2", - "SSLOptions +StdEnvVars +ExportCertData", - f"SSLCACertificateFile {cax_file}", - "SSLUserName SSL_CLIENT_S_DN_CN" - ]) - conf.end_vhost() - conf.install() - assert env.apache_restart() == 0 - - def test_tls_17_proxy_machine_cert_get_a(self, env): - data = env.tls_get_json(env.domain_a, "/proxy-tls/index.json") - assert data == {'domain': env.domain_a} - - @pytest.mark.parametrize("name, value", [ - ("SERVER_NAME", "a.mod-tls.test"), - ("SSL_CLIENT_VERIFY", "SUCCESS"), - ("REMOTE_USER", "user1"), - ]) - def test_tls_17_proxy_machine_cert_vars(self, env, name: str, value: str): - r = env.tls_get(env.domain_a, f"/proxy-tls/vars.py?name={name}") - assert r.exit_code == 0, r.stderr - assert r.json == {name: value}, r.stdout diff --git a/test/travis_run_linux.sh b/test/travis_run_linux.sh index 373e6668ee..67d9d00505 100755 --- a/test/travis_run_linux.sh +++ b/test/travis_run_linux.sh @@ -215,14 +215,6 @@ if ! test -v SKIP_TESTING; then RV=$? fi - if test -v TEST_MOD_TLS -a $RV -eq 0; then - # Run mod_tls tests. The underlying librustls was build - # and installed before we configured the server (see top of file). - # This will be replaved once librustls is available as a package. - py.test-3 test/modules/tls - RV=$? - fi - # Catch cases where abort()s get logged to stderr by libraries but # only cause child processes to terminate e.g. during shutdown, # which may not otherwise trigger test failures. From c2fb699b8fea59069f0dfef45b07d7ddc96c1a16 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Tue, 17 Sep 2024 12:10:23 +0000 Subject: [PATCH 059/176] Merge /httpd/httpd/trunk:r1920747,1920751 *) mod_md: update to version 2.4.28 - When the server starts, it looks for new, staged certificates to activate. If the staged set of files in 'md/staging/' is messed up, this could prevent further renewals to happen. Now, when the staging set is present, but could not be activated due to an error, purge the whole directory. [icing] - Fix certificate retrieval on ACME renewal to not require a 'Location:' header returned by the ACME CA. This was the way it was done in ACME before it became an IETF standard. Let's Encrypt still supports this, but other CAs do not. [icing] - Restore compatibility with OpenSSL < 1.1. [ylavic] git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1920753 13f79535-47bb-0310-9956-ffa450edef68 --- changes-entries/md_v2.4.28.txt | 11 ++++ modules/md/md_acme_drive.c | 10 +-- modules/md/md_reg.c | 6 +- modules/md/md_version.h | 4 +- test/modules/md/conftest.py | 8 +-- test/modules/md/md_cert_util.py | 70 ++++++-------------- test/modules/md/md_env.py | 27 ++++---- test/modules/md/test_502_acmev2_drive.py | 14 ++-- test/modules/md/test_702_auto.py | 54 ++++++++++++--- test/modules/md/test_730_static.py | 42 +++++++----- test/modules/md/test_741_setup_errors.py | 26 ++++++++ test/modules/md/test_801_stapling.py | 13 ++-- test/modules/md/test_901_message.py | 30 +++++---- test/modules/md/test_920_status.py | 16 +++-- test/pyhttpd/certs.py | 83 +++++++++++++++++------- 15 files changed, 264 insertions(+), 150 deletions(-) create mode 100644 changes-entries/md_v2.4.28.txt diff --git a/changes-entries/md_v2.4.28.txt b/changes-entries/md_v2.4.28.txt new file mode 100644 index 0000000000..3eb2bc4917 --- /dev/null +++ b/changes-entries/md_v2.4.28.txt @@ -0,0 +1,11 @@ + *) mod_md: update to version 2.4.28 + - When the server starts, it looks for new, staged certificates to + activate. If the staged set of files in 'md/staging/' is messed + up, this could prevent further renewals to happen. Now, when the staging + set is present, but could not be activated due to an error, purge the + whole directory. [icing] + - Fix certificate retrieval on ACME renewal to not require a 'Location:' + header returned by the ACME CA. This was the way it was done in ACME + before it became an IETF standard. Let's Encrypt still supports this, + but other CAs do not. [icing] + - Restore compatibility with OpenSSL < 1.1. [ylavic] diff --git a/modules/md/md_acme_drive.c b/modules/md/md_acme_drive.c index 4bb04f321c..0ec409c863 100644 --- a/modules/md/md_acme_drive.c +++ b/modules/md/md_acme_drive.c @@ -305,11 +305,11 @@ static apr_status_t csr_req(md_acme_t *acme, const md_http_response_t *res, void (void)acme; location = apr_table_get(res->headers, "location"); - if (!location) { - md_log_perror(MD_LOG_MARK, MD_LOG_ERR, APR_EINVAL, d->p, - "cert created without giving its location header"); - return APR_EINVAL; - } + if (!location) + return rv; + + md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, d->p, + "cert created with location header (old ACMEv1 style)"); ad->order->certificate = apr_pstrdup(d->p, location); if (APR_SUCCESS != (rv = md_acme_order_save(d->store, d->p, MD_SG_STAGING, d->md->name, ad->order, 0))) { diff --git a/modules/md/md_reg.c b/modules/md/md_reg.c index 6aa7d78876..dc49446ae4 100644 --- a/modules/md/md_reg.c +++ b/modules/md/md_reg.c @@ -1194,7 +1194,7 @@ static apr_status_t run_load_staging(void *baton, apr_pool_t *p, apr_pool_t *pte result = va_arg(ap, md_result_t*); if (APR_STATUS_IS_ENOENT(rv = md_load(reg->store, MD_SG_STAGING, md->name, NULL, ptemp))) { - md_log_perror(MD_LOG_MARK, MD_LOG_TRACE2, 0, ptemp, "%s: nothing staged", md->name); + md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, 0, ptemp, "%s: nothing staged", md->name); goto out; } @@ -1259,7 +1259,9 @@ apr_status_t md_reg_load_stagings(md_reg_t *reg, apr_array_header_t *mds, } else if (!APR_STATUS_IS_ENOENT(rv)) { md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, p, APLOGNO(10069) - "%s: error loading staged set", md->name); + "%s: error loading staged set, purging it", md->name); + md_store_purge(reg->store, p, MD_SG_STAGING, md->name); + md_store_purge(reg->store, p, MD_SG_CHALLENGES, md->name); } } diff --git a/modules/md/md_version.h b/modules/md/md_version.h index cefbb8ded7..3e2914d6b6 100644 --- a/modules/md/md_version.h +++ b/modules/md/md_version.h @@ -27,7 +27,7 @@ * @macro * Version number of the md module as c string */ -#define MOD_MD_VERSION "2.4.26" +#define MOD_MD_VERSION "2.4.28" /** * @macro @@ -35,7 +35,7 @@ * release. This is a 24 bit number with 8 bits for major number, 8 bits * for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203. */ -#define MOD_MD_VERSION_NUM 0x02041a +#define MOD_MD_VERSION_NUM 0x02041c #define MD_ACME_DEF_URL "https://acme-v02.api.letsencrypt.org/directory" #define MD_TAILSCALE_DEF_URL "file://localhost/var/run/tailscale/tailscaled.sock" diff --git a/test/modules/md/conftest.py b/test/modules/md/conftest.py index a7b064b6a9..0118de5e13 100755 --- a/test/modules/md/conftest.py +++ b/test/modules/md/conftest.py @@ -39,9 +39,7 @@ def env(pytestconfig) -> MDTestEnv: @pytest.fixture(autouse=True, scope="package") def _md_package_scope(env): env.httpd_error_log.add_ignored_lognos([ - "AH10085", # There are no SSL certificates configured and no other module contributed any - "AH10045", # No VirtualHost matches Managed Domain - "AH10105", # MDomain does not match any VirtualHost with 'SSLEngine on' + "AH10085" # There are no SSL certificates configured and no other module contributed any ]) @@ -59,7 +57,3 @@ def acme(env): if acme_server is not None: acme_server.stop() -@pytest.fixture(autouse=True, scope="package") -def _stop_package_scope(env): - yield - assert env.apache_stop() == 0 diff --git a/test/modules/md/md_cert_util.py b/test/modules/md/md_cert_util.py index abcd36b938..6cd034a02b 100755 --- a/test/modules/md/md_cert_util.py +++ b/test/modules/md/md_cert_util.py @@ -1,6 +1,5 @@ import logging import re -import os import socket import OpenSSL import time @@ -12,6 +11,7 @@ from http.client import HTTPConnection from urllib.parse import urlparse +from cryptography import x509 SEC_PER_DAY = 24 * 60 * 60 @@ -23,45 +23,6 @@ class MDCertUtil(object): # Utility class for inspecting certificates in test cases # Uses PyOpenSSL: https://pyopenssl.org/en/stable/index.html - @classmethod - def create_self_signed_cert(cls, path, name_list, valid_days, serial=1000): - domain = name_list[0] - if not os.path.exists(path): - os.makedirs(path) - - cert_file = os.path.join(path, 'pubcert.pem') - pkey_file = os.path.join(path, 'privkey.pem') - # create a key pair - if os.path.exists(pkey_file): - key_buffer = open(pkey_file, 'rt').read() - k = OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, key_buffer) - else: - k = OpenSSL.crypto.PKey() - k.generate_key(OpenSSL.crypto.TYPE_RSA, 2048) - - # create a self-signed cert - cert = OpenSSL.crypto.X509() - cert.get_subject().C = "DE" - cert.get_subject().ST = "NRW" - cert.get_subject().L = "Muenster" - cert.get_subject().O = "greenbytes GmbH" - cert.get_subject().CN = domain - cert.set_serial_number(serial) - cert.gmtime_adj_notBefore(valid_days["notBefore"] * SEC_PER_DAY) - cert.gmtime_adj_notAfter(valid_days["notAfter"] * SEC_PER_DAY) - cert.set_issuer(cert.get_subject()) - - cert.add_extensions([OpenSSL.crypto.X509Extension( - b"subjectAltName", False, b", ".join(map(lambda n: b"DNS:" + n.encode(), name_list)) - )]) - cert.set_pubkey(k) - cert.sign(k, 'sha1') - - open(cert_file, "wt").write( - OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, cert).decode('utf-8')) - open(pkey_file, "wt").write( - OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, k).decode('utf-8')) - @classmethod def load_server_cert(cls, host_ip, host_port, host_name, tls=None, ciphers=None): ctx = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD) @@ -138,17 +99,26 @@ def get_serial(self): # add leading 0s to align with word boundaries. return ("%lx" % (self.cert.get_serial_number())).upper() - def same_serial_as(self, other): - if isinstance(other, MDCertUtil): - return self.cert.get_serial_number() == other.cert.get_serial_number() - elif isinstance(other, OpenSSL.crypto.X509): - return self.cert.get_serial_number() == other.get_serial_number() - elif isinstance(other, str): + @staticmethod + def _get_serial(cert) -> int: + if isinstance(cert, x509.Certificate): + return cert.serial_number + if isinstance(cert, MDCertUtil): + return cert.get_serial_number() + elif isinstance(cert, OpenSSL.crypto.X509): + return cert.get_serial_number() + elif isinstance(cert, str): # assume a hex number - return self.cert.get_serial_number() == int(other, 16) - elif isinstance(other, int): - return self.cert.get_serial_number() == other - return False + return int(cert, 16) + elif isinstance(cert, int): + return cert + return 0 + + def get_serial_number(self): + return self._get_serial(self.cert) + + def same_serial_as(self, other): + return self._get_serial(self.cert) == self._get_serial(other) def get_not_before(self): tsp = self.cert.get_notBefore() diff --git a/test/modules/md/md_env.py b/test/modules/md/md_env.py index 360086f97b..acc8417b14 100755 --- a/test/modules/md/md_env.py +++ b/test/modules/md/md_env.py @@ -12,9 +12,9 @@ import time from datetime import datetime, timedelta -from typing import Dict, Optional +from typing import Dict, Optional, Any -from pyhttpd.certs import CertificateSpec +from pyhttpd.certs import CertificateSpec, Credentials, HttpdTestCA from .md_cert_util import MDCertUtil from pyhttpd.env import HttpdTestSetup, HttpdTestEnv from pyhttpd.result import ExecResult @@ -73,10 +73,10 @@ def has_acme_server(cls): @classmethod def has_acme_eab(cls): - # Pebble v2.5.0 and v2.5.1 do not support HS256 for EAB, which - # is the only thing mod_md supports. - # Should work for pebble until v2.4.0 and v2.5.2+. - # Reference: https://github.com/letsencrypt/pebble/issues/455 + # Pebble, in v2.5.0 no longer supported HS256 for EAB, which + # is the only thing mod_md supports. Issue opened at pebble: + # https://github.com/letsencrypt/pebble/issues/455 + # is fixed in v2.6.0 return cls.get_acme_server() == 'pebble' @classmethod @@ -611,8 +611,13 @@ def await_ocsp_status(self, domain, timeout=10, ca_file=None): time.sleep(0.1) raise TimeoutError(f"ocsp respopnse not available: {domain}") - def create_self_signed_cert(self, name_list, valid_days, serial=1000, path=None): - dirpath = path - if not path: - dirpath = os.path.join(self.store_domains(), name_list[0]) - return MDCertUtil.create_self_signed_cert(dirpath, name_list, valid_days, serial) + def create_self_signed_cert(self, spec: CertificateSpec, + valid_from: timedelta = timedelta(days=-1), + valid_to: timedelta = timedelta(days=89), + serial: Optional[int] = None) -> Credentials: + key_type = spec.key_type if spec.key_type else 'rsa4096' + return HttpdTestCA.create_credentials(spec=spec, issuer=None, + key_type=key_type, + valid_from=valid_from, + valid_to=valid_to, + serial=serial) diff --git a/test/modules/md/test_502_acmev2_drive.py b/test/modules/md/test_502_acmev2_drive.py index eb754f25ef..b064647450 100644 --- a/test/modules/md/test_502_acmev2_drive.py +++ b/test/modules/md/test_502_acmev2_drive.py @@ -4,11 +4,12 @@ import json import os.path import re -import time +from datetime import timedelta import pytest +from pyhttpd.certs import CertificateSpec -from .md_conf import MDConf, MDConf +from .md_conf import MDConf from .md_cert_util import MDCertUtil from .md_env import MDTestEnv @@ -430,9 +431,12 @@ def test_md_502_201(self, env, renew_window, test_data_list): print("TRACE: start testing renew window: %s" % renew_window) for tc in test_data_list: print("TRACE: create self-signed cert: %s" % tc["valid"]) - env.create_self_signed_cert([name], tc["valid"]) - cert2 = MDCertUtil(env.store_domain_file(name, 'pubcert.pem')) - assert not cert2.same_serial_as(cert1) + creds = env.create_self_signed_cert(CertificateSpec(domains=[name]), + valid_from=timedelta(days=tc["valid"]["notBefore"]), + valid_to=timedelta(days=tc["valid"]["notAfter"])) + assert creds.certificate.serial_number != cert1.get_serial_number() + # copy it over, assess status again + creds.save_cert_pem(env.store_domain_file(name, 'pubcert.pem')) md = env.a2md(["list", name]).json['output'][0] assert md["renew"] == tc["renew"], \ "Expected renew == {} indicator in {}, test case {}".format(tc["renew"], md, tc) diff --git a/test/modules/md/test_702_auto.py b/test/modules/md/test_702_auto.py index 04a9c7561a..90103e3aff 100644 --- a/test/modules/md/test_702_auto.py +++ b/test/modules/md/test_702_auto.py @@ -1,9 +1,9 @@ import os -import time +from datetime import timedelta import pytest +from pyhttpd.certs import CertificateSpec -from pyhttpd.conf import HttpdConf from pyhttpd.env import HttpdTestEnv from .md_cert_util import MDCertUtil from .md_env import MDTestEnv @@ -320,18 +320,22 @@ def test_md_702_009(self, env): assert cert1.same_serial_as(stat['rsa']['serial']) # # create self-signed cert, with critical remaining valid duration -> drive again - env.create_self_signed_cert([domain], {"notBefore": -120, "notAfter": 2}, serial=7029) - cert3 = MDCertUtil(env.store_domain_file(domain, 'pubcert.pem')) - assert cert3.same_serial_as('1B75') + creds = env.create_self_signed_cert(CertificateSpec(domains=[domain]), + valid_from=timedelta(days=-120), + valid_to=timedelta(days=2), + serial=7029) + creds.save_cert_pem(env.store_domain_file(domain, 'pubcert.pem')) + creds.save_pkey_pem(env.store_domain_file(domain, 'privkey.pem')) + assert creds.certificate.serial_number == 7029 assert env.apache_restart() == 0 stat = env.get_certificate_status(domain) - assert cert3.same_serial_as(stat['rsa']['serial']) + assert creds.certificate.serial_number == int(stat['rsa']['serial'], 16) # # cert should renew and be different afterwards assert env.await_completion([domain], must_renew=True) stat = env.get_certificate_status(domain) - assert not cert3.same_serial_as(stat['rsa']['serial']) - + creds.certificate.serial_number != int(stat['rsa']['serial'], 16) + # test case: drive with an unsupported challenge due to port availability def test_md_702_010(self, env): domain = self.test_domain @@ -543,6 +547,40 @@ def test_md_702_032(self, env): assert name2 in cert1b.get_san_list() assert not cert1.same_serial_as(cert1b) + # test case: one MD on a vhost with ServerAlias. Renew. + # Exchange ServerName and ServerAlias. Is the rename detected? + # See: https://github.com/icing/mod_md/issues/338 + def test_md_702_033(self, env): + domain = self.test_domain + name_x = "test-x." + domain + name_a = "test-a." + domain + domains1 = [name_x, name_a] + # + # generate 1 MD and 2 vhosts + conf = MDConf(env, admin="admin@" + domain) + conf.add_md(domains=[name_x]) + conf.add_vhost(domains=domains1) + conf.install() + # + # restart (-> drive), check that MD was synched and completes + assert env.apache_restart() == 0 + env.check_md(domains1) + assert env.await_completion([name_x]) + env.check_md_complete(name_x) + cert_x = env.get_cert(name_x) + # + # reverse ServerName and ServerAlias + domains2 = [name_a, name_x] + conf = MDConf(env, admin="admin@" + domain) + conf.add_md(domains=[name_a]) + conf.add_vhost(domains=domains2) + conf.install() + # restart, check that host still works and kept the cert + assert env.apache_restart() == 0 + status = env.get_certificate_status(name_a) + assert cert_x.same_serial_as(status['rsa']['serial']) + + # test case: test "tls-alpn-01" challenge handling def test_md_702_040(self, env): domain = self.test_domain diff --git a/test/modules/md/test_730_static.py b/test/modules/md/test_730_static.py index 891ae620bb..91a5f4445d 100644 --- a/test/modules/md/test_730_static.py +++ b/test/modules/md/test_730_static.py @@ -1,6 +1,8 @@ import os +from datetime import timedelta import pytest +from pyhttpd.certs import CertificateSpec from .md_conf import MDConf from .md_env import MDTestEnv @@ -28,14 +30,17 @@ def test_md_730_001(self, env): # MD with static cert files, will not be driven domain = self.test_domain domains = [domain, 'www.%s' % domain] - testpath = os.path.join(env.gen_dir, 'test_920_001') + testpath = os.path.join(env.gen_dir, 'test_730_001') + env.mkpath(testpath) # cert that is only 10 more days valid - env.create_self_signed_cert(domains, {"notBefore": -80, "notAfter": 10}, - serial=730001, path=testpath) + creds = env.create_self_signed_cert(CertificateSpec(domains=domains), + valid_from=timedelta(days=-80), + valid_to=timedelta(days=10), + serial=730001) cert_file = os.path.join(testpath, 'pubcert.pem') pkey_file = os.path.join(testpath, 'privkey.pem') - assert os.path.exists(cert_file) - assert os.path.exists(pkey_file) + creds.save_cert_pem(cert_file) + creds.save_pkey_pem(pkey_file) conf = MDConf(env) conf.start_md(domains) conf.add(f"MDCertificateFile {cert_file}") @@ -58,14 +63,17 @@ def test_md_730_002(self, env): # MD with static cert files, force driving domain = self.test_domain domains = [domain, 'www.%s' % domain] - testpath = os.path.join(env.gen_dir, 'test_920_001') + testpath = os.path.join(env.gen_dir, 'test_730_002') + env.mkpath(testpath) # cert that is only 10 more days valid - env.create_self_signed_cert(domains, {"notBefore": -80, "notAfter": 10}, - serial=730001, path=testpath) + creds = env.create_self_signed_cert(CertificateSpec(domains=domains), + valid_from=timedelta(days=-80), + valid_to=timedelta(days=10), + serial=730001) cert_file = os.path.join(testpath, 'pubcert.pem') pkey_file = os.path.join(testpath, 'privkey.pem') - assert os.path.exists(cert_file) - assert os.path.exists(pkey_file) + creds.save_cert_pem(cert_file) + creds.save_pkey_pem(pkey_file) conf = MDConf(env) conf.start_md(domains) conf.add(f"MDPrivateKeys secp384r1 rsa3072") @@ -91,15 +99,17 @@ def test_md_730_003(self, env): # just configuring one file will not work domain = self.test_domain domains = [domain, 'www.%s' % domain] - testpath = os.path.join(env.gen_dir, 'test_920_001') + testpath = os.path.join(env.gen_dir, 'test_730_003') + env.mkpath(testpath) # cert that is only 10 more days valid - env.create_self_signed_cert(domains, {"notBefore": -80, "notAfter": 10}, - serial=730001, path=testpath) + creds = env.create_self_signed_cert(CertificateSpec(domains=domains), + valid_from=timedelta(days=-80), + valid_to=timedelta(days=10), + serial=730001) cert_file = os.path.join(testpath, 'pubcert.pem') pkey_file = os.path.join(testpath, 'privkey.pem') - assert os.path.exists(cert_file) - assert os.path.exists(pkey_file) - + creds.save_cert_pem(cert_file) + creds.save_pkey_pem(pkey_file) conf = MDConf(env) conf.start_md(domains) conf.add(f"MDCertificateFile {cert_file}") diff --git a/test/modules/md/test_741_setup_errors.py b/test/modules/md/test_741_setup_errors.py index 9ad79f0b1e..958f13f4d1 100644 --- a/test/modules/md/test_741_setup_errors.py +++ b/test/modules/md/test_741_setup_errors.py @@ -56,3 +56,29 @@ def test_md_741_001(self, env): r'.*CA considers answer to challenge invalid.*' ] ) + + # mess up the produced staging area before reload + def test_md_741_002(self, env): + domain = self.test_domain + domains = [domain] + conf = MDConf(env) + conf.add_md(domains) + conf.add_vhost(domains) + conf.install() + assert env.apache_restart() == 0 + env.check_md(domains) + assert env.await_completion([domain], restart=False) + staged_md_path = env.store_staged_file(domain, 'md.json') + with open(staged_md_path, 'w') as fd: + fd.write('garbage\n') + assert env.apache_restart() == 0 + assert env.await_completion([domain]) + env.check_md_complete(domain) + env.httpd_error_log.ignore_recent( + lognos = [ + "AH10069" # failed to load JSON file + ], + matches = [ + r'.*failed to load JSON file.*', + ] + ) diff --git a/test/modules/md/test_801_stapling.py b/test/modules/md/test_801_stapling.py index 5c0360251b..7992337964 100644 --- a/test/modules/md/test_801_stapling.py +++ b/test/modules/md/test_801_stapling.py @@ -2,7 +2,9 @@ import os import time +from datetime import timedelta import pytest +from pyhttpd.certs import CertificateSpec from .md_conf import MDConf from .md_env import MDTestEnv @@ -333,13 +335,16 @@ def test_md_801_009(self, env): md = self.mdA domains = [md] testpath = os.path.join(env.gen_dir, 'test_801_009') + env.mkpath(testpath) # cert that is 30 more days valid - env.create_self_signed_cert(domains, {"notBefore": -60, "notAfter": 30}, - serial=801009, path=testpath) + creds = env.create_self_signed_cert(CertificateSpec(domains=domains), + valid_from=timedelta(days=-60), + valid_to=timedelta(days=30), + serial=801009) cert_file = os.path.join(testpath, 'pubcert.pem') pkey_file = os.path.join(testpath, 'privkey.pem') - assert os.path.exists(cert_file) - assert os.path.exists(pkey_file) + creds.save_cert_pem(cert_file) + creds.save_pkey_pem(pkey_file) conf = MDConf(env) conf.start_md(domains) conf.add("MDCertificateFile %s" % cert_file) diff --git a/test/modules/md/test_901_message.py b/test/modules/md/test_901_message.py index b18cfd38d4..c0018393e7 100644 --- a/test/modules/md/test_901_message.py +++ b/test/modules/md/test_901_message.py @@ -3,9 +3,11 @@ import json import os import time +from datetime import timedelta import pytest +from pyhttpd.certs import CertificateSpec -from .md_conf import MDConf, MDConf +from .md_conf import MDConf from .md_env import MDTestEnv @@ -155,13 +157,16 @@ def test_md_901_010(self, env): domain = self.test_domain domains = [domain, 'www.%s' % domain] testpath = os.path.join(env.gen_dir, 'test_901_010') - # cert that is only 10 more days valid - env.create_self_signed_cert(domains, {"notBefore": -70, "notAfter": 20}, - serial=901010, path=testpath) + env.mkpath(testpath) + # cert that is only 20 more days valid + creds = env.create_self_signed_cert(CertificateSpec(domains=domains), + valid_from=timedelta(days=-70), + valid_to=timedelta(days=20), + serial=901010) cert_file = os.path.join(testpath, 'pubcert.pem') pkey_file = os.path.join(testpath, 'privkey.pem') - assert os.path.exists(cert_file) - assert os.path.exists(pkey_file) + creds.save_cert_pem(cert_file) + creds.save_pkey_pem(pkey_file) conf = MDConf(env) conf.add(f"MDMessageCmd {self.mcmd} {self.mlog}") conf.start_md(domains) @@ -178,13 +183,16 @@ def test_md_901_011(self, env): domain = self.test_domain domains = [domain, f'www.{domain}'] testpath = os.path.join(env.gen_dir, 'test_901_011') - # cert that is only 10 more days valid - env.create_self_signed_cert(domains, {"notBefore": -85, "notAfter": 5}, - serial=901011, path=testpath) + env.mkpath(testpath) + # cert that is only 5 more days valid + creds = env.create_self_signed_cert(CertificateSpec(domains=domains), + valid_from=timedelta(days=-85), + valid_to=timedelta(days=5), + serial=901010) cert_file = os.path.join(testpath, 'pubcert.pem') pkey_file = os.path.join(testpath, 'privkey.pem') - assert os.path.exists(cert_file) - assert os.path.exists(pkey_file) + creds.save_cert_pem(cert_file) + creds.save_pkey_pem(pkey_file) conf = MDConf(env) conf.add(f"MDMessageCmd {self.mcmd} {self.mlog}") conf.start_md(domains) diff --git a/test/modules/md/test_920_status.py b/test/modules/md/test_920_status.py index 6ad708728c..306b131a16 100644 --- a/test/modules/md/test_920_status.py +++ b/test/modules/md/test_920_status.py @@ -2,9 +2,10 @@ import os import re -import time +from datetime import timedelta import pytest +from pyhttpd.certs import CertificateSpec from .md_conf import MDConf from shutil import copyfile @@ -165,13 +166,16 @@ def test_md_920_011(self, env): domain = self.test_domain domains = [domain, 'www.%s' % domain] testpath = os.path.join(env.gen_dir, 'test_920_011') - # cert that is only 10 more days valid - env.create_self_signed_cert(domains, {"notBefore": -70, "notAfter": 20}, - serial=920011, path=testpath) + env.mkpath(testpath) + # cert that is only 20 more days valid + creds = env.create_self_signed_cert(CertificateSpec(domains=domains), + valid_from=timedelta(days=-70), + valid_to=timedelta(days=20), + serial=920011) cert_file = os.path.join(testpath, 'pubcert.pem') pkey_file = os.path.join(testpath, 'privkey.pem') - assert os.path.exists(cert_file) - assert os.path.exists(pkey_file) + creds.save_cert_pem(cert_file) + creds.save_pkey_pem(pkey_file) conf = MDConf(env, std_vhosts=False, std_ports=False, text=f""" MDBaseServer on MDPortMap http:- https:{env.https_port} diff --git a/test/pyhttpd/certs.py b/test/pyhttpd/certs.py index 5519f16188..a08d5e64e4 100644 --- a/test/pyhttpd/certs.py +++ b/test/pyhttpd/certs.py @@ -181,6 +181,14 @@ def issue_cert(self, spec: CertificateSpec, chain: List['Credentials'] = None) - creds.issue_certs(spec.sub_specs, chain=subchain) return creds + def save_cert_pem(self, fpath): + with open(fpath, "wb") as fd: + fd.write(self.cert_pem) + + def save_pkey_pem(self, fpath): + with open(fpath, "wb") as fd: + fd.write(self.pkey_pem) + class CertStore: @@ -282,6 +290,7 @@ def create_root(cls, name: str, store_dir: str, key_type: str = "rsa2048") -> Cr def create_credentials(spec: CertificateSpec, issuer: Credentials, key_type: Any, valid_from: timedelta = timedelta(days=-1), valid_to: timedelta = timedelta(days=89), + serial: Optional[int] = None, ) -> Credentials: """Create a certificate signed by this CA for the given domains. :returns: the certificate and private key PEM file paths @@ -289,15 +298,18 @@ def create_credentials(spec: CertificateSpec, issuer: Credentials, key_type: Any if spec.domains and len(spec.domains): creds = HttpdTestCA._make_server_credentials(name=spec.name, domains=spec.domains, issuer=issuer, valid_from=valid_from, - valid_to=valid_to, key_type=key_type) + valid_to=valid_to, key_type=key_type, + serial=serial) elif spec.client: creds = HttpdTestCA._make_client_credentials(name=spec.name, issuer=issuer, email=spec.email, valid_from=valid_from, - valid_to=valid_to, key_type=key_type) + valid_to=valid_to, key_type=key_type, + serial=serial) elif spec.name: creds = HttpdTestCA._make_ca_credentials(name=spec.name, issuer=issuer, valid_from=valid_from, valid_to=valid_to, - key_type=key_type) + key_type=key_type, + serial=serial) else: raise Exception(f"unrecognized certificate specification: {spec}") return creds @@ -320,7 +332,8 @@ def _make_csr( pkey: Any, issuer_subject: Optional[Credentials], valid_from_delta: timedelta = None, - valid_until_delta: timedelta = None + valid_until_delta: timedelta = None, + serial: Optional[int] = None ): pubkey = pkey.public_key() issuer_subject = issuer_subject if issuer_subject is not None else subject @@ -331,7 +344,8 @@ def _make_csr( valid_until = datetime.now() if valid_until_delta is not None: valid_until += valid_until_delta - + if serial is None: + serial = x509.random_serial_number() return ( x509.CertificateBuilder() .subject_name(subject) @@ -339,7 +353,7 @@ def _make_csr( .public_key(pubkey) .not_valid_before(valid_from) .not_valid_after(valid_until) - .serial_number(x509.random_serial_number()) + .serial_number(serial) .add_extension( x509.SubjectKeyIdentifier.from_public_key(pubkey), critical=False, @@ -374,23 +388,28 @@ def _add_ca_usages(csr: Any) -> Any: @staticmethod def _add_leaf_usages(csr: Any, domains: List[str], issuer: Credentials) -> Any: - return csr.add_extension( + csr = csr.add_extension( x509.BasicConstraints(ca=False, path_length=None), critical=True, - ).add_extension( - x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier( - issuer.certificate.extensions.get_extension_for_class( - x509.SubjectKeyIdentifier).value), - critical=False - ).add_extension( + ) + if issuer is not None: + csr = csr.add_extension( + x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier( + issuer.certificate.extensions.get_extension_for_class( + x509.SubjectKeyIdentifier).value), + critical=False + ) + csr = csr.add_extension( x509.SubjectAlternativeName([x509.DNSName(domain) for domain in domains]), critical=True, - ).add_extension( + ) + csr = csr.add_extension( x509.ExtendedKeyUsage([ ExtendedKeyUsageOID.SERVER_AUTH, ]), critical=True ) + return csr @staticmethod def _add_client_usages(csr: Any, issuer: Credentials, rfc82name: str = None) -> Any: @@ -421,6 +440,7 @@ def _make_ca_credentials(name, key_type: Any, issuer: Credentials = None, valid_from: timedelta = timedelta(days=-1), valid_to: timedelta = timedelta(days=89), + serial: Optional[int] = None, ) -> Credentials: pkey = _private_key(key_type=key_type) if issuer is not None: @@ -432,7 +452,8 @@ def _make_ca_credentials(name, key_type: Any, subject = HttpdTestCA._make_x509_name(org_name=name, parent=issuer.subject if issuer else None) csr = HttpdTestCA._make_csr(subject=subject, issuer_subject=issuer_subject, pkey=pkey, - valid_from_delta=valid_from, valid_until_delta=valid_to) + valid_from_delta=valid_from, valid_until_delta=valid_to, + serial=serial) csr = HttpdTestCA._add_ca_usages(csr) cert = csr.sign(private_key=issuer_key, algorithm=hashes.SHA256(), @@ -444,15 +465,23 @@ def _make_server_credentials(name: str, domains: List[str], issuer: Credentials, key_type: Any, valid_from: timedelta = timedelta(days=-1), valid_to: timedelta = timedelta(days=89), + serial: Optional[int] = None, ) -> Credentials: name = name pkey = _private_key(key_type=key_type) - subject = HttpdTestCA._make_x509_name(common_name=name, parent=issuer.subject) + if issuer is not None: + issuer_subject = issuer.certificate.subject + issuer_key = issuer.private_key + else: + issuer_subject = None + issuer_key = pkey + subject = HttpdTestCA._make_x509_name(common_name=name, parent=issuer_subject) csr = HttpdTestCA._make_csr(subject=subject, - issuer_subject=issuer.certificate.subject, pkey=pkey, - valid_from_delta=valid_from, valid_until_delta=valid_to) + issuer_subject=issuer_subject, pkey=pkey, + valid_from_delta=valid_from, valid_until_delta=valid_to, + serial=serial) csr = HttpdTestCA._add_leaf_usages(csr, domains=domains, issuer=issuer) - cert = csr.sign(private_key=issuer.private_key, + cert = csr.sign(private_key=issuer_key, algorithm=hashes.SHA256(), backend=default_backend()) return Credentials(name=name, cert=cert, pkey=pkey, issuer=issuer) @@ -463,14 +492,22 @@ def _make_client_credentials(name: str, key_type: Any, valid_from: timedelta = timedelta(days=-1), valid_to: timedelta = timedelta(days=89), + serial: Optional[int] = None, ) -> Credentials: pkey = _private_key(key_type=key_type) - subject = HttpdTestCA._make_x509_name(common_name=name, parent=issuer.subject) + if issuer is not None: + issuer_subject = issuer.certificate.subject + issuer_key = issuer.private_key + else: + issuer_subject = None + issuer_key = pkey + subject = HttpdTestCA._make_x509_name(common_name=name, parent=issuer_subject) csr = HttpdTestCA._make_csr(subject=subject, - issuer_subject=issuer.certificate.subject, pkey=pkey, - valid_from_delta=valid_from, valid_until_delta=valid_to) + issuer_subject=issuer_subject, pkey=pkey, + valid_from_delta=valid_from, valid_until_delta=valid_to, + serial=serial) csr = HttpdTestCA._add_client_usages(csr, issuer=issuer, rfc82name=email) - cert = csr.sign(private_key=issuer.private_key, + cert = csr.sign(private_key=issuer_key, algorithm=hashes.SHA256(), backend=default_backend()) return Credentials(name=name, cert=cert, pkey=pkey, issuer=issuer) From 096bfb037032cc6a401ab1af8fefc391fa1c0adf Mon Sep 17 00:00:00 2001 From: Lucien Gentis Date: Mon, 23 Sep 2024 12:25:49 +0000 Subject: [PATCH 060/176] fr doc xml files updated and corrected. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1920858 13f79535-47bb-0310-9956-ffa450edef68 --- docs/manual/content-negotiation.xml.fr | 705 +++++++++++++------------ docs/manual/mod/allmodules.xml.fr | 2 +- 2 files changed, 354 insertions(+), 353 deletions(-) diff --git a/docs/manual/content-negotiation.xml.fr b/docs/manual/content-negotiation.xml.fr index 98cbccbe7a..3116260f7e 100644 --- a/docs/manual/content-negotiation.xml.fr +++ b/docs/manual/content-negotiation.xml.fr @@ -24,137 +24,137 @@ -Négociation de contenu +Négociation de contenu -

    Apache HTTPD supporte la négociation de - contenu telle qu'elle est décrite - dans la spécification HTTP/1.1. Il peut choisir la meilleure représentation - d'une ressource en fonction des préférences du navigateur pour ce qui - concerne le type de media, les langages, le jeu de caractères et son - encodage. Il implémente aussi quelques fonctionnalités pour traiter de - manière plus intelligente les requêtes en provenance de navigateurs qui - envoient des informations de négociation incomplètes.

    - -

    La négociation de contenu est assurée par le module - mod_negotiation qui est compilé par défaut +

    Apache HTTPD prend en charge la négociation de + contenu telle qu'elle est décrite + dans la spécification HTTP/1.1. Il peut choisir la meilleure représentation + d'une ressource en fonction des préférences du navigateur pour ce qui + concerne le type de media, les langages, le jeu de caractères et son + encodage. Il implémente aussi quelques fonctionnalités pour traiter de + manière plus intelligente les requêtes en provenance de navigateurs qui + envoient des informations de négociation incomplètes.

    + +

    La négociation de contenu est assurée par le module + mod_negotiation qui est compilé par défaut dans le serveur.

    -
    À propos de la négociation de contenu +
    À propos de la négociation de contenu -

    Une ressource peut être disponible selon différentes représentations. - Par exemple, elle peut être disponible en différents langages ou pour - différents types de média, ou une combinaison des deux. - Pour faire le meilleur choix, on peut fournir à l'utilisateur une page +

    Une ressource peut être disponible selon différentes représentations. + Par exemple, elle peut être disponible en différents langages ou pour + différents types de média, ou une combinaison des deux. + Pour faire le meilleur choix, on peut fournir à l'utilisateur une page d'index, et le laisser choisir. Cependant, le serveur peut souvent faire - ce choix automatiquement. Ceci est possible car les navigateurs peuvent + ce choix automatiquement. Cela est possible car les navigateurs peuvent envoyer des informations sur les - représentations qu'ils préfèrent à l'intérieur de chaque requête. + représentations qu'ils préfèrent à l'intérieur de chaque requête. Par exemple, un navigateur peut indiquer - qu'il préfère voir les informations en français, mais qu'en cas - d'impossibilité l'anglais peut convenir. Les navigateurs indiquent leurs - préférences à l'aide d'en-têtes dans la requête. Pour ne demander que des - représentations en français, le navigateur peut utiliser l'en-tête :

    + qu'il préfère voir les informations en français, mais qu'en cas + d'impossibilité l'anglais peut convenir. Les navigateurs indiquent leurs + préférences à l'aide d'en-têtes dans la requête. Pour ne demander que des + représentations en français, le navigateur peut utiliser l'en-tête :

    Accept-Language: fr -

    Notez qu'il ne sera tenu compte de cette préférence que s'il existe un - choix de représentations et que ces dernières varient en fonction +

    Notez qu'il ne sera tenu compte de cette préférence que s'il existe un + choix de représentations et que ces dernières varient en fonction du langage.

    -

    À titre d'exemple d'une requête plus complexe, ce navigateur a été - configuré pour accepter le français et l'anglais, avec une préférence pour - le français, et accepter différents types de média, avec une préférence - pour HTML par rapport à au texte plat ("plain text") ou autres types de fichiers texte, et - avec une préférence pour GIF ou JPEG par rapport à tout autre type de - média, mais autorisant tout autre type de média en dernier ressort :

    +

    À titre d'exemple d'une requête plus complexe, ce navigateur a été + configuré pour accepter le français et l'anglais, avec une préférence pour + le français, et accepter différents types de média, avec une préférence + pour HTML par rapport à au texte plat (« plain text ») ou autres types de fichiers texte, et + avec une préférence pour GIF ou JPEG par rapport à tout autre type de + média, mais autorisant tout autre type de média en dernier ressort :

    Accept-Language: fr; q=1.0, en; q=0.5
    Accept: text/html; q=1.0, text/*; q=0.8, image/gif; q=0.6, image/jpeg; q=0.6, image/*; q=0.5, */*; q=0.1
    -

    httpd supporte la négociation de contenu "server driven" (telle qu'elle - est définie dans la spécification HTTP/1.1), où c'est le serveur qui - décide quelle est la meilleure représentation à retourner pour la ressource - demandée. Il supporte entièrement les en-têtes de requête +

    httpd prend en charge la négociation de contenu « server driven » (telle qu'elle + est définie dans la spécification HTTP/1.1), où c'est le serveur qui + décide quelle est la meilleure représentation à renvoyer pour la ressource + demandée. Il prend entièrement en charge les en-têtes de requête Accept, Accept-Language, Accept-Charset et Accept-Encoding. - httpd supporte aussi la négociation de contenu transparente, qui est un - protocole de négociation expérimental défini dans les RFC 2295 et 2296. - Il ne supporte pas la négociation de fonctionnalité (feature negotiation) - telle qu'elle est définie dans ces RFCs.

    - -

    Une ressource est une entité conceptuelle identifiée - par une URI (RFC 2396). Un serveur HTTP comme le serveur HTTP Apache - propose l'accès à des - représentations de la ressource à l'intérieur de son - espace de nommage, chaque représentation étant composée d'une séquence - d'octets avec la définition d'un type de media, d'un jeu de caractères, - d'un encodage, etc... A un instant donné, chaque ressource peut être - associée avec zéro, une ou plusieurs représentations. Si plusieurs - représentations sont disponibles, la ressource est qualifiée de - négociable et chacune de ses représentations se nomme - variante. Les différences entre les - variantes disponibles d'une ressource négociable constituent les - dimensions de la négociation.

    + httpd prend aussi en charge la négociation de contenu transparente, qui est un + protocole de négociation expérimental défini dans les RFC 2295 et 2296. + Il ne prend pas en charge la négociation de fonctionnalité (feature negotiation) + telle qu'elle est définie dans ces RFCs.

    + +

    Une ressource est une entité conceptuelle identifiée + par un URI (RFC 2396). Un serveur HTTP comme le serveur HTTP Apache + propose l'accès à des + représentations de la ressource à l'intérieur de son + espace de nommage, chaque représentation étant composée d'une séquence + d'octets avec la définition d'un type de media, d'un jeu de caractères, + d'un encodage, etc. À un instant donné, chaque ressource peut être + associée avec zéro, une ou plusieurs représentations. Si plusieurs + représentations sont disponibles, la ressource est qualifiée de + négociable et chacune de ses représentations se nomme + variante. Les différences entre les + variantes disponibles d'une ressource négociable constituent les + dimensions de la négociation.

    -
    La négociation avec httpd +
    La négociation avec httpd -

    Afin de négocier une ressource, on doit fournir au serveur des - informations à propos de chacune des variantes. Il y a deux manières - d'accomplir ceci :

    +

    Pour négocier une ressource, on doit fournir au serveur des + informations à propos de chacune des variantes. Il y a deux manières + d'y parvenir :

      -
    • Utiliser une liste de correspondances de type ("type-map") (c'est à dire +
    • Utiliser une liste de correspondances de type (« type-map ») (c'est à dire un fichier *.var) qui nomme explicitement les fichiers contenant les variantes, ou
    • -
    • Utiliser une recherche "multivues", où le serveur effectue une +
    • Utiliser une recherche « multivues », où le serveur effectue une recherche de correspondance sur un motif de nom de fichier implicite et - fait son choix parmi les différents résultats.
    • + fait son choix parmi les différents résultats.
    Utilisation d'un fichier de correspondances de types (type-map) -

    Une liste de correspondances de types est un document associé au - gestionnaire type-map (ou, dans un souci de compatibilité +

    Une liste de correspondances de types est un document associé au + gestionnaire type-map (ou, dans un souci de compatibilité ascendante avec des configurations de httpd plus anciennes, le type MIME application/x-type-map). Notez que pour utiliser cette - fonctionnalité, vous devez, dans le fichier de configuration, définir un - gestionnaire qui associe un suffixe de fichier à une type-map; + fonctionnalité, vous devez, dans le fichier de configuration, définir un + gestionnaire qui associe un suffixe de fichier à une type-map, ce qui se fait simplement en ajoutant

    AddHandler type-map .var

    dans le fichier de configuration du serveur.

    -

    Les fichiers de correspondances de types doivent posséder le même nom que - la ressource qu'ils décrivent, avec pour extension +

    Les fichiers de correspondances de types doivent posséder le même nom que + la ressource qu'ils décrivent, avec pour extension .var. Dans l'exemple ci-dessous, la ressource a pour nom foo, et le fichier de correspondances se nomme donc foo.var.

    -

    Ce fichier doit comporter une entrée pour chaque variante - disponible; chaque entrée consiste en une ligne contiguë d'en-têtes au - format HTTP. les entrées sont séparées par des lignes vides. Les lignes - vides à l'intérieur d'une entrée sont interdites. Par convention, le - fichier de correspondances de types débute par une entrée concernant l'entité - considérée dans son ensemble (bien que ce ne soit pas obligatoire, et - ignoré si présent). Un exemple de fichier de - correspondance de types est fourni +

    Ce fichier doit comporter une entrée pour chaque variante + disponible ; chaque entrée consiste en une ligne contiguë d'en-têtes au + format HTTP. Les entrées sont séparées par des lignes vides. Les lignes + vides à l'intérieur d'une entrée sont interdites. Par convention, le + fichier de correspondances de types débute par une entrée concernant l'entité + considérée dans son ensemble (bien que ce ne soit pas obligatoire, et + ignoré si présent). Un exemple de fichier de + correspondances de types est fourni ci-dessous.

    -

    Les URIs de ce fichier sont relatifs à la localisation du fichier - de correspondances de types. En général, ces fichiers se trouveront dans le - même répertoire que le fichier de correspondances de types, mais ce +

    Les URIs de ce fichier sont relatifs à la localisation du fichier + de correspondances de types. En général, ces fichiers se trouveront dans le + même répertoire que le fichier de correspondances de types, mais ce n'est pas obligatoire. Vous pouvez utiliser des URIs absolus ou - relatifs pour tout fichier situé sur le même serveur que le fichier + relatifs pour tout fichier situé sur le même serveur que le fichier de correspondances.

    @@ -170,9 +170,9 @@

    Notez aussi qu'un fichier de correspondances de types prend le pas sur - les extensions de noms de fichiers, même si les Multivues sont activées. - Si les variantes sont de qualités différentes, on doit l'indiquer - à l'aide du paramètre "qs" à la suite du type de média, comme pour cette + les extensions de noms de fichiers, même si les Multivues sont activées. + Si les variantes sont de qualités différentes, on doit l'indiquer + à l'aide du paramètre « qs » à la suite du type de média, comme pour cette image (disponible aux formats JPEG, GIF, ou ASCII-art) :

    @@ -189,19 +189,19 @@ Content-type: text/plain; qs=0.01
    -

    Les valeurs de qs peuvent varier de 0.000 à 1.000. Notez que toute - variante possédant une valeur de qs de 0.000 ne sera jamais choisie. - Les variantes qui n'ont pas de paramètre qs défini se voient attribuer - une valeur de 1.0. Le paramètre qs indique la qualité relative de la - variante comparée à celle des autres variantes disponibles, sans tenir - compte des capacités du client. Par exemple, un fichier JPEG possède - en général une qualité supérieure à celle d'un fichier ASCII s'il - représente une photographie. Cependant, si la ressource représentée est - à un ASCII art original, la représentation ASCII sera de meilleure qualité - que la représentation JPEG. Ainsi une valeur de qs est associée à une - variante en fonction de la nature de la ressource qu'elle représente.

    - -

    La liste complète des en-têtes reconnus est disponible dans la +

    Les valeurs de qs peuvent varier de 0.000 à 1.000. Notez que toute + variante possédant une valeur de qs de 0.000 ne sera jamais choisie. + Les variantes qui n'ont pas de paramètre qs défini se voient attribuer + une valeur de 1.0. Le paramètre qs indique la qualité relative de la + variante comparée à celle des autres variantes disponibles, sans tenir + compte des capacités du client. Par exemple, un fichier JPEG possède + en général une qualité supérieure à celle d'un fichier ASCII s'il + représente une photographie. Cependant, si la ressource représentée est + un ASCII art original, la représentation ASCII sera de meilleure qualité + que la représentation JPEG. Ainsi une valeur de qs est associée à une + variante en fonction de la nature de la ressource qu'elle représente.

    + +

    La liste complète des en-têtes reconnus est disponible dans la documentation sur les correspondances de types du module mod_negotiation.

    @@ -209,88 +209,88 @@
    Multivues (option Multiviews) -

    MultiViews est une option qui s'applique à un répertoire, - ce qui signifie qu'elle peut être activée à l'aide d'une directive - Options à l'intérieur d'une section +

    MultiViews est une option qui s'applique à un répertoire, + ce qui signifie qu'elle peut être activée à l'aide d'une directive + Options à l'intérieur d'une section Directory, Location ou Files dans httpd.conf, ou (si AllowOverride est correctement positionnée) dans + module="core">AllowOverride est correctement positionnée) dans des fichiers .htaccess. Notez que Options All - n'active pas MultiViews; vous devez activer cette option en + n'active pas MultiViews ; vous devez activer cette option en la nommant explicitement.

    -

    L'effet de MultiViews est le suivant : si le serveur reçoit - une requête pour /tel/répertoire/foo, si - MultiViews est activée pour - /tel/répertoire, et si - /tel/répertoire/foo n'existe pas, le serveur parcourt - le répertoire à la recherche de fichiers nommés foo.*, et simule - littéralement une correspondance de types (type map) qui liste tous ces - fichiers, en leur associant les mêmes types de média et encodages de - contenu qu'ils auraient eu si le client avait demandé l'accès à l'un +

    L'effet de MultiViews est le suivant : si le serveur reçoit + une requête pour /tel/répertoire/foo, si + MultiViews est activée pour + /tel/répertoire et si + /tel/répertoire/foo n'existe pas, le serveur parcourt + le répertoire à la recherche de fichiers nommés foo.*, et simule + littéralement une correspondance de types (type map) qui liste tous ces + fichiers, en leur associant les mêmes types de média et encodages de + contenu qu'ils auraient eu si le client avait demandé l'accès à l'un d'entre eux par son nom. Il choisit ensuite ce qui correspond le mieux aux besoins du client.

    -

    MultiViews peut aussi s'appliquer à la recherche du fichier - nommé par la directive MultiViews peut aussi s'appliquer à la recherche du fichier + nommé par la directive DirectoryIndex, si le serveur tente d'indexer - un répertoire. Si les fichiers de configuration spécifient

    + un répertoire. Si les fichiers de configuration spécifient

    DirectoryIndex index

    le serveur va choisir entre index.html - et index.html3 si les deux fichiers sont présents. Si aucun - n'est présent, mais index.cgi existe, - le serveur l'exécutera.

    + et index.html3 si les deux fichiers sont présents. Si aucun + n'est présent, alors qu’index.cgi existe, + le serveur l'exécutera.

    Si, parcequ'elle n'est pas reconnue par mod_mime, - l'extension d'un des fichiers du répertoire ne permet pas de - déterminer son jeu de caractères, son type de contenu, son langage, ou son - encodage, alors - le résultat dépendra de la définition de la directive MultiViewsMatch. Cette directive détermine - si les gestionnaires (handlers), les filtres, et autres types d'extensions - peuvent participer à la négociation MultiVues.

    + l'extension d'un des fichiers du répertoire ne permet pas de + déterminer son jeu de caractères, son type de contenu, son langage, ou son + encodage, + le résultat dépendra de la définition de la directive MultiViewsMatch. Cette directive détermine + si les gestionnaires (handlers), les filtres et autres types d'extensions + peuvent participer à la négociation MultiVues.

    -
    Les méthodes de négociation +
    Les méthodes de négociation -

    Une fois obtenue la liste des variantes pour une ressource donnée, - httpd dispose de deux méthodes pour choisir la meilleure variante à - retourner, s'il y a lieu, soit à partir d'un fichier de - correspondances de types, soit en se basant sur les noms de fichiers du - répertoire. Il n'est pas nécessaire de connaître en détails comment la - négociation fonctionne réellement pour pouvoir utiliser les fonctionnalités - de négociation de contenu de httpd. La suite de ce document explique - cependant les méthodes utilisées pour ceux ou celles qui sont - intéressés(ées).

    +

    Une fois obtenue la liste des variantes pour une ressource donnée, + httpd dispose de deux méthodes pour choisir la meilleure variante à + renvoyer, s'il y a lieu, soit à partir d'un fichier de + correspondances de types, soit en se basant sur les noms de fichier du + répertoire. Il n'est pas nécessaire de connaître en détails comment la + négociation fonctionne réellement pour pouvoir utiliser les fonctionnalités + de négociation de contenu de httpd. La suite de ce document explique + cependant les méthodes utilisées pour ceux ou celles qui sont + intéressés(ées).

    -

    Il existe deux méthodes de négociation :

    +

    Il existe deux méthodes de négociation :

      -
    1. La négociation effectuée par le serveur selon l'algorithme - de httpd est normalement utilisée. l'algorithme de +
    2. La négociation effectuée par le serveur selon l'algorithme + de httpd est utilisée par défaut. L'algorithme de httpd est - expliqué plus en détails ci-dessous. Quand cet algorithme est utilisé, - httpd peut parfois "bricoler" le facteur de qualité (qs) d'une dimension - particulière afin d'obtenir un meilleur résultat. - La manière dont httpd peut modifier les facteurs de qualité est - expliquée plus en détails ci-dessous.
    3. - -
    4. La négociation de contenu transparente est utilisée - quand le navigateur le demande explicitement selon le mécanisme défini - dans la RFC 2295. Cette méthode de négociation donne au navigateur le - contrôle total du choix de la meilleure variante; le résultat dépend - cependant de la spécificité des algorithmes utilisés par le navigateur. - Au cours du processus de négociation transparente, le navigateur peut - demander à httpd d'exécuter l'"algorithme de sélection de variante à - distance" défini dans la RFC 2296.
    5. + expliqué plus en détails ci-dessous. Quand cet algorithme est utilisé, + httpd peut parfois « bricoler » le facteur de qualité (qs) d'une dimension + particulière afin d'obtenir un meilleur résultat. + La manière dont httpd peut modifier les facteurs de qualité est + expliquée plus en détails ci-dessous. + +
    6. La négociation de contenu transparente est utilisée + quand le navigateur le demande explicitement selon le mécanisme défini + dans la RFC 2295. Cette méthode de négociation donne au navigateur le + contrôle total du choix de la meilleure variante ; le résultat dépend + cependant de la spécificité des algorithmes utilisés par le navigateur. + Au cours du processus de négociation transparente, le navigateur peut + demander à httpd d'exécuter l'« algorithme de sélection de variante à + distance » défini dans la RFC 2296.
    -
    Les dimensions de la négociation +
    Les dimensions de la négociation @@ -301,240 +301,241 @@ - + - + - - + - + - + - +
    Type de médiaType de médiaLe navigateur affiche ses préférences à l'aide du champ d'en-tête - Accept. Chaque type de média peut se voir associé un facteur de - qualité. La description de la variante peut aussi avoir un facteur de - qualité (le paramètre "qs").Le navigateur affiche ses préférences à l'aide du champ d'en-tête + Accept. Chaque type de média peut se voir associé un facteur de + qualité. La description de la variante peut aussi avoir un facteur de + qualité (le paramètre « qs »).
    LangageLe navigateur affiche ses préférences à l'aide du champ d'en-tête - Accept-Language. Chaque langue peut se voir associé un facteur de - qualité. Les variantes peuvent être associées avec zéro, un ou + Le navigateur affiche ses préférences à l'aide du champ d'en-tête + Accept-Language. Chaque langue peut se voir associé un facteur de + qualité. Les variantes peuvent être associées avec zéro, un ou plusieurs langages.
    EncodingEncodageLe navigateur affiche ses préférences à l'aide du champ d'en-tête - Accept-Encoding. Chaque encodage peut se voir associé un facteur de - qualité.Le navigateur affiche ses préférences à l'aide du champ d'en-tête + Accept-Encoding. Chaque encodage peut se voir associé un facteur de + qualité.
    CharsetJeu de caractèresLe navigateur affiche ses préférences à l'aide du champ d'en-tête - Accept-Charset. Chaque jeu de caractère peut se voir associé un facteur de - qualité. Les variantes peuvent préciser un jeu de caractères comme - paramètre du type de média.Le navigateur affiche ses préférences à l'aide du champ d'en-tête + Accept-Charset. Chaque jeu de caractère peut se voir associé un facteur de + qualité. Les variantes peuvent préciser un jeu de caractères comme + paramètre du type de média.
    -
    L'algorithme de négociation de +<section id="algorithm"><title>L'algorithme de négociation de httpd -

    httpd peut utiliser l'algorithme suivant pour choisir la "meilleure" - variante (s'il y en a une) à retourner au navigateur. Cet algorithme n'est pas +

    httpd peut utiliser l'algorithme suivant pour choisir la « meilleure » + variante (s'il y en a une) à renvoyer au navigateur. Cet algorithme n'est pas configurable. Il fonctionne comme suit :

      -
    1. En premier lieu, pour chaque dimension de la négociation, consulter - le champ d'en-tête Accept* approprié et assigner une qualité à - chaque variante. Si l'en-tête Accept* pour toute dimension - implique que la variante n'est pas acceptable, éliminer cette dernière. - S'il ne reste plus de variante, aller à l'étape 4.
    2. +
    3. En premier lieu, pour chaque dimension de la négociation, consulter + le champ d'en-tête Accept* approprié et assigner une qualité à + chaque variante. Si l'en-tête Accept* pour toute dimension + implique que la variante n'est pas acceptable, éliminer cette dernière. + S'il ne reste plus de variante, aller à l'étape 4.
    4. - Choisir la "meilleure" variante par élimination. Chacun des tests - suivants est effectué dans cet ordre. Toute variante non sélectionnée - à l'issue d'un test est éliminée. Après chaque test, s'il reste une - seule variante, choisir cette dernière comme celle qui correspond le - mieux puis aller à l'étape 3. S'il reste plusieurs variantes, passer + Choisir la « meilleure » variante par élimination. Chacun des tests + suivants est effectué dans cet ordre. Toute variante non sélectionnée + à l'issue d'un test est éliminée. Après chaque test, s'il reste une + seule variante, choisir cette dernière comme celle qui correspond le + mieux puis aller à l'étape 3. S'il reste plusieurs variantes, passer au test suivant.
        -
      1. Multiplier le facteur de qualité de l'en-tête - Accept par le facteur de qualité "qs" pour le type de - média de ces variantes, et choisir la variante qui possède la valeur +
      2. Multiplier le facteur de qualité de l'en-tête + Accept par le facteur de qualité « qs » pour le type de + média de ces variantes, et choisir la variante qui possède la valeur la plus importante.
      3. -
      4. Sélectionner les variantes qui possèdent le facteur de qualité +
      5. Sélectionner les variantes qui possèdent le facteur de qualité de langage le plus haut.
      6. -
      7. Sélectionner les variantes dont le langage correspond le mieux, - en se basant sur l'ordre des langages de l'en-tête +
      8. Sélectionner les variantes dont le langage correspond le mieux, + en se basant sur l'ordre des langages de l'en-tête Accept-Language (s'il existe), ou de la directive LanguagePriority (si elle existe).
      9. -
      10. Sélectionner les variantes possédant le paramètre de média - "level" le plus élevé (utilisé pour préciser la version des types de - média text/html).
      11. +
      12. Sélectionner les variantes possédant le paramètre de média + « level » le plus élevé (utilisé pour préciser la version des types de + média text/html).
      13. -
      14. Sélectionner les variantes possédant le paramètre de média - "charset" (jeu de caractères) qui correspond le mieux, en se basant - sur la ligne d'en-tête Accept-Charset . Le jeu de - caractères ISO-8859-1 est acceptable sauf s'il est explicitement - exclus. Les variantes avec un type de média text/* - mais non explicitement associées avec un jeu de caractères - particulier sont supposées être en ISO-8859-1.
      15. +
      16. Sélectionner les variantes possédant le paramètre de média + « charset » (jeu de caractères) qui correspond le mieux, en se basant + sur la ligne d'en-tête Accept-Charset . Le jeu de + caractères ISO-8859-1 est acceptable sauf s'il est explicitement + exclus. Les variantes avec un type de média text/* + mais non explicitement associées avec un jeu de caractères + particulier sont supposées être en ISO-8859-1.
      17. -
      18. Sélectionner les variantes dont le paramètre de média "charset" - associé n'est pas ISO-8859-1. S'il n'en existe pas, - sélectionner toutes les variantes.
      19. +
      20. Sélectionner les variantes dont le paramètre de média « charset » + associé n'est pas ISO-8859-1. S'il n'en existe pas, + sélectionner toutes les variantes.
      21. -
      22. Sélectionner les variantes avec le meilleur encodage. S'il existe +
      23. Sélectionner les variantes avec le meilleur encodage. S'il existe des variantes avec un encodage acceptable pour le client, - sélectionner celles-ci. Sinon, s'il existe des variantes encodées et - des variantes non encodées, ne sélectionner que les variantes non - encodées. Si toutes les variantes sont encodées ou si aucune - ne l'est, sélectionner toutes les variantes.
      24. + sélectionner celles-ci. Sinon, s'il existe des variantes encodées et + des variantes non encodées, ne sélectionner que les variantes non + encodées. Si toutes les variantes sont encodées ou si aucune + ne l'est, sélectionner toutes les variantes. -
      25. Sélectionner les variantes dont le contenu a la longueur +
      26. Sélectionner les variantes dont le contenu a la longueur la plus courte.
      27. -
      28. Sélectionner la première des variantes restantes. Il s'agira - soit de la première variante listée dans le fichier de +
      29. Sélectionner la première des variantes restantes. Il s'agira + soit de la première variante listée dans le fichier de correspondances de types, soit, quand les variantes sont lues depuis - le répertoire, la première par ordre alphabétique quand elles sont - triées selon le code ASCII.
      30. + le répertoire, la première par ordre alphabétique quand elles sont + triées selon le code ASCII.
    5. -
    6. L'algorithme a maintenant sélectionné une variante considérée comme - la "meilleure", il la retourne donc au client en guise de réponse. - L'en-tête HTTP Vary de la réponse est renseigné de façon à - indiquer les dimensions de la négociation (les navigateurs et les caches +
    7. L'algorithme a maintenant sélectionné une variante considérée comme + la « meilleure », il la renvoie donc au client en guise de réponse. + L'en-tête HTTP Vary de la réponse est renseigné de façon à + indiquer les dimensions de la négociation (les navigateurs et les caches peuvent utiliser cette information lors de la mise en cache de la - ressource). Travail terminé.
    8. - -
    9. Le passage par cette étape signifie qu'aucune variante n'a été - sélectionnée (parcequ'aucune n'est acceptable pour le navigateur). - Envoyer une réponse avec un code de statut 406 (qui signifie "Aucune - représentation acceptable") et un corps comportant un document HTML qui - affiche les variantes disponibles. Renseigner aussi l'en-tête HTTP - Vary de façon à indiquer les dimensions de la variante.
    10. + ressource). Travail terminé. + +
    11. Le passage par cette étape signifie qu'aucune variante n'a été + sélectionnée (parce qu'aucune n'est acceptable pour le navigateur). + Envoyer une réponse avec un code de statut 406 (qui signifie « Aucune + représentation acceptable ») et un corps comportant un document HTML qui + affiche les variantes disponibles. Renseigner aussi l'en-tête HTTP + Vary de façon à indiquer les dimensions de la variante.
    -
    Ajustement des valeurs de qualité +
    Ajustement des valeurs de qualité -

    Parfois httpd modifie les valeurs de qualité par rapport à celles qui - découleraient d'une stricte interprétation de l'algorithme de négociation - de httpd ci-dessus, ceci pour améliorer les résultats de l'algorithme pour - les navigateurs qui envoient des informations incomplètes ou inappropriées. +

    Parfois httpd modifie les valeurs de qualité par rapport à celles qui + découleraient d'une stricte interprétation de l'algorithme de négociation + de httpd ci-dessus, cela afin d’améliorer les résultats de l'algorithme pour + les navigateurs qui envoient des informations incomplètes ou inappropriées. Certains des navigateurs les plus populaires envoient des informations dans - l'en-tête Accept qui, sans ce traitement, provoqueraient la - sélection d'une variante inappropriée dans de nombreux cas. Quand un - navigateur envoie des informations complètes et correctes ces ajustements - ne sont pas effectués.

    + l'en-tête Accept qui, sans ce traitement, provoqueraient la + sélection d'une variante inappropriée dans de nombreux cas. Quand un + navigateur envoie des informations complètes et correctes ces ajustements + ne sont pas effectués.

    -
    Types de média et caractères génériques +
    Types de média et caractères génériques -

    L'en-tête de requête Accept: indique les types de média - souhaités. Il peut aussi contenir des types de média avec caractères - génériques, comme "image/*" ou "*/*" où * correspond à n'importe quelle - chaîne de caractères. Ainsi une requête contenant :

    +

    L'en-tête de requête Accept: indique les types de média + souhaités. Il peut aussi contenir des types de média avec caractères + génériques, comme « image/* » ou « */* » où * correspond à n'importe quelle + chaîne de caractères. Ainsi une requête contenant :

    Accept: image/*, */* -

    indiquerait que tout type de média est acceptable, avec une préférence - pour les types commençant par "image/". - Certains navigateurs ajoutent par défaut des types de média avec caractères - génériques aux types explicitement nommés qu'ils peuvent gérer. +

    indiquerait que tout type de média est acceptable, avec une préférence + pour les types commençant par « image/ ». + Certains navigateurs ajoutent par défaut des types de média avec caractères + génériques aux types explicitement nommés qu'ils peuvent gérer. Par exemple :

    Accept: text/html, text/plain, image/gif, image/jpeg, */* -

    Ceci indique que les types explicitement listés sont préférés, mais - qu'une représentation avec un type différent de ces derniers conviendra - aussi. Les valeurs de qualités explicites, - afin de préciser ce que veut vraiment le navigateur, s'utilisent +

    Cela indique que les types explicitement listés sont préférés, mais + qu'une représentation avec un type différent de ces derniers conviendra + aussi. Les valeurs de qualités explicites, + afin de préciser ce que veut vraiment le navigateur, s'utilisent comme suit :

    Accept: text/html, text/plain, image/gif, image/jpeg, */*; q=0.01 -

    Les types explicites n'ont pas de facteur de qualité, la valeur par - défaut de leur préférence est donc de 1.0 (la plus haute). Le type avec - caractères génériques */* se voit attribuer une préférence basse de 0.01, - si bien que les types autres que ceux explicitement listés ne seront retournés - que s'il n'existe pas de variante correspondant à un type explicitement - listé.

    - -

    Si l'en-tête Accept: ne contient pas aucun - facteur de qualité, httpd positionne la valeur de qualité de - "*/*", si present, à 0.01 pour simuler l'effet désiré. Il positionne aussi - la valeur de qualité des types avec caractères génériques au format - "type/*" à 0.02 (ils sont donc préférés à ceux correspondant à "*/*"). Si - un type de média dans l'en-tête Accept: contient un facteur de - qualité, ces valeurs spéciales ne seront pas appliquées, de façon - à ce que les requêtes de navigateurs qui envoient les informations - explicites à prendre en compte fonctionnent comme souhaité.

    +

    Les types explicites n'ont pas de facteur de qualité, la valeur par + défaut de leur préférence est donc de 1.0 (la plus haute). Le type avec + caractères génériques */* se voit attribuer une préférence basse de 0.01, + si bien que les types autres que ceux explicitement listés ne seront + renvoyés + que s'il n'existe pas de variante correspondant à un type explicitement + listé.

    + +

    Si l'en-tête Accept: ne contient pas de + facteur de qualité, httpd positionne la valeur de qualité de + « */* », si présent, à 0.01 pour simuler l'effet désiré. Il positionne aussi + la valeur de qualité des types avec caractères génériques au format + « type/* » à 0.02 (ils sont donc préférés à ceux correspondant à « */* »). Si + un type de média dans l'en-tête Accept: contient un facteur de + qualité, ces valeurs spéciales ne seront pas appliquées, de façon + à ce que les requêtes de navigateurs qui envoient les informations + explicites à prendre en compte fonctionnent comme souhaité.

    -
    Exceptions dans la négociation du +<section id="exceptions"><title>Exceptions dans la négociation du langage -

    A partir de la version 2.0 de httpd, certaines exceptions ont été - ajoutées à l'algorithme de négociation afin de ménager une issue de secours - quand la négociation ne trouve aucun langage correspondant.

    +

    A partir de la version 2.0 de httpd, certaines exceptions ont été + ajoutées à l'algorithme de négociation afin de ménager une issue de secours + quand la négociation ne trouve aucun langage correspondant.

    Quand un client demande une page sur votre serveur, si ce dernier ne - parvient pas à trouver une page dont la langue corresponde à l'en-tête - Accept-language envoyé par le navigateur, il enverra au client - une réponse "Aucune variante acceptable" ou "Plusieurs choix possibles". - Pour éviter ces - messages d'erreur, il est possible de configurer httpd de façon à ce que, - dans ces cas, il ignore l'en-tête Accept-language et fournisse - tout de même un document, même s'il ne correspond pas exactement à la + parvient pas à trouver une page dont la langue correspond à l'en-tête + Accept-language envoyé par le navigateur, il enverra au client + une réponse « Aucune variante acceptable » ou « Plusieurs choix possibles ». + Pour éviter ces + messages d'erreur, il est possible de configurer httpd de façon que, + dans ces cas, il ignore l'en-tête Accept-language et fournisse + tout de même un document, même s'il ne correspond pas exactement à la demande explicite du client. La directive ForceLanguagePriority - peut être utilisée pour éviter ces messages d'erreur et leur substituer une - page dont le langage sera déterminé en fonction du contenu de la directive + peut être utilisée pour éviter ces messages d'erreur et leur substituer une + page dont le langage sera déterminé en fonction du contenu de la directive LanguagePriority.

    -

    Le serveur va aussi essayer d'étendre sa recherche de correspondance aux - sous-ensembles de langages quand aucune correspondance exacte ne peut être - trouvée. Par exemple, si un client demande des documents possédant le - langage en-GB, c'est à dire anglais britannique, le standard - HTTP/1.1 n'autorise normalement pas le serveur à faire correspondre cette - demande à un document dont le langage est simplement en. - (Notez qu'inclure en-GB et non en dans l'en-tête +

    Le serveur va aussi essayer d'étendre sa recherche de correspondance aux + sous-ensembles de langages quand aucune correspondance exacte ne peut être + trouvée. Par exemple, si un client demande des documents possédant le + langage en-GB, c'est à dire anglais britannique, le standard + HTTP/1.1 n'autorise normalement pas le serveur à faire correspondre cette + demande à un document dont le langage est simplement en + (notez qu'inclure en-GB et non en dans l'en-tête Accept-Language constitue une quasi-erreur de configuration, - car il est très peu probable qu'un lecteur qui comprend l'anglais - britannique, ne comprenne pas l'anglais en général. Malheureusement, de - nombreux clients ont réellement des configurations par défaut de ce type.) - Cependant, si aucune autre correspondance de langage n'est possible, et que le - serveur est sur le point de retourner une erreur "Aucune variable - acceptable" ou de choisir le langage défini par la directive LanguagePriority, le serveur ignorera - la spécification du sous-ensemble de langage et associera la demande en - en-GB à des documents en en. Implicitement, - httpd ajoute le langage parent à la liste de langues acceptés par le - client avec une valeur de qualité très basse. Notez cependant que si le - client demande "en-GB; q=0.9, fr; q=0.8", et le serveur dispose de - documents estampillés "en" et "fr", alors c'est le document "fr" qui sera - retourné, tout ceci dans un souci de compatibilité avec la spécification + la spécification du sous-ensemble de langage et associera la demande en + en-GB à des documents en en. Implicitement, + httpd ajoute le langage parent à la liste de langages acceptés par le + client avec une valeur de qualité très basse. Notez cependant que si le + client demande « en-GB; q=0.9, fr; q=0.8 », et si le serveur dispose de + documents estampillés « en » et « fr », c'est le document « fr » qui sera + renvoyé, tout cela dans un souci de compatibilité avec la spécification HTTP/1.1 et afin de fonctionner efficacement avec les clients - correctement configurés.

    + correctement configurés.

    -

    Pour supporter les techniques avancées (comme les cookies ou les chemins - d'URL spéciaux) afin de déterminer le langage préféré de l'utilisateur, le - module mod_negotiation reconnaît la +

    Pour prendre en charge les techniques avancées (comme les cookies ou les chemins + d'URL spéciaux) afin de déterminer le langage préféré de l'utilisateur, le + module mod_negotiation reconnaît la variable d'environnement prefer-language - depuis la version 2.0.47 de httpd. Si elle est définie et contient un - symbole de langage approprié, mod_negotiation va essayer - de sélectionner une variante correspondante. S'il n'existe pas de telle - variante, le processus normal de négociation sera lancé.

    + depuis la version 2.0.47 de httpd. Si elle est définie et contient un + symbole de langage approprié, mod_negotiation va essayer + de sélectionner une variante correspondante. S'il n'existe pas de telle + variante, le processus normal de négociation sera lancé.

    Exemple @@ -545,35 +546,35 @@ Header append Vary cookie
    -
    Extensions à la négociation de contenu +<section id="extensions"><title>Extensions à la négociation de contenu transparente -

    httpd étend le protocole de négociation de contenu transparente (RFC -2295) comme suit. Un nouvel élément {encodage ..} est utilisé dans +

    httpd étend le protocole de négociation de contenu transparente (RFC +2295) comme suit. Un nouvel élément {encodage ..} est utilisé dans les listes de variantes pour marquer celles qui ne sont disponibles qu'avec un -encodage de contenu spécifique. L'implémentation de l'algorithme -RVSA/1.0 (RFC 2296) est étendue à la reconnaissance de variantes encodées dans -la liste, et à leur utilisation en tant que variantes candidates à partir du -moment où leur encodage satisfait au contenu de l'en-tête de requête -Accept-Encoding. L'implémentation RVSA/1.0 n'arrondit pas les -facteurs de qualité calculés à 5 décimales avant d'avoir choisi la meilleure +encodage de contenu spécifique. L'implémentation de l'algorithme +RVSA/1.0 (RFC 2296) est étendue à la reconnaissance de variantes encodées dans +la liste, et à leur utilisation en tant que variantes candidates à partir du +moment où leur encodage satisfait au contenu de l'en-tête de requête +Accept-Encoding. L'implémentation RVSA/1.0 n'arrondit pas les +facteurs de qualité calculés à 5 décimales avant d'avoir choisi la meilleure variante.

    -
    Remarques à propos des liens hypertextes et des +<section id="naming"><title>Remarques à propos des liens hypertextes et des conventions de nommage -

    Si vous utilisez la négociation de langage, vous avez le choix entre - différentes conventions de nommage, car les fichiers peuvent posséder - plusieurs extensions, et l'ordre dans lequel ces dernières apparaissent - est en général sans rapport (voir la documentation sur le module Si vous utilisez la négociation de langage, vous avez le choix entre + différentes conventions de nommage, car les fichiers peuvent posséder + plusieurs extensions, et l'ordre dans lequel ces dernières apparaissent + est en général sans rapport (voir la documentation sur le module mod_mime - pour plus de détails).

    + pour plus de détails).

    -

    Un fichier type possède une extension liée au type MIME +

    Un fichier type possède une extension liée au type MIME (par exemple, html), mais parfois aussi une - extension liée à l'encodage (par exemple, gz), - et bien sûr une extension liée au langage + extension liée à l'encodage (par exemple, gz), + et bien sûr une extension liée au langage (par exemple, en) quand plusieurs variantes de langage sont disponibles pour ce fichier.

    @@ -588,7 +589,7 @@ conventions de nommage

    Ci-dessous d'autres exemples de noms de fichiers avec des liens - hypertextes valides et invalides :

    + hypertextes valables et non valables :

    @@ -662,48 +663,48 @@ conventions de nommage

    En regardant la table ci-dessus, vous remarquerez qu'il est toujours possible d'utiliser le nom de fichier sans extension dans un lien (par exemple, foo). L'avantage est de pouvoir - dissimuler le type réel du fichier associé à un document et de pouvoir + dissimuler le type réel du fichier associé à un document et de pouvoir le modifier - ultérieurement, par exemple, de html à - shtml ou cgi sans avoir à - mettre à jour aucun lien.

    - -

    Si vous souhaitez continuer à utiliser un type MIME dans vos liens - (par exemple foo.html), l'extension liée au langage - (y compris une extension liée à l'encodage s'il en existe une) - doit se trouver à droite de l'extension liée au type MIME + ultérieurement, par exemple, de html à + shtml ou cgi sans avoir à + mettre à jour aucun lien.

    + +

    Si vous souhaitez continuer à utiliser un type MIME dans vos liens + (par exemple foo.html), l'extension liée au langage + (y compris une extension liée à l'encodage s'il en existe une) + doit se trouver à droite de l'extension liée au type MIME (par exemple, foo.html.en).

    Remarque sur la mise en cache -

    Quand un cache stocke une représentation, il l'associe avec l'URL de la - requête. Lorsque cette URL est à nouveau demandée, le cache peut utiliser - la représentation stockée. Cependant, si la ressource est négociable au - niveau du serveur, il se peut que seule la première variante demandée soit +

    Quand un cache stocke une représentation, il l'associe avec l'URL de la + requête. Lorsque cette URL est à nouveau demandée, le cache peut utiliser + la représentation stockée. Cependant, si la ressource est négociable au + niveau du serveur, il se peut que seule la première variante demandée soit mise en cache et de ce fait, la correspondance positive du cache peut - entraîner une réponse inappropriée. Pour - éviter ceci, httpd marque par - défaut toutes les réponses qui sont retournées après une négociation de - contenu comme "non-cachables" par les clients HTTP/1.0. httpd supporte - aussi les fonctionnalités du protocole HTTP/1.1 afin de permettre la mise - en cache des réponses négociées.

    - -

    Pour les requêtes en provenance d'un client compatible HTTP/1.0 + entraîner une réponse inappropriée. Pour + éviter cela, httpd marque par + défaut toutes les réponses qui sont renvoyées après une négociation de + contenu comme « non-cachables » par les clients HTTP/1.0. httpd prend + aussi en charge les fonctionnalités du protocole HTTP/1.1 afin de permettre la mise + en cache des réponses négociées.

    + +

    Pour les requêtes en provenance d'un client compatible HTTP/1.0 (un navigateur ou un cache), la directive CacheNegotiatedDocs peut être utilisée - pour permettre la mise en cache des réponses qui ont fait l'objet d'une - négociation. Cette directive peut intervenir dans la configuration au - niveau du serveur ou de l'hôte virtuel, et n'accepte aucun argument. Elle - n'a aucun effet sur les requêtes en provenance de clients HTTP/1.1.

    - -

    Pour les clients HTTP/1.1, httpd envoie un en-tête de réponse HTTP - Vary afin d'indiquer les dimensions de la négociation pour - cette réponse. Les caches peuvent - utiliser cette information afin de déterminer - si une requête peut être servie à partir de la copie locale. Pour inciter - un cache à utiliser la copie locale sans tenir compte des dimensions de la - négociation, définissez la + module="mod_negotiation">CacheNegotiatedDocs peut être utilisée + pour permettre la mise en cache des réponses qui ont fait l'objet d'une + négociation. Cette directive peut intervenir dans la configuration au + niveau du serveur ou de l'hôte virtuel, et n'accepte aucun argument. Elle + n'a aucun effet sur les requêtes en provenance de clients HTTP/1.1.

    + +

    Pour les clients HTTP/1.1, httpd envoie un en-tête de réponse HTTP + Vary afin d'indiquer les dimensions de la négociation pour + cette réponse. Les caches peuvent + utiliser cette information afin de déterminer + si une requête peut être servie à partir de la copie locale. Pour inciter + un cache à utiliser la copie locale sans tenir compte des dimensions de la + négociation, définissez la variable d'environnement force-no-vary.

    diff --git a/docs/manual/mod/allmodules.xml.fr b/docs/manual/mod/allmodules.xml.fr index 9da2838e64..950c26b7f6 100644 --- a/docs/manual/mod/allmodules.xml.fr +++ b/docs/manual/mod/allmodules.xml.fr @@ -119,7 +119,7 @@ mod_substitute.xml.fr mod_suexec.xml.fr mod_systemd.xml.fr - mod_tls.xml + mod_tls.xml.fr mod_unique_id.xml.fr mod_unixd.xml.fr mod_userdir.xml.fr From 07d211950671232ad7cb5694b155da540ce19059 Mon Sep 17 00:00:00 2001 From: Lucien Gentis Date: Mon, 23 Sep 2024 12:27:19 +0000 Subject: [PATCH 061/176] fr doc rebuild. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1920859 13f79535-47bb-0310-9956-ffa450edef68 --- docs/manual/content-negotiation.html.fr.utf8 | 147 ++++++++++--------- docs/manual/mod/allmodules.xml.de | 1 - docs/manual/mod/allmodules.xml.es | 1 - docs/manual/mod/allmodules.xml.fr | 1 - docs/manual/mod/allmodules.xml.ja | 1 - docs/manual/mod/allmodules.xml.ko | 1 - docs/manual/mod/allmodules.xml.tr | 1 - docs/manual/mod/allmodules.xml.zh-cn | 1 - docs/manual/mod/directives.html.fr.utf8 | 15 -- docs/manual/mod/index.html.fr.utf8 | 5 +- docs/manual/mod/quickreference.html.fr.utf8 | 79 ++++------ docs/manual/sitemap.html.fr.utf8 | 1 - 12 files changed, 107 insertions(+), 147 deletions(-) diff --git a/docs/manual/content-negotiation.html.fr.utf8 b/docs/manual/content-negotiation.html.fr.utf8 index 7272db7d44..40cb87ff99 100644 --- a/docs/manual/content-negotiation.html.fr.utf8 +++ b/docs/manual/content-negotiation.html.fr.utf8 @@ -31,7 +31,7 @@ -

    Apache HTTPD supporte la négociation de +

    Apache HTTPD prend en charge la négociation de contenu telle qu'elle est décrite dans la spécification HTTP/1.1. Il peut choisir la meilleure représentation d'une ressource en fonction des préférences du navigateur pour ce qui @@ -63,7 +63,7 @@ conventions de nommage différents types de média, ou une combinaison des deux. Pour faire le meilleur choix, on peut fournir à l'utilisateur une page d'index, et le laisser choisir. Cependant, le serveur peut souvent faire - ce choix automatiquement. Ceci est possible car les navigateurs peuvent + ce choix automatiquement. Cela est possible car les navigateurs peuvent envoyer des informations sur les représentations qu'ils préfèrent à l'intérieur de chaque requête. Par exemple, un navigateur peut indiquer @@ -81,7 +81,7 @@ conventions de nommage

    À titre d'exemple d'une requête plus complexe, ce navigateur a été configuré pour accepter le français et l'anglais, avec une préférence pour le français, et accepter différents types de média, avec une préférence - pour HTML par rapport à au texte plat ("plain text") ou autres types de fichiers texte, et + pour HTML par rapport à au texte plat (« plain text ») ou autres types de fichiers texte, et avec une préférence pour GIF ou JPEG par rapport à tout autre type de média, mais autorisant tout autre type de média en dernier ressort :

    @@ -90,24 +90,24 @@ conventions de nommage Accept: text/html; q=1.0, text/*; q=0.8, image/gif; q=0.6, image/jpeg; q=0.6, image/*; q=0.5, */*; q=0.1

    -

    httpd supporte la négociation de contenu "server driven" (telle qu'elle +

    httpd prend en charge la négociation de contenu « server driven » (telle qu'elle est définie dans la spécification HTTP/1.1), où c'est le serveur qui - décide quelle est la meilleure représentation à retourner pour la ressource - demandée. Il supporte entièrement les en-têtes de requête + décide quelle est la meilleure représentation à renvoyer pour la ressource + demandée. Il prend entièrement en charge les en-têtes de requête Accept, Accept-Language, Accept-Charset et Accept-Encoding. - httpd supporte aussi la négociation de contenu transparente, qui est un + httpd prend aussi en charge la négociation de contenu transparente, qui est un protocole de négociation expérimental défini dans les RFC 2295 et 2296. - Il ne supporte pas la négociation de fonctionnalité (feature negotiation) + Il ne prend pas en charge la négociation de fonctionnalité (feature negotiation) telle qu'elle est définie dans ces RFCs.

    Une ressource est une entité conceptuelle identifiée - par une URI (RFC 2396). Un serveur HTTP comme le serveur HTTP Apache + par un URI (RFC 2396). Un serveur HTTP comme le serveur HTTP Apache propose l'accès à des représentations de la ressource à l'intérieur de son espace de nommage, chaque représentation étant composée d'une séquence d'octets avec la définition d'un type de media, d'un jeu de caractères, - d'un encodage, etc... A un instant donné, chaque ressource peut être + d'un encodage, etc. À un instant donné, chaque ressource peut être associée avec zéro, une ou plusieurs représentations. Si plusieurs représentations sont disponibles, la ressource est qualifiée de négociable et chacune de ses représentations se nomme @@ -118,16 +118,16 @@ conventions de nommage

    La négociation avec httpd

    -

    Afin de négocier une ressource, on doit fournir au serveur des +

    Pour négocier une ressource, on doit fournir au serveur des informations à propos de chacune des variantes. Il y a deux manières - d'accomplir ceci :

    + d'y parvenir :

      -
    • Utiliser une liste de correspondances de type ("type-map") (c'est à dire +
    • Utiliser une liste de correspondances de type (« type-map ») (c'est à dire un fichier *.var) qui nomme explicitement les fichiers contenant les variantes, ou
    • -
    • Utiliser une recherche "multivues", où le serveur effectue une +
    • Utiliser une recherche « multivues », où le serveur effectue une recherche de correspondance sur un motif de nom de fichier implicite et fait son choix parmi les différents résultats.
    @@ -141,7 +141,7 @@ conventions de nommage type MIME application/x-type-map). Notez que pour utiliser cette fonctionnalité, vous devez, dans le fichier de configuration, définir un - gestionnaire qui associe un suffixe de fichier à une type-map; + gestionnaire qui associe un suffixe de fichier à une type-map, ce qui se fait simplement en ajoutant

    AddHandler type-map .var
    @@ -156,13 +156,13 @@ conventions de nommage foo.var.

    Ce fichier doit comporter une entrée pour chaque variante - disponible; chaque entrée consiste en une ligne contiguë d'en-têtes au - format HTTP. les entrées sont séparées par des lignes vides. Les lignes + disponible ; chaque entrée consiste en une ligne contiguë d'en-têtes au + format HTTP. Les entrées sont séparées par des lignes vides. Les lignes vides à l'intérieur d'une entrée sont interdites. Par convention, le fichier de correspondances de types débute par une entrée concernant l'entité considérée dans son ensemble (bien que ce ne soit pas obligatoire, et ignoré si présent). Un exemple de fichier de - correspondance de types est fourni + correspondances de types est fourni ci-dessous.

    Les URIs de ce fichier sont relatifs à la localisation du fichier @@ -187,7 +187,7 @@ conventions de nommage

    Notez aussi qu'un fichier de correspondances de types prend le pas sur les extensions de noms de fichiers, même si les Multivues sont activées. Si les variantes sont de qualités différentes, on doit l'indiquer - à l'aide du paramètre "qs" à la suite du type de média, comme pour cette + à l'aide du paramètre « qs » à la suite du type de média, comme pour cette image (disponible aux formats JPEG, GIF, ou ASCII-art) :

    @@ -212,7 +212,7 @@ conventions de nommage compte des capacités du client. Par exemple, un fichier JPEG possède en général une qualité supérieure à celle d'un fichier ASCII s'il représente une photographie. Cependant, si la ressource représentée est - à un ASCII art original, la représentation ASCII sera de meilleure qualité + un ASCII art original, la représentation ASCII sera de meilleure qualité que la représentation JPEG. Ainsi une valeur de qs est associée à une variante en fonction de la nature de la ressource qu'elle représente.

    @@ -230,13 +230,13 @@ conventions de nommage httpd.conf, ou (si AllowOverride est correctement positionnée) dans des fichiers .htaccess. Notez que Options All - n'active pas MultiViews; vous devez activer cette option en + n'active pas MultiViews ; vous devez activer cette option en la nommant explicitement.

    L'effet de MultiViews est le suivant : si le serveur reçoit une requête pour /tel/répertoire/foo, si MultiViews est activée pour - /tel/répertoire, et si + /tel/répertoire et si /tel/répertoire/foo n'existe pas, le serveur parcourt le répertoire à la recherche de fichiers nommés foo.*, et simule littéralement une correspondance de types (type map) qui liste tous ces @@ -252,15 +252,15 @@ conventions de nommage

    le serveur va choisir entre index.html et index.html3 si les deux fichiers sont présents. Si aucun - n'est présent, mais index.cgi existe, + n'est présent, alors qu’index.cgi existe, le serveur l'exécutera.

    Si, parcequ'elle n'est pas reconnue par mod_mime, l'extension d'un des fichiers du répertoire ne permet pas de déterminer son jeu de caractères, son type de contenu, son langage, ou son - encodage, alors + encodage, le résultat dépendra de la définition de la directive MultiViewsMatch. Cette directive détermine - si les gestionnaires (handlers), les filtres, et autres types d'extensions + si les gestionnaires (handlers), les filtres et autres types d'extensions peuvent participer à la négociation MultiVues.

    top
    @@ -269,8 +269,8 @@ conventions de nommage

    Une fois obtenue la liste des variantes pour une ressource donnée, httpd dispose de deux méthodes pour choisir la meilleure variante à - retourner, s'il y a lieu, soit à partir d'un fichier de - correspondances de types, soit en se basant sur les noms de fichiers du + renvoyer, s'il y a lieu, soit à partir d'un fichier de + correspondances de types, soit en se basant sur les noms de fichier du répertoire. Il n'est pas nécessaire de connaître en détails comment la négociation fonctionne réellement pour pouvoir utiliser les fonctionnalités de négociation de contenu de httpd. La suite de ce document explique @@ -281,10 +281,10 @@ conventions de nommage

    1. La négociation effectuée par le serveur selon l'algorithme - de httpd est normalement utilisée. l'algorithme de + de httpd est utilisée par défaut. L'algorithme de httpd est expliqué plus en détails ci-dessous. Quand cet algorithme est utilisé, - httpd peut parfois "bricoler" le facteur de qualité (qs) d'une dimension + httpd peut parfois « bricoler » le facteur de qualité (qs) d'une dimension particulière afin d'obtenir un meilleur résultat. La manière dont httpd peut modifier les facteurs de qualité est expliquée plus en détails ci-dessous.
    2. @@ -292,11 +292,11 @@ conventions de nommage
    3. La négociation de contenu transparente est utilisée quand le navigateur le demande explicitement selon le mécanisme défini dans la RFC 2295. Cette méthode de négociation donne au navigateur le - contrôle total du choix de la meilleure variante; le résultat dépend + contrôle total du choix de la meilleure variante ; le résultat dépend cependant de la spécificité des algorithmes utilisés par le navigateur. Au cours du processus de négociation transparente, le navigateur peut - demander à httpd d'exécuter l'"algorithme de sélection de variante à - distance" défini dans la RFC 2296.
    4. + demander à httpd d'exécuter l'« algorithme de sélection de variante à + distance » défini dans la RFC 2296.

    Les dimensions de la négociation

    @@ -315,7 +315,7 @@ conventions de nommage
    + qualité (le paramètre « qs »). @@ -328,7 +328,7 @@ conventions de nommage - + - + - + + + + + + From 452b4827c6d1c103282306bba3dac36667f596c8 Mon Sep 17 00:00:00 2001 From: Yann Ylavic Date: Fri, 18 Oct 2024 13:14:11 +0000 Subject: [PATCH 085/176] Follow up to r1920745: More mod_tls docs removal. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1921403 13f79535-47bb-0310-9956-ffa450edef68 --- docs/manual/mod/mod_tls.html | 5 - docs/manual/mod/mod_tls.html.en | 663 ------------------------------- docs/manual/mod/mod_tls.xml.meta | 12 - 3 files changed, 680 deletions(-) delete mode 100644 docs/manual/mod/mod_tls.html delete mode 100644 docs/manual/mod/mod_tls.html.en delete mode 100644 docs/manual/mod/mod_tls.xml.meta diff --git a/docs/manual/mod/mod_tls.html b/docs/manual/mod/mod_tls.html deleted file mode 100644 index 1e7dfb0761..0000000000 --- a/docs/manual/mod/mod_tls.html +++ /dev/null @@ -1,5 +0,0 @@ -# GENERATED FROM XML -- DO NOT EDIT - -URI: mod_tls.html.en -Content-Language: en -Content-type: text/html; charset=UTF-8 diff --git a/docs/manual/mod/mod_tls.html.en b/docs/manual/mod/mod_tls.html.en deleted file mode 100644 index 56a59b8ec1..0000000000 --- a/docs/manual/mod/mod_tls.html.en +++ /dev/null @@ -1,663 +0,0 @@ - - - - - -mod_tls - Apache HTTP Server Version 2.4 - - - - - - - - -
    <-
    - -
    -

    Apache Module mod_tls

    -
    -

    Available Languages:  en 

    -
    -
    Le navigateur affiche ses préférences à l'aide du champ d'en-tête Accept. Chaque type de média peut se voir associé un facteur de qualité. La description de la variante peut aussi avoir un facteur de - qualité (le paramètre "qs").
    EncodingEncodage Le navigateur affiche ses préférences à l'aide du champ d'en-tête Accept-Encoding. Chaque encodage peut se voir associé un facteur de @@ -336,7 +336,7 @@ conventions de nommage
    CharsetJeu de caractères Le navigateur affiche ses préférences à l'aide du champ d'en-tête Accept-Charset. Chaque jeu de caractère peut se voir associé un facteur de @@ -349,8 +349,8 @@ conventions de nommage

    L'algorithme de négociation de httpd

    -

    httpd peut utiliser l'algorithme suivant pour choisir la "meilleure" - variante (s'il y en a une) à retourner au navigateur. Cet algorithme n'est pas +

    httpd peut utiliser l'algorithme suivant pour choisir la « meilleure » + variante (s'il y en a une) à renvoyer au navigateur. Cet algorithme n'est pas configurable. Il fonctionne comme suit :

      @@ -361,7 +361,7 @@ httpd S'il ne reste plus de variante, aller à l'étape 4.
    1. - Choisir la "meilleure" variante par élimination. Chacun des tests + Choisir la « meilleure » variante par élimination. Chacun des tests suivants est effectué dans cet ordre. Toute variante non sélectionnée à l'issue d'un test est éliminée. Après chaque test, s'il reste une seule variante, choisir cette dernière comme celle qui correspond le @@ -370,7 +370,7 @@ httpd
      1. Multiplier le facteur de qualité de l'en-tête - Accept par le facteur de qualité "qs" pour le type de + Accept par le facteur de qualité « qs » pour le type de média de ces variantes, et choisir la variante qui possède la valeur la plus importante.
      2. @@ -383,18 +383,18 @@ httpd LanguagePriority (si elle existe).
      3. Sélectionner les variantes possédant le paramètre de média - "level" le plus élevé (utilisé pour préciser la version des types de + « level » le plus élevé (utilisé pour préciser la version des types de média text/html).
      4. Sélectionner les variantes possédant le paramètre de média - "charset" (jeu de caractères) qui correspond le mieux, en se basant + « charset » (jeu de caractères) qui correspond le mieux, en se basant sur la ligne d'en-tête Accept-Charset . Le jeu de caractères ISO-8859-1 est acceptable sauf s'il est explicitement exclus. Les variantes avec un type de média text/* mais non explicitement associées avec un jeu de caractères particulier sont supposées être en ISO-8859-1.
      5. -
      6. Sélectionner les variantes dont le paramètre de média "charset" +
      7. Sélectionner les variantes dont le paramètre de média « charset » associé n'est pas ISO-8859-1. S'il n'en existe pas, sélectionner toutes les variantes.
      8. @@ -417,16 +417,16 @@ httpd
      9. L'algorithme a maintenant sélectionné une variante considérée comme - la "meilleure", il la retourne donc au client en guise de réponse. + la « meilleure », il la renvoie donc au client en guise de réponse. L'en-tête HTTP Vary de la réponse est renseigné de façon à indiquer les dimensions de la négociation (les navigateurs et les caches peuvent utiliser cette information lors de la mise en cache de la ressource). Travail terminé.
      10. Le passage par cette étape signifie qu'aucune variante n'a été - sélectionnée (parcequ'aucune n'est acceptable pour le navigateur). - Envoyer une réponse avec un code de statut 406 (qui signifie "Aucune - représentation acceptable") et un corps comportant un document HTML qui + sélectionnée (parce qu'aucune n'est acceptable pour le navigateur). + Envoyer une réponse avec un code de statut 406 (qui signifie « Aucune + représentation acceptable ») et un corps comportant un document HTML qui affiche les variantes disponibles. Renseigner aussi l'en-tête HTTP Vary de façon à indiquer les dimensions de la variante.
      @@ -437,7 +437,7 @@ httpd

      Parfois httpd modifie les valeurs de qualité par rapport à celles qui découleraient d'une stricte interprétation de l'algorithme de négociation - de httpd ci-dessus, ceci pour améliorer les résultats de l'algorithme pour + de httpd ci-dessus, cela afin d’améliorer les résultats de l'algorithme pour les navigateurs qui envoient des informations incomplètes ou inappropriées. Certains des navigateurs les plus populaires envoient des informations dans l'en-tête Accept qui, sans ce traitement, provoqueraient la @@ -449,13 +449,13 @@ httpd

      L'en-tête de requête Accept: indique les types de média souhaités. Il peut aussi contenir des types de média avec caractères - génériques, comme "image/*" ou "*/*" où * correspond à n'importe quelle + génériques, comme « image/* » ou « */* » où * correspond à n'importe quelle chaîne de caractères. Ainsi une requête contenant :

      Accept: image/*, */*

      indiquerait que tout type de média est acceptable, avec une préférence - pour les types commençant par "image/". + pour les types commençant par « image/ ». Certains navigateurs ajoutent par défaut des types de média avec caractères génériques aux types explicitement nommés qu'ils peuvent gérer. Par exemple :

      @@ -463,7 +463,7 @@ httpd

      Accept: text/html, text/plain, image/gif, image/jpeg, */*

      -

      Ceci indique que les types explicitement listés sont préférés, mais +

      Cela indique que les types explicitement listés sont préférés, mais qu'une représentation avec un type différent de ces derniers conviendra aussi. Les valeurs de qualités explicites, afin de préciser ce que veut vraiment le navigateur, s'utilisent @@ -474,15 +474,16 @@ httpd

      Les types explicites n'ont pas de facteur de qualité, la valeur par défaut de leur préférence est donc de 1.0 (la plus haute). Le type avec caractères génériques */* se voit attribuer une préférence basse de 0.01, - si bien que les types autres que ceux explicitement listés ne seront retournés + si bien que les types autres que ceux explicitement listés ne seront + renvoyés que s'il n'existe pas de variante correspondant à un type explicitement listé.

      -

      Si l'en-tête Accept: ne contient pas aucun +

      Si l'en-tête Accept: ne contient pas de facteur de qualité, httpd positionne la valeur de qualité de - "*/*", si present, à 0.01 pour simuler l'effet désiré. Il positionne aussi + « */* », si présent, à 0.01 pour simuler l'effet désiré. Il positionne aussi la valeur de qualité des types avec caractères génériques au format - "type/*" à 0.02 (ils sont donc préférés à ceux correspondant à "*/*"). Si + « type/* » à 0.02 (ils sont donc préférés à ceux correspondant à « */* »). Si un type de média dans l'en-tête Accept: contient un facteur de qualité, ces valeurs spéciales ne seront pas appliquées, de façon à ce que les requêtes de navigateurs qui envoient les informations @@ -497,11 +498,11 @@ langage quand la négociation ne trouve aucun langage correspondant.

      Quand un client demande une page sur votre serveur, si ce dernier ne - parvient pas à trouver une page dont la langue corresponde à l'en-tête + parvient pas à trouver une page dont la langue correspond à l'en-tête Accept-language envoyé par le navigateur, il enverra au client - une réponse "Aucune variante acceptable" ou "Plusieurs choix possibles". + une réponse « Aucune variante acceptable » ou « Plusieurs choix possibles ». Pour éviter ces - messages d'erreur, il est possible de configurer httpd de façon à ce que, + messages d'erreur, il est possible de configurer httpd de façon que, dans ces cas, il ignore l'en-tête Accept-language et fournisse tout de même un document, même s'il ne correspond pas exactement à la demande explicite du client. La directive ForceLanguagePriority @@ -514,26 +515,26 @@ langage trouvée. Par exemple, si un client demande des documents possédant le langage en-GB, c'est à dire anglais britannique, le standard HTTP/1.1 n'autorise normalement pas le serveur à faire correspondre cette - demande à un document dont le langage est simplement en. - (Notez qu'inclure en-GB et non en dans l'en-tête + demande à un document dont le langage est simplement en + (notez qu'inclure en-GB et non en dans l'en-tête Accept-Language constitue une quasi-erreur de configuration, car il est très peu probable qu'un lecteur qui comprend l'anglais britannique, ne comprenne pas l'anglais en général. Malheureusement, de - nombreux clients ont réellement des configurations par défaut de ce type.) - Cependant, si aucune autre correspondance de langage n'est possible, et que le - serveur est sur le point de retourner une erreur "Aucune variable - acceptable" ou de choisir le langage défini par la directive LanguagePriority, le serveur ignorera + nombreux clients ont réellement des configurations par défaut de ce type). + Cependant, si aucune autre correspondance de langage n'est possible, et si le + serveur est sur le point de renvoyer une erreur « Aucune variable + acceptable » ou de choisir le langage défini par la directive LanguagePriority, le serveur ignorera la spécification du sous-ensemble de langage et associera la demande en en-GB à des documents en en. Implicitement, - httpd ajoute le langage parent à la liste de langues acceptés par le + httpd ajoute le langage parent à la liste de langages acceptés par le client avec une valeur de qualité très basse. Notez cependant que si le - client demande "en-GB; q=0.9, fr; q=0.8", et le serveur dispose de - documents estampillés "en" et "fr", alors c'est le document "fr" qui sera - retourné, tout ceci dans un souci de compatibilité avec la spécification + client demande « en-GB; q=0.9, fr; q=0.8 », et si le serveur dispose de + documents estampillés « en » et « fr », c'est le document « fr » qui sera + renvoyé, tout cela dans un souci de compatibilité avec la spécification HTTP/1.1 et afin de fonctionner efficacement avec les clients correctement configurés.

      -

      Pour supporter les techniques avancées (comme les cookies ou les chemins +

      Pour prendre en charge les techniques avancées (comme les cookies ou les chemins d'URL spéciaux) afin de déterminer le langage préféré de l'utilisateur, le module mod_negotiation reconnaît la variable d'environnement @@ -591,7 +592,7 @@ conventions de nommage

      Ci-dessous d'autres exemples de noms de fichiers avec des liens - hypertextes valides et invalides :

      + hypertextes valables et non valables :

      @@ -685,10 +686,10 @@ conventions de nommage niveau du serveur, il se peut que seule la première variante demandée soit mise en cache et de ce fait, la correspondance positive du cache peut entraîner une réponse inappropriée. Pour - éviter ceci, httpd marque par - défaut toutes les réponses qui sont retournées après une négociation de - contenu comme "non-cachables" par les clients HTTP/1.0. httpd supporte - aussi les fonctionnalités du protocole HTTP/1.1 afin de permettre la mise + éviter cela, httpd marque par + défaut toutes les réponses qui sont renvoyées après une négociation de + contenu comme « non-cachables » par les clients HTTP/1.0. httpd prend + aussi en charge les fonctionnalités du protocole HTTP/1.1 afin de permettre la mise en cache des réponses négociées.

      Pour les requêtes en provenance d'un client compatible HTTP/1.0 diff --git a/docs/manual/mod/allmodules.xml.de b/docs/manual/mod/allmodules.xml.de index e81ec7b053..fc9a3aecc3 100644 --- a/docs/manual/mod/allmodules.xml.de +++ b/docs/manual/mod/allmodules.xml.de @@ -119,7 +119,6 @@ mod_substitute.xml mod_suexec.xml mod_systemd.xml - mod_tls.xml mod_unique_id.xml mod_unixd.xml mod_userdir.xml diff --git a/docs/manual/mod/allmodules.xml.es b/docs/manual/mod/allmodules.xml.es index 2f0be77bf9..db82b11cb5 100644 --- a/docs/manual/mod/allmodules.xml.es +++ b/docs/manual/mod/allmodules.xml.es @@ -119,7 +119,6 @@ mod_substitute.xml mod_suexec.xml mod_systemd.xml - mod_tls.xml mod_unique_id.xml mod_unixd.xml mod_userdir.xml diff --git a/docs/manual/mod/allmodules.xml.fr b/docs/manual/mod/allmodules.xml.fr index 950c26b7f6..71c021f0f2 100644 --- a/docs/manual/mod/allmodules.xml.fr +++ b/docs/manual/mod/allmodules.xml.fr @@ -119,7 +119,6 @@ mod_substitute.xml.fr mod_suexec.xml.fr mod_systemd.xml.fr - mod_tls.xml.fr mod_unique_id.xml.fr mod_unixd.xml.fr mod_userdir.xml.fr diff --git a/docs/manual/mod/allmodules.xml.ja b/docs/manual/mod/allmodules.xml.ja index 1925f5691c..50afa31691 100644 --- a/docs/manual/mod/allmodules.xml.ja +++ b/docs/manual/mod/allmodules.xml.ja @@ -119,7 +119,6 @@ mod_substitute.xml mod_suexec.xml.ja mod_systemd.xml - mod_tls.xml mod_unique_id.xml.ja mod_unixd.xml mod_userdir.xml.ja diff --git a/docs/manual/mod/allmodules.xml.ko b/docs/manual/mod/allmodules.xml.ko index ec69ca22fa..c811120a4b 100644 --- a/docs/manual/mod/allmodules.xml.ko +++ b/docs/manual/mod/allmodules.xml.ko @@ -119,7 +119,6 @@ mod_substitute.xml mod_suexec.xml.ko mod_systemd.xml - mod_tls.xml mod_unique_id.xml.ko mod_unixd.xml mod_userdir.xml.ko diff --git a/docs/manual/mod/allmodules.xml.tr b/docs/manual/mod/allmodules.xml.tr index cb24c701e8..d94c89f1aa 100644 --- a/docs/manual/mod/allmodules.xml.tr +++ b/docs/manual/mod/allmodules.xml.tr @@ -119,7 +119,6 @@ mod_substitute.xml mod_suexec.xml.tr mod_systemd.xml - mod_tls.xml mod_unique_id.xml mod_unixd.xml.tr mod_userdir.xml.tr diff --git a/docs/manual/mod/allmodules.xml.zh-cn b/docs/manual/mod/allmodules.xml.zh-cn index 9f45eaafed..8fdd483eaa 100644 --- a/docs/manual/mod/allmodules.xml.zh-cn +++ b/docs/manual/mod/allmodules.xml.zh-cn @@ -119,7 +119,6 @@ mod_substitute.xml mod_suexec.xml mod_systemd.xml - mod_tls.xml mod_unique_id.xml mod_unixd.xml mod_userdir.xml diff --git a/docs/manual/mod/directives.html.fr.utf8 b/docs/manual/mod/directives.html.fr.utf8 index 66686a97cc..923c5a01b7 100644 --- a/docs/manual/mod/directives.html.fr.utf8 +++ b/docs/manual/mod/directives.html.fr.utf8 @@ -741,21 +741,6 @@

    2. ThreadsPerChild
    3. ThreadStackSize
    4. TimeOut
    5. -
    6. TLSCertificate
    7. -
    8. TLSCiphersPrefer
    9. -
    10. TLSCiphersSuppress
    11. -
    12. TLSEngine
    13. -
    14. TLSHonorClientOrder
    15. -
    16. TLSOptions
    17. -
    18. TLSProtocol
    19. -
    20. TLSProxyCA
    21. -
    22. TLSProxyCiphersPrefer
    23. -
    24. TLSProxyCiphersSuppress
    25. -
    26. TLSProxyEngine
    27. -
    28. TLSProxyMachineCertificate
    29. -
    30. TLSProxyProtocol
    31. -
    32. TLSSessionCache
    33. -
    34. TLSStrictSNI
    35. TraceEnable
    36. TransferLog
    37. TypesConfig
    38. diff --git a/docs/manual/mod/index.html.fr.utf8 b/docs/manual/mod/index.html.fr.utf8 index efa5f1cd94..fa620e2f33 100644 --- a/docs/manual/mod/index.html.fr.utf8 +++ b/docs/manual/mod/index.html.fr.utf8 @@ -70,7 +70,7 @@ multi-processus multi-thread
      top

      Autres Modules

      -

       A  |  B  |  C  |  D  |  E  |  F  |  H  |  I  |  L  |  M  |  N  |  P  |  R  |  S  |  T  |  U  |  V  |  W  |  X 

      +

       A  |  B  |  C  |  D  |  E  |  F  |  H  |  I  |  L  |  M  |  N  |  P  |  R  |  S  |  U  |  V  |  W  |  X 

      mod_access_compat
      Autorisations de groupe à base de nom d'hôte (nom ou adresse IP)
      mod_actions
      Exécution des scripts CGI en fonction du @@ -286,9 +286,6 @@ corps de réponses
      mod_suexec
      Permet l'exécution des scripts CGI sous l'utilisateur et le groupe spécifiés
      mod_systemd
      Fournit un support amélioré pour l'intégration de systemd
      -
      mod_tls
      TLS v1.2 and v1.3 implemented in memory-safe Rust via - the rustls library -
      mod_unique_id
      Fournit une variable d'environnement contenant un identifiant unique pour chaque requête
      mod_unixd
      Sécurité de base (nécessaire) pour les plates-formes de la diff --git a/docs/manual/mod/quickreference.html.fr.utf8 b/docs/manual/mod/quickreference.html.fr.utf8 index ba0870f043..30e50f7433 100644 --- a/docs/manual/mod/quickreference.html.fr.utf8 +++ b/docs/manual/mod/quickreference.html.fr.utf8 @@ -1497,74 +1497,59 @@ enfant traitent les connexions clients
      - - - - - - - - - - - - - - - - - - - + + - - - - - + + + + - - - - - - - - + - - - - - - - - + - - + -
      TimeOut secondes 60 svC
      Temps pendant lequel le serveur va attendre certains évènements avant de considérer qu'une requête a échoué
      TLSCertificate cert_file [key_file]svX
      adds a certificate and key (PEM encoded) to a server/virtual host.
      TLSCiphersPrefer cipher(-list)svX
      defines ciphers that are preferred.
      TLSCiphersSuppress cipher(-list)svX
      defines ciphers that are not to be used.
      TLSEngine [address:]portsX
      defines on which address+port the module shall handle incoming connections.
      TLSHonorClientOrder on|off on svX
      determines if the order of ciphers supported by the client is honored
      TLSOptions [+|-]optionsvdhX
      enables SSL variables for requests.
      TLSProtocol version+ v1.2+ svX
      specifies the minimum version of the TLS protocol to use.
      TLSProxyCA file.pemsvpX
      sets the root certificates to validate the backend server with.
      TLSProxyCiphersPrefer cipher(-list)svpX
      defines ciphers that are preferred for a proxy connection.
      TLSProxyCiphersSuppress cipher(-list)svpX
      defines ciphers that are not to be used for a proxy connection.
      TLSProxyEngine on|offsvpX
      enables TLS for backend connections.
      TLSProxyMachineCertificate cert_file [key_file]svpX
      adds a certificate and key file (PEM encoded) to a proxy setup.
      TLSProxyProtocol version+ v1.2+ svpX
      specifies the minimum version of the TLS protocol to use in proxy connections.
      TLSSessionCache cache-specsX
      specifies the cache for TLS session resumption.
      TLSStrictSNI on|off on sX
      enforces exact matches of client server indicators (SNI) against host names.
      TraceEnable [on|off|extended] on svC
      Détermine le comportement des requêtes +
      TraceEnable [on|off|extended] on svC
      Détermine le comportement des requêtes TRACE
      TransferLog fichier|pipesvB
      Spécifie l'emplacement d'un fichier journal
      TypesConfig chemin-fichier conf/mime.types sB
      Le chemin du fichier mime.types
      UNCList hostname [hostname...]sC
      Définit quels sont les noms d’hôte UNC auxquels le serveur peut accéder +
      TransferLog fichier|pipesvB
      Spécifie l'emplacement d'un fichier journal
      TypesConfig chemin-fichier conf/mime.types sB
      Le chemin du fichier mime.types
      UNCList hostname [hostname...]sC
      Définit quels sont les noms d’hôte UNC auxquels le serveur peut accéder
      UnDefine nom-variablesC
      Invalide la définition d'une variable
      UndefMacro nomsvdB
      Supprime une macro
      UnsetEnv var-env [var-env] -...svdhB
      Supprime des variables de l'environnement
      Use nom [valeur1 ... valeurN] -svdB
      Utilisation d'une macro
      UseCanonicalName On|Off|DNS Off svdC
      Définit la manière dont le serveur détermine son propre nom +
      UnDefine nom-variablesC
      Invalide la définition d'une variable
      UndefMacro nomsvdB
      Supprime une macro
      UnsetEnv var-env [var-env] +...svdhB
      Supprime des variables de l'environnement
      Use nom [valeur1 ... valeurN] +svdB
      Utilisation d'une macro
      UseCanonicalName On|Off|DNS Off svdC
      Définit la manière dont le serveur détermine son propre nom et son port
      UseCanonicalPhysicalPort On|Off Off svdC
      Définit la manière dont le serveur +
      UseCanonicalPhysicalPort On|Off Off svdC
      Définit la manière dont le serveur détermine son propre port
      User utilisateur unix #-1 sB
      L'utilisateur sous lequel le serveur va traiter les +
      User utilisateur unix #-1 sB
      L'utilisateur sous lequel le serveur va traiter les requêtes
      UserDir nom-répertoire [nom-répertoire] ... -svB
      Chemin des répertoires propres à un +
      UserDir nom-répertoire [nom-répertoire] ... +svB
      Chemin des répertoires propres à un utilisateur
      VHostCGIMode On|Off|Secure On vX
      Détermine si le serveur virtuel peut exécuter des +
      VHostCGIMode On|Off|Secure On vX
      Détermine si le serveur virtuel peut exécuter des sous-processus, et définit les privilèges disponibles pour ces dernier.
      VHostCGIPrivs [+-]?privilege-name [[+-]?privilege-name] ...vX
      Assigne des privilèges au choix aux sous-processus créés +
      VHostCGIPrivs [+-]?privilege-name [[+-]?privilege-name] ...vX
      Assigne des privilèges au choix aux sous-processus créés par un serveur virtuel.
      VHostGroup identifiant-groupe-unixvX
      Définit l'identifiant du groupe sous lequel s'exécute un +
      VHostGroup identifiant-groupe-unixvX
      Définit l'identifiant du groupe sous lequel s'exécute un serveur virtuel.
      VHostPrivs [+-]?nom-privilège [[+-]?nom-privilège] ...vX
      Assigne des privilèges à un serveur virtuel.
      VHostSecure On|Off On vX
      Détermine si le serveur s'exécute avec une sécurité avancée +
      VHostPrivs [+-]?nom-privilège [[+-]?nom-privilège] ...vX
      Assigne des privilèges à un serveur virtuel.
      VHostSecure On|Off On vX
      Détermine si le serveur s'exécute avec une sécurité avancée pour les serveurs virtuels.
      VHostUser identifiant-utilisateur-unixvX
      Définit l'identifiant utilisateur sous lequel s'exécute un +
      VHostUser identifiant-utilisateur-unixvX
      Définit l'identifiant utilisateur sous lequel s'exécute un serveur virtuel.
      VirtualDocumentRoot répertoire-interpolé|none none svE
      Permet une configuration dynamique de la racine des +
      VirtualDocumentRoot répertoire-interpolé|none none svE
      Permet une configuration dynamique de la racine des documents d'un serveur virtuel donné
      VirtualDocumentRootIP répertoire-interpolé|none none svE
      Configuration dynamique de la racine des documents pour un +
      VirtualDocumentRootIP répertoire-interpolé|none none svE
      Configuration dynamique de la racine des documents pour un serveur virtuel donné
      <VirtualHost +
      <VirtualHost adresse IP[:port] [adresse IP[:port]] ...> ... - </VirtualHost>sC
      Contient des directives qui ne s'appliquent qu'à un nom + </VirtualHost>sC
      Contient des directives qui ne s'appliquent qu'à un nom d'hôte spécifique ou à une adresse IP
      VirtualScriptAlias répertoire-interpolé|none none svE
      Configuration dynamique du répertoire des scripts CGI pour +
      VirtualScriptAlias répertoire-interpolé|none none svE
      Configuration dynamique du répertoire des scripts CGI pour un serveur virtuel donné
      VirtualScriptAliasIP répertoire-interpolé|none none svE
      Configuration dynamique du répertoire des scripts CGI pour +
      VirtualScriptAliasIP répertoire-interpolé|none none svE
      Configuration dynamique du répertoire des scripts CGI pour un serveur virtuel donné
      WatchdogInterval time-interval[s] 1 sB
      Intervalle Watchdog en secondes
      XBitHack on|off|full off svdhB
      Interprète les directives SSI dans les fichiers dont le bit +
      WatchdogInterval time-interval[s] 1 sB
      Intervalle Watchdog en secondes
      XBitHack on|off|full off svdhB
      Interprète les directives SSI dans les fichiers dont le bit d'exécution est positionné
      xml2EncAlias jeu-de-caractères alias [alias ...]sB
      Définit des alias pour les valeurs d'encodage
      xml2EncDefault nomsvdhB
      Définit un encodage par défaut à utiliser lorsqu'aucune +
      xml2EncAlias jeu-de-caractères alias [alias ...]sB
      Définit des alias pour les valeurs d'encodage
      xml2EncDefault nomsvdhB
      Définit un encodage par défaut à utiliser lorsqu'aucune information ne peut être automatiquement détectée
      xml2StartParse élément [élément ...]svdhB
      Indique à l'interpréteur à partir de quelle balise il doit +
      xml2StartParse élément [élément ...]svdhB
      Indique à l'interpréteur à partir de quelle balise il doit commencer son traitement.
      diff --git a/docs/manual/sitemap.html.fr.utf8 b/docs/manual/sitemap.html.fr.utf8 index f7cbd2f698..7c67c748a6 100644 --- a/docs/manual/sitemap.html.fr.utf8 +++ b/docs/manual/sitemap.html.fr.utf8 @@ -323,7 +323,6 @@ pour décrire les directives Apache
    39. Module Apache mod_substitute
    40. Module Apache mod_suexec
    41. Module Apache mod_systemd
    42. -
    43. Module Apache mod_tls
    44. Module Apache mod_unique_id
    45. Module Apache mod_unixd
    46. Module Apache mod_userdir
    47. From 0b277bc6c279057ffe0615158fb62c23403d6bed Mon Sep 17 00:00:00 2001 From: Lucien Gentis Date: Tue, 24 Sep 2024 11:00:56 +0000 Subject: [PATCH 062/176] fr doc xml file reviewed and corrected. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1920874 13f79535-47bb-0310-9956-ffa450edef68 --- docs/manual/dso.xml.fr | 330 ++++++++++++++++++++--------------------- 1 file changed, 165 insertions(+), 165 deletions(-) diff --git a/docs/manual/dso.xml.fr b/docs/manual/dso.xml.fr index 803f818454..a9e988a46f 100644 --- a/docs/manual/dso.xml.fr +++ b/docs/manual/dso.xml.fr @@ -24,28 +24,28 @@ - Support des objets dynamiques partagés (DSO) + Prise en charge des objets dynamiques partagés (DSO) -

      La conception modulaire du serveur HTTP Apache permet à l'administrateur - de choisir les fonctionnalités à inclure dans le serveur en sélectionnant - un certain nombre de modules. Les modules seront compilés en tant - qu'Objets Dynamiques Partagés (Dynamic Shared Objects ou DSOs) - qui mènent une existence séparée du fichier binaire principal - httpd. Les modules DSO peuvent être compilés en - même temps que le serveur, ou compilés et ajoutés ultérieurement via - l'Outil des Extensions à Apache (Apache Extension Tool ou +

      La conception modulaire du serveur HTTP Apache permet à l'administrateur + de choisir les fonctionnalités à inclure dans le serveur en sélectionnant + un certain nombre de modules. Les modules seront compilés en tant + qu'Objets Dynamiques Partagés (Dynamic Shared Objects ou DSOs) + qui mènent une existence séparée du fichier binaire principal + httpd. Les modules DSO peuvent être compilés en + même temps que le serveur, ou compilés et ajoutés ultérieurement via + l'Outil des Extensions à Apache (Apache Extension Tool ou apxs).

      -

      Les modules peuvent aussi être intégrés statiquement dans le +

      Les modules peuvent aussi être intégrés statiquement dans le binaire httpd lors de la compilation de ce dernier.

      -

      Ce document décrit l'utilisation des modules DSO ainsi que les dessous +

      Ce document décrit l'utilisation des modules DSO ainsi que les dessous de leur fonctionnement.

      -
      Implémentation +
      Implémentation @@ -56,45 +56,45 @@ -

      Le support DSO pour le chargement de modules individuels d'Apache +

      La prise en charge de DSO pour le chargement de modules individuels d'Apache httpd est - assuré par un module nommé mod_so qui doit être compilé + assuré par un module nommé mod_so qui doit être compilé statiquement dans le coeur d'Apache httpd. Il s'agit du seul module avec le - module core à ne pas pouvoir être compilé en tant que - module DSO lui-même. Pratiquement tous les autres modules d'Apache httpd - distribués seront alors compilés en tant que modules DSO. Une fois - compilé en tant que module DSO nommé mod_foo.so, un - module peut être chargé en mémoire au - démarrage ou redémarrage du serveur à l'aide de + module core à ne pas pouvoir être compilé en tant que + module DSO lui-même. Pratiquement tous les autres modules d'Apache httpd + distribués seront alors compilés en tant que modules DSO. Une fois + compilé en tant que module DSO nommé mod_foo.so, un + module peut être chargé en mémoire au + démarrage ou redémarrage du serveur à l'aide de la directive LoadModule du module - mod_so, placée + mod_so placée dans votre fichier httpd.conf.

      -

      La compilation en mode DSO peut être désactivée pour certains +

      La compilation en mode DSO peut être désactivée pour certains modules via l'option --enable-mods-static du script - configure, comme expliqué dans la configure, comme expliqué dans la Documentation sur l'installation.

      -

      Un utilitaire permet de simplifier la création de +

      Un utilitaire permet de simplifier la création de fichiers DSO pour les modules d'Apache httpd - (particulièrement pour les modules tiers) ; il s'agit du programme nommé + (particulièrement pour les modules tiers) ; il s'agit du programme nommé apxs (APache eXtenSion). On peut l'utiliser pour construire des modules de type - DSO en dehors de l'arborescence des sources d'Apache httpd. L'idée est - simple : à l'installation du serveur HTTP Apache, la procédure make install - du script configure installe les fichiers d'en-têtes + DSO en dehors de l'arborescence des sources d'Apache httpd. L'idée est + simple : à l'installation du serveur HTTP Apache, la procédure make install + du script configure installe les fichiers d'en-têtes d'Apache httpd et positionne, pour la plateforme de compilation, les drapeaux du compilateur et de - l'éditeur de liens à l'intérieur du programme - apxs, qui sera utilisé pour la construction de fichiers DSO. + l'éditeur de liens à l'intérieur du programme + apxs qui sera utilisé pour la construction de fichiers DSO. Il est ainsi possible d'utiliser le programme apxs pour compiler ses sources de modules Apache httpd sans avoir besoin de - l'arborescence des sources de la distribution d'Apache, et sans avoir à - régler les drapeaux du compilateur et de l'éditeur de liens pour le support DSO.

      + l'arborescence des sources de la distribution d'Apache, et sans avoir à + régler les drapeaux du compilateur et de l'éditeur de liens pour la prise en charge de DSO.

      Mode d'emploi succinct -

      Afin que vous puissiez vous faire une idée des fonctionnalités DSO - du serveur HTTP Apache 2.x, en voici un résumé court et concis :

      +

      Afin que vous puissiez vous faire une idée des fonctionnalités DSO + du serveur HTTP Apache 2.x, en voici un résumé court et concis :

      1. @@ -109,10 +109,10 @@ $ make install
      2. -

        Configure le serveur HTTP Apache avec tous les modules - activés. Seul un jeu de modules de base sera chargé au - démarrage du serveur. Vous pouvez modifier ce jeu de modules - chargés au démarrage en activant ou désactivant les directives Configurer le serveur HTTP Apache avec tous les modules + activés. Seul un jeu de modules de base sera chargé au + démarrage du serveur. Vous pouvez modifier ce jeu de modules + chargés au démarrage en activant ou désactivant les directives LoadModule correspondantes dans le fichier httpd.conf.

        @@ -123,18 +123,18 @@ $ make install

        L'argument most de l'option --enable-modules indique que tous les modules - non-expérimentaux ou qui ne sont pas là à titre d'exemple seront - compilés.

        + non-expérimentaux ou qui ne sont pas là à titre d'exemple seront + compilés.

      3. -

        Certains modules ne sont utilisés que par les développeurs et - ne seront pas compilés. Si vous voulez les utiliser, spécifiez +

        Certains modules ne sont utilisés que par les développeurs et + ne seront pas compilés. Si vous voulez les utiliser, spécifiez l'option all. Pour compiler tous les modules disponibles, - y compris les modules de développeurs, spécifiez l'option + y compris les modules de développeurs, spécifiez l'option reallyall. En outre, la directive LoadModule peut être activée pour tous - les modules compilés via l'option du script configure + module="mod_so">LoadModule peut être activée pour tous + les modules compilés via l'option du script configure --enable-load-all-modules.

        @@ -147,7 +147,7 @@ $ make install Construire et installer un module Apache httpd tiers, par exemple mod_foo.c, en tant que module DSO mod_foo.so en dehors de l'arborescence des sources - d'Apache httpd à l'aide du programme apxs : + d'Apache httpd à l'aide du programme apxs : $ cd /chemin/vers/module_tiers
        @@ -156,172 +156,172 @@ $ apxs -cia mod_foo.c
      -

      Dans tous les cas, une fois le module partagé compilé, vous devez +

      Dans tous les cas, une fois le module partagé compilé, vous devez ajouter une directive LoadModule dans le fichier httpd.conf pour qu'Apache httpd active le module.

      Voir la documentation sur apxs - pour plus de détails.

      + pour plus de détails.

      Les dessous du fonctionnement des DSO -

      Les clônes modernes d'UNIX proposent un mécanisme - appelé édition de liens et chargement dynamiques d' - Objets Dynamiques Partagés (DSO), qui permet de construire un - morceau de programme dans un format spécial pour le rendre chargeable - à l'exécution dans l'espace d'adressage d'un programme exécutable.

      - -

      Ce chargement peut s'effectuer de deux manières : automatiquement par - un programme système appelé ld.so quand un programme - exécutable est démarré, ou manuellement à partir du programme en cours - d'exécution via sa propre interface système vers le chargeur Unix à l'aide - des appels système dlopen()/dlsym().

      - -

      Dans la première méthode, les DSO sont en général appelés - bibliothèques partagées ou encore bibliothèques DSO, et - possèdent des noms du style - libfoo.so ou libfoo.so.1.2. Ils résident dans un - répertoire système (en général /usr/lib) - et le lien avec le programme exécutable est établi à la compilation en - ajoutant -lfoo à la commande de l'éditeur de liens. Les - références à la bibliothèque sont ainsi codées en dur dans le fichier du - programme exécutable de façon à ce qu'au démarrage du programme, le +

      Les clones modernes d'UNIX proposent un mécanisme + appelé édition de liens et chargement dynamiques d' + Objets Dynamiques Partagés (DSO), qui permet de construire un + morceau de programme dans un format spécial pour le rendre chargeable + à l'exécution dans l'espace d'adressage d'un programme exécutable.

      + +

      Ce chargement peut s'effectuer de deux manières : automatiquement par + un programme système appelé ld.so quand un programme + exécutable est démarré, ou manuellement à partir du programme en cours + d'exécution à l’aide de sa propre interface système vers le chargeur Unix à l'aide + des appels système dlopen()/dlsym().

      + +

      Dans la première méthode, les DSO sont en général appelés + bibliothèques partagées ou encore bibliothèques DSO, et + possèdent des noms du style + libfoo.so ou libfoo.so.1.2. Ils résident dans un + répertoire système (en général /usr/lib) + et le lien avec le programme exécutable est établi à la compilation en + ajoutant -lfoo à la commande de l'éditeur de liens. Les + références à la bibliothèque sont ainsi codées en dur dans le fichier du + programme exécutable de façon qu'au démarrage du programme, le chargeur Unix soit capable de localiser libfoo.so dans - /usr/lib, dans des chemins codés en dur à l'aide d'options de - l'éditeur de liens comme -R ou dans des chemins définis par la + /usr/lib, dans des chemins codés en dur à l'aide d'options de + l'éditeur de liens comme -R ou dans des chemins définis par la variable d'environnement - LD_LIBRARY_PATH. Le chargeur peut dès lors résoudre tous les symboles - (jusque là non encore résolus) du DSO dans le programme exécutable.

      - -

      Les symboles du programme exécutable ne sont en général pas - référencés par le DSO (car c'est une bibliothèque de code à usage général - et réutilisable), - et ainsi aucune résolution supplémentaire n'est nécessaire. De son côté, - le programme exécutable ne doit accomplir aucune action particulière + LD_LIBRARY_PATH. Le chargeur peut dès lors résoudre tous les symboles + (jusque là non encore résolus) du DSO dans le programme exécutable.

      + +

      Les symboles du programme exécutable ne sont en général pas + référencés par le DSO (car c'est une bibliothèque de code à usage général + et réutilisable), + et ainsi aucune résolution supplémentaire n'est nécessaire. De son côté, + le programme exécutable ne doit accomplir aucune action particulière pour utiliser les - symboles du DSO car toutes les résolutions sont effectuées par le chargeur + symboles du DSO car toutes les résolutions sont effectuées par le chargeur Unix. En fait, le code permettant d'invoquer - ld.so fait partie du code de démarrage pour l'exécution qui - est lié dans tout programme exécutable non statiquement lié. - L'avantage du chargement dynamique du code d'une bibliothèque partagée est - évident : le code de la bibliothèque ne doit être stocké qu'une seule fois - dans une bibliothèque système telle que libc.so, ce qui permet - d'économiser de l'espace disque pour les autres programmes.

      - -

      Dans la seconde méthode, les DSO sont en général appelés objets - partagés ou fichiers DSO, et peuvent être nommés avec - l'extension de son choix (bien que le nom conseillé soit du style - foo.so). Ces fichiers résident en général dans un répertoire - spécifique à un programme, et aucun lien n'est automatiquement établi avec - le programme exécutable dans lequel ils sont utilisés. - Le programme exécutable charge manuellement le DSO à l'exécution dans son - espace d'adressage à l'aide de l'appel système dlopen(). - A ce moment, aucune résolution de symboles du DSO n'est effectuée pour le - programme exécutable. Par contre le chargeur Unix - résoud automatiquement tout symbole du DSO (non encore résolu) - faisant partie de l'ensemble de symboles exporté par le programme - exécutable et ses bibliothèques DSO déjà chargées (et en particulier tous - les symboles de la bibliothèque à tout faire libc.so). - De cette façon, le DSO prend connaissance de l'ensemble de symboles du - programme exécutable comme s'il avait été lié statiquement avec lui + ld.so fait partie du code de démarrage pour l'exécution qui + est lié dans tout programme exécutable non statiquement lié. + L'avantage du chargement dynamique du code d'une bibliothèque partagée est + évident : le code de la bibliothèque ne doit être stocké qu'une seule fois + dans une bibliothèque système telle que libc.so, ce qui permet + d'économiser de l'espace disque pour les autres programmes.

      + +

      Dans la seconde méthode, les DSO sont en général appelés objets + partagés ou fichiers DSO, et peuvent être nommés avec + l'extension de son choix (bien que le nom conseillé soit du style + foo.so). Ces fichiers résident en général dans un répertoire + spécifique à un programme, et aucun lien n'est automatiquement établi avec + le programme exécutable dans lequel ils sont utilisés. + Le programme exécutable charge manuellement le DSO à l'exécution dans son + espace d'adressage à l'aide de l'appel système dlopen(). + A ce moment, aucune résolution de symboles du DSO n'est effectuée pour le + programme exécutable. Par contre le chargeur Unix + résoud automatiquement tout symbole du DSO (non encore résolu) + faisant partie de l'ensemble de symboles exporté par le programme + exécutable et ses bibliothèques DSO déjà chargées (et en particulier tous + les symboles de la bibliothèque à tout faire libc.so). + De cette façon, le DSO prend connaissance de l'ensemble de symboles du + programme exécutable comme s'il avait été lié statiquement avec lui auparavant.

      -

      Finalement, pour tirer profit de l'API des DSO, le programme exécutable - doit résoudre certains symboles du DSO à l'aide de l'appel système - dlsym() pour une utilisation ultérieure dans les tables de - distribution, etc... En d'autres termes, le programme exécutable doit - résoudre manuellement tous les symboles dont il a besoin pour pouvoir les +

      Finalement, pour tirer profit de l'API des DSO, le programme exécutable + doit résoudre certains symboles du DSO à l'aide de l'appel système + dlsym() pour une utilisation ultérieure dans les tables de + distribution, etc. En d'autres termes, le programme exécutable doit + résoudre manuellement tous les symboles dont il a besoin pour pouvoir les utiliser. - Avantage d'un tel mécanisme : les modules optionnels du programme n'ont pas - besoin d'être chargés (et ne gaspillent donc pas de ressources mémoire) - tant qu'il ne sont pas nécessaires au programme en question. Si nécessaire, - ces modules peuvent être chargés dynamiquement afin d'étendre les - fonctionnalités de base du programme.

      - -

      Bien que ce mécanisme DSO paraisse évident, il comporte au moins une - étape difficile : la résolution des symboles depuis le programme exécutable - pour le DSO lorsqu'on utilise un DSO pour étendre les fonctionnalités d'un - programme (la seconde méthode). Pourquoi ? Parce que la "résolution - inverse" des symboles DSO à partir du jeu de symboles du programme - exécutable dépend de la conception de la bibliothèque (la bibliothèque n'a - aucune information sur le programme qui l'utilise) et n'est ni standardisée + Avantage d'un tel mécanisme : les modules optionnels du programme n'ont pas + besoin d'être chargés (et ne gaspillent donc pas de ressources mémoire) + tant qu'il ne sont pas nécessaires au programme en question. Si nécessaire, + ces modules peuvent être chargés dynamiquement afin d'étendre les + fonctionnalités de base du programme.

      + +

      Bien que ce mécanisme DSO paraisse évident, il comporte au moins une + étape difficile : la résolution des symboles depuis le programme exécutable + pour le DSO lorsqu'on utilise un DSO pour étendre les fonctionnalités d'un + programme (la seconde méthode). Pourquoi ? Parce que la « résolution + inverse » des symboles DSO à partir du jeu de symboles du programme + exécutable dépend de la conception de la bibliothèque (la bibliothèque n'a + aucune information sur le programme qui l'utilise) et n'est ni standardisée ni disponible sur toutes les plateformes. En pratique, les symboles globaux - du programme exécutable ne sont en général pas réexportés et donc - indisponibles pour l'utilisation dans un DSO. Trouver une méthode pour - forcer l'éditeur de liens à exporter tous les symboles globaux est le - principal problème que l'on doit résoudre lorsqu'on utilise un DSO pour - étendre les fonctionnalités d'un programme au moment de son exécution.

      - -

      L'approche des bibliothèques partagées est la plus courante, parce que - c'est dans cette optique que le mécanisme DSO a été conçu ; c'est cette + du programme exécutable ne sont en général pas réexportés et donc + indisponibles pour l'utilisation dans un DSO. Trouver une méthode pour + forcer l'éditeur de liens à exporter tous les symboles globaux est le + principal problème que l'on doit résoudre lorsqu'on utilise un DSO pour + étendre les fonctionnalités d'un programme au moment de son exécution.

      + +

      L'approche des bibliothèques partagées est la plus courante, parce que + c'est dans cette optique que le mécanisme DSO a été conçu ; c'est cette approche qui est ainsi - utilisée par pratiquement tous les types de bibliothèques que fournit le - système d'exploitation.

      + utilisée par pratiquement tous les types de bibliothèques que fournit le + système d'exploitation.

      -
      Avantages et inconvénients +
      Avantages et inconvénients -

      Les fonctionnalités ci-dessus basées sur les DSO présentent les +

      Les fonctionnalités ci-dessus basées sur les DSO présentent les avantages suivants :

        -
      • Le paquetage du serveur est plus flexible à l'exécution car le - processus serveur peut être assemblé à l'exécution via la +
      • Le paquetage du serveur est plus flexible à l'exécution car le + processus serveur peut être assemblé à l'exécution via la directive LoadModule du fichier de - configuration httpd.conf plutôt que par des options du script - configure à la compilation. Par exemple, - on peut ainsi exécuter différentes instances du serveur + configuration httpd.conf plutôt que par des options du script + configure à la compilation. Par exemple, + on peut ainsi exécuter différentes instances du serveur (standard et version SSL, version minimale et version dynamique - [mod_perl, mod_php], etc...) à partir d'une seule installation + [mod_perl, mod_php], etc.) à partir d'une seule installation d'Apache httpd.
      • -
      • Le paquetage du serveur peut être facilement étendu avec des modules - tiers, même après l'installation. Ceci présente un gros - avantage pour les mainteneurs de paquetages destinés aux distributions, - car ils peuvent créer un paquetage Apache httpd de base, et des paquetages +
      • Le paquetage du serveur peut être facilement étendu avec des modules + tiers, même après l'installation. Ceci présente un gros + avantage pour les mainteneurs de paquetages destinés aux distributions, + car ils peuvent créer un paquetage Apache httpd de base, et des paquetages additionnels contenant des extensions telles que PHP, mod_perl, mod_fastcgi, - etc...
      • + etc. -
      • Une facilité de prototypage des modules Apache httpd, car la paire +
      • Une facilité de prototypage des modules Apache httpd, car la paire DSO/apxs vous permet d'une part de travailler en dehors de l'arborescence des sources d'Apache httpd, et d'autre part de n'avoir besoin que de la commande apxs -i suivie d'un apachectl restart pour introduire une nouvelle - version de votre module fraîchement développé dans le serveur HTTP Apache - en cours d'exécution.
      • + version de votre module fraîchement développé dans le serveur HTTP Apache + en cours d'exécution.
      -

      Inconvénients des DSO :

      +

      Inconvénients des DSO :

        -
      • Le serveur est environ 20 % plus lent au démarrage - à cause des résolutions de symboles supplémentaires que le chargeur +
      • Le serveur est environ 20 % plus lent au démarrage + à cause des résolutions de symboles supplémentaires que le chargeur Unix doit effectuer.
      • -
      • Le serveur est environ 5 % plus lent à l'exécution - sur certaines plates-formes, car le code indépendant de la position (PIC) - nécessite parfois des manipulations compliquées en assembleur pour +
      • Le serveur est environ 5 % plus lent à l'exécution + sur certaines plates-formes, car le code indépendant de la position (PIC) + nécessite parfois des manipulations compliquées en assembleur pour l'adressage relatif qui ne sont pas toujours aussi rapides que celles que permet l'adressage absolu.
      • -
      • Comme les modules DSO ne peuvent pas être liés avec d'autres - bibliothèques basées sur DSO (ld -lfoo) sur toutes les +
      • Comme les modules DSO ne peuvent pas être liés avec d'autres + bibliothèques basées sur DSO (ld -lfoo) sur toutes les plates-formes - (par exemple, les plates-formes basées sur a.out ne fournissent en - général pas cette fonctionnalité alors que les plates-formes basées sur - ELF le font), vous ne pouvez pas utiliser le mécanisme DSO pour tous les - types de modules. Ou en d'autres termes, les modules compilés comme + (par exemple, les plates-formes basées sur a.out ne fournissent en + général pas cette fonctionnalité alors que les plates-formes basées sur + ELF le font), vous ne pouvez pas utiliser le mécanisme DSO pour tous les + types de modules. Ou en d'autres termes, les modules compilés comme fichiers DSO sont contraints de n'utiliser que les symboles du coeur - d'Apache httpd, de la bibliothèque C - (libc) et toutes autres bibliothèques statiques ou - dynamiques utilisées par le coeur d'Apache httpd, ou d'archives statiques - (libfoo.a) contenant du code indépendant de la + d'Apache httpd, de la bibliothèque C + (libc) et toutes autres bibliothèques statiques ou + dynamiques utilisées par le coeur d'Apache httpd, ou d'archives statiques + (libfoo.a) contenant du code indépendant de la position (PIC). Il y a deux solutions pour utiliser un autre type de code : soit le - coeur d'Apache httpd contient déjà lui-même une référence au code, soit vous - chargez le code vous-même via dlopen().
      • + coeur d'Apache httpd contient déjà lui-même une référence au code, soit vous + chargez le code vous-même à l’aide de dlopen().
      From 8b62ddb204b9941323c83b624d9039a1f2d14a0c Mon Sep 17 00:00:00 2001 From: Lucien Gentis Date: Wed, 25 Sep 2024 12:52:39 +0000 Subject: [PATCH 063/176] fr doc xml file reviewed and corrected. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1920910 13f79535-47bb-0310-9956-ffa450edef68 --- docs/manual/env.xml.fr | 62 +++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/docs/manual/env.xml.fr b/docs/manual/env.xml.fr index 7e037875d2..d4272ca8e4 100644 --- a/docs/manual/env.xml.fr +++ b/docs/manual/env.xml.fr @@ -24,7 +24,7 @@ - Apache et les variables d'environnement + Apache httpd et les variables d'environnement

      Deux types de variables d'environnement affectent le serveur @@ -34,7 +34,7 @@ contrôlées par le système d'exploitation sous-jacent et définies avant le démarrage du serveur. Leurs valeurs peuvent être utilisées directement dans les fichiers de configuration, et peuvent - éventuellement être transmises aux scripts CGI et SSI via la + éventuellement être transmises aux scripts CGI et SSI à l’aide de la directive PassEnv.

      Le second type correspond aux variables nommées appelées aussi @@ -50,7 +50,7 @@ d'environnement, il ne faut pas les confondre avec les variables d'environnement contrôlées par le système d'exploitation sous-jacent. En fait, ces variables sont stockées et manipulées dans une structure - interne à Apache. Elles ne deviennent de véritables variables + interne à Apache httpd. Elles ne deviennent de véritables variables d'environnement du système d'exploitation que lorsqu'elles sont mises à la disposition de scripts CGI et de scripts inclus côté serveur (SSI). Si vous souhaitez manipuler l'environnement du système d'exploitation sous lequel @@ -85,7 +85,7 @@ Manipulations de base de l'environnement

      La méthode la plus élémentaire pour définir une variable - d'environnement au niveau d'Apache consiste à utiliser la directive + d'environnement au niveau d'Apache httpd consiste à utiliser la directive inconditionnelle SetEnv. Les variables peuvent aussi être transmises depuis l'environnement du shell à partir duquel le serveur a été démarré en @@ -114,7 +114,7 @@

      Finalement, le module mod_unique_id définit la variable d'environnement UNIQUE_ID pour chaque requête à une valeur - qui est garantie unique parmi "toutes" les requêtes sous des + qui est garantie unique parmi « toutes » les requêtes sous des conditions très spécifiques.

      @@ -122,7 +122,7 @@ Variables CGI standards

      En plus de l'ensemble des variables d'environnement internes à la - configuration d'Apache et de celles transmises depuis le shell, + configuration d'Apache httpd et de celles transmises depuis le shell, les scripts CGI et les pages SSI se voient affectés un ensemble de variables d'environnement contenant des méta-informations à propos de la requête @@ -145,17 +145,17 @@ suexec.c.

    48. Pour des raisons de portabilité, les noms des variables - d'environnement ne peuvent contenir que des lettres, des chiffres, et - le caractère "sousligné". En outre, le premier caractère ne doit pas + d'environnement ne peuvent contenir que des lettres, des chiffres et + le caractère « souligné ». En outre, le premier caractère ne doit pas être un chiffre. Les caractères qui ne satisfont pas à ces conditions - seront remplacés par un caractère "sousligné" quand ils seront + seront remplacés par un caractère « souligné » quand ils seront transmis aux scripts CGI et aux pages SSI.
    49. Les contenus d'en-têtes HTTP transmis aux scripts de type - CGI ou autre via des variables d'environnement constituent un + CGI ou autre à l’aide de variables d'environnement constituent un cas particulier (voir plus loin). Leur nom est converti en majuscules et seuls les tirets sont remplacés par des - caractères '_' ("souligné") ; si le format du nom de l'en-tête + caractères '_' (« souligné ») ; si le format du nom de l'en-tête n'est pas valide, celui-ci est ignoré. Voir plus loin pour une solution de contournement du problème.
    50. @@ -172,7 +172,7 @@ ref="subrequest">sous-requête interne (par exemple la recherche d'un DirectoryIndex), ou lorsqu'il génère un - listing du contenu d'un répertoire via le module + listing du contenu d'un répertoire à l’aide du module mod_autoindex, la sous-requête n'hérite pas des variables d'environnement spécifiques à la requête. En outre, à cause des phases de l'API auxquelles mod_setenvif prend @@ -215,7 +215,7 @@ principales utilisations des variables d'environnement. Comme indiqué plus haut, l'environnement transmis aux scripts CGI comprend des méta-informations standards à propos de la requête, en plus des - variables définies dans la configuration d'Apache. Pour plus de + variables définies dans la configuration d'Apache httpd. Pour plus de détails, se référer au tutoriel CGI.

      @@ -230,7 +230,7 @@ et peuvent utiliser des variables d'environnement dans les éléments de contrôle de flux pour rendre certaines parties d'une page conditionnelles en fonction des caractéristiques de la requête. - Apache fournit aussi les variables d'environnement CGI standards + Apache httpd fournit aussi les variables d'environnement CGI standards aux pages SSI comme indiqué plus haut. Pour plus de détails, se référer au tutoriel SSI.

      @@ -243,7 +243,7 @@ variables d'environnement à l'aide des directives Require env et Require not env. En association avec la directive - SetEnvIf, ceci confère une + SetEnvIf, cela confère une grande souplesse au contrôle d'accès au serveur en fonction des caractéristiques du client. Par exemple, vous pouvez utiliser ces directives pour interdire l'accès depuis un navigateur particulier @@ -262,7 +262,7 @@ forme conditionnelle de la directive CustomLog. En association avec la directive SetEnvIf, ceci confère une grande souplesse au contrôle + >SetEnvIf, cela confère une grande souplesse au contrôle du traçage des requêtes. Par exemple, vous pouvez choisir de ne pas tracer les requêtes pour des noms de fichiers se terminant par gif, ou encore de ne tracer que les requêtes des clients @@ -275,7 +275,7 @@

      La directive Header peut se baser sur la présence ou l'absence d'une variable d'environnement pour décider si un certain en-tête HTTP sera placé - dans la réponse au client. Ceci permet, par exemple, de n'envoyer un + dans la réponse au client. Cela permet, par exemple, de n'envoyer un certain en-tête de réponse que si un en-tête correspondant est présent dans la requête du client.

      @@ -314,7 +314,7 @@ Variables d'environnement à usage spécial

      Des problèmes d'interopérabilité ont conduit à l'introduction de - mécanismes permettant de modifier le comportement d'Apache lorsqu'il + mécanismes permettant de modifier le comportement d'Apache httpd lorsqu'il dialogue avec certains clients. Afin de rendre ces mécanismes aussi souples que possible, ils sont invoqués en définissant des variables d'environnement, en général à l'aide de la directive @@ -326,7 +326,7 @@

      downgrade-1.0 -

      Ceci force le traitement d'une requête comme une requête HTTP/1.0 +

      Cela force le traitement d'une requête comme une requête HTTP/1.0 même si elle a été rédigée dans un langage plus récent.

      @@ -362,13 +362,13 @@
      gzip-only-text/html -

      Positionnée à "1", cette variable désactive le filtre en sortie +

      Positionnée à « 1 », cette variable désactive le filtre en sortie DEFLATE fourni par le module mod_deflate pour les types de contenu autres que text/html. Si vous préférez utiliser des fichiers compressés statiquement, mod_negotiation évalue aussi la variable (non seulement pour gzip, mais aussi pour tous les encodages autres que - "identity").

      + « identity »).

      no-gzip @@ -381,13 +381,13 @@
      no-cache -

      Disponible dans les versions 2.2.12 et ultérieures d'Apache

      +

      Disponible dans les versions 2.2.12 et ultérieures d'Apache httpd

      Lorsque cette variable est définie, mod_cache ne sauvegardera pas de réponse susceptible d'être mise en cache. Cette variable d'environnement n'a aucune incidence sur le fait qu'une réponse déjà enregistrée - dans la cache soit utilisée ou non pour la requête courante.

      + dans le cache soit utilisée ou non pour la requête courante.

      @@ -428,17 +428,17 @@

      Disponible dans les versions postérieures à 2.0.54

      -

      Quand Apache génère une redirection en réponse à une requête client, +

      Quand Apache httpd génère une redirection en réponse à une requête client, la réponse inclut un texte destiné à être affiché au cas où le client ne suivrait pas, ou ne pourrait pas suivre automatiquement la redirection. - Habituellement, Apache marque ce texte en accord avec le jeu de caractères + Habituellement, Apache httpd marque ce texte en accord avec le jeu de caractères qu'il utilise, à savoir ISO-8859-1.

      Cependant, si la redirection fait référence à une page qui utilise un jeu de caractères différent, certaines versions de navigateurs obsolètes essaieront d'utiliser le jeu de caractères du texte de la redirection plutôt que celui de la page réelle. - Ceci peut entraîner, par exemple, un rendu incorrect du Grec.

      -

      Si cette variable d'environnement est définie, Apache omettra le jeu de + Cela peut entraîner, par exemple, un rendu incorrect du Grec.

      +

      Si cette variable d'environnement est définie, Apache httpd omettra le jeu de caractères pour le texte de la redirection, et les navigateurs obsolètes précités utiliseront correctement celui de la page de destination.

      @@ -483,17 +483,17 @@ Transmission du contenu d'en-têtes non valides aux scripts CGI -

      Avec la version 2.4, Apache est plus strict avec la conversion +

      Avec la version 2.4, Apache httpd est plus strict avec la conversion des en-têtes HTTP en variables d'environnement dans mod_cgi et d'autres modules : dans les versions - précédentes, tout caractère invalide dans les noms d'en-têtes + précédentes, tout caractère non valable dans les noms d'en-têtes était tout simplement remplacé par un caractère '_', ce qui pouvait exposer à des attaques de type cross-site-scripting via injection d'en-têtes (voir Bogues du Web inhabituelles, planche 19/20).

      -

      Si vous devez supporter un client qui envoie des en-têtes non +

      Si vous devez prendre en charge un client qui envoie des en-têtes non conformes et si ceux-ci ne peuvent pas être corrigés, il existe une solution de contournement simple mettant en jeu les modules mod_setenvif et mod_headers, @@ -557,7 +557,7 @@ CustomLog "logs/access_log" common env=!image-request

      - Prévention du "Vol d'image" + Prévention du « Vol d'image »

      Cet exemple montre comment empêcher les utilisateurs ne faisant pas partie de votre serveur d'utiliser des images de votre serveur comme From 911ff158d5c0dc4869cb6bd78999f7ef83100a23 Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Thu, 26 Sep 2024 15:39:54 +0000 Subject: [PATCH 064/176] vote, summarize must-haves [skip ci] git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1920959 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/STATUS b/STATUS index 7e4449c693..2518e17b11 100644 --- a/STATUS +++ b/STATUS @@ -153,9 +153,9 @@ CURRENT RELEASE NOTES: RELEASE SHOWSTOPPERS: -- PR69235 -- PR69260 -- PR69203 +- PR69235 (UDS+rewrite?) +- PR69260 (dup of above) +- PR69203 (FPM) PATCHES ACCEPTED TO BACKPORT FROM TRUNK: @@ -259,7 +259,7 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: Backport version for 2.4.x of patch: Trunk version of patch works svn merge -c 1920566 ^/httpd/httpd/trunk . - +1: rpluem, + +1: rpluem, covener PATCHES/ISSUES THAT ARE BEING WORKED [ New entries should be added at the START of the list ] From 9b557ddb9e9dd37ff40e2d80936ff75fc37b844f Mon Sep 17 00:00:00 2001 From: Joe Orton Date: Thu, 26 Sep 2024 16:00:21 +0000 Subject: [PATCH 065/176] Vote x3, propose x1, note: CMake changes should be CTR. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1920961 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 63 ++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/STATUS b/STATUS index 2518e17b11..3117ec11e5 100644 --- a/STATUS +++ b/STATUS @@ -183,6 +183,35 @@ PATCHES ACCEPTED TO BACKPORT FROM TRUNK: +1 covener, rpluem, steffenal + *) mod_rewrite: don't merge leading slashes when they come from a perdir prefix + (rather than the substitution) + Trunk version of patch: + https://svn.apache.org/r1919860 + Backport version for 2.4.x of patch: + https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/473.diff + Can be applied via apply_backport_pr.sh 473 + +1: covener, rpluem, jorton + + *) mod_http: Trust content-type values set from configuration + r1918823 takes care of the content-type fix, while r1427465 + is backported to avoid a conflict. It removes support for Request-Range + header sent by Navigator 2-3 and MSIE 3. + Trunk version of patch: + https://svn.apache.org/r1427465 + https://svn.apache.org/r1918823 + Backport version for 2.4.x of patch: + https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/475.diff + Can be applied via apply_backport_pr.sh 475 + +1: rpluem, covener, jorton + + *) mod_rewrite: Improve safe question mark detection + Trunk version of patch: + https://svn.apache.org/r1920566 + Backport version for 2.4.x of patch: + Trunk version of patch works + svn merge -c 1920566 ^/httpd/httpd/trunk . + +1: rpluem, covener, jorton + PATCHES PROPOSED TO BACKPORT FROM TRUNK: [ New proposals should be added at the end of the list ] @@ -231,35 +260,13 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: https://svn.apache.org/r1919602 2.4.x patch: svn merge -c r1919413 -c r1919587 -c r1919602 ^/httpd/httpd/trunk . +1: ivan + +0: jorton - falls under RTC exception for "non-Unix build" - *) mod_rewrite: don't merge leading slashes when they come from a perdir prefix - (rather than the substitution) - Trunk version of patch: - https://svn.apache.org/r1919860 - Backport version for 2.4.x of patch: - https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/473.diff - Can be applied via apply_backport_pr.sh 473 - +1: covener, rpluem - - *) mod_http: Trust content-type values set from configuration - r1918823 takes care of the content-type fix, while r1427465 - is backported to avoid a conflict. It removes support for Request-Range - header sent by Navigator 2-3 and MSIE 3. - Trunk version of patch: - https://svn.apache.org/r1427465 - https://svn.apache.org/r1918823 - Backport version for 2.4.x of patch: - https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/475.diff - Can be applied via apply_backport_pr.sh 475 - +1: rpluem, covener - - *) mod_rewrite: Improve safe question mark detection - Trunk version of patch: - https://svn.apache.org/r1920566 - Backport version for 2.4.x of patch: - Trunk version of patch works - svn merge -c 1920566 ^/httpd/httpd/trunk . - +1: rpluem, covener + *) mod_ssl: Fix regression in PKCS#11 handling which should work without + SSLCryptoDevice configured + trunk patch: https://svn.apache.org/r1920597 + 2.4.x patch: svn merge -c 1920597 ^/httpd/httpd/trunk . + +1: jorton, PATCHES/ISSUES THAT ARE BEING WORKED [ New entries should be added at the START of the list ] From 5849cf524118e53431598d65fa07c3f12a85e896 Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Fri, 27 Sep 2024 13:05:54 +0000 Subject: [PATCH 066/176] update-changes [skip ci] git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1920976 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES | 17 +++++++++++++++++ changes-entries/md_v2.4.28.txt | 11 ----------- changes-entries/tls_removed.txt | 4 ---- 3 files changed, 17 insertions(+), 15 deletions(-) delete mode 100644 changes-entries/md_v2.4.28.txt delete mode 100644 changes-entries/tls_removed.txt diff --git a/CHANGES b/CHANGES index b79ec2b77e..0b22403453 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,23 @@ -*- coding: utf-8 -*- Changes with Apache 2.4.63 + *) mod_md: update to version 2.4.28 + - When the server starts, it looks for new, staged certificates to + activate. If the staged set of files in 'md/staging/' is messed + up, this could prevent further renewals to happen. Now, when the staging + set is present, but could not be activated due to an error, purge the + whole directory. [icing] + - Fix certificate retrieval on ACME renewal to not require a 'Location:' + header returned by the ACME CA. This was the way it was done in ACME + before it became an IETF standard. Let's Encrypt still supports this, + but other CAs do not. [icing] + - Restore compatibility with OpenSSL < 1.1. [ylavic] + + *) mod_tls: removed the experimental module. It now is availble standalone + from https://github.com/icing/mod_tls. The rustls provided API is not + stable and does not align with the httpd release cycle. + [Stefan Eissing] + *) mod_rewrite: Better question mark tracking to avoid UnsafeAllow3F. PR 69197. [Yann Ylavic, Eric Covener] diff --git a/changes-entries/md_v2.4.28.txt b/changes-entries/md_v2.4.28.txt deleted file mode 100644 index 3eb2bc4917..0000000000 --- a/changes-entries/md_v2.4.28.txt +++ /dev/null @@ -1,11 +0,0 @@ - *) mod_md: update to version 2.4.28 - - When the server starts, it looks for new, staged certificates to - activate. If the staged set of files in 'md/staging/' is messed - up, this could prevent further renewals to happen. Now, when the staging - set is present, but could not be activated due to an error, purge the - whole directory. [icing] - - Fix certificate retrieval on ACME renewal to not require a 'Location:' - header returned by the ACME CA. This was the way it was done in ACME - before it became an IETF standard. Let's Encrypt still supports this, - but other CAs do not. [icing] - - Restore compatibility with OpenSSL < 1.1. [ylavic] diff --git a/changes-entries/tls_removed.txt b/changes-entries/tls_removed.txt deleted file mode 100644 index d56a3dc4e9..0000000000 --- a/changes-entries/tls_removed.txt +++ /dev/null @@ -1,4 +0,0 @@ - *) mod_tls: removed the experimental module. It now is availble standalone - from https://github.com/icing/mod_tls. The rustls provided API is not - stable and does not align with the httpd release cycle. - [Stefan Eissing] From cbf81b46440fc7759205ea715ebc452bdab7d937 Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Fri, 27 Sep 2024 13:06:46 +0000 Subject: [PATCH 067/176] Merge r1919532, r1919533 from trunk: *) mod_proxy: Avoid AH01059 parsing error for SetHandler "unix:" URLs in (incomplete fix in 2.4.62). PR 69160. When SetHandler "unix:..." is used in a block, the path gets appended (including $DOCUMENT_ROOT somehow) to r->filename hence the current checks in fixup_uds_filename() to add "localhost" when missing don't work. Fix them. mod_proxy: Allow for empty UDS URL hostname in ProxyPass workers too. Using "unix:/udspath|scheme:" or "unix:/udspath|scheme://" for a ProxyPass URL does not work currently, while it works for SetHandler "proxy:unix:...". Submitted by: ylavic Reviewed by: ylavic, covener, rpluem Github: closes #467 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1920977 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES | 3 +++ modules/proxy/mod_proxy.c | 9 ++++++--- modules/proxy/proxy_util.c | 40 +++++++++++++++++++++++++++----------- 3 files changed, 38 insertions(+), 14 deletions(-) diff --git a/CHANGES b/CHANGES index 0b22403453..db727016a5 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ -*- coding: utf-8 -*- Changes with Apache 2.4.63 + *) mod_proxy: Avoid AH01059 parsing error for SetHandler "unix:" URLs + in (incomplete fix in 2.4.62). PR 69160. [Yann Ylavic] + *) mod_md: update to version 2.4.28 - When the server starts, it looks for new, staged certificates to activate. If the staged set of files in 'md/staging/' is messed diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c index 8f13e686f9..756c41c4a1 100644 --- a/modules/proxy/mod_proxy.c +++ b/modules/proxy/mod_proxy.c @@ -1948,9 +1948,9 @@ PROXY_DECLARE(const char *) ap_proxy_de_socketfy(apr_pool_t *p, const char *url) const char *ret, *c; ret = ptr + 1; - /* special case: "unix:....|scheme:" is OK, expand - * to "unix:....|scheme://localhost" - * */ + /* special cases: "unix:...|scheme:" ind "unix:...|scheme://" are OK, + * expand to "unix:....|scheme://localhost" + */ c = ap_strchr_c(ret, ':'); if (c == NULL) { return NULL; @@ -1958,6 +1958,9 @@ PROXY_DECLARE(const char *) ap_proxy_de_socketfy(apr_pool_t *p, const char *url) if (c[1] == '\0') { return apr_pstrcat(p, ret, "//localhost", NULL); } + else if (c[1] == '/' && c[2] == '/' && !c[3]) { + return apr_pstrcat(p, ret, "localhost", NULL); + } else { return ret; } diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c index 7c0d3150c3..07621daed1 100644 --- a/modules/proxy/proxy_util.c +++ b/modules/proxy/proxy_util.c @@ -1972,7 +1972,7 @@ PROXY_DECLARE(char *) ap_proxy_define_worker_ex(apr_pool_t *p, && (ptr = ap_strchr_c(url + 5, '|'))) { rv = apr_uri_parse(p, apr_pstrmemdup(p, url, ptr - url), &uri); if (rv == APR_SUCCESS) { - sockpath = ap_runtime_dir_relative(p, uri.path);; + sockpath = ap_runtime_dir_relative(p, uri.path); ptr++; /* so we get the scheme for the uds */ } else { @@ -2038,7 +2038,7 @@ PROXY_DECLARE(char *) ap_proxy_define_worker_ex(apr_pool_t *p, if (!uri.scheme) { return apr_pstrcat(p, "URL must be absolute!: ", url, NULL); } - if (!uri.hostname) { + if (!uri.hostname || !*uri.hostname) { if (sockpath) { /* allow for unix:/path|http: */ uri.hostname = "localhost"; @@ -2434,7 +2434,7 @@ static int fixup_uds_filename(request_rec *r) if (!strncmp(r->filename, "proxy:", 6) && !ap_cstr_casecmpn(uds_url, "unix:", 5) && (origin_url = ap_strchr(uds_url + 5, '|'))) { - char *uds_path = NULL, *end; + char *uds_path = NULL, *col; apr_uri_t urisock; apr_status_t rv; @@ -2446,7 +2446,7 @@ static int fixup_uds_filename(request_rec *r) || !urisock.hostname[0])) { uds_path = ap_runtime_dir_relative(r->pool, urisock.path); } - if (!uds_path || !(end = ap_strchr(origin_url, ':'))) { + if (!uds_path || !(col = ap_strchr(origin_url, ':'))) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10292) "Invalid proxy UDS filename (%s)", r->filename); apr_table_unset(r->notes, "uds_path"); @@ -2459,21 +2459,39 @@ static int fixup_uds_filename(request_rec *r) r->filename, origin_url, uds_path); /* The hostname part of the URL is not mandated for UDS though - * the canon_handler hooks will require it, so add "localhost" - * if it's missing (won't be used anyway for an AF_UNIX socket). + * the canon_handler hooks will require it. ProxyPass URLs are + * fixed at load time by adding "localhost" automatically in the + * worker URL, but SetHandler "proxy:unix:/udspath|scheme:[//]" + * URLs are not so we have to fix it here the same way. */ - if (!end[1]) { + if (!col[1]) { + /* origin_url is "scheme:" */ r->filename = apr_pstrcat(r->pool, "proxy:", origin_url, "//localhost", NULL); } - else if (end[1] == '/' && end[2] == '/' && !end[3]) { + /* For a SetHandler "proxy:..." in a , the "/path" + * is appended to r->filename, hence the below origin_url cases too: + */ + else if (col[1] == '/' && (col[2] != '/' /* "scheme:/path" */ + || col[3] == '/' /* "scheme:///path" */ + || !col[3])) { /* "scheme://" */ + char *scheme = origin_url; + *col = '\0'; /* nul terminate scheme */ + if (col[2] != '/') { + origin_url = col + 1; + } + else { + origin_url = col + 3; + } r->filename = apr_pstrcat(r->pool, "proxy:", - origin_url, "localhost", - NULL); + scheme, "://localhost", + origin_url, NULL); } else { - /* Overwrite the UDS part of r->filename in place */ + /* origin_url is normal "scheme://host/path", can overwrite + * the UDS part of r->filename in place. + */ memmove(uds_url, origin_url, strlen(origin_url) + 1); } return OK; From 67982b79d9de53da783ebc69d23975279134b400 Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Fri, 27 Sep 2024 13:07:26 +0000 Subject: [PATCH 068/176] *) mod_ldap: Add a hint to install the apr_ldap module on init failure. trunk patch: http://svn.apache.org/r1914038 2.4.x patch: svn merge -c r1914038 ^/httpd/httpd/trunk . +1: minfrin, covener, rpluem git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1920978 13f79535-47bb-0310-9956-ffa450edef68 --- modules/ldap/util_ldap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ldap/util_ldap.c b/modules/ldap/util_ldap.c index 8c9e58717d..4747d826ae 100644 --- a/modules/ldap/util_ldap.c +++ b/modules/ldap/util_ldap.c @@ -350,7 +350,7 @@ static int uldap_connection_init(request_rec *r, /* something really bad happened */ ldc->bound = 0; if (NULL == ldc->reason) { - ldc->reason = "LDAP: ldap initialization failed"; + ldc->reason = "LDAP: ldap initialization failed. Make sure the apr_ldap module is installed."; } return(APR_EGENERAL); } From 82736c811b0af3f85dfdf29abdef1e759063c7b7 Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Fri, 27 Sep 2024 13:08:17 +0000 Subject: [PATCH 069/176] *) Windows: Make UNCList EXEC_ON_READ to be early enough for `Include //computername/include.conf`. PR69313 Trunk version of patch: https://svn.apache.org/r1920564 Backport version for 2.4.x of patch: svn merge -c r1920564 ^/httpd/httpd/trunk . +1 covener, rpluem, steffenal git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1920979 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES | 3 +++ server/core.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index db727016a5..cf7ebfc03a 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ -*- coding: utf-8 -*- Changes with Apache 2.4.63 + *) Windows: Restore the ability to "Include" configuration files on UNC + paths. PR69313 [Eric Covener] + *) mod_proxy: Avoid AH01059 parsing error for SetHandler "unix:" URLs in (incomplete fix in 2.4.62). PR 69160. [Yann Ylavic] diff --git a/server/core.c b/server/core.c index 843b97320f..a27769f3d3 100644 --- a/server/core.c +++ b/server/core.c @@ -4547,7 +4547,7 @@ AP_INIT_TAKE1("FlushMaxPipelined", set_flush_max_pipelined, NULL, RSRC_CONF, "Maximum number of pipelined responses (pending) above which they are " "flushed to the network"), #ifdef WIN32 -AP_INIT_TAKE_ARGV("UNCList", set_unc_list, NULL, RSRC_CONF, +AP_INIT_TAKE_ARGV("UNCList", set_unc_list, NULL, RSRC_CONF|EXEC_ON_READ, "Controls what UNC hosts may be looked up"), #endif From be9f2ea3bbff45d0f793491c623beb3b70c5147d Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Fri, 27 Sep 2024 13:09:43 +0000 Subject: [PATCH 070/176] Merge r1919860 from trunk: don't merge slashes on perdir prefix Submitted by: covener Reviewed by: covener, rpluem, jorton Github: closes #473 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1920980 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES | 4 ++++ modules/mappers/mod_rewrite.c | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index cf7ebfc03a..ffd8cfba1c 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,10 @@ -*- coding: utf-8 -*- Changes with Apache 2.4.63 + *) mod_rewrite: Don't require [UNC] flag to preserve a leading // + added by applying the perdir prefix to the substitution. + [Ruediger Pluem, Eric Covener] + *) Windows: Restore the ability to "Include" configuration files on UNC paths. PR69313 [Eric Covener] diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c index 24e21c6f4d..ef3e52fb79 100644 --- a/modules/mappers/mod_rewrite.c +++ b/modules/mappers/mod_rewrite.c @@ -4322,6 +4322,7 @@ static rule_return_type apply_rewrite_rule(rewriterule_entry *p, char *newuri = NULL; request_rec *r = ctx->r; int is_proxyreq = 0; + int prefix_added = 0; ctx->uri = r->filename; @@ -4483,6 +4484,7 @@ static rule_return_type apply_rewrite_rule(rewriterule_entry *p, newuri, ctx->perdir, newuri); newuri = apr_pstrcat(r->pool, ctx->perdir, newuri, NULL); + prefix_added = 1; } else if (!(p->flags & (RULEFLAG_PROXY | RULEFLAG_FORCEREDIRECT))) { /* Not an absolute URI-path and the scheme (if any) is unknown, @@ -4496,6 +4498,7 @@ static rule_return_type apply_rewrite_rule(rewriterule_entry *p, newuri, newuri); newuri = apr_pstrcat(r->pool, "/", newuri, NULL); + prefix_added = 1; } } @@ -4576,7 +4579,7 @@ static rule_return_type apply_rewrite_rule(rewriterule_entry *p, return RULE_RC_MATCH; } - if (!(p->flags & RULEFLAG_UNC)) { + if (!((p->flags & RULEFLAG_UNC) || prefix_added)) { /* merge leading slashes, unless they were literals in the sub */ if (!AP_IS_SLASH(p->output[0]) || !AP_IS_SLASH(p->output[1])) { while (AP_IS_SLASH(r->filename[0]) && From 5f82765bc640ddb6a13a681464856bf8f8a5cb10 Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Fri, 27 Sep 2024 13:10:34 +0000 Subject: [PATCH 071/176] Merge r1427465, r1918823 from trunk: Remove support for Request-Range header sent by Navigator 2-3 and MSIE 3 * Follow up to r1918814: Strings are from configuration and thus trusted Submitted by: sf, rpluem Reviewed by: rpluem, covener, jorton Github: closes #475 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1920981 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES | 3 +++ modules/filters/mod_ext_filter.c | 2 +- modules/generators/mod_autoindex.c | 6 ++--- modules/http/byterange_filter.c | 43 +++++------------------------- modules/http/http_request.c | 2 +- modules/proxy/mod_proxy_ftp.c | 4 +-- 6 files changed, 16 insertions(+), 44 deletions(-) diff --git a/CHANGES b/CHANGES index ffd8cfba1c..a22755fdca 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ -*- coding: utf-8 -*- Changes with Apache 2.4.63 + *) http: Remove support for Request-Range header sent by Navigator 2-3 and + MSIE 3. [Stefan Fritsch] + *) mod_rewrite: Don't require [UNC] flag to preserve a leading // added by applying the perdir prefix to the substitution. [Ruediger Pluem, Eric Covener] diff --git a/modules/filters/mod_ext_filter.c b/modules/filters/mod_ext_filter.c index 7afd8dda16..6a7c9e4bfe 100644 --- a/modules/filters/mod_ext_filter.c +++ b/modules/filters/mod_ext_filter.c @@ -610,7 +610,7 @@ static apr_status_t init_filter_instance(ap_filter_t *f) } if (ctx->filter->outtype && ctx->filter->outtype != OUTTYPE_UNCHANGED) { - ap_set_content_type(f->r, ctx->filter->outtype); + ap_set_content_type_ex(f->r, ctx->filter->outtype, 1); } if (ctx->filter->preserves_content_length != 1) { /* nasty, but needed to avoid confusing the browser diff --git a/modules/generators/mod_autoindex.c b/modules/generators/mod_autoindex.c index cb4460357c..62804309ea 100644 --- a/modules/generators/mod_autoindex.c +++ b/modules/generators/mod_autoindex.c @@ -2052,11 +2052,11 @@ static int index_directory(request_rec *r, #endif } if (*charset) { - ap_set_content_type(r, apr_pstrcat(r->pool, ctype, ";charset=", - charset, NULL)); + ap_set_content_type_ex(r, apr_pstrcat(r->pool, ctype, ";charset=", + charset, NULL), 1); } else { - ap_set_content_type(r, ctype); + ap_set_content_type_ex(r, ctype, 1); } if (autoindex_opts & TRACK_MODIFIED) { diff --git a/modules/http/byterange_filter.c b/modules/http/byterange_filter.c index 5ebe853320..a1ffdd385b 100644 --- a/modules/http/byterange_filter.c +++ b/modules/http/byterange_filter.c @@ -100,21 +100,7 @@ static int ap_set_byterange(request_rec *r, apr_off_t clength, return 0; } - /* - * Check for Range request-header (HTTP/1.1) or Request-Range for - * backwards-compatibility with second-draft Luotonen/Franks - * byte-ranges (e.g. Netscape Navigator 2-3). - * - * We support this form, with Request-Range, and (farther down) we - * send multipart/x-byteranges instead of multipart/byteranges for - * Request-Range based requests to work around a bug in Netscape - * Navigator 2-3 and MSIE 3. - */ - - if (!(range = apr_table_get(r->headers_in, "Range"))) { - range = apr_table_get(r->headers_in, "Request-Range"); - } - + range = apr_table_get(r->headers_in, "Range"); if (!range || strncasecmp(range, "bytes=", 6) || r->status != HTTP_OK) { return 0; } @@ -126,10 +112,9 @@ static int ap_set_byterange(request_rec *r, apr_off_t clength, /* is content already a multiple range? */ if ((ct = apr_table_get(r->headers_out, "Content-Type")) - && (!strncasecmp(ct, "multipart/byteranges", 20) - || !strncasecmp(ct, "multipart/x-byteranges", 22))) { + && strncasecmp(ct, "multipart/byteranges", 20) == 0) { return 0; - } + } /* * Check the If-Range header for Etag or Date. @@ -298,21 +283,6 @@ static int ap_set_byterange(request_rec *r, apr_off_t clength, return num_ranges; } -/* - * Here we try to be compatible with clients that want multipart/x-byteranges - * instead of multipart/byteranges (also see above), as per HTTP/1.1. We - * look for the Request-Range header (e.g. Netscape 2 and 3) as an indication - * that the browser supports an older protocol. We also check User-Agent - * for Microsoft Internet Explorer 3, which needs this as well. - */ -static int use_range_x(request_rec *r) -{ - const char *ua; - return (apr_table_get(r->headers_in, "Request-Range") - || ((ua = apr_table_get(r->headers_in, "User-Agent")) - && ap_strstr_c(ua, "MSIE 3"))); -} - #define BYTERANGE_FMT "%" APR_OFF_T_FMT "-%" APR_OFF_T_FMT "/%" APR_OFF_T_FMT static apr_status_t copy_brigade_range(apr_bucket_brigade *bb, @@ -503,10 +473,9 @@ AP_CORE_DECLARE_NONSTD(apr_status_t) ap_byterange_filter(ap_filter_t *f, /* Is ap_make_content_type required here? */ const char *orig_ct = ap_make_content_type(r, r->content_type); - ap_set_content_type(r, apr_pstrcat(r->pool, "multipart", - use_range_x(r) ? "/x-" : "/", - "byteranges; boundary=", - ap_multipart_boundary, NULL)); + ap_set_content_type_ex(r, apr_pstrcat(r->pool, + "multipart/byteranges; boundary=", + ap_multipart_boundary, NULL), 1); if (orig_ct) { bound_head = apr_pstrcat(r->pool, diff --git a/modules/http/http_request.c b/modules/http/http_request.c index 7e9477be1f..46da143986 100644 --- a/modules/http/http_request.c +++ b/modules/http/http_request.c @@ -808,7 +808,7 @@ AP_DECLARE(void) ap_internal_redirect_handler(const char *new_uri, request_rec * } if (r->handler) - ap_set_content_type(new, r->content_type); + ap_set_content_type_ex(new, r->content_type, AP_REQUEST_IS_TRUSTED_CT(r)); access_status = ap_process_request_internal(new); if (access_status == OK) { access_status = ap_invoke_handler(new); diff --git a/modules/proxy/mod_proxy_ftp.c b/modules/proxy/mod_proxy_ftp.c index e0032e5358..5175e45584 100644 --- a/modules/proxy/mod_proxy_ftp.c +++ b/modules/proxy/mod_proxy_ftp.c @@ -1878,10 +1878,10 @@ static int proxy_ftp_handler(request_rec *r, proxy_worker *worker, /* set content-type */ if (dirlisting) { - ap_set_content_type(r, apr_pstrcat(p, "text/html;charset=", + ap_set_content_type_ex(r, apr_pstrcat(p, "text/html;charset=", fdconf->ftp_directory_charset ? fdconf->ftp_directory_charset : - "ISO-8859-1", NULL)); + "ISO-8859-1", NULL), 1); } else { if (xfer_type != 'A' && size != NULL) { From c91445b7f905587aa86ad552f4a1a3f29345e695 Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Fri, 27 Sep 2024 13:11:05 +0000 Subject: [PATCH 072/176] *) mod_rewrite: Improve safe question mark detection Trunk version of patch: https://svn.apache.org/r1920566 Backport version for 2.4.x of patch: Trunk version of patch works svn merge -c 1920566 ^/httpd/httpd/trunk . +1: rpluem, covener, jorton git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1920982 13f79535-47bb-0310-9956-ffa450edef68 --- modules/mappers/mod_rewrite.c | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c index ef3e52fb79..0bf4404923 100644 --- a/modules/mappers/mod_rewrite.c +++ b/modules/mappers/mod_rewrite.c @@ -2442,21 +2442,19 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry, *unsafe_qmark = 0; /* keep tracking only if interested in the last qmark */ - if (entry && (entry->flags & RULEFLAG_QSLAST)) { - do { - span++; - span += strcspn(input + span, EXPAND_SPECIALS "?"); - } while (input[span] == '?'); - } - else { + if (!entry || !(entry->flags & RULEFLAG_QSLAST)) { unsafe_qmark = NULL; - span += strcspn(input + span, EXPAND_SPECIALS); } + + /* find the next real special char, any (last) qmark up to + * there is safe too + */ + span += strcspn(input + span, EXPAND_SPECIALS); } } - /* fast exit */ - if (inputlen == span) { + /* fast path (no specials) */ + if (span >= inputlen) { return apr_pstrmemdup(pool, input, inputlen); } @@ -2637,16 +2635,14 @@ static char *do_expand(char *input, rewrite_ctx *ctx, rewriterule_entry *entry, *unsafe_qmark = 0; /* keep tracking only if interested in the last qmark */ - if (entry && (entry->flags & RULEFLAG_QSLAST)) { - do { - span++; - span += strcspn(p + span, EXPAND_SPECIALS "?"); - } while (p[span] == '?'); - } - else { + if (!entry || !(entry->flags & RULEFLAG_QSLAST)) { unsafe_qmark = NULL; - span += strcspn(p + span, EXPAND_SPECIALS); } + + /* find the next real special char, any (last) qmark up to + * there is safe too + */ + span += strcspn(p + span, EXPAND_SPECIALS); } } if (span > 0) { From 2095d87c3b324469eae9b851a5222ba35d45ba9a Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Fri, 27 Sep 2024 13:11:34 +0000 Subject: [PATCH 073/176] backported [skip ci] git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1920983 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 51 --------------------------------------------------- 1 file changed, 51 deletions(-) diff --git a/STATUS b/STATUS index 3117ec11e5..1e07bdcd58 100644 --- a/STATUS +++ b/STATUS @@ -161,57 +161,6 @@ RELEASE SHOWSTOPPERS: PATCHES ACCEPTED TO BACKPORT FROM TRUNK: [ start all new proposals below, under PATCHES PROPOSED. ] - *) mod_proxy: Avoid AH01059 parsing error for SetHandler "unix:" URLs - in (incomplete fix in 2.4.62). PR 69160. - trunk patch: https://svn.apache.org/r1919532 - https://svn.apache.org/r1919533 - 2.4.x patch: https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/467.diff - PR: https://github.com/apache/httpd/pull/467 - +1: ylavic, covener, rpluem - - *) mod_ldap: Add a hint to install the apr_ldap module on init failure. - trunk patch: http://svn.apache.org/r1914038 - 2.4.x patch: svn merge -c r1914038 ^/httpd/httpd/trunk . - +1: minfrin, covener, rpluem - - *) Windows: Make UNCList EXEC_ON_READ to be early enough for - `Include //computername/include.conf`. PR69313 - Trunk version of patch: - https://svn.apache.org/r1920564 - Backport version for 2.4.x of patch: - svn merge -c r1920564 ^/httpd/httpd/trunk . - +1 covener, rpluem, steffenal - - - *) mod_rewrite: don't merge leading slashes when they come from a perdir prefix - (rather than the substitution) - Trunk version of patch: - https://svn.apache.org/r1919860 - Backport version for 2.4.x of patch: - https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/473.diff - Can be applied via apply_backport_pr.sh 473 - +1: covener, rpluem, jorton - - *) mod_http: Trust content-type values set from configuration - r1918823 takes care of the content-type fix, while r1427465 - is backported to avoid a conflict. It removes support for Request-Range - header sent by Navigator 2-3 and MSIE 3. - Trunk version of patch: - https://svn.apache.org/r1427465 - https://svn.apache.org/r1918823 - Backport version for 2.4.x of patch: - https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/475.diff - Can be applied via apply_backport_pr.sh 475 - +1: rpluem, covener, jorton - - *) mod_rewrite: Improve safe question mark detection - Trunk version of patch: - https://svn.apache.org/r1920566 - Backport version for 2.4.x of patch: - Trunk version of patch works - svn merge -c 1920566 ^/httpd/httpd/trunk . - +1: rpluem, covener, jorton - PATCHES PROPOSED TO BACKPORT FROM TRUNK: [ New proposals should be added at the end of the list ] From 3955cf80fca0838eebd576cb46f280897a143078 Mon Sep 17 00:00:00 2001 From: Ruediger Pluem Date: Fri, 27 Sep 2024 15:31:02 +0000 Subject: [PATCH 074/176] * Add proposal git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1920993 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/STATUS b/STATUS index 1e07bdcd58..58c942689a 100644 --- a/STATUS +++ b/STATUS @@ -217,6 +217,18 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: 2.4.x patch: svn merge -c 1920597 ^/httpd/httpd/trunk . +1: jorton, + *) mod_rewrite, mod_proxy: mod_proxy to cononicalize rewritten [P] URLs, + including "unix:" ones. PR 69235, PR 69260, PR 56264 + Trunk version of patch: + https://svn.apache.org/r1838684 + https://svn.apache.org/r1920570 + https://svn.apache.org/r1920571 + https://svn.apache.org/r1920572 + Backport version for 2.4.x of patch: + https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/484.diff + Can be applied via apply_backport_pr.sh 484 + +1: rpluem, + PATCHES/ISSUES THAT ARE BEING WORKED [ New entries should be added at the START of the list ] From 2d65485ea6a0a7f769b0be5be64144d9716188da Mon Sep 17 00:00:00 2001 From: Yann Ylavic Date: Sat, 28 Sep 2024 00:07:55 +0000 Subject: [PATCH 075/176] +1 x 2 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1921001 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/STATUS b/STATUS index 58c942689a..1917e47329 100644 --- a/STATUS +++ b/STATUS @@ -215,7 +215,7 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: SSLCryptoDevice configured trunk patch: https://svn.apache.org/r1920597 2.4.x patch: svn merge -c 1920597 ^/httpd/httpd/trunk . - +1: jorton, + +1: jorton, ylavic, *) mod_rewrite, mod_proxy: mod_proxy to cononicalize rewritten [P] URLs, including "unix:" ones. PR 69235, PR 69260, PR 56264 @@ -227,7 +227,7 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: Backport version for 2.4.x of patch: https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/484.diff Can be applied via apply_backport_pr.sh 484 - +1: rpluem, + +1: rpluem, ylavic, PATCHES/ISSUES THAT ARE BEING WORKED [ New entries should be added at the START of the list ] From 03d91935cb82c47caeab63efd59296345945aa15 Mon Sep 17 00:00:00 2001 From: Joe Orton Date: Tue, 1 Oct 2024 16:28:26 +0000 Subject: [PATCH 076/176] Update & reset mod_ssl vote. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1921077 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/STATUS b/STATUS index 1917e47329..9000417750 100644 --- a/STATUS +++ b/STATUS @@ -214,8 +214,9 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: *) mod_ssl: Fix regression in PKCS#11 handling which should work without SSLCryptoDevice configured trunk patch: https://svn.apache.org/r1920597 - 2.4.x patch: svn merge -c 1920597 ^/httpd/httpd/trunk . - +1: jorton, ylavic, + https://svn.apache.org/r1921076 + 2.4.x patch: svn merge -c 1920597 -c 1921076 ^/httpd/httpd/trunk . + +1: jorton, *) mod_rewrite, mod_proxy: mod_proxy to cononicalize rewritten [P] URLs, including "unix:" ones. PR 69235, PR 69260, PR 56264 From f9ecbc63e490887a9cce033566f277b9f9394100 Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Wed, 2 Oct 2024 14:36:35 +0000 Subject: [PATCH 077/176] vote/promote/comment [skip ci] git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1921085 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/STATUS b/STATUS index 9000417750..1c799b7cf9 100644 --- a/STATUS +++ b/STATUS @@ -161,6 +161,18 @@ RELEASE SHOWSTOPPERS: PATCHES ACCEPTED TO BACKPORT FROM TRUNK: [ start all new proposals below, under PATCHES PROPOSED. ] + *) mod_rewrite, mod_proxy: mod_proxy to cononicalize rewritten [P] URLs, + including "unix:" ones. PR 69235, PR 69260, PR 56264 + Trunk version of patch: + https://svn.apache.org/r1838684 + https://svn.apache.org/r1920570 + https://svn.apache.org/r1920571 + https://svn.apache.org/r1920572 + Backport version for 2.4.x of patch: + https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/484.diff + Can be applied via apply_backport_pr.sh 484 + +1: rpluem, ylavic, covener + PATCHES PROPOSED TO BACKPORT FROM TRUNK: [ New proposals should be added at the end of the list ] @@ -181,6 +193,7 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: https://svn.apache.org/repos/asf/httpd/httpd/patches/2.4.x/httpd-2.4-httpd-2.4-ldap-search5.patch +1: minfrin, covener rpluem says: https://svn.apache.org/repos/asf/httpd/httpd/patches/2.4.x/httpd-2.4-ldap-search5.patch returns 404 + covener: fixed slightly diff URL above *) mod_proxy: Honor parameters of ProxyPassMatch workers with substitution in the host name or port. PR 69233. @@ -199,8 +212,7 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: https://svn.apache.org/r1919628 2.4.x patch: https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/470.diff PR: https://github.com/apache/httpd/pull/470 - +1: ylavic - covener: pending https://github.com/apache/httpd/pull/470#discussion_r1718079315 outcome + +1: ylavic, covener *) CMake: Remove awk dependency when building using CMake. Before this awk was required for -DWITH_MODULES option. @@ -218,17 +230,6 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: 2.4.x patch: svn merge -c 1920597 -c 1921076 ^/httpd/httpd/trunk . +1: jorton, - *) mod_rewrite, mod_proxy: mod_proxy to cononicalize rewritten [P] URLs, - including "unix:" ones. PR 69235, PR 69260, PR 56264 - Trunk version of patch: - https://svn.apache.org/r1838684 - https://svn.apache.org/r1920570 - https://svn.apache.org/r1920571 - https://svn.apache.org/r1920572 - Backport version for 2.4.x of patch: - https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/484.diff - Can be applied via apply_backport_pr.sh 484 - +1: rpluem, ylavic, PATCHES/ISSUES THAT ARE BEING WORKED [ New entries should be added at the START of the list ] From fc2f7c55f8bb0c8be1268485e0cbdb21a7cd1ee6 Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Wed, 2 Oct 2024 14:42:25 +0000 Subject: [PATCH 078/176] pause on rewrite/proxy thing git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1921086 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/STATUS b/STATUS index 1c799b7cf9..9ad3fd5bde 100644 --- a/STATUS +++ b/STATUS @@ -161,18 +161,6 @@ RELEASE SHOWSTOPPERS: PATCHES ACCEPTED TO BACKPORT FROM TRUNK: [ start all new proposals below, under PATCHES PROPOSED. ] - *) mod_rewrite, mod_proxy: mod_proxy to cononicalize rewritten [P] URLs, - including "unix:" ones. PR 69235, PR 69260, PR 56264 - Trunk version of patch: - https://svn.apache.org/r1838684 - https://svn.apache.org/r1920570 - https://svn.apache.org/r1920571 - https://svn.apache.org/r1920572 - Backport version for 2.4.x of patch: - https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/484.diff - Can be applied via apply_backport_pr.sh 484 - +1: rpluem, ylavic, covener - PATCHES PROPOSED TO BACKPORT FROM TRUNK: [ New proposals should be added at the end of the list ] @@ -230,6 +218,19 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: 2.4.x patch: svn merge -c 1920597 -c 1921076 ^/httpd/httpd/trunk . +1: jorton, + *) mod_rewrite, mod_proxy: mod_proxy to cononicalize rewritten [P] URLs, + including "unix:" ones. PR 69235, PR 69260, PR 56264 + Trunk version of patch: + https://svn.apache.org/r1838684 + https://svn.apache.org/r1920570 + https://svn.apache.org/r1920571 + https://svn.apache.org/r1920572 + Backport version for 2.4.x of patch: + https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/484.diff + Can be applied via apply_backport_pr.sh 484 + +1: rpluem, ylavic + covener: what about remaining parts of https://bz.apache.org/bugzilla/show_bug.cgi?id=69203 ? 69260 was marked dup of 69203. + PATCHES/ISSUES THAT ARE BEING WORKED [ New entries should be added at the START of the list ] From 2840f91f063bdd0a204987b548347d1cefb3546f Mon Sep 17 00:00:00 2001 From: Yann Ylavic Date: Thu, 10 Oct 2024 16:30:29 +0000 Subject: [PATCH 079/176] Split mod_proxy_fcgi backports in two, the showstopper (BZ-69203) and fixup for proxy-fcgi-pathinfo=full, thus reset Ruediger's vote. Move showstopper proposals to their section (BZ-69203 and BZ-69235/69260/56264) instead of the BZ refs. Re-add my vote for r1920597. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1921239 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 55 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/STATUS b/STATUS index 9ad3fd5bde..3a8de697ba 100644 --- a/STATUS +++ b/STATUS @@ -153,10 +153,29 @@ CURRENT RELEASE NOTES: RELEASE SHOWSTOPPERS: -- PR69235 (UDS+rewrite?) -- PR69260 (dup of above) -- PR69203 (FPM) + *) mod_proxy_fcgi: Don't re-encode SCRIPT_FILENAME when set via SetHandler. PR 69203. + trunk patch: https://svn.apache.org/r1919620 + https://svn.apache.org/r1919621 + https://svn.apache.org/r1919623 + https://svn.apache.org/r1919628 + https://svn.apache.org/r1921237 + 2.4.x patch: https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/470.diff + PR: https://github.com/apache/httpd/pull/470 + +1: ylavic, + *) mod_rewrite, mod_proxy: mod_proxy to cononicalize rewritten [P] URLs, + including "unix:" ones. PR 69235, PR 69260, PR 56264 + Trunk version of patch: + https://svn.apache.org/r1838684 + https://svn.apache.org/r1920570 + https://svn.apache.org/r1920571 + https://svn.apache.org/r1920572 + Backport version for 2.4.x of patch: + https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/484.diff + Can be applied via apply_backport_pr.sh 484 + +1: rpluem, ylavic + covener: what about remaining parts of https://bz.apache.org/bugzilla/show_bug.cgi?id=69203 ? 69260 was marked dup of 69203. + ylavic: BZ-69203 is addressed in mod_proxy_fcgi proposal above (https://github.com/apache/httpd/pull/470) PATCHES ACCEPTED TO BACKPORT FROM TRUNK: [ start all new proposals below, under PATCHES PROPOSED. ] @@ -192,16 +211,6 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: PR: https://github.com/apache/httpd/pull/469 +1: ylavic, rpluem - *) mod_proxy_fcgi: Don't re-encode SCRIPT_FILENAME when set via SetHandler. PR 69203. - trunk patch: https://svn.apache.org/r1919547 - https://svn.apache.org/r1919620 - https://svn.apache.org/r1919621 - https://svn.apache.org/r1919623 - https://svn.apache.org/r1919628 - 2.4.x patch: https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/470.diff - PR: https://github.com/apache/httpd/pull/470 - +1: ylavic, covener - *) CMake: Remove awk dependency when building using CMake. Before this awk was required for -DWITH_MODULES option. trunk patch: https://svn.apache.org/r1919413 @@ -216,20 +225,14 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: trunk patch: https://svn.apache.org/r1920597 https://svn.apache.org/r1921076 2.4.x patch: svn merge -c 1920597 -c 1921076 ^/httpd/httpd/trunk . - +1: jorton, + +1: jorton, ylavic, - *) mod_rewrite, mod_proxy: mod_proxy to cononicalize rewritten [P] URLs, - including "unix:" ones. PR 69235, PR 69260, PR 56264 - Trunk version of patch: - https://svn.apache.org/r1838684 - https://svn.apache.org/r1920570 - https://svn.apache.org/r1920571 - https://svn.apache.org/r1920572 - Backport version for 2.4.x of patch: - https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/484.diff - Can be applied via apply_backport_pr.sh 484 - +1: rpluem, ylavic - covener: what about remaining parts of https://bz.apache.org/bugzilla/show_bug.cgi?id=69203 ? 69260 was marked dup of 69203. + *) mod_proxy_fcgi: Fix proxy-fcgi-pathinfo=full + trunk patch: https://svn.apache.org/r1919547 + https://svn.apache.org/r1921238 + 2.4.x patch: https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/489.diff + PR: https://github.com/apache/httpd/pull/489 + +1: ylavic, PATCHES/ISSUES THAT ARE BEING WORKED From b5910882a5668e260c24002545802f365a419c91 Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Sat, 12 Oct 2024 18:46:27 +0000 Subject: [PATCH 080/176] vote/promote [skip ci] git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1921279 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/STATUS b/STATUS index 3a8de697ba..ab647490ad 100644 --- a/STATUS +++ b/STATUS @@ -161,7 +161,9 @@ RELEASE SHOWSTOPPERS: https://svn.apache.org/r1921237 2.4.x patch: https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/470.diff PR: https://github.com/apache/httpd/pull/470 - +1: ylavic, + +1: ylavic, covener +PATCHES ACCEPTED TO BACKPORT FROM TRUNK: + [ start all new proposals below, under PATCHES PROPOSED. ] *) mod_rewrite, mod_proxy: mod_proxy to cononicalize rewritten [P] URLs, including "unix:" ones. PR 69235, PR 69260, PR 56264 @@ -173,12 +175,8 @@ RELEASE SHOWSTOPPERS: Backport version for 2.4.x of patch: https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/484.diff Can be applied via apply_backport_pr.sh 484 - +1: rpluem, ylavic - covener: what about remaining parts of https://bz.apache.org/bugzilla/show_bug.cgi?id=69203 ? 69260 was marked dup of 69203. - ylavic: BZ-69203 is addressed in mod_proxy_fcgi proposal above (https://github.com/apache/httpd/pull/470) + +1: rpluem, ylavic, covener -PATCHES ACCEPTED TO BACKPORT FROM TRUNK: - [ start all new proposals below, under PATCHES PROPOSED. ] PATCHES PROPOSED TO BACKPORT FROM TRUNK: [ New proposals should be added at the end of the list ] @@ -232,7 +230,7 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: https://svn.apache.org/r1921238 2.4.x patch: https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/489.diff PR: https://github.com/apache/httpd/pull/489 - +1: ylavic, + +1: ylavic, covener PATCHES/ISSUES THAT ARE BEING WORKED From 0531a7deac4f8cbcc1f3b0f60da2aa98b6d139b2 Mon Sep 17 00:00:00 2001 From: Ruediger Pluem Date: Mon, 14 Oct 2024 06:52:14 +0000 Subject: [PATCH 081/176] * Vote and promote [skip ci] git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1921298 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/STATUS b/STATUS index ab647490ad..a6474ce1af 100644 --- a/STATUS +++ b/STATUS @@ -177,6 +177,12 @@ PATCHES ACCEPTED TO BACKPORT FROM TRUNK: Can be applied via apply_backport_pr.sh 484 +1: rpluem, ylavic, covener + *) mod_ssl: Fix regression in PKCS#11 handling which should work without + SSLCryptoDevice configured + trunk patch: https://svn.apache.org/r1920597 + https://svn.apache.org/r1921076 + 2.4.x patch: svn merge -c 1920597 -c 1921076 ^/httpd/httpd/trunk . + +1: jorton, ylavic, rpluem PATCHES PROPOSED TO BACKPORT FROM TRUNK: [ New proposals should be added at the end of the list ] @@ -218,13 +224,6 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: +1: ivan +0: jorton - falls under RTC exception for "non-Unix build" - *) mod_ssl: Fix regression in PKCS#11 handling which should work without - SSLCryptoDevice configured - trunk patch: https://svn.apache.org/r1920597 - https://svn.apache.org/r1921076 - 2.4.x patch: svn merge -c 1920597 -c 1921076 ^/httpd/httpd/trunk . - +1: jorton, ylavic, - *) mod_proxy_fcgi: Fix proxy-fcgi-pathinfo=full trunk patch: https://svn.apache.org/r1919547 https://svn.apache.org/r1921238 From 88ebfaa60d3a1987dda88d74eb820294c16edc3d Mon Sep 17 00:00:00 2001 From: Ruediger Pluem Date: Mon, 14 Oct 2024 06:56:45 +0000 Subject: [PATCH 082/176] Merge r1838684, r1920570, r1920571, r1920572 from trunk: When a rewrite to proxy is configured in the server config, a check is made to make sure mod_proxy is active. But the same is not done if a rewrite to proxy is configured in an .htaccess file. Basically this patch is the block of code from hook_uri2file that does the proxy check, copied to hook_fixup. Patch provided by Michael Streeter [mstreeter1 gmail.com], slightly modified to use a new APLOGNO PR 56264 mod_rewrite, mod_proxy: mod_proxy to cononicalize rewritten [P] URLs. PR 69235. When mod_rewrite sets a "proxy:" URL with [P], it should be canonicalized by mod_proxy still, notably to handle any "unix:" local socket part. To avoid double encoding in perdir context, a follow up commit should remove the ap_escape_uri() done in mod_rewrite since it's now on mod_proxy to canonicalize, per PR 69260. * Leave the proper escaping of the URL and the adding of r->args to the proxy module which runs after us after r1920570. Just take care to add r->args in case the proxy rule has the [NE] flag set and tell the proxy module to not escape in this case. * Mention the additional bug Submitted by: jailletc36, ylavic, rpluem Reviewed by: rpluem, ylavic, covener Github: closes #484 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1921299 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES | 7 +++++ STATUS | 12 -------- modules/mappers/mod_rewrite.c | 52 +++++++++++++++++------------------ modules/proxy/mod_proxy.c | 13 ++++----- 4 files changed, 39 insertions(+), 45 deletions(-) diff --git a/CHANGES b/CHANGES index a22755fdca..9e0cf40777 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,13 @@ -*- coding: utf-8 -*- Changes with Apache 2.4.63 + *) mod_rewrite, mod_proxy: mod_proxy to canonicalize rewritten [P] URLs, + including "unix:" ones. PR 69235, PR 69260. [Yann Ylavic, Ruediger Pluem] + + *) mod_rewrite: Error out in case a RewriteRule in directory context uses the + proxy, but mod_proxy is not loaded. PR 56264. + [Christophe Jaillet, Michael Streeter ] + *) http: Remove support for Request-Range header sent by Navigator 2-3 and MSIE 3. [Stefan Fritsch] diff --git a/STATUS b/STATUS index a6474ce1af..e505ea4591 100644 --- a/STATUS +++ b/STATUS @@ -165,18 +165,6 @@ RELEASE SHOWSTOPPERS: PATCHES ACCEPTED TO BACKPORT FROM TRUNK: [ start all new proposals below, under PATCHES PROPOSED. ] - *) mod_rewrite, mod_proxy: mod_proxy to cononicalize rewritten [P] URLs, - including "unix:" ones. PR 69235, PR 69260, PR 56264 - Trunk version of patch: - https://svn.apache.org/r1838684 - https://svn.apache.org/r1920570 - https://svn.apache.org/r1920571 - https://svn.apache.org/r1920572 - Backport version for 2.4.x of patch: - https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/484.diff - Can be applied via apply_backport_pr.sh 484 - +1: rpluem, ylavic, covener - *) mod_ssl: Fix regression in PKCS#11 handling which should work without SSLCryptoDevice configured trunk patch: https://svn.apache.org/r1920597 diff --git a/modules/mappers/mod_rewrite.c b/modules/mappers/mod_rewrite.c index 0bf4404923..93430e5952 100644 --- a/modules/mappers/mod_rewrite.c +++ b/modules/mappers/mod_rewrite.c @@ -4515,20 +4515,6 @@ static rule_return_type apply_rewrite_rule(rewriterule_entry *p, * ourself). */ if (p->flags & RULEFLAG_PROXY) { - /* For rules evaluated in server context, the mod_proxy fixup - * hook can be relied upon to escape the URI as and when - * necessary, since it occurs later. If in directory context, - * the ordering of the fixup hooks is forced such that - * mod_proxy comes first, so the URI must be escaped here - * instead. See PR 39746, 46428, and other headaches. */ - if (ctx->perdir && (p->flags & RULEFLAG_NOESCAPE) == 0) { - char *old_filename = r->filename; - - r->filename = ap_escape_uri(r->pool, r->filename); - rewritelog(r, 2, ctx->perdir, "escaped URI in per-dir context " - "for proxy, %s -> %s", old_filename, r->filename); - } - fully_qualify_uri(r); rewritelog(r, 2, ctx->perdir, "forcing proxy-throughput with %s", @@ -5051,7 +5037,7 @@ static int hook_uri2file(request_rec *r) } if ((r->args != NULL) && ((r->proxyreq == PROXYREQ_PROXY) - || (rulestatus == ACTION_NOESCAPE))) { + || apr_table_get(r->notes, "proxy-nocanon"))) { /* see proxy_http:proxy_http_canon() */ r->filename = apr_pstrcat(r->pool, r->filename, "?", r->args, NULL); @@ -5342,13 +5328,28 @@ static int hook_fixup(request_rec *r) if (to_proxyreq) { /* it should go on as an internal proxy request */ - /* make sure the QUERY_STRING and - * PATH_INFO parts get incorporated + /* check if the proxy module is enabled, so + * we can actually use it! + */ + if (!proxy_available) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10160) + "attempt to make remote request from mod_rewrite " + "without proxy enabled: %s", r->filename); + return HTTP_FORBIDDEN; + } + + if (rulestatus == ACTION_NOESCAPE) { + apr_table_setn(r->notes, "proxy-nocanon", "1"); + } + + /* make sure the QUERY_STRING gets incorporated in the case + * [NE] was specified on the Proxy rule. We are preventing + * mod_proxy canon handler from incorporating r->args as well + * as escaping the URL. * (r->path_info was already appended by the * rewriting engine because of the per-dir context!) */ - if (r->args != NULL) { - /* see proxy_http:proxy_http_canon() */ + if ((r->args != NULL) && apr_table_get(r->notes, "proxy-nocanon")) { r->filename = apr_pstrcat(r->pool, r->filename, "?", r->args, NULL); } @@ -5648,10 +5649,7 @@ static void ap_register_rewrite_mapfunc(char *name, rewrite_mapfunc_t *func) static void register_hooks(apr_pool_t *p) { - /* fixup after mod_proxy, so that the proxied url will not - * escaped accidentally by mod_proxy's fixup. - */ - static const char * const aszPre[]={ "mod_proxy.c", NULL }; + static const char * const aszModProxy[] = { "mod_proxy.c", NULL }; /* make the hashtable before registering the function, so that * other modules are prevented from accessing uninitialized memory. @@ -5663,10 +5661,12 @@ static void register_hooks(apr_pool_t *p) ap_hook_pre_config(pre_config, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_post_config(post_config, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_child_init(init_child, NULL, NULL, APR_HOOK_MIDDLE); - - ap_hook_fixups(hook_fixup, aszPre, NULL, APR_HOOK_FIRST); + + /* allow to change the uri before mod_proxy takes over it */ + ap_hook_translate_name(hook_uri2file, NULL, aszModProxy, APR_HOOK_FIRST); + /* fixup before mod_proxy so that a [P] URL gets fixed up there */ + ap_hook_fixups(hook_fixup, NULL, aszModProxy, APR_HOOK_FIRST); ap_hook_fixups(hook_mimetype, NULL, NULL, APR_HOOK_LAST); - ap_hook_translate_name(hook_uri2file, NULL, NULL, APR_HOOK_FIRST); } /* the main config structure */ diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c index 756c41c4a1..ab29c321df 100644 --- a/modules/proxy/mod_proxy.c +++ b/modules/proxy/mod_proxy.c @@ -3347,27 +3347,26 @@ static int proxy_pre_config(apr_pool_t *pconf, apr_pool_t *plog, } static void register_hooks(apr_pool_t *p) { - /* fixup before mod_rewrite, so that the proxied url will not - * escaped accidentally by our fixup. - */ - static const char * const aszSucc[] = { "mod_rewrite.c", NULL}; /* Only the mpm_winnt has child init hook handler. * make sure that we are called after the mpm * initializes. */ static const char *const aszPred[] = { "mpm_winnt.c", "mod_proxy_balancer.c", "mod_proxy_hcheck.c", NULL}; + static const char * const aszModRewrite[] = { "mod_rewrite.c", NULL }; + /* handler */ ap_hook_handler(proxy_handler, NULL, NULL, APR_HOOK_FIRST); /* filename-to-URI translation */ ap_hook_pre_translate_name(proxy_pre_translate_name, NULL, NULL, APR_HOOK_MIDDLE); - ap_hook_translate_name(proxy_translate_name, aszSucc, NULL, + /* mod_rewrite has a say on the uri before proxy translation */ + ap_hook_translate_name(proxy_translate_name, aszModRewrite, NULL, APR_HOOK_FIRST); /* walk entries and suppress default TRACE behavior */ ap_hook_map_to_storage(proxy_map_location, NULL,NULL, APR_HOOK_FIRST); - /* fixups */ - ap_hook_fixups(proxy_fixup, NULL, aszSucc, APR_HOOK_FIRST); + /* fixup after mod_rewrite so that a [P] URL from there gets fixed up */ + ap_hook_fixups(proxy_fixup, aszModRewrite, NULL, APR_HOOK_FIRST); /* post read_request handling */ ap_hook_post_read_request(proxy_detect, NULL, NULL, APR_HOOK_FIRST); /* pre config handling */ From be19b272f1154e93725d8d138c1fc1aeccae2e64 Mon Sep 17 00:00:00 2001 From: Joe Orton Date: Tue, 15 Oct 2024 11:33:02 +0000 Subject: [PATCH 083/176] Merge r1921311 from trunk: [RTC exception for CI] CI: Use the image version in the cache keys. This is likely a simpler and more robust fix for the issues with Perl XS builds being cached. Root cause was likely "ubuntu-latest" changing from 22.04 to 24.04. Cache keys will now change when that happens again, preventing reuse of cached builds across OS versions. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1921330 13f79535-47bb-0310-9956-ffa450edef68 --- .github/workflows/linux.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 69c3fd380c..592002ca99 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -247,10 +247,14 @@ jobs: CONFIG: ${{ matrix.config }} name: ${{ matrix.name }} steps: + # JOBID is used in the cache keys, created here as a hash of all + # properties of the environment, including the image OS version, + # compiler flags and any job-specific properties. - name: Set environment variables run: | echo "${{ matrix.env }}" >> $GITHUB_ENV - echo JOBID=`echo "${{ matrix.notest-cflags }} ${{ matrix.env }} ${{ matrix.config }}'"| md5sum - | sed 's/ .*//'` >> $GITHUB_ENV + echo JOBID=`echo "OS=$ImageOS ${{ matrix.notest-cflags }} ${{ matrix.env }} ${{ matrix.config }}" \ + | md5sum - | sed 's/ .*//'` >> $GITHUB_ENV # https://github.com/actions/runner-images/issues/9491#issuecomment-1989718917 - name: Workaround ASAN issue in Ubuntu 22.04 run: sudo sysctl vm.mmap_rnd_bits=28 From f5a68b69eb19fbf1ede868710cb0c18a2a77a097 Mon Sep 17 00:00:00 2001 From: Yann Ylavic Date: Fri, 18 Oct 2024 12:58:05 +0000 Subject: [PATCH 084/176] Document the %{cuz}t and %{}t time formats for ErrorLogFormat. ErrorLogFormat %{c}t is actually what ISO 8601 calls "extended" format. Improve ErrorLogFormat's %{cuz}t and %{%-format}t descriptions. Merges r1921257, r1921259, r1921399 from trunk [docs CTR, available since 2.4.58] git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1921401 13f79535-47bb-0310-9956-ffa450edef68 --- docs/manual/mod/core.xml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/manual/mod/core.xml b/docs/manual/mod/core.xml index fc7731b14d..a4239d5a65 100644 --- a/docs/manual/mod/core.xml +++ b/docs/manual/mod/core.xml @@ -1737,9 +1737,18 @@ ErrorLogFormat "[%t] [%l] [pid %P] %F: %E: [client %a] %M"

    The current time including micro-seconds
    %{cu}tThe current time in compact ISO 8601 format, including + The current time in ISO 8601 extended format (compact), including micro-seconds
    %{cuz}tThe current time in ISO 8601 extended format (compact), including + micro-seconds and time zone in the ISO 8601:2000 standard format. + Available since 2.4.58 only
    %{%-format}tThe current time formatted per the strftime(3) function. + Available since 2.4.58 only
    %v The canonical ServerName of the current server.
    - - - -
    Description:TLS v1.2 and v1.3 implemented in memory-safe Rust via - the rustls library -
    Status:Experimental
    Module Identifier:tls_module
    Source File:mod_tls.c
    Compatibility:Available in version 2.4.52 and later
    -

    Summary

    - -

    - mod_tls is an alternative to mod_ssl for providing https to a server. - It's feature set is a subset, described in more detail below. It can - be used as a companion to mod_ssl, e.g. both modules can be loaded at - the same time. -

    - mod_tls, being written in C, used the Rust implementation of TLS named - rustls via its C interface - rustls-ffi. This gives - memory safe cryptography and protocol handling at comparable - performance. -

    - It can be configured for frontend and backend connections. The configuration - directive have been kept mostly similar to mod_ssl ones. -

    -
    - -
    top
    -
    -

    TLS in a VirtualHost context

    - -
    Listen 443
    -TLSEngine 443
    -
    -<VirtualHost *:443>
    -  ServerName example.net
    -  TLSCertificate file_with_certificate.pem file_with_key.pem
    -  ...
    -</VirtualHost>
    - -

    - The above is a minimal configuration. Instead of enabling mod_tls - in every virtual host, the port for incoming TLS connections is - specified. -

    - You cannot mix virtual hosts with mod_ssl and mod_tls on the same - port. It's either or. SNI and ALPN are supported. You may use several - virtual hosts on the same port and a mix of protocols like http/1.1 - and h2. -

    -
    top
    -
    -

    Feature Comparison with mod_ssl

    -

    - The table below gives a comparison of feature between - mod_ssl and mod_tls. If a feature of mod_ssl is no listed here, - it is not supported by mod_tls. The one difference, probably most relevant - is the lack for client certificate support in the current version of - mod_tls. -

    - - - - - - - - - - - - - - - - - - - - - - - -
    Featuremod_sslmod_tlsComment
    Frontend TLSyesyes
    Backend TLSyesyes
    TLS v1.3yes*yes*)with recent OpenSSL
    TLS v1.2yesyes
    TLS v1.0yes*no*)if enabled in OpenSSL
    SNI Virtual Hostsyesyes
    Client Certificatesyesno
    Machine Certificates for Backendyesyes
    OCSP Staplingyesyes**)via mod_md
    Backend OCSP checkyesno**)stapling will be verified
    TLS version to allowmin-maxmin
    TLS ciphersexclusive listpreferred/suppressed
    TLS cipher orderingclient/serverclient/server
    TLS sessionsyesyes
    SNI strictnessdefault nodefault yes
    Option EnvVarsexhaustivelimited**)see var list
    Option ExportCertDataclient+serverserver
    Backend CAfile/dirfile
    Revocation CRLsyesno
    TLS Renegotiationyes*no*)in TLS v1.2
    Encrypted Cert Keysyesno
    -

    -

    -
    top
    -
    -

    TLS Protocols

    -

    - mod_tls supports TLS protocol version 1.2 and 1.3. Should there ever be - a version 1.4 and rustls supports it, it will be available as well. -

    -

    - In mod_tls, you configure the minimum version to use, never the maximum: -

    -
    TLSProtocol TLSv1.3+
    - -

    - This allows only version 1.3 and whatever may be its successor one day when talking - to your server or to a particular virtual host. -

    -
    top
    -
    -

    TLS Ciphers

    -

    - The list of TLS ciphers supported in the rustls library, - can be found here. All TLS v1.3 - ciphers are supported. For TLS v1.2, only ciphers that rustls considers - secure are available. -

    - mod_tls supports the following names for TLS ciphers: -

    -
      -
    1. - The IANA assigned name - which uses `_` to separate parts. Example: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 -
    2. -
    3. - The OpenSSL name, using `-` as separator (for 1.2). Example: ECDHE-ECDSA-AES256-SHA384. - Such names often appear in documentation. `mod_tls` defines them for all TLS v1.2 ciphers. - For TLS v1.3 ciphers, names starting with TLS13_ are also supported. -
    4. -
    5. - The IANA assigned identifier, - which is a 16-bit numeric value. Example: 0xc024. - You can use this in configurations as TLS_CIPHER_0xc024. -
    6. -
    -

    - You can configure a preference for ciphers, which means they will be used - for clients that support them. If you do not configure a preference, rustls - will use the one that it considers best. This is recommended. -

    -

    - Should you nevertheless have the need to prefer one cipher over another, you - may configure it like this: -

    -
    TLSCiphersPrefer ECDHE-ECDSA-AES256-SHA384
    -# or several
    -TLSCiphersPrefer ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305
    - -

    - If you name a cipher that is unknown, the configuration will fail. - If you name a cipher is not supported by rustls (or no - longer supported in an updated version of rustls for security - reasons), mod_tls will log a WARNING, but continue to work. -

    -

    - A similar mechanism exists, if you want to disable a particular cipher: -

    -
    TLSCipherSuppress ECDHE-ECDSA-AES256-SHA384
    - -

    - A suppressed cipher will not longer be used. - If you name a cipher that is unknown, the configuration will fail. - If you name a cipher is not supported by rustls (or no - longer supported in an updated version of rustls for security - reasons), mod_tls will log a WARNING, but continue to work. -

    -
    top
    -
    -

    Virtual Hosts

    -

    - mod_tls uses the SNI (Server Name Indicator) to select one of the - configured virtual hosts that match the port being served. Should - the client not provide an SNI, the first configured - virtual host will be selected. If the client does provide - an SNI (as all today's clients do), it must match one - virtual host (ServerName or - ServerAlias) - or the connection will fail. -

    -

    - As with mod_ssl, you may specify ciphers and protocol - versions for the base server (global) and/or individual virtual hosts - that are selected via SNI by the client. -

    -
    Listen 443
    -TLSEngine 443
    -
    -<VirtualHost *:443>
    -  ServerName example1.net
    -  TLSCertificate example1-cert.pem
    -  ...
    -</VirtualHost>
    -
    -<VirtualHost *:443>
    -  ServerName example2.net
    -  TLSCertificate example2-cert.pem
    -  ...
    -  TLSProtocol v1.3+
    -</VirtualHost>
    - -

    - The example above show different TLS settings for virtual hosts on the - same port. This is supported. example1 can be contacted via - all TLS versions and example2 only allows v1.3 or later. -

    -
    top
    -
    -

    ACME Certificates

    -

    - ACME certificates via mod_md are supported, just as - for mod_ssl. A minimal configuration: -

    -
    Listen 443
    -TLSEngine 443
    -MDomain example.net
    -
    -<VirtualHost *:443>
    -  ServerName example.net
    -  ...
    -</VirtualHost>
    - -
    top
    -
    -

    OCSP Stapling

    -

    - mod_tls has no own implementation to retrieve OCSP information for - a certificate. However, it will use such for Stapling if it is provided - by mod_md. See mod_md's documentation - on how to enable this. -

    -
    top
    -
    -

    TLS Variables

    -

    - Via the directive TLSOptions, several variables - are placed into the environment of requests and can be inspected, for - example in a CGI script. -

    -

    - The variable names are given by mod_ssl. Note that these - are only a subset of the many variables that mod_ssl exposes. -

    - - - - - - - - - - - - - -
    VariableTLSOptionDescription
    SSL_TLS_SNI*the server name indicator (SNI) send by the client
    SSL_PROTOCOL*the TLS protocol negotiated
    SSL_CIPHER*the name of the TLS cipher negotiated
    SSL_VERSION_INTERFACEStdEnvVarsthe module version
    SSL_VERSION_LIBRARYStdEnvVarsthe rustls-ffi version
    SSL_SECURE_RENEGStdEnvVarsalways `false`
    SSL_COMPRESS_METHODStdEnvVarsalways `false`
    SSL_CIPHER_EXPORTStdEnvVarsalways `false`
    SSL_CLIENT_VERIFYStdEnvVarsalways `false`
    SSL_SESSION_RESUMEDStdEnvVarseither `Resumed` if a known TLS session id was presented by the client or `Initial` otherwise
    SSL_SERVER_CERTExportCertDatathe selected server certificate in PEM format
    -

    - The variable SSL_SESSION_ID is intentionally not supported as - it contains sensitive information. -

    -
    top
    -
    -

    Client Certificates

    -

    - While rustls supports client certificates in principle, parts - of the infrastructure to make use of these in a server are not - offered. -

    -

    - Among these features are: revocation lists, inspection of certificate - extensions and the matched issuer chain for OCSP validation. Without these, - revocation of client certificates is not possible. Offering authentication - without revocation is not considered an option. -

    -

    - Work will continue on this and client certificate support may become - available in a future release. -

    -
    -
    top
    -

    TLSCertificate Directive

    - - - - - - -
    Description:adds a certificate and key (PEM encoded) to a server/virtual host.
    Syntax:TLSCertificate cert_file [key_file]
    Context:server config, virtual host
    Status:Experimental
    Module:mod_tls
    -

    - If you do not specify a separate key file, the key is assumed to also be - found in the first file. You may add more than one certificate to a - server/virtual host. The first certificate suitable for a client is then chosen. -

    - The path can be specified relative to the server root. -

    - -
    -
    top
    -

    TLSCiphersPrefer Directive

    - - - - - - -
    Description:defines ciphers that are preferred.
    Syntax:TLSCiphersPrefer cipher(-list)
    Context:server config, virtual host
    Status:Experimental
    Module:mod_tls
    -

    - This will not disable any ciphers supported by `rustls`. If you - specify a cipher that is completely unknown, the configuration will - fail. If you specify a cipher that is known but not supported by `rustls`, - a warning will be logged but the server will continue. -

    -

    -

    Example

    TLSCiphersPrefer ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305
    -
    -

    - The example gives 2 ciphers preference over others, in the - order they are mentioned. -

    - -
    -
    top
    -

    TLSCiphersSuppress Directive

    - - - - - - -
    Description:defines ciphers that are not to be used.
    Syntax:TLSCiphersSuppress cipher(-list)
    Context:server config, virtual host
    Status:Experimental
    Module:mod_tls
    -

    - This will not disable any unmentioned ciphers supported by `rustls`. - If you specify a cipher that is completely unknown, the configuration will fail. - If you specify a cipher that is known but not supported by `rustls`, - a warning will be logged but the server will continue. -

    -

    -

    Example

    TLSCiphersSuppress ECDHE-ECDSA-CHACHA20-POLY1305
    -
    -

    - The example removes a cipher for use in connections. -

    - -
    -
    top
    -

    TLSEngine Directive

    - - - - - - -
    Description:defines on which address+port the module shall handle incoming connections.
    Syntax:TLSEngine [address:]port
    Context:server config
    Status:Experimental
    Module:mod_tls
    -

    - This is set on a global level, not in individual <VirtualHost>s. - It will affect all <VirtualHost> - that match the specified address/port. - You can use TLSEngine several times to use more than one address/port. -

    -

    -

    Example

    TLSEngine 443
    -
    -

    - The example tells mod_tls to handle incoming connection on port 443 for - all listeners. -

    - -
    -
    top
    -

    TLSHonorClientOrder Directive

    - - - - - - - -
    Description:determines if the order of ciphers supported by the client is honored
    Syntax:TLSHonorClientOrder on|off
    Default:TLSHonorClientOrder on
    Context:server config, virtual host
    Status:Experimental
    Module:mod_tls
    -

    - TLSHonorClientOrder determines if the order of ciphers - supported by the client is honored. -

    -

    - -
    -
    top
    -

    TLSOptions Directive

    - - - - - - -
    Description:enables SSL variables for requests.
    Syntax:TLSOptions [+|-]option
    Context:server config, virtual host, directory, .htaccess
    Status:Experimental
    Module:mod_tls
    -

    - TLSOptions is analog to SSLOptions in mod_ssl. - It can be set per directory/location and `option` can be: -

    -
      -
    • `StdEnvVars`: adds more variables to the requests environment, - as forwarded for example to CGI processing and other applications. -
    • -
    • `ExportCertData`: adds certificate related variables to the request environment. -
    • -
    • `Defaults`: resets all options to their default values.
    • -
    -

    - Adding variables to a request environment adds overhead, especially - when certificates need to be inspected and fields extracted. - Therefore most variables are not set by default. -

    -

    - You can configure TLSOptions per location or generally on a - server/virtual host. Prefixing an option with `-` disables this - option while leaving others unchanged. - A `+` prefix is the same as writing the option without one. -

    -

    - The `Defaults` value can be used to reset any options that are - inherited from other locations or the virtual host/server. -

    -

    Example

    <Location /myplace/app>
    -  TLSOptions Defaults StdEnvVars
    -  ...
    -</Location>
    -
    - -
    -
    top
    -

    TLSProtocol Directive

    - - - - - - - -
    Description:specifies the minimum version of the TLS protocol to use.
    Syntax:TLSProtocol version+
    Default:TLSProtocol v1.2+
    Context:server config, virtual host
    Status:Experimental
    Module:mod_tls
    -

    - The default is `v1.2+`. Settings this to `v1.3+` would disable TLSv1.2. -

    - -
    -
    top
    -

    TLSProxyCA Directive

    - - - - - - -
    Description:sets the root certificates to validate the backend server with.
    Syntax:TLSProxyCA file.pem
    Context:server config, virtual host, proxy section
    Status:Experimental
    Module:mod_tls
    -

    - -

    - -
    -
    top
    -

    TLSProxyCiphersPrefer Directive

    - - - - - - -
    Description:defines ciphers that are preferred for a proxy connection.
    Syntax:TLSProxyCiphersPrefer cipher(-list)
    Context:server config, virtual host, proxy section
    Status:Experimental
    Module:mod_tls
    -

    - This will not disable any ciphers supported by `rustls`. - If you specify a cipher that is completely unknown, the configuration will fail. - If you specify a cipher that is known but not supported by `rustls`, - a warning will be logged but the server will continue. -

    - -
    -
    top
    -

    TLSProxyCiphersSuppress Directive

    - - - - - - -
    Description:defines ciphers that are not to be used for a proxy connection.
    Syntax:TLSProxyCiphersSuppress cipher(-list)
    Context:server config, virtual host, proxy section
    Status:Experimental
    Module:mod_tls
    -

    - This will not disable any unmentioned ciphers supported by `rustls`. - If you specify a cipher that is completely unknown, the configuration will fail. - If you specify a cipher that is known but not supported by `rustls`, - a warning will be logged but the server will continue. -

    - -
    -
    top
    -

    TLSProxyEngine Directive

    - - - - - - -
    Description:enables TLS for backend connections.
    Syntax:TLSProxyEngine on|off
    Context:server config, virtual host, proxy section
    Status:Experimental
    Module:mod_tls
    -

    - TLSProxyEngine is analog to SSLProxyEngine in mod_ssl. -

    - This can be used in a server/virtual host or <Proxy> section to - enable the module for outgoing connections using mod_proxy. -

    - -
    -
    top
    -

    TLSProxyMachineCertificate Directive

    - - - - - - -
    Description:adds a certificate and key file (PEM encoded) to a proxy setup.
    Syntax:TLSProxyMachineCertificate cert_file [key_file]
    Context:server config, virtual host, proxy section
    Status:Experimental
    Module:mod_tls
    -

    - The certificate is used to authenticate against a proxied backend server. -

    - If you do not specify a separate key file, the key is assumed to also be - found in the first file. You may add more than one certificate to a proxy - setup. The first certificate suitable for a proxy connection to a backend - is then chosen by rustls. -

    -

    - The path can be specified relative to the server root. -

    - -
    -
    top
    -

    TLSProxyProtocol Directive

    - - - - - - - -
    Description:specifies the minimum version of the TLS protocol to use in proxy connections.
    Syntax:TLSProxyProtocol version+
    Default:TLSProxyProtocol v1.2+
    Context:server config, virtual host, proxy section
    Status:Experimental
    Module:mod_tls
    -

    - The default is `v1.2+`. Settings this to `v1.3+` would disable TLSv1.2. -

    - -
    -
    top
    -

    TLSSessionCache Directive

    - - - - - - -
    Description:specifies the cache for TLS session resumption.
    Syntax:TLSSessionCache cache-spec
    Context:server config
    Status:Experimental
    Module:mod_tls
    -

    - This uses a cache on the server side to allow clients to resume connections. -

    - You can set this to `none` or define a cache as in the SSLSessionCache - directive of mod_ssl. -

    - If not configured, `mod_tls` will try to create a shared memory cache on its own, - using `shmcb:tls/session-cache` as specification. - Should that fail, a warning is logged, but the server continues. -

    - -
    -
    top
    -

    TLSStrictSNI Directive

    - - - - - - - -
    Description:enforces exact matches of client server indicators (SNI) against host names.
    Syntax:TLSStrictSNI on|off
    Default:TLSStrictSNI on
    Context:server config
    Status:Experimental
    Module:mod_tls
    -

    - Client connections using SNI will be unsuccessful if no match is found. -

    - -
    -
    -
    -

    Available Languages:  en 

    -
    top

    Comments

    Notice:
    This is not a Q&A section. Comments placed here should be pointed towards suggestions on improving the documentation or server, and may be removed by our moderators if they are either implemented or considered invalid/off-topic. Questions on how to manage the Apache HTTP Server should be directed at either our IRC channel, #httpd, on Libera.chat, or sent to our mailing lists.
    -
    - \ No newline at end of file diff --git a/docs/manual/mod/mod_tls.xml.meta b/docs/manual/mod/mod_tls.xml.meta deleted file mode 100644 index 321d1ad732..0000000000 --- a/docs/manual/mod/mod_tls.xml.meta +++ /dev/null @@ -1,12 +0,0 @@ - - - - - mod_tls - /mod/ - .. - - - en - - From f45abec1bd20396cea777a411bd5975abefad279 Mon Sep 17 00:00:00 2001 From: Yann Ylavic Date: Fri, 18 Oct 2024 13:21:27 +0000 Subject: [PATCH 086/176] xforms git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1921404 13f79535-47bb-0310-9956-ffa450edef68 --- docs/manual/mod/core.html.en | 9 ++++++++- docs/manual/mod/core.html.fr.utf8 | 2 ++ docs/manual/mod/core.xml.de | 2 +- docs/manual/mod/core.xml.es | 2 +- docs/manual/mod/core.xml.fr | 2 +- docs/manual/mod/core.xml.ja | 2 +- docs/manual/mod/core.xml.meta | 2 +- docs/manual/mod/core.xml.tr | 2 +- 8 files changed, 16 insertions(+), 7 deletions(-) diff --git a/docs/manual/mod/core.html.en b/docs/manual/mod/core.html.en index f5efca3f01..de76a39ad3 100644 --- a/docs/manual/mod/core.html.en +++ b/docs/manual/mod/core.html.en @@ -1633,8 +1633,15 @@ ErrorLogFormat "[%t] [%l] [pid %P] %F: %E: [client %a] %M" %{u}t The current time including micro-seconds %{cu}t - The current time in compact ISO 8601 format, including + The current time in ISO 8601 extended format (compact), including micro-seconds +%{cuz}t + The current time in ISO 8601 extended format (compact), including + micro-seconds and time zone in the ISO 8601:2000 standard format. + Available since 2.4.58 only +%{%-format}t + The current time formatted per the strftime(3) function. + Available since 2.4.58 only %v The canonical ServerName of the current server. diff --git a/docs/manual/mod/core.html.fr.utf8 b/docs/manual/mod/core.html.fr.utf8 index cc7a612493..aae55fe4c4 100644 --- a/docs/manual/mod/core.html.fr.utf8 +++ b/docs/manual/mod/core.html.fr.utf8 @@ -33,6 +33,8 @@  ja  |  tr 

    +
    Cette traduction peut être périmée. Vérifiez la version + anglaise pour les changements récents.
    Description:Fonctionnalités de base du serveur HTTP Apache toujours disponibles
    Statut:Noyau httpd
    diff --git a/docs/manual/mod/core.xml.de b/docs/manual/mod/core.xml.de index 7345dc100a..0c05b71119 100644 --- a/docs/manual/mod/core.xml.de +++ b/docs/manual/mod/core.xml.de @@ -1,7 +1,7 @@ - + + + diff --git a/docs/manual/mod/core.xml.ja b/docs/manual/mod/core.xml.ja index 6307573b32..7a4e82a6ea 100644 --- a/docs/manual/mod/core.xml.ja +++ b/docs/manual/mod/core.xml.ja @@ -1,7 +1,7 @@ - + + + @@ -1888,9 +1888,19 @@ ErrorLogFormat "[%t] [%l] [pid %P] %F: %E: [client %a] %M" L'heure courante avec les microsecondes %{cu}t - L'heure courante au format compact ISO 8601, avec les + L'heure courante au format ISO 8601 étendu (compact), avec les microsecondes + %{cuz}t + L'heure actuelle au format ISO 8601 étendu (compact), avec les + microsecondes et la zone horaire au format standard ISO 8601:2000. + Disponible depuis la version 2.4.58 seulement + + %{%-format}t + L'heure actuelle formatée selon la fonction + strftime(3). Disponible depuis la version 2.4.58 + seulement + %v Le nom de serveur canonique ServerName du serveur courant. From 01a2aec6c7306f4c7fae7b58a7be3b041d183053 Mon Sep 17 00:00:00 2001 From: Lucien Gentis Date: Sat, 19 Oct 2024 09:51:47 +0000 Subject: [PATCH 088/176] fr doc rebuild. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1921419 13f79535-47bb-0310-9956-ffa450edef68 --- docs/manual/dso.html.fr.utf8 | 32 ++++++++-------- docs/manual/env.html.fr.utf8 | 64 +++++++++++++++---------------- docs/manual/mod/core.html.fr.utf8 | 12 ++++-- docs/manual/mod/core.xml.meta | 2 +- 4 files changed, 58 insertions(+), 52 deletions(-) diff --git a/docs/manual/dso.html.fr.utf8 b/docs/manual/dso.html.fr.utf8 index 39bb753704..0d7d0f613f 100644 --- a/docs/manual/dso.html.fr.utf8 +++ b/docs/manual/dso.html.fr.utf8 @@ -7,7 +7,7 @@ This file is generated from xml source: DO NOT EDIT XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX --> -Support des objets dynamiques partagés (DSO) - Serveur HTTP Apache Version 2.4 +Prise en charge des objets dynamiques partagés (DSO) - Serveur HTTP Apache Version 2.4 @@ -21,7 +21,7 @@
    <-

    Support des objets dynamiques partagés (DSO)

    +Apache > Serveur HTTP > Documentation > Version 2.4

    Prise en charge des objets dynamiques partagés (DSO)

    Langues Disponibles:  en  |  fr  | @@ -57,7 +57,7 @@ -

    Le support DSO pour le chargement de modules individuels d'Apache +

    La prise en charge de DSO pour le chargement de modules individuels d'Apache httpd est assuré par un module nommé mod_so qui doit être compilé statiquement dans le coeur d'Apache httpd. Il s'agit du seul module avec le @@ -68,7 +68,7 @@ module peut être chargé en mémoire au démarrage ou redémarrage du serveur à l'aide de la directive LoadModule du module - mod_so, placée + mod_so placée dans votre fichier httpd.conf.

    La compilation en mode DSO peut être désactivée pour certains modules via l'option --enable-mods-static du script @@ -84,11 +84,11 @@ du script configure installe les fichiers d'en-têtes d'Apache httpd et positionne, pour la plateforme de compilation, les drapeaux du compilateur et de l'éditeur de liens à l'intérieur du programme - apxs, qui sera utilisé pour la construction de fichiers DSO. + apxs qui sera utilisé pour la construction de fichiers DSO. Il est ainsi possible d'utiliser le programme apxs pour compiler ses sources de modules Apache httpd sans avoir besoin de l'arborescence des sources de la distribution d'Apache, et sans avoir à - régler les drapeaux du compilateur et de l'éditeur de liens pour le support DSO.

    + régler les drapeaux du compilateur et de l'éditeur de liens pour la prise en charge de DSO.

    top

    Mode d'emploi succinct

    @@ -109,7 +109,7 @@ $ make install
  • -

    Configure le serveur HTTP Apache avec tous les modules +

    Configurer le serveur HTTP Apache avec tous les modules activés. Seul un jeu de modules de base sera chargé au démarrage du serveur. Vous pouvez modifier ce jeu de modules chargés au démarrage en activant ou désactivant les directives LoadModule correspondantes dans le @@ -164,7 +164,7 @@ $ apxs -cia mod_foo.c

    Les dessous du fonctionnement des DSO

    -

    Les clônes modernes d'UNIX proposent un mécanisme +

    Les clones modernes d'UNIX proposent un mécanisme appelé édition de liens et chargement dynamiques d' Objets Dynamiques Partagés (DSO), qui permet de construire un morceau de programme dans un format spécial pour le rendre chargeable @@ -173,7 +173,7 @@ $ apxs -cia mod_foo.c

    Ce chargement peut s'effectuer de deux manières : automatiquement par un programme système appelé ld.so quand un programme exécutable est démarré, ou manuellement à partir du programme en cours - d'exécution via sa propre interface système vers le chargeur Unix à l'aide + d'exécution à l’aide de sa propre interface système vers le chargeur Unix à l'aide des appels système dlopen()/dlsym().

    Dans la première méthode, les DSO sont en général appelés @@ -184,7 +184,7 @@ $ apxs -cia mod_foo.c et le lien avec le programme exécutable est établi à la compilation en ajoutant -lfoo à la commande de l'éditeur de liens. Les références à la bibliothèque sont ainsi codées en dur dans le fichier du - programme exécutable de façon à ce qu'au démarrage du programme, le + programme exécutable de façon qu'au démarrage du programme, le chargeur Unix soit capable de localiser libfoo.so dans /usr/lib, dans des chemins codés en dur à l'aide d'options de l'éditeur de liens comme -R ou dans des chemins définis par la @@ -228,7 +228,7 @@ $ apxs -cia mod_foo.c

    Finalement, pour tirer profit de l'API des DSO, le programme exécutable doit résoudre certains symboles du DSO à l'aide de l'appel système dlsym() pour une utilisation ultérieure dans les tables de - distribution, etc... En d'autres termes, le programme exécutable doit + distribution, etc. En d'autres termes, le programme exécutable doit résoudre manuellement tous les symboles dont il a besoin pour pouvoir les utiliser. Avantage d'un tel mécanisme : les modules optionnels du programme n'ont pas @@ -240,8 +240,8 @@ $ apxs -cia mod_foo.c

    Bien que ce mécanisme DSO paraisse évident, il comporte au moins une étape difficile : la résolution des symboles depuis le programme exécutable pour le DSO lorsqu'on utilise un DSO pour étendre les fonctionnalités d'un - programme (la seconde méthode). Pourquoi ? Parce que la "résolution - inverse" des symboles DSO à partir du jeu de symboles du programme + programme (la seconde méthode). Pourquoi ? Parce que la « résolution + inverse » des symboles DSO à partir du jeu de symboles du programme exécutable dépend de la conception de la bibliothèque (la bibliothèque n'a aucune information sur le programme qui l'utilise) et n'est ni standardisée ni disponible sur toutes les plateformes. En pratique, les symboles globaux @@ -272,7 +272,7 @@ $ apxs -cia mod_foo.c configure à la compilation. Par exemple, on peut ainsi exécuter différentes instances du serveur (standard et version SSL, version minimale et version dynamique - [mod_perl, mod_php], etc...) à partir d'une seule installation + [mod_perl, mod_php], etc.) à partir d'une seule installation d'Apache httpd.

  • Le paquetage du serveur peut être facilement étendu avec des modules @@ -280,7 +280,7 @@ $ apxs -cia mod_foo.c avantage pour les mainteneurs de paquetages destinés aux distributions, car ils peuvent créer un paquetage Apache httpd de base, et des paquetages additionnels contenant des extensions telles que PHP, mod_perl, mod_fastcgi, - etc...
  • + etc.
  • Une facilité de prototypage des modules Apache httpd, car la paire DSO/apxs vous permet d'une part de travailler en @@ -319,7 +319,7 @@ $ apxs -cia mod_foo.c position (PIC). Il y a deux solutions pour utiliser un autre type de code : soit le coeur d'Apache httpd contient déjà lui-même une référence au code, soit vous - chargez le code vous-même via dlopen().
  • + chargez le code vous-même à l’aide de dlopen().
    diff --git a/docs/manual/env.html.fr.utf8 b/docs/manual/env.html.fr.utf8 index 71cb0e19ec..e11796e6eb 100644 --- a/docs/manual/env.html.fr.utf8 +++ b/docs/manual/env.html.fr.utf8 @@ -7,7 +7,7 @@ This file is generated from xml source: DO NOT EDIT XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX --> -Apache et les variables d'environnement - Serveur HTTP Apache Version 2.4 +Apache httpd et les variables d'environnement - Serveur HTTP Apache Version 2.4 @@ -21,7 +21,7 @@
    <-

    Apache et les variables d'environnement

    +Apache > Serveur HTTP > Documentation > Version 2.4

    Apache httpd et les variables d'environnement

    Langues Disponibles:  en  |  fr  | @@ -37,7 +37,7 @@ contrôlées par le système d'exploitation sous-jacent et définies avant le démarrage du serveur. Leurs valeurs peuvent être utilisées directement dans les fichiers de configuration, et peuvent - éventuellement être transmises aux scripts CGI et SSI via la + éventuellement être transmises aux scripts CGI et SSI à l’aide de la directive PassEnv.

    Le second type correspond aux variables nommées appelées aussi @@ -53,7 +53,7 @@ d'environnement, il ne faut pas les confondre avec les variables d'environnement contrôlées par le système d'exploitation sous-jacent. En fait, ces variables sont stockées et manipulées dans une structure - interne à Apache. Elles ne deviennent de véritables variables + interne à Apache httpd. Elles ne deviennent de véritables variables d'environnement du système d'exploitation que lorsqu'elles sont mises à la disposition de scripts CGI et de scripts inclus côté serveur (SSI). Si vous souhaitez manipuler l'environnement du système d'exploitation sous lequel @@ -76,7 +76,7 @@

    La méthode la plus élémentaire pour définir une variable - d'environnement au niveau d'Apache consiste à utiliser la directive + d'environnement au niveau d'Apache httpd consiste à utiliser la directive inconditionnelle SetEnv. Les variables peuvent aussi être transmises depuis l'environnement du shell à partir duquel le serveur a été démarré en utilisant la directive @@ -104,7 +104,7 @@

    Finalement, le module mod_unique_id définit la variable d'environnement UNIQUE_ID pour chaque requête à une valeur - qui est garantie unique parmi "toutes" les requêtes sous des + qui est garantie unique parmi « toutes » les requêtes sous des conditions très spécifiques.

    @@ -112,7 +112,7 @@

    En plus de l'ensemble des variables d'environnement internes à la - configuration d'Apache et de celles transmises depuis le shell, + configuration d'Apache httpd et de celles transmises depuis le shell, les scripts CGI et les pages SSI se voient affectés un ensemble de variables d'environnement contenant des méta-informations à propos de la requête @@ -135,17 +135,17 @@ suexec.c.

  • Pour des raisons de portabilité, les noms des variables - d'environnement ne peuvent contenir que des lettres, des chiffres, et - le caractère "sousligné". En outre, le premier caractère ne doit pas + d'environnement ne peuvent contenir que des lettres, des chiffres et + le caractère « souligné ». En outre, le premier caractère ne doit pas être un chiffre. Les caractères qui ne satisfont pas à ces conditions - seront remplacés par un caractère "sousligné" quand ils seront + seront remplacés par un caractère « souligné » quand ils seront transmis aux scripts CGI et aux pages SSI.
  • Les contenus d'en-têtes HTTP transmis aux scripts de type - CGI ou autre via des variables d'environnement constituent un + CGI ou autre à l’aide de variables d'environnement constituent un cas particulier (voir plus loin). Leur nom est converti en majuscules et seuls les tirets sont remplacés par des - caractères '_' ("souligné") ; si le format du nom de l'en-tête + caractères '_' (« souligné ») ; si le format du nom de l'en-tête n'est pas valide, celui-ci est ignoré. Voir plus loin pour une solution de contournement du problème.
  • @@ -156,7 +156,7 @@
  • Lorsque le serveur cherche un chemin via une sous-requête interne (par exemple la recherche d'un DirectoryIndex), ou lorsqu'il génère un - listing du contenu d'un répertoire via le module + listing du contenu d'un répertoire à l’aide du module mod_autoindex, la sous-requête n'hérite pas des variables d'environnement spécifiques à la requête. En outre, à cause des phases de l'API auxquelles mod_setenvif prend @@ -178,7 +178,7 @@ principales utilisations des variables d'environnement. Comme indiqué plus haut, l'environnement transmis aux scripts CGI comprend des méta-informations standards à propos de la requête, en plus des - variables définies dans la configuration d'Apache. Pour plus de + variables définies dans la configuration d'Apache httpd. Pour plus de détails, se référer au tutoriel CGI.

    @@ -193,7 +193,7 @@ et peuvent utiliser des variables d'environnement dans les éléments de contrôle de flux pour rendre certaines parties d'une page conditionnelles en fonction des caractéristiques de la requête. - Apache fournit aussi les variables d'environnement CGI standards + Apache httpd fournit aussi les variables d'environnement CGI standards aux pages SSI comme indiqué plus haut. Pour plus de détails, se référer au tutoriel SSI.

    @@ -206,7 +206,7 @@ variables d'environnement à l'aide des directives Require env et Require not env. En association avec la directive - SetEnvIf, ceci confère une + SetEnvIf, cela confère une grande souplesse au contrôle d'accès au serveur en fonction des caractéristiques du client. Par exemple, vous pouvez utiliser ces directives pour interdire l'accès depuis un navigateur particulier @@ -224,7 +224,7 @@ en fonction de l'état de variables d'environnement en utilisant la forme conditionnelle de la directive CustomLog. En - association avec la directive SetEnvIf, ceci confère une grande souplesse au contrôle + association avec la directive SetEnvIf, cela confère une grande souplesse au contrôle du traçage des requêtes. Par exemple, vous pouvez choisir de ne pas tracer les requêtes pour des noms de fichiers se terminant par gif, ou encore de ne tracer que les requêtes des clients @@ -237,7 +237,7 @@

    La directive Header peut se baser sur la présence ou l'absence d'une variable d'environnement pour décider si un certain en-tête HTTP sera placé - dans la réponse au client. Ceci permet, par exemple, de n'envoyer un + dans la réponse au client. Cela permet, par exemple, de n'envoyer un certain en-tête de réponse que si un en-tête correspondant est présent dans la requête du client.

    @@ -275,7 +275,7 @@

    Des problèmes d'interopérabilité ont conduit à l'introduction de - mécanismes permettant de modifier le comportement d'Apache lorsqu'il + mécanismes permettant de modifier le comportement d'Apache httpd lorsqu'il dialogue avec certains clients. Afin de rendre ces mécanismes aussi souples que possible, ils sont invoqués en définissant des variables d'environnement, en général à l'aide de la directive @@ -287,7 +287,7 @@

    downgrade-1.0

    -

    Ceci force le traitement d'une requête comme une requête HTTP/1.0 +

    Cela force le traitement d'une requête comme une requête HTTP/1.0 même si elle a été rédigée dans un langage plus récent.

    @@ -323,13 +323,13 @@

    gzip-only-text/html

    -

    Positionnée à "1", cette variable désactive le filtre en sortie +

    Positionnée à « 1 », cette variable désactive le filtre en sortie DEFLATE fourni par le module mod_deflate pour les types de contenu autres que text/html. Si vous préférez utiliser des fichiers compressés statiquement, mod_negotiation évalue aussi la variable (non seulement pour gzip, mais aussi pour tous les encodages autres que - "identity").

    + « identity »).

    no-gzip

    @@ -342,13 +342,13 @@

    no-cache

    -

    Disponible dans les versions 2.2.12 et ultérieures d'Apache

    +

    Disponible dans les versions 2.2.12 et ultérieures d'Apache httpd

    Lorsque cette variable est définie, mod_cache ne sauvegardera pas de réponse susceptible d'être mise en cache. Cette variable d'environnement n'a aucune incidence sur le fait qu'une réponse déjà enregistrée - dans la cache soit utilisée ou non pour la requête courante.

    + dans le cache soit utilisée ou non pour la requête courante.

    @@ -389,17 +389,17 @@

    Disponible dans les versions postérieures à 2.0.54

    -

    Quand Apache génère une redirection en réponse à une requête client, +

    Quand Apache httpd génère une redirection en réponse à une requête client, la réponse inclut un texte destiné à être affiché au cas où le client ne suivrait pas, ou ne pourrait pas suivre automatiquement la redirection. - Habituellement, Apache marque ce texte en accord avec le jeu de caractères + Habituellement, Apache httpd marque ce texte en accord avec le jeu de caractères qu'il utilise, à savoir ISO-8859-1.

    Cependant, si la redirection fait référence à une page qui utilise un jeu de caractères différent, certaines versions de navigateurs obsolètes essaieront d'utiliser le jeu de caractères du texte de la redirection plutôt que celui de la page réelle. - Ceci peut entraîner, par exemple, un rendu incorrect du Grec.

    -

    Si cette variable d'environnement est définie, Apache omettra le jeu de + Cela peut entraîner, par exemple, un rendu incorrect du Grec.

    +

    Si cette variable d'environnement est définie, Apache httpd omettra le jeu de caractères pour le texte de la redirection, et les navigateurs obsolètes précités utiliseront correctement celui de la page de destination.

    @@ -444,16 +444,16 @@ CGI -

    Avec la version 2.4, Apache est plus strict avec la conversion +

    Avec la version 2.4, Apache httpd est plus strict avec la conversion des en-têtes HTTP en variables d'environnement dans mod_cgi et d'autres modules : dans les versions - précédentes, tout caractère invalide dans les noms d'en-têtes + précédentes, tout caractère non valable dans les noms d'en-têtes était tout simplement remplacé par un caractère '_', ce qui pouvait exposer à des attaques de type cross-site-scripting via injection d'en-têtes (voir Bogues du Web inhabituelles, planche 19/20).

    -

    Si vous devez supporter un client qui envoie des en-têtes non +

    Si vous devez prendre en charge un client qui envoie des en-têtes non conformes et si ceux-ci ne peuvent pas être corrigés, il existe une solution de contournement simple mettant en jeu les modules mod_setenvif et mod_headers, @@ -513,7 +513,7 @@ CustomLog "logs/access_log" common env=!image-request -

    Prévention du "Vol d'image"

    +

    Prévention du « Vol d'image »

    Cet exemple montre comment empêcher les utilisateurs ne faisant pas diff --git a/docs/manual/mod/core.html.fr.utf8 b/docs/manual/mod/core.html.fr.utf8 index aae55fe4c4..b5505d1b5e 100644 --- a/docs/manual/mod/core.html.fr.utf8 +++ b/docs/manual/mod/core.html.fr.utf8 @@ -33,8 +33,6 @@  ja  |  tr 

  • -
    Cette traduction peut être périmée. Vérifiez la version - anglaise pour les changements récents.
    Description:Fonctionnalités de base du serveur HTTP Apache toujours disponibles
    Statut:Noyau httpd
    @@ -1739,8 +1737,16 @@ ErrorLogFormat "[%t] [%l] [pid %P] %F: %E: [client %a] %M" %{u}t L'heure courante avec les microsecondes %{cu}t - L'heure courante au format compact ISO 8601, avec les + L'heure courante au format ISO 8601 étendu (compact), avec les microsecondes +%{cuz}t + L'heure actuelle au format ISO 8601 étendu (compact), avec les + microsecondes et la zone horaire au format standard ISO 8601:2000. + Disponible depuis la version 2.4.58 seulement +%{%-format}t + L'heure actuelle formatée selon la fonction + strftime(3). Disponible depuis la version 2.4.58 + seulement %v Le nom de serveur canonique ServerName du serveur courant. %V diff --git a/docs/manual/mod/core.xml.meta b/docs/manual/mod/core.xml.meta index b9d96ee4c5..e78755527a 100644 --- a/docs/manual/mod/core.xml.meta +++ b/docs/manual/mod/core.xml.meta @@ -10,7 +10,7 @@ de en es - fr + fr ja tr From 378f5182ebe4279486b54920c2a9e49c4456ac9a Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Thu, 7 Nov 2024 12:05:05 +0000 Subject: [PATCH 089/176] propose r1921805 for backport git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1921806 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/STATUS b/STATUS index e505ea4591..5008311ca1 100644 --- a/STATUS +++ b/STATUS @@ -219,6 +219,10 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: PR: https://github.com/apache/httpd/pull/489 +1: ylavic, covener + *) mod_http2: Fix failed request counting and keepalive timeout + trunk patch: https://svn.apache.org/r1921805 + 2.4.x patch: svn merge -c r1921805 ^/httpd/httpd/trunk . + +1: icing PATCHES/ISSUES THAT ARE BEING WORKED [ New entries should be added at the START of the list ] From abbc2897472488efb615357fe35922092c64feff Mon Sep 17 00:00:00 2001 From: Joe Orton Date: Mon, 25 Nov 2024 13:19:46 +0000 Subject: [PATCH 090/176] Vote. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1922078 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/STATUS b/STATUS index 5008311ca1..b954fd69db 100644 --- a/STATUS +++ b/STATUS @@ -161,7 +161,8 @@ RELEASE SHOWSTOPPERS: https://svn.apache.org/r1921237 2.4.x patch: https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/470.diff PR: https://github.com/apache/httpd/pull/470 - +1: ylavic, covener + +1: ylavic, covener, jorton + PATCHES ACCEPTED TO BACKPORT FROM TRUNK: [ start all new proposals below, under PATCHES PROPOSED. ] From 2aa446f5b08a10c37e952daf96d0c80d3460873a Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Mon, 25 Nov 2024 13:32:44 +0000 Subject: [PATCH 091/176] Merge r1919620, r1919621, r1919623, r1919628, r1921237 from trunk: mod_proxy_fcgi: Don't re-encode SCRIPT_FILENAME. PR 69203 Before r1918550 (r1918559 in 2.4.60), "SetHandler proxy:..." configurations did not pass through proxy_fixup() hence the proxy_canon_handler hooks, leaving fcgi's SCRIPT_FILENAME environment variable (from r->filename) decoded, or more exactly not re-encoded. We still want to call ap_proxy_canon_url() for "fcgi:" to handle/strip the UDS "unix:" case and check that r->filename is valid and contains no controls, but proxy_fcgi_canon() will not ap_proxy_canonenc_ex() thus re-encode anymore. Note that this will do the same for "ProxyPass fcgi:...", there is no reason that using SetHandler or ProxyPass don't result in the same thing. If an opt in/out makes sense we should probably look at ProxyFCGIBackendType. Follow up to r1919620: CHANGES entry indent. Follow up to r1919620: init path after "proxy:" is skipped. Follow up to r1919620: Restore r->filename re-encoding for ProxyPass URLs. mod_proxy_fgci: Follow up to r1919628: Simplify. Variable from_handler is used once so axe it. Submitted by: ylavic Reviewed by: ylavic, covener, jorton Github: closes #470 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1922080 13f79535-47bb-0310-9956-ffa450edef68 --- CHANGES | 3 +++ changes-entries/bz69203.txt | 2 ++ modules/proxy/mod_proxy.c | 2 ++ modules/proxy/mod_proxy_fcgi.c | 37 +++++++++++++++++++++++----------- 4 files changed, 32 insertions(+), 12 deletions(-) create mode 100644 changes-entries/bz69203.txt diff --git a/CHANGES b/CHANGES index 9e0cf40777..d510c67423 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ -*- coding: utf-8 -*- Changes with Apache 2.4.63 + *) mod_proxy_fcgi: Don't re-encode SCRIPT_FILENAME when set via SetHandler. + PR 69203. [Yann Ylavic] + *) mod_rewrite, mod_proxy: mod_proxy to canonicalize rewritten [P] URLs, including "unix:" ones. PR 69235, PR 69260. [Yann Ylavic, Ruediger Pluem] diff --git a/changes-entries/bz69203.txt b/changes-entries/bz69203.txt new file mode 100644 index 0000000000..5562d6e039 --- /dev/null +++ b/changes-entries/bz69203.txt @@ -0,0 +1,2 @@ + *) mod_proxy_fcgi: Don't re-encode SCRIPT_FILENAME when set via SetHandler. + PR 69203. [Yann Ylavic] diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c index ab29c321df..4047d58f2a 100644 --- a/modules/proxy/mod_proxy.c +++ b/modules/proxy/mod_proxy.c @@ -1240,6 +1240,7 @@ static int proxy_handler(request_rec *r) r->proxyreq = PROXYREQ_REVERSE; r->filename = apr_pstrcat(r->pool, r->handler, r->filename, NULL); + apr_table_setn(r->notes, "proxy-sethandler", "1"); /* Still need to canonicalize r->filename */ rc = ap_proxy_canon_url(r); @@ -1249,6 +1250,7 @@ static int proxy_handler(request_rec *r) } } else if (r->proxyreq && strncmp(r->filename, "proxy:", 6) == 0) { + apr_table_unset(r->notes, "proxy-sethandler"); rc = OK; } if (rc != OK) { diff --git a/modules/proxy/mod_proxy_fcgi.c b/modules/proxy/mod_proxy_fcgi.c index d420df6a77..50f443e50d 100644 --- a/modules/proxy/mod_proxy_fcgi.c +++ b/modules/proxy/mod_proxy_fcgi.c @@ -63,6 +63,8 @@ static int proxy_fcgi_canon(request_rec *r, char *url) apr_port_t port, def_port; fcgi_req_config_t *rconf = NULL; const char *pathinfo_type = NULL; + fcgi_dirconf_t *dconf = ap_get_module_config(r->per_dir_config, + &proxy_fcgi_module); if (ap_cstr_casecmpn(url, "fcgi:", 5) == 0) { url += 5; @@ -92,9 +94,30 @@ static int proxy_fcgi_canon(request_rec *r, char *url) host = apr_pstrcat(r->pool, "[", host, "]", NULL); } - if (apr_table_get(r->notes, "proxy-nocanon") + if (apr_table_get(r->notes, "proxy-sethandler") + || apr_table_get(r->notes, "proxy-nocanon") || apr_table_get(r->notes, "proxy-noencode")) { - path = url; /* this is the raw/encoded path */ + char *c = url; + + /* We do not call ap_proxy_canonenc_ex() on the path here, don't + * let control characters pass still, and for php-fpm no '?' either. + */ + if (FCGI_MAY_BE_FPM(dconf)) { + while (!apr_iscntrl(*c) && *c != '?') + c++; + } + else { + while (!apr_iscntrl(*c)) + c++; + } + if (*c) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10414) + "To be forwarded path contains control characters%s (%s)", + FCGI_MAY_BE_FPM(dconf) ? " or '?'" : "", url); + return HTTP_FORBIDDEN; + } + + path = url; /* this is the raw path */ } else { core_dir_config *d = ap_get_core_module_config(r->per_dir_config); @@ -106,16 +129,6 @@ static int proxy_fcgi_canon(request_rec *r, char *url) return HTTP_BAD_REQUEST; } } - /* - * If we have a raw control character or a ' ' in nocanon path, - * correct encoding was missed. - */ - if (path == url && *ap_scan_vchar_obstext(path)) { - ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(10414) - "To be forwarded path contains control " - "characters or spaces"); - return HTTP_FORBIDDEN; - } r->filename = apr_pstrcat(r->pool, "proxy:fcgi://", host, sport, "/", path, NULL); From e0cfc8350b438390499e860ae39dbeb3568b58b2 Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Mon, 25 Nov 2024 13:33:51 +0000 Subject: [PATCH 092/176] dunno how this ended up in CHANGES also in r1922080 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1922081 13f79535-47bb-0310-9956-ffa450edef68 --- changes-entries/bz69203.txt | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 changes-entries/bz69203.txt diff --git a/changes-entries/bz69203.txt b/changes-entries/bz69203.txt deleted file mode 100644 index 5562d6e039..0000000000 --- a/changes-entries/bz69203.txt +++ /dev/null @@ -1,2 +0,0 @@ - *) mod_proxy_fcgi: Don't re-encode SCRIPT_FILENAME when set via SetHandler. - PR 69203. [Yann Ylavic] From dd544174479a2dde945efc9cd5b9323d87b53cf4 Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Mon, 25 Nov 2024 13:34:26 +0000 Subject: [PATCH 093/176] ported [skip ci] git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1922082 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 9 --------- 1 file changed, 9 deletions(-) diff --git a/STATUS b/STATUS index b954fd69db..37f2d974b1 100644 --- a/STATUS +++ b/STATUS @@ -153,15 +153,6 @@ CURRENT RELEASE NOTES: RELEASE SHOWSTOPPERS: - *) mod_proxy_fcgi: Don't re-encode SCRIPT_FILENAME when set via SetHandler. PR 69203. - trunk patch: https://svn.apache.org/r1919620 - https://svn.apache.org/r1919621 - https://svn.apache.org/r1919623 - https://svn.apache.org/r1919628 - https://svn.apache.org/r1921237 - 2.4.x patch: https://patch-diff.githubusercontent.com/raw/apache/httpd/pull/470.diff - PR: https://github.com/apache/httpd/pull/470 - +1: ylavic, covener, jorton PATCHES ACCEPTED TO BACKPORT FROM TRUNK: [ start all new proposals below, under PATCHES PROPOSED. ] From c18e0e7b078b857f7d65577e46d42e3df7bb150b Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Mon, 25 Nov 2024 13:37:20 +0000 Subject: [PATCH 094/176] mod_ssl: Fix regression in PKCS#11 handling which should work without ... SSLCryptoDevice configured Submitted By: jorton, ylavic Reviewed By: jorton, ylavic, rpluem git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1922083 13f79535-47bb-0310-9956-ffa450edef68 --- changes-entries/modssl-engine-fallback.txt | 2 ++ modules/ssl/ssl_engine_pphrase.c | 35 ++++++++++++++-------- 2 files changed, 24 insertions(+), 13 deletions(-) create mode 100644 changes-entries/modssl-engine-fallback.txt diff --git a/changes-entries/modssl-engine-fallback.txt b/changes-entries/modssl-engine-fallback.txt new file mode 100644 index 0000000000..6e56641d0e --- /dev/null +++ b/changes-entries/modssl-engine-fallback.txt @@ -0,0 +1,2 @@ + *) mod_ssl: Restore support for loading PKCS#11 keys via ENGINE + without "SSLCryptoDevice" configured. [Joe Orton] diff --git a/modules/ssl/ssl_engine_pphrase.c b/modules/ssl/ssl_engine_pphrase.c index 8a08ede67a..5f18589a03 100644 --- a/modules/ssl/ssl_engine_pphrase.c +++ b/modules/ssl/ssl_engine_pphrase.c @@ -839,6 +839,9 @@ static apr_status_t modssl_engine_cleanup(void *engine) return APR_SUCCESS; } +/* Tries to load the key and optionally certificate via the ENGINE + * API. Returns APR_ENOTIMPL if an ENGINE could not be identified + * loaded from the key name. */ static apr_status_t modssl_load_keypair_engine(server_rec *s, apr_pool_t *pconf, apr_pool_t *ptemp, const char *vhostid, @@ -861,19 +864,19 @@ static apr_status_t modssl_load_keypair_engine(server_rec *s, apr_pool_t *pconf, c = ap_strchr_c(keyid, ':'); if (!c || c == keyid) { - ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10131) + ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, APLOGNO(10131) "Init: Unrecognized private key identifier `%s'", keyid); - return ssl_die(s); + return APR_ENOTIMPL; } scheme = apr_pstrmemdup(ptemp, keyid, c - keyid); if (!(e = ENGINE_by_id(scheme))) { - ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(10132) + ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, s, APLOGNO(10132) "Init: Failed to load engine for private key %s", keyid); - ssl_log_ssl_error(SSLLOG_MARK, APLOG_EMERG, s); - return ssl_die(s); + ssl_log_ssl_error(SSLLOG_MARK, APLOG_NOTICE, s); + return APR_ENOTIMPL; } if (!ENGINE_init(e)) { @@ -1029,15 +1032,21 @@ apr_status_t modssl_load_engine_keypair(server_rec *s, X509 **pubkey, EVP_PKEY **privkey) { #if MODSSL_HAVE_ENGINE_API - SSLModConfigRec *mc = myModConfig(s); + apr_status_t rv; + + rv = modssl_load_keypair_engine(s, pconf, ptemp, + vhostid, certid, keyid, + pubkey, privkey); + if (rv == APR_SUCCESS) { + return rv; + } + /* If STORE support is not present, all errors are fatal here; if + * STORE is present and the ENGINE could not be loaded, ignore the + * error and fall through to try loading via the STORE API. */ + else if (!MODSSL_HAVE_OPENSSL_STORE || rv != APR_ENOTIMPL) { + return ssl_die(s); + } - /* For OpenSSL 3.x, use the STORE-based API if either ENGINE - * support was not present compile-time, or if it's built but - * SSLCryptoDevice is not configured. */ - if (mc->szCryptoDevice) - return modssl_load_keypair_engine(s, pconf, ptemp, - vhostid, certid, keyid, - pubkey, privkey); #endif #if MODSSL_HAVE_OPENSSL_STORE return modssl_load_keypair_store(s, ptemp, vhostid, certid, keyid, From c39fba732d8b92374ad4922c92b84f22ecf822fb Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Mon, 25 Nov 2024 13:37:36 +0000 Subject: [PATCH 095/176] backported [skip ci] git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1922084 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 6 ------ 1 file changed, 6 deletions(-) diff --git a/STATUS b/STATUS index 37f2d974b1..ed7cafeb74 100644 --- a/STATUS +++ b/STATUS @@ -157,12 +157,6 @@ RELEASE SHOWSTOPPERS: PATCHES ACCEPTED TO BACKPORT FROM TRUNK: [ start all new proposals below, under PATCHES PROPOSED. ] - *) mod_ssl: Fix regression in PKCS#11 handling which should work without - SSLCryptoDevice configured - trunk patch: https://svn.apache.org/r1920597 - https://svn.apache.org/r1921076 - 2.4.x patch: svn merge -c 1920597 -c 1921076 ^/httpd/httpd/trunk . - +1: jorton, ylavic, rpluem PATCHES PROPOSED TO BACKPORT FROM TRUNK: [ New proposals should be added at the end of the list ] From 9445696ccca6313dccd7d128bf0b2c5d01875191 Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Wed, 27 Nov 2024 15:39:02 +0000 Subject: [PATCH 096/176] Merge r1922169 from trunk: PR65095: elaborate on "default port" in ... UseCanonicalPhysicalPort git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1922171 13f79535-47bb-0310-9956-ffa450edef68 --- docs/manual/mod/core.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/manual/mod/core.xml b/docs/manual/mod/core.xml index a4239d5a65..2ea71469dc 100644 --- a/docs/manual/mod/core.xml +++ b/docs/manual/mod/core.xml @@ -5046,7 +5046,7 @@ port
    1. Port provided in Servername
    2. Physical port
    3. -
    4. Default port
    5. +
    6. Default port for the scheme/protocol (such as 80 or 443)
    UseCanonicalName Off | DNS
    @@ -5055,7 +5055,7 @@ port
  • Parsed port from Host: header
  • Physical port
  • Port provided in Servername
  • -
  • Default port
  • +
  • Default port for the scheme/protocol (such as 80 or 443)
  • From bff4c0747f616e30bcd632baabcb33befeea96f6 Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Wed, 27 Nov 2024 15:41:21 +0000 Subject: [PATCH 097/176] xforms [skip ci] git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1922172 13f79535-47bb-0310-9956-ffa450edef68 --- docs/manual/mod/core.html.en | 4 +- docs/manual/mod/core.xml.de | 2 +- docs/manual/mod/core.xml.es | 2 +- docs/manual/mod/core.xml.fr | 2 +- docs/manual/mod/core.xml.ja | 2 +- docs/manual/mod/core.xml.meta | 2 +- docs/manual/mod/core.xml.tr | 2 +- docs/manual/mod/directives.html.en | 15 ----- docs/manual/mod/index.html.en | 5 +- docs/manual/mod/mod_rewrite.html.en | 6 +- docs/manual/mod/quickreference.html.en | 79 +++++++++++--------------- docs/manual/rewrite/flags.html.en | 10 +++- docs/manual/sitemap.html.en | 1 - 13 files changed, 52 insertions(+), 80 deletions(-) diff --git a/docs/manual/mod/core.html.en b/docs/manual/mod/core.html.en index de76a39ad3..7b36a9551e 100644 --- a/docs/manual/mod/core.html.en +++ b/docs/manual/mod/core.html.en @@ -5157,7 +5157,7 @@ port
    1. Port provided in Servername
    2. Physical port
    3. -
    4. Default port
    5. +
    6. Default port for the scheme/protocol (such as 80 or 443)
    UseCanonicalName Off | DNS
    @@ -5166,7 +5166,7 @@ port
  • Parsed port from Host: header
  • Physical port
  • Port provided in Servername
  • -
  • Default port
  • +
  • Default port for the scheme/protocol (such as 80 or 443)
  • diff --git a/docs/manual/mod/core.xml.de b/docs/manual/mod/core.xml.de index 0c05b71119..e731bab651 100644 --- a/docs/manual/mod/core.xml.de +++ b/docs/manual/mod/core.xml.de @@ -1,7 +1,7 @@ - + + + diff --git a/docs/manual/mod/core.xml.ja b/docs/manual/mod/core.xml.ja index 7a4e82a6ea..bbf1060119 100644 --- a/docs/manual/mod/core.xml.ja +++ b/docs/manual/mod/core.xml.ja @@ -1,7 +1,7 @@ - + + + @@ -5450,7 +5450,7 @@ host
    1. Port indiqué dans Servername
    2. Port physique
    3. -
    4. Port par défaut
    5. +
    6. Port par défaut pour le contexte/protocole (comme 80 ou 443)
    UseCanonicalName Off | DNS
    @@ -5459,7 +5459,7 @@ host
  • Port spécifié dans l'en-tête Host:
  • Port physique
  • Port spécifié par Servername
  • -
  • Port par défaut
  • +
  • Port par défaut pour le contexte/protocole (comme 80 ou 443)
  • From 7566c2f4a565f0d9b9d91527aa7c73c097966e46 Mon Sep 17 00:00:00 2001 From: Lucien Gentis Date: Sat, 30 Nov 2024 13:05:06 +0000 Subject: [PATCH 099/176] fr doc rebuild. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1922236 13f79535-47bb-0310-9956-ffa450edef68 --- docs/manual/mod/core.html.fr.utf8 | 4 ++-- docs/manual/mod/core.xml.meta | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/manual/mod/core.html.fr.utf8 b/docs/manual/mod/core.html.fr.utf8 index b5505d1b5e..4d5b754879 100644 --- a/docs/manual/mod/core.html.fr.utf8 +++ b/docs/manual/mod/core.html.fr.utf8 @@ -5532,7 +5532,7 @@ détermine son propre port
    1. Port indiqué dans Servername
    2. Port physique
    3. -
    4. Port par défaut
    5. +
    6. Port par défaut pour le contexte/protocole (comme 80 ou 443)
    UseCanonicalName Off | DNS
    @@ -5541,7 +5541,7 @@ détermine son propre port
  • Port spécifié dans l'en-tête Host:
  • Port physique
  • Port spécifié par Servername
  • -
  • Port par défaut
  • +
  • Port par défaut pour le contexte/protocole (comme 80 ou 443)
  • diff --git a/docs/manual/mod/core.xml.meta b/docs/manual/mod/core.xml.meta index b9d96ee4c5..e78755527a 100644 --- a/docs/manual/mod/core.xml.meta +++ b/docs/manual/mod/core.xml.meta @@ -10,7 +10,7 @@ de en es - fr + fr ja tr From 6f5a4244f68f743770f3bd9c76ffd4632ddbb3be Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Sun, 1 Dec 2024 14:17:01 +0000 Subject: [PATCH 100/176] Merge r1922246 from trunk: Don't use AuthFormLoginRequiredLocation in inline Intro to inline says: If a non-authenticated user attempts to access a page protected by mod_auth_form that isn't configured with a AuthFormLoginRequiredLocation directive, a HTTP_UNAUTHORIZED status code is returned to the browser indicating to the user that they are not authorized to view the page. The entire point seems to be to keep the URL the same by using an internal redirect via ErrorDocument, and AuthFormLoginRequiredLocation conflicts with it. Submitted By: Rishikeshan Lavakumar/Sulochana git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1922247 13f79535-47bb-0310-9956-ffa450edef68 --- docs/manual/mod/mod_auth_form.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/manual/mod/mod_auth_form.xml b/docs/manual/mod/mod_auth_form.xml index 7b6479d1b3..69cd8b028d 100644 --- a/docs/manual/mod/mod_auth_form.xml +++ b/docs/manual/mod/mod_auth_form.xml @@ -212,7 +212,6 @@ ErrorDocument 401 "/login.shtml" AuthUserFile "conf/passwd" AuthType form AuthName realm -AuthFormLoginRequiredLocation "http://example.com/login.html" Session On SessionCookieName session path=/ From 74723e69c3822a48779688ecbe2384c3251944c6 Mon Sep 17 00:00:00 2001 From: Eric Covener Date: Sun, 1 Dec 2024 14:17:20 +0000 Subject: [PATCH 101/176] xforms [skip ci] git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1922248 13f79535-47bb-0310-9956-ffa450edef68 --- docs/manual/mod/mod_auth_form.html.en | 1 - docs/manual/mod/mod_auth_form.xml.fr | 2 +- docs/manual/mod/mod_auth_form.xml.meta | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/manual/mod/mod_auth_form.html.en b/docs/manual/mod/mod_auth_form.html.en index d1f8895269..18401d4b15 100644 --- a/docs/manual/mod/mod_auth_form.html.en +++ b/docs/manual/mod/mod_auth_form.html.en @@ -234,7 +234,6 @@ ErrorDocument 401 "/login.shtml" AuthUserFile "conf/passwd" AuthType form AuthName realm -AuthFormLoginRequiredLocation "http://example.com/login.html" Session On SessionCookieName session path=/
    diff --git a/docs/manual/mod/mod_auth_form.xml.fr b/docs/manual/mod/mod_auth_form.xml.fr index cd115087e0..e3b254a1ca 100644 --- a/docs/manual/mod/mod_auth_form.xml.fr +++ b/docs/manual/mod/mod_auth_form.xml.fr @@ -1,7 +1,7 @@ - + diff --git a/docs/manual/mod/mod_auth_form.xml.meta b/docs/manual/mod/mod_auth_form.xml.meta index 66a7abbcd2..ff178f6df2 100644 --- a/docs/manual/mod/mod_auth_form.xml.meta +++ b/docs/manual/mod/mod_auth_form.xml.meta @@ -8,6 +8,6 @@ en - fr + fr From 486f1d4f334f8d30c3820e434998952141e88622 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Tue, 3 Dec 2024 09:59:46 +0000 Subject: [PATCH 102/176] Merge /httpd/httpd/trunk:r1922279 *) mod_md: update to version 2.4.29 - Fixed HTTP-01 challenges to not carry a final newline, as some ACME server fail to ignore it. [Michael Kaufmann (@mkauf)] - Fixed missing label+newline in server-status plain text output when MDStapling is enabled. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1922280 13f79535-47bb-0310-9956-ffa450edef68 --- changes-entries/md_v2.4.29.txt | 5 +++++ modules/md/md_acme_authz.c | 3 +-- modules/md/md_version.h | 4 ++-- modules/md/mod_md_status.c | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) create mode 100644 changes-entries/md_v2.4.29.txt diff --git a/changes-entries/md_v2.4.29.txt b/changes-entries/md_v2.4.29.txt new file mode 100644 index 0000000000..09323cd948 --- /dev/null +++ b/changes-entries/md_v2.4.29.txt @@ -0,0 +1,5 @@ + *) mod_md: update to version 2.4.29 + - Fixed HTTP-01 challenges to not carry a final newline, as some ACME + server fail to ignore it. [Michael Kaufmann (@mkauf)] + - Fixed missing label+newline in server-status plain text output when + MDStapling is enabled. diff --git a/modules/md/md_acme_authz.c b/modules/md/md_acme_authz.c index f4579b366b..fc46274fff 100644 --- a/modules/md/md_acme_authz.c +++ b/modules/md/md_acme_authz.c @@ -263,9 +263,8 @@ static apr_status_t cha_http_01_setup(md_acme_authz_cha_t *cha, md_acme_authz_t rv = md_store_load(store, MD_SG_CHALLENGES, authz->domain, MD_FN_HTTP01, MD_SV_TEXT, (void**)&data, p); if ((APR_SUCCESS == rv && strcmp(cha->key_authz, data)) || APR_STATUS_IS_ENOENT(rv)) { - const char *content = apr_psprintf(p, "%s\n", cha->key_authz); rv = md_store_save(store, p, MD_SG_CHALLENGES, authz->domain, MD_FN_HTTP01, - MD_SV_TEXT, (void*)content, 0); + MD_SV_TEXT, (void*)cha->key_authz, 0); notify_server = 1; } diff --git a/modules/md/md_version.h b/modules/md/md_version.h index 3e2914d6b6..326b74cf25 100644 --- a/modules/md/md_version.h +++ b/modules/md/md_version.h @@ -27,7 +27,7 @@ * @macro * Version number of the md module as c string */ -#define MOD_MD_VERSION "2.4.28" +#define MOD_MD_VERSION "2.4.29" /** * @macro @@ -35,7 +35,7 @@ * release. This is a 24 bit number with 8 bits for major number, 8 bits * for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203. */ -#define MOD_MD_VERSION_NUM 0x02041c +#define MOD_MD_VERSION_NUM 0x02041d #define MD_ACME_DEF_URL "https://acme-v02.api.letsencrypt.org/directory" #define MD_TAILSCALE_DEF_URL "file://localhost/var/run/tailscale/tailscaled.sock" diff --git a/modules/md/mod_md_status.c b/modules/md/mod_md_status.c index 6b29256b67..033628f267 100644 --- a/modules/md/mod_md_status.c +++ b/modules/md/mod_md_status.c @@ -617,7 +617,7 @@ static void si_val_stapling(status_ctx *ctx, md_json_t *mdj, const status_info * apr_brigade_puts(ctx->bb, NULL, NULL, "on"); } else { - apr_brigade_printf(ctx->bb, NULL, NULL, "%s: on", ctx->prefix); + apr_brigade_printf(ctx->bb, NULL, NULL, "%sStapling: on\n", ctx->prefix); } } From 707fb91c0f6e66b83d36a0e35553f0449d6a5562 Mon Sep 17 00:00:00 2001 From: Lucien Gentis Date: Sat, 7 Dec 2024 14:42:23 +0000 Subject: [PATCH 103/176] fr doc XML file update. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1922364 13f79535-47bb-0310-9956-ffa450edef68 --- docs/manual/mod/mod_auth_form.xml.fr | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/manual/mod/mod_auth_form.xml.fr b/docs/manual/mod/mod_auth_form.xml.fr index e3b254a1ca..e5b897899d 100644 --- a/docs/manual/mod/mod_auth_form.xml.fr +++ b/docs/manual/mod/mod_auth_form.xml.fr @@ -1,7 +1,7 @@ - + @@ -247,7 +247,6 @@ ErrorDocument 401 "/login.shtml" AuthUserFile "conf/passwd" AuthType form AuthName realm -AuthFormLoginRequiredLocation "http://example.com/login.html" Session On SessionCookieName session path=/ From 83771f5ba2f5925189cd2ee0d8c4a1b69100c443 Mon Sep 17 00:00:00 2001 From: Lucien Gentis Date: Sat, 7 Dec 2024 14:43:13 +0000 Subject: [PATCH 104/176] fr doc rebuild. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1922365 13f79535-47bb-0310-9956-ffa450edef68 --- docs/manual/mod/mod_auth_form.html.fr.utf8 | 1 - docs/manual/mod/mod_auth_form.xml.meta | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/manual/mod/mod_auth_form.html.fr.utf8 b/docs/manual/mod/mod_auth_form.html.fr.utf8 index 98fc0a2745..7081ec8be7 100644 --- a/docs/manual/mod/mod_auth_form.html.fr.utf8 +++ b/docs/manual/mod/mod_auth_form.html.fr.utf8 @@ -262,7 +262,6 @@ ErrorDocument 401 "/login.shtml" AuthUserFile "conf/passwd" AuthType form AuthName realm -AuthFormLoginRequiredLocation "http://example.com/login.html" Session On SessionCookieName session path=/
    diff --git a/docs/manual/mod/mod_auth_form.xml.meta b/docs/manual/mod/mod_auth_form.xml.meta index ff178f6df2..66a7abbcd2 100644 --- a/docs/manual/mod/mod_auth_form.xml.meta +++ b/docs/manual/mod/mod_auth_form.xml.meta @@ -8,6 +8,6 @@ en - fr + fr From 3817732131faf8f3e1b3f4595668d3e6285ebee0 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Wed, 11 Dec 2024 12:44:56 +0000 Subject: [PATCH 105/176] Merge /httpd/httpd/trunk:r1922429 *) mod_md: change log level from error to debug when MDStapling is enabled but a certificate carries no OCSP url. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1922430 13f79535-47bb-0310-9956-ffa450edef68 --- modules/md/md_ocsp.c | 2 +- modules/md/md_version.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/md/md_ocsp.c b/modules/md/md_ocsp.c index 8276137c3e..af2dd15293 100644 --- a/modules/md/md_ocsp.c +++ b/modules/md/md_ocsp.c @@ -334,7 +334,7 @@ apr_status_t md_ocsp_prime(md_ocsp_reg_t *reg, const char *ext_id, apr_size_t ex "md[%s]: getting ocsp responder from cert", name); rv = md_cert_get_ocsp_responder_url(&ostat->responder_url, reg->p, cert); if (APR_SUCCESS != rv) { - md_log_perror(MD_LOG_MARK, MD_LOG_ERR, rv, reg->p, + md_log_perror(MD_LOG_MARK, MD_LOG_DEBUG, rv, reg->p, "md[%s]: certificate with serial %s has no OCSP responder URL", name, md_cert_get_serial_number(cert, reg->p)); goto cleanup; diff --git a/modules/md/md_version.h b/modules/md/md_version.h index 326b74cf25..2304194b99 100644 --- a/modules/md/md_version.h +++ b/modules/md/md_version.h @@ -27,7 +27,7 @@ * @macro * Version number of the md module as c string */ -#define MOD_MD_VERSION "2.4.29" +#define MOD_MD_VERSION "2.4.30" /** * @macro @@ -35,7 +35,7 @@ * release. This is a 24 bit number with 8 bits for major number, 8 bits * for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203. */ -#define MOD_MD_VERSION_NUM 0x02041d +#define MOD_MD_VERSION_NUM 0x02041e #define MD_ACME_DEF_URL "https://acme-v02.api.letsencrypt.org/directory" #define MD_TAILSCALE_DEF_URL "file://localhost/var/run/tailscale/tailscaled.sock" From 945e3ca74abfbb6f467cb11a7a45f3731b9ac30d Mon Sep 17 00:00:00 2001 From: Joe Orton Date: Thu, 12 Dec 2024 17:54:24 +0000 Subject: [PATCH 106/176] Merge r1921310, r1922412 from trunk: [CTR for CI changes] CI: Further fixes for ubuntu-latest image updates on GitHub Actions. CI: Switch down to GCC 12, the ubuntu-latest image is not consistently an Ubuntu 24.04 environment yet, this version should be available in both the -22.04 and -24.04 images. Github: closes #498 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1922457 13f79535-47bb-0310-9956-ffa450edef68 --- .github/workflows/linux.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 592002ca99..8f811382f1 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -67,11 +67,11 @@ jobs: env: | TEST_ARGS=-order=random # ------------------------------------------------------------------------- - - name: GCC 10 maintainer-mode w/-Werror, install + VPATH + - name: GCC 12 maintainer-mode w/-Werror, install + VPATH config: --enable-mods-shared=reallyall --enable-maintainer-mode notest-cflags: -Werror -O2 env: | - CC=gcc-10 + CC=gcc-12 TEST_VPATH=1 TEST_INSTALL=1 SKIP_TESTING=1 @@ -292,5 +292,6 @@ jobs: if: failure() with: name: error_log-${{ env.JOBID }} - path: test/perl-framework/t/logs/error_log - + path: | + **/config.log + test/perl-framework/t/logs/error_log From 4587cd6886df1d7ddd165470778dd29d14823fd3 Mon Sep 17 00:00:00 2001 From: Joe Orton Date: Fri, 13 Dec 2024 15:10:51 +0000 Subject: [PATCH 107/176] 2 small backports. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1922466 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/STATUS b/STATUS index ed7cafeb74..567bfca1ae 100644 --- a/STATUS +++ b/STATUS @@ -210,6 +210,17 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: 2.4.x patch: svn merge -c r1921805 ^/httpd/httpd/trunk . +1: icing + *) mod_authnz_ldap: Fix attribute allocation size. + trunk patch: https://svn.apache.org/r1921971 + 2.4.x patch: svn merge -c 1921971 ^/httpd/httpd/trunk . + +1: jorton, + + *) mod_log_config: Fix LogFormat directive merging + trunk patch: https://svn.apache.org/r1921305 + https://svn.apache.org/r1921306 + 2.4.x patch: svn merge -c 1921305,1921306 ^/httpd/httpd/trunk . + +1: jorton, + PATCHES/ISSUES THAT ARE BEING WORKED [ New entries should be added at the START of the list ] From 19718a9936688cd7bec59ea9e3b6db1631843649 Mon Sep 17 00:00:00 2001 From: Joe Orton Date: Fri, 13 Dec 2024 15:49:24 +0000 Subject: [PATCH 108/176] One more small patch. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1922467 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/STATUS b/STATUS index 567bfca1ae..ec4f4ed6a2 100644 --- a/STATUS +++ b/STATUS @@ -221,6 +221,11 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: 2.4.x patch: svn merge -c 1921305,1921306 ^/httpd/httpd/trunk . +1: jorton, + *) mod_lua: Make r.ap_auth_type writable + trunk patch: https://svn.apache.org/r1921260 + 2.4.x patch: svn merge -c 1921260 ^/httpd/httpd/trunk . + +1: jorton, + PATCHES/ISSUES THAT ARE BEING WORKED [ New entries should be added at the START of the list ] From 20ede44d6b405d87777867289458c27ffcf24d1c Mon Sep 17 00:00:00 2001 From: Christophe Jaillet Date: Sat, 14 Dec 2024 15:16:07 +0000 Subject: [PATCH 109/176] Easy proposals git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1922498 13f79535-47bb-0310-9956-ffa450edef68 --- STATUS | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/STATUS b/STATUS index ec4f4ed6a2..86e388a64b 100644 --- a/STATUS +++ b/STATUS @@ -226,6 +226,34 @@ PATCHES PROPOSED TO BACKPORT FROM TRUNK: 2.4.x patch: svn merge -c 1921260 ^/httpd/httpd/trunk . +1: jorton, + *) Easy patches: synch 2.4.x and trunk + - server: Use apr_size_t instead of int to harden against overflows + - mod_http2: DOXYGEN has nothing to do here, just remove this + strange "#if defined(DOXYGEN)" + - test: make the compiler happy when using --enable-maintainer-mode + - mod_proxy: Fix format string type check + - mod_http2: Fix comment, no functional change + - : Remove unnecessary APLOGNO() use in TRACE-level logging + - mod_cache_socache: Update comment only, to remove reference to + session cache + - mod_dav: Fix error message formatting if an unauthenticated user + tries to use an authenticated user's lock token + - : trigger ci + - server: Fix typo in comment + trunk patch: + https://svn.apache.org/r1903680 + https://svn.apache.org/r1912663 + https://svn.apache.org/r1917013 + https://svn.apache.org/r1912941 + https://svn.apache.org/r1913078 + https://svn.apache.org/r1913338 + https://svn.apache.org/r1914035 + https://svn.apache.org/r1914439 + https://svn.apache.org/r1915270 + https://svn.apache.org/r1915543 + 2.4.x patch: svn merge -c 1903680,1912663,1917013,1912941,1913078,1913338,1914035,1914439,1915270,1915543 ^/httpd/httpd/trunk . + +1: jailletc36, + PATCHES/ISSUES THAT ARE BEING WORKED [ New entries should be added at the START of the list ] From ef667e2608df815cf843eb2c17f541d7e7fc1b56 Mon Sep 17 00:00:00 2001 From: Rainer Jung Date: Wed, 1 Jan 2025 11:13:49 +0000 Subject: [PATCH 110/176] Happy New Year 2025 git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1922819 13f79535-47bb-0310-9956-ffa450edef68 --- docs/manual/style/xsl/common.xsl | 2 +- include/ap_release.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/manual/style/xsl/common.xsl b/docs/manual/style/xsl/common.xsl index 3955c47e18..9ecd188b7d 100644 --- a/docs/manual/style/xsl/common.xsl +++ b/docs/manual/style/xsl/common.xsl @@ -418,7 +418,7 @@ var comments_identifier = 'http://httpd.apache.org/docs/]]>&httpd.doc