1    	// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2    	// vim: ts=8 sw=2 smarttab
3    	
4    	#include "AuthRegistry.h"
5    	
6    	#include "cephx/CephxAuthorizeHandler.h"
7    	#ifdef HAVE_GSSAPI
8    	#include "krb/KrbAuthorizeHandler.hpp"
9    	#endif
10   	#include "none/AuthNoneAuthorizeHandler.h"
11   	#include "common/ceph_context.h"
12   	#include "common/debug.h"
13   	#include "auth/KeyRing.h"
14   	
15   	#define dout_subsys ceph_subsys_auth
16   	#undef dout_prefix
17   	#define dout_prefix *_dout << "AuthRegistry(" << this << ") "
18   	
19   	AuthRegistry::AuthRegistry(CephContext *cct)
20   	  : cct(cct)
21   	{
22   	  cct->_conf.add_observer(this);
23   	}
24   	
(1) Event exn_spec_violation: An exception of type "std::system_error" is thrown but the throw list "throw()" doesn't allow it to be thrown. This will cause a call to unexpected() which usually calls terminate().
Also see events: [fun_call_w_exception]
25   	AuthRegistry::~AuthRegistry()
26   	{
(2) Event fun_call_w_exception: Called function throws an exception of type "std::system_error". [details]
Also see events: [exn_spec_violation]
27   	  cct->_conf.remove_observer(this);
28   	  for (auto i : authorize_handlers) {
29   	    delete i.second;
30   	  }
31   	}
32   	
33   	const char** AuthRegistry::get_tracked_conf_keys() const
34   	{
35   	  static const char *keys[] = {
36   	    "auth_supported",
37   	    "auth_client_required",
38   	    "auth_cluster_required",
39   	    "auth_service_required",
40   	    "ms_mon_cluster_mode",
41   	    "ms_mon_service_mode",
42   	    "ms_mon_client_mode",
43   	    "ms_cluster_mode",
44   	    "ms_service_mode",
45   	    "ms_client_mode",
46   	    "keyring",
47   	    NULL
48   	  };
49   	  return keys;
50   	}
51   	
52   	void AuthRegistry::handle_conf_change(
53   	  const ConfigProxy& conf,
54   	  const std::set<std::string>& changed)
55   	{
56   	  std::scoped_lock l(lock);
57   	  _refresh_config();
58   	}
59   	
60   	
61   	void AuthRegistry::_parse_method_list(const string& s,
62   					      std::vector<uint32_t> *v)
63   	{
64   	  std::list<std::string> sup_list;
65   	  get_str_list(s, sup_list);
66   	  if (sup_list.empty()) {
67   	    lderr(cct) << "WARNING: empty auth protocol list" << dendl;
68   	  }
69   	  v->clear();
70   	  for (auto& i : sup_list) {
71   	    ldout(cct, 5) << "adding auth protocol: " << i << dendl;
72   	    if (i == "cephx") {
73   	      v->push_back(CEPH_AUTH_CEPHX);
74   	    } else if (i == "none") {
75   	      v->push_back(CEPH_AUTH_NONE);
76   	    } else if (i == "gss") {
77   	      v->push_back(CEPH_AUTH_GSS);
78   	    } else {
79   	      lderr(cct) << "WARNING: unknown auth protocol defined: " << i << dendl;
80   	    }
81   	  }
82   	  if (v->empty()) {
83   	    lderr(cct) << "WARNING: no auth protocol defined" << dendl;
84   	  }
85   	  ldout(cct,20) << __func__ << " " << s << " -> " << *v << dendl;
86   	}
87   	
88   	void AuthRegistry::_parse_mode_list(const string& s,
89   					    std::vector<uint32_t> *v)
90   	{
91   	  std::list<std::string> sup_list;
92   	  get_str_list(s, sup_list);
93   	  if (sup_list.empty()) {
94   	    lderr(cct) << "WARNING: empty auth protocol list" << dendl;
95   	  }
96   	  v->clear();
97   	  for (auto& i : sup_list) {
98   	    ldout(cct, 5) << "adding con mode: " << i << dendl;
99   	    if (i == "crc") {
100  	      v->push_back(CEPH_CON_MODE_CRC);
101  	    } else if (i == "secure") {
102  	      v->push_back(CEPH_CON_MODE_SECURE);
103  	    } else {
104  	      lderr(cct) << "WARNING: unknown connection mode " << i << dendl;
105  	    }
106  	  }
107  	  if (v->empty()) {
108  	    lderr(cct) << "WARNING: no connection modes defined" << dendl;
109  	  }
110  	  ldout(cct,20) << __func__ << " " << s << " -> " << *v << dendl;
111  	}
112  	
113  	void AuthRegistry::_refresh_config()
114  	{
115  	  if (cct->_conf->auth_supported.size()) {
116  	    _parse_method_list(cct->_conf->auth_supported, &cluster_methods);
117  	    _parse_method_list(cct->_conf->auth_supported, &service_methods);
118  	    _parse_method_list(cct->_conf->auth_supported, &client_methods);
119  	  } else {
120  	    _parse_method_list(cct->_conf->auth_cluster_required, &cluster_methods);
121  	    _parse_method_list(cct->_conf->auth_service_required, &service_methods);
122  	    _parse_method_list(cct->_conf->auth_client_required, &client_methods);
123  	  }
124  	  _parse_mode_list(cct->_conf.get_val<string>("ms_mon_cluster_mode"),
125  			   &mon_cluster_modes);
126  	  _parse_mode_list(cct->_conf.get_val<string>("ms_mon_service_mode"),
127  			   &mon_service_modes);
128  	  _parse_mode_list(cct->_conf.get_val<string>("ms_mon_client_mode"),
129  			   &mon_client_modes);
130  	  _parse_mode_list(cct->_conf.get_val<string>("ms_cluster_mode"),
131  			   &cluster_modes);
132  	  _parse_mode_list(cct->_conf.get_val<string>("ms_service_mode"),
133  			   &service_modes);
134  	  _parse_mode_list(cct->_conf.get_val<string>("ms_client_mode"),
135  			   &client_modes);
136  	
137  	  ldout(cct,10) << __func__ << " cluster_methods " << cluster_methods
138  			<< " service_methods " << service_methods
139  			<< " client_methods " << client_methods
140  			<< dendl;
141  	  ldout(cct,10) << __func__ << " mon_cluster_modes " << mon_cluster_modes
142  			<< " mon_service_modes " << mon_service_modes
143  			<< " mon_client_modes " << mon_client_modes
144  			<< "; cluster_modes " << cluster_modes
145  			<< " service_modes " << service_modes
146  			<< " client_modes " << client_modes
147  			<< dendl;
148  	
149  	  // if we have no keyring, filter out cephx
150  	  _no_keyring_disabled_cephx = false;
151  	  bool any_cephx = false;
152  	  for (auto *p : {&cluster_methods, &service_methods, &client_methods}) {
153  	    auto q = std::find(p->begin(), p->end(), CEPH_AUTH_CEPHX);
154  	    if (q != p->end()) {
155  	      any_cephx = true;
156  	      break;
157  	    }
158  	  }
159  	  if (any_cephx) {
160  	    KeyRing k;
161  	    int r = k.from_ceph_context(cct);
162  	    if (r == -ENOENT) {
163  	      for (auto *p : {&cluster_methods, &service_methods, &client_methods}) {
164  		auto q = std::find(p->begin(), p->end(), CEPH_AUTH_CEPHX);
165  		if (q != p->end()) {
166  		  p->erase(q);
167  		  _no_keyring_disabled_cephx = true;
168  		}
169  	      }
170  	    }
171  	    if (_no_keyring_disabled_cephx) {
172  	      lderr(cct) << "no keyring found at " << cct->_conf->keyring
173  		       << ", disabling cephx" << dendl;
174  	    }
175  	  }
176  	}
177  	
178  	void AuthRegistry::get_supported_methods(
179  	  int peer_type,
180  	  std::vector<uint32_t> *methods,
181  	  std::vector<uint32_t> *modes) const
182  	{
183  	  if (methods) {
184  	    methods->clear();
185  	  }
186  	  if (modes) {
187  	    modes->clear();
188  	  }
189  	  std::scoped_lock l(lock);
190  	  switch (cct->get_module_type()) {
191  	  case CEPH_ENTITY_TYPE_CLIENT:
192  	    // i am client
193  	    if (methods) {
194  	      *methods = client_methods;
195  	    }
196  	    if (modes) {
197  	      switch (peer_type) {
198  	      case CEPH_ENTITY_TYPE_MON:
199  		*modes = mon_client_modes;
200  		break;
201  	      default:
202  		*modes = client_modes;
203  	      }
204  	    }
205  	    return;
206  	  case CEPH_ENTITY_TYPE_MON:
207  	    // i am mon
208  	    switch (peer_type) {
209  	    case CEPH_ENTITY_TYPE_MON:
210  	      // they are mon
211  	      if (methods) {
212  		*methods = cluster_methods;
213  	      }
214  	      if (modes) {
215  		*modes = mon_cluster_modes;
216  	      }
217  	      break;
218  	    default:
219  	      // they are anything but mons
220  	      if (methods) {
221  		*methods = service_methods;
222  	      }
223  	      if (modes) {
224  		*modes = mon_service_modes;
225  	      }
226  	    }
227  	    return;
228  	  default:
229  	    // i am a non-mon daemon
230  	    switch (peer_type) {
231  	    case CEPH_ENTITY_TYPE_MON:
232  	    case CEPH_ENTITY_TYPE_MGR:
233  	    case CEPH_ENTITY_TYPE_MDS:
234  	    case CEPH_ENTITY_TYPE_OSD:
235  	      // they are another daemon
236  	      if (methods) {
237  		*methods = cluster_methods;
238  	      }
239  	      if (modes) {
240  		*modes = cluster_modes;
241  	      }
242  	      break;
243  	    default:
244  	      // they are a client
245  	      if (methods) {
246  		*methods = service_methods;
247  	      }
248  	      if (modes) {
249  		*modes = service_modes;
250  	      }
251  	      break;
252  	    }
253  	  }
254  	}
255  	
256  	bool AuthRegistry::is_supported_method(int peer_type, int method) const
257  	{
258  	  std::vector<uint32_t> s;
259  	  get_supported_methods(peer_type, &s);
260  	  return std::find(s.begin(), s.end(), method) != s.end();
261  	}
262  	
263  	bool AuthRegistry::any_supported_methods(int peer_type) const
264  	{
265  	  std::vector<uint32_t> s;
266  	  get_supported_methods(peer_type, &s);
267  	  return !s.empty();
268  	}
269  	
270  	void AuthRegistry::get_supported_modes(
271  	  int peer_type,
272  	  uint32_t auth_method,
273  	  std::vector<uint32_t> *modes) const
274  	{
275  	  std::vector<uint32_t> s;
276  	  get_supported_methods(peer_type, nullptr, &s);
277  	  if (auth_method == CEPH_AUTH_NONE) {
278  	    // filter out all but crc for AUTH_NONE
279  	    modes->clear();
280  	    for (auto mode : s) {
281  	      if (mode == CEPH_CON_MODE_CRC) {
282  		modes->push_back(mode);
283  	      }
284  	    }
285  	  } else {
286  	    *modes = s;
287  	  }
288  	}
289  	
290  	uint32_t AuthRegistry::pick_mode(
291  	  int peer_type,
292  	  uint32_t auth_method,
293  	  const std::vector<uint32_t>& preferred_modes)
294  	{
295  	  std::vector<uint32_t> allowed_modes;
296  	  get_supported_modes(peer_type, auth_method, &allowed_modes);
297  	  for (auto mode : preferred_modes) {
298  	    if (std::find(allowed_modes.begin(), allowed_modes.end(), mode)
299  		!= allowed_modes.end()) {
300  	      return mode;
301  	    }
302  	  }
303  	  ldout(cct,1) << "failed to pick con mode from client's " << preferred_modes
304  		       << " and our " << allowed_modes << dendl;
305  	  return CEPH_CON_MODE_UNKNOWN;
306  	}
307  	
308  	AuthAuthorizeHandler *AuthRegistry::get_handler(int peer_type, int method)
309  	{
310  	  std::scoped_lock l{lock};
311  	  ldout(cct,20) << __func__ << " peer_type " << peer_type << " method " << method
312  			<< " cluster_methods " << cluster_methods
313  			<< " service_methods " << service_methods
314  			<< " client_methods " << client_methods
315  			<< dendl;
316  	  if (cct->get_module_type() == CEPH_ENTITY_TYPE_CLIENT) {
317  	    return nullptr;
318  	  }
319  	  switch (peer_type) {
320  	  case CEPH_ENTITY_TYPE_MON:
321  	  case CEPH_ENTITY_TYPE_MGR:
322  	  case CEPH_ENTITY_TYPE_MDS:
323  	  case CEPH_ENTITY_TYPE_OSD:
324  	    if (std::find(cluster_methods.begin(), cluster_methods.end(), method) ==
325  		cluster_methods.end()) {
326  	      return nullptr;
327  	    }
328  	    break;
329  	  default:
330  	    if (std::find(service_methods.begin(), service_methods.end(), method) ==
331  		service_methods.end()) {
332  	      return nullptr;
333  	    }
334  	    break;
335  	  }
336  	
337  	  auto iter = authorize_handlers.find(method);
338  	  if (iter != authorize_handlers.end()) {
339  	    return iter->second;
340  	  }
341  	  AuthAuthorizeHandler *ah = nullptr;
342  	  switch (method) {
343  	  case CEPH_AUTH_NONE:
344  	    ah = new AuthNoneAuthorizeHandler();
345  	    break;
346  	  case CEPH_AUTH_CEPHX:
347  	    ah = new CephxAuthorizeHandler();
348  	    break;
349  	#ifdef HAVE_GSSAPI
350  	  case CEPH_AUTH_GSS:
351  	    ah = new KrbAuthorizeHandler();
352  	    break;
353  	#endif
354  	  }
355  	  if (ah) {
356  	    authorize_handlers[method] = ah;
357  	  }
358  	  return ah;
359  	}
360  	
361