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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors