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->plugin.str= strmake_root(root, plugin.str, plugin.length);
dst->auth_string.str= safe_strdup_root(root, auth_string.str); dst->auth_string.str= safe_strdup_root(root, auth_string.str);
dst->host.hostname= safe_strdup_root(root, host.hostname); dst->host.hostname= safe_strdup_root(root, host.hostname);
dst->role_grants= this->role_grants; bzero(&dst->role_grants, sizeof(role_grants));
return dst; return dst;
} }
}; };
@ -262,7 +262,6 @@ public:
char *user,*db; char *user,*db;
}; };
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
static void update_hostname(acl_host_and_ip *host, const char *hostname); static void update_hostname(acl_host_and_ip *host, const char *hostname);
static ulong get_sort(uint count,...); 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; return (uchar*) entry->key;
} }
uchar* acl_role_get_key(ACL_USER *entry, size_t *length, static uchar* acl_role_get_key(ACL_USER *entry, size_t *length,
my_bool not_used __attribute__((unused))) my_bool not_used __attribute__((unused)))
{ {
*length=(uint) entry->user.length; *length=(uint) entry->user.length;
return (uchar*) entry->user.str; 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 IP_ADDR_STRLEN (3 + 1 + 3 + 1 + 3 + 1 + 3)
#define ACL_KEY_LENGTH (IP_ADDR_STRLEN + 1 + NAME_LEN + \ #define ACL_KEY_LENGTH (IP_ADDR_STRLEN + 1 + NAME_LEN + \
1 + USERNAME_LENGTH + 1) 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 DYNAMIC_ARRAY acl_hosts, acl_users, acl_dbs, acl_proxy_users;
static HASH acl_roles; 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 MEM_ROOT mem, memex;
static bool initialized=0; static bool initialized=0;
static bool allow_all_hosts=1; 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 acl_load(THD *thd, TABLE_LIST *tables);
static my_bool grant_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 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() Enumeration of various ACL's and Hashes used in handle_grant_struct()
*/ */
@ -597,12 +624,6 @@ enum enum_acl_lists
PROXY_USERS_ACL PROXY_USERS_ACL
}; };
typedef struct st_role_grant
{
char *username;
char *hostname;
} ROLE_GRANT_PAIR;
static static
void void
free_acl_user(ACL_USER *user) free_acl_user(ACL_USER *user)
@ -863,7 +884,8 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
table->use_all_columns(); table->use_all_columns();
(void) my_init_dynamic_array(&acl_users,sizeof(ACL_USER), 50, 100, MYF(0)); (void) my_init_dynamic_array(&acl_users,sizeof(ACL_USER), 50, 100, MYF(0));
(void) my_hash_init2(&acl_roles,50,system_charset_info, (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); username_char_length= min(table->field[1]->char_length(), USERNAME_CHAR_LENGTH);
password_length= table->field[2]->field_length / password_length= table->field[2]->field_length /
@ -1062,17 +1084,23 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
#endif #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)); 50, 100, MYF(0));
if (is_role) { if (is_role) {
sql_print_information("Found role %s", user.user.str); DBUG_PRINT("info", ("Found role %s", user.user.str));
my_hash_insert(&acl_roles, (uchar*) user.copy(&mem)); 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; continue;
} }
else 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); (void) push_dynamic(&acl_users,(uchar*) &user);
} }
if (!user.host.hostname || if (!user.host.hostname ||
@ -1200,34 +1228,42 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
if (!initialized) if (!initialized)
mysql_mutex_lock(&acl_cache->lock); 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))) while (!(read_record_info.read_record(&read_record_info)))
{ {
ROLE_GRANT_PAIR role_ref; ROLE_GRANT_PAIR *mapping = (ROLE_GRANT_PAIR *)alloc_root(
ROLE_GRANT_PAIR user_ref; &mem,
user_ref.hostname= get_field(&mem, table->field[0]); sizeof(ROLE_GRANT_PAIR));
user_ref.username= get_field(&mem, table->field[1]); mapping->u_hname= get_field(&mem, table->field[0]);
role_ref.hostname= get_field(&mem, table->field[2]); mapping->u_uname= get_field(&mem, table->field[1]);
role_ref.username= get_field(&mem, table->field[3]); mapping->r_hname= get_field(&mem, table->field[2]);
ACL_USER *user= find_acl_user((user_ref.hostname) ? user_ref.hostname: "", mapping->r_uname= get_field(&mem, table->field[3]);
(user_ref.username) ? user_ref.username: "",
TRUE); size_t len[4] = {mapping->u_hname ? strlen(mapping->u_hname) : 0,
ACL_USER *role= find_acl_role(role_ref.username ? role_ref.username: ""); mapping->u_uname ? strlen(mapping->u_uname) : 0,
if (user == NULL || role == NULL) 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'", sql_print_error("Invalid roles_mapping table entry '%s@%s', '%s@%s'",
user_ref.username ? user_ref.username : "", mapping->u_uname ? mapping->u_uname : "",
user_ref.hostname ? user_ref.hostname : "", mapping->u_hname ? mapping->u_hname : "",
role_ref.username ? role_ref.username : "", mapping->r_uname ? mapping->r_uname : "",
role_ref.hostname ? role_ref.hostname : "", mapping->r_hname ? mapping->r_hname : "");
user, role);
continue; continue;
} }
push_dynamic(&user->role_grants, (uchar*) &role_ref); my_hash_insert(&acl_roles_mappings, (uchar*) mapping);
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);
} }
end_read_record(&read_record_info); end_read_record(&read_record_info);
@ -1250,14 +1286,15 @@ end:
void acl_free(bool end) void acl_free(bool end)
{ {
my_hash_free(&acl_roles);
free_root(&mem,MYF(0)); free_root(&mem,MYF(0));
delete_dynamic(&acl_hosts); 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_dbs);
delete_dynamic(&acl_wild_hosts); delete_dynamic(&acl_wild_hosts);
delete_dynamic(&acl_proxy_users); delete_dynamic(&acl_proxy_users);
my_hash_free(&acl_roles);
my_hash_free(&acl_check_hosts); my_hash_free(&acl_check_hosts);
my_hash_free(&acl_roles_mappings);
plugin_unlock(0, native_password_plugin); plugin_unlock(0, native_password_plugin);
plugin_unlock(0, old_password_plugin); plugin_unlock(0, old_password_plugin);
if (!end) if (!end)
@ -1293,7 +1330,7 @@ my_bool acl_reload(THD *thd)
{ {
TABLE_LIST tables[5]; TABLE_LIST tables[5];
DYNAMIC_ARRAY old_acl_hosts, old_acl_users, old_acl_dbs, old_acl_proxy_users; 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; MEM_ROOT old_mem;
bool old_initialized; bool old_initialized;
my_bool return_val= TRUE; my_bool return_val= TRUE;
@ -1350,6 +1387,7 @@ my_bool acl_reload(THD *thd)
old_acl_hosts= acl_hosts; old_acl_hosts= acl_hosts;
old_acl_users= acl_users; old_acl_users= acl_users;
old_acl_roles= acl_roles; old_acl_roles= acl_roles;
old_acl_roles_mappings= acl_roles_mappings;
old_acl_proxy_users= acl_proxy_users; old_acl_proxy_users= acl_proxy_users;
old_acl_dbs= acl_dbs; old_acl_dbs= acl_dbs;
old_mem= mem; old_mem= mem;
@ -1363,6 +1401,7 @@ my_bool acl_reload(THD *thd)
acl_hosts= old_acl_hosts; acl_hosts= old_acl_hosts;
acl_users= old_acl_users; acl_users= old_acl_users;
acl_roles= old_acl_roles; acl_roles= old_acl_roles;
acl_roles_mappings= old_acl_roles_mappings;
acl_proxy_users= old_acl_proxy_users; acl_proxy_users= old_acl_proxy_users;
acl_dbs= old_acl_dbs; acl_dbs= old_acl_dbs;
mem= old_mem; mem= old_mem;
@ -1370,12 +1409,14 @@ my_bool acl_reload(THD *thd)
} }
else else
{ {
my_hash_free(&old_acl_roles);
free_root(&old_mem,MYF(0)); free_root(&old_mem,MYF(0));
delete_dynamic(&old_acl_hosts); delete_dynamic(&old_acl_hosts);
delete_dynamic_recursive(&old_acl_users, (FREE_FUNC) free_acl_user); delete_dynamic_recursive(&old_acl_users, (FREE_FUNC) free_acl_user);
delete_dynamic(&old_acl_proxy_users); delete_dynamic(&old_acl_proxy_users);
delete_dynamic(&old_acl_dbs); 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) if (old_initialized)
mysql_mutex_unlock(&acl_cache->lock); mysql_mutex_unlock(&acl_cache->lock);
@ -1916,8 +1957,7 @@ static void init_check_host(void)
acl_users.elements, 1, MYF(0)); acl_users.elements, 1, MYF(0));
(void) my_hash_init(&acl_check_hosts,system_charset_info, (void) my_hash_init(&acl_check_hosts,system_charset_info,
acl_users.elements, 0, 0, acl_users.elements, 0, 0,
(my_hash_get_key) check_get_key, (my_hash_get_key) check_get_key, 0, 0);
(void (*)(void *))free_acl_user, 0);
if (!allow_all_hosts) if (!allow_all_hosts)
{ {
for (uint i=0 ; i < acl_users.elements ; i++) for (uint i=0 ; i < acl_users.elements ; i++)
@ -1972,7 +2012,55 @@ void rebuild_check_host(void)
init_check_host(); 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 */ /* Return true if there is no users that can match the given host */
bool acl_check_host(const char *host, const char *ip) 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); const char *name, uint length, Security_context *sctx);
bool check_column_grant_in_table_ref(THD *thd, TABLE_LIST * table_ref, bool check_column_grant_in_table_ref(THD *thd, TABLE_LIST * table_ref,
const char *name, uint length); 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); Field_iterator_table_ref *fields);
bool check_grant_routine(THD *thd, ulong want_access, bool check_grant_routine(THD *thd, ulong want_access,
TABLE_LIST *procs, bool is_proc, bool no_error); TABLE_LIST *procs, bool is_proc, bool no_error);