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