From 135c85a46edbeb70cda97515534628574b2c3cfe Mon Sep 17 00:00:00 2001 From: Josh Durgin Date: Fri, 28 Sep 2012 11:03:16 -0700 Subject: [PATCH] OSDCap: add separate caps for class read and class write These are useful for rbd layering, since reading an rbd image requires read-only class methods. Fixes: #3167 Signed-off-by: Josh Durgin --- src/osd/OSDCap.cc | 26 ++++-- src/osd/OSDCap.h | 10 +- src/test/osd/osdcap.cc | 208 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 229 insertions(+), 15 deletions(-) diff --git a/src/osd/OSDCap.cc b/src/osd/OSDCap.cc index 0831e85b52f07..cd9c374568b86 100644 --- a/src/osd/OSDCap.cc +++ b/src/osd/OSDCap.cc @@ -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::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 match = ( (auid >> object_prefix) [_val = phoenix::construct(_1, _2)] | (pool_name >> object_prefix) [_val = phoenix::construct(_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 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 [classcap] capspec = diff --git a/src/osd/OSDCap.h b/src/osd/OSDCap.h index 13cd658b59d6e..189f229ed9d91 100644 --- a/src/osd/OSDCap.h +++ b/src/osd/OSDCap.h @@ -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; diff --git a/src/test/osd/osdcap.cc b/src/test/osd/osdcap.cc index ad2f6a3997995..18145e156b6ec 100644 --- a/src/test/osd/osdcap.cc +++ b/src/test/osd/osdcap.cc @@ -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", -- 2.39.5