sql/auth/dynamic_privileges_impl.cc (121 lines of code) (raw):

/* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. This program 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; version 2 of the License. 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 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 <mysql/components/service_implementation.h> #include <auth/auth_common.h> #include <auth/dynamic_privilege_table.h> #include <auth/sql_security_ctx.h> #include <mysql/components/my_service.h> #include <mysql/components/services/dynamic_privilege.h> #include <stddef.h> #include "dynamic_privileges_impl.h" #include <mysql/service_plugin_registry.h> #include "current_thd.h" #include "auth/sql_auth_cache.h" #include "sql_thd_internal_api.h" // create_thd /** This helper class is used for either selecting a previous THD or if it's missing, create a new THD. */ class Thd_creator { public: Thd_creator(THD *thd) : m_thd(thd), m_tmp_thd(0) {} /** Returns a THD handle either by creating a new one or by returning a previously created THD. */ THD *operator()() { if (m_thd == 0 && m_tmp_thd == 0) { /* Initiate a THD without plugins, without attaching to the Global_THD_manager, and without setting an OS thread ID. */ m_tmp_thd= create_thd(false, true, false, PSI_NOT_INSTRUMENTED); return m_tmp_thd; } else if (m_thd == 0) { return m_tmp_thd; } return m_thd; } /** Automatically frees any THD handle created by this class. */ ~Thd_creator() { if (m_thd == 0 && m_tmp_thd != 0) { destroy_thd(m_tmp_thd); } } private: THD *m_thd; THD *m_tmp_thd; }; /** Register a privilege identifiers in the list of known identifiers. This enable the SQL syntax to recognize the identifier as a valid token. @param privilege_str The privilege identifier string @param privilege_str_len The length of the identifier string @note This function acquires the THD from the current_thd @returns Error flag @return true The privilege ID couldn't be inserted. @return false The privilege ID was successfully registered. */ DEFINE_BOOL_METHOD(dynamic_privilege_services_impl::register_privilege, (const char *privilege_str, size_t privilege_str_len)) { Thd_creator get_thd(current_thd); try{ Acl_cache_lock_guard acl_cache_lock(get_thd(), Acl_cache_lock_mode::WRITE_MODE); Dynamic_privilege_register *reg= get_dynamic_privilege_register(); std::string priv; const char *c= &privilege_str[0]; for(size_t i= 0; i< privilege_str_len; ++i, ++c) priv.append(1, static_cast<char>(toupper(*c))); if (reg->find(priv) != reg->end()) { /* If the privilege ID already is registered; report success */ return false; } return !get_dynamic_privilege_register()->insert(priv).second; } catch(...) { return true; } } /** Unregister a privilege identifiers in the list of known identifiers. This disables the SQL syntax from recognizing the identifier as a valid token. @param privilege_str The privilege identifier string @param privilege_str_len The length of the identifier string @note This function acquires the THD from the current_thd @returns Error flag @return true The privilege ID wasn't in the list or remove failed. @return false The privilege ID was successfully unregistered. */ DEFINE_BOOL_METHOD(dynamic_privilege_services_impl::unregister_privilege, (const char *privilege_str, size_t privilege_str_len)) { Thd_creator get_thd(current_thd); try { Acl_cache_lock_guard acl_cache_lock(get_thd(), Acl_cache_lock_mode::WRITE_MODE); std::string priv; const char *c= &privilege_str[0]; for(size_t i= 0; i< privilege_str_len; ++i, ++c) priv.append(1, static_cast<char>(toupper(*c))); return (get_dynamic_privilege_register()->erase(priv) == 0); } catch(...) { return true; } } /** Checks if a user has a specified privilege ID granted to it. @param handle The active security context of the user to be checked. @param privilege_str The privilege identifier string @param privilege_str_len The length of the identifier string @returns Success state @return true The user has the grant @return false The user hasn't the grant */ DEFINE_BOOL_METHOD(dynamic_privilege_services_impl::has_global_grant, (Security_context_handle handle, const char *privilege_str, size_t privilege_str_len)) { Security_context *sctx= reinterpret_cast<Security_context *>(handle); return sctx->has_global_grant(privilege_str, privilege_str_len).first; } /** Boostrap the dynamic privilege service by seeding it with server implementation specific data. */ bool dynamic_privilege_init(void) { // Set up default dynamic privileges SERVICE_TYPE(registry) *r= mysql_plugin_registry_acquire(); bool ret= false; { my_service<SERVICE_TYPE(dynamic_privilege_register)> service("dynamic_privilege_register.mysql_server", r); if (service.is_valid()) { ret |= service->register_privilege(STRING_WITH_LEN("ROLE_ADMIN")); ret |= service->register_privilege(STRING_WITH_LEN("SYSTEM_VARIABLES_ADMIN")); ret |= service->register_privilege(STRING_WITH_LEN("BINLOG_ADMIN")); ret |= service->register_privilege(STRING_WITH_LEN("REPLICATION_SLAVE_ADMIN")); ret |= service->register_privilege(STRING_WITH_LEN("GROUP_REPLICATION_ADMIN")); ret |= service->register_privilege(STRING_WITH_LEN("ENCRYPTION_KEY_ADMIN")); ret |= service->register_privilege(STRING_WITH_LEN("CONNECTION_ADMIN")); ret |= service->register_privilege(STRING_WITH_LEN("SET_USER_ID")); ret |= service->register_privilege(STRING_WITH_LEN("XA_RECOVER_ADMIN")); ret |= service->register_privilege(STRING_WITH_LEN("PERSIST_RO_VARIABLES_ADMIN")); } } // exist scope mysql_plugin_registry_release(r); return ret; }