diff options
Diffstat (limited to '')
-rw-r--r-- | src/auth/krb/KrbAuthorizeHandler.cpp | 53 | ||||
-rw-r--r-- | src/auth/krb/KrbAuthorizeHandler.hpp | 46 | ||||
-rw-r--r-- | src/auth/krb/KrbClientHandler.cpp | 253 | ||||
-rw-r--r-- | src/auth/krb/KrbClientHandler.hpp | 84 | ||||
-rw-r--r-- | src/auth/krb/KrbProtocol.cpp | 86 | ||||
-rw-r--r-- | src/auth/krb/KrbProtocol.hpp | 160 | ||||
-rw-r--r-- | src/auth/krb/KrbServiceHandler.cpp | 225 | ||||
-rw-r--r-- | src/auth/krb/KrbServiceHandler.hpp | 61 | ||||
-rw-r--r-- | src/auth/krb/KrbSessionHandler.hpp | 37 |
9 files changed, 1005 insertions, 0 deletions
diff --git a/src/auth/krb/KrbAuthorizeHandler.cpp b/src/auth/krb/KrbAuthorizeHandler.cpp new file mode 100644 index 00000000..1faad8bb --- /dev/null +++ b/src/auth/krb/KrbAuthorizeHandler.cpp @@ -0,0 +1,53 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (c) 2018 SUSE LLC. + * Author: Daniel Oliveira <doliveira@suse.com> + * + * 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 + * Foundation. See file COPYING. + * + */ + +#include "KrbAuthorizeHandler.hpp" + +#include "common/debug.h" + +#define dout_subsys ceph_subsys_auth + +bool KrbAuthorizeHandler::verify_authorizer( + CephContext* ceph_ctx, + KeyStore* keys, + const bufferlist& authorizer_data, + size_t connection_secret_required_len, + bufferlist *authorizer_reply, + EntityName *entity_name, + uint64_t *global_id, + AuthCapsInfo *caps_info, + CryptoKey *session_key, + std::string *connection_secret, + std::unique_ptr<AuthAuthorizerChallenge>* challenge) +{ + auto itr(authorizer_data.cbegin()); + + try { + uint8_t value = (1); + + using ceph::decode; + decode(value, itr); + decode(*entity_name, itr); + decode(*global_id, itr); + } catch (const buffer::error& err) { + ldout(ceph_ctx, 0) + << "Error: KrbAuthorizeHandler::verify_authorizer() failed!" << dendl; + return false; + } + caps_info->allow_all = true; + return true; +} + + diff --git a/src/auth/krb/KrbAuthorizeHandler.hpp b/src/auth/krb/KrbAuthorizeHandler.hpp new file mode 100644 index 00000000..bc8eac62 --- /dev/null +++ b/src/auth/krb/KrbAuthorizeHandler.hpp @@ -0,0 +1,46 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (c) 2018 SUSE LLC. + * Author: Daniel Oliveira <doliveira@suse.com> + * + * 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 + * Foundation. See file COPYING. + * + */ + +#ifndef KRB_AUTHORIZE_HANDLER_HPP +#define KRB_AUTHORIZE_HANDLER_HPP + +#include "auth/AuthAuthorizeHandler.h" + +class KrbAuthorizeHandler : public AuthAuthorizeHandler { + bool verify_authorizer( + CephContext*, + KeyStore*, + const bufferlist&, + size_t, + bufferlist *, + EntityName *, + uint64_t *, + AuthCapsInfo *, + CryptoKey *, + std::string *connection_secret, + std::unique_ptr< + AuthAuthorizerChallenge>* = nullptr) override; + + int authorizer_session_crypto() override { + return SESSION_SYMMETRIC_AUTHENTICATE; + }; + + ~KrbAuthorizeHandler() override = default; + +}; + + +#endif //-- KRB_AUTHORIZE_HANDLER_HPP + diff --git a/src/auth/krb/KrbClientHandler.cpp b/src/auth/krb/KrbClientHandler.cpp new file mode 100644 index 00000000..e39d074e --- /dev/null +++ b/src/auth/krb/KrbClientHandler.cpp @@ -0,0 +1,253 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (c) 2018 SUSE LLC. + * Author: Daniel Oliveira <doliveira@suse.com> + * + * 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 + * Foundation. See file COPYING. + * + */ + +#include "KrbClientHandler.hpp" + +#include <errno.h> +#include <string> +#include "KrbProtocol.hpp" + +#include "auth/KeyRing.h" +#include "include/random.h" +#include "common/ceph_context.h" +#include "common/config.h" +#include "common/dout.h" + +#define dout_subsys ceph_subsys_auth +#undef dout_prefix +#define dout_prefix *_dout << "krb5/gssapi client request: " + +struct AuthAuthorizer; + +AuthAuthorizer* +KrbClientHandler::build_authorizer(uint32_t service_id) const +{ + ldout(cct, 20) + << "KrbClientHandler::build_authorizer(): Service: " + << ceph_entity_type_name(service_id) << dendl; + + KrbAuthorizer* krb_auth = new KrbAuthorizer(); + if (krb_auth) { + krb_auth->build_authorizer(cct->_conf->name, global_id); + } + return krb_auth; +} + + +KrbClientHandler::~KrbClientHandler() +{ + OM_uint32 gss_minor_status(0); + + gss_release_name(&gss_minor_status, &m_gss_client_name); + gss_release_name(&gss_minor_status, &m_gss_service_name); + gss_release_cred(&gss_minor_status, &m_gss_credentials); + gss_delete_sec_context(&gss_minor_status, &m_gss_sec_ctx, GSS_C_NO_BUFFER); + gss_release_buffer(&gss_minor_status, + static_cast<gss_buffer_t>(&m_gss_buffer_out)); +} + + +int KrbClientHandler::build_request(bufferlist& buff_list) const +{ + ldout(cct, 20) + << "KrbClientHandler::build_request() " << dendl; + + KrbTokenBlob krb_token; + KrbRequest krb_request; + + krb_request.m_request_type = + static_cast<int>(GSSAuthenticationRequest::GSS_TOKEN); + + using ceph::encode; + encode(krb_request, buff_list); + + if (m_gss_buffer_out.length != 0) { + krb_token.m_token_blob.append(buffer::create_static( + m_gss_buffer_out.length, + reinterpret_cast<char*> + (m_gss_buffer_out.value))); + + encode(krb_token, buff_list); + ldout(cct, 20) + << "KrbClientHandler::build_request() : Token Blob: " << "\n"; + krb_token.m_token_blob.hexdump(*_dout); + *_dout << dendl; + } + return 0; +} + + +int KrbClientHandler::handle_response( + int ret, + bufferlist::const_iterator& buff_list, + CryptoKey *session_key, + std::string *connection_secret) +{ + auto result(ret); + gss_buffer_desc gss_buffer_in = {0, nullptr}; + gss_OID_set_desc gss_mechs_wanted = {0, nullptr}; + OM_uint32 gss_major_status(0); + OM_uint32 gss_minor_status(0); + OM_uint32 gss_wanted_flags(GSS_C_MUTUAL_FLAG | + GSS_C_INTEG_FLAG); + OM_uint32 gss_result_flags(0); + + ldout(cct, 20) + << "KrbClientHandler::handle_response() " << dendl; + + if (result < 0) { + return result; + } + + gss_mechs_wanted.elements = const_cast<gss_OID>(&GSS_API_SPNEGO_OID_PTR); + gss_mechs_wanted.count = 1; + + KrbResponse krb_response; + + using ceph::decode; + decode(krb_response, buff_list); + if (m_gss_credentials == GSS_C_NO_CREDENTIAL) { + gss_OID krb_client_type = GSS_C_NT_USER_NAME; + std::string krb_client_name(cct->_conf->name.to_str()); + + gss_buffer_in.length = krb_client_name.length(); + gss_buffer_in.value = (const_cast<char*>(krb_client_name.c_str())); + + if (cct->_conf->name.get_type() == CEPH_ENTITY_TYPE_CLIENT) { + gss_major_status = gss_import_name(&gss_minor_status, + &gss_buffer_in, + krb_client_type, + &m_gss_client_name); + if (gss_major_status != GSS_S_COMPLETE) { + auto status_str(gss_auth_show_status(gss_major_status, + gss_minor_status)); + ldout(cct, 0) + << "ERROR: KrbClientHandler::handle_response() " + "[gss_import_name(gss_client_name)] failed! " + << gss_major_status << " " + << gss_minor_status << " " + << status_str + << dendl; + } + } + + gss_major_status = gss_acquire_cred(&gss_minor_status, + m_gss_client_name, + 0, + &gss_mechs_wanted, + GSS_C_INITIATE, + &m_gss_credentials, + nullptr, + nullptr); + if (gss_major_status != GSS_S_COMPLETE) { + auto status_str(gss_auth_show_status(gss_major_status, + gss_minor_status)); + ldout(cct, 20) + << "ERROR: KrbClientHandler::handle_response() " + "[gss_acquire_cred()] failed! " + << gss_major_status << " " + << gss_minor_status << " " + << status_str + << dendl; + return (-EPERM); + } + + gss_buffer_desc krb_input_name_buff = {0, nullptr}; + gss_OID krb_input_type = GSS_C_NT_HOSTBASED_SERVICE; + std::string gss_target_name(cct->_conf.get_val<std::string> + ("gss_target_name")); + krb_input_name_buff.length = gss_target_name.length(); + krb_input_name_buff.value = (const_cast<char*>(gss_target_name.c_str())); + + gss_major_status = gss_import_name(&gss_minor_status, + &krb_input_name_buff, + krb_input_type, + &m_gss_service_name); + if (gss_major_status != GSS_S_COMPLETE) { + auto status_str(gss_auth_show_status(gss_major_status, + gss_minor_status)); + ldout(cct, 0) + << "ERROR: KrbClientHandler::handle_response() " + "[gss_import_name(gss_service_name)] failed! " + << gss_major_status << " " + << gss_minor_status << " " + << status_str + << dendl; + } + } else { + KrbTokenBlob krb_token; + + using ceph::decode; + decode(krb_token, buff_list); + ldout(cct, 20) + << "KrbClientHandler::handle_response() : Token Blob: " << "\n"; + krb_token.m_token_blob.hexdump(*_dout); + *_dout << dendl; + + gss_buffer_in.length = krb_token.m_token_blob.length(); + gss_buffer_in.value = krb_token.m_token_blob.c_str(); + } + + const gss_OID gss_mech_type = gss_mechs_wanted.elements; + if (m_gss_buffer_out.length != 0) { + gss_release_buffer(&gss_minor_status, + static_cast<gss_buffer_t>(&m_gss_buffer_out)); + } + + gss_major_status = gss_init_sec_context(&gss_minor_status, + m_gss_credentials, + &m_gss_sec_ctx, + m_gss_service_name, + gss_mech_type, + gss_wanted_flags, + 0, + nullptr, + &gss_buffer_in, + nullptr, + &m_gss_buffer_out, + &gss_result_flags, + nullptr); + switch (gss_major_status) { + case GSS_S_CONTINUE_NEEDED: + ldout(cct, 20) + << "KrbClientHandler::handle_response() : " + "[gss_init_sec_context(GSS_S_CONTINUE_NEEDED)] " << dendl; + result = (-EAGAIN); + break; + + case GSS_S_COMPLETE: + ldout(cct, 20) + << "KrbClientHandler::handle_response() : " + "[gss_init_sec_context(GSS_S_COMPLETE)] " << dendl; + result = 0; + break; + + default: + auto status_str(gss_auth_show_status(gss_major_status, + gss_minor_status)); + ldout(cct, 0) + << "ERROR: KrbClientHandler::handle_response() " + "[gss_init_sec_context()] failed! " + << gss_major_status << " " + << gss_minor_status << " " + << status_str + << dendl; + result = (-EPERM); + break; + } + + return result; +} + diff --git a/src/auth/krb/KrbClientHandler.hpp b/src/auth/krb/KrbClientHandler.hpp new file mode 100644 index 00000000..f1546dbb --- /dev/null +++ b/src/auth/krb/KrbClientHandler.hpp @@ -0,0 +1,84 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (c) 2018 SUSE LLC. + * Author: Daniel Oliveira <doliveira@suse.com> + * + * 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 + * Foundation. See file COPYING. + * + */ + +#ifndef KRB_CLIENT_HANDLER_HPP +#define KRB_CLIENT_HANDLER_HPP + +#include "auth/AuthClientHandler.h" +#include "auth/RotatingKeyRing.h" + +#include "KrbProtocol.hpp" + +#include <gssapi.h> +#include <gssapi/gssapi_generic.h> +#include <gssapi/gssapi_krb5.h> +#include <gssapi/gssapi_ext.h> + + +class CephContext; +class Keyring; + + +class KrbClientHandler : public AuthClientHandler { + + public: + KrbClientHandler(CephContext* ceph_ctx = nullptr) + : AuthClientHandler(ceph_ctx) { + reset(); + } + ~KrbClientHandler() override; + + KrbClientHandler* clone() const override { + return new KrbClientHandler(*this); + } + + int get_protocol() const override { return CEPH_AUTH_GSS; } + void reset() override { + m_gss_client_name = GSS_C_NO_NAME; + m_gss_service_name = GSS_C_NO_NAME; + m_gss_credentials = GSS_C_NO_CREDENTIAL; + m_gss_sec_ctx = GSS_C_NO_CONTEXT; + m_gss_buffer_out = {0, 0}; + } + + void prepare_build_request() override { }; + int build_request(bufferlist& buff_list) const override; + int handle_response(int ret, + bufferlist::const_iterator& buff_list, + CryptoKey *session_key, + std::string *connection_secret) override; + + bool build_rotating_request(bufferlist& buff_list) const override { + return false; + } + + AuthAuthorizer* build_authorizer(uint32_t service_id) const override; + bool need_tickets() override { return false; } + void set_global_id(uint64_t guid) override { global_id = guid; } + + + private: + gss_name_t m_gss_client_name; + gss_name_t m_gss_service_name; + gss_cred_id_t m_gss_credentials; + gss_ctx_id_t m_gss_sec_ctx; + gss_buffer_desc m_gss_buffer_out; + + protected: + void validate_tickets() override { } +}; + +#endif //-- KRB_CLIENT_HANDLER_HPP + diff --git a/src/auth/krb/KrbProtocol.cpp b/src/auth/krb/KrbProtocol.cpp new file mode 100644 index 00000000..6988d355 --- /dev/null +++ b/src/auth/krb/KrbProtocol.cpp @@ -0,0 +1,86 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (c) 2018 SUSE LLC. + * Author: Daniel Oliveira <doliveira@suse.com> + * + * 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 + * Foundation. See file COPYING. + * + */ + +#include "KrbProtocol.hpp" + +#include "common/Clock.h" +#include "common/config.h" +#include "common/debug.h" +#include "include/buffer.h" + +#define dout_subsys ceph_subsys_auth +#undef dout_prefix +#define dout_prefix *_dout << "krb5/gssapi protocol: " + + +std::string gss_auth_show_status(const OM_uint32 gss_major_status, + const OM_uint32 gss_minor_status) +{ + const std::string STR_DOT("."); + const std::string STR_BLANK(" "); + + gss_buffer_desc gss_str_status = {0, nullptr}; + OM_uint32 gss_maj_status(0); + OM_uint32 gss_min_status(0); + OM_uint32 gss_ctx_message(-1); + + std::string str_status(""); + + const auto gss_complete_status_str_format = [&](const uint32_t gss_status) { + if (gss_status == GSS_S_COMPLETE) { + std::string str_tmp(""); + str_tmp.append(reinterpret_cast<char*>(gss_str_status.value), + gss_str_status.length); + str_tmp += STR_DOT; + if (gss_ctx_message != 0) { + str_tmp += STR_BLANK; + } + return str_tmp; + } + return STR_BLANK; + }; + + while (gss_ctx_message != 0) { + gss_maj_status = gss_display_status(&gss_min_status, + gss_major_status, + GSS_C_GSS_CODE, + GSS_C_NO_OID, + &gss_ctx_message, + &gss_str_status); + + if (gss_maj_status == GSS_S_COMPLETE) { + str_status += gss_complete_status_str_format(gss_maj_status); + gss_release_buffer(&gss_min_status, &gss_str_status); + } + } + + if (gss_major_status == GSS_S_FAILURE) { + gss_ctx_message = -1; + while (gss_ctx_message != 0) { + gss_maj_status = gss_display_status(&gss_min_status, + gss_minor_status, + GSS_C_MECH_CODE, + const_cast<gss_OID>(&GSS_API_KRB5_OID_PTR), + &gss_ctx_message, + &gss_str_status); + if (gss_maj_status == GSS_S_COMPLETE) { + str_status += gss_complete_status_str_format(gss_maj_status); + gss_release_buffer(&gss_min_status, &gss_str_status); + } + } + } + return str_status; +} + diff --git a/src/auth/krb/KrbProtocol.hpp b/src/auth/krb/KrbProtocol.hpp new file mode 100644 index 00000000..abddb584 --- /dev/null +++ b/src/auth/krb/KrbProtocol.hpp @@ -0,0 +1,160 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (c) 2018 SUSE LLC. + * Author: Daniel Oliveira <doliveira@suse.com> + * + * 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 + * Foundation. See file COPYING. + * + */ + +#ifndef KRB_PROTOCOL_HPP +#define KRB_PROTOCOL_HPP + +#include "auth/Auth.h" + +#include <errno.h> +#include <gssapi.h> +#include <gssapi/gssapi_generic.h> +#include <gssapi/gssapi_krb5.h> +#include <gssapi/gssapi_ext.h> + +#include <map> +#include <sstream> +#include <string> + +/* + Kerberos Version 5 GSS-API Mechanism + OID {1.2.840.113554.1.2.2} + RFC https://tools.ietf.org/html/rfc1964 +*/ +static const gss_OID_desc GSS_API_KRB5_OID_PTR = + { 9, (void *)"\052\206\110\206\367\022\001\002\002" }; + +/* + Kerberos Version 5 GSS-API Mechanism + Simple and Protected GSS-API Negotiation Mechanism + OID {1.3.6.1.5.5.2} + RFC https://tools.ietf.org/html/rfc4178 +*/ +static const gss_OID_desc GSS_API_SPNEGO_OID_PTR = + {6, (void *)"\x2b\x06\x01\x05\x05\x02"}; + +static const std::string KRB_SERVICE_NAME("kerberos/gssapi"); +static const std::string GSS_API_SPNEGO_OID("{1.3.6.1.5.5.2}"); +static const std::string GSS_API_KRB5_OID("{1.2.840.113554.1.2.2}"); + +enum class GSSAuthenticationRequest { + GSS_CRYPTO_ERR = 1, + GSS_MUTUAL = 0x100, + GSS_TOKEN = 0x200, + GSS_REQUEST_MASK = 0x0F00 +}; + +enum class GSSKeyExchange { + USERAUTH_GSSAPI_RESPONSE = 70, + USERAUTH_GSSAPI_TOKEN, + USERAUTH_GSSAPI_EXCHANGE_COMPLETE, + USERAUTH_GSSAPI_ERROR, + USERAUTH_GSSAPI_ERRTOK, + USERAUTH_GSSAPI_MIC, +}; +static constexpr auto CEPH_GSS_OIDTYPE(0x07); + +struct AuthAuthorizer; + + +class KrbAuthorizer : public AuthAuthorizer { + + public: + KrbAuthorizer() : AuthAuthorizer(CEPH_AUTH_GSS) { } + ~KrbAuthorizer() = default; + bool build_authorizer(const EntityName& entity_name, + const uint64_t guid) { + uint8_t value = (1); + + using ceph::encode; + encode(value, bl, 0); + encode(entity_name, bl, 0); + encode(guid, bl, 0); + return false; + } + + bool verify_reply(bufferlist::const_iterator& buff_list, + std::string *connection_secret) override { + return true; + } + bool add_challenge(CephContext* ceph_ctx, + const bufferlist& buff_list) override { + return true; + } +}; + +class KrbRequest { + + public: + void decode(bufferlist::const_iterator& buff_list) { + using ceph::decode; + decode(m_request_type, buff_list); + } + + void encode(bufferlist& buff_list) const { + using ceph::encode; + encode(m_request_type, buff_list); + } + + uint16_t m_request_type; +}; +WRITE_CLASS_ENCODER(KrbRequest); + +class KrbResponse { + + public: + void decode(bufferlist::const_iterator& buff_list) { + using ceph::decode; + decode(m_response_type, buff_list); + } + + void encode(bufferlist& buff_list) const { + using ceph::encode; + encode(m_response_type, buff_list); + } + + uint16_t m_response_type; +}; +WRITE_CLASS_ENCODER(KrbResponse); + +class KrbTokenBlob { + + public: + void decode(bufferlist::const_iterator& buff_list) { + uint8_t value = (0); + + using ceph::decode; + decode(value, buff_list); + decode(m_token_blob, buff_list); + } + + void encode(bufferlist& buff_list) const { + uint8_t value = (1); + + using ceph::encode; + encode(value, buff_list, 0); + encode(m_token_blob, buff_list, 0); + } + + bufferlist m_token_blob; +}; +WRITE_CLASS_ENCODER(KrbTokenBlob); + + +std::string gss_auth_show_status(const OM_uint32 gss_major_status, + const OM_uint32 gss_minor_status); + +#endif //-- KRB_PROTOCOL_HPP + diff --git a/src/auth/krb/KrbServiceHandler.cpp b/src/auth/krb/KrbServiceHandler.cpp new file mode 100644 index 00000000..94858876 --- /dev/null +++ b/src/auth/krb/KrbServiceHandler.cpp @@ -0,0 +1,225 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (c) 2018 SUSE LLC. + * Author: Daniel Oliveira <doliveira@suse.com> + * + * 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 + * Foundation. See file COPYING. + * + */ + +#include "KrbServiceHandler.hpp" +#include "KrbProtocol.hpp" +#include <errno.h> +#include <sstream> + +#include "common/config.h" +#include "common/debug.h" + +#define dout_subsys ceph_subsys_auth +#undef dout_prefix +#define dout_prefix *_dout << "krb5/gssapi service: " << entity_name << " : " + + +int KrbServiceHandler::handle_request( + bufferlist::const_iterator& indata, + size_t connection_secret_required_length, + bufferlist *buff_list, + AuthCapsInfo *caps, + CryptoKey *session_key, + std::string *connection_secret) +{ + auto result(0); + gss_buffer_desc gss_buffer_in = {0, nullptr}; + gss_name_t gss_client_name = GSS_C_NO_NAME; + gss_OID gss_object_id = {0}; + OM_uint32 gss_major_status(0); + OM_uint32 gss_minor_status(0); + OM_uint32 gss_result_flags(0); + std::string status_str(" "); + + ldout(cct, 20) + << "KrbServiceHandler::handle_request() " << dendl; + + KrbRequest krb_request; + KrbTokenBlob krb_token; + + using ceph::decode; + decode(krb_request, indata); + decode(krb_token, indata); + + gss_buffer_in.length = krb_token.m_token_blob.length(); + gss_buffer_in.value = krb_token.m_token_blob.c_str(); + + ldout(cct, 20) + << "KrbClientHandler::handle_request() : Token Blob: " + << "\n"; + krb_token.m_token_blob.hexdump(*_dout); + *_dout << dendl; + + if (m_gss_buffer_out.length != 0) { + gss_release_buffer(&gss_minor_status, + static_cast<gss_buffer_t>(&m_gss_buffer_out)); + } + + gss_major_status = gss_accept_sec_context(&gss_minor_status, + &m_gss_sec_ctx, + m_gss_credentials, + &gss_buffer_in, + GSS_C_NO_CHANNEL_BINDINGS, + &gss_client_name, + &gss_object_id, + &m_gss_buffer_out, + &gss_result_flags, + nullptr, + nullptr); + switch (gss_major_status) { + case GSS_S_CONTINUE_NEEDED: + { + ldout(cct, 20) + << "KrbServiceHandler::handle_response() : " + "[KrbServiceHandler(GSS_S_CONTINUE_NEEDED)] " << dendl; + result = 0; + break; + } + + case GSS_S_COMPLETE: + { + result = 0; + ldout(cct, 20) + << "KrbServiceHandler::handle_response() : " + "[KrbServiceHandler(GSS_S_COMPLETE)] " << dendl; + if (!m_key_server->get_service_caps(entity_name, + CEPH_ENTITY_TYPE_MON, + *caps)) { + result = (-EACCES); + ldout(cct, 0) + << "KrbServiceHandler::handle_response() : " + "ERROR: Could not get MONITOR CAPS : " << entity_name << dendl; + } else { + if (!caps->caps.c_str()) { + result = (-EACCES); + ldout(cct, 0) + << "KrbServiceHandler::handle_response() : " + "ERROR: MONITOR CAPS invalid : " << entity_name << dendl; + } + } + break; + } + + default: + { + status_str = gss_auth_show_status(gss_major_status, + gss_minor_status); + ldout(cct, 0) + << "ERROR: KrbServiceHandler::handle_response() " + "[gss_accept_sec_context()] failed! " + << gss_major_status << " " + << gss_minor_status << " " + << status_str + << dendl; + result = (-EPERM); + break; + } + } + + if (m_gss_buffer_out.length != 0) { + KrbResponse krb_response; + KrbTokenBlob krb_token; + krb_response.m_response_type = + static_cast<int>(GSSAuthenticationRequest::GSS_TOKEN); + + using ceph::encode; + encode(krb_response, *buff_list); + + krb_token.m_token_blob.append(buffer::create_static( + m_gss_buffer_out.length, + reinterpret_cast<char*> + (m_gss_buffer_out.value))); + encode(krb_token, *buff_list); + ldout(cct, 20) + << "KrbServiceHandler::handle_request() : Token Blob: " << "\n"; + krb_token.m_token_blob.hexdump(*_dout); + *_dout << dendl; + } + gss_release_name(&gss_minor_status, &gss_client_name); + return result; +} + +int KrbServiceHandler::do_start_session( + bool is_new_global_id, + bufferlist *buff_list, + AuthCapsInfo *caps) +{ + gss_buffer_desc gss_buffer_in = {0, nullptr}; + gss_OID gss_object_id = GSS_C_NT_HOSTBASED_SERVICE; + gss_OID_set gss_mechs_wanted = GSS_C_NO_OID_SET; + OM_uint32 gss_major_status(0); + OM_uint32 gss_minor_status(0); + std::string gss_service_name(cct->_conf.get_val<std::string> + ("gss_target_name")); + + gss_buffer_in.length = gss_service_name.length(); + gss_buffer_in.value = (const_cast<char*>(gss_service_name.c_str())); + + gss_major_status = gss_import_name(&gss_minor_status, + &gss_buffer_in, + gss_object_id, + &m_gss_service_name); + if (gss_major_status != GSS_S_COMPLETE) { + auto status_str(gss_auth_show_status(gss_major_status, + gss_minor_status)); + ldout(cct, 0) + << "ERROR: KrbServiceHandler::start_session() " + "[gss_import_name(gss_client_name)] failed! " + << gss_major_status << " " + << gss_minor_status << " " + << status_str + << dendl; + } + + gss_major_status = gss_acquire_cred(&gss_minor_status, + m_gss_service_name, + 0, + gss_mechs_wanted, + GSS_C_ACCEPT, + &m_gss_credentials, + nullptr, + nullptr); + if (gss_major_status != GSS_S_COMPLETE) { + auto status_str(gss_auth_show_status(gss_major_status, + gss_minor_status)); + ldout(cct, 0) + << "ERROR: KrbServiceHandler::start_session() " + "[gss_acquire_cred()] failed! " + << gss_major_status << " " + << gss_minor_status << " " + << status_str + << dendl; + return (-EPERM); + } else { + KrbResponse krb_response; + krb_response.m_response_type = + static_cast<int>(GSSAuthenticationRequest::GSS_MUTUAL); + + using ceph::encode; + encode(krb_response, *buff_list); + return (CEPH_AUTH_GSS); + } +} + +KrbServiceHandler::~KrbServiceHandler() +{ + OM_uint32 gss_minor_status(0); + + gss_release_name(&gss_minor_status, &m_gss_service_name); + gss_release_cred(&gss_minor_status, &m_gss_credentials); + gss_delete_sec_context(&gss_minor_status, &m_gss_sec_ctx, GSS_C_NO_BUFFER); + gss_release_buffer(&gss_minor_status, static_cast<gss_buffer_t>(&m_gss_buffer_out)); +} + diff --git a/src/auth/krb/KrbServiceHandler.hpp b/src/auth/krb/KrbServiceHandler.hpp new file mode 100644 index 00000000..ee91baa5 --- /dev/null +++ b/src/auth/krb/KrbServiceHandler.hpp @@ -0,0 +1,61 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (c) 2018 SUSE LLC. + * Author: Daniel Oliveira <doliveira@suse.com> + * + * 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 + * Foundation. See file COPYING. + * + */ + +#ifndef KRB_SERVICE_HANDLER_HPP +#define KRB_SERVICE_HANDLER_HPP + +#include "auth/AuthServiceHandler.h" +#include "auth/Auth.h" +#include "auth/cephx/CephxKeyServer.h" + +#include <gssapi.h> +#include <gssapi/gssapi_generic.h> +#include <gssapi/gssapi_krb5.h> +#include <gssapi/gssapi_ext.h> + + +class KrbServiceHandler : public AuthServiceHandler { + + public: + explicit KrbServiceHandler(CephContext* ceph_ctx, KeyServer* kserver) : + AuthServiceHandler(ceph_ctx), + m_gss_buffer_out({0, nullptr}), + m_gss_credentials(GSS_C_NO_CREDENTIAL), + m_gss_sec_ctx(GSS_C_NO_CONTEXT), + m_gss_service_name(GSS_C_NO_NAME), + m_key_server(kserver) { } + ~KrbServiceHandler(); + int handle_request(bufferlist::const_iterator& indata, + size_t connection_secret_required_length, + bufferlist *buff_list, + AuthCapsInfo *caps, + CryptoKey *session_key, + std::string *connection_secret) override; + + private: + int do_start_session(bool is_new_global_id, + bufferlist *buff_list, + AuthCapsInfo *caps) override; + + gss_buffer_desc m_gss_buffer_out; + gss_cred_id_t m_gss_credentials; + gss_ctx_id_t m_gss_sec_ctx; + gss_name_t m_gss_service_name; + KeyServer* m_key_server; + +}; + +#endif //-- KRB_SERVICE_HANDLER_HPP + diff --git a/src/auth/krb/KrbSessionHandler.hpp b/src/auth/krb/KrbSessionHandler.hpp new file mode 100644 index 00000000..ee80d790 --- /dev/null +++ b/src/auth/krb/KrbSessionHandler.hpp @@ -0,0 +1,37 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (c) 2018 SUSE LLC. + * Author: Daniel Oliveira <doliveira@suse.com> + * + * 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 + * Foundation. See file COPYING. + * + */ + +#ifndef KRB_SESSION_HANDLER_HPP +#define KRB_SESSION_HANDLER_HPP + +#include "auth/AuthSessionHandler.h" +#include "auth/Auth.h" + +#include "KrbProtocol.hpp" +#include <errno.h> +#include <sstream> + +#include "common/config.h" +#include "include/ceph_features.h" +#include "msg/Message.h" + +#define dout_subsys ceph_subsys_auth + +struct KrbSessionHandler : DummyAuthSessionHandler { +}; + +#endif //-- KRB_SESSION_HANDLER_HPP + + |