Acl.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2022 The Squid Software Foundation and contributors
3 *
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.
7 */
8
9/* DEBUG: section 28 Access Control */
10
11#include "squid.h"
12#include "acl/Acl.h"
13#include "acl/Checklist.h"
14#include "acl/Gadgets.h"
15#include "acl/Options.h"
16#include "anyp/PortCfg.h"
17#include "cache_cf.h"
18#include "ConfigParser.h"
19#include "debug/Stream.h"
20#include "fatal.h"
21#include "globals.h"
22#include "sbuf/List.h"
23#include "sbuf/Stream.h"
24#include "SquidConfig.h"
25
26#include <algorithm>
27#include <map>
28
29const char *AclMatchedName = nullptr;
30
31namespace Acl {
32
35public:
36 bool operator()(TypeName a, TypeName b) const { return strcmp(a, b) < 0; }
37};
38
40typedef std::map<TypeName, Maker, TypeNameCmp> Makers;
41
43static Makers &
45{
46 static Makers Registry;
47 return Registry;
48}
49
51static
52ACL *
53Make(TypeName typeName)
54{
55 const auto pos = TheMakers().find(typeName);
56 if (pos == TheMakers().end()) {
57 debugs(28, DBG_CRITICAL, "FATAL: Invalid ACL type '" << typeName << "'");
59 assert(false); // not reached
60 }
61
62 ACL *result = (pos->second)(pos->first);
63 debugs(28, 4, typeName << '=' << result);
64 assert(result);
65 return result;
66}
67
68} // namespace Acl
69
70void
72{
73 assert(typeName);
74 assert(*typeName);
75 TheMakers().emplace(typeName, maker);
76}
77
78void *
79ACL::operator new (size_t)
80{
81 fatal ("unusable ACL::new");
82 return (void *)1;
83}
84
85void
86ACL::operator delete (void *)
87{
88 fatal ("unusable ACL::delete");
89}
90
91ACL *
92ACL::FindByName(const char *name)
93{
94 ACL *a;
95 debugs(28, 9, "ACL::FindByName '" << name << "'");
96
97 for (a = Config.aclList; a; a = a->next)
98 if (!strcasecmp(a->name, name))
99 return a;
100
101 debugs(28, 9, "ACL::FindByName found no match");
102
103 return nullptr;
104}
105
107 cfgline(nullptr),
108 next(nullptr),
109 registered(false)
110{
111 *name = 0;
112}
113
114bool ACL::valid () const
115{
116 return true;
117}
118
119bool
120ACL::matches(ACLChecklist *checklist) const
121{
122 debugs(28, 5, "checking " << name);
123
124 // XXX: AclMatchedName does not contain a matched ACL name when the acl
125 // does not match. It contains the last (usually leaf) ACL name checked
126 // (or is NULL if no ACLs were checked).
128
129 int result = 0;
130 if (!checklist->hasAle() && requiresAle()) {
131 debugs(28, DBG_IMPORTANT, "WARNING: " << name << " ACL is used in " <<
132 "context without an ALE state. Assuming mismatch.");
133 } else if (!checklist->hasRequest() && requiresRequest()) {
134 debugs(28, DBG_IMPORTANT, "WARNING: " << name << " ACL is used in " <<
135 "context without an HTTP request. Assuming mismatch.");
136 } else if (!checklist->hasReply() && requiresReply()) {
137 debugs(28, DBG_IMPORTANT, "WARNING: " << name << " ACL is used in " <<
138 "context without an HTTP response. Assuming mismatch.");
139 } else {
140 // make sure the ALE has as much data as possible
141 if (requiresAle())
142 checklist->verifyAle();
143
144 // have to cast because old match() API is missing const
145 result = const_cast<ACL*>(this)->match(checklist);
146 }
147
148 const char *extra = checklist->asyncInProgress() ? " async" : "";
149 debugs(28, 3, "checked: " << name << " = " << result << extra);
150 return result == 1; // true for match; false for everything else
151}
152
153void
154ACL::context(const char *aName, const char *aCfgLine)
155{
156 name[0] = '\0';
157 if (aName)
158 xstrncpy(name, aName, ACL_NAME_SZ-1);
160 if (aCfgLine)
161 cfgline = xstrdup(aCfgLine);
162}
163
164void
166{
167 /* we're already using strtok() to grok the line */
168 char *t = nullptr;
169 ACL *A = nullptr;
170 LOCAL_ARRAY(char, aclname, ACL_NAME_SZ);
171 int new_acl = 0;
172
173 /* snarf the ACL name */
174
175 if ((t = ConfigParser::NextToken()) == nullptr) {
176 debugs(28, DBG_CRITICAL, "ERROR: aclParseAclLine: missing ACL name.");
177 parser.destruct();
178 return;
179 }
180
181 if (strlen(t) >= ACL_NAME_SZ) {
182 debugs(28, DBG_CRITICAL, "aclParseAclLine: aclParseAclLine: ACL name '" << t <<
183 "' too long, max " << ACL_NAME_SZ - 1 << " characters supported");
184 parser.destruct();
185 return;
186 }
187
188 xstrncpy(aclname, t, ACL_NAME_SZ);
189 /* snarf the ACL type */
190 const char *theType;
191
192 if ((theType = ConfigParser::NextToken()) == nullptr) {
193 debugs(28, DBG_CRITICAL, "ERROR: aclParseAclLine: missing ACL type.");
194 parser.destruct();
195 return;
196 }
197
198 // Is this ACL going to work?
199 if (strcmp(theType, "myip") == 0) {
201 while (p != nullptr) {
202 // Bug 3239: not reliable when there is interception traffic coming
203 if (p->flags.natIntercept)
204 debugs(28, DBG_CRITICAL, "WARNING: 'myip' ACL is not reliable for interception proxies. Please use 'myportname' instead.");
205 p = p->next;
206 }
207 debugs(28, DBG_IMPORTANT, "WARNING: UPGRADE: ACL 'myip' type has been renamed to 'localip' and matches the IP the client connected to.");
208 theType = "localip";
209 } else if (strcmp(theType, "myport") == 0) {
211 while (p != nullptr) {
212 // Bug 3239: not reliable when there is interception traffic coming
213 // Bug 3239: myport - not reliable (yet) when there is interception traffic coming
214 if (p->flags.natIntercept)
215 debugs(28, DBG_CRITICAL, "WARNING: 'myport' ACL is not reliable for interception proxies. Please use 'myportname' instead.");
216 p = p->next;
217 }
218 theType = "localport";
219 debugs(28, DBG_IMPORTANT, "WARNING: UPGRADE: ACL 'myport' type has been renamed to 'localport' and matches the port the client connected to.");
220 } else if (strcmp(theType, "proto") == 0 && strcmp(aclname, "manager") == 0) {
221 // ACL manager is now a built-in and has a different type.
222 debugs(28, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: UPGRADE: ACL 'manager' is now a built-in ACL. Remove it from your config file.");
223 return; // ignore the line
224 } else if (strcmp(theType, "clientside_mark") == 0) {
225 debugs(28, DBG_IMPORTANT, "WARNING: UPGRADE: ACL 'clientside_mark' type has been renamed to 'client_connection_mark'.");
226 theType = "client_connection_mark";
227 }
228
229 if ((A = FindByName(aclname)) == nullptr) {
230 debugs(28, 3, "aclParseAclLine: Creating ACL '" << aclname << "'");
231 A = Acl::Make(theType);
232 A->context(aclname, config_input_line);
233 new_acl = 1;
234 } else {
235 if (strcmp (A->typeString(),theType) ) {
236 debugs(28, DBG_CRITICAL, "aclParseAclLine: ACL '" << A->name << "' already exists with different type.");
237 parser.destruct();
238 return;
239 }
240
241 debugs(28, 3, "aclParseAclLine: Appending to '" << aclname << "'");
242 new_acl = 0;
243 }
244
245 /*
246 * Here we set AclMatchedName in case we need to use it in a
247 * warning message in aclDomainCompare().
248 */
249 AclMatchedName = A->name; /* ugly */
250
251 A->parseFlags();
252
253 /*split the function here */
254 A->parse();
255
256 /*
257 * Clear AclMatchedName from our temporary hack
258 */
259 AclMatchedName = nullptr; /* ugly */
260
261 if (!new_acl)
262 return;
263
264 if (A->empty()) {
265 debugs(28, DBG_CRITICAL, "WARNING: empty ACL: " << A->cfgline);
266 }
267
268 if (!A->valid()) {
269 fatalf("ERROR: Invalid ACL: %s\n",
270 A->cfgline);
271 }
272
273 // add to the global list for searching explicit ACLs by name
274 assert(head && *head == Config.aclList);
275 A->next = *head;
276 *head = A;
277
278 // register for centralized cleanup
279 aclRegister(A);
280}
281
282bool
284{
285 return false;
286}
287
288void
290{
291 Acl::Options allOptions = options();
292 for (const auto lineOption: lineOptions()) {
293 lineOption->unconfigure(); // forget any previous "acl ..." line effects
294 allOptions.push_back(lineOption);
295 }
296 Acl::ParseFlags(allOptions);
297}
298
301{
302 SBufList result;
303
304 const auto &myOptions = options();
305 // XXX: No lineOptions() call here because we do not remember ACL "line"
306 // boundaries and associated "line" options; we cannot report them.
307
308 // optimization: most ACLs do not have myOptions
309 // this check also works around dump_SBufList() adding ' ' after empty items
310 if (!myOptions.empty()) {
311 SBufStream stream;
312 stream << myOptions;
313 const SBuf optionsImage = stream.buf();
314 if (!optionsImage.isEmpty())
315 result.push_back(optionsImage);
316 }
317 return result;
318}
319
320/* ACL result caching routines */
321
322int
324{
325 /* This is a fatal to ensure that cacheMatchAcl calls are _only_
326 * made for supported acl types */
327 fatal("aclCacheMatchAcl: unknown or unexpected ACL type");
328 return 0; /* NOTREACHED */
329}
330
331/*
332 * we lookup an acl's cached results, and if we cannot find the acl being
333 * checked we check it and cache the result. This function is a template
334 * method to support caching of multiple acl types.
335 * Note that caching of time based acl's is not
336 * wise in long lived caches (i.e. the auth_user proxy match cache)
337 * RBC
338 * TODO: does a dlink_list perform well enough? Kinkie
339 */
340int
342{
343 acl_proxy_auth_match_cache *auth_match;
344 dlink_node *link;
345 link = cache->head;
346
347 while (link) {
348 auth_match = (acl_proxy_auth_match_cache *)link->data;
349
350 if (auth_match->acl_data == this) {
351 debugs(28, 4, "ACL::cacheMatchAcl: cache hit on acl '" << name << "' (" << this << ")");
352 return auth_match->matchrv;
353 }
354
355 link = link->next;
356 }
357
358 auth_match = new acl_proxy_auth_match_cache(matchForCache(checklist), this);
359 dlinkAddTail(auth_match, &auth_match->link, cache);
360 debugs(28, 4, "ACL::cacheMatchAcl: miss for '" << name << "'. Adding result " << auth_match->matchrv);
361 return auth_match->matchrv;
362}
363
364void
366{
367 acl_proxy_auth_match_cache *auth_match;
368 dlink_node *link, *tmplink;
369 link = cache->head;
370
371 debugs(28, 8, "aclCacheMatchFlush called for cache " << cache);
372
373 while (link) {
374 auth_match = (acl_proxy_auth_match_cache *)link->data;
375 tmplink = link;
376 link = link->next;
377 dlinkDelete(tmplink, cache);
378 delete auth_match;
379 }
380}
381
382bool
384{
385 return false;
386}
387
388bool
390{
391 return false;
392}
393
394bool
396{
397 return false;
398}
399
400/*********************/
401/* Destroy functions */
402/*********************/
403
405{
406 debugs(28, 3, "freeing ACL " << name);
408 AclMatchedName = nullptr; // in case it was pointing to our name
409}
410
411void
413{
414 ACL *a = Config.aclList;
415 debugs(53, 3, "ACL::Initialize");
416
417 while (a) {
418 a->prepareForUse();
419 a = a->next;
420 }
421}
422
#define false
Definition: GnuRegex.c:240
AnyP::PortCfgPointer HttpPortList
list of Squid http(s)_port configured
Definition: PortCfg.cc:22
class SquidConfig Config
Definition: SquidConfig.cc:12
#define ACL_NAME_SZ
Definition: forward.h:41
squidaio_request_t * head
Definition: aiops.cc:126
#define assert(EX)
Definition: assert.h:19
char config_input_line[BUFSIZ]
Definition: cache_cf.cc:273
void self_destruct(void)
Definition: cache_cf.cc:276
virtual bool hasReply() const =0
bool asyncInProgress() const
async call has been started and has not finished (or failed) yet
Definition: Checklist.h:151
virtual void verifyAle() const =0
warns if there are uninitialized ALE components and fills them
virtual bool hasAle() const =0
virtual bool hasRequest() const =0
Definition: Acl.h:40
ACL()
Definition: Acl.cc:106
virtual bool valid() const
Definition: Acl.cc:114
virtual bool requiresAle() const
whether our (i.e. shallow) match() requires checklist to have a AccessLogEntry
Definition: Acl.cc:383
virtual bool requiresRequest() const
whether our (i.e. shallow) match() requires checklist to have a request
Definition: Acl.cc:395
int cacheMatchAcl(dlink_list *cache, ACLChecklist *)
Definition: Acl.cc:341
char * cfgline
Definition: Acl.h:82
virtual int match(ACLChecklist *checklist)=0
Matches the actual data in checklist against this ACL.
void context(const char *name, const char *configuration)
sets user-specified ACL name and squid.conf context
Definition: Acl.cc:154
virtual int matchForCache(ACLChecklist *checklist)
Definition: Acl.cc:323
virtual bool requiresReply() const
whether our (i.e. shallow) match() requires checklist to have a reply
Definition: Acl.cc:389
static ACL * FindByName(const char *name)
Definition: Acl.cc:92
bool matches(ACLChecklist *checklist) const
Definition: Acl.cc:120
char name[ACL_NAME_SZ]
Definition: Acl.h:81
ACL * next
Definition: Acl.h:83
static void Initialize()
Definition: Acl.cc:412
virtual const Acl::Options & lineOptions()
Definition: Acl.h:103
SBufList dumpOptions()
Definition: Acl.cc:300
virtual void prepareForUse()
Definition: Acl.h:77
void parseFlags()
configures ACL options, throwing on configuration errors
Definition: Acl.cc:289
virtual ~ACL()
Definition: Acl.cc:404
virtual bool isProxyAuth() const
Definition: Acl.cc:283
virtual const Acl::Options & options()
Definition: Acl.h:99
static void ParseAclLine(ConfigParser &parser, ACL **head)
Definition: Acl.cc:165
ACL type name comparison functor.
Definition: Acl.cc:34
bool operator()(TypeName a, TypeName b) const
Definition: Acl.cc:36
static char * NextToken()
void destruct()
Definition: ConfigParser.cc:37
SBuf buf()
bytes written so far
Definition: Stream.h:41
Definition: SBuf.h:94
bool isEmpty() const
Definition: SBuf.h:431
class ACL * aclList
Definition: SquidConfig.h:354
#define DBG_PARSE_NOTE(x)
Definition: Stream.h:45
#define DBG_IMPORTANT
Definition: Stream.h:41
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:196
#define DBG_CRITICAL
Definition: Stream.h:40
void fatal(const char *message)
Definition: fatal.cc:28
void fatalf(const char *fmt,...)
Definition: fatal.cc:68
void aclCacheMatchFlush(dlink_list *cache)
Definition: Acl.cc:365
void aclRegister(ACL *acl)
Definition: Gadgets.cc:224
const char * AclMatchedName
Definition: Acl.cc:29
static uint32 A
Definition: md4.c:43
Definition: Acl.cc:31
void RegisterMaker(TypeName typeName, Maker maker)
use the given ACL Maker for all ACLs of the named type
Definition: Acl.cc:71
const char * TypeName
the ACL type name known to admins
Definition: Acl.h:27
static Makers & TheMakers()
registered ACL Makers
Definition: Acl.cc:44
static ACL * Make(TypeName typeName)
creates an ACL object of the named (and already registered) ACL child type
Definition: Acl.cc:53
ACL *(* Maker)(TypeName typeName)
a "factory" function for making ACL objects (of some ACL child type)
Definition: Acl.h:29
void ParseFlags(const Options &options)
Definition: Options.cc:227
std::map< TypeName, Maker, TypeNameCmp > Makers
ACL makers indexed by ACL type name.
Definition: Acl.cc:40
std::vector< const Option * > Options
Definition: Options.h:214
#define xstrdup
std::list< SBuf > SBufList
Definition: forward.h:23
#define LOCAL_ARRAY(type, name, size)
Definition: squid.h:68
int const char size_t
Definition: stub_liblog.cc:86
#define safe_free(x)
Definition: xalloc.h:73
char * xstrncpy(char *dst, const char *src, size_t n)
Definition: xstring.cc:37

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors