]>
Commit | Line | Data |
---|---|---|
8213067d | 1 | /* |
262a0e14 | 2 | * $Id$ |
30a4f2a8 | 3 | * |
4 | * DEBUG: section 28 Access Control | |
5 | * AUTHOR: Duane Wessels | |
6 | * | |
2b6662ba | 7 | * SQUID Web Proxy Cache http://www.squid-cache.org/ |
e25c139f | 8 | * ---------------------------------------------------------- |
30a4f2a8 | 9 | * |
2b6662ba | 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. | |
30a4f2a8 | 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 | * |
30a4f2a8 | 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 | * |
30a4f2a8 | 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 | |
cbdec147 | 31 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. |
e25c139f | 32 | * |
8213067d | 33 | */ |
f5bffbd5 | 34 | #include "config.h" |
7dd57fa2 | 35 | |
e1f7507e | 36 | #if 0 |
7dd57fa2 | 37 | #include "squid.h" |
e1f7507e AJ |
38 | #include "HttpRequest.h" |
39 | #endif | |
40 | ||
29b17d63 | 41 | #include "ACL.h" |
4fb35c3c | 42 | #include "ACLChecklist.h" |
d295d770 | 43 | #include "ConfigParser.h" |
e1f7507e AJ |
44 | #include "dlink.h" |
45 | /* for special-case PURGE test */ | |
46 | #include "HttpRequestMethod.h" | |
47 | /* for Vector<> Instances */ | |
48 | #include "assert.h" | |
23351cb2 | 49 | |
b0dd28ba | 50 | const char *AclMatchedName = NULL; |
51 | ||
8000a965 | 52 | void * |
53 | ACL::operator new (size_t byteCount) | |
54 | { | |
b0dd28ba | 55 | fatal ("unusable ACL::new"); |
56 | return (void *)1; | |
8000a965 | 57 | } |
58 | ||
59 | void | |
60 | ACL::operator delete (void *address) | |
61 | { | |
b0dd28ba | 62 | fatal ("unusable ACL::delete"); |
56b63fa1 | 63 | } |
64 | ||
97427e90 | 65 | ACL * |
225b7b10 | 66 | ACL::FindByName(const char *name) |
7dd57fa2 | 67 | { |
97427e90 | 68 | ACL *a; |
bf8fe701 | 69 | debugs(28, 9, "ACL::FindByName '" << name << "'"); |
62e76326 | 70 | |
9bea1d5b | 71 | for (a = Config.aclList; a; a = a->next) |
62e76326 | 72 | if (!strcasecmp(a->name, name)) |
73 | return a; | |
74 | ||
bf8fe701 | 75 | debugs(28, 9, "ACL::FindByName found no match"); |
6bf4f823 | 76 | |
9bea1d5b | 77 | return NULL; |
7dd57fa2 | 78 | } |
79 | ||
8000a965 | 80 | ACL * |
81 | ACL::Factory (char const *type) | |
82 | { | |
83 | ACL *result = Prototype::Factory (type); | |
62e76326 | 84 | |
b0dd28ba | 85 | if (!result) |
62e76326 | 86 | fatal ("Unknown acl type in ACL::Factory"); |
62e76326 | 87 | |
8000a965 | 88 | return result; |
89 | } | |
90 | ||
d295d770 | 91 | ACL::ACL () :cfgline(NULL) {} |
8000a965 | 92 | |
4b0f5de8 | 93 | bool ACL::valid () const |
94 | { | |
95 | return true; | |
96 | } | |
97 | ||
8203a132 | 98 | void |
a9f20260 | 99 | ACL::ParseAclLine(ConfigParser &parser, ACL ** head) |
9bea1d5b | 100 | { |
101 | /* we're already using strtok() to grok the line */ | |
102 | char *t = NULL; | |
97427e90 | 103 | ACL *A = NULL; |
9bea1d5b | 104 | LOCAL_ARRAY(char, aclname, ACL_NAME_SZ); |
9bea1d5b | 105 | int new_acl = 0; |
106 | ||
107 | /* snarf the ACL name */ | |
62e76326 | 108 | |
9bea1d5b | 109 | if ((t = strtok(NULL, w_space)) == NULL) { |
bf8fe701 | 110 | debugs(28, 0, "aclParseAclLine: missing ACL name."); |
a9f20260 | 111 | parser.destruct(); |
62e76326 | 112 | return; |
9bea1d5b | 113 | } |
62e76326 | 114 | |
401f503a | 115 | if (strlen(t) >= ACL_NAME_SZ) { |
bf8fe701 | 116 | debugs(28, 0, "aclParseAclLine: aclParseAclLine: ACL name '" << t << |
117 | "' too long, max " << ACL_NAME_SZ - 1 << " characters supported"); | |
401f503a | 118 | parser.destruct(); |
119 | return; | |
120 | } | |
121 | ||
9bea1d5b | 122 | xstrncpy(aclname, t, ACL_NAME_SZ); |
123 | /* snarf the ACL type */ | |
b0dd28ba | 124 | char *theType; |
62e76326 | 125 | |
b0dd28ba | 126 | if ((theType = strtok(NULL, w_space)) == NULL) { |
bf8fe701 | 127 | debugs(28, 0, "aclParseAclLine: missing ACL type."); |
a9f20260 | 128 | parser.destruct(); |
62e76326 | 129 | return; |
9bea1d5b | 130 | } |
62e76326 | 131 | |
b0dd28ba | 132 | if (!Prototype::Registered (theType)) { |
bf8fe701 | 133 | debugs(28, 0, "aclParseAclLine: Invalid ACL type '" << theType << "'"); |
a9f20260 | 134 | parser.destruct(); |
62e76326 | 135 | return; |
9bea1d5b | 136 | } |
62e76326 | 137 | |
225b7b10 | 138 | if ((A = FindByName(aclname)) == NULL) { |
bf8fe701 | 139 | debugs(28, 3, "aclParseAclLine: Creating ACL '" << aclname << "'"); |
b0dd28ba | 140 | A = ACL::Factory(theType); |
62e76326 | 141 | xstrncpy(A->name, aclname, ACL_NAME_SZ); |
142 | A->cfgline = xstrdup(config_input_line); | |
143 | new_acl = 1; | |
9bea1d5b | 144 | } else { |
b0dd28ba | 145 | if (strcmp (A->typeString(),theType) ) { |
bf8fe701 | 146 | debugs(28, 0, "aclParseAclLine: ACL '" << A->name << "' already exists with different type."); |
a9f20260 | 147 | parser.destruct(); |
62e76326 | 148 | return; |
149 | } | |
150 | ||
bf8fe701 | 151 | debugs(28, 3, "aclParseAclLine: Appending to '" << aclname << "'"); |
62e76326 | 152 | new_acl = 0; |
9bea1d5b | 153 | } |
62e76326 | 154 | |
9bea1d5b | 155 | /* |
156 | * Here we set AclMatchedName in case we need to use it in a | |
157 | * warning message in aclDomainCompare(). | |
158 | */ | |
8000a965 | 159 | AclMatchedName = A->name; /* ugly */ |
160 | ||
161 | /*split the function here */ | |
162 | A->parse(); | |
62e76326 | 163 | |
8000a965 | 164 | /* |
165 | * Clear AclMatchedName from our temporary hack | |
166 | */ | |
167 | AclMatchedName = NULL; /* ugly */ | |
62e76326 | 168 | |
8000a965 | 169 | if (!new_acl) |
62e76326 | 170 | return; |
171 | ||
4b0f5de8 | 172 | if (A->empty()) { |
bf8fe701 | 173 | debugs(28, 0, "Warning: empty ACL: " << A->cfgline); |
4b0f5de8 | 174 | } |
175 | ||
176 | if (!A->valid()) { | |
177 | fatalf("ERROR: Invalid ACL: %s\n", | |
178 | A->cfgline); | |
8000a965 | 179 | } |
62e76326 | 180 | |
8000a965 | 181 | /* append */ |
182 | while (*head) | |
62e76326 | 183 | head = &(*head)->next; |
184 | ||
8000a965 | 185 | *head = A; |
186 | } | |
187 | ||
8000a965 | 188 | bool |
189 | ACL::isProxyAuth() const | |
190 | { | |
225b7b10 | 191 | return false; |
8000a965 | 192 | } |
1cfdbcf0 | 193 | |
8000a965 | 194 | |
195 | ACLList::ACLList() : op (1), _acl (NULL), next (NULL) | |
62e76326 | 196 | {} |
8000a965 | 197 | |
198 | void | |
199 | ACLList::negated(bool isNegated) | |
200 | { | |
201 | if (isNegated) | |
62e76326 | 202 | op = 0; |
8000a965 | 203 | else |
62e76326 | 204 | op = 1; |
d6827718 | 205 | } |
206 | ||
94439e4e | 207 | /* ACL result caching routines */ |
208 | ||
225b7b10 | 209 | int |
210 | ACL::matchForCache(ACLChecklist *checklist) | |
211 | { | |
212 | /* This is a fatal to ensure that cacheMatchAcl calls are _only_ | |
213 | * made for supported acl types */ | |
214 | fatal("aclCacheMatchAcl: unknown or unexpected ACL type"); | |
215 | return 0; /* NOTREACHED */ | |
216 | } | |
217 | ||
94439e4e | 218 | /* |
26ac0430 | 219 | * we lookup an acl's cached results, and if we cannot find the acl being |
225b7b10 | 220 | * checked we check it and cache the result. This function is a template |
221 | * method to support caching of multiple acl types. | |
222 | * Note that caching of time based acl's is not | |
6bf4f823 | 223 | * wise in long lived caches (i.e. the auth_user proxy match cache) |
94439e4e | 224 | * RBC |
6bf4f823 | 225 | * TODO: does a dlink_list perform well enough? Kinkie |
94439e4e | 226 | */ |
225b7b10 | 227 | int |
228 | ACL::cacheMatchAcl(dlink_list * cache, ACLChecklist *checklist) | |
9bea1d5b | 229 | { |
9bea1d5b | 230 | acl_proxy_auth_match_cache *auth_match; |
231 | dlink_node *link; | |
232 | link = cache->head; | |
62e76326 | 233 | |
9bea1d5b | 234 | while (link) { |
62e76326 | 235 | auth_match = (acl_proxy_auth_match_cache *)link->data; |
236 | ||
237 | if (auth_match->acl_data == this) { | |
bf8fe701 | 238 | debugs(28, 4, "ACL::cacheMatchAcl: cache hit on acl '" << name << "' (" << this << ")"); |
62e76326 | 239 | return auth_match->matchrv; |
240 | } | |
241 | ||
242 | link = link->next; | |
9bea1d5b | 243 | } |
62e76326 | 244 | |
11a9f1b1 | 245 | auth_match = new acl_proxy_auth_match_cache(); |
225b7b10 | 246 | auth_match->matchrv = matchForCache (checklist); |
247 | auth_match->acl_data = this; | |
9bea1d5b | 248 | dlinkAddTail(auth_match, &auth_match->link, cache); |
bf8fe701 | 249 | debugs(28, 4, "ACL::cacheMatchAcl: miss for '" << name << "'. Adding result " << auth_match->matchrv); |
225b7b10 | 250 | return auth_match->matchrv; |
94439e4e | 251 | } |
252 | ||
253 | void | |
9bea1d5b | 254 | aclCacheMatchFlush(dlink_list * cache) |
94439e4e | 255 | { |
9bea1d5b | 256 | acl_proxy_auth_match_cache *auth_match; |
257 | dlink_node *link, *tmplink; | |
258 | link = cache->head; | |
62e76326 | 259 | |
bf8fe701 | 260 | debugs(28, 8, "aclCacheMatchFlush called for cache " << cache); |
6bf4f823 | 261 | |
9bea1d5b | 262 | while (link) { |
62e76326 | 263 | auth_match = (acl_proxy_auth_match_cache *)link->data; |
264 | tmplink = link; | |
265 | link = link->next; | |
266 | dlinkDelete(tmplink, cache); | |
11a9f1b1 | 267 | delete auth_match; |
1f38f50a | 268 | } |
c68e9c6b | 269 | } |
73e67ee0 | 270 | |
b0dd28ba | 271 | bool |
272 | ACL::requiresReply() const | |
273 | { | |
274 | return false; | |
275 | } | |
60d096f4 | 276 | |
b0dd28ba | 277 | bool |
278 | ACL::requiresRequest() const | |
9bea1d5b | 279 | { |
b0dd28ba | 280 | return false; |
281 | } | |
62e76326 | 282 | |
b0dd28ba | 283 | int |
284 | ACL::checklistMatches(ACLChecklist *checklist) | |
285 | { | |
6bf4f823 | 286 | int rv; |
287 | ||
b0dd28ba | 288 | if (NULL == checklist->request && requiresRequest()) { |
bf8fe701 | 289 | debugs(28, 1, "ACL::checklistMatches WARNING: '" << name << "' ACL is used but there is no HTTP request -- not matching."); |
b0dd28ba | 290 | return 0; |
d35b9a94 | 291 | } |
62e76326 | 292 | |
b0dd28ba | 293 | if (NULL == checklist->reply && requiresReply()) { |
bf8fe701 | 294 | debugs(28, 1, "ACL::checklistMatches WARNING: '" << name << "' ACL is used but there is no HTTP reply -- not matching."); |
b0dd28ba | 295 | return 0; |
78e0ce43 | 296 | } |
62e76326 | 297 | |
bf8fe701 | 298 | debugs(28, 3, "ACL::checklistMatches: checking '" << name << "'"); |
6bf4f823 | 299 | rv= match(checklist); |
bf8fe701 | 300 | debugs(28, 3, "ACL::ChecklistMatches: result for '" << name << "' is " << rv); |
6bf4f823 | 301 | return rv; |
60d096f4 | 302 | } |
c68e9c6b | 303 | |
b0dd28ba | 304 | bool |
305 | ACLList::matches (ACLChecklist *checklist) const | |
60d096f4 | 306 | { |
b0dd28ba | 307 | assert (_acl); |
308 | AclMatchedName = _acl->name; | |
bf8fe701 | 309 | debugs(28, 3, "ACLList::matches: checking " << (op ? null_string : "!") << _acl->name); |
62e76326 | 310 | |
b0dd28ba | 311 | if (_acl->checklistMatches(checklist) != op) { |
bf8fe701 | 312 | debugs(28, 4, "ACLList::matches: result is false"); |
ab321f4b | 313 | return checklist->lastACLResult(false); |
b0dd28ba | 314 | } |
62e76326 | 315 | |
bf8fe701 | 316 | debugs(28, 4, "ACLList::matches: result is true"); |
ab321f4b | 317 | return checklist->lastACLResult(true); |
60d096f4 | 318 | } |
94439e4e | 319 | |
348b2031 | 320 | |
f32789f4 | 321 | /*********************/ |
322 | /* Destroy functions */ | |
323 | /*********************/ | |
324 | ||
8000a965 | 325 | ACL::~ACL() |
326 | { | |
bf8fe701 | 327 | debugs(28, 3, "ACL::~ACL: '" << cfgline << "'"); |
62e76326 | 328 | safe_free(cfgline); |
92a6f4b1 | 329 | } |
330 | ||
b0dd28ba | 331 | #include "ACLStrategised.h" |
8000a965 | 332 | bool |
333 | acl_access::containsPURGE() const | |
334 | { | |
335 | acl_access const *a = this; | |
76cd39d7 | 336 | ACLList *b; |
62e76326 | 337 | |
bf8fe701 | 338 | debugs(28, 6, "acl_access::containsPURGE: invoked for '" << cfgline << "'"); |
6bf4f823 | 339 | |
9bea1d5b | 340 | for (; a; a = a->next) { |
62e76326 | 341 | for (b = a->aclList; b; b = b->next) { |
60745f24 | 342 | ACLStrategised<HttpRequestMethod> *tempAcl = dynamic_cast<ACLStrategised<HttpRequestMethod> *>(b->_acl); |
b0dd28ba | 343 | |
6bf4f823 | 344 | if (!tempAcl) { |
bf8fe701 | 345 | debugs(28, 7, "acl_access::containsPURGE: can't create tempAcl"); |
62e76326 | 346 | continue; |
6bf4f823 | 347 | } |
62e76326 | 348 | |
6bf4f823 | 349 | if (tempAcl->match(METHOD_PURGE)) { |
bf8fe701 | 350 | debugs(28, 6, "acl_access::containsPURGE: returning true"); |
62e76326 | 351 | return true; |
6bf4f823 | 352 | } |
62e76326 | 353 | } |
53cb32a9 | 354 | } |
62e76326 | 355 | |
bf8fe701 | 356 | debugs(28, 6, "acl_access::containsPURGE: returning false"); |
8000a965 | 357 | return false; |
358 | } | |
359 | ||
29b17d63 | 360 | /* to be split into separate files in the future */ |
361 | ||
8000a965 | 362 | CBDATA_CLASS_INIT(acl_access); |
363 | ||
364 | void * | |
365 | acl_access::operator new (size_t) | |
366 | { | |
367 | CBDATA_INIT_TYPE(acl_access); | |
368 | acl_access *result = cbdataAlloc(acl_access); | |
369 | return result; | |
370 | } | |
371 | ||
372 | void | |
373 | acl_access::operator delete (void *address) | |
374 | { | |
375 | acl_access *t = static_cast<acl_access *>(address); | |
376 | cbdataFree(t); | |
377 | } | |
378 | ||
8000a965 | 379 | ACL::Prototype::Prototype() : prototype (NULL), typeString (NULL) {} |
380 | ||
62e76326 | 381 | ACL::Prototype::Prototype (ACL const *aPrototype, char const *aType) : prototype (aPrototype), typeString (aType) |
8000a965 | 382 | { |
383 | registerMe (); | |
384 | } | |
385 | ||
386 | Vector<ACL::Prototype const *> * ACL::Prototype::Registry; | |
387 | void *ACL::Prototype::Initialized; | |
388 | ||
389 | bool | |
62e76326 | 390 | ACL::Prototype::Registered(char const *aType) |
8000a965 | 391 | { |
bf8fe701 | 392 | debugs(28, 7, "ACL::Prototype::Registered: invoked for type " << aType); |
6bf4f823 | 393 | |
8000a965 | 394 | for (iterator i = Registry->begin(); i != Registry->end(); ++i) |
6bf4f823 | 395 | if (!strcmp (aType, (*i)->typeString)) { |
bf8fe701 | 396 | debugs(28, 7, "ACL::Prototype::Registered: yes"); |
62e76326 | 397 | return true; |
6bf4f823 | 398 | } |
62e76326 | 399 | |
bf8fe701 | 400 | debugs(28, 7, "ACL::Prototype::Registered: no"); |
8000a965 | 401 | return false; |
402 | } | |
403 | ||
404 | void | |
405 | ACL::Prototype::registerMe () | |
406 | { | |
407 | if (!Registry || (Initialized != ((char *)Registry - 5)) ) { | |
62e76326 | 408 | /* TODO: extract this */ |
409 | /* Not initialised */ | |
410 | Registry = new Vector <ACL::Prototype const *>; | |
411 | Initialized = (char *)Registry - 5; | |
8000a965 | 412 | } |
62e76326 | 413 | |
8000a965 | 414 | if (Registered (typeString)) |
62e76326 | 415 | fatalf ("Attempt to register %s twice", typeString); |
416 | ||
8000a965 | 417 | Registry->push_back (this); |
418 | } | |
419 | ||
62e76326 | 420 | ACL::Prototype::~Prototype() |
8000a965 | 421 | { |
67b7fa0d | 422 | // TODO: unregister me |
8000a965 | 423 | } |
424 | ||
425 | ACL * | |
426 | ACL::Prototype::Factory (char const *typeToClone) | |
427 | { | |
bf8fe701 | 428 | debugs(28, 4, "ACL::Prototype::Factory: cloning an object for type '" << typeToClone << "'"); |
6bf4f823 | 429 | |
8000a965 | 430 | for (iterator i = Registry->begin(); i != Registry->end(); ++i) |
62e76326 | 431 | if (!strcmp (typeToClone, (*i)->typeString)) |
432 | return (*i)->prototype->clone(); | |
433 | ||
bf8fe701 | 434 | debugs(28, 4, "ACL::Prototype::Factory: cloning failed, no type '" << typeToClone << "' available"); |
6bf4f823 | 435 | |
8000a965 | 436 | return NULL; |
437 | } | |
438 | ||
b0dd28ba | 439 | void |
440 | ACL::Initialize() | |
8000a965 | 441 | { |
97427e90 | 442 | ACL *a = Config.aclList; |
bf8fe701 | 443 | debugs(53, 3, "ACL::Initialize"); |
b0dd28ba | 444 | |
445 | while (a) { | |
446 | a->prepareForUse(); | |
447 | a = a->next; | |
448 | } | |
8000a965 | 449 | } |