]>
Commit | Line | Data |
---|---|---|
4fb35c3c | 1 | /* |
bde978a6 | 2 | * Copyright (C) 1996-2015 The Squid Software Foundation and contributors |
4fb35c3c | 3 | * |
bbc27441 AJ |
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. | |
4fb35c3c | 7 | */ |
8 | ||
9 | #ifndef SQUID_ACLCHECKLIST_H | |
10 | #define SQUID_ACLCHECKLIST_H | |
11 | ||
6f58d7d7 AR |
12 | #include "acl/InnerNode.h" |
13 | #include <stack> | |
640fe8fb | 14 | #include <vector> |
4fb35c3c | 15 | |
2efeb0b7 AJ |
16 | /// ACL checklist callback |
17 | typedef void ACLCB(allow_t, void *); | |
18 | ||
351fe86d AR |
19 | /** \ingroup ACLAPI |
20 | Base class for maintaining Squid and transaction state for access checks. | |
f53969cc SM |
21 | Provides basic ACL checking methods. Its only child, ACLFilledChecklist, |
22 | keeps the actual state data. The split is necessary to avoid exposing | |
351fe86d | 23 | all ACL-related code to virtually Squid data types. */ |
62e76326 | 24 | class ACLChecklist |
25 | { | |
26 | ||
27 | public: | |
8000a965 | 28 | |
63be0a78 | 29 | /** |
30 | * State class. | |
8000a965 | 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. | |
63be0a78 | 35 | * |
36 | \note *no* state should be stored in the state object, | |
8000a965 | 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 | ||
62e76326 | 44 | class AsyncState |
45 | { | |
46 | ||
47 | public: | |
48 | virtual void checkForAsync(ACLChecklist *) const = 0; | |
f75662c9 | 49 | virtual ~AsyncState() {} |
8000a965 | 50 | }; |
51 | ||
26ac0430 | 52 | class NullState : public AsyncState |
62e76326 | 53 | { |
54 | ||
55 | public: | |
56 | static NullState *Instance(); | |
57 | virtual void checkForAsync(ACLChecklist *) const; | |
f75662c9 | 58 | virtual ~NullState() {} |
62e76326 | 59 | |
60 | private: | |
61 | static NullState _instance; | |
8000a965 | 62 | }; |
62e76326 | 63 | |
351fe86d | 64 | public: |
4fb35c3c | 65 | ACLChecklist(); |
351fe86d | 66 | virtual ~ACLChecklist(); |
b50e327b AJ |
67 | |
68 | /** | |
e0f7153c AR |
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. | |
b50e327b | 87 | */ |
2efeb0b7 | 88 | void nonBlockingCheck(ACLCB * callback, void *callback_data); |
b50e327b AJ |
89 | |
90 | /** | |
e0f7153c AR |
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). | |
af6a12ee | 96 | * |
e0f7153c AR |
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. | |
b50e327b | 99 | * |
e0f7153c AR |
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. | |
af6a12ee | 103 | * |
e0f7153c AR |
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. | |
b50e327b | 109 | */ |
2efeb0b7 | 110 | allow_t const & fastCheck(); |
b50e327b AJ |
111 | |
112 | /** | |
e0f7153c AR |
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. | |
af6a12ee | 120 | * |
e0f7153c AR |
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. | |
b50e327b | 132 | */ |
6f58d7d7 AR |
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 | ||
e936c41c | 139 | /// Matches (or resumes matching of) a child node while maintaning |
6f58d7d7 AR |
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); | |
b50e327b | 142 | |
6f58d7d7 AR |
143 | /// Whether we should continue to match tree nodes or stop/pause. |
144 | bool keepMatching() const { return !finished() && !asyncInProgress(); } | |
b50e327b | 145 | |
e0f7153c | 146 | /// whether markFinished() was called |
6f58d7d7 AR |
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; } | |
e0f7153c AR |
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); | |
b50e327b | 153 | |
e0f7153c | 154 | const allow_t ¤tAnswer() const { return allow_; } |
b50e327b | 155 | |
640fe8fb CT |
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 | ||
af6a12ee AJ |
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 | |
351fe86d | 163 | // for ACL::checklistMatches to use |
af6a12ee AJ |
164 | virtual bool hasRequest() const = 0; |
165 | virtual bool hasReply() const = 0; | |
b50e327b | 166 | |
3d29e126 AR |
167 | /// change the current ACL list |
168 | /// \return a pointer to the old list, or NULL if that is no longer CBDATA-valid | |
169 | const Acl::Tree *changeAcl(const Acl::Tree *t) { | |
170 | const Acl::Tree *old = accessList; | |
171 | if (t != accessList) { | |
172 | accessList = cbdataReference(t); | |
173 | cbdataReferenceDone(accessList); | |
174 | } | |
175 | return cbdataReferenceValid(old) ? old : nullptr; | |
176 | } | |
177 | ||
eac759e1 | 178 | private: |
d5cbce97 AR |
179 | /// Calls non-blocking check callback with the answer and destroys self. |
180 | void checkCallback(allow_t answer); | |
181 | ||
6f58d7d7 AR |
182 | void matchAndFinish(); |
183 | ||
184 | void changeState(AsyncState *); | |
185 | AsyncState *asyncState() const; | |
b50e327b | 186 | |
6f58d7d7 | 187 | const Acl::Tree *accessList; |
3d29e126 | 188 | public: |
62e76326 | 189 | |
2efeb0b7 | 190 | ACLCB *callback; |
4fb35c3c | 191 | void *callback_data; |
62e76326 | 192 | |
6f58d7d7 AR |
193 | /// Resumes non-blocking check started by nonBlockingCheck() and |
194 | /// suspended until some async operation updated Squid state. | |
195 | void resumeNonBlockingCheck(AsyncState *state); | |
2efeb0b7 | 196 | |
b50e327b | 197 | private: /* internal methods */ |
6f58d7d7 | 198 | /// Position of a child node within an ACL tree. |
e936c41c AR |
199 | class Breadcrumb |
200 | { | |
6f58d7d7 AR |
201 | public: |
202 | Breadcrumb(): parent(NULL) {} | |
203 | Breadcrumb(const Acl::InnerNode *aParent, Acl::Nodes::const_iterator aPos): parent(aParent), position(aPos) {} | |
204 | bool operator ==(const Breadcrumb &b) const { return parent == b.parent && (!parent || position == b.position); } | |
205 | bool operator !=(const Breadcrumb &b) const { return !this->operator ==(b); } | |
206 | void clear() { parent = NULL; } | |
207 | const Acl::InnerNode *parent; ///< intermediate node in the ACL tree | |
208 | Acl::Nodes::const_iterator position; ///< child position inside parent | |
209 | }; | |
210 | ||
e0f7153c AR |
211 | /// possible outcomes when trying to match a single ACL node in a list |
212 | typedef enum { nmrMatch, nmrMismatch, nmrFinished, nmrNeedsAsync } | |
c0f81932 | 213 | NodeMatchingResult; |
e0f7153c AR |
214 | |
215 | /// prepare for checking ACLs; called once per check | |
216 | void preCheck(const char *what); | |
6f58d7d7 AR |
217 | bool prepNonBlocking(); |
218 | void completeNonBlocking(); | |
219 | void calcImplicitAnswer(); | |
b50e327b | 220 | |
6f58d7d7 | 221 | bool asyncCaller_; ///< whether the caller supports async/slow ACLs |
7c469a68 | 222 | bool occupied_; ///< whether a check (fast or non-blocking) is in progress |
8000a965 | 223 | bool finished_; |
224 | allow_t allow_; | |
351fe86d | 225 | |
6f58d7d7 AR |
226 | enum AsyncStage { asyncNone, asyncStarting, asyncRunning, asyncFailed }; |
227 | AsyncStage asyncStage_; | |
228 | AsyncState *state_; | |
229 | Breadcrumb matchLoc_; ///< location of the node running matches() now | |
230 | Breadcrumb asyncLoc_; ///< currentNode_ that called goAsync() | |
1707b9ad | 231 | unsigned asyncLoopDepth_; ///< how many times the current async state has resumed |
ab321f4b | 232 | |
315b856d | 233 | bool callerGone(); |
6f58d7d7 AR |
234 | |
235 | /// suspended (due to an async lookup) matches() in the ACL tree | |
236 | std::stack<Breadcrumb> matchPath; | |
640fe8fb CT |
237 | /// the list of actions which must ignored during acl checks |
238 | std::vector<allow_t> bannedActions_; | |
4fb35c3c | 239 | }; |
240 | ||
241 | #endif /* SQUID_ACLCHECKLIST_H */ | |
f53969cc | 242 |