List:Commits« Previous MessageNext Message »
From:ahristov Date:February 10 2006 3:03pm
Subject:bk commit into 5.1 tree (andrey:1.2101) BUG#17289
View as plain text  
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#17289ahristov10 Feb