From 887a1ac862abd28256ae251a40c5eb00dca0d4c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Thu, 17 Oct 2013 15:03:21 -0700 Subject: Implemented Roles Mappings association between users and roles. No more memory leaks in the code. --- sql/sql_acl.cc | 174 +++++++++++++++++++++++++++++++++++++++++++-------------- sql/sql_acl.h | 2 +- 2 files changed, 132 insertions(+), 44 deletions(-) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 4705e152f37..c3589461b9f 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -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) diff --git a/sql/sql_acl.h b/sql/sql_acl.h index 3169746419c..3bc1b1eae45 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -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); -- cgit v1.2.1