Bug fixes for authentication
OLD_PASSWORD made a keyword to allow set password=old_password('abc') constructions.
This commit is contained in:
parent
7df0475847
commit
1d20b23247
@ -624,3 +624,8 @@ vio/test-sslserver
|
||||
vio/viotest-ssl
|
||||
start_mysqld.sh
|
||||
mysys/main.cc
|
||||
BitKeeper/post-commit
|
||||
BitKeeper/post-commit-manual
|
||||
build_tags.sh
|
||||
tests/connect_test
|
||||
BUILD/compile-pentium-maintainer
|
||||
|
@ -327,7 +327,7 @@ 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);
|
||||
char *scramble(char *to, const char *message, 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);
|
||||
|
@ -619,16 +619,20 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
|
||||
/* write scrambled password according to server capabilities */
|
||||
if (passwd[0])
|
||||
{
|
||||
/* Write NULL-terminated scrambled password: */
|
||||
end= mysql->server_capabilities & CLIENT_SECURE_CONNECTION ?
|
||||
scramble(end, mysql->scramble, passwd) :
|
||||
scramble_323(end, mysql->scramble_323, passwd,
|
||||
(my_bool) (mysql->protocol_version == 9));
|
||||
if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
|
||||
{
|
||||
*end++= SCRAMBLE_LENGTH;
|
||||
scramble(end, mysql->scramble, passwd);
|
||||
end+= SCRAMBLE_LENGTH;
|
||||
}
|
||||
else
|
||||
end= scramble_323(end, mysql->scramble_323, passwd,
|
||||
(my_bool) (mysql->protocol_version == 9)) + 1;
|
||||
}
|
||||
else
|
||||
*end= '\0'; // empty password
|
||||
*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);
|
||||
|
@ -1823,7 +1823,7 @@ 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);
|
||||
|
||||
@ -1835,21 +1835,25 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
|
||||
end= strend(end) + 1;
|
||||
if (passwd[0])
|
||||
{
|
||||
/* Write NULL-terminated scrambled password: */
|
||||
end= mysql->server_capabilities & CLIENT_SECURE_CONNECTION ?
|
||||
scramble(end, mysql->scramble, passwd) :
|
||||
scramble_323(end, mysql->scramble_323, passwd,
|
||||
(my_bool) (mysql->protocol_version == 9));
|
||||
if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
|
||||
{
|
||||
*end++= SCRAMBLE_LENGTH;
|
||||
scramble(end, mysql->scramble, passwd);
|
||||
end+= SCRAMBLE_LENGTH;
|
||||
}
|
||||
else
|
||||
end= scramble_323(end, mysql->scramble_323, passwd,
|
||||
(my_bool) (mysql->protocol_version == 9)) + 1;
|
||||
}
|
||||
else
|
||||
*end= '\0'; /* empty password */
|
||||
*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))
|
||||
|
@ -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);
|
||||
|
@ -1360,6 +1360,14 @@ String *Item_func_password::val_str(String *str)
|
||||
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)
|
||||
@ -1374,6 +1382,14 @@ String *Item_func_old_password::val_str(String *str)
|
||||
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)+'.')
|
||||
|
||||
|
@ -270,6 +270,7 @@ public:
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
@ -288,7 +289,7 @@ public:
|
||||
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"; }
|
||||
unsigned int size_of() { return sizeof(*this);}
|
||||
static char *alloc(THD *thd, const char *password);
|
||||
};
|
||||
|
||||
|
||||
|
@ -284,6 +284,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},
|
||||
@ -577,7 +578,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)},
|
||||
|
@ -446,22 +446,20 @@ make_scrambled_password(char *to, const char *password)
|
||||
Produce an obscure octet sequence from password and random
|
||||
string, recieved from the server. This sequence corresponds to the
|
||||
password, but password can not be easily restored from it. The sequence
|
||||
is then sent to the server for validation. Trailing zero is stored in
|
||||
the buf.
|
||||
is then sent to the server for validation. Trailing zero is not stored
|
||||
in the buf as it is not needed.
|
||||
This function is used by client to create authenticated reply to the
|
||||
server's greeting.
|
||||
SYNOPSIS
|
||||
scramble()
|
||||
buf OUT store scrambled string here. The buf must be at least
|
||||
SHA1_HASH_SIZE+1 bytes long.
|
||||
SHA1_HASH_SIZE bytes long.
|
||||
message IN random message, must be exactly SCRAMBLE_LENGTH long and
|
||||
NULL-terminated.
|
||||
password IN users' password
|
||||
RETURN VALUE
|
||||
end of scrambled string
|
||||
*/
|
||||
|
||||
char *
|
||||
void
|
||||
scramble(char *to, const char *message, const char *password)
|
||||
{
|
||||
SHA1_CONTEXT sha1_context;
|
||||
@ -483,8 +481,6 @@ scramble(char *to, const char *message, const char *password)
|
||||
/* xor allows 'from' and 'to' overlap: lets take advantage of it */
|
||||
sha1_result(&sha1_context, (uint8 *) to);
|
||||
my_crypt(to, (const uint8 *) to, hash_stage1, SCRAMBLE_LENGTH);
|
||||
to[SHA1_HASH_SIZE]= '\0';
|
||||
return to + SHA1_HASH_SIZE;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
@ -208,7 +208,8 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
|
||||
|
||||
DBUG_PRINT("info",("user table fields: %d, password length: %d",
|
||||
table->fields, table->field[2]->field_length));
|
||||
if (table->field[2]->field_length < 41 && !use_old_passwords)
|
||||
if (table->field[2]->field_length < SCRAMBLED_PASSWORD_CHAR_LENGTH &&
|
||||
!use_old_passwords)
|
||||
{
|
||||
sql_print_error("mysql.user table is not updated to new password format; "
|
||||
"Disabling new password usage until "
|
||||
@ -516,6 +517,7 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b)
|
||||
RETURN VALUE
|
||||
0 success: thread data and 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.
|
||||
*/
|
||||
|
||||
@ -564,6 +566,9 @@ acl_getroot(THD *thd, USER_RESOURCES *mqh,
|
||||
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;
|
||||
}
|
||||
|
256
sql/sql_parse.cc
256
sql/sql_parse.cc
@ -195,11 +195,8 @@ end:
|
||||
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 internal error; error is sent to client
|
||||
Note, that this return semantics differs from check_connection,
|
||||
which returns -1 if message was already sent.
|
||||
-1 acl entry for this user contains old scramble, but passwd contains
|
||||
new one, error is not 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 enum_server_command command,
|
||||
@ -208,87 +205,129 @@ static int check_user(THD *thd, enum enum_server_command command,
|
||||
{
|
||||
DBUG_ENTER("check_user");
|
||||
|
||||
if (passwd_len != 0 &&
|
||||
passwd_len != SCRAMBLE_LENGTH &&
|
||||
passwd_len != SCRAMBLE_LENGTH_323)
|
||||
DBUG_RETURN(ER_HANDSHAKE_ERROR);
|
||||
|
||||
/*
|
||||
Why this is set here? - probably to reset current DB to 'no database
|
||||
selected' in case of 'change user' failure.
|
||||
*/
|
||||
thd->db= 0;
|
||||
thd->db_length= 0;
|
||||
|
||||
|
||||
char buff[NAME_LEN + 1]; /* to conditionally save db */
|
||||
|
||||
USER_RESOURCES ur;
|
||||
int res= acl_getroot(thd, &ur, passwd, passwd_len,
|
||||
protocol_version == 9 ||
|
||||
!(thd->client_capabilities & CLIENT_LONG_PASSWORD));
|
||||
if (res == 0 && !(thd->master_access & NO_ACCESS)) // authentification is OK
|
||||
if (res == -1)
|
||||
{
|
||||
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)
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
/* save db because network buffer is to hold new packet */
|
||||
if (db)
|
||||
{
|
||||
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);
|
||||
}
|
||||
strmake(buff, db, NAME_LEN);
|
||||
db= buff;
|
||||
}
|
||||
|
||||
/* 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*) "");
|
||||
|
||||
/* Why is it set here? */
|
||||
thd->db_access=0;
|
||||
|
||||
/* Don't allow user to connect if he has done too many queries */
|
||||
if ((ur.questions || ur.updates || ur.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])
|
||||
NET *net= &thd->net;
|
||||
if (my_net_write(net, thd->scramble_323, SCRAMBLE_LENGTH_323 + 1) ||
|
||||
net_flush(net) ||
|
||||
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,
|
||||
false);
|
||||
}
|
||||
/* here res is always >= 0 */
|
||||
if (res == 0)
|
||||
{
|
||||
if (!(thd->master_access & NO_ACCESS)) // authentification is OK
|
||||
{
|
||||
if (mysql_change_db(thd, db))
|
||||
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)
|
||||
{
|
||||
if (thd->user_connect)
|
||||
decrease_user_connections(thd->user_connect);
|
||||
DBUG_RETURN(1);
|
||||
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*) "");
|
||||
|
||||
/* Why is it set here? */
|
||||
thd->db_access=0;
|
||||
|
||||
/* Don't allow user to connect if he has done too many queries */
|
||||
if ((ur.questions || ur.updates || ur.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
|
||||
send_ok(thd);
|
||||
thd->password= test(passwd_len); // remember for error messages
|
||||
/* Ready to handle queries */
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
else
|
||||
send_ok(thd);
|
||||
thd->password= test(passwd_len); // remember for error messages
|
||||
/* Ready to handle queries */
|
||||
}
|
||||
else if (res != -1) // authentication failure
|
||||
else if (res == 2) // client gave short hash, server has long hash
|
||||
{
|
||||
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));
|
||||
net_printf(thd, ER_NOT_SUPPORTED_AUTH_MODE);
|
||||
mysql_log.write(thd,COM_CONNECT,ER(ER_NOT_SUPPORTED_AUTH_MODE));
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
DBUG_RETURN(res);
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -491,60 +530,6 @@ static void reset_mqh(THD *thd, LEX_USER *lu, bool get_them= 0)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Perform check for scrambled password, re-request scrambled password
|
||||
from client if necessary. See also help for check_user.
|
||||
SYNOPSIS
|
||||
authenticate()
|
||||
RETURN VALUE
|
||||
0 success, OK sent to client
|
||||
-1 error, sent to client
|
||||
> 0 error, not sent to client
|
||||
*/
|
||||
|
||||
static
|
||||
int
|
||||
authenticate(THD *thd, enum enum_server_command command,
|
||||
const char *passwd, uint passwd_len, const char *db,
|
||||
bool check_count)
|
||||
{
|
||||
if (passwd_len != 0 &&
|
||||
passwd_len != SCRAMBLE_LENGTH &&
|
||||
passwd_len != SCRAMBLE_LENGTH_323)
|
||||
return 1;
|
||||
int res= check_user(thd, COM_CONNECT, passwd, passwd_len, db, check_count);
|
||||
if (res < 0)
|
||||
{
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
char buff[NAME_LEN + 1];
|
||||
/* save db because network buffer is to hold new packet */
|
||||
if (db)
|
||||
{
|
||||
strmake(buff, db, NAME_LEN);
|
||||
db= buff;
|
||||
}
|
||||
NET *net= &thd->net;
|
||||
if (my_net_write(net, thd->scramble_323, SCRAMBLE_LENGTH_323 + 1) ||
|
||||
net_flush(net) ||
|
||||
my_net_read(net) != SCRAMBLE_LENGTH_323 + 1) // We have to read very
|
||||
{ // specific packet size
|
||||
inc_host_errors(&thd->remote.sin_addr);
|
||||
return ER_HANDSHAKE_ERROR;
|
||||
}
|
||||
/* Final attempt to check the user based on reply */
|
||||
/* So as passwd is short, errcode is always sent to user and res >= 0 */
|
||||
res= check_user(thd, COM_CONNECT, (char *) net->read_pos,
|
||||
SCRAMBLE_LENGTH_323, db, check_count);
|
||||
}
|
||||
return res > 0 ? -1 : 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Perform handshake, authorize client and update thd ACL variables.
|
||||
SYNOPSIS
|
||||
@ -643,7 +628,7 @@ check_connection(THD *thd)
|
||||
|
||||
/*
|
||||
Old clients does not understand long scrambles, but can ignore packet
|
||||
tail: that's why first part of scramble is placed here, and second
|
||||
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_323, SCRAMBLE_LENGTH_323) + 1;
|
||||
@ -760,17 +745,23 @@ check_connection(THD *thd)
|
||||
|
||||
char *user= end;
|
||||
char *passwd= strend(user)+1;
|
||||
uint passwd_len= strlen(passwd);
|
||||
|
||||
char *db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
|
||||
passwd+passwd_len+1 : 0;
|
||||
char *db= passwd;
|
||||
/*
|
||||
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;
|
||||
|
||||
if (thd->user)
|
||||
x_free(thd->user);
|
||||
thd->user= my_strdup(user, MYF(0));
|
||||
if (!thd->user)
|
||||
return(ER_OUT_OF_RESOURCES);
|
||||
return authenticate(thd, COM_CONNECT, passwd, passwd_len, db, true);
|
||||
return check_user(thd, COM_CONNECT, passwd, passwd_len, db, true);
|
||||
}
|
||||
|
||||
|
||||
@ -1137,8 +1128,15 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
||||
statistic_increment(com_other, &LOCK_status);
|
||||
char *user= (char*) packet;
|
||||
char *passwd= strend(user)+1;
|
||||
uint passwd_len= strlen(passwd);
|
||||
char *db= passwd + passwd_len + 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;
|
||||
|
||||
/* Small check for incomming packet */
|
||||
if ((uint) ((uchar*) db - net->read_pos) > packet_length)
|
||||
@ -1163,7 +1161,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
||||
break;
|
||||
}
|
||||
|
||||
int res= authenticate(thd, COM_CHANGE_USER, passwd, passwd_len, db, false);
|
||||
int res= check_user(thd, COM_CHANGE_USER, passwd, passwd_len, db, false);
|
||||
|
||||
if (res)
|
||||
{
|
||||
|
@ -493,6 +493,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
|
||||
@ -2516,9 +2517,11 @@ simple_expr:
|
||||
{ $$= new Item_func_now($3); Lex->safe_to_cache_query=0;}
|
||||
| PASSWORD '(' expr ')'
|
||||
{
|
||||
$$= use_old_passwords ? (Item *) new Item_func_old_password($3) :
|
||||
(Item *) new Item_func_password($3);
|
||||
}
|
||||
$$= use_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 ')'
|
||||
@ -4412,6 +4415,7 @@ keyword:
|
||||
| NO_SYM {}
|
||||
| NONE_SYM {}
|
||||
| OFFSET_SYM {}
|
||||
| OLD_PASSWORD {}
|
||||
| OPEN_SYM {}
|
||||
| PACK_KEYS_SYM {}
|
||||
| PARTIAL {}
|
||||
@ -4603,24 +4607,15 @@ text_or_password:
|
||||
TEXT_STRING { $$=$1.str;}
|
||||
| PASSWORD '(' TEXT_STRING ')'
|
||||
{
|
||||
if (!$3.length)
|
||||
$$=$3.str;
|
||||
else if (use_old_passwords)
|
||||
{
|
||||
char *buff= (char *)
|
||||
YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1);
|
||||
if (buff)
|
||||
make_scrambled_password_323(buff, $3.str);
|
||||
$$=buff;
|
||||
}
|
||||
else
|
||||
{
|
||||
char *buff= (char *)
|
||||
YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH+1);
|
||||
if (buff)
|
||||
make_scrambled_password(buff, $3.str);
|
||||
$$=buff;
|
||||
}
|
||||
$$= $3.length ? use_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;
|
||||
}
|
||||
;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user