]> git.proxmox.com Git - ceph.git/blob - ceph/src/osd/OSDCap.cc
update sources to v12.1.0
[ceph.git] / 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
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
24 using std::ostream;
25 using std::vector;
26
27 ostream& operator<<(ostream& out, const osd_rwxa_t& p)
28 {
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
47 ostream& 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
56 ostream& operator<<(ostream& out, const OSDCapMatch& m)
57 {
58 if (m.auid != -1LL) {
59 out << "auid " << m.auid << " ";
60 }
61 if (m.object_prefix.length()) {
62 out << "object_prefix " << m.object_prefix << " ";
63 }
64 if (m.pool_name.length()) {
65 out << "pool " << m.pool_name << " ";
66 }
67 if (m.is_nspace) {
68 out << "namespace ";
69 if (m.nspace.length() == 0)
70 out << "\"\"";
71 else
72 out << m.nspace;
73 out << " ";
74 }
75 return out;
76 }
77
78 bool OSDCapMatch::is_match(const string& pn, const string& ns, int64_t pool_auid, const string& object) const
79 {
80 if (auid >= 0) {
81 if (auid != pool_auid)
82 return false;
83 }
84 if (pool_name.length()) {
85 if (pool_name != pn)
86 return false;
87 }
88 if (is_nspace) {
89 if (nspace != ns)
90 return false;
91 }
92 if (object_prefix.length()) {
93 if (object.find(object_prefix) != 0)
94 return false;
95 }
96 return true;
97 }
98
99 bool OSDCapMatch::is_match_all() const
100 {
101 if (auid >= 0)
102 return false;
103 if (pool_name.length())
104 return false;
105 if (is_nspace)
106 return false;
107 if (object_prefix.length())
108 return false;
109 return true;
110 }
111
112 ostream& operator<<(ostream& out, const OSDCapGrant& g)
113 {
114 return out << "grant(" << g.match << g.spec << ")";
115 }
116
117
118 bool OSDCap::allow_all() const
119 {
120 for (vector<OSDCapGrant>::const_iterator p = grants.begin(); p != grants.end(); ++p)
121 if (p->match.is_match_all() && p->spec.allow_all())
122 return true;
123 return false;
124 }
125
126 void OSDCap::set_allow_all()
127 {
128 grants.clear();
129 grants.push_back(OSDCapGrant(OSDCapMatch(), OSDCapSpec(OSD_CAP_ANY)));
130 }
131
132 bool OSDCap::is_capable(const string& pool_name, const string& ns, int64_t pool_auid,
133 const string& object, bool op_may_read, bool op_may_write,
134 const std::vector<OpRequest::ClassInfo>& classes) const
135 {
136 const size_t num_classes = classes.size();
137 std::vector<bool> class_allowed(num_classes, false);
138 osd_rwxa_t allow = 0;
139 for (vector<OSDCapGrant>::const_iterator p = grants.begin();
140 p != grants.end(); ++p) {
141 if (p->match.is_match(pool_name, ns, pool_auid, object)) {
142 allow = allow | p->spec.allow;
143 if ((op_may_read && !(allow & OSD_CAP_R)) ||
144 (op_may_write && !(allow & OSD_CAP_W)))
145 continue;
146 if (num_classes) {
147 // check 'allow *'
148 if (p->spec.allow_all())
149 return true;
150 // compare this grant to each class in the operation
151 for (size_t i = 0; i < num_classes; i++) {
152 // check 'allow class foo'
153 if (classes[i].name == p->spec.class_name &&
154 !p->spec.class_name.empty()) {
155 class_allowed[i] = true;
156 continue;
157 }
158 // check 'allow x | class-{rw}': must be on whitelist
159 if (!classes[i].whitelisted)
160 continue;
161 if ((classes[i].read && !(allow & OSD_CAP_CLS_R)) ||
162 (classes[i].write && !(allow & OSD_CAP_CLS_W))) {
163 continue;
164 }
165 class_allowed[i] = true;
166 }
167 if (std::all_of(class_allowed.cbegin(), class_allowed.cend(),
168 [](bool v) { return v; }))
169 return true;
170 else
171 continue;
172 }
173 return true;
174 }
175 }
176 return false;
177 }
178
179
180 // grammar
181 namespace qi = boost::spirit::qi;
182 namespace ascii = boost::spirit::ascii;
183 namespace phoenix = boost::phoenix;
184
185 template <typename Iterator>
186 struct OSDCapParser : qi::grammar<Iterator, OSDCap()>
187 {
188 OSDCapParser() : OSDCapParser::base_type(osdcap)
189 {
190 using qi::char_;
191 using qi::int_;
192 using qi::lexeme;
193 using qi::alnum;
194 using qi::_val;
195 using qi::_1;
196 using qi::_2;
197 using qi::_3;
198 using qi::eps;
199 using qi::lit;
200
201 quoted_string %=
202 lexeme['"' >> +(char_ - '"') >> '"'] |
203 lexeme['\'' >> +(char_ - '\'') >> '\''];
204 equoted_string %=
205 lexeme['"' >> *(char_ - '"') >> '"'] |
206 lexeme['\'' >> *(char_ - '\'') >> '\''];
207 unquoted_word %= +char_("a-zA-Z0-9_.-");
208 str %= quoted_string | unquoted_word;
209 estr %= equoted_string | unquoted_word;
210
211 spaces = +ascii::space;
212
213
214 // match := [pool[=]<poolname> [namespace[=]<namespace>] | auid <123>] [object_prefix <prefix>]
215 pool_name %= -(spaces >> lit("pool") >> (lit('=') | spaces) >> str);
216 nspace %= (spaces >> lit("namespace") >> (lit('=') | spaces) >> estr);
217 auid %= (spaces >> lit("auid") >> spaces >> int_);
218 object_prefix %= -(spaces >> lit("object_prefix") >> spaces >> str);
219
220 match = ( (auid >> object_prefix) [_val = phoenix::construct<OSDCapMatch>(_1, _2)] |
221 (pool_name >> nspace >> object_prefix) [_val = phoenix::construct<OSDCapMatch>(_1, _2, _3)] |
222 (pool_name >> object_prefix) [_val = phoenix::construct<OSDCapMatch>(_1, _2)]);
223
224 // rwxa := * | [r][w][x] [class-read] [class-write]
225 rwxa =
226 (spaces >> lit("*")[_val = OSD_CAP_ANY]) |
227 ( eps[_val = 0] >>
228 (
229 spaces >>
230 ( lit('r')[_val |= OSD_CAP_R] ||
231 lit('w')[_val |= OSD_CAP_W] ||
232 lit('x')[_val |= OSD_CAP_X] )) ||
233 ( (spaces >> lit("class-read")[_val |= OSD_CAP_CLS_R]) ||
234 (spaces >> lit("class-write")[_val |= OSD_CAP_CLS_W]) ));
235
236 // capspec := * | rwx | class <name> [classcap]
237 capspec =
238 rwxa [_val = phoenix::construct<OSDCapSpec>(_1)] |
239 ( spaces >> lit("class") >> spaces >> ((str >> spaces >> str) [_val = phoenix::construct<OSDCapSpec>(_1, _2)] |
240 str [_val = phoenix::construct<OSDCapSpec>(_1, string())] ));
241
242 // grant := allow match capspec
243 grant = (*ascii::blank >> lit("allow") >>
244 ((capspec >> match) [_val = phoenix::construct<OSDCapGrant>(_2, _1)] |
245 (match >> capspec) [_val = phoenix::construct<OSDCapGrant>(_1, _2)]) >>
246 *ascii::blank);
247 // osdcap := grant [grant ...]
248 grants %= (grant % (lit(';') | lit(',')));
249 osdcap = grants [_val = phoenix::construct<OSDCap>(_1)];
250 }
251 qi::rule<Iterator> spaces;
252 qi::rule<Iterator, unsigned()> rwxa;
253 qi::rule<Iterator, string()> quoted_string, equoted_string;
254 qi::rule<Iterator, string()> unquoted_word;
255 qi::rule<Iterator, string()> str, estr;
256 qi::rule<Iterator, int()> auid;
257 qi::rule<Iterator, OSDCapSpec()> capspec;
258 qi::rule<Iterator, string()> pool_name;
259 qi::rule<Iterator, string()> nspace;
260 qi::rule<Iterator, string()> object_prefix;
261 qi::rule<Iterator, OSDCapMatch()> match;
262 qi::rule<Iterator, OSDCapGrant()> grant;
263 qi::rule<Iterator, std::vector<OSDCapGrant>()> grants;
264 qi::rule<Iterator, OSDCap()> osdcap;
265 };
266
267 bool OSDCap::parse(const string& str, ostream *err)
268 {
269 OSDCapParser<string::const_iterator> g;
270 string::const_iterator iter = str.begin();
271 string::const_iterator end = str.end();
272
273 bool r = qi::phrase_parse(iter, end, g, ascii::space, *this);
274 if (r && iter == end)
275 return true;
276
277 // Make sure no grants are kept after parsing failed!
278 grants.clear();
279
280 if (err)
281 *err << "osdcap parse failed, stopped at '" << std::string(iter, end)
282 << "' of '" << str << "'\n";
283
284 return false;
285 }
286