]> git.ipfire.org Git - thirdparty/squid.git/blob - src/acl/Gadgets.cc
Bug 3972: Segfault when getting the deny info page ID after a reconfigure
[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 /* does name lookup, returns page_id */
54 err_type
55 aclGetDenyInfoPage(AclDenyInfoList ** head, const char *name, int redirect_allowed)
56 {
57 if (!name) {
58 debugs(28, 3, "ERR_NONE due to a NULL name");
59 return ERR_NONE;
60 }
61
62 AclDenyInfoList *A = NULL;
63
64 debugs(28, 8, HERE << "got called for " << name);
65
66 for (A = *head; A; A = A->next) {
67 AclNameList *L = NULL;
68
69 if (!redirect_allowed && strchr(A->err_page_name, ':') ) {
70 debugs(28, 8, HERE << "Skip '" << A->err_page_name << "' 30x redirects not allowed as response here.");
71 continue;
72 }
73
74 for (L = A->acl_list; L; L = L->next) {
75 if (!strcmp(name, L->name)) {
76 debugs(28, 8, HERE << "match on " << name);
77 return A->err_page_id;
78 }
79
80 }
81 }
82
83 debugs(28, 8, "aclGetDenyInfoPage: no match");
84 return ERR_NONE;
85 }
86
87 /* does name lookup, returns if it is a proxy_auth acl */
88 int
89 aclIsProxyAuth(const char *name)
90 {
91 debugs(28, 5, "aclIsProxyAuth: called for " << name);
92
93 if (NULL == name)
94 return false;
95
96 ACL *a;
97
98 if ((a = ACL::FindByName(name))) {
99 debugs(28, 5, "aclIsProxyAuth: returning " << a->isProxyAuth());
100 return a->isProxyAuth();
101 }
102
103 debugs(28, 3, "aclIsProxyAuth: WARNING, called for nonexistent ACL");
104 return false;
105 }
106
107 /* maex@space.net (05.09.96)
108 * get the info for redirecting "access denied" to info pages
109 * TODO (probably ;-)
110 * currently there is no optimization for
111 * - more than one deny_info line with the same url
112 * - a check, whether the given acl really is defined
113 * - a check, whether an acl is added more than once for the same url
114 */
115
116 void
117 aclParseDenyInfoLine(AclDenyInfoList ** head)
118 {
119 char *t = NULL;
120 AclDenyInfoList *A = NULL;
121 AclDenyInfoList *B = NULL;
122 AclDenyInfoList **T = NULL;
123 AclNameList *L = NULL;
124 AclNameList **Tail = NULL;
125
126 /* first expect a page name */
127
128 if ((t = ConfigParser::NextToken()) == NULL) {
129 debugs(28, DBG_CRITICAL, "aclParseDenyInfoLine: " << cfg_filename << " line " << config_lineno << ": " << config_input_line);
130 debugs(28, DBG_CRITICAL, "aclParseDenyInfoLine: missing 'error page' parameter.");
131 return;
132 }
133
134 A = (AclDenyInfoList *)memAllocate(MEM_ACL_DENY_INFO_LIST);
135 A->err_page_id = errorReservePageId(t);
136 A->err_page_name = xstrdup(t);
137 A->next = (AclDenyInfoList *) NULL;
138 /* next expect a list of ACL names */
139 Tail = &A->acl_list;
140
141 while ((t = ConfigParser::NextToken())) {
142 L = (AclNameList *)memAllocate(MEM_ACL_NAME_LIST);
143 xstrncpy(L->name, t, ACL_NAME_SZ-1);
144 *Tail = L;
145 Tail = &L->next;
146 }
147
148 if (A->acl_list == NULL) {
149 debugs(28, DBG_CRITICAL, "aclParseDenyInfoLine: " << cfg_filename << " line " << config_lineno << ": " << config_input_line);
150 debugs(28, DBG_CRITICAL, "aclParseDenyInfoLine: deny_info line contains no ACL's, skipping");
151 memFree(A, MEM_ACL_DENY_INFO_LIST);
152 return;
153 }
154
155 for (B = *head, T = head; B; T = &B->next, B = B->next)
156
157 ; /* find the tail */
158 *T = A;
159 }
160
161 void
162 aclParseAccessLine(const char *directive, ConfigParser &, acl_access **treep)
163 {
164 /* first expect either 'allow' or 'deny' */
165 const char *t = ConfigParser::NextToken();
166
167 if (!t) {
168 debugs(28, DBG_CRITICAL, "aclParseAccessLine: " << cfg_filename << " line " << config_lineno << ": " << config_input_line);
169 debugs(28, DBG_CRITICAL, "aclParseAccessLine: missing 'allow' or 'deny'.");
170 return;
171 }
172
173 allow_t action = ACCESS_DUNNO;
174 if (!strcmp(t, "allow"))
175 action = ACCESS_ALLOWED;
176 else if (!strcmp(t, "deny"))
177 action = ACCESS_DENIED;
178 else {
179 debugs(28, DBG_CRITICAL, "aclParseAccessLine: " << cfg_filename << " line " << config_lineno << ": " << config_input_line);
180 debugs(28, DBG_CRITICAL, "aclParseAccessLine: expecting 'allow' or 'deny', got '" << t << "'.");
181 return;
182 }
183
184 const int ruleId = ((treep && *treep) ? (*treep)->childrenCount() : 0) + 1;
185 MemBuf ctxBuf;
186 ctxBuf.init();
187 ctxBuf.Printf("%s#%d", directive, ruleId);
188 ctxBuf.terminate();
189
190 Acl::AndNode *rule = new Acl::AndNode;
191 rule->context(ctxBuf.content(), config_input_line);
192 rule->lineParse();
193 if (rule->empty()) {
194 debugs(28, DBG_CRITICAL, "aclParseAccessLine: " << cfg_filename << " line " << config_lineno << ": " << config_input_line);
195 debugs(28, DBG_CRITICAL, "aclParseAccessLine: Access line contains no ACL's, skipping");
196 delete rule;
197 return;
198 }
199
200 /* Append to the end of this list */
201
202 assert(treep);
203 if (!*treep) {
204 *treep = new Acl::Tree;
205 (*treep)->context(directive, config_input_line);
206 }
207
208 (*treep)->add(rule, action);
209
210 /* We lock _acl_access structures in ACLChecklist::matchNonBlocking() */
211 }
212
213 // aclParseAclList does not expect or set actions (cf. aclParseAccessLine)
214 void
215 aclParseAclList(ConfigParser &, Acl::Tree **treep, const char *label)
216 {
217 // accomodate callers unable to convert their ACL list context to string
218 if (!label)
219 label = "...";
220
221 MemBuf ctxLine;
222 ctxLine.init();
223 ctxLine.Printf("(%s %s line)", cfg_directive, label);
224 ctxLine.terminate();
225
226 Acl::AndNode *rule = new Acl::AndNode;
227 rule->context(ctxLine.content(), config_input_line);
228 rule->lineParse();
229
230 MemBuf ctxTree;
231 ctxTree.init();
232 ctxTree.Printf("%s %s", cfg_directive, label);
233 ctxTree.terminate();
234
235 // We want a cbdata-protected Tree (despite giving it only one child node).
236 Acl::Tree *tree = new Acl::Tree;
237 tree->add(rule);
238 tree->context(ctxTree.content(), config_input_line);
239
240 assert(treep);
241 assert(!*treep);
242 *treep = tree;
243 }
244
245 /*********************/
246 /* Destroy functions */
247 /*********************/
248
249 void
250 aclDestroyAcls(ACL ** head)
251 {
252 ACL *next = NULL;
253
254 debugs(28, 8, "aclDestroyACLs: invoked");
255
256 for (ACL *a = *head; a; a = next) {
257 next = a->next;
258 delete a;
259 }
260
261 *head = NULL;
262 }
263
264 void
265 aclDestroyAclList(ACLList **list)
266 {
267 debugs(28, 8, "aclDestroyAclList: invoked");
268 assert(list);
269 cbdataFree(*list);
270 }
271
272 void
273 aclDestroyAccessList(acl_access ** list)
274 {
275 assert(list);
276 if (*list)
277 debugs(28, 3, "destroying: " << *list << ' ' << (*list)->name);
278 cbdataFree(*list);
279 }
280
281 /* maex@space.net (06.09.1996)
282 * destroy an AclDenyInfoList */
283
284 void
285 aclDestroyDenyInfoList(AclDenyInfoList ** list)
286 {
287 AclDenyInfoList *a = NULL;
288 AclDenyInfoList *a_next = NULL;
289 AclNameList *l = NULL;
290 AclNameList *l_next = NULL;
291
292 debugs(28, 8, "aclDestroyDenyInfoList: invoked");
293
294 for (a = *list; a; a = a_next) {
295 for (l = a->acl_list; l; l = l_next) {
296 l_next = l->next;
297 safe_free(l);
298 }
299
300 a_next = a->next;
301 xfree(a->err_page_name);
302 memFree(a, MEM_ACL_DENY_INFO_LIST);
303 }
304
305 *list = NULL;
306 }