]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mds/MDSAuthCaps: parse and enforce network restriction
authorSage Weil <sage@redhat.com>
Fri, 3 Aug 2018 20:20:16 +0000 (15:20 -0500)
committerSage Weil <sage@redhat.com>
Sun, 12 Aug 2018 22:01:05 +0000 (17:01 -0500)
Signed-off-by: Sage Weil <sage@redhat.com>
src/mds/MDSAuthCaps.cc
src/mds/MDSAuthCaps.h
src/mds/MDSRank.cc
src/test/mds/TestMDSAuthCaps.cc

index 61835928e56bfcc421bf548ccc2bc38927c4ddd5..ffa06f60e973d88f9504faab12c1752bbb42b40c 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "common/debug.h"
 #include "MDSAuthCaps.h"
+#include "include/ipaddr.h"
 
 #define dout_subsys ceph_subsys_mds
 
@@ -58,6 +59,7 @@ struct MDSCapParser : qi::grammar<Iterator, MDSAuthCaps()>
       lexeme[lit("\"") >> *(char_ - '"') >> '"'] | 
       lexeme[lit("'") >> *(char_ - '\'') >> '\''];
     unquoted_path %= +char_("a-zA-Z0-9_./-");
+    network_str %= +char_("/.:a-fA-F0-9][");
 
     // match := [path=<path>] [uid=<uid> [gids=<gid>[,<gid>...]]
     path %= (spaces >> lit("path") >> lit('=') >> (quoted_path | unquoted_path));
@@ -86,12 +88,14 @@ struct MDSCapParser : qi::grammar<Iterator, MDSAuthCaps()>
         (lit("r"))[_val = MDSCapSpec(MDSCapSpec::READ)]
         );
 
-    grant = lit("allow") >> (capspec >> match)[_val = phoenix::construct<MDSCapGrant>(_1, _2)];
+    grant = lit("allow") >> (capspec >> match >>
+                            -(spaces >> lit("network") >> spaces >> network_str))
+      [_val = phoenix::construct<MDSCapGrant>(_1, _2, _3)];
     grants %= (grant % (*lit(' ') >> (lit(';') | lit(',')) >> *lit(' ')));
     mdscaps = grants  [_val = phoenix::construct<MDSAuthCaps>(_1)]; 
   }
   qi::rule<Iterator> spaces;
-  qi::rule<Iterator, string()> quoted_path, unquoted_path;
+  qi::rule<Iterator, string()> quoted_path, unquoted_path, network_str;
   qi::rule<Iterator, MDSCapSpec()> capspec;
   qi::rule<Iterator, string()> path;
   qi::rule<Iterator, uint32_t()> uid;
@@ -163,6 +167,12 @@ bool MDSCapMatch::match_path(std::string_view target_path) const
   return true;
 }
 
+void MDSCapGrant::parse_network()
+{
+  network_valid = ::parse_network(network.c_str(), &network_parsed,
+                                 &network_prefix);
+}
+
 /**
  * Is the client *potentially* able to access this path?  Actual
  * permission will depend on uids/modes in the full is_capable.
@@ -207,6 +217,13 @@ bool MDSAuthCaps::is_capable(std::string_view inode_path,
   for (std::vector<MDSCapGrant>::const_iterator i = grants.begin();
        i != grants.end();
        ++i) {
+    if (i->network.size() &&
+       (!i->network_valid ||
+        !network_contains(i->network_parsed,
+                          i->network_prefix,
+                          addr))) {
+      continue;
+    }
 
     if (i->match.match(inode_path, caller_uid, caller_gid, caller_gid_list) &&
        i->spec.allows(mask & (MAY_READ|MAY_EXECUTE), mask & MAY_WRITE)) {
@@ -287,7 +304,8 @@ bool MDSAuthCaps::is_capable(std::string_view inode_path,
 void MDSAuthCaps::set_allow_all()
 {
     grants.clear();
-    grants.push_back(MDSCapGrant(MDSCapSpec(MDSCapSpec::ALL), MDSCapMatch()));
+    grants.push_back(MDSCapGrant(MDSCapSpec(MDSCapSpec::ALL), MDSCapMatch(),
+                                {}));
 }
 
 bool MDSAuthCaps::parse(CephContext *c, std::string_view str, ostream *err)
@@ -295,7 +313,8 @@ bool MDSAuthCaps::parse(CephContext *c, std::string_view str, ostream *err)
   // Special case for legacy caps
   if (str == "allow") {
     grants.clear();
-    grants.push_back(MDSCapGrant(MDSCapSpec(MDSCapSpec::RWPS), MDSCapMatch()));
+    grants.push_back(MDSCapGrant(MDSCapSpec(MDSCapSpec::RWPS), MDSCapMatch(),
+                                {}));
     return true;
   }
 
@@ -308,6 +327,7 @@ bool MDSAuthCaps::parse(CephContext *c, std::string_view str, ostream *err)
   if (r && iter == end) {
     for (auto& grant : grants) {
       std::sort(grant.match.gids.begin(), grant.match.gids.end());
+      grant.parse_network();
     }
     return true;
   } else {
@@ -390,7 +410,9 @@ ostream &operator<<(ostream &out, const MDSCapGrant &grant)
   if (!grant.match.is_match_all()) {
     out << " " << grant.match;
   }
-
+  if (grant.network.size()) {
+    out << " network " << grant.network;
+  }
   return out;
 }
 
index 6297a456be6a145eec770b757e73ba4e4ebffdf5..c21df082137ed6b666327f37a11ee8fe3b0bfca9 100644 (file)
@@ -132,9 +132,23 @@ struct MDSCapGrant {
   MDSCapSpec spec;
   MDSCapMatch match;
 
-  MDSCapGrant(const MDSCapSpec &spec_, const MDSCapMatch &match_)
-    : spec(spec_), match(match_) {}
+  std::string network;
+
+  entity_addr_t network_parsed;
+  unsigned network_prefix = 0;
+  bool network_valid = true;
+
+  MDSCapGrant(const MDSCapSpec &spec_, const MDSCapMatch &match_,
+             boost::optional<std::string> n)
+    : spec(spec_), match(match_) {
+    if (n) {
+      network = *n;
+      parse_network();
+    }
+  }
   MDSCapGrant() {}
+
+  void parse_network();
 };
 
 class MDSAuthCaps
index 1accfeb85083a824b467e6f6b712248b29b4e197..fb65a117130f0b7f210c58784f909007dff8fcce 100644 (file)
@@ -914,7 +914,7 @@ Session *MDSRank::get_session(Message *m)
         imported_session->info.auth_name = session->info.auth_name;
         //assert(session->info.auth_name == imported_session->info.auth_name);
         assert(session->info.inst == imported_session->info.inst);
-        imported_session->connection = session->connection;
+        imported_session->set_connection(session->connection);
         // send out any queued messages
         while (!session->preopen_out_queue.empty()) {
           imported_session->connection->send_message(session->preopen_out_queue.front());
index 7b88a7d878757e3dd4680b307177d88d2b15e8be..deaddf51c0878ad4f72b25adc4fa62128bf7537d 100644 (file)
@@ -44,6 +44,8 @@ const char *parse_good[] = {
   "allow r ; allow * uid=1",
   "allow r ; allow * uid=1",
   "allow r uid=1 gids=1,2,3, allow * uid=2",
+  "allow r network 1.2.3.4/8",
+  "allow rw path=/foo uid=1 gids=1,2,3 network 2.3.4.5/16",
   0
 };
 
@@ -271,3 +273,17 @@ TEST(MDSAuthCaps, OutputParsed) {
     ASSERT_EQ(test_values[i].output, stringify(cap));
   }
 }
+
+TEST(MDSAuthCaps, network) {
+  entity_addr_t a, b, c;
+  a.parse("10.1.2.3");
+  b.parse("192.168.2.3");
+  c.parse("192.167.2.3");
+
+  MDSAuthCaps cap;
+  ASSERT_TRUE(cap.parse(g_ceph_context, "allow * network 192.168.0.0/16, allow * network 10.0.0.0/8", NULL));
+
+  ASSERT_TRUE(cap.is_capable("foo", 0, 0, 0777, 0, 0, NULL, MAY_READ, 0, 0, a));
+  ASSERT_TRUE(cap.is_capable("foo", 0, 0, 0777, 0, 0, NULL, MAY_READ, 0, 0, b));
+  ASSERT_FALSE(cap.is_capable("foo", 0, 0, 0777, 0, 0, NULL, MAY_READ, 0, 0, c));
+}