]>
Commit | Line | Data |
---|---|---|
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 |
33 | int 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 |
86 | int 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 | ||
120 | void KeyRing::encode_plaintext(bufferlist& bl) | |
121 | { | |
122 | std::ostringstream os; | |
123 | print(os); | |
124 | string str = os.str(); | |
125 | bl.append(str); | |
126 | } | |
127 | ||
128 | void 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 | 157 | void 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 | 196 | void 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 | ||
209 | int 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 | ||
235 | void 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 | ||
256 | void 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 |