]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/acl/Gadgets.cc
2 * Copyright (C) 1996-2014 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"
36 typedef std::set
<ACL
*> AclSet
;
37 /// Accumulates all ACLs to facilitate their clean deletion despite reuse.
38 static AclSet
*RegisteredAcls
; // TODO: Remove when ACLs are refcounted
40 /* does name lookup, returns page_id */
42 aclGetDenyInfoPage(AclDenyInfoList
** head
, const char *name
, int redirect_allowed
)
45 debugs(28, 3, "ERR_NONE due to a NULL name");
49 AclDenyInfoList
*A
= NULL
;
51 debugs(28, 8, HERE
<< "got called for " << name
);
53 for (A
= *head
; A
; A
= A
->next
) {
54 AclNameList
*L
= NULL
;
56 if (!redirect_allowed
&& strchr(A
->err_page_name
, ':') ) {
57 debugs(28, 8, HERE
<< "Skip '" << A
->err_page_name
<< "' 30x redirects not allowed as response here.");
61 for (L
= A
->acl_list
; L
; L
= L
->next
) {
62 if (!strcmp(name
, L
->name
)) {
63 debugs(28, 8, HERE
<< "match on " << name
);
64 return A
->err_page_id
;
70 debugs(28, 8, "aclGetDenyInfoPage: no match");
74 /* does name lookup, returns if it is a proxy_auth acl */
76 aclIsProxyAuth(const char *name
)
79 debugs(28, 3, "false due to a NULL name");
83 debugs(28, 5, "aclIsProxyAuth: called for " << name
);
87 if ((a
= ACL::FindByName(name
))) {
88 debugs(28, 5, "aclIsProxyAuth: returning " << a
->isProxyAuth());
89 return a
->isProxyAuth();
92 debugs(28, 3, "aclIsProxyAuth: WARNING, called for nonexistent ACL");
96 /* maex@space.net (05.09.96)
97 * get the info for redirecting "access denied" to info pages
99 * currently there is no optimization for
100 * - more than one deny_info line with the same url
101 * - a check, whether the given acl really is defined
102 * - a check, whether an acl is added more than once for the same url
106 aclParseDenyInfoLine(AclDenyInfoList
** head
)
109 AclDenyInfoList
*A
= NULL
;
110 AclDenyInfoList
*B
= NULL
;
111 AclDenyInfoList
**T
= NULL
;
112 AclNameList
*L
= NULL
;
113 AclNameList
**Tail
= NULL
;
115 /* first expect a page name */
117 if ((t
= ConfigParser::NextToken()) == NULL
) {
118 debugs(28, DBG_CRITICAL
, "aclParseDenyInfoLine: " << cfg_filename
<< " line " << config_lineno
<< ": " << config_input_line
);
119 debugs(28, DBG_CRITICAL
, "aclParseDenyInfoLine: missing 'error page' parameter.");
123 A
= (AclDenyInfoList
*)memAllocate(MEM_ACL_DENY_INFO_LIST
);
124 A
->err_page_id
= errorReservePageId(t
);
125 A
->err_page_name
= xstrdup(t
);
126 A
->next
= (AclDenyInfoList
*) NULL
;
127 /* next expect a list of ACL names */
130 while ((t
= ConfigParser::NextToken())) {
131 L
= (AclNameList
*)memAllocate(MEM_ACL_NAME_LIST
);
132 xstrncpy(L
->name
, t
, ACL_NAME_SZ
-1);
137 if (A
->acl_list
== NULL
) {
138 debugs(28, DBG_CRITICAL
, "aclParseDenyInfoLine: " << cfg_filename
<< " line " << config_lineno
<< ": " << config_input_line
);
139 debugs(28, DBG_CRITICAL
, "aclParseDenyInfoLine: deny_info line contains no ACL's, skipping");
140 memFree(A
, MEM_ACL_DENY_INFO_LIST
);
144 for (B
= *head
, T
= head
; B
; T
= &B
->next
, B
= B
->next
)
146 ; /* find the tail */
151 aclParseAccessLine(const char *directive
, ConfigParser
&, acl_access
**treep
)
153 /* first expect either 'allow' or 'deny' */
154 const char *t
= ConfigParser::NextToken();
157 debugs(28, DBG_CRITICAL
, "aclParseAccessLine: " << cfg_filename
<< " line " << config_lineno
<< ": " << config_input_line
);
158 debugs(28, DBG_CRITICAL
, "aclParseAccessLine: missing 'allow' or 'deny'.");
162 allow_t action
= ACCESS_DUNNO
;
163 if (!strcmp(t
, "allow"))
164 action
= ACCESS_ALLOWED
;
165 else if (!strcmp(t
, "deny"))
166 action
= ACCESS_DENIED
;
168 debugs(28, DBG_CRITICAL
, "aclParseAccessLine: " << cfg_filename
<< " line " << config_lineno
<< ": " << config_input_line
);
169 debugs(28, DBG_CRITICAL
, "aclParseAccessLine: expecting 'allow' or 'deny', got '" << t
<< "'.");
173 const int ruleId
= ((treep
&& *treep
) ? (*treep
)->childrenCount() : 0) + 1;
176 ctxBuf
.Printf("%s#%d", directive
, ruleId
);
179 Acl::AndNode
*rule
= new Acl::AndNode
;
180 rule
->context(ctxBuf
.content(), config_input_line
);
183 debugs(28, DBG_CRITICAL
, "aclParseAccessLine: " << cfg_filename
<< " line " << config_lineno
<< ": " << config_input_line
);
184 debugs(28, DBG_CRITICAL
, "aclParseAccessLine: Access line contains no ACL's, skipping");
189 /* Append to the end of this list */
193 *treep
= new Acl::Tree
;
194 (*treep
)->context(directive
, config_input_line
);
197 (*treep
)->add(rule
, action
);
199 /* We lock _acl_access structures in ACLChecklist::matchNonBlocking() */
202 // aclParseAclList does not expect or set actions (cf. aclParseAccessLine)
204 aclParseAclList(ConfigParser
&, Acl::Tree
**treep
, const char *label
)
206 // accomodate callers unable to convert their ACL list context to string
212 ctxLine
.Printf("(%s %s line)", cfg_directive
, label
);
215 Acl::AndNode
*rule
= new Acl::AndNode
;
216 rule
->context(ctxLine
.content(), config_input_line
);
221 ctxTree
.Printf("%s %s", cfg_directive
, label
);
224 // We want a cbdata-protected Tree (despite giving it only one child node).
225 Acl::Tree
*tree
= new Acl::Tree
;
227 tree
->context(ctxTree
.content(), config_input_line
);
235 aclRegister(ACL
*acl
)
237 if (!acl
->registered
) {
239 RegisteredAcls
= new AclSet
;
240 RegisteredAcls
->insert(acl
);
241 acl
->registered
= true;
245 /// remove registered acl from the centralized deletion set
248 aclDeregister(ACL
*acl
)
250 if (acl
->registered
) {
252 RegisteredAcls
->erase(acl
);
253 acl
->registered
= false;
257 /*********************/
258 /* Destroy functions */
259 /*********************/
261 /// called to delete ALL Acls.
263 aclDestroyAcls(ACL
** head
)
265 *head
= NULL
; // Config.aclList
266 if (AclSet
*acls
= RegisteredAcls
) {
267 debugs(28, 8, "deleting all " << acls
->size() << " ACLs");
268 while (!acls
->empty()) {
269 ACL
*acl
= *acls
->begin();
270 // We use centralized deletion (this function) so ~ACL should not
271 // delete other ACLs, but we still deregister first to prevent any
272 // accesses to the being-deleted ACL via RegisteredAcls.
273 assert(acl
->registered
); // make sure we are making progress
281 aclDestroyAclList(ACLList
**list
)
283 debugs(28, 8, "aclDestroyAclList: invoked");
290 aclDestroyAccessList(acl_access
** list
)
294 debugs(28, 3, "destroying: " << *list
<< ' ' << (*list
)->name
);
299 /* maex@space.net (06.09.1996)
300 * destroy an AclDenyInfoList */
303 aclDestroyDenyInfoList(AclDenyInfoList
** list
)
305 AclDenyInfoList
*a
= NULL
;
306 AclDenyInfoList
*a_next
= NULL
;
307 AclNameList
*l
= NULL
;
308 AclNameList
*l_next
= NULL
;
310 debugs(28, 8, "aclDestroyDenyInfoList: invoked");
312 for (a
= *list
; a
; a
= a_next
) {
313 for (l
= a
->acl_list
; l
; l
= l_next
) {
319 xfree(a
->err_page_name
);
320 memFree(a
, MEM_ACL_DENY_INFO_LIST
);