/* Copyright (c) 2021, 2024, Oracle and/or its affiliates. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2.0, as published by the Free Software Foundation. This program is designed to work with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in included license documentation. The authors of MySQL hereby grant you an additional permission to link the program and your derivative works with the separately licensed software that they have either included with the program or referenced in the documentation. This program 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, version 2.0, for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "my_dbug.h" #include "mysql_server_keyring_lockable_imp.h" #include #include #include #include #include #include #include "sql/mysqld.h" /* srv_registry */ #include "sql/set_var.h" /* keyring_access_test */ #include "sql/sql_component.h" /* init and deinit function for RWLock */ #include "sql/sql_plugin.h" /* opt_plugin_dir */ /* clang-format off */ /** @page PAGE_COMPONENT_KEYRING_MYSQL_SERVER component_keyring_mysql_server MySQL server component provides a wrapper implementation of all component services related to keyring. Following is the list of services: - keyring_aes - keyring_generate - keyring_keys_metadata_iterator - keyring_component_status - keyring_metadata_query - keyring_reader - keyring_load - keyring_writer The implementation of above services in turn calls actual keyring component implementation (such as component_keyring_file). However, this component provides concurrency control for read/write operations affecting keyring. In addition, this implementation also checks if KEYRING_OPERATIONS system variable permits given operation or not. This implementation is set as default implementation for MySQL server. Handles for underlying keyring component service implementations are obtained at two locations: 1. After processing server's manifest file 2. After installing proxy keyring component for keyring plugin Once handles are set, they are not set again. Thus, if a keyring component is installed through manifest file, keyring plugin will not considered even if it is installed through --early-plugin-load. These handles ares freed at the time of server shutdown. */ /* clang-format on */ /** Server handle for keyring AES encryption service */ SERVICE_TYPE(keyring_aes) *srv_keyring_aes = nullptr; /** Server handle for keyring generator service */ SERVICE_TYPE(keyring_generator) *srv_keyring_generator = nullptr; /** Server handle for keyring keys metadata service */ SERVICE_TYPE(keyring_keys_metadata_iterator) *srv_keyring_keys_metadata_iterator = nullptr; /** Server handle for keyring status service */ SERVICE_TYPE(keyring_component_status) *srv_keyring_component_status = nullptr; /** Server handle for keyring component metadata service */ SERVICE_TYPE(keyring_component_metadata_query) *srv_keyring_component_metadata_query = nullptr; /** Server handle for keyring reader service */ SERVICE_TYPE(keyring_reader_with_status) *srv_keyring_reader = nullptr; /** Server handle for keyring load service */ SERVICE_TYPE(keyring_load) *srv_keyring_load = nullptr; /** Server handle for keyring writer service */ SERVICE_TYPE(keyring_writer) *srv_keyring_writer = nullptr; enum lockable_service_enum { AES_ENCRYPTION = 0, GENERATOR, KEYS_METADATA_ITERATOR, COMPONENT_STATUS, COMPONENT_METADATA_QUERY, READER_WITH_STATUS, LOAD, WRITER }; static const char *lockable_service_names[] = { "keyring_aes", "keyring_generator", "keyring_keys_metadata_iterator", "keyring_component_status", "keyring_component_metadata_query", "keyring_reader_with_status", "keyring_load", "keyring_writer"}; namespace keyring_lockable { /** Server component internal handle for keyring AES encryption service */ SERVICE_TYPE(keyring_aes) *internal_keyring_aes = nullptr; /** Server component internal handle for keyring generator service */ SERVICE_TYPE(keyring_generator) *internal_keyring_generator = nullptr; /** Server component internal handle for keyring keys metadata service */ SERVICE_TYPE(keyring_keys_metadata_iterator) *internal_keyring_keys_metadata_iterator = nullptr; /** Server component internal handle for keyring component status service */ SERVICE_TYPE(keyring_component_status) *internal_keyring_component_status = nullptr; /** Server component internal handle for keyring component metadata service */ SERVICE_TYPE(keyring_component_metadata_query) *internal_keyring_component_metadata_query = nullptr; /** Server component internal handle for keyring reader service */ SERVICE_TYPE(keyring_reader_with_status) *internal_keyring_reader = nullptr; /** Server component internal handle for keyring load service */ SERVICE_TYPE(keyring_load) *internal_keyring_load = nullptr; /** Server component internal handle for keyring writer service */ SERVICE_TYPE(keyring_writer) *internal_keyring_writer = nullptr; /** Access control for keyring */ mysql_rwlock_t LOCK_keyring_component; /** PSI key for @sa LOCK_keyring_component */ static PSI_rwlock_key key_LOCK_keyring_component; /** Error messages */ /** Wrapper over my_h_keyring_reader_object to associate RWlock. Read lock is taken when reader is initialized and freed when reader is deinitialized. This makes sure that fetch_length() and fetch() APIs are protected by the read lock. */ struct my_h_keyring_reader_object_server { my_h_keyring_reader_object object_; rwlock_scoped_lock lock_; }; /** Wrapper over my_h_keyring_keys_metadata_iterator to associate RWlock. Read lock is taken when iterator is initialized and freed when iterator is deinitialized. This makes sure that get_length(), get(), next() and is_valid() APIs are protected by the read lock. */ struct my_h_keyring_keys_metadata_iterator_server { my_h_keyring_keys_metadata_iterator iterator_; rwlock_scoped_lock lock_; }; namespace keyring_common { namespace service_definition { /** Helper to check service validity @param [in] service Service handle @param [in] name Service name enum @returns validity state of esrvice @retval false Valid service handle @retval true Invalid service handle. Error raised. */ static bool check_service(const void *service, enum lockable_service_enum name) { if (service == nullptr) { LogErr(WARNING_LEVEL, ER_WARN_NO_KEYRING_COMPONENT_SERVICE_FOUND, lockable_service_names[name]); return true; } return false; } /* AES Encryption Service */ DEFINE_BOOL_METHOD(Keyring_aes_service_impl::get_size, (size_t input_length, const char *mode, size_t block_size, size_t *out_size)) { if (check_service(internal_keyring_aes, AES_ENCRYPTION)) return true; /* No need to take a lock as this one does not access keyring */ return internal_keyring_aes->get_size(input_length, mode, block_size, out_size); } DEFINE_BOOL_METHOD(Keyring_aes_service_impl::encrypt, (const char *data_id, const char *auth_id, const char *mode, size_t block_size, const unsigned char *iv, int padding, const unsigned char *data_buffer, size_t data_buffer_length, unsigned char *out_buffer, size_t out_buffer_length, size_t *out_length)) { if (check_service(internal_keyring_aes, AES_ENCRYPTION)) return true; const rwlock_scoped_lock lock(&LOCK_keyring_component, false, __FILE__, __LINE__); return internal_keyring_aes->encrypt( data_id, auth_id, mode, block_size, iv, padding, data_buffer, data_buffer_length, out_buffer, out_buffer_length, out_length); } DEFINE_BOOL_METHOD(Keyring_aes_service_impl::decrypt, (const char *data_id, const char *auth_id, const char *mode, size_t block_size, const unsigned char *iv, int padding, const unsigned char *data_buffer, size_t data_buffer_length, unsigned char *out_buffer, size_t out_buffer_length, size_t *out_length)) { if (check_service(internal_keyring_aes, AES_ENCRYPTION)) return true; const rwlock_scoped_lock lock(&LOCK_keyring_component, false, __FILE__, __LINE__); return internal_keyring_aes->decrypt( data_id, auth_id, mode, block_size, iv, padding, data_buffer, data_buffer_length, out_buffer, out_buffer_length, out_length); } /* keyring_generator */ DEFINE_BOOL_METHOD(Keyring_generator_service_impl::generate, (const char *data_id, const char *auth_id, const char *data_type, size_t data_size)) { if (keyring_access_test()) return true; if (check_service(internal_keyring_generator, GENERATOR)) return true; DBUG_EXECUTE_IF("keyring_generate_fail", DBUG_SUICIDE();); const rwlock_scoped_lock lock(&LOCK_keyring_component, true, __FILE__, __LINE__); return internal_keyring_generator->generate(data_id, auth_id, data_type, data_size); } /* keyring_keys_metdata_iterator */ DEFINE_BOOL_METHOD(Keyring_keys_metadata_iterator_service_impl::init, (my_h_keyring_keys_metadata_iterator * forward_iterator)) { if (check_service(internal_keyring_keys_metadata_iterator, KEYS_METADATA_ITERATOR)) return true; rwlock_scoped_lock lock(&LOCK_keyring_component, false, __FILE__, __LINE__); my_h_keyring_keys_metadata_iterator_server *local_object = new my_h_keyring_keys_metadata_iterator_server{nullptr, std::move(lock)}; if (local_object == nullptr) return true; const bool retval = internal_keyring_keys_metadata_iterator->init(&local_object->iterator_); if (retval == true) { delete local_object; return retval; } *forward_iterator = reinterpret_cast(local_object); return retval; } DEFINE_BOOL_METHOD(Keyring_keys_metadata_iterator_service_impl::deinit, (my_h_keyring_keys_metadata_iterator forward_iterator)) { if (check_service(internal_keyring_keys_metadata_iterator, KEYS_METADATA_ITERATOR)) return true; my_h_keyring_keys_metadata_iterator_server *local_object = reinterpret_cast( forward_iterator); if (!local_object) return true; /* Even if underlying keyring fails to deinitialize actual iterator, we will release the lock. Otherwise, keyring will remain in locked state */ const bool retval = internal_keyring_keys_metadata_iterator->deinit(local_object->iterator_); local_object->iterator_ = nullptr; /* This shall release the lock too */ delete local_object; return retval; } DEFINE_BOOL_METHOD(Keyring_keys_metadata_iterator_service_impl::is_valid, (my_h_keyring_keys_metadata_iterator forward_iterator)) { if (check_service(internal_keyring_keys_metadata_iterator, KEYS_METADATA_ITERATOR)) return false; my_h_keyring_keys_metadata_iterator_server *local_object = reinterpret_cast( forward_iterator); if (!local_object) return false; return internal_keyring_keys_metadata_iterator->is_valid( local_object->iterator_); } DEFINE_BOOL_METHOD(Keyring_keys_metadata_iterator_service_impl::get_length, (my_h_keyring_keys_metadata_iterator forward_iterator, size_t *data_id_length, size_t *auth_id_length)) { if (check_service(internal_keyring_keys_metadata_iterator, KEYS_METADATA_ITERATOR)) return true; my_h_keyring_keys_metadata_iterator_server *local_object = reinterpret_cast( forward_iterator); if (!local_object) return true; return internal_keyring_keys_metadata_iterator->get_length( local_object->iterator_, data_id_length, auth_id_length); } DEFINE_BOOL_METHOD(Keyring_keys_metadata_iterator_service_impl::next, (my_h_keyring_keys_metadata_iterator forward_iterator)) { if (check_service(internal_keyring_keys_metadata_iterator, KEYS_METADATA_ITERATOR)) return true; my_h_keyring_keys_metadata_iterator_server *local_object = reinterpret_cast( forward_iterator); if (!local_object) return true; return internal_keyring_keys_metadata_iterator->next(local_object->iterator_); } DEFINE_BOOL_METHOD(Keyring_keys_metadata_iterator_service_impl::get, (my_h_keyring_keys_metadata_iterator forward_iterator, char *data_id, size_t data_id_length, char *auth_id, size_t auth_id_length)) { if (check_service(internal_keyring_keys_metadata_iterator, KEYS_METADATA_ITERATOR)) return true; my_h_keyring_keys_metadata_iterator_server *local_object = reinterpret_cast( forward_iterator); if (!local_object) return true; return internal_keyring_keys_metadata_iterator->get(local_object->iterator_, data_id, data_id_length, auth_id, auth_id_length); } /* keyring_component_metadata_query */ DEFINE_BOOL_METHOD(Keyring_metadata_query_service_impl::is_initialized, ()) { if (check_service(internal_keyring_component_status, COMPONENT_STATUS)) return false; return internal_keyring_component_status->is_initialized(); } DEFINE_BOOL_METHOD(Keyring_metadata_query_service_impl::init, (my_h_keyring_component_metadata_iterator * metadata_iterator)) { if (check_service(internal_keyring_component_metadata_query, COMPONENT_METADATA_QUERY)) return true; const rwlock_scoped_lock lock(&LOCK_keyring_component, false, __FILE__, __LINE__); return internal_keyring_component_metadata_query->init(metadata_iterator); } DEFINE_BOOL_METHOD( Keyring_metadata_query_service_impl::deinit, (my_h_keyring_component_metadata_iterator metadata_iterator)) { if (check_service(internal_keyring_component_metadata_query, COMPONENT_METADATA_QUERY)) return true; const rwlock_scoped_lock lock(&LOCK_keyring_component, false, __FILE__, __LINE__); return internal_keyring_component_metadata_query->deinit(metadata_iterator); } DEFINE_BOOL_METHOD( Keyring_metadata_query_service_impl::is_valid, (my_h_keyring_component_metadata_iterator metadata_iterator)) { if (check_service(internal_keyring_component_metadata_query, COMPONENT_METADATA_QUERY)) return false; const rwlock_scoped_lock lock(&LOCK_keyring_component, false, __FILE__, __LINE__); return internal_keyring_component_metadata_query->is_valid(metadata_iterator); } DEFINE_BOOL_METHOD( Keyring_metadata_query_service_impl::next, (my_h_keyring_component_metadata_iterator metadata_iterator)) { if (check_service(internal_keyring_component_metadata_query, COMPONENT_METADATA_QUERY)) return true; const rwlock_scoped_lock lock(&LOCK_keyring_component, false, __FILE__, __LINE__); return internal_keyring_component_metadata_query->next(metadata_iterator); } DEFINE_BOOL_METHOD(Keyring_metadata_query_service_impl::get_length, (my_h_keyring_component_metadata_iterator metadata_iterator, size_t *key_buffer_length, size_t *value_buffer_length)) { if (check_service(internal_keyring_component_metadata_query, COMPONENT_METADATA_QUERY)) return true; const rwlock_scoped_lock lock(&LOCK_keyring_component, false, __FILE__, __LINE__); return internal_keyring_component_metadata_query->get_length( metadata_iterator, key_buffer_length, value_buffer_length); } DEFINE_BOOL_METHOD(Keyring_metadata_query_service_impl::get, (my_h_keyring_component_metadata_iterator metadata_iterator, char *key_buffer, size_t key_buffer_length, char *value_buffer, size_t value_buffer_length)) { if (check_service(internal_keyring_component_metadata_query, COMPONENT_METADATA_QUERY)) return true; const rwlock_scoped_lock lock(&LOCK_keyring_component, false, __FILE__, __LINE__); return internal_keyring_component_metadata_query->get( metadata_iterator, key_buffer, key_buffer_length, value_buffer, value_buffer_length); } /* keyring_reader_with_status */ DEFINE_BOOL_METHOD(Keyring_reader_service_impl::init, (const char *data_id, const char *auth_id, my_h_keyring_reader_object *reader_object)) { if (check_service(internal_keyring_reader, READER_WITH_STATUS)) return true; rwlock_scoped_lock lock(&LOCK_keyring_component, false, __FILE__, __LINE__); my_h_keyring_reader_object_server *local_object = new my_h_keyring_reader_object_server{nullptr, std::move(lock)}; if (local_object == nullptr) return true; const bool retval = internal_keyring_reader->init(data_id, auth_id, &(local_object->object_)); if (retval == true || local_object->object_ == nullptr) { delete local_object; *reader_object = nullptr; return retval; } *reader_object = reinterpret_cast(local_object); return retval; } DEFINE_BOOL_METHOD(Keyring_reader_service_impl::deinit, (my_h_keyring_reader_object reader_object)) { if (check_service(internal_keyring_reader, READER_WITH_STATUS)) return true; my_h_keyring_reader_object_server *local_object = reinterpret_cast(reader_object); if (!local_object) return true; /* Even if underlying keyring fails to deinitialize actual iterator, we will release the lock. Otherwise, keyring will remain in locked state */ const bool retval = internal_keyring_reader->deinit(local_object->object_); local_object->object_ = nullptr; /* This shall release the lock too */ delete local_object; return retval; } DEFINE_BOOL_METHOD(Keyring_reader_service_impl::fetch_length, (my_h_keyring_reader_object reader_object, size_t *data_size, size_t *data_type_size)) { if (check_service(internal_keyring_reader, READER_WITH_STATUS)) return true; my_h_keyring_reader_object_server *local_object = reinterpret_cast(reader_object); if (!local_object) return true; return internal_keyring_reader->fetch_length(local_object->object_, data_size, data_type_size); } DEFINE_BOOL_METHOD(Keyring_reader_service_impl::fetch, (my_h_keyring_reader_object reader_object, unsigned char *data_buffer, size_t data_buffer_length, size_t *data_size, char *data_type, size_t data_type_buffer_length, size_t *data_type_size)) { if (check_service(internal_keyring_reader, READER_WITH_STATUS)) return true; my_h_keyring_reader_object_server *local_object = reinterpret_cast(reader_object); if (!local_object) return true; return internal_keyring_reader->fetch( local_object->object_, data_buffer, data_buffer_length, data_size, data_type, data_type_buffer_length, data_type_size); } /* keyring_load */ DEFINE_BOOL_METHOD(Keyring_load_service_impl::load, (const char *component_path, const char *instance_path)) { if (keyring_access_test()) return true; if (check_service(internal_keyring_load, LOAD)) return true; const rwlock_scoped_lock lock(&LOCK_keyring_component, true, __FILE__, __LINE__); return internal_keyring_load->load(component_path, instance_path); } /* keyring_writer */ DEFINE_BOOL_METHOD(Keyring_writer_service_impl::store, (const char *data_id, const char *auth_id, const unsigned char *data, size_t data_size, const char *data_type)) { if (keyring_access_test()) return true; if (check_service(internal_keyring_writer, WRITER)) return true; const rwlock_scoped_lock lock(&LOCK_keyring_component, true, __FILE__, __LINE__); return internal_keyring_writer->store(data_id, auth_id, data, data_size, data_type); } DEFINE_BOOL_METHOD(Keyring_writer_service_impl::remove, (const char *data_id, const char *auth_id)) { if (keyring_access_test()) return true; if (check_service(internal_keyring_writer, WRITER)) return true; const rwlock_scoped_lock lock(&LOCK_keyring_component, true, __FILE__, __LINE__); return internal_keyring_writer->remove(data_id, auth_id); } } // namespace service_definition } // namespace keyring_common } // namespace keyring_lockable using keyring_aes_t = SERVICE_TYPE_NO_CONST(keyring_aes); using keyring_generator_t = SERVICE_TYPE_NO_CONST(keyring_generator); using keyring_keys_metadata_iterator_t = SERVICE_TYPE_NO_CONST(keyring_keys_metadata_iterator); using keyring_component_status_t = SERVICE_TYPE_NO_CONST(keyring_component_status); using keyring_component_metadata_query_t = SERVICE_TYPE_NO_CONST(keyring_component_metadata_query); using keyring_reader_with_status_t = SERVICE_TYPE_NO_CONST(keyring_reader_with_status); using keyring_load_t = SERVICE_TYPE_NO_CONST(keyring_load); using keyring_writer_t = SERVICE_TYPE_NO_CONST(keyring_writer); /** Initialize lockable keyring component */ void keyring_lockable_init() { mysql_rwlock_init(keyring_lockable::key_LOCK_keyring_component, &keyring_lockable::LOCK_keyring_component); } /** Deinitialize lockable keyring component */ void keyring_lockable_deinit() { mysql_rwlock_destroy(&keyring_lockable::LOCK_keyring_component); } /** Set server's implementation of keyring as default server component provides implementation of all keyring related services to provide concurrency control. In turn it uses either one of the following as actual implementation(in order of priority): A> A keyring component loaded through manifest file B> Proxy keyring component over keyring plugin There are two places where this function is called. Path 1 ====== At the time of server startup, server_component's services are registered when minimal chassis is initialized. However, without actual keyring implementation, they are not really of any use. After minimal chassis initialization, server read manifest file. If file is present and contains keyring component details, the component is loaded and services are registered. At this point we have 2 implementations of each keyring services: One provided by server and another provided by keyring component. One component is loaded set_srv_keyring_implementation_as_default() is called. At this stage function will: 1. Set server's implementation of lockable keyring as default 2. Acquire handles to all services provided by keyring component After this point, keyring functionality can be used. Path 2 ====== If manifest file is not provided or does not contain details of keyring plugin, call to set_srv_keyring_implementation_as_default() will still be made and set server's implementation as default. However, no internal handles are set. Thus, keyring functionality can not be used still. Startup sequence will then process --early-plugin-load if provided. Afterwards, daemon_proxy_keyring_implementation plugin is loaded which registers a subset of keyring component services. These services will use keyring plugin if installed. At this point set_srv_keyring_implementation_as_default() is called once again. If internal handles were not set with the first call, they are set now and will use daemon_proxy_keyring_implementation. This means, if keyring plugin is available (either through --early-plugin-load OR loaded later through INSTALL PLUGIN), it will be used. */ void set_srv_keyring_implementation_as_default() { my_service registrator( "registry_registration", srv_registry); auto obtain_service_handles = [](const char *component_part, SERVICE_TYPE(keyring_aes) * *aes_encryption, SERVICE_TYPE(keyring_generator) * *generator, SERVICE_TYPE(keyring_keys_metadata_iterator) * *keys_metadata_iterator, SERVICE_TYPE(keyring_component_status) * *component_status, SERVICE_TYPE(keyring_component_metadata_query) * *component_metadata_query, SERVICE_TYPE(keyring_reader_with_status) * *reader, SERVICE_TYPE(keyring_load) * *load, SERVICE_TYPE(keyring_writer) * *writer) { my_service lamda_registrator( "registry_registration", srv_registry); std::string service_name; /* Reader service */ service_name.assign(lockable_service_names[READER_WITH_STATUS]); service_name.append(component_part); srv_registry->acquire( service_name.c_str(), reinterpret_cast( const_cast(reader))); /* AES encryption service */ service_name.assign(lockable_service_names[AES_ENCRYPTION]); srv_registry->acquire_related( service_name.c_str(), reinterpret_cast( const_cast(*reader)), reinterpret_cast( const_cast(aes_encryption))); /* Generator service */ service_name.assign(lockable_service_names[GENERATOR]); srv_registry->acquire_related( service_name.c_str(), reinterpret_cast( const_cast(*reader)), reinterpret_cast( const_cast(generator))); /* Keys metadata iterator service */ service_name.assign(lockable_service_names[KEYS_METADATA_ITERATOR]); srv_registry->acquire_related( service_name.c_str(), reinterpret_cast( const_cast(*reader)), reinterpret_cast( const_cast( keys_metadata_iterator))); /* Component status service */ service_name.assign(lockable_service_names[COMPONENT_STATUS]); srv_registry->acquire_related( service_name.c_str(), reinterpret_cast( const_cast(*reader)), reinterpret_cast( const_cast(component_status))); /* Component metadata query service */ service_name.assign(lockable_service_names[COMPONENT_METADATA_QUERY]); srv_registry->acquire_related( service_name.c_str(), reinterpret_cast( const_cast(*reader)), reinterpret_cast( const_cast( component_metadata_query))); /* Reload service */ service_name.assign(lockable_service_names[LOAD]); srv_registry->acquire_related( service_name.c_str(), reinterpret_cast( const_cast(*reader)), reinterpret_cast( const_cast(load))); /* Writer service */ service_name.assign(lockable_service_names[WRITER]); srv_registry->acquire_related( service_name.c_str(), reinterpret_cast( const_cast(*reader)), reinterpret_cast( const_cast(writer))); }; /* Part 1: Set lockable keyring as default */ /* The service infrastructure's current behavior is that for any given service, the very first implementation that's registered with service registry becomes the default implementation for that service. Since server component's services are registered right after initializing minimal chassis, we don't have to set server component's implementation for keyring services as default explicitly. If this changes in future, something similar to following will be needed. for (auto service : lockable_service_names) { std::string name(service); name.append(".mysql_server"); registrator->set_default(name.c_str()); } */ /* Part 2: Set internal handles that point to actual implementation */ if (keyring_lockable::internal_keyring_aes == nullptr && keyring_lockable::internal_keyring_generator == nullptr && keyring_lockable::internal_keyring_component_status == nullptr && keyring_lockable::internal_keyring_keys_metadata_iterator == nullptr && keyring_lockable::internal_keyring_component_metadata_query == nullptr && keyring_lockable::internal_keyring_reader == nullptr && keyring_lockable::internal_keyring_load == nullptr && keyring_lockable::internal_keyring_writer == nullptr) { /* 1. Acquire iterator for keyring_reader 2. Move forward if current handle is pointing to keyring_reader.mysql_server 3. If found, acquire all related services (writer, generator, forward iterator, status) 4. Set global handles to point to them */ my_h_service_iterator iterator; my_service reg_query("registry_query", srv_registry); if (reg_query->create(lockable_service_names[READER_WITH_STATUS], &iterator)) return; std::string service_name; { auto guard = create_scope_guard( [®_query, &iterator] { reg_query->release(iterator); }); for (; !reg_query->is_valid(iterator); reg_query->next(iterator)) { const char *name = nullptr; if (reg_query->get(iterator, &name)) return; service_name.assign(name); /* Registry implementation does not necessarily return services with name "keyring_error_state". Current implementation returns an iterator over std::map. Hence, if following entries are present in the service registry: "keyring_reader.mysql_server" "keyring_writer.mysql_server" "keyring_generator.mysql_server" iterator will not only return "keyring_error_state.mysql_server", but also "keyring_reader.mysql_server" and "keyring_writer.mysql_server". Thus, we can not assume that only services matching with "keyring_error_state" will be returned through iterator. Hence, we need to match service name and component name part. This will fall apart if a clever implementation decides to register keyring_error_state service with name other than "keyring_error_state". To resolve that, we need iterator based on service type and not service name. */ if (service_name.find(lockable_service_names[READER_WITH_STATUS]) != std::string::npos) { if (service_name.find("mysql_server") == std::string::npos) break; } service_name.clear(); } } if (service_name.length()) { obtain_service_handles( /* Find dot, the component name is right after the dot. */ strchr(service_name.c_str(), '.'), &keyring_lockable::internal_keyring_aes, &keyring_lockable::internal_keyring_generator, &keyring_lockable::internal_keyring_keys_metadata_iterator, &keyring_lockable::internal_keyring_component_status, &keyring_lockable::internal_keyring_component_metadata_query, &keyring_lockable::internal_keyring_reader, &keyring_lockable::internal_keyring_load, &keyring_lockable::internal_keyring_writer); } /* Initialize keyring */ if (keyring_lockable::internal_keyring_load != nullptr) { (void)keyring_lockable::internal_keyring_load->load(opt_plugin_dir, mysql_real_data_home); } } /* Part 3: Set server wide handles */ if (srv_keyring_aes == nullptr && srv_keyring_component_metadata_query == nullptr && srv_keyring_generator == nullptr && srv_keyring_keys_metadata_iterator == nullptr && srv_keyring_reader == nullptr && srv_keyring_load == nullptr && srv_keyring_writer == nullptr) { obtain_service_handles( ".mysql_server", &srv_keyring_aes, &srv_keyring_generator, &srv_keyring_keys_metadata_iterator, &srv_keyring_component_status, &srv_keyring_component_metadata_query, &srv_keyring_reader, &srv_keyring_load, &srv_keyring_writer); } } void release_keyring_handles() { auto release_service_handles = [](SERVICE_TYPE(keyring_aes) * *aes_encryption, SERVICE_TYPE(keyring_generator) * *generator, SERVICE_TYPE(keyring_keys_metadata_iterator) * *keys_metadata_iterator, SERVICE_TYPE(keyring_component_status) * *component_status, SERVICE_TYPE(keyring_component_metadata_query) * *component_metadata_query, SERVICE_TYPE(keyring_reader_with_status) * *reader, SERVICE_TYPE(keyring_load) * *load, SERVICE_TYPE(keyring_writer) * *writer) { my_service registrator( "registry_registration", srv_registry); if (*aes_encryption) srv_registry->release(reinterpret_cast( const_cast(*aes_encryption))); *aes_encryption = nullptr; if (*generator) srv_registry->release(reinterpret_cast( const_cast(*generator))); *generator = nullptr; if (*keys_metadata_iterator) srv_registry->release(reinterpret_cast( const_cast( *keys_metadata_iterator))); *keys_metadata_iterator = nullptr; if (*component_status) srv_registry->release(reinterpret_cast( const_cast(*component_status))); *component_status = nullptr; if (*component_metadata_query) srv_registry->release(reinterpret_cast( const_cast( *component_metadata_query))); *component_metadata_query = nullptr; if (*reader) srv_registry->release(reinterpret_cast( const_cast(*reader))); *reader = nullptr; if (*load) srv_registry->release(reinterpret_cast( const_cast(*load))); *load = nullptr; if (*writer) srv_registry->release(reinterpret_cast( const_cast(*writer))); *writer = nullptr; }; /* Part 1: Release server wide handles */ release_service_handles( &srv_keyring_aes, &srv_keyring_generator, &srv_keyring_keys_metadata_iterator, &srv_keyring_component_status, &srv_keyring_component_metadata_query, &srv_keyring_reader, &srv_keyring_load, &srv_keyring_writer); /* Part 2: Release internal handles that point to actual implementation */ release_service_handles( &keyring_lockable::internal_keyring_aes, &keyring_lockable::internal_keyring_generator, &keyring_lockable::internal_keyring_keys_metadata_iterator, &keyring_lockable::internal_keyring_component_status, &keyring_lockable::internal_keyring_component_metadata_query, &keyring_lockable::internal_keyring_reader, &keyring_lockable::internal_keyring_load, &keyring_lockable::internal_keyring_writer); } bool keyring_status_no_error() { return ( keyring_lockable::internal_keyring_component_status != nullptr && keyring_lockable::internal_keyring_component_status->is_initialized()); }