]> git.ipfire.org Git - thirdparty/squid.git/blobdiff - src/acl/ServerName.cc
Source Format Enforcement (#1234)
[thirdparty/squid.git] / src / acl / ServerName.cc
index 5af6d223088cf9064c4bf91ad37d0656c9cf3de1..fe356923e9897f985d88a7b67a85bdb1b5e2fb72 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
+ * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
  *
  * Squid software is distributed under GPLv2+ license and includes
  * contributions from numerous individuals and organizations.
@@ -9,19 +9,19 @@
 /* DEBUG: section 28    Access Control */
 
 #include "squid.h"
-#include "acl/Checklist.h"
 #include "acl/DomainData.h"
+#include "acl/FilledChecklist.h"
 #include "acl/RegexData.h"
 #include "acl/ServerName.h"
 #include "client_side.h"
 #include "fde.h"
+#include "http/Stream.h"
 #include "HttpRequest.h"
 #include "ipcache.h"
 #include "SquidString.h"
 #include "ssl/bio.h"
 #include "ssl/ServerBump.h"
 #include "ssl/support.h"
-#include "URL.h"
 
 // Compare function for tree search algorithms
 static int
@@ -30,13 +30,13 @@ aclHostDomainCompare( char *const &a, char * const &b)
     const char *h = static_cast<const char *>(a);
     const char *d = static_cast<const char *>(b);
     debugs(28, 7, "Match:" << h << " <>  " << d);
-    return matchDomainName(h, d, true);
+    return matchDomainName(h, d, mdnHonorWildcards);
 }
 
 bool
 ACLServerNameData::match(const char *host)
 {
-    if (host == NULL)
+    if (host == nullptr)
         return 0;
 
     debugs(28, 3, "checking '" << host << "'");
@@ -46,18 +46,10 @@ ACLServerNameData::match(const char *host)
 
     debugs(28, 3, "'" << host << "' " << (result ? "found" : "NOT found"));
 
-    return (result != NULL);
+    return (result != nullptr);
 
 }
 
-ACLData<char const *> *
-ACLServerNameData::clone() const
-{
-    /* Splay trees don't clone yet. */
-    assert (!domains);
-    return new ACLServerNameData;
-}
-
 /// A helper function to be used with Ssl::matchX509CommonNames().
 /// \retval 0 when the name (cn or an alternate name) matches acl data
 /// \retval 1 when the name does not match
@@ -86,38 +78,73 @@ check_cert_domain( void *check_data, ASN1_STRING *cn_data)
 }
 
 int
-ACLServerNameStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist, ACLFlags &flags)
+ACLServerNameStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist)
 {
-    assert(checklist != NULL && checklist->request != NULL);
-
-    if (checklist->conn() && checklist->conn()->serverBump()) {
-        if (X509 *peer_cert = checklist->conn()->serverBump()->serverCert.get()) {
-            if (Ssl::matchX509CommonNames(peer_cert, (void *)data, check_cert_domain<MatchType>))
-                return 1;
+    assert(checklist != nullptr && checklist->request != nullptr);
+
+    const char *serverName = nullptr;
+    SBuf clientSniKeeper; // because c_str() is not constant
+    if (ConnStateData *conn = checklist->conn()) {
+        const char *clientRequestedServerName = nullptr;
+        clientSniKeeper = conn->tlsClientSni();
+        if (clientSniKeeper.isEmpty()) {
+            const char *host = checklist->request->url.host();
+            if (host && *host) // paranoid first condition: host() is never nil
+                clientRequestedServerName = host;
+        } else
+            clientRequestedServerName = clientSniKeeper.c_str();
+
+        if (useConsensus) {
+            X509 *peer_cert = conn->serverBump() ? conn->serverBump()->serverCert.get() : nullptr;
+            // use the client requested name if it matches the server
+            // certificate or if the certificate is not available
+            if (!peer_cert || Ssl::checkX509ServerValidity(peer_cert, clientRequestedServerName))
+                serverName = clientRequestedServerName;
+        } else if (useClientRequested)
+            serverName = clientRequestedServerName;
+        else { // either no options or useServerProvided
+            if (X509 *peer_cert = (conn->serverBump() ? conn->serverBump()->serverCert.get() : nullptr))
+                return Ssl::matchX509CommonNames(peer_cert, (void *)data, check_cert_domain<MatchType>);
+            if (!useServerProvided)
+                serverName = clientRequestedServerName;
         }
     }
 
-    const char *serverName = NULL;
-    if (checklist->conn() && !checklist->conn()->sslCommonName().isEmpty()) {
-        SBuf scn = checklist->conn()->sslCommonName();
-        serverName = scn.c_str();
-    }
-
-    if (serverName == NULL)
-        serverName = checklist->request->GetHost();
+    if (!serverName)
+        serverName = "none";
 
-    if (serverName && data->match(serverName)) {
-        return 1;
-    }
-
-    return data->match("none");
+    return data->match(serverName);
 }
 
-ACLServerNameStrategy *
-ACLServerNameStrategy::Instance()
+const Acl::Options &
+ACLServerNameStrategy::options()
 {
-    return &Instance_;
+    static const Acl::BooleanOption ClientRequested("--client-requested");
+    static const Acl::BooleanOption ServerProvided("--server-provided");
+    static const Acl::BooleanOption Consensus("--consensus");
+    static const Acl::Options MyOptions = { &ClientRequested, &ServerProvided, &Consensus };
+    ClientRequested.linkWith(&useClientRequested);
+    ServerProvided.linkWith(&useServerProvided);
+    Consensus.linkWith(&useConsensus);
+    return MyOptions;
 }
 
-ACLServerNameStrategy ACLServerNameStrategy::Instance_;
+bool
+ACLServerNameStrategy::valid() const
+{
+    int optionCount = 0;
+
+    if (useClientRequested)
+        optionCount++;
+    if (useServerProvided)
+        optionCount++;
+    if (useConsensus)
+        optionCount++;
+
+    if (optionCount > 1) {
+        debugs(28, DBG_CRITICAL, "ERROR: Multiple options given for the server_name ACL");
+        return false;
+    }
+    return true;
+}