#include "common/debug.h"
#include "MDSAuthCaps.h"
+#include "include/ipaddr.h"
#define dout_subsys ceph_subsys_mds
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));
(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;
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.
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)) {
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)
// 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;
}
if (r && iter == end) {
for (auto& grant : grants) {
std::sort(grant.match.gids.begin(), grant.match.gids.end());
+ grant.parse_network();
}
return true;
} else {
if (!grant.match.is_match_all()) {
out << " " << grant.match;
}
-
+ if (grant.network.size()) {
+ out << " network " << grant.network;
+ }
return out;
}
"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
};
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));
+}