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   	int KeyRing::from_ceph_context(CephContext *cct)
34   	{
35   	  const auto& 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;
(1) Event fun_call_w_exception: Called function throws an exception of type "ceph::buffer::v14_2_0::bad_alloc". [details]
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   	int KeyRing::set_modifier(const char *type,
87   				  const char *val,
88   				  EntityName& name,
89   				  map<string, bufferlist>& caps)
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;
109  	    encode(l, bl);
110  	    caps[caps_entity] = bl;
111  	    set_caps(name, caps);
112  	  } else if (strcmp(type, "auid") == 0) {
113  	    // just ignore it so we can still decode "old" keyrings that have an auid
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  	{
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());
140  	    f->open_object_section("caps");
141  	    for (map<string, bufferlist>::iterator q = p->second.caps.begin();
142  		 q != p->second.caps.end();
143  		 ++q) {
144  	      auto dataiter = q->second.cbegin();
145  	      string caps;
146  	      using ceph::decode;
147  	      decode(caps, dataiter);
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  	
157  	void KeyRing::decode_plaintext(bufferlist::const_iterator& bli)
158  	{
159  	  int ret;
160  	  bufferlist bl;
161  	  bli.copy_all(bl);
162  	  ConfFile cf;
163  	
164  	  if (cf.parse_bufferlist(&bl, nullptr) != 0) {
165  	    throw buffer::malformed_input("cannot parse buffer");
166  	  }
167  	
168  	  for (auto& [name, section] : cf) {
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  	
180  	    for (auto& [k, val] : section) {
181  	      if (k.empty())
182  	        continue;
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);
186  	      if (ret < 0) {
187  		ostringstream oss;
188  		oss << "error setting modifier for [" << name << "] type=" << key
189  		    << " val=" << val;
190  		throw buffer::malformed_input(oss.str().c_str());
191  	      }
192  	    }
193  	  }
194  	}
195  	
196  	void KeyRing::decode(bufferlist::const_iterator& bl) {
197  	  __u8 struct_v;
198  	  auto start_pos = bl;
199  	  try {
200  	    using ceph::decode;
201  	    decode(struct_v, bl);
202  	    decode(keys, bl);
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 {
223  	    auto iter = bl.cbegin();
224  	    decode(iter);
225  	  }
226  	  catch (const buffer::error& err) {
227  	    lderr(cct) << "error parsing file " << filename << ": " << err.what() << dendl;
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;
242  	
243  	    for (map<string, bufferlist>::iterator q = p->second.caps.begin();
244  		 q != p->second.caps.end();
245  		 ++q) {
246  	      auto dataiter = q->second.cbegin();
247  	      string caps;
248  	      using ceph::decode;
249  	      decode(caps, dataiter);
250  	      boost::replace_all(caps, "\"", "\\\"");
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  	
268