]> git.ipfire.org Git - thirdparty/squid.git/blob - src/acl/Checklist.h
Merge from trunk
[thirdparty/squid.git] / src / acl / Checklist.h
1 /*
2 *
3 * SQUID Web Proxy Cache http://www.squid-cache.org/
4 * ----------------------------------------------------------
5 *
6 * Squid is the result of efforts by numerous individuals from
7 * the Internet community; see the CONTRIBUTORS file for full
8 * details. Many organizations have provided support for Squid's
9 * development; see the SPONSORS file for full details. Squid is
10 * Copyrighted (C) 2001 by the Regents of the University of
11 * California; see the COPYRIGHT file for full details. Squid
12 * incorporates software developed and/or copyrighted by other
13 * sources; see the CREDITS file for full details.
14 *
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
28 *
29 */
30
31 #ifndef SQUID_ACLCHECKLIST_H
32 #define SQUID_ACLCHECKLIST_H
33
34 #include "acl/InnerNode.h"
35 #include <stack>
36
37 /// ACL checklist callback
38 typedef void ACLCB(allow_t, void *);
39
40 /** \ingroup ACLAPI
41 Base class for maintaining Squid and transaction state for access checks.
42 Provides basic ACL checking methods. Its only child, ACLFilledChecklist,
43 keeps the actual state data. The split is necessary to avoid exposing
44 all ACL-related code to virtually Squid data types. */
45 class ACLChecklist
46 {
47
48 public:
49
50 /**
51 * State class.
52 * This abstract class defines the behaviour of
53 * async lookups - which can vary for different ACL types.
54 * Today, every state object must be a singleton.
55 * See NULLState for an example.
56 *
57 \note *no* state should be stored in the state object,
58 * they are used to change the behaviour of the checklist, not
59 * to hold information. If you need to store information in the
60 * state object, consider subclassing ACLChecklist, converting it
61 * to a composite, or changing the state objects from singletons to
62 * refcounted objects.
63 */
64
65 class AsyncState
66 {
67
68 public:
69 virtual void checkForAsync(ACLChecklist *) const = 0;
70 virtual ~AsyncState() {}
71 };
72
73 class NullState : public AsyncState
74 {
75
76 public:
77 static NullState *Instance();
78 virtual void checkForAsync(ACLChecklist *) const;
79 virtual ~NullState() {}
80
81 private:
82 static NullState _instance;
83 };
84
85 public:
86 ACLChecklist();
87 virtual ~ACLChecklist();
88
89 /**
90 * Start a non-blocking (async) check for a list of allow/deny rules.
91 * Each rule comes with a list of ACLs.
92 *
93 * The callback specified will be called with the result of the check.
94 *
95 * The first rule where all ACLs match wins. If there is such a rule,
96 * the result becomes that rule keyword (ACCESS_ALLOWED or ACCESS_DENIED).
97 *
98 * If there are rules but all ACL lists mismatch, an implicit rule is used.
99 * Its result is the negation of the keyword of the last seen rule.
100 *
101 * Some ACLs may stop the check prematurely by setting an exceptional
102 * check result (e.g., ACCESS_AUTH_REQUIRED) instead of declaring a
103 * match or mismatch.
104 *
105 * If there are no rules to check at all, the result becomes ACCESS_DUNNO.
106 * Calling this method with no rules to check wastes a lot of CPU cycles
107 * and will result in a DBG_CRITICAL debugging message.
108 */
109 void nonBlockingCheck(ACLCB * callback, void *callback_data);
110
111 /**
112 * Perform a blocking (immediate) check for a list of allow/deny rules.
113 * Each rule comes with a list of ACLs.
114 *
115 * The first rule where all ACLs match wins. If there is such a rule,
116 * the result becomes that rule keyword (ACCESS_ALLOWED or ACCESS_DENIED).
117 *
118 * If there are rules but all ACL lists mismatch, an implicit rule is used
119 * Its result is the negation of the keyword of the last seen rule.
120 *
121 * Some ACLs may stop the check prematurely by setting an exceptional
122 * check result (e.g., ACCESS_AUTH_REQUIRED) instead of declaring a
123 * match or mismatch.
124 *
125 * Some ACLs may require an async lookup which is prohibited by this
126 * method. In this case, the exceptional check result of ACCESS_DUNNO is
127 * immediately returned.
128 *
129 * If there are no rules to check at all, the result becomes ACCESS_DUNNO.
130 */
131 allow_t const & fastCheck();
132
133 /**
134 * Perform a blocking (immediate) check whether a list of ACLs matches.
135 * This method is meant to be used with squid.conf ACL-driven options that
136 * lack allow/deny keywords and are tested one ACL list at a time. Whether
137 * the checks for other occurrences of the same option continue after this
138 * call is up to the caller and option semantics.
139 *
140 * If all ACLs match, the result becomes ACCESS_ALLOWED.
141 *
142 * If all ACLs mismatch, the result becomes ACCESS_DENIED.
143 *
144 * Some ACLs may stop the check prematurely by setting an exceptional
145 * check result (e.g., ACCESS_AUTH_REQUIRED) instead of declaring a
146 * match or mismatch.
147 *
148 * Some ACLs may require an async lookup which is prohibited by this
149 * method. In this case, the exceptional check result of ACCESS_DUNNO is
150 * immediately returned.
151 *
152 * If there are no ACLs to check at all, the result becomes ACCESS_ALLOWED.
153 */
154 allow_t const & fastCheck(const Acl::Tree *list);
155
156 /// If slow lookups are allowed, switches into "async in progress" state.
157 /// Otherwise, returns false; the caller is expected to handle the failure.
158 bool goAsync(AsyncState *);
159
160 /// Matches (or resumes matching of) a child node while maintaning
161 /// resumption breadcrumbs if a [grand]child node goes async.
162 bool matchChild(const Acl::InnerNode *parent, Acl::Nodes::const_iterator pos, const ACL *child);
163
164 /// Whether we should continue to match tree nodes or stop/pause.
165 bool keepMatching() const { return !finished() && !asyncInProgress(); }
166
167 /// whether markFinished() was called
168 bool finished() const { return finished_; }
169 /// async call has been started and has not finished (or failed) yet
170 bool asyncInProgress() const { return asyncStage_ != asyncNone; }
171 /// called when no more ACLs should be checked; sets the final answer and
172 /// prints a debugging message explaining the reason for that answer
173 void markFinished(const allow_t &newAnswer, const char *reason);
174
175 const allow_t &currentAnswer() const { return allow_; }
176
177 // XXX: ACLs that need request or reply have to use ACLFilledChecklist and
178 // should do their own checks so that we do not have to povide these two
179 // for ACL::checklistMatches to use
180 virtual bool hasRequest() const = 0;
181 virtual bool hasReply() const = 0;
182
183 private:
184 /// Calls non-blocking check callback with the answer and destroys self.
185 void checkCallback(allow_t answer);
186
187 void matchAndFinish();
188
189 void changeState(AsyncState *);
190 AsyncState *asyncState() const;
191
192 public:
193 const Acl::Tree *accessList;
194
195 ACLCB *callback;
196 void *callback_data;
197
198 /// Resumes non-blocking check started by nonBlockingCheck() and
199 /// suspended until some async operation updated Squid state.
200 void resumeNonBlockingCheck(AsyncState *state);
201
202 private: /* internal methods */
203 /// Position of a child node within an ACL tree.
204 class Breadcrumb
205 {
206 public:
207 Breadcrumb(): parent(NULL) {}
208 Breadcrumb(const Acl::InnerNode *aParent, Acl::Nodes::const_iterator aPos): parent(aParent), position(aPos) {}
209 bool operator ==(const Breadcrumb &b) const { return parent == b.parent && (!parent || position == b.position); }
210 bool operator !=(const Breadcrumb &b) const { return !this->operator ==(b); }
211 void clear() { parent = NULL; }
212 const Acl::InnerNode *parent; ///< intermediate node in the ACL tree
213 Acl::Nodes::const_iterator position; ///< child position inside parent
214 };
215
216 /// possible outcomes when trying to match a single ACL node in a list
217 typedef enum { nmrMatch, nmrMismatch, nmrFinished, nmrNeedsAsync }
218 NodeMatchingResult;
219
220 /// prepare for checking ACLs; called once per check
221 void preCheck(const char *what);
222 bool prepNonBlocking();
223 void completeNonBlocking();
224 void calcImplicitAnswer();
225
226 bool asyncCaller_; ///< whether the caller supports async/slow ACLs
227 bool finished_;
228 allow_t allow_;
229
230 enum AsyncStage { asyncNone, asyncStarting, asyncRunning, asyncFailed };
231 AsyncStage asyncStage_;
232 AsyncState *state_;
233 Breadcrumb matchLoc_; ///< location of the node running matches() now
234 Breadcrumb asyncLoc_; ///< currentNode_ that called goAsync()
235
236 bool callerGone();
237
238 /// suspended (due to an async lookup) matches() in the ACL tree
239 std::stack<Breadcrumb> matchPath;
240 };
241
242 #endif /* SQUID_ACLCHECKLIST_H */