mirror of
https://github.com/MariaDB/server.git
synced 2025-01-17 20:42:30 +01:00
Merge kosipov@bk-internal.mysql.com:/home/bk/mysql-4.1
into oak.local:/home/kostja/mysql/mysql-4.1-root
This commit is contained in:
commit
711a3f6806
56 changed files with 1404 additions and 1548 deletions
15
.bzrignore
15
.bzrignore
|
@ -23,6 +23,7 @@
|
|||
.vimrc
|
||||
50
|
||||
=6
|
||||
BUILD/compile-pentium-maintainer
|
||||
BitKeeper/etc/config
|
||||
BitKeeper/etc/csets
|
||||
BitKeeper/etc/csets-in
|
||||
|
@ -30,6 +31,8 @@ BitKeeper/etc/csets-out
|
|||
BitKeeper/etc/gone
|
||||
BitKeeper/etc/level
|
||||
BitKeeper/etc/pushed
|
||||
BitKeeper/post-commit
|
||||
BitKeeper/post-commit-manual
|
||||
BitKeeper/tmp/*
|
||||
BitKeeper/tmp/bkr3sAHD
|
||||
BitKeeper/tmp/gone
|
||||
|
@ -223,6 +226,7 @@ bkpull.log.5
|
|||
bkpull.log.6
|
||||
bkpush.log
|
||||
build.log
|
||||
build_tags.sh
|
||||
client/insert_test
|
||||
client/log_event.cc
|
||||
client/log_event.h
|
||||
|
@ -311,6 +315,8 @@ libmysql_r/conf_to_src
|
|||
libmysql_r/my_static.h
|
||||
libmysql_r/mysys_priv.h
|
||||
libmysqld/backup_dir
|
||||
libmysqld/client.c
|
||||
libmysqld/client_settings.h
|
||||
libmysqld/convert.cc
|
||||
libmysqld/derror.cc
|
||||
libmysqld/errmsg.c
|
||||
|
@ -355,6 +361,7 @@ libmysqld/item_sum.cc
|
|||
libmysqld/item_timefunc.cc
|
||||
libmysqld/item_uniq.cc
|
||||
libmysqld/key.cc
|
||||
libmysqld/libmysql.c
|
||||
libmysqld/lock.cc
|
||||
libmysqld/log.cc
|
||||
libmysqld/log_event.cc
|
||||
|
@ -366,6 +373,7 @@ libmysqld/net_serv.cc
|
|||
libmysqld/opt_ft.cc
|
||||
libmysqld/opt_range.cc
|
||||
libmysqld/opt_sum.cc
|
||||
libmysqld/pack.c
|
||||
libmysqld/password.c
|
||||
libmysqld/procedure.cc
|
||||
libmysqld/protocol.cc
|
||||
|
@ -483,6 +491,7 @@ mysys/#mf_iocache.c#
|
|||
mysys/charset2html
|
||||
mysys/getopt.c
|
||||
mysys/getopt1.c
|
||||
mysys/main.cc
|
||||
mysys/ste5KbMa
|
||||
mysys/test_charset
|
||||
mysys/test_dir
|
||||
|
@ -586,6 +595,7 @@ stamp-h1
|
|||
stamp-h2
|
||||
stamp-h3
|
||||
stamp-h4
|
||||
start_mysqld.sh
|
||||
strings/conf_to_src
|
||||
strings/ctype_autoconf.c
|
||||
strings/ctype_extra_sources.c
|
||||
|
@ -612,6 +622,7 @@ support-files/mysql.spec
|
|||
tags
|
||||
test_xml
|
||||
tests/client_test
|
||||
tests/connect_test
|
||||
thread_test
|
||||
tmp/*
|
||||
tools/my_vsnprintf.c
|
||||
|
@ -623,7 +634,3 @@ vio/test-ssl
|
|||
vio/test-sslclient
|
||||
vio/test-sslserver
|
||||
vio/viotest-ssl
|
||||
libmysqld/client.c
|
||||
libmysqld/client_settings.h
|
||||
libmysqld/libmysql.c
|
||||
libmysqld/pack.c
|
||||
|
|
|
@ -769,9 +769,12 @@ 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);
|
||||
{
|
||||
if (find_type(argv[0], &command_typelib, 2) == ADMIN_OLD_PASSWORD)
|
||||
make_scrambled_password_323(crypted_pw, argv[1]);
|
||||
else
|
||||
make_scrambled_password(crypted_pw, argv[1]);
|
||||
}
|
||||
else
|
||||
crypted_pw[0]=0; /* No password */
|
||||
sprintf(buff,"set password='%s',sql_log_off=0",crypted_pw);
|
||||
|
|
|
@ -229,7 +229,9 @@ typedef struct st_mysql
|
|||
enum mysql_status status;
|
||||
my_bool free_me; /* If free in mysql_close */
|
||||
my_bool reconnect; /* set to 1 if automatic reconnect */
|
||||
char scramble_buff[21]; /* New protocol requires longer scramble*/
|
||||
|
||||
/* session-wide random string */
|
||||
char scramble[SCRAMBLE_LENGTH+1];
|
||||
|
||||
/*
|
||||
Set if this is the original connection, not a master or a slave we have
|
||||
|
|
|
@ -49,8 +49,15 @@ enum enum_server_command
|
|||
};
|
||||
|
||||
|
||||
#define SCRAMBLE_LENGTH 8
|
||||
#define SCRAMBLE41_LENGTH 20
|
||||
/*
|
||||
Length of random string sent by server on handshake; this is also length of
|
||||
obfuscated password, recieved from client
|
||||
*/
|
||||
#define SCRAMBLE_LENGTH 20
|
||||
#define SCRAMBLE_LENGTH_323 8
|
||||
/* length of password stored in the db: new passwords are preceeded with '*' */
|
||||
#define SCRAMBLED_PASSWORD_CHAR_LENGTH (SCRAMBLE_LENGTH*2+1)
|
||||
#define SCRAMBLED_PASSWORD_CHAR_LENGTH_323 (SCRAMBLE_LENGTH_323*2)
|
||||
|
||||
|
||||
#define NOT_NULL_FLAG 1 /* Field can't be NULL */
|
||||
|
@ -302,31 +309,34 @@ extern "C" {
|
|||
extern unsigned long max_allowed_packet;
|
||||
extern unsigned long net_buffer_length;
|
||||
|
||||
void randominit(struct rand_struct *,unsigned long seed1,
|
||||
unsigned long seed2);
|
||||
/*
|
||||
These functions are used for authentication by client and server and
|
||||
implemented in sql/password.c
|
||||
*/
|
||||
|
||||
void randominit(struct rand_struct *, unsigned long seed1,
|
||||
unsigned long seed2);
|
||||
double my_rnd(struct rand_struct *);
|
||||
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,
|
||||
unsigned long* 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(unsigned long* 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,
|
||||
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,
|
||||
unsigned long *salt,my_bool old_ver);
|
||||
void create_random_string(char *to, uint length, struct rand_struct *rand_st);
|
||||
|
||||
void hash_password(ulong *to, const char *password, uint password_len);
|
||||
void make_scrambled_password_323(char *to, const char *password);
|
||||
void scramble_323(char *to, const char *message, const char *password);
|
||||
my_bool check_scramble_323(const char *, const char *message,
|
||||
unsigned long *salt);
|
||||
void get_salt_from_password_323(unsigned long *res, const char *password);
|
||||
void make_password_from_salt_323(char *to, const unsigned long *salt);
|
||||
|
||||
void make_scrambled_password(char *to, const char *password);
|
||||
void scramble(char *to, const char *message, const char *password);
|
||||
my_bool check_scramble(const char *reply, const char *message,
|
||||
const unsigned char *hash_stage2);
|
||||
void get_salt_from_password(unsigned char *res, const char *password);
|
||||
void make_password_from_salt(char *to, const unsigned char *hash_stage2);
|
||||
|
||||
/* end of password.c */
|
||||
|
||||
char *get_tty_password(char *opt_message);
|
||||
void hash_password(unsigned long *result, const char *password);
|
||||
const char *mysql_errno_to_sqlstate(unsigned int mysql_errno);
|
||||
|
||||
/* Some other useful functions */
|
||||
|
|
|
@ -290,4 +290,5 @@
|
|||
#define ER_VARIABLE_IS_NOT_STRUCT 1271
|
||||
#define ER_UNKNOWN_COLLATION 1272
|
||||
#define ER_SLAVE_IGNORED_SSL_PARAMS 1273
|
||||
#define ER_ERROR_MESSAGES 274
|
||||
#define ER_SERVER_IS_IN_SECURE_AUTH_MODE 1274
|
||||
#define ER_ERROR_MESSAGES 275
|
||||
|
|
|
@ -604,41 +604,55 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
|
|||
/* 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)
|
||||
/* write scrambled password according to server capabilities */
|
||||
if (passwd[0])
|
||||
{
|
||||
if (passwd[0])
|
||||
if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
|
||||
{
|
||||
/* Prepare false scramble */
|
||||
bfill(end, SCRAMBLE_LENGTH, 'x');
|
||||
end+=SCRAMBLE_LENGTH;
|
||||
*end=0;
|
||||
|
||||
*end++= SCRAMBLE_LENGTH;
|
||||
scramble(end, mysql->scramble, passwd);
|
||||
end+= SCRAMBLE_LENGTH;
|
||||
}
|
||||
else
|
||||
{
|
||||
scramble_323(end, mysql->scramble, passwd);
|
||||
end+= SCRAMBLE_LENGTH_323 + 1;
|
||||
}
|
||||
else /* For empty password */
|
||||
*end=0; /* zero length scramble */
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
Real scramble is only sent to old servers. This can be blocked
|
||||
by calling mysql_options(MYSQL *, MYSQL_SECURE_CONNECT, (char*) &1);
|
||||
*/
|
||||
end=scramble(end, mysql->scramble_buff, passwd,
|
||||
(my_bool) (mysql->protocol_version == 9));
|
||||
}
|
||||
*end++= '\0'; // empty password
|
||||
/* Add database if needed */
|
||||
end=strmov(end+1,db ? db : "");
|
||||
end= strmov(end, db ? db : "") + 1;
|
||||
|
||||
/* Write authentication package */
|
||||
simple_command(mysql,COM_CHANGE_USER, buff,(ulong) (end-buff),1);
|
||||
|
||||
if (mysql_autenticate(mysql, passwd))
|
||||
NET *net= &mysql->net;
|
||||
ulong pkt_length= net_safe_read(mysql);
|
||||
|
||||
if (pkt_length == packet_error)
|
||||
goto error;
|
||||
|
||||
if (pkt_length == 1 && net->read_pos[0] == 254 &&
|
||||
mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
|
||||
{
|
||||
/*
|
||||
By sending this very specific reply server asks us to send scrambled
|
||||
password in old format. The reply contains scramble_323.
|
||||
*/
|
||||
scramble_323(buff, mysql->scramble, passwd);
|
||||
if (my_net_write(net, buff, SCRAMBLE_LENGTH_323 + 1) || net_flush(net))
|
||||
{
|
||||
net->last_errno= CR_SERVER_LOST;
|
||||
strmov(net->sqlstate, unknown_sqlstate);
|
||||
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;
|
||||
}
|
||||
|
||||
/* Free old connect information */
|
||||
my_free(mysql->user,MYF(MY_ALLOW_ZERO_PTR));
|
||||
my_free(mysql->passwd,MYF(MY_ALLOW_ZERO_PTR));
|
||||
|
|
|
@ -30,6 +30,7 @@ show tables;
|
|||
Tables_in_test
|
||||
update mysql.user set password=old_password("gambling2") where user="test";
|
||||
flush privileges;
|
||||
set password=old_password('gambling3');
|
||||
show tables;
|
||||
Tables_in_mysql
|
||||
columns_priv
|
||||
|
|
|
@ -1,15 +1,79 @@
|
|||
select length(encrypt('foo', 'ff')) <> 0;
|
||||
length(encrypt('foo', 'ff')) <> 0
|
||||
1
|
||||
select password("a",""), password("a",NULL), password("","a"), password(NULL,"a");
|
||||
password("a","") password("a",NULL) password("","a") password(NULL,"a")
|
||||
*2517f7235d68d4ba2e5019c93420523101157a792c01 NULL NULL
|
||||
select password("aaaaaaaaaaaaaaaa","a"), password("a","aaaaaaaaaaaaaaaa");
|
||||
password("aaaaaaaaaaaaaaaa","a") password("a","aaaaaaaaaaaaaaaa")
|
||||
*2cd3b9a44e9a9994789a30f935c92f45a96c5472f381 *37c7c5c794ff144819f2531bf03c57772cd84e40db09
|
||||
select old_password('test'), length(password("1")), length(encrypt('test')), encrypt('test','aa');
|
||||
old_password('test') length(password("1")) length(encrypt('test')) encrypt('test','aa')
|
||||
378b243e220ca493 45 13 aaqPiZY5xR5l.
|
||||
select old_password(""), old_password(NULL), password(""), password(NULL);
|
||||
old_password("") old_password(NULL) password("") password(NULL)
|
||||
NULL NULL
|
||||
select password('abc');
|
||||
password('abc')
|
||||
*0D3CED9BEC10A777AEC23CCC353A8C08A633045E
|
||||
select password('');
|
||||
password('')
|
||||
|
||||
select old_password('abc');
|
||||
old_password('abc')
|
||||
7cd2b5942be28759
|
||||
select old_password('');
|
||||
old_password('')
|
||||
|
||||
select password('gabbagabbahey');
|
||||
password('gabbagabbahey')
|
||||
*B0F99D2963660DD7E16B751EC9EE2F17B6A68FA6
|
||||
select old_password('idkfa');
|
||||
old_password('idkfa')
|
||||
5c078dc54ca0fcca
|
||||
select length(password('1'));
|
||||
length(password('1'))
|
||||
41
|
||||
select length(encrypt('test'));
|
||||
length(encrypt('test'))
|
||||
13
|
||||
select encrypt('test','aa');
|
||||
encrypt('test','aa')
|
||||
aaqPiZY5xR5l.
|
||||
select old_password(NULL);
|
||||
old_password(NULL)
|
||||
NULL
|
||||
select password(NULL);
|
||||
password(NULL)
|
||||
NULL
|
||||
set global old_passwords=on;
|
||||
select password('');
|
||||
password('')
|
||||
|
||||
select old_password('');
|
||||
old_password('')
|
||||
|
||||
select password('idkfa');
|
||||
password('idkfa')
|
||||
*B669C9DAC3AA6F2254B03CDEF8DFDD6B2D1054BA
|
||||
select old_password('idkfa');
|
||||
old_password('idkfa')
|
||||
5c078dc54ca0fcca
|
||||
set old_passwords=on;
|
||||
select password('idkfa');
|
||||
password('idkfa')
|
||||
5c078dc54ca0fcca
|
||||
select old_password('idkfa');
|
||||
old_password('idkfa')
|
||||
5c078dc54ca0fcca
|
||||
set global old_passwords=off;
|
||||
select password('idkfa');
|
||||
password('idkfa')
|
||||
5c078dc54ca0fcca
|
||||
select old_password('idkfa');
|
||||
old_password('idkfa')
|
||||
5c078dc54ca0fcca
|
||||
set old_passwords=off;
|
||||
select password('idkfa ');
|
||||
password('idkfa ')
|
||||
*2DC31D90647B4C1ABC9231563D2236E96C9A2DB2
|
||||
select password('idkfa');
|
||||
password('idkfa')
|
||||
*B669C9DAC3AA6F2254B03CDEF8DFDD6B2D1054BA
|
||||
select password(' idkfa');
|
||||
password(' idkfa')
|
||||
*12B099E56BB7FE8D43C78FD834A9D1D11178D045
|
||||
select old_password('idkfa');
|
||||
old_password('idkfa')
|
||||
5c078dc54ca0fcca
|
||||
select old_password(' i d k f a ');
|
||||
old_password(' i d k f a ')
|
||||
5c078dc54ca0fcca
|
||||
|
|
|
@ -48,8 +48,9 @@ flush privileges;
|
|||
#connect (con1,localhost,test,gambling2,"");
|
||||
#show tables;
|
||||
connect (con1,localhost,test,gambling2,mysql);
|
||||
set password=old_password('gambling3');
|
||||
show tables;
|
||||
connect (con1,localhost,test,gambling2,test);
|
||||
connect (con1,localhost,test,gambling3,test);
|
||||
show tables;
|
||||
|
||||
# Re enable this one day if error handling on connect will take place
|
||||
|
@ -63,7 +64,9 @@ show tables;
|
|||
#connect (con1,localhost,test,zorro,);
|
||||
#--error 1045
|
||||
|
||||
|
||||
# remove user 'test' so that other tests which may use 'test'
|
||||
# do not depend on this test.
|
||||
|
||||
delete from mysql.user where user="test";
|
||||
flush privileges;
|
||||
|
|
|
@ -4,7 +4,33 @@ select length(encrypt('foo', 'ff')) <> 0;
|
|||
--replace_result $1$aa$4OSUA5cjdx0RUQ08opV27/ aaqPiZY5xR5l.
|
||||
|
||||
# Test new and old password handling functions
|
||||
select password("a",""), password("a",NULL), password("","a"), password(NULL,"a");
|
||||
select password("aaaaaaaaaaaaaaaa","a"), password("a","aaaaaaaaaaaaaaaa");
|
||||
select old_password('test'), length(password("1")), length(encrypt('test')), encrypt('test','aa');
|
||||
select old_password(""), old_password(NULL), password(""), password(NULL);
|
||||
select password('abc');
|
||||
select password('');
|
||||
select old_password('abc');
|
||||
select old_password('');
|
||||
select password('gabbagabbahey');
|
||||
select old_password('idkfa');
|
||||
select length(password('1'));
|
||||
select length(encrypt('test'));
|
||||
select encrypt('test','aa');
|
||||
select old_password(NULL);
|
||||
select password(NULL);
|
||||
set global old_passwords=on;
|
||||
select password('');
|
||||
select old_password('');
|
||||
select password('idkfa');
|
||||
select old_password('idkfa');
|
||||
set old_passwords=on;
|
||||
select password('idkfa');
|
||||
select old_password('idkfa');
|
||||
set global old_passwords=off;
|
||||
select password('idkfa');
|
||||
select old_password('idkfa');
|
||||
|
||||
# this test shows that new scrambles honor spaces in passwords:
|
||||
set old_passwords=off;
|
||||
select password('idkfa ');
|
||||
select password('idkfa');
|
||||
select password(' idkfa');
|
||||
select old_password('idkfa');
|
||||
select old_password(' i d k f a ');
|
||||
|
|
|
@ -108,7 +108,7 @@ then
|
|||
c_u="$c_u CREATE TABLE user ("
|
||||
c_u="$c_u Host char(60) binary DEFAULT '' NOT NULL,"
|
||||
c_u="$c_u User char(16) binary DEFAULT '' NOT NULL,"
|
||||
c_u="$c_u Password char(45) binary DEFAULT '' NOT NULL,"
|
||||
c_u="$c_u Password char(41) binary DEFAULT '' NOT NULL,"
|
||||
c_u="$c_u Select_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
|
||||
c_u="$c_u Insert_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
|
||||
c_u="$c_u Update_priv enum('N','Y') DEFAULT 'N' NOT NULL,"
|
||||
|
|
|
@ -16,7 +16,7 @@ ALTER TABLE host type=MyISAM;
|
|||
ALTER TABLE func type=MyISAM;
|
||||
ALTER TABLE columns_priv type=MyISAM;
|
||||
ALTER TABLE tables_priv type=MyISAM;
|
||||
ALTER TABLE user change Password Password char(45) not null;
|
||||
ALTER TABLE user change Password Password char(41) not null;
|
||||
ALTER TABLE user add File_priv enum('N','Y') NOT NULL;
|
||||
CREATE TABLE IF NOT EXISTS func (
|
||||
name char(64) DEFAULT '' NOT NULL,
|
||||
|
|
|
@ -1391,76 +1391,6 @@ mysql_ssl_free(MYSQL *mysql __attribute__((unused)))
|
|||
#endif /* HAVE_OPENSSL */
|
||||
|
||||
|
||||
/*
|
||||
Handle password authentication
|
||||
*/
|
||||
|
||||
my_bool mysql_autenticate(MYSQL *mysql, const char *passwd)
|
||||
{
|
||||
ulong pkt_length;
|
||||
NET *net= &mysql->net;
|
||||
char buff[SCRAMBLE41_LENGTH];
|
||||
char password_hash[SCRAMBLE41_LENGTH]; /* Used for storage of stage1 hash */
|
||||
|
||||
/* We shall only query server 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 always happen with new server unless empty password
|
||||
OK/Error packets have zero as the first char
|
||||
*/
|
||||
if (pkt_length == 24 && net->read_pos[0])
|
||||
{
|
||||
/* Old passwords will have '*' 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,SCRAMBLE41_LENGTH);
|
||||
/* Finally hash complete password using hash we got from server */
|
||||
password_hash_stage2(password_hash,(const char*) net->read_pos);
|
||||
/* Decypt and store scramble 4 = hash for stage2 */
|
||||
password_crypt((const char*) net->read_pos+4,mysql->scramble_buff,
|
||||
password_hash, SCRAMBLE41_LENGTH);
|
||||
mysql->scramble_buff[SCRAMBLE41_LENGTH]=0;
|
||||
/* Encode scramble with password. Recycle buffer */
|
||||
password_crypt(mysql->scramble_buff,buff,buff,SCRAMBLE41_LENGTH);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Create password to decode scramble */
|
||||
create_key_from_old_password(passwd,password_hash);
|
||||
/* Decypt and store scramble 4 = hash for stage2 */
|
||||
password_crypt((const char*) net->read_pos+4,mysql->scramble_buff,
|
||||
password_hash, SCRAMBLE41_LENGTH);
|
||||
mysql->scramble_buff[SCRAMBLE41_LENGTH]=0;
|
||||
/* Finally scramble decoded scramble with password */
|
||||
scramble(buff, mysql->scramble_buff, passwd,0);
|
||||
}
|
||||
/* Write second package of authentication */
|
||||
if (my_net_write(net,buff,SCRAMBLE41_LENGTH) || net_flush(net))
|
||||
{
|
||||
net->last_errno= CR_SERVER_LOST;
|
||||
strmov(net->sqlstate, unknown_sqlstate);
|
||||
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;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
error:
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Note that the mysql argument must be initialized with mysql_init()
|
||||
before calling mysql_real_connect !
|
||||
|
@ -1553,7 +1483,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
|
|||
mysql->server_status=SERVER_STATUS_AUTOCOMMIT;
|
||||
|
||||
/*
|
||||
Grab a socket and connect it to the server
|
||||
Part 0: Grab a socket and connect it to the server
|
||||
*/
|
||||
#if defined(HAVE_SMEM)
|
||||
if ((!mysql->options.protocol ||
|
||||
|
@ -1754,6 +1684,11 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
|
|||
strmov(net->last_error,ER(net->last_errno));
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
Part 1: Connection established, read and parse first packet
|
||||
*/
|
||||
|
||||
if ((pkt_length=net_safe_read(mysql)) == packet_error)
|
||||
goto error;
|
||||
|
||||
|
@ -1774,8 +1709,13 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
|
|||
end=strend((char*) net->read_pos+1);
|
||||
mysql->thread_id=uint4korr(end+1);
|
||||
end+=5;
|
||||
strmake(mysql->scramble_buff,end,8);
|
||||
end+=9;
|
||||
/*
|
||||
Scramble is split into two parts because old clients does not understand
|
||||
long scrambles; here goes the first part.
|
||||
*/
|
||||
strmake(mysql->scramble, end, SCRAMBLE_LENGTH_323);
|
||||
end+= SCRAMBLE_LENGTH_323+1;
|
||||
|
||||
if (pkt_length >= (uint) (end+1 - (char*) net->read_pos))
|
||||
mysql->server_capabilities=uint2korr(end);
|
||||
if (pkt_length >= (uint) (end+18 - (char*) net->read_pos))
|
||||
|
@ -1784,6 +1724,14 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
|
|||
mysql->server_language=end[2];
|
||||
mysql->server_status=uint2korr(end+3);
|
||||
}
|
||||
end+= 18;
|
||||
if (pkt_length >= (uint) (end + SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323 + 1 -
|
||||
(char *) net->read_pos))
|
||||
strmake(mysql->scramble+SCRAMBLE_LENGTH_323, end,
|
||||
SCRAMBLE_LENGTH-SCRAMBLE_LENGTH_323);
|
||||
else
|
||||
mysql->server_capabilities&= ~CLIENT_SECURE_CONNECTION;
|
||||
|
||||
charset_number= mysql->server_language;
|
||||
|
||||
/* Set character set */
|
||||
|
@ -1860,9 +1808,12 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
|
|||
mysql->unix_socket=0;
|
||||
strmov(mysql->server_version,(char*) net->read_pos+1);
|
||||
mysql->port=port;
|
||||
client_flag|=mysql->options.client_flag;
|
||||
|
||||
/* Send client information for access check */
|
||||
/*
|
||||
Part 2: format and send client info to the server for access check
|
||||
*/
|
||||
|
||||
client_flag|=mysql->options.client_flag;
|
||||
client_flag|=CLIENT_CAPABILITIES;
|
||||
if (client_flag & CLIENT_MULTI_QUERIES)
|
||||
client_flag|= CLIENT_MULTI_RESULTS;
|
||||
|
@ -1949,7 +1900,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
|
|||
mysql->server_status, client_flag));
|
||||
/* This needs to be changed as it's not useful with big packets */
|
||||
if (user && user[0])
|
||||
strmake(end,user,32); /* Max user name */
|
||||
strmake(end,user,USERNAME_LENGTH); /* Max user name */
|
||||
else
|
||||
read_user_name((char*) end);
|
||||
|
||||
|
@ -1958,41 +1909,30 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
|
|||
#include "_cust_libmysql.h"
|
||||
#endif
|
||||
DBUG_PRINT("info",("user: %s",end));
|
||||
/*
|
||||
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)
|
||||
end= strend(end) + 1;
|
||||
if (passwd[0])
|
||||
{
|
||||
if (passwd[0])
|
||||
if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
|
||||
{
|
||||
/* Prepare false scramble */
|
||||
end=strend(end)+1;
|
||||
bfill(end, SCRAMBLE_LENGTH, 'x');
|
||||
end+=SCRAMBLE_LENGTH;
|
||||
*end=0;
|
||||
*end++= SCRAMBLE_LENGTH;
|
||||
scramble(end, mysql->scramble, passwd);
|
||||
end+= SCRAMBLE_LENGTH;
|
||||
}
|
||||
else /* For empty password*/
|
||||
else
|
||||
{
|
||||
end=strend(end)+1;
|
||||
*end=0; /* Store zero length scramble */
|
||||
scramble_323(end, mysql->scramble, passwd);
|
||||
end+= SCRAMBLE_LENGTH_323 + 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
Real scramble is only sent to old servers. This can be blocked
|
||||
by calling mysql_options(MYSQL *, MYSQL_SECURE_CONNECT, (char*) &1);
|
||||
*/
|
||||
end=scramble(strend(end)+1, mysql->scramble_buff, passwd,
|
||||
(my_bool) (mysql->protocol_version == 9));
|
||||
}
|
||||
*end++= '\0'; /* empty password */
|
||||
|
||||
/* Add database if needed */
|
||||
if (db && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB))
|
||||
{
|
||||
end=strmake(end+1,db,NAME_LEN);
|
||||
mysql->db=my_strdup(db,MYF(MY_WME));
|
||||
db=0;
|
||||
end= strmake(end, db, NAME_LEN) + 1;
|
||||
mysql->db= my_strdup(db,MYF(MY_WME));
|
||||
db= 0;
|
||||
}
|
||||
/* Write authentication package */
|
||||
if (my_net_write(net,buff,(ulong) (end-buff)) || net_flush(net))
|
||||
|
@ -2002,10 +1942,36 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
|
|||
strmov(net->last_error,ER(net->last_errno));
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
Part 3: Authorization data's been sent. Now server can reply with
|
||||
OK-packet, or re-request scrambled password.
|
||||
*/
|
||||
|
||||
if (mysql_autenticate(mysql, passwd))
|
||||
if ((pkt_length=net_safe_read(mysql)) == packet_error)
|
||||
goto error;
|
||||
|
||||
if (pkt_length == 1 && net->read_pos[0] == 254 &&
|
||||
mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
|
||||
{
|
||||
/*
|
||||
By sending this very specific reply server asks us to send scrambled
|
||||
password in old format.
|
||||
*/
|
||||
scramble_323(buff, mysql->scramble, passwd);
|
||||
if (my_net_write(net, buff, SCRAMBLE_LENGTH_323 + 1) || net_flush(net))
|
||||
{
|
||||
net->last_errno= CR_SERVER_LOST;
|
||||
strmov(net->sqlstate, unknown_sqlstate);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
if (client_flag & CLIENT_COMPRESS) /* We will use compression */
|
||||
net->compress=1;
|
||||
|
||||
|
|
|
@ -52,13 +52,6 @@ Item *create_func_ord(Item* a)
|
|||
return new Item_func_ord(a);
|
||||
}
|
||||
|
||||
Item *create_func_old_password(Item* a)
|
||||
{
|
||||
return new Item_func_old_password(a);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Item *create_func_asin(Item* a)
|
||||
{
|
||||
return new Item_func_asin(a);
|
||||
|
@ -332,11 +325,6 @@ Item *create_func_quarter(Item* a)
|
|||
return new Item_func_quarter(a);
|
||||
}
|
||||
|
||||
Item *create_func_password(Item* a)
|
||||
{
|
||||
return new Item_func_password(a);
|
||||
}
|
||||
|
||||
Item *create_func_radians(Item *a)
|
||||
{
|
||||
return new Item_func_units((char*) "radians",a,M_PI/180,0.0);
|
||||
|
|
|
@ -69,14 +69,12 @@ Item *create_func_monthname(Item* a);
|
|||
Item *create_func_nullif(Item* a, Item *b);
|
||||
Item *create_func_oct(Item *);
|
||||
Item *create_func_ord(Item* a);
|
||||
Item *create_func_old_password(Item* a);
|
||||
Item *create_func_period_add(Item* a, Item *b);
|
||||
Item *create_func_period_diff(Item* a, Item *b);
|
||||
Item *create_func_pi(void);
|
||||
Item *create_func_pow(Item* a, Item *b);
|
||||
Item *create_func_current_user(void);
|
||||
Item *create_func_quarter(Item* a);
|
||||
Item *create_func_password(Item* a);
|
||||
Item *create_func_radians(Item *a);
|
||||
Item *create_func_release_lock(Item* a);
|
||||
Item *create_func_repeat(Item* a, Item *b);
|
||||
|
|
|
@ -1327,95 +1327,49 @@ void Item_func_trim::fix_length_and_dec()
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void Item_func_password::fix_length_and_dec()
|
||||
{
|
||||
/*
|
||||
If PASSWORD() was called with only one argument, it depends on a random
|
||||
number so we need to save this random number into the binary log.
|
||||
If called with two arguments, it is repeatable.
|
||||
*/
|
||||
if (arg_count == 1)
|
||||
{
|
||||
THD *thd= current_thd;
|
||||
thd->rand_used= 1;
|
||||
thd->rand_saved_seed1= thd->rand.seed1;
|
||||
thd->rand_saved_seed2= thd->rand.seed2;
|
||||
}
|
||||
max_length= get_password_length(use_old_passwords);
|
||||
}
|
||||
|
||||
/*
|
||||
Password() function has 2 arguments. Second argument can be used
|
||||
to make results repeatable
|
||||
*/
|
||||
/* Item_func_password */
|
||||
|
||||
String *Item_func_password::val_str(String *str)
|
||||
{
|
||||
struct rand_struct rand_st; // local structure for 2 param version
|
||||
ulong seed=0; // seed to initialise random generator to
|
||||
|
||||
String *res =args[0]->val_str(str);
|
||||
if ((null_value=args[0]->null_value))
|
||||
return 0;
|
||||
|
||||
if (arg_count == 1)
|
||||
{
|
||||
if (res->length() == 0)
|
||||
return &empty_string;
|
||||
make_scrambled_password(tmp_value,res->c_ptr(),use_old_passwords,
|
||||
¤t_thd->rand);
|
||||
str->set(tmp_value,get_password_length(use_old_passwords),res->charset());
|
||||
return str;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We'll need the buffer to get second parameter */
|
||||
char key_buff[80];
|
||||
String tmp_key_value(key_buff, sizeof(key_buff), system_charset_info);
|
||||
String *key =args[1]->val_str(&tmp_key_value);
|
||||
|
||||
/* Check second argument for NULL value. First one is already checked */
|
||||
if ((null_value=args[1]->null_value))
|
||||
return 0;
|
||||
|
||||
/* This shall be done after checking for null for proper results */
|
||||
if (res->length() == 0)
|
||||
return &empty_string;
|
||||
|
||||
/* Generate the seed first this allows to avoid double allocation */
|
||||
char* seed_ptr=key->c_ptr();
|
||||
while (*seed_ptr)
|
||||
{
|
||||
seed=(seed*211+*seed_ptr) & 0xffffffffL; /* Use simple hashing */
|
||||
seed_ptr++;
|
||||
}
|
||||
|
||||
/* Use constants which allow nice random values even with small seed */
|
||||
randominit(&rand_st,
|
||||
(ulong) ((ulonglong) seed*111111+33333333L) & (ulong) 0xffffffff,
|
||||
(ulong) ((ulonglong) seed*1111+55555555L) & (ulong) 0xffffffff);
|
||||
|
||||
make_scrambled_password(tmp_value,res->c_ptr(),use_old_passwords,
|
||||
&rand_st);
|
||||
str->set(tmp_value,get_password_length(use_old_passwords),res->charset());
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
String *Item_func_old_password::val_str(String *str)
|
||||
{
|
||||
String *res =args[0]->val_str(str);
|
||||
String *res= args[0]->val_str(str);
|
||||
if ((null_value=args[0]->null_value))
|
||||
return 0;
|
||||
if (res->length() == 0)
|
||||
return &empty_string;
|
||||
make_scrambled_password(tmp_value,res->c_ptr(),1,¤t_thd->rand);
|
||||
str->set(tmp_value,16,res->charset());
|
||||
make_scrambled_password(tmp_value, res->c_ptr());
|
||||
str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH, res->charset());
|
||||
return str;
|
||||
}
|
||||
|
||||
char *Item_func_password::alloc(THD *thd, const char *password)
|
||||
{
|
||||
char *buff= (char *) thd->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH+1);
|
||||
if (buff)
|
||||
make_scrambled_password(buff, password);
|
||||
return buff;
|
||||
}
|
||||
|
||||
/* Item_func_old_password */
|
||||
|
||||
String *Item_func_old_password::val_str(String *str)
|
||||
{
|
||||
String *res= args[0]->val_str(str);
|
||||
if ((null_value=args[0]->null_value))
|
||||
return 0;
|
||||
if (res->length() == 0)
|
||||
return &empty_string;
|
||||
make_scrambled_password_323(tmp_value, res->c_ptr());
|
||||
str->set(tmp_value, SCRAMBLED_PASSWORD_CHAR_LENGTH_323, res->charset());
|
||||
return str;
|
||||
}
|
||||
|
||||
char *Item_func_old_password::alloc(THD *thd, const char *password)
|
||||
{
|
||||
char *buff= (char *) thd->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1);
|
||||
if (buff)
|
||||
make_scrambled_password_323(buff, password);
|
||||
return buff;
|
||||
}
|
||||
|
||||
|
||||
#define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.')
|
||||
|
|
|
@ -254,30 +254,45 @@ public:
|
|||
};
|
||||
|
||||
|
||||
/*
|
||||
Item_func_password -- new (4.1.1) PASSWORD() function implementation.
|
||||
Returns strcat('*', octet2hex(sha1(sha1(password)))). '*' stands for new
|
||||
password format, sha1(sha1(password) is so-called hash_stage2 value.
|
||||
Length of returned string is always 41 byte. To find out how entire
|
||||
authentification procedure works, see comments in password.c.
|
||||
*/
|
||||
|
||||
class Item_func_password :public Item_str_func
|
||||
{
|
||||
char tmp_value[64]; /* This should be enough for new password format */
|
||||
char tmp_value[SCRAMBLED_PASSWORD_CHAR_LENGTH+1];
|
||||
public:
|
||||
Item_func_password(Item *a) :Item_str_func(a) {}
|
||||
Item_func_password(Item *a, Item *b) :Item_str_func(a,b) {}
|
||||
String *val_str(String *);
|
||||
void fix_length_and_dec();
|
||||
String *val_str(String *str);
|
||||
void fix_length_and_dec() { max_length= SCRAMBLED_PASSWORD_CHAR_LENGTH; }
|
||||
const char *func_name() const { return "password"; }
|
||||
static char *alloc(THD *thd, const char *password);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Item_func_old_password -- PASSWORD() implementation used in MySQL 3.21 - 4.0
|
||||
compatibility mode. This item is created in sql_yacc.yy when
|
||||
'old_passwords' session variable is set, and to handle OLD_PASSWORD()
|
||||
function.
|
||||
*/
|
||||
|
||||
class Item_func_old_password :public Item_str_func
|
||||
{
|
||||
char tmp_value[17]; /* old password length +1 */
|
||||
char tmp_value[SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1];
|
||||
public:
|
||||
Item_func_old_password(Item *a) :Item_str_func(a) {}
|
||||
String *val_str(String *);
|
||||
void fix_length_and_dec() { max_length = get_password_length(1); }
|
||||
String *val_str(String *str);
|
||||
void fix_length_and_dec() { max_length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323; }
|
||||
const char *func_name() const { return "old_password"; }
|
||||
static char *alloc(THD *thd, const char *password);
|
||||
};
|
||||
|
||||
|
||||
|
||||
class Item_func_des_encrypt :public Item_str_func
|
||||
{
|
||||
String tmp_value;
|
||||
|
|
|
@ -294,6 +294,7 @@ static SYMBOL symbols[] = {
|
|||
{ "NULL", SYM(NULL_SYM),0,0},
|
||||
{ "NUMERIC", SYM(NUMERIC_SYM),0,0},
|
||||
{ "OFFSET", SYM(OFFSET_SYM),0,0},
|
||||
{ "OLD_PASSWORD", SYM(OLD_PASSWORD),0,0},
|
||||
{ "ON", SYM(ON),0,0},
|
||||
{ "OPEN", SYM(OPEN_SYM),0,0},
|
||||
{ "OPTIMIZE", SYM(OPTIMIZE),0,0},
|
||||
|
@ -596,7 +597,6 @@ static SYMBOL sql_functions[] = {
|
|||
{ "NUMPOINTS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_numpoints)},
|
||||
{ "OCTET_LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_length)},
|
||||
{ "OCT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_oct)},
|
||||
{ "OLD_PASSWORD", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_old_password)},
|
||||
{ "ORD", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ord)},
|
||||
{ "OVERLAPS", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_overlaps)},
|
||||
{ "PERIOD_ADD", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_period_add)},
|
||||
|
|
|
@ -74,9 +74,6 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset;
|
|||
****************************************************************************/
|
||||
|
||||
#define ACL_CACHE_SIZE 256
|
||||
/* Password lengh for 4.1 version previous versions had 16 bytes password hash */
|
||||
#define HASH_PASSWORD_LENGTH 45
|
||||
#define HASH_OLD_PASSWORD_LENGTH 16
|
||||
#define MAX_PASSWORD_LENGTH 32
|
||||
#define HOST_CACHE_SIZE 128
|
||||
#define MAX_ACCEPT_RETRY 10 // Test accept this many times
|
||||
|
@ -771,7 +768,7 @@ extern my_bool opt_safe_show_db, opt_local_infile, lower_case_table_names;
|
|||
extern my_bool opt_slave_compressed_protocol, use_temp_pool;
|
||||
extern my_bool opt_readonly;
|
||||
extern my_bool opt_enable_named_pipe;
|
||||
extern my_bool opt_old_passwords, use_old_passwords;
|
||||
extern my_bool opt_secure_auth;
|
||||
extern char *shared_memory_base_name, *mysqld_unix_port;
|
||||
extern bool opt_enable_shared_memory;
|
||||
|
||||
|
|
|
@ -257,9 +257,10 @@ my_bool opt_local_infile, opt_external_locking, opt_slave_compressed_protocol;
|
|||
my_bool opt_safe_user_create = 0, opt_no_mix_types = 0;
|
||||
my_bool lower_case_table_names, opt_old_rpl_compat;
|
||||
my_bool opt_show_slave_auth_info, opt_sql_bin_update = 0;
|
||||
my_bool opt_log_slave_updates= 0, opt_old_passwords=0, use_old_passwords=0;
|
||||
my_bool opt_log_slave_updates= 0;
|
||||
my_bool opt_console= 0, opt_bdb, opt_innodb, opt_isam;
|
||||
my_bool opt_readonly, use_temp_pool, relay_log_purge;
|
||||
my_bool opt_secure_auth= 0;
|
||||
volatile bool mqh_used = 0;
|
||||
|
||||
uint mysqld_port, test_flags, select_errors, dropping_tables, ha_open_options;
|
||||
|
@ -2819,12 +2820,6 @@ static void create_new_thread(THD *thd)
|
|||
if (thread_count-delayed_insert_threads > max_used_connections)
|
||||
max_used_connections=thread_count-delayed_insert_threads;
|
||||
thd->thread_id=thread_id++;
|
||||
for (uint i=0; i < 8 ; i++) // Generate password teststring
|
||||
thd->scramble[i]= (char) (my_rnd(&sql_rand)*94+33);
|
||||
thd->scramble[8]=0;
|
||||
// Back it up as old clients may need it
|
||||
memcpy(thd->old_scramble,thd->scramble,9);
|
||||
|
||||
|
||||
thd->real_id=pthread_self(); // Keep purify happy
|
||||
|
||||
|
@ -3535,7 +3530,8 @@ enum options
|
|||
OPT_EXPIRE_LOGS_DAYS,
|
||||
OPT_DEFAULT_WEEK_FORMAT,
|
||||
OPT_GROUP_CONCAT_MAX_LEN,
|
||||
OPT_DEFAULT_COLLATION
|
||||
OPT_DEFAULT_COLLATION,
|
||||
OPT_SECURE_AUTH
|
||||
};
|
||||
|
||||
|
||||
|
@ -3845,9 +3841,10 @@ master-ssl",
|
|||
(gptr*) &opt_no_mix_types, (gptr*) &opt_no_mix_types, 0, GET_BOOL, NO_ARG,
|
||||
0, 0, 0, 0, 0, 0},
|
||||
#endif
|
||||
{"old-protocol", 'o', "Use the old (3.20) protocol client/server protocol.",
|
||||
(gptr*) &protocol_version, (gptr*) &protocol_version, 0, GET_UINT, NO_ARG,
|
||||
PROTOCOL_VERSION, 0, 0, 0, 0, 0},
|
||||
{"old-passwords", OPT_OLD_PASSWORDS, "Use old password encryption method (needed for 4.0 and older clients).",
|
||||
(gptr*) &global_system_variables.old_passwords,
|
||||
(gptr*) &max_system_variables.old_passwords, 0, GET_BOOL, NO_ARG,
|
||||
0, 0, 0, 0, 0, 0},
|
||||
{"old-rpl-compat", OPT_OLD_RPL_COMPAT,
|
||||
"Use old LOAD DATA format in the binary log (don't save data in file).",
|
||||
(gptr*) &opt_old_rpl_compat, (gptr*) &opt_old_rpl_compat, 0, GET_BOOL,
|
||||
|
@ -3914,8 +3911,6 @@ relay logs.",
|
|||
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"safe-mode", OPT_SAFE, "Skip some optimize stages (for testing).",
|
||||
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"old-passwords", OPT_OLD_PASSWORDS, "Use old password encryption method (needed for 4.0 and older clients).",
|
||||
(gptr*) &opt_old_passwords, (gptr*) &opt_old_passwords, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
||||
#ifndef TO_BE_DELETED
|
||||
{"safe-show-database", OPT_SAFE_SHOW_DB,
|
||||
"Deprecated option; One should use GRANT SHOW DATABASES instead...",
|
||||
|
@ -3925,6 +3920,9 @@ relay logs.",
|
|||
"Don't allow new user creation by the user who has no write privileges to the mysql.user table.",
|
||||
(gptr*) &opt_safe_user_create, (gptr*) &opt_safe_user_create, 0, GET_BOOL,
|
||||
NO_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"secure-auth", OPT_SECURE_AUTH, "Disallow authentication for accounts that have old (pre-4.1) passwords.",
|
||||
(gptr*) &opt_secure_auth, (gptr*) &opt_secure_auth, 0, GET_BOOL, NO_ARG,
|
||||
my_bool(0), 0, 0, 0, 0, 0},
|
||||
{"server-id", OPT_SERVER_ID,
|
||||
"Uniquely identifies the server instance in the community of replication partners.",
|
||||
(gptr*) &server_id, (gptr*) &server_id, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 0,
|
||||
|
@ -4709,7 +4707,8 @@ static void mysql_init_variables(void)
|
|||
opt_log= opt_update_log= opt_bin_log= opt_slow_log= 0;
|
||||
opt_disable_networking= opt_skip_show_db=0;
|
||||
opt_logname= opt_update_logname= opt_binlog_index_name= opt_slow_logname=0;
|
||||
opt_bootstrap= opt_myisam_log= use_old_passwords= 0;
|
||||
opt_secure_auth= 0;
|
||||
opt_bootstrap= opt_myisam_log= 0;
|
||||
mqh_used= 0;
|
||||
segfaulted= kill_in_progress= 0;
|
||||
cleanup_done= 0;
|
||||
|
@ -4813,6 +4812,7 @@ static void mysql_init_variables(void)
|
|||
max_system_variables.select_limit= (ulonglong) HA_POS_ERROR;
|
||||
global_system_variables.max_join_size= (ulonglong) HA_POS_ERROR;
|
||||
max_system_variables.max_join_size= (ulonglong) HA_POS_ERROR;
|
||||
global_system_variables.old_passwords= 0;
|
||||
|
||||
/* Variables that depends on compile options */
|
||||
#ifndef DBUG_OFF
|
||||
|
@ -4934,9 +4934,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
|
|||
case 'L':
|
||||
strmake(language, argument, sizeof(language)-1);
|
||||
break;
|
||||
case 'o':
|
||||
protocol_version=PROTOCOL_VERSION-1;
|
||||
break;
|
||||
#ifdef HAVE_REPLICATION
|
||||
case OPT_SLAVE_SKIP_ERRORS:
|
||||
init_slave_skip_errors(argument);
|
||||
|
|
936
sql/password.c
936
sql/password.c
File diff suppressed because it is too large
Load diff
|
@ -349,6 +349,25 @@ send_eof(THD *thd, bool no_flush)
|
|||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/*
|
||||
Please client to send scrambled_password in old format.
|
||||
SYNOPSYS
|
||||
send_old_password_request()
|
||||
thd thread handle
|
||||
|
||||
RETURN VALUE
|
||||
0 ok
|
||||
!0 error
|
||||
*/
|
||||
|
||||
bool send_old_password_request(THD *thd)
|
||||
{
|
||||
static char buff[1]= { (char) 254 };
|
||||
NET *net= &thd->net;
|
||||
return my_net_write(net, buff, 1) || net_flush(net);
|
||||
}
|
||||
|
||||
#endif /* EMBEDDED_LIBRARY */
|
||||
|
||||
/*
|
||||
|
|
|
@ -164,6 +164,7 @@ void net_printf(THD *thd,uint sql_errno, ...);
|
|||
void send_ok(THD *thd, ha_rows affected_rows=0L, ulonglong id=0L,
|
||||
const char *info=0);
|
||||
void send_eof(THD *thd, bool no_flush=0);
|
||||
bool send_old_password_request(THD *thd);
|
||||
char *net_store_length(char *packet,ulonglong length);
|
||||
char *net_store_length(char *packet,uint length);
|
||||
char *net_store_data(char *to,const char *from, uint length);
|
||||
|
|
|
@ -216,6 +216,7 @@ sys_var_thd_ulong sys_net_retry_count("net_retry_count",
|
|||
&SV::net_retry_count,
|
||||
fix_net_retry_count);
|
||||
sys_var_thd_bool sys_new_mode("new", &SV::new_mode);
|
||||
sys_var_thd_bool sys_old_passwords("old_passwords", &SV::old_passwords);
|
||||
sys_var_thd_ulong sys_preload_buff_size("preload_buffer_size",
|
||||
&SV::preload_buff_size);
|
||||
sys_var_thd_ulong sys_read_buff_size("read_buffer_size",
|
||||
|
@ -242,6 +243,7 @@ sys_var_thd_enum sys_query_cache_type("query_cache_type",
|
|||
&SV::query_cache_type,
|
||||
&query_cache_type_typelib);
|
||||
#endif /* HAVE_QUERY_CACHE */
|
||||
sys_var_bool_ptr sys_secure_auth("secure_auth", &opt_secure_auth);
|
||||
sys_var_long_ptr sys_server_id("server_id",&server_id);
|
||||
sys_var_bool_ptr sys_slave_compressed_protocol("slave_compressed_protocol",
|
||||
&opt_slave_compressed_protocol);
|
||||
|
@ -432,6 +434,7 @@ sys_var *sys_variables[]=
|
|||
&sys_net_wait_timeout,
|
||||
&sys_net_write_timeout,
|
||||
&sys_new_mode,
|
||||
&sys_old_passwords,
|
||||
&sys_preload_buff_size,
|
||||
&sys_pseudo_thread_id,
|
||||
&sys_query_cache_size,
|
||||
|
@ -450,6 +453,7 @@ sys_var *sys_variables[]=
|
|||
#endif
|
||||
&sys_rpl_recovery_rank,
|
||||
&sys_safe_updates,
|
||||
&sys_secure_auth,
|
||||
&sys_select_limit,
|
||||
&sys_server_id,
|
||||
#ifdef HAVE_REPLICATION
|
||||
|
@ -608,6 +612,7 @@ struct show_var_st init_vars[]= {
|
|||
{sys_net_retry_count.name, (char*) &sys_net_retry_count, SHOW_SYS},
|
||||
{sys_net_write_timeout.name,(char*) &sys_net_write_timeout, SHOW_SYS},
|
||||
{sys_new_mode.name, (char*) &sys_new_mode, SHOW_SYS},
|
||||
{sys_old_passwords.name, (char*) &sys_old_passwords, SHOW_SYS},
|
||||
{"open_files_limit", (char*) &open_files_limit, SHOW_LONG},
|
||||
{"pid_file", (char*) pidfile_name, SHOW_CHAR},
|
||||
{"log_error", (char*) log_error_file, SHOW_CHAR},
|
||||
|
@ -628,6 +633,7 @@ struct show_var_st init_vars[]= {
|
|||
SHOW_SYS},
|
||||
{sys_query_cache_size.name, (char*) &sys_query_cache_size, SHOW_SYS},
|
||||
{sys_query_cache_type.name, (char*) &sys_query_cache_type, SHOW_SYS},
|
||||
{"secure_auth", (char*) &sys_secure_auth, SHOW_SYS},
|
||||
#endif /* HAVE_QUERY_CACHE */
|
||||
#ifdef HAVE_SMEM
|
||||
{"shared_memory", (char*) &opt_enable_shared_memory, SHOW_MY_BOOL},
|
||||
|
|
|
@ -689,6 +689,9 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/* updated in sql_acl.cc */
|
||||
|
||||
extern sys_var_thd_bool sys_old_passwords;
|
||||
|
||||
/* For sql_yacc */
|
||||
struct sys_var_with_base
|
||||
|
|
|
@ -279,3 +279,4 @@ v/*
|
|||
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
|
||||
"Unknown collation: '%-.64s'",
|
||||
"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
|
||||
"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
|
||||
|
|
|
@ -273,3 +273,4 @@
|
|||
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
|
||||
"Unknown collation: '%-.64s'",
|
||||
"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
|
||||
"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
|
||||
|
|
|
@ -281,3 +281,4 @@
|
|||
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
|
||||
"Unknown collation: '%-.64s'",
|
||||
"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
|
||||
"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
|
||||
|
|
|
@ -275,3 +275,4 @@
|
|||
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
|
||||
"Unknown collation: '%-.64s'",
|
||||
"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
|
||||
"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
|
||||
|
|
|
@ -275,3 +275,4 @@
|
|||
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
|
||||
"Unknown collation: '%-.64s'",
|
||||
"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
|
||||
"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
|
||||
|
|
|
@ -270,3 +270,4 @@
|
|||
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
|
||||
"Unknown collation: '%-.64s'",
|
||||
"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
|
||||
"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
|
||||
|
|
|
@ -279,3 +279,4 @@
|
|||
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
|
||||
"Unknown collation: '%-.64s'",
|
||||
"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
|
||||
"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
|
||||
|
|
|
@ -270,3 +270,4 @@
|
|||
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
|
||||
"Unknown collation: '%-.64s'",
|
||||
"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
|
||||
"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
|
||||
|
|
|
@ -272,3 +272,4 @@
|
|||
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
|
||||
"Unknown collation: '%-.64s'",
|
||||
"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
|
||||
"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
|
||||
|
|
|
@ -270,3 +270,4 @@
|
|||
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
|
||||
"Unknown collation: '%-.64s'",
|
||||
"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
|
||||
"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
|
||||
|
|
|
@ -272,3 +272,4 @@
|
|||
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
|
||||
"Unknown collation: '%-.64s'",
|
||||
"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
|
||||
"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
|
||||
|
|
|
@ -270,3 +270,4 @@
|
|||
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
|
||||
"Unknown collation: '%-.64s'",
|
||||
"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
|
||||
"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
|
||||
|
|
|
@ -272,3 +272,4 @@
|
|||
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
|
||||
"Unknown collation: '%-.64s'",
|
||||
"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
|
||||
"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
|
||||
|
|
|
@ -272,3 +272,4 @@
|
|||
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
|
||||
"Unknown collation: '%-.64s'",
|
||||
"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
|
||||
"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
|
||||
|
|
|
@ -274,3 +274,4 @@
|
|||
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
|
||||
"Unknown collation: '%-.64s'",
|
||||
"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
|
||||
"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
|
||||
|
|
|
@ -270,3 +270,4 @@
|
|||
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
|
||||
"Unknown collation: '%-.64s'",
|
||||
"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
|
||||
"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
|
||||
|
|
|
@ -274,3 +274,4 @@
|
|||
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
|
||||
"Unknown collation: '%-.64s'",
|
||||
"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
|
||||
"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
|
||||
|
|
|
@ -272,3 +272,4 @@
|
|||
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
|
||||
"Unknown collation: '%-.64s'",
|
||||
"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
|
||||
"Сервер запущен в режиме --secure-auth (безопасной авторизации), но для пользователя '%s@%s' пароль сохранён в старом формате; необходимо обновить формат пароля"
|
||||
|
|
|
@ -265,3 +265,4 @@
|
|||
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
|
||||
"Unknown collation: '%-.64s'",
|
||||
"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
|
||||
"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
|
||||
|
|
|
@ -278,3 +278,4 @@
|
|||
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
|
||||
"Unknown collation: '%-.64s'",
|
||||
"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
|
||||
"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
|
||||
|
|
|
@ -271,3 +271,4 @@
|
|||
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
|
||||
"Unknown collation: '%-.64s'",
|
||||
"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
|
||||
"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
|
||||
|
|
|
@ -270,3 +270,4 @@
|
|||
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
|
||||
"Unknown collation: '%-.64s'",
|
||||
"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
|
||||
"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
|
||||
|
|
|
@ -275,3 +275,4 @@
|
|||
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
|
||||
"Unknown collation: '%-.64s'",
|
||||
"SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started."
|
||||
"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format"
|
||||
|
|
|
@ -1554,7 +1554,7 @@ void init_master_info_with_options(MASTER_INFO* mi)
|
|||
if (master_user)
|
||||
strmake(mi->user, master_user, sizeof(mi->user) - 1);
|
||||
if (master_password)
|
||||
strmake(mi->password, master_password, HASH_PASSWORD_LENGTH);
|
||||
strmake(mi->password, master_password, MAX_PASSWORD_LENGTH);
|
||||
mi->port = master_port;
|
||||
mi->connect_retry = master_connect_retry;
|
||||
|
||||
|
@ -1707,8 +1707,8 @@ file '%s')", fname);
|
|||
master_host) ||
|
||||
init_strvar_from_file(mi->user, sizeof(mi->user), &mi->file,
|
||||
master_user) ||
|
||||
init_strvar_from_file(mi->password, HASH_PASSWORD_LENGTH+1, &mi->file,
|
||||
master_password) ||
|
||||
init_strvar_from_file(mi->password, SCRAMBLED_PASSWORD_CHAR_LENGTH+1,
|
||||
&mi->file, master_password) ||
|
||||
init_intvar_from_file(&port, &mi->file, master_port) ||
|
||||
init_intvar_from_file(&connect_retry, &mi->file,
|
||||
master_connect_retry))
|
||||
|
|
615
sql/sql_acl.cc
615
sql/sql_acl.cc
|
@ -51,7 +51,7 @@ static byte* acl_entry_get_key(acl_entry *entry,uint *length,
|
|||
return (byte*) entry->key;
|
||||
}
|
||||
|
||||
#define ACL_KEY_LENGTH (sizeof(long)+NAME_LEN+17)
|
||||
#define ACL_KEY_LENGTH (sizeof(long)+NAME_LEN+USERNAME_LENGTH+1)
|
||||
|
||||
static DYNAMIC_ARRAY acl_hosts,acl_users,acl_dbs;
|
||||
static MEM_ROOT mem, memex;
|
||||
|
@ -68,11 +68,53 @@ static ulong get_sort(uint count,...);
|
|||
static void init_check_host(void);
|
||||
static ACL_USER *find_acl_user(const char *host, const char *user);
|
||||
static bool update_user_table(THD *thd, const char *host, const char *user,
|
||||
const char *new_password);
|
||||
const char *new_password, uint new_password_len);
|
||||
static void update_hostname(acl_host_and_ip *host, const char *hostname);
|
||||
static bool compare_hostname(const acl_host_and_ip *host,const char *hostname,
|
||||
const char *ip);
|
||||
|
||||
/*
|
||||
Convert scrambled password to binary form, according to scramble type,
|
||||
Binary form is stored in user.salt.
|
||||
*/
|
||||
|
||||
static
|
||||
void
|
||||
set_user_salt(ACL_USER *acl_user, const char *password, uint password_len)
|
||||
{
|
||||
if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH)
|
||||
{
|
||||
get_salt_from_password(acl_user->salt, password);
|
||||
acl_user->salt_len= SCRAMBLE_LENGTH;
|
||||
}
|
||||
else if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
|
||||
{
|
||||
get_salt_from_password_323((ulong *) acl_user->salt, password);
|
||||
acl_user->salt_len= SCRAMBLE_LENGTH_323;
|
||||
}
|
||||
else
|
||||
acl_user->salt_len= 0;
|
||||
}
|
||||
|
||||
/*
|
||||
This after_update function is used when user.password is less than
|
||||
SCRAMBLE_LENGTH bytes.
|
||||
*/
|
||||
|
||||
static void restrict_update_of_old_passwords_var(THD *thd,
|
||||
enum_var_type var_type)
|
||||
{
|
||||
if (var_type == OPT_GLOBAL)
|
||||
{
|
||||
pthread_mutex_lock(&LOCK_global_system_variables);
|
||||
global_system_variables.old_passwords= 1;
|
||||
pthread_mutex_unlock(&LOCK_global_system_variables);
|
||||
}
|
||||
else
|
||||
thd->variables.old_passwords= 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Read grant privileges from the privilege tables in the 'mysql' database.
|
||||
|
||||
|
@ -114,8 +156,6 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
|
|||
if (!(thd=new THD))
|
||||
DBUG_RETURN(1); /* purecov: inspected */
|
||||
thd->store_globals();
|
||||
/* Use passwords according to command line option */
|
||||
use_old_passwords= opt_old_passwords;
|
||||
|
||||
acl_cache->clear(1); // Clear locked hostname cache
|
||||
thd->db= my_strdup("mysql",MYF(0));
|
||||
|
@ -172,103 +212,126 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
|
|||
|
||||
init_read_record(&read_record_info,thd,table=tables[1].table,NULL,1,0);
|
||||
VOID(my_init_dynamic_array(&acl_users,sizeof(ACL_USER),50,100));
|
||||
if (table->field[2]->field_length == 8 &&
|
||||
protocol_version == PROTOCOL_VERSION)
|
||||
if (table->field[2]->field_length < SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
|
||||
{
|
||||
sql_print_error("Old 'user' table. (Check README or the Reference manual). Continuing --old-protocol"); /* purecov: tested */
|
||||
protocol_version=9; /* purecov: tested */
|
||||
sql_print_error("Fatal error: mysql.user table is damaged or in "
|
||||
"unsupported 3.20 format.");
|
||||
goto end;
|
||||
}
|
||||
|
||||
DBUG_PRINT("info",("user table fields: %d, password length: %d",
|
||||
table->fields, table->field[2]->field_length));
|
||||
if (table->field[2]->field_length < 45 && !use_old_passwords)
|
||||
|
||||
pthread_mutex_lock(&LOCK_global_system_variables);
|
||||
if (table->field[2]->field_length < SCRAMBLED_PASSWORD_CHAR_LENGTH)
|
||||
{
|
||||
sql_print_error("mysql.user table is not updated to new password format; Disabling new password usage until mysql_fix_privilege_tables is run");
|
||||
use_old_passwords= 1;
|
||||
if (opt_secure_auth)
|
||||
{
|
||||
pthread_mutex_unlock(&LOCK_global_system_variables);
|
||||
sql_print_error("Fatal error: mysql.user table is in old format, "
|
||||
"but server started with --secure-auth option.");
|
||||
goto end;
|
||||
}
|
||||
sys_old_passwords.after_update= restrict_update_of_old_passwords_var;
|
||||
if (global_system_variables.old_passwords)
|
||||
pthread_mutex_unlock(&LOCK_global_system_variables);
|
||||
else
|
||||
{
|
||||
global_system_variables.old_passwords= 1;
|
||||
pthread_mutex_unlock(&LOCK_global_system_variables);
|
||||
sql_print_error("mysql.user table is not updated to new password format; "
|
||||
"Disabling new password usage until "
|
||||
"mysql_fix_privilege_tables is run");
|
||||
}
|
||||
thd->variables.old_passwords= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
sys_old_passwords.after_update= 0;
|
||||
pthread_mutex_unlock(&LOCK_global_system_variables);
|
||||
}
|
||||
|
||||
allow_all_hosts=0;
|
||||
while (!(read_record_info.read_record(&read_record_info)))
|
||||
{
|
||||
ACL_USER user;
|
||||
uint length=0;
|
||||
update_hostname(&user.host,get_field(&mem, table->field[0]));
|
||||
user.user=get_field(&mem, table->field[1]);
|
||||
user.password=get_field(&mem, table->field[2]);
|
||||
if (user.password && (length=(uint) strlen(user.password)) == 8 &&
|
||||
protocol_version == PROTOCOL_VERSION)
|
||||
update_hostname(&user.host, get_field(&mem, table->field[0]));
|
||||
user.user= get_field(&mem, table->field[1]);
|
||||
const char *password= get_field(&mem, table->field[2]);
|
||||
uint password_len= password ? strlen(password) : 0;
|
||||
set_user_salt(&user, password, password_len);
|
||||
if (user.salt_len == 0 && password_len != 0)
|
||||
{
|
||||
sql_print_error(
|
||||
"Found old style password for user '%s'. Ignoring user. (You may want to restart mysqld using --old-protocol)",
|
||||
user.user ? user.user : ""); /* purecov: tested */
|
||||
switch (password_len) {
|
||||
case 45: /* 4.1: to be removed */
|
||||
sql_print_error("Found 4.1 style password for user '%s@%s'. "
|
||||
"Ignoring user. "
|
||||
"You should change password for this user.",
|
||||
user.user ? user.user : "",
|
||||
user.host.hostname ? user.host.hostname : "");
|
||||
break;
|
||||
default:
|
||||
sql_print_error("Found invalid password for user: '%s@%s'; "
|
||||
"Ignoring user", user.user ? user.user : "",
|
||||
user.host.hostname ? user.host.hostname : "");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else /* non empty and not short passwords */
|
||||
else // password is correct
|
||||
{
|
||||
user.pversion=get_password_version(user.password);
|
||||
/* Only passwords of specific lengths depending on version are allowed */
|
||||
if ((!user.pversion && (length % 8 || length > 16)) ||
|
||||
(user.pversion && length != 45))
|
||||
user.access= get_access(table,3) & GLOBAL_ACLS;
|
||||
user.sort= get_sort(2,user.host.hostname,user.user);
|
||||
user.hostname_length= (user.host.hostname ?
|
||||
(uint) strlen(user.host.hostname) : 0);
|
||||
if (table->fields >= 31) /* Starting from 4.0.2 we have more fields */
|
||||
{
|
||||
sql_print_error(
|
||||
"Found invalid password for user: '%s'@'%s'; Ignoring user",
|
||||
user.user ? user.user : "",
|
||||
user.host.hostname ? user.host.hostname : ""); /* purecov: tested */
|
||||
continue; /* purecov: tested */
|
||||
char *ssl_type=get_field(&mem, table->field[24]);
|
||||
if (!ssl_type)
|
||||
user.ssl_type=SSL_TYPE_NONE;
|
||||
else if (!strcmp(ssl_type, "ANY"))
|
||||
user.ssl_type=SSL_TYPE_ANY;
|
||||
else if (!strcmp(ssl_type, "X509"))
|
||||
user.ssl_type=SSL_TYPE_X509;
|
||||
else /* !strcmp(ssl_type, "SPECIFIED") */
|
||||
user.ssl_type=SSL_TYPE_SPECIFIED;
|
||||
|
||||
user.ssl_cipher= get_field(&mem, table->field[25]);
|
||||
user.x509_issuer= get_field(&mem, table->field[26]);
|
||||
user.x509_subject= get_field(&mem, table->field[27]);
|
||||
|
||||
char *ptr = get_field(&mem, table->field[28]);
|
||||
user.user_resource.questions=atoi(ptr);
|
||||
ptr = get_field(&mem, table->field[29]);
|
||||
user.user_resource.updates=atoi(ptr);
|
||||
ptr = get_field(&mem, table->field[30]);
|
||||
user.user_resource.connections=atoi(ptr);
|
||||
if (user.user_resource.questions || user.user_resource.updates ||
|
||||
user.user_resource.connections)
|
||||
mqh_used=1;
|
||||
}
|
||||
}
|
||||
get_salt_from_password(user.salt,user.password);
|
||||
user.access=get_access(table,3) & GLOBAL_ACLS;
|
||||
user.sort=get_sort(2,user.host.hostname,user.user);
|
||||
user.hostname_length= (user.host.hostname ?
|
||||
(uint) strlen(user.host.hostname) : 0);
|
||||
if (table->fields >= 31) /* Starting from 4.0.2 we have more fields */
|
||||
{
|
||||
char *ssl_type=get_field(&mem, table->field[24]);
|
||||
if (!ssl_type)
|
||||
user.ssl_type=SSL_TYPE_NONE;
|
||||
else if (!strcmp(ssl_type, "ANY"))
|
||||
user.ssl_type=SSL_TYPE_ANY;
|
||||
else if (!strcmp(ssl_type, "X509"))
|
||||
user.ssl_type=SSL_TYPE_X509;
|
||||
else /* !strcmp(ssl_type, "SPECIFIED") */
|
||||
user.ssl_type=SSL_TYPE_SPECIFIED;
|
||||
|
||||
user.ssl_cipher= get_field(&mem, table->field[25]);
|
||||
user.x509_issuer= get_field(&mem, table->field[26]);
|
||||
user.x509_subject= get_field(&mem, table->field[27]);
|
||||
|
||||
char *ptr = get_field(&mem, table->field[28]);
|
||||
user.user_resource.questions=atoi(ptr);
|
||||
ptr = get_field(&mem, table->field[29]);
|
||||
user.user_resource.updates=atoi(ptr);
|
||||
ptr = get_field(&mem, table->field[30]);
|
||||
user.user_resource.connections=atoi(ptr);
|
||||
if (user.user_resource.questions || user.user_resource.updates ||
|
||||
user.user_resource.connections)
|
||||
mqh_used=1;
|
||||
}
|
||||
else
|
||||
{
|
||||
user.ssl_type=SSL_TYPE_NONE;
|
||||
bzero((char *)&(user.user_resource),sizeof(user.user_resource));
|
||||
else
|
||||
{
|
||||
user.ssl_type=SSL_TYPE_NONE;
|
||||
bzero((char *)&(user.user_resource),sizeof(user.user_resource));
|
||||
#ifndef TO_BE_REMOVED
|
||||
if (table->fields <= 13)
|
||||
{ // Without grant
|
||||
if (user.access & CREATE_ACL)
|
||||
user.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL;
|
||||
}
|
||||
/* Convert old privileges */
|
||||
user.access|= LOCK_TABLES_ACL | CREATE_TMP_ACL | SHOW_DB_ACL;
|
||||
if (user.access & FILE_ACL)
|
||||
user.access|= REPL_CLIENT_ACL | REPL_SLAVE_ACL;
|
||||
if (user.access & PROCESS_ACL)
|
||||
user.access|= SUPER_ACL | EXECUTE_ACL;
|
||||
if (table->fields <= 13)
|
||||
{ // Without grant
|
||||
if (user.access & CREATE_ACL)
|
||||
user.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL;
|
||||
}
|
||||
/* Convert old privileges */
|
||||
user.access|= LOCK_TABLES_ACL | CREATE_TMP_ACL | SHOW_DB_ACL;
|
||||
if (user.access & FILE_ACL)
|
||||
user.access|= REPL_CLIENT_ACL | REPL_SLAVE_ACL;
|
||||
if (user.access & PROCESS_ACL)
|
||||
user.access|= SUPER_ACL | EXECUTE_ACL;
|
||||
#endif
|
||||
}
|
||||
VOID(push_dynamic(&acl_users,(gptr) &user));
|
||||
if (!user.host.hostname || user.host.hostname[0] == wild_many &&
|
||||
!user.host.hostname[1])
|
||||
allow_all_hosts=1; // Anyone can connect
|
||||
}
|
||||
VOID(push_dynamic(&acl_users,(gptr) &user));
|
||||
if (!user.host.hostname || user.host.hostname[0] == wild_many &&
|
||||
!user.host.hostname[1])
|
||||
allow_all_hosts=1; // Anyone can connect
|
||||
}
|
||||
qsort((gptr) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements,
|
||||
sizeof(ACL_USER),(qsort_cmp) acl_compare);
|
||||
|
@ -469,135 +532,105 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b)
|
|||
|
||||
|
||||
/*
|
||||
Prepare crypted scramble to be sent to the client
|
||||
Seek ACL entry for a user, check password, SSL cypher, and if
|
||||
everything is OK, update THD user data and USER_RESOURCES struct.
|
||||
|
||||
IMPLEMENTATION
|
||||
This function does not check if the user has any sensible privileges:
|
||||
only user's existence and validity is checked.
|
||||
Note, that entire operation is protected by acl_cache_lock.
|
||||
|
||||
SYNOPSIS
|
||||
acl_getroot()
|
||||
thd thread handle. If all checks are OK,
|
||||
thd->priv_user, thd->master_access are updated.
|
||||
thd->host, thd->ip, thd->user are used for checks.
|
||||
mqh user resources; on success mqh is reset, else
|
||||
unchanged
|
||||
passwd scrambled & crypted password, recieved from client
|
||||
(to check): thd->scramble or thd->scramble_323 is
|
||||
used to decrypt passwd, so they must contain
|
||||
original random string,
|
||||
passwd_len length of passwd, must be one of 0, 8,
|
||||
SCRAMBLE_LENGTH_323, SCRAMBLE_LENGTH
|
||||
'thd' and 'mqh' are updated on success; other params are IN.
|
||||
|
||||
RETURN VALUE
|
||||
0 success: thd->priv_user, thd->priv_host, thd->master_access, mqh are
|
||||
updated
|
||||
1 user not found or authentification failure
|
||||
2 user found, has long (4.1.1) salt, but passwd is in old (3.23) format.
|
||||
-1 user found, has short (3.23) salt, but passwd is in new (4.1.1) format.
|
||||
*/
|
||||
|
||||
void prepare_scramble(THD *thd, ACL_USER *acl_user,char* prepared_scramble)
|
||||
int acl_getroot(THD *thd, USER_RESOURCES *mqh,
|
||||
const char *passwd, uint passwd_len)
|
||||
{
|
||||
/* Binary password format to be used for generation*/
|
||||
char bin_password[SCRAMBLE41_LENGTH];
|
||||
/* Generate new long scramble for the thread */
|
||||
create_random_string(SCRAMBLE41_LENGTH,&thd->rand,thd->scramble);
|
||||
thd->scramble[SCRAMBLE41_LENGTH]=0;
|
||||
/* Get binary form, First 4 bytes of prepared scramble is salt */
|
||||
get_hash_and_password(acl_user->salt,acl_user->pversion,prepared_scramble,
|
||||
(unsigned char*) bin_password);
|
||||
/* Store "*" as identifier for old passwords */
|
||||
if (!acl_user->pversion)
|
||||
prepared_scramble[0]='*';
|
||||
/* Finally encrypt password to get prepared scramble */
|
||||
password_crypt(thd->scramble, prepared_scramble+4, bin_password,
|
||||
SCRAMBLE41_LENGTH);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
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,
|
||||
char *priv_host, bool old_ver, USER_RESOURCES *mqh,
|
||||
char *prepared_scramble, uint *cur_priv_version,
|
||||
ACL_USER **cached_user)
|
||||
{
|
||||
ulong user_access=NO_ACCESS;
|
||||
*priv_user= (char*) user;
|
||||
bool password_correct= 0;
|
||||
int stage= (*cached_user != NULL); /* NULL passed as first stage */
|
||||
ACL_USER *acl_user= NULL;
|
||||
DBUG_ENTER("acl_getroot");
|
||||
|
||||
bzero((char*) mqh, sizeof(USER_RESOURCES));
|
||||
if (!initialized)
|
||||
{
|
||||
// If no data allow anything
|
||||
DBUG_RETURN((ulong) ~NO_ACCESS); /* purecov: tested */
|
||||
/*
|
||||
here if mysqld's been started with --skip-grant-tables option.
|
||||
*/
|
||||
thd->priv_user= (char *) ""; // privileges for
|
||||
*thd->priv_host= '\0'; // the user are unknown
|
||||
thd->master_access= ~NO_ACCESS; // everything is allowed
|
||||
bzero(mqh, sizeof(*mqh));
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
int res= 1;
|
||||
|
||||
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.
|
||||
Find acl entry in user database. Note, that find_acl_user is not the same,
|
||||
because it doesn't take into account the case when user is not empty,
|
||||
but acl_user->user is empty
|
||||
*/
|
||||
|
||||
if (stage && (*cur_priv_version == priv_version))
|
||||
acl_user= *cached_user;
|
||||
else
|
||||
ACL_USER *acl_user= 0;
|
||||
for (uint i=0 ; i < acl_users.elements ; i++)
|
||||
{
|
||||
for (uint i=0 ; i < acl_users.elements ; i++)
|
||||
ACL_USER *user_i = dynamic_element(&acl_users,i,ACL_USER*);
|
||||
if (!user_i->user || !strcmp(thd->user, user_i->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(&user_i->host, thd->host, thd->ip))
|
||||
{
|
||||
if (compare_hostname(&acl_user_search->host,host,ip))
|
||||
/* check password: it should be empty or valid */
|
||||
if (passwd_len == user_i->salt_len)
|
||||
{
|
||||
/* Found mathing user */
|
||||
acl_user= acl_user_search;
|
||||
/* Store it as a cache */
|
||||
*cached_user= acl_user;
|
||||
*cur_priv_version= priv_version;
|
||||
break;
|
||||
if (user_i->salt_len == 0 ||
|
||||
user_i->salt_len == SCRAMBLE_LENGTH &&
|
||||
check_scramble(passwd, thd->scramble, user_i->salt) == 0 ||
|
||||
check_scramble_323(passwd, thd->scramble,
|
||||
(ulong *) user_i->salt) == 0)
|
||||
{
|
||||
acl_user= user_i;
|
||||
res= 0;
|
||||
}
|
||||
}
|
||||
else if (passwd_len == SCRAMBLE_LENGTH &&
|
||||
user_i->salt_len == SCRAMBLE_LENGTH_323)
|
||||
res= -1;
|
||||
else if (passwd_len == SCRAMBLE_LENGTH_323 &&
|
||||
user_i->salt_len == SCRAMBLE_LENGTH)
|
||||
res= 2;
|
||||
/* linear search complete: */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Now we have acl_user found and may start our checks */
|
||||
/*
|
||||
This was moved to separate tree because of heavy HAVE_OPENSSL case.
|
||||
If acl_user is not null, res is 0.
|
||||
*/
|
||||
|
||||
if (acl_user)
|
||||
{
|
||||
/* Password should present for both or absend for both */
|
||||
if (!acl_user->password && !*password)
|
||||
password_correct=1;
|
||||
else if (!acl_user->password || !*password)
|
||||
{
|
||||
*cached_user= 0; // Impossible to connect
|
||||
}
|
||||
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 if (!stage) /* Here if password incorrect */
|
||||
{
|
||||
/* At the first stage - prepare scramble */
|
||||
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 */
|
||||
|
||||
{
|
||||
/* OK. User found and password checked continue validation */
|
||||
thd->master_access= NO_ACCESS;
|
||||
Vio *vio=thd->net.vio;
|
||||
/*
|
||||
At this point we know that user is allowed to connect
|
||||
|
@ -608,32 +641,32 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
|
|||
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;
|
||||
thd->master_access= acl_user->access;
|
||||
break;
|
||||
#ifdef HAVE_OPENSSL
|
||||
case SSL_TYPE_ANY: /* Any kind of SSL is good enough */
|
||||
if (vio_type(vio) == VIO_TYPE_SSL)
|
||||
user_access=acl_user->access;
|
||||
thd->master_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.
|
||||
|
||||
We need to check for absence of SSL because without SSL
|
||||
we should reject connection.
|
||||
Connections with non-valid certificates are dropped already
|
||||
in sslaccept() anyway, so we do not check validity here.
|
||||
|
||||
We need to check for absence of SSL because without SSL
|
||||
we should reject connection.
|
||||
*/
|
||||
if (vio_type(vio) == VIO_TYPE_SSL &&
|
||||
SSL_get_verify_result(vio->ssl_) == X509_V_OK &&
|
||||
SSL_get_peer_certificate(vio->ssl_))
|
||||
user_access=acl_user->access;
|
||||
thd->master_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.
|
||||
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 (vio_type(vio) != VIO_TYPE_SSL ||
|
||||
SSL_get_verify_result(vio->ssl_) != X509_V_OK)
|
||||
|
@ -643,14 +676,13 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
|
|||
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;
|
||||
thd->master_access= acl_user->access;
|
||||
else
|
||||
{
|
||||
if (global_system_variables.log_warnings)
|
||||
sql_print_error("X509 ciphers mismatch: should be '%s' but is '%s'",
|
||||
acl_user->ssl_cipher,
|
||||
SSL_get_cipher(vio->ssl_));
|
||||
user_access=NO_ACCESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -661,64 +693,58 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
|
|||
/* If X509 issuer is speified, we check it... */
|
||||
if (acl_user->x509_issuer)
|
||||
{
|
||||
DBUG_PRINT("info",("checkpoint 3"));
|
||||
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))
|
||||
{
|
||||
if (global_system_variables.log_warnings)
|
||||
sql_print_error("X509 issuer mismatch: should be '%s' but is '%s'",
|
||||
acl_user->x509_issuer, ptr);
|
||||
user_access=NO_ACCESS;
|
||||
free(ptr);
|
||||
break;
|
||||
}
|
||||
user_access=acl_user->access;
|
||||
free(ptr);
|
||||
if (strcmp(acl_user->x509_issuer, ptr))
|
||||
{
|
||||
if (global_system_variables.log_warnings)
|
||||
sql_print_error("X509 issuer mismatch: should be '%s' "
|
||||
"but is '%s'", acl_user->x509_issuer, ptr);
|
||||
free(ptr);
|
||||
break;
|
||||
}
|
||||
thd->master_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))
|
||||
{
|
||||
if (global_system_variables.log_warnings)
|
||||
sql_print_error("X509 subject mismatch: '%s' vs '%s'",
|
||||
acl_user->x509_subject, ptr);
|
||||
user_access=NO_ACCESS;
|
||||
}
|
||||
else
|
||||
user_access=acl_user->access;
|
||||
free(ptr);
|
||||
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))
|
||||
{
|
||||
if (global_system_variables.log_warnings)
|
||||
sql_print_error("X509 subject mismatch: '%s' vs '%s'",
|
||||
acl_user->x509_subject, ptr);
|
||||
}
|
||||
else
|
||||
thd->master_access= acl_user->access;
|
||||
free(ptr);
|
||||
}
|
||||
break;
|
||||
#else /* HAVE_OPENSSL */
|
||||
#else /* HAVE_OPENSSL */
|
||||
default:
|
||||
/*
|
||||
If we don't have SSL but SSL is required for this user the
|
||||
authentication should fail.
|
||||
*/
|
||||
If we don't have SSL but SSL is required for this user the
|
||||
authentication should fail.
|
||||
*/
|
||||
break;
|
||||
#endif /* HAVE_OPENSSL */
|
||||
}
|
||||
thd->priv_user= acl_user->user ? thd->user : (char *) "";
|
||||
*mqh= acl_user->user_resource;
|
||||
|
||||
if (acl_user->host.hostname)
|
||||
strmake(thd->priv_host, acl_user->host.hostname, MAX_HOSTNAME);
|
||||
else
|
||||
*thd->priv_host= 0;
|
||||
}
|
||||
|
||||
*mqh=acl_user->user_resource;
|
||||
if (!acl_user->user)
|
||||
*priv_user=(char*) ""; // Change to anonymous user /* purecov: inspected */
|
||||
|
||||
if (acl_user->host.hostname)
|
||||
strmake(priv_host, acl_user->host.hostname, MAX_HOSTNAME);
|
||||
else
|
||||
*priv_host= 0;
|
||||
|
||||
unlock_and_exit:
|
||||
VOID(pthread_mutex_unlock(&acl_cache->lock));
|
||||
DBUG_RETURN(user_access);
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
|
||||
|
||||
|
@ -729,8 +755,9 @@ static byte* check_get_key(ACL_USER *buff,uint *length,
|
|||
return (byte*) buff->host.hostname;
|
||||
}
|
||||
|
||||
|
||||
static void acl_update_user(const char *user, const char *host,
|
||||
const char *password,
|
||||
const char *password, uint password_len,
|
||||
enum SSL_type ssl_type,
|
||||
const char *ssl_cipher,
|
||||
const char *x509_issuer,
|
||||
|
@ -766,20 +793,9 @@ static void acl_update_user(const char *user, const char *host,
|
|||
acl_user->x509_subject= (x509_subject ?
|
||||
strdup_root(&mem,x509_subject) : 0);
|
||||
}
|
||||
if (password)
|
||||
{
|
||||
if (!password[0]) /* If password is empty set it to null */
|
||||
{
|
||||
acl_user->password=0;
|
||||
acl_user->pversion=0; // just initialize
|
||||
}
|
||||
else
|
||||
{
|
||||
acl_user->password=(char*) ""; // Just point at something
|
||||
get_salt_from_password(acl_user->salt,password);
|
||||
acl_user->pversion=get_password_version(acl_user->password);
|
||||
}
|
||||
}
|
||||
|
||||
set_user_salt(acl_user, password, password_len);
|
||||
/* search complete: */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -788,7 +804,7 @@ static void acl_update_user(const char *user, const char *host,
|
|||
|
||||
|
||||
static void acl_insert_user(const char *user, const char *host,
|
||||
const char *password,
|
||||
const char *password, uint password_len,
|
||||
enum SSL_type ssl_type,
|
||||
const char *ssl_cipher,
|
||||
const char *x509_issuer,
|
||||
|
@ -799,7 +815,6 @@ static void acl_insert_user(const char *user, const char *host,
|
|||
ACL_USER acl_user;
|
||||
acl_user.user=*user ? strdup_root(&mem,user) : 0;
|
||||
update_hostname(&acl_user.host,strdup_root(&mem,host));
|
||||
acl_user.password=0;
|
||||
acl_user.access=privileges;
|
||||
acl_user.user_resource = *mqh;
|
||||
acl_user.sort=get_sort(2,acl_user.host.hostname,acl_user.user);
|
||||
|
@ -809,12 +824,8 @@ static void acl_insert_user(const char *user, const char *host,
|
|||
acl_user.ssl_cipher= ssl_cipher ? strdup_root(&mem,ssl_cipher) : 0;
|
||||
acl_user.x509_issuer= x509_issuer ? strdup_root(&mem,x509_issuer) : 0;
|
||||
acl_user.x509_subject=x509_subject ? strdup_root(&mem,x509_subject) : 0;
|
||||
if (password)
|
||||
{
|
||||
acl_user.password=(char*) ""; // Just point at something
|
||||
get_salt_from_password(acl_user.salt,password);
|
||||
acl_user.pversion=get_password_version(password);
|
||||
}
|
||||
|
||||
set_user_salt(&acl_user, password, password_len);
|
||||
|
||||
VOID(push_dynamic(&acl_users,(gptr) &acl_user));
|
||||
if (!acl_user.host.hostname || acl_user.host.hostname[0] == wild_many
|
||||
|
@ -1151,7 +1162,6 @@ bool check_change_password(THD *thd, const char *host, const char *user)
|
|||
bool change_password(THD *thd, const char *host, const char *user,
|
||||
char *new_password)
|
||||
{
|
||||
uint length=0;
|
||||
DBUG_ENTER("change_password");
|
||||
DBUG_PRINT("enter",("host: '%s' user: '%s' new_password: '%s'",
|
||||
host,user,new_password));
|
||||
|
@ -1160,37 +1170,27 @@ bool change_password(THD *thd, const char *host, const char *user,
|
|||
if (check_change_password(thd, host, user))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
/*
|
||||
password should always be 0,16 or 45 chars;
|
||||
Simple hack to avoid cracking
|
||||
*/
|
||||
length=(uint) strlen(new_password);
|
||||
if (length != 45)
|
||||
new_password[length & 16]=0;
|
||||
|
||||
VOID(pthread_mutex_lock(&acl_cache->lock));
|
||||
ACL_USER *acl_user;
|
||||
if (!(acl_user= find_acl_user(host,user)))
|
||||
if (!(acl_user= find_acl_user(host, user)))
|
||||
{
|
||||
send_error(thd, ER_PASSWORD_NO_MATCH);
|
||||
VOID(pthread_mutex_unlock(&acl_cache->lock));
|
||||
send_error(thd, ER_PASSWORD_NO_MATCH);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
/* update loaded acl entry: */
|
||||
uint new_password_len= new_password ? strlen(new_password) : 0;
|
||||
set_user_salt(acl_user, new_password, new_password_len);
|
||||
|
||||
if (update_user_table(thd,
|
||||
acl_user->host.hostname ? acl_user->host.hostname : "",
|
||||
acl_user->user ? acl_user->user : "",
|
||||
new_password))
|
||||
new_password, new_password_len))
|
||||
{
|
||||
VOID(pthread_mutex_unlock(&acl_cache->lock)); /* purecov: deadcode */
|
||||
send_error(thd,0); /* purecov: deadcode */
|
||||
DBUG_RETURN(1); /* purecov: deadcode */
|
||||
}
|
||||
get_salt_from_password(acl_user->salt,new_password);
|
||||
acl_user->pversion=get_password_version(new_password);
|
||||
if (!new_password[0])
|
||||
acl_user->password=0;
|
||||
else
|
||||
acl_user->password=(char*) ""; // Point at something
|
||||
|
||||
acl_cache->clear(1); // Clear locked hostname cache
|
||||
VOID(pthread_mutex_unlock(&acl_cache->lock));
|
||||
|
@ -1230,7 +1230,7 @@ find_acl_user(const char *host, const char *user)
|
|||
if (!acl_user->user && !user[0] ||
|
||||
acl_user->user && !strcmp(user,acl_user->user))
|
||||
{
|
||||
if (compare_hostname(&(acl_user->host),host,host))
|
||||
if (compare_hostname(&acl_user->host,host,host))
|
||||
{
|
||||
DBUG_RETURN(acl_user);
|
||||
}
|
||||
|
@ -1303,7 +1303,7 @@ static bool compare_hostname(const acl_host_and_ip *host, const char *hostname,
|
|||
*/
|
||||
|
||||
static bool update_user_table(THD *thd, const char *host, const char *user,
|
||||
const char *new_password)
|
||||
const char *new_password, uint new_password_len)
|
||||
{
|
||||
TABLE_LIST tables;
|
||||
TABLE *table;
|
||||
|
@ -1345,7 +1345,7 @@ static bool update_user_table(THD *thd, const char *host, const char *user,
|
|||
DBUG_RETURN(1); /* purecov: deadcode */
|
||||
}
|
||||
store_record(table,record[1]);
|
||||
table->field[2]->store(new_password,(uint) strlen(new_password), &my_charset_latin1);
|
||||
table->field[2]->store(new_password, new_password_len, &my_charset_latin1);
|
||||
if ((error=table->file->update_row(table->record[1],table->record[0])))
|
||||
{
|
||||
table->file->print_error(error,MYF(0)); /* purecov: deadcode */
|
||||
|
@ -1393,24 +1393,23 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
|
|||
{
|
||||
int error = -1;
|
||||
bool old_row_exists=0;
|
||||
char *password,empty_string[1];
|
||||
const char *password= "";
|
||||
uint password_len= 0;
|
||||
char what= (revoke_grant) ? 'N' : 'Y';
|
||||
DBUG_ENTER("replace_user_table");
|
||||
safe_mutex_assert_owner(&acl_cache->lock);
|
||||
|
||||
password=empty_string;
|
||||
empty_string[0]=0;
|
||||
|
||||
if (combo.password.str && combo.password.str[0])
|
||||
{
|
||||
if ((combo.password.length != HASH_PASSWORD_LENGTH)
|
||||
&& combo.password.length != HASH_OLD_PASSWORD_LENGTH)
|
||||
if (combo.password.length != SCRAMBLED_PASSWORD_CHAR_LENGTH &&
|
||||
combo.password.length != SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
|
||||
{
|
||||
my_printf_error(ER_PASSWORD_NO_MATCH,
|
||||
"Password hash should be a %d-digit hexadecimal number",
|
||||
MYF(0),HASH_PASSWORD_LENGTH);
|
||||
"Password hash should be a %d-digit hexadecimal number",
|
||||
MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH);
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
password_len= combo.password.length;
|
||||
password=combo.password.str;
|
||||
}
|
||||
|
||||
|
@ -1435,17 +1434,20 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
|
|||
goto end;
|
||||
}
|
||||
old_row_exists = 0;
|
||||
restore_record(table,default_values); // cp empty row from default_values
|
||||
table->field[0]->store(combo.host.str,combo.host.length, &my_charset_latin1);
|
||||
table->field[1]->store(combo.user.str,combo.user.length, &my_charset_latin1);
|
||||
table->field[2]->store(password,(uint) strlen(password), &my_charset_latin1);
|
||||
restore_record(table,default_values); // cp empty row from default_values
|
||||
table->field[0]->store(combo.host.str,combo.host.length,
|
||||
&my_charset_latin1);
|
||||
table->field[1]->store(combo.user.str,combo.user.length,
|
||||
&my_charset_latin1);
|
||||
table->field[2]->store(password, password_len,
|
||||
&my_charset_latin1);
|
||||
}
|
||||
else
|
||||
{
|
||||
old_row_exists = 1;
|
||||
store_record(table,record[1]); // Save copy for update
|
||||
if (combo.password.str) // If password given
|
||||
table->field[2]->store(password,(uint) strlen(password), &my_charset_latin1);
|
||||
table->field[2]->store(password, password_len, &my_charset_latin1);
|
||||
}
|
||||
|
||||
/* Update table columns with new privileges */
|
||||
|
@ -1542,10 +1544,8 @@ end:
|
|||
if (!error)
|
||||
{
|
||||
acl_cache->clear(1); // Clear privilege cache
|
||||
if (!combo.password.str)
|
||||
password=0; // No password given on command
|
||||
if (old_row_exists)
|
||||
acl_update_user(combo.user.str,combo.host.str,password,
|
||||
acl_update_user(combo.user.str, combo.host.str, password, password_len,
|
||||
thd->lex.ssl_type,
|
||||
thd->lex.ssl_cipher,
|
||||
thd->lex.x509_issuer,
|
||||
|
@ -1553,7 +1553,7 @@ end:
|
|||
&thd->lex.mqh,
|
||||
rights);
|
||||
else
|
||||
acl_insert_user(combo.user.str,combo.host.str,password,
|
||||
acl_insert_user(combo.user.str, combo.host.str, password, password_len,
|
||||
thd->lex.ssl_type,
|
||||
thd->lex.ssl_cipher,
|
||||
thd->lex.x509_issuer,
|
||||
|
@ -3024,12 +3024,15 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
|
|||
global.append ("'@'",3);
|
||||
global.append(lex_user->host.str,lex_user->host.length);
|
||||
global.append ('\'');
|
||||
if (acl_user->password)
|
||||
if (acl_user->salt_len)
|
||||
{
|
||||
char passd_buff[HASH_PASSWORD_LENGTH+1];
|
||||
make_password_from_salt(passd_buff,acl_user->salt,acl_user->pversion);
|
||||
char passwd_buff[SCRAMBLED_PASSWORD_CHAR_LENGTH+1];
|
||||
if (acl_user->salt_len == SCRAMBLE_LENGTH)
|
||||
make_password_from_salt(passwd_buff, acl_user->salt);
|
||||
else
|
||||
make_password_from_salt_323(passwd_buff, (ulong *) acl_user->salt);
|
||||
global.append(" IDENTIFIED BY PASSWORD '",25);
|
||||
global.append(passd_buff);
|
||||
global.append(passwd_buff);
|
||||
global.append('\'');
|
||||
}
|
||||
/* "show grants" SSL related stuff */
|
||||
|
|
|
@ -111,9 +111,9 @@ 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
|
||||
char *user;
|
||||
uint8 salt[SCRAMBLE_LENGTH+1]; // scrambled password in binary form
|
||||
uint8 salt_len; // 0 - no password, 4 - 3.20, 8 - 3.23, 20 - 4.1.1
|
||||
enum SSL_type ssl_type;
|
||||
const char *ssl_cipher, *x509_issuer, *x509_subject;
|
||||
};
|
||||
|
@ -135,11 +135,8 @@ void acl_reload(THD *thd);
|
|||
void acl_free(bool end=0);
|
||||
ulong acl_get(const char *host, const char *ip, const char *bin_ip,
|
||||
const char *user, const char *db, my_bool db_is_pattern);
|
||||
ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
|
||||
const char *password,const char *scramble,
|
||||
char **priv_user, char *priv_host,
|
||||
bool old_ver, USER_RESOURCES *max,char* prepared_scramble,
|
||||
uint *cur_priv_version, ACL_USER **cached_user);
|
||||
int acl_getroot(THD *thd, USER_RESOURCES *mqh, const char *passwd,
|
||||
uint passwd_len);
|
||||
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,
|
||||
|
|
|
@ -138,6 +138,7 @@ THD::THD():user_time(0), is_fatal_error(0),
|
|||
set_query_id=1;
|
||||
db_access=NO_ACCESS;
|
||||
version=refresh_version; // For boot
|
||||
*scramble= '\0';
|
||||
|
||||
init();
|
||||
/* Initialize sub structures */
|
||||
|
|
|
@ -399,6 +399,7 @@ struct system_variables
|
|||
my_bool log_warnings;
|
||||
my_bool low_priority_updates;
|
||||
my_bool new_mode;
|
||||
my_bool old_passwords;
|
||||
|
||||
CHARSET_INFO *character_set_server;
|
||||
CHARSET_INFO *character_set_database;
|
||||
|
@ -556,10 +557,10 @@ public:
|
|||
enum_tx_isolation session_tx_isolation;
|
||||
/* for user variables replication*/
|
||||
DYNAMIC_ARRAY user_var_events;
|
||||
// extend scramble to handle new auth
|
||||
char scramble[SCRAMBLE41_LENGTH+1];
|
||||
// old scramble is needed to handle old clients
|
||||
char old_scramble[SCRAMBLE_LENGTH+1];
|
||||
|
||||
/* scramble - random string sent to client on handshake */
|
||||
char scramble[SCRAMBLE_LENGTH+1];
|
||||
|
||||
uint8 query_cache_type; // type of query cache processing
|
||||
bool slave_thread;
|
||||
bool set_query_id,locked,count_cuted_fields,some_tables_deleted;
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
SQL_CRYPT::SQL_CRYPT(const char *password)
|
||||
{
|
||||
ulong rand_nr[2];
|
||||
hash_password(rand_nr,password);
|
||||
hash_password(rand_nr,password, strlen(password));
|
||||
crypt_init(rand_nr);
|
||||
}
|
||||
|
||||
|
|
614
sql/sql_parse.cc
614
sql/sql_parse.cc
|
@ -178,153 +178,179 @@ end:
|
|||
|
||||
|
||||
/*
|
||||
Check if user is ok
|
||||
|
||||
Check if user exist and password supplied is correct.
|
||||
SYNOPSIS
|
||||
check_user()
|
||||
thd Thread handle
|
||||
command Command for connection (for log)
|
||||
user Name of user trying to connect
|
||||
passwd Scrambled password sent from client
|
||||
db Database to connect to
|
||||
check_count If set to 1, don't allow too many connection
|
||||
simple_connect If 1 then client is of old type and we should connect
|
||||
using the old method (no challange)
|
||||
do_send_error Set to 1 if we should send error to user
|
||||
prepared_scramble Buffer to store hash password of new connection
|
||||
had_password Set to 1 if the user gave a password
|
||||
cur_priv_version Check flag to know if someone flushed the privileges
|
||||
since last code
|
||||
hint_user Pointer used by acl_getroot() to remmeber user for
|
||||
next call
|
||||
thd thread handle, thd->{host,user,ip} are used
|
||||
command originator of the check: now check_user is called
|
||||
during connect and change user procedures; used for
|
||||
logging.
|
||||
passwd scrambled password recieved from client
|
||||
passwd_len length of scrambled password
|
||||
db database name to connect to, may be NULL
|
||||
check_count dont know exactly
|
||||
|
||||
RETURN
|
||||
0 ok
|
||||
thd->user, thd->master_access, thd->priv_user, thd->db and
|
||||
thd->db_access are updated
|
||||
1 Access denied; Error sent to client
|
||||
-1 If do_send_error == 1: Failed connect, error sent to client
|
||||
If do_send_error == 0: Prepare for stage of connect
|
||||
Note, that host, user and passwd may point to communication buffer.
|
||||
Current implementation does not depened on that, but future changes
|
||||
should be done with this in mind; 'thd' is INOUT, all other params
|
||||
are 'IN'.
|
||||
|
||||
RETURN VALUE
|
||||
0 OK; thd->user, thd->master_access, thd->priv_user, thd->db and
|
||||
thd->db_access are updated; OK is sent to client;
|
||||
-1 access denied or handshake error; error is sent to client;
|
||||
>0 error, not sent to client
|
||||
*/
|
||||
|
||||
static int check_user(THD *thd,enum_server_command command, const char *user,
|
||||
const char *passwd, const char *db, bool check_count,
|
||||
bool simple_connect, bool do_send_error,
|
||||
char *prepared_scramble, bool had_password,
|
||||
uint *cur_priv_version, ACL_USER** hint_user)
|
||||
static int check_user(THD *thd, enum enum_server_command command,
|
||||
const char *passwd, uint passwd_len, const char *db,
|
||||
bool check_count)
|
||||
{
|
||||
thd->db=0;
|
||||
thd->db_length=0;
|
||||
USER_RESOURCES ur;
|
||||
char tmp_passwd[SCRAMBLE41_LENGTH+1];
|
||||
DBUG_ENTER("check_user");
|
||||
|
||||
my_bool opt_secure_auth_local;
|
||||
pthread_mutex_lock(&LOCK_global_system_variables);
|
||||
opt_secure_auth_local= opt_secure_auth;
|
||||
pthread_mutex_unlock(&LOCK_global_system_variables);
|
||||
|
||||
/*
|
||||
Move password to temporary buffer as it may be stored in communication
|
||||
buffer
|
||||
If the server is running in secure auth mode, short scrambles are
|
||||
forbidden.
|
||||
*/
|
||||
strmake(tmp_passwd, passwd, sizeof(tmp_passwd));
|
||||
passwd= tmp_passwd; // Use local copy
|
||||
|
||||
/* We shall avoid dupplicate user allocations here */
|
||||
if (!thd->user && !(thd->user = my_strdup(user, MYF(0))))
|
||||
if (opt_secure_auth_local && passwd_len == SCRAMBLE_LENGTH_323)
|
||||
{
|
||||
send_error(thd,ER_OUT_OF_RESOURCES);
|
||||
DBUG_RETURN(1);
|
||||
net_printf(thd, ER_NOT_SUPPORTED_AUTH_MODE);
|
||||
mysql_log.write(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
thd->master_access=acl_getroot(thd, thd->host, thd->ip, thd->user,
|
||||
passwd, thd->scramble,
|
||||
&thd->priv_user, thd->priv_host,
|
||||
(protocol_version == 9 ||
|
||||
!(thd->client_capabilities &
|
||||
CLIENT_LONG_PASSWORD)),
|
||||
&ur,prepared_scramble,
|
||||
cur_priv_version,hint_user);
|
||||
|
||||
DBUG_PRINT("info",
|
||||
("Capabilities: %d packet_length: %ld Host: '%s' Login user: '%s' Priv_user: '%s' Using password: %s Access: %u db: '%s'",
|
||||
thd->client_capabilities, thd->max_client_packet_length,
|
||||
thd->host_or_ip, thd->user, thd->priv_user,
|
||||
had_password ? "yes": "no",
|
||||
thd->master_access, thd->db ? thd->db : "*none*"));
|
||||
if (passwd_len != 0 &&
|
||||
passwd_len != SCRAMBLE_LENGTH &&
|
||||
passwd_len != SCRAMBLE_LENGTH_323)
|
||||
DBUG_RETURN(ER_HANDSHAKE_ERROR);
|
||||
|
||||
/*
|
||||
In case we're going to retry we should not send error message at this
|
||||
point
|
||||
Clear thd->db as it points to something, that will be freed when
|
||||
connection is closed. We don't want to accidently free a wrong pointer
|
||||
if connect failed. Also in case of 'CHANGE USER' failure, current
|
||||
database will be switched to 'no database selected'.
|
||||
*/
|
||||
if (thd->master_access & NO_ACCESS)
|
||||
thd->db= 0;
|
||||
thd->db_length= 0;
|
||||
|
||||
USER_RESOURCES ur;
|
||||
int res= acl_getroot(thd, &ur, passwd, passwd_len);
|
||||
if (res == -1)
|
||||
{
|
||||
if (do_send_error || !had_password || !*hint_user)
|
||||
/*
|
||||
This happens when client (new) sends password scrambled with
|
||||
scramble(), but database holds old value (scrambled with
|
||||
scramble_323()). Here we please client to send scrambled_password
|
||||
in old format.
|
||||
*/
|
||||
NET *net= &thd->net;
|
||||
if (opt_secure_auth_local)
|
||||
{
|
||||
DBUG_PRINT("info",("Access denied"));
|
||||
/*
|
||||
Old client should get nicer error message if password version is
|
||||
not supported
|
||||
*/
|
||||
if (simple_connect && *hint_user && (*hint_user)->pversion)
|
||||
net_printf(thd, ER_SERVER_IS_IN_SECURE_AUTH_MODE,
|
||||
thd->user, thd->host_or_ip);
|
||||
mysql_log.write(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE),
|
||||
thd->user, thd->host_or_ip);
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
if (send_old_password_request(thd) ||
|
||||
my_net_read(net) != SCRAMBLE_LENGTH_323 + 1) // We have to read very
|
||||
{ // specific packet size
|
||||
inc_host_errors(&thd->remote.sin_addr);
|
||||
DBUG_RETURN(ER_HANDSHAKE_ERROR);
|
||||
}
|
||||
/* Final attempt to check the user based on reply */
|
||||
/* So as passwd is short, errcode is always >= 0 */
|
||||
res= acl_getroot(thd, &ur, (char *) net->read_pos, SCRAMBLE_LENGTH_323);
|
||||
}
|
||||
/* here res is always >= 0 */
|
||||
if (res == 0)
|
||||
{
|
||||
if (!(thd->master_access & NO_ACCESS)) // authentification is OK
|
||||
{
|
||||
DBUG_PRINT("info",
|
||||
("Capabilities: %d packet_length: %ld Host: '%s' "
|
||||
"Login user: '%s' Priv_user: '%s' Using password: %s "
|
||||
"Access: %u db: '%s'",
|
||||
thd->client_capabilities, thd->max_client_packet_length,
|
||||
thd->host_or_ip, thd->user, thd->priv_user,
|
||||
passwd_len ? "yes": "no",
|
||||
thd->master_access, thd->db ? thd->db : "*none*"));
|
||||
|
||||
if (check_count)
|
||||
{
|
||||
net_printf(thd, ER_NOT_SUPPORTED_AUTH_MODE);
|
||||
mysql_log.write(thd,COM_CONNECT,ER(ER_NOT_SUPPORTED_AUTH_MODE));
|
||||
VOID(pthread_mutex_lock(&LOCK_thread_count));
|
||||
bool count_ok= thread_count < max_connections + delayed_insert_threads
|
||||
|| (thd->master_access & SUPER_ACL);
|
||||
VOID(pthread_mutex_unlock(&LOCK_thread_count));
|
||||
if (!count_ok)
|
||||
{ // too many connections
|
||||
send_error(thd, ER_CON_COUNT_ERROR);
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Why logging is performed before all checks've passed? */
|
||||
mysql_log.write(thd,command,
|
||||
(thd->priv_user == thd->user ?
|
||||
(char*) "%s@%s on %s" :
|
||||
(char*) "%s@%s as anonymous on %s"),
|
||||
thd->user, thd->host_or_ip,
|
||||
db ? db : (char*) "");
|
||||
|
||||
/*
|
||||
This is the default access rights for the current database. It's
|
||||
set to 0 here because we don't have an active database yet (and we
|
||||
may not have an active database to set.
|
||||
*/
|
||||
thd->db_access=0;
|
||||
|
||||
/* Don't allow user to connect if he has done too many queries */
|
||||
if ((ur.questions || ur.updates ||
|
||||
ur.connections || max_user_connections) &&
|
||||
get_or_create_user_conn(thd,thd->user,thd->host_or_ip,&ur))
|
||||
DBUG_RETURN(1);
|
||||
if (thd->user_connect && thd->user_connect->user_resources.connections &&
|
||||
check_for_max_user_connections(thd, thd->user_connect))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
/* Change database if necessary: OK or FAIL is sent in mysql_change_db */
|
||||
if (db && db[0])
|
||||
{
|
||||
if (mysql_change_db(thd, db))
|
||||
{
|
||||
if (thd->user_connect)
|
||||
decrease_user_connections(thd->user_connect);
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
net_printf(thd, ER_ACCESS_DENIED_ERROR,
|
||||
thd->user,
|
||||
thd->host_or_ip,
|
||||
had_password ? ER(ER_YES) : ER(ER_NO));
|
||||
mysql_log.write(thd,COM_CONNECT,ER(ER_ACCESS_DENIED_ERROR),
|
||||
thd->user,
|
||||
thd->host_or_ip,
|
||||
had_password ? ER(ER_YES) : ER(ER_NO));
|
||||
}
|
||||
DBUG_RETURN(1); // Error already given
|
||||
}
|
||||
DBUG_PRINT("info",("Prepare for second part of handshake"));
|
||||
DBUG_RETURN(-1); // no report error in special handshake
|
||||
}
|
||||
|
||||
if (check_count)
|
||||
{
|
||||
VOID(pthread_mutex_lock(&LOCK_thread_count));
|
||||
bool tmp=(thread_count - delayed_insert_threads >= max_connections &&
|
||||
!(thd->master_access & SUPER_ACL));
|
||||
VOID(pthread_mutex_unlock(&LOCK_thread_count));
|
||||
if (tmp)
|
||||
{ // Too many connections
|
||||
send_error(thd, ER_CON_COUNT_ERROR);
|
||||
DBUG_RETURN(1);
|
||||
send_ok(thd);
|
||||
thd->password= test(passwd_len); // remember for error messages
|
||||
/* Ready to handle queries */
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
}
|
||||
mysql_log.write(thd,command,
|
||||
(thd->priv_user == thd->user ?
|
||||
(char*) "%s@%s on %s" :
|
||||
(char*) "%s@%s as anonymous on %s"),
|
||||
user,
|
||||
thd->host_or_ip,
|
||||
db ? db : (char*) "");
|
||||
thd->db_access=0;
|
||||
/* Don't allow user to connect if he has done too many queries */
|
||||
if ((ur.questions || ur.updates || ur.connections || max_user_connections) &&
|
||||
get_or_create_user_conn(thd,user,thd->host_or_ip,&ur))
|
||||
DBUG_RETURN(1);
|
||||
if (thd->user_connect && ((thd->user_connect->user_resources.connections) ||
|
||||
max_user_connections) &&
|
||||
check_for_max_user_connections(thd, thd->user_connect))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
if (db && db[0])
|
||||
else if (res == 2) // client gave short hash, server has long hash
|
||||
{
|
||||
int error= test(mysql_change_db(thd,db));
|
||||
if (error && thd->user_connect)
|
||||
decrease_user_connections(thd->user_connect);
|
||||
DBUG_RETURN(error);
|
||||
net_printf(thd, ER_NOT_SUPPORTED_AUTH_MODE);
|
||||
mysql_log.write(thd,COM_CONNECT,ER(ER_NOT_SUPPORTED_AUTH_MODE));
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
send_ok(thd); // Ready to handle questions
|
||||
thd->password= test(passwd[0]); // Remember for error messages
|
||||
DBUG_RETURN(0); // ok
|
||||
net_printf(thd, ER_ACCESS_DENIED_ERROR,
|
||||
thd->user,
|
||||
thd->host_or_ip,
|
||||
passwd_len ? ER(ER_YES) : ER(ER_NO));
|
||||
mysql_log.write(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR),
|
||||
thd->user,
|
||||
thd->host_or_ip,
|
||||
passwd_len ? ER(ER_YES) : ER(ER_NO));
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Check for maximum allowable user connections, if the mysqld server is
|
||||
started with corresponding variable that is greater then 0.
|
||||
|
@ -526,45 +552,36 @@ static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them= 0)
|
|||
|
||||
|
||||
/*
|
||||
Check connnectionn and get priviliges
|
||||
|
||||
Perform handshake, authorize client and update thd ACL variables.
|
||||
SYNOPSIS
|
||||
check_connections
|
||||
thd Thread handle
|
||||
check_connection()
|
||||
thd thread handle
|
||||
|
||||
RETURN
|
||||
0 ok
|
||||
-1 Error, which is sent to user
|
||||
> 0 Error code (not sent to user)
|
||||
0 success, OK is sent to user, thd is updated.
|
||||
-1 error, which is sent to user
|
||||
> 0 error code (not sent to user)
|
||||
*/
|
||||
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
static int
|
||||
check_connections(THD *thd)
|
||||
check_connection(THD *thd)
|
||||
{
|
||||
int res;
|
||||
uint connect_errors=0;
|
||||
uint cur_priv_version;
|
||||
bool using_password;
|
||||
uint connect_errors= 0;
|
||||
NET *net= &thd->net;
|
||||
char *end, *user, *passwd, *db;
|
||||
char prepared_scramble[SCRAMBLE41_LENGTH+4]; /* Buffer for scramble&hash */
|
||||
char db_buff[NAME_LEN+1];
|
||||
ACL_USER* cached_user=NULL; /* Initialise to NULL for first stage */
|
||||
DBUG_PRINT("info",("New connection received on %s",
|
||||
vio_description(net->vio)));
|
||||
|
||||
/* Remove warning from valgrind. TODO: Fix it in password.c */
|
||||
bzero((char*) &prepared_scramble[0], sizeof(prepared_scramble));
|
||||
DBUG_PRINT("info",
|
||||
("New connection received on %s", vio_description(net->vio)));
|
||||
|
||||
if (!thd->host) // If TCP/IP connection
|
||||
{
|
||||
char ip[30];
|
||||
|
||||
if (vio_peer_addr(net->vio, ip, &thd->peer_port))
|
||||
return (ER_BAD_HOST_ERROR);
|
||||
if (!(thd->ip = my_strdup(ip,MYF(0))))
|
||||
if (!(thd->ip= my_strdup(ip,MYF(0))))
|
||||
return (ER_OUT_OF_RESOURCES);
|
||||
thd->host_or_ip=thd->ip;
|
||||
thd->host_or_ip= thd->ip;
|
||||
#if !defined(HAVE_SYS_UN_H) || defined(HAVE_mit_thread)
|
||||
/* Fast local hostname resolve for Win32 */
|
||||
if (!strcmp(thd->ip,"127.0.0.1"))
|
||||
|
@ -600,15 +617,16 @@ check_connections(THD *thd)
|
|||
DBUG_PRINT("info",("Host: %s",thd->host));
|
||||
thd->host_or_ip= thd->host;
|
||||
thd->ip= 0;
|
||||
bzero((char*) &thd->remote,sizeof(struct sockaddr));
|
||||
bzero((char*) &thd->remote, sizeof(struct sockaddr));
|
||||
}
|
||||
/* Ensure that wrong hostnames doesn't cause buffer overflows */
|
||||
vio_keepalive(net->vio, TRUE);
|
||||
|
||||
ulong pkt_len=0;
|
||||
ulong pkt_len= 0;
|
||||
char *end;
|
||||
{
|
||||
/* buff[] needs to big enough to hold the server_version variable */
|
||||
char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH+64];
|
||||
char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64];
|
||||
ulong client_flags = (CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB |
|
||||
CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION);
|
||||
|
||||
|
@ -622,19 +640,34 @@ check_connections(THD *thd)
|
|||
client_flags |= CLIENT_SSL; /* Wow, SSL is avalaible! */
|
||||
#endif /* HAVE_OPENSSL */
|
||||
|
||||
end=strnmov(buff,server_version,SERVER_VERSION_LENGTH)+1;
|
||||
int4store((uchar*) end,thd->thread_id);
|
||||
end+=4;
|
||||
memcpy(end,thd->scramble,SCRAMBLE_LENGTH+1);
|
||||
end+=SCRAMBLE_LENGTH +1;
|
||||
int2store(end,client_flags);
|
||||
end= strnmov(buff, server_version, SERVER_VERSION_LENGTH) + 1;
|
||||
int4store((uchar*) end, thd->thread_id);
|
||||
end+= 4;
|
||||
/*
|
||||
So as check_connection is the only entry point to authorization
|
||||
procedure, scramble is set here. This gives us new scramble for
|
||||
each handshake.
|
||||
*/
|
||||
create_random_string(thd->scramble, SCRAMBLE_LENGTH, &thd->rand);
|
||||
/*
|
||||
Old clients does not understand long scrambles, but can ignore packet
|
||||
tail: that's why first part of the scramble is placed here, and second
|
||||
part at the end of packet.
|
||||
*/
|
||||
end= strmake(end, thd->scramble, SCRAMBLE_LENGTH_323) + 1;
|
||||
|
||||
int2store(end, client_flags);
|
||||
/* write server characteristics: up to 16 bytes allowed */
|
||||
end[2]=(char) default_charset_info->number;
|
||||
int2store(end+3,thd->server_status);
|
||||
bzero(end+5,13);
|
||||
end+=18;
|
||||
int2store(end+3, thd->server_status);
|
||||
bzero(end+5, 13);
|
||||
end+= 18;
|
||||
/* write scramble tail */
|
||||
end= strmake(end, thd->scramble + SCRAMBLE_LENGTH_323,
|
||||
SCRAMBLE_LENGTH - SCRAMBLE_LENGTH_323) + 1;
|
||||
|
||||
// At this point we write connection message and read reply
|
||||
if (net_write_command(net,(uchar) protocol_version, "", 0, buff,
|
||||
/* At this point we write connection message and read reply */
|
||||
if (net_write_command(net, (uchar) protocol_version, "", 0, buff,
|
||||
(uint) (end-buff)) ||
|
||||
(pkt_len= my_net_read(net)) == packet_error ||
|
||||
pkt_len < MIN_HANDSHAKE_SIZE)
|
||||
|
@ -723,7 +756,7 @@ check_connections(THD *thd)
|
|||
return(ER_HANDSHAKE_ERROR);
|
||||
}
|
||||
DBUG_PRINT("info", ("Reading user information over SSL layer"));
|
||||
if ((pkt_len=my_net_read(net)) == packet_error ||
|
||||
if ((pkt_len= my_net_read(net)) == packet_error ||
|
||||
pkt_len < NORMAL_HANDSHAKE_SIZE)
|
||||
{
|
||||
DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
|
||||
|
@ -740,13 +773,30 @@ check_connections(THD *thd)
|
|||
return(ER_HANDSHAKE_ERROR);
|
||||
}
|
||||
|
||||
user= end;
|
||||
passwd= strend(user)+1;
|
||||
db=0;
|
||||
using_password= test(passwd[0]);
|
||||
if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB)
|
||||
if (thd->client_capabilities & CLIENT_INTERACTIVE)
|
||||
thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
|
||||
if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
|
||||
opt_using_transactions)
|
||||
net->return_status= &thd->server_status;
|
||||
net->read_timeout=(uint) thd->variables.net_read_timeout;
|
||||
|
||||
char *user= end;
|
||||
char *passwd= strend(user)+1;
|
||||
char *db= passwd;
|
||||
char db_buff[NAME_LEN+1]; // buffer to store db in utf8
|
||||
/*
|
||||
Old clients send null-terminated string as password; new clients send
|
||||
the size (1 byte) + string (not null-terminated). Hence in case of empty
|
||||
password both send '\0'.
|
||||
*/
|
||||
uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
|
||||
*passwd++ : strlen(passwd);
|
||||
db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
|
||||
db + passwd_len + 1 : 0;
|
||||
|
||||
/* Since 4.1 all database names are stored in utf8 */
|
||||
if (db)
|
||||
{
|
||||
db= strend(passwd)+1;
|
||||
uint32 length= copy_and_convert(db_buff, sizeof(db_buff)-1,
|
||||
system_charset_info,
|
||||
db, strlen(db),
|
||||
|
@ -755,71 +805,11 @@ check_connections(THD *thd)
|
|||
db= db_buff;
|
||||
}
|
||||
|
||||
/* We can get only old hash at this point */
|
||||
if (using_password && 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) &&
|
||||
opt_using_transactions)
|
||||
net->return_status= &thd->server_status;
|
||||
net->read_timeout=(uint) thd->variables.net_read_timeout;
|
||||
|
||||
/* Simple connect only for old clients. New clients always use secure auth */
|
||||
bool simple_connect=(!(thd->client_capabilities & CLIENT_SECURE_CONNECTION));
|
||||
|
||||
/* Check user permissions. If password failure we'll get scramble back */
|
||||
if ((res=check_user(thd, COM_CONNECT, user, passwd, db, 1, simple_connect,
|
||||
simple_connect, prepared_scramble, using_password,
|
||||
&cur_priv_version,
|
||||
&cached_user)) < 0)
|
||||
{
|
||||
/* 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 the client is old we just have to return error */
|
||||
if (simple_connect)
|
||||
return -1;
|
||||
|
||||
DBUG_PRINT("info",("password challenge"));
|
||||
|
||||
tmp_user[0]= tmp_db[0]= 0;
|
||||
if (user)
|
||||
strmake(tmp_user,user,USERNAME_LENGTH);
|
||||
if (db)
|
||||
strmake(tmp_db,db,NAME_LEN);
|
||||
|
||||
/* Write hash and encrypted scramble to client */
|
||||
if (my_net_write(net,prepared_scramble,SCRAMBLE41_LENGTH+4) ||
|
||||
net_flush(net))
|
||||
{
|
||||
inc_host_errors(&thd->remote.sin_addr);
|
||||
return ER_HANDSHAKE_ERROR;
|
||||
}
|
||||
/* Reading packet back */
|
||||
if ((pkt_len= my_net_read(net)) == packet_error)
|
||||
{
|
||||
inc_host_errors(&thd->remote.sin_addr);
|
||||
return ER_HANDSHAKE_ERROR;
|
||||
}
|
||||
/* We have to get very specific packet size */
|
||||
if (pkt_len != SCRAMBLE41_LENGTH)
|
||||
{
|
||||
inc_host_errors(&thd->remote.sin_addr);
|
||||
return ER_HANDSHAKE_ERROR;
|
||||
}
|
||||
/* Final attempt to check the user based on reply */
|
||||
if (check_user(thd,COM_CONNECT, tmp_user, (char*)net->read_pos,
|
||||
tmp_db, 1, 0, 1, prepared_scramble, using_password,
|
||||
&cur_priv_version,
|
||||
&cached_user))
|
||||
return -1;
|
||||
}
|
||||
else if (res)
|
||||
return -1; // Error sent from check_user()
|
||||
return 0;
|
||||
if (thd->user)
|
||||
x_free(thd->user);
|
||||
if (!(thd->user= my_strdup(user, MYF(0))))
|
||||
return (ER_OUT_OF_RESOURCES);
|
||||
return check_user(thd, COM_CONNECT, passwd, passwd_len, db, true);
|
||||
}
|
||||
|
||||
|
||||
|
@ -876,7 +866,7 @@ pthread_handler_decl(handle_one_connection,arg)
|
|||
NET *net= &thd->net;
|
||||
thd->thread_stack= (char*) &thd;
|
||||
|
||||
if ((error=check_connections(thd)))
|
||||
if ((error=check_connection(thd)))
|
||||
{ // Wrong permissions
|
||||
if (error > 0)
|
||||
net_printf(thd,error,thd->host_or_ip);
|
||||
|
@ -1188,116 +1178,74 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
|||
case COM_CHANGE_USER:
|
||||
{
|
||||
thd->change_user();
|
||||
thd->clear_error(); // If errors from rollback
|
||||
thd->clear_error(); // if errors from rollback
|
||||
|
||||
statistic_increment(com_other,&LOCK_status);
|
||||
char *user= (char*) packet;
|
||||
statistic_increment(com_other, &LOCK_status);
|
||||
char *user= (char*) packet;
|
||||
char *passwd= strend(user)+1;
|
||||
char *db= strend(passwd)+1;
|
||||
/*
|
||||
Old clients send null-terminated string ('\0' for empty string) for
|
||||
password. New clients send the size (1 byte) + string (not null
|
||||
terminated, so also '\0' for empty string).
|
||||
*/
|
||||
char *db= passwd;
|
||||
uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
|
||||
*passwd++ : strlen(passwd);
|
||||
db+= passwd_len + 1;
|
||||
/* Convert database name to utf8 */
|
||||
String convdb;
|
||||
convdb.copy(db, strlen(db), thd->variables.character_set_client,
|
||||
system_charset_info);
|
||||
db= convdb.c_ptr();
|
||||
|
||||
|
||||
|
||||
/* Small check for incomming packet */
|
||||
if ((uint) ((uchar*) db - net->read_pos) > packet_length)
|
||||
{
|
||||
send_error(thd, ER_UNKNOWN_COM_ERROR);
|
||||
break;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
bool simple_connect;
|
||||
bool using_password;
|
||||
char prepared_scramble[SCRAMBLE41_LENGTH+4];/* Buffer for scramble,hash */
|
||||
char tmp_user[USERNAME_LENGTH+1];
|
||||
char tmp_db[NAME_LEN+1];
|
||||
ACL_USER* cached_user ; /* Cached user */
|
||||
uint cur_priv_version; /* Cached grant version */
|
||||
int res;
|
||||
ulong pkt_len= 0; /* Length of reply packet */
|
||||
|
||||
bzero((char*) prepared_scramble, sizeof(prepared_scramble));
|
||||
/* Small check for incomming packet */
|
||||
|
||||
if ((uint) ((uchar*) db - net->read_pos) > packet_length)
|
||||
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;
|
||||
|
||||
cached_user= NULL;
|
||||
|
||||
/* 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]);
|
||||
|
||||
if (simple_connect) /* Restore scramble for old clients */
|
||||
memcpy(thd->scramble,thd->old_scramble,9);
|
||||
|
||||
/*
|
||||
Check user permissions. If password failure we'll get scramble back
|
||||
Do not retry if we already have sent error (result>0)
|
||||
*/
|
||||
if ((res=check_user(thd,COM_CHANGE_USER, user, passwd, db, 0,
|
||||
simple_connect, simple_connect, prepared_scramble,
|
||||
using_password, &cur_priv_version, &cached_user)) < 0)
|
||||
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;
|
||||
char *save_priv_user= thd->priv_user;
|
||||
char *save_db= thd->db;
|
||||
USER_CONN *save_uc= thd->user_connect;
|
||||
thd->user= my_strdup(user, MYF(0));
|
||||
if (!thd->user)
|
||||
{
|
||||
/* 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 */
|
||||
tmp_user[0]= tmp_db[0]= 0;
|
||||
if (user)
|
||||
strmake(tmp_user,user,USERNAME_LENGTH);
|
||||
if (db)
|
||||
strmake(tmp_db,db,NAME_LEN);
|
||||
|
||||
/* 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_CHANGE_USER, tmp_user, (char*) net->read_pos,
|
||||
tmp_db, 0, 0, 1, prepared_scramble, using_password,
|
||||
&cur_priv_version, &cached_user))
|
||||
goto restore_user;
|
||||
thd->user= save_user;
|
||||
send_error(thd, ER_OUT_OF_RESOURCES);
|
||||
break;
|
||||
}
|
||||
else if (res)
|
||||
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;
|
||||
int res= check_user(thd, COM_CHANGE_USER, passwd, passwd_len, db, false);
|
||||
|
||||
/* Bad luck we shall restore old user */
|
||||
restore_user_err:
|
||||
send_error(thd, ER_UNKNOWN_COM_ERROR);
|
||||
|
||||
restore_user:
|
||||
x_free(thd->user);
|
||||
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;
|
||||
if (res)
|
||||
{
|
||||
/* authentification failure, we shall restore old user */
|
||||
if (res > 0)
|
||||
send_error(thd, ER_UNKNOWN_COM_ERROR);
|
||||
x_free(thd->user);
|
||||
thd->user= save_user;
|
||||
thd->priv_user= save_priv_user;
|
||||
thd->master_access= save_master_access;
|
||||
thd->db_access= save_db_access;
|
||||
thd->db= save_db;
|
||||
thd->db_length= save_db_length;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 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);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif /* EMBEDDED_LIBRARY */
|
||||
|
@ -3247,7 +3195,7 @@ error:
|
|||
Check grants for commands which work only with one table and all other
|
||||
tables belong to subselects.
|
||||
|
||||
SYNOPSYS
|
||||
SYNOPSIS
|
||||
single_table_command_access()
|
||||
thd - Thread handler
|
||||
privilege - asked privelage
|
||||
|
|
|
@ -506,6 +506,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
|
|||
%token MULTIPOINT
|
||||
%token MULTIPOLYGON
|
||||
%token NOW_SYM
|
||||
%token OLD_PASSWORD
|
||||
%token PASSWORD
|
||||
%token POINTFROMTEXT
|
||||
%token POINT_SYM
|
||||
|
@ -2607,9 +2608,13 @@ simple_expr:
|
|||
| NOW_SYM '(' expr ')'
|
||||
{ $$= new Item_func_now_local($3); Lex->safe_to_cache_query=0;}
|
||||
| PASSWORD '(' expr ')'
|
||||
{ $$= new Item_func_password($3); }
|
||||
| PASSWORD '(' expr ',' expr ')'
|
||||
{ $$= new Item_func_password($3,$5); }
|
||||
{
|
||||
$$= YYTHD->variables.old_passwords ?
|
||||
(Item *) new Item_func_old_password($3) :
|
||||
(Item *) new Item_func_password($3);
|
||||
}
|
||||
| OLD_PASSWORD '(' expr ')'
|
||||
{ $$= new Item_func_old_password($3); }
|
||||
| POINT_SYM '(' expr ',' expr ')'
|
||||
{ $$= new Item_func_point($3,$5); }
|
||||
| POINTFROMTEXT '(' expr ')'
|
||||
|
@ -4517,6 +4522,7 @@ keyword:
|
|||
| NO_SYM {}
|
||||
| NONE_SYM {}
|
||||
| OFFSET_SYM {}
|
||||
| OLD_PASSWORD {}
|
||||
| OPEN_SYM {}
|
||||
| PACK_KEYS_SYM {}
|
||||
| PARTIAL {}
|
||||
|
@ -4741,15 +4747,15 @@ text_or_password:
|
|||
TEXT_STRING { $$=$1.str;}
|
||||
| PASSWORD '(' TEXT_STRING ')'
|
||||
{
|
||||
if (!$3.length)
|
||||
$$=$3.str;
|
||||
else
|
||||
{
|
||||
char *buff=(char*) YYTHD->alloc(HASH_PASSWORD_LENGTH+1);
|
||||
make_scrambled_password(buff,$3.str,use_old_passwords,
|
||||
&YYTHD->rand);
|
||||
$$=buff;
|
||||
}
|
||||
$$= $3.length ? YYTHD->variables.old_passwords ?
|
||||
Item_func_old_password::alloc(YYTHD, $3.str) :
|
||||
Item_func_password::alloc(YYTHD, $3.str) :
|
||||
$3.str;
|
||||
}
|
||||
| OLD_PASSWORD '(' TEXT_STRING ')'
|
||||
{
|
||||
$$= $3.length ? Item_func_old_password::alloc(YYTHD, $3.str) :
|
||||
$3.str;
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -5057,14 +5063,24 @@ grant_user:
|
|||
$$=$1; $1->password=$4;
|
||||
if ($4.length)
|
||||
{
|
||||
char *buff=(char*) YYTHD->alloc(HASH_PASSWORD_LENGTH+1);
|
||||
if (buff)
|
||||
{
|
||||
make_scrambled_password(buff,$4.str,use_old_passwords,
|
||||
&YYTHD->rand);
|
||||
$1->password.str=buff;
|
||||
$1->password.length=HASH_PASSWORD_LENGTH;
|
||||
}
|
||||
if (YYTHD->variables.old_passwords)
|
||||
{
|
||||
char *buff=
|
||||
(char *) YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1);
|
||||
if (buff)
|
||||
make_scrambled_password_323(buff, $4.str);
|
||||
$1->password.str= buff;
|
||||
$1->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
|
||||
}
|
||||
else
|
||||
{
|
||||
char *buff=
|
||||
(char *) YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH+1);
|
||||
if (buff)
|
||||
make_scrambled_password(buff, $4.str);
|
||||
$1->password.str= buff;
|
||||
$1->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH;
|
||||
}
|
||||
}
|
||||
}
|
||||
| user IDENTIFIED_SYM BY PASSWORD TEXT_STRING
|
||||
|
|
Loading…
Reference in a new issue