]> git.proxmox.com Git - ceph.git/blame - ceph/src/auth/cephx/CephxServiceHandler.cc
import 15.2.0 Octopus source
[ceph.git] / ceph / src / auth / cephx / CephxServiceHandler.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 "CephxServiceHandler.h"
17#include "CephxProtocol.h"
18#include "CephxKeyServer.h"
19#include <errno.h>
20#include <sstream>
21
11fdf7f2 22#include "include/random.h"
7c673cae
FG
23#include "common/config.h"
24#include "common/debug.h"
25
26#define dout_subsys ceph_subsys_auth
27#undef dout_prefix
28#define dout_prefix *_dout << "cephx server " << entity_name << ": "
29
11fdf7f2
TL
30int CephxServiceHandler::start_session(
31 const EntityName& name,
32 size_t connection_secret_required_length,
33 bufferlist *result_bl,
34 AuthCapsInfo *caps,
35 CryptoKey *session_key,
36 std::string *connection_secret)
7c673cae
FG
37{
38 entity_name = name;
39
11fdf7f2
TL
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;
7c673cae
FG
45
46 CephXServerChallenge ch;
47 ch.server_challenge = server_challenge;
11fdf7f2
TL
48 encode(ch, *result_bl);
49 return 0;
7c673cae
FG
50}
51
11fdf7f2
TL
52int CephxServiceHandler::handle_request(
53 bufferlist::const_iterator& indata,
54 size_t connection_secret_required_len,
55 bufferlist *result_bl,
56 uint64_t *global_id,
57 AuthCapsInfo *caps,
58 CryptoKey *psession_key,
59 std::string *pconnection_secret)
7c673cae
FG
60{
61 int ret = 0;
62
63 struct CephXRequestHeader cephx_header;
eafe8130
TL
64 try {
65 decode(cephx_header, indata);
66 } catch (buffer::error& e) {
67 ldout(cct, 0) << __func__ << " failed to decode CephXRequestHeader: "
68 << e.what() << dendl;
69 return -EPERM;
70 }
7c673cae
FG
71
72 switch (cephx_header.request_type) {
73 case CEPHX_GET_AUTH_SESSION_KEY:
74 {
11fdf7f2
TL
75 ldout(cct, 10) << "handle_request get_auth_session_key for "
76 << entity_name << dendl;
7c673cae
FG
77
78 CephXAuthenticate req;
eafe8130
TL
79 try {
80 decode(req, indata);
81 } catch (buffer::error& e) {
82 ldout(cct, 0) << __func__ << " failed to decode CephXAuthenticate: "
83 << e.what() << dendl;
84 ret = -EPERM;
85 break;
86 }
7c673cae
FG
87
88 CryptoKey secret;
89 if (!key_server->get_secret(entity_name, secret)) {
90 ldout(cct, 0) << "couldn't find entity name: " << entity_name << dendl;
9f95a23c 91 ret = -EACCES;
7c673cae
FG
92 break;
93 }
94
95 if (!server_challenge) {
9f95a23c 96 ret = -EACCES;
7c673cae
FG
97 break;
98 }
99
100 uint64_t expected_key;
101 std::string error;
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;
9f95a23c 106 ret = -EACCES;
7c673cae
FG
107 break;
108 }
109
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;
9f95a23c 115 ret = -EACCES;
7c673cae
FG
116 break;
117 }
118
119 CryptoKey session_key;
120 CephXSessionAuthInfo info;
121 bool should_enc_ticket = false;
122
123 EntityAuth eauth;
124 if (! key_server->get_auth(entity_name, eauth)) {
9f95a23c 125 ret = -EACCES;
7c673cae
FG
126 break;
127 }
128 CephXServiceTicketInfo old_ticket_info;
129
130 if (cephx_decode_ticket(cct, key_server, CEPH_ENTITY_TYPE_AUTH,
131 req.old_ticket, old_ticket_info)) {
11fdf7f2
TL
132 *global_id = old_ticket_info.ticket.global_id;
133 ldout(cct, 10) << "decoded old_ticket with global_id=" << *global_id
134 << dendl;
7c673cae
FG
135 should_enc_ticket = true;
136 }
137
11fdf7f2
TL
138 ldout(cct,10) << __func__ << " auth ticket global_id " << *global_id
139 << dendl;
140 info.ticket.init_timestamps(ceph_clock_now(),
141 cct->_conf->auth_mon_ticket_ttl);
7c673cae 142 info.ticket.name = entity_name;
11fdf7f2 143 info.ticket.global_id = *global_id;
7c673cae
FG
144 info.validity += cct->_conf->auth_mon_ticket_ttl;
145
7c673cae
FG
146 key_server->generate_secret(session_key);
147
148 info.session_key = session_key;
11fdf7f2
TL
149 if (psession_key) {
150 *psession_key = session_key;
151 }
7c673cae
FG
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;
155 ret = -EIO;
156 break;
157 }
158
159 vector<CephXSessionAuthInfo> info_vec;
160 info_vec.push_back(info);
161
11fdf7f2
TL
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)) {
7c673cae 166 ret = -EIO;
11fdf7f2 167 break;
7c673cae
FG
168 }
169
11fdf7f2
TL
170 if (!key_server->get_service_caps(entity_name, CEPH_ENTITY_TYPE_MON,
171 *caps)) {
7c673cae
FG
172 ldout(cct, 0) << " could not get mon caps for " << entity_name << dendl;
173 ret = -EACCES;
11fdf7f2 174 break;
7c673cae 175 } else {
11fdf7f2 176 char *caps_str = caps->caps.c_str();
7c673cae
FG
177 if (!caps_str || !caps_str[0]) {
178 ldout(cct,0) << "mon caps null for " << entity_name << dendl;
179 ret = -EACCES;
11fdf7f2 180 break;
7c673cae 181 }
11fdf7f2
TL
182
183 if (req.other_keys) {
184 // nautilus+ client
185 // generate a connection_secret
186 bufferlist cbl;
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);
192 }
193 std::string err;
194 if (encode_encrypt(cct, *pconnection_secret, session_key, cbl,
195 err)) {
196 lderr(cct) << __func__ << " failed to encrypt connection secret, "
197 << err << dendl;
198 ret = -EACCES;
199 break;
200 }
201 }
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;
206 service_id <<= 1) {
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(
212 service_id,
213 info.ticket,
214 svc_info);
215 svc_info.validity += cct->_conf->auth_service_ticket_ttl;
216 info_vec.push_back(svc_info);
217 }
218 }
219 bufferlist extra;
220 if (!info_vec.empty()) {
221 CryptoKey no_key;
222 cephx_build_service_ticket_reply(
223 cct, session_key, info_vec, false, no_key, extra);
224 }
225 encode(extra, *result_bl);
226 }
227
228 // caller should try to finish authentication
229 ret = 1;
7c673cae
FG
230 }
231 }
232 break;
233
234 case CEPHX_GET_PRINCIPAL_SESSION_KEY:
235 {
236 ldout(cct, 10) << "handle_request get_principal_session_key" << dendl;
237
238 bufferlist tmp_bl;
239 CephXServiceTicketInfo auth_ticket_info;
28e407b8 240 // note: no challenge here.
11fdf7f2 241 if (!cephx_verify_authorizer(
9f95a23c 242 cct, *key_server, indata, 0, auth_ticket_info, nullptr,
11fdf7f2
TL
243 nullptr,
244 &tmp_bl)) {
9f95a23c 245 ret = -EACCES;
7c673cae
FG
246 break;
247 }
248
249 CephXServiceTicketRequest ticket_req;
eafe8130
TL
250 try {
251 decode(ticket_req, indata);
252 } catch (buffer::error& e) {
253 ldout(cct, 0) << __func__
254 << " failed to decode CephXServiceTicketRequest: "
255 << e.what() << dendl;
256 ret = -EPERM;
257 break;
258 }
7c673cae
FG
259 ldout(cct, 10) << " ticket_req.keys = " << ticket_req.keys << dendl;
260
261 ret = 0;
262 vector<CephXSessionAuthInfo> info_vec;
263 int found_services = 0;
264 int service_err = 0;
265 for (uint32_t service_id = 1; service_id <= ticket_req.keys;
266 service_id <<= 1) {
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;
11fdf7f2
TL
271 int r = key_server->build_session_auth_info(
272 service_id,
273 auth_ticket_info.ticket, // parent ticket (client's auth ticket)
274 info);
7c673cae
FG
275 // tolerate missing MGR rotating key for the purposes of upgrades.
276 if (r < 0) {
277 ldout(cct, 10) << " missing key for service "
278 << ceph_entity_type_name(service_id) << dendl;
279 service_err = r;
280 continue;
281 }
282 info.validity += cct->_conf->auth_service_ticket_ttl;
283 info_vec.push_back(info);
284 ++found_services;
285 }
286 }
287 if (!found_services && service_err) {
288 ldout(cct, 10) << __func__ << " did not find any service keys" << dendl;
289 ret = service_err;
290 }
291 CryptoKey no_key;
11fdf7f2
TL
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);
7c673cae
FG
295 }
296 break;
297
298 case CEPHX_GET_ROTATING_KEY:
299 {
11fdf7f2
TL
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)) {
9f95a23c 304 ret = -EACCES;
7c673cae
FG
305 break;
306 }
307 }
308 break;
309
310 default:
311 ldout(cct, 10) << "handle_request unknown op " << cephx_header.request_type << dendl;
312 return -EINVAL;
313 }
314 return ret;
315}
316
317void CephxServiceHandler::build_cephx_response_header(int request_type, int status, bufferlist& bl)
318{
319 struct CephXResponseHeader header;
320 header.request_type = request_type;
321 header.status = status;
11fdf7f2 322 encode(header, bl);
7c673cae 323}