]> git.proxmox.com Git - ceph.git/blob - ceph/src/auth/cephx/CephxServiceHandler.cc
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / auth / cephx / CephxServiceHandler.cc
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
22 #include "include/random.h"
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
30 int 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)
37 {
38 entity_name = name;
39
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;
45
46 CephXServerChallenge ch;
47 ch.server_challenge = server_challenge;
48 encode(ch, *result_bl);
49 return 0;
50 }
51
52 int 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)
60 {
61 int ret = 0;
62
63 struct CephXRequestHeader cephx_header;
64 decode(cephx_header, indata);
65
66 switch (cephx_header.request_type) {
67 case CEPHX_GET_AUTH_SESSION_KEY:
68 {
69 ldout(cct, 10) << "handle_request get_auth_session_key for "
70 << entity_name << dendl;
71
72 CephXAuthenticate req;
73 decode(req, indata);
74
75 CryptoKey secret;
76 if (!key_server->get_secret(entity_name, secret)) {
77 ldout(cct, 0) << "couldn't find entity name: " << entity_name << dendl;
78 ret = -EPERM;
79 break;
80 }
81
82 if (!server_challenge) {
83 ret = -EPERM;
84 break;
85 }
86
87 uint64_t expected_key;
88 std::string error;
89 cephx_calc_client_server_challenge(cct, secret, server_challenge,
90 req.client_challenge, &expected_key, error);
91 if (!error.empty()) {
92 ldout(cct, 0) << " cephx_calc_client_server_challenge error: " << error << dendl;
93 ret = -EPERM;
94 break;
95 }
96
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;
102 ret = -EPERM;
103 break;
104 }
105
106 CryptoKey session_key;
107 CephXSessionAuthInfo info;
108 bool should_enc_ticket = false;
109
110 EntityAuth eauth;
111 if (! key_server->get_auth(entity_name, eauth)) {
112 ret = -EPERM;
113 break;
114 }
115 CephXServiceTicketInfo old_ticket_info;
116
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
121 << dendl;
122 should_enc_ticket = true;
123 }
124
125 ldout(cct,10) << __func__ << " auth ticket global_id " << *global_id
126 << dendl;
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;
132
133 key_server->generate_secret(session_key);
134
135 info.session_key = session_key;
136 if (psession_key) {
137 *psession_key = session_key;
138 }
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;
142 ret = -EIO;
143 break;
144 }
145
146 vector<CephXSessionAuthInfo> info_vec;
147 info_vec.push_back(info);
148
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)) {
153 ret = -EIO;
154 break;
155 }
156
157 if (!key_server->get_service_caps(entity_name, CEPH_ENTITY_TYPE_MON,
158 *caps)) {
159 ldout(cct, 0) << " could not get mon caps for " << entity_name << dendl;
160 ret = -EACCES;
161 break;
162 } else {
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;
166 ret = -EACCES;
167 break;
168 }
169
170 if (req.other_keys) {
171 // nautilus+ client
172 // generate a connection_secret
173 bufferlist cbl;
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);
179 }
180 std::string err;
181 if (encode_encrypt(cct, *pconnection_secret, session_key, cbl,
182 err)) {
183 lderr(cct) << __func__ << " failed to encrypt connection secret, "
184 << err << dendl;
185 ret = -EACCES;
186 break;
187 }
188 }
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;
193 service_id <<= 1) {
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(
199 service_id,
200 info.ticket,
201 svc_info);
202 svc_info.validity += cct->_conf->auth_service_ticket_ttl;
203 info_vec.push_back(svc_info);
204 }
205 }
206 bufferlist extra;
207 if (!info_vec.empty()) {
208 CryptoKey no_key;
209 cephx_build_service_ticket_reply(
210 cct, session_key, info_vec, false, no_key, extra);
211 }
212 encode(extra, *result_bl);
213 }
214
215 // caller should try to finish authentication
216 ret = 1;
217 }
218 }
219 break;
220
221 case CEPHX_GET_PRINCIPAL_SESSION_KEY:
222 {
223 ldout(cct, 10) << "handle_request get_principal_session_key" << dendl;
224
225 bufferlist tmp_bl;
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,
230 nullptr,
231 &tmp_bl)) {
232 ret = -EPERM;
233 break;
234 }
235
236 CephXServiceTicketRequest ticket_req;
237 decode(ticket_req, indata);
238 ldout(cct, 10) << " ticket_req.keys = " << ticket_req.keys << dendl;
239
240 ret = 0;
241 vector<CephXSessionAuthInfo> info_vec;
242 int found_services = 0;
243 int service_err = 0;
244 for (uint32_t service_id = 1; service_id <= ticket_req.keys;
245 service_id <<= 1) {
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(
251 service_id,
252 auth_ticket_info.ticket, // parent ticket (client's auth ticket)
253 info);
254 // tolerate missing MGR rotating key for the purposes of upgrades.
255 if (r < 0) {
256 ldout(cct, 10) << " missing key for service "
257 << ceph_entity_type_name(service_id) << dendl;
258 service_err = r;
259 continue;
260 }
261 info.validity += cct->_conf->auth_service_ticket_ttl;
262 info_vec.push_back(info);
263 ++found_services;
264 }
265 }
266 if (!found_services && service_err) {
267 ldout(cct, 10) << __func__ << " did not find any service keys" << dendl;
268 ret = service_err;
269 }
270 CryptoKey no_key;
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);
274 }
275 break;
276
277 case CEPHX_GET_ROTATING_KEY:
278 {
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)) {
283 ret = -EPERM;
284 break;
285 }
286 }
287 break;
288
289 default:
290 ldout(cct, 10) << "handle_request unknown op " << cephx_header.request_type << dendl;
291 return -EINVAL;
292 }
293 return ret;
294 }
295
296 void CephxServiceHandler::build_cephx_response_header(int request_type, int status, bufferlist& bl)
297 {
298 struct CephXResponseHeader header;
299 header.request_type = request_type;
300 header.status = status;
301 encode(header, bl);
302 }