Commit 0d7e68c9 authored by unknown's avatar unknown
Browse files

WL2131: Access control for SHOW ... PROCEDURE|FUNCTION ...

parent 0ae5efb4
Loading
Loading
Loading
Loading
+42 −3
Original line number Diff line number Diff line
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;
+30 −7
Original line number Diff line number Diff line
@@ -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;
+1 −0
Original line number Diff line number Diff line
@@ -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);
+33 −2
Original line number Diff line number Diff line
@@ -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,12 +1037,16 @@ 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;
  sql_mode_var= find_sys_var("SQL_MODE", 8);
@@ -1047,6 +1072,7 @@ 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);
  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,6 +1144,7 @@ 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);
  if (full_access)
    protocol->store(m_defstr.str, m_defstr.length, system_charset_info);
  res= protocol->write();
  send_eof(thd);
+31 −0
Original line number Diff line number Diff line
@@ -3583,6 +3583,37 @@ bool check_grant_procedure(THD *thd, ulong want_access,
}


/*
  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)
*****************************************************************************/
Loading