]> git.ipfire.org Git - thirdparty/squid.git/blob - src/acl/Gadgets.cc
Sync with trunk rev.13542
[thirdparty/squid.git] / src / acl / Gadgets.cc
1 /*
2 * DEBUG: section 28 Access Control
3 * AUTHOR: Duane Wessels
4 *
5 * This file contains ACL routines that are not part of the
6 * ACL class, nor any other class yet, and that need to be
7 * factored into appropriate places. They are here to reduce
8 * unneeded dependencies between the ACL class and the rest
9 * of squid.
10 *
11 * SQUID Web Proxy Cache http://www.squid-cache.org/
12 * ----------------------------------------------------------
13 *
14 * Squid is the result of efforts by numerous individuals from
15 * the Internet community; see the CONTRIBUTORS file for full
16 * details. Many organizations have provided support for Squid's
17 * development; see the SPONSORS file for full details. Squid is
18 * Copyrighted (C) 2001 by the Regents of the University of
19 * California; see the COPYRIGHT file for full details. Squid
20 * incorporates software developed and/or copyrighted by other
21 * sources; see the CREDITS file for full details.
22 *
23 * This program is free software; you can redistribute it and/or modify
24 * it under the terms of the GNU General Public License as published by
25 * the Free Software Foundation; either version 2 of the License, or
26 * (at your option) any later version.
27 *
28 * This program is distributed in the hope that it will be useful,
29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 * GNU General Public License for more details.
32 *
33 * You should have received a copy of the GNU General Public License
34 * along with this program; if not, write to the Free Software
35 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
36 *
37 */
38
39 #include "squid.h"
40 #include "acl/Acl.h"
41 #include "acl/AclDenyInfoList.h"
42 #include "acl/AclNameList.h"
43 #include "acl/Checklist.h"
44 #include "acl/Gadgets.h"
45 #include "acl/Strategised.h"
46 #include "acl/Tree.h"
47 #include "ConfigParser.h"
48 #include "errorpage.h"
49 #include "globals.h"
50 #include "HttpRequest.h"
51 #include "Mem.h"
52
53 #include <set>
54 #include <algorithm>
55
56 typedef std::set<ACL*> AclSet;
57 /// Accumulates all ACLs to facilitate their clean deletion despite reuse.
58 static AclSet *RegisteredAcls; // TODO: Remove when ACLs are refcounted
59
60 /* does name lookup, returns page_id */
61 err_type
62 aclGetDenyInfoPage(AclDenyInfoList ** head, const char *name, int redirect_allowed)
63 {
64 if (!name) {
65 debugs(28, 3, "ERR_NONE due to a NULL name");
66 return ERR_NONE;
67 }
68
69 AclDenyInfoList *A = NULL;
70
71 debugs(28, 8, HERE << "got called for " << name);
72
73 for (A = *head; A; A = A->next) {
74 AclNameList *L = NULL;
75
76 if (!redirect_allowed && strchr(A->err_page_name, ':') ) {
77 debugs(28, 8, HERE << "Skip '" << A->err_page_name << "' 30x redirects not allowed as response here.");
78 continue;
79 }
80
81 for (L = A->acl_list; L; L = L->next) {
82 if (!strcmp(name, L->name)) {
83 debugs(28, 8, HERE << "match on " << name);
84 return A->err_page_id;
85 }
86
87 }
88 }
89
90 debugs(28, 8, "aclGetDenyInfoPage: no match");
91 return ERR_NONE;
92 }
93
94 /* does name lookup, returns if it is a proxy_auth acl */
95 int
96 aclIsProxyAuth(const char *name)
97 {
98 if (!name) {
99 debugs(28, 3, "false due to a NULL name");
100 return false;
101 }
102
103 debugs(28, 5, "aclIsProxyAuth: called for " << name);
104
105 ACL *a;
106
107 if ((a = ACL::FindByName(name))) {
108 debugs(28, 5, "aclIsProxyAuth: returning " << a->isProxyAuth());
109 return a->isProxyAuth();
110 }
111
112 debugs(28, 3, "aclIsProxyAuth: WARNING, called for nonexistent ACL");
113 return false;
114 }
115
116 /* maex@space.net (05.09.96)
117 * get the info for redirecting "access denied" to info pages
118 * TODO (probably ;-)
119 * currently there is no optimization for
120 * - more than one deny_info line with the same url
121 * - a check, whether the given acl really is defined
122 * - a check, whether an acl is added more than once for the same url
123 */
124
125 void
126 aclParseDenyInfoLine(AclDenyInfoList ** head)
127 {
128 char *t = NULL;
129 AclDenyInfoList *A = NULL;
130 AclDenyInfoList *B = NULL;
131 AclDenyInfoList **T = NULL;
132 AclNameList *L = NULL;
133 AclNameList **Tail = NULL;
134
135 /* first expect a page name */
136
137 if ((t = ConfigParser::NextToken()) == NULL) {
138 debugs(28, DBG_CRITICAL, "aclParseDenyInfoLine: " << cfg_filename << " line " << config_lineno << ": " << config_input_line);
139 debugs(28, DBG_CRITICAL, "aclParseDenyInfoLine: missing 'error page' parameter.");
140 return;
141 }
142
143 A = (AclDenyInfoList *)memAllocate(MEM_ACL_DENY_INFO_LIST);
144 A->err_page_id = errorReservePageId(t);
145 A->err_page_name = xstrdup(t);
146 A->next = (AclDenyInfoList *) NULL;
147 /* next expect a list of ACL names */
148 Tail = &A->acl_list;
149
150 while ((t = ConfigParser::NextToken())) {
151 L = (AclNameList *)memAllocate(MEM_ACL_NAME_LIST);
152 xstrncpy(L->name, t, ACL_NAME_SZ-1);
153 *Tail = L;
154 Tail = &L->next;
155 }
156
157 if (A->acl_list == NULL) {
158 debugs(28, DBG_CRITICAL, "aclParseDenyInfoLine: " << cfg_filename << " line " << config_lineno << ": " << config_input_line);
159 debugs(28, DBG_CRITICAL, "aclParseDenyInfoLine: deny_info line contains no ACL's, skipping");
160 memFree(A, MEM_ACL_DENY_INFO_LIST);
161 return;
162 }
163
164 for (B = *head, T = head; B; T = &B->next, B = B->next)
165
166 ; /* find the tail */
167 *T = A;
168 }
169
170 void
171 aclParseAccessLine(const char *directive, ConfigParser &, acl_access **treep)
172 {
173 /* first expect either 'allow' or 'deny' */
174 const char *t = ConfigParser::NextToken();
175
176 if (!t) {
177 debugs(28, DBG_CRITICAL, "aclParseAccessLine: " << cfg_filename << " line " << config_lineno << ": " << config_input_line);
178 debugs(28, DBG_CRITICAL, "aclParseAccessLine: missing 'allow' or 'deny'.");
179 return;
180 }
181
182 allow_t action = ACCESS_DUNNO;
183 if (!strcmp(t, "allow"))
184 action = ACCESS_ALLOWED;
185 else if (!strcmp(t, "deny"))
186 action = ACCESS_DENIED;
187 else {
188 debugs(28, DBG_CRITICAL, "aclParseAccessLine: " << cfg_filename << " line " << config_lineno << ": " << config_input_line);
189 debugs(28, DBG_CRITICAL, "aclParseAccessLine: expecting 'allow' or 'deny', got '" << t << "'.");
190 return;
191 }
192
193 const int ruleId = ((treep && *treep) ? (*treep)->childrenCount() : 0) + 1;
194 MemBuf ctxBuf;
195 ctxBuf.init();
196 ctxBuf.Printf("%s#%d", directive, ruleId);
197 ctxBuf.terminate();
198
199 Acl::AndNode *rule = new Acl::AndNode;
200 rule->context(ctxBuf.content(), config_input_line);
201 rule->lineParse();
202 if (rule->empty()) {
203 debugs(28, DBG_CRITICAL, "aclParseAccessLine: " << cfg_filename << " line " << config_lineno << ": " << config_input_line);
204 debugs(28, DBG_CRITICAL, "aclParseAccessLine: Access line contains no ACL's, skipping");
205 delete rule;
206 return;
207 }
208
209 /* Append to the end of this list */
210
211 assert(treep);
212 if (!*treep) {
213 *treep = new Acl::Tree;
214 (*treep)->context(directive, config_input_line);
215 }
216
217 (*treep)->add(rule, action);
218
219 /* We lock _acl_access structures in ACLChecklist::matchNonBlocking() */
220 }
221
222 // aclParseAclList does not expect or set actions (cf. aclParseAccessLine)
223 void
224 aclParseAclList(ConfigParser &, Acl::Tree **treep, const char *label)
225 {
226 // accomodate callers unable to convert their ACL list context to string
227 if (!label)
228 label = "...";
229
230 MemBuf ctxLine;
231 ctxLine.init();
232 ctxLine.Printf("(%s %s line)", cfg_directive, label);
233 ctxLine.terminate();
234
235 Acl::AndNode *rule = new Acl::AndNode;
236 rule->context(ctxLine.content(), config_input_line);
237 rule->lineParse();
238
239 MemBuf ctxTree;
240 ctxTree.init();
241 ctxTree.Printf("%s %s", cfg_directive, label);
242 ctxTree.terminate();
243
244 // We want a cbdata-protected Tree (despite giving it only one child node).
245 Acl::Tree *tree = new Acl::Tree;
246 tree->add(rule);
247 tree->context(ctxTree.content(), config_input_line);
248
249 assert(treep);
250 assert(!*treep);
251 *treep = tree;
252 }
253
254 void
255 aclRegister(ACL *acl)
256 {
257 if (!acl->registered) {
258 if (!RegisteredAcls)
259 RegisteredAcls = new AclSet;
260 RegisteredAcls->insert(acl);
261 acl->registered = true;
262 }
263 }
264
265 /// remove registered acl from the centralized deletion set
266 static
267 void
268 aclDeregister(ACL *acl)
269 {
270 if (acl->registered) {
271 if (RegisteredAcls)
272 RegisteredAcls->erase(acl);
273 acl->registered = false;
274 }
275 }
276
277 /*********************/
278 /* Destroy functions */
279 /*********************/
280
281 /// called to delete ALL Acls.
282 void
283 aclDestroyAcls(ACL ** head)
284 {
285 *head = NULL; // Config.aclList
286 if (AclSet *acls = RegisteredAcls) {
287 debugs(28, 8, "deleting all " << acls->size() << " ACLs");
288 while (!acls->empty()) {
289 ACL *acl = *acls->begin();
290 // We use centralized deletion (this function) so ~ACL should not
291 // delete other ACLs, but we still deregister first to prevent any
292 // accesses to the being-deleted ACL via RegisteredAcls.
293 assert(acl->registered); // make sure we are making progress
294 aclDeregister(acl);
295 delete acl;
296 }
297 }
298 }
299
300 void
301 aclDestroyAclList(ACLList **list)
302 {
303 debugs(28, 8, "aclDestroyAclList: invoked");
304 assert(list);
305 delete *list;
306 *list = NULL;
307 }
308
309 void
310 aclDestroyAccessList(acl_access ** list)
311 {
312 assert(list);
313 if (*list)
314 debugs(28, 3, "destroying: " << *list << ' ' << (*list)->name);
315 delete *list;
316 *list = NULL;
317 }
318
319 /* maex@space.net (06.09.1996)
320 * destroy an AclDenyInfoList */
321
322 void
323 aclDestroyDenyInfoList(AclDenyInfoList ** list)
324 {
325 AclDenyInfoList *a = NULL;
326 AclDenyInfoList *a_next = NULL;
327 AclNameList *l = NULL;
328 AclNameList *l_next = NULL;
329
330 debugs(28, 8, "aclDestroyDenyInfoList: invoked");
331
332 for (a = *list; a; a = a_next) {
333 for (l = a->acl_list; l; l = l_next) {
334 l_next = l->next;
335 safe_free(l);
336 }
337
338 a_next = a->next;
339 xfree(a->err_page_name);
340 memFree(a, MEM_ACL_DENY_INFO_LIST);
341 }
342
343 *list = NULL;
344 }