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