]> git.ipfire.org Git - thirdparty/squid.git/blob - src/acl.cc
Cleanup: zap CVS Id tags
[thirdparty/squid.git] / src / acl.cc
1 /*
2 * $Id$
3 *
4 * DEBUG: section 28 Access Control
5 * AUTHOR: Duane Wessels
6 *
7 * SQUID Web Proxy Cache http://www.squid-cache.org/
8 * ----------------------------------------------------------
9 *
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.
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
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
32 *
33 */
34 #include "config.h"
35
36 #if 0
37 #include "squid.h"
38 #include "HttpRequest.h"
39 #endif
40
41 #include "ACL.h"
42 #include "ACLChecklist.h"
43 #include "ConfigParser.h"
44 #include "dlink.h"
45 /* for special-case PURGE test */
46 #include "HttpRequestMethod.h"
47 /* for Vector<> Instances */
48 #include "assert.h"
49
50 const char *AclMatchedName = NULL;
51
52 void *
53 ACL::operator new (size_t byteCount)
54 {
55 fatal ("unusable ACL::new");
56 return (void *)1;
57 }
58
59 void
60 ACL::operator delete (void *address)
61 {
62 fatal ("unusable ACL::delete");
63 }
64
65 ACL *
66 ACL::FindByName(const char *name)
67 {
68 ACL *a;
69 debugs(28, 9, "ACL::FindByName '" << name << "'");
70
71 for (a = Config.aclList; a; a = a->next)
72 if (!strcasecmp(a->name, name))
73 return a;
74
75 debugs(28, 9, "ACL::FindByName found no match");
76
77 return NULL;
78 }
79
80 ACL *
81 ACL::Factory (char const *type)
82 {
83 ACL *result = Prototype::Factory (type);
84
85 if (!result)
86 fatal ("Unknown acl type in ACL::Factory");
87
88 return result;
89 }
90
91 ACL::ACL () :cfgline(NULL) {}
92
93 bool ACL::valid () const
94 {
95 return true;
96 }
97
98 void
99 ACL::ParseAclLine(ConfigParser &parser, ACL ** head)
100 {
101 /* we're already using strtok() to grok the line */
102 char *t = NULL;
103 ACL *A = NULL;
104 LOCAL_ARRAY(char, aclname, ACL_NAME_SZ);
105 int new_acl = 0;
106
107 /* snarf the ACL name */
108
109 if ((t = strtok(NULL, w_space)) == NULL) {
110 debugs(28, 0, "aclParseAclLine: missing ACL name.");
111 parser.destruct();
112 return;
113 }
114
115 if (strlen(t) >= ACL_NAME_SZ) {
116 debugs(28, 0, "aclParseAclLine: aclParseAclLine: ACL name '" << t <<
117 "' too long, max " << ACL_NAME_SZ - 1 << " characters supported");
118 parser.destruct();
119 return;
120 }
121
122 xstrncpy(aclname, t, ACL_NAME_SZ);
123 /* snarf the ACL type */
124 char *theType;
125
126 if ((theType = strtok(NULL, w_space)) == NULL) {
127 debugs(28, 0, "aclParseAclLine: missing ACL type.");
128 parser.destruct();
129 return;
130 }
131
132 if (!Prototype::Registered (theType)) {
133 debugs(28, 0, "aclParseAclLine: Invalid ACL type '" << theType << "'");
134 parser.destruct();
135 return;
136 }
137
138 if ((A = FindByName(aclname)) == NULL) {
139 debugs(28, 3, "aclParseAclLine: Creating ACL '" << aclname << "'");
140 A = ACL::Factory(theType);
141 xstrncpy(A->name, aclname, ACL_NAME_SZ);
142 A->cfgline = xstrdup(config_input_line);
143 new_acl = 1;
144 } else {
145 if (strcmp (A->typeString(),theType) ) {
146 debugs(28, 0, "aclParseAclLine: ACL '" << A->name << "' already exists with different type.");
147 parser.destruct();
148 return;
149 }
150
151 debugs(28, 3, "aclParseAclLine: Appending to '" << aclname << "'");
152 new_acl = 0;
153 }
154
155 /*
156 * Here we set AclMatchedName in case we need to use it in a
157 * warning message in aclDomainCompare().
158 */
159 AclMatchedName = A->name; /* ugly */
160
161 /*split the function here */
162 A->parse();
163
164 /*
165 * Clear AclMatchedName from our temporary hack
166 */
167 AclMatchedName = NULL; /* ugly */
168
169 if (!new_acl)
170 return;
171
172 if (A->empty()) {
173 debugs(28, 0, "Warning: empty ACL: " << A->cfgline);
174 }
175
176 if (!A->valid()) {
177 fatalf("ERROR: Invalid ACL: %s\n",
178 A->cfgline);
179 }
180
181 /* append */
182 while (*head)
183 head = &(*head)->next;
184
185 *head = A;
186 }
187
188 bool
189 ACL::isProxyAuth() const
190 {
191 return false;
192 }
193
194
195 ACLList::ACLList() : op (1), _acl (NULL), next (NULL)
196 {}
197
198 void
199 ACLList::negated(bool isNegated)
200 {
201 if (isNegated)
202 op = 0;
203 else
204 op = 1;
205 }
206
207 /* ACL result caching routines */
208
209 int
210 ACL::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
218 /*
219 * we lookup an acl's cached results, and if we cannot find the acl being
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
223 * wise in long lived caches (i.e. the auth_user proxy match cache)
224 * RBC
225 * TODO: does a dlink_list perform well enough? Kinkie
226 */
227 int
228 ACL::cacheMatchAcl(dlink_list * cache, ACLChecklist *checklist)
229 {
230 acl_proxy_auth_match_cache *auth_match;
231 dlink_node *link;
232 link = cache->head;
233
234 while (link) {
235 auth_match = (acl_proxy_auth_match_cache *)link->data;
236
237 if (auth_match->acl_data == this) {
238 debugs(28, 4, "ACL::cacheMatchAcl: cache hit on acl '" << name << "' (" << this << ")");
239 return auth_match->matchrv;
240 }
241
242 link = link->next;
243 }
244
245 auth_match = new acl_proxy_auth_match_cache();
246 auth_match->matchrv = matchForCache (checklist);
247 auth_match->acl_data = this;
248 dlinkAddTail(auth_match, &auth_match->link, cache);
249 debugs(28, 4, "ACL::cacheMatchAcl: miss for '" << name << "'. Adding result " << auth_match->matchrv);
250 return auth_match->matchrv;
251 }
252
253 void
254 aclCacheMatchFlush(dlink_list * cache)
255 {
256 acl_proxy_auth_match_cache *auth_match;
257 dlink_node *link, *tmplink;
258 link = cache->head;
259
260 debugs(28, 8, "aclCacheMatchFlush called for cache " << cache);
261
262 while (link) {
263 auth_match = (acl_proxy_auth_match_cache *)link->data;
264 tmplink = link;
265 link = link->next;
266 dlinkDelete(tmplink, cache);
267 delete auth_match;
268 }
269 }
270
271 bool
272 ACL::requiresReply() const
273 {
274 return false;
275 }
276
277 bool
278 ACL::requiresRequest() const
279 {
280 return false;
281 }
282
283 int
284 ACL::checklistMatches(ACLChecklist *checklist)
285 {
286 int rv;
287
288 if (NULL == checklist->request && requiresRequest()) {
289 debugs(28, 1, "ACL::checklistMatches WARNING: '" << name << "' ACL is used but there is no HTTP request -- not matching.");
290 return 0;
291 }
292
293 if (NULL == checklist->reply && requiresReply()) {
294 debugs(28, 1, "ACL::checklistMatches WARNING: '" << name << "' ACL is used but there is no HTTP reply -- not matching.");
295 return 0;
296 }
297
298 debugs(28, 3, "ACL::checklistMatches: checking '" << name << "'");
299 rv= match(checklist);
300 debugs(28, 3, "ACL::ChecklistMatches: result for '" << name << "' is " << rv);
301 return rv;
302 }
303
304 bool
305 ACLList::matches (ACLChecklist *checklist) const
306 {
307 assert (_acl);
308 AclMatchedName = _acl->name;
309 debugs(28, 3, "ACLList::matches: checking " << (op ? null_string : "!") << _acl->name);
310
311 if (_acl->checklistMatches(checklist) != op) {
312 debugs(28, 4, "ACLList::matches: result is false");
313 return checklist->lastACLResult(false);
314 }
315
316 debugs(28, 4, "ACLList::matches: result is true");
317 return checklist->lastACLResult(true);
318 }
319
320
321 /*********************/
322 /* Destroy functions */
323 /*********************/
324
325 ACL::~ACL()
326 {
327 debugs(28, 3, "ACL::~ACL: '" << cfgline << "'");
328 safe_free(cfgline);
329 }
330
331 #include "ACLStrategised.h"
332 bool
333 acl_access::containsPURGE() const
334 {
335 acl_access const *a = this;
336 ACLList *b;
337
338 debugs(28, 6, "acl_access::containsPURGE: invoked for '" << cfgline << "'");
339
340 for (; a; a = a->next) {
341 for (b = a->aclList; b; b = b->next) {
342 ACLStrategised<HttpRequestMethod> *tempAcl = dynamic_cast<ACLStrategised<HttpRequestMethod> *>(b->_acl);
343
344 if (!tempAcl) {
345 debugs(28, 7, "acl_access::containsPURGE: can't create tempAcl");
346 continue;
347 }
348
349 if (tempAcl->match(METHOD_PURGE)) {
350 debugs(28, 6, "acl_access::containsPURGE: returning true");
351 return true;
352 }
353 }
354 }
355
356 debugs(28, 6, "acl_access::containsPURGE: returning false");
357 return false;
358 }
359
360 /* to be split into separate files in the future */
361
362 CBDATA_CLASS_INIT(acl_access);
363
364 void *
365 acl_access::operator new (size_t)
366 {
367 CBDATA_INIT_TYPE(acl_access);
368 acl_access *result = cbdataAlloc(acl_access);
369 return result;
370 }
371
372 void
373 acl_access::operator delete (void *address)
374 {
375 acl_access *t = static_cast<acl_access *>(address);
376 cbdataFree(t);
377 }
378
379 ACL::Prototype::Prototype() : prototype (NULL), typeString (NULL) {}
380
381 ACL::Prototype::Prototype (ACL const *aPrototype, char const *aType) : prototype (aPrototype), typeString (aType)
382 {
383 registerMe ();
384 }
385
386 Vector<ACL::Prototype const *> * ACL::Prototype::Registry;
387 void *ACL::Prototype::Initialized;
388
389 bool
390 ACL::Prototype::Registered(char const *aType)
391 {
392 debugs(28, 7, "ACL::Prototype::Registered: invoked for type " << aType);
393
394 for (iterator i = Registry->begin(); i != Registry->end(); ++i)
395 if (!strcmp (aType, (*i)->typeString)) {
396 debugs(28, 7, "ACL::Prototype::Registered: yes");
397 return true;
398 }
399
400 debugs(28, 7, "ACL::Prototype::Registered: no");
401 return false;
402 }
403
404 void
405 ACL::Prototype::registerMe ()
406 {
407 if (!Registry || (Initialized != ((char *)Registry - 5)) ) {
408 /* TODO: extract this */
409 /* Not initialised */
410 Registry = new Vector <ACL::Prototype const *>;
411 Initialized = (char *)Registry - 5;
412 }
413
414 if (Registered (typeString))
415 fatalf ("Attempt to register %s twice", typeString);
416
417 Registry->push_back (this);
418 }
419
420 ACL::Prototype::~Prototype()
421 {
422 // TODO: unregister me
423 }
424
425 ACL *
426 ACL::Prototype::Factory (char const *typeToClone)
427 {
428 debugs(28, 4, "ACL::Prototype::Factory: cloning an object for type '" << typeToClone << "'");
429
430 for (iterator i = Registry->begin(); i != Registry->end(); ++i)
431 if (!strcmp (typeToClone, (*i)->typeString))
432 return (*i)->prototype->clone();
433
434 debugs(28, 4, "ACL::Prototype::Factory: cloning failed, no type '" << typeToClone << "' available");
435
436 return NULL;
437 }
438
439 void
440 ACL::Initialize()
441 {
442 ACL *a = Config.aclList;
443 debugs(53, 3, "ACL::Initialize");
444
445 while (a) {
446 a->prepareForUse();
447 a = a->next;
448 }
449 }