]>
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> | |
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 |
32 | int 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 | ||
85 | KeyRing *KeyRing::create_empty() | |
86 | { | |
87 | return new KeyRing(); | |
88 | } | |
89 | ||
11fdf7f2 TL |
90 | int 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 | ||
124 | void KeyRing::encode_plaintext(bufferlist& bl) | |
125 | { | |
126 | std::ostringstream os; | |
127 | print(os); | |
128 | string str = os.str(); | |
129 | bl.append(str); | |
130 | } | |
131 | ||
132 | void 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 | 161 | void 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 | 204 | void 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 | ||
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 { | |
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 | ||
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; | |
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 | ||
263 | void 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 |