]> git.proxmox.com Git - ceph.git/blob - ceph/src/auth/cephx/CephxServiceHandler.cc
update sources to 12.2.7
[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 "common/config.h"
23 #include "common/debug.h"
24
25 #define dout_subsys ceph_subsys_auth
26 #undef dout_prefix
27 #define dout_prefix *_dout << "cephx server " << entity_name << ": "
28
29 int CephxServiceHandler::start_session(EntityName& name, bufferlist::iterator& indata, bufferlist& result_bl, AuthCapsInfo& caps)
30 {
31 entity_name = name;
32
33 get_random_bytes((char *)&server_challenge, sizeof(server_challenge));
34 if (!server_challenge)
35 server_challenge = 1; // always non-zero.
36 ldout(cct, 10) << "start_session server_challenge " << hex << server_challenge << dec << dendl;
37
38 CephXServerChallenge ch;
39 ch.server_challenge = server_challenge;
40 ::encode(ch, result_bl);
41 return CEPH_AUTH_CEPHX;
42 }
43
44 int CephxServiceHandler::handle_request(bufferlist::iterator& indata, bufferlist& result_bl, uint64_t& global_id, AuthCapsInfo& caps, uint64_t *auid)
45 {
46 int ret = 0;
47
48 struct CephXRequestHeader cephx_header;
49 ::decode(cephx_header, indata);
50
51
52 switch (cephx_header.request_type) {
53 case CEPHX_GET_AUTH_SESSION_KEY:
54 {
55 ldout(cct, 10) << "handle_request get_auth_session_key for " << entity_name << dendl;
56
57 CephXAuthenticate req;
58 ::decode(req, indata);
59
60 CryptoKey secret;
61 if (!key_server->get_secret(entity_name, secret)) {
62 ldout(cct, 0) << "couldn't find entity name: " << entity_name << dendl;
63 ret = -EPERM;
64 break;
65 }
66
67 if (!server_challenge) {
68 ret = -EPERM;
69 break;
70 }
71
72 uint64_t expected_key;
73 std::string error;
74 cephx_calc_client_server_challenge(cct, secret, server_challenge,
75 req.client_challenge, &expected_key, error);
76 if (!error.empty()) {
77 ldout(cct, 0) << " cephx_calc_client_server_challenge error: " << error << dendl;
78 ret = -EPERM;
79 break;
80 }
81
82 ldout(cct, 20) << " checking key: req.key=" << hex << req.key
83 << " expected_key=" << expected_key << dec << dendl;
84 if (req.key != expected_key) {
85 ldout(cct, 0) << " unexpected key: req.key=" << hex << req.key
86 << " expected_key=" << expected_key << dec << dendl;
87 ret = -EPERM;
88 break;
89 }
90
91 CryptoKey session_key;
92 CephXSessionAuthInfo info;
93 bool should_enc_ticket = false;
94
95 EntityAuth eauth;
96 if (! key_server->get_auth(entity_name, eauth)) {
97 ret = -EPERM;
98 break;
99 }
100 CephXServiceTicketInfo old_ticket_info;
101
102 if (cephx_decode_ticket(cct, key_server, CEPH_ENTITY_TYPE_AUTH,
103 req.old_ticket, old_ticket_info)) {
104 global_id = old_ticket_info.ticket.global_id;
105 ldout(cct, 10) << "decoded old_ticket with global_id=" << global_id << dendl;
106 should_enc_ticket = true;
107 }
108
109 info.ticket.init_timestamps(ceph_clock_now(), cct->_conf->auth_mon_ticket_ttl);
110 info.ticket.name = entity_name;
111 info.ticket.global_id = global_id;
112 info.ticket.auid = eauth.auid;
113 info.validity += cct->_conf->auth_mon_ticket_ttl;
114
115 if (auid) *auid = eauth.auid;
116
117 key_server->generate_secret(session_key);
118
119 info.session_key = session_key;
120 info.service_id = CEPH_ENTITY_TYPE_AUTH;
121 if (!key_server->get_service_secret(CEPH_ENTITY_TYPE_AUTH, info.service_secret, info.secret_id)) {
122 ldout(cct, 0) << " could not get service secret for auth subsystem" << dendl;
123 ret = -EIO;
124 break;
125 }
126
127 vector<CephXSessionAuthInfo> info_vec;
128 info_vec.push_back(info);
129
130 build_cephx_response_header(cephx_header.request_type, 0, result_bl);
131 if (!cephx_build_service_ticket_reply(cct, eauth.key, info_vec, should_enc_ticket,
132 old_ticket_info.session_key, result_bl)) {
133 ret = -EIO;
134 }
135
136 if (!key_server->get_service_caps(entity_name, CEPH_ENTITY_TYPE_MON, caps)) {
137 ldout(cct, 0) << " could not get mon caps for " << entity_name << dendl;
138 ret = -EACCES;
139 } else {
140 char *caps_str = caps.caps.c_str();
141 if (!caps_str || !caps_str[0]) {
142 ldout(cct,0) << "mon caps null for " << entity_name << dendl;
143 ret = -EACCES;
144 }
145 }
146 }
147 break;
148
149 case CEPHX_GET_PRINCIPAL_SESSION_KEY:
150 {
151 ldout(cct, 10) << "handle_request get_principal_session_key" << dendl;
152
153 bufferlist tmp_bl;
154 CephXServiceTicketInfo auth_ticket_info;
155 // note: no challenge here.
156 if (!cephx_verify_authorizer(cct, key_server, indata, auth_ticket_info, nullptr,
157 tmp_bl)) {
158 ret = -EPERM;
159 break;
160 }
161
162 CephXServiceTicketRequest ticket_req;
163 ::decode(ticket_req, indata);
164 ldout(cct, 10) << " ticket_req.keys = " << ticket_req.keys << dendl;
165
166 ret = 0;
167 vector<CephXSessionAuthInfo> info_vec;
168 int found_services = 0;
169 int service_err = 0;
170 for (uint32_t service_id = 1; service_id <= ticket_req.keys;
171 service_id <<= 1) {
172 if (ticket_req.keys & service_id) {
173 ldout(cct, 10) << " adding key for service "
174 << ceph_entity_type_name(service_id) << dendl;
175 CephXSessionAuthInfo info;
176 int r = key_server->build_session_auth_info(service_id,
177 auth_ticket_info, info);
178 // tolerate missing MGR rotating key for the purposes of upgrades.
179 if (r < 0) {
180 ldout(cct, 10) << " missing key for service "
181 << ceph_entity_type_name(service_id) << dendl;
182 service_err = r;
183 continue;
184 }
185 info.validity += cct->_conf->auth_service_ticket_ttl;
186 info_vec.push_back(info);
187 ++found_services;
188 }
189 }
190 if (!found_services && service_err) {
191 ldout(cct, 10) << __func__ << " did not find any service keys" << dendl;
192 ret = service_err;
193 }
194 CryptoKey no_key;
195 build_cephx_response_header(cephx_header.request_type, ret, result_bl);
196 cephx_build_service_ticket_reply(cct, auth_ticket_info.session_key, info_vec, false, no_key, result_bl);
197 }
198 break;
199
200 case CEPHX_GET_ROTATING_KEY:
201 {
202 ldout(cct, 10) << "handle_request getting rotating secret for " << entity_name << dendl;
203 build_cephx_response_header(cephx_header.request_type, 0, result_bl);
204 if (!key_server->get_rotating_encrypted(entity_name, result_bl)) {
205 ret = -EPERM;
206 break;
207 }
208 }
209 break;
210
211 default:
212 ldout(cct, 10) << "handle_request unknown op " << cephx_header.request_type << dendl;
213 return -EINVAL;
214 }
215 return ret;
216 }
217
218 void CephxServiceHandler::build_cephx_response_header(int request_type, int status, bufferlist& bl)
219 {
220 struct CephXResponseHeader header;
221 header.request_type = request_type;
222 header.status = status;
223 ::encode(header, bl);
224 }