]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mon: whitelist individual commands in mon cap string
authorSage Weil <sage@newdream.net>
Tue, 23 Aug 2011 20:56:46 +0000 (13:56 -0700)
committerSage Weil <sage@newdream.net>
Tue, 23 Aug 2011 20:56:46 +0000 (13:56 -0700)
This lets you whitelist a command prefix.  For example,

 'allow command osd foo'

will let you do any command that begins with 'osd foo', including
'osd foo' and 'osd foo bar baz bam'.

No deny, and no pattern matching.

Signed-off-by: Sage Weil <sage@newdream.net>
src/include/ceph_fs.h
src/mon/MonCaps.cc
src/mon/MonCaps.h
src/mon/Monitor.cc
src/mon/Monitor.h

index bea17f95bee0d2c4d67eb2fdecf7b3c34e1eb8d3..999e75724f305313a6f471c6e7b20fbbfeef68dd 100644 (file)
@@ -23,7 +23,7 @@
  */
 #define CEPH_OSD_PROTOCOL     8 /* cluster internal */
 #define CEPH_MDS_PROTOCOL    14 /* cluster internal */
-#define CEPH_MON_PROTOCOL     7 /* cluster internal */
+#define CEPH_MON_PROTOCOL     8 /* cluster internal */
 #define CEPH_OSDC_PROTOCOL   24 /* server/client */
 #define CEPH_MDSC_PROTOCOL   32 /* server/client */
 #define CEPH_MONC_PROTOCOL   15 /* server/client */
index 5145aa2fcb42661837590d233f3671c0c40e8942..8948edc82a1742c3b204a78b0dc7177fae974536 100644 (file)
@@ -112,6 +112,8 @@ bool MonCaps::parse(bufferlist::iterator& iter)
     bool op_deny = false;
     bool any_cmd = false;
     bool got_eq = false;
+    bool got_command = false;
+    list<string> command;
     list<int> services_list;
     list<int> uid_list;
     bool last_is_comma = false;
@@ -123,6 +125,8 @@ bool MonCaps::parse(bufferlist::iterator& iter)
         op_deny = false;
         any_cmd = false;
         got_eq = false;
+       got_command = false;
+       command.clear();
         last_is_comma = false;
         cap_val = 0;
         init = false;
@@ -141,6 +145,9 @@ do { \
        if (token.compare("*") == 0) { //allow all operations
          ASSERT_STATE(op_allow);
          allow_all = true;
+       } else if (token.compare("command") == 0) {
+         ASSERT_STATE(op_allow);
+         got_command = true;
        } else if (token.compare("=") == 0) {
           ASSERT_STATE(any_cmd);
           got_eq = true;
@@ -160,26 +167,34 @@ do { \
        } 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);
-          } else {
-            last_is_comma = false;
-           int service = get_service_id(token);
-            if (service != -EINVAL) {
-             if (service >= 0) {
-               services_list.push_back(service);
-             } else {
-               generic_dout(0) << "error parsing caps at pos=" << pos << ", unknown service_name: " << token << dendl;
+         if (got_command) {
+           command.push_back(token);
+         } else {
+           ASSERT_STATE(got_eq);
+           if (token.compare(",") == 0) {
+             ASSERT_STATE(!last_is_comma);
+           } else {
+             last_is_comma = false;
+             int service = get_service_id(token);
+             if (service != -EINVAL) {
+               if (service >= 0) {
+                 services_list.push_back(service);
+               } else {
+                 generic_dout(0) << "error parsing caps at pos=" << pos << ", unknown service_name: " << token << dendl;
+               }
+             } else { //must be a uid
+               uid_list.push_back(strtoul(token.c_str(), NULL, 10));
              }
-           } else { //must be a uid
-             uid_list.push_back(strtoul(token.c_str(), NULL, 10));
            }
           }
         }
 
         if (token.compare(";") == 0 || pos >= s.size()) {
-          if (got_eq) {
+         if (got_command) {
+           generic_dout(0) << "parsed command " << command << dendl;
+           cmd_allow.push_back(command);
+         }
+         else if (got_eq) {
             ASSERT_STATE((services_list.size() > 0) ||
                         (uid_list.size() > 0));
             
index eeb2c90295988322a6abf4d55fc90aebe2621d7e..3738c787f29195504dc359cc34c18eb1788027c0 100644 (file)
@@ -68,9 +68,15 @@ struct MonCaps {
   int get_service_id(string& token);
   bool allow_all;
   uint64_t auid;
+
+  // command whitelist
+  list<list<string> > cmd_allow;
+
 public:
-  MonCaps() : text(), default_action(0),
-             allow_all(false), auid(CEPH_AUTH_UID_DEFAULT) {}
+  MonCaps()
+    : text(), default_action(0),
+      allow_all(false), auid(CEPH_AUTH_UID_DEFAULT)
+  {}
   const string& get_str() const { return text; }
   bool parse(bufferlist::iterator& iter);
   rwx_t get_caps(int service) const;
@@ -80,24 +86,29 @@ public:
   void set_auid(uint64_t uid) { auid = uid; }
 
   void encode(bufferlist& bl) const {
+    __u8 v = 2;
+    ::encode(v, bl);
     ::encode(text, bl);
     ::encode(default_action, bl);
     ::encode(services_map, bl);
     ::encode(pool_auid_map, bl);
     ::encode(allow_all, bl);
     ::encode(auid, bl);
+    ::encode(cmd_allow, bl);
   }
 
   void decode(bufferlist::iterator& bl) {
+    __u8 v;
+    ::decode(v, bl);
     ::decode(text, bl);
     ::decode(default_action, bl);
     ::decode(services_map, bl);
     ::decode(pool_auid_map, bl);
     ::decode(allow_all, bl);
     ::decode(auid, bl);
+    ::decode(cmd_allow, bl);
   }
 };
-
 WRITE_CLASS_ENCODER(MonCaps);
 
 inline ostream& operator<<(ostream& out, const MonCaps& m) {
index 52d06ab40a4f4cc2aed2f9a027d06d8e27b8b186..5058ecee3260c0dc759a2326087966672e088b6b 100644 (file)
@@ -299,6 +299,27 @@ void Monitor::lose_election(epoch_t epoch, set<int> &q, int l)
   resend_routed_requests();
 }
 
+bool Monitor::_allowed_command(MonSession *s, const vector<string>& cmd)
+{
+  if (s->caps.check_privileges(PAXOS_MONMAP, MON_CAP_ALL))
+    return true;
+
+  for (list<list<string> >::iterator p = s->caps.cmd_allow.begin();
+       p != s->caps.cmd_allow.end();
+       ++p) {
+    list<string>::iterator q;
+    int i = 0;
+    for (q = p->begin(); q != p->end(); ++q, ++i) {
+      if (*q != cmd[i])
+       break;
+    }
+    if (q == p->end())
+      return true;   // match
+  }
+
+  return false;
+}
+
 void Monitor::handle_command(MMonCommand *m)
 {
   if (ceph_fsid_compare(&m->fsid, &monmap->fsid)) {
@@ -308,8 +329,7 @@ void Monitor::handle_command(MMonCommand *m)
   }
 
   MonSession *session = m->get_session();
-  if (!session ||
-      !session->caps.check_privileges(PAXOS_MONMAP, MON_CAP_ALL)) {
+  if (!session || !_allowed_command(session, m->cmd)) {
     string rs = "Access denied";
     reply_command(m, -EACCES, rs, 0);
     return;
index 0bbaf5c816386b30b9a5ab7c8c75fac1614b3d67..4832ea7b13b1fae07b7579e33d916733f8bfe3f5 100644 (file)
@@ -150,6 +150,7 @@ public:
   void handle_get_version(MMonGetVersion *m);
   void handle_subscribe(MMonSubscribe *m);
   void handle_mon_get_map(MMonGetMap *m);
+  bool _allowed_command(MonSession *s, const vector<std::string>& cmd);
   void handle_command(class MMonCommand *m);
   void handle_observe(MMonObserve *m);
   void handle_route(MRoute *m);