From a4aec769b00a5a6c890305cb9f0d9c9f0c455511 Mon Sep 17 00:00:00 2001
From: "dellis@goetia.(none)" <>
Date: Mon, 18 Oct 2004 20:25:47 -0500
Subject: [PATCH 1/2] sql_acl.cc:   BUG #5831 Revoke privileges in a loop until
 no more privileges are revoked, because acl_dbs and column_priv_hash can
 re-organize during privilege removal.

---
 sql/sql_acl.cc | 122 +++++++++++++++++++++++++++++--------------------
 1 file changed, 73 insertions(+), 49 deletions(-)

diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index fc252c1f5ac..07647f4eb82 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -3623,67 +3623,91 @@ int mysql_revoke_all(THD *thd,  List <LEX_USER> &list)
     }
 
     /* Remove db access privileges */
-    for (counter= 0 ; counter < acl_dbs.elements ; )
+    /*
+      Because acl_dbs and column_priv_hash shrink and may re-order
+      as privileges are removed, removal occurs in a repeated loop
+      until no more privileges are revoked.
+     */
+    while (1)
     {
-      const char *user,*host;
-
-      acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*);
-      if (!(user=acl_db->user))
-	user= "";
-      if (!(host=acl_db->host.hostname))
-	host= "";
-
-      if (!strcmp(lex_user->user.str,user) &&
-	  !my_strcasecmp(system_charset_info, lex_user->host.str, host))
+      int revoke= 0;
+      for (counter= 0 ; counter < acl_dbs.elements ; )
       {
-	if (replace_db_table(tables[1].table, acl_db->db, *lex_user, ~0, 1))
-	  result= -1;
-	else
-	  continue;
+	const char *user,*host;
+	
+	acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*);
+	if (!(user=acl_db->user))
+	  user= "";
+	if (!(host=acl_db->host.hostname))
+	  host= "";
+	
+	if (!strcmp(lex_user->user.str,user) &&
+	    !my_strcasecmp(system_charset_info, lex_user->host.str, host))
+	{
+	  if (replace_db_table(tables[1].table, acl_db->db, *lex_user, ~0, 1))
+	    result= -1;
+	  else
+	  {
+	    revoke= 1;
+	    continue;
+	  }
+	}
+	++counter;
       }
-      ++counter;
+      if (!revoke)
+	break;
     }
 
     /* Remove column access */
-    for (counter= 0 ; counter < column_priv_hash.records ; )
+    while (1)
     {
-      const char *user,*host;
-      GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&column_priv_hash,
-							    counter);
-      if (!(user=grant_table->user))
-	user= "";
-      if (!(host=grant_table->host))
-	host= "";
-
-      if (!strcmp(lex_user->user.str,user) &&
-	  !my_strcasecmp(system_charset_info, lex_user->host.str, host))
+      int revoke= 0;
+      for (counter= 0 ; counter < column_priv_hash.records ; )
       {
-	if (replace_table_table(thd,grant_table,tables[2].table,*lex_user,
-				grant_table->db,
-				grant_table->tname,
-				~0, 0, 1))
+	const char *user,*host;
+	GRANT_TABLE *grant_table= (GRANT_TABLE*)hash_element(&column_priv_hash,
+							     counter);
+	if (!(user=grant_table->user))
+	  user= "";
+	if (!(host=grant_table->host))
+	  host= "";
+	
+	if (!strcmp(lex_user->user.str,user) &&
+	    !my_strcasecmp(system_charset_info, lex_user->host.str, host))
 	{
-	  result= -1;
-	}
-	else
-	{
-	  if (grant_table->cols)
-	  {
-	    List<LEX_COLUMN> columns;
-	    if (replace_column_table(grant_table,tables[3].table, *lex_user,
-				     columns,
-				     grant_table->db,
-				     grant_table->tname,
-				     ~0, 1))
-	      result= -1;
-	    else
-	      continue;
-	  }
+	  if (replace_table_table(thd,grant_table,tables[2].table,*lex_user,
+				  grant_table->db,
+				  grant_table->tname,
+				  ~0, 0, 1))
+	    result= -1;
 	  else
-	    continue;
+	  {
+	    if (grant_table->cols)
+	    {
+	      List<LEX_COLUMN> columns;
+	      if (replace_column_table(grant_table,tables[3].table, *lex_user,
+				       columns,
+				       grant_table->db,
+				       grant_table->tname,
+				       ~0, 1))
+		result= -1;
+	      else
+	      {
+		revoke= 1;
+		continue;
+	      }
+	    }
+	    else
+	    {
+	      revoke= 1;
+	      continue;
+	    }
+	  }
 	}
+	++counter;
       }
-      ++counter;
+      if (!revoke)
+	break;
     }
   }
 

From e1d5815341cfddde712c271fa3304fc71bd546ea Mon Sep 17 00:00:00 2001
From: "dellis@goetia.(none)" <>
Date: Fri, 22 Oct 2004 13:41:40 -0500
Subject: [PATCH 2/2] sql_acl.cc:   BUG #5831  Post-review changes, merging
 improvements from Monty.

---
 sql/sql_acl.cc | 67 +++++++++++++++++++++++---------------------------
 1 file changed, 31 insertions(+), 36 deletions(-)

diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 07647f4eb82..b44b4e9ada5 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -3590,7 +3590,7 @@ int mysql_drop_user(THD *thd, List <LEX_USER> &list)
 
 int mysql_revoke_all(THD *thd,  List <LEX_USER> &list)
 {
-  uint counter;
+  uint counter, revoked;
   int result;
   ACL_DB *acl_db;
   TABLE_LIST tables[4];
@@ -3628,10 +3628,9 @@ int mysql_revoke_all(THD *thd,  List <LEX_USER> &list)
       as privileges are removed, removal occurs in a repeated loop
       until no more privileges are revoked.
      */
-    while (1)
+    do
     {
-      int revoke= 0;
-      for (counter= 0 ; counter < acl_dbs.elements ; )
+      for (counter= 0, revoked= 0 ; counter < acl_dbs.elements ; )
       {
 	const char *user,*host;
 	
@@ -3644,25 +3643,25 @@ int mysql_revoke_all(THD *thd,  List <LEX_USER> &list)
 	if (!strcmp(lex_user->user.str,user) &&
 	    !my_strcasecmp(system_charset_info, lex_user->host.str, host))
 	{
-	  if (replace_db_table(tables[1].table, acl_db->db, *lex_user, ~0, 1))
-	    result= -1;
-	  else
+	  if (!replace_db_table(tables[1].table, acl_db->db, *lex_user, ~0, 1))
 	  {
-	    revoke= 1;
+	    /*
+	      Don't increment counter as replace_db_table deleted the
+	      current element in acl_dbs.
+	     */
+	    revoked= 1;
 	    continue;
 	  }
+	  result= -1; // Something went wrong
 	}
-	++counter;
+	counter++;
       }
-      if (!revoke)
-	break;
-    }
+    } while (revoked);
 
     /* Remove column access */
-    while (1)
+    do
     {
-      int revoke= 0;
-      for (counter= 0 ; counter < column_priv_hash.records ; )
+      for (counter= 0, revoked= 0 ; counter < column_priv_hash.records ; )
       {
 	const char *user,*host;
 	GRANT_TABLE *grant_table= (GRANT_TABLE*)hash_element(&column_priv_hash,
@@ -3679,36 +3678,32 @@ int mysql_revoke_all(THD *thd,  List <LEX_USER> &list)
 				  grant_table->db,
 				  grant_table->tname,
 				  ~0, 0, 1))
+	  {
 	    result= -1;
+	  }
 	  else
 	  {
-	    if (grant_table->cols)
+	    if (!grant_table->cols)
 	    {
-	      List<LEX_COLUMN> columns;
-	      if (replace_column_table(grant_table,tables[3].table, *lex_user,
-				       columns,
-				       grant_table->db,
-				       grant_table->tname,
-				       ~0, 1))
-		result= -1;
-	      else
-	      {
-		revoke= 1;
-		continue;
-	      }
-	    }
-	    else
-	    {
-	      revoke= 1;
+	      revoked= 1;
 	      continue;
 	    }
+	    List<LEX_COLUMN> columns;
+	    if (!replace_column_table(grant_table,tables[3].table, *lex_user,
+				     columns,
+				     grant_table->db,
+				     grant_table->tname,
+				     ~0, 1))
+	    {
+	      revoked= 1;
+	      continue;
+	    }
+	    result= -1;
 	  }
 	}
-	++counter;
+	counter++;
       }
-      if (!revoke)
-	break;
-    }
+    } while (revoked);
   }
 
   VOID(pthread_mutex_unlock(&acl_cache->lock));