summaryrefslogtreecommitdiff
path: root/sql/sql_acl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_acl.cc')
-rw-r--r--sql/sql_acl.cc371
1 files changed, 182 insertions, 189 deletions
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 89fecc92e9b..f62dd5471eb 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -9645,8 +9645,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;
@@ -9747,82 +9747,98 @@ 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:
- 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:
+ 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
{
@@ -9830,154 +9846,131 @@ 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:
- 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:
+ 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:
- {
- /*
- 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:
+ {
+ /*
+ 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);
+
+ /*
+ 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;
+ }
- /*
- 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++;
+ 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 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;
+ }
- 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
+ default:
+ DBUG_ASSERT(0);
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