1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2004-2009 Sage Weil <sage@newdream.net>
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.
15 #include "common/config.h"
16 #include "CephxKeyServer.h"
17 #include "common/dout.h"
20 #define dout_subsys ceph_subsys_auth
22 #define dout_prefix *_dout << "cephx keyserverdata: "
24 bool KeyServerData::get_service_secret(CephContext
*cct
, uint32_t service_id
,
25 ExpiringCryptoKey
& secret
, uint64_t& secret_id
) const
27 map
<uint32_t, RotatingSecrets
>::const_iterator iter
=
28 rotating_secrets
.find(service_id
);
29 if (iter
== rotating_secrets
.end()) {
30 ldout(cct
, 10) << "get_service_secret service " << ceph_entity_type_name(service_id
) << " not found " << dendl
;
34 const RotatingSecrets
& secrets
= iter
->second
;
36 // second to oldest, unless it's expired
37 map
<uint64_t, ExpiringCryptoKey
>::const_iterator riter
=
38 secrets
.secrets
.begin();
39 if (secrets
.secrets
.size() > 1)
42 if (riter
->second
.expiration
< ceph_clock_now())
43 ++riter
; // "current" key has expired, use "next" key instead
45 secret_id
= riter
->first
;
46 secret
= riter
->second
;
47 ldout(cct
, 30) << "get_service_secret service " << ceph_entity_type_name(service_id
)
48 << " id " << secret_id
<< " " << secret
<< dendl
;
52 bool KeyServerData::get_service_secret(CephContext
*cct
, uint32_t service_id
,
53 CryptoKey
& secret
, uint64_t& secret_id
) const
57 if (!get_service_secret(cct
, service_id
, e
, secret_id
))
64 bool KeyServerData::get_service_secret(CephContext
*cct
, uint32_t service_id
,
65 uint64_t secret_id
, CryptoKey
& secret
) const
67 map
<uint32_t, RotatingSecrets
>::const_iterator iter
=
68 rotating_secrets
.find(service_id
);
69 if (iter
== rotating_secrets
.end())
72 const RotatingSecrets
& secrets
= iter
->second
;
73 map
<uint64_t, ExpiringCryptoKey
>::const_iterator riter
=
74 secrets
.secrets
.find(secret_id
);
76 if (riter
== secrets
.secrets
.end()) {
77 ldout(cct
, 10) << "get_service_secret service " << ceph_entity_type_name(service_id
)
78 << " secret " << secret_id
<< " not found" << dendl
;
79 ldout(cct
, 30) << " I have:" << dendl
;
80 for (map
<uint64_t, ExpiringCryptoKey
>::const_iterator iter
=
81 secrets
.secrets
.begin();
82 iter
!= secrets
.secrets
.end();
84 ldout(cct
, 30) << " id " << iter
->first
<< " " << iter
->second
<< dendl
;
88 secret
= riter
->second
.key
;
92 bool KeyServerData::get_auth(const EntityName
& name
, EntityAuth
& auth
) const {
93 map
<EntityName
, EntityAuth
>::const_iterator iter
= secrets
.find(name
);
94 if (iter
!= secrets
.end()) {
98 return extra_secrets
->get_auth(name
, auth
);
101 bool KeyServerData::get_secret(const EntityName
& name
, CryptoKey
& secret
) const {
102 map
<EntityName
, EntityAuth
>::const_iterator iter
= secrets
.find(name
);
103 if (iter
!= secrets
.end()) {
104 secret
= iter
->second
.key
;
107 return extra_secrets
->get_secret(name
, secret
);
110 bool KeyServerData::get_caps(CephContext
*cct
, const EntityName
& name
,
111 const string
& type
, AuthCapsInfo
& caps_info
) const
113 caps_info
.allow_all
= false;
115 ldout(cct
, 10) << "get_caps: name=" << name
.to_str() << dendl
;
116 map
<EntityName
, EntityAuth
>::const_iterator iter
= secrets
.find(name
);
117 if (iter
!= secrets
.end()) {
118 ldout(cct
, 10) << "get_secret: num of caps=" << iter
->second
.caps
.size() << dendl
;
119 map
<string
, bufferlist
>::const_iterator capsiter
= iter
->second
.caps
.find(type
);
120 if (capsiter
!= iter
->second
.caps
.end()) {
121 caps_info
.caps
= capsiter
->second
;
126 return extra_secrets
->get_caps(name
, type
, caps_info
);
131 #define dout_prefix *_dout << "cephx keyserver: "
134 KeyServer::KeyServer(CephContext
*cct_
, KeyRing
*extra_secrets
)
137 lock("KeyServer::lock")
141 int KeyServer::start_server()
143 Mutex::Locker
l(lock
);
145 _check_rotating_secrets();
146 _dump_rotating_secrets();
150 bool KeyServer::_check_rotating_secrets()
152 ldout(cct
, 10) << "_check_rotating_secrets" << dendl
;
155 added
+= _rotate_secret(CEPH_ENTITY_TYPE_AUTH
);
156 added
+= _rotate_secret(CEPH_ENTITY_TYPE_MON
);
157 added
+= _rotate_secret(CEPH_ENTITY_TYPE_OSD
);
158 added
+= _rotate_secret(CEPH_ENTITY_TYPE_MDS
);
159 added
+= _rotate_secret(CEPH_ENTITY_TYPE_MGR
);
162 ldout(cct
, 10) << __func__
<< " added " << added
<< dendl
;
164 //data.next_rotating_time = ceph_clock_now(cct);
165 //data.next_rotating_time += MIN(cct->_conf->auth_mon_ticket_ttl, cct->_conf->auth_service_ticket_ttl);
166 _dump_rotating_secrets();
172 void KeyServer::_dump_rotating_secrets()
174 ldout(cct
, 30) << "_dump_rotating_secrets" << dendl
;
175 for (map
<uint32_t, RotatingSecrets
>::iterator iter
= data
.rotating_secrets
.begin();
176 iter
!= data
.rotating_secrets
.end();
178 RotatingSecrets
& key
= iter
->second
;
179 for (map
<uint64_t, ExpiringCryptoKey
>::iterator mapiter
= key
.secrets
.begin();
180 mapiter
!= key
.secrets
.end();
182 ldout(cct
, 30) << "service " << ceph_entity_type_name(iter
->first
)
183 << " id " << mapiter
->first
184 << " key " << mapiter
->second
<< dendl
;
188 int KeyServer::_rotate_secret(uint32_t service_id
)
190 RotatingSecrets
& r
= data
.rotating_secrets
[service_id
];
192 utime_t now
= ceph_clock_now();
193 double ttl
= service_id
== CEPH_ENTITY_TYPE_AUTH
? cct
->_conf
->auth_mon_ticket_ttl
: cct
->_conf
->auth_service_ticket_ttl
;
195 while (r
.need_new_secrets(now
)) {
196 ExpiringCryptoKey ek
;
197 generate_secret(ek
.key
);
201 utime_t next_ttl
= now
;
203 ek
.expiration
= MAX(next_ttl
, r
.next().expiration
);
205 ek
.expiration
+= ttl
;
206 uint64_t secret_id
= r
.add(ek
);
207 ldout(cct
, 10) << "_rotate_secret adding " << ceph_entity_type_name(service_id
) << dendl
;
208 ldout(cct
, 30) << "_rotate_secret adding " << ceph_entity_type_name(service_id
)
209 << " id " << secret_id
<< " " << ek
216 bool KeyServer::get_secret(const EntityName
& name
, CryptoKey
& secret
) const
218 Mutex::Locker
l(lock
);
219 return data
.get_secret(name
, secret
);
222 bool KeyServer::get_auth(const EntityName
& name
, EntityAuth
& auth
) const
224 Mutex::Locker
l(lock
);
225 return data
.get_auth(name
, auth
);
228 bool KeyServer::get_caps(const EntityName
& name
, const string
& type
,
229 AuthCapsInfo
& caps_info
) const
231 Mutex::Locker
l(lock
);
233 return data
.get_caps(cct
, name
, type
, caps_info
);
236 bool KeyServer::get_service_secret(uint32_t service_id
,
237 ExpiringCryptoKey
& secret
, uint64_t& secret_id
) const
239 Mutex::Locker
l(lock
);
241 return data
.get_service_secret(cct
, service_id
, secret
, secret_id
);
244 bool KeyServer::get_service_secret(uint32_t service_id
,
245 CryptoKey
& secret
, uint64_t& secret_id
) const
247 Mutex::Locker
l(lock
);
249 return data
.get_service_secret(cct
, service_id
, secret
, secret_id
);
252 bool KeyServer::get_service_secret(uint32_t service_id
,
253 uint64_t secret_id
, CryptoKey
& secret
) const
255 Mutex::Locker
l(lock
);
257 return data
.get_service_secret(cct
, service_id
, secret_id
, secret
);
260 bool KeyServer::generate_secret(CryptoKey
& secret
)
263 CryptoHandler
*crypto
= cct
->get_crypto_handler(CEPH_CRYPTO_AES
);
267 if (crypto
->create(bp
) < 0)
270 secret
.set_secret(CEPH_CRYPTO_AES
, bp
, ceph_clock_now());
275 bool KeyServer::generate_secret(EntityName
& name
, CryptoKey
& secret
)
277 if (!generate_secret(secret
))
280 Mutex::Locker
l(lock
);
285 data
.add_auth(name
, auth
);
290 bool KeyServer::contains(const EntityName
& name
) const
292 Mutex::Locker
l(lock
);
294 return data
.contains(name
);
297 int KeyServer::encode_secrets(Formatter
*f
, stringstream
*ds
) const
299 Mutex::Locker
l(lock
);
300 map
<EntityName
, EntityAuth
>::const_iterator mapiter
= data
.secrets_begin();
302 if (mapiter
== data
.secrets_end())
306 f
->open_array_section("auth_dump");
308 while (mapiter
!= data
.secrets_end()) {
309 const EntityName
& name
= mapiter
->first
;
311 *ds
<< name
.to_str() << std::endl
;
312 *ds
<< "\tkey: " << mapiter
->second
.key
<< std::endl
;
313 if (mapiter
->second
.auid
!= CEPH_AUTH_UID_DEFAULT
)
314 *ds
<< "\tauid: " << mapiter
->second
.auid
<< std::endl
;
317 f
->open_object_section("auth_entities");
318 f
->dump_string("entity", name
.to_str());
319 f
->dump_stream("key") << mapiter
->second
.key
;
320 if (mapiter
->second
.auid
!= CEPH_AUTH_UID_DEFAULT
)
321 f
->dump_int("auid", mapiter
->second
.auid
);
322 f
->open_object_section("caps");
325 map
<string
, bufferlist
>::const_iterator capsiter
=
326 mapiter
->second
.caps
.begin();
327 for (; capsiter
!= mapiter
->second
.caps
.end(); ++capsiter
) {
328 // FIXME: need a const_iterator for bufferlist, but it doesn't exist yet.
329 bufferlist
*bl
= const_cast<bufferlist
*>(&capsiter
->second
);
330 bufferlist::iterator dataiter
= bl
->begin();
332 ::decode(caps
, dataiter
);
334 *ds
<< "\tcaps: [" << capsiter
->first
<< "] " << caps
<< std::endl
;
336 f
->dump_string(capsiter
->first
.c_str(), caps
);
339 f
->close_section(); // caps
340 f
->close_section(); // auth_entities
347 f
->close_section(); // auth_dump
351 void KeyServer::encode_formatted(string label
, Formatter
*f
, bufferlist
&bl
)
354 f
->open_object_section(label
.c_str());
355 encode_secrets(f
, NULL
);
360 void KeyServer::encode_plaintext(bufferlist
&bl
)
363 encode_secrets(NULL
, &os
);
367 bool KeyServer::updated_rotating(bufferlist
& rotating_bl
, version_t
& rotating_ver
)
369 Mutex::Locker
l(lock
);
371 _check_rotating_secrets();
373 if (data
.rotating_ver
<= rotating_ver
)
376 data
.encode_rotating(rotating_bl
);
378 rotating_ver
= data
.rotating_ver
;
383 bool KeyServer::get_rotating_encrypted(const EntityName
& name
,
384 bufferlist
& enc_bl
) const
386 Mutex::Locker
l(lock
);
388 map
<EntityName
, EntityAuth
>::const_iterator mapiter
= data
.find_name(name
);
389 if (mapiter
== data
.secrets_end())
392 const CryptoKey
& specific_key
= mapiter
->second
.key
;
394 map
<uint32_t, RotatingSecrets
>::const_iterator rotate_iter
=
395 data
.rotating_secrets
.find(name
.get_type());
396 if (rotate_iter
== data
.rotating_secrets
.end())
399 RotatingSecrets secrets
= rotate_iter
->second
;
402 if (encode_encrypt(cct
, secrets
, specific_key
, enc_bl
, error
))
408 bool KeyServer::_get_service_caps(const EntityName
& name
, uint32_t service_id
,
409 AuthCapsInfo
& caps_info
) const
411 string s
= ceph_entity_type_name(service_id
);
413 return data
.get_caps(cct
, name
, s
, caps_info
);
416 bool KeyServer::get_service_caps(const EntityName
& name
, uint32_t service_id
,
417 AuthCapsInfo
& caps_info
) const
419 Mutex::Locker
l(lock
);
420 return _get_service_caps(name
, service_id
, caps_info
);
424 int KeyServer::_build_session_auth_info(uint32_t service_id
, CephXServiceTicketInfo
& auth_ticket_info
,
425 CephXSessionAuthInfo
& info
)
427 info
.service_id
= service_id
;
428 info
.ticket
= auth_ticket_info
.ticket
;
429 info
.ticket
.init_timestamps(ceph_clock_now(), cct
->_conf
->auth_service_ticket_ttl
);
431 generate_secret(info
.session_key
);
433 // mon keys are stored externally. and the caps are blank anyway.
434 if (service_id
!= CEPH_ENTITY_TYPE_MON
) {
435 string s
= ceph_entity_type_name(service_id
);
436 if (!data
.get_caps(cct
, info
.ticket
.name
, s
, info
.ticket
.caps
)) {
443 int KeyServer::build_session_auth_info(uint32_t service_id
, CephXServiceTicketInfo
& auth_ticket_info
,
444 CephXSessionAuthInfo
& info
)
446 if (!get_service_secret(service_id
, info
.service_secret
, info
.secret_id
)) {
450 Mutex::Locker
l(lock
);
452 return _build_session_auth_info(service_id
, auth_ticket_info
, info
);
455 int KeyServer::build_session_auth_info(uint32_t service_id
, CephXServiceTicketInfo
& auth_ticket_info
, CephXSessionAuthInfo
& info
,
456 CryptoKey
& service_secret
, uint64_t secret_id
)
458 info
.service_secret
= service_secret
;
459 info
.secret_id
= secret_id
;
461 Mutex::Locker
l(lock
);
462 return _build_session_auth_info(service_id
, auth_ticket_info
, info
);