summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <kostja@oak.local>2003-07-09 18:24:43 +0400
committerunknown <kostja@oak.local>2003-07-09 18:24:43 +0400
commit04a75388e4e127652685bb8010d04fbb7c5e3b0b (patch)
tree9774a7006312380fb4dbc92767fe0c009a485b12 /sql
parent531a5d76bf5c38589df89985fa43b6a0d215b28e (diff)
parentdb3e9344d6ccfd5b39d8fa2499e5dcb2ed90f808 (diff)
downloadmariadb-git-04a75388e4e127652685bb8010d04fbb7c5e3b0b.tar.gz
resolved conflict with pulled changeset
include/mysql.h: Auto merged include/mysql_com.h: Auto merged libmysql/libmysql.c: Auto merged sql/item_create.cc: Auto merged sql/item_create.h: Auto merged sql/lex.h: Auto merged sql/mysql_priv.h: Auto merged sql/mysqld.cc: Auto merged sql/set_var.cc: Auto merged sql/sql_parse.cc: Auto merged sql/sql_yacc.yy: Auto merged include/mysqld_error.h: manually resolved conflict with ER_VARIABLE_IS_NOT_STRUCT sql/set_var.h: manually resolved conflict sql/share/czech/errmsg.txt: manually resolved conflict with ER_VARIABLE_IS_NOT_STRUCT sql/share/danish/errmsg.txt: manually resolved conflict with ER_VARIABLE_IS_NOT_STRUCT sql/share/dutch/errmsg.txt: manually resolved conflict with ER_VARIABLE_IS_NOT_STRUCT sql/share/english/errmsg.txt: manually resolved conflict with ER_VARIABLE_IS_NOT_STRUCT sql/share/estonian/errmsg.txt: manually resolved conflict with ER_VARIABLE_IS_NOT_STRUCT sql/share/french/errmsg.txt: manually resolved conflict with ER_VARIABLE_IS_NOT_STRUCT sql/share/german/errmsg.txt: manually resolved conflict with ER_VARIABLE_IS_NOT_STRUCT sql/share/greek/errmsg.txt: manually resolved conflict with ER_VARIABLE_IS_NOT_STRUCT sql/share/hungarian/errmsg.txt: manually resolved conflict with ER_VARIABLE_IS_NOT_STRUCT sql/share/italian/errmsg.txt: manually resolved conflict with ER_VARIABLE_IS_NOT_STRUCT sql/share/japanese/errmsg.txt: manually resolved conflict with ER_VARIABLE_IS_NOT_STRUCT sql/share/korean/errmsg.txt: manually resolved conflict with ER_VARIABLE_IS_NOT_STRUCT sql/share/norwegian-ny/errmsg.txt: manually resolved conflict with ER_VARIABLE_IS_NOT_STRUCT sql/share/norwegian/errmsg.txt: manually resolved conflict with ER_VARIABLE_IS_NOT_STRUCT sql/share/polish/errmsg.txt: manually resolved conflict with ER_VARIABLE_IS_NOT_STRUCT sql/share/portuguese/errmsg.txt: manually resolved conflict with ER_VARIABLE_IS_NOT_STRUCT sql/share/romanian/errmsg.txt: manually resolved conflict with ER_VARIABLE_IS_NOT_STRUCT sql/share/russian/errmsg.txt: manually resolved conflict with ER_VARIABLE_IS_NOT_STRUCT sql/share/serbian/errmsg.txt: manually resolved conflict with ER_VARIABLE_IS_NOT_STRUCT sql/share/slovak/errmsg.txt: manually resolved conflict with ER_VARIABLE_IS_NOT_STRUCT sql/share/spanish/errmsg.txt: manually resolved conflict with ER_VARIABLE_IS_NOT_STRUCT sql/share/swedish/errmsg.txt: manually resolved conflict with ER_VARIABLE_IS_NOT_STRUCT sql/share/ukrainian/errmsg.txt: manually resolved conflict with ER_VARIABLE_IS_NOT_STRUCT
Diffstat (limited to 'sql')
-rw-r--r--sql/item_create.cc12
-rw-r--r--sql/item_create.h2
-rw-r--r--sql/item_strfunc.cc100
-rw-r--r--sql/item_strfunc.h31
-rw-r--r--sql/lex.h2
-rw-r--r--sql/mysql_priv.h5
-rw-r--r--sql/mysqld.cc31
-rw-r--r--sql/password.c821
-rw-r--r--sql/set_var.cc6
-rw-r--r--sql/set_var.h4
-rw-r--r--sql/share/czech/errmsg.txt1
-rw-r--r--sql/share/danish/errmsg.txt1
-rw-r--r--sql/share/dutch/errmsg.txt1
-rw-r--r--sql/share/english/errmsg.txt1
-rw-r--r--sql/share/estonian/errmsg.txt1
-rw-r--r--sql/share/french/errmsg.txt1
-rw-r--r--sql/share/german/errmsg.txt1
-rw-r--r--sql/share/greek/errmsg.txt1
-rw-r--r--sql/share/hungarian/errmsg.txt1
-rw-r--r--sql/share/italian/errmsg.txt1
-rw-r--r--sql/share/japanese/errmsg.txt1
-rw-r--r--sql/share/korean/errmsg.txt1
-rw-r--r--sql/share/norwegian-ny/errmsg.txt1
-rw-r--r--sql/share/norwegian/errmsg.txt1
-rw-r--r--sql/share/polish/errmsg.txt1
-rw-r--r--sql/share/portuguese/errmsg.txt1
-rw-r--r--sql/share/romanian/errmsg.txt1
-rw-r--r--sql/share/russian/errmsg.txt1
-rw-r--r--sql/share/serbian/errmsg.txt1
-rw-r--r--sql/share/slovak/errmsg.txt1
-rw-r--r--sql/share/spanish/errmsg.txt1
-rw-r--r--sql/share/swedish/errmsg.txt1
-rw-r--r--sql/share/ukrainian/errmsg.txt1
-rw-r--r--sql/slave.cc6
-rw-r--r--sql/slave.h2
-rw-r--r--sql/sql_acl.cc712
-rw-r--r--sql/sql_acl.h13
-rw-r--r--sql/sql_class.cc1
-rw-r--r--sql/sql_class.h15
-rw-r--r--sql/sql_parse.cc596
-rw-r--r--sql/sql_repl.h2
-rw-r--r--sql/sql_yacc.yy56
42 files changed, 1089 insertions, 1351 deletions
diff --git a/sql/item_create.cc b/sql/item_create.cc
index eaa27c1009d..67179c8d002 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -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);
diff --git a/sql/item_create.h b/sql/item_create.h
index 32e452c15dd..434a0b134c1 100644
--- a/sql/item_create.h
+++ b/sql/item_create.h
@@ -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);
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 2d29f76c2d7..4b62ce22d5f 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -1325,95 +1325,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);
+ 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,
- &current_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;
- }
+ if (res->length() == 0)
+ return &empty_string;
+ 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);
+ 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,&current_thd->rand);
- str->set(tmp_value,16,res->charset());
+ 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)+'.')
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 6cc6d730627..96e264fd8d2 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -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;
diff --git a/sql/lex.h b/sql/lex.h
index a148baad07f..d177a17eae8 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -288,6 +288,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},
@@ -586,7 +587,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)},
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 65451ca40b5..90cf2a62bf6 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -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 HOST_CACHE_SIZE 128
#define MAX_ACCEPT_RETRY 10 // Test accept this many times
#define MAX_FIELDS_BEFORE_HASH 32
@@ -756,7 +753,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;
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 709ba036f7e..cfe2605ed62 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -250,9 +250,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;
@@ -2757,12 +2758,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
@@ -3472,7 +3467,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
};
@@ -3773,9 +3769,10 @@ Does nothing yet.",
(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,
@@ -3844,8 +3841,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...",
@@ -3855,6 +3850,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,
@@ -4624,7 +4622,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;
@@ -4727,6 +4726,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
@@ -4848,9 +4848,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);
diff --git a/sql/password.c b/sql/password.c
index 257547671e5..2e9139c12aa 100644
--- a/sql/password.c
+++ b/sql/password.c
@@ -29,28 +29,33 @@
The password is saved (in user.password) by using the PASSWORD() function in
mysql.
+ This is .c file because it's used in libmysqlclient, which is entirely in C.
+ (we need it to be portable to a variety of systems).
Example:
update user set password=PASSWORD("hello") where user="test"
This saves a hashed number as a string in the password field.
+ The new autentication is performed in following manner:
- New in MySQL 4.1 authentication works even more secure way.
- At the first step client sends user name to the sever, and password if
- it is empty. So in case of empty password authentication is as fast as before.
- At the second stap servers sends scramble to client, which is encoded with
- password stage2 hash stored in the password database as well as salt, needed
- for client to build stage2 password to decrypt scramble.
- Client decrypts the scramble and encrypts it once again with stage1 password.
- This information is sent to server.
- Server decrypts the scramble to get stage1 password and hashes it to get
- stage2 hash. This hash is when compared to hash stored in the database.
+ SERVER: public_seed=create_random_string()
+ send(public_seed)
- This authentication needs 2 packet round trips instead of one but it is much
- stronger. Now if one will steal mysql database content he will not be able
- to break into MySQL.
+ CLIENT: recv(public_seed)
+ hash_stage1=sha1("password")
+ hash_stage2=sha1(hash_stage1)
+ reply=xor(hash_stage1, sha1(public_seed,hash_stage2)
- New Password handling functions by Peter Zaitsev
+ // this three steps are done in scramble()
+ send(reply)
+
+
+ SERVER: recv(reply)
+ hash_stage1=xor(reply, sha1(public_seed,hash_stage2))
+ candidate_hash2=sha1(hash_stage1)
+ check(candidate_hash2==hash_stage2)
+
+ // this three steps are done in check_scramble()
*****************************************************************************/
@@ -60,31 +65,21 @@
#include <sha1.h>
#include "mysql.h"
-
-
-/* Character to use as version identifier for version 4.1 */
-#define PVERSION41_CHAR '*'
-
-/* Scramble length for new password version */
-
+/************ MySQL 3.23-4.0 authentification routines: untouched ***********/
/*
New (MySQL 3.21+) random generation structure initialization
-
SYNOPSIS
randominit()
rand_st OUT Structure to initialize
seed1 IN First initialization parameter
seed2 IN Second initialization parameter
-
- RETURN
- none
*/
-void randominit(struct rand_struct *rand_st,ulong seed1, ulong seed2)
-{ /* For mysql 3.21.# */
+void randominit(struct rand_struct *rand_st, ulong seed1, ulong seed2)
+{ /* For mysql 3.21.# */
#ifdef HAVE_purify
- bzero((char*) rand_st,sizeof(*rand_st)); /* Avoid UMC varnings */
+ bzero((char*) rand_st,sizeof(*rand_st)); /* Avoid UMC varnings */
#endif
rand_st->max_value= 0x3FFFFFFFL;
rand_st->max_value_dbl=(double) rand_st->max_value;
@@ -94,35 +89,12 @@ void randominit(struct rand_struct *rand_st,ulong seed1, ulong seed2)
/*
- Old (MySQL 3.20) random generation structure initialization
-
- SYNOPSIS
- old_randominit()
- rand_st OUT Structure to initialize
- seed1 IN First initialization parameter
-
- RETURN
- none
-*/
-
-static void old_randominit(struct rand_struct *rand_st,ulong seed1)
-{ /* For mysql 3.20.# */
- rand_st->max_value= 0x01FFFFFFL;
- rand_st->max_value_dbl=(double) rand_st->max_value;
- seed1%=rand_st->max_value;
- rand_st->seed1=seed1 ; rand_st->seed2=seed1/2;
-}
-
-
-/*
- Generate Random number
-
+ Generate random number.
SYNOPSIS
my_rnd()
rand_st INOUT Structure used for number generation
-
- RETURN
- Generated pseudo random number
+ RETURN VALUE
+ generated pseudo random number
*/
double my_rnd(struct rand_struct *rand_st)
@@ -134,63 +106,12 @@ double my_rnd(struct rand_struct *rand_st)
/*
- Generate String of printable random characters of requested length
- String will not be zero terminated.
-
+ Generate binary hash from raw text string
+ Used for Pre-4.1 password handling
SYNOPSIS
- create_random_string()
- length IN Lenght of
- rand_st INOUT Structure used for number generation
- target OUT Buffer for generation
-
- RETURN
- none
-*/
-
-void create_random_string(int length,struct rand_struct *rand_st,char *target)
-{
- char *end=target+length;
- /* Use pointer arithmetics as it is faster way to do so. */
- for (; target<end ; target++)
- *target= (char) (my_rnd(rand_st)*94+33);
-}
-
-
-/*
- Encrypt/Decrypt function used for password encryption in authentication
- Simple XOR is used here but it is OK as we crypt random strings
-
- SYNOPSIS
- password_crypt()
- from IN Data for encryption
- to OUT Encrypt data to the buffer (may be the same)
- password IN Password used for encryption (same length)
- length IN Length of data to encrypt
-
- RETURN
- none
-*/
-
-void password_crypt(const char *from,char *to, const char *password,int length)
-{
- const char *from_end=from+length;
-
- while (from < from_end)
- *to++= *(from++) ^* (password++);
-}
-
-
-/*
- Generate binary hash from raw text password
- Used for Pre-4.1 Password handling
-
- SYNOPSIS
- hash_pasword()
- result OUT Store hash in this location
- password IN Plain text password to build hash
-
- RETURN
- none
+ hash_password()
+ result OUT store hash in this location
+ password IN plain text password to build hash
*/
void hash_password(ulong *result, const char *password)
@@ -200,7 +121,7 @@ void hash_password(ulong *result, const char *password)
for (; *password ; password++)
{
if (*password == ' ' || *password == '\t')
- continue; /* skipp space in password */
+ continue; /* skip space in password */
tmp= (ulong) (uchar) *password;
nr^= (((nr & 63)+add)*tmp)+ (nr << 8);
nr2+=(nr2 << 8) ^ nr;
@@ -213,514 +134,388 @@ void hash_password(ulong *result, const char *password)
/*
- Stage one password hashing.
- Used in MySQL 4.1 password handling
-
+ Create password to be stored in user database from raw string
+ Used for pre-4.1 password handling
SYNOPSIS
- password_hash_stage1()
- to OUT Store stage one hash to this location
- password IN Plain text password to build hash
-
- RETURN
- none
+ make_scrambled_password_323()
+ to OUT store scrambled password here
+ password IN user-supplied password
*/
-void password_hash_stage1(char *to, const char *password)
+void make_scrambled_password_323(char *to, const char *password)
{
- SHA1_CONTEXT context;
- sha1_reset(&context);
- for (; *password ; password++)
- {
- if (*password == ' ' || *password == '\t')
- continue;/* skip space in password */
- sha1_input(&context,(uint8*) &password[0],1);
- }
- sha1_result(&context,(uint8*)to);
+ ulong hash_res[2];
+ hash_password(hash_res, password);
+ sprintf(to, "%08lx%08lx", hash_res[0], hash_res[1]);
}
/*
- Stage two password hashing.
- Used in MySQL 4.1 password handling
-
+ Scramble string with password.
+ Used in pre 4.1 authentication phase.
SYNOPSIS
- password_hash_stage2()
- to INOUT Use this as stage one hash and store stage two hash here
- salt IN Salt used for stage two hashing
-
+ scramble_323()
+ to OUT Store scrambled message here. Buffer must be at least
+ SCRAMBLE_LENGTH_323+1 bytes long
+ message IN Message to scramble. Message must be exactly
+ SRAMBLE_LENGTH_323 long and NULL terminated.
+ password IN Password to use while scrambling
RETURN
- none
+ End of scrambled string
*/
-void password_hash_stage2(char *to, const char *salt)
+char *scramble_323(char *to, const char *message, const char *password)
{
- SHA1_CONTEXT context;
- sha1_reset(&context);
- sha1_input(&context,(uint8*) salt, 4);
- sha1_input(&context,(uint8*) to, SHA1_HASH_SIZE);
- sha1_result(&context,(uint8*) to);
+ struct rand_struct rand_st;
+ ulong hash_pass[2], hash_message[2];
+
+ if (password && password[0])
+ {
+ char *to_start=to;
+ hash_password(hash_pass,password);
+ hash_password(hash_message, message);
+ randominit(&rand_st,hash_pass[0] ^ hash_message[0],
+ hash_pass[1] ^ hash_message[1]);
+ while (*message++)
+ *to++= (char) (floor(my_rnd(&rand_st)*31)+64);
+ char extra=(char) (floor(my_rnd(&rand_st)*31));
+ while (to_start != to)
+ *(to_start++)^=extra;
+ }
+ *to= 0;
+ return to;
}
/*
- Create password to be stored in user database from raw string
- Handles both MySQL 4.1 and Pre-MySQL 4.1 passwords
-
+ Check scrambled message
+ Used in pre 4.1 password handling
SYNOPSIS
- make_scramble_password()
- to OUT Store scrambled password here
- password IN Raw string password
- force_old_scramle
- IN Force generation of old scramble variant
- rand_st INOUT Structure for temporary number generation.
- RETURN
- none
+ check_scramble_323()
+ scrambled IN scrambled message to check.
+ message IN original random message which was used for scrambling; must
+ be exactly SCRAMBLED_LENGTH_323 bytes long and
+ NULL-terminated.
+ hash_pass IN password which should be used for scrambling
+ RETURN VALUE
+ 0 - password correct
+ !0 - password invalid
*/
-void make_scrambled_password(char *to,const char *password,
- my_bool force_old_scramble,
- struct rand_struct *rand_st)
+my_bool
+check_scramble_323(const char *scrambled, const char *message,
+ ulong *hash_pass)
{
- ulong hash_res[2]; /* Used for pre 4.1 password hashing */
- unsigned short salt; /* Salt for 4.1 version password */
- uint8 digest[SHA1_HASH_SIZE];
- if (force_old_scramble) /* Pre 4.1 password encryption */
- {
- hash_password(hash_res,password);
- sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
- }
- else /* New password 4.1 password scrambling */
+ struct rand_struct rand_st;
+ ulong hash_message[2];
+ char buff[16],*to,extra; /* Big enough for check */
+ const char *pos;
+
+ /* Check if this exactly N bytes. Overwise this is something fishy */
+ if (strlen(message) != SCRAMBLE_LENGTH_323)
+ return 1; /* Wrong password */
+
+ hash_password(hash_message,message);
+ randominit(&rand_st,hash_pass[0] ^ hash_message[0],
+ hash_pass[1] ^ hash_message[1]);
+ to=buff;
+ for (pos=scrambled ; *pos ; pos++)
+ *to++=(char) (floor(my_rnd(&rand_st)*31)+64);
+ extra=(char) (floor(my_rnd(&rand_st)*31));
+ to=buff;
+ while (*scrambled)
{
- to[0]=PVERSION41_CHAR; /* New passwords have version prefix */
- /* Rnd returns number from 0 to 1 so this would be good salt generation.*/
- salt=(unsigned short) (my_rnd(rand_st)*65535+1);
- /* Use only 2 first bytes from it */
- sprintf(to+1,"%04x",salt);
- /* First hasing is done without salt */
- password_hash_stage1((char*) digest, password);
- /* Second stage is done with salt */
- password_hash_stage2((char*) digest,(char*)to+1),
- /* Print resulting hash into the password*/
- sprintf(to+5,
- "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
- digest[0],digest[1],digest[2],digest[3],digest[4],digest[5],digest[6],
- digest[7],digest[8],digest[9],digest[10],digest[11],digest[12],digest[13],
- digest[14],digest[15],digest[16],digest[17],digest[18],digest[19]);
+ if (*scrambled++ != (char) (*to++ ^ extra))
+ return 1; /* Wrong password */
}
+ return 0;
}
+static uint8 char_val(uint8 X)
+{
+ return (uint) (X >= '0' && X <= '9' ? X-'0' :
+ X >= 'A' && X <= 'Z' ? X-'A'+10 : X-'a'+10);
+}
-/*
- Convert password from binary string form to salt form
- Used for MySQL 4.1 password handling
+/*
+ Convert password from hex string (as stored in mysql.user) to binary form.
SYNOPSIS
- get_salt_from_bin_password()
- res OUT Store salt form password here
- password IN Binary password to be converted
- salt IN hashing-salt to be used for salt form generation
-
- RETURN
- none
+ get_salt_from_password_323()
+ res OUT store salt here
+ password IN password string as stored in mysql.user
+ NOTE
+ This function does not have length check for passwords. It will just crash
+ Password hashes in old format must have length divisible by 8
*/
-void get_salt_from_bin_password(ulong *res,unsigned char *password,ulong salt)
+void get_salt_from_password_323(ulong *res, const char *password)
{
- unsigned char *password_end=password+SCRAMBLE41_LENGTH;
- *res=salt;
- res++;
-
- /* Process password of known length*/
- while (password<password_end)
+ res[0]= res[1]= 0;
+ if (password)
{
- ulong val=0;
- uint i;
- for (i=0 ; i < 4 ; i++)
- val=(val << 8)+(*password++);
- *res++=val;
+ while (*password)
+ {
+ ulong val=0;
+ uint i;
+ for (i=0 ; i < 8 ; i++)
+ val=(val << 4)+char_val(*password++);
+ *res++=val;
+ }
}
}
/*
- Validate password for MySQL 4.1 password handling.
-
+ Convert scrambled password from binary form to asciiz hex string.
SYNOPSIS
- validate_password()
- password IN Encrypted Scramble which we got from the client
- message IN Original scramble which we have sent to the client before
- salt IN Password in the salted form to match to
-
- RETURN
- 0 for correct password
- !0 for invalid password
+ make_password_from_salt_323()
+ to OUT store resulting string password here, at least 17 bytes
+ salt IN password in salt format, 2 ulongs
*/
-my_bool validate_password(const char *password, const char *message,
- ulong *salt)
+void make_password_from_salt_323(char *to, const ulong *salt)
{
- char buffer[SCRAMBLE41_LENGTH]; /* Used for password validation */
- char tmpsalt[8]; /* Temporary value to convert salt to string form */
- ulong salt_candidate[6]; /* Computed candidate salt */
- ulong *sc=salt_candidate; /* we need to be able to increment */
- ulong *salt_end;
-
- /* Now we shall get stage1 encrypted password in buffer*/
- password_crypt(password,buffer,message,SCRAMBLE41_LENGTH);
-
- /* For compatibility reasons we use ulong to store salt while we need char */
- sprintf(tmpsalt,"%04x",(unsigned short)salt[0]);
-
- password_hash_stage2(buffer,tmpsalt);
- /* Convert password to salt to compare */
- get_salt_from_bin_password(salt_candidate,(uchar*) buffer,salt[0]);
-
- /* Now we shall get exactly the same password as we have stored for user */
- for (salt_end=salt+5 ; salt < salt_end; )
- if (*++salt != *++sc)
- return 1;
-
- /* Or password correct*/
- return 0;
+ sprintf(to,"%08lx%08lx", salt[0], salt[1]);
}
+/******************* MySQL 4.1.1 authentification routines ******************/
/*
- Get length of password string which is stored in mysql.user table
-
+ Generate string of printable random characters of requested length
SYNOPSIS
- get_password_length()
- force_old_scramble IN If we wish to use pre 4.1 scramble format
-
- RETURN
- password length >0
+ create_random_string()
+ to OUT buffer for generation; must be at least length+1 bytes
+ long; result string is always null-terminated
+ length IN how many random characters to put in buffer
+ rand_st INOUT structure used for number generation
*/
-int get_password_length(my_bool force_old_scramble)
+void create_random_string(char *to, uint length, struct rand_struct *rand_st)
{
- return (force_old_scramble) ? 16 : SHA1_HASH_SIZE*2+4+1;
+ char *end= to + length;
+ /* Use pointer arithmetics as it is faster way to do so. */
+ for (; to < end; to++)
+ *to= (char) (my_rnd(rand_st)*94+33);
+ *to= '\0';
}
-/*
- Get version of the password based on mysql.user password string
-
- SYNOPSIS
- get_password_version()
- password IN Password string as stored in mysql.user
-
- RETURN
- 0 for pre 4.1 passwords
- !0 password version char for newer passwords
-*/
+/* Character to use as version identifier for version 4.1 */
-char get_password_version(const char *password)
-{
- if (password==NULL) return 0;
- if (password[0]==PVERSION41_CHAR) return PVERSION41_CHAR;
- return 0;
-}
+#define PVERSION41_CHAR '*'
/*
- Get integer value of Hex character
-
+ Convert given octet sequence to asciiz string of hex characters;
+ str..str+len and 'to' may not overlap.
SYNOPSIS
- char_val()
- X IN Character to find value for
-
- RETURN
- Appropriate integer value
+ octet2hex()
+ buf OUT output buffer. Must be at least 2*len+1 bytes
+ str, len IN the beginning and the length of the input string
*/
-
-
-static inline unsigned int char_val(char X)
+static
+void
+octet2hex(char *to, const uint8 *str, uint len)
{
- return (uint) (X >= '0' && X <= '9' ? X-'0' :
- X >= 'A' && X <= 'Z' ? X-'A'+10 :
- X-'a'+10);
+ static const char alphabet[] = { '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+ const uint8 *str_end= str + len;
+ for (; str != str_end; ++str)
+ {
+ *to++= alphabet[(*str & 0xF0) >> 4];
+ *to++= alphabet[*str & 0x0F];
+ }
+ *to++= '\0';
}
/*
- Get Binary salt from password as in mysql.user format
-
+ Convert given asciiz string of hex (0..9 a..f) characters to octet
+ sequence.
SYNOPSIS
- get_salt_from_password()
- res OUT Store binary salt here
- password IN Password string as stored in mysql.user
-
- RETURN
- none
-
- NOTE
- This function does not have length check for passwords. It will just crash
- Password hashes in old format must have length divisible by 8
-*/
-
-void get_salt_from_password(ulong *res,const char *password)
+ hex2octet()
+ to OUT buffer to place result; must be at least len/2 bytes
+ str, len IN begin, length for character string; str and to may not
+ overlap; len % 2 == 0
+*/
+
+static
+void
+hex2octet(uint8 *to, const char *str, uint len)
{
- if (password) /* zero salt corresponds to empty password */
+ const char *str_end= str + len;
+ while (str < str_end)
{
- if (password[0]==PVERSION41_CHAR) /* if new password */
- {
- uint val=0;
- uint i;
- password++; /* skip version identifier */
-
- /*get hashing salt from password and store in in the start of array */
- for (i=0 ; i < 4 ; i++)
- val=(val << 4)+char_val(*password++);
- *res++=val;
- }
- /* We process old passwords the same way as new ones in other case */
-#ifdef EXTRA_DEBUG
- if (strlen(password)%8!=0)
- fprintf(stderr,"Warning: Incorrect password length for salting: %d\n",
- strlen(password));
-#endif
- while (*password)
- {
- ulong val=0;
- uint i;
- for (i=0 ; i < 8 ; i++)
- val=(val << 4)+char_val(*password++);
- *res++=val;
- }
+ *to= char_val(*str++) << 4;
+ *to++|= char_val(*str++);
}
- return;
}
/*
- Get string version as stored in mysql.user from salt form
-
+ Encrypt/Decrypt function used for password encryption in authentication.
+ Simple XOR is used here but it is OK as we crypt random strings. Note,
+ that XOR(s1, XOR(s1, s2)) == s2, XOR(s1, s2) == XOR(s2, s1)
SYNOPSIS
- make_password_from_salt()
- to OUT Store resulting string password here
- hash_res IN Password in salt format
- password_version
- IN According to which version salt should be treated
-
- RETURN
- none
+ my_crypt()
+ to OUT buffer to hold crypted string; must be at least len bytes
+ long; to and s1 (or s2) may be the same.
+ s1, s2 IN input strings (of equal length)
+ len IN length of s1 and s2
*/
-void make_password_from_salt(char *to, ulong *hash_res,uint8 password_version)
+static
+void
+my_crypt(char *to, const uint8 *s1, const uint8 *s2, uint len)
{
- if (!password_version) /* Handling of old passwords. */
- sprintf(to,"%08lx%08lx",hash_res[0],hash_res[1]);
- else
- if (password_version==PVERSION41_CHAR)
- sprintf(to,"%c%04x%08lx%08lx%08lx%08lx%08lx",PVERSION41_CHAR,(unsigned short)hash_res[0],hash_res[1],
- hash_res[2],hash_res[3],hash_res[4],hash_res[5]);
- else /* Just use empty password if we can't handle it. This should not happen */
- to[0]='\0';
+ const uint8 *s1_end= s1 + len;
+ while (s1 < s1_end)
+ *to++= *s1++ ^ *s2++;
}
/*
- Convert password in salted form to binary string password and hash-salt
- For old password this involes one more hashing
-
+ MySQL 4.1.1 password hashing: SHA conversion (see RFC 2289, 3174) twice
+ applied to the password string, and then produced octet sequence is
+ converted to hex string.
+ The result of this function is used as return value from PASSWORD() and
+ is stored in the database.
SYNOPSIS
- get_hash_and_password()
- salt IN Salt to convert from
- pversion IN Password version to use
- hash OUT Store zero ended hash here
- bin_password OUT Store binary password here (no zero at the end)
-
- RETURN
- 0 for pre 4.1 passwords
- !0 password version char for newer passwords
+ make_scrambled_password()
+ buf OUT buffer of size 2*SHA1_HASH_SIZE + 2 to store hex string
+ password IN NULL-terminated password string
*/
-void get_hash_and_password(ulong *salt, uint8 pversion, char *hash,
- unsigned char *bin_password)
+void
+make_scrambled_password(char *to, const char *password)
{
- int t;
- ulong* salt_end;
- ulong val;
- SHA1_CONTEXT context;
-
- if (pversion) /* New password version assumed */
- {
- salt_end=salt+5;
- sprintf(hash,"%04x",(unsigned short)salt[0]);
- while (salt<salt_end)
- {
- val=*(++salt);
- for (t=3; t>=0; t--)
- {
- bin_password[t]= (char) (val & 255);
- val>>=8; /* Scroll 8 bits to get next part*/
- }
- bin_password+=4; /* Get to next 4 chars*/
- }
- }
- else
- {
- unsigned char *bp= bin_password; /* Binary password loop pointer */
-
- /* Use zero starting hash as an indication of old password */
- hash[0]=0;
- salt_end=salt+2;
- /* Encode salt using SHA1 here */
- sha1_reset(&context);
- while (salt<salt_end) /* Iterate over these elements*/
- {
- val= *salt;
- for (t=3;t>=0;t--)
- {
- bp[t]= (uchar) (val & 255);
- val>>=8; /* Scroll 8 bits to get next part*/
- }
- bp+= 4; /* Get to next 4 chars*/
- salt++;
- }
- /* Use 8 bytes of binary password for hash */
- sha1_input(&context,(uint8*)bin_password,8);
- sha1_result(&context,(uint8*)bin_password);
- }
+ SHA1_CONTEXT sha1_context;
+ uint8 hash_stage2[SHA1_HASH_SIZE];
+
+ sha1_reset(&sha1_context);
+ /* stage 1: hash password */
+ sha1_input(&sha1_context, (uint8 *) password, strlen(password));
+ sha1_result(&sha1_context, (uint8 *) to);
+ /* stage 2: hash stage1 output */
+ sha1_reset(&sha1_context);
+ sha1_input(&sha1_context, (uint8 *) to, SHA1_HASH_SIZE);
+ /* separate buffer is used to pass 'to' in octet2hex */
+ sha1_result(&sha1_context, hash_stage2);
+ /* convert hash_stage2 to hex string */
+ *to++= PVERSION41_CHAR;
+ octet2hex(to, hash_stage2, SHA1_HASH_SIZE);
}
-
+
/*
- Create key from old password to decode scramble
- Used in 4.1 authentication with passwords stored old way
-
+ 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 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
- create_key_from_old_password()
- passwd IN Password used for key generation
- key OUT Created 20 bytes key
-
- RETURN
- None
+ scramble()
+ buf OUT store scrambled string here. The buf must be at least
+ SHA1_HASH_SIZE bytes long.
+ message IN random message, must be exactly SCRAMBLE_LENGTH long and
+ NULL-terminated.
+ password IN users' password
*/
-
-void create_key_from_old_password(const char *passwd, char *key)
+void
+scramble(char *to, const char *message, const char *password)
{
- char buffer[SCRAMBLE41_LENGTH]; /* Buffer for various needs */
- ulong salt[6]; /* Salt (large for safety) */
- /* At first hash password to the string stored in password */
- make_scrambled_password(buffer,passwd,1,(struct rand_struct *)NULL);
- /* Now convert it to the salt form */
- get_salt_from_password(salt,buffer);
- /* Finally get hash and bin password from salt */
- get_hash_and_password(salt,0,buffer,(unsigned char*) key);
+ SHA1_CONTEXT sha1_context;
+ uint8 hash_stage1[SHA1_HASH_SIZE];
+ uint8 hash_stage2[SHA1_HASH_SIZE];
+
+ sha1_reset(&sha1_context);
+ /* stage 1: hash password */
+ sha1_input(&sha1_context, (uint8 *) password, strlen(password));
+ sha1_result(&sha1_context, hash_stage1);
+ /* stage 2: hash stage 1; note that hash_stage2 is stored in the database */
+ sha1_reset(&sha1_context);
+ sha1_input(&sha1_context, hash_stage1, SHA1_HASH_SIZE);
+ sha1_result(&sha1_context, hash_stage2);
+ /* create crypt string as sha1(message, hash_stage2) */;
+ sha1_reset(&sha1_context);
+ sha1_input(&sha1_context, (const uint8 *) message, SCRAMBLE_LENGTH);
+ sha1_input(&sha1_context, hash_stage2, SHA1_HASH_SIZE);
+ /* 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);
}
/*
- Scramble string with password
- Used at pre 4.1 authentication phase.
-
+ Check that scrambled message corresponds to the password; the function
+ is used by server to check that recieved reply is authentic.
+ This function does not check lengths of given strings: message must be
+ null-terminated, reply and hash_stage2 must be at least SHA1_HASH_SIZE
+ long (if not, something fishy is going on).
SYNOPSIS
- scramble()
- to OUT Store scrambled message here
- message IN Message to scramble
- password IN Password to use while scrambling
- old_ver IN Forse old version random number generator
-
- RETURN
- End of scrambled string
+ check_scramble()
+ scramble IN clients' reply, presumably produced by scramble()
+ message IN original random string, previously sent to client
+ (presumably second argument of scramble()), must be
+ exactly SCRAMBLE_LENGTH long and NULL-terminated.
+ hash_stage2 IN hex2octet-decoded database entry
+ RETURN VALUE
+ 0 password is correct
+ !0 password is invalid
*/
-char *scramble(char *to,const char *message,const char *password,
- my_bool old_ver)
+my_bool
+check_scramble(const char *scramble, const char *message,
+ const uint8 *hash_stage2)
{
- struct rand_struct rand_st;
- ulong hash_pass[2],hash_message[2];
- char message_buffer[9]; /* Real message buffer */
- char *msg=message_buffer;
-
- /* We use special message buffer now as new server can provide longer hash */
-
- memcpy(message_buffer,message,8);
- message_buffer[8]=0;
-
- if (password && password[0])
- {
- char *to_start=to;
- hash_password(hash_pass,password);
- hash_password(hash_message,message_buffer);
- if (old_ver)
- old_randominit(&rand_st,hash_pass[0] ^ hash_message[0]);
- else
- randominit(&rand_st,hash_pass[0] ^ hash_message[0],
- hash_pass[1] ^ hash_message[1]);
- while (*msg++)
- *to++= (char) (floor(my_rnd(&rand_st)*31)+64);
- if (!old_ver)
- { /* Make it harder to break */
- char extra=(char) (floor(my_rnd(&rand_st)*31));
- while (to_start != to)
- *(to_start++)^=extra;
- }
- }
- *to=0;
- return to;
+ SHA1_CONTEXT sha1_context;
+ uint8 buf[SHA1_HASH_SIZE];
+ uint8 hash_stage2_reassured[SHA1_HASH_SIZE];
+
+ sha1_reset(&sha1_context);
+ /* create key to encrypt scramble */
+ sha1_input(&sha1_context, (const uint8 *) message, SCRAMBLE_LENGTH);
+ sha1_input(&sha1_context, hash_stage2, SHA1_HASH_SIZE);
+ sha1_result(&sha1_context, buf);
+ /* encrypt scramble */
+ my_crypt((char *) buf, buf, (const uint8 *) scramble, SCRAMBLE_LENGTH);
+ /* now buf supposedly contains hash_stage1: so we can get hash_stage2 */
+ sha1_reset(&sha1_context);
+ sha1_input(&sha1_context, buf, SHA1_HASH_SIZE);
+ sha1_result(&sha1_context, hash_stage2_reassured);
+ return memcmp(hash_stage2, hash_stage2_reassured, SHA1_HASH_SIZE);
}
/*
- Check scrambled message
- Used for pre 4.1 password handling
-
+ Convert scrambled password from asciiz hex string to binary form.
SYNOPSIS
- scramble()
- scrambled IN Scrambled message to check
- message IN Original message which was scramble
- hash_pass IN Password which should be used for scrambling
- old_ver IN Forse old version random number generator
+ get_salt_from_password()
+ res OUT buf to hold password. Must be at least SHA1_HASH_SIZE
+ bytes long.
+ password IN 4.1.1 version value of user.password
+*/
+
+void get_salt_from_password(uint8 *hash_stage2, const char *password)
+{
+ hex2octet(hash_stage2, password+1 /* skip '*' */, SHA1_HASH_SIZE * 2);
+}
- RETURN
- 0 Password correct
- !0 Password invalid
+/*
+ Convert scrambled password from binary form to asciiz hex string.
+ SYNOPSIS
+ make_password_from_salt()
+ to OUT store resulting string here, 2*SHA1_HASH_SIZE+2 bytes
+ salt IN password in salt format
*/
-my_bool check_scramble(const char *scrambled, const char *message,
- ulong *hash_pass, my_bool old_ver)
+void make_password_from_salt(char *to, const uint8 *hash_stage2)
{
- struct rand_struct rand_st;
- ulong hash_message[2];
- char buff[16],*to,extra; /* Big enough for check */
- const char *pos;
- char message_buffer[SCRAMBLE_LENGTH+1]; /* Copy of message */
-
- /* We need to copy the message as this function can be called for MySQL 4.1
- scramble which is not zero ended and can have zeroes inside
- We could just write zero to proper place in original message but
- this would make it harder to understand code for next generations
- */
-
- memcpy(message_buffer,message,SCRAMBLE_LENGTH); /* Ignore the rest */
- message_buffer[SCRAMBLE_LENGTH]=0;
-
- /* Check if this exactly N bytes. Overwise this is something fishy */
- if (strlen(message_buffer)!=SCRAMBLE_LENGTH)
- return 1; /* Wrong password */
-
- hash_password(hash_message,message_buffer);
- if (old_ver)
- old_randominit(&rand_st,hash_pass[0] ^ hash_message[0]);
- else
- randominit(&rand_st,hash_pass[0] ^ hash_message[0],
- hash_pass[1] ^ hash_message[1]);
- to=buff;
- for (pos=scrambled ; *pos ; pos++)
- *to++=(char) (floor(my_rnd(&rand_st)*31)+64);
- if (old_ver)
- extra=0;
- else
- extra=(char) (floor(my_rnd(&rand_st)*31));
- to=buff;
- while (*scrambled)
- {
- if (*scrambled++ != (char) (*to++ ^ extra))
- return 1; /* Wrong password */
- }
- return 0;
+ *to++= PVERSION41_CHAR;
+ octet2hex(to, hash_stage2, SHA1_HASH_SIZE);
}
diff --git a/sql/set_var.cc b/sql/set_var.cc
index cb6c875d513..31706b21734 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -208,6 +208,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",
@@ -234,6 +235,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);
@@ -423,6 +425,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,
@@ -441,6 +444,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
@@ -598,6 +602,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},
@@ -618,6 +623,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},
diff --git a/sql/set_var.h b/sql/set_var.h
index 978aba3384a..8f12016bab4 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -692,6 +692,9 @@ public:
}
};
+/* updated in sql_acl.cc */
+
+extern sys_var_thd_bool sys_old_passwords;
/*
Prototypes for helper functions
@@ -705,6 +708,7 @@ void fix_delay_key_write(THD *thd, enum_var_type type);
ulong fix_sql_mode(ulong sql_mode);
extern sys_var_str sys_charset_system;
CHARSET_INFO *get_old_charset_by_name(const char *old_name);
+
gptr find_named(I_List<NAMED_LIST> *list, const char *name, uint length);
void delete_elements(I_List<NAMED_LIST> *list, void (*free_element)(gptr));
diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt
index 30516e8dad1..1c555e93cf2 100644
--- a/sql/share/czech/errmsg.txt
+++ b/sql/share/czech/errmsg.txt
@@ -276,3 +276,4 @@ v/*
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"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"
diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt
index 289f70c79ed..874e0680830 100644
--- a/sql/share/danish/errmsg.txt
+++ b/sql/share/danish/errmsg.txt
@@ -270,3 +270,4 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"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"
diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt
index 8cf926554a4..8719ec37916 100644
--- a/sql/share/dutch/errmsg.txt
+++ b/sql/share/dutch/errmsg.txt
@@ -278,3 +278,4 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"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"
diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt
index 6f0de413a47..5a87d9fbc28 100644
--- a/sql/share/english/errmsg.txt
+++ b/sql/share/english/errmsg.txt
@@ -272,3 +272,4 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"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"
diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt
index f4107e91d5b..6239d1c309d 100644
--- a/sql/share/estonian/errmsg.txt
+++ b/sql/share/estonian/errmsg.txt
@@ -272,3 +272,4 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"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"
diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt
index 5d82eebefda..c2d54d4de87 100644
--- a/sql/share/french/errmsg.txt
+++ b/sql/share/french/errmsg.txt
@@ -267,3 +267,4 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"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"
diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt
index 4512cd1e0cb..5760f29e719 100644
--- a/sql/share/german/errmsg.txt
+++ b/sql/share/german/errmsg.txt
@@ -276,3 +276,4 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"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"
diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt
index 873f8385462..a94a14873a9 100644
--- a/sql/share/greek/errmsg.txt
+++ b/sql/share/greek/errmsg.txt
@@ -267,3 +267,4 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"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"
diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt
index 93ab550b60f..e6e74d2d76d 100644
--- a/sql/share/hungarian/errmsg.txt
+++ b/sql/share/hungarian/errmsg.txt
@@ -269,3 +269,4 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"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"
diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt
index cc21f7cf42a..86823dcd360 100644
--- a/sql/share/italian/errmsg.txt
+++ b/sql/share/italian/errmsg.txt
@@ -267,3 +267,4 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"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"
diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt
index b8bc6e1d761..0a57d70205d 100644
--- a/sql/share/japanese/errmsg.txt
+++ b/sql/share/japanese/errmsg.txt
@@ -269,3 +269,4 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"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"
diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt
index 9bbcaa16076..7d0fe2f6d6d 100644
--- a/sql/share/korean/errmsg.txt
+++ b/sql/share/korean/errmsg.txt
@@ -267,3 +267,4 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"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"
diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt
index f562553e40a..b6d449bb70a 100644
--- a/sql/share/norwegian-ny/errmsg.txt
+++ b/sql/share/norwegian-ny/errmsg.txt
@@ -269,3 +269,4 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"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"
diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt
index dcb7be9a053..b46fa718d4d 100644
--- a/sql/share/norwegian/errmsg.txt
+++ b/sql/share/norwegian/errmsg.txt
@@ -269,3 +269,4 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"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"
diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt
index 9cd63dfc009..e00e99bb0a8 100644
--- a/sql/share/polish/errmsg.txt
+++ b/sql/share/polish/errmsg.txt
@@ -271,3 +271,4 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"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"
diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt
index 14a1e6763b4..d904243e2fb 100644
--- a/sql/share/portuguese/errmsg.txt
+++ b/sql/share/portuguese/errmsg.txt
@@ -267,3 +267,4 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"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"
diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt
index c5be6e5df8d..702591a89ec 100644
--- a/sql/share/romanian/errmsg.txt
+++ b/sql/share/romanian/errmsg.txt
@@ -271,3 +271,4 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"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"
diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt
index e193eac6793..c011de8f093 100644
--- a/sql/share/russian/errmsg.txt
+++ b/sql/share/russian/errmsg.txt
@@ -269,3 +269,4 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"óÅÒ×ÅÒ ÚÁÐÕÝÅÎ × ÒÅÖÉÍÅ --secure-auth (ÂÅÚÏÐÁÓÎÏÊ Á×ÔÏÒÉÚÁÃÉÉ), ÎÏ ÄÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%s@%s' ÐÁÒÏÌØ ÓÏÈÒÁÎ£Î × ÓÔÁÒÏÍ ÆÏÒÍÁÔÅ; ÎÅÏÂÈÏÄÉÍÏ ÏÂÎÏ×ÉÔØ ÆÏÒÍÁÔ ÐÁÒÏÌÑ"
diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt
index e413097a997..89672811a25 100644
--- a/sql/share/serbian/errmsg.txt
+++ b/sql/share/serbian/errmsg.txt
@@ -263,3 +263,4 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"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"
diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt
index a3e34b8b41a..51bcde43b91 100644
--- a/sql/share/slovak/errmsg.txt
+++ b/sql/share/slovak/errmsg.txt
@@ -275,3 +275,4 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"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"
diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt
index c1b3f19da4f..c8931faeb16 100644
--- a/sql/share/spanish/errmsg.txt
+++ b/sql/share/spanish/errmsg.txt
@@ -268,3 +268,4 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"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"
diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt
index b1153c83504..f38f2126602 100644
--- a/sql/share/swedish/errmsg.txt
+++ b/sql/share/swedish/errmsg.txt
@@ -267,3 +267,4 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"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"
diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt
index 2fc14372f54..a3e2c46bed1 100644
--- a/sql/share/ukrainian/errmsg.txt
+++ b/sql/share/ukrainian/errmsg.txt
@@ -272,3 +272,4 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"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"
diff --git a/sql/slave.cc b/sql/slave.cc
index c45c11f8bef..91376df5590 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -1459,7 +1459,7 @@ int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
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, SCRAMBLED_PASSWORD_CHAR_LENGTH);
mi->port = master_port;
mi->connect_retry = master_connect_retry;
}
@@ -1483,8 +1483,8 @@ int init_master_info(MASTER_INFO* mi, const char* master_info_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))
diff --git a/sql/slave.h b/sql/slave.h
index 429456eb0bb..d3565565ded 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -292,7 +292,7 @@ typedef struct st_master_info
/* the variables below are needed because we can change masters on the fly */
char host[HOSTNAME_LENGTH+1];
char user[USERNAME_LENGTH+1];
- char password[HASH_PASSWORD_LENGTH+1];
+ char password[SCRAMBLED_PASSWORD_CHAR_LENGTH+1];
pthread_mutex_t data_lock,run_lock;
pthread_cond_t data_cond,start_cond,stop_cond;
THD *io_thd;
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 1bdca7167e8..ee544335a99 100644
--- a/sql/sql_acl.cc
+++ b/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,12 +68,54 @@ 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.
SYNOPSIS
@@ -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,125 @@ 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)
- {
- 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 */
- }
- else /* non empty and not short passwords */
- {
- user.pversion=get_password_version(user.password);
- /* Only passwords of specific lengths depending on version are allowed */
- if ( (!user.pversion && length % 8) || (user.pversion && length!=45 ))
- {
- 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 */
+ 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)
+ {
+ switch (password_len) {
+ case 45: /* 4.1: to be removed */
+ sql_print_error("Found 4.1 style password for user '%s'. "
+ "Ignoring user. "
+ "You should change password for this user.",
+ user.user ? user.user : "");
+ 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;
}
}
- 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
+ else // password is correct
{
- user.ssl_type=SSL_TYPE_NONE;
- bzero(&(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;
+ 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;
}
- /* 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;
+ else
+ {
+ user.ssl_type=SSL_TYPE_NONE;
+ bzero(&(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;
#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);
@@ -462,247 +524,205 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b)
/*
- Prepare crypted scramble to be sent to the client
-*/
-
-void prepare_scramble(THD *thd, ACL_USER *acl_user,char* prepared_scramble)
-{
- /* 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;
-
+ Seek ACL entry for a user, check password, SSL cypher, and if
+ everything is OK, update THD user data and USER_RESOURCES struct.
+ 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
+ thd INOUT 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 OUT user resources; on success mqh is reset, else
+ unchanged
+ passwd IN 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 IN length of passwd, must be one of 0, 8,
+ SCRAMBLE_LENGTH_323, SCRAMBLE_LENGTH
+ 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.
*/
-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)
+int acl_getroot(THD *thd, USER_RESOURCES *mqh,
+ const char *passwd, uint passwd_len)
{
- 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(mqh,sizeof(USER_RESOURCES));
- if (!initialized)
- {
- // If no data allow anything
- DBUG_RETURN((ulong) ~NO_ACCESS); /* purecov: tested */
+ if (!initialized) /* if no data allow anything */
+ {
+ DBUG_RETURN(1);
}
+
+ 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_323,
+ (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 */
#ifdef HAVE_OPENSSL
- {
- Vio *vio=thd->net.vio;
- /*
- At this point we know that user is allowed to connect
- from given host by given username/password pair. Now
- we check if SSL is required, if user is using SSL and
- if X509 certificate attributes are OK
- */
- switch (acl_user->ssl_type) {
- case SSL_TYPE_NOT_SPECIFIED: // Impossible
- case SSL_TYPE_NONE: /* SSL is not required to connect */
- user_access=acl_user->access;
- break;
- case SSL_TYPE_ANY: /* Any kind of SSL is good enough */
- if (vio_type(vio) == VIO_TYPE_SSL)
- user_access=acl_user->access;
- break;
- case SSL_TYPE_X509: /* Client should have any valid certificate. */
- /*
- Connections with non-valid certificates are dropped already
- in sslaccept() anyway, so we do not check validity here.
-
- We need to check for absence of SSL because without SSL
- we should reject connection.
- */
- if (vio_type(vio) == VIO_TYPE_SSL && SSL_get_peer_certificate(vio->ssl_))
- user_access=acl_user->access;
- break;
- case SSL_TYPE_SPECIFIED: /* Client should have specified attrib */
+ {
+ ulong user_access= NO_ACCESS;
+ Vio *vio=thd->net.vio;
/*
- 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.
+ At this point we know that user is allowed to connect
+ from given host by given username/password pair. Now
+ we check if SSL is required, if user is using SSL and
+ if X509 certificate attributes are OK
*/
- if (vio_type(vio) != VIO_TYPE_SSL)
- break;
- if (acl_user->ssl_cipher)
- {
- DBUG_PRINT("info",("comparing ciphers: '%s' and '%s'",
- acl_user->ssl_cipher,SSL_get_cipher(vio->ssl_)));
- if (!strcmp(acl_user->ssl_cipher,SSL_get_cipher(vio->ssl_)))
- user_access=acl_user->access;
- else
- {
- 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;
- }
- }
- /* Prepare certificate (if exists) */
- DBUG_PRINT("info",("checkpoint 1"));
- X509* cert=SSL_get_peer_certificate(vio->ssl_);
- DBUG_PRINT("info",("checkpoint 2"));
- /* If X509 issuer is speified, we check it... */
- if (acl_user->x509_issuer)
- {
- DBUG_PRINT("info",("checkpoint 3"));
- char *ptr = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
- DBUG_PRINT("info",("comparing issuers: '%s' and '%s'",
- acl_user->x509_issuer, ptr));
- if (strcmp(acl_user->x509_issuer, ptr))
- {
- 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);
- }
- 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);
+ switch (acl_user->ssl_type) {
+ case SSL_TYPE_NOT_SPECIFIED: // Impossible
+ case SSL_TYPE_NONE: /* SSL is not required to connect */
+ user_access=acl_user->access;
+ break;
+ case SSL_TYPE_ANY: /* Any kind of SSL is good enough */
+ if (vio_type(vio) == VIO_TYPE_SSL)
+ user_access=acl_user->access;
+ break;
+ case SSL_TYPE_X509: /* Client should have any valid certificate. */
+ /*
+ Connections with non-valid certificates are dropped already
+ in sslaccept() anyway, so we do not check validity here.
+
+ We need to check for absence of SSL because without SSL
+ we should reject connection.
+ */
+ if (vio_type(vio) == VIO_TYPE_SSL &&
+ SSL_get_peer_certificate(vio->ssl_))
+ user_access=acl_user->access;
+ break;
+ case SSL_TYPE_SPECIFIED: /* Client should have specified attrib */
+ /*
+ We do not check for absence of SSL because without SSL it does
+ not pass all checks here anyway.
+ If cipher name is specified, we compare it to actual cipher in
+ use.
+ */
+ if (vio_type(vio) != VIO_TYPE_SSL)
+ break;
+ if (acl_user->ssl_cipher)
+ {
+ DBUG_PRINT("info",("comparing ciphers: '%s' and '%s'",
+ acl_user->ssl_cipher,SSL_get_cipher(vio->ssl_)));
+ if (!strcmp(acl_user->ssl_cipher,SSL_get_cipher(vio->ssl_)))
+ user_access=acl_user->access;
+ else
+ {
+ 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;
+ }
+ }
+ /* Prepare certificate (if exists) */
+ DBUG_PRINT("info",("checkpoint 1"));
+ X509* cert=SSL_get_peer_certificate(vio->ssl_);
+ DBUG_PRINT("info",("checkpoint 2"));
+ /* If X509 issuer is speified, we check it... */
+ if (acl_user->x509_issuer)
+ {
+ DBUG_PRINT("info",("checkpoint 3"));
+ char *ptr = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
+ DBUG_PRINT("info",("comparing issuers: '%s' and '%s'",
+ acl_user->x509_issuer, ptr));
+ if (strcmp(acl_user->x509_issuer, ptr))
+ {
+ 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);
+ }
+ 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);
+ }
+ break;
}
- break;
+ /* end of SSL stuff: assign result */
+ thd->master_access= user_access;
}
- }
#else /* HAVE_OPENSSL */
- user_access=acl_user->access;
+ thd->master_access= acl_user->access;
#endif /* HAVE_OPENSSL */
- *mqh=acl_user->user_resource;
- if (!acl_user->user)
- *priv_user=(char*) ""; // Change to anonymous user /* purecov: inspected */
+ thd->priv_user= acl_user->user ? thd->user : (char *) "";
+ *mqh= acl_user->user_resource;
- if (acl_user->host.hostname)
- strmake(priv_host, acl_user->host.hostname, MAX_HOSTNAME);
- else
- *priv_host= 0;
-
-unlock_and_exit:
+ if (acl_user->host.hostname)
+ strmake(thd->priv_host, acl_user->host.hostname, MAX_HOSTNAME);
+ else
+ *thd->priv_host= 0;
+ }
VOID(pthread_mutex_unlock(&acl_cache->lock));
- DBUG_RETURN(user_access);
+ DBUG_RETURN(res);
}
@@ -713,8 +733,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,
@@ -750,20 +771,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;
}
}
@@ -772,7 +782,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,
@@ -783,7 +793,6 @@ static void acl_insert_user(const char *user, const char *host,
ACL_USER acl_user;
acl_user.user=strdup_root(&mem,user);
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);
@@ -793,12 +802,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
@@ -1135,7 +1140,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));
@@ -1144,37 +1148,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));
@@ -1210,7 +1204,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);
}
@@ -1280,7 +1274,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;
@@ -1304,7 +1298,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 */
@@ -1352,24 +1346,24 @@ 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];
+ char empty_string[]= { '\0' };
+ char *password= empty_string;
+ 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);
+ MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH);
DBUG_RETURN(-1);
}
+ password_len= combo.password.length;
password=combo.password.str;
}
@@ -1394,17 +1388,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 */
@@ -1501,10 +1498,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,
@@ -1512,7 +1507,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,
@@ -2915,12 +2910,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 */
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index e6c6771253c..b4ee1a9b15f 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -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);
-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,
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index c233ffd422a..ebb3e819ddc 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -139,6 +139,7 @@ THD::THD():user_time(0), is_fatal_error(0),
set_query_id=1;
db_access=NO_ACCESS;
version=refresh_version; // For boot
+ *scramble= *scramble_323= '\0';
init();
/* Initialize sub structures */
diff --git a/sql/sql_class.h b/sql/sql_class.h
index f6336cb7dd9..e80b5d9c8d5 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -386,6 +386,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;
@@ -544,10 +545,16 @@ 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];
+ /*
+ The same as scramble but for old password checking routines. It always
+ contains first N bytes of scramble.
+ See check_connection() at sql_parse.cc for authentification details.
+ */
+ char scramble_323[SCRAMBLE_LENGTH_323+1];
+
uint8 query_cache_type; // type of query cache processing
bool slave_thread;
bool set_query_id,locked,count_cuted_fields,some_tables_deleted;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 9e670a97e92..7878f2c8a29 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -178,152 +178,178 @@ 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
-
- 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
+ thd INOUT thread handle, thd->{host,user,ip} are used
+ command IN originator of the check: now check_user is called
+ during connect and change user procedures; used for
+ logging.
+ passwd IN scrambled password recieved from client
+ passwd_len IN length of scrambled password
+ db IN database name to connect to, may be NULL
+ check_count IN dont know exactly
+ 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.
+ 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];
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
+ Why this is set here? - probably to reset current DB to 'no database
+ selected' in case of 'change user' failure.
*/
- if (thd->master_access & NO_ACCESS)
+ 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);
+ 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.
+ */
+ 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_NOT_SUPPORTED_AUTH_MODE);
- mysql_log.write(thd,COM_CONNECT,ER(ER_NOT_SUPPORTED_AUTH_MODE));
- }
- 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
+ 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);
}
- DBUG_PRINT("info",("Prepare for second part of handshake"));
- DBUG_RETURN(-1); // no report error in special handshake
+ /* 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);
+ 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);
}
-
- if (check_count)
+ /* here res is always >= 0 */
+ if (res == 0)
{
- 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);
+ 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? */
+ 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);
}
}
- 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) &&
- 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 &&
- 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);
- }
- send_ok(thd); // Ready to handle questions
- thd->password= test(passwd[0]); // Remember for error messages
- DBUG_RETURN(0); // ok
+ net_printf(thd, ER_NOT_SUPPORTED_AUTH_MODE);
+ mysql_log.write(thd,COM_CONNECT,ER(ER_NOT_SUPPORTED_AUTH_MODE));
+ DBUG_RETURN(-1);
+ }
+ 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.
@@ -525,48 +551,39 @@ 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 INOUT 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
+ -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 */
- 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"))
- thd->host=(char*) localhost;
+ thd->host= (char *) localhost;
else
#endif
{
@@ -595,15 +612,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);
@@ -617,19 +635,36 @@ 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[2]=(char) default_charset_info->number;
- int2store(end+3,thd->server_status);
- bzero(end+5,13);
- end+=18;
+ 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);
+ strmake(thd->scramble_323, thd->scramble, SCRAMBLE_LENGTH_323);
- // At this point we write connection message and read reply
- if (net_write_command(net,(uchar) protocol_version, "", 0, buff,
+ /*
+ 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_323, 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;
+ /* 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,
(uint) (end-buff)) ||
(pkt_len= my_net_read(net)) == packet_error ||
pkt_len < MIN_HANDSHAKE_SIZE)
@@ -702,7 +737,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)",
@@ -719,16 +754,7 @@ 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)
- db=strend(passwd)+1;
-
- /* We can get only old hash at this point */
- if (using_password && strlen(passwd) != SCRAMBLE_LENGTH)
- return ER_HANDSHAKE_ERROR;
+ /* why has it been put here? */
if (thd->client_capabilities & CLIENT_INTERACTIVE)
thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
@@ -737,60 +763,25 @@ check_connections(THD *thd)
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);
+ char *user= end;
+ char *passwd= strend(user)+1;
+ 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;
- /* 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);
+ thd->user= my_strdup(user, MYF(0));
+ if (!thd->user)
+ return(ER_OUT_OF_RESOURCES);
+ return check_user(thd, COM_CONNECT, passwd, passwd_len, db, true);
}
@@ -847,7 +838,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);
@@ -1157,116 +1148,67 @@ 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;
- /* 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);
+ {
+ send_error(thd, ER_UNKNOWN_COM_ERROR);
+ break;
+ }
- /*
- 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)
+ /* 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;
+ 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;
- /* Bad luck we shall restore old user */
-restore_user_err:
- send_error(thd, ER_UNKNOWN_COM_ERROR);
+ int res= check_user(thd, COM_CHANGE_USER, passwd, passwd_len, db, false);
-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 */
@@ -3168,7 +3110,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
diff --git a/sql/sql_repl.h b/sql/sql_repl.h
index e3d600b9798..b53551845bc 100644
--- a/sql/sql_repl.h
+++ b/sql/sql_repl.h
@@ -7,7 +7,7 @@ typedef struct st_slave_info
uint32 rpl_recovery_rank, master_id;
char host[HOSTNAME_LENGTH+1];
char user[USERNAME_LENGTH+1];
- char password[HASH_PASSWORD_LENGTH+1];
+ char password[SCRAMBLED_PASSWORD_CHAR_LENGTH+1];
uint16 port;
THD* thd;
} SLAVE_INFO;
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 3098bd18b2d..807501b6ab4 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -499,6 +499,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
@@ -2538,9 +2539,13 @@ simple_expr:
| NOW_SYM '(' expr ')'
{ $$= new Item_func_now($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 ')'
@@ -4451,6 +4456,7 @@ keyword:
| NO_SYM {}
| NONE_SYM {}
| OFFSET_SYM {}
+ | OLD_PASSWORD {}
| OPEN_SYM {}
| PACK_KEYS_SYM {}
| PARTIAL {}
@@ -4664,15 +4670,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;
}
;
@@ -4980,14 +4986,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