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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors