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.
16 #include "CephxServiceHandler.h"
17 #include "CephxProtocol.h"
18 #include "CephxKeyServer.h"
22 #include "include/random.h"
23 #include "common/config.h"
24 #include "common/debug.h"
26 #define dout_subsys ceph_subsys_auth
28 #define dout_prefix *_dout << "cephx server " << entity_name << ": "
30 int CephxServiceHandler::start_session(
31 const EntityName
& name
,
32 size_t connection_secret_required_length
,
33 bufferlist
*result_bl
,
35 CryptoKey
*session_key
,
36 std::string
*connection_secret
)
40 uint64_t min
= 1; // always non-zero
41 uint64_t max
= std::numeric_limits
<uint64_t>::max();
42 server_challenge
= ceph::util::generate_random_number
<uint64_t>(min
, max
);
43 ldout(cct
, 10) << "start_session server_challenge "
44 << hex
<< server_challenge
<< dec
<< dendl
;
46 CephXServerChallenge ch
;
47 ch
.server_challenge
= server_challenge
;
48 encode(ch
, *result_bl
);
52 int CephxServiceHandler::handle_request(
53 bufferlist::const_iterator
& indata
,
54 size_t connection_secret_required_len
,
55 bufferlist
*result_bl
,
58 CryptoKey
*psession_key
,
59 std::string
*pconnection_secret
)
63 struct CephXRequestHeader cephx_header
;
64 decode(cephx_header
, indata
);
66 switch (cephx_header
.request_type
) {
67 case CEPHX_GET_AUTH_SESSION_KEY
:
69 ldout(cct
, 10) << "handle_request get_auth_session_key for "
70 << entity_name
<< dendl
;
72 CephXAuthenticate req
;
76 if (!key_server
->get_secret(entity_name
, secret
)) {
77 ldout(cct
, 0) << "couldn't find entity name: " << entity_name
<< dendl
;
82 if (!server_challenge
) {
87 uint64_t expected_key
;
89 cephx_calc_client_server_challenge(cct
, secret
, server_challenge
,
90 req
.client_challenge
, &expected_key
, error
);
92 ldout(cct
, 0) << " cephx_calc_client_server_challenge error: " << error
<< dendl
;
97 ldout(cct
, 20) << " checking key: req.key=" << hex
<< req
.key
98 << " expected_key=" << expected_key
<< dec
<< dendl
;
99 if (req
.key
!= expected_key
) {
100 ldout(cct
, 0) << " unexpected key: req.key=" << hex
<< req
.key
101 << " expected_key=" << expected_key
<< dec
<< dendl
;
106 CryptoKey session_key
;
107 CephXSessionAuthInfo info
;
108 bool should_enc_ticket
= false;
111 if (! key_server
->get_auth(entity_name
, eauth
)) {
115 CephXServiceTicketInfo old_ticket_info
;
117 if (cephx_decode_ticket(cct
, key_server
, CEPH_ENTITY_TYPE_AUTH
,
118 req
.old_ticket
, old_ticket_info
)) {
119 *global_id
= old_ticket_info
.ticket
.global_id
;
120 ldout(cct
, 10) << "decoded old_ticket with global_id=" << *global_id
122 should_enc_ticket
= true;
125 ldout(cct
,10) << __func__
<< " auth ticket global_id " << *global_id
127 info
.ticket
.init_timestamps(ceph_clock_now(),
128 cct
->_conf
->auth_mon_ticket_ttl
);
129 info
.ticket
.name
= entity_name
;
130 info
.ticket
.global_id
= *global_id
;
131 info
.validity
+= cct
->_conf
->auth_mon_ticket_ttl
;
133 key_server
->generate_secret(session_key
);
135 info
.session_key
= session_key
;
137 *psession_key
= session_key
;
139 info
.service_id
= CEPH_ENTITY_TYPE_AUTH
;
140 if (!key_server
->get_service_secret(CEPH_ENTITY_TYPE_AUTH
, info
.service_secret
, info
.secret_id
)) {
141 ldout(cct
, 0) << " could not get service secret for auth subsystem" << dendl
;
146 vector
<CephXSessionAuthInfo
> info_vec
;
147 info_vec
.push_back(info
);
149 build_cephx_response_header(cephx_header
.request_type
, 0, *result_bl
);
150 if (!cephx_build_service_ticket_reply(
151 cct
, eauth
.key
, info_vec
, should_enc_ticket
,
152 old_ticket_info
.session_key
, *result_bl
)) {
157 if (!key_server
->get_service_caps(entity_name
, CEPH_ENTITY_TYPE_MON
,
159 ldout(cct
, 0) << " could not get mon caps for " << entity_name
<< dendl
;
163 char *caps_str
= caps
->caps
.c_str();
164 if (!caps_str
|| !caps_str
[0]) {
165 ldout(cct
,0) << "mon caps null for " << entity_name
<< dendl
;
170 if (req
.other_keys
) {
172 // generate a connection_secret
174 if (pconnection_secret
) {
175 pconnection_secret
->resize(connection_secret_required_len
);
176 if (connection_secret_required_len
) {
177 cct
->random()->get_bytes(pconnection_secret
->data(),
178 connection_secret_required_len
);
181 if (encode_encrypt(cct
, *pconnection_secret
, session_key
, cbl
,
183 lderr(cct
) << __func__
<< " failed to encrypt connection secret, "
189 encode(cbl
, *result_bl
);
190 // provite all of the other tickets at the same time
191 vector
<CephXSessionAuthInfo
> info_vec
;
192 for (uint32_t service_id
= 1; service_id
<= req
.other_keys
;
194 if (req
.other_keys
& service_id
) {
195 ldout(cct
, 10) << " adding key for service "
196 << ceph_entity_type_name(service_id
) << dendl
;
197 CephXSessionAuthInfo svc_info
;
198 key_server
->build_session_auth_info(
202 svc_info
.validity
+= cct
->_conf
->auth_service_ticket_ttl
;
203 info_vec
.push_back(svc_info
);
207 if (!info_vec
.empty()) {
209 cephx_build_service_ticket_reply(
210 cct
, session_key
, info_vec
, false, no_key
, extra
);
212 encode(extra
, *result_bl
);
215 // caller should try to finish authentication
221 case CEPHX_GET_PRINCIPAL_SESSION_KEY
:
223 ldout(cct
, 10) << "handle_request get_principal_session_key" << dendl
;
226 CephXServiceTicketInfo auth_ticket_info
;
227 // note: no challenge here.
228 if (!cephx_verify_authorizer(
229 cct
, key_server
, indata
, 0, auth_ticket_info
, nullptr,
236 CephXServiceTicketRequest ticket_req
;
237 decode(ticket_req
, indata
);
238 ldout(cct
, 10) << " ticket_req.keys = " << ticket_req
.keys
<< dendl
;
241 vector
<CephXSessionAuthInfo
> info_vec
;
242 int found_services
= 0;
244 for (uint32_t service_id
= 1; service_id
<= ticket_req
.keys
;
246 if (ticket_req
.keys
& service_id
) {
247 ldout(cct
, 10) << " adding key for service "
248 << ceph_entity_type_name(service_id
) << dendl
;
249 CephXSessionAuthInfo info
;
250 int r
= key_server
->build_session_auth_info(
252 auth_ticket_info
.ticket
, // parent ticket (client's auth ticket)
254 // tolerate missing MGR rotating key for the purposes of upgrades.
256 ldout(cct
, 10) << " missing key for service "
257 << ceph_entity_type_name(service_id
) << dendl
;
261 info
.validity
+= cct
->_conf
->auth_service_ticket_ttl
;
262 info_vec
.push_back(info
);
266 if (!found_services
&& service_err
) {
267 ldout(cct
, 10) << __func__
<< " did not find any service keys" << dendl
;
271 build_cephx_response_header(cephx_header
.request_type
, ret
, *result_bl
);
272 cephx_build_service_ticket_reply(cct
, auth_ticket_info
.session_key
,
273 info_vec
, false, no_key
, *result_bl
);
277 case CEPHX_GET_ROTATING_KEY
:
279 ldout(cct
, 10) << "handle_request getting rotating secret for "
280 << entity_name
<< dendl
;
281 build_cephx_response_header(cephx_header
.request_type
, 0, *result_bl
);
282 if (!key_server
->get_rotating_encrypted(entity_name
, *result_bl
)) {
290 ldout(cct
, 10) << "handle_request unknown op " << cephx_header
.request_type
<< dendl
;
296 void CephxServiceHandler::build_cephx_response_header(int request_type
, int status
, bufferlist
& bl
)
298 struct CephXResponseHeader header
;
299 header
.request_type
= request_type
;
300 header
.status
= status
;