Commit ccbcf1c9 authored by unknown's avatar unknown

Bug fixes for authentication

OLD_PASSWORD made a keyword to allow set password=old_password('abc') constructions.


BitKeeper/etc/ignore:
  Added BitKeeper/post-commit BitKeeper/post-commit-manual build_tags.sh tests/connect_test BUILD/compile-pentium-maintainer to the ignore list
include/mysql_com.h:
  scramble return type changed to void as now it's not used
libmysql/libmysql.c:
  fixed bug with with failed authentification when scramble contained zero byte
sql-common/client.c:
  applied patch from Lycos team
  fixed bug with scramble containing zero byte
sql/item_create.cc:
  removed create_func_old_password, create_func_password as they are not used any more
sql/item_create.h:
  removed create_func_old_password, create_func_password as they are not used any more
sql/item_strfunc.cc:
  Added alloc() function to Item_func_password, Item_func_old_password, which is used in sql_yacc.yy
sql/item_strfunc.h:
  Added alloc() function to Item_func_password, Item_func_old_password, which is used in sql_yacc.yy
sql/lex.h:
  OLD_PASSWORD now is keyword, to allow statements like
  set password=old_password('abc')
sql/password.c:
  fixed scramble return value
  trailing zero now is not written
sql/sql_acl.cc:
  incorporated patch from Lycos team
  41 replaced with constant
  acl_getroot rewritten to support ER_AUTH_... error
sql/sql_parse.cc:
  authenticate merged with check_user
  check_user return values reversed, support for ER_AUTH in check_user.added
sql/sql_yacc.yy:
  OLD_PASSWORD now is keyword, to allow statements like
  set password=old_password('abc')
parent dbb088b0
...@@ -624,3 +624,8 @@ vio/test-sslserver ...@@ -624,3 +624,8 @@ vio/test-sslserver
vio/viotest-ssl vio/viotest-ssl
start_mysqld.sh start_mysqld.sh
mysys/main.cc 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); ...@@ -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_password_from_salt_323(char *to, const unsigned long *salt);
void make_scrambled_password(char *to, const char *password); 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, my_bool check_scramble(const char *reply, const char *message,
const unsigned char *hash_stage2); const unsigned char *hash_stage2);
void get_salt_from_password(unsigned char *res, const char *password); 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, ...@@ -619,16 +619,20 @@ my_bool STDCALL mysql_change_user(MYSQL *mysql, const char *user,
/* write scrambled password according to server capabilities */ /* write scrambled password according to server capabilities */
if (passwd[0]) if (passwd[0])
{ {
/* Write NULL-terminated scrambled password: */ if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
end= mysql->server_capabilities & CLIENT_SECURE_CONNECTION ? {
scramble(end, mysql->scramble, passwd) : *end++= SCRAMBLE_LENGTH;
scramble_323(end, mysql->scramble_323, passwd, scramble(end, mysql->scramble, passwd);
(my_bool) (mysql->protocol_version == 9)); end+= SCRAMBLE_LENGTH;
}
else
end= scramble_323(end, mysql->scramble_323, passwd,
(my_bool) (mysql->protocol_version == 9)) + 1;
} }
else else
*end= '\0'; // empty password *end++= '\0'; // empty password
/* Add database if needed */ /* Add database if needed */
end=strmov(end+1,db ? db : ""); end= strmov(end, db ? db : "") + 1;
/* Write authentication package */ /* Write authentication package */
simple_command(mysql,COM_CHANGE_USER, buff,(ulong) (end-buff),1); 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, ...@@ -1823,7 +1823,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
mysql->server_status, client_flag)); mysql->server_status, client_flag));
/* This needs to be changed as it's not useful with big packets */ /* This needs to be changed as it's not useful with big packets */
if (user && user[0]) if (user && user[0])
strmake(end,user,32); /* Max user name */ strmake(end,user,USERNAME_LENGTH); /* Max user name */
else else
read_user_name((char*) end); read_user_name((char*) end);
...@@ -1835,21 +1835,25 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user, ...@@ -1835,21 +1835,25 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
end= strend(end) + 1; end= strend(end) + 1;
if (passwd[0]) if (passwd[0])
{ {
/* Write NULL-terminated scrambled password: */ if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
end= mysql->server_capabilities & CLIENT_SECURE_CONNECTION ? {
scramble(end, mysql->scramble, passwd) : *end++= SCRAMBLE_LENGTH;
scramble_323(end, mysql->scramble_323, passwd, scramble(end, mysql->scramble, passwd);
(my_bool) (mysql->protocol_version == 9)); end+= SCRAMBLE_LENGTH;
}
else
end= scramble_323(end, mysql->scramble_323, passwd,
(my_bool) (mysql->protocol_version == 9)) + 1;
} }
else else
*end= '\0'; /* empty password */ *end++= '\0'; /* empty password */
/* Add database if needed */ /* Add database if needed */
if (db && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB)) if (db && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB))
{ {
end=strmake(end+1,db,NAME_LEN); end= strmake(end, db, NAME_LEN) + 1;
mysql->db=my_strdup(db,MYF(MY_WME)); mysql->db= my_strdup(db,MYF(MY_WME));
db=0; db= 0;
} }
/* Write authentication package */ /* Write authentication package */
if (my_net_write(net,buff,(ulong) (end-buff)) || net_flush(net)) if (my_net_write(net,buff,(ulong) (end-buff)) || net_flush(net))
......
...@@ -52,13 +52,6 @@ Item *create_func_ord(Item* a) ...@@ -52,13 +52,6 @@ Item *create_func_ord(Item* a)
return new Item_func_ord(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) Item *create_func_asin(Item* a)
{ {
return new Item_func_asin(a); return new Item_func_asin(a);
...@@ -332,11 +325,6 @@ Item *create_func_quarter(Item* a) ...@@ -332,11 +325,6 @@ Item *create_func_quarter(Item* a)
return new Item_func_quarter(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) Item *create_func_radians(Item *a)
{ {
return new Item_func_units((char*) "radians",a,M_PI/180,0.0); return new Item_func_units((char*) "radians",a,M_PI/180,0.0);
......
...@@ -69,14 +69,12 @@ Item *create_func_monthname(Item* a); ...@@ -69,14 +69,12 @@ Item *create_func_monthname(Item* a);
Item *create_func_nullif(Item* a, Item *b); Item *create_func_nullif(Item* a, Item *b);
Item *create_func_oct(Item *); Item *create_func_oct(Item *);
Item *create_func_ord(Item* a); 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_add(Item* a, Item *b);
Item *create_func_period_diff(Item* a, Item *b); Item *create_func_period_diff(Item* a, Item *b);
Item *create_func_pi(void); Item *create_func_pi(void);
Item *create_func_pow(Item* a, Item *b); Item *create_func_pow(Item* a, Item *b);
Item *create_func_current_user(void); Item *create_func_current_user(void);
Item *create_func_quarter(Item* a); Item *create_func_quarter(Item* a);
Item *create_func_password(Item* a);
Item *create_func_radians(Item *a); Item *create_func_radians(Item *a);
Item *create_func_release_lock(Item* a); Item *create_func_release_lock(Item* a);
Item *create_func_repeat(Item* a, Item *b); Item *create_func_repeat(Item* a, Item *b);
......
...@@ -1360,6 +1360,14 @@ String *Item_func_password::val_str(String *str) ...@@ -1360,6 +1360,14 @@ String *Item_func_password::val_str(String *str)
return 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 */ /* Item_func_old_password */
String *Item_func_old_password::val_str(String *str) String *Item_func_old_password::val_str(String *str)
...@@ -1374,6 +1382,14 @@ String *Item_func_old_password::val_str(String *str) ...@@ -1374,6 +1382,14 @@ String *Item_func_old_password::val_str(String *str)
return 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)+'.') #define bin_to_ascii(c) ((c)>=38?((c)-38+'a'):(c)>=12?((c)-12+'A'):(c)+'.')
......
...@@ -270,6 +270,7 @@ class Item_func_password :public Item_str_func ...@@ -270,6 +270,7 @@ class Item_func_password :public Item_str_func
String *val_str(String *str); String *val_str(String *str);
void fix_length_and_dec() { max_length= SCRAMBLED_PASSWORD_CHAR_LENGTH; } void fix_length_and_dec() { max_length= SCRAMBLED_PASSWORD_CHAR_LENGTH; }
const char *func_name() const { return "password"; } const char *func_name() const { return "password"; }
static char *alloc(THD *thd, const char *password);
}; };
...@@ -288,7 +289,7 @@ class Item_func_old_password :public Item_str_func ...@@ -288,7 +289,7 @@ class Item_func_old_password :public Item_str_func
String *val_str(String *str); String *val_str(String *str);
void fix_length_and_dec() { max_length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323; } void fix_length_and_dec() { max_length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323; }
const char *func_name() const { return "old_password"; } 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[] = { ...@@ -284,6 +284,7 @@ static SYMBOL symbols[] = {
{ "NULL", SYM(NULL_SYM),0,0}, { "NULL", SYM(NULL_SYM),0,0},
{ "NUMERIC", SYM(NUMERIC_SYM),0,0}, { "NUMERIC", SYM(NUMERIC_SYM),0,0},
{ "OFFSET", SYM(OFFSET_SYM),0,0}, { "OFFSET", SYM(OFFSET_SYM),0,0},
{ "OLD_PASSWORD", SYM(OLD_PASSWORD),0,0},
{ "ON", SYM(ON),0,0}, { "ON", SYM(ON),0,0},
{ "OPEN", SYM(OPEN_SYM),0,0}, { "OPEN", SYM(OPEN_SYM),0,0},
{ "OPTIMIZE", SYM(OPTIMIZE),0,0}, { "OPTIMIZE", SYM(OPTIMIZE),0,0},
...@@ -577,7 +578,6 @@ static SYMBOL sql_functions[] = { ...@@ -577,7 +578,6 @@ static SYMBOL sql_functions[] = {
{ "NUMPOINTS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_numpoints)}, { "NUMPOINTS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_numpoints)},
{ "OCTET_LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_length)}, { "OCTET_LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_length)},
{ "OCT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_oct)}, { "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)}, { "ORD", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ord)},
{ "OVERLAPS", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_overlaps)}, { "OVERLAPS", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_overlaps)},
{ "PERIOD_ADD", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_period_add)}, { "PERIOD_ADD", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_period_add)},
......
...@@ -446,22 +446,20 @@ make_scrambled_password(char *to, const char *password) ...@@ -446,22 +446,20 @@ make_scrambled_password(char *to, const char *password)
Produce an obscure octet sequence from password and random Produce an obscure octet sequence from password and random
string, recieved from the server. This sequence corresponds to the string, recieved from the server. This sequence corresponds to the
password, but password can not be easily restored from it. The sequence 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 is then sent to the server for validation. Trailing zero is not stored
the buf. in the buf as it is not needed.
This function is used by client to create authenticated reply to the This function is used by client to create authenticated reply to the
server's greeting. server's greeting.
SYNOPSIS SYNOPSIS
scramble() scramble()
buf OUT store scrambled string here. The buf must be at least 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 message IN random message, must be exactly SCRAMBLE_LENGTH long and
NULL-terminated. NULL-terminated.
password IN users' password password IN users' password
RETURN VALUE
end of scrambled string
*/ */
char * void
scramble(char *to, const char *message, const char *password) scramble(char *to, const char *message, const char *password)
{ {
SHA1_CONTEXT sha1_context; SHA1_CONTEXT sha1_context;
...@@ -483,8 +481,6 @@ scramble(char *to, const char *message, const char *password) ...@@ -483,8 +481,6 @@ scramble(char *to, const char *message, const char *password)
/* xor allows 'from' and 'to' overlap: lets take advantage of it */ /* xor allows 'from' and 'to' overlap: lets take advantage of it */
sha1_result(&sha1_context, (uint8 *) to); sha1_result(&sha1_context, (uint8 *) to);
my_crypt(to, (const uint8 *) to, hash_stage1, SCRAMBLE_LENGTH); 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, ...@@ -51,7 +51,7 @@ static byte* acl_entry_get_key(acl_entry *entry,uint *length,
return (byte*) entry->key; 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 DYNAMIC_ARRAY acl_hosts,acl_users,acl_dbs;
static MEM_ROOT mem, memex; static MEM_ROOT mem, memex;
...@@ -208,7 +208,8 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) ...@@ -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", DBUG_PRINT("info",("user table fields: %d, password length: %d",
table->fields, table->field[2]->field_length)); 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; " sql_print_error("mysql.user table is not updated to new password format; "
"Disabling new password usage until " "Disabling new password usage until "
...@@ -516,6 +517,7 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b) ...@@ -516,6 +517,7 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b)
RETURN VALUE RETURN VALUE
0 success: thread data and mqh are updated 0 success: thread data and mqh are updated
1 user not found or authentification failure 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. -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, ...@@ -564,6 +566,9 @@ acl_getroot(THD *thd, USER_RESOURCES *mqh,
else if (passwd_len == SCRAMBLE_LENGTH && else if (passwd_len == SCRAMBLE_LENGTH &&
user_i->salt_len == SCRAMBLE_LENGTH_323) user_i->salt_len == SCRAMBLE_LENGTH_323)
res= -1; res= -1;
else if (passwd_len == SCRAMBLE_LENGTH_323 &&
user_i->salt_len == SCRAMBLE_LENGTH)
res= 2;
/* linear search complete: */ /* linear search complete: */
break; break;
} }
......
...@@ -195,11 +195,8 @@ static int get_or_create_user_conn(THD *thd, const char *user, ...@@ -195,11 +195,8 @@ static int get_or_create_user_conn(THD *thd, const char *user,
RETURN VALUE RETURN VALUE
0 OK; thd->user, thd->master_access, thd->priv_user, thd->db and 0 OK; thd->user, thd->master_access, thd->priv_user, thd->db and
thd->db_access are updated; OK is sent to client; thd->db_access are updated; OK is sent to client;
1 access denied or internal error; error is sent to client -1 access denied or handshake error; error is sent to client;
Note, that this return semantics differs from check_connection, >0 error, not sent to client
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
*/ */
static int check_user(THD *thd, enum enum_server_command command, 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, ...@@ -208,87 +205,129 @@ static int check_user(THD *thd, enum enum_server_command command,
{ {
DBUG_ENTER("check_user"); 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 Why this is set here? - probably to reset current DB to 'no database
selected' in case of 'change user' failure. selected' in case of 'change user' failure.
*/ */
thd->db= 0; thd->db= 0;
thd->db_length= 0; thd->db_length= 0;
char buff[NAME_LEN + 1]; /* to conditionally save db */
USER_RESOURCES ur; USER_RESOURCES ur;
int res= acl_getroot(thd, &ur, passwd, passwd_len, int res= acl_getroot(thd, &ur, passwd, passwd_len,
protocol_version == 9 || protocol_version == 9 ||
!(thd->client_capabilities & CLIENT_LONG_PASSWORD)); !(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' " This happens when client (new) sends password scrambled with
"Login user: '%s' Priv_user: '%s' Using password: %s " scramble(), but database holds old value (scrambled with
"Access: %u db: '%s'", scramble_323()). Here we please client to send scrambled_password
thd->client_capabilities, thd->max_client_packet_length, in old format.
thd->host_or_ip, thd->user, thd->priv_user, */
passwd_len ? "yes": "no", /* save db because network buffer is to hold new packet */
thd->master_access, thd->db ? thd->db : "*none*")); if (db)
if (check_count)
{ {
VOID(pthread_mutex_lock(&LOCK_thread_count)); strmake(buff, db, NAME_LEN);
bool count_ok= thread_count < max_connections + delayed_insert_threads || db= buff;
thd->master_access & SUPER_ACL; }
VOID(pthread_mutex_unlock(&LOCK_thread_count)); NET *net= &thd->net;
if (!count_ok) if (my_net_write(net, thd->scramble_323, SCRAMBLE_LENGTH_323 + 1) ||
{ // too many connections net_flush(net) ||
send_error(thd, ER_CON_COUNT_ERROR); my_net_read(net) != SCRAMBLE_LENGTH_323 + 1) // We have to read very
DBUG_RETURN(1); { // 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
{
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)
{
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? */ /* Why logging is performed before all checks've passed? */
mysql_log.write(thd,command, mysql_log.write(thd,command,
(thd->priv_user == thd->user ? (thd->priv_user == thd->user ?
(char*) "%s@%s on %s" : (char*) "%s@%s on %s" :
(char*) "%s@%s as anonymous on %s"), (char*) "%s@%s as anonymous on %s"),
thd->user, thd->host_or_ip, thd->user, thd->host_or_ip,
db ? db : (char*) ""); db ? db : (char*) "");
/* Why is it set here? */ /* Why is it set here? */
thd->db_access=0; thd->db_access=0;
/* Don't allow user to connect if he has done too many queries */ /* Don't allow user to connect if he has done too many queries */
if ((ur.questions || ur.updates || ur.connections) && if ((ur.questions || ur.updates || ur.connections) &&
get_or_create_user_conn(thd,thd->user,thd->host_or_ip,&ur)) get_or_create_user_conn(thd,thd->user,thd->host_or_ip,&ur))
DBUG_RETURN(1); DBUG_RETURN(1);
if (thd->user_connect && thd->user_connect->user_resources.connections && if (thd->user_connect && thd->user_connect->user_resources.connections &&
check_for_max_user_connections(thd, thd->user_connect)) check_for_max_user_connections(thd, thd->user_connect))
DBUG_RETURN(1); DBUG_RETURN(1);
/* Change database if necessary: OK or FAIL is sent in mysql_change_db */ /* Change database if necessary: OK or FAIL is sent in mysql_change_db */
if (db && db[0]) if (db && db[0])
{
if (mysql_change_db(thd, db))
{ {
if (thd->user_connect) if (mysql_change_db(thd, db))
decrease_user_connections(thd->user_connect); {
DBUG_RETURN(1); 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, net_printf(thd, ER_NOT_SUPPORTED_AUTH_MODE);
thd->user, mysql_log.write(thd,COM_CONNECT,ER(ER_NOT_SUPPORTED_AUTH_MODE));
thd->host_or_ip, DBUG_RETURN(-1);
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(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) ...@@ -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. Perform handshake, authorize client and update thd ACL variables.
SYNOPSIS SYNOPSIS
...@@ -643,7 +628,7 @@ check_connection(THD *thd) ...@@ -643,7 +628,7 @@ check_connection(THD *thd)
/* /*
Old clients does not understand long scrambles, but can ignore packet 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. part at the end of packet.
*/ */
end= strmake(end, thd->scramble_323, SCRAMBLE_LENGTH_323) + 1; end= strmake(end, thd->scramble_323, SCRAMBLE_LENGTH_323) + 1;
...@@ -760,17 +745,23 @@ check_connection(THD *thd) ...@@ -760,17 +745,23 @@ check_connection(THD *thd)
char *user= end; char *user= end;
char *passwd= strend(user)+1; char *passwd= strend(user)+1;
uint passwd_len= strlen(passwd); char *db= passwd;
/*
char *db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ? Old clients send null-terminated string as password; new clients send
passwd+passwd_len+1 : 0; 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) if (thd->user)
x_free(thd->user); x_free(thd->user);
thd->user= my_strdup(user, MYF(0)); thd->user= my_strdup(user, MYF(0));
if (!thd->user) if (!thd->user)
return(ER_OUT_OF_RESOURCES); 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, ...@@ -1137,8 +1128,15 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
statistic_increment(com_other, &LOCK_status); statistic_increment(com_other, &LOCK_status);
char *user= (char*) packet; char *user= (char*) packet;
char *passwd= strend(user)+1; 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 */ /* Small check for incomming packet */
if ((uint) ((uchar*) db - net->read_pos) > packet_length) if ((uint) ((uchar*) db - net->read_pos) > packet_length)
...@@ -1163,7 +1161,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, ...@@ -1163,7 +1161,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break; 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) if (res)
{ {
......
...@@ -493,6 +493,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ...@@ -493,6 +493,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token MULTIPOINT %token MULTIPOINT
%token MULTIPOLYGON %token MULTIPOLYGON
%token NOW_SYM %token NOW_SYM
%token OLD_PASSWORD
%token PASSWORD %token PASSWORD
%token POINTFROMTEXT %token POINTFROMTEXT
%token POINT_SYM %token POINT_SYM
...@@ -2516,9 +2517,11 @@ simple_expr: ...@@ -2516,9 +2517,11 @@ simple_expr:
{ $$= new Item_func_now($3); Lex->safe_to_cache_query=0;} { $$= new Item_func_now($3); Lex->safe_to_cache_query=0;}
| PASSWORD '(' expr ')' | PASSWORD '(' expr ')'
{ {
$$= use_old_passwords ? (Item *) new Item_func_old_password($3) : $$= use_old_passwords ? (Item *) new Item_func_old_password($3) :
(Item *) new Item_func_password($3); (Item *) new Item_func_password($3);
} }
| OLD_PASSWORD '(' expr ')'
{ $$= new Item_func_old_password($3); }
| POINT_SYM '(' expr ',' expr ')' | POINT_SYM '(' expr ',' expr ')'
{ $$= new Item_func_point($3,$5); } { $$= new Item_func_point($3,$5); }
| POINTFROMTEXT '(' expr ')' | POINTFROMTEXT '(' expr ')'
...@@ -4412,6 +4415,7 @@ keyword: ...@@ -4412,6 +4415,7 @@ keyword:
| NO_SYM {} | NO_SYM {}
| NONE_SYM {} | NONE_SYM {}
| OFFSET_SYM {} | OFFSET_SYM {}
| OLD_PASSWORD {}
| OPEN_SYM {} | OPEN_SYM {}
| PACK_KEYS_SYM {} | PACK_KEYS_SYM {}
| PARTIAL {} | PARTIAL {}
...@@ -4603,24 +4607,15 @@ text_or_password: ...@@ -4603,24 +4607,15 @@ text_or_password:
TEXT_STRING { $$=$1.str;} TEXT_STRING { $$=$1.str;}
| PASSWORD '(' TEXT_STRING ')' | PASSWORD '(' TEXT_STRING ')'
{ {
if (!$3.length) $$= $3.length ? use_old_passwords ?
$$=$3.str; Item_func_old_password::alloc(YYTHD, $3.str) :
else if (use_old_passwords) Item_func_password::alloc(YYTHD, $3.str) :
{ $3.str;
char *buff= (char *) }
YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1); | OLD_PASSWORD '(' TEXT_STRING ')'
if (buff) {
make_scrambled_password_323(buff, $3.str); $$= $3.length ? Item_func_old_password::alloc(YYTHD, $3.str) :
$$=buff; $3.str;
}
else
{
char *buff= (char *)
YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH+1);
if (buff)
make_scrambled_password(buff, $3.str);
$$=buff;
}
} }
; ;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment