]> git.ipfire.org Git - thirdparty/squid.git/blame - src/acl/Checklist.h
Simplify appending SBuf to String (#2108)
[thirdparty/squid.git] / src / acl / Checklist.h
CommitLineData
4fb35c3c 1/*
1f7b830e 2 * Copyright (C) 1996-2025 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
ff9d9458
FC
9#ifndef SQUID_SRC_ACL_CHECKLIST_H
10#define SQUID_SRC_ACL_CHECKLIST_H
4fb35c3c 11
922513e5 12#include "acl/Acl.h"
6f58d7d7 13#include "acl/InnerNode.h"
922513e5 14#include "cbdata.h"
25aa6c9a
AR
15
16#include <optional>
6f58d7d7 17#include <stack>
640fe8fb 18#include <vector>
4fb35c3c 19
cb365059
EB
20class HttpRequest;
21
2efeb0b7 22/// ACL checklist callback
329c128c 23typedef void ACLCB(Acl::Answer, void *);
2efeb0b7 24
351fe86d
AR
25/** \ingroup ACLAPI
26 Base class for maintaining Squid and transaction state for access checks.
f53969cc
SM
27 Provides basic ACL checking methods. Its only child, ACLFilledChecklist,
28 keeps the actual state data. The split is necessary to avoid exposing
351fe86d 29 all ACL-related code to virtually Squid data types. */
62e76326 30class ACLChecklist
31{
32
33public:
8000a965 34
5fb6afec 35 /// a function that initiates asynchronous ACL checks; see goAsync()
922513e5 36 using AsyncStarter = void (ACLFilledChecklist &, const Acl::Node &);
62e76326 37
351fe86d 38public:
4fb35c3c 39 ACLChecklist();
351fe86d 40 virtual ~ACLChecklist();
b50e327b 41
b50e327b 42 /**
e0f7153c
AR
43 * Perform a blocking (immediate) check for a list of allow/deny rules.
44 * Each rule comes with a list of ACLs.
45 *
46 * The first rule where all ACLs match wins. If there is such a rule,
47 * the result becomes that rule keyword (ACCESS_ALLOWED or ACCESS_DENIED).
af6a12ee 48 *
e0f7153c
AR
49 * If there are rules but all ACL lists mismatch, an implicit rule is used
50 * Its result is the negation of the keyword of the last seen rule.
b50e327b 51 *
e0f7153c
AR
52 * Some ACLs may stop the check prematurely by setting an exceptional
53 * check result (e.g., ACCESS_AUTH_REQUIRED) instead of declaring a
54 * match or mismatch.
af6a12ee 55 *
e0f7153c
AR
56 * Some ACLs may require an async lookup which is prohibited by this
57 * method. In this case, the exceptional check result of ACCESS_DUNNO is
58 * immediately returned.
59 *
60 * If there are no rules to check at all, the result becomes ACCESS_DUNNO.
b50e327b 61 */
329c128c 62 Acl::Answer const & fastCheck();
b50e327b
AJ
63
64 /**
e0f7153c
AR
65 * Perform a blocking (immediate) check whether a list of ACLs matches.
66 * This method is meant to be used with squid.conf ACL-driven options that
67 * lack allow/deny keywords and are tested one ACL list at a time. Whether
68 * the checks for other occurrences of the same option continue after this
69 * call is up to the caller and option semantics.
70 *
71 * If all ACLs match, the result becomes ACCESS_ALLOWED.
af6a12ee 72 *
e0f7153c
AR
73 * If all ACLs mismatch, the result becomes ACCESS_DENIED.
74 *
75 * Some ACLs may stop the check prematurely by setting an exceptional
76 * check result (e.g., ACCESS_AUTH_REQUIRED) instead of declaring a
77 * match or mismatch.
78 *
79 * Some ACLs may require an async lookup which is prohibited by this
80 * method. In this case, the exceptional check result of ACCESS_DUNNO is
81 * immediately returned.
82 *
83 * If there are no ACLs to check at all, the result becomes ACCESS_ALLOWED.
b50e327b 84 */
0d645414 85 const Acl::Answer &fastCheck(const ACLList *);
6f58d7d7
AR
86
87 /// If slow lookups are allowed, switches into "async in progress" state.
88 /// Otherwise, returns false; the caller is expected to handle the failure.
922513e5 89 bool goAsync(AsyncStarter, const Acl::Node &);
6f58d7d7 90
0d645414 91 /// Matches (or resumes matching of) a child node at pos while maintaining
6f58d7d7 92 /// resumption breadcrumbs if a [grand]child node goes async.
0d645414 93 bool matchChild(const Acl::InnerNode *parent, Acl::Nodes::const_iterator pos);
b50e327b 94
6f58d7d7
AR
95 /// Whether we should continue to match tree nodes or stop/pause.
96 bool keepMatching() const { return !finished() && !asyncInProgress(); }
b50e327b 97
e0f7153c 98 /// whether markFinished() was called
6f58d7d7
AR
99 bool finished() const { return finished_; }
100 /// async call has been started and has not finished (or failed) yet
101 bool asyncInProgress() const { return asyncStage_ != asyncNone; }
e0f7153c
AR
102 /// called when no more ACLs should be checked; sets the final answer and
103 /// prints a debugging message explaining the reason for that answer
329c128c 104 void markFinished(const Acl::Answer &newAnswer, const char *reason);
b50e327b 105
329c128c 106 const Acl::Answer &currentAnswer() const { return answer_; }
b50e327b 107
640fe8fb 108 /// whether the action is banned or not
329c128c 109 bool bannedAction(const Acl::Answer &action) const;
640fe8fb 110 /// add action to the list of banned actions
329c128c 111 void banAction(const Acl::Answer &action);
640fe8fb 112
af6a12ee
AJ
113 // XXX: ACLs that need request or reply have to use ACLFilledChecklist and
114 // should do their own checks so that we do not have to povide these two
351fe86d 115 // for ACL::checklistMatches to use
af6a12ee
AJ
116 virtual bool hasRequest() const = 0;
117 virtual bool hasReply() const = 0;
4ff6370b 118 virtual bool hasAle() const = 0;
cb365059
EB
119 /// assigns uninitialized adapted_request and url ALE components
120 virtual void syncAle(HttpRequest *adaptedRequest, const char *logUri) const = 0;
121 /// warns if there are uninitialized ALE components and fills them
122 virtual void verifyAle() const = 0;
b50e327b 123
3d29e126 124 /// change the current ACL list
0d645414 125 void changeAcl(const acl_access *);
3d29e126 126
25aa6c9a
AR
127 /// remember the name of the last ACL being evaluated
128 void setLastCheckedName(const SBuf &name) { lastCheckedName_ = name; }
129
c56edb4a
EB
130protected:
131 /**
132 * Start a non-blocking (async) check for a list of allow/deny rules.
133 * Each rule comes with a list of ACLs.
134 *
135 * The callback specified will be called with the result of the check.
136 *
137 * The first rule where all ACLs match wins. If there is such a rule,
138 * the result becomes that rule keyword (ACCESS_ALLOWED or ACCESS_DENIED).
139 *
140 * If there are rules but all ACL lists mismatch, an implicit rule is used.
141 * Its result is the negation of the keyword of the last seen rule.
142 *
143 * Some ACLs may stop the check prematurely by setting an exceptional
144 * check result (e.g., ACCESS_AUTH_REQUIRED) instead of declaring a
145 * match or mismatch.
146 *
147 * If there are no rules to check at all, the result becomes ACCESS_DUNNO.
148 * Calling this method with no rules to check wastes a lot of CPU cycles
149 * and will result in a DBG_CRITICAL debugging message.
150 */
151 void nonBlockingCheck(ACLCB * callback, void *callback_data);
152
eac759e1 153private:
d5cbce97 154 /// Calls non-blocking check callback with the answer and destroys self.
96ab90cc
EB
155 /// If abortReason is provided, sets the final answer to ACCESS_DUNNO.
156 void checkCallback(const char *abortReason);
d5cbce97 157
6f58d7d7
AR
158 void matchAndFinish();
159
0d645414
AR
160 /// \copydoc changeAcl()
161 /// \returns old accessList pointer (that may be nil)
162 Acl::TreePointer swapAcl(const acl_access *);
163
164 Acl::TreePointer accessList;
165
3d29e126 166public:
62e76326 167
2efeb0b7 168 ACLCB *callback;
4fb35c3c 169 void *callback_data;
62e76326 170
6f58d7d7
AR
171 /// Resumes non-blocking check started by nonBlockingCheck() and
172 /// suspended until some async operation updated Squid state.
5fb6afec 173 void resumeNonBlockingCheck();
2efeb0b7 174
b50e327b 175private: /* internal methods */
922513e5 176 /// Position of a child node within an Acl::Node tree.
e936c41c
AR
177 class Breadcrumb
178 {
6f58d7d7 179 public:
aee3523a 180 Breadcrumb(): parent(nullptr) {}
6f58d7d7
AR
181 Breadcrumb(const Acl::InnerNode *aParent, Acl::Nodes::const_iterator aPos): parent(aParent), position(aPos) {}
182 bool operator ==(const Breadcrumb &b) const { return parent == b.parent && (!parent || position == b.position); }
183 bool operator !=(const Breadcrumb &b) const { return !this->operator ==(b); }
aee3523a 184 void clear() { parent = nullptr; }
0d645414 185 RefCount<const Acl::InnerNode> parent; ///< intermediate node in the ACL tree
6f58d7d7
AR
186 Acl::Nodes::const_iterator position; ///< child position inside parent
187 };
188
e0f7153c
AR
189 /// possible outcomes when trying to match a single ACL node in a list
190 typedef enum { nmrMatch, nmrMismatch, nmrFinished, nmrNeedsAsync }
c0f81932 191 NodeMatchingResult;
e0f7153c
AR
192
193 /// prepare for checking ACLs; called once per check
194 void preCheck(const char *what);
6f58d7d7
AR
195 bool prepNonBlocking();
196 void completeNonBlocking();
197 void calcImplicitAnswer();
b50e327b 198
6f58d7d7 199 bool asyncCaller_; ///< whether the caller supports async/slow ACLs
7c469a68 200 bool occupied_; ///< whether a check (fast or non-blocking) is in progress
8000a965 201 bool finished_;
329c128c 202 Acl::Answer answer_;
351fe86d 203
6f58d7d7
AR
204 enum AsyncStage { asyncNone, asyncStarting, asyncRunning, asyncFailed };
205 AsyncStage asyncStage_;
6f58d7d7
AR
206 Breadcrumb matchLoc_; ///< location of the node running matches() now
207 Breadcrumb asyncLoc_; ///< currentNode_ that called goAsync()
1707b9ad 208 unsigned asyncLoopDepth_; ///< how many times the current async state has resumed
ab321f4b 209
315b856d 210 bool callerGone();
6f58d7d7
AR
211
212 /// suspended (due to an async lookup) matches() in the ACL tree
213 std::stack<Breadcrumb> matchPath;
640fe8fb 214 /// the list of actions which must ignored during acl checks
329c128c 215 std::vector<Acl::Answer> bannedActions_;
25aa6c9a
AR
216
217 /// the name of the last evaluated ACL (if any ACLs were evaluated)
218 std::optional<SBuf> lastCheckedName_;
4fb35c3c 219};
220
ff9d9458 221#endif /* SQUID_SRC_ACL_CHECKLIST_H */
f53969cc 222