]> git.ipfire.org Git - thirdparty/squid.git/blame - src/adaptation/AccessCheck.cc
Removed squid-old.h
[thirdparty/squid.git] / src / adaptation / AccessCheck.cc
CommitLineData
582c2af2 1#include "squid.h"
127dce76 2#include "acl/FilledChecklist.h"
582c2af2
FC
3#include "adaptation/AccessCheck.h"
4#include "adaptation/AccessRule.h"
5#include "adaptation/Config.h"
79628299 6#include "adaptation/Initiator.h"
62c7f90e
AR
7#include "adaptation/Service.h"
8#include "adaptation/ServiceGroups.h"
582c2af2 9#include "base/AsyncJobCalls.h"
3d93a84d 10#include "base/TextException.h"
582c2af2
FC
11#include "ConfigParser.h"
12#include "globals.h"
13#include "HttpReply.h"
14#include "HttpRequest.h"
15#include "structs.h"
62c7f90e 16
d85b8894 17/** \cond AUTODOCS-IGNORE */
62c7f90e 18cbdata_type Adaptation::AccessCheck::CBDATA_AccessCheck = CBDATA_UNKNOWN;
d85b8894 19/** \endcond */
62c7f90e 20
abd4b611
AR
21bool
22Adaptation::AccessCheck::Start(Method method, VectPoint vp,
79628299 23 HttpRequest *req, HttpReply *rep, Adaptation::Initiator *initiator)
26ac0430 24{
abd4b611
AR
25
26 if (Config::Enabled) {
27 // the new check will call the callback and delete self, eventually
4299f876 28 AsyncJob::Start(new AccessCheck( // we do not store so not a CbcPointer
79628299 29 ServiceFilter(method, vp, req, rep), initiator));
4299f876 30 return true;
26ac0430 31 }
abd4b611
AR
32
33 debugs(83, 3, HERE << "adaptation off, skipping");
34 return false;
35}
36
a22e6cd3 37Adaptation::AccessCheck::AccessCheck(const ServiceFilter &aFilter,
79628299 38 Adaptation::Initiator *initiator):
e1381638 39 AsyncJob("AccessCheck"), filter(aFilter),
79628299 40 theInitiator(initiator),
e1381638 41 acl_checklist(NULL)
62c7f90e 42{
3ff65596 43#if ICAP_CLIENT
a22e6cd3 44 Adaptation::Icap::History::Pointer h = filter.request->icapHistory();
3ff65596
AR
45 if (h != NULL)
46 h->start("ACL");
47#endif
48
a22e6cd3 49 debugs(93, 5, HERE << "AccessCheck constructed for " <<
e1381638 50 methodStr(filter.method) << " " << vectPointStr(filter.point));
62c7f90e
AR
51}
52
53Adaptation::AccessCheck::~AccessCheck()
54{
3ff65596 55#if ICAP_CLIENT
a22e6cd3 56 Adaptation::Icap::History::Pointer h = filter.request->icapHistory();
3ff65596
AR
57 if (h != NULL)
58 h->stop("ACL");
59#endif
62c7f90e
AR
60}
61
dd5d7172 62void
e1381638
AJ
63Adaptation::AccessCheck::start()
64{
65 AsyncJob::start();
53340485
AR
66
67 if (!usedDynamicRules())
68 check();
69}
70
71/// returns true if previous services configured dynamic chaining "rules"
72bool
73Adaptation::AccessCheck::usedDynamicRules()
74{
75 Adaptation::History::Pointer ah = filter.request->adaptHistory();
76 if (!ah)
77 return false; // dynamic rules not enabled or not triggered
78
79 DynamicGroupCfg services;
80 if (!ah->extractFutureServices(services)) { // clears history
81 debugs(85,9, HERE << "no service-proposed rules stored");
82 return false; // earlier service did not plan for the future
83 }
84
85 debugs(85,3, HERE << "using stored service-proposed rules: " << services);
86
87 ServiceGroupPointer g = new DynamicServiceChain(services, filter);
88 callBack(g);
89 Must(done());
90 return true;
dd5d7172
AR
91}
92
a22e6cd3 93/// Walk the access rules list to find rules with applicable service groups
62c7f90e
AR
94void
95Adaptation::AccessCheck::check()
96{
192378eb 97 debugs(93, 4, HERE << "start checking");
62c7f90e
AR
98
99 typedef AccessRules::iterator ARI;
100 for (ARI i = AllRules().begin(); i != AllRules().end(); ++i) {
62c7f90e 101 AccessRule *r = *i;
a22e6cd3
AR
102 if (isCandidate(*r)) {
103 debugs(93, 5, HERE << "check: rule '" << r->id << "' is a candidate");
62c7f90e
AR
104 candidates += r->id;
105 }
106 }
107
108 checkCandidates();
109}
110
111// XXX: Here and everywhere we call FindRule(topCandidate()):
112// Once we identified the candidate, we should not just ignore it
113// if reconfigure changes rules. We should either lock the rule to
114// prevent reconfigure from stealing it or restart the check with
115// new rules. Throwing an exception may also be appropriate.
116void
117Adaptation::AccessCheck::checkCandidates()
118{
192378eb 119 debugs(93, 4, HERE << "has " << candidates.size() << " rules");
62c7f90e
AR
120
121 while (!candidates.empty()) {
122 if (AccessRule *r = FindRule(topCandidate())) {
b50e327b 123 /* BUG 2526: what to do when r->acl is empty?? */
62c7f90e 124 // XXX: we do not have access to conn->rfc931 here.
a22e6cd3
AR
125 acl_checklist = new ACLFilledChecklist(r->acl, filter.request, dash_str);
126 acl_checklist->reply = filter.reply ? HTTPMSGLOCK(filter.reply) : NULL;
62c7f90e
AR
127 acl_checklist->nonBlockingCheck(AccessCheckCallbackWrapper, this);
128 return;
129 }
130
131 candidates.shift(); // the rule apparently went away (reconfigure)
132 }
133
192378eb 134 debugs(93, 4, HERE << "NO candidates left");
a22e6cd3
AR
135 callBack(NULL);
136 Must(done());
62c7f90e
AR
137}
138
139void
2efeb0b7 140Adaptation::AccessCheck::AccessCheckCallbackWrapper(allow_t answer, void *data)
62c7f90e 141{
192378eb 142 debugs(93, 8, HERE << "callback answer=" << answer);
62c7f90e 143 AccessCheck *ac = (AccessCheck*)data;
f9cf4ba9 144
7dfddb79 145 /** \todo AYJ 2008-06-12: If answer == ACCESS_AUTH_REQUIRED
f9cf4ba9
AJ
146 * we should be kicking off an authentication before continuing
147 * with this request. see bug 2400 for details.
148 */
7866ecc9
AR
149
150 // convert to async call to get async call protections and features
2efeb0b7 151 typedef UnaryMemFunT<AccessCheck, allow_t> MyDialer;
7866ecc9
AR
152 AsyncCall::Pointer call =
153 asyncCall(93,7, "Adaptation::AccessCheck::noteAnswer",
2efeb0b7 154 MyDialer(ac, &Adaptation::AccessCheck::noteAnswer, answer));
7866ecc9
AR
155 ScheduleCallHere(call);
156
62c7f90e
AR
157}
158
a22e6cd3 159/// process the results of the ACL check
62c7f90e 160void
2efeb0b7 161Adaptation::AccessCheck::noteAnswer(allow_t answer)
62c7f90e 162{
a22e6cd3
AR
163 Must(!candidates.empty()); // the candidate we were checking must be there
164 debugs(93,5, HERE << topCandidate() << " answer=" << answer);
165
2efeb0b7 166 if (answer == ACCESS_ALLOWED) { // the rule matched
a22e6cd3
AR
167 ServiceGroupPointer g = topGroup();
168 if (g != NULL) { // the corresponding group found
169 callBack(g);
170 Must(done());
171 return;
172 }
62c7f90e
AR
173 }
174
a22e6cd3
AR
175 // no match or the group disappeared during reconfiguration
176 candidates.shift();
177 checkCandidates();
62c7f90e
AR
178}
179
a22e6cd3
AR
180/// call back with a possibly nil group; the job ends here because all failures
181/// at this point are fatal to the access check process
62c7f90e 182void
a22e6cd3 183Adaptation::AccessCheck::callBack(const ServiceGroupPointer &g)
62c7f90e 184{
a22e6cd3 185 debugs(93,3, HERE << g);
79628299
CT
186 CallJobHere1(93, 5, theInitiator, Adaptation::Initiator,
187 noteAdaptationAclCheckDone, g);
a22e6cd3
AR
188 mustStop("done"); // called back or will never be able to call back
189}
62c7f90e 190
a22e6cd3
AR
191Adaptation::ServiceGroupPointer
192Adaptation::AccessCheck::topGroup() const
193{
194 ServiceGroupPointer g;
62c7f90e
AR
195 if (candidates.size()) {
196 if (AccessRule *r = FindRule(topCandidate())) {
a22e6cd3
AR
197 g = FindGroup(r->groupId);
198 debugs(93,5, HERE << "top group for " << r->id << " is " << g);
62c7f90e 199 } else {
a22e6cd3 200 debugs(93,5, HERE << "no rule for " << topCandidate());
62c7f90e 201 }
26ac0430 202 } else {
a22e6cd3 203 debugs(93,5, HERE << "no candidates"); // should not happen
26ac0430 204 }
62c7f90e 205
a22e6cd3 206 return g;
62c7f90e
AR
207}
208
a22e6cd3
AR
209/** Returns true iff the rule's service group will be used after ACL matches.
210 Used to detect rules worth ACl-checking. */
211bool
212Adaptation::AccessCheck::isCandidate(AccessRule &r)
26ac0430 213{
a22e6cd3 214 debugs(93,7,HERE << "checking candidacy of " << r.id << ", group " <<
e1381638 215 r.groupId);
62c7f90e 216
a22e6cd3 217 ServiceGroupPointer g = FindGroup(r.groupId);
62c7f90e
AR
218
219 if (!g) {
a22e6cd3
AR
220 debugs(93,7,HERE << "lost " << r.groupId << " group in rule" << r.id);
221 return false;
62c7f90e
AR
222 }
223
a22e6cd3
AR
224 const bool wants = g->wants(filter);
225 debugs(93,7,HERE << r.groupId << (wants ? " wants" : " ignores"));
226 return wants;
62c7f90e 227}