]> git.proxmox.com Git - ceph.git/blame - ceph/src/auth/KeyRing.cc
import 15.2.0 Octopus source
[ceph.git] / ceph / src / auth / KeyRing.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3/*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2004-2009 Sage Weil <sage@newdream.net>
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15#include <errno.h>
16#include <map>
17#include <memory>
18#include <sstream>
19#include <algorithm>
494da23a 20#include <boost/algorithm/string/replace.hpp>
7c673cae 21#include "auth/KeyRing.h"
11fdf7f2 22#include "common/ceph_context.h"
7c673cae
FG
23#include "common/config.h"
24#include "common/debug.h"
25#include "common/errno.h"
26#include "common/Formatter.h"
27
28#define dout_subsys ceph_subsys_auth
29
30#undef dout_prefix
31#define dout_prefix *_dout << "auth: "
32
7c673cae
FG
33int KeyRing::from_ceph_context(CephContext *cct)
34{
11fdf7f2 35 const auto& conf = cct->_conf;
7c673cae
FG
36 string filename;
37
38 int ret = ceph_resolve_file_search(conf->keyring, filename);
39 if (!ret) {
40 ret = load(cct, filename);
41 if (ret < 0)
42 lderr(cct) << "failed to load " << filename
43 << ": " << cpp_strerror(ret) << dendl;
44 } else {
45 lderr(cct) << "unable to find a keyring on " << conf->keyring
46 << ": " << cpp_strerror(ret) << dendl;
47 }
48
49 if (!conf->key.empty()) {
50 EntityAuth ea;
51 try {
52 ea.key.decode_base64(conf->key);
53 add(conf->name, ea);
54 return 0;
55 }
56 catch (buffer::error& e) {
57 lderr(cct) << "failed to decode key '" << conf->key << "'" << dendl;
58 return -EINVAL;
59 }
60 }
61
62 if (!conf->keyfile.empty()) {
63 bufferlist bl;
64 string err;
65 int r = bl.read_file(conf->keyfile.c_str(), &err);
66 if (r < 0) {
67 lderr(cct) << err << dendl;
68 return r;
69 }
70 string k(bl.c_str(), bl.length());
71 EntityAuth ea;
72 try {
73 ea.key.decode_base64(k);
74 add(conf->name, ea);
75 }
76 catch (buffer::error& e) {
77 lderr(cct) << "failed to decode key '" << k << "'" << dendl;
78 return -EINVAL;
79 }
80 return 0;
81 }
82
83 return ret;
84}
85
11fdf7f2
TL
86int KeyRing::set_modifier(const char *type,
87 const char *val,
88 EntityName& name,
89 map<string, bufferlist>& caps)
7c673cae
FG
90{
91 if (!val)
92 return -EINVAL;
93
94 if (strcmp(type, "key") == 0) {
95 CryptoKey key;
96 string l(val);
97 try {
98 key.decode_base64(l);
99 } catch (const buffer::error& err) {
100 return -EINVAL;
101 }
102 set_key(name, key);
103 } else if (strncmp(type, "caps ", 5) == 0) {
104 const char *caps_entity = type + 5;
105 if (!*caps_entity)
106 return -EINVAL;
107 string l(val);
108 bufferlist bl;
11fdf7f2 109 encode(l, bl);
7c673cae
FG
110 caps[caps_entity] = bl;
111 set_caps(name, caps);
112 } else if (strcmp(type, "auid") == 0) {
11fdf7f2 113 // just ignore it so we can still decode "old" keyrings that have an auid
7c673cae
FG
114 } else
115 return -EINVAL;
116
117 return 0;
118}
119
120void KeyRing::encode_plaintext(bufferlist& bl)
121{
122 std::ostringstream os;
123 print(os);
124 string str = os.str();
125 bl.append(str);
126}
127
128void KeyRing::encode_formatted(string label, Formatter *f, bufferlist& bl)
129{
7c673cae
FG
130 f->open_array_section(label.c_str());
131 for (map<EntityName, EntityAuth>::iterator p = keys.begin();
132 p != keys.end();
133 ++p) {
134
135 f->open_object_section("auth_entities");
136 f->dump_string("entity", p->first.to_str().c_str());
137 std::ostringstream keyss;
138 keyss << p->second.key;
139 f->dump_string("key", keyss.str());
7c673cae
FG
140 f->open_object_section("caps");
141 for (map<string, bufferlist>::iterator q = p->second.caps.begin();
11fdf7f2 142 q != p->second.caps.end();
7c673cae 143 ++q) {
11fdf7f2 144 auto dataiter = q->second.cbegin();
7c673cae 145 string caps;
11fdf7f2
TL
146 using ceph::decode;
147 decode(caps, dataiter);
7c673cae
FG
148 f->dump_string(q->first.c_str(), caps);
149 }
150 f->close_section(); /* caps */
151 f->close_section(); /* auth_entities */
152 }
153 f->close_section(); /* auth_dump */
154 f->flush(bl);
155}
156
11fdf7f2 157void KeyRing::decode_plaintext(bufferlist::const_iterator& bli)
7c673cae
FG
158{
159 int ret;
160 bufferlist bl;
161 bli.copy_all(bl);
162 ConfFile cf;
7c673cae 163
9f95a23c 164 if (cf.parse_bufferlist(&bl, nullptr) != 0) {
7c673cae
FG
165 throw buffer::malformed_input("cannot parse buffer");
166 }
167
9f95a23c 168 for (auto& [name, section] : cf) {
7c673cae
FG
169 if (name == "global")
170 continue;
171
172 EntityName ename;
173 map<string, bufferlist> caps;
174 if (!ename.from_str(name)) {
175 ostringstream oss;
176 oss << "bad entity name in keyring: " << name;
177 throw buffer::malformed_input(oss.str().c_str());
178 }
179
9f95a23c
TL
180 for (auto& [k, val] : section) {
181 if (k.empty())
7c673cae 182 continue;
9f95a23c
TL
183 string key;
184 std::replace_copy(k.begin(), k.end(), back_inserter(key), '_', ' ');
185 ret = set_modifier(key.c_str(), val.c_str(), ename, caps);
7c673cae
FG
186 if (ret < 0) {
187 ostringstream oss;
9f95a23c
TL
188 oss << "error setting modifier for [" << name << "] type=" << key
189 << " val=" << val;
7c673cae
FG
190 throw buffer::malformed_input(oss.str().c_str());
191 }
192 }
193 }
194}
195
11fdf7f2 196void KeyRing::decode(bufferlist::const_iterator& bl) {
7c673cae 197 __u8 struct_v;
11fdf7f2 198 auto start_pos = bl;
7c673cae 199 try {
11fdf7f2
TL
200 using ceph::decode;
201 decode(struct_v, bl);
202 decode(keys, bl);
7c673cae
FG
203 } catch (buffer::error& err) {
204 keys.clear();
205 decode_plaintext(start_pos);
206 }
207}
208
209int KeyRing::load(CephContext *cct, const std::string &filename)
210{
211 if (filename.empty())
212 return -EINVAL;
213
214 bufferlist bl;
215 std::string err;
216 int ret = bl.read_file(filename.c_str(), &err);
217 if (ret < 0) {
218 lderr(cct) << "error reading file: " << filename << ": " << err << dendl;
219 return ret;
220 }
221
222 try {
11fdf7f2 223 auto iter = bl.cbegin();
7c673cae
FG
224 decode(iter);
225 }
226 catch (const buffer::error& err) {
11fdf7f2 227 lderr(cct) << "error parsing file " << filename << ": " << err.what() << dendl;
7c673cae
FG
228 return -EIO;
229 }
230
231 ldout(cct, 2) << "KeyRing::load: loaded key file " << filename << dendl;
232 return 0;
233}
234
235void KeyRing::print(ostream& out)
236{
237 for (map<EntityName, EntityAuth>::iterator p = keys.begin();
238 p != keys.end();
239 ++p) {
240 out << "[" << p->first << "]" << std::endl;
241 out << "\tkey = " << p->second.key << std::endl;
7c673cae
FG
242
243 for (map<string, bufferlist>::iterator q = p->second.caps.begin();
244 q != p->second.caps.end();
245 ++q) {
11fdf7f2 246 auto dataiter = q->second.cbegin();
7c673cae 247 string caps;
11fdf7f2
TL
248 using ceph::decode;
249 decode(caps, dataiter);
494da23a 250 boost::replace_all(caps, "\"", "\\\"");
7c673cae
FG
251 out << "\tcaps " << q->first << " = \"" << caps << '"' << std::endl;
252 }
253 }
254}
255
256void KeyRing::import(CephContext *cct, KeyRing& other)
257{
258 for (map<EntityName, EntityAuth>::iterator p = other.keys.begin();
259 p != other.keys.end();
260 ++p) {
261 ldout(cct, 10) << " importing " << p->first << dendl;
262 ldout(cct, 30) << " " << p->second << dendl;
263 keys[p->first] = p->second;
264 }
265}
266
267