List:Commits« Previous MessageNext Message »
From:Tatiana A. Nurnberg Date:May 29 2009 3:58pm
Subject:bzr commit into mysql-5.1-bugteam branch (azundris:2912)
View as plain text  
#At file:///misc/mysql/forest/39200k/51-39200k/ based on revid:azundris@stripped

 2912 Tatiana A. Nurnberg	2009-05-29 [merge]
      auto-merge

    modified:
      mysql-test/r/grant.result
      mysql-test/t/grant.test
      sql/sp.cc
      sql/sp.h
      sql/sql_acl.cc
      sql/sql_acl.h
      sql/sql_class.cc
      sql/sql_class.h
      sql/sql_parse.cc
=== modified file 'mysql-test/r/grant.result'
--- a/mysql-test/r/grant.result	2009-02-25 12:18:24 +0000
+++ b/mysql-test/r/grant.result	2009-05-29 13:37:54 +0000
@@ -1358,3 +1358,58 @@ DROP USER 'userbug33464'@'localhost';
 USE test;
 DROP DATABASE dbbug33464;
 SET @@global.log_bin_trust_function_creators= @old_log_bin_trust_function_creators;
+CREATE USER user1;
+CREATE USER user2;
+GRANT CREATE ON db1.* TO 'user1'@'localhost';
+GRANT CREATE ROUTINE ON db1.* TO 'user1'@'localhost';
+GRANT CREATE ON db1.* TO 'user2'@'%';
+GRANT CREATE ROUTINE ON db1.* TO 'user2'@'%';
+FLUSH PRIVILEGES;
+SHOW GRANTS FOR 'user1'@'localhost';
+Grants for user1@localhost
+GRANT USAGE ON *.* TO 'user1'@'localhost'
+GRANT CREATE, CREATE ROUTINE ON `db1`.* TO 'user1'@'localhost'
+** Connect as user1 and create a procedure.
+** The creation will imply implicitly assigned
+** EXECUTE and ALTER ROUTINE privileges to
+** the current user user1@localhost. 
+SELECT @@GLOBAL.sql_mode;
+@@GLOBAL.sql_mode
+
+SELECT @@SESSION.sql_mode;
+@@SESSION.sql_mode
+
+CREATE DATABASE db1;
+CREATE PROCEDURE db1.proc1(p1 INT)
+BEGIN
+SET @x = 0;
+REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT;
+END ;||
+** Connect as user2 and create a procedure.
+** Implicitly assignment of privileges will
+** fail because the user2@localhost is an
+** unknown user.
+CREATE PROCEDURE db1.proc2(p1 INT)
+BEGIN
+SET @x = 0;
+REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT;
+END ;||
+Warnings:
+Warning	1404	Failed to grant EXECUTE and ALTER ROUTINE privileges
+SHOW GRANTS FOR 'user1'@'localhost';
+Grants for user1@localhost
+GRANT USAGE ON *.* TO 'user1'@'localhost'
+GRANT CREATE, CREATE ROUTINE ON `db1`.* TO 'user1'@'localhost'
+GRANT EXECUTE, ALTER ROUTINE ON PROCEDURE `db1`.`proc1` TO 'user1'@'localhost'
+SHOW GRANTS FOR 'user2';
+Grants for user2@%
+GRANT USAGE ON *.* TO 'user2'@'%'
+GRANT CREATE, CREATE ROUTINE ON `db1`.* TO 'user2'@'%'
+DROP PROCEDURE db1.proc1;
+DROP PROCEDURE db1.proc2;
+REVOKE ALL ON db1.* FROM 'user1'@'localhost';
+REVOKE ALL ON db1.* FROM 'user2'@'%';
+DROP USER 'user1';
+DROP USER 'user1'@'localhost';
+DROP USER 'user2';
+DROP DATABASE db1;

=== modified file 'mysql-test/t/grant.test'
--- a/mysql-test/t/grant.test	2009-02-10 10:23:47 +0000
+++ b/mysql-test/t/grant.test	2009-05-29 13:37:54 +0000
@@ -1471,5 +1471,59 @@ DROP DATABASE dbbug33464;
 
 SET @@global.log_bin_trust_function_creators= @old_log_bin_trust_function_creators;
 
+#
+# Bug#44658 Create procedure makes server crash when user does not have ALL privilege
+#
+CREATE USER user1;
+CREATE USER user2;
+GRANT CREATE ON db1.* TO 'user1'@'localhost';
+GRANT CREATE ROUTINE ON db1.* TO 'user1'@'localhost';
+GRANT CREATE ON db1.* TO 'user2'@'%';
+GRANT CREATE ROUTINE ON db1.* TO 'user2'@'%';
+FLUSH PRIVILEGES;
+SHOW GRANTS FOR 'user1'@'localhost';
+connect (con1,localhost,user1,,);
+--echo ** Connect as user1 and create a procedure.
+--echo ** The creation will imply implicitly assigned
+--echo ** EXECUTE and ALTER ROUTINE privileges to
+--echo ** the current user user1@localhost. 
+SELECT @@GLOBAL.sql_mode;
+SELECT @@SESSION.sql_mode;
+CREATE DATABASE db1;
+DELIMITER ||;
+CREATE PROCEDURE db1.proc1(p1 INT)
+ BEGIN
+ SET @x = 0;
+ REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT;
+ END ;||
+DELIMITER ;||
+
+connect (con2,localhost,user2,,);
+--echo ** Connect as user2 and create a procedure.
+--echo ** Implicitly assignment of privileges will
+--echo ** fail because the user2@localhost is an
+--echo ** unknown user.
+DELIMITER ||;
+CREATE PROCEDURE db1.proc2(p1 INT)
+ BEGIN
+ SET @x = 0;
+ REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT;
+ END ;||
+DELIMITER ;||
+
+connection default;
+SHOW GRANTS FOR 'user1'@'localhost';
+SHOW GRANTS FOR 'user2';
+disconnect con1;
+disconnect con2;
+DROP PROCEDURE db1.proc1;
+DROP PROCEDURE db1.proc2;
+REVOKE ALL ON db1.* FROM 'user1'@'localhost';
+REVOKE ALL ON db1.* FROM 'user2'@'%';
+DROP USER 'user1';
+DROP USER 'user1'@'localhost';
+DROP USER 'user2';
+DROP DATABASE db1;
+
 # Wait till we reached the initial number of concurrent sessions
 --source include/wait_until_count_sessions.inc

=== modified file 'sql/sp.cc'
--- a/sql/sp.cc	2009-04-08 23:42:51 +0000
+++ b/sql/sp.cc	2009-05-29 13:37:54 +0000
@@ -1308,13 +1308,20 @@ sp_find_routine(THD *thd, int type, sp_n
 /**
   This is used by sql_acl.cc:mysql_routine_grant() and is used to find
   the routines in 'routines'.
+
+  @param thd Thread handler
+  @param routines List of needles in the hay stack
+  @param any Any of the needles are good enough
+
+  @return
+    @retval FALSE Found.
+    @retval TRUE  Not found
 */
 
-int
-sp_exist_routines(THD *thd, TABLE_LIST *routines, bool any, bool no_error)
+bool
+sp_exist_routines(THD *thd, TABLE_LIST *routines, bool any)
 {
   TABLE_LIST *routine;
-  bool result= 0;
   bool sp_object_found;
   DBUG_ENTER("sp_exists_routine");
   for (routine= routines; routine; routine= routine->next_global)
@@ -1336,21 +1343,16 @@ sp_exist_routines(THD *thd, TABLE_LIST *
     if (sp_object_found)
     {
       if (any)
-        DBUG_RETURN(1);
-      result= 1;
+        break;
     }
     else if (!any)
     {
-      if (!no_error)
-      {
-	my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION or PROCEDURE", 
-		 routine->table_name);
-	DBUG_RETURN(-1);
-      }
-      DBUG_RETURN(0);
+      my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION or PROCEDURE",
+               routine->table_name);
+      DBUG_RETURN(TRUE);
     }
   }
-  DBUG_RETURN(result);
+  DBUG_RETURN(FALSE);
 }
 
 

=== modified file 'sql/sp.h'
--- a/sql/sp.h	2008-04-08 16:31:40 +0000
+++ b/sql/sp.h	2009-05-29 13:37:54 +0000
@@ -39,8 +39,8 @@ sp_head *
 sp_find_routine(THD *thd, int type, sp_name *name,
                 sp_cache **cp, bool cache_only);
 
-int
-sp_exist_routines(THD *thd, TABLE_LIST *procs, bool any, bool no_error);
+bool
+sp_exist_routines(THD *thd, TABLE_LIST *procs, bool any);
 
 int
 sp_routine_exists_in_table(THD *thd, int type, sp_name *name);

=== modified file 'sql/sql_acl.cc'
--- a/sql/sql_acl.cc	2009-05-25 13:00:18 +0000
+++ b/sql/sql_acl.cc	2009-05-29 14:25:22 +0000
@@ -3198,26 +3198,24 @@ int mysql_table_grant(THD *thd, TABLE_LI
 }
 
 
-/*
+/**
   Store routine level grants in the privilege tables
 
-  SYNOPSIS
-    mysql_routine_grant()
-    thd			Thread handle
-    table_list		List of routines to give grant
-    is_proc             true indicates routine list are procedures
-    user_list		List of users to give grant
-    rights		Table level grant
-    revoke_grant	Set to 1 if this is a REVOKE command
-
-  RETURN
-    0	ok
-    1	error
+  @param thd Thread handle
+  @param table_list List of routines to give grant
+  @param is_proc Is this a list of procedures?
+  @param user_list List of users to give grant
+  @param rights Table level grant
+  @param revoke_grant Is this is a REVOKE command?
+
+  @return
+    @retval FALSE Success.
+    @retval TRUE An error occurred.
 */
 
 bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
 			 List <LEX_USER> &user_list, ulong rights,
-			 bool revoke_grant, bool no_error)
+			 bool revoke_grant, bool write_to_binlog)
 {
   List_iterator <LEX_USER> str_list (user_list);
   LEX_USER *Str, *tmp_Str;
@@ -3228,22 +3226,20 @@ bool mysql_routine_grant(THD *thd, TABLE
 
   if (!initialized)
   {
-    if (!no_error)
-      my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0),
-               "--skip-grant-tables");
+    my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0),
+             "--skip-grant-tables");
     DBUG_RETURN(TRUE);
   }
   if (rights & ~PROC_ACLS)
   {
-    if (!no_error)
-      my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER(ER_ILLEGAL_GRANT_FOR_TABLE),
-        	 MYF(0));
+    my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER(ER_ILLEGAL_GRANT_FOR_TABLE),
+               MYF(0));
     DBUG_RETURN(TRUE);
   }
 
   if (!revoke_grant)
   {
-    if (sp_exist_routines(thd, table_list, is_proc, no_error)<0)
+    if (sp_exist_routines(thd, table_list, is_proc))
       DBUG_RETURN(TRUE);
   }
 
@@ -3324,9 +3320,8 @@ bool mysql_routine_grant(THD *thd, TABLE
     {
       if (revoke_grant)
       {
-        if (!no_error)
-          my_error(ER_NONEXISTING_PROC_GRANT, MYF(0),
-		   Str->user.str, Str->host.str, table_name);
+        my_error(ER_NONEXISTING_PROC_GRANT, MYF(0),
+	         Str->user.str, Str->host.str, table_name);
 	result= TRUE;
 	continue;
       }
@@ -3351,16 +3346,14 @@ bool mysql_routine_grant(THD *thd, TABLE
   }
   thd->mem_root= old_root;
   pthread_mutex_unlock(&acl_cache->lock);
-  if (!result && !no_error)
+
+  if (write_to_binlog)
   {
     write_bin_log(thd, TRUE, thd->query, thd->query_length);
   }
 
   rw_unlock(&LOCK_grant);
 
-  if (!result && !no_error)
-    my_ok(thd);
-
   /* Tables are automatically closed */
   DBUG_RETURN(result);
 }
@@ -6157,21 +6150,20 @@ bool sp_revoke_privileges(THD *thd, cons
 }
 
 
-/*
+/**
   Grant EXECUTE,ALTER privilege for a stored procedure
 
-  SYNOPSIS
-    sp_grant_privileges()
-    thd                         The current thread.
-    db				DB of the stored procedure
-    name			Name of the stored procedure
+  @param thd The current thread.
+  @param sp_db
+  @param sp_name
+  @param is_proc
 
-  RETURN
-    0           OK.
-    < 0         Error. Error message not yet sent.
+  @return
+    @retval FALSE Success
+    @retval TRUE An error occured. Error message not yet sent.
 */
 
-int sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
+bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
                          bool is_proc)
 {
   Security_context *sctx= thd->security_ctx;
@@ -6181,6 +6173,7 @@ int sp_grant_privileges(THD *thd, const
   bool result;
   ACL_USER *au;
   char passwd_buff[SCRAMBLED_PASSWORD_CHAR_LENGTH+1];
+  Dummy_error_handler error_handler;
   DBUG_ENTER("sp_grant_privileges");
 
   if (!(combo=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
@@ -6231,8 +6224,11 @@ int sp_grant_privileges(THD *thd, const
     }
     else
     {
-      my_error(ER_PASSWD_LENGTH, MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH);
-      return -1;
+      push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                          ER_PASSWD_LENGTH,
+                          ER(ER_PASSWD_LENGTH),
+                          SCRAMBLED_PASSWORD_CHAR_LENGTH);
+      return TRUE;
     }
     combo->password.str= passwd_buff;
   }
@@ -6248,8 +6244,14 @@ int sp_grant_privileges(THD *thd, const
   thd->lex->ssl_type= SSL_TYPE_NOT_SPECIFIED;
   bzero((char*) &thd->lex->mqh, sizeof(thd->lex->mqh));
 
+  /*
+    Only care about whether the operation failed or succeeded
+    as all errors will be handled later.
+  */
+  thd->push_internal_handler(&error_handler);
   result= mysql_routine_grant(thd, tables, is_proc, user_list,
-  				DEFAULT_CREATE_PROC_ACLS, 0, 1);
+                              DEFAULT_CREATE_PROC_ACLS, FALSE, FALSE);
+  thd->pop_internal_handler();
   DBUG_RETURN(result);
 }
 

=== modified file 'sql/sql_acl.h'
--- a/sql/sql_acl.h	2008-03-21 15:48:28 +0000
+++ b/sql/sql_acl.h	2009-05-29 13:37:54 +0000
@@ -233,7 +233,7 @@ int mysql_table_grant(THD *thd, TABLE_LI
                        bool revoke);
 bool mysql_routine_grant(THD *thd, TABLE_LIST *table, bool is_proc,
 			 List <LEX_USER> &user_list, ulong rights,
-			 bool revoke, bool no_error);
+			 bool revoke, bool write_to_binlog);
 my_bool grant_init();
 void grant_free(void);
 my_bool grant_reload(THD *thd);
@@ -264,7 +264,7 @@ void fill_effective_table_privileges(THD
                                      const char *db, const char *table);
 bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
                           bool is_proc);
-int sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
+bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
                          bool is_proc);
 bool check_routine_level_acl(THD *thd, const char *db, const char *name,
                              bool is_proc);

=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc	2009-05-15 13:25:29 +0000
+++ b/sql/sql_class.cc	2009-05-29 14:25:22 +0000
@@ -674,31 +674,40 @@ THD::THD()
 
 void THD::push_internal_handler(Internal_error_handler *handler)
 {
-  /*
-    TODO: The current implementation is limited to 1 handler at a time only.
-    THD and sp_rcontext need to be modified to use a common handler stack.
-  */
-  DBUG_ASSERT(m_internal_handler == NULL);
-  m_internal_handler= handler;
+  if (m_internal_handler)
+  {
+    handler->m_prev_internal_handler= m_internal_handler;
+    m_internal_handler= handler;
+  }
+  else
+  {
+    m_internal_handler= handler;
+  }
 }
 
 
 bool THD::handle_error(uint sql_errno, const char *message,
                        MYSQL_ERROR::enum_warning_level level)
 {
-  if (m_internal_handler)
+  if (!m_internal_handler)
+    return FALSE;
+
+  for (Internal_error_handler *error_handler= m_internal_handler;
+       error_handler;
+       error_handler= m_internal_handler->m_prev_internal_handler)
   {
-    return m_internal_handler->handle_error(sql_errno, message, level, this);
+    if (error_handler->handle_error(sql_errno, message, level, this))
+    return TRUE;
   }
 
-  return FALSE;                                 // 'FALSE', as per coding style
+  return FALSE;
 }
 
 
 void THD::pop_internal_handler()
 {
   DBUG_ASSERT(m_internal_handler != NULL);
-  m_internal_handler= NULL;
+  m_internal_handler= m_internal_handler->m_prev_internal_handler;
 }
 
 extern "C"

=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h	2009-05-15 12:57:51 +0000
+++ b/sql/sql_class.h	2009-05-29 14:25:22 +0000
@@ -1036,7 +1036,10 @@ show_system_thread(enum_thread_type thre
 class Internal_error_handler
 {
 protected:
-  Internal_error_handler() {}
+  Internal_error_handler() :
+    m_prev_internal_handler(NULL)
+  {}
+
   virtual ~Internal_error_handler() {}
 
 public:
@@ -1069,6 +1072,28 @@ public:
                             const char *message,
                             MYSQL_ERROR::enum_warning_level level,
                             THD *thd) = 0;
+private:
+  Internal_error_handler *m_prev_internal_handler;
+  friend class THD;
+};
+
+
+/**
+  Implements the trivial error handler which cancels all error states
+  and prevents an SQLSTATE to be set.
+*/
+
+class Dummy_error_handler : public Internal_error_handler
+{
+public:
+  bool handle_error(uint sql_errno,
+                    const char *message,
+                    MYSQL_ERROR::enum_warning_level level,
+                    THD *thd)
+  {
+    /* Ignore error */
+    return TRUE;
+  }
 };
 
 
@@ -2210,6 +2235,9 @@ public:
   thd_scheduler scheduler;
 
 public:
+  inline Internal_error_handler *get_internal_handler()
+  { return m_internal_handler; }
+
   /**
     Add an internal error handler to the thread execution context.
     @param handler the exception handler to add

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	2009-05-15 13:40:09 +0000
+++ b/sql/sql_parse.cc	2009-05-29 14:25:22 +0000
@@ -3880,7 +3880,9 @@ end_with_restore_list:
         res= mysql_routine_grant(thd, all_tables,
                                  lex->type == TYPE_ENUM_PROCEDURE, 
                                  lex->users_list, grants,
-                                 lex->sql_command == SQLCOM_REVOKE, 0);
+                                 lex->sql_command == SQLCOM_REVOKE, TRUE);
+        if (!res)
+          my_ok(thd);
       }
       else
       {


Attachment: [text/bzr-bundle] bzr/azundris@mysql.com-20090529155845-way72kgxecurbn8y.bundle
Thread
bzr commit into mysql-5.1-bugteam branch (azundris:2912) Tatiana A. Nurnberg29 May