]>
Commit | Line | Data |
---|---|---|
bbc27441 | 1 | /* |
f70aedc4 | 2 | * Copyright (C) 1996-2021 The Squid Software Foundation and contributors |
bbc27441 AJ |
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 | ||
582c2af2 FC |
9 | #include "squid.h" |
10 | #include "acl/FilledChecklist.h" | |
351fe86d | 11 | #include "client_side.h" |
582c2af2 FC |
12 | #include "comm/Connection.h" |
13 | #include "comm/forward.h" | |
c59baaa8 | 14 | #include "DebugMessages.h" |
abdd93d0 | 15 | #include "ExternalACLEntry.h" |
d3dddfb5 | 16 | #include "http/Stream.h" |
582c2af2 FC |
17 | #include "HttpReply.h" |
18 | #include "HttpRequest.h" | |
4d5904f7 | 19 | #include "SquidConfig.h" |
2f1431ea | 20 | #if USE_AUTH |
351fe86d | 21 | #include "auth/AclProxyAuth.h" |
602d9612 | 22 | #include "auth/UserRequest.h" |
2f1431ea | 23 | #endif |
582c2af2 | 24 | |
351fe86d AR |
25 | CBDATA_CLASS_INIT(ACLFilledChecklist); |
26 | ||
351fe86d | 27 | ACLFilledChecklist::ACLFilledChecklist() : |
f53969cc SM |
28 | dst_rdns(NULL), |
29 | request (NULL), | |
30 | reply (NULL), | |
2f1431ea | 31 | #if USE_AUTH |
f53969cc | 32 | auth_user_request (NULL), |
2f1431ea | 33 | #endif |
351fe86d | 34 | #if SQUID_SNMP |
f53969cc | 35 | snmp_community(NULL), |
351fe86d | 36 | #endif |
cb4f4424 | 37 | #if USE_OPENSSL |
f53969cc | 38 | sslErrors(NULL), |
fa24d749 | 39 | #endif |
3248e962 | 40 | requestErrorType(ERR_MAX), |
f53969cc SM |
41 | conn_(NULL), |
42 | fd_(-1), | |
43 | destinationDomainChecked_(false), | |
44 | sourceDomainChecked_(false) | |
351fe86d | 45 | { |
4dd643d5 AJ |
46 | my_addr.setEmpty(); |
47 | src_addr.setEmpty(); | |
48 | dst_addr.setEmpty(); | |
351fe86d AR |
49 | rfc931[0] = '\0'; |
50 | } | |
51 | ||
351fe86d AR |
52 | ACLFilledChecklist::~ACLFilledChecklist() |
53 | { | |
54 | assert (!asyncInProgress()); | |
55 | ||
12ef783b AJ |
56 | safe_free(dst_rdns); // created by xstrdup(). |
57 | ||
351fe86d AR |
58 | HTTPMSGUNLOCK(request); |
59 | ||
60 | HTTPMSGUNLOCK(reply); | |
61 | ||
351fe86d AR |
62 | cbdataReferenceDone(conn_); |
63 | ||
cb4f4424 | 64 | #if USE_OPENSSL |
7a957a93 | 65 | cbdataReferenceDone(sslErrors); |
fa24d749 | 66 | #endif |
4fb72cb9 | 67 | |
351fe86d AR |
68 | debugs(28, 4, HERE << "ACLFilledChecklist destroyed " << this); |
69 | } | |
70 | ||
fbbea662 AJ |
71 | static void |
72 | showDebugWarning(const char *msg) | |
73 | { | |
74 | static uint16_t count = 0; | |
bdd92d83 | 75 | if (count > 10) |
fbbea662 AJ |
76 | return; |
77 | ||
78 | ++count; | |
c59baaa8 | 79 | debugs(28, Important(58), "ALE missing " << msg); |
fbbea662 AJ |
80 | } |
81 | ||
82 | void | |
cb365059 | 83 | ACLFilledChecklist::verifyAle() const |
fbbea662 AJ |
84 | { |
85 | // make sure the ALE fields used by Format::assemble to | |
86 | // fill the old external_acl_type codes are set if any | |
87 | // data on them exists in the Checklist | |
88 | ||
89 | if (!al->cache.port && conn()) { | |
90 | showDebugWarning("listening port"); | |
91 | al->cache.port = conn()->port; | |
92 | } | |
93 | ||
94 | if (request) { | |
95 | if (!al->request) { | |
96 | showDebugWarning("HttpRequest object"); | |
cb365059 EB |
97 | // XXX: al->request should be original, |
98 | // but the request may be already adapted | |
fbbea662 AJ |
99 | al->request = request; |
100 | HTTPMSGLOCK(al->request); | |
101 | } | |
102 | ||
103 | if (!al->adapted_request) { | |
104 | showDebugWarning("adapted HttpRequest object"); | |
105 | al->adapted_request = request; | |
106 | HTTPMSGLOCK(al->adapted_request); | |
107 | } | |
108 | ||
f57ae909 | 109 | if (al->url.isEmpty()) { |
fbbea662 | 110 | showDebugWarning("URL"); |
cb365059 EB |
111 | // XXX: al->url should be the request URL from client, |
112 | // but request->url may be different (e.g.,redirected) | |
57a5679b | 113 | al->url = request->effectiveRequestUri(); |
fbbea662 AJ |
114 | } |
115 | } | |
116 | ||
117 | if (reply && !al->reply) { | |
118 | showDebugWarning("HttpReply object"); | |
119 | al->reply = reply; | |
fbbea662 AJ |
120 | } |
121 | ||
122 | #if USE_IDENT | |
c1ebba41 | 123 | if (*rfc931 && !al->cache.rfc931) { |
fbbea662 AJ |
124 | showDebugWarning("IDENT"); |
125 | al->cache.rfc931 = xstrdup(rfc931); | |
126 | } | |
127 | #endif | |
128 | } | |
129 | ||
cb365059 EB |
130 | void |
131 | ACLFilledChecklist::syncAle(HttpRequest *adaptedRequest, const char *logUri) const | |
132 | { | |
133 | if (!al) | |
134 | return; | |
7a023df9 | 135 | if (adaptedRequest && !al->adapted_request) { |
cb365059 EB |
136 | al->adapted_request = adaptedRequest; |
137 | HTTPMSGLOCK(al->adapted_request); | |
138 | } | |
7a023df9 | 139 | if (logUri && al->url.isEmpty()) |
cb365059 EB |
140 | al->url = logUri; |
141 | } | |
142 | ||
351fe86d AR |
143 | ConnStateData * |
144 | ACLFilledChecklist::conn() const | |
145 | { | |
6cf166fc | 146 | return cbdataReferenceValid(conn_) ? conn_ : nullptr; |
351fe86d AR |
147 | } |
148 | ||
149 | void | |
e227da8d | 150 | ACLFilledChecklist::setConn(ConnStateData *aConn) |
351fe86d | 151 | { |
e227da8d AR |
152 | if (conn_ == aConn) |
153 | return; // no new information | |
154 | ||
155 | // no conn_ replacement/removal to reduce inconsistent fill concerns | |
156 | assert(!conn_); | |
157 | assert(aConn); | |
158 | ||
159 | // To reduce inconsistent fill concerns, we should be the only ones calling | |
160 | // fillConnectionLevelDetails(). Set conn_ first so that the filling method | |
161 | // can detect (some) direct calls from others. | |
351fe86d | 162 | conn_ = cbdataReference(aConn); |
e227da8d | 163 | aConn->fillConnectionLevelDetails(*this); |
351fe86d AR |
164 | } |
165 | ||
166 | int | |
167 | ACLFilledChecklist::fd() const | |
168 | { | |
6cf166fc EB |
169 | const auto c = conn(); |
170 | return (c && c->clientConnection) ? c->clientConnection->fd : fd_; | |
351fe86d AR |
171 | } |
172 | ||
173 | void | |
174 | ACLFilledChecklist::fd(int aDescriptor) | |
175 | { | |
6cf166fc EB |
176 | const auto c = conn(); |
177 | assert(!c || !c->clientConnection || c->clientConnection->fd == aDescriptor); | |
351fe86d AR |
178 | fd_ = aDescriptor; |
179 | } | |
180 | ||
181 | bool | |
182 | ACLFilledChecklist::destinationDomainChecked() const | |
183 | { | |
184 | return destinationDomainChecked_; | |
185 | } | |
186 | ||
187 | void | |
188 | ACLFilledChecklist::markDestinationDomainChecked() | |
189 | { | |
190 | assert (!finished() && !destinationDomainChecked()); | |
191 | destinationDomainChecked_ = true; | |
192 | } | |
193 | ||
194 | bool | |
195 | ACLFilledChecklist::sourceDomainChecked() const | |
196 | { | |
197 | return sourceDomainChecked_; | |
198 | } | |
199 | ||
200 | void | |
201 | ACLFilledChecklist::markSourceDomainChecked() | |
202 | { | |
203 | assert (!finished() && !sourceDomainChecked()); | |
204 | sourceDomainChecked_ = true; | |
205 | } | |
206 | ||
207 | /* | |
208 | * There are two common ACLFilledChecklist lifecycles paths: | |
209 | * | |
210 | * A) Using aclCheckFast(): The caller creates an ACLFilledChecklist object | |
211 | * on stack and calls aclCheckFast(). | |
212 | * | |
213 | * B) Using aclNBCheck() and callbacks: The caller allocates an | |
214 | * ACLFilledChecklist object (via operator new) and passes it to | |
215 | * aclNBCheck(). Control eventually passes to ACLChecklist::checkCallback(), | |
216 | * which will invoke the callback function as requested by the | |
217 | * original caller of aclNBCheck(). This callback function must | |
218 | * *not* delete the list. After the callback function returns, | |
219 | * checkCallback() will delete the list (i.e., self). | |
220 | */ | |
f4462b38 | 221 | ACLFilledChecklist::ACLFilledChecklist(const acl_access *A, HttpRequest *http_request, const char *ident): |
f53969cc SM |
222 | dst_rdns(NULL), |
223 | request(NULL), | |
224 | reply(NULL), | |
cc8c4af2 | 225 | #if USE_AUTH |
f53969cc | 226 | auth_user_request(NULL), |
2f1431ea | 227 | #endif |
351fe86d | 228 | #if SQUID_SNMP |
f53969cc | 229 | snmp_community(NULL), |
351fe86d | 230 | #endif |
cb4f4424 | 231 | #if USE_OPENSSL |
f53969cc | 232 | sslErrors(NULL), |
fa24d749 | 233 | #endif |
cc8c4af2 | 234 | requestErrorType(ERR_MAX), |
f53969cc SM |
235 | conn_(NULL), |
236 | fd_(-1), | |
237 | destinationDomainChecked_(false), | |
238 | sourceDomainChecked_(false) | |
351fe86d | 239 | { |
4dd643d5 AJ |
240 | my_addr.setEmpty(); |
241 | src_addr.setEmpty(); | |
242 | dst_addr.setEmpty(); | |
351fe86d | 243 | rfc931[0] = '\0'; |
af6a12ee | 244 | |
3d29e126 | 245 | changeAcl(A); |
819be284 EB |
246 | setRequest(http_request); |
247 | setIdent(ident); | |
248 | } | |
351fe86d | 249 | |
819be284 EB |
250 | void ACLFilledChecklist::setRequest(HttpRequest *httpRequest) |
251 | { | |
252 | assert(!request); | |
253 | if (httpRequest) { | |
254 | request = httpRequest; | |
b248c2a3 | 255 | HTTPMSGLOCK(request); |
351fe86d AR |
256 | #if FOLLOW_X_FORWARDED_FOR |
257 | if (Config.onoff.acl_uses_indirect_client) | |
258 | src_addr = request->indirect_client_addr; | |
259 | else | |
260 | #endif /* FOLLOW_X_FORWARDED_FOR */ | |
261 | src_addr = request->client_addr; | |
262 | my_addr = request->my_addr; | |
16a16ffe | 263 | |
e227da8d AR |
264 | if (const auto cmgr = request->clientConnectionManager.get()) |
265 | setConn(cmgr); | |
351fe86d | 266 | } |
819be284 | 267 | } |
351fe86d | 268 | |
819be284 EB |
269 | void |
270 | ACLFilledChecklist::setIdent(const char *ident) | |
271 | { | |
351fe86d | 272 | #if USE_IDENT |
819be284 | 273 | assert(!rfc931[0]); |
351fe86d AR |
274 | if (ident) |
275 | xstrncpy(rfc931, ident, USER_IDENT_SZ); | |
276 | #endif | |
277 | } | |
f53969cc | 278 |