]> git.ipfire.org Git - thirdparty/squid.git/blame - src/acl/Acl.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / acl / 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 */
f7f3304a 34#include "squid.h"
c15d448c
AR
35#include "acl/Acl.h"
36#include "acl/Checklist.h"
582c2af2 37#include "anyp/PortCfg.h"
d295d770 38#include "ConfigParser.h"
38dedeed 39#include "Debug.h"
e1f7507e 40#include "dlink.h"
582c2af2 41#include "globals.h"
23351cb2 42
b0dd28ba 43const char *AclMatchedName = NULL;
44
8000a965 45void *
46ACL::operator new (size_t byteCount)
47{
b0dd28ba 48 fatal ("unusable ACL::new");
49 return (void *)1;
8000a965 50}
51
52void
53ACL::operator delete (void *address)
54{
b0dd28ba 55 fatal ("unusable ACL::delete");
56b63fa1 56}
57
97427e90 58ACL *
225b7b10 59ACL::FindByName(const char *name)
7dd57fa2 60{
97427e90 61 ACL *a;
bf8fe701 62 debugs(28, 9, "ACL::FindByName '" << name << "'");
62e76326 63
9bea1d5b 64 for (a = Config.aclList; a; a = a->next)
62e76326 65 if (!strcasecmp(a->name, name))
66 return a;
67
bf8fe701 68 debugs(28, 9, "ACL::FindByName found no match");
6bf4f823 69
9bea1d5b 70 return NULL;
7dd57fa2 71}
72
8000a965 73ACL *
74ACL::Factory (char const *type)
75{
76 ACL *result = Prototype::Factory (type);
62e76326 77
b0dd28ba 78 if (!result)
62e76326 79 fatal ("Unknown acl type in ACL::Factory");
62e76326 80
8000a965 81 return result;
82}
83
d295d770 84ACL::ACL () :cfgline(NULL) {}
8000a965 85
4b0f5de8 86bool ACL::valid () const
87{
88 return true;
89}
90
8203a132 91void
a9f20260 92ACL::ParseAclLine(ConfigParser &parser, ACL ** head)
9bea1d5b 93{
94 /* we're already using strtok() to grok the line */
95 char *t = NULL;
97427e90 96 ACL *A = NULL;
9bea1d5b 97 LOCAL_ARRAY(char, aclname, ACL_NAME_SZ);
9bea1d5b 98 int new_acl = 0;
99
100 /* snarf the ACL name */
62e76326 101
9bea1d5b 102 if ((t = strtok(NULL, w_space)) == NULL) {
fa84c01d 103 debugs(28, DBG_CRITICAL, "aclParseAclLine: missing ACL name.");
a9f20260 104 parser.destruct();
62e76326 105 return;
9bea1d5b 106 }
62e76326 107
401f503a 108 if (strlen(t) >= ACL_NAME_SZ) {
fa84c01d 109 debugs(28, DBG_CRITICAL, "aclParseAclLine: aclParseAclLine: ACL name '" << t <<
bf8fe701 110 "' too long, max " << ACL_NAME_SZ - 1 << " characters supported");
401f503a 111 parser.destruct();
112 return;
113 }
114
9bea1d5b 115 xstrncpy(aclname, t, ACL_NAME_SZ);
116 /* snarf the ACL type */
38dedeed 117 const char *theType;
62e76326 118
b0dd28ba 119 if ((theType = strtok(NULL, w_space)) == NULL) {
fa84c01d 120 debugs(28, DBG_CRITICAL, "aclParseAclLine: missing ACL type.");
a9f20260 121 parser.destruct();
62e76326 122 return;
9bea1d5b 123 }
62e76326 124
8306968f 125 // Is this ACL going to work?
18c41901 126 if (strcmp(theType, "myip") == 0) {
65d448bc 127 AnyP::PortCfg *p = Config.Sockaddr.http;
a9336c23 128 while (p) {
8306968f
AJ
129 // Bug 3239: not reliable when there is interception traffic coming
130 if (p->intercepted)
131 debugs(28, DBG_CRITICAL, "WARNING: 'myip' ACL is not reliable for interception proxies. Please use 'myportname' instead.");
132 p = p->next;
133 }
38dedeed 134 debugs(28, DBG_IMPORTANT, "UPGRADE: ACL 'myip' type is has been renamed to 'localip' and matches the IP the client connected to.");
1e40905d 135 theType = "localip";
18c41901 136 } else if (strcmp(theType, "myport") == 0) {
65d448bc 137 AnyP::PortCfg *p = Config.Sockaddr.http;
a9336c23 138 while (p) {
8306968f
AJ
139 // Bug 3239: not reliable when there is interception traffic coming
140 // Bug 3239: myport - not reliable (yet) when there is interception traffic coming
141 if (p->intercepted)
142 debugs(28, DBG_CRITICAL, "WARNING: 'myport' ACL is not reliable for interception proxies. Please use 'myportname' instead.");
143 p = p->next;
144 }
1e40905d 145 theType = "localport";
38dedeed 146 debugs(28, DBG_IMPORTANT, "UPGRADE: ACL 'myport' type is has been renamed to 'localport' and matches the port the client connected to.");
1e40905d
AJ
147 }
148
149 if (!Prototype::Registered(theType)) {
150 debugs(28, DBG_CRITICAL, "FATAL: Invalid ACL type '" << theType << "'");
151 // XXX: make this an ERROR and skip the ACL creation. We *may* die later when its use is attempted. Or may not.
152 parser.destruct();
153 return;
8306968f
AJ
154 }
155
225b7b10 156 if ((A = FindByName(aclname)) == NULL) {
bf8fe701 157 debugs(28, 3, "aclParseAclLine: Creating ACL '" << aclname << "'");
b0dd28ba 158 A = ACL::Factory(theType);
62e76326 159 xstrncpy(A->name, aclname, ACL_NAME_SZ);
160 A->cfgline = xstrdup(config_input_line);
161 new_acl = 1;
9bea1d5b 162 } else {
b0dd28ba 163 if (strcmp (A->typeString(),theType) ) {
fa84c01d 164 debugs(28, DBG_CRITICAL, "aclParseAclLine: ACL '" << A->name << "' already exists with different type.");
a9f20260 165 parser.destruct();
62e76326 166 return;
167 }
168
bf8fe701 169 debugs(28, 3, "aclParseAclLine: Appending to '" << aclname << "'");
62e76326 170 new_acl = 0;
9bea1d5b 171 }
62e76326 172
9bea1d5b 173 /*
174 * Here we set AclMatchedName in case we need to use it in a
175 * warning message in aclDomainCompare().
176 */
8000a965 177 AclMatchedName = A->name; /* ugly */
178
179 /*split the function here */
180 A->parse();
62e76326 181
8000a965 182 /*
183 * Clear AclMatchedName from our temporary hack
184 */
185 AclMatchedName = NULL; /* ugly */
62e76326 186
8000a965 187 if (!new_acl)
62e76326 188 return;
189
4b0f5de8 190 if (A->empty()) {
fa84c01d 191 debugs(28, DBG_CRITICAL, "Warning: empty ACL: " << A->cfgline);
4b0f5de8 192 }
193
194 if (!A->valid()) {
195 fatalf("ERROR: Invalid ACL: %s\n",
196 A->cfgline);
8000a965 197 }
62e76326 198
8000a965 199 /* append */
200 while (*head)
62e76326 201 head = &(*head)->next;
202
8000a965 203 *head = A;
204}
205
8000a965 206bool
207ACL::isProxyAuth() const
208{
225b7b10 209 return false;
8000a965 210}
1cfdbcf0 211
8000a965 212ACLList::ACLList() : op (1), _acl (NULL), next (NULL)
62e76326 213{}
8000a965 214
215void
216ACLList::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 226int
227ACL::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 244int
245ACL::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
270void
9bea1d5b 271aclCacheMatchFlush(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 288bool
289ACL::requiresReply() const
290{
291 return false;
292}
60d096f4 293
b0dd28ba 294bool
295ACL::requiresRequest() const
9bea1d5b 296{
b0dd28ba 297 return false;
298}
62e76326 299
b0dd28ba 300int
301ACL::checklistMatches(ACLChecklist *checklist)
302{
6bf4f823 303 int rv;
304
c15d448c 305 if (!checklist->hasRequest() && requiresRequest()) {
e0236918 306 debugs(28, DBG_IMPORTANT, "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()) {
e0236918 311 debugs(28, DBG_IMPORTANT, "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 321bool
322ACLList::matches (ACLChecklist *checklist) const
60d096f4 323{
b0dd28ba 324 assert (_acl);
e0f7153c 325 // XXX: AclMatchedName does not contain a matched ACL name when the acl
c0f81932 326 // does not match (or contains stale name if no ACLs are checked). In
e0f7153c
AR
327 // either case, we get misleading debugging and possibly incorrect error
328 // messages. Unfortunately, deny_info's "when none http_access
329 // lines match" exception essentially requires this mess.
330 // TODO: Rework by using an acl-free deny_info for the no-match cases?
b0dd28ba 331 AclMatchedName = _acl->name;
bf8fe701 332 debugs(28, 3, "ACLList::matches: checking " << (op ? null_string : "!") << _acl->name);
62e76326 333
b0dd28ba 334 if (_acl->checklistMatches(checklist) != op) {
bf8fe701 335 debugs(28, 4, "ACLList::matches: result is false");
e0f7153c 336 return false;
b0dd28ba 337 }
62e76326 338
bf8fe701 339 debugs(28, 4, "ACLList::matches: result is true");
e0f7153c 340 return true;
60d096f4 341}
94439e4e 342
f32789f4 343/*********************/
344/* Destroy functions */
345/*********************/
346
8000a965 347ACL::~ACL()
348{
bf8fe701 349 debugs(28, 3, "ACL::~ACL: '" << cfgline << "'");
62e76326 350 safe_free(cfgline);
92a6f4b1 351}
352
29b17d63 353/* to be split into separate files in the future */
354
8000a965 355CBDATA_CLASS_INIT(acl_access);
356
357void *
358acl_access::operator new (size_t)
359{
360 CBDATA_INIT_TYPE(acl_access);
361 acl_access *result = cbdataAlloc(acl_access);
362 return result;
363}
364
365void
366acl_access::operator delete (void *address)
367{
368 acl_access *t = static_cast<acl_access *>(address);
369 cbdataFree(t);
370}
371
8000a965 372ACL::Prototype::Prototype() : prototype (NULL), typeString (NULL) {}
373
62e76326 374ACL::Prototype::Prototype (ACL const *aPrototype, char const *aType) : prototype (aPrototype), typeString (aType)
8000a965 375{
376 registerMe ();
377}
378
379Vector<ACL::Prototype const *> * ACL::Prototype::Registry;
380void *ACL::Prototype::Initialized;
381
382bool
62e76326 383ACL::Prototype::Registered(char const *aType)
8000a965 384{
bf8fe701 385 debugs(28, 7, "ACL::Prototype::Registered: invoked for type " << aType);
6bf4f823 386
8000a965 387 for (iterator i = Registry->begin(); i != Registry->end(); ++i)
6bf4f823 388 if (!strcmp (aType, (*i)->typeString)) {
bf8fe701 389 debugs(28, 7, "ACL::Prototype::Registered: yes");
62e76326 390 return true;
6bf4f823 391 }
62e76326 392
bf8fe701 393 debugs(28, 7, "ACL::Prototype::Registered: no");
8000a965 394 return false;
395}
396
397void
398ACL::Prototype::registerMe ()
399{
400 if (!Registry || (Initialized != ((char *)Registry - 5)) ) {
62e76326 401 /* TODO: extract this */
402 /* Not initialised */
403 Registry = new Vector <ACL::Prototype const *>;
404 Initialized = (char *)Registry - 5;
8000a965 405 }
62e76326 406
8000a965 407 if (Registered (typeString))
62e76326 408 fatalf ("Attempt to register %s twice", typeString);
409
8000a965 410 Registry->push_back (this);
411}
412
62e76326 413ACL::Prototype::~Prototype()
8000a965 414{
67b7fa0d 415 // TODO: unregister me
8000a965 416}
417
418ACL *
419ACL::Prototype::Factory (char const *typeToClone)
420{
bf8fe701 421 debugs(28, 4, "ACL::Prototype::Factory: cloning an object for type '" << typeToClone << "'");
6bf4f823 422
8000a965 423 for (iterator i = Registry->begin(); i != Registry->end(); ++i)
62e76326 424 if (!strcmp (typeToClone, (*i)->typeString))
425 return (*i)->prototype->clone();
426
bf8fe701 427 debugs(28, 4, "ACL::Prototype::Factory: cloning failed, no type '" << typeToClone << "' available");
6bf4f823 428
8000a965 429 return NULL;
430}
431
b0dd28ba 432void
433ACL::Initialize()
8000a965 434{
97427e90 435 ACL *a = Config.aclList;
bf8fe701 436 debugs(53, 3, "ACL::Initialize");
b0dd28ba 437
438 while (a) {
439 a->prepareForUse();
440 a = a->next;
441 }
8000a965 442}