]> git.proxmox.com Git - ceph.git/blame - ceph/src/auth/cephx/CephxClientHandler.cc
import ceph 14.2.5
[ceph.git] / ceph / src / auth / cephx / CephxClientHandler.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3/*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2004-2009 Sage Weil <sage@newdream.net>
7 *
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.
12 *
13 */
14
15
16#include <errno.h>
17
18#include "CephxClientHandler.h"
19#include "CephxProtocol.h"
20
21#include "auth/KeyRing.h"
11fdf7f2
TL
22#include "include/random.h"
23#include "common/ceph_context.h"
7c673cae
FG
24#include "common/config.h"
25#include "common/dout.h"
26
27#define dout_subsys ceph_subsys_auth
28#undef dout_prefix
29#define dout_prefix *_dout << "cephx client: "
30
11fdf7f2
TL
31void CephxClientHandler::reset()
32{
33 ldout(cct,10) << __func__ << dendl;
34 starting = true;
35 server_challenge = 0;
36}
7c673cae
FG
37
38int CephxClientHandler::build_request(bufferlist& bl) const
39{
40 ldout(cct, 10) << "build_request" << dendl;
41
7c673cae
FG
42 if (need & CEPH_ENTITY_TYPE_AUTH) {
43 /* authenticate */
44 CephXRequestHeader header;
45 header.request_type = CEPHX_GET_AUTH_SESSION_KEY;
11fdf7f2 46 encode(header, bl);
7c673cae
FG
47
48 CryptoKey secret;
49 const bool got = keyring->get_secret(cct->_conf->name, secret);
50 if (!got) {
51 ldout(cct, 20) << "no secret found for entity: " << cct->_conf->name << dendl;
52 return -ENOENT;
53 }
54
55 // is the key OK?
56 if (!secret.get_secret().length()) {
57 ldout(cct, 20) << "secret for entity " << cct->_conf->name << " is invalid" << dendl;
58 return -EINVAL;
59 }
60
61 CephXAuthenticate req;
11fdf7f2 62 req.client_challenge = ceph::util::generate_random_number<uint64_t>();
7c673cae
FG
63 std::string error;
64 cephx_calc_client_server_challenge(cct, secret, server_challenge,
65 req.client_challenge, &req.key, error);
66 if (!error.empty()) {
67 ldout(cct, 20) << "cephx_calc_client_server_challenge error: " << error << dendl;
68 return -EIO;
69 }
70
71 req.old_ticket = ticket_handler->ticket;
72
11fdf7f2
TL
73 // for nautilus+ servers: request other keys at the same time
74 req.other_keys = need;
75
7c673cae
FG
76 if (req.old_ticket.blob.length()) {
77 ldout(cct, 20) << "old ticket len=" << req.old_ticket.blob.length() << dendl;
78 }
79
11fdf7f2 80 encode(req, bl);
7c673cae
FG
81
82 ldout(cct, 10) << "get auth session key: client_challenge "
11fdf7f2 83 << std::hex << req.client_challenge << std::dec << dendl;
7c673cae
FG
84 return 0;
85 }
86
87 if (_need_tickets()) {
88 /* get service tickets */
89 ldout(cct, 10) << "get service keys: want=" << want << " need=" << need << " have=" << have << dendl;
90
91 CephXRequestHeader header;
92 header.request_type = CEPHX_GET_PRINCIPAL_SESSION_KEY;
11fdf7f2 93 encode(header, bl);
7c673cae
FG
94
95 CephXAuthorizer *authorizer = ticket_handler->build_authorizer(global_id);
96 if (!authorizer)
97 return -EINVAL;
98 bl.claim_append(authorizer->bl);
99 delete authorizer;
100
101 CephXServiceTicketRequest req;
102 req.keys = need;
11fdf7f2 103 encode(req, bl);
7c673cae
FG
104 }
105
106 return 0;
107}
108
109bool CephxClientHandler::_need_tickets() const
110{
111 // do not bother (re)requesting tickets if we *only* need the MGR
112 // ticket; that can happen during an upgrade and we want to avoid a
113 // loop. we'll end up re-requesting it later when the secrets
114 // rotating.
115 return need && need != CEPH_ENTITY_TYPE_MGR;
116}
117
11fdf7f2
TL
118int CephxClientHandler::handle_response(
119 int ret,
120 bufferlist::const_iterator& indata,
121 CryptoKey *session_key,
122 std::string *connection_secret)
7c673cae 123{
11fdf7f2 124 ldout(cct, 10) << this << " handle_response ret = " << ret << dendl;
7c673cae
FG
125
126 if (ret < 0)
127 return ret; // hrm!
128
129 if (starting) {
130 CephXServerChallenge ch;
eafe8130
TL
131 try {
132 decode(ch, indata);
133 } catch (buffer::error& e) {
134 ldout(cct, 1) << __func__ << " failed to decode CephXServerChallenge: "
135 << e.what() << dendl;
136 return -EPERM;
137 }
7c673cae
FG
138 server_challenge = ch.server_challenge;
139 ldout(cct, 10) << " got initial server challenge "
11fdf7f2 140 << std::hex << server_challenge << std::dec << dendl;
7c673cae
FG
141 starting = false;
142
143 tickets.invalidate_ticket(CEPH_ENTITY_TYPE_AUTH);
144 return -EAGAIN;
145 }
146
147 struct CephXResponseHeader header;
eafe8130
TL
148 try {
149 decode(header, indata);
150 } catch (buffer::error& e) {
151 ldout(cct, 1) << __func__ << " failed to decode CephXResponseHeader: "
152 << e.what() << dendl;
153 return -EPERM;
154 }
7c673cae
FG
155
156 switch (header.request_type) {
157 case CEPHX_GET_AUTH_SESSION_KEY:
158 {
159 ldout(cct, 10) << " get_auth_session_key" << dendl;
160 CryptoKey secret;
161 const bool got = keyring->get_secret(cct->_conf->name, secret);
162 if (!got) {
163 ldout(cct, 0) << "key not found for " << cct->_conf->name << dendl;
164 return -ENOENT;
165 }
166
167 if (!tickets.verify_service_ticket_reply(secret, indata)) {
168 ldout(cct, 0) << "could not verify service_ticket reply" << dendl;
169 return -EPERM;
170 }
171 ldout(cct, 10) << " want=" << want << " need=" << need << " have=" << have << dendl;
11fdf7f2
TL
172 if (!indata.end()) {
173 bufferlist cbl, extra_tickets;
eafe8130
TL
174 try {
175 decode(cbl, indata);
176 decode(extra_tickets, indata);
177 } catch (buffer::error& e) {
178 ldout(cct, 1) << __func__ << " failed to decode tickets: "
179 << e.what() << dendl;
180 return -EPERM;
181 }
11fdf7f2
TL
182 ldout(cct, 10) << " got connection bl " << cbl.length()
183 << " and extra tickets " << extra_tickets.length()
184 << dendl;
185 if (session_key && connection_secret) {
186 CephXTicketHandler& ticket_handler =
187 tickets.get_handler(CEPH_ENTITY_TYPE_AUTH);
188 if (session_key) {
189 *session_key = ticket_handler.session_key;
190 }
191 if (cbl.length() && connection_secret) {
192 auto p = cbl.cbegin();
193 string err;
194 if (decode_decrypt(cct, *connection_secret, *session_key, p,
195 err)) {
196 lderr(cct) << __func__ << " failed to decrypt connection_secret"
197 << dendl;
198 } else {
199 ldout(cct, 10) << " got connection_secret "
200 << connection_secret->size() << " bytes" << dendl;
201 }
202 }
203 if (extra_tickets.length()) {
204 auto p = extra_tickets.cbegin();
205 if (!tickets.verify_service_ticket_reply(
206 *session_key, p)) {
207 lderr(cct) << "could not verify extra service_tickets" << dendl;
208 } else {
209 ldout(cct, 10) << " got extra service_tickets" << dendl;
210 }
211 }
212 }
213 }
7c673cae
FG
214 validate_tickets();
215 if (_need_tickets())
216 ret = -EAGAIN;
217 else
218 ret = 0;
11fdf7f2 219 }
7c673cae
FG
220 break;
221
222 case CEPHX_GET_PRINCIPAL_SESSION_KEY:
223 {
224 CephXTicketHandler& ticket_handler = tickets.get_handler(CEPH_ENTITY_TYPE_AUTH);
225 ldout(cct, 10) << " get_principal_session_key session_key " << ticket_handler.session_key << dendl;
226
227 if (!tickets.verify_service_ticket_reply(ticket_handler.session_key, indata)) {
228 ldout(cct, 0) << "could not verify service_ticket reply" << dendl;
229 return -EPERM;
230 }
231 validate_tickets();
232 if (!_need_tickets()) {
233 ret = 0;
234 }
235 }
236 break;
237
238 case CEPHX_GET_ROTATING_KEY:
239 {
240 ldout(cct, 10) << " get_rotating_key" << dendl;
241 if (rotating_secrets) {
242 RotatingSecrets secrets;
243 CryptoKey secret_key;
244 const bool got = keyring->get_secret(cct->_conf->name, secret_key);
245 if (!got) {
246 ldout(cct, 0) << "key not found for " << cct->_conf->name << dendl;
247 return -ENOENT;
248 }
249 std::string error;
250 if (decode_decrypt(cct, secrets, secret_key, indata, error)) {
251 ldout(cct, 0) << "could not set rotating key: decode_decrypt failed. error:"
252 << error << dendl;
253 return -EINVAL;
254 } else {
224ce89b 255 rotating_secrets->set_secrets(std::move(secrets));
7c673cae
FG
256 }
257 }
258 }
259 break;
260
261 default:
262 ldout(cct, 0) << " unknown request_type " << header.request_type << dendl;
263 ceph_abort();
264 }
265 return ret;
266}
267
268
7c673cae
FG
269AuthAuthorizer *CephxClientHandler::build_authorizer(uint32_t service_id) const
270{
7c673cae
FG
271 ldout(cct, 10) << "build_authorizer for service " << ceph_entity_type_name(service_id) << dendl;
272 return tickets.build_authorizer(service_id);
273}
274
275
276bool CephxClientHandler::build_rotating_request(bufferlist& bl) const
277{
278 ldout(cct, 10) << "build_rotating_request" << dendl;
279 CephXRequestHeader header;
280 header.request_type = CEPHX_GET_ROTATING_KEY;
11fdf7f2 281 encode(header, bl);
7c673cae
FG
282 return true;
283}
284
285void CephxClientHandler::prepare_build_request()
286{
7c673cae
FG
287 ldout(cct, 10) << "validate_tickets: want=" << want << " need=" << need
288 << " have=" << have << dendl;
289 validate_tickets();
290 ldout(cct, 10) << "want=" << want << " need=" << need << " have=" << have
291 << dendl;
292
293 ticket_handler = &(tickets.get_handler(CEPH_ENTITY_TYPE_AUTH));
294}
295
296void CephxClientHandler::validate_tickets()
297{
298 // lock should be held for write
299 tickets.validate_tickets(want, have, need);
300}
301
302bool CephxClientHandler::need_tickets()
303{
7c673cae
FG
304 validate_tickets();
305
306 ldout(cct, 20) << "need_tickets: want=" << want
307 << " have=" << have
308 << " need=" << need
309 << dendl;
310
311 return _need_tickets();
312}