]>
git.proxmox.com Git - ceph.git/blob - ceph/src/osd/OSDCap.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2009-2011 New Dream Network
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.
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>
21 #include "common/config.h"
22 #include "common/debug.h"
27 ostream
& operator<<(ostream
& out
, const osd_rwxa_t
& p
)
36 if ((p
& OSD_CAP_X
) == OSD_CAP_X
) {
39 if (p
& OSD_CAP_CLS_R
)
41 if (p
& OSD_CAP_CLS_W
)
42 out
<< " class-write";
47 ostream
& operator<<(ostream
& out
, const OSDCapSpec
& s
)
50 return out
<< s
.allow
;
51 if (s
.class_name
.length())
52 return out
<< "class '" << s
.class_name
<< "' '" << s
.class_allow
<< "'";
56 ostream
& operator<<(ostream
& out
, const OSDCapPoolNamespace
& pns
)
58 if (!pns
.pool_name
.empty()) {
59 out
<< "pool " << pns
.pool_name
<< " ";
63 if (pns
.nspace
->empty()) {
73 ostream
& operator<<(ostream
& out
, const OSDCapMatch
& m
)
76 out
<< "auid " << m
.auid
<< " ";
78 out
<< m
.pool_namespace
;
81 if (m
.object_prefix
.length()) {
82 out
<< "object_prefix " << m
.object_prefix
<< " ";
87 ostream
& operator<<(ostream
& out
, const OSDCapProfile
& m
)
89 out
<< "profile " << m
.name
;
90 out
<< m
.pool_namespace
;
94 bool OSDCapPoolNamespace::is_match(const std::string
& pn
,
95 const std::string
& ns
) const
97 if (!pool_name
.empty()) {
98 if (pool_name
!= pn
) {
110 bool OSDCapPoolNamespace::is_match_all() const
112 if (!pool_name
.empty())
119 bool OSDCapMatch::is_match(const string
& pn
, const string
& ns
,
120 int64_t pool_auid
, const string
& object
) const
123 if (auid
!= pool_auid
)
125 } else if (!pool_namespace
.is_match(pn
, ns
)) {
129 if (object_prefix
.length()) {
130 if (object
.find(object_prefix
) != 0)
136 bool OSDCapMatch::is_match_all() const
140 } else if (!pool_namespace
.is_match_all()) {
144 if (object_prefix
.length()) {
150 ostream
& operator<<(ostream
& out
, const OSDCapGrant
& g
)
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()) {
164 out
<< g
.match
<< g
.spec
;
170 bool OSDCapGrant::allow_all() const
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();
179 return (match
.is_match_all() && spec
.allow_all());
182 bool 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
188 osd_rwxa_t allow
= 0;
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
);
196 if (match
.is_match(pool_name
, ns
, pool_auid
, object
)) {
197 allow
= allow
| spec
.allow
;
198 if ((op_may_read
&& !(allow
& OSD_CAP_R
)) ||
199 (op_may_write
&& !(allow
& OSD_CAP_W
))) {
202 if (!classes
.empty()) {
204 if (spec
.allow_all()) {
208 // compare this grant to each class in the operation
209 for (size_t i
= 0; i
< classes
.size(); ++i
) {
210 // check 'allow class foo'
211 if (!spec
.class_name
.empty() && classes
[i
].name
== spec
.class_name
) {
212 (*class_allowed
)[i
] = true;
215 // check 'allow x | class-{rw}': must be on whitelist
216 if (!classes
[i
].whitelisted
) {
219 if ((classes
[i
].read
&& !(allow
& OSD_CAP_CLS_R
)) ||
220 (classes
[i
].write
&& !(allow
& OSD_CAP_CLS_W
))) {
223 (*class_allowed
)[i
] = true;
225 if (!std::all_of(class_allowed
->cbegin(), class_allowed
->cend(),
226 [](bool v
) { return v
; })) {
236 void OSDCapGrant::expand_profile()
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
)));
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
)));
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
|
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
|
269 bool OSDCap::allow_all() const
271 for (auto &grant
: grants
) {
272 if (grant
.allow_all()) {
279 void OSDCap::set_allow_all()
282 grants
.push_back(OSDCapGrant(OSDCapMatch(), OSDCapSpec(OSD_CAP_ANY
)));
285 bool 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
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
)) {
302 namespace qi
= boost::spirit::qi
;
303 namespace ascii
= boost::spirit::ascii
;
304 namespace phoenix
= boost::phoenix
;
306 template <typename Iterator
>
307 struct OSDCapParser
: qi::grammar
<Iterator
, OSDCap()>
309 OSDCapParser() : OSDCapParser::base_type(osdcap
)
323 lexeme
['"' >> +(char_
- '"') >> '"'] |
324 lexeme
['\'' >> +(char_
- '\'') >> '\''];
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
;
332 spaces
= +ascii::space
;
334 pool_name
%= -(spaces
>> lit("pool") >> (lit('=') | spaces
) >> str
);
335 nspace
%= (spaces
>> lit("namespace") >> (lit('=') | spaces
) >> estr
);
337 // match := [pool[=]<poolname> [namespace[=]<namespace>] | auid <123>] [object_prefix <prefix>]
338 auid
%= (spaces
>> lit("auid") >> spaces
>> int_
);
339 object_prefix
%= -(spaces
>> lit("object_prefix") >> spaces
>> str
);
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
)]);
346 // rwxa := * | [r][w][x] [class-read] [class-write]
348 (spaces
>> lit("*")[_val
= OSD_CAP_ANY
]) |
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
]) ));
358 // capspec := * | rwx | class <name> [classcap]
359 class_name
%= (spaces
>> lit("class") >> spaces
>> str
);
360 class_cap
%= -(spaces
>> str
);
362 (rwxa
) [_val
= phoenix::construct
<OSDCapSpec
>(_1
)] |
363 (class_name
>> class_cap
) [_val
= phoenix::construct
<OSDCapSpec
>(_1
, _2
)]);
365 // profile := profile <name> [pool[=]<pool> [namespace[=]<namespace>]]
366 profile_name
%= (lit("profile") >> (lit('=') | spaces
) >> str
);
368 (profile_name
>> pool_name
>> nspace
) [_val
= phoenix::construct
<OSDCapProfile
>(_1
, _2
, _3
)] |
369 (profile_name
>> pool_name
) [_val
= phoenix::construct
<OSDCapProfile
>(_1
, _2
)]);
371 // grant := allow match capspec
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
)]
377 // osdcap := grant [grant ...]
378 grants
%= (grant
% (lit(';') | lit(',')));
379 osdcap
= grants
[_val
= phoenix::construct
<OSDCap
>(_1
)];
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
;
387 qi::rule
<Iterator
, string()> class_name
;
388 qi::rule
<Iterator
, string()> class_cap
;
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
;
394 qi::rule
<Iterator
, string()> profile_name
;
395 qi::rule
<Iterator
, OSDCapProfile()> profile
;
396 qi::rule
<Iterator
, OSDCapGrant()> grant
;
397 qi::rule
<Iterator
, std::vector
<OSDCapGrant
>()> grants
;
398 qi::rule
<Iterator
, OSDCap()> osdcap
;
401 bool OSDCap::parse(const string
& str
, ostream
*err
)
403 OSDCapParser
<string::const_iterator
> g
;
404 string::const_iterator iter
= str
.begin();
405 string::const_iterator end
= str
.end();
407 bool r
= qi::phrase_parse(iter
, end
, g
, ascii::space
, *this);
408 if (r
&& iter
== end
)
411 // Make sure no grants are kept after parsing failed!
415 *err
<< "osdcap parse failed, stopped at '" << std::string(iter
, end
)
416 << "' of '" << str
<< "'\n";