Gadgets.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2019 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 /*
10  * DEBUG: section 28 Access Control
11  *
12  * This file contains ACL routines that are not part of the
13  * ACL class, nor any other class yet, and that need to be
14  * factored into appropriate places. They are here to reduce
15  * unneeded dependencies between the ACL class and the rest
16  * of squid.
17  */
18 
19 #include "squid.h"
20 #include "acl/Acl.h"
21 #include "acl/AclDenyInfoList.h"
22 #include "acl/Checklist.h"
23 #include "acl/Gadgets.h"
24 #include "acl/Strategised.h"
25 #include "acl/Tree.h"
26 #include "ConfigParser.h"
27 #include "errorpage.h"
28 #include "globals.h"
29 #include "HttpRequest.h"
30 #include "src/sbuf/Stream.h"
31 
32 #include <set>
33 #include <algorithm>
34 
35 typedef std::set<ACL*> AclSet;
37 static AclSet *RegisteredAcls; // TODO: Remove when ACLs are refcounted
38 
39 /* does name lookup, returns page_id */
41 aclGetDenyInfoPage(AclDenyInfoList ** head, const char *name, int redirect_allowed)
42 {
43  if (!name) {
44  debugs(28, 3, "ERR_NONE due to a NULL name");
45  return ERR_NONE;
46  }
47 
49 
50  debugs(28, 8, HERE << "got called for " << name);
51 
52  for (A = *head; A; A = A->next) {
53  if (!redirect_allowed && strchr(A->err_page_name, ':') ) {
54  debugs(28, 8, HERE << "Skip '" << A->err_page_name << "' 30x redirects not allowed as response here.");
55  continue;
56  }
57 
58  for (const auto &aclName: A->acl_list) {
59  if (aclName.cmp(name) == 0) {
60  debugs(28, 8, "match on " << name);
61  return A->err_page_id;
62  }
63  }
64  }
65 
66  debugs(28, 8, "aclGetDenyInfoPage: no match");
67  return ERR_NONE;
68 }
69 
70 /* does name lookup, returns if it is a proxy_auth acl */
71 int
72 aclIsProxyAuth(const char *name)
73 {
74  if (!name) {
75  debugs(28, 3, "false due to a NULL name");
76  return false;
77  }
78 
79  debugs(28, 5, "aclIsProxyAuth: called for " << name);
80 
81  ACL *a;
82 
83  if ((a = ACL::FindByName(name))) {
84  debugs(28, 5, "aclIsProxyAuth: returning " << a->isProxyAuth());
85  return a->isProxyAuth();
86  }
87 
88  debugs(28, 3, "aclIsProxyAuth: WARNING, called for nonexistent ACL");
89  return false;
90 }
91 
92 /* maex@space.net (05.09.96)
93  * get the info for redirecting "access denied" to info pages
94  * TODO (probably ;-)
95  * currently there is no optimization for
96  * - more than one deny_info line with the same url
97  * - a check, whether the given acl really is defined
98  * - a check, whether an acl is added more than once for the same url
99  */
100 
101 void
103 {
104  char *t = NULL;
106  AclDenyInfoList **T;
107 
108  /* first expect a page name */
109 
110  if ((t = ConfigParser::NextToken()) == NULL) {
111  debugs(28, DBG_CRITICAL, "aclParseDenyInfoLine: " << cfg_filename << " line " << config_lineno << ": " << config_input_line);
112  debugs(28, DBG_CRITICAL, "aclParseDenyInfoLine: missing 'error page' parameter.");
113  return;
114  }
115 
116  const auto A = new AclDenyInfoList(t, ConfigParser::CurrentLocation());
117 
118  /* next expect a list of ACL names */
119  while ((t = ConfigParser::NextToken())) {
120  A->acl_list.emplace_back(t);
121  }
122 
123  if (A->acl_list.empty()) {
124  debugs(28, DBG_CRITICAL, "aclParseDenyInfoLine: " << cfg_filename << " line " << config_lineno << ": " << config_input_line);
125  debugs(28, DBG_CRITICAL, "aclParseDenyInfoLine: deny_info line contains no ACL's, skipping");
126  delete A;
127  return;
128  }
129 
130  for (B = *head, T = head; B; T = &B->next, B = B->next)
131 
132  ; /* find the tail */
133  *T = A;
134 }
135 
136 void
137 aclParseAccessLine(const char *directive, ConfigParser &, acl_access **treep)
138 {
139  /* first expect either 'allow' or 'deny' */
140  const char *t = ConfigParser::NextToken();
141 
142  if (!t) {
143  debugs(28, DBG_CRITICAL, "aclParseAccessLine: " << cfg_filename << " line " << config_lineno << ": " << config_input_line);
144  debugs(28, DBG_CRITICAL, "aclParseAccessLine: missing 'allow' or 'deny'.");
145  return;
146  }
147 
149  if (!strcmp(t, "allow"))
151  else if (!strcmp(t, "deny"))
153  else {
154  debugs(28, DBG_CRITICAL, "aclParseAccessLine: " << cfg_filename << " line " << config_lineno << ": " << config_input_line);
155  debugs(28, DBG_CRITICAL, "aclParseAccessLine: expecting 'allow' or 'deny', got '" << t << "'.");
156  return;
157  }
158 
159  const int ruleId = ((treep && *treep) ? (*treep)->childrenCount() : 0) + 1;
160  MemBuf ctxBuf;
161  ctxBuf.init();
162  ctxBuf.appendf("%s#%d", directive, ruleId);
163  ctxBuf.terminate();
164 
165  Acl::AndNode *rule = new Acl::AndNode;
166  rule->context(ctxBuf.content(), config_input_line);
167  rule->lineParse();
168  if (rule->empty()) {
169  debugs(28, DBG_CRITICAL, "aclParseAccessLine: " << cfg_filename << " line " << config_lineno << ": " << config_input_line);
170  debugs(28, DBG_CRITICAL, "aclParseAccessLine: Access line contains no ACL's, skipping");
171  delete rule;
172  return;
173  }
174 
175  /* Append to the end of this list */
176 
177  assert(treep);
178  if (!*treep) {
179  *treep = new Acl::Tree;
180  (*treep)->context(directive, config_input_line);
181  }
182 
183  (*treep)->add(rule, action);
184 
185  /* We lock _acl_access structures in ACLChecklist::matchNonBlocking() */
186 }
187 
188 // aclParseAclList does not expect or set actions (cf. aclParseAccessLine)
189 void
190 aclParseAclList(ConfigParser &, Acl::Tree **treep, const char *label)
191 {
192  // accomodate callers unable to convert their ACL list context to string
193  if (!label)
194  label = "...";
195 
196  MemBuf ctxLine;
197  ctxLine.init();
198  ctxLine.appendf("(%s %s line)", cfg_directive, label);
199  ctxLine.terminate();
200 
201  Acl::AndNode *rule = new Acl::AndNode;
202  rule->context(ctxLine.content(), config_input_line);
203  rule->lineParse();
204 
205  MemBuf ctxTree;
206  ctxTree.init();
207  ctxTree.appendf("%s %s", cfg_directive, label);
208  ctxTree.terminate();
209 
210  // We want a cbdata-protected Tree (despite giving it only one child node).
211  Acl::Tree *tree = new Acl::Tree;
212  tree->add(rule);
213  tree->context(ctxTree.content(), config_input_line);
214 
215  assert(treep);
216  assert(!*treep);
217  *treep = tree;
218 }
219 
220 void
222 {
223  if (!acl->registered) {
224  if (!RegisteredAcls)
225  RegisteredAcls = new AclSet;
226  RegisteredAcls->insert(acl);
227  acl->registered = true;
228  }
229 }
230 
232 static
233 void
235 {
236  if (acl->registered) {
237  if (RegisteredAcls)
238  RegisteredAcls->erase(acl);
239  acl->registered = false;
240  }
241 }
242 
243 /*********************/
244 /* Destroy functions */
245 /*********************/
246 
248 void
250 {
251  *head = NULL; // Config.aclList
252  if (AclSet *acls = RegisteredAcls) {
253  debugs(28, 8, "deleting all " << acls->size() << " ACLs");
254  while (!acls->empty()) {
255  ACL *acl = *acls->begin();
256  // We use centralized deletion (this function) so ~ACL should not
257  // delete other ACLs, but we still deregister first to prevent any
258  // accesses to the being-deleted ACL via RegisteredAcls.
259  assert(acl->registered); // make sure we are making progress
260  aclDeregister(acl);
261  delete acl;
262  }
263  }
264 }
265 
266 void
268 {
269  debugs(28, 8, "aclDestroyAclList: invoked");
270  assert(list);
271  delete *list;
272  *list = NULL;
273 }
274 
275 void
277 {
278  assert(list);
279  if (*list)
280  debugs(28, 3, "destroying: " << *list << ' ' << (*list)->name);
281  delete *list;
282  *list = NULL;
283 }
284 
285 /* maex@space.net (06.09.1996)
286  * destroy an AclDenyInfoList */
287 
288 void
290 {
292  AclDenyInfoList *a_next = NULL;
293 
294  debugs(28, 8, "aclDestroyDenyInfoList: invoked");
295 
296  for (a = *list; a; a = a_next) {
297  a_next = a->next;
298  delete a;
299  }
300 
301  *list = NULL;
302 }
303 
void add(ACL *rule, const Answer &action)
appends and takes control over the rule with a given action
Definition: Tree.cc:44
#define assert(EX)
Definition: assert.h:17
Definition: Tree.h:20
static SBuf CurrentLocation()
static uint32 B
Definition: md4.c:43
Definition: Acl.h:39
#define ACLList
Definition: forward.h:45
void aclDestroyDenyInfoList(AclDenyInfoList **list)
Definition: Gadgets.cc:289
#define DBG_CRITICAL
Definition: Debug.h:45
int aclIsProxyAuth(const char *name)
Definition: Gadgets.cc:72
void init(mb_size_t szInit, mb_size_t szMax)
Definition: MemBuf.cc:96
deny_info representation. Currently a POD.
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:124
int config_lineno
const char * cfg_directive
During parsing, the name of the current squid.conf directive being parsed.
const char * cfg_filename
static ACL * FindByName(const char *name)
Definition: Acl.cc:93
virtual bool empty() const
Definition: InnerNode.cc:29
static char * NextToken()
virtual bool isProxyAuth() const
Definition: Acl.cc:286
void aclDestroyAccessList(acl_access **list)
Definition: Gadgets.cc:276
void lineParse()
parses one "acl name type acl1 acl2..." line, appending to nodes
Definition: InnerNode.cc:45
std::set< ACL * > AclSet
Definition: Gadgets.cc:35
char * content()
start of the added data
Definition: MemBuf.h:41
std::ostream & HERE(std::ostream &s)
Definition: Debug.h:153
static uint32 A
Definition: md4.c:43
bool action(int fd, size_t metasize, const char *fn, const char *url, const SquidMetaList &meta)
Definition: purge.cc:311
static AclSet * RegisteredAcls
Accumulates all ACLs to facilitate their clean deletion despite reuse.
Definition: Gadgets.cc:37
void aclRegister(ACL *acl)
Definition: Gadgets.cc:221
char config_input_line[BUFSIZ]
void appendf(const char *fmt,...) PRINTF_FORMAT_ARG2
Append operation with printf-style arguments.
Definition: Packable.h:61
err_type err_page_id
Definition: MemBuf.h:23
void aclParseAclList(ConfigParser &, Acl::Tree **treep, const char *label)
Definition: Gadgets.cc:190
int a
Definition: membanger.c:50
void aclDestroyAcls(ACL **head)
called to delete ALL Acls.
Definition: Gadgets.cc:249
#define acl_access
Definition: forward.h:44
AclDenyInfoList * next
void context(const char *name, const char *configuration)
sets user-specified ACL name and squid.conf context
Definition: Acl.cc:157
void aclDestroyAclList(ACLList **list)
Definition: Gadgets.cc:267
SBufList acl_list
ACL names in configured order.
squidaio_request_t * head
Definition: aiops.cc:127
#define NULL
Definition: types.h:166
void aclParseDenyInfoLine(AclDenyInfoList **head)
Definition: Gadgets.cc:102
static void aclDeregister(ACL *acl)
remove registered acl from the centralized deletion set
Definition: Gadgets.cc:234
err_type
Definition: err_type.h:12
void aclParseAccessLine(const char *directive, ConfigParser &, acl_access **treep)
Definition: Gadgets.cc:137
err_type aclGetDenyInfoPage(AclDenyInfoList **head, const char *name, int redirect_allowed)
Definition: Gadgets.cc:41
bool registered
added to the global list of ACLs via aclRegister()
Definition: Acl.h:86
void terminate()
Definition: MemBuf.cc:250

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors