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.
18 #include "CephxClientHandler.h"
19 #include "CephxProtocol.h"
21 #include "auth/KeyRing.h"
22 #include "common/config.h"
23 #include "common/dout.h"
25 #define dout_subsys ceph_subsys_auth
27 #define dout_prefix *_dout << "cephx client: "
30 int CephxClientHandler::build_request(bufferlist
& bl
) const
32 ldout(cct
, 10) << "build_request" << dendl
;
34 RWLock::RLocker
l(lock
);
36 if (need
& CEPH_ENTITY_TYPE_AUTH
) {
38 CephXRequestHeader header
;
39 header
.request_type
= CEPHX_GET_AUTH_SESSION_KEY
;
43 const bool got
= keyring
->get_secret(cct
->_conf
->name
, secret
);
45 ldout(cct
, 20) << "no secret found for entity: " << cct
->_conf
->name
<< dendl
;
50 if (!secret
.get_secret().length()) {
51 ldout(cct
, 20) << "secret for entity " << cct
->_conf
->name
<< " is invalid" << dendl
;
55 CephXAuthenticate req
;
56 get_random_bytes((char *)&req
.client_challenge
, sizeof(req
.client_challenge
));
58 cephx_calc_client_server_challenge(cct
, secret
, server_challenge
,
59 req
.client_challenge
, &req
.key
, error
);
61 ldout(cct
, 20) << "cephx_calc_client_server_challenge error: " << error
<< dendl
;
65 req
.old_ticket
= ticket_handler
->ticket
;
67 if (req
.old_ticket
.blob
.length()) {
68 ldout(cct
, 20) << "old ticket len=" << req
.old_ticket
.blob
.length() << dendl
;
73 ldout(cct
, 10) << "get auth session key: client_challenge "
74 << hex
<< req
.client_challenge
<< dendl
;
78 if (_need_tickets()) {
79 /* get service tickets */
80 ldout(cct
, 10) << "get service keys: want=" << want
<< " need=" << need
<< " have=" << have
<< dendl
;
82 CephXRequestHeader header
;
83 header
.request_type
= CEPHX_GET_PRINCIPAL_SESSION_KEY
;
86 CephXAuthorizer
*authorizer
= ticket_handler
->build_authorizer(global_id
);
89 bl
.claim_append(authorizer
->bl
);
92 CephXServiceTicketRequest req
;
100 bool CephxClientHandler::_need_tickets() const
102 // do not bother (re)requesting tickets if we *only* need the MGR
103 // ticket; that can happen during an upgrade and we want to avoid a
104 // loop. we'll end up re-requesting it later when the secrets
106 return need
&& need
!= CEPH_ENTITY_TYPE_MGR
;
109 int CephxClientHandler::handle_response(int ret
, bufferlist::iterator
& indata
)
111 ldout(cct
, 10) << "handle_response ret = " << ret
<< dendl
;
112 RWLock::WLocker
l(lock
);
118 CephXServerChallenge ch
;
119 ::decode(ch
, indata
);
120 server_challenge
= ch
.server_challenge
;
121 ldout(cct
, 10) << " got initial server challenge "
122 << hex
<< server_challenge
<< dendl
;
125 tickets
.invalidate_ticket(CEPH_ENTITY_TYPE_AUTH
);
129 struct CephXResponseHeader header
;
130 ::decode(header
, indata
);
132 switch (header
.request_type
) {
133 case CEPHX_GET_AUTH_SESSION_KEY
:
135 ldout(cct
, 10) << " get_auth_session_key" << dendl
;
137 const bool got
= keyring
->get_secret(cct
->_conf
->name
, secret
);
139 ldout(cct
, 0) << "key not found for " << cct
->_conf
->name
<< dendl
;
143 if (!tickets
.verify_service_ticket_reply(secret
, indata
)) {
144 ldout(cct
, 0) << "could not verify service_ticket reply" << dendl
;
147 ldout(cct
, 10) << " want=" << want
<< " need=" << need
<< " have=" << have
<< dendl
;
156 case CEPHX_GET_PRINCIPAL_SESSION_KEY
:
158 CephXTicketHandler
& ticket_handler
= tickets
.get_handler(CEPH_ENTITY_TYPE_AUTH
);
159 ldout(cct
, 10) << " get_principal_session_key session_key " << ticket_handler
.session_key
<< dendl
;
161 if (!tickets
.verify_service_ticket_reply(ticket_handler
.session_key
, indata
)) {
162 ldout(cct
, 0) << "could not verify service_ticket reply" << dendl
;
166 if (!_need_tickets()) {
172 case CEPHX_GET_ROTATING_KEY
:
174 ldout(cct
, 10) << " get_rotating_key" << dendl
;
175 if (rotating_secrets
) {
176 RotatingSecrets secrets
;
177 CryptoKey secret_key
;
178 const bool got
= keyring
->get_secret(cct
->_conf
->name
, secret_key
);
180 ldout(cct
, 0) << "key not found for " << cct
->_conf
->name
<< dendl
;
184 if (decode_decrypt(cct
, secrets
, secret_key
, indata
, error
)) {
185 ldout(cct
, 0) << "could not set rotating key: decode_decrypt failed. error:"
189 rotating_secrets
->set_secrets(std::move(secrets
));
196 ldout(cct
, 0) << " unknown request_type " << header
.request_type
<< dendl
;
204 AuthAuthorizer
*CephxClientHandler::build_authorizer(uint32_t service_id
) const
206 RWLock::RLocker
l(lock
);
207 ldout(cct
, 10) << "build_authorizer for service " << ceph_entity_type_name(service_id
) << dendl
;
208 return tickets
.build_authorizer(service_id
);
212 bool CephxClientHandler::build_rotating_request(bufferlist
& bl
) const
214 ldout(cct
, 10) << "build_rotating_request" << dendl
;
215 CephXRequestHeader header
;
216 header
.request_type
= CEPHX_GET_ROTATING_KEY
;
217 ::encode(header
, bl
);
221 void CephxClientHandler::prepare_build_request()
223 RWLock::WLocker
l(lock
);
224 ldout(cct
, 10) << "validate_tickets: want=" << want
<< " need=" << need
225 << " have=" << have
<< dendl
;
227 ldout(cct
, 10) << "want=" << want
<< " need=" << need
<< " have=" << have
230 ticket_handler
= &(tickets
.get_handler(CEPH_ENTITY_TYPE_AUTH
));
233 void CephxClientHandler::validate_tickets()
235 // lock should be held for write
236 tickets
.validate_tickets(want
, have
, need
);
239 bool CephxClientHandler::need_tickets()
241 RWLock::WLocker
l(lock
);
244 ldout(cct
, 20) << "need_tickets: want=" << want
249 return _need_tickets();