summaryrefslogtreecommitdiffstats
path: root/src/auth/KeyRing.cc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:54:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:54:28 +0000
commite6918187568dbd01842d8d1d2c808ce16a894239 (patch)
tree64f88b554b444a49f656b6c656111a145cbbaa28 /src/auth/KeyRing.cc
parentInitial commit. (diff)
downloadceph-b26c4052f3542036551aa9dec9caa4226e456195.tar.xz
ceph-b26c4052f3542036551aa9dec9caa4226e456195.zip
Adding upstream version 18.2.2.upstream/18.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/auth/KeyRing.cc')
-rw-r--r--src/auth/KeyRing.cc256
1 files changed, 256 insertions, 0 deletions
diff --git a/src/auth/KeyRing.cc b/src/auth/KeyRing.cc
new file mode 100644
index 000000000..eca429d0b
--- /dev/null
+++ b/src/auth/KeyRing.cc
@@ -0,0 +1,256 @@
+// -*- 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 <boost/algorithm/string/replace.hpp>
+#include "auth/KeyRing.h"
+#include "include/stringify.h"
+#include "common/ceph_context.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 std::map;
+using std::ostream;
+using std::ostringstream;
+using std::string;
+
+using ceph::bufferlist;
+using ceph::Formatter;
+
+int KeyRing::from_ceph_context(CephContext *cct)
+{
+ const auto& 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 if (conf->key.empty() && conf->keyfile.empty()) {
+ 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 (ceph::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 (ceph::buffer::error& e) {
+ lderr(cct) << "failed to decode key '" << k << "'" << dendl;
+ return -EINVAL;
+ }
+ return 0;
+ }
+
+ return ret;
+}
+
+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 ceph::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) {
+ // just ignore it so we can still decode "old" keyrings that have an 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)
+{
+ f->open_array_section(label.c_str());
+ for (const auto &[ename, eauth] : keys) {
+ f->open_object_section("auth_entities");
+ f->dump_string("entity", ename.to_str().c_str());
+ f->dump_string("key", stringify(eauth.key));
+ if (!eauth.pending_key.empty()) {
+ f->dump_string("pending_key", stringify(eauth.pending_key));
+ }
+ f->open_object_section("caps");
+ for (auto& [sys, capsbl] : eauth.caps) {
+ auto dataiter = capsbl.cbegin();
+ string caps;
+ ceph::decode(caps, dataiter);
+ f->dump_string(sys.c_str(), caps);
+ }
+ f->close_section(); /* caps */
+ f->close_section(); /* auth_entities */
+ }
+ f->close_section(); /* auth_dump */
+ f->flush(bl);
+}
+
+void KeyRing::decode(bufferlist::const_iterator& bli)
+{
+ int ret;
+ bufferlist bl;
+ bli.copy_all(bl);
+ ConfFile cf;
+
+ if (cf.parse_bufferlist(&bl, nullptr) != 0) {
+ throw ceph::buffer::malformed_input("cannot parse buffer");
+ }
+
+ for (auto& [name, section] : cf) {
+ 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 ceph::buffer::malformed_input(oss.str().c_str());
+ }
+
+ for (auto& [k, val] : section) {
+ if (k.empty())
+ continue;
+ string key;
+ std::replace_copy(k.begin(), k.end(), back_inserter(key), '_', ' ');
+ ret = set_modifier(key.c_str(), val.c_str(), ename, caps);
+ if (ret < 0) {
+ ostringstream oss;
+ oss << "error setting modifier for [" << name << "] type=" << key
+ << " val=" << val;
+ throw ceph::buffer::malformed_input(oss.str().c_str());
+ }
+ }
+ }
+}
+
+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 {
+ auto iter = bl.cbegin();
+ decode(iter);
+ }
+ catch (const ceph::buffer::error& err) {
+ lderr(cct) << "error parsing file " << filename << ": " << err.what() << dendl;
+ return -EIO;
+ }
+
+ ldout(cct, 2) << "KeyRing::load: loaded key file " << filename << dendl;
+ return 0;
+}
+
+void KeyRing::print(ostream& out)
+{
+ for (auto& [ename, eauth] : keys) {
+ out << "[" << ename << "]" << std::endl;
+ out << "\tkey = " << eauth.key << std::endl;
+ if (!eauth.pending_key.empty()) {
+ out << "\tpending key = " << eauth.pending_key << std::endl;
+ }
+
+ for (auto& [sys, capbl] : eauth.caps) {
+ auto dataiter = capbl.cbegin();
+ string caps;
+ ceph::decode(caps, dataiter);
+ boost::replace_all(caps, "\"", "\\\"");
+ out << "\tcaps " << sys << " = \"" << 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;
+ }
+}
+
+