1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +03:00

Merge 10.2 into 10.3

This commit is contained in:
Marko Mäkelä
2021-10-21 13:41:04 +03:00
70 changed files with 1947 additions and 527 deletions

View File

@ -9624,8 +9624,8 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop,
LEX_USER *user_from, LEX_USER *user_to)
{
int result= 0;
int idx;
int elements;
bool restart;
const char *UNINIT_VAR(user);
const char *UNINIT_VAR(host);
ACL_USER *acl_user= NULL;
@ -9734,84 +9734,100 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop,
DBUG_RETURN(-1);
}
#ifdef EXTRA_DEBUG
DBUG_PRINT("loop",("scan struct: %u search user: '%s' host: '%s'",
struct_no, user_from->user.str, user_from->host.str));
#endif
/* Loop over all elements *backwards* (see the comment below). */
for (idx= elements - 1; idx >= 0; idx--)
{
/*
Get a pointer to the element.
*/
switch (struct_no) {
case USER_ACL:
acl_user= dynamic_element(&acl_users, idx, ACL_USER*);
user= acl_user->user.str;
host= acl_user->host.hostname;
break;
/* Loop over elements backwards as it may reduce the number of mem-moves
for dynamic arrays.
case DB_ACL:
acl_db= &acl_dbs.at(idx);
user= acl_db->user;
host= acl_db->host.hostname;
We restart the loop, if we deleted or updated anything in a hash table
because calling my_hash_delete or my_hash_update shuffles elements indices
and we can miss some if we do only one scan.
*/
do {
restart= false;
for (int idx= elements - 1; idx >= 0; idx--)
{
/*
Get a pointer to the element.
*/
switch (struct_no) {
case USER_ACL:
acl_user= dynamic_element(&acl_users, idx, ACL_USER*);
user= acl_user->user.str;
host= acl_user->host.hostname;
break;
case COLUMN_PRIVILEGES_HASH:
case PROC_PRIVILEGES_HASH:
case FUNC_PRIVILEGES_HASH:
case PACKAGE_SPEC_PRIVILEGES_HASH:
case PACKAGE_BODY_PRIVILEGES_HASH:
grant_name= (GRANT_NAME*) my_hash_element(grant_name_hash, idx);
user= grant_name->user;
host= grant_name->host.hostname;
break;
case DB_ACL:
acl_db= &acl_dbs.at(idx);
user= acl_db->user;
host= acl_db->host.hostname;
break;
case PROXY_USERS_ACL:
acl_proxy_user= dynamic_element(&acl_proxy_users, idx, ACL_PROXY_USER*);
user= acl_proxy_user->get_user();
host= acl_proxy_user->get_host();
break;
case COLUMN_PRIVILEGES_HASH:
case PROC_PRIVILEGES_HASH:
case FUNC_PRIVILEGES_HASH:
case PACKAGE_SPEC_PRIVILEGES_HASH:
case PACKAGE_BODY_PRIVILEGES_HASH:
grant_name= (GRANT_NAME*) my_hash_element(grant_name_hash, idx);
user= grant_name->user;
host= grant_name->host.hostname;
break;
case ROLES_MAPPINGS_HASH:
role_grant_pair= (ROLE_GRANT_PAIR *) my_hash_element(roles_mappings_hash, idx);
user= role_grant_pair->u_uname;
host= role_grant_pair->u_hname;
break;
case PROXY_USERS_ACL:
acl_proxy_user= dynamic_element(&acl_proxy_users, idx, ACL_PROXY_USER*);
user= acl_proxy_user->get_user();
host= acl_proxy_user->get_host();
break;
default:
DBUG_ASSERT(0);
}
if (! user)
user= "";
if (! host)
host= "";
case ROLES_MAPPINGS_HASH:
role_grant_pair= (ROLE_GRANT_PAIR *) my_hash_element(roles_mappings_hash, idx);
user= role_grant_pair->u_uname;
host= role_grant_pair->u_hname;
break;
default:
DBUG_ASSERT(0);
}
if (! user)
user= "";
if (! host)
host= "";
#ifdef EXTRA_DEBUG
DBUG_PRINT("loop",("scan struct: %u index: %u user: '%s' host: '%s'",
struct_no, idx, user, host));
DBUG_PRINT("loop",("scan struct: %u index: %u user: '%s' host: '%s'",
struct_no, idx, user, host));
#endif
if (struct_no == ROLES_MAPPINGS_HASH)
{
const char* role= role_grant_pair->r_uname? role_grant_pair->r_uname: "";
if (user_from->is_role())
if (struct_no == ROLES_MAPPINGS_HASH)
{
/* When searching for roles within the ROLES_MAPPINGS_HASH, we have
to check both the user field as well as the role field for a match.
const char* role= role_grant_pair->r_uname? role_grant_pair->r_uname: "";
if (user_from->is_role())
{
/* When searching for roles within the ROLES_MAPPINGS_HASH, we have
to check both the user field as well as the role field for a match.
It is possible to have a role granted to a role. If we are going
to modify the mapping entry, it needs to be done on either on the
"user" end (here represented by a role) or the "role" end. At least
one part must match.
It is possible to have a role granted to a role. If we are going
to modify the mapping entry, it needs to be done on either on the
"user" end (here represented by a role) or the "role" end. At least
one part must match.
If the "user" end has a not-empty host string, it can never match
as we are searching for a role here. A role always has an empty host
string.
*/
if ((*host || strcmp(user_from->user.str, user)) &&
strcmp(user_from->user.str, role))
continue;
If the "user" end has a not-empty host string, it can never match
as we are searching for a role here. A role always has an empty host
string.
*/
if ((*host || strcmp(user_from->user.str, user)) &&
strcmp(user_from->user.str, role))
continue;
}
else
{
if (strcmp(user_from->user.str, user) ||
my_strcasecmp(system_charset_info, user_from->host.str, host))
continue;
}
}
else
{
@ -9819,158 +9835,135 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop,
my_strcasecmp(system_charset_info, user_from->host.str, host))
continue;
}
}
else
{
if (strcmp(user_from->user.str, user) ||
my_strcasecmp(system_charset_info, user_from->host.str, host))
continue;
}
result= 1; /* At least one element found. */
if ( drop )
{
elements--;
switch ( struct_no ) {
case USER_ACL:
free_acl_user(dynamic_element(&acl_users, idx, ACL_USER*));
delete_dynamic_element(&acl_users, idx);
break;
result= 1; /* At least one element found. */
if ( drop )
{
elements--;
switch ( struct_no ) {
case USER_ACL:
free_acl_user(dynamic_element(&acl_users, idx, ACL_USER*));
delete_dynamic_element(&acl_users, idx);
break;
case DB_ACL:
acl_dbs.del(idx);
break;
case DB_ACL:
acl_dbs.del(idx);
break;
case COLUMN_PRIVILEGES_HASH:
case PROC_PRIVILEGES_HASH:
case FUNC_PRIVILEGES_HASH:
case PACKAGE_SPEC_PRIVILEGES_HASH:
case PACKAGE_BODY_PRIVILEGES_HASH:
my_hash_delete(grant_name_hash, (uchar*) grant_name);
/*
In our HASH implementation on deletion one elements
is moved into a place where a deleted element was,
and the last element is moved into the empty space.
Thus we need to re-examine the current element, but
we don't have to restart the search from the beginning.
*/
if (idx != elements)
idx++;
break;
case COLUMN_PRIVILEGES_HASH:
case PROC_PRIVILEGES_HASH:
case FUNC_PRIVILEGES_HASH:
case PACKAGE_SPEC_PRIVILEGES_HASH:
case PACKAGE_BODY_PRIVILEGES_HASH:
my_hash_delete(grant_name_hash, (uchar*) grant_name);
restart= true;
break;
case PROXY_USERS_ACL:
delete_dynamic_element(&acl_proxy_users, idx);
break;
case PROXY_USERS_ACL:
delete_dynamic_element(&acl_proxy_users, idx);
break;
case ROLES_MAPPINGS_HASH:
my_hash_delete(roles_mappings_hash, (uchar*) role_grant_pair);
if (idx != elements)
idx++;
break;
case ROLES_MAPPINGS_HASH:
my_hash_delete(roles_mappings_hash, (uchar*) role_grant_pair);
restart= true;
break;
default:
DBUG_ASSERT(0);
break;
default:
DBUG_ASSERT(0);
break;
}
}
}
else if ( user_to )
{
switch ( struct_no ) {
case USER_ACL:
acl_user->user.str= strdup_root(&acl_memroot, user_to->user.str);
acl_user->user.length= user_to->user.length;
update_hostname(&acl_user->host, strdup_root(&acl_memroot, user_to->host.str));
acl_user->hostname_length= strlen(acl_user->host.hostname);
break;
else if ( user_to )
{
switch ( struct_no ) {
case USER_ACL:
acl_user->user.str= strdup_root(&acl_memroot, user_to->user.str);
acl_user->user.length= user_to->user.length;
update_hostname(&acl_user->host, strdup_root(&acl_memroot, user_to->host.str));
acl_user->hostname_length= strlen(acl_user->host.hostname);
break;
case DB_ACL:
acl_db->user= strdup_root(&acl_memroot, user_to->user.str);
update_hostname(&acl_db->host, strdup_root(&acl_memroot, user_to->host.str));
break;
case DB_ACL:
acl_db->user= strdup_root(&acl_memroot, user_to->user.str);
update_hostname(&acl_db->host, strdup_root(&acl_memroot, user_to->host.str));
break;
case COLUMN_PRIVILEGES_HASH:
case PROC_PRIVILEGES_HASH:
case FUNC_PRIVILEGES_HASH:
case PACKAGE_SPEC_PRIVILEGES_HASH:
case PACKAGE_BODY_PRIVILEGES_HASH:
{
/*
Save old hash key and its length to be able to properly update
element position in hash.
*/
char *old_key= grant_name->hash_key;
size_t old_key_length= grant_name->key_length;
case COLUMN_PRIVILEGES_HASH:
case PROC_PRIVILEGES_HASH:
case FUNC_PRIVILEGES_HASH:
case PACKAGE_SPEC_PRIVILEGES_HASH:
case PACKAGE_BODY_PRIVILEGES_HASH:
{
/*
Save old hash key and its length to be able to properly update
element position in hash.
*/
char *old_key= grant_name->hash_key;
size_t old_key_length= grant_name->key_length;
/*
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);
/*
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
*/
my_hash_update(grant_name_hash, (uchar*) grant_name, (uchar*) old_key,
old_key_length);
/*
hash_update() operation could have moved element from the tail or
the head of the hash to the current position. But it can never
move an element from the head to the tail or from the tail to the
head over the current element.
So we need to examine the current element once again, but
we don't need to restart the search from the beginning.
*/
idx++;
/*
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
*/
my_hash_update(grant_name_hash, (uchar*) grant_name, (uchar*) old_key,
old_key_length);
restart= true;
break;
}
case PROXY_USERS_ACL:
acl_proxy_user->set_user (&acl_memroot, user_to->user.str);
acl_proxy_user->set_host (&acl_memroot, user_to->host.str);
break;
case ROLES_MAPPINGS_HASH:
{
/*
Save old hash key and its length to be able to properly update
element position in hash.
*/
char *old_key= role_grant_pair->hashkey.str;
size_t old_key_length= role_grant_pair->hashkey.length;
bool oom;
if (user_to->is_role())
oom= role_grant_pair->init(&acl_memroot, role_grant_pair->u_uname,
role_grant_pair->u_hname,
user_to->user.str, false);
else
oom= role_grant_pair->init(&acl_memroot, user_to->user.str,
user_to->host.str,
role_grant_pair->r_uname, false);
if (oom)
DBUG_RETURN(-1);
my_hash_update(roles_mappings_hash, (uchar*) role_grant_pair,
(uchar*) old_key, old_key_length);
restart= true;
break;
}
default:
DBUG_ASSERT(0);
break;
}
case PROXY_USERS_ACL:
acl_proxy_user->set_user (&acl_memroot, user_to->user.str);
acl_proxy_user->set_host (&acl_memroot, user_to->host.str);
break;
case ROLES_MAPPINGS_HASH:
{
/*
Save old hash key and its length to be able to properly update
element position in hash.
*/
char *old_key= role_grant_pair->hashkey.str;
size_t old_key_length= role_grant_pair->hashkey.length;
bool oom;
if (user_to->is_role())
oom= role_grant_pair->init(&acl_memroot, role_grant_pair->u_uname,
role_grant_pair->u_hname,
user_to->user.str, false);
else
oom= role_grant_pair->init(&acl_memroot, user_to->user.str,
user_to->host.str,
role_grant_pair->r_uname, false);
if (oom)
DBUG_RETURN(-1);
my_hash_update(roles_mappings_hash, (uchar*) role_grant_pair,
(uchar*) old_key, old_key_length);
idx++; // see the comment above
break;
}
default:
DBUG_ASSERT(0);
}
else
{
/* If search is requested, we do not need to search further. */
break;
}
}
else
{
/* If search is requested, we do not need to search further. */
break;
}
}
} while (restart);
#ifdef EXTRA_DEBUG
DBUG_PRINT("loop",("scan struct: %u result %d", struct_no, result));
#endif