commit c9499e9a93d
Author: Nikita Malyavin <nikitamalyavin@gmail.com>
Date:   Fri Jun 14 11:11:10 2024 +0200

    WIP server changes

diff --git a/include/mysql/plugin_auth.h b/include/mysql/plugin_auth.h
index 3827db33431..defa7d928cc 100644
--- a/include/mysql/plugin_auth.h
+++ b/include/mysql/plugin_auth.h
@@ -85,6 +85,11 @@ typedef struct st_mysql_server_auth_info
   */  
   char external_user[MYSQL_USERNAME_LENGTH+1];
 
+  /**
+    Pointer to thd->scramble, which is used to verify the session handshake.
+  */
+  char *scramble;
+
   /**
     This only affects the "Authentication failed. Password used: %s"
     error message. has the following values : 
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index ca011f396ba..5c20de6302a 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -80,17 +80,17 @@ const char *safe_vio_type_name(Vio *vio)
 
 #include "sql_acl_getsort.ic"
 
-static Lex_ident_plugin native_password_plugin_name=
+Lex_ident_plugin native_password_plugin_name=
   "mysql_native_password"_Lex_ident_plugin;
 
 
 static Lex_ident_plugin old_password_plugin_name=
   "mysql_old_password"_Lex_ident_plugin;
 
+static Lex_ident_plugin ed25519v2_plugin_name {"ed25519v2"_Lex_ident_plugin};
 
-/// @todo make it configurable
-LEX_CSTRING *default_auth_plugin_name= &native_password_plugin_name;
-
+plugin_ref default_auth_plugin;
+const char *default_auth_plugin_name= native_password_plugin_name.str;
 /*
   Wildcard host, matches any hostname
 */
@@ -2521,7 +2521,11 @@ bool acl_init(bool dont_read_acl_tables)
   old_password_plugin= my_plugin_lock_by_name(0,
            &old_password_plugin_name, MYSQL_AUTHENTICATION_PLUGIN);
 
-  if (!native_password_plugin || !old_password_plugin)
+  Lex_cstring_strlen def_plugin_name(default_auth_plugin_name);
+  default_auth_plugin= my_plugin_lock_by_name(NULL, &def_plugin_name,
+                                              MYSQL_AUTHENTICATION_PLUGIN);
+
+  if (!native_password_plugin || !old_password_plugin || !default_auth_plugin)
     DBUG_RETURN(1);
 
   if (dont_read_acl_tables)
@@ -2923,6 +2927,7 @@ void acl_free(bool end)
     acl_cache->clear(1); /* purecov: inspected */
   else
   {
+    plugin_unlock(0, default_auth_plugin);
     plugin_unlock(0, native_password_plugin);
     plugin_unlock(0, old_password_plugin);
     delete acl_cache;
@@ -3341,7 +3346,7 @@ static int check_role_is_granted_callback(ACL_USER_BASE *grantee, void *data)
   this function finds anonymous users too, it's when a
   user is not empty, but priv_user (acl_user->user) is empty.
 */
-static ACL_USER *find_user_or_anon(const char *host, const char *user, const char *ip)
+ACL_USER *find_user_or_anon(const char *host, const char *user, const char *ip)
 {
   return find_by_username_or_anon<ACL_USER>
     (reinterpret_cast<ACL_USER*>(acl_users.buffer), acl_users.elements,
@@ -14359,6 +14364,17 @@ static int server_mpvio_write_packet(MYSQL_PLUGIN_VIO *param,
   DBUG_RETURN(res);
 }
 
+void mpvio_init_auth_info(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *ai)
+{
+  MPVIO_EXT * const mpvio= (MPVIO_EXT *) vio;
+
+  ai->user_name= ai->thd->security_ctx->user;
+  ai->user_name_length= (uint) strlen(ai->user_name);
+  ai->auth_string= mpvio->acl_user->auth[mpvio->curr_auth].salt.str;
+  ai->auth_string_length= (ulong) mpvio->acl_user->auth[mpvio->curr_auth].salt.length;
+  strmake_buf(ai->authenticated_as, mpvio->acl_user->user.str);
+}
+
 /**
   vio->read_packet() callback method for server authentication plugins
 
@@ -14446,11 +14462,7 @@ static int server_mpvio_read_packet(MYSQL_PLUGIN_VIO *param, uchar **buf)
     goto err;
   }
 
-  ai->user_name= ai->thd->security_ctx->user;
-  ai->user_name_length= (uint) strlen(ai->user_name);
-  ai->auth_string= mpvio->acl_user->auth[mpvio->curr_auth].salt.str;
-  ai->auth_string_length= (ulong) mpvio->acl_user->auth[mpvio->curr_auth].salt.length;
-  strmake_buf(ai->authenticated_as, mpvio->acl_user->user.str);
+  mpvio_init_auth_info(param, ai);
 
   DBUG_RETURN((int)pkt_len);
 
@@ -14607,47 +14619,50 @@ static void make_ssl_info(THD *thd, LEX_CSTRING salt, char *info)
 #endif
 }
 
-static int do_auth_once(THD *thd, const LEX_CSTRING *auth_plugin_name,
+static int do_auth_once(THD *thd, plugin_ref plugin,
                         MPVIO_EXT *mpvio)
 {
-  int res= CR_OK;
-  bool unlock_plugin= false;
-  plugin_ref plugin= get_auth_plugin(thd, *auth_plugin_name, &unlock_plugin);
-
   mpvio->plugin= plugin;
   mpvio->auth_info.user_name= NULL;
-
-  if (plugin)
-  {
-    st_mysql_auth *info= (st_mysql_auth *) plugin_decl(plugin)->info;
-    switch (info->interface_version >> 8) {
-    case 0x02:
-      res= info->authenticate_user(mpvio, &mpvio->auth_info);
-      break;
-    case 0x01:
-      {
-        MYSQL_SERVER_AUTH_INFO_0x0100 compat;
-        compat.downgrade(&mpvio->auth_info);
-        res= info->authenticate_user(mpvio, (MYSQL_SERVER_AUTH_INFO *)&compat);
-        compat.upgrade(&mpvio->auth_info);
-      }
-      break;
-    default: DBUG_ASSERT(0);
+  int res= CR_OK;
+  st_mysql_auth *info= (st_mysql_auth *) plugin_decl(plugin)->info;
+  switch (info->interface_version >> 8) {
+  case 0x02:
+    res= info->authenticate_user(mpvio, &mpvio->auth_info);
+    break;
+  case 0x01:
+    {
+      MYSQL_SERVER_AUTH_INFO_0x0100 compat;
+      compat.downgrade(&mpvio->auth_info);
+      res= info->authenticate_user(mpvio, (MYSQL_SERVER_AUTH_INFO *)&compat);
+      compat.upgrade(&mpvio->auth_info);
     }
-
-    if (unlock_plugin)
-      plugin_unlock(thd, plugin);
+    break;
+  default: DBUG_ASSERT(0);
   }
-  else
+
+  return res;
+}
+
+static int do_auth_once(THD *thd, const LEX_CSTRING *auth_plugin_name,
+                        MPVIO_EXT *mpvio)
+{
+  bool unlock_plugin= false;
+  plugin_ref plugin= get_auth_plugin(thd, *auth_plugin_name, &unlock_plugin);
+  if (unlikely(!plugin))
   {
     /* Server cannot load the required plugin. */
     Host_errors errors;
     errors.m_no_auth_plugin= 1;
     inc_host_errors(mpvio->auth_info.thd->security_ctx->ip, &errors);
     my_error(ER_PLUGIN_IS_NOT_LOADED, MYF(0), auth_plugin_name->str);
-    res= CR_ERROR;
+    return CR_ERROR;
   }
 
+  int res= do_auth_once(thd, plugin, mpvio);
+  if (unlock_plugin)
+    plugin_unlock(thd, plugin);
+
   return res;
 }
 
@@ -14741,6 +14756,7 @@ bool acl_authenticate(THD *thd, uint com_change_user_pkt_len)
   mpvio.auth_info.host_or_ip= thd->security_ctx->host_or_ip;
   mpvio.auth_info.host_or_ip_length=
     (unsigned int) strlen(thd->security_ctx->host_or_ip);
+  mpvio.auth_info.scramble= thd->scramble;
 
   DBUG_PRINT("info", ("com_change_user_pkt_len=%u", com_change_user_pkt_len));
 
@@ -14769,7 +14785,7 @@ bool acl_authenticate(THD *thd, uint com_change_user_pkt_len)
       the correct plugin.
     */
 
-    res= do_auth_once(thd, default_auth_plugin_name, &mpvio);
+    res= do_auth_once(thd, default_auth_plugin, &mpvio);
   }
 
   PSI_CALL_set_connection_type(vio_type(thd->net.vio));
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index cc774263c91..1a98cf5d3b5 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -157,6 +157,9 @@ int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
 int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
 int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *wildstr);
 
+class ACL_USER;
+ACL_USER *find_user_or_anon(const char *host, const char *user, const char *ip);
+
 /**
   Result of an access check for an internal schema or table.
   Internal ACL checks are always performed *before* using
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 41f3f49cdd1..4645fda2d77 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -4514,6 +4514,14 @@ static Sys_var_plugin Sys_enforce_storage_engine(
        DEFAULT(&enforced_storage_engine), NO_MUTEX_GUARD, NOT_IN_BINLOG,
        ON_CHECK(check_has_super));
 
+extern const char *default_auth_plugin_name;
+extern LEX_CSTRING native_password_plugin_name;
+static Sys_var_charptr Sys_default_auth_plugin(
+        "default_auth_plugin", "Default plugin, that will be tried first when authenticating new connections",
+        READ_ONLY GLOBAL_VAR(default_auth_plugin_name), CMD_LINE(OPT_ARG),
+        DEFAULT(native_password_plugin_name.str),
+        NO_MUTEX_GUARD, NOT_IN_BINLOG);
+
 
 #ifdef HAVE_REPLICATION
 /*
