]> git.ipfire.org Git - thirdparty/squid.git/blame - src/acl/ServerName.cc
Source Format Enforcement (#763)
[thirdparty/squid.git] / src / acl / ServerName.cc
CommitLineData
69f69080 1/*
f70aedc4 2 * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
69f69080
CT
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9/* DEBUG: section 28 Access Control */
10
11#include "squid.h"
69f69080 12#include "acl/DomainData.h"
4eac3407 13#include "acl/FilledChecklist.h"
69f69080 14#include "acl/RegexData.h"
8823b1c9 15#include "acl/ServerName.h"
69f69080
CT
16#include "client_side.h"
17#include "fde.h"
d3dddfb5 18#include "http/Stream.h"
69f69080
CT
19#include "HttpRequest.h"
20#include "ipcache.h"
21#include "SquidString.h"
22#include "ssl/bio.h"
23#include "ssl/ServerBump.h"
24#include "ssl/support.h"
69f69080
CT
25
26// Compare function for tree search algorithms
27static int
28aclHostDomainCompare( char *const &a, char * const &b)
29{
30 const char *h = static_cast<const char *>(a);
31 const char *d = static_cast<const char *>(b);
32 debugs(28, 7, "Match:" << h << " <> " << d);
abbd7825 33 return matchDomainName(h, d, mdnHonorWildcards);
69f69080
CT
34}
35
36bool
37ACLServerNameData::match(const char *host)
38{
39 if (host == NULL)
40 return 0;
41
42 debugs(28, 3, "checking '" << host << "'");
43
44 char *h = const_cast<char *>(host);
45 char const * const * result = domains->find(h, aclHostDomainCompare);
46
47 debugs(28, 3, "'" << host << "' " << (result ? "found" : "NOT found"));
48
49 return (result != NULL);
50
51}
52
53ACLData<char const *> *
54ACLServerNameData::clone() const
55{
56 /* Splay trees don't clone yet. */
57 assert (!domains);
58 return new ACLServerNameData;
59}
60
61/// A helper function to be used with Ssl::matchX509CommonNames().
62/// \retval 0 when the name (cn or an alternate name) matches acl data
63/// \retval 1 when the name does not match
64template<class MatchType>
65int
66check_cert_domain( void *check_data, ASN1_STRING *cn_data)
67{
68 char cn[1024];
69 ACLData<MatchType> * data = (ACLData<MatchType> *)check_data;
70
71 if (cn_data->length > (int)sizeof(cn) - 1)
72 return 1; // ignore data that does not fit our buffer
8823b1c9 73
0f7f4cfc
AJ
74 char *s = reinterpret_cast<char *>(cn_data->data);
75 char *d = cn;
76 for (int i = 0; i < cn_data->length; ++i, ++d, ++s) {
77 if (*s == '\0')
78 return 1; // always a domain mismatch. contains 0x00
79 *d = *s;
80 }
69f69080
CT
81 cn[cn_data->length] = '\0';
82 debugs(28, 4, "Verifying certificate name/subjectAltName " << cn);
83 if (data->match(cn))
84 return 0;
85 return 1;
86}
87
88int
4eac3407 89ACLServerNameStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist)
69f69080
CT
90{
91 assert(checklist != NULL && checklist->request != NULL);
92
8d9e6d7f 93 const char *serverName = nullptr;
4f6990ec 94 SBuf clientSniKeeper; // because c_str() is not constant
8d9e6d7f 95 if (ConnStateData *conn = checklist->conn()) {
4f6990ec
CT
96 const char *clientRequestedServerName = nullptr;
97 clientSniKeeper = conn->tlsClientSni();
98 if (clientSniKeeper.isEmpty()) {
8d9e6d7f
CT
99 const char *host = checklist->request->url.host();
100 if (host && *host) // paranoid first condition: host() is never nil
4f6990ec
CT
101 clientRequestedServerName = host;
102 } else
103 clientRequestedServerName = clientSniKeeper.c_str();
104
105 if (useConsensus) {
106 X509 *peer_cert = conn->serverBump() ? conn->serverBump()->serverCert.get() : nullptr;
107 // use the client requested name if it matches the server
108 // certificate or if the certificate is not available
109 if (!peer_cert || Ssl::checkX509ServerValidity(peer_cert, clientRequestedServerName))
110 serverName = clientRequestedServerName;
111 } else if (useClientRequested)
112 serverName = clientRequestedServerName;
113 else { // either no options or useServerProvided
114 if (X509 *peer_cert = (conn->serverBump() ? conn->serverBump()->serverCert.get() : nullptr))
115 return Ssl::matchX509CommonNames(peer_cert, (void *)data, check_cert_domain<MatchType>);
116 if (!useServerProvided)
117 serverName = clientRequestedServerName;
8d9e6d7f 118 }
69f69080
CT
119 }
120
8d9e6d7f
CT
121 if (!serverName)
122 serverName = "none";
69f69080 123
8d9e6d7f 124 return data->match(serverName);
69f69080
CT
125}
126
4f6990ec
CT
127const Acl::Options &
128ACLServerNameStrategy::options()
129{
130 static const Acl::BooleanOption ClientRequested;
131 static const Acl::BooleanOption ServerProvided;
132 static const Acl::BooleanOption Consensus;
133 static const Acl::Options MyOptions = {
134 {"--client-requested", &ClientRequested},
135 {"--server-provided", &ServerProvided},
136 {"--consensus", &Consensus}
137 };
138
139 ClientRequested.linkWith(&useClientRequested);
140 ServerProvided.linkWith(&useServerProvided);
141 Consensus.linkWith(&useConsensus);
142 return MyOptions;
143}
144
145bool
146ACLServerNameStrategy::valid() const
147{
148 int optionCount = 0;
149
150 if (useClientRequested)
151 optionCount++;
152 if (useServerProvided)
153 optionCount++;
154 if (useConsensus)
155 optionCount++;
156
157 if (optionCount > 1) {
158 debugs(28, DBG_CRITICAL, "ERROR: Multiple options given for the server_name ACL");
159 return false;
160 }
161 return true;
162}
aa28452d 163