From: Ricardo Dias Date: Tue, 13 Nov 2018 15:51:39 +0000 (+0000) Subject: msg/async: msgr2: cephx authentication X-Git-Tag: v14.1.0~271^2~48 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=01b247b11085beb822feef73f956430743e4a3de;p=ceph.git msg/async: msgr2: cephx authentication Signed-off-by: Ricardo Dias --- diff --git a/src/msg/Dispatcher.h b/src/msg/Dispatcher.h index fbfa80e86a49..105030855893 100644 --- a/src/msg/Dispatcher.h +++ b/src/msg/Dispatcher.h @@ -1,4 +1,4 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system @@ -7,9 +7,9 @@ * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2.1, as published by the Free Software + * License version 2.1, as published by the Free Software * Foundation. See file COPYING. - * + * */ @@ -167,7 +167,7 @@ public: virtual void ms_handle_fast_accept(Connection *con) {} /* - * this indicates that the ordered+reliable delivery semantics have + * this indicates that the ordered+reliable delivery semantics have * been violated. Messages may have been lost due to a fault * in the network connection. * Only called on lossy Connections. @@ -187,7 +187,7 @@ public: * a reference to it. */ virtual void ms_handle_remote_reset(Connection *con) = 0; - + /** * This indicates that the connection is both broken and further * connection attempts are failing because other side refuses @@ -202,6 +202,15 @@ public: * @defgroup Authentication * @{ */ + + /** + * Return the allowed authentication methods for peer + **/ + virtual int ms_get_auth_allowed_methods( + uint32_t peer_type, std::vector &allowed_methods) { + return 0; + } + /** * handle successful authentication (msgr2) * diff --git a/src/msg/Messenger.cc b/src/msg/Messenger.cc index 75b9d2082091..d7dc58fc0a6c 100644 --- a/src/msg/Messenger.cc +++ b/src/msg/Messenger.cc @@ -118,6 +118,37 @@ int Messenger::bindv(const entity_addrvec_t& addrs) return bind(addrs.legacy_addr()); } +void Messenger::ms_deliver_get_auth_allowed_methods( + int peer_type, std::vector &allowed_methods) +{ + for (const auto &dispatcher : dispatchers) { + if (dispatcher->ms_get_auth_allowed_methods(peer_type, allowed_methods)) + return; + } + if (allowed_methods.empty()) { + if (get_mytype() == CEPH_ENTITY_TYPE_MON && + peer_type != CEPH_ENTITY_TYPE_MON) { + allowed_methods.push_back(CEPH_AUTH_NONE); + return; + } + std::string method; + if (!cct->_conf->auth_supported.empty()) { + method = cct->_conf->auth_supported; + } else if (peer_type == CEPH_ENTITY_TYPE_OSD || + peer_type == CEPH_ENTITY_TYPE_MDS || + peer_type == CEPH_ENTITY_TYPE_MON || + peer_type == CEPH_ENTITY_TYPE_MGR) { + method = cct->_conf->auth_cluster_required; + } else { + method = cct->_conf->auth_client_required; + } + AuthMethodList auth_list(cct, method); + for (auto pt : auth_list.get_supported_set()) { + allowed_methods.push_back(pt); + } + } +} + bool Messenger::ms_deliver_verify_authorizer( Connection *con, int peer_type, diff --git a/src/msg/Messenger.h b/src/msg/Messenger.h index 04a7686c868d..6e26bf528271 100644 --- a/src/msg/Messenger.h +++ b/src/msg/Messenger.h @@ -1,4 +1,4 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system @@ -7,9 +7,9 @@ * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public - * License version 2.1, as published by the Free Software + * License version 2.1, as published by the Free Software * Foundation. See file COPYING. - * + * */ @@ -334,7 +334,7 @@ public: * * @param d The Dispatcher to insert into the list. */ - void add_dispatcher_head(Dispatcher *d) { + void add_dispatcher_head(Dispatcher *d) { bool first = dispatchers.empty(); dispatchers.push_front(d); if (d->ms_can_fast_dispatch_any()) @@ -349,7 +349,7 @@ public: * * @param d The Dispatcher to insert into the list. */ - void add_dispatcher_tail(Dispatcher *d) { + void add_dispatcher_tail(Dispatcher *d) { bool first = dispatchers.empty(); dispatchers.push_back(d); if (d->ms_can_fast_dispatch_any()) @@ -745,6 +745,12 @@ public: } } + /** + * Get allowed authentication methods for a specific peer type + **/ + void ms_deliver_get_auth_allowed_methods( + int peer_type, std::vector &allowed_methods); + /** * Get the AuthAuthorizer for a new outgoing Connection. * diff --git a/src/msg/async/ProtocolV2.cc b/src/msg/async/ProtocolV2.cc index b8d29b641a54..b5b36f025d34 100644 --- a/src/msg/async/ProtocolV2.cc +++ b/src/msg/async/ProtocolV2.cc @@ -53,6 +53,8 @@ ProtocolV2::ProtocolV2(AsyncConnection *connection) temp_buffer(nullptr), state(NONE), peer_required_features(0), + authorizer(nullptr), + got_bad_auth(false), cookie(0), connect_seq(0), peer_global_seq(0), @@ -65,9 +67,23 @@ ProtocolV2::ProtocolV2(AsyncConnection *connection) temp_buffer = new char[4096]; } -ProtocolV2::~ProtocolV2() { delete[] temp_buffer; } +ProtocolV2::~ProtocolV2() { + delete[] temp_buffer; + if (authorizer) { + delete authorizer; + } +} + +void ProtocolV2::connect() { + state = START_CONNECT; -void ProtocolV2::connect() { state = START_CONNECT; } + got_bad_auth = false; + if (authorizer) { + delete authorizer; + authorizer = nullptr; + } + global_seq = messenger->get_global_seq(); +} void ProtocolV2::accept() { state = START_ACCEPT; } @@ -180,6 +196,14 @@ uint64_t ProtocolV2::discard_requeued_up_to(uint64_t out_seq, uint64_t seq) { } void ProtocolV2::reset_recv_state() { + if (state == CONNECTING) { + if (authorizer) { + delete authorizer; + } + authorizer = nullptr; + got_bad_auth = false; + } + // clean read and write callbacks connection->pendingReadLen.reset(); connection->writeCallback.reset(); @@ -863,39 +887,52 @@ CtPtr ProtocolV2::handle_auth_more(char *payload, uint32_t length) { ldout(cct, 20) << __func__ << " payload_len=" << length << dendl; AuthMoreFrame auth_more(payload, length); - ldout(cct, 1) << __func__ << " auth more len=" << auth_more.len << dendl; - - /* BEGIN TO REMOVE */ - auto p = auth_more.auth_payload.cbegin(); - int32_t i; - std::string s; - try { - decode(i, p); - decode(s, p); - } catch (const buffer::error &e) { - lderr(cct) << __func__ << " decode auth_payload failed" << dendl; - return _fault(); - } + ldout(cct, 1) << __func__ + << " auth more len=" << auth_more.auth_payload.length() + << dendl; - ldout(cct, 10) << __func__ << " (TO REMOVE) auth_more (" << (int32_t)i << ", " - << s << ")" << dendl; + if (state == CONNECTING) { + ldout(cct, 10) << __func__ << " connect got auth challenge" << dendl; - if (i == 45 && s == "hello server more") { - bufferlist auth_bl; - encode((int32_t)55, auth_bl, 0); - std::string hello("hello client more"); - encode(hello, auth_bl, 0); - /* END TO REMOVE */ - AuthMoreFrame more(auth_bl); - bufferlist &bl = more.get_buffer(); - return WRITE(bl, handle_auth_more_write); - } - /* END TO REMOVE */ + ceph_assert(authorizer); + authorizer->add_challenge(cct, auth_more.auth_payload); + AuthMoreFrame more_reply(authorizer->bl); + return WRITE(more_reply.get_buffer(), handle_auth_more_write); - AuthDoneFrame auth_done(0); + } else if (state == ACCEPTING) { + connection->lock.unlock(); + bool authorizer_valid; + bufferlist authorizer_reply; + ceph_assert((bool)authorizer_challenge); + if (!messenger->ms_deliver_verify_authorizer( + connection, connection->peer_type, auth_method, + auth_more.auth_payload, authorizer_reply, authorizer_valid, + session_key, &authorizer_challenge) || + !authorizer_valid) { + connection->lock.lock(); - bufferlist &bl = auth_done.get_buffer(); - return WRITE(bl, handle_auth_done_write); + ldout(cct, 0) << __func__ << " got bad authorizer, auth_reply_len=" + << authorizer_reply.length() << dendl; + session_security.reset(); + AuthBadAuthFrame bad_auth(EPERM, "Bad Authorizer"); + bufferlist &bl = bad_auth.get_buffer(); + return WRITE(bl, handle_auth_bad_auth_write); + } + + connection->lock.lock(); + + session_security.reset(get_auth_session_handler( + cct, auth_method, session_key, + CEPH_FEATURE_MSG_AUTH | CEPH_FEATURE_CEPHX_V2)); + + AuthDoneFrame auth_done(0, authorizer_reply); + bufferlist &bl = auth_done.get_buffer(); + return WRITE(bl, handle_auth_done_write); + } else { + ceph_abort(); + } + + return nullptr; } CtPtr ProtocolV2::handle_auth_more_write(int r) { @@ -1412,8 +1449,6 @@ CtPtr ProtocolV2::start_client_banner_exchange() { ldout(cct, 20) << __func__ << dendl; state = CONNECTING; - global_seq = messenger->get_global_seq(); - return _banner_exchange(CONTINUATION(post_client_banner_exchange)); } @@ -1426,28 +1461,49 @@ CtPtr ProtocolV2::post_client_banner_exchange() { return send_auth_request(); } -CtPtr ProtocolV2::send_auth_request(std::vector<__u32> allowed_methods) { +CtPtr ProtocolV2::send_auth_request(std::vector allowed_methods) { ldout(cct, 20) << __func__ << dendl; - // We need to get an authorizer at this point. - // this->messenger->get_authorizer(...) - - bufferlist auth_bl; - /* BEGIN TO REMOVE */ - encode((int32_t)35, auth_bl, 0); - std::string hello("hello"); - encode(hello, auth_bl, 0); - /* END TO REMOVE */ - __le32 method; - if (allowed_methods.empty()) { - // choose client's preferred method - method = 23; // 23 is just for testing purposes (REMOVE THIS) - } else { - // choose one of the allowed methods - method = allowed_methods[0]; + if (!authorizer) { + authorizer = + messenger->ms_deliver_get_authorizer(connection->peer_type); + } + + auth_method = CEPH_AUTH_NONE; + if (!authorizer) { + if (!allowed_methods.empty() && + std::find(allowed_methods.begin(), allowed_methods.end(), + auth_method) == allowed_methods.end()) { + ldout(cct, 0) << __func__ + << " peer requires authentication, stopping connection" + << dendl; + stop(); + connection->dispatch_queue->queue_reset(connection); + return nullptr; + } + ldout(cct, 10) << __func__ << " authorizer not found for peer_type=" + << connection->peer_type << dendl; + AuthRequestFrame authFrame(auth_method); + bufferlist &bl = authFrame.get_buffer(); + return WRITE(bl, handle_auth_request_write); + } + + auth_method = authorizer->protocol; + if (!allowed_methods.empty() && + std::find(allowed_methods.begin(), allowed_methods.end(), auth_method) == + allowed_methods.end()) { + ldout(cct, 0) << __func__ << " peer does not allow authentication method=" + << auth_method << dendl; + stop(); + connection->dispatch_queue->queue_reset(connection); + return nullptr; } - AuthRequestFrame authFrame(method, auth_bl); + ldout(cct, 10) << __func__ + << " sending auth request len=" << authorizer->bl.length() + << dendl; + + AuthRequestFrame authFrame(auth_method, authorizer->bl); bufferlist &bl = authFrame.get_buffer(); return WRITE(bl, handle_auth_request_write); } @@ -1483,16 +1539,53 @@ CtPtr ProtocolV2::handle_auth_bad_auth(char *payload, uint32_t length) { << " error code=" << bad_auth.error_code << " error message=" << bad_auth.error_msg << dendl; - return _fault(); + if (got_bad_auth) { + return _fault(); + } + + got_bad_auth = true; + delete authorizer; + authorizer = messenger->ms_deliver_get_authorizer(connection->peer_type, + true); // try harder + ldout(cct, 10) << __func__ + << " sending auth request len=" << authorizer->bl.length() + << dendl; + + AuthRequestFrame authFrame(auth_method, authorizer->bl); + bufferlist &bl = authFrame.get_buffer(); + return WRITE(bl, handle_auth_request_write); } CtPtr ProtocolV2::handle_auth_done(char *payload, uint32_t length) { ldout(cct, 20) << __func__ << " payload_len=" << length << dendl; AuthDoneFrame auth_done(payload, length); + + if (authorizer) { + auto iter = auth_done.auth_payload.cbegin(); + if (!authorizer->verify_reply(iter)) { + ldout(cct, 0) << __func__ << " failed verifying authorize reply" << dendl; + return _fault(); + } + } + ldout(cct, 1) << __func__ << " authentication done," << " flags=" << auth_done.flags << dendl; + if (authorizer) { + ldout(cct, 10) << __func__ << " setting up session_security with auth " + << authorizer << dendl; + session_security.reset(get_auth_session_handler( + cct, authorizer->protocol, authorizer->session_key, + CEPH_FEATURE_MSG_AUTH | CEPH_FEATURE_CEPHX_V2)); + } else { + // We have no authorizer, so we shouldn't be applying security to messages + // in this connection. + ldout(cct, 10) << __func__ << " no authorizer, clearing session_security" + << dendl; + session_security.reset(); + } + if (!cookie) { ceph_assert(connect_seq == 0); return send_client_ident(); @@ -1707,42 +1800,12 @@ CtPtr ProtocolV2::handle_auth_request(char *payload, uint32_t length) { ldout(cct, 10) << __func__ << " AuthRequest(method=" << auth_request.method << ", auth_len=" << auth_request.len << ")" << dendl; - /* BEGIN TO REMOVE */ - auto p = auth_request.auth_payload.cbegin(); - int32_t i; - std::string s; - try { - decode(i, p); - decode(s, p); - } catch (const buffer::error &e) { - lderr(cct) << __func__ << " decode auth_payload failed" << dendl; - return _fault(); - } - - ldout(cct, 10) << __func__ << " (TO REMOVE) auth_payload (" << (int32_t)i - << ", " << s << ")" << dendl; - - /* END TO REMOVE */ - - /* - * Get the auth methods from somewhere. - * In V1 the allowed auth methods depend on the peer_type. - * In V2, at this stage, we still don't know the peer_type so either - * we define the set of allowed auth methods for any entity type, - * or we need to exchange the entity type before reaching this point. - */ - - std::vector<__u32> allowed_methods = {CEPH_AUTH_NONE, CEPH_AUTH_CEPHX}; - - bool found = false; - for (const auto &a_method : allowed_methods) { - if (a_method == auth_request.method) { - // auth method allowed by the server - found = true; - break; - } - } + std::vector allowed_methods; + messenger->ms_deliver_get_auth_allowed_methods(connection->peer_type, + allowed_methods); + bool found = std::find(allowed_methods.begin(), allowed_methods.end(), + auth_request.method) != allowed_methods.end(); if (!found) { ldout(cct, 1) << __func__ << " auth method=" << auth_request.method << " not allowed" << dendl; @@ -1753,24 +1816,54 @@ CtPtr ProtocolV2::handle_auth_request(char *payload, uint32_t length) { ldout(cct, 10) << __func__ << " auth method=" << auth_request.method << " accepted" << dendl; - // verify authorization blob - bool valid = i == 35; - - if (!valid) { - AuthBadAuthFrame bad_auth(12, "Permission denied"); - bufferlist &bl = bad_auth.get_buffer(); - return WRITE(bl, handle_auth_bad_auth_write); - } - - bufferlist auth_bl; - /* BEGIN TO REMOVE */ - encode((int32_t)45, auth_bl, 0); - std::string hello("hello server more"); - encode(hello, auth_bl, 0); - /* END TO REMOVE */ - AuthMoreFrame more(auth_bl); - bufferlist &bl = more.get_buffer(); - return WRITE(bl, handle_auth_more_write); + + auth_method = auth_request.method; + + if (auth_request.method == CEPH_AUTH_NONE) { + ldout(cct, 1) << __func__ << " proceeding without authentication" << dendl; + + session_security.reset(); + bufferlist empty_bl; + AuthDoneFrame auth_done(0, empty_bl); + bufferlist &bl = auth_done.get_buffer(); + return WRITE(bl, handle_auth_done_write); + } + + connection->lock.unlock(); + bool authorizer_valid; + bufferlist authorizer_reply; + bool had_challenge = (bool)authorizer_challenge; + if (!messenger->ms_deliver_verify_authorizer( + connection, connection->peer_type, auth_request.method, + auth_request.auth_payload, authorizer_reply, authorizer_valid, + session_key, &authorizer_challenge) || + !authorizer_valid) { + connection->lock.lock(); + + if (!had_challenge && authorizer_challenge) { + ldout(cct, 10) << __func__ << " challenging authorizer" << dendl; + ceph_assert(authorizer_reply.length()); + AuthMoreFrame more(authorizer_reply); + return WRITE(more.get_buffer(), handle_auth_more_write); + } else { + ldout(cct, 0) << __func__ << " got bad authorizer, auth_reply_len=" + << authorizer_reply.length() << dendl; + session_security.reset(); + AuthBadAuthFrame bad_auth(EPERM, "Bad Authorizer"); + bufferlist &bl = bad_auth.get_buffer(); + return WRITE(bl, handle_auth_bad_auth_write); + } + } + + connection->lock.lock(); + + session_security.reset( + get_auth_session_handler(cct, auth_method, session_key, + CEPH_FEATURE_MSG_AUTH | CEPH_FEATURE_CEPHX_V2)); + + AuthDoneFrame auth_done(0, authorizer_reply); + bufferlist &bl = auth_done.get_buffer(); + return WRITE(bl, handle_auth_done_write); } CtPtr ProtocolV2::handle_auth_bad_method_write(int r) { diff --git a/src/msg/async/ProtocolV2.h b/src/msg/async/ProtocolV2.h index bd8ff9e4191f..be44f379bf44 100644 --- a/src/msg/async/ProtocolV2.h +++ b/src/msg/async/ProtocolV2.h @@ -104,6 +104,11 @@ private: payload.claim_append(auth_payload); } + AuthRequestFrame(uint32_t method) : Frame(Tag::AUTH_REQUEST) { + encode(method, payload, 0); + encode((uint32_t)0, payload, 0); + } + AuthRequestFrame(char *payload, uint32_t length) : Frame() { method = *(uint32_t *)payload; len = *(uint32_t *)(payload + sizeof(uint32_t)); @@ -114,9 +119,9 @@ private: struct AuthBadMethodFrame : public Frame { uint32_t method; - std::vector<__u32> allowed_methods; + std::vector allowed_methods; - AuthBadMethodFrame(uint32_t method, std::vector<__u32> methods) + AuthBadMethodFrame(uint32_t method, std::vector methods) : Frame(Tag::AUTH_BAD_METHOD) { encode(method, payload, 0); encode((uint32_t)methods.size(), payload, 0); @@ -154,7 +159,6 @@ private: }; struct AuthMoreFrame : public Frame { - uint32_t len; bufferlist auth_payload; AuthMoreFrame(bufferlist &auth_payload) : Frame(Tag::AUTH_MORE) { @@ -163,7 +167,7 @@ private: } AuthMoreFrame(char *payload, uint32_t length) : Frame() { - len = *(uint32_t *)payload; + uint32_t len = *(uint32_t *)payload; ceph_assert((length - sizeof(uint32_t)) == len); auth_payload.append(payload + sizeof(uint32_t), len); } @@ -171,13 +175,21 @@ private: struct AuthDoneFrame : public Frame { uint64_t flags; + bufferlist auth_payload; - AuthDoneFrame(uint64_t flags) : Frame(Tag::AUTH_DONE) { + AuthDoneFrame(uint64_t flags, bufferlist &auth_payload) + : Frame(Tag::AUTH_DONE) { encode(flags, payload, 0); + encode(auth_payload.length(), payload, 0); + payload.claim_append(auth_payload); } AuthDoneFrame(char *payload, uint32_t length) : Frame() { flags = *(uint64_t *)payload; + payload += sizeof(uint64_t); + uint32_t len = *(uint32_t *)payload; + ceph_assert((length - sizeof(uint32_t) - sizeof(uint64_t)) == len); + auth_payload.append(payload + sizeof(uint32_t), len); } }; @@ -435,6 +447,12 @@ private: char *temp_buffer; State state; uint64_t peer_required_features; + AuthAuthorizer *authorizer; + uint32_t auth_method; + bool got_bad_auth; + CryptoKey session_key; + std::shared_ptr session_security; + std::unique_ptr authorizer_challenge; uint64_t connection_features; uint64_t cookie; uint64_t global_seq; @@ -562,7 +580,7 @@ private: Ct *start_client_banner_exchange(); Ct *post_client_banner_exchange(); - Ct *send_auth_request(std::vector<__u32> allowed_methods = {}); + Ct *send_auth_request(std::vector allowed_methods = {}); Ct *handle_auth_request_write(int r); Ct *handle_auth_bad_method(char *payload, uint32_t length); Ct *handle_auth_bad_auth(char *payload, uint32_t length);