initial code repo
[stor4nfv.git] / src / ceph / src / auth / KeyRing.cc
diff --git a/src/ceph/src/auth/KeyRing.cc b/src/ceph/src/auth/KeyRing.cc
new file mode 100644 (file)
index 0000000..b946a29
--- /dev/null
@@ -0,0 +1,275 @@
+// -*- 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-2009 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.
+ *
+ */
+
+#include <errno.h>
+#include <map>
+#include <memory>
+#include <sstream>
+#include <algorithm>
+#include "auth/KeyRing.h"
+#include "common/config.h"
+#include "common/debug.h"
+#include "common/errno.h"
+#include "common/Formatter.h"
+
+#define dout_subsys ceph_subsys_auth
+
+#undef dout_prefix
+#define dout_prefix *_dout << "auth: "
+
+using namespace std;
+
+int KeyRing::from_ceph_context(CephContext *cct)
+{
+  const md_config_t *conf = cct->_conf;
+  string filename;
+
+  int ret = ceph_resolve_file_search(conf->keyring, filename);
+  if (!ret) {
+    ret = load(cct, filename);
+    if (ret < 0)
+      lderr(cct) << "failed to load " << filename
+                << ": " << cpp_strerror(ret) << dendl;
+  } else {
+    lderr(cct) << "unable to find a keyring on " << conf->keyring
+              << ": " << cpp_strerror(ret) << dendl;
+  }
+
+  if (!conf->key.empty()) {
+    EntityAuth ea;
+    try {
+      ea.key.decode_base64(conf->key);
+      add(conf->name, ea);
+      return 0;
+    }
+    catch (buffer::error& e) {
+      lderr(cct) << "failed to decode key '" << conf->key << "'" << dendl;
+      return -EINVAL;
+    }
+  }
+
+  if (!conf->keyfile.empty()) {
+    bufferlist bl;
+    string err;
+    int r = bl.read_file(conf->keyfile.c_str(), &err);
+    if (r < 0) {
+      lderr(cct) << err << dendl;
+      return r;
+    }
+    string k(bl.c_str(), bl.length());
+    EntityAuth ea;
+    try {
+      ea.key.decode_base64(k);
+      add(conf->name, ea);
+    }
+    catch (buffer::error& e) {
+      lderr(cct) << "failed to decode key '" << k << "'" << dendl;
+      return -EINVAL;
+    }
+    return 0;
+  }
+
+  return ret;
+}
+
+KeyRing *KeyRing::create_empty()
+{
+  return new KeyRing();
+}
+
+int KeyRing::set_modifier(const char *type, const char *val, EntityName& name, map<string, bufferlist>& caps)
+{
+  if (!val)
+    return -EINVAL;
+
+  if (strcmp(type, "key") == 0) {
+    CryptoKey key;
+    string l(val);
+    try {
+      key.decode_base64(l);
+    } catch (const buffer::error& err) {
+      return -EINVAL;
+    }
+    set_key(name, key);
+  } else if (strncmp(type, "caps ", 5) == 0) {
+    const char *caps_entity = type + 5;
+    if (!*caps_entity)
+      return -EINVAL;
+    string l(val);
+    bufferlist bl;
+    ::encode(l, bl);
+    caps[caps_entity] = bl;
+    set_caps(name, caps);
+  } else if (strcmp(type, "auid") == 0) {
+    uint64_t auid = strtoull(val, NULL, 0);
+    set_uid(name, auid);
+  } else
+    return -EINVAL;
+
+  return 0;
+}
+
+void KeyRing::encode_plaintext(bufferlist& bl)
+{
+  std::ostringstream os;
+  print(os);
+  string str = os.str();
+  bl.append(str);
+}
+
+void KeyRing::encode_formatted(string label, Formatter *f, bufferlist& bl)
+{
+  std::ostringstream(os);
+  f->open_array_section(label.c_str());
+  for (map<EntityName, EntityAuth>::iterator p = keys.begin();
+       p != keys.end();
+       ++p) {
+
+    f->open_object_section("auth_entities");
+    f->dump_string("entity", p->first.to_str().c_str());
+    std::ostringstream keyss;
+    keyss << p->second.key;
+    f->dump_string("key", keyss.str());
+    if (p->second.auid != CEPH_AUTH_UID_DEFAULT)
+      f->dump_int("auid", p->second.auid);
+    f->open_object_section("caps");
+    for (map<string, bufferlist>::iterator q = p->second.caps.begin();
+        q != p->second.caps.end();
+        ++q) {
+      bufferlist::iterator dataiter = q->second.begin();
+      string caps;
+      ::decode(caps, dataiter);
+      f->dump_string(q->first.c_str(), caps);
+    }
+    f->close_section();        /* caps */
+    f->close_section();        /* auth_entities */
+  }
+  f->close_section();  /* auth_dump */
+  f->flush(bl);
+}
+
+void KeyRing::decode_plaintext(bufferlist::iterator& bli)
+{
+  int ret;
+  bufferlist bl;
+  bli.copy_all(bl);
+  ConfFile cf;
+  std::deque<std::string> parse_errors;
+
+  if (cf.parse_bufferlist(&bl, &parse_errors, NULL) != 0) {
+    throw buffer::malformed_input("cannot parse buffer");
+  }
+
+  for (ConfFile::const_section_iter_t s = cf.sections_begin();
+           s != cf.sections_end(); ++s) {
+    string name = s->first;
+    if (name == "global")
+      continue;
+
+    EntityName ename;
+    map<string, bufferlist> caps;
+    if (!ename.from_str(name)) {
+      ostringstream oss;
+      oss << "bad entity name in keyring: " << name;
+      throw buffer::malformed_input(oss.str().c_str());
+    }
+
+    for (ConfSection::const_line_iter_t l = s->second.lines.begin();
+        l != s->second.lines.end(); ++l) {
+      if (l->key.empty())
+        continue;
+      string k(l->key);
+      std::replace(k.begin(), k.end(), '_', ' ');
+      ret = set_modifier(k.c_str(), l->val.c_str(), ename, caps);
+      if (ret < 0) {
+       ostringstream oss;
+       oss << "error setting modifier for [" << name << "] type=" << k
+           << " val=" << l->val;
+       throw buffer::malformed_input(oss.str().c_str());
+      }
+    }
+  }
+}
+
+void KeyRing::decode(bufferlist::iterator& bl) {
+  __u8 struct_v;
+  bufferlist::iterator start_pos = bl;
+  try {
+    ::decode(struct_v, bl);
+    ::decode(keys, bl);
+  } catch (buffer::error& err) {
+    keys.clear();
+    decode_plaintext(start_pos);
+  }
+}
+
+int KeyRing::load(CephContext *cct, const std::string &filename)
+{
+  if (filename.empty())
+    return -EINVAL;
+
+  bufferlist bl;
+  std::string err;
+  int ret = bl.read_file(filename.c_str(), &err);
+  if (ret < 0) {
+    lderr(cct) << "error reading file: " << filename << ": " << err << dendl;
+    return ret;
+  }
+
+  try {
+    bufferlist::iterator iter = bl.begin();
+    decode(iter);
+  }
+  catch (const buffer::error& err) {
+    lderr(cct) << "error parsing file " << filename << dendl;
+    return -EIO;
+  }
+
+  ldout(cct, 2) << "KeyRing::load: loaded key file " << filename << dendl;
+  return 0;
+}
+
+void KeyRing::print(ostream& out)
+{
+  for (map<EntityName, EntityAuth>::iterator p = keys.begin();
+       p != keys.end();
+       ++p) {
+    out << "[" << p->first << "]" << std::endl;
+    out << "\tkey = " << p->second.key << std::endl;
+    if (p->second.auid != CEPH_AUTH_UID_DEFAULT)
+      out << "\tauid = " << p->second.auid << std::endl;
+
+    for (map<string, bufferlist>::iterator q = p->second.caps.begin();
+        q != p->second.caps.end();
+        ++q) {
+      bufferlist::iterator dataiter = q->second.begin();
+      string caps;
+      ::decode(caps, dataiter);
+      out << "\tcaps " << q->first << " = \"" << caps << '"' << std::endl;
+    }
+  }
+}
+
+void KeyRing::import(CephContext *cct, KeyRing& other)
+{
+  for (map<EntityName, EntityAuth>::iterator p = other.keys.begin();
+       p != other.keys.end();
+       ++p) {
+    ldout(cct, 10) << " importing " << p->first << dendl;
+    ldout(cct, 30) << "    " << p->second << dendl;
+    keys[p->first] = p->second;
+  }
+}
+
+