class CryptoKey;
struct AuthCapsInfo;
+enum class global_id_status_t {
+ NONE,
+ // fresh client (global_id == 0); waiting for CephXAuthenticate
+ NEW_PENDING,
+ // connected client; new enough to correctly reclaim global_id
+ NEW_OK,
+ // connected client; unknown whether it can reclaim global_id correctly
+ NEW_NOT_EXPOSED,
+ // reconnecting client (global_id != 0); waiting for CephXAuthenticate
+ RECLAIM_PENDING,
+ // reconnected client; correctly reclaimed global_id
+ RECLAIM_OK,
+ // reconnected client; did not properly prove prior global_id ownership
+ RECLAIM_INSECURE
+};
+
struct AuthServiceHandler {
protected:
CephContext *cct;
EntityName entity_name;
uint64_t global_id = 0;
+ global_id_status_t global_id_status = global_id_status_t::NONE;
public:
explicit AuthServiceHandler(CephContext *cct_) : cct(cct_) {}
virtual int handle_request(ceph::buffer::list::const_iterator& indata,
size_t connection_secret_required_length,
ceph::buffer::list *result,
- uint64_t *global_id,
AuthCapsInfo *caps,
CryptoKey *session_key,
std::string *connection_secret) = 0;
const EntityName& get_entity_name() { return entity_name; }
uint64_t get_global_id() { return global_id; }
+ global_id_status_t get_global_id_status() { return global_id_status; }
private:
virtual int do_start_session(bool is_new_global_id,
bufferlist *result_bl,
AuthCapsInfo *caps)
{
+ global_id_status = is_new_global_id ? global_id_status_t::NEW_PENDING :
+ global_id_status_t::RECLAIM_PENDING;
+
uint64_t min = 1; // always non-zero
uint64_t max = std::numeric_limits<uint64_t>::max();
server_challenge = ceph::util::generate_random_number<uint64_t>(min, max);
return 0;
}
+int CephxServiceHandler::verify_old_ticket(
+ const CephXAuthenticate& req,
+ CephXServiceTicketInfo& old_ticket_info,
+ bool& should_enc_ticket)
+{
+ ldout(cct, 20) << " checking old_ticket: secret_id="
+ << req.old_ticket.secret_id
+ << " len=" << req.old_ticket.blob.length()
+ << ", old_ticket_may_be_omitted="
+ << req.old_ticket_may_be_omitted << dendl;
+ ceph_assert(global_id_status != global_id_status_t::NONE);
+ if (global_id_status == global_id_status_t::NEW_PENDING) {
+ // old ticket is not needed
+ if (req.old_ticket.blob.length()) {
+ ldout(cct, 0) << " superfluous ticket presented" << dendl;
+ return -EINVAL;
+ }
+ if (req.old_ticket_may_be_omitted) {
+ ldout(cct, 10) << " new global_id " << global_id
+ << " (unexposed legacy client)" << dendl;
+ global_id_status = global_id_status_t::NEW_NOT_EXPOSED;
+ } else {
+ ldout(cct, 10) << " new global_id " << global_id << dendl;
+ global_id_status = global_id_status_t::NEW_OK;
+ }
+ return 0;
+ }
+
+ if (!req.old_ticket.blob.length()) {
+ // old ticket is needed but not presented
+ if (cct->_conf->auth_allow_insecure_global_id_reclaim &&
+ req.old_ticket_may_be_omitted) {
+ ldout(cct, 10) << " allowing reclaim of global_id " << global_id
+ << " with no ticket presented (legacy client, auth_allow_insecure_global_id_reclaim=true)"
+ << dendl;
+ global_id_status = global_id_status_t::RECLAIM_INSECURE;
+ return 0;
+ }
+ ldout(cct, 0) << " attempt to reclaim global_id " << global_id
+ << " without presenting ticket" << dendl;
+ return -EACCES;
+ }
+
+ if (!cephx_decode_ticket(cct, key_server, CEPH_ENTITY_TYPE_AUTH,
+ req.old_ticket, old_ticket_info)) {
+ if (cct->_conf->auth_allow_insecure_global_id_reclaim &&
+ req.old_ticket_may_be_omitted) {
+ ldout(cct, 10) << " allowing reclaim of global_id " << global_id
+ << " using bad ticket (legacy client, auth_allow_insecure_global_id_reclaim=true)"
+ << dendl;
+ global_id_status = global_id_status_t::RECLAIM_INSECURE;
+ return 0;
+ }
+ ldout(cct, 0) << " attempt to reclaim global_id " << global_id
+ << " using bad ticket" << dendl;
+ return -EACCES;
+ }
+ ldout(cct, 20) << " decoded old_ticket: global_id="
+ << old_ticket_info.ticket.global_id << dendl;
+ if (global_id != old_ticket_info.ticket.global_id) {
+ if (cct->_conf->auth_allow_insecure_global_id_reclaim &&
+ req.old_ticket_may_be_omitted) {
+ ldout(cct, 10) << " allowing reclaim of global_id " << global_id
+ << " using mismatching ticket (legacy client, auth_allow_insecure_global_id_reclaim=true)"
+ << dendl;
+ global_id_status = global_id_status_t::RECLAIM_INSECURE;
+ return 0;
+ }
+ ldout(cct, 0) << " attempt to reclaim global_id " << global_id
+ << " using mismatching ticket" << dendl;
+ return -EACCES;
+ }
+ ldout(cct, 10) << " allowing reclaim of global_id " << global_id
+ << " (valid ticket presented, will encrypt new ticket)"
+ << dendl;
+ global_id_status = global_id_status_t::RECLAIM_OK;
+ should_enc_ticket = true;
+ return 0;
+}
+
int CephxServiceHandler::handle_request(
bufferlist::const_iterator& indata,
size_t connection_secret_required_len,
bufferlist *result_bl,
- uint64_t *global_id,
AuthCapsInfo *caps,
CryptoKey *psession_key,
std::string *pconnection_secret)
ret = -EACCES;
break;
}
- CephXServiceTicketInfo old_ticket_info;
- if (cephx_decode_ticket(cct, key_server, CEPH_ENTITY_TYPE_AUTH,
- req.old_ticket, old_ticket_info)) {
- *global_id = old_ticket_info.ticket.global_id;
- ldout(cct, 10) << "decoded old_ticket with global_id=" << *global_id
- << dendl;
- should_enc_ticket = true;
+ CephXServiceTicketInfo old_ticket_info;
+ ret = verify_old_ticket(req, old_ticket_info, should_enc_ticket);
+ if (ret) {
+ ldout(cct, 0) << " could not verify old ticket" << dendl;
+ break;
}
- ldout(cct,10) << __func__ << " auth ticket global_id " << *global_id
- << dendl;
info.ticket.init_timestamps(ceph_clock_now(),
cct->_conf->auth_mon_ticket_ttl);
info.ticket.name = entity_name;
- info.ticket.global_id = *global_id;
+ info.ticket.global_id = global_id;
info.validity += cct->_conf->auth_mon_ticket_ttl;
key_server->generate_secret(session_key);