]>
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 | |
eac759e1 | 167 | private: |
d5cbce97 AR |
168 | /// Calls non-blocking check callback with the answer and destroys self. |
169 | void checkCallback(allow_t answer); | |
170 | ||
6f58d7d7 AR |
171 | void matchAndFinish(); |
172 | ||
173 | void changeState(AsyncState *); | |
174 | AsyncState *asyncState() const; | |
b50e327b | 175 | |
351fe86d | 176 | public: |
6f58d7d7 | 177 | const Acl::Tree *accessList; |
62e76326 | 178 | |
2efeb0b7 | 179 | ACLCB *callback; |
4fb35c3c | 180 | void *callback_data; |
62e76326 | 181 | |
6f58d7d7 AR |
182 | /// Resumes non-blocking check started by nonBlockingCheck() and |
183 | /// suspended until some async operation updated Squid state. | |
184 | void resumeNonBlockingCheck(AsyncState *state); | |
2efeb0b7 | 185 | |
b50e327b | 186 | private: /* internal methods */ |
6f58d7d7 | 187 | /// Position of a child node within an ACL tree. |
e936c41c AR |
188 | class Breadcrumb |
189 | { | |
6f58d7d7 AR |
190 | public: |
191 | Breadcrumb(): parent(NULL) {} | |
192 | Breadcrumb(const Acl::InnerNode *aParent, Acl::Nodes::const_iterator aPos): parent(aParent), position(aPos) {} | |
193 | bool operator ==(const Breadcrumb &b) const { return parent == b.parent && (!parent || position == b.position); } | |
194 | bool operator !=(const Breadcrumb &b) const { return !this->operator ==(b); } | |
195 | void clear() { parent = NULL; } | |
196 | const Acl::InnerNode *parent; ///< intermediate node in the ACL tree | |
197 | Acl::Nodes::const_iterator position; ///< child position inside parent | |
198 | }; | |
199 | ||
e0f7153c AR |
200 | /// possible outcomes when trying to match a single ACL node in a list |
201 | typedef enum { nmrMatch, nmrMismatch, nmrFinished, nmrNeedsAsync } | |
c0f81932 | 202 | NodeMatchingResult; |
e0f7153c AR |
203 | |
204 | /// prepare for checking ACLs; called once per check | |
205 | void preCheck(const char *what); | |
6f58d7d7 AR |
206 | bool prepNonBlocking(); |
207 | void completeNonBlocking(); | |
208 | void calcImplicitAnswer(); | |
b50e327b | 209 | |
6f58d7d7 | 210 | bool asyncCaller_; ///< whether the caller supports async/slow ACLs |
7c469a68 | 211 | bool occupied_; ///< whether a check (fast or non-blocking) is in progress |
8000a965 | 212 | bool finished_; |
213 | allow_t allow_; | |
351fe86d | 214 | |
6f58d7d7 AR |
215 | enum AsyncStage { asyncNone, asyncStarting, asyncRunning, asyncFailed }; |
216 | AsyncStage asyncStage_; | |
217 | AsyncState *state_; | |
218 | Breadcrumb matchLoc_; ///< location of the node running matches() now | |
219 | Breadcrumb asyncLoc_; ///< currentNode_ that called goAsync() | |
1707b9ad | 220 | unsigned asyncLoopDepth_; ///< how many times the current async state has resumed |
ab321f4b | 221 | |
315b856d | 222 | bool callerGone(); |
6f58d7d7 AR |
223 | |
224 | /// suspended (due to an async lookup) matches() in the ACL tree | |
225 | std::stack<Breadcrumb> matchPath; | |
640fe8fb CT |
226 | /// the list of actions which must ignored during acl checks |
227 | std::vector<allow_t> bannedActions_; | |
4fb35c3c | 228 | }; |
229 | ||
230 | #endif /* SQUID_ACLCHECKLIST_H */ | |
f53969cc | 231 |