]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
osd: reimplement OSDCap struct
authorSage Weil <sage@inktank.com>
Wed, 13 Jun 2012 02:16:28 +0000 (19:16 -0700)
committerSage Weil <sage@inktank.com>
Wed, 13 Jun 2012 02:16:28 +0000 (19:16 -0700)
The old OSDCaps had a few undesireable features:

 - deny
 - weird 'default permissions' semantics when auid matches and no other
   cap is specified
 - difficult to understand, maintain parser

This version is renamed and has a few nice features:

 - spirit grammar for parsing
 - simple internal grant structure with simple semantics
 - support for object prefix maches
 - partial support for per-class (not yet implmeented by the OSD)

Signed-off-by: Sage Weil <sage@inktank.com>
src/Makefile.am
src/osd/OSD.cc
src/osd/OSD.h
src/osd/OSDCap.cc [new file with mode: 0644]
src/osd/OSDCap.h [new file with mode: 0644]
src/osd/OSDCaps.cc [deleted file]
src/osd/OSDCaps.h [deleted file]
src/test/osd/osdcap.cc [new file with mode: 0644]

index c02f4c317489cbcc5242c1464a1579ceab94985a..f6204a02fef04bd24933876050031b9aa755876d 100644 (file)
@@ -679,6 +679,12 @@ unittest_daemon_config_LDADD =  ${UNITTEST_LDADD} ${LIBGLOBAL_LDA}
 unittest_daemon_config_CXXFLAGS = ${CRYPTO_CFLAGS} ${AM_CXXFLAGS} ${UNITTEST_CXXFLAGS}
 check_PROGRAMS += unittest_daemon_config
 
+unittest_osd_osdcap_SOURCES = test/osd/osdcap.cc
+unittest_osd_osdcap_LDFLAGS = $(PTHREAD_CFLAGS) ${AM_LDFLAGS}
+unittest_osd_osdcap_LDADD =  ${UNITTEST_LDADD} ${LIBGLOBAL_LDA} libosd.a
+unittest_osd_osdcap_CXXFLAGS = ${CRYPTO_CFLAGS} ${AM_CXXFLAGS} ${UNITTEST_CXXFLAGS}
+check_PROGRAMS += unittest_osd_osdcap
+
 #if WITH_RADOSGW
 #unittest_librgw_SOURCES = test/librgw.cc
 #unittest_librgw_LDFLAGS = -lrt $(PTHREAD_CFLAGS) -lcurl ${AM_LDFLAGS}
@@ -1163,7 +1169,7 @@ libosd_a_SOURCES = \
        osd/ReplicatedPG.cc \
        osd/Ager.cc \
        osd/OSD.cc \
-       osd/OSDCaps.cc \
+       osd/OSDCap.cc \
        osd/Watch.cc \
        osd/ClassHandler.cc \
        osd/OpRequest.cc
@@ -1582,7 +1588,7 @@ noinst_HEADERS = \
         osd/Ager.h\
        osd/ClassHandler.h\
         osd/OSD.h\
-        osd/OSDCaps.h\
+        osd/OSDCap.h\
         osd/OSDMap.h\
         osd/ObjectVersioner.h\
        osd/OpRequest.h\
index 5a59ed76ee680b7f307661c88e1934e5402f77fe..60596a793fd09350201df173d2dc586273a046f7 100644 (file)
@@ -2339,10 +2339,10 @@ void OSD::handle_command(MCommand *m)
     return;
   }
 
-  OSDCaps& caps = session->caps;
+  OSDCap& caps = session->caps;
   session->put();
 
-  if (!caps.allow_all || m->get_source().is_mon()) {
+  if (!caps.allow_all() || m->get_source().is_mon()) {
     client_messenger->send_message(new MCommandReply(m, -EPERM), con);
     m->put();
     return;
@@ -2760,13 +2760,23 @@ bool OSD::ms_verify_authorizer(Connection *con, int peer_type,
     }
 
     s->entity_name = name;
-    s->caps.set_allow_all(caps_info.allow_all);
-    s->caps.set_auid(auid);
+    if (caps_info.allow_all)
+      s->caps.set_allow_all();
+    s->auid = auid;
  
     if (caps_info.caps.length() > 0) {
-      bufferlist::iterator iter = caps_info.caps.begin();
-      s->caps.parse(iter);
-      dout(10) << " session " << s << " " << s->entity_name << " has caps " << s->caps << dendl;
+      bufferlist::iterator p = caps_info.caps.begin();
+      string str;
+      try {
+       ::decode(str, p);
+      }
+      catch (buffer::error& e) {
+      }
+      bool success = s->caps.parse(str);
+      if (success)
+       dout(10) << " session " << s << " " << s->entity_name << " has caps " << s->caps << " '" << str << "'" << dendl;
+      else
+       dout(10) << " session " << s << " " << s->entity_name << " failed to parse caps '" << str << "'" << dendl;
     }
     
     s->put();
@@ -5366,24 +5376,31 @@ bool OSD::op_has_sufficient_caps(PG *pg, MOSDOp *op)
     dout(0) << "op_has_sufficient_caps: no session for op " << *op << dendl;
     return false;
   }
-  OSDCaps& caps = session->caps;
+  OSDCap& caps = session->caps;
   session->put();
+  
+  string key = op->get_object_locator().key;
+  if (key.length() == 0)
+    key = op->get_oid().name;
+
+  const OSDCapSpec *spec = caps.get_cap(session->auid, pg->pool->name, pg->pool->auid, key);
+  // just do the rwx, for now!
+  rwxa_t perm = spec ? spec->allow : 0;
 
-  int perm = caps.get_pool_cap(pg->pool->name, pg->pool->auid);
   dout(20) << "op_has_sufficient_caps pool=" << pg->pool->id << " (" << pg->pool->name
-          << ") owner=" << pg->pool->auid << " perm=" << perm
+          << ") owner=" << pg->pool->auid << " allow=" << perm
           << " may_read=" << op->may_read()
           << " may_write=" << op->may_write()
           << " may_exec=" << op->may_exec()
            << " require_exec_caps=" << op->require_exec_caps() << dendl;
 
-  if (op->may_read() && !(perm & OSD_POOL_CAP_R)) {
+  if (op->may_read() && !(perm & OSD_CAP_R)) {
     dout(10) << " no READ permission to access pool " << pg->pool->name << dendl;
     return false;
-  } else if (op->may_write() && !(perm & OSD_POOL_CAP_W)) {
+  } else if (op->may_write() && !(perm & OSD_CAP_W)) {
     dout(10) << " no WRITE permission to access pool " << pg->pool->name << dendl;
     return false;
-  } else if (op->require_exec_caps() && !(perm & OSD_POOL_CAP_X)) {
+  } else if (op->require_exec_caps() && !(perm & OSD_CAP_X)) {
     dout(10) << " no EXEC permission to access pool " << pg->pool->name << dendl;
     return false;
   }
index 01365c3dccaf17703ea2a8df135b806bf1aaec86..1c3df1819c4ca74b318ff742319e2f7993e091c7 100644 (file)
@@ -26,7 +26,7 @@
 #include "common/LogClient.h"
 
 #include "os/ObjectStore.h"
-#include "OSDCaps.h"
+#include "OSDCap.h"
 
 #include "common/DecayCounter.h"
 #include "osd/ClassHandler.h"
@@ -238,13 +238,14 @@ private:
 public:
   struct Session : public RefCountedObject {
     EntityName entity_name;
-    OSDCaps caps;
+    OSDCap caps;
+    int64_t auid;
     epoch_t last_sent_epoch;
     Connection *con;
     std::map<void *, pg_t> watches;
     std::map<void *, entity_name_t> notifs;
 
-    Session() : last_sent_epoch(0), con(0) {}
+    Session() : auid(-1), last_sent_epoch(0), con(0) {}
     void add_notif(void *n, entity_name_t& name) {
       notifs[n] = name;
     }
diff --git a/src/osd/OSDCap.cc b/src/osd/OSDCap.cc
new file mode 100644 (file)
index 0000000..19cf90b
--- /dev/null
@@ -0,0 +1,202 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2009-2011 New Dream Network
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#include <boost/config/warning_disable.hpp>
+#include <boost/spirit/include/qi.hpp>
+#include <boost/spirit/include/phoenix_operator.hpp>
+#include <boost/spirit/include/phoenix.hpp>
+
+#include "OSDCap.h"
+#include "common/config.h"
+#include "common/debug.h"
+
+using std::ostream;
+using std::vector;
+
+ostream& operator<<(ostream& out, rwxa_t p)
+{ 
+  if (p & OSD_CAP_ANY)
+    return out << "*";
+
+  if (p & OSD_CAP_R)
+    out << "r";
+  if (p & OSD_CAP_W)
+    out << "w";
+  if (p & OSD_CAP_X)
+    out << "x";
+  return out;
+}
+
+ostream& operator<<(ostream& out, const OSDCapSpec& s)
+{
+  if (s.allow & OSD_CAP_ANY)
+    return out << "*";
+  if (s.allow) {
+    if (s.allow & OSD_CAP_R)
+      out << 'r';
+    if (s.allow & OSD_CAP_W)
+      out << 'w';
+    if (s.allow & OSD_CAP_X)
+      out << 'x';
+    return out;
+  }
+  if (s.class_name.length())
+    return out << "class '" << s.class_name << "' '" << s.class_allow << "'";
+  return out << s.allow;
+}
+
+ostream& operator<<(ostream& out, const OSDCapMatch& m)
+{
+  if (m.auid != -1LL) {
+    out << "auid " << m.auid << " ";
+  }
+  if (m.object_prefix.length()) {
+    out << "object_prefix " << m.object_prefix << " ";
+  }
+  if (m.pool_name.length()) {
+    out << "pool " << m.pool_name << " ";
+  }
+  return out;
+}
+
+bool OSDCapMatch::is_match(int64_t a, const string& pn, int64_t pool_auid, const string& object) const
+{
+  if (auid >= 0) {
+    if (auid != pool_auid)
+      return false;
+  }
+  if (pool_name.length()) {
+    if (pool_name != pn)
+      return false;
+  }
+  if (object_prefix.length()) {
+    if (object.find(object_prefix) != 0)
+      return false;
+  }
+  return true;
+}
+
+ostream& operator<<(ostream& out, const OSDCapGrant& g)
+{
+  return out << "grant(" << g.match << g.spec << ")";
+}
+
+
+bool OSDCap::allow_all() const
+{
+  for (vector<OSDCapGrant>::const_iterator p = grants.begin(); p != grants.end(); ++p)
+    if (p->spec.allow_all())
+      return true;
+  return false;
+}
+
+void OSDCap::set_allow_all()
+{
+  grants.clear();
+  grants.push_back(OSDCapGrant(OSDCapMatch(), OSDCapSpec(OSD_CAP_ANY)));
+}
+
+const OSDCapSpec *OSDCap::get_cap(int64_t auid, const string& pool_name, int64_t pool_auid, const string& object) const
+{
+  for (vector<OSDCapGrant>::const_iterator p = grants.begin(); p != grants.end(); ++p) {
+    if (p->match.is_match(auid, pool_name, pool_auid, object))
+      return &p->spec;
+  }
+  return NULL;
+}
+
+
+// grammar
+namespace qi = boost::spirit::qi;
+namespace ascii = boost::spirit::ascii;
+namespace phoenix = boost::phoenix;
+
+template <typename Iterator>
+struct OSDCapParser : qi::grammar<Iterator, OSDCap(), ascii::space_type>
+{
+  OSDCapParser() : OSDCapParser::base_type(osdcap)
+  {
+    using qi::char_;
+    using qi::int_;
+    using qi::lexeme;
+    using qi::alnum;
+    using qi::_val;
+    using qi::_1;
+    using qi::_2;
+    using qi::_3;
+    using qi::eps;
+    using qi::lit;
+
+    quoted_string %=
+      lexeme['"' >> +(char_ - '"') >> '"'] | 
+      lexeme['\'' >> +(char_ - '\'') >> '\''];
+    unquoted_word %= +(alnum | '_' | '-');
+    str %= quoted_string | unquoted_word;
+
+    // match := [pool <poolname> | uid <123>] [object_prefix <prefix>]
+    pool_name %= -(lit("pool") >> str);
+    object_prefix %= -(lit("object_prefix") >> str);
+    match = ( (lit("auid") >> int_ >> object_prefix)[_val = phoenix::construct<OSDCapMatch>(_1, _2)] |
+             (pool_name >> object_prefix)[_val = phoenix::construct<OSDCapMatch>(_1, _2)]);
+             
+
+    // rwxa := * | [r][w][x]
+    rwxa =
+      lit('*')[_val = OSD_CAP_ANY] |
+      ( eps[_val = 0] >>
+       ( lit('r')[_val |= OSD_CAP_R] ||
+         lit('w')[_val |= OSD_CAP_W] ||
+         lit('x')[_val |= OSD_CAP_X] ));
+
+    // capspec := * | rwx | class <name> [classcap]
+    capspec =
+      rwxa[_val = phoenix::construct<OSDCapSpec>(_1)] |
+      ( lit("class") >> ((str >> str)[_val = phoenix::construct<OSDCapSpec>(_1, _2)] |
+                        str[_val = phoenix::construct<OSDCapSpec>(_1, string())] ));
+
+    // grant := allow match capspec
+    grant = lit("allow") >> ((match >> capspec)[_val = phoenix::construct<OSDCapGrant>(_1, _2)]);
+
+    // osdcap := grant [grant ...]
+    osdcap %= (grant % (lit(';') | lit(',')))[_val = phoenix::construct<OSDCap>(_1)];
+  }
+  qi::rule<Iterator, unsigned(), ascii::space_type> rwxa;
+  qi::rule<Iterator, string(), ascii::space_type> quoted_string;
+  qi::rule<Iterator, string()> unquoted_word;
+  qi::rule<Iterator, string(), ascii::space_type> str;
+  qi::rule<Iterator, OSDCapSpec(), ascii::space_type> capspec;
+  qi::rule<Iterator, string(), ascii::space_type> pool_name;
+  qi::rule<Iterator, string(), ascii::space_type> object_prefix;
+  qi::rule<Iterator, OSDCapMatch(), ascii::space_type> match;
+  qi::rule<Iterator, OSDCapGrant(), ascii::space_type> grant;
+  qi::rule<Iterator, OSDCap(), ascii::space_type> osdcap;
+};
+
+bool OSDCap::parse(const string& str, ostream *err)
+{
+  OSDCapParser<string::const_iterator> g;
+  string::const_iterator iter = str.begin();
+  string::const_iterator end = str.end();
+
+  bool r = qi::phrase_parse(iter, end, g, ascii::space, *this);
+  if (r && iter == end)
+    return true;
+
+  if (err)
+    *err << "osdcap parse failed, stopped at '" << std::string(iter, end)
+        << "' of '" << str << "'\n";
+
+  return false; 
+}
+
diff --git a/src/osd/OSDCap.h b/src/osd/OSDCap.h
new file mode 100644 (file)
index 0000000..b5c5374
--- /dev/null
@@ -0,0 +1,115 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- 
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software 
+ * Foundation.  See file COPYING.
+ * 
+ * OSDCaps: Hold the capabilities associated with a single authenticated 
+ * user key. These are specified by text strings of the form
+ * "allow r" (which allows reading anything on the OSD)
+ * "allow rwx auid foo[,bar,baz]" (which allows full access to listed auids)
+ *  "allow rwx pool foo[,bar,baz]" (which allows full access to listed pools)
+ * "allow *" (which allows full access to EVERYTHING)
+ *
+ * The OSD assumes that anyone with * caps is an admin and has full
+ * message permissions. This means that only the monitor and the OSDs
+ * should get *
+ */
+
+#ifndef CEPH_OSDCAP_H
+#define CEPH_OSDCAP_H
+
+#include <ostream>
+using std::ostream;
+
+#include "include/types.h"
+
+
+#define OSD_CAP_R 0x01
+#define OSD_CAP_W 0x02
+#define OSD_CAP_X 0x04
+#define OSD_CAP_ANY 0xff
+#define OSD_CAP_ALL (OSD_CAP_R | OSD_CAP_W | OSD_CAP_X)
+
+typedef __u8 rwxa_t;
+
+ostream& operator<<(ostream& out, rwxa_t p);
+
+struct OSDCapSpec {
+  rwxa_t allow;
+  std::string class_name;
+  std::string class_allow;
+
+  OSDCapSpec() : allow(0) {}
+  OSDCapSpec(rwxa_t v) : allow(v) {}
+  OSDCapSpec(std::string n) : allow(0), class_name(n) {}
+  OSDCapSpec(std::string n, std::string a) : allow(0), class_name(n), class_allow(a) {}
+
+  bool allow_all() const {
+    return allow & OSD_CAP_ANY;
+  }
+};
+
+ostream& operator<<(ostream& out, const OSDCapSpec& s);
+
+
+struct OSDCapMatch {
+  int64_t auid;
+  std::string pool_name;
+  std::string object_prefix;
+
+  OSDCapMatch() : auid(CEPH_AUTH_UID_DEFAULT) {}
+  OSDCapMatch(std::string pl, std::string pre) : auid(CEPH_AUTH_UID_DEFAULT), pool_name(pl), object_prefix(pre) {}
+  OSDCapMatch(uint64_t auid, std::string pre) : auid(auid), object_prefix(pre) {}
+
+  /**
+   * check if given request parameters match our constraints
+   *
+   * @param auid requesting user's auid
+   * @param pool_name pool name
+   * @param pool_auid pool's auid
+   * @param object object name
+   * @return true if we match, false otherwise
+   */
+  bool is_match(int64_t auid, const std::string& pool_name, int64_t pool_auid, const std::string& object) const;
+};
+
+ostream& operator<<(ostream& out, const OSDCapMatch& m);
+
+
+struct OSDCapGrant {
+  OSDCapMatch match;
+  OSDCapSpec spec;
+
+  OSDCapGrant() {}
+  OSDCapGrant(OSDCapMatch m, OSDCapSpec s) : match(m), spec(s) {}
+};
+
+ostream& operator<<(ostream& out, const OSDCapGrant& g);
+
+
+struct OSDCap {
+  std::vector<OSDCapGrant> grants;
+
+  OSDCap() {}
+  OSDCap(std::vector<OSDCapGrant> g) : grants(g) {}
+
+  bool allow_all() const;
+  void set_allow_all();
+  bool parse(const std::string& str, ostream *err=NULL);
+
+  const OSDCapSpec *get_cap(int64_t auid, const std::string& pool_name, int64_t pool_auid, const std::string& object) const;
+};
+
+static inline ostream& operator<<(ostream& out, const OSDCap& cap) 
+{
+  return out << "osdcap" << cap.grants;
+}
+
+#endif
diff --git a/src/osd/OSDCaps.cc b/src/osd/OSDCaps.cc
deleted file mode 100644 (file)
index 3bb935e..0000000
+++ /dev/null
@@ -1,258 +0,0 @@
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
-// vim: ts=8 sw=2 smarttab
-/*
- * Ceph - scalable distributed file system
- *
- * Copyright (C) 2009-2011 New Dream Network
- *
- * This is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1, as published by the Free Software
- * Foundation.  See file COPYING.
- *
- */
-
-#include "OSDCaps.h"
-#include "common/config.h"
-#include "common/debug.h"
-
-CapMap::~CapMap()
-{
-}
-
-void PoolsMap::dump()
-{
-  map<string, OSDCap>::iterator it;
-  for (it = pools_map.begin(); it != pools_map.end(); ++it) {
-    generic_dout(0) << it->first << " -> (" << (int)it->second.allow << "." << (int)it->second.deny << ")" << dendl;
-  }
-}
-
-void PoolsMap::apply_caps(string& name, int& cap)
-{
-  map<string, OSDCap>::iterator iter;
-
-  if ((iter = pools_map.find(name)) != pools_map.end()) {
-    OSDCap& c = iter->second;
-    cap |= c.allow;
-    cap &= ~c.deny;
-  }
-}
-
-void AuidMap::apply_caps(uint64_t uid, int& cap)
-{
-  map<uint64_t, OSDCap>::iterator iter;
-
-  if ((iter = auid_map.find(uid)) != auid_map.end()) {
-    OSDCap& auid_cap = iter->second;
-    cap |= auid_cap.allow;
-    cap &= ~auid_cap.deny;
-  }
-}
-
-bool OSDCaps::get_next_token(string s, size_t& pos, string& token)
-{
-  int start = s.find_first_not_of(" \t", pos);
-  int end;
-
-  if (start < 0) {
-    return false; 
-  }
-
-  if (s[start] == '=' || s[start] == ',' || s[start] == ';') {
-    end = start + 1;
-  } else {
-    end = s.find_first_of(";,= \t", start+1);
-  }
-
-  if (end < 0) {
-    end=s.size();
-  }
-
-  token = s.substr(start, end - start);
-
-  pos = end;
-
-  return true;
-}
-
-bool OSDCaps::is_rwx(string& token, rwx_t& cap_val)
-{
-  const char *t = token.c_str();
-  int val = 0;
-
-  while (*t) {
-    switch (*t) {
-    case 'r':
-      val |= OSD_POOL_CAP_R;
-      break;
-    case 'w':
-      val |= OSD_POOL_CAP_W;
-      break;
-    case 'x':
-      val |= OSD_POOL_CAP_X;
-      break;
-    default:
-      return false;
-    }
-    t++;
-  }
-
-  cap_val = val;
-  return true;
-}
-
-bool OSDCaps::parse(bufferlist::iterator& iter)
-{
-  string s;
-
-  try {
-    ::decode(s, iter);
-
-    generic_dout(10) << "decoded caps: " << s << dendl;
-
-    size_t pos = 0;
-    string token;
-    bool init = true;
-
-    bool op_allow = false;
-    bool op_deny = false;
-    bool cmd_pool = false;
-    bool cmd_uid = false;
-    bool any_cmd = false;
-    bool got_eq = false;
-    list<string> name_list;
-    bool last_is_comma = false;
-    rwx_t cap_val = 0;
-
-    while (pos < s.size()) {
-      if (init) {
-        op_allow = false;
-        op_deny = false;
-        cmd_pool = false;
-       cmd_uid = false;
-        any_cmd = false;
-        got_eq = false;
-        last_is_comma = false;
-        cap_val = 0;
-        init = false;
-        name_list.clear();
-      }
-
-#define ASSERT_STATE(x) \
-do { \
-  if (!(x)) { \
-       derr << "error parsing caps at pos=" << pos << " (" #x ")" << dendl; \
-  } \
-} while (0)
-
-      if (get_next_token(s, pos, token)) {
-       if (token.compare("*") == 0) { //allow all operations 
-         ASSERT_STATE(op_allow);
-         allow_all = true;
-       } else if (token.compare("=") == 0) {
-          ASSERT_STATE(any_cmd);
-          got_eq = true;
-        } else if (token.compare("allow") == 0) {
-          ASSERT_STATE((!op_allow) && (!op_deny));
-          op_allow = true;
-        } else if (token.compare("deny") == 0) {
-          ASSERT_STATE((!op_allow) && (!op_deny));
-          op_deny = true;
-        } else if ((token.compare("pools") == 0) ||
-                   (token.compare("pool") == 0)) {
-          ASSERT_STATE(!cmd_uid && (op_allow || op_deny));
-          cmd_pool = true;
-          any_cmd = true;
-       } else if (token.compare("uid") == 0) {
-         ASSERT_STATE(!cmd_pool && (op_allow || op_deny));
-         any_cmd = true;
-         cmd_uid = true;
-        } else if (is_rwx(token, cap_val)) {
-          ASSERT_STATE(op_allow || op_deny);
-        } else if (token.compare(";") != 0) {
-         ASSERT_STATE(got_eq);
-          if (token.compare(",") == 0) {
-            ASSERT_STATE(!last_is_comma);
-           last_is_comma = true;
-          } else {
-            last_is_comma = false;
-            name_list.push_back(token);
-          }
-        }
-
-        if (token.compare(";") == 0 || pos >= s.size()) {
-          if (got_eq) {
-            ASSERT_STATE(name_list.size() > 0);
-           CapMap *working_map = &pools_map;
-           if (cmd_uid)
-             working_map = &auid_map;
-            for (list<string>::iterator iter2 = name_list.begin();
-                iter2 != name_list.end();
-                ++iter2) {
-              OSDCap& cap = working_map->get_cap(*iter2);
-              if (op_allow) {
-                cap.allow |= cap_val;
-              } else {
-                cap.deny |= cap_val;
-              }
-            }
-          } else {
-            if (op_allow) {
-              default_allow |= cap_val;
-            } else {
-              default_deny |= cap_val;
-            }
-          }
-          init = true;
-        }
-        
-      }
-    }
-  } catch (const buffer::error &err) {
-    return false;
-  }
-
-  generic_dout(10) << "default allow=" << (int)default_allow << " default_deny=" << (int) default_deny << dendl;
-  pools_map.dump();
-  return true;
-}
-
-/**
- * Get the caps given this OSDCaps object for a given pool id
- * and uid (the pool's owner).
- *
- * Basic strategy: chain of permissions: default allow -> auid
- * -> pool -> default_deny.
- *
- * Starting with default allowed caps. Next check if you have caps on
- * the auid and apply, then apply any caps granted on the pool
- * (this lets users give out caps to their auid but keep one pool
- * private, for instance).
- * If these two steps haven't given you explicit caps
- * on the pool, check if you're the pool owner and grant full.
- */
-int OSDCaps::get_pool_cap(string& pool_name, uint64_t uid)
-{
-  if (allow_all)
-    return OSD_POOL_CAP_ALL;
-
-  int explicit_cap = default_allow; //explicitly granted caps
-  
-  //if the owner is granted permissions on the pool owner's auid, grant them
-  auid_map.apply_caps(uid, explicit_cap);
-
-  //check for explicitly granted caps and apply if needed
-  pools_map.apply_caps(pool_name, explicit_cap);
-
-  //owner gets full perms by default:
-  if (uid == auid
-      && explicit_cap == 0) {
-    explicit_cap = OSD_POOL_CAP_ALL;
-  }
-
-  explicit_cap &= ~default_deny;
-
-  return explicit_cap;
-}
-
diff --git a/src/osd/OSDCaps.h b/src/osd/OSDCaps.h
deleted file mode 100644 (file)
index 5f06cd1..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- 
-// vim: ts=8 sw=2 smarttab
-/*
- * Ceph - scalable distributed file system
- *
- * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
- *
- * This is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2.1, as published by the Free Software 
- * Foundation.  See file COPYING.
- * 
- * OSDCaps: Hold the capabilities associated with a single authenticated 
- * user key. These are specified by text strings of the form
- * "allow r" (which allows reading anything on the OSD)
- * "allow rwx auid foo[,bar,baz]" (which allows full access to listed auids)
- *  "allow rwx pool foo[,bar,baz]" (which allows full access to listed pools)
- * "allow *" (which allows full access to EVERYTHING)
- *
- * The OSD assumes that anyone with * caps is an admin and has full
- * message permissions. This means that only the monitor and the OSDs
- * should get *
- */
-
-#ifndef CEPH_OSDCAPS_H
-#define CEPH_OSDCAPS_H
-
-#include "include/types.h"
-
-#define OSD_POOL_CAP_R 0x01
-#define OSD_POOL_CAP_W 0x02
-#define OSD_POOL_CAP_X 0x04
-
-#define OSD_POOL_CAP_ALL (OSD_POOL_CAP_R | OSD_POOL_CAP_W | OSD_POOL_CAP_X)
-
-typedef __u8 rwx_t;
-
-static inline ostream& operator<<(ostream& out, rwx_t p) {
-  if (p & OSD_POOL_CAP_R)
-    out << "r";
-  if (p & OSD_POOL_CAP_W)
-    out << "w";
-  if (p & OSD_POOL_CAP_X)
-    out << "x";
-  return out;
-}
-
-
-struct OSDCap {
-  rwx_t allow;
-  rwx_t deny;
-  OSDCap() : allow(0), deny(0) {}
-};
-
-static inline ostream& operator<<(ostream& out, const OSDCap& pc) {
-  return out << "(allow " << pc.allow << ", deny " << pc.deny << ")";
-}
-
-struct CapMap {
-  virtual ~CapMap();
-  virtual OSDCap& get_cap(string& name) = 0;
-};
-
-struct PoolsMap : public CapMap {
-  map<string, OSDCap> pools_map;
-
-  OSDCap& get_cap(string& name) { return pools_map[name]; }
-
-  void dump();
-  void apply_caps(string& name, int& cap);
-};
-
-struct AuidMap : public CapMap {
-  map<uint64_t, OSDCap> auid_map;
-
-  OSDCap& get_cap(string& name) {
-    uint64_t num = strtoll(name.c_str(), NULL, 10);
-    return auid_map[num];
-  }
-
-  void apply_caps(uint64_t uid, int& cap);
-};
-
-struct OSDCaps {
-  PoolsMap pools_map;
-  AuidMap auid_map;
-  rwx_t default_allow;
-  rwx_t default_deny;
-  bool allow_all;
-  uint64_t auid;
-
-  bool get_next_token(string s, size_t& pos, string& token);
-  bool is_rwx(string& token, rwx_t& cap_val);
-  
-  OSDCaps() : default_allow(0), default_deny(0), allow_all(false),
-             auid(CEPH_AUTH_UID_DEFAULT) {}
-  bool parse(bufferlist::iterator& iter);
-  int get_pool_cap(string& pool_name, uint64_t uid = CEPH_AUTH_UID_DEFAULT);
-  void set_allow_all(bool allow) { allow_all = allow; }
-  void set_auid(uint64_t uid) { auid = uid; }
-};
-
-static inline ostream& operator<<(ostream& out, const OSDCaps& c) {
-  return out << "osdcaps(pools=" << c.pools_map.pools_map << " default allow=" << c.default_allow << " default_deny=" << c.default_deny << ")";
-}
-
-#endif
diff --git a/src/test/osd/osdcap.cc b/src/test/osd/osdcap.cc
new file mode 100644 (file)
index 0000000..d3d38e8
--- /dev/null
@@ -0,0 +1,141 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2012 Inktank
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#include "osd/OSDCap.h"
+
+#include "gtest/gtest.h"
+
+const char *parse_good[] = {
+  "allow *",
+  "allow r",
+  "allow rwx",
+  "allow pool foo r",
+  "allow pool taco wx",
+  "allow pool taco object_prefix obj wx",
+  "allow pool taco object_prefix obj_with_underscores_and_no_quotes wx",
+  "allow pool 'weird name' rwx",
+  "allow pool \"weird name with ''s\" rwx",
+  "allow auid 123 rwx",
+  "allow pool foo rwx, allow pool bar r",
+  "allow pool foo rwx ; allow pool bar r",
+  "allow pool foo rwx ;allow pool bar r",
+  "allow pool foo rwx; allow pool bar r",
+  "  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 foo",
+  "allow class clsname \"clsthingidon'tunderstand\"",
+  0
+};
+
+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);
+  }
+}
+
+const char *parse_bad[] = {
+  "ALLOW r",
+  "allow rwx,",
+  "allow r pool foo",
+  "allow pool taco wwx",
+  "allow pool taco^funny&chars wwx",
+  "allow pool 'weird name'' rwx",
+  "allow object_prefix \"beforepool\" pool weird rwx",
+  "allow auid 123 pool asdf rwx",
+  "allow pool foo xrwx,, allow pool bar r",
+  ";allow pool foo rwx ; allow pool bar r",
+  "allow pool foo rwx ;allow pool bar r gibberish",
+  0
+};
+
+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);
+  }
+}
+
+TEST(OSDCap, AllowAll) {
+  OSDCap cap;
+  ASSERT_FALSE(cap.allow_all());
+
+  bool r = cap.parse("allow *", NULL);
+  ASSERT_TRUE(r);
+  ASSERT_TRUE(cap.allow_all());
+
+  const OSDCapSpec *s;
+  s = cap.get_cap(0, "foo", 0, "asdf");
+  ASSERT_TRUE(!!s);
+  ASSERT_TRUE((s->allow & (OSD_CAP_R|OSD_CAP_W|OSD_CAP_X)) == (OSD_CAP_R|OSD_CAP_W|OSD_CAP_X));
+}
+
+TEST(OSDCap, AllowPool) {
+  OSDCap cap;
+  bool r = cap.parse("allow pool foo rwx", NULL);
+  ASSERT_TRUE(r);
+
+  const OSDCapSpec *s;
+  s = cap.get_cap(0, "foo", 0, "");
+  ASSERT_TRUE(!!s);
+  ASSERT_EQ(s->allow, OSD_CAP_R|OSD_CAP_W|OSD_CAP_X);
+  s = cap.get_cap(0, "bar", 0, "");
+  ASSERT_TRUE(!s || !s->allow);
+}
+
+TEST(OSDCap, AllowPools) {
+  OSDCap cap;
+  bool r = cap.parse("allow pool foo rwx, allow pool bar r", NULL);
+  ASSERT_TRUE(r);
+
+  const OSDCapSpec *s;
+  s = cap.get_cap(0, "foo", 0, "");
+  ASSERT_TRUE(!!s);
+  ASSERT_EQ(s->allow, OSD_CAP_R|OSD_CAP_W|OSD_CAP_X);
+  s = cap.get_cap(0, "bar", 0, "");
+  ASSERT_TRUE(!!s);
+  ASSERT_EQ(s->allow, OSD_CAP_R);
+  s = cap.get_cap(0, "baz", 0, "");
+  ASSERT_TRUE(!s || !s->allow);
+}
+
+TEST(OSDCap, ObjectPrefix) {
+  OSDCap cap;
+  bool r = cap.parse("allow object_prefix foo rwx", NULL);
+  ASSERT_TRUE(r);
+
+  const OSDCapSpec *s;
+  s = cap.get_cap(0, "foo", 0, "foo");
+  ASSERT_TRUE(!!s);
+  ASSERT_EQ(s->allow, OSD_CAP_R|OSD_CAP_W|OSD_CAP_X);
+  s = cap.get_cap(0, "foo", 0, "food");
+  ASSERT_TRUE(!!s);
+  ASSERT_EQ(s->allow, OSD_CAP_R|OSD_CAP_W|OSD_CAP_X);
+  s = cap.get_cap(0, "foo", 0, "foo_bar");
+  ASSERT_TRUE(!!s);
+  ASSERT_EQ(s->allow, OSD_CAP_R|OSD_CAP_W|OSD_CAP_X);
+
+  s = cap.get_cap(0, "foo", 0, "_foo");
+  ASSERT_TRUE(!s || !s->allow);
+  s = cap.get_cap(0, "foo", 0, " foo ");
+  ASSERT_TRUE(!s || !s->allow);
+  s = cap.get_cap(0, "foo", 0, " foo ");
+  ASSERT_TRUE(!s || !s->allow);
+}
+