Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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       if (!cephx_verify_authorizer(cct, key_server, indata, auth_ticket_info, tmp_bl)) {
156         ret = -EPERM;
157         break;
158       }
159
160       CephXServiceTicketRequest ticket_req;
161       ::decode(ticket_req, indata);
162       ldout(cct, 10) << " ticket_req.keys = " << ticket_req.keys << dendl;
163
164       ret = 0;
165       vector<CephXSessionAuthInfo> info_vec;
166       int found_services = 0;
167       int service_err = 0;
168       for (uint32_t service_id = 1; service_id <= ticket_req.keys;
169            service_id <<= 1) {
170         if (ticket_req.keys & service_id) {
171           ldout(cct, 10) << " adding key for service "
172                          << ceph_entity_type_name(service_id) << dendl;
173           CephXSessionAuthInfo info;
174           int r = key_server->build_session_auth_info(service_id,
175                                                       auth_ticket_info, info);
176           // tolerate missing MGR rotating key for the purposes of upgrades.
177           if (r < 0) {
178             ldout(cct, 10) << "   missing key for service "
179                            << ceph_entity_type_name(service_id) << dendl;
180             service_err = r;
181             continue;
182           }
183           info.validity += cct->_conf->auth_service_ticket_ttl;
184           info_vec.push_back(info);
185           ++found_services;
186         }
187       }
188       if (!found_services && service_err) {
189         ldout(cct, 10) << __func__ << " did not find any service keys" << dendl;
190         ret = service_err;
191       }
192       CryptoKey no_key;
193       build_cephx_response_header(cephx_header.request_type, ret, result_bl);
194       cephx_build_service_ticket_reply(cct, auth_ticket_info.session_key, info_vec, false, no_key, result_bl);
195     }
196     break;
197
198   case CEPHX_GET_ROTATING_KEY:
199     {
200       ldout(cct, 10) << "handle_request getting rotating secret for " << entity_name << dendl;
201       build_cephx_response_header(cephx_header.request_type, 0, result_bl);
202       if (!key_server->get_rotating_encrypted(entity_name, result_bl)) {
203         ret = -EPERM;
204         break;
205       }
206     }
207     break;
208
209   default:
210     ldout(cct, 10) << "handle_request unknown op " << cephx_header.request_type << dendl;
211     return -EINVAL;
212   }
213   return ret;
214 }
215
216 void CephxServiceHandler::build_cephx_response_header(int request_type, int status, bufferlist& bl)
217 {
218   struct CephXResponseHeader header;
219   header.request_type = request_type;
220   header.status = status;
221   ::encode(header, bl);
222 }