]>
Commit | Line | Data |
---|---|---|
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 | |
27 | static int | |
28 | aclHostDomainCompare( 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 | ||
36 | bool | |
37 | ACLServerNameData::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 | ||
53 | ACLData<char const *> * | |
54 | ACLServerNameData::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 | |
64 | template<class MatchType> | |
65 | int | |
66 | check_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 | ||
88 | int | |
4eac3407 | 89 | ACLServerNameStrategy::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 |
127 | const Acl::Options & |
128 | ACLServerNameStrategy::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 | ||
145 | bool | |
146 | ACLServerNameStrategy::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 |