diff options
Diffstat (limited to 'sql/sql_acl.cc')
-rw-r--r-- | sql/sql_acl.cc | 384 |
1 files changed, 261 insertions, 123 deletions
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index da2232d1478..1e5eeec7dbc 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -261,10 +261,9 @@ my_bool acl_init(bool dont_read_acl_tables) DBUG_ENTER("acl_init"); acl_cache= new hash_filo(ACL_CACHE_SIZE, 0, 0, - (hash_get_key) acl_entry_get_key, - (hash_free_key) free, - lower_case_file_system ? - system_charset_info : &my_charset_bin); + (my_hash_get_key) acl_entry_get_key, + (my_hash_free_key) free, + &my_charset_utf8_bin); if (dont_read_acl_tables) { DBUG_RETURN(0); /* purecov: tested */ @@ -277,7 +276,6 @@ my_bool acl_init(bool dont_read_acl_tables) DBUG_RETURN(1); /* purecov: inspected */ thd->thread_stack= (char*) &thd; thd->store_globals(); - lex_start(thd); /* It is safe to call acl_reload() since acl_* arrays and hashes which will be freed there are global static objects and thus are initialized @@ -638,7 +636,7 @@ void acl_free(bool end) delete_dynamic(&acl_users); delete_dynamic(&acl_dbs); delete_dynamic(&acl_wild_hosts); - hash_free(&acl_check_hosts); + my_hash_free(&acl_check_hosts); if (!end) acl_cache->clear(1); /* purecov: inspected */ else @@ -714,7 +712,7 @@ my_bool acl_reload(THD *thd) old_acl_dbs=acl_dbs; old_mem=mem; delete_dynamic(&acl_wild_hosts); - hash_free(&acl_check_hosts); + my_hash_free(&acl_check_hosts); if ((return_val= acl_load(thd, tables))) { // Error. Revert to old list @@ -1429,8 +1427,8 @@ static void init_check_host(void) DBUG_ENTER("init_check_host"); VOID(my_init_dynamic_array(&acl_wild_hosts,sizeof(struct acl_host_and_ip), acl_users.elements,1)); - VOID(hash_init(&acl_check_hosts,system_charset_info,acl_users.elements,0,0, - (hash_get_key) check_get_key,0,0)); + VOID(my_hash_init(&acl_check_hosts,system_charset_info,acl_users.elements,0,0, + (my_hash_get_key) check_get_key,0,0)); if (!allow_all_hosts) { for (uint i=0 ; i < acl_users.elements ; i++) @@ -1452,8 +1450,9 @@ static void init_check_host(void) if (j == acl_wild_hosts.elements) // If new (void) push_dynamic(&acl_wild_hosts,(uchar*) &acl_user->host); } - else if (!hash_search(&acl_check_hosts,(uchar*) acl_user->host.hostname, - strlen(acl_user->host.hostname))) + else if (!my_hash_search(&acl_check_hosts,(uchar*) + acl_user->host.hostname, + strlen(acl_user->host.hostname))) { if (my_hash_insert(&acl_check_hosts,(uchar*) acl_user)) { // End of memory @@ -1480,7 +1479,7 @@ static void init_check_host(void) void rebuild_check_host(void) { delete_dynamic(&acl_wild_hosts); - hash_free(&acl_check_hosts); + my_hash_free(&acl_check_hosts); init_check_host(); } @@ -1493,8 +1492,8 @@ bool acl_check_host(const char *host, const char *ip) return 0; VOID(pthread_mutex_lock(&acl_cache->lock)); - if ((host && hash_search(&acl_check_hosts,(uchar*) host,strlen(host))) || - (ip && hash_search(&acl_check_hosts,(uchar*) ip, strlen(ip)))) + if ((host && my_hash_search(&acl_check_hosts,(uchar*) host,strlen(host))) || + (ip && my_hash_search(&acl_check_hosts,(uchar*) ip, strlen(ip)))) { VOID(pthread_mutex_unlock(&acl_cache->lock)); return 0; // Found host @@ -1879,7 +1878,7 @@ static bool test_if_create_new_users(THD *thd) sctx->priv_user, tl.db, 0); if (!(db_access & INSERT_ACL)) { - if (check_grant(thd, INSERT_ACL, &tl, 0, UINT_MAX, 1)) + if (check_grant(thd, INSERT_ACL, &tl, FALSE, UINT_MAX, TRUE)) create_new_users=0; } } @@ -2251,10 +2250,13 @@ public: ulong sort; size_t key_length; GRANT_NAME(const char *h, const char *d,const char *u, - const char *t, ulong p); - GRANT_NAME (TABLE *form); + const char *t, ulong p, bool is_routine); + GRANT_NAME (TABLE *form, bool is_routine); virtual ~GRANT_NAME() {}; virtual bool ok() { return privs != 0; } + void set_user_details(const char *h, const char *d, + const char *u, const char *t, + bool is_routine); }; @@ -2272,38 +2274,48 @@ public: }; - -GRANT_NAME::GRANT_NAME(const char *h, const char *d,const char *u, - const char *t, ulong p) - :privs(p) +void GRANT_NAME::set_user_details(const char *h, const char *d, + const char *u, const char *t, + bool is_routine) { /* Host given by user */ update_hostname(&host, strdup_root(&memex, h)); - db = strdup_root(&memex,d); + if (db != d) + { + db= strdup_root(&memex, d); + if (lower_case_table_names) + my_casedn_str(files_charset_info, db); + } user = strdup_root(&memex,u); sort= get_sort(3,host.hostname,db,user); - tname= strdup_root(&memex,t); - if (lower_case_table_names) + if (tname != t) { - my_casedn_str(files_charset_info, db); - my_casedn_str(files_charset_info, tname); + tname= strdup_root(&memex, t); + if (lower_case_table_names || is_routine) + my_casedn_str(files_charset_info, tname); } key_length= strlen(d) + strlen(u)+ strlen(t)+3; hash_key= (char*) alloc_root(&memex,key_length); strmov(strmov(strmov(hash_key,user)+1,db)+1,tname); } +GRANT_NAME::GRANT_NAME(const char *h, const char *d,const char *u, + const char *t, ulong p, bool is_routine) + :db(0), tname(0), privs(p) +{ + set_user_details(h, d, u, t, is_routine); +} GRANT_TABLE::GRANT_TABLE(const char *h, const char *d,const char *u, const char *t, ulong p, ulong c) - :GRANT_NAME(h,d,u,t,p), cols(c) + :GRANT_NAME(h,d,u,t,p, FALSE), cols(c) { - (void) hash_init2(&hash_columns,4,system_charset_info, - 0,0,0, (hash_get_key) get_key_column,0,0); + (void) my_hash_init2(&hash_columns,4,system_charset_info, + 0,0,0, (my_hash_get_key) get_key_column,0,0); } -GRANT_NAME::GRANT_NAME(TABLE *form) +GRANT_NAME::GRANT_NAME(TABLE *form, bool is_routine) { update_hostname(&host, get_field(&memex, form->field[0])); db= get_field(&memex,form->field[1]); @@ -2321,6 +2333,9 @@ GRANT_NAME::GRANT_NAME(TABLE *form) if (lower_case_table_names) { my_casedn_str(files_charset_info, db); + } + if (lower_case_table_names || is_routine) + { my_casedn_str(files_charset_info, tname); } key_length= (strlen(db) + strlen(user) + strlen(tname) + 3); @@ -2332,22 +2347,22 @@ GRANT_NAME::GRANT_NAME(TABLE *form) GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs) - :GRANT_NAME(form) + :GRANT_NAME(form, FALSE) { uchar key[MAX_KEY_LENGTH]; if (!db || !tname) { /* Wrong table row; Ignore it */ - hash_clear(&hash_columns); /* allow for destruction */ + my_hash_clear(&hash_columns); /* allow for destruction */ cols= 0; return; } cols= (ulong) form->field[7]->val_int(); cols = fix_rights_for_column(cols); - (void) hash_init2(&hash_columns,4,system_charset_info, - 0,0,0, (hash_get_key) get_key_column,0,0); + (void) my_hash_init2(&hash_columns,4,system_charset_info, + 0,0,0, (my_hash_get_key) get_key_column,0,0); if (cols) { uint key_prefix_len; @@ -2399,7 +2414,7 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs) GRANT_TABLE::~GRANT_TABLE() { - hash_free(&hash_columns); + my_hash_free(&hash_columns); } @@ -2413,7 +2428,7 @@ static uchar* get_grant_table(GRANT_NAME *buff, size_t *length, void free_grant_table(GRANT_TABLE *grant_table) { - hash_free(&grant_table->hash_columns); + my_hash_free(&grant_table->hash_columns); } @@ -2431,11 +2446,11 @@ static GRANT_NAME *name_hash_search(HASH *name_hash, HASH_SEARCH_STATE state; len = (uint) (strmov(strmov(strmov(helping,user)+1,db)+1,tname)-helping)+ 1; - for (grant_name= (GRANT_NAME*) hash_first(name_hash, (uchar*) helping, - len, &state); + for (grant_name= (GRANT_NAME*) my_hash_first(name_hash, (uchar*) helping, + len, &state); grant_name ; - grant_name= (GRANT_NAME*) hash_next(name_hash,(uchar*) helping, - len, &state)) + grant_name= (GRANT_NAME*) my_hash_next(name_hash,(uchar*) helping, + len, &state)) { if (exact) { @@ -2479,7 +2494,8 @@ table_hash_search(const char *host, const char *ip, const char *db, inline GRANT_COLUMN * column_hash_search(GRANT_TABLE *t, const char *cname, uint length) { - return (GRANT_COLUMN*) hash_search(&t->hash_columns, (uchar*) cname,length); + return (GRANT_COLUMN*) my_hash_search(&t->hash_columns, + (uchar*) cname, length); } @@ -2659,7 +2675,7 @@ static int replace_column_table(GRANT_TABLE *g_t, goto end; /* purecov: deadcode */ } if (grant_column) - hash_delete(&g_t->hash_columns,(uchar*) grant_column); + my_hash_delete(&g_t->hash_columns,(uchar*) grant_column); } } } while (!table->file->index_next(table->record[0]) && @@ -2785,7 +2801,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, } else { - hash_delete(&column_priv_hash,(uchar*) grant_table); + my_hash_delete(&column_priv_hash,(uchar*) grant_table); } DBUG_RETURN(0); @@ -2906,7 +2922,8 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name, } else { - hash_delete(is_proc ? &proc_priv_hash : &func_priv_hash,(uchar*) grant_name); + my_hash_delete(is_proc ? &proc_priv_hash : &func_priv_hash,(uchar*) + grant_name); } DBUG_RETURN(0); @@ -3147,8 +3164,8 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, column_priv= 0; for (uint idx=0 ; idx < grant_table->hash_columns.records ; idx++) { - grant_column= (GRANT_COLUMN*) hash_element(&grant_table->hash_columns, - idx); + grant_column= (GRANT_COLUMN*) + my_hash_element(&grant_table->hash_columns, idx); grant_column->rights&= ~rights; // Fix other columns column_priv|= grant_column->rights; } @@ -3184,7 +3201,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, if (!result) /* success */ { - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } rw_unlock(&LOCK_grant); @@ -3327,7 +3344,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, } grant_name= new GRANT_NAME(Str->host.str, db_name, Str->user.str, table_name, - rights); + rights, TRUE); if (!grant_name) { result= TRUE; @@ -3349,7 +3366,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, if (write_to_binlog) { - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } rw_unlock(&LOCK_grant); @@ -3461,7 +3478,7 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list, if (!result) { - write_bin_log(thd, TRUE, thd->query, thd->query_length); + write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } rw_unlock(&LOCK_grant); @@ -3479,9 +3496,9 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list, void grant_free(void) { DBUG_ENTER("grant_free"); - hash_free(&column_priv_hash); - hash_free(&proc_priv_hash); - hash_free(&func_priv_hash); + my_hash_free(&column_priv_hash); + my_hash_free(&proc_priv_hash); + my_hash_free(&func_priv_hash); free_root(&memex,MYF(0)); DBUG_VOID_RETURN; } @@ -3506,7 +3523,6 @@ my_bool grant_init() DBUG_RETURN(1); /* purecov: deadcode */ thd->thread_stack= (char*) &thd; thd->store_globals(); - lex_start(thd); return_val= grant_reload(thd); delete thd; /* Remember that we don't have a THD */ @@ -3538,12 +3554,12 @@ static my_bool grant_load_procs_priv(TABLE *p_table) MEM_ROOT **save_mem_root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**, THR_MALLOC); DBUG_ENTER("grant_load_procs_priv"); - (void) hash_init(&proc_priv_hash,system_charset_info, - 0,0,0, (hash_get_key) get_grant_table, - 0,0); - (void) hash_init(&func_priv_hash,system_charset_info, - 0,0,0, (hash_get_key) get_grant_table, - 0,0); + (void) my_hash_init(&proc_priv_hash, &my_charset_utf8_bin, + 0,0,0, (my_hash_get_key) get_grant_table, + 0,0); + (void) my_hash_init(&func_priv_hash, &my_charset_utf8_bin, + 0,0,0, (my_hash_get_key) get_grant_table, + 0,0); p_table->file->ha_index_init(0, 1); p_table->use_all_columns(); @@ -3555,7 +3571,7 @@ static my_bool grant_load_procs_priv(TABLE *p_table) { GRANT_NAME *mem_check; HASH *hash; - if (!(mem_check=new (memex_ptr) GRANT_NAME(p_table))) + if (!(mem_check=new (memex_ptr) GRANT_NAME(p_table, TRUE))) { /* This could only happen if we are out memory */ goto end_unlock; @@ -3639,9 +3655,9 @@ static my_bool grant_load(THD *thd, TABLE_LIST *tables) thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH; - (void) hash_init(&column_priv_hash,system_charset_info, - 0,0,0, (hash_get_key) get_grant_table, - (hash_free_key) free_grant_table,0); + (void) my_hash_init(&column_priv_hash, &my_charset_utf8_bin, + 0,0,0, (my_hash_get_key) get_grant_table, + (my_hash_free_key) free_grant_table,0); t_table = tables[0].table; c_table = tables[1].table; @@ -3744,8 +3760,8 @@ static my_bool grant_reload_procs_priv(THD *thd) } else { - hash_free(&old_proc_priv_hash); - hash_free(&old_func_priv_hash); + my_hash_free(&old_proc_priv_hash); + my_hash_free(&old_func_priv_hash); } rw_unlock(&LOCK_grant); @@ -3814,7 +3830,7 @@ my_bool grant_reload(THD *thd) } else { - hash_free(&old_column_priv_hash); + my_hash_free(&old_column_priv_hash); free_root(&old_mem,MYF(0)); } rw_unlock(&LOCK_grant); @@ -3835,40 +3851,52 @@ end: DBUG_RETURN(return_val); } -/**************************************************************************** - Check table level grants - SYNOPSIS - bool check_grant() - thd Thread handler - want_access Bits of privileges user needs to have - tables List of tables to check. The user should have 'want_access' - to all tables in list. - show_table <> 0 if we are in show table. In this case it's enough to have - any privilege for the table - number Check at most this number of tables. - no_errors If 0 then we write an error. The error is sent directly to - the client +/** + @brief Check table level grants - RETURN - 0 ok - 1 Error: User did not have the requested privileges + @param thd Thread handler + @param want_access Bits of privileges user needs to have. + @param tables List of tables to check. The user should have + 'want_access' to all tables in list. + @param any_combination_will_do TRUE if it's enough to have any privilege for + any combination of the table columns. + @param number Check at most this number of tables. + @param no_errors TRUE if no error should be sent directly to the client. - NOTE - This functions assumes that either number of tables to be inspected + If table->grant.want_privilege != 0 then the requested privileges where + in the set of COL_ACLS but access was not granted on the table level. As + a consequence an extra check of column privileges is required. + + Specifically if this function returns FALSE the user has some kind of + privilege on a combination of columns in each table. + + This function is usually preceeded by check_access which establish the + User-, Db- and Host access rights. + + @see check_access + @see check_table_access + + @note This functions assumes that either number of tables to be inspected by it is limited explicitly (i.e. is is not UINT_MAX) or table list used and thd->lex->query_tables_own_last value correspond to each other (the latter should be either 0 or point to next_global member of one of elements of this table list). -****************************************************************************/ + + @return Access status + @retval FALSE Access granted; But column privileges might need to be + checked. + @retval TRUE The user did not have the requested privileges on any of the + tables. + +*/ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, - uint show_table, uint number, bool no_errors) + bool any_combination_will_do, uint number, bool no_errors) { 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); @@ -3886,7 +3914,10 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, i < number && table != first_not_own_table; table= table->next_global, i++) { - /* Remove SHOW_VIEW_ACL, because it will be checked during making view */ + /* + Save a copy of the privileges without the SHOW_VIEW_ACL attribute. + It will be checked during making view. + */ table->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL); } @@ -3899,7 +3930,6 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, sctx = test(table->security_ctx) ? table->security_ctx : thd->security_ctx; - want_access= orig_want_access; want_access&= ~sctx->master_access; if (!want_access) continue; // ok @@ -3929,8 +3959,13 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, want_access &= ~table->grant.privilege; goto err; // No grants } - if (show_table) - continue; // We have some priv on this + + /* + For SHOW COLUMNS, SHOW INDEX it is enough to have some + privileges on any column combination on the table. + */ + if (any_combination_will_do) + continue; table->grant.grant_table=grant_table; // Remember for column test table->grant.version=grant_version; @@ -3948,7 +3983,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, } } rw_unlock(&LOCK_grant); - DBUG_RETURN(0); + DBUG_RETURN(FALSE); err: rw_unlock(&LOCK_grant); @@ -3962,7 +3997,97 @@ err: sctx->host_or_ip, table ? table->get_table_name() : "unknown"); } - DBUG_RETURN(1); + DBUG_RETURN(TRUE); +} + + +/** + 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; } @@ -4209,7 +4334,7 @@ static bool check_grant_db_routine(THD *thd, const char *db, HASH *hash) for (uint idx= 0; idx < hash->records; ++idx) { - GRANT_NAME *item= (GRANT_NAME*) hash_element(hash, idx); + GRANT_NAME *item= (GRANT_NAME*) my_hash_element(hash, idx); if (strcmp(item->user, sctx->priv_user) == 0 && strcmp(item->db, db) == 0 && @@ -4242,8 +4367,9 @@ bool check_grant_db(THD *thd,const char *db) for (uint idx=0 ; idx < column_priv_hash.records ; idx++) { - GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&column_priv_hash, - idx); + GRANT_TABLE *grant_table= (GRANT_TABLE*) + my_hash_element(&column_priv_hash, + idx); if (len < grant_table->key_length && !memcmp(grant_table->hash_key,helping,len) && compare_hostname(&grant_table->host, sctx->host, sctx->ip)) @@ -4466,13 +4592,13 @@ static const char *command_array[]= "ALTER", "SHOW DATABASES", "SUPER", "CREATE TEMPORARY TABLES", "LOCK TABLES", "EXECUTE", "REPLICATION SLAVE", "REPLICATION CLIENT", "CREATE VIEW", "SHOW VIEW", "CREATE ROUTINE", "ALTER ROUTINE", - "CREATE USER", "EVENT", "TRIGGER" + "CREATE USER", "EVENT", "TRIGGER", "CREATE TABLESPACE" }; static uint command_lengths[]= { 6, 6, 6, 6, 6, 4, 6, 8, 7, 4, 5, 10, 5, 5, 14, 5, 23, 11, 7, 17, 18, 11, 9, - 14, 13, 11, 5, 7 + 14, 13, 11, 5, 7, 17 }; @@ -4527,7 +4653,7 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) strxmov(buff,"Grants for ",lex_user->user.str,"@", lex_user->host.str,NullS); field_list.push_back(field); - if (protocol->send_fields(&field_list, + if (protocol->send_result_set_metadata(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) { VOID(pthread_mutex_unlock(&acl_cache->lock)); @@ -4715,8 +4841,8 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) for (index=0 ; index < column_priv_hash.records ; index++) { const char *user, *host; - GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&column_priv_hash, - index); + GRANT_TABLE *grant_table= (GRANT_TABLE*) + my_hash_element(&column_priv_hash, index); if (!(user=grant_table->user)) user= ""; @@ -4769,7 +4895,7 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) col_index++) { GRANT_COLUMN *grant_column = (GRANT_COLUMN*) - hash_element(&grant_table->hash_columns,col_index); + my_hash_element(&grant_table->hash_columns,col_index); if (grant_column->rights & j) { if (!found_col) @@ -4859,7 +4985,7 @@ static int show_routine_grants(THD* thd, LEX_USER *lex_user, HASH *hash, for (index=0 ; index < hash->records ; index++) { const char *user, *host; - GRANT_NAME *grant_proc= (GRANT_NAME*) hash_element(hash, index); + GRANT_NAME *grant_proc= (GRANT_NAME*) my_hash_element(hash, index); if (!(user=grant_proc->user)) user= ""; @@ -5372,13 +5498,13 @@ static int handle_grant_struct(uint struct_no, bool drop, break; case 2: - grant_name= (GRANT_NAME*) hash_element(&column_priv_hash, idx); + grant_name= (GRANT_NAME*) my_hash_element(&column_priv_hash, idx); user= grant_name->user; host= grant_name->host.hostname; break; case 3: - grant_name= (GRANT_NAME*) hash_element(&proc_priv_hash, idx); + grant_name= (GRANT_NAME*) my_hash_element(&proc_priv_hash, idx); user= grant_name->user; host= grant_name->host.hostname; break; @@ -5411,11 +5537,11 @@ static int handle_grant_struct(uint struct_no, bool drop, break; case 2: - hash_delete(&column_priv_hash, (uchar*) grant_name); + my_hash_delete(&column_priv_hash, (uchar*) grant_name); break; case 3: - hash_delete(&proc_priv_hash, (uchar*) grant_name); + my_hash_delete(&proc_priv_hash, (uchar*) grant_name); break; } elements--; @@ -5436,9 +5562,21 @@ static int handle_grant_struct(uint struct_no, bool drop, case 2: case 3: - grant_name->user= strdup_root(&mem, user_to->user.str); - update_hostname(&grant_name->host, - strdup_root(&mem, user_to->host.str)); + /* + Update the grant structure with the new user name and + host name + */ + grant_name->set_user_details(user_to->host.str, grant_name->db, + user_to->user.str, grant_name->tname, + TRUE); + + /* + Since username is part of the hash key, when the user name + is renamed, the hash key is changed. Update the hash to + ensure that the position matches the new hash key value + */ + my_hash_update(&column_priv_hash, (uchar*) grant_name, + (uchar*) grant_name->hash_key, grant_name->key_length); break; } } @@ -5663,7 +5801,7 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list) my_error(ER_CANNOT_USER, MYF(0), "CREATE USER", wrong_users.c_ptr_safe()); if (some_users_created) - write_bin_log(thd, FALSE, thd->query, thd->query_length); + write_bin_log(thd, FALSE, thd->query(), thd->query_length()); rw_unlock(&LOCK_grant); close_thread_tables(thd); @@ -5736,7 +5874,7 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list) my_error(ER_CANNOT_USER, MYF(0), "DROP USER", wrong_users.c_ptr_safe()); if (some_users_deleted) - write_bin_log(thd, FALSE, thd->query, thd->query_length); + write_bin_log(thd, FALSE, thd->query(), thd->query_length()); rw_unlock(&LOCK_grant); close_thread_tables(thd); @@ -5821,7 +5959,7 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list) my_error(ER_CANNOT_USER, MYF(0), "RENAME USER", wrong_users.c_ptr_safe()); if (some_users_renamed && mysql_bin_log.is_open()) - write_bin_log(thd, FALSE, thd->query, thd->query_length); + write_bin_log(thd, FALSE, thd->query(), thd->query_length()); rw_unlock(&LOCK_grant); close_thread_tables(thd); @@ -5929,8 +6067,8 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list) for (counter= 0, revoked= 0 ; counter < column_priv_hash.records ; ) { const char *user,*host; - GRANT_TABLE *grant_table= (GRANT_TABLE*)hash_element(&column_priv_hash, - counter); + GRANT_TABLE *grant_table= + (GRANT_TABLE*) my_hash_element(&column_priv_hash, counter); if (!(user=grant_table->user)) user= ""; if (!(host=grant_table->host.hostname)) @@ -5976,7 +6114,7 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list) for (counter= 0, revoked= 0 ; counter < hash->records ; ) { const char *user,*host; - GRANT_NAME *grant_proc= (GRANT_NAME*) hash_element(hash, counter); + GRANT_NAME *grant_proc= (GRANT_NAME*) my_hash_element(hash, counter); if (!(user=grant_proc->user)) user= ""; if (!(host=grant_proc->host.hostname)) @@ -6003,7 +6141,7 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list) VOID(pthread_mutex_unlock(&acl_cache->lock)); - write_bin_log(thd, FALSE, thd->query, thd->query_length); + write_bin_log(thd, FALSE, thd->query(), thd->query_length()); rw_unlock(&LOCK_grant); close_thread_tables(thd); @@ -6124,8 +6262,8 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name, { for (counter= 0, revoked= 0 ; counter < hash->records ; ) { - GRANT_NAME *grant_proc= (GRANT_NAME*) hash_element(hash, counter); - if (!my_strcasecmp(system_charset_info, grant_proc->db, sp_db) && + GRANT_NAME *grant_proc= (GRANT_NAME*) my_hash_element(hash, counter); + if (!my_strcasecmp(&my_charset_utf8_bin, grant_proc->db, sp_db) && !my_strcasecmp(system_charset_info, grant_proc->tname, sp_name)) { LEX_USER lex_user; @@ -6515,7 +6653,7 @@ int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond) for (index=0 ; index < column_priv_hash.records ; index++) { const char *user, *host, *is_grantable= "YES"; - GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&column_priv_hash, + GRANT_TABLE *grant_table= (GRANT_TABLE*) my_hash_element(&column_priv_hash, index); if (!(user=grant_table->user)) user= ""; @@ -6598,7 +6736,7 @@ int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond) for (index=0 ; index < column_priv_hash.records ; index++) { const char *user, *host, *is_grantable= "YES"; - GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&column_priv_hash, + GRANT_TABLE *grant_table= (GRANT_TABLE*) my_hash_element(&column_priv_hash, index); if (!(user=grant_table->user)) user= ""; @@ -6633,7 +6771,7 @@ int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond) col_index++) { GRANT_COLUMN *grant_column = (GRANT_COLUMN*) - hash_element(&grant_table->hash_columns,col_index); + my_hash_element(&grant_table->hash_columns,col_index); if ((grant_column->rights & j) && (table_access & j)) { if (update_schema_privilege(thd, table, buff, grant_table->db, |