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