diff options
author | Vicențiu Ciorbaru <cvicentiu@gmail.com> | 2021-11-24 23:39:52 +0200 |
---|---|---|
committer | Vicențiu Ciorbaru <cvicentiu@gmail.com> | 2022-02-28 17:02:58 +0200 |
commit | d6c7f025242d3322e69ea2ec0aa7b3f3d4dc5af0 (patch) | |
tree | 8e4dc1b3485345c3b061fc82c0aaa863748593d7 | |
parent | 7fecfaf779b93d4582c21fa636ba6b132a001e93 (diff) | |
download | mariadb-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.cc | 200 | ||||
-rw-r--r-- | sql/sql_acl.h | 7 |
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) |