]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/mds/MDSAuthCaps.cc
import ceph 16.2.6
[ceph.git] / ceph / src / mds / MDSAuthCaps.cc
index 7f9f4b02a34bbaeaae4c1773d5d797669a31a02d..b78ebd6615b792f8ec9be0d99893e7d10f03df3c 100644 (file)
  * 
  */
 
-#include <boost/utility/string_view.hpp>
+#include <string_view>
 
 #include <errno.h>
-#include <fcntl.h>
 
 #include <boost/spirit/include/qi.hpp>
 #include <boost/spirit/include/phoenix_operator.hpp>
@@ -23,6 +22,8 @@
 
 #include "common/debug.h"
 #include "MDSAuthCaps.h"
+#include "mdstypes.h"
+#include "include/ipaddr.h"
 
 #define dout_subsys ceph_subsys_mds
 
@@ -31,6 +32,7 @@
 
 using std::ostream;
 using std::string;
+using std::vector;
 namespace qi = boost::spirit::qi;
 namespace ascii = boost::spirit::ascii;
 namespace phoenix = boost::phoenix;
@@ -40,6 +42,8 @@ struct MDSCapParser : qi::grammar<Iterator, MDSAuthCaps()>
 {
   MDSCapParser() : MDSCapParser::base_type(mdscaps)
   {
+    using qi::attr;
+    using qi::bool_;
     using qi::char_;
     using qi::int_;
     using qi::uint_;
@@ -58,36 +62,65 @@ 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][");
+    fs_name_str %= +char_("a-zA-Z0-9_.-");
 
     // match := [path=<path>] [uid=<uid> [gids=<gid>[,<gid>...]]
+    // TODO: allow fsname, and root_squash to be specified with uid, and gidlist
     path %= (spaces >> lit("path") >> lit('=') >> (quoted_path | unquoted_path));
     uid %= (spaces >> lit("uid") >> lit('=') >> uint_);
     uintlist %= (uint_ % lit(','));
     gidlist %= -(spaces >> lit("gids") >> lit('=') >> uintlist);
+    fs_name %= -(spaces >> lit("fsname") >> lit('=') >> fs_name_str);
+    root_squash %= (spaces >> lit("root_squash") >> attr(true));
     match = -(
+             (fs_name >> path >> root_squash)[_val = phoenix::construct<MDSCapMatch>(_2, _1, _3)] |
             (uid >> gidlist)[_val = phoenix::construct<MDSCapMatch>(_1, _2)] |
             (path >> uid >> gidlist)[_val = phoenix::construct<MDSCapMatch>(_1, _2, _3)] |
-             (path)[_val = phoenix::construct<MDSCapMatch>(_1)]);
-
-    // capspec = * | r[w]
+             (fs_name >> path)[_val = phoenix::construct<MDSCapMatch>(_2, _1)] |
+             (fs_name >> root_squash)[_val = phoenix::construct<MDSCapMatch>(std::string(), _1, _2)] |
+             (path >> root_squash)[_val = phoenix::construct<MDSCapMatch>(_1, std::string(), _2)] |
+             (path)[_val = phoenix::construct<MDSCapMatch>(_1)] |
+             (root_squash)[_val = phoenix::construct<MDSCapMatch>(std::string(), std::string(), _1)] |
+             (fs_name)[_val = phoenix::construct<MDSCapMatch>(std::string(),
+                                                             _1)]);
+
+    // capspec = * | r[w][f][p][s]
     capspec = spaces >> (
-        lit("*")[_val = MDSCapSpec(true, true, true, true)]
+        lit("*")[_val = MDSCapSpec(MDSCapSpec::ALL)]
+        |
+        lit("all")[_val = MDSCapSpec(MDSCapSpec::ALL)]
+        |
+        (lit("rwfps"))[_val = MDSCapSpec(MDSCapSpec::RWFPS)]
+        |
+        (lit("rwps"))[_val = MDSCapSpec(MDSCapSpec::RWPS)]
+        |
+        (lit("rwfp"))[_val = MDSCapSpec(MDSCapSpec::RWFP)]
+        |
+        (lit("rwfs"))[_val = MDSCapSpec(MDSCapSpec::RWFS)]
+        |
+        (lit("rwp"))[_val = MDSCapSpec(MDSCapSpec::RWP)]
         |
-        (lit("rwp"))[_val = MDSCapSpec(true, true, false, true)]
+        (lit("rws"))[_val = MDSCapSpec(MDSCapSpec::RWS)]
         |
-        (lit("rw"))[_val = MDSCapSpec(true, true, false, false)]
+        (lit("rwf"))[_val = MDSCapSpec(MDSCapSpec::RWF)]
         |
-        (lit("r"))[_val = MDSCapSpec(true, false, false, false)]
+        (lit("rw"))[_val = MDSCapSpec(MDSCapSpec::RW)]
+        |
+        (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, string()> fs_name_str, fs_name, path;
+  qi::rule<Iterator, bool()> root_squash;
   qi::rule<Iterator, MDSCapSpec()> capspec;
-  qi::rule<Iterator, string()> path;
   qi::rule<Iterator, uint32_t()> uid;
   qi::rule<Iterator, std::vector<uint32_t>() > uintlist;
   qi::rule<Iterator, std::vector<uint32_t>() > gidlist;
@@ -109,7 +142,7 @@ void MDSCapMatch::normalize_path()
   // drop ..
 }
 
-bool MDSCapMatch::match(boost::string_view target_path,
+bool MDSCapMatch::match(std::string_view target_path,
                        const int caller_uid,
                        const int caller_gid,
                        const vector<uint64_t> *caller_gid_list) const
@@ -141,7 +174,7 @@ bool MDSCapMatch::match(boost::string_view target_path,
   return true;
 }
 
-bool MDSCapMatch::match_path(boost::string_view target_path) const
+bool MDSCapMatch::match_path(std::string_view target_path) const
 {
   if (path.length()) {
     if (target_path.find(path) != 0)
@@ -157,11 +190,17 @@ bool MDSCapMatch::match_path(boost::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.
  */
-bool MDSAuthCaps::path_capable(boost::string_view inode_path) const
+bool MDSAuthCaps::path_capable(std::string_view inode_path) const
 {
   for (const auto &i : grants) {
     if (i.match.match_path(inode_path)) {
@@ -179,13 +218,14 @@ bool MDSAuthCaps::path_capable(boost::string_view inode_path) const
  * This is true if any of the 'grant' clauses in the capability match the
  * requested path + op.
  */
-bool MDSAuthCaps::is_capable(boost::string_view inode_path,
+bool MDSAuthCaps::is_capable(std::string_view inode_path,
                             uid_t inode_uid, gid_t inode_gid,
                             unsigned inode_mode,
                             uid_t caller_uid, gid_t caller_gid,
                             const vector<uint64_t> *caller_gid_list,
                             unsigned mask,
-                            uid_t new_uid, gid_t new_gid) const
+                            uid_t new_uid, gid_t new_gid,
+                            const entity_addr_t& addr) const
 {
   if (cct)
     ldout(cct, 10) << __func__ << " inode(path /" << inode_path
@@ -197,20 +237,29 @@ bool MDSAuthCaps::is_capable(boost::string_view inode_path,
                   << " new " << new_uid << ":" << new_gid
                   << " cap: " << *this << dendl;
 
-  for (std::vector<MDSCapGrant>::const_iterator i = grants.begin();
-       i != grants.end();
-       ++i) {
+  for (const auto& grant : grants) {
+    if (grant.network.size() &&
+       (!grant.network_valid ||
+        !network_contains(grant.network_parsed,
+                          grant.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)) {
+    if (grant.match.match(inode_path, caller_uid, caller_gid, caller_gid_list) &&
+       grant.spec.allows(mask & (MAY_READ|MAY_EXECUTE), mask & MAY_WRITE)) {
+      if (grant.match.root_squash && ((caller_uid == 0) || (caller_gid == 0)) &&
+          (mask & MAY_WRITE)) {
+           continue;
+      }
       // we have a match; narrow down GIDs to those specifically allowed here
       vector<uint64_t> gids;
-      if (std::find(i->match.gids.begin(), i->match.gids.end(), caller_gid) !=
-         i->match.gids.end()) {
+      if (std::find(grant.match.gids.begin(), grant.match.gids.end(), caller_gid) !=
+         grant.match.gids.end()) {
        gids.push_back(caller_gid);
       }
       if (caller_gid_list) {
-       std::set_intersection(i->match.gids.begin(), i->match.gids.end(),
+       std::set_intersection(grant.match.gids.begin(), grant.match.gids.end(),
                              caller_gid_list->begin(), caller_gid_list->end(),
                              std::back_inserter(gids));
        std::sort(gids.begin(), gids.end());
@@ -219,13 +268,25 @@ bool MDSAuthCaps::is_capable(boost::string_view inode_path,
 
       // Spec is non-allowing if caller asked for set pool but spec forbids it
       if (mask & MAY_SET_VXATTR) {
-        if (!i->spec.allows_set_vxattr()) {
+        if (!grant.spec.allow_set_vxattr()) {
+          continue;
+        }
+      }
+
+      if (mask & MAY_SNAPSHOT) {
+        if (!grant.spec.allow_snapshot()) {
+          continue;
+        }
+      }
+
+      if (mask & MAY_FULL) {
+        if (!grant.spec.allow_full()) {
           continue;
         }
       }
 
       // check unix permissions?
-      if (i->match.uid == MDSCapMatch::MDS_AUTH_UID_ANY) {
+      if (grant.match.uid == MDSCapMatch::MDS_AUTH_UID_ANY) {
         return true;
       }
 
@@ -274,17 +335,17 @@ bool MDSAuthCaps::is_capable(boost::string_view inode_path,
 void MDSAuthCaps::set_allow_all()
 {
     grants.clear();
-    grants.push_back(MDSCapGrant(
-                       MDSCapSpec(true, true, true, true),
-                       MDSCapMatch()));
+    grants.push_back(MDSCapGrant(MDSCapSpec(MDSCapSpec::ALL), MDSCapMatch(),
+                                {}));
 }
 
-bool MDSAuthCaps::parse(CephContext *c, boost::string_view str, ostream *err)
+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(true, true, false, true), MDSCapMatch()));
+    grants.push_back(MDSCapGrant(MDSCapSpec(MDSCapSpec::RWPS), MDSCapMatch(),
+                                {}));
     return true;
   }
 
@@ -297,6 +358,7 @@ bool MDSAuthCaps::parse(CephContext *c, boost::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 {
@@ -304,8 +366,9 @@ bool MDSAuthCaps::parse(CephContext *c, boost::string_view str, ostream *err)
     grants.clear();
 
     if (err)
-      *err << "MDSAuthCaps parse failed, stopped at '" << std::string(iter, end)
-           << "' of '" << str << "'\n";
+      *err << "mds capability parse failed, stopped at '"
+          << std::string(iter, end)
+           << "' of '" << str << "'";
     return false; 
   }
 }
@@ -313,8 +376,8 @@ bool MDSAuthCaps::parse(CephContext *c, boost::string_view str, ostream *err)
 
 bool MDSAuthCaps::allow_all() const
 {
-  for (std::vector<MDSCapGrant>::const_iterator i = grants.begin(); i != grants.end(); ++i) {
-    if (i->match.is_match_all() && i->spec.allow_all()) {
+  for (const auto& grant : grants) {
+    if (grant.match.is_match_all() && grant.spec.allow_all()) {
       return true;
     }
   }
@@ -325,22 +388,25 @@ bool MDSAuthCaps::allow_all() const
 
 ostream &operator<<(ostream &out, const MDSCapMatch &match)
 {
+  if (!match.fs_name.empty()) {
+    out << " fsname=" << match.fs_name;
+  }
   if (match.path.length()) {
-    out << "path=\"/" << match.path << "\"";
-    if (match.uid != MDSCapMatch::MDS_AUTH_UID_ANY) {
-      out << " ";
-    }
+    out << " path=\"/" << match.path << "\"";
+  }
+  if (match.root_squash) {
+    out << " root_squash";
   }
   if (match.uid != MDSCapMatch::MDS_AUTH_UID_ANY) {
-    out << "uid=" << match.uid;
+    out << " uid=" << match.uid;
     if (!match.gids.empty()) {
       out << " gids=";
-      for (std::vector<gid_t>::const_iterator p = match.gids.begin();
-          p != match.gids.end();
-          ++p) {
-       if (p != match.gids.begin())
+      bool first = true;
+      for (const auto& gid : match.gids) {
+       if (!first)
          out << ',';
-       out << *p;
+       out << gid;
+        first = false;
       }
     }
   }
@@ -351,15 +417,24 @@ ostream &operator<<(ostream &out, const MDSCapMatch &match)
 
 ostream &operator<<(ostream &out, const MDSCapSpec &spec)
 {
-  if (spec.any) {
+  if (spec.allow_all()) {
     out << "*";
   } else {
-    if (spec.read) {
+    if (spec.allow_read()) {
       out << "r";
     }
-    if (spec.write) {
+    if (spec.allow_write()) {
       out << "w";
     }
+    if (spec.allow_full()) {
+      out << "f";
+    }
+    if (spec.allow_set_vxattr()) {
+      out << "p";
+    }
+    if (spec.allow_snapshot()) {
+      out << "s";
+    }
   }
 
   return out;
@@ -370,10 +445,10 @@ ostream &operator<<(ostream &out, const MDSCapGrant &grant)
 {
   out << "allow ";
   out << grant.spec;
-  if (!grant.match.is_match_all()) {
-    out << " " << grant.match;
+  out << grant.match;
+  if (grant.network.size()) {
+    out << " network " << grant.network;
   }
-
   return out;
 }