]> git.ipfire.org Git - thirdparty/squid.git/blame - src/acl/Checklist.cc
Renamed squid.h to squid-old.h and config.h to squid.h
[thirdparty/squid.git] / src / acl / Checklist.cc
CommitLineData
225b7b10 1/*
262a0e14 2 * $Id$
225b7b10 3 *
4 * DEBUG: section 28 Access Control
5 * AUTHOR: Duane Wessels
6 *
7 * SQUID Web Proxy Cache http://www.squid-cache.org/
8 * ----------------------------------------------------------
9 *
10 * Squid is the result of efforts by numerous individuals from
11 * the Internet community; see the CONTRIBUTORS file for full
12 * details. Many organizations have provided support for Squid's
13 * development; see the SPONSORS file for full details. Squid is
14 * Copyrighted (C) 2001 by the Regents of the University of
15 * California; see the COPYRIGHT file for full details. Squid
16 * incorporates software developed and/or copyrighted by other
17 * sources; see the CREDITS file for full details.
18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
26ac0430 23 *
225b7b10 24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
26ac0430 28 *
225b7b10 29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
32 *
33 * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
34 */
35
f7f3304a 36#include "squid-old.h"
351fe86d 37#include "acl/Checklist.h"
225b7b10 38
39allow_t const &
40ACLChecklist::currentAnswer() const
41{
42 return allow_;
43}
44
45void
46ACLChecklist::currentAnswer(allow_t const newAnswer)
47{
48 allow_ = newAnswer;
49}
62e76326 50
225b7b10 51void
2efeb0b7 52ACLChecklist::matchNonBlocking()
225b7b10 53{
b6f25d16 54 if (checking())
62e76326 55 return;
56
070b2c0c 57 /** Deny if no rules present. */
225b7b10 58 currentAnswer(ACCESS_DENIED);
62e76326 59
315b856d 60 if (callerGone()) {
26ac0430
AJ
61 checkCallback(currentAnswer());
62 return;
315b856d 63 }
64
070b2c0c
AJ
65 /** The ACL List should NEVER be NULL when calling this method.
66 * Always caller should check for NULL and handle appropriate to its needs first.
67 * We cannot select a sensible default for all callers here. */
68 if (accessList == NULL) {
69 debugs(28, DBG_CRITICAL, "SECURITY ERROR: ACL " << this << " checked with nothing to match against!!");
70 currentAnswer(ACCESS_DENIED);
71 checkCallback(currentAnswer());
72 return;
73 }
74
225b7b10 75 /* NOTE: This holds a cbdata reference to the current access_list
76 * entry, not the whole list.
77 */
78 while (accessList != NULL) {
070b2c0c 79 /** \par
62e76326 80 * If the _acl_access is no longer valid (i.e. its been
81 * freed because of a reconfigure), then bail on this
82 * access check. For now, return ACCESS_DENIED.
83 */
84
85 if (!cbdataReferenceValid(accessList)) {
86 cbdataReferenceDone(accessList);
bf8fe701 87 debugs(28, 4, "ACLChecklist::check: " << this << " accessList is invalid");
62e76326 88 continue;
89 }
90
91 checking (true);
92 checkAccessList();
93 checking (false);
94
95 if (asyncInProgress()) {
96 return;
97 }
98
99 if (finished()) {
070b2c0c
AJ
100 /** \par
101 * Either the request is allowed, denied, requires authentication.
62e76326 102 */
bf8fe701 103 debugs(28, 3, "ACLChecklist::check: " << this << " match found, calling back with " << currentAnswer());
62e76326 104 cbdataReferenceDone(accessList); /* A */
105 checkCallback(currentAnswer());
106 /* From here on in, this may be invalid */
107 return;
108 }
109
110 /*
111 * Reference the next access entry
112 */
113 const acl_access *A = accessList;
114
115 assert (A);
116
117 accessList = cbdataReference(A->next);
118
119 cbdataReferenceDone(A);
225b7b10 120 }
62e76326 121
070b2c0c
AJ
122 /** If dropped off the end of the list return inversion of last line allow/deny action. */
123 debugs(28, 3, HERE << this << " NO match found, returning " <<
bf8fe701 124 (currentAnswer() != ACCESS_DENIED ? ACCESS_DENIED : ACCESS_ALLOWED));
62e76326 125
225b7b10 126 checkCallback(currentAnswer() != ACCESS_DENIED ? ACCESS_DENIED : ACCESS_ALLOWED);
127}
128
129bool
130ACLChecklist::asyncInProgress() const
131{
132 return async_;
133}
134
135void
136ACLChecklist::asyncInProgress(bool const newAsync)
137{
3841dd46 138 assert (!finished() && !(asyncInProgress() && newAsync));
225b7b10 139 async_ = newAsync;
bf8fe701 140 debugs(28, 3, "ACLChecklist::asyncInProgress: " << this <<
141 " async set to " << async_);
225b7b10 142}
143
144bool
145ACLChecklist::finished() const
146{
147 return finished_;
148}
149
150void
151ACLChecklist::markFinished()
152{
3841dd46 153 assert (!finished() && !asyncInProgress());
225b7b10 154 finished_ = true;
bf8fe701 155 debugs(28, 3, "ACLChecklist::markFinished: " << this <<
156 " checklist processing finished");
225b7b10 157}
158
c35e260d 159void
160ACLChecklist::preCheck()
161{
bf8fe701 162 debugs(28, 3, "ACLChecklist::preCheck: " << this << " checking '" << accessList->cfgline << "'");
c35e260d 163 /* what is our result on a match? */
164 currentAnswer(accessList->allow);
165}
166
225b7b10 167void
168ACLChecklist::checkAccessList()
169{
c35e260d 170 preCheck();
225b7b10 171 /* does the current AND clause match */
2efeb0b7 172 matchAclList(accessList->aclList, false);
225b7b10 173}
174
175void
176ACLChecklist::checkForAsync()
177{
3841dd46 178 asyncState()->checkForAsync(this);
225b7b10 179}
180
351fe86d
AR
181// ACLFilledChecklist overwrites this to unclock something before we
182// "delete this"
225b7b10 183void
184ACLChecklist::checkCallback(allow_t answer)
185{
2efeb0b7 186 ACLCB *callback_;
225b7b10 187 void *cbdata_;
bf8fe701 188 debugs(28, 3, "ACLChecklist::checkCallback: " << this << " answer=" << answer);
189
225b7b10 190 callback_ = callback;
191 callback = NULL;
62e76326 192
225b7b10 193 if (cbdataReferenceValidDone(callback_data, &cbdata_))
62e76326 194 callback_(answer, cbdata_);
195
00d77d6b 196 delete this;
225b7b10 197}
62e76326 198
48071869 199void
76cd39d7 200ACLChecklist::matchAclList(const ACLList * head, bool const fast)
225b7b10 201{
202 PROF_start(aclMatchAclList);
76cd39d7 203 const ACLList *node = head;
62e76326 204
ba63443a 205 finished_ = false;
206
225b7b10 207 while (node) {
62e76326 208 bool nodeMatched = node->matches(this);
209
210 if (fast)
211 changeState(NullState::Instance());
212
26ac0430
AJ
213 if (finished()) {
214 PROF_stop(aclMatchAclList);
215 return;
216 }
ff3f3722 217
62e76326 218 if (!nodeMatched || state_ != NullState::Instance()) {
bf8fe701 219
ab321f4b 220 bool async = state_ != NullState::Instance();
221
48071869 222 checkForAsync();
501b58f9 223
ab321f4b 224 bool async_in_progress = asyncInProgress();
bf8fe701 225 debugs(28, 3, "aclmatchAclList: async=" << (async ? 1 : 0) <<
226 " nodeMatched=" << (nodeMatched ? 1 : 0) <<
227 " async_in_progress=" << (async_in_progress ? 1 : 0) <<
ff3f3722 228 " lastACLResult() = " << (lastACLResult() ? 1 : 0) <<
26ac0430 229 " finished() = " << finished());
ff3f3722 230
26ac0430 231 if (finished()) {
d325a2eb 232 debugs(28, 3, "aclmatchAclList: " << this << " returning (AND list entry failed to match)");
26ac0430
AJ
233 PROF_stop(aclMatchAclList);
234 return;
235 }
ab321f4b 236
237 if (async && nodeMatched && !asyncInProgress() && lastACLResult()) {
238 // async acl, but using cached response, and it was a match
239 node = node->next;
240 continue;
241 }
242
d325a2eb 243 debugs(28, 3, "aclmatchAclList: " << this << " returning (AND list entry awaiting an async lookup)");
62e76326 244 PROF_stop(aclMatchAclList);
48071869 245 return;
62e76326 246 }
247
248 node = node->next;
225b7b10 249 }
62e76326 250
bf8fe701 251 debugs(28, 3, "aclmatchAclList: " << this << " returning true (AND list satisfied)");
252
48071869 253 markFinished();
225b7b10 254 PROF_stop(aclMatchAclList);
225b7b10 255}
256
cc192b50 257ACLChecklist::ACLChecklist() :
258 accessList (NULL),
4f0ef8e8 259 callback (NULL),
62e76326 260 callback_data (NULL),
62e76326 261 async_(false),
262 finished_(false),
263 allow_(ACCESS_DENIED),
264 state_(NullState::Instance()),
ab321f4b 265 lastACLResult_(false)
225b7b10 266{
225b7b10 267}
268
269ACLChecklist::~ACLChecklist()
270{
271 assert (!asyncInProgress());
62e76326 272
225b7b10 273 cbdataReferenceDone(accessList);
62e76326 274
bf8fe701 275 debugs(28, 4, "ACLChecklist::~ACLChecklist: destroyed " << this);
225b7b10 276}
277
278
225b7b10 279void
280ACLChecklist::AsyncState::changeState (ACLChecklist *checklist, AsyncState *newState) const
281{
282 checklist->changeState(newState);
283}
284
285ACLChecklist::NullState *
286ACLChecklist::NullState::Instance()
287{
288 return &_instance;
289}
290
291void
292ACLChecklist::NullState::checkForAsync(ACLChecklist *) const
26ac0430 293{}
225b7b10 294
295ACLChecklist::NullState ACLChecklist::NullState::_instance;
296
297void
298ACLChecklist::changeState (AsyncState *newState)
299{
300 /* only change from null to active and back again,
301 * not active to active.
302 * relax this once conversion to states is complete
303 * RBC 02 2003
304 */
305 assert (state_ == NullState::Instance() || newState == NullState::Instance());
306 state_ = newState;
307}
308
309ACLChecklist::AsyncState *
310ACLChecklist::asyncState() const
311{
312 return state_;
313}
314
b50e327b
AJ
315/**
316 * Kick off a non-blocking (slow) ACL access list test
317 *
318 * NP: this should probably be made Async now.
319 */
225b7b10 320void
2efeb0b7 321ACLChecklist::nonBlockingCheck(ACLCB * callback_, void *callback_data_)
225b7b10 322{
323 callback = callback_;
324 callback_data = cbdataReference(callback_data_);
2efeb0b7
AJ
325 matchNonBlocking();
326}
327
328allow_t const &
329ACLChecklist::fastCheck(const ACLList * list)
330{
331 PROF_start(aclCheckFast);
332 currentAnswer(ACCESS_DUNNO);
333 matchAclList(list, true);
334 // assume ALLOWED on matches due to not having an acl_access object
335 if (finished())
336 currentAnswer(ACCESS_ALLOWED);
337 PROF_stop(aclCheckFast);
338 return currentAnswer();
225b7b10 339}
340
b448c119 341/* Warning: do not cbdata lock this here - it
342 * may be static or on the stack
343 */
2efeb0b7 344allow_t const &
b448c119 345ACLChecklist::fastCheck()
346{
347 PROF_start(aclCheckFast);
2efeb0b7
AJ
348 currentAnswer(ACCESS_DUNNO);
349
bf8fe701 350 debugs(28, 5, "aclCheckFast: list: " << accessList);
bea5dacc
CT
351 const acl_access *acl = cbdataReference(accessList);
352 while (acl != NULL && cbdataReferenceValid(acl)) {
2efeb0b7
AJ
353 matchAclList(acl->aclList, true);
354 if (finished()) {
b2021431 355 currentAnswer(acl->allow);
b448c119 356 PROF_stop(aclCheckFast);
bea5dacc 357 cbdataReferenceDone(acl);
2efeb0b7 358 return currentAnswer();
b448c119 359 }
360
fddded8f 361 /*
362 * Reference the next access entry
363 */
bea5dacc
CT
364 const acl_access *A = acl;
365 acl = cbdataReference(acl->next);
fddded8f 366 cbdataReferenceDone(A);
b448c119 367 }
368
2efeb0b7 369 debugs(28, 5, "aclCheckFast: no matches, returning: " << currentAnswer());
b448c119 370 PROF_stop(aclCheckFast);
2efeb0b7
AJ
371
372 return currentAnswer();
b448c119 373}
374
375
b6f25d16 376bool
377ACLChecklist::checking() const
378{
379 return checking_;
380}
381
382void
383ACLChecklist::checking (bool const newValue)
384{
385 checking_ = newValue;
386}
ef1955a5 387
351fe86d
AR
388bool
389ACLChecklist::callerGone()
b448c119 390{
351fe86d 391 return !cbdataReferenceValid(callback_data);
b448c119 392}