]>
Commit | Line | Data |
---|---|---|
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 | ||
36 | #include "squid.h" | |
37 | #include "ACLChecklist.h" | |
225b7b10 | 38 | #include "HttpRequest.h" |
7dc5f514 | 39 | #include "HttpReply.h" |
225b7b10 | 40 | #include "authenticate.h" |
225b7b10 | 41 | #include "ACLProxyAuth.h" |
a46d2c0e | 42 | #include "client_side.h" |
2d2b0bb7 | 43 | #include "auth/UserRequest.h" |
225b7b10 | 44 | |
45 | int | |
46 | ACLChecklist::authenticated() | |
47 | { | |
48 | http_hdr_type headertype; | |
62e76326 | 49 | |
225b7b10 | 50 | if (NULL == request) { |
62e76326 | 51 | fatal ("requiresRequest SHOULD have been true for this ACL!!"); |
52 | return 0; | |
d048c262 | 53 | } else if (request->flags.accelerated) { |
62e76326 | 54 | /* WWW authorization on accelerated requests */ |
55 | headertype = HDR_AUTHORIZATION; | |
f165d2fb | 56 | } else if (request->flags.intercepted || request->flags.spoof_client_ip) { |
2ad20b4f | 57 | debugs(28, DBG_IMPORTANT, HERE << " authentication not applicable on intercepted requests."); |
62e76326 | 58 | return -1; |
d048c262 | 59 | } else { |
60 | /* Proxy authorization on proxy requests */ | |
61 | headertype = HDR_PROXY_AUTHORIZATION; | |
225b7b10 | 62 | } |
62e76326 | 63 | |
225b7b10 | 64 | /* get authed here */ |
6bf4f823 | 65 | /* Note: this fills in auth_user_request when applicable */ |
4f0ef8e8 | 66 | /* |
67 | * DPW 2007-05-08 | |
68 | * tryToAuthenticateAndSetAuthUser used to try to lock and | |
69 | * unlock auth_user_request on our behalf, but it was too | |
70 | * ugly and hard to follow. Now we do our own locking here. | |
71 | * | |
72 | * I'm not sure what tryToAuthenticateAndSetAuthUser does when | |
73 | * auth_user_request is set before calling. I'm tempted to | |
74 | * unlock and set it to NULL, but it seems safer to save the | |
75 | * pointer before calling and unlock it afterwards. If the | |
76 | * pointer doesn't change then its a no-op. | |
77 | */ | |
78 | AuthUserRequest *old_auth_user_request = auth_user_request; | |
79 | auth_acl_t result = AuthUserRequest::tryToAuthenticateAndSetAuthUser (&auth_user_request, headertype, request, conn(), src_addr); | |
80 | if (auth_user_request) | |
26ac0430 | 81 | AUTHUSERREQUESTLOCK(auth_user_request, "ACLChecklist"); |
4f0ef8e8 | 82 | AUTHUSERREQUESTUNLOCK(old_auth_user_request, "old ACLChecklist"); |
83 | switch (result) { | |
62e76326 | 84 | |
225b7b10 | 85 | case AUTH_ACL_CANNOT_AUTHENTICATE: |
bf8fe701 | 86 | debugs(28, 4, "aclMatchAcl: returning 0 user authenticated but not authorised."); |
62e76326 | 87 | return 0; |
88 | ||
225b7b10 | 89 | case AUTH_AUTHENTICATED: |
8777d90e | 90 | |
62e76326 | 91 | return 1; |
92 | break; | |
93 | ||
225b7b10 | 94 | case AUTH_ACL_HELPER: |
bf8fe701 | 95 | debugs(28, 4, "aclMatchAcl: returning 0 sending credentials to helper."); |
62e76326 | 96 | changeState (ProxyAuthLookup::Instance()); |
97 | return 0; | |
98 | ||
225b7b10 | 99 | case AUTH_ACL_CHALLENGE: |
bf8fe701 | 100 | debugs(28, 4, "aclMatchAcl: returning 0 sending authentication challenge."); |
62e76326 | 101 | changeState (ProxyAuthNeeded::Instance()); |
102 | return 0; | |
103 | ||
225b7b10 | 104 | default: |
62e76326 | 105 | fatal("unexpected authenticateAuthenticate reply\n"); |
106 | return 0; | |
225b7b10 | 107 | } |
108 | } | |
109 | ||
110 | allow_t const & | |
111 | ACLChecklist::currentAnswer() const | |
112 | { | |
113 | return allow_; | |
114 | } | |
115 | ||
116 | void | |
117 | ACLChecklist::currentAnswer(allow_t const newAnswer) | |
118 | { | |
119 | allow_ = newAnswer; | |
120 | } | |
62e76326 | 121 | |
225b7b10 | 122 | void |
123 | ACLChecklist::check() | |
124 | { | |
b6f25d16 | 125 | if (checking()) |
62e76326 | 126 | return; |
127 | ||
070b2c0c | 128 | /** Deny if no rules present. */ |
225b7b10 | 129 | currentAnswer(ACCESS_DENIED); |
62e76326 | 130 | |
315b856d | 131 | if (callerGone()) { |
26ac0430 AJ |
132 | checkCallback(currentAnswer()); |
133 | return; | |
315b856d | 134 | } |
135 | ||
070b2c0c AJ |
136 | /** The ACL List should NEVER be NULL when calling this method. |
137 | * Always caller should check for NULL and handle appropriate to its needs first. | |
138 | * We cannot select a sensible default for all callers here. */ | |
139 | if (accessList == NULL) { | |
140 | debugs(28, DBG_CRITICAL, "SECURITY ERROR: ACL " << this << " checked with nothing to match against!!"); | |
141 | currentAnswer(ACCESS_DENIED); | |
142 | checkCallback(currentAnswer()); | |
143 | return; | |
144 | } | |
145 | ||
225b7b10 | 146 | /* NOTE: This holds a cbdata reference to the current access_list |
147 | * entry, not the whole list. | |
148 | */ | |
149 | while (accessList != NULL) { | |
070b2c0c | 150 | /** \par |
62e76326 | 151 | * If the _acl_access is no longer valid (i.e. its been |
152 | * freed because of a reconfigure), then bail on this | |
153 | * access check. For now, return ACCESS_DENIED. | |
154 | */ | |
155 | ||
156 | if (!cbdataReferenceValid(accessList)) { | |
157 | cbdataReferenceDone(accessList); | |
bf8fe701 | 158 | debugs(28, 4, "ACLChecklist::check: " << this << " accessList is invalid"); |
62e76326 | 159 | continue; |
160 | } | |
161 | ||
162 | checking (true); | |
163 | checkAccessList(); | |
164 | checking (false); | |
165 | ||
166 | if (asyncInProgress()) { | |
167 | return; | |
168 | } | |
169 | ||
170 | if (finished()) { | |
070b2c0c AJ |
171 | /** \par |
172 | * Either the request is allowed, denied, requires authentication. | |
62e76326 | 173 | */ |
bf8fe701 | 174 | debugs(28, 3, "ACLChecklist::check: " << this << " match found, calling back with " << currentAnswer()); |
62e76326 | 175 | cbdataReferenceDone(accessList); /* A */ |
176 | checkCallback(currentAnswer()); | |
177 | /* From here on in, this may be invalid */ | |
178 | return; | |
179 | } | |
180 | ||
181 | /* | |
182 | * Reference the next access entry | |
183 | */ | |
184 | const acl_access *A = accessList; | |
185 | ||
186 | assert (A); | |
187 | ||
188 | accessList = cbdataReference(A->next); | |
189 | ||
190 | cbdataReferenceDone(A); | |
225b7b10 | 191 | } |
62e76326 | 192 | |
070b2c0c AJ |
193 | /** If dropped off the end of the list return inversion of last line allow/deny action. */ |
194 | debugs(28, 3, HERE << this << " NO match found, returning " << | |
bf8fe701 | 195 | (currentAnswer() != ACCESS_DENIED ? ACCESS_DENIED : ACCESS_ALLOWED)); |
62e76326 | 196 | |
225b7b10 | 197 | checkCallback(currentAnswer() != ACCESS_DENIED ? ACCESS_DENIED : ACCESS_ALLOWED); |
198 | } | |
199 | ||
200 | bool | |
201 | ACLChecklist::asyncInProgress() const | |
202 | { | |
203 | return async_; | |
204 | } | |
205 | ||
206 | void | |
207 | ACLChecklist::asyncInProgress(bool const newAsync) | |
208 | { | |
3841dd46 | 209 | assert (!finished() && !(asyncInProgress() && newAsync)); |
225b7b10 | 210 | async_ = newAsync; |
bf8fe701 | 211 | debugs(28, 3, "ACLChecklist::asyncInProgress: " << this << |
212 | " async set to " << async_); | |
225b7b10 | 213 | } |
214 | ||
215 | bool | |
216 | ACLChecklist::finished() const | |
217 | { | |
218 | return finished_; | |
219 | } | |
220 | ||
221 | void | |
222 | ACLChecklist::markFinished() | |
223 | { | |
3841dd46 | 224 | assert (!finished() && !asyncInProgress()); |
225b7b10 | 225 | finished_ = true; |
bf8fe701 | 226 | debugs(28, 3, "ACLChecklist::markFinished: " << this << |
227 | " checklist processing finished"); | |
225b7b10 | 228 | } |
229 | ||
c35e260d | 230 | void |
231 | ACLChecklist::preCheck() | |
232 | { | |
bf8fe701 | 233 | debugs(28, 3, "ACLChecklist::preCheck: " << this << " checking '" << accessList->cfgline << "'"); |
c35e260d | 234 | /* what is our result on a match? */ |
235 | currentAnswer(accessList->allow); | |
236 | } | |
237 | ||
225b7b10 | 238 | void |
239 | ACLChecklist::checkAccessList() | |
240 | { | |
c35e260d | 241 | preCheck(); |
225b7b10 | 242 | /* does the current AND clause match */ |
ef1955a5 | 243 | matchAclListSlow(accessList->aclList); |
225b7b10 | 244 | } |
245 | ||
246 | void | |
247 | ACLChecklist::checkForAsync() | |
248 | { | |
3841dd46 | 249 | asyncState()->checkForAsync(this); |
225b7b10 | 250 | } |
251 | ||
252 | void | |
253 | ACLChecklist::checkCallback(allow_t answer) | |
254 | { | |
255 | PF *callback_; | |
256 | void *cbdata_; | |
bf8fe701 | 257 | debugs(28, 3, "ACLChecklist::checkCallback: " << this << " answer=" << answer); |
258 | ||
6bf4f823 | 259 | /* During reconfigure, we can end up not finishing call |
260 | * sequences into the auth code */ | |
261 | ||
262 | if (auth_user_request) { | |
263 | /* the checklist lock */ | |
26ac0430 | 264 | AUTHUSERREQUESTUNLOCK(auth_user_request, "ACLChecklist"); |
6bf4f823 | 265 | /* it might have been connection based */ |
4d3a24ca | 266 | assert(conn() != NULL); |
26ac0430 AJ |
267 | /* |
268 | * DPW 2007-05-08 | |
269 | * yuck, this make me uncomfortable. why do this here? | |
270 | * ConnStateData will do its own unlocking. | |
271 | */ | |
272 | AUTHUSERREQUESTUNLOCK(conn()->auth_user_request, "conn via ACLChecklist"); | |
6bf4f823 | 273 | conn()->auth_type = AUTH_BROKEN; |
6bf4f823 | 274 | } |
62e76326 | 275 | |
225b7b10 | 276 | callback_ = callback; |
277 | callback = NULL; | |
62e76326 | 278 | |
225b7b10 | 279 | if (cbdataReferenceValidDone(callback_data, &cbdata_)) |
62e76326 | 280 | callback_(answer, cbdata_); |
281 | ||
00d77d6b | 282 | delete this; |
225b7b10 | 283 | } |
62e76326 | 284 | |
5ea3aff4 | 285 | void |
76cd39d7 | 286 | ACLChecklist::matchAclListSlow(const ACLList * list) |
5ea3aff4 | 287 | { |
288 | matchAclList(list, false); | |
289 | } | |
290 | ||
48071869 | 291 | void |
76cd39d7 | 292 | ACLChecklist::matchAclList(const ACLList * head, bool const fast) |
225b7b10 | 293 | { |
294 | PROF_start(aclMatchAclList); | |
76cd39d7 | 295 | const ACLList *node = head; |
62e76326 | 296 | |
ba63443a | 297 | finished_ = false; |
298 | ||
225b7b10 | 299 | while (node) { |
62e76326 | 300 | bool nodeMatched = node->matches(this); |
301 | ||
302 | if (fast) | |
303 | changeState(NullState::Instance()); | |
304 | ||
26ac0430 AJ |
305 | if (finished()) { |
306 | PROF_stop(aclMatchAclList); | |
307 | return; | |
308 | } | |
ff3f3722 | 309 | |
62e76326 | 310 | if (!nodeMatched || state_ != NullState::Instance()) { |
bf8fe701 | 311 | debugs(28, 3, "aclmatchAclList: " << this << " returning false (AND list entry failed to match)"); |
312 | ||
ab321f4b | 313 | bool async = state_ != NullState::Instance(); |
314 | ||
48071869 | 315 | checkForAsync(); |
501b58f9 | 316 | |
ab321f4b | 317 | bool async_in_progress = asyncInProgress(); |
bf8fe701 | 318 | debugs(28, 3, "aclmatchAclList: async=" << (async ? 1 : 0) << |
319 | " nodeMatched=" << (nodeMatched ? 1 : 0) << | |
320 | " async_in_progress=" << (async_in_progress ? 1 : 0) << | |
ff3f3722 | 321 | " lastACLResult() = " << (lastACLResult() ? 1 : 0) << |
26ac0430 | 322 | " finished() = " << finished()); |
ff3f3722 | 323 | |
26ac0430 AJ |
324 | if (finished()) { |
325 | PROF_stop(aclMatchAclList); | |
326 | return; | |
327 | } | |
ab321f4b | 328 | |
329 | if (async && nodeMatched && !asyncInProgress() && lastACLResult()) { | |
330 | // async acl, but using cached response, and it was a match | |
331 | node = node->next; | |
332 | continue; | |
333 | } | |
334 | ||
62e76326 | 335 | PROF_stop(aclMatchAclList); |
501b58f9 | 336 | |
48071869 | 337 | return; |
62e76326 | 338 | } |
339 | ||
340 | node = node->next; | |
225b7b10 | 341 | } |
62e76326 | 342 | |
bf8fe701 | 343 | debugs(28, 3, "aclmatchAclList: " << this << " returning true (AND list satisfied)"); |
344 | ||
48071869 | 345 | markFinished(); |
225b7b10 | 346 | PROF_stop(aclMatchAclList); |
225b7b10 | 347 | } |
348 | ||
349 | CBDATA_CLASS_INIT(ACLChecklist); | |
350 | ||
351 | void * | |
352 | ACLChecklist::operator new (size_t size) | |
353 | { | |
354 | assert (size == sizeof(ACLChecklist)); | |
355 | CBDATA_INIT_TYPE(ACLChecklist); | |
356 | ACLChecklist *result = cbdataAlloc(ACLChecklist); | |
aa625860 | 357 | return result; |
225b7b10 | 358 | } |
62e76326 | 359 | |
225b7b10 | 360 | void |
361 | ACLChecklist::operator delete (void *address) | |
362 | { | |
363 | ACLChecklist *t = static_cast<ACLChecklist *>(address); | |
aa625860 | 364 | cbdataFree(t); |
225b7b10 | 365 | } |
366 | ||
cc192b50 | 367 | ACLChecklist::ACLChecklist() : |
368 | accessList (NULL), | |
6db78a1a | 369 | dst_peer(NULL), |
cc192b50 | 370 | request (NULL), |
62e76326 | 371 | reply (NULL), |
4f0ef8e8 | 372 | auth_user_request (NULL), |
225b7b10 | 373 | #if SQUID_SNMP |
4f0ef8e8 | 374 | snmp_community(NULL), |
8f756a9c | 375 | #endif |
376 | #if USE_SSL | |
377 | ssl_error(0), | |
225b7b10 | 378 | #endif |
4f0ef8e8 | 379 | callback (NULL), |
62e76326 | 380 | callback_data (NULL), |
381 | extacl_entry (NULL), | |
382 | conn_(NULL), | |
8f756a9c | 383 | fd_(-1), |
62e76326 | 384 | async_(false), |
385 | finished_(false), | |
386 | allow_(ACCESS_DENIED), | |
387 | state_(NullState::Instance()), | |
388 | destinationDomainChecked_(false), | |
ab321f4b | 389 | sourceDomainChecked_(false), |
390 | lastACLResult_(false) | |
225b7b10 | 391 | { |
cc192b50 | 392 | my_addr.SetEmpty(); |
393 | src_addr.SetEmpty(); | |
394 | dst_addr.SetEmpty(); | |
225b7b10 | 395 | rfc931[0] = '\0'; |
225b7b10 | 396 | } |
397 | ||
398 | ACLChecklist::~ACLChecklist() | |
399 | { | |
400 | assert (!asyncInProgress()); | |
62e76326 | 401 | |
225b7b10 | 402 | if (extacl_entry) |
62e76326 | 403 | cbdataReferenceDone(extacl_entry); |
404 | ||
6dd9f4bd | 405 | HTTPMSGUNLOCK(request); |
62e76326 | 406 | |
7dc5f514 | 407 | HTTPMSGUNLOCK(reply); |
408 | ||
702c0b9b | 409 | // no auth_user_request in builds without any Authentication configured |
410 | if (auth_user_request) | |
411 | AUTHUSERREQUESTUNLOCK(auth_user_request, "ACLChecklist destructor"); | |
4f0ef8e8 | 412 | |
69d779f8 | 413 | cbdataReferenceDone(conn_); |
62e76326 | 414 | |
225b7b10 | 415 | cbdataReferenceDone(accessList); |
62e76326 | 416 | |
bf8fe701 | 417 | debugs(28, 4, "ACLChecklist::~ACLChecklist: destroyed " << this); |
225b7b10 | 418 | } |
419 | ||
420 | ||
69d779f8 | 421 | ConnStateData * |
b50e327b | 422 | ACLChecklist::conn() const |
225b7b10 | 423 | { |
424 | return conn_; | |
425 | } | |
426 | ||
427 | void | |
69d779f8 | 428 | ACLChecklist::conn(ConnStateData *aConn) |
225b7b10 | 429 | { |
4d3a24ca | 430 | assert (conn() == NULL); |
69d779f8 | 431 | conn_ = cbdataReference(aConn); |
225b7b10 | 432 | } |
433 | ||
8f756a9c | 434 | int |
435 | ACLChecklist::fd() const | |
436 | { | |
437 | return conn_ != NULL ? conn_->fd : fd_; | |
438 | } | |
439 | ||
440 | void | |
441 | ACLChecklist::fd(int aDescriptor) | |
442 | { | |
443 | assert(!conn() || conn()->fd == aDescriptor); | |
444 | fd_ = aDescriptor; | |
445 | } | |
446 | ||
225b7b10 | 447 | void |
448 | ACLChecklist::AsyncState::changeState (ACLChecklist *checklist, AsyncState *newState) const | |
449 | { | |
450 | checklist->changeState(newState); | |
451 | } | |
452 | ||
453 | ACLChecklist::NullState * | |
454 | ACLChecklist::NullState::Instance() | |
455 | { | |
456 | return &_instance; | |
457 | } | |
458 | ||
459 | void | |
460 | ACLChecklist::NullState::checkForAsync(ACLChecklist *) const | |
26ac0430 | 461 | {} |
225b7b10 | 462 | |
463 | ACLChecklist::NullState ACLChecklist::NullState::_instance; | |
464 | ||
465 | void | |
466 | ACLChecklist::changeState (AsyncState *newState) | |
467 | { | |
468 | /* only change from null to active and back again, | |
469 | * not active to active. | |
470 | * relax this once conversion to states is complete | |
471 | * RBC 02 2003 | |
472 | */ | |
473 | assert (state_ == NullState::Instance() || newState == NullState::Instance()); | |
474 | state_ = newState; | |
475 | } | |
476 | ||
477 | ACLChecklist::AsyncState * | |
478 | ACLChecklist::asyncState() const | |
479 | { | |
480 | return state_; | |
481 | } | |
482 | ||
b50e327b AJ |
483 | /** |
484 | * Kick off a non-blocking (slow) ACL access list test | |
485 | * | |
486 | * NP: this should probably be made Async now. | |
487 | */ | |
225b7b10 | 488 | void |
489 | ACLChecklist::nonBlockingCheck(PF * callback_, void *callback_data_) | |
490 | { | |
491 | callback = callback_; | |
492 | callback_data = cbdataReference(callback_data_); | |
493 | check(); | |
494 | } | |
495 | ||
b448c119 | 496 | /* Warning: do not cbdata lock this here - it |
497 | * may be static or on the stack | |
498 | */ | |
499 | int | |
500 | ACLChecklist::fastCheck() | |
501 | { | |
502 | PROF_start(aclCheckFast); | |
503 | currentAnswer(ACCESS_DENIED); | |
bf8fe701 | 504 | debugs(28, 5, "aclCheckFast: list: " << accessList); |
b448c119 | 505 | |
506 | while (accessList) { | |
c35e260d | 507 | preCheck(); |
b448c119 | 508 | matchAclListFast(accessList->aclList); |
509 | ||
510 | if (finished()) { | |
511 | PROF_stop(aclCheckFast); | |
108d65b2 | 512 | cbdataReferenceDone(accessList); |
b448c119 | 513 | return currentAnswer() == ACCESS_ALLOWED; |
514 | } | |
515 | ||
fddded8f | 516 | /* |
517 | * Reference the next access entry | |
518 | */ | |
519 | const acl_access *A = accessList; | |
520 | ||
521 | assert (A); | |
522 | ||
523 | accessList = cbdataReference(A->next); | |
524 | ||
525 | cbdataReferenceDone(A); | |
b448c119 | 526 | } |
527 | ||
bf8fe701 | 528 | debugs(28, 5, "aclCheckFast: no matches, returning: " << (currentAnswer() == ACCESS_DENIED)); |
529 | ||
b448c119 | 530 | PROF_stop(aclCheckFast); |
531 | return currentAnswer() == ACCESS_DENIED; | |
532 | } | |
533 | ||
534 | ||
3841dd46 | 535 | bool |
536 | ACLChecklist::destinationDomainChecked() const | |
537 | { | |
538 | return destinationDomainChecked_; | |
539 | } | |
540 | ||
541 | void | |
542 | ACLChecklist::markDestinationDomainChecked() | |
543 | { | |
544 | assert (!finished() && !destinationDomainChecked()); | |
545 | destinationDomainChecked_ = true; | |
546 | } | |
547 | ||
548 | bool | |
549 | ACLChecklist::sourceDomainChecked() const | |
550 | { | |
551 | return sourceDomainChecked_; | |
552 | } | |
553 | ||
554 | void | |
555 | ACLChecklist::markSourceDomainChecked() | |
556 | { | |
557 | assert (!finished() && !sourceDomainChecked()); | |
558 | sourceDomainChecked_ = true; | |
559 | } | |
b6f25d16 | 560 | |
561 | bool | |
562 | ACLChecklist::checking() const | |
563 | { | |
564 | return checking_; | |
565 | } | |
566 | ||
567 | void | |
568 | ACLChecklist::checking (bool const newValue) | |
569 | { | |
570 | checking_ = newValue; | |
571 | } | |
ef1955a5 | 572 | |
b448c119 | 573 | /* |
574 | * Any ACLChecklist created by aclChecklistCreate() must eventually be | |
575 | * freed by ACLChecklist::operator delete(). There are two common cases: | |
576 | * | |
577 | * A) Using aclCheckFast(): The caller creates the ACLChecklist using | |
578 | * aclChecklistCreate(), checks it using aclCheckFast(), and frees it | |
579 | * using aclChecklistFree(). | |
580 | * | |
581 | * B) Using aclNBCheck() and callbacks: The caller creates the | |
582 | * ACLChecklist using aclChecklistCreate(), and passes it to | |
583 | * aclNBCheck(). Control eventually passes to ACLChecklist::checkCallback(), | |
584 | * which will invoke the callback function as requested by the | |
585 | * original caller of aclNBCheck(). This callback function must | |
586 | * *not* invoke aclChecklistFree(). After the callback function | |
587 | * returns, ACLChecklist::checkCallback() will free the ACLChecklist using | |
588 | * aclChecklistFree(). | |
589 | */ | |
b448c119 | 590 | ACLChecklist * |
591 | aclChecklistCreate(const acl_access * A, HttpRequest * request, const char *ident) | |
592 | { | |
8f756a9c | 593 | // TODO: make this a constructor? On-stack creation uses the same code. |
b448c119 | 594 | ACLChecklist *checklist = new ACLChecklist; |
595 | ||
596 | if (A) | |
597 | checklist->accessList = cbdataReference(A); | |
598 | ||
26ac0430 | 599 | if (request != NULL) { |
6dd9f4bd | 600 | checklist->request = HTTPMSGLOCK(request); |
3d674977 AJ |
601 | #if FOLLOW_X_FORWARDED_FOR |
602 | if (Config.onoff.acl_uses_indirect_client) | |
603 | checklist->src_addr = request->indirect_client_addr; | |
604 | else | |
605 | #endif /* FOLLOW_X_FORWARDED_FOR */ | |
606 | checklist->src_addr = request->client_addr; | |
b448c119 | 607 | checklist->my_addr = request->my_addr; |
b448c119 | 608 | } |
609 | ||
610 | #if USE_IDENT | |
611 | if (ident) | |
612 | xstrncpy(checklist->rfc931, ident, USER_IDENT_SZ); | |
613 | ||
614 | #endif | |
615 | ||
b448c119 | 616 | return checklist; |
617 | } | |
618 | ||
315b856d | 619 | bool |
620 | ACLChecklist::callerGone() | |
621 | { | |
622 | return !cbdataReferenceValid(callback_data); | |
623 | } | |
624 | ||
ef1955a5 | 625 | #ifndef _USE_INLINE_ |
626 | #include "ACLChecklist.cci" | |
627 | #endif |