mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Fix for bug#36544 "DROP USER does not remove stored function
privileges". The first problem was that DROP USER didn't properly remove privileges on stored functions from in-memory structures. So the dropped user could have called stored functions on which he had privileges before being dropped while his connection was still around. Even worse if a new user with the same name was created he would inherit privileges on stored functions from the dropped user. Similar thing happened with old user name and function privileges during RENAME USER. This problem stemmed from the fact that the handle_grant_data() function which handled DROP/RENAME USER didn't take any measures to update in-memory hash with information about function privileges after updating them on disk. This patch solves this problem by adding code doing just that. The second problem was that RENAME USER didn't properly update in-memory structures describing table-level privileges and privileges on stored procedures. As result such privileges could have been lost after a rename (i.e. not associated with the new name of user) and inherited by a new user with the same name as the old name of the original user. This problem was caused by code handling RENAME USER in handle_grant_struct() which [sic!]: a) tried to update wrong (tables) hash when updating stored procedure privileges for new user name. b) passed wrong arguments to function performing the hash update and didn't take into account the way in which such update could have changed the order of the hash elements. This patch solves this problem by ensuring that a) the correct hash is updated, b) correct arguments are used for the hash_update() function and c) we take into account possible changes in the order of hash elements.
This commit is contained in:
122
sql/sql_acl.cc
122
sql/sql_acl.cc
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2000-2003 MySQL AB
|
||||
/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -5048,18 +5048,15 @@ static int handle_grant_table(TABLE_LIST *tables, uint table_no, bool drop,
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/**
|
||||
Handle an in-memory privilege structure.
|
||||
|
||||
SYNOPSIS
|
||||
handle_grant_struct()
|
||||
struct_no The number of the structure to handle (0..3).
|
||||
drop If user_from is to be dropped.
|
||||
user_from The the user to be searched/dropped/renamed.
|
||||
user_to The new name for the user if to be renamed,
|
||||
NULL otherwise.
|
||||
@param struct_no The number of the structure to handle (0..4).
|
||||
@param drop If user_from is to be dropped.
|
||||
@param user_from The the user to be searched/dropped/renamed.
|
||||
@param user_to The new name for the user if to be renamed, NULL otherwise.
|
||||
|
||||
DESCRIPTION
|
||||
@note
|
||||
Scan through all elements in an in-memory grant structure and apply
|
||||
the requested operation.
|
||||
Delete from grant structure if drop is true.
|
||||
@ -5069,12 +5066,12 @@ static int handle_grant_table(TABLE_LIST *tables, uint table_no, bool drop,
|
||||
0 acl_users
|
||||
1 acl_dbs
|
||||
2 column_priv_hash
|
||||
3 procs_priv_hash
|
||||
3 proc_priv_hash
|
||||
4 func_priv_hash
|
||||
|
||||
RETURN
|
||||
> 0 At least one element matched.
|
||||
0 OK, but no element matched.
|
||||
-1 Wrong arguments to function
|
||||
@retval > 0 At least one element matched.
|
||||
@retval 0 OK, but no element matched.
|
||||
@retval -1 Wrong arguments to function.
|
||||
*/
|
||||
|
||||
static int handle_grant_struct(uint struct_no, bool drop,
|
||||
@ -5088,6 +5085,7 @@ static int handle_grant_struct(uint struct_no, bool drop,
|
||||
ACL_USER *UNINIT_VAR(acl_user);
|
||||
ACL_DB *UNINIT_VAR(acl_db);
|
||||
GRANT_NAME *UNINIT_VAR(grant_name);
|
||||
HASH *UNINIT_VAR(grant_name_hash);
|
||||
DBUG_ENTER("handle_grant_struct");
|
||||
DBUG_PRINT("info",("scan struct: %u search: '%s'@'%s'",
|
||||
struct_no, user_from->user.str, user_from->host.str));
|
||||
@ -5104,9 +5102,15 @@ static int handle_grant_struct(uint struct_no, bool drop,
|
||||
break;
|
||||
case 2:
|
||||
elements= column_priv_hash.records;
|
||||
grant_name_hash= &column_priv_hash;
|
||||
break;
|
||||
case 3:
|
||||
elements= proc_priv_hash.records;
|
||||
grant_name_hash= &proc_priv_hash;
|
||||
break;
|
||||
case 4:
|
||||
elements= func_priv_hash.records;
|
||||
grant_name_hash= &func_priv_hash;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
@ -5136,16 +5140,13 @@ static int handle_grant_struct(uint struct_no, bool drop,
|
||||
break;
|
||||
|
||||
case 2:
|
||||
grant_name= (GRANT_NAME*) hash_element(&column_priv_hash, idx);
|
||||
case 3:
|
||||
case 4:
|
||||
grant_name= (GRANT_NAME*) hash_element(grant_name_hash, idx);
|
||||
user= grant_name->user;
|
||||
host= grant_name->host.hostname;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
grant_name= (GRANT_NAME*) hash_element(&proc_priv_hash, idx);
|
||||
user= grant_name->user;
|
||||
host= grant_name->host.hostname;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
@ -5176,14 +5177,25 @@ static int handle_grant_struct(uint struct_no, bool drop,
|
||||
break;
|
||||
|
||||
case 2:
|
||||
hash_delete(&column_priv_hash, (byte*) grant_name);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
hash_delete(&proc_priv_hash, (byte*) grant_name);
|
||||
case 4:
|
||||
hash_delete(grant_name_hash, (byte*) grant_name);
|
||||
break;
|
||||
}
|
||||
elements--;
|
||||
/*
|
||||
- If we are iterating through an array then we just have moved all
|
||||
elements after the current element one position closer to its head.
|
||||
This means that we have to take another look at the element at
|
||||
current position as it is a new element from the array's tail.
|
||||
- If we are iterating through a hash the current element was replaced
|
||||
with one of elements from the tail. So we also have to take a look
|
||||
at the new element in current position.
|
||||
Note that in our HASH implementation hash_delete() won't move any
|
||||
elements with position after current one to position before the
|
||||
current (i.e. from the tail to the head), so it is safe to continue
|
||||
iteration without re-starting.
|
||||
*/
|
||||
idx--;
|
||||
}
|
||||
else if ( user_to )
|
||||
@ -5201,22 +5213,41 @@ static int handle_grant_struct(uint struct_no, bool drop,
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
/*
|
||||
Update the grant structure with the new user name and
|
||||
host name
|
||||
*/
|
||||
grant_name->set_user_details(user_to->host.str, grant_name->db,
|
||||
user_to->user.str, grant_name->tname,
|
||||
TRUE);
|
||||
case 4:
|
||||
{
|
||||
/*
|
||||
Save old hash key and its length to be able properly update
|
||||
element position in hash.
|
||||
*/
|
||||
char *old_key= grant_name->hash_key;
|
||||
size_t old_key_length= grant_name->key_length;
|
||||
|
||||
/*
|
||||
Since username is part of the hash key, when the user name
|
||||
is renamed, the hash key is changed. Update the hash to
|
||||
ensure that the position matches the new hash key value
|
||||
*/
|
||||
hash_update(&column_priv_hash, (byte*) grant_name,
|
||||
(byte *) grant_name->hash_key, grant_name->key_length);
|
||||
break;
|
||||
/*
|
||||
Update the grant structure with the new user name and host name.
|
||||
*/
|
||||
grant_name->set_user_details(user_to->host.str, grant_name->db,
|
||||
user_to->user.str, grant_name->tname,
|
||||
TRUE);
|
||||
|
||||
/*
|
||||
Since username is part of the hash key, when the user name
|
||||
is renamed, the hash key is changed. Update the hash to
|
||||
ensure that the position matches the new hash key value
|
||||
*/
|
||||
hash_update(grant_name_hash, (byte*) grant_name, (byte*) old_key,
|
||||
old_key_length);
|
||||
/*
|
||||
hash_update() operation could have moved element from the tail
|
||||
of the hash to the current position. So we need to take a look
|
||||
at the element in current position once again.
|
||||
Thanks to the fact that hash_update() for our HASH implementation
|
||||
won't move any elements from the tail of the hash to the positions
|
||||
before the current one (a.k.a. head) it is safe to continue
|
||||
iteration without restarting.
|
||||
*/
|
||||
idx--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -5302,7 +5333,7 @@ static int handle_grant_data(TABLE_LIST *tables, bool drop,
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle procedures table. */
|
||||
/* Handle stored routines table. */
|
||||
if ((found= handle_grant_table(tables, 4, drop, user_from, user_to)) < 0)
|
||||
{
|
||||
/* Handle of table failed, don't touch in-memory array. */
|
||||
@ -5319,6 +5350,15 @@ static int handle_grant_data(TABLE_LIST *tables, bool drop,
|
||||
if (! drop && ! user_to)
|
||||
goto end;
|
||||
}
|
||||
/* Handle funcs array. */
|
||||
if (((handle_grant_struct(4, drop, user_from, user_to) && ! result) ||
|
||||
found) && ! result)
|
||||
{
|
||||
result= 1; /* At least one record/element found. */
|
||||
/* If search is requested, we do not need to search further. */
|
||||
if (! drop && ! user_to)
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle tables table. */
|
||||
|
Reference in New Issue
Block a user