← Back to team overview

maria-developers team mailing list archive

Re: Review of 5.2 pluggable-auth tree

 

Hi, Monty!

On Mar 26, Sergei Golubchik wrote:
> 
> Hi, Monty!
> 
> See the answers below:
> (no reply means "ok, changed")
> 
> On Mar 25, Michael Widenius wrote:

And here's a patch that implements your review comments.

Regards,
Sergei
=== modified file 'client/mysql.cc'
*** client/mysql.cc	2010-03-15 17:35:32 +0000
--- client/mysql.cc	2010-03-26 11:32:46 +0000
***************
*** 4273,4296 ****
                                                   const char *prompt,
                                                   char *buf, int buf_len)
  {
!   int ch;
!   char *s=buf, *end=buf+buf_len-1;
  
!   fputs("[mysql] ", stdout);
    fputs(prompt, stdout);
    fputs(" ", stdout);
  
    if (type == 2) /* password */
    {
      s= get_tty_password("");
!     strncpy(buf, s, buf_len);
      my_free(s, MYF(0));
    }
    else
    {
!     for (ch= fgetc(stdin); s < end && ch != '\n' && ch != EOF; ch= fgetc(stdin))
!       *s++= ch;
!     *s=0;
    }
  
    return buf;
--- 4273,4296 ----
                                                   const char *prompt,
                                                   char *buf, int buf_len)
  {
!   char *s=buf;
  
!   fputs("[mariadb] ", stdout);
    fputs(prompt, stdout);
    fputs(" ", stdout);
  
    if (type == 2) /* password */
    {
      s= get_tty_password("");
!     strnmov(buf, s, buf_len);
!     buf[buf_len-1]= 0;
      my_free(s, MYF(0));
    }
    else
    {
!     fgets(buf, buf_len-1, stdin);
!     if (buf[0] && (s= strend(buf))[-1] == '\n')
!       s[-1]= 0;
    }
  
    return buf;

=== modified file 'libmysqld/lib_sql.cc'
*** libmysqld/lib_sql.cc	2010-03-15 17:35:32 +0000
--- libmysqld/lib_sql.cc	2010-03-26 11:32:46 +0000
***************
*** 415,421 ****
  int emb_read_change_user_result(MYSQL *mysql)
  {
    mysql->net.read_pos= (uchar*)""; // fake an OK packet
!   return mysql_errno(mysql) ? packet_error : 1;
  }
  
  MYSQL_METHODS embedded_methods= 
--- 415,421 ----
  int emb_read_change_user_result(MYSQL *mysql)
  {
    mysql->net.read_pos= (uchar*)""; // fake an OK packet
!   return mysql_errno(mysql) ? packet_error : 1 /* length of the OK packet */;
  }
  
  MYSQL_METHODS embedded_methods= 

=== modified file 'plugin/auth/auth_socket.c'
*** plugin/auth/auth_socket.c	2010-03-11 12:33:22 +0000
--- plugin/auth/auth_socket.c	2010-03-26 11:32:46 +0000
***************
*** 1,5 ****
  /* Copyright (C) 2010 Monty Program Ab
! /* Copyright (C) 2010 Monty Program Ab
  
     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
--- 1,5 ----
  /* Copyright (C) 2010 Monty Program Ab
! /* Copyright (C) 2010 Sergei Golubchik and Monty Program Ab
  
     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

=== modified file 'plugin/auth/dialog.c'
*** plugin/auth/dialog.c	2010-03-11 12:33:22 +0000
--- plugin/auth/dialog.c	2010-03-26 11:32:46 +0000
***************
*** 1,5 ****
  /* Copyright (C) 2010 Monty Program Ab
! /* Copyright (C) 2010 Monty Program Ab
  
     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
--- 1,5 ----
  /* Copyright (C) 2010 Monty Program Ab
! /* Copyright (C) 2010 Sergei Golubchik and Monty Program Ab
  
     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
***************
*** 236,242 ****
          We send the "password", assuming the client knows what its doing.
          (in other words, the dialog plugin should be only set as a default
          authentication plugin on the client if the first question
!         asks for a password - which will be sent in cleat text, by the way)
        */
        reply= mysql->passwd;
      }
--- 236,242 ----
          We send the "password", assuming the client knows what its doing.
          (in other words, the dialog plugin should be only set as a default
          authentication plugin on the client if the first question
!         asks for a password - which will be sent in clear text, by the way)
        */
        reply= mysql->passwd;
      }

=== modified file 'sql-common/client.c'
*** sql-common/client.c	2010-03-11 12:33:22 +0000
--- sql-common/client.c	2010-03-26 11:32:46 +0000
***************
*** 109,114 ****
  #include <sql_common.h>
  #include <mysql/client_plugin.h>
  
  uint            mysql_port=0;
  char            *mysql_unix_port= 0;
  const char      *unknown_sqlstate= "HY000";
--- 109,117 ----
  #include <sql_common.h>
  #include <mysql/client_plugin.h>
  
+ #define native_password_plugin_name "mysql_native_password"
+ #define old_password_plugin_name    "mysql_old_password"
+ 
  uint            mysql_port=0;
  char            *mysql_unix_port= 0;
  const char      *unknown_sqlstate= "HY000";
***************
*** 1047,1059 ****
    return 0;
  }
  
! #define extension_free(OPTS, X)                                  \
      if ((OPTS)->extension)                                       \
        my_free((OPTS)->extension->X, MYF(MY_ALLOW_ZERO_PTR));     \
      else                                                         \
        (OPTS)->extension= (struct st_mysql_options_extention *)   \
          my_malloc(sizeof(struct st_mysql_options_extention),     \
!                   MYF(MY_WME | MY_ZEROFILL));
  
  void mysql_read_default_options(struct st_mysql_options *options,
                                  const char *filename,const char *group)
--- 1050,1063 ----
    return 0;
  }
  
! #define extension_set_string(OPTS, X, STR)                       \
      if ((OPTS)->extension)                                       \
        my_free((OPTS)->extension->X, MYF(MY_ALLOW_ZERO_PTR));     \
      else                                                         \
        (OPTS)->extension= (struct st_mysql_options_extention *)   \
          my_malloc(sizeof(struct st_mysql_options_extention),     \
!                   MYF(MY_WME | MY_ZEROFILL));                    \
!     (OPTS)->extension->X= my_strdup((STR), MYF(MY_WME));
  
  void mysql_read_default_options(struct st_mysql_options *options,
                                  const char *filename,const char *group)
***************
*** 1243,1254 ****
            options->report_data_truncation= opt_arg ? test(atoi(opt_arg)) : 1;
            break;
          case OPT_plugin_dir:
!           extension_free(options, plugin_dir);
!           options->extension->plugin_dir= my_strdup(opt_arg, MYF(MY_WME));
            break;
          case OPT_default_auth:
!           extension_free(options, default_auth);
!           options->extension->default_auth= my_strdup(opt_arg, MYF(MY_WME));
            break;
          default:
            DBUG_PRINT("warning",("unknown option: %s",option[0]));
--- 1247,1256 ----
            options->report_data_truncation= opt_arg ? test(atoi(opt_arg)) : 1;
            break;
          case OPT_plugin_dir:
!           extension_set_string(options, plugin_dir, opt_arg);
            break;
          case OPT_default_auth:
!           extension_set_string(options, default_auth, opt_arg);
            break;
          default:
            DBUG_PRINT("warning",("unknown option: %s",option[0]));
***************
*** 1892,1897 ****
  /*********** client side authentication support **************************/
  
  typedef struct st_mysql_client_plugin_AUTHENTICATION auth_plugin_t;
  
  /* this is a "superset" of MYSQL_PLUGIN_VIO, in C++ I use inheritance */
  typedef struct {
--- 1894,1937 ----
  /*********** client side authentication support **************************/
  
  typedef struct st_mysql_client_plugin_AUTHENTICATION auth_plugin_t;
+ static int client_mpvio_write_packet(struct st_plugin_vio*, const uchar*, int);
+ static int native_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
+ static int old_password_auth_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
+ 
+ static auth_plugin_t native_password_client_plugin=
+ {
+   MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
+   MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION,
+   native_password_plugin_name,
+   "R.J.Silk, Sergei Golubchik",
+   "Native MySQL authentication",
+   {1, 0, 0},
+   NULL,
+   NULL,
+   native_password_auth_client
+ };
+ 
+ static auth_plugin_t old_password_client_plugin=
+ {
+   MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
+   MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION,
+   old_password_plugin_name,
+   "R.J.Silk, Sergei Golubchik",
+   "Old MySQL-3.23 authentication",
+   {1, 0, 0},
+   NULL,
+   NULL,
+   old_password_auth_client
+ };
+ 
+ struct st_mysql_client_plugin *mysql_client_builtins[]=
+ {
+   (struct st_mysql_client_plugin *)&native_password_client_plugin,
+   (struct st_mysql_client_plugin *)&old_password_client_plugin,
+   0
+ };
+ 
+ 
  
  /* this is a "superset" of MYSQL_PLUGIN_VIO, in C++ I use inheritance */
  typedef struct {
***************
*** 1906,1918 ****
      uchar *pkt;                     /**< pointer into NET::buff */
      uint pkt_len;
    } cached_server_reply;
!   int packets_read, packets_written; /**< counters for send/received packets */
!   int mysql_change_user;            /**< if it's mysql_change_user() */
    int last_read_packet_len;         /**< the length of the last *read* packet */
  } MCPVIO_EXT;
- 
- #define native_password_plugin_name "mysql_native_password"
- #define old_password_plugin_name    "mysql_old_password"
  
  /**
    sends a COM_CHANGE_USER command with a caller provided payload
--- 1946,1955 ----
      uchar *pkt;                     /**< pointer into NET::buff */
      uint pkt_len;
    } cached_server_reply;
!   uint packets_read, packets_written; /**< counters for send/received packets */
!   my_bool mysql_change_user;          /**< if it's mysql_change_user() */
    int last_read_packet_len;         /**< the length of the last *read* packet */
  } MCPVIO_EXT;
  
  /**
    sends a COM_CHANGE_USER command with a caller provided payload
***************
*** 2124,2130 ****
        goto error;
      }
    }
! #endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
  
    DBUG_PRINT("info",("Server version = '%s'  capabilites: %lu  status: %u  client_flag: %lu",
                       mysql->server_version, mysql->server_capabilities,
--- 2161,2167 ----
        goto error;
      }
    }
! #endif /* HAVE_OPENSSL */
  
    DBUG_PRINT("info",("Server version = '%s'  capabilites: %lu  status: %u  client_flag: %lu",
                       mysql->server_version, mysql->server_capabilities,
***************
*** 2187,2194 ****
  }
  
  
- static int client_mpvio_write_packet(struct st_plugin_vio*, const uchar*, int);
- 
  /**
    vio->read_packet() callback method for client authentication plugins
  
--- 2224,2229 ----
  }
  
  
  /**
    vio->read_packet() callback method for client authentication plugins
  
***************
*** 2202,2208 ****
    MYSQL *mysql= mpvio->mysql;
    ulong  pkt_len;
  
!   if (mpvio->packets_read == 0 && !mpvio->cached_server_reply.pkt)
    {
      /*
        the server handshake packet came from the wrong plugin,
--- 2237,2252 ----
    MYSQL *mysql= mpvio->mysql;
    ulong  pkt_len;
  
!   /* there are cached data left, feed it to a plugin */
!   if (mpvio->cached_server_reply.pkt)
!   {
!     *buf= mpvio->cached_server_reply.pkt;
!     mpvio->cached_server_reply.pkt= 0;
!     mpvio->packets_read++;
!     return mpvio->cached_server_reply.pkt_len;
!   }
! 
!   if (mpvio->packets_read == 0)
    {
      /*
        the server handshake packet came from the wrong plugin,
***************
*** 2214,2228 ****
        return (int)packet_error;
    }
  
-   /* there are cached data left, feed it to a plugin */
-   if (mpvio->cached_server_reply.pkt)
-   {
-     *buf= mpvio->cached_server_reply.pkt;
-     mpvio->cached_server_reply.pkt= 0;
-     mpvio->packets_read++;
-     return mpvio->cached_server_reply.pkt_len;
-   }
- 
    /* otherwise read the data */
    pkt_len= (*mysql->methods->read_change_user_result)(mysql);
    mpvio->last_read_packet_len= pkt_len;
--- 2258,2263 ----
        return (int)packet_error;
    }
  
    /* otherwise read the data */
    pkt_len= (*mysql->methods->read_change_user_result)(mysql);
    mpvio->last_read_packet_len= pkt_len;
***************
*** 2236,2241 ****
      the server sends \1\255 or \1\254 instead of just \255 or \254 -
      for us to not confuse it with an error or "change plugin" packets.
      We remove this escaping \1 here.
    */
    if (pkt_len && **buf == 1)
    {
--- 2271,2278 ----
      the server sends \1\255 or \1\254 instead of just \255 or \254 -
      for us to not confuse it with an error or "change plugin" packets.
      We remove this escaping \1 here.
+ 
+     See also server_mpvio_write_packet() where the escaping is done.
    */
    if (pkt_len && **buf == 1)
    {
***************
*** 2368,2381 ****
    /* determine the default/initial plugin to use */
    if (mysql->options.extension && mysql->options.extension->default_auth &&
        mysql->server_capabilities & CLIENT_PLUGIN_AUTH)
      auth_plugin_name= mysql->options.extension->default_auth;
-   else
-     auth_plugin_name= mysql->server_capabilities & CLIENT_PROTOCOL_41 ?
-       native_password_plugin_name : old_password_plugin_name;
- 
    if (!(auth_plugin= (auth_plugin_t*) mysql_client_find_plugin(mysql,
                           auth_plugin_name, MYSQL_CLIENT_AUTHENTICATION_PLUGIN)))
      return 1; /* oops, not found */
  
    mysql->net.last_errno= 0; /* just in case */
  
--- 2405,2422 ----
    /* determine the default/initial plugin to use */
    if (mysql->options.extension && mysql->options.extension->default_auth &&
        mysql->server_capabilities & CLIENT_PLUGIN_AUTH)
+   {
      auth_plugin_name= mysql->options.extension->default_auth;
    if (!(auth_plugin= (auth_plugin_t*) mysql_client_find_plugin(mysql,
                           auth_plugin_name, MYSQL_CLIENT_AUTHENTICATION_PLUGIN)))
      return 1; /* oops, not found */
+   }
+   else
+   {
+     auth_plugin= mysql->server_capabilities & CLIENT_PROTOCOL_41 ?
+       &native_password_client_plugin : &old_password_client_plugin;
+     auth_plugin_name= auth_plugin->name;
+   }
  
    mysql->net.last_errno= 0; /* just in case */
  
***************
*** 2436,2451 ****
    {
      /* The server asked to use a different authentication plugin */
      if (pkt_length == 1)
!     { /* old "use short scramble" packet */
        auth_plugin_name= old_password_plugin_name;
        mpvio.cached_server_reply.pkt= (uchar*)mysql->scramble;
        mpvio.cached_server_reply.pkt_len= SCRAMBLE_LENGTH + 1;
      }
      else
!     { /* new "use different plugin" packet */
        uint len;
        auth_plugin_name= (char*)mysql->net.read_pos + 1;
!       len= strlen(auth_plugin_name);
        mpvio.cached_server_reply.pkt_len= pkt_length - len - 2;
        mpvio.cached_server_reply.pkt= mysql->net.read_pos + len + 2;
      }
--- 2477,2494 ----
    {
      /* The server asked to use a different authentication plugin */
      if (pkt_length == 1)
!     {
!       /* old "use short scramble" packet */
        auth_plugin_name= old_password_plugin_name;
        mpvio.cached_server_reply.pkt= (uchar*)mysql->scramble;
        mpvio.cached_server_reply.pkt_len= SCRAMBLE_LENGTH + 1;
      }
      else
!     {
!       /* new "use different plugin" packet */
        uint len;
        auth_plugin_name= (char*)mysql->net.read_pos + 1;
!       len= strlen(auth_plugin_name); /* safe as my_net_read always appends \0 */
        mpvio.cached_server_reply.pkt_len= pkt_length - len - 2;
        mpvio.cached_server_reply.pkt= mysql->net.read_pos + len + 2;
      }
***************
*** 2496,2503 ****
  {
    char          buff[NAME_LEN+USERNAME_LENGTH+100];
    int           scramble_data_len, pkt_scramble_len;
!   char          *end,*host_info, *server_version_end, *pkt_end, *scramble_data;
!   char          *scramble_plugin;
    my_socket     sock;
    in_addr_t     ip_addr;
    struct        sockaddr_in sock_addr;
--- 2539,2546 ----
  {
    char          buff[NAME_LEN+USERNAME_LENGTH+100];
    int           scramble_data_len, pkt_scramble_len;
!   char          *end, *host_info=0, *server_version_end, *pkt_end;
!   char          *scramble_data, *scramble_plugin;
    my_socket     sock;
    in_addr_t     ip_addr;
    struct        sockaddr_in sock_addr;
***************
*** 2898,2903 ****
      {
        scramble_data_len= pkt_scramble_len;
        scramble_plugin= scramble_data + scramble_data_len;
      }
      else
      {
--- 2941,2948 ----
      {
        scramble_data_len= pkt_scramble_len;
        scramble_plugin= scramble_data + scramble_data_len;
+       if (scramble_data + scramble_data_len > pkt_end)
+         scramble_data_len= pkt_end - scramble_data;
      }
      else
      {
***************
*** 3665,3676 ****
        mysql->options.client_flag&= ~CLIENT_SSL_VERIFY_SERVER_CERT;
      break;
    case MYSQL_PLUGIN_DIR:
!     extension_free(&mysql->options, plugin_dir);
!     mysql->options.extension->plugin_dir= my_strdup(arg, MYF(MY_WME));
      break;
    case MYSQL_DEFAULT_AUTH:
!     extension_free(&mysql->options, default_auth);
!     mysql->options.extension->default_auth= my_strdup(arg, MYF(MY_WME));
      break;
    default:
      DBUG_RETURN(1);
--- 3710,3719 ----
        mysql->options.client_flag&= ~CLIENT_SSL_VERIFY_SERVER_CERT;
      break;
    case MYSQL_PLUGIN_DIR:
!     extension_set_string(&mysql->options, plugin_dir, arg);
      break;
    case MYSQL_DEFAULT_AUTH:
!     extension_set_string(&mysql->options, default_auth, arg);
      break;
    default:
      DBUG_RETURN(1);
***************
*** 3876,3911 ****
    return CR_OK;
  }
  
- static auth_plugin_t native_password_client_plugin=
- {
-   MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
-   MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION,
-   native_password_plugin_name,
-   "R.J.Silk, Sergei Golubchik",
-   "Native MySQL authentication",
-   {1, 0, 0},
-   NULL,
-   NULL,
-   native_password_auth_client
- };
- 
- static auth_plugin_t old_password_client_plugin=
- {
-   MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
-   MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION,
-   old_password_plugin_name,
-   "R.J.Silk, Sergei Golubchik",
-   "Old MySQL-3.23 authentication",
-   {1, 0, 0},
-   NULL,
-   NULL,
-   old_password_auth_client
- };
- 
- struct st_mysql_client_plugin *mysql_client_builtins[]=
- {
-   (struct st_mysql_client_plugin *)&native_password_client_plugin,
-   (struct st_mysql_client_plugin *)&old_password_client_plugin,
-   0
- };
- 
--- 3919,3921 ----
    return CR_OK;
  }
  

=== modified file 'sql-common/client_plugin.c'
*** sql-common/client_plugin.c	2010-03-11 12:33:22 +0000
--- sql-common/client_plugin.c	2010-03-26 11:32:46 +0000
***************
*** 1,5 ****
  /* Copyright (C) 2010 Monty Program Ab
! /* Copyright (C) 2010 Monty Program Ab
  
     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
--- 1,5 ----
  /* Copyright (C) 2010 Monty Program Ab
! /* Copyright (C) 2010 Sergei Golubchik and Monty Program Ab
  
     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
***************
*** 209,226 ****
    char *plugs, *free_env, *s= getenv("LIBMYSQL_PLUGINS");
  
    /* no plugins to load */
!   if(!s)
      return;
  
    free_env= plugs= my_strdup(s, MYF(MY_WME));
-   s= NULL;
  
    do {
      if ((s= strchr(plugs, ';')))
        *s= '\0';
      mysql_load_plugin(mysql, plugs, -1, 0);
!     if(s)
!       plugs= ++s;
    } while (s);
  
    my_free(free_env, MYF(0));
--- 209,224 ----
    char *plugs, *free_env, *s= getenv("LIBMYSQL_PLUGINS");
  
    /* no plugins to load */
!   if (!s)
      return;
  
    free_env= plugs= my_strdup(s, MYF(MY_WME));
  
    do {
      if ((s= strchr(plugs, ';')))
        *s= '\0';
      mysql_load_plugin(mysql, plugs, -1, 0);
!     plugs= s + 1;
    } while (s);
  
    my_free(free_env, MYF(0));

=== modified file 'sql/mysqld.cc'
*** sql/mysqld.cc	2010-03-15 17:35:32 +0000
--- sql/mysqld.cc	2010-03-26 11:32:46 +0000
***************
*** 3491,3497 ****
    if (init_errmessage())        /* Read error messages from file */
      return 1;
    init_client_errs();
!   mysql_library_init(un,us,ed); /* for replication */
    lex_init();
    if (item_create_init())
      return 1;
--- 3491,3497 ----
    if (init_errmessage())        /* Read error messages from file */
      return 1;
    init_client_errs();
!   mysql_library_init(never,never,never); /* for replication */
    lex_init();
    if (item_create_init())
      return 1;

=== modified file 'sql/sql_acl.cc'
*** sql/sql_acl.cc	2010-03-22 18:09:47 +0000
--- sql/sql_acl.cc	2010-03-26 11:32:46 +0000
***************
*** 664,671 ****
                                  user.user ? user.user : "",
                                  user.host.hostname ? user.host.hostname : "");
              }
              user.plugin.str= tmpstr;
              user.plugin.length= strlen(tmpstr);
              user.auth_string.str= get_field(&mem, table->field[next_field++]);
              if (!user.auth_string.str)
                user.auth_string.str= const_cast<char*>("");
--- 664,681 ----
                                  user.user ? user.user : "",
                                  user.host.hostname ? user.host.hostname : "");
              }
+             if (my_strcasecmp(system_charset_info, tmpstr,
+                               native_password_plugin_name.str) == 0)
+               user.plugin= native_password_plugin_name;
+             else
+             if (my_strcasecmp(system_charset_info, tmpstr,
+                               old_password_plugin_name.str) == 0)
+               user.plugin= old_password_plugin_name;
+             else
+             {
                user.plugin.str= tmpstr;
                user.plugin.length= strlen(tmpstr);
+             }
              user.auth_string.str= get_field(&mem, table->field[next_field++]);
              if (!user.auth_string.str)
                user.auth_string.str= const_cast<char*>("");
***************
*** 6828,6839 ****
  
  /* few defines to have less ifdef's in the code below */
  #ifdef EMBEDDED_LIBRARY
  #ifdef NO_EMBEDDED_ACCESS_CHECKS
  #define initialized 0
  #define decrease_user_connections(X)        /* nothing */
  #define check_for_max_user_connections(X,Y)   0
  #endif
- #undef HAVE_OPENSSL
  #endif
  #ifndef HAVE_OPENSSL
  #define ssl_acceptor_fd 0
--- 6838,6849 ----
  
  /* few defines to have less ifdef's in the code below */
  #ifdef EMBEDDED_LIBRARY
+ #undef HAVE_OPENSSL
  #ifdef NO_EMBEDDED_ACCESS_CHECKS
  #define initialized 0
  #define decrease_user_connections(X)        /* nothing */
  #define check_for_max_user_connections(X,Y)   0
  #endif
  #endif
  #ifndef HAVE_OPENSSL
  #define ssl_acceptor_fd 0
***************
*** 6929,6934 ****
                                           const char *data, uint data_len)
  {
    DBUG_ASSERT(mpvio->status == MPVIO_EXT::FAILURE);
  
    THD *thd= mpvio->thd;
    char *buff= (char *)my_alloca(1 + SERVER_VERSION_LENGTH + data_len + 64);
--- 6939,6945 ----
                                           const char *data, uint data_len)
  {
    DBUG_ASSERT(mpvio->status == MPVIO_EXT::FAILURE);
+   DBUG_ASSERT(data_len <= 255);
  
    THD *thd= mpvio->thd;
    char *buff= (char *)my_alloca(1 + SERVER_VERSION_LENGTH + data_len + 64);
***************
*** 7018,7025 ****
    return res;
  }
  
  
! static uchar switch_plugin_request_buf[]= { 254 };
  
  /**
    sends a "change plugin" packet, requesting a client to restart authentication
--- 7029,7059 ----
    return res;
  }
  
+ static bool secure_auth(THD *thd)
+ {
+   if (!opt_secure_auth)
+     return 0;
  
!   /*
!     If the server is running in secure auth mode, short scrambles are 
!     forbidden. Extra juggling to report the same error as the old code.
!   */
!   if (thd->client_capabilities & CLIENT_PROTOCOL_41)
!   {
!     my_error(ER_SERVER_IS_IN_SECURE_AUTH_MODE, MYF(0),
!              thd->security_ctx->user,
!              thd->security_ctx->host_or_ip);
!     general_log_print(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE),
!                       thd->security_ctx->user,
!                       thd->security_ctx->host_or_ip);
!   }
!   else
!   {
!     my_error(ER_NOT_SUPPORTED_AUTH_MODE, MYF(0));
!     general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
!   }
!   return 1;
! }
  
  /**
    sends a "change plugin" packet, requesting a client to restart authentication
***************
*** 7049,7054 ****
    DBUG_ASSERT(mpvio->packets_written == 1);
    DBUG_ASSERT(mpvio->packets_read == 1);
    NET *net= &mpvio->thd->net;
  
    mpvio->status= MPVIO_EXT::FAILURE; // the status is no longer RESTART
  
--- 7083,7090 ----
    DBUG_ASSERT(mpvio->packets_written == 1);
    DBUG_ASSERT(mpvio->packets_read == 1);
    NET *net= &mpvio->thd->net;
+   static uchar switch_plugin_request_buf[]= { 254 };
+ 
  
    mpvio->status= MPVIO_EXT::FAILURE; // the status is no longer RESTART
  
***************
*** 7061,7074 ****
      we send an old "short 4.0 scramble request", if we need to request a
      client to use 4.0 auth plugin (short scramble) and the scramble was
      already sent to the client
    */
    bool switch_from_long_to_short_scramble=
!     my_strcasecmp(system_charset_info, native_password_plugin_name.str,
!                   mpvio->cached_client_reply.plugin) == 0 &&
      client_auth_plugin == old_password_plugin_name.str;
  
    if (switch_from_long_to_short_scramble)
!     return my_net_write(net, switch_plugin_request_buf, 1) ||
             net_flush(net);
  
    /*
--- 7097,7114 ----
      we send an old "short 4.0 scramble request", if we need to request a
      client to use 4.0 auth plugin (short scramble) and the scramble was
      already sent to the client
+ 
+     below, cached_client_reply.plugin is the plugin name that client has used,
+     client_auth_plugin is derived from mysql.user table, for the given
+     user account, it's the plugin that the client need to use to login.
    */
    bool switch_from_long_to_short_scramble=
!     native_password_plugin_name.str == mpvio->cached_client_reply.plugin &&
      client_auth_plugin == old_password_plugin_name.str;
  
    if (switch_from_long_to_short_scramble)
!     return secure_auth(mpvio->thd) ||
!            my_net_write(net, switch_plugin_request_buf, 1) ||
             net_flush(net);
  
    /*
***************
*** 7077,7084 ****
      ask an old 4.0 client to use the new 4.1 authentication protocol.
    */
    bool switch_from_short_to_long_scramble=
!     my_strcasecmp(system_charset_info, old_password_plugin_name.str,
!                   mpvio->cached_client_reply.plugin) == 0 &&
      client_auth_plugin == native_password_plugin_name.str;
  
    if (switch_from_short_to_long_scramble)
--- 7117,7123 ----
      ask an old 4.0 client to use the new 4.1 authentication protocol.
    */
    bool switch_from_short_to_long_scramble=
!     old_password_plugin_name.str == mpvio->cached_client_reply.plugin &&
      client_auth_plugin == native_password_plugin_name.str;
  
    if (switch_from_short_to_long_scramble)
***************
*** 7111,7122 ****
  
  static bool find_mpvio_user(MPVIO_EXT *mpvio, Security_context *sctx)
  {
    pthread_mutex_lock(&acl_cache->lock);
    for (uint i=0 ; i < acl_users.elements ; i++)
    {
      ACL_USER *acl_user_tmp= dynamic_element(&acl_users,i,ACL_USER*);
!     if (!acl_user_tmp->user || (!strcmp(sctx->user, acl_user_tmp->user) &&
!         compare_hostname(&acl_user_tmp->host, sctx->host, sctx->ip)))
      {
        mpvio->acl_user= acl_user_tmp->copy(mpvio->thd->mem_root);
        break;
--- 7150,7163 ----
  
  static bool find_mpvio_user(MPVIO_EXT *mpvio, Security_context *sctx)
  {
+   DBUG_ASSERT(mpvio->acl_user == 0);
+ 
    pthread_mutex_lock(&acl_cache->lock);
    for (uint i=0 ; i < acl_users.elements ; i++)
    {
      ACL_USER *acl_user_tmp= dynamic_element(&acl_users,i,ACL_USER*);
!     if ((!acl_user_tmp->user || !strcmp(sctx->user, acl_user_tmp->user)) &&
!         compare_hostname(&acl_user_tmp->host, sctx->host, sctx->ip))
      {
        mpvio->acl_user= acl_user_tmp->copy(mpvio->thd->mem_root);
        break;
***************
*** 7131,7142 ****
    }
  
    /* user account requires non-default plugin and the client is too old */
!   if (my_strcasecmp(system_charset_info, mpvio->acl_user->plugin.str,
!                                          native_password_plugin_name.str) &&
!       my_strcasecmp(system_charset_info, mpvio->acl_user->plugin.str,
!                                          old_password_plugin_name.str) &&
        !(mpvio->thd->client_capabilities & CLIENT_PLUGIN_AUTH))
    {
      my_error(ER_NOT_SUPPORTED_AUTH_MODE, MYF(0));
      general_log_print(mpvio->thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
      return 1;
--- 7172,7185 ----
    }
  
    /* user account requires non-default plugin and the client is too old */
!   if (mpvio->acl_user->plugin.str != native_password_plugin_name.str &&
!       mpvio->acl_user->plugin.str != old_password_plugin_name.str &&
        !(mpvio->thd->client_capabilities & CLIENT_PLUGIN_AUTH))
    {
+     DBUG_ASSERT(my_strcasecmp(system_charset_info, mpvio->acl_user->plugin.str,
+                               native_password_plugin_name.str));
+     DBUG_ASSERT(my_strcasecmp(system_charset_info, mpvio->acl_user->plugin.str,
+                               old_password_plugin_name.str));
      my_error(ER_NOT_SUPPORTED_AUTH_MODE, MYF(0));
      general_log_print(mpvio->thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
      return 1;
***************
*** 7203,7219 ****
  
    char *ptr= db + db_len + 1;
  
-   /* Convert database and user names to utf8 */
-   db_buff[db_len= copy_and_convert(db_buff, sizeof(db_buff)-1,
-                                    system_charset_info, db, db_len,
-                                    thd->charset(), &dummy_errors)]= 0;
-   db= db_buff;
- 
-   user_buff[user_len= copy_and_convert(user_buff, sizeof(user_buff)-1,
-                                        system_charset_info, user, user_len,
-                                        thd->charset(), &dummy_errors)]= '\0';
-   user= user_buff;
- 
    if (ptr+1 < end)
    {
      uint cs_number= uint2korr(ptr);
--- 7246,7251 ----
  
    char *ptr= db + db_len + 1;
  
    if (ptr+1 < end)
    {
      uint cs_number= uint2korr(ptr);
***************
*** 7221,7234 ****
      thd->update_charset();
    }
  
!   if (!(sctx->user= my_strdup(user, MYF(MY_WME))))
      return 1;
  
    /* Clear variables that are allocated */
    thd->user_connect= 0;
    strmake(sctx->priv_user, sctx->user, USERNAME_LENGTH);
  
!   if (thd->make_lex_string(&mpvio->db, db, db_len, 0) == 0)
      return 1; /* The error is set by make_lex_string(). */
  
    /*
--- 7253,7274 ----
      thd->update_charset();
    }
  
!   /* Convert database and user names to utf8 */
!   db_len= copy_and_convert(db_buff, sizeof(db_buff)-1, system_charset_info,
!                            db, db_len, thd->charset(), &dummy_errors);
! 
!   user_len= copy_and_convert(user_buff, sizeof(user_buff)-1,
!                              system_charset_info, user, user_len,
!                              thd->charset(), &dummy_errors);
! 
!   if (!(sctx->user= my_strndup(user_buff, user_len, MYF(MY_WME))))
      return 1;
  
    /* Clear variables that are allocated */
    thd->user_connect= 0;
    strmake(sctx->priv_user, sctx->user, USERNAME_LENGTH);
  
!   if (thd->make_lex_string(&mpvio->db, db_buff, db_len, 0) == 0)
      return 1; /* The error is set by make_lex_string(). */
  
    /*
***************
*** 7260,7265 ****
      }
    }
    else
      if (thd->client_capabilities & CLIENT_SECURE_CONNECTION)
        client_plugin= native_password_plugin_name.str;
      else
--- 7300,7306 ----
      }
    }
    else
+   {
      if (thd->client_capabilities & CLIENT_SECURE_CONNECTION)
        client_plugin= native_password_plugin_name.str;
      else
***************
*** 7274,7279 ****
        if (mpvio->acl_user->auth_string.length == 0)
          mpvio->acl_user->plugin= old_password_plugin_name;
      }
    
    /* remember the data part of the packet, to present it to plugin in read_packet() */
    mpvio->cached_client_reply.pkt= passwd;
--- 7315,7321 ----
        if (mpvio->acl_user->auth_string.length == 0)
          mpvio->acl_user->plugin= old_password_plugin_name;
      }
+   }
    
    /* remember the data part of the packet, to present it to plugin in read_packet() */
    mpvio->cached_client_reply.pkt= passwd;
***************
*** 7362,7368 ****
  
    char *user= end;
    char *passwd= strend(user)+1;
!   uint user_len= passwd - user - 1;
    char *db= passwd;
    char db_buff[NAME_LEN + 1];           // buffer to store db in utf8
    char user_buff[USERNAME_LENGTH + 1];  // buffer to store user in utf8
--- 7404,7410 ----
  
    char *user= end;
    char *passwd= strend(user)+1;
!   uint user_len= passwd - user - 1, db_len;
    char *db= passwd;
    char db_buff[NAME_LEN + 1];           // buffer to store db in utf8
    char user_buff[USERNAME_LENGTH + 1];  // buffer to store user in utf8
***************
*** 7380,7389 ****
    */
    uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
                     (uchar)(*passwd++) : strlen(passwd);
!   db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
!         db + passwd_len + 1 : 0;
    /* strlen() can't be easily deleted without changing protocol */
!   uint db_len= db ? strlen(db) : 0;
  
    if (passwd + passwd_len + db_len > (char *)net->read_pos + pkt_len)
      return packet_error;
--- 7422,7439 ----
    */
    uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
                     (uchar)(*passwd++) : strlen(passwd);
! 
!   if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB)
!   {
!     db= db + passwd_len + 1;
    /* strlen() can't be easily deleted without changing protocol */
!     db_len= strlen(db);
!   }
!   else
!   {
!     db= 0;
!     db_len= 0;
!   }
  
    if (passwd + passwd_len + db_len > (char *)net->read_pos + pkt_len)
      return packet_error;
***************
*** 7393,7414 ****
    /* Since 4.1 all database names are stored in utf8 */
    if (db)
    {
!     db_buff[db_len= copy_and_convert(db_buff, sizeof(db_buff)-1,
!                                      system_charset_info,
!                                      db, db_len,
!                                      thd->charset(), &dummy_errors)]= 0;
      db= db_buff;
    }
  
!   user_buff[user_len= copy_and_convert(user_buff, sizeof(user_buff)-1,
                                         system_charset_info, user, user_len,
!                                        thd->charset(), &dummy_errors)]= '\0';
    user= user_buff;
  
    /* If username starts and ends in "'", chop them off */
    if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'')
    {
-     user[user_len-1]= 0;
      user++;
      user_len-= 2;
    }
--- 7443,7461 ----
    /* Since 4.1 all database names are stored in utf8 */
    if (db)
    {
!     db_len= copy_and_convert(db_buff, sizeof(db_buff)-1, system_charset_info,
!                              db, db_len, thd->charset(), &dummy_errors);
      db= db_buff;
    }
  
!   user_len= copy_and_convert(user_buff, sizeof(user_buff)-1,
                                         system_charset_info, user, user_len,
!                              thd->charset(), &dummy_errors);
    user= user_buff;
  
    /* If username starts and ends in "'", chop them off */
    if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'')
    {
      user++;
      user_len-= 2;
    }
***************
*** 7419,7425 ****
      return packet_error; /* The error is set by make_lex_string(). */
    if (sctx->user)
      x_free(sctx->user);
!   if (!(sctx->user= my_strdup(user, MYF(MY_WME))))
      return packet_error; /* The error is set by my_strdup(). */
  
    /*
--- 7466,7472 ----
      return packet_error; /* The error is set by make_lex_string(). */
    if (sctx->user)
      x_free(sctx->user);
!   if (!(sctx->user= my_strndup(user, user_len, MYF(MY_WME))))
      return packet_error; /* The error is set by my_strdup(). */
  
    /*
***************
*** 7446,7451 ****
        return packet_error;
    }
    else
      if (thd->client_capabilities & CLIENT_SECURE_CONNECTION)
        client_plugin= native_password_plugin_name.str;
      else
--- 7493,7499 ----
        return packet_error;
    }
    else
+   {
      if (thd->client_capabilities & CLIENT_SECURE_CONNECTION)
        client_plugin= native_password_plugin_name.str;
      else
***************
*** 7460,7465 ****
        if (mpvio->acl_user->auth_string.length == 0)
          mpvio->acl_user->plugin= old_password_plugin_name;
      }
    
    /*
      if the acl_user needs a different plugin to authenticate
--- 7508,7514 ----
        if (mpvio->acl_user->auth_string.length == 0)
          mpvio->acl_user->plugin= old_password_plugin_name;
      }
+   }
    
    /*
      if the acl_user needs a different plugin to authenticate
***************
*** 7574,7580 ****
    {
      /*
        plugin wants to read the data without sending anything first.
!       send an empty packet, to start a handshake
      */
      if (server_mpvio_write_packet(mpvio, 0, 0))
        pkt_len= packet_error;
--- 7624,7630 ----
    {
      /*
        plugin wants to read the data without sending anything first.
!       send an empty packet to force a server handshake packet to be sent
      */
      if (server_mpvio_write_packet(mpvio, 0, 0))
        pkt_len= packet_error;
***************
*** 7661,7667 ****
  }
  
  
! static int acl_check_ssl(THD *thd, ACL_USER *acl_user)
  {
  #if defined(HAVE_OPENSSL)
    Vio *vio=thd->net.vio;
--- 7711,7717 ----
  }
  
  
! static bool acl_check_ssl(THD *thd, ACL_USER *acl_user)
  {
  #if defined(HAVE_OPENSSL)
    Vio *vio=thd->net.vio;
***************
*** 7766,7771 ****
    return 1;
  }
  
  
  /**
    Perform the handshake, authorize the client and update thd sctx variables.
--- 7816,7871 ----
    return 1;
  }
  
+ static int do_auth_once(THD *thd, LEX_STRING *auth_plugin_name,
+                         MPVIO_EXT *mpvio)
+ {
+   int res= CR_OK, old_status= MPVIO_EXT::FAILURE;
+   bool unlock_plugin= false;
+   plugin_ref plugin;
+ 
+   if (auth_plugin_name->str == native_password_plugin_name.str)
+     plugin= native_password_plugin;
+   else
+ #ifndef EMBEDDED_LIBRARY
+   if (auth_plugin_name->str == old_password_plugin_name.str)
+     plugin= old_password_plugin;
+   else
+   if ((plugin= my_plugin_lock_by_name(thd, auth_plugin_name,
+                                       MYSQL_AUTHENTICATION_PLUGIN)))
+     unlock_plugin= true;
+ #endif
+ 
+   mpvio->plugin= plugin;
+   old_status= mpvio->status;
+ 
+   if (plugin)
+   {
+     st_mysql_auth *auth= (st_mysql_auth*)plugin_decl(plugin)->info;
+     res= auth->authenticate_user(mpvio, &mpvio->auth_info);
+ 
+     if (unlock_plugin)
+       plugin_unlock(thd, plugin);
+   }
+   else
+   {
+     /* Server cannot load the required plugin. */
+     my_error(ER_PLUGIN_IS_NOT_LOADED, MYF(0), auth_plugin_name->str);
+     res= CR_ERROR;
+   }
+ 
+   /*
+     If the status was MPVIO_EXT::RESTART before the authenticate_user() call
+     it can never be MPVIO_EXT::RESTART after the call, because any call
+     to write_packet() or read_packet() will reset the status.
+ 
+     But (!) if a plugin never called a read_packet() or write_packet(), the
+     status will stay unchanged. We'll fix it, by resetting the status here.
+   */
+   if (old_status == MPVIO_EXT::RESTART && mpvio->status == MPVIO_EXT::RESTART)
+     mpvio->status= MPVIO_EXT::FAILURE; // reset to the default
+ 
+   return res;
+ }
  
  /**
    Perform the handshake, authorize the client and update thd sctx variables.
***************
*** 7782,7798 ****
    @retval 1  error
  */
  
! int acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len)
  {
!   DBUG_ENTER("acl_authenticate");
!   int res= CR_OK, old_status= MPVIO_EXT::FAILURE;
!   plugin_ref plugin;
    MPVIO_EXT mpvio;
-   st_mysql_auth *auth;
    LEX_STRING *auth_plugin_name= default_auth_plugin_name;
-   bool unlock_plugin;
    enum  enum_server_command command= com_change_user_pkt_len ? COM_CHANGE_USER
                                                               : COM_CONNECT;
  
    compile_time_assert(MYSQL_USERNAME_LENGTH == USERNAME_LENGTH);
  
--- 7882,7895 ----
    @retval 1  error
  */
  
! bool acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len)
  {
!   int res= CR_OK;
    MPVIO_EXT mpvio;
    LEX_STRING *auth_plugin_name= default_auth_plugin_name;
    enum  enum_server_command command= com_change_user_pkt_len ? COM_CHANGE_USER
                                                               : COM_CONNECT;
+   DBUG_ENTER("acl_authenticate");
  
    compile_time_assert(MYSQL_USERNAME_LENGTH == USERNAME_LENGTH);
  
***************
*** 7804,7812 ****
    mpvio.connect_errors= connect_errors;
    mpvio.status= MPVIO_EXT::FAILURE;
  
!   if (com_change_user_pkt_len == 0)
!     thd->scramble[SCRAMBLE_LENGTH]= 1; // it means - there is no scramble yet
!   else
    {
      mpvio.packets_written++; // pretend that a server handshake packet was sent
      mpvio.packets_read++;    // take COM_CHANGE_USER packet into account
--- 7901,7907 ----
    mpvio.connect_errors= connect_errors;
    mpvio.status= MPVIO_EXT::FAILURE;
  
!   if (command == COM_CHANGE_USER)
    {
      mpvio.packets_written++; // pretend that a server handshake packet was sent
      mpvio.packets_read++;    // take COM_CHANGE_USER packet into account
***************
*** 7816,7882 ****
  
      DBUG_ASSERT(mpvio.status == MPVIO_EXT::RESTART ||
                  mpvio.status == MPVIO_EXT::SUCCESS);
-     /*
-       we skip the first step of the authentication -
-       the one that starts a default plugin, sends the handshake packet with the
-       scramble and reads the packet with the user name.
-       in COM_CHANGE_USER the client already has the scramble and we already
-       know the user name
-     */
-     goto skip_first;
    }
- 
- retry:
-   unlock_plugin= false;
-   if (auth_plugin_name->str == native_password_plugin_name.str)
-     plugin= native_password_plugin;
    else
- #ifndef EMBEDDED_LIBRARY
-   if (auth_plugin_name->str == old_password_plugin_name.str)
-     plugin= old_password_plugin;
-   else
-   if ((plugin= my_plugin_lock_by_name(thd, auth_plugin_name,
-                                       MYSQL_AUTHENTICATION_PLUGIN)))
-     unlock_plugin= true;
-   else
- #endif
    {
!     /* Server cannot load required plugin. */
!     my_error(ER_PLUGIN_IS_NOT_LOADED, MYF(0), auth_plugin_name->str);
!     DBUG_RETURN(1);
!   }
  
-   mpvio.plugin= plugin;
-   auth= (st_mysql_auth*)plugin_decl(plugin)->info;
- 
-   old_status= mpvio.status;
-   res= auth->authenticate_user(&mpvio, &mpvio.auth_info);
- 
-   if (unlock_plugin)
-     plugin_unlock(thd, plugin);
- 
- skip_first:
    /*
!     restart the authentication, if needed.
  
!     Note, that we only trust RESTART status if it wasn't set before
!     the authentication. If it was - it can never be set after the call, as
!     any read_packet() or write_packet() would've reset it. So, if it's
!     was set before authenticate_user() and we see it here, it simply means
!     that there was a restart, but a plugin never called read_packet() or
!     write_packet() and what we see is the old status from before the
!     authenticate_user() call.
    */
    if (mpvio.status == MPVIO_EXT::RESTART)
    {
-     if (old_status == MPVIO_EXT::RESTART)
-       mpvio.status= MPVIO_EXT::FAILURE; // reset to the default
-     else
-     {
        DBUG_ASSERT(mpvio.acl_user);
        auth_plugin_name= &mpvio.acl_user->plugin;
!       goto retry;
!     }
    }
  
    Security_context *sctx= thd->security_ctx;
--- 7911,7943 ----
  
      DBUG_ASSERT(mpvio.status == MPVIO_EXT::RESTART ||
                  mpvio.status == MPVIO_EXT::SUCCESS);
    }
    else
    {
!     /* mark the thd as having no scramble yet */
!     thd->scramble[SCRAMBLE_LENGTH]= 1;
  
    /*
!       perform the first authentication attempt, with the default plugin.
!       This sends the server handshake packet, reads the client reply
!       with a user name, and performs the authentication if everyone has used
!       the correct plugin.
!     */
!     res= do_auth_once(thd, auth_plugin_name, &mpvio);
!   }
  
!   /*
!     retry the authentication, if - after receiving the user name -
!     we found that we need to switch to a non-default plugin
    */
    if (mpvio.status == MPVIO_EXT::RESTART)
    {
      DBUG_ASSERT(mpvio.acl_user);
+     DBUG_ASSERT(command == COM_CHANGE_USER ||
+                 my_strcasecmp(system_charset_info, auth_plugin_name->str,
+                               mpvio.acl_user->plugin.str));
      auth_plugin_name= &mpvio.acl_user->plugin;
!     res= do_auth_once(thd, auth_plugin_name, &mpvio);
    }
  
    Security_context *sctx= thd->security_ctx;
***************
*** 7995,8002 ****
        /* mysql_change_db() has pushed the error message. */
        if (thd->user_connect)
        {
-         decrease_user_connections(thd->user_connect);
          status_var_increment(thd->status_var.access_denied_errors);
          thd->user_connect= 0;
        }
        DBUG_RETURN(1);
--- 8056,8063 ----
        /* mysql_change_db() has pushed the error message. */
        if (thd->user_connect)
        {
          status_var_increment(thd->status_var.access_denied_errors);
+         decrease_user_connections(thd->user_connect);
          thd->user_connect= 0;
        }
        DBUG_RETURN(1);
***************
*** 8036,8059 ****
    MPVIO_EXT *mpvio=(MPVIO_EXT*)vio;
    THD *thd=mpvio->thd;
  
!   /*
!     let's check if the client has got the scramble already.
!     That could've happened if another plugin has started the authentication,
!     has sent the scramble, but after reading the user name the server has found
!     that this particular user should be handled by this particular plugin.
!   */
! 
    if (thd->scramble[SCRAMBLE_LENGTH])
!   {
!     /* no scramble was sent to the client yet, do it now */
!     create_random_string(thd->scramble,
!                          pkt_len= SCRAMBLE_LENGTH, &thd->rand);
!     pkt= (uchar*)thd->scramble;
!     if (mpvio->write_packet(mpvio, pkt, pkt_len + 1))
        return CR_ERROR;
-   }
  
!   /* ok, the client has got the scramble. read the reply and authenticate */
  
    /*
      <digression>
--- 8097,8111 ----
    MPVIO_EXT *mpvio=(MPVIO_EXT*)vio;
    THD *thd=mpvio->thd;
  
!   /* generate the scramble, or reuse the old one */
    if (thd->scramble[SCRAMBLE_LENGTH])
!     create_random_string(thd->scramble, SCRAMBLE_LENGTH, &thd->rand);
! 
!   /* send it to the client */
!   if (mpvio->write_packet(mpvio, (uchar*)thd->scramble, SCRAMBLE_LENGTH + 1))
        return CR_ERROR;
  
!   /* reply and authenticate */
  
    /*
      <digression>
***************
*** 8085,8091 ****
        plugins are involved.
  
        Anyway, it still looks simple from a plugin point of view:
!       "the client has got the scramble, read the reply and authenticate".
        All the magic is transparently handled by the server.
      </digression>
    */
--- 8137,8143 ----
        plugins are involved.
  
        Anyway, it still looks simple from a plugin point of view:
!       "send the scramble, read the reply and authenticate".
        All the magic is transparently handled by the server.
      </digression>
    */
***************
*** 8120,8136 ****
    MPVIO_EXT *mpvio=(MPVIO_EXT*)vio;
    THD *thd=mpvio->thd;
  
    if (thd->scramble[SCRAMBLE_LENGTH])
!   {
!     /* no scramble was sent to the client yet, do it now */
!     create_random_string(thd->scramble,
!                          pkt_len= SCRAMBLE_LENGTH, &thd->rand);
!     pkt= (uchar*)thd->scramble;
!     if (mpvio->write_packet(mpvio, pkt, pkt_len))
        return CR_ERROR;
-   }
  
!   /* ok, the client has got the scramble. read the reply and authenticate */
    if ((pkt_len= mpvio->read_packet(mpvio, &pkt)) < 0)
      return CR_ERROR;
  
--- 8172,8186 ----
    MPVIO_EXT *mpvio=(MPVIO_EXT*)vio;
    THD *thd=mpvio->thd;
  
+   /* generate the scramble, or reuse the old one */
    if (thd->scramble[SCRAMBLE_LENGTH])
!     create_random_string(thd->scramble, SCRAMBLE_LENGTH, &thd->rand);
! 
!   /* send it to the client */
!   if (mpvio->write_packet(mpvio, (uchar*)thd->scramble, SCRAMBLE_LENGTH + 1))
        return CR_ERROR;
  
!   /* read the reply and authenticate */
    if ((pkt_len= mpvio->read_packet(mpvio, &pkt)) < 0)
      return CR_ERROR;
  
***************
*** 8149,8176 ****
    if (pkt_len == 0) /* no password */
      return info->auth_string[0] ? CR_ERROR : CR_OK;
  
!   /*
!     If the server is running in secure auth mode, short scrambles are 
!     forbidden. Extra juggling to report the same error as the old code.
!   */
!   if (opt_secure_auth)
!   {
!     if (thd->client_capabilities & CLIENT_PROTOCOL_41)
!     {
!       my_error(ER_SERVER_IS_IN_SECURE_AUTH_MODE, MYF(0),
!                thd->security_ctx->user,
!                thd->security_ctx->host_or_ip);
!       general_log_print(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE),
!                         thd->security_ctx->user,
!                         thd->security_ctx->host_or_ip);
!     }
!     else
!     {
!       my_error(ER_NOT_SUPPORTED_AUTH_MODE, MYF(0));
!       general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
!     }
      return CR_ERROR;
-   }
  
    info->password_used = 1;
  
--- 8199,8206 ----
    if (pkt_len == 0) /* no password */
      return info->auth_string[0] ? CR_ERROR : CR_OK;
  
!   if (secure_auth(thd))
      return CR_ERROR;
  
    info->password_used = 1;
  

=== modified file 'sql/sql_acl.h'
*** sql/sql_acl.h	2010-02-19 08:18:09 +0000
--- sql/sql_acl.h	2010-03-26 11:32:46 +0000
***************
*** 169,175 ****
  void acl_free(bool end=0);
  ulong acl_get(const char *host, const char *ip,
                const char *user, const char *db, my_bool db_is_pattern);
! int acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len);
  bool acl_getroot(Security_context *sctx, char *user, char *host,
                   char *ip, char *db);
  bool acl_check_host(const char *host, const char *ip);
--- 169,175 ----
  void acl_free(bool end=0);
  ulong acl_get(const char *host, const char *ip,
                const char *user, const char *db, my_bool db_is_pattern);
! bool acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len);
  bool acl_getroot(Security_context *sctx, char *user, char *host,
                   char *ip, char *db);
  bool acl_check_host(const char *host, const char *ip);

=== modified file 'sql/sql_parse.cc'
*** sql/sql_parse.cc	2010-03-19 20:29:42 +0000
--- sql/sql_parse.cc	2010-03-26 11:32:46 +0000
***************
*** 1115,1122 ****
        x_free(thd->security_ctx->user);
        *thd->security_ctx= save_security_ctx;
        thd->user_connect= save_user_connect;
!       thd->db= save_db;
!       thd->db_length= save_db_length;
        thd->variables.character_set_client= save_character_set_client;
        thd->variables.collation_connection= save_collation_connection;
        thd->variables.character_set_results= save_character_set_results;
--- 1115,1121 ----
        x_free(thd->security_ctx->user);
        *thd->security_ctx= save_security_ctx;
        thd->user_connect= save_user_connect;
!       thd->reset_db(save_db, save_db_length);
        thd->variables.character_set_client= save_character_set_client;
        thd->variables.collation_connection= save_collation_connection;
        thd->variables.character_set_results= save_character_set_results;


References