]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
osd: caps now support whitelisting execution of class methods
authorJason Dillaman <dillaman@redhat.com>
Thu, 4 Jan 2018 21:52:00 +0000 (16:52 -0500)
committerJason Dillaman <dillaman@redhat.com>
Thu, 4 Jan 2018 21:52:00 +0000 (16:52 -0500)
Signed-off-by: Jason Dillaman <dillaman@redhat.com>
src/osd/OSDCap.cc
src/osd/OSDCap.h
src/test/osd/osdcap.cc

index 3ab02878921737f7d8fab9a8186778d19fc66496..cd1b747d6922740206c14d795bdf5838e5bbcb6d 100644 (file)
@@ -49,8 +49,12 @@ ostream& operator<<(ostream& out, const OSDCapSpec& s)
 {
   if (s.allow)
     return out << s.allow;
-  if (s.class_name.length())
-    return out << "class '" << s.class_name << "' '" << s.class_allow << "'";
+  if (s.class_name.length()) {
+    out << "class '" << s.class_name << "'";
+    if (!s.method_name.empty()) {
+      out << " '" << s.method_name << "'";
+    }
+  }
   return out;
 }
 
@@ -271,9 +275,11 @@ bool OSDCapGrant::is_capable(const string& pool_name, const string& ns,
 
         // compare this grant to each class in the operation
         for (size_t i = 0; i < classes.size(); ++i) {
-          // check 'allow class foo'
+          // check 'allow class foo [method_name]'
           if (!spec.class_name.empty() &&
-              classes[i].class_name == spec.class_name) {
+              classes[i].class_name == spec.class_name &&
+              (spec.method_name.empty() ||
+               classes[i].method_name == spec.method_name)) {
             (*class_allowed)[i] = true;
             continue;
           }
@@ -434,12 +440,12 @@ struct OSDCapParser : qi::grammar<Iterator, OSDCap()>
        ( (spaces >> lit("class-read")[_val |= OSD_CAP_CLS_R]) ||
          (spaces >> lit("class-write")[_val |= OSD_CAP_CLS_W]) ));
 
-    // capspec := * | rwx | class <name> [classcap]
+    // capspec := * | rwx | class <name> [<method name>]
     class_name %= (spaces >> lit("class") >> spaces >> str);
-    class_cap %= -(spaces >> str);
+    method_name %= -(spaces >> str);
     capspec = (
-      (rwxa)                    [_val = phoenix::construct<OSDCapSpec>(_1)] |
-      (class_name >> class_cap) [_val = phoenix::construct<OSDCapSpec>(_1, _2)]);
+      (rwxa)                      [_val = phoenix::construct<OSDCapSpec>(_1)] |
+      (class_name >> method_name) [_val = phoenix::construct<OSDCapSpec>(_1, _2)]);
 
     // profile := profile <name> [pool[=]<pool> [namespace[=]<namespace>]]
     profile_name %= (lit("profile") >> (lit('=') | spaces) >> str);
@@ -465,7 +471,7 @@ struct OSDCapParser : qi::grammar<Iterator, OSDCap()>
   qi::rule<Iterator, string()> wildcard;
   qi::rule<Iterator, int()> auid;
   qi::rule<Iterator, string()> class_name;
-  qi::rule<Iterator, string()> class_cap;
+  qi::rule<Iterator, string()> method_name;
   qi::rule<Iterator, OSDCapSpec()> capspec;
   qi::rule<Iterator, string()> pool_name;
   qi::rule<Iterator, string()> nspace;
index 59b8392f67e1953b9f0924f817fd165185215478..eeb3835aa1484466931c1e7597303fda1471c84e 100644 (file)
@@ -64,13 +64,13 @@ ostream& operator<<(ostream& out, const osd_rwxa_t& p);
 struct OSDCapSpec {
   osd_rwxa_t allow;
   std::string class_name;
-  std::string class_allow;
+  std::string method_name;
 
   OSDCapSpec() : allow(0) {}
   explicit OSDCapSpec(osd_rwxa_t v) : allow(v) {}
-  explicit OSDCapSpec(std::string n) : allow(0), class_name(std::move(n)) {}
-  OSDCapSpec(std::string n, std::string a) :
-    allow(0), class_name(std::move(n)), class_allow(std::move(a)) {}
+  OSDCapSpec(std::string class_name, std::string method_name)
+    : allow(0), class_name(std::move(class_name)),
+      method_name(std::move(method_name)) {}
 
   bool allow_all() const {
     return allow == OSD_CAP_ANY;
index 5b6ccd4a92c2afcf8f0c0432c0e3887f8fed060f..2a06eb4702eef4bd62428a72a6fccd62d2046085 100644 (file)
@@ -947,6 +947,33 @@ TEST(OSDCap, AllowClass) {
   ASSERT_FALSE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"bar", "", true, true, false}}));
 }
 
+TEST(OSDCap, AllowClassMethod) {
+  OSDCap cap;
+  ASSERT_TRUE(cap.parse("allow class foo xyz", NULL));
+
+  // can call the xyz method on class foo regardless of whitelist status
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"foo", "xyz", true, false, true}}));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"foo", "xyz", false, true, true}}));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"foo", "xyz", true, true, true}}));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"foo", "xyz", true, false, false}}));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"foo", "xyz", false, true, false}}));
+  ASSERT_TRUE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"foo", "xyz", true, true, false}}));
+
+  // does not permit invoking class bar
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"bar", "", true, false, true}}));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"bar", "", false, true, true}}));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"bar", "", true, true, true}}));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"bar", "", true, false, false}}));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"bar", "", false, true, false}}));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"bar", "", true, true, false}}));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"bar", "xyz", true, false, true}}));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"bar", "xyz", false, true, true}}));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"bar", "xyz", true, true, true}}));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"bar", "xyz", true, false, false}}));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"bar", "xyz", false, true, false}}));
+  ASSERT_FALSE(cap.is_capable("bar", "", 0, {}, "foo", false, false, {{"bar", "xyz", true, true, false}}));
+}
+
 TEST(OSDCap, AllowClass2) {
   OSDCap cap;
   ASSERT_TRUE(cap.parse("allow class foo, allow class bar", NULL));