Implemented Roles Mappings association between users and roles.

No more memory leaks in the code.
This commit is contained in:
Vicențiu Ciorbaru 2013-10-17 15:03:21 -07:00 committed by Sergei Golubchik
parent deffce1ace
commit 887a1ac862
2 changed files with 132 additions and 44 deletions

View File

@ -250,7 +250,7 @@ public:
dst->plugin.str= strmake_root(root, plugin.str, plugin.length);
dst->auth_string.str= safe_strdup_root(root, auth_string.str);
dst->host.hostname= safe_strdup_root(root, host.hostname);
dst->role_grants= this->role_grants;
bzero(&dst->role_grants, sizeof(role_grants));
return dst;
}
};
@ -262,7 +262,6 @@ public:
char *user,*db;
};
#ifndef NO_EMBEDDED_ACCESS_CHECKS
static void update_hostname(acl_host_and_ip *host, const char *hostname);
static ulong get_sort(uint count,...);
@ -528,13 +527,29 @@ static uchar* acl_entry_get_key(acl_entry *entry, size_t *length,
return (uchar*) entry->key;
}
uchar* acl_role_get_key(ACL_USER *entry, size_t *length,
my_bool not_used __attribute__((unused)))
static uchar* acl_role_get_key(ACL_USER *entry, size_t *length,
my_bool not_used __attribute__((unused)))
{
*length=(uint) entry->user.length;
return (uchar*) entry->user.str;
}
typedef struct st_role_grant
{
char *u_uname;
char *u_hname;
char *r_uname;
char *r_hname;
LEX_STRING hashkey;
} ROLE_GRANT_PAIR;
static uchar* acl_role_map_get_key(ROLE_GRANT_PAIR *entry, size_t *length,
my_bool not_used __attribute__((unused)))
{
*length=(uint) entry->hashkey.length;
return (uchar*) entry->hashkey.str;
}
#define IP_ADDR_STRLEN (3 + 1 + 3 + 1 + 3 + 1 + 3)
#define ACL_KEY_LENGTH (IP_ADDR_STRLEN + 1 + NAME_LEN + \
1 + USERNAME_LENGTH + 1)
@ -561,6 +576,13 @@ uchar* acl_role_get_key(ACL_USER *entry, size_t *length,
static DYNAMIC_ARRAY acl_hosts, acl_users, acl_dbs, acl_proxy_users;
static HASH acl_roles;
/*
An hash containing mappings user <--> role
A hash is used so as to make updates quickly
The hashkey used represents all the entries combined
*/
static HASH acl_roles_mappings;
static MEM_ROOT mem, memex;
static bool initialized=0;
static bool allow_all_hosts=1;
@ -584,6 +606,11 @@ static bool update_user_table(THD *thd, TABLE *table, const char *host,
static my_bool acl_load(THD *thd, TABLE_LIST *tables);
static my_bool grant_load(THD *thd, TABLE_LIST *tables);
static inline void get_grantor(THD *thd, char* grantor);
static my_bool acl_user_reset_grant(ACL_USER *user,
void * not_used __attribute__((unused)));
static my_bool add_role_user_mapping(ROLE_GRANT_PAIR *entry,
void * not_used __attribute__((unused)));
/*
Enumeration of various ACL's and Hashes used in handle_grant_struct()
*/
@ -597,12 +624,6 @@ enum enum_acl_lists
PROXY_USERS_ACL
};
typedef struct st_role_grant
{
char *username;
char *hostname;
} ROLE_GRANT_PAIR;
static
void
free_acl_user(ACL_USER *user)
@ -863,7 +884,8 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
table->use_all_columns();
(void) my_init_dynamic_array(&acl_users,sizeof(ACL_USER), 50, 100, MYF(0));
(void) my_hash_init2(&acl_roles,50,system_charset_info,
0,0,0, (my_hash_get_key) acl_role_get_key, 0,0);
0,0,0, (my_hash_get_key) acl_role_get_key,
(void (*)(void *))free_acl_user, 0);
username_char_length= min(table->field[1]->char_length(), USERNAME_CHAR_LENGTH);
password_length= table->field[2]->field_length /
@ -1062,17 +1084,23 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
#endif
}
(void) my_init_dynamic_array(&user.role_grants,sizeof(ROLE_GRANT_PAIR),
(void) my_init_dynamic_array(&user.role_grants,sizeof(ACL_USER *),
50, 100, MYF(0));
if (is_role) {
sql_print_information("Found role %s", user.user.str);
my_hash_insert(&acl_roles, (uchar*) user.copy(&mem));
DBUG_PRINT("info", ("Found role %s", user.user.str));
ACL_USER *entry= user.copy(&mem);
entry->role_grants = user.role_grants;
my_hash_insert(&acl_roles, (uchar *)entry);
HASH_SEARCH_STATE t;
entry= (ACL_USER *) my_hash_first(&acl_roles,
(uchar *)entry->user.str, entry->user.length, &t);
continue;
}
else
{
sql_print_information("Found user %s", user.user.str);
DBUG_PRINT("info", ("Found user %s", user.user.str));
(void) push_dynamic(&acl_users,(uchar*) &user);
}
if (!user.host.hostname ||
@ -1200,34 +1228,42 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
if (!initialized)
mysql_mutex_lock(&acl_cache->lock);
(void) my_hash_init2(&acl_roles_mappings,50,system_charset_info,
0,0,0, (my_hash_get_key) acl_role_map_get_key, 0,0);
while (!(read_record_info.read_record(&read_record_info)))
{
ROLE_GRANT_PAIR role_ref;
ROLE_GRANT_PAIR user_ref;
user_ref.hostname= get_field(&mem, table->field[0]);
user_ref.username= get_field(&mem, table->field[1]);
role_ref.hostname= get_field(&mem, table->field[2]);
role_ref.username= get_field(&mem, table->field[3]);
ACL_USER *user= find_acl_user((user_ref.hostname) ? user_ref.hostname: "",
(user_ref.username) ? user_ref.username: "",
TRUE);
ACL_USER *role= find_acl_role(role_ref.username ? role_ref.username: "");
if (user == NULL || role == NULL)
{
ROLE_GRANT_PAIR *mapping = (ROLE_GRANT_PAIR *)alloc_root(
&mem,
sizeof(ROLE_GRANT_PAIR));
mapping->u_hname= get_field(&mem, table->field[0]);
mapping->u_uname= get_field(&mem, table->field[1]);
mapping->r_hname= get_field(&mem, table->field[2]);
mapping->r_uname= get_field(&mem, table->field[3]);
size_t len[4] = {mapping->u_hname ? strlen(mapping->u_hname) : 0,
mapping->u_uname ? strlen(mapping->u_uname) : 0,
mapping->r_hname ? strlen(mapping->r_hname) : 0,
mapping->r_uname ? strlen(mapping->r_uname) : 0};
char *buff= (char *)alloc_root(&mem, len[0] + len[1] + len[2] + len[3] + 1);
memcpy(buff, mapping->u_hname, len[0]);
memcpy(buff + len[0], mapping->u_uname, len[1]);
memcpy(buff + len[0] + len[1], mapping->r_hname, len[2]);
memcpy(buff + len[0] + len[1] + len[2], mapping->r_uname, len[3]);
buff[len[0] + len[1] + len[2] + len[3]] = '\0';
mapping->hashkey.str = buff;
mapping->hashkey.length = len[0] + len[1] + len[2] + len[3];
if (add_role_user_mapping(mapping, NULL) == 1) {
sql_print_error("Invalid roles_mapping table entry '%s@%s', '%s@%s'",
user_ref.username ? user_ref.username : "",
user_ref.hostname ? user_ref.hostname : "",
role_ref.username ? role_ref.username : "",
role_ref.hostname ? role_ref.hostname : "",
user, role);
mapping->u_uname ? mapping->u_uname : "",
mapping->u_hname ? mapping->u_hname : "",
mapping->r_uname ? mapping->r_uname : "",
mapping->r_hname ? mapping->r_hname : "");
continue;
}
push_dynamic(&user->role_grants, (uchar*) &role_ref);
push_dynamic(&role->role_grants, (uchar*) &user_ref);
sql_print_information("Found user %s@%s having role granted %s@%s\n",
user->user.str, user->host.hostname,
role->user.str, role->host.hostname);
my_hash_insert(&acl_roles_mappings, (uchar*) mapping);
}
end_read_record(&read_record_info);
@ -1250,14 +1286,15 @@ end:
void acl_free(bool end)
{
my_hash_free(&acl_roles);
free_root(&mem,MYF(0));
delete_dynamic(&acl_hosts);
delete_dynamic_recursive(&acl_users, (FREE_FUNC)free_acl_user);
delete_dynamic_recursive(&acl_users, (FREE_FUNC) free_acl_user);
delete_dynamic(&acl_dbs);
delete_dynamic(&acl_wild_hosts);
delete_dynamic(&acl_proxy_users);
my_hash_free(&acl_roles);
my_hash_free(&acl_check_hosts);
my_hash_free(&acl_roles_mappings);
plugin_unlock(0, native_password_plugin);
plugin_unlock(0, old_password_plugin);
if (!end)
@ -1293,7 +1330,7 @@ my_bool acl_reload(THD *thd)
{
TABLE_LIST tables[5];
DYNAMIC_ARRAY old_acl_hosts, old_acl_users, old_acl_dbs, old_acl_proxy_users;
HASH old_acl_roles;
HASH old_acl_roles, old_acl_roles_mappings;
MEM_ROOT old_mem;
bool old_initialized;
my_bool return_val= TRUE;
@ -1350,6 +1387,7 @@ my_bool acl_reload(THD *thd)
old_acl_hosts= acl_hosts;
old_acl_users= acl_users;
old_acl_roles= acl_roles;
old_acl_roles_mappings= acl_roles_mappings;
old_acl_proxy_users= acl_proxy_users;
old_acl_dbs= acl_dbs;
old_mem= mem;
@ -1363,6 +1401,7 @@ my_bool acl_reload(THD *thd)
acl_hosts= old_acl_hosts;
acl_users= old_acl_users;
acl_roles= old_acl_roles;
acl_roles_mappings= old_acl_roles_mappings;
acl_proxy_users= old_acl_proxy_users;
acl_dbs= old_acl_dbs;
mem= old_mem;
@ -1370,12 +1409,14 @@ my_bool acl_reload(THD *thd)
}
else
{
my_hash_free(&old_acl_roles);
free_root(&old_mem,MYF(0));
delete_dynamic(&old_acl_hosts);
delete_dynamic_recursive(&old_acl_users, (FREE_FUNC) free_acl_user);
delete_dynamic(&old_acl_proxy_users);
delete_dynamic(&old_acl_dbs);
my_hash_free(&old_acl_roles);
my_hash_free(&old_acl_roles_mappings);
my_hash_free(&old_acl_roles_mappings);
}
if (old_initialized)
mysql_mutex_unlock(&acl_cache->lock);
@ -1916,8 +1957,7 @@ static void init_check_host(void)
acl_users.elements, 1, MYF(0));
(void) my_hash_init(&acl_check_hosts,system_charset_info,
acl_users.elements, 0, 0,
(my_hash_get_key) check_get_key,
(void (*)(void *))free_acl_user, 0);
(my_hash_get_key) check_get_key, 0, 0);
if (!allow_all_hosts)
{
for (uint i=0 ; i < acl_users.elements ; i++)
@ -1972,7 +2012,55 @@ void rebuild_check_host(void)
init_check_host();
}
/*
Rebuild the role grants every time the acl_users is modified
The role grants in the ACL_USER class need to be rebuilt, as they contain
pointers to elements of the acl_users array.
*/
my_bool acl_user_reset_grant(ACL_USER *user,
void * not_used __attribute__((unused)))
{
reset_dynamic(&user->role_grants);
return 0;
}
my_bool add_role_user_mapping(ROLE_GRANT_PAIR *mapping,
void * not_used __attribute__((unused)))
{
ACL_USER *user= find_acl_user((mapping->u_hname) ? mapping->u_hname: "",
(mapping->u_uname) ? mapping->u_uname: "",
TRUE);
ACL_USER *role= find_acl_role(mapping->r_uname ? mapping->r_uname: "");
if (user == NULL || role == NULL)
return 1;
push_dynamic(&user->role_grants, (uchar*) role);
push_dynamic(&role->role_grants, (uchar*) user);
DBUG_PRINT("info", ("Found user %s@%s having role granted %s@%s\n",
user->user.str, user->host.hostname,
role->user.str, role->host.hostname));
return 0;
}
void rebuild_role_grants(void)
{
/*
Reset every user's and role's role_grants array
*/
for (uint i=0; i < acl_users.elements; i++) {
ACL_USER * user = dynamic_element(&acl_users, i, ACL_USER *);
reset_dynamic(&user->role_grants);
}
my_hash_iterate(&acl_roles,
(my_hash_walk_action) acl_user_reset_grant, NULL);
my_hash_iterate(&acl_roles_mappings,
(my_hash_walk_action) add_role_user_mapping, NULL);
}
/* Return true if there is no users that can match the given host */
bool acl_check_host(const char *host, const char *ip)

View File

@ -215,7 +215,7 @@ bool check_grant_column (THD *thd, GRANT_INFO *grant,
const char *name, uint length, Security_context *sctx);
bool check_column_grant_in_table_ref(THD *thd, TABLE_LIST * table_ref,
const char *name, uint length);
bool check_grant_all_columns(THD *thd, ulong want_access,
bool check_grant_all_columns(THD *thd, ulong want_access,
Field_iterator_table_ref *fields);
bool check_grant_routine(THD *thd, ulong want_access,
TABLE_LIST *procs, bool is_proc, bool no_error);