summaryrefslogtreecommitdiff
path: root/sql/sql_acl.cc
diff options
context:
space:
mode:
authorunknown <dlenev@mysql.com>2005-09-01 17:01:25 +0400
committerunknown <dlenev@mysql.com>2005-09-01 17:01:25 +0400
commit84ddd543c7c10b8022e3b22d1913faa3704d59a8 (patch)
tree2ba4742d506ba1b6e095df67d530e67f6b82ae7c /sql/sql_acl.cc
parent3aa2467ebbf7b86448fa270b3d77e497f9e2dd11 (diff)
parent2a64e9a2e89456c412ba1d53026a92a53d28940c (diff)
downloadmariadb-git-84ddd543c7c10b8022e3b22d1913faa3704d59a8.tar.gz
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.
Diffstat (limited to 'sql/sql_acl.cc')
-rw-r--r--sql/sql_acl.cc402
1 files changed, 241 insertions, 161 deletions
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 813754ad937..1b5f69c7873 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -62,18 +62,21 @@ static HASH acl_check_hosts, column_priv_hash;
static DYNAMIC_ARRAY acl_wild_hosts;
static hash_filo *acl_cache;
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 int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b);
static ulong get_sort(uint count,...);
static void init_check_host(void);
static ACL_USER *find_acl_user(const char *host, const char *user,
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);
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);
/*
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
acl_init()
- thd Thread handler
- dont_read_acl_tables Set to 1 if run with --skip-grant
+ dont_read_acl_tables TRUE if we want to skip loading data from
+ 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
0 ok
1 Could not initialize grant's
*/
-
-my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
+my_bool acl_init(bool dont_read_acl_tables)
{
THD *thd;
- TABLE_LIST tables[3];
- 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];
-
+ my_bool return_val;
DBUG_ENTER("acl_init");
- if (!acl_cache)
- acl_cache=new hash_filo(ACL_CACHE_SIZE,0,0,
- (hash_get_key) acl_entry_get_key,
- (hash_free_key) free, system_charset_info);
+ acl_cache= new hash_filo(ACL_CACHE_SIZE, 0, 0,
+ (hash_get_key) acl_entry_get_key,
+ (hash_free_key) free, system_charset_info);
if (dont_read_acl_tables)
{
DBUG_RETURN(0); /* purecov: tested */
}
- priv_version++; /* Privileges updated */
-
/*
To be able to run this from boot, we allocate a temporary THD
*/
if (!(thd=new THD))
DBUG_RETURN(1); /* purecov: inspected */
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
- 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_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));
@@ -432,21 +440,10 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
freeze_size(&acl_dbs);
init_check_host();
- mysql_unlock_tables(thd, lock);
initialized=1;
- thd->version--; // Force close to free memory
return_val=0;
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);
}
@@ -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
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;
MEM_ROOT old_mem;
bool old_initialized;
+ my_bool return_val= 1;
DBUG_ENTER("acl_reload");
- if (thd && thd->locked_tables)
+ if (thd->locked_tables)
{ // Can't have locked tables here
thd->lock=thd->locked_tables;
thd->locked_tables=0;
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))
VOID(pthread_mutex_lock(&acl_cache->lock));
@@ -500,7 +531,7 @@ void acl_reload(THD *thd)
delete_dynamic(&acl_wild_hosts);
hash_free(&acl_check_hosts);
- if (acl_init(thd, 0))
+ if ((return_val= acl_load(thd, tables)))
{ // Error. Revert to old list
DBUG_PRINT("error",("Reverting to old privileges"));
acl_free(); /* purecov: inspected */
@@ -519,7 +550,9 @@ void acl_reload(THD *thd)
}
if (old_initialized)
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,
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);
+ bool result= 1;
DBUG_ENTER("change_password");
DBUG_PRINT("enter",("host: '%s' user: '%s' new_password: '%s'",
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))
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));
ACL_USER *acl_user;
if (!(acl_user= find_acl_user(host, user, TRUE)))
{
VOID(pthread_mutex_unlock(&acl_cache->lock));
send_error(thd, ER_PASSWORD_NO_MATCH);
- DBUG_RETURN(1);
+ goto end;
}
/* update loaded acl entry: */
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->user ? acl_user->user : "",
new_password, new_password_len))
{
VOID(pthread_mutex_unlock(&acl_cache->lock)); /* purecov: deadcode */
send_error(thd,0); /* purecov: deadcode */
- DBUG_RETURN(1); /* purecov: deadcode */
+ goto end;
}
acl_cache->clear(1); // Clear locked hostname cache
VOID(pthread_mutex_unlock(&acl_cache->lock));
-
- char buff[512]; /* Extend with extended password length*/
- ulong query_length=
+ result= 0;
+ query_length=
my_sprintf(buff,
(buff,"SET PASSWORD FOR \"%-.120s\"@\"%-.120s\"=\"%-.120s\"",
acl_user->user ? acl_user->user : "",
acl_user->host.hostname ? acl_user->host.hostname : "",
new_password));
- thd->clear_error();
mysql_update_log.write(thd, buff, query_length);
- Query_log_event qinfo(thd, buff, query_length, 0, FALSE);
- mysql_bin_log.write(&qinfo);
- DBUG_RETURN(0);
+ if (mysql_bin_log.is_open())
+ {
+ 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;
}
+
/*
- 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)
{
- TABLE_LIST tables;
- TABLE *table;
- bool error=1;
+ int error;
DBUG_ENTER("update_user_table");
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[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])))
{
table->file->print_error(error,MYF(0)); /* purecov: deadcode */
- goto end; /* purecov: deadcode */
+ DBUG_RETURN(1);
}
- error=0; // Record updated
-
-end:
- close_thread_tables(thd);
- DBUG_RETURN(error);
+ DBUG_RETURN(0);
}
@@ -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;
- TABLE_LIST tables[2];
- MYSQL_LOCK *lock;
+ my_bool return_val;
+ 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;
my_bool return_val= 1;
TABLE *t_table, *c_table;
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;
(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);
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->file->ha_index_init(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;
- /* Will be restored by org_thd->store_globals() */
memex_ptr= &memex;
my_pthread_setspecific_ptr(THR_MALLOC, &memex_ptr);
do
@@ -2711,48 +2774,63 @@ my_bool grant_init(THD *org_thd)
end_unlock:
t_table->file->ha_index_end();
- mysql_unlock_tables(thd, lock);
- 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);
- }
+ my_pthread_setspecific_ptr(THR_MALLOC, save_mem_root_ptr);
DBUG_RETURN(return_val);
}
/*
- Reload grant array (table and column privileges) if possible
+ Reload information about table and column level privileges if possible.
SYNOPSIS
grant_reload()
- thd Thread handler (can be NULL)
+ thd Current thread
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;
bool old_grant_option;
MEM_ROOT old_mem;
+ my_bool return_val= 1;
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);
grant_version++;
old_column_priv_hash= column_priv_hash;
old_grant_option= grant_option;
old_mem= memex;
- if (grant_init(thd))
+ if ((return_val= grant_load(tables)))
{ // Error. Revert to old hash
DBUG_PRINT("error",("Reverting to old privileges"));
grant_free(); /* purecov: deadcode */
@@ -2766,7 +2844,9 @@ void grant_reload(THD *thd)
free_root(&old_mem,MYF(0));
}
rw_unlock(&LOCK_grant);
- DBUG_VOID_RETURN;
+end:
+ close_thread_tables(thd);
+ DBUG_RETURN(return_val);
}