]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
OSDCap: add separate caps for class read and class write
authorJosh Durgin <josh.durgin@inktank.com>
Fri, 28 Sep 2012 18:03:16 +0000 (11:03 -0700)
committerJosh Durgin <josh.durgin@inktank.com>
Tue, 2 Oct 2012 22:43:37 +0000 (15:43 -0700)
These are useful for rbd layering, since reading an rbd image
requires read-only class methods.

Fixes: #3167
Signed-off-by: Josh Durgin <josh.durgin@inktank.com>
src/osd/OSDCap.cc
src/osd/OSDCap.h
src/test/osd/osdcap.cc

index 0831e85b52f079f6090dd6a6166931419ff6a583..cd9c374568b8638b9008c4811772d60d2d2ecb50 100644 (file)
@@ -33,8 +33,14 @@ ostream& operator<<(ostream& out, rwxa_t p)
     out << "r";
   if (p & OSD_CAP_W)
     out << "w";
-  if (p & OSD_CAP_X)
+  if ((p & OSD_CAP_X) == OSD_CAP_X) {
     out << "x";
+  } else {
+    if (p & OSD_CAP_CLS_R)
+      out << " class-read";
+    if (p & OSD_CAP_CLS_W)
+      out << " class-write";
+  }
   return out;
 }
 
@@ -105,11 +111,15 @@ bool OSDCap::is_capable(const string& pool_name, int64_t pool_auid, const string
   for (vector<OSDCapGrant>::const_iterator p = grants.begin(); p != grants.end(); ++p) {
     if (p->match.is_match(pool_name, pool_auid, object)) {
       allow |= p->spec.allow;
-      if (op_may_read && !(allow & OSD_CAP_R))
-       continue;
-      if (op_may_write && !(allow & OSD_CAP_W))
+      rwxa_t cap_read = OSD_CAP_R;
+      rwxa_t cap_write = OSD_CAP_W;
+      if (op_may_exec) {
+       cap_read = OSD_CAP_CLS_R;
+       cap_write = OSD_CAP_CLS_W;
+      }
+      if (op_may_read && !(allow & cap_read))
        continue;
-      if (op_may_exec && !(allow & OSD_CAP_X))
+      if (op_may_write && !(allow & cap_write))
        continue;
       return true;
     }
@@ -155,7 +165,7 @@ struct OSDCapParser : qi::grammar<Iterator, OSDCap()>
     match = ( (auid >> object_prefix)                 [_val = phoenix::construct<OSDCapMatch>(_1, _2)] |
              (pool_name >> object_prefix)            [_val = phoenix::construct<OSDCapMatch>(_1, _2)]);
 
-    // rwxa := * | [r][w][x]
+    // rwxa := * | [r][w][x] [class-read] [class-write]
     rwxa =
       (spaces >> lit("*")[_val = OSD_CAP_ANY]) |
       ( eps[_val = 0] >>
@@ -163,7 +173,9 @@ struct OSDCapParser : qi::grammar<Iterator, OSDCap()>
         spaces >>
         ( lit('r')[_val |= OSD_CAP_R] ||
           lit('w')[_val |= OSD_CAP_W] ||
-          lit('x')[_val |= OSD_CAP_X] )));
+          lit('x')[_val |= OSD_CAP_X] )) ||
+       ( (spaces >> lit("class-read")[_val |= OSD_CAP_CLS_R]) ||
+         (spaces >> lit("class-write")[_val |= OSD_CAP_CLS_W]) ));
 
     // capspec := * | rwx | class <name> [classcap]
     capspec =
index 13cd658b59d6ed97d7adad568e2623e55aba84e5..189f229ed9d912682c2822fcfec04e50f050275d 100644 (file)
@@ -32,10 +32,12 @@ using std::ostream;
 
 #include "include/types.h"
 
-static const __u8 OSD_CAP_R = 0x01;      // read
-static const __u8 OSD_CAP_W = 0x02;      // write
-static const __u8 OSD_CAP_X = 0x04;      // (class) execute
-static const __u8 OSD_CAP_ANY = 0xff;    // *
+static const __u8 OSD_CAP_R     = (1 << 1);      // read
+static const __u8 OSD_CAP_W     = (1 << 2);      // write
+static const __u8 OSD_CAP_CLS_R = (1 << 3);      // class read
+static const __u8 OSD_CAP_CLS_W = (1 << 4);      // class write
+static const __u8 OSD_CAP_X     = (OSD_CAP_CLS_R | OSD_CAP_CLS_W); // execute
+static const __u8 OSD_CAP_ANY   = 0xff;          // *
 
 typedef __u8 rwxa_t;
 
index ad2f6a399799544b833855e6275b270458503459..18145e156b6ecaedd4014872cf60c69afc616f77 100644 (file)
@@ -45,6 +45,13 @@ const char *parse_good[] = {
   "allow pool foo rwx ;allow pool bar r",
   "allow pool foo rwx; allow pool bar r",
   "allow pool data rw, allow pool rbd rwx, allow pool images class rbd foo",
+  "allow class-read",
+  "allow class-write",
+  "allow class-read class-write",
+  "allow r class-read pool foo",
+  "allow rw class-read class-write pool foo",
+  "allow r class-read pool foo",
+  "allow pool bar rwx; allow pool baz r class-read",
   "allow class foo",
   "allow class clsname \"clsthingidon'tunderstand\"",
   "  allow rwx pool foo; allow r pool bar  ",
@@ -60,8 +67,8 @@ TEST(OSDCap, ParseGood) {
   for (int i=0; parse_good[i]; i++) {
     string str = parse_good[i];
     OSDCap cap;
-    bool r = cap.parse(str, &cout);
-    ASSERT_TRUE(r);
+    std::cout << "Testing good input: '" << str << "'" << std::endl;
+    ASSERT_TRUE(cap.parse(str, &cout));
   }
 }
 
@@ -87,8 +94,8 @@ TEST(OSDCap, ParseBad) {
   for (int i=0; parse_bad[i]; i++) {
     string str = parse_bad[i];
     OSDCap cap;
-    bool r = cap.parse(str, &cout);
-    ASSERT_FALSE(r);
+    std::cout << "Testing bad input: '" << str << "'" << std::endl;
+    ASSERT_FALSE(cap.parse(str, &cout));
   }
 }
 
@@ -187,6 +194,193 @@ TEST(OSDCap, ObjectPoolAndPrefix) {
   ASSERT_FALSE(cap.is_capable("baz", 0, "fo", true, true, true));
 }
 
+TEST(OSDCap, BasicR) {
+  OSDCap cap;
+  ASSERT_TRUE(cap.parse("allow r", NULL));
+
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, false, false));
+
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", false, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, false, true));
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", false, true, false));
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, true, false));
+}
+
+TEST(OSDCap, BasicW) {
+  OSDCap cap;
+  ASSERT_TRUE(cap.parse("allow w", NULL));
+
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, true, false));
+
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", false, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, false, true));
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, false, false));
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, true, false));
+}
+
+TEST(OSDCap, BasicX) {
+  OSDCap cap;
+  ASSERT_TRUE(cap.parse("allow x", NULL));
+
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, true, true));
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, false, true));
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, true, true));
+
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", false, true, false));
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, false, false));
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, true, false));
+}
+
+TEST(OSDCap, BasicRW) {
+  OSDCap cap;
+  ASSERT_TRUE(cap.parse("allow rw", NULL));
+
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, true, false));
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, false, false));
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, true, false));
+
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", false, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, false, true));
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, true, true));
+}
+
+TEST(OSDCap, BasicRX) {
+  OSDCap cap;
+  ASSERT_TRUE(cap.parse("allow rx", NULL));
+
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, false, true));
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, false, false));
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, true, true));
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, true, true));
+
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", false, true, false));
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, true, false));
+}
+
+TEST(OSDCap, BasicWX) {
+  OSDCap cap;
+  ASSERT_TRUE(cap.parse("allow wx", NULL));
+
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, true, false));
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, true, true));
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, false, true));
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, true, true));
+
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, false, false));
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, true, false));
+}
+
+TEST(OSDCap, BasicRWX) {
+  OSDCap cap;
+  ASSERT_TRUE(cap.parse("allow rwx", NULL));
+
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, false, true));
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, false, false));
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, true, true));
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, true, true));
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, true, false));
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, true, false));
+}
+
+TEST(OSDCap, BasicRWClassRClassW) {
+  OSDCap cap;
+  ASSERT_TRUE(cap.parse("allow rw class-read class-write", NULL));
+
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, false, true));
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, false, true));
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, false, false));
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, true, true));
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, true, true));
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, true, false));
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, true, false));
+}
+
+TEST(OSDCap, ClassR) {
+  OSDCap cap;
+  ASSERT_TRUE(cap.parse("allow class-read", NULL));
+
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, false, true));
+
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, false, false));
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", false, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", false, true, false));
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, true, false));
+}
+
+TEST(OSDCap, ClassW) {
+  OSDCap cap;
+  ASSERT_TRUE(cap.parse("allow class-write", NULL));
+
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, true, true));
+
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, false, true));
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, false, false));
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", false, true, false));
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, true, false));
+}
+
+TEST(OSDCap, ClassRW) {
+  OSDCap cap;
+  ASSERT_TRUE(cap.parse("allow class-read class-write", NULL));
+
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, false, true));
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, false, true));
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, true, true));
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, true, true));
+
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, false, false));
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", false, true, false));
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, true, false));
+}
+
+TEST(OSDCap, BasicRClassR) {
+  OSDCap cap;
+  ASSERT_TRUE(cap.parse("allow r class-read", NULL));
+
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, false, true));
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, false, true));
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, false, false));
+
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", false, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", false, true, false));
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, true, false));
+}
+
+TEST(OSDCap, PoolClassR) {
+  OSDCap cap;
+  ASSERT_TRUE(cap.parse("allow pool bar r class-read, allow pool foo rwx", NULL));
+
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", false, false, true));
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, false, true));
+  ASSERT_TRUE(cap.is_capable("bar", 0, "foo", true, false, false));
+
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", false, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, true, true));
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", false, true, false));
+  ASSERT_FALSE(cap.is_capable("bar", 0, "foo", true, true, false));
+
+  ASSERT_TRUE(cap.is_capable("foo", 0, "foo", false, false, true));
+  ASSERT_TRUE(cap.is_capable("foo", 0, "foo", true, false, true));
+  ASSERT_TRUE(cap.is_capable("foo", 0, "foo", true, false, false));
+  ASSERT_TRUE(cap.is_capable("foo", 0, "foo", false, true, true));
+  ASSERT_TRUE(cap.is_capable("foo", 0, "foo", true, true, true));
+  ASSERT_TRUE(cap.is_capable("foo", 0, "foo", false, true, false));
+  ASSERT_TRUE(cap.is_capable("foo", 0, "foo", true, true, false));
+
+  ASSERT_FALSE(cap.is_capable("baz", 0, "foo", false, false, true));
+  ASSERT_FALSE(cap.is_capable("baz", 0, "foo", true, false, true));
+  ASSERT_FALSE(cap.is_capable("baz", 0, "foo", true, false, false));
+  ASSERT_FALSE(cap.is_capable("baz", 0, "foo", false, true, true));
+  ASSERT_FALSE(cap.is_capable("baz", 0, "foo", true, true, true));
+  ASSERT_FALSE(cap.is_capable("baz", 0, "foo", false, true, false));
+  ASSERT_FALSE(cap.is_capable("baz", 0, "foo", true, true, false));
+}
+
 TEST(OSDCap, OutputParsed)
 {
   struct CapsTest {
@@ -202,6 +396,12 @@ TEST(OSDCap, OutputParsed)
      "osdcap[grant(rx)]"},
     {"allow rwx",
      "osdcap[grant(rwx)]"},
+    {"allow rw class-read class-write",
+     "osdcap[grant(rwx)]"},
+    {"allow rw class-read",
+     "osdcap[grant(rw class-read)]"},
+    {"allow rw class-write",
+     "osdcap[grant(rw class-write)]"},
     {"allow rwx pool images",
      "osdcap[grant(pool images rwx)]"},
     {"allow r pool images",