summaryrefslogtreecommitdiff
path: root/sql/sql_acl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_acl.cc')
-rw-r--r--sql/sql_acl.cc1209
1 files changed, 771 insertions, 438 deletions
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 7592986ef81..0b33abcfba2 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -26,16 +26,131 @@
#include "mysql_priv.h"
#include "hash_filo.h"
-#ifdef HAVE_REPLICATION
-#include "sql_repl.h" //for tables_ok()
-#endif
#include <m_ctype.h>
#include <stdarg.h>
#include "sp_head.h"
#include "sp.h"
+time_t mysql_db_table_last_check= 0L;
+
+TABLE_FIELD_W_TYPE mysql_db_table_fields[MYSQL_DB_FIELD_COUNT] = {
+ {
+ { C_STRING_WITH_LEN("Host") },
+ { C_STRING_WITH_LEN("char(60)") },
+ {NULL, 0}
+ },
+ {
+ { C_STRING_WITH_LEN("Db") },
+ { C_STRING_WITH_LEN("char(64)") },
+ {NULL, 0}
+ },
+ {
+ { C_STRING_WITH_LEN("User") },
+ { C_STRING_WITH_LEN("char(16)") },
+ {NULL, 0}
+ },
+ {
+ { C_STRING_WITH_LEN("Select_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Insert_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Update_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Delete_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Create_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Drop_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Grant_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("References_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Index_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Alter_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Create_tmp_table_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Lock_tables_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Create_view_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Show_view_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Create_routine_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Alter_routine_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Execute_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Event_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ },
+ {
+ { C_STRING_WITH_LEN("Trigger_priv") },
+ { C_STRING_WITH_LEN("enum('N','Y')") },
+ { C_STRING_WITH_LEN("utf8") }
+ }
+};
+
+
#ifndef NO_EMBEDDED_ACCESS_CHECKS
+#define FIRST_NON_YN_FIELD 26
+
class acl_entry :public hash_filo_element
{
public:
@@ -45,11 +160,11 @@ public:
};
-static byte* acl_entry_get_key(acl_entry *entry,uint *length,
- my_bool not_used __attribute__((unused)))
+static uchar* acl_entry_get_key(acl_entry *entry, size_t *length,
+ my_bool not_used __attribute__((unused)))
{
*length=(uint) entry->length;
- return (byte*) entry->key;
+ return (uchar*) entry->key;
}
#define IP_ADDR_STRLEN (3+1+3+1+3+1+3)
@@ -77,7 +192,7 @@ static void update_hostname(acl_host_and_ip *host, const char *hostname);
static bool compare_hostname(const acl_host_and_ip *host,const char *hostname,
const char *ip);
static my_bool acl_load(THD *thd, TABLE_LIST *tables);
-static my_bool grant_load(TABLE_LIST *tables);
+static my_bool grant_load(THD *thd, TABLE_LIST *tables);
/*
Convert scrambled password to binary form, according to scramble type,
@@ -162,6 +277,7 @@ 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
@@ -198,14 +314,18 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE;
char tmp_name[NAME_LEN+1];
int password_length;
+ ulong old_sql_mode= thd->variables.sql_mode;
DBUG_ENTER("acl_load");
+ thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH;
+
grant_version++; /* Privileges updated */
acl_cache->clear(1); // Clear locked hostname cache
init_sql_alloc(&mem, ACL_ALLOC_BLOCK_SIZE, 0);
init_read_record(&read_record_info,thd,table= tables[0].table,NULL,1,0);
+ table->use_all_columns();
VOID(my_init_dynamic_array(&acl_hosts,sizeof(ACL_HOST),20,50));
while (!(read_record_info.read_record(&read_record_info)))
{
@@ -246,14 +366,15 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
host.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL | CREATE_TMP_ACL;
}
#endif
- VOID(push_dynamic(&acl_hosts,(gptr) &host));
+ VOID(push_dynamic(&acl_hosts,(uchar*) &host));
}
- my_qsort((gptr) dynamic_element(&acl_hosts,0,ACL_HOST*),acl_hosts.elements,
- sizeof(ACL_HOST),(qsort_cmp) acl_compare);
+ my_qsort((uchar*) dynamic_element(&acl_hosts,0,ACL_HOST*),acl_hosts.elements,
+ sizeof(ACL_HOST),(qsort_cmp) acl_compare);
end_read_record(&read_record_info);
freeze_size(&acl_hosts);
init_read_record(&read_record_info,thd,table=tables[1].table,NULL,1,0);
+ table->use_all_columns();
VOID(my_init_dynamic_array(&acl_users,sizeof(ACL_USER),50,100));
password_length= table->field[2]->field_length /
table->field[2]->charset()->mbmaxlen;
@@ -357,6 +478,20 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
if (table->s->fields <= 36 && (user.access & GRANT_ACL))
user.access|= CREATE_USER_ACL;
+
+ /*
+ if it is pre 5.1.6 privilege table then map CREATE privilege on
+ CREATE|ALTER|DROP|EXECUTE EVENT
+ */
+ if (table->s->fields <= 37 && (user.access & SUPER_ACL))
+ user.access|= EVENT_ACL;
+
+ /*
+ if it is pre 5.1.6 privilege then map TRIGGER privilege on CREATE.
+ */
+ if (table->s->fields <= 38 && (user.access & SUPER_ACL))
+ user.access|= TRIGGER_ACL;
+
user.sort= get_sort(2,user.host.hostname,user.user);
user.hostname_length= (user.host.hostname ?
(uint) strlen(user.host.hostname) : 0);
@@ -415,30 +550,31 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
user.access|= SUPER_ACL | EXECUTE_ACL;
#endif
}
- VOID(push_dynamic(&acl_users,(gptr) &user));
+ VOID(push_dynamic(&acl_users,(uchar*) &user));
if (!user.host.hostname ||
(user.host.hostname[0] == wild_many && !user.host.hostname[1]))
allow_all_hosts=1; // Anyone can connect
}
}
- my_qsort((gptr) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements,
- sizeof(ACL_USER),(qsort_cmp) acl_compare);
+ my_qsort((uchar*) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements,
+ sizeof(ACL_USER),(qsort_cmp) acl_compare);
end_read_record(&read_record_info);
freeze_size(&acl_users);
init_read_record(&read_record_info,thd,table=tables[2].table,NULL,1,0);
+ table->use_all_columns();
VOID(my_init_dynamic_array(&acl_dbs,sizeof(ACL_DB),50,100));
while (!(read_record_info.read_record(&read_record_info)))
{
ACL_DB db;
- update_hostname(&db.host,get_field(&mem, table->field[0]));
- db.db=get_field(&mem, table->field[1]);
+ update_hostname(&db.host,get_field(&mem, table->field[MYSQL_DB_FIELD_HOST]));
+ db.db=get_field(&mem, table->field[MYSQL_DB_FIELD_DB]);
if (!db.db)
{
sql_print_warning("Found an entry in the 'db' table with empty database name; Skipped");
continue;
}
- db.user=get_field(&mem, table->field[2]);
+ db.user=get_field(&mem, table->field[MYSQL_DB_FIELD_USER]);
if (check_no_resolve && hostname_requires_resolving(db.host.hostname))
{
sql_print_warning("'db' entry '%s %s@%s' "
@@ -477,10 +613,10 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
db.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL;
}
#endif
- VOID(push_dynamic(&acl_dbs,(gptr) &db));
+ VOID(push_dynamic(&acl_dbs,(uchar*) &db));
}
- my_qsort((gptr) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements,
- sizeof(ACL_DB),(qsort_cmp) acl_compare);
+ my_qsort((uchar*) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements,
+ sizeof(ACL_DB),(qsort_cmp) acl_compare);
end_read_record(&read_record_info);
freeze_size(&acl_dbs);
init_check_host();
@@ -489,6 +625,7 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
return_val=0;
end:
+ thd->variables.sql_mode= old_sql_mode;
DBUG_RETURN(return_val);
}
@@ -558,11 +695,13 @@ my_bool acl_reload(THD *thd)
tables[0].next_local= tables[0].next_global= tables+1;
tables[1].next_local= tables[1].next_global= tables+2;
tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_READ;
+ tables[0].skip_temporary= tables[1].skip_temporary=
+ tables[2].skip_temporary= TRUE;
if (simple_open_n_lock_tables(thd, tables))
{
sql_print_error("Fatal error: Can't open and lock privilege tables: %s",
- thd->net.last_error);
+ thd->main_da.message());
goto end;
}
@@ -628,7 +767,7 @@ static ulong get_access(TABLE *form, uint fieldnr, uint *next_field)
Field **pos;
for (pos=form->field+fieldnr, bit=1;
- *pos && (*pos)->real_type() == FIELD_TYPE_ENUM &&
+ *pos && (*pos)->real_type() == MYSQL_TYPE_ENUM &&
((Field_enum*) (*pos))->typelib->count == 2 ;
pos++, fieldnr++, bit<<=1)
{
@@ -1023,11 +1162,11 @@ bool acl_getroot_no_password(Security_context *sctx, char *user, char *host,
DBUG_RETURN(res);
}
-static byte* check_get_key(ACL_USER *buff,uint *length,
- my_bool not_used __attribute__((unused)))
+static uchar* check_get_key(ACL_USER *buff, size_t *length,
+ my_bool not_used __attribute__((unused)))
{
*length=buff->hostname_length;
- return (byte*) buff->host.hostname;
+ return (uchar*) buff->host.hostname;
}
@@ -1108,12 +1247,12 @@ static void acl_insert_user(const char *user, const char *host,
set_user_salt(&acl_user, password, password_len);
- VOID(push_dynamic(&acl_users,(gptr) &acl_user));
+ VOID(push_dynamic(&acl_users,(uchar*) &acl_user));
if (!acl_user.host.hostname ||
(acl_user.host.hostname[0] == wild_many && !acl_user.host.hostname[1]))
allow_all_hosts=1; // Anyone can connect /* purecov: tested */
- my_qsort((gptr) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements,
- sizeof(ACL_USER),(qsort_cmp) acl_compare);
+ my_qsort((uchar*) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements,
+ sizeof(ACL_USER),(qsort_cmp) acl_compare);
/* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */
rebuild_check_host();
@@ -1174,9 +1313,9 @@ static void acl_insert_db(const char *user, const char *host, const char *db,
acl_db.db=strdup_root(&mem,db);
acl_db.access=privileges;
acl_db.sort=get_sort(3,acl_db.host.hostname,acl_db.db,acl_db.user);
- VOID(push_dynamic(&acl_dbs,(gptr) &acl_db));
- my_qsort((gptr) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements,
- sizeof(ACL_DB),(qsort_cmp) acl_compare);
+ VOID(push_dynamic(&acl_dbs,(uchar*) &acl_db));
+ my_qsort((uchar*) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements,
+ sizeof(ACL_DB),(qsort_cmp) acl_compare);
}
@@ -1192,7 +1331,8 @@ ulong acl_get(const char *host, const char *ip,
const char *user, const char *db, my_bool db_is_pattern)
{
ulong host_access= ~(ulong)0, db_access= 0;
- uint i,key_length;
+ uint i;
+ size_t key_length;
char key[ACL_KEY_LENGTH],*tmp_db,*end;
acl_entry *entry;
DBUG_ENTER("acl_get");
@@ -1204,8 +1344,9 @@ ulong acl_get(const char *host, const char *ip,
my_casedn_str(files_charset_info, tmp_db);
db=tmp_db;
}
- key_length=(uint) (end-key);
- if (!db_is_pattern && (entry=(acl_entry*) acl_cache->search(key,key_length)))
+ key_length= (size_t) (end-key);
+ if (!db_is_pattern && (entry=(acl_entry*) acl_cache->search((uchar*) key,
+ key_length)))
{
db_access=entry->access;
VOID(pthread_mutex_unlock(&acl_cache->lock));
@@ -1259,7 +1400,7 @@ exit:
{
entry->access=(db_access & host_access);
entry->length=key_length;
- memcpy((gptr) entry->key,key,key_length);
+ memcpy((uchar*) entry->key,key,key_length);
acl_cache->add(entry);
}
VOID(pthread_mutex_unlock(&acl_cache->lock));
@@ -1301,12 +1442,12 @@ static void init_check_host(void)
break; // already stored
}
if (j == acl_wild_hosts.elements) // If new
- (void) push_dynamic(&acl_wild_hosts,(char*) &acl_user->host);
+ (void) push_dynamic(&acl_wild_hosts,(uchar*) &acl_user->host);
}
- else if (!hash_search(&acl_check_hosts,(byte*) acl_user->host.hostname,
- (uint) strlen(acl_user->host.hostname)))
+ else if (!hash_search(&acl_check_hosts,(uchar*) acl_user->host.hostname,
+ strlen(acl_user->host.hostname)))
{
- if (my_hash_insert(&acl_check_hosts,(byte*) acl_user))
+ if (my_hash_insert(&acl_check_hosts,(uchar*) acl_user))
{ // End of memory
allow_all_hosts=1; // Should never happen
DBUG_VOID_RETURN;
@@ -1344,8 +1485,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,(byte*) host,(uint) strlen(host)) ||
- ip && hash_search(&acl_check_hosts,(byte*) ip,(uint) strlen(ip)))
+ if (host && hash_search(&acl_check_hosts,(uchar*) host,strlen(host)) ||
+ ip && hash_search(&acl_check_hosts,(uchar*) ip, strlen(ip)))
{
VOID(pthread_mutex_unlock(&acl_cache->lock));
return 0; // Found host
@@ -1404,7 +1545,7 @@ int check_change_password(THD *thd, const char *host, const char *user,
MYF(0));
return(1);
}
- uint len=strlen(new_password);
+ size_t len= strlen(new_password);
if (len && len != SCRAMBLED_PASSWORD_CHAR_LENGTH &&
len != SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
{
@@ -1438,7 +1579,7 @@ bool change_password(THD *thd, const char *host, const char *user,
/* Buffer should be extended when password length is extended. */
char buff[512];
ulong query_length;
- uint new_password_len= strlen(new_password);
+ uint new_password_len= (uint) strlen(new_password);
bool result= 1;
DBUG_ENTER("change_password");
DBUG_PRINT("enter",("host: '%s' user: '%s' new_password: '%s'",
@@ -1457,7 +1598,7 @@ bool change_password(THD *thd, const char *host, const char *user,
GRANT and REVOKE are applied the slave in/exclusion rules as they are
some kind of updates to the mysql.% tables.
*/
- if (thd->slave_thread && table_rules_on)
+ if (thd->slave_thread && rpl_filter->is_on())
{
/*
The tables must be marked "updating" so that tables_ok() takes them into
@@ -1465,12 +1606,12 @@ bool change_password(THD *thd, const char *host, const char *user,
*/
tables.updating= 1;
/* Thanks to bzero, tables.next==0 */
- if (!tables_ok(thd, &tables))
+ if (!(thd->spcont || rpl_filter->tables_ok(0, &tables)))
DBUG_RETURN(0);
}
#endif
- if (!(table= open_ltable(thd, &tables, TL_WRITE)))
+ if (!(table= open_ltable(thd, &tables, TL_WRITE, 0)))
DBUG_RETURN(1);
VOID(pthread_mutex_lock(&acl_cache->lock));
@@ -1505,8 +1646,7 @@ bool change_password(THD *thd, const char *host, const char *user,
acl_user->host.hostname ? acl_user->host.hostname : "",
new_password));
thd->clear_error();
- Query_log_event qinfo(thd, buff, query_length, 0, FALSE);
- mysql_bin_log.write(&qinfo);
+ thd->binlog_query(THD::MYSQL_QUERY_TYPE, buff, query_length, FALSE, FALSE);
}
end:
close_thread_tables(thd);
@@ -1640,8 +1780,8 @@ bool hostname_requires_resolving(const char *hostname)
char cur;
if (!hostname)
return FALSE;
- int namelen= strlen(hostname);
- int lhlen= strlen(my_localhost);
+ size_t namelen= strlen(hostname);
+ size_t lhlen= strlen(my_localhost);
if ((namelen == lhlen) &&
!my_strnncoll(system_charset_info, (const uchar *)hostname, namelen,
(const uchar *)my_localhost, strlen(my_localhost)))
@@ -1678,15 +1818,15 @@ static bool update_user_table(THD *thd, TABLE *table,
DBUG_ENTER("update_user_table");
DBUG_PRINT("enter",("user: %s host: %s",user,host));
+ table->use_all_columns();
table->field[0]->store(host,(uint) strlen(host), system_charset_info);
table->field[1]->store(user,(uint) strlen(user), system_charset_info);
- key_copy((byte *) user_key, table->record[0], table->key_info,
+ key_copy((uchar *) user_key, table->record[0], table->key_info,
table->key_info->key_length);
- table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
- if (table->file->index_read_idx(table->record[0], 0,
- (byte *) user_key, table->key_info->key_length,
- HA_READ_KEY_EXACT))
+ if (table->file->index_read_idx_map(table->record[0], 0,
+ (uchar *) user_key, HA_WHOLE_KEY,
+ HA_READ_KEY_EXACT))
{
my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH),
MYF(0)); /* purecov: deadcode */
@@ -1694,7 +1834,8 @@ static bool update_user_table(THD *thd, TABLE *table,
}
store_record(table,record[1]);
table->field[2]->store(new_password, new_password_len, system_charset_info);
- if ((error=table->file->update_row(table->record[1],table->record[0])))
+ if ((error=table->file->ha_update_row(table->record[1],table->record[0])) &&
+ error != HA_ERR_RECORD_IS_THE_SAME)
{
table->file->print_error(error,MYF(0)); /* purecov: deadcode */
DBUG_RETURN(1);
@@ -1750,7 +1891,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
const char *password= "";
uint password_len= 0;
char what= (revoke_grant) ? 'N' : 'Y';
- byte user_key[MAX_KEY_LENGTH];
+ uchar user_key[MAX_KEY_LENGTH];
LEX *lex= thd->lex;
DBUG_ENTER("replace_user_table");
@@ -1768,15 +1909,17 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
password=combo.password.str;
}
- table->field[0]->store(combo.host.str,combo.host.length, system_charset_info);
- table->field[1]->store(combo.user.str,combo.user.length, system_charset_info);
+ table->use_all_columns();
+ table->field[0]->store(combo.host.str,combo.host.length,
+ system_charset_info);
+ table->field[1]->store(combo.user.str,combo.user.length,
+ system_charset_info);
key_copy(user_key, table->record[0], table->key_info,
table->key_info->key_length);
- table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
- if (table->file->index_read_idx(table->record[0], 0,
- user_key, table->key_info->key_length,
- HA_READ_KEY_EXACT))
+ if (table->file->index_read_idx_map(table->record[0], 0, user_key,
+ HA_WHOLE_KEY,
+ HA_READ_KEY_EXACT))
{
/* what == 'N' means revoke */
if (what == 'N')
@@ -1837,7 +1980,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
ulong priv;
uint next_field;
for (tmp_field= table->field+3, priv = SELECT_ACL;
- *tmp_field && (*tmp_field)->real_type() == FIELD_TYPE_ENUM &&
+ *tmp_field && (*tmp_field)->real_type() == MYSQL_TYPE_ENUM &&
((Field_enum*) (*tmp_field))->typelib->count == 2 ;
tmp_field++, priv <<= 1)
{
@@ -1909,19 +2052,23 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
We should NEVER delete from the user table, as a uses can still
use mysqld even if he doesn't have any privileges in the user table!
*/
- table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
- if (cmp_record(table,record[1]) &&
- (error=table->file->update_row(table->record[1],table->record[0])))
- { // This should never happen
- table->file->print_error(error,MYF(0)); /* purecov: deadcode */
- error= -1; /* purecov: deadcode */
- goto end; /* purecov: deadcode */
+ if (cmp_record(table,record[1]))
+ {
+ if ((error=
+ table->file->ha_update_row(table->record[1],table->record[0])) &&
+ error != HA_ERR_RECORD_IS_THE_SAME)
+ { // This should never happen
+ table->file->print_error(error,MYF(0)); /* purecov: deadcode */
+ error= -1; /* purecov: deadcode */
+ goto end; /* purecov: deadcode */
+ }
+ else
+ error= 0;
}
}
- else if ((error=table->file->write_row(table->record[0]))) // insert
+ else if ((error=table->file->ha_write_row(table->record[0]))) // insert
{ // This should never happen
- if (error && error != HA_ERR_FOUND_DUPP_KEY &&
- error != HA_ERR_FOUND_DUPP_UNIQUE) /* purecov: inspected */
+ if (table->file->is_fatal_error(error, HA_CHECK_DUP))
{
table->file->print_error(error,MYF(0)); /* purecov: deadcode */
error= -1; /* purecov: deadcode */
@@ -1969,7 +2116,7 @@ static int replace_db_table(TABLE *table, const char *db,
bool old_row_exists=0;
int error;
char what= (revoke_grant) ? 'N' : 'Y';
- byte user_key[MAX_KEY_LENGTH];
+ uchar user_key[MAX_KEY_LENGTH];
DBUG_ENTER("replace_db_table");
if (!initialized)
@@ -1985,16 +2132,18 @@ static int replace_db_table(TABLE *table, const char *db,
DBUG_RETURN(-1);
}
- table->field[0]->store(combo.host.str,combo.host.length, system_charset_info);
+ table->use_all_columns();
+ table->field[0]->store(combo.host.str,combo.host.length,
+ system_charset_info);
table->field[1]->store(db,(uint) strlen(db), system_charset_info);
- table->field[2]->store(combo.user.str,combo.user.length, system_charset_info);
+ table->field[2]->store(combo.user.str,combo.user.length,
+ system_charset_info);
key_copy(user_key, table->record[0], table->key_info,
table->key_info->key_length);
- table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
- if (table->file->index_read_idx(table->record[0],0,
- user_key, table->key_info->key_length,
- HA_READ_KEY_EXACT))
+ if (table->file->index_read_idx_map(table->record[0],0, user_key,
+ HA_WHOLE_KEY,
+ HA_READ_KEY_EXACT))
{
if (what == 'N')
{ // no row, no revoke
@@ -2003,9 +2152,11 @@ static int replace_db_table(TABLE *table, const char *db,
}
old_row_exists = 0;
restore_record(table, s->default_values);
- table->field[0]->store(combo.host.str,combo.host.length, system_charset_info);
+ table->field[0]->store(combo.host.str,combo.host.length,
+ system_charset_info);
table->field[1]->store(db,(uint) strlen(db), system_charset_info);
- table->field[2]->store(combo.user.str,combo.user.length, system_charset_info);
+ table->field[2]->store(combo.user.str,combo.user.length,
+ system_charset_info);
}
else
{
@@ -2027,19 +2178,20 @@ static int replace_db_table(TABLE *table, const char *db,
/* update old existing row */
if (rights)
{
- table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
- if ((error=table->file->update_row(table->record[1],table->record[0])))
+ if ((error= table->file->ha_update_row(table->record[1],
+ table->record[0])) &&
+ error != HA_ERR_RECORD_IS_THE_SAME)
goto table_error; /* purecov: deadcode */
}
else /* must have been a revoke of all privileges */
{
- if ((error = table->file->delete_row(table->record[1])))
+ if ((error= table->file->ha_delete_row(table->record[1])))
goto table_error; /* purecov: deadcode */
}
}
- else if (rights && (error=table->file->write_row(table->record[0])))
+ else if (rights && (error= table->file->ha_write_row(table->record[0])))
{
- if (error && error != HA_ERR_FOUND_DUPP_KEY) /* purecov: inspected */
+ if (table->file->is_fatal_error(error, HA_CHECK_DUP_KEY))
goto table_error; /* purecov: deadcode */
}
@@ -2068,16 +2220,16 @@ public:
uint key_length;
GRANT_COLUMN(String &c, ulong y) :rights (y)
{
- column= memdup_root(&memex,c.ptr(), key_length=c.length());
+ column= (char*) memdup_root(&memex,c.ptr(), key_length=c.length());
}
};
-static byte* get_key_column(GRANT_COLUMN *buff,uint *length,
+static uchar* get_key_column(GRANT_COLUMN *buff, size_t *length,
my_bool not_used __attribute__((unused)))
{
*length=buff->key_length;
- return (byte*) buff->column;
+ return (uchar*) buff->column;
}
@@ -2088,7 +2240,7 @@ public:
char *db, *user, *tname, *hash_key;
ulong privs;
ulong sort;
- uint key_length;
+ size_t key_length;
GRANT_NAME(const char *h, const char *d,const char *u,
const char *t, ulong p);
GRANT_NAME (TABLE *form);
@@ -2127,8 +2279,8 @@ GRANT_NAME::GRANT_NAME(const char *h, const char *d,const char *u,
my_casedn_str(files_charset_info, db);
my_casedn_str(files_charset_info, tname);
}
- key_length =(uint) strlen(d)+(uint) strlen(u)+(uint) strlen(t)+3;
- hash_key = (char*) alloc_root(&memex,key_length);
+ 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);
}
@@ -2137,7 +2289,7 @@ 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)
{
- (void) hash_init(&hash_columns,system_charset_info,
+ (void) hash_init2(&hash_columns,4,system_charset_info,
0,0,0, (hash_get_key) get_key_column,0,0);
}
@@ -2162,9 +2314,8 @@ GRANT_NAME::GRANT_NAME(TABLE *form)
my_casedn_str(files_charset_info, db);
my_casedn_str(files_charset_info, tname);
}
- key_length = ((uint) strlen(db) + (uint) strlen(user) +
- (uint) strlen(tname) + 3);
- hash_key = (char*) alloc_root(&memex,key_length);
+ key_length= (strlen(db) + strlen(user) + strlen(tname) + 3);
+ hash_key= (char*) alloc_root(&memex, key_length);
strmov(strmov(strmov(hash_key,user)+1,db)+1,tname);
privs = (ulong) form->field[6]->val_int();
privs = fix_rights_for_table(privs);
@@ -2174,7 +2325,7 @@ GRANT_NAME::GRANT_NAME(TABLE *form)
GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs)
:GRANT_NAME(form)
{
- byte key[MAX_KEY_LENGTH];
+ uchar key[MAX_KEY_LENGTH];
if (!db || !tname)
{
@@ -2186,14 +2337,15 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs)
cols= (ulong) form->field[7]->val_int();
cols = fix_rights_for_column(cols);
- (void) hash_init(&hash_columns,system_charset_info,
+ (void) hash_init2(&hash_columns,4,system_charset_info,
0,0,0, (hash_get_key) get_key_column,0,0);
if (cols)
{
uint key_prefix_len;
KEY_PART_INFO *key_part= col_privs->key_info->key_part;
col_privs->field[0]->store(host.hostname,
- host.hostname ? (uint) strlen(host.hostname) : 0,
+ host.hostname ? (uint) strlen(host.hostname) :
+ 0,
system_charset_info);
col_privs->field[1]->store(db,(uint) strlen(db), system_charset_info);
col_privs->field[2]->store(user,(uint) strlen(user), system_charset_info);
@@ -2206,10 +2358,9 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs)
key_copy(key, col_privs->record[0], col_privs->key_info, key_prefix_len);
col_privs->field[4]->store("",0, &my_charset_latin1);
- col_privs->file->ha_index_init(0);
- if (col_privs->file->index_read(col_privs->record[0],
- (byte*) key,
- key_prefix_len, HA_READ_KEY_EXACT))
+ col_privs->file->ha_index_init(0, 1);
+ if (col_privs->file->index_read_map(col_privs->record[0], (uchar*) key,
+ (key_part_map)15, HA_READ_KEY_EXACT))
{
cols = 0; /* purecov: deadcode */
col_privs->file->ha_index_end();
@@ -2229,7 +2380,7 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs)
privs = cols = 0; /* purecov: deadcode */
return; /* purecov: deadcode */
}
- my_hash_insert(&hash_columns, (byte *) mem_check);
+ my_hash_insert(&hash_columns, (uchar *) mem_check);
} while (!col_privs->file->index_next(col_privs->record[0]) &&
!key_cmp_if_same(col_privs,key,0,key_prefix_len));
col_privs->file->ha_index_end();
@@ -2243,11 +2394,11 @@ GRANT_TABLE::~GRANT_TABLE()
}
-static byte* get_grant_table(GRANT_NAME *buff,uint *length,
+static uchar* get_grant_table(GRANT_NAME *buff, size_t *length,
my_bool not_used __attribute__((unused)))
{
*length=buff->key_length;
- return (byte*) buff->hash_key;
+ return (uchar*) buff->hash_key;
}
@@ -2260,10 +2411,10 @@ void free_grant_table(GRANT_TABLE *grant_table)
/* Search after a matching grant. Prefer exact grants before not exact ones */
static GRANT_NAME *name_hash_search(HASH *name_hash,
- const char *host,const char* ip,
- const char *db,
- const char *user, const char *tname,
- bool exact)
+ const char *host,const char* ip,
+ const char *db,
+ const char *user, const char *tname,
+ bool exact)
{
char helping [NAME_LEN*2+USERNAME_LENGTH+3];
uint len;
@@ -2271,10 +2422,10 @@ 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, (byte*) helping,
+ for (grant_name= (GRANT_NAME*) hash_first(name_hash, (uchar*) helping,
len, &state);
grant_name ;
- grant_name= (GRANT_NAME*) hash_next(name_hash,(byte*) helping,
+ grant_name= (GRANT_NAME*) hash_next(name_hash,(uchar*) helping,
len, &state))
{
if (exact)
@@ -2319,7 +2470,7 @@ 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, (byte*) cname,length);
+ return (GRANT_COLUMN*) hash_search(&t->hash_columns, (uchar*) cname,length);
}
@@ -2330,11 +2481,12 @@ static int replace_column_table(GRANT_TABLE *g_t,
ulong rights, bool revoke_grant)
{
int error=0,result=0;
- byte key[MAX_KEY_LENGTH];
+ uchar key[MAX_KEY_LENGTH];
uint key_prefix_length;
KEY_PART_INFO *key_part= table->key_info->key_part;
DBUG_ENTER("replace_column_table");
+ table->use_all_columns();
table->field[0]->store(combo.host.str,combo.host.length,
system_charset_info);
table->field[1]->store(db,(uint) strlen(db),
@@ -2344,7 +2496,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
table->field[3]->store(table_name,(uint) strlen(table_name),
system_charset_info);
- /* Get length of 3 first key parts */
+ /* Get length of 4 first key parts */
key_prefix_length= (key_part[0].store_length + key_part[1].store_length +
key_part[2].store_length + key_part[3].store_length);
key_copy(key, table->record[0], table->key_info, key_prefix_length);
@@ -2355,12 +2507,12 @@ static int replace_column_table(GRANT_TABLE *g_t,
List_iterator <LEX_COLUMN> iter(columns);
class LEX_COLUMN *column;
- table->file->ha_index_init(0);
+ table->file->ha_index_init(0, 1);
while ((column= iter++))
{
ulong privileges= column->rights;
bool old_row_exists=0;
- byte user_key[MAX_KEY_LENGTH];
+ uchar user_key[MAX_KEY_LENGTH];
key_restore(table->record[0],key,table->key_info,
key_prefix_length);
@@ -2370,10 +2522,8 @@ static int replace_column_table(GRANT_TABLE *g_t,
key_copy(user_key, table->record[0], table->key_info,
table->key_info->key_length);
- table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
- if (table->file->index_read(table->record[0], user_key,
- table->key_info->key_length,
- HA_READ_KEY_EXACT))
+ if (table->file->index_read_map(table->record[0], user_key, HA_WHOLE_KEY,
+ HA_READ_KEY_EXACT))
{
if (revoke_grant)
{
@@ -2409,15 +2559,17 @@ static int replace_column_table(GRANT_TABLE *g_t,
{
GRANT_COLUMN *grant_column;
if (privileges)
- error=table->file->update_row(table->record[1],table->record[0]);
+ error=table->file->ha_update_row(table->record[1],table->record[0]);
else
- error=table->file->delete_row(table->record[1]);
- if (error)
+ error=table->file->ha_delete_row(table->record[1]);
+ if (error && error != HA_ERR_RECORD_IS_THE_SAME)
{
table->file->print_error(error,MYF(0)); /* purecov: inspected */
result= -1; /* purecov: inspected */
goto end; /* purecov: inspected */
}
+ else
+ error= 0;
grant_column= column_hash_search(g_t, column->column.ptr(),
column->column.length());
if (grant_column) // Should always be true
@@ -2426,14 +2578,14 @@ static int replace_column_table(GRANT_TABLE *g_t,
else // new grant
{
GRANT_COLUMN *grant_column;
- if ((error=table->file->write_row(table->record[0])))
+ if ((error=table->file->ha_write_row(table->record[0])))
{
table->file->print_error(error,MYF(0)); /* purecov: inspected */
result= -1; /* purecov: inspected */
goto end; /* purecov: inspected */
}
grant_column= new GRANT_COLUMN(column->column,privileges);
- my_hash_insert(&g_t->hash_columns,(byte*) grant_column);
+ my_hash_insert(&g_t->hash_columns,(uchar*) grant_column);
}
}
@@ -2444,14 +2596,13 @@ static int replace_column_table(GRANT_TABLE *g_t,
if (revoke_grant)
{
- byte user_key[MAX_KEY_LENGTH];
+ uchar user_key[MAX_KEY_LENGTH];
key_copy(user_key, table->record[0], table->key_info,
key_prefix_length);
- table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
- if (table->file->index_read(table->record[0], user_key,
- key_prefix_length,
- HA_READ_KEY_EXACT))
+ if (table->file->index_read_map(table->record[0], user_key,
+ (key_part_map)15,
+ HA_READ_KEY_EXACT))
goto end;
/* Scan through all rows with the same host,db,user and table */
@@ -2478,8 +2629,9 @@ static int replace_column_table(GRANT_TABLE *g_t,
if (privileges)
{
int tmp_error;
- if ((tmp_error=table->file->update_row(table->record[1],
- table->record[0])))
+ if ((tmp_error=table->file->ha_update_row(table->record[1],
+ table->record[0])) &&
+ tmp_error != HA_ERR_RECORD_IS_THE_SAME)
{ /* purecov: deadcode */
table->file->print_error(tmp_error,MYF(0)); /* purecov: deadcode */
result= -1; /* purecov: deadcode */
@@ -2491,14 +2643,14 @@ static int replace_column_table(GRANT_TABLE *g_t,
else
{
int tmp_error;
- if ((tmp_error = table->file->delete_row(table->record[1])))
+ if ((tmp_error = table->file->ha_delete_row(table->record[1])))
{ /* purecov: deadcode */
table->file->print_error(tmp_error,MYF(0)); /* purecov: deadcode */
result= -1; /* purecov: deadcode */
goto end; /* purecov: deadcode */
}
if (grant_column)
- hash_delete(&g_t->hash_columns,(byte*) grant_column);
+ hash_delete(&g_t->hash_columns,(uchar*) grant_column);
}
}
} while (!table->file->index_next(table->record[0]) &&
@@ -2521,7 +2673,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
int old_row_exists = 1;
int error=0;
ulong store_table_rights, store_col_rights;
- byte user_key[MAX_KEY_LENGTH];
+ uchar user_key[MAX_KEY_LENGTH];
DBUG_ENTER("replace_table_table");
strxmov(grantor, thd->security_ctx->user, "@",
@@ -2538,19 +2690,22 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
DBUG_RETURN(-1); /* purecov: deadcode */
}
+ table->use_all_columns();
restore_record(table, s->default_values); // Get empty record
- table->field[0]->store(combo.host.str,combo.host.length, system_charset_info);
+ table->field[0]->store(combo.host.str,combo.host.length,
+ system_charset_info);
table->field[1]->store(db,(uint) strlen(db), system_charset_info);
- table->field[2]->store(combo.user.str,combo.user.length, system_charset_info);
- table->field[3]->store(table_name,(uint) strlen(table_name), system_charset_info);
+ table->field[2]->store(combo.user.str,combo.user.length,
+ system_charset_info);
+ table->field[3]->store(table_name,(uint) strlen(table_name),
+ system_charset_info);
store_record(table,record[1]); // store at pos 1
key_copy(user_key, table->record[0], table->key_info,
table->key_info->key_length);
- table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
- if (table->file->index_read_idx(table->record[0], 0,
- user_key, table->key_info->key_length,
- HA_READ_KEY_EXACT))
+ if (table->file->index_read_idx_map(table->record[0], 0, user_key,
+ HA_WHOLE_KEY,
+ HA_READ_KEY_EXACT))
{
/*
The following should never happen as we first check the in memory
@@ -2599,16 +2754,18 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
{
if (store_table_rights || store_col_rights)
{
- if ((error=table->file->update_row(table->record[1],table->record[0])))
+ if ((error=table->file->ha_update_row(table->record[1],
+ table->record[0])) &&
+ error != HA_ERR_RECORD_IS_THE_SAME)
goto table_error; /* purecov: deadcode */
}
- else if ((error = table->file->delete_row(table->record[1])))
+ else if ((error = table->file->ha_delete_row(table->record[1])))
goto table_error; /* purecov: deadcode */
}
else
{
- error=table->file->write_row(table->record[0]);
- if (error && error != HA_ERR_FOUND_DUPP_KEY)
+ error=table->file->ha_write_row(table->record[0]);
+ if (table->file->is_fatal_error(error, HA_CHECK_DUP_KEY))
goto table_error; /* purecov: deadcode */
}
@@ -2619,7 +2776,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
}
else
{
- hash_delete(&column_priv_hash,(byte*) grant_table);
+ hash_delete(&column_priv_hash,(uchar*) grant_table);
}
DBUG_RETURN(0);
@@ -2630,6 +2787,10 @@ table_error:
}
+/**
+ @retval 0 success
+ @retval -1 error
+*/
static int replace_routine_table(THD *thd, GRANT_NAME *grant_name,
TABLE *table, const LEX_USER &combo,
const char *db, const char *routine_name,
@@ -2651,29 +2812,28 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name,
thd->security_ctx->host_or_ip, NullS);
/*
- The following should always succeed as new users are created before
- this function is called!
+ New users are created before this function is called.
+
+ There may be some cases where a routine's definer is removed but the
+ routine remains.
*/
- if (!find_acl_user(combo.host.str, combo.user.str, FALSE))
- {
- my_error(ER_PASSWORD_NO_MATCH,MYF(0));
- DBUG_RETURN(-1);
- }
+ table->use_all_columns();
restore_record(table, s->default_values); // Get empty record
table->field[0]->store(combo.host.str,combo.host.length, &my_charset_latin1);
table->field[1]->store(db,(uint) strlen(db), &my_charset_latin1);
table->field[2]->store(combo.user.str,combo.user.length, &my_charset_latin1);
table->field[3]->store(routine_name,(uint) strlen(routine_name),
&my_charset_latin1);
- table->field[4]->store((longlong)(is_proc ?
+ table->field[4]->store((longlong)(is_proc ?
TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION),
TRUE);
store_record(table,record[1]); // store at pos 1
- if (table->file->index_read_idx(table->record[0],0,
- (byte*) table->field[0]->ptr,0,
- HA_READ_KEY_EXACT))
+ if (table->file->index_read_idx_map(table->record[0], 0,
+ (uchar*) table->field[0]->ptr,
+ HA_WHOLE_KEY,
+ HA_READ_KEY_EXACT))
{
/*
The following should never happen as we first check the in memory
@@ -2716,16 +2876,18 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name,
{
if (store_proc_rights)
{
- if ((error=table->file->update_row(table->record[1],table->record[0])))
+ if ((error=table->file->ha_update_row(table->record[1],
+ table->record[0])) &&
+ error != HA_ERR_RECORD_IS_THE_SAME)
goto table_error;
}
- else if ((error= table->file->delete_row(table->record[1])))
+ else if ((error= table->file->ha_delete_row(table->record[1])))
goto table_error;
}
else
{
- error=table->file->write_row(table->record[0]);
- if (error && error != HA_ERR_FOUND_DUPP_KEY)
+ error=table->file->ha_write_row(table->record[0]);
+ if (table->file->is_fatal_error(error, HA_CHECK_DUP_KEY))
goto table_error;
}
@@ -2735,7 +2897,7 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name,
}
else
{
- hash_delete(is_proc ? &proc_priv_hash : &func_priv_hash,(byte*) grant_name);
+ hash_delete(is_proc ? &proc_priv_hash : &func_priv_hash,(uchar*) grant_name);
}
DBUG_RETURN(0);
@@ -2825,9 +2987,10 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
if (!(rights & CREATE_ACL))
{
char buf[FN_REFLEN];
- sprintf(buf,"%s/%s/%s.frm",mysql_data_home, table_list->db,
- table_list->table_name);
- fn_format(buf,buf,"","",4+16+32);
+ build_table_filename(buf, sizeof(buf), table_list->db,
+ table_list->table_name, reg_ext, 0);
+ fn_format(buf, buf, "", "", MY_UNPACK_FILENAME | MY_RESOLVE_SYMLINKS |
+ MY_RETURN_REAL_PATH | MY_APPEND_EXT);
if (access(buf,F_OK))
{
my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->alias);
@@ -2863,19 +3026,26 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_WRITE;
tables[0].db=tables[1].db=tables[2].db=(char*) "mysql";
+ /*
+ This statement will be replicated as a statement, even when using
+ row-based replication. The flag will be reset at the end of the
+ statement.
+ */
+ thd->clear_current_stmt_binlog_row_based();
+
#ifdef HAVE_REPLICATION
/*
GRANT and REVOKE are applied the slave in/exclusion rules as they are
some kind of updates to the mysql.% tables.
*/
- if (thd->slave_thread && table_rules_on)
+ if (thd->slave_thread && rpl_filter->is_on())
{
/*
The tables must be marked "updating" so that tables_ok() takes them into
account in tests.
*/
tables[0].updating= tables[1].updating= tables[2].updating= 1;
- if (!tables_ok(thd, tables))
+ if (!(thd->spcont || rpl_filter->tables_ok(0, tables)))
DBUG_RETURN(FALSE);
}
#endif
@@ -2949,7 +3119,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
result= TRUE; /* purecov: deadcode */
continue; /* purecov: deadcode */
}
- my_hash_insert(&column_priv_hash,(byte*) grant_table);
+ my_hash_insert(&column_priv_hash,(uchar*) grant_table);
}
/* If revoke_grant, calculate the new column privilege for tables_priv */
@@ -3004,24 +3174,18 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
}
}
}
-
thd->mem_root= old_root;
pthread_mutex_unlock(&acl_cache->lock);
if (!result) /* success */
{
- if (mysql_bin_log.is_open())
- {
- thd->clear_error();
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
- mysql_bin_log.write(&qinfo);
- }
+ write_bin_log(thd, TRUE, thd->query, thd->query_length);
}
rw_unlock(&LOCK_grant);
if (!result) /* success */
- send_ok(thd);
+ my_ok(thd);
/* Tables are automatically closed */
thd->lex->restore_backup_query_tables_list(&backup);
@@ -3087,19 +3251,26 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
tables[0].lock_type=tables[1].lock_type=TL_WRITE;
tables[0].db=tables[1].db=(char*) "mysql";
+ /*
+ This statement will be replicated as a statement, even when using
+ row-based replication. The flag will be reset at the end of the
+ statement.
+ */
+ thd->clear_current_stmt_binlog_row_based();
+
#ifdef HAVE_REPLICATION
/*
GRANT and REVOKE are applied the slave in/exclusion rules as they are
some kind of updates to the mysql.% tables.
*/
- if (thd->slave_thread && table_rules_on)
+ if (thd->slave_thread && rpl_filter->is_on())
{
/*
The tables must be marked "updating" so that tables_ok() takes them into
account in tests.
*/
tables[0].updating= tables[1].updating= 1;
- if (!tables_ok(thd, tables))
+ if (!(thd->spcont || rpl_filter->tables_ok(0, tables)))
DBUG_RETURN(FALSE);
}
#endif
@@ -3162,33 +3333,28 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
result= TRUE;
continue;
}
- my_hash_insert(is_proc ? &proc_priv_hash : &func_priv_hash,(byte*) grant_name);
+ my_hash_insert(is_proc ? &proc_priv_hash : &func_priv_hash,(uchar*) grant_name);
}
if (replace_routine_table(thd, grant_name, tables[1].table, *Str,
- db_name, table_name, is_proc, rights, revoke_grant))
+ db_name, table_name, is_proc, rights,
+ revoke_grant) != 0)
{
result= TRUE;
continue;
}
}
-
thd->mem_root= old_root;
pthread_mutex_unlock(&acl_cache->lock);
if (!result && !no_error)
{
- if (mysql_bin_log.is_open())
- {
- thd->clear_error();
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
- mysql_bin_log.write(&qinfo);
- }
+ write_bin_log(thd, TRUE, thd->query, thd->query_length);
}
rw_unlock(&LOCK_grant);
if (!result && !no_error)
- send_ok(thd);
+ my_ok(thd);
/* Tables are automatically closed */
DBUG_RETURN(result);
@@ -3226,19 +3392,26 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
tables[0].lock_type=tables[1].lock_type=TL_WRITE;
tables[0].db=tables[1].db=(char*) "mysql";
+ /*
+ This statement will be replicated as a statement, even when using
+ row-based replication. The flag will be reset at the end of the
+ statement.
+ */
+ thd->clear_current_stmt_binlog_row_based();
+
#ifdef HAVE_REPLICATION
/*
GRANT and REVOKE are applied the slave in/exclusion rules as they are
some kind of updates to the mysql.% tables.
*/
- if (thd->slave_thread && table_rules_on)
+ if (thd->slave_thread && rpl_filter->is_on())
{
/*
The tables must be marked "updating" so that tables_ok() takes them into
account in tests.
*/
tables[0].updating= tables[1].updating= 1;
- if (!tables_ok(thd, tables))
+ if (!(thd->spcont || rpl_filter->tables_ok(0, tables)))
DBUG_RETURN(FALSE);
}
#endif
@@ -3290,19 +3463,14 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
if (!result)
{
- if (mysql_bin_log.is_open())
- {
- thd->clear_error();
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
- mysql_bin_log.write(&qinfo);
- }
+ write_bin_log(thd, TRUE, thd->query, thd->query_length);
}
rw_unlock(&LOCK_grant);
close_thread_tables(thd);
if (!result)
- send_ok(thd);
+ my_ok(thd);
DBUG_RETURN(result);
}
@@ -3313,7 +3481,6 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
void grant_free(void)
{
DBUG_ENTER("grant_free");
- grant_option = FALSE;
hash_free(&column_priv_hash);
hash_free(&proc_priv_hash);
hash_free(&func_priv_hash);
@@ -3322,16 +3489,13 @@ void grant_free(void)
}
-/*
- Initialize structures responsible for table/column-level privilege checking
- and load information for them from tables in the 'mysql' database.
-
- SYNOPSIS
- grant_init()
+/**
+ @brief Initialize structures responsible for table/column-level privilege
+ checking and load information for them from tables in the 'mysql' database.
- RETURN VALUES
- 0 ok
- 1 Could not initialize grant's
+ @return Error status
+ @retval 0 OK
+ @retval 1 Could not initialize grant subsystem.
*/
my_bool grant_init()
@@ -3344,107 +3508,159 @@ 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 */
my_pthread_setspecific_ptr(THR_THD, 0);
- /* Set the grant option flag so we will check grants */
- grant_option= TRUE;
DBUG_RETURN(return_val);
}
-/*
- Initialize structures responsible for table/column-level privilege
- checking and load information about grants from open privilege tables.
+/**
+ @brief Helper function to grant_reload_procs_priv
- SYNOPSIS
- grant_load()
- thd Current thread
- tables List containing open "mysql.tables_priv" and
- "mysql.columns_priv" tables.
+ Reads the procs_priv table into memory hash.
- RETURN VALUES
- FALSE - success
- TRUE - error
+ @param table A pointer to the procs_priv table structure.
+
+ @see grant_reload
+ @see grant_reload_procs_priv
+
+ @return Error state
+ @retval TRUE An error occurred
+ @retval FALSE Success
*/
-static my_bool grant_load(TABLE_LIST *tables)
+static my_bool grant_load_procs_priv(TABLE *p_table)
{
MEM_ROOT *memex_ptr;
my_bool return_val= 1;
- TABLE *t_table, *c_table, *p_table;
bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE;
MEM_ROOT **save_mem_root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**,
THR_MALLOC);
- DBUG_ENTER("grant_load");
-
- (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);
+ 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);
+ 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);
- init_sql_alloc(&memex, ACL_ALLOC_BLOCK_SIZE, 0);
+ 0,0,0, (hash_get_key) get_grant_table,
+ 0,0);
+ p_table->file->ha_index_init(0, 1);
+ p_table->use_all_columns();
- t_table = tables[0].table; c_table = tables[1].table;
- p_table= tables[2].table;
- t_table->file->ha_index_init(0);
- p_table->file->ha_index_init(0);
- if (!t_table->file->index_first(t_table->record[0]))
+ if (!p_table->file->index_first(p_table->record[0]))
{
memex_ptr= &memex;
my_pthread_setspecific_ptr(THR_MALLOC, &memex_ptr);
do
{
- GRANT_TABLE *mem_check;
- if (!(mem_check=new GRANT_TABLE(t_table,c_table)))
+ GRANT_NAME *mem_check;
+ HASH *hash;
+ if (!(mem_check=new (memex_ptr) GRANT_NAME(p_table)))
{
- /* This could only happen if we are out memory */
- grant_option= FALSE;
- goto end_unlock;
+ /* This could only happen if we are out memory */
+ goto end_unlock;
}
if (check_no_resolve)
{
if (hostname_requires_resolving(mem_check->host.hostname))
{
- sql_print_warning("'tables_priv' entry '%s %s@%s' "
+ sql_print_warning("'procs_priv' entry '%s %s@%s' "
"ignored in --skip-name-resolve mode.",
- mem_check->tname,
- mem_check->user ? mem_check->user : "",
+ mem_check->tname, mem_check->user,
mem_check->host.hostname ?
mem_check->host.hostname : "");
- continue;
- }
+ continue;
+ }
+ }
+ if (p_table->field[4]->val_int() == TYPE_ENUM_PROCEDURE)
+ {
+ hash= &proc_priv_hash;
+ }
+ else
+ if (p_table->field[4]->val_int() == TYPE_ENUM_FUNCTION)
+ {
+ hash= &func_priv_hash;
+ }
+ else
+ {
+ sql_print_warning("'procs_priv' entry '%s' "
+ "ignored, bad routine type",
+ mem_check->tname);
+ continue;
}
+ mem_check->privs= fix_rights_for_procedure(mem_check->privs);
if (! mem_check->ok())
- delete mem_check;
- else if (my_hash_insert(&column_priv_hash,(byte*) mem_check))
+ delete mem_check;
+ else if (my_hash_insert(hash, (uchar*) mem_check))
{
- delete mem_check;
- grant_option= FALSE;
- goto end_unlock;
+ delete mem_check;
+ goto end_unlock;
}
}
- while (!t_table->file->index_next(t_table->record[0]));
+ while (!p_table->file->index_next(p_table->record[0]));
}
- if (!p_table->file->index_first(p_table->record[0]))
+ /* Return ok */
+ return_val= 0;
+
+end_unlock:
+ p_table->file->ha_index_end();
+ my_pthread_setspecific_ptr(THR_MALLOC, save_mem_root_ptr);
+ DBUG_RETURN(return_val);
+}
+
+
+/**
+ @brief Initialize structures responsible for table/column-level privilege
+ checking and load information about grants from open privilege tables.
+
+ @param thd Current thread
+ @param tables List containing open "mysql.tables_priv" and
+ "mysql.columns_priv" tables.
+
+ @see grant_reload
+
+ @return Error state
+ @retval FALSE Success
+ @retval TRUE Error
+*/
+
+static my_bool grant_load(THD *thd, TABLE_LIST *tables)
+{
+ MEM_ROOT *memex_ptr;
+ my_bool return_val= 1;
+ TABLE *t_table= 0, *c_table= 0;
+ bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE;
+ MEM_ROOT **save_mem_root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**,
+ THR_MALLOC);
+ ulong old_sql_mode= thd->variables.sql_mode;
+ DBUG_ENTER("grant_load");
+
+ 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);
+
+ t_table = tables[0].table;
+ c_table = tables[1].table;
+ t_table->file->ha_index_init(0, 1);
+ t_table->use_all_columns();
+ c_table->use_all_columns();
+
+ if (!t_table->file->index_first(t_table->record[0]))
{
memex_ptr= &memex;
my_pthread_setspecific_ptr(THR_MALLOC, &memex_ptr);
do
{
- GRANT_NAME *mem_check;
- HASH *hash;
- if (!(mem_check=new GRANT_NAME(p_table)))
+ GRANT_TABLE *mem_check;
+ if (!(mem_check=new (memex_ptr) GRANT_TABLE(t_table,c_table)))
{
/* This could only happen if we are out memory */
- grant_option= FALSE;
goto end_unlock;
}
@@ -3452,75 +3668,113 @@ static my_bool grant_load(TABLE_LIST *tables)
{
if (hostname_requires_resolving(mem_check->host.hostname))
{
- sql_print_warning("'procs_priv' entry '%s %s@%s' "
+ sql_print_warning("'tables_priv' entry '%s %s@%s' "
"ignored in --skip-name-resolve mode.",
- mem_check->tname, mem_check->user,
+ mem_check->tname,
+ mem_check->user ? mem_check->user : "",
mem_check->host.hostname ?
mem_check->host.hostname : "");
continue;
}
}
- if (p_table->field[4]->val_int() == TYPE_ENUM_PROCEDURE)
- {
- hash= &proc_priv_hash;
- }
- else
- if (p_table->field[4]->val_int() == TYPE_ENUM_FUNCTION)
- {
- hash= &func_priv_hash;
- }
- else
- {
- sql_print_warning("'procs_priv' entry '%s' "
- "ignored, bad routine type",
- mem_check->tname);
- continue;
- }
- mem_check->privs= fix_rights_for_procedure(mem_check->privs);
if (! mem_check->ok())
delete mem_check;
- else if (my_hash_insert(hash, (byte*) mem_check))
+ else if (my_hash_insert(&column_priv_hash,(uchar*) mem_check))
{
delete mem_check;
- grant_option= FALSE;
goto end_unlock;
}
}
- while (!p_table->file->index_next(p_table->record[0]));
+ while (!t_table->file->index_next(t_table->record[0]));
}
+
return_val=0; // Return ok
end_unlock:
+ thd->variables.sql_mode= old_sql_mode;
t_table->file->ha_index_end();
- p_table->file->ha_index_end();
my_pthread_setspecific_ptr(THR_MALLOC, save_mem_root_ptr);
DBUG_RETURN(return_val);
}
-/*
- Reload information about table and column level privileges if possible.
+/**
+ @brief Helper function to grant_reload. Reloads procs_priv table is it
+ exists.
- SYNOPSIS
- grant_reload()
- thd Current thread
+ @param thd A pointer to the thread handler object.
- NOTES
- Locked tables are checked by acl_reload() and doesn't have to be checked
- in this call.
- This function is also used for initialization of structures responsible
- for table/column-level privilege checking.
+ @see grant_reload
- RETURN VALUE
- FALSE Success
- TRUE Error
+ @return Error state
+ @retval FALSE Success
+ @retval TRUE An error has occurred.
+*/
+
+static my_bool grant_reload_procs_priv(THD *thd)
+{
+ HASH old_proc_priv_hash, old_func_priv_hash;
+ TABLE_LIST table;
+ my_bool return_val= FALSE;
+ DBUG_ENTER("grant_reload_procs_priv");
+
+ bzero((char*) &table, sizeof(table));
+ table.alias= table.table_name= (char*) "procs_priv";
+ table.db= (char *) "mysql";
+ table.lock_type= TL_READ;
+ table.skip_temporary= 1;
+
+ if (simple_open_n_lock_tables(thd, &table))
+ {
+ close_thread_tables(thd);
+ DBUG_RETURN(TRUE);
+ }
+
+ /* 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;
+
+ rw_wrlock(&LOCK_grant);
+ if ((return_val= grant_load_procs_priv(table.table)))
+ {
+ /* Error; Reverting to old hash */
+ DBUG_PRINT("error",("Reverting to old privileges"));
+ grant_free();
+ proc_priv_hash= old_proc_priv_hash;
+ func_priv_hash= old_func_priv_hash;
+ }
+ else
+ {
+ hash_free(&old_proc_priv_hash);
+ hash_free(&old_func_priv_hash);
+ }
+ rw_unlock(&LOCK_grant);
+
+ close_thread_tables(thd);
+ DBUG_RETURN(return_val);
+}
+
+
+/**
+ @brief Reload information about table and column level privileges if possible
+
+ @param thd Current thread
+
+ Locked tables are checked by acl_reload() and doesn't have to be checked
+ in this call.
+ This function is also used for initialization of structures responsible
+ for table/column-level privilege checking.
+
+ @return Error state
+ @retval FALSE Success
+ @retval TRUE Error
*/
my_bool grant_reload(THD *thd)
{
- TABLE_LIST tables[3];
- HASH old_column_priv_hash, old_proc_priv_hash, old_func_priv_hash;
+ TABLE_LIST tables[2];
+ HASH old_column_priv_hash;
MEM_ROOT old_mem;
my_bool return_val= 1;
DBUG_ENTER("grant_reload");
@@ -3532,12 +3786,10 @@ my_bool grant_reload(THD *thd)
bzero((char*) tables, sizeof(tables));
tables[0].alias= tables[0].table_name= (char*) "tables_priv";
tables[1].alias= tables[1].table_name= (char*) "columns_priv";
- tables[2].alias= tables[2].table_name= (char*) "procs_priv";
- tables[0].db= tables[1].db= tables[2].db= (char *) "mysql";
+ tables[0].db= tables[1].db= (char *) "mysql";
tables[0].next_local= tables[0].next_global= tables+1;
- tables[1].next_local= tables[1].next_global= tables+2;
- tables[0].lock_type= tables[1].lock_type= tables[2].lock_type= TL_READ;
-
+ tables[0].lock_type= tables[1].lock_type= TL_READ;
+ tables[0].skip_temporary= tables[1].skip_temporary= TRUE;
/*
To avoid deadlocks we should obtain table locks before
obtaining LOCK_grant rwlock.
@@ -3546,35 +3798,45 @@ my_bool grant_reload(THD *thd)
goto end;
rw_wrlock(&LOCK_grant);
- grant_version++;
old_column_priv_hash= column_priv_hash;
- old_proc_priv_hash= proc_priv_hash;
- old_func_priv_hash= func_priv_hash;
+
+ /*
+ Create a new memory pool but save the current memory pool to make an undo
+ opertion possible in case of failure.
+ */
old_mem= memex;
+ init_sql_alloc(&memex, ACL_ALLOC_BLOCK_SIZE, 0);
- if ((return_val= grant_load(tables)))
+ if ((return_val= grant_load(thd, tables)))
{ // Error. Revert to old hash
DBUG_PRINT("error",("Reverting to old privileges"));
grant_free(); /* purecov: deadcode */
column_priv_hash= old_column_priv_hash; /* purecov: deadcode */
- proc_priv_hash= old_proc_priv_hash;
- func_priv_hash= old_func_priv_hash;
memex= old_mem; /* purecov: deadcode */
}
else
{
hash_free(&old_column_priv_hash);
- hash_free(&old_proc_priv_hash);
- hash_free(&old_func_priv_hash);
free_root(&old_mem,MYF(0));
}
rw_unlock(&LOCK_grant);
-end:
close_thread_tables(thd);
+
+ /*
+ It is OK failing to load procs_priv table because we may be
+ working with 4.1 privilege tables.
+ */
+ if (grant_reload_procs_priv(thd))
+ return_val= 1;
+
+ rw_wrlock(&LOCK_grant);
+ grant_version++;
+ rw_unlock(&LOCK_grant);
+
+end:
DBUG_RETURN(return_val);
}
-
/****************************************************************************
Check table level grants
@@ -3623,7 +3885,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
of other queries). For simple queries first_not_own_table is 0.
*/
for (i= 0, table= tables;
- table != first_not_own_table && i < number;
+ i < number && table != first_not_own_table;
table= table->next_global, i++)
{
/* Remove SHOW_VIEW_ACL, because it will be checked during making view */
@@ -3831,8 +4093,8 @@ bool check_column_grant_in_table_ref(THD *thd, TABLE_LIST * table_ref,
/* Normal or temporary table. */
TABLE *table= table_ref->table;
grant= &(table->grant);
- db_name= table->s->db;
- table_name= table->s->table_name;
+ db_name= table->s->db.str;
+ table_name= table->s->table_name.str;
}
if (grant->want_privilege)
@@ -3866,60 +4128,55 @@ bool check_grant_all_columns(THD *thd, ulong want_access_arg,
ulong want_access= want_access_arg;
const char *table_name= NULL;
- if (grant_option)
- {
- const char* db_name;
- GRANT_INFO *grant;
- /* Initialized only to make gcc happy */
- GRANT_TABLE *grant_table= NULL;
+ const char* db_name;
+ GRANT_INFO *grant;
+ /* Initialized only to make gcc happy */
+ GRANT_TABLE *grant_table= NULL;
- rw_rdlock(&LOCK_grant);
+ rw_rdlock(&LOCK_grant);
- for (; !fields->end_of_fields(); fields->next())
- {
- const char *field_name= fields->name();
+ for (; !fields->end_of_fields(); fields->next())
+ {
+ const char *field_name= fields->name();
- if (table_name != fields->table_name())
+ if (table_name != fields->table_name())
+ {
+ table_name= fields->table_name();
+ db_name= fields->db_name();
+ grant= fields->grant();
+ /* get a fresh one for each table */
+ want_access= want_access_arg & ~grant->privilege;
+ if (want_access)
{
- table_name= fields->table_name();
- db_name= fields->db_name();
- grant= fields->grant();
- /* get a fresh one for each table */
- want_access= want_access_arg & ~grant->privilege;
- if (want_access)
+ /* reload table if someone has modified any grants */
+ if (grant->version != grant_version)
{
- /* reload table if someone has modified any grants */
- if (grant->version != grant_version)
- {
- grant->grant_table=
- table_hash_search(sctx->host, sctx->ip, db_name,
- sctx->priv_user,
- table_name, 0); /* purecov: inspected */
- grant->version= grant_version; /* purecov: inspected */
- }
-
- grant_table= grant->grant_table;
- DBUG_ASSERT (grant_table);
+ grant->grant_table=
+ table_hash_search(sctx->host, sctx->ip, db_name,
+ sctx->priv_user,
+ table_name, 0); /* purecov: inspected */
+ grant->version= grant_version; /* purecov: inspected */
}
- }
- if (want_access)
- {
- GRANT_COLUMN *grant_column=
- column_hash_search(grant_table, field_name,
- (uint) strlen(field_name));
- if (!grant_column || (~grant_column->rights & want_access))
- goto err;
+ grant_table= grant->grant_table;
+ DBUG_ASSERT (grant_table);
}
}
- rw_unlock(&LOCK_grant);
- return 0;
-err:
- rw_unlock(&LOCK_grant);
+ if (want_access)
+ {
+ GRANT_COLUMN *grant_column=
+ column_hash_search(grant_table, field_name,
+ (uint) strlen(field_name));
+ if (!grant_column || (~grant_column->rights & want_access))
+ goto err;
+ }
}
- else
- table_name= fields->table_name();
+ rw_unlock(&LOCK_grant);
+ return 0;
+
+err:
+ rw_unlock(&LOCK_grant);
char command[128];
get_privilege_desc(command, sizeof(command), want_access);
@@ -4079,18 +4336,15 @@ bool check_routine_level_acl(THD *thd, const char *db, const char *name,
bool is_proc)
{
bool no_routine_acl= 1;
- if (grant_option)
- {
- GRANT_NAME *grant_proc;
- Security_context *sctx= thd->security_ctx;
- rw_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);
- }
+ GRANT_NAME *grant_proc;
+ Security_context *sctx= thd->security_ctx;
+ rw_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);
return no_routine_acl;
}
@@ -4199,13 +4453,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"
+ "CREATE USER", "EVENT", "TRIGGER"
};
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
+ 14, 13, 11, 5, 7
};
@@ -4577,7 +4831,7 @@ end:
VOID(pthread_mutex_unlock(&acl_cache->lock));
rw_unlock(&LOCK_grant);
- send_eof(thd);
+ my_eof(thd);
DBUG_RETURN(error);
}
@@ -4762,7 +5016,7 @@ int open_grant_tables(THD *thd, TABLE_LIST *tables)
GRANT and REVOKE are applied the slave in/exclusion rules as they are
some kind of updates to the mysql.% tables.
*/
- if (thd->slave_thread && table_rules_on)
+ if (thd->slave_thread && rpl_filter->is_on())
{
/*
The tables must be marked "updating" so that tables_ok() takes them into
@@ -4770,7 +5024,7 @@ int open_grant_tables(THD *thd, TABLE_LIST *tables)
*/
tables[0].updating=tables[1].updating=tables[2].updating=
tables[3].updating=tables[4].updating=1;
- if (!tables_ok(thd, tables))
+ if (!(thd->spcont || rpl_filter->tables_ok(0, tables)))
DBUG_RETURN(1);
tables[0].updating=tables[1].updating=tables[2].updating=
tables[3].updating=tables[4].updating=0;;
@@ -4847,13 +5101,17 @@ static int modify_grant_table(TABLE *table, Field *host_field,
system_charset_info);
user_field->store(user_to->user.str, user_to->user.length,
system_charset_info);
- if ((error= table->file->update_row(table->record[1], table->record[0])))
+ if ((error= table->file->ha_update_row(table->record[1],
+ table->record[0])) &&
+ error != HA_ERR_RECORD_IS_THE_SAME)
table->file->print_error(error, MYF(0));
+ else
+ error= 0;
}
else
{
/* delete */
- if ((error=table->file->delete_row(table->record[0])))
+ if ((error=table->file->ha_delete_row(table->record[0])))
table->file->print_error(error, MYF(0));
}
@@ -4904,11 +5162,12 @@ static int handle_grant_table(TABLE_LIST *tables, uint table_no, bool drop,
char *user_str= user_from->user.str;
const char *host;
const char *user;
- byte user_key[MAX_KEY_LENGTH];
+ uchar user_key[MAX_KEY_LENGTH];
uint key_prefix_length;
DBUG_ENTER("handle_grant_table");
THD *thd= current_thd;
+ table->use_all_columns();
if (! table_no) // mysql.user table
{
/*
@@ -4921,7 +5180,7 @@ static int handle_grant_table(TABLE_LIST *tables, uint table_no, bool drop,
by the searched record, if it exists.
*/
DBUG_PRINT("info",("read table: '%s' search: '%s'@'%s'",
- table->s->table_name, user_str, host_str));
+ table->s->table_name.str, user_str, host_str));
host_field->store(host_str, user_from->host.length, system_charset_info);
user_field->store(user_str, user_from->user.length, system_charset_info);
@@ -4929,11 +5188,11 @@ static int handle_grant_table(TABLE_LIST *tables, uint table_no, bool drop,
table->key_info->key_part[1].store_length);
key_copy(user_key, table->record[0], table->key_info, key_prefix_length);
- if ((error= table->file->index_read_idx(table->record[0], 0,
- user_key, key_prefix_length,
- HA_READ_KEY_EXACT)))
+ if ((error= table->file->index_read_idx_map(table->record[0], 0,
+ user_key, (key_part_map)3,
+ HA_READ_KEY_EXACT)))
{
- if (error != HA_ERR_KEY_NOT_FOUND)
+ if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
{
table->file->print_error(error, MYF(0));
result= -1;
@@ -4964,7 +5223,7 @@ static int handle_grant_table(TABLE_LIST *tables, uint table_no, bool drop,
{
#ifdef EXTRA_DEBUG
DBUG_PRINT("info",("scan table: '%s' search: '%s'@'%s'",
- table->s->table_name, user_str, host_str));
+ table->s->table_name.str, user_str, host_str));
#endif
while ((error= table->file->rnd_next(table->record[0])) !=
HA_ERR_END_OF_FILE)
@@ -5056,6 +5315,8 @@ static int handle_grant_struct(uint struct_no, bool drop,
LINT_INIT(acl_user);
LINT_INIT(acl_db);
LINT_INIT(grant_name);
+ LINT_INIT(user);
+ LINT_INIT(host);
safe_mutex_assert_owner(&acl_cache->lock);
@@ -5130,8 +5391,7 @@ static int handle_grant_struct(uint struct_no, bool drop,
result= 1; /* At least one element found. */
if ( drop )
{
- switch ( struct_no )
- {
+ switch ( struct_no ) {
case 0:
delete_dynamic_element(&acl_users, idx);
break;
@@ -5141,11 +5401,11 @@ static int handle_grant_struct(uint struct_no, bool drop,
break;
case 2:
- hash_delete(&column_priv_hash, (byte*) grant_name);
+ hash_delete(&column_priv_hash, (uchar*) grant_name);
break;
case 3:
- hash_delete(&proc_priv_hash, (byte*) grant_name);
+ hash_delete(&proc_priv_hash, (uchar*) grant_name);
break;
}
elements--;
@@ -5345,6 +5605,13 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list)
bool some_users_created= FALSE;
DBUG_ENTER("mysql_create_user");
+ /*
+ This statement will be replicated as a statement, even when using
+ row-based replication. The flag will be reset at the end of the
+ statement.
+ */
+ thd->clear_current_stmt_binlog_row_based();
+
/* CREATE USER may be skipped on replication client. */
if ((result= open_grant_tables(thd, tables)))
DBUG_RETURN(result != 1);
@@ -5385,11 +5652,8 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list)
if (result)
my_error(ER_CANNOT_USER, MYF(0), "CREATE USER", wrong_users.c_ptr_safe());
- if (some_users_created && mysql_bin_log.is_open())
- {
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
- mysql_bin_log.write(&qinfo);
- }
+ if (some_users_created)
+ write_bin_log(thd, FALSE, thd->query, thd->query_length);
rw_unlock(&LOCK_grant);
close_thread_tables(thd);
@@ -5420,6 +5684,13 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list)
bool some_users_deleted= FALSE;
DBUG_ENTER("mysql_drop_user");
+ /*
+ This statement will be replicated as a statement, even when using
+ row-based replication. The flag will be reset at the end of the
+ statement.
+ */
+ thd->clear_current_stmt_binlog_row_based();
+
/* DROP USER may be skipped on replication client. */
if ((result= open_grant_tables(thd, tables)))
DBUG_RETURN(result != 1);
@@ -5452,14 +5723,8 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list)
if (result)
my_error(ER_CANNOT_USER, MYF(0), "DROP USER", wrong_users.c_ptr_safe());
- DBUG_PRINT("info", ("thd->net.last_errno: %d", thd->net.last_errno));
- DBUG_PRINT("info", ("thd->net.last_error: %s", thd->net.last_error));
-
- if (some_users_deleted && mysql_bin_log.is_open())
- {
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
- mysql_bin_log.write(&qinfo);
- }
+ if (some_users_deleted)
+ write_bin_log(thd, FALSE, thd->query, thd->query_length);
rw_unlock(&LOCK_grant);
close_thread_tables(thd);
@@ -5491,6 +5756,13 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list)
bool some_users_renamed= FALSE;
DBUG_ENTER("mysql_rename_user");
+ /*
+ This statement will be replicated as a statement, even when using
+ row-based replication. The flag will be reset at the end of the
+ statement.
+ */
+ thd->clear_current_stmt_binlog_row_based();
+
/* RENAME USER may be skipped on replication client. */
if ((result= open_grant_tables(thd, tables)))
DBUG_RETURN(result != 1);
@@ -5536,10 +5808,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())
- {
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
- mysql_bin_log.write(&qinfo);
- }
+ write_bin_log(thd, FALSE, thd->query, thd->query_length);
rw_unlock(&LOCK_grant);
close_thread_tables(thd);
@@ -5569,6 +5838,13 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
TABLE_LIST tables[GRANT_TABLES];
DBUG_ENTER("mysql_revoke_all");
+ /*
+ This statement will be replicated as a statement, even when using
+ row-based replication. The flag will be reset at the end of the
+ statement.
+ */
+ thd->clear_current_stmt_binlog_row_based();
+
if ((result= open_grant_tables(thd, tables)))
DBUG_RETURN(result != 1);
@@ -5618,7 +5894,8 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
if (!strcmp(lex_user->user.str,user) &&
!strcmp(lex_user->host.str, host))
{
- if (!replace_db_table(tables[1].table, acl_db->db, *lex_user, ~(ulong)0, 1))
+ if (!replace_db_table(tables[1].table, acl_db->db, *lex_user,
+ ~(ulong)0, 1))
{
/*
Don't increment counter as replace_db_table deleted the
@@ -5695,11 +5972,11 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
if (!strcmp(lex_user->user.str,user) &&
!strcmp(lex_user->host.str, host))
{
- if (!replace_routine_table(thd,grant_proc,tables[4].table,*lex_user,
+ if (replace_routine_table(thd,grant_proc,tables[4].table,*lex_user,
grant_proc->db,
grant_proc->tname,
is_proc,
- ~(ulong)0, 1))
+ ~(ulong)0, 1) == 0)
{
revoked= 1;
continue;
@@ -5713,11 +5990,7 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
VOID(pthread_mutex_unlock(&acl_cache->lock));
- if (mysql_bin_log.is_open())
- {
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
- mysql_bin_log.write(&qinfo);
- }
+ write_bin_log(thd, FALSE, thd->query, thd->query_length);
rw_unlock(&LOCK_grant);
close_thread_tables(thd);
@@ -5729,17 +6002,73 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
}
-/*
- Revoke privileges for all users on a stored procedure
- SYNOPSIS
- sp_revoke_privileges()
+
+/**
+ If the defining user for a routine does not exist, then the ACL lookup
+ code should raise two errors which we should intercept. We convert the more
+ descriptive error into a warning, and consume the other.
+
+ If any other errors are raised, then we set a flag that should indicate
+ that there was some failure we should complain at a higher level.
+*/
+class Silence_routine_definer_errors : public Internal_error_handler
+{
+public:
+ Silence_routine_definer_errors()
+ : is_grave(FALSE)
+ {}
+
+ virtual ~Silence_routine_definer_errors()
+ {}
+
+ virtual bool handle_error(uint sql_errno, const char *message,
+ MYSQL_ERROR::enum_warning_level level,
+ THD *thd);
+
+ bool has_errors() { return is_grave; }
+
+private:
+ bool is_grave;
+};
+
+bool
+Silence_routine_definer_errors::handle_error(uint sql_errno,
+ const char *message,
+ MYSQL_ERROR::enum_warning_level level,
+ THD *thd)
+{
+ if (level == MYSQL_ERROR::WARN_LEVEL_ERROR)
+ {
+ switch (sql_errno)
+ {
+ case ER_NONEXISTING_PROC_GRANT:
+ /* Convert the error into a warning. */
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, sql_errno, message);
+ return TRUE;
+ default:
+ is_grave= TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+/**
+ Revoke privileges for all users on a stored procedure. Use an error handler
+ that converts errors about missing grants into warnings.
+
+ @param
thd The current thread.
+ @param
db DB of the stored procedure
+ @param
name Name of the stored procedure
- RETURN
+ @retval
0 OK.
+ @retval
< 0 Error. Error message not yet sent.
*/
@@ -5750,14 +6079,25 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
int result;
TABLE_LIST tables[GRANT_TABLES];
HASH *hash= is_proc ? &proc_priv_hash : &func_priv_hash;
+ Silence_routine_definer_errors error_handler;
DBUG_ENTER("sp_revoke_privileges");
if ((result= open_grant_tables(thd, tables)))
DBUG_RETURN(result != 1);
+ /* Be sure to pop this before exiting this scope! */
+ thd->push_internal_handler(&error_handler);
+
rw_wrlock(&LOCK_grant);
VOID(pthread_mutex_lock(&acl_cache->lock));
+ /*
+ This statement will be replicated as a statement, even when using
+ row-based replication. The flag will be reset at the end of the
+ statement.
+ */
+ thd->clear_current_stmt_binlog_row_based();
+
/* Remove procedure access */
do
{
@@ -5774,14 +6114,14 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
grant_proc->host.hostname : (char*)"";
lex_user.host.length= grant_proc->host.hostname ?
strlen(grant_proc->host.hostname) : 0;
- if (!replace_routine_table(thd,grant_proc,tables[4].table,lex_user,
- grant_proc->db, grant_proc->tname,
- is_proc, ~(ulong)0, 1))
+
+ if (replace_routine_table(thd,grant_proc,tables[4].table,lex_user,
+ grant_proc->db, grant_proc->tname,
+ is_proc, ~(ulong)0, 1) == 0)
{
revoked= 1;
continue;
}
- result= -1; // Something went wrong
}
counter++;
}
@@ -5791,10 +6131,9 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
rw_unlock(&LOCK_grant);
close_thread_tables(thd);
- if (result)
- my_message(ER_REVOKE_GRANTS, ER(ER_REVOKE_GRANTS), MYF(0));
+ thd->pop_internal_handler();
- DBUG_RETURN(result);
+ DBUG_RETURN(error_handler.has_errors());
}
@@ -5961,16 +6300,16 @@ void update_schema_privilege(TABLE *table, char *buff, const char* db,
int i= 2;
CHARSET_INFO *cs= system_charset_info;
restore_record(table, s->default_values);
- table->field[0]->store(buff, strlen(buff), cs);
+ table->field[0]->store(buff, (uint) strlen(buff), cs);
if (db)
- table->field[i++]->store(db, strlen(db), cs);
+ table->field[i++]->store(db, (uint) strlen(db), cs);
if (t_name)
- table->field[i++]->store(t_name, strlen(t_name), cs);
+ table->field[i++]->store(t_name, (uint) strlen(t_name), cs);
if (column)
table->field[i++]->store(column, col_length, cs);
table->field[i++]->store(priv, priv_length, cs);
- table->field[i]->store(is_grantable, strlen(is_grantable), cs);
- table->file->write_row(table->record[0]);
+ table->field[i]->store(is_grantable, (uint) strlen(is_grantable), cs);
+ table->file->ha_write_row(table->record[0]);
}
@@ -6283,12 +6622,6 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
/* db privileges */
grant->privilege|= acl_get(sctx->host, sctx->ip, sctx->priv_user, db, 0);
- if (!grant_option)
- {
- DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege));
- DBUG_VOID_RETURN;
- }
-
/* table privileges */
rw_rdlock(&LOCK_grant);
if (grant->version != grant_version)