summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjimw@mysql.com <>2005-08-11 17:04:16 -0700
committerjimw@mysql.com <>2005-08-11 17:04:16 -0700
commit3a815f45bd7030cddf636d5018faf13918f99ca6 (patch)
treecdafc43f17feb3e2c94df11c7bcc6df37c52eae3
parent03162293da783ce3f153ac8f713e0cea103b440b (diff)
downloadmariadb-git-3a815f45bd7030cddf636d5018faf13918f99ca6.tar.gz
Avoid spurious error when restoring INFORMATION_SCHEMA as the current
database after failing to execute a stored procedure in an inaccessible database. (Bug #12318)
-rw-r--r--mysql-test/r/sp-security.result13
-rw-r--r--mysql-test/t/sp-security.test36
-rw-r--r--sql/mysql_priv.h2
-rw-r--r--sql/sp.cc110
-rw-r--r--sql/sp.h4
-rw-r--r--sql/sql_db.cc52
-rw-r--r--sql/sql_parse.cc18
7 files changed, 92 insertions, 143 deletions
diff --git a/mysql-test/r/sp-security.result b/mysql-test/r/sp-security.result
index 184978e4a0d..d78f5fc36ea 100644
--- a/mysql-test/r/sp-security.result
+++ b/mysql-test/r/sp-security.result
@@ -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;
diff --git a/mysql-test/t/sp-security.test b/mysql-test/t/sp-security.test
index 15fcba5ebe9..c7c7ef20a5b 100644
--- a/mysql-test/t/sp-security.test
+++ b/mysql-test/t/sp-security.test
@@ -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.
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index dae564a15c0..21fea8e5975 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -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);
diff --git a/sql/sp.cc b/sql/sp.cc
index 5dd7c613a10..4b50cf00119 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -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);
-}
diff --git a/sql/sp.h b/sql/sp.h
index 9f110f87807..c278da863e0 100644
--- a/sql/sp.h
+++ b/sql/sp.h
@@ -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_ */
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index d110ff6f778..67fc1053774 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -996,8 +996,9 @@ err:
SYNOPSIS
mysql_change_db()
- thd Thread handler
- name Databasename
+ thd Thread handler
+ name Databasename
+ no_access_check True= don't do access check
DESCRIPTION
Becasue the database name may have been given directly from the
@@ -1009,15 +1010,16 @@ err:
replication slave SQL thread (for that thread, setting of thd->db is done
in ::exec_event() methods of log_event.cc).
- This function does not send the error message to the client, if that
- should be sent to the client, call net_send_error after this function
+ This function does not send anything, including error messages to the
+ client, if that should be sent to the client, call net_send_error after
+ this function.
RETURN VALUES
0 ok
1 error
*/
-bool mysql_change_db(THD *thd, const char *name)
+bool mysql_change_db(THD *thd, const char *name, bool no_access_check)
{
int length, db_length;
char *dbname=my_strdup((char*) name,MYF(MY_WME));
@@ -1053,23 +1055,25 @@ bool mysql_change_db(THD *thd, const char *name)
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- 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);
+ if (!no_access_check) {
+ 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);
@@ -1083,12 +1087,12 @@ bool mysql_change_db(THD *thd, const char *name)
DBUG_RETURN(1);
}
end:
- send_ok(thd);
x_free(thd->db);
thd->db=dbname; // THD::~THD will free this
thd->db_length=db_length;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- thd->db_access=db_access;
+ if (!no_access_check)
+ thd->db_access=db_access;
#endif
if (schema_db)
{
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index fefe670432c..2c53dbbd2a3 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -275,7 +275,7 @@ int check_user(THD *thd, enum enum_server_command command,
{
thd->db= 0;
thd->db_length= 0;
- if (mysql_change_db(thd, db))
+ if (mysql_change_db(thd, db, FALSE))
{
/* Send the error to the client */
net_send_error(thd);
@@ -284,8 +284,7 @@ int check_user(THD *thd, enum enum_server_command command,
DBUG_RETURN(-1);
}
}
- else
- send_ok(thd);
+ send_ok(thd);
DBUG_RETURN(0);
#else
@@ -410,7 +409,7 @@ int check_user(THD *thd, enum enum_server_command command,
/* Change database if necessary */
if (db && db[0])
{
- if (mysql_change_db(thd, db))
+ if (mysql_change_db(thd, db, FALSE))
{
/* Send error to the client */
net_send_error(thd);
@@ -419,8 +418,7 @@ int check_user(THD *thd, enum enum_server_command command,
DBUG_RETURN(-1);
}
}
- else
- send_ok(thd);
+ send_ok(thd);
thd->password= test(passwd_len); // remember for error messages
/* Ready to handle queries */
DBUG_RETURN(0);
@@ -1514,8 +1512,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
&LOCK_status);
thd->convert_string(&tmp, system_charset_info,
packet, strlen(packet), thd->charset());
- if (!mysql_change_db(thd, tmp.str))
+ if (!mysql_change_db(thd, tmp.str, FALSE))
+ {
mysql_log.write(thd,command,"%s",thd->db);
+ send_ok(thd);
+ }
break;
}
#ifdef HAVE_REPLICATION
@@ -3407,7 +3408,8 @@ end_with_restore_list:
}
#endif
case SQLCOM_CHANGE_DB:
- mysql_change_db(thd,select_lex->db);
+ if (!mysql_change_db(thd,select_lex->db,FALSE))
+ send_ok(thd);
break;
case SQLCOM_LOAD: