mirror of
https://github.com/MariaDB/server.git
synced 2025-08-07 00:04:31 +03:00
Merge bk-internal.mysql.com:/home/bk/mysql-4.1
into mysql.com:/home/dlenev/src/mysql-4.1-bg12423 sql/mysqld.cc: Auto merged sql/sql_acl.cc: Auto merged sql/sql_parse.cc: Auto merged mysql-test/r/grant2.result: Manual merge. mysql-test/t/grant2.test: Manual merge.
This commit is contained in:
@@ -122,3 +122,12 @@ flush privileges;
|
|||||||
drop database mysqltest_1;
|
drop database mysqltest_1;
|
||||||
set password = password("changed");
|
set password = password("changed");
|
||||||
ERROR 42000: Access denied for user ''@'localhost' to database 'mysql'
|
ERROR 42000: Access denied for user ''@'localhost' to database 'mysql'
|
||||||
|
lock table mysql.user write;
|
||||||
|
flush privileges;
|
||||||
|
grant all on *.* to 'mysqltest_1'@'localhost';
|
||||||
|
unlock tables;
|
||||||
|
lock table mysql.user write;
|
||||||
|
set password for 'mysqltest_1'@'localhost' = password('');
|
||||||
|
revoke all on *.* from 'mysqltest_1'@'localhost';
|
||||||
|
unlock tables;
|
||||||
|
drop user 'mysqltest_1'@'localhost';
|
||||||
|
@@ -163,4 +163,47 @@ set password = password("changed");
|
|||||||
disconnect n5;
|
disconnect n5;
|
||||||
connection default;
|
connection default;
|
||||||
|
|
||||||
|
|
||||||
|
# Bug #12423 "Deadlock when doing FLUSH PRIVILEGES and GRANT in
|
||||||
|
# multi-threaded environment". We should be able to execute FLUSH
|
||||||
|
# PRIVILEGES and SET PASSWORD simultaneously with other account
|
||||||
|
# management commands (such as GRANT and REVOKE) without causing
|
||||||
|
# deadlocks. To achieve this we should ensure that all account
|
||||||
|
# management commands take table and internal locks in the same order.
|
||||||
|
connect (con2root,localhost,root,,);
|
||||||
|
connect (con3root,localhost,root,,);
|
||||||
|
# Check that we can execute FLUSH PRIVILEGES and GRANT simultaneously
|
||||||
|
# This will check that locks are taken in proper order during both
|
||||||
|
# user/db-level and table/column-level privileges reloading.
|
||||||
|
connection default;
|
||||||
|
lock table mysql.user write;
|
||||||
|
connection con2root;
|
||||||
|
send flush privileges;
|
||||||
|
connection con3root;
|
||||||
|
send grant all on *.* to 'mysqltest_1'@'localhost';
|
||||||
|
connection default;
|
||||||
|
unlock tables;
|
||||||
|
connection con2root;
|
||||||
|
reap;
|
||||||
|
connection con3root;
|
||||||
|
reap;
|
||||||
|
# Check for simultaneous SET PASSWORD and REVOKE.
|
||||||
|
connection default;
|
||||||
|
lock table mysql.user write;
|
||||||
|
connection con2root;
|
||||||
|
send set password for 'mysqltest_1'@'localhost' = password('');
|
||||||
|
connection con3root;
|
||||||
|
send revoke all on *.* from 'mysqltest_1'@'localhost';
|
||||||
|
connection default;
|
||||||
|
unlock tables;
|
||||||
|
connection con2root;
|
||||||
|
reap;
|
||||||
|
connection con3root;
|
||||||
|
reap;
|
||||||
|
connection default;
|
||||||
|
# Clean-up
|
||||||
|
drop user 'mysqltest_1'@'localhost';
|
||||||
|
disconnect con2root;
|
||||||
|
disconnect con3root;
|
||||||
|
|
||||||
# End of 4.1 tests
|
# End of 4.1 tests
|
||||||
|
@@ -3080,7 +3080,7 @@ we force server id to 2, but this MySQL server will not act as a slave.");
|
|||||||
*/
|
*/
|
||||||
error_handler_hook = my_message_sql;
|
error_handler_hook = my_message_sql;
|
||||||
start_signal_handler(); // Creates pidfile
|
start_signal_handler(); // Creates pidfile
|
||||||
if (acl_init((THD *)0, opt_noacl) ||
|
if (acl_init(opt_noacl) ||
|
||||||
my_tz_init((THD *)0, default_tz_name, opt_bootstrap))
|
my_tz_init((THD *)0, default_tz_name, opt_bootstrap))
|
||||||
{
|
{
|
||||||
abort_loop=1;
|
abort_loop=1;
|
||||||
@@ -3097,7 +3097,7 @@ we force server id to 2, but this MySQL server will not act as a slave.");
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if (!opt_noacl)
|
if (!opt_noacl)
|
||||||
(void) grant_init((THD *)0);
|
(void) grant_init();
|
||||||
|
|
||||||
#ifdef HAVE_DLOPEN
|
#ifdef HAVE_DLOPEN
|
||||||
if (!opt_noacl)
|
if (!opt_noacl)
|
||||||
|
402
sql/sql_acl.cc
402
sql/sql_acl.cc
@@ -62,18 +62,21 @@ static HASH acl_check_hosts, column_priv_hash;
|
|||||||
static DYNAMIC_ARRAY acl_wild_hosts;
|
static DYNAMIC_ARRAY acl_wild_hosts;
|
||||||
static hash_filo *acl_cache;
|
static hash_filo *acl_cache;
|
||||||
static uint grant_version=0;
|
static uint grant_version=0;
|
||||||
static uint priv_version=0; /* Version of priv tables. incremented by acl_init */
|
static uint priv_version=0; /* Version of priv tables. incremented by acl_load */
|
||||||
static ulong get_access(TABLE *form,uint fieldnr, uint *next_field=0);
|
static ulong get_access(TABLE *form,uint fieldnr, uint *next_field=0);
|
||||||
static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b);
|
static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b);
|
||||||
static ulong get_sort(uint count,...);
|
static ulong get_sort(uint count,...);
|
||||||
static void init_check_host(void);
|
static void init_check_host(void);
|
||||||
static ACL_USER *find_acl_user(const char *host, const char *user,
|
static ACL_USER *find_acl_user(const char *host, const char *user,
|
||||||
my_bool exact);
|
my_bool exact);
|
||||||
static bool update_user_table(THD *thd, const char *host, const char *user,
|
static bool update_user_table(THD *thd, TABLE *table,
|
||||||
|
const char *host, const char *user,
|
||||||
const char *new_password, uint new_password_len);
|
const char *new_password, uint new_password_len);
|
||||||
static void update_hostname(acl_host_and_ip *host, const char *hostname);
|
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,
|
static bool compare_hostname(const acl_host_and_ip *host,const char *hostname,
|
||||||
const char *ip);
|
const char *ip);
|
||||||
|
static my_bool acl_load(THD *thd, TABLE_LIST *tables);
|
||||||
|
static my_bool grant_load(TABLE_LIST *tables);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Convert scrambled password to binary form, according to scramble type,
|
Convert scrambled password to binary form, according to scramble type,
|
||||||
@@ -118,79 +121,84 @@ static void restrict_update_of_old_passwords_var(THD *thd,
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Read grant privileges from the privilege tables in the 'mysql' database.
|
Initialize structures responsible for user/db-level privilege checking and
|
||||||
|
load privilege information for them from tables in the 'mysql' database.
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
acl_init()
|
acl_init()
|
||||||
thd Thread handler
|
dont_read_acl_tables TRUE if we want to skip loading data from
|
||||||
dont_read_acl_tables Set to 1 if run with --skip-grant
|
privilege tables and disable privilege checking.
|
||||||
|
|
||||||
|
NOTES
|
||||||
|
This function is mostly responsible for preparatory steps, main work
|
||||||
|
on initialization and grants loading is done in acl_reload().
|
||||||
|
|
||||||
RETURN VALUES
|
RETURN VALUES
|
||||||
0 ok
|
0 ok
|
||||||
1 Could not initialize grant's
|
1 Could not initialize grant's
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
my_bool acl_init(bool dont_read_acl_tables)
|
||||||
my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
|
|
||||||
{
|
{
|
||||||
THD *thd;
|
THD *thd;
|
||||||
TABLE_LIST tables[3];
|
my_bool return_val;
|
||||||
TABLE *table;
|
|
||||||
READ_RECORD read_record_info;
|
|
||||||
MYSQL_LOCK *lock;
|
|
||||||
my_bool return_val=1;
|
|
||||||
bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE;
|
|
||||||
char tmp_name[NAME_LEN+1];
|
|
||||||
|
|
||||||
DBUG_ENTER("acl_init");
|
DBUG_ENTER("acl_init");
|
||||||
|
|
||||||
if (!acl_cache)
|
acl_cache= new hash_filo(ACL_CACHE_SIZE, 0, 0,
|
||||||
acl_cache=new hash_filo(ACL_CACHE_SIZE,0,0,
|
(hash_get_key) acl_entry_get_key,
|
||||||
(hash_get_key) acl_entry_get_key,
|
(hash_free_key) free, system_charset_info);
|
||||||
(hash_free_key) free, system_charset_info);
|
|
||||||
if (dont_read_acl_tables)
|
if (dont_read_acl_tables)
|
||||||
{
|
{
|
||||||
DBUG_RETURN(0); /* purecov: tested */
|
DBUG_RETURN(0); /* purecov: tested */
|
||||||
}
|
}
|
||||||
|
|
||||||
priv_version++; /* Privileges updated */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
To be able to run this from boot, we allocate a temporary THD
|
To be able to run this from boot, we allocate a temporary THD
|
||||||
*/
|
*/
|
||||||
if (!(thd=new THD))
|
if (!(thd=new THD))
|
||||||
DBUG_RETURN(1); /* purecov: inspected */
|
DBUG_RETURN(1); /* purecov: inspected */
|
||||||
thd->store_globals();
|
thd->store_globals();
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
by zeros at startup.
|
||||||
|
*/
|
||||||
|
return_val= acl_reload(thd);
|
||||||
|
delete thd;
|
||||||
|
/* Remember that we don't have a THD */
|
||||||
|
my_pthread_setspecific_ptr(THR_THD, 0);
|
||||||
|
DBUG_RETURN(return_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Initialize structures responsible for user/db-level privilege checking
|
||||||
|
and load information about grants from open privilege tables.
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
acl_load()
|
||||||
|
thd Current thread
|
||||||
|
tables List containing open "mysql.host", "mysql.user" and
|
||||||
|
"mysql.db" tables.
|
||||||
|
|
||||||
|
RETURN VALUES
|
||||||
|
FALSE Success
|
||||||
|
TRUE Error
|
||||||
|
*/
|
||||||
|
|
||||||
|
static my_bool acl_load(THD *thd, TABLE_LIST *tables)
|
||||||
|
{
|
||||||
|
TABLE *table;
|
||||||
|
READ_RECORD read_record_info;
|
||||||
|
my_bool return_val= 1;
|
||||||
|
bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE;
|
||||||
|
char tmp_name[NAME_LEN+1];
|
||||||
|
DBUG_ENTER("acl_load");
|
||||||
|
|
||||||
|
priv_version++; /* Privileges updated */
|
||||||
|
|
||||||
acl_cache->clear(1); // Clear locked hostname cache
|
acl_cache->clear(1); // Clear locked hostname cache
|
||||||
thd->db= my_strdup("mysql",MYF(0));
|
|
||||||
thd->db_length=5; // Safety
|
|
||||||
bzero((char*) &tables,sizeof(tables));
|
|
||||||
tables[0].alias=tables[0].real_name=(char*) "host";
|
|
||||||
tables[1].alias=tables[1].real_name=(char*) "user";
|
|
||||||
tables[2].alias=tables[2].real_name=(char*) "db";
|
|
||||||
tables[0].next=tables+1;
|
|
||||||
tables[1].next=tables+2;
|
|
||||||
tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_READ;
|
|
||||||
tables[0].db=tables[1].db=tables[2].db=thd->db;
|
|
||||||
|
|
||||||
uint counter;
|
|
||||||
if (open_tables(thd, tables, &counter))
|
|
||||||
{
|
|
||||||
sql_print_error("Fatal error: Can't open privilege tables: %s",
|
|
||||||
thd->net.last_error);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
TABLE *ptr[3]; // Lock tables for quick update
|
|
||||||
ptr[0]= tables[0].table;
|
|
||||||
ptr[1]= tables[1].table;
|
|
||||||
ptr[2]= tables[2].table;
|
|
||||||
if (! (lock= mysql_lock_tables(thd, ptr, 3, 0)))
|
|
||||||
{
|
|
||||||
sql_print_error("Fatal error: Can't lock privilege tables: %s",
|
|
||||||
thd->net.last_error);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
init_sql_alloc(&mem, ACL_ALLOC_BLOCK_SIZE, 0);
|
init_sql_alloc(&mem, ACL_ALLOC_BLOCK_SIZE, 0);
|
||||||
init_read_record(&read_record_info,thd,table= tables[0].table,NULL,1,0);
|
init_read_record(&read_record_info,thd,table= tables[0].table,NULL,1,0);
|
||||||
VOID(my_init_dynamic_array(&acl_hosts,sizeof(ACL_HOST),20,50));
|
VOID(my_init_dynamic_array(&acl_hosts,sizeof(ACL_HOST),20,50));
|
||||||
@@ -432,21 +440,10 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
|
|||||||
freeze_size(&acl_dbs);
|
freeze_size(&acl_dbs);
|
||||||
init_check_host();
|
init_check_host();
|
||||||
|
|
||||||
mysql_unlock_tables(thd, lock);
|
|
||||||
initialized=1;
|
initialized=1;
|
||||||
thd->version--; // Force close to free memory
|
|
||||||
return_val=0;
|
return_val=0;
|
||||||
|
|
||||||
end:
|
end:
|
||||||
close_thread_tables(thd);
|
|
||||||
delete thd;
|
|
||||||
if (org_thd)
|
|
||||||
org_thd->store_globals(); /* purecov: inspected */
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Remember that we don't have a THD */
|
|
||||||
my_pthread_setspecific_ptr(THR_THD, 0);
|
|
||||||
}
|
|
||||||
DBUG_RETURN(return_val);
|
DBUG_RETURN(return_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -470,26 +467,60 @@ void acl_free(bool end)
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Forget current privileges and read new privileges from the privilege tables
|
Forget current user/db-level privileges and read new privileges
|
||||||
|
from the privilege tables.
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
acl_reload()
|
acl_reload()
|
||||||
thd Thread handle (can be NULL)
|
thd Current thread
|
||||||
|
|
||||||
|
NOTE
|
||||||
|
All tables of calling thread which were open and locked by LOCK TABLES
|
||||||
|
statement will be unlocked and closed.
|
||||||
|
This function is also used for initialization of structures responsible
|
||||||
|
for user/db-level privilege checking.
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
FALSE Success
|
||||||
|
TRUE Failure
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void acl_reload(THD *thd)
|
my_bool acl_reload(THD *thd)
|
||||||
{
|
{
|
||||||
|
TABLE_LIST tables[3];
|
||||||
DYNAMIC_ARRAY old_acl_hosts,old_acl_users,old_acl_dbs;
|
DYNAMIC_ARRAY old_acl_hosts,old_acl_users,old_acl_dbs;
|
||||||
MEM_ROOT old_mem;
|
MEM_ROOT old_mem;
|
||||||
bool old_initialized;
|
bool old_initialized;
|
||||||
|
my_bool return_val= 1;
|
||||||
DBUG_ENTER("acl_reload");
|
DBUG_ENTER("acl_reload");
|
||||||
|
|
||||||
if (thd && thd->locked_tables)
|
if (thd->locked_tables)
|
||||||
{ // Can't have locked tables here
|
{ // Can't have locked tables here
|
||||||
thd->lock=thd->locked_tables;
|
thd->lock=thd->locked_tables;
|
||||||
thd->locked_tables=0;
|
thd->locked_tables=0;
|
||||||
close_thread_tables(thd);
|
close_thread_tables(thd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
To avoid deadlocks we should obtain table locks before
|
||||||
|
obtaining acl_cache->lock mutex.
|
||||||
|
*/
|
||||||
|
bzero((char*) tables, sizeof(tables));
|
||||||
|
tables[0].alias=tables[0].real_name=(char*) "host";
|
||||||
|
tables[1].alias=tables[1].real_name=(char*) "user";
|
||||||
|
tables[2].alias=tables[2].real_name=(char*) "db";
|
||||||
|
tables[0].db=tables[1].db=tables[2].db= (char*) "mysql";
|
||||||
|
tables[0].next= tables+1;
|
||||||
|
tables[1].next= tables+2;
|
||||||
|
tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_READ;
|
||||||
|
|
||||||
|
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);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
if ((old_initialized=initialized))
|
if ((old_initialized=initialized))
|
||||||
VOID(pthread_mutex_lock(&acl_cache->lock));
|
VOID(pthread_mutex_lock(&acl_cache->lock));
|
||||||
|
|
||||||
@@ -500,7 +531,7 @@ void acl_reload(THD *thd)
|
|||||||
delete_dynamic(&acl_wild_hosts);
|
delete_dynamic(&acl_wild_hosts);
|
||||||
hash_free(&acl_check_hosts);
|
hash_free(&acl_check_hosts);
|
||||||
|
|
||||||
if (acl_init(thd, 0))
|
if ((return_val= acl_load(thd, tables)))
|
||||||
{ // Error. Revert to old list
|
{ // Error. Revert to old list
|
||||||
DBUG_PRINT("error",("Reverting to old privileges"));
|
DBUG_PRINT("error",("Reverting to old privileges"));
|
||||||
acl_free(); /* purecov: inspected */
|
acl_free(); /* purecov: inspected */
|
||||||
@@ -519,7 +550,9 @@ void acl_reload(THD *thd)
|
|||||||
}
|
}
|
||||||
if (old_initialized)
|
if (old_initialized)
|
||||||
VOID(pthread_mutex_unlock(&acl_cache->lock));
|
VOID(pthread_mutex_unlock(&acl_cache->lock));
|
||||||
DBUG_VOID_RETURN;
|
end:
|
||||||
|
close_thread_tables(thd);
|
||||||
|
DBUG_RETURN(return_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1230,7 +1263,13 @@ bool check_change_password(THD *thd, const char *host, const char *user,
|
|||||||
bool change_password(THD *thd, const char *host, const char *user,
|
bool change_password(THD *thd, const char *host, const char *user,
|
||||||
char *new_password)
|
char *new_password)
|
||||||
{
|
{
|
||||||
|
TABLE_LIST tables;
|
||||||
|
TABLE *table;
|
||||||
|
/* 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= strlen(new_password);
|
||||||
|
bool result= 1;
|
||||||
DBUG_ENTER("change_password");
|
DBUG_ENTER("change_password");
|
||||||
DBUG_PRINT("enter",("host: '%s' user: '%s' new_password: '%s'",
|
DBUG_PRINT("enter",("host: '%s' user: '%s' new_password: '%s'",
|
||||||
host,user,new_password));
|
host,user,new_password));
|
||||||
@@ -1239,42 +1278,71 @@ bool change_password(THD *thd, const char *host, const char *user,
|
|||||||
if (check_change_password(thd, host, user, new_password, new_password_len))
|
if (check_change_password(thd, host, user, new_password, new_password_len))
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
|
bzero((char*) &tables, sizeof(tables));
|
||||||
|
tables.alias=tables.real_name= (char*) "user";
|
||||||
|
tables.db= (char*) "mysql";
|
||||||
|
|
||||||
|
#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)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
The tables must be marked "updating" so that tables_ok() takes them into
|
||||||
|
account in tests. It's ok to leave 'updating' set after tables_ok.
|
||||||
|
*/
|
||||||
|
tables.updating= 1;
|
||||||
|
/* Thanks to bzero, tables.next==0 */
|
||||||
|
if (!tables_ok(0, &tables))
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!(table= open_ltable(thd, &tables, TL_WRITE)))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
VOID(pthread_mutex_lock(&acl_cache->lock));
|
VOID(pthread_mutex_lock(&acl_cache->lock));
|
||||||
ACL_USER *acl_user;
|
ACL_USER *acl_user;
|
||||||
if (!(acl_user= find_acl_user(host, user, TRUE)))
|
if (!(acl_user= find_acl_user(host, user, TRUE)))
|
||||||
{
|
{
|
||||||
VOID(pthread_mutex_unlock(&acl_cache->lock));
|
VOID(pthread_mutex_unlock(&acl_cache->lock));
|
||||||
send_error(thd, ER_PASSWORD_NO_MATCH);
|
send_error(thd, ER_PASSWORD_NO_MATCH);
|
||||||
DBUG_RETURN(1);
|
goto end;
|
||||||
}
|
}
|
||||||
/* update loaded acl entry: */
|
/* update loaded acl entry: */
|
||||||
set_user_salt(acl_user, new_password, new_password_len);
|
set_user_salt(acl_user, new_password, new_password_len);
|
||||||
|
|
||||||
if (update_user_table(thd,
|
if (update_user_table(thd, table,
|
||||||
acl_user->host.hostname ? acl_user->host.hostname : "",
|
acl_user->host.hostname ? acl_user->host.hostname : "",
|
||||||
acl_user->user ? acl_user->user : "",
|
acl_user->user ? acl_user->user : "",
|
||||||
new_password, new_password_len))
|
new_password, new_password_len))
|
||||||
{
|
{
|
||||||
VOID(pthread_mutex_unlock(&acl_cache->lock)); /* purecov: deadcode */
|
VOID(pthread_mutex_unlock(&acl_cache->lock)); /* purecov: deadcode */
|
||||||
send_error(thd,0); /* purecov: deadcode */
|
send_error(thd,0); /* purecov: deadcode */
|
||||||
DBUG_RETURN(1); /* purecov: deadcode */
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
acl_cache->clear(1); // Clear locked hostname cache
|
acl_cache->clear(1); // Clear locked hostname cache
|
||||||
VOID(pthread_mutex_unlock(&acl_cache->lock));
|
VOID(pthread_mutex_unlock(&acl_cache->lock));
|
||||||
|
result= 0;
|
||||||
char buff[512]; /* Extend with extended password length*/
|
query_length=
|
||||||
ulong query_length=
|
|
||||||
my_sprintf(buff,
|
my_sprintf(buff,
|
||||||
(buff,"SET PASSWORD FOR \"%-.120s\"@\"%-.120s\"=\"%-.120s\"",
|
(buff,"SET PASSWORD FOR \"%-.120s\"@\"%-.120s\"=\"%-.120s\"",
|
||||||
acl_user->user ? acl_user->user : "",
|
acl_user->user ? acl_user->user : "",
|
||||||
acl_user->host.hostname ? acl_user->host.hostname : "",
|
acl_user->host.hostname ? acl_user->host.hostname : "",
|
||||||
new_password));
|
new_password));
|
||||||
thd->clear_error();
|
|
||||||
mysql_update_log.write(thd, buff, query_length);
|
mysql_update_log.write(thd, buff, query_length);
|
||||||
Query_log_event qinfo(thd, buff, query_length, 0, FALSE);
|
if (mysql_bin_log.is_open())
|
||||||
mysql_bin_log.write(&qinfo);
|
{
|
||||||
DBUG_RETURN(0);
|
thd->clear_error();
|
||||||
|
Query_log_event qinfo(thd, buff, query_length, 0, FALSE);
|
||||||
|
mysql_bin_log.write(&qinfo);
|
||||||
|
}
|
||||||
|
end:
|
||||||
|
close_thread_tables(thd);
|
||||||
|
DBUG_RETURN(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1388,43 +1456,28 @@ bool hostname_requires_resolving(const char *hostname)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Update grants in the user and database privilege tables
|
Update record for user in mysql.user privilege table with new password.
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
update_user_table()
|
||||||
|
thd Thread handle
|
||||||
|
table Pointer to TABLE object for open mysql.user table
|
||||||
|
host/user Hostname/username pair identifying user for which
|
||||||
|
new password should be set
|
||||||
|
new_password New password
|
||||||
|
new_password_len Length of new password
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static bool update_user_table(THD *thd, const char *host, const char *user,
|
static bool update_user_table(THD *thd, TABLE *table,
|
||||||
|
const char *host, const char *user,
|
||||||
const char *new_password, uint new_password_len)
|
const char *new_password, uint new_password_len)
|
||||||
{
|
{
|
||||||
TABLE_LIST tables;
|
int error;
|
||||||
TABLE *table;
|
|
||||||
bool error=1;
|
|
||||||
DBUG_ENTER("update_user_table");
|
DBUG_ENTER("update_user_table");
|
||||||
DBUG_PRINT("enter",("user: %s host: %s",user,host));
|
DBUG_PRINT("enter",("user: %s host: %s",user,host));
|
||||||
|
|
||||||
bzero((char*) &tables,sizeof(tables));
|
|
||||||
tables.alias=tables.real_name=(char*) "user";
|
|
||||||
tables.db=(char*) "mysql";
|
|
||||||
|
|
||||||
#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)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
The tables must be marked "updating" so that tables_ok() takes them into
|
|
||||||
account in tests. It's ok to leave 'updating' set after tables_ok.
|
|
||||||
*/
|
|
||||||
tables.updating= 1;
|
|
||||||
/* Thanks to bzero, tables.next==0 */
|
|
||||||
if (!tables_ok(0, &tables))
|
|
||||||
DBUG_RETURN(0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!(table=open_ltable(thd,&tables,TL_WRITE)))
|
|
||||||
DBUG_RETURN(1); /* purecov: deadcode */
|
|
||||||
table->field[0]->store(host,(uint) strlen(host), &my_charset_latin1);
|
table->field[0]->store(host,(uint) strlen(host), &my_charset_latin1);
|
||||||
table->field[1]->store(user,(uint) strlen(user), &my_charset_latin1);
|
table->field[1]->store(user,(uint) strlen(user), &my_charset_latin1);
|
||||||
|
|
||||||
@@ -1442,13 +1495,9 @@ static bool update_user_table(THD *thd, const char *host, const char *user,
|
|||||||
if ((error=table->file->update_row(table->record[1],table->record[0])))
|
if ((error=table->file->update_row(table->record[1],table->record[0])))
|
||||||
{
|
{
|
||||||
table->file->print_error(error,MYF(0)); /* purecov: deadcode */
|
table->file->print_error(error,MYF(0)); /* purecov: deadcode */
|
||||||
goto end; /* purecov: deadcode */
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
error=0; // Record updated
|
DBUG_RETURN(0);
|
||||||
|
|
||||||
end:
|
|
||||||
close_thread_tables(thd);
|
|
||||||
DBUG_RETURN(error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -2620,18 +2669,59 @@ void grant_free(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Init grant array if possible */
|
/*
|
||||||
|
Initialize structures responsible for table/column-level privilege checking
|
||||||
|
and load information for them from tables in the 'mysql' database.
|
||||||
|
|
||||||
my_bool grant_init(THD *org_thd)
|
SYNOPSIS
|
||||||
|
grant_init()
|
||||||
|
|
||||||
|
RETURN VALUES
|
||||||
|
0 ok
|
||||||
|
1 Could not initialize grant's
|
||||||
|
*/
|
||||||
|
|
||||||
|
my_bool grant_init()
|
||||||
{
|
{
|
||||||
THD *thd;
|
THD *thd;
|
||||||
TABLE_LIST tables[2];
|
my_bool return_val;
|
||||||
MYSQL_LOCK *lock;
|
DBUG_ENTER("grant_init");
|
||||||
|
|
||||||
|
if (!(thd= new THD))
|
||||||
|
DBUG_RETURN(1); /* purecov: deadcode */
|
||||||
|
thd->store_globals();
|
||||||
|
return_val= grant_reload(thd);
|
||||||
|
delete thd;
|
||||||
|
/* Remember that we don't have a THD */
|
||||||
|
my_pthread_setspecific_ptr(THR_THD, 0);
|
||||||
|
DBUG_RETURN(return_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Initialize structures responsible for table/column-level privilege
|
||||||
|
checking and load information about grants from open privilege tables.
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
grant_load()
|
||||||
|
thd Current thread
|
||||||
|
tables List containing open "mysql.tables_priv" and
|
||||||
|
"mysql.columns_priv" tables.
|
||||||
|
|
||||||
|
RETURN VALUES
|
||||||
|
FALSE - success
|
||||||
|
TRUE - error
|
||||||
|
*/
|
||||||
|
|
||||||
|
static my_bool grant_load(TABLE_LIST *tables)
|
||||||
|
{
|
||||||
MEM_ROOT *memex_ptr;
|
MEM_ROOT *memex_ptr;
|
||||||
my_bool return_val= 1;
|
my_bool return_val= 1;
|
||||||
TABLE *t_table, *c_table;
|
TABLE *t_table, *c_table;
|
||||||
bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE;
|
bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE;
|
||||||
DBUG_ENTER("grant_init");
|
MEM_ROOT **save_mem_root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**,
|
||||||
|
THR_MALLOC);
|
||||||
|
DBUG_ENTER("grant_load");
|
||||||
|
|
||||||
grant_option = FALSE;
|
grant_option = FALSE;
|
||||||
(void) hash_init(&column_priv_hash,&my_charset_latin1,
|
(void) hash_init(&column_priv_hash,&my_charset_latin1,
|
||||||
@@ -2639,32 +2729,6 @@ my_bool grant_init(THD *org_thd)
|
|||||||
(hash_free_key) free_grant_table,0);
|
(hash_free_key) free_grant_table,0);
|
||||||
init_sql_alloc(&memex, ACL_ALLOC_BLOCK_SIZE, 0);
|
init_sql_alloc(&memex, ACL_ALLOC_BLOCK_SIZE, 0);
|
||||||
|
|
||||||
/* Don't do anything if running with --skip-grant */
|
|
||||||
if (!initialized)
|
|
||||||
DBUG_RETURN(0); /* purecov: tested */
|
|
||||||
|
|
||||||
if (!(thd=new THD))
|
|
||||||
DBUG_RETURN(1); /* purecov: deadcode */
|
|
||||||
thd->store_globals();
|
|
||||||
thd->db= my_strdup("mysql",MYF(0));
|
|
||||||
thd->db_length=5; // Safety
|
|
||||||
bzero((char*) &tables, sizeof(tables));
|
|
||||||
tables[0].alias=tables[0].real_name= (char*) "tables_priv";
|
|
||||||
tables[1].alias=tables[1].real_name= (char*) "columns_priv";
|
|
||||||
tables[0].next=tables+1;
|
|
||||||
tables[0].lock_type=tables[1].lock_type=TL_READ;
|
|
||||||
tables[0].db=tables[1].db=thd->db;
|
|
||||||
|
|
||||||
uint counter;
|
|
||||||
if (open_tables(thd, tables, &counter))
|
|
||||||
goto end;
|
|
||||||
|
|
||||||
TABLE *ptr[2]; // Lock tables for quick update
|
|
||||||
ptr[0]= tables[0].table;
|
|
||||||
ptr[1]= tables[1].table;
|
|
||||||
if (! (lock= mysql_lock_tables(thd, ptr, 2, 0)))
|
|
||||||
goto end;
|
|
||||||
|
|
||||||
t_table = tables[0].table; c_table = tables[1].table;
|
t_table = tables[0].table; c_table = tables[1].table;
|
||||||
t_table->file->ha_index_init(0);
|
t_table->file->ha_index_init(0);
|
||||||
if (t_table->file->index_first(t_table->record[0]))
|
if (t_table->file->index_first(t_table->record[0]))
|
||||||
@@ -2674,7 +2738,6 @@ my_bool grant_init(THD *org_thd)
|
|||||||
}
|
}
|
||||||
grant_option= TRUE;
|
grant_option= TRUE;
|
||||||
|
|
||||||
/* Will be restored by org_thd->store_globals() */
|
|
||||||
memex_ptr= &memex;
|
memex_ptr= &memex;
|
||||||
my_pthread_setspecific_ptr(THR_MALLOC, &memex_ptr);
|
my_pthread_setspecific_ptr(THR_MALLOC, &memex_ptr);
|
||||||
do
|
do
|
||||||
@@ -2711,48 +2774,63 @@ my_bool grant_init(THD *org_thd)
|
|||||||
|
|
||||||
end_unlock:
|
end_unlock:
|
||||||
t_table->file->ha_index_end();
|
t_table->file->ha_index_end();
|
||||||
mysql_unlock_tables(thd, lock);
|
my_pthread_setspecific_ptr(THR_MALLOC, save_mem_root_ptr);
|
||||||
thd->version--; // Force close to free memory
|
|
||||||
|
|
||||||
end:
|
|
||||||
close_thread_tables(thd);
|
|
||||||
delete thd;
|
|
||||||
if (org_thd)
|
|
||||||
org_thd->store_globals();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Remember that we don't have a THD */
|
|
||||||
my_pthread_setspecific_ptr(THR_THD, 0);
|
|
||||||
}
|
|
||||||
DBUG_RETURN(return_val);
|
DBUG_RETURN(return_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Reload grant array (table and column privileges) if possible
|
Reload information about table and column level privileges if possible.
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
grant_reload()
|
grant_reload()
|
||||||
thd Thread handler (can be NULL)
|
thd Current thread
|
||||||
|
|
||||||
NOTES
|
NOTES
|
||||||
Locked tables are checked by acl_init and doesn't have to be checked here
|
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 VALUE
|
||||||
|
FALSE Success
|
||||||
|
TRUE Error
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void grant_reload(THD *thd)
|
my_bool grant_reload(THD *thd)
|
||||||
{
|
{
|
||||||
|
TABLE_LIST tables[2];
|
||||||
HASH old_column_priv_hash;
|
HASH old_column_priv_hash;
|
||||||
bool old_grant_option;
|
bool old_grant_option;
|
||||||
MEM_ROOT old_mem;
|
MEM_ROOT old_mem;
|
||||||
|
my_bool return_val= 1;
|
||||||
DBUG_ENTER("grant_reload");
|
DBUG_ENTER("grant_reload");
|
||||||
|
|
||||||
|
/* Don't do anything if running with --skip-grant-tables */
|
||||||
|
if (!initialized)
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
|
||||||
|
bzero((char*) tables, sizeof(tables));
|
||||||
|
tables[0].alias=tables[0].real_name= (char*) "tables_priv";
|
||||||
|
tables[1].alias=tables[1].real_name= (char*) "columns_priv";
|
||||||
|
tables[0].db=tables[1].db= (char *) "mysql";
|
||||||
|
tables[0].next=tables+1;
|
||||||
|
tables[0].lock_type=tables[1].lock_type=TL_READ;
|
||||||
|
|
||||||
|
/*
|
||||||
|
To avoid deadlocks we should obtain table locks before
|
||||||
|
obtaining LOCK_grant rwlock.
|
||||||
|
*/
|
||||||
|
if (simple_open_n_lock_tables(thd, tables))
|
||||||
|
goto end;
|
||||||
|
|
||||||
rw_wrlock(&LOCK_grant);
|
rw_wrlock(&LOCK_grant);
|
||||||
grant_version++;
|
grant_version++;
|
||||||
old_column_priv_hash= column_priv_hash;
|
old_column_priv_hash= column_priv_hash;
|
||||||
old_grant_option= grant_option;
|
old_grant_option= grant_option;
|
||||||
old_mem= memex;
|
old_mem= memex;
|
||||||
|
|
||||||
if (grant_init(thd))
|
if ((return_val= grant_load(tables)))
|
||||||
{ // Error. Revert to old hash
|
{ // Error. Revert to old hash
|
||||||
DBUG_PRINT("error",("Reverting to old privileges"));
|
DBUG_PRINT("error",("Reverting to old privileges"));
|
||||||
grant_free(); /* purecov: deadcode */
|
grant_free(); /* purecov: deadcode */
|
||||||
@@ -2766,7 +2844,9 @@ void grant_reload(THD *thd)
|
|||||||
free_root(&old_mem,MYF(0));
|
free_root(&old_mem,MYF(0));
|
||||||
}
|
}
|
||||||
rw_unlock(&LOCK_grant);
|
rw_unlock(&LOCK_grant);
|
||||||
DBUG_VOID_RETURN;
|
end:
|
||||||
|
close_thread_tables(thd);
|
||||||
|
DBUG_RETURN(return_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -134,8 +134,8 @@ public:
|
|||||||
/* prototypes */
|
/* prototypes */
|
||||||
|
|
||||||
bool hostname_requires_resolving(const char *hostname);
|
bool hostname_requires_resolving(const char *hostname);
|
||||||
my_bool acl_init(THD *thd, bool dont_read_acl_tables);
|
my_bool acl_init(bool dont_read_acl_tables);
|
||||||
void acl_reload(THD *thd);
|
my_bool acl_reload(THD *thd);
|
||||||
void acl_free(bool end=0);
|
void acl_free(bool end=0);
|
||||||
ulong acl_get(const char *host, const char *ip,
|
ulong acl_get(const char *host, const char *ip,
|
||||||
const char *user, const char *db, my_bool db_is_pattern);
|
const char *user, const char *db, my_bool db_is_pattern);
|
||||||
@@ -151,9 +151,9 @@ int mysql_grant(THD *thd, const char *db, List <LEX_USER> &user_list,
|
|||||||
int mysql_table_grant(THD *thd, TABLE_LIST *table, List <LEX_USER> &user_list,
|
int mysql_table_grant(THD *thd, TABLE_LIST *table, List <LEX_USER> &user_list,
|
||||||
List <LEX_COLUMN> &column_list, ulong rights,
|
List <LEX_COLUMN> &column_list, ulong rights,
|
||||||
bool revoke);
|
bool revoke);
|
||||||
my_bool grant_init(THD *thd);
|
my_bool grant_init();
|
||||||
void grant_free(void);
|
void grant_free(void);
|
||||||
void grant_reload(THD *thd);
|
my_bool grant_reload(THD *thd);
|
||||||
bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
|
bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
|
||||||
uint show_command, uint number, bool dont_print_error);
|
uint show_command, uint number, bool dont_print_error);
|
||||||
bool check_grant_column (THD *thd,TABLE *table, const char *name, uint length,
|
bool check_grant_column (THD *thd,TABLE *table, const char *name, uint length,
|
||||||
|
@@ -4988,10 +4988,27 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
|
|||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
if (options & REFRESH_GRANT)
|
if (options & REFRESH_GRANT)
|
||||||
{
|
{
|
||||||
acl_reload(thd);
|
THD *tmp_thd= 0;
|
||||||
grant_reload(thd);
|
/*
|
||||||
if (mqh_used)
|
If reload_acl_and_cache() is called from SIGHUP handler we have to
|
||||||
reset_mqh(thd,(LEX_USER *) NULL,TRUE);
|
allocate temporary THD for execution of acl_reload()/grant_reload().
|
||||||
|
*/
|
||||||
|
if (!thd && (thd= (tmp_thd= new THD)))
|
||||||
|
thd->store_globals();
|
||||||
|
if (thd)
|
||||||
|
{
|
||||||
|
(void)acl_reload(thd);
|
||||||
|
(void)grant_reload(thd);
|
||||||
|
if (mqh_used)
|
||||||
|
reset_mqh(thd, (LEX_USER *) NULL, TRUE);
|
||||||
|
}
|
||||||
|
if (tmp_thd)
|
||||||
|
{
|
||||||
|
delete tmp_thd;
|
||||||
|
/* Remember that we don't have a THD */
|
||||||
|
my_pthread_setspecific_ptr(THR_THD, 0);
|
||||||
|
thd= 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (options & REFRESH_LOG)
|
if (options & REFRESH_LOG)
|
||||||
|
Reference in New Issue
Block a user