]>
Commit | Line | Data |
---|---|---|
8213067d | 1 | /* |
ef57eb7b | 2 | * Copyright (C) 1996-2016 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 | ||
76ee67ac CT |
27 | #define abortFlags(CONTENT) \ |
28 | do { \ | |
29 | debugs(28, 0, CONTENT); \ | |
30 | self_destruct(); \ | |
31 | } while (0) | |
32 | ||
33810b1d CT |
33 | const ACLFlag ACLFlags::NoFlags[1] = {ACL_F_END}; |
34 | ||
b0dd28ba | 35 | const char *AclMatchedName = NULL; |
36 | ||
76ee67ac CT |
37 | ACLFlags::FlagsTokenizer::FlagsTokenizer(): tokPos(NULL) { } |
38 | ||
39 | ACLFlag | |
40 | ACLFlags::FlagsTokenizer::nextFlag() | |
41 | { | |
42 | if (needNextToken()) { | |
43 | if (!nextToken()) | |
44 | return 0; | |
45 | } else | |
46 | ++tokPos; | |
47 | return *tokPos; | |
48 | } | |
49 | ||
50 | bool | |
51 | ACLFlags::FlagsTokenizer::hasParameter() const | |
52 | { | |
53 | return tokPos && tokPos[0] && tokPos[1] == '=' && tokPos[2]; | |
54 | } | |
55 | ||
56 | SBuf | |
57 | ACLFlags::FlagsTokenizer::getParameter() const | |
58 | { | |
59 | return hasParameter() ? SBuf(&tokPos[2]) : SBuf(); | |
60 | } | |
61 | ||
62 | bool | |
63 | ACLFlags::FlagsTokenizer::needNextToken() const | |
64 | { | |
65 | return !tokPos || !tokPos[0] || !tokPos[1] || tokPos[1] == '='; | |
66 | } | |
67 | ||
68 | bool | |
69 | ACLFlags::FlagsTokenizer::nextToken() | |
70 | { | |
71 | char *t = ConfigParser::PeekAtToken(); | |
72 | if (t == NULL || t[0] != '-' || !t[1]) | |
73 | return false; | |
74 | (void)ConfigParser::NextQuotedToken(); | |
75 | if (strcmp(t, "--") == 0) | |
76 | return false; | |
77 | tokPos = t + 1; | |
78 | return true; | |
79 | } | |
80 | ||
81 | ACLFlags::~ACLFlags() | |
82 | { | |
83 | delete delimiters_; | |
84 | } | |
85 | ||
86 | ACLFlags::Status | |
87 | ACLFlags::flagStatus(const ACLFlag f) const | |
33810b1d CT |
88 | { |
89 | if (f == ACL_F_REGEX_CASE) | |
76ee67ac CT |
90 | return noParameter; |
91 | if (f == ACL_F_SUBSTRING) | |
92 | return parameterOptional; | |
93 | if (supported_.find(f) != std::string::npos) | |
94 | return noParameter; | |
95 | return notSupported; | |
96 | } | |
97 | ||
98 | bool | |
99 | ACLFlags::parameterSupported(const ACLFlag f, const SBuf &val) const | |
100 | { | |
101 | if (f == ACL_F_SUBSTRING) | |
102 | return val.findFirstOf(CharacterSet::ALPHA + CharacterSet::DIGIT) == SBuf::npos; | |
103 | return true; | |
104 | } | |
105 | ||
106 | void | |
107 | ACLFlags::makeSet(const ACLFlag f, const SBuf ¶m) | |
108 | { | |
109 | flags_ |= flagToInt(f); | |
110 | if (!param.isEmpty()) | |
111 | flagParameters_[f].append(param); | |
112 | } | |
113 | ||
114 | void | |
115 | ACLFlags::makeUnSet(const ACLFlag f) | |
116 | { | |
5269fa82 SM |
117 | flags_ &= ~flagToInt(f); |
118 | flagParameters_[f].clear(); | |
33810b1d CT |
119 | } |
120 | ||
aec45181 | 121 | void |
788542bd | 122 | ACLFlags::parseFlags() |
33810b1d | 123 | { |
76ee67ac CT |
124 | FlagsTokenizer tokenizer; |
125 | ACLFlag flag('\0'); | |
126 | while ((flag = tokenizer.nextFlag())) { | |
127 | switch (flagStatus(flag)) | |
128 | { | |
5269fa82 SM |
129 | case notSupported: |
130 | abortFlags("Flag '" << flag << "' not supported"); | |
131 | break; | |
132 | case noParameter: | |
133 | makeSet(flag); | |
134 | break; | |
135 | case parameterRequired: | |
136 | if (!tokenizer.hasParameter()) { | |
137 | abortFlags("Flag '" << flag << "' must have a parameter"); | |
76ee67ac | 138 | break; |
5269fa82 SM |
139 | } |
140 | case parameterOptional: | |
141 | SBuf param; | |
142 | if (tokenizer.hasParameter()) { | |
143 | param = tokenizer.getParameter(); | |
144 | if (!parameterSupported(flag, param)) | |
145 | abortFlags("Parameter '" << param << "' for flag '" << flag << "' not supported"); | |
146 | } | |
147 | makeSet(flag, param); | |
148 | break; | |
33810b1d CT |
149 | } |
150 | } | |
151 | ||
152 | /*Regex code needs to parse -i file*/ | |
702240e4 | 153 | if ( isSet(ACL_F_REGEX_CASE)) { |
2eceb328 | 154 | ConfigParser::TokenPutBack("-i"); |
702240e4 FC |
155 | makeUnSet('i'); |
156 | } | |
33810b1d CT |
157 | } |
158 | ||
76ee67ac CT |
159 | SBuf |
160 | ACLFlags::parameter(const ACLFlag f) const | |
161 | { | |
162 | assert(static_cast<uint32_t>(f - 'A') < FlagIndexMax); | |
163 | auto p = flagParameters_.find(f); | |
164 | return p == flagParameters_.end() ? SBuf() : p->second; | |
165 | } | |
166 | ||
167 | const CharacterSet * | |
168 | ACLFlags::delimiters() | |
169 | { | |
170 | if (isSet(ACL_F_SUBSTRING) && !delimiters_) { | |
171 | static const SBuf defaultParameter(","); | |
172 | SBuf rawParameter = parameter(ACL_F_SUBSTRING); | |
173 | if (rawParameter.isEmpty()) | |
174 | rawParameter = defaultParameter; | |
175 | delimiters_ = new CharacterSet("ACLFlags::delimiters", rawParameter.c_str()); | |
176 | } | |
177 | return delimiters_; | |
178 | } | |
179 | ||
33810b1d CT |
180 | const char * |
181 | ACLFlags::flagsStr() const | |
182 | { | |
183 | static char buf[64]; | |
184 | if (flags_ == 0) | |
185 | return ""; | |
186 | ||
187 | char *s = buf; | |
188 | *s++ = '-'; | |
189 | for (ACLFlag f = 'A'; f <= 'z'; f++) { | |
190 | // ACL_F_REGEX_CASE (-i) flag handled by ACLRegexData class, ignore | |
191 | if (isSet(f) && f != ACL_F_REGEX_CASE) | |
192 | *s++ = f; | |
193 | } | |
194 | *s = '\0'; | |
195 | return buf; | |
196 | } | |
197 | ||
8000a965 | 198 | void * |
ced8def3 | 199 | ACL::operator new (size_t) |
8000a965 | 200 | { |
b0dd28ba | 201 | fatal ("unusable ACL::new"); |
202 | return (void *)1; | |
8000a965 | 203 | } |
204 | ||
205 | void | |
ced8def3 | 206 | ACL::operator delete (void *) |
8000a965 | 207 | { |
b0dd28ba | 208 | fatal ("unusable ACL::delete"); |
56b63fa1 | 209 | } |
210 | ||
97427e90 | 211 | ACL * |
225b7b10 | 212 | ACL::FindByName(const char *name) |
7dd57fa2 | 213 | { |
97427e90 | 214 | ACL *a; |
bf8fe701 | 215 | debugs(28, 9, "ACL::FindByName '" << name << "'"); |
62e76326 | 216 | |
9bea1d5b | 217 | for (a = Config.aclList; a; a = a->next) |
62e76326 | 218 | if (!strcasecmp(a->name, name)) |
219 | return a; | |
220 | ||
bf8fe701 | 221 | debugs(28, 9, "ACL::FindByName found no match"); |
6bf4f823 | 222 | |
9bea1d5b | 223 | return NULL; |
7dd57fa2 | 224 | } |
225 | ||
8000a965 | 226 | ACL * |
227 | ACL::Factory (char const *type) | |
228 | { | |
229 | ACL *result = Prototype::Factory (type); | |
62e76326 | 230 | |
b0dd28ba | 231 | if (!result) |
62e76326 | 232 | fatal ("Unknown acl type in ACL::Factory"); |
62e76326 | 233 | |
8000a965 | 234 | return result; |
235 | } | |
236 | ||
478a0611 | 237 | ACL::ACL() : |
d59e4742 FC |
238 | cfgline(nullptr), |
239 | next(nullptr), | |
240 | registered(false) | |
241 | { | |
242 | *name = 0; | |
243 | } | |
244 | ||
245 | ACL::ACL(const ACLFlag flgs[]) : | |
f53969cc SM |
246 | cfgline(NULL), |
247 | next(NULL), | |
d59e4742 | 248 | flags(flgs), |
f53969cc | 249 | registered(false) |
478a0611 AJ |
250 | { |
251 | *name = 0; | |
252 | } | |
8000a965 | 253 | |
4b0f5de8 | 254 | bool ACL::valid () const |
255 | { | |
256 | return true; | |
257 | } | |
258 | ||
6f58d7d7 AR |
259 | bool |
260 | ACL::matches(ACLChecklist *checklist) const | |
261 | { | |
262 | PROF_start(ACL_matches); | |
263 | debugs(28, 5, "checking " << name); | |
264 | ||
265 | // XXX: AclMatchedName does not contain a matched ACL name when the acl | |
266 | // does not match. It contains the last (usually leaf) ACL name checked | |
267 | // (or is NULL if no ACLs were checked). | |
268 | AclMatchedName = name; | |
269 | ||
270 | int result = 0; | |
4ff6370b | 271 | if (!checklist->hasAle() && requiresAle()) { |
4e56d7f6 | 272 | debugs(28, DBG_IMPORTANT, "WARNING: " << name << " ACL is used in " << |
acfe8e09 | 273 | "context without an ALE state. Assuming mismatch."); |
4e56d7f6 | 274 | } else if (!checklist->hasRequest() && requiresRequest()) { |
6f58d7d7 AR |
275 | debugs(28, DBG_IMPORTANT, "WARNING: " << name << " ACL is used in " << |
276 | "context without an HTTP request. Assuming mismatch."); | |
277 | } else if (!checklist->hasReply() && requiresReply()) { | |
278 | debugs(28, DBG_IMPORTANT, "WARNING: " << name << " ACL is used in " << | |
279 | "context without an HTTP response. Assuming mismatch."); | |
280 | } else { | |
fbbea662 AJ |
281 | // make sure the ALE has as much data as possible |
282 | if (requiresAle()) | |
283 | checklist->syncAle(); | |
284 | ||
6f58d7d7 AR |
285 | // have to cast because old match() API is missing const |
286 | result = const_cast<ACL*>(this)->match(checklist); | |
287 | } | |
288 | ||
289 | const char *extra = checklist->asyncInProgress() ? " async" : ""; | |
290 | debugs(28, 3, "checked: " << name << " = " << result << extra); | |
291 | PROF_stop(ACL_matches); | |
292 | return result == 1; // true for match; false for everything else | |
293 | } | |
294 | ||
295 | void | |
296 | ACL::context(const char *aName, const char *aCfgLine) | |
297 | { | |
298 | name[0] = '\0'; | |
299 | if (aName) | |
300 | xstrncpy(name, aName, ACL_NAME_SZ-1); | |
301 | safe_free(cfgline); | |
302 | if (aCfgLine) | |
303 | cfgline = xstrdup(aCfgLine); | |
304 | } | |
305 | ||
8203a132 | 306 | void |
a9f20260 | 307 | ACL::ParseAclLine(ConfigParser &parser, ACL ** head) |
9bea1d5b | 308 | { |
309 | /* we're already using strtok() to grok the line */ | |
310 | char *t = NULL; | |
97427e90 | 311 | ACL *A = NULL; |
9bea1d5b | 312 | LOCAL_ARRAY(char, aclname, ACL_NAME_SZ); |
9bea1d5b | 313 | int new_acl = 0; |
314 | ||
315 | /* snarf the ACL name */ | |
62e76326 | 316 | |
2eceb328 | 317 | if ((t = ConfigParser::NextToken()) == NULL) { |
fa84c01d | 318 | debugs(28, DBG_CRITICAL, "aclParseAclLine: missing ACL name."); |
a9f20260 | 319 | parser.destruct(); |
62e76326 | 320 | return; |
9bea1d5b | 321 | } |
62e76326 | 322 | |
401f503a | 323 | if (strlen(t) >= ACL_NAME_SZ) { |
fa84c01d | 324 | debugs(28, DBG_CRITICAL, "aclParseAclLine: aclParseAclLine: ACL name '" << t << |
bf8fe701 | 325 | "' too long, max " << ACL_NAME_SZ - 1 << " characters supported"); |
401f503a | 326 | parser.destruct(); |
327 | return; | |
328 | } | |
329 | ||
9bea1d5b | 330 | xstrncpy(aclname, t, ACL_NAME_SZ); |
331 | /* snarf the ACL type */ | |
38dedeed | 332 | const char *theType; |
62e76326 | 333 | |
2eceb328 | 334 | if ((theType = ConfigParser::NextToken()) == NULL) { |
fa84c01d | 335 | debugs(28, DBG_CRITICAL, "aclParseAclLine: missing ACL type."); |
a9f20260 | 336 | parser.destruct(); |
62e76326 | 337 | return; |
9bea1d5b | 338 | } |
62e76326 | 339 | |
8306968f | 340 | // Is this ACL going to work? |
18c41901 | 341 | if (strcmp(theType, "myip") == 0) { |
fa720bfb AJ |
342 | AnyP::PortCfgPointer p = HttpPortList; |
343 | while (p != NULL) { | |
8306968f | 344 | // Bug 3239: not reliable when there is interception traffic coming |
6a25a046 | 345 | if (p->flags.natIntercept) |
8306968f AJ |
346 | debugs(28, DBG_CRITICAL, "WARNING: 'myip' ACL is not reliable for interception proxies. Please use 'myportname' instead."); |
347 | p = p->next; | |
348 | } | |
38dedeed | 349 | debugs(28, DBG_IMPORTANT, "UPGRADE: ACL 'myip' type is has been renamed to 'localip' and matches the IP the client connected to."); |
1e40905d | 350 | theType = "localip"; |
18c41901 | 351 | } else if (strcmp(theType, "myport") == 0) { |
fa720bfb AJ |
352 | AnyP::PortCfgPointer p = HttpPortList; |
353 | while (p != NULL) { | |
8306968f AJ |
354 | // Bug 3239: not reliable when there is interception traffic coming |
355 | // Bug 3239: myport - not reliable (yet) when there is interception traffic coming | |
6a25a046 | 356 | if (p->flags.natIntercept) |
8306968f AJ |
357 | debugs(28, DBG_CRITICAL, "WARNING: 'myport' ACL is not reliable for interception proxies. Please use 'myportname' instead."); |
358 | p = p->next; | |
359 | } | |
1e40905d | 360 | theType = "localport"; |
38dedeed | 361 | debugs(28, DBG_IMPORTANT, "UPGRADE: ACL 'myport' type is has been renamed to 'localport' and matches the port the client connected to."); |
49549cd1 AJ |
362 | } else if (strcmp(theType, "proto") == 0 && strcmp(aclname, "manager") == 0) { |
363 | // ACL manager is now a built-in and has a different type. | |
364 | debugs(28, DBG_PARSE_NOTE(DBG_IMPORTANT), "UPGRADE: ACL 'manager' is now a built-in ACL. Remove it from your config file."); | |
365 | return; // ignore the line | |
1e40905d AJ |
366 | } |
367 | ||
368 | if (!Prototype::Registered(theType)) { | |
369 | debugs(28, DBG_CRITICAL, "FATAL: Invalid ACL type '" << theType << "'"); | |
370 | // XXX: make this an ERROR and skip the ACL creation. We *may* die later when its use is attempted. Or may not. | |
371 | parser.destruct(); | |
372 | return; | |
8306968f AJ |
373 | } |
374 | ||
225b7b10 | 375 | if ((A = FindByName(aclname)) == NULL) { |
bf8fe701 | 376 | debugs(28, 3, "aclParseAclLine: Creating ACL '" << aclname << "'"); |
b0dd28ba | 377 | A = ACL::Factory(theType); |
6f58d7d7 | 378 | A->context(aclname, config_input_line); |
62e76326 | 379 | new_acl = 1; |
9bea1d5b | 380 | } else { |
b0dd28ba | 381 | if (strcmp (A->typeString(),theType) ) { |
fa84c01d | 382 | debugs(28, DBG_CRITICAL, "aclParseAclLine: ACL '" << A->name << "' already exists with different type."); |
a9f20260 | 383 | parser.destruct(); |
62e76326 | 384 | return; |
385 | } | |
386 | ||
bf8fe701 | 387 | debugs(28, 3, "aclParseAclLine: Appending to '" << aclname << "'"); |
62e76326 | 388 | new_acl = 0; |
9bea1d5b | 389 | } |
62e76326 | 390 | |
9bea1d5b | 391 | /* |
392 | * Here we set AclMatchedName in case we need to use it in a | |
393 | * warning message in aclDomainCompare(). | |
394 | */ | |
f53969cc | 395 | AclMatchedName = A->name; /* ugly */ |
8000a965 | 396 | |
788542bd | 397 | A->flags.parseFlags(); |
33810b1d | 398 | |
8000a965 | 399 | /*split the function here */ |
400 | A->parse(); | |
62e76326 | 401 | |
8000a965 | 402 | /* |
403 | * Clear AclMatchedName from our temporary hack | |
404 | */ | |
f53969cc | 405 | AclMatchedName = NULL; /* ugly */ |
62e76326 | 406 | |
8000a965 | 407 | if (!new_acl) |
62e76326 | 408 | return; |
409 | ||
4b0f5de8 | 410 | if (A->empty()) { |
fa84c01d | 411 | debugs(28, DBG_CRITICAL, "Warning: empty ACL: " << A->cfgline); |
4b0f5de8 | 412 | } |
413 | ||
414 | if (!A->valid()) { | |
415 | fatalf("ERROR: Invalid ACL: %s\n", | |
416 | A->cfgline); | |
8000a965 | 417 | } |
62e76326 | 418 | |
ed898bdf | 419 | // add to the global list for searching explicit ACLs by name |
6f58d7d7 | 420 | assert(head && *head == Config.aclList); |
a57c224d | 421 | A->next = *head; |
8000a965 | 422 | *head = A; |
ed898bdf AR |
423 | |
424 | // register for centralized cleanup | |
425 | aclRegister(A); | |
8000a965 | 426 | } |
427 | ||
8000a965 | 428 | bool |
429 | ACL::isProxyAuth() const | |
430 | { | |
225b7b10 | 431 | return false; |
8000a965 | 432 | } |
1cfdbcf0 | 433 | |
94439e4e | 434 | /* ACL result caching routines */ |
435 | ||
225b7b10 | 436 | int |
ced8def3 | 437 | ACL::matchForCache(ACLChecklist *) |
225b7b10 | 438 | { |
439 | /* This is a fatal to ensure that cacheMatchAcl calls are _only_ | |
440 | * made for supported acl types */ | |
441 | fatal("aclCacheMatchAcl: unknown or unexpected ACL type"); | |
f53969cc | 442 | return 0; /* NOTREACHED */ |
225b7b10 | 443 | } |
444 | ||
94439e4e | 445 | /* |
26ac0430 | 446 | * we lookup an acl's cached results, and if we cannot find the acl being |
225b7b10 | 447 | * checked we check it and cache the result. This function is a template |
448 | * method to support caching of multiple acl types. | |
449 | * Note that caching of time based acl's is not | |
6bf4f823 | 450 | * wise in long lived caches (i.e. the auth_user proxy match cache) |
94439e4e | 451 | * RBC |
6bf4f823 | 452 | * TODO: does a dlink_list perform well enough? Kinkie |
94439e4e | 453 | */ |
225b7b10 | 454 | int |
455 | ACL::cacheMatchAcl(dlink_list * cache, ACLChecklist *checklist) | |
9bea1d5b | 456 | { |
9bea1d5b | 457 | acl_proxy_auth_match_cache *auth_match; |
458 | dlink_node *link; | |
459 | link = cache->head; | |
62e76326 | 460 | |
9bea1d5b | 461 | while (link) { |
62e76326 | 462 | auth_match = (acl_proxy_auth_match_cache *)link->data; |
463 | ||
464 | if (auth_match->acl_data == this) { | |
bf8fe701 | 465 | debugs(28, 4, "ACL::cacheMatchAcl: cache hit on acl '" << name << "' (" << this << ")"); |
62e76326 | 466 | return auth_match->matchrv; |
467 | } | |
468 | ||
469 | link = link->next; | |
9bea1d5b | 470 | } |
62e76326 | 471 | |
d59e4742 | 472 | auth_match = new acl_proxy_auth_match_cache(matchForCache(checklist), this); |
9bea1d5b | 473 | dlinkAddTail(auth_match, &auth_match->link, cache); |
bf8fe701 | 474 | debugs(28, 4, "ACL::cacheMatchAcl: miss for '" << name << "'. Adding result " << auth_match->matchrv); |
225b7b10 | 475 | return auth_match->matchrv; |
94439e4e | 476 | } |
477 | ||
478 | void | |
9bea1d5b | 479 | aclCacheMatchFlush(dlink_list * cache) |
94439e4e | 480 | { |
9bea1d5b | 481 | acl_proxy_auth_match_cache *auth_match; |
482 | dlink_node *link, *tmplink; | |
483 | link = cache->head; | |
62e76326 | 484 | |
bf8fe701 | 485 | debugs(28, 8, "aclCacheMatchFlush called for cache " << cache); |
6bf4f823 | 486 | |
9bea1d5b | 487 | while (link) { |
62e76326 | 488 | auth_match = (acl_proxy_auth_match_cache *)link->data; |
489 | tmplink = link; | |
490 | link = link->next; | |
491 | dlinkDelete(tmplink, cache); | |
11a9f1b1 | 492 | delete auth_match; |
1f38f50a | 493 | } |
c68e9c6b | 494 | } |
73e67ee0 | 495 | |
4e56d7f6 | 496 | bool |
4ff6370b | 497 | ACL::requiresAle() const |
4e56d7f6 AJ |
498 | { |
499 | return false; | |
500 | } | |
501 | ||
b0dd28ba | 502 | bool |
503 | ACL::requiresReply() const | |
504 | { | |
505 | return false; | |
506 | } | |
60d096f4 | 507 | |
b0dd28ba | 508 | bool |
509 | ACL::requiresRequest() const | |
9bea1d5b | 510 | { |
b0dd28ba | 511 | return false; |
512 | } | |
62e76326 | 513 | |
f32789f4 | 514 | /*********************/ |
515 | /* Destroy functions */ | |
516 | /*********************/ | |
517 | ||
8000a965 | 518 | ACL::~ACL() |
519 | { | |
e20d485b | 520 | debugs(28, 3, "freeing ACL " << name); |
62e76326 | 521 | safe_free(cfgline); |
6f58d7d7 | 522 | AclMatchedName = NULL; // in case it was pointing to our name |
92a6f4b1 | 523 | } |
524 | ||
8000a965 | 525 | ACL::Prototype::Prototype() : prototype (NULL), typeString (NULL) {} |
526 | ||
62e76326 | 527 | ACL::Prototype::Prototype (ACL const *aPrototype, char const *aType) : prototype (aPrototype), typeString (aType) |
8000a965 | 528 | { |
529 | registerMe (); | |
530 | } | |
531 | ||
81481ec0 | 532 | std::vector<ACL::Prototype const *> * ACL::Prototype::Registry; |
8000a965 | 533 | void *ACL::Prototype::Initialized; |
534 | ||
535 | bool | |
62e76326 | 536 | ACL::Prototype::Registered(char const *aType) |
8000a965 | 537 | { |
bf8fe701 | 538 | debugs(28, 7, "ACL::Prototype::Registered: invoked for type " << aType); |
6bf4f823 | 539 | |
8000a965 | 540 | for (iterator i = Registry->begin(); i != Registry->end(); ++i) |
6bf4f823 | 541 | if (!strcmp (aType, (*i)->typeString)) { |
bf8fe701 | 542 | debugs(28, 7, "ACL::Prototype::Registered: yes"); |
62e76326 | 543 | return true; |
6bf4f823 | 544 | } |
62e76326 | 545 | |
bf8fe701 | 546 | debugs(28, 7, "ACL::Prototype::Registered: no"); |
8000a965 | 547 | return false; |
548 | } | |
549 | ||
550 | void | |
551 | ACL::Prototype::registerMe () | |
552 | { | |
553 | if (!Registry || (Initialized != ((char *)Registry - 5)) ) { | |
62e76326 | 554 | /* TODO: extract this */ |
555 | /* Not initialised */ | |
81481ec0 | 556 | Registry = new std::vector<ACL::Prototype const *>; |
62e76326 | 557 | Initialized = (char *)Registry - 5; |
8000a965 | 558 | } |
62e76326 | 559 | |
8000a965 | 560 | if (Registered (typeString)) |
62e76326 | 561 | fatalf ("Attempt to register %s twice", typeString); |
562 | ||
8000a965 | 563 | Registry->push_back (this); |
564 | } | |
565 | ||
62e76326 | 566 | ACL::Prototype::~Prototype() |
8000a965 | 567 | { |
67b7fa0d | 568 | // TODO: unregister me |
8000a965 | 569 | } |
570 | ||
571 | ACL * | |
572 | ACL::Prototype::Factory (char const *typeToClone) | |
573 | { | |
bf8fe701 | 574 | debugs(28, 4, "ACL::Prototype::Factory: cloning an object for type '" << typeToClone << "'"); |
6bf4f823 | 575 | |
8000a965 | 576 | for (iterator i = Registry->begin(); i != Registry->end(); ++i) |
33810b1d CT |
577 | if (!strcmp (typeToClone, (*i)->typeString)) { |
578 | ACL *A = (*i)->prototype->clone(); | |
579 | A->flags = (*i)->prototype->flags; | |
580 | return A; | |
581 | } | |
62e76326 | 582 | |
bf8fe701 | 583 | debugs(28, 4, "ACL::Prototype::Factory: cloning failed, no type '" << typeToClone << "' available"); |
6bf4f823 | 584 | |
8000a965 | 585 | return NULL; |
586 | } | |
587 | ||
b0dd28ba | 588 | void |
589 | ACL::Initialize() | |
8000a965 | 590 | { |
97427e90 | 591 | ACL *a = Config.aclList; |
bf8fe701 | 592 | debugs(53, 3, "ACL::Initialize"); |
b0dd28ba | 593 | |
594 | while (a) { | |
595 | a->prepareForUse(); | |
596 | a = a->next; | |
597 | } | |
8000a965 | 598 | } |
f53969cc | 599 |