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}
osd/ReplicatedPG.cc \
osd/Ager.cc \
osd/OSD.cc \
- osd/OSDCaps.cc \
+ osd/OSDCap.cc \
osd/Watch.cc \
osd/ClassHandler.cc \
osd/OpRequest.cc
osd/Ager.h\
osd/ClassHandler.h\
osd/OSD.h\
- osd/OSDCaps.h\
+ osd/OSDCap.h\
osd/OSDMap.h\
osd/ObjectVersioner.h\
osd/OpRequest.h\
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;
}
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();
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;
}
#include "common/LogClient.h"
#include "os/ObjectStore.h"
-#include "OSDCaps.h"
+#include "OSDCap.h"
#include "common/DecayCounter.h"
#include "osd/ClassHandler.h"
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;
}
--- /dev/null
+// -*- 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;
+}
+
--- /dev/null
+// -*- 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
+++ /dev/null
-// -*- 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;
-}
-
+++ /dev/null
-// -*- 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
--- /dev/null
+// -*- 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);
+}
+