From a2a2e32c02643a0cec111511220227703fda1cd5 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 1 Jul 2024 20:15:00 +0200 Subject: Merging upstream version 1:11.4.2. Signed-off-by: Daniel Baumann --- sql/sql_acl.cc | 222 +++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 138 insertions(+), 84 deletions(-) (limited to 'sql/sql_acl.cc') diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 0fbf11ce..8806462b 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -201,15 +201,11 @@ public: }; -class ACL_USER :public ACL_USER_BASE, - public ACL_USER_PARAM +class ACL_USER :public ACL_USER_BASE, public ACL_USER_PARAM { public: - ACL_USER() = default; - ACL_USER(THD *thd, const LEX_USER &combo, - const Account_options &options, - const privilege_t privileges); + ACL_USER(THD *, const LEX_USER &, const Account_options &, const privilege_t); ACL_USER *copy(MEM_ROOT *root) { @@ -1059,7 +1055,7 @@ class User_table_tabular: public User_table access|= DELETE_HISTORY_ACL; if (access & SUPER_ACL) - access|= GLOBAL_SUPER_ADDED_SINCE_USER_TABLE_ACLS; + access|= ALLOWED_BY_SUPER_BEFORE_101100 | ALLOWED_BY_SUPER_BEFORE_110000; /* The SHOW SLAVE HOSTS statement : @@ -1075,6 +1071,9 @@ class User_table_tabular: public User_table if (access & REPL_SLAVE_ACL) access|= SLAVE_MONITOR_ACL; + if ((access & ALL_KNOWN_ACL_100304) == ALL_KNOWN_ACL_100304) + access|= SHOW_CREATE_ROUTINE_ACL; + return access & GLOBAL_ACLS; } @@ -1546,12 +1545,21 @@ class User_table_json: public User_table { privilege_t mask= ALL_KNOWN_ACL_100304; ulonglong orig_access= access; + if (version_id < 110000) + { + if (access & SUPER_ACL) + access|= ALLOWED_BY_SUPER_BEFORE_110000; + } if (version_id < 101100) { if (access & SUPER_ACL) - access|= READ_ONLY_ADMIN_ACL; + access|= ALLOWED_BY_SUPER_BEFORE_101100; } - if (version_id >= 100509) + if (version_id >= 110300) + { + mask= ALL_KNOWN_ACL_110300; + } + else if (version_id >= 100509) { mask= ALL_KNOWN_ACL_100509; } @@ -1566,26 +1574,6 @@ class User_table_json: public User_table } 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 @@ -1599,6 +1587,11 @@ class User_table_json: public User_table print_warning_bad_access(version_id, mask, orig_access); return NO_ACL; } + + // ALL PRIVILEGES always means ALL PRIVILEGES + if ((orig_access & mask) == mask) + access= ALL_KNOWN_ACL; + return access & ALL_KNOWN_ACL; } @@ -2542,6 +2535,8 @@ bool acl_init(bool dont_read_acl_tables) DBUG_RETURN(1); /* purecov: inspected */ thd->thread_stack= (char*) &thd; thd->store_globals(); + thd->set_query_inner((char*) STRING_WITH_LEN("intern:acl_init"), + default_charset_info); /* It is safe to call acl_reload() since acl_* arrays and hashes which will be freed there are global static objects and thus are initialized @@ -2798,6 +2793,9 @@ static bool acl_load(THD *thd, const Grant_tables& tables) db.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL; } #endif + if (db_table.num_fields() <= 23) + if ((db.access | SHOW_CREATE_ROUTINE_ACL | GRANT_ACL) == DB_ACLS) + db.access|= SHOW_CREATE_ROUTINE_ACL; acl_dbs.push(db); } end_read_record(&read_record_info); @@ -5053,6 +5051,9 @@ static int replace_db_table(TABLE *table, const char *db, } rights=get_access(table,3); rights=fix_rights_for_db(rights); + if (table->s->fields <= 23) + if ((rights | SHOW_CREATE_ROUTINE_ACL | GRANT_ACL) == DB_ACLS) + rights|= SHOW_CREATE_ROUTINE_ACL; if (old_row_exists) { @@ -7894,31 +7895,30 @@ bool mysql_grant_role(THD *thd, List &list, bool revoke) } -bool mysql_grant(THD *thd, const char *db, List &list, +static +bool mysql_grant(THD *thd, LEX_CSTRING db, List &list, privilege_t rights, bool revoke_grant, bool is_proxy) { List_iterator str_list (list); LEX_USER *Str, *tmp_Str, *proxied_user= NULL; - char tmp_db[SAFE_NAME_LEN+1]; + IdentBuffer tmp_db; bool create_new_users=0; int result; DBUG_ENTER("mysql_grant"); - if (lower_case_table_names && db) + if (lower_case_table_names && db.str) { - char *end= strnmov(tmp_db,db, sizeof(tmp_db)); - if (end >= tmp_db + sizeof(tmp_db)) + if (tmp_db.copy_casedn(db).length() > SAFE_NAME_LEN) { - my_error(ER_WRONG_DB_NAME ,MYF(0), db); + my_error(ER_WRONG_DB_NAME ,MYF(0), db.str); DBUG_RETURN(TRUE); } - my_casedn_str(files_charset_info, tmp_db); - db=tmp_db; + db= tmp_db.to_lex_cstring(); } if (is_proxy) { - DBUG_ASSERT(!db); + DBUG_ASSERT(!db.str); proxied_user= str_list++; } @@ -7954,20 +7954,20 @@ bool mysql_grant(THD *thd, const char *db, List &list, if (copy_and_check_auth(Str, tmp_Str, thd) || replace_user_table(thd, tables.user_table(), Str, - (!db ? rights : NO_ACL), + (!db.str ? rights : NO_ACL), revoke_grant, create_new_users, MY_TEST(!is_public(Str) && (thd->variables.sql_mode & MODE_NO_AUTO_CREATE_USER)))) result= true; - else if (db) + else if (db.str) { privilege_t db_rights(rights & DB_ACLS); if (db_rights == rights) { - if (replace_db_table(tables.db_table().table(), db, *Str, db_rights, - revoke_grant)) - result= true; + if (replace_db_table(tables.db_table().table(), db.str, + *Str, db_rights, revoke_grant)) + result= true; } else { @@ -7983,8 +7983,9 @@ bool mysql_grant(THD *thd, const char *db, List &list, } if (Str->is_role()) propagate_role_grants(find_acl_role(Str->user.str, true), - db ? PRIVS_TO_MERGE::DB : PRIVS_TO_MERGE::GLOBAL, - db); + db.str ? PRIVS_TO_MERGE::DB : + PRIVS_TO_MERGE::GLOBAL, + db.str); } mysql_mutex_unlock(&acl_cache->lock); @@ -8036,6 +8037,9 @@ bool grant_init() DBUG_RETURN(1); /* purecov: deadcode */ thd->thread_stack= (char*) &thd; thd->store_globals(); + thd->set_query_inner((char*) STRING_WITH_LEN("intern:grant_init"), + default_charset_info); + return_val= grant_reload(thd); delete thd; DBUG_RETURN(return_val); @@ -9021,7 +9025,8 @@ err: 1 error */ -bool check_routine_level_acl(THD *thd, const char *db, const char *name, +bool check_routine_level_acl(THD *thd, privilege_t acl, + const char *db, const char *name, const Sp_handler *sph) { bool no_routine_acl= 1; @@ -9032,7 +9037,7 @@ bool check_routine_level_acl(THD *thd, const char *db, const char *name, sctx->ip, db, sctx->priv_user, name, sph, 0))) - no_routine_acl= !(grant_proc->privs & SHOW_PROC_ACLS); + no_routine_acl= !(grant_proc->privs & acl); if (no_routine_acl && sctx->priv_role[0]) /* current set role check */ { @@ -9040,7 +9045,7 @@ bool check_routine_level_acl(THD *thd, const char *db, const char *name, NULL, db, sctx->priv_role, name, sph, 0))) - no_routine_acl= !(grant_proc->privs & SHOW_PROC_ACLS); + no_routine_acl= !(grant_proc->privs & SHOW_PROC_WITHOUT_DEFINITION_ACLS); } mysql_rwlock_unlock(&LOCK_grant); return no_routine_acl; @@ -9274,7 +9279,7 @@ static const char *command_array[]= "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" + "BINLOG REPLAY", "SLAVE MONITOR", "SHOW CREATE ROUTINE" }; static uint command_lengths[]= @@ -9287,7 +9292,7 @@ static uint command_lengths[]= 11, 5, 7, 17, 14, 8, 15, 16, 15, 23, 24, 12, - 13, 13 + 13, 13, 19 }; @@ -12210,6 +12215,9 @@ bool check_grant(THD *, privilege_t, TABLE_LIST *, bool, uint, bool) { return 0; } inline privilege_t public_access() { return NO_ACL; } +privilege_t get_column_grant(THD *, GRANT_INFO *, + const char *, const char *, const char *) +{ return ALL_KNOWN_ACL; } #endif /*NO_EMBEDDED_ACCESS_CHECKS */ @@ -12306,7 +12314,7 @@ bool Sql_cmd_grant_proxy::execute(THD *thd) 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, + if (mysql_grant(thd, null_clex_str/*db*/, lex->users_list, m_grant_option, is_revoke(), true/*proxy*/)) return true; @@ -12407,7 +12415,7 @@ bool Sql_cmd_grant_table::execute_table_mask(THD *thd) 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, + if (mysql_grant(thd, m_db, lex->users_list, m_object_privilege, is_revoke(), false/*not proxy*/)) return true; @@ -13003,7 +13011,8 @@ void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant, Dummy wrappers when we don't have any access checks ****************************************************************************/ -bool check_routine_level_acl(THD *thd, const char *db, const char *name, +bool check_routine_level_acl(THD *thd, privilege_t acl, + const char *db, const char *name, const Sp_handler *sph) { return FALSE; @@ -13335,12 +13344,7 @@ static bool send_server_handshake_packet(MPVIO_EXT *mpvio, data_len= SCRAMBLE_LENGTH; } - /* When server version is specified in config file, don't include - the replication hack prefix. */ - if (using_custom_server_version) - end= strnmov(end, server_version, SERVER_VERSION_LENGTH) + 1; - else - end= strxnmov(end, SERVER_VERSION_LENGTH, RPL_VERSION_HACK, server_version, NullS) + 1; + end= strnmov(end, server_version, SERVER_VERSION_LENGTH) + 1; int4store((uchar*) end, mpvio->auth_info.thd->thread_id); end+= 4; @@ -13821,6 +13825,34 @@ static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length) } +#ifndef EMBEDDED_LIBRARY +/** + Check that a client uses secure connection type in case the option + require_secure_transport is on. + + @param thd thread handle + + @return true in case the option require_secure_transport is on and the client + uses euther named pipe or unix socket or ssl, else return false +*/ + +static bool check_require_secured_transport(THD *thd) +{ + Vio *vio= thd->net.vio; + if (opt_require_secure_transport) + { + enum enum_vio_type type= vio_type(vio); + + return + (type != VIO_TYPE_SSL) && + (type != VIO_TYPE_NAMEDPIPE) && + (type != VIO_TYPE_SOCKET); + } + return 0; +} +#endif + + /* the packet format is described in send_client_reply_packet() */ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio, uchar **buff, ulong pkt_len) @@ -13890,6 +13922,22 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio, return packet_error; } } + /* + Check whether the option require_secure_transport is on and in case + it is true that the secured connection type is used, that is either + unix socket or named pipe or ssl is in use. + */ + else if (check_require_secured_transport(thd)) + { + Host_errors errors; + + errors.m_ssl= 1; + inc_host_errors(mpvio->auth_info.thd->security_ctx->ip, &errors); + status_var_increment(thd->status_var.access_denied_errors); + my_error(ER_SECURE_TRANSPORT_REQUIRED, MYF(0)); + + return packet_error; + } if (client_capabilities & CLIENT_PROTOCOL_41) { @@ -14263,8 +14311,8 @@ static void server_mpvio_info(MYSQL_PLUGIN_VIO *vio, static bool acl_check_ssl(THD *thd, const ACL_USER *acl_user) { - Vio *vio= thd->net.vio; #ifdef HAVE_OPENSSL + Vio *vio= thd->net.vio; SSL *ssl= (SSL *) vio->ssl_arg; X509 *cert; #endif @@ -14276,26 +14324,8 @@ static bool acl_check_ssl(THD *thd, const ACL_USER *acl_user) if X509 certificate attributes are OK */ 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 - } + case SSL_TYPE_NOT_SPECIFIED: // Impossible + case SSL_TYPE_NONE: // SSL is not required FOR THIS SPECIFIC USER return 0; #ifdef HAVE_OPENSSL case SSL_TYPE_ANY: // Any kind of SSL is ok @@ -14388,6 +14418,29 @@ static bool acl_check_ssl(THD *thd, const ACL_USER *acl_user) return 1; } +static void make_ssl_info(THD *thd, LEX_CSTRING salt, char *info) +{ +#ifdef HAVE_OPENSSL + uchar digest[256/8]; + if (!salt.length) + return; + + /* + mark that it's after-auth mysql->info version 1. + meaning, it contains sha2(salt, scramble, sha2_cert_fingerprint) + encoded in 64 lowercase letters 'a'..'p', one letter per 4 bits (0..15) + */ + *info++= 1; // Version 1 + + DBUG_ASSERT(thd->scramble[SCRAMBLE_LENGTH] == 0); + + LEX_CUSTRING fp= ssl_acceptor_fingerprint(); + my_sha256_multi(digest, salt.str, salt.length, thd->scramble, + (size_t)SCRAMBLE_LENGTH, fp.str, fp.length, NULL); + octet2hex(info, digest, sizeof(digest)); + +#endif +} static int do_auth_once(THD *thd, const LEX_CSTRING *auth_plugin_name, MPVIO_EXT *mpvio) @@ -14505,6 +14558,7 @@ bool acl_authenticate(THD *thd, uint com_change_user_pkt_len) { int res= CR_OK; MPVIO_EXT mpvio; + char ssl_info[256/4 + 2]= {0}; // '\1', SHA256 (1 char per 4 bits), '\0' enum enum_server_command command= com_change_user_pkt_len ? COM_CHANGE_USER : COM_CONNECT; DBUG_ENTER("acl_authenticate"); @@ -14842,10 +14896,10 @@ bool acl_authenticate(THD *thd, uint com_change_user_pkt_len) 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); + if (initialized && !com_change_user_pkt_len) + make_ssl_info(thd, acl_user->auth[mpvio.curr_auth-1].salt, ssl_info); + + my_ok(thd, 0, 0, ssl_info[0] == '\1' ? ssl_info : NULL); PSI_CALL_set_thread_account (thd->main_security_ctx.user, static_cast(strlen(thd->main_security_ctx.user)), -- cgit v1.2.3