Commit 887a1ac8 authored by Vicențiu Ciorbaru's avatar Vicențiu Ciorbaru Committed by Sergei Golubchik

Implemented Roles Mappings association between users and roles.

No more memory leaks in the code.
parent deffce1a
......@@ -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)
......
......@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment