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