/*
- * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
+ * Copyright (C) 1996-2018 The Squid Software Foundation and contributors
*
* Squid software is distributed under GPLv2+ license and includes
* contributions from numerous individuals and organizations.
/* 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"
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
}
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;
+ 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->url.host();
-
- if (serverName && data->match(serverName)) {
- return 1;
- }
+ if (!serverName)
+ serverName = "none";
- return data->match("none");
+ return data->match(serverName);
}
-ACLServerNameStrategy *
-ACLServerNameStrategy::Instance()
+const Acl::Options &
+ACLServerNameStrategy::options()
{
- return &Instance_;
+ static const Acl::BooleanOption ClientRequested;
+ static const Acl::BooleanOption ServerProvided;
+ static const Acl::BooleanOption Consensus;
+ static const Acl::Options MyOptions = {
+ {"--client-requested", &ClientRequested},
+ {"--server-provided", &ServerProvided},
+ {"--consensus", &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;
+}