diff options
Diffstat (limited to 'sql/sql_acl.cc')
-rw-r--r-- | sql/sql_acl.cc | 1066 |
1 files changed, 745 insertions, 321 deletions
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index c8b829c83a0..9d8d678b052 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2018, Oracle and/or its affiliates. - Copyright (c) 2009, 2020, MariaDB + Copyright (c) 2009, 2021, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -62,13 +62,22 @@ bool mysql_user_table_is_in_short_password_format= false; bool using_global_priv_table= true; -#ifndef NO_EMBEDDED_ACCESS_CHECKS // set that from field length in acl_load? +#ifndef NO_EMBEDDED_ACCESS_CHECKS const uint max_hostname_length= 60; const uint max_dbname_length= 64; +#endif -#include "sql_acl_getsort.ic" +const char *safe_vio_type_name(Vio *vio) +{ + size_t unused; +#ifdef EMBEDDED_LIBRARY + if (!vio) return "Internal"; #endif + return vio_type_name(vio_type(vio), &unused); +} + +#include "sql_acl_getsort.ic" static LEX_CSTRING native_password_plugin_name= { STRING_WITH_LEN("mysql_native_password") @@ -126,9 +135,9 @@ static bool compare_hostname(const acl_host_and_ip *, const char *, const char * class ACL_ACCESS { public: ulonglong sort; - ulong access; + privilege_t access; ACL_ACCESS() - :sort(0), access(0) + :sort(0), access(NO_ACL) { } }; @@ -193,7 +202,7 @@ public: ACL_USER() { } ACL_USER(THD *thd, const LEX_USER &combo, const Account_options &options, - const ulong privileges); + const privilege_t privileges); ACL_USER *copy(MEM_ROOT *root) { @@ -259,7 +268,7 @@ public: the ACL_USER::access field needs to be reset first. The field initial_role_access holds initial grants, as granted directly to the role */ - ulong initial_role_access; + privilege_t initial_role_access; /* In subgraph traversal, when we need to traverse only a part of the graph (e.g. all direct and indirect grantees of a role X), the counter holds the @@ -270,16 +279,17 @@ public: DYNAMIC_ARRAY parent_grantee; // array of backlinks to elements granted ACL_ROLE(ACL_USER * user, MEM_ROOT *mem); - ACL_ROLE(const char * rolename, ulong privileges, MEM_ROOT *mem); + ACL_ROLE(const char * rolename, privilege_t privileges, MEM_ROOT *mem); }; class ACL_DB :public ACL_ACCESS { public: + ACL_DB() :initial_access(NO_ACL) { } acl_host_and_ip host; const char *user,*db; - ulong initial_access; /* access bits present in the table */ + privilege_t initial_access; /* access bits present in the table */ const char *get_username() { return user; } }; @@ -521,7 +531,7 @@ public: class acl_entry :public hash_filo_element { public: - ulong access; + privilege_t access; uint16 length; char key[1]; // Key will be stored here }; @@ -645,7 +655,7 @@ bool ROLE_GRANT_PAIR::init(MEM_ROOT *mem, const char *username, #define ROLE_OPENED (1L << 3) static DYNAMIC_ARRAY acl_hosts, acl_users, acl_proxy_users; -static Dynamic_array<ACL_DB> acl_dbs(0U,50U); +static Dynamic_array<ACL_DB> acl_dbs(PSI_INSTRUMENT_MEM, 0U, 50U); typedef Dynamic_array<ACL_DB>::CMP_FUNC acl_dbs_cmp; static HASH acl_roles; /* @@ -663,7 +673,7 @@ static HASH package_spec_priv_hash, package_body_priv_hash; static DYNAMIC_ARRAY acl_wild_hosts; static Hash_filo<acl_entry> *acl_cache; static uint grant_version=0; /* Version of priv tables. incremented by acl_load */ -static ulong get_access(TABLE *form,uint fieldnr, uint *next_field=0); +static privilege_t get_access(TABLE *form, uint fieldnr, uint *next_field=0); static int acl_compare(const ACL_ACCESS *a, const ACL_ACCESS *b); static int acl_user_compare(const ACL_USER *a, const ACL_USER *b); static void rebuild_acl_users(); @@ -810,15 +820,15 @@ class Grant_table_base /* Return the underlying TABLE handle. */ TABLE* table() const { return m_table; } - ulong get_access() const + privilege_t get_access() const { - ulong access_bits= 0, bit= 1; + ulonglong access_bits= 0, bit= 1; for (uint i = start_priv_columns; i < end_priv_columns; i++, bit<<=1) { if (get_YN_as_bool(m_table->field[i])) access_bits|= bit; } - return access_bits; + return ALL_KNOWN_ACL & access_bits; } protected: @@ -875,8 +885,8 @@ class User_table: public Grant_table_base virtual LEX_CSTRING& name() const = 0; virtual int get_auth(THD *, MEM_ROOT *, ACL_USER *u) const= 0; virtual bool set_auth(const ACL_USER &u) const = 0; - virtual ulong get_access() const = 0; - virtual void set_access(ulong rights, bool revoke) const = 0; + virtual privilege_t get_access() const = 0; + virtual void set_access(const privilege_t rights, bool revoke) const = 0; char *get_host(MEM_ROOT *root) const { return ::get_field(root, m_table->field[0]); } @@ -994,9 +1004,9 @@ class User_table_tabular: public User_table return 0; } - ulong get_access() const + privilege_t get_access() const { - ulong access= Grant_table_base::get_access(); + privilege_t access(Grant_table_base::get_access()); if ((num_fields() <= 13) && (access & CREATE_ACL)) access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL; @@ -1004,7 +1014,8 @@ class User_table_tabular: public User_table { access|= LOCK_TABLES_ACL | CREATE_TMP_ACL | SHOW_DB_ACL; if (access & FILE_ACL) - access|= REPL_CLIENT_ACL | REPL_SLAVE_ACL; + access|= BINLOG_MONITOR_ACL | REPL_SLAVE_ACL | BINLOG_ADMIN_ACL | + BINLOG_REPLAY_ACL; if (access & PROCESS_ACL) access|= SUPER_ACL | EXECUTE_ACL; } @@ -1032,12 +1043,29 @@ class User_table_tabular: public User_table if (num_fields() <= 46 && (access & DELETE_ACL)) access|= DELETE_HISTORY_ACL; + if (access & SUPER_ACL) + access|= GLOBAL_SUPER_ADDED_SINCE_USER_TABLE_ACLS; + + /* + The SHOW SLAVE HOSTS statement : + - required REPLICATION SLAVE privilege prior to 10.5.2 + - requires REPLICATION MASTER ADMIN privilege since 10.5.2 + There is no a way to GRANT MASTER ADMIN with User_table_tabular. + So let's automatically add REPLICATION MASTER ADMIN for all users + that had REPLICATION SLAVE. This will allow to do SHOW SLAVE HOSTS. + */ + if (access & REPL_SLAVE_ACL) + access|= REPL_MASTER_ADMIN_ACL; + + if (access & REPL_SLAVE_ACL) + access|= SLAVE_MONITOR_ACL; + return access & GLOBAL_ACLS; } - void set_access(ulong rights, bool revoke) const + void set_access(const privilege_t rights, bool revoke) const { - ulong priv= SELECT_ACL; + ulonglong priv(SELECT_ACL); for (uint i= start_priv_columns; i < end_priv_columns; i++, priv <<= 1) { if (priv & rights) @@ -1478,23 +1506,118 @@ class User_table_json: public User_table set_str_value("authentication_string", u.auth[i].auth_string.str, u.auth[i].auth_string.length); } - ulong get_access() const + + void print_warning_bad_version_id(ulonglong version_id) const + { + sql_print_warning("'user' entry '%s@%s' has a wrong 'version_id' value %lld", + safe_str(get_user(current_thd->mem_root)), + safe_str(get_host(current_thd->mem_root)), + version_id); + } + + void print_warning_bad_access(ulonglong version_id, + privilege_t mask, + ulonglong access) const + { + sql_print_warning("'user' entry '%s@%s' " + "has a wrong 'access' value 0x%llx " + "(allowed mask is 0x%llx, version_id=%lld)", + safe_str(get_user(current_thd->mem_root)), + safe_str(get_host(current_thd->mem_root)), + access, mask, version_id); + } + + privilege_t adjust_access(ulonglong version_id, ulonglong access) const + { + privilege_t mask= ALL_KNOWN_ACL_100304; + ulonglong orig_access= access; + if (version_id >= 100509) + { + mask= ALL_KNOWN_ACL_100509; + } + else if (version_id >= 100502) + { + if (version_id >= 100508) + mask= ALL_KNOWN_ACL_100508; + else + mask= ALL_KNOWN_ACL_100502; + if (access & REPL_SLAVE_ADMIN_ACL) + access|= SLAVE_MONITOR_ACL; + } + else // 100501 or earlier + { + /* + Address changes in SUPER and REPLICATION SLAVE made in 10.5.2. + This also covers a special case: if the user had ALL PRIVILEGES before + the upgrade, it gets ALL PRIVILEGES after the upgrade. + */ + if (access & SUPER_ACL) + { + if (access & REPL_SLAVE_ACL) + { + /* + The user could do both before the upgrade: + - set global variables (because of SUPER_ACL) + - execute "SHOW SLAVE HOSTS" (because of REPL_SLAVE_ACL) + Grant all new privileges that were splitted from SUPER (in 10.5.2), + and REPLICATION MASTER ADMIN, so it still can do "SHOW SLAVE HOSTS". + */ + access|= REPL_MASTER_ADMIN_ACL; + } + access|= GLOBAL_SUPER_ADDED_SINCE_USER_TABLE_ACLS; + } + /* + REPLICATION_CLIENT(BINLOG_MONITOR_ACL) should allow SHOW SLAVE STATUS + REPLICATION SLAVE should allow SHOW RELAYLOG EVENTS + */ + if (access & BINLOG_MONITOR_ACL || access & REPL_SLAVE_ACL) + access|= SLAVE_MONITOR_ACL; + } + + if (orig_access & ~mask) + { + print_warning_bad_access(version_id, mask, orig_access); + return NO_ACL; + } + return access & ALL_KNOWN_ACL; + } + + privilege_t get_access() const { + ulonglong version_id= (ulonglong) get_int_value("version_id"); + ulonglong access= (ulonglong) get_int_value("access"); + /* - when new privileges will be added, we'll start storing GLOBAL_ACLS - (or, for example, my_count_bits(GLOBAL_ACLS)) - in the json too, and it'll allow us to do privilege upgrades + Special case: + mysql_system_tables_data.sql populates "ALL PRIVILEGES" + for the super user this way: + {"access":18446744073709551615} */ - return get_int_value("access") & GLOBAL_ACLS; + if (access == (ulonglong) ~0) + return GLOBAL_ACLS; + + /* + Reject obviously bad (negative and too large) version_id values. + Also reject versions before 10.4.0 (when JSON table was added). + */ + if ((longlong) version_id < 0 || version_id > 999999 || + (version_id > 0 && version_id < 100400)) + { + print_warning_bad_version_id(version_id); + return NO_ACL; + } + return adjust_access(version_id, access) & GLOBAL_ACLS; } - void set_access(ulong rights, bool revoke) const + + void set_access(const privilege_t rights, bool revoke) const { - ulong access= get_access(); + privilege_t access= get_access(); if (revoke) access&= ~rights; else access|= rights; - set_int_value("access", access & GLOBAL_ACLS); + set_int_value("access", (longlong) (access & GLOBAL_ACLS)); + set_int_value("version_id", (longlong) MYSQL_VERSION_ID); } const char *unsafe_str(const char *s) const { return s[0] ? s : NULL; } @@ -1878,7 +2001,9 @@ class Grant_tables if (res) DBUG_RETURN(res); - if (lock_tables(thd, first, counter, MYSQL_LOCK_IGNORE_TIMEOUT)) + if (lock_tables(thd, first, counter, + MYSQL_LOCK_IGNORE_TIMEOUT | + MYSQL_OPEN_IGNORE_LOGGING_FORMAT)) DBUG_RETURN(-1); p_user_table->set_table(tables[USER_TABLE].table); @@ -1987,17 +2112,20 @@ enum enum_acl_lists ROLES_MAPPINGS_HASH }; -ACL_ROLE::ACL_ROLE(ACL_USER *user, MEM_ROOT *root) : counter(0) +ACL_ROLE::ACL_ROLE(ACL_USER *user, MEM_ROOT *root) + : + /* set initial role access the same as the table row privileges */ + initial_role_access(user->access), + counter(0) { access= user->access; - /* set initial role access the same as the table row privileges */ - initial_role_access= user->access; this->user= user->user; bzero(&parent_grantee, sizeof(parent_grantee)); flags= IS_ROLE; } -ACL_ROLE::ACL_ROLE(const char * rolename, ulong privileges, MEM_ROOT *root) : +ACL_ROLE::ACL_ROLE(const char * rolename, privilege_t privileges, + MEM_ROOT *root) : initial_role_access(privileges), counter(0) { this->access= initial_role_access; @@ -2265,10 +2393,10 @@ bool acl_init(bool dont_read_acl_tables) bool return_val; DBUG_ENTER("acl_init"); - acl_cache= new Hash_filo<acl_entry>(ACL_CACHE_SIZE, 0, 0, + acl_cache= new Hash_filo<acl_entry>(key_memory_acl_cache, ACL_CACHE_SIZE, 0, 0, (my_hash_get_key) acl_entry_get_key, - (my_hash_free_key) free, - &my_charset_utf8_bin); + (my_hash_free_key) my_free, + &my_charset_utf8mb3_bin); /* cache built-in native authentication plugins, @@ -2342,7 +2470,7 @@ static bool acl_load(THD *thd, const Grant_tables& tables) grant_version++; /* Privileges updated */ const Host_table& host_table= tables.host_table(); - init_sql_alloc(&acl_memroot, "ACL", ACL_ALLOC_BLOCK_SIZE, 0, MYF(0)); + init_sql_alloc(key_memory_acl_mem, &acl_memroot, ACL_ALLOC_BLOCK_SIZE, 0, MYF(0)); if (host_table.table_exists()) // "host" table may not exist (e.g. in MySQL 5.6.7+) { if (host_table.init_read_record(&read_record_info)) @@ -2419,7 +2547,8 @@ static bool acl_load(THD *thd, const Grant_tables& tables) user.sort= get_magic_sort("hu", user.host.hostname, user.user.str); user.hostname_length= safe_strlen(user.host.hostname); - my_init_dynamic_array(&user.role_grants, sizeof(ACL_ROLE *), 0, 8, MYF(0)); + my_init_dynamic_array(key_memory_acl_mem, &user.role_grants, + sizeof(ACL_ROLE *), 0, 8, MYF(0)); user.account_locked= user_table.get_account_locked(); @@ -2437,7 +2566,7 @@ static bool acl_load(THD *thd, const Grant_tables& tables) ACL_ROLE *entry= new (&acl_memroot) ACL_ROLE(&user, &acl_memroot); entry->role_grants = user.role_grants; - my_init_dynamic_array(&entry->parent_grantee, + my_init_dynamic_array(key_memory_acl_mem, &entry->parent_grantee, sizeof(ACL_USER_BASE *), 0, 8, MYF(0)); my_hash_insert(&acl_roles, (uchar *)entry); @@ -2582,7 +2711,7 @@ static bool acl_load(THD *thd, const Grant_tables& tables) DBUG_RETURN(TRUE); MEM_ROOT temp_root; - init_alloc_root(&temp_root, "ACL_tmp", ACL_ALLOC_BLOCK_SIZE, 0, MYF(0)); + init_alloc_root(key_memory_acl_mem, &temp_root, ACL_ALLOC_BLOCK_SIZE, 0, MYF(0)); while (!(read_record_info.read_record())) { char *hostname= safe_str(get_field(&temp_root, roles_mapping_table.host())); @@ -2701,15 +2830,16 @@ bool acl_reload(THD *thd) old_acl_roles_mappings= acl_roles_mappings; old_acl_proxy_users= acl_proxy_users; old_acl_dbs= acl_dbs; - my_init_dynamic_array(&acl_hosts, sizeof(ACL_HOST), 20, 50, MYF(0)); - my_init_dynamic_array(&acl_users, sizeof(ACL_USER), 50, 100, MYF(0)); - acl_dbs.init(50, 100); - my_init_dynamic_array(&acl_proxy_users, sizeof(ACL_PROXY_USER), 50, 100, MYF(0)); - my_hash_init2(&acl_roles,50, &my_charset_utf8_bin, + my_init_dynamic_array(key_memory_acl_mem, &acl_hosts, sizeof(ACL_HOST), 20, 50, MYF(0)); + my_init_dynamic_array(key_memory_acl_mem, &acl_users, sizeof(ACL_USER), 50, 100, MYF(0)); + acl_dbs.init(key_memory_acl_mem, 50, 100); + my_init_dynamic_array(key_memory_acl_mem, &acl_proxy_users, sizeof(ACL_PROXY_USER), 50, 100, MYF(0)); + my_hash_init2(key_memory_acl_mem, &acl_roles,50, &my_charset_utf8mb3_bin, 0, 0, 0, (my_hash_get_key) acl_role_get_key, 0, (void (*)(void *))free_acl_role, 0); - my_hash_init2(&acl_roles_mappings, 50, &my_charset_utf8_bin, 0, 0, 0, - (my_hash_get_key) acl_role_map_get_key, 0, 0, 0); + my_hash_init2(key_memory_acl_mem, &acl_roles_mappings, 50, + &my_charset_utf8mb3_bin, 0, 0, 0, (my_hash_get_key) + acl_role_map_get_key, 0, 0, 0); old_mem= acl_memroot; delete_dynamic(&acl_wild_hosts); my_hash_free(&acl_check_hosts); @@ -2762,9 +2892,9 @@ end: privilege mask */ -static ulong get_access(TABLE *form, uint fieldnr, uint *next_field) +static privilege_t get_access(TABLE *form, uint fieldnr, uint *next_field) { - ulong access_bits=0,bit; + ulonglong access_bits=0,bit; char buff[2]; String res(buff,sizeof(buff),&my_charset_latin1); Field **pos; @@ -2779,7 +2909,7 @@ static ulong get_access(TABLE *form, uint fieldnr, uint *next_field) } if (next_field) *next_field=fieldnr; - return access_bits; + return ALL_KNOWN_ACL & access_bits; } @@ -2983,7 +3113,7 @@ bool acl_getroot(Security_context *sctx, const char *user, const char *host, mysql_mutex_lock(&acl_cache->lock); - sctx->db_access= 0; + sctx->db_access= NO_ACL; if (host[0]) // User, not Role { @@ -3045,9 +3175,10 @@ static ACL_USER *find_user_or_anon(const char *host, const char *user, const cha user, host, ip, NULL, FALSE, NULL); } -static int check_user_can_set_role(THD *thd, const char *user, const char *host, - const char *ip, const char *rolename, - ulonglong *access) + +static int check_user_can_set_role(THD *thd, const char *user, + const char *host, const char *ip, + const char *rolename, privilege_t *access) { ACL_ROLE *role; ACL_USER_BASE *acl_user_base; @@ -3158,7 +3289,7 @@ end: } -int acl_check_setrole(THD *thd, const char *rolename, ulonglong *access) +int acl_check_setrole(THD *thd, const char *rolename, privilege_t *access) { if (!initialized) { @@ -3171,11 +3302,11 @@ int acl_check_setrole(THD *thd, const char *rolename, ulonglong *access) } -int acl_setrole(THD *thd, const char *rolename, ulonglong access) +int acl_setrole(THD *thd, const char *rolename, privilege_t access) { /* merge the privileges */ Security_context *sctx= thd->security_ctx; - sctx->master_access= static_cast<ulong>(access); + sctx->master_access= access; if (thd->db.str) sctx->db_access= acl_get(sctx->host, sctx->ip, sctx->user, thd->db.str, FALSE); @@ -3200,7 +3331,8 @@ static uchar* check_get_key(ACL_USER *buff, size_t *length, return (uchar*) buff->host.hostname; } -static void acl_update_role(const char *rolename, ulong privileges) + +static void acl_update_role(const char *rolename, const privilege_t privileges) { ACL_ROLE *role= find_acl_role(rolename); if (role) @@ -3210,7 +3342,7 @@ static void acl_update_role(const char *rolename, ulong privileges) ACL_USER::ACL_USER(THD *thd, const LEX_USER &combo, const Account_options &options, - const ulong privileges) + const privilege_t privileges) { user= safe_lexcstrdup_root(&acl_memroot, combo.user); update_hostname(&host, safe_strdup_root(&acl_memroot, combo.host.str)); @@ -3218,14 +3350,14 @@ ACL_USER::ACL_USER(THD *thd, const LEX_USER &combo, sort= get_magic_sort("hu", host.hostname, user.str); password_last_changed= thd->query_start(); password_lifetime= -1; - my_init_dynamic_array(&role_grants, sizeof(ACL_USER *), 0, 8, MYF(0)); + my_init_dynamic_array(PSI_INSTRUMENT_ME, &role_grants, sizeof(ACL_USER *), 0, 8, MYF(0)); } static int acl_user_update(THD *thd, ACL_USER *acl_user, uint nauth, const LEX_USER &combo, const Account_options &options, - const ulong privileges) + const privilege_t privileges) { ACL_USER_PARAM::AUTH *work_copy= NULL; if (nauth) @@ -3321,22 +3453,23 @@ static int acl_user_update(THD *thd, ACL_USER *acl_user, uint nauth, } -static void acl_insert_role(const char *rolename, ulong privileges) +static void acl_insert_role(const char *rolename, privilege_t privileges) { ACL_ROLE *entry; mysql_mutex_assert_owner(&acl_cache->lock); entry= new (&acl_memroot) ACL_ROLE(rolename, privileges, &acl_memroot); - my_init_dynamic_array(&entry->parent_grantee, + my_init_dynamic_array(key_memory_acl_mem, &entry->parent_grantee, sizeof(ACL_USER_BASE *), 0, 8, MYF(0)); - my_init_dynamic_array(&entry->role_grants, sizeof(ACL_ROLE *), 0, 8, MYF(0)); + my_init_dynamic_array(key_memory_acl_mem, &entry->role_grants, + sizeof(ACL_ROLE *), 0, 8, MYF(0)); my_hash_insert(&acl_roles, (uchar *)entry); } static bool acl_update_db(const char *user, const char *host, const char *db, - ulong privileges) + privilege_t privileges) { mysql_mutex_assert_owner(&acl_cache->lock); @@ -3388,7 +3521,7 @@ static bool acl_update_db(const char *user, const char *host, const char *db, */ static void acl_insert_db(const char *user, const char *host, const char *db, - ulong privileges) + const privilege_t privileges) { ACL_DB acl_db; mysql_mutex_assert_owner(&acl_cache->lock); @@ -3409,10 +3542,10 @@ static void acl_insert_db(const char *user, const char *host, const char *db, acl_cache is not used if db_is_pattern is set. */ -ulong acl_get(const char *host, const char *ip, - const char *user, const char *db, my_bool db_is_pattern) +privilege_t acl_get(const char *host, const char *ip, + const char *user, const char *db, my_bool db_is_pattern) { - ulong host_access= ~(ulong)0, db_access= 0; + privilege_t host_access(ALL_KNOWN_ACL), db_access(NO_ACL); uint i; size_t key_length; char key[ACL_KEY_LENGTH],*tmp_db,*end; @@ -3423,7 +3556,7 @@ ulong acl_get(const char *host, const char *ip, end= strnmov(tmp_db, db, key + sizeof(key) - tmp_db); if (end >= key + sizeof(key)) // db name was truncated - DBUG_RETURN(0); // no privileges for an invalid db name + DBUG_RETURN(NO_ACL); // no privileges for an invalid db name if (lower_case_table_names) { @@ -3437,7 +3570,7 @@ ulong acl_get(const char *host, const char *ip, { db_access=entry->access; mysql_mutex_unlock(&acl_cache->lock); - DBUG_PRINT("exit", ("access: 0x%lx", db_access)); + DBUG_PRINT("exit", ("access: 0x%llx", (longlong) db_access)); DBUG_RETURN(db_access); } @@ -3460,7 +3593,7 @@ ulong acl_get(const char *host, const char *ip, /* No host specified for user. Get hostdata from host table */ - host_access=0; // Host must be found + host_access= NO_ACL; // Host must be found for (i=0 ; i < acl_hosts.elements ; i++) { ACL_HOST *acl_host=dynamic_element(&acl_hosts,i,ACL_HOST*); @@ -3476,7 +3609,8 @@ ulong acl_get(const char *host, const char *ip, exit: /* Save entry in cache for quick retrieval */ if (!db_is_pattern && - (entry= (acl_entry*) malloc(sizeof(acl_entry)+key_length))) + (entry= (acl_entry*) my_malloc(key_memory_acl_cache, + sizeof(acl_entry)+key_length, MYF(MY_WME)))) { entry->access=(db_access & host_access); DBUG_ASSERT(key_length < 0xffff); @@ -3485,7 +3619,7 @@ exit: acl_cache->add(entry); } mysql_mutex_unlock(&acl_cache->lock); - DBUG_PRINT("exit", ("access: 0x%lx", db_access & host_access)); + DBUG_PRINT("exit", ("access: 0x%llx", (longlong) (db_access & host_access))); DBUG_RETURN(db_access & host_access); } @@ -3500,9 +3634,10 @@ exit: static void init_check_host(void) { DBUG_ENTER("init_check_host"); - (void) my_init_dynamic_array(&acl_wild_hosts,sizeof(struct acl_host_and_ip), + (void) my_init_dynamic_array(key_memory_acl_mem, &acl_wild_hosts, + sizeof(struct acl_host_and_ip), acl_users.elements, 1, MYF(0)); - (void) my_hash_init(&acl_check_hosts,system_charset_info, + (void) my_hash_init(key_memory_acl_mem, &acl_check_hosts,system_charset_info, acl_users.elements, 0, 0, (my_hash_get_key) check_get_key, 0, 0); if (!allow_all_hosts) @@ -4267,7 +4402,7 @@ bool hostname_requires_resolving(const char *hostname) if (hostname == my_localhost || (hostname_len == localhost_len && - !my_strnncoll(system_charset_info, + !system_charset_info->strnncoll( (const uchar *) hostname, hostname_len, (const uchar *) my_localhost, strlen(my_localhost)))) { @@ -4378,7 +4513,7 @@ static bool test_if_create_new_users(THD *thd) if (!create_new_users) { TABLE_LIST tl; - ulong db_access; + privilege_t db_access(NO_ACL); tl.init_one_table(&MYSQL_SCHEMA_NAME, &MYSQL_TABLE_NAME[USER_TABLE], NULL, TL_WRITE); create_new_users= 1; @@ -4403,8 +4538,9 @@ static bool test_if_create_new_users(THD *thd) static USER_AUTH auth_no_password; static int replace_user_table(THD *thd, const User_table &user_table, - LEX_USER * const combo, ulong rights, - const bool revoke_grant, const bool can_create_user, + LEX_USER * const combo, privilege_t rights, + const bool revoke_grant, + const bool can_create_user, const bool no_auto_create) { int error = -1; @@ -4662,10 +4798,11 @@ end: static int replace_db_table(TABLE *table, const char *db, const LEX_USER &combo, - ulong rights, const bool revoke_grant) + privilege_t rights, const bool revoke_grant) { uint i; - ulong priv,store_rights; + ulonglong priv; + privilege_t store_rights(NO_ACL); bool old_row_exists=0; int error; char what= revoke_grant ? 'N' : 'Y'; @@ -4916,7 +5053,7 @@ acl_update_proxy_user(ACL_PROXY_USER *new_value, bool is_revoke) { if (is_revoke) { - DBUG_PRINT("info", ("delting ACL_PROXY_USER")); + DBUG_PRINT("info", ("deleting ACL_PROXY_USER")); delete_dynamic_element(&acl_proxy_users, i); } else @@ -5071,17 +5208,17 @@ class GRANT_COLUMN :public Sql_alloc { public: char *column; - ulong rights; - ulong init_rights; + privilege_t rights; + privilege_t init_rights; uint key_length; - GRANT_COLUMN(String &c, ulong y) :rights (y), init_rights(y) + GRANT_COLUMN(String &c, privilege_t y) :rights (y), init_rights(y) { column= (char*) memdup_root(&grant_memroot,c.ptr(), key_length=c.length()); } /* this constructor assumes thas source->column is allocated in grant_memroot */ GRANT_COLUMN(GRANT_COLUMN *source) : column(source->column), - rights (source->rights), init_rights(0), key_length(source->key_length) { } + rights (source->rights), init_rights(NO_ACL), key_length(source->key_length) { } }; @@ -5097,37 +5234,43 @@ class GRANT_NAME :public Sql_alloc public: acl_host_and_ip host; char *db, *user, *tname, *hash_key; - ulong privs; - ulong init_privs; /* privileges found in physical table */ + privilege_t privs; + privilege_t init_privs; /* privileges found in physical table */ ulonglong sort; size_t key_length; GRANT_NAME(const char *h, const char *d,const char *u, - const char *t, ulong p, bool is_routine); + const char *t, privilege_t p, bool is_routine); GRANT_NAME (TABLE *form, bool is_routine); virtual ~GRANT_NAME() {}; - virtual bool ok() { return privs != 0; } + virtual bool ok() { return privs != NO_ACL; } void set_user_details(const char *h, const char *d, const char *u, const char *t, bool is_routine); }; +static privilege_t get_access_value_from_val_int(Field *field) +{ + return privilege_t(ALL_KNOWN_ACL & (ulonglong) field->val_int()); +} + + class GRANT_TABLE :public GRANT_NAME { public: - ulong cols; - ulong init_cols; /* privileges found in physical table */ + privilege_t cols; + privilege_t init_cols; /* privileges found in physical table */ HASH hash_columns; GRANT_TABLE(const char *h, const char *d,const char *u, - const char *t, ulong p, ulong c); + const char *t, privilege_t p, privilege_t c); GRANT_TABLE (TABLE *form, TABLE *col_privs); ~GRANT_TABLE(); - bool ok() { return privs != 0 || cols != 0; } + bool ok() { return privs != NO_ACL || cols != NO_ACL; } void init_hash() { - my_hash_init2(&hash_columns, 4, system_charset_info, 0, 0, 0, - (my_hash_get_key) get_key_column, 0, 0, 0); + my_hash_init2(key_memory_acl_memex, &hash_columns, 4, system_charset_info, + 0, 0, 0, (my_hash_get_key) get_key_column, 0, 0, 0); } }; @@ -5158,15 +5301,15 @@ void GRANT_NAME::set_user_details(const char *h, const char *d, } GRANT_NAME::GRANT_NAME(const char *h, const char *d,const char *u, - const char *t, ulong p, bool is_routine) + const char *t, privilege_t p, bool is_routine) :db(0), tname(0), privs(p), init_privs(p) { set_user_details(h, d, u, t, is_routine); } GRANT_TABLE::GRANT_TABLE(const char *h, const char *d,const char *u, - const char *t, ulong p, ulong c) - :GRANT_NAME(h,d,u,t,p, FALSE), cols(c) + const char *t, privilege_t p, privilege_t c) + :GRANT_NAME(h,d,u,t,p, FALSE), cols(c), init_cols(NO_ACL) { init_hash(); } @@ -5176,6 +5319,7 @@ GRANT_TABLE::GRANT_TABLE(const char *h, const char *d,const char *u, to 0 */ GRANT_NAME::GRANT_NAME(TABLE *form, bool is_routine) + :privs(NO_ACL), init_privs(NO_ACL) { user= safe_str(get_field(&grant_memroot,form->field[2])); @@ -5191,7 +5335,6 @@ GRANT_NAME::GRANT_NAME(TABLE *form, bool is_routine) if (!db || !tname) { /* Wrong table row; Ignore it */ - privs= 0; return; /* purecov: inspected */ } sort= get_magic_sort("hdu", host.hostname, db, user); @@ -5206,14 +5349,14 @@ GRANT_NAME::GRANT_NAME(TABLE *form, bool is_routine) key_length= (strlen(db) + strlen(user) + strlen(tname) + 3); hash_key= (char*) alloc_root(&grant_memroot, key_length); strmov(strmov(strmov(hash_key,user)+1,db)+1,tname); - privs = (ulong) form->field[6]->val_int(); + privs = get_access_value_from_val_int(form->field[6]); privs = fix_rights_for_table(privs); init_privs= privs; } GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs) - :GRANT_NAME(form, FALSE) + :GRANT_NAME(form, FALSE), cols(NO_ACL), init_cols(NO_ACL) { uchar key[MAX_KEY_LENGTH]; @@ -5221,10 +5364,10 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs) { /* Wrong table row; Ignore it */ my_hash_clear(&hash_columns); /* allow for destruction */ - cols= 0; + cols= NO_ACL; return; } - cols= (ulong) form->field[7]->val_int(); + cols= get_access_value_from_val_int(form->field[7]); cols= fix_rights_for_column(cols); /* Initial columns privileges are the same as column privileges on creation. @@ -5256,8 +5399,8 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs) if (col_privs->file->ha_index_init(0, 1)) { - cols= 0; - init_cols= 0; + cols= NO_ACL; + init_cols= NO_ACL; return; } @@ -5265,8 +5408,8 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs) (key_part_map)15, HA_READ_KEY_EXACT)) { - cols= 0; /* purecov: deadcode */ - init_cols= 0; + cols= NO_ACL; /* purecov: deadcode */ + init_cols= NO_ACL; col_privs->file->ha_index_end(); return; } @@ -5276,18 +5419,18 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs) GRANT_COLUMN *mem_check; /* As column name is a string, we don't have to supply a buffer */ res=col_privs->field[4]->val_str(&column_name); - ulong priv= (ulong) col_privs->field[6]->val_int(); + privilege_t priv= get_access_value_from_val_int(col_privs->field[6]); if (!(mem_check = new GRANT_COLUMN(*res, fix_rights_for_column(priv)))) { /* Don't use this entry */ - privs= cols= init_privs= init_cols=0; /* purecov: deadcode */ + privs= cols= init_privs= init_cols= NO_ACL; /* purecov: deadcode */ return; /* purecov: deadcode */ } if (my_hash_insert(&hash_columns, (uchar *) mem_check)) { /* Invalidate this entry */ - privs= cols= init_privs= init_cols=0; + privs= cols= init_privs= init_cols= NO_ACL; return; } } while (!col_privs->file->ha_index_next(col_privs->record[0]) && @@ -5397,8 +5540,7 @@ column_hash_search(GRANT_TABLE *t, const char *cname, size_t length) { if (!my_hash_inited(&t->hash_columns)) return (GRANT_COLUMN*) 0; - return (GRANT_COLUMN*) my_hash_search(&t->hash_columns, - (uchar*) cname, length); + return (GRANT_COLUMN*)my_hash_search(&t->hash_columns, (uchar*)cname, length); } @@ -5406,7 +5548,7 @@ static int replace_column_table(GRANT_TABLE *g_t, TABLE *table, const LEX_USER &combo, List <LEX_COLUMN> &columns, const char *db, const char *table_name, - ulong rights, bool revoke_grant) + privilege_t rights, bool revoke_grant) { int result=0; uchar key[MAX_KEY_LENGTH]; @@ -5435,6 +5577,7 @@ static int replace_column_table(GRANT_TABLE *g_t, List_iterator <LEX_COLUMN> iter(columns); class LEX_COLUMN *column; + int error= table->file->ha_index_init(0, 1); if (unlikely(error)) { @@ -5444,7 +5587,7 @@ static int replace_column_table(GRANT_TABLE *g_t, while ((column= iter++)) { - ulong privileges= column->rights; + privilege_t privileges= column->rights; bool old_row_exists=0; uchar user_key[MAX_KEY_LENGTH]; @@ -5476,7 +5619,7 @@ static int replace_column_table(GRANT_TABLE *g_t, } else { - ulong tmp= (ulong) table->field[6]->val_int(); + privilege_t tmp= get_access_value_from_val_int(table->field[6]); tmp=fix_rights_for_column(tmp); if (revoke_grant) @@ -5546,7 +5689,7 @@ static int replace_column_table(GRANT_TABLE *g_t, /* Scan through all rows with the same host,db,user and table */ do { - ulong privileges = (ulong) table->field[6]->val_int(); + privilege_t privileges = get_access_value_from_val_int(table->field[6]); privileges=fix_rights_for_column(privileges); store_record(table,record[1]); @@ -5559,7 +5702,7 @@ static int replace_column_table(GRANT_TABLE *g_t, privileges&= ~rights; table->field[6]->store((longlong) - get_rights_for_column(privileges), TRUE); + get_rights_for_column(privileges), TRUE); table->field[4]->val_str(&column_name); grant_column = column_hash_search(g_t, column_name.ptr(), @@ -5632,13 +5775,13 @@ static inline void get_grantor(THD *thd, char *grantor) static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, TABLE *table, const LEX_USER &combo, const char *db, const char *table_name, - ulong rights, ulong col_rights, + privilege_t rights, privilege_t col_rights, bool revoke_grant) { char grantor[USER_HOST_BUFF_SIZE]; int old_row_exists = 1; int error=0; - ulong store_table_rights, store_col_rights; + privilege_t store_table_rights(NO_ACL), store_col_rights(NO_ACL); uchar user_key[MAX_KEY_LENGTH]; DBUG_ENTER("replace_table_table"); @@ -5694,10 +5837,9 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, store_col_rights= get_rights_for_column(col_rights); if (old_row_exists) { - ulong j,k; store_record(table,record[1]); - j = (ulong) table->field[6]->val_int(); - k = (ulong) table->field[7]->val_int(); + privilege_t j= get_access_value_from_val_int(table->field[6]); + privilege_t k= get_access_value_from_val_int(table->field[7]); if (revoke_grant) { @@ -5766,12 +5908,11 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name, TABLE *table, const LEX_USER &combo, const char *db, const char *routine_name, const Sp_handler *sph, - ulong rights, bool revoke_grant) + privilege_t rights, bool revoke_grant) { char grantor[USER_HOST_BUFF_SIZE]; int old_row_exists= 1; int error=0; - ulong store_proc_rights; HASH *hash= sph->get_priv_hash(); DBUG_ENTER("replace_routine_table"); @@ -5797,7 +5938,7 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name, */ table->use_all_columns(); - restore_record(table, s->default_values); // Get empty record + restore_record(table, s->default_values); // Get empty record table->field[0]->store(combo.host.str,combo.host.length, &my_charset_latin1); table->field[1]->store(db,(uint) strlen(db), &my_charset_latin1); table->field[2]->store(combo.user.str,combo.user.length, &my_charset_latin1); @@ -5829,12 +5970,11 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name, restore_record(table,record[1]); // Get saved record } - store_proc_rights= get_rights_for_procedure(rights); + privilege_t store_proc_rights= get_rights_for_procedure(rights); if (old_row_exists) { - ulong j; store_record(table,record[1]); - j= (ulong) table->field[6]->val_int(); + privilege_t j= get_access_value_from_val_int(table->field[6]); if (revoke_grant) { @@ -5927,19 +6067,19 @@ struct PRIVS_TO_MERGE }; -static enum PRIVS_TO_MERGE::what sp_privs_to_merge(stored_procedure_type type) +static enum PRIVS_TO_MERGE::what sp_privs_to_merge(enum_sp_type type) { switch (type) { - case TYPE_ENUM_FUNCTION: + case SP_TYPE_FUNCTION: return PRIVS_TO_MERGE::FUNC; - case TYPE_ENUM_PROCEDURE: + case SP_TYPE_PROCEDURE: return PRIVS_TO_MERGE::PROC; - case TYPE_ENUM_PACKAGE: + case SP_TYPE_PACKAGE: return PRIVS_TO_MERGE::PACKAGE_SPEC; - case TYPE_ENUM_PACKAGE_BODY: + case SP_TYPE_PACKAGE_BODY: return PRIVS_TO_MERGE::PACKAGE_BODY; - case TYPE_ENUM_TRIGGER: - case TYPE_ENUM_PROXY: + case SP_TYPE_EVENT: + case SP_TYPE_TRIGGER: break; } DBUG_ASSERT(0); @@ -6239,7 +6379,7 @@ typedef Hash_set<ACL_ROLE> role_hash_t; static bool merge_role_global_privileges(ACL_ROLE *grantee) { - ulong old= grantee->access; + privilege_t old= grantee->access; grantee->access= grantee->initial_role_access; DBUG_EXECUTE_IF("role_merge_stats", role_global_merges++;); @@ -6270,7 +6410,7 @@ static int db_name_sort(const int *db1, const int *db2) 2 - ACL_DB was added 4 - ACL_DB was deleted */ -static int update_role_db(int merged, int first, ulong access, +static int update_role_db(int merged, int first, privilege_t access, const char *role) { if (first < 0) @@ -6295,12 +6435,12 @@ static int update_role_db(int merged, int first, ulong access, acl_db.host.ip= acl_db.host.ip_mask= 0; acl_db.db= acl_dbs.at(first).db; acl_db.access= access; - acl_db.initial_access= 0; + acl_db.initial_access= NO_ACL; acl_db.sort= get_magic_sort("hdu", "", acl_db.db, role); acl_dbs.push(acl_db); return 2; } - else if (access == 0) + else if (access == NO_ACL) { /* there is ACL_DB but the role has no db privileges granted @@ -6334,7 +6474,7 @@ static int update_role_db(int merged, int first, ulong access, static bool merge_role_db_privileges(ACL_ROLE *grantee, const char *dbname, role_hash_t *rhash) { - Dynamic_array<int> dbs; + Dynamic_array<int> dbs(PSI_INSTRUMENT_MEM); /* Supposedly acl_dbs can be huge, but only a handful of db grants @@ -6362,14 +6502,15 @@ static bool merge_role_db_privileges(ACL_ROLE *grantee, const char *dbname, is not necessarily the first and may be not present at all. */ int first= -1, merged= -1; - ulong access= 0, update_flags= 0; + privilege_t access(NO_ACL); + ulong update_flags= 0; for (int *p= dbs.front(); p <= dbs.back(); p++) { if (first<0 || (!dbname && strcmp(acl_dbs.at(p[0]).db, acl_dbs.at(p[-1]).db))) { // new db name series update_flags|= update_role_db(merged, first, access, grantee->user.str); merged= -1; - access= 0; + access= NO_ACL; first= *p; } if (strcmp(acl_dbs.at(*p).user, grantee->user.str) == 0) @@ -6427,7 +6568,7 @@ static int update_role_columns(GRANT_TABLE *merged, GRANT_TABLE **cur, GRANT_TABLE **last) { - ulong rights __attribute__((unused))= 0; + privilege_t rights __attribute__((unused)) (NO_ACL); int changed= 0; if (!merged->cols) { @@ -6497,7 +6638,8 @@ static int update_role_columns(GRANT_TABLE *merged, */ static int update_role_table_columns(GRANT_TABLE *merged, GRANT_TABLE **first, GRANT_TABLE **last, - ulong privs, ulong cols, const char *role) + privilege_t privs, privilege_t cols, + const char *role) { if (!first) return 0; @@ -6513,12 +6655,12 @@ static int update_role_table_columns(GRANT_TABLE *merged, DBUG_ASSERT(privs | cols); merged= new (&grant_memroot) GRANT_TABLE("", first[0]->db, role, first[0]->tname, privs, cols); - merged->init_privs= merged->init_cols= 0; + merged->init_privs= merged->init_cols= NO_ACL; update_role_columns(merged, first, last); column_priv_insert(merged); return 2; } - else if ((privs | cols) == 0) + else if ((privs | cols) == NO_ACL) { /* there is GRANT_TABLE object but the role has no table or column @@ -6551,7 +6693,7 @@ static int update_role_table_columns(GRANT_TABLE *merged, static bool merge_role_table_and_column_privileges(ACL_ROLE *grantee, const char *db, const char *tname, role_hash_t *rhash) { - Dynamic_array<GRANT_TABLE *> grants; + Dynamic_array<GRANT_TABLE *> grants(PSI_INSTRUMENT_MEM); DBUG_ASSERT(MY_TEST(db) == MY_TEST(tname)); // both must be set, or neither /* @@ -6573,7 +6715,8 @@ static bool merge_role_table_and_column_privileges(ACL_ROLE *grantee, grants.sort(table_name_sort); GRANT_TABLE **first= NULL, *merged= NULL, **cur; - ulong privs= 0, cols= 0, update_flags= 0; + privilege_t privs(NO_ACL), cols(NO_ACL); + ulong update_flags= 0; for (cur= grants.front(); cur <= grants.back(); cur++) { if (!first || @@ -6583,7 +6726,7 @@ static bool merge_role_table_and_column_privileges(ACL_ROLE *grantee, update_flags|= update_role_table_columns(merged, first, cur, privs, cols, grantee->user.str); merged= NULL; - privs= cols= 0; + privs= cols= NO_ACL; first= cur; } if (strcmp(cur[0]->user, grantee->user.str) == 0) @@ -6626,7 +6769,7 @@ static int routine_name_sort(GRANT_NAME * const *r1, GRANT_NAME * const *r2) 4 - GRANT_NAME was deleted */ static int update_role_routines(GRANT_NAME *merged, GRANT_NAME **first, - ulong privs, const char *role, HASH *hash) + privilege_t privs, const char *role, HASH *hash) { if (!first) return 0; @@ -6642,11 +6785,11 @@ static int update_role_routines(GRANT_NAME *merged, GRANT_NAME **first, DBUG_ASSERT(privs); merged= new (&grant_memroot) GRANT_NAME("", first[0]->db, role, first[0]->tname, privs, true); - merged->init_privs= 0; // all privs are inherited + merged->init_privs= NO_ACL; // all privs are inherited my_hash_insert(hash, (uchar *)merged); return 2; } - else if (privs == 0) + else if (privs == NO_ACL) { /* there is GRANT_NAME but the role has no privileges granted @@ -6679,7 +6822,7 @@ static bool merge_role_routine_grant_privileges(ACL_ROLE *grantee, DBUG_ASSERT(MY_TEST(db) == MY_TEST(tname)); // both must be set, or neither - Dynamic_array<GRANT_NAME *> grants; + Dynamic_array<GRANT_NAME *> grants(PSI_INSTRUMENT_MEM); /* first, collect routine privileges granted to roles in question */ for (uint i=0 ; i < hash->records ; i++) @@ -6697,7 +6840,7 @@ static bool merge_role_routine_grant_privileges(ACL_ROLE *grantee, grants.sort(routine_name_sort); GRANT_NAME **first= NULL, *merged= NULL; - ulong privs= 0 ; + privilege_t privs(NO_ACL); for (GRANT_NAME **cur= grants.front(); cur <= grants.back(); cur++) { if (!first || @@ -6707,7 +6850,7 @@ static bool merge_role_routine_grant_privileges(ACL_ROLE *grantee, update_flags|= update_role_routines(merged, first, privs, grantee->user.str, hash); merged= NULL; - privs= 0; + privs= NO_ACL; first= cur; } if (strcmp(cur[0]->user, grantee->user.str) == 0) @@ -6740,7 +6883,7 @@ static int merge_role_privileges(ACL_ROLE *role __attribute__((unused)), grantee->counter= 1; // Mark the grantee as merged. /* if we'll do db/table/routine privileges, create a hash of role names */ - role_hash_t role_hash(role_key); + role_hash_t role_hash(PSI_INSTRUMENT_MEM, role_key); if (data->what != PRIVS_TO_MERGE::GLOBAL) { role_hash.insert(grantee); @@ -6831,11 +6974,11 @@ static bool copy_and_check_auth(LEX_USER *to, LEX_USER *from, THD *thd) int mysql_table_grant(THD *thd, TABLE_LIST *table_list, List <LEX_USER> &user_list, - List <LEX_COLUMN> &columns, ulong rights, + List <LEX_COLUMN> &columns, privilege_t rights, bool revoke_grant) { - ulong column_priv= 0; - int result, res; + privilege_t column_priv(NO_ACL); + int result; List_iterator <LEX_USER> str_list (user_list); LEX_USER *Str, *tmp_Str; bool create_new_users=0; @@ -6954,7 +7097,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, /* Create user if needed */ error= copy_and_check_auth(Str, tmp_Str, thd) || replace_user_table(thd, tables.user_table(), Str, - 0, revoke_grant, create_new_users, + NO_ACL, revoke_grant, create_new_users, MY_TEST(thd->variables.sql_mode & MODE_NO_AUTO_CREATE_USER)); if (unlikely(error)) @@ -7007,7 +7150,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, grant_column->rights&= ~(column->rights | rights); } /* scan trough all columns to get new column grant */ - column_priv= 0; + column_priv= NO_ACL; for (uint idx=0 ; idx < grant_table->hash_columns.records ; idx++) { grant_column= (GRANT_COLUMN*) @@ -7035,10 +7178,10 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, revoke_grant)) result= TRUE; } - if ((res= replace_table_table(thd, grant_table, - tables.tables_priv_table().table(), - *Str, db_name, table_name, - rights, column_priv, revoke_grant))) + if (int res= replace_table_table(thd, grant_table, + tables.tables_priv_table().table(), + *Str, db_name, table_name, + rights, column_priv, revoke_grant)) { if (res > 0) { @@ -7084,7 +7227,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, const Sp_handler *sph, - List <LEX_USER> &user_list, ulong rights, + List <LEX_USER> &user_list, privilege_t rights, bool revoke_grant, bool write_to_binlog) { List_iterator <LEX_USER> str_list (user_list); @@ -7134,7 +7277,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, /* Create user if needed */ if (copy_and_check_auth(Str, tmp_Str, thd) || replace_user_table(thd, tables.user_table(), Str, - 0, revoke_grant, create_new_users, + NO_ACL, revoke_grant, create_new_users, MY_TEST(thd->variables.sql_mode & MODE_NO_AUTO_CREATE_USER))) { @@ -7405,7 +7548,7 @@ bool mysql_grant_role(THD *thd, List <LEX_USER> &list, bool revoke) user_combo.user = username; if (copy_and_check_auth(&user_combo, &user_combo, thd) || - replace_user_table(thd, tables.user_table(), &user_combo, 0, + replace_user_table(thd, tables.user_table(), &user_combo, NO_ACL, false, create_new_user, no_auto_create_user)) { @@ -7518,7 +7661,7 @@ bool mysql_grant_role(THD *thd, List <LEX_USER> &list, bool revoke) bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list, - ulong rights, bool revoke_grant, bool is_proxy) + privilege_t rights, bool revoke_grant, bool is_proxy) { List_iterator <LEX_USER> str_list (list); LEX_USER *Str, *tmp_Str, *proxied_user= NULL; @@ -7577,13 +7720,14 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list, if (copy_and_check_auth(Str, tmp_Str, thd) || replace_user_table(thd, tables.user_table(), Str, - (!db ? rights : 0), revoke_grant, create_new_users, + (!db ? rights : NO_ACL), + revoke_grant, create_new_users, MY_TEST(thd->variables.sql_mode & MODE_NO_AUTO_CREATE_USER))) result= true; else if (db) { - ulong db_rights= rights & DB_ACLS; + privilege_t db_rights(rights & DB_ACLS); if (db_rights == rights) { if (replace_db_table(tables.db_table().table(), db, *Str, db_rights, @@ -7687,23 +7831,26 @@ static bool grant_load(THD *thd, TABLE *t_table, *c_table, *p_table; bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE; MEM_ROOT *save_mem_root= thd->mem_root; - sql_mode_t old_sql_mode= thd->variables.sql_mode; DBUG_ENTER("grant_load"); - thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH; - - (void) my_hash_init(&column_priv_hash, &my_charset_utf8_bin, - 0,0,0, (my_hash_get_key) get_grant_table, - (my_hash_free_key) free_grant_table,0); - (void) my_hash_init(&proc_priv_hash, &my_charset_utf8_bin, - 0,0,0, (my_hash_get_key) get_grant_table, 0,0); - (void) my_hash_init(&func_priv_hash, &my_charset_utf8_bin, - 0,0,0, (my_hash_get_key) get_grant_table, 0,0); - (void) my_hash_init(&package_spec_priv_hash, &my_charset_utf8_bin, - 0,0,0, (my_hash_get_key) get_grant_table, 0,0); - (void) my_hash_init(&package_body_priv_hash, &my_charset_utf8_bin, - 0,0,0, (my_hash_get_key) get_grant_table, 0,0); - init_sql_alloc(&grant_memroot, "GRANT", ACL_ALLOC_BLOCK_SIZE, 0, MYF(0)); + Sql_mode_instant_remove sms(thd, MODE_PAD_CHAR_TO_FULL_LENGTH); + + (void) my_hash_init(key_memory_acl_memex, &column_priv_hash, + &my_charset_utf8mb3_bin, 0,0,0, (my_hash_get_key) + get_grant_table, (my_hash_free_key) free_grant_table, 0); + (void) my_hash_init(key_memory_acl_memex, &proc_priv_hash, + &my_charset_utf8mb3_bin, 0,0,0, (my_hash_get_key) + get_grant_table, 0,0); + (void) my_hash_init(key_memory_acl_memex, &func_priv_hash, + &my_charset_utf8mb3_bin, 0,0,0, (my_hash_get_key) + get_grant_table, 0,0); + (void) my_hash_init(key_memory_acl_memex, &package_spec_priv_hash, + &my_charset_utf8mb3_bin, 0,0,0, (my_hash_get_key) + get_grant_table, 0,0); + (void) my_hash_init(key_memory_acl_memex, &package_body_priv_hash, + &my_charset_utf8mb3_bin, 0,0,0, (my_hash_get_key) + get_grant_table, 0,0); + init_sql_alloc(key_memory_acl_mem, &grant_memroot, ACL_ALLOC_BLOCK_SIZE, 0, MYF(0)); t_table= tables_priv.table(); c_table= columns_priv.table(); @@ -7784,7 +7931,7 @@ static bool grant_load(THD *thd, continue; } } - stored_procedure_type type= (stored_procedure_type)procs_priv.routine_type()->val_int(); + enum_sp_type type= (enum_sp_type)procs_priv.routine_type()->val_int(); const Sp_handler *sph= Sp_handler::handler(type); if (!sph || !(hash= sph->get_priv_hash())) { @@ -7815,7 +7962,6 @@ end_unlock: t_table->file->ha_index_end(); thd->mem_root= save_mem_root; end_index_init: - thd->variables.sql_mode= old_sql_mode; DBUG_RETURN(return_val); } @@ -7959,14 +8105,14 @@ bool grant_reload(THD *thd) */ -bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, +bool check_grant(THD *thd, privilege_t want_access, TABLE_LIST *tables, bool any_combination_will_do, uint number, bool no_errors) { TABLE_LIST *tl; TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table(); Security_context *sctx= thd->security_ctx; uint i; - ulong original_want_access= want_access; + privilege_t original_want_access(want_access); bool locked= 0; GRANT_TABLE *grant_table; GRANT_TABLE *grant_table_role= NULL; @@ -8000,7 +8146,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, TABLE_LIST *const t_ref= tl->correspondent_table ? tl->correspondent_table : tl; sctx= t_ref->security_ctx ? t_ref->security_ctx : thd->security_ctx; - ulong orig_want_access= original_want_access; + privilege_t orig_want_access(original_want_access); /* If sequence is used as part of NEXT VALUE, PREVIOUS VALUE or SELECT, @@ -8033,15 +8179,9 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, switch(access->check(orig_want_access, &t_ref->grant.privilege)) { case ACL_INTERNAL_ACCESS_GRANTED: - /* - Currently, - - the information_schema does not subclass ACL_internal_table_access, - there are no per table privilege checks for I_S, - - the performance schema does use per tables checks, but at most - returns 'CHECK_GRANT', and never 'ACCESS_GRANTED'. - so this branch is not used. - */ - DBUG_ASSERT(0); + t_ref->grant.privilege|= orig_want_access; + t_ref->grant.want_privilege= NO_ACL; + continue; case ACL_INTERNAL_ACCESS_DENIED: goto err; case ACL_INTERNAL_ACCESS_CHECK_GRANT: @@ -8071,7 +8211,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, clause, or an INFORMATION_SCHEMA table, drop the request for a privilege. */ - t_ref->grant.want_privilege= 0; + t_ref->grant.want_privilege= NO_ACL; } continue; } @@ -8085,7 +8225,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, if user has CREATE_TMP_ACL. */ t_ref->grant.privilege|= TMP_TABLE_ACLS; - t_ref->grant.want_privilege= 0; + t_ref->grant.want_privilege= NO_ACL; continue; } @@ -8122,15 +8262,15 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, t_ref->grant.grant_table_user= grant_table; // Remember for column test t_ref->grant.grant_table_role= grant_table_role; t_ref->grant.version= grant_version; - t_ref->grant.privilege|= grant_table ? grant_table->privs : 0; - t_ref->grant.privilege|= grant_table_role ? grant_table_role->privs : 0; + t_ref->grant.privilege|= grant_table ? grant_table->privs : NO_ACL; + t_ref->grant.privilege|= grant_table_role ? grant_table_role->privs : NO_ACL; t_ref->grant.want_privilege= ((want_access & COL_ACLS) & ~t_ref->grant.privilege); if (!(~t_ref->grant.privilege & want_access)) continue; - if ((want_access&= ~((grant_table ? grant_table->cols : 0) | - (grant_table_role ? grant_table_role->cols : 0) | + if ((want_access&= ~((grant_table ? grant_table->cols : NO_ACL) | + (grant_table_role ? grant_table_role->cols : NO_ACL) | t_ref->grant.privilege))) { goto err; // impossible @@ -8160,7 +8300,7 @@ err: static void check_grant_column_int(GRANT_TABLE *grant_table, const char *name, - uint length, ulong *want_access) + uint length, privilege_t *want_access) { if (grant_table) { @@ -8196,9 +8336,10 @@ bool check_grant_column(THD *thd, GRANT_INFO *grant, const char *db_name, const char *table_name, const char *name, size_t length, Security_context *sctx) { - ulong want_access= grant->want_privilege & ~grant->privilege; + privilege_t want_access(grant->want_privilege & ~grant->privilege); DBUG_ENTER("check_grant_column"); - DBUG_PRINT("enter", ("table: %s want_access: %lu", table_name, want_access)); + DBUG_PRINT("enter", ("table: %s want_access: %llx", + table_name, (longlong) want_access)); if (!want_access) DBUG_RETURN(0); // Already checked @@ -8278,7 +8419,7 @@ bool check_column_grant_in_table_ref(THD *thd, TABLE_LIST * table_ref, if (table_ref->view || table_ref->field_translation) { /* View or derived information schema table. */ - ulong view_privs; + privilege_t view_privs(NO_ACL); grant= &(table_ref->grant); db_name= table_ref->view_db.str; table_name= table_ref->view_name.str; @@ -8329,11 +8470,11 @@ bool check_column_grant_in_table_ref(THD *thd, TABLE_LIST * table_ref, For each table it will retrieve the grant information and will use it to check the required access privileges for the fields requested from it. */ -bool check_grant_all_columns(THD *thd, ulong want_access_arg, +bool check_grant_all_columns(THD *thd, privilege_t want_access_arg, Field_iterator_table_ref *fields) { Security_context *sctx= thd->security_ctx; - ulong UNINIT_VAR(want_access); + privilege_t want_access(NO_ACL); const char *table_name= NULL; const char* db_name; GRANT_INFO *grant; @@ -8386,7 +8527,7 @@ bool check_grant_all_columns(THD *thd, ulong want_access_arg, if (want_access) { - ulong have_access= 0; + privilege_t have_access(NO_ACL); if (grant_table) { GRANT_COLUMN *grant_column= @@ -8553,7 +8694,7 @@ bool check_grant_db(THD *thd, const char *db) 1 Error: User did not have the requested privielges ****************************************************************************/ -bool check_grant_routine(THD *thd, ulong want_access, +bool check_grant_routine(THD *thd, privilege_t want_access, TABLE_LIST *procs, const Sp_handler *sph, bool no_errors) { @@ -8656,9 +8797,8 @@ bool check_routine_level_acl(THD *thd, const char *db, const char *name, Functions to retrieve the grant for a table/column (for SHOW functions) *****************************************************************************/ -ulong get_table_grant(THD *thd, TABLE_LIST *table) +privilege_t get_table_grant(THD *thd, TABLE_LIST *table) { - ulong privilege; Security_context *sctx= thd->security_ctx; const char *db = table->db.str ? table->db.str : thd->db.str; GRANT_TABLE *grant_table; @@ -8682,7 +8822,7 @@ ulong get_table_grant(THD *thd, TABLE_LIST *table) table->grant.privilege|= grant_table->privs; if (grant_table_role) table->grant.privilege|= grant_table_role->privs; - privilege= table->grant.privilege; + privilege_t privilege(table->grant.privilege); mysql_rwlock_unlock(&LOCK_grant); return privilege; } @@ -8706,14 +8846,14 @@ ulong get_table_grant(THD *thd, TABLE_LIST *table) The access priviliges for the field db_name.table_name.field_name */ -ulong get_column_grant(THD *thd, GRANT_INFO *grant, - const char *db_name, const char *table_name, - const char *field_name) +privilege_t get_column_grant(THD *thd, GRANT_INFO *grant, + const char *db_name, const char *table_name, + const char *field_name) { GRANT_TABLE *grant_table; GRANT_TABLE *grant_table_role; GRANT_COLUMN *grant_column; - ulong priv= 0; + privilege_t priv(NO_ACL); mysql_rwlock_rdlock(&LOCK_grant); /* reload table if someone has modified any grants */ @@ -8892,19 +9032,34 @@ static const char *command_array[]= "SELECT", "INSERT", "UPDATE", "DELETE", "CREATE", "DROP", "RELOAD", "SHUTDOWN", "PROCESS","FILE", "GRANT", "REFERENCES", "INDEX", "ALTER", "SHOW DATABASES", "SUPER", "CREATE TEMPORARY TABLES", - "LOCK TABLES", "EXECUTE", "REPLICATION SLAVE", "REPLICATION CLIENT", + "LOCK TABLES", "EXECUTE", "REPLICATION SLAVE", "BINLOG MONITOR", "CREATE VIEW", "SHOW VIEW", "CREATE ROUTINE", "ALTER ROUTINE", - "CREATE USER", "EVENT", "TRIGGER", "CREATE TABLESPACE", - "DELETE HISTORY" + "CREATE USER", "EVENT", "TRIGGER", "CREATE TABLESPACE", "DELETE HISTORY", + "SET USER", "FEDERATED ADMIN", "CONNECTION ADMIN", "READ_ONLY ADMIN", + "REPLICATION SLAVE ADMIN", "REPLICATION MASTER ADMIN", "BINLOG ADMIN", + "BINLOG REPLAY", "SLAVE MONITOR" }; static uint command_lengths[]= { - 6, 6, 6, 6, 6, 4, 6, 8, 7, 4, 5, 10, 5, 5, 14, 5, 23, 11, 7, 17, 18, 11, 9, - 14, 13, 11, 5, 7, 17, 14, + 6, 6, 6, 6, 6, 4, 6, + 8, 7, 4, 5, 10, 5, + 5, 14, 5, 23, + 11, 7, 17, 14, + 11, 9, 14, 13, + 11, 5, 7, 17, 14, + 8, 15, 16, 15, + 23, 24, 12, + 13, 13 }; +static_assert(array_elements(command_array) == PRIVILEGE_T_MAX_BIT + 1, + "The definition of command_array does not match privilege_t"); +static_assert(array_elements(command_lengths) == PRIVILEGE_T_MAX_BIT + 1, + "The definition of command_lengths does not match privilege_t"); + + static bool print_grants_for_role(THD *thd, ACL_ROLE * role) { char buff[1024]; @@ -9345,7 +9500,7 @@ static bool show_global_privileges(THD *thd, ACL_USER_BASE *acl_entry, char *buff, size_t buffsize) { uint counter; - ulong want_access; + privilege_t want_access(NO_ACL); Protocol *protocol= thd->protocol; String global(buff, buffsize, system_charset_info); @@ -9363,7 +9518,8 @@ static bool show_global_privileges(THD *thd, ACL_USER_BASE *acl_entry, else { bool found=0; - ulong j,test_access= want_access & ~GRANT_ACL; + ulonglong j; + privilege_t test_access(want_access & ~GRANT_ACL); for (counter=0, j = SELECT_ACL;j <= GLOBAL_ACLS;counter++,j <<= 1) { if (test_access & j) @@ -9412,7 +9568,7 @@ static bool show_database_privileges(THD *thd, const char *username, const char *hostname, char *buff, size_t buffsize) { - ulong want_access; + privilege_t want_access(NO_ACL); Protocol *protocol= thd->protocol; for (uint i=0 ; i < acl_dbs.elements() ; i++) @@ -9454,7 +9610,8 @@ static bool show_database_privileges(THD *thd, const char *username, else { int found=0, cnt; - ulong j,test_access= want_access & ~GRANT_ACL; + ulonglong j; + privilege_t test_access(want_access & ~GRANT_ACL); for (cnt=0, j = SELECT_ACL; j <= DB_ACLS; cnt++,j <<= 1) { if (test_access & j) @@ -9511,8 +9668,8 @@ static bool show_table_and_column_privileges(THD *thd, const char *username, if (!strcmp(username,user) && !my_strcasecmp(system_charset_info, hostname, host)) { - ulong table_access; - ulong cols_access; + privilege_t table_access(NO_ACL); + privilege_t cols_access(NO_ACL); if (*hostname) // User { table_access= grant_table->privs; @@ -9524,10 +9681,10 @@ static bool show_table_and_column_privileges(THD *thd, const char *username, cols_access= grant_table->init_cols; } - if ((table_access | cols_access) != 0) + if ((table_access | cols_access) != NO_ACL) { String global(buff, sizeof(buff), system_charset_info); - ulong test_access= (table_access | cols_access) & ~GRANT_ACL; + privilege_t test_access= (table_access | cols_access) & ~GRANT_ACL; global.length(0); global.append(STRING_WITH_LEN("GRANT ")); @@ -9540,7 +9697,7 @@ static bool show_table_and_column_privileges(THD *thd, const char *username, { /* Add specific column access */ int found= 0; - ulong j; + ulonglong j; for (counter= 0, j= SELECT_ACL; j <= TABLE_ACLS; counter++, j<<= 1) { @@ -9644,16 +9801,16 @@ static int show_routine_grants(THD* thd, if (!strcmp(username, user) && !my_strcasecmp(system_charset_info, hostname, host)) { - ulong proc_access; + privilege_t proc_access(NO_ACL); if (*hostname) // User proc_access= grant_proc->privs; else // Role proc_access= grant_proc->init_privs; - if (proc_access != 0) + if (proc_access != NO_ACL) { String global(buff, buffsize, system_charset_info); - ulong test_access= proc_access & ~GRANT_ACL; + privilege_t test_access(proc_access & ~GRANT_ACL); global.length(0); global.append(STRING_WITH_LEN("GRANT ")); @@ -9664,7 +9821,7 @@ static int show_routine_grants(THD* thd, { /* Add specific procedure access */ int found= 0; - ulong j; + ulonglong j; for (counter= 0, j= SELECT_ACL; j <= PROC_ACLS; counter++, j<<= 1) { @@ -9707,13 +9864,13 @@ static int show_routine_grants(THD* thd, Make a clear-text version of the requested privilege. */ -void get_privilege_desc(char *to, uint max_length, ulong access) +void get_privilege_desc(char *to, uint max_length, privilege_t access_arg) { uint pos; char *start=to; DBUG_ASSERT(max_length >= 30); // For end ', ' removal - if (access) + if (ulonglong access= access_arg) { max_length--; // Reserve place for end-zero for (pos=0 ; access ; pos++, access>>=1) @@ -10733,7 +10890,8 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list, bool handle_as_role) } } - if (replace_user_table(thd, tables.user_table(), user_name, 0, 0, 1, 0)) + if (replace_user_table(thd, tables.user_table(), user_name, + NO_ACL, 0, 1, 0)) { append_user(thd, &wrong_users, user_name); result= TRUE; @@ -10818,7 +10976,6 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list, bool handle_as_role) LEX_USER *user_name, *tmp_user_name; List_iterator <LEX_USER> user_list(list); bool binlog= false; - sql_mode_t old_sql_mode= thd->variables.sql_mode; DBUG_ENTER("mysql_drop_user"); DBUG_PRINT("entry", ("Handle as %s", handle_as_role ? "role" : "user")); @@ -10830,7 +10987,7 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list, bool handle_as_role) if ((result= tables.open_and_lock(thd, tables_to_open, TL_WRITE))) DBUG_RETURN(result != 1); - thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH; + Sql_mode_instant_remove sms(thd, MODE_PAD_CHAR_TO_FULL_LENGTH); mysql_rwlock_wrlock(&LOCK_grant); mysql_mutex_lock(&acl_cache->lock); @@ -10905,7 +11062,6 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list, bool handle_as_role) result |= write_bin_log(thd, FALSE, thd->query(), thd->query_length()); mysql_rwlock_unlock(&LOCK_grant); - thd->variables.sql_mode= old_sql_mode; DBUG_RETURN(result); } @@ -11037,8 +11193,9 @@ int mysql_alter_user(THD* thd, List<LEX_USER> &users_list) while ((tmp_lex_user= users_list_iterator++)) { LEX_USER* lex_user= get_current_user(thd, tmp_lex_user, false); - if (!lex_user || replace_user_table(thd, tables.user_table(), lex_user, 0, - false, false, true)) + if (!lex_user || + replace_user_table(thd, tables.user_table(), lex_user, NO_ACL, + false, false, true)) { thd->clear_error(); append_user(thd, &wrong_users, tmp_lex_user); @@ -11100,7 +11257,7 @@ mysql_revoke_sp_privs(THD *thd, Grant_tables *tables, const Sp_handler *sph, tables->procs_priv_table().table(), *lex_user, grant_proc->db, grant_proc->tname, - sph, ~(ulong)0, 1) == 0) + sph, ALL_KNOWN_ACL, 1) == 0) { revoked= 1; continue; @@ -11131,7 +11288,7 @@ mysql_revoke_sp_privs(THD *thd, Grant_tables *tables, const Sp_handler *sph, bool mysql_revoke_all(THD *thd, List <LEX_USER> &list) { uint counter, revoked; - int result, res; + int result; ACL_DB *acl_db; DBUG_ENTER("mysql_revoke_all"); @@ -11166,7 +11323,7 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list) } if (replace_user_table(thd, tables.user_table(), lex_user, - ~(ulong)0, 1, 0, 0)) + ALL_KNOWN_ACL, 1, 0, 0)) { result= -1; continue; @@ -11195,7 +11352,7 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list) /* TODO(cvicentiu) refactor replace_db_table to use Db_table instead of TABLE directly. */ if (!replace_db_table(tables.db_table().table(), acl_db->db, *lex_user, - ~(ulong)0, 1)) + ALL_KNOWN_ACL, 1)) { /* Don't increment counter as replace_db_table deleted the @@ -11215,31 +11372,30 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list) { for (counter= 0, revoked= 0 ; counter < column_priv_hash.records ; ) { - const char *user,*host; + const char *user,*host; GRANT_TABLE *grant_table= (GRANT_TABLE*) my_hash_element(&column_priv_hash, counter); user= grant_table->user; host= safe_str(grant_table->host.hostname); - if (!strcmp(lex_user->user.str,user) && + if (!strcmp(lex_user->user.str,user) && !strcmp(lex_user->host.str, host)) - { + { List<LEX_COLUMN> columns; - /* TODO(cvicentiu) refactor replace_db_table to use + /* TODO(cvicentiu) refactor to use Db_table instead of TABLE directly. */ if (replace_column_table(grant_table, tables.columns_priv_table().table(), - *lex_user, columns, grant_table->db, - grant_table->tname, ~(ulong)0, 1)) - result= -1; - - /* TODO(cvicentiu) refactor replace_db_table to use - Db_table instead of TABLE directly. */ - if ((res= replace_table_table(thd, grant_table, - tables.tables_priv_table().table(), - *lex_user, grant_table->db, - grant_table->tname, ~(ulong)0, 0, 1))) - { + *lex_user, columns, + grant_table->db, grant_table->tname, + ALL_KNOWN_ACL, 1)) + result= -1; + if (int res= replace_table_table(thd, grant_table, + tables.tables_priv_table().table(), + *lex_user, + grant_table->db, grant_table->tname, + ALL_KNOWN_ACL, NO_ACL, 1)) + { if (res > 0) result= -1; else @@ -11253,7 +11409,7 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list) } } } - counter++; + counter++; } } while (revoked); @@ -11443,7 +11599,7 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name, for (counter= 0, revoked= 0 ; counter < hash->records ; ) { GRANT_NAME *grant_proc= (GRANT_NAME*) my_hash_element(hash, counter); - if (!my_strcasecmp(&my_charset_utf8_bin, grant_proc->db, sp_db) && + if (!my_strcasecmp(&my_charset_utf8mb3_bin, grant_proc->db, sp_db) && !my_strcasecmp(system_charset_info, grant_proc->tname, sp_name)) { LEX_USER lex_user; @@ -11454,7 +11610,7 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name, if (replace_routine_table(thd, grant_proc, tables.procs_priv_table().table(), lex_user, grant_proc->db, grant_proc->tname, - sph, ~(ulong)0, 1) == 0) + sph, ALL_KNOWN_ACL, 1) == 0) { revoked= 1; continue; @@ -11788,10 +11944,231 @@ static int show_database_grants(THD *thd, SHOW_VAR *var, char *buff, #else static bool set_user_salt_if_needed(ACL_USER *, int, plugin_ref) { return 0; } -bool check_grant(THD *, ulong, TABLE_LIST *, bool, uint, bool) +bool check_grant(THD *, privilege_t, TABLE_LIST *, bool, uint, bool) { return 0; } #endif /*NO_EMBEDDED_ACCESS_CHECKS */ + +#ifdef NO_EMBEDDED_ACCESS_CHECKS + +bool Sql_cmd_grant_proxy::execute(THD *thd) +{ + my_ok(thd); + return false; +} + +bool Sql_cmd_grant_table::execute(THD *thd) +{ + my_ok(thd); + return false; +} + + +bool Sql_cmd_grant_sp::execute(THD *thd) +{ + my_ok(thd); + return false; +} + +#else // not NO_EMBEDDED_ACCESS_CHECKS + + +void Sql_cmd_grant::warn_hostname_requires_resolving(THD *thd, + List<LEX_USER> &users) +{ + LEX_USER *user; + List_iterator <LEX_USER> it(users); + while ((user= it++)) + { + if (specialflag & SPECIAL_NO_RESOLVE && + hostname_requires_resolving(user->host.str)) + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + ER_WARN_HOSTNAME_WONT_WORK, + ER_THD(thd, ER_WARN_HOSTNAME_WONT_WORK)); + } +} + + +void Sql_cmd_grant::grant_stage0(THD *thd) +{ + thd->binlog_invoker(false); // Replicate current user as grantor + if (thd->security_ctx->user) // If not replication + warn_hostname_requires_resolving(thd, thd->lex->users_list); +} + + +bool Sql_cmd_grant::user_list_reset_mqh(THD *thd, List<LEX_USER> &users) +{ + List_iterator <LEX_USER> it(users); + LEX_USER *user, *tmp_user; + while ((tmp_user= it++)) + { + if (!(user= get_current_user(thd, tmp_user))) + return true; + reset_mqh(user, 0); + } + return false; +} + + +bool Sql_cmd_grant_proxy::check_access_proxy(THD *thd, List<LEX_USER> &users) +{ + LEX_USER *user; + List_iterator <LEX_USER> it(users); + if ((user= it++)) + { + // GRANT/REVOKE PROXY has the target user as a first entry in the list + if (!(user= get_current_user(thd, user)) || !user->host.str) + return true; + if (acl_check_proxy_grant_access(thd, user->host.str, user->user.str, + m_grant_option & GRANT_ACL)) + return true; + } + return false; +} + + +bool Sql_cmd_grant_proxy::execute(THD *thd) +{ + LEX *lex= thd->lex; + + DBUG_ASSERT(lex->first_select_lex()->table_list.first == NULL); + DBUG_ASSERT((m_grant_option & ~GRANT_ACL) == NO_ACL); // only WITH GRANT OPTION + + grant_stage0(thd); + + if (thd->security_ctx->user /* If not replication */ && + check_access_proxy(thd, lex->users_list)) + return true; + + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); + /* Conditionally writes to binlog */ + if (mysql_grant(thd, NULL/*db*/, lex->users_list, m_grant_option, + is_revoke(), true/*proxy*/)) + return true; + + return !is_revoke() && user_list_reset_mqh(thd, lex->users_list); + +#ifdef WITH_WSREP +wsrep_error_label: + return true; +#endif // WITH_WSREP +} + + +bool Sql_cmd_grant_object::grant_stage0_exact_object(THD *thd, + TABLE_LIST *table) +{ + privilege_t priv= m_object_privilege | m_column_privilege_total | GRANT_ACL; + if (check_access(thd, priv, table->db.str, + &table->grant.privilege, &table->grant.m_internal, + 0, 0)) + return true; + grant_stage0(thd); + return false; +} + + +bool Sql_cmd_grant_table::execute_exact_table(THD *thd, TABLE_LIST *table) +{ + LEX *lex= thd->lex; + if (grant_stage0_exact_object(thd, table) || + check_grant(thd, m_object_privilege | m_column_privilege_total | GRANT_ACL, + lex->query_tables, FALSE, UINT_MAX, FALSE)) + return true; + /* Conditionally writes to binlog */ + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); + return mysql_table_grant(thd, lex->query_tables, lex->users_list, + m_columns, m_object_privilege, + is_revoke()); +#ifdef WITH_WSREP +wsrep_error_label: + return true; +#endif // WITH_WSREP +} + + +bool Sql_cmd_grant_sp::execute(THD *thd) +{ + DBUG_ASSERT(!m_columns.elements); + DBUG_ASSERT(!m_column_privilege_total); + LEX *lex= thd->lex; + TABLE_LIST *table= lex->first_select_lex()->table_list.first; + privilege_t grants= m_all_privileges + ? (PROC_ACLS & ~GRANT_ACL) | (m_object_privilege & GRANT_ACL) + : m_object_privilege; + + if (!table) // e.g: GRANT EXECUTE ON PROCEDURE *.* + { + my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER_THD(thd, ER_ILLEGAL_GRANT_FOR_TABLE), + MYF(0)); + return true; + } + + if (grant_stage0_exact_object(thd, table) || + check_grant_routine(thd, grants|GRANT_ACL, lex->query_tables, &m_sph, 0)) + return true; + + /* Conditionally writes to binlog */ + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); + if (mysql_routine_grant(thd, lex->query_tables, &m_sph, + lex->users_list, grants, + is_revoke(), true)) + return true; + my_ok(thd); + return false; +#ifdef WITH_WSREP +wsrep_error_label: + return true; +#endif // WITH_WSREP +} + + +bool Sql_cmd_grant_table::execute_table_mask(THD *thd) +{ + LEX *lex= thd->lex; + DBUG_ASSERT(lex->first_select_lex()->table_list.first == NULL); + + if (check_access(thd, m_object_privilege | m_column_privilege_total | GRANT_ACL, + m_db.str, NULL, NULL, 1, 0)) + return true; + + grant_stage0(thd); + + if (m_columns.elements) // e.g. GRANT SELECT (a) ON *.* + { + my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER_THD(thd, ER_ILLEGAL_GRANT_FOR_TABLE), + MYF(0)); + return true; + } + + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); + /* Conditionally writes to binlog */ + if (mysql_grant(thd, m_db.str, lex->users_list, m_object_privilege, + is_revoke(), false/*not proxy*/)) + return true; + + return !is_revoke() && user_list_reset_mqh(thd, lex->users_list); + +#ifdef WITH_WSREP +wsrep_error_label: + return true; +#endif // WITH_WSREP +} + + +bool Sql_cmd_grant_table::execute(THD *thd) +{ + TABLE_LIST *table= thd->lex->first_select_lex()->table_list.first; + return table ? execute_exact_table(thd, table) : + execute_table_mask(thd); +} + + +#endif // NO_EMBEDDED_ACCESS_CHECKS + + + SHOW_VAR acl_statistics[] = { #ifndef NO_EMBEDDED_ACCESS_CHECKS {"column_grants", (char*)show_column_grants, SHOW_SIMPLE_FUNC}, @@ -11998,7 +12375,6 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond) int error= 0; uint counter; ACL_USER *acl_user; - ulong want_access; TABLE *table= tables->table; bool no_global_access= check_access(thd, SELECT_ACL, "mysql", NULL, NULL, 1, 1); @@ -12019,7 +12395,7 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond) !thd->security_ctx->is_priv_user(user, host)) continue; - want_access= acl_user->access; + privilege_t want_access(acl_user->access); if (!(want_access & GRANT_ACL)) is_grantable= "NO"; @@ -12036,7 +12412,8 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond) else { uint priv_id; - ulong j,test_access= want_access & ~GRANT_ACL; + ulonglong j; + privilege_t test_access(want_access & ~GRANT_ACL); for (priv_id=0, j = SELECT_ACL;j <= GLOBAL_ACLS; priv_id++,j <<= 1) { if (test_access & j) @@ -12068,7 +12445,6 @@ int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond) int error= 0; uint counter; ACL_DB *acl_db; - ulong want_access; TABLE *table= tables->table; bool no_global_access= check_access(thd, SELECT_ACL, "mysql", NULL, NULL, 1, 1); @@ -12090,7 +12466,7 @@ int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond) !thd->security_ctx->is_priv_user(user, host)) continue; - want_access=acl_db->access; + privilege_t want_access(acl_db->access); if (want_access) { if (!(want_access & GRANT_ACL)) @@ -12110,7 +12486,8 @@ int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond) else { int cnt; - ulong j,test_access= want_access & ~GRANT_ACL; + ulonglong j; + privilege_t test_access(want_access & ~GRANT_ACL); for (cnt=0, j = SELECT_ACL; j <= DB_ACLS; cnt++,j <<= 1) if (test_access & j) { @@ -12160,10 +12537,10 @@ int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond) !thd->security_ctx->is_priv_user(user, host)) continue; - ulong table_access= grant_table->privs; + privilege_t table_access(grant_table->privs); if (table_access) { - ulong test_access= table_access & ~GRANT_ACL; + privilege_t test_access(table_access & ~GRANT_ACL); /* We should skip 'usage' privilege on table if we have any privileges on column(s) of this table @@ -12187,7 +12564,7 @@ int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond) } else { - ulong j; + ulonglong j; int cnt; for (cnt= 0, j= SELECT_ACL; j <= TABLE_ACLS; cnt++, j<<= 1) { @@ -12241,19 +12618,19 @@ int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond) !thd->security_ctx->is_priv_user(user, host)) continue; - ulong table_access= grant_table->cols; - if (table_access != 0) + privilege_t table_access(grant_table->cols); + if (table_access != NO_ACL) { if (!(grant_table->privs & GRANT_ACL)) is_grantable= "NO"; - ulong test_access= table_access & ~GRANT_ACL; + privilege_t test_access(table_access & ~GRANT_ACL); Grantee_str grantee(user, host); if (!test_access) continue; else { - ulong j; + ulonglong j; int cnt; for (cnt= 0, j= SELECT_ACL; j <= TABLE_ACLS; cnt++, j<<= 1) { @@ -12319,8 +12696,8 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant, if (!initialized) { DBUG_PRINT("info", ("skip grants")); - grant->privilege= ~NO_ACCESS; // everything is allowed - DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege)); + grant->privilege= ALL_KNOWN_ACL; // everything is allowed + DBUG_PRINT("info", ("privilege 0x%llx", (longlong) grant->privilege)); DBUG_VOID_RETURN; } @@ -12364,7 +12741,7 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant, } mysql_rwlock_unlock(&LOCK_grant); - DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege)); + DBUG_PRINT("info", ("privilege 0x%llx", (longlong) grant->privilege)); DBUG_VOID_RETURN; } @@ -12866,7 +13243,7 @@ static bool send_plugin_request_packet(MPVIO_EXT *mpvio, static bool ignore_max_password_errors(const ACL_USER *acl_user) { const char *host= acl_user->host.hostname; - return (acl_user->access & SUPER_ACL) + return (acl_user->access & PRIV_IGNORE_MAX_PASSWORD_ERRORS) && (!strcasecmp(host, "localhost") || !strcmp(host, "127.0.0.1") || !strcmp(host, "::1")); @@ -12909,7 +13286,7 @@ static bool find_mpvio_user(MPVIO_EXT *mpvio) */ ulong nr1=1, nr2=4; CHARSET_INFO *cs= &my_charset_latin1; - cs->coll->hash_sort(cs, (uchar*) sctx->user, strlen(sctx->user), &nr1, &nr2); + cs->hash_sort((uchar*) sctx->user, strlen(sctx->user), &nr1, &nr2); mysql_mutex_lock(&acl_cache->lock); if (!acl_users.elements) @@ -13054,7 +13431,8 @@ static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length) system_charset_info, user, user_len, thd->charset(), &dummy_errors); - if (!(sctx->user= my_strndup(user_buff, user_len, MYF(MY_WME)))) + if (!(sctx->user= my_strndup(key_memory_MPVIO_EXT_auth_info, user_buff, + user_len, MYF(MY_WME)))) DBUG_RETURN(1); /* Clear variables that are allocated */ @@ -13313,8 +13691,8 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio, Security_context *sctx= thd->security_ctx; - my_free((char*) sctx->user); - if (!(sctx->user= my_strndup(user, user_len, MYF(MY_WME)))) + my_free(const_cast<char*>(sctx->user)); + if (!(sctx->user= my_strndup(key_memory_MPVIO_EXT_auth_info, user, user_len, MYF(MY_WME)))) return packet_error; /* The error is set by my_strdup(). */ @@ -13576,8 +13954,8 @@ static void server_mpvio_info(MYSQL_PLUGIN_VIO *vio, static bool acl_check_ssl(THD *thd, const ACL_USER *acl_user) { -#ifdef HAVE_OPENSSL Vio *vio= thd->net.vio; +#ifdef HAVE_OPENSSL SSL *ssl= (SSL *) vio->ssl_arg; X509 *cert; #endif @@ -13591,6 +13969,24 @@ static bool acl_check_ssl(THD *thd, const ACL_USER *acl_user) switch (acl_user->ssl_type) { case SSL_TYPE_NOT_SPECIFIED: // Impossible case SSL_TYPE_NONE: // SSL is not required + if (opt_require_secure_transport) + { + enum enum_vio_type type= vio_type(vio); +#ifdef HAVE_OPENSSL + return type != VIO_TYPE_SSL && +#ifndef _WIN32 + type != VIO_TYPE_SOCKET; +#else + type != VIO_TYPE_NAMEDPIPE; +#endif +#else +#ifndef _WIN32 + return type != VIO_TYPE_SOCKET; +#else + return type != VIO_TYPE_NAMEDPIPE; +#endif +#endif + } return 0; #ifdef HAVE_OPENSSL case SSL_TYPE_ANY: // Any kind of SSL is ok @@ -13845,6 +14241,8 @@ bool acl_authenticate(THD *thd, uint com_change_user_pkt_len) res= do_auth_once(thd, default_auth_plugin_name, &mpvio); } + PSI_CALL_set_connection_type(vio_type(thd->net.vio)); + Security_context * const sctx= thd->security_ctx; const ACL_USER * acl_user= mpvio.acl_user; if (!acl_user) @@ -13882,17 +14280,9 @@ bool acl_authenticate(THD *thd, uint com_change_user_pkt_len) */ if (sctx->user) { - if (strcmp(sctx->priv_user, sctx->user)) - { - general_log_print(thd, command, "%s@%s as %s on %s", - sctx->user, sctx->host_or_ip, - sctx->priv_user[0] ? sctx->priv_user : "anonymous", - safe_str(mpvio.db.str)); - } - else - general_log_print(thd, command, (char*) "%s@%s on %s", - sctx->user, sctx->host_or_ip, - safe_str(mpvio.db.str)); + general_log_print(thd, command, (char*) "%s@%s on %s using %s", + sctx->user, sctx->host_or_ip, + safe_str(mpvio.db.str), safe_vio_type_name(thd->net.vio)); } if (res > CR_OK && mpvio.status != MPVIO_EXT::SUCCESS) @@ -14067,20 +14457,16 @@ bool acl_authenticate(THD *thd, uint com_change_user_pkt_len) DBUG_PRINT("info", ("Capabilities: %llu packet_length: %ld Host: '%s' " "Login user: '%s' Priv_user: '%s' Using password: %s " - "Access: %lu db: '%s'", + "Access: %llx db: '%s'", thd->client_capabilities, thd->max_client_packet_length, sctx->host_or_ip, sctx->user, sctx->priv_user, thd->password ? "yes": "no", - sctx->master_access, mpvio.db.str)); + (longlong) sctx->master_access, mpvio.db.str)); if (command == COM_CONNECT && - !(thd->main_security_ctx.master_access & SUPER_ACL)) + !(thd->main_security_ctx.master_access & PRIV_IGNORE_MAX_CONNECTIONS)) { - mysql_mutex_lock(&LOCK_connection_count); - bool count_ok= (*thd->scheduler->connection_count <= - *thd->scheduler->max_connections); - mysql_mutex_unlock(&LOCK_connection_count); - if (!count_ok) + if (*thd->scheduler->connection_count > *thd->scheduler->max_connections) { // too many connections my_error(ER_CON_COUNT_ERROR, MYF(0)); DBUG_RETURN(1); @@ -14092,14 +14478,14 @@ bool acl_authenticate(THD *thd, uint com_change_user_pkt_len) set to 0 here because we don't have an active database yet (and we may not have an active database to set. */ - sctx->db_access=0; + sctx->db_access= NO_ACL; #ifndef NO_EMBEDDED_ACCESS_CHECKS /* In case the user has a default role set, attempt to set that role */ if (initialized && acl_user->default_rolename.length) { - ulonglong access= 0; + privilege_t access(NO_ACL); int result; result= acl_check_setrole(thd, acl_user->default_rolename.str, &access); if (!result) @@ -14140,16 +14526,17 @@ bool acl_authenticate(THD *thd, uint com_change_user_pkt_len) thd->net.net_skip_rest_factor= 2; // skip at most 2*max_packet_size if (mpvio.auth_info.external_user[0]) - sctx->external_user= my_strdup(mpvio.auth_info.external_user, MYF(0)); + sctx->external_user= my_strdup(key_memory_MPVIO_EXT_auth_info, + mpvio.auth_info.external_user, MYF(0)); if (res == CR_OK_HANDSHAKE_COMPLETE) thd->get_stmt_da()->disable_status(); else my_ok(thd); - PSI_CALL_set_thread_user_host - (thd->main_security_ctx.user, (uint)strlen(thd->main_security_ctx.user), - thd->main_security_ctx.host_or_ip, (uint)strlen(thd->main_security_ctx.host_or_ip)); + PSI_CALL_set_thread_account + (thd->main_security_ctx.user, static_cast<uint>(strlen(thd->main_security_ctx.user)), + thd->main_security_ctx.host_or_ip, static_cast<uint>(strlen(thd->main_security_ctx.host_or_ip))); /* Ready to handle queries */ DBUG_RETURN(0); @@ -14440,3 +14827,40 @@ maria_declare_plugin(mysql_password) MariaDB_PLUGIN_MATURITY_STABLE /* Maturity */ } maria_declare_plugin_end; + + +/* + Exporting functions that allow plugins to do server-style + host/user matching. Used in server_audit2 plugin. +*/ +extern "C" int maria_compare_hostname( + const char *wild_host, long wild_ip, long ip_mask, + const char *host, const char *ip) +{ +#ifndef NO_EMBEDDED_ACCESS_CHECKS + acl_host_and_ip h; + h.hostname= (char *) wild_host; + h.ip= wild_ip; + h.ip_mask= ip_mask; + + return compare_hostname(&h, host, ip); +#else + return 0; +#endif +} + + +extern "C" void maria_update_hostname( + const char **wild_host, long *wild_ip, long *ip_mask, + const char *host) +{ +#ifndef NO_EMBEDDED_ACCESS_CHECKS + acl_host_and_ip h; + update_hostname(&h, host); + *wild_host= h.hostname; + *wild_ip= h.ip; + *ip_mask= h.ip_mask; +#endif +} + + |