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