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
;
65 decode(cephx_header
, indata
);
66 } catch (buffer::error
& e
) {
67 ldout(cct
, 0) << __func__
<< " failed to decode CephXRequestHeader: "
72 switch (cephx_header
.request_type
) {
73 case CEPHX_GET_AUTH_SESSION_KEY
:
75 ldout(cct
, 10) << "handle_request get_auth_session_key for "
76 << entity_name
<< dendl
;
78 CephXAuthenticate req
;
81 } catch (buffer::error
& e
) {
82 ldout(cct
, 0) << __func__
<< " failed to decode CephXAuthenticate: "
89 if (!key_server
->get_secret(entity_name
, secret
)) {
90 ldout(cct
, 0) << "couldn't find entity name: " << entity_name
<< dendl
;
95 if (!server_challenge
) {
100 uint64_t expected_key
;
102 cephx_calc_client_server_challenge(cct
, secret
, server_challenge
,
103 req
.client_challenge
, &expected_key
, error
);
104 if (!error
.empty()) {
105 ldout(cct
, 0) << " cephx_calc_client_server_challenge error: " << error
<< dendl
;
110 ldout(cct
, 20) << " checking key: req.key=" << hex
<< req
.key
111 << " expected_key=" << expected_key
<< dec
<< dendl
;
112 if (req
.key
!= expected_key
) {
113 ldout(cct
, 0) << " unexpected key: req.key=" << hex
<< req
.key
114 << " expected_key=" << expected_key
<< dec
<< dendl
;
119 CryptoKey session_key
;
120 CephXSessionAuthInfo info
;
121 bool should_enc_ticket
= false;
124 if (! key_server
->get_auth(entity_name
, eauth
)) {
128 CephXServiceTicketInfo old_ticket_info
;
130 if (cephx_decode_ticket(cct
, key_server
, CEPH_ENTITY_TYPE_AUTH
,
131 req
.old_ticket
, old_ticket_info
)) {
132 *global_id
= old_ticket_info
.ticket
.global_id
;
133 ldout(cct
, 10) << "decoded old_ticket with global_id=" << *global_id
135 should_enc_ticket
= true;
138 ldout(cct
,10) << __func__
<< " auth ticket global_id " << *global_id
140 info
.ticket
.init_timestamps(ceph_clock_now(),
141 cct
->_conf
->auth_mon_ticket_ttl
);
142 info
.ticket
.name
= entity_name
;
143 info
.ticket
.global_id
= *global_id
;
144 info
.validity
+= cct
->_conf
->auth_mon_ticket_ttl
;
146 key_server
->generate_secret(session_key
);
148 info
.session_key
= session_key
;
150 *psession_key
= session_key
;
152 info
.service_id
= CEPH_ENTITY_TYPE_AUTH
;
153 if (!key_server
->get_service_secret(CEPH_ENTITY_TYPE_AUTH
, info
.service_secret
, info
.secret_id
)) {
154 ldout(cct
, 0) << " could not get service secret for auth subsystem" << dendl
;
159 vector
<CephXSessionAuthInfo
> info_vec
;
160 info_vec
.push_back(info
);
162 build_cephx_response_header(cephx_header
.request_type
, 0, *result_bl
);
163 if (!cephx_build_service_ticket_reply(
164 cct
, eauth
.key
, info_vec
, should_enc_ticket
,
165 old_ticket_info
.session_key
, *result_bl
)) {
170 if (!key_server
->get_service_caps(entity_name
, CEPH_ENTITY_TYPE_MON
,
172 ldout(cct
, 0) << " could not get mon caps for " << entity_name
<< dendl
;
176 char *caps_str
= caps
->caps
.c_str();
177 if (!caps_str
|| !caps_str
[0]) {
178 ldout(cct
,0) << "mon caps null for " << entity_name
<< dendl
;
183 if (req
.other_keys
) {
185 // generate a connection_secret
187 if (pconnection_secret
) {
188 pconnection_secret
->resize(connection_secret_required_len
);
189 if (connection_secret_required_len
) {
190 cct
->random()->get_bytes(pconnection_secret
->data(),
191 connection_secret_required_len
);
194 if (encode_encrypt(cct
, *pconnection_secret
, session_key
, cbl
,
196 lderr(cct
) << __func__
<< " failed to encrypt connection secret, "
202 encode(cbl
, *result_bl
);
203 // provite all of the other tickets at the same time
204 vector
<CephXSessionAuthInfo
> info_vec
;
205 for (uint32_t service_id
= 1; service_id
<= req
.other_keys
;
207 if (req
.other_keys
& service_id
) {
208 ldout(cct
, 10) << " adding key for service "
209 << ceph_entity_type_name(service_id
) << dendl
;
210 CephXSessionAuthInfo svc_info
;
211 key_server
->build_session_auth_info(
215 svc_info
.validity
+= cct
->_conf
->auth_service_ticket_ttl
;
216 info_vec
.push_back(svc_info
);
220 if (!info_vec
.empty()) {
222 cephx_build_service_ticket_reply(
223 cct
, session_key
, info_vec
, false, no_key
, extra
);
225 encode(extra
, *result_bl
);
228 // caller should try to finish authentication
234 case CEPHX_GET_PRINCIPAL_SESSION_KEY
:
236 ldout(cct
, 10) << "handle_request get_principal_session_key" << dendl
;
239 CephXServiceTicketInfo auth_ticket_info
;
240 // note: no challenge here.
241 if (!cephx_verify_authorizer(
242 cct
, *key_server
, indata
, 0, auth_ticket_info
, nullptr,
249 CephXServiceTicketRequest ticket_req
;
251 decode(ticket_req
, indata
);
252 } catch (buffer::error
& e
) {
253 ldout(cct
, 0) << __func__
254 << " failed to decode CephXServiceTicketRequest: "
255 << e
.what() << dendl
;
259 ldout(cct
, 10) << " ticket_req.keys = " << ticket_req
.keys
<< dendl
;
262 vector
<CephXSessionAuthInfo
> info_vec
;
263 int found_services
= 0;
265 for (uint32_t service_id
= 1; service_id
<= ticket_req
.keys
;
267 if (ticket_req
.keys
& service_id
) {
268 ldout(cct
, 10) << " adding key for service "
269 << ceph_entity_type_name(service_id
) << dendl
;
270 CephXSessionAuthInfo info
;
271 int r
= key_server
->build_session_auth_info(
273 auth_ticket_info
.ticket
, // parent ticket (client's auth ticket)
275 // tolerate missing MGR rotating key for the purposes of upgrades.
277 ldout(cct
, 10) << " missing key for service "
278 << ceph_entity_type_name(service_id
) << dendl
;
282 info
.validity
+= cct
->_conf
->auth_service_ticket_ttl
;
283 info_vec
.push_back(info
);
287 if (!found_services
&& service_err
) {
288 ldout(cct
, 10) << __func__
<< " did not find any service keys" << dendl
;
292 build_cephx_response_header(cephx_header
.request_type
, ret
, *result_bl
);
293 cephx_build_service_ticket_reply(cct
, auth_ticket_info
.session_key
,
294 info_vec
, false, no_key
, *result_bl
);
298 case CEPHX_GET_ROTATING_KEY
:
300 ldout(cct
, 10) << "handle_request getting rotating secret for "
301 << entity_name
<< dendl
;
302 build_cephx_response_header(cephx_header
.request_type
, 0, *result_bl
);
303 if (!key_server
->get_rotating_encrypted(entity_name
, *result_bl
)) {
311 ldout(cct
, 10) << "handle_request unknown op " << cephx_header
.request_type
<< dendl
;
317 void CephxServiceHandler::build_cephx_response_header(int request_type
, int status
, bufferlist
& bl
)
319 struct CephXResponseHeader header
;
320 header
.request_type
= request_type
;
321 header
.status
= status
;