Below is the list of changes that have just been committed into a local
5.1 repository of andrey. When andrey does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
ChangeSet
1.2101 06/02/10 15:02:57 andrey@lmy004. +6 -0
fix for bug #17289 Events: missing privilege check for drop database
Events were executed with all privileges possible on planet Earth :(
WL#1034
sql/sql_error.cc
1.37 06/02/10 15:02:49 andrey@lmy004. +9 -4
- make warning_level_names public to be used in event_executor.cc
- change from 2 arrays to a LEX_STRING array
sql/event_timed.cc
1.26 06/02/10 15:02:49 andrey@lmy004. +80 -4
- fix documentation
- add a new error code -99, EVENT was revoked from the user on the DB
- set_sec_ctx, execute, restore_sex_ctx
sql/event_executor.cc
1.24 06/02/10 15:02:49 andrey@lmy004. +65 -21
- move code regarding privilieges checking to event_timed::execute()
- add a new function evex_print_warnings() which prints the notes/warnings/errors
to the console (easily capturable with logs-into-tables) so one can see what
has happened if there was an error of some sort!
sql/event.h
1.18 06/02/10 15:02:49 andrey@lmy004. +6 -0
-add two new methods to event_timed to change and restore
the security context
mysql-test/t/events.test
1.15 06/02/10 15:02:49 andrey@lmy004. +33 -0
test for bug#17289 Events: missing privilege check for drop database
mysql-test/r/events.result
1.14 06/02/10 15:02:49 andrey@lmy004. +26 -1
update test results
# This is a BitKeeper patch. What follows are the unified diffs for the
# set of deltas contained in the patch. The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User: andrey
# Host: lmy004.
# Root: /work/mysql-5.1-bug17289
--- 1.13/mysql-test/r/events.result 2006-02-09 22:43:58 +01:00
+++ 1.14/mysql-test/r/events.result 2006-02-10 15:02:49 +01:00
@@ -1,5 +1,28 @@
create database if not exists events_test;
use events_test;
+CREATE USER pauline@localhost;
+CREATE DATABASE db_x;
+GRANT EVENT ON db_x.* TO pauline@localhost;
+USE db_x;
+CREATE TABLE x_table(a int);
+CREATE EVENT e_x1 ON SCHEDULE EVERY 1 SECOND DO DROP DATABASE db_x;
+CREATE EVENT e_x2 ON SCHEDULE EVERY 1 SECOND DO DROP TABLE x_table;
+SHOW DATABASES LIKE 'db_x';
+Database (db_x)
+db_x
+SET GLOBAL event_scheduler=1;
+SHOW DATABASES LIKE 'db_x';
+Database (db_x)
+db_x
+SHOW TABLES FROM db_x;
+Tables_in_db_x
+x_table
+SET GLOBAL event_scheduler=0;
+DROP EVENT e_x1;
+DROP EVENT e_x2;
+DROP DATABASE db_x;
+DROP USER pauline@localhost;
+USE events_test;
drop event if exists event1;
Warnings:
Note 1305 Event event1 does not exist
@@ -166,7 +189,7 @@
Id User Host db Command Time State Info
# root localhost events_test Query # NULL show processlist
# event_scheduler NULL Connect # Sleeping NULL
-# root events_test Connect # User lock select get_lock("test_lock2", 20)
+# root localhost events_test Connect # User lock select get_lock("test_lock2", 20)
"Release the mutex, the event worker should finish."
select release_lock("test_lock2");
release_lock("test_lock2")
@@ -184,6 +207,8 @@
show processlist;
Id User Host db Command Time State Info
# root localhost events_test Query # NULL show processlist
+# event_scheduler NULL Connect # Sleeping NULL
+# root localhost events_test Connect # User lock select get_lock("test_lock2_1", 20)
"Release the lock so the child process should finish. Hence the scheduler also"
select release_lock("test_lock2_1");
release_lock("test_lock2_1")
--- 1.14/mysql-test/t/events.test 2006-02-09 22:43:58 +01:00
+++ 1.15/mysql-test/t/events.test 2006-02-10 15:02:49 +01:00
@@ -1,5 +1,38 @@
create database if not exists events_test;
use events_test;
+
+#
+# START: BUG #17289 Events: missing privilege check for drop database
+#
+CREATE USER pauline@localhost;
+CREATE DATABASE db_x;
+GRANT EVENT ON db_x.* TO pauline@localhost;
+USE db_x;
+CREATE TABLE x_table(a int);
+connect (priv_conn,localhost,pauline,,db_x);
+CREATE EVENT e_x1 ON SCHEDULE EVERY 1 SECOND DO DROP DATABASE db_x;
+CREATE EVENT e_x2 ON SCHEDULE EVERY 1 SECOND DO DROP TABLE x_table;
+connection default;
+SHOW DATABASES LIKE 'db_x';
+SET GLOBAL event_scheduler=1;
+--sleep 2
+SHOW DATABASES LIKE 'db_x';
+SHOW TABLES FROM db_x;
+SET GLOBAL event_scheduler=0;
+--sleep 1
+connection priv_conn;
+DROP EVENT e_x1;
+DROP EVENT e_x2;
+disconnect priv_conn;
+connection default;
+DROP DATABASE db_x;
+DROP USER pauline@localhost;
+USE events_test;
+--sleep 1
+#
+# END: BUG #17289 Events: missing privilege check for drop database
+#
+
drop event if exists event1;
create event event1 on schedule every 15 minute starts now() ends date_add(now(),
interval 5 hour) DO begin end;
alter event event1 rename to event2 enable;
--- 1.17/sql/event.h 2006-01-31 17:22:28 +01:00
+++ 1.18/sql/event.h 2006-02-10 15:02:49 +01:00
@@ -203,6 +203,12 @@
delete sphead;
sphead= 0;
}
+protected:
+ bool
+ change_security_context(THD *thd, Security_context **backup);
+
+ void
+ restore_security_context(THD *thd, Security_context *backup);
};
--- 1.23/sql/event_executor.cc 2006-01-31 23:41:11 +01:00
+++ 1.24/sql/event_executor.cc 2006-02-10 15:02:49 +01:00
@@ -49,7 +49,8 @@
static int
evex_load_events_from_db(THD *thd);
-
+bool
+evex_print_warnings(THD *thd, event_timed *et);
/*
TODO Andrey: Check for command line option whether to start
@@ -135,7 +136,8 @@
{
DBUG_ENTER("init_event_thread");
thd->client_capabilities= 0;
- thd->security_ctx->skip_grants();
+ thd->security_ctx->master_access= 0;
+ thd->security_ctx->db_access= 0;
thd->security_ctx->host= (char*)my_localhost;
my_net_init(&thd->net, 0);
thd->net.read_timeout = slave_net_timeout;
@@ -204,7 +206,7 @@
if (init_event_thread(thd))
goto err;
-
+ thd->security_ctx->skip_grants();
// make this thread invisible it has no vio -> show processlist won't see
thd->system_thread= 1;
@@ -481,21 +483,8 @@
thd= current_thd;
#endif
- // thd->security_ctx->priv_host is char[MAX_HOSTNAME]
-
- strxnmov(thd->security_ctx->priv_host,
sizeof(thd->security_ctx->priv_host),
- event->definer_host.str, NullS);
-
- thd->security_ctx->user= thd->security_ctx->priv_user=
- my_strdup(event->definer_user.str, MYF(0));
-
- thd->db= event->dbname.str;
- if (!check_access(thd, EVENT_ACL, event->dbname.str, 0, 0, 0,
- is_schema_db(event->dbname.str)))
{
int ret;
- DBUG_PRINT("info", (" EVEX EXECUTING event %s.%s [EXPR:%d]",
- event->dbname.str, event->name.str,(int) event->expression));
sql_print_information(" EVEX EXECUTING event %s.%s [EXPR:%d]",
event->dbname.str, event->name.str,(int) event->expression);
@@ -507,10 +496,7 @@
if (ret == EVEX_COMPILE_ERROR)
sql_print_information(" EVEX COMPILE ERROR for event %s.%s",
event->dbname.str, event->name.str);
-
- DBUG_PRINT("info", (" EVEX EXECUTED event %s.%s [EXPR:%d]. RetCode=%d",
- event->dbname.str, event->name.str,
- (int) event->expression, ret));
+ evex_print_warnings(thd, event);
}
if ((event->flags & EVENT_EXEC_NO_MORE) ||
event->status==MYSQL_EVENT_DISABLED)
{
@@ -521,7 +507,6 @@
delete event;
}
- thd->db= 0;
err:
VOID(pthread_mutex_lock(&LOCK_thread_count));
@@ -666,3 +651,62 @@
DBUG_RETURN(0);
}
+extern LEX_STRING warning_level_names[];
+
+/*
+ Prints the stack of infos, warnings, errors from thd to
+ the console so it can be fetched by the logs-into-tables and
+ checked later.
+
+ Synopsis
+ evex_print_warnings
+ thd - thread used during the execution of the event
+ et - the event itself
+
+ Returns
+ 0 - OK (always)
+
+*/
+
+bool
+evex_print_warnings(THD *thd, event_timed *et)
+{
+ MYSQL_ERROR *err;
+ DBUG_ENTER("evex_show_warnings");
+ char msg_buf[1024];
+ char prefix_buf[512];
+ String prefix(prefix_buf, sizeof(prefix_buf), system_charset_info);
+ prefix.length(0);
+
+ List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
+ while ((err= it++))
+ {
+ String err_msg(msg_buf, sizeof(msg_buf), system_charset_info);
+ err_msg.length(0);// set it to 0 or we start adding at the end
+ if (!prefix.length())
+ {
+ prefix.append("SCHEDULER: [");
+
+
append_identifier(thd,&prefix,et->definer_user.str,et->definer_user.length);
+ prefix.append('@');
+
append_identifier(thd,&prefix,et->definer_host.str,et->definer_host.length);
+ prefix.append("][", 2);
+ append_identifier(thd,&prefix, et->dbname.str, et->dbname.length);
+ prefix.append('.');
+ append_identifier(thd,&prefix, et->name.str, et->name.length);
+ prefix.append("] ", 2);
+ }
+
+ err_msg.append(prefix);
+ err_msg.append('[');
+ err_msg.append(warning_level_names[err->level].str,
+ warning_level_names[err->level].length, system_charset_info);
+ err_msg.append("] [");
+ err_msg.append(err->msg, strlen(err->msg), system_charset_info);
+ err_msg.append("]");
+ sql_print_information("%*s", err_msg.length(), err_msg.c_ptr());
+ }
+
+
+ DBUG_RETURN(FALSE);
+}
--- 1.25/sql/event_timed.cc 2006-02-07 19:37:22 +01:00
+++ 1.26/sql/event_timed.cc 2006-02-10 15:02:49 +01:00
@@ -982,12 +982,13 @@
Executes the event (the underlying sp_head object);
SYNOPSIS
- evex_fill_row()
+ event_timed::execute()
thd THD
mem_root If != NULL use it to compile the event on it
Returns
0 - success
+ -99 - No access to the database.
-100 - event in execution (parallel execution is impossible)
others - retcodes of sp_head::execute_procedure()
@@ -996,10 +997,12 @@
int
event_timed::execute(THD *thd, MEM_ROOT *mem_root)
{
- List<Item> empty_item_list;
+ Security_context *save_ctx;
int ret= 0;
DBUG_ENTER("event_timed::execute");
+ DBUG_PRINT("info", (" EVEX EXECUTING event %s.%s [EXPR:%d]",
+ dbname.str, name.str, (int) expression));
VOID(pthread_mutex_lock(&this->LOCK_running));
if (running)
@@ -1011,12 +1014,35 @@
VOID(pthread_mutex_unlock(&this->LOCK_running));
// TODO Andrey : make this as member variable and delete in destructor
- empty_item_list.empty();
if (!sphead && (ret= compile(thd, mem_root)))
goto done;
- ret= sphead->execute_procedure(thd, &empty_item_list);
+ thd->db= dbname.str;
+ thd->db_length= dbname.length;
+
+ DBUG_PRINT("info", ("master_access=%d db_access=%d",
+ thd->security_ctx->master_access,
thd->security_ctx->db_access));
+ change_security_context(thd, &save_ctx);
+ DBUG_PRINT("info", ("master_access=%d db_access=%d",
+ thd->security_ctx->master_access,
thd->security_ctx->db_access));
+// if (mysql_change_db(thd, dbname.str, 0))
+ if (!check_access(thd, EVENT_ACL,dbname.str, 0, 0, 0,is_schema_db(dbname.str)))
+ {
+ List<Item> empty_item_list;
+ empty_item_list.empty();
+ ret= sphead->execute_procedure(thd, &empty_item_list);
+ }
+ else
+ {
+ DBUG_PRINT("error", ("%s@%s has no rights on %s", definer_user.str,
+ definer_host.str, dbname.str));
+ ret= -99;
+ }
+ restore_security_context(thd, save_ctx);
+ DBUG_PRINT("info", ("master_access=%d db_access=%d",
+ thd->security_ctx->master_access,
thd->security_ctx->db_access));
+ thd->db= 0;
VOID(pthread_mutex_lock(&this->LOCK_running));
running= false;
@@ -1029,8 +1055,58 @@
delete sphead;
sphead= 0;
}
+ DBUG_PRINT("info", (" EVEX EXECUTED event %s.%s [EXPR:%d]. RetCode=%d",
+ dbname.str, name.str, (int) expression, ret));
DBUG_RETURN(ret);
+}
+
+
+/*
+ Switches the security context
+ Synopsis
+ event_timed::change_security_context()
+ thd - thread
+ backup - where to store the old context
+
+ RETURN
+ 0 - OK
+ 1 - Error (generates error too)
+*/
+bool
+event_timed::change_security_context(THD *thd, Security_context **backup)
+{
+ DBUG_ENTER("event_timed::change_security_context");
+ DBUG_PRINT("info",("%s@%s@%s",definer_user.str,definer_host.str, dbname.str));
+ *backup= 0;
+ if (acl_getroot_no_password(&sphead->m_security_ctx, definer_user.str,
+ definer_host.str, definer_host.str, dbname.str))
+ {
+ my_error(ER_NO_SUCH_USER, MYF(0), definer_user.str, definer_host.str);
+ DBUG_RETURN(TRUE);
+ }
+ *backup= thd->security_ctx;
+ thd->security_ctx= &sphead->m_security_ctx;
+
+ DBUG_RETURN(FALSE);
+}
+
+
+/*
+ Restores the security context
+ Synopsis
+ event_timed::restore_security_context()
+ thd - thread
+ backup - switch to this context
+ */
+
+void
+event_timed::restore_security_context(THD *thd, Security_context *backup)
+{
+ DBUG_ENTER("event_timed::change_security_context");
+ if (backup)
+ thd->security_ctx= backup;
+ DBUG_VOID_RETURN;
}
--- 1.36/sql/sql_error.cc 2005-10-17 15:07:23 +02:00
+++ 1.37/sql/sql_error.cc 2006-02-10 15:02:49 +01:00
@@ -211,8 +211,13 @@
TRUE Error sending data to client
*/
-static const char *warning_level_names[]= {"Note", "Warning", "Error", "?"};
-static int warning_level_length[]= { 4, 7, 5, 1 };
+LEX_STRING warning_level_names[]=
+{
+ {(char*) STRING_WITH_LEN("Note")},
+ {(char*) STRING_WITH_LEN("Warning")},
+ {(char*) STRING_WITH_LEN("Error")},
+ {(char*) STRING_WITH_LEN("?")}
+};
bool mysqld_show_warnings(THD *thd, ulong levels_to_show)
{
@@ -246,8 +251,8 @@
if (idx > unit->select_limit_cnt)
break;
protocol->prepare_for_resend();
- protocol->store(warning_level_names[err->level],
- warning_level_length[err->level], system_charset_info);
+ protocol->store(warning_level_names[err->level].str,
+ warning_level_names[err->level].length, system_charset_info);
protocol->store((uint32) err->code);
protocol->store(err->msg, strlen(err->msg), system_charset_info);
if (protocol->write())
| Thread |
|---|
| • bk commit into 5.1 tree (andrey:1.2101) BUG#17289 | ahristov | 10 Feb |