]> git.ipfire.org Git - thirdparty/squid.git/blame - src/acl.cc
Add [] operator for offset-based access into String's.
[thirdparty/squid.git] / src / acl.cc
CommitLineData
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 41const char *AclMatchedName = NULL;
42
8000a965 43void *
44ACL::operator new (size_t byteCount)
45{
b0dd28ba 46 fatal ("unusable ACL::new");
47 return (void *)1;
8000a965 48}
49
50void
51ACL::operator delete (void *address)
52{
b0dd28ba 53 fatal ("unusable ACL::delete");
56b63fa1 54}
55
97427e90 56ACL *
225b7b10 57ACL::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 71ACL *
72ACL::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 82ACL::ACL () :cfgline(NULL) {}
8000a965 83
4b0f5de8 84bool ACL::valid () const
85{
86 return true;
87}
88
8203a132 89void
a9f20260 90ACL::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 179bool
180ACL::isProxyAuth() const
181{
225b7b10 182 return false;
8000a965 183}
1cfdbcf0 184
8000a965 185
186ACLList::ACLList() : op (1), _acl (NULL), next (NULL)
62e76326 187{}
8000a965 188
189void
190ACLList::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 200int
201ACL::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 218int
219ACL::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
244void
9bea1d5b 245aclCacheMatchFlush(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 262bool
263ACL::requiresReply() const
264{
265 return false;
266}
60d096f4 267
b0dd28ba 268bool
269ACL::requiresRequest() const
9bea1d5b 270{
b0dd28ba 271 return false;
272}
62e76326 273
b0dd28ba 274int
275ACL::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 295bool
296ACLList::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 316ACL::~ACL()
317{
bf8fe701 318 debugs(28, 3, "ACL::~ACL: '" << cfgline << "'");
62e76326 319 safe_free(cfgline);
92a6f4b1 320}
321
b0dd28ba 322#include "ACLStrategised.h"
8000a965 323bool
324acl_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 353CBDATA_CLASS_INIT(acl_access);
354
355void *
356acl_access::operator new (size_t)
357{
358 CBDATA_INIT_TYPE(acl_access);
359 acl_access *result = cbdataAlloc(acl_access);
360 return result;
361}
362
363void
364acl_access::operator delete (void *address)
365{
366 acl_access *t = static_cast<acl_access *>(address);
367 cbdataFree(t);
368}
369
8000a965 370ACL::Prototype::Prototype() : prototype (NULL), typeString (NULL) {}
371
62e76326 372ACL::Prototype::Prototype (ACL const *aPrototype, char const *aType) : prototype (aPrototype), typeString (aType)
8000a965 373{
374 registerMe ();
375}
376
377Vector<ACL::Prototype const *> * ACL::Prototype::Registry;
378void *ACL::Prototype::Initialized;
379
380bool
62e76326 381ACL::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
395void
396ACL::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 411ACL::Prototype::~Prototype()
8000a965 412{
67b7fa0d 413 // TODO: unregister me
8000a965 414}
415
416ACL *
417ACL::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 430void
431ACL::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}