diff --git a/mysql-test/r/dd_is_compatibility_ci.result b/mysql-test/r/dd_is_compatibility_ci.result index 24017215b245..e99498dd4b70 100644 --- a/mysql-test/r/dd_is_compatibility_ci.result +++ b/mysql-test/r/dd_is_compatibility_ci.result @@ -155,6 +155,7 @@ SELECT * FROM v1; table_name ADMINISTRABLE_ROLE_AUTHORIZATIONS APPLICABLE_ROLES +AUTHINFO CHARACTER_SETS CHECK_CONSTRAINTS COLLATIONS diff --git a/mysql-test/r/dd_is_compatibility_cs.result b/mysql-test/r/dd_is_compatibility_cs.result index f32805c1b0b5..6cdec201341a 100644 --- a/mysql-test/r/dd_is_compatibility_cs.result +++ b/mysql-test/r/dd_is_compatibility_cs.result @@ -155,6 +155,7 @@ SELECT * FROM v1; table_name ADMINISTRABLE_ROLE_AUTHORIZATIONS APPLICABLE_ROLES +AUTHINFO CHARACTER_SETS CHECK_CONSTRAINTS COLLATIONS diff --git a/mysql-test/r/information_schema_authinfo.result b/mysql-test/r/information_schema_authinfo.result new file mode 100644 index 000000000000..92491a82a1fd --- /dev/null +++ b/mysql-test/r/information_schema_authinfo.result @@ -0,0 +1,6 @@ +# +# Test case for information_schema.authinfo table +# (SSL connection) +# +include/assert.inc [SSL field for the current connection must be set to 1] +include/assert.inc [Info field (peer certificate) for the current connection must be non-empty] diff --git a/mysql-test/r/information_schema_authinfo_nossl.result b/mysql-test/r/information_schema_authinfo_nossl.result new file mode 100644 index 000000000000..dc8f6befd719 --- /dev/null +++ b/mysql-test/r/information_schema_authinfo_nossl.result @@ -0,0 +1,6 @@ +# +# Test case for information_schema.authinfo table +# (non-SSL connection) +# +include/assert.inc [SSL field for the current connection must be set to 0] +include/assert.inc [Info field (peer certificate) for the current connection must be NULL] diff --git a/mysql-test/r/information_schema_ci.result b/mysql-test/r/information_schema_ci.result index 383228b1159d..26c21a9362ba 100644 --- a/mysql-test/r/information_schema_ci.result +++ b/mysql-test/r/information_schema_ci.result @@ -63,6 +63,7 @@ select * from v1; c ADMINISTRABLE_ROLE_AUTHORIZATIONS APPLICABLE_ROLES +AUTHINFO CHARACTER_SETS CHECK_CONSTRAINTS COLLATIONS @@ -895,7 +896,7 @@ table_schema IN ('mysql', 'information_schema', 'test', 'mysqltest') AND table_name not like 'ndb%' AND table_name COLLATE utf8_general_ci not like 'innodb_%' GROUP BY TABLE_SCHEMA; TABLE_SCHEMA count(*) -information_schema 49 +information_schema 50 mysql 35 create table t1 (i int, j int); create trigger trg1 before insert on t1 for each row @@ -1348,6 +1349,7 @@ group by t.table_name order by num1, t.table_name COLLATE utf8_general_ci; TABLE_NAME group_concat(t.table_schema, '.', t.table_name) num1 ADMINISTRABLE_ROLE_AUTHORIZATIONS information_schema.ADMINISTRABLE_ROLE_AUTHORIZATIONS 1 APPLICABLE_ROLES information_schema.APPLICABLE_ROLES 1 +AUTHINFO information_schema.AUTHINFO 1 CHARACTER_SETS information_schema.CHARACTER_SETS 1 CHECK_CONSTRAINTS information_schema.CHECK_CONSTRAINTS 1 COLLATIONS information_schema.COLLATIONS 1 @@ -2489,6 +2491,7 @@ c1.column_name COLLATE utf8mb3_general_ci; TABLE_NAME COLUMN_NAME ADMINISTRABLE_ROLE_AUTHORIZATIONS USER APPLICABLE_ROLES USER +AUTHINFO ID CHARACTER_SETS CHARACTER_SET_NAME CHECK_CONSTRAINTS CONSTRAINT_SCHEMA COLLATIONS COLLATION_NAME @@ -2558,6 +2561,7 @@ c1.column_name COLLATE utf8mb3_general_ci; TABLE_NAME COLUMN_NAME ADMINISTRABLE_ROLE_AUTHORIZATIONS USER APPLICABLE_ROLES USER +AUTHINFO ID CHARACTER_SETS CHARACTER_SET_NAME CHECK_CONSTRAINTS CONSTRAINT_SCHEMA COLLATIONS COLLATION_NAME diff --git a/mysql-test/r/information_schema_cs.result b/mysql-test/r/information_schema_cs.result index 26e7ce55c8f5..5824f73bfd14 100644 --- a/mysql-test/r/information_schema_cs.result +++ b/mysql-test/r/information_schema_cs.result @@ -63,6 +63,7 @@ select * from v1; c ADMINISTRABLE_ROLE_AUTHORIZATIONS APPLICABLE_ROLES +AUTHINFO CHARACTER_SETS CHECK_CONSTRAINTS COLLATIONS @@ -899,7 +900,7 @@ AND table_name COLLATE utf8mb3_general_ci not like 'innodb_%' AND table_name COLLATE utf8mb3_general_ci not like 'rocksdb_%' GROUP BY TABLE_SCHEMA; TABLE_SCHEMA count(*) -information_schema 49 +information_schema 50 mysql 35 create table t1 (i int, j int); create trigger trg1 before insert on t1 for each row @@ -1353,6 +1354,7 @@ group by t.table_name order by num1, t.table_name COLLATE utf8mb3_general_ci; TABLE_NAME group_concat(t.table_schema, '.', t.table_name) num1 ADMINISTRABLE_ROLE_AUTHORIZATIONS information_schema.ADMINISTRABLE_ROLE_AUTHORIZATIONS 1 APPLICABLE_ROLES information_schema.APPLICABLE_ROLES 1 +AUTHINFO information_schema.AUTHINFO 1 CHARACTER_SETS information_schema.CHARACTER_SETS 1 CHECK_CONSTRAINTS information_schema.CHECK_CONSTRAINTS 1 COLLATIONS information_schema.COLLATIONS 1 @@ -2494,6 +2496,7 @@ c1.column_name COLLATE utf8mb3_general_ci; TABLE_NAME COLUMN_NAME ADMINISTRABLE_ROLE_AUTHORIZATIONS USER APPLICABLE_ROLES USER +AUTHINFO ID CHARACTER_SETS CHARACTER_SET_NAME CHECK_CONSTRAINTS CONSTRAINT_SCHEMA COLLATIONS COLLATION_NAME @@ -2563,6 +2566,7 @@ c1.column_name COLLATE utf8mb3_general_ci; TABLE_NAME COLUMN_NAME ADMINISTRABLE_ROLE_AUTHORIZATIONS USER APPLICABLE_ROLES USER +AUTHINFO ID CHARACTER_SETS CHARACTER_SET_NAME CHECK_CONSTRAINTS CONSTRAINT_SCHEMA COLLATIONS COLLATION_NAME diff --git a/mysql-test/r/mysqlshow_ci.result b/mysql-test/r/mysqlshow_ci.result index 5916513b6e65..daf1692d67de 100644 --- a/mysql-test/r/mysqlshow_ci.result +++ b/mysql-test/r/mysqlshow_ci.result @@ -81,6 +81,7 @@ Database: information_schema +---------------------------------------+ | ADMINISTRABLE_ROLE_AUTHORIZATIONS | | APPLICABLE_ROLES | +| AUTHINFO | | CHARACTER_SETS | | CHECK_CONSTRAINTS | | COLLATION_CHARACTER_SET_APPLICABILITY | @@ -181,6 +182,7 @@ Database: INFORMATION_SCHEMA +---------------------------------------+ | ADMINISTRABLE_ROLE_AUTHORIZATIONS | | APPLICABLE_ROLES | +| AUTHINFO | | CHARACTER_SETS | | CHECK_CONSTRAINTS | | COLLATION_CHARACTER_SET_APPLICABILITY | diff --git a/mysql-test/r/mysqlshow_cs.result b/mysql-test/r/mysqlshow_cs.result index 2b3c2392b5bd..98ebd4fd0156 100644 --- a/mysql-test/r/mysqlshow_cs.result +++ b/mysql-test/r/mysqlshow_cs.result @@ -81,6 +81,7 @@ Database: information_schema +---------------------------------------+ | ADMINISTRABLE_ROLE_AUTHORIZATIONS | | APPLICABLE_ROLES | +| AUTHINFO | | CHARACTER_SETS | | CHECK_CONSTRAINTS | | COLLATIONS | @@ -182,6 +183,7 @@ Database: INFORMATION_SCHEMA +---------------------------------------+ | ADMINISTRABLE_ROLE_AUTHORIZATIONS | | APPLICABLE_ROLES | +| AUTHINFO | | CHARACTER_SETS | | CHECK_CONSTRAINTS | | COLLATIONS | diff --git a/mysql-test/suite/funcs_1/r/is_columns_is_cs.result b/mysql-test/suite/funcs_1/r/is_columns_is_cs.result index 7e9a177482e1..09d0acf98f6e 100644 --- a/mysql-test/suite/funcs_1/r/is_columns_is_cs.result +++ b/mysql-test/suite/funcs_1/r/is_columns_is_cs.result @@ -24,6 +24,11 @@ def information_schema APPLICABLE_ROLES ROLE_HOST 6 NULL YES varchar 256 1024 NU def information_schema APPLICABLE_ROLES IS_GRANTABLE 7 NO varchar 3 9 NULL NULL NULL utf8mb3 utf8mb3_general_ci varchar(3) select NULL def information_schema APPLICABLE_ROLES IS_DEFAULT 8 NULL YES varchar 3 9 NULL NULL NULL utf8mb3 utf8mb3_general_ci varchar(3) select NULL def information_schema APPLICABLE_ROLES IS_MANDATORY 9 NO varchar 3 9 NULL NULL NULL utf8mb3 utf8mb3_general_ci varchar(3) select NULL +def information_schema AUTHINFO ID 1 NO bigint NULL NULL NULL NULL NULL NULL NULL bigint unsigned select NULL +def information_schema AUTHINFO USER 2 NO varchar 26 80 NULL NULL NULL utf8mb3 utf8mb3_general_ci varchar(80) select NULL +def information_schema AUTHINFO HOST 3 NO varchar 86 260 NULL NULL NULL utf8mb3 utf8mb3_general_ci varchar(260) select NULL +def information_schema AUTHINFO SSL 4 NO int NULL NULL NULL NULL NULL NULL NULL int select NULL +def information_schema AUTHINFO INFO 5 YES varchar 21845 65535 NULL NULL NULL utf8mb3 utf8mb3_general_ci varchar(65535) select NULL def information_schema CHARACTER_SETS CHARACTER_SET_NAME 1 NULL NO varchar 64 192 NULL NULL NULL utf8mb3 utf8mb3_general_ci varchar(64) select NULL def information_schema CHARACTER_SETS DEFAULT_COLLATE_NAME 2 NULL NO varchar 64 192 NULL NULL NULL utf8mb3 utf8mb3_general_ci varchar(64) select NULL def information_schema CHARACTER_SETS DESCRIPTION 3 NULL NO varchar 2048 6144 NULL NULL NULL utf8mb3 utf8mb3_general_ci varchar(2048) select NULL @@ -624,6 +629,7 @@ COL_CML DATA_TYPE CHARACTER_SET_NAME COLLATION_NAME 3.0088 varchar utf8mb3 utf8mb3_general_ci 3.0118 varchar utf8mb3 utf8mb3_general_ci 3.0156 varchar utf8mb3 utf8mb3_general_ci +3.0233 varchar utf8mb3 utf8mb3_general_ci 3.0238 varchar utf8mb3 utf8mb3_general_ci 3.0303 varchar utf8mb3 utf8mb3_general_ci 3.0476 varchar utf8mb3 utf8mb3_general_ci @@ -689,6 +695,11 @@ COL_CML TABLE_SCHEMA TABLE_NAME COLUMN_NAME DATA_TYPE CHARACTER_MAXIMUM_LENGTH C 3.0000 information_schema APPLICABLE_ROLES IS_GRANTABLE varchar 3 9 utf8mb3 utf8mb3_general_ci varchar(3) 3.0000 information_schema APPLICABLE_ROLES IS_DEFAULT varchar 3 9 utf8mb3 utf8mb3_general_ci varchar(3) 3.0000 information_schema APPLICABLE_ROLES IS_MANDATORY varchar 3 9 utf8mb3 utf8mb3_general_ci varchar(3) +NULL information_schema AUTHINFO ID bigint NULL NULL NULL NULL bigint unsigned +3.0769 information_schema AUTHINFO USER varchar 26 80 utf8mb3 utf8mb3_general_ci varchar(80) +3.0233 information_schema AUTHINFO HOST varchar 86 260 utf8mb3 utf8mb3_general_ci varchar(260) +NULL information_schema AUTHINFO SSL int NULL NULL NULL NULL int +3.0000 information_schema AUTHINFO INFO varchar 21845 65535 utf8mb3 utf8mb3_general_ci varchar(65535) 3.0000 information_schema CHARACTER_SETS CHARACTER_SET_NAME varchar 64 192 utf8mb3 utf8mb3_general_ci varchar(64) 3.0000 information_schema CHARACTER_SETS DEFAULT_COLLATE_NAME varchar 64 192 utf8mb3 utf8mb3_general_ci varchar(64) 3.0000 information_schema CHARACTER_SETS DESCRIPTION varchar 2048 6144 utf8mb3 utf8mb3_general_ci varchar(2048) diff --git a/mysql-test/suite/funcs_1/r/is_tables_is.result b/mysql-test/suite/funcs_1/r/is_tables_is.result index cda85a938a14..7f5c4b360e51 100644 --- a/mysql-test/suite/funcs_1/r/is_tables_is.result +++ b/mysql-test/suite/funcs_1/r/is_tables_is.result @@ -64,6 +64,29 @@ user_comment Separator ----------------------------------------------------- TABLE_CATALOG def TABLE_SCHEMA information_schema +TABLE_NAME AUTHINFO +TABLE_TYPE SYSTEM VIEW +ENGINE NULL +VERSION 10 +ROW_FORMAT NULL +TABLE_ROWS #TBLR# +AVG_ROW_LENGTH #ARL# +DATA_LENGTH #DL# +MAX_DATA_LENGTH #MDL# +INDEX_LENGTH #IL# +DATA_FREE #DF# +AUTO_INCREMENT #AI# +CREATE_TIME #CRT# +UPDATE_TIME #UT# +CHECK_TIME #CT# +TABLE_COLLATION NULL +CHECKSUM NULL +CREATE_OPTIONS #CO# +TABLE_COMMENT #TC# +user_comment +Separator ----------------------------------------------------- +TABLE_CATALOG def +TABLE_SCHEMA information_schema TABLE_NAME CHARACTER_SETS TABLE_TYPE SYSTEM VIEW ENGINE NULL @@ -1188,6 +1211,29 @@ user_comment Separator ----------------------------------------------------- TABLE_CATALOG def TABLE_SCHEMA information_schema +TABLE_NAME AUTHINFO +TABLE_TYPE SYSTEM VIEW +ENGINE NULL +VERSION 10 +ROW_FORMAT NULL +TABLE_ROWS #TBLR# +AVG_ROW_LENGTH #ARL# +DATA_LENGTH #DL# +MAX_DATA_LENGTH #MDL# +INDEX_LENGTH #IL# +DATA_FREE #DF# +AUTO_INCREMENT #AI# +CREATE_TIME #CRT# +UPDATE_TIME #UT# +CHECK_TIME #CT# +TABLE_COLLATION NULL +CHECKSUM NULL +CREATE_OPTIONS #CO# +TABLE_COMMENT #TC# +user_comment +Separator ----------------------------------------------------- +TABLE_CATALOG def +TABLE_SCHEMA information_schema TABLE_NAME CHARACTER_SETS TABLE_TYPE SYSTEM VIEW ENGINE NULL diff --git a/mysql-test/suite/information_schema/r/information_schema_db.result b/mysql-test/suite/information_schema/r/information_schema_db.result index 2d56c0c7e593..f850b2be7b38 100644 --- a/mysql-test/suite/information_schema/r/information_schema_db.result +++ b/mysql-test/suite/information_schema/r/information_schema_db.result @@ -8,6 +8,7 @@ show tables where Tables_in_information_schema NOT LIKE 'INNODB%' and Tables_in_ Tables_in_information_schema ADMINISTRABLE_ROLE_AUTHORIZATIONS APPLICABLE_ROLES +AUTHINFO CHARACTER_SETS CHECK_CONSTRAINTS COLLATIONS diff --git a/mysql-test/t/information_schema_authinfo-client.opt b/mysql-test/t/information_schema_authinfo-client.opt new file mode 100644 index 000000000000..88ed9f04cf43 --- /dev/null +++ b/mysql-test/t/information_schema_authinfo-client.opt @@ -0,0 +1,4 @@ +--ssl-mode=VERIFY_CA +--ssl-ca=$MYSQL_TEST_DIR/std_data/cacert.pem +--ssl-cert=$MYSQL_TEST_DIR/std_data/client-cert.pem +--ssl-key=$MYSQL_TEST_DIR/std_data/client-key.pem diff --git a/mysql-test/t/information_schema_authinfo-master.opt b/mysql-test/t/information_schema_authinfo-master.opt new file mode 100644 index 000000000000..317b93f46621 --- /dev/null +++ b/mysql-test/t/information_schema_authinfo-master.opt @@ -0,0 +1,4 @@ +--ssl=1 +--ssl-ca=$MYSQL_TEST_DIR/std_data/cacert.pem +--ssl-cert=$MYSQL_TEST_DIR/std_data/server-cert.pem +--ssl-key=$MYSQL_TEST_DIR/std_data/server-key.pem diff --git a/mysql-test/t/information_schema_authinfo.test b/mysql-test/t/information_schema_authinfo.test new file mode 100644 index 000000000000..42c7a432670c --- /dev/null +++ b/mysql-test/t/information_schema_authinfo.test @@ -0,0 +1,12 @@ +--echo # +--echo # Test case for information_schema.authinfo table +--echo # (SSL connection) +--echo # + +--let $assert_text= SSL field for the current connection must be set to 1 +--let $assert_cond= [ SELECT `ssl` = 1 FROM information_schema.authinfo WHERE id = CONNECTION_ID() ] +--source include/assert.inc + +--let $assert_text= Info field (peer certificate) for the current connection must be non-empty +--let $assert_cond= [ SELECT LENGTH(info) > 0 FROM information_schema.authinfo WHERE id = CONNECTION_ID() ] +--source include/assert.inc diff --git a/mysql-test/t/information_schema_authinfo_nossl.test b/mysql-test/t/information_schema_authinfo_nossl.test new file mode 100644 index 000000000000..1797665da3e4 --- /dev/null +++ b/mysql-test/t/information_schema_authinfo_nossl.test @@ -0,0 +1,12 @@ +--echo # +--echo # Test case for information_schema.authinfo table +--echo # (non-SSL connection) +--echo # + +--let $assert_text= SSL field for the current connection must be set to 0 +--let $assert_cond= [ SELECT `ssl` = 0 FROM information_schema.authinfo WHERE id = CONNECTION_ID() ] +--source include/assert.inc + +--let $assert_text= Info field (peer certificate) for the current connection must be NULL +--let $assert_cond= [ SELECT info IS NULL FROM information_schema.authinfo WHERE id = CONNECTION_ID() ] +--source include/assert.inc diff --git a/sql/auth/sql_authentication.cc b/sql/auth/sql_authentication.cc index a514e52cacb2..16f9d32f27ca 100644 --- a/sql/auth/sql_authentication.cc +++ b/sql/auth/sql_authentication.cc @@ -2636,9 +2636,6 @@ static bool read_client_connect_attrs(THD *thd, char **ptr, return false; } -typedef std::string Sql_string_t; -static Sql_string_t x509_cert_write(X509 *cert); - static bool acl_check_ssl(THD *thd, const ACL_USER *acl_user) { Vio *vio = thd->get_protocol_classic()->get_vio(); SSL *ssl = (SSL *)vio->ssl_arg; @@ -2667,7 +2664,6 @@ static bool acl_check_ssl(THD *thd, const ACL_USER *acl_user) { if (vio_type(vio) == VIO_TYPE_SSL && SSL_get_verify_result(ssl) == X509_V_OK && (cert = SSL_get_peer_certificate(ssl))) { - thd->set_connection_certificate(x509_cert_write(cert)); X509_free(cert); return false; } @@ -2717,7 +2713,6 @@ static bool acl_check_ssl(THD *thd, const ACL_USER *acl_user) { } OPENSSL_free(ptr); } - thd->set_connection_certificate(x509_cert_write(cert)); X509_free(cert); return false; } @@ -4438,6 +4433,8 @@ int acl_authenticate(THD *thd, enum_server_command command) { goto end; } + thd->update_connection_certificate(); + /* Check whether the account has been locked. */ @@ -5066,6 +5063,8 @@ static SYS_VAR *sha256_password_sysvars[] = { MYSQL_SYSVAR(private_key_path), MYSQL_SYSVAR(public_key_path), MYSQL_SYSVAR(auto_generate_rsa_keys), nullptr}; +typedef std::string Sql_string_t; + /** Exception free resize diff --git a/sql/handler.h b/sql/handler.h index 0045615d7c74..965244120b55 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -949,7 +949,8 @@ enum enum_schema_tables : int { SCH_USER_PRIVILEGES, SCH_TMP_TABLE_COLUMNS, SCH_TMP_TABLE_KEYS, - SCH_LAST = SCH_TMP_TABLE_KEYS + SCH_AUTHINFO, + SCH_LAST = SCH_AUTHINFO }; enum ha_stat_type { diff --git a/sql/server_component/mysql_server_event_tracking_bridge_imp.cc b/sql/server_component/mysql_server_event_tracking_bridge_imp.cc index 982237ee621e..e9fe14be4544 100644 --- a/sql/server_component/mysql_server_event_tracking_bridge_imp.cc +++ b/sql/server_component/mysql_server_event_tracking_bridge_imp.cc @@ -978,8 +978,10 @@ DEFINE_BOOL_METHOD(Event_connection_bridge_implementation::notify, plugin_data.ip = TO_LEXCSTRING(data->ip); plugin_data.database = TO_LEXCSTRING(data->database); plugin_data.connection_type = data->connection_type; - plugin_data.connection_certificate.str = thd->connection_certificate().c_str(); - plugin_data.connection_certificate.length = thd->connection_certificate().size(); + plugin_data.connection_certificate.str = + thd->get_connection_certificate().c_str(); + plugin_data.connection_certificate.length = + thd->get_connection_certificate().size(); plugin_data.port = mysqld_port; return event_class_dispatch(thd, MYSQL_AUDIT_CONNECTION_CLASS, diff --git a/sql/sql_audit.cc b/sql/sql_audit.cc index fc7e85a9f161..f37de2aed5f6 100644 --- a/sql/sql_audit.cc +++ b/sql/sql_audit.cc @@ -934,8 +934,9 @@ int mysql_event_tracking_connection_notify( event.ip = {ip.str, ip.length}; event.database = {db.str, db.length}; event.connection_type = thd->get_vio_type(); - event.connection_certificate.str = thd->connection_certificate().c_str(); - event.connection_certificate.length = thd->connection_certificate().size(); + event.connection_certificate.str = thd->get_connection_certificate().c_str(); + event.connection_certificate.length = + thd->get_connection_certificate().size(); event.port = mysqld_port; struct st_mysql_event_generic event_generic; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index e0feed546667..cf97beb69084 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -1247,7 +1248,7 @@ void THD::cleanup_connection(void) { sp_cache_clear(&sp_proc_cache); sp_cache_clear(&sp_func_cache); - m_connection_certificate = ""; + reset_connection_certificate(); clear_error(); // clear the warnings @@ -1285,13 +1286,45 @@ bool THD::is_cleanup_done() { m_thd_life_cycle_stage >= enum_thd_life_cycle_stages::CLEANED_UP); } -void THD::set_connection_certificate(std::string const &cert) { - assert(m_connection_certificate.empty()); - m_connection_certificate = cert; -} +std::string THD::extract_peer_certificate_info(const THD *thd, bool printable) { + // Extracting user certificate from the thread + if (!thd->has_net_vio_ssl_arg()) return {}; + + auto ssl = static_cast(thd->get_net_vio_ssl_arg()); + + // Creating new X509 abstraction + auto cert_deleter = [](X509 *cert) { + if (cert != nullptr) X509_free(cert); + }; + using x509_ptr = std::unique_ptr; + + x509_ptr cert{SSL_get_peer_certificate(ssl), cert_deleter}; + if (!cert) return {}; + + // Creating new memory-based BIO object + auto bio_deleter = [](BIO *bio) { + if (bio != nullptr) BIO_free(bio); + }; + using bio_ptr = std::unique_ptr; + + bio_ptr bio{BIO_new(BIO_s_mem()), bio_deleter}; + if (!bio) return {}; + + // Printing the certificate to the bio object + int print_result = 0; + if (printable) + print_result = X509_print(bio.get(), cert.get()); + else + print_result = PEM_write_bio_X509(bio.get(), cert.get()); + if (print_result != 1) return {}; + + // Extracting data from the bio object + BUF_MEM *buf_mem; + BIO_get_mem_ptr(bio.get(), &buf_mem); + assert(buf_mem->length <= buf_mem->max); + if (buf_mem->data == nullptr) return {}; -std::string const &THD::connection_certificate() const noexcept { - return m_connection_certificate; + return std::string{buf_mem->data, buf_mem->length}; } /* @@ -1480,7 +1513,7 @@ void THD::release_resources() { if (current_thd == this) restore_globals(); - m_connection_certificate = ""; + reset_connection_certificate(); mysql_mutex_lock(&LOCK_status); /* Add thread status to the global totals. */ diff --git a/sql/sql_class.h b/sql/sql_class.h index 73fa950c0846..30cf84c5b62d 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1904,6 +1904,14 @@ class THD : public MDL_context_owner, String packet; // dynamic buffer for network I/O public: const NET *get_net() const { return &net; } + bool has_net_vio() const noexcept { return net.vio != nullptr; } + const Vio *get_net_vio() const noexcept { return net.vio; } + bool has_net_vio_ssl_arg() const noexcept { + return has_net_vio() && get_net_vio()->ssl_arg != nullptr; + } + const void *get_net_vio_ssl_arg() const noexcept { + return has_net_vio() ? get_net_vio()->ssl_arg : nullptr; + } void set_skip_readonly_check() { skip_readonly_check = true; @@ -3873,10 +3881,28 @@ class THD : public MDL_context_owner, Gtid_set owned_gtid_set; #endif + public: + static std::string extract_peer_certificate_info(const THD *thd, + bool printable); + + private: + friend int acl_authenticate(THD *, enum_server_command); + std::string m_connection_certificate; - std::string const &connection_certificate() const noexcept; - void set_connection_certificate(std::string const &cert); + void update_connection_certificate() { + m_connection_certificate = + extract_peer_certificate_info(this, false /* pem format */); + } + void reset_connection_certificate() { + m_connection_certificate.clear(); + m_connection_certificate.shrink_to_fit(); + } + + public: + std::string const &get_connection_certificate() const noexcept { + return m_connection_certificate; + } /* Replication related context. diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 84c687e75b33..d971263f91e0 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2871,6 +2871,101 @@ static const char *thread_state_info(THD *invoking_thd, THD *inspected_thd) { } } +/** + This class implements callback function used by fill_schema_authinfo() + to populate all the client SSL auth information into I_S table. +*/ +class Fill_authinfo_list : public Do_THD_Impl { + private: + THD *const m_thd; + TABLE *const m_table; + const char *const m_user; + + public: + Fill_authinfo_list(THD *thd, Table_ref *tables) noexcept + : m_thd(thd), + m_table(tables->table), + m_user(thd->security_context()->check_access(PROCESS_ACL) + ? nullptr + : thd->security_context()->priv_user().str) {} + + virtual void operator()(THD *iteration_thd) override { + const auto current_sctx = iteration_thd->security_context(); + const auto current_sctx_user = current_sctx->user(); + + if (!iteration_thd->has_net_vio() && + iteration_thd->system_thread == NON_SYSTEM_THREAD) + return; + if (m_user != nullptr && (current_sctx_user.str == nullptr || + strcmp(current_sctx_user.str, m_user) != 0)) + return; + + restore_record(m_table, s->default_values); + + /* ID */ + m_table->field[0]->store(static_cast(iteration_thd->thread_id()), + /*unsigned=*/true); + + /* USER */ + const char *val = current_sctx_user.str + ? current_sctx_user.str + : (iteration_thd->system_thread != NON_SYSTEM_THREAD + ? "system user" + : "unauthenticated user"); + m_table->field[1]->store(val, strlen(val), system_charset_info); + + /* HOST */ + const auto current_sctx_host = current_sctx->host(); + const auto current_sctx_ip = current_sctx->ip(); + const auto current_sctx_host_or_ip = current_sctx->host_or_ip(); + + std::string host_and_port; + if (current_sctx_host.str != nullptr && current_sctx_host.str[0] != '\0') { + host_and_port.assign(current_sctx_host.str, current_sctx_host.length); + } else if (current_sctx_ip.str != nullptr && + current_sctx_ip.str[0] != '\0') { + host_and_port.assign(current_sctx_ip.str, current_sctx_ip.length); + } else if (current_sctx_host_or_ip.str != nullptr && + current_sctx_host_or_ip.str[0] == '\0') { + host_and_port.assign(current_sctx_host_or_ip.str, + current_sctx_host_or_ip.length); + } + if (!host_and_port.empty() && iteration_thd->peer_port != 0) { + host_and_port += ':'; + host_and_port += std::to_string(iteration_thd->peer_port); + } + m_table->field[2]->store(host_and_port.c_str(), host_and_port.size(), + system_charset_info); + + /* SSL */ + const auto ssl = iteration_thd->has_net_vio_ssl_arg(); + m_table->field[3]->store(ssl, /*unsigned=*/true); + + /* Info */ + const auto cert = THD::extract_peer_certificate_info( + iteration_thd, true /* printable format */); + if (!cert.empty()) { + const auto width = std::min( + static_cast(PROCESS_LIST_INFO_WIDTH), cert.size()); + m_table->field[4]->store(cert.c_str(), width, system_charset_info); + m_table->field[4]->set_notnull(); + } + + schema_table_store_record(m_thd, m_table); + } +}; + +int fill_schema_authinfo(THD *thd, Table_ref *tables, Item *) { + DBUG_ENTER("fill_schema_authinfo"); + + Fill_authinfo_list fill_authinfo_list(thd, tables); + if (!thd->killed) { + Global_THD_manager::get_instance()->do_for_all_thd_copy( + &fill_authinfo_list); + } + DBUG_RETURN(0); +} + /** This class implements callback function used by mysqld_list_processes() to list all the client process information. @@ -5154,6 +5249,14 @@ ST_FIELD_INFO processlist_fields_info[] = { {"INFO", PROCESS_LIST_INFO_WIDTH, MYSQL_TYPE_STRING, 0, 1, "Info", 0}, {nullptr, 0, MYSQL_TYPE_STRING, 0, 0, nullptr, 0}}; +ST_FIELD_INFO authinfo_fields_info[] = { + {"ID", 21, MYSQL_TYPE_LONGLONG, 0, MY_I_S_UNSIGNED, "Id", 0}, + {"USER", USERNAME_CHAR_LENGTH, MYSQL_TYPE_STRING, 0, 0, "User", 0}, + {"HOST", HOST_AND_PORT_LENGTH - 1, MYSQL_TYPE_STRING, 0, 0, "Host", 0}, + {"SSL", 7, MYSQL_TYPE_LONG, 0, 0, "Ssl", 0}, + {"INFO", PROCESS_LIST_INFO_WIDTH, MYSQL_TYPE_STRING, 0, 1, "Info", 0}, + {0, 0, MYSQL_TYPE_STRING, 0, 0, 0, 0}}; + ST_FIELD_INFO plugin_fields_info[] = { {"PLUGIN_NAME", NAME_CHAR_LEN, MYSQL_TYPE_STRING, 0, 0, "Name", 0}, {"PLUGIN_VERSION", 20, MYSQL_TYPE_STRING, 0, 0, nullptr, 0}, @@ -5244,6 +5347,8 @@ ST_SCHEMA_TABLE schema_tables[] = { make_tmp_table_columns_format, get_schema_tmp_table_columns_record, true}, {"TMP_TABLE_KEYS", tmp_table_keys_fields_info, show_temporary_tables, make_old_format, get_schema_tmp_table_keys_record, true}, + {"AUTHINFO", authinfo_fields_info, fill_schema_authinfo, make_old_format, 0, + false}, {nullptr, nullptr, nullptr, nullptr, nullptr, false}}; int initialize_schema_table(st_plugin_int *plugin) {