]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/mon/MonCap.cc
update sources to v12.1.2
[ceph.git] / ceph / src / mon / MonCap.cc
index af98eb2d863aeb81bc8d5a7401a74a6d71c43889..3096fd2b46ad16ff1983d815ab5e56ccefd5d8ef 100644 (file)
@@ -27,6 +27,9 @@
 
 #include <algorithm>
 
+#include <boost/regex.hpp>
+#include "include/assert.h"
+
 static inline bool is_not_alnum_space(char c)
 {
   return !(isalpha(c) || isdigit(c) || (c == '-') || (c == '_'));
@@ -60,10 +63,17 @@ ostream& operator<<(ostream& out, const mon_rwxa_t& p)
 
 ostream& operator<<(ostream& out, const StringConstraint& c)
 {
-  if (c.prefix.length())
-    return out << "prefix " << c.prefix;
-  else
+  switch (c.match_type) {
+  case StringConstraint::MATCH_TYPE_EQUAL:
     return out << "value " << c.value;
+  case StringConstraint::MATCH_TYPE_PREFIX:
+    return out << "prefix " << c.value;
+  case StringConstraint::MATCH_TYPE_REGEX:
+    return out << "regex " << c.value;
+  default:
+    break;
+  }
+  return out;
 }
 
 ostream& operator<<(ostream& out, const MonCapGrant& m)
@@ -79,10 +89,22 @@ ostream& operator<<(ostream& out, const MonCapGrant& m)
       for (map<string,StringConstraint>::const_iterator p = m.command_args.begin();
           p != m.command_args.end();
           ++p) {
-       if (p->second.value.length())
-         out << " " << maybe_quote_string(p->first) << "=" << maybe_quote_string(p->second.value);
-       else
-         out << " " << maybe_quote_string(p->first) << " prefix " << maybe_quote_string(p->second.prefix);
+        switch (p->second.match_type) {
+        case StringConstraint::MATCH_TYPE_EQUAL:
+         out << " " << maybe_quote_string(p->first) << "="
+              << maybe_quote_string(p->second.value);
+          break;
+        case StringConstraint::MATCH_TYPE_PREFIX:
+         out << " " << maybe_quote_string(p->first) << " prefix "
+              << maybe_quote_string(p->second.value);
+          break;
+        case StringConstraint::MATCH_TYPE_REGEX:
+         out << " " << maybe_quote_string(p->first) << " regex "
+              << maybe_quote_string(p->second.value);
+          break;
+        default:
+          break;
+        }
       }
     }
   }
@@ -108,8 +130,8 @@ BOOST_FUSION_ADAPT_STRUCT(MonCapGrant,
                          (mon_rwxa_t, allow))
 
 BOOST_FUSION_ADAPT_STRUCT(StringConstraint,
-                         (std::string, value)
-                         (std::string, prefix))
+                          (StringConstraint::MatchType, match_type)
+                         (std::string, value))
 
 // </magic>
 
@@ -176,66 +198,67 @@ void MonCapGrant::expand_profile_mon(const EntityName& name) const
     profile_grants.push_back(MonCapGrant("osd", MON_CAP_R | MON_CAP_W));
     profile_grants.push_back(MonCapGrant("auth", MON_CAP_R | MON_CAP_X));
     profile_grants.push_back(MonCapGrant("config-key", MON_CAP_R | MON_CAP_W));
-    string prefix = string("daemon-private/mgr/");
-    profile_grants.push_back(MonCapGrant("config-key get", "key",
-                                        StringConstraint("", prefix)));
-    profile_grants.push_back(MonCapGrant("config-key put", "key",
-                                        StringConstraint("", prefix)));
-    profile_grants.push_back(MonCapGrant("config-key exists", "key",
-                                        StringConstraint("", prefix)));
-    profile_grants.push_back(MonCapGrant("config-key delete", "key",
-                                        StringConstraint("", prefix)));
+    StringConstraint constraint(StringConstraint::MATCH_TYPE_PREFIX,
+                                "daemon-private/mgr/");
+    profile_grants.push_back(MonCapGrant("config-key get", "key", constraint));
+    profile_grants.push_back(MonCapGrant("config-key set", "key", constraint));
+    profile_grants.push_back(MonCapGrant("config-key put", "key", constraint));
+    profile_grants.push_back(MonCapGrant("config-key exists", "key", constraint));
+    profile_grants.push_back(MonCapGrant("config-key delete", "key", constraint));
   }
   if (profile == "osd" || profile == "mds" || profile == "mon" ||
       profile == "mgr") {
+    StringConstraint constraint(StringConstraint::MATCH_TYPE_PREFIX,
+                                string("daemon-private/") + stringify(name) +
+                                string("/"));
     string prefix = string("daemon-private/") + stringify(name) + string("/");
-    profile_grants.push_back(MonCapGrant("config-key get", "key", StringConstraint("", prefix)));
-    profile_grants.push_back(MonCapGrant("config-key put", "key", StringConstraint("", prefix)));
-    profile_grants.push_back(MonCapGrant("config-key exists", "key", StringConstraint("", prefix)));
-    profile_grants.push_back(MonCapGrant("config-key delete", "key", StringConstraint("", prefix)));
+    profile_grants.push_back(MonCapGrant("config-key get", "key", constraint));
+    profile_grants.push_back(MonCapGrant("config-key put", "key", constraint));
+    profile_grants.push_back(MonCapGrant("config-key set", "key", constraint));
+    profile_grants.push_back(MonCapGrant("config-key exists", "key", constraint));
+    profile_grants.push_back(MonCapGrant("config-key delete", "key", constraint));
   }
   if (profile == "bootstrap-osd") {
-    string prefix = "dm-crypt/osd";
-    profile_grants.push_back(MonCapGrant("config-key put", "key", StringConstraint("", prefix)));
     profile_grants.push_back(MonCapGrant("mon", MON_CAP_R));  // read monmap
     profile_grants.push_back(MonCapGrant("osd", MON_CAP_R));  // read osdmap
     profile_grants.push_back(MonCapGrant("mon getmap"));
-    profile_grants.push_back(MonCapGrant("osd create"));
-    profile_grants.push_back(MonCapGrant("auth get-or-create"));
-    profile_grants.back().command_args["entity"] = StringConstraint("", "client.");
-    prefix = "allow command \"config-key get\" with key=\"dm-crypt/osd/";
-    profile_grants.back().command_args["caps_mon"] = StringConstraint("", prefix);
-    profile_grants.push_back(MonCapGrant("auth add"));
-    profile_grants.back().command_args["entity"] = StringConstraint("", "osd.");
-    profile_grants.back().command_args["caps_mon"] = StringConstraint("allow profile osd", "");
-    profile_grants.back().command_args["caps_osd"] = StringConstraint("allow *", "");
+    profile_grants.push_back(MonCapGrant("osd new"));
   }
   if (profile == "bootstrap-mds") {
     profile_grants.push_back(MonCapGrant("mon", MON_CAP_R));  // read monmap
     profile_grants.push_back(MonCapGrant("osd", MON_CAP_R));  // read osdmap
     profile_grants.push_back(MonCapGrant("mon getmap"));
     profile_grants.push_back(MonCapGrant("auth get-or-create"));  // FIXME: this can expose other mds keys
-    profile_grants.back().command_args["entity"] = StringConstraint("", "mds.");
-    profile_grants.back().command_args["caps_mon"] = StringConstraint("allow profile mds", "");
-    profile_grants.back().command_args["caps_osd"] = StringConstraint("allow rwx", "");
-    profile_grants.back().command_args["caps_mds"] = StringConstraint("allow", "");
+    profile_grants.back().command_args["entity"] = StringConstraint(
+      StringConstraint::MATCH_TYPE_PREFIX, "mds.");
+    profile_grants.back().command_args["caps_mon"] = StringConstraint(
+      StringConstraint::MATCH_TYPE_EQUAL, "allow profile mds");
+    profile_grants.back().command_args["caps_osd"] = StringConstraint(
+      StringConstraint::MATCH_TYPE_EQUAL, "allow rwx");
+    profile_grants.back().command_args["caps_mds"] = StringConstraint(
+      StringConstraint::MATCH_TYPE_EQUAL, "allow");
   }
   if (profile == "bootstrap-mgr") {
     profile_grants.push_back(MonCapGrant("mon", MON_CAP_R));  // read monmap
     profile_grants.push_back(MonCapGrant("osd", MON_CAP_R));  // read osdmap
     profile_grants.push_back(MonCapGrant("mon getmap"));
     profile_grants.push_back(MonCapGrant("auth get-or-create"));  // FIXME: this can expose other mgr keys
-    profile_grants.back().command_args["entity"] = StringConstraint("", "mgr.");
-    profile_grants.back().command_args["caps_mon"] = StringConstraint("allow profile mgr", "");
+    profile_grants.back().command_args["entity"] = StringConstraint(
+      StringConstraint::MATCH_TYPE_PREFIX, "mgr.");
+    profile_grants.back().command_args["caps_mon"] = StringConstraint(
+      StringConstraint::MATCH_TYPE_EQUAL, "allow profile mgr");
   }
   if (profile == "bootstrap-rgw") {
     profile_grants.push_back(MonCapGrant("mon", MON_CAP_R));  // read monmap
     profile_grants.push_back(MonCapGrant("osd", MON_CAP_R));  // read osdmap
     profile_grants.push_back(MonCapGrant("mon getmap"));
     profile_grants.push_back(MonCapGrant("auth get-or-create"));  // FIXME: this can expose other mds keys
-    profile_grants.back().command_args["entity"] = StringConstraint("", "client.rgw.");
-    profile_grants.back().command_args["caps_mon"] = StringConstraint("allow rw", "");
-    profile_grants.back().command_args["caps_osd"] = StringConstraint("allow rwx", "");
+    profile_grants.back().command_args["entity"] = StringConstraint(
+      StringConstraint::MATCH_TYPE_PREFIX, "client.rgw.");
+    profile_grants.back().command_args["caps_mon"] = StringConstraint(
+      StringConstraint::MATCH_TYPE_EQUAL, "allow rw");
+    profile_grants.back().command_args["caps_osd"] = StringConstraint(
+      StringConstraint::MATCH_TYPE_EQUAL, "allow rwx");
   }
   if (profile == "fs-client") {
     profile_grants.push_back(MonCapGrant("mon", MON_CAP_R));
@@ -248,6 +271,18 @@ void MonCapGrant::expand_profile_mon(const EntityName& name) const
     profile_grants.push_back(MonCapGrant("osd", MON_CAP_R));
     profile_grants.push_back(MonCapGrant("pg", MON_CAP_R));
   }
+  if (profile == "rbd") {
+    profile_grants.push_back(MonCapGrant("mon", MON_CAP_R));
+    profile_grants.push_back(MonCapGrant("osd", MON_CAP_R));
+    profile_grants.push_back(MonCapGrant("pg", MON_CAP_R));
+
+    // exclusive lock dead-client blacklisting (IP+nonce required)
+    profile_grants.push_back(MonCapGrant("osd blacklist"));
+    profile_grants.back().command_args["blacklistop"] = StringConstraint(
+      StringConstraint::MATCH_TYPE_EQUAL, "add");
+    profile_grants.back().command_args["addr"] = StringConstraint(
+      StringConstraint::MATCH_TYPE_REGEX, "^[^/]/[0-9]*$");
+  }
 
   if (profile == "role-definer") {
     // grants ALL caps to the auth subsystem, read-only on the
@@ -284,14 +319,25 @@ mon_rwxa_t MonCapGrant::get_allowed(CephContext *cct,
       // argument must be present if a constraint exists
       if (q == c_args.end())
        return 0;
-      if (p->second.value.length()) {
-       // match value
+      switch (p->second.match_type) {
+      case StringConstraint::MATCH_TYPE_EQUAL:
        if (p->second.value != q->second)
          return 0;
-      } else {
-       // match prefix
-       if (q->second.find(p->second.prefix) != 0)
+        break;
+      case StringConstraint::MATCH_TYPE_PREFIX:
+       if (q->second.find(p->second.value) != 0)
          return 0;
+        break;
+      case StringConstraint::MATCH_TYPE_REGEX:
+        {
+         boost::regex pattern(p->second.value,
+                               boost::regex::basic | boost::regex::no_except);
+          if (pattern.empty() || !boost::regex_match(q->second, pattern))
+           return 0;
+        }
+        break;
+      default:
+        break;
       }
     }
     return MON_CAP_ALL;
@@ -436,9 +482,12 @@ struct MonCapParser : qi::grammar<Iterator, MonCap()>
     spaces = +(lit(' ') | lit('\n') | lit('\t'));
 
     // command := command[=]cmd [k1=v1 k2=v2 ...]
-    str_match = '=' >> str >> qi::attr(string());
-    str_prefix = spaces >> lit("prefix") >> spaces >> qi::attr(string()) >> str;
-    kv_pair = str >> (str_match | str_prefix);
+    str_match = '=' >> qi::attr(StringConstraint::MATCH_TYPE_EQUAL) >> str;
+    str_prefix = spaces >> lit("prefix") >> spaces >>
+                 qi::attr(StringConstraint::MATCH_TYPE_PREFIX) >> str;
+    str_regex = spaces >> lit("regex") >> spaces >>
+                 qi::attr(StringConstraint::MATCH_TYPE_REGEX) >> str;
+    kv_pair = str >> (str_match | str_prefix | str_regex);
     kv_map %= kv_pair >> *(spaces >> kv_pair);
     command_match = -spaces >> lit("allow") >> spaces >> lit("command") >> (lit('=') | spaces)
                            >> qi::attr(string()) >> qi::attr(string())
@@ -453,7 +502,8 @@ struct MonCapParser : qi::grammar<Iterator, MonCap()>
                              >> spaces >> rwxa;
 
     // profile foo
-    profile_match %= -spaces >> lit("allow") >> spaces >> lit("profile") >> (lit('=') | spaces)
+    profile_match %= -spaces >> -(lit("allow") >> spaces)
+                             >> lit("profile") >> (lit('=') | spaces)
                             >> qi::attr(string())
                             >> str
                             >> qi::attr(string())
@@ -490,7 +540,7 @@ struct MonCapParser : qi::grammar<Iterator, MonCap()>
   qi::rule<Iterator, string()> unquoted_word;
   qi::rule<Iterator, string()> str;
 
-  qi::rule<Iterator, StringConstraint()> str_match, str_prefix;
+  qi::rule<Iterator, StringConstraint()> str_match, str_prefix, str_regex;
   qi::rule<Iterator, pair<string, StringConstraint>()> kv_pair;
   qi::rule<Iterator, map<string, StringConstraint>()> kv_map;