]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/acl/Gadgets.cc
2 * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
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.
10 * DEBUG: section 28 Access Control
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
21 #include "acl/AclDenyInfoList.h"
22 #include "acl/Checklist.h"
23 #include "acl/Gadgets.h"
24 #include "acl/Strategised.h"
26 #include "ConfigParser.h"
27 #include "errorpage.h"
29 #include "HttpRequest.h"
30 #include "src/sbuf/Stream.h"
35 typedef std::set
<ACL
*> AclSet
;
36 /// Accumulates all ACLs to facilitate their clean deletion despite reuse.
37 static AclSet
*RegisteredAcls
; // TODO: Remove when ACLs are refcounted
39 /* does name lookup, returns page_id */
41 aclGetDenyInfoPage(AclDenyInfoList
** head
, const char *name
, int redirect_allowed
)
44 debugs(28, 3, "ERR_NONE due to a NULL name");
48 AclDenyInfoList
*A
= NULL
;
50 debugs(28, 8, HERE
<< "got called for " << name
);
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.");
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
;
66 debugs(28, 8, "aclGetDenyInfoPage: no match");
70 /* does name lookup, returns if it is a proxy_auth acl */
72 aclIsProxyAuth(const char *name
)
75 debugs(28, 3, "false due to a NULL name");
79 debugs(28, 5, "aclIsProxyAuth: called for " << name
);
83 if ((a
= ACL::FindByName(name
))) {
84 debugs(28, 5, "aclIsProxyAuth: returning " << a
->isProxyAuth());
85 return a
->isProxyAuth();
88 debugs(28, 3, "aclIsProxyAuth: WARNING, called for nonexistent ACL");
92 /* maex@space.net (05.09.96)
93 * get the info for redirecting "access denied" to info pages
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
102 aclParseDenyInfoLine(AclDenyInfoList
** head
)
108 /* first expect a page name */
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.");
116 const auto A
= new AclDenyInfoList(t
, ConfigParser::CurrentLocation());
118 /* next expect a list of ACL names */
119 while ((t
= ConfigParser::NextToken())) {
120 A
->acl_list
.emplace_back(t
);
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");
130 for (B
= *head
, T
= head
; B
; T
= &B
->next
, B
= B
->next
)
132 ; /* find the tail */
137 aclParseAccessLine(const char *directive
, ConfigParser
&, acl_access
**treep
)
139 /* first expect either 'allow' or 'deny' */
140 const char *t
= ConfigParser::NextToken();
143 debugs(28, DBG_CRITICAL
, "aclParseAccessLine: " << cfg_filename
<< " line " << config_lineno
<< ": " << config_input_line
);
144 debugs(28, DBG_CRITICAL
, "aclParseAccessLine: missing 'allow' or 'deny'.");
148 auto action
= Acl::Answer(ACCESS_DUNNO
);
149 if (!strcmp(t
, "allow"))
150 action
= Acl::Answer(ACCESS_ALLOWED
);
151 else if (!strcmp(t
, "deny"))
152 action
= Acl::Answer(ACCESS_DENIED
);
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
<< "'.");
159 const int ruleId
= ((treep
&& *treep
) ? (*treep
)->childrenCount() : 0) + 1;
162 ctxBuf
.appendf("%s#%d", directive
, ruleId
);
165 Acl::AndNode
*rule
= new Acl::AndNode
;
166 rule
->context(ctxBuf
.content(), config_input_line
);
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");
175 /* Append to the end of this list */
179 *treep
= new Acl::Tree
;
180 (*treep
)->context(directive
, config_input_line
);
183 (*treep
)->add(rule
, action
);
185 /* We lock _acl_access structures in ACLChecklist::matchNonBlocking() */
188 // aclParseAclList does not expect or set actions (cf. aclParseAccessLine)
190 aclParseAclList(ConfigParser
&, Acl::Tree
**treep
, const char *label
)
192 // accommodate callers unable to convert their ACL list context to string
198 ctxLine
.appendf("(%s %s line)", cfg_directive
, label
);
201 Acl::AndNode
*rule
= new Acl::AndNode
;
202 rule
->context(ctxLine
.content(), config_input_line
);
203 const auto aclCount
= rule
->lineParse();
207 ctxTree
.appendf("%s %s", cfg_directive
, label
);
210 // We want a cbdata-protected Tree (despite giving it only one child node).
211 Acl::Tree
*tree
= new Acl::Tree
;
213 tree
->context(ctxTree
.content(), config_input_line
);
223 aclRegister(ACL
*acl
)
225 if (!acl
->registered
) {
227 RegisteredAcls
= new AclSet
;
228 RegisteredAcls
->insert(acl
);
229 acl
->registered
= true;
233 /// remove registered acl from the centralized deletion set
236 aclDeregister(ACL
*acl
)
238 if (acl
->registered
) {
240 RegisteredAcls
->erase(acl
);
241 acl
->registered
= false;
245 /*********************/
246 /* Destroy functions */
247 /*********************/
249 /// called to delete ALL Acls.
251 aclDestroyAcls(ACL
** head
)
253 *head
= NULL
; // Config.aclList
254 if (AclSet
*acls
= RegisteredAcls
) {
255 debugs(28, 8, "deleting all " << acls
->size() << " ACLs");
256 while (!acls
->empty()) {
257 ACL
*acl
= *acls
->begin();
258 // We use centralized deletion (this function) so ~ACL should not
259 // delete other ACLs, but we still deregister first to prevent any
260 // accesses to the being-deleted ACL via RegisteredAcls.
261 assert(acl
->registered
); // make sure we are making progress
269 aclDestroyAclList(ACLList
**list
)
271 debugs(28, 8, "aclDestroyAclList: invoked");
278 aclDestroyAccessList(acl_access
** list
)
282 debugs(28, 3, "destroying: " << *list
<< ' ' << (*list
)->name
);
287 /* maex@space.net (06.09.1996)
288 * destroy an AclDenyInfoList */
291 aclDestroyDenyInfoList(AclDenyInfoList
** list
)
293 AclDenyInfoList
*a
= NULL
;
294 AclDenyInfoList
*a_next
= NULL
;
296 debugs(28, 8, "aclDestroyDenyInfoList: invoked");
298 for (a
= *list
; a
; a
= a_next
) {