Acl.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2021 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.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 
29 const char *AclMatchedName = NULL;
30 
31 namespace Acl {
32 
34 class TypeNameCmp {
35 public:
36  bool operator()(TypeName a, TypeName b) const { return strcmp(a, b) < 0; }
37 };
38 
40 typedef std::map<TypeName, Maker, TypeNameCmp> Makers;
41 
43 static Makers &
45 {
46  static Makers Registry;
47  return Registry;
48 }
49 
51 static
52 ACL *
53 Make(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 << "'");
58  self_destruct();
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 
70 void
72 {
73  assert(typeName);
74  assert(*typeName);
75  TheMakers().emplace(typeName, maker);
76 }
77 
78 void *
79 ACL::operator new (size_t)
80 {
81  fatal ("unusable ACL::new");
82  return (void *)1;
83 }
84 
85 void
86 ACL::operator delete (void *)
87 {
88  fatal ("unusable ACL::delete");
89 }
90 
91 ACL *
92 ACL::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 NULL;
104 }
105 
107  cfgline(nullptr),
108  next(nullptr),
109  registered(false)
110 {
111  *name = 0;
112 }
113 
114 bool ACL::valid () const
115 {
116  return true;
117 }
118 
119 bool
120 ACL::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 
153 void
154 ACL::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 
164 void
166 {
167  /* we're already using strtok() to grok the line */
168  char *t = NULL;
169  ACL *A = NULL;
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()) == NULL) {
176  debugs(28, DBG_CRITICAL, "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()) == NULL) {
193  debugs(28, DBG_CRITICAL, "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 != NULL) {
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, "UPGRADE: ACL 'myip' type is 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 != NULL) {
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, "UPGRADE: ACL 'myport' type is 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), "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, "UPGRADE: ACL 'clientside_mark' type has been renamed to 'client_connection_mark'.");
226  theType = "client_connection_mark";
227  }
228 
229  if ((A = FindByName(aclname)) == NULL) {
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 = NULL; /* 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 
282 bool
284 {
285  return false;
286 }
287 
288 void
290 {
291  // ACL kids that carry ACLData which supports parameter flags override this
293 }
294 
295 SBufList
297 {
298  SBufList result;
299  const auto &myOptions = options();
300  // optimization: most ACLs do not have myOptions
301  // this check also works around dump_SBufList() adding ' ' after empty items
302  if (!myOptions.empty()) {
303  SBufStream stream;
304  stream << myOptions;
305  const SBuf optionsImage = stream.buf();
306  if (!optionsImage.isEmpty())
307  result.push_back(optionsImage);
308  }
309  return result;
310 }
311 
312 /* ACL result caching routines */
313 
314 int
316 {
317  /* This is a fatal to ensure that cacheMatchAcl calls are _only_
318  * made for supported acl types */
319  fatal("aclCacheMatchAcl: unknown or unexpected ACL type");
320  return 0; /* NOTREACHED */
321 }
322 
323 /*
324  * we lookup an acl's cached results, and if we cannot find the acl being
325  * checked we check it and cache the result. This function is a template
326  * method to support caching of multiple acl types.
327  * Note that caching of time based acl's is not
328  * wise in long lived caches (i.e. the auth_user proxy match cache)
329  * RBC
330  * TODO: does a dlink_list perform well enough? Kinkie
331  */
332 int
334 {
335  acl_proxy_auth_match_cache *auth_match;
336  dlink_node *link;
337  link = cache->head;
338 
339  while (link) {
340  auth_match = (acl_proxy_auth_match_cache *)link->data;
341 
342  if (auth_match->acl_data == this) {
343  debugs(28, 4, "ACL::cacheMatchAcl: cache hit on acl '" << name << "' (" << this << ")");
344  return auth_match->matchrv;
345  }
346 
347  link = link->next;
348  }
349 
350  auth_match = new acl_proxy_auth_match_cache(matchForCache(checklist), this);
351  dlinkAddTail(auth_match, &auth_match->link, cache);
352  debugs(28, 4, "ACL::cacheMatchAcl: miss for '" << name << "'. Adding result " << auth_match->matchrv);
353  return auth_match->matchrv;
354 }
355 
356 void
358 {
359  acl_proxy_auth_match_cache *auth_match;
360  dlink_node *link, *tmplink;
361  link = cache->head;
362 
363  debugs(28, 8, "aclCacheMatchFlush called for cache " << cache);
364 
365  while (link) {
366  auth_match = (acl_proxy_auth_match_cache *)link->data;
367  tmplink = link;
368  link = link->next;
369  dlinkDelete(tmplink, cache);
370  delete auth_match;
371  }
372 }
373 
374 bool
376 {
377  return false;
378 }
379 
380 bool
382 {
383  return false;
384 }
385 
386 bool
388 {
389  return false;
390 }
391 
392 /*********************/
393 /* Destroy functions */
394 /*********************/
395 
397 {
398  debugs(28, 3, "freeing ACL " << name);
400  AclMatchedName = NULL; // in case it was pointing to our name
401 }
402 
403 void
405 {
406  ACL *a = Config.aclList;
407  debugs(53, 3, "ACL::Initialize");
408 
409  while (a) {
410  a->prepareForUse();
411  a = a->next;
412  }
413 }
414 
void fatal(const char *message)
Definition: fatal.cc:28
virtual int matchForCache(ACLChecklist *checklist)
Definition: Acl.cc:315
void ParseFlags(const Options &options, const ParameterFlags &flags)
Definition: Options.cc:240
std::map< TypeName, Maker, TypeNameCmp > Makers
ACL makers indexed by ACL type name.
Definition: Acl.cc:40
const char * TypeName
the ACL type name known to admins
Definition: Acl.h:27
virtual void verifyAle() const =0
warns if there are uninitialized ALE components and fills them
#define LOCAL_ARRAY(type, name, size)
Definition: squid.h:75
AnyP::PortCfgPointer HttpPortList
list of Squid http(s)_port configured
Definition: PortCfg.cc:21
void RegisterMaker(TypeName typeName, Maker maker)
use the given ACL Maker for all ACLs of the named type
Definition: Acl.cc:71
static Makers & TheMakers()
registered ACL Makers
Definition: Acl.cc:44
bool isEmpty() const
Definition: SBuf.h:424
static ACL * FindByName(const char *name)
Definition: Acl.cc:92
const ParameterFlags & NoFlags()
Definition: Options.cc:254
std::list< SBuf > SBufList
Definition: forward.h:22
Definition: SBuf.h:87
virtual void parseFlags()
configures ACL options, throwing on configuration errors
Definition: Acl.cc:289
#define xstrdup
ACL * next
Definition: Acl.h:85
void aclRegister(ACL *acl)
Definition: Gadgets.cc:224
Definition: Acl.cc:31
char * xstrncpy(char *dst, const char *src, size_t n)
Definition: xstring.cc:37
SBufList dumpOptions()
Definition: Acl.cc:296
#define DBG_CRITICAL
Definition: Debug.h:40
virtual bool hasAle() const =0
static ACL * Make(TypeName typeName)
creates an ACL object of the named (and already registered) ACL child type
Definition: Acl.cc:53
#define DBG_IMPORTANT
Definition: Debug.h:41
bool asyncInProgress() const
async call has been started and has not finished (or failed) yet
Definition: Checklist.h:151
int const char size_t
Definition: stub_liblog.cc:86
void self_destruct(void)
Definition: cache_cf.cc:275
const char * AclMatchedName
Definition: Acl.cc:29
#define NULL
Definition: types.h:166
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:123
static uint32 A
Definition: md4.c:43
static void ParseAclLine(ConfigParser &parser, ACL **head)
Definition: Acl.cc:165
virtual bool hasRequest() const =0
void destruct()
Definition: ConfigParser.cc:37
ACL *(* Maker)(TypeName typeName)
a "factory" function for making ACL objects (of some ACL child type)
Definition: Acl.h:29
#define safe_free(x)
Definition: xalloc.h:73
#define assert(EX)
Definition: assert.h:19
void context(const char *name, const char *configuration)
sets user-specified ACL name and squid.conf context
Definition: Acl.cc:154
ACL type name comparison functor.
Definition: Acl.cc:34
void fatalf(const char *fmt,...)
Definition: fatal.cc:68
SBuf buf()
Retrieve a copy of the current stream status.
Definition: Stream.h:105
void aclCacheMatchFlush(dlink_list *cache)
Definition: Acl.cc:357
virtual ~ACL()
Definition: Acl.cc:396
#define DBG_PARSE_NOTE(x)
Definition: Debug.h:45
virtual bool isProxyAuth() const
Definition: Acl.cc:283
static char * NextToken()
Definition: Acl.h:40
#define ACL_NAME_SZ
Definition: forward.h:41
virtual bool hasReply() const =0
static void Initialize()
Definition: Acl.cc:404
bool matches(ACLChecklist *checklist) const
Definition: Acl.cc:120
char * cfgline
Definition: Acl.h:84
virtual bool requiresRequest() const
whether our (i.e. shallow) match() requires checklist to have a request
Definition: Acl.cc:387
squidaio_request_t * head
Definition: aiops.cc:127
virtual bool valid() const
Definition: Acl.cc:114
virtual int match(ACLChecklist *checklist)=0
Matches the actual data in checklist against this ACL.
bool operator()(TypeName a, TypeName b) const
Definition: Acl.cc:36
virtual const Acl::Options & options()
Definition: Acl.h:63
ACL()
Definition: Acl.cc:106
int cacheMatchAcl(dlink_list *cache, ACLChecklist *)
Definition: Acl.cc:333
virtual void prepareForUse()
Definition: Acl.h:79
class ACL * aclList
Definition: SquidConfig.h:363
#define false
Definition: GnuRegex.c:233
char config_input_line[BUFSIZ]
Definition: cache_cf.cc:272
virtual bool requiresAle() const
whether our (i.e. shallow) match() requires checklist to have a AccessLogEntry
Definition: Acl.cc:375
char name[ACL_NAME_SZ]
Definition: Acl.h:83
class SquidConfig Config
Definition: SquidConfig.cc:12
virtual bool requiresReply() const
whether our (i.e. shallow) match() requires checklist to have a reply
Definition: Acl.cc:381

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors