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