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;
}