AccessCheck.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 #include "squid.h"
10 #include "AccessLogEntry.h"
11 #include "acl/FilledChecklist.h"
12 #include "adaptation/AccessCheck.h"
13 #include "adaptation/AccessRule.h"
14 #include "adaptation/Config.h"
15 #include "adaptation/Initiator.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 
26 cbdata_type Adaptation::AccessCheck::CBDATA_AccessCheck = CBDATA_UNKNOWN;
29 bool
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 
69 void
71 {
73 
74  if (!usedDynamicRules())
75  check();
76 }
77 
79 bool
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 
101 void
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.
123 void
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 
147 void
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 
168 void
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 
190 void
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 
219 bool
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 
void start() override
called by AsyncStart; do not call directly
Definition: AccessCheck.cc:70
DynamicGroupCfg extractCurrentServices(const ServiceFilter &)
returns and forgets planned/future services matching the given filter
Definition: History.cc:165
void check()
Walk the access rules list to find rules with applicable service groups.
Definition: AccessCheck.cc:102
static bool Enabled
Definition: Config.h:42
a temporary service chain built upon another service request
information used to search for adaptation services
Definition: ServiceFilter.h:22
ServiceGroupPointer topGroup() const
Definition: AccessCheck.cc:200
AccessCheck(const ServiceFilter &aFilter, Adaptation::Initiator *)
Definition: AccessCheck.cc:46
#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
HttpRequest * request
HTTP request being adapted or cause; may be nil.
Definition: ServiceFilter.h:34
void callBack(const ServiceGroupPointer &g)
Definition: AccessCheck.cc:191
static MakingPointer Make(const acl_access *a, HttpRequest *r)
static const cbdata_type CBDATA_UNKNOWN
Definition: cbdata.h:196
static void AccessCheckCallbackWrapper(Acl::Answer, void *)
Definition: AccessCheck.cc:148
bool wants(const ServiceFilter &filter) const
int cbdata_type
Definition: cbdata.h:195
const ServiceFilter filter
Definition: AccessCheck.h:47
static void NonBlockingCheck(MakingPointer &&p, ACLCB *cb, void *data)
void noteAnswer(Acl::Answer answer)
process the results of the ACL check
Definition: AccessCheck.cc:169
Adaptation::Icap::History::Pointer icapHistory() const
Returns possibly nil history, creating it if icap logging is enabled.
Definition: HttpRequest.cc:389
bool usedDynamicRules()
not done until mustStop
Definition: AccessCheck.cc:80
AccessRules & AllRules()
Definition: AccessRule.cc:61
bool isCandidate(AccessRule &r)
Definition: AccessCheck.cc:220
AccessRule * FindRule(const AccessRule::Id &id)
Definition: AccessRule.cc:69
bool allowed() const
Definition: Acl.h:82
ServiceGroupPointer FindGroup(const ServiceGroup::Id &id)
virtual void start()
called by AsyncStart; do not call directly
Definition: AsyncJob.cc:59
#define Must(condition)
Definition: TextException.h:75
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:192
static bool Start(Method method, VectPoint vp, HttpRequest *req, HttpReply *, const AccessLogEntryPointer &, Adaptation::Initiator *)
Definition: AccessCheck.cc:30
static void Start(const Pointer &job)
Definition: AsyncJob.cc:37
#define CallJobHere1(debugSection, debugLevel, job, Class, method, arg1)
Definition: AsyncJobCalls.h:64

 

Introduction

Documentation

Support

Miscellaneous