]> git.ipfire.org Git - thirdparty/squid.git/blame - src/acl/Acl.cc
Cleanup: fix most 'unused parameter' warnings
[thirdparty/squid.git] / src / acl / Acl.cc
CommitLineData
8213067d 1/*
bbc27441 2 * Copyright (C) 1996-2014 The Squid Software Foundation and contributors
e25c139f 3 *
bbc27441
AJ
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
8213067d 7 */
bbc27441
AJ
8
9/* DEBUG: section 28 Access Control */
10
f7f3304a 11#include "squid.h"
c15d448c
AR
12#include "acl/Acl.h"
13#include "acl/Checklist.h"
ed898bdf 14#include "acl/Gadgets.h"
582c2af2 15#include "anyp/PortCfg.h"
33810b1d 16#include "cache_cf.h"
d295d770 17#include "ConfigParser.h"
38dedeed 18#include "Debug.h"
e1f7507e 19#include "dlink.h"
ed6e9fb9 20#include "fatal.h"
582c2af2 21#include "globals.h"
6f58d7d7 22#include "profiler/Profiler.h"
4d5904f7 23#include "SquidConfig.h"
23351cb2 24
81481ec0
FC
25#include <vector>
26
33810b1d
CT
27const ACLFlag ACLFlags::NoFlags[1] = {ACL_F_END};
28
b0dd28ba 29const char *AclMatchedName = NULL;
30
aec45181 31bool ACLFlags::supported(const ACLFlag f) const
33810b1d
CT
32{
33 if (f == ACL_F_REGEX_CASE)
34 return true;
aec45181 35 return (supported_.find(f) != std::string::npos);
33810b1d
CT
36}
37
aec45181 38void
788542bd 39ACLFlags::parseFlags()
33810b1d 40{
788542bd 41 char *nextToken;
bde7a8ce
CT
42 while ((nextToken = ConfigParser::PeekAtToken()) != NULL && nextToken[0] == '-') {
43 (void)ConfigParser::NextToken(); //Get token from cfg line
33810b1d 44 //if token is the "--" break flag
aec45181 45 if (strcmp(nextToken, "--") == 0)
33810b1d
CT
46 break;
47
48 for (const char *flg = nextToken+1; *flg!='\0'; flg++ ) {
49 if (supported(*flg)) {
50 makeSet(*flg);
aec45181 51 } else {
33810b1d
CT
52 debugs(28, 0, HERE << "Flag '" << *flg << "' not supported");
53 self_destruct();
54 }
55 }
56 }
57
58 /*Regex code needs to parse -i file*/
59 if ( isSet(ACL_F_REGEX_CASE))
2eceb328 60 ConfigParser::TokenPutBack("-i");
33810b1d
CT
61}
62
63const char *
64ACLFlags::flagsStr() const
65{
66 static char buf[64];
67 if (flags_ == 0)
68 return "";
69
70 char *s = buf;
71 *s++ = '-';
72 for (ACLFlag f = 'A'; f <= 'z'; f++) {
73 // ACL_F_REGEX_CASE (-i) flag handled by ACLRegexData class, ignore
74 if (isSet(f) && f != ACL_F_REGEX_CASE)
75 *s++ = f;
76 }
77 *s = '\0';
78 return buf;
79}
80
8000a965 81void *
ced8def3 82ACL::operator new (size_t)
8000a965 83{
b0dd28ba 84 fatal ("unusable ACL::new");
85 return (void *)1;
8000a965 86}
87
88void
ced8def3 89ACL::operator delete (void *)
8000a965 90{
b0dd28ba 91 fatal ("unusable ACL::delete");
56b63fa1 92}
93
97427e90 94ACL *
225b7b10 95ACL::FindByName(const char *name)
7dd57fa2 96{
97427e90 97 ACL *a;
bf8fe701 98 debugs(28, 9, "ACL::FindByName '" << name << "'");
62e76326 99
9bea1d5b 100 for (a = Config.aclList; a; a = a->next)
62e76326 101 if (!strcasecmp(a->name, name))
102 return a;
103
bf8fe701 104 debugs(28, 9, "ACL::FindByName found no match");
6bf4f823 105
9bea1d5b 106 return NULL;
7dd57fa2 107}
108
8000a965 109ACL *
110ACL::Factory (char const *type)
111{
112 ACL *result = Prototype::Factory (type);
62e76326 113
b0dd28ba 114 if (!result)
62e76326 115 fatal ("Unknown acl type in ACL::Factory");
62e76326 116
8000a965 117 return result;
118}
119
478a0611 120ACL::ACL() :
f53969cc
SM
121 cfgline(NULL),
122 next(NULL),
123 registered(false)
478a0611
AJ
124{
125 *name = 0;
126}
8000a965 127
4b0f5de8 128bool ACL::valid () const
129{
130 return true;
131}
132
6f58d7d7
AR
133bool
134ACL::matches(ACLChecklist *checklist) const
135{
136 PROF_start(ACL_matches);
137 debugs(28, 5, "checking " << name);
138
139 // XXX: AclMatchedName does not contain a matched ACL name when the acl
140 // does not match. It contains the last (usually leaf) ACL name checked
141 // (or is NULL if no ACLs were checked).
142 AclMatchedName = name;
143
144 int result = 0;
145 if (!checklist->hasRequest() && requiresRequest()) {
146 debugs(28, DBG_IMPORTANT, "WARNING: " << name << " ACL is used in " <<
147 "context without an HTTP request. Assuming mismatch.");
148 } else if (!checklist->hasReply() && requiresReply()) {
149 debugs(28, DBG_IMPORTANT, "WARNING: " << name << " ACL is used in " <<
150 "context without an HTTP response. Assuming mismatch.");
151 } else {
152 // have to cast because old match() API is missing const
153 result = const_cast<ACL*>(this)->match(checklist);
154 }
155
156 const char *extra = checklist->asyncInProgress() ? " async" : "";
157 debugs(28, 3, "checked: " << name << " = " << result << extra);
158 PROF_stop(ACL_matches);
159 return result == 1; // true for match; false for everything else
160}
161
162void
163ACL::context(const char *aName, const char *aCfgLine)
164{
165 name[0] = '\0';
166 if (aName)
167 xstrncpy(name, aName, ACL_NAME_SZ-1);
168 safe_free(cfgline);
169 if (aCfgLine)
170 cfgline = xstrdup(aCfgLine);
171}
172
8203a132 173void
a9f20260 174ACL::ParseAclLine(ConfigParser &parser, ACL ** head)
9bea1d5b 175{
176 /* we're already using strtok() to grok the line */
177 char *t = NULL;
97427e90 178 ACL *A = NULL;
9bea1d5b 179 LOCAL_ARRAY(char, aclname, ACL_NAME_SZ);
9bea1d5b 180 int new_acl = 0;
181
182 /* snarf the ACL name */
62e76326 183
2eceb328 184 if ((t = ConfigParser::NextToken()) == NULL) {
fa84c01d 185 debugs(28, DBG_CRITICAL, "aclParseAclLine: missing ACL name.");
a9f20260 186 parser.destruct();
62e76326 187 return;
9bea1d5b 188 }
62e76326 189
401f503a 190 if (strlen(t) >= ACL_NAME_SZ) {
fa84c01d 191 debugs(28, DBG_CRITICAL, "aclParseAclLine: aclParseAclLine: ACL name '" << t <<
bf8fe701 192 "' too long, max " << ACL_NAME_SZ - 1 << " characters supported");
401f503a 193 parser.destruct();
194 return;
195 }
196
9bea1d5b 197 xstrncpy(aclname, t, ACL_NAME_SZ);
198 /* snarf the ACL type */
38dedeed 199 const char *theType;
62e76326 200
2eceb328 201 if ((theType = ConfigParser::NextToken()) == NULL) {
fa84c01d 202 debugs(28, DBG_CRITICAL, "aclParseAclLine: missing ACL type.");
a9f20260 203 parser.destruct();
62e76326 204 return;
9bea1d5b 205 }
62e76326 206
8306968f 207 // Is this ACL going to work?
18c41901 208 if (strcmp(theType, "myip") == 0) {
fa720bfb
AJ
209 AnyP::PortCfgPointer p = HttpPortList;
210 while (p != NULL) {
8306968f 211 // Bug 3239: not reliable when there is interception traffic coming
6a25a046 212 if (p->flags.natIntercept)
8306968f
AJ
213 debugs(28, DBG_CRITICAL, "WARNING: 'myip' ACL is not reliable for interception proxies. Please use 'myportname' instead.");
214 p = p->next;
215 }
38dedeed 216 debugs(28, DBG_IMPORTANT, "UPGRADE: ACL 'myip' type is has been renamed to 'localip' and matches the IP the client connected to.");
1e40905d 217 theType = "localip";
18c41901 218 } else if (strcmp(theType, "myport") == 0) {
fa720bfb
AJ
219 AnyP::PortCfgPointer p = HttpPortList;
220 while (p != NULL) {
8306968f
AJ
221 // Bug 3239: not reliable when there is interception traffic coming
222 // Bug 3239: myport - not reliable (yet) when there is interception traffic coming
6a25a046 223 if (p->flags.natIntercept)
8306968f
AJ
224 debugs(28, DBG_CRITICAL, "WARNING: 'myport' ACL is not reliable for interception proxies. Please use 'myportname' instead.");
225 p = p->next;
226 }
1e40905d 227 theType = "localport";
38dedeed 228 debugs(28, DBG_IMPORTANT, "UPGRADE: ACL 'myport' type is has been renamed to 'localport' and matches the port the client connected to.");
1e40905d
AJ
229 }
230
231 if (!Prototype::Registered(theType)) {
232 debugs(28, DBG_CRITICAL, "FATAL: Invalid ACL type '" << theType << "'");
233 // XXX: make this an ERROR and skip the ACL creation. We *may* die later when its use is attempted. Or may not.
234 parser.destruct();
235 return;
8306968f
AJ
236 }
237
225b7b10 238 if ((A = FindByName(aclname)) == NULL) {
bf8fe701 239 debugs(28, 3, "aclParseAclLine: Creating ACL '" << aclname << "'");
b0dd28ba 240 A = ACL::Factory(theType);
6f58d7d7 241 A->context(aclname, config_input_line);
62e76326 242 new_acl = 1;
9bea1d5b 243 } else {
b0dd28ba 244 if (strcmp (A->typeString(),theType) ) {
fa84c01d 245 debugs(28, DBG_CRITICAL, "aclParseAclLine: ACL '" << A->name << "' already exists with different type.");
a9f20260 246 parser.destruct();
62e76326 247 return;
248 }
249
bf8fe701 250 debugs(28, 3, "aclParseAclLine: Appending to '" << aclname << "'");
62e76326 251 new_acl = 0;
9bea1d5b 252 }
62e76326 253
9bea1d5b 254 /*
255 * Here we set AclMatchedName in case we need to use it in a
256 * warning message in aclDomainCompare().
257 */
f53969cc 258 AclMatchedName = A->name; /* ugly */
8000a965 259
788542bd 260 A->flags.parseFlags();
33810b1d 261
8000a965 262 /*split the function here */
263 A->parse();
62e76326 264
8000a965 265 /*
266 * Clear AclMatchedName from our temporary hack
267 */
f53969cc 268 AclMatchedName = NULL; /* ugly */
62e76326 269
8000a965 270 if (!new_acl)
62e76326 271 return;
272
4b0f5de8 273 if (A->empty()) {
fa84c01d 274 debugs(28, DBG_CRITICAL, "Warning: empty ACL: " << A->cfgline);
4b0f5de8 275 }
276
277 if (!A->valid()) {
278 fatalf("ERROR: Invalid ACL: %s\n",
279 A->cfgline);
8000a965 280 }
62e76326 281
ed898bdf 282 // add to the global list for searching explicit ACLs by name
6f58d7d7 283 assert(head && *head == Config.aclList);
a57c224d 284 A->next = *head;
8000a965 285 *head = A;
ed898bdf
AR
286
287 // register for centralized cleanup
288 aclRegister(A);
8000a965 289}
290
8000a965 291bool
292ACL::isProxyAuth() const
293{
225b7b10 294 return false;
8000a965 295}
1cfdbcf0 296
94439e4e 297/* ACL result caching routines */
298
225b7b10 299int
ced8def3 300ACL::matchForCache(ACLChecklist *)
225b7b10 301{
302 /* This is a fatal to ensure that cacheMatchAcl calls are _only_
303 * made for supported acl types */
304 fatal("aclCacheMatchAcl: unknown or unexpected ACL type");
f53969cc 305 return 0; /* NOTREACHED */
225b7b10 306}
307
94439e4e 308/*
26ac0430 309 * we lookup an acl's cached results, and if we cannot find the acl being
225b7b10 310 * checked we check it and cache the result. This function is a template
311 * method to support caching of multiple acl types.
312 * Note that caching of time based acl's is not
6bf4f823 313 * wise in long lived caches (i.e. the auth_user proxy match cache)
94439e4e 314 * RBC
6bf4f823 315 * TODO: does a dlink_list perform well enough? Kinkie
94439e4e 316 */
225b7b10 317int
318ACL::cacheMatchAcl(dlink_list * cache, ACLChecklist *checklist)
9bea1d5b 319{
9bea1d5b 320 acl_proxy_auth_match_cache *auth_match;
321 dlink_node *link;
322 link = cache->head;
62e76326 323
9bea1d5b 324 while (link) {
62e76326 325 auth_match = (acl_proxy_auth_match_cache *)link->data;
326
327 if (auth_match->acl_data == this) {
bf8fe701 328 debugs(28, 4, "ACL::cacheMatchAcl: cache hit on acl '" << name << "' (" << this << ")");
62e76326 329 return auth_match->matchrv;
330 }
331
332 link = link->next;
9bea1d5b 333 }
62e76326 334
11a9f1b1 335 auth_match = new acl_proxy_auth_match_cache();
225b7b10 336 auth_match->matchrv = matchForCache (checklist);
337 auth_match->acl_data = this;
9bea1d5b 338 dlinkAddTail(auth_match, &auth_match->link, cache);
bf8fe701 339 debugs(28, 4, "ACL::cacheMatchAcl: miss for '" << name << "'. Adding result " << auth_match->matchrv);
225b7b10 340 return auth_match->matchrv;
94439e4e 341}
342
343void
9bea1d5b 344aclCacheMatchFlush(dlink_list * cache)
94439e4e 345{
9bea1d5b 346 acl_proxy_auth_match_cache *auth_match;
347 dlink_node *link, *tmplink;
348 link = cache->head;
62e76326 349
bf8fe701 350 debugs(28, 8, "aclCacheMatchFlush called for cache " << cache);
6bf4f823 351
9bea1d5b 352 while (link) {
62e76326 353 auth_match = (acl_proxy_auth_match_cache *)link->data;
354 tmplink = link;
355 link = link->next;
356 dlinkDelete(tmplink, cache);
11a9f1b1 357 delete auth_match;
1f38f50a 358 }
c68e9c6b 359}
73e67ee0 360
b0dd28ba 361bool
362ACL::requiresReply() const
363{
364 return false;
365}
60d096f4 366
b0dd28ba 367bool
368ACL::requiresRequest() const
9bea1d5b 369{
b0dd28ba 370 return false;
371}
62e76326 372
f32789f4 373/*********************/
374/* Destroy functions */
375/*********************/
376
8000a965 377ACL::~ACL()
378{
bf8fe701 379 debugs(28, 3, "ACL::~ACL: '" << cfgline << "'");
62e76326 380 safe_free(cfgline);
6f58d7d7 381 AclMatchedName = NULL; // in case it was pointing to our name
92a6f4b1 382}
383
8000a965 384ACL::Prototype::Prototype() : prototype (NULL), typeString (NULL) {}
385
62e76326 386ACL::Prototype::Prototype (ACL const *aPrototype, char const *aType) : prototype (aPrototype), typeString (aType)
8000a965 387{
388 registerMe ();
389}
390
81481ec0 391std::vector<ACL::Prototype const *> * ACL::Prototype::Registry;
8000a965 392void *ACL::Prototype::Initialized;
393
394bool
62e76326 395ACL::Prototype::Registered(char const *aType)
8000a965 396{
bf8fe701 397 debugs(28, 7, "ACL::Prototype::Registered: invoked for type " << aType);
6bf4f823 398
8000a965 399 for (iterator i = Registry->begin(); i != Registry->end(); ++i)
6bf4f823 400 if (!strcmp (aType, (*i)->typeString)) {
bf8fe701 401 debugs(28, 7, "ACL::Prototype::Registered: yes");
62e76326 402 return true;
6bf4f823 403 }
62e76326 404
bf8fe701 405 debugs(28, 7, "ACL::Prototype::Registered: no");
8000a965 406 return false;
407}
408
409void
410ACL::Prototype::registerMe ()
411{
412 if (!Registry || (Initialized != ((char *)Registry - 5)) ) {
62e76326 413 /* TODO: extract this */
414 /* Not initialised */
81481ec0 415 Registry = new std::vector<ACL::Prototype const *>;
62e76326 416 Initialized = (char *)Registry - 5;
8000a965 417 }
62e76326 418
8000a965 419 if (Registered (typeString))
62e76326 420 fatalf ("Attempt to register %s twice", typeString);
421
8000a965 422 Registry->push_back (this);
423}
424
62e76326 425ACL::Prototype::~Prototype()
8000a965 426{
67b7fa0d 427 // TODO: unregister me
8000a965 428}
429
430ACL *
431ACL::Prototype::Factory (char const *typeToClone)
432{
bf8fe701 433 debugs(28, 4, "ACL::Prototype::Factory: cloning an object for type '" << typeToClone << "'");
6bf4f823 434
8000a965 435 for (iterator i = Registry->begin(); i != Registry->end(); ++i)
33810b1d
CT
436 if (!strcmp (typeToClone, (*i)->typeString)) {
437 ACL *A = (*i)->prototype->clone();
438 A->flags = (*i)->prototype->flags;
439 return A;
440 }
62e76326 441
bf8fe701 442 debugs(28, 4, "ACL::Prototype::Factory: cloning failed, no type '" << typeToClone << "' available");
6bf4f823 443
8000a965 444 return NULL;
445}
446
b0dd28ba 447void
448ACL::Initialize()
8000a965 449{
97427e90 450 ACL *a = Config.aclList;
bf8fe701 451 debugs(53, 3, "ACL::Initialize");
b0dd28ba 452
453 while (a) {
454 a->prepareForUse();
455 a = a->next;
456 }
8000a965 457}
f53969cc 458