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