]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/acl/Gadgets.cc
9d39813aac01d003c11766037b42daab4cb2ed72
2 * Copyright (C) 1996-2015 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/AclNameList.h"
23 #include "acl/Checklist.h"
24 #include "acl/Gadgets.h"
25 #include "acl/Strategised.h"
27 #include "ConfigParser.h"
28 #include "errorpage.h"
30 #include "HttpRequest.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 AclNameList
*L
= NULL
;
55 if (!redirect_allowed
&& strchr(A
->err_page_name
, ':') ) {
56 debugs(28, 8, HERE
<< "Skip '" << A
->err_page_name
<< "' 30x redirects not allowed as response here.");
60 for (L
= A
->acl_list
; L
; L
= L
->next
) {
61 if (!strcmp(name
, L
->name
)) {
62 debugs(28, 8, HERE
<< "match on " << name
);
63 return A
->err_page_id
;
69 debugs(28, 8, "aclGetDenyInfoPage: no match");
73 /* does name lookup, returns if it is a proxy_auth acl */
75 aclIsProxyAuth(const char *name
)
78 debugs(28, 3, "false due to a NULL name");
82 debugs(28, 5, "aclIsProxyAuth: called for " << name
);
86 if ((a
= ACL::FindByName(name
))) {
87 debugs(28, 5, "aclIsProxyAuth: returning " << a
->isProxyAuth());
88 return a
->isProxyAuth();
91 debugs(28, 3, "aclIsProxyAuth: WARNING, called for nonexistent ACL");
95 /* maex@space.net (05.09.96)
96 * get the info for redirecting "access denied" to info pages
98 * currently there is no optimization for
99 * - more than one deny_info line with the same url
100 * - a check, whether the given acl really is defined
101 * - a check, whether an acl is added more than once for the same url
105 aclParseDenyInfoLine(AclDenyInfoList
** head
)
108 AclDenyInfoList
*A
= NULL
;
109 AclDenyInfoList
*B
= NULL
;
110 AclDenyInfoList
**T
= NULL
;
111 AclNameList
*L
= NULL
;
112 AclNameList
**Tail
= NULL
;
114 /* first expect a page name */
116 if ((t
= ConfigParser::NextToken()) == NULL
) {
117 debugs(28, DBG_CRITICAL
, "aclParseDenyInfoLine: " << cfg_filename
<< " line " << config_lineno
<< ": " << config_input_line
);
118 debugs(28, DBG_CRITICAL
, "aclParseDenyInfoLine: missing 'error page' parameter.");
122 A
= (AclDenyInfoList
*)memAllocate(MEM_ACL_DENY_INFO_LIST
);
123 A
->err_page_id
= errorReservePageId(t
);
124 A
->err_page_name
= xstrdup(t
);
125 A
->next
= (AclDenyInfoList
*) NULL
;
126 /* next expect a list of ACL names */
129 while ((t
= ConfigParser::NextToken())) {
130 L
= (AclNameList
*)memAllocate(MEM_ACL_NAME_LIST
);
131 xstrncpy(L
->name
, t
, ACL_NAME_SZ
-1);
136 if (A
->acl_list
== NULL
) {
137 debugs(28, DBG_CRITICAL
, "aclParseDenyInfoLine: " << cfg_filename
<< " line " << config_lineno
<< ": " << config_input_line
);
138 debugs(28, DBG_CRITICAL
, "aclParseDenyInfoLine: deny_info line contains no ACL's, skipping");
139 memFree(A
, MEM_ACL_DENY_INFO_LIST
);
143 for (B
= *head
, T
= head
; B
; T
= &B
->next
, B
= B
->next
)
145 ; /* find the tail */
150 aclParseAccessLine(const char *directive
, ConfigParser
&, acl_access
**treep
)
152 /* first expect either 'allow' or 'deny' */
153 const char *t
= ConfigParser::NextToken();
156 debugs(28, DBG_CRITICAL
, "aclParseAccessLine: " << cfg_filename
<< " line " << config_lineno
<< ": " << config_input_line
);
157 debugs(28, DBG_CRITICAL
, "aclParseAccessLine: missing 'allow' or 'deny'.");
161 allow_t action
= ACCESS_DUNNO
;
162 if (!strcmp(t
, "allow"))
163 action
= ACCESS_ALLOWED
;
164 else if (!strcmp(t
, "deny"))
165 action
= ACCESS_DENIED
;
167 debugs(28, DBG_CRITICAL
, "aclParseAccessLine: " << cfg_filename
<< " line " << config_lineno
<< ": " << config_input_line
);
168 debugs(28, DBG_CRITICAL
, "aclParseAccessLine: expecting 'allow' or 'deny', got '" << t
<< "'.");
172 const int ruleId
= ((treep
&& *treep
) ? (*treep
)->childrenCount() : 0) + 1;
175 ctxBuf
.appendf("%s#%d", directive
, ruleId
);
178 Acl::AndNode
*rule
= new Acl::AndNode
;
179 rule
->context(ctxBuf
.content(), config_input_line
);
182 debugs(28, DBG_CRITICAL
, "aclParseAccessLine: " << cfg_filename
<< " line " << config_lineno
<< ": " << config_input_line
);
183 debugs(28, DBG_CRITICAL
, "aclParseAccessLine: Access line contains no ACL's, skipping");
188 /* Append to the end of this list */
192 *treep
= new Acl::Tree
;
193 (*treep
)->context(directive
, config_input_line
);
196 (*treep
)->add(rule
, action
);
198 /* We lock _acl_access structures in ACLChecklist::matchNonBlocking() */
201 // aclParseAclList does not expect or set actions (cf. aclParseAccessLine)
203 aclParseAclList(ConfigParser
&, Acl::Tree
**treep
, const char *label
)
205 // accomodate callers unable to convert their ACL list context to string
211 ctxLine
.appendf("(%s %s line)", cfg_directive
, label
);
214 Acl::AndNode
*rule
= new Acl::AndNode
;
215 rule
->context(ctxLine
.content(), config_input_line
);
220 ctxTree
.appendf("%s %s", cfg_directive
, label
);
223 // We want a cbdata-protected Tree (despite giving it only one child node).
224 Acl::Tree
*tree
= new Acl::Tree
;
226 tree
->context(ctxTree
.content(), config_input_line
);
234 aclRegister(ACL
*acl
)
236 if (!acl
->registered
) {
238 RegisteredAcls
= new AclSet
;
239 RegisteredAcls
->insert(acl
);
240 acl
->registered
= true;
244 /// remove registered acl from the centralized deletion set
247 aclDeregister(ACL
*acl
)
249 if (acl
->registered
) {
251 RegisteredAcls
->erase(acl
);
252 acl
->registered
= false;
256 /*********************/
257 /* Destroy functions */
258 /*********************/
260 /// called to delete ALL Acls.
262 aclDestroyAcls(ACL
** head
)
264 *head
= NULL
; // Config.aclList
265 if (AclSet
*acls
= RegisteredAcls
) {
266 debugs(28, 8, "deleting all " << acls
->size() << " ACLs");
267 while (!acls
->empty()) {
268 ACL
*acl
= *acls
->begin();
269 // We use centralized deletion (this function) so ~ACL should not
270 // delete other ACLs, but we still deregister first to prevent any
271 // accesses to the being-deleted ACL via RegisteredAcls.
272 assert(acl
->registered
); // make sure we are making progress
280 aclDestroyAclList(ACLList
**list
)
282 debugs(28, 8, "aclDestroyAclList: invoked");
289 aclDestroyAccessList(acl_access
** list
)
293 debugs(28, 3, "destroying: " << *list
<< ' ' << (*list
)->name
);
298 /* maex@space.net (06.09.1996)
299 * destroy an AclDenyInfoList */
302 aclDestroyDenyInfoList(AclDenyInfoList
** list
)
304 AclDenyInfoList
*a
= NULL
;
305 AclDenyInfoList
*a_next
= NULL
;
306 AclNameList
*l
= NULL
;
307 AclNameList
*l_next
= NULL
;
309 debugs(28, 8, "aclDestroyDenyInfoList: invoked");
311 for (a
= *list
; a
; a
= a_next
) {
312 for (l
= a
->acl_list
; l
; l
= l_next
) {
318 xfree(a
->err_page_name
);
319 memFree(a
, MEM_ACL_DENY_INFO_LIST
);