diff options
Diffstat (limited to 'sql/sql_acl.cc')
-rw-r--r-- | sql/sql_acl.cc | 461 |
1 files changed, 252 insertions, 209 deletions
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 0e8c4e7b055..9bb50d58dc5 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2003 MySQL AB +/* Copyright (C) 2000-2003 MySQL AB, 2008-2009 Sun Microsystems, Inc 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 @@ -371,23 +371,23 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) DBUG_PRINT("info",("user table fields: %d, password length: %d", table->s->fields, password_length)); - pthread_mutex_lock(&LOCK_global_system_variables); + mysql_mutex_lock(&LOCK_global_system_variables); if (password_length < SCRAMBLED_PASSWORD_CHAR_LENGTH) { if (opt_secure_auth) { - pthread_mutex_unlock(&LOCK_global_system_variables); + mysql_mutex_unlock(&LOCK_global_system_variables); sql_print_error("Fatal error: mysql.user table is in old format, " "but server started with --secure-auth option."); goto end; } mysql_user_table_is_in_short_password_format= true; if (global_system_variables.old_passwords) - pthread_mutex_unlock(&LOCK_global_system_variables); + mysql_mutex_unlock(&LOCK_global_system_variables); else { global_system_variables.old_passwords= 1; - pthread_mutex_unlock(&LOCK_global_system_variables); + mysql_mutex_unlock(&LOCK_global_system_variables); sql_print_warning("mysql.user table is not updated to new password format; " "Disabling new password usage until " "mysql_fix_privilege_tables is run"); @@ -397,7 +397,7 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) else { mysql_user_table_is_in_short_password_format= false; - pthread_mutex_unlock(&LOCK_global_system_variables); + mysql_mutex_unlock(&LOCK_global_system_variables); } allow_all_hosts=0; @@ -689,7 +689,7 @@ my_bool acl_reload(THD *thd) } if ((old_initialized=initialized)) - pthread_mutex_lock(&acl_cache->lock); + mysql_mutex_lock(&acl_cache->lock); old_acl_hosts=acl_hosts; old_acl_users=acl_users; @@ -716,7 +716,7 @@ my_bool acl_reload(THD *thd) delete_dynamic(&old_acl_dbs); } if (old_initialized) - pthread_mutex_unlock(&acl_cache->lock); + mysql_mutex_unlock(&acl_cache->lock); end: close_thread_tables(thd); DBUG_RETURN(return_val); @@ -868,7 +868,7 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh, DBUG_RETURN(0); } - pthread_mutex_lock(&acl_cache->lock); + mysql_mutex_lock(&acl_cache->lock); /* Find acl entry in user database. Note, that find_acl_user is not the same, @@ -1047,7 +1047,7 @@ int acl_getroot(THD *thd, USER_RESOURCES *mqh, else *sctx->priv_host= 0; } - pthread_mutex_unlock(&acl_cache->lock); + mysql_mutex_unlock(&acl_cache->lock); DBUG_RETURN(res); } @@ -1094,7 +1094,7 @@ bool acl_getroot_no_password(Security_context *sctx, char *user, char *host, DBUG_RETURN(FALSE); } - pthread_mutex_lock(&acl_cache->lock); + mysql_mutex_lock(&acl_cache->lock); sctx->master_access= 0; sctx->db_access= 0; @@ -1148,7 +1148,7 @@ bool acl_getroot_no_password(Security_context *sctx, char *user, char *host, else *sctx->priv_host= 0; } - pthread_mutex_unlock(&acl_cache->lock); + mysql_mutex_unlock(&acl_cache->lock); DBUG_RETURN(res); } @@ -1169,7 +1169,7 @@ static void acl_update_user(const char *user, const char *host, USER_RESOURCES *mqh, ulong privileges) { - safe_mutex_assert_owner(&acl_cache->lock); + mysql_mutex_assert_owner(&acl_cache->lock); for (uint i=0 ; i < acl_users.elements ; i++) { @@ -1221,7 +1221,7 @@ static void acl_insert_user(const char *user, const char *host, { ACL_USER acl_user; - safe_mutex_assert_owner(&acl_cache->lock); + mysql_mutex_assert_owner(&acl_cache->lock); acl_user.user=*user ? strdup_root(&mem,user) : 0; update_hostname(&acl_user.host, *host ? strdup_root(&mem, host): 0); @@ -1252,7 +1252,7 @@ static void acl_insert_user(const char *user, const char *host, static void acl_update_db(const char *user, const char *host, const char *db, ulong privileges) { - safe_mutex_assert_owner(&acl_cache->lock); + mysql_mutex_assert_owner(&acl_cache->lock); for (uint i=0 ; i < acl_dbs.elements ; i++) { @@ -1297,7 +1297,7 @@ static void acl_insert_db(const char *user, const char *host, const char *db, ulong privileges) { ACL_DB acl_db; - safe_mutex_assert_owner(&acl_cache->lock); + mysql_mutex_assert_owner(&acl_cache->lock); acl_db.user=strdup_root(&mem,user); update_hostname(&acl_db.host, *host ? strdup_root(&mem,host) : 0); acl_db.db=strdup_root(&mem,db); @@ -1327,7 +1327,7 @@ ulong acl_get(const char *host, const char *ip, acl_entry *entry; DBUG_ENTER("acl_get"); - pthread_mutex_lock(&acl_cache->lock); + mysql_mutex_lock(&acl_cache->lock); end=strmov((tmp_db=strmov(strmov(key, ip ? ip : "")+1,user)+1),db); if (lower_case_table_names) { @@ -1339,7 +1339,7 @@ ulong acl_get(const char *host, const char *ip, key_length))) { db_access=entry->access; - pthread_mutex_unlock(&acl_cache->lock); + mysql_mutex_unlock(&acl_cache->lock); DBUG_PRINT("exit", ("access: 0x%lx", db_access)); DBUG_RETURN(db_access); } @@ -1393,7 +1393,7 @@ exit: memcpy((uchar*) entry->key,key,key_length); acl_cache->add(entry); } - pthread_mutex_unlock(&acl_cache->lock); + mysql_mutex_unlock(&acl_cache->lock); DBUG_PRINT("exit", ("access: 0x%lx", db_access & host_access)); DBUG_RETURN(db_access & host_access); } @@ -1475,12 +1475,12 @@ bool acl_check_host(const char *host, const char *ip) { if (allow_all_hosts) return 0; - pthread_mutex_lock(&acl_cache->lock); + mysql_mutex_lock(&acl_cache->lock); if ((host && my_hash_search(&acl_check_hosts,(uchar*) host,strlen(host))) || (ip && my_hash_search(&acl_check_hosts,(uchar*) ip, strlen(ip)))) { - pthread_mutex_unlock(&acl_cache->lock); + mysql_mutex_unlock(&acl_cache->lock); return 0; // Found host } for (uint i=0 ; i < acl_wild_hosts.elements ; i++) @@ -1488,11 +1488,11 @@ bool acl_check_host(const char *host, const char *ip) acl_host_and_ip *acl=dynamic_element(&acl_wild_hosts,i,acl_host_and_ip*); if (compare_hostname(acl, host, ip)) { - pthread_mutex_unlock(&acl_cache->lock); + mysql_mutex_unlock(&acl_cache->lock); return 0; // Host ok } } - pthread_mutex_unlock(&acl_cache->lock); + mysql_mutex_unlock(&acl_cache->lock); return 1; // Host is not allowed } @@ -1528,7 +1528,7 @@ int check_change_password(THD *thd, const char *host, const char *user, my_strcasecmp(system_charset_info, host, thd->security_ctx->priv_host))) { - if (check_access(thd, UPDATE_ACL, "mysql",0,1,0,0)) + if (check_access(thd, UPDATE_ACL, "mysql", NULL, NULL, 1, 0)) return(1); } if (!thd->slave_thread && !thd->security_ctx->user[0]) @@ -1606,11 +1606,11 @@ bool change_password(THD *thd, const char *host, const char *user, if (!(table= open_ltable(thd, &tables, TL_WRITE, 0))) DBUG_RETURN(1); - pthread_mutex_lock(&acl_cache->lock); + mysql_mutex_lock(&acl_cache->lock); ACL_USER *acl_user; if (!(acl_user= find_acl_user(host, user, TRUE))) { - pthread_mutex_unlock(&acl_cache->lock); + mysql_mutex_unlock(&acl_cache->lock); my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH), MYF(0)); goto end; } @@ -1622,12 +1622,12 @@ bool change_password(THD *thd, const char *host, const char *user, acl_user->user ? acl_user->user : "", new_password, new_password_len)) { - pthread_mutex_unlock(&acl_cache->lock); /* purecov: deadcode */ + mysql_mutex_unlock(&acl_cache->lock); /* purecov: deadcode */ goto end; } acl_cache->clear(1); // Clear locked hostname cache - pthread_mutex_unlock(&acl_cache->lock); + mysql_mutex_unlock(&acl_cache->lock); result= 0; if (mysql_bin_log.is_open()) { @@ -1668,9 +1668,9 @@ bool is_acl_user(const char *host, const char *user) if (!initialized) return TRUE; - pthread_mutex_lock(&acl_cache->lock); + mysql_mutex_lock(&acl_cache->lock); res= find_acl_user(host, user, TRUE) != NULL; - pthread_mutex_unlock(&acl_cache->lock); + mysql_mutex_unlock(&acl_cache->lock); return res; } @@ -1685,7 +1685,7 @@ find_acl_user(const char *host, const char *user, my_bool exact) DBUG_ENTER("find_acl_user"); DBUG_PRINT("enter",("host: '%s' user: '%s'",host,user)); - safe_mutex_assert_owner(&acl_cache->lock); + mysql_mutex_assert_owner(&acl_cache->lock); for (uint i=0 ; i < acl_users.elements ; i++) { @@ -1947,7 +1947,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, LEX *lex= thd->lex; DBUG_ENTER("replace_user_table"); - safe_mutex_assert_owner(&acl_cache->lock); + mysql_mutex_assert_owner(&acl_cache->lock); if (combo.password.str && combo.password.str[0]) { @@ -3147,8 +3147,8 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, if (!revoke_grant) create_new_users= test_if_create_new_users(thd); bool result= FALSE; - rw_wrlock(&LOCK_grant); - pthread_mutex_lock(&acl_cache->lock); + mysql_rwlock_wrlock(&LOCK_grant); + mysql_mutex_lock(&acl_cache->lock); MEM_ROOT *old_root= thd->mem_root; thd->mem_root= &memex; grant_version++; @@ -3253,14 +3253,14 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, } } thd->mem_root= old_root; - pthread_mutex_unlock(&acl_cache->lock); + mysql_mutex_unlock(&acl_cache->lock); if (!result) /* success */ { result= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } - rw_unlock(&LOCK_grant); + mysql_rwlock_unlock(&LOCK_grant); if (!result) /* success */ my_ok(thd); @@ -3357,8 +3357,8 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, if (!revoke_grant) create_new_users= test_if_create_new_users(thd); - rw_wrlock(&LOCK_grant); - pthread_mutex_lock(&acl_cache->lock); + mysql_rwlock_wrlock(&LOCK_grant); + mysql_mutex_lock(&acl_cache->lock); MEM_ROOT *old_root= thd->mem_root; thd->mem_root= &memex; @@ -3419,7 +3419,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, } } thd->mem_root= old_root; - pthread_mutex_unlock(&acl_cache->lock); + mysql_mutex_unlock(&acl_cache->lock); if (write_to_binlog) { @@ -3427,7 +3427,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, result= TRUE; } - rw_unlock(&LOCK_grant); + mysql_rwlock_unlock(&LOCK_grant); /* Tables are automatically closed */ DBUG_RETURN(result); @@ -3499,8 +3499,8 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list, create_new_users= test_if_create_new_users(thd); /* go through users in user_list */ - rw_wrlock(&LOCK_grant); - pthread_mutex_lock(&acl_cache->lock); + mysql_rwlock_wrlock(&LOCK_grant); + mysql_mutex_lock(&acl_cache->lock); grant_version++; int result=0; @@ -3539,14 +3539,14 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list, } } } - pthread_mutex_unlock(&acl_cache->lock); + mysql_mutex_unlock(&acl_cache->lock); if (!result) { result= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } - rw_unlock(&LOCK_grant); + mysql_rwlock_unlock(&LOCK_grant); close_thread_tables(thd); if (!result) @@ -3810,7 +3810,7 @@ static my_bool grant_reload_procs_priv(THD *thd) DBUG_RETURN(TRUE); } - rw_wrlock(&LOCK_grant); + mysql_rwlock_wrlock(&LOCK_grant); /* Save a copy of the current hash if we need to undo the grant load */ old_proc_priv_hash= proc_priv_hash; old_func_priv_hash= func_priv_hash; @@ -3828,7 +3828,7 @@ static my_bool grant_reload_procs_priv(THD *thd) my_hash_free(&old_proc_priv_hash); my_hash_free(&old_func_priv_hash); } - rw_unlock(&LOCK_grant); + mysql_rwlock_unlock(&LOCK_grant); close_thread_tables(thd); DBUG_RETURN(return_val); @@ -3876,7 +3876,7 @@ my_bool grant_reload(THD *thd) if (simple_open_n_lock_tables(thd, tables)) goto end; - rw_wrlock(&LOCK_grant); + mysql_rwlock_wrlock(&LOCK_grant); old_column_priv_hash= column_priv_hash; /* @@ -3898,7 +3898,7 @@ my_bool grant_reload(THD *thd) my_hash_free(&old_column_priv_hash); free_root(&old_mem,MYF(0)); } - rw_unlock(&LOCK_grant); + mysql_rwlock_unlock(&LOCK_grant); close_thread_tables(thd); /* @@ -3908,9 +3908,9 @@ my_bool grant_reload(THD *thd) if (grant_reload_procs_priv(thd)) return_val= 1; - rw_wrlock(&LOCK_grant); + mysql_rwlock_wrlock(&LOCK_grant); grant_version++; - rw_unlock(&LOCK_grant); + mysql_rwlock_unlock(&LOCK_grant); end: DBUG_RETURN(return_val); @@ -3962,6 +3962,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, TABLE_LIST *table, *first_not_own_table= thd->lex->first_not_own_table(); Security_context *sctx= thd->security_ctx; uint i; + ulong orig_want_access= want_access; DBUG_ENTER("check_grant"); DBUG_ASSERT(number > 0); @@ -3986,7 +3987,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, table->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL); } - rw_rdlock(&LOCK_grant); + mysql_rwlock_rdlock(&LOCK_grant); for (table= tables; table && number-- && table != first_not_own_table; table= table->next_global) @@ -3995,6 +3996,33 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, sctx = test(table->security_ctx) ? table->security_ctx : thd->security_ctx; + const ACL_internal_table_access *access; + access= get_cached_table_access(&table->grant.m_internal, + table->get_db_name(), + table->get_table_name()); + + if (access) + { + switch(access->check(orig_want_access, &table->grant.privilege)) + { + case ACL_INTERNAL_ACCESS_GRANTED: + /* + Currently, + - the information_schema does not subclass ACL_internal_table_access, + there are no per table privilege checks for I_S, + - the performance schema does use per tables checks, but at most + returns 'CHECK_GRANT', and never 'ACCESS_GRANTED'. + so this branch is not used. + */ + DBUG_ASSERT(0); + case ACL_INTERNAL_ACCESS_DENIED: + goto err; + case ACL_INTERNAL_ACCESS_CHECK_GRANT: + break; + } + } + + want_access= orig_want_access; want_access&= ~sctx->master_access; if (!want_access) continue; // ok @@ -4047,11 +4075,11 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, goto err; // impossible } } - rw_unlock(&LOCK_grant); + mysql_rwlock_unlock(&LOCK_grant); DBUG_RETURN(FALSE); err: - rw_unlock(&LOCK_grant); + mysql_rwlock_unlock(&LOCK_grant); if (!no_errors) // Not a silent skip of table { char command[128]; @@ -4066,96 +4094,6 @@ err: } -/** - Check if all tables in the table list has any of the requested table level - privileges matching the current user. - - @param thd A pointer to the thread context. - @param required_access Set of privileges to compare against. - @param tables[in,out] A list of tables to be checked. - - @note If the table grant hash contains any grant table, this table will be - attached to the corresponding TABLE_LIST object in 'tables'. - - @return - @retval TRUE There is a privilege on the table level granted to the - current user. - @retval FALSE There are no privileges on the table level granted to the - current user. -*/ - -bool has_any_table_level_privileges(THD *thd, ulong required_access, - TABLE_LIST *tables) -{ - - Security_context *sctx; - GRANT_TABLE *grant_table; - TABLE_LIST *table; - - /* For each table in tables */ - for (table= tables; table; table= table->next_global) - { - /* - If this table is a VIEW, then it will supply its own security context. - This is because VIEWs can have a DEFINER or an INVOKER security role. - */ - sctx= table->security_ctx ? table->security_ctx : thd->security_ctx; - - /* - Get privileges from table_priv and column_priv tables by searching - the cache. - */ - rw_rdlock(&LOCK_grant); - grant_table= table_hash_search(sctx->host, sctx->ip, - table->db, sctx->priv_user, - table->table_name,0); - rw_unlock(&LOCK_grant); - - /* Stop if there are no grants for the current user */ - if (!grant_table) - return FALSE; - - /* - Save a pointer to the found grant_table in the table object. - This pointer can later be used to verify other access requirements - without having to look up the grant table in the hash. - */ - table->grant.grant_table= grant_table; - table->grant.version= grant_version; - table->grant.privilege|= grant_table->privs; - /* - Save all privileges which might be subject to column privileges - but not which aren't yet granted by table level ACLs. - This is can later be used for column privilege checks. - */ - table->grant.want_privilege= ((required_access & COL_ACLS) - & ~table->grant.privilege); - - /* - If the requested privileges share any intersection with the current - table privileges we have found at least one common privilege on the - table level. - */ - if (grant_table->privs & required_access) - continue; /* Check next table */ - - /* - There are no table level privileges which satisfies any of the - requested privileges. There might still be column privileges which - does though. - */ - return FALSE; - } - - /* - All tables in TABLE_LIST satisfy the requirement of having any - privilege on the table level. - */ - - return TRUE; -} - - /* Check column rights in given security context @@ -4187,7 +4125,7 @@ bool check_grant_column(THD *thd, GRANT_INFO *grant, if (!want_access) DBUG_RETURN(0); // Already checked - rw_rdlock(&LOCK_grant); + mysql_rwlock_rdlock(&LOCK_grant); /* reload table if someone has modified any grants */ @@ -4205,12 +4143,12 @@ bool check_grant_column(THD *thd, GRANT_INFO *grant, grant_column=column_hash_search(grant_table, name, length); if (grant_column && !(~grant_column->rights & want_access)) { - rw_unlock(&LOCK_grant); + mysql_rwlock_unlock(&LOCK_grant); DBUG_RETURN(0); } err: - rw_unlock(&LOCK_grant); + mysql_rwlock_unlock(&LOCK_grant); char command[128]; get_privilege_desc(command, sizeof(command), want_access); my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), @@ -4325,7 +4263,7 @@ bool check_grant_all_columns(THD *thd, ulong want_access_arg, */ bool using_column_privileges= FALSE; - rw_rdlock(&LOCK_grant); + mysql_rwlock_rdlock(&LOCK_grant); for (; !fields->end_of_fields(); fields->next()) { @@ -4366,11 +4304,11 @@ bool check_grant_all_columns(THD *thd, ulong want_access_arg, goto err; } } - rw_unlock(&LOCK_grant); + mysql_rwlock_unlock(&LOCK_grant); return 0; err: - rw_unlock(&LOCK_grant); + mysql_rwlock_unlock(&LOCK_grant); char command[128]; get_privilege_desc(command, sizeof(command), want_access); @@ -4428,7 +4366,7 @@ bool check_grant_db(THD *thd,const char *db) len= (uint) (strmov(strmov(helping, sctx->priv_user) + 1, db) - helping) + 1; - rw_rdlock(&LOCK_grant); + mysql_rwlock_rdlock(&LOCK_grant); for (uint idx=0 ; idx < column_priv_hash.records ; idx++) { @@ -4448,7 +4386,7 @@ bool check_grant_db(THD *thd,const char *db) error= check_grant_db_routine(thd, db, &proc_priv_hash) && check_grant_db_routine(thd, db, &func_priv_hash); - rw_unlock(&LOCK_grant); + mysql_rwlock_unlock(&LOCK_grant); return error; } @@ -4484,7 +4422,7 @@ bool check_grant_routine(THD *thd, ulong want_access, if (!want_access) DBUG_RETURN(0); // ok - rw_rdlock(&LOCK_grant); + mysql_rwlock_rdlock(&LOCK_grant); for (table= procs; table; table= table->next_global) { GRANT_NAME *grant_proc; @@ -4498,10 +4436,10 @@ bool check_grant_routine(THD *thd, ulong want_access, goto err; } } - rw_unlock(&LOCK_grant); + mysql_rwlock_unlock(&LOCK_grant); DBUG_RETURN(0); err: - rw_unlock(&LOCK_grant); + mysql_rwlock_unlock(&LOCK_grant); if (!no_errors) { char buff[1024]; @@ -4542,13 +4480,13 @@ bool check_routine_level_acl(THD *thd, const char *db, const char *name, bool no_routine_acl= 1; GRANT_NAME *grant_proc; Security_context *sctx= thd->security_ctx; - rw_rdlock(&LOCK_grant); + mysql_rwlock_rdlock(&LOCK_grant); if ((grant_proc= routine_hash_search(sctx->priv_host, sctx->ip, db, sctx->priv_user, name, is_proc, 0))) no_routine_acl= !(grant_proc->privs & SHOW_PROC_ACLS); - rw_unlock(&LOCK_grant); + mysql_rwlock_unlock(&LOCK_grant); return no_routine_acl; } @@ -4564,7 +4502,7 @@ ulong get_table_grant(THD *thd, TABLE_LIST *table) const char *db = table->db ? table->db : thd->db; GRANT_TABLE *grant_table; - rw_rdlock(&LOCK_grant); + mysql_rwlock_rdlock(&LOCK_grant); #ifdef EMBEDDED_LIBRARY grant_table= NULL; #else @@ -4576,7 +4514,7 @@ ulong get_table_grant(THD *thd, TABLE_LIST *table) if (grant_table) table->grant.privilege|= grant_table->privs; privilege= table->grant.privilege; - rw_unlock(&LOCK_grant); + mysql_rwlock_unlock(&LOCK_grant); return privilege; } @@ -4607,7 +4545,7 @@ ulong get_column_grant(THD *thd, GRANT_INFO *grant, GRANT_COLUMN *grant_column; ulong priv; - rw_rdlock(&LOCK_grant); + mysql_rwlock_rdlock(&LOCK_grant); /* reload table if someone has modified any grants */ if (grant->version != grant_version) { @@ -4630,7 +4568,7 @@ ulong get_column_grant(THD *thd, GRANT_INFO *grant, else priv= (grant->privilege | grant_table->privs | grant_column->rights); } - rw_unlock(&LOCK_grant); + mysql_rwlock_unlock(&LOCK_grant); return priv; } @@ -4697,14 +4635,14 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) DBUG_RETURN(TRUE); } - rw_rdlock(&LOCK_grant); - pthread_mutex_lock(&acl_cache->lock); + mysql_rwlock_rdlock(&LOCK_grant); + mysql_mutex_lock(&acl_cache->lock); acl_user= find_acl_user(lex_user->host.str, lex_user->user.str, TRUE); if (!acl_user) { - pthread_mutex_unlock(&acl_cache->lock); - rw_unlock(&LOCK_grant); + mysql_mutex_unlock(&acl_cache->lock); + mysql_rwlock_unlock(&LOCK_grant); my_error(ER_NONEXISTING_GRANT, MYF(0), lex_user->user.str, lex_user->host.str); @@ -4721,8 +4659,8 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) if (protocol->send_result_set_metadata(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) { - pthread_mutex_unlock(&acl_cache->lock); - rw_unlock(&LOCK_grant); + mysql_mutex_unlock(&acl_cache->lock); + mysql_rwlock_unlock(&LOCK_grant); DBUG_RETURN(TRUE); } @@ -5032,8 +4970,8 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) } end: - pthread_mutex_unlock(&acl_cache->lock); - rw_unlock(&LOCK_grant); + mysql_mutex_unlock(&acl_cache->lock); + mysql_rwlock_unlock(&LOCK_grant); my_eof(thd); DBUG_RETURN(error); @@ -5157,14 +5095,14 @@ void get_mqh(const char *user, const char *host, USER_CONN *uc) { ACL_USER *acl_user; - pthread_mutex_lock(&acl_cache->lock); + mysql_mutex_lock(&acl_cache->lock); if (initialized && (acl_user= find_acl_user(host,user, FALSE))) uc->user_resources= acl_user->user_resource; else bzero((char*) &uc->user_resources, sizeof(uc->user_resources)); - pthread_mutex_unlock(&acl_cache->lock); + mysql_mutex_unlock(&acl_cache->lock); } /* @@ -5250,7 +5188,7 @@ ACL_USER *check_acl_user(LEX_USER *user_name, ACL_USER *acl_user= 0; uint counter; - safe_mutex_assert_owner(&acl_cache->lock); + mysql_mutex_assert_owner(&acl_cache->lock); for (counter= 0 ; counter < acl_users.elements ; counter++) { @@ -5519,7 +5457,7 @@ static int handle_grant_struct(uint struct_no, bool drop, LINT_INIT(user); LINT_INIT(host); - safe_mutex_assert_owner(&acl_cache->lock); + mysql_mutex_assert_owner(&acl_cache->lock); /* Get the number of elements in the in-memory structure. */ switch (struct_no) { @@ -5829,8 +5767,8 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list) if ((result= open_grant_tables(thd, tables))) DBUG_RETURN(result != 1); - rw_wrlock(&LOCK_grant); - pthread_mutex_lock(&acl_cache->lock); + mysql_rwlock_wrlock(&LOCK_grant); + mysql_mutex_lock(&acl_cache->lock); while ((tmp_user_name= user_list++)) { @@ -5860,7 +5798,7 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list) } } - pthread_mutex_unlock(&acl_cache->lock); + mysql_mutex_unlock(&acl_cache->lock); if (result) my_error(ER_CANNOT_USER, MYF(0), "CREATE USER", wrong_users.c_ptr_safe()); @@ -5868,7 +5806,7 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list) if (some_users_created) result |= write_bin_log(thd, FALSE, thd->query(), thd->query_length()); - rw_unlock(&LOCK_grant); + mysql_rwlock_unlock(&LOCK_grant); close_thread_tables(thd); DBUG_RETURN(result); } @@ -5911,8 +5849,8 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list) thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH; - rw_wrlock(&LOCK_grant); - pthread_mutex_lock(&acl_cache->lock); + mysql_rwlock_wrlock(&LOCK_grant); + mysql_mutex_lock(&acl_cache->lock); while ((tmp_user_name= user_list++)) { @@ -5933,7 +5871,7 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list) /* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */ rebuild_check_host(); - pthread_mutex_unlock(&acl_cache->lock); + mysql_mutex_unlock(&acl_cache->lock); if (result) my_error(ER_CANNOT_USER, MYF(0), "DROP USER", wrong_users.c_ptr_safe()); @@ -5941,7 +5879,7 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list) if (some_users_deleted) result |= write_bin_log(thd, FALSE, thd->query(), thd->query_length()); - rw_unlock(&LOCK_grant); + mysql_rwlock_unlock(&LOCK_grant); close_thread_tables(thd); thd->variables.sql_mode= old_sql_mode; DBUG_RETURN(result); @@ -5983,8 +5921,8 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list) if ((result= open_grant_tables(thd, tables))) DBUG_RETURN(result != 1); - rw_wrlock(&LOCK_grant); - pthread_mutex_lock(&acl_cache->lock); + mysql_rwlock_wrlock(&LOCK_grant); + mysql_mutex_lock(&acl_cache->lock); while ((tmp_user_from= user_list++)) { @@ -6018,7 +5956,7 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list) /* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */ rebuild_check_host(); - pthread_mutex_unlock(&acl_cache->lock); + mysql_mutex_unlock(&acl_cache->lock); if (result) my_error(ER_CANNOT_USER, MYF(0), "RENAME USER", wrong_users.c_ptr_safe()); @@ -6026,7 +5964,7 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list) if (some_users_renamed && mysql_bin_log.is_open()) result |= write_bin_log(thd, FALSE, thd->query(), thd->query_length()); - rw_unlock(&LOCK_grant); + mysql_rwlock_unlock(&LOCK_grant); close_thread_tables(thd); DBUG_RETURN(result); } @@ -6064,8 +6002,8 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list) if ((result= open_grant_tables(thd, tables))) DBUG_RETURN(result != 1); - rw_wrlock(&LOCK_grant); - pthread_mutex_lock(&acl_cache->lock); + mysql_rwlock_wrlock(&LOCK_grant); + mysql_mutex_lock(&acl_cache->lock); LEX_USER *lex_user, *tmp_lex_user; List_iterator <LEX_USER> user_list(list); @@ -6204,12 +6142,12 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list) } while (revoked); } - pthread_mutex_unlock(&acl_cache->lock); + mysql_mutex_unlock(&acl_cache->lock); int binlog_error= write_bin_log(thd, FALSE, thd->query(), thd->query_length()); - rw_unlock(&LOCK_grant); + mysql_rwlock_unlock(&LOCK_grant); close_thread_tables(thd); /* error for writing binary log has already been reported */ @@ -6314,8 +6252,8 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name, /* Be sure to pop this before exiting this scope! */ thd->push_internal_handler(&error_handler); - rw_wrlock(&LOCK_grant); - pthread_mutex_lock(&acl_cache->lock); + mysql_rwlock_wrlock(&LOCK_grant); + mysql_mutex_lock(&acl_cache->lock); /* This statement will be replicated as a statement, even when using @@ -6353,8 +6291,8 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name, } } while (revoked); - pthread_mutex_unlock(&acl_cache->lock); - rw_unlock(&LOCK_grant); + mysql_mutex_unlock(&acl_cache->lock); + mysql_rwlock_unlock(&LOCK_grant); close_thread_tables(thd); thd->pop_internal_handler(); @@ -6394,7 +6332,7 @@ bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name, combo->user.str= sctx->user; - pthread_mutex_lock(&acl_cache->lock); + mysql_mutex_lock(&acl_cache->lock); if ((au= find_acl_user(combo->host.str=(char*)sctx->host_or_ip,combo->user.str,FALSE))) goto found_acl; @@ -6405,11 +6343,11 @@ bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name, if((au= find_acl_user(combo->host.str=(char*)"%", combo->user.str, FALSE))) goto found_acl; - pthread_mutex_unlock(&acl_cache->lock); + mysql_mutex_unlock(&acl_cache->lock); DBUG_RETURN(TRUE); found_acl: - pthread_mutex_unlock(&acl_cache->lock); + mysql_mutex_unlock(&acl_cache->lock); bzero((char*)tables, sizeof(TABLE_LIST)); user_list.empty(); @@ -6562,13 +6500,14 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond) ulong want_access; char buff[100]; TABLE *table= tables->table; - bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0); + bool no_global_access= check_access(thd, SELECT_ACL, "mysql", + NULL, NULL, 1, 1); char *curr_host= thd->security_ctx->priv_host_name(); DBUG_ENTER("fill_schema_user_privileges"); if (!initialized) DBUG_RETURN(0); - pthread_mutex_lock(&acl_cache->lock); + mysql_mutex_lock(&acl_cache->lock); for (counter=0 ; counter < acl_users.elements ; counter++) { @@ -6618,7 +6557,7 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond) } } err: - pthread_mutex_unlock(&acl_cache->lock); + mysql_mutex_unlock(&acl_cache->lock); DBUG_RETURN(error); #else @@ -6636,13 +6575,14 @@ int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond) ulong want_access; char buff[100]; TABLE *table= tables->table; - bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0); + bool no_global_access= check_access(thd, SELECT_ACL, "mysql", + NULL, NULL, 1, 1); char *curr_host= thd->security_ctx->priv_host_name(); DBUG_ENTER("fill_schema_schema_privileges"); if (!initialized) DBUG_RETURN(0); - pthread_mutex_lock(&acl_cache->lock); + mysql_mutex_lock(&acl_cache->lock); for (counter=0 ; counter < acl_dbs.elements ; counter++) { @@ -6695,7 +6635,7 @@ int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond) } } err: - pthread_mutex_unlock(&acl_cache->lock); + mysql_mutex_unlock(&acl_cache->lock); DBUG_RETURN(error); #else @@ -6711,11 +6651,12 @@ int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond) uint index; char buff[100]; TABLE *table= tables->table; - bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0); + bool no_global_access= check_access(thd, SELECT_ACL, "mysql", + NULL, NULL, 1, 1); char *curr_host= thd->security_ctx->priv_host_name(); DBUG_ENTER("fill_schema_table_privileges"); - rw_rdlock(&LOCK_grant); + mysql_rwlock_rdlock(&LOCK_grant); for (index=0 ; index < column_priv_hash.records ; index++) { @@ -6778,7 +6719,7 @@ int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond) } } err: - rw_unlock(&LOCK_grant); + mysql_rwlock_unlock(&LOCK_grant); DBUG_RETURN(error); #else @@ -6794,11 +6735,12 @@ int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond) uint index; char buff[100]; TABLE *table= tables->table; - bool no_global_access= check_access(thd, SELECT_ACL, "mysql",0,1,1,0); + bool no_global_access= check_access(thd, SELECT_ACL, "mysql", + NULL, NULL, 1, 1); char *curr_host= thd->security_ctx->priv_host_name(); DBUG_ENTER("fill_schema_table_privileges"); - rw_rdlock(&LOCK_grant); + mysql_rwlock_rdlock(&LOCK_grant); for (index=0 ; index < column_priv_hash.records ; index++) { @@ -6859,7 +6801,7 @@ int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond) } } err: - rw_unlock(&LOCK_grant); + mysql_rwlock_unlock(&LOCK_grant); DBUG_RETURN(error); #else @@ -6911,7 +6853,7 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant, grant->privilege|= acl_get(sctx->host, sctx->ip, sctx->priv_user, db, 0); /* table privileges */ - rw_rdlock(&LOCK_grant); + mysql_rwlock_rdlock(&LOCK_grant); if (grant->version != grant_version) { grant->grant_table= @@ -6924,7 +6866,7 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant, { grant->privilege|= grant->grant_table->privs; } - rw_unlock(&LOCK_grant); + mysql_rwlock_unlock(&LOCK_grant); DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege)); DBUG_VOID_RETURN; @@ -6943,3 +6885,104 @@ bool check_routine_level_acl(THD *thd, const char *db, const char *name, } #endif + +struct ACL_internal_schema_registry_entry +{ + const LEX_STRING *m_name; + const ACL_internal_schema_access *m_access; +}; + +/** + Internal schema registered. + Currently, this is only: + - performance_schema + - information_schema, + This can be reused later for: + - mysql +*/ +static ACL_internal_schema_registry_entry registry_array[2]; +static uint m_registry_array_size= 0; + +/** + Add an internal schema to the registry. + @param name the schema name + @param access the schema ACL specific rules +*/ +void ACL_internal_schema_registry::register_schema + (const LEX_STRING *name, const ACL_internal_schema_access *access) +{ + DBUG_ASSERT(m_registry_array_size < array_elements(registry_array)); + + /* Not thread safe, and does not need to be. */ + registry_array[m_registry_array_size].m_name= name; + registry_array[m_registry_array_size].m_access= access; + m_registry_array_size++; +} + +/** + Search per internal schema ACL by name. + @param name a schema name + @return per schema rules, or NULL +*/ +const ACL_internal_schema_access * +ACL_internal_schema_registry::lookup(const char *name) +{ + DBUG_ASSERT(name != NULL); + + uint i; + + for (i= 0; i<m_registry_array_size; i++) + { + if (my_strcasecmp(system_charset_info, registry_array[i].m_name->str, + name) == 0) + return registry_array[i].m_access; + } + return NULL; +} + +/** + Get a cached internal schema access. + @param grant_internal_info the cache + @param schema_name the name of the internal schema +*/ +const ACL_internal_schema_access * +get_cached_schema_access(GRANT_INTERNAL_INFO *grant_internal_info, + const char *schema_name) +{ + if (grant_internal_info) + { + if (! grant_internal_info->m_schema_lookup_done) + { + grant_internal_info->m_schema_access= + ACL_internal_schema_registry::lookup(schema_name); + grant_internal_info->m_schema_lookup_done= TRUE; + } + return grant_internal_info->m_schema_access; + } + return ACL_internal_schema_registry::lookup(schema_name); +} + +/** + Get a cached internal table access. + @param grant_internal_info the cache + @param schema_name the name of the internal schema + @param table_name the name of the internal table +*/ +const ACL_internal_table_access * +get_cached_table_access(GRANT_INTERNAL_INFO *grant_internal_info, + const char *schema_name, + const char *table_name) +{ + DBUG_ASSERT(grant_internal_info); + if (! grant_internal_info->m_table_lookup_done) + { + const ACL_internal_schema_access *schema_access; + schema_access= get_cached_schema_access(grant_internal_info, schema_name); + if (schema_access) + grant_internal_info->m_table_access= schema_access->lookup(table_name); + grant_internal_info->m_table_lookup_done= TRUE; + } + return grant_internal_info->m_table_access; +} + + |