]> git.proxmox.com Git - ceph.git/blame - ceph/src/osd/OSDCap.cc
update sources to v12.1.2
[ceph.git] / ceph / src / osd / OSDCap.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3/*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2009-2011 New Dream Network
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15#include <boost/config/warning_disable.hpp>
16#include <boost/spirit/include/qi.hpp>
17#include <boost/spirit/include/phoenix_operator.hpp>
18#include <boost/spirit/include/phoenix.hpp>
19
20#include "OSDCap.h"
21#include "common/config.h"
22#include "common/debug.h"
23
24using std::ostream;
25using std::vector;
26
31f18b77 27ostream& operator<<(ostream& out, const osd_rwxa_t& p)
c07f9fc5 28{
7c673cae
FG
29 if (p == OSD_CAP_ANY)
30 return out << "*";
31
32 if (p & OSD_CAP_R)
33 out << "r";
34 if (p & OSD_CAP_W)
35 out << "w";
36 if ((p & OSD_CAP_X) == OSD_CAP_X) {
37 out << "x";
38 } else {
39 if (p & OSD_CAP_CLS_R)
40 out << " class-read";
41 if (p & OSD_CAP_CLS_W)
42 out << " class-write";
43 }
44 return out;
45}
46
47ostream& operator<<(ostream& out, const OSDCapSpec& s)
48{
49 if (s.allow)
50 return out << s.allow;
51 if (s.class_name.length())
52 return out << "class '" << s.class_name << "' '" << s.class_allow << "'";
53 return out;
54}
55
c07f9fc5
FG
56ostream& operator<<(ostream& out, const OSDCapPoolNamespace& pns)
57{
58 if (!pns.pool_name.empty()) {
59 out << "pool " << pns.pool_name << " ";
60 }
61 if (pns.nspace) {
62 out << "namespace ";
63 if (pns.nspace->empty()) {
64 out << "\"\"";
65 } else {
66 out << *pns.nspace;
67 }
68 out << " ";
69 }
70 return out;
71}
72
7c673cae
FG
73ostream& operator<<(ostream& out, const OSDCapMatch& m)
74{
75 if (m.auid != -1LL) {
76 out << "auid " << m.auid << " ";
c07f9fc5
FG
77 } else {
78 out << m.pool_namespace;
7c673cae 79 }
c07f9fc5 80
7c673cae
FG
81 if (m.object_prefix.length()) {
82 out << "object_prefix " << m.object_prefix << " ";
83 }
7c673cae
FG
84 return out;
85}
86
c07f9fc5 87ostream& operator<<(ostream& out, const OSDCapProfile& m)
7c673cae 88{
c07f9fc5
FG
89 out << "profile " << m.name;
90 out << m.pool_namespace;
91 return out;
92}
93
94bool OSDCapPoolNamespace::is_match(const std::string& pn,
95 const std::string& ns) const
96{
97 if (!pool_name.empty()) {
98 if (pool_name != pn) {
7c673cae 99 return false;
c07f9fc5 100 }
7c673cae 101 }
c07f9fc5
FG
102 if (nspace) {
103 if (*nspace != ns) {
7c673cae 104 return false;
c07f9fc5 105 }
7c673cae 106 }
c07f9fc5
FG
107 return true;
108}
109
110bool OSDCapPoolNamespace::is_match_all() const
111{
112 if (!pool_name.empty())
113 return false;
114 if (nspace)
115 return false;
116 return true;
117}
118
119bool OSDCapMatch::is_match(const string& pn, const string& ns,
120 int64_t pool_auid, const string& object) const
121{
122 if (auid >= 0) {
123 if (auid != pool_auid)
7c673cae 124 return false;
c07f9fc5
FG
125 } else if (!pool_namespace.is_match(pn, ns)) {
126 return false;
7c673cae 127 }
c07f9fc5 128
7c673cae
FG
129 if (object_prefix.length()) {
130 if (object.find(object_prefix) != 0)
131 return false;
132 }
133 return true;
134}
135
136bool OSDCapMatch::is_match_all() const
137{
c07f9fc5 138 if (auid >= 0) {
7c673cae 139 return false;
c07f9fc5 140 } else if (!pool_namespace.is_match_all()) {
7c673cae 141 return false;
c07f9fc5
FG
142 }
143
144 if (object_prefix.length()) {
7c673cae 145 return false;
c07f9fc5 146 }
7c673cae
FG
147 return true;
148}
149
150ostream& operator<<(ostream& out, const OSDCapGrant& g)
151{
c07f9fc5
FG
152 out << "grant(";
153 if (g.profile.is_valid()) {
154 out << g.profile << " [";
155 for (auto it = g.profile_grants.cbegin();
156 it != g.profile_grants.cend(); ++it) {
157 if (it != g.profile_grants.cbegin()) {
158 out << ",";
159 }
160 out << *it;
161 }
162 out << "]";
163 } else {
164 out << g.match << g.spec;
165 }
166 out << ")";
167 return out;
7c673cae
FG
168}
169
c07f9fc5 170bool OSDCapGrant::allow_all() const
7c673cae 171{
c07f9fc5
FG
172 if (profile.is_valid()) {
173 return std::any_of(profile_grants.cbegin(), profile_grants.cend(),
174 [](const OSDCapGrant& grant) {
175 return grant.allow_all();
176 });
177 }
7c673cae 178
c07f9fc5 179 return (match.is_match_all() && spec.allow_all());
7c673cae
FG
180}
181
c07f9fc5
FG
182bool OSDCapGrant::is_capable(const string& pool_name, const string& ns,
183 int64_t pool_auid, const string& object,
184 bool op_may_read, bool op_may_write,
185 const std::vector<OpRequest::ClassInfo>& classes,
186 std::vector<bool>* class_allowed) const
7c673cae 187{
7c673cae 188 osd_rwxa_t allow = 0;
c07f9fc5
FG
189 if (profile.is_valid()) {
190 return std::any_of(profile_grants.cbegin(), profile_grants.cend(),
191 [&](const OSDCapGrant& grant) {
192 return grant.is_capable(pool_name, ns, pool_auid, object, op_may_read,
193 op_may_write, classes, class_allowed);
194 });
195 } else {
196 if (match.is_match(pool_name, ns, pool_auid, object)) {
197 allow = allow | spec.allow;
7c673cae 198 if ((op_may_read && !(allow & OSD_CAP_R)) ||
c07f9fc5
FG
199 (op_may_write && !(allow & OSD_CAP_W))) {
200 return false;
201 }
202 if (!classes.empty()) {
7c673cae 203 // check 'allow *'
c07f9fc5 204 if (spec.allow_all()) {
7c673cae 205 return true;
c07f9fc5
FG
206 }
207
7c673cae 208 // compare this grant to each class in the operation
c07f9fc5 209 for (size_t i = 0; i < classes.size(); ++i) {
7c673cae 210 // check 'allow class foo'
c07f9fc5
FG
211 if (!spec.class_name.empty() && classes[i].name == spec.class_name) {
212 (*class_allowed)[i] = true;
7c673cae
FG
213 continue;
214 }
215 // check 'allow x | class-{rw}': must be on whitelist
c07f9fc5 216 if (!classes[i].whitelisted) {
7c673cae 217 continue;
c07f9fc5 218 }
7c673cae
FG
219 if ((classes[i].read && !(allow & OSD_CAP_CLS_R)) ||
220 (classes[i].write && !(allow & OSD_CAP_CLS_W))) {
221 continue;
222 }
c07f9fc5
FG
223 (*class_allowed)[i] = true;
224 }
225 if (!std::all_of(class_allowed->cbegin(), class_allowed->cend(),
226 [](bool v) { return v; })) {
227 return false;
7c673cae 228 }
7c673cae
FG
229 }
230 return true;
231 }
232 }
233 return false;
234}
235
c07f9fc5
FG
236void OSDCapGrant::expand_profile()
237{
238 if (profile.name == "read-only") {
239 // grants READ-ONLY caps to the OSD
240 profile_grants.emplace_back(OSDCapMatch(profile.pool_namespace),
241 OSDCapSpec(osd_rwxa_t(OSD_CAP_R)));
242 return;
243 }
244 if (profile.name == "read-write") {
245 // grants READ-WRITE caps to the OSD
246 profile_grants.emplace_back(OSDCapMatch(profile.pool_namespace),
247 OSDCapSpec(osd_rwxa_t(OSD_CAP_R | OSD_CAP_W)));
248 }
249
250 if (profile.name == "rbd") {
251 // RBD read-write grant
252 profile_grants.emplace_back(OSDCapMatch("", "", "rbd_children"),
253 OSDCapSpec(osd_rwxa_t(OSD_CAP_CLS_R)));
254 profile_grants.emplace_back(OSDCapMatch("", "", "rbd_mirroring"),
255 OSDCapSpec(osd_rwxa_t(OSD_CAP_CLS_R)));
256 profile_grants.emplace_back(OSDCapMatch(profile.pool_namespace),
257 OSDCapSpec(osd_rwxa_t(OSD_CAP_R |
258 OSD_CAP_W |
259 OSD_CAP_X)));
260 }
261 if (profile.name == "rbd-read-only") {
262 // RBD read-only grant
263 profile_grants.emplace_back(OSDCapMatch(profile.pool_namespace),
264 OSDCapSpec(osd_rwxa_t(OSD_CAP_R |
265 OSD_CAP_CLS_R)));
266 }
267}
268
269bool OSDCap::allow_all() const
270{
271 for (auto &grant : grants) {
272 if (grant.allow_all()) {
273 return true;
274 }
275 }
276 return false;
277}
278
279void OSDCap::set_allow_all()
280{
281 grants.clear();
282 grants.push_back(OSDCapGrant(OSDCapMatch(), OSDCapSpec(OSD_CAP_ANY)));
283}
284
285bool OSDCap::is_capable(const string& pool_name, const string& ns,
286 int64_t pool_auid, const string& object,
287 bool op_may_read, bool op_may_write,
288 const std::vector<OpRequest::ClassInfo>& classes) const
289{
290 std::vector<bool> class_allowed(classes.size(), false);
291 for (auto &grant : grants) {
292 if (grant.is_capable(pool_name, ns, pool_auid, object, op_may_read,
293 op_may_write, classes, &class_allowed)) {
294 return true;
295 }
296 }
297 return false;
298}
299
7c673cae
FG
300
301// grammar
302namespace qi = boost::spirit::qi;
303namespace ascii = boost::spirit::ascii;
304namespace phoenix = boost::phoenix;
305
306template <typename Iterator>
307struct OSDCapParser : qi::grammar<Iterator, OSDCap()>
308{
309 OSDCapParser() : OSDCapParser::base_type(osdcap)
310 {
311 using qi::char_;
312 using qi::int_;
313 using qi::lexeme;
314 using qi::alnum;
315 using qi::_val;
316 using qi::_1;
317 using qi::_2;
318 using qi::_3;
319 using qi::eps;
320 using qi::lit;
321
322 quoted_string %=
323 lexeme['"' >> +(char_ - '"') >> '"'] |
324 lexeme['\'' >> +(char_ - '\'') >> '\''];
325 equoted_string %=
326 lexeme['"' >> *(char_ - '"') >> '"'] |
327 lexeme['\'' >> *(char_ - '\'') >> '\''];
328 unquoted_word %= +char_("a-zA-Z0-9_.-");
329 str %= quoted_string | unquoted_word;
330 estr %= equoted_string | unquoted_word;
331
332 spaces = +ascii::space;
333
7c673cae
FG
334 pool_name %= -(spaces >> lit("pool") >> (lit('=') | spaces) >> str);
335 nspace %= (spaces >> lit("namespace") >> (lit('=') | spaces) >> estr);
c07f9fc5
FG
336
337 // match := [pool[=]<poolname> [namespace[=]<namespace>] | auid <123>] [object_prefix <prefix>]
7c673cae
FG
338 auid %= (spaces >> lit("auid") >> spaces >> int_);
339 object_prefix %= -(spaces >> lit("object_prefix") >> spaces >> str);
340
c07f9fc5
FG
341 match = (
342 (auid >> object_prefix) [_val = phoenix::construct<OSDCapMatch>(_1, _2)] |
343 (pool_name >> nspace >> object_prefix) [_val = phoenix::construct<OSDCapMatch>(_1, _2, _3)] |
344 (pool_name >> object_prefix) [_val = phoenix::construct<OSDCapMatch>(_1, _2)]);
7c673cae
FG
345
346 // rwxa := * | [r][w][x] [class-read] [class-write]
347 rwxa =
348 (spaces >> lit("*")[_val = OSD_CAP_ANY]) |
349 ( eps[_val = 0] >>
350 (
351 spaces >>
352 ( lit('r')[_val |= OSD_CAP_R] ||
353 lit('w')[_val |= OSD_CAP_W] ||
354 lit('x')[_val |= OSD_CAP_X] )) ||
355 ( (spaces >> lit("class-read")[_val |= OSD_CAP_CLS_R]) ||
356 (spaces >> lit("class-write")[_val |= OSD_CAP_CLS_W]) ));
357
358 // capspec := * | rwx | class <name> [classcap]
c07f9fc5
FG
359 class_name %= (spaces >> lit("class") >> spaces >> str);
360 class_cap %= -(spaces >> str);
361 capspec = (
362 (rwxa) [_val = phoenix::construct<OSDCapSpec>(_1)] |
363 (class_name >> class_cap) [_val = phoenix::construct<OSDCapSpec>(_1, _2)]);
364
365 // profile := profile <name> [pool[=]<pool> [namespace[=]<namespace>]]
366 profile_name %= (lit("profile") >> (lit('=') | spaces) >> str);
367 profile = (
368 (profile_name >> pool_name >> nspace) [_val = phoenix::construct<OSDCapProfile>(_1, _2, _3)] |
369 (profile_name >> pool_name) [_val = phoenix::construct<OSDCapProfile>(_1, _2)]);
7c673cae
FG
370
371 // grant := allow match capspec
c07f9fc5
FG
372 grant = (*ascii::blank >>
373 ((lit("allow") >> capspec >> match) [_val = phoenix::construct<OSDCapGrant>(_2, _1)] |
374 (lit("allow") >> match >> capspec) [_val = phoenix::construct<OSDCapGrant>(_1, _2)] |
375 (profile) [_val = phoenix::construct<OSDCapGrant>(_1)]
376 ) >> *ascii::blank);
7c673cae
FG
377 // osdcap := grant [grant ...]
378 grants %= (grant % (lit(';') | lit(',')));
c07f9fc5 379 osdcap = grants [_val = phoenix::construct<OSDCap>(_1)];
7c673cae
FG
380 }
381 qi::rule<Iterator> spaces;
382 qi::rule<Iterator, unsigned()> rwxa;
383 qi::rule<Iterator, string()> quoted_string, equoted_string;
384 qi::rule<Iterator, string()> unquoted_word;
385 qi::rule<Iterator, string()> str, estr;
386 qi::rule<Iterator, int()> auid;
c07f9fc5
FG
387 qi::rule<Iterator, string()> class_name;
388 qi::rule<Iterator, string()> class_cap;
7c673cae
FG
389 qi::rule<Iterator, OSDCapSpec()> capspec;
390 qi::rule<Iterator, string()> pool_name;
391 qi::rule<Iterator, string()> nspace;
392 qi::rule<Iterator, string()> object_prefix;
393 qi::rule<Iterator, OSDCapMatch()> match;
c07f9fc5
FG
394 qi::rule<Iterator, string()> profile_name;
395 qi::rule<Iterator, OSDCapProfile()> profile;
7c673cae
FG
396 qi::rule<Iterator, OSDCapGrant()> grant;
397 qi::rule<Iterator, std::vector<OSDCapGrant>()> grants;
398 qi::rule<Iterator, OSDCap()> osdcap;
399};
400
401bool OSDCap::parse(const string& str, ostream *err)
402{
403 OSDCapParser<string::const_iterator> g;
404 string::const_iterator iter = str.begin();
405 string::const_iterator end = str.end();
406
407 bool r = qi::phrase_parse(iter, end, g, ascii::space, *this);
408 if (r && iter == end)
409 return true;
410
411 // Make sure no grants are kept after parsing failed!
412 grants.clear();
413
414 if (err)
415 *err << "osdcap parse failed, stopped at '" << std::string(iter, end)
416 << "' of '" << str << "'\n";
417
418 return false;
419}
420