diff options
author | jimw@mysql.com <> | 2005-08-11 17:04:16 -0700 |
---|---|---|
committer | jimw@mysql.com <> | 2005-08-11 17:04:16 -0700 |
commit | 3a815f45bd7030cddf636d5018faf13918f99ca6 (patch) | |
tree | cdafc43f17feb3e2c94df11c7bcc6df37c52eae3 | |
parent | 03162293da783ce3f153ac8f713e0cea103b440b (diff) | |
download | mariadb-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.result | 13 | ||||
-rw-r--r-- | mysql-test/t/sp-security.test | 36 | ||||
-rw-r--r-- | sql/mysql_priv.h | 2 | ||||
-rw-r--r-- | sql/sp.cc | 110 | ||||
-rw-r--r-- | sql/sp.h | 4 | ||||
-rw-r--r-- | sql/sql_db.cc | 52 | ||||
-rw-r--r-- | sql/sql_parse.cc | 18 |
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); -} @@ -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: |