diff --git a/include/wsrep/allowlist_service.hpp b/include/wsrep/allowlist_service.hpp new file mode 100644 index 0000000..1e619ce --- /dev/null +++ b/include/wsrep/allowlist_service.hpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2021 Codership Oy + * + * This file is part of wsrep-lib. + * + * Wsrep-lib is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Wsrep-lib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wsrep-lib. If not, see . + */ + + +/** @file allowlist_service.hpp + * + * Service interface for interacting with DBMS provided + * allowlist callback. + */ + +#ifndef WSREP_ALLOWLIST_SERVICE_HPP +#define WSREP_ALLOWLIST_SERVICE_HPP + +#include "compiler.hpp" +#include "wsrep/buffer.hpp" + +#include // ssize_t + +namespace wsrep +{ + class allowlist_service + { + public: + enum allowlist_key + { + /** IP allowlist check */ + allowlist_ip, + /** SSL allowlist check */ + allowlist_ssl + }; + + virtual ~allowlist_service() { } + + /** + * Allowlist callback. + */ + virtual bool allowlist_cb(allowlist_key key, + const wsrep::const_buffer& value) WSREP_NOEXCEPT = 0; + }; +} + +#endif // WSREP_ALLOWLIST_SERVICE_HPP diff --git a/include/wsrep/provider.hpp b/include/wsrep/provider.hpp index 4c85880..d17f595 100644 --- a/include/wsrep/provider.hpp +++ b/include/wsrep/provider.hpp @@ -46,6 +46,7 @@ namespace wsrep class high_priority_service; class thread_service; class tls_service; + class allowlist_service; class stid { @@ -422,9 +423,11 @@ namespace wsrep { wsrep::thread_service* thread_service; wsrep::tls_service* tls_service; + wsrep::allowlist_service* allowlist_service; services() : thread_service() , tls_service() + , allowlist_service() { } }; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3a5d287..2e771b3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -20,5 +20,6 @@ add_library(wsrep-lib transaction.cpp uuid.cpp reporter.cpp + allowlist_service_v1.cpp wsrep_provider_v26.cpp) target_link_libraries(wsrep-lib wsrep_api_v26 pthread ${WSREP_LIB_LIBDL}) diff --git a/src/allowlist_service_v1.cpp b/src/allowlist_service_v1.cpp new file mode 100644 index 0000000..9e7bf2a --- /dev/null +++ b/src/allowlist_service_v1.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2021 Codership Oy + * + * This file is part of wsrep-lib. + * + * Wsrep-lib is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Wsrep-lib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wsrep-lib. If not, see . + */ + +#include "allowlist_service_v1.hpp" +#include "service_helpers.hpp" + +#include "wsrep/allowlist_service.hpp" +#include "wsrep/buffer.hpp" +#include "v26/wsrep_allowlist_service.h" + +#include +#include +#include + +namespace wsrep_allowlist_service_v1 +{ + // Pointer to allowlist service implementation provided by + // the application. + static wsrep::allowlist_service* allowlist_service_impl{ 0 }; + static std::atomic use_count; + + enum wsrep::allowlist_service::allowlist_key allowlist_key_from_native(wsrep_allowlist_key_t key) + { + switch (key) + { + case WSREP_ALLOWLIST_KEY_IP: return wsrep::allowlist_service::allowlist_key::allowlist_ip; + case WSREP_ALLOWLIST_KEY_SSL: return wsrep::allowlist_service::allowlist_key::allowlist_ssl; + default: throw wsrep::runtime_error("Unknown allowlist key"); + } + } + + // + // allowlist service callbacks + // + + wsrep_status_t allowlist_cb( + wsrep_allowlist_context_t*, + wsrep_allowlist_key_t key, + const wsrep_buf_t* value + ) + { + assert(allowlist_service_impl); + wsrep::const_buffer allowlist_value(value->ptr, value->len); + if (allowlist_service_impl->allowlist_cb(allowlist_key_from_native(key), + allowlist_value)) + { + return WSREP_OK; + } + return WSREP_NOT_ALLOWED; + } + + static wsrep_allowlist_service_v1_t allowlist_service_callbacks + = { allowlist_cb, + 0 }; +} + +int wsrep::allowlist_service_v1_probe(void* dlh) +{ + typedef int (*init_fn)(wsrep_allowlist_service_v1_t*); + typedef void (*deinit_fn)(); + if (wsrep_impl::service_probe( + dlh, WSREP_ALLOWLIST_SERVICE_INIT_FUNC_V1, "allowlist service v1") || + wsrep_impl::service_probe( + dlh, WSREP_ALLOWLIST_SERVICE_DEINIT_FUNC_V1, "allowlist service v1")) + { + wsrep::log_warning() << "Provider does not support allowlist service v1"; + return 1; + } + return 0; +} + +int wsrep::allowlist_service_v1_init(void* dlh, + wsrep::allowlist_service* allowlist_service) +{ + if (not (dlh && allowlist_service)) return EINVAL; + typedef int (*init_fn)(wsrep_allowlist_service_v1_t*); + wsrep_allowlist_service_v1::allowlist_service_impl = allowlist_service; + int ret(0); + if ((ret = wsrep_impl::service_init( + dlh, WSREP_ALLOWLIST_SERVICE_INIT_FUNC_V1, + &wsrep_allowlist_service_v1::allowlist_service_callbacks, + "allowlist service v1"))) + { + wsrep_allowlist_service_v1::allowlist_service_impl = 0; + } + else + { + ++wsrep_allowlist_service_v1::use_count; + } + return ret; +} + +void wsrep::allowlist_service_v1_deinit(void* dlh) +{ + typedef int (*deinit_fn)(); + wsrep_impl::service_deinit( + dlh, WSREP_ALLOWLIST_SERVICE_DEINIT_FUNC_V1, "allowlist service v1"); + --wsrep_allowlist_service_v1::use_count; + if (wsrep_allowlist_service_v1::use_count == 0) + { + wsrep_allowlist_service_v1::allowlist_service_impl = 0; + } +} diff --git a/src/allowlist_service_v1.hpp b/src/allowlist_service_v1.hpp new file mode 100644 index 0000000..eb73bd9 --- /dev/null +++ b/src/allowlist_service_v1.hpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2021 Codership Oy + * + * This file is part of wsrep-lib. + * + * Wsrep-lib is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * Wsrep-lib is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wsrep-lib. If not, see . + */ + +#ifndef WSREP_ALLOWLIST_SERVICE_V1_HPP +#define WSREP_ALLOWLIST_SERVICE_V1_HPP + +namespace wsrep +{ + class allowlist_service; + /** + * Probe allowlist_service_v1 support in loaded library. + * + * @param dlh Handle returned by dlopen(). + * + * @return Zero on success, non-zero system error code on failure. + */ + int allowlist_service_v1_probe(void *dlh); + + /** + * Initialize the allowlist service. + * + * @param dlh Handle returned by dlopen(). + * @param allowlist_service Pointer to wsrep::allowlist_service implementation. + * + * @return Zero on success, non-zero system error code on failure. + */ + int allowlist_service_v1_init(void* dlh, + wsrep::allowlist_service* allowlist_service); + + /** + * Deinitialize the allowlist service. + * + * @params dlh Handler returned by dlopen(). + */ + void allowlist_service_v1_deinit(void* dlh); + +} + +#endif // WSREP_allowlist_SERVICE_V1_HPP diff --git a/src/wsrep_provider_v26.cpp b/src/wsrep_provider_v26.cpp index a579dff..d9bc835 100644 --- a/src/wsrep_provider_v26.cpp +++ b/src/wsrep_provider_v26.cpp @@ -27,9 +27,11 @@ #include "wsrep/logger.hpp" #include "wsrep/thread_service.hpp" #include "wsrep/tls_service.hpp" +#include "wsrep/allowlist_service.hpp" #include "thread_service_v1.hpp" #include "tls_service_v1.hpp" +#include "allowlist_service_v1.hpp" #include "v26/wsrep_api.h" @@ -635,6 +637,23 @@ namespace // assert(not wsrep::tls_service_v1_probe(dlh)); wsrep::tls_service_v1_deinit(dlh); } + + static int init_allowlist_service(void* dlh, + wsrep::allowlist_service* allowlist_service) + { + assert(allowlist_service); + if (not wsrep::allowlist_service_v1_probe(dlh)) + { + return wsrep::allowlist_service_v1_init(dlh, allowlist_service); + } + return 1; + } + + static void deinit_allowlist_service(void* dlh) + { + // assert(not wsrep::allowlist_service_v1_probe(dlh)); + wsrep::allowlist_service_v1_deinit(dlh); + } } void wsrep::wsrep_provider_v26::init_services( @@ -656,6 +675,14 @@ void wsrep::wsrep_provider_v26::init_services( } services_enabled_.tls_service = services.tls_service; } + if (services.allowlist_service) + { + if (init_allowlist_service(wsrep_->dlh, services.allowlist_service)) + { + throw wsrep::runtime_error("Failed to initialze allowlist service"); + } + services_enabled_.allowlist_service = services.allowlist_service; + } } void wsrep::wsrep_provider_v26::deinit_services() @@ -664,6 +691,8 @@ void wsrep::wsrep_provider_v26::deinit_services() deinit_tls_service(wsrep_->dlh); if (services_enabled_.thread_service) deinit_thread_service(wsrep_->dlh); + if (services_enabled_.allowlist_service) + deinit_allowlist_service(wsrep_->dlh); } wsrep::wsrep_provider_v26::wsrep_provider_v26( diff --git a/wsrep-API/v26 b/wsrep-API/v26 index 4e50c45..02ed172 160000 --- a/wsrep-API/v26 +++ b/wsrep-API/v26 @@ -1 +1 @@ -Subproject commit 4e50c45cdb976f829e00ab71e6a6bc2dfe8f3afa +Subproject commit 02ed17238cee97b5a3ea2495ca87b63570403f01