2
* $Id: acl.cc,v 1.321 2006/07/29 13:46:05 hno Exp $
4
* DEBUG: section 28 Access Control
5
* AUTHOR: Duane Wessels
7
* SQUID Web Proxy Cache http://www.squid-cache.org/
8
* ----------------------------------------------------------
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.
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.
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.
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
31
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
37
#include "ACLChecklist.h"
38
#include "ConfigParser.h"
39
#include "HttpRequest.h"
41
const char *AclMatchedName = NULL;
44
ACL::operator new (size_t byteCount)
46
fatal ("unusable ACL::new");
51
ACL::operator delete (void *address)
53
fatal ("unusable ACL::delete");
57
ACL::FindByName(const char *name)
60
debug(28, 9) ("ACL::FindByName '%s'\n",name);
62
for (a = Config.aclList; a; a = a->next)
63
if (!strcasecmp(a->name, name))
66
debug(28,9) ("ACL::FindByName found no match\n");
72
ACL::Factory (char const *type)
74
ACL *result = Prototype::Factory (type);
77
fatal ("Unknown acl type in ACL::Factory");
82
ACL::ACL () :cfgline(NULL) {}
84
bool ACL::valid () const
90
ACL::ParseAclLine(ConfigParser &parser, ACL ** head)
92
/* we're already using strtok() to grok the line */
95
LOCAL_ARRAY(char, aclname, ACL_NAME_SZ);
98
/* snarf the ACL name */
100
if ((t = strtok(NULL, w_space)) == NULL) {
101
debug(28, 0) ("aclParseAclLine: missing ACL name.\n");
106
if (strlen(t) >= ACL_NAME_SZ) {
107
debug(28, 0) ("aclParseAclLine: aclParseAclLine: ACL name '%s' too long, max %d characters supported\n", t, ACL_NAME_SZ - 1);
112
xstrncpy(aclname, t, ACL_NAME_SZ);
113
/* snarf the ACL type */
116
if ((theType = strtok(NULL, w_space)) == NULL) {
117
debug(28, 0) ("aclParseAclLine: missing ACL type.\n");
122
if (!Prototype::Registered (theType)) {
123
debug(28, 0) ("aclParseAclLine: Invalid ACL type '%s'\n", theType);
128
if ((A = FindByName(aclname)) == NULL) {
129
debug(28, 3) ("aclParseAclLine: Creating ACL '%s'\n", aclname);
130
A = ACL::Factory(theType);
131
xstrncpy(A->name, aclname, ACL_NAME_SZ);
132
A->cfgline = xstrdup(config_input_line);
135
if (strcmp (A->typeString(),theType) ) {
136
debug(28, 0) ("aclParseAclLine: ACL '%s' already exists with different type.\n", A->name);
141
debug(28, 3) ("aclParseAclLine: Appending to '%s'\n", aclname);
146
* Here we set AclMatchedName in case we need to use it in a
147
* warning message in aclDomainCompare().
149
AclMatchedName = A->name; /* ugly */
151
/*split the function here */
155
* Clear AclMatchedName from our temporary hack
157
AclMatchedName = NULL; /* ugly */
163
debug(28, 0) ("Warning: empty ACL: %s\n",
168
fatalf("ERROR: Invalid ACL: %s\n",
174
head = &(*head)->next;
180
ACL::isProxyAuth() const
186
ACLList::ACLList() : op (1), _acl (NULL), next (NULL)
190
ACLList::negated(bool isNegated)
198
/* ACL result caching routines */
201
ACL::matchForCache(ACLChecklist *checklist)
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 */
210
* we lookup an acl's cached results, and if we cannot find the acl being
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
214
* wise in long lived caches (i.e. the auth_user proxy match cache)
216
* TODO: does a dlink_list perform well enough? Kinkie
219
ACL::cacheMatchAcl(dlink_list * cache, ACLChecklist *checklist)
221
acl_proxy_auth_match_cache *auth_match;
226
auth_match = (acl_proxy_auth_match_cache *)link->data;
228
if (auth_match->acl_data == this) {
229
debug(28, 4) ("ACL::cacheMatchAcl: cache hit on acl '%s' (%p)\n", name, this);
230
return auth_match->matchrv;
236
auth_match = new acl_proxy_auth_match_cache();
237
auth_match->matchrv = matchForCache (checklist);
238
auth_match->acl_data = this;
239
dlinkAddTail(auth_match, &auth_match->link, cache);
240
debug(28,4)("ACL::cacheMatchAcl: miss for '%s'. Adding result %d\n",name,auth_match->matchrv);
241
return auth_match->matchrv;
245
aclCacheMatchFlush(dlink_list * cache)
247
acl_proxy_auth_match_cache *auth_match;
248
dlink_node *link, *tmplink;
251
debug(28,8)("aclCacheMatchFlush called for cache %p\n",cache);
254
auth_match = (acl_proxy_auth_match_cache *)link->data;
257
dlinkDelete(tmplink, cache);
263
ACL::requiresReply() const
269
ACL::requiresRequest() const
275
ACL::checklistMatches(ACLChecklist *checklist)
279
if (NULL == checklist->request && requiresRequest()) {
280
debug(28, 1) ( "ACL::checklistMatches "
281
"WARNING: '%s' ACL is used but there is no"
282
" HTTP request -- not matching.\n", name);
286
if (NULL == checklist->reply && requiresReply()) {
287
debug(28, 1) ( "ACL::checklistMatches "
288
"WARNING: '%s' ACL is used but there is no"
289
" HTTP reply -- not matching.\n", name);
293
debug(28, 3) ("ACL::checklistMatches: checking '%s'\n", name);
294
rv= match(checklist);
295
debug(28,3) ("ACL::ChecklistMatches: result for '%s' is %d\n",name,rv);
300
ACLList::matches (ACLChecklist *checklist) const
303
AclMatchedName = _acl->name;
304
debug(28, 3) ("ACLList::matches: checking %s%s\n",
305
op ? null_string : "!", _acl->name);
307
if (_acl->checklistMatches(checklist) != op) {
308
debug(28,4)("ACLList::matches: result is false\n");
309
return checklist->lastACLResult(false);
312
debug(28,4)("ACLList::matches: result is true\n");
313
return checklist->lastACLResult(true);
317
/*********************/
318
/* Destroy functions */
319
/*********************/
323
debug(28, 3) ("ACL::~ACL: '%s'\n", cfgline);
327
#include "ACLStrategised.h"
329
acl_access::containsPURGE() const
331
acl_access const *a = this;
334
debug(28,6)("acl_access::containsPURGE: invoked for '%s'\n",cfgline);
336
for (; a; a = a->next) {
337
for (b = a->aclList; b; b = b->next) {
338
ACLStrategised<method_t> *tempAcl = dynamic_cast<ACLStrategised<method_t> *>(b->_acl);
341
debug(28,7)("acl_access::containsPURGE: can't create tempAcl\n");
345
if (tempAcl->match(METHOD_PURGE)) {
346
debug(28,6)("acl_access::containsPURGE: returning true\n");
352
debug(28,6)("acl_access::containsPURGE: returning false\n");
356
/* to be split into separate files in the future */
358
CBDATA_CLASS_INIT(acl_access);
361
acl_access::operator new (size_t)
363
CBDATA_INIT_TYPE(acl_access);
364
acl_access *result = cbdataAlloc(acl_access);
369
acl_access::operator delete (void *address)
371
acl_access *t = static_cast<acl_access *>(address);
375
ACL::Prototype::Prototype() : prototype (NULL), typeString (NULL) {}
377
ACL::Prototype::Prototype (ACL const *aPrototype, char const *aType) : prototype (aPrototype), typeString (aType)
382
Vector<ACL::Prototype const *> * ACL::Prototype::Registry;
383
void *ACL::Prototype::Initialized;
386
ACL::Prototype::Registered(char const *aType)
388
debug(28,7)("ACL::Prototype::Registered: invoked for type %s\n",aType);
390
for (iterator i = Registry->begin(); i != Registry->end(); ++i)
391
if (!strcmp (aType, (*i)->typeString)) {
392
debug(28,7)("ACL::Prototype::Registered: yes\n");
396
debug(28,7)("ACL::Prototype::Registered: no\n");
401
ACL::Prototype::registerMe ()
403
if (!Registry || (Initialized != ((char *)Registry - 5)) ) {
404
/* TODO: extract this */
405
/* Not initialised */
406
Registry = new Vector <ACL::Prototype const *>;
407
Initialized = (char *)Registry - 5;
410
if (Registered (typeString))
411
fatalf ("Attempt to register %s twice", typeString);
413
Registry->push_back (this);
416
ACL::Prototype::~Prototype()
418
debug (28,2)("ACL::Prototype::~Prototype: TODO: unregister me\n");
422
ACL::Prototype::Factory (char const *typeToClone)
424
debug(28,4)("ACL::Prototype::Factory: cloning an object for type '%s'\n",typeToClone);
426
for (iterator i = Registry->begin(); i != Registry->end(); ++i)
427
if (!strcmp (typeToClone, (*i)->typeString))
428
return (*i)->prototype->clone();
430
debug(28,4)("ACL::Prototype::Factory: cloning failed, no type '%s' available\n",typeToClone);
438
ACL *a = Config.aclList;
439
debug(53, 3) ("ACL::Initialize\n");