summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVicențiu Ciorbaru <cvicentiu@gmail.com>2021-11-24 23:39:52 +0200
committerVicențiu Ciorbaru <cvicentiu@gmail.com>2022-02-28 17:02:58 +0200
commitd6c7f025242d3322e69ea2ec0aa7b3f3d4dc5af0 (patch)
tree8e4dc1b3485345c3b061fc82c0aaa863748593d7
parent7fecfaf779b93d4582c21fa636ba6b132a001e93 (diff)
downloadmariadb-git-d6c7f025242d3322e69ea2ec0aa7b3f3d4dc5af0.tar.gz
refactor: cache get_current_user result for Sql_cmd_grant
There are a number of get_current_user calls which can cause a malloc. Reorganize code within mysql_grant_xxx such that it assumes LEX_USERS are already resolved. This eliminates a number of mallocs and also simplifies code in mysql_grant_xxx functions. grant_stage0 now resolves lex_users, places it in a list copy, copies the clone's auth structures. Sql_cmd_grant_*::execute now uses the list for all subsequent mysql_grant_xxx functions calls.
-rw-r--r--sql/sql_acl.cc200
-rw-r--r--sql/sql_acl.h7
2 files changed, 94 insertions, 113 deletions
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index b1a6673b05e..a70f4d7b9f6 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -8058,8 +8058,7 @@ static bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list,
List <LEX_USER> &user_list, privilege_t rights,
bool revoke_grant, bool write_to_binlog)
{
- List_iterator <LEX_USER> str_list (user_list);
- LEX_USER *Str, *tmp_Str;
+ List_iterator<LEX_USER> it(user_list);
bool create_new_users= 0;
int result;
const char *db_name, *table_name;
@@ -8094,18 +8093,11 @@ static bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list,
DBUG_PRINT("info",("now time to iterate and add users"));
- while ((tmp_Str= str_list++))
+ for (LEX_USER *user= it++; user != NULL; user= it++)
{
GRANT_NAME *grant_name;
- if (!(Str= get_current_user(thd, tmp_Str, false)))
- {
- result= TRUE;
- continue;
- }
- Str->auth= tmp_Str->auth;
- /* Create user if needed */
- if (check_if_auth_can_be_changed(Str, thd) ||
- replace_user_table(thd, tables.user_table(), Str,
+ if (check_if_auth_can_be_changed(user, thd) ||
+ replace_user_table(thd, tables.user_table(), user,
{NO_ACL, revoke_grant},
create_new_users,
MY_TEST(thd->variables.sql_mode &
@@ -8117,36 +8109,36 @@ static bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list,
db_name= table_list->db.str;
table_name= table_list->table_name.str;
- grant_name= routine_hash_search(Str->host.str, NullS, db_name,
- Str->user.str, table_name, sph, 1);
+ grant_name= routine_hash_search(user->host.str, NullS, db_name,
+ user->user.str, table_name, sph, 1);
if (!grant_name || !grant_name->init_privs)
{
if (revoke_grant)
{
my_error(ER_NONEXISTING_PROC_GRANT, MYF(0),
- Str->user.str, Str->host.str, table_name);
- result= TRUE;
- continue;
+ user->user.str, user->host.str, table_name);
+ result= TRUE;
+ continue;
}
- grant_name= new GRANT_NAME(Str->host.str, db_name,
- Str->user.str, table_name,
- rights, TRUE);
+ grant_name= new GRANT_NAME(user->host.str, db_name,
+ user->user.str, table_name,
+ rights, TRUE);
if (!grant_name ||
my_hash_insert(sph->get_priv_hash(), (uchar*) grant_name))
{
result= TRUE;
- continue;
+ continue;
}
}
if (replace_routine_table(thd, grant_name, tables.procs_priv_table().table(),
- *Str, db_name, table_name, sph, rights, revoke_grant) != 0)
+ *user, db_name, table_name, sph, rights, revoke_grant) != 0)
{
result= TRUE;
continue;
}
- if (Str->is_role())
- propagate_role_grants(find_acl_role(Str->user.str),
+ if (user->is_role())
+ propagate_role_grants(find_acl_role(user->user.str),
sp_privs_to_merge(sph->type()),
db_name, table_name);
}
@@ -8503,27 +8495,16 @@ static bool mysql_grant_global(THD *thd,
/* go through users in user_list */
for (LEX_USER *user= it++; user != NULL; user= it++)
{
- /* Resolve if it the proxy is "CURRENT_USER" or "CURRENT_ROLE" or
- a username / rolename without a hostname specified. */
- LEX_USER *resolved_user= get_current_user(thd, user, false);
- if (!resolved_user)
- {
- result= true;
- continue;
- }
- /* TODO(cvicentiu) This might actually not be necessary for grant_proxy.
- Carry over auth information. */
- resolved_user->auth= user->auth;
- if (check_if_auth_can_be_changed(resolved_user, thd) ||
+ if (check_if_auth_can_be_changed(user, thd) ||
replace_user_table(thd, tables.user_table(),
- resolved_user,
+ user,
priv_spec,
create_new_users,
no_auto_create_users))
result= true;
- if (resolved_user->is_role())
- propagate_role_grants(find_acl_role(resolved_user->user.str),
+ if (user->is_role())
+ propagate_role_grants(find_acl_role(user->user.str),
PRIVS_TO_MERGE::GLOBAL);
}
DBUG_RETURN(result);
@@ -8545,29 +8526,18 @@ static bool mysql_grant_db(THD *thd,
/* go through users in user_list */
for (LEX_USER *user= it++; user != NULL; user= it++)
{
- /* Resolve if it the proxy is "CURRENT_USER" or "CURRENT_ROLE" or
- a username / rolename without a hostname specified. */
- LEX_USER *resolved_user= get_current_user(thd, user, false);
- if (!resolved_user)
- {
- result= true;
- continue;
- }
- /* TODO(cvicentiu) This might actually not be necessary for grant_proxy.
- Carry over auth information. */
- resolved_user->auth= user->auth;
- if (check_if_auth_can_be_changed(resolved_user, thd) ||
+ if (check_if_auth_can_be_changed(user, thd) ||
replace_user_table(thd, tables.user_table(),
- resolved_user,
+ user,
{NO_ACL, priv_spec.revoke},
create_new_users,
no_auto_create_users) ||
replace_db_table(tables.db_table().table(),
- db, *resolved_user, priv_spec.access, priv_spec.revoke))
+ db, *user, priv_spec.access, priv_spec.revoke))
result= true;
- if (resolved_user->is_role())
- propagate_role_grants(find_acl_role(resolved_user->user.str),
+ if (user->is_role())
+ propagate_role_grants(find_acl_role(user->user.str),
PRIVS_TO_MERGE::DB, db);
}
DBUG_RETURN(result);
@@ -8588,32 +8558,17 @@ static bool mysql_grant_proxy(THD *thd,
DBUG_ASSERT(!(priv_spec.access & ~GRANT_ACL)); // Only WITH GRANT OPTION
DBUG_ENTER("mysql_grant_proxy");
-
- proxied_user= get_current_user(thd, proxied_user, false);
- if (!proxied_user)
- DBUG_RETURN(true);
-
/* go through users in user_list */
for (LEX_USER *proxy= it++; proxy != NULL; proxy= it++)
{
- /* Resolve if it the proxy is "CURRENT_USER" or "CURRENT_ROLE" or
- a username / rolename without a hostname specified. */
- LEX_USER *resolved_user= get_current_user(thd, proxy, false);
- if (!resolved_user)
- {
- result= true;
- continue;
- }
- /* Carry over auth information. */
- resolved_user->auth= proxy->auth;
- if (check_if_auth_can_be_changed(resolved_user, thd) ||
+ if (check_if_auth_can_be_changed(proxy, thd) ||
replace_user_table(thd, tables.user_table(),
- resolved_user,
+ proxy,
priv_spec,
create_new_users,
no_auto_create_users) ||
replace_proxies_priv_table(thd, tables.proxies_priv_table().table(),
- resolved_user, proxied_user,
+ proxy, proxied_user,
with_grant_option, priv_spec.revoke))
result= true;
}
@@ -12511,20 +12466,16 @@ bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
Security_context *sctx= thd->security_ctx;
LEX_USER *combo;
TABLE_LIST tables[1];
- List<LEX_USER> user_list;
+ List<LEX_USER> resolved_user_list;
bool result;
ACL_USER *au;
Dummy_error_handler error_handler;
DBUG_ENTER("sp_grant_privileges");
- if (!(combo=(LEX_USER*) thd->alloc(sizeof(LEX_USER))))
- DBUG_RETURN(TRUE);
-
- combo->user.str= (char *) sctx->priv_user;
mysql_mutex_lock(&acl_cache->lock);
- if ((au= find_user_exact(combo->host.str= (char *) sctx->priv_host,
- combo->user.str)))
+ if ((au= find_user_exact(sctx->priv_host,
+ sctx->priv_user)))
goto found_acl;
mysql_mutex_unlock(&acl_cache->lock);
@@ -12534,19 +12485,27 @@ bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
mysql_mutex_unlock(&acl_cache->lock);
bzero((char*)tables, sizeof(TABLE_LIST));
- user_list.empty();
+ resolved_user_list.empty();
tables->db.str= sp_db;
tables->db.length= sp_db ? strlen(sp_db) : 0;
tables->table_name.str= tables->alias.str= sp_name;
tables->table_name.length= tables->alias.length= sp_name ? strlen(sp_name) : 0;
- thd->make_lex_string(&combo->user, combo->user.str, strlen(combo->user.str));
- thd->make_lex_string(&combo->host, combo->host.str, strlen(combo->host.str));
+ if (!(combo=(LEX_USER*) thd->alloc(sizeof(LEX_USER))))
+ DBUG_RETURN(TRUE);
+
+ combo->user.str= (char *) sctx->priv_user;
+
+ if (!thd->make_lex_string(&combo->user, sctx->priv_user, strlen(sctx->priv_user)) ||
+ !thd->make_lex_string(&combo->host, sctx->priv_host, strlen(sctx->priv_host)))
+ DBUG_RETURN(TRUE);
+
+ combo= get_current_user(thd, combo);
combo->auth= NULL;
- if (user_list.push_back(combo, thd->mem_root))
+ if (resolved_user_list.push_back(combo, thd->mem_root))
DBUG_RETURN(TRUE);
thd->lex->account_options.reset();
@@ -12556,7 +12515,7 @@ bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
as all errors will be handled later.
*/
thd->push_internal_handler(&error_handler);
- result= mysql_routine_grant(thd, tables, sph, user_list,
+ result= mysql_routine_grant(thd, tables, sph, resolved_user_list,
DEFAULT_CREATE_PROC_ACLS, FALSE, FALSE);
thd->pop_internal_handler();
DBUG_RETURN(result);
@@ -12604,7 +12563,7 @@ acl_find_proxy_user(const char *user, const char *host, const char *ip,
}
-bool
+static bool
acl_check_proxy_grant_access(THD *thd, const char *host, const char *user,
bool with_grant)
{
@@ -12852,36 +12811,51 @@ void Sql_cmd_grant::warn_hostname_requires_resolving(THD *thd,
}
-void Sql_cmd_grant::grant_stage0(THD *thd)
+bool Sql_cmd_grant::grant_stage0(THD *thd)
{
thd->binlog_invoker(false); // Replicate current user as grantor
if (thd->security_ctx->user) // If not replication
warn_hostname_requires_resolving(thd, thd->lex->users_list);
-}
+ /*
+ Resolve all users (current_user, current_role,
+ user_without_host_specified).
-bool Sql_cmd_grant::user_list_reset_mqh(THD *thd, List<LEX_USER> &users)
-{
- List_iterator <LEX_USER> it(users);
- LEX_USER *user, *tmp_user;
- while ((tmp_user= it++))
+ This resolved list is needed within all grant ops so we store it as
+ a class member.
+ */
+ List_iterator<LEX_USER> it(thd->lex->users_list);
+ m_resolved_users.empty();
+ for (LEX_USER *tmp_user= it++; tmp_user != NULL; tmp_user= it++)
{
- if (!(user= get_current_user(thd, tmp_user)))
+ LEX_USER *resolved_user= get_current_user(thd, tmp_user);
+ if (!resolved_user) // OOM
return true;
- reset_mqh(user, 0);
+ /* Propagate if there are any auth specs. */
+ resolved_user->auth= tmp_user->auth;
+ m_resolved_users.push_back(resolved_user);
}
return false;
}
-bool Sql_cmd_grant_proxy::check_access_proxy(THD *thd, List<LEX_USER> &users)
+void Sql_cmd_grant::user_list_reset_mqh()
+{
+ List_iterator <LEX_USER> it(m_resolved_users);
+ for (LEX_USER *user= it++; user != NULL; user= it++)
+ reset_mqh(user, 0);
+}
+
+
+bool Sql_cmd_grant_proxy::check_access_proxy(THD *thd,
+ List<LEX_USER> &resolved_users)
{
LEX_USER *user;
- List_iterator <LEX_USER> it(users);
+ List_iterator <LEX_USER> it(resolved_users);
if ((user= it++))
{
// GRANT/REVOKE PROXY has the target user as a first entry in the list
- if (!(user= get_current_user(thd, user)) || !user->host.str)
+ if (!user->host.str)
return true;
if (acl_check_proxy_grant_access(thd, user->host.str, user->user.str,
m_grant_option & GRANT_ACL))
@@ -12903,10 +12877,11 @@ bool Sql_cmd_grant_proxy::execute(THD *thd)
DBUG_ASSERT(lex->first_select_lex()->table_list.first == NULL);
DBUG_ASSERT((m_grant_option & ~GRANT_ACL) == NO_ACL); // only WITH GRANT OPTION
- grant_stage0(thd);
+ if (grant_stage0(thd))
+ return true;
if (thd->security_ctx->user /* If not replication */ &&
- check_access_proxy(thd, lex->users_list))
+ check_access_proxy(thd, m_resolved_users))
return true;
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
@@ -12925,7 +12900,7 @@ bool Sql_cmd_grant_proxy::execute(THD *thd)
grant_version++;
result= mysql_grant_proxy(thd, tables,
- lex->users_list,
+ m_resolved_users,
{m_grant_option, is_revoke()},
create_new_users, no_auto_create_users);
@@ -12938,7 +12913,10 @@ bool Sql_cmd_grant_proxy::execute(THD *thd)
if (!result)
my_ok(thd);
- return !is_revoke() && user_list_reset_mqh(thd, lex->users_list);
+ if (!is_revoke())
+ user_list_reset_mqh();
+
+ return false;
#ifdef WITH_WSREP
wsrep_error_label:
@@ -12954,9 +12932,9 @@ bool Sql_cmd_grant_object::grant_stage0_exact_object(THD *thd,
GRANT_ACL;
if (check_access(thd, priv, table->db.str,
&table->grant.privilege, &table->grant.m_internal,
- 0, 0))
+ 0, 0) ||
+ grant_stage0(thd))
return true;
- grant_stage0(thd);
return false;
}
@@ -13008,7 +12986,7 @@ bool Sql_cmd_grant_sp::execute(THD *thd)
/* Conditionally writes to binlog */
WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL);
if (mysql_routine_grant(thd, lex->query_tables, &m_sph,
- lex->users_list, grants,
+ m_resolved_users, grants,
is_revoke(), true))
return true;
my_ok(thd);
@@ -13037,7 +13015,8 @@ bool Sql_cmd_grant_table::execute_table_mask(THD *thd)
if (check_access(thd, required_access, m_gp.db().str, NULL, NULL, 1, 0))
return true;
- grant_stage0(thd);
+ if (grant_stage0(thd))
+ return true;
if (!is_revoke())
create_new_users= test_if_create_new_users(thd);
@@ -13082,7 +13061,7 @@ bool Sql_cmd_grant_table::execute_table_mask(THD *thd)
grant_version++;
result= mysql_grant_db(thd, tables,
- lex->users_list, db,
+ m_resolved_users, db,
{m_gp.object_privilege(), is_revoke()},
create_new_users, no_auto_create_users);
@@ -13106,7 +13085,7 @@ bool Sql_cmd_grant_table::execute_table_mask(THD *thd)
grant_version++;
/* Conditionally writes to binlog */
result= mysql_grant_global(thd, tables,
- lex->users_list,
+ m_resolved_users,
{m_gp.object_privilege(), is_revoke()},
create_new_users,
no_auto_create_users);
@@ -13120,7 +13099,10 @@ bool Sql_cmd_grant_table::execute_table_mask(THD *thd)
my_ok(thd);
}
- return !is_revoke() && user_list_reset_mqh(thd, lex->users_list);
+ if (!is_revoke())
+ user_list_reset_mqh();
+
+ return false;
#ifdef WITH_WSREP
wsrep_error_label:
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index 1a13fac0299..65be8f13a22 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -311,8 +311,6 @@ get_cached_table_access(GRANT_INTERNAL_INFO *grant_internal_info,
const char *schema_name,
const char *table_name);
-bool acl_check_proxy_grant_access (THD *thd, const char *host, const char *user,
- bool with_grant);
int acl_setrole(THD *thd, const char *rolename, privilege_t access);
int acl_check_setrole(THD *thd, const char *rolename, privilege_t *access);
int acl_check_set_default_role(THD *thd, const char *host, const char *user,
@@ -340,10 +338,11 @@ class Sql_cmd_grant: public Sql_cmd
{
protected:
enum_sql_command m_command;
+ List<LEX_USER> m_resolved_users;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
void warn_hostname_requires_resolving(THD *thd, List<LEX_USER> &list);
- bool user_list_reset_mqh(THD *thd, List<LEX_USER> &list);
- void grant_stage0(THD *thd);
+ void user_list_reset_mqh();
+ bool grant_stage0(THD *thd);
#endif
public:
Sql_cmd_grant(enum_sql_command command)