Branch data Line data Source code
1 : : // Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
2 : : //
3 : : // Permission to use, copy, modify, and/or distribute this software for any
4 : : // purpose with or without fee is hereby granted, provided that the above
5 : : // copyright notice and this permission notice appear in all copies.
6 : : //
7 : : // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
8 : : // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
9 : : // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
10 : : // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
11 : : // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
12 : : // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
13 : : // PERFORMANCE OF THIS SOFTWARE.
14 : :
15 : : #ifndef ACL_LOGIC_CHECK_H
16 : : #define ACL_LOGIC_CHECK_H
17 : :
18 : : #include "check.h"
19 : : #include "loader.h"
20 : :
21 : : namespace isc {
22 : : namespace acl {
23 : :
24 : : /// \brief Constants for the AnyOf implementation
25 : : class AnyOfSpec {
26 : : public:
27 : : static bool start() { return (false); }
28 : : static bool terminate(const bool another) {
29 : : return (another);
30 : : }
31 : : };
32 : :
33 : : /// \brief Constants for the AllOf implementation
34 : : class AllOfSpec {
35 : : public:
36 : : static bool start() { return (true); }
37 : : static bool terminate(const bool another) {
38 : : return (!another);
39 : : }
40 : : };
41 : :
42 : : /**
43 : : * \brief Logic operators
44 : : *
45 : : * This class implements the AllOf and AnyOf compound checks. As their
46 : : * behaviour is almost the same, the same template class is used. Which
47 : : * one it is depends on the Mode template parameter. The Mode should be
48 : : * one of AnyOfSpec or AllOfSpec, which provide some commands for the
49 : : * internal implementation. It would be nice to provide typedefs for
50 : : * them, but it is impossible to do so, as we have the Context template
51 : : * parameter as well and C++ doesn't like templated typedefs.
52 : : *
53 : : * The object holds several subexpressions and returns true if all
54 : : * of the subexpressions return true (in case of AllOfSpec Mode) or
55 : : * at last one of them return true (in case of AnyOfSpec Mode). If
56 : : * some subexpression guarantees the result (eg. some returns false
57 : : * in case of AllOfSpec), the rest is not tried for performance
58 : : * reasons.
59 : : */
60 : : template<typename Mode, typename Context>
61 [ + - ][ + - ]: 61 : class LogicOperator : public CompoundCheck<Context> {
62 : : public:
63 : : /**
64 : : * \brief Add another subexpression.
65 : : *
66 : : * This adds another subexpression to the list of checked expressions.
67 : : * This is usually done shortly after the creation, before using the
68 : : * check for matches.
69 : : *
70 : : * Currently there's no way to place the expression into arbitrary place
71 : : * or to remove it. It might turn out it would be needed in future to
72 : : * optimise or it might even turn out we need shared pointers for it.
73 : : *
74 : : * \param expr The new expression to put inside.
75 : : */
76 : : void addSubexpression(const boost::shared_ptr<Check<Context> >& expr) {
77 [ + - + - ]: 40 : checks_.push_back(expr);
[ # # ][ + -
+ - # # #
# ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ]
78 : : }
79 : : /**
80 : : * \brief The current list of subexpressions.
81 : : */
82 : 35 : virtual typename CompoundCheck<Context>::Checks getSubexpressions() const {
83 : 0 : typename CompoundCheck<Context>::Checks result;
84 [ + + ][ + + ]: 105 : for (typename Checks::const_iterator i(checks_.begin());
85 : : i != checks_.end(); ++i) {
86 [ + - ][ + - ]: 70 : result.push_back(i->get());
87 : : }
88 : 35 : return (result);
89 : : }
90 : : /**
91 : : * \brief The match of the check.
92 : : *
93 : : * Runs the subexpressions, one by one, and then decides based on that
94 : : * what to return.
95 : : */
96 : 24 : virtual bool matches(const Context& context) const {
97 : : /*
98 : : * This might look slightly complicated. However, this is just
99 : : * generalized version of multi-and or multi-or. The usual
100 : : * implementation of multi-and starts with true and if one with
101 : : * false is found, it turns to be false forever and false is
102 : : * returned. It is exactly the other way around with or.
103 : : *
104 : : * So, if we ever find one that makes it the other one than start
105 : : * (false in case of and, true in case of or), we can just stop and
106 : : * return that one right away. If it meets no such expression, we
107 : : * get to the end and return the default.
108 : : */
109 [ + + ][ + + ]: 65 : for (typename Checks::const_iterator i(checks_.begin());
110 : : i != checks_.end(); ++i) {
111 [ + + ][ + + ]: 41 : if (Mode::terminate((*i)->matches(context))) {
[ + ][ + + ]
112 : : return (!Mode::start());
113 : : }
114 : : }
115 : : return (Mode::start());
116 : : }
117 : : private:
118 : : /// \brief List of subexpressions
119 : : typedef typename std::vector<boost::shared_ptr<Check<Context> > > Checks;
120 : : Checks checks_;
121 : : };
122 : :
123 : : /**
124 : : * \brief Creator for the LogicOperator compound check.
125 : : *
126 : : * This class can load the ANY and ALL operators from JSON. They expect
127 : : * a list of subexpressions as a parameter, eg. like this:
128 : : *
129 : : * \verbatim
130 : : * {"ANY": [
131 : : * {"ip": "1.2.3.4"},
132 : : * {"ip": "5.6.7.8"}
133 : : * ]}
134 : : * \endverbatim
135 : : *
136 : : * It uses the loader to load the subexpressions, therefore whatever is
137 : : * supported there is supported here as well.
138 : : *
139 : : * The Mode template parameter has the same meaning as with LogicOperator,
140 : : * it is used to know which operators to create.
141 : : */
142 : : template<typename Mode, typename Context, typename Action = BasicAction>
143 : 60 : class LogicCreator : public Loader<Context, Action>::CheckCreator {
144 : : public:
145 : : /**
146 : : * \brief Constructor.
147 : : *
148 : : * \param name The name for which the loader will work. In practice,
149 : : * it will usually be ANY or ALL (depending on the mode), but
150 : : * anything else can be used as well.
151 : : */
152 : : LogicCreator(const std::string& name) :
153 [ - + ][ - + ]: 28 : name_(name)
154 : : {}
155 : : /// \brief Returns vector containing the name.
156 : 28 : virtual std::vector<std::string> names() const {
157 : 0 : std::vector<std::string> result;
158 [ + - ][ + - ]: 28 : result.push_back(name_);
159 : 28 : return (result);
160 : : }
161 : : /**
162 : : * \brief Converts a JSON description into the logic operator.
163 : : *
164 : : * This is the place where the actual loading happens. It creates
165 : : * the logic operator and calls the loader on each of the list
166 : : * elements, placing the result into the logic operator.
167 : : *
168 : : * The first parameter is ignored and is there only to match interface.
169 : : *
170 : : * \param definition The JSON definition of the subexpressions. This must
171 : : * be a list (if it isn't, the LoaderError is thrown) and the elements
172 : : * must be loadable by the loader (the exceptions from it are not
173 : : * caught).
174 : : * \param loader The loader to use for loading of subexpressions.
175 : : */
176 : 25 : virtual boost::shared_ptr<Check<Context> > create(const std::string&,
177 : : data::ConstElementPtr
178 : : definition,
179 : : const Loader<Context,
180 : : Action>& loader)
181 : : {
182 : 25 : std::vector<data::ConstElementPtr> subexprs;
183 : : try {
184 [ + + ][ + - ]: 25 : subexprs = definition->listValue();
[ + + ][ + - ]
185 : : }
186 [ - + ][ - + ]: 20 : catch (const data::TypeError&) {
187 [ - + ][ - + ]: 30 : isc_throw_1(LoaderError, "Logic operator takes list", definition);
[ - + ][ - + ]
[ - + ][ - + ]
188 : : }
189 : : boost::shared_ptr<LogicOperator<Mode, Context> >
190 [ + - ][ + - ]: 15 : result(new LogicOperator<Mode, Context>);
[ + - ][ + - ]
191 [ + + ][ + + ]: 39 : for (std::vector<data::ConstElementPtr>::const_iterator
192 : 54 : i(subexprs.begin());
193 : : i != subexprs.end(); ++i) {
194 [ + + ][ + + ]: 26 : result->addSubexpression(loader.loadCheck(*i));
[ + - ]
195 : : }
196 : 13 : return (result);
197 : : }
198 : 25 : virtual bool allowListAbbreviation() const { return (false); }
199 : : private:
200 : : const std::string name_;
201 : : };
202 : :
203 : : /**
204 : : * \brief The NOT operator for ACLs.
205 : : *
206 : : * This simply returns the negation of whatever returns the subexpression.
207 : : */
208 : : template<typename Context>
209 : 6 : class NotOperator : public CompoundCheck<Context> {
210 : : public:
211 : : /**
212 : : * \brief Constructor
213 : : *
214 : : * \param expr The subexpression to be negated by this NOT.
215 : : */
216 : : NotOperator(const boost::shared_ptr<Check<Context> >& expr) :
217 : 8 : expr_(expr)
218 : : { }
219 : : /**
220 : : * \brief The list of subexpressions
221 : : *
222 : : * \return The vector will contain single value and it is the expression
223 : : * passed by constructor.
224 : : */
225 : 4 : virtual typename CompoundCheck<Context>::Checks getSubexpressions() const {
226 : 0 : typename CompoundCheck<Context>::Checks result;
227 [ + - ]: 4 : result.push_back(expr_.get());
228 : 4 : return (result);
229 : : }
230 : : /// \brief The matching function
231 : 3 : virtual bool matches(const Context& context) const {
232 : 3 : return (!expr_->matches(context));
233 : : }
234 : : private:
235 : : /// \brief The subexpression
236 : : const boost::shared_ptr<Check<Context> > expr_;
237 : : };
238 : :
239 : : template<typename Context, typename Action = BasicAction>
240 : 30 : class NotCreator : public Loader<Context, Action>::CheckCreator {
241 : : public:
242 : : /**
243 : : * \brief Constructor
244 : : *
245 : : * \param name The name of the NOT operator to be loaded as.
246 : : */
247 : : NotCreator(const std::string& name) :
248 [ - + ]: 14 : name_(name)
249 : : { }
250 : : /**
251 : : * \brief List of the names this loads
252 : : *
253 : : * \return Single-value vector containing the name passed to the
254 : : * constructor.
255 : : */
256 : 14 : virtual std::vector<std::string> names() const {
257 : 0 : std::vector<std::string> result;
258 [ + - ]: 14 : result.push_back(name_);
259 : 14 : return (result);
260 : : }
261 : : /// \brief Create the check.
262 : 8 : virtual boost::shared_ptr<Check<Context> > create(const std::string&,
263 : : data::ConstElementPtr
264 : : definition,
265 : : const Loader<Context,
266 : : Action>& loader)
267 : : {
268 : : return (boost::shared_ptr<Check<Context> >(new NotOperator<Context>(
269 [ + - ]: 10 : loader.loadCheck(definition))));
270 : : }
271 : : /**
272 : : * \brief Or-abbreviated form.
273 : : *
274 : : * This returns false. In theory, the NOT operator could be used with
275 : : * the abbreviated form, but it would be confusing. Such syntax is
276 : : * therefore explicitly forbidden.
277 : : */
278 : 8 : virtual bool allowListAbbreviation() const { return (false); }
279 : : public:
280 : : const std::string name_;
281 : : };
282 : :
283 : : }
284 : : }
285 : :
286 : : #endif
|