Squid Web Cache master
Loading...
Searching...
No Matches
AccessCheck.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2025 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#include "squid.h"
10#include "AccessLogEntry.h"
11#include "acl/FilledChecklist.h"
14#include "adaptation/Config.h"
16#include "adaptation/Service.h"
18#include "base/AsyncJobCalls.h"
19#include "base/TextException.h"
20#include "ConfigParser.h"
21#include "globals.h"
22#include "HttpReply.h"
23#include "HttpRequest.h"
24
26cbdata_type Adaptation::AccessCheck::CBDATA_AccessCheck = CBDATA_UNKNOWN;
29bool
31 HttpRequest *req, HttpReply *rep,
32 const AccessLogEntryPointer &al, Adaptation::Initiator *initiator)
33{
34
35 if (Config::Enabled) {
36 // the new check will call the callback and delete self, eventually
37 AsyncJob::Start(new AccessCheck( // we do not store so not a CbcPointer
38 ServiceFilter(method, vp, req, rep, al), initiator));
39 return true;
40 }
41
42 debugs(83, 3, "adaptation off, skipping");
43 return false;
44}
45
47 Adaptation::Initiator *initiator):
48 AsyncJob("AccessCheck"), filter(aFilter),
49 theInitiator(initiator)
50{
51#if ICAP_CLIENT
53 if (h != nullptr)
54 h->start("ACL");
55#endif
56
57 debugs(93, 5, "AccessCheck constructed for " << filter);
58}
59
61{
62#if ICAP_CLIENT
63 Adaptation::Icap::History::Pointer h = filter.request->icapHistory();
64 if (h != nullptr)
65 h->stop("ACL");
66#endif
67}
68
69void
71{
73
74 if (!usedDynamicRules())
75 check();
76}
77
79bool
81{
82 Adaptation::History::Pointer ah = filter.request->adaptHistory();
83 if (!ah)
84 return false; // dynamic rules not enabled or not triggered
85
86 const auto services = ah->extractCurrentServices(filter); // updates history
87 if (services.empty()) {
88 debugs(85, 5, "no service-proposed rules for " << filter);
89 return false;
90 }
91
92 debugs(85,3, "using stored service-proposed rules: " << services);
93
94 ServiceGroupPointer g = new DynamicServiceChain(services, filter);
95 callBack(g);
96 Must(done());
97 return true;
98}
99
101void
103{
104 debugs(93, 4, "start checking");
105
106 typedef AccessRules::iterator ARI;
107 for (ARI i = AllRules().begin(); i != AllRules().end(); ++i) {
108 AccessRule *r = *i;
109 if (isCandidate(*r)) {
110 debugs(93, 5, "check: rule '" << r->id << "' is a candidate");
111 candidates.push_back(r->id);
112 }
113 }
114
115 checkCandidates();
116}
117
118// XXX: Here and everywhere we call FindRule(topCandidate()):
119// Once we identified the candidate, we should not just ignore it
120// if reconfigure changes rules. We should either lock the rule to
121// prevent reconfigure from stealing it or restart the check with
122// new rules. Throwing an exception may also be appropriate.
123void
125{
126 debugs(93, 4, "has " << candidates.size() << " rules");
127
128 while (!candidates.empty()) {
129 if (AccessRule *r = FindRule(topCandidate())) {
130 /* BUG 2526: what to do when r->acl is empty?? */
131 auto acl_checklist = ACLFilledChecklist::Make(r->acl, filter.request);
132 acl_checklist->updateAle(filter.al);
133 acl_checklist->updateReply(filter.reply);
134 acl_checklist->syncAle(filter.request, nullptr);
135 ACLFilledChecklist::NonBlockingCheck(std::move(acl_checklist), AccessCheckCallbackWrapper, this);
136 return;
137 }
138
139 candidates.erase(candidates.begin()); // the rule apparently went away (reconfigure)
140 }
141
142 debugs(93, 4, "NO candidates left");
143 callBack(nullptr);
144 Must(done());
145}
146
147void
149{
150 debugs(93, 8, "callback answer=" << answer);
151 AccessCheck *ac = (AccessCheck*)data;
152
153 /* TODO: AYJ 2008-06-12: If answer == ACCESS_AUTH_REQUIRED
154 * we should be kicking off an authentication before continuing
155 * with this request. see bug 2400 for details.
156 */
157
158 // convert to async call to get async call protections and features
160 AsyncCall::Pointer call =
161 asyncCall(93,7, "Adaptation::AccessCheck::noteAnswer",
162 MyDialer(ac, &Adaptation::AccessCheck::noteAnswer, answer));
163 ScheduleCallHere(call);
164
165}
166
168void
170{
171 Must(!candidates.empty()); // the candidate we were checking must be there
172 debugs(93,5, topCandidate() << " answer=" << answer);
173
174 if (answer.allowed()) { // the rule matched
175 ServiceGroupPointer g = topGroup();
176 if (g != nullptr) { // the corresponding group found
177 callBack(g);
178 Must(done());
179 return;
180 }
181 }
182
183 // no match or the group disappeared during reconfiguration
184 candidates.erase(candidates.begin());
185 checkCandidates();
186}
187
190void
192{
193 debugs(93,3, g);
194 CallJobHere1(93, 5, theInitiator, Adaptation::Initiator,
195 noteAdaptationAclCheckDone, g);
196 mustStop("done"); // called back or will never be able to call back
197}
198
201{
203 if (candidates.size()) {
204 if (AccessRule *r = FindRule(topCandidate())) {
205 g = FindGroup(r->groupId);
206 debugs(93,5, "top group for " << r->id << " is " << g);
207 } else {
208 debugs(93,5, "no rule for " << topCandidate());
209 }
210 } else {
211 debugs(93,5, "no candidates"); // should not happen
212 }
213
214 return g;
215}
216
219bool
221{
222 debugs(93,7, "checking candidacy of " << r.id << ", group " <<
223 r.groupId);
224
226
227 if (!g) {
228 debugs(93,7, "lost " << r.groupId << " group in rule" << r.id);
229 return false;
230 }
231
232 const bool wants = g->wants(filter);
233 debugs(93,7, r.groupId << (wants ? " wants" : " ignores"));
234 return wants;
235}
236
#define ScheduleCallHere(call)
Definition AsyncCall.h:166
RefCount< AsyncCallT< Dialer > > asyncCall(int aDebugSection, int aDebugLevel, const char *aName, const Dialer &aDialer)
Definition AsyncCall.h:156
#define CallJobHere1(debugSection, debugLevel, job, Class, method, arg1)
#define Must(condition)
static const cbdata_type CBDATA_UNKNOWN
Definition cbdata.h:196
int cbdata_type
Definition cbdata.h:195
static MakingPointer Make(const acl_access *a, HttpRequest *r)
static void NonBlockingCheck(MakingPointer &&p, ACLCB *cb, void *data)
bool allowed() const
Definition Acl.h:82
const ServiceFilter filter
Definition AccessCheck.h:47
ServiceGroupPointer topGroup() const
void callBack(const ServiceGroupPointer &g)
void noteAnswer(Acl::Answer answer)
process the results of the ACL check
bool usedDynamicRules()
not done until mustStop
void check()
Walk the access rules list to find rules with applicable service groups.
bool isCandidate(AccessRule &r)
void start() override
called by AsyncStart; do not call directly
static bool Start(Method method, VectPoint vp, HttpRequest *req, HttpReply *, const AccessLogEntryPointer &, Adaptation::Initiator *)
AccessCheck(const ServiceFilter &aFilter, Adaptation::Initiator *)
static void AccessCheckCallbackWrapper(Acl::Answer, void *)
static bool Enabled
Definition Config.h:42
a temporary service chain built upon another service request
DynamicGroupCfg extractCurrentServices(const ServiceFilter &)
returns and forgets planned/future services matching the given filter
Definition History.cc:165
information used to search for adaptation services
HttpRequest * request
HTTP request being adapted or cause; may be nil.
bool wants(const ServiceFilter &filter) const
static void Start(const Pointer &job)
Definition AsyncJob.cc:37
virtual void start()
called by AsyncStart; do not call directly
Definition AsyncJob.cc:59
Adaptation::Icap::History::Pointer icapHistory() const
Returns possibly nil history, creating it if icap logging is enabled.
#define debugs(SECTION, LEVEL, CONTENT)
Definition Stream.h:192
AccessRules & AllRules()
Definition AccessRule.cc:61
ServiceGroupPointer FindGroup(const ServiceGroup::Id &id)
AccessRule * FindRule(const AccessRule::Id &id)
Definition AccessRule.cc:69