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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors