summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <gluh@gluh.mysql.r18.ru>2005-03-05 14:35:32 +0300
committerunknown <gluh@gluh.mysql.r18.ru>2005-03-05 14:35:32 +0300
commit0d7e68c92a4ded30d02a66b434cbe624c3df5e1e (patch)
treed882344cb6e35451bd9dffbfd69b088912a9fce8
parent0ae5efb4dc1df3af598030cf7b96b95841306c70 (diff)
downloadmariadb-git-0d7e68c92a4ded30d02a66b434cbe624c3df5e1e.tar.gz
WL2131: Access control for SHOW ... PROCEDURE|FUNCTION ...
-rw-r--r--mysql-test/r/information_schema.result45
-rw-r--r--mysql-test/t/information_schema.test37
-rw-r--r--sql/mysql_priv.h1
-rw-r--r--sql/sp_head.cc35
-rw-r--r--sql/sql_acl.cc31
-rw-r--r--sql/sql_acl.h4
-rw-r--r--sql/sql_parse.cc32
-rw-r--r--sql/sql_show.cc52
8 files changed, 206 insertions, 31 deletions
diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result
index 8e49a3df4c8..0e72de7ab12 100644
--- a/mysql-test/r/information_schema.result
+++ b/mysql-test/r/information_schema.result
@@ -1,7 +1,8 @@
show variables where variable_name like "skip_show_database";
Variable_name Value
skip_show_database OFF
-grant all privileges on test.* to mysqltest_1@localhost;
+grant select, update, execute on test.* to mysqltest_2@localhost;
+grant select, update on test.* to mysqltest_1@localhost;
select * from information_schema.SCHEMATA where schema_name > 'm';
CATALOG_NAME SCHEMA_NAME DEFAULT_CHARACTER_SET_NAME SQL_PATH
NULL mysql latin1 NULL
@@ -229,6 +230,44 @@ sel2 sel2
select count(*) from information_schema.ROUTINES;
count(*)
2
+select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES;
+ROUTINE_NAME ROUTINE_DEFINITION
+show create function sub1;
+ERROR 42000: FUNCTION sub1 does not exist
+select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES;
+ROUTINE_NAME ROUTINE_DEFINITION
+sel2
+sub1
+grant all privileges on test.* to mysqltest_1@localhost;
+select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES;
+ROUTINE_NAME ROUTINE_DEFINITION
+sel2
+sub1
+create function sub2(i int) returns int
+return i+1;
+select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES;
+ROUTINE_NAME ROUTINE_DEFINITION
+sel2
+sub1
+sub2 return i+1
+show create procedure sel2;
+Procedure sql_mode Create Procedure
+sel2
+show create function sub1;
+Function sql_mode Create Function
+sub1
+show create function sub2;
+Function sql_mode Create Function
+sub2 CREATE FUNCTION `test`.`sub2`(i int) RETURNS int
+return i+1
+drop function sub2;
+show create procedure sel2;
+Procedure sql_mode Create Procedure
+sel2 CREATE PROCEDURE `test`.`sel2`()
+begin
+select * from t1;
+select * from t2;
+end
create view v0 (c) as select schema_name from information_schema.schemata;
select * from v0;
c
@@ -311,8 +350,8 @@ GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME PRIVILEGE_TYPE IS_GRAN
'mysqltest_1'@'localhost' NULL test t1 a INSERT NO
'mysqltest_1'@'localhost' NULL test t1 a UPDATE NO
'mysqltest_1'@'localhost' NULL test t1 a REFERENCES NO
-delete from mysql.user where user='mysqltest_1';
-delete from mysql.db where user='mysqltest_1';
+delete from mysql.user where user='mysqltest_1' or user='mysqltest_2';
+delete from mysql.db where user='mysqltest_1' or user='mysqltest_2';
delete from mysql.tables_priv where user='mysqltest_1';
delete from mysql.columns_priv where user='mysqltest_1';
flush privileges;
diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test
index 9ff0b1fdf61..4319fec258c 100644
--- a/mysql-test/t/information_schema.test
+++ b/mysql-test/t/information_schema.test
@@ -3,7 +3,8 @@
# show databases
show variables where variable_name like "skip_show_database";
-grant all privileges on test.* to mysqltest_1@localhost;
+grant select, update, execute on test.* to mysqltest_2@localhost;
+grant select, update on test.* to mysqltest_1@localhost;
select * from information_schema.SCHEMATA where schema_name > 'm';
select schema_name from information_schema.schemata;
@@ -104,6 +105,30 @@ select a.ROUTINE_NAME, b.name from information_schema.ROUTINES a,
mysql.proc b where a.ROUTINE_NAME = convert(b.name using utf8);
select count(*) from information_schema.ROUTINES;
+connect (user1,localhost,mysqltest_1,,);
+connect (user3,localhost,mysqltest_2,,);
+connection user1;
+select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES;
+--error 1305
+show create function sub1;
+connection user3;
+select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES;
+connection default;
+grant all privileges on test.* to mysqltest_1@localhost;
+connect (user2,localhost,mysqltest_1,,);
+connection user2;
+select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES;
+create function sub2(i int) returns int
+ return i+1;
+select ROUTINE_NAME, ROUTINE_DEFINITION from information_schema.ROUTINES;
+show create procedure sel2;
+show create function sub1;
+show create function sub2;
+connection default;
+disconnect user1;
+drop function sub2;
+show create procedure sel2;
+
#
# Test for views
#
@@ -138,8 +163,8 @@ select * from information_schema.USER_PRIVILEGES where grantee like '%mysqltest_
select * from information_schema.SCHEMA_PRIVILEGES where grantee like '%mysqltest_1%';
select * from information_schema.TABLE_PRIVILEGES where grantee like '%mysqltest_1%';
select * from information_schema.COLUMN_PRIVILEGES where grantee like '%mysqltest_1%';
-delete from mysql.user where user='mysqltest_1';
-delete from mysql.db where user='mysqltest_1';
+delete from mysql.user where user='mysqltest_1' or user='mysqltest_2';
+delete from mysql.db where user='mysqltest_1' or user='mysqltest_2';
delete from mysql.tables_priv where user='mysqltest_1';
delete from mysql.columns_priv where user='mysqltest_1';
flush privileges;
@@ -160,13 +185,11 @@ TABLE_SCHEMA= "test";
select * from information_schema.KEY_COLUMN_USAGE where
TABLE_SCHEMA= "test";
-
-connect (user1,localhost,mysqltest_1,,);
-connection user1;
+connection user2;
select table_name from information_schema.TABLES where table_schema like "test%";
select table_name,column_name from information_schema.COLUMNS where table_schema like "test%";
select ROUTINE_NAME from information_schema.ROUTINES;
-disconnect user1;
+disconnect user2;
connection default;
delete from mysql.user where user='mysqltest_1';
drop table t1;
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index aef1cd1efec..b978ffe175b 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -453,6 +453,7 @@ bool check_procedure_access(THD *thd,ulong want_access,char *db,char *name,
bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table);
bool check_merge_table_access(THD *thd, char *db,
TABLE_LIST *table_list);
+bool check_some_routine_access(THD *thd, char *db, char *name);
bool multi_update_precheck(THD *thd, TABLE_LIST *tables);
bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count);
bool mysql_multi_update_prepare(THD *thd);
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 59cdac1b153..30f3cac8a0d 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -1004,6 +1004,27 @@ sp_head::restore_thd_mem_root(THD *thd)
}
+bool check_show_routine_acceess(THD *thd, sp_head *sp, bool *full_access)
+{
+ TABLE_LIST tables;
+ bzero((char*) &tables,sizeof(tables));
+ tables.db= (char*) "mysql";
+ tables.table_name= tables.alias= (char*) "proc";
+ *full_access= !check_table_access(thd, SELECT_ACL, &tables, 1);
+ if (!(*full_access))
+ *full_access= (!strcmp(sp->m_definer_user.str, thd->priv_user) &&
+ !strcmp(sp->m_definer_host.str, thd->priv_host));
+ if (!(*full_access))
+ {
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ return check_some_routine_access(thd, (char * )sp->m_db.str,
+ (char * ) sp->m_name.str);
+#endif
+ }
+ return 0;
+}
+
+
int
sp_head::show_create_procedure(THD *thd)
{
@@ -1016,11 +1037,15 @@ sp_head::show_create_procedure(THD *thd)
sys_var *sql_mode_var;
byte *sql_mode_str;
ulong sql_mode_len;
+ bool full_access;
DBUG_ENTER("sp_head::show_create_procedure");
DBUG_PRINT("info", ("procedure %s", m_name.str));
LINT_INIT(sql_mode_str);
LINT_INIT(sql_mode_len);
+
+ if (check_show_routine_acceess(thd, this, &full_access))
+ return 1;
old_sql_mode= thd->variables.sql_mode;
thd->variables.sql_mode= m_sql_mode;
@@ -1047,7 +1072,8 @@ sp_head::show_create_procedure(THD *thd)
protocol->store(m_name.str, m_name.length, system_charset_info);
if (sql_mode_var)
protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info);
- protocol->store(m_defstr.str, m_defstr.length, system_charset_info);
+ if (full_access)
+ protocol->store(m_defstr.str, m_defstr.length, system_charset_info);
res= protocol->write();
send_eof(thd);
@@ -1085,11 +1111,15 @@ sp_head::show_create_function(THD *thd)
sys_var *sql_mode_var;
byte *sql_mode_str;
ulong sql_mode_len;
+ bool full_access;
DBUG_ENTER("sp_head::show_create_function");
DBUG_PRINT("info", ("procedure %s", m_name.str));
LINT_INIT(sql_mode_str);
LINT_INIT(sql_mode_len);
+ if (check_show_routine_acceess(thd, this, &full_access))
+ return 1;
+
old_sql_mode= thd->variables.sql_mode;
thd->variables.sql_mode= m_sql_mode;
sql_mode_var= find_sys_var("SQL_MODE", 8);
@@ -1114,7 +1144,8 @@ sp_head::show_create_function(THD *thd)
protocol->store(m_name.str, m_name.length, system_charset_info);
if (sql_mode_var)
protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info);
- protocol->store(m_defstr.str, m_defstr.length, system_charset_info);
+ if (full_access)
+ protocol->store(m_defstr.str, m_defstr.length, system_charset_info);
res= protocol->write();
send_eof(thd);
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 041154c96cc..3db219b5fdc 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -3583,6 +3583,37 @@ err:
}
+/*
+ Check if routine has any of the
+ procedure level grants
+
+ SYNPOSIS
+ bool check_routine_level_acl()
+ thd Thread handler
+ db Database name
+ name Routine name
+
+ RETURN
+ 1 error
+ 0 Ok
+*/
+
+bool check_routine_level_acl(THD *thd, char *db, char *name)
+{
+ bool no_routine_acl= 1;
+ if (grant_option)
+ {
+ GRANT_NAME *grant_proc;
+ rw_rdlock(&LOCK_grant);
+ if ((grant_proc= proc_hash_search(thd->priv_host, thd->ip, db,
+ thd->priv_user, name, 0)))
+ no_routine_acl= !(grant_proc->privs & SHOW_PROC_ACLS);
+ rw_unlock(&LOCK_grant);
+ }
+ return no_routine_acl;
+}
+
+
/*****************************************************************************
Functions to retrieve the grant for a table/column (for SHOW functions)
*****************************************************************************/
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index 3a9df84a35d..30e335c7afd 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -63,6 +63,9 @@
#define PROC_ACLS \
(ALTER_PROC_ACL | EXECUTE_ACL | GRANT_ACL)
+#define SHOW_PROC_ACLS \
+(ALTER_PROC_ACL | EXECUTE_ACL | CREATE_PROC_ACL)
+
#define GLOBAL_ACLS \
(SELECT_ACL | INSERT_ACL | UPDATE_ACL | DELETE_ACL | CREATE_ACL | DROP_ACL | \
RELOAD_ACL | SHUTDOWN_ACL | PROCESS_ACL | FILE_ACL | GRANT_ACL | \
@@ -216,6 +219,7 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
const char *db, const char *table);
bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name);
bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name);
+bool check_routine_level_acl(THD *thd, char *db, char *name);
#ifdef NO_EMBEDDED_ACCESS_CHECKS
#define check_grant(A,B,C,D,E,F) 0
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index e5c29f56305..2ec5e0a4128 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -4745,6 +4745,38 @@ check_procedure_access(THD *thd, ulong want_access,char *db, char *name,
return FALSE;
}
+
+/*
+ Check if the routine has any of the routine privileges
+
+ SYNOPSIS
+ check_some_routine_access()
+ thd Thread handler
+ db Database name
+ name Routine name
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
+bool check_some_routine_access(THD *thd, char *db, char *name)
+{
+ ulong save_priv;
+ if (thd->master_access & SHOW_PROC_ACLS)
+ return FALSE;
+ if (!check_access(thd, SHOW_PROC_ACLS, db, &save_priv, 0, 1) ||
+ (save_priv & SHOW_PROC_ACLS))
+ return FALSE;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (grant_option)
+ return check_routine_level_acl(thd, db, name);
+#endif
+
+ return FALSE;
+}
+
+
/*
Check if the given table has any of the asked privileges
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 7a4ee9f5de3..4ffe7110cfa 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -2468,32 +2468,41 @@ int fill_schema_coll_charset_app(THD *thd, TABLE_LIST *tables, COND *cond)
}
-void store_schema_proc(THD *thd, TABLE *table,
- TABLE *proc_table,
- const char *wild)
+void store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
+ const char *wild, bool full_access, const char *sp_user)
{
String tmp_string;
TIME time;
LEX *lex= thd->lex;
CHARSET_INFO *cs= system_charset_info;
- restore_record(table, s->default_values);
+ const char *sp_db, *sp_name, *definer;
+ sp_db= get_field(thd->mem_root, proc_table->field[0]);
+ sp_name= get_field(thd->mem_root, proc_table->field[1]);
+ definer= get_field(thd->mem_root, proc_table->field[11]);
+ if (!full_access)
+ full_access= !strcmp(sp_user, definer);
+ if (!full_access)
+ {
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ if (check_some_routine_access(thd, (char * )sp_db, (char * )sp_name))
+ return;
+#endif
+ }
+
if (lex->orig_sql_command == SQLCOM_SHOW_STATUS_PROC &&
proc_table->field[2]->val_int() == TYPE_ENUM_PROCEDURE ||
lex->orig_sql_command == SQLCOM_SHOW_STATUS_FUNC &&
proc_table->field[2]->val_int() == TYPE_ENUM_FUNCTION ||
lex->orig_sql_command == SQLCOM_END)
{
- tmp_string.length(0);
- get_field(thd->mem_root, proc_table->field[1], &tmp_string);
- if (!wild || !wild[0] || !wild_compare(tmp_string.ptr(), wild, 0))
+ restore_record(table, s->default_values);
+ if (!wild || !wild[0] || !wild_compare(sp_name, wild, 0))
{
- table->field[3]->store(tmp_string.ptr(), tmp_string.length(), cs);
+ table->field[3]->store(sp_name, strlen(sp_name), cs);
tmp_string.length(0);
get_field(thd->mem_root, proc_table->field[3], &tmp_string);
table->field[0]->store(tmp_string.ptr(), tmp_string.length(), cs);
- tmp_string.length(0);
- get_field(thd->mem_root, proc_table->field[0], &tmp_string);
- table->field[2]->store(tmp_string.ptr(), tmp_string.length(), cs);
+ table->field[2]->store(sp_db, strlen(sp_db), cs);
tmp_string.length(0);
get_field(thd->mem_root, proc_table->field[2], &tmp_string);
table->field[4]->store(tmp_string.ptr(), tmp_string.length(), cs);
@@ -2504,10 +2513,13 @@ void store_schema_proc(THD *thd, TABLE *table,
table->field[5]->store(tmp_string.ptr(), tmp_string.length(), cs);
table->field[5]->set_notnull();
}
+ if (full_access)
+ {
+ tmp_string.length(0);
+ get_field(thd->mem_root, proc_table->field[10], &tmp_string);
+ table->field[7]->store(tmp_string.ptr(), tmp_string.length(), cs);
+ }
table->field[6]->store("SQL", 3, cs);
- tmp_string.length(0);
- get_field(thd->mem_root, proc_table->field[10], &tmp_string);
- table->field[7]->store(tmp_string.ptr(), tmp_string.length(), cs);
table->field[10]->store("SQL", 3, cs);
tmp_string.length(0);
get_field(thd->mem_root, proc_table->field[6], &tmp_string);
@@ -2531,9 +2543,7 @@ void store_schema_proc(THD *thd, TABLE *table,
tmp_string.length(0);
get_field(thd->mem_root, proc_table->field[15], &tmp_string);
table->field[18]->store(tmp_string.ptr(), tmp_string.length(), cs);
- tmp_string.length(0);
- get_field(thd->mem_root, proc_table->field[11], &tmp_string);
- table->field[19]->store(tmp_string.ptr(), tmp_string.length(), cs);
+ table->field[19]->store(definer, strlen(definer), cs);
table->file->write_row(table->record[0]);
}
}
@@ -2547,14 +2557,18 @@ int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond)
const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
int res= 0;
TABLE *table= tables->table, *old_open_tables= thd->open_tables;
+ bool full_access;
+ char definer[HOSTNAME_LENGTH+USERNAME_LENGTH+2];
DBUG_ENTER("fill_schema_proc");
+ strxmov(definer, thd->priv_user, "@", thd->priv_host, NullS);
bzero((char*) &proc_tables,sizeof(proc_tables));
proc_tables.db= (char*) "mysql";
proc_tables.db_length= 5;
proc_tables.table_name= proc_tables.alias= (char*) "proc";
proc_tables.table_name_length= 4;
proc_tables.lock_type= TL_READ;
+ full_access= !check_table_access(thd, SELECT_ACL, &proc_tables, 1);
if (!(proc_table= open_ltable(thd, &proc_tables, TL_READ)))
{
DBUG_RETURN(1);
@@ -2565,9 +2579,9 @@ int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond)
res= (res == HA_ERR_END_OF_FILE) ? 0 : 1;
goto err;
}
- store_schema_proc(thd, table, proc_table, wild);
+ store_schema_proc(thd, table, proc_table, wild, full_access, definer);
while (!proc_table->file->index_next(proc_table->record[0]))
- store_schema_proc(thd, table, proc_table, wild);
+ store_schema_proc(thd, table, proc_table, wild, full_access, definer);
err:
proc_table->file->ha_index_end();