summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorpeter@mysql.com <>2002-11-30 16:31:58 +0300
committerpeter@mysql.com <>2002-11-30 16:31:58 +0300
commit54ff0efe7cb79c2f3e7acc84f74905d750e51ba0 (patch)
tree8cb72ffc1f46d5e546f302958453ce4a83d26d5e /sql
parent08f51eaedd8fb15eb629614af323d3cdc64dace1 (diff)
downloadmariadb-git-54ff0efe7cb79c2f3e7acc84f74905d750e51ba0.tar.gz
SCRUM: Secure auth
Implement mysql_change_user Get rid of double user search at authentication Some cleanups
Diffstat (limited to 'sql')
-rw-r--r--sql/password.c2
-rw-r--r--sql/sql_acl.cc351
-rw-r--r--sql/sql_acl.h52
-rw-r--r--sql/sql_parse.cc141
4 files changed, 331 insertions, 215 deletions
diff --git a/sql/password.c b/sql/password.c
index b9eb6012354..98cac1e07d0 100644
--- a/sql/password.c
+++ b/sql/password.c
@@ -48,6 +48,8 @@
This authentication needs 2 packet round trips instead of one but it is much
stronger. Now if one will steal mysql database content he will not be able
to break into MySQL.
+
+ New Password handling functions by Peter Zaitsev
*****************************************************************************/
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index d4ca8ed1bc7..3ebd3fdbd3b 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -33,52 +33,6 @@
#include <stdarg.h>
-struct acl_host_and_ip
-{
- char *hostname;
- long ip,ip_mask; // Used with masked ip:s
-};
-
-
-class ACL_ACCESS {
-public:
- ulong sort;
- ulong access;
-};
-
-
-/* ACL_HOST is used if no host is specified */
-
-class ACL_HOST :public ACL_ACCESS
-{
-public:
- acl_host_and_ip host;
- char *db;
-};
-
-
-class ACL_USER :public ACL_ACCESS
-{
-public:
- acl_host_and_ip host;
- uint hostname_length;
- USER_RESOURCES user_resource;
- char *user,*password;
- ulong salt[6]; // New password has longer length
- uint8 pversion; // password version
- enum SSL_type ssl_type;
- const char *ssl_cipher, *x509_issuer, *x509_subject;
-};
-
-
-class ACL_DB :public ACL_ACCESS
-{
-public:
- acl_host_and_ip host;
- char *user,*db;
-};
-
-
class acl_entry :public hash_filo_element
{
public:
@@ -105,6 +59,7 @@ static HASH acl_check_hosts, hash_tables;
static DYNAMIC_ARRAY acl_wild_hosts;
static hash_filo *acl_cache;
static uint grant_version=0;
+static uint priv_version=0; /* Version of priv tables. incremented by acl_init */
static ulong get_access(TABLE *form,uint fieldnr);
static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b);
static ulong get_sort(uint count,...);
@@ -148,7 +103,9 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
{
DBUG_RETURN(0); /* purecov: tested */
}
-
+
+ priv_version++; /* Priveleges updated */
+
/*
To be able to run this from boot, we allocate a temporary THD
*/
@@ -515,15 +472,23 @@ void prepare_scramble(THD* thd, ACL_USER *acl_user,char* prepared_scramble)
/*
Get master privilges for user (priviliges for all tables).
Required before connecting to MySQL
+
+ as we have 2 stage handshake now we cache user not to lookup
+ it second time. At the second stage we do not lookup user in case
+ we already know it;
+
*/
ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
const char *password,const char *message,char **priv_user,
- bool old_ver, USER_RESOURCES *mqh,char* prepared_scramble,int stage)
+ bool old_ver, USER_RESOURCES *mqh,char* prepared_scramble,
+ int stage,uint *cur_priv_version,ACL_USER** hint_user)
{
ulong user_access=NO_ACCESS;
*priv_user=(char*) user;
bool password_correct=0;
+ ACL_USER *acl_user=NULL;
+
DBUG_ENTER("acl_getroot");
bzero(mqh,sizeof(USER_RESOURCES));
@@ -533,159 +498,175 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
DBUG_RETURN((ulong) ~NO_ACCESS); /* purecov: tested */
}
VOID(pthread_mutex_lock(&acl_cache->lock));
-
+
+
/*
Get possible access from user_list. This is or'ed to others not
fully specified
+
+ If we have cached user use it, in other case look it up.
*/
- for (uint i=0 ; i < acl_users.elements ; i++)
- {
- ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
- if (!acl_user->user || !strcmp(user,acl_user->user))
+
+ if (stage && (*cur_priv_version==priv_version))
+ acl_user=*hint_user;
+ else
+ for (uint i=0 ; i < acl_users.elements ; i++)
{
- if (compare_hostname(&acl_user->host,host,ip))
+ ACL_USER *acl_user_search=dynamic_element(&acl_users,i,ACL_USER*);
+ if (!acl_user_search->user || !strcmp(user,acl_user_search->user))
{
- if (!acl_user->password && !*password ||
- (acl_user->password && *password))
- {
- /* Quick check and accept for empty passwords*/
- if (!acl_user->password && !*password)
- password_correct=1;
- else
- {
- /* New version password is checked differently */
- if (acl_user->pversion)
- {
- if (stage) /* We check password only on the second stage */
- {
- if (!validate_password(password,message,acl_user->salt))
- password_correct=1;
- }
- else /* First stage - just prepare scramble */
- prepare_scramble(thd,acl_user,prepared_scramble);
- }
- /* Old way to check password */
- else
- {
- /* Checking the scramble at any stage. First - old clients */
- if (!check_scramble(password,message,acl_user->salt,
- (my_bool) old_ver))
- password_correct=1;
- else /* Password incorrect */
- /* At the first stage - prepare scramble */
- if (!stage)
- prepare_scramble(thd,acl_user,prepared_scramble);
- }
+ if (compare_hostname(&acl_user_search->host,host,ip))
+ {
+ /* Found mathing user */
+ acl_user=acl_user_search;
+ /* Store it as a cache */
+ *hint_user=acl_user;
+ *cur_priv_version=priv_version;
+ break;
+ }
+ }
+ }
+
+
+ /* Now we have acl_user found and may start our checks */
+
+ if (acl_user)
+ {
+ /* Password should present for both or absend for both */
+ if (!acl_user->password && !*password ||
+ (acl_user->password && *password))
+ {
+ /* Quick check and accept for empty passwords*/
+ if (!acl_user->password && !*password)
+ password_correct=1;
+ else /* Normal password presents */
+ {
+ /* New version password is checked differently */
+ if (acl_user->pversion)
+ {
+ if (stage) /* We check password only on the second stage */
+ {
+ if (!validate_password(password,message,acl_user->salt))
+ password_correct=1;
}
- /* If password correct continue with checking other limitations */
- if (password_correct)
- {
-#ifdef HAVE_OPENSSL
- Vio *vio=thd->net.vio;
- /*
- In this point we know that user is allowed to connect
- from given host by given username/password pair. Now
- we check if SSL is required, if user is using SSL and
- 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 to connect */
- user_access=acl_user->access;
- break;
- case SSL_TYPE_ANY: /* Any kind of SSL is good enough */
- if (vio_type(vio) == VIO_TYPE_SSL)
- user_access=acl_user->access;
- break;
- case SSL_TYPE_X509: /* Client should have any valid certificate. */
- /*
- Connections with non-valid certificates are dropped already
- in sslaccept() anyway, so we do not check validity here.
- */
- if (SSL_get_peer_certificate(vio->ssl_))
- user_access=acl_user->access;
- break;
- case SSL_TYPE_SPECIFIED: /* Client should have specified attrib */
- /*
- We do not check for absence of SSL because without SSL it does
- not pass all checks here anyway.
- If cipher name is specified, we compare it to actual cipher in
- use.
- */
- if (acl_user->ssl_cipher)
- {
- DBUG_PRINT("info",("comparing ciphers: '%s' and '%s'",
- acl_user->ssl_cipher,
- SSL_get_cipher(vio->ssl_)));
- if (!strcmp(acl_user->ssl_cipher,SSL_get_cipher(vio->ssl_)))
- user_access=acl_user->access;
- else
- {
- user_access=NO_ACCESS;
- break;
- }
- }
- /* Prepare certificate (if exists) */
- DBUG_PRINT("info",("checkpoint 1"));
- X509* cert=SSL_get_peer_certificate(vio->ssl_);
- DBUG_PRINT("info",("checkpoint 2"));
- /* If X509 issuer is speified, we check it... */
- if (acl_user->x509_issuer)
- {
- DBUG_PRINT("info",("checkpoint 3"));
- char *ptr = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
- DBUG_PRINT("info",("comparing issuers: '%s' and '%s'",
- acl_user->x509_issuer, ptr));
- if (strcmp(acl_user->x509_issuer, ptr))
- {
- user_access=NO_ACCESS;
- free(ptr);
- break;
- }
- user_access=acl_user->access;
- free(ptr);
- }
- DBUG_PRINT("info",("checkpoint 4"));
- /* X509 subject is specified, we check it .. */
- if (acl_user->x509_subject)
- {
- char *ptr= X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
- DBUG_PRINT("info",("comparing subjects: '%s' and '%s'",
- acl_user->x509_subject, ptr));
- if (strcmp(acl_user->x509_subject,ptr))
- user_access=NO_ACCESS;
- else
- user_access=acl_user->access;
- free(ptr);
- }
- break;
- }
-#else /* HAVE_OPENSSL */
- user_access=acl_user->access;
-#endif /* HAVE_OPENSSL */
- *mqh=acl_user->user_resource;
- if (!acl_user->user)
- *priv_user=(char*) ""; // Change to anonymous user /* purecov: inspected */
- break;
- } // correct password
- } // found matching user
+ else /* First stage - just prepare scramble */
+ prepare_scramble(thd,acl_user,prepared_scramble);
+ }
+ /* Old way to check password */
+ else
+ {
+ /* Checking the scramble at any stage. First - old clients */
+ if (!check_scramble(password,message,acl_user->salt,
+ (my_bool) old_ver))
+ password_correct=1;
+ else /* Password incorrect */
+ /* At the first stage - prepare scramble */
+ if (!stage)
+ prepare_scramble(thd,acl_user,prepared_scramble);
+ }
+ }
+ }
+ }
+
+ /* If user not found password_correct will also be zero */
+ if (!password_correct)
+ goto unlock_and_exit;
+
+ /* OK. User found and password checked continue validation */
+
-#ifndef ALLOW_DOWNGRADE_OF_USERS
- break; // Wrong password breaks loop /* purecov: inspected */
-#endif
+#ifdef HAVE_OPENSSL
+ Vio *vio=thd->net.vio;
+ /*
+ In this point we know that user is allowed to connect
+ from given host by given username/password pair. Now
+ we check if SSL is required, if user is using SSL and
+ 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 to connect */
+ user_access=acl_user->access;
+ break;
+ case SSL_TYPE_ANY: /* Any kind of SSL is good enough */
+ if (vio_type(vio) == VIO_TYPE_SSL)
+ user_access=acl_user->access;
+ break;
+ case SSL_TYPE_X509: /* Client should have any valid certificate. */
+ /*
+ Connections with non-valid certificates are dropped already
+ in sslaccept() anyway, so we do not check validity here.
+ */
+ if (SSL_get_peer_certificate(vio->ssl_))
+ user_access=acl_user->access;
+ break;
+ case SSL_TYPE_SPECIFIED: /* Client should have specified attrib */
+ /*
+ We do not check for absence of SSL because without SSL it does
+ not pass all checks here anyway.
+ If cipher name is specified, we compare it to actual cipher in
+ use.
+ */
+ if (acl_user->ssl_cipher)
+ {
+ DBUG_PRINT("info",("comparing ciphers: '%s' and '%s'",
+ acl_user->ssl_cipher,SSL_get_cipher(vio->ssl_)));
+ if (!strcmp(acl_user->ssl_cipher,SSL_get_cipher(vio->ssl_)))
+ user_access=acl_user->access;
+ else
+ {
+ user_access=NO_ACCESS;
+ break;
+ }
+ }
+ /* Prepare certificate (if exists) */
+ DBUG_PRINT("info",("checkpoint 1"));
+ X509* cert=SSL_get_peer_certificate(vio->ssl_);
+ DBUG_PRINT("info",("checkpoint 2"));
+ /* If X509 issuer is speified, we check it... */
+ if (acl_user->x509_issuer)
+ {
+ DBUG_PRINT("info",("checkpoint 3"));
+ char *ptr = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
+ DBUG_PRINT("info",("comparing issuers: '%s' and '%s'",
+ acl_user->x509_issuer, ptr));
+ if (strcmp(acl_user->x509_issuer, ptr))
+ {
+ user_access=NO_ACCESS;
+ free(ptr);
+ break;
}
+ user_access=acl_user->access;
+ free(ptr);
+ }
+ DBUG_PRINT("info",("checkpoint 4"));
+ /* X509 subject is specified, we check it .. */
+ if (acl_user->x509_subject)
+ {
+ char *ptr= X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
+ DBUG_PRINT("info",("comparing subjects: '%s' and '%s'",
+ acl_user->x509_subject, ptr));
+ if (strcmp(acl_user->x509_subject,ptr))
+ user_access=NO_ACCESS;
+ else
+ user_access=acl_user->access;
+ free(ptr);
}
+ break;
}
+#else /* HAVE_OPENSSL */
+ user_access=acl_user->access;
+#endif /* HAVE_OPENSSL */
+ *mqh=acl_user->user_resource;
+ if (!acl_user->user)
+ *priv_user=(char*) ""; // Change to anonymous user /* purecov: inspected */
+
+unlock_and_exit:
VOID(pthread_mutex_unlock(&acl_cache->lock));
DBUG_RETURN(user_access);
}
-/*
-** Functions to add and change user and database privileges when one
-** changes things with GRANT
-*/
-
static byte* check_get_key(ACL_USER *buff,uint *length,
my_bool not_used __attribute__((unused)))
{
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index 66e7d0dad7c..cfab9bf22cf 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -79,6 +79,55 @@
#define fix_rights_for_column(A) (((A) & COL_ACLS) | ((A & ~COL_ACLS) << 7))
#define get_rights_for_column(A) (((A) & COL_ACLS) | ((A & ~COL_ACLS) >> 7))
+/* Classes */
+
+struct acl_host_and_ip
+{
+ char *hostname;
+ long ip,ip_mask; // Used with masked ip:s
+};
+
+
+class ACL_ACCESS {
+public:
+ ulong sort;
+ ulong access;
+};
+
+
+/* ACL_HOST is used if no host is specified */
+
+class ACL_HOST :public ACL_ACCESS
+{
+public:
+ acl_host_and_ip host;
+ char *db;
+};
+
+
+class ACL_USER :public ACL_ACCESS
+{
+public:
+ acl_host_and_ip host;
+ uint hostname_length;
+ USER_RESOURCES user_resource;
+ char *user,*password;
+ ulong salt[6]; // New password has longer length
+ uint8 pversion; // password version
+ enum SSL_type ssl_type;
+ const char *ssl_cipher, *x509_issuer, *x509_subject;
+};
+
+
+class ACL_DB :public ACL_ACCESS
+{
+public:
+ acl_host_and_ip host;
+ char *user,*db;
+};
+
+
+
/* prototypes */
my_bool acl_init(THD *thd, bool dont_read_acl_tables);
@@ -88,7 +137,8 @@ ulong acl_get(const char *host, const char *ip, const char *bin_ip,
const char *user, const char *db);
ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
const char *password,const char *scramble,char **priv_user,
- bool old_ver, USER_RESOURCES *max,char* prepared_scramble, int stage);
+ bool old_ver, USER_RESOURCES *max,char* prepared_scramble,
+ int stage, uint *cur_priv_version, ACL_USER **cached_user);
bool acl_check_host(const char *host, const char *ip);
bool check_change_password(THD *thd, const char *host, const char *user);
bool change_password(THD *thd, const char *host, const char *user,
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 48a02b56c0b..bdb074b304d 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -188,14 +188,16 @@ end:
thd->user, thd->master_access, thd->priv_user, thd->db, thd->db_access
*/
-static bool check_user(THD *thd,enum_server_command command, const char *user,
+static int check_user(THD *thd,enum_server_command command, const char *user,
const char *passwd, const char *db, bool check_count,
bool do_send_error, char* crypted_scramble,int stage,
- bool had_password)
+ bool had_password,uint *cur_priv_version,
+ ACL_USER** hint_user)
{
thd->db=0;
thd->db_length=0;
USER_RESOURCES ur;
+
/* We shall avoid dupplicate user allocations here */
if (!(thd->user))
if (!(thd->user = my_strdup(user, MYF(0))))
@@ -207,7 +209,9 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
passwd, thd->scramble, &thd->priv_user,
protocol_version == 9 ||
!(thd->client_capabilities &
- CLIENT_LONG_PASSWORD),&ur,crypted_scramble,stage);
+ CLIENT_LONG_PASSWORD),&ur,crypted_scramble,
+ stage,cur_priv_version,hint_user);
+
DBUG_PRINT("info",
("Capabilities: %d packet_length: %d Host: '%s' User: '%s' Using password: %s Access: %u db: '%s'",
thd->client_capabilities, thd->max_client_packet_length,
@@ -233,7 +237,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
else
return(-1); // do not report error in special handshake
}
-
+
if (check_count)
{
VOID(pthread_mutex_lock(&LOCK_thread_count));
@@ -261,12 +265,13 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
if (thd->user_connect && thd->user_connect->user_resources.connections &&
check_for_max_user_connections(thd, thd->user_connect))
return -1;
+
if (db && db[0])
{
bool error=test(mysql_change_db(thd,db));
if (error && thd->user_connect)
decrease_user_connections(thd->user_connect);
- return error;
+ return error;
}
else
send_ok(thd); // Ready to handle questions
@@ -616,7 +621,7 @@ check_connections(THD *thd)
/* We can get only old hash at this point */
if (passwd[0] && strlen(passwd)!=SCRAMBLE_LENGTH)
return ER_HANDSHAKE_ERROR;
-
+
if (thd->client_capabilities & CLIENT_INTERACTIVE)
thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
@@ -625,6 +630,9 @@ check_connections(THD *thd)
net->read_timeout=(uint) thd->variables.net_read_timeout;
char prepared_scramble[SCRAMBLE41_LENGTH+4]; /* Buffer for scramble and hash */
+
+ ACL_USER* cached_user;
+ uint cur_priv_version;
/* Simple connect only for old clients. New clients always use secure auth */
bool simple_connect=(!(thd->client_capabilities & CLIENT_SECURE_CONNECTION));
@@ -634,7 +642,7 @@ check_connections(THD *thd)
/* Check user permissions. If password failure we'll get scramble back */
if (check_user(thd,COM_CONNECT, user, passwd, db, 1, simple_connect,
- prepared_scramble,0,using_password))
+ prepared_scramble,0,using_password,&cur_priv_version,&cached_user)<0)
{
/* If The client is old we just have to return error */
if (simple_connect)
@@ -682,7 +690,8 @@ check_connections(THD *thd)
}
/* Final attempt to check the user based on reply */
if (check_user(thd,COM_CONNECT, tmp_user, (char*)net->read_pos,
- tmp_db, 1, 1,prepared_scramble,1,using_password))
+ tmp_db, 1, 1,prepared_scramble,1,using_password,&cur_priv_version,
+ &cached_user))
return -1;
}
thd->password=using_password;
@@ -1034,43 +1043,117 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
char *user= (char*) packet;
char *passwd= strend(user)+1;
char *db= strend(passwd)+1;
-
+
/* Save user and privileges */
uint save_master_access=thd->master_access;
uint save_db_access= thd->db_access;
uint save_db_length= thd->db_length;
char *save_user= thd->user;
+ thd->user=NULL; /* Needed for check_user to allocate new user */
char *save_priv_user= thd->priv_user;
char *save_db= thd->db;
- USER_CONN *save_uc= thd->user_connect;
+ USER_CONN *save_uc= thd->user_connect;
+ bool simple_connect;
+ bool using_password;
+
+ ulong pkt_len=0; /* Length of reply packet */
+
+ /* Small check for incomming packet */
if ((uint) ((uchar*) db - net->read_pos) > packet_length)
- { // Check if protocol is ok
- send_error(thd, ER_UNKNOWN_COM_ERROR);
- break;
- }
- /* WARNING THIS HAS TO BE REWRITTEN */
- char tmp_buffer[64];
- printf("Change user called: %s %s %s\n",user,passwd,db);
- if (check_user(thd, COM_CHANGE_USER, user, passwd, db, 0,1,tmp_buffer,0,1))
- { // Restore old user
- x_free(thd->user);
- x_free(thd->db);
- thd->master_access=save_master_access;
- thd->db_access=save_db_access;
- thd->db=save_db;
- thd->db_length=save_db_length;
- thd->user=save_user;
- thd->priv_user=save_priv_user;
- break;
+ goto restore_user_err;
+
+ /* Now we shall basically perform authentication again */
+
+ /* We can get only old hash at this point */
+ if (passwd[0] && strlen(passwd)!=SCRAMBLE_LENGTH)
+ goto restore_user_err;
+
+ char prepared_scramble[SCRAMBLE41_LENGTH+4];/* Buffer for scramble,hash */
+ ACL_USER* cached_user; /* Cached user */
+ uint cur_priv_version; /* Cached grant version */
+
+ /* Simple connect only for old clients. New clients always use sec. auth*/
+ simple_connect=(!(thd->client_capabilities & CLIENT_SECURE_CONNECTION));
+
+ /* Store information if we used password. passwd will be dammaged */
+ using_password=test(passwd[0]);
+
+ /*
+ Check user permissions. If password failure we'll get scramble back
+ Do not retry if we already have sent error (result>0)
+ */
+ if (check_user(thd,COM_CHANGE_USER, user, passwd, db, 0, simple_connect,
+ prepared_scramble,0,using_password,&cur_priv_version,&cached_user)<0)
+ {
+ /* If The client is old we just have to have auth failure */
+ if (simple_connect)
+ goto restore_user; /* Error is already reported */
+
+ /* Store current used and database as they are erased with next packet */
+
+ char tmp_user[USERNAME_LENGTH+1];
+ char tmp_db[NAME_LEN+1];
+
+ if (user)
+ {
+ strncpy(tmp_user,user,USERNAME_LENGTH+1);
+ /* Extra safety if we have too long data */
+ tmp_user[USERNAME_LENGTH]=0;
+ }
+ else
+ tmp_user[0]=0;
+ if (db)
+ {
+ strncpy(tmp_db,db,NAME_LEN+1);
+ tmp_db[NAME_LEN]=0;
+ }
+ else
+ tmp_db[0]=0;
+
+ /* Write hash and encrypted scramble to client */
+ if (my_net_write(net,prepared_scramble,SCRAMBLE41_LENGTH+4)
+ || net_flush(net))
+ goto restore_user_err;
+
+ /* Reading packet back */
+ if ((pkt_len=my_net_read(net)) == packet_error)
+ goto restore_user_err;
+
+ /* We have to get very specific packet size */
+ if (pkt_len!=SCRAMBLE41_LENGTH)
+ goto restore_user;
+
+ /* Final attempt to check the user based on reply */
+ if (check_user(thd,COM_CONNECT, tmp_user, (char*)net->read_pos,
+ tmp_db, 0, 1,prepared_scramble,1,using_password,&cur_priv_version,
+ &cached_user))
+ goto restore_user;
}
+ /* Finally we've authenticated new user */
if (max_connections && save_uc)
decrease_user_connections(save_uc);
x_free((gptr) save_db);
x_free((gptr) save_user);
- thd->password=test(passwd[0]);
+ thd->password=using_password;
+ break;
+
+ /* Bad luck we shall restore old user */
+ restore_user_err:
+ send_error(thd, ER_UNKNOWN_COM_ERROR);
+
+ restore_user:
+ x_free(thd->user);
+ x_free(thd->db);
+ thd->master_access=save_master_access;
+ thd->db_access=save_db_access;
+ thd->db=save_db;
+ thd->db_length=save_db_length;
+ thd->user=save_user;
+ thd->priv_user=save_priv_user;
break;
}
+
case COM_EXECUTE:
{
mysql_stmt_execute(thd, packet);