Gadgets.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
3 *
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.
7 */
8
9/*
10 * DEBUG: section 28 Access Control
11 *
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
16 * of squid.
17 */
18
19#include "squid.h"
20#include "acl/Acl.h"
21#include "acl/AclDenyInfoList.h"
22#include "acl/Checklist.h"
23#include "acl/Gadgets.h"
24#include "acl/Strategised.h"
25#include "acl/Tree.h"
26#include "cache_cf.h"
27#include "ConfigParser.h"
28#include "errorpage.h"
29#include "globals.h"
30#include "HttpRequest.h"
31#include "src/sbuf/Stream.h"
32
33#include <set>
34#include <algorithm>
35
36typedef std::set<ACL*> AclSet;
38static AclSet *RegisteredAcls; // TODO: Remove when ACLs are refcounted
39
40/* does name lookup, returns page_id */
42aclGetDenyInfoPage(AclDenyInfoList ** head, const char *name, int redirect_allowed)
43{
44 if (!name) {
45 debugs(28, 3, "ERR_NONE due to a NULL name");
46 return ERR_NONE;
47 }
48
49 AclDenyInfoList *A = nullptr;
50
51 debugs(28, 8, "got called for " << name);
52
53 for (A = *head; A; A = A->next) {
54 if (!redirect_allowed && strchr(A->err_page_name, ':') ) {
55 debugs(28, 8, "Skip '" << A->err_page_name << "' 30x redirects not allowed as response here.");
56 continue;
57 }
58
59 for (const auto &aclName: A->acl_list) {
60 if (aclName.cmp(name) == 0) {
61 debugs(28, 8, "match on " << name);
62 return A->err_page_id;
63 }
64 }
65 }
66
67 debugs(28, 8, "aclGetDenyInfoPage: no match");
68 return ERR_NONE;
69}
70
71/* does name lookup, returns if it is a proxy_auth acl */
72int
73aclIsProxyAuth(const char *name)
74{
75 if (!name) {
76 debugs(28, 3, "false due to a NULL name");
77 return false;
78 }
79
80 debugs(28, 5, "aclIsProxyAuth: called for " << name);
81
82 ACL *a;
83
84 if ((a = ACL::FindByName(name))) {
85 debugs(28, 5, "aclIsProxyAuth: returning " << a->isProxyAuth());
86 return a->isProxyAuth();
87 }
88
89 debugs(28, 3, "aclIsProxyAuth: WARNING, called for nonexistent ACL");
90 return false;
91}
92
93/* maex@space.net (05.09.96)
94 * get the info for redirecting "access denied" to info pages
95 * TODO (probably ;-)
96 * currently there is no optimization for
97 * - more than one deny_info line with the same url
98 * - a check, whether the given acl really is defined
99 * - a check, whether an acl is added more than once for the same url
100 */
101
102void
104{
105 char *t = nullptr;
107 AclDenyInfoList **T;
108
109 /* first expect a page name */
110
111 if ((t = ConfigParser::NextToken()) == nullptr) {
112 debugs(28, DBG_CRITICAL, "aclParseDenyInfoLine: " << cfg_filename << " line " << config_lineno << ": " << config_input_line);
113 debugs(28, DBG_CRITICAL, "ERROR: aclParseDenyInfoLine: missing 'error page' parameter.");
114 return;
115 }
116
117 const auto A = new AclDenyInfoList(t, ConfigParser::CurrentLocation());
118
119 /* next expect a list of ACL names */
120 while ((t = ConfigParser::NextToken())) {
121 A->acl_list.emplace_back(t);
122 }
123
124 if (A->acl_list.empty()) {
125 debugs(28, DBG_CRITICAL, "aclParseDenyInfoLine: " << cfg_filename << " line " << config_lineno << ": " << config_input_line);
126 debugs(28, DBG_CRITICAL, "aclParseDenyInfoLine: deny_info line contains no ACL's, skipping");
127 delete A;
128 return;
129 }
130
131 for (B = *head, T = head; B; T = &B->next, B = B->next)
132
133 ; /* find the tail */
134 *T = A;
135}
136
137void
138aclParseAccessLine(const char *directive, ConfigParser &, acl_access **treep)
139{
140 /* first expect either 'allow' or 'deny' */
141 const char *t = ConfigParser::NextToken();
142
143 if (!t) {
144 debugs(28, DBG_CRITICAL, "aclParseAccessLine: " << cfg_filename << " line " << config_lineno << ": " << config_input_line);
145 debugs(28, DBG_CRITICAL, "ERROR: aclParseAccessLine: missing 'allow' or 'deny'.");
146 return;
147 }
148
150 if (!strcmp(t, "allow"))
152 else if (!strcmp(t, "deny"))
154 else {
155 debugs(28, DBG_CRITICAL, "aclParseAccessLine: " << cfg_filename << " line " << config_lineno << ": " << config_input_line);
156 debugs(28, DBG_CRITICAL, "aclParseAccessLine: expecting 'allow' or 'deny', got '" << t << "'.");
157 return;
158 }
159
160 const int ruleId = ((treep && *treep) ? (*treep)->childrenCount() : 0) + 1;
161 MemBuf ctxBuf;
162 ctxBuf.init();
163 ctxBuf.appendf("%s#%d", directive, ruleId);
164 ctxBuf.terminate();
165
166 Acl::AndNode *rule = new Acl::AndNode;
167 rule->context(ctxBuf.content(), config_input_line);
168 rule->lineParse();
169 if (rule->empty()) {
170 debugs(28, DBG_CRITICAL, "aclParseAccessLine: " << cfg_filename << " line " << config_lineno << ": " << config_input_line);
171 debugs(28, DBG_CRITICAL, "aclParseAccessLine: Access line contains no ACL's, skipping");
172 delete rule;
173 return;
174 }
175
176 /* Append to the end of this list */
177
178 assert(treep);
179 if (!*treep) {
180 *treep = new Acl::Tree;
181 (*treep)->context(directive, config_input_line);
182 }
183
184 (*treep)->add(rule, action);
185
186 /* We lock _acl_access structures in ACLChecklist::matchNonBlocking() */
187}
188
189// aclParseAclList does not expect or set actions (cf. aclParseAccessLine)
190size_t
191aclParseAclList(ConfigParser &, Acl::Tree **treep, const char *label)
192{
193 // accommodate callers unable to convert their ACL list context to string
194 if (!label)
195 label = "...";
196
197 MemBuf ctxLine;
198 ctxLine.init();
199 ctxLine.appendf("(%s %s line)", cfg_directive, label);
200 ctxLine.terminate();
201
202 Acl::AndNode *rule = new Acl::AndNode;
203 rule->context(ctxLine.content(), config_input_line);
204 const auto aclCount = rule->lineParse();
205
206 MemBuf ctxTree;
207 ctxTree.init();
208 ctxTree.appendf("%s %s", cfg_directive, label);
209 ctxTree.terminate();
210
211 // We want a cbdata-protected Tree (despite giving it only one child node).
212 Acl::Tree *tree = new Acl::Tree;
213 tree->add(rule);
214 tree->context(ctxTree.content(), config_input_line);
215
216 assert(treep);
217 assert(!*treep);
218 *treep = tree;
219
220 return aclCount;
221}
222
223void
225{
226 if (!acl->registered) {
227 if (!RegisteredAcls)
229 RegisteredAcls->insert(acl);
230 acl->registered = true;
231 }
232}
233
235static
236void
238{
239 if (acl->registered) {
240 if (RegisteredAcls)
241 RegisteredAcls->erase(acl);
242 acl->registered = false;
243 }
244}
245
246/*********************/
247/* Destroy functions */
248/*********************/
249
251void
253{
254 *head = nullptr; // Config.aclList
255 if (AclSet *acls = RegisteredAcls) {
256 debugs(28, 8, "deleting all " << acls->size() << " ACLs");
257 while (!acls->empty()) {
258 ACL *acl = *acls->begin();
259 // We use centralized deletion (this function) so ~ACL should not
260 // delete other ACLs, but we still deregister first to prevent any
261 // accesses to the being-deleted ACL via RegisteredAcls.
262 assert(acl->registered); // make sure we are making progress
263 aclDeregister(acl);
264 delete acl;
265 }
266 }
267}
268
269void
271{
272 debugs(28, 8, "aclDestroyAclList: invoked");
273 assert(list);
274 delete *list;
275 *list = nullptr;
276}
277
278void
280{
281 assert(list);
282 if (*list)
283 debugs(28, 3, "destroying: " << *list << ' ' << (*list)->name);
284 delete *list;
285 *list = nullptr;
286}
287
288/* maex@space.net (06.09.1996)
289 * destroy an AclDenyInfoList */
290
291void
293{
294 AclDenyInfoList *a = nullptr;
295 AclDenyInfoList *a_next = nullptr;
296
297 debugs(28, 8, "aclDestroyDenyInfoList: invoked");
298
299 for (a = *list; a; a = a_next) {
300 a_next = a->next;
301 delete a;
302 }
303
304 *list = nullptr;
305}
306
void aclParseAccessLine(const char *directive, ConfigParser &, acl_access **treep)
Definition: Gadgets.cc:138
static void aclDeregister(ACL *acl)
remove registered acl from the centralized deletion set
Definition: Gadgets.cc:237
size_t aclParseAclList(ConfigParser &, Acl::Tree **treep, const char *label)
Definition: Gadgets.cc:191
std::set< ACL * > AclSet
Definition: Gadgets.cc:36
static AclSet * RegisteredAcls
Accumulates all ACLs to facilitate their clean deletion despite reuse.
Definition: Gadgets.cc:38
#define acl_access
Definition: forward.h:45
#define ACLList
Definition: forward.h:46
squidaio_request_t * head
Definition: aiops.cc:127
#define assert(EX)
Definition: assert.h:17
const char * cfg_directive
During parsing, the name of the current squid.conf directive being parsed.
Definition: cache_cf.cc:270
char config_input_line[BUFSIZ]
Definition: cache_cf.cc:273
const char * cfg_filename
Definition: cache_cf.cc:271
int config_lineno
Definition: cache_cf.cc:272
Definition: Acl.h:46
void context(const char *name, const char *configuration)
sets user-specified ACL name and squid.conf context
Definition: Acl.cc:180
static ACL * FindByName(const char *name)
Definition: Acl.cc:118
virtual bool isProxyAuth() const
Definition: Acl.cc:309
bool registered
added to the global list of ACLs via aclRegister()
Definition: Acl.h:90
deny_info representation. Currently a POD.
AclDenyInfoList * next
bool empty() const override
Definition: InnerNode.cc:29
size_t lineParse()
Definition: InnerNode.cc:44
Definition: Tree.h:21
void add(ACL *rule, const Answer &action)
appends and takes control over the rule with a given action
Definition: Tree.cc:44
static SBuf CurrentLocation()
static char * NextToken()
Definition: MemBuf.h:24
void init(mb_size_t szInit, mb_size_t szMax)
Definition: MemBuf.cc:93
char * content()
start of the added data
Definition: MemBuf.h:41
void terminate()
Definition: MemBuf.cc:241
void appendf(const char *fmt,...) PRINTF_FORMAT_ARG2
Append operation with printf-style arguments.
Definition: Packable.h:61
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:194
#define DBG_CRITICAL
Definition: Stream.h:37
err_type
Definition: forward.h:14
@ ERR_NONE
Definition: forward.h:15
void aclDestroyAccessList(acl_access **list)
Definition: Gadgets.cc:279
void aclDestroyAcls(ACL **head)
called to delete ALL Acls.
Definition: Gadgets.cc:252
void aclDestroyDenyInfoList(AclDenyInfoList **list)
Definition: Gadgets.cc:292
err_type aclGetDenyInfoPage(AclDenyInfoList **head, const char *name, int redirect_allowed)
Definition: Gadgets.cc:42
int aclIsProxyAuth(const char *name)
Definition: Gadgets.cc:73
void aclDestroyAclList(ACLList **list)
Definition: Gadgets.cc:270
void aclRegister(ACL *acl)
Definition: Gadgets.cc:224
void aclParseDenyInfoLine(AclDenyInfoList **head)
Definition: Gadgets.cc:103
@ ACCESS_DENIED
Definition: Acl.h:115
@ ACCESS_ALLOWED
Definition: Acl.h:116
@ ACCESS_DUNNO
Definition: Acl.h:117
static uint32 A
Definition: md4.c:43
static uint32 B
Definition: md4.c:43
static bool action(int fd, size_t metasize, const char *fn, const char *url, const SquidMetaList &meta)
Definition: purge.cc:315

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors