mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
SCRUM: Secure auth
Implement mysql_change_user Get rid of double user search at authentication Some cleanups
This commit is contained in:
@ -768,8 +768,9 @@ static int execute_commands(MYSQL *mysql,int argc, char **argv)
|
||||
return 1;
|
||||
}
|
||||
if (argv[1][0])
|
||||
make_scrambled_password(crypted_pw,argv[1],(find_type(argv[0],&command_typelib,2)
|
||||
==ADMIN_OLD_PASSWORD),&rand_st);
|
||||
make_scrambled_password(crypted_pw,argv[1],(find_type(argv[0],
|
||||
&command_typelib,2)==ADMIN_OLD_PASSWORD),
|
||||
&rand_st);
|
||||
else
|
||||
crypted_pw[0]=0; /* No password */
|
||||
sprintf(buff,"set password='%s',sql_log_off=0",crypted_pw);
|
||||
|
@ -280,18 +280,22 @@ extern unsigned long net_buffer_length;
|
||||
void randominit(struct rand_struct *,unsigned long seed1,
|
||||
unsigned long seed2);
|
||||
double rnd(struct rand_struct *);
|
||||
void make_scrambled_password(char *to,const char *password,my_bool force_old_scramble,struct rand_struct *rand_st);
|
||||
void make_scrambled_password(char *to,const char *password,
|
||||
my_bool force_old_scramble,struct rand_struct *rand_st);
|
||||
int get_password_length(my_bool force_old_scramble);
|
||||
char get_password_version(const char* password);
|
||||
void create_random_string(int length,struct rand_struct *rand_st,char* target);
|
||||
my_bool validate_password(const char* password, const char* message, ulong* salt);
|
||||
my_bool validate_password(const char* password, const char* message,
|
||||
ulong* salt);
|
||||
void password_hash_stage1(char *to, const char *password);
|
||||
void password_hash_stage2(char *to,const char *salt);
|
||||
void password_crypt(const char* from,char* to, const char* password,int length);
|
||||
void get_hash_and_password(ulong* salt, uint8 pversion,char* hash, unsigned char* bin_password);
|
||||
void get_hash_and_password(ulong* salt, unsigned char pversion,char* hash,
|
||||
unsigned char* bin_password);
|
||||
void get_salt_from_password(unsigned long *res,const char *password);
|
||||
void create_key_from_old_password(const char* password,char* key);
|
||||
void make_password_from_salt(char *to, unsigned long *hash_res, uint8 password_version);
|
||||
void make_password_from_salt(char *to, unsigned long *hash_res,
|
||||
unsigned char password_version);
|
||||
char *scramble(char *to,const char *message,const char *password,
|
||||
my_bool old_ver);
|
||||
my_bool check_scramble(const char *, const char *message,
|
||||
|
@ -2228,8 +2228,8 @@ Try also with PIPE or TCP/IP
|
||||
{
|
||||
if (passwd[0])
|
||||
{
|
||||
/* Use something for not empty password not to match it against empty one */
|
||||
end=scramble(strend(buff+5)+1, mysql->scramble_buff,"~MySQL#!",
|
||||
/* Use something for not empty password not to match against empty one */
|
||||
end=scramble(strend(buff+5)+1, mysql->scramble_buff,"\1~MySQL#!\2",
|
||||
(my_bool) (mysql->protocol_version == 9));
|
||||
}
|
||||
else /* For empty password*/
|
||||
@ -2409,7 +2409,11 @@ static my_bool mysql_reconnect(MYSQL *mysql)
|
||||
my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
|
||||
const char *passwd, const char *db)
|
||||
{
|
||||
char buff[512],*pos=buff;
|
||||
char buff[512],*end=buff;
|
||||
ulong pkt_length;
|
||||
char password_hash[20]; /* Used for tmp storage of stage1 hash */
|
||||
NET *net= &mysql->net;
|
||||
|
||||
DBUG_ENTER("mysql_change_user");
|
||||
|
||||
if (!user)
|
||||
@ -2417,12 +2421,83 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
|
||||
if (!passwd)
|
||||
passwd="";
|
||||
|
||||
pos=strmov(pos,user)+1;
|
||||
pos=scramble(pos, mysql->scramble_buff, passwd,
|
||||
/* Store user into the buffer */
|
||||
end=strmov(end,user)+1;
|
||||
|
||||
/*
|
||||
We always start with old type handshake the only difference is message sent
|
||||
If server handles secure connection type we'll not send the real scramble
|
||||
*/
|
||||
if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
|
||||
{
|
||||
if (passwd[0])
|
||||
{
|
||||
/* Use something for not empty password not to match it against empty one */
|
||||
end=scramble(end, mysql->scramble_buff,"\1~MySQL#!\2",
|
||||
(my_bool) (mysql->protocol_version == 9));
|
||||
pos=strmov(pos+1,db ? db : "");
|
||||
if (simple_command(mysql,COM_CHANGE_USER, buff,(ulong) (pos-buff),0))
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
else /* For empty password*/
|
||||
*end=0; /* Store zero length scramble */
|
||||
}
|
||||
/* Real scramble is sent only for servers. This is to be blocked by option */
|
||||
else
|
||||
end=scramble(end, mysql->scramble_buff, passwd,
|
||||
(my_bool) (mysql->protocol_version == 9));
|
||||
|
||||
/* Add database if needed */
|
||||
end=strmov(end+1,db ? db : "");
|
||||
|
||||
/* Write authentication package */
|
||||
|
||||
simple_command(mysql,COM_CHANGE_USER, buff,(ulong) (end-buff),1);
|
||||
|
||||
/* We shall only query sever if it expect us to do so */
|
||||
if ( (pkt_length=net_safe_read(mysql)) == packet_error)
|
||||
goto error;
|
||||
|
||||
if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
|
||||
{
|
||||
/* This should basically always happen with new server unless empty password */
|
||||
if (pkt_length==24) /* We have new hash back */
|
||||
{
|
||||
/* Old passwords will have zero at the first byte of hash */
|
||||
if (net->read_pos[0])
|
||||
{
|
||||
/* Build full password hash as it is required to decode scramble */
|
||||
password_hash_stage1(buff, passwd);
|
||||
/* Store copy as we'll need it later */
|
||||
memcpy(password_hash,buff,20);
|
||||
/* Finally hash complete password using hash we got from server */
|
||||
password_hash_stage2(password_hash,net->read_pos);
|
||||
/* Decypt and store scramble 4 = hash for stage2 */
|
||||
password_crypt(net->read_pos+4,mysql->scramble_buff,password_hash,20);
|
||||
mysql->scramble_buff[20]=0;
|
||||
/* Encode scramble with password. Recycle buffer */
|
||||
password_crypt(mysql->scramble_buff,buff,buff,20);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Create password to decode scramble */
|
||||
create_key_from_old_password(passwd,password_hash);
|
||||
/* Decypt and store scramble 4 = hash for stage2 */
|
||||
password_crypt(net->read_pos+4,mysql->scramble_buff,password_hash,20);
|
||||
mysql->scramble_buff[20]=0;
|
||||
/* Finally scramble decoded scramble with password */
|
||||
scramble(buff, mysql->scramble_buff, passwd,
|
||||
(my_bool) (mysql->protocol_version == 9));
|
||||
}
|
||||
/* Write second package of authentication */
|
||||
if (my_net_write(net,buff,20) || net_flush(net))
|
||||
{
|
||||
net->last_errno= CR_SERVER_LOST;
|
||||
strmov(net->last_error,ER(net->last_errno));
|
||||
goto error;
|
||||
}
|
||||
/* Read What server thinks about out new auth message report */
|
||||
if (net_safe_read(mysql) == packet_error)
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
my_free(mysql->user,MYF(MY_ALLOW_ZERO_PTR));
|
||||
my_free(mysql->passwd,MYF(MY_ALLOW_ZERO_PTR));
|
||||
@ -2432,6 +2507,10 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
|
||||
mysql->passwd=my_strdup(passwd,MYF(MY_WME));
|
||||
mysql->db= db ? my_strdup(db,MYF(MY_WME)) : 0;
|
||||
DBUG_RETURN(0);
|
||||
|
||||
error:
|
||||
DBUG_RETURN(1);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -49,6 +49,8 @@
|
||||
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
|
||||
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
|
121
sql/sql_acl.cc
121
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,...);
|
||||
@ -149,6 +104,8 @@ 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));
|
||||
@ -534,24 +499,47 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
|
||||
}
|
||||
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.
|
||||
*/
|
||||
|
||||
if (stage && (*cur_priv_version==priv_version))
|
||||
acl_user=*hint_user;
|
||||
else
|
||||
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))
|
||||
ACL_USER *acl_user_search=dynamic_element(&acl_users,i,ACL_USER*);
|
||||
if (!acl_user_search->user || !strcmp(user,acl_user_search->user))
|
||||
{
|
||||
if (compare_hostname(&acl_user->host,host,ip))
|
||||
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
|
||||
else /* Normal password presents */
|
||||
{
|
||||
/* New version password is checked differently */
|
||||
if (acl_user->pversion)
|
||||
@ -577,9 +565,16 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
|
||||
prepare_scramble(thd,acl_user,prepared_scramble);
|
||||
}
|
||||
}
|
||||
/* If password correct continue with checking other limitations */
|
||||
if (password_correct)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
Vio *vio=thd->net.vio;
|
||||
/*
|
||||
@ -615,8 +610,7 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
|
||||
if (acl_user->ssl_cipher)
|
||||
{
|
||||
DBUG_PRINT("info",("comparing ciphers: '%s' and '%s'",
|
||||
acl_user->ssl_cipher,
|
||||
SSL_get_cipher(vio->ssl_)));
|
||||
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
|
||||
@ -666,26 +660,13 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
|
||||
*mqh=acl_user->user_resource;
|
||||
if (!acl_user->user)
|
||||
*priv_user=(char*) ""; // Change to anonymous user /* purecov: inspected */
|
||||
break;
|
||||
} // correct password
|
||||
} // found matching user
|
||||
|
||||
#ifndef ALLOW_DOWNGRADE_OF_USERS
|
||||
break; // Wrong password breaks loop /* purecov: inspected */
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
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)))
|
||||
{
|
||||
|
@ -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,
|
||||
|
123
sql/sql_parse.cc
123
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,
|
||||
@ -261,6 +265,7 @@ 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));
|
||||
@ -626,6 +631,9 @@ check_connections(THD *thd)
|
||||
|
||||
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;
|
||||
@ -1040,20 +1049,100 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
}
|
||||
/* 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
|
||||
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=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;
|
||||
@ -1064,13 +1153,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
||||
thd->priv_user=save_priv_user;
|
||||
break;
|
||||
}
|
||||
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]);
|
||||
break;
|
||||
}
|
||||
|
||||
case COM_EXECUTE:
|
||||
{
|
||||
mysql_stmt_execute(thd, packet);
|
||||
|
Reference in New Issue
Block a user