Commit e0607f0a authored by unknown's avatar unknown
Browse files

Avoid spurious error when restoring INFORMATION_SCHEMA as the current

database after failing to execute a stored procedure in an inaccessible
database. (Bug #12318)


mysql-test/r/sp-security.result:
  Update results
mysql-test/t/sp-security.test:
  Add regression test
sql/mysql_priv.h:
  Add additional argument to mysql_change_db()
sql/sp.cc:
  Use mysql_change_db(), get rid of sp_change_db().
sql/sp.h:
  Get rid of sp_change_db().
sql/sql_db.cc:
  Handle no_access_check flag to mysql_change_db, and remove the send_ok()
  call.
sql/sql_parse.cc:
  Add extra argument to mysql_change_db(), and call send_ok() after
  successful calls to same (since it no longer does it for us).
parent 04e2ca68
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -236,3 +236,16 @@ drop procedure bug7291_2;
drop procedure bug7291_0;
REVOKE ALL PRIVILEGES, GRANT OPTION FROM user1@localhost;
drop user user1@localhost;
drop database if exists mysqltest_1;
create database mysqltest_1;
create procedure mysqltest_1.p1()
begin
select 1 from dual;
end//
grant usage on *.* to mysqltest_1@localhost;
call mysqltest_1.p1();
ERROR 42000: execute command denied to user 'mysqltest_1'@'localhost' for routine 'mysqltest_1.p1'
drop procedure mysqltest_1.p1;
drop database mysqltest_1;
revoke usage on *.* from mysqltest_1@localhost;
drop user mysqltest_1@localhost;
+36 −0
Original line number Diff line number Diff line
@@ -371,3 +371,39 @@ drop procedure bug7291_0;
disconnect user1;
REVOKE ALL PRIVILEGES, GRANT OPTION FROM user1@localhost;
drop user user1@localhost;

#
# Bug #12318: Wrong error message when accessing an inaccessible stored
# procedure in another database when the current database is
# information_schema.
# 

--disable_warnings
drop database if exists mysqltest_1;
--enable_warnings

create database mysqltest_1;
delimiter //;
create procedure mysqltest_1.p1()
begin
   select 1 from dual;
end//
delimiter ;//

grant usage on *.* to mysqltest_1@localhost;

connect (n1,localhost,mysqltest_1,,information_schema,$MASTER_MYPORT,$MASTER_MYSOCK);
connection n1;
--error 1370
call mysqltest_1.p1();
disconnect n1;

connection default;

drop procedure mysqltest_1.p1;
drop database mysqltest_1;

revoke usage on *.* from mysqltest_1@localhost;
drop user mysqltest_1@localhost;

# End of 5.0 bugs.
+1 −1
Original line number Diff line number Diff line
@@ -587,7 +587,7 @@ int quick_rm_table(enum db_type base,const char *db,
		   const char *table_name);
void close_cached_table(THD *thd, TABLE *table);
bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list);
bool mysql_change_db(THD *thd,const char *name);
bool mysql_change_db(THD *thd,const char *name,bool no_access_check);
void mysql_parse(THD *thd,char *inBuf,uint length);
bool mysql_test_parse_for_slave(THD *thd,char *inBuf,uint length);
bool is_update_query(enum enum_sql_command command);
+4 −106
Original line number Diff line number Diff line
@@ -427,7 +427,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
      LEX *newlex= thd->lex;
      sp_head *sp= newlex->sphead;

      if (dbchanged && (ret= sp_change_db(thd, olddb, 1)))
      if (dbchanged && (ret= mysql_change_db(thd, olddb, 1)))
	goto done;
      if (sp)
      {
@@ -438,7 +438,7 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
    }
    else
    {
      if (dbchanged && (ret= sp_change_db(thd, olddb, 1)))
      if (dbchanged && (ret= mysql_change_db(thd, olddb, 1)))
	goto done;
      *sphp= thd->lex->sphead;
      (*sphp)->set_info((char *)definer, (uint)strlen(definer),
@@ -594,7 +594,7 @@ db_create_routine(THD *thd, int type, sp_head *sp)
done:
  close_thread_tables(thd);
  if (dbchanged)
    (void)sp_change_db(thd, olddb, 1);
    (void)mysql_change_db(thd, olddb, 1);
  DBUG_RETURN(ret);
}

@@ -1612,112 +1612,10 @@ sp_use_new_db(THD *thd, char *newdb, char *olddb, uint olddblen,
  }
  else
  {
    int ret= sp_change_db(thd, newdb, no_access_check);
    int ret= mysql_change_db(thd, newdb, no_access_check);

    if (! ret)
      *dbchangedp= TRUE;
    DBUG_RETURN(ret);
  }
}

/*
  Change database.

  SYNOPSIS
    sp_change_db()
    thd		    Thread handler
    name	    Database name
    empty_is_ok     True= it's ok with "" as name
    no_access_check True= don't do access check

  DESCRIPTION
    This is the same as mysql_change_db(), but with some extra
    arguments for Stored Procedure usage; doing implicit "use" 
    when executing an SP in a different database.
    We also use different error routines, since this might be
    invoked from a function when executing a query or statement.
    Note: We would have prefered to reuse mysql_change_db(), but
      the error handling in particular made that too awkward, so
      we (reluctantly) have a "copy" here.

  RETURN VALUES
    0	ok
    1	error
*/

int
sp_change_db(THD *thd, char *name, bool no_access_check)
{
  int length, db_length;
  char *dbname=my_strdup((char*) name,MYF(MY_WME));
  char	path[FN_REFLEN];
  HA_CREATE_INFO create;
  DBUG_ENTER("sp_change_db");
  DBUG_PRINT("enter", ("db: %s, no_access_check: %d", name, no_access_check));

  db_length= (!dbname ? 0 : strip_sp(dbname));
  if (dbname && db_length)
  {
    if ((db_length > NAME_LEN) || check_db_name(dbname))
    {
      my_error(ER_WRONG_DB_NAME, MYF(0), dbname);
      x_free(dbname);
      DBUG_RETURN(1);
    }
  }

  if (dbname && db_length)
  {
#ifndef NO_EMBEDDED_ACCESS_CHECKS
    if (! no_access_check)
    {
      ulong db_access;

      if (test_all_bits(thd->master_access,DB_ACLS))
	db_access=DB_ACLS;
      else
	db_access= (acl_get(thd->host,thd->ip, thd->priv_user,dbname,0) |
		    thd->master_access);  
      if (!(db_access & DB_ACLS) &&
	  (!grant_option || check_grant_db(thd,dbname)))
      {
	my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
                 thd->priv_user,
                 thd->priv_host,
                 dbname);
	mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR),
			thd->priv_user,
			thd->priv_host,
			dbname);
	my_free(dbname,MYF(0));
	DBUG_RETURN(1);
      }
    }
#endif
    (void) sprintf(path,"%s/%s",mysql_data_home,dbname);
    length=unpack_dirname(path,path);		// Convert if not unix
    if (length && path[length-1] == FN_LIBCHAR)
      path[length-1]=0;				// remove ending '\'
    if (access(path,F_OK))
    {
      my_error(ER_BAD_DB_ERROR, MYF(0), dbname);
      my_free(dbname,MYF(0));
      DBUG_RETURN(1);
    }
  }

  x_free(thd->db);
  thd->db=dbname;				// THD::~THD will free this
  thd->db_length=db_length;

  if (dbname && db_length)
  {
    strmov(path+unpack_dirname(path,path), MY_DB_OPT_FILE);
    load_db_opt(thd, path, &create);
    thd->db_charset= create.default_table_charset ?
      create.default_table_charset :
      thd->variables.collation_server;
    thd->variables.collation_database= thd->db_charset;
  }
  DBUG_RETURN(0);
}
+0 −4
Original line number Diff line number Diff line
@@ -112,8 +112,4 @@ int
sp_use_new_db(THD *thd, char *newdb, char *olddb, uint olddbmax,
	      bool no_access_check, bool *dbchangedp);

// Like mysql_change_db() but handles empty db name and the  send_ok() problem.
int
sp_change_db(THD *thd, char *db, bool no_access_check);

#endif /* _SP_H_ */
Loading