]> git.ipfire.org Git - thirdparty/squid.git/blame - src/acl.cc
Cleanup: zap CVS Id tags
[thirdparty/squid.git] / src / acl.cc
CommitLineData
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 50const char *AclMatchedName = NULL;
51
8000a965 52void *
53ACL::operator new (size_t byteCount)
54{
b0dd28ba 55 fatal ("unusable ACL::new");
56 return (void *)1;
8000a965 57}
58
59void
60ACL::operator delete (void *address)
61{
b0dd28ba 62 fatal ("unusable ACL::delete");
56b63fa1 63}
64
97427e90 65ACL *
225b7b10 66ACL::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 80ACL *
81ACL::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 91ACL::ACL () :cfgline(NULL) {}
8000a965 92
4b0f5de8 93bool ACL::valid () const
94{
95 return true;
96}
97
8203a132 98void
a9f20260 99ACL::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 188bool
189ACL::isProxyAuth() const
190{
225b7b10 191 return false;
8000a965 192}
1cfdbcf0 193
8000a965 194
195ACLList::ACLList() : op (1), _acl (NULL), next (NULL)
62e76326 196{}
8000a965 197
198void
199ACLList::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 209int
210ACL::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 227int
228ACL::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
253void
9bea1d5b 254aclCacheMatchFlush(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 271bool
272ACL::requiresReply() const
273{
274 return false;
275}
60d096f4 276
b0dd28ba 277bool
278ACL::requiresRequest() const
9bea1d5b 279{
b0dd28ba 280 return false;
281}
62e76326 282
b0dd28ba 283int
284ACL::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 304bool
305ACLList::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 325ACL::~ACL()
326{
bf8fe701 327 debugs(28, 3, "ACL::~ACL: '" << cfgline << "'");
62e76326 328 safe_free(cfgline);
92a6f4b1 329}
330
b0dd28ba 331#include "ACLStrategised.h"
8000a965 332bool
333acl_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 362CBDATA_CLASS_INIT(acl_access);
363
364void *
365acl_access::operator new (size_t)
366{
367 CBDATA_INIT_TYPE(acl_access);
368 acl_access *result = cbdataAlloc(acl_access);
369 return result;
370}
371
372void
373acl_access::operator delete (void *address)
374{
375 acl_access *t = static_cast<acl_access *>(address);
376 cbdataFree(t);
377}
378
8000a965 379ACL::Prototype::Prototype() : prototype (NULL), typeString (NULL) {}
380
62e76326 381ACL::Prototype::Prototype (ACL const *aPrototype, char const *aType) : prototype (aPrototype), typeString (aType)
8000a965 382{
383 registerMe ();
384}
385
386Vector<ACL::Prototype const *> * ACL::Prototype::Registry;
387void *ACL::Prototype::Initialized;
388
389bool
62e76326 390ACL::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
404void
405ACL::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 420ACL::Prototype::~Prototype()
8000a965 421{
67b7fa0d 422 // TODO: unregister me
8000a965 423}
424
425ACL *
426ACL::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 439void
440ACL::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}