Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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 "auth/KeyRing.h"
21 #include "common/config.h"
22 #include "common/debug.h"
23 #include "common/errno.h"
24 #include "common/Formatter.h"
25
26 #define dout_subsys ceph_subsys_auth
27
28 #undef dout_prefix
29 #define dout_prefix *_dout << "auth: "
30
31 using namespace std;
32
33 int KeyRing::from_ceph_context(CephContext *cct)
34 {
35   const md_config_t *conf = cct->_conf;
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
86 KeyRing *KeyRing::create_empty()
87 {
88   return new KeyRing();
89 }
90
91 int KeyRing::set_modifier(const char *type, const char *val, EntityName& name, map<string, bufferlist>& caps)
92 {
93   if (!val)
94     return -EINVAL;
95
96   if (strcmp(type, "key") == 0) {
97     CryptoKey key;
98     string l(val);
99     try {
100       key.decode_base64(l);
101     } catch (const buffer::error& err) {
102       return -EINVAL;
103     }
104     set_key(name, key);
105   } else if (strncmp(type, "caps ", 5) == 0) {
106     const char *caps_entity = type + 5;
107     if (!*caps_entity)
108       return -EINVAL;
109     string l(val);
110     bufferlist bl;
111     ::encode(l, bl);
112     caps[caps_entity] = bl;
113     set_caps(name, caps);
114   } else if (strcmp(type, "auid") == 0) {
115     uint64_t auid = strtoull(val, NULL, 0);
116     set_uid(name, auid);
117   } else
118     return -EINVAL;
119
120   return 0;
121 }
122
123 void KeyRing::encode_plaintext(bufferlist& bl)
124 {
125   std::ostringstream os;
126   print(os);
127   string str = os.str();
128   bl.append(str);
129 }
130
131 void KeyRing::encode_formatted(string label, Formatter *f, bufferlist& bl)
132 {
133   std::ostringstream(os);
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());
144     if (p->second.auid != CEPH_AUTH_UID_DEFAULT)
145       f->dump_int("auid", p->second.auid);
146     f->open_object_section("caps");
147     for (map<string, bufferlist>::iterator q = p->second.caps.begin();
148          q != p->second.caps.end();
149          ++q) {
150       bufferlist::iterator dataiter = q->second.begin();
151       string caps;
152       ::decode(caps, dataiter);
153       f->dump_string(q->first.c_str(), caps);
154     }
155     f->close_section(); /* caps */
156     f->close_section(); /* auth_entities */
157   }
158   f->close_section();   /* auth_dump */
159   f->flush(bl);
160 }
161
162 void KeyRing::decode_plaintext(bufferlist::iterator& bli)
163 {
164   int ret;
165   bufferlist bl;
166   bli.copy_all(bl);
167   ConfFile cf;
168   std::deque<std::string> parse_errors;
169
170   if (cf.parse_bufferlist(&bl, &parse_errors, NULL) != 0) {
171     throw buffer::malformed_input("cannot parse buffer");
172   }
173
174   for (ConfFile::const_section_iter_t s = cf.sections_begin();
175             s != cf.sections_end(); ++s) {
176     string name = s->first;
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 buffer::malformed_input(oss.str().c_str());
186     }
187
188     for (ConfSection::const_line_iter_t l = s->second.lines.begin();
189          l != s->second.lines.end(); ++l) {
190       if (l->key.empty())
191         continue;
192       string k(l->key);
193       std::replace(k.begin(), k.end(), '_', ' ');
194       ret = set_modifier(k.c_str(), l->val.c_str(), ename, caps);
195       if (ret < 0) {
196         ostringstream oss;
197         oss << "error setting modifier for [" << name << "] type=" << k
198             << " val=" << l->val;
199         throw buffer::malformed_input(oss.str().c_str());
200       }
201     }
202   }
203 }
204
205 void KeyRing::decode(bufferlist::iterator& bl) {
206   __u8 struct_v;
207   bufferlist::iterator start_pos = bl;
208   try {
209     ::decode(struct_v, bl);
210     ::decode(keys, bl);
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 {
231     bufferlist::iterator iter = bl.begin();
232     decode(iter);
233   }
234   catch (const buffer::error& err) {
235     lderr(cct) << "error parsing file " << filename << 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     if (p->second.auid != CEPH_AUTH_UID_DEFAULT)
251       out << "\tauid = " << p->second.auid << std::endl;
252
253     for (map<string, bufferlist>::iterator q = p->second.caps.begin();
254          q != p->second.caps.end();
255          ++q) {
256       bufferlist::iterator dataiter = q->second.begin();
257       string caps;
258       ::decode(caps, dataiter);
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