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