From fe2d26570495c1f484b3f22fe7dfc38dd9d48193 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 18 Oct 2013 09:15:55 -0700 Subject: [PATCH] INFORMATION_SCHEMA.APPLICABLE_ROLES table --- mysql-test/r/acl_roles_show_grants.result | 7 ++ .../suite/funcs_1/r/is_tables_is.result | 46 ++++++++++++ mysql-test/t/acl_roles_show_grants.test | 4 + sql/handler.h | 1 + sql/sql_acl.cc | 74 +++++++++++++++++-- sql/sql_acl.h | 1 + sql/sql_show.cc | 23 ++++-- 7 files changed, 146 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/acl_roles_show_grants.result b/mysql-test/r/acl_roles_show_grants.result index a9faee58fb9..63080ed1b38 100644 --- a/mysql-test/r/acl_roles_show_grants.result +++ b/mysql-test/r/acl_roles_show_grants.result @@ -27,6 +27,13 @@ user host % grant select on mysql.* to test_role2; flush privileges; +select * from information_schema.applicable_roles; +GRANTEE ROLE_NAME IS_GRANTABLE +select * from information_schema.applicable_roles; +GRANTEE ROLE_NAME IS_GRANTABLE +test_user@localhost test_role1 YES +test_role1 test_role2 YES +test_user@localhost test_role2 YES show grants; Grants for test_user@localhost GRANT USAGE ON *.* TO 'test_user'@'localhost' diff --git a/mysql-test/suite/funcs_1/r/is_tables_is.result b/mysql-test/suite/funcs_1/r/is_tables_is.result index 93c1a51e9ed..5ecac2f296f 100644 --- a/mysql-test/suite/funcs_1/r/is_tables_is.result +++ b/mysql-test/suite/funcs_1/r/is_tables_is.result @@ -39,6 +39,29 @@ user_comment Separator ----------------------------------------------------- TABLE_CATALOG def TABLE_SCHEMA information_schema +TABLE_NAME APPLICABLE_ROLES +TABLE_TYPE SYSTEM VIEW +ENGINE MEMORY +VERSION 10 +ROW_FORMAT Fixed +TABLE_ROWS #TBLR# +AVG_ROW_LENGTH #ARL# +DATA_LENGTH #DL# +MAX_DATA_LENGTH #MDL# +INDEX_LENGTH #IL# +DATA_FREE #DF# +AUTO_INCREMENT NULL +CREATE_TIME #CRT# +UPDATE_TIME #UT# +CHECK_TIME #CT# +TABLE_COLLATION utf8_general_ci +CHECKSUM NULL +CREATE_OPTIONS #CO# +TABLE_COMMENT #TC# +user_comment +Separator ----------------------------------------------------- +TABLE_CATALOG def +TABLE_SCHEMA information_schema TABLE_NAME CHARACTER_SETS TABLE_TYPE SYSTEM VIEW ENGINE MEMORY @@ -885,6 +908,29 @@ user_comment Separator ----------------------------------------------------- TABLE_CATALOG def TABLE_SCHEMA information_schema +TABLE_NAME APPLICABLE_ROLES +TABLE_TYPE SYSTEM VIEW +ENGINE MEMORY +VERSION 10 +ROW_FORMAT Fixed +TABLE_ROWS #TBLR# +AVG_ROW_LENGTH #ARL# +DATA_LENGTH #DL# +MAX_DATA_LENGTH #MDL# +INDEX_LENGTH #IL# +DATA_FREE #DF# +AUTO_INCREMENT NULL +CREATE_TIME #CRT# +UPDATE_TIME #UT# +CHECK_TIME #CT# +TABLE_COLLATION utf8_general_ci +CHECKSUM NULL +CREATE_OPTIONS #CO# +TABLE_COMMENT #TC# +user_comment +Separator ----------------------------------------------------- +TABLE_CATALOG def +TABLE_SCHEMA information_schema TABLE_NAME CHARACTER_SETS TABLE_TYPE SYSTEM VIEW ENGINE MEMORY diff --git a/mysql-test/t/acl_roles_show_grants.test b/mysql-test/t/acl_roles_show_grants.test index 157458b5c79..b520745128e 100644 --- a/mysql-test/t/acl_roles_show_grants.test +++ b/mysql-test/t/acl_roles_show_grants.test @@ -24,8 +24,12 @@ select user, host from mysql.db; grant select on mysql.* to test_role2; flush privileges; +select * from information_schema.applicable_roles; + change_user 'test_user'; +select * from information_schema.applicable_roles; + --sorted_result show grants; select current_user(), current_role(); diff --git a/sql/handler.h b/sql/handler.h index 6427edb01a6..e77d80e7668 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -594,6 +594,7 @@ struct TABLE; enum enum_schema_tables { SCH_ALL_PLUGINS, + SCH_APPLICABLE_ROLES, SCH_CHARSETS, SCH_CLIENT_STATS, SCH_COLLATIONS, diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 5c39722d009..bfd19f76b4b 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -318,8 +318,7 @@ static bool compare_hostname(const acl_host_and_ip *host, const char *hostname, static bool show_proxy_grants (THD *thd, const char *username, const char *hostname, char *buff, size_t buffsize); -static bool show_role_grants(THD *thd, - const char *username, const char *hostname, +static bool show_role_grants(THD *thd, const char *username, const char *hostname, ACL_USER_BASE *acl_entry, char *buff, size_t buffsize); static bool show_global_privileges(THD *thd, ACL_USER_BASE *acl_entry, @@ -726,8 +725,7 @@ static void rebuild_check_host(void); static void rebuild_role_grants(void); static void free_acl_user(ACL_USER *acl_user); static void free_acl_role(ACL_ROLE *acl_role); -static ACL_USER *find_user_no_anon(const char *host, const char *user, - my_bool exact); +static ACL_USER *find_user_no_anon(const char *host, const char *user, bool exact); static ACL_USER *find_user(const char *host, const char *user, const char *ip); static ACL_ROLE *find_acl_role(const char *user); static bool update_user_table(THD *thd, TABLE *table, const char *host, @@ -3034,7 +3032,7 @@ find_user(const char *host, const char *user, const char *ip) Find first entry that matches the current user */ static ACL_USER * -find_user_no_anon(const char *host, const char *user, my_bool exact) +find_user_no_anon(const char *host, const char *user, bool exact) { DBUG_ENTER("find_user_no_anon"); DBUG_PRINT("enter",("host: '%s' user: '%s'",host,user)); @@ -9472,6 +9470,39 @@ fill_schema_enabled_roles_insert(ACL_ROLE *unused __attribute__((unused)), /*return*/ schema_table_store_record(table->in_use, table); } +static int fill_schema_applicable_roles_insert_data(ACL_USER_BASE *grantee, + LEX_STRING *name, TABLE *table); + +static void +fill_schema_applicable_roles_insert(ACL_ROLE *unused __attribute__((unused)), + ACL_ROLE *role, void *context_data) +{ + /*return*/ fill_schema_applicable_roles_insert_data(role, &role->user, + (TABLE*)context_data); +} + +static int +fill_schema_applicable_roles_insert_data(ACL_USER_BASE *grantee, + LEX_STRING *name, TABLE *table) +{ + CHARSET_INFO *cs= system_charset_info; + + for (uint i= 0; i < grantee->role_grants.elements; i++) + { + ACL_ROLE *role= *(dynamic_element(&grantee->role_grants, i, ACL_ROLE**)); + restore_record(table, s->default_values); + table->field[0]->store(name->str, name->length, cs); + table->field[1]->store(role->user.str, role->user.length, cs); + table->field[2]->store(STRING_WITH_LEN("YES"), cs); // TODO FIXME + if (schema_table_store_record(table->in_use, table)) + return 1; + if (! (grantee->flags & IS_ROLE)) + traverse_role_graph(role, table, NULL, NULL, NULL, + fill_schema_applicable_roles_insert); + } + return 0; +} + #endif /*NO_EMBEDDED_ACCESS_CHECKS */ int fill_schema_enabled_roles(THD *thd, TABLE_LIST *tables, COND *cond) @@ -9498,6 +9529,39 @@ int fill_schema_enabled_roles(THD *thd, TABLE_LIST *tables, COND *cond) } +/* + This shows all roles granted to current user + and recursively all roles granted to those roles +*/ +int fill_schema_applicable_roles(THD *thd, TABLE_LIST *tables, COND *cond) +{ +#ifndef NO_EMBEDDED_ACCESS_CHECKS + if (initialized) + { + TABLE *table= tables->table; + Security_context *sctx= thd->security_ctx; + mysql_rwlock_rdlock(&LOCK_grant); + mysql_mutex_lock(&acl_cache->lock); + ACL_USER *user= find_user_no_anon(sctx->priv_host, sctx->priv_user, true); + + char buff[USER_HOST_BUFF_SIZE+10]; + DBUG_ASSERT(user->user.length + user->hostname_length +2 < sizeof(buff)); + char *end= strxmov(buff, user->user.str, "@", user->host.hostname, NULL); + LEX_STRING name= { buff, end - buff }; + + int res= fill_schema_applicable_roles_insert_data(user, &name, table); + + mysql_mutex_unlock(&acl_cache->lock); + mysql_rwlock_unlock(&LOCK_grant); + + return res; + } +#endif + + return 0; +} + + int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *wildstr) { reg3 int flag; diff --git a/sql/sql_acl.h b/sql/sql_acl.h index 64370f8705f..506a1fe4d40 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -234,6 +234,7 @@ ulong get_column_grant(THD *thd, GRANT_INFO *grant, const char *field_name); bool mysql_show_grants(THD *thd, LEX_USER *user); int fill_schema_enabled_roles(THD *thd, TABLE_LIST *tables, COND *cond); +int fill_schema_applicable_roles(THD *thd, TABLE_LIST *tables, COND *cond); void get_privilege_desc(char *to, uint max_length, ulong access); void get_mqh(const char *user, const char *host, USER_CONN *uc); bool mysql_create_user(THD *thd, List &list, bool handle_as_role); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 184f94f5b5c..5fc5afcc0fd 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -90,6 +90,8 @@ enum enum_i_s_events_fields ISE_DB_CL }; +#define USERNAME_WITH_HOST_CHAR_LENGTH (USERNAME_CHAR_LENGTH + HOSTNAME_LENGTH + 2) + #ifndef NO_EMBEDDED_ACCESS_CHECKS static const char *grant_names[]={ "select","insert","update","delete","create","drop","reload","shutdown", @@ -8369,9 +8371,18 @@ ST_FIELD_INFO collation_fields_info[]= }; +ST_FIELD_INFO applicable_roles_fields_info[]= +{ + {"GRANTEE", USERNAME_WITH_HOST_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, + {"ROLE_NAME", USERNAME_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, + {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, + {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE} +}; + + ST_FIELD_INFO enabled_roles_fields_info[]= { - {"ROLE_NAME", USERNAME_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, 0, 0}, + {"ROLE_NAME", USERNAME_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, MY_I_S_MAYBE_NULL, 0, SKIP_OPEN_TABLE}, {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE} }; @@ -8529,7 +8540,7 @@ ST_FIELD_INFO view_fields_info[]= ST_FIELD_INFO user_privileges_fields_info[]= { - {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, + {"GRANTEE", USERNAME_WITH_HOST_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"PRIVILEGE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"IS_GRANTABLE", 3, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, @@ -8539,7 +8550,7 @@ ST_FIELD_INFO user_privileges_fields_info[]= ST_FIELD_INFO schema_privileges_fields_info[]= { - {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, + {"GRANTEE", USERNAME_WITH_HOST_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"PRIVILEGE_TYPE", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, @@ -8550,7 +8561,7 @@ ST_FIELD_INFO schema_privileges_fields_info[]= ST_FIELD_INFO table_privileges_fields_info[]= { - {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, + {"GRANTEE", USERNAME_WITH_HOST_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, @@ -8562,7 +8573,7 @@ ST_FIELD_INFO table_privileges_fields_info[]= ST_FIELD_INFO column_privileges_fields_info[]= { - {"GRANTEE", 81, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, + {"GRANTEE", USERNAME_WITH_HOST_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"TABLE_CATALOG", FN_REFLEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"TABLE_SCHEMA", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, {"TABLE_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, 0, SKIP_OPEN_TABLE}, @@ -8973,6 +8984,8 @@ ST_SCHEMA_TABLE schema_tables[]= { {"ALL_PLUGINS", plugin_fields_info, create_schema_table, fill_all_plugins, make_old_format, 0, 5, -1, 0, 0}, + {"APPLICABLE_ROLES", applicable_roles_fields_info, create_schema_table, + fill_schema_applicable_roles, 0, 0, -1, -1, 0, 0}, {"CHARACTER_SETS", charsets_fields_info, create_schema_table, fill_schema_charsets, make_character_sets_old_format, 0, -1, -1, 0, 0}, {"CLIENT_STATISTICS", client_stats_fields_info, create_schema_table,